Guest User

Untitled

a guest
Jun 1st, 2011
353
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 115.98 KB | None | 0 0
  1. //  VirtualDub - Video processing and capture application
  2. //  A/V interface library
  3. //  Copyright (C) 1998-2004 Avery Lee
  4. //
  5. //  This program is free software; you can redistribute it and/or modify
  6. //  it under the terms of the GNU General Public License as published by
  7. //  the Free Software Foundation; either version 2 of the License, or
  8. //  (at your option) any later version.
  9. //
  10. //  This program is distributed in the hope that it will be useful,
  11. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //  GNU General Public License for more details.
  14. //
  15. //  You should have received a copy of the GNU General Public License
  16. //  along with this program; if not, write to the Free Software
  17. //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #pragma warning(disable: 4786)  // STFU
  20.  
  21. #define NO_DSHOW_STRSAFE
  22. #include <vd2/Riza/capdriver.h>
  23. #include <vd2/Riza/cap_dshow.h>
  24. #include <vd2/system/profile.h>
  25. #include <vd2/system/vdstring.h>
  26. #include <vd2/system/time.h>
  27. #include <vd2/system/fraction.h>
  28. #include <vd2/system/error.h>
  29. #include <vd2/system/math.h>
  30. #include <vd2/system/log.h>
  31. #include <vd2/system/refcount.h>
  32. #include <vd2/system/registry.h>
  33. #include <vd2/system/thread.h>
  34. #include <objbase.h>
  35. #include <dshow.h>
  36. #include <windows.h>
  37. #include <qedit.h>
  38. #include <guiddef.h>
  39. #include <dvdmedia.h>       // VIDEOINFOHEADER2
  40. #include <ks.h>
  41. #include <ksmedia.h>
  42. #include <vector>
  43.  
  44. using namespace nsVDCapture;
  45.  
  46. #pragma comment(lib, "amstrmid.lib")
  47.  
  48. extern HINSTANCE g_hInst;
  49.  
  50. #ifdef _MSC_VER
  51.     #pragma warning(disable: 4355)      // warning C4355: 'this' : used in base member initializer list
  52. #endif
  53.  
  54. #ifdef _DEBUG
  55.     #define DS_VERIFY(exp, msg) if (FAILED(hr = (exp))) { VDDEBUG("Failed: " msg " [%08lx : %s]\n", hr, GetDXErrorName(hr)); VDDumpFilterGraphDShow(mpGraph); TearDownGraph(); return false; } else
  56. #else
  57.     #define DS_VERIFY(exp, msg) if (FAILED(hr = (exp))) { VDLog(kVDLogWarning, VDStringW(L"CapDShow: Failed to build filter graph: " L##msg L"\n")); TearDownGraph(); return false; } else
  58. #endif
  59.  
  60. //#define VD_DSHOW_VERBOSE_LOGGING 1
  61.  
  62. #if VD_DSHOW_VERBOSE_LOGGING
  63.     #define DS_VERBOSE_LOG(msg) (VDLog(kVDLogInfo, VDStringW(L##msg)))
  64.     #define DS_VERBOSE_LOGF(...) (VDLog(kVDLogInfo, VDswprintf(__VA_ARGS__)))
  65. #else
  66.     #define DS_VERBOSE_LOG(msg) ((void)0)
  67.     #define DS_VERBOSE_LOGF(...) ((void)0)
  68. #endif
  69.  
  70. ///////////////////////////////////////////////////////////////////////////
  71. //
  72. //  smart pointers
  73. //
  74. ///////////////////////////////////////////////////////////////////////////
  75.  
  76. namespace {
  77.     // New auto ptr for COM because the MS one has some really unsafe
  78.     // overloads -- for instance, operator&() makes it a landmine if you
  79.     // try putting it in an STL container. Also, the DDK doesn't come
  80.     // with comsupp.lib.
  81.  
  82.     template<class T, const IID *T_IID>
  83.     class VD_MSCOMAutoPtr {
  84.     public:
  85.         VD_MSCOMAutoPtr() : mp(NULL) {}
  86.  
  87.         VD_MSCOMAutoPtr(const VD_MSCOMAutoPtr& src)
  88.             : mp(src.mp)
  89.         {
  90.             if (mp)
  91.                 mp->AddRef();
  92.         }
  93.  
  94.         VD_MSCOMAutoPtr(T *p) : mp(p) {
  95.             if (mp)
  96.                 mp->AddRef();
  97.         }
  98.  
  99.         ~VD_MSCOMAutoPtr() {
  100.             if (mp)
  101.                 mp->Release();
  102.         }
  103.  
  104.         VD_MSCOMAutoPtr& operator=(const VD_MSCOMAutoPtr& src) {
  105.             T *const p = src.mp;
  106.  
  107.             if (p != mp) {
  108.                 if (p)
  109.                     p->AddRef();
  110.                 T *pOld = mp;
  111.                 mp = p;
  112.                 if (pOld)
  113.                     pOld->Release();
  114.             }
  115.             return *this;
  116.         }
  117.  
  118.         VD_MSCOMAutoPtr& operator=(T *p) {
  119.             if (mp != p) {
  120.                 if(p)
  121.                     p->AddRef();
  122.                 T *pOld = mp;
  123.                 mp = p;
  124.                 if (pOld)
  125.                     pOld->Release();
  126.             }
  127.             return *this;
  128.         }
  129.  
  130.         operator T*() const {
  131.             return mp;
  132.         }
  133.  
  134.         T& operator*() const {
  135.             return *mp;
  136.         }
  137.  
  138.         T *operator->() const {
  139.             return mp;
  140.         }
  141.  
  142.         T **operator~() {
  143.             if (mp) {
  144.                 mp->Release();
  145.                 mp = NULL;
  146.             }
  147.             return &mp;
  148.         }
  149.  
  150.         bool operator!() const { return !mp; }
  151.         bool operator==(T* p) const { return mp == p; }
  152.         bool operator!=(T* p) const { return mp != p; }
  153.  
  154.         void Swap(VD_MSCOMAutoPtr& x) {
  155.             std::swap(mp, x.mp);
  156.         }
  157.  
  158.         HRESULT CreateInstance(const CLSID& clsid, IUnknown *pOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) {
  159.             if (mp) {
  160.                 mp->Release();
  161.                 mp = NULL;
  162.             }
  163.  
  164.             return CoCreateInstance(clsid, pOuter, dwClsContext, *T_IID, (void **)&mp);
  165.         }
  166.  
  167.         T *mp;
  168.     };
  169.  
  170.     template<class T>
  171.     bool operator==(T *p, const VD_MSCOMAutoPtr<T, &__uuidof(T)>& ap) {
  172.         return p == ap.mp;
  173.     }
  174.  
  175.     template<class T>
  176.     bool operator!=(T *p, const VD_MSCOMAutoPtr<T, &__uuidof(T)>& ap) {
  177.         return p != ap.mp;
  178.     }
  179.  
  180.     #define I_HATE(x) typedef VD_MSCOMAutoPtr<x, &__uuidof(x)> x##Ptr
  181.  
  182.     I_HATE(IAMAnalogVideoDecoder);
  183.     I_HATE(IAMAudioInputMixer);
  184.     I_HATE(IAMCrossbar);
  185.     I_HATE(IAMStreamConfig);
  186.     I_HATE(IAMStreamControl);
  187.     I_HATE(IAMTuner);
  188.     I_HATE(IAMTVTuner);
  189.     I_HATE(IAMVfwCaptureDialogs);
  190.     I_HATE(IBaseFilter);
  191.     I_HATE(ICaptureGraphBuilder2);
  192.     I_HATE(IEnumFilters);
  193.     I_HATE(IEnumMediaTypes);
  194.     I_HATE(IEnumPins);
  195.     I_HATE(IFilterGraph);
  196.     I_HATE(IGraphBuilder);
  197.     I_HATE(IMediaControl);
  198.     I_HATE(IMediaEventEx);
  199.     I_HATE(IMediaFilter);
  200.     I_HATE(IMediaSample);
  201.     I_HATE(IMoniker);
  202.     I_HATE(IPin);
  203.     I_HATE(IReferenceClock);
  204.     I_HATE(ISampleGrabber);
  205.     I_HATE(ISpecifyPropertyPages);
  206.     I_HATE(IVideoWindow);
  207.     I_HATE(IKsPropertySet);
  208.     I_HATE(IClassFactory);
  209.     I_HATE(IAMVideoProcAmp);
  210.  
  211.     #undef I_HATE
  212. }
  213.  
  214. namespace {
  215.     #ifdef _DEBUG
  216.         const char *GetDXErrorName(const HRESULT hr) {
  217. #define X(err) case err: return #err
  218.             switch(hr) {
  219.                 X(VFW_E_INVALIDMEDIATYPE);
  220.                 X(VFW_E_INVALIDSUBTYPE);
  221.                 X(VFW_E_NEED_OWNER);
  222.                 X(VFW_E_ENUM_OUT_OF_SYNC);
  223.                 X(VFW_E_ALREADY_CONNECTED);
  224.                 X(VFW_E_FILTER_ACTIVE);
  225.                 X(VFW_E_NO_TYPES);
  226.                 X(VFW_E_NO_ACCEPTABLE_TYPES);
  227.                 X(VFW_E_INVALID_DIRECTION);
  228.                 X(VFW_E_NOT_CONNECTED);
  229.                 X(VFW_E_NO_ALLOCATOR);
  230.                 X(VFW_E_RUNTIME_ERROR);
  231.                 X(VFW_E_BUFFER_NOTSET);
  232.                 X(VFW_E_BUFFER_OVERFLOW);
  233.                 X(VFW_E_BADALIGN);
  234.                 X(VFW_E_ALREADY_COMMITTED);
  235.                 X(VFW_E_BUFFERS_OUTSTANDING);
  236.                 X(VFW_E_NOT_COMMITTED);
  237.                 X(VFW_E_SIZENOTSET);
  238.                 X(VFW_E_NO_CLOCK);
  239.                 X(VFW_E_NO_SINK);
  240.                 X(VFW_E_NO_INTERFACE);
  241.                 X(VFW_E_NOT_FOUND);
  242.                 X(VFW_E_CANNOT_CONNECT);
  243.                 X(VFW_E_CANNOT_RENDER);
  244.                 X(VFW_E_CHANGING_FORMAT);
  245.                 X(VFW_E_NO_COLOR_KEY_SET);
  246.                 X(VFW_E_NOT_OVERLAY_CONNECTION);
  247.                 X(VFW_E_NOT_SAMPLE_CONNECTION);
  248.                 X(VFW_E_PALETTE_SET);
  249.                 X(VFW_E_COLOR_KEY_SET);
  250.                 X(VFW_E_NO_COLOR_KEY_FOUND);
  251.                 X(VFW_E_NO_PALETTE_AVAILABLE);
  252.                 X(VFW_E_NO_DISPLAY_PALETTE);
  253.                 X(VFW_E_TOO_MANY_COLORS);
  254.                 X(VFW_E_STATE_CHANGED);
  255.                 X(VFW_E_NOT_STOPPED);
  256.                 X(VFW_E_NOT_PAUSED);
  257.                 X(VFW_E_NOT_RUNNING);
  258.                 X(VFW_E_WRONG_STATE);
  259.                 X(VFW_E_START_TIME_AFTER_END);
  260.                 X(VFW_E_INVALID_RECT);
  261.                 X(VFW_E_TYPE_NOT_ACCEPTED);
  262.                 X(VFW_E_SAMPLE_REJECTED);
  263.                 X(VFW_E_SAMPLE_REJECTED_EOS);
  264.                 X(VFW_E_DUPLICATE_NAME);
  265.                 X(VFW_S_DUPLICATE_NAME);
  266.                 X(VFW_E_TIMEOUT);
  267.                 X(VFW_E_INVALID_FILE_FORMAT);
  268.                 X(VFW_E_ENUM_OUT_OF_RANGE);
  269.                 X(VFW_E_CIRCULAR_GRAPH);
  270.                 X(VFW_E_NOT_ALLOWED_TO_SAVE);
  271.                 X(VFW_E_TIME_ALREADY_PASSED);
  272.                 X(VFW_E_ALREADY_CANCELLED);
  273.                 X(VFW_E_CORRUPT_GRAPH_FILE);
  274.                 X(VFW_E_ADVISE_ALREADY_SET);
  275.                 X(VFW_S_STATE_INTERMEDIATE);
  276.                 X(VFW_E_NO_MODEX_AVAILABLE);
  277.                 X(VFW_E_NO_ADVISE_SET);
  278.                 X(VFW_E_NO_FULLSCREEN);
  279.                 X(VFW_E_IN_FULLSCREEN_MODE);
  280.                 X(VFW_E_UNKNOWN_FILE_TYPE);
  281.                 X(VFW_E_CANNOT_LOAD_SOURCE_FILTER);
  282.                 X(VFW_S_PARTIAL_RENDER);
  283.                 X(VFW_E_FILE_TOO_SHORT);
  284.                 X(VFW_E_INVALID_FILE_VERSION);
  285.                 X(VFW_S_SOME_DATA_IGNORED);
  286.                 X(VFW_S_CONNECTIONS_DEFERRED);
  287.                 X(VFW_E_INVALID_CLSID);
  288.                 X(VFW_E_INVALID_MEDIA_TYPE);
  289.                 X(VFW_E_SAMPLE_TIME_NOT_SET);
  290.                 X(VFW_S_RESOURCE_NOT_NEEDED);
  291.                 X(VFW_E_MEDIA_TIME_NOT_SET);
  292.                 X(VFW_E_NO_TIME_FORMAT_SET);
  293.                 X(VFW_E_MONO_AUDIO_HW);
  294.                 X(VFW_S_MEDIA_TYPE_IGNORED);
  295.                 X(VFW_E_NO_DECOMPRESSOR);
  296.                 X(VFW_E_NO_AUDIO_HARDWARE);
  297.                 X(VFW_S_VIDEO_NOT_RENDERED);
  298.                 X(VFW_S_AUDIO_NOT_RENDERED);
  299.                 X(VFW_E_RPZA);
  300.                 X(VFW_S_RPZA);
  301.                 X(VFW_E_PROCESSOR_NOT_SUITABLE);
  302.                 X(VFW_E_UNSUPPORTED_AUDIO);
  303.                 X(VFW_E_UNSUPPORTED_VIDEO);
  304.                 X(VFW_E_MPEG_NOT_CONSTRAINED);
  305.                 X(VFW_E_NOT_IN_GRAPH);
  306.                 X(VFW_S_ESTIMATED);
  307.                 X(VFW_E_NO_TIME_FORMAT);
  308.                 X(VFW_E_READ_ONLY);
  309.                 X(VFW_S_RESERVED);
  310.                 X(VFW_E_BUFFER_UNDERFLOW);
  311.                 X(VFW_E_UNSUPPORTED_STREAM);
  312.                 X(VFW_E_NO_TRANSPORT);
  313.                 X(VFW_S_STREAM_OFF);
  314.                 X(VFW_S_CANT_CUE);
  315.                 X(VFW_E_BAD_VIDEOCD);
  316.                 X(VFW_S_NO_STOP_TIME);
  317.                 X(VFW_E_OUT_OF_VIDEO_MEMORY);
  318.                 X(VFW_E_VP_NEGOTIATION_FAILED);
  319.                 X(VFW_E_DDRAW_CAPS_NOT_SUITABLE);
  320.                 X(VFW_E_NO_VP_HARDWARE);
  321.                 X(VFW_E_NO_CAPTURE_HARDWARE);
  322.                 X(VFW_E_DVD_OPERATION_INHIBITED);
  323.                 X(VFW_E_DVD_INVALIDDOMAIN);
  324.                 X(VFW_E_DVD_NO_BUTTON);
  325.                 X(VFW_E_DVD_GRAPHNOTREADY);
  326.                 X(VFW_E_DVD_RENDERFAIL);
  327.                 X(VFW_E_DVD_DECNOTENOUGH);
  328.                 X(VFW_E_DVD_NOT_IN_KARAOKE_MODE);
  329.                 X(VFW_E_FRAME_STEP_UNSUPPORTED);
  330.                 X(VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD);
  331.                 X(VFW_E_PIN_ALREADY_BLOCKED);
  332.                 X(VFW_E_CERTIFICATION_FAILURE);
  333.                 X(VFW_E_VMR_NOT_IN_MIXER_MODE);
  334.                 X(VFW_E_VMR_NO_AP_SUPPLIED);
  335.                 X(VFW_E_VMR_NO_DEINTERLACE_HW);
  336.                 X(VFW_E_VMR_NO_PROCAMP_HW);
  337.                 X(VFW_E_DVD_VMR9_INCOMPATIBLEDEC);
  338.                 X(VFW_E_BAD_KEY);
  339.             default:
  340.                 return "";
  341.             }
  342. #undef X
  343.         }
  344.     #else
  345.         const char *GetDXErrorName(const HRESULT hr) {
  346.             return "";
  347.         }
  348.     #endif
  349.  
  350.     HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
  351.     {
  352.         IMoniker * pMoniker;
  353.         IRunningObjectTable *pROT;
  354.         if (FAILED(GetRunningObjectTable(0, &pROT))) {
  355.             return E_FAIL;
  356.         }
  357.         WCHAR wsz[256];
  358.         swprintf(wsz, 256, L"FilterGraph %08p pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
  359.         HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
  360.         if (SUCCEEDED(hr)) {
  361.             hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);
  362.             pMoniker->Release();
  363.         }
  364.         pROT->Release();
  365.         return hr;
  366.     }
  367.  
  368.     void RemoveFromRot(DWORD pdwRegister)
  369.     {
  370.         IRunningObjectTable *pROT;
  371.         if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
  372.             pROT->Revoke(pdwRegister);
  373.             pROT->Release();
  374.         }
  375.     }
  376.  
  377.     void DestroySubgraph(IFilterGraph *pGraph, IBaseFilter *pFilt, IBaseFilter *pKeepFilter, IBaseFilter *pKeepFilter2) {
  378.         IEnumPins *pEnum;
  379.  
  380.         if (!pFilt)
  381.             return;
  382.  
  383.         if (SUCCEEDED(pFilt->EnumPins(&pEnum))) {
  384.             IPin *pPin;
  385.  
  386.             pEnum->Reset();
  387.  
  388.             for(;;) {
  389.                 HRESULT hr = pEnum->Next(1, &pPin, 0);
  390.                 if (hr == VFW_E_ENUM_OUT_OF_SYNC) {
  391.                     hr = pEnum->Reset();
  392.                     if (SUCCEEDED(hr))
  393.                         continue;
  394.                 }
  395.                 if (hr != S_OK)
  396.                     break;
  397.  
  398.                 PIN_DIRECTION dir;
  399.  
  400.                 VDVERIFY(SUCCEEDED(pPin->QueryDirection(&dir)));
  401.  
  402.                 if (dir == PINDIR_OUTPUT) {
  403.                     IPin *pPin2;
  404.  
  405.                     if (SUCCEEDED(pPin->ConnectedTo(&pPin2))) {
  406.                         PIN_INFO pi;
  407.  
  408.                         if (SUCCEEDED(pPin2->QueryPinInfo(&pi))) {
  409.                             DestroySubgraph(pGraph, pi.pFilter, pKeepFilter, pKeepFilter2);
  410.  
  411.                             if ((!pKeepFilter || pi.pFilter != pKeepFilter) && (!pKeepFilter2 || pi.pFilter != pKeepFilter2))
  412.                                 VDVERIFY(SUCCEEDED(pGraph->RemoveFilter(pi.pFilter)));
  413.  
  414.                             pi.pFilter->Release();
  415.                         }
  416.  
  417.                         pPin2->Release();
  418.                     }
  419.                 }
  420.  
  421.                 pPin->Release();
  422.             }
  423.  
  424.             pEnum->Release();
  425.         }
  426.     }
  427.  
  428.     AM_MEDIA_TYPE *RizaCopyMediaType(const AM_MEDIA_TYPE *pSrc) {
  429.         AM_MEDIA_TYPE *pamt;
  430.  
  431.         if (pamt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))) {
  432.  
  433.             *pamt = *pSrc;
  434.  
  435.             if (pamt->pbFormat = (BYTE *)CoTaskMemAlloc(pSrc->cbFormat)) {
  436.                 memcpy(pamt->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
  437.  
  438.                 if (pamt->pUnk)
  439.                     pamt->pUnk->AddRef();
  440.  
  441.                 return pamt;
  442.             }
  443.  
  444.             CoTaskMemFree(pamt);
  445.         }
  446.  
  447.         return NULL;
  448.     }
  449.  
  450.     bool RizaCopyMediaType(AM_MEDIA_TYPE *pDst, const AM_MEDIA_TYPE *pSrc) {
  451.         *pDst = *pSrc;
  452.  
  453.         if (pDst->pbFormat = (BYTE *)CoTaskMemAlloc(pSrc->cbFormat)) {
  454.             memcpy(pDst->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
  455.  
  456.             if (pDst->pUnk)
  457.                 pDst->pUnk->AddRef();
  458.  
  459.             return true;
  460.         }
  461.  
  462.         return false;
  463.     }
  464.  
  465.     void RizaDeleteMediaType(AM_MEDIA_TYPE *pamt) {
  466.         if (!pamt)
  467.             return;
  468.  
  469.         if (pamt->pUnk)
  470.             pamt->pUnk->Release();
  471.  
  472.         if (pamt->pbFormat)
  473.             CoTaskMemFree(pamt->pbFormat);
  474.  
  475.         CoTaskMemFree(pamt);
  476.     }
  477.  
  478.     bool SetClockFromDownstream(IBaseFilter *pFilt, IMediaFilter *pGraphMF) {
  479.         IReferenceClock *pRC;
  480.         if (SUCCEEDED(pFilt->QueryInterface(IID_IReferenceClock, (void **)&pRC))) {
  481.             pGraphMF->SetSyncSource(pRC);
  482.             pRC->Release();
  483.  
  484.             return true;
  485.         }
  486.  
  487.         bool success = false;
  488.  
  489.         IEnumPins *pEnum;
  490.         if (SUCCEEDED(pFilt->EnumPins(&pEnum))) {
  491.             IPin *pPin;
  492.  
  493.             pEnum->Reset();
  494.  
  495.             for(;;) {
  496.                 HRESULT hr = pEnum->Next(1, &pPin, 0);
  497.                 if (hr == VFW_E_ENUM_OUT_OF_SYNC) {
  498.                     hr = pEnum->Reset();
  499.                     if (SUCCEEDED(hr))
  500.                         continue;
  501.                 }
  502.                 if (hr != S_OK)
  503.                     break;
  504.  
  505.                 PIN_DIRECTION dir;
  506.  
  507.                 VDVERIFY(SUCCEEDED(pPin->QueryDirection(&dir)));
  508.  
  509.                 if (dir == PINDIR_OUTPUT) {
  510.                     IPin *pPin2;
  511.  
  512.                     if (SUCCEEDED(pPin->ConnectedTo(&pPin2))) {
  513.                         PIN_INFO pi;
  514.  
  515.                         if (SUCCEEDED(pPin2->QueryPinInfo(&pi))) {
  516.                             if (SetClockFromDownstream(pi.pFilter, pGraphMF))
  517.                                 success = true;
  518.  
  519.                             pi.pFilter->Release();
  520.                         }
  521.  
  522.                         pPin2->Release();
  523.                     }
  524.                 }
  525.  
  526.                 pPin->Release();
  527.  
  528.                 if (success)
  529.                     break;
  530.             }
  531.  
  532.             pEnum->Release();
  533.         }
  534.  
  535.         return success;
  536.     }
  537.  
  538.     typedef std::vector<std::pair<IMonikerPtr, VDStringW> > tDeviceVector;
  539.  
  540.     void Enumerate(tDeviceVector& devlist, REFCLSID devclsid) {
  541.         ICreateDevEnum *pCreateDevEnum;
  542.         IEnumMoniker *pEm = NULL;
  543.  
  544.         if (SUCCEEDED(CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pCreateDevEnum))) {
  545.             pCreateDevEnum->CreateClassEnumerator(devclsid, &pEm, 0);
  546.             pCreateDevEnum->Release();
  547.         }
  548.  
  549.         if (pEm) {
  550.             IMoniker *pM;
  551.             ULONG cFetched;
  552.  
  553.             while(S_OK == pEm->Next(1, &pM, &cFetched) && cFetched==1) {
  554.                 IPropertyBag *pPropBag;
  555.  
  556.                 if (SUCCEEDED(pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag))) {
  557.                     VARIANT varName;
  558.  
  559.                     varName.vt = VT_BSTR;
  560.                     varName.bstrVal = NULL;
  561.  
  562.                     if (SUCCEEDED(pPropBag->Read(L"FriendlyName", &varName, 0))) {
  563.                         VDStringW name(varName.bstrVal);
  564.  
  565.                         if (devclsid == CLSID_VideoInputDeviceCategory) {
  566.                             bool isVFWDriver = false;
  567.                             LPOLESTR displayName;
  568.                             if (SUCCEEDED(pM->GetDisplayName(NULL, NULL, &displayName))) {
  569.                                 // Detect a VFW driver by the compression manager tag.
  570.                                 if (!wcsncmp(displayName, L"@device:cm:", 11))
  571.                                     isVFWDriver = true;
  572.                                 CoTaskMemFree(displayName);
  573.                             }
  574.                             name += (isVFWDriver ? L" (VFW>DirectShow)" : L" (DirectShow)");
  575.                         }
  576.  
  577.                         devlist.push_back(tDeviceVector::value_type(pM, name));
  578.  
  579.                         SysFreeString(varName.bstrVal);
  580.                     }
  581.  
  582.                     pPropBag->Release();
  583.                 }
  584.  
  585.                 pM->Release();
  586.             }
  587.  
  588.             pEm->Release();
  589.         }
  590.     }
  591.  
  592.     class VDWaveFormatAsDShowMediaType : public AM_MEDIA_TYPE {
  593.     public:
  594.         VDWaveFormatAsDShowMediaType(const WAVEFORMATEX *pwfex, UINT size) {
  595.             majortype       = MEDIATYPE_Audio;
  596.             subtype.Data1   = pwfex->wFormatTag;
  597.             subtype.Data2   = 0;
  598.             subtype.Data3   = 0x0010;
  599.             subtype.Data4[0] = 0x80;
  600.             subtype.Data4[1] = 0x00;
  601.             subtype.Data4[2] = 0x00;
  602.             subtype.Data4[3] = 0xAA;
  603.             subtype.Data4[4] = 0x00;
  604.             subtype.Data4[5] = 0x38;
  605.             subtype.Data4[6] = 0x9B;
  606.             subtype.Data4[7] = 0x71;
  607.             bFixedSizeSamples   = TRUE;
  608.             bTemporalCompression    = FALSE;
  609.             lSampleSize     = pwfex->nBlockAlign;
  610.             formattype      = FORMAT_WaveFormatEx;
  611.             pUnk            = NULL;
  612.             cbFormat        = size;
  613.             pbFormat        = (BYTE *)pwfex;
  614.         }
  615.     };
  616.  
  617.     class VDAMMediaType : public AM_MEDIA_TYPE {
  618.     public:
  619.         VDAMMediaType() {
  620.             cbFormat = 0;
  621.             pbFormat = NULL;
  622.         }
  623.  
  624.         VDAMMediaType(const VDAMMediaType& src) {
  625.             *static_cast<AM_MEDIA_TYPE *>(this) = src;
  626.  
  627.             if (pbFormat) {
  628.                 pbFormat = (BYTE *)CoTaskMemAlloc(cbFormat);
  629.                 if (pbFormat)
  630.                     memcpy(pbFormat, src.pbFormat, cbFormat);
  631.                 else
  632.                     cbFormat = 0;
  633.             } else
  634.                 cbFormat = 0;
  635.         }
  636.  
  637.         VDAMMediaType(const AM_MEDIA_TYPE& src) {
  638.             *static_cast<AM_MEDIA_TYPE *>(this) = src;
  639.  
  640.             if (pbFormat) {
  641.                 pbFormat = (BYTE *)CoTaskMemAlloc(cbFormat);
  642.                 if (pbFormat)
  643.                     memcpy(pbFormat, src.pbFormat, cbFormat);
  644.                 else
  645.                     cbFormat = 0;
  646.             } else
  647.                 cbFormat = 0;
  648.         }
  649.  
  650.         ~VDAMMediaType() {
  651.             if (pbFormat)
  652.                 CoTaskMemFree(pbFormat);
  653.         }
  654.  
  655.         VDAMMediaType& operator=(const VDAMMediaType& src) {
  656.             if (pbFormat)
  657.                 CoTaskMemFree(pbFormat);
  658.  
  659.             *static_cast<AM_MEDIA_TYPE *>(this) = src;
  660.  
  661.             if (pbFormat) {
  662.                 pbFormat = (BYTE *)CoTaskMemAlloc(cbFormat);
  663.                 if (pbFormat)
  664.                     memcpy(pbFormat, src.pbFormat, cbFormat);
  665.                 else
  666.                     cbFormat = 0;
  667.             } else
  668.                 cbFormat = 0;
  669.  
  670.             return *this;
  671.         }
  672.  
  673.         VDAMMediaType& operator=(const AM_MEDIA_TYPE& src) {
  674.             if (pbFormat)
  675.                 CoTaskMemFree(pbFormat);
  676.  
  677.             *static_cast<AM_MEDIA_TYPE *>(this) = src;
  678.  
  679.             if (pbFormat) {
  680.                 pbFormat = (BYTE *)CoTaskMemAlloc(cbFormat);
  681.                 if (pbFormat)
  682.                     memcpy(pbFormat, src.pbFormat, cbFormat);
  683.                 else
  684.                     cbFormat = 0;
  685.             } else
  686.                 cbFormat = 0;
  687.  
  688.             return *this;
  689.         }
  690.  
  691.         void clear() {
  692.             if (pbFormat) {
  693.                 CoTaskMemFree(pbFormat);
  694.                 pbFormat = NULL;
  695.                 cbFormat = 0;
  696.             }
  697.  
  698.             majortype = GUID_NULL;
  699.             subtype = GUID_NULL;
  700.             formattype = GUID_NULL;
  701.         }
  702.  
  703.         void *realloc(size_t n) {
  704.             if (cbFormat != n) {
  705.                 if (pbFormat) {
  706.                     CoTaskMemFree(pbFormat);
  707.                     pbFormat = NULL;
  708.                     cbFormat = 0;
  709.                 }
  710.  
  711.                 pbFormat = (BYTE *)CoTaskMemAlloc(n);
  712.                 if (pbFormat)
  713.                     cbFormat = n;
  714.                 else
  715.                     cbFormat = 0;
  716.             }
  717.  
  718.             return pbFormat;
  719.         }
  720.     };
  721.  
  722.     const wchar_t *VDGetNameForPhysicalConnectorTypeDShow(PhysicalConnectorType type) {
  723.         switch(type) {
  724.         case PhysConn_Video_Tuner:              return L"Video Tuner";
  725.         case PhysConn_Video_Composite:          return L"Video Composite";
  726.         case PhysConn_Video_SVideo:             return L"Video SVideo";
  727.         case PhysConn_Video_RGB:                return L"Video RGB";
  728.         case PhysConn_Video_YRYBY:              return L"Video YRYBY";
  729.         case PhysConn_Video_SerialDigital:      return L"Video Serial Digital";
  730.         case PhysConn_Video_ParallelDigital:    return L"Video Parallel Digital";
  731.         case PhysConn_Video_SCSI:               return L"Video SCSI";
  732.         case PhysConn_Video_AUX:                return L"Video AUX";
  733.         case PhysConn_Video_1394:               return L"Video 1394";
  734.         case PhysConn_Video_USB:                return L"Video USB";
  735.         case PhysConn_Video_VideoDecoder:       return L"Video Decoder";
  736.         case PhysConn_Video_VideoEncoder:       return L"Video Encoder";
  737.         case PhysConn_Video_SCART:              return L"Video SCART";
  738.  
  739.         case PhysConn_Audio_Tuner:              return L"Audio Tuner";
  740.         case PhysConn_Audio_Line:               return L"Audio Line";
  741.         case PhysConn_Audio_Mic:                return L"Audio Mic";
  742.         case PhysConn_Audio_AESDigital:         return L"Audio AES Digital";
  743.         case PhysConn_Audio_SPDIFDigital:       return L"Audio SPDIF Digital";
  744.         case PhysConn_Audio_SCSI:               return L"Audio SCSI";
  745.         case PhysConn_Audio_AUX:                return L"Audio AUX";
  746.         case PhysConn_Audio_1394:               return L"Audio 1394";
  747.         case PhysConn_Audio_USB:                return L"Audio USB";
  748.         case PhysConn_Audio_AudioDecoder:       return L"Audio Decoder";
  749.  
  750.         default:                                return L"(Unknown type)";
  751.         }
  752.     }
  753.  
  754.     bool VDIsPinConnectedDShow(IPin *pPin) {
  755.         IPinPtr pConn;
  756.         return SUCCEEDED(pPin->ConnectedTo(~pConn));
  757.     }
  758.  
  759.     bool VDGetFilterConnectedToPinDShow(IPin *pPin, IBaseFilter **ppFilter) {
  760.         IPinPtr pConn;
  761.         if (FAILED(pPin->ConnectedTo(~pConn)))
  762.             return false;
  763.  
  764.         PIN_INFO pi;
  765.         if (FAILED(pConn->QueryPinInfo(&pi)))
  766.             return false;
  767.  
  768.         *ppFilter = pi.pFilter;
  769.         return true;
  770.     }
  771.  
  772.     bool VDIsFilterInGraphDShow(IBaseFilter *pFilter) {
  773.         FILTER_INFO fi;
  774.  
  775.         if (FAILED(pFilter->QueryFilterInfo(&fi)))
  776.             return false;
  777.  
  778.         bool inGraph = fi.pGraph != NULL;
  779.  
  780.         if (fi.pGraph)
  781.             fi.pGraph->Release();
  782.  
  783.         return inGraph;
  784.     }
  785.  
  786.     void VDDumpFilterGraphDShow(IFilterGraph *pGraph) {
  787.         std::list<IBaseFilterPtr> filters;
  788.  
  789.         IEnumFiltersPtr pEnumFilters;
  790.         if (SUCCEEDED(pGraph->EnumFilters(~pEnumFilters))) {
  791.             for(;;) {
  792.                 IBaseFilterPtr pFilter;
  793.                 HRESULT hr = pEnumFilters->Next(1, ~pFilter, NULL);
  794.                 if (hr == VFW_E_ENUM_OUT_OF_SYNC) {
  795.                     filters.clear();
  796.                     if (FAILED(pEnumFilters->Reset()))
  797.                         break;
  798.                     continue;
  799.                 }
  800.  
  801.                 if (hr != S_OK)
  802.                     break;
  803.  
  804.                 filters.push_back(pFilter);
  805.             }
  806.             pEnumFilters = NULL;
  807.         }
  808.  
  809.         VDDEBUG("Filter graph %p:\n", &*pGraph);
  810.  
  811.         IMediaFilterPtr pGraphMF;
  812.         if (SUCCEEDED(pGraph->QueryInterface(IID_IMediaFilter, (void **)~pGraphMF))) {
  813.             IReferenceClockPtr pRefClock;
  814.  
  815.             if (SUCCEEDED(pGraphMF->GetSyncSource(~pRefClock))) {
  816.                 IBaseFilterPtr pRefFilter;
  817.                 if (!pRefClock)
  818.                     VDDEBUG("  Reference clock: none\n");
  819.                 else if (SUCCEEDED(pRefClock->QueryInterface(IID_IFilterGraph, (void **)~IFilterGraphPtr())))
  820.                     VDDEBUG("  Reference clock: filter graph\n");
  821.                 else if (SUCCEEDED(pRefClock->QueryInterface(IID_IBaseFilter, (void **)~pRefFilter))) {
  822.                     FILTER_INFO fi;
  823.  
  824.                     if (SUCCEEDED(pRefFilter->QueryFilterInfo(&fi))) {
  825.                         if (fi.pGraph)
  826.                             fi.pGraph->Release();
  827.  
  828.                         VDDEBUG("  Reference clock: filter \"%ls\"\n", fi.achName);
  829.                     }
  830.                 } else if (pRefClock)
  831.                     VDDEBUG("  Reference clock: unknown\n");
  832.             }
  833.         }
  834.  
  835.         while(!filters.empty()) {
  836.             IBaseFilterPtr pFilter;
  837.  
  838.             pFilter.Swap(filters.front());
  839.             filters.pop_front();
  840.  
  841.             FILTER_INFO fi;
  842.             fi.achName[0] = 0;
  843.             if (SUCCEEDED(pFilter->QueryFilterInfo(&fi))) {
  844.                 fi.pGraph->Release();
  845.             }
  846.             VDDEBUG("  Filter %p [%ls]:\n", &*pFilter, fi.achName);
  847.  
  848.             IEnumPinsPtr pEnumPins;
  849.             if (SUCCEEDED(pFilter->EnumPins(~pEnumPins))) {
  850.                 for(;;) {
  851.                     IPinPtr pPin;
  852.                     HRESULT hr = pEnumPins->Next(1, ~pPin, NULL);
  853.                     if (hr != S_OK)
  854.                         break;
  855.  
  856.                     PIN_INFO pi;
  857.                     VDVERIFY(SUCCEEDED(pPin->QueryPinInfo(&pi)));
  858.                     pi.pFilter->Release();
  859.                     VDDEBUG("    Pin \"%ls\" (%s): ", pi.achName, pi.dir == PINDIR_INPUT ? "input " : "output");
  860.  
  861.                     IPinPtr pPinConn;
  862.                     if (SUCCEEDED(pPin->ConnectedTo(~pPinConn))) {
  863.                         PIN_INFO pi2;
  864.                         FILTER_INFO fi2;
  865.                         VDVERIFY(SUCCEEDED(pPinConn->QueryPinInfo(&pi2)));
  866.                         VDVERIFY(SUCCEEDED(pi2.pFilter->QueryFilterInfo(&fi2)));
  867.                         VDDEBUG(" connected to pin \"%ls\" of filter \"%ls\"\n", pi2.achName, fi2.achName);
  868.                         fi2.pGraph->Release();
  869.                         pi2.pFilter->Release();
  870.                     } else
  871.                         VDDEBUG(" unconnected\n");
  872.                 }
  873.             }
  874.         }
  875.         VDDEBUG("\n");
  876.     }
  877.  
  878.     bool VDSaveFilterGraphDShow(const wchar_t *filename, IFilterGraph *pGraph) {
  879.         bool success = false;
  880.  
  881.         IStorage *pStorage = NULL;
  882.         HRESULT hr = StgCreateDocfile(filename, STGM_CREATE | STGM_TRANSACTED | STGM_WRITE | STGM_SHARE_DENY_READ, 0, &pStorage);
  883.         if (SUCCEEDED(hr)) {
  884.             IPersistStream *pPersistStream = NULL;
  885.             hr = pGraph->QueryInterface(IID_IPersistStream, (void **)&pPersistStream);
  886.             if (SUCCEEDED(hr)) {
  887.                 IStream *pStream = NULL;
  888.                 hr = pStorage->CreateStream(L"ActiveMovieGraph", STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream);
  889.                 if(SUCCEEDED(hr)) {
  890.                     hr = pPersistStream->Save(pStream, TRUE);
  891.                     success = SUCCEEDED(hr);
  892.                     pStream->Release();
  893.                 }
  894.                 pPersistStream->Release();
  895.             }
  896.             pStorage->Commit(STGC_DEFAULT);
  897.             pStorage->Release();
  898.         }
  899.         return success;
  900.     }
  901. }
  902.  
  903. ///////////////////////////////////////////////////////////////////////////
  904. //
  905. //  DirectShow sample callbacks.
  906. //
  907. //  We place these in separate classes because we need two of them, and
  908. //  that means we can't place it in the device. *sigh*
  909. //
  910. ///////////////////////////////////////////////////////////////////////////
  911.  
  912. class IVDCaptureDSCallback {
  913. public:
  914.     virtual bool CapTryEnterCriticalSection() = 0;
  915.     virtual void CapProcessData(int stream, const void *data, uint32 size, sint64 timestamp, bool key) = 0;
  916.     virtual void CapLeaveCriticalSection() = 0;
  917. };
  918.  
  919. class VDCapDevDSCallback : public ISampleGrabberCB {
  920. protected:
  921.  
  922.     VDAtomicInt mRefCount;
  923.     IVDCaptureDSCallback *mpCallback;
  924.     VDAtomicInt mBlockSamples;
  925.     bool mIgnoreTimestamps;
  926.     uint32 mTimeBase;
  927.  
  928. public:
  929.  
  930.     VDCapDevDSCallback(IVDCaptureDSCallback *pCB)
  931.         : mRefCount(1)
  932.         , mpCallback(pCB)
  933.         , mBlockSamples(true)
  934.         , mIgnoreTimestamps(false)
  935.         , mTimeBase(0)
  936.     {
  937.     }
  938.  
  939.     void SetBlockSamples(bool block) {
  940.         mBlockSamples = block;
  941.     }
  942.  
  943.     void SetIgnoreTimestamps(bool enabled, uint32 timeBase) {
  944.         mIgnoreTimestamps = enabled;
  945.         mTimeBase = timeBase;
  946.     }
  947.  
  948.     // IUnknown
  949.  
  950.     HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject) {
  951.         if (iid == IID_IUnknown) {
  952.             *ppvObject = static_cast<IUnknown *>(this);
  953.             AddRef();
  954.             return S_OK;
  955.         } else if (iid == IID_ISampleGrabberCB) {
  956.             *ppvObject = static_cast<ISampleGrabberCB *>(this);
  957.             AddRef();
  958.             return S_OK;
  959.         }
  960.  
  961.         *ppvObject = NULL;
  962.         return E_NOINTERFACE;
  963.     }
  964.  
  965.     ULONG __stdcall AddRef() {
  966.         return ++mRefCount;
  967.     }
  968.  
  969.     ULONG __stdcall Release() {
  970.         int rv = --mRefCount;
  971.  
  972.         if (!rv)
  973.             delete this;
  974.  
  975.         return (ULONG)rv;
  976.     }
  977.  
  978.     // ISampleGrabberCB
  979.  
  980.     HRESULT __stdcall BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen) {
  981.         return E_FAIL;
  982.     }
  983. };
  984.  
  985. class VDCapDevDSVideoCallback : public VDCapDevDSCallback {
  986. public:
  987.     VDCapDevDSVideoCallback(IVDCaptureDSCallback *pCB)
  988.         : VDCapDevDSCallback(pCB)
  989.         , mChannel(0)
  990.         , mVCallback("DSVideo")
  991.     {
  992.     }
  993.  
  994.     void SetChannel(int chan) { mChannel = chan; }
  995.     void SetFrameCount(int count) { mFrameCount = count; }
  996.     int GetFrameCount() const { return mFrameCount; }
  997.  
  998.     HRESULT __stdcall SampleCB(double SampleTime, IMediaSample *pSample) {
  999.         BYTE *pData;
  1000.         HRESULT hr;
  1001.  
  1002.         if (mBlockSamples)
  1003.             return S_OK;
  1004.  
  1005.         mVCallback.Begin(0xe0e0e0, "VC");
  1006.         if (mpCallback->CapTryEnterCriticalSection()) {
  1007.             // retrieve sample pointer
  1008.             hr = pSample->GetPointer(&pData);
  1009.             if (FAILED(hr)) {
  1010.                 mpCallback->CapLeaveCriticalSection();
  1011.                 mVCallback.End();
  1012.                 return hr;
  1013.             }
  1014.  
  1015.             // retrieve times
  1016.             __int64 t1, t2;
  1017.             if (mIgnoreTimestamps) {
  1018.                 t1 = (VDGetAccurateTick() - mTimeBase) * 1000;
  1019.             } else {
  1020.                 hr = pSample->GetTime(&t1, &t2);
  1021.                 if (FAILED(hr))
  1022.                     t1 = t2 = -1;
  1023.                 else
  1024.                     t1 = (t1+5)/10;
  1025.             }
  1026.  
  1027.             mpCallback->CapProcessData(mChannel, pData, pSample->GetActualDataLength(), t1, S_OK == pSample->IsSyncPoint());
  1028.             ++mFrameCount;
  1029.  
  1030.             mpCallback->CapLeaveCriticalSection();
  1031.         }
  1032.         mVCallback.End();
  1033.  
  1034.         return S_OK;
  1035.     }
  1036.  
  1037. protected:
  1038.     int mChannel;
  1039.     VDAtomicInt mFrameCount;
  1040.     VDRTProfileChannel mVCallback;
  1041. };
  1042.  
  1043. class VDCapDevDSAudioCallback : public VDCapDevDSCallback {
  1044. public:
  1045.     VDCapDevDSAudioCallback(IVDCaptureDSCallback *pCB)
  1046.         : VDCapDevDSCallback(pCB)
  1047.         , mChannel(1)
  1048.         , mACallback("DSAudio")
  1049.     {
  1050.     }
  1051.  
  1052.     void SetChannel(int chan) { mChannel = chan; }
  1053.  
  1054.     HRESULT __stdcall SampleCB(double SampleTime, IMediaSample *pSample) {
  1055.         BYTE *pData;
  1056.         HRESULT hr;
  1057.  
  1058.         if (mBlockSamples)
  1059.             return S_OK;
  1060.  
  1061.         mACallback.Begin(0xe0e0e0, "AC");
  1062.         if (mpCallback->CapTryEnterCriticalSection()) {
  1063.             // retrieve sample pointer
  1064.             hr = pSample->GetPointer(&pData);
  1065.             if (FAILED(hr)) {
  1066.                 mpCallback->CapLeaveCriticalSection();
  1067.                 mACallback.End();
  1068.                 return hr;
  1069.             }
  1070.  
  1071.             // Retrieve times. Note that if no clock is set, this will fail.
  1072.             REFERENCE_TIME t1, t2;
  1073.             hr = pSample->GetTime(&t1, &t2);
  1074.             if (FAILED(hr))
  1075.                 t1 = t2 = -1;
  1076.             else
  1077.                 t1 = (t1+5)/10;
  1078.  
  1079.             mpCallback->CapProcessData(mChannel, pData, pSample->GetActualDataLength(), t1, S_OK == pSample->IsSyncPoint());
  1080.             mpCallback->CapLeaveCriticalSection();
  1081.         }
  1082.         mACallback.End();
  1083.  
  1084.         return S_OK;
  1085.     }
  1086.  
  1087. protected:
  1088.     int mChannel;
  1089.     VDRTProfileChannel mACallback;
  1090. };
  1091.  
  1092. ///////////////////////////////////////////////////////////////////////////
  1093. //
  1094. //  capture driver: DirectShow
  1095. //
  1096. ///////////////////////////////////////////////////////////////////////////
  1097.  
  1098. class VDCaptureDriverDS : public IVDCaptureDriver, public IVDCaptureDriverDShow, public IVDCaptureDSCallback {
  1099.     VDCaptureDriverDS(const VDCaptureDriverDS&);
  1100.     VDCaptureDriverDS& operator=(const VDCaptureDriverDS&);
  1101. public:
  1102.     VDCaptureDriverDS(IMoniker *pVideoDevice);
  1103.     ~VDCaptureDriverDS();
  1104.  
  1105.     void    *AsInterface(uint32 id);
  1106.  
  1107.     bool    Init(VDGUIHandle hParent);
  1108.     void    Shutdown();
  1109.  
  1110.     void    SetCallback(IVDCaptureDriverCallback *pCB);
  1111.  
  1112.     void    LockUpdates();
  1113.     void    UnlockUpdates();
  1114.  
  1115.     bool    IsHardwareDisplayAvailable();
  1116.  
  1117.     void    SetDisplayMode(nsVDCapture::DisplayMode m);
  1118.     nsVDCapture::DisplayMode        GetDisplayMode();
  1119.  
  1120.     void    SetDisplayRect(const vdrect32& r);
  1121.     vdrect32    GetDisplayRectAbsolute();
  1122.     void    SetDisplayVisibility(bool vis);
  1123.  
  1124.     void    SetFramePeriod(sint32 framePeriod100nsUnits);
  1125.     sint32  GetFramePeriod();
  1126.  
  1127.     uint32  GetPreviewFrameCount();
  1128.  
  1129.     bool    GetVideoFormat(vdstructex<BITMAPINFOHEADER>& vformat);
  1130.     bool    SetVideoFormat(const BITMAPINFOHEADER *pbih, uint32 size);
  1131.  
  1132.     bool    SetTunerChannel(int channel);
  1133.     int     GetTunerChannel();
  1134.     bool    GetTunerChannelRange(int& minChannel, int& maxChannel);
  1135.     uint32  GetTunerFrequencyPrecision();
  1136.     uint32  GetTunerExactFrequency();
  1137.     bool    SetTunerExactFrequency(uint32 freq);
  1138.     nsVDCapture::TunerInputMode GetTunerInputMode();
  1139.     void    SetTunerInputMode(nsVDCapture::TunerInputMode tunerMode);
  1140.  
  1141.     int     GetAudioDeviceCount();
  1142.     const wchar_t *GetAudioDeviceName(int idx);
  1143.     bool    SetAudioDevice(int idx);
  1144.     int     GetAudioDeviceIndex();
  1145.     bool    IsAudioDeviceIntegrated(int idx);
  1146.  
  1147.     int     GetVideoSourceCount();
  1148.     const wchar_t *GetVideoSourceName(int idx);
  1149.     bool    SetVideoSource(int idx);
  1150.     int     GetVideoSourceIndex();
  1151.  
  1152.     int     GetAudioSourceCount();
  1153.     const wchar_t *GetAudioSourceName(int idx);
  1154.     bool    SetAudioSource(int idx);
  1155.     int     GetAudioSourceIndex();
  1156.  
  1157.     int     GetAudioSourceForVideoSource(int idx);
  1158.  
  1159.     int     GetAudioInputCount();
  1160.     const wchar_t *GetAudioInputName(int idx);
  1161.     bool    SetAudioInput(int idx);
  1162.     int     GetAudioInputIndex();
  1163.  
  1164.     bool    IsAudioCapturePossible();
  1165.     bool    IsAudioCaptureEnabled();
  1166.     bool    IsAudioPlaybackPossible();
  1167.     bool    IsAudioPlaybackEnabled();
  1168.     void    SetAudioCaptureEnabled(bool b);
  1169.     void    SetAudioAnalysisEnabled(bool b);
  1170.     void    SetAudioPlaybackEnabled(bool b);
  1171.  
  1172.     void    GetAvailableAudioFormats(std::list<vdstructex<WAVEFORMATEX> >& aformats);
  1173.  
  1174.     bool    GetAudioFormat(vdstructex<WAVEFORMATEX>& aformat);
  1175.     bool    SetAudioFormat(const WAVEFORMATEX *pwfex, uint32 size);
  1176.  
  1177.     bool    IsDriverDialogSupported(nsVDCapture::DriverDialog dlg);
  1178.     void    DisplayDriverDialog(nsVDCapture::DriverDialog dlg);
  1179.  
  1180.     bool    IsPropertySupported(uint32 id);
  1181.     sint32  GetPropertyInt(uint32 id, bool *pAutomatic);
  1182.     void    SetPropertyInt(uint32 id, sint32 value, bool automatic);
  1183.     void    GetPropertyInfoInt(uint32 id, sint32& minVal, sint32& maxVal, sint32& step, sint32& defaultVal, bool& automatic, bool& manual);
  1184.  
  1185.     bool    CaptureStart();
  1186.     void    CaptureStop();
  1187.     void    CaptureAbort();
  1188.  
  1189. public:
  1190.     bool    GetDisableClockForPreview();
  1191.     void    SetDisableClockForPreview(bool enabled);
  1192.  
  1193.     bool    GetForceAudioRendererClock();
  1194.     void    SetForceAudioRendererClock(bool enabled);
  1195.  
  1196.     bool    GetIgnoreVideoTimestamps();
  1197.     void    SetIgnoreVideoTimestamps(bool enabled);
  1198.  
  1199. protected:
  1200.     struct InputSource;
  1201.     typedef std::vector<InputSource>    InputSources;
  1202.  
  1203.     void    UpdateDisplay();
  1204.     bool    StartGraph();
  1205.     bool    StopGraph();
  1206.     bool    BuildPreviewGraph();
  1207.     bool    BuildCaptureGraph();
  1208.     bool    BuildGraph(bool bNeedCapture, bool bEnableAudio);
  1209.     void    TearDownGraph();
  1210.     void    CheckForWindow();
  1211.     void    CheckForChanges();
  1212.     bool    DisplayPropertyPages(IUnknown *ptr, HWND hwndParent, const GUID *pDisablePages, int nDisablePages);
  1213.     int     EnumerateCrossbarSources(InputSources& sources, IAMCrossbar *pCrossbar, int output);
  1214.     int     UpdateCrossbarSource(InputSources& sources, IAMCrossbar *pCrossbar, int output);
  1215.     void    DoEvents();
  1216.  
  1217.     static LRESULT CALLBACK StaticMessageSinkWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  1218.     LRESULT MessageSinkWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  1219.  
  1220.     bool CapTryEnterCriticalSection();
  1221.     void CapProcessData(int stream, const void *data, uint32 size, sint64 timestamp, bool key);
  1222.     void CapLeaveCriticalSection();
  1223.  
  1224.     IVDCaptureDriverCallback    *mpCB;
  1225.     DisplayMode         mDisplayMode;
  1226.  
  1227.     typedef std::vector<std::pair<IMonikerPtr, VDStringW> > tDeviceVector;
  1228.  
  1229.     IMonikerPtr         mVideoDeviceMoniker;
  1230.     tDeviceVector       mAudioDevices;
  1231.     int                 mAudioDeviceIndex;
  1232.  
  1233.     // Some essentials for the filter graph.
  1234.     IFilterGraphPtr             mpGraph;
  1235.     IGraphBuilderPtr            mpGraphBuilder;
  1236.     ICaptureGraphBuilder2Ptr    mpCapGraphBuilder2;
  1237.     IMediaControlPtr            mpGraphControl;
  1238.     IMediaEventExPtr            mpMediaEventEx;
  1239.  
  1240.     // Pointers to filters and pins in the graph.
  1241.     IBaseFilterPtr      mpCapFilt;
  1242.     IBaseFilterPtr      mpCapSplitFilt;         // DV Splitter, if INTERLEAVED is detected
  1243.     IBaseFilterPtr      mpCapTransformFilt;     //
  1244.     IPinPtr             mpShadowedRealCapturePin;       // the one on the cap filt
  1245.     IPinPtr             mpRealCapturePin;       // the one on the cap filt, or a transform filter if present
  1246.     IPinPtr             mpRealPreviewPin;       // the one on the cap filt
  1247.     IPinPtr             mpRealAudioPin;         // the one on the cap filt
  1248.     IPinPtr             mpCapFiltVideoPortPin;  // on cap filt
  1249.     IPinPtr             mpAudioPin;
  1250.     IAMAnalogVideoDecoderPtr mpAnalogVideoDecoder;
  1251.     IAMCrossbarPtr      mpCrossbar;
  1252.     IAMCrossbarPtr      mpCrossbar2;
  1253.     IAMTunerPtr         mpTuner;
  1254.     IAMTVTunerPtr       mpTVTuner;
  1255.     IAMVideoProcAmpPtr  mpVideoProcAmp;
  1256.     IVideoWindowPtr     mpVideoWindow;
  1257.     typedef std::list<IVideoWindowPtr> VideoWindows;
  1258.     VideoWindows        mVideoWindows;
  1259.     IQualProp           *mpVideoQualProp;
  1260.  
  1261.     typedef std::list<IBaseFilterPtr> ExtraFilters;
  1262.     ExtraFilters        mExtraFilters;
  1263.  
  1264.     // Video formats.
  1265.     typedef std::list<VDAMMediaType> VideoFormats;
  1266.     VideoFormats mPreferredVideoFormats;
  1267.  
  1268.     // Audio filter.  We may not have one of these, actually.
  1269.     IBaseFilterPtr      mpAudioCapFilt;
  1270.  
  1271.     // Audio inputs
  1272.     struct InputSource {
  1273.         int                     mCrossbarPin;
  1274.         int                     mPhysicalType;
  1275.         VDStringW               mName;
  1276.  
  1277.         InputSource(int crossbarInputPin, int physType, const VDStringW& name) : mCrossbarPin(crossbarInputPin), mPhysicalType(physType), mName(name) {}
  1278.     };
  1279.  
  1280.     struct AudioInput {
  1281.         IAMAudioInputMixerPtr   mMixerEnable;
  1282.         VDStringW               mName;
  1283.  
  1284.         AudioInput(IAMAudioInputMixer *pMixerEnable, const VDStringW& name) : mMixerEnable(pMixerEnable), mName(name) {}
  1285.     };
  1286.  
  1287.     typedef std::vector<AudioInput> AudioInputs;
  1288.  
  1289.     InputSources    mVideoSources;
  1290.     int             mCurrentVideoSource;
  1291.     InputSources    mAudioSources;
  1292.     int             mCurrentAudioSource;
  1293.     AudioInputs mAudioInputs;
  1294.     int         mCurrentAudioInput;
  1295.     IAMCrossbar *mpAudioCrossbar;       // This aliases either mpCrossbar or mpCrossbar2.
  1296.     IAMCrossbar *mpVideoCrossbar;       // This aliases either mpCrossbar or mpCrossbar2.
  1297.     int         mAudioCrossbarOutput;
  1298.     int         mVideoCrossbarOutput;
  1299.  
  1300.     // These have to be nullified when we destroy parts of the graph.
  1301.     ISampleGrabberPtr   mpVideoGrabber;
  1302.     ISampleGrabberPtr   mpAudioGrabber;
  1303.  
  1304.     IAMVfwCaptureDialogsPtr     mpVFWDialogs;
  1305.     IAMStreamConfigPtr          mpVideoConfigCap;
  1306.     IAMStreamConfigPtr          mpVideoConfigPrv;
  1307.     IAMStreamConfigPtr          mpAudioConfig;
  1308.  
  1309.     // Callbacks
  1310.     VDCapDevDSVideoCallback     mVideoCallback;
  1311.     VDCapDevDSAudioCallback     mAudioCallback;
  1312.     VDSemaphore                 mGraphStateLock;
  1313.  
  1314.     // Misc flags & state
  1315.     DWORD mdwRegisterGraph;             // Used to register filter graph in ROT for graphedit
  1316.     HWND mhwndParent;                   // Parent window
  1317.     HWND mhwndEventSink;                // Our dummy window used as DS event sink
  1318.     vdrect32 mDisplayRect;
  1319.  
  1320.     uint32  mUpdateLocks;
  1321.     bool    mbUpdatePending;
  1322.     bool    mbStartPending;
  1323.  
  1324.     bool mbAudioCaptureEnabled;
  1325.     bool mbAudioAnalysisEnabled;
  1326.     bool mbAudioPlaybackEnabled;
  1327.     bool mbGraphActive;                 // true if the graph is currently running
  1328.     bool mbGraphHasPreview;             // true if the graph has separate capture and preview pins
  1329.     bool mbDisplayVisible;
  1330.     bool mbForceAudioRendererClock;     // force the audio renderer to be the clock when present
  1331.     bool mbDisableClockForPreview;      // disable the clock by default
  1332.     bool mbIgnoreVideoTimestamps;
  1333.  
  1334.     // state tracking for reporting changes
  1335.     sint32      mTrackedFramePeriod;
  1336.     vdstructex<BITMAPINFOHEADER>    mTrackedVideoFormat;
  1337.  
  1338.     vdstructex<WAVEFORMATEX>    mAudioFormat;
  1339.  
  1340.     uint32  mCaptureStart;
  1341.  
  1342.     VDAtomicInt mCaptureStopQueued;
  1343.  
  1344.     HANDLE  mCaptureThread;
  1345.     VDAtomicPtr<MyError>    mpCaptureError;
  1346.  
  1347.     static ATOM sMsgSinkClass;
  1348. };
  1349.  
  1350. ATOM VDCaptureDriverDS::sMsgSinkClass;
  1351.  
  1352. VDCaptureDriverDS::VDCaptureDriverDS(IMoniker *pVideoDevice)
  1353.     : mpCB(NULL)
  1354.     , mDisplayMode(kDisplayNone)
  1355.     , mVideoDeviceMoniker(pVideoDevice)
  1356.     , mAudioDeviceIndex(0)
  1357.     , mpVideoQualProp(NULL)
  1358.     , mdwRegisterGraph(0)
  1359.     , mCurrentVideoSource(-1)
  1360.     , mCurrentAudioSource(-1)
  1361.     , mCurrentAudioInput(-1)
  1362.     , mpAudioCrossbar(NULL)
  1363.     , mpVideoCrossbar(NULL)
  1364.     , mVideoCallback(this)
  1365.     , mAudioCallback(this)
  1366.     , mGraphStateLock(2)
  1367.     , mhwndParent(NULL)
  1368.     , mhwndEventSink(NULL)
  1369.     , mDisplayRect(0,0,0,0)
  1370.     , mUpdateLocks(0)
  1371.     , mbUpdatePending(false)
  1372.     , mbStartPending(false)
  1373.     , mbAudioCaptureEnabled(true)
  1374.     , mbAudioAnalysisEnabled(false)
  1375.     , mbAudioPlaybackEnabled(false)
  1376.     , mbGraphActive(false)
  1377.     , mbGraphHasPreview(false)
  1378.     , mbDisplayVisible(false)
  1379.     , mbDisableClockForPreview(false)
  1380.     , mbForceAudioRendererClock(true)
  1381.     , mTrackedFramePeriod(0)
  1382.     , mCaptureStart(0)
  1383.     , mCaptureStopQueued(0)
  1384.     , mCaptureThread(NULL)
  1385.     , mpCaptureError(NULL)
  1386. {
  1387. }
  1388.  
  1389. VDCaptureDriverDS::~VDCaptureDriverDS() {
  1390.     Shutdown();
  1391. }
  1392.  
  1393. void *VDCaptureDriverDS::AsInterface(uint32 id) {
  1394.     if (id == IVDCaptureDriverDShow::kTypeID)
  1395.         return static_cast<IVDCaptureDriverDShow *>(this);
  1396.     return NULL;
  1397. }
  1398.  
  1399. void VDCaptureDriverDS::SetCallback(IVDCaptureDriverCallback *pCB) {
  1400.     mpCB = pCB;
  1401. }
  1402.  
  1403. bool VDCaptureDriverDS::Init(VDGUIHandle hParent) {
  1404.     mhwndParent = (HWND)hParent;
  1405.  
  1406.     HRESULT hr;
  1407.  
  1408.     if (!sMsgSinkClass) {
  1409.         WNDCLASS wc = { 0, StaticMessageSinkWndProc, 0, sizeof(void *), g_hInst, NULL, NULL, NULL, NULL, "Riza DirectShow event sink" };
  1410.  
  1411.         sMsgSinkClass = RegisterClass(&wc);
  1412.  
  1413.         if (!sMsgSinkClass)
  1414.             return false;
  1415.     }
  1416.  
  1417.     // Create message sink.
  1418.  
  1419.     if (!(mhwndEventSink = CreateWindow((LPCTSTR)sMsgSinkClass, "", WS_POPUP, 0, 0, 0, 0, mhwndParent, NULL, g_hInst, this)))
  1420.         return false;
  1421.  
  1422.     // Create a filter graph manager.
  1423.     DS_VERIFY(mpGraph.CreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER), "create filter graph manager");
  1424.     DS_VERIFY(mpGraph->QueryInterface(IID_IGraphBuilder, (void **)~mpGraphBuilder), "find graph builder if");
  1425.  
  1426.     // Create a capture filter graph builder (we're lazy).
  1427.  
  1428.     DS_VERIFY(mpCapGraphBuilder2.CreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER), "create filter graph builder");
  1429.  
  1430.     mpCapGraphBuilder2->SetFiltergraph(mpGraphBuilder);
  1431.  
  1432.     AddToRot(mpGraphBuilder, &mdwRegisterGraph);
  1433.  
  1434.     VDDEBUG("ROT entry: %x   PID: %x\n", mdwRegisterGraph, GetCurrentProcessId());
  1435.  
  1436.     // Try to find the event sink interface.
  1437.     if (SUCCEEDED(mpGraphBuilder->QueryInterface(IID_IMediaEventEx,(void **)~mpMediaEventEx))) {
  1438.         mpMediaEventEx->SetNotifyWindow((OAHWND)mhwndEventSink, WM_APP, 0);
  1439.         mpMediaEventEx->CancelDefaultHandling(EC_VIDEO_SIZE_CHANGED);
  1440.     }
  1441.  
  1442.     // Attempt to instantiate the capture filter.
  1443.  
  1444.     DS_VERIFY(mVideoDeviceMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void **)~mpCapFilt), "create capture filter");
  1445.     DS_VERIFY(mpGraphBuilder->AddFilter(mpCapFilt, L"Capture device"), "add capture filter");
  1446.  
  1447.     // Find the capture pin first.  If we don't have one of these, we
  1448.     // might as well give up.
  1449.     bool interleaved = true;
  1450.  
  1451.     hr = mpCapGraphBuilder2->FindPin(mpCapFilt, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, TRUE, 0, ~mpRealCapturePin);
  1452.     if (SUCCEEDED(hr)) {
  1453.         // We got one, so attach a DV splitter now.
  1454.         DS_VERIFY(mpCapSplitFilt.CreateInstance(CLSID_DVSplitter, NULL, CLSCTX_INPROC_SERVER), "create DV splitter");
  1455.         DS_VERIFY(mpGraphBuilder->AddFilter(mpCapSplitFilt, L"DV splitter"), "add DV splitter");
  1456.  
  1457.         IPinPtr pCapSplitIn;
  1458.         IPinPtr pCapSplitOutVideo;
  1459.         IPinPtr pCapSplitOutAudio;
  1460.         DS_VERIFY(mpCapGraphBuilder2->FindPin(mpCapSplitFilt, PINDIR_INPUT, NULL, NULL, TRUE, 0, ~pCapSplitIn), "find DV splitter input");
  1461.         DS_VERIFY(mpGraphBuilder->Connect(mpRealCapturePin, pCapSplitIn), "connect capture -> dv splitter");
  1462.  
  1463.         DS_VERIFY(mpCapGraphBuilder2->FindPin(mpCapSplitFilt, PINDIR_OUTPUT, NULL, &MEDIATYPE_Video, TRUE, 0, ~pCapSplitOutVideo), "find DV splitter video output");
  1464.         DS_VERIFY(mpCapGraphBuilder2->FindPin(mpCapSplitFilt, PINDIR_OUTPUT, NULL, &MEDIATYPE_Audio, TRUE, 0, ~pCapSplitOutAudio), "find DV splitter audio output");
  1465.  
  1466.         // Treat the outputs of the DV splitter as the "real" audio and video capture pins.
  1467.         mpRealCapturePin = pCapSplitOutVideo;
  1468.         mpRealAudioPin = pCapSplitOutAudio;
  1469.     } else {
  1470.         hr = mpCapGraphBuilder2->FindPin(mpCapFilt, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, TRUE, 0, ~mpRealCapturePin);
  1471.  
  1472.         DS_VERIFY(hr, "find capture pin");
  1473.  
  1474.         interleaved = false;
  1475.     }
  1476.  
  1477.     // If we have the transform filter, insert it inline now and make its output pin
  1478.     // the "capture" pin.
  1479.     VDRegistryAppKey key("Hidden features");
  1480.     VDStringW name;
  1481.  
  1482.     if (key.getString("CapDShow: Transform filter name", name)) {
  1483.         IClassFactoryPtr pCF;
  1484.         hr = CoGetObject(name.c_str(), NULL, IID_IBaseFilter, (void **)~mpCapTransformFilt);
  1485.         if (SUCCEEDED(hr)) {
  1486.             IPinPtr pPinTIn, pPinTOut;
  1487.             DS_VERIFY(mpGraphBuilder->AddFilter(mpCapTransformFilt, L"Video transform"), "add transform filter");
  1488.             DS_VERIFY(mpCapGraphBuilder2->FindPin(mpCapTransformFilt, PINDIR_INPUT, NULL, NULL, TRUE, 0, ~pPinTIn), "find transform filter input");
  1489.             DS_VERIFY(mpCapGraphBuilder2->FindPin(mpCapTransformFilt, PINDIR_OUTPUT, NULL, NULL, TRUE, 0, ~pPinTOut), "find transform filter output");
  1490.             DS_VERIFY(mpGraphBuilder->Connect(mpRealCapturePin, pPinTIn), "connect capture -> transform");
  1491.             mpShadowedRealCapturePin = mpRealCapturePin;
  1492.             mpRealCapturePin = pPinTOut;
  1493.         }
  1494.     }
  1495.  
  1496.     // Look for a preview pin.  It's actually likely that we won't get
  1497.     // one if someone has a USB webcam, so we have to be prepared for
  1498.     // it.
  1499.     hr = mpCapGraphBuilder2->FindPin(mpCapFilt, PINDIR_OUTPUT, &PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, TRUE, 0, ~mpRealPreviewPin);
  1500.     mbGraphHasPreview = SUCCEEDED(hr);
  1501.  
  1502.     // Enumerate video formats from the capture pin.
  1503.     IEnumMediaTypesPtr pEnum;
  1504.     if (SUCCEEDED(mpRealCapturePin->EnumMediaTypes(~pEnum))) {
  1505.         AM_MEDIA_TYPE *pMediaType;
  1506.         for(;;) {
  1507.             HRESULT hr = pEnum->Next(1, &pMediaType, NULL);
  1508.  
  1509.             if (hr == VFW_E_ENUM_OUT_OF_SYNC) {
  1510.                 mPreferredVideoFormats.clear();
  1511.                 if (FAILED(pEnum->Reset()))
  1512.                     break;
  1513.                 continue;
  1514.             }
  1515.  
  1516.             if (hr != S_OK)
  1517.                 break;
  1518.  
  1519.             if (pMediaType->majortype == MEDIATYPE_Video && pMediaType->formattype == FORMAT_VideoInfo
  1520.                 && pMediaType->cbFormat >= sizeof(VIDEOINFOHEADER)) {
  1521.  
  1522.                 mPreferredVideoFormats.push_back(*pMediaType);
  1523.             }
  1524.  
  1525.             RizaDeleteMediaType(pMediaType);
  1526.         }
  1527.     }
  1528.  
  1529.     // Look for an audio pin. We may need to attach a null renderer to
  1530.     // it for smooth previews.
  1531.     if (!interleaved)
  1532.         hr = mpCapGraphBuilder2->FindPin(mpCapFilt, PINDIR_OUTPUT, NULL, &MEDIATYPE_Audio, TRUE, 0, ~mpRealAudioPin);
  1533.  
  1534.     // Get video format configurator
  1535.  
  1536.     hr = mpCapGraphBuilder2->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, mpCapFilt, IID_IAMStreamConfig, (void **)~mpVideoConfigCap);
  1537.  
  1538.     if (FAILED(hr))
  1539.         hr = mpCapGraphBuilder2->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, mpCapFilt, IID_IAMStreamConfig, (void **)~mpVideoConfigCap);
  1540.  
  1541.     DS_VERIFY(hr, "find video format config if");
  1542.  
  1543.     hr = mpCapGraphBuilder2->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Interleaved, mpCapFilt, IID_IAMStreamConfig, (void **)~mpVideoConfigPrv);
  1544.  
  1545.     if (FAILED(hr))
  1546.         hr = mpCapGraphBuilder2->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, mpCapFilt, IID_IAMStreamConfig, (void **)~mpVideoConfigPrv);
  1547.  
  1548.     // Look for a video port pin. We _HAVE_ to render this if it exists; otherwise,
  1549.     // the ATI All-in-Wonder driver can lock on a wait in kernel mode and zombie
  1550.     // our process. And no, a Null Renderer doesn't work. It's OK for this to fail.
  1551.  
  1552.     hr = mpCapGraphBuilder2->FindPin(mpCapFilt, PINDIR_OUTPUT, &PIN_CATEGORY_VIDEOPORT, NULL, FALSE, 0, ~mpCapFiltVideoPortPin);
  1553.  
  1554.     // Check for VFW capture dialogs, TV tuner, and crossbar
  1555.  
  1556.     mpCapGraphBuilder2->FindInterface(NULL, NULL, mpCapFilt, IID_IAMVfwCaptureDialogs, (void **)~mpVFWDialogs);
  1557.     mpCapGraphBuilder2->FindInterface(NULL, NULL, mpCapFilt, IID_IAMCrossbar, (void **)~mpCrossbar);
  1558.     if (mpCrossbar) {
  1559.         IBaseFilterPtr pXFilt;
  1560.  
  1561.         if (SUCCEEDED(mpCrossbar->QueryInterface(IID_IBaseFilter, (void **)~pXFilt)))
  1562.             mpCapGraphBuilder2->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, pXFilt, IID_IAMCrossbar, (void **)~mpCrossbar2);
  1563.     }
  1564.  
  1565.     // Search for tuner interfaces. Note that IAMTVTuner inherits from IAMTuner.
  1566.     if (SUCCEEDED(mpCapGraphBuilder2->FindInterface(NULL, NULL, mpCapFilt, IID_IAMTVTuner, (void **)~mpTVTuner)))
  1567.         mpTuner = mpTVTuner;
  1568.     else
  1569.         mpCapGraphBuilder2->FindInterface(NULL, NULL, mpCapFilt, IID_IAMTuner, (void **)~mpTuner);
  1570.  
  1571.     mpCapGraphBuilder2->FindInterface(NULL, NULL, mpCapFilt, IID_IAMAnalogVideoDecoder, (void **)~mpAnalogVideoDecoder);
  1572.     mpCapGraphBuilder2->FindInterface(NULL, NULL, mpCapFilt, IID_IAMVideoProcAmp, (void **)~mpVideoProcAmp);
  1573.  
  1574.     // If there is at least one crossbar, examine the crossbars to see if we can spot
  1575.     // an audio input switch.
  1576.     mpAudioCrossbar = NULL;
  1577.     mpVideoCrossbar = NULL;
  1578.     for(int i=0; i<2; ++i) {
  1579.         IAMCrossbar *pCrossbar;
  1580.         if (i == 0)
  1581.             pCrossbar = mpCrossbar;
  1582.         else
  1583.             pCrossbar = mpCrossbar2;
  1584.  
  1585.         if (!pCrossbar)
  1586.             continue;
  1587.  
  1588.         long outputs, inputs;
  1589.         if (FAILED(pCrossbar->get_PinCounts(&outputs, &inputs)))
  1590.             continue;
  1591.  
  1592.         for(int pin=0; pin<outputs; ++pin) {
  1593.             long related;
  1594.             long phystype;
  1595.  
  1596.             if (FAILED(pCrossbar->get_CrossbarPinInfo(FALSE, pin, &related, &phystype)))
  1597.                 continue;
  1598.  
  1599.             if (!mpAudioCrossbar) {
  1600.                 if (phystype == PhysConn_Audio_AudioDecoder) {
  1601.                     mpAudioCrossbar = pCrossbar;
  1602.                     mAudioCrossbarOutput = pin;
  1603.                 }
  1604.             }
  1605.            
  1606.             if (!mpVideoCrossbar) {
  1607.                 if (phystype == PhysConn_Video_VideoDecoder) {
  1608.                     mpVideoCrossbar = pCrossbar;
  1609.                     mVideoCrossbarOutput = pin;
  1610.                 }
  1611.             }
  1612.         }
  1613.     }
  1614.  
  1615.     mCurrentAudioSource = -1;
  1616.     mCurrentVideoSource = -1;
  1617.     mVideoSources.clear();
  1618.     mAudioSources.clear();
  1619.  
  1620.     // Scan crossbars for sources
  1621.     if (mpAudioCrossbar)
  1622.         mCurrentAudioSource = EnumerateCrossbarSources(mAudioSources, mpAudioCrossbar, mAudioCrossbarOutput);
  1623.  
  1624.     if (mpVideoCrossbar)
  1625.         mCurrentVideoSource = EnumerateCrossbarSources(mVideoSources, mpVideoCrossbar, mVideoCrossbarOutput);
  1626.  
  1627.     DS_VERIFY(mpGraphBuilder->QueryInterface(IID_IMediaControl, (void **)~mpGraphControl), "find graph control interface");
  1628.  
  1629.     // Enumerate audio drivers. If the capture filter supports audio, make it audio
  1630.     // device zero.
  1631.     if (mpRealAudioPin) {
  1632.         FILTER_INFO fi;
  1633.  
  1634.         if (SUCCEEDED(mpCapFilt->QueryFilterInfo(&fi))) {
  1635.             mAudioDevices.push_back(tDeviceVector::value_type(NULL, VDStringW(fi.achName)));
  1636.  
  1637.             fi.pGraph->Release();
  1638.         }
  1639.     }
  1640.  
  1641.     Enumerate(mAudioDevices, CLSID_AudioInputDeviceCategory);
  1642.  
  1643. #if 0   // Disabled Dazzle hack for now.
  1644.     Enumerate(mAudioDevices, KSCATEGORY_CAPTURE);
  1645. #endif
  1646.  
  1647.     // Select the first audio device if there is one.
  1648.     mAudioDeviceIndex = -1;
  1649.     if (!mAudioDevices.empty())
  1650.         SetAudioDevice(0);
  1651.  
  1652.     UpdateDisplay();
  1653.  
  1654.     return true;
  1655. }
  1656.  
  1657. void VDCaptureDriverDS::Shutdown() {
  1658.     if (mpVideoQualProp) {
  1659.         mpVideoQualProp->Release();
  1660.         mpVideoQualProp = NULL;
  1661.     }
  1662.  
  1663.     if (mpVideoWindow) {
  1664.         mpVideoWindow->put_Visible(OAFALSE);
  1665.         mpVideoWindow->put_Owner(NULL);
  1666.         mpVideoWindow = NULL;
  1667.     }
  1668.  
  1669.     mVideoWindows.clear();
  1670.  
  1671.     if (mpGraphBuilder)
  1672.         TearDownGraph();
  1673.  
  1674.     // FIXME:   We need to tear down the filter graph manager, but to do so we
  1675.     //          need to manually kill the smart pointers.  This is not the
  1676.     //          cleanest way to wipe a graph and there's probably something
  1677.     //          wrong with doing it this way.
  1678.  
  1679.     mpAudioCapFilt      = NULL;
  1680.     mpAudioGrabber      = NULL;
  1681.     mpAudioConfig       = NULL;
  1682.  
  1683.     mpCapFilt           = NULL;
  1684.     mpCapSplitFilt      = NULL;
  1685.     mpCapTransformFilt  = NULL;
  1686.     mpShadowedRealCapturePin    = NULL;
  1687.     mpRealCapturePin    = NULL;
  1688.     mpRealPreviewPin    = NULL;
  1689.     mpCapFiltVideoPortPin   = NULL;
  1690.     mpRealAudioPin      = NULL;
  1691.     mpAudioPin          = NULL;
  1692.     mpAnalogVideoDecoder = NULL;
  1693.     mpCrossbar          = NULL;
  1694.     mpCrossbar2         = NULL;
  1695.     mpTuner             = NULL;
  1696.     mpTVTuner           = NULL;
  1697.     mpVideoProcAmp      = NULL;
  1698.     mpVideoGrabber      = NULL;
  1699.     mpVFWDialogs        = NULL;
  1700.     mpVideoConfigCap    = NULL;
  1701.     mpVideoConfigPrv    = NULL;
  1702.     mpMediaEventEx      = NULL;
  1703.     mpGraphBuilder              = NULL;
  1704.     mpCapGraphBuilder2      = NULL;
  1705.     mpGraphControl      = NULL;
  1706.  
  1707.     mpAudioCrossbar     = NULL;
  1708.     mpVideoCrossbar     = NULL;
  1709.  
  1710.     if (mhwndEventSink) {
  1711.         DestroyWindow(mhwndEventSink);
  1712.         mhwndEventSink = NULL;
  1713.     }
  1714.  
  1715.     mAudioDevices.clear();
  1716.     mAudioInputs.clear();
  1717.  
  1718.     if (mdwRegisterGraph) {
  1719.         RemoveFromRot(mdwRegisterGraph);
  1720.         mdwRegisterGraph = 0;
  1721.     }
  1722.  
  1723.     if (mCaptureThread) {
  1724.         CloseHandle(mCaptureThread);
  1725.         mCaptureThread = NULL;
  1726.     }
  1727.  
  1728.     if (MyError *e = mpCaptureError.xchg(NULL))
  1729.         delete e;
  1730. }
  1731.  
  1732. void VDCaptureDriverDS::LockUpdates() {
  1733.     ++mUpdateLocks;
  1734. }
  1735.  
  1736. void VDCaptureDriverDS::UnlockUpdates() {
  1737.     --mUpdateLocks;
  1738.     VDASSERT((int)mUpdateLocks >= 0);
  1739.  
  1740.     if (!mUpdateLocks) {
  1741.         if (mbUpdatePending)
  1742.             UpdateDisplay();
  1743.         else if (mbStartPending)
  1744.             StartGraph();
  1745.  
  1746.         mbUpdatePending = mbStartPending = false;
  1747.     }
  1748. }
  1749.  
  1750. bool VDCaptureDriverDS::IsHardwareDisplayAvailable() {
  1751.     return true;
  1752. }
  1753.  
  1754. void VDCaptureDriverDS::SetDisplayMode(nsVDCapture::DisplayMode mode) {
  1755.     if (mDisplayMode == mode)
  1756.         return;
  1757.  
  1758.     mDisplayMode = mode;
  1759.  
  1760.     if (mode == kDisplayNone) {
  1761.         TearDownGraph();
  1762.         return;
  1763.     }
  1764.  
  1765.     UpdateDisplay();
  1766. }
  1767.  
  1768. nsVDCapture::DisplayMode VDCaptureDriverDS::GetDisplayMode() {
  1769.     return mDisplayMode;
  1770. }
  1771.  
  1772. void VDCaptureDriverDS::SetDisplayRect(const vdrect32& r) {
  1773.     mDisplayRect = r;
  1774.  
  1775.     if (mpVideoWindow) {
  1776.         mpVideoWindow->put_Left(r.left);
  1777.         mpVideoWindow->put_Top(r.top);
  1778.         mpVideoWindow->put_Width(r.width());
  1779.         mpVideoWindow->put_Height(r.height());
  1780.     }
  1781. }
  1782.  
  1783. vdrect32 VDCaptureDriverDS::GetDisplayRectAbsolute() {
  1784.     return mDisplayRect;
  1785. }
  1786.  
  1787. void VDCaptureDriverDS::SetDisplayVisibility(bool vis) {
  1788.     if (mbDisplayVisible == vis)
  1789.         return;
  1790.  
  1791.     mbDisplayVisible = vis;
  1792.  
  1793.     if (mpVideoWindow)
  1794.         mpVideoWindow->put_Visible(vis ? OATRUE : OAFALSE);
  1795. }
  1796.  
  1797. void VDCaptureDriverDS::SetFramePeriod(sint32 framePeriod100nsUnits) {
  1798.     AM_MEDIA_TYPE *past;
  1799.     VDFraction pf;
  1800.     bool bRet = false;
  1801.  
  1802.     StopGraph();
  1803.  
  1804.     if (mpVideoConfigCap && SUCCEEDED(mpVideoConfigCap->GetFormat(&past))) {
  1805.         if (past->formattype == FORMAT_VideoInfo) {
  1806.             VIDEOINFOHEADER *pvih = (VIDEOINFOHEADER *)past->pbFormat;
  1807.  
  1808.             pvih->AvgTimePerFrame = framePeriod100nsUnits;
  1809.  
  1810.             bRet = SUCCEEDED(mpVideoConfigCap->SetFormat(past));
  1811.             VDASSERT(bRet);
  1812.         }
  1813.  
  1814.         RizaDeleteMediaType(past);
  1815.     }
  1816.  
  1817.     if (mpVideoConfigPrv && SUCCEEDED(mpVideoConfigPrv->GetFormat(&past))) {
  1818.         if (past->formattype == FORMAT_VideoInfo) {
  1819.             VIDEOINFOHEADER *pvih = (VIDEOINFOHEADER *)past->pbFormat;
  1820.  
  1821.             pvih->AvgTimePerFrame = framePeriod100nsUnits;
  1822.  
  1823.             bRet = SUCCEEDED(mpVideoConfigPrv->SetFormat(past));
  1824.             VDASSERT(bRet);
  1825.         }
  1826.  
  1827.         RizaDeleteMediaType(past);
  1828.     }
  1829.  
  1830.     CheckForChanges();
  1831.  
  1832.     VDDEBUG("Desired frame period = %u*100ns, actual = %u*100ns\n", framePeriod100nsUnits, GetFramePeriod());
  1833.  
  1834.     StartGraph();
  1835.  
  1836.     VDASSERT(bRet);
  1837. }
  1838.  
  1839. sint32 VDCaptureDriverDS::GetFramePeriod() {
  1840.     AM_MEDIA_TYPE *past;
  1841.     sint32 rate;
  1842.     bool bRet = false;
  1843.  
  1844.     if (SUCCEEDED(mpVideoConfigCap->GetFormat(&past))) {
  1845.         if (past->formattype == FORMAT_VideoInfo || past->formattype == FORMAT_MPEGVideo) {
  1846.             const VIDEOINFOHEADER *pvih = (const VIDEOINFOHEADER *)past->pbFormat;
  1847.  
  1848.             rate = VDClampToSint32(pvih->AvgTimePerFrame);
  1849.  
  1850.             bRet = true;
  1851.         } else if (past->formattype == FORMAT_VideoInfo2 || past->formattype == FORMAT_MPEG2Video) {
  1852.             const VIDEOINFOHEADER2 *pvih = (const VIDEOINFOHEADER2 *)past->pbFormat;
  1853.  
  1854.             rate = VDClampToSint32(pvih->AvgTimePerFrame);
  1855.  
  1856.             bRet = true;
  1857.         } else if (past->formattype == FORMAT_DvInfo) {
  1858.             const DVINFO& dvi = *(const DVINFO *)past->pbFormat;
  1859.  
  1860.             if (dvi.dwDVVAuxSrc & 0x200000)
  1861.                 rate = 400000;  // PAL
  1862.             else
  1863.                 rate = 333667;  // NTSC
  1864.  
  1865.             bRet = true;
  1866.         }
  1867.  
  1868.         RizaDeleteMediaType(past);
  1869.     }
  1870.  
  1871.     if (!bRet) {
  1872.         VDASSERT(false);
  1873.         return 10000000/15;
  1874.     }
  1875.  
  1876.     return rate;
  1877. }
  1878.  
  1879. uint32 VDCaptureDriverDS::GetPreviewFrameCount() {
  1880.     int framesDrawn;
  1881.  
  1882.     if (mDisplayMode == kDisplayAnalyze)
  1883.         return mVideoCallback.GetFrameCount();
  1884.     else if (mpVideoQualProp && SUCCEEDED(mpVideoQualProp->get_FramesDrawn(&framesDrawn)))
  1885.         return (uint32)framesDrawn;
  1886.  
  1887.     return 0;
  1888. }
  1889.  
  1890. bool VDCaptureDriverDS::GetVideoFormat(vdstructex<BITMAPINFOHEADER>& vformat) {
  1891.     AM_MEDIA_TYPE *pmt = NULL;
  1892.     // If the DV splitter is in use, we need to query what its video pin outputs and
  1893.     // not the capture filter itself.
  1894.     if (mpCapSplitFilt || mpCapTransformFilt) {
  1895.         IEnumMediaTypesPtr pEnum;
  1896.  
  1897.         if (SUCCEEDED(mpRealCapturePin->EnumMediaTypes(~pEnum))) {
  1898.             ULONG cFetched;
  1899.  
  1900.             if (S_OK == pEnum->Next(1, &pmt, &cFetched)) {
  1901.                 if (pmt->majortype == MEDIATYPE_Video
  1902.                     && pmt->formattype == FORMAT_VideoInfo) {
  1903.                     vformat.assign(&((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader, pmt->cbFormat - offsetof(VIDEOINFOHEADER, bmiHeader));
  1904.                     RizaDeleteMediaType(pmt);
  1905.                     return true;
  1906.                 }
  1907.  
  1908.                 RizaDeleteMediaType(pmt);
  1909.             }
  1910.         }
  1911.     } else if (SUCCEEDED(mpVideoConfigCap->GetFormat(&pmt))) {
  1912.         if (pmt->majortype == MEDIATYPE_Video
  1913.             && pmt->formattype == FORMAT_VideoInfo) {
  1914.             vformat.assign(&((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader, pmt->cbFormat - offsetof(VIDEOINFOHEADER, bmiHeader));
  1915.             RizaDeleteMediaType(pmt);
  1916.             return true;
  1917.         }
  1918.         RizaDeleteMediaType(pmt);
  1919.     }
  1920.  
  1921.     vformat.clear();
  1922.     return false;
  1923. }
  1924.  
  1925. bool VDCaptureDriverDS::SetVideoFormat(const BITMAPINFOHEADER *pbih, uint32 size) {
  1926.     vdstructex<VIDEOINFOHEADER> vhdr;
  1927.  
  1928.     vhdr.resize(offsetof(VIDEOINFOHEADER, bmiHeader) + size);
  1929.     memcpy(&vhdr->bmiHeader, pbih, size);
  1930.  
  1931.     vhdr->rcSource.left     = 0;
  1932.     vhdr->rcSource.top      = 0;
  1933.     vhdr->rcSource.right    = 0;
  1934.     vhdr->rcSource.bottom   = 0;
  1935.     vhdr->rcTarget          = vhdr->rcSource;
  1936.     vhdr->AvgTimePerFrame   = GetFramePeriod();
  1937.     vhdr->dwBitRate         = VDRoundToInt(pbih->biSizeImage * 80000000.0 / vhdr->AvgTimePerFrame);
  1938.     vhdr->dwBitErrorRate    = 0;
  1939.  
  1940.     AM_MEDIA_TYPE vformat;
  1941.  
  1942.     vformat.majortype           = MEDIATYPE_Video;
  1943.     vformat.subtype.Data1       = pbih->biCompression;
  1944.     vformat.subtype.Data2       = 0;
  1945.     vformat.subtype.Data3       = 0x0010;
  1946.     vformat.subtype.Data4[0]    = 0x80;
  1947.     vformat.subtype.Data4[1]    = 0x00;
  1948.     vformat.subtype.Data4[2]    = 0x00;
  1949.     vformat.subtype.Data4[3]    = 0xAA;
  1950.     vformat.subtype.Data4[4]    = 0x00;
  1951.     vformat.subtype.Data4[5]    = 0x38;
  1952.     vformat.subtype.Data4[6]    = 0x9B;
  1953.     vformat.subtype.Data4[7]    = 0x71;
  1954.     vformat.bFixedSizeSamples   = FALSE;
  1955.     vformat.bTemporalCompression = TRUE;
  1956.     vformat.lSampleSize         = 0;
  1957.     vformat.formattype          = FORMAT_VideoInfo;
  1958.     vformat.pUnk                = NULL;
  1959.     vformat.cbFormat            = vhdr.size();
  1960.     vformat.pbFormat            = (BYTE *)vhdr.data();
  1961.  
  1962.     // Check for one of the special subtypes....
  1963.  
  1964.     bool fixed = false;
  1965.  
  1966.     switch(pbih->biCompression) {
  1967.     case BI_RGB:
  1968.         if (pbih->biPlanes == 1) {
  1969.             if (pbih->biBitCount == 1) {
  1970.                 vformat.subtype = MEDIASUBTYPE_RGB1;
  1971.                 fixed = true;
  1972.             } else if (pbih->biBitCount == 4) {
  1973.                 vformat.subtype = MEDIASUBTYPE_RGB4;
  1974.                 fixed = true;
  1975.             } else if (pbih->biBitCount == 8) {
  1976.                 vformat.subtype = MEDIASUBTYPE_RGB8;
  1977.                 fixed = true;
  1978.             } else if (pbih->biBitCount == 16) {
  1979.                 vformat.subtype = MEDIASUBTYPE_RGB555;
  1980.                 fixed = true;
  1981.             } else if (pbih->biBitCount == 24) {
  1982.                 vformat.subtype = MEDIASUBTYPE_RGB24;
  1983.                 fixed = true;
  1984.             } else if (pbih->biBitCount == 32) {
  1985.                 vformat.subtype = MEDIASUBTYPE_RGB32;
  1986.                 fixed = true;
  1987.             }
  1988.         }
  1989.         break;
  1990.     case BI_BITFIELDS:
  1991.         {
  1992.             const BITMAPV4HEADER& v4hdr = *(const BITMAPV4HEADER *)pbih;
  1993.             DWORD a = 0;
  1994.  
  1995.             if (v4hdr.bV4Size >= sizeof(BITMAPV4HEADER))
  1996.                 a = v4hdr.bV4AlphaMask;
  1997.  
  1998.             const DWORD r = v4hdr.bV4RedMask;
  1999.             const DWORD g = v4hdr.bV4GreenMask;
  2000.             const DWORD b = v4hdr.bV4BlueMask;
  2001.             const int bits = v4hdr.bV4BitCount;
  2002.  
  2003.             switch(bits) {
  2004.             case 16:
  2005.                 if (r == 0x7c00 && g == 0x03e0 && b == 0x001f) {
  2006.                     if (!a) {
  2007.                         vformat.subtype = MEDIASUBTYPE_RGB555;
  2008.                         fixed = true;
  2009.                     } else if (a == 0x8000) {
  2010.                         vformat.subtype = MEDIASUBTYPE_ARGB1555;
  2011.                         fixed = true;
  2012.                     }
  2013.                 } else if (r == 0xf800 && g == 0x07e0 && b == 0x001f) {
  2014.                     if (!a) {
  2015.                         vformat.subtype = MEDIASUBTYPE_RGB565;
  2016.                         fixed = true;
  2017.                     }
  2018.                 }
  2019.                 break;
  2020.             case 24:
  2021.                 if (!a && r == 0xff0000 && g == 0xff00 && b == 0xff) {
  2022.                     vformat.subtype = MEDIASUBTYPE_RGB24;
  2023.                     fixed = true;
  2024.                 }
  2025.                 break;
  2026.             case 32:
  2027.                 if (r == 0xff0000 && g == 0xff00 && b == 0xff) {
  2028.                     if (!a) {
  2029.                         vformat.subtype = MEDIASUBTYPE_RGB32;
  2030.                         fixed = true;
  2031.                     } else if (a == 0xff000000) {
  2032.                         vformat.subtype = MEDIASUBTYPE_ARGB32;
  2033.                         fixed = true;
  2034.                     }
  2035.                 }
  2036.                 break;
  2037.             }
  2038.         }
  2039.         break;
  2040.     case MAKEFOURCC('A', 'Y', 'U', 'V'):
  2041.     case MAKEFOURCC('U', 'Y', 'V', 'Y'):
  2042.     case MAKEFOURCC('Y', '4', '1', '1'):
  2043.     case MAKEFOURCC('Y', '4', '1', 'P'):
  2044.     case MAKEFOURCC('Y', '2', '1', '1'):
  2045.     case MAKEFOURCC('Y', 'U', 'Y', '2'):
  2046.     case MAKEFOURCC('Y', 'V', 'Y', 'U'):
  2047.     case MAKEFOURCC('Y', 'U', 'Y', 'V'):
  2048.     case MAKEFOURCC('I', 'F', '0', '9'):
  2049.     case MAKEFOURCC('I', 'Y', 'U', 'V'):
  2050.     case MAKEFOURCC('Y', 'V', '1', '6'):
  2051.     case MAKEFOURCC('Y', 'V', '1', '2'):
  2052.     case MAKEFOURCC('Y', 'V', 'U', '9'):
  2053.         // The FOURCC encoding is already correct for these formats, but
  2054.         // we also happen to know that these are uncompressed formats.
  2055.         fixed = true;
  2056.         break;
  2057.     }
  2058.  
  2059.     if (fixed) {
  2060.         vformat.bFixedSizeSamples       = TRUE;
  2061.         vformat.bTemporalCompression    = FALSE;
  2062.         vformat.lSampleSize             = pbih->biSizeImage;
  2063.     } else {
  2064.         // We don't recognize the format, so iterate through the list of
  2065.         // preferred formats and see if one of the existing formats is
  2066.         // similar to what we have here. If so, copy the fields from
  2067.         // that format.
  2068.  
  2069.         VideoFormats::const_iterator it(mPreferredVideoFormats.begin()), itEnd(mPreferredVideoFormats.end());
  2070.  
  2071.         for(; it!=itEnd; ++it) {
  2072.             const AM_MEDIA_TYPE& amtype = *it;
  2073.             const VIDEOINFOHEADER& vhdr2 = *(const VIDEOINFOHEADER *)amtype.pbFormat;
  2074.  
  2075.             if (vhdr2.bmiHeader.biCompression == pbih->biCompression) {
  2076.                 vformat.bFixedSizeSamples       = amtype.bFixedSizeSamples;
  2077.                 vformat.bTemporalCompression    = amtype.bTemporalCompression;
  2078.                 vformat.lSampleSize             = amtype.lSampleSize;
  2079.  
  2080.                 // tweak the frame rate to be the same if they're within the margin
  2081.                 // of error (since we use 1us and not 100ns units)
  2082.                 __int64 deltaTime = vhdr->AvgTimePerFrame - vhdr2.AvgTimePerFrame;
  2083.                 if (-20 < deltaTime && deltaTime < 20)
  2084.                     vhdr->AvgTimePerFrame = vhdr2.AvgTimePerFrame;
  2085.  
  2086.                 break;
  2087.             }
  2088.         }
  2089.     }
  2090.  
  2091.     // tear down graph
  2092.     TearDownGraph();
  2093.  
  2094.     // check if format is compatible
  2095.     bool success = false;
  2096.     HRESULT hr = mpVideoConfigCap->SetFormat(&vformat);
  2097.     if (SUCCEEDED(hr)) {
  2098.         success = true;
  2099.     } else {
  2100.         VDDEBUG("Riza/CapDShow: Unable to set video format: [%s]\n", GetDXErrorName(hr));
  2101.     }
  2102.  
  2103.     // rebuild display
  2104.     UpdateDisplay();
  2105.  
  2106.     return success;
  2107. }
  2108.  
  2109. bool VDCaptureDriverDS::SetTunerChannel(int channel) {
  2110.     return mpTuner && SUCCEEDED(mpTuner->put_Channel(channel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT));
  2111. }
  2112.  
  2113. int VDCaptureDriverDS::GetTunerChannel() {
  2114.     long ch, videoSub, audioSub;
  2115.     if (mpTuner && SUCCEEDED(mpTuner->get_Channel(&ch, &videoSub, &audioSub))) {
  2116.         return ch;
  2117.     }
  2118.  
  2119.     return -1;
  2120. }
  2121.  
  2122. bool VDCaptureDriverDS::GetTunerChannelRange(int& minChannel, int& maxChannel) {
  2123.     long mn, mx;
  2124.  
  2125.     if (mpTuner && SUCCEEDED(mpTuner->ChannelMinMax(&mn, &mx))) {
  2126.         minChannel = mn;
  2127.         maxChannel = mx;
  2128.         return true;
  2129.     }
  2130.  
  2131.     return false;
  2132. }
  2133.  
  2134. namespace
  2135. {
  2136.     struct TunerInfo {
  2137.         bool Init(IUnknown *pTuner) {
  2138.             if (!pTuner)
  2139.                 return false;
  2140.  
  2141.             if (FAILED(pTuner->QueryInterface(IID_IKsPropertySet, (void **)~mpPropSet)))
  2142.                 return false;
  2143.  
  2144.             DWORD dwSupport;
  2145.             if (FAILED(mpPropSet->QuerySupported(PROPSETID_TUNER, KSPROPERTY_TUNER_MODE_CAPS, &dwSupport)))
  2146.                 return false;
  2147.  
  2148.             if (!(dwSupport & KSPROPERTY_SUPPORT_GET))
  2149.                 return false;
  2150.  
  2151.             DWORD actual;
  2152.  
  2153.             // uselessness of IKsPropertySet::Get() docs is astounding... InstanceData is supposed
  2154.             // to be the portion of the struct after sizeof(KSPROPERTY).
  2155.             memset(&mTunerModeCaps, 0, sizeof mTunerModeCaps);
  2156.             mTunerModeCaps.Mode = KSPROPERTY_TUNER_MODE_TV;
  2157.             if (FAILED(mpPropSet->Get(PROPSETID_TUNER, KSPROPERTY_TUNER_MODE_CAPS, (KSPROPERTY *)&mTunerModeCaps + 1, sizeof mTunerModeCaps - sizeof(KSPROPERTY), &mTunerModeCaps, sizeof mTunerModeCaps, &actual)))
  2158.                 return false;
  2159.  
  2160.             return true;
  2161.         }
  2162.  
  2163.         IKsPropertySetPtr mpPropSet;
  2164.         KSPROPERTY_TUNER_MODE_CAPS_S mTunerModeCaps;
  2165.     };
  2166. }
  2167.  
  2168. uint32 VDCaptureDriverDS::GetTunerFrequencyPrecision() {
  2169.     TunerInfo info;
  2170.  
  2171.     if (!info.Init(mpTuner))
  2172.         return 0;
  2173.  
  2174.     return info.mTunerModeCaps.TuningGranularity;
  2175. }
  2176.  
  2177. uint32 VDCaptureDriverDS::GetTunerExactFrequency() {
  2178.     TunerInfo info;
  2179.  
  2180.     if (!info.Init(mpTuner))
  2181.         return 0;
  2182.  
  2183.     KSPROPERTY_TUNER_FREQUENCY_S freq = {0};
  2184.     DWORD actual;
  2185.  
  2186.     if (FAILED(info.mpPropSet->Get(PROPSETID_TUNER, KSPROPERTY_TUNER_FREQUENCY, (KSPROPERTY *)&freq + 1, sizeof freq - sizeof(KSPROPERTY), &freq, sizeof freq, &actual)))
  2187.         return 0;
  2188.  
  2189.     return freq.Frequency;
  2190. }
  2191.  
  2192. bool VDCaptureDriverDS::SetTunerExactFrequency(uint32 freq) {
  2193.     TunerInfo info;
  2194.  
  2195.     if (!info.Init(mpTuner))
  2196.         return 0;
  2197.  
  2198.     if (freq < info.mTunerModeCaps.MinFrequency || freq > info.mTunerModeCaps.MaxFrequency)
  2199.         return 0;
  2200.  
  2201.     KSPROPERTY_TUNER_FREQUENCY_S freqData = {0};
  2202.     DWORD actual;
  2203.  
  2204.     if (FAILED(info.mpPropSet->Get(PROPSETID_TUNER, KSPROPERTY_TUNER_FREQUENCY, (KSPROPERTY *)&freq + 1, sizeof freqData - sizeof(KSPROPERTY), &freqData, sizeof freqData, &actual)))
  2205.         return 0;
  2206.  
  2207.     freqData.Frequency = freq;
  2208.     freqData.TuningFlags = KS_TUNER_TUNING_EXACT;
  2209.  
  2210.     HRESULT hr = info.mpPropSet->Set(PROPSETID_TUNER, KSPROPERTY_TUNER_FREQUENCY, (KSPROPERTY *)&freqData + 1, sizeof freqData - sizeof(KSPROPERTY), &freqData, sizeof freqData);
  2211.  
  2212.     return SUCCEEDED(hr);
  2213. }
  2214.  
  2215. nsVDCapture::TunerInputMode VDCaptureDriverDS::GetTunerInputMode() {
  2216.     if (!mpTVTuner)
  2217.         return kTunerInputUnknown;
  2218.  
  2219.     long index;
  2220.     HRESULT hr = mpTVTuner->get_ConnectInput(&index);
  2221.     if (FAILED(hr))
  2222.         return kTunerInputUnknown;
  2223.  
  2224.     TunerInputType type;
  2225.     hr = mpTVTuner->get_InputType(index, &type);
  2226.     if (FAILED(hr))
  2227.         return kTunerInputUnknown;
  2228.  
  2229.     switch(type) {
  2230.         case TunerInputCable:
  2231.             return kTunerInputCable;
  2232.         case TunerInputAntenna:
  2233.             return kTunerInputAntenna;
  2234.         default:
  2235.             return kTunerInputUnknown;
  2236.     }
  2237. }
  2238.  
  2239. void VDCaptureDriverDS::SetTunerInputMode(nsVDCapture::TunerInputMode tunerMode) {
  2240.     if (!mpTVTuner)
  2241.         return;
  2242.  
  2243.     long index;
  2244.     HRESULT hr = mpTVTuner->get_ConnectInput(&index);
  2245.     if (FAILED(hr))
  2246.         return;
  2247.  
  2248.     TunerInputType type;
  2249.  
  2250.     switch(tunerMode) {
  2251.         case kTunerInputAntenna:
  2252.         default:
  2253.             type = TunerInputAntenna;
  2254.             break;
  2255.  
  2256.         case kTunerInputCable:
  2257.             type = TunerInputCable;
  2258.             break;
  2259.     }
  2260.  
  2261.     mpTVTuner->put_InputType(index, type);
  2262. }
  2263.  
  2264. int VDCaptureDriverDS::GetAudioDeviceCount() {
  2265.     return mAudioDevices.size();
  2266. }
  2267.  
  2268. const wchar_t *VDCaptureDriverDS::GetAudioDeviceName(int idx) {
  2269.     if ((unsigned)idx >= mAudioDevices.size())
  2270.         return NULL;
  2271.  
  2272.     return mAudioDevices[idx].second.c_str();
  2273. }
  2274.  
  2275. bool VDCaptureDriverDS::SetAudioDevice(int idx) {
  2276.     if (idx == mAudioDeviceIndex)
  2277.         return true;
  2278.  
  2279.     if ((unsigned)idx >= mAudioDevices.size())
  2280.         idx = -1;
  2281.  
  2282.     StopGraph();
  2283.  
  2284.     // Kill an existing device.
  2285.     if (mpAudioCapFilt) {
  2286.         DestroySubgraph(mpGraphBuilder, mpAudioCapFilt, NULL, NULL);
  2287.         VDVERIFY(SUCCEEDED(mpGraphBuilder->RemoveFilter(mpAudioCapFilt)));
  2288.         mpAudioCapFilt = NULL;
  2289.     }
  2290.  
  2291.     mAudioDeviceIndex = -1;
  2292.     mCurrentAudioInput = -1;
  2293.     mAudioInputs.clear();
  2294.  
  2295.     // Attempt to connect to existing device
  2296.  
  2297.     bool success = false;
  2298.  
  2299.     if (idx < 0) {
  2300.         success = true;
  2301.     } else {
  2302.         const IMonikerPtr& pAudioDeviceMoniker = mAudioDevices[idx].first;
  2303.         HRESULT hr = S_OK;
  2304.  
  2305.         if (!pAudioDeviceMoniker) {
  2306.             VDASSERT(mpRealAudioPin);
  2307.             mpAudioPin = mpRealAudioPin;
  2308.         } else {
  2309.             hr = pAudioDeviceMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void **)~mpAudioCapFilt);
  2310.             if (FAILED(hr))
  2311.                 VDDEBUG("Failed to create audio filter: %s\n", GetDXErrorName(hr));
  2312.  
  2313.             // Do NOT add the audio capture filter into the graph at this
  2314.             // point. See BuildGraph() for an explanation of why.
  2315.  
  2316.             if (SUCCEEDED(hr)) {
  2317.                 hr = mpCapGraphBuilder2->FindPin(mpAudioCapFilt, PINDIR_OUTPUT, NULL, &MEDIATYPE_Audio, TRUE, 0, ~mpAudioPin);
  2318.  
  2319.                 if (FAILED(hr))
  2320.                     VDDEBUG("Couldn't find audio output pin: %s\n", GetDXErrorName(hr));
  2321.             }
  2322.  
  2323.             // scan the inputs of the audio capture filter and look for IAMAudioInputMixer
  2324.             // interfaces
  2325.  
  2326.             IEnumPinsPtr pEnumPins;
  2327.             if (SUCCEEDED(mpAudioCapFilt->EnumPins(~pEnumPins))) {
  2328.                 IPinPtr pPin;
  2329.  
  2330.                 mCurrentAudioInput = -1;
  2331.  
  2332.                 for(;;) {
  2333.                     ULONG actual;
  2334.                     HRESULT hr = pEnumPins->Next(1, ~pPin, &actual);
  2335.  
  2336.                     if (hr == VFW_E_ENUM_OUT_OF_SYNC) {
  2337.                         mAudioInputs.clear();
  2338.                         mCurrentAudioInput = -1;
  2339.                         if (FAILED(pEnumPins->Reset()))
  2340.                             break;
  2341.                         continue;
  2342.                     }
  2343.  
  2344.                     if (hr != S_OK)
  2345.                         break;
  2346.  
  2347.                     PIN_DIRECTION dir;
  2348.                     if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT) {
  2349.                         IAMAudioInputMixerPtr pInputMixer;
  2350.  
  2351.                         if (SUCCEEDED(pPin->QueryInterface(IID_IAMAudioInputMixer, (void **)~pInputMixer))) {
  2352.                             // attempt to get pin name
  2353.                             PIN_INFO pinInfo;
  2354.                             if (SUCCEEDED(pPin->QueryPinInfo(&pinInfo))) {
  2355.                                 mAudioInputs.push_back(AudioInput(pInputMixer, VDStringW(pinInfo.achName)));
  2356.  
  2357.                                 // if we haven't already found an enabled pin, check if this one
  2358.                                 // is enabled
  2359.                                 if (mCurrentAudioInput < 0) {
  2360.                                     BOOL enabled;
  2361.                                     if (SUCCEEDED(pInputMixer->get_Enable(&enabled)) && enabled)
  2362.                                         mCurrentAudioInput = mAudioInputs.size() - 1;
  2363.                                 }
  2364.  
  2365.                                 pinInfo.pFilter->Release();
  2366.                             }
  2367.                         }
  2368.                     }
  2369.                 }
  2370.             }
  2371.         }
  2372.  
  2373.         mAudioDeviceIndex = idx;
  2374.  
  2375.         // Reset audio format to first available format.
  2376.         if (mpAudioPin) {
  2377.             std::list<vdstructex<WAVEFORMATEX> > aformats;
  2378.  
  2379.             GetAvailableAudioFormats(aformats);
  2380.  
  2381.             mAudioFormat.clear();
  2382.             if (!aformats.empty())
  2383.                 mAudioFormat = aformats.front();
  2384.         }
  2385.     }
  2386.  
  2387.     UpdateDisplay();
  2388.  
  2389.     return success;
  2390. }
  2391.  
  2392. int VDCaptureDriverDS::GetAudioDeviceIndex() {
  2393.     return mAudioDeviceIndex;
  2394. }
  2395.  
  2396. bool VDCaptureDriverDS::IsAudioDeviceIntegrated(int idx) {
  2397.     return (unsigned)idx < mAudioDevices.size() && !mAudioDevices[idx].first;
  2398. }
  2399.  
  2400. int VDCaptureDriverDS::GetVideoSourceCount() {
  2401.     return mVideoSources.size();
  2402. }
  2403.  
  2404. const wchar_t *VDCaptureDriverDS::GetVideoSourceName(int idx) {
  2405.     return (unsigned)idx < mVideoSources.size() ? mVideoSources[idx].mName.c_str() : NULL;
  2406. }
  2407.  
  2408. bool VDCaptureDriverDS::SetVideoSource(int idx) {
  2409.     if (!mpVideoCrossbar)
  2410.         return false;
  2411.  
  2412.     const unsigned nSources = mVideoSources.size();
  2413.     if ((unsigned)idx >= nSources && idx != -1)
  2414.         return false;
  2415.  
  2416.     if (idx == mCurrentVideoSource)
  2417.         return true;
  2418.  
  2419.     const int inputPin = idx<0 ? -1 : mVideoSources[idx].mCrossbarPin;
  2420.  
  2421.     VDASSERT(inputPin >= -1);
  2422.     if (FAILED(mpVideoCrossbar->Route(mVideoCrossbarOutput, inputPin)))
  2423.         return false;
  2424.  
  2425.     mCurrentVideoSource = idx;
  2426.  
  2427.     return true;
  2428. }
  2429.  
  2430. int VDCaptureDriverDS::GetVideoSourceIndex() {
  2431.     return mCurrentVideoSource;
  2432. }
  2433.  
  2434. int VDCaptureDriverDS::GetAudioSourceCount() {
  2435.     return mAudioSources.size();
  2436. }
  2437.  
  2438. const wchar_t *VDCaptureDriverDS::GetAudioSourceName(int idx) {
  2439.     return (unsigned)idx < mAudioSources.size() ? mAudioSources[idx].mName.c_str() : NULL;
  2440. }
  2441.  
  2442. bool VDCaptureDriverDS::SetAudioSource(int idx) {
  2443.     if (!mpAudioCrossbar)
  2444.         return false;
  2445.  
  2446.     const unsigned nSources = mAudioSources.size();
  2447.     if ((unsigned)idx >= nSources && idx != -1)
  2448.         return false;
  2449.  
  2450.     if (idx == mCurrentAudioSource)
  2451.         return true;
  2452.  
  2453.     const int inputPin = idx<0 ? -1 : mAudioSources[idx].mCrossbarPin;
  2454.  
  2455.     VDASSERT(inputPin >= -1);
  2456.     if (FAILED(mpAudioCrossbar->Route(mAudioCrossbarOutput, inputPin)))
  2457.         return false;
  2458.  
  2459.     mCurrentAudioSource = idx;
  2460.  
  2461.     return true;
  2462. }
  2463.  
  2464. int VDCaptureDriverDS::GetAudioSourceIndex() {
  2465.     return mCurrentAudioSource;
  2466. }
  2467.  
  2468. int VDCaptureDriverDS::GetAudioSourceForVideoSource(int idx) {
  2469.     if (idx == -1)
  2470.         return -1;
  2471.  
  2472.     if ((unsigned)idx >= mVideoSources.size())
  2473.         return -2;
  2474.  
  2475.     int audioPhysType = -1;
  2476.  
  2477.     switch(mVideoSources[idx].mPhysicalType) {
  2478.     case PhysConn_Video_Tuner:      audioPhysType = PhysConn_Audio_Tuner; break;
  2479.     case PhysConn_Video_Composite:  audioPhysType = PhysConn_Audio_Line; break;
  2480.     case PhysConn_Video_SVideo:     audioPhysType = PhysConn_Audio_Line; break;
  2481.     case PhysConn_Video_SCSI:       audioPhysType = PhysConn_Audio_SCSI; break;
  2482.     case PhysConn_Video_AUX:        audioPhysType = PhysConn_Audio_AUX; break;
  2483.     case PhysConn_Video_1394:       audioPhysType = PhysConn_Audio_1394; break;
  2484.     case PhysConn_Video_USB:        audioPhysType = PhysConn_Audio_USB; break;
  2485.     default:                        return -2;
  2486.     }
  2487.  
  2488.     const int audioSources = mAudioSources.size();
  2489.  
  2490.     for(int i=0; i<audioSources; ++i) {
  2491.         if (mAudioSources[i].mPhysicalType == audioPhysType)
  2492.             return i;
  2493.     }
  2494.  
  2495.     return -2;
  2496. }
  2497.  
  2498. int VDCaptureDriverDS::GetAudioInputCount() {
  2499.     return mpAudioPin != 0 ? mAudioInputs.size() : 0;
  2500. }
  2501.  
  2502. const wchar_t *VDCaptureDriverDS::GetAudioInputName(int idx) {
  2503.     return (unsigned)idx < mAudioInputs.size() ? mAudioInputs[idx].mName.c_str() : NULL;
  2504. }
  2505.  
  2506. bool VDCaptureDriverDS::SetAudioInput(int idx) {
  2507.     if (!mpAudioPin)
  2508.         return false;
  2509.  
  2510.     const size_t nInputs = mAudioInputs.size();
  2511.     if ((unsigned)idx >= nInputs && idx != -1)
  2512.         return false;
  2513.  
  2514.     if (idx == mCurrentAudioInput)
  2515.         return true;
  2516.  
  2517.     // run through all of the pins and set the enables accordingly
  2518.     for(int i=0; (unsigned)i<nInputs; ++i) {
  2519.         const AudioInput& ai = mAudioInputs[i];
  2520.  
  2521.         if (ai.mMixerEnable) {
  2522.             // We deliberately ignore the return value here. The reason is
  2523.             // that the put_Enable method can return E_NOTIMPL when
  2524.             // attempting to set an input to FALSE on a device that can only
  2525.             // support one enabled input at a time (Creative SBLive!). This
  2526.             // strikes me as BS since E_NOTIMPL is supposed to mean a function
  2527.             // that is not implemented, but we must handle it nevertheless.
  2528.             ai.mMixerEnable->put_Enable(i == idx);
  2529.         }
  2530.     }
  2531.  
  2532.     mCurrentAudioInput = idx;
  2533.  
  2534.     return true;
  2535. }
  2536.  
  2537. int VDCaptureDriverDS::GetAudioInputIndex() {
  2538.     return mpAudioPin != 0 ? mCurrentAudioInput : -1;
  2539. }
  2540.  
  2541. bool VDCaptureDriverDS::IsAudioCapturePossible() {
  2542.     return !!mpAudioPin;
  2543. }
  2544.  
  2545. bool VDCaptureDriverDS::IsAudioCaptureEnabled() {
  2546.     return mbAudioCaptureEnabled && !!mpAudioPin;
  2547. }
  2548.  
  2549. bool VDCaptureDriverDS::IsAudioPlaybackPossible() {
  2550.     return !!mpAudioPin;
  2551. }
  2552.  
  2553. bool VDCaptureDriverDS::IsAudioPlaybackEnabled() {
  2554.     return mpAudioPin && mbAudioPlaybackEnabled;
  2555. }
  2556.  
  2557. void VDCaptureDriverDS::SetAudioCaptureEnabled(bool b) {
  2558.     if (mbAudioCaptureEnabled == b)
  2559.         return;
  2560.  
  2561.     mbAudioCaptureEnabled = b;
  2562.  
  2563.     if (mbAudioAnalysisEnabled)
  2564.         UpdateDisplay();
  2565. }
  2566.  
  2567. void VDCaptureDriverDS::SetAudioAnalysisEnabled(bool b) {
  2568.     if (mbAudioAnalysisEnabled == b)
  2569.         return;
  2570.  
  2571.     mbAudioAnalysisEnabled = b;
  2572.  
  2573.     if (mbAudioCaptureEnabled)
  2574.         UpdateDisplay();
  2575. }
  2576.  
  2577. void VDCaptureDriverDS::SetAudioPlaybackEnabled(bool b) {
  2578.     if (mbAudioPlaybackEnabled == b)
  2579.         return;
  2580.  
  2581.     mbAudioPlaybackEnabled = b;
  2582.  
  2583.     if (mpAudioPin)
  2584.         UpdateDisplay();
  2585. }
  2586.  
  2587. namespace {
  2588.     struct AudioFormatSorter {
  2589.         bool operator()(const vdstructex<WAVEFORMATEX>& af1, const vdstructex<WAVEFORMATEX>& af2) {
  2590.             const WAVEFORMATEX& f1 = *af1;
  2591.             const WAVEFORMATEX& f2 = *af2;
  2592.  
  2593.             if (f1.wFormatTag < f2.wFormatTag)
  2594.                 return true;
  2595.             if (f1.wFormatTag > f2.wFormatTag)
  2596.                 return false;
  2597.  
  2598.             if (f1.nSamplesPerSec > f2.nSamplesPerSec)
  2599.                 return true;
  2600.             if (f1.nSamplesPerSec < f2.nSamplesPerSec)
  2601.                 return false;
  2602.  
  2603.             if (f1.wBitsPerSample > f2.wBitsPerSample)
  2604.                 return true;
  2605.             if (f1.wBitsPerSample < f2.wBitsPerSample)
  2606.                 return false;
  2607.  
  2608.             if (f1.nChannels > f2.nChannels)
  2609.                 return true;
  2610.  
  2611.             return false;
  2612.         }
  2613.     };
  2614. }
  2615.  
  2616. void VDCaptureDriverDS::GetAvailableAudioFormats(std::list<vdstructex<WAVEFORMATEX> >& aformats) {
  2617.     aformats.clear();
  2618.  
  2619.     if (!mpAudioPin)
  2620.         return;
  2621.  
  2622.     IEnumMediaTypesPtr pEnum;
  2623.  
  2624.     if (FAILED(mpAudioPin->EnumMediaTypes(~pEnum)))
  2625.         return;
  2626.  
  2627.     AM_MEDIA_TYPE *pMediaType;
  2628.     while(S_OK == pEnum->Next(1, &pMediaType, NULL)) {
  2629.  
  2630.         if (pMediaType->majortype == MEDIATYPE_Audio && pMediaType->formattype == FORMAT_WaveFormatEx
  2631.             && pMediaType->cbFormat >= sizeof(WAVEFORMATEX)) {
  2632.             const WAVEFORMATEX *pwfex = (const WAVEFORMATEX *)pMediaType->pbFormat;
  2633.  
  2634.             if (pwfex->wFormatTag == WAVE_FORMAT_PCM)
  2635.                 aformats.push_back(vdstructex<WAVEFORMATEX>(pwfex, sizeof(WAVEFORMATEX)));
  2636.             else if (pwfex->cbSize + sizeof(WAVEFORMATEX) <= pMediaType->cbFormat)
  2637.                 aformats.push_back(vdstructex<WAVEFORMATEX>(pwfex, pwfex->cbSize + sizeof(WAVEFORMATEX)));
  2638.         }
  2639.  
  2640.         RizaDeleteMediaType(pMediaType);
  2641.     }
  2642.  
  2643.     aformats.sort(AudioFormatSorter());
  2644.  
  2645.     std::list<vdstructex<WAVEFORMATEX> >::iterator it(aformats.begin()), itEnd(aformats.end());
  2646.     if (it != itEnd) {
  2647.         for(;;) {
  2648.             std::list<vdstructex<WAVEFORMATEX> >::iterator itNext(it);
  2649.             ++itNext;
  2650.  
  2651.             if (itNext == itEnd)
  2652.                 break;
  2653.  
  2654.             const vdstructex<WAVEFORMATEX>& f1 = *it;
  2655.             const vdstructex<WAVEFORMATEX>& f2 = *itNext;
  2656.  
  2657.             if (f1 == f2)
  2658.                 aformats.erase(it);
  2659.  
  2660.             it = itNext;
  2661.         }
  2662.     }
  2663. }
  2664.  
  2665. bool VDCaptureDriverDS::GetAudioFormat(vdstructex<WAVEFORMATEX>& aformat) {
  2666.     if (!mpAudioPin)
  2667.         return false;
  2668.  
  2669.     if (!mAudioFormat.empty()) {
  2670.         aformat = mAudioFormat;
  2671.         return true;
  2672.     }
  2673.  
  2674.     return false;
  2675. }
  2676.  
  2677. bool VDCaptureDriverDS::SetAudioFormat(const WAVEFORMATEX *pwfex, uint32 size) {
  2678.     if (!mpAudioPin)
  2679.         return false;
  2680.  
  2681.     VDWaveFormatAsDShowMediaType    amt(pwfex, size);
  2682.  
  2683.     if (SUCCEEDED(mpAudioPin->QueryAccept(&amt))) {
  2684.         mAudioFormat.assign(pwfex, size);
  2685.  
  2686.         if (mbAudioCaptureEnabled && mbAudioAnalysisEnabled)
  2687.             UpdateDisplay();
  2688.  
  2689.         return true;
  2690.     }
  2691.  
  2692.     return false;
  2693. }
  2694.  
  2695. bool VDCaptureDriverDS::IsDriverDialogSupported(nsVDCapture::DriverDialog dlg) {
  2696.     switch(dlg) {
  2697.     case kDialogVideoFormat:        return mpVFWDialogs && SUCCEEDED(mpVFWDialogs->HasDialog(VfwCaptureDialog_Format));
  2698.     case kDialogVideoSource:        return mpVFWDialogs && SUCCEEDED(mpVFWDialogs->HasDialog(VfwCaptureDialog_Source));
  2699.     case kDialogVideoDisplay:
  2700.         if (mpCapTransformFilt)
  2701.             return DisplayPropertyPages(mpCapTransformFilt, NULL, NULL, 0);
  2702.         else
  2703.             return mpVFWDialogs && SUCCEEDED(mpVFWDialogs->HasDialog(VfwCaptureDialog_Display));
  2704.     case kDialogVideoCaptureFilter: return DisplayPropertyPages(mpCapFilt, NULL, NULL, 0);
  2705.     case kDialogVideoCapturePin:    return DisplayPropertyPages(mpRealCapturePin, NULL, NULL, 0);
  2706.     case kDialogVideoPreviewPin:    return DisplayPropertyPages(mpRealPreviewPin, NULL, NULL, 0);
  2707.     case kDialogVideoCrossbar:      return DisplayPropertyPages(mpCrossbar, NULL, NULL, 0);
  2708.     case kDialogVideoCrossbar2:     return DisplayPropertyPages(mpCrossbar2, NULL, NULL, 0);
  2709.     case kDialogTVTuner:            return DisplayPropertyPages(mpTVTuner, NULL, NULL, 0);
  2710.     }
  2711.  
  2712.     return false;
  2713. }
  2714.  
  2715. void VDCaptureDriverDS::DisplayDriverDialog(nsVDCapture::DriverDialog dlg) {
  2716.     bool bRestart = mbGraphActive;
  2717.  
  2718.     switch(dlg) {
  2719.     case kDialogVideoDisplay:
  2720.         if (mpCapTransformFilt) {
  2721.             DisplayPropertyPages(mpCapTransformFilt, mhwndParent, NULL, 0);
  2722.             break;
  2723.         }
  2724.         // fall through
  2725.     case kDialogVideoFormat:
  2726.     case kDialogVideoSource:
  2727.  
  2728.         if (mpVFWDialogs) {                    
  2729.             // Disable the parent window manually to prevent reentrancy. The
  2730.             // dialogs are supposed to do this, but for some reason the VFW dialogs
  2731.             // sometimes don't.
  2732.  
  2733.             bool wasEnabled = false;
  2734.            
  2735.             if (mhwndParent) {
  2736.                 wasEnabled = !!IsWindowEnabled(mhwndParent);
  2737.  
  2738.                 if (wasEnabled)
  2739.                     EnableWindow(mhwndParent, FALSE);
  2740.             }
  2741.  
  2742.             // The filter graph must be stopped for VFW dialogs.
  2743.             StopGraph();
  2744.  
  2745.             HRESULT hr;
  2746.             switch(dlg) {
  2747.             case kDialogVideoFormat:
  2748.                 hr = mpVFWDialogs->ShowDialog(VfwCaptureDialog_Format, mhwndParent);
  2749.                 break;
  2750.             case kDialogVideoSource:
  2751.                 hr = mpVFWDialogs->ShowDialog(VfwCaptureDialog_Source, mhwndParent);
  2752.                 break;
  2753.             case kDialogVideoDisplay:
  2754.                 hr = mpVFWDialogs->ShowDialog(VfwCaptureDialog_Display, mhwndParent);
  2755.                 break;
  2756.             }
  2757.  
  2758.             // The VFW dialogs have a habit of coming up with a NULL parent handle
  2759.             // when we're not in Hardware display mode. I don't know why; it appears
  2760.             // to be something funky in the o100vc driver, not in DirectShow. Anyway,
  2761.             // we kludge that here.
  2762.             SetForegroundWindow(mhwndParent);
  2763.  
  2764.             if (hr == VFW_E_CANNOT_CONNECT)
  2765.                 BuildPreviewGraph();
  2766.  
  2767.             // Restart the filter graph.
  2768.  
  2769.             if (bRestart)
  2770.                 StartGraph();
  2771.  
  2772.             // reenable main window
  2773.             if (mhwndParent && wasEnabled)
  2774.                 EnableWindow(mhwndParent, TRUE);
  2775.         }
  2776.  
  2777.         break;
  2778.  
  2779.     case kDialogVideoCapturePin:
  2780.     case kDialogVideoPreviewPin:
  2781.         TearDownGraph();
  2782.  
  2783.         switch(dlg) {
  2784.         case kDialogVideoCapturePin:
  2785.             {
  2786.                 // For some strange reason, the Adaptec GameBridge 1.00 drivers specify two property
  2787.                 // pages for the video capture pin, one of which is CLSID_AudioSamplingRate. Attempting
  2788.                 // to display this page causes a crash (reproduced with AMCAP). We detect this errant
  2789.                 // page and specifically exclude it from being displayed.
  2790.                 //
  2791.                 // Interestingly, GraphEdit does NOT have this problem... but it also doesn't seem
  2792.                 // to use OleCreatePropertyFrame. Either the GraphEdit guys accidentally bypassed this
  2793.                 // bug with custom code, or they know something and aren't telling us.
  2794.                 //
  2795.                 static const GUID kInvalidVideoCapturePinGuids[]={
  2796.                     { 0x05ea6f6b, 0x3b1e, 0x4958, 0xa6, 0x8d, 0xa3, 0x7f, 0x0b, 0x6a, 0x29, 0x95 }
  2797.                 };
  2798.  
  2799.                 DisplayPropertyPages(mpRealCapturePin, mhwndParent, kInvalidVideoCapturePinGuids, sizeof(kInvalidVideoCapturePinGuids)/sizeof(kInvalidVideoCapturePinGuids[0]));
  2800.             }
  2801.             break;
  2802.         case kDialogVideoPreviewPin:
  2803.             DisplayPropertyPages(mpRealPreviewPin, mhwndParent, NULL, 0);
  2804.             break;
  2805.         }
  2806.  
  2807.         // Restart the filter graph.
  2808.  
  2809.         BuildPreviewGraph();
  2810.         if (bRestart)
  2811.             StartGraph();
  2812.         break;
  2813.  
  2814.     case kDialogVideoCaptureFilter:
  2815.         DisplayPropertyPages(mpCapFilt, mhwndParent, NULL, 0);
  2816.         break;
  2817.     case kDialogVideoCrossbar:
  2818.         DisplayPropertyPages(mpCrossbar, mhwndParent, NULL, 0);
  2819.         break;
  2820.     case kDialogVideoCrossbar2:
  2821.         DisplayPropertyPages(mpCrossbar2, mhwndParent, NULL, 0);
  2822.         break;
  2823.     case kDialogTVTuner:
  2824.         DisplayPropertyPages(mpTVTuner, mhwndParent, NULL, 0);
  2825.         break;
  2826.     }
  2827.  
  2828.     CheckForChanges();
  2829. }
  2830.  
  2831. namespace {
  2832.     bool VDGetDShowProcAmpPropertyFromCaptureProperty(uint32 id, VideoProcAmpProperty& dshowPropId) {
  2833.         switch(id) {
  2834.             case kPropBacklightCompensation:
  2835.                 dshowPropId = VideoProcAmp_BacklightCompensation;
  2836.                 return true;
  2837.  
  2838.             case kPropBrightness:
  2839.                 dshowPropId = VideoProcAmp_Brightness;
  2840.                 return true;
  2841.  
  2842.             case kPropColorEnable:
  2843.                 dshowPropId = VideoProcAmp_ColorEnable;
  2844.                 return true;
  2845.  
  2846.             case kPropContrast:
  2847.                 dshowPropId = VideoProcAmp_Contrast;
  2848.                 return true;
  2849.  
  2850.             case kPropGain:
  2851.                 dshowPropId = VideoProcAmp_Gain;
  2852.                 return true;
  2853.  
  2854.             case kPropGamma:
  2855.                 dshowPropId = VideoProcAmp_Gamma;
  2856.                 return true;
  2857.  
  2858.             case kPropSaturation:
  2859.                 dshowPropId = VideoProcAmp_Saturation;
  2860.                 return true;
  2861.  
  2862.             case kPropHue:
  2863.                 dshowPropId = VideoProcAmp_Hue;
  2864.                 return true;
  2865.  
  2866.             case kPropSharpness:
  2867.                 dshowPropId = VideoProcAmp_Sharpness;
  2868.                 return true;
  2869.  
  2870.             case kPropWhiteBalance:
  2871.                 dshowPropId = VideoProcAmp_WhiteBalance;
  2872.                 return true;
  2873.  
  2874.             default:
  2875.                 return false;
  2876.         }
  2877.     }
  2878. }
  2879.  
  2880. bool VDCaptureDriverDS::IsPropertySupported(uint32 id) {
  2881.     if (!mpVideoProcAmp)
  2882.         return false;
  2883.  
  2884.     VideoProcAmpProperty prop;
  2885.     if (!VDGetDShowProcAmpPropertyFromCaptureProperty(id, prop))
  2886.         return false;
  2887.  
  2888.     long minVal, maxVal, steppingDelta, defaultVal, capsFlags;
  2889.     HRESULT hr = mpVideoProcAmp->GetRange(prop, &minVal, &maxVal, &steppingDelta, &defaultVal, &capsFlags);
  2890.     return SUCCEEDED(hr);
  2891. }
  2892.  
  2893. sint32 VDCaptureDriverDS::GetPropertyInt(uint32 id, bool *pAutomatic) {
  2894.     VideoProcAmpProperty prop;
  2895.     if (!mpVideoProcAmp || !VDGetDShowProcAmpPropertyFromCaptureProperty(id, prop))
  2896.         return false;
  2897.  
  2898.     long lValue, lFlags;
  2899.     HRESULT hr = mpVideoProcAmp->Get(prop, &lValue, &lFlags);
  2900.  
  2901.     if (FAILED(hr))
  2902.         lValue = lFlags = 0;
  2903.  
  2904.     if (pAutomatic)
  2905.         *pAutomatic = (lFlags == VideoProcAmp_Flags_Auto);
  2906.  
  2907.     return lValue;
  2908. }
  2909.  
  2910. void VDCaptureDriverDS::SetPropertyInt(uint32 id, sint32 value, bool automatic) {
  2911.     VideoProcAmpProperty prop;
  2912.     if (!mpVideoProcAmp || !VDGetDShowProcAmpPropertyFromCaptureProperty(id, prop))
  2913.         return;
  2914.  
  2915.     HRESULT hr = mpVideoProcAmp->Set(prop, value, automatic ? VideoProcAmp_Flags_Auto : VideoProcAmp_Flags_Manual);
  2916.     VDASSERT(SUCCEEDED(hr));
  2917. }
  2918.  
  2919. void VDCaptureDriverDS::GetPropertyInfoInt(uint32 id, sint32& minVal, sint32& maxVal, sint32& step, sint32& defaultVal, bool& automatic, bool& manual) {
  2920.     minVal = maxVal = 0;
  2921.     step = 1;
  2922.     defaultVal = 0;
  2923.     automatic = false;
  2924.     manual = false;
  2925.  
  2926.     VideoProcAmpProperty prop;
  2927.     if (!mpVideoProcAmp || !VDGetDShowProcAmpPropertyFromCaptureProperty(id, prop))
  2928.         return;
  2929.  
  2930.     long lMinVal, lMaxVal, lSteppingDelta, lDefaultVal, lCapsFlags;
  2931.     HRESULT hr = mpVideoProcAmp->GetRange(prop, &lMinVal, &lMaxVal, &lSteppingDelta, &lDefaultVal, &lCapsFlags);
  2932.     if (SUCCEEDED(hr)) {
  2933.         minVal = lMinVal;
  2934.         maxVal = lMaxVal;
  2935.         step = lSteppingDelta;
  2936.         defaultVal = lDefaultVal;
  2937.         automatic = (lCapsFlags & VideoProcAmp_Flags_Auto) != 0;
  2938.         manual = (lCapsFlags & VideoProcAmp_Flags_Manual) != 0;
  2939.     }
  2940. }
  2941.  
  2942. bool VDCaptureDriverDS::CaptureStart() {
  2943.     DS_VERBOSE_LOG("DShow: Entering CaptureStart().");
  2944.  
  2945.     if (VDINLINEASSERTFALSE(mCaptureThread)) {
  2946.         CloseHandle(mCaptureThread);
  2947.         mCaptureThread = NULL;
  2948.     }
  2949.  
  2950.     HANDLE hProcess = GetCurrentProcess();
  2951.     if (!DuplicateHandle(hProcess, GetCurrentThread(), hProcess, &mCaptureThread, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  2952.         VDLog(kVDLogWarning, VDStringW(L"CapDShow: Unable to duplicate process handle.\n"));
  2953.         return false;
  2954.     }
  2955.  
  2956.     // there had better not be update locks when we're trying to start a capture!
  2957.     VDASSERT(!mUpdateLocks);
  2958.  
  2959.     // switch to a capture graph, but don't start it.
  2960.     DS_VERBOSE_LOG("DShow: Building capture graph.");
  2961.  
  2962.     int audioSource = mCurrentAudioSource;
  2963.     if (BuildCaptureGraph()) {
  2964.         if (audioSource != mCurrentAudioSource)
  2965.             VDLog(kVDLogWarning, VDStringW(L"CapDShow: Audio source change was detected during capture start.\n"));
  2966.  
  2967.         // cancel default handling for EC_REPAINT, otherwise
  2968.         // the Video Renderer will start sending back extra requests
  2969.         mpMediaEventEx->CancelDefaultHandling(EC_REPAINT);
  2970.  
  2971.         // kick the sample grabbers and go!!
  2972.         mpVideoGrabber->SetCallback(&mVideoCallback, 0);
  2973.  
  2974.         if (mpAudioGrabber)
  2975.             mpAudioGrabber->SetCallback(&mAudioCallback, 0);
  2976.  
  2977.         mCaptureStart = VDGetAccurateTick();
  2978.         mCaptureStopQueued = false;
  2979.  
  2980.         // Kick the graph into PAUSED state.
  2981.  
  2982.         DS_VERBOSE_LOG("DShow: Pausing filter graph.");    
  2983.         HRESULT hr = mpGraphControl->Pause();
  2984.  
  2985.         if (hr == S_FALSE) {
  2986.             OAFilterState state;
  2987.             for(int i=0; i<30; ++i) {
  2988.                 hr = mpGraphControl->GetState(1000, &state);
  2989.                 if (hr != VFW_S_STATE_INTERMEDIATE)
  2990.                     break;
  2991.             }
  2992.  
  2993.             if (hr == VFW_S_STATE_INTERMEDIATE)
  2994.                 VDLog(kVDLogWarning, VDStringW(L"CapDShow: Filter graph took more than 30 seconds to transition state.\n"));
  2995.         }
  2996.  
  2997.         if (FAILED(hr)) {
  2998.             VDLog(kVDLogWarning, VDStringW(L"CapDShow: Unable to transition filter graph to paused state.\n"));
  2999.         } else {
  3000.             if (!mpCB || mpCB->CapEvent(kEventPreroll, 0)) {
  3001.                 // reset capture start time in case there was a preroll dialog
  3002.                 mCaptureStart = VDGetAccurateTick();
  3003.                 mVideoCallback.SetIgnoreTimestamps(mbIgnoreVideoTimestamps, mCaptureStart);
  3004.  
  3005.                 bool success = false;
  3006.                 if (mpCB) {
  3007.                     try {
  3008.                         mpCB->CapBegin(0);
  3009.                         success = true;
  3010.                     } catch(MyError& e) {
  3011.                         MyError *p = new MyError;
  3012.                         p->TransferFrom(e);
  3013.                         delete mpCaptureError.xchg(p);
  3014.                     }
  3015.                 }
  3016.  
  3017.                 if (success) {
  3018.                     DS_VERBOSE_LOG("DShow: Running filter graph.");
  3019.  
  3020.                     if (StartGraph()) {
  3021.                         DS_VERBOSE_LOG("DShow: Exiting CaptureStart() (success).");
  3022.                         return true;
  3023.                     }
  3024.  
  3025.                     DS_VERBOSE_LOG("DShow: Failed to run filter graph.");
  3026.                 }
  3027.             }
  3028.         }
  3029.  
  3030.         mGraphStateLock.Wait();     // 2x because of audio/video
  3031.         mGraphStateLock.Wait();
  3032.  
  3033.         hr = mpGraphControl->Stop();        // Have to do this because our graph state flag doesn't track PAUSED. Okay to fail.
  3034.         if (hr == S_FALSE) {
  3035.             OAFilterState state;
  3036.             for(int i=0; i<30; ++i) {
  3037.                 hr = mpGraphControl->GetState(1000, &state);
  3038.                 if (hr != VFW_S_STATE_INTERMEDIATE)
  3039.                     break;
  3040.             }
  3041.  
  3042.             if (hr == VFW_S_STATE_INTERMEDIATE)
  3043.                 VDLog(kVDLogWarning, VDStringW(L"CapDShow: Filter graph took more than 30 seconds to transition state.\n"));
  3044.         }
  3045.  
  3046.         if (FAILED(hr))
  3047.             VDLog(kVDLogWarning, VDStringW(L"CapDShow: Unable to stop filter graph.\n"));
  3048.  
  3049.         mGraphStateLock.Post();     // 2x because of audio/video
  3050.         mGraphStateLock.Post();
  3051.  
  3052.         if (mpCB)
  3053.             mpCB->CapEnd(mpCaptureError ? mpCaptureError : NULL);
  3054.  
  3055.         delete mpCaptureError.xchg(NULL);
  3056.  
  3057.         if (mpAudioGrabber)
  3058.             mpAudioGrabber->SetCallback(NULL, 0);
  3059.  
  3060.         mpVideoGrabber->SetCallback(NULL, 0);
  3061.     }
  3062.  
  3063.     mpMediaEventEx->RestoreDefaultHandling(EC_REPAINT);
  3064.  
  3065.     UpdateDisplay();
  3066.  
  3067.     DS_VERBOSE_LOG("DShow: Exiting CaptureStart() (failed).");
  3068.     return false;
  3069. }
  3070.  
  3071. void VDCaptureDriverDS::CaptureStop() {
  3072.     DS_VERBOSE_LOG("DShow: Entering CaptureStop().");
  3073.  
  3074.     if (mCaptureThread) {
  3075.         mCaptureStopQueued = true;
  3076.  
  3077.         StopGraph();
  3078.  
  3079.         if (mpVideoGrabber)
  3080.             mpVideoGrabber->SetCallback(NULL, 0);
  3081.  
  3082.         mpMediaEventEx->RestoreDefaultHandling(EC_REPAINT);
  3083.  
  3084.         if (mpCB) {
  3085.             mpCB->CapEnd(mpCaptureError ? mpCaptureError : NULL);
  3086.         }
  3087.         delete mpCaptureError.xchg(NULL);
  3088.  
  3089.         if (mCaptureThread) {
  3090.             CloseHandle(mCaptureThread);
  3091.             mCaptureThread = NULL;
  3092.         }
  3093.  
  3094.         mCaptureStopQueued = false;
  3095.  
  3096.         // Switch to a preview graph.
  3097.  
  3098.         int audioSource = mCurrentAudioSource;
  3099.         UpdateDisplay();
  3100.         if (audioSource != mCurrentAudioSource)
  3101.             VDLog(kVDLogWarning, VDStringW(L"CapDShow: Audio source change was detected during capture stop.\n"));
  3102.     }
  3103.  
  3104.     DS_VERBOSE_LOG("DShow: Exiting CaptureStop().");
  3105. }
  3106.  
  3107. void VDCaptureDriverDS::CaptureAbort() {
  3108.     CaptureStop();
  3109. }
  3110.  
  3111. bool VDCaptureDriverDS::GetDisableClockForPreview() {
  3112.     return mbDisableClockForPreview;
  3113. }
  3114.  
  3115. void VDCaptureDriverDS::SetDisableClockForPreview(bool enabled) {
  3116.     mbDisableClockForPreview = enabled;
  3117. }
  3118.  
  3119. bool VDCaptureDriverDS::GetForceAudioRendererClock() {
  3120.     return mbForceAudioRendererClock;
  3121. }
  3122.  
  3123. void VDCaptureDriverDS::SetForceAudioRendererClock(bool enabled) {
  3124.     mbForceAudioRendererClock = enabled;
  3125. }
  3126.  
  3127. bool VDCaptureDriverDS::GetIgnoreVideoTimestamps() {
  3128.     return mbIgnoreVideoTimestamps;
  3129. }
  3130.  
  3131. void VDCaptureDriverDS::SetIgnoreVideoTimestamps(bool enabled) {
  3132.     mbIgnoreVideoTimestamps = enabled;
  3133. }
  3134.  
  3135. void VDCaptureDriverDS::UpdateDisplay() {
  3136.     if (mUpdateLocks)
  3137.         mbUpdatePending = true;
  3138.     else {
  3139.         mbUpdatePending = false;
  3140.  
  3141.         DS_VERBOSE_LOG("DShow: Entering UpdateDisplay().");
  3142.  
  3143.         VDVERIFY(BuildPreviewGraph() && StartGraph());
  3144.  
  3145.         DS_VERBOSE_LOG("DShow: Exiting UpdateDisplay().");
  3146.     }
  3147. }
  3148.  
  3149. bool VDCaptureDriverDS::StopGraph() {
  3150.     if (!mbGraphActive)
  3151.         return true;
  3152.  
  3153.     mbGraphActive = false;
  3154.     mbStartPending = false;
  3155.  
  3156.     mVideoCallback.SetBlockSamples(true);
  3157.     mAudioCallback.SetBlockSamples(true);
  3158.  
  3159. #ifdef _DEBUG
  3160.     uint32 startTime = VDGetAccurateTick();
  3161.     VDDEBUG("Riza/CapDShow: Filter graph stopping...\n");
  3162. #endif
  3163.  
  3164.     mGraphStateLock.Wait();     // 2x because of audio/video
  3165.     mGraphStateLock.Wait();
  3166.  
  3167.     HRESULT hr = mpGraphControl->Stop();
  3168.  
  3169.     if (hr == S_FALSE) {
  3170.         OAFilterState state;
  3171.         for(int i=0; i<30; ++i) {
  3172.             hr = mpGraphControl->GetState(1000, &state);
  3173.             if (hr != VFW_S_STATE_INTERMEDIATE)
  3174.                 break;
  3175.         }
  3176.  
  3177.         if (hr == VFW_S_STATE_INTERMEDIATE)
  3178.             VDLog(kVDLogWarning, VDStringW(L"CapDShow: Filter graph took more than 30 seconds to transition state.\n"));
  3179.     }
  3180.  
  3181.     if (FAILED(hr))
  3182.         VDLog(kVDLogWarning, VDStringW(L"CapDShow: Unable to stop filter graph.\n"));
  3183.  
  3184.     mGraphStateLock.Post();     // 2x because of audio/video
  3185.     mGraphStateLock.Post();
  3186.  
  3187. #ifdef _DEBUG
  3188.     VDDEBUG("Riza/CapDShow: Filter graph stopped in %d ms.\n", VDGetAccurateTick() - startTime);
  3189. #endif
  3190.  
  3191.     return SUCCEEDED(hr);
  3192. }
  3193.  
  3194. bool VDCaptureDriverDS::StartGraph() {
  3195.     if (mbGraphActive)
  3196.         return true;
  3197.  
  3198.     mVideoCallback.SetFrameCount(0);
  3199.  
  3200.     if (mUpdateLocks) {
  3201.         mbStartPending = true;
  3202.         return true;
  3203.     }
  3204.  
  3205.     mbStartPending = false;
  3206.  
  3207.     mVideoCallback.SetBlockSamples(false);
  3208.     mAudioCallback.SetBlockSamples(false);
  3209.  
  3210.     mbGraphActive = false;
  3211.     HRESULT hr = mpGraphControl->Run();
  3212.  
  3213.     if (hr == S_FALSE) {
  3214.         OAFilterState state;
  3215.         for(int i=0; i<30; ++i) {
  3216.             hr = mpGraphControl->GetState(1000, &state);
  3217.             if (hr != VFW_S_STATE_INTERMEDIATE)
  3218.                 break;
  3219.         }
  3220.  
  3221.         if (hr == VFW_S_STATE_INTERMEDIATE)
  3222.             VDLog(kVDLogWarning, VDStringW(L"CapDShow: Filter graph took more than 30 seconds to transition state.\n"));
  3223.     }
  3224.  
  3225.     if (FAILED(hr)) {
  3226.         const char *err = GetDXErrorName(hr);
  3227.         VDLog(kVDLogWarning, VDswprintf(L"CapDShow: Unable to transition filter graph to run state: hr = %08x (%hs)\n", 2, &hr, &err));
  3228.  
  3229.         mVideoCallback.SetBlockSamples(true);
  3230.         mAudioCallback.SetBlockSamples(true);
  3231.     } else {
  3232.         mbGraphActive = true;
  3233.     }
  3234.  
  3235.     return mbGraphActive;
  3236. }
  3237.  
  3238. //  BuildPreviewGraph()
  3239. //
  3240. //  This routine builds the preview part of a graph.  It turns out that
  3241. //  if you try to leave the Capture pin connected, VFW drivers may not
  3242. //  send anything over their Preview pin (@#*&$*($).
  3243. //
  3244. //  Usually, this simply involves creating a video renderer and slapping
  3245. //  it on the Preview pin.
  3246. //
  3247. bool VDCaptureDriverDS::BuildPreviewGraph() {
  3248.     mVideoCallback.SetChannel(-1);
  3249.     mAudioCallback.SetChannel(-2);
  3250.     if (!BuildGraph(mDisplayMode == kDisplayAnalyze, mbAudioCaptureEnabled && mbAudioAnalysisEnabled))
  3251.         return false;
  3252.  
  3253.     if (mpAudioGrabber && mbAudioCaptureEnabled && mbAudioAnalysisEnabled)
  3254.         mpAudioGrabber->SetCallback(&mAudioCallback, 0);
  3255.  
  3256.     if (mpVideoGrabber && mDisplayMode == kDisplayAnalyze)
  3257.         mpVideoGrabber->SetCallback(&mVideoCallback, 0);
  3258.  
  3259.     return true;
  3260. }
  3261.  
  3262. //  BuildCaptureGraph()
  3263. //
  3264. //  This routine builds the capture part of the graph:
  3265. //
  3266. //  * Check if the capture filter only has a capture pin.  If so, insert
  3267. //    a smart tee filter to make a fake preview pin.
  3268. //
  3269. //  * Connect a sample grabber and then a null renderer onto the capture
  3270. //    pin.
  3271. //
  3272. //  * Render the preview pin.
  3273. //
  3274. bool VDCaptureDriverDS::BuildCaptureGraph() {
  3275.     if (BuildGraph(true, mbAudioCaptureEnabled)) {
  3276.         mVideoCallback.SetChannel(0);
  3277.         mAudioCallback.SetChannel(1);
  3278.         return true;
  3279.     }
  3280.  
  3281.     return false;
  3282. }
  3283.  
  3284. bool VDCaptureDriverDS::BuildGraph(bool bNeedCapture, bool bEnableAudio) {
  3285.     IPinPtr pCapturePin = mpRealCapturePin;
  3286.     IPinPtr pPreviewPin = mpRealPreviewPin;
  3287.     IPinPtr pVideoPortPin = mpCapFiltVideoPortPin;
  3288.     HRESULT hr;
  3289.  
  3290.     VDASSERT(!mUpdateLocks);
  3291.  
  3292.     // Tear down existing graph.
  3293.     TearDownGraph();
  3294.  
  3295.     // Check if the audio filter is in the filter graph, and if so, rip
  3296.     // it out of the graph. The reason we have to do so is that the DivX
  3297.     // Decoder filter is broken and can connect to MEDIASUBTYPE_AnalogAudio
  3298.     // inputs on the audio capture filter, completely screwing up the
  3299.     // graph building process. This was observed with the DivX 5.2.1
  3300.     // DirectShow decoder when rendering the preview pin of the Plextor
  3301.     // PX-M402U capture filter with an SBLive! Capture filter already in
  3302.     // the graph.
  3303.  
  3304.     if (mpAudioCapFilt) {
  3305.         if (VDIsFilterInGraphDShow(mpAudioCapFilt))
  3306.             mpGraphBuilder->RemoveFilter(mpAudioCapFilt);
  3307.     }
  3308.  
  3309.     ///////////////////////////////////////////////////////////////////////
  3310.     //
  3311.     // VIDEO PORTION
  3312.     //
  3313.     ///////////////////////////////////////////////////////////////////////
  3314.     VDASSERT(!mpAudioPin || !VDIsPinConnectedDShow(mpAudioPin));
  3315.  
  3316.     // Check if we need to reattach a transform filter (it can unattach
  3317.     // on a format change).
  3318.     if (mpCapTransformFilt) {
  3319.         IPinPtr pPinTest;
  3320.  
  3321.         if (VFW_E_NOT_CONNECTED == mpShadowedRealCapturePin->ConnectedTo(~pPinTest)) {
  3322.             // Reconnect transform filter input to capture pin
  3323.             IPinPtr pPinTIn;
  3324.             DS_VERIFY(mpCapGraphBuilder2->FindPin(mpCapTransformFilt, PINDIR_INPUT, NULL, NULL, TRUE, 0, ~pPinTIn), "find transform filter input");
  3325.             DS_VERIFY(mpGraphBuilder->Connect(mpShadowedRealCapturePin, pPinTIn), "reconnect capture -> transform");
  3326.         }
  3327.     }
  3328.  
  3329.     if (bNeedCapture || mDisplayMode == kDisplaySoftware) {
  3330.         // Create a sample grabber.
  3331.         IBaseFilterPtr pVideoPullFilt;
  3332.  
  3333.         DS_VERIFY(pVideoPullFilt.CreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER), "create sample grabber");
  3334.         DS_VERIFY(mpGraphBuilder->AddFilter(pVideoPullFilt, L"Video pulldown"), "add sample grabber");
  3335.  
  3336.         mExtraFilters.push_back(pVideoPullFilt);
  3337.  
  3338.         // Set the sample grabber to continuous mode.
  3339.         //
  3340.         // NOTE: In preview mode we use this sample grabber to force the
  3341.         // stream to a particular format. We don't actually install a
  3342.         // callback.
  3343.  
  3344.         DS_VERIFY(pVideoPullFilt->QueryInterface(IID_ISampleGrabber, (void **)~mpVideoGrabber), "find sample grabber if");
  3345.         DS_VERIFY(mpVideoGrabber->SetOneShot(FALSE), "switch sample grabber to continuous");
  3346.  
  3347.         AM_MEDIA_TYPE vamtDummy;
  3348.  
  3349.         vamtDummy.majortype = MEDIATYPE_Video;
  3350.         vamtDummy.subtype   = GUID_NULL;
  3351.         vamtDummy.bFixedSizeSamples = FALSE;
  3352.         vamtDummy.bTemporalCompression = FALSE;
  3353.         vamtDummy.lSampleSize   = 0;
  3354.         vamtDummy.formattype    = FORMAT_VideoInfo;
  3355.         vamtDummy.pUnk      = NULL;
  3356.         vamtDummy.cbFormat  = 0;
  3357.         vamtDummy.pbFormat  = NULL;
  3358.  
  3359.         DS_VERIFY(mpVideoGrabber->SetMediaType(&vamtDummy), "set video sample grabber format");
  3360.  
  3361.         // Attach the sink to the grabber, and the grabber to the capture pin.
  3362.  
  3363.         IPinPtr pPinSGIn, pPinSGOut;
  3364.  
  3365.         DS_VERIFY(mpCapGraphBuilder2->FindPin(pVideoPullFilt, PINDIR_INPUT, NULL, NULL, TRUE, 0, ~pPinSGIn), "find sample grabber input");
  3366.         DS_VERIFY(mpCapGraphBuilder2->FindPin(pVideoPullFilt, PINDIR_OUTPUT, NULL, NULL, TRUE, 0, ~pPinSGOut), "find sample grabber output");
  3367.         DS_VERIFY(mpGraphBuilder->Connect(pCapturePin, pPinSGIn), "connect capture -> grabber");
  3368.  
  3369.         pCapturePin = pPinSGOut;
  3370.     }
  3371.     VDASSERT(!mpAudioPin || !VDIsPinConnectedDShow(mpAudioPin));
  3372.  
  3373.     // Render the preview part.
  3374.     //
  3375.     //
  3376.     // Software configuration:
  3377.     //
  3378.     // +----------------+~capture  +--------------+     +----------+
  3379.     // |                |--------->|sample grabber|---->| renderer |
  3380.     // | capture filter |          +--------------+     +----------+
  3381.     // |                |->
  3382.     // +----------------+preview
  3383.     //
  3384.     //
  3385.     // Hardware configuration:
  3386.     // +----------------+~capture  +--------------+
  3387.     // |                |--------->|sample grabber|---------------------->
  3388.     // | capture filter |          +--------------+     +----------+
  3389.     // |                |------------------------------>| renderer |
  3390.     // +----------------+preview                        +----------+
  3391.     //
  3392.     // Note that we use the video port pin preferentially to the preview
  3393.     // pin.
  3394.  
  3395.     VDASSERT(pPreviewPin != mpAudioPin);
  3396.     VDASSERT(pCapturePin != mpAudioPin);
  3397.  
  3398.     switch(mDisplayMode) {
  3399.     case kDisplayHardware:
  3400.         // Render the preview pin if it exists, otherwise fall through.
  3401.         if (pVideoPortPin) {
  3402.             // No need to handle this here, as we always render the VP pin below.
  3403.             break;
  3404.         } else if (pPreviewPin) {
  3405.             DS_VERIFY(mpGraphBuilder->Render(pPreviewPin), "render preview pin (hardware display)");
  3406.             pPreviewPin = NULL;
  3407.             break;
  3408.         }
  3409.     case kDisplaySoftware:
  3410.         // In software mode we force the rendering path to use the same format that
  3411.         // would be used for capture. This is already done for us above, so we
  3412.         // simply add the renderer.
  3413.         //
  3414.         // Note that while it might seem like a good idea to use a Smart Tee to rip off the
  3415.         // timestamps, this doesn't work since it causes the video to play at maximum speed,
  3416.         // causing horrible stuttering on the PX-M402U.
  3417.         //
  3418.         DS_VERIFY(mpGraphBuilder->Render(pCapturePin), "render capture pin (hardware display)");
  3419.         pCapturePin = NULL;
  3420.         break;
  3421.     }
  3422.  
  3423.     // Render the video port pin. We're supposed to do this in any case
  3424.     // according to the DirectShow docs for Video Port pins. We HAVE to do
  3425.     // this regardless of whether we actually want to use the overlay as
  3426.     // otherwise the ATI All-in-Wonder RADEON driver locks up and zombies
  3427.     // our process.
  3428.  
  3429.     if (pVideoPortPin) {
  3430.         DS_VERIFY(mpGraphBuilder->Render(pVideoPortPin), "render video port pin");
  3431.         pVideoPortPin = NULL;
  3432.     }
  3433.  
  3434.     // Add the audio filter back into the graph, if it exists.
  3435.     if (mpAudioCapFilt) {
  3436.         DS_VERIFY(mpGraphBuilder->AddFilter(mpAudioCapFilt, L"Audio capture"), "add audio capture filter to graph");
  3437.     }
  3438.  
  3439.     VDASSERT(!mpAudioPin || !VDIsPinConnectedDShow(mpAudioPin));
  3440.  
  3441.     // Terminate the capture pin with a null renderer if it has not
  3442.     // already been terminated.
  3443.     //
  3444.     //            +-------------+
  3445.     //   -------->|null renderer|
  3446.     //            +-------------+
  3447.     //
  3448.     if (pCapturePin) {
  3449.         IBaseFilterPtr pNullRenderer;
  3450.         IPinPtr pPinNRIn;
  3451.  
  3452.         DS_VERIFY(pNullRenderer.CreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER), "create null renderer");
  3453.         DS_VERIFY(mpGraphBuilder->AddFilter(pNullRenderer, L"Video sink"), "add null renderer");
  3454.         mExtraFilters.push_back(pNullRenderer);
  3455.         DS_VERIFY(mpCapGraphBuilder2->FindPin(pNullRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, ~pPinNRIn), "find null renderer input");
  3456.         DS_VERIFY(mpGraphBuilder->Connect(pCapturePin, pPinNRIn), "connect grabber -> sink");
  3457.         pCapturePin = NULL;
  3458.     }
  3459.  
  3460.     ///////////////////////////////////////////////////////////////////////
  3461.     //
  3462.     // AUDIO PORTION
  3463.     //
  3464.     ///////////////////////////////////////////////////////////////////////
  3465.  
  3466.     IPinPtr pAudioPin = mpAudioPin;
  3467.  
  3468.     VDASSERT(!pAudioPin || !VDIsPinConnectedDShow(pAudioPin));
  3469.     if (bNeedCapture || (bEnableAudio && mbAudioAnalysisEnabled)) {
  3470.         // We need to do the audio now.
  3471.  
  3472.         if (pAudioPin && bEnableAudio) {
  3473.             IPinPtr pPinSGIn, pPinSGOut;
  3474.             IBaseFilterPtr pAudioPullFilt;
  3475.  
  3476.             DS_VERIFY(pAudioPullFilt.CreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER), "create sample grabber");
  3477.             DS_VERIFY(mpGraphBuilder->AddFilter(pAudioPullFilt, L"Audio pulldown"), "add sample grabber");
  3478.             mExtraFilters.push_back(pAudioPullFilt);
  3479.  
  3480.             // Set the sample grabber to continuous mode.
  3481.  
  3482.             DS_VERIFY(pAudioPullFilt->QueryInterface(IID_ISampleGrabber, (void **)~mpAudioGrabber), "find sample grabber if");
  3483.  
  3484.             if (mAudioFormat.empty())
  3485.                 return false;
  3486.  
  3487.             VDWaveFormatAsDShowMediaType amt(mAudioFormat.data(), mAudioFormat.size());
  3488.  
  3489.             DS_VERIFY(mpAudioGrabber->SetMediaType(&amt), "set media type");
  3490.             DS_VERIFY(mpAudioGrabber->SetOneShot(FALSE), "switch sample grabber to continuous");
  3491.  
  3492.             // Attach the grabber to the capture pin.
  3493.  
  3494.             DS_VERIFY(mpCapGraphBuilder2->FindPin(pAudioPullFilt, PINDIR_INPUT, NULL, NULL, TRUE, 0, ~pPinSGIn), "find sample grabber input");
  3495.             DS_VERIFY(mpCapGraphBuilder2->FindPin(pAudioPullFilt, PINDIR_OUTPUT, NULL, NULL, TRUE, 0, ~pPinSGOut), "find sample grabber output");
  3496.  
  3497.             // If audio analysis is enabled, try to keep the latency down to at least 1/30th of a second.
  3498.             if (mbAudioAnalysisEnabled) {
  3499.                 ALLOCATOR_PROPERTIES allocProp;
  3500.  
  3501.                 allocProp.cbAlign = -1;
  3502.                 allocProp.cbBuffer = mAudioFormat->nAvgBytesPerSec/30;
  3503.                 if (!allocProp.cbBuffer)
  3504.                     allocProp.cbBuffer = 1;
  3505.                 allocProp.cbBuffer += mAudioFormat->nBlockAlign - 1;
  3506.                 allocProp.cbBuffer -= allocProp.cbBuffer % mAudioFormat->nBlockAlign;
  3507.                 allocProp.cbPrefix = -1;
  3508.                 allocProp.cBuffers = -1;
  3509.  
  3510.                 IAMBufferNegotiation *pBN;
  3511.  
  3512.                 if (SUCCEEDED(pAudioPin->QueryInterface(IID_IAMBufferNegotiation, (void **)&pBN))) {
  3513.                     if (FAILED(pBN->SuggestAllocatorProperties(&allocProp))) {
  3514.                         VDDEBUG("Riza/DShow: Warning: Unable to suggest buffer size of %u bytes to audio capture pin\n", (unsigned)allocProp.cbBuffer);
  3515.                     }
  3516.                     pBN->Release();
  3517.                 }
  3518.  
  3519.                 if (SUCCEEDED(pPinSGIn->QueryInterface(IID_IAMBufferNegotiation, (void **)&pBN))) {
  3520.                     if (FAILED(pBN->SuggestAllocatorProperties(&allocProp))) {
  3521.                         VDDEBUG("Riza/DShow: Warning: Unable to suggest buffer size of %u bytes to sample grabber pin\n", (unsigned)allocProp.cbBuffer);
  3522.                     }
  3523.                     pBN->Release();
  3524.                 }
  3525.             }
  3526.  
  3527.             DS_VERIFY(mpGraphBuilder->Connect(pAudioPin, pPinSGIn), "connect capture -> grabber");
  3528.             pAudioPin = pPinSGOut;
  3529.             VDASSERT(!VDIsPinConnectedDShow(pAudioPin));
  3530.         }
  3531.     }
  3532.  
  3533.     // Terminate the audio path with a null renderer or a sound output. We do this
  3534.     // even if we are just previewing, because the Plextor PX-M402U doesn't output
  3535.     // frames reliably otherwise.
  3536.     bool bUseDefaultClock = true;
  3537.  
  3538.     if (pAudioPin) {
  3539.         VDASSERT(!VDIsPinConnectedDShow(pAudioPin));
  3540.  
  3541.         if (mbAudioPlaybackEnabled) {
  3542.             HRESULT hrRender = mpGraphBuilder->Render(pAudioPin);
  3543.  
  3544.             // Reset the filter graph clock. We have to do this because when we
  3545.             // create a capture graph a different filter may end up being the
  3546.             // clock. For some reason the DirectSound Renderer refuses to play
  3547.             // if we try using the system clock. (SAA713x)
  3548.             if (mbForceAudioRendererClock) {
  3549.                 IMediaFilterPtr pGraphMF;
  3550.  
  3551.                 if (SUCCEEDED(mpGraphBuilder->QueryInterface(IID_IMediaFilter, (void **)~pGraphMF))) {
  3552.                     IPinPtr pAudioPinConnect;
  3553.                     if (SUCCEEDED(pAudioPin->ConnectedTo(~pAudioPinConnect))) {
  3554.                         PIN_INFO pi;
  3555.  
  3556.                         if (SUCCEEDED(pAudioPinConnect->QueryPinInfo(&pi))) {
  3557.                             bUseDefaultClock = !SetClockFromDownstream(pi.pFilter, pGraphMF);
  3558.                             pi.pFilter->Release();
  3559.                         }
  3560.                     }
  3561.                 }
  3562.             }
  3563.  
  3564.             if (SUCCEEDED(hrRender))
  3565.                 pAudioPin = NULL;
  3566.         }
  3567.  
  3568.         if (pAudioPin) {
  3569.             IPinPtr pPinRIn;
  3570.             IBaseFilterPtr pRenderer;
  3571.             VDASSERT(!VDIsPinConnectedDShow(pAudioPin));
  3572.             DS_VERIFY(pRenderer.CreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER), "create audio null renderer");
  3573.             DS_VERIFY(mpGraphBuilder->AddFilter(pRenderer, L"Audio sink"), "add null renderer");
  3574.             mExtraFilters.push_back(pRenderer);
  3575.             DS_VERIFY(mpCapGraphBuilder2->FindPin(pRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, ~pPinRIn), "find audio renderer input");
  3576.             DS_VERIFY(mpGraphBuilder->Connect(pAudioPin, pPinRIn), "connect audio null renderer");
  3577.         }
  3578.     }
  3579.  
  3580.     // If the capture filter has an audio pin that's not being used, terminate that too.
  3581.     if (mpRealAudioPin && mpRealAudioPin != mpAudioPin) {
  3582.         IPinPtr pPinRIn;
  3583.         IBaseFilterPtr pRenderer;
  3584.         DS_VERIFY(pRenderer.CreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER), "create audio null renderer");
  3585.         DS_VERIFY(mpGraphBuilder->AddFilter(pRenderer, L"Audio sink"), "add null renderer");
  3586.         mExtraFilters.push_back(pRenderer);
  3587.         DS_VERIFY(mpCapGraphBuilder2->FindPin(pRenderer, PINDIR_INPUT, NULL, NULL, TRUE, 0, ~pPinRIn), "find audio renderer input");
  3588.         DS_VERIFY(mpGraphBuilder->Connect(mpRealAudioPin, pPinRIn), "connect audio null renderer to real audio cap pin");
  3589.     }
  3590.  
  3591.     // Set the graph clock
  3592.     if (mbDisableClockForPreview && !bNeedCapture) {
  3593.         IMediaFilterPtr pGraphMF;
  3594.  
  3595.         if (SUCCEEDED(mpGraphBuilder->QueryInterface(IID_IMediaFilter, (void **)~pGraphMF)))
  3596.             pGraphMF->SetSyncSource(NULL);
  3597.     } else if (bUseDefaultClock) {
  3598.         IMediaFilterPtr pGraphMF;
  3599.  
  3600.         if (SUCCEEDED(mpGraphBuilder->QueryInterface(IID_IMediaFilter, (void **)~pGraphMF))) {
  3601.             IReferenceClockPtr pGraphClock;
  3602.  
  3603.             if (SUCCEEDED(pGraphClock.CreateInstance(CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER)))
  3604.                 pGraphMF->SetSyncSource(pGraphClock);
  3605.         }
  3606.     }
  3607.  
  3608.     // Dump the graph to stdout.
  3609.     VDDumpFilterGraphDShow(mpGraphBuilder);
  3610.  
  3611.     // Check for a window and return.
  3612.     CheckForWindow();
  3613.  
  3614.     // Broadcast events if values changed.
  3615.     CheckForChanges();
  3616.  
  3617.     return true;
  3618. }
  3619.  
  3620. //
  3621. //  TearDownGraph()
  3622. //
  3623. //  This rips up everything in the filter graph beyond the capture filter.
  3624. //
  3625. void VDCaptureDriverDS::TearDownGraph() {
  3626.     StopGraph();
  3627.  
  3628.     // drop pointers to graph components
  3629.     if (mpAudioGrabber)
  3630.         mpAudioGrabber->SetCallback(NULL, 0);
  3631.  
  3632.     mpVideoGrabber          = NULL;
  3633.     mpVideoWindow           = NULL;
  3634.     mVideoWindows.clear();
  3635.     if (mpVideoQualProp) {
  3636.         mpVideoQualProp->Release();
  3637.         mpVideoQualProp = NULL;
  3638.     }
  3639.  
  3640.     mpAudioGrabber = NULL;
  3641.  
  3642.     // reset capture clock
  3643.     IMediaFilterPtr pGraphMF;
  3644.  
  3645.     if (SUCCEEDED(mpGraphBuilder->QueryInterface(IID_IMediaFilter, (void **)~pGraphMF))) {
  3646.         pGraphMF->SetSyncSource(NULL);
  3647.     }
  3648.  
  3649.     // destroy downstreams
  3650.     DestroySubgraph(mpGraphBuilder, mpCapFilt, mpCapSplitFilt, mpCapTransformFilt);
  3651.     DestroySubgraph(mpGraphBuilder, mpAudioCapFilt, NULL, NULL);
  3652.  
  3653.     // yank any loose filters
  3654.     while(!mExtraFilters.empty()) {
  3655.         IBaseFilterPtr filt = mExtraFilters.back();
  3656.         mExtraFilters.pop_back();
  3657.  
  3658.         FILTER_INFO finfo;
  3659.         if (SUCCEEDED(filt->QueryFilterInfo(&finfo))) {
  3660.             if (finfo.pGraph) {
  3661.                 finfo.pGraph->RemoveFilter(filt);
  3662.                 finfo.pGraph->Release();
  3663.             }
  3664.         }
  3665.     }
  3666.  
  3667.     VDASSERT(!mpRealAudioPin || !VDIsPinConnectedDShow(mpRealAudioPin));
  3668.     VDASSERT(!mpAudioPin || !VDIsPinConnectedDShow(mpAudioPin));
  3669. }
  3670.  
  3671. //
  3672. //  CheckForWindow()
  3673. //
  3674. //  Look for a video window in the capture graph, and make it ours if
  3675. //  there is one.
  3676. //
  3677. void VDCaptureDriverDS::CheckForWindow() {
  3678.     if (mpVideoQualProp) {
  3679.         mpVideoQualProp->Release();
  3680.         mpVideoQualProp = NULL;
  3681.     }
  3682.  
  3683.     // Sweep the filter graph and pick up all video windows, along with
  3684.     // the first IVideoQualProp interface we can find.
  3685.     IEnumFiltersPtr pEnumFilters;
  3686.  
  3687.     mVideoWindows.clear();
  3688.     if (SUCCEEDED(mpGraphBuilder->EnumFilters(~pEnumFilters))) {
  3689.         IBaseFilterPtr pFilter;
  3690.  
  3691.         while(S_OK == pEnumFilters->Next(1, ~pFilter, NULL)) {
  3692.             if (!mpVideoQualProp)
  3693.                 pFilter->QueryInterface(IID_IQualProp, (void **)&mpVideoQualProp);  // OK for this to fail.
  3694.  
  3695.             IVideoWindowPtr pVW;
  3696.             if (SUCCEEDED(pFilter->QueryInterface(IID_IVideoWindow, (void **)~pVW))) {
  3697.                 // hide the video window
  3698.                 pVW->put_Visible(OAFALSE);
  3699.                 pVW->put_AutoShow(OAFALSE);
  3700.  
  3701.                 // add it to our list
  3702.                 mVideoWindows.push_back(IVideoWindowPtr());
  3703.                 mVideoWindows.back().Swap(pVW);
  3704.             }
  3705.         }
  3706.     }
  3707.  
  3708.     VDDEBUG("Riza/CapDShow: %u windows found.\n", mVideoWindows.size());
  3709.  
  3710.     // Only overlay and preview modes use DirectShow displays
  3711.     if (mDisplayMode == kDisplayNone || mDisplayMode == kDisplayAnalyze)
  3712.         return;
  3713.  
  3714.     // Look for the one video window we do want to show. The order is capture, then
  3715.     // preview, then video port. We'll always have at least one if display is enabled,
  3716.     // and possibly two if we hide the video port (we always have to have it).
  3717.  
  3718.     IBaseFilterPtr pFilter;
  3719.     bool success = false;
  3720.  
  3721.     // try capture pin first
  3722.     if (mpRealCapturePin) {
  3723.         success = VDGetFilterConnectedToPinDShow(mpRealCapturePin, ~pFilter);
  3724.         if (success) {
  3725.             HRESULT hr = mpCapGraphBuilder2->FindInterface(&LOOK_DOWNSTREAM_ONLY, NULL, pFilter, IID_IVideoWindow, (void **)~mpVideoWindow);
  3726.             success = SUCCEEDED(hr);
  3727.         }
  3728.     }
  3729.  
  3730.     // next, try preview pin
  3731.     if (!success && mpRealPreviewPin) {
  3732.         success = VDGetFilterConnectedToPinDShow(mpRealPreviewPin, ~pFilter);
  3733.         if (success) {
  3734.             HRESULT hr = mpCapGraphBuilder2->FindInterface(&LOOK_DOWNSTREAM_ONLY, NULL, pFilter, IID_IVideoWindow, (void **)~mpVideoWindow);
  3735.             success = SUCCEEDED(hr);
  3736.         }
  3737.     }
  3738.  
  3739.     // try video port
  3740.     if (!success && mpCapFiltVideoPortPin) {
  3741.         success = VDGetFilterConnectedToPinDShow(mpCapFiltVideoPortPin, ~pFilter);
  3742.         if (success) {
  3743.             HRESULT hr = mpCapGraphBuilder2->FindInterface(&LOOK_DOWNSTREAM_ONLY, NULL, pFilter, IID_IVideoWindow, (void **)~mpVideoWindow);
  3744.             success = SUCCEEDED(hr);
  3745.         }
  3746.     }
  3747.  
  3748.     // okay... use any others
  3749.     if (!success && !mVideoWindows.empty())
  3750.         mpVideoWindow = mVideoWindows.front();
  3751.  
  3752.     // if we have a video window, configure it
  3753.     if (mpVideoWindow) {
  3754.         long styles;
  3755.  
  3756.         mpVideoWindow->put_Visible(OAFALSE);
  3757.         mpVideoWindow->put_AutoShow(mbDisplayVisible ? OATRUE : OAFALSE);
  3758.  
  3759.         if (SUCCEEDED(mpVideoWindow->get_WindowStyle(&styles))) {
  3760.             mpVideoWindow->put_WindowStyle(styles & ~(WS_CAPTION|WS_THICKFRAME));
  3761.         }
  3762.  
  3763.         // Add WS_EX_NOPARENTNOTIFY to try to avoid certain kinds of deadlocks,
  3764.         // since the video window is in a different thread than its parent.
  3765.  
  3766.         if (SUCCEEDED(mpVideoWindow->get_WindowStyleEx(&styles))) {
  3767.             mpVideoWindow->put_WindowStyleEx(styles | WS_EX_NOPARENTNOTIFY);
  3768.         }
  3769.  
  3770.         SetDisplayRect(mDisplayRect);
  3771.         mpVideoWindow->put_Owner((OAHWND)mhwndParent);
  3772.     }
  3773. }
  3774.  
  3775. void VDCaptureDriverDS::CheckForChanges() {
  3776.     // check for crossbar changes
  3777.     if (mpAudioCrossbar) {
  3778.         int newAudioSource = UpdateCrossbarSource(mAudioSources, mpAudioCrossbar, mAudioCrossbarOutput);
  3779.  
  3780.         // Sigh... DirectShow crossbars seem to have the general problem that after stopping the graph,
  3781.         // get_IsRoutedTo() starts returning -1 even though the crossbar is actually still routing
  3782.         // audio. You can see this in GraphEdit if you start and stop the graph -- afterward the crossbar
  3783.         // property page shows Mute In (-1) for the audio input. As such, we ignore the return value if
  3784.         // -1 is returned.
  3785.         //
  3786.         // Seen directly on the Adaptec GameBridge; similar behavior reported for WinFast and Usenet
  3787.         // hints it happens on ATI too.
  3788.  
  3789.         if (mCurrentAudioSource != newAudioSource && newAudioSource != -1) {
  3790.             mCurrentAudioSource = newAudioSource;
  3791.  
  3792.             DS_VERBOSE_LOGF(L"DShow: Detected audio source change: %d", 1, &newAudioSource);
  3793.  
  3794.             if (mpCB)
  3795.                 mpCB->CapEvent(kEventAudioSourceChanged, newAudioSource);
  3796.         }
  3797.     }
  3798.  
  3799.     if (mpVideoCrossbar) {
  3800.         int newVideoSource = UpdateCrossbarSource(mVideoSources, mpVideoCrossbar, mVideoCrossbarOutput);
  3801.  
  3802.         if (mCurrentVideoSource != newVideoSource) {
  3803.             mCurrentVideoSource = newVideoSource;
  3804.  
  3805.             if (mpCB)
  3806.                 mpCB->CapEvent(kEventVideoSourceChanged, newVideoSource);
  3807.         }
  3808.     }
  3809.  
  3810.     // check for video frame or format changes
  3811.     if (mpCB) {
  3812.         bool keepGoing = true;
  3813.  
  3814.         sint32 fp = GetFramePeriod();
  3815.  
  3816.         if (mTrackedFramePeriod != fp) {
  3817.             mTrackedFramePeriod = fp;
  3818.  
  3819.             keepGoing &= mpCB->CapEvent(kEventVideoFrameRateChanged, 0);
  3820.         }
  3821.  
  3822.         vdstructex<BITMAPINFOHEADER> vf;
  3823.         GetVideoFormat(vf);
  3824.  
  3825.         if (mTrackedVideoFormat != vf) {
  3826.             mTrackedVideoFormat = vf;
  3827.  
  3828.             keepGoing &= mpCB->CapEvent(kEventVideoFormatChanged, 0);
  3829.         }
  3830.  
  3831.         if (!keepGoing && mCaptureThread)
  3832.             CaptureStop();
  3833.     }
  3834. }
  3835.  
  3836. bool VDCaptureDriverDS::DisplayPropertyPages(IUnknown *ptr, HWND hwndParent, const GUID *pDisablePages, int nDisablePages) {
  3837.     if (!ptr)
  3838.         return false;
  3839.  
  3840.     HRESULT hr;
  3841.     ISpecifyPropertyPages *pPages;
  3842.     hr = ptr->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pPages);
  3843.     if (FAILED(hr))
  3844.         return false;
  3845.  
  3846.     CAUUID cauuid;
  3847.     hr = pPages->GetPages(&cauuid);
  3848.     pPages->Release();
  3849.  
  3850.     if (FAILED(hr))
  3851.         return false;
  3852.  
  3853.     bool success = false;
  3854.     if (cauuid.cElems) {
  3855.         uint32 n = 0;
  3856.         for(uint32 i = 0; i < cauuid.cElems; ++i) {
  3857.             const GUID& guid = cauuid.pElems[i];
  3858.             bool copy = true;
  3859.  
  3860.             for(int j=0; j<nDisablePages; ++j) {
  3861.                 if (guid == pDisablePages[j]) {
  3862.                     copy = false;
  3863.                     break;
  3864.                 }
  3865.             }
  3866.  
  3867.             if (copy)
  3868.                 cauuid.pElems[n++] = guid;
  3869.         }
  3870.  
  3871.         if (n) {
  3872.             if (hwndParent) {
  3873.                 HRESULT hr = OleCreatePropertyFrame(hwndParent, 0, 0, NULL, 1,
  3874.                     &ptr, n, cauuid.pElems, 0, 0, NULL);
  3875.  
  3876.                 success = SUCCEEDED(hr);
  3877.             } else
  3878.                 success = true;
  3879.         }
  3880.     }
  3881.  
  3882.     CoTaskMemFree(cauuid.pElems);
  3883.  
  3884.     return success;
  3885. }
  3886.  
  3887. int VDCaptureDriverDS::EnumerateCrossbarSources(InputSources& sources, IAMCrossbar *pCrossbar, int output) {
  3888.     // If there is an audio crossbar, scan it for sources.
  3889.     long inputs, outputs;
  3890.     int currentSourceIndex = -1;
  3891.  
  3892.     if (SUCCEEDED(pCrossbar->get_PinCounts(&outputs, &inputs))) {
  3893.         long currentSource = -1;
  3894.  
  3895.         VDVERIFY(SUCCEEDED(pCrossbar->get_IsRoutedTo(output, &currentSource)));
  3896.  
  3897.         for(int pin=0; pin<inputs; ++pin) {
  3898.             // get pin type
  3899.             long relatedPin;
  3900.             long physType;
  3901.             if (FAILED(pCrossbar->get_CrossbarPinInfo(TRUE, pin, &relatedPin, &physType)))
  3902.                 continue;
  3903.  
  3904.             // check if this input can be routed to the audio output
  3905.             if (S_OK != pCrossbar->CanRoute(output, pin))
  3906.                 continue;
  3907.  
  3908.             // check if this is the current pin
  3909.             if (pin == currentSource)
  3910.                 currentSourceIndex = sources.size();
  3911.  
  3912.             // add entry for this pin
  3913.             sources.push_back(InputSource(pin, physType, VDStringW(VDGetNameForPhysicalConnectorTypeDShow((PhysicalConnectorType)physType))));
  3914.         }
  3915.  
  3916.         // If the crossbar is current set to -1, we force it to the first source for two reasons.
  3917.         // One is so that we get audio/video by default. The other is so that we're sure that
  3918.         // the source index we return is consistent. get_IsRoutedTo() has a nasty habit of
  3919.         // returning -1 when the graph is stopped or paused, even if a route actually exists.
  3920.         if (currentSource < 0 && !sources.empty()) {
  3921.             HRESULT hr = pCrossbar->Route(output, sources.front().mCrossbarPin);
  3922.             if (SUCCEEDED(hr))
  3923.                 currentSourceIndex = 0;
  3924.         }
  3925.     }
  3926.  
  3927.     return currentSourceIndex;
  3928. }
  3929.  
  3930. int VDCaptureDriverDS::UpdateCrossbarSource(InputSources& sources, IAMCrossbar *pCrossbar, int output) {
  3931.     // If there is an audio crossbar, scan it for sources.
  3932.     long inputs, outputs;
  3933.     HRESULT hr = pCrossbar->get_PinCounts(&outputs, &inputs);
  3934.  
  3935.     if (FAILED(hr)) {
  3936.         VDLog(kVDLogWarning, VDStringW(L"CapDShow: Unable to retrieve crossbar pin counts.\n"));
  3937.         return -1;
  3938.     }
  3939.  
  3940.     long currentSource = -1;
  3941.  
  3942.     hr = pCrossbar->get_IsRoutedTo(output, &currentSource);
  3943.     if (FAILED(hr)) {
  3944.         VDLog(kVDLogWarning, VDStringW(L"CapDShow: Unable to retrieve crossbar output pin routing.\n"));
  3945.         return -1;
  3946.     }
  3947.  
  3948.     if (hr == S_FALSE || currentSource == -1)
  3949.         return -1;
  3950.  
  3951.     InputSources::const_iterator it(sources.begin()), itEnd(sources.end());
  3952.     int index = 0;
  3953.     for(; it!=itEnd; ++it, ++index) {
  3954.         const InputSource& src = *it;
  3955.  
  3956.         if (src.mCrossbarPin == currentSource)
  3957.             return index;
  3958.     }
  3959.  
  3960.     VDLog(kVDLogWarning, VDStringW(L"CapDShow: Current crossbar pin does not correspond to a known source.\n"));
  3961.     return -1;
  3962. }
  3963.  
  3964. void VDCaptureDriverDS::DoEvents() {
  3965.     long evCode;
  3966.     LONG_PTR param1, param2;
  3967.  
  3968.     while(SUCCEEDED(mpMediaEventEx->GetEvent(&evCode, &param1, &param2, 0))) {
  3969. #if 0
  3970.         if (mpEventCallback)
  3971.             switch(evCode) {
  3972.             case EC_VIDEO_SIZE_CHANGED:
  3973.                 mpEventCallback->EventVideoSizeChanged(LOWORD(param1), HIWORD(param1));
  3974.                 break;
  3975.             }
  3976. #endif
  3977.         switch(evCode) {
  3978.         case EC_ERRORABORT:
  3979.             VDDEBUG("Cap/DShow: Error abort detected: hr=%08x (%s)\n", (int)param1, GetDXErrorName((HRESULT)param1));
  3980.             break;
  3981.         default:
  3982.             VDDEBUG("Cap/DShow: Unknown event %08x detected\n", (int)evCode);
  3983.             break;
  3984.         }
  3985.  
  3986.         mpMediaEventEx->FreeEventParams(evCode, param1, param2);
  3987.     }
  3988. }
  3989.  
  3990. LRESULT CALLBACK VDCaptureDriverDS::StaticMessageSinkWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  3991.     if (msg == WM_NCCREATE)
  3992.         SetWindowLongPtr(hwnd, 0, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
  3993.  
  3994.     VDCaptureDriverDS *pThis = (VDCaptureDriverDS *)GetWindowLongPtr(hwnd, 0);
  3995.  
  3996.     return pThis ? pThis->MessageSinkWndProc(hwnd, msg, wParam, lParam) : DefWindowProc(hwnd, msg, wParam, lParam);
  3997. }
  3998.  
  3999. LRESULT VDCaptureDriverDS::MessageSinkWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  4000.     if (msg == WM_APP)
  4001.         DoEvents();
  4002.     else if (msg == WM_APP+1)
  4003.         CaptureStop();
  4004.     else {
  4005.         VideoWindows::const_iterator it(mVideoWindows.begin()), itEnd(mVideoWindows.end());
  4006.         for(; it!=itEnd; ++it) {
  4007.             const IVideoWindowPtr& p = *it;
  4008.  
  4009.             p->NotifyOwnerMessage((OAHWND)hwnd, msg, wParam, lParam);
  4010.         }
  4011.     }
  4012.  
  4013.     return DefWindowProc(hwnd, msg, wParam, lParam);
  4014. }
  4015.  
  4016. bool VDCaptureDriverDS::CapTryEnterCriticalSection() {
  4017.     return mGraphStateLock.TryWait();
  4018. }
  4019.  
  4020. void VDCaptureDriverDS::CapProcessData(int stream, const void *data, uint32 size, sint64 timestamp, bool key) {
  4021.     if (mpCaptureError)
  4022.         return;
  4023.  
  4024.     if (mpCB) {
  4025.         sint64 reltime = (sint64)(VDGetAccurateTick() - mCaptureStart) * 1000;
  4026.  
  4027.         try {
  4028.             if (!mCaptureStopQueued) {
  4029.                 if (mCaptureThread) {
  4030.                     if (!mpCB->CapEvent(kEventCapturing, 0)) {
  4031.                         if (!mCaptureStopQueued.xchg(1))
  4032.                             PostMessage(mhwndEventSink, WM_APP+1, 0, 0);
  4033.  
  4034.                         goto skip_processing;
  4035.                     }
  4036.                 }
  4037.  
  4038.                 mpCB->CapProcessData(stream, data, size, timestamp, key, reltime);
  4039. skip_processing:
  4040.                 ;
  4041.             }
  4042.         } catch(MyError& e) {
  4043.             MyError *e2 = new MyError;
  4044.             e2->TransferFrom(e);
  4045.             delete mpCaptureError.xchg(e2);
  4046.  
  4047.             if (!mCaptureStopQueued.xchg(1))
  4048.                 PostMessage(mhwndEventSink, WM_APP+1, 0, 0);
  4049.         }
  4050.     }
  4051. }
  4052.  
  4053. void VDCaptureDriverDS::CapLeaveCriticalSection() {
  4054.     mGraphStateLock.Post();
  4055. }
  4056.  
  4057. ///////////////////////////////////////////////////////////////////////////
  4058. //
  4059. //  capture system: DirectShow
  4060. //
  4061. ///////////////////////////////////////////////////////////////////////////
  4062.  
  4063. class VDCaptureSystemDS : public IVDCaptureSystem {
  4064. public:
  4065.     VDCaptureSystemDS();
  4066.     ~VDCaptureSystemDS();
  4067.  
  4068.     void EnumerateDrivers();
  4069.  
  4070.     int GetDeviceCount();
  4071.     const wchar_t *GetDeviceName(int index);
  4072.  
  4073.     IVDCaptureDriver *CreateDriver(int deviceIndex);
  4074.  
  4075. protected:
  4076.     int mDriverCount;
  4077.  
  4078.     tDeviceVector mVideoDevices;
  4079. };
  4080.  
  4081. IVDCaptureSystem *VDCreateCaptureSystemDS() {
  4082.     return new VDCaptureSystemDS;
  4083. }
  4084.  
  4085. VDCaptureSystemDS::VDCaptureSystemDS()
  4086.     : mDriverCount(0)
  4087. {
  4088.     CoInitialize(NULL);
  4089. }
  4090.  
  4091. VDCaptureSystemDS::~VDCaptureSystemDS() {
  4092.     mVideoDevices.clear();      // must clear this first before COM goes away
  4093.     CoUninitialize();
  4094. }
  4095.  
  4096. void VDCaptureSystemDS::EnumerateDrivers() {
  4097.     mDriverCount = 0;
  4098.     mVideoDevices.clear();
  4099.  
  4100.     Enumerate(mVideoDevices, CLSID_VideoInputDeviceCategory);
  4101.     mDriverCount = mVideoDevices.size();
  4102. }
  4103.  
  4104. int VDCaptureSystemDS::GetDeviceCount() {
  4105.     return mDriverCount;
  4106. }
  4107.  
  4108. const wchar_t *VDCaptureSystemDS::GetDeviceName(int index) {
  4109.     if ((unsigned)index >= (unsigned)mDriverCount)
  4110.         return NULL;
  4111.  
  4112.     return mVideoDevices[index].second.c_str();
  4113. }
  4114.  
  4115. IVDCaptureDriver *VDCaptureSystemDS::CreateDriver(int index) {
  4116.     if ((unsigned)index >= (unsigned)mDriverCount)
  4117.         return NULL;
  4118.  
  4119.     return new VDCaptureDriverDS(mVideoDevices[index].first);
  4120. }
Advertisement
Add Comment
Please, Sign In to add comment