home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / vidcap.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-19  |  37.3 KB  |  1,339 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992 - 1996  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11.  
  12. //
  13. //  Video capture stream source filter
  14. //
  15.  
  16. // Uses the AVICap window to capture video data to pass downstream.
  17. // By using the video callback it avoids AVICap sending data to a file
  18. // - AVICap is merely capturing buffers for us to pass on.
  19. //
  20. // Uses a custom interface to allow the driver to be configured.
  21. // An app can use this to allow the user to configure their caapture session.
  22. // Configuration is only allowed when the filter is unconnected.
  23.  
  24. // Caveats
  25. //
  26. // ** Should reject going active when the user has format dialogs up. Does this
  27. //    need a CSource re-engineering?
  28.  
  29. #include <streams.h>
  30.  
  31. #include <initguid.h>
  32. #include <mmsystem.h>
  33. #include <vfw.h>
  34. #include <string.h>
  35. #include <stddef.h>     // for offsetof macro
  36.  
  37. #include "ivconfig.h"
  38. #include "vidcap.h"
  39.  
  40. // setup data
  41.  
  42. AMOVIESETUP_MEDIATYPE sudOpPinTypes = { &MEDIATYPE_Video       // clsMajorType
  43.                                       , &MEDIASUBTYPE_NULL };  // clsMinorType
  44.  
  45. AMOVIESETUP_PIN sudOpPin = { L"Output"          // strName
  46.                            , FALSE              // bRendered
  47.                            , TRUE               // bOutput
  48.                            , FALSE              // bZero
  49.                            , FALSE              // bMany
  50.                            , &CLSID_NULL        // clsConnectsToFilter
  51.                            , NULL               // strConnectsToPin
  52.                            , 1                  // nMediaTypes
  53.                            , &sudOpPinTypes };  // lpMediaType
  54.  
  55. AMOVIESETUP_FILTER sudVidCapax = { &CLSID_VidCap              // clsID
  56.                                  , L"Video Capture (AVICap)"  // strName
  57.                                  , MERIT_UNLIKELY             // dwMerit
  58.                                  , 1                          // nPins
  59.                                  , &sudOpPin };               // lpPin
  60.  
  61. // COM global table of objects available in this dll
  62. CFactoryTemplate g_Templates[1] = {
  63.  
  64.     {L"Video Capture (AVICap)", &CLSID_VidCap, CVidCap::CreateInstance}
  65. };
  66. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  67.  
  68.  
  69. // exported entry points for registration and
  70. // unregistration (in this case they only call
  71. // through to default implmentations).
  72. //
  73. HRESULT DllRegisterServer()
  74. {
  75.   return AMovieDllRegisterServer();
  76. }
  77.  
  78. HRESULT DllUnregisterServer()
  79. {
  80.   return AMovieDllUnregisterServer();
  81. }
  82.  
  83.  
  84. //
  85. // CVidCap::Constructor
  86. //
  87. // create an output pin for the first driver we find.
  88. // Name it after the driver we have found
  89. CVidCap::CVidCap(TCHAR *pName, LPUNKNOWN lpunk, HRESULT *phr)
  90.     : CSource(pName, lpunk, CLSID_VidCap, phr) {
  91.  
  92.     CAutoLock l(&m_cStateLock);
  93.  
  94.  
  95.     TCHAR szName[giDriverNameStrLen];   // AVICap recommends a giDriverNameStrLen
  96.                                         // byte buffer (minimum)
  97.  
  98.     for (int i=0 ; i < 10 ; i++) { // have a look for a driver with indices  0-9
  99.                                    // (see AVICap documentation)
  100.                                    // need to provide some enumeration i/f (MRIDs?)
  101.  
  102.         if ( capGetDriverDescription( i
  103.                                     , (LPTSTR) &szName
  104.                                     , sizeof(szName)
  105.                                     , NULL
  106.                                     , 0
  107.                                     )
  108.            )
  109.         {
  110.  
  111.             break; // we've found one!
  112.         }
  113.     }
  114.  
  115. #ifndef UNICODE
  116.     OLECHAR wszName[giDriverNameStrLen];
  117.     MultiByteToWideChar(CP_ACP, 0,              // Quartz i/f are always unicode,
  118.                                                 // so convert name to
  119.                             szName, -1,         // unicode.
  120.                             wszName, giDriverNameStrLen);
  121. #else
  122.     #define wszName szName
  123. #endif
  124.  
  125.     CSourceStream *ps = new CVidStream( NAME("Video capture stream"),
  126.                     phr, this, i, wszName);
  127.     if (ps == NULL) {
  128.         *phr = E_OUTOFMEMORY;
  129.         return;
  130.     }
  131.  
  132.     if (FAILED(*phr)) {
  133.     delete ps;
  134.         return;
  135.     }
  136.  
  137.     DbgLog((LOG_TRACE, 1, TEXT("CVidCap created")));
  138. }
  139.  
  140.  
  141. //
  142. // CVidCap::Destructor
  143. //
  144. CVidCap::~CVidCap(void) {
  145.     DbgLog((LOG_TRACE, 1, TEXT("CVidCap destroyed")) );
  146. }
  147.  
  148.  
  149. //
  150. // CreateInstance
  151. //
  152. // Called by CoCreateInstance to create a vidcap filter.
  153. CUnknown *CVidCap::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) {
  154.  
  155.     CUnknown *punk = new CVidCap(TEXT("Video capture filter"), lpunk, phr);
  156.     if (punk == NULL) {
  157.         *phr = E_OUTOFMEMORY;
  158.     }
  159.     return punk;
  160. }
  161.  
  162.  
  163. //
  164. // Run
  165. //
  166. // Activate the pin, letting it know that we are moving to
  167. // State_Running
  168. STDMETHODIMP CVidCap::Run(REFERENCE_TIME tStart) {
  169.     CAutoLock l(pStateLock());
  170.  
  171.     HRESULT hr;
  172.  
  173.     m_tStart = tStart;  // remember the stream time offset
  174.  
  175.     hr = CSource::Run(tStart);
  176.  
  177.     if (SUCCEEDED(hr)) {
  178.     // start us running
  179.     hr = ((CVidStream *)GetPin(0))->Run();
  180.     }
  181.  
  182.     return S_OK;
  183. }
  184.  
  185.  
  186. //
  187. // Pause
  188. //
  189. // Activate the pin, letting it know that Paused will
  190. // be the next state
  191. STDMETHODIMP CVidCap::Pause(void) {
  192.     CAutoLock l(pStateLock());
  193.  
  194.     if (m_State == State_Paused) {
  195.         return S_OK;
  196.     }
  197.  
  198.  
  199.     CVidStream* pPin = (CVidStream*) GetPin(0);
  200.  
  201.     // for a live source, pausing means we send a poster frame
  202.     // but nothing else. So if pausing from running, we first stop
  203.     // and then start again. To stop in this pausing state we
  204.     // need to flush the data
  205.     if (m_State == State_Running) {
  206.  
  207.         pPin->DeliverBeginFlush();
  208.         Stop();
  209.         pPin->DeliverEndFlush();
  210.     }
  211.  
  212.     // need to change state before sending the pause request
  213.     // or the thread will not be created when we try to signal it.
  214.     FILTER_STATE oldstate = m_State;
  215.     HRESULT hr = CSource::Pause();
  216.     if (FAILED(hr)) {
  217.         return hr;
  218.     }
  219.  
  220.  
  221.     // we need to send some data (poster frame) when we start
  222.     // pausing, but we don't send the real data until
  223.     // we start running (as this is a live source, any cued data will
  224.     // be late when we start running from paused
  225.     return pPin->Pause();
  226. }
  227.  
  228.  
  229. //
  230. // Stop
  231. //
  232. // Pass the current state to the pins Inactive method
  233. STDMETHODIMP CVidCap::Stop(void) {
  234.     CAutoLock l(pStateLock());
  235.  
  236.     HRESULT hr;
  237.  
  238.     hr = CSource::Stop();
  239.  
  240.     m_tStart = CRefTime(0L);
  241.  
  242.     return hr;
  243. }
  244.  
  245. //
  246. // GetSetupData
  247. //
  248. LPAMOVIESETUP_FILTER CVidCap::GetSetupData()
  249. {
  250.   return &sudVidCapax;
  251. }
  252.  
  253.  
  254. // *
  255. // * Implements CVidStream - manages the output pin
  256. // *
  257.  
  258.  
  259. long      CVidStream::m_lObjectCount = 0;   // The number of CVidStream objects.
  260.                                             // Only 1 is allowed.
  261.  
  262.  
  263. //
  264. // CVidStream::Constructor
  265. //
  266. // keep the driver index to open.
  267. // We will open it when we go active, as we shouldn't keep resources
  268. // whilst inactive.
  269. CVidStream::CVidStream(TCHAR            *pObjectName
  270.                       , HRESULT         *phr
  271.                       , CVidCap         *pParentFilter
  272.                       , unsigned int    uiDriverIndex
  273.                       , LPCWSTR          pPinName
  274.                       )
  275.     :CSourceStream(pObjectName, phr, pParentFilter, pPinName),
  276.      m_uiDriverIndex(uiDriverIndex),
  277.      m_lCountActual(0),
  278.      m_plFilled(NULL),
  279.      m_hwCapCapturing(NULL),
  280.      m_fFormatDirty(FALSE),
  281.      m_dwMicroSecPerFrame(66667)        // default to 15fps
  282.     {
  283.  
  284.     CAutoLock lock(m_pFilter->pStateLock());
  285.  
  286.     // !!! Quote from docs:
  287.     // > The variable pointed to by the lplVal parameter must be aligned
  288.     // > on a 32-bit boundary;
  289.     // > otherwise, this function will fail on multiprocessor x86 systems.
  290.     // This is ensured by the compiler provided the structure packing level is
  291.     // correct.
  292.     InterlockedIncrement(&m_lObjectCount);
  293.     if (m_lObjectCount > 1) {                   // A CVidStream already exists
  294.         *phr = E_UNEXPECTED;
  295.         MessageBox(NULL,
  296.                    TEXT("Only one copy of this filter can be created"),
  297.                    TEXT("Video Capture (AVICap)"),
  298.                    MB_ICONSTOP | MB_OK);
  299.         DbgLog( (LOG_ERROR, 1, TEXT("Trying to create > 1 CVidStreams") ));
  300.         return;
  301.     }
  302.  
  303.     HWND hwndCap = CreateCaptureWindow(0);
  304.     if (hwndCap == NULL) {
  305.         *phr = E_FAIL;
  306.         return;
  307.     }
  308.  
  309. #ifdef UNICODE
  310.     capDriverGetName(hwndCap, m_szName, sizeof(m_szName));
  311.     capDriverGetVersion(hwndCap, m_szVersion, sizeof(m_szVersion));
  312. #else
  313.     char sz[giDriverNameStrLen];
  314.     capDriverGetName(hwndCap, sz, sizeof(sz));
  315.     MultiByteToWideChar(CP_ACP, 0,
  316.                             sz, -1,
  317.                             m_szName, giDriverNameStrLen);
  318.  
  319.     capDriverGetVersion(hwndCap, sz, sizeof(sz));
  320.     MultiByteToWideChar(CP_ACP, 0,
  321.                             sz, -1,
  322.                             m_szVersion, giDriverVerStrLen);
  323. #endif
  324.     // Establish what dialogs this driver can display.
  325.  
  326.     CAPDRIVERCAPS DriverCaps;
  327.     capDriverGetCaps(hwndCap, &DriverCaps, sizeof(DriverCaps) );
  328.     m_SupportsVideoSourceDialog  = DriverCaps.fHasDlgVideoSource;
  329.     m_SupportsVideoDisplayDialog = DriverCaps.fHasDlgVideoDisplay;
  330.     m_SupportsVideoFormatDialog  = DriverCaps.fHasDlgVideoFormat;
  331.     m_SuppliesPalettes = DriverCaps.fDriverSuppliesPalettes;
  332.  
  333.     if (!DestroyCaptureWindow(hwndCap)) {
  334.         *phr = E_FAIL;
  335.         return;
  336.     }
  337.  
  338.     DbgLog( (LOG_TRACE, 1, TEXT("CVidStream created") ) );
  339. }
  340.  
  341.  
  342. //
  343. // CVidStream::Destructor
  344. //
  345. // we should be inactive before this is called.
  346. CVidStream::~CVidStream(void) {
  347.  
  348.     CAutoLock lock(m_pFilter->pStateLock());
  349.  
  350.     ASSERT(!m_pFilter->IsActive());
  351.  
  352.     InterlockedDecrement(&m_lObjectCount);
  353.  
  354.     DbgLog( (LOG_TRACE, 1, TEXT("CVidStream destroyed") ) );
  355.  
  356. }
  357.  
  358.  
  359. //
  360. // GetMediaType
  361. //
  362. // Queries the video driver and places an appropriate media type in *pmt
  363. HRESULT CVidStream::GetMediaType(CMediaType *pmt) {
  364.  
  365.     CAutoLock l(&m_cSharedState);
  366.  
  367.     HWND hwndCap;
  368.  
  369.     if (m_hwCapCapturing == NULL) {     // No active window, so create one.
  370.         hwndCap = CreateCaptureWindow(0);
  371.         if (hwndCap == NULL) {
  372.             return E_FAIL;
  373.         }
  374.     }
  375.     else {                              // Use the currently active window
  376.         hwndCap = m_hwCapCapturing;
  377.     }
  378.  
  379.     pmt->SetType(&MEDIATYPE_Video);
  380.     pmt->SetFormatType(&FORMAT_VideoInfo);
  381.  
  382.     DWORD dwFormatSize;
  383.     VIDEOINFO *pvi;
  384.  
  385.     dwFormatSize = capGetVideoFormatSize(hwndCap);
  386.  
  387.     ASSERT(dwFormatSize > 0);
  388.  
  389.     // Find out how big we need to allocate the buffer
  390. #define AllocBufferSize (max(sizeof(VIDEOINFO), dwFormatSize+offsetof(VIDEOINFO,bmiHeader)))
  391.  
  392.     // Set up the format section of the mediatype to be the right size
  393.     pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(AllocBufferSize);
  394. #undef AllocBufferSize
  395.     if (pvi == NULL) {
  396.         return E_OUTOFMEMORY;
  397.     }
  398.  
  399.     // make sure all fields are initially zero
  400.     ZeroMemory((void *)pvi, sizeof(VIDEOINFO));
  401.  
  402.     // grab the BITMAPINFOHEADER straight in
  403.     // will leave the memory after the last palette entry as zeros.
  404.     capGetVideoFormat(hwndCap, &(pvi->bmiHeader), dwFormatSize);
  405.  
  406.     const GUID SubTypeGUID = GetBitmapSubtype(&pvi->bmiHeader);
  407.     pmt->SetSubtype(&SubTypeGUID);
  408.     pmt->SetSampleSize(GetSampleSize(&pvi->bmiHeader));
  409.  
  410.     if (m_hwCapCapturing == NULL) { // destroy the window we created
  411.         DestroyCaptureWindow(hwndCap);
  412.     }
  413.  
  414.     return NOERROR;
  415. }
  416.  
  417.  
  418. //
  419. // OnThreadCreate
  420. //
  421. // Start streaming & reset time samples are stamped with.
  422. HRESULT CVidStream::OnThreadCreate(void) {
  423.  
  424.     CAutoLock l(&m_cSharedState);
  425.  
  426.     m_ThreadState = Stopped;
  427.  
  428.     m_hwCapCapturing = CreateCaptureWindow(m_lCountActual);
  429.     if (m_hwCapCapturing == NULL) {
  430.         return E_FAIL;
  431.     }
  432.  
  433.     CMediaType mt;
  434.     GetMediaType(&mt);        // get the media type the driver _currently_ supports
  435.     if (mt != m_mt) {         // Is it the same as the one we negotiated?
  436.         return E_UNEXPECTED;  // ...if not, bail out.
  437.     }
  438.  
  439.     m_plFilled = new CVideoBufferList( m_mt.lSampleSize
  440.                                      , (LONG)(m_dwMicroSecPerFrame / 1000)
  441.                                      , (CVidCap *)m_pFilter
  442.                                      );
  443.     if (m_plFilled == NULL) {
  444.         return E_OUTOFMEMORY;
  445.     }
  446.  
  447.     return NOERROR;
  448. }
  449.  
  450.  
  451. //
  452. // OnThreadDestroy
  453. //
  454. // Free the list of completed buffers and stop streaming
  455. // Attempts to stop streaming and destroy the window, even in error
  456. // cases.
  457. HRESULT CVidStream::OnThreadDestroy(void) {
  458.  
  459.     CAutoLock l(&m_cSharedState);
  460.  
  461.     ASSERT(m_ThreadState == Stopped);
  462.  
  463.     BOOL fWindowGone = DestroyCaptureWindow(m_hwCapCapturing);
  464.     m_hwCapCapturing = NULL;
  465.  
  466.     delete m_plFilled, m_plFilled = NULL;
  467.  
  468.     if (!fWindowGone) {
  469.         return E_UNEXPECTED;
  470.     }
  471.     else {
  472.         return NOERROR;
  473.     }
  474. }
  475.  
  476.  
  477. //
  478. // DecideBufferSize
  479. //
  480. // Check the allocator can give us appropriately sized buffers
  481. // Always called after format negotiation.
  482. HRESULT CVidStream::DecideBufferSize(IMemAllocator *pAlloc,
  483.                                      ALLOCATOR_PROPERTIES *pProperties)
  484. {
  485.     CAutoLock lock(m_pFilter->pStateLock());
  486.     CAutoLock l(&m_cSharedState);
  487.     ASSERT(pAlloc);
  488.     ASSERT(pProperties);
  489.     HRESULT hr = NOERROR;
  490.  
  491.     pProperties->cBuffers = 5;
  492.     pProperties->cbBuffer = m_mt.lSampleSize;
  493.  
  494.     ASSERT(pProperties->cbBuffer);
  495.  
  496.     // Ask the allocator to reserve us some sample memory, NOTE the function
  497.     // can succeed (that is return NOERROR) but still not have allocated the
  498.     // memory that we requested, so we must check we got whatever we wanted
  499.  
  500.     ALLOCATOR_PROPERTIES Actual;
  501.     hr = pAlloc->SetProperties(pProperties,&Actual);
  502.     if (!FAILED(hr)) {
  503.         // Is this allocator unsuitable
  504.  
  505.         if (Actual.cbBuffer < pProperties->cbBuffer) {
  506.             hr = E_FAIL;
  507.         }
  508.     }
  509.     return hr;
  510. }
  511.  
  512.  
  513. //
  514. // GetSampleSize
  515. //
  516. // Given a BITMAPINFOHEADER, calculates the sample size needed.
  517. long CVidStream::GetSampleSize(LPBITMAPINFOHEADER pbmi) {
  518.  
  519.     long lSize;
  520.  
  521.     if (pbmi->biSizeImage > 0) {
  522.  
  523.         lSize = pbmi->biSizeImage;
  524.  
  525.     }
  526.     else {      // biSizeImage is allowed to be zero for uncompressed formats,
  527.                 // so do the maths ourselves...
  528.  
  529.         lSize = (pbmi->biWidth *
  530.                  pbmi->biHeight *
  531.                  pbmi->biBitCount) / 8 + 1;
  532.         if (lSize < 0) { // biHeight was negative
  533.             lSize *= -1;
  534.         }
  535.     }
  536.  
  537.     lSize += sizeof(DWORD) - (lSize % sizeof(DWORD));   // make size DWORD aligned.
  538.  
  539.     return lSize;
  540. }
  541.  
  542.  
  543. //
  544. // CreateCaptureWindow
  545. //
  546. // Create a hidden AVICap window, and make sure it is configured appropriately
  547. // Returns NULL on failure.
  548. // successful calls should be balanced with calls to DestroyCaptureWindow()
  549. // Creates the AVICap window with (up to) lBufferCount no. of buffers.
  550. // use lBufferCount = 0, when you only wish to interrgoate the the driver, or
  551. // specify a number of buffers, if you actually want to capture.
  552. HWND CVidStream::CreateCaptureWindow(long lBufferCount) {
  553.  
  554.     CAutoLock lock(&m_cSharedState);
  555.  
  556.     BOOL bErr;  //return code of capXXX calls
  557.  
  558.     HWND hwndCapture;   // The window to return
  559.  
  560.     hwndCapture = capCreateCaptureWindow(NULL,           // No name
  561.                                          0,              // no style.
  562.                                                          // defaults to invisible
  563.                                          0, 0, 150, 150, // an arbitrary size
  564.                                          0,              // no parent
  565.                                          0);             // don't care about the id
  566.  
  567.     if (!hwndCapture) {
  568.         DbgLog((LOG_ERROR|LOG_TRACE, 1, TEXT("Window could not be created") ));
  569.         return NULL;
  570.     }
  571.  
  572.     bErr = capDriverConnect(hwndCapture, m_uiDriverIndex);
  573.     if (!bErr) {
  574.         DestroyWindow(hwndCapture);
  575.         DbgLog((LOG_ERROR|LOG_TRACE, 1, TEXT("Driver failed to connect") ) );
  576.         return NULL;
  577.     }
  578.     DbgLog((LOG_TRACE, 2, TEXT("Driver Connected") ));
  579.  
  580.     CAPTUREPARMS cp;
  581.     capCaptureGetSetup(hwndCapture, &cp, sizeof(cp) ); // get the current defaults
  582.  
  583.     cp.dwRequestMicroSecPerFrame = m_dwMicroSecPerFrame; // Set desired frame rate
  584.     cp.fMakeUserHitOKToCapture   = FALSE;
  585.     cp.fYield                    = TRUE;                 // we want capture on a
  586.                                                          // background thread.
  587.     cp.wNumVideoRequested        = (WORD) lBufferCount;  // we may get less than
  588.                                                          // this - no problem
  589.     cp.fCaptureAudio             = FALSE;
  590.     cp.vKeyAbort                 = 0;                    // If no key is provided,
  591.                                                          // it won't stop...
  592.     cp.fAbortLeftMouse           = FALSE;
  593.     cp.fAbortRightMouse          = FALSE;
  594.     cp.fLimitEnabled             = FALSE;                // we want to stop
  595.     cp.fMCIControl               = FALSE;
  596.  
  597.     capCaptureSetSetup(hwndCapture, &cp, sizeof(cp) );
  598.  
  599.     capSetCallbackOnVideoStream(hwndCapture, &VideoCallback);
  600.     capSetCallbackOnFrame(hwndCapture, &VideoCallback);      // also use for single
  601.                                                              // frame capture
  602.  
  603. #if 0
  604.     CAPSTATUS    cs;
  605.     ZeroMemory(&cs, sizeof(cs));
  606.     capGetStatus(hwndCapture, &cs, sizeof(cs));
  607.  
  608.     // try to see if the driver uses palettes
  609.     if (((cs.hPalCurrent != NULL) || (cs.fUsingDefaultPalette))) {
  610.     m_UsesPalettes = TRUE;
  611.     } else {
  612.         m_UsesPalettes = FALSE;
  613.     }
  614.     if (m_UsesPalettes && m_SuppliesPalettes) {
  615.     capPaletteAuto(hwndCapture, 10, 236);
  616.     }
  617. #endif
  618.  
  619.     SetWindowLong(hwndCapture, GWL_USERDATA, (LONG) this);
  620.  
  621.     return hwndCapture;
  622. }
  623.  
  624.  
  625. //
  626. // DestroyCaptureWindow()
  627. //
  628. // Disconnect the driver before destroying the window.
  629. BOOL CVidStream::DestroyCaptureWindow(HWND hwnd) {
  630.  
  631.     ASSERT(hwnd != NULL);
  632.  
  633.     BOOL bDriverDisconnected = capDriverDisconnect(hwnd);
  634.     DbgLog(( LOG_ERROR|LOG_TRACE, 2
  635.            , TEXT("Driver disconnect: %x"), bDriverDisconnected) );
  636.  
  637.     BOOL bWindowGone = DestroyWindow(hwnd);
  638.     DbgLog((LOG_ERROR|LOG_TRACE, 2, TEXT("Window destroy: %x"), bWindowGone) );
  639.  
  640.     return (bDriverDisconnected && bWindowGone);
  641. }
  642.  
  643.  
  644. //
  645. // VideoCallback
  646. //
  647. // The AVICap Video callback. Keep a copy of the buffer we are given
  648. // May be called after the worker thread, or even the pin has gone away, depending
  649. // on AVICap's internal timing. Therefore be very careful with the pointers we use.
  650. LRESULT CALLBACK CVidStream::VideoCallback(HWND hwnd, LPVIDEOHDR lpVHdr) {
  651.  
  652.     if (m_lObjectCount == 0) {
  653.         return (LRESULT) TRUE; // the video stream has gone away
  654.                                // so we can ignore this buffer.
  655.     }
  656.  
  657.     ASSERT(m_lObjectCount == 1);
  658.  
  659.     CVidStream *pThis = (CVidStream *) GetWindowLong(hwnd, GWL_USERDATA);
  660.  
  661.     ASSERT(pThis);
  662.  
  663.     if (pThis->m_plFilled == NULL) {    // The filled list has gone away.
  664.                                         // ignore this buffer
  665.         return (LRESULT) TRUE;
  666.     }
  667.     else {
  668.         pThis->m_plFilled->Add(lpVHdr);
  669.     }
  670.  
  671.     return (LRESULT) TRUE;
  672. }
  673.  
  674.  
  675.  
  676. // Override to handle quality messages
  677. STDMETHODIMP CVidStream::Notify(IFilter * pSender, Quality q)
  678. {
  679.     // if q.Late.RefTime.QuadPart >0 then skip ahead that much.
  680.     // thereafter adjust the time per frame by a factor of
  681.     // 1000/q.Proportion (watch for truncation of fractions
  682.     // do the multiply first!
  683.  
  684.     // Not Yet Implemented :-)
  685.  
  686.     return NOERROR;
  687. }
  688.  
  689.  
  690.  
  691. //
  692. // DoBufferProcessingLoop
  693. //
  694. // Replace the loop in CSourceStream with something of my own, so that I can
  695. // wait for buffers & commands.
  696. HRESULT CVidStream::DoBufferProcessingLoop(void) {
  697.  
  698.     HANDLE haWaitObjects[2];
  699.     {
  700.         CAutoLock l(&m_cSharedState);
  701.  
  702.         haWaitObjects[0] = GetRequestHandle();  // command handle first so that
  703.                                                 // it has priority over buffers
  704.         haWaitObjects[1] = m_plFilled->GetWaitHandle();
  705.     }
  706.  
  707.     for (;;) {
  708.  
  709.         // wait for commands or buffers
  710.         DWORD dwWaitObject
  711.             = WaitForMultipleObjects(2, haWaitObjects, FALSE, INFINITE);
  712.  
  713.         if (dwWaitObject == WAIT_OBJECT_0) {    // thread command request
  714.  
  715.         Command com;
  716.     
  717.             EXECUTE_ASSERT(CheckRequest(&com));
  718.             switch (com) {
  719.             case CMD_RUN:
  720.  
  721.         com = GetRequest();
  722.  
  723.                 if (m_ThreadState != Running) {
  724.                     capCaptureSequenceNoFile(m_hwCapCapturing);
  725.                 }
  726.                 m_ThreadState = Running;
  727.                 Reply(NOERROR);
  728.                 break;
  729.  
  730.             case CMD_PAUSE:
  731.  
  732.         com = GetRequest();
  733.         
  734.                 switch (m_ThreadState) {
  735.                 case Stopped:
  736.                     capGrabFrame(m_hwCapCapturing);
  737.             m_ThreadState = Paused; // mark that we have our poster
  738.                     break;
  739.                 case Running:
  740.             // !!!! why is this commented out?
  741.                     // -- answer: see CVidCap::Pause() for what happens
  742.                     // when we pause from running and why (we stop
  743.                     // and repause).
  744. //                  capCaptureStop(m_hwCapCapturing);
  745. //                  break;
  746.                 default:
  747.                     // null op
  748.                     break;
  749.                 }
  750.                 m_ThreadState = Paused;
  751.                 Reply(NOERROR);
  752.                 break;
  753.  
  754.             case CMD_STOP:
  755.  
  756.                 if (m_ThreadState == Running) {
  757.                     capCaptureStop(m_hwCapCapturing);
  758.                 }
  759.                 m_ThreadState = Stopped;
  760.                 DbgLog((LOG_TRACE, 1, TEXT("Seen Stop command")));
  761.                 // don't reply here as that is done by CSourceStream
  762.                 return NOERROR;
  763.  
  764.             default:
  765.  
  766.                 ASSERT(!"Unexpected thread command");
  767.         com = GetRequest();
  768.                 break;
  769.             }
  770.  
  771.         }
  772.         else if (dwWaitObject == (WAIT_OBJECT_0 + 1)) { // m_plFilled
  773.  
  774.             // Process the buffer we've just been signalled on
  775.             IMediaSample *pSample;
  776.  
  777.             // get a buffer to put this video data in
  778.             HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0);
  779.             if (FAILED(hr)) {
  780.                 continue;
  781.             }
  782.  
  783.             FillBuffer(pSample);
  784.  
  785.             Deliver(pSample);
  786.  
  787.             pSample->Release();
  788.  
  789.         }
  790.         else {  // get out - otherwise we will infinite loop...
  791.  
  792.             DbgLog((LOG_TRACE, 1
  793.                    , TEXT("Unexpected buffer/command wait return: %d")
  794.                    , dwWaitObject));
  795.             return E_UNEXPECTED;
  796.         }
  797.     }
  798.  
  799.     ASSERT(m_ThreadState == Stopped);
  800.  
  801.     return NOERROR;
  802. }
  803.  
  804.  
  805. //
  806. // FillBuffer
  807. //
  808. // Take the buffer from the head of the video buffer list.
  809. // We will only be called when there is such a buffer
  810. HRESULT CVidStream::FillBuffer(IMediaSample *pSample) {
  811.  
  812.     CAutoLock l(&m_cSharedState);
  813.  
  814.     HRESULT hr = m_plFilled->RemoveHeadIntoSample(pSample);
  815.  
  816.     if (SUCCEEDED(hr)) {
  817.         if (m_fFormatDirty) {       // we need to pass on a format change
  818.                                     // ! In practice, since change is only allowed on
  819.                                     // an inactive pin, this will be when we process
  820.                                     // the first sample.
  821.             CMediaType mt;
  822.             GetMediaType(&mt);
  823.             pSample->SetMediaType(&mt);
  824.  
  825.             m_fFormatDirty = FALSE;
  826.         }
  827.     }
  828.  
  829.     return hr;
  830. }
  831.  
  832.  
  833. // *
  834. // * IVideoCaptureConfigure implementation
  835. // *
  836.  
  837.  
  838. //
  839. // NonDelegatingQueryInterface
  840. //
  841. // Expose the IVideoCaptureConfigure interface, and pass up any
  842. // other requests.
  843. STDMETHODIMP CVidStream::NonDelegatingQueryInterface(REFIID riid, void ** ppv) {
  844.  
  845.    if (riid == IID_IVideoCaptureConfigure)
  846.        return GetInterface( (IVideoCaptureConfigure *) this, ppv);
  847.    else
  848.        return CSourceStream::NonDelegatingQueryInterface(riid, ppv);
  849. }
  850.  
  851.  
  852. //
  853. // GetDriverName
  854. //
  855. // Place the driver name in DriverName. Allocate memory if required
  856. STDMETHODIMP CVidStream::get_DriverName(BSTR DriverName) {
  857.  
  858.     CAutoLock lock(m_pFilter->pStateLock());
  859.  
  860.     if (DriverName == NULL) { // we need to allocate the BSTR
  861.  
  862.         DriverName = SysAllocStringLen(m_szName, giDriverNameStrLen);
  863.         if (DriverName == NULL)
  864.             return E_OUTOFMEMORY;
  865.  
  866.     }
  867.     else {      // we have been given an allocated BSTR
  868.         if (SysStringLen(DriverName) < giDriverNameStrLen) {
  869.  
  870.             if (!SysReAllocStringLen(&DriverName, m_szName, giDriverNameStrLen))
  871.                 return E_OUTOFMEMORY;
  872.         }
  873.         else {  // length is OK
  874.             lstrcpyW(DriverName, m_szName);
  875.         }
  876.     }
  877.  
  878.     return NOERROR;
  879. }
  880.  
  881.  
  882. //
  883. // GetDriverVersion
  884. //
  885. // Place the driver's version string in DriverVersion. Allocate memory if necessary
  886. STDMETHODIMP CVidStream::get_DriverVersion(BSTR DriverVersion) {
  887.  
  888.     CAutoLock lock(m_pFilter->pStateLock());
  889.  
  890.     if (DriverVersion == NULL) { // we need to allocate the BSTR
  891.  
  892.         DriverVersion = SysAllocStringLen(m_szVersion, giDriverVerStrLen);
  893.         if (DriverVersion == NULL)
  894.             return E_OUTOFMEMORY;
  895.     }
  896.     else {      // we have been given an allocated BSTR
  897.         if (SysStringLen(DriverVersion) < giDriverVerStrLen) {
  898.  
  899.             if (!SysReAllocStringLen( &DriverVersion
  900.                                     , m_szVersion
  901.                                     , giDriverVerStrLen
  902.                                     )
  903.                )
  904.                 return E_OUTOFMEMORY;
  905.         }
  906.         else {  // length is OK
  907.             lstrcpyW(DriverVersion, m_szVersion);
  908.         }
  909.     }
  910.  
  911.     return NOERROR;
  912. }
  913.  
  914.  
  915. //
  916. // get_SupportsVideoSourceDialog
  917. //
  918. STDMETHODIMP CVidStream::get_SupportsVideoSourceDialog(void) {
  919.  
  920.     CAutoLock lock(m_pFilter->pStateLock());
  921.  
  922.     if (SupportsVideoDialog(Source))
  923.         return NOERROR;
  924.     else
  925.         return S_FALSE;
  926. }
  927.  
  928.  
  929. //
  930. // get_SupportsVideoCompressionDialog
  931. //
  932. STDMETHODIMP CVidStream::get_SupportsVideoCompressionDialog(void) {
  933.  
  934.     CAutoLock lock(m_pFilter->pStateLock());
  935.  
  936.     if (SupportsVideoDialog(Compression))
  937.         return NOERROR;
  938.     else
  939.         return S_FALSE;
  940. }
  941.  
  942.  
  943. //
  944. // get_SupportsVideoFormatDialog
  945. //
  946. STDMETHODIMP CVidStream::get_SupportsVideoFormatDialog(void) {
  947.  
  948.     CAutoLock lock(m_pFilter->pStateLock());
  949.  
  950.     if (SupportsVideoDialog(Format))
  951.         return NOERROR;
  952.     else
  953.         return S_FALSE;
  954. }
  955.  
  956.  
  957. //
  958. // get_SupportsVideoDisplayDialog
  959. //
  960. STDMETHODIMP CVidStream::get_SupportsVideoDisplayDialog(void) {
  961.  
  962.     CAutoLock lock(m_pFilter->pStateLock());
  963.  
  964.     if (SupportsVideoDialog(Display))
  965.         return NOERROR;
  966.     else
  967.         return S_FALSE;
  968. }
  969.  
  970.  
  971. //
  972. // DisplayVideoDialog
  973. //
  974. // put the requested dialog on screen
  975. BOOL CVidStream::DisplayVideoDialog(HWND hwnd, DialogType Dialog) {
  976.  
  977.     CAutoLock lock(m_pFilter->pStateLock());
  978.  
  979.     switch (Dialog) {
  980.     case Source:
  981.         return capDlgVideoSource(hwnd);
  982.     case Display:
  983.         return capDlgVideoDisplay(hwnd);
  984.     case Format:
  985.         return capDlgVideoFormat(hwnd);
  986.     case Compression:
  987.         return capDlgVideoCompression(hwnd);
  988.     default:
  989.         return FALSE;
  990.     }
  991. }
  992.  
  993.  
  994. //
  995. // SupportsVideoDialog
  996. //
  997. // Does the driver support this dialog?
  998. BOOL CVidStream::SupportsVideoDialog(DialogType Dialog) {
  999.  
  1000.     CAutoLock lock(m_pFilter->pStateLock());
  1001.  
  1002.     switch (Dialog) {
  1003.     case Source:
  1004.         return m_SupportsVideoSourceDialog;
  1005.     case Display:
  1006.         return m_SupportsVideoDisplayDialog;
  1007.     case Format:
  1008.         return m_SupportsVideoFormatDialog;
  1009.     case Compression:
  1010.         return TRUE;
  1011.     default:
  1012.         return FALSE;
  1013.     }
  1014. }
  1015.  
  1016.  
  1017. //
  1018. // DisplayDialog
  1019. //
  1020. // Display the dialog if: the driver supports it
  1021. //                        and we are not active.
  1022. HRESULT CVidStream::DisplayDialog(DialogType Dialog) {
  1023.  
  1024.     CAutoLock lock(m_pFilter->pStateLock());
  1025.     CAutoLock l(&m_cSharedState);
  1026.  
  1027.     if (!SupportsVideoDialog(Dialog))   // Can we display this dialog?
  1028.         return E_UNEXPECTED;
  1029.  
  1030.     if (m_hwCapCapturing == NULL) { // we are not currently active.
  1031.         HWND hwndCap = CreateCaptureWindow(0);
  1032.         if (hwndCap == NULL) {
  1033.             return E_FAIL;
  1034.         }
  1035.  
  1036.         BOOL fFormatOK = TRUE;  // Has the user selected an acceptable format?
  1037.         do {
  1038.  
  1039.             if (!DisplayVideoDialog(hwndCap, Dialog)) {
  1040.                 DestroyCaptureWindow(hwndCap);
  1041.                 return E_FAIL;
  1042.             }
  1043.  
  1044.             if (IsConnected()) {        // We need to re-negotiate the format
  1045.  
  1046.                 CMediaType mt;
  1047.                 GetMediaType(&mt);
  1048.  
  1049.                 HRESULT hr = m_Connected->QueryAccept(&mt);  // Acceptable to peer?
  1050.  
  1051.                 if (hr == S_OK) {               // our peer likes the format
  1052.                     m_fFormatDirty = TRUE;
  1053.                     fFormatOK = TRUE;
  1054.                 }
  1055.                 else if (hr == S_FALSE) {       // unacceptable format
  1056.  
  1057.                     // !!! Need .rc file for these...
  1058.                     int iRet = MessageBox(NULL,
  1059.                                           TEXT("The format selected is not available, please select another."),
  1060.                                           TEXT("Format Unavailable"),
  1061.                                           MB_OK | MB_ICONEXCLAMATION);
  1062.                     if (iRet == 0) {
  1063.                         DestroyCaptureWindow(hwndCap);
  1064.                         return E_OUTOFMEMORY;
  1065.                     }
  1066.                     if (iRet != IDOK) {
  1067.                         DestroyCaptureWindow(hwndCap);
  1068.                         return E_FAIL;  // not out of memory, but something
  1069.                                         // else bizarre is going on...
  1070.                     }
  1071.                     fFormatOK = FALSE;
  1072.                 }
  1073.                 else {                          // an error occured...
  1074.                     DestroyCaptureWindow(hwndCap);
  1075.                     return E_FAIL;
  1076.                 }
  1077.             }
  1078.         } while (!fFormatOK);
  1079.  
  1080.         DestroyCaptureWindow(hwndCap);
  1081.         return NOERROR;
  1082.     }
  1083.     else { // we are active
  1084.         return E_ACCESSDENIED;
  1085.     }
  1086.  
  1087. }
  1088.  
  1089.  
  1090. //
  1091. // SetRequestedMicroSecondsPerFrame
  1092. //
  1093. // Set the number of microseconds per frame to MicroSecondsPerFrame.
  1094. // returns: S_OK if successful
  1095. //          E_ACCESSDENIED if you can't change at the moment - if the pin is active
  1096. // Use GetMicroSecondsPerFrame to find the actual rate set.
  1097. STDMETHODIMP CVidStream::
  1098.     put_RequestedMicroSecondsPerFrame (long MicroSecondsPerFrame) {
  1099.  
  1100.     CAutoLock lock(m_pFilter->pStateLock());
  1101.     CAutoLock l(&m_cSharedState);
  1102.  
  1103.     if (m_hwCapCapturing != NULL)
  1104.         return E_ACCESSDENIED;
  1105.  
  1106.     m_dwMicroSecPerFrame = MicroSecondsPerFrame;
  1107.  
  1108.     return NOERROR;
  1109.  
  1110. }
  1111.  
  1112.  
  1113. //
  1114. // GetMicroSecondsPerFrame
  1115. //
  1116. // returns the current number of microseconds per frame
  1117. // in MicroSecondsperFrame.
  1118. STDMETHODIMP CVidStream::
  1119.     get_RequestedMicroSecondsPerFrame (long *MicroSecondsPerFrame) {
  1120.  
  1121.     CAutoLock lock(m_pFilter->pStateLock());
  1122.     CAutoLock l(&m_cSharedState);
  1123.  
  1124.     *MicroSecondsPerFrame = m_dwMicroSecPerFrame;
  1125.     return NOERROR;
  1126. }
  1127.  
  1128.  
  1129. // *
  1130. // * CVideoBufferList
  1131. // *
  1132.  
  1133.  
  1134. //
  1135. // CVideoBufferList::Constructor
  1136. //
  1137. CVideoBufferList::CVideoBufferList( int iBufferSize
  1138.                                   , CRefTime rtMilliSecPerFrame
  1139.                                   , CVidCap *pFilter
  1140.                                   , int iBuffers
  1141.                                   )
  1142.     :m_rtMilliSecPerFrame(rtMilliSecPerFrame),
  1143.      m_uiFramesCaptured(0),
  1144.      m_uiFramesSkipped(0),
  1145.      m_uiFramesDelivered(0),
  1146.      m_FirstBuffer(TRUE),
  1147.      m_rtStartTime(0L),
  1148.      m_rtPrevEnd(0L),
  1149.      m_pFilter(pFilter),
  1150.      m_evList(TRUE),
  1151.      m_lFilled(NAME("Pending, full, buffers"),
  1152.                DEFAULTCACHE),   // default cache
  1153.      m_lFree(NAME("Empty buffers"),
  1154.                DEFAULTCACHE)    // default cache
  1155. {
  1156.     for (int i=0; i < iBuffers; i++) {
  1157.  
  1158.         CBuffer *pBuffer = new CBuffer(iBufferSize);
  1159.         if (pBuffer == NULL) {
  1160.             return;
  1161.         }
  1162.         m_lFree.AddTail(pBuffer);
  1163.  
  1164.     }
  1165. }
  1166.  
  1167.  
  1168. //
  1169. // CVideoBufferList::Destructor
  1170. //
  1171. CVideoBufferList::~CVideoBufferList() {
  1172.  
  1173.     while (m_lFree.GetCount() > 0) {            // free buffers on the free list...
  1174.  
  1175.         CBuffer *pBuff = m_lFree.RemoveHead();
  1176.         delete pBuff;
  1177.     }
  1178.  
  1179.  
  1180.     DbgLog((LOG_TRACE, 1
  1181.            , TEXT("Filled frames not sent before stop issued: %d")
  1182.            , m_lFilled.GetCount()));
  1183.  
  1184.     while (m_lFilled.GetCount() > 0) { //... then free buffers on filled list
  1185.                                        // - we don't care about the data they hold.
  1186.  
  1187.         CBuffer *pBuff = m_lFilled.RemoveHead();
  1188.         delete pBuff;
  1189.     }
  1190.  
  1191.     DbgLog((LOG_TRACE, 1, TEXT("Frames Captured: %d"), m_uiFramesCaptured));
  1192.     DbgLog((LOG_TRACE, 1, TEXT("Frames Skipped: %d"), m_uiFramesSkipped));
  1193.     DbgLog((LOG_TRACE, 1, TEXT("Frames Delivered: %d"), m_uiFramesDelivered));
  1194. }
  1195.  
  1196.  
  1197. //
  1198. // Add
  1199. //
  1200. // Add a video buffer to this list. gets a free buffer from m_lFree, copies
  1201. // the video data into it and then puts it on m_lFilled.
  1202. // if m_lFree is empty, fail silently, effectively skipping the buffer.
  1203. HRESULT CVideoBufferList::Add(LPVIDEOHDR lpVHdr) {
  1204.  
  1205.     CAutoLock lck(&m_ListCrit);
  1206.  
  1207.     if (m_lFree.GetCount() > 0) {
  1208.  
  1209.         CBuffer *pBuff = m_lFree.RemoveHead();
  1210.         pBuff->CopyBuffer(lpVHdr);
  1211.         m_lFilled.AddTail(pBuff);
  1212.         if (m_lFilled.GetCount() == 1) {
  1213.             m_evList.Set();
  1214.         }
  1215.  
  1216.         m_uiFramesCaptured++;
  1217.     }
  1218.     else {      // replace oldest filled frame...
  1219.  
  1220.         if (m_lFilled.GetCount() > 0) { // ...but only if there is one
  1221.             CBuffer *pBuff = m_lFilled.RemoveHead();
  1222.             pBuff->CopyBuffer(lpVHdr);
  1223.             m_lFilled.AddTail(pBuff);
  1224.             m_uiFramesCaptured++;
  1225.         }
  1226.  
  1227.         m_uiFramesSkipped++;
  1228.  
  1229.     }
  1230.  
  1231.     return NOERROR;
  1232. }
  1233.  
  1234.  
  1235. //
  1236. // RemoveHeadIntoSample
  1237. //
  1238. // Copy the head of the filled list into the supplied IMediaSample.
  1239. // Fail with E_UNEXPECTED if called on an empty m_lFilled;
  1240. HRESULT CVideoBufferList::RemoveHeadIntoSample(IMediaSample *pSample) {
  1241.  
  1242.     HRESULT hr;
  1243.     CAutoLock lck(&m_ListCrit);
  1244.  
  1245.     if (m_lFilled.GetCount() < 1) {
  1246.         hr = E_UNEXPECTED;
  1247.     } else {
  1248.  
  1249.         CBuffer *pBuff = m_lFilled.RemoveHead();
  1250.         if (m_lFilled.GetCount() == 0) {
  1251.             m_evList.Reset();
  1252.         }
  1253.  
  1254.         BYTE *pSampleBuffer;
  1255.         hr = pSample->GetPointer(&pSampleBuffer);
  1256.         if (SUCCEEDED(hr)) {
  1257.  
  1258.         LONG lSampleSize = pSample->GetSize();
  1259.             ASSERT(pBuff->GetSize() <= pSample->GetSize());
  1260.  
  1261.         // Copy the captured data
  1262.             CopyMemory((void *)pSampleBuffer, pBuff->GetPointer(), lSampleSize);
  1263.         pSample->SetActualDataLength(lSampleSize);
  1264.  
  1265.             FILTER_STATE State;
  1266.             m_pFilter->GetState(0, &State);
  1267.  
  1268.             CRefTime rtStart;
  1269.             if (State == State_Paused) {
  1270.                 // this is a poster frame
  1271.                 rtStart = 0;
  1272.             } else if (m_FirstBuffer && (State == State_Running)) {
  1273.  
  1274.                 m_pFilter->StreamTime(m_rtStartTime);   // get the current stream time
  1275.                                                         // to allow for our start up time
  1276.                 rtStart = m_rtStartTime;
  1277.  
  1278.                 m_FirstBuffer = FALSE;
  1279.  
  1280.             } else {
  1281.  
  1282.                 rtStart = m_rtStartTime + pBuff->GetCaptureTime();
  1283.             }
  1284.  
  1285.             DbgLog((LOG_TIMING, 1, TEXT("Sample Time: %d"), rtStart.Millisecs()));
  1286.             CRefTime rtEnd = rtStart + CRefTime(m_rtMilliSecPerFrame);
  1287.             ASSERT(rtStart <= rtEnd);
  1288.  
  1289.             pSample->SetTime((REFERENCE_TIME*)&rtStart,
  1290.                              (REFERENCE_TIME*)&rtEnd);
  1291.  
  1292.             m_rtPrevEnd = rtEnd;
  1293.             m_uiFramesDelivered++;
  1294.             m_lFree.AddTail(pBuff);
  1295.         }
  1296.     }
  1297.  
  1298.     return hr;
  1299. }
  1300.  
  1301.  
  1302. //
  1303. // CBuffer::Constructor
  1304. //
  1305. //Get a new buffer of the maximum size we will handle
  1306. CVideoBufferList::CBuffer::CBuffer(int iBufferSize) {
  1307.  
  1308.     m_pData = new BYTE[iBufferSize];
  1309.  
  1310.     // Set the two length fields to the maximum size
  1311.     m_iCaptureDataLength = m_iDataLength = iBufferSize;
  1312.  
  1313. }
  1314.  
  1315.  
  1316. //
  1317. // CVideoDataBuffer::Destructor
  1318. //
  1319. CVideoBufferList::CBuffer::~CBuffer() {
  1320.  
  1321.     delete m_pData;
  1322. }
  1323.  
  1324.  
  1325. //
  1326. // CopyBuffer
  1327. //
  1328. // Copy the supplied data in lpVHdr->lpData to this Buffer
  1329. void CVideoBufferList::CBuffer::CopyBuffer(LPVIDEOHDR lpVHdr) {
  1330.  
  1331.     ASSERT((DWORD) m_iDataLength >= lpVHdr->dwBufferLength);
  1332.  
  1333.     // Copy the captured video buffer, and remember its length
  1334.     CopyMemory(m_pData, lpVHdr->lpData, (m_iCaptureDataLength = lpVHdr->dwBufferLength));
  1335.  
  1336.     m_rt = CRefTime((LONG)lpVHdr->dwTimeCaptured); // use constructor to initialise
  1337.                                                    // with Millisec.
  1338. }
  1339.