Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

751 lines
20 KiB

  1. // Copyright (c) 1997 - 1998 Microsoft Corporation. All Rights Reserved.
  2. // Stream.cpp : Implementation of CStream
  3. #include "stdafx.h"
  4. #include "project.h"
  5. /////////////////////////////////////////////////////////////////////////////
  6. // CStream
  7. CStream::CStream() :
  8. m_bCommitted(false),
  9. m_lRequestedBufferCount(0),
  10. m_bFlushing(false),
  11. m_rtWaiting(0),
  12. m_lWaiting(0),
  13. m_hWaitFreeSem(NULL),
  14. m_pFirstFree(NULL),
  15. m_pLastFree(NULL),
  16. m_cAllocated(0),
  17. m_bEndOfStream(false),
  18. m_FilterState(State_Stopped),
  19. m_pFilter(NULL),
  20. m_pFilterGraph(NULL),
  21. m_pMMStream(NULL),
  22. m_pWritePump(NULL),
  23. m_rtSegmentStart(0),
  24. m_bNoStall(false),
  25. m_bStopIfNoSamples(false)
  26. {
  27. InitMediaType(&m_ConnectedMediaType);
  28. InitMediaType(&m_ActualMediaType);
  29. CHECKSAMPLELIST
  30. }
  31. #ifdef DEBUG
  32. bool CStream::CheckSampleList()
  33. {
  34. if (m_pFirstFree) {
  35. CSample *pSample = m_pFirstFree;
  36. if (pSample->m_pPrevFree != NULL) {
  37. return false;
  38. }
  39. while (pSample->m_pNextFree) {
  40. if (pSample->m_pNextFree->m_pPrevFree != pSample) {
  41. return false;
  42. }
  43. pSample = pSample->m_pNextFree;
  44. }
  45. if (pSample != m_pLastFree) {
  46. return false;
  47. }
  48. } else {
  49. if (m_pLastFree) {
  50. return false;
  51. }
  52. }
  53. return true;
  54. }
  55. #endif
  56. HRESULT CStream::FinalConstruct(void)
  57. {
  58. m_hWaitFreeSem = CreateSemaphore(NULL, 0, 0x7FFFFFF, NULL);
  59. return m_hWaitFreeSem ? S_OK : E_OUTOFMEMORY;
  60. }
  61. CStream::~CStream()
  62. {
  63. SetState(State_Stopped); // Make sure we're decommitted and pump is dead
  64. Disconnect(); // Free any allocated media types and release held references
  65. if (m_hWaitFreeSem) {
  66. CloseHandle(m_hWaitFreeSem);
  67. }
  68. }
  69. STDMETHODIMP CStream::GetMultiMediaStream(IMultiMediaStream **ppMultiMediaStream)
  70. {
  71. TRACEINTERFACE(_T("IMediaStream::GetMultiMediaStream(0x%8.8X)\n"),
  72. ppMultiMediaStream);
  73. if (NULL == ppMultiMediaStream) {
  74. return E_POINTER;
  75. }
  76. if (m_pMMStream != NULL) {
  77. m_pMMStream->AddRef();
  78. }
  79. *ppMultiMediaStream = m_pMMStream;
  80. return S_OK;
  81. }
  82. STDMETHODIMP CStream::GetInformation(MSPID *pPurposeId, STREAM_TYPE *pType)
  83. {
  84. TRACEINTERFACE(_T("IMediaStream::GetInformation(0x%8.8X, 0x%8.8X)\n"),
  85. pPurposeId, pType);
  86. if (pPurposeId) {
  87. *pPurposeId = m_PurposeId;
  88. }
  89. if (pType) {
  90. *pType = m_StreamType;
  91. }
  92. return S_OK;
  93. }
  94. STDMETHODIMP CStream::SendEndOfStream(DWORD dwFlags)
  95. {
  96. TRACEINTERFACE(_T("IMediaStream::SendEndOfStream(0x%8.8X)\n"),
  97. dwFlags);
  98. if (m_StreamType != STREAMTYPE_WRITE) {
  99. return MS_E_INVALIDSTREAMTYPE;
  100. }
  101. if (m_pConnectedPin) {
  102. return m_pConnectedPin->EndOfStream();
  103. }
  104. return S_OK;
  105. }
  106. STDMETHODIMP CStream::Initialize(IUnknown *pSourceObject, DWORD dwFlags,
  107. REFMSPID PurposeId, const STREAM_TYPE StreamType)
  108. {
  109. TRACEINTERFACE(_T("IMediaStream::Initalize(0x%8.8X, 0x%8.8X, %s, %d)\n"),
  110. pSourceObject, dwFlags, TextFromPurposeId(PurposeId), StreamType);
  111. HRESULT hr = NOERROR;
  112. if (dwFlags & ~(AMMSF_CREATEPEER | AMMSF_STOPIFNOSAMPLES)) {
  113. return E_INVALIDARG;
  114. }
  115. m_PurposeId = PurposeId;
  116. m_StreamType = StreamType;
  117. m_Direction = (StreamType == STREAMTYPE_WRITE) ? PINDIR_OUTPUT : PINDIR_INPUT;
  118. if (dwFlags & AMMSF_CREATEPEER) {
  119. if (!pSourceObject) {
  120. hr = E_INVALIDARG;
  121. } else {
  122. CComQIPtr<IMediaStream, &IID_IMediaStream> pMediaStream(pSourceObject);
  123. if (!pSourceObject) {
  124. hr = E_INVALIDARG;
  125. } else {
  126. hr = SetSameFormat(pMediaStream, 0);
  127. }
  128. }
  129. }
  130. m_bStopIfNoSamples = dwFlags & AMMSF_STOPIFNOSAMPLES ? true : false;
  131. return hr;
  132. }
  133. STDMETHODIMP CStream::SetState(FILTER_STATE State)
  134. {
  135. TRACEINTERFACE(_T("IMediaStream::SetState(%d)\n"),
  136. State);
  137. Lock();
  138. if (m_pConnectedPin == NULL) {
  139. Unlock();
  140. if (State == STREAMSTATE_RUN) {
  141. EndOfStream();
  142. }
  143. } else {
  144. _ASSERTE(m_pAllocator != NULL);
  145. FILTER_STATE prevState = m_FilterState;
  146. m_FilterState = State;
  147. if (State == State_Stopped) {
  148. m_pAllocator->Decommit();
  149. if (!m_bUsingMyAllocator) {
  150. Decommit();
  151. }
  152. CPump *pPump = m_pWritePump;
  153. m_pWritePump = NULL;
  154. Unlock();
  155. delete pPump;
  156. } else {
  157. m_pAllocator->Commit();
  158. if (!m_bUsingMyAllocator) {
  159. Commit();
  160. }
  161. if( State_Stopped == prevState )
  162. {
  163. // need this in the case of a seek while stopped, since BeginFlush
  164. // may not be called to reset this flag
  165. m_bEndOfStream = false;
  166. }
  167. Unlock();
  168. }
  169. }
  170. return S_OK;
  171. }
  172. STDMETHODIMP CStream::JoinAMMultiMediaStream(IAMMultiMediaStream *pAMMultiMediaStream)
  173. {
  174. _ASSERTE(pAMMultiMediaStream == NULL || m_pMMStream == NULL);
  175. AUTO_CRIT_LOCK;
  176. HRESULT hr;
  177. if (m_cAllocated) {
  178. hr = MS_E_SAMPLEALLOC;
  179. } else {
  180. m_pMMStream = pAMMultiMediaStream;
  181. }
  182. return S_OK;
  183. }
  184. STDMETHODIMP CStream::JoinFilter(IMediaStreamFilter *pMediaStreamFilter)
  185. {
  186. _ASSERTE(pMediaStreamFilter == NULL || m_pFilter == NULL);
  187. m_pFilter = pMediaStreamFilter;
  188. pMediaStreamFilter->QueryInterface(IID_IBaseFilter, (void **)&m_pBaseFilter);
  189. m_pBaseFilter->Release();
  190. return S_OK;
  191. }
  192. STDMETHODIMP CStream::JoinFilterGraph(IFilterGraph *pFilterGraph)
  193. {
  194. _ASSERTE(pFilterGraph == NULL || m_pFilterGraph == NULL);
  195. m_pFilterGraph = pFilterGraph;
  196. return S_OK;
  197. }
  198. //
  199. // IPin Implementation
  200. //
  201. STDMETHODIMP CStream::Disconnect()
  202. {
  203. m_pConnectedPin = NULL;
  204. m_pConnectedMemInputPin.Release(); // Magically sets to NULL here
  205. m_pQC.Release();
  206. m_pAllocator = NULL;
  207. m_lRequestedBufferCount = 0;
  208. FreeMediaType(m_ConnectedMediaType);
  209. FreeMediaType(m_ActualMediaType);
  210. return S_OK;
  211. }
  212. STDMETHODIMP CStream::ConnectedTo(IPin **pPin)
  213. {
  214. *pPin = m_pConnectedPin;
  215. if (*pPin) {
  216. (*pPin)->AddRef();
  217. return S_OK;
  218. } else {
  219. return VFW_E_NOT_CONNECTED;
  220. }
  221. }
  222. STDMETHODIMP CStream::ConnectionMediaType(AM_MEDIA_TYPE *pmt)
  223. {
  224. if (m_pConnectedPin) {
  225. CopyMediaType(pmt, &m_ConnectedMediaType);
  226. return S_OK;
  227. } else {
  228. ZeroMemory(pmt, sizeof(*pmt));
  229. pmt->lSampleSize = 1;
  230. pmt->bFixedSizeSamples = TRUE;
  231. return VFW_E_NOT_CONNECTED;
  232. }
  233. }
  234. void CStream::GetName(LPWSTR pszBuf)
  235. {
  236. if (m_PurposeId == GUID_NULL) {
  237. pszBuf[0] = 0;
  238. } else {
  239. pszBuf[0] = (m_Direction == PINDIR_INPUT) ? (WCHAR)'I' : (WCHAR)'O';
  240. WStringFromGUID(&m_PurposeId, &pszBuf[1]);
  241. }
  242. }
  243. STDMETHODIMP CStream::QueryPinInfo(PIN_INFO * pInfo)
  244. {
  245. pInfo->dir = m_Direction;
  246. GetName(pInfo->achName);
  247. return m_pFilter->QueryInterface(IID_IBaseFilter, (void **)&pInfo->pFilter);
  248. }
  249. STDMETHODIMP CStream::QueryDirection(PIN_DIRECTION * pPinDir)
  250. {
  251. *pPinDir = m_Direction;
  252. return S_OK;
  253. }
  254. STDMETHODIMP CStream::QueryId(LPWSTR * Id)
  255. {
  256. *Id = (LPWSTR)CoTaskMemAlloc(128 * sizeof(WCHAR));
  257. if (*Id) {
  258. GetName(*Id);
  259. return S_OK;
  260. } else {
  261. return E_OUTOFMEMORY;
  262. }
  263. }
  264. //
  265. // Derived classes must override this method
  266. //
  267. STDMETHODIMP CStream::QueryAccept(const AM_MEDIA_TYPE *pmt)
  268. {
  269. return E_NOTIMPL;
  270. };
  271. STDMETHODIMP CStream::QueryInternalConnections(IPin **apPin, ULONG *nPin)
  272. {
  273. //
  274. // Returning E_NOTIMPL tells the filter graph manager that all input pins are connected to
  275. // all output pins.
  276. //
  277. return E_NOTIMPL;
  278. };
  279. STDMETHODIMP CStream::EndOfStream(void)
  280. {
  281. HRESULT hr = S_OK;
  282. Lock();
  283. if (m_bFlushing || m_bEndOfStream) {
  284. hr = E_FAIL;
  285. } else {
  286. m_bEndOfStream = true;
  287. CSample *pSample = m_pFirstFree;
  288. m_pFirstFree = m_pLastFree = NULL; // Out of paranoia, clear these pointers first
  289. while (pSample) {
  290. CSample *pNext = pSample->m_pNextFree;
  291. pSample->SetCompletionStatus(MS_S_ENDOFSTREAM); // WARNING! This sample may go away!!!
  292. pSample = pNext;
  293. }
  294. CHECKSAMPLELIST
  295. }
  296. if (S_OK == hr) {
  297. m_pFilter->EndOfStream();
  298. }
  299. Unlock();
  300. return hr;
  301. }
  302. STDMETHODIMP CStream::BeginFlush(void)
  303. {
  304. HRESULT hr = S_OK;
  305. Lock();
  306. const BOOL bCancelEOS = m_bEndOfStream;
  307. if (m_bFlushing) {
  308. hr = S_FALSE;
  309. } else {
  310. m_bFlushing = true;
  311. m_bEndOfStream = false;
  312. Decommit(); // Force everyone to unblock
  313. }
  314. if (S_OK == hr) {
  315. m_pFilter->Flush(bCancelEOS);
  316. }
  317. Unlock();
  318. return hr;
  319. }
  320. STDMETHODIMP CStream::EndFlush(void)
  321. {
  322. AUTO_CRIT_LOCK;
  323. m_bFlushing = false;
  324. _ASSERTE(!m_bEndOfStream);
  325. Commit(); // Let getbuffer work again
  326. return S_OK;
  327. }
  328. STDMETHODIMP CStream::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
  329. {
  330. Lock();
  331. m_rtSegmentStart = tStart;
  332. m_bEndOfStream = false;
  333. Unlock();
  334. return S_OK;
  335. }
  336. //
  337. // IMemInputPin
  338. //
  339. STDMETHODIMP CStream::GetAllocator(IMemAllocator ** ppAllocator)
  340. {
  341. return GetControllingUnknown()->QueryInterface(IID_IMemAllocator, (void **)ppAllocator);
  342. }
  343. STDMETHODIMP CStream::NotifyAllocator(IMemAllocator * pAllocator, BOOL bReadOnly)
  344. {
  345. m_bUsingMyAllocator = IsSameObject(pAllocator, GetControllingUnknown());
  346. m_bSamplesAreReadOnly = bReadOnly ? true : false;
  347. HRESULT hr = S_OK;
  348. if (!m_bUsingMyAllocator) {
  349. // Transfer the properties across
  350. ALLOCATOR_PROPERTIES Props;
  351. hr = pAllocator->GetProperties(&Props);
  352. if (FAILED(hr)) {
  353. return hr;
  354. }
  355. ALLOCATOR_PROPERTIES PropsActual;
  356. hr = SetProperties(&Props, &PropsActual);
  357. }
  358. m_pAllocator = pAllocator;
  359. return hr;
  360. }
  361. STDMETHODIMP CStream::GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps)
  362. {
  363. // Return E_NOTIMPL to indicate that we don't have any requirement and will not accept someone
  364. // elses allocator.
  365. return E_NOTIMPL;
  366. }
  367. STDMETHODIMP CStream::ReceiveMultiple(IMediaSample **pSamples, long nSamples, long *nSamplesProcessed)
  368. {
  369. HRESULT hr = S_OK;
  370. *nSamplesProcessed = 0;
  371. while (nSamples-- > 0) {
  372. hr = Receive(pSamples[*nSamplesProcessed]);
  373. if (hr != S_OK) {
  374. break;
  375. }
  376. (*nSamplesProcessed)++;
  377. }
  378. return hr;
  379. }
  380. STDMETHODIMP CStream::ReceiveCanBlock()
  381. {
  382. return S_OK; // Pin can block if not using our allocator or using read-only samples
  383. }
  384. //
  385. // This method assumes the critical section is taken.
  386. //
  387. HRESULT CStream::ConnectThisMediaType(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
  388. {
  389. HRESULT hr = pReceivePin->ReceiveConnection(this, pmt);
  390. if (SUCCEEDED(hr)) {
  391. m_pConnectedMemInputPin = pReceivePin; // Does a magic QI here!
  392. if (!m_pConnectedMemInputPin) {
  393. hr = VFW_E_TYPE_NOT_ACCEPTED;
  394. } else {
  395. hr = ReceiveConnection(pReceivePin, pmt);
  396. if (SUCCEEDED(hr)) {
  397. hr = m_pConnectedMemInputPin->NotifyAllocator(this, TRUE);
  398. }
  399. if (SUCCEEDED(hr)) {
  400. CopyMediaType(&m_ConnectedMediaType, pmt);
  401. }
  402. if (SUCCEEDED(hr)) {
  403. m_pAllocator = this;
  404. m_bUsingMyAllocator = true;
  405. } else {
  406. Disconnect();
  407. }
  408. }
  409. }
  410. return hr;
  411. }
  412. STDMETHODIMP CStream::Connect(IPin * pReceivePin, const AM_MEDIA_TYPE *pmt)
  413. {
  414. HRESULT hr;
  415. AUTO_CRIT_LOCK;
  416. if (pmt) {
  417. hr = ConnectThisMediaType(pReceivePin, pmt);
  418. } else {
  419. AM_MEDIA_TYPE *pCurMediaType;
  420. hr = GetMediaType(0, &pCurMediaType);
  421. if (SUCCEEDED(hr)) {
  422. hr = ConnectThisMediaType(pReceivePin, pCurMediaType);
  423. DeleteMediaType(pCurMediaType);
  424. }
  425. }
  426. return hr;
  427. }
  428. STDMETHODIMP CStream::EnumMediaTypes(IEnumMediaTypes **ppEnum)
  429. {
  430. HRESULT hr = S_OK;
  431. CMediaTypeEnum *pNewEnum = new CComObject<CMediaTypeEnum>;
  432. if (pNewEnum == NULL) {
  433. hr = E_OUTOFMEMORY;
  434. } else {
  435. pNewEnum->Initialize(this, 0);
  436. }
  437. pNewEnum->GetControllingUnknown()->QueryInterface(IID_IEnumMediaTypes, (void **)ppEnum);
  438. return hr;
  439. }
  440. STDMETHODIMP CStream::Commit()
  441. {
  442. AUTO_CRIT_LOCK;
  443. if (!m_bCommitted) {
  444. if (m_StreamType == STREAMTYPE_WRITE) {
  445. if (!m_pWritePump) {
  446. HRESULT hr = CPump::CreatePump(this, &m_pWritePump);
  447. if (hr != S_OK) {
  448. return hr;
  449. }
  450. }
  451. m_pWritePump->Run(true);
  452. }
  453. //
  454. // Interesting thing to note here -- Even if we have not been initialized we will still
  455. // work correctly on commit. We will simply set the requested buffer count to 1.
  456. //
  457. if (m_lRequestedBufferCount == 0) {
  458. m_lRequestedBufferCount = 1;
  459. }
  460. m_bCommitted = true;
  461. }
  462. return S_OK;
  463. }
  464. STDMETHODIMP CStream::Decommit()
  465. {
  466. HRESULT hr = S_OK;
  467. AUTO_CRIT_LOCK;
  468. if (m_bCommitted) { // If we're already decommitted then just return S_OK.
  469. m_bCommitted = false;
  470. if (m_lWaiting > 0) {
  471. ReleaseSemaphore(m_hWaitFreeSem, m_lWaiting, 0);
  472. m_lWaiting = 0;
  473. }
  474. if (m_pWritePump) {
  475. m_pWritePump->Run(false);
  476. }
  477. }
  478. return hr;
  479. }
  480. //
  481. // This method is not supported and never will be!
  482. //
  483. STDMETHODIMP CStream::ReleaseBuffer(IMediaSample *pBuffer)
  484. {
  485. return E_UNEXPECTED;
  486. };
  487. //
  488. // The caller holds the reference to the sample after this point.
  489. //
  490. HRESULT CStream::AllocSampleFromPool(
  491. const REFERENCE_TIME *pStartTime,
  492. CSample **ppSample
  493. )
  494. {
  495. CSample *pSample = NULL;
  496. HRESULT hr = NOERROR;
  497. bool bWaited = false;
  498. bool bCreatedTemp = false;
  499. do {
  500. LONGLONG llLate = 0;
  501. Lock();
  502. // Check we are committed -- This can happen after we've blocked and then
  503. // wake back up due to a decommit.
  504. if (!m_bCommitted) {
  505. hr = VFW_E_NOT_COMMITTED;
  506. break;
  507. }
  508. if (pStartTime) {
  509. REFERENCE_TIME CurTime;
  510. if (m_pFilter->GetCurrentStreamTime(&CurTime) == S_OK) {
  511. llLate = CurTime - *pStartTime;
  512. /* Block if more than a millisecond early */
  513. if (-llLate >= 10000) {
  514. m_rtWaiting = *pStartTime;
  515. Unlock();
  516. m_pFilter->WaitUntil(*pStartTime);
  517. Lock();
  518. m_rtWaiting = 0;
  519. if (!m_bCommitted) {
  520. hr = VFW_E_NOT_COMMITTED;
  521. break;
  522. }
  523. }
  524. }
  525. }
  526. pSample = m_pFirstFree;
  527. if (bWaited && pSample == NULL) {
  528. _ASSERTE(m_bNoStall);
  529. if (!m_bUsingMyAllocator) {
  530. hr = HRESULT_FROM_WIN32(ERROR_SEM_TIMEOUT);
  531. break;
  532. } else {
  533. // Try to make one
  534. CreateTempSample(&pSample);
  535. if (pSample) {
  536. bCreatedTemp = true;
  537. }
  538. // pSample->SetCompletionStatus(MS_S_PENDING);
  539. }
  540. }
  541. if (pSample == NULL) {
  542. m_lWaiting++;
  543. Unlock();
  544. // Only wait for half a second if non-blocking
  545. DWORD dwWait = INFINITE;
  546. if (m_bNoStall) {
  547. const LONGLONG llLateMs = llLate / 10000;
  548. const DWORD dwMaxLateMs = 100;
  549. if (llLateMs > dwMaxLateMs) {
  550. dwWait = 0;
  551. } else {
  552. // llLateMs could be negative which means we waited
  553. // just above
  554. if (llLateMs > 0) {
  555. dwWait = dwMaxLateMs - (DWORD)llLateMs;
  556. } else {
  557. dwWait = dwMaxLateMs;
  558. }
  559. }
  560. }
  561. bWaited = WAIT_TIMEOUT == WaitForSingleObject(
  562. m_hWaitFreeSem,
  563. dwWait) ?
  564. true : false;
  565. } else if (!bCreatedTemp) {
  566. m_pFirstFree = pSample->m_pNextFree;
  567. if (m_pFirstFree) {
  568. m_pFirstFree->m_pPrevFree = NULL;
  569. } else {
  570. m_pLastFree = NULL;
  571. }
  572. pSample->m_pNextFree = NULL; // Just to be tidy. We know that m_pPrevFree is null!
  573. _ASSERTE(pSample->m_Status == MS_S_PENDING);
  574. CHECKSAMPLELIST
  575. }
  576. } while (pSample == NULL);
  577. Unlock();
  578. if (pSample) {
  579. pSample->m_bWaited = pStartTime != 0 ? true : false;
  580. }
  581. *ppSample = pSample;
  582. return hr;
  583. }
  584. void CStream::AddSampleToFreePool(CSample *pSample)
  585. {
  586. Lock();
  587. _ASSERTE(pSample->m_pPrevFree == NULL && pSample->m_pNextFree == NULL);
  588. if (m_pFirstFree) {
  589. pSample->m_pPrevFree = m_pLastFree;
  590. m_pLastFree->m_pNextFree = pSample;
  591. } else {
  592. pSample->m_pPrevFree = NULL;
  593. m_pFirstFree = pSample;
  594. }
  595. pSample->m_pNextFree = NULL; // We know that the prev ptr is already null
  596. m_pLastFree = pSample;
  597. CHECKSAMPLELIST
  598. if (m_lWaiting > 0) {
  599. ReleaseSemaphore(m_hWaitFreeSem, 1, 0);
  600. m_lWaiting--;
  601. }
  602. Unlock();
  603. }
  604. //
  605. // The caller holds the reference to the sample after this point!
  606. //
  607. bool CStream::StealSampleFromFreePool(CSample *pSample, BOOL bAbort)
  608. {
  609. bool bWorked = false;
  610. Lock();
  611. if (m_pFirstFree) {
  612. if (m_pFirstFree == pSample) {
  613. // We'll only steal the first sample if there's nobody waiting for it right now.
  614. bool bTakeFirstFree = true;
  615. if (!bAbort && m_bCommitted) {
  616. REFERENCE_TIME CurTime;
  617. if (m_rtWaiting && m_pFilter->GetCurrentStreamTime(&CurTime) == S_OK) {
  618. bTakeFirstFree = m_rtWaiting > CurTime;
  619. }
  620. }
  621. if (bTakeFirstFree) {
  622. m_pFirstFree = pSample->m_pNextFree;
  623. if (m_pFirstFree) {
  624. m_pFirstFree->m_pPrevFree = NULL;
  625. } else {
  626. m_pLastFree = NULL;
  627. }
  628. pSample->m_pNextFree = NULL; // We know the prev ptr is already null!
  629. _ASSERTE(pSample->m_pPrevFree == NULL);
  630. bWorked = true;
  631. }
  632. } else {
  633. if (pSample->m_pPrevFree) {
  634. pSample->m_pPrevFree->m_pNextFree = pSample->m_pNextFree;
  635. if (pSample->m_pNextFree) {
  636. pSample->m_pNextFree->m_pPrevFree = pSample->m_pPrevFree;
  637. } else {
  638. m_pLastFree = pSample->m_pPrevFree;
  639. }
  640. pSample->m_pNextFree = pSample->m_pPrevFree = NULL;
  641. bWorked = true;
  642. }
  643. }
  644. CHECKSAMPLELIST
  645. }
  646. Unlock();
  647. return bWorked;
  648. }
  649. HRESULT CStream::CheckReceiveConnectionPin(IPin * pPin)
  650. {
  651. HRESULT hr;
  652. if (!pPin) {
  653. hr = E_POINTER;
  654. } else {
  655. if (m_pConnectedPin != NULL) {
  656. hr = VFW_E_ALREADY_CONNECTED;
  657. } else {
  658. PIN_INFO pinfo;
  659. hr = pPin->QueryPinInfo(&pinfo);
  660. if (hr == NOERROR) {
  661. pinfo.pFilter->Release();
  662. if (pinfo.dir == m_Direction) {
  663. hr = VFW_E_INVALID_DIRECTION;
  664. }
  665. }
  666. }
  667. }
  668. return hr;
  669. }