home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / BaseClasses / transip.cpp < prev    next >
Encoding:
Text File  |  2001-10-08  |  31.6 KB  |  923 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-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.  
  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. #ifdef PERF
  273.     RegisterPerfId();
  274. #endif //  PERF
  275.  
  276. } // constructor
  277.  
  278. #ifdef UNICODE
  279. CTransInPlaceFilter::CTransInPlaceFilter
  280.    ( CHAR     *pName,
  281.      LPUNKNOWN  pUnk,
  282.      REFCLSID   clsid,
  283.      HRESULT   *phr,
  284.      bool       bModifiesData
  285.    )
  286.    : CTransformFilter(pName, pUnk, clsid),
  287.      m_bModifiesData(bModifiesData) {
  288. #ifdef PERF
  289.     RegisterPerfId();
  290. #endif //  PERF
  291.  
  292. } // constructor
  293. #endif
  294.  
  295. // return a non-addrefed CBasePin * for the user to addref if he holds onto it
  296. // for longer than his pointer to us. We create the pins dynamically when they
  297. // are asked for rather than in the constructor. This is because we want to
  298. // give the derived class an oppportunity to return different pin objects
  299.  
  300. // As soon as any pin is needed we create both (this is different from the
  301. // usual transform filter) because enumerators, allocators etc are passed
  302. // through from one pin to another and it becomes very painful if the other
  303. // pin isn't there.  If we fail to create either pin we ensure we fail both.
  304.  
  305. CBasePin *
  306. CTransInPlaceFilter::GetPin(int n) {
  307.     HRESULT hr = S_OK;
  308.  
  309.     // Create an input pin if not already done
  310.  
  311.     if(m_pInput == NULL) {
  312.  
  313.         m_pInput = new CTransInPlaceInputPin(NAME("TransInPlace input pin")
  314.             , this        // Owner filter
  315.             , &hr         // Result code
  316.             , L"Input"    // Pin name
  317.             );
  318.  
  319.         // Constructor for CTransInPlaceInputPin can't fail
  320.         ASSERT(SUCCEEDED(hr));
  321.     }
  322.  
  323.     // Create an output pin if not already done
  324.  
  325.     if(m_pInput!=NULL && m_pOutput == NULL) {
  326.  
  327.         m_pOutput = new CTransInPlaceOutputPin(NAME("TransInPlace output pin")
  328.             , this       // Owner filter
  329.             , &hr        // Result code
  330.             , L"Output"  // Pin name
  331.             );
  332.  
  333.         // a failed return code should delete the object
  334.  
  335.         ASSERT(SUCCEEDED(hr));
  336.         if(m_pOutput == NULL) {
  337.             delete m_pInput;
  338.             m_pInput = NULL;
  339.         }
  340.     }
  341.  
  342.     // Return the appropriate pin
  343.  
  344.     ASSERT(n>=0 && n<=1);
  345.     if(n == 0) {
  346.         return m_pInput;
  347.     }
  348.     else if(n==1) {
  349.         return m_pOutput;
  350.     }
  351.     else {
  352.         return NULL;
  353.     }
  354.  
  355. } // GetPin
  356.  
  357.  
  358.  
  359. // dir is the direction of our pin.
  360. // pReceivePin is the pin we are connecting to.
  361. HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin) {
  362.     UNREFERENCED_PARAMETER(pReceivePin);
  363.     ASSERT(m_pInput);
  364.     ASSERT(m_pOutput);
  365.  
  366.     // if we are not part of a graph, then don't indirect the pointer
  367.     // this probably prevents use of the filter without a filtergraph
  368.     if(!m_pGraph) {
  369.         return VFW_E_NOT_IN_GRAPH;
  370.     }
  371.  
  372.     // Always reconnect the input to account for buffering changes
  373.     //
  374.     // Because we don't get to suggest a type on ReceiveConnection
  375.     // we need another way of making sure the right type gets used.
  376.     //
  377.     // One way would be to have our EnumMediaTypes return our output
  378.     // connection type first but more deterministic and simple is to
  379.     // call ReconnectEx passing the type we want to reconnect with
  380.     // via the base class ReconeectPin method.
  381.  
  382.     if(dir == PINDIR_OUTPUT) {
  383.         if(m_pInput->IsConnected()) {
  384.             return ReconnectPin(m_pInput, &m_pOutput->CurrentMediaType());
  385.         }
  386.         return NOERROR;
  387.     }
  388.  
  389.     ASSERT(dir == PINDIR_INPUT);
  390.  
  391.     // Reconnect output if necessary
  392.  
  393.     if(m_pOutput->IsConnected()) {
  394.  
  395.         if(m_pInput->CurrentMediaType()
  396.             != m_pOutput->CurrentMediaType()) {
  397.             return ReconnectPin(m_pOutput, &m_pInput->CurrentMediaType());
  398.         }
  399.     }
  400.     return NOERROR;
  401.  
  402. } // ComnpleteConnect
  403.  
  404.  
  405. //
  406. // DecideBufferSize
  407. //
  408. // Tell the output pin's allocator what size buffers we require.
  409. // *pAlloc will be the allocator our output pin is using.
  410. //
  411.  
  412. HRESULT CTransInPlaceFilter::DecideBufferSize
  413.             ( IMemAllocator *pAlloc
  414.             , ALLOCATOR_PROPERTIES *pProperties
  415.             ) {
  416.     ALLOCATOR_PROPERTIES Request, Actual;
  417.     HRESULT hr;
  418.  
  419.     // If we are connected upstream, get his views
  420.     if(m_pInput->IsConnected()) {
  421.         // Get the input pin allocator, and get its size and count.
  422.         // we don't care about his alignment and prefix.
  423.  
  424.         hr = InputPin()->PeekAllocator()->GetProperties(&Request);
  425.         if(FAILED(hr)) {
  426.             // Input connected but with a secretive allocator - enough!
  427.             return hr;
  428.         }
  429.     }
  430.     else {
  431.         // We're reduced to blind guessing.  Let's guess one byte and if
  432.         // this isn't enough then when the other pin does get connected
  433.         // we can revise it.
  434.         ZeroMemory(&Request, sizeof(Request));
  435.         Request.cBuffers = 1;
  436.         Request.cbBuffer = 1;
  437.     }
  438.  
  439.  
  440.     DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements")));
  441.     DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"),
  442.         Request.cBuffers, Request.cbBuffer));
  443.  
  444.     // Pass the allocator requirements to our output side
  445.     // but do a little sanity checking first or we'll just hit
  446.     // asserts in the allocator.
  447.  
  448.     pProperties->cBuffers = Request.cBuffers;
  449.     pProperties->cbBuffer = Request.cbBuffer;
  450.     if(pProperties->cBuffers<=0) {pProperties->cBuffers = 1; 
  451.     }
  452.     if(pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; 
  453.     }
  454.     hr = pAlloc->SetProperties(pProperties, &Actual);
  455.  
  456.     if(FAILED(hr)) {
  457.         return hr;
  458.     }
  459.  
  460.     DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements")));
  461.     DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"),
  462.         Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign));
  463.  
  464.     // Make sure we got the right alignment and at least the minimum required
  465.  
  466.     if((Request.cBuffers > Actual.cBuffers)
  467.         || (Request.cbBuffer > Actual.cbBuffer)
  468.         || (Request.cbAlign  > Actual.cbAlign)) {
  469.         return E_FAIL;
  470.     }
  471.     return NOERROR;
  472.  
  473. } // DecideBufferSize
  474.  
  475. //
  476. // Copy
  477. //
  478. // return a pointer to an identical copy of pSample
  479. IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) {
  480.     IMediaSample * pDest;
  481.  
  482.     HRESULT hr;
  483.     REFERENCE_TIME tStart, tStop;
  484.     const BOOL bTime = S_OK == pSource->GetTime(&tStart, &tStop);
  485.  
  486.     // this may block for an indeterminate amount of time
  487.     hr = OutputPin()->PeekAllocator()->GetBuffer(&pDest
  488.         , bTime ? &tStart : NULL
  489.         , bTime ? &tStop : NULL
  490.         , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0);
  491.  
  492.     if(FAILED(hr)) {
  493.         return NULL;
  494.     }
  495.  
  496.     ASSERT(pDest);
  497.     IMediaSample2 *pSample2;
  498.     if(SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
  499.         HRESULT hr = pSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer),
  500.             (PBYTE)m_pInput->SampleProps());
  501.         pSample2->Release();
  502.         if(FAILED(hr)) {
  503.             pDest->Release();
  504.             return NULL;
  505.         }
  506.     }
  507.     else {
  508.         if(bTime) {
  509.             pDest->SetTime(&tStart, &tStop);
  510.         }
  511.  
  512.         if(S_OK == pSource->IsSyncPoint()) {
  513.             pDest->SetSyncPoint(TRUE);
  514.         }
  515.         if(S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) {
  516.             pDest->SetDiscontinuity(TRUE);
  517.         }
  518.         if(S_OK == pSource->IsPreroll()) {
  519.             pDest->SetPreroll(TRUE);
  520.         }
  521.  
  522.         // Copy the media type
  523.         AM_MEDIA_TYPE *pMediaType;
  524.         if(S_OK == pSource->GetMediaType(&pMediaType)) {
  525.             pDest->SetMediaType(pMediaType);
  526.             DeleteMediaType(pMediaType);
  527.         }
  528.  
  529.     }
  530.  
  531.     m_bSampleSkipped = FALSE;
  532.  
  533.     // Copy the sample media times
  534.     REFERENCE_TIME TimeStart, TimeEnd;
  535.     if(pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) {
  536.         pDest->SetMediaTime(&TimeStart,&TimeEnd);
  537.     }
  538.  
  539.     // Copy the actual data length and the actual data.
  540.     {
  541.         const long lDataLength = pSource->GetActualDataLength();
  542.         pDest->SetActualDataLength(lDataLength);
  543.  
  544.         // Copy the sample data
  545.         {
  546.             BYTE *pSourceBuffer, *pDestBuffer;
  547.             long lSourceSize  = pSource->GetSize();
  548.             long lDestSize = pDest->GetSize();
  549.  
  550.             ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength);
  551.  
  552.             pSource->GetPointer(&pSourceBuffer);
  553.             pDest->GetPointer(&pDestBuffer);
  554.             ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL);
  555.  
  556.             CopyMemory((PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength);
  557.         }
  558.     }
  559.  
  560.     return pDest;
  561.  
  562. } // Copy
  563.  
  564.  
  565. // override this to customize the transform process
  566.  
  567. HRESULT
  568. CTransInPlaceFilter::Receive(IMediaSample *pSample) {
  569.     /*  Check for other streams and pass them on */
  570.     AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
  571.     if(pProps->dwStreamId != AM_STREAM_MEDIA) {
  572.         return m_pOutput->Deliver(pSample);
  573.     }
  574.     HRESULT hr;
  575.  
  576.     // Start timing the TransInPlace (if PERF is defined)
  577.     MSR_START(m_idTransInPlace);
  578.  
  579.     if(UsingDifferentAllocators()) {
  580.  
  581.         // We have to copy the data.
  582.  
  583.         pSample = Copy(pSample);
  584.  
  585.         if(pSample==NULL) {
  586.             MSR_STOP(m_idTransInPlace);
  587.             return E_UNEXPECTED;
  588.         }
  589.     }
  590.  
  591.     // have the derived class transform the data
  592.     hr = Transform(pSample);
  593.  
  594.     // Stop the clock and log it (if PERF is defined)
  595.     MSR_STOP(m_idTransInPlace);
  596.  
  597.     if(FAILED(hr)) {
  598.         DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));
  599.         if(UsingDifferentAllocators()) {
  600.             pSample->Release();
  601.         }
  602.         return hr;
  603.     }
  604.  
  605.     // the Transform() function can return S_FALSE to indicate that the
  606.     // sample should not be delivered; we only deliver the sample if it's
  607.     // really S_OK (same as NOERROR, of course.)
  608.     if(hr == NOERROR) {
  609.         hr = m_pOutput->Deliver(pSample);
  610.     }
  611.     else {
  612.         //  But it would be an error to return this private workaround
  613.         //  to the caller ...
  614.         if(S_FALSE == hr) {
  615.             // S_FALSE returned from Transform is a PRIVATE agreement
  616.             // We should return NOERROR from Receive() in this cause because
  617.             // returning S_FALSE from Receive() means that this is the end
  618.             // of the stream and no more data should be sent.
  619.             m_bSampleSkipped = TRUE;
  620.             if(!m_bQualityChanged) {
  621.                 NotifyEvent(EC_QUALITY_CHANGE,0,0);
  622.                 m_bQualityChanged = TRUE;
  623.             }
  624.             hr = NOERROR;
  625.         }
  626.     }
  627.  
  628.     // release the output buffer. If the connected pin still needs it,
  629.     // it will have addrefed it itself.
  630.     if(UsingDifferentAllocators()) {
  631.         pSample->Release();
  632.     }
  633.  
  634.     return hr;
  635.  
  636. } // Receive
  637.  
  638.  
  639.  
  640. // =================================================================
  641. // Implements the CTransInPlaceInputPin class
  642. // =================================================================
  643.  
  644.  
  645. // constructor
  646.  
  647. CTransInPlaceInputPin::CTransInPlaceInputPin
  648.     ( TCHAR               *pObjectName
  649.     , CTransInPlaceFilter *pFilter
  650.     , HRESULT             *phr
  651.     , LPCWSTR              pName
  652.     )
  653.     : CTransformInputPin(pObjectName,
  654.                          pFilter,
  655.                          phr,
  656.                          pName)
  657.     , m_bReadOnly(FALSE)
  658.     , m_pTIPFilter(pFilter) {
  659.  
  660.     DbgLog((LOG_TRACE, 2
  661.         , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin")));
  662.  
  663. } // constructor
  664.  
  665.  
  666. // =================================================================
  667. // Implements IMemInputPin interface
  668. // =================================================================
  669.  
  670.  
  671. // If the downstream filter has one then offer that (even if our own output
  672. // pin is not using it yet.  If the upstream filter chooses it then we will
  673. // tell our output pin to ReceiveAllocator).
  674. // Else if our output pin is using an allocator then offer that.
  675. //     ( This could mean offering the upstream filter his own allocator,
  676. //       it could mean offerring our own
  677. //     ) or it could mean offering the one from downstream
  678. // Else fail to offer any allocator at all.
  679.  
  680. STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator) {
  681.     CheckPointer(ppAllocator,E_POINTER);
  682.     ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
  683.     CAutoLock cObjectLock(m_pLock);
  684.  
  685.     HRESULT hr;
  686.  
  687.     if(m_pTIPFilter->m_pOutput->IsConnected()) {
  688.         //  Store the allocator we got
  689.         hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  690.         ->GetAllocator(ppAllocator);
  691.         if(SUCCEEDED(hr)) {
  692.             m_pTIPFilter->OutputPin()->SetAllocator(*ppAllocator);
  693.         }
  694.     }
  695.     else {
  696.         //  Help upstream filter (eg TIP filter which is having to do a copy)
  697.         //  by providing a temp allocator here - we'll never use
  698.         //  this allocator because when our output is connected we'll
  699.         //  reconnect this pin
  700.         hr = CTransformInputPin::GetAllocator(ppAllocator);
  701.     }
  702.     return hr;
  703.  
  704. } // GetAllocator
  705.  
  706.  
  707.  
  708. /* Get told which allocator the upstream output pin is actually going to use */
  709.  
  710.  
  711. STDMETHODIMP
  712. CTransInPlaceInputPin::NotifyAllocator(
  713.     IMemAllocator * pAllocator,
  714.     BOOL bReadOnly) {
  715.     HRESULT hr = S_OK;
  716.     CheckPointer(pAllocator,E_POINTER);
  717.     ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
  718.  
  719.     CAutoLock cObjectLock(m_pLock);
  720.  
  721.     m_bReadOnly = bReadOnly;
  722.     //  If we modify data then don't accept the allocator if it's
  723.     //  the same as the output pin's allocator
  724.  
  725.     //  If our output is not connected just accept the allocator
  726.     //  We're never going to use this allocator because when our
  727.     //  output pin is connected we'll reconnect this pin
  728.     if(!m_pTIPFilter->OutputPin()->IsConnected()) {
  729.         return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly);
  730.     }
  731.  
  732.     //  If the allocator is read-only and we're modifying data
  733.     //  and the allocator is the same as the output pin's
  734.     //  then reject
  735.     if(bReadOnly && m_pTIPFilter->m_bModifiesData) {
  736.         IMemAllocator *pOutputAllocator =
  737.             m_pTIPFilter->OutputPin()->PeekAllocator();
  738.  
  739.         //  Make sure we have an output allocator
  740.         if(pOutputAllocator == NULL) {
  741.             hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()->
  742.             GetAllocator(&pOutputAllocator);
  743.             if(FAILED(hr)) {
  744.                 hr = CreateMemoryAllocator(&pOutputAllocator);
  745.             }
  746.             if(SUCCEEDED(hr)) {
  747.                 m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator);
  748.                 pOutputAllocator->Release();
  749.             }
  750.         }
  751.         if(pAllocator == pOutputAllocator) {
  752.             hr = E_FAIL;
  753.         }
  754.         else if(SUCCEEDED(hr)) {
  755.             //  Must copy so set the allocator properties on the output
  756.             ALLOCATOR_PROPERTIES Props, Actual={0};
  757.             hr = pAllocator->GetProperties(&Props);
  758.             if(SUCCEEDED(hr)) {
  759.                 hr = pOutputAllocator->SetProperties(&Props, &Actual);
  760.             }
  761.             if(SUCCEEDED(hr)) {
  762.                 if((Props.cBuffers > Actual.cBuffers)
  763.                     || (Props.cbBuffer > Actual.cbBuffer)
  764.                     || (Props.cbAlign  > Actual.cbAlign)) {
  765.                     hr =  E_FAIL;
  766.                 }
  767.             }
  768.  
  769.             //  Set the allocator on the output pin
  770.             if(SUCCEEDED(hr)) {
  771.                 hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  772.                                  ->NotifyAllocator(pOutputAllocator, FALSE);
  773.             }
  774.         }
  775.     }
  776.     else {
  777.         hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  778.                          ->NotifyAllocator(pAllocator, bReadOnly);
  779.         if(SUCCEEDED(hr)) {
  780.             m_pTIPFilter->OutputPin()->SetAllocator(pAllocator);
  781.         }
  782.     }
  783.  
  784.     if(SUCCEEDED(hr)) {
  785.  
  786.         // It's possible that the old and the new are the same thing.
  787.         // AddRef before release ensures that we don't unload it.
  788.         pAllocator->AddRef();
  789.  
  790.         if(m_pAllocator != NULL)
  791.             m_pAllocator->Release();
  792.  
  793.         m_pAllocator = pAllocator;    // We have an allocator for the input pin
  794.     }
  795.  
  796.     return hr;
  797.  
  798. } // NotifyAllocator
  799.  
  800.  
  801. // EnumMediaTypes
  802. // - pass through to our downstream filter
  803. STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) {
  804.     // Can only pass through if connected
  805.     if(!m_pTIPFilter->m_pOutput->IsConnected())
  806.         return VFW_E_NOT_CONNECTED;
  807.  
  808.     return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes(ppEnum);
  809.  
  810. } // EnumMediaTypes
  811.  
  812.  
  813. // CheckMediaType
  814. // - agree to anything if not connected,
  815. // otherwise pass through to the downstream filter.
  816. // This assumes that the filter does not change the media type.
  817.  
  818. HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt ) {
  819.     HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
  820.     if(hr!=S_OK) return hr;
  821.  
  822.     if(m_pTIPFilter->m_pOutput->IsConnected())
  823.         return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept(pmt);
  824.     else
  825.         return S_OK;
  826.  
  827. } // CheckMediaType
  828.  
  829.  
  830. // If upstream asks us what our requirements are, we will try to ask downstream
  831. // if that doesn't work, we'll just take the defaults.
  832. STDMETHODIMP
  833. CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps) {
  834.  
  835.     if(m_pTIPFilter->m_pOutput->IsConnected())
  836.         return m_pTIPFilter->OutputPin()
  837.         ->ConnectedIMemInputPin()->GetAllocatorRequirements(pProps);
  838.     else
  839.         return E_NOTIMPL;
  840.  
  841. } // GetAllocatorRequirements
  842.  
  843.  
  844.  
  845. // =================================================================
  846. // Implements the CTransInPlaceOutputPin class
  847. // =================================================================
  848.  
  849.  
  850. // constructor
  851.  
  852. CTransInPlaceOutputPin::CTransInPlaceOutputPin(
  853.     TCHAR *pObjectName,
  854.     CTransInPlaceFilter *pFilter,
  855.     HRESULT * phr,
  856.     LPCWSTR pPinName)
  857.     : CTransformOutputPin( pObjectName
  858.                          , pFilter
  859.                          , phr
  860.                          , pPinName),
  861.       m_pTIPFilter(pFilter) {
  862.  
  863.     DbgLog(( LOG_TRACE, 2
  864.         , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin")));
  865.  
  866. } // constructor
  867.  
  868.  
  869. // EnumMediaTypes
  870. // - pass through to our upstream filter
  871. STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum ) {
  872.     // Can only pass through if connected.
  873.     if(! m_pTIPFilter->m_pInput->IsConnected())
  874.         return VFW_E_NOT_CONNECTED;
  875.  
  876.     return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes(ppEnum);
  877.  
  878. } // EnumMediaTypes
  879.  
  880.  
  881.  
  882. // CheckMediaType
  883. // - agree to anything if not connected,
  884. // otherwise pass through to the upstream filter.
  885.  
  886. HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt ) {
  887.     // Don't accept any output pin type changes if we're copying
  888.     // between allocators - it's too late to change the input
  889.     // allocator size.
  890.     if(m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) {
  891.         if(*pmt == m_mt) {
  892.             return S_OK;
  893.         }
  894.         else {
  895.             return VFW_E_TYPE_NOT_ACCEPTED;
  896.         }
  897.     }
  898.  
  899.     // Assumes the type does not change.  That's why we're calling
  900.     // CheckINPUTType here on the OUTPUT pin.
  901.     HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
  902.     if(hr!=S_OK) 
  903.         return hr;
  904.  
  905.     if(m_pTIPFilter->m_pInput->IsConnected())
  906.         return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept(pmt);
  907.     else
  908.         return S_OK;
  909.  
  910. } //CheckMediaType
  911.  
  912.  
  913. /* Save the allocator pointer in the output pin
  914. */
  915. void
  916. CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator) {
  917.     pAllocator->AddRef();
  918.     if(m_pAllocator) {
  919.         m_pAllocator->Release();
  920.     }
  921.     m_pAllocator = pAllocator;
  922. } // receiveAllocator
  923.