This page tries to explain how to write your own filter.
First of all you need Avidemux sources (if you do plugins you don't even have to compile Avidemux itself but you still need the sources).
For windows, you need MinGW GCC/g++ (v4.x) or cygwin GCC/g++ (v4.x). MSVC will not work as there will be some C++ links and MSVC C++ is incompatible with g++.
All filters inside Avidemux are derivative of AVDMGenericVideoStream class. Only a few methods need to be defined:
It takes 2 arguments:
The constructor has to update its _info field which contains a description of the output format. If you dont change fps nor width/height you can just copy the one from the previous filter using _in->getInfo().
You should have a field of your class named _param which is a structure describing your parameters. For example:
typedef struct rotateParam { uint32_t angle; }rotateParam;
In the constructor you can use the handy *GET* macro to retrive the parameter from CONFcouple e.g. GET(angle);
The next method is printConf. It is used to print the configuration in the filter dialog box.
char *yourClassName::printConf (void) { static char buf[[50]]; sprintf ((char *) buf, " My rotate filter, angle :%d",_param->angle); return buf; }
Note that the buffer is static to avoid allocating/freeing it as it can be complicated.
This method is used to retrieve the current configuration. The simplest way is to use the CSET macro like this:
uint8_t yourClassName::getCoupledConf (CONFcouple ** couples) { ADM_assert (_param); *couples = new CONFcouple (1); // Number of param in your structure #undef CSET #define CSET(x) (*couples)->setCouple(#x,(_param->x)) CSET (angle); return 1; }
getCoupledConf and the constructor are a pair. It is vital they use the same number of parameters and the same parameter names. Else you will have asserts popping.
uint8_t yourClassName::configure (AVDMGenericVideoStream * in)
This method is used to configure the filter. The parameter is the same as for the constructor. It is safer to update _in with it though. It is recommended (strongly) to use dialogFactory as it will work on both GTK+ and Windows (Qt) and is quite simple to use.
Some info:
Important: The change must be done immediately in configure!
This is the central method as the work will be done here.
uint8_t yourClassName::getFrameNumberNoAlloc (uint32_t inframe, uint32_t * len, ADMImage * data, uint32_t * flags)
len is the size in bytes of the output image. flags can be ignored. inframe is the frame you have to render. data is the place when you have to render the frame.
Remember that the filters are a chain, so each filter may ask for (any) frame to its predecessor. In most cases you will want to allocate a temporary buffer in the constructor (which is often called _uncompressed) and ask the previous filter to fill it for you. For example, the verticalFlip can be simplified like that:
uint8_t yourClassName::getFrameNumberNoAlloc (uint32_t inframe, uint32_t * len, ADMImage * data, uint32_t * flags) { ADM_assert(inframe<_info.nb_frames); // Make sure we don't go out of bounds // Read frames for the previous ADM_assert(_in->getFrameNumberNoAlloc(inframe,len,_uncompressed,flags)); // Now _uncompressed contains the frame // Flip from _uncompressed to data, which holds the final image Return 1; // ok }
Some notes:
There are 2 ways of declaring your filter: bundled or plugin. You can do both at the same time, in the same file.
Is is a bit more complicated. You have to:
REGISTERX("rotate","Rotate","Rotate the picture by 90, 180 or 270 degrees.",VF_ROTATE,1,rotate_create,rotate_script);
The first parameter is the internal name (must be unique). The second and 3rd parameters are the one used for display a,d brief. The fourth one is the tag you declared above. DON'T REUSE AN EXISTING TAG. You would have big problems, believe me. The 2 last ones must be the same as the function described below
Let's go back to our filter C++ file. First you need to declare a const which looks like
static FILTER_PARAM yourfilter_param = { 1,"angle"};
The first parameter is the number of parameters in your param structure followed by the parameters name, EXACTLY like in your structure. Then use these two macros:
BUILD_CREATE (rotate_create, yourClassName); SCRIPT_CREATE (rotate_script, yourClassName, yourfilter_param);
Make sure the first parameter of these two macros match the one you used in REGISTERX.
That's all .
It is simpler. You still have to declare the const which looks like
static FILTER_PARAM yourfilter_param = { 1,"angle"};
Then
extern "C" { SCRIPT_CREATE(FILTER_create_fromscript,yourClassName,yourfilter_param); BUILD_CREATE(FILTER_create,yourClassName); char *FILTER_getName(void) { return "DynRotate"; // Name of your filter. must be unique! } char *FILTER_getDesc(void) { return "Blah blah"; // Short description of your filter } uint32_t FILTER_getVersion(void) { return 1; // Version of your filter } uint32_t FILTER_getAPIVersion(void) { return ADM_FILTER_API_VERSION; } }
It is self contained, you don't have to change any file in ADM_filter/xxx if it just a plugin. You can do both declaration in the same file, so that it can be bundled inside Avidemux or compiled as a plugin filter.
The simplest it to start from the ADM_filter/ADM_vidDummyFilter.cpp which is a very simple filter you can build using
sh(nbsp)builddummy.sh on Unix
or
sh(nbsp)builddummy_win32.sh on Windows (you may have to change the path/names for your gcc).
The main differences with Avisynth are: