Tutorial step 3: building the DLL and testing the filter

We have all that's necessary for a bare VirtualDub filter, and in fact, if this were an internal filter, all that would be left is to add the filterDef_tutorial structure to the list in f_list.cpp. However, for this filter to be loaded externally, we need to add the necessary DLL framework.

Module load and unload functions

VirtualDub requires that filter DLLs export two functions:

Function VirtualdubFilterModuleInit2(fm: PFilterModule; const ff: PFilterFunctions; var vdfd_ver: Integer; var vdfd_compat: Integer): Integer; cdecl;

Procedure VirtualdubFilterModuleDeinit(fm: PFilterModule; const ff: PFilterFunctions); cdecl;

These functions must be exported undecorated, that is, not as _VirtualdubFilterModuleInit@12 or some mess of C++ decorations. Note also at the functions start with Virtualdub, with the second d uncapitalized.

The purpose of the init routines is to add/remove filters from VirtualDub's global list when the DLL loads and unloads, and to perform any necessary module-level initialization. Preferably, module-level initialization should be kept to a minimum to reduce resource usage when the module's filters are loaded but unused. Usually, the init/deinit functions need only call ff->addFilter() and ff->removeFilter().

The init function returns non-zero on failure, but VirtualDub does not remove any filters you have already added. With multiple filters, you must back out any filters you have already added if you wish to fail because not all filters could be loaded.

Init functions also have one other purpose: they allow VirtualDub to detect if a filter uses an old, incompatible interface.  The vdfd_ver variable holds the current interface version, and the vdfd_compat holds the earliest version that this build of VirtualDub is backwards compatible with.  Before returning, set them with the versions in your header files:

vdfd_ver := VIRTUALDUB_FILTERDEF_VERSION;
vdfd_compat := VIRTUALDUB_FILTERDEF_COMPATIBLE;

If your filter uses an interface version which the current version of VirtualDub cannot support, VirtualDub will abort the filter load and notify the user.

VIRTUALDUB_FILTERDEF_COMPATIBLE specifies the minimum version of VirtualDub that can handle the basic filter API.  This does not mean that all functions specified in the header file are available.  If you use features that are not supported in API V4 (V1.2), you must either hardcode a higher API level for vdfd_compat, or check vdfd_ver and avoid calling functions if they are not provided by the host.

Creating the load and unload functions for the tutorial filter

Because tutorial only has one filter in its module, the functions are fairly straightforward:

Var
 fd_tutorial: PFilterDefinition;

Function VirtualdubFilterModuleInit2(fm: PFilterModule; const ff: PFilterFunctions; var vdfd_ver: Integer; var vdfd_compat: Integer): Integer; cdecl;
begin {VirtualdubFilterModuleInit2}
fd_tutorial := nil;
fd_tutorial := ff^.addFilter(fm, @filterDef_tutorial, sizeof(TFilterDefinition));
if fd_tutorial = nil then Result := 1;
vdfd_ver := VIRTUALDUB_FILTERDEF_VERSION;
vdfd_compat := VIRTUALDUB_FILTERDEF_COMPATIBLE;
Result := 0;
end; {VirtualdubFilterModuleInit2}

Procedure VirtualdubFilterModuleDeinit(fm: PFilterModule; const ff: PFilterFunctions); cdecl;
begin {VirtualdubFilterModuleDeinit}
ff^.removeFilter(fd_tutorial);
end; {VirtualdubFilterModuleDeinit}

Exports
 VirtualdubFilterModuleInit2,
 VirtualdubFilterModuleDeinit;

Because the FilterDefinition record may expand later, VirtualDub returns a new definition pointer when the filter is added. This pointer is the record that VirtualDub uses, and is the one that needs to be passed to the removeFilter function.

Building and testing the filter

Create a new Win32 DLL project if you haven't already, and throw all the code so far into a file along with uses VdFilter;. Compile and build a DLL file out of it. If you used the directive {$E .vdf}, the output file will already have the ".vdf" extension. Otherwise rename the output DLL to tutorial.vdf. Right now your delphi project file should look like this.
Now load VirtualDub, select Video > Filters. Click Add..., and then Load... to load the filter. If you're lucky, the filter will appear on the list, and you can use it to process video files!