DirectShow learning (7) CTRANSINPLACEFILTER and source code resolution of associated PIN class

xiaoxiao2021-03-06  40

DirectShow Learning (7): CTRANSINPLACEFILTER and the source code resolution of the associated PIN class

1. CTRANSINPLACEINPUTPIN Class [Transip.h / Transip.cpp] derived from CTRANSFORMINPUTPIN.

a) Member variable: CTransinplaceFilter * const m_ptipfilter; // outfilter m_breadonly; // incoming stream is read Onlym_BreadOnly initialized to False.

b) IMemInputPin interface functions // Return our upstream allocator // If the downstream filter has one then offer that (even if our own output pin is not using it yet. // If the upstream filter chooses it then we will tell our output pin to ReceiveAllocator) .// Else if our output pin is using an allocator then offer that.// (This could mean offering the upstream filter his own allocator, it could mean offerring our own //) or it could mean offering the one from downstream // Else fail to offer any allocator at all.STDMETHODIMP GetAllocator (IMemAllocator ** ppAllocator); {CAutoLock cObjectLock (m_pLock); if (m_pTIPFilter-> m_pOutput-> IsConnected ()) {// Store the allocator we got hr = m_pTIPFilter-> OutputPin () -> ConnectedIMemInputPin () -> GetAllocator (ppAllocator); if (SUCCEEDED (hr)) {m_pTIPFilter-> OutputPin () -> SetAllocator (* ppAllocator);}} else {hr = CTransformInputPin :: GetAllocator (ppallocator);}} // get told which allocator the upstream output pin is actually going to use.STDMETHODIMP NotifyAllocator (IMemAllocator * pAllocator, BOOL bReadOnly); {CAutoLock cObjectLock (m_pLock); m_bReadOnly = bReadOnly; // If we modify data then do not accept the allocator if it's the same as the output pin's allocator // If our output is not connected just accept the allocator // We're never going to use this allocator because when our // output pin is connected we'll reconnect this pin if ( ! m_ptfilter-> Outputpin () -> isconnected ()) {return ctransformInputpin :: NotifyAllocator (Pallocator, BreadOnly);} // if the allocator is read-only and we '

re modifying data // and the allocator is the same as the output pin's then reject if (bReadOnly && m_pTIPFilter-> m_bModifiesData) {IMemAllocator * pOutputAllocator = m_pTIPFilter-> OutputPin () -> PeekAllocator (); // Make sure we have an output allocator if (pOutputAllocator == NULL) {hr = m_pTIPFilter-> OutputPin () -> ConnectedIMemInputPin () -> GetAllocator (& pOutputAllocator); if (FAILED (hr)) {hr = CreateMemoryAllocator (& pOutputAllocator);} if (SUCCEEDED ( HR)) {m_ptifilter-> Outputpin () -> setallocator; poutputallocator-> release ();}} if (pallocator == poutputallocator) {hr = e_fail;} else if (succeeded (hr)) {// Must Copy Set The Allocator Properties on The Output Allocator_Properties PROPS, ACTUAL; HR = Pallocator-> getProperties (& props); if (succeededed (hr)) { HR = poutputallocator-> setProperties (& props, & actual);} f (successded (hr)) {IF ((Props.cbuffers> Actual.cbuffers) || (Props.cbBuffer> actual.cbbuffer) || (Props.cbalign> Actual.cbAlign)) {hr = E_FAIL;}} // Set the allocator on the output pin if (SUCCEEDED (hr)) {hr = m_pTIPFilter-> OutputPin () -> ConnectedIMemInputPin () -> NotifyAllocator (pOutputAllocator, FALSE) }}} Else {hr = m_ptipfilter->

