home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / source.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-18  |  11.5 KB  |  490 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992 - 1996  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11.  
  12. // Implements CSource. A Quartz source filter 'template', March 1995
  13.  
  14. // Locking Strategy.
  15. //
  16. // Hold the filter critical section (m_pFilter->pStateLock()) to serialise
  17. // access to functions. Note that, in general, this lock may be held
  18. // by a function when the worker thread may want to hold it. Therefore
  19. // if you wish to access shared state from the worker thread you will
  20. // need to add another critical section object. The execption is during
  21. // the threads processing loop, when it is safe to get the filter critical
  22. // section from within FillBuffer().
  23.  
  24. #include <streams.h>
  25.  
  26.  
  27. //
  28. // CSource::Constructor
  29. //
  30. // Initialise the pin count for the filter. The user will create the pins in
  31. // the derived class.
  32. CSource::CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr)
  33.     : CBaseFilter(pName, lpunk, &m_cStateLock, clsid, phr),
  34.       m_iPins(0),
  35.       m_paStreams(NULL)
  36. {
  37. }
  38.  
  39. //
  40. // CSource::Destructor
  41. //
  42. CSource::~CSource()
  43. {
  44.     /*  Free our pins and pin array */
  45.     while (m_iPins != 0) {
  46.     // deleting the pins causes them to be removed from the array...
  47.     delete m_paStreams[m_iPins - 1];
  48.     }
  49.  
  50.     ASSERT(m_paStreams == NULL);
  51. }
  52.  
  53.  
  54. //
  55. //  Add a new pin
  56. //
  57. HRESULT CSource::AddPin(CSourceStream *pStream)
  58. {
  59.     CAutoLock lock(&m_cStateLock);
  60.  
  61.     /*  Allocate space for this pin and the old ones */
  62.     CSourceStream **paStreams = new CSourceStream *[m_iPins + 1];
  63.     if (paStreams == NULL) {
  64.         return E_OUTOFMEMORY;
  65.     }
  66.     if (m_paStreams != NULL) {
  67.         CopyMemory((PVOID)paStreams, (PVOID)m_paStreams,
  68.                    m_iPins * sizeof(m_paStreams[0]));
  69.         paStreams[m_iPins] = pStream;
  70.         delete [] m_paStreams;
  71.     }
  72.     m_paStreams = paStreams;
  73.     m_paStreams[m_iPins] = pStream;
  74.     m_iPins++;
  75.     return S_OK;
  76. }
  77.  
  78. //
  79. //  Remove a pin - pStream is NOT deleted
  80. //
  81. HRESULT CSource::RemovePin(CSourceStream *pStream)
  82. {
  83.     int i;
  84.     for (i = 0; i < m_iPins; i++) {
  85.         if (m_paStreams[i] == pStream) {
  86.             if (m_iPins == 1) {
  87.                 delete [] m_paStreams;
  88.                 m_paStreams = NULL;
  89.             } else {
  90.                 /*  no need to reallocate */
  91.         while (++i < m_iPins)
  92.             m_paStreams[i - 1] = m_paStreams[i];
  93.             }
  94.             m_iPins--;
  95.             return S_OK;
  96.         }
  97.     }
  98.     return S_FALSE;
  99. }
  100.  
  101.  
  102. //
  103. // GetPinCount
  104. //
  105. // Returns the number of pins this filter has
  106. int CSource::GetPinCount(void) {
  107.  
  108.     CAutoLock lock(&m_cStateLock);
  109.     return m_iPins;
  110. }
  111.  
  112.  
  113. //
  114. // GetPin
  115. //
  116. // Return a non-addref'd pointer to pin n
  117. // needed by CBaseFilter
  118. CBasePin *CSource::GetPin(int n) {
  119.  
  120.     CAutoLock lock(&m_cStateLock);
  121.  
  122.     // n must be in the range 0..m_iPins-1
  123.     // if m_iPins>n  && n>=0 it follows that m_iPins>0
  124.     // which is what used to be checked (i.e. checking that we have a pin)
  125.     if ((n >= 0) && (n < m_iPins)) {
  126.  
  127.         ASSERT(m_paStreams[n]);
  128.     return m_paStreams[n];
  129.     }
  130.     return NULL;
  131. }
  132.  
  133.  
  134. //
  135. // FindPin
  136. //
  137. // Set *ppPin to the IPin* that has the id Id.
  138. // or to NULL if the Id cannot be matched.
  139. STDMETHODIMP CSource::FindPin(LPCWSTR Id, IPin **ppPin)
  140. {
  141.     CheckPointer(ppPin,E_POINTER);
  142.     ValidateReadWritePtr(ppPin,sizeof(IPin *));
  143.     // The -1 undoes the +1 in QueryId and ensures that totally bogus
  144.     // strings (for which WstrToInt delivers 0) give a deliver a NULL pin.
  145.     int i = WstrToInt(Id) -1;
  146.     *ppPin = GetPin(i);
  147.     if (*ppPin!=NULL){
  148.         (*ppPin)->AddRef();
  149.         return NOERROR;
  150.     } else {
  151.         return VFW_E_NOT_FOUND;
  152.     }
  153. }
  154.  
  155. //
  156. // FindPinNumber
  157. //
  158. // return the number of the pin with this IPin* or -1 if none
  159. int CSource::FindPinNumber(IPin *iPin) {
  160.     int i;
  161.     for (i=0; i<m_iPins; ++i) {
  162.         if ((IPin *)(m_paStreams[i])==iPin) {
  163.             return i;
  164.         }
  165.     }
  166.     return -1;
  167. }
  168.  
  169.  
  170.  
  171.  
  172. // *
  173. // * --- CSourceStream ----
  174. // *
  175.  
  176. //
  177. // Set Id to point to a CoTaskMemAlloc'd
  178. STDMETHODIMP CSourceStream::QueryId(LPWSTR *Id) {
  179.     CheckPointer(Id,E_POINTER);
  180.     ValidateReadWritePtr(Id,sizeof(LPWSTR));
  181.  
  182.     // We give the pins id's which are 1,2,...
  183.     // FindPinNumber returns -1 for a bogus pin
  184.     int i = 1+ m_pFilter->FindPinNumber(this);
  185.     if (i<1) return VFW_E_NOT_FOUND;
  186.     *Id = (LPWSTR)CoTaskMemAlloc(8);
  187.     if (*Id==NULL) {
  188.        return E_OUTOFMEMORY;
  189.     }
  190.     IntToWstr(i, *Id);
  191.     return NOERROR;
  192. }
  193.  
  194.  
  195. //
  196. // CSourceStream::Constructor
  197. //
  198. // increments the number of pins present on the filter
  199. CSourceStream::CSourceStream(
  200.     TCHAR *pObjectName,
  201.     HRESULT *phr,
  202.     CSource *ps,
  203.     LPCWSTR pPinName)
  204.     : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
  205.       m_pFilter(ps) {
  206.  
  207.      *phr = m_pFilter->AddPin(this);
  208. }
  209.  
  210.  
  211. //
  212. // CSourceStream::Destructor
  213. //
  214. // Decrements the number of pins on this filter
  215. CSourceStream::~CSourceStream(void) {
  216.  
  217.      m_pFilter->RemovePin(this);
  218. }
  219.  
  220.  
  221. //
  222. // CheckMediaType
  223. //
  224. // Do we support this type? Provides the default support for 1 type.
  225. HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) {
  226.  
  227.     CAutoLock lock(m_pFilter->pStateLock());
  228.  
  229.     CMediaType mt;
  230.     GetMediaType(&mt);
  231.  
  232.     if (mt == *pMediaType) {
  233.         return NOERROR;
  234.     }
  235.  
  236.     return E_FAIL;
  237. }
  238.  
  239.  
  240. //
  241. // GetMediaType/3
  242. //
  243. // By default we support only one type
  244. // iPosition indexes are 0-n
  245. HRESULT CSourceStream::GetMediaType(int iPosition, CMediaType *pMediaType) {
  246.  
  247.     CAutoLock lock(m_pFilter->pStateLock());
  248.  
  249.     if (iPosition<0) {
  250.         return E_INVALIDARG;
  251.     }
  252.     if (iPosition>0) {
  253.         return VFW_S_NO_MORE_ITEMS;
  254.     }
  255.     return GetMediaType(pMediaType);
  256. }
  257.  
  258.  
  259. //
  260. // Active
  261. //
  262. // The pin is active - start up the worker thread
  263. HRESULT CSourceStream::Active(void) {
  264.  
  265.     CAutoLock lock(m_pFilter->pStateLock());
  266.  
  267.     HRESULT hr;
  268.  
  269.     if (m_pFilter->IsActive()) {
  270.     return S_FALSE;    // succeeded, but did not allocate resources (they already exist...)
  271.     }
  272.  
  273.     // do nothing if not connected - its ok not to connect to
  274.     // all pins of a source filter
  275.     if (!IsConnected()) {
  276.         return NOERROR;
  277.     }
  278.  
  279.     hr = CBaseOutputPin::Active();
  280.     if (FAILED(hr)) {
  281.         return hr;
  282.     }
  283.  
  284.     ASSERT(!ThreadExists());
  285.  
  286.     // start the thread
  287.     if (!Create()) {
  288.         return E_FAIL;
  289.     }
  290.  
  291.     // Tell thread to initialize. If OnThreadCreate Fails, so does this.
  292.     hr = Init();
  293.     if (FAILED(hr))
  294.     return hr;
  295.  
  296.     return Pause();
  297. }
  298.  
  299.  
  300. //
  301. // Inactive
  302. //
  303. // Pin is inactive - shut down the worker thread
  304. // Waits for the worker to exit before returning.
  305. HRESULT CSourceStream::Inactive(void) {
  306.  
  307.     CAutoLock lock(m_pFilter->pStateLock());
  308.  
  309.     HRESULT hr;
  310.  
  311.     // do nothing if not connected - its ok not to connect to
  312.     // all pins of a source filter
  313.     if (!IsConnected()) {
  314.         return NOERROR;
  315.     }
  316.  
  317.     // !!! need to do this before trying to stop the thread, because
  318.     // we may be stuck waiting for our own allocator!!!
  319.  
  320.     hr = CBaseOutputPin::Inactive();  // call this first to Decommit the allocator
  321.     if (FAILED(hr)) {
  322.     return hr;
  323.     }
  324.  
  325.     if (ThreadExists()) {
  326.     hr = Stop();
  327.  
  328.     if (FAILED(hr)) {
  329.         return hr;
  330.     }
  331.  
  332.     hr = Exit();
  333.     if (FAILED(hr)) {
  334.         return hr;
  335.     }
  336.  
  337.     Close();    // Wait for the thread to exit, then tidy up.
  338.     }
  339.  
  340.     // hr = CBaseOutputPin::Inactive();  // call this first to Decommit the allocator
  341.     //if (FAILED(hr)) {
  342.     //    return hr;
  343.     //}
  344.  
  345.     return NOERROR;
  346. }
  347.  
  348.  
  349. //
  350. // ThreadProc
  351. //
  352. // When this returns the thread exits
  353. // Return codes > 0 indicate an error occured
  354. DWORD CSourceStream::ThreadProc(void) {
  355.  
  356.     HRESULT hr;  // the return code from calls
  357.     Command com;
  358.  
  359.     do {
  360.     com = GetRequest();
  361.     if (com != CMD_INIT) {
  362.         DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command")));
  363.         Reply(E_UNEXPECTED);
  364.     }
  365.     } while (com != CMD_INIT);
  366.  
  367.     DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing")));
  368.  
  369.     hr = OnThreadCreate(); // perform set up tasks
  370.     if (FAILED(hr)) {
  371.         DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread.")));
  372.         OnThreadDestroy();
  373.     Reply(hr);    // send failed return code from OnThreadCreate
  374.         return 1;
  375.     }
  376.  
  377.     // Initialisation suceeded
  378.     Reply(NOERROR);
  379.  
  380.     Command cmd;
  381.     do {
  382.     cmd = GetRequest();
  383.  
  384.     switch (cmd) {
  385.  
  386.     case CMD_EXIT:
  387.         Reply(NOERROR);
  388.         break;
  389.  
  390.     case CMD_RUN:
  391.         DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???")));
  392.         // !!! fall through???
  393.     
  394.     case CMD_PAUSE:
  395.         Reply(NOERROR);
  396.         DoBufferProcessingLoop();
  397.         break;
  398.  
  399.     case CMD_STOP:
  400.         Reply(NOERROR);
  401.         break;
  402.  
  403.     default:
  404.         DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd));
  405.         Reply(E_NOTIMPL);
  406.         break;
  407.     }
  408.     } while (cmd != CMD_EXIT);
  409.  
  410.     hr = OnThreadDestroy();    // tidy up.
  411.     if (FAILED(hr)) {
  412.         DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread.")));
  413.         return 1;
  414.     }
  415.  
  416.     DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting")));
  417.     return 0;
  418. }
  419.  
  420.  
  421. //
  422. // DoBufferProcessingLoop
  423. //
  424. // Grabs a buffer and calls the users processing function.
  425. // Overridable, so that different delivery styles can be catered for.
  426. HRESULT CSourceStream::DoBufferProcessingLoop(void) {
  427.  
  428.     Command com;
  429.  
  430.     OnThreadStartPlay();
  431.  
  432.     do {
  433.     while (!CheckRequest(&com)) {
  434.  
  435.         IMediaSample *pSample;
  436.  
  437.         HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0);
  438.         if (FAILED(hr)) {
  439.                 Sleep(1);
  440.         continue;    // go round again. Perhaps the error will go away
  441.                 // or the allocator is decommited & we will be asked to
  442.                 // exit soon.
  443.         }
  444.  
  445.         // Virtual function user will override.
  446.         hr = FillBuffer(pSample);
  447.  
  448.         if (hr == S_OK) {
  449.         hr = Deliver(pSample);
  450.                 pSample->Release();
  451.  
  452.                 // downstream filter returns S_FALSE if it wants us to
  453.                 // stop or an error if it's reporting an error.
  454.                 if(hr != S_OK)
  455.                 {
  456.                   DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr));
  457.                   return S_OK;
  458.                 }
  459.  
  460.         } else if (hr == S_FALSE) {
  461.                 // derived class wants us to stop pushing data
  462.         pSample->Release();
  463.         DeliverEndOfStream();
  464.         return S_OK;
  465.         } else {
  466.                 // derived class encountered an error
  467.                 pSample->Release();
  468.         DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr));
  469.                 DeliverEndOfStream();
  470.                 m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
  471.                 return hr;
  472.         }
  473.  
  474.             // all paths release the sample
  475.     }
  476.  
  477.         // For all commands sent to us there must be a Reply call!
  478.  
  479.     if (com == CMD_RUN || com == CMD_PAUSE) {
  480.         Reply(NOERROR);
  481.     } else if (com != CMD_STOP) {
  482.         Reply(E_UNEXPECTED);
  483.         DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!")));
  484.     }
  485.     } while (com != CMD_STOP);
  486.  
  487.     return S_FALSE;
  488. }
  489.  
  490.