Skip to content

videofilt_scriptingsupport

shekh edited this page Apr 15, 2018 · 1 revision

VirtualDub Plugin SDK 1.2

Scripting support

Video filters can expose a Config() method that allows scripts to control filter configuration values, without requiring user intervention. This is also required for your filter to work in batch mode (job control). It is highly recommended that any filter offering configurable parameters implement scripting/batch support.

Implementing the Config() method

To expose the script method, the script_obj field of the filter definition must be filled. This points to a script object definition, which describes the Config() method group exposed by the filter. Typically this just points to a function list:

VDXScriptObject script_obj = { NULL, script_functions, NULL };

The function list, in turn, describes all of the methods exposed in terms of a C/C++ handler function, name, and argument list:

VDXScriptFunctionDef script_functions[] = {
    { (VDXScriptFunctionPtr)configScriptFunc, "Config", "0i" },
    { NULL, NULL, NULL },
};

Normally, the function list only consists of one function entry and the NULL sentinel. The third argument describes the argument list to the script function, and consists of the first character, which describes the return type, and subsequent characters, which correspond to arguments. The return value should always be a zero (0) for void, while the argument characters can be i for integer or s for string.

V11+ only: Function parameters can also be of type 64-bit long (l) or double (d).

The function callback is called with a pointer to the script interpreter, filter activation context, arguments, and argument count:

static void configScriptFunc(IVDXScriptInterpreter *isi, void *lpVoid, VDXScriptValue *argv, int argc) {
    VDXFilterActivation *fa = (VDXFilterActivation *)lpVoid;

    MyData *mfd = (MyData *)fa->filter_data;

    mfd->width = argv[0].asDouble();
    mfd->height = atoi(*argv[1].asString());

    if (argc >= 3 && argv[2].isInt())
        mfd->mode = argv[2].asInt();
}

Note: Due to the cast when initializing the VDXScriptFunctionDef structure, it is possible to accidentally supply the wrong function prototype when declaring the function. Make sure that the prototype is correct, including the calling convention (__cdecl). The return value will vary depending on the return type specified in the function signature -- it should be void for a 0.

Creating the script line

Once the script method has been declared, an additional fssProc function must be supplied to emit the Config() script call describing the current configuration. This generally simply calls a printf() style function to generate the script line:

bool fssProc(VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int bufsize) {
    MyData *mfd = (MyData *)fa->filter_data;

    if ((unsigned)_snprintf(buf, buflen, "Config(%g, \"%d\", %d)"
            , mfd->width
            , mfd->height
            , mfd->mode) >= (unsigned)(bufsize - 1))
        return false;
    
    return true;
}

Note: Bounded versions of sprintf(), such as the VC++-specific _snprintf() call above, should be used to avoid a buffer overflow in case the script string is too large to fit.

Raising errors

The script interpreter checks argument types against the method prototypes specified in the function list, so it is not normally required for the handler function to check types manually. If the handler function does detect an error, it can raise the error by using the EXT_SCRIPT_ERROR() macro, which in turns calls the IVDXScriptInterpreter::ScriptError() method. This method throws a C++ exception and thus does not return.

In general, however, it is better to store the invalid parameters and flag the error on the startProc method. This allows for more friendly reporting and consolidates error handling logic in the filter.

Function overloading

Once a filter has been released, it may be necessary to update the filter's script interface in a way that is backwards compatible. This is done by overloading the Config() method with multiple argument lists:

VDXScriptFunctionDef script_functions[] = {
    { (VDXScriptFunctionPtr)configScriptFunc, "Config", "0i" },
    { (VDXScriptFunctionPtr)configScriptFunc, NULL, "0iis" },
    { NULL, NULL, NULL },
};

The Config name should only be specified for the first entry, with subsequent entries using NULL for the name. The handler function can be the same or different for each entry; if it is the same, the function must determine which prototype was used by checking the argument count and parameter types.

Once overloads have been declared, the script engine chooses the best match based on the arguments provided and the argument lists of each overload. If multiple methods match and no match is clearly better than the rest, an ambiguity error is raised and script execution fails.

Tip: Avoid declaring overloads that differ only in argument types of int, double, or long. This can produce unexpected ambiguities when the config string is emitted with numbers that are valid int values, such as zero. It is safest to extend the method list by adding parameters or by swapping numbers and strings.


Copyright (C) 2007-2012 Avery Lee.

Clone this wiki locally