OutputPin () -> ConnectedIMemInputPin () -> NotifyAllocator (pAllocator, bReadOnly); if (SUCCEEDED (hr)) {m_pTIPFilter-> OutputPin () -> SetAllocator (pAllocator);}} if (SUCCEEDED (hr)) {// It's possible that the old and the new are the same thing // AddRef before release ensures that we do not unload it pAllocator-> AddRef ();.. if (! m_pAllocator = NULL) m_pAllocator-> Release (); m_pAllocator = pAllocator; // We have an allocator for the input pin}} // Pass this on downstream if it ever gets called.STDMETHODIMP GetAllocatorRequirements (ALLOCATOR_PROPERTIES * pProps); {if (m_pTIPFilter-> m_pOutput-> IsConnected ()) return m_pTIPFilter- > OUTPUTPIN () -> ConnectedimeMinputpin () -> getAllocatorRequirements (PPROPS); Else Return E_NOTIMPL;

c) IPin interface function and CBasePin, CBaseInputPin inherit function // Provide an enumerator for media types by getting one from downstreamSTDMETHODIMP EnumMediaTypes (IEnumMediaTypes ** ppEnum); {// Can only pass through if connected if (m_pTIPFilter-> m_pOutput->! IsConnected ()) return VFW_E_NOT_CONNECTED; return m_pTIPFilter-> m_pOutput-> getConnected () -> EnumMediaTypes (ppEnum);.} // Say whether media type is acceptable - agree to anything if not connected, // otherwise pass through to the downstream filter.// This assumes that the filter does not change the media type.HRESULT CheckMediaType (const CMediaType * pmt); {HRESULT hr = m_pTIPFilter-> CheckInputType (pmt); if (m_pTIPFilter-> m_pOutput-> IsConnected ()) return m_pTIPFilter-> m_pOutput-> getConnected () -> QueryAccept (pmt); else return S_OK;} HRESULT CompleteConnect (IPin * pReceivePin); {HRESULT hr = CBaseInputPin :: CompleteConnect (pReceivePin); return m_pTransformFilter-> CompleteConnect (PINDIR_INPUT, pReceivePin ); d) Other functions // allow the filter to see what allocator we have name n.b. this does not addrefime mallocator * peekallocator () const {return m_pallocator;} inline const bool readonly ()}}

2. CTransinplaceoutputPin class [transip.h / transip.cpp]

a) Member variables CTransinplaceFilter * const m_ptipfilter;

b) IPin interface function, CBaseOutputPin functions // Provide a media type enumerator Get it from upstream.STDMETHODIMP EnumMediaTypes. (IEnumMediaTypes ** ppEnum);! {if (m_pTIPFilter-> m_pInput-> IsConnected ()) return VFW_E_NOT_CONNECTED; return m_pTIPFilter- > m_pInput-> getConnected () -> EnumMediaTypes (ppEnum);} // Say whether media type is acceptable - agree to anything if not connected, // otherwise pass through to the upstream filter.HRESULT CheckMediaType (const CMediaType * pmt). ; {if (m_pTIPFilter-> UsingDifferentAllocators () && m_pFilter-> isStopped ()!) {if (* pmt == m_mt) {return S_OK;} else {return VFW_E_TYPE_NOT_ACCEPTED;}} HRESULT hr = m_pTIPFilter-> CheckInputType (pmt) ; if (m_pTIPFilter-> m_pInput-> IsConnected ()) return m_pTIPFilter-> m_pInput-> getConnected () -> QueryAccept (pmt); else return S_OK;} HRESULT CompleteConnect (IPin * pReceivePin); {HRESULT hr = CBaseOutputPin :: CompleteConnect (PreceivePin); Return M_PTRANSFORMFILTER-> CompleteConnec t (PINDIR_OUTPUT, pReceivePin);} c) Other functions // This just saves the allocator being used on the output pin // Also called by input pin's GetAllocator () void SetAllocator (IMemAllocator * pAllocator); {pAllocator-> AddRef () ; if (m_pAllocator) {m_pAllocator-> Release ();} m_pAllocator = pAllocator;} IMemInputPin * ConnectedIMemInputPin () {return m_pInputPin;} IMemAllocator * PeekAllocator () const {return m_pAllocator;}

3. CTransinplaceFilter class [transip.h / transip.cpp]

a) Member variable BOOL M_BMODIFIFIESDATA; / / DOES THIS FILTER CHANGE THE DATA? M_BMODIFIESDATA is initialized by BModiFiesData in the Constructor.

b) Newly added Virtual function Virtual HRESULT TRANSFORM (IMEDIASAMPLE * PSAMPLE) PURE

