home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / ctlutil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-20  |  57.0 KB  |  2,574 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. // Base classes implementing IDispatch parsing for the basic control dual
  13. // interfaces. Derive from these and implement just the custom method and
  14. // property methods. We also implement CPosPassThru that can be used by
  15. // renderers and transforms to pass by IMediaPosition and IMediaSelection
  16.  
  17.  
  18. #include <streams.h>
  19. #include <limits.h>
  20.  
  21.  
  22. // --- CBaseDispatch implementation ----------
  23.  
  24.  
  25. CBaseDispatch::CBaseDispatch() : m_pti(NULL)
  26. {
  27. }
  28.  
  29.  
  30. CBaseDispatch::~CBaseDispatch()
  31. {
  32.     if (m_pti) {
  33.         m_pti->Release();
  34.     }
  35. }
  36.  
  37.  
  38. // return 1 if we support GetTypeInfo
  39.  
  40. STDMETHODIMP
  41. CBaseDispatch::GetTypeInfoCount(UINT * pctinfo)
  42. {
  43.     CheckPointer(pctinfo,E_POINTER);
  44.     ValidateReadWritePtr(pctinfo,sizeof(UINT *));
  45.     *pctinfo = 1;
  46.     return S_OK;
  47. }
  48.  
  49.  
  50. typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)(
  51.                             const OLECHAR FAR *szFile,
  52.                             ITypeLib FAR* FAR* pptlib);
  53.  
  54. typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid,
  55.                             WORD wVerMajor,
  56.                             WORD wVerMinor,
  57.                             LCID lcid,
  58.                             ITypeLib FAR* FAR* pptlib);
  59.  
  60. // attempt to find our type library
  61.  
  62. STDMETHODIMP
  63. CBaseDispatch::GetTypeInfo(
  64.   REFIID riid,
  65.   UINT itinfo,
  66.   LCID lcid,
  67.   ITypeInfo ** pptinfo)
  68. {
  69.     CheckPointer(pptinfo,E_POINTER);
  70.     ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *));
  71.     HRESULT hr;
  72.  
  73.     *pptinfo = NULL;
  74.  
  75.     // we only support one type element
  76.     if (0 != itinfo) {
  77.         return TYPE_E_ELEMENTNOTFOUND;
  78.     }
  79.  
  80.     if (NULL == pptinfo) {
  81.         return E_POINTER;
  82.     }
  83.  
  84.     // always look for neutral
  85.     if (NULL == m_pti) {
  86.  
  87.         LPLOADTYPELIB       lpfnLoadTypeLib;
  88.         LPLOADREGTYPELIB    lpfnLoadRegTypeLib;
  89.         ITypeLib            *ptlib;
  90.         HINSTANCE           hInst;
  91.  
  92.         static const TCHAR szOle32Aut[]   = TEXT("OleAut32.dll");
  93.         static const char  szTypeLib[]    = "LoadTypeLib";
  94.         static const char  szRegTypeLib[] = "LoadRegTypeLib";
  95.         static const WCHAR szControl[]    = L"control.tlb";
  96.  
  97.         //
  98.         // Try to get the Ole32Aut.dll module handle.
  99.         //
  100.  
  101.         hInst = GetModuleHandle(szOle32Aut);
  102.         if (hInst == NULL) {
  103.  
  104.             hInst = LoadLibrary(szOle32Aut);
  105.             if (hInst == NULL) {
  106.                 DWORD dwError = GetLastError();
  107.                 return HRESULT_FROM_WIN32(dwError);
  108.             }
  109.         }
  110.         lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst,
  111.                                                               szRegTypeLib);
  112.         if (lpfnLoadRegTypeLib == NULL) {
  113.             DWORD dwError = GetLastError();
  114.             return HRESULT_FROM_WIN32(dwError);
  115.         }
  116.  
  117.         hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0
  118.                                    lcid, &ptlib);
  119.  
  120.         if (FAILED(hr)) {
  121.  
  122.             // attempt to load directly - this will fill the
  123.             // registry in if it finds it
  124.  
  125.             lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib);
  126.             if (lpfnLoadTypeLib == NULL) {
  127.                 DWORD dwError = GetLastError();
  128.                 return HRESULT_FROM_WIN32(dwError);
  129.             }
  130.  
  131.             hr = (*lpfnLoadTypeLib)(szControl, &ptlib);
  132.             if (FAILED(hr)) {
  133.                 return hr;
  134.             }
  135.         }
  136.  
  137.         hr = ptlib->GetTypeInfoOfGuid(
  138.                     riid,
  139.                     &m_pti);
  140.  
  141.         ptlib->Release();
  142.  
  143.         if (FAILED(hr)) {
  144.             return hr;
  145.         }
  146.     }
  147.  
  148.     *pptinfo = m_pti;
  149.     m_pti->AddRef();
  150.     return S_OK;
  151. }
  152.  
  153.  
  154. STDMETHODIMP
  155. CBaseDispatch::GetIDsOfNames(
  156.   REFIID riid,
  157.   OLECHAR  ** rgszNames,
  158.   UINT cNames,
  159.   LCID lcid,
  160.   DISPID * rgdispid)
  161. {
  162.     // although the IDispatch riid is dead, we use this to pass from
  163.     // the interface implementation class to us the iid we are talking about.
  164.  
  165.     ITypeInfo * pti;
  166.     HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti);
  167.  
  168.     if (SUCCEEDED(hr)) {
  169.  
  170.         try {
  171.             hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid);
  172.         } except(EXCEPTION_EXECUTE_HANDLER) {
  173.             hr = E_FAIL;
  174.         }
  175.  
  176.         pti->Release();
  177.     }
  178.     return hr;
  179. }
  180.  
  181.  
  182. // --- CMediaControl implementation ---------
  183.  
  184.  
  185. CMediaControl::CMediaControl(TCHAR * name,
  186.                              LPUNKNOWN pUnk,
  187.                              HRESULT * phr) :
  188.     CUnknown(name, pUnk, phr)
  189. {
  190. }
  191.  
  192.  
  193. CMediaControl::~CMediaControl()
  194. {
  195. }
  196.  
  197.  
  198. // expose our interfaces IMediaControl and IUnknown
  199.  
  200. STDMETHODIMP
  201. CMediaControl::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  202. {
  203.     CheckPointer(ppv,E_POINTER)
  204.     ValidateReadWritePtr(ppv,sizeof(PVOID));
  205.     if (riid == IID_IMediaControl) {
  206.         return GetInterface( (IMediaControl *) this, ppv);
  207.     } else {
  208.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  209.     }
  210. }
  211.  
  212.  
  213. // return 1 if we support GetTypeInfo
  214.  
  215. STDMETHODIMP
  216. CMediaControl::GetTypeInfoCount(UINT * pctinfo)
  217. {
  218.     return m_basedisp.GetTypeInfoCount(pctinfo);
  219. }
  220.  
  221.  
  222. // attempt to find our type library
  223.  
  224. STDMETHODIMP
  225. CMediaControl::GetTypeInfo(
  226.   UINT itinfo,
  227.   LCID lcid,
  228.   ITypeInfo ** pptinfo)
  229. {
  230.     return m_basedisp.GetTypeInfo(
  231.                 IID_IMediaControl,
  232.                 itinfo,
  233.                 lcid,
  234.                 pptinfo);
  235. }
  236.  
  237.  
  238. STDMETHODIMP
  239. CMediaControl::GetIDsOfNames(
  240.   REFIID riid,
  241.   OLECHAR  ** rgszNames,
  242.   UINT cNames,
  243.   LCID lcid,
  244.   DISPID * rgdispid)
  245. {
  246.     return m_basedisp.GetIDsOfNames(
  247.                         IID_IMediaControl,
  248.                         rgszNames,
  249.                         cNames,
  250.                         lcid,
  251.                         rgdispid);
  252. }
  253.  
  254.  
  255. STDMETHODIMP
  256. CMediaControl::Invoke(
  257.   DISPID dispidMember,
  258.   REFIID riid,
  259.   LCID lcid,
  260.   WORD wFlags,
  261.   DISPPARAMS * pdispparams,
  262.   VARIANT * pvarResult,
  263.   EXCEPINFO * pexcepinfo,
  264.   UINT * puArgErr)
  265. {
  266.     // this parameter is a dead leftover from an earlier interface
  267.     if (IID_NULL != riid) {
  268.         return DISP_E_UNKNOWNINTERFACE;
  269.     }
  270.  
  271.     ITypeInfo * pti;
  272.     HRESULT hr = GetTypeInfo(0, lcid, &pti);
  273.  
  274.     if (FAILED(hr)) {
  275.         return hr;
  276.     }
  277.  
  278.     hr = pti->Invoke(
  279.             (IMediaControl *)this,
  280.             dispidMember,
  281.             wFlags,
  282.             pdispparams,
  283.             pvarResult,
  284.             pexcepinfo,
  285.             puArgErr);
  286.  
  287.     pti->Release();
  288.     return hr;
  289. }
  290.  
  291.  
  292. // --- CMediaEvent implementation ----------
  293.  
  294.  
  295. CMediaEvent::CMediaEvent(TCHAR * name,
  296.                          LPUNKNOWN pUnk,
  297.                          HRESULT * phr) :
  298.     CUnknown(name, pUnk, phr)
  299. {
  300. }
  301.  
  302.  
  303. CMediaEvent::~CMediaEvent()
  304. {
  305. }
  306.  
  307.  
  308. // expose our interfaces IMediaEvent and IUnknown
  309.  
  310. STDMETHODIMP
  311. CMediaEvent::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  312. {
  313.     CheckPointer(ppv,E_POINTER);
  314.     ValidateReadWritePtr(ppv,sizeof(PVOID));
  315.     if (riid == IID_IMediaEvent) {
  316.         return GetInterface( (IMediaEvent *) this, ppv);
  317.     } else {
  318.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  319.     }
  320. }
  321.  
  322.  
  323. // return 1 if we support GetTypeInfo
  324.  
  325. STDMETHODIMP
  326. CMediaEvent::GetTypeInfoCount(UINT * pctinfo)
  327. {
  328.     return m_basedisp.GetTypeInfoCount(pctinfo);
  329. }
  330.  
  331.  
  332. // attempt to find our type library
  333.  
  334. STDMETHODIMP
  335. CMediaEvent::GetTypeInfo(
  336.   UINT itinfo,
  337.   LCID lcid,
  338.   ITypeInfo ** pptinfo)
  339. {
  340.     return m_basedisp.GetTypeInfo(
  341.                 IID_IMediaEvent,
  342.                 itinfo,
  343.                 lcid,
  344.                 pptinfo);
  345. }
  346.  
  347.  
  348. STDMETHODIMP
  349. CMediaEvent::GetIDsOfNames(
  350.   REFIID riid,
  351.   OLECHAR  ** rgszNames,
  352.   UINT cNames,
  353.   LCID lcid,
  354.   DISPID * rgdispid)
  355. {
  356.     return m_basedisp.GetIDsOfNames(
  357.                         IID_IMediaEvent,
  358.                         rgszNames,
  359.                         cNames,
  360.                         lcid,
  361.                         rgdispid);
  362. }
  363.  
  364.  
  365. STDMETHODIMP
  366. CMediaEvent::Invoke(
  367.   DISPID dispidMember,
  368.   REFIID riid,
  369.   LCID lcid,
  370.   WORD wFlags,
  371.   DISPPARAMS * pdispparams,
  372.   VARIANT * pvarResult,
  373.   EXCEPINFO * pexcepinfo,
  374.   UINT * puArgErr)
  375. {
  376.     // this parameter is a dead leftover from an earlier interface
  377.     if (IID_NULL != riid) {
  378.         return DISP_E_UNKNOWNINTERFACE;
  379.     }
  380.  
  381.     ITypeInfo * pti;
  382.     HRESULT hr = GetTypeInfo(0, lcid, &pti);
  383.  
  384.     if (FAILED(hr)) {
  385.         return hr;
  386.     }
  387.  
  388.     hr = pti->Invoke(
  389.             (IMediaEvent *)this,
  390.             dispidMember,
  391.             wFlags,
  392.             pdispparams,
  393.             pvarResult,
  394.             pexcepinfo,
  395.             puArgErr);
  396.  
  397.     pti->Release();
  398.     return hr;
  399. }
  400.  
  401.  
  402. // --- CMediaPosition implementation ----------
  403.  
  404.  
  405. CMediaPosition::CMediaPosition(TCHAR * name,
  406.                                LPUNKNOWN pUnk,
  407.                                HRESULT * phr) :
  408.     CUnknown(name, pUnk, phr)
  409. {
  410. }
  411.  
  412.  
  413. CMediaPosition::~CMediaPosition()
  414. {
  415. }
  416.  
  417.  
  418. // expose our interfaces IMediaPosition and IUnknown
  419.  
  420. STDMETHODIMP
  421. CMediaPosition::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  422. {
  423.     CheckPointer(ppv,E_POINTER);
  424.     ValidateReadWritePtr(ppv,sizeof(PVOID));
  425.     if (riid == IID_IMediaPosition) {
  426.         return GetInterface( (IMediaPosition *) this, ppv);
  427.     } else {
  428.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  429.     }
  430. }
  431.  
  432.  
  433. // return 1 if we support GetTypeInfo
  434.  
  435. STDMETHODIMP
  436. CMediaPosition::GetTypeInfoCount(UINT * pctinfo)
  437. {
  438.     return m_basedisp.GetTypeInfoCount(pctinfo);
  439. }
  440.  
  441.  
  442. // attempt to find our type library
  443.  
  444. STDMETHODIMP
  445. CMediaPosition::GetTypeInfo(
  446.   UINT itinfo,
  447.   LCID lcid,
  448.   ITypeInfo ** pptinfo)
  449. {
  450.     return m_basedisp.GetTypeInfo(
  451.                 IID_IMediaPosition,
  452.                 itinfo,
  453.                 lcid,
  454.                 pptinfo);
  455. }
  456.  
  457.  
  458. STDMETHODIMP
  459. CMediaPosition::GetIDsOfNames(
  460.   REFIID riid,
  461.   OLECHAR  ** rgszNames,
  462.   UINT cNames,
  463.   LCID lcid,
  464.   DISPID * rgdispid)
  465. {
  466.     return m_basedisp.GetIDsOfNames(
  467.                         IID_IMediaPosition,
  468.                         rgszNames,
  469.                         cNames,
  470.                         lcid,
  471.                         rgdispid);
  472. }
  473.  
  474.  
  475. STDMETHODIMP
  476. CMediaPosition::Invoke(
  477.   DISPID dispidMember,
  478.   REFIID riid,
  479.   LCID lcid,
  480.   WORD wFlags,
  481.   DISPPARAMS * pdispparams,
  482.   VARIANT * pvarResult,
  483.   EXCEPINFO * pexcepinfo,
  484.   UINT * puArgErr)
  485. {
  486.     // this parameter is a dead leftover from an earlier interface
  487.     if (IID_NULL != riid) {
  488.         return DISP_E_UNKNOWNINTERFACE;
  489.     }
  490.  
  491.     ITypeInfo * pti;
  492.     HRESULT hr = GetTypeInfo(0, lcid, &pti);
  493.  
  494.     if (FAILED(hr)) {
  495.         return hr;
  496.     }
  497.  
  498.     hr = pti->Invoke(
  499.             (IMediaPosition *)this,
  500.             dispidMember,
  501.             wFlags,
  502.             pdispparams,
  503.             pvarResult,
  504.             pexcepinfo,
  505.             puArgErr);
  506.  
  507.     pti->Release();
  508.     return hr;
  509. }
  510.  
  511.  
  512. // --- IMediaPosition and IMediaSelection pass through class ----------
  513.  
  514.  
  515. CPosPassThru::CPosPassThru(TCHAR *pName,
  516.                            LPUNKNOWN pUnk,
  517.                            HRESULT *phr,
  518.                            IPin *pPin) :
  519.     CMediaPosition(pName,pUnk,phr),
  520.     m_pPin(pPin)
  521. {
  522.     if (pPin == NULL) {
  523.         *phr = E_POINTER;
  524.         return;
  525.     }
  526. }
  527.  
  528.  
  529. // Expose our IMediaSelection and IMediaPosition interfaces
  530.  
  531. STDMETHODIMP
  532. CPosPassThru::NonDelegatingQueryInterface(REFIID riid,void **ppv)
  533. {
  534.     CheckPointer(ppv,E_POINTER);
  535.     *ppv = NULL;
  536.  
  537.     if (riid == IID_IMediaSelection) {
  538.         return GetInterface( (IMediaSelection *) this, ppv);
  539.     }
  540.     return CMediaPosition::NonDelegatingQueryInterface(riid,ppv);
  541. }
  542.  
  543.  
  544. // Return the IMediaPosition interface from our peer
  545.  
  546. HRESULT
  547. CPosPassThru::GetPeer(IMediaPosition ** ppMP)
  548. {
  549.     *ppMP = NULL;
  550.  
  551.     IPin *pConnected;
  552.     HRESULT hr = m_pPin->ConnectedTo(&pConnected);
  553.     if (FAILED(hr)) {
  554.         return E_NOTIMPL;
  555.     }
  556.     IMediaPosition * pMP;
  557.     hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP);
  558.     pConnected->Release();
  559.     if (FAILED(hr)) {
  560.         return E_NOTIMPL;
  561.     }
  562.  
  563.     *ppMP = pMP;
  564.     return S_OK;
  565. }
  566.  
  567.  
  568. // Return the IMediaSelection interface from our peer
  569.  
  570. HRESULT
  571. CPosPassThru::GetPeerSelection(IMediaSelection ** ppMS)
  572. {
  573.     *ppMS = NULL;
  574.  
  575.     IPin *pConnected;
  576.     HRESULT hr = m_pPin->ConnectedTo(&pConnected);
  577.     if (FAILED(hr)) {
  578.         return E_NOTIMPL;
  579.     }
  580.     IMediaSelection * pMS;
  581.     hr = pConnected->QueryInterface(IID_IMediaSelection, (void **) &pMS);
  582.     pConnected->Release();
  583.     if (FAILED(hr)) {
  584.         return E_NOTIMPL;
  585.     }
  586.  
  587.     *ppMS = pMS;
  588.     return S_OK;
  589. }
  590.  
  591.  
  592. // --- IMediaSelection methods ----------
  593.  
  594.  
  595. STDMETHODIMP
  596. CPosPassThru::IsFormatSupported(const GUID Format)
  597. {
  598.     IMediaSelection* pMS;
  599.     HRESULT hr = GetPeerSelection(&pMS);
  600.     if (FAILED(hr)) {
  601.         return hr;
  602.     }
  603.  
  604.     hr = pMS->IsFormatSupported(Format);
  605.     pMS->Release();
  606.     return hr;
  607. }
  608.  
  609.  
  610. STDMETHODIMP
  611. CPosPassThru::QueryPreferredFormat(GUID *pFormat)
  612. {
  613.     IMediaSelection* pMS;
  614.     HRESULT hr = GetPeerSelection(&pMS);
  615.     if (FAILED(hr)) {
  616.         return hr;
  617.     }
  618.  
  619.     hr = pMS->QueryPreferredFormat(pFormat);
  620.     pMS->Release();
  621.     return hr;
  622. }
  623.  
  624.  
  625. STDMETHODIMP
  626. CPosPassThru::SetTimeFormat(const GUID Format)
  627. {
  628.     IMediaSelection* pMS;
  629.     HRESULT hr = GetPeerSelection(&pMS);
  630.     if (FAILED(hr)) {
  631.         return hr;
  632.     }
  633.  
  634.     hr = pMS->SetTimeFormat(Format);
  635.     pMS->Release();
  636.     return hr;
  637. }
  638.  
  639.  
  640. STDMETHODIMP
  641. CPosPassThru::GetTimeFormat(GUID *pFormat)
  642. {
  643.     IMediaSelection* pMS;
  644.     HRESULT hr = GetPeerSelection(&pMS);
  645.     if (FAILED(hr)) {
  646.         return hr;
  647.     }
  648.  
  649.     hr = pMS->GetTimeFormat(pFormat);
  650.     pMS->Release();
  651.     return hr;
  652. }
  653.  
  654.  
  655. STDMETHODIMP
  656. CPosPassThru::GetDuration(LONGLONG *pDuration)
  657. {
  658.     IMediaSelection* pMS;
  659.     HRESULT hr = GetPeerSelection(&pMS);
  660.     if (FAILED(hr)) {
  661.         return hr;
  662.     }
  663.  
  664.     hr = pMS->GetDuration(pDuration);
  665.     pMS->Release();
  666.     return hr;
  667. }
  668.  
  669.  
  670. // If we don't have a current position then ask upstream
  671.  
  672. STDMETHODIMP
  673. CPosPassThru::GetCurrentPosition(LONGLONG *pCurrent)
  674. {
  675.     // Can we report the current position
  676.  
  677.     HRESULT hr = GetMediaTime(pCurrent,NULL);
  678.     if (SUCCEEDED(hr)) {
  679.         return NOERROR;
  680.     }
  681.  
  682.     IMediaSelection* pMS;
  683.     hr = GetPeerSelection(&pMS);
  684.     if (FAILED(hr)) {
  685.         return hr;
  686.     }
  687.  
  688.     // Ask upstream for the information
  689.  
  690.     hr = pMS->GetCurrentPosition(pCurrent);
  691.     pMS->Release();
  692.     return hr;
  693. }
  694.  
  695.  
  696. STDMETHODIMP
  697. CPosPassThru::GetStopPosition(LONGLONG *pStop)
  698. {
  699.     IMediaSelection* pMS;
  700.     HRESULT hr = GetPeerSelection(&pMS);
  701.     if (FAILED(hr)) {
  702.         return hr;
  703.     }
  704.  
  705.     hr = pMS->GetStopPosition(pStop);
  706.     pMS->Release();
  707.     return hr;
  708. }
  709.  
  710.  
  711. STDMETHODIMP
  712. CPosPassThru::SetSelection(LONGLONG Current,
  713.                            LONGLONG Stop,
  714.                            REFTIME *pTime)
  715. {
  716.     IMediaSelection* pMS;
  717.     HRESULT hr = GetPeerSelection(&pMS);
  718.     if (FAILED(hr)) {
  719.         return hr;
  720.     }
  721.  
  722.     hr = pMS->SetSelection(Current,Stop,pTime);
  723.     pMS->Release();
  724.     return hr;
  725. }
  726.  
  727.  
  728. // --- IMediaPosition methods ----------
  729.  
  730.  
  731. STDMETHODIMP
  732. CPosPassThru::get_Duration(REFTIME * plength)
  733. {
  734.     IMediaPosition* pMP;
  735.     HRESULT hr = GetPeer(&pMP);
  736.     if (FAILED(hr)) {
  737.         return hr;
  738.     }
  739.  
  740.     hr = pMP->get_Duration(plength);
  741.     pMP->Release();
  742.     return hr;
  743. }
  744.  
  745.  
  746. STDMETHODIMP
  747. CPosPassThru::get_CurrentPosition(REFTIME * pllTime)
  748. {
  749.     IMediaPosition* pMP;
  750.     HRESULT hr = GetPeer(&pMP);
  751.     if (FAILED(hr)) {
  752.         return hr;
  753.     }
  754.     hr = pMP->get_CurrentPosition(pllTime);
  755.     pMP->Release();
  756.     return hr;
  757. }
  758.  
  759.  
  760. STDMETHODIMP
  761. CPosPassThru::put_CurrentPosition(REFTIME llTime)
  762. {
  763.     IMediaPosition* pMP;
  764.     HRESULT hr = GetPeer(&pMP);
  765.     if (FAILED(hr)) {
  766.         return hr;
  767.     }
  768.     hr = pMP->put_CurrentPosition(llTime);
  769.     pMP->Release();
  770.     return hr;
  771. }
  772.  
  773.  
  774. STDMETHODIMP
  775. CPosPassThru::get_StopTime(REFTIME * pllTime)
  776. {
  777.     IMediaPosition* pMP;
  778.     HRESULT hr = GetPeer(&pMP);
  779.     if (FAILED(hr)) {
  780.         return hr;
  781.     }
  782.     hr = pMP->get_StopTime(pllTime);
  783.     pMP->Release();
  784.     return hr;
  785. }
  786.  
  787.  
  788. STDMETHODIMP
  789. CPosPassThru::put_StopTime(REFTIME llTime)
  790. {
  791.     IMediaPosition* pMP;
  792.     HRESULT hr = GetPeer(&pMP);
  793.     if (FAILED(hr)) {
  794.         return hr;
  795.     }
  796.     hr = pMP->put_StopTime(llTime);
  797.     pMP->Release();
  798.     return hr;
  799. }
  800.  
  801.  
  802. STDMETHODIMP
  803. CPosPassThru::get_PrerollTime(REFTIME * pllTime)
  804. {
  805.     IMediaPosition* pMP;
  806.     HRESULT hr = GetPeer(&pMP);
  807.     if (FAILED(hr)) {
  808.         return hr;
  809.     }
  810.     hr = pMP->get_PrerollTime(pllTime);
  811.     pMP->Release();
  812.     return hr;
  813. }
  814.  
  815.  
  816. STDMETHODIMP
  817. CPosPassThru::put_PrerollTime(REFTIME llTime)
  818. {
  819.     IMediaPosition* pMP;
  820.     HRESULT hr = GetPeer(&pMP);
  821.     if (FAILED(hr)) {
  822.         return hr;
  823.     }
  824.     hr = pMP->put_PrerollTime(llTime);
  825.     pMP->Release();
  826.     return hr;
  827. }
  828.  
  829.  
  830. STDMETHODIMP
  831. CPosPassThru::get_Rate(double * pdRate)
  832. {
  833.     IMediaPosition* pMP;
  834.     HRESULT hr = GetPeer(&pMP);
  835.     if (FAILED(hr)) {
  836.         return hr;
  837.     }
  838.     hr = pMP->get_Rate(pdRate);
  839.     pMP->Release();
  840.     return hr;
  841. }
  842.  
  843.  
  844. STDMETHODIMP
  845. CPosPassThru::put_Rate(double dRate)
  846. {
  847.     if (0.0 == dRate) {
  848.         return E_INVALIDARG;
  849.     }
  850.  
  851.     IMediaPosition* pMP;
  852.     HRESULT hr = GetPeer(&pMP);
  853.     if (FAILED(hr)) {
  854.         return hr;
  855.     }
  856.     hr = pMP->put_Rate(dRate);
  857.     pMP->Release();
  858.     return hr;
  859. }
  860.  
  861.  
  862. STDMETHODIMP
  863. CPosPassThru::CanSeekForward(LONG *pCanSeekForward)
  864. {
  865.     IMediaPosition* pMP;
  866.     HRESULT hr = GetPeer(&pMP);
  867.     if (FAILED(hr)) {
  868.         return hr;
  869.     }
  870.     hr = pMP->CanSeekForward(pCanSeekForward);
  871.     pMP->Release();
  872.     return hr;
  873. }
  874.  
  875.  
  876. STDMETHODIMP
  877. CPosPassThru::CanSeekBackward(LONG *pCanSeekBackward)
  878. {
  879.     IMediaPosition* pMP;
  880.     HRESULT hr = GetPeer(&pMP);
  881.     if (FAILED(hr)) {
  882.         return hr;
  883.     }
  884.     hr = pMP->CanSeekBackward(pCanSeekBackward);
  885.     pMP->Release();
  886.     return hr;
  887. }
  888.  
  889.  
  890. // --- Implements the CRendererPosPassThru class ----------
  891.  
  892.  
  893. // Media times (eg current frame, field, sample etc) are passed through the
  894. // filtergraph in media samples. When a renderer gets a sample with media
  895. // times in it, it will call one of the RegisterMediaTime methods we expose
  896. // (one takes an IMediaSample, the other takes the media times direct). We
  897. // store the media times internally and return them in GetCurrentPosition.
  898.  
  899. CRendererPosPassThru::CRendererPosPassThru(TCHAR *pName,
  900.                                            LPUNKNOWN pUnk,
  901.                                            HRESULT *phr,
  902.                                            IPin *pPin) :
  903.     CPosPassThru(pName,pUnk,phr,pPin),
  904.     m_StartMedia(0),
  905.     m_EndMedia(0),
  906.     m_bReset(TRUE)
  907. {
  908. }
  909.  
  910.  
  911. // Sets the media times the object should report
  912.  
  913. HRESULT
  914. CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample)
  915. {
  916.     ASSERT(pMediaSample);
  917.     LONGLONG StartMedia;
  918.     LONGLONG EndMedia;
  919.  
  920.     CAutoLock cAutoLock(&m_PositionLock);
  921.  
  922.     // Get the media times from the sample
  923.  
  924.     HRESULT hr = pMediaSample->GetMediaTime(&StartMedia,&EndMedia);
  925.     if (hr == VFW_E_MEDIA_TIME_NOT_SET) {
  926.         return VFW_E_MEDIA_TIME_NOT_SET;
  927.     }
  928.  
  929.     m_StartMedia = StartMedia;
  930.     m_EndMedia = EndMedia;
  931.     m_bReset = FALSE;
  932.     return NOERROR;
  933. }
  934.  
  935.  
  936. // Sets the media times the object should report
  937.  
  938. HRESULT
  939. CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime)
  940. {
  941.     CAutoLock cAutoLock(&m_PositionLock);
  942.     m_StartMedia = StartTime;
  943.     m_EndMedia = EndTime;
  944.     m_bReset = FALSE;
  945.     return NOERROR;
  946. }
  947.  
  948.  
  949. // Return the current media times registered in the object
  950.  
  951. HRESULT
  952. CRendererPosPassThru::GetMediaTime(LONGLONG *pStartTime,LONGLONG *pEndTime)
  953. {
  954.     ASSERT(pStartTime);
  955.  
  956.     CAutoLock cAutoLock(&m_PositionLock);
  957.     if (m_bReset == TRUE) {
  958.         return E_FAIL;
  959.     }
  960.  
  961.     // We don't have to return the end time
  962.  
  963.     *pStartTime = m_StartMedia;
  964.     if (pEndTime) {
  965.         *pEndTime = m_EndMedia;
  966.     }
  967.     return NOERROR;
  968. }
  969.  
  970.  
  971. // Resets the media times we hold
  972.  
  973. HRESULT
  974. CRendererPosPassThru::ResetMediaTime()
  975. {
  976.     CAutoLock cAutoLock(&m_PositionLock);
  977.     m_StartMedia = 0;
  978.     m_EndMedia = 0;
  979.     m_bReset = TRUE;
  980.     return NOERROR;
  981. }
  982.  
  983. // Intended to be called by the owing filter during EOS processing so
  984. // that the media times can be adjusted to the stop time.  This ensures
  985. // that the GetCurrentPosition will actully get to the stop position.
  986. HRESULT
  987. CRendererPosPassThru::EOS()
  988. {
  989.     HRESULT hr;
  990.  
  991.     if ( m_bReset == TRUE ) hr = E_FAIL;
  992.     else
  993.     {
  994.         LONGLONG llStop;
  995.         if SUCCEEDED(hr=GetStopPosition(&llStop))
  996.         {
  997.             CAutoLock cAutoLock(&m_PositionLock);
  998.             m_StartMedia =
  999.             m_EndMedia   = llStop;
  1000.         }
  1001.     }
  1002.     return hr;
  1003. }
  1004. // --- Implements the CMultiPinPosPassThru class ----------
  1005.  
  1006.  
  1007. CMultiPinPosPassThru::CMultiPinPosPassThru(TCHAR *pName,
  1008.                                            LPUNKNOWN pUnk,
  1009.                                            HRESULT *phr) :
  1010.     CMediaPosition(pName,pUnk,phr),
  1011.     m_apMP(NULL)
  1012. {
  1013. }
  1014.  
  1015.  
  1016. HRESULT CMultiPinPosPassThru::SetPins(CBasePin **apPins,
  1017.                       CRefTime *apOffsets,
  1018.                       int iPinCount)
  1019. {
  1020.     int i;
  1021.  
  1022.     // Discard our current pointers
  1023.     ResetPins();
  1024.  
  1025.     // Reset our start/stop times
  1026.     m_rtStartTime = 0;
  1027.     m_rtStopTime = 0;
  1028.     m_rtPrerollTime = 0;
  1029.     m_dRate = 1.0;
  1030.  
  1031.     // Check that all pointers are valid
  1032.     if (!apPins) {
  1033.         DbgBreak("bad pointer");
  1034.         return E_POINTER;
  1035.     }
  1036.  
  1037.     // We need each pin to be connected
  1038.     for (i = 0; i < iPinCount; i++)
  1039.         if (apPins[i] == NULL)
  1040.             return E_POINTER;
  1041.  
  1042.     // Allocate an array of pointers to the pin's IMediaPosition interfaces.
  1043.     m_apMP = new IMediaPosition*[iPinCount];
  1044.  
  1045.     if (m_apMP == NULL) {
  1046.         return E_OUTOFMEMORY;
  1047.     }
  1048.  
  1049.     // Reset in case of trouble
  1050.     for (i = 0; i < iPinCount; i++) {
  1051.         m_apMP[i] = NULL;
  1052.     }
  1053.  
  1054.     // Get the IMediaPosition interface for each pin
  1055.     for (i = 0; i < iPinCount; i++) {
  1056.         IPin *pConnected;
  1057.  
  1058.         HRESULT hr = apPins[i]->ConnectedTo(&pConnected);
  1059.         if (FAILED(hr)) {
  1060.             ResetPins();
  1061.             return hr;
  1062.         }
  1063.  
  1064.         IMediaPosition * pMP;
  1065.         hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP);
  1066.         pConnected->Release();
  1067.  
  1068.         if (FAILED(hr)) {
  1069.             ResetPins();
  1070.             return hr;
  1071.         }
  1072.         m_apMP[i] = pMP;
  1073.     }
  1074.  
  1075.     // Finally set the pointer up if all went well
  1076.  
  1077.     m_iPinCount = iPinCount;
  1078.     m_apOffsets = apOffsets;
  1079.     get_Duration(&m_rtStopTime);
  1080.     return NOERROR;
  1081. }
  1082.  
  1083.  
  1084. HRESULT CMultiPinPosPassThru::ResetPins(void)
  1085. {
  1086.     // Must be called when a pin is connected
  1087.     if (m_apMP != NULL) {
  1088.         for (int i = 0; i < m_iPinCount; i++)
  1089.             m_apMP[i]->Release();
  1090.  
  1091.         delete [] m_apMP;
  1092.         m_apMP = NULL;
  1093.     }
  1094.     return NOERROR;
  1095. }
  1096.  
  1097.  
  1098. CMultiPinPosPassThru::~CMultiPinPosPassThru()
  1099. {
  1100.     ResetPins();
  1101. }
  1102.  
  1103.  
  1104. // --- IMediaPosition methods ---------
  1105.  
  1106.  
  1107. STDMETHODIMP CMultiPinPosPassThru::get_Duration(REFTIME * plength)
  1108. {
  1109.     CheckPointer(plength,E_POINTER)
  1110.     CheckPointer(m_apMP,E_NOTIMPL);
  1111.     ValidateReadWritePtr(plength,sizeof(REFTIME));
  1112.  
  1113.     // our duration is the minimum duration of all of our
  1114.     // input pins
  1115.  
  1116.     REFTIME rtDuration;
  1117.     REFTIME rt;
  1118.     HRESULT hr;
  1119.  
  1120.     // Initialise rtDuration with the duration of our first pin
  1121.  
  1122.     ASSERT(m_apMP[0] != NULL);
  1123.     hr = m_apMP[0]->get_Duration(&rtDuration);
  1124.  
  1125.     if (FAILED(hr)) {
  1126.         return hr;
  1127.     }
  1128.  
  1129.     if (m_apOffsets) {
  1130.     rtDuration += (REFTIME) COARefTime(m_apOffsets[0]);
  1131.     }
  1132.  
  1133.     // Compare the rtDuration with the duration of
  1134.     // every other input pin and keep the lowest
  1135.     for (int i = 1; i < m_iPinCount; i++) {
  1136.         ASSERT(m_apMP[i] != NULL);
  1137.  
  1138.         HRESULT hr = m_apMP[i]->get_Duration(&rt);
  1139.         if (FAILED(hr))
  1140.             return hr;
  1141.  
  1142.     if (m_apOffsets)
  1143.         rt += (REFTIME) COARefTime(m_apOffsets[i]);
  1144.  
  1145.         if (rt < rtDuration)
  1146.             rtDuration = rt;
  1147.     }
  1148.  
  1149.     *plength = rtDuration;
  1150.     return NOERROR;
  1151. }
  1152.  
  1153.  
  1154. STDMETHODIMP
  1155. CMultiPinPosPassThru::put_CurrentPosition(REFTIME llTime)
  1156. {
  1157.     CheckPointer(m_apMP,E_NOTIMPL);
  1158.     ASSERT(llTime <= m_rtStopTime);
  1159.  
  1160.     m_rtStartTime = llTime;
  1161.  
  1162.     // Inform everybody of our new start time
  1163.     for (int i = 0; i < m_iPinCount; i++) {
  1164.         ASSERT(m_apMP[i] != NULL);
  1165.  
  1166.     REFTIME rt = m_rtStartTime;
  1167.  
  1168.     // adjust for when this particular stream starts
  1169.     if (m_apOffsets) {
  1170.         if (rt < (REFTIME) COARefTime(m_apOffsets[i]))
  1171.         rt = 0;
  1172.         else
  1173.         rt -= (REFTIME) COARefTime(m_apOffsets[i]);
  1174.     }
  1175.  
  1176.         HRESULT hr = m_apMP[i]->put_CurrentPosition(rt);
  1177.         if (FAILED(hr)) {
  1178.             return hr;
  1179.         }
  1180.     }
  1181.     return NOERROR;
  1182. }
  1183.  
  1184.  
  1185. // Note this is not an IMediaPosition method
  1186. //  - this is just used by StartStreaming
  1187.  
  1188. STDMETHODIMP CMultiPinPosPassThru::get_StartTime(REFTIME * pllTime)
  1189. {
  1190.     CheckPointer(pllTime,E_POINTER)
  1191.     CheckPointer(m_apMP,E_NOTIMPL);
  1192.     ValidateReadWritePtr(pllTime,sizeof(REFTIME));
  1193.  
  1194.     // Start time is initialised to zero in SetPins
  1195.     *pllTime = m_rtStartTime;
  1196.     return NOERROR;
  1197. }
  1198.  
  1199.  
  1200. STDMETHODIMP
  1201. CMultiPinPosPassThru::get_StopTime(REFTIME * pllTime)
  1202. {
  1203.     CheckPointer(pllTime,E_POINTER)
  1204.     CheckPointer(m_apMP,E_NOTIMPL);
  1205.     ValidateReadWritePtr(pllTime,sizeof(REFTIME));
  1206.  
  1207.     // m_rtStopTime is initialised to get_Duration in SetPins
  1208.     *pllTime = m_rtStopTime;
  1209.     return NOERROR;
  1210. }
  1211.  
  1212.  
  1213. STDMETHODIMP
  1214. CMultiPinPosPassThru::put_StopTime(REFTIME llTime)
  1215. {
  1216.     CheckPointer(m_apMP,E_NOTIMPL);
  1217.     ASSERT(llTime >= m_rtStartTime);
  1218.  
  1219.     m_rtStopTime = llTime ;
  1220.  
  1221.     // Inform everybody of our new stop time
  1222.     for (int i = 0; i < m_iPinCount; i++) {
  1223.         ASSERT(m_apMP[i] != NULL);
  1224.  
  1225.     REFTIME rt = m_rtStopTime;
  1226.  
  1227.     // Adjust for when this particular stream starts
  1228.     if (m_apOffsets) {
  1229.         if (rt < (REFTIME) COARefTime(m_apOffsets[i]))
  1230.         rt = 0;
  1231.         else
  1232.         rt -= (REFTIME) COARefTime(m_apOffsets[i]);
  1233.     }
  1234.  
  1235.         HRESULT hr = m_apMP[i]->put_StopTime(rt);
  1236.  
  1237.         if (FAILED(hr))
  1238.             return hr;
  1239.     }
  1240.     return NOERROR;
  1241. }
  1242.  
  1243.  
  1244. STDMETHODIMP
  1245. CMultiPinPosPassThru::get_PrerollTime(REFTIME * pllTime)
  1246. {
  1247.     CheckPointer(pllTime,E_POINTER)
  1248.     CheckPointer(m_apMP,E_NOTIMPL);
  1249.     ValidateReadWritePtr(pllTime,sizeof(REFTIME));
  1250.  
  1251.     // Our preroll is the maximum of all our the prerolls
  1252.     // on the input pins
  1253.     REFTIME rt, rtPreroll = 0;
  1254.  
  1255.     for (int i = 1; i < m_iPinCount; i++) {
  1256.         ASSERT(m_apMP[i] != NULL);
  1257.  
  1258.         HRESULT hr = m_apMP[i]->get_PrerollTime(&rt);
  1259.         if (FAILED(hr))
  1260.             return hr;
  1261.  
  1262.         if (rt > rtPreroll)
  1263.             rtPreroll = rt;
  1264.     }
  1265.  
  1266.     *pllTime = rtPreroll;
  1267.     return NOERROR;
  1268. }
  1269.  
  1270.  
  1271. STDMETHODIMP
  1272. CMultiPinPosPassThru::put_PrerollTime(REFTIME llTime)
  1273. {
  1274.     CheckPointer(m_apMP,E_NOTIMPL);
  1275.  
  1276.     // Inform all of our input times of the new preroll
  1277.  
  1278.     for (int i = 0; i < m_iPinCount; i ++) {
  1279.         ASSERT(m_apMP[i] != NULL);
  1280.  
  1281.         HRESULT hr = m_apMP[i]->put_PrerollTime(llTime);
  1282.         if (FAILED(hr))
  1283.             return hr;
  1284.     }
  1285.     return NOERROR;
  1286. }
  1287.  
  1288.  
  1289. STDMETHODIMP
  1290. CMultiPinPosPassThru::get_Rate(double * pdRate)
  1291. {
  1292.     CheckPointer(pdRate,E_POINTER)
  1293.     CheckPointer(m_apMP,E_NOTIMPL);
  1294.     ValidateReadWritePtr(pdRate,sizeof(double));
  1295.  
  1296.     // m_dRate is initialised to 1.0 in SetPins
  1297.     *pdRate = m_dRate;
  1298.     return NOERROR;
  1299. }
  1300.  
  1301.  
  1302. STDMETHODIMP
  1303. CMultiPinPosPassThru::put_Rate(double dRate)
  1304. {
  1305.     CheckPointer(m_apMP,E_NOTIMPL);
  1306.  
  1307.     if (0.0 == dRate) {
  1308.     return E_INVALIDARG;
  1309.     }
  1310.  
  1311.     m_dRate = dRate;
  1312.  
  1313.     // Inform everybody of our new rate
  1314.     for (int i = 0; i < m_iPinCount; i++) {
  1315.         ASSERT(m_apMP[i] != NULL);
  1316.  
  1317.         HRESULT hr = m_apMP[i]->put_Rate(m_dRate);
  1318.  
  1319.         if (FAILED(hr))
  1320.             return hr;
  1321.     }
  1322.     return NOERROR;
  1323. }
  1324.  
  1325.  
  1326. STDMETHODIMP
  1327. CMultiPinPosPassThru::CanSeekForward(LONG *pCanSeekForward)
  1328. {
  1329.     CheckPointer(pCanSeekForward,E_POINTER);
  1330.     for (int i = 0; i < m_iPinCount; i++) {
  1331.         ASSERT(m_apMP[i] != NULL);
  1332.  
  1333.         HRESULT hr = m_apMP[i]->CanSeekForward(pCanSeekForward);
  1334.         if (FAILED(hr)) {
  1335.             return hr;
  1336.         }
  1337.  
  1338.         // anyone saying no stops us supporting it
  1339.  
  1340.         if (*pCanSeekForward == OAFALSE) {
  1341.             return NOERROR;
  1342.         }
  1343.     }
  1344.     return NOERROR;
  1345. }
  1346.  
  1347.  
  1348. STDMETHODIMP
  1349. CMultiPinPosPassThru::CanSeekBackward(LONG *pCanSeekBackward)
  1350. {
  1351.     CheckPointer(pCanSeekBackward,E_POINTER);
  1352.     for (int i = 0; i < m_iPinCount; i++) {
  1353.         ASSERT(m_apMP[i] != NULL);
  1354.  
  1355.         HRESULT hr = m_apMP[i]->CanSeekBackward(pCanSeekBackward);
  1356.         if (FAILED(hr)) {
  1357.             return hr;
  1358.         }
  1359.  
  1360.         // anyone saying no stops us supporting it
  1361.  
  1362.         if (*pCanSeekBackward == OAFALSE) {
  1363.             return NOERROR;
  1364.         }
  1365.     }
  1366.     return NOERROR;
  1367. }
  1368.  
  1369.  
  1370. // --- CSourcePosition implementation ----------
  1371.  
  1372.  
  1373. CSourcePosition::CSourcePosition(TCHAR * pName,
  1374.                                  LPUNKNOWN pUnk,
  1375.                                  HRESULT* phr,
  1376.                                  CCritSec * pLock) :
  1377.     CMediaPosition(pName, pUnk, phr),
  1378.     m_pLock(pLock),
  1379.     m_Start(CRefTime((LONGLONG)0))
  1380. {
  1381.     m_Stop = CRefTime((LONGLONG)_I64_MAX);
  1382.     m_Rate = 1.0;
  1383. }
  1384.  
  1385.  
  1386. STDMETHODIMP
  1387. CSourcePosition::get_Duration(REFTIME * plength)
  1388. {
  1389.     CheckPointer(plength,E_POINTER);
  1390.     ValidateReadWritePtr(plength,sizeof(REFTIME));
  1391.     CAutoLock lock(m_pLock);
  1392.  
  1393.     *plength = m_Duration;
  1394.     return S_OK;
  1395. }
  1396.  
  1397.  
  1398. STDMETHODIMP
  1399. CSourcePosition::put_CurrentPosition(REFTIME llTime)
  1400. {
  1401.     m_pLock->Lock();
  1402.     m_Start = llTime;
  1403.     m_pLock->Unlock();
  1404.  
  1405.     return ChangeStart();
  1406. }
  1407.  
  1408.  
  1409. STDMETHODIMP
  1410. CSourcePosition::get_StopTime(REFTIME * pllTime)
  1411. {
  1412.     CheckPointer(pllTime,E_POINTER);
  1413.     ValidateReadWritePtr(pllTime,sizeof(REFTIME));
  1414.     CAutoLock lock(m_pLock);
  1415.  
  1416.     *pllTime = m_Stop;
  1417.     return S_OK;
  1418. }
  1419.  
  1420.  
  1421. STDMETHODIMP
  1422. CSourcePosition::put_StopTime(REFTIME llTime)
  1423. {
  1424.     m_pLock->Lock();
  1425.     m_Stop = llTime;
  1426.     m_pLock->Unlock();
  1427.  
  1428.     return ChangeStop();
  1429. }
  1430.  
  1431.  
  1432. STDMETHODIMP
  1433. CSourcePosition::get_PrerollTime(REFTIME * pllTime)
  1434. {
  1435.     CheckPointer(pllTime,E_POINTER);
  1436.     ValidateReadWritePtr(pllTime,sizeof(REFTIME));
  1437.     return E_NOTIMPL;
  1438. }
  1439.  
  1440.  
  1441. STDMETHODIMP
  1442. CSourcePosition::put_PrerollTime(REFTIME llTime)
  1443. {
  1444.     return E_NOTIMPL;
  1445. }
  1446.  
  1447.  
  1448. STDMETHODIMP
  1449. CSourcePosition::get_Rate(double * pdRate)
  1450. {
  1451.     CheckPointer(pdRate,E_POINTER);
  1452.     ValidateReadWritePtr(pdRate,sizeof(double));
  1453.     CAutoLock lock(m_pLock);
  1454.  
  1455.     *pdRate = m_Rate;
  1456.     return S_OK;
  1457. }
  1458.  
  1459.  
  1460. STDMETHODIMP
  1461. CSourcePosition::put_Rate(double dRate)
  1462. {
  1463.     m_pLock->Lock();
  1464.     m_Rate = dRate;
  1465.     m_pLock->Unlock();
  1466.  
  1467.     return ChangeRate();
  1468. }
  1469.  
  1470.  
  1471. // By default we can seek forwards
  1472.  
  1473. STDMETHODIMP
  1474. CSourcePosition::CanSeekForward(LONG *pCanSeekForward)
  1475. {
  1476.     CheckPointer(pCanSeekForward,E_POINTER);
  1477.     *pCanSeekForward = OATRUE;
  1478.     return S_OK;
  1479. }
  1480.  
  1481.  
  1482. // By default we can seek backwards
  1483.  
  1484. STDMETHODIMP
  1485. CSourcePosition::CanSeekBackward(LONG *pCanSeekBackward)
  1486. {
  1487.     CheckPointer(pCanSeekBackward,E_POINTER);
  1488.     *pCanSeekBackward = OATRUE;
  1489.     return S_OK;
  1490. }
  1491.  
  1492.  
  1493. // --- Implementation of CBasicAudio class ----------
  1494.  
  1495.  
  1496. CBasicAudio::CBasicAudio(TCHAR * pName,
  1497.                          LPUNKNOWN punk,
  1498.                          HRESULT *phr) :
  1499.     CUnknown(pName, punk, phr)
  1500. {
  1501. }
  1502.  
  1503.  
  1504. CBasicAudio::~CBasicAudio()
  1505. {
  1506. }
  1507.  
  1508.  
  1509. // overriden to publicise our interfaces
  1510.  
  1511. STDMETHODIMP
  1512. CBasicAudio::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  1513. {
  1514.     CheckPointer(ppv,E_POINTER);
  1515.     ValidateReadWritePtr(ppv,sizeof(PVOID));
  1516.     if (riid == IID_IBasicAudio) {
  1517.         return GetInterface( (IBasicAudio *) this, ppv);
  1518.     } else {
  1519.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  1520.     }
  1521. }
  1522.  
  1523.  
  1524. STDMETHODIMP
  1525. CBasicAudio::GetTypeInfoCount(UINT * pctinfo)
  1526. {
  1527.     return m_basedisp.GetTypeInfoCount(pctinfo);
  1528. }
  1529.  
  1530.  
  1531. STDMETHODIMP
  1532. CBasicAudio::GetTypeInfo(
  1533.   UINT itinfo,
  1534.   LCID lcid,
  1535.   ITypeInfo ** pptinfo)
  1536. {
  1537.     return m_basedisp.GetTypeInfo(
  1538.                 IID_IBasicAudio,
  1539.                 itinfo,
  1540.                 lcid,
  1541.                 pptinfo);
  1542. }
  1543.  
  1544.  
  1545. STDMETHODIMP
  1546. CBasicAudio::GetIDsOfNames(
  1547.   REFIID riid,
  1548.   OLECHAR  ** rgszNames,
  1549.   UINT cNames,
  1550.   LCID lcid,
  1551.   DISPID * rgdispid)
  1552. {
  1553.     return m_basedisp.GetIDsOfNames(
  1554.                         IID_IBasicAudio,
  1555.                         rgszNames,
  1556.                         cNames,
  1557.                         lcid,
  1558.                         rgdispid);
  1559. }
  1560.  
  1561.  
  1562. STDMETHODIMP
  1563. CBasicAudio::Invoke(
  1564.   DISPID dispidMember,
  1565.   REFIID riid,
  1566.   LCID lcid,
  1567.   WORD wFlags,
  1568.   DISPPARAMS * pdispparams,
  1569.   VARIANT * pvarResult,
  1570.   EXCEPINFO * pexcepinfo,
  1571.   UINT * puArgErr)
  1572. {
  1573.     // this parameter is a dead leftover from an earlier interface
  1574.     if (IID_NULL != riid) {
  1575.         return DISP_E_UNKNOWNINTERFACE;
  1576.     }
  1577.  
  1578.     ITypeInfo * pti;
  1579.     HRESULT hr = GetTypeInfo(0, lcid, &pti);
  1580.  
  1581.     if (FAILED(hr)) {
  1582.         return hr;
  1583.     }
  1584.  
  1585.     hr = pti->Invoke(
  1586.             (IBasicAudio *)this,
  1587.             dispidMember,
  1588.             wFlags,
  1589.             pdispparams,
  1590.             pvarResult,
  1591.             pexcepinfo,
  1592.             puArgErr);
  1593.  
  1594.     pti->Release();
  1595.     return hr;
  1596. }
  1597.  
  1598.  
  1599. // --- IVideoWindow implementation ----------
  1600.  
  1601. CBaseVideoWindow::CBaseVideoWindow(TCHAR * pName,
  1602.                                    LPUNKNOWN punk,
  1603.                                    HRESULT *phr) :
  1604.     CUnknown(pName, punk, phr)
  1605. {
  1606.     ASSERT(phr);
  1607. }
  1608.  
  1609.  
  1610. CBaseVideoWindow::~CBaseVideoWindow()
  1611. {
  1612. }
  1613.  
  1614.  
  1615. // overriden to publicise our interfaces
  1616.  
  1617. STDMETHODIMP
  1618. CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  1619. {
  1620.     CheckPointer(ppv,E_POINTER);
  1621.     ValidateReadWritePtr(ppv,sizeof(PVOID));
  1622.     if (riid == IID_IVideoWindow) {
  1623.         return GetInterface( (IVideoWindow *) this, ppv);
  1624.     } else {
  1625.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  1626.     }
  1627. }
  1628.  
  1629.  
  1630. STDMETHODIMP
  1631. CBaseVideoWindow::GetTypeInfoCount(UINT * pctinfo)
  1632. {
  1633.     return m_basedisp.GetTypeInfoCount(pctinfo);
  1634. }
  1635.  
  1636.  
  1637. STDMETHODIMP
  1638. CBaseVideoWindow::GetTypeInfo(
  1639.   UINT itinfo,
  1640.   LCID lcid,
  1641.   ITypeInfo ** pptinfo)
  1642. {
  1643.     return m_basedisp.GetTypeInfo(
  1644.                 IID_IVideoWindow,
  1645.                 itinfo,
  1646.                 lcid,
  1647.                 pptinfo);
  1648. }
  1649.  
  1650.  
  1651. STDMETHODIMP
  1652. CBaseVideoWindow::GetIDsOfNames(
  1653.   REFIID riid,
  1654.   OLECHAR  ** rgszNames,
  1655.   UINT cNames,
  1656.   LCID lcid,
  1657.   DISPID * rgdispid)
  1658. {
  1659.     return m_basedisp.GetIDsOfNames(
  1660.                         IID_IVideoWindow,
  1661.                         rgszNames,
  1662.                         cNames,
  1663.                         lcid,
  1664.                         rgdispid);
  1665. }
  1666.  
  1667.  
  1668. STDMETHODIMP
  1669. CBaseVideoWindow::Invoke(
  1670.   DISPID dispidMember,
  1671.   REFIID riid,
  1672.   LCID lcid,
  1673.   WORD wFlags,
  1674.   DISPPARAMS * pdispparams,
  1675.   VARIANT * pvarResult,
  1676.   EXCEPINFO * pexcepinfo,
  1677.   UINT * puArgErr)
  1678. {
  1679.     // this parameter is a dead leftover from an earlier interface
  1680.     if (IID_NULL != riid) {
  1681.         return DISP_E_UNKNOWNINTERFACE;
  1682.     }
  1683.  
  1684.     ITypeInfo * pti;
  1685.     HRESULT hr = GetTypeInfo(0, lcid, &pti);
  1686.  
  1687.     if (FAILED(hr)) {
  1688.         return hr;
  1689.     }
  1690.  
  1691.     hr = pti->Invoke(
  1692.             (IVideoWindow *)this,
  1693.             dispidMember,
  1694.             wFlags,
  1695.             pdispparams,
  1696.             pvarResult,
  1697.             pexcepinfo,
  1698.             puArgErr);
  1699.  
  1700.     pti->Release();
  1701.     return hr;
  1702. }
  1703.  
  1704.  
  1705. // --- IBasicVideo implementation ----------
  1706.  
  1707.  
  1708. CBaseBasicVideo::CBaseBasicVideo(TCHAR * pName,
  1709.                                  LPUNKNOWN punk,
  1710.                                  HRESULT *phr) :
  1711.     CUnknown(pName, punk, phr)
  1712. {
  1713.     ASSERT(phr);
  1714. }
  1715.  
  1716.  
  1717. CBaseBasicVideo::~CBaseBasicVideo()
  1718. {
  1719. }
  1720.  
  1721.  
  1722. // overriden to publicise our interfaces
  1723.  
  1724. STDMETHODIMP
  1725. CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  1726. {
  1727.     CheckPointer(ppv,E_POINTER);
  1728.     ValidateReadWritePtr(ppv,sizeof(PVOID));
  1729.     if (riid == IID_IBasicVideo) {
  1730.         return GetInterface( (IBasicVideo *) this, ppv);
  1731.     } else {
  1732.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  1733.     }
  1734. }
  1735.  
  1736.  
  1737. STDMETHODIMP
  1738. CBaseBasicVideo::GetTypeInfoCount(UINT * pctinfo)
  1739. {
  1740.     return m_basedisp.GetTypeInfoCount(pctinfo);
  1741. }
  1742.  
  1743.  
  1744. STDMETHODIMP
  1745. CBaseBasicVideo::GetTypeInfo(
  1746.   UINT itinfo,
  1747.   LCID lcid,
  1748.   ITypeInfo ** pptinfo)
  1749. {
  1750.     return m_basedisp.GetTypeInfo(
  1751.                 IID_IBasicVideo,
  1752.                 itinfo,
  1753.                 lcid,
  1754.                 pptinfo);
  1755. }
  1756.  
  1757.  
  1758. STDMETHODIMP
  1759. CBaseBasicVideo::GetIDsOfNames(
  1760.   REFIID riid,
  1761.   OLECHAR  ** rgszNames,
  1762.   UINT cNames,
  1763.   LCID lcid,
  1764.   DISPID * rgdispid)
  1765. {
  1766.     return m_basedisp.GetIDsOfNames(
  1767.                         IID_IBasicVideo,
  1768.                         rgszNames,
  1769.                         cNames,
  1770.                         lcid,
  1771.                         rgdispid);
  1772. }
  1773.  
  1774.  
  1775. STDMETHODIMP
  1776. CBaseBasicVideo::Invoke(
  1777.   DISPID dispidMember,
  1778.   REFIID riid,
  1779.   LCID lcid,
  1780.   WORD wFlags,
  1781.   DISPPARAMS * pdispparams,
  1782.   VARIANT * pvarResult,
  1783.   EXCEPINFO * pexcepinfo,
  1784.   UINT * puArgErr)
  1785. {
  1786.     // this parameter is a dead leftover from an earlier interface
  1787.     if (IID_NULL != riid) {
  1788.         return DISP_E_UNKNOWNINTERFACE;
  1789.     }
  1790.  
  1791.     ITypeInfo * pti;
  1792.     HRESULT hr = GetTypeInfo(0, lcid, &pti);
  1793.  
  1794.     if (FAILED(hr)) {
  1795.         return hr;
  1796.     }
  1797.  
  1798.     hr = pti->Invoke(
  1799.             (IBasicVideo *)this,
  1800.             dispidMember,
  1801.             wFlags,
  1802.             pdispparams,
  1803.             pvarResult,
  1804.             pexcepinfo,
  1805.             puArgErr);
  1806.  
  1807.     pti->Release();
  1808.     return hr;
  1809. }
  1810.  
  1811.  
  1812. // --- Implementation of Deferred Commands ----------
  1813.  
  1814.  
  1815. CDispParams::CDispParams(UINT nArgs, VARIANT* pArgs)
  1816. {
  1817.    cNamedArgs = 0;
  1818.    rgdispidNamedArgs = NULL;
  1819.    cArgs = nArgs;
  1820.  
  1821.     if (cArgs) {
  1822.         rgvarg = new VARIANT[cArgs];
  1823.  
  1824.         for (UINT i = 0; i < cArgs; i++) {
  1825.  
  1826.             VARIANT * pDest = &rgvarg[i];
  1827.             VARIANT * pSrc = &pArgs[i];
  1828.  
  1829.             pDest->vt = pSrc->vt;
  1830.             switch(pDest->vt) {
  1831.  
  1832.             case VT_I4:
  1833.                 pDest->lVal = pSrc->lVal;
  1834.                 break;
  1835.  
  1836.             case VT_UI1:
  1837.                 pDest->bVal = pSrc->bVal;
  1838.                 break;
  1839.  
  1840.             case VT_I2:
  1841.                 pDest->iVal = pSrc->iVal;
  1842.                 break;
  1843.  
  1844.             case VT_R4:
  1845.                 pDest->fltVal = pSrc->fltVal;
  1846.                 break;
  1847.  
  1848.             case VT_R8:
  1849.                 pDest->dblVal = pSrc->dblVal;
  1850.                 break;
  1851.  
  1852.             case VT_BOOL:
  1853.                 pDest->bool = pSrc->bool;
  1854.                 break;
  1855.  
  1856.             case VT_ERROR:
  1857.                 pDest->scode = pSrc->scode;
  1858.                 break;
  1859.  
  1860.             case VT_CY:
  1861.                 pDest->cyVal = pSrc->cyVal;
  1862.                 break;
  1863.  
  1864.             case VT_DATE:
  1865.                 pDest->date = pSrc->date;
  1866.                 break;
  1867.  
  1868.             case VT_BSTR:
  1869.                 if (pSrc->bstrVal == NULL) {
  1870.                     pDest->bstrVal = NULL;
  1871.                 } else {
  1872.  
  1873.                     // a BSTR is a WORD followed by a UNICODE string.
  1874.                     // the pointer points just after the WORD
  1875.  
  1876.                     WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR)));
  1877.                     OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))];
  1878.                     WORD *pui = (WORD*)pch;
  1879.                     *pui = len;
  1880.                     pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR));
  1881.                     CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR));
  1882.                 }
  1883.                 pDest->bstrVal = pSrc->bstrVal;
  1884.                 break;
  1885.  
  1886.             case VT_UNKNOWN:
  1887.                 pDest->punkVal = pSrc->punkVal;
  1888.                 pDest->punkVal->AddRef();
  1889.                 break;
  1890.  
  1891.             case VT_DISPATCH:
  1892.                 pDest->pdispVal = pSrc->pdispVal;
  1893.                 pDest->pdispVal->AddRef();
  1894.                 break;
  1895.  
  1896.             default:
  1897.                 // a type we haven't got round to adding yet!
  1898.                 ASSERT(0);
  1899.                 break;
  1900.             }
  1901.         }
  1902.  
  1903.     } else {
  1904.         rgvarg = NULL;
  1905.     }
  1906.  
  1907. }
  1908.  
  1909.  
  1910. CDispParams::~CDispParams()
  1911. {
  1912.     for (UINT i = 0; i < cArgs; i++) {
  1913.         switch(rgvarg[i].vt) {
  1914.         case VT_BSTR:
  1915.             if (rgvarg[i].bstrVal != NULL) {
  1916.                 OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR));
  1917.                 delete pch;
  1918.             }
  1919.             break;
  1920.  
  1921.         case VT_UNKNOWN:
  1922.             rgvarg[i].punkVal->Release();
  1923.             break;
  1924.  
  1925.         case VT_DISPATCH:
  1926.             rgvarg[i].pdispVal->Release();
  1927.             break;
  1928.         }
  1929.     }
  1930.     delete[] rgvarg;
  1931. }
  1932.  
  1933.  
  1934. // lifetime is controlled by refcounts (see defer.h)
  1935.  
  1936. CDeferredCommand::CDeferredCommand(
  1937.     CCmdQueue * pQ,
  1938.     LPUNKNOWN   pUnk,
  1939.     HRESULT *   phr,
  1940.     LPUNKNOWN   pUnkExecutor,
  1941.     REFTIME     time,
  1942.     GUID*       iid,
  1943.     long        dispidMethod,
  1944.     short       wFlags,
  1945.     long        nArgs,
  1946.     VARIANT*    pDispParams,
  1947.     VARIANT*    pvarResult,
  1948.     short*      puArgErr,
  1949.     BOOL        bStream
  1950.     ) :
  1951.         CUnknown(NAME("DeferredCommand"), pUnk, phr),
  1952.         m_pQueue(pQ),
  1953.         m_pUnk(pUnkExecutor),
  1954.         m_iid(iid),
  1955.         m_dispidMethod(dispidMethod),
  1956.         m_wFlags(wFlags),
  1957.         m_DispParams(nArgs, pDispParams),
  1958.         m_pvarResult(pvarResult),
  1959.         m_bStream(bStream),
  1960.         m_hrResult(E_ABORT)
  1961.  
  1962. {
  1963.     // convert REFTIME to REFERENCE_TIME
  1964.     COARefTime convertor(time);
  1965.     m_time = convertor;
  1966.  
  1967.     // no check of time validity - it's ok to queue a command that's
  1968.     // already late
  1969.  
  1970.     // check iid is supportable on pUnk by QueryInterface for it
  1971.     IUnknown * pInterface;
  1972.     HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface);
  1973.     if (FAILED(hr)) {
  1974.         *phr = hr;
  1975.         return;
  1976.     }
  1977.     pInterface->Release();
  1978.  
  1979.  
  1980.     // !!! check dispidMethod and param/return types using typelib
  1981.     ITypeInfo *pti;
  1982.     hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti);
  1983.     if (FAILED(hr)) {
  1984.         *phr = hr;
  1985.         return;
  1986.     }
  1987.     // !!! some sort of ITypeInfo validity check here
  1988.     pti->Release();
  1989.  
  1990.  
  1991.  
  1992.     // all checks ok - add to queue
  1993.     hr = pQ->Insert(this);
  1994.     if (FAILED(hr)) {
  1995.         *phr = hr;
  1996.     }
  1997. }
  1998.  
  1999.  
  2000. // refcounts are held by caller of InvokeAt... and by list. So if
  2001. // we get here, we can't be on the list
  2002.  
  2003. CDeferredCommand::~CDeferredCommand()
  2004. {
  2005.     // this assert is invalid since if the queue is deleted while we are
  2006.     // still on the queue, we will have been removed by the queue and this
  2007.     // m_pQueue will not have been modified.
  2008.     // ASSERT(m_pQueue == NULL);
  2009.  
  2010.     // we don't hold a ref count on pUnk, which is the object that should
  2011.     // execute the command.
  2012.     // This is because there would otherwise be a circular refcount problem
  2013.     // since pUnk probably owns the CmdQueue object that has a refcount
  2014.     // on us.
  2015.     // The lifetime of pUnk is guaranteed by it being part of, or lifetime
  2016.     // controlled by, our parent object. As long as we are on the list, pUnk
  2017.     // must be valid. Once we are off the list, we do not use pUnk.
  2018.  
  2019. }
  2020.  
  2021.  
  2022. // overriden to publicise our interfaces
  2023.  
  2024. STDMETHODIMP
  2025. CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  2026. {
  2027.     CheckPointer(ppv,E_POINTER);
  2028.     ValidateReadWritePtr(ppv,sizeof(PVOID));
  2029.     if (riid == IID_IDeferredCommand) {
  2030.         return GetInterface( (IDeferredCommand *) this, ppv);
  2031.     } else {
  2032.         return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  2033.     }
  2034. }
  2035.  
  2036.  
  2037. // remove from q. this will reduce the refcount by one (since the q
  2038. // holds a count) but can't make us go away since he must have a
  2039. // refcount in order to call this method.
  2040.  
  2041. STDMETHODIMP
  2042. CDeferredCommand::Cancel()
  2043. {
  2044.     if (m_pQueue == NULL) {
  2045.         return VFW_E_ALREADY_CANCELLED;
  2046.     }
  2047.  
  2048.     HRESULT hr = m_pQueue->Remove(this);
  2049.     if (FAILED(hr)) {
  2050.         return hr;
  2051.     }
  2052.  
  2053.     m_pQueue = NULL;
  2054.     return S_OK;
  2055. }
  2056.  
  2057.  
  2058. STDMETHODIMP
  2059. CDeferredCommand::Confidence(LONG* pConfidence)
  2060. {
  2061.     return E_NOTIMPL;
  2062. }
  2063.  
  2064.  
  2065. STDMETHODIMP
  2066. CDeferredCommand::GetHResult(HRESULT * phrResult)
  2067. {
  2068.     CheckPointer(phrResult,E_POINTER);
  2069.     ValidateReadWritePtr(phrResult,sizeof(HRESULT));
  2070.  
  2071.     if (m_pQueue != NULL) {
  2072.         return E_ABORT;
  2073.     }
  2074.     *phrResult = m_hrResult;
  2075.     return S_OK;
  2076. }
  2077.  
  2078.  
  2079. // set the time to be a new time (checking that it is valid) and
  2080. // then requeue
  2081.  
  2082. STDMETHODIMP
  2083. CDeferredCommand::Postpone(REFTIME newtime)
  2084. {
  2085.  
  2086.     // check that this time is not past
  2087.     // convert REFTIME to REFERENCE_TIME
  2088.     COARefTime convertor(newtime);
  2089.  
  2090.     // check that the time has not passed
  2091.     if (m_pQueue->CheckTime(convertor, IsStreamTime())) {
  2092.         return VFW_E_TIME_ALREADY_PASSED;
  2093.     }
  2094.  
  2095.     // extract from list
  2096.     HRESULT hr = m_pQueue->Remove(this);
  2097.     if (FAILED(hr)) {
  2098.         return hr;
  2099.     }
  2100.  
  2101.     // change time
  2102.     m_time = convertor;
  2103.  
  2104.     // requeue
  2105.     hr = m_pQueue->Insert(this);
  2106.  
  2107.     return hr;
  2108. }
  2109.  
  2110.  
  2111. HRESULT
  2112. CDeferredCommand::Invoke()
  2113. {
  2114.     // check that we are still outstanding
  2115.     if (m_pQueue == NULL) {
  2116.         return VFW_E_ALREADY_CANCELLED;
  2117.     }
  2118.  
  2119.     // get the type info
  2120.     ITypeInfo* pti;
  2121.     HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti);
  2122.     if (FAILED(hr)) {
  2123.         return hr;
  2124.     }
  2125.  
  2126.     // qi for the expected interface and then invoke it. Note that we have to
  2127.     // treat the returned interface as IUnknown since we don't know its type.
  2128.     IUnknown* pInterface;
  2129.  
  2130.     hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface);
  2131.     if (FAILED(hr)) {
  2132.         pti->Release();
  2133.         return hr;
  2134.     }
  2135.  
  2136.     EXCEPINFO expinfo;
  2137.     UINT uArgErr;
  2138.     m_hrResult = pti->Invoke(
  2139.         pInterface,
  2140.         GetMethod(),
  2141.         GetFlags(),
  2142.         GetParams(),
  2143.         GetResult(),
  2144.         &expinfo,
  2145.         &uArgErr);
  2146.  
  2147.     // release the interface we QI'd for
  2148.     pInterface->Release();
  2149.     pti->Release();
  2150.  
  2151.  
  2152.     // remove from list whether or not successful
  2153.     // or we loop indefinitely
  2154.     hr = m_pQueue->Remove(this);
  2155.     m_pQueue = NULL;
  2156.     return hr;
  2157. }
  2158.  
  2159.  
  2160.  
  2161. // --- CCmdQueue methods ----------
  2162.  
  2163.  
  2164. CCmdQueue::CCmdQueue() :
  2165.     m_listPresentation(NAME("Presentation time command list"), 0, FALSE, FALSE),
  2166.     m_listStream(NAME("Stream time command list"), 0, FALSE, FALSE),
  2167.     m_evDue(TRUE),    // manual reset
  2168.     m_dwAdvise(0),
  2169.     m_pClock(NULL),
  2170.     m_bRunning(FALSE)
  2171. {
  2172. }
  2173.  
  2174.  
  2175. CCmdQueue::~CCmdQueue()
  2176. {
  2177.     // empty all our lists
  2178.  
  2179.     // we hold a refcount on each, so traverse and Release each
  2180.     // entry then RemoveAll to empty the list
  2181.     POSITION pos = m_listPresentation.GetHeadPosition();
  2182.  
  2183.     while(pos) {
  2184.         CDeferredCommand* pCmd = m_listPresentation.GetNext(pos);
  2185.         pCmd->Release();
  2186.     }
  2187.     m_listPresentation.RemoveAll();
  2188.  
  2189.     pos = m_listStream.GetHeadPosition();
  2190.  
  2191.     while(pos) {
  2192.         CDeferredCommand* pCmd = m_listStream.GetNext(pos);
  2193.         pCmd->Release();
  2194.     }
  2195.     m_listStream.RemoveAll();
  2196.  
  2197.     if (m_pClock) {
  2198.         if (m_dwAdvise) {
  2199.             m_pClock->Unadvise(m_dwAdvise);
  2200.             m_dwAdvise = 0;
  2201.         }
  2202.         m_pClock->Release();
  2203.     }
  2204. }
  2205.  
  2206.  
  2207. // returns a new CDeferredCommand object that will be initialised with
  2208. // the parameters and will be added to the queue during construction.
  2209. // returns S_OK if successfully created otherwise an error and
  2210. // no object has been queued.
  2211.  
  2212. HRESULT
  2213. CCmdQueue::New(
  2214.     CDeferredCommand **ppCmd,
  2215.     LPUNKNOWN   pUnk,           // this object will execute command
  2216.     REFTIME     time,
  2217.     GUID*       iid,
  2218.     long        dispidMethod,
  2219.     short       wFlags,
  2220.     long        cArgs,
  2221.     VARIANT*    pDispParams,
  2222.     VARIANT*    pvarResult,
  2223.     short*      puArgErr,
  2224.     BOOL        bStream
  2225. )
  2226. {
  2227.     CAutoLock lock(&m_Lock);
  2228.  
  2229.     HRESULT hr = S_OK;
  2230.     *ppCmd = NULL;
  2231.  
  2232.     CDeferredCommand* pCmd;
  2233.     pCmd = new CDeferredCommand(
  2234.                     this,
  2235.                     NULL,           // not aggregated
  2236.                     &hr,
  2237.                     pUnk,           // this guy will execute
  2238.                     time,
  2239.                     iid,
  2240.                     dispidMethod,
  2241.                     wFlags,
  2242.                     cArgs,
  2243.                     pDispParams,
  2244.                     pvarResult,
  2245.                     puArgErr,
  2246.                     bStream);
  2247.  
  2248.     if (pCmd == NULL) {
  2249.         hr = E_OUTOFMEMORY;
  2250.     } else {
  2251.     *ppCmd = pCmd;
  2252.     }
  2253.     return hr;
  2254. }
  2255.  
  2256.  
  2257. HRESULT
  2258. CCmdQueue::Insert(CDeferredCommand* pCmd)
  2259. {
  2260.     CAutoLock lock(&m_Lock);
  2261.  
  2262.     // addref the item
  2263.     pCmd->AddRef();
  2264.  
  2265.     CGenericList<CDeferredCommand> * pList;
  2266.     if (pCmd->IsStreamTime()) {
  2267.         pList = &m_listStream;
  2268.     } else {
  2269.         pList = &m_listPresentation;
  2270.     }
  2271.     POSITION pos = pList->GetHeadPosition();
  2272.  
  2273.     // seek past all items that are before us
  2274.     while (pos &&
  2275.         (pList->Get(pos)->GetTime() <= pCmd->GetTime())) {
  2276.  
  2277.         pList->GetNext(pos);
  2278.     }
  2279.  
  2280.     // now at end of list or in front of items that come later
  2281.     if (!pos) {
  2282.         pList->AddTail(pCmd);
  2283.     } else {
  2284.         pList->AddBefore(pos, pCmd);
  2285.     }
  2286.  
  2287.     SetTimeAdvise();
  2288.     return S_OK;
  2289. }
  2290.  
  2291.  
  2292. HRESULT
  2293. CCmdQueue::Remove(CDeferredCommand* pCmd)
  2294. {
  2295.     CAutoLock lock(&m_Lock);
  2296.     HRESULT hr = S_OK;
  2297.  
  2298.     CGenericList<CDeferredCommand> * pList;
  2299.     if (pCmd->IsStreamTime()) {
  2300.         pList = &m_listStream;
  2301.     } else {
  2302.         pList = &m_listPresentation;
  2303.     }
  2304.     POSITION pos = pList->GetHeadPosition();
  2305.  
  2306.     // traverse the list
  2307.     while (pos && (pList->Get(pos) != pCmd)) {
  2308.         pList->GetNext(pos);
  2309.     }
  2310.  
  2311.     // did we drop off the end?
  2312.     if (!pos) {
  2313.         hr = VFW_E_NOT_FOUND;
  2314.     } else {
  2315.  
  2316.         // found it - now take off list
  2317.         pList->Remove(pos);
  2318.  
  2319.         // Insert did an AddRef, so release it
  2320.         pCmd->Release();
  2321.  
  2322.         // check that timer request is still for earliest time
  2323.         SetTimeAdvise();
  2324.     }
  2325.     return hr;
  2326. }
  2327.  
  2328.  
  2329. // set the clock used for timing
  2330.  
  2331. HRESULT
  2332. CCmdQueue::SetSyncSource(IReferenceClock* pClock)
  2333. {
  2334.     CAutoLock lock(&m_Lock);
  2335.  
  2336.     // addref the new clock first in case they are the same
  2337.     if (pClock) {
  2338.         pClock->AddRef();
  2339.     }
  2340.  
  2341.     // kill any advise on the old clock
  2342.     if (m_pClock) {
  2343.         if (m_dwAdvise) {
  2344.             m_pClock->Unadvise(m_dwAdvise);
  2345.             m_dwAdvise = 0;
  2346.         }
  2347.         m_pClock->Release();
  2348.     }
  2349.     m_pClock = pClock;
  2350.  
  2351.     // set up a new advise
  2352.     SetTimeAdvise();
  2353.     return S_OK;
  2354. }
  2355.  
  2356.  
  2357. // set up a timer event with the reference clock
  2358.  
  2359. void
  2360. CCmdQueue::SetTimeAdvise(void)
  2361. {
  2362.     // make sure we have a clock to use
  2363.     if (!m_pClock) {
  2364.         return;
  2365.     }
  2366.  
  2367.     // reset the event whenever we are requesting a new signal
  2368.     m_evDue.Reset();
  2369.  
  2370.     // time 0 is earliest
  2371.     CRefTime current;
  2372.  
  2373.     // find the earliest presentation time
  2374.     if (m_listPresentation.GetCount() > 0) {
  2375.  
  2376.         POSITION pos = m_listPresentation.GetHeadPosition();
  2377.         current = m_listPresentation.Get(pos)->GetTime();
  2378.     }
  2379.  
  2380.     // if we're running, check the stream times too
  2381.     if (m_bRunning) {
  2382.  
  2383.         CRefTime t;
  2384.  
  2385.         if (m_listStream.GetCount() > 0) {
  2386.  
  2387.             POSITION pos = m_listStream.GetHeadPosition();
  2388.             t = m_listStream.Get(pos)->GetTime();
  2389.  
  2390.             // add on stream time offset to get presentation time
  2391.             t += m_StreamTimeOffset;
  2392.  
  2393.             // is this earlier?
  2394.             if ((current == TimeZero) || (t < current)) {
  2395.                 current = t;
  2396.             }
  2397.         }
  2398.     }
  2399.  
  2400.     // need to change?
  2401.     if ((current > TimeZero) && (current != m_tCurrentAdvise)) {
  2402.     if (m_dwAdvise) {
  2403.         m_pClock->Unadvise(m_dwAdvise);
  2404.         // reset the event whenever we are requesting a new signal
  2405.         m_evDue.Reset();
  2406.     }
  2407.  
  2408.         // ask for time advice - the first two params are either
  2409.         // stream time offset and stream time or
  2410.         // presentation time and 0. we always use the latter
  2411.         HRESULT hr = m_pClock->AdviseTime(
  2412.                     (REFERENCE_TIME)current,
  2413.                     TimeZero,
  2414.                     (HEVENT) HANDLE(m_evDue),
  2415.                     &m_dwAdvise);
  2416.  
  2417.         ASSERT(SUCCEEDED(hr));
  2418.         m_tCurrentAdvise = current;
  2419.     }
  2420. }
  2421.  
  2422.  
  2423. // switch to run mode. Streamtime to Presentation time mapping known.
  2424.  
  2425. HRESULT
  2426. CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset)
  2427. {
  2428.     CAutoLock lock(&m_Lock);
  2429.  
  2430.     m_StreamTimeOffset = tStreamTimeOffset;
  2431.     m_bRunning = TRUE;
  2432.  
  2433.     // ensure advise is accurate
  2434.     SetTimeAdvise();
  2435.     return S_OK;
  2436. }
  2437.  
  2438.  
  2439. // switch to Stopped or Paused mode. Time mapping not known.
  2440.  
  2441. HRESULT
  2442. CCmdQueue::EndRun()
  2443. {
  2444.     CAutoLock lock(&m_Lock);
  2445.  
  2446.     m_bRunning = FALSE;
  2447.  
  2448.     // check timer setting - stream times
  2449.     SetTimeAdvise();
  2450.     return S_OK;
  2451. }
  2452.  
  2453.  
  2454. // return a pointer to the next due command. Blocks for msTimeout
  2455. // milliseconds until there is a due command.
  2456. // Stream-time commands will only become due between Run and Endrun calls.
  2457. // The command remains queued until invoked or cancelled.
  2458. // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error).
  2459. //
  2460. // returns an AddRef'd object
  2461.  
  2462. HRESULT
  2463. CCmdQueue::GetDueCommand(CDeferredCommand ** ppCmd, long msTimeout)
  2464. {
  2465.     // loop until we timeout or find a due command
  2466.     for (;;) {
  2467.  
  2468.         {
  2469.             CAutoLock lock(&m_Lock);
  2470.  
  2471.  
  2472.             // find the earliest command
  2473.             CDeferredCommand * pCmd = NULL;
  2474.  
  2475.             // check the presentation time and the
  2476.             // stream time list to find the earliest
  2477.  
  2478.             if (m_listPresentation.GetCount() > 0) {
  2479.                 POSITION pos = m_listPresentation.GetHeadPosition();
  2480.                 pCmd = m_listPresentation.Get(pos);
  2481.             }
  2482.  
  2483.             if (m_bRunning && (m_listStream.GetCount() > 0)) {
  2484.                 POSITION pos = m_listStream.GetHeadPosition();
  2485.                 CDeferredCommand* pStrm = m_listStream.Get(pos);
  2486.  
  2487.                 CRefTime t = pStrm->GetTime() + m_StreamTimeOffset;
  2488.                 if (!pCmd || (t < pCmd->GetTime())) {
  2489.                     pCmd = pStrm;
  2490.                 }
  2491.             }
  2492.  
  2493.             //  if we have found one, is it due?
  2494.             if (pCmd) {
  2495.                 if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) {
  2496.  
  2497.                     // yes it's due - addref it
  2498.                     pCmd->AddRef();
  2499.                     *ppCmd = pCmd;
  2500.                     return S_OK;
  2501.                 }
  2502.             }
  2503.         }
  2504.  
  2505.         // block until the advise is signalled
  2506.         if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) {
  2507.             return E_ABORT;
  2508.         }
  2509.     }
  2510. }
  2511.  
  2512.  
  2513. // return a pointer to a command that will be due for a given time.
  2514. // Pass in a stream time here. The stream time offset will be passed
  2515. // in via the Run method.
  2516. // Commands remain queued until invoked or cancelled.
  2517. // This method will not block. It will report E_ABORT if there are no
  2518. // commands due yet.
  2519. //
  2520. // returns an AddRef'd object
  2521.  
  2522. HRESULT
  2523. CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, CDeferredCommand**ppCmd)
  2524. {
  2525.     CAutoLock lock(&m_Lock);
  2526.  
  2527.     CRefTime tStream(rtStream);
  2528.  
  2529.     // find the earliest stream and presentation time commands
  2530.     CDeferredCommand* pStream = NULL;
  2531.     if (m_listStream.GetCount() > 0) {
  2532.         POSITION pos = m_listStream.GetHeadPosition();
  2533.         pStream = m_listStream.Get(pos);
  2534.     }
  2535.     CDeferredCommand* pPresent = NULL;
  2536.     if (m_listPresentation.GetCount() > 0) {
  2537.         POSITION pos = m_listPresentation.GetHeadPosition();
  2538.         pPresent = m_listPresentation.Get(pos);
  2539.     }
  2540.  
  2541.     // is there a presentation time that has passed already
  2542.     if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) {
  2543.         pPresent->AddRef();
  2544.         *ppCmd = pPresent;
  2545.         return S_OK;
  2546.     }
  2547.  
  2548.     // is there a stream time command due before this stream time
  2549.     if (pStream && (pStream->GetTime() <= tStream)) {
  2550.         pPresent->AddRef();
  2551.         *ppCmd = pStream;
  2552.         return S_OK;
  2553.     }
  2554.  
  2555.     // if we are running, we can map presentation times to
  2556.     // stream time. In this case, is there a presentation time command
  2557.     // that will be due before this stream time is presented?
  2558.     if (m_bRunning && pPresent) {
  2559.  
  2560.         // this stream time will appear at...
  2561.         tStream += m_StreamTimeOffset;
  2562.  
  2563.         // due before that?
  2564.         if (pPresent->GetTime() <= tStream) {
  2565.             *ppCmd = pPresent;
  2566.             return S_OK;
  2567.         }
  2568.     }
  2569.  
  2570.     // no commands due yet
  2571.     return VFW_E_NOT_FOUND;
  2572. }
  2573.  
  2574.