📄 transip.cpp
字号:
//------------------------------------------------------------------------------
// File: TransIP.cpp
//
// Desc: DirectShow base classes - implements class for simple Transform-
// In-Place filters such as audio.
//
// Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
// How allocators are 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 then 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 it 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 of connection
// (There is a precedent for insisting on the input
// being connected first. Insisting on the output being connected first is
// not allowed. That would break RenderFile.)
//
// The base pin classes (CBaseOutputPin and CBaseInputPin) both have a
// m_pAllocator member which is used in places like
// CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive.
// To avoid lots of extra overriding, we should keep these happy
// by using 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 are 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 should ever be
// multiple refcounts associated with the same pointer, this had better
// be cleared up before that happens. To avoid such 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
//
// <input pin state> <output pin state> <comments>
//
// 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 states. Some states are nonsense (two different
// allocators from the same place). These are 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 states appears to be inaccessible:
// -> || Inaccessible
// || -> Inaccessible
// || <- Inaccessible
// Some states only ever occur as intermediates with a pending reconnect which
// is guaranteed to finish in another state.
// -> 00 ?? unstable goes to || 00
// 00 <- ?? unstable goes to 00 ||
// -> <- ?? unstable goes to -> ->
// <- || ?? unstable goes to <- <-
// <- -> ?? unstable goes to <- <-
// And that leaves 11 possible resting states:
// 1 00 00 Nothing connected.
// 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 preferable
// 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 states
// 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 are 8 possible transitions:
// A: Connect upstream to filter with R-O allocator that insists 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 that does not offer an allocator
// G: disconnect upstream
// H: Disconnect downstream
//
// A B C D E F G H
// ---------------------------------------------------------
// 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 H
//
// All these states 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 then 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 then the input pin being told it can only have a R-O one.
// Note that you CAN 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 you get into state 4).
//
// The reconnection stuff goes as follows (some of the cases shown here as
// "no reconnect" may get one to finalise media type - an old story).
// If there is a reconnect where it says "no reconnect" here then the
// reconnection must not change the allocator choice.
//
// state 2: <- 00 transition E <- <- case C <- <- (no change)
// case D -> <- and then to -> ->
//
// 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 then 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 cases <- <-
// 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 connected 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 different from the output one
// and that 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 them A and Z). We should 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
// are 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 sees that 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 downstream 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
// Alternatively, 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 Z then it goes:
// 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 (essentially spurious) reconnects peter out
// with no change in the chain.
#include <streams.h>
#include <measure.h>
#include <transip.h>
// =================================================================
// Implements the CTransInPlaceFilter class
// =================================================================
CTransInPlaceFilter::CTransInPlaceFilter
( TCHAR *pName,
LPUNKNOWN pUnk,
REFCLSID clsid,
HRESULT *phr,
bool bModifiesData
)
: CTransformFilter(pName, pUnk, clsid),
m_bModifiesData(bModifiesData)
{
#ifdef PERF
RegisterPerfId();
#endif // PERF
} // constructor
#ifdef UNICODE
CTransInPlaceFilter::CTransInPlaceFilter
( CHAR *pName,
LPUNKNOWN pUnk,
REFCLSID clsid,
HRESULT *phr,
bool bModifiesData
)
: CTransformFilter(pName, pUnk, clsid),
m_bModifiesData(bModifiesData)
{
#ifdef PERF
RegisterPerfId();
#endif // PERF
} // constructor
#endif
// return a non-addrefed CBasePin * for the user to addref if he holds onto it
// for longer than his pointer to us. We create the pins dynamically when they
// are asked for rather than in the constructor. This is because we want to
// give the derived class an oppportunity to return different pin objects
// As soon as any pin is needed we create both (this is different from the
// usual transform filter) because enumerators, allocators etc are passed
// through from one pin to another and it becomes very painful if the other
// pin isn't there. If we fail to create either pin we ensure we fail both.
CBasePin *
CTransInPlaceFilter::GetPin(int n)
{
HRESULT hr = S_OK;
// 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
);
// Constructor for CTransInPlaceInputPin can't fail
ASSERT(SUCCEEDED(hr));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -