------------------------------------------------------------------------------
File: TransIP.cpp
Desc: DirectShow base classes - implements class for simple Transform-
In-Place filters such as audio.
Copyright (c) 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 BaseInputPin::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.
'3.구현 > VC++' 카테고리의 다른 글
윈도우 타이틀과 테두리 없애기 (0) | 2007.03.29 |
---|---|
SQL Sever 2005 Integration Sevice pocket book (0) | 2007.03.19 |
DirectX 간단한 사용 강좌(이준곤님글) (0) | 2007.02.16 |
Win32 쓰레드에서 동기화 방법 (0) | 2007.02.16 |
HRESULT 일반적인 값들 (0) | 2007.01.30 |