home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / vdremote / Main.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  23.1 KB  |  905 lines

  1. #include <crtdbg.h>
  2. #include <objbase.h>
  3.  
  4. #include "clsid.h"
  5. #include "vdremote.h"
  6. #include "vdserver.h"
  7.  
  8. #pragma warning(disable: 4355)        // warning C4355: 'this' : used in base member initializer list
  9.  
  10. long CAVIFileRemote::gRefCnt = 0;
  11. long CAVIStreamRemote::gRefCnt = 0;
  12.  
  13. ////////////////////////////////////////////////////////////
  14.  
  15. const GUID CDECL CLSID_AVIFile
  16.     = { 0x00020000, 0, 0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  17.  
  18. const GUID CDECL another_IID_IAVIFile
  19.     = { 0x00020020, 0, 0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  20.  
  21. const GUID CDECL another_IID_IAVIStream
  22.     = { 0x00020021, 0, 0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
  23.  
  24. const GUID CDECL CLSID_Avisynth
  25.     = { 0xE6D6B700, 0x124D, 0x11D4, 0x86, 0xF3, 0xDB, 0x80, 0xAF, 0xD9, 0x87, 0x78};
  26.  
  27. ////////////////////////////////////////////////////////////
  28.  
  29. BOOL APIENTRY DllMain(HANDLE hModule, ULONG ulReason, LPVOID lpReserved) {
  30.  
  31.     switch(ulReason) {
  32.     case DLL_PROCESS_ATTACH:
  33.         CoInitialize(NULL);
  34.         _RPT0(0,"Process attach\n");
  35.         break;
  36.  
  37.     case DLL_PROCESS_DETACH:
  38.         CoUninitialize();
  39.         _RPT0(0,"Process detach\n");
  40.         break;
  41.     }
  42.  
  43.     return TRUE;
  44. }
  45.  
  46. const GUID CDECL CLSID_CAVIFileRemote
  47.     = {0x894288e0,0x0948,0x11d2,{0x81,0x09,0x00,0x48,0x45,0x00,0x0e,0xb5}};
  48. const GUID CDECL CLSID_CAVIStreamRemote
  49.     = {0x91379540,0x0948,0x11d2,{0x81,0x09,0x00,0x48,0x45,0x00,0x0e,0xb5}};
  50.  
  51. // From the Microsoft AVIFile docs.  Dense code...
  52.  
  53. extern "C" STDAPI DllGetClassObject(const CLSID& rclsid, const IID& riid, void **ppv);
  54.  
  55. STDAPI DllGetClassObject(const CLSID& rclsid, const IID& riid, void **ppv) {
  56.     HRESULT hresult;
  57.  
  58.     _RPT0(0,"DllGetClassObject()\n");
  59.  
  60.     if (rclsid == CLSID_CAVIStreamRemote) {
  61.         _RPT0(0,"\tCLSID: CAVIStreamRemote\n");
  62.         hresult = CAVIStreamRemote::Create(rclsid, riid, ppv);
  63.     } else { // if (rclsid == CLSID_CAVIStreamRemote) {
  64.         _RPT0(0,"\tCLSID: CAVIFileRemote (default) \n");
  65.         hresult = CAVIFileRemote::Create(rclsid, riid, ppv);
  66.     }
  67.  
  68.     _RPT0(0,"DllGetClassObject() exit\n");
  69.  
  70.     return hresult;
  71. }
  72.  
  73. extern "C" STDAPI DllCanUnloadNow();
  74.  
  75. STDAPI DllCanUnloadNow() {
  76.     _RPT2(0,"DllCanUnloadNow(): CAVIFileRemote %ld, CAVIStreamRemote %ld\n", CAVIFileRemote::gRefCnt, CAVIStreamRemote::gRefCnt);
  77.  
  78.     return (CAVIFileRemote::gRefCnt || CAVIStreamRemote::gRefCnt) ? S_FALSE : S_OK;
  79. }
  80.  
  81.  
  82. ///////////////////////////////////////////////////////////////////////////
  83. //
  84. //    CAVIFileRemote
  85. //
  86. ///////////////////////////////////////////////////////////////////////////
  87.  
  88.  
  89. HRESULT CAVIFileRemote::CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,  void * * ppvObj) {
  90.     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
  91.  
  92.     return Create(CLSID_CAVIFileRemote, riid, ppvObj);
  93. }
  94.  
  95. HRESULT CAVIFileRemote::LockServer (BOOL fLock) {
  96.     _RPT1(0,"%p->CAVIFileRemote::LockServer()\n", this);
  97.     return S_OK;
  98. }
  99.  
  100. STDMETHODIMP CAVIFileRemote::GetClassID(LPCLSID lpClassID) {
  101.     _RPT1(0,"%p->CAVIFileRemote::GetClassID()\n", this);
  102.  
  103.     *lpClassID = CLSID_CAVIFileRemote;
  104.  
  105.     return S_OK;
  106. }
  107.  
  108. STDMETHODIMP CAVIFileRemote::IsDirty() {
  109.     _RPT1(0,"%p->CAVIFileRemote::IsDirty()\n", this);
  110.     return S_FALSE;
  111. }
  112.  
  113. STDMETHODIMP CAVIFileRemote::Load(LPCOLESTR lpszFileName, DWORD grfMode) {
  114.     char filename[MAX_PATH];
  115.  
  116.     _RPT1(0,"%p->CAVIFileRemote::Load()\n", this);
  117.  
  118.     WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, lpszFileName, -1, filename, sizeof filename, NULL, NULL); 
  119.  
  120.     return Open(filename, grfMode, lpszFileName);
  121. }
  122.  
  123. STDMETHODIMP CAVIFileRemote::Save(LPCOLESTR lpszFileName, BOOL fRemember) {
  124.     _RPT1(0,"%p->CAVIFileRemote::Save()\n", this);
  125.     return E_FAIL;
  126. }
  127.  
  128. STDMETHODIMP CAVIFileRemote::SaveCompleted(LPCOLESTR lpszFileName) {
  129.     _RPT1(0,"%p->CAVIFileRemote::SaveCompleted()\n", this);
  130.     return S_OK;
  131. }
  132.  
  133. STDMETHODIMP CAVIFileRemote::GetCurFile(LPOLESTR *lplpszFileName) {
  134.     _RPT1(0,"%p->CAVIFileRemote::GetCurFile()\n", this);
  135.     *lplpszFileName = NULL;
  136.  
  137.     return E_FAIL;
  138. }
  139.  
  140. ///////////////////////////////////////////////////
  141.  
  142. HRESULT CAVIFileRemote::Create(const CLSID& rclsid, const IID& riid, void **ppv) {
  143.     CAVIFileRemote *pAVIFileRemote;
  144.     HRESULT hresult;
  145.  
  146.     _RPT0(0,"CAVIFileRemote::Create()\n");
  147.  
  148.     pAVIFileRemote = new CAVIFileRemote(rclsid);
  149.  
  150.     if (!pAVIFileRemote) return ResultFromScode(E_OUTOFMEMORY);
  151.  
  152.     hresult = pAVIFileRemote->QueryInterface(riid, ppv);
  153.     pAVIFileRemote->Release();
  154.     if (FAILED(GetScode(hresult))) {
  155.         _RPT0(0,"failed!\n");
  156.     }
  157.  
  158.     _RPT0(0,"CAVIFileRemote::Create() exit\n");
  159.  
  160.     return hresult;
  161. }
  162.  
  163. STDMETHODIMP CAVIFileRemote::QueryInterface(const IID& iid, void **ppv) {
  164.     _RPT1(0,"%08lx->CAVIFileRemote::QueryInterface()\n", this);
  165.  
  166.     _RPT3(0,"\tGUID: {%08lx-%04x-%04x-", iid.Data1, iid.Data2, iid.Data3);
  167.     _RPT4(0,"%02x%02x-%02x%02x", iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3]);
  168.     _RPT4(0,"%02x%02x%02x%02x} (", iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7]);
  169.  
  170.     if (iid == IID_IUnknown) {
  171.         *ppv = (IUnknown *)(IAVIFile *)this;
  172.         _RPT0(0,"IUnknown)\n");
  173.     } else if (iid == IID_IClassFactory) {
  174.         *ppv = (IClassFactory *)this;
  175.         _RPT0(0,"IClassFactory)\n");
  176.     } else if (iid == IID_IPersist) {
  177.         *ppv = (IPersist *)this;
  178.         _RPT0(0,"IPersist)\n");
  179.     } else if (iid == IID_IPersistFile) {
  180.         *ppv = (IPersistFile *)this;
  181.         _RPT0(0,"IPersistFile)\n");
  182.     } else if (iid == another_IID_IAVIFile) {
  183.         *ppv = (IAVIFile *)this;
  184.         _RPT0(0,"IAVIFile)\n");
  185.     } else {
  186.         _RPT0(0,"unknown!)\n");
  187.         *ppv = NULL;
  188.         return ResultFromScode(E_NOINTERFACE);
  189.     }
  190.  
  191.     AddRef();
  192.  
  193.     return NULL;
  194. }
  195.  
  196. STDMETHODIMP_(ULONG) CAVIFileRemote::AddRef() {
  197.     _RPT1(0,"%p->CAVIFileRemote::AddRef()\n", this);
  198.     ++gRefCnt;
  199.     return ++m_refs;
  200. }
  201.  
  202. STDMETHODIMP_(ULONG) CAVIFileRemote::Release() {
  203.     _RPT1(0,"%p->CAVIFileRemote::Release()\n", this);
  204.  
  205.     if (!--m_refs)
  206.         delete this;
  207.  
  208.     --gRefCnt;
  209.  
  210.     _RPT0(0,"CAVIFileRemote::Release() exit\n");
  211.  
  212.     return m_refs;
  213. }
  214.  
  215. ///////////////////////////////////////////////////////////////////////////
  216. //
  217. //    CAVIStreamRemote - binding glue
  218. //
  219. ///////////////////////////////////////////////////////////////////////////
  220.  
  221. CAVIStreamClassFactory::CAVIStreamClassFactory(CAVIStreamRemote *af) {
  222.     avifile = af;
  223. }
  224.  
  225. HRESULT CAVIStreamClassFactory::QueryInterface (REFIID riid, void * * ppvObj) {
  226.     return avifile->QueryInterface(riid, ppvObj);
  227. }
  228.  
  229. unsigned long  CAVIStreamClassFactory::AddRef () {
  230.     return avifile->AddRef();
  231. }
  232.  
  233. unsigned long  CAVIStreamClassFactory::Release () {
  234.     return avifile->Release();
  235. }
  236.  
  237. HRESULT CAVIStreamClassFactory::CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid,  void * * ppvObj) {
  238.     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
  239.  
  240.     return avifile->Create(CLSID_CAVIFileRemote, riid, ppvObj);
  241. }
  242.  
  243. HRESULT CAVIStreamClassFactory::LockServer (BOOL fLock) {
  244.     return S_OK;
  245. }
  246.  
  247. ///////////////////////
  248.  
  249. HRESULT CAVIStreamRemote::Create(const CLSID& rclsid, const IID& riid, void **ppv) {
  250.     CAVIStreamRemote *pAVIStreamRemote;
  251.     IUnknown *pUnknown;
  252.     HRESULT hresult;
  253.  
  254.     _RPT0(0,"CAVIStreamRemote::Create()\n");
  255.  
  256.     pAVIStreamRemote = new CAVIStreamRemote(rclsid, (void **)&pUnknown);
  257.  
  258.     if (!pAVIStreamRemote) return ResultFromScode(E_OUTOFMEMORY);
  259.  
  260.     hresult = pUnknown->QueryInterface(riid, ppv);
  261.     pAVIStreamRemote->Release();
  262.     if (FAILED(GetScode(hresult))) {
  263.         _RPT0(0,"Failed!\n");
  264.     }
  265.  
  266.     _RPT0(0,"CAVIStreamRemote::Create() exit\n");
  267.  
  268.     return hresult;
  269. }
  270.  
  271. STDMETHODIMP CAVIStreamRemote::QueryInterface(const IID& iid, void **ppv) {
  272.     _RPT1(0,"%08lx->CAVIStreamRemote::QueryInterface()\n", this);
  273.  
  274.     _RPT3(0,"\tGUID: {%08lx-%04x-%04x-", iid.Data1, iid.Data2, iid.Data3);
  275.     _RPT4(0,"%02x%02x-%02x%02x", iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3]);
  276.     _RPT4(0,"%02x%02x%02x%02x} (", iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7]);
  277.  
  278.     if (iid == IID_IUnknown) {
  279.         *ppv = (IUnknown *)this;
  280.         _RPT0(0,"IUnknown)\n");
  281.     } else if (iid == IID_IClassFactory) {
  282.         *ppv = (IClassFactory *)&iclassfactory;
  283.         _RPT0(0,"IClassFactory)\n");
  284.     } else if (iid == IID_IAVIStream) {
  285.         *ppv = (IAVIStream *)this;
  286.         _RPT0(0,"IAVIStream)\n");
  287.     } else {
  288.         _RPT0(0,"unknown)\n");
  289.         *ppv = NULL;
  290.         return ResultFromScode(E_NOINTERFACE);
  291.     }
  292.  
  293.     AddRef();
  294.  
  295.     return NULL;
  296. }
  297.  
  298. STDMETHODIMP_(ULONG) CAVIStreamRemote::AddRef() {
  299.     _RPT0(0,"CAVIStreamRemote::AddRef()\n");
  300.  
  301.     ++gRefCnt;
  302.     return ++m_refs;
  303. }
  304.  
  305. STDMETHODIMP_(ULONG) CAVIStreamRemote::Release() {
  306.     _RPT0(0,"CAVIStreamRemote::Release()\n");
  307.  
  308.     if (!--m_refs)
  309.         delete this;
  310.  
  311.     --gRefCnt;
  312.  
  313.     _RPT0(0,"CAVIStreamRemote::Release() exit\n");
  314.  
  315.     return m_refs;
  316. }
  317.  
  318. ////////////////////////////////////////////////////////////////////////
  319. //
  320. //        CAVIFileRemote
  321. //
  322. ////////////////////////////////////////////////////////////////////////
  323.  
  324. STDMETHODIMP CAVIFileRemote::CreateStream(PAVISTREAM *ppStream, AVISTREAMINFOW *psi) {
  325.     _RPT1(0,"%p->CAVIFileRemote::CreateStream()\n", this);
  326.  
  327.     if (pafTunnel)
  328.         return pafTunnel->CreateStream(ppStream, psi);
  329.  
  330.     return AVIERR_READONLY;
  331. }
  332.  
  333. STDMETHODIMP CAVIFileRemote::EndRecord() {
  334.     _RPT1(0,"%p->CAVIFileRemote::EndRecord()\n", this);
  335.  
  336.     if (pafTunnel)
  337.         return pafTunnel->EndRecord();
  338.  
  339.     return AVIERR_READONLY;
  340. }
  341.  
  342. STDMETHODIMP CAVIFileRemote::Save(LPCSTR szFile, AVICOMPRESSOPTIONS FAR *lpOptions,
  343.                 AVISAVECALLBACK lpfnCallback) {
  344.     _RPT1(0,"%p->CAVIFileRemote::Save()\n", this);
  345.  
  346.     return AVIERR_READONLY;
  347. }
  348.  
  349. STDMETHODIMP CAVIFileRemote::ReadData(DWORD fcc, LPVOID lp, LONG *lpcb) {
  350.     _RPT1(0,"%p->CAVIFileRemote::ReadData()\n", this);
  351.  
  352.     if (pafTunnel)
  353.         return pafTunnel->ReadData(fcc, lp, lpcb);
  354.  
  355.     return AVIERR_NODATA;
  356. }
  357.  
  358. STDMETHODIMP CAVIFileRemote::WriteData(DWORD fcc, LPVOID lpBuffer, LONG cbBuffer) {
  359.     _RPT1(0,"%p->CAVIFileRemote::WriteData()\n", this);
  360.  
  361.     if (pafTunnel)
  362.         return pafTunnel->WriteData(fcc, lpBuffer, cbBuffer);
  363.  
  364.     return AVIERR_READONLY;
  365. }
  366.  
  367. STDMETHODIMP CAVIFileRemote::DeleteStream(DWORD fccType, LONG lParam) {
  368.     _RPT1(0,"%p->CAVIFileRemote::DeleteStream()\n", this);
  369.  
  370.     if (pafTunnel)
  371.         return pafTunnel->DeleteStream(fccType, lParam);
  372.  
  373.     return AVIERR_READONLY;
  374. }
  375.  
  376.  
  377.  
  378.  
  379. CAVIFileRemote::CAVIFileRemote(const CLSID& rclsid) {
  380.     _RPT0(0,"CAVIFileRemote::CAVIFileRemote()\n");
  381.  
  382.     m_refs = 0; AddRef();
  383.  
  384.     szPath = NULL;
  385.     ivdsl = NULL;
  386.     ivdac = NULL;
  387.     vFormat = NULL;
  388.     aFormat = NULL;
  389.     pafTunnel = NULL;
  390.  
  391.     InitializeCriticalSection(&csPort);
  392. }
  393.  
  394. CAVIFileRemote::~CAVIFileRemote() {
  395.     _RPT0(0,"CAVIFileRemote::~CAVIFileRemote()\n");
  396.  
  397.     DeleteCriticalSection(&csPort);
  398.  
  399.     if (ivdac) ivdsl->FrameServerDisconnect(ivdac);
  400.     delete szPath;
  401.  
  402.     if (pafTunnel)
  403.         pafTunnel->Release();
  404. }
  405.  
  406.  
  407. STDMETHODIMP CAVIFileRemote::Open(LPCSTR szFile, UINT mode, LPCOLESTR lpszFileName) {
  408.     HMMIO hmmio = NULL;
  409.     MMCKINFO mmiriff, mmi;
  410.     MMRESULT mmerr;
  411.     HRESULT final = S_OK;
  412.  
  413.     _RPT2(0,"CAVIFileRemote::Open(\"%s\", %08lx)\n", szFile, mode);
  414.  
  415.     if (pafTunnel) {
  416.         pafTunnel->Release();
  417.         pafTunnel = NULL;
  418.     }
  419.  
  420.     if (mode & (OF_CREATE|OF_WRITE)) {
  421.         IPersistFile *ppf;
  422.  
  423.         if (FAILED(CoCreateInstance(CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  424.             return (HRESULT)E_FAIL;
  425.  
  426.         if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  427.             return (HRESULT)E_FAIL;
  428.  
  429.         HRESULT hr = ppf->Load(lpszFileName, mode);
  430.  
  431.         ppf->Release();
  432.  
  433.         return hr;
  434.     }
  435.  
  436.     if (!(hmmio = mmioOpen((char *)szFile, NULL, MMIO_READ)))
  437.         return E_FAIL;
  438.  
  439.     _RPT0(0,"File opened.\n");
  440.  
  441.     // RIFF <size> VDRM { PATH <remote-path> }
  442.  
  443.     try {
  444.         char buf[16];
  445.  
  446.         _RPT0(0,"Checking for Avisynth signature...\n");
  447.  
  448.         if (16==mmioRead(hmmio, buf, 16)) {
  449.             buf[9] = 0;
  450.             if (!_stricmp(buf, "#avisynth")) {
  451.  
  452.                 mmioClose(hmmio, 0);
  453.  
  454.                 // Hand it off to the Avisynth handler.
  455.  
  456.                 IPersistFile *ppf;
  457.  
  458.                 // Okay, it's not one of our files.  Now try passing it off
  459.                 // to the regular AVI handler!
  460.  
  461.                 _RPT0(0,"Attempt avisynth tunnel create\n");
  462.  
  463.                 if (FAILED(CoCreateInstance(CLSID_Avisynth, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  464.                     return (HRESULT)E_FAIL;
  465.  
  466.                 _RPT0(0,"Attempt avisynth tunnel query -> IPersistFile\n");
  467.  
  468.                 if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  469.                     return (HRESULT)E_FAIL;
  470.  
  471.                 _RPT0(0,"Attempt avisynth tunnel load\n");
  472.  
  473.                 HRESULT hr = ppf->Load(lpszFileName, mode);
  474.  
  475.                 ppf->Release();
  476.  
  477.                 return hr;
  478.             }
  479.         }
  480.  
  481.         mmioSeek(hmmio, 0, SEEK_SET);
  482.  
  483.         _RPT0(0,"Attempting to find 'VDRM'...\n");
  484.  
  485.         mmiriff.fccType = 'MRDV';
  486.         mmerr = mmioDescend(hmmio, &mmiriff, NULL, MMIO_FINDRIFF);
  487.         if (mmerr == MMIOERR_CHUNKNOTFOUND) {
  488.             IPersistFile *ppf;
  489.  
  490.             mmioClose(hmmio, 0);
  491.  
  492.             // Okay, it's not one of our files.  Now try passing it off
  493.             // to the regular AVI handler!
  494.  
  495.             _RPT0(0,"Attempt tunnel create\n");
  496.  
  497.             if (FAILED(CoCreateInstance(CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, another_IID_IAVIFile, (void **)&pafTunnel)))
  498.                 return (HRESULT)E_FAIL;
  499.  
  500.             _RPT0(0,"Attempt tunnel query -> IPersistFile\n");
  501.  
  502.             if (FAILED(pafTunnel->QueryInterface(IID_IPersistFile, (void **)&ppf)))
  503.                 return (HRESULT)E_FAIL;
  504.  
  505.             _RPT0(0,"Attempt tunnel load\n");
  506.  
  507.             HRESULT hr = ppf->Load(lpszFileName, mode);
  508.  
  509.             ppf->Release();
  510.  
  511.             return hr;
  512.         }
  513.  
  514.         else if (mmerr != MMSYSERR_NOERROR) throw (HRESULT)E_FAIL;
  515.  
  516.         _RPT0(0,"Attempting to find 'PATH'...\n");
  517.         mmi.ckid = 'HTAP';
  518.         mmerr = mmioDescend(hmmio, &mmi, &mmiriff, MMIO_FINDCHUNK);
  519.         if (mmerr == MMIOERR_CHUNKNOTFOUND) throw (HRESULT)E_FAIL;
  520.         else if (mmerr != MMSYSERR_NOERROR) throw (HRESULT)E_FAIL;
  521.  
  522.         _RPT0(0,"Allocate path memory...\n");
  523.         if (!(szPath = new char[mmi.cksize+1]))
  524.             throw (HRESULT)E_OUTOFMEMORY;
  525.  
  526.         szPath[mmi.cksize]=0;
  527.  
  528.         _RPT0(0,"Read in path...\n");
  529.  
  530.         if ((LONG)mmi.cksize != mmioRead(hmmio, szPath, mmi.cksize))
  531.             throw (HRESULT)E_FAIL;
  532.  
  533.         _RPT1(0,"File parsed, remote-path: [%s]\n", szPath);
  534.  
  535.         // now attempt to open the link
  536.  
  537.         ivdsl = GetDubServerInterface();
  538.         if (!ivdsl) throw (HRESULT)E_FAIL;
  539.  
  540.         _RPT0(0,"Have dub server interface.\n");
  541.  
  542.         ivdac = ivdsl->FrameServerConnect(szPath);
  543.         if (!ivdac) throw (HRESULT)E_FAIL;
  544.  
  545.         // retrieve streaminfo and format information
  546.  
  547.         _RPT0(0,"Connected to frameserver.\n");
  548.  
  549.         fHasAudio = ivdac->hasAudio();
  550.  
  551.         _RPT0(0,"Reading video stream info...\n");
  552.  
  553.         if (!ivdac->readStreamInfo(&vStreamInfo, FALSE, &vSampleFirst, &vSampleLast))
  554.             throw (HRESULT)E_FAIL;
  555.  
  556.         _RPT0(0,"Reading video format length...\n");
  557.  
  558.         if ((vFormatLen = ivdac->readFormat(NULL, FALSE))<=0)
  559.             throw (HRESULT)E_FAIL;
  560.  
  561.         _RPT1(0,"Allocating video format (%ld bytes)...\n", vFormatLen);
  562.  
  563.         if (!(vFormat = (BITMAPINFOHEADER *)malloc(vFormatLen)))
  564.             throw (HRESULT)E_OUTOFMEMORY;
  565.  
  566.         _RPT0(0,"Reading video format...\n");
  567.  
  568.         if (ivdac->readFormat(vFormat, FALSE)<=0)
  569.             throw (HRESULT)E_FAIL;
  570.  
  571.         if (fHasAudio) {
  572.             _RPT0(0,"Reading audio stream info...\n");
  573.  
  574.             if (!ivdac->readStreamInfo(&aStreamInfo, TRUE, &aSampleFirst, &aSampleLast))
  575.                 throw (HRESULT)E_FAIL;
  576.  
  577.             _RPT0(0,"Reading audio format length...\n");
  578.  
  579.             if ((aFormatLen = ivdac->readFormat(NULL, TRUE))<=0)
  580.                 throw (HRESULT)E_FAIL;
  581.  
  582.             _RPT1(0,"Allocating audio format (%ld bytes)...\n", aFormatLen);
  583.  
  584.             if (!(aFormat = (WAVEFORMATEX *)malloc(aFormatLen)))
  585.                 throw (HRESULT)E_OUTOFMEMORY;
  586.  
  587.             _RPT0(0,"Reading audio format...\n");
  588.  
  589.             if (ivdac->readFormat(aFormat, TRUE)<=0)
  590.                 throw (HRESULT)E_FAIL;
  591.         }
  592.  
  593.     } catch(HRESULT res) {
  594.         _RPT0(0,"*** failed!\n");
  595.  
  596.         final = res;
  597.     }
  598.  
  599.     if (hmmio) mmioClose(hmmio, 0);
  600.  
  601.     _RPT0(0,"CAVIFileRemote::Open() exit\n");
  602.  
  603.     return final;
  604. }
  605.  
  606. STDMETHODIMP CAVIFileRemote::Info(AVIFILEINFOW *psi, LONG lSize) {
  607.     AVISTREAMINFO *asi;
  608.  
  609.     _RPT0(0,"CAVIFileRemote::Info()\n");
  610.  
  611.     if (pafTunnel)
  612.         return pafTunnel->Info(psi, lSize);
  613.     
  614.     if (!psi || !ivdac) return E_FAIL;
  615.  
  616.     psi->dwMaxBytesPerSec        = 0;
  617.     psi->dwFlags                = AVIFILEINFO_HASINDEX | AVIFILEINFO_ISINTERLEAVED;
  618.     psi->dwCaps                    = AVIFILECAPS_CANREAD | AVIFILECAPS_ALLKEYFRAMES | AVIFILECAPS_NOCOMPRESSION;
  619.     psi->dwStreams                = fHasAudio ? 2 : 1;
  620.     psi->dwSuggestedBufferSize    = 0;
  621.     psi->dwWidth                = vFormat->biWidth;
  622.     psi->dwHeight                = vFormat->biHeight;
  623.     psi->dwEditCount            = 0;
  624.     wcscpy(psi->szFileType, L"VirtualDub Remote AVI");
  625.  
  626.     // determine which stream is longer.
  627.     // v_dwRate / v_dwScale < a_dwRate / a_dwScale
  628.     // v_dwRate * a_dwScale < a_dwRate * v_dwScale
  629.     //
  630.     // DON'T: Panasonic uses AVISTREAMINFO.dwLength as the frame count!
  631.  
  632.     asi = &vStreamInfo;
  633.  
  634. //    if (fHasAudio && vStreamInfo.dwRate * aStreamInfo.dwScale < aStreamInfo.dwRate * vStreamInfo.dwScale)
  635. //        asi = &aStreamInfo;
  636.  
  637.     psi->dwRate                    = asi->dwRate;
  638.     psi->dwScale                = asi->dwScale;
  639.     psi->dwLength                = asi->dwLength;
  640.  
  641.     return 0;
  642. }
  643.  
  644. STDMETHODIMP CAVIFileRemote::GetStream(PAVISTREAM *ppStream, DWORD fccType, LONG lParam) {
  645.     CAVIStreamRemote *casr;
  646.  
  647.     _RPT4(0,"%p->CAVIFileRemote::GetStream(%p, %08lx, %ld)\n", this, ppStream, fccType, lParam);
  648.  
  649.     if (pafTunnel) {
  650.         HRESULT hr;
  651.         hr = pafTunnel->GetStream(ppStream, fccType, lParam);
  652.  
  653.         _RPT2(0,"%08lx %08lx\n", *ppStream, hr);
  654.  
  655.         return hr;
  656.     }
  657.  
  658.     *ppStream = NULL;
  659.  
  660.     if (!fccType) {
  661.         if (lParam==0) fccType = streamtypeVIDEO;
  662.         else if (lParam==1) {
  663.             lParam = 0;
  664.             fccType = streamtypeAUDIO;
  665.         }
  666.     }
  667.  
  668.     if (lParam > 0) return AVIERR_NODATA;
  669.  
  670.     if (fccType == streamtypeVIDEO) {
  671.         if (!(casr = new CAVIStreamRemote(this, FALSE, &vStreamInfo, vFormat, vFormatLen, vSampleFirst, vSampleLast)))
  672.             return AVIERR_MEMORY;
  673.  
  674.         *ppStream = (IAVIStream *)casr;
  675.  
  676.     } else if (fccType == streamtypeAUDIO) {
  677.         if (!fHasAudio) return AVIERR_NODATA;
  678.  
  679.         if (!(casr = new CAVIStreamRemote(this, TRUE, &aStreamInfo, aFormat, aFormatLen, aSampleFirst, aSampleLast)))
  680.             return AVIERR_MEMORY;
  681.  
  682.         *ppStream = (IAVIStream *)casr;
  683.     } else
  684.         return AVIERR_NODATA;
  685.  
  686.     return 0;
  687. }
  688.  
  689.  
  690.  
  691.  
  692.  
  693. void CAVIFileRemote::LockPort() {
  694.     EnterCriticalSection(&csPort);
  695. }
  696.  
  697. void CAVIFileRemote::UnlockPort() {
  698.     LeaveCriticalSection(&csPort);
  699. }
  700.  
  701.  
  702.  
  703. ////////////////////////////////////////////////////////////////////////
  704. //
  705. //        CAVIStreamRemote
  706. //
  707. ////////////////////////////////////////////////////////////////////////
  708.  
  709. STDMETHODIMP CAVIStreamRemote::Create(LPARAM lParam1, LPARAM lParam2) {
  710.     _RPT1(0,"%p->CAVIStreamRemote::Create()\n", this);
  711.     return AVIERR_READONLY;
  712. }
  713.  
  714. STDMETHODIMP CAVIStreamRemote::Delete(LONG lStart, LONG lSamples) {
  715.     _RPT1(0,"%p->CAVIStreamRemote::Delete()\n", this);
  716.     return AVIERR_READONLY;
  717. }
  718.  
  719. STDMETHODIMP CAVIStreamRemote::ReadData(DWORD fcc, LPVOID lp, LONG *lpcb) {
  720.     _RPT1(0,"%p->CAVIStreamRemote::ReadData()\n", this);
  721.     return AVIERR_NODATA;
  722. }
  723.  
  724. STDMETHODIMP CAVIStreamRemote::SetFormat(LONG lPos, LPVOID lpFormat, LONG cbFormat) {
  725.     _RPT1(0,"%p->CAVIStreamRemote::SetFormat()\n", this);
  726.     return AVIERR_READONLY;
  727. }
  728.  
  729. STDMETHODIMP CAVIStreamRemote::WriteData(DWORD fcc, LPVOID lpBuffer, LONG cbBuffer) {
  730.     _RPT1(0,"%p->CAVIStreamRemote::WriteData()\n", this);
  731.     return AVIERR_READONLY;
  732. }
  733.  
  734. STDMETHODIMP CAVIStreamRemote::SetInfo(AVISTREAMINFOW *psi, LONG lSize) {
  735.     return AVIERR_READONLY;
  736. }
  737.  
  738.  
  739.  
  740. CAVIStreamRemote::CAVIStreamRemote(const CLSID& rclsid, void **pUnknown) : iclassfactory(this) {
  741.     _RPT1(0,"%p->CAVIStreamRemote()\n", this);
  742.     m_refs = 0; AddRef();
  743.  
  744.     parent            = NULL;
  745.     streamInfo        = NULL;
  746.     wfexFormat        = NULL;
  747.     bmihFormat        = NULL;
  748. }
  749.  
  750. CAVIStreamRemote::CAVIStreamRemote(CAVIFileRemote *parentPtr, BOOL isAudio, AVISTREAMINFO *asi, void *format, long format_len, long sample_first, long sample_last) : iclassfactory(this) {
  751.     _RPT2(0,"%p->CAVIStreamRemote(%s)\n", this, isAudio ? "audio" : "video");
  752.     m_refs = 0; AddRef();
  753.  
  754.     parentPtr->AddRef();
  755.  
  756.     parent            = parentPtr;
  757.     fAudio            = isAudio;
  758.     streamInfo        = asi;
  759.     wfexFormat        = (WAVEFORMATEX *)format;
  760.     bmihFormat        = (BITMAPINFOHEADER *)format;
  761.     lFormatLen        = format_len;
  762.     lSampleFirst    = sample_first;
  763.     lSampleLast        = sample_last;
  764. }
  765.  
  766. CAVIStreamRemote::~CAVIStreamRemote() {
  767.     _RPT1(0,"%p->~CAVIStreamRemote()\n", this);
  768.  
  769.     parent->Release();
  770. }
  771.  
  772. STDMETHODIMP_(LONG) CAVIStreamRemote::Info(AVISTREAMINFOW *psi, LONG lSize) {
  773.     AVISTREAMINFOW asiw;
  774.  
  775.     _RPT3(0,"%p->CAVIStreamRemote::Info(%p, %ld)\n", this, psi, lSize);
  776.  
  777.     _RPT1(0,"stream length: %ld\n", streamInfo->dwLength);
  778.     memset(psi, 0, lSize);
  779.     memcpy(&asiw, streamInfo, sizeof(AVISTREAMINFO));
  780.     wcscpy(asiw.szName, fAudio ? L"VDub remote audio #1" : L"VDub remote video #1");
  781.     if (lSize < sizeof(AVISTREAMINFOW)) {
  782.         memcpy(psi, &asiw, lSize);
  783.     } else {
  784.         memcpy(psi, &asiw, sizeof(AVISTREAMINFOW));
  785.     }
  786.  
  787.     return 0;
  788. }
  789.  
  790. STDMETHODIMP_(LONG) CAVIStreamRemote::FindSample(LONG lPos, LONG lFlags) {
  791.     _RPT3(0,"%p->CAVIStreamRemote::FindSample(%ld, %08lx)\n", this, lPos, lFlags);
  792.  
  793.     if (lFlags & FIND_FORMAT)
  794.         return -1;
  795.  
  796.     if (lFlags & FIND_FROM_START)
  797.         return 0;
  798.  
  799.     return lPos;
  800. }
  801.  
  802. STDMETHODIMP CAVIStreamRemote::Read(LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG *plBytes, LONG *plSamples) {
  803.     HRESULT hres = 0;
  804.     int err;
  805.  
  806.     _RPT3(0,"%p->CAVIStreamRemote::Read(%ld samples at %ld)\n", this, lSamples, lStart);
  807.     _RPT2(0,"\tbuffer: %ld bytes at %p\n", cbBuffer, lpBuffer);
  808.  
  809.     parent->LockPort();
  810.  
  811.     if (plSamples) *plSamples = 0;
  812.     if (plBytes) *plBytes = 0;
  813.  
  814.     // Panasonic does some bad things if you give it fewer samples than it asks for,
  815.     // particularly if cbBuffer is 0 and lpBuffer = NULL.
  816.  
  817.     if (fAudio) {
  818.         LONG lABytes, lASamples;
  819.  
  820.         if (lSamples == AVISTREAMREAD_CONVENIENT)
  821.             lSamples = cbBuffer;
  822.  
  823.             while(lSamples > 0) {
  824.                 err = parent->ivdac->readAudio(lStart, lSamples, lpBuffer, cbBuffer, &lABytes, &lASamples);
  825.  
  826.                 if (err == VDSRVERR_TOOBIG || !lASamples)
  827.                     break;
  828.  
  829.                 if (err != VDSRVERR_OK) {
  830.                     hres = AVIERR_FILEREAD;
  831.                     break;
  832.                 }
  833.  
  834.                 if (plBytes)
  835.                     *plBytes += lABytes;
  836.  
  837.                 if (plSamples)
  838.                     *plSamples += lASamples;
  839.  
  840.                 if (lpBuffer)
  841.                     lpBuffer = (char *)lpBuffer + lABytes;
  842.  
  843.                 cbBuffer -= lABytes;
  844.                 lStart += lASamples;
  845.                 lSamples -= lASamples;
  846.             }
  847.     } else {
  848.         if (lSamples == AVISTREAMREAD_CONVENIENT)
  849.             lSamples = 1;
  850.  
  851.         if (!lpBuffer) {
  852.             if (plSamples) *plSamples = 1;
  853.             if (plBytes) *plBytes = bmihFormat->biSizeImage;
  854.         } else if (cbBuffer < (long)bmihFormat->biSizeImage) {
  855.             _RPT1(0,"\tBuffer too small; should be %ld samples\n", bmihFormat->biSizeImage);
  856.             hres = AVIERR_BUFFERTOOSMALL;
  857.             if (plSamples) *plSamples = 1;
  858.             if (plBytes) *plBytes = bmihFormat->biSizeImage;
  859.         } else {
  860.             _RPT0(0,"\tAttempting to read\n");
  861.             err = parent->ivdac->readVideo(lStart, lpBuffer);
  862.             if (!err) {
  863.                 _RPT0(0,"\tRead successful\n");
  864.                 if (plSamples) *plSamples = 1;
  865.                 if (plBytes) *plBytes = bmihFormat->biSizeImage;
  866.             } else {
  867.                 _RPT0(0,"\tError!\n");
  868.                 hres = AVIERR_FILEREAD;
  869.             }
  870.         }
  871.     }
  872.  
  873.     parent->UnlockPort();
  874.  
  875.     return hres;
  876. }
  877.  
  878. STDMETHODIMP CAVIStreamRemote::ReadFormat(LONG lPos, LPVOID lpFormat, LONG *lpcbFormat) {
  879.     _RPT1(0,"%p->CAVIStreamRemote::ReadFormat()\n", this);
  880.  
  881.     if (!lpFormat) {
  882.         *lpcbFormat = lFormatLen;
  883.         return S_OK;
  884.     }
  885.  
  886.     if (*lpcbFormat < lFormatLen)
  887.         memcpy(lpFormat, wfexFormat, *lpcbFormat);
  888.     else {
  889.         memcpy(lpFormat, wfexFormat, lFormatLen);
  890.         *lpcbFormat = lFormatLen;
  891.     }
  892.  
  893.     return S_OK;
  894. }
  895.  
  896. STDMETHODIMP CAVIStreamRemote::Write(LONG lStart, LONG lSamples, LPVOID lpBuffer,
  897.     LONG cbBuffer, DWORD dwFlags, LONG FAR *plSampWritten, 
  898.     LONG FAR *plBytesWritten) {
  899.  
  900.     _RPT1(0,"%p->CAVIStreamRemote::Write()\n", this);
  901.  
  902.     return AVIERR_READONLY;
  903. }
  904.  
  905.