View Full Version : Use of AVSValue in constructor and in get frame
vcmohan
11th May 2005, 04:42
In one of my plugins I have an array of numbers for processing obtained by an i+ specification. One way of using is to recursively call the function with a limited set of actually required values of array. Since each time this happens a new class is generated this approach is not very efficient.
Instead I tried returning AVSValue args as a parameter to class. In the constructor I could fill an already reserved array with calls like
for(int i=0; i<args[3].ArraySize(); i++)
x[i]=args[3][i].AsInt();
This however requires a reservation of storage for array or make a call for new and in destructor delete it. I find this is mostly OK but I thought I can use a better approach as follows as depending upon frame number I could just use particular values of parameter.
In the GetFrame call back I tried
nvalues=args[3].ArraySize();
I find I get always a zero value. So I could not process.
Why is there this behaviour?
stickboy
11th May 2005, 09:29
Originally posted by vcmohan
In one of my plugins I have an array of numbers for processing obtained by an i+ specification. One way of using is to recursively call the function with a limited set of actually required values of array. Since each time this happens a new class is generated this approach is not very efficient.Can you post code explaining this? I don't understand what you mean.
Instead I tried returning AVSValue args as a parameter to class.This seems like the normal approach. The C function that is registered into the script environment parses the AVSValue arguments and then passes them to the filter's constructor.
In the constructor I could fill an already reserved array with calls like
for(int i=0; i<args[3].ArraySize(); i++)
x[i]=args[3][i].AsInt();
This however requires a reservation of storage for array or make a call for new and in destructor delete it. I find this is mostly OK but I thought I can use a better approach as follows as depending upon frame number I could just use particular values of parameter.I don't understand what you mean without more code.
In the GetFrame call back I tried
nvalues=args[3].ArraySize();
I find I get always a zero value. So I could not process.
Why is there this behaviour?I'm really confused now. Why would you do any of that within GetFrame? The arguments should never change between frames.
Bidoche
11th May 2005, 14:33
Originally posted by vcmohan
In the GetFrame call back I tried
nvalues=args[3].ArraySize();
I find I get always a zero value. So I could not process.
Why is there this behaviour? Is args[3] an array itself ?
Anyway, like stickboy, i need more details in order to understand your point.
vcmohan
12th May 2005, 03:43
This is the situation. Sorry that my first post could not be understood.
.AsClip(), // clip on which areas are to be filled
args[1].AsClip(), // clip to be used as mask
args[2].AsInt(), // start frame number to process
args,
}
class Shift : public GenericVideoFilter {
PClip Ref; // clip on which edges are marked
int nl; //start frame number of (child) clip
AVSValue args, // x y coordinates of lines
----------------
// in constructor I can access args[3].ArraySize() and individual array values.
------------------
// I want to process every array value for each frame so I tried in GetFrame
npoints=args[3].ArraySize(); // always get zero value
As all these stages get IScriptEnvironment env, it should be possible to get these values in all stages excepting if Avisynth after constructor call, reuses the args area for some other function call.
Slightly different but similar problem is:-
I can use in script clip.width or clip.numframes etc.
However I can not use this to get info in the Create section of code.
stickboy
12th May 2005, 06:33
Originally posted by vcmohan
extern "C" __declspec(dllexport)
const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)
{
env->AddFunction("Shift", "ccii+", Create_Shift, 0);
return "Shift Plugin";
}
AVSValue __cdecl
Create_Shift(AVSValue args, void* user_data, IScriptEnvironment* env)
{
return new Shift(args[0].AsClip(), // clip on which areas are to be filled
args[1].AsClip(), // clip to be used as mask
args[2].AsInt(), // start frame number to process
args,
}
Huh? This code is incomplete. Please don't retype code when asking for help; copy-and-paste so we see exactly what you're using.class Shift : public GenericVideoFilter {
PClip Ref; // clip on which edges are marked
int nl; //start frame number of (child) clip
AVSValue args, // x y coordinates of lines
----------------
// in constructor I can access args[3].ArraySize() and individual array values.
------------------
// I want to process every array value for each frame so I tried in GetFrame
npoints=args[3].ArraySize(); // always get zero valueHow do you initialize Shift::args? You haven't provided the relevant code. I'm going to assume that you can access the args array in your constructor because you're accessing a local variable and neglected to copy it into the "args" member.
Why not do:AVSValue __cdecl Create_Shift(AVSValue args, void* user_data, IScriptEnvironment* env)
{
std::vector<int> rest;
for (int i = 0; i < args[3].ArraySize(); ++i)
{
rest.push_back(args[3][i].AsInt());
}
return new Shift(args[0].AsClip(),
args[1].AsClip(),
args[2].AsInt(),
rest);
}
class Shift
: public GenericVideoFilter
{
std::vector<int> rest;
Shift(PClip child, PClip foo, int bar,
const std::vector<int>& rest_)
: rest(rest_)
{
}
}
AVSValue __cdecl Create_Shift(AVSValue args, void* user_data, IScriptEnvironment* env)
{
return new Shift( args[0].AsClip(), // clip on which areas are to be filled
args[1].AsClip(), // clip to be used as mask
args[2].AsInt(), // start frame number to process
args[3], // Array of ints
env);
}
Shift::Shift(PClip _child, PClip _mask, int _frame, AVSValue* _args, IScriptEnvironment env)IanB
vcmohan
13th May 2005, 03:06
sorry once again for not posting fully the code, as I thought the standard practices are assumed to be followed by all. I also see workarounds for the problem, but that necessity to work around should not arise in the first place.
As I have meanwhile changed shift code using one that works, I am posting a code of another function this time fully. Even here I am using an array that will be filled by the constructor. My tial of using in the GetFrame has failed here also.
;
int Arraysize;
public:
//Definition of function
DrawLines(PClip _child,int _nl,int _enl,
AVSValue _args,bool _curve,
bool _black,
IScriptEnvironment* env) ;
~DrawLines(); //destructor
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
// This is the function that AviSynth calls to get a given frame.
// So when this functions gets called, the filter is supposed to return frame n.
};
/*************************************************
* The following is the implementation
* of the defined functions.
*************************************************/
//Here is the acutal constructor code used
DrawLines::DrawLines(PClip _child,int _nl,int _enl,
AVSValue _args, bool _curve,
bool _black,
IScriptEnvironment* env) :
GenericVideoFilter(_child),nl(_nl),enl(_enl),
args(_args), curve(_curve),
black(_black)
{
char * Tname="DrawLines";
if(!vi.IsRGB24() && !vi.IsRGB32() && !vi.IsYUY2() && !vi.IsYV12())
env->ThrowError("DrawLines: This color format is not supported here");
// if(x1>=vi.width || y1 >=vi.height || x2>=vi.width || y2 >=vi.height)
// env->ThrowError("DrawLines: The coordinates are outside frame");
if(enl<nl || nl<0 )
env->ThrowError("DrawLines:invalid frame numbers");
for(int i=0; i<args[3].ArraySize(); i+=2)
if(args[3][i+0].AsInt()>=vi.width||args[3][i+1].AsInt()>= vi.height)
env->ThrowError("DrawLines: One or more coordinates are outside this frame width of %d or frame height of %d", vi.width, vi.height);
// following had to be used as use of similar construct in GetFrame failed
for(i=0; i<args[3].ArraySize(); i++)
xyarray[i]= args[3][i].AsInt();
Arraysize=args[3].ArraySize();
}
DrawLines::~DrawLines()
{
// include in destructor
}
/***************************************************************/
PVideoFrame __stdcall DrawLines::GetFrame(int n, IScriptEnvironment* env)
{
PVideoFrame LeftFrame = child->GetFrame(n, env);
if(n<nl || n>enl)
return LeftFrame;
// const VideoInfo& vi = child->GetVideoInfo();
const int bwd = vi.width;
const int bht = LeftFrame->GetHeight();
const int lpitch = LeftFrame->GetPitch();
int x1,x2,x3,y1,y2,y3; // coordinates of 3 consequtive points
int kb=vi.BitsPerPixel()/8;
int max= black? 0 : 255;
env->MakeWritable(&LeftFrame);
unsigned char *lp= LeftFrame->GetWritePtr();
// here originally I tried using for(int i=0; i<args[3].ArraySize(); i+=2)
// that did not work. so I used the following
int nsegments=curve?Arraysize/2-2:Arraysize/2-1; //process code here.....................
}
AVSValue __cdecl Create_DrawLines(AVSValue args, void* user_data, IScriptEnvironment* env)
{
if(args[4].AsBool())
{
if(args[3].ArraySize() < 6 || (args[3].ArraySize()) & 1 ==1)
env->ThrowError("DrawLines:For a curve x y coordinate pairs,and atleast 3 points must be specified");
for(int i=0; i<(args[3].ArraySize())/2-2;i++)
{
if( (args[3][i].AsInt()>args[3][i+2].AsInt() && args[3][i+2].AsInt()>args[3][i+4].AsInt())
||(args[3][i].AsInt()<args[3][i+2].AsInt() && args[3][i+2].AsInt()<args[3][i+4].AsInt())
||(args[3][i+1].AsInt()>args[3][i+3].AsInt() && args[3][i+3].AsInt()>args[3][i+5].AsInt())
||(args[3][i+1].AsInt()<args[3][i+3].AsInt() && args[3][i+3].AsInt()<args[3][i+5].AsInt()) )
continue;
env->ThrowError("DrawLines: the %d, %d and %d points do not have either increasing or decreasing x or y coordinates",i,i+1,i+2);
}
}
else
{
if(args[3].ArraySize() < 4 || (args[3].ArraySize()) & 1 ==1 )
env->ThrowError("DrawLines:For a straight line x y coordinate pairs for all and atleast 2 points must be specified");
}
for(int i=0; i<(args[3].ArraySize()); i++)
if(args[3][i].AsInt()<0)
env->ThrowError("DrawLines:One or more values in the sets is invalid being negative");
return new DrawLines( args[0].AsClip(), // clip on which lines are to be drawn
args[1].AsInt(), // start frame number to process
args[2].AsInt(), // end frame number to process
args, // to get array in the constructor
// max array size 10 line ends coordinates i.e. 40
args[4].AsBool(), // true for curve, false for straight lines
args[5].AsBool(true),// Black line if false white
env);
}
// The following function is the function that actually registers the filter in AviSynth
// It is called automatically, when the plugin is loaded to see which functions this filter contains.
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)
{
env->AddFunction("DrawLines", "ciii+[curve]b[black]b", Create_DrawLines, 0);
return "DrawLines Plugin";
}
Hope my question regarding accessing clip.width etc in the Create section is also been looked into.
stickboy
13th May 2005, 04:44
Originally posted by vcmohan
Slightly different but similar problem is:-
I can use in script clip.width or clip.numframes etc.
However I can not use this to get info in the Create section of code.Yes you can. Your first argument is a PClip, and the width, number of frames, etc. are properties of it (or rather, they are properties of the clip's VideoInfo struct).
Bidoche
14th May 2005, 12:15
@vcmohan
#include <vector>
//...
class DrawLines : public GenericVideoFilter
{
int nl; //frame number of (child) clip
int enl; // end frame number for this line
bool black; // True for black, false for white in YUY or yv12 only y and v values are used;
bool curve;
struct Point
{
int x, y;
Point(int x_, int y_) : x( x_ ), y( y_ ) { }
};
std::vector<Point> pts;
public: //structors
DrawLines(PClip _child, int _nl, int _enl, AVSValue _args, bool _curve, bool _black, IScriptEnvironment* env);
virtual ~DrawLines() { } //it's ok to inline trivial destructor
public: //IClip interface
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
// This is the function that AviSynth calls to get a given frame.
// So when this functions gets called, the filter is supposed to return frame n.
};
/*************************************************
* The following is the implementation
* of the defined functions.
*************************************************/
//Here is the acutal constructor code used
DrawLines:DrawLines(PClip _child, int _nl, int _enl, AVSValue _args, bool _curve, bool _black, IScriptEnvironment* env)
: GenericVideoFilter( _child )
, nl( _nl )
, enl( _enl )
, curve( _curve )
, black( _black )
{
char * Tname = "DrawLines";
if ( ! vi.IsRGB24() && ! vi.IsRGB32() && ! vi.IsYUY2() && ! vi.IsYV12() )
env->ThrowError("DrawLines: This color format is not supported here");
if ( enl < nl || nl < 0 )
env->ThrowError("DrawLines:invalid frame numbers");
for ( int i = 0; i < args[3].ArraySize(); i += 2 )
{
int x = args[3][i].AsInt();
int y = arg[3][i + 1].AsInt();
if ( x >= vi.width || y >= vi.height )
env->ThrowError("DrawLines: One or more coordinates are outside this frame width of %d or frame height of %d", vi.width, vi.height);
pts.push_back( Point(x, y) );
}
}
Please note that I do not keep args as a member since it's unneeded once the points value are copied in the array (vector here)
And as for why you had to make that copy, I think it's due to a bug within AVSValue handling of arrays :
ie the AVSValue copy constructor doesn't deep copy the array inside, so this one got destroyed when the original args (in the parser) got destroyed, and you end up with garbage.
In fact it's even strange you just don't get segfaults.
vcmohan
17th May 2005, 03:27
Originally posted by stickboy
Yes you can. Your first argument is a PClip, and the width, number of frames, etc. are properties of it (or rather, they are properties of the clip's VideoInfo struct).
Well I tried this
int w =args[0].AsClip().width;
but always get a compilation error message stating that width is not a member of PClip.
Incidentally I posted this message two days back but seems to have been lost
they are properties of the clip's VideoInfo structint w =args[0].AsClip().width;
but always get a compilation error message stating that width is not a member of PClip.[/B]int w =args[0].AsClip()->vi.width;
Use control-space in VStudio to auto-complete and inspect membership hierarchies.
IanB
vcmohan
19th May 2005, 02:44
Originally posted by IanB
int w =args[0].AsClip()->vi.width;
Use control-space in VStudio to auto-complete and inspect membership hierarchies.
IanB
Even this statement results in a compilation error stating that it is not a member of IClip.
ctrl-space produces such a long list I couldnt understand what I need to do. I did not find vi or width etc in that list.
stickboy
19th May 2005, 03:14
Sigh.
args[0].AsClip()->GetVideoInfo().width;
Please look at avisynth.h. All of the class definitions are there.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.