Advanced Capture Application for C++

The following code demonstrates an advanced capture application. It utilizes most of the functions available in the ltmmCapture object.

// include the LEAD Multimedia TOOLKIT header
#include "ltmm.h"

#include "resource.h"
#include <tchar.h>
#include <stdio.h>
#include <olectl.h>
#include <math.h>
#include <assert.h>

#define SZ_WNDCLASS_CAPTURE _T("CAPTURE WNDCLASS")

#define WM_CAPTURENOTIFY (WM_USER + 1000)

HINSTANCE g_hInstance;    // application instance handle
HWND g_hwndCapture;      // video frame window
IltmmCapture* g_pCapture;      // capture object interface pointer

//
// FreeTarget
// resets target and free asssociated resources
//
void FreeTarget(void)
{
   long type;
   VARIANT var;

   g_pCapture->get_TargetType(&type);
   if(type == ltmmCapture_Target_Array)
   {
      g_pCapture->get_TargetArray(&var);
      g_pCapture->ResetTarget();
      VariantClear(&var);
   }
   else
   {
      g_pCapture->ResetTarget();
   }
}

//
// SnapFrameToVideo
// resizes the frame window to match the video width and height
//
void SnapFrameToVideo(void)
{
   HWND hwnd;
   RECT rcWindow, rcClient;
   long cx, cy;

   // get the frame window
   g_pCapture->get_VideoWindowFrame((long*) &hwnd);

   // get the video dimensions
   g_pCapture->get_VideoWidth(&cx);
   g_pCapture->get_VideoHeight(&cy);

   // adjust by the border dimensions
   GetWindowRect(hwnd, &rcWindow);
   GetClientRect(hwnd, &rcClient);
   cx += ((rcWindow.right - rcWindow.left) - (rcClient.right - rcClient.left));
   cy += ((rcWindow.bottom - rcWindow.top) - (rcClient.bottom - rcClient.top));

   // resize the window
   SetWindowPos(hwnd, NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER);
}

