Using GDI in VirtualDub video filters

Usually, you will not want to use GDI (Graphics Device Interface) to handle video data.  GDI's output is often not antialiased and sometimes even broken (StretchBlt with RGB555 bitmaps).  Under Windows 95/98, GDI is also very slow.  In most cases, you will get much better performance by using VirtualDub's routines or rolling your own.

There is one task for which you will want to use GDI: font rendering.  To do this, you will need to request a GDI display context (DC) to VirtualDub's framebuffers.

Avisynth does not support display contexts at all in its emulation layer, and Nina's refcounting architecture will likely require additional buffer copies to emulate DC support -- so use this feature with caution.

Requesting GDI display context handles

If you need a DC for either your input or output buffer, request it in your paramProc function by setting the NEEDS_HDC flag in the TVFBitmap structure:

fa^.src^.dwFlags := TVFBitmap.NEEDS_HDC;

You can request a DC for the source buffer, the destination buffer, or both.  VirtualDub will now pass you a valid HDC through the fa^.src^.hdc and/or fa^.dst^.hdc variables.

Using the GDI display context handles

Delphi encapsulates the Windows GDI at two levels. At the first level, you can call GDI functions directly, in which case you need to have a handle to a device context, into which you select various drawing tools such as pens, brushes, and fonts. In this case you will use the handle in fa^.src^.hdc or fa^.dst^.hdc. After rendering your graphic image, you must restore the device context to its original state before disposing of it.

var
  PenHandle, OldPenHandle: HPEN;
  BrushHandle, OldBrushHandle: HBRUSH;
begin
  PenHandle := CreatePen(PS_SOLID, 1, RGB(0, 0, 255)); { create blue pen }
  OldPenHandle := SelectObject(fa^.dst^.hdc, PenHandle); { tell DC to use blue pen }
  BrushHandle := CreateSolidBrush(RGB(255, 255, 0)); { create a yellow brush }
  OldBrushHandle := SelectObject(fa^.dst^.hdc, BrushHandle); { tell DC to use yellow brush }
  Ellipse(fa^.dst^.hdc, 10, 10, 50, 50); { draw the ellipse }
  SelectObject(fa^.dst^.hdc, OldBrushHandle); { restore original brush }
  DeleteObject(BrushHandle); { delete yellow brush }
  SelectObject(fa^.dst^.hdc, OldPenHandle); { restore original pen }
  DeleteObject(PenHandle); { destroy blue pen }
end;

At the second level, you can use the TCanvas class which encapsulates a Windows device context and handles all drawing for both forms, visual containers (such as panels) and the printer object. Using the canvas object, you no longer have to worry about allocating pens, brushes, palettes, and so on — all the allocation and deallocation are handled for you. The TCanvas object also protects you against common Windows graphics errors, such as restoring device contexts, pens, brushes, and so on to the value they had before the drawing operation.

var
  aCanvas: TCanvas;
begin
  aCanvas := TCanvas.Create;
  aCanvas.Handle := fa^.dst^.hdc;
  aCanvas.TextOut(10, 10, 'Some text.');
  aCanvas.Free;
end;

Caveats

Your DC handles may be shared with the previous and next filters if they have also requested DC handles.  For this reason, you must treat your DC handles as you would GetDC() handles: if you SelectObject() pens, brushes, etc. into the DC, you must restore the original objects before your runProc function terminates.  Do not change the mapping mode.

VirtualDub uses the clipping and origin-setting abilities of GDI to handle input clipping windows.  If you use clipping regions, be sure to intersect new regions with the existing region, and do not call SelectClipRgn(NULL); instead, restore the original clipping region.  You do not have to restore the clipping region before you exit.

Be sure you call GdiFlush before accessing the bitmap directly, calling VirtualDub bitmap functions, or exiting runProc.  This ensures that GDI has completed all drawing to the bitmap.

Rendering text into VirtualDub bitmaps

Fonts pose a special problem because Windows treats memory DCs differently than display DCs when rendering antialiased fonts.  Windows 95/98 will not render antialiased fonts to a memory DC, even if the font smoother is installed, but Windows NT will.  This means that simple text operations will result in better output under NT than under 95/98.  Even NT font rendering can be unsatisfactory, because the font renderer tweaks fonts to be visible at high resolutions, even if it involves less accurate renderings.  If quality is important -- or the font driver's antialiasing is causing problems -- then create a monochrome DIB, select it into a memory DC, and shrink the image yourself to render an antialiased font.  This is slower, but produces better font output.