c) inherited IBaseFilter, CBaseFilter and CTransformFilter functions // chance to customize the transform processvirtual HRESULT Receive (IMediaSample * pSample); {/ * Check for other streams and pass them on * / AM_SAMPLE2_PROPERTIES * const pProps = m_pInput-> SampleProps () ; if (! pProps-> dwStreamId = AM_STREAM_MEDIA) {return m_pOutput-> Deliver (pSample);} if (UsingDifferentAllocators ()) {pSample = Copy (pSample);} // have the derived class transform the data hr = Transform ( pSample); hr = m_pOutput-> Deliver (pSample); if (UsingDifferentAllocators ()) {pSample-> Release ();}} HRESULT CompleteConnect (PIN_DIRECTION dir, IPin * pReceivePin); {if (dir == PINDIR_OUTPUT) {if (m_pInput-> IsConnected ()) {return ReconnectPin (m_pInput, & m_pOutput-> CurrentMediaType ());} return NOERROR;!} if (m_pOutput-> IsConnected ()) {if (m_pInput-> CurrentMediaType () = m_pOutput-> CurrentMediatype ()) {Return ReconnectPi n (m_pOutput, & m_pInput-> CurrentMediaType ());}}} // must overrideHRESULT GetMediaType (int iPosition, CMediaType * pMediaType) // This is called when we actually have to provide out own allocator.HRESULT DecideBufferSize (IMemAllocator *, ALLOCATOR_PROPERTIES *); {// if we are connect upstream, get his views if (m_pinput-> isconnected ()) {hr = inputpin () -> peekallocator () -> getproperties (& recommended);} // Plug Allocator_Properties, and call Palloc-> setProperties (Pproperties, & Actual);

