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

P2P编程

开发平台:

Visual C++

  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) Microsoft Corporation.  All rights reserved.
  8. //------------------------------------------------------------------------------
  9. // How allocators are decided.
  10. //
  11. // An in-place transform tries to do its work in someone else's buffers.
  12. // It tries to persuade the filters on either side to use the same allocator
  13. // (and for that matter the same media type).  In desperation, if the downstream
  14. // filter refuses to supply an allocator and the upstream filter offers only
  15. // a read-only one then it will provide an allocator.
  16. // if the upstream filter insists on a read-only allocator then the transform
  17. // filter will (reluctantly) copy the data before transforming it.
  18. //
  19. // In order to pass an allocator through it needs to remember the one it got
  20. // from the first connection to pass it on to the second one.
  21. //
  22. // It is good if we can avoid insisting on a particular order of connection
  23. // (There is a precedent for insisting on the input
  24. // being connected first.  Insisting on the output being connected first is
  25. // not allowed.  That would break RenderFile.)
  26. //
  27. // The base pin classes (CBaseOutputPin and CBaseInputPin) both have a
  28. // m_pAllocator member which is used in places like
  29. // CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive.
  30. // To avoid lots of extra overriding, we should keep these happy
  31. // by using these pointers.
  32. //
  33. // When each pin is connected, it will set the corresponding m_pAllocator
  34. // and will have a single ref-count on that allocator.
  35. //
  36. // Refcounts are acquired by GetAllocator calls which return AddReffed
  37. // allocators and are released in one of:
  38. //     CBaseInputPin::Disconnect
  39. //     CBaseOutputPin::BreakConect
  40. // In each case m_pAllocator is set to NULL after the release, so this
  41. // is the last chance to ever release it.  If there should ever be
  42. // multiple refcounts associated with the same pointer, this had better
  43. // be cleared up before that happens.  To avoid such problems, we'll
  44. // stick with one per pointer.
  45. // RECONNECTING and STATE CHANGES
  46. //
  47. // Each pin could be disconnected, connected with a read-only allocator,
  48. // connected with an upstream read/write allocator, connected with an
  49. // allocator from downstream or connected with its own allocator.
  50. // Five states for each pin gives a data space of 25 states.
  51. //
  52. // Notation:
  53. //
  54. // R/W == read/write
  55. // R-O == read-only
  56. //
  57. // <input pin state> <output pin state> <comments>
  58. //
  59. // 00 means an unconnected pin.
  60. // <- means using a R/W allocator from the upstream filter
  61. // <= means using a R-O allocator from an upstream filter
  62. // || means using our own (R/W) allocator.
  63. // -> means using a R/W allocator from a downstream filter
  64. //    (a R-O allocator from downstream is nonsense, it can't ever work).
  65. //
  66. //
  67. // That makes 25 possible states.  Some states are nonsense (two different
  68. // allocators from the same place).  These are just an artifact of the notation.
  69. //        <=  <-  Nonsense.
  70. //        <-  <=  Nonsense
  71. // Some states are illegal (the output pin never accepts a R-O allocator):
  72. //        00  <=  !! Error !!
  73. //        <=  <=  !! Error !!
  74. //        ||  <=  !! Error !!
  75. //        ->  <=  !! Error !!
  76. // Three states appears to be inaccessible:
  77. //        ->  ||  Inaccessible
  78. //        ||  ->  Inaccessible
  79. //        ||  <-  Inaccessible
  80. // Some states only ever occur as intermediates with a pending reconnect which
  81. // is guaranteed to finish in another state.
  82. //        ->  00  ?? unstable goes to || 00
  83. //        00  <-  ?? unstable goes to 00 ||
  84. //        ->  <-  ?? unstable goes to -> ->
  85. //        <-  ||  ?? unstable goes to <- <-
  86. //        <-  ->  ?? unstable goes to <- <-
  87. // And that leaves 11 possible resting states:
  88. // 1      00  00  Nothing connected.
  89. // 2      <-  00  Input pin connected.
  90. // 3      <=  00  Input pin connected using R-O allocator.
  91. // 4      ||  00  Needs several state changes to get here.
  92. // 5      00  ||  Output pin connected using our allocator
  93. // 6      00  ->  Downstream only connected
  94. // 7      ||  ||  Undesirable but can be forced upon us.
  95. // 8      <=  ||  Copy forced.  <=  -> is preferable
  96. // 9      <=  ->  OK - forced to copy.
  97. // 10     <-  <-  Transform in place (ideal)
  98. // 11     ->  ->  Transform in place (ideal)
  99. //
  100. // The object of the exercise is to ensure that we finish up in states
  101. // 10 or 11 whenever possible.  State 10 is only possible if the upstream
  102. // filter has a R/W allocator (the AVI splitter notoriously
  103. // doesn't) and state 11 is only possible if the downstream filter does
  104. // offer an allocator.
  105. //
  106. // The transition table (entries marked * go via a reconnect)
  107. //
  108. // There are 8 possible transitions:
  109. // A: Connect upstream to filter with R-O allocator that insists on using it.
  110. // B: Connect upstream to filter with R-O allocator but chooses not to use it.
  111. // C: Connect upstream to filter with R/W allocator and insists on using it.
  112. // D: Connect upstream to filter with R/W allocator but chooses not to use it.
  113. // E: Connect downstream to a filter that offers an allocator
  114. // F: Connect downstream to a filter that does not offer an allocator
  115. // G: disconnect upstream
  116. // H: Disconnect downstream
  117. //
  118. //            A      B      C      D      E      F      G      H
  119. //           ---------------------------------------------------------
  120. // 00  00 1 | 3      3      2      2      6      5      .      .      |1  00  00
  121. // <-  00 2 | .      .      .      .      *10/11 10     1      .      |2  <-  00
  122. // <=  00 3 | .      .      .      .      *9/11  *7/8   1      .      |3  <=  00
  123. // ||  00 4 | .      .      .      .      *8     *7     1      .      |4  ||  00
  124. // 00  || 5 | 8      7      *10    7      .      .      .      1      |5  00  ||
  125. // 00  -> 6 | 9      11     *10    11     .      .      .      1      |6  00  ->
  126. // ||  || 7 | .      .      .      .      .      .      5      4      |7  ||  ||
  127. // <=  || 8 | .      .      .      .      .      .      5      3      |8  <=  ||
  128. // <=  -> 9 | .      .      .      .      .      .      6      3      |9  <=  ->
  129. // <-  <- 10| .      .      .      .      .      .      *5/6   2      |10 <-  <-
  130. // ->  -> 11| .      .      .      .      .      .      6      *2/3   |11 ->  ->
  131. //           ---------------------------------------------------------
  132. //            A      B      C      D      E      F      G      H
  133. //
  134. // All these states are accessible without requiring any filter to
  135. // change its behaviour but not all transitions are accessible, for
  136. // instance a transition from state 4 to anywhere other than
  137. // state 8 requires that the upstream filter first offer a R-O allocator
  138. // and then changes its mind and offer R/W.  This is NOT allowable - it
  139. // leads to things like the output pin getting a R/W allocator from
  140. // upstream and then the input pin being told it can only have a R-O one.
  141. // Note that you CAN change (say) the upstream filter for a different one, but
  142. // only as a disconnect / connect, not as a Reconnect.  (Exercise for
  143. // the reader is to see how you get into state 4).
  144. //
  145. // The reconnection stuff goes as follows (some of the cases shown here as
  146. // "no reconnect" may get one to finalise media type - an old story).
  147. // If there is a reconnect where it says "no reconnect" here then the
  148. // reconnection must not change the allocator choice.
  149. //
  150. // state 2: <- 00 transition E <- <- case C <- <- (no change)
  151. //                                   case D -> <- and then to -> ->
  152. //
  153. // state 2: <- 00 transition F <- <- (no reconnect)
  154. //
  155. // state 3: <= 00 transition E <= -> case A <= -> (no change)
  156. //                                   case B -> ->
  157. //                transition F <= || case A <= || (no change)
  158. //                                   case B || ||
  159. //
  160. // state 4: || 00 transition E || || case B -> || and then all cases to -> ->
  161. //                           F || || case B || || (no change)
  162. //
  163. // state 5: 00 || transition A <= || (no reconnect)
  164. //                           B || || (no reconnect)
  165. //                           C <- || all cases     <- <-
  166. //                           D || || (unfortunate, but upstream's choice)
  167. //
  168. // state 6: 00 -> transition A <= -> (no reconnect)
  169. //                           B -> -> (no reconnect)
  170. //                           C <- -> all cases <- <-
  171. //                           D -> -> (no reconnect)
  172. //
  173. // state 10:<- <- transition G 00 <- case E 00 ->
  174. //                                   case F 00 ||
  175. //
  176. // state 11:-> -> transition H -> 00 case A <= 00 (schizo)
  177. //                                   case B <= 00
  178. //                                   case C <- 00 (schizo)
  179. //                                   case D <- 00
  180. //
  181. // The Rules:
  182. // To sort out media types:
  183. // The input is reconnected
  184. //    if the input pin is connected and the output pin connects
  185. // The output is reconnected
  186. //    If the output pin is connected
  187. //    and the input pin connects to a different media type
  188. //
  189. // To sort out allocators:
  190. // The input is reconnected
  191. //    if the output disconnects and the input was using a downstream allocator
  192. // The output pin calls SetAllocator to pass on a new allocator
  193. //    if the output is connected and
  194. //       if the input disconnects and the output was using an upstream allocator
  195. //       if the input acquires an allocator different from the output one
  196. //          and that new allocator is not R-O
  197. //
  198. // Data is copied (i.e. call getbuffer and copy the data before transforming it)
  199. //    if the two allocators are different.
  200. // CHAINS of filters:
  201. //
  202. // We sit between two filters (call them A and Z).  We should finish up
  203. // with the same allocator on both of our pins and that should be the
  204. // same one that A and Z would have agreed on if we hadn't been in the
  205. // way.  Furthermore, it should not matter how many in-place transforms
  206. // are in the way.  Let B, C, D... be in-place transforms ("us").
  207. // Here's how it goes:
  208. //
  209. // 1.
  210. // A connects to B.  They agree on A's allocator.
  211. //   A-a->B
  212. //
  213. // 2.
  214. // B connects to C.  Same story. There is no point in a reconnect, but
  215. // B will request an input reconnect anyway.
  216. //   A-a->B-a->C
  217. //
  218. // 3.
  219. // C connects to Z.
  220. // C insists on using A's allocator, but compromises by requesting a reconnect.
  221. // of C's input.
  222. //   A-a->B-?->C-a->Z
  223. //
  224. // We now have pending reconnects on both A--->B and B--->C
  225. //
  226. // 4.
  227. // The A--->B link is reconnected.
  228. // A asks B for an allocator.  B sees that it has a downstream connection so
  229. // asks its downstream input pin i.e. C's input pin for an allocator.  C sees
  230. // that it too has a downstream connection so asks Z for an allocator.
  231. //
  232. // Even though Z's input pin is connected, it is being asked for an allocator.
  233. // It could refuse, in which case the chain is done and will use A's allocator
  234. // Alternatively, Z may supply one.  A chooses either Z's or A's own one.
  235. // B's input pin gets NotifyAllocator called to tell it the decision and it
  236. // propagates this downstream by calling ReceiveAllocator on its output pin
  237. // which calls NotifyAllocator on the next input pin downstream etc.
  238. // If the choice is Z then it goes:
  239. //   A-z->B-a->C-a->Z
  240. //   A-z->B-z->C-a->Z
  241. //   A-z->B-z->C-z->Z
  242. //
  243. // And that's IT!!  Any further (essentially spurious) reconnects peter out
  244. // with no change in the chain.
  245. #include <streams.h>
  246. #include <measure.h>
  247. #include <transip.h>
  248. // =================================================================
  249. // Implements the CTransInPlaceFilter class
  250. // =================================================================
  251. CTransInPlaceFilter::CTransInPlaceFilter
  252.    ( TCHAR     *pName,
  253.      LPUNKNOWN  pUnk,
  254.      REFCLSID   clsid,
  255.      HRESULT   *phr,
  256.      bool       bModifiesData
  257.    )
  258.    : CTransformFilter(pName, pUnk, clsid),
  259.      m_bModifiesData(bModifiesData)
  260. {
  261. #ifdef PERF
  262.     RegisterPerfId();
  263. #endif //  PERF
  264. } // constructor
  265. #ifdef UNICODE
  266. CTransInPlaceFilter::CTransInPlaceFilter
  267.    ( CHAR     *pName,
  268.      LPUNKNOWN  pUnk,
  269.      REFCLSID   clsid,
  270.      HRESULT   *phr,
  271.      bool       bModifiesData
  272.    )
  273.    : CTransformFilter(pName, pUnk, clsid),
  274.      m_bModifiesData(bModifiesData)
  275. {
  276. #ifdef PERF
  277.     RegisterPerfId();
  278. #endif //  PERF
  279. } // constructor
  280. #endif
  281. // return a non-addrefed CBasePin * for the user to addref if he holds onto it
  282. // for longer than his pointer to us. We create the pins dynamically when they
  283. // are asked for rather than in the constructor. This is because we want to
  284. // give the derived class an oppportunity to return different pin objects
  285. // As soon as any pin is needed we create both (this is different from the
  286. // usual transform filter) because enumerators, allocators etc are passed
  287. // through from one pin to another and it becomes very painful if the other
  288. // pin isn't there.  If we fail to create either pin we ensure we fail both.
  289. CBasePin *
  290. CTransInPlaceFilter::GetPin(int n)
  291. {
  292.     HRESULT hr = S_OK;
  293.     // Create an input pin if not already done
  294.     if (m_pInput == NULL) {
  295.         m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin")
  296.                                             , this        // Owner filter
  297.                                             , &hr         // Result code
  298.                                             , L"Input"    // Pin name
  299.                                             );
  300.         // Constructor for CTransInPlaceInputPin can't fail
  301.         ASSERT(SUCCEEDED(hr));
  302.     }
  303.     // Create an output pin if not already done
  304.     if (m_pInput!=NULL && m_pOutput == NULL) {
  305.         m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin")
  306.                                               , this       // Owner filter
  307.                                               , &hr        // Result code
  308.                                               , L"Output"  // Pin name
  309.                                               );
  310.         // a failed return code should delete the object
  311.         ASSERT(SUCCEEDED(hr));
  312.         if (m_pOutput == NULL) {
  313.             delete m_pInput;
  314.             m_pInput = NULL;
  315.         }
  316.     }
  317.     // Return the appropriate pin
  318.     ASSERT (n>=0 && n<=1);
  319.     if (n == 0) {
  320.         return m_pInput;
  321.     } else if (n==1) {
  322.         return m_pOutput;
  323.     } else {
  324.         return NULL;
  325.     }
  326. } // GetPin
  327. // dir is the direction of our pin.
  328. // pReceivePin is the pin we are connecting to.
  329. HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin)
  330. {
  331.     UNREFERENCED_PARAMETER(pReceivePin);
  332.     ASSERT(m_pInput);
  333.     ASSERT(m_pOutput);
  334.     // if we are not part of a graph, then don't indirect the pointer
  335.     // this probably prevents use of the filter without a filtergraph
  336.     if (!m_pGraph) {
  337.         return VFW_E_NOT_IN_GRAPH;
  338.     }
  339.     // Always reconnect the input to account for buffering changes
  340.     //
  341.     // Because we don't get to suggest a type on ReceiveConnection
  342.     // we need another way of making sure the right type gets used.
  343.     //
  344.     // One way would be to have our EnumMediaTypes return our output
  345.     // connection type first but more deterministic and simple is to
  346.     // call ReconnectEx passing the type we want to reconnect with
  347.     // via the base class ReconeectPin method.
  348.     if (dir == PINDIR_OUTPUT) {
  349.         if( m_pInput->IsConnected() ) {
  350.             return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() );
  351.         }
  352.         return NOERROR;
  353.     }
  354.     ASSERT(dir == PINDIR_INPUT);
  355.     // Reconnect output if necessary
  356.     if( m_pOutput->IsConnected() ) {
  357.         if (  m_pInput->CurrentMediaType()
  358.            != m_pOutput->CurrentMediaType()
  359.            ) {
  360.             return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() );
  361.         }
  362.     }
  363.     return NOERROR;
  364. } // ComnpleteConnect
  365. //
  366. // DecideBufferSize
  367. //
  368. // Tell the output pin's allocator what size buffers we require.
  369. // *pAlloc will be the allocator our output pin is using.
  370. //
  371. HRESULT CTransInPlaceFilter::DecideBufferSize
  372.             ( IMemAllocator *pAlloc
  373.             , ALLOCATOR_PROPERTIES *pProperties
  374.             )
  375. {
  376.     ALLOCATOR_PROPERTIES Request, Actual;
  377.     HRESULT hr;
  378.     // If we are connected upstream, get his views
  379.     if (m_pInput->IsConnected()) {
  380.         // Get the input pin allocator, and get its size and count.
  381.         // we don't care about his alignment and prefix.
  382.         hr = InputPin()->PeekAllocator()->GetProperties(&Request);
  383.         if (FAILED(hr)) {
  384.             // Input connected but with a secretive allocator - enough!
  385.             return hr;
  386.         }
  387.     } else {
  388.         // We're reduced to blind guessing.  Let's guess one byte and if
  389.         // this isn't enough then when the other pin does get connected
  390.         // we can revise it.
  391.         ZeroMemory(&Request, sizeof(Request));
  392.         Request.cBuffers = 1;
  393.         Request.cbBuffer = 1;
  394.     }
  395.     DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements")));
  396.     DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"),
  397.            Request.cBuffers, Request.cbBuffer));
  398.     // Pass the allocator requirements to our output side
  399.     // but do a little sanity checking first or we'll just hit
  400.     // asserts in the allocator.
  401.     pProperties->cBuffers = Request.cBuffers;
  402.     pProperties->cbBuffer = Request.cbBuffer;
  403.     pProperties->cbAlign = Request.cbAlign;
  404.     if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; }
  405.     if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; }
  406.     hr = pAlloc->SetProperties(pProperties, &Actual);
  407.     if (FAILED(hr)) {
  408.         return hr;
  409.     }
  410.     DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements")));
  411.     DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"),
  412.            Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign));
  413.     // Make sure we got the right alignment and at least the minimum required
  414.     if (  (Request.cBuffers > Actual.cBuffers)
  415.        || (Request.cbBuffer > Actual.cbBuffer)
  416.        || (Request.cbAlign  > Actual.cbAlign)
  417.        ) {
  418.         return E_FAIL;
  419.     }
  420.     return NOERROR;
  421. } // DecideBufferSize
  422. //
  423. // Copy
  424. //
  425. // return a pointer to an identical copy of pSample
  426. IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource)
  427. {
  428.     IMediaSample * pDest;
  429.     HRESULT hr;
  430.     REFERENCE_TIME tStart, tStop;
  431.     const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop);
  432.     // this may block for an indeterminate amount of time
  433.     hr = OutputPin()->PeekAllocator()->GetBuffer(
  434.               &pDest
  435.               , bTime ? &tStart : NULL
  436.               , bTime ? &tStop : NULL
  437.               , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0
  438.               );
  439.     if (FAILED(hr)) {
  440.         return NULL;
  441.     }
  442.     ASSERT(pDest);
  443.     IMediaSample2 *pSample2;
  444.     if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
  445.         HRESULT hr = pSample2->SetProperties(
  446.             FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer),
  447.             (PBYTE)m_pInput->SampleProps());
  448.         pSample2->Release();
  449.         if (FAILED(hr)) {
  450.             pDest->Release();
  451.             return NULL;
  452.         }
  453.     } else {
  454.         if (bTime) {
  455.             pDest->SetTime(&tStart, &tStop);
  456.         }
  457.         if (S_OK == pSource->IsSyncPoint()) {
  458.             pDest->SetSyncPoint(TRUE);
  459.         }
  460.         if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) {
  461.             pDest->SetDiscontinuity(TRUE);
  462.         }
  463.         if (S_OK == pSource->IsPreroll()) {
  464.             pDest->SetPreroll(TRUE);
  465.         }
  466.         // Copy the media type
  467.         AM_MEDIA_TYPE *pMediaType;
  468.         if (S_OK == pSource->GetMediaType(&pMediaType)) {
  469.             pDest->SetMediaType(pMediaType);
  470.             DeleteMediaType( pMediaType );
  471.         }
  472.     }
  473.     m_bSampleSkipped = FALSE;
  474.     // Copy the sample media times
  475.     REFERENCE_TIME TimeStart, TimeEnd;
  476.     if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) {
  477.         pDest->SetMediaTime(&TimeStart,&TimeEnd);
  478.     }
  479.     // Copy the actual data length and the actual data.
  480.     {
  481.         const long lDataLength = pSource->GetActualDataLength();
  482.         pDest->SetActualDataLength(lDataLength);
  483.         // Copy the sample data
  484.         {
  485.             BYTE *pSourceBuffer, *pDestBuffer;
  486.             long lSourceSize  = pSource->GetSize();
  487.             long lDestSize = pDest->GetSize();
  488.             ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength);
  489.             pSource->GetPointer(&pSourceBuffer);
  490.             pDest->GetPointer(&pDestBuffer);
  491.             ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL);
  492.             CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength );
  493.         }
  494.     }
  495.     return pDest;
  496. } // Copy
  497. // override this to customize the transform process
  498. HRESULT
  499. CTransInPlaceFilter::Receive(IMediaSample *pSample)
  500. {
  501.     /*  Check for other streams and pass them on */
  502.     AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
  503.     if (pProps->dwStreamId != AM_STREAM_MEDIA) {
  504.         return m_pOutput->Deliver(pSample);
  505.     }
  506.     HRESULT hr;
  507.     // Start timing the TransInPlace (if PERF is defined)
  508.     MSR_START(m_idTransInPlace);
  509.     if (UsingDifferentAllocators()) {
  510.         // We have to copy the data.
  511.         pSample = Copy(pSample);
  512.         if (pSample==NULL) {
  513.             MSR_STOP(m_idTransInPlace);
  514.             return E_UNEXPECTED;
  515.         }
  516.     }
  517.     // have the derived class transform the data
  518.     hr = Transform(pSample);
  519.     // Stop the clock and log it (if PERF is defined)
  520.     MSR_STOP(m_idTransInPlace);
  521.     if (FAILED(hr)) {
  522.         DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));
  523.         if (UsingDifferentAllocators()) {
  524.             pSample->Release();
  525.         }
  526.         return hr;
  527.     }
  528.     // the Transform() function can return S_FALSE to indicate that the
  529.     // sample should not be delivered; we only deliver the sample if it's
  530.     // really S_OK (same as NOERROR, of course.)
  531.     if (hr == NOERROR) {
  532.         hr = m_pOutput->Deliver(pSample);
  533.     } else {
  534.         //  But it would be an error to return this private workaround
  535.         //  to the caller ...
  536.         if (S_FALSE == hr) {
  537.             // S_FALSE returned from Transform is a PRIVATE agreement
  538.             // We should return NOERROR from Receive() in this cause because
  539.             // returning S_FALSE from Receive() means that this is the end
  540.             // of the stream and no more data should be sent.
  541.             m_bSampleSkipped = TRUE;
  542.             if (!m_bQualityChanged) {
  543.                 NotifyEvent(EC_QUALITY_CHANGE,0,0);
  544.                 m_bQualityChanged = TRUE;
  545.             }
  546.             hr = NOERROR;
  547.         }
  548.     }
  549.     // release the output buffer. If the connected pin still needs it,
  550.     // it will have addrefed it itself.
  551.     if (UsingDifferentAllocators()) {
  552.         pSample->Release();
  553.     }
  554.     return hr;
  555. } // Receive
  556. // =================================================================
  557. // Implements the CTransInPlaceInputPin class
  558. // =================================================================
  559. // constructor
  560. CTransInPlaceInputPin::CTransInPlaceInputPin
  561.     ( TCHAR               *pObjectName
  562.     , CTransInPlaceFilter *pFilter
  563.     , HRESULT             *phr
  564.     , LPCWSTR              pName
  565.     )
  566.     : CTransformInputPin(pObjectName,
  567.                          pFilter,
  568.                          phr,
  569.                          pName)
  570.     , m_bReadOnly(FALSE)
  571.     , m_pTIPFilter(pFilter)
  572. {
  573.     DbgLog((LOG_TRACE, 2
  574.            , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin")));
  575. } // constructor
  576. // =================================================================
  577. // Implements IMemInputPin interface
  578. // =================================================================
  579. // If the downstream filter has one then offer that (even if our own output
  580. // pin is not using it yet.  If the upstream filter chooses it then we will
  581. // tell our output pin to ReceiveAllocator).
  582. // Else if our output pin is using an allocator then offer that.
  583. //     ( This could mean offering the upstream filter his own allocator,
  584. //       it could mean offerring our own
  585. //     ) or it could mean offering the one from downstream
  586. // Else fail to offer any allocator at all.
  587. STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator)
  588. {
  589.     CheckPointer(ppAllocator,E_POINTER);
  590.     ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
  591.     CAutoLock cObjectLock(m_pLock);
  592.     HRESULT hr;
  593.     if ( m_pTIPFilter->m_pOutput->IsConnected() ) {
  594.         //  Store the allocator we got
  595.         hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  596.                                         ->GetAllocator( ppAllocator );
  597.         if (SUCCEEDED(hr)) {
  598.             m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator );
  599.         }
  600.     }
  601.     else {
  602.         //  Help upstream filter (eg TIP filter which is having to do a copy)
  603.         //  by providing a temp allocator here - we'll never use
  604.         //  this allocator because when our output is connected we'll
  605.         //  reconnect this pin
  606.         hr = CTransformInputPin::GetAllocator( ppAllocator );
  607.     }
  608.     return hr;
  609. } // GetAllocator
  610. /* Get told which allocator the upstream output pin is actually going to use */
  611. STDMETHODIMP
  612. CTransInPlaceInputPin::NotifyAllocator(
  613.     IMemAllocator * pAllocator,
  614.     BOOL bReadOnly)
  615. {
  616.     HRESULT hr = S_OK;
  617.     CheckPointer(pAllocator,E_POINTER);
  618.     ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
  619.     CAutoLock cObjectLock(m_pLock);
  620.     m_bReadOnly = bReadOnly;
  621.     //  If we modify data then don't accept the allocator if it's
  622.     //  the same as the output pin's allocator
  623.     //  If our output is not connected just accept the allocator
  624.     //  We're never going to use this allocator because when our
  625.     //  output pin is connected we'll reconnect this pin
  626.     if (!m_pTIPFilter->OutputPin()->IsConnected()) {
  627.         return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly);
  628.     }
  629.     //  If the allocator is read-only and we're modifying data
  630.     //  and the allocator is the same as the output pin's
  631.     //  then reject
  632.     if (bReadOnly && m_pTIPFilter->m_bModifiesData) {
  633.         IMemAllocator *pOutputAllocator =
  634.             m_pTIPFilter->OutputPin()->PeekAllocator();
  635.         //  Make sure we have an output allocator
  636.         if (pOutputAllocator == NULL) {
  637.             hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()->
  638.                                       GetAllocator(&pOutputAllocator);
  639.             if(FAILED(hr)) {
  640.                 hr = CreateMemoryAllocator(&pOutputAllocator);
  641.             }
  642.             if (SUCCEEDED(hr)) {
  643.                 m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator);
  644.                 pOutputAllocator->Release();
  645.             }
  646.         }
  647.         if (pAllocator == pOutputAllocator) {
  648.             hr = E_FAIL;
  649.         } else if(SUCCEEDED(hr)) {
  650.             //  Must copy so set the allocator properties on the output
  651.             ALLOCATOR_PROPERTIES Props, Actual;
  652.             hr = pAllocator->GetProperties(&Props);
  653.             if (SUCCEEDED(hr)) {
  654.                 hr = pOutputAllocator->SetProperties(&Props, &Actual);
  655.             }
  656.             if (SUCCEEDED(hr)) {
  657.                 if (  (Props.cBuffers > Actual.cBuffers)
  658.                    || (Props.cbBuffer > Actual.cbBuffer)
  659.                    || (Props.cbAlign  > Actual.cbAlign)
  660.                    ) {
  661.                     hr =  E_FAIL;
  662.                 }
  663.             }
  664.             //  Set the allocator on the output pin
  665.             if (SUCCEEDED(hr)) {
  666.                 hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  667.                                        ->NotifyAllocator( pOutputAllocator, FALSE );
  668.             }
  669.         }
  670.     } else {
  671.         hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  672.                                    ->NotifyAllocator( pAllocator, bReadOnly );
  673.         if (SUCCEEDED(hr)) {
  674.             m_pTIPFilter->OutputPin()->SetAllocator( pAllocator );
  675.         }
  676.     }
  677.     if (SUCCEEDED(hr)) {
  678.         // It's possible that the old and the new are the same thing.
  679.         // AddRef before release ensures that we don't unload it.
  680.         pAllocator->AddRef();
  681.         if( m_pAllocator != NULL )
  682.             m_pAllocator->Release();
  683.         m_pAllocator = pAllocator;    // We have an allocator for the input pin
  684.     }
  685.     return hr;
  686. } // NotifyAllocator
  687. // EnumMediaTypes
  688. // - pass through to our downstream filter
  689. STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
  690. {
  691.     // Can only pass through if connected
  692.     if( !m_pTIPFilter->m_pOutput->IsConnected() )
  693.         return VFW_E_NOT_CONNECTED;
  694.     return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum );
  695. } // EnumMediaTypes
  696. // CheckMediaType
  697. // - agree to anything if not connected,
  698. // otherwise pass through to the downstream filter.
  699. // This assumes that the filter does not change the media type.
  700. HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt )
  701. {
  702.     HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
  703.     if (hr!=S_OK) return hr;
  704.     if( m_pTIPFilter->m_pOutput->IsConnected() )
  705.         return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt );
  706.     else
  707.         return S_OK;
  708. } // CheckMediaType
  709. // If upstream asks us what our requirements are, we will try to ask downstream
  710. // if that doesn't work, we'll just take the defaults.
  711. STDMETHODIMP
  712. CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps)
  713. {
  714.     if( m_pTIPFilter->m_pOutput->IsConnected() )
  715.         return m_pTIPFilter->OutputPin()
  716.                ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps );
  717.     else
  718.         return E_NOTIMPL;
  719. } // GetAllocatorRequirements
  720. // CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect()
  721. // and then calls CTransInPlaceFilter::CompleteConnect().  It does this because 
  722. // CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not
  723. // want to reconnect a pin if CBaseInputPin::CompleteConnect() fails.
  724. HRESULT
  725. CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin)
  726. {
  727.     HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin);
  728.     if (FAILED(hr)) {
  729.         return hr;
  730.     }
  731.     return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
  732. } // CompleteConnect
  733. // =================================================================
  734. // Implements the CTransInPlaceOutputPin class
  735. // =================================================================
  736. // constructor
  737. CTransInPlaceOutputPin::CTransInPlaceOutputPin(
  738.     TCHAR *pObjectName,
  739.     CTransInPlaceFilter *pFilter,
  740.     HRESULT * phr,
  741.     LPCWSTR pPinName)
  742.     : CTransformOutputPin( pObjectName
  743.                          , pFilter
  744.                          , phr
  745.                          , pPinName),
  746.       m_pTIPFilter(pFilter)
  747. {
  748.     DbgLog(( LOG_TRACE, 2
  749.            , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin")));
  750. } // constructor
  751. // EnumMediaTypes
  752. // - pass through to our upstream filter
  753. STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
  754. {
  755.     // Can only pass through if connected.
  756.     if( ! m_pTIPFilter->m_pInput->IsConnected() )
  757.         return VFW_E_NOT_CONNECTED;
  758.     return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum );
  759. } // EnumMediaTypes
  760. // CheckMediaType
  761. // - agree to anything if not connected,
  762. // otherwise pass through to the upstream filter.
  763. HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt )
  764. {
  765.     // Don't accept any output pin type changes if we're copying
  766.     // between allocators - it's too late to change the input
  767.     // allocator size.
  768.     if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) {
  769.         if (*pmt == m_mt) {
  770.             return S_OK;
  771.         } else {
  772.             return VFW_E_TYPE_NOT_ACCEPTED;
  773.         }
  774.     }
  775.     // Assumes the type does not change.  That's why we're calling
  776.     // CheckINPUTType here on the OUTPUT pin.
  777.     HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
  778.     if (hr!=S_OK) return hr;
  779.     if( m_pTIPFilter->m_pInput->IsConnected() )
  780.         return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt );
  781.     else
  782.         return S_OK;
  783. } // CheckMediaType
  784. /* Save the allocator pointer in the output pin
  785. */
  786. void
  787. CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator)
  788. {
  789.     pAllocator->AddRef();
  790.     if (m_pAllocator) {
  791.         m_pAllocator->Release();
  792.     }
  793.     m_pAllocator = pAllocator;
  794. } // SetAllocator
  795. // CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect()
  796. // and then calls CTransInPlaceFilter::CompleteConnect().  It does this because 
  797. // CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to 
  798. // reconnect a pin if CBaseOutputPin::CompleteConnect() fails.  
  799. // CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected 
  800. // to the Video Mixing Renderer.
  801. HRESULT
  802. CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin)
  803. {
  804.     HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
  805.     if (FAILED(hr)) {
  806.         return hr;
  807.     }
  808.     return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
  809. } // CompleteConnect