//
// CaptureWndProc
// video frame window procedure
//
LRESULT CALLBACK CaptureWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   VARIANT_BOOL f;
   HRESULT hr;
   HGLOBAL hDIB;
   IPictureDisp* pPictureDisp;
   BSTR bstr;

   IltmmDevices* pDevices;
   IltmmTargetDevices* pTargetDevices;
   long index;
   IltmmCompressors* pCompressors;
   long l;
   long l2;
   BOOL fActive;
   ltmmSizeMode sm;
   TCHAR sz[2048];
   LPTSTR p;
   double d;
   VARIANT var;
   long x, y, cx, cy;
   RECT rc;
   POINT pt;
   IltmmVCRControl* pVCR;

   switch (message) 
   {
   case WM_CREATE:
      g_hwndCapture = hwnd;

      // window is the video window frame
      g_pCapture->put_VideoWindowFrame((long) hwnd);


      // want notification messages as well
      g_pCapture->SetNotifyWindow((long) hwnd, WM_CAPTURENOTIFY);

      // set preview source video only
      g_pCapture->put_PreviewSource(ltmmCapture_Preview_Video);

      // enable preview
      g_pCapture->put_Preview(VARIANT_TRUE);

      // set preferred renderer
      g_pCapture->put_PreferredVideoRenderer(ltmmVideoRenderer_VMR9);

      // disable close captioning
      g_pCapture->put_CloseCaptioning(VARIANT_FALSE);

      // assign initial frame delay
      g_pCapture->put_FrameDelay(1.0);

      // assign a target file
      bstr = SysAllocString(L"c:\\target.avi");
      g_pCapture->put_TargetFile(bstr);
      SysFreeString(bstr);

      // select the LEAD video compressor
      g_pCapture->get_VideoCompressors(&pCompressors);
       bstr = SysAllocString(L"@device:sw:{33D9A760-90C8-11D0-BD43-00A0C911CE86}\\LEAD MCMP/MJPEG Codec  A COmpressor combined with a DECompressor, or encoder and a decoder, which allows you to both compress and decompress that same data.COmpressor Also known as an encoder, this is a module or algorithm to compress data. Playing that data back requires a decompressor, or decoder. combined with a DECompressor, or encoder Also known as compressor, this is a module or algorithm to compress data. Playing that data back requires a decompressor, or decoder. and a decoder Also known as a decompressor, this is a module or algorithm to decompress data., which allows you to both compress and decompress that same data. (2.0)");
      pCompressors->Find(bstr, &index);
      SysFreeString(bstr);
      if(index >= 0)
         pCompressors->put_Selection(index);
      pCompressors->Release();
   

      // select the MP3 audio video compressor
      g_pCapture->get_AudioCompressors(&pCompressors);
      bstr = SysAllocString(L"@device:cm:{33D9A761-90C8-11D0-BD43-00A0C911CE86}\\85MPEG Layer-3");
      pCompressors->Find(bstr, &index);
      SysFreeString(bstr);
      if(index >= 0)
         pCompressors->put_Selection(index);
      pCompressors->Release();

      // target format is AVI
      g_pCapture->put_TargetFormat(ltmmCapture_TargetFormat_Avi);

      // preallocate file to 10 MB
      g_pCapture->AllocTarget(10);

      // select the first audio device available
      g_pCapture->get_AudioDevices(&pDevices);
      pDevices->put_Selection(0);
      pDevices->Release();

      // select the first video device available
      g_pCapture->get_VideoDevices(&pDevices);
      pDevices->put_Selection(0);
      pDevices->Release();

      SnapFrameToVideo();

      return 0;
      break;

   case WM_CAPTURENOTIFY:
      switch(wParam)
      {
      case ltmmCapture_Notify_Started:
         _stprintf(sz, _T("Started"));
         SetWindowText(hwnd, sz);
         break;
      case ltmmCapture_Notify_Complete:
         // stop recording, if vcr output
         g_pCapture->get_TargetVCRControl(&pVCR);
         pVCR->Stop();
         pVCR->Release();

         g_pCapture->get_Mode(&l);
         if(l == ltmmCapture_Mode_Still)
         {
            _stprintf(sz, _T("Complete - [still]"));
         }
         else
         {
            g_pCapture->get_TargetType(&l);
            if(l == ltmmCapture_Target_Array)
            {
               _stprintf(sz, _T("Complete - [array]"));
            }
            else if(l == ltmmCapture_Target_Device)
            {
               _stprintf(sz, _T("Complete - [device]"));
            }
            else
            {
               g_pCapture->get_TargetFile(&bstr);
               _stprintf(sz, _T("Complete - [%ls]"), bstr);
               SysFreeString(bstr);
            }
         }
         SetWindowText(hwnd, sz);
         break;

      case ltmmCapture_Notify_ErrorAbort:
         // stop recording, if vcr output
         g_pCapture->get_TargetVCRControl(&pVCR);
         pVCR->Stop();
         pVCR->Release();

         _stprintf(sz, _T("Error 0x%.8X. Capture stopped."), lParam);
         MessageBox(hwnd, sz, _T("Play"), MB_ICONEXCLAMATION | MB_OK);
         break;

      case ltmmCapture_Notify_Progress:
         p = sz;

         *p = _T('\0');

         hr = g_pCapture->get_NumDropped(&l);
         if(SUCCEEDED(hr))
         {
            if(p != sz)
               p += _stprintf(p, _T(", "));
            p += _stprintf(p, _T("Dropped: %d"), l);
         }

         hr = g_pCapture->get_NumNotDropped(&l);
         if(SUCCEEDED(hr))
         {
            if(p != sz)
               p += _stprintf(p, _T(", "));
            p += _stprintf(p, _T("Not Dropped: %d"), l);
         }

         hr = g_pCapture->get_AverageFrameSize(&l);
         if(SUCCEEDED(hr))
         {
            if(p != sz)
               p += _stprintf(p, _T(", "));
            p += _stprintf(p, _T("Frame Size: %d"), l);
         }

         g_pCapture->get_Mode(&l);
         if(l != ltmmCapture_Mode_Still || l != ltmmCapture_Mode_ManualFrames)
         {
            // only display the capture time for free running captures
            hr = g_pCapture->get_CaptureTime(&d);
            if(SUCCEEDED(hr))
            {
               if(p != sz)
                  p += _stprintf(p, _T(", "));
               p += _stprintf(p, _T("Time: %f"), d);
            }
         }
         SetWindowText(hwnd, sz);
         break;
      }
      return 0;
      break;

   case WM_KEYDOWN:
      if(wParam == VK_ESCAPE)
      {
         // if fullscreen mode then exit it
         g_pCapture->get_FullScreenMode(&f);
         if(f)
         {
            g_pCapture->put_FullScreenMode(VARIANT_FALSE);
            return 0;
         }
      }
      break;

   case WM_DESTROY:

      FreeTarget();
      // no video frame
      g_pCapture->put_VideoWindowFrame((long) NULL);
      // no more notifications
      g_pCapture->SetNotifyWindow((long) NULL, 0);
      PostQuitMessage(0);
      break;

   case WM_INITMENUPOPUP:
      if(GetSubMenu(GetMenu(hwnd), 0) == (HMENU)wParam)
      {
         // determine whether the object is active
         g_pCapture->get_State(&l);
         fActive = (l == ltmmCapture_State_Pending || l == ltmmCapture_State_Running);

         // enable stop if active
         EnableMenuItem((HMENU) wParam, ID_CONTROL_STOPCAPTURE, fActive ? MF_ENABLED : MF_GRAYED);

         // enable run if paused
         EnableMenuItem((HMENU) wParam, ID_CONTROL_RUN, (l == ltmmCapture_State_Paused) ? MF_ENABLED : MF_GRAYED);

         // enable pause if running or pending
         EnableMenuItem((HMENU) wParam, ID_CONTROL_PAUSE, (l == ltmmCapture_State_Running || l == ltmmCapture_State_Pending) ? MF_ENABLED : MF_GRAYED);

         // determine if capture properties are available
         g_pCapture->HasDialog(ltmmCapture_Dlg_Capture, &f);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_CAPTUREPROPERTIES, (!fActive && f) ? MF_ENABLED : MF_GRAYED);

         // can perform normal capture?
         g_pCapture->IsModeAvailable(ltmmCapture_Mode_VideoOrAudio, &f);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_STARTCAPTURE, f ? MF_ENABLED : MF_GRAYED);
   
         // can perform auto frame capture?
         g_pCapture->IsModeAvailable(ltmmCapture_Mode_AutoFrames, &f);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_CAPTUREAUTOFRAMES, f ? MF_ENABLED : MF_GRAYED);

         // can perform manual frame capture?
         g_pCapture->IsModeAvailable(ltmmCapture_Mode_ManualFrames, &f);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_CAPTUREMANUALFRAMES, f ? MF_ENABLED : MF_GRAYED);

         // can perform still image capture?
         g_pCapture->IsModeAvailable(ltmmCapture_Mode_Still, &f);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_CAPTUREDIB, f ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_CAPTUREPICTURE, f ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_GETSTILLDIB, f ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_GETSTILLPICTURE, f ? MF_ENABLED : MF_GRAYED);
      
         // check the current video size mode
         g_pCapture->get_VideoWindowSizeMode(&sm);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_FITTOWINDOW, (sm == ltmmFit) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_STRETCHTOWINDOW, (sm == ltmmStretch) ? MF_CHECKED : MF_UNCHECKED);

         // check preview
         g_pCapture->get_Preview(&f);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_PREVIEW, f ? MF_CHECKED : MF_UNCHECKED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_PREVIEW, !fActive ? MF_ENABLED : MF_GRAYED);
   
         // check preview audio
         g_pCapture->get_PreviewSource(&l);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_PREVIEWVIDEOANDAUDIO, (l == ltmmCapture_Preview_VideoAndAudio) ? MF_CHECKED : MF_UNCHECKED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_PREVIEWVIDEOANDAUDIO, !fActive ? MF_ENABLED : MF_GRAYED);

         // check close captioning
         g_pCapture->get_CloseCaptioning(&f);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_CLOSECAPTIONING, f ? MF_CHECKED : MF_UNCHECKED);

         g_pCapture->get_CloseCaptionAvailable(&f);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_CLOSECAPTIONING, (!fActive && f) ? MF_ENABLED : MF_GRAYED);

      
         // check master stream
         g_pCapture->get_MasterStream(&l);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_MASTERSTREAM_NONE, (l == ltmmCapture_MasterStream_None) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_MASTERSTREAM_AUDIO, (l == ltmmCapture_MasterStream_Audio) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_MASTERSTREAM_VIDEO, (l == ltmmCapture_MasterStream_Video) ? MF_CHECKED : MF_UNCHECKED);

         EnableMenuItem((HMENU) wParam, ID_CONTROL_MASTERSTREAM_NONE, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_MASTERSTREAM_AUDIO, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_MASTERSTREAM_VIDEO, (!fActive) ? MF_ENABLED : MF_GRAYED);

         // check frame rate
         g_pCapture->get_UseFrameRate(&f);
         g_pCapture->get_FrameRate(&d);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_FRAMERATE_DEFAULT, (!f) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_FRAMERATE_15FPS, (f && fabs(d - 15.0) < 0.1) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_FRAMERATE_30FPS, (f && fabs(d - 30.0) < 0.1) ? MF_CHECKED : MF_UNCHECKED);

         EnableMenuItem((HMENU) wParam, ID_CONTROL_FRAMERATE_DEFAULT, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_FRAMERATE_15FPS, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_FRAMERATE_30FPS, (!fActive) ? MF_ENABLED : MF_GRAYED);

         // check time limit
         g_pCapture->get_UseTimeLimit(&f);
         g_pCapture->get_TimeLimit(&d);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TIMELIMIT_NONE, (!f) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TIMELIMIT_15SEC, (f && fabs(d - 15.0) < 0.1) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TIMELIMIT_30SEC, (f && fabs(d - 30.0) < 0.1) ? MF_CHECKED : MF_UNCHECKED);

         EnableMenuItem((HMENU) wParam, ID_CONTROL_TIMELIMIT_NONE, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_TIMELIMIT_15SEC, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_TIMELIMIT_30SEC, (!fActive) ? MF_ENABLED : MF_GRAYED);
      
         // check frame delay
         g_pCapture->get_FrameDelay(&d);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_FRAMEDELAY_1SEC, (fabs(d - 1.0) < 0.1) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_FRAMEDELAY_5SEC, (fabs(d - 5.0) < 0.1) ? MF_CHECKED : MF_UNCHECKED);

         EnableMenuItem((HMENU) wParam, ID_CONTROL_FRAMEDELAY_1SEC, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_FRAMEDELAY_5SEC, (!fActive) ? MF_ENABLED : MF_GRAYED);

         // check target
         g_pCapture->get_TargetType(&l);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TARGET_FILE, (l == ltmmCapture_Target_File) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TARGET_ARRAY, (l == ltmmCapture_Target_Array) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TARGET_DEVICE, (l == ltmmCapture_Target_Device) ? MF_CHECKED : MF_UNCHECKED);

         EnableMenuItem((HMENU) wParam, ID_CONTROL_TARGET_FILE, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_TARGET_ARRAY, (!fActive) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_TARGET_DEVICE, (!fActive) ? MF_ENABLED : MF_GRAYED);

         // check target format
         g_pCapture->get_TargetFormat(&l);
         g_pCapture->get_TargetType(&l2);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TARGETFORMAT_AVI, (l == ltmmCapture_TargetFormat_Avi) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TARGETFORMAT_WAVE, (l == ltmmCapture_TargetFormat_WAVE) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_TARGETFORMAT_MPEG1AUDIO, (l == ltmmCapture_TargetFormat_MPEG1Audio) ? MF_CHECKED : MF_UNCHECKED);

         EnableMenuItem((HMENU) wParam, ID_CONTROL_TARGETFORMAT_AVI, (!fActive && l2 != ltmmCapture_Target_Device) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_TARGETFORMAT_WAVE, (!fActive && l2 != ltmmCapture_Target_Device) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_TARGETFORMAT_MPEG1AUDIO, (!fActive && l2 != ltmmCapture_Target_Device) ? MF_ENABLED : MF_GRAYED);

         // check processor preview
         g_pCapture->get_PreviewTap(&l);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_PREVIEWPROCESSORS, (l == ltmmCapture_PreviewTap_Processors) ? MF_CHECKED : MF_UNCHECKED);

         // check properties preview
         g_pCapture->get_ShowDialogPreview(&f);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_PROPERTIESPREVIEW, (f) ? MF_CHECKED : MF_UNCHECKED);

         // enable vcr controls
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->get_DeviceType(&l);

         // if no tape is loaded, then disallow vcr control
         pVCR->get_MediaType(&l2);
         if(l2 == ltmmVCRControl_MediaType_NotPresent)
            l = ltmmVCRControl_DeviceType_NotPresent;

         // get the current vcr mode
         pVCR->get_Mode(&l2);

         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_PLAY, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_Play) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_STOP, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_Stop) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_PAUSE, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_Pause) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_REWIND, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_Rewind) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_FASTFORWARD, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_FastForward) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_STEPFORWARD, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_StepForward) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_STEPBACKWARD, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_StepBackward) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_FASTESTFORWARD, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_FastestForward) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_FASTESTREVERSE, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_FastestReverse) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_SLOWESTFORWARD, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_SlowestForward) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_SLOWESTREVERSE, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != ltmmVCRControl_Mode_SlowestReverse) ? MF_ENABLED : MF_GRAYED);

         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_RECORD, (l != ltmmVCRControl_DeviceType_NotPresent && l2 != ltmmVCRControl_Mode_Record) ? MF_ENABLED : MF_GRAYED);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_PAUSERECORDING, (l != ltmmVCRControl_DeviceType_NotPresent && l2 != ltmmVCRControl_Mode_PauseRecording) ? MF_ENABLED : MF_GRAYED);

         pVCR->ReadTimecode(&l2);
         EnableMenuItem((HMENU) wParam, ID_CONTROL_VCR_SEEKSTART, (l != ltmmVCRControl_DeviceType_NotPresent  && l != ltmmVCRControl_DeviceType_Camera && l2 != 0) ? MF_ENABLED : MF_GRAYED);

         pVCR->Release();

         // check audio buffer size
         g_pCapture->get_AudioBufferSize(&d);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_AUDIOBUFFERING_05SECONDS, (fabs(d - 0.5) < 0.01) ? MF_CHECKED : MF_UNCHECKED);
         CheckMenuItem((HMENU) wParam, ID_CONTROL_AUDIOBUFFERING_005SECONDS, (fabs(d - 0.05) < 0.01) ? MF_CHECKED : MF_UNCHECKED);

      }
      break;

   case WM_COMMAND:
      switch(LOWORD(wParam))
      {
      case ID_CONTROL_FITTOWINDOW:
         // fit the video to the window
         g_pCapture->put_VideoWindowSizeMode(ltmmFit);
         return 0;
         break;

      case ID_CONTROL_STRETCHTOWINDOW:
         // stretch the video to the window
         g_pCapture->put_VideoWindowSizeMode(ltmmStretch);
         return 0;
         break;

      case ID_CONTROL_FULLSCREEN:
         // toggle fullscreen mode
         g_pCapture->ToggleFullScreenMode();
         return 0;
         break;

      case ID_CONTROL_PREVIEW:
         // toggle preview
         g_pCapture->TogglePreview();
         return 0;
         break;

      case ID_CONTROL_PREVIEWVIDEOANDAUDIO:
         // toggle audio preview
         g_pCapture->get_PreviewSource(&l);
         if(l == ltmmCapture_Preview_VideoAndAudio)
            g_pCapture->put_PreviewSource(ltmmCapture_Preview_Video);
         else
            g_pCapture->put_PreviewSource(ltmmCapture_Preview_VideoAndAudio);

         return 0;
         break;

      case ID_CONTROL_CLOSECAPTIONING:
         // toggle close captioning
         g_pCapture->ToggleCloseCaptioning();
         return 0;
         break;

      case ID_CONTROL_STOPCAPTURE:
         // stop capturing
         g_pCapture->StopCapture();
         return 0;
         break;

      case ID_CONTROL_CAPTUREPROPERTIES:
         // set capture properties
         g_pCapture->ShowDialog(ltmmCapture_Dlg_Capture, (long) hwnd);
         return 0;
         break;

      case ID_CONTROL_STARTCAPTURE:
         // ready capture to eliminate start delays
         hr = g_pCapture->ReadyCapture(ltmmCapture_Mode_VideoOrAudio);

         if(SUCCEEDED(hr))
         {
            // start recording, if vcr output
            g_pCapture->get_TargetVCRControl(&pVCR);
            pVCR->Record();
            pVCR->Release();

            // uncomment the following line to view the the graph in DirectShow GraphEdit
            // g_pCapture->EditGraph();
            if(MessageBox(hwnd, _T("Ready to capture. Click 'ok' to start."), _T("Capture"), MB_OKCANCEL) == IDOK)
            {
               // start capturing
               g_pCapture->StartCapture(ltmmCapture_Mode_VideoOrAudio);
            }
            else
            {
               // cancel capture
               g_pCapture->StopCapture();

               // stop recording, if vcr output
               g_pCapture->get_TargetVCRControl(&pVCR);
               pVCR->Stop();
               pVCR->Release();

            }
         }
         return 0;
         break;

      case ID_CONTROL_RUN:
         // run the capture graph
         g_pCapture->RunCapture();
         return 0;
         break;

      case ID_CONTROL_PAUSE:
         // pause the capture graph
         g_pCapture->PauseCapture();
         return 0;
         break;

      case ID_CONTROL_CAPTUREAUTOFRAMES:

         hr = g_pCapture->ReadyCapture(ltmmCapture_Mode_AutoFrames);

         if(SUCCEEDED(hr))
         {
            // start recording, if vcr output
            g_pCapture->get_TargetVCRControl(&pVCR);
            hr = pVCR->Record();
            pVCR->Release();
            if(SUCCEEDED(hr))
               Sleep(2000);
      // give the vcr 2 seconds to startup

            // start capturing automatic frame sequence
            g_pCapture->StartCapture(ltmmCapture_Mode_AutoFrames);

         }
         return 0;
         break;

      case ID_CONTROL_CAPTUREMANUALFRAMES:
      
         hr = g_pCapture->ReadyCapture(ltmmCapture_Mode_ManualFrames);

         if(SUCCEEDED(hr))
         {
            // start recording, if vcr output
            g_pCapture->get_TargetVCRControl(&pVCR);
            hr = pVCR->Record();
            pVCR->Release();
            if(SUCCEEDED(hr))
               Sleep(2000);      // give the vcr 2 seconds to startup

            // start capturing automatic frame sequence
            hr = g_pCapture->StartCapture(ltmmCapture_Mode_ManualFrames);

            if(SUCCEEDED(hr))
            {
      
               while(MessageBox(hwnd, _T("Press 'ok' to capture frame."), _T("Capture Manual Frames"), MB_OKCANCEL) == IDOK)
                  g_pCapture->CaptureFrame();

               g_pCapture->StopCapture();
            }
         
            // stop recording, if vcr output
            g_pCapture->get_TargetVCRControl(&pVCR);
            pVCR->Stop();
            pVCR->Release();
         }
         return 0;
         break;

      case ID_CONTROL_CAPTUREDIB:
         // capture device independent bitmap
         hr = g_pCapture->CaptureDIB((long*) &hDIB);
         if(SUCCEEDED(hr))
         {
            // copy to the clipboard
            OpenClipboard(hwnd);
            EmptyClipboard();
            SetClipboardData(CF_DIB, hDIB);
            CloseClipboard();
         }
         return 0;
         break;
      case ID_CONTROL_CAPTUREPICTURE:
         // capture ole picture object
         hr = g_pCapture->CapturePicture(&pPictureDisp);
         if(SUCCEEDED(hr))
         {
            // save the picture
            bstr = SysAllocString(L"c:\\still.bmp");
            OleSavePictureFile(pPictureDisp, bstr);
            SysFreeString(bstr);
            pPictureDisp->Release();
         }
         return 0;
         break;
      case ID_CONTROL_GETSTILLDIB:
         // alternate method of capturing a device independent bitmap
         hr = g_pCapture->StartCapture(ltmmCapture_Mode_Still);
         if(SUCCEEDED(hr))
         {
            hr = g_pCapture->GetStillDIB(INFINITE, (long*) &hDIB);
            g_pCapture->StopCapture();
            if(SUCCEEDED(hr))
            {
               // copy to the clipboard
               OpenClipboard(hwnd);
               EmptyClipboard();
               SetClipboardData(CF_DIB, hDIB);
               CloseClipboard();
            }
         }
         return 0;
         break;
      case ID_CONTROL_GETSTILLPICTURE:
         // alternate method of capturing an ole picture object
         hr = g_pCapture->StartCapture(ltmmCapture_Mode_Still);
         if(SUCCEEDED(hr))
         {
            hr = g_pCapture->GetStillPicture(INFINITE, &pPictureDisp);
            g_pCapture->StopCapture();
            if(SUCCEEDED(hr))
            {
               // save the picture
               bstr = SysAllocString(L"c:\\still.bmp");
               OleSavePictureFile(pPictureDisp, bstr);
               SysFreeString(bstr);
               pPictureDisp->Release();
            }
         }
         return 0;
         break;

      case ID_CONTROL_COPYTARGET:
         // copy target file
         bstr = SysAllocString(L"c:\\targetcopy.avi");
         g_pCapture->CopyTarget(bstr, VARIANT_FALSE);
         SysFreeString(bstr);
         return 0;
         break;

      case ID_CONTROL_MASTERSTREAM_NONE:
         // no master stream
         g_pCapture->put_MasterStream(ltmmCapture_MasterStream_None);
         return 0;
         break;

      case ID_CONTROL_MASTERSTREAM_AUDIO:
         // set audio master
         g_pCapture->put_MasterStream(ltmmCapture_MasterStream_Audio);
         return 0;
         break;

      case ID_CONTROL_MASTERSTREAM_VIDEO:
         // set video master
         g_pCapture->put_MasterStream(ltmmCapture_MasterStream_Video);
         return 0;
         break;

      case ID_CONTROL_FRAMERATE_DEFAULT:
         // set rate to default
         g_pCapture->put_UseFrameRate(VARIANT_FALSE);
         return 0;
         break;

      case ID_CONTROL_FRAMERATE_15FPS:
         // set rate to 15 fps
         g_pCapture->put_FrameRate(15.0);
         g_pCapture->put_UseFrameRate(VARIANT_TRUE);
         return 0;
         break;

      case ID_CONTROL_FRAMERATE_30FPS:
         // set rate to 30 fps
         g_pCapture->put_FrameRate(30.0);
         g_pCapture->put_UseFrameRate(VARIANT_TRUE);
         return 0;
         break;

      case ID_CONTROL_TIMELIMIT_NONE:
         // no time limit
         g_pCapture->put_UseTimeLimit(VARIANT_FALSE);
         return 0;
         break;

      case ID_CONTROL_TIMELIMIT_15SEC:
         // 15 sec time limit
         g_pCapture->put_TimeLimit(15.0);
         g_pCapture->put_UseTimeLimit(VARIANT_TRUE);
         return 0;
         break;

      case ID_CONTROL_TIMELIMIT_30SEC:
         // 30 sec time limit
         g_pCapture->put_TimeLimit(30.0);
         g_pCapture->put_UseTimeLimit(VARIANT_TRUE);
         return 0;
         break;

      case ID_CONTROL_FRAMEDELAY_1SEC:
         // 1 sec frame delay
         g_pCapture->put_FrameDelay(1.0);
         return 0;
         break;

      case ID_CONTROL_FRAMEDELAY_5SEC:
         // 5 sec frame delay
         g_pCapture->put_FrameDelay(5.0);
         return 0;
         break;

      case ID_CONTROL_TARGET_FILE:
         // assign a target file
         FreeTarget();
         
         // select the LEAD video compressor
         g_pCapture->get_VideoCompressors(&pCompressors);
         bstr = SysAllocString(L"@device:sw:{33D9A760-90C8-11D0-BD43-00A0C911CE86}\\LEAD MCMP/MJPEG Codec (2.0)");
         pCompressors->Find(bstr, &index);
         SysFreeString(bstr);
         if(index >= 0)
            pCompressors->put_Selection(index);
         pCompressors->Release();
         
         // select the MP3 audio video compressor
         g_pCapture->get_AudioCompressors(&pCompressors);
         bstr = SysAllocString(L"@device:cm:{33D9A761-90C8-11D0-BD43-00A0C911CE86}\\85MPEG Layer-3");
         pCompressors->Find(bstr, &index);
         SysFreeString(bstr);
         if(index >= 0)
            pCompressors->put_Selection(index);
         pCompressors->Release();
         
         g_pCapture->put_TargetFormat(ltmmCapture_TargetFormat_Avi);
         bstr = SysAllocString(L"c:\\target.avi");
         g_pCapture->put_TargetFile(bstr);
         SysFreeString(bstr);
         return 0;
         break;

      case ID_CONTROL_TARGET_ARRAY:
         // assign a target array
         FreeTarget();
         
         // select the LEAD video compressor
         g_pCapture->get_VideoCompressors(&pCompressors);
         bstr = SysAllocString(L"@device:sw:{33D9A760-90C8-11D0-BD43-00A0C911CE86}\\LEAD MCMP/MJPEG Codec (2.0)");
         pCompressors->Find(bstr, &index);
         SysFreeString(bstr);
         if(index >= 0)
            pCompressors->put_Selection(index);
         pCompressors->Release();
         
         // select the MP3 audio video compressor
         g_pCapture->get_AudioCompressors(&pCompressors);
         bstr = SysAllocString(L"@device:cm:{33D9A761-90C8-11D0-BD43-00A0C911CE86}\\85MPEG Layer-3");
         pCompressors->Find(bstr, &index);
         SysFreeString(bstr);
         if(index >= 0)
            pCompressors->put_Selection(index);
         pCompressors->Release();
         
         g_pCapture->put_TargetFormat(ltmmCapture_TargetFormat_Avi);
         
         VariantInit(&var);
         V_VT(&var) = (VT_ARRAY | VT_UI1);
         V_ARRAY(&var) = SafeArrayCreateVector(VT_UI1, 0, 0);
         g_pCapture->put_TargetArray(var);
         return 0;
         break;
      case ID_CONTROL_TARGET_DEVICE:
         // assign target device
         FreeTarget();

         // deselect all compressors
         g_pCapture->get_VideoCompressors(&pCompressors);
         pCompressors->put_Selection(-1);
         pCompressors->Release();
         
         g_pCapture->get_AudioCompressors(&pCompressors);
         pCompressors->put_Selection(-1);
         pCompressors->Release();

         // select dvsd format
         g_pCapture->put_TargetFormat(ltmmCapture_TargetFormat_dvsd);

         // select the first output device
         g_pCapture->get_TargetDevices(&pTargetDevices);
         pTargetDevices->put_Selection(0);
         pTargetDevices->Release();
         return 0;
         break;

      case ID_CONTROL_TARGETFORMAT_AVI:
         // is target a file?
         g_pCapture->get_TargetType(&l);
         if(l == ltmmCapture_Target_File)
         {
            // rename it
            bstr = SysAllocString(L"c:\\target.avi");
            g_pCapture->put_TargetFile(bstr);
            SysFreeString(bstr);
         }
         g_pCapture->put_TargetFormat(ltmmCapture_TargetFormat_Avi);
         return 0;
         break;

      case ID_CONTROL_TARGETFORMAT_WAVE:
         // is target a file?
         g_pCapture->get_TargetType(&l);
         if(l == ltmmCapture_Target_File)
         {
            // rename it
            bstr = SysAllocString(L"c:\\target.wav");
            g_pCapture->put_TargetFile(bstr);
            SysFreeString(bstr);
         }
         g_pCapture->put_TargetFormat(ltmmCapture_TargetFormat_WAVE);
         return 0;
         break;

      case ID_CONTROL_TARGETFORMAT_MPEG1AUDIO:
         // is target a file?
         g_pCapture->get_TargetType(&l);
         if(l == ltmmCapture_Target_File)
         {
            // rename it
            bstr = SysAllocString(L"c:\\target.mp3");
            g_pCapture->put_TargetFile(bstr);
            SysFreeString(bstr);
         }
         // we have already selected the MP3 compressor
         g_pCapture->put_TargetFormat(ltmmCapture_TargetFormat_MPEG1Audio);
         return 0;
         break;

      case ID_CONTROL_AUDIOPROCESSORS:
         // edit audio processors
         g_pCapture->ShowDialog(ltmmCapture_Dlg_AudioProcessors, (long) hwnd);
         return 0;
         break;

      case ID_CONTROL_VIDEOPROCESSORS:
         // edit video processors
         g_pCapture->ShowDialog(ltmmCapture_Dlg_VideoProcessors, (long) hwnd);
         return 0;
         break;

      case ID_CONTROL_PREVIEWPROCESSORS:
         // toggle processor preview
         g_pCapture->get_PreviewTap(&l);
         g_pCapture->put_PreviewTap((l == ltmmCapture_PreviewTap_Processors) ? ltmmCapture_PreviewTap_Source : ltmmCapture_PreviewTap_Processors);
         return 0;
         break;

      case ID_CONTROL_PROPERTIESPREVIEW:
         // toggle preview while editing properties
         g_pCapture->get_ShowDialogPreview(&f);
         g_pCapture->put_ShowDialogPreview(f ? VARIANT_FALSE : VARIANT_TRUE);
         return 0;
         break;

      case ID_CONTROL_VCR_PLAY:
         // vcr play
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->Play();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_STOP:
         // vcr stop
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->Stop();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_PAUSE:
         // vcr pause
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->Pause();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_FASTFORWARD:
         // vcr fast forward
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->FastForward();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_REWIND:
         // vcr rewind
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->Rewind();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_RECORD:
         // vcr record
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->Record();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_PAUSERECORDING:
         // vcr pause recording
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->PauseRecording();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_STEPFORWARD:
         // vcr step forward
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->StepForward();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_STEPBACKWARD:
         // vcr step backward
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->StepBackward();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_FASTESTFORWARD:
         // vcr fastest forward
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->FastestForward();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_FASTESTREVERSE:
         // vcr fastest reverse
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->FastestReverse();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_SLOWESTFORWARD:
         // vcr slowest forward
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->SlowestForward();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_SLOWESTREVERSE:
         // vcr slowest reverse
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->SlowestReverse();
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_VCR_SEEKSTART:
         // vcr seek start
         g_pCapture->get_CaptureVCRControl(&pVCR);
         pVCR->SeekTimecode(0);
         pVCR->Release();
         return 0;
         break;

      case ID_CONTROL_AUDIOBUFFERING_05SECONDS:
         // set 0.5 second audio buffer
         g_pCapture->put_AudioBufferSize(0.5);
         return 0;
         break;

      case ID_CONTROL_AUDIOBUFFERING_005SECONDS:
         // set 0.05 second audio buffer
         g_pCapture->put_AudioBufferSize(0.05);
         return 0;
         break;
      }
      break;

   case WM_LBUTTONDOWN:
      g_pCapture->get_State(&l);
      if(l != ltmmCapture_State_Pending || l != ltmmCapture_State_Running)
      {
         g_pCapture->get_VideoWindowLeft(&x);
         g_pCapture->get_VideoWindowTop(&y);
         g_pCapture->get_VideoWindowWidth(&cx);
         g_pCapture->get_VideoWindowHeight(&cy);
         SetRect(&rc, x, y, x + cx, y + cy);
         pt.x = (short) LOWORD(lParam);
         pt.y = (short) HIWORD(lParam);
         if(PtInRect(&rc, pt))
         {
            // set capture properties
            g_pCapture->ShowDialog(ltmmCapture_Dlg_Capture, (long) hwnd);
         }
      }
      return 0;
      break;
   }
   return DefWindowProc(hwnd, message, wParam, lParam);

}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
   MSG msg;
   HRESULT hr;
   WNDCLASSEX wcex;
   
   g_hInstance = hInstance;

   // initialize COM library
   hr = CoInitialize(NULL);
   if(FAILED(hr))
      goto error;
   
   
   // register the video frame window class
   wcex.cbSize = sizeof(WNDCLASSEX); 
   wcex.style         = CS_HREDRAW | CS_VREDRAW;
   wcex.lpfnWndProc   = CaptureWndProc;
   wcex.cbClsExtra    = 0;
   wcex.cbWndExtra    = 0;
   wcex.hInstance      = g_hInstance;
   wcex.hIcon         = NULL;
   wcex.hCursor      = LoadCursor(NULL, IDC_ARROW);
   wcex.hbrBackground   = (HBRUSH) (COLOR_APPWORKSPACE + 1);
   wcex.lpszMenuName   = (LPCWSTR)IDR_MENU;
   wcex.lpszClassName   = SZ_WNDCLASS_CAPTURE;
   wcex.hIconSm      = NULL;
   
   if(!RegisterClassEx(&wcex))
      goto error;

   
   // create the capture object
   hr = CoCreateInstance(CLSID_ltmmCapture, NULL, CLSCTX_INPROC_SERVER, IID_IltmmCapture, (void**) &g_pCapture);
   if(FAILED(hr))
      goto error;
   
   // create the video frame window
   if(!CreateWindow(SZ_WNDCLASS_CAPTURE, _T("Capture"), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, g_hInstance, NULL))
      goto error;
   
   ShowWindow(g_hwndCapture, nCmdShow);

   UpdateWindow(g_hwndCapture);

   // process until done
   while (GetMessage(&msg, NULL, 0, 0)) 
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
   
error:
   if(g_pCapture)
      g_pCapture->Release();

   CoUninitialize();

   return 0;   
}