{// create an input pin if not already DONE IF (m_pinput == null) {m_pinput = new cTransinplaceInputPin (Name ("Transinplace Input Pin"), this // Owner Filter, & HR // Result Code, L "Input" / / Pin name); if (m_pint! = Null && m_poutput == null) {m_poutput = new cTransinplaceoutputPin (Name ("Transinplace Output Pin"), this // Owner Filter, & HR // Result Code, L "Output" // Pin name); if (n == 0) {return m_pinput;} else == 1) {return m_poutput;}}} d) Other functions iMediasample * cTransinplaceFilter :: copy (iMediasample * psource ); Copy two sample} CTransinplacei nputPin * InputPin () const {return (CTransInPlaceInputPin *) m_pInput;} CTransInPlaceOutputPin * OutputPin () const {return (CTransInPlaceOutputPin *) m_pOutput;} // Helper to see if the input and output types matchBOOL TypesMatch () {return InputPin () -> CurrentMediaType () == OutputPin () -> CurrentMediaType ();} // Are the input and output allocators different BOOL UsingDifferentAllocators () const {return InputPin () -> PeekAllocator () = OutputPin () -> PeekAllocator?! ();

Attached to the design idea annotation in CTransinplacefilter, these classes should be the most comments in Base Classes, the easiest class. // How allocators area decided.

// An in-place Transform Tries To Do ITS Work In Someone else's buffers. It Tries To Persuade // The Filters on Either Side To Use The Same Allocator (AND for That Matter the Same Media Type).

// in desperation, if the downstream filter refuses to supply an allocator and the Upstream Filter

// Offers Only a Read-Only One IT Will Provide an Allocator. if The Upstream Filter Insists

// ON A Read-Only Allocator Then the Transform Filter Will (Reluctantly) COPY The Data Before

// transforming it

// in Order To Pass An Allocator Through It NEEDS TO REMEMBER THE ONE GOT from the first

// connection to pass it on to the second one.

// it is good if we can avoid insisting on a Particular ORDER ORDER OF Connection (There Is A Precedent

// for insisting on the input being connection first. insisting on the output being connected. INSISTING INTED

// first is not allowed. That Would Break Renderfile.)

// the base pin classes (CBASEOUTPUTPIN AND CBASEINPUTPIN) BOTH HAVE A M_PALLOCATOR MEMBER Which

// is buy in placepin :: getDeliverybuffer and cbaseinputpin :: inactive.

// TO Avoid Lots of extra overriding, We Should Keep these Happy, these Pointers.

// when Each Pin Is Connected, IT Will Set The Corresponding M_Pallocator and Will Have A Single

// Ref-Count On That Allocator Refcounts Are Acquired by getAllocator Calls Which Return AddReffed

// Allocators and is Released in One of:

// CBaseInputpin :: disconnect

// CBaseOutputpin :: BreakConect

// in each case m_pallocator is set to null after the release, so this is the last chance to EVER

// Release it. if there is the Same Pointer, this, THIS, IF THESETE.

// Had Better Be Cleared Up Before That PROBLEMS, We'll Stick with One // Per Pointer.

// Reconnecting and State Changes

// Each PIN COULD BE Disconnected, Connected with a Read-Only Allocator, Connected with an upstream

// read / Write Allocator, Connected with an allocator from DownStream or Connected with ITS OWN

// Allocator. Five States for Each PIN GIVES A DATA Space of 25 States.

// NOTATION:

// r / w == Read / Write

// r-o == read-only

//

//

// 00 means an unconnected pin.

// <- means using a r / w Allocator from the Upstream Filter

// <= means using a r-o allocator from an upstream filter

// || Means Using Our OWN (R / W) Allocator.

// -> Means Using A R / W Allocator from a DownStream Filter

// (A R-O Allocator from DownStream Is Nonsense, IT CAN't Ever Work).

//

// That Makes 25 Possible State. Some States Are Nonsense (Two Different

// Allocators from the Same Place. The Ree Just An Artifact of The Notation.

// <= <- nonsense.

// <= nonsense

// Some States Are Illegal (The Output Pin Never Accepts A R-O Allocator):

// 00 <= !! Error !!

// <= <= !! Error !!

// || <= !! Error !!

// -> <= !! Error !!

// Three State Appears to be inaccessible:

// -> || inaccessible

// || -> inaccessible

// || <- inaccessible

// Some State Only Ever Occur As Intermediate with a Pending Reconnect Which

// is Guaranteed to finish in another.

// -> 00 ?? Unstable Goes to || 00 00

// 00 <- ?? unstable goes to 00 || // -> <- ?? unsteable goes to -> ->

// <- || ?? unsteable goes to <- <-

// <- -> ?? unsteable goes to <- <-

// and That Leaves 11 Possible Resting State:

// 1 00 00 Nothing connect.

// 2 <- 00 Input Pin Connected.

// 3 <= 00 Input Pin Connected Using R-O Allocator.

// 4 || 00 Needs Several State Changes To Get Here.

// 5 00 || Output Pin Connected Using Our Allocator

// 6 00 -> DOWNSTREAM ONLY Connected

// 7 || || Undesirable But can be forced upon us.

// 8 <= || Copy Forced. <= -> Is Preference

// 9 <= -> OK - forced to copy.

// 10 <- <- Transform in Place (Ideal)

//11 -> -> Transform in Place (Ideal)

//

// The Object of The Exercise is to ensure That We finish Up in State 10 or 11 WHENEVER POSSIBLE.

// state 10 is Only Possible if The Upstream Filter Has A R / W Allocator (The Avi Splitter

// notoriously doesn't) And State 11 is Only Possible if The DownStream Filter Does Offer AN

// allocator.

// the transition table (Entries Marked * Go Via a reconnect)

// there 8 Possible Transitions:

// A: Connect Upstream To FILTER WITH R-O Allocator That INSSTS ON Using IT.

// b: Connect Upstream To Filter with r-o Allocator But Chooses Not to Use IT.

// c: Connect Upstream To FILTER WITH R / W Allocator and INSISTS ON Using IT.

// D: Connect Upstream To FILTER WITH R / W Allocator But Chooses Not To Use IT.

// E: Connect DownStream To a filter That Offers an Allocator

// f: Connect DownStream to a filter triaes not offer an allocator

// g: Disconnect Upstream

// h: disconnect downstream //

// a b c d e f g

/ / -------------------------------------------------------------------------------------------- ---------

// 00 00 1 | 3 3 2 2 6 5.. | 1 00 00

// <- 00 2 |... * 10/11 10 1. | 2 <- 00

// <= 00 3 |... * 9/11 * 7/8 1. | 3 <= 00

// || 00 4 |... * 8 * 7 1. | 4 || 00

// 00 || 5 | 8 7 * 10 7... 1 | 5 00 ||

// 00 -> 6 | 9 11 * 10 11... 1 | 6 00 ->

// || || 7 |...... 5 4 | 7 || ||

// <= || 8 |...... 5 3 | 8 <= ||

// <= -> 9 |....... 6 3 | 9 <= ->

// <- <- 10 |........ * 5/6 2 | 10 <- <-

// -> -> 11 |...... 6 * 2/3 | 11 -> ->

/ / -------------------------------------------------------------------------------------------- ---------

// a b c d e f g

//

// All these State Are Accessible without Requiring Any Filter To change its Behaviour But Not

// all transitions are accessible, // for instance a transition from state 4 to anywhere Other

// Than State 8 Requires That The Upstream Filter First Offer A R-O Allocator and the Changes

// ITS MIND AND OFFER R / W. this is not allowable - it Leads to things like the output pin

// getting a r / w Allocator from Upstream and the the INPUT PIN Being Told It Can Only Have A // R-O One.

// Note That You Chan Change (SAY) The Upstream Filter for a Different One, But Only As a Disconnect // Connect, NOT As a reconnect. (Exercise for the Reader Is To See How Get Into State 4).

//

// The reconnection stuff goes as Follows (some of the case shown here as "no reconnect" May

// Get One to finalise Media Type - An Old Story). if it is a reconnect where it, "no

// reconnect "Here The Reconnection Must Not Change The Allocator Choice.

// state 2: <- 00 Transition E <- <- Case C <- <- (no change)

// Case D -> <- and dam> -> ->

//

// state 2: <- 00 Transition f <- <- (no reconnect)

//

// state 3: <= 00 Transition E <= -> Case a <= -> (no change)

// Case B -> ->

// transition f <= || Case a <= || (no change)

// Case B || ||

//

// state 4: || 00 Transition E || || Case B -> || And the all cases to -> ->

// f || || Case B || || (no change)

//

// State 5: 00 || Transition a <= || (no reconnect)

// b || || (no reconnect)

// c <- || All Cases <- <-

// D || || (Unfortunate, But Upstream's Choice)

//

// State 6: 00 -> Transition a <= -> (no reconnect)

// b -> -> (no reconnect)

// c <- -> all case <- <- <-

// d -> -> (no reconnect) //

// state 10: <- <- Transition G 00 <- Case E 00 ->

// case f 00 ||

//

// State 11: -> -> Transition h -> 00 case a <= 00 (Schizo)

// case b <= 00

// case c <- 00 (Schizo)

// case d <- 00

//

// the rules:

// TO Sort Out Media Types:

// the input is reconnected

// if the input pin is connection and the output pin connects

// the output is reconnected

// if the output pin is connected

// and the input pin connects to a Different Media Type

//

// TO Sort Out Allocators:

// the input is reconnected

// if The Output Disconnects and the Input WAS Using A DownStream Allocator

// The Output Pin Calls Setallocator to Pass ON A NEW Allocator

// if the output is connected and

// if The Input Disconnects and the Output WAS Using An Upstream Allocator

// if the input acquires an allocator diffrom the Output One

// and this new allocator is not r-o

//

// Data is copied (i.e. Call getBuffer and Copy The Data Before Transforming IT)

// if The Two Allocators Are Different.

// CHAINS OF FILTERS:

// We Sit Between Two Filters (Call The and Z). We shop Finish Up with The Same Allocator

// on Both of Our Pins and That SHOULD BE The Same One That A and Z Would Have Agreed on IF WE

// Hadn't Been in the Way. Furthermore, IT Should Not Matter How Many In-Place Transforms

// is in the Way. Let B, C, D ... be in-place transforms ("US").

// here's how it goes:

//

// 1.

// a connects to b. They agree on a's allocator.// A-A-> B

//

// 2.

// b Connects to C. Same Story. There is no point in a reconnect, but

// b Will Request An Input Reconnect Anyway.

// a-a-> b-a-> c

//

// 3.

// c Connects to Z.

// c INSISTS ON Using A's Allocator, But Compromises by Requesting A Reconnect.

// of C's INPUT.

// a-a-> b -? -> c-a-> z

//

// We now have pending reconnects on Both A ---> B And B ---> C

//

// 4.

// The a ---> b Link is reconnected.

// A askS B for an Allocator. B See it Has A DownStream Connection So Asks Its DownStream

// INPUT PIN I.E. C's INPUT PIN for an Allocator. c Sees That It Too Has A Dowstream Connection

// so askS z for an allocator.

//

// Even though Z's Input Pin IS Connected, IT IS Being Asked for An Allocator.

// IT Could Refuse, in Which Case The Chain Is Done and Will Use A's Allocator

// Alternative, z May Supply One. A Chooses Either Z'S or A'S OWN One.

// b's INPUT PIN GETS NotifyAllocator Called to Tell It The Decision and IT

// Propagates this DownStream by Calling ReceiveAllocator on Its Output Pin

// Which Calls NotifyAllocator on The next Input PIN DOWNSTREAM ETC.

// if the choice is z1n it ing:

// a-z-> b-a-> c-a-> z

// a-z-> b-z-> c-a-> z

// a-z-> b-z-> c-z-> z

//

// and That's it !! any further (essential solious) reconnects peter out with no change in

// the chain.

Previous Article:

(6) Analysis of source code analysis of CTransfromFilter and associated PIN class

转载请注明原文地址:https://www.9cbs.com/read-63589.html

New Post(0)