[FFmpeg-devel] [PATCH 3/3] lavfi: support multiple rounds of format negotiation.
Stefano Sabatini
stefasab at gmail.com
Sun Mar 24 00:27:19 CET 2013
On date Thursday 2013-02-21 20:44:15 +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 | 103 ++++++++++++++++++++++++++++++++-----------
> 2 files changed, 83 insertions(+), 25 deletions(-)
>
>
> The logic is this: the query_formats() function will fail with
> AVERROR(EINVAL) if some filters could not be configured yet but progress was
Do you mean AVERROR(EAGAIN)?
> made, and the calling site will loop on that condition. It is as simple as
> that, all the noise in the diff is mostly connected to making sure that
> filters are not configured twice (most of them would cause crashes).
>
> I believe that with this feature, overlay can peek at its inputs supported
> formats (and possibly output too) and decide automatically between the
> yuv420/yuv444/rgb mode.
>
> Note that that feature must be used parsimoniously, because the mode filters
> use it, the more likely it is that the process will fail because of a
> circular dependency.
>
[...]
> @@ -238,27 +240,46 @@ static int filter_query_formats(AVFilterContext *ctx)
> return 0;
> }
>
> +static int formats_queried(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 merge_done = 0, merge_already = 0, merge_delayed = 0;
I suggest: merge_already -> merge_already_done
>
> - for (j = 0; j < 2; j++) {
> - /* ask all the sub-filters for their supported media formats */
> for (i = 0; i < graph->filter_count; 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_queried(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;
> }
> - }
>
> /* go through and merge as many format lists as possible */
> for (i = 0; i < graph->filter_count; i++) {
> @@ -271,20 +292,32 @@ 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))
> - convert_needed = 1;
> +#define MERGE_DISPATCH(field, statement) \
> + if (!(link->in_ ## field && link->out_ ## field)) { \
> + merge_delayed++; \
> + } else if (link->in_ ## field == link->out_ ## field) { \
> + merge_already++; \
> + } else { \
> + merge_done++; \
> + statement \
> + }
> + MERGE_DISPATCH(formats,
> + if (!ff_merge_formats(link->in_formats, link->out_formats))
> + 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,
> + MERGE_DISPATCH(channel_layouts,
> + if (!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))
> - convert_needed = 1;
> + 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;
> @@ -363,6 +396,24 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
> }
> }
>
> + av_log(graph, AV_LOG_DEBUG,
> + "query_formats: %d done, %d already, %d delayed\n",
> + merge_done, merge_already, merge_delayed);
> + if (merge_delayed) {
> + AVBPrint bp;
> +
> + if (merge_done)
> + return AVERROR(EAGAIN);
> + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
> + for (i = 0; i < graph->filter_count; i++)
> + if (!formats_queried(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.\n", bp.str);
> + return AVERROR(EIO);
> + }
Looks good from a second reading apart from the nits, thanks.
--
FFmpeg = Fascinating Faithless Multipurpose Pacific Educated Goblin
More information about the ffmpeg-devel
mailing list