View Full Version : Simple Source Filter. (RandomSource)
StainlessS
25th November 2012, 00:58
#include "windows.h"
#include "avisynth.h"
class RandomSource : public IClip {
private:
const VideoInfo vi;
bool parity;
public:
RandomSource(const VideoInfo& _vi,bool _parity) : vi(_vi), parity(_parity) {}
~RandomSource(){}
void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) {}
const VideoInfo& __stdcall GetVideoInfo() { return vi; }
bool __stdcall GetParity(int n) { return (vi.IsFieldBased() ? (n&1) : false) ^ parity; }
void __stdcall SetCacheHints(int cachehints,int frame_range) {};
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};
PVideoFrame __stdcall RandomSource::GetFrame(int n, IScriptEnvironment* env) {
PVideoFrame frame = env->NewVideoFrame(vi);
BYTE* p = frame->GetWritePtr();
int size = frame->GetPitch() * frame->GetHeight();
for (int i=0; i<size; i+=4) {
*(p+i+0) = rand() & 0xFF; // B
*(p+i+1) = rand() & 0xFF; // G
*(p+i+2) = rand() & 0xFF; // R
*(p+i+3) = 0; // Alpha
}
return frame;
}
static AVSValue __cdecl Create_RandomSource(AVSValue args, void*, IScriptEnvironment* env) {
VideoInfo vi;
memset(&vi, 0, sizeof(VideoInfo));
vi.width =640;
vi.height =480;
vi.fps_numerator =24;
vi.fps_denominator =1;
vi.num_frames =10000;
vi.pixel_type =VideoInfo::CS_BGR32;
vi.audio_samples_per_second =0; // 0 means no audio
vi.sample_type =0; // as of 2.5
vi.num_audio_samples =0; // changed as of 2.5
vi.nchannels =0; // as of 2.5
vi.SetFieldBased(false);
bool parity=false;
return new RandomSource(vi, parity);
}
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("RandomSource","",Create_RandomSource, 0);
return "`RandomSource' RandomSource plugin";
}
Memory usage constantly creeps upwards (in AvsMeter), am I doing wrong or is that normal.
(EDIT: Memory usage does max out so looks not to be buggy.)
If normal, is there a way of limiting memory usage within plugin, eg
SetCacheHints(CACHE_NOTHING, 0) or whatever, but as we are a source plugin, is it us that need to
do something for the SetCacheHints call ?
EDIT:
I would be quite happy with a single non-cached re-writeable frame.
Also, perhaps an int 'last' variable implemented in class, to track previously generated frame,
to avoid regeneration when called by another filter on the same frame number.
Want to use this as test clip generator to verify similar results when modding a filter
(in the immediate case for a ShowChannels update).
See Mediafire in sig below for dll + source.
StainlessS
25th November 2012, 03:34
This seems to implement the "remember previous frame generated" in 'last' variable but as caching insists on butting in, is untested.
#include "windows.h"
#include "avisynth.h"
class RandomSource : public IClip {
private:
const VideoInfo vi;
bool parity;
int last; // remember last frame generated
PVideoFrame frame;
public:
RandomSource(const VideoInfo& _vi,PVideoFrame _frame, bool _parity) : vi(_vi), frame(_frame),parity(_parity), last(-1) {}
~RandomSource(){}
void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) {}
const VideoInfo& __stdcall GetVideoInfo() { return vi; }
bool __stdcall GetParity(int n) { return (vi.IsFieldBased() ? (n&1) : false) ^ parity; }
void __stdcall SetCacheHints(int cachehints,int frame_range) {}
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};
PVideoFrame __stdcall RandomSource::GetFrame(int n, IScriptEnvironment* env) {
n = (n < 0) ? 0 : (n >= vi.num_frames) ? vi.num_frames - 1 : n; // Range limit
if(n != last) {
frame = env->NewVideoFrame(vi); // create new frame
BYTE* p = frame->GetWritePtr();
int size = frame->GetPitch() * frame->GetHeight();
for (int i=0; i<size; i+=4) {
*(p+i+0) = rand() & 0xFF; // B
*(p+i+1) = rand() & 0xFF; // G
*(p+i+2) = rand() & 0xFF; // R
*(p+i+3) = 0; // Alpha
}
last = n; // Remember last generated frame number
}
return frame;
}
static AVSValue __cdecl Create_RandomSource(AVSValue args, void*, IScriptEnvironment* env) {
VideoInfo vi;
memset(&vi, 0, sizeof(VideoInfo));
vi.width =640;
vi.height =480;
vi.fps_numerator =24;
vi.fps_denominator =1;
vi.num_frames =1000000;
vi.pixel_type =VideoInfo::CS_BGR32;
vi.SetFieldBased(false);
bool parity=false;
PVideoFrame frame = env->NewVideoFrame(vi); // Create initial frame
return new RandomSource(vi,frame, parity);
}
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("RandomSource","",Create_RandomSource, 0);
return "`RandomSource' RandomSource plugin";
}
IanB
25th November 2012, 22:34
Memory usage constantly creeps upwards (in AvsMeter), am I doing wrong or is that normal.
(EDIT: Memory usage does max out so looks not to be buggy.)
If normal, is there a way of limiting memory usage within plugin, eg
SetCacheHints(CACHE_NOTHING, 0) or whatever, but as we are a source plugin, is it us that need to
do something for the SetCacheHints call ?
EDIT:
I would be quite happy with a single non-cached re-writeable frame.
Also, perhaps an int 'last' variable implemented in class, to track previously generated frame,
to avoid regeneration when called by another filter on the same frame number.
Want to use this as test clip generator to verify similar results when modding a filter
(in the immediate case for a ShowChannels update).
As a source filter you don't have a cache as you don't have a child.
The parent filter(s) above you will have a cache. With some trickery you could explicitly add a cache after your source filter then configure it, however there is no guarantee that the parent filter won't reconfigure it for their needs.
Under normal circumstances env->NewVideoFrame(vi); will deliver a freshly malloc'd chunk of memory until the pool for frame buffers reaches the SetMemoryMax size, then it will deliver the ""oldest"" unused chunk of memory. The pool is global to the whole script not just local to your source filter. And fiddling with the cache doesn't effect that behaviour.
As the primary owner of PVideoFrame frame; you could reuse it for each call as long as no parent filter has a reference to an instance of the frame, GetWritePtr returns zero when there are multiple references to signal the fail. And GetWritePtr increments the frame's sequence number each time it is successfully called.
...
if(n != last) {
BYTE* p = frame->GetWritePtr(); // try to reuse old frame
if (!p) {
frame = env->NewVideoFrame(vi); // ditch old frame and create a new frame
p = frame->GetWritePtr();
}
int size = frame->GetPitch() * frame->GetHeight();
...
As a sample test filter it probably doesn't matter much, but the expectation for all Avisynth filters is that they return identical frame contents for a given frame number every time they are called. The above filter returns the same frame for subsequent call of a constant frame number but different random contents for return visits. AddGrain had a similar problem in the past, iirc it now remembers the rand seed for each frame it returns so it can regenerate the identical sequence next time it is needed.
kolak
26th November 2012, 00:47
As a sample test filter it probably doesn't matter much, but the expectation for all Avisynth filters is that they return identical frame contents for a given frame number every time they are called. The above filter returns the same frame for subsequent call of a constant frame number but different random contents for return visits. AddGrain had a similar problem in the past, iirc it now remembers the rand seed for each frame it returns so it can regenerate the identical sequence next time it is needed.
I had such an issue with ditheirng based on random noise :) It was used with encoder, which does store source information during 1st pass and than reports source change during 2nd pass. Good thing that this can be turned off- otherwise it would not encode 2nd pass :)
IanB
26th November 2012, 06:13
@kolak,
Good point, although Avisynth only expects repeatability from filters within the current session, it is advantageous for many users to have the output repeatable across sessions as well.
StainlessS
26th November 2012, 07:00
Thank you both very much for the input.
I shall implement the frame->GetWritePtr() mod and also give seed as an option, repeatable across sessions
(EDIT: Had intended to do that anyway, so that a test can be repeated).
Was in a hurry to get this working ok, as I need to test across multiple colorspaces/croppings and
also because of coordinates being variable down to a single pixel x/y/w/h, its a lot of testing needed.
(got a GScript/RT_Stats script to auto test at a range of coordinates to compare with a previous version).
Also very tricky coping with mod 1 coords in ALL colorspaces including 2.6 ones (although will not be testable
unless compiled for such [EDIT: Except Y8]).
Got to ensure that its all working ok, before I start adding the interlaced planar arg which will make it even
more tricky to deal with 2.6 colorspaces and mod 1 coords.
Shall post here any update to above simple source filter as I dont think I've seen anything similar, at least not in full.
Again, thanks. :)
StainlessS
11th January 2013, 05:50
This seems to work ok:
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include "avisynth.h"
#define OUTBUG
#ifdef OUTBUG
int dprintf(char* fmt, ...) {
char printString[2048];
char *p=printString;
va_list argp;
va_start(argp, fmt);
vsprintf(p, fmt, argp);
va_end(argp);
for(;*p++;);
--p; // @ null term
if(printString == p || p[-1] != '\n') {
p[0]='\n'; // append n/l if not there already
p[1]='\0';
OutputDebugString(printString);
p[0]='\0'; // remove appended n/l
} else {
OutputDebugString(printString);
}
return p-printString; // strlen printString
}
#endif
class RandomSource : public IClip {
private:
const VideoInfo vi;
bool parity;
int last; // remember last frame generated
PVideoFrame frame;
//
//
const unsigned int UserSeed; // User supplied or random (time(0))
unsigned __int64 SetupSeed; // Used to setup WELLRNG512 random bits
//
unsigned int state[16]; // need initialize state to random bits
unsigned int index; // init should also reset this to 0
//
unsigned int GetSetupRand(void);
void InitWELLRNG512(unsigned int n);
unsigned int WELLRNG512(void);
//
public:
RandomSource(const VideoInfo& _vi,PVideoFrame _frame, bool _parity,unsigned int _userseed)
: vi(_vi), frame(_frame),parity(_parity),UserSeed(_userseed), last(-1) {}
~RandomSource(){}
void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) {}
const VideoInfo& __stdcall GetVideoInfo() { return vi; }
bool __stdcall GetParity(int n) { return (vi.IsFieldBased() ? (n&1) : false) ^ parity; }
void __stdcall SetCacheHints(int cachehints,int frame_range) {}
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};
PVideoFrame __stdcall RandomSource::GetFrame(int n, IScriptEnvironment* env) {
n = (n < 0) ? 0 : (n >= vi.num_frames) ? vi.num_frames - 1 : n; // Range limit
if(n != last) {
BYTE* p = frame->GetWritePtr(); // Try to reuse old frame
if (!p) {
frame = env->NewVideoFrame(vi); // Ditch old frame and create a new frame
p = frame->GetWritePtr();
}
InitWELLRNG512(n); // init
int i,size = frame->GetPitch() * frame->GetHeight();
for (i=0; i<size; i+=4) {
unsigned int rgb = WELLRNG512() & 0x00FFFFFF;
*((unsigned int*)(p+i)) = rgb;
}
last = n; // Remember last generated frame number
}
return frame;
}
unsigned int RandomSource::GetSetupRand(void) {
// http://en.wikipedia.org/wiki/Linear_congruential_generator
// Numbers by Donald Knuth, MMIX.
//
// X_n+1 equiv ( a * X_n + c ) % m
//
unsigned __int64 a = 6364136223846793005;
unsigned __int64 c = 1442695040888963407;
// m = 2 ^ 64
SetupSeed = (a * SetupSeed + c); // % m (2 ^ 64)
return (unsigned int)(SetupSeed >> 32); // Hi 32 bits, (most randomized bits)
}
void RandomSource::InitWELLRNG512(unsigned int n) {
SetupSeed = (n + 1) * 4562693 + UserSeed; // init the setup seed (4562693 prime picked out of the hat)
int i;
for(i=0;i<13;++i) // Kick it through a few iterations
GetSetupRand();
for(i=0;i<16;++i) {
state[i]= GetSetupRand(); // Initialise WELLRNG512
}
index = 0; // All systems GO!
for(i=0;i<7;++i) // Kick main rand generator through a few iterations Too
WELLRNG512();
}
unsigned int RandomSource::WELLRNG512(void) { // return 32 bit random number
// Public Domain, Chriss Lomont @ http://www.lomont.org : Feb 8 2008.
unsigned long a, b, c, d;
a = state[index];
c = state[(index+13) & 15];
b = a^c^(a<<16)^(c<<15);
c = state[(index+9) & 15];
c ^= (c>>11);
a = state[index] = b^c;
d = a^((a<<5) & 0xDA442D24UL);
index = (index + 15) & 15;
a = state[index];
state[index] = a^b^d^(a<<2)^(b<<18)^(c<<28);
return state[index];
}
static AVSValue __cdecl Create_RandomSource(AVSValue args, void*, IScriptEnvironment* env) {
int userseed = args[0].AsInt(0); // userseed defaults to 0 (ALWAYS SAME)
if(userseed == -1)
userseed = (int)(time(NULL));
#ifdef OUTBUG
dprintf("RandomSource: Seed = %d (0x%08X)\n",userseed,userseed);
#endif
VideoInfo vi;
memset(&vi, 0, sizeof(VideoInfo));
vi.width =640;
vi.height =480;
vi.fps_numerator =24;
vi.fps_denominator =1;
vi.num_frames =24*60*60;
vi.pixel_type =VideoInfo::CS_BGR32;
vi.SetFieldBased(false);
bool parity=false;
PVideoFrame frame = env->NewVideoFrame(vi); // Create initial frame
return new RandomSource(vi,frame, parity,(unsigned int)userseed);
}
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("RandomSource","[seed]i",Create_RandomSource, 0);
return "`RandomSource' RandomSource plugin";
}
RandomSource(int "seed"=0)
Random seed if 'seed' == -1, [time(NULL)].
Uses fixed seed if not supplied (0).
Otherwise uses user supplied seed.
Random seed (-1), frames repeatable within current session,
Supplied seed (or default 0) , repeatable across sessions.
Creates 640x480@24FPS RGB32, 1 hour (86400 frames, 24*60*60).
StainlessS
11th January 2013, 21:54
Changed defaults, default seed now 0, so that user need NOT supply a seed to get repeatable frames across sessions.
Seed -1, now sets the randomized seed [time(0)].
Other supplied seeds set that value seed.
We also now, kick the main rand genny through a few iterations in init routine.
See updated previous post.
EDIT: Can anyone else see vertical lines in the random frames, or is it my imagination ?
EDIT: Closed VDubMod (100% zoom), opened in current VD, no vertical lines. Re-opened in VDMod again, lines gone. Go figure.
StainlessS
29th October 2015, 01:28
I dont seem to have provided this as a plugin, only source, so here is usable dll, See Mediafire in sig (32KB, Incl source)
RandomSource(clip c,Int "seed"=0)
RandomSource creates 640x480 24FPS RGB32 @ 24*60*60 frames (1 hour).
Seed, Default 0 ( = always same). -1, Random Seed, other supplied seeds set that value seed (again, same every time).
EDIT: No audio.
See Mediafire in sig below for dll + source.
EDIT: Now posted in Usage forum, with additional args for Length, width and Height:- https://forum.doom9.org/showthread.php?p=1862844#post1862844
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.