1
0

transip.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  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. // 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. ( __in_opt LPCTSTR pName,
  253. __inout_opt LPUNKNOWN pUnk,
  254. REFCLSID clsid,
  255. __inout 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. ( __in_opt LPCSTR pName,
  268. __inout_opt LPUNKNOWN pUnk,
  269. REFCLSID clsid,
  270. __inout 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. , __inout 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. // Propose one byte
  389. // If 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. __out_opt 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 hrProps = pSample2->SetProperties(
  446. FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer),
  447. (PBYTE)m_pInput->SampleProps());
  448. pSample2->Release();
  449. if (FAILED(hrProps)) {
  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. if (FAILED(pDest->SetActualDataLength(lDataLength))) {
  483. pDest->Release();
  484. return NULL;
  485. }
  486. // Copy the sample data
  487. {
  488. BYTE *pSourceBuffer, *pDestBuffer;
  489. long lSourceSize = pSource->GetSize();
  490. long lDestSize = pDest->GetSize();
  491. ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength);
  492. if (FAILED(pSource->GetPointer(&pSourceBuffer)) ||
  493. FAILED(pDest->GetPointer(&pDestBuffer)) ||
  494. lDestSize < lDataLength ||
  495. lDataLength < 0) {
  496. pDest->Release();
  497. return NULL;
  498. }
  499. ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL);
  500. CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength );
  501. }
  502. }
  503. return pDest;
  504. } // Copy
  505. // override this to customize the transform process
  506. HRESULT
  507. CTransInPlaceFilter::Receive(IMediaSample *pSample)
  508. {
  509. /* Check for other streams and pass them on */
  510. AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
  511. if (pProps->dwStreamId != AM_STREAM_MEDIA) {
  512. return m_pOutput->Deliver(pSample);
  513. }
  514. HRESULT hr;
  515. // Start timing the TransInPlace (if PERF is defined)
  516. MSR_START(m_idTransInPlace);
  517. if (UsingDifferentAllocators()) {
  518. // We have to copy the data.
  519. pSample = Copy(pSample);
  520. if (pSample==NULL) {
  521. MSR_STOP(m_idTransInPlace);
  522. return E_UNEXPECTED;
  523. }
  524. }
  525. // have the derived class transform the data
  526. hr = Transform(pSample);
  527. // Stop the clock and log it (if PERF is defined)
  528. MSR_STOP(m_idTransInPlace);
  529. if (FAILED(hr)) {
  530. DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));
  531. if (UsingDifferentAllocators()) {
  532. pSample->Release();
  533. }
  534. return hr;
  535. }
  536. // the Transform() function can return S_FALSE to indicate that the
  537. // sample should not be delivered; we only deliver the sample if it's
  538. // really S_OK (same as NOERROR, of course.)
  539. if (hr == NOERROR) {
  540. hr = m_pOutput->Deliver(pSample);
  541. } else {
  542. // But it would be an error to return this private workaround
  543. // to the caller ...
  544. if (S_FALSE == hr) {
  545. // S_FALSE returned from Transform is a PRIVATE agreement
  546. // We should return NOERROR from Receive() in this cause because
  547. // returning S_FALSE from Receive() means that this is the end
  548. // of the stream and no more data should be sent.
  549. m_bSampleSkipped = TRUE;
  550. if (!m_bQualityChanged) {
  551. NotifyEvent(EC_QUALITY_CHANGE,0,0);
  552. m_bQualityChanged = TRUE;
  553. }
  554. hr = NOERROR;
  555. }
  556. }
  557. // release the output buffer. If the connected pin still needs it,
  558. // it will have addrefed it itself.
  559. if (UsingDifferentAllocators()) {
  560. pSample->Release();
  561. }
  562. return hr;
  563. } // Receive
  564. // =================================================================
  565. // Implements the CTransInPlaceInputPin class
  566. // =================================================================
  567. // constructor
  568. CTransInPlaceInputPin::CTransInPlaceInputPin
  569. ( __in_opt LPCTSTR pObjectName
  570. , __inout CTransInPlaceFilter *pFilter
  571. , __inout HRESULT *phr
  572. , __in_opt LPCWSTR pName
  573. )
  574. : CTransformInputPin(pObjectName,
  575. pFilter,
  576. phr,
  577. pName)
  578. , m_bReadOnly(FALSE)
  579. , m_pTIPFilter(pFilter)
  580. {
  581. DbgLog((LOG_TRACE, 2
  582. , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin")));
  583. } // constructor
  584. // =================================================================
  585. // Implements IMemInputPin interface
  586. // =================================================================
  587. // If the downstream filter has one then offer that (even if our own output
  588. // pin is not using it yet. If the upstream filter chooses it then we will
  589. // tell our output pin to ReceiveAllocator).
  590. // Else if our output pin is using an allocator then offer that.
  591. // ( This could mean offering the upstream filter his own allocator,
  592. // it could mean offerring our own
  593. // ) or it could mean offering the one from downstream
  594. // Else fail to offer any allocator at all.
  595. STDMETHODIMP CTransInPlaceInputPin::GetAllocator(__deref_out IMemAllocator ** ppAllocator)
  596. {
  597. CheckPointer(ppAllocator,E_POINTER);
  598. ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
  599. CAutoLock cObjectLock(m_pLock);
  600. HRESULT hr;
  601. if ( m_pTIPFilter->m_pOutput->IsConnected() ) {
  602. // Store the allocator we got
  603. hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  604. ->GetAllocator( ppAllocator );
  605. if (SUCCEEDED(hr)) {
  606. m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator );
  607. }
  608. }
  609. else {
  610. // Help upstream filter (eg TIP filter which is having to do a copy)
  611. // by providing a temp allocator here - we'll never use
  612. // this allocator because when our output is connected we'll
  613. // reconnect this pin
  614. hr = CTransformInputPin::GetAllocator( ppAllocator );
  615. }
  616. return hr;
  617. } // GetAllocator
  618. /* Get told which allocator the upstream output pin is actually going to use */
  619. STDMETHODIMP
  620. CTransInPlaceInputPin::NotifyAllocator(
  621. IMemAllocator * pAllocator,
  622. BOOL bReadOnly)
  623. {
  624. HRESULT hr = S_OK;
  625. CheckPointer(pAllocator,E_POINTER);
  626. ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
  627. CAutoLock cObjectLock(m_pLock);
  628. m_bReadOnly = bReadOnly;
  629. // If we modify data then don't accept the allocator if it's
  630. // the same as the output pin's allocator
  631. // If our output is not connected just accept the allocator
  632. // We're never going to use this allocator because when our
  633. // output pin is connected we'll reconnect this pin
  634. if (!m_pTIPFilter->OutputPin()->IsConnected()) {
  635. return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly);
  636. }
  637. // If the allocator is read-only and we're modifying data
  638. // and the allocator is the same as the output pin's
  639. // then reject
  640. if (bReadOnly && m_pTIPFilter->m_bModifiesData) {
  641. IMemAllocator *pOutputAllocator =
  642. m_pTIPFilter->OutputPin()->PeekAllocator();
  643. // Make sure we have an output allocator
  644. if (pOutputAllocator == NULL) {
  645. hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()->
  646. GetAllocator(&pOutputAllocator);
  647. if(FAILED(hr)) {
  648. hr = CreateMemoryAllocator(&pOutputAllocator);
  649. }
  650. if (SUCCEEDED(hr)) {
  651. m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator);
  652. pOutputAllocator->Release();
  653. }
  654. }
  655. if (pAllocator == pOutputAllocator) {
  656. hr = E_FAIL;
  657. } else if(SUCCEEDED(hr)) {
  658. // Must copy so set the allocator properties on the output
  659. ALLOCATOR_PROPERTIES Props, Actual;
  660. hr = pAllocator->GetProperties(&Props);
  661. if (SUCCEEDED(hr)) {
  662. hr = pOutputAllocator->SetProperties(&Props, &Actual);
  663. }
  664. if (SUCCEEDED(hr)) {
  665. if ( (Props.cBuffers > Actual.cBuffers)
  666. || (Props.cbBuffer > Actual.cbBuffer)
  667. || (Props.cbAlign > Actual.cbAlign)
  668. ) {
  669. hr = E_FAIL;
  670. }
  671. }
  672. // Set the allocator on the output pin
  673. if (SUCCEEDED(hr)) {
  674. hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  675. ->NotifyAllocator( pOutputAllocator, FALSE );
  676. }
  677. }
  678. } else {
  679. hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
  680. ->NotifyAllocator( pAllocator, bReadOnly );
  681. if (SUCCEEDED(hr)) {
  682. m_pTIPFilter->OutputPin()->SetAllocator( pAllocator );
  683. }
  684. }
  685. if (SUCCEEDED(hr)) {
  686. // It's possible that the old and the new are the same thing.
  687. // AddRef before release ensures that we don't unload it.
  688. pAllocator->AddRef();
  689. if( m_pAllocator != NULL )
  690. m_pAllocator->Release();
  691. m_pAllocator = pAllocator; // We have an allocator for the input pin
  692. }
  693. return hr;
  694. } // NotifyAllocator
  695. // EnumMediaTypes
  696. // - pass through to our downstream filter
  697. STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum )
  698. {
  699. // Can only pass through if connected
  700. if( !m_pTIPFilter->m_pOutput->IsConnected() )
  701. return VFW_E_NOT_CONNECTED;
  702. return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum );
  703. } // EnumMediaTypes
  704. // CheckMediaType
  705. // - agree to anything if not connected,
  706. // otherwise pass through to the downstream filter.
  707. // This assumes that the filter does not change the media type.
  708. HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt )
  709. {
  710. HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
  711. if (hr!=S_OK) return hr;
  712. if( m_pTIPFilter->m_pOutput->IsConnected() )
  713. return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt );
  714. else
  715. return S_OK;
  716. } // CheckMediaType
  717. // If upstream asks us what our requirements are, we will try to ask downstream
  718. // if that doesn't work, we'll just take the defaults.
  719. STDMETHODIMP
  720. CTransInPlaceInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps)
  721. {
  722. if( m_pTIPFilter->m_pOutput->IsConnected() )
  723. return m_pTIPFilter->OutputPin()
  724. ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps );
  725. else
  726. return E_NOTIMPL;
  727. } // GetAllocatorRequirements
  728. // CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect()
  729. // and then calls CTransInPlaceFilter::CompleteConnect(). It does this because
  730. // CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not
  731. // want to reconnect a pin if CBaseInputPin::CompleteConnect() fails.
  732. HRESULT
  733. CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin)
  734. {
  735. HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin);
  736. if (FAILED(hr)) {
  737. return hr;
  738. }
  739. return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
  740. } // CompleteConnect
  741. // =================================================================
  742. // Implements the CTransInPlaceOutputPin class
  743. // =================================================================
  744. // constructor
  745. CTransInPlaceOutputPin::CTransInPlaceOutputPin(
  746. __in_opt LPCTSTR pObjectName,
  747. __inout CTransInPlaceFilter *pFilter,
  748. __inout HRESULT * phr,
  749. __in_opt LPCWSTR pPinName)
  750. : CTransformOutputPin( pObjectName
  751. , pFilter
  752. , phr
  753. , pPinName),
  754. m_pTIPFilter(pFilter)
  755. {
  756. DbgLog(( LOG_TRACE, 2
  757. , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin")));
  758. } // constructor
  759. // EnumMediaTypes
  760. // - pass through to our upstream filter
  761. STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum )
  762. {
  763. // Can only pass through if connected.
  764. if( ! m_pTIPFilter->m_pInput->IsConnected() )
  765. return VFW_E_NOT_CONNECTED;
  766. return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum );
  767. } // EnumMediaTypes
  768. // CheckMediaType
  769. // - agree to anything if not connected,
  770. // otherwise pass through to the upstream filter.
  771. HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt )
  772. {
  773. // Don't accept any output pin type changes if we're copying
  774. // between allocators - it's too late to change the input
  775. // allocator size.
  776. if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) {
  777. if (*pmt == m_mt) {
  778. return S_OK;
  779. } else {
  780. return VFW_E_TYPE_NOT_ACCEPTED;
  781. }
  782. }
  783. // Assumes the type does not change. That's why we're calling
  784. // CheckINPUTType here on the OUTPUT pin.
  785. HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
  786. if (hr!=S_OK) return hr;
  787. if( m_pTIPFilter->m_pInput->IsConnected() )
  788. return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt );
  789. else
  790. return S_OK;
  791. } // CheckMediaType
  792. /* Save the allocator pointer in the output pin
  793. */
  794. void
  795. CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator)
  796. {
  797. pAllocator->AddRef();
  798. if (m_pAllocator) {
  799. m_pAllocator->Release();
  800. }
  801. m_pAllocator = pAllocator;
  802. } // SetAllocator
  803. // CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect()
  804. // and then calls CTransInPlaceFilter::CompleteConnect(). It does this because
  805. // CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to
  806. // reconnect a pin if CBaseOutputPin::CompleteConnect() fails.
  807. // CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected
  808. // to the Video Mixing Renderer.
  809. HRESULT
  810. CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin)
  811. {
  812. HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
  813. if (FAILED(hr)) {
  814. return hr;
  815. }
  816. return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
  817. } // CompleteConnect