home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / directshow / baseclasses / transip.cpp < prev    next >
Encoding:
Text File  |  2000-10-02  |  32.5 KB  |  945 lines

  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 - 2000, 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.  
  263. CTransInPlaceFilter::CTransInPlaceFilter
  264.    ( TCHAR     *pName,
  265.      LPUNKNOWN  pUnk,
  266.      REFCLSID   clsid,
  267.      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
  280. CTransInPlaceFilter::CTransInPlaceFilter
  281.    ( CHAR     *pName,
  282.      LPUNKNOWN  pUnk,
  283.      REFCLSID   clsid,
  284.      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 *
  308. CTransInPlaceFilter::GetPin(int n)
  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() ) {
  386.             return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() );
  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()
  398.            != m_pOutput->CurrentMediaType()
  399.            ) {
  400.             return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() );
  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. // Note this function is for compatibility with older versions and
  414. // is not used in the new design where the output pin upstream
  415. // negotiates directy with the input pin downstream
  416.  
  417. HRESULT CTransInPlaceFilter::DecideBufferSize
  418.             ( IMemAllocator *pAlloc
  419.             , ALLOCATOR_PROPERTIES *pProperties
  420.             )
  421. {
  422.     ALLOCATOR_PROPERTIES Request, Actual;
  423.     HRESULT hr;
  424.  
  425.     // If we are connected upstream, get his views
  426.     if (m_pInput->IsConnected()) {
  427.         // Get the input pin allocator, and get its size and count.
  428.         // we don't care about his alignment and prefix.
  429.  
  430.         hr = InputPin()->PeekAllocator()->GetProperties(&Request);
  431.         if (FAILED(hr)) {
  432.             // Input connected but with a secretive allocator - enough!
  433.             return hr;
  434.         }
  435.     } else {
  436.         // We're reduced to blind guessing.  Let's guess one byte and if
  437.         // this isn't enough then when the other pin does get connected
  438.         // we can revise it.
  439.         ZeroMemory(&Request, sizeof(Request));
  440.         Request.cBuffers = 1;
  441.         Request.cbBuffer = 1;
  442.     }
  443.  
  444.  
  445.     DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements")));
  446.     DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"),
  447.            Request.cBuffers, Request.cbBuffer));
  448.  
  449.     // Pass the allocator requirements to our output side
  450.     // but do a little sanity checking first or we'll just hit
  451.     // asserts in the allocator.
  452.  
  453.     pProperties->cBuffers = Request.cBuffers;
  454.     pProperties->cbBuffer = Request.cbBuffer;
  455.     if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; }
  456.     if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; }
  457.     hr = pAlloc->SetProperties(pProperties, &Actual);
  458.  
  459.     if (FAILED(hr)) {
  460.         return hr;
  461.     }
  462.  
  463.     DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements")));
  464.     DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"),
  465.            Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign));
  466.  
  467.     // Make sure we got the right alignment and at least the minimum required
  468.  
  469.     if (  (Request.cBuffers > Actual.cBuffers)
  470.        || (Request.cbBuffer > Actual.cbBuffer)
  471.        || (Request.cbAlign  > Actual.cbAlign)
  472.        ) {
  473.         return E_FAIL;
  474.     }
  475.     return NOERROR;
  476.  
  477. } // DecideBufferSize
  478.  
  479. //
  480. // Copy
  481. //
  482. // return a pointer to an identical copy of pSample
  483. IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource)
  484. {
  485.     IMediaSample * pDest;
  486.  
  487.     HRESULT hr;
  488.     REFERENCE_TIME tStart, tStop;
  489.     const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop);
  490.  
  491.     // this may block for an indeterminate amount of time
  492.     hr = OutputPin()->PeekAllocator()->GetBuffer(
  493.               &pDest
  494.               , bTime ? &tStart : NULL
  495.               , bTime ? &tStop : NULL
  496.               , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0
  497.               );
  498.  
  499.     if (FAILED(hr)) {
  500.         return NULL;
  501.     }
  502.  
  503.     ASSERT(pDest);
  504.     IMediaSample2 *pSample2;
  505.     if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
  506.         HRESULT hr = pSample2->SetProperties(
  507.             FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer),
  508.             (PBYTE)m_pInput->SampleProps());
  509.         pSample2->Release();
  510.         if (FAILED(hr)) {
  511.             pDest->Release();
  512.             return NULL;
  513.         }
  514.     } else {
  515.         if (bTime) {
  516.             pDest->SetTime(&tStart, &tStop);
  517.         }
  518.  
  519.         if (S_OK == pSource->IsSyncPoint()) {
  520.             pDest->SetSyncPoint(TRUE);
  521.         }
  522.         if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) {
  523.             pDest->SetDiscontinuity(TRUE);
  524.         }
  525.         if (S_OK == pSource->IsPreroll()) {
  526.             pDest->SetPreroll(TRUE);
  527.         }
  528.  
  529.         // Copy the media type
  530.         AM_MEDIA_TYPE *pMediaType;
  531.         if (S_OK == pSource->GetMediaType(&pMediaType)) {
  532.             pDest->SetMediaType(pMediaType);
  533.             DeleteMediaType( pMediaType );
  534.         }
  535.  
  536.     }
  537.  
  538.     m_bSampleSkipped = FALSE;
  539.  
  540.     // Copy the sample media times
  541.     REFERENCE_TIME TimeStart, TimeEnd;
  542.     if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) {
  543.         pDest->SetMediaTime(&TimeStart,&TimeEnd);
  544.     }
  545.  
  546.     // Copy the actual data length and the actual data.
  547.     {
  548.         const long lDataLength = pSource->GetActualDataLength();
  549.         pDest->SetActualDataLength(lDataLength);
  550.  
  551.         // Copy the sample data
  552.         {
  553.             BYTE *pSourceBuffer, *pDestBuffer;
  554.             long lSourceSize  = pSource->GetSize();
  555.             long lDestSize = pDest->GetSize();
  556.  
  557.             ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength);
  558.  
  559.             pSource->GetPointer(&pSourceBuffer);
  560.             pDest->GetPointer(&pDestBuffer);
  561.             ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL);
  562.  
  563.             CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength );
  564.         }
  565.     }
  566.  
  567.     return pDest;
  568.  
  569. } // Copy
  570.  
  571.  
  572. // override this to customize the transform process
  573.  
  574. HRESULT
  575. CTransInPlaceFilter::Receive(IMediaSample *pSample)
  576. {
  577.     /*  Check for other streams and pass them on */
  578.     AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
  579.     if (pProps->dwStreamId != AM_STREAM_MEDIA) {
  580.         return m_pOutput->Deliver(pSample);
  581.     }
  582.     HRESULT hr;
  583.  
  584.     // Start timing the TransInPlace (if PERF is defined)
  585.     MSR_START(m_idTransInPlace);
  586.  
  587.     if (UsingDifferentAllocators()) {
  588.  
  589.         // We have to copy the data.
  590.  
  591.         pSample = Copy(pSample);
  592.  
  593.         if (pSample==NULL) {
  594.             MSR_STOP(m_idTransInPlace);
  595.             return E_UNEXPECTED;
  596.         }
  597.     }
  598.  
  599.     // have the derived class transform the data
  600.     hr = Transform(pSample);
  601.  
  602.     // Stop the clock and log it (if PERF is defined)
  603.     MSR_STOP(m_idTransInPlace);
  604.  
  605.     if (FAILED(hr)) {
  606.         DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));
  607.         if (UsingDifferentAllocators()) {
  608.             pSample->Release();
  609.         }
  610.         return hr;
  611.     }
  612.  
  613.     // the Transform() function can return S_FALSE to indicate that the
  614.     // sample should not be delivered; we only deliver the sample if it's
  615.     // really S_OK (same as NOERROR, of course.)
  616.     if (hr == NOERROR) {
  617.         hr = m_pOutput->Deliver(pSample);
  618.     } else {
  619.         //  But it would be an error to return this private workaround
  620.         //  to the caller ...
  621.         if (S_FALSE == hr) {
  622.             // S_FALSE returned from Transform is a PRIVATE agreement
  623.             // We should return NOERROR from Receive() in this cause because 
  624.             // returning S_FALSE from Receive() means that this is the end 
  625.             // of the stream and no more data should be sent.
  626.             m_bSampleSkipped = TRUE;
  627.             if (!m_bQualityChanged) {
  628.                 NotifyEvent(EC_QUALITY_CHANGE,0,0);
  629.                 m_bQualityChanged = TRUE;
  630.             }
  631.             hr = NOERROR;
  632.         }
  633.     }
  634.  
  635.     // release the output buffer. If the connected pin still needs it,
  636.     // it will have addrefed it itself.
  637.     if (UsingDifferentAllocators()) {
  638.         pSample->Release();
  639.     }
  640.  
  641.     return hr;
  642.  
  643. } // Receive
  644.  
  645.  
  646.  
  647. // =================================================================
  648. // Implements the CTransInPlaceInputPin class
  649. // =================================================================
  650.  
  651.  
  652. // constructor
  653.  
  654. CTransInPlaceInputPin::CTransInPlaceInputPin
  655.     ( TCHAR               *pObjectName
  656.     , CTransInPlaceFilter *pFilter
  657.     , HRESULT             *phr
  658.     , LPCWSTR              pName
  659.     )
  660.     : CTransformInputPin(pObjectName,
  661.                          pFilter,
  662.                          phr,
  663.                          pName)
  664.     , m_bReadOnly(FALSE)
  665.     , m_pTIPFilter(pFilter)
  666. {
  667.     DbgLog((LOG_TRACE, 2
  668.            , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin")));
  669.  
  670. } // constructor
  671.  
  672.  
  673. // =================================================================
  674. // Implements IMemInputPin interface
  675. // =================================================================
  676.  
  677.  
  678. // If the downstream filter has one then offer that (even if our own output
  679. // pin is not using it yet.  If the upstream filter chooses it then we will
  680. // tell our output pin to ReceiveAllocator).
  681. // Else if our output pin is using an allocator then offer that.
  682. //     ( This could mean offering the upstream filter his own allocator,
  683. //       it could mean offerring our own
  684. //     ) or it could mean offering the one from downstream
  685. // Else fail to offer any allocator at all.
  686.  
  687. STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator)
  688. {
  689.     CheckPointer(ppAllocator,E_POINTER);
  690.     ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
  691.     CAutoLock cObjectLock(m_pLock);
  692.  
  693.     HRESULT hr;
  694.  
  695.     if ( m_pTIPFilter->m_pOutput->IsConnected() ) {
  696.         //  Store the allocator we got
  697.         hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  698.                                         ->GetAllocator( ppAllocator );
  699.         if (SUCCEEDED(hr)) {
  700.             m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator );
  701.         }
  702.     }
  703.     else {
  704.         //  Help upstream filter (eg TIP filter which is having to do a copy)
  705.         //  by providing a temp allocator here - we'll never use
  706.         //  this allocator because when our output is connected we'll
  707.         //  reconnect this pin
  708.         hr = CTransformInputPin::GetAllocator( ppAllocator );
  709.     }
  710.     return hr;
  711.  
  712. } // GetAllocator
  713.  
  714.  
  715.  
  716. /* Get told which allocator the upstream output pin is actually going to use */
  717.  
  718.  
  719. STDMETHODIMP
  720. CTransInPlaceInputPin::NotifyAllocator(
  721.     IMemAllocator * pAllocator,
  722.     BOOL bReadOnly)
  723. {
  724.     HRESULT hr;
  725.     CheckPointer(pAllocator,E_POINTER);
  726.     ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
  727.  
  728.     CAutoLock cObjectLock(m_pLock);
  729.  
  730.     m_bReadOnly = bReadOnly;
  731.     //  If we modify data then don't accept the allocator if it's
  732.     //  the same as the output pin's allocator
  733.  
  734.     //  If our output is not connected just accept the allocator
  735.     //  We're never going to use this allocator because when our
  736.     //  output pin is connected we'll reconnect this pin
  737.     if (!m_pTIPFilter->OutputPin()->IsConnected()) {
  738.         return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly);
  739.     }
  740.  
  741.     //  If the allocator is read-only and we're modifying data
  742.     //  and the allocator is the same as the output pin's
  743.     //  then reject
  744.     if (bReadOnly && m_pTIPFilter->m_bModifiesData) {
  745.         IMemAllocator *pOutputAllocator =
  746.             m_pTIPFilter->OutputPin()->PeekAllocator();
  747.  
  748.         //  Make sure we have an output allocator
  749.         if (pOutputAllocator == NULL) {
  750.             hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()->
  751.                                       GetAllocator(&pOutputAllocator);
  752.             if (SUCCEEDED(hr)) {
  753.                 m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator);
  754.                 pOutputAllocator->Release();
  755.             }
  756.         }
  757.         if (pAllocator == pOutputAllocator) {
  758.             hr = E_FAIL;
  759.         } else {
  760.             //  Must copy so set the allocator properties on the output
  761.             ALLOCATOR_PROPERTIES Props, Actual;
  762.             hr = pAllocator->GetProperties(&Props);
  763.             if (SUCCEEDED(hr)) {
  764.                 hr = pOutputAllocator->SetProperties(&Props, &Actual);
  765.             }
  766.             if (SUCCEEDED(hr)) {
  767.                 if (  (Props.cBuffers > Actual.cBuffers)
  768.                    || (Props.cbBuffer > Actual.cbBuffer)
  769.                    || (Props.cbAlign  > Actual.cbAlign)
  770.                    ) {
  771.                     hr =  E_FAIL;
  772.                 }
  773.             }
  774.  
  775.             //  Set the allocator on the output pin
  776.             if (SUCCEEDED(hr)) {
  777.                 hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  778.                                        ->NotifyAllocator( pOutputAllocator, FALSE );
  779.             }
  780.         }
  781.     } else {
  782.         hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  783.                                    ->NotifyAllocator( pAllocator, bReadOnly );
  784.         if (SUCCEEDED(hr)) {
  785.             m_pTIPFilter->OutputPin()->SetAllocator( pAllocator );
  786.         }
  787.     }
  788.  
  789.     if (SUCCEEDED(hr)) {
  790.  
  791.         // It's possible that the old and the new are the same thing.
  792.         // AddRef before release ensures that we don't unload it.
  793.         pAllocator->AddRef();
  794.  
  795.         if( m_pAllocator != NULL )
  796.             m_pAllocator->Release();
  797.  
  798.         m_pAllocator = pAllocator;    // We have an allocator for the input pin
  799.     }
  800.  
  801.     return hr;
  802.  
  803. } // NotifyAllocator
  804.  
  805.  
  806. // EnumMediaTypes
  807. // - pass through to our downstream filter
  808. STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
  809. {
  810.     // Can only pass through if connected
  811.     if( !m_pTIPFilter->m_pOutput->IsConnected() )
  812.         return VFW_E_NOT_CONNECTED;
  813.  
  814.     return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum );
  815.  
  816. } // EnumMediaTypes
  817.  
  818.  
  819. // CheckMediaType
  820. // - agree to anything if not connected,
  821. // otherwise pass through to the downstream filter.
  822. // This assumes that the filter does not change the media type.
  823.  
  824. HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt )
  825. {
  826.     HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
  827.     if (hr!=S_OK) return hr;
  828.  
  829.     if( m_pTIPFilter->m_pOutput->IsConnected() )
  830.         return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt );
  831.     else
  832.         return S_OK;
  833.  
  834. } // CheckMediaType
  835.  
  836.  
  837. // If upstream asks us what our requirements are, we will try to ask downstream
  838. // if that doesn't work, we'll just take the defaults.
  839. STDMETHODIMP
  840. CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps)
  841. {
  842.  
  843.     if( m_pTIPFilter->m_pOutput->IsConnected() )
  844.         return m_pTIPFilter->OutputPin()
  845.                ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps );
  846.     else
  847.         return E_NOTIMPL;
  848.  
  849. } // GetAllocatorRequirements
  850.  
  851.  
  852.  
  853. // =================================================================
  854. // Implements the CTransInPlaceOutputPin class
  855. // =================================================================
  856.  
  857.  
  858. // constructor
  859.  
  860. CTransInPlaceOutputPin::CTransInPlaceOutputPin(
  861.     TCHAR *pObjectName,
  862.     CTransInPlaceFilter *pFilter,
  863.     HRESULT * phr,
  864.     LPCWSTR pPinName)
  865.     : CTransformOutputPin( pObjectName
  866.                          , pFilter
  867.                          , phr
  868.                          , pPinName),
  869.       m_pTIPFilter(pFilter)
  870. {
  871.     DbgLog(( LOG_TRACE, 2
  872.            , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin")));
  873.  
  874. } // constructor
  875.  
  876.  
  877. // EnumMediaTypes
  878. // - pass through to our upstream filter
  879. STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
  880. {
  881.     // Can only pass through if connected.
  882.     if( ! m_pTIPFilter->m_pInput->IsConnected() )
  883.         return VFW_E_NOT_CONNECTED;
  884.  
  885.     return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum );
  886.  
  887. } // EnumMediaTypes
  888.  
  889.  
  890.  
  891. // CheckMediaType
  892. // - agree to anything if not connected,
  893. // otherwise pass through to the upstream filter.
  894.  
  895. HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt )
  896. {
  897.     // Don't accept any output pin type changes if we're copying
  898.     // between allocators - it's too late to change the input
  899.     // allocator size.
  900.     if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) {
  901.         if (*pmt == m_mt) {
  902.             return S_OK;
  903.         } else {
  904.             return VFW_E_TYPE_NOT_ACCEPTED;
  905.         }
  906.     }
  907.  
  908.     // Assumes the type does not change.  That's why we're calling
  909.     // CheckINPUTType here on the OUTPUT pin.
  910.     HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
  911.     if (hr!=S_OK) return hr;
  912.  
  913.     if( m_pTIPFilter->m_pInput->IsConnected() )
  914.         return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt );
  915.     else
  916.         return S_OK;
  917.  
  918. } //CheckMediaType
  919.  
  920.  
  921. //
  922. //  Dummy - we don't ever decide an allocator ourselves - we
  923. //  let the upstream filter talk almost directly with the
  924. //  downstream input pin
  925. //
  926. HRESULT
  927. CTransInPlaceOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc)
  928. {
  929.     //  Allocator will be decided during input pin reconnect
  930.     return S_OK;
  931. } // DecideAllocator
  932.  
  933.  
  934. /* Save the allocator pointer in the output pin
  935. */
  936. void
  937. CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator)
  938. {
  939.     pAllocator->AddRef();
  940.     if (m_pAllocator) {
  941.         m_pAllocator->Release();
  942.     }
  943.     m_pAllocator = pAllocator;
  944. } // receiveAllocator
  945.