User Tools

Site Tools


tutorial:writing_your_own_filter

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
tutorial:writing_your_own_filter [2010/04/13 19:52]
meanadmin created
tutorial:writing_your_own_filter [2012/11/11 08:51] (current)
Line 1: Line 1:
 +====== Writing your own filter ======
  
-This page tries to explain how to write your own filter+This page tries to explain how to write your own filter.
  
-======  ​Setup & Tools  ======+===== 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)+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). +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++.+MSVC will not work as there will be some C++ links and MSVC C++ is incompatible with g++.
  
  
-======  ​Everything is a class  ======+===== Everything is a class =====
  
-All filters inside ​avidemux ​are derivative of AVDMGenericVideoStream class. +All filters inside ​Avidemux ​are derivative of AVDMGenericVideoStream class. 
-Only a few methods need to be defined :+Only a few methods need to be defined:
  
-======  ​The constructor ​ ====== +===== The constructor ===== 
-It takes 2 arguments + 
-  ​The previous filter in the chain, it will be copied into _in +It takes 2 arguments: 
-  ​CONFcouple * couples which contains the configuration. It it is null it means you have to use your default value.+  ​The previous filter in the chain, it will be copied into _in 
 +  ​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. 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()+If you dont change fps nor width/​height you can just copy the one from the previous filter using _in<​nowiki>​-></​nowiki>​getInfo().
  
 You should have a field of your class named _param which is a structure describing your parameters. You should have a field of your class named _param which is a structure describing your parameters.
-For example +For example
-  typedef struct rotateParam + 
-   ​+<code cpp> 
-     ​uint32_t angle; +typedef struct rotateParam 
-   ​}rotateParam;​+ { 
 +   ​uint32_t angle; 
 + ​}rotateParam;​ 
 +</​code>​ 
 In the constructor you can use the handy *GET* macro to retrive the parameter from CONFcouple In the constructor you can use the handy *GET* macro to retrive the parameter from CONFcouple
 e.g. GET(angle); e.g. GET(angle);
  
 +===== printConf =====
  
-======  ​printConf ​ ​======+The next method is printConf. It is used to print the configuration in the filter dialog box.
  
-the next method is printConf. It is used to print the configuration in the filter dialog box. +<code cpp> 
-  char *yourClassName::​printConf (void) +char *yourClassName::​printConf (void) 
-  {+{
   static char buf[[50]];   static char buf[[50]];
   sprintf ((char *) buf, " My rotate filter, angle :​%d",​_param->​angle);​   sprintf ((char *) buf, " My rotate filter, angle :​%d",​_param->​angle);​
   return buf;   return buf;
-  ​}+} 
 +</​code>​
  
 Note that the buffer is static to avoid allocating/​freeing it as it can be complicated. Note that the buffer is static to avoid allocating/​freeing it as it can be complicated.
  
-======  ​GetCouple ​ ====== +===== 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) +This method is used to retrieve the current configuration. The simplest way is to use the CSET macro like this: 
-  {+ 
 +<code cpp> 
 +uint8_t yourClassName::​getCoupledConf (CONFcouple ** couples) 
 +{
   ADM_assert (_param);   ADM_assert (_param);
   *couples = new CONFcouple (1); // Number of param in your structure   *couples = new CONFcouple (1); // Number of param in your structure
Line 57: Line 66:
   CSET (angle);   CSET (angle);
   return 1;   return 1;
-  ​}+} 
 +</​code>​
  
-getCoupledConf and the constructor are a pair. +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.
-It is vital they use the same number of parameters and the same parameter names. +
-Else you will have asserts popping.+
  
-======  ​Configure ​ ======+===== Configure =====
  
-  ​uint8_t yourClassName::​configure (AVDMGenericVideoStream * in)+<code cpp>uint8_t yourClassName::​configure (AVDMGenericVideoStream * in)</​code>​
  
 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. 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 ​and is quite simple to use. +It is recommended (strongly) to use dialogFactory as it will work on both GTKand Windows (Qt) and is quite simple to use. 
-Some infos + 
-  * Returning 0 means nothing has changed+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.   * 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!+**Important**: The change must be done immediately in configure!
  
-======  ​getFrameNoAlloc ​ ======+===== getFrameNoAlloc =====
  
 This is the central method as the work will be done here. This is the central method as the work will be done here.
  
-  ​uint8_t yourClassName::​getFrameNumberNoAlloc (uint32_t inframe, +<code cpp> 
-                                uint32_t * len, +uint8_t yourClassName::​getFrameNumberNoAlloc (uint32_t inframe, 
-                                ADMImage * data, uint32_t * flags)+                              uint32_t * len, 
 +                              ADMImage * data, uint32_t * flags) 
 +</​code>​
  
