From: yangyalei <269032...@qq.com> 1. Support reuse the graph to play different audio. 2. Support config part of the graph.
Signed-off-by: yangyalei <269032...@qq.com> --- libavfilter/avfilter.c | 8 +- libavfilter/avfilter.h | 9 ++ libavfilter/avfiltergraph.c | 217 +++++++++++++++++++++++++++++++++--- 3 files changed, 215 insertions(+), 19 deletions(-) diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index e732556ffa..71396674fe 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -345,7 +345,8 @@ int ff_filter_config_links(AVFilterContext *filter) FilterLinkInternal *li = ff_link_internal(link); FilterLinkInternal *li_in; - if (!link) continue; + if (!link || !link->incfg.formats || !link->outcfg.formats) + continue; if (!link->src || !link->dst) { av_log(filter, AV_LOG_ERROR, "Not all input and output are properly linked (%d).\n", i); @@ -359,6 +360,11 @@ int ff_filter_config_links(AVFilterContext *filter) switch (li->init_state) { case AVLINK_INIT: + /* for part graph re-negotiation. + * For example: output-filter link has config_props, + * but the input-filter still need config_props. */ + if ((ret = ff_filter_config_links(link->src)) < 0) + return ret; continue; case AVLINK_STARTINIT: av_log(filter, AV_LOG_INFO, "circular filter chain detected\n"); diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index 4520d5f978..9727b14231 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -715,6 +715,15 @@ enum { */ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx); +/** + * Check validity and reconfigure all the links and formats in the graph. + * + * @param graphctx the filter graph + * @param log_ctx context used for logging + * @return >= 0 in case of success, a negative AVERROR code otherwise + */ +int ff_avfilter_graph_reconfig(AVFilterGraph *graphctx, void *log_ctx); + /** * Free a graph, destroy its links, and set *graph to NULL. * If *graph is NULL, do nothing. diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 5e93f93aab..1758e87d63 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -23,6 +23,7 @@ #include "config.h" #include <string.h> +#include <stdbool.h> #include "libavutil/avassert.h" #include "libavutil/bprint.h" @@ -348,7 +349,7 @@ static int filter_query_formats(AVFilterContext *ctx) if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC) { if ((ret = filter->formats.query_func(ctx)) < 0) { - if (ret != AVERROR(EAGAIN)) + if (ret != AVERROR(EAGAIN) && ret != FFERROR_NOT_READY) av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n", ctx->name, av_err2str(ret)); return ret; @@ -390,7 +391,7 @@ static int filter_query_formats(AVFilterContext *ctx) av_freep(&cfg_in_dyn); av_freep(&cfg_out_dyn); if (ret < 0) { - if (ret != AVERROR(EAGAIN)) + if (ret != AVERROR(EAGAIN) && ret != FFERROR_NOT_READY) av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n", ctx->name, av_err2str(ret)); return ret; @@ -438,6 +439,85 @@ static int formats_declared(AVFilterContext *f) return 1; } +void ff_avfilter_link_unref_formats(AVFilterLink *link) +{ + ff_formats_unref(&link->incfg.formats); + ff_formats_unref(&link->outcfg.formats); + ff_formats_unref(&link->incfg.samplerates); + ff_formats_unref(&link->outcfg.samplerates); + ff_channel_layouts_unref(&link->incfg.channel_layouts); + ff_channel_layouts_unref(&link->outcfg.channel_layouts); +} + +static bool formats_useless(AVFilterContext *f) +{ + bool in, out; + int i; + + if (!f->nb_inputs || !f->nb_outputs) + return false; + + in = out = true; + + for (i = 0; i < f->nb_inputs; i++) + if (f->inputs[i]->outcfg.formats) { + in = false; + break; + } + + for (i = 0; i < f->nb_outputs; i++) + if (f->outputs[i]->incfg.formats) { + out = false; + break; + } + + if (!strcmp(f->name, "amix@a2dp")) { + av_log(f, AV_LOG_ERROR, "check amix@a2dp, in:%d, out:%d, ret:%d\n", in, out, in ^ out); + } + + return in ^ out; +} + + +static bool sanitize_formats(AVFilterGraph *graph) +{ + AVFilterContext *f; + bool changed = false; + unsigned i, j; + + for (i = 0; i < graph->nb_filters; i++) { + f = graph->filters[i]; + + for (j = 0; j < f->nb_inputs; j++) { + if ((!f->inputs[j]->outcfg.formats && f->inputs[j]->incfg.formats) + || (f->inputs[j]->outcfg.formats && !f->inputs[j]->incfg.formats)) { + ff_avfilter_link_unref_formats(f->inputs[j]); + changed = true; + } + } + + for (j = 0; j < f->nb_outputs; j++) { + if ((!f->outputs[j]->incfg.formats && f->outputs[j]->outcfg.formats) + || (f->outputs[j]->incfg.formats && !f->outputs[j]->outcfg.formats)) { + ff_avfilter_link_unref_formats(f->outputs[j]); + changed = true; + } + } + + if (formats_useless(f)) { + for (j = 0; j < f->nb_inputs; j++) + ff_avfilter_link_unref_formats(f->inputs[j]); + + for (j = 0; j < f->nb_outputs; j++) + ff_avfilter_link_unref_formats(f->outputs[j]); + + changed = true; + } + } + + return changed; +} + /** * Perform one round of query_formats() and merging formats lists on the * filter graph. @@ -462,12 +542,14 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) if (formats_declared(f)) continue; ret = filter_query_formats(f); - if (ret < 0 && ret != AVERROR(EAGAIN)) + if (ret < 0 && ret != AVERROR(EAGAIN) && ret != FFERROR_NOT_READY) return ret; /* note: EAGAIN could indicate a partial success, not counted yet */ count_queried += ret >= 0; } + while (sanitize_formats(graph)); + /* go through and merge as many format lists as possible */ for (i = 0; i < graph->nb_filters; i++) { AVFilterContext *filter = graph->filters[i]; @@ -478,7 +560,7 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) unsigned neg_step; int convert_needed = 0; - if (!link) + if (!link || !link->incfg.formats) continue; neg = ff_filter_get_negotiation(link); @@ -492,6 +574,7 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx) break; } } + for (neg_step = 0; neg_step < neg->nb_mergers; neg_step++) { const AVFilterFormatsMerger *m = &neg->mergers[neg_step]; void *a = FF_FIELD_AT(void *, m->offset, link->incfg); @@ -789,17 +872,6 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) return ret; } - ff_formats_unref(&link->incfg.formats); - ff_formats_unref(&link->outcfg.formats); - ff_formats_unref(&link->incfg.samplerates); - ff_formats_unref(&link->outcfg.samplerates); - ff_channel_layouts_unref(&link->incfg.channel_layouts); - ff_channel_layouts_unref(&link->outcfg.channel_layouts); - ff_formats_unref(&link->incfg.color_spaces); - ff_formats_unref(&link->outcfg.color_spaces); - ff_formats_unref(&link->incfg.color_ranges); - ff_formats_unref(&link->outcfg.color_ranges); - return 0; } @@ -818,6 +890,7 @@ do { \ list_type *fmts; \ \ if (link->type != out_link->type || \ + !out_link->incfg.list || \ out_link->incfg.list->nb == 1) \ continue; \ fmts = out_link->incfg.list; \ @@ -925,6 +998,7 @@ static void swap_samplerates_on_filter(AVFilterContext *filter) link = filter->inputs[i]; if (link->type == AVMEDIA_TYPE_AUDIO && + link->outcfg.samplerates && link->outcfg.samplerates->nb_formats== 1) break; } @@ -938,6 +1012,7 @@ static void swap_samplerates_on_filter(AVFilterContext *filter) int best_idx, best_diff = INT_MAX; if (outlink->type != AVMEDIA_TYPE_AUDIO || + !outlink->incfg.samplerates || outlink->incfg.samplerates->nb_formats < 2) continue; @@ -1007,6 +1082,7 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) link = filter->inputs[i]; if (link->type == AVMEDIA_TYPE_AUDIO && + link->outcfg.channel_layouts && link->outcfg.channel_layouts->nb_channel_layouts == 1) break; } @@ -1018,6 +1094,7 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) int best_idx = -1, best_score = INT_MIN, best_count_diff = INT_MAX; if (outlink->type != AVMEDIA_TYPE_AUDIO || + !outlink->incfg.channel_layouts || outlink->incfg.channel_layouts->nb_channel_layouts < 2) continue; @@ -1110,6 +1187,7 @@ static void swap_sample_fmts_on_filter(AVFilterContext *filter) link = filter->inputs[i]; if (link->type == AVMEDIA_TYPE_AUDIO && + link->outcfg.formats && link->outcfg.formats->nb_formats == 1) break; } @@ -1124,6 +1202,7 @@ static void swap_sample_fmts_on_filter(AVFilterContext *filter) int best_idx = -1, best_score = INT_MIN; if (outlink->type != AVMEDIA_TYPE_AUDIO || + !outlink->incfg.formats || outlink->incfg.formats->nb_formats < 2) continue; @@ -1180,7 +1259,8 @@ static int pick_formats(AVFilterGraph *graph) AVFilterContext *filter = graph->filters[i]; if (filter->nb_inputs){ for (j = 0; j < filter->nb_inputs; j++){ - if (filter->inputs[j]->incfg.formats && filter->inputs[j]->incfg.formats->nb_formats == 1) { + if (filter->inputs[j]->format < 0 && + filter->inputs[j]->incfg.formats && filter->inputs[j]->incfg.formats->nb_formats == 1) { if ((ret = pick_format(filter->inputs[j], NULL)) < 0) return ret; change = 1; @@ -1189,7 +1269,8 @@ static int pick_formats(AVFilterGraph *graph) } if (filter->nb_outputs){ for (j = 0; j < filter->nb_outputs; j++){ - if (filter->outputs[j]->incfg.formats && filter->outputs[j]->incfg.formats->nb_formats == 1) { + if (filter->outputs[j]->format < 0 && + filter->outputs[j]->incfg.formats && filter->outputs[j]->incfg.formats->nb_formats == 1) { if ((ret = pick_format(filter->outputs[j], NULL)) < 0) return ret; change = 1; @@ -1198,7 +1279,7 @@ static int pick_formats(AVFilterGraph *graph) } if (filter->nb_inputs && filter->nb_outputs && filter->inputs[0]->format>=0) { for (j = 0; j < filter->nb_outputs; j++) { - if (filter->outputs[j]->format<0) { + if (filter->outputs[j]->format < 0 && filter->outputs[j]->incfg.formats) { if ((ret = pick_format(filter->outputs[j], filter->inputs[0])) < 0) return ret; change = 1; @@ -1292,6 +1373,82 @@ static int graph_config_pointers(AVFilterGraph *graph, void *log_ctx) return 0; } +static void graph_clear_formats(AVFilterGraph *graph, void *log_ctx) +{ + int status_in, status_out; + AVRational time_base; + AVFilterContext *f; + FilterLinkInternal *ilinki; + FilterLinkInternal *olinki; + int i, j; + + for (i = graph->nb_filters - 1; i >= 0; i--) { + f = graph->filters[i]; + + if (!strncmp(f->name, "auto_", strlen("auto_"))) { + ilinki = ff_link_internal(f->inputs[0]); + olinki = ff_link_internal(f->outputs[0]); + if (ilinki->status_out || ilinki->status_in || + olinki->status_out || olinki->status_in) { + AVFilterContext *src = f->inputs[0]->src; + AVFilterContext *dst = f->outputs[0]->dst; + unsigned srcpad = FF_OUTLINK_IDX(f->inputs[0]); + unsigned dstpad = FF_INLINK_IDX(f->outputs[0]); + + status_in = ilinki->status_in; + status_out = ilinki->status_out; + time_base = f->inputs[0]->time_base; + + avfilter_free(f); + avfilter_link(src, srcpad, dst, dstpad); + + olinki->status_in = status_in; + olinki->status_out = status_out; + dst->inputs[0]->time_base = time_base; + + ff_filter_set_ready(dst, 200); + continue; + } + } + + for (j = 0; j < f->nb_inputs; j++) { + ilinki = ff_link_internal(f->inputs[j]); + if (ilinki->status_out) { + ff_formats_unref(&f->inputs[j]->outcfg.formats); + ff_formats_unref(&f->inputs[j]->outcfg.samplerates); + ff_channel_layouts_unref(&f->inputs[j]->outcfg.channel_layouts); + + if (ilinki->status_in) { + f->inputs[j]->format = -1; + f->inputs[j]->sample_rate = 0; + ilinki->init_state = AVLINK_UNINIT; + f->inputs[j]->time_base.num = 0; + f->inputs[j]->time_base.den = 0; + av_channel_layout_uninit(&f->inputs[j]->ch_layout); + } + } + } + + for (j = 0; j < f->nb_outputs; j++) { + olinki = ff_link_internal(f->outputs[j]); + if (olinki->status_in) { + ff_formats_unref(&f->outputs[j]->incfg.formats); + ff_formats_unref(&f->outputs[j]->incfg.samplerates); + ff_channel_layouts_unref(&f->outputs[j]->incfg.channel_layouts); + + if (olinki->status_out) { + f->outputs[j]->format = -1; + f->outputs[j]->sample_rate = 0; + olinki->init_state = AVLINK_UNINIT; + f->outputs[j]->time_base.num = 0; + f->outputs[j]->time_base.den = 0; + av_channel_layout_uninit(&f->outputs[j]->ch_layout); + } + } + } + } +} + int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) { int ret; @@ -1310,6 +1467,30 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) return 0; } +int ff_avfilter_graph_reconfig(AVFilterGraph *graphctx, void *log_ctx) +{ + AVClass *avc = log_ctx ? *(AVClass **)log_ctx : NULL; + int ret, i; + + if (avc) + av_log(log_ctx, AV_LOG_INFO, "%s set graph reconfig\n", avc->item_name(log_ctx)); + + for (i = 0; i < graphctx->nb_filters; i++) + av_log(log_ctx, AV_LOG_INFO, "\t%s", graphctx->filters[i]->name); + + graph_clear_formats(graphctx, log_ctx); + if ((ret = graph_config_formats(graphctx, log_ctx))) + return ret; + if ((ret = graph_config_links(graphctx, log_ctx))) + return ret; + if ((ret = graph_check_links(graphctx, log_ctx))) + return ret; + if ((ret = graph_config_pointers(graphctx, log_ctx))) + return ret; + + return 0; +} + int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags) { int i, r = AVERROR(ENOSYS); -- 2.47.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".