1 //------------------------------------------------------------------------------
4 // Desc: DirectShow base classes - implements CPullPin class that pulls data
7 // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
28 // returns S_OK if successfully connected to an IAsyncReader interface
30 // Optional allocator should be proposed as a preferred allocator if
33 CPullPin::Connect(IUnknown
* pUnk
, IMemAllocator
* pAlloc
, BOOL bSync
)
35 CAutoLock
lock(&m_AccessLock
);
38 return VFW_E_ALREADY_CONNECTED
;
41 HRESULT hr
= pUnk
->QueryInterface(IID_IAsyncReader
, (void**)&m_pReader
);
46 hr
= DecideAllocator(pAlloc
, NULL
);
52 LONGLONG llTotal
, llAvail
;
53 hr
= m_pReader
->Length(&llTotal
, &llAvail
);
59 // convert from file position to reference time
60 m_tDuration
= llTotal
* UNITS
;
61 m_tStop
= m_tDuration
;
69 // disconnect any connection made in Connect
71 CPullPin::Disconnect()
73 CAutoLock
lock(&m_AccessLock
);
90 // agree an allocator using RequestAllocator - optional
91 // props param specifies your requirements (non-zero fields).
92 // returns an error code if fail to match requirements.
93 // optional IMemAllocator interface is offered as a preferred allocator
94 // but no error occurs if it can't be met.
96 CPullPin::DecideAllocator(
97 IMemAllocator
* pAlloc
,
98 ALLOCATOR_PROPERTIES
* pProps
)
100 ALLOCATOR_PROPERTIES
*pRequest
;
101 ALLOCATOR_PROPERTIES Request
;
102 if (pProps
== NULL
) {
103 Request
.cBuffers
= 3;
104 Request
.cbBuffer
= 64*1024;
106 Request
.cbPrefix
= 0;
111 HRESULT hr
= m_pReader
->RequestAllocator(
118 // start pulling data
120 CPullPin::Active(void)
122 ASSERT(!ThreadExists());
123 return StartThread();
128 CPullPin::Inactive(void)
136 CPullPin::Seek(REFERENCE_TIME tStart
, REFERENCE_TIME tStop
)
138 CAutoLock
lock(&m_AccessLock
);
140 ThreadMsg AtStart
= m_State
;
142 if (AtStart
== TM_Start
) {
152 if (AtStart
== TM_Start
) {
160 CPullPin::Duration(REFERENCE_TIME
* ptDuration
)
162 *ptDuration
= m_tDuration
;
168 CPullPin::StartThread()
170 CAutoLock
lock(&m_AccessLock
);
172 if (!m_pAlloc
|| !m_pReader
) {
177 if (!ThreadExists()) {
180 hr
= m_pAlloc
->Commit();
192 hr
= (HRESULT
) CallWorker(m_State
);
197 CPullPin::PauseThread()
199 CAutoLock
lock(&m_AccessLock
);
201 if (!ThreadExists()) {
205 // need to flush to ensure the thread is not blocked
207 HRESULT hr
= m_pReader
->BeginFlush();
213 hr
= CallWorker(TM_Pause
);
215 m_pReader
->EndFlush();
220 CPullPin::StopThread()
222 CAutoLock
lock(&m_AccessLock
);
224 if (!ThreadExists()) {
228 // need to flush to ensure the thread is not blocked
230 HRESULT hr
= m_pReader
->BeginFlush();
236 hr
= CallWorker(TM_Exit
);
238 m_pReader
->EndFlush();
240 // wait for thread to completely exit
243 // decommit allocator
245 m_pAlloc
->Decommit();
253 CPullPin::ThreadProc(void)
256 DWORD cmd
= GetRequest();
263 // we are paused already
273 // at this point, there should be no outstanding requests on the
275 // We should force begin/endflush to ensure that this is true.
276 // !!!Note that we may currently be inside a BeginFlush/EndFlush pair
277 // on another thread, but the premature EndFlush will do no harm now
279 m_pReader
->BeginFlush();
281 m_pReader
->EndFlush();
286 CPullPin::QueueSample(
287 REFERENCE_TIME
& tCurrent
,
288 REFERENCE_TIME tAlignStop
,
292 IMediaSample
* pSample
;
294 HRESULT hr
= m_pAlloc
->GetBuffer(&pSample
, NULL
, NULL
, 0);
299 LONGLONG tStopThis
= tCurrent
+ (pSample
->GetSize() * UNITS
);
300 if (tStopThis
> tAlignStop
) {
301 tStopThis
= tAlignStop
;
303 pSample
->SetTime(&tCurrent
, &tStopThis
);
304 tCurrent
= tStopThis
;
306 pSample
->SetDiscontinuity(bDiscontinuity
);
308 hr
= m_pReader
->Request(
321 CPullPin::CollectAndDeliver(
322 REFERENCE_TIME tStart
,
323 REFERENCE_TIME tStop
)
325 IMediaSample
* pSample
= NULL
; // better be sure pSample is set
327 HRESULT hr
= m_pReader
->WaitForNext(
336 hr
= DeliverSample(pSample
, tStart
, tStop
);
347 CPullPin::DeliverSample(
348 IMediaSample
* pSample
,
349 REFERENCE_TIME tStart
,
353 // fix up sample if past actual stop (for sector alignment)
354 REFERENCE_TIME t1
, t2
;
355 pSample
->GetTime(&t1
, &t2
);
360 // adjust times to be relative to (aligned) start time
363 pSample
->SetTime(&t1
, &t2
);
366 HRESULT hr
= Receive(pSample
);
372 CPullPin::Process(void)
374 // is there anything to do?
375 if (m_tStop
<= m_tStart
) {
380 BOOL bDiscontinuity
= TRUE
;
382 // if there is more than one sample at the allocator,
383 // then try to queue 2 at once in order to overlap.
384 // -- get buffer count and required alignment
385 ALLOCATOR_PROPERTIES Actual
;
386 HRESULT hr
= m_pAlloc
->GetProperties(&Actual
);
388 // align the start position downwards
389 REFERENCE_TIME tStart
= AlignDown(m_tStart
/ UNITS
, Actual
.cbAlign
) * UNITS
;
390 REFERENCE_TIME tCurrent
= tStart
;
392 REFERENCE_TIME tStop
= m_tStop
;
393 if (tStop
> m_tDuration
) {
397 // align the stop position - may be past stop, but that
399 REFERENCE_TIME tAlignStop
= AlignUp(tStop
/ UNITS
, Actual
.cbAlign
) * UNITS
;
406 // Break out of the loop either if we get to the end or we're asked
407 // to do something else
408 while (tCurrent
< tAlignStop
) {
410 // Break out without calling EndOfStream if we're asked to
411 // do something different
412 if (CheckRequest(&dwRequest
)) {
416 // queue a first sample
417 if (Actual
.cBuffers
> 1) {
419 hr
= QueueSample(tCurrent
, tAlignStop
, TRUE
);
420 bDiscontinuity
= FALSE
;
429 // loop queueing second and waiting for first..
430 while (tCurrent
< tAlignStop
) {
432 hr
= QueueSample(tCurrent
, tAlignStop
, bDiscontinuity
);
433 bDiscontinuity
= FALSE
;
439 hr
= CollectAndDeliver(tStart
, tStop
);
442 // stop if error, or if downstream filter said
448 if (Actual
.cBuffers
> 1) {
449 hr
= CollectAndDeliver(tStart
, tStop
);
457 // sync version of above loop
458 while (tCurrent
< tAlignStop
) {
460 // Break out without calling EndOfStream if we're asked to
461 // do something different
462 if (CheckRequest(&dwRequest
)) {
466 IMediaSample
* pSample
;
468 hr
= m_pAlloc
->GetBuffer(&pSample
, NULL
, NULL
, 0);
474 LONGLONG tStopThis
= tCurrent
+ (pSample
->GetSize() * UNITS
);
475 if (tStopThis
> tAlignStop
) {
476 tStopThis
= tAlignStop
;
478 pSample
->SetTime(&tCurrent
, &tStopThis
);
479 tCurrent
= tStopThis
;
481 if (bDiscontinuity
) {
482 pSample
->SetDiscontinuity(TRUE
);
483 bDiscontinuity
= FALSE
;
486 hr
= m_pReader
->SyncReadAligned(pSample
);
494 hr
= DeliverSample(pSample
, tStart
, tStop
);
507 // after a flush, cancelled i/o will be waiting for collection
510 CPullPin::CleanupCancelled(void)
513 IMediaSample
* pSample
;
516 HRESULT hr
= m_pReader
->WaitForNext(