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.
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 forHWND
used to reduce header dependencies on <windows.h>; it can be casted as such. - Some Win32 UI examples use
NULL
for theHINSTANCE
parameter passed to UI functions. This will not work in a video filter, since filters are implemented in DLLs. Your filter should implement aDllMain()
function instead and store the DLL'sHINSTANCE
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 thatcomctl32
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.
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.
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 thefa->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, andIVDXFilterPreview::RedoSystem()
afterward. -
V11+ only:
fa->ifp2
provides theIVDXFilterPreview2
interface, which can be used to query if the preview window is currently displayed.
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()
orIVDXFilterPreview::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.