A Fast Bresenham Type Algorithm For Drawing Ellipses by John Kennedy
[xy_vsfilter.git] / src / filters / BaseClasses / transip.cpp
blob5b0e4f1916afd4c4f2e867d899c88f162dbfef49
1 //------------------------------------------------------------------------------
2 // File: TransIP.cpp
3 //
4 // Desc: DirectShow base classes - implements class for simple Transform-
5 // In-Place filters such as audio.
6 //
7 // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
11 // How allocators are decided.
13 // An in-place transform tries to do its work in someone else's buffers.
14 // It tries to persuade the filters on either side to use the same allocator
15 // (and for that matter the same media type). In desperation, if the downstream
16 // filter refuses to supply an allocator and the upstream filter offers only
17 // a read-only one then it will provide an allocator.
18 // if the upstream filter insists on a read-only allocator then the transform
19 // filter will (reluctantly) copy the data before transforming it.
21 // In order to pass an allocator through it needs to remember the one it got
22 // from the first connection to pass it on to the second one.
24 // It is good if we can avoid insisting on a particular order of connection
25 // (There is a precedent for insisting on the input
26 // being connected first. Insisting on the output being connected first is
27 // not allowed. That would break RenderFile.)
29 // The base pin classes (CBaseOutputPin and CBaseInputPin) both have a
30 // m_pAllocator member which is used in places like
31 // CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive.
32 // To avoid lots of extra overriding, we should keep these happy
33 // by using these pointers.
35 // When each pin is connected, it will set the corresponding m_pAllocator
36 // and will have a single ref-count on that allocator.
38 // Refcounts are acquired by GetAllocator calls which return AddReffed
39 // allocators and are released in one of:
40 // CBaseInputPin::Disconnect
41 // CBaseOutputPin::BreakConect
42 // In each case m_pAllocator is set to NULL after the release, so this
43 // is the last chance to ever release it. If there should ever be
44 // multiple refcounts associated with the same pointer, this had better
45 // be cleared up before that happens. To avoid such problems, we'll
46 // stick with one per pointer.
50 // RECONNECTING and STATE CHANGES
52 // Each pin could be disconnected, connected with a read-only allocator,
53 // connected with an upstream read/write allocator, connected with an
54 // allocator from downstream or connected with its own allocator.
55 // Five states for each pin gives a data space of 25 states.
57 // Notation:
59 // R/W == read/write
60 // R-O == read-only
62 // <input pin state> <output pin state> <comments>
64 // 00 means an unconnected pin.
65 // <- means using a R/W allocator from the upstream filter
66 // <= means using a R-O allocator from an upstream filter
67 // || means using our own (R/W) allocator.
68 // -> means using a R/W allocator from a downstream filter
69 // (a R-O allocator from downstream is nonsense, it can't ever work).
72 // That makes 25 possible states. Some states are nonsense (two different
73 // allocators from the same place). These are just an artifact of the notation.
74 // <= <- Nonsense.
75 // <- <= Nonsense
76 // Some states are illegal (the output pin never accepts a R-O allocator):
77 // 00 <= !! Error !!
78 // <= <= !! Error !!
79 // || <= !! Error !!
80 // -> <= !! Error !!
81 // Three states appears to be inaccessible:
82 // -> || Inaccessible
83 // || -> Inaccessible
84 // || <- Inaccessible
85 // Some states only ever occur as intermediates with a pending reconnect which
86 // is guaranteed to finish in another state.
87 // -> 00 ?? unstable goes to || 00
88 // 00 <- ?? unstable goes to 00 ||
89 // -> <- ?? unstable goes to -> ->
90 // <- || ?? unstable goes to <- <-
91 // <- -> ?? unstable goes to <- <-
92 // And that leaves 11 possible resting states:
93 // 1 00 00 Nothing connected.
94 // 2 <- 00 Input pin connected.
95 // 3 <= 00 Input pin connected using R-O allocator.
96 // 4 || 00 Needs several state changes to get here.
97 // 5 00 || Output pin connected using our allocator
98 // 6 00 -> Downstream only connected
99 // 7 || || Undesirable but can be forced upon us.
100 // 8 <= || Copy forced. <= -> is preferable
101 // 9 <= -> OK - forced to copy.
102 // 10 <- <- Transform in place (ideal)
103 // 11 -> -> Transform in place (ideal)
105 // The object of the exercise is to ensure that we finish up in states
106 // 10 or 11 whenever possible. State 10 is only possible if the upstream
107 // filter has a R/W allocator (the AVI splitter notoriously
108 // doesn't) and state 11 is only possible if the downstream filter does
109 // offer an allocator.
111 // The transition table (entries marked * go via a reconnect)
113 // There are 8 possible transitions:
114 // A: Connect upstream to filter with R-O allocator that insists on using it.
115 // B: Connect upstream to filter with R-O allocator but chooses not to use it.
116 // C: Connect upstream to filter with R/W allocator and insists on using it.
117 // D: Connect upstream to filter with R/W allocator but chooses not to use it.
118 // E: Connect downstream to a filter that offers an allocator
119 // F: Connect downstream to a filter that does not offer an allocator
120 // G: disconnect upstream
121 // H: Disconnect downstream
123 // A B C D E F G H
124 // ---------------------------------------------------------
125 // 00 00 1 | 3 3 2 2 6 5 . . |1 00 00
126 // <- 00 2 | . . . . *10/11 10 1 . |2 <- 00
127 // <= 00 3 | . . . . *9/11 *7/8 1 . |3 <= 00
128 // || 00 4 | . . . . *8 *7 1 . |4 || 00
129 // 00 || 5 | 8 7 *10 7 . . . 1 |5 00 ||
130 // 00 -> 6 | 9 11 *10 11 . . . 1 |6 00 ->
131 // || || 7 | . . . . . . 5 4 |7 || ||
132 // <= || 8 | . . . . . . 5 3 |8 <= ||
133 // <= -> 9 | . . . . . . 6 3 |9 <= ->
134 // <- <- 10| . . . . . . *5/6 2 |10 <- <-
135 // -> -> 11| . . . . . . 6 *2/3 |11 -> ->
136 // ---------------------------------------------------------
137 // A B C D E F G H
139 // All these states are accessible without requiring any filter to
140 // change its behaviour but not all transitions are accessible, for
141 // instance a transition from state 4 to anywhere other than
142 // state 8 requires that the upstream filter first offer a R-O allocator
143 // and then changes its mind and offer R/W. This is NOT allowable - it
144 // leads to things like the output pin getting a R/W allocator from
145 // upstream and then the input pin being told it can only have a R-O one.
146 // Note that you CAN change (say) the upstream filter for a different one, but
147 // only as a disconnect / connect, not as a Reconnect. (Exercise for
148 // the reader is to see how you get into state 4).
150 // The reconnection stuff goes as follows (some of the cases shown here as
151 // "no reconnect" may get one to finalise media type - an old story).
152 // If there is a reconnect where it says "no reconnect" here then the
153 // reconnection must not change the allocator choice.
155 // state 2: <- 00 transition E <- <- case C <- <- (no change)
156 // case D -> <- and then to -> ->
158 // state 2: <- 00 transition F <- <- (no reconnect)
160 // state 3: <= 00 transition E <= -> case A <= -> (no change)
161 // case B -> ->
162 // transition F <= || case A <= || (no change)
163 // case B || ||
165 // state 4: || 00 transition E || || case B -> || and then all cases to -> ->
166 // F || || case B || || (no change)
168 // state 5: 00 || transition A <= || (no reconnect)
169 // B || || (no reconnect)
170 // C <- || all cases <- <-
171 // D || || (unfortunate, but upstream's choice)
173 // state 6: 00 -> transition A <= -> (no reconnect)
174 // B -> -> (no reconnect)
175 // C <- -> all cases <- <-
176 // D -> -> (no reconnect)
178 // state 10:<- <- transition G 00 <- case E 00 ->
179 // case F 00 ||
181 // state 11:-> -> transition H -> 00 case A <= 00 (schizo)
182 // case B <= 00
183 // case C <- 00 (schizo)
184 // case D <- 00
186 // The Rules:
187 // To sort out media types:
188 // The input is reconnected
189 // if the input pin is connected and the output pin connects
190 // The output is reconnected
191 // If the output pin is connected
192 // and the input pin connects to a different media type
194 // To sort out allocators:
195 // The input is reconnected
196 // if the output disconnects and the input was using a downstream allocator
197 // The output pin calls SetAllocator to pass on a new allocator
198 // if the output is connected and
199 // if the input disconnects and the output was using an upstream allocator
200 // if the input acquires an allocator different from the output one
201 // and that new allocator is not R-O
203 // Data is copied (i.e. call getbuffer and copy the data before transforming it)
204 // if the two allocators are different.
208 // CHAINS of filters:
210 // We sit between two filters (call them A and Z). We should finish up
211 // with the same allocator on both of our pins and that should be the
212 // same one that A and Z would have agreed on if we hadn't been in the
213 // way. Furthermore, it should not matter how many in-place transforms
214 // are in the way. Let B, C, D... be in-place transforms ("us").
215 // Here's how it goes:
217 // 1.
218 // A connects to B. They agree on A's allocator.
219 // A-a->B
221 // 2.
222 // B connects to C. Same story. There is no point in a reconnect, but
223 // B will request an input reconnect anyway.
224 // A-a->B-a->C
226 // 3.
227 // C connects to Z.
228 // C insists on using A's allocator, but compromises by requesting a reconnect.
229 // of C's input.
230 // A-a->B-?->C-a->Z
232 // We now have pending reconnects on both A--->B and B--->C
234 // 4.
235 // The A--->B link is reconnected.
236 // A asks B for an allocator. B sees that it has a downstream connection so
237 // asks its downstream input pin i.e. C's input pin for an allocator. C sees
238 // that it too has a downstream connection so asks Z for an allocator.
240 // Even though Z's input pin is connected, it is being asked for an allocator.
241 // It could refuse, in which case the chain is done and will use A's allocator
242 // Alternatively, Z may supply one. A chooses either Z's or A's own one.
243 // B's input pin gets NotifyAllocator called to tell it the decision and it
244 // propagates this downstream by calling ReceiveAllocator on its output pin
245 // which calls NotifyAllocator on the next input pin downstream etc.
246 // If the choice is Z then it goes:
247 // A-z->B-a->C-a->Z
248 // A-z->B-z->C-a->Z
249 // A-z->B-z->C-z->Z
251 // And that's IT!! Any further (essentially spurious) reconnects peter out
252 // with no change in the chain.
254 #include <streams.h>
255 #include <measure.h>
256 #include <transip.h>
259 // =================================================================
260 // Implements the CTransInPlaceFilter class
261 // =================================================================
263 CTransInPlaceFilter::CTransInPlaceFilter
264 ( TCHAR *pName,
265 LPUNKNOWN pUnk,
266 REFCLSID clsid,
267 HRESULT *phr,
268 bool bModifiesData
270 : CTransformFilter(pName, pUnk, clsid),
271 m_bModifiesData(bModifiesData)
273 #ifdef PERF
274 RegisterPerfId();
275 #endif // PERF
277 } // constructor
279 #ifdef UNICODE
280 CTransInPlaceFilter::CTransInPlaceFilter
281 ( CHAR *pName,
282 LPUNKNOWN pUnk,
283 REFCLSID clsid,
284 HRESULT *phr,
285 bool bModifiesData
287 : CTransformFilter(pName, pUnk, clsid),
288 m_bModifiesData(bModifiesData)
290 #ifdef PERF
291 RegisterPerfId();
292 #endif // PERF
294 } // constructor
295 #endif
297 // return a non-addrefed CBasePin * for the user to addref if he holds onto it
298 // for longer than his pointer to us. We create the pins dynamically when they
299 // are asked for rather than in the constructor. This is because we want to
300 // give the derived class an oppportunity to return different pin objects
302 // As soon as any pin is needed we create both (this is different from the
303 // usual transform filter) because enumerators, allocators etc are passed
304 // through from one pin to another and it becomes very painful if the other
305 // pin isn't there. If we fail to create either pin we ensure we fail both.
307 CBasePin *
308 CTransInPlaceFilter::GetPin(int n)
310 HRESULT hr = S_OK;
312 // Create an input pin if not already done
314 if (m_pInput == NULL) {
316 m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin")
317 , this // Owner filter
318 , &hr // Result code
319 , L"Input" // Pin name
322 // Constructor for CTransInPlaceInputPin can't fail
323 ASSERT(SUCCEEDED(hr));
326 // Create an output pin if not already done
328 if (m_pInput!=NULL && m_pOutput == NULL) {
330 m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin")
331 , this // Owner filter
332 , &hr // Result code
333 , L"Output" // Pin name
336 // a failed return code should delete the object
338 ASSERT(SUCCEEDED(hr));
339 if (m_pOutput == NULL) {
340 delete m_pInput;
341 m_pInput = NULL;
345 // Return the appropriate pin
347 ASSERT (n>=0 && n<=1);
348 if (n == 0) {
349 return m_pInput;
350 } else if (n==1) {
351 return m_pOutput;
352 } else {
353 return NULL;
356 } // GetPin
360 // dir is the direction of our pin.
361 // pReceivePin is the pin we are connecting to.
362 HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin)
364 UNREFERENCED_PARAMETER(pReceivePin);
365 ASSERT(m_pInput);
366 ASSERT(m_pOutput);
368 // if we are not part of a graph, then don't indirect the pointer
369 // this probably prevents use of the filter without a filtergraph
370 if (!m_pGraph) {
371 return VFW_E_NOT_IN_GRAPH;
374 // Always reconnect the input to account for buffering changes
376 // Because we don't get to suggest a type on ReceiveConnection
377 // we need another way of making sure the right type gets used.
379 // One way would be to have our EnumMediaTypes return our output
380 // connection type first but more deterministic and simple is to
381 // call ReconnectEx passing the type we want to reconnect with
382 // via the base class ReconeectPin method.
384 if (dir == PINDIR_OUTPUT) {
385 if( m_pInput->IsConnected() ) {
386 return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() );
388 return NOERROR;
391 ASSERT(dir == PINDIR_INPUT);
393 // Reconnect output if necessary
395 if( m_pOutput->IsConnected() ) {
397 if ( m_pInput->CurrentMediaType()
398 != m_pOutput->CurrentMediaType()
400 return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() );
403 return NOERROR;
405 } // ComnpleteConnect
409 // DecideBufferSize
411 // Tell the output pin's allocator what size buffers we require.
412 // *pAlloc will be the allocator our output pin is using.
415 HRESULT CTransInPlaceFilter::DecideBufferSize
416 ( IMemAllocator *pAlloc
417 , ALLOCATOR_PROPERTIES *pProperties
420 ALLOCATOR_PROPERTIES Request, Actual;
421 HRESULT hr;
423 // If we are connected upstream, get his views
424 if (m_pInput->IsConnected()) {
425 // Get the input pin allocator, and get its size and count.
426 // we don't care about his alignment and prefix.
428 hr = InputPin()->PeekAllocator()->GetProperties(&Request);
429 if (FAILED(hr)) {
430 // Input connected but with a secretive allocator - enough!
431 return hr;
433 } else {
434 // We're reduced to blind guessing. Let's guess one byte and if
435 // this isn't enough then when the other pin does get connected
436 // we can revise it.
437 ZeroMemory(&Request, sizeof(Request));
438 Request.cBuffers = 1;
439 Request.cbBuffer = 1;
443 DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements")));
444 DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"),
445 Request.cBuffers, Request.cbBuffer));
447 // Pass the allocator requirements to our output side
448 // but do a little sanity checking first or we'll just hit
449 // asserts in the allocator.
451 pProperties->cBuffers = Request.cBuffers;
452 pProperties->cbBuffer = Request.cbBuffer;
453 pProperties->cbAlign = Request.cbAlign;
454 if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; }
455 if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; }
456 hr = pAlloc->SetProperties(pProperties, &Actual);
458 if (FAILED(hr)) {
459 return hr;
462 DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements")));
463 DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"),
464 Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign));
466 // Make sure we got the right alignment and at least the minimum required
468 if ( (Request.cBuffers > Actual.cBuffers)
469 || (Request.cbBuffer > Actual.cbBuffer)
470 || (Request.cbAlign > Actual.cbAlign)
472 return E_FAIL;
474 return NOERROR;
476 } // DecideBufferSize
479 // Copy
481 // return a pointer to an identical copy of pSample
482 IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource)
484 IMediaSample * pDest;
486 HRESULT hr;
487 REFERENCE_TIME tStart, tStop;
488 const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop);
490 // this may block for an indeterminate amount of time
491 hr = OutputPin()->PeekAllocator()->GetBuffer(
492 &pDest
493 , bTime ? &tStart : NULL
494 , bTime ? &tStop : NULL
495 , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0
498 if (FAILED(hr)) {
499 return NULL;
502 ASSERT(pDest);
503 IMediaSample2 *pSample2;
504 if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
505 HRESULT hr = pSample2->SetProperties(
506 FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer),
507 (PBYTE)m_pInput->SampleProps());
508 pSample2->Release();
509 if (FAILED(hr)) {
510 pDest->Release();
511 return NULL;
513 } else {
514 if (bTime) {
515 pDest->SetTime(&tStart, &tStop);
518 if (S_OK == pSource->IsSyncPoint()) {
519 pDest->SetSyncPoint(TRUE);
521 if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) {
522 pDest->SetDiscontinuity(TRUE);
524 if (S_OK == pSource->IsPreroll()) {
525 pDest->SetPreroll(TRUE);
528 // Copy the media type
529 AM_MEDIA_TYPE *pMediaType;
530 if (S_OK == pSource->GetMediaType(&pMediaType)) {
531 pDest->SetMediaType(pMediaType);
532 DeleteMediaType( pMediaType );
537 m_bSampleSkipped = FALSE;
539 // Copy the sample media times
540 REFERENCE_TIME TimeStart, TimeEnd;
541 if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) {
542 pDest->SetMediaTime(&TimeStart,&TimeEnd);
545 // Copy the actual data length and the actual data.
547 const long lDataLength = pSource->GetActualDataLength();
548 pDest->SetActualDataLength(lDataLength);
550 // Copy the sample data
552 BYTE *pSourceBuffer, *pDestBuffer;
553 long lSourceSize = pSource->GetSize();
554 long lDestSize = pDest->GetSize();
556 ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength);
558 pSource->GetPointer(&pSourceBuffer);
559 pDest->GetPointer(&pDestBuffer);
560 ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL);
562 CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength );
566 return pDest;
568 } // Copy
571 // override this to customize the transform process
573 HRESULT
574 CTransInPlaceFilter::Receive(IMediaSample *pSample)
576 /* Check for other streams and pass them on */
577 AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
578 if (pProps->dwStreamId != AM_STREAM_MEDIA) {
579 return m_pOutput->Deliver(pSample);
581 HRESULT hr;
583 // Start timing the TransInPlace (if PERF is defined)
584 MSR_START(m_idTransInPlace);
586 if (UsingDifferentAllocators()) {
588 // We have to copy the data.
590 pSample = Copy(pSample);
592 if (pSample==NULL) {
593 MSR_STOP(m_idTransInPlace);
594 return E_UNEXPECTED;
598 // have the derived class transform the data
599 hr = Transform(pSample);
601 // Stop the clock and log it (if PERF is defined)
602 MSR_STOP(m_idTransInPlace);
604 if (FAILED(hr)) {
605 DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));
606 if (UsingDifferentAllocators()) {
607 pSample->Release();
609 return hr;
612 // the Transform() function can return S_FALSE to indicate that the
613 // sample should not be delivered; we only deliver the sample if it's
614 // really S_OK (same as NOERROR, of course.)
615 if (hr == NOERROR) {
616 hr = m_pOutput->Deliver(pSample);
617 } else {
618 // But it would be an error to return this private workaround
619 // to the caller ...
620 if (S_FALSE == hr) {
621 // S_FALSE returned from Transform is a PRIVATE agreement
622 // We should return NOERROR from Receive() in this cause because
623 // returning S_FALSE from Receive() means that this is the end
624 // of the stream and no more data should be sent.
625 m_bSampleSkipped = TRUE;
626 if (!m_bQualityChanged) {
627 NotifyEvent(EC_QUALITY_CHANGE,0,0);
628 m_bQualityChanged = TRUE;
630 hr = NOERROR;
634 // release the output buffer. If the connected pin still needs it,
635 // it will have addrefed it itself.
636 if (UsingDifferentAllocators()) {
637 pSample->Release();
640 return hr;
642 } // Receive
646 // =================================================================
647 // Implements the CTransInPlaceInputPin class
648 // =================================================================
651 // constructor
653 CTransInPlaceInputPin::CTransInPlaceInputPin
654 ( TCHAR *pObjectName
655 , CTransInPlaceFilter *pFilter
656 , HRESULT *phr
657 , LPCWSTR pName
659 : CTransformInputPin(pObjectName,
660 pFilter,
661 phr,
662 pName)
663 , m_bReadOnly(FALSE)
664 , m_pTIPFilter(pFilter)
666 DbgLog((LOG_TRACE, 2
667 , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin")));
669 } // constructor
672 // =================================================================
673 // Implements IMemInputPin interface
674 // =================================================================
677 // If the downstream filter has one then offer that (even if our own output
678 // pin is not using it yet. If the upstream filter chooses it then we will
679 // tell our output pin to ReceiveAllocator).
680 // Else if our output pin is using an allocator then offer that.
681 // ( This could mean offering the upstream filter his own allocator,
682 // it could mean offerring our own
683 // ) or it could mean offering the one from downstream
684 // Else fail to offer any allocator at all.
686 STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator)
688 CheckPointer(ppAllocator,E_POINTER);
689 ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
690 CAutoLock cObjectLock(m_pLock);
692 HRESULT hr;
694 if ( m_pTIPFilter->m_pOutput->IsConnected() ) {
695 // Store the allocator we got
696 hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
697 ->GetAllocator( ppAllocator );
698 if (SUCCEEDED(hr)) {
699 m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator );
702 else {
703 // Help upstream filter (eg TIP filter which is having to do a copy)
704 // by providing a temp allocator here - we'll never use
705 // this allocator because when our output is connected we'll
706 // reconnect this pin
707 hr = CTransformInputPin::GetAllocator( ppAllocator );
709 return hr;
711 } // GetAllocator
715 /* Get told which allocator the upstream output pin is actually going to use */
718 STDMETHODIMP
719 CTransInPlaceInputPin::NotifyAllocator(
720 IMemAllocator * pAllocator,
721 BOOL bReadOnly)
723 HRESULT hr = S_OK;
724 CheckPointer(pAllocator,E_POINTER);
725 ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
727 CAutoLock cObjectLock(m_pLock);
729 m_bReadOnly = bReadOnly;
730 // If we modify data then don't accept the allocator if it's
731 // the same as the output pin's allocator
733 // If our output is not connected just accept the allocator
734 // We're never going to use this allocator because when our
735 // output pin is connected we'll reconnect this pin
736 if (!m_pTIPFilter->OutputPin()->IsConnected()) {
737 return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly);
740 // If the allocator is read-only and we're modifying data
741 // and the allocator is the same as the output pin's
742 // then reject
743 if (bReadOnly && m_pTIPFilter->m_bModifiesData) {
744 IMemAllocator *pOutputAllocator =
745 m_pTIPFilter->OutputPin()->PeekAllocator();
747 // Make sure we have an output allocator
748 if (pOutputAllocator == NULL) {
749 hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()->
750 GetAllocator(&pOutputAllocator);
751 if(FAILED(hr)) {
752 hr = CreateMemoryAllocator(&pOutputAllocator);
754 if (SUCCEEDED(hr)) {
755 m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator);
756 pOutputAllocator->Release();
759 if (pAllocator == pOutputAllocator) {
760 hr = E_FAIL;
761 } else if(SUCCEEDED(hr)) {
762 // Must copy so set the allocator properties on the output
763 ALLOCATOR_PROPERTIES Props, Actual;
764 hr = pAllocator->GetProperties(&Props);
765 if (SUCCEEDED(hr)) {
766 hr = pOutputAllocator->SetProperties(&Props, &Actual);
768 if (SUCCEEDED(hr)) {
769 if ( (Props.cBuffers > Actual.cBuffers)
770 || (Props.cbBuffer > Actual.cbBuffer)
771 || (Props.cbAlign > Actual.cbAlign)
773 hr = E_FAIL;
777 // Set the allocator on the output pin
778 if (SUCCEEDED(hr)) {
779 hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
780 ->NotifyAllocator( pOutputAllocator, FALSE );
783 } else {
784 hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
785 ->NotifyAllocator( pAllocator, bReadOnly );
786 if (SUCCEEDED(hr)) {
787 m_pTIPFilter->OutputPin()->SetAllocator( pAllocator );
791 if (SUCCEEDED(hr)) {
793 // It's possible that the old and the new are the same thing.
794 // AddRef before release ensures that we don't unload it.
795 pAllocator->AddRef();
797 if( m_pAllocator != NULL )
798 m_pAllocator->Release();
800 m_pAllocator = pAllocator; // We have an allocator for the input pin
803 return hr;
805 } // NotifyAllocator
808 // EnumMediaTypes
809 // - pass through to our downstream filter
810 STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
812 // Can only pass through if connected
813 if( !m_pTIPFilter->m_pOutput->IsConnected() )
814 return VFW_E_NOT_CONNECTED;
816 return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum );
818 } // EnumMediaTypes
821 // CheckMediaType
822 // - agree to anything if not connected,
823 // otherwise pass through to the downstream filter.
824 // This assumes that the filter does not change the media type.
826 HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt )
828 HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
829 if (hr!=S_OK) return hr;
831 if( m_pTIPFilter->m_pOutput->IsConnected() )
832 return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt );
833 else
834 return S_OK;
836 } // CheckMediaType
839 // If upstream asks us what our requirements are, we will try to ask downstream
840 // if that doesn't work, we'll just take the defaults.
841 STDMETHODIMP
842 CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps)
845 if( m_pTIPFilter->m_pOutput->IsConnected() )
846 return m_pTIPFilter->OutputPin()
847 ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps );
848 else
849 return E_NOTIMPL;
851 } // GetAllocatorRequirements
854 // CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect()
855 // and then calls CTransInPlaceFilter::CompleteConnect(). It does this because
856 // CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not
857 // want to reconnect a pin if CBaseInputPin::CompleteConnect() fails.
858 HRESULT
859 CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin)
861 HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin);
862 if (FAILED(hr)) {
863 return hr;
866 return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
867 } // CompleteConnect
870 // =================================================================
871 // Implements the CTransInPlaceOutputPin class
872 // =================================================================
875 // constructor
877 CTransInPlaceOutputPin::CTransInPlaceOutputPin(
878 TCHAR *pObjectName,
879 CTransInPlaceFilter *pFilter,
880 HRESULT * phr,
881 LPCWSTR pPinName)
882 : CTransformOutputPin( pObjectName
883 , pFilter
884 , phr
885 , pPinName),
886 m_pTIPFilter(pFilter)
888 DbgLog(( LOG_TRACE, 2
889 , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin")));
891 } // constructor
894 // EnumMediaTypes
895 // - pass through to our upstream filter
896 STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
898 // Can only pass through if connected.
899 if( ! m_pTIPFilter->m_pInput->IsConnected() )
900 return VFW_E_NOT_CONNECTED;
902 return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum );
904 } // EnumMediaTypes
908 // CheckMediaType
909 // - agree to anything if not connected,
910 // otherwise pass through to the upstream filter.
912 HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt )
914 // Don't accept any output pin type changes if we're copying
915 // between allocators - it's too late to change the input
916 // allocator size.
917 if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) {
918 if (*pmt == m_mt) {
919 return S_OK;
920 } else {
921 return VFW_E_TYPE_NOT_ACCEPTED;
925 // Assumes the type does not change. That's why we're calling
926 // CheckINPUTType here on the OUTPUT pin.
927 HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
928 if (hr!=S_OK) return hr;
930 if( m_pTIPFilter->m_pInput->IsConnected() )
931 return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt );
932 else
933 return S_OK;
935 } // CheckMediaType
938 /* Save the allocator pointer in the output pin
940 void
941 CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator)
943 pAllocator->AddRef();
944 if (m_pAllocator) {
945 m_pAllocator->Release();
947 m_pAllocator = pAllocator;
948 } // SetAllocator
951 // CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect()
952 // and then calls CTransInPlaceFilter::CompleteConnect(). It does this because
953 // CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to
954 // reconnect a pin if CBaseOutputPin::CompleteConnect() fails.
955 // CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected
956 // to the Video Mixing Renderer.
957 HRESULT
958 CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin)
960 HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
961 if (FAILED(hr)) {
962 return hr;
965 return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
966 } // CompleteConnect