# [FFmpeg-devel] [PATCH] [2/??] [3/3] Filter graphs - Parser for a graph description

Fri Mar 21 19:47:32 CET 2008

```On 21 Mar 2008, at 14:40, Robert Swain wrote:

>>> The diagram for the second of the two examples might be clearer if
>>> it
>>> were drawn as follows:
>>>
>>>     ---> filter1 ---> (abc)
>>>             |
>>>             v
>>> (def) ---> filter2 --->
>>>
>>> I prefer this because the inputs are on the left and the outputs on
>>> the right. Please note, however, that the output of filter1 to (abc)
>>> would be filter1's second output looking at your diagram. The first
>>> output of filter1 goes to filter2 in your diagram.
>>
>> Ok, let's assume that.
>>
>>> We have two input streams, the input of filter1 and (def). The
>>> inputs
>>> of filter2 come from filter1 (or the first output of split in your
>>> notation) and from (def). In what order are these fed into filter2?
>>> Is
>>> the 'spare' input that isn't used by filter1 to be kept in a list of
>>> remaining input possibilities and later used by the next filter that
>>> doesn't have enough inputs coming from other filters in the chain?
>>> What takes priority - the inputs from the chain or the initial
>>> inputs
>>> to the graph? Is this just a case that really needs some named
>>> inputs?
>>
>> Probably the easiest way to look at this is to compose blocks F, G,
>> H, ... where each of the blocks is build using * so as the number of
>> inputs and outputs matches at each stage. The pairing is then
>> straightforward: 1st output from a block is 1st input for the
>> successive block, 2nd output from a block is 2nd input for the
>> successive block, etc. For instance in the case above:
>>
>>   - start with F = filter1,split : 1 ---> 2 and G = filter2 : 2 --->
>> 1;
>> 	then the final filter is (F * nop) , (nop * G) : 2 ---> 2.
>> 	This is because:
>>
>>   - the 2nd input (def) passes the first block untouched to be fed
>> to G;
>> 	you can do that by writing F*nop : 2 ---> 3
>>
>>   - now the 1st output of F passes the second block untouched to be
>> 	output. you can write that as nop*G : 3 ---> 2.
>
> Originally you wrote:
>
> filter1->filter2
> |         ^
> v         |
> (abc)     (def)
>
> ...gives...
>
> filter1, split, (filter2 * nop)

>
>
> Now you're writing (substituting filter1, split back in...):
>
> (filter1, split) * nop, nop * filter2

Wait a minute: this graph is different from that of your previous
email which is just reported above. The differences being that here
filter1 has no input stream, while above it's got one, and here (abc)
is the first output stream, while above is the 2nd. So the graph above
is

(filter1, split) * nop, nop * filter2

while this graph is:

(filter1, split) * nop, nop * filter2, swap

> Was the "* nop" in "F * nop" implicit?

no, there is nothing implicit with indices: I just got it wrong the
first time around.

> If so, I can accept this but,
> the second input to the graph would have been passed through the * nop
> and filter2 would have used both outputs from the split after filter1,
> which wasn't what was desired from the graph diagram. I think the
> filter2 * nop should have been nop * filter2 as you are now stating.

That would not have happened because the types were wrong:

filter1, split : 0 ---> 2 while filter2 *nop : 3 ---> 2 and (def) :
---> 1

the parser would have caught this...

> This kind of confusion could probably have been avoided using explicit
> naming. :)

... however it is clearly the case that if one gets the permutation
wrong, obtains unexpected results possibly without any warning
whatsoever. Same might happen with names though, it is not exactly
impossible to confuse a tmp_i with a tmp_j in something like this:

> (in0,tmp0,tmp2)filter1(tmp1,out0,tmp2);
> (in1,tmp1,tmp3)filter2(tmp3,tmp0,out1)