videofilt_makingafilterconfigurable - shekh/VirtualDub2 GitHub Wiki

VirtualDub Plugin SDK 1.2

Making a filter configurable

Once you have a video filter up and running, it's useful to replace hard-coded constants in the filter with configurable parameters. This makes it easier to tune those parameters and also exposes more control to end users.

The configProc entry point

configProc is the entry point used for interactive configuration of a filter. It is the only entry point in a video filter which is allowed to display UI. Typically, the main action performed by configProc is to display a modal dialog:

#include <windows.h>
#include "resource.h"

HINSTANCE g_hInst;

INT_PTR CALLBACK MyDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) {
    MyData *data = (MyData *)GetWindowLongPtr(hdlg, DWLP_USER);
    switch(msg) {
        case WM_INITDIALOG:
            SetWindowLongPtr(hdlg, DWLP_USER, (LONG_PTR)lParam);
            data = (MyData *)lParam;
            
            CheckDlgButton(hdlg, IDC_ACTIVE, data->active ? BST_CHECKED : BST_UNCHECKED);
            return TRUE;
            
        case WM_COMMAND:
            switch(LOWORD(wParam)) {
                case IDOK:
                    data->active = (0 != IsDlgButtonChecked(hdlg, IDC_ACTIVE));
                    EndDialog(hdlg, true);
                    return TRUE;
                    
                case IDCANCEL:
                    EndDialog(hdlg, false);
                    return TRUE;
            }
            break;
    }
    
    return FALSE;
}
        
int configProc(VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hwndParent) {
    MyData *data = (MyData *)fa->filter_data;
    
    return !DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_MY_DIALOG), (HWND)hwndParent, MyDlgProc, (LPARAM)data);
}

The example above constructs a modal dialog by direct Win32 UI programming, which understandably can be somewhat cumbersome. Feel free to use whatever UI toolkit you desire, just as long as you keep the following in mind:

  • Configuration parameters should not be stored in global variables. There may be multiple instances of your filter in the same filter chain, each with different configuration values.
  • configProc should return a non-zero value when the user clicks Cancel (note that this is an error code convention, reversed from the usual true-for-success convention). This is used by the host to determine when a filter hasn't been configured. Current versions of VirtualDub display the configuration dialog for a filter instance automatically on add, and will auto-delete the instance if the dialog is cancelled. Failing to return the correct code will cause strange behavior here.
  • If the user clicks Cancel, the configuration parameters in the instance data should not be changed. This was accomplished above by delaying data exchange until the IDOK button command, but an alternate way is to copy off the data prior to invoking the dialog and restore it afterward on cancellation. This is useful for filter preview, which is described later.
  • VDXHWND is an alias for HWND used to reduce header dependencies on <windows.h>; it can be casted as such.
  • Some Win32 UI examples use NULL for the HINSTANCE parameter passed to UI functions. This will not work in a video filter, since filters are implemented in DLLs. Your filter should implement a DllMain() function instead and store the DLL's HINSTANCE in a global variable, or use another method of obtaining the DLL's instance handle.
  • If you use Win32 common controls, make sure your filter DLL calls InitCommonControls() or equivalent to ensure that comctl32 is pulled in. VirtualDub does this, but hosts are not required to do so.

V11+ only: fa->src is guaranteed to be set up prior to calling configProc. This can be used in the configuration dialog UI to base parameters on the input video, such as providing a relative size parameter.

Displaying a configuration blurb

The stringProc2 method allows the filter to expose a short, user-readable blurb that briefly describes the filter's configuration. The host can use this in filter chain lists to allow the user to scan the configuration of each filter at a glance. stringProc2 simply produces a short string:

static void stringProc2(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen) {
    MyData *mfd = (MyData *)fa->filter_data;

    _snprintf(buf, maxlen, " (%s)", mfd->enabled ? "enabled" : "disabled");
}

Not every parameter needs to be exposed in the blurb, as it's for visual scanning only and is never interpreted by program code other than to display to the user.

V1-V7 only: Older versions of the filter API only support the stringProc entry point, which serves the same purpose but does not provide a buffer size. You should always support stringProc2 for reliability, but you can support older host versions as well by implementing stringProc in terms of stringProc2 with a small hardcoded buffer size of 80.

Interactive filter preview

By using the fa->ifp field in the VDXFilterActivation structure, it is possible for the user to interactively view results of changing filter parameters. This is accomplished by running the filter while its configuration dialog is displayed. The host automatically manages the UI for the preview window, easing implementation in the filter. The steps to get this working are as follows:

  • Check if fa->ifp is NULL. It may not be available if no video is loaded.

  • Copy fa->ifp to a location accessible by the dialog procedure code.

  • Call IVDXFilterPreview::InitButton() to associate filter preview with a button on your dialog. By doing this, the host will automatically toggle the button's caption text between "Show preview" and "Hide preview" automatically as the preview window is opened and closed.

    VirtualDub 1.7.0 and later: VirtualDub attempts to preserve any existing keyboard shortcuts prefixed by & in the existing button caption.

  • When the button is clicked, call IVDXFilterPreview::Toggle() with the window handle of your dialog. The window handle is used as the owner for the preview window, so that it always appears above the filter dialog.

  • Call IVDXFilterPreview::SetButtonCallback() to be notified when the preview window is opened or closed. This can be used to implement custom button change behavior.

  • IVDXFilterPreview::Display() can be used to explicitly control the display of the preview window.

  • IVDXFilterPreview::Close() closes the preview window and breaks any existing connection to a preview button.

  • When a configuration parameter is changed, call IVDXFilterPreview::RedoFrame() to cause the current frame to be refiltered and redisplayed. This means that you do need to change the filter parameters directly on the fa->filter_data structure. Make sure any unwanted changes are rolled back if the dialog is cancelled.

  • For changes that require the filter chain to be reconstructed, such as changes in frame size, call IVDXFilterPreview::UndoSystem() prior to effecting the change, and IVDXFilterPreview::RedoSystem() afterward.

  • V11+ only: fa->ifp2 provides the IVDXFilterPreview2 interface, which can be used to query if the preview window is currently displayed.

Sampling the input video

The sampling functionality in the filter API allows your configuration dialog to process frames in the input video and use it to augment the UI. For instance, a filter designed to modify image luminance levels can analyze a video frame and display a histogram to aid the user in setting appropriate ranges, or even automatically set the parameters based on image analysis.

To implement sampling:

  • Implement filter preview first. The preview UI is required for sampling to be used.

  • Add sampling buttons to your UI. Two buttons are needed, one for sampling the current frame, and the other for sampling the whole video. You may want to implement the button callback in order to enable those buttons only when the preview display is updated.

  • Implement a sampling callback and hook it up via IVDXFilterPreview::SetSamplingCallback().

  • Call IVDXFilterPreview::SampleCurrentFrame() or IVDXFilterPreview::SampleFrames() whenever the appropriate button is pressed.

  • The sampling callback is invoked for each frame processed during the sampling operation.

    VirtualDub specific: The SampleFrames() function displays UI allowing the user to sample only a subset of the frames in the video for speed. This occurs invisibly without the filter knowing.

Note that it is not possible for the filter to autonomously request frames — sampling must always be driven by the user through the filter preview UI.

V12+ only: The format of the video frames passed to the filter is the one negotiated by the filter's paramProc routine, since the filter chain is always running when sampling occurs. If your filter accepts non-RGB formats, your sampling routine must also accept them as well.


Copyright (C) 2007-2012 Avery Lee.

⚠️ **GitHub.com Fallback** ⚠️