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

Michael Niedermayer michaelni
Wed May 7 02:24:36 CEST 2008


On Mon, May 05, 2008 at 10:01:36PM +0200, Vitor Sessak wrote:
> Hi
>
> Michael Niedermayer wrote:
>> On Wed, Apr 23, 2008 at 11:05:37PM +0200, Vitor Sessak wrote:
>>> Hi and thanks for the review
>> [...]
>>>>>             p->filter = filter;
>>>>>             p->pad_idx = pad;
>>>>>             p->next = *openLinks;
>>>>>             *openLinks = p;
>>>>>         }
>>>>>     }
>>>>>
>>>>>
>>>>>     if(*currInputs) {
>>>>>         av_log(log_ctx, AV_LOG_ERROR,
>>>>>                "Too many inputs specified for the \"%s\" filter.\n",
>>>>>                filter->name);
>>>>>         return -1;
>>>>>     }
>>>>>
>>>>>     pad = filter->output_count;
>>>>>     while(pad) {
>>>>>         AVFilterInOut *currlinkn = av_malloc(sizeof(AVFilterInOut));
>>>>>         pad--;
>>>>>         currlinkn->name    = NULL;
>>>>>         currlinkn->type    = LinkTypeOut;
>>>>>         currlinkn->filter  = filter;
>>>>>         currlinkn->pad_idx = pad;
>>>>>         currlinkn->next    = *currInputs;
>>>>>         *currInputs = currlinkn;
>>>> somehow i thik this can be factored with the above as well
>>> Maybe, but without worsening a lot readability?
>> We need to find a way to simplify the whole parser without reducing
>> readability.
>> Its much more complex than i would like ...
>
> Do you really think it can be so much more simpler? The "complex" part
> of it (free_inout(), extract_inout(), link_filter_inouts(),
> parse_inputs(), parse_outputs(), avfilter_parse_graph()) make 240 lines
> of code.

What i really dont like on the code is that it is complex and at the
same time only supports a small subset of what we wanted to support.
300 lines would be fine for a complete implemantation with ; * () user
defined filters, and all the other things discussed
Saying ok to the code to then see it grow to 3 times that to support
everything is something i really dont want to see ...

Also when i just look at the API i cant help but it feels quite hostile
to an implemantation of "user defined filters", and not only that.


[...]
>>>>>             AVFilterInOut *currlinkn = 
>>>>> av_malloc(sizeof(AVFilterInOut));
>>>>>
>>>>>             currlinkn->name    = name;
>>>>>             currlinkn->type    = LinkTypeIn;
>>>>>             currlinkn->filter  = NULL;
>>>>>             currlinkn->pad_idx = pad;
>>>>>             currlinkn->next    = *currInputs;
>>>>>             *currInputs = currlinkn;
>>>> Ive seen similar code a few times already here somewhere ...
>>> This code appears three times. But doing something like
>>>
>>> currlinkn = new_link(NULL, LinkTypeOut, filter, pad, *currInputs);
>>>
>>> wouldn't make this new_link() function a senseless wrapper?
>> maybe iam not sure, do what you prefer
>
> I did instead
>
>              AVFilterInOut tmp_link = { LinkTypeIn,
>                                         name,
>                                         NULL,
>                                         pad,
>                                         *currInputs,
>                                       };
>              AVFilterInOut *currlinkn = av_malloc(sizeof(AVFilterInOut));
>              *currlinkn = tmp_link;
>
> I think it is more readable.

I dont, i prefered the original

also
currlinkn->next    = *currInputs;
*currInputs = currlinkn;

is duplicated, its a insert_blah() 


[...]
>> Also name could be moved to AVFilterLink, that way we would still have
>> the names after the filter graph is build as a sideeffect.
>
> I agree that would be a nice side-effect (that could be done even
> without changing AVFilterInOut).

What i was aiming at was to remove the AVFilterInOut struct completely.
I just am not sure yet if its a good idea or not, but moving name out is a
good idea even on its own.
Leaving it in AVFilterInOut while adding it to AVFilterLink would be just
a duplicate field.


[...]
> /**
>  * Parse "[linkname]"
>  * @arg name a pointer (that need to be free'd after use) to the name between
>  *           parenthesis
>  */
> static void parse_link_name(const char **buf, char **name, AVClass *log_ctx)
> {
>     const char *start = *buf;
>     (*buf)++;
> 
>     *name = consume_string(buf);
> 
>     if(!*name[0]) {
>         av_log(log_ctx, AV_LOG_ERROR,
>                "Bad (empty?) label found in the following: \"%s\".\n", start);
>         goto fail;
>     }
> 
>     if(*(*buf)++ != ']') {
>         av_log(log_ctx, AV_LOG_ERROR,
>                "Mismatched '[' found in the following: \"%s\".\n", start);
>     fail:
>         av_freep(name);
>     }
> }

this function should return char * not void.


> 
> static void free_inout(AVFilterInOut *head)
> {
>     while(head) {
>         AVFilterInOut *next = head->next;
>         av_free(head);
>         head = next;
>     }
> }
> 

> static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
> {
>     AVFilterInOut *ret;
> 
>     while(*links && strcmp((*links)->name, label))
>         links = &((*links)->next);
> 
>     ret = *links;
> 
>     if(ret)
>         *links = ret->next;
> 
>     return ret;
> }

Maybe it would be cleaner to split this in find and remove ?

static AVFilterInOut **find_inout(const char *label, AVFilterInOut **links)
{
    while(*links && strcmp((*links)->name, label))
        links = &((*links)->next);

    return links;
}

x= find_inout()
if(*x)
    *x = (*x)->next;

the if() exists already after all extract_inout() calls


> 
> 
> static int link_filter_inouts(AVFilterContext *filter,
>                               AVFilterInOut **currInputs,
>                               AVFilterInOut **openLinks, AVClass *log_ctx)
> {
>     int pad = filter->input_count;
> 
>     while(pad--) {

>         AVFilterInOut *p = *currInputs;
>         *currInputs = (*currInputs)->next;
>         if(!p) {

>             av_log(log_ctx, AV_LOG_ERROR,

unreachable, this would have segfaulted already


[...]
> static int parse_inputs(const char **buf, AVFilterInOut **currInputs,
>                         AVFilterInOut **openLinks, AVClass *log_ctx)
> {
>     int pad = 0;
> 
>     while(**buf == '[') {
>         char *name;
>         AVFilterInOut *link_to_add;
>         AVFilterInOut *match;
> 
>         parse_link_name(buf, &name, log_ctx);
> 
>         if(!name)
>             return -1;
> 
>         /* First check if the label is not in the openLinks list */
>         match = extract_inout(name, openLinks);
> 
>         if(match) {
>             /* A label of a open link. Make it one of the inputs of the next
>                filter */
>             if(match->type != LinkTypeOut) {
>                 av_log(log_ctx, AV_LOG_ERROR,
>                        "Label \"%s\" appears twice as input!\n", match->name);
>                 return -1;
>             }

Just a totally wild idea, what about spliting openLinks into a list of
open inputs and a list of open outputs? that would avoid these type checks
and possibly the type field as well?

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Everything should be made as simple as possible, but not simpler.
-- Albert Einstein
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20080507/66a56177/attachment.pgp>



More information about the ffmpeg-devel mailing list