source.cpp
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:12k
源码类别:

P2P编程

开发平台:

Visual C++

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