PDA

View Full Version : simple example which uses static memory (accumulate statistics over frames)?


jbeale
1st July 2010, 18:59
I'm new to avisynth plugin writing. So far I have confirmed that MSVC++ 2010 Express does work to compile SimpleSample.dll (the 2010 version is the only free download available now from MS; the earlier ones mentioned at http://avisynth.org/mediawiki/Filter_SDK/SDK_necessaries have gone away)

I'm trying to write a plugin that accumulates statistics over many (all) frames in a clip. Is there a simple example of such a filter that I can start with? I think I am looking for some global or static memory allocation (?) which can be written out at the end, and is freed only after the clip has played through completely. I guess I also need to figure out how to write out the accumulated data after the last frame is processed, that is, have a different behavior on the last frame, than every other frame.

It seems that most filters work on one frame at a time, or rely on a cache to speed up accesses to frames n+1 or n-1, etc. What I'd like to do is create a fixed array which holds some statistical data on all previous frames processed, and accumulates as each additional frame goes through the filter. Hoping to find a code example to see where in the code such persistent variables would be declared. Thanks for any tips!

Gavino
1st July 2010, 19:16
This is more a basic C++ question than about Avisynth.

Just declare any variables you need within your filter class, write to them from GetFrame and write out the accumulated data in the filter destructor.

davidhorman
1st July 2010, 20:06
To give a little more detail (and this is what I've accumulated more through trial and error than inherent knowledge), you declare your variables in the "private" section (which simplesample may not have):

class SimpleSample : public GenericVideoFilter {
public:
SimpleSample(PClip _child, IScriptEnvironment* env);
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
private:
int *data; // could be a struct, or pointer to an array of structs... etc
};

then malloc() inside the constructor:

SimpleSample::SimpleSample(PClip _child, IScriptEnvironment* env) : GenericVideoFilter(_child) {
if (vi.IsPlanar()) // is input planar?
env->ThrowError("SimpleSample: input to filter must be in YUY2 or RGB");
data=calloc(1024,sizeof(int));
}

and free() inside the destructor (which again SimpleSample may not have):

SimpleSample::~SimpleSample() {
free(data);
}

Hope that helps/works.

Oh yes, and as Gavino says, you can also use the destructor to write out your data, though I'm not exactly sure under which circumstances it is called (presumably when the clip is closed).

David

jbeale
1st July 2010, 20:11
This is more a basic C++ question than about Avisynth. Just declare any variables you need within your filter class, write to them from GetFrame and write out the accumulated data in the filter destructor.

Thanks for the quick answer! I know C, but not C++ and not Avisynth internals. I wasn't sure if the constructor and destructor code was invoked only once per script, or once per clip, or once per frame; hence what scope any variables declared there might have. Anyway, I gather it's once per clip, so the constructor code variable will do what I want- thanks!

davidhorman
1st July 2010, 20:15
Anyway, I gather it's once per clip, so the constructor code variable will do what I want- thanks!

It's once per invocation of the filter, but that's essentially the same in your case :)

David

Gavino
1st July 2010, 20:25
I wasn't sure if the constructor and destructor code was invoked only once per script, or once per clip, or once per frame;
The constructor is invoked for each call of the filter in the script, eg if you call the filter twice in the script you will get two instances, each with its own data.

The destructor is invoked (for each instance) when the script is unloaded by the Avisynth client application (eg VDub or AvsP).

jbeale
2nd July 2010, 19:55
Thanks again for the quick help on this issue! ...ok, I have modified the SimpleSample example to do my histogram accumulation. It compiles ok, but I get a runtime error. Obviously I'm doing something wrong in my usage of std::vector hdat, but I'm not sure what. I include the relevant parts below.

class SimpleSample : public GenericVideoFilter {
int SquareSize;
std::vector<unsigned long> hdat;
public:
SimpleSample(PClip _child, int _SquareSize, IScriptEnvironment* env);
~SimpleSample();
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};

SimpleSample::SimpleSample(PClip _child, int _SquareSize, IScriptEnvironment* env) :
GenericVideoFilter(_child), SquareSize(_SquareSize) {

std::vector<unsigned long> hdat(256*256*256); // 64 MB of memory, init to 0
}

SimpleSample::~SimpleSample() {
int i,j,k;
unsigned char byte;
ofstream ofl;
ofl.open("histout.bin",ios::binary); // open for output in binary mode

for (i=0;i<256;i++) { // write each element of hdat[i] using log2()
for (j=0;j<256;j++) {
for (k=0;k<256;k++) {
byte = (unsigned char) (hdat[idx(i,j,k)]);
ofl << byte;
}
}
}
ofl.close();
}

PVideoFrame __stdcall SimpleSample::GetFrame(int n, IScriptEnvironment* env) {
/* loop over each pixel, assign (Y' Cb Cr) values to (i j k) for each pixel, increment hdat[i,j,k] ... */

hdat[idx(i,j,k)]++;
/* other stuff */
}

UPDATE: oh well, I just dropped the C++ vector stuff; and used the old fashioned malloc() / free() way:

SimpleSample::SimpleSample(PClip _child, int _SquareSize, IScriptEnvironment* env) :
GenericVideoFilter(_child), SquareSize(_SquareSize) {

size_t hbytes = 256*256*256*sizeof(unsigned long);
hdat = (unsigned long *) malloc(hbytes);
memset(hdat, 0, hbytes);
}

Now it actually works :-)