-len is the size in bytes of the output image. +**len** is the size in bytes of the output image. 
-flags can be ignored. +**flags** can be ignored. 
-inframe is the frame you have to render. +**inframe** is the frame you have to render. 
-data is the place when you have to render the frame.+**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. +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:
-In most case 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, +<code cpp> 
-                                uint32_t * len, +uint8_t yourClassName::​getFrameNumberNoAlloc (uint32_t inframe, 
-                                ADMImage * data, uint32_t * flags) +                              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(inframe<​_info.nb_frames);​ // Make sure we don't go out of bounds 
-    ADM_assert(_in->​getFrameNumberNoAlloc(inframe,​len,​_uncompressed,​flags));​ // Now _uncompressed contains the frame +  // Read frames for the previous 
-    // Flip from _uncompressed to data, which holds the final image +  ADM_assert(_in->​getFrameNumberNoAlloc(inframe,​len,​_uncompressed,​flags));​ // Now _uncompressed contains the frame 
-    Return 1; // ok +  // Flip from _uncompressed to data, which holds the final image 
-  }+  Return 1; // ok 
 +} 
 +</​code>​
  
-Some notes : +Some notes: 
-  * All images are in YV12 format  +  * 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+  * If you need several images to render one image out (3:2 pulldown, noise removal,​...),​ you should instantiate a VideoCache object.
  
-======  ​Declaring your filter ​ ======+===== Declaring your filter =====
  
-There is 2 ways of declaring your filter : bundled or plugin. +There are 2 ways of declaring your filter: bundled or plugin. You can do both at the same time, in the same file.
-You can do both at the same time, in the same file.+
  
-=====  ​Bundled filter ​ =====+==== Bundled filter ====
  
-Is is a bit more complicated. You have to :+Is is a bit more complicated. You have to:
   * Declare a tag for your filter in ADM_filter/​video_filters.h   * Declare a tag for your filter in ADM_filter/​video_filters.h
   * Register your filter in ADM_filter/​filter_declaration.cpp using    * 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) +<code cpp> 
-The second and 3rd parameters are the one used for display a,d brief +REGISTERX("​rotate","​Rotate","​Rotate the picture by 90, 180 or 270 degrees.",​VF_ROTATE,​1,​rotate_create,​rotate_script);​ 
-The Fourth ​one is the tag you declared above. ​DONT REUSE AN EXISTING TAG. You would have big problems, believe me.+</​code>​ 
 + 
 +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 The 2 last ones must be the same as the function described below
  
 Let's go back to our filter C++ file. Let's go back to our filter C++ file.
-First you need to declare a const which looks like  +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. +<code cpp>static FILTER_PARAM yourfilter_param =  { 1,"​angle"​};​</​code>​ 
-Then use these two macros :+ 
 +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);​ +<code cpp> 
-  SCRIPT_CREATE (rotate_script,​ yourClassName,​ yourfilter_param);​+BUILD_CREATE (rotate_create,​ yourClassName);​ 
 +SCRIPT_CREATE (rotate_script,​ yourClassName,​ yourfilter_param);​ 
 +</​code>​
  
 Make sure the first parameter of these two macros match the one you used in REGISTERX. Make sure the first parameter of these two macros match the one you used in REGISTERX.
  
-That's all :).+That's all :-).
  
-=====  ​Plugin ​ =====+==== Plugin ====
  
 It is simpler. It is simpler.
-You still have to declare the const which looks like  +You still have to declare the const which looks like
-  static FILTER_PARAM yourfilter_param =  { 1,"​angle"​};​ +
-Then +
  
-  ​extern "​C"​+<code cpp>​static FILTER_PARAM yourfilter_param =  { 1,"​angle"​};</​code>​ 
 + 
 +Then 
 + 
 +<code cpp> 
 +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)
   {   {
-    ​SCRIPT_CREATE(FILTER_create_fromscript,​yourClassName,​yourfilter_param);​ +    return ADM_FILTER_API_VERSION; ​
-    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; ​ +
-   }+
   }   }
 +}
 +</​code>​
  
 It is self contained, you don't have to change any file in ADM_filter/​xxx if it just a plugin. 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.+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  ======+===== Final words =====
  
 The simplest it to start from the ADM_filter/​ADM_vidDummyFilter.cpp which is a very simple filter you can build using The simplest it to start from the ADM_filter/​ADM_vidDummyFilter.cpp which is a very simple filter you can build using
-  sh builddummy.sh on unix 
-or  
-  sh builddummy_win32.sh on windows (you may have to change the path/names for your gcc) 
  
-The main differences with avisynth are : +//​sh(nbsp)builddummy.sh//​ on Unix
-  * Image format is always yv12 +
-  * stride=width +
-  * You don't return the frame, it is given to you by the caller as argument+
  
 +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.1271181136.txt.gz · Last modified: 2012/11/11 08:51 (external edit)