AJA NTV2 SDK  17.6.0.2675
NTV2 SDK 17.6.0.2675
transip.cpp
Go to the documentation of this file.
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-2001 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
9 
10 
11 // How allocators are decided.
12 //
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.
20 //
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.
23 //
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.)
28 //
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.
34 //
35 // When each pin is connected, it will set the corresponding m_pAllocator
36 // and will have a single ref-count on that allocator.
37 //
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.
47 
48 
49 
50 // RECONNECTING and STATE CHANGES
51 //
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.
56 //
57 // Notation:
58 //
59 // R/W == read/write
60 // R-O == read-only
61 //
62 // <input pin state> <output pin state> <comments>
63 //
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).
70 //
71 //
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)
104 //
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.
110 //
111 // The transition table (entries marked * go via a reconnect)
112 //
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
122 //
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
138 //
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).
149 //
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.
154 //
155 // state 2: <- 00 transition E <- <- case C <- <- (no change)
156 // case D -> <- and then to -> ->
157 //
158 // state 2: <- 00 transition F <- <- (no reconnect)
159 //
160 // state 3: <= 00 transition E <= -> case A <= -> (no change)
161 // case B -> ->
162 // transition F <= || case A <= || (no change)
163 // case B || ||
164 //
165 // state 4: || 00 transition E || || case B -> || and then all cases to -> ->
166 // F || || case B || || (no change)
167 //
168 // state 5: 00 || transition A <= || (no reconnect)
169 // B || || (no reconnect)
170 // C <- || all cases <- <-
171 // D || || (unfortunate, but upstream's choice)
172 //
173 // state 6: 00 -> transition A <= -> (no reconnect)
174 // B -> -> (no reconnect)
175 // C <- -> all cases <- <-
176 // D -> -> (no reconnect)
177 //
178 // state 10:<- <- transition G 00 <- case E 00 ->
179 // case F 00 ||
180 //
181 // state 11:-> -> transition H -> 00 case A <= 00 (schizo)
182 // case B <= 00
183 // case C <- 00 (schizo)
184 // case D <- 00
185 //
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
193 //
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
202 //
203 // Data is copied (i.e. call getbuffer and copy the data before transforming it)
204 // if the two allocators are different.
205 
206 
207 
208 // CHAINS of filters:
209 //
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:
216 //
217 // 1.
218 // A connects to B. They agree on A's allocator.
219 // A-a->B
220 //
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
225 //
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
231 //
232 // We now have pending reconnects on both A--->B and B--->C
233 //
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.
239 //
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
250 //
251 // And that's IT!! Any further (essentially spurious) reconnects peter out
252 // with no change in the chain.
253 
254 #include <streams.h>
255 #include <measure.h>
256 #include <transip.h>
257 
258 
259 // =================================================================
260 // Implements the CTransInPlaceFilter class
261 // =================================================================
262 
264  ( __in_opt LPCTSTR pName,
265  __inout_opt LPUNKNOWN pUnk,
266  REFCLSID clsid,
267  __inout HRESULT *phr,
268  bool bModifiesData
269  )
270  : CTransformFilter(pName, pUnk, clsid),
271  m_bModifiesData(bModifiesData)
272 {
273 #ifdef PERF
274  RegisterPerfId();
275 #endif // PERF
276 
277 } // constructor
278 
279 #ifdef UNICODE
281  ( __in_opt LPCSTR pName,
282  __inout_opt LPUNKNOWN pUnk,
283  REFCLSID clsid,
284  __inout HRESULT *phr,
285  bool bModifiesData
286  )
287  : CTransformFilter(pName, pUnk, clsid),
288  m_bModifiesData(bModifiesData)
289 {
290 #ifdef PERF
291  RegisterPerfId();
292 #endif // PERF
293 
294 } // constructor
295 #endif
296 
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
301 
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.
306 
307 CBasePin *
309 {
310  HRESULT hr = S_OK;
311 
312  // Create an input pin if not already done
313 
314  if (m_pInput == NULL) {
315 
316  m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin")
317  , this // Owner filter
318  , &hr // Result code
319  , L"Input" // Pin name
320  );
321 
322  // Constructor for CTransInPlaceInputPin can't fail
323  ASSERT(SUCCEEDED(hr));
324  }
325 
326  // Create an output pin if not already done
327 
328  if (m_pInput!=NULL && m_pOutput == NULL) {
329 
330  m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin")
331  , this // Owner filter
332  , &hr // Result code
333  , L"Output" // Pin name
334  );
335 
336  // a failed return code should delete the object
337 
338  ASSERT(SUCCEEDED(hr));
339  if (m_pOutput == NULL) {
340  delete m_pInput;
341  m_pInput = NULL;
342  }
343  }
344 
345  // Return the appropriate pin
346 
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;
354  }
355 
356 } // GetPin
357 
358 
359 
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)
363 {
364  UNREFERENCED_PARAMETER(pReceivePin);
365  ASSERT(m_pInput);
366  ASSERT(m_pOutput);
367 
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;
372  }
373 
374  // Always reconnect the input to account for buffering changes
375  //
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.
378  //
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.
383 
384  if (dir == PINDIR_OUTPUT) {
385  if( m_pInput->IsConnected() ) {
387  }
388  return NOERROR;
389  }
390 
391  ASSERT(dir == PINDIR_INPUT);
392 
393  // Reconnect output if necessary
394 
395  if( m_pOutput->IsConnected() ) {
396 
397  if ( m_pInput->CurrentMediaType()
399  ) {
401  }
402  }
403  return NOERROR;
404 
405 } // ComnpleteConnect
406 
407 
408 //
409 // DecideBufferSize
410 //
411 // Tell the output pin's allocator what size buffers we require.
412 // *pAlloc will be the allocator our output pin is using.
413 //
414 
416  ( IMemAllocator *pAlloc
417  , __inout ALLOCATOR_PROPERTIES *pProperties
418  )
419 {
420  ALLOCATOR_PROPERTIES Request, Actual;
421  HRESULT hr;
422 
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.
427 
428  hr = InputPin()->PeekAllocator()->GetProperties(&Request);
429  if (FAILED(hr)) {
430  // Input connected but with a secretive allocator - enough!
431  return hr;
432  }
433  } else {
434  // Propose one byte
435  // If 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;
440  }
441 
442 
443  DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements")));
444  DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"),
445  Request.cBuffers, Request.cbBuffer));
446 
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.
450 
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);
457 
458  if (FAILED(hr)) {
459  return hr;
460  }
461 
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));
465 
466  // Make sure we got the right alignment and at least the minimum required
467 
468  if ( (Request.cBuffers > Actual.cBuffers)
469  || (Request.cbBuffer > Actual.cbBuffer)
470  || (Request.cbAlign > Actual.cbAlign)
471  ) {
472  return E_FAIL;
473  }
474  return NOERROR;
475 
476 } // DecideBufferSize
477 
478 //
479 // Copy
480 //
481 // return a pointer to an identical copy of pSample
482 __out_opt IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource)
483 {
484  IMediaSample * pDest;
485 
486  HRESULT hr;
487  REFERENCE_TIME tStart, tStop;
488  const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop);
489 
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
496  );
497 
498  if (FAILED(hr)) {
499  return NULL;
500  }
501 
502  ASSERT(pDest);
503  IMediaSample2 *pSample2;
504  if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
505  HRESULT hrProps = pSample2->SetProperties(
506  FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer),
507  (PBYTE)m_pInput->SampleProps());
508  pSample2->Release();
509  if (FAILED(hrProps)) {
510  pDest->Release();
511  return NULL;
512  }
513  } else {
514  if (bTime) {
515  pDest->SetTime(&tStart, &tStop);
516  }
517 
518  if (S_OK == pSource->IsSyncPoint()) {
519  pDest->SetSyncPoint(TRUE);
520  }
521  if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) {
522  pDest->SetDiscontinuity(TRUE);
523  }
524  if (S_OK == pSource->IsPreroll()) {
525  pDest->SetPreroll(TRUE);
526  }
527 
528  // Copy the media type
529  AM_MEDIA_TYPE *pMediaType;
530  if (S_OK == pSource->GetMediaType(&pMediaType)) {
531  pDest->SetMediaType(pMediaType);
532  DeleteMediaType( pMediaType );
533  }
534 
535  }
536 
537  m_bSampleSkipped = FALSE;
538 
539  // Copy the sample media times
540  REFERENCE_TIME TimeStart, TimeEnd;
541  if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) {
542  pDest->SetMediaTime(&TimeStart,&TimeEnd);
543  }
544 
545  // Copy the actual data length and the actual data.
546  {
547  const long lDataLength = pSource->GetActualDataLength();
548  if (FAILED(pDest->SetActualDataLength(lDataLength))) {
549  pDest->Release();
550  return NULL;
551  }
552 
553  // Copy the sample data
554  {
555  BYTE *pSourceBuffer, *pDestBuffer;
556  long lSourceSize = pSource->GetSize();
557  long lDestSize = pDest->GetSize();
558 
559  ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength);
560 
561  if (FAILED(pSource->GetPointer(&pSourceBuffer)) ||
562  FAILED(pDest->GetPointer(&pDestBuffer)) ||
563  lDestSize < lDataLength ||
564  lDataLength < 0) {
565  pDest->Release();
566  return NULL;
567  }
568  ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL);
569 
570  CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength );
571  }
572  }
573 
574  return pDest;
575 
576 } // Copy
577 
578 
579 // override this to customize the transform process
580 
581 HRESULT
582 CTransInPlaceFilter::Receive(IMediaSample *pSample)
583 {
584  /* Check for other streams and pass them on */
585  AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
586  if (pProps->dwStreamId != AM_STREAM_MEDIA) {
587  return m_pOutput->Deliver(pSample);
588  }
589  HRESULT hr;
590 
591  // Start timing the TransInPlace (if PERF is defined)
592  MSR_START(m_idTransInPlace);
593 
594  if (UsingDifferentAllocators()) {
595 
596  // We have to copy the data.
597 
598  pSample = Copy(pSample);
599 
600  if (pSample==NULL) {
601  MSR_STOP(m_idTransInPlace);
602  return E_UNEXPECTED;
603  }
604  }
605 
606  // have the derived class transform the data
607  hr = Transform(pSample);
608 
609  // Stop the clock and log it (if PERF is defined)
610  MSR_STOP(m_idTransInPlace);
611 
612  if (FAILED(hr)) {
613  DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));
614  if (UsingDifferentAllocators()) {
615  pSample->Release();
616  }
617  return hr;
618  }
619 
620  // the Transform() function can return S_FALSE to indicate that the
621  // sample should not be delivered; we only deliver the sample if it's
622  // really S_OK (same as NOERROR, of course.)
623  if (hr == NOERROR) {
624  hr = m_pOutput->Deliver(pSample);
625  } else {
626  // But it would be an error to return this private workaround
627  // to the caller ...
628  if (S_FALSE == hr) {
629  // S_FALSE returned from Transform is a PRIVATE agreement
630  // We should return NOERROR from Receive() in this cause because
631  // returning S_FALSE from Receive() means that this is the end
632  // of the stream and no more data should be sent.
633  m_bSampleSkipped = TRUE;
634  if (!m_bQualityChanged) {
635  NotifyEvent(EC_QUALITY_CHANGE,0,0);
636  m_bQualityChanged = TRUE;
637  }
638  hr = NOERROR;
639  }
640  }
641 
642  // release the output buffer. If the connected pin still needs it,
643  // it will have addrefed it itself.
644  if (UsingDifferentAllocators()) {
645  pSample->Release();
646  }
647 
648  return hr;
649 
650 } // Receive
651 
652 
653 
654 // =================================================================
655 // Implements the CTransInPlaceInputPin class
656 // =================================================================
657 
658 
659 // constructor
660 
662  ( __in_opt LPCTSTR pObjectName
663  , __inout CTransInPlaceFilter *pFilter
664  , __inout HRESULT *phr
665  , __in_opt LPCWSTR pName
666  )
667  : CTransformInputPin(pObjectName,
668  pFilter,
669  phr,
670  pName)
671  , m_bReadOnly(FALSE)
672  , m_pTIPFilter(pFilter)
673 {
674  DbgLog((LOG_TRACE, 2
675  , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin")));
676 
677 } // constructor
678 
679 
680 // =================================================================
681 // Implements IMemInputPin interface
682 // =================================================================
683 
684 
685 // If the downstream filter has one then offer that (even if our own output
686 // pin is not using it yet. If the upstream filter chooses it then we will
687 // tell our output pin to ReceiveAllocator).
688 // Else if our output pin is using an allocator then offer that.
689 // ( This could mean offering the upstream filter his own allocator,
690 // it could mean offerring our own
691 // ) or it could mean offering the one from downstream
692 // Else fail to offer any allocator at all.
693 
694 STDMETHODIMP CTransInPlaceInputPin::GetAllocator(__deref_out IMemAllocator ** ppAllocator)
695 {
696  CheckPointer(ppAllocator,E_POINTER);
697  ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
698  CAutoLock cObjectLock(m_pLock);
699 
700  HRESULT hr;
701 
702  if ( m_pTIPFilter->m_pOutput->IsConnected() ) {
703  // Store the allocator we got
705  ->GetAllocator( ppAllocator );
706  if (SUCCEEDED(hr)) {
707  m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator );
708  }
709  }
710  else {
711  // Help upstream filter (eg TIP filter which is having to do a copy)
712  // by providing a temp allocator here - we'll never use
713  // this allocator because when our output is connected we'll
714  // reconnect this pin
715  hr = CTransformInputPin::GetAllocator( ppAllocator );
716  }
717  return hr;
718 
719 } // GetAllocator
720 
721 
722 
723 /* Get told which allocator the upstream output pin is actually going to use */
724 
725 
726 STDMETHODIMP
728  IMemAllocator * pAllocator,
729  BOOL bReadOnly)
730 {
731  HRESULT hr = S_OK;
732  CheckPointer(pAllocator,E_POINTER);
733  ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
734 
735  CAutoLock cObjectLock(m_pLock);
736 
737  m_bReadOnly = bReadOnly;
738  // If we modify data then don't accept the allocator if it's
739  // the same as the output pin's allocator
740 
741  // If our output is not connected just accept the allocator
742  // We're never going to use this allocator because when our
743  // output pin is connected we'll reconnect this pin
744  if (!m_pTIPFilter->OutputPin()->IsConnected()) {
745  return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly);
746  }
747 
748  // If the allocator is read-only and we're modifying data
749  // and the allocator is the same as the output pin's
750  // then reject
751  if (bReadOnly && m_pTIPFilter->m_bModifiesData) {
752  IMemAllocator *pOutputAllocator =
754 
755  // Make sure we have an output allocator
756  if (pOutputAllocator == NULL) {
758  GetAllocator(&pOutputAllocator);
759  if(FAILED(hr)) {
760  hr = CreateMemoryAllocator(&pOutputAllocator);
761  }
762  if (SUCCEEDED(hr)) {
763  m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator);
764  pOutputAllocator->Release();
765  }
766  }
767  if (pAllocator == pOutputAllocator) {
768  hr = E_FAIL;
769  } else if(SUCCEEDED(hr)) {
770  // Must copy so set the allocator properties on the output
771  ALLOCATOR_PROPERTIES Props, Actual;
772  hr = pAllocator->GetProperties(&Props);
773  if (SUCCEEDED(hr)) {
774  hr = pOutputAllocator->SetProperties(&Props, &Actual);
775  }
776  if (SUCCEEDED(hr)) {
777  if ( (Props.cBuffers > Actual.cBuffers)
778  || (Props.cbBuffer > Actual.cbBuffer)
779  || (Props.cbAlign > Actual.cbAlign)
780  ) {
781  hr = E_FAIL;
782  }
783  }
784 
785  // Set the allocator on the output pin
786  if (SUCCEEDED(hr)) {
788  ->NotifyAllocator( pOutputAllocator, FALSE );
789  }
790  }
791  } else {
793  ->NotifyAllocator( pAllocator, bReadOnly );
794  if (SUCCEEDED(hr)) {
795  m_pTIPFilter->OutputPin()->SetAllocator( pAllocator );
796  }
797  }
798 
799  if (SUCCEEDED(hr)) {
800 
801  // It's possible that the old and the new are the same thing.
802  // AddRef before release ensures that we don't unload it.
803  pAllocator->AddRef();
804 
805  if( m_pAllocator != NULL )
806  m_pAllocator->Release();
807 
808  m_pAllocator = pAllocator; // We have an allocator for the input pin
809  }
810 
811  return hr;
812 
813 } // NotifyAllocator
814 
815 
816 // EnumMediaTypes
817 // - pass through to our downstream filter
818 STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum )
819 {
820  // Can only pass through if connected
822  return VFW_E_NOT_CONNECTED;
823 
824  return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum );
825 
826 } // EnumMediaTypes
827 
828 
829 // CheckMediaType
830 // - agree to anything if not connected,
831 // otherwise pass through to the downstream filter.
832 // This assumes that the filter does not change the media type.
833 
835 {
836  HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
837  if (hr!=S_OK) return hr;
838 
840  return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt );
841  else
842  return S_OK;
843 
844 } // CheckMediaType
845 
846 
847 // If upstream asks us what our requirements are, we will try to ask downstream
848 // if that doesn't work, we'll just take the defaults.
849 STDMETHODIMP
850 CTransInPlaceInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps)
851 {
852 
854  return m_pTIPFilter->OutputPin()
855  ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps );
856  else
857  return E_NOTIMPL;
858 
859 } // GetAllocatorRequirements
860 
861 
862 // CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect()
863 // and then calls CTransInPlaceFilter::CompleteConnect(). It does this because
864 // CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not
865 // want to reconnect a pin if CBaseInputPin::CompleteConnect() fails.
866 HRESULT
868 {
869  HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin);
870  if (FAILED(hr)) {
871  return hr;
872  }
873 
874  return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
875 } // CompleteConnect
876 
877 
878 // =================================================================
879 // Implements the CTransInPlaceOutputPin class
880 // =================================================================
881 
882 
883 // constructor
884 
886  __in_opt LPCTSTR pObjectName,
887  __inout CTransInPlaceFilter *pFilter,
888  __inout HRESULT * phr,
889  __in_opt LPCWSTR pPinName)
890  : CTransformOutputPin( pObjectName
891  , pFilter
892  , phr
893  , pPinName),
894  m_pTIPFilter(pFilter)
895 {
896  DbgLog(( LOG_TRACE, 2
897  , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin")));
898 
899 } // constructor
900 
901 
902 // EnumMediaTypes
903 // - pass through to our upstream filter
904 STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum )
905 {
906  // Can only pass through if connected.
907  if( ! m_pTIPFilter->m_pInput->IsConnected() )
908  return VFW_E_NOT_CONNECTED;
909 
910  return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum );
911 
912 } // EnumMediaTypes
913 
914 
915 
916 // CheckMediaType
917 // - agree to anything if not connected,
918 // otherwise pass through to the upstream filter.
919 
921 {
922  // Don't accept any output pin type changes if we're copying
923  // between allocators - it's too late to change the input
924  // allocator size.
926  if (*pmt == m_mt) {
927  return S_OK;
928  } else {
929  return VFW_E_TYPE_NOT_ACCEPTED;
930  }
931  }
932 
933  // Assumes the type does not change. That's why we're calling
934  // CheckINPUTType here on the OUTPUT pin.
935  HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
936  if (hr!=S_OK) return hr;
937 
939  return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt );
940  else
941  return S_OK;
942 
943 } // CheckMediaType
944 
945 
946 /* Save the allocator pointer in the output pin
947 */
948 void
949 CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator)
950 {
951  pAllocator->AddRef();
952  if (m_pAllocator) {
953  m_pAllocator->Release();
954  }
955  m_pAllocator = pAllocator;
956 } // SetAllocator
957 
958 
959 // CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect()
960 // and then calls CTransInPlaceFilter::CompleteConnect(). It does this because
961 // CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to
962 // reconnect a pin if CBaseOutputPin::CompleteConnect() fails.
963 // CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected
964 // to the Video Mixing Renderer.
965 HRESULT
967 {
968  HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
969  if (FAILED(hr)) {
970  return hr;
971  }
972 
973  return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
974 } // CompleteConnect
CTransformFilter::m_pOutput
CTransformOutputPin * m_pOutput
Definition: transfrm.h:299
CTransInPlaceOutputPin::m_pTIPFilter
CTransInPlaceFilter *const m_pTIPFilter
Definition: transip.h:96
CTransInPlaceFilter::OutputPin
__out CTransInPlaceOutputPin * OutputPin() const
Definition: transip.h:230
CBasePin::m_pLock
CCritSec * m_pLock
Definition: amfilter.h:338
CBasePin::GetConnected
IPin * GetConnected()
Definition: amfilter.h:501
CTransInPlaceInputPin::CheckMediaType
HRESULT CheckMediaType(const CMediaType *pmt)
Definition: transip.cpp:834
CBaseFilter::NotifyEvent
HRESULT NotifyEvent(long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
Definition: amfilter.cpp:811
CTransformOutputPin
Definition: transfrm.h:108
ValidateReadPtr
#define ValidateReadPtr(p, cb)
Definition: wxdebug.h:239
CBasePin
Definition: amfilter.h:330
CTransInPlaceOutputPin::SetAllocator
void SetAllocator(IMemAllocator *pAllocator)
Definition: transip.cpp:949
streams.h
CTransInPlaceFilter::m_bModifiesData
bool m_bModifiesData
Definition: transip.h:219
NULL
#define NULL
Definition: ntv2caption608types.h:19
CTransformFilter::m_pInput
CTransformInputPin * m_pInput
Definition: transfrm.h:298
CTransInPlaceFilter::GetPin
virtual CBasePin * GetPin(int n)
Definition: transip.cpp:308
MSR_STOP
#define MSR_STOP(a)
Definition: measure.h:138
CTransformOutputPin::CurrentMediaType
CMediaType & CurrentMediaType()
Definition: transfrm.h:170
LOG_TRACE
@ LOG_TRACE
Definition: wxdebug.h:45
NAME
#define NAME(_x_)
Definition: wxdebug.h:179
CTransInPlaceInputPin::EnumMediaTypes
STDMETHODIMP EnumMediaTypes(__deref_out IEnumMediaTypes **ppEnum)
Definition: transip.cpp:818
CBaseOutputPin::Deliver
virtual HRESULT Deliver(IMediaSample *)
Definition: amfilter.cpp:2685
CAutoLock
Definition: wxutil.h:83
CBaseInputPin::SampleProps
AM_SAMPLE2_PROPERTIES * SampleProps()
Definition: amfilter.h:938
CTransInPlaceFilter::UsingDifferentAllocators
BOOL UsingDifferentAllocators() const
Definition: transip.h:243
CBasePin::IsConnected
BOOL IsConnected(void)
Definition: amfilter.h:499
CBaseInputPin::NotifyAllocator
STDMETHODIMP NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly)
Definition: amfilter.cpp:2896
CMediaType
Definition: mtype.h:18
n
unsigned int n
Definition: pstream.cpp:148
CTransInPlaceInputPin::CompleteConnect
HRESULT CompleteConnect(IPin *pReceivePin)
Definition: transip.cpp:867
CTransformOutputPin::CTransformFilter
friend class CTransformFilter
Definition: transfrm.h:110
ValidateReadWritePtr
#define ValidateReadWritePtr(p, cb)
Definition: wxdebug.h:241
CTransInPlaceOutputPin::ConnectedIMemInputPin
__out_opt IMemInputPin * ConnectedIMemInputPin()
Definition: transip.h:125
CTransInPlaceInputPin::GetAllocatorRequirements
STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps)
Definition: transip.cpp:850
CBaseFilter::IsStopped
BOOL IsStopped()
Definition: amfilter.h:246
MSR_START
#define MSR_START(a)
Definition: measure.h:137
CBaseFilter::ReconnectPin
HRESULT ReconnectPin(IPin *pPin, __in_opt AM_MEDIA_TYPE const *pmt)
Definition: amfilter.cpp:834
CTransInPlaceFilter::DecideBufferSize
HRESULT DecideBufferSize(IMemAllocator *, __inout ALLOCATOR_PROPERTIES *)
Definition: transip.cpp:416
pName
CHAR * pName
Definition: amvideo.cpp:26
DbgLog
#define DbgLog(_x_)
Definition: wxdebug.h:183
CreateMemoryAllocator
STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator)
Definition: amfilter.cpp:41
transip.h
CTransInPlaceFilter::CTransInPlaceFilter
CTransInPlaceFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, bool bModifiesData=true)
Definition: transip.cpp:264
CTransInPlaceFilter
Definition: transip.h:138
CTransInPlaceInputPin::NotifyAllocator
STDMETHODIMP NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly)
Definition: transip.cpp:727
DeleteMediaType
void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt)
Definition: mtype.cpp:353
CTransInPlaceFilter::CTransInPlaceInputPin
friend class CTransInPlaceInputPin
Definition: transip.h:223
PVOID
void * PVOID
Definition: ajatypes.h:319
LOG_MEMORY
@ LOG_MEMORY
Definition: wxdebug.h:46
CTransformFilter::m_bQualityChanged
BOOL m_bQualityChanged
Definition: transfrm.h:277
CBaseOutputPin::CompleteConnect
virtual HRESULT CompleteConnect(IPin *pReceivePin)
Definition: amfilter.cpp:2488
CopyMemory
#define CopyMemory(a, b, c)
Definition: ntv2baremetaldriverinterface.h:16
CBaseOutputPin::m_pAllocator
IMemAllocator * m_pAllocator
Definition: amfilter.h:717
CTransInPlaceOutputPin::CheckMediaType
HRESULT CheckMediaType(const CMediaType *pmt)
Definition: transip.cpp:920
CTransformFilter::CompleteConnect
virtual HRESULT CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin)
Definition: transfrm.cpp:209
CTransInPlaceInputPin::GetAllocator
STDMETHODIMP GetAllocator(__deref_out IMemAllocator **ppAllocator)
Definition: transip.cpp:694
CTransInPlaceFilter::Copy
__out_opt IMediaSample * Copy(IMediaSample *pSource)
Definition: transip.cpp:482
CTransInPlaceInputPin::m_bReadOnly
BOOL m_bReadOnly
Definition: transip.h:47
CTransInPlaceFilter::Transform
virtual HRESULT Transform(IMediaSample *pSample) PURE
CTransInPlaceOutputPin::EnumMediaTypes
STDMETHODIMP EnumMediaTypes(__deref_out IEnumMediaTypes **ppEnum)
Definition: transip.cpp:904
CBasePin::CompleteConnect
virtual HRESULT CompleteConnect(IPin *pReceivePin)
Definition: amfilter.cpp:1979
CTransformInputPin::CurrentMediaType
CMediaType & CurrentMediaType()
Definition: transfrm.h:100
CTransInPlaceOutputPin::PeekAllocator
__out IMemAllocator * PeekAllocator() const
Definition: transip.h:130
CBasePin::m_pFilter
CBaseFilter * m_pFilter
Definition: amfilter.h:343
CBaseInputPin::GetAllocator
STDMETHODIMP GetAllocator(__deref_out IMemAllocator **ppAllocator)
Definition: amfilter.cpp:2870
CTransformFilter::CheckInputType
virtual HRESULT CheckInputType(const CMediaType *mtIn) PURE
CTransformFilter::m_bSampleSkipped
BOOL m_bSampleSkipped
Definition: transfrm.h:276
CTransInPlaceFilter::CompleteConnect
HRESULT CompleteConnect(PIN_DIRECTION dir, IPin *pReceivePin)
Definition: transip.cpp:362
CTransformOutputPin::m_pTransformFilter
CTransformFilter * m_pTransformFilter
Definition: transfrm.h:113
CTransInPlaceFilter::CTransInPlaceOutputPin
friend class CTransInPlaceOutputPin
Definition: transip.h:224
CTransInPlaceInputPin::m_pTIPFilter
CTransInPlaceFilter *const m_pTIPFilter
Definition: transip.h:46
CBasePin::m_mt
CMediaType m_mt
Definition: amfilter.h:346
CTransInPlaceOutputPin::CTransInPlaceOutputPin
CTransInPlaceOutputPin(__in_opt LPCTSTR pObjectName, __inout CTransInPlaceFilter *pFilter, __inout HRESULT *phr, __in_opt LPCWSTR pName)
Definition: transip.cpp:885
CTransInPlaceOutputPin::CompleteConnect
HRESULT CompleteConnect(IPin *pReceivePin)
Definition: transip.cpp:966
CTransInPlaceFilter::Receive
virtual HRESULT Receive(IMediaSample *pSample)
Definition: transip.cpp:582
CTransformInputPin::m_pTransformFilter
CTransformFilter * m_pTransformFilter
Definition: transfrm.h:38
CheckPointer
#define CheckPointer(p, ret)
Definition: wxdebug.h:225
CTransformInputPin
Definition: transfrm.h:33
ASSERT
#define ASSERT(_x_)
Definition: wxdebug.h:205
hr
__out HRESULT & hr
Definition: pstream.cpp:145
CBaseInputPin::m_pAllocator
IMemAllocator * m_pAllocator
Definition: amfilter.h:825
CTransformFilter
Definition: transfrm.h:174
measure.h
CBaseFilter::m_pGraph
IFilterGraph * m_pGraph
Definition: amfilter.h:164
CTransInPlaceInputPin::CTransInPlaceInputPin
CTransInPlaceInputPin(__in_opt LPCTSTR pObjectName, __inout CTransInPlaceFilter *pFilter, __inout HRESULT *phr, __in_opt LPCWSTR pName)
Definition: transip.cpp:662