[FFmpeg-devel] [PATCH] lavfi: support multiple rounds of format negotiation.

Stefano Sabatini stefasab at gmail.com
Sun Mar 24 20:00:19 CET 2013


On date Sunday 2013-03-24 19:43:21 +0100, Nicolas George encoded:
> Remove the temporary hack for amerge and replace it with a
> generic solution.
> 
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
>  doc/filter_design.txt       |    5 ++
>  libavfilter/avfiltergraph.c |  109 ++++++++++++++++++++++++++++++++-----------
>  2 files changed, 88 insertions(+), 26 deletions(-)
[...] 
> diff --git a/doc/filter_design.txt b/doc/filter_design.txt
> index 772ca9d..2f9e57d 100644
> --- a/doc/filter_design.txt
> +++ b/doc/filter_design.txt
> @@ -29,6 +29,11 @@ Format negotiation
>    same format amongst a supported list, all it has to do is use a reference
>    to the same list of formats.
>  
> +  query_formats can leave some formats unset and return AVERROR(EAGAIN) to
> +  cause the negotiation mechanism to try again later. That can be used by
> +  filters with complex requirements to use the format negotiated on one link
> +  to set the formats supported on another.
> +
>  
>  Buffer references ownership and permissions
>  ===========================================
> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
> index 89cdda3..449e5cc 100644
> --- a/libavfilter/avfiltergraph.c
> +++ b/libavfilter/avfiltergraph.c
> @@ -23,6 +23,7 @@
>  #include <string.h>
>  
>  #include "libavutil/avassert.h"
> +#include "libavutil/bprint.h"
>  #include "libavutil/channel_layout.h"
>  #include "libavutil/opt.h"
>  #include "libavutil/pixdesc.h"
> @@ -211,8 +212,9 @@ static int filter_query_formats(AVFilterContext *ctx)
>                              AVMEDIA_TYPE_VIDEO;
>  
>      if ((ret = ctx->filter->query_formats(ctx)) < 0) {
> -        av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n",
> -               ctx->name, av_err2str(ret));
> +        if (ret != AVERROR(EAGAIN))
> +            av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n",
> +                   ctx->name, av_err2str(ret));
>          return ret;
>      }
>  
> @@ -238,26 +240,47 @@ static int filter_query_formats(AVFilterContext *ctx)
>      return 0;
>  }
>  
> +static int formats_declared(AVFilterContext *f)
> +{
> +    int i;
> +
> +    for (i = 0; i < f->nb_inputs; i++) {
> +        if (!f->inputs[i]->out_formats)
> +            return 0;
> +        if (f->inputs[i]->type == AVMEDIA_TYPE_AUDIO &&
> +            !(f->inputs[i]->out_samplerates &&
> +              f->inputs[i]->out_channel_layouts))
> +            return 0;
> +    }
> +    for (i = 0; i < f->nb_outputs; i++) {
> +        if (!f->outputs[i]->in_formats)
> +            return 0;
> +        if (f->outputs[i]->type == AVMEDIA_TYPE_AUDIO &&
> +            !(f->outputs[i]->in_samplerates &&
> +              f->outputs[i]->in_channel_layouts))
> +            return 0;
> +    }
> +    return 1;
> +}
> +
>  static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>  {
>      int i, j, ret;
>      int scaler_count = 0, resampler_count = 0;
> +    int count_query = 0, count_merged = 0, count_already_merged = 0,

nit: "count_queried" for grammatical consistency

> +        count_delayed = 0;
>  
> -    for (j = 0; j < 2; j++) {
> -    /* ask all the sub-filters for their supported media formats */
>      for (i = 0; i < graph->nb_filters; i++) {
> -        /* Call query_formats on sources first.
> -           This is a temporary workaround for amerge,
> -           until format renegociation is implemented. */
> -        if (!graph->filters[i]->nb_inputs == j)
> +        AVFilterContext *f = graph->filters[i];
> +        if (formats_declared(f))
>              continue;
> -        if (graph->filters[i]->filter->query_formats)
> -            ret = filter_query_formats(graph->filters[i]);
> +        if (f->filter->query_formats)
> +            ret = filter_query_formats(f);
>          else
> -            ret = ff_default_query_formats(graph->filters[i]);
> -        if (ret < 0)
> +            ret = ff_default_query_formats(f);
> +        if (ret < 0 && ret != AVERROR(EAGAIN))
>              return ret;
> -    }
> +        count_query++;
>      }
>  
>      /* go through and merge as many format lists as possible */
> @@ -271,20 +294,33 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>              if (!link)
>                  continue;
>  
> -            if (link->in_formats != link->out_formats &&
> -                !ff_merge_formats(link->in_formats, link->out_formats,
> -                                  link->type))
> -                convert_needed = 1;
> -            if (link->type == AVMEDIA_TYPE_AUDIO) {
> -                if (link->in_channel_layouts != link->out_channel_layouts &&
> -                    !ff_merge_channel_layouts(link->in_channel_layouts,
> -                                              link->out_channel_layouts))
> -                    convert_needed = 1;
> -                if (link->in_samplerates != link->out_samplerates &&
> -                    !ff_merge_samplerates(link->in_samplerates,
> -                                          link->out_samplerates))
> +#define MERGE_DISPATCH(field, statement)                                     \
> +            if (!(link->in_ ## field && link->out_ ## field)) {              \
> +                count_delayed++;                                             \
> +            } else if (link->in_ ## field == link->out_ ## field) {          \
> +                count_already_merged++;                                      \
> +            } else {                                                         \
> +                count_merged++;                                              \
> +                statement                                                    \
> +            }
> +            MERGE_DISPATCH(formats,
> +                if (!ff_merge_formats(link->in_formats, link->out_formats,
> +                                      link->type))
>                      convert_needed = 1;
> +            )
> +            if (link->type == AVMEDIA_TYPE_AUDIO) {
> +                MERGE_DISPATCH(channel_layouts,
> +                    if (!ff_merge_channel_layouts(link->in_channel_layouts,
> +                                                  link->out_channel_layouts))
> +                        convert_needed = 1;
> +                )
> +                MERGE_DISPATCH(samplerates,
> +                    if (!ff_merge_samplerates(link->in_samplerates,
> +                                              link->out_samplerates))
> +                        convert_needed = 1;
> +                )
>              }
> +#undef MERGE_DISPATCH
>  
>              if (convert_needed) {
>                  AVFilterContext *convert;
> @@ -368,6 +404,25 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>          }
>      }
>  
> +    av_log(graph, AV_LOG_DEBUG, "query_formats: "
> +           "%d queried, %d merged, %d already done, %d delayed\n",
> +           count_query, count_merged, count_already_merged, count_delayed);
> +    if (count_delayed) {
> +        AVBPrint bp;
> +
> +        if (count_query || count_merged)
> +            return AVERROR(EAGAIN);
> +        av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
> +        for (i = 0; i < graph->nb_filters; i++)
> +            if (!formats_declared(graph->filters[i]))
> +                av_bprintf(&bp, "%s%s", bp.len ? ", " : "",
> +                          graph->filters[i]->name);
> +        av_log(graph, AV_LOG_ERROR,
> +               "The following filters could not choose their formats: %s\n"
> +               "Consider inserting the (a)format filter near their input or "
> +               "output.\n", bp.str);

> +        return AVERROR(EIO);

Still looks a weird error code but not blocking.

> +    }
>      return 0;
>  }
>  
> @@ -831,7 +886,9 @@ static int graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
>      int ret;
>  
>      /* find supported formats from sub-filters, and merge along links */
> -    if ((ret = query_formats(graph, log_ctx)) < 0)
> +    while ((ret = query_formats(graph, log_ctx)) == AVERROR(EAGAIN))
> +        av_log(graph, AV_LOG_DEBUG, "query_formats not finished\n");
> +    if (ret < 0)
>          return ret;

LGTM otherwise, thanks.
-- 
FFmpeg = Fierce and Forgiving Multimedia Proud Earthshaking Gem


More information about the ffmpeg-devel mailing list