Tutorial step 8: Adding job (batch) support |
|
Only one major feature is missing from our filter: job support. As it stands, our filter will revert to default parameters if it is used in a batch operation. Time to fix that. How VirtualDub batch operation works with filtersIf you look in a virtualdub.jobs file, you'll find lines like this:
VirtualDub.video.filters.Add("rotate2");
VirtualDub.video.filters.instance[0].Config(233017,2);
The first line adds the filter to the list, while the second configures filter-specific parameters. Your filter is responsible for the second line only, through the script_obj and fssProc fields of the FilterDefinition record. When the job is run, the lines are interpreted by a primitive C-like scripting language called Sylia. The tutorial filter will interface to Sylia and add methods to the VirtualDub object tree. Custom objects in the Sylia scripting languageThis is the CScriptObject record:
CScriptObject = packed record An object can hold methods, other objects, or even variables. Because of limitations on the configuration strings that filters can generate, we're only interested in adding Config functions to our object, and thus the Lookup and obj_list will be NULL. func_list points to an array of function definitions:
PScriptfunctionDef = ^ScriptfunctionDef; arg_list describes the function's return type and parameters. The first character should be 0 (zero) for void; subsequent characters should be i for an int and s for a string. Thus, "0iis" becomes the function template (int, int, string). You can also end the parameter list with . (period) to specify a variable argument list; anything will do for the remainder. To specify overloaded members, add one entry with a name and an arg_list, and follow up with more entries that have NULL for name. The script interpreter will pick the first one that fits. End the function list with an all NULL entry. A member list might look like this:
ScriptFunctionDef tutorial_func_defs[]={
{ (ScriptFunctionPtr)tutorialScriptConfig, "Config", "0ii" },
{ (ScriptFunctionPtr)tutorialScriptConfig, NULL, "0iii." },
{ (ScriptFunctionPtr)tutorialScriptConfig, NULL, "0is" },
{ NULL },
};
Const
tutorial_func_defs: Array [1..3] of TScriptFunctionDef = (
(func_ptr: tutorialScriptConfig; name: 'Config'; arg_list: '0ii'),
(func_ptr: tutorialScriptConfig; name: nil; arg_list: '0iii.'),
(func_ptr: tutorialScriptConfig; name: nil; arg_list: '0is'));
This defines three methods: void Config(int, int), void Config(int, int, int, ...), and void Config(int, string). All definitions point to the same handler, which would have to check the parameter types to discover which signature fits. Implementing the Config functionAll Config script functions have the following prototype: function configScriptProc(isi: PIScriptInterpreter; fa: PFilterActivation; argv: PCScriptValue; argc: Integer): PCScriptValue; cdecl; fa gives your access to the filter's instance data pointer and argc/argv contains the input parameters. The parameter argv points to an array containing the several arguments passed to the script function. Each element of the array is a CObj_CScriptValue instance object. Use the following TCScriptValue class methods to get information from each argument.
Of course, argc is the argument count. The parameter list is guaranteed to fit one of the signatures specified for this function, so often it's easiest to point all the overloaded members to a single function, and use the is* functions to determine which signature is being used. Implementing the fssProc functionfssProc's job is to generate the script function call and has this prototype: function fssProc(fa: PFilterActivation; const ff: PFilterfunctions; buf: PChar; maxlen: Integer): Boolean; cdecl; This function should supply the buffer to StrCopy or StrLCopy when generating the config string. VirtualDub provides the string up to instance[n]. and the semicolon, so fssProc need only fill buf with Config(...). For instance, a resampling filter with a size of 240x180 might fill buf with this: Config(240,180) fssProc should normally return true. If fssProc returns false, VirtualDub ignores buf and discards the entire configuration line. This is useful if the filter instance hasn't been changed from the default configuration. Note that you must be careful when adding strings to your configuration function. In particular, watch out for backslashes and quotes. Sylia understands vC/C++ escape sequences, so the safest bet is preprocessing those characters into \" and \\. If you must include binary data, the best bet is to encode the data into a safe format such as MIME BASE64. Adding script support to the tutorial filterWe'll use a Config(int, int) script function to control our filter, with one int for each flag:
Function tutorialFssProc(fa: PFilterActivation; const ff: PFilterFunctions; buf: PChar; maxlen: Integer): Boolean; cdecl; Now, the implementation of the Config function:
Function tutorialScriptConfig(isi: PIScriptInterpreter; fa: PFilterActivation; argv: PCScriptValue; argc: Integer): PCScriptValue; cdecl; Finally, add the scripting support to the FilterDefinition struct:
Const And that's it. You have finished your first complete filter. Your final project file should look like this. Additional notes
|
© 2005 Fernando Reis < >Adapted from VirtualDub external filter SDK 1.05 documentation © 1999-2001 Avery Lee |