User Tools

Site Tools


tutorial:writing_your_own_filter

Writing your own filter

This page tries to explain how to write your own filter.

Setup & tools

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++.

Everything is a class

All filters inside Avidemux are derivative of AVDMGenericVideoStream class. Only a few methods need to be defined:

The constructor

It takes 2 arguments:

  1. The previous filter in the chain, it will be copied into _in
  2. CONFcouple * couples which contains the configuration. It it is null it means you have to use your default value.

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);

printConf

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.

GetCouple

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.

Configure

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:

  • Returning 0 means nothing has changed.
  • Returning 1 means you have changes something and that the filter chain might have to be rebuild.

Important: The change must be done immediately in configure!

getFrameNoAlloc

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:

  • All images are in YV12 format.
  • If you need several images to render one image out (3:2 pulldown, noise removal,…), you should instantiate a VideoCache object.

Declaring your filter

There are 2 ways of declaring your filter: bundled or plugin. You can do both at the same time, in the same file.

Bundled filter

Is is a bit more complicated. You have to:

  • Declare a tag for your filter in ADM_filter/video_filters.h
  • Register your filter in ADM_filter/filter_declaration.cpp using
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 :-).

Plugin

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.

Final words

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:

  • Image format is always YV12.
  • stride=width
  • You don't return the frame, it is given to you by the caller as argument.
tutorial/writing_your_own_filter.txt · Last modified: 2012/11/11 08:51 (external edit)