OSDN Git Service

Merge commit '42c7c61ab25809620b8c8809b3da73e25f5bbaaf'
authorMichael Niedermayer <michaelni@gmx.at>
Sat, 16 Mar 2013 15:09:37 +0000 (16:09 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 16 Mar 2013 15:09:37 +0000 (16:09 +0100)
* commit '42c7c61ab25809620b8c8809b3da73e25f5bbaaf':
  avfiltergraph: replace AVFilterGraph.filter_count with nb_filters

Conflicts:
doc/APIchanges
libavfilter/avfiltergraph.c
libavfilter/avfiltergraph.h
libavfilter/graphparser.c
libavfilter/version.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
doc/APIchanges
libavfilter/avfiltergraph.c
libavfilter/avfiltergraph.h
libavfilter/graphdump.c
libavfilter/graphparser.c
libavfilter/version.h
tools/graph2dot.c

diff --cc doc/APIchanges
@@@ -15,135 -13,9 +15,138 @@@ libavutil:     2012-10-2
  
  API changes, most recent first:
  
 +2013-03-07 - xxxxxx - lavu 52.18.100 - avstring.h,bprint.h
 +  Add av_escape() and av_bprint_escape() API.
 +
 +2013-02-24 - xxxxxx - lavfi 3.41.100 - buffersink.h
 +  Add sample_rates field to AVABufferSinkParams.
 +
 +2013-01-17 - a1a707f - lavf 54.61.100
 +  Add av_codec_get_tag2().
 +
 +2013-01-01 - 2eb2e17 - lavfi 3.34.100
 +  Add avfilter_get_audio_buffer_ref_from_arrays_channels.
 +
 +2012-12-20 - 34de47aa - lavfi 3.29.100 - avfilter.h
 +  Add AVFilterLink.channels, avfilter_link_get_channels()
 +  and avfilter_ref_get_channels().
 +
 +2012-12-15 - 2ada584d - lavc 54.80.100 - avcodec.h
 +  Add pkt_size field to AVFrame.
 +
 +2012-11-25 - c70ec631 - lavu 52.9.100 - opt.h
 +  Add the following convenience functions to opt.h:
 +   av_opt_get_image_size
 +   av_opt_get_pixel_fmt
 +   av_opt_get_sample_fmt
 +   av_opt_set_image_size
 +   av_opt_set_pixel_fmt
 +   av_opt_set_sample_fmt
 +
 +2012-11-17 - 4cd74c81 - lavu 52.8.100 - bprint.h
 +  Add av_bprint_strftime().
 +
 +2012-11-15 - 92648107 - lavu 52.7.100 - opt.h
 +  Add av_opt_get_key_value().
 +
 +2012-11-13 - 79456652 - lavfi 3.23.100 - avfilter.h
 +  Add channels field to AVFilterBufferRefAudioProps.
 +
 +2012-11-03 - 481fdeee - lavu 52.3.100 - opt.h
 +  Add AV_OPT_TYPE_SAMPLE_FMT value to AVOptionType enum.
 +
 +2012-10-21 - 6fb2fd8 - lavc  54.68.100 - avcodec.h
 +                       lavfi  3.20.100 - avfilter.h
 +  Add AV_PKT_DATA_STRINGS_METADATA side data type, used to transmit key/value
 +  strings between AVPacket and AVFrame, and add metadata field to
 +  AVCodecContext (which shall not be accessed by users; see AVFrame metadata
 +  instead).
 +
 +2012-09-27 - a70b493 - lavd 54.3.100 - version.h
 +  Add LIBAVDEVICE_IDENT symbol.
 +
 +2012-09-27 - a70b493 - lavfi 3.18.100 - version.h
 +  Add LIBAVFILTER_IDENT symbol.
 +
 +2012-09-27 - a70b493 - libswr 0.16.100 - version.h
 +  Add LIBSWRESAMPLE_VERSION, LIBSWRESAMPLE_BUILD
 +  and LIBSWRESAMPLE_IDENT symbols.
 +
 +2012-09-06 - 29e972f - lavu 51.72.100 - parseutils.h
 +  Add av_small_strptime() time parsing function.
 +
 +  Can be used as a stripped-down replacement for strptime(), on
 +  systems which do not support it.
 +
 +2012-08-25 - 2626cc4 - lavf 54.28.100
 +  Matroska demuxer now identifies SRT subtitles as AV_CODEC_ID_SUBRIP instead
 +  of AV_CODEC_ID_TEXT.
 +
 +2012-08-13 - 5c0d8bc - lavfi 3.8.100 - avfilter.h
 +  Add avfilter_get_class() function, and priv_class field to AVFilter
 +  struct.
 +
 +2012-08-12 - a25346e - lavu 51.69.100 - opt.h
 +  Add AV_OPT_FLAG_FILTERING_PARAM symbol in opt.h.
 +
 +2012-07-31 - 23fc4dd - lavc 54.46.100
 +  Add channels field to AVFrame.
 +
 +2012-07-30 - f893904 - lavu 51.66.100
 +  Add av_get_channel_description()
 +  and av_get_standard_channel_layout() functions.
 +
 +2012-07-21 - 016a472 - lavc 54.43.100
 +  Add decode_error_flags field to AVFrame.
 +
 +2012-07-20 - b062936 - lavf 54.18.100
 +  Add avformat_match_stream_specifier() function.
 +
 +2012-07-14 - f49ec1b - lavc 54.38.100 - avcodec.h
 +  Add metadata to AVFrame, and the accessor functions
 +  av_frame_get_metadata() and av_frame_set_metadata().
 +
 +2012-07-10 - 0e003d8 - lavc 54.33.100
 +  Add av_fast_padded_mallocz().
 +
 +2012-07-10 - 21d5609 - lavfi 3.2.0 - avfilter.h
 +  Add init_opaque() callback to AVFilter struct.
 +
 +2012-06-26 - e6674e4 - lavu 51.63.100 - imgutils.h
 +  Add functions to libavutil/imgutils.h:
 +  av_image_get_buffer_size()
 +  av_image_fill_arrays()
 +  av_image_copy_to_buffer()
 +
 +2012-06-24 - c41899a - lavu 51.62.100 - version.h
 +  version moved from avutil.h to version.h
 +
 +2012-04-11 - 359abb1 - lavu 51.58.100 - error.h
 +  Add av_make_error_string() and av_err2str() utilities to
 +  libavutil/error.h.
 +
 +2012-06-05 - 62b39d4 - lavc 54.24.100
 +  Add pkt_duration field to AVFrame.
 +
 +2012-05-24 - f2ee065 - lavu 51.54.100
 +  Move AVPALETTE_SIZE and AVPALETTE_COUNT macros from
 +  libavcodec/avcodec.h to libavutil/pixfmt.h.
 +
 +2012-05-14 - 94a9ac1 - lavf 54.5.100
 +  Add av_guess_sample_aspect_ratio() function.
 +
 +2012-04-20 - 65fa7bc - lavfi 2.70.100
 +  Add avfilter_unref_bufferp() to avfilter.h.
 +
 +2012-04-13 - 162e400 - lavfi 2.68.100
 +  Install libavfilter/asrc_abuffer.h public header.
 +
 +2012-03-26 - a67d9cf - lavfi 2.66.100
 +  Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions.
 +
+ 2013-xx-xx - lavfi 3.6.0
+   Add AVFilterGraph.nb_filters, deprecate AVFilterGraph.filter_count.
  2013-03-xx - Reference counted buffers - lavu 52.8.0, lavc 55.0.0, lavf 55.0.0,
  lavd 54.0.0, lavfi 3.5.0
    xxxxxxx, xxxxxxx - add a new API for reference counted buffers and buffer
@@@ -62,11 -50,9 +62,11 @@@ void avfilter_graph_free(AVFilterGraph 
  {
      if (!*graph)
          return;
-     for (; (*graph)->filter_count > 0; (*graph)->filter_count--)
-         avfilter_free((*graph)->filters[(*graph)->filter_count - 1]);
+     for (; (*graph)->nb_filters > 0; (*graph)->nb_filters--)
+         avfilter_free((*graph)->filters[(*graph)->nb_filters - 1]);
 +    av_freep(&(*graph)->sink_links);
      av_freep(&(*graph)->scale_sws_opts);
 +    av_freep(&(*graph)->aresample_swr_opts);
      av_freep(&(*graph)->resample_lavr_opts);
      av_freep(&(*graph)->filters);
      av_freep(graph);
@@@ -124,8 -105,7 +124,8 @@@ static int graph_check_validity(AVFilte
      AVFilterContext *filt;
      int i, j;
  
-     for (i = 0; i < graph->filter_count; i++) {
+     for (i = 0; i < graph->nb_filters; i++) {
 +        const AVFilterPad *pad;
          filt = graph->filters[i];
  
          for (j = 0; j < filt->nb_inputs; j++) {
@@@ -243,21 -168,12 +243,21 @@@ static int query_formats(AVFilterGraph 
      int i, j, ret;
      int scaler_count = 0, resampler_count = 0;
  
 +    for (j = 0; j < 2; j++) {
      /* ask all the sub-filters for their supported media formats */
-     for (i = 0; i < graph->filter_count; i++) {
+     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)
 +            continue;
          if (graph->filters[i]->filter->query_formats)
 -            graph->filters[i]->filter->query_formats(graph->filters[i]);
 +            ret = filter_query_formats(graph->filters[i]);
          else
 -            ff_default_query_formats(graph->filters[i]);
 +            ret = ff_default_query_formats(graph->filters[i]);
 +        if (ret < 0)
 +            return ret;
 +    }
      }
  
      /* go through and merge as many format lists as possible */
@@@ -774,43 -616,8 +774,43 @@@ static void swap_sample_fmts(AVFilterGr
  static int pick_formats(AVFilterGraph *graph)
  {
      int i, j, ret;
-         for (i = 0; i < graph->filter_count; i++) {
 +    int change;
 +
 +    do{
 +        change = 0;
++        for (i = 0; i < graph->nb_filters; i++) {
 +            AVFilterContext *filter = graph->filters[i];
 +            if (filter->nb_inputs){
 +                for (j = 0; j < filter->nb_inputs; j++){
 +                    if(filter->inputs[j]->in_formats && filter->inputs[j]->in_formats->format_count == 1) {
 +                        if ((ret = pick_format(filter->inputs[j], NULL)) < 0)
 +                            return ret;
 +                        change = 1;
 +                    }
 +                }
 +            }
 +            if (filter->nb_outputs){
 +                for (j = 0; j < filter->nb_outputs; j++){
 +                    if(filter->outputs[j]->in_formats && filter->outputs[j]->in_formats->format_count == 1) {
 +                        if ((ret = pick_format(filter->outputs[j], NULL)) < 0)
 +                            return ret;
 +                        change = 1;
 +                    }
 +                }
 +            }
 +            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 ((ret = pick_format(filter->outputs[j], filter->inputs[0])) < 0)
 +                            return ret;
 +                        change = 1;
 +                    }
 +                }
 +            }
 +        }
 +    }while(change);
  
-     for (i = 0; i < graph->filter_count; i++) {
+     for (i = 0; i < graph->nb_filters; i++) {
          AVFilterContext *filter = graph->filters[i];
  
          for (j = 0; j < filter->nb_inputs; j++)
@@@ -851,48 -658,6 +851,48 @@@ static int graph_config_formats(AVFilte
      return 0;
  }
  
-     for (i = 0; i < graph->filter_count; i++) {
 +static int ff_avfilter_graph_config_pointers(AVFilterGraph *graph,
 +                                             AVClass *log_ctx)
 +{
 +    unsigned i, j;
 +    int sink_links_count = 0, n = 0;
 +    AVFilterContext *f;
 +    AVFilterLink **sinks;
 +
-     for (i = 0; i < graph->filter_count; i++) {
++    for (i = 0; i < graph->nb_filters; i++) {
 +        f = graph->filters[i];
 +        for (j = 0; j < f->nb_inputs; j++) {
 +            f->inputs[j]->graph     = graph;
 +            f->inputs[j]->age_index = -1;
 +        }
 +        for (j = 0; j < f->nb_outputs; j++) {
 +            f->outputs[j]->graph    = graph;
 +            f->outputs[j]->age_index= -1;
 +        }
 +        if (!f->nb_outputs) {
 +            if (f->nb_inputs > INT_MAX - sink_links_count)
 +                return AVERROR(EINVAL);
 +            sink_links_count += f->nb_inputs;
 +        }
 +    }
 +    sinks = av_calloc(sink_links_count, sizeof(*sinks));
 +    if (!sinks)
 +        return AVERROR(ENOMEM);
++    for (i = 0; i < graph->nb_filters; i++) {
 +        f = graph->filters[i];
 +        if (!f->nb_outputs) {
 +            for (j = 0; j < f->nb_inputs; j++) {
 +                sinks[n] = f->inputs[j];
 +                f->inputs[j]->age_index = n++;
 +            }
 +        }
 +    }
 +    av_assert0(n == sink_links_count);
 +    graph->sink_links       = sinks;
 +    graph->sink_links_count = sink_links_count;
 +    return 0;
 +}
 +
  static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx)
  {
      AVFilterContext *f;
@@@ -948,126 -711,3 +948,126 @@@ int avfilter_graph_config(AVFilterGrap
  
      return 0;
  }
-     for (i = 0; i < graph->filter_count; i++) {
 +
 +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);
 +
 +    if(!graph)
 +        return r;
 +
 +    if((flags & AVFILTER_CMD_FLAG_ONE) && !(flags & AVFILTER_CMD_FLAG_FAST)) {
 +        r=avfilter_graph_send_command(graph, target, cmd, arg, res, res_len, flags | AVFILTER_CMD_FLAG_FAST);
 +        if(r != AVERROR(ENOSYS))
 +            return r;
 +    }
 +
 +    if(res_len && res)
 +        res[0]= 0;
 +
-     for (i = 0; i < graph->filter_count; i++) {
++    for (i = 0; i < graph->nb_filters; i++) {
 +        AVFilterContext *filter = graph->filters[i];
 +        if(!strcmp(target, "all") || (filter->name && !strcmp(target, filter->name)) || !strcmp(target, filter->filter->name)){
 +            r = avfilter_process_command(filter, cmd, arg, res, res_len, flags);
 +            if(r != AVERROR(ENOSYS)) {
 +                if((flags & AVFILTER_CMD_FLAG_ONE) || r<0)
 +                    return r;
 +            }
 +        }
 +    }
 +
 +    return r;
 +}
 +
 +int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const char *command, const char *arg, int flags, double ts)
 +{
 +    int i;
 +
 +    if(!graph)
 +        return 0;
 +
++    for (i = 0; i < graph->nb_filters; i++) {
 +        AVFilterContext *filter = graph->filters[i];
 +        if(filter && (!strcmp(target, "all") || !strcmp(target, filter->name) || !strcmp(target, filter->filter->name))){
 +            AVFilterCommand **queue = &filter->command_queue, *next;
 +            while (*queue && (*queue)->time <= ts)
 +                queue = &(*queue)->next;
 +            next = *queue;
 +            *queue = av_mallocz(sizeof(AVFilterCommand));
 +            (*queue)->command = av_strdup(command);
 +            (*queue)->arg     = av_strdup(arg);
 +            (*queue)->time    = ts;
 +            (*queue)->flags   = flags;
 +            (*queue)->next    = next;
 +            if(flags & AVFILTER_CMD_FLAG_ONE)
 +                return 0;
 +        }
 +    }
 +
 +    return 0;
 +}
 +
 +static void heap_bubble_up(AVFilterGraph *graph,
 +                           AVFilterLink *link, int index)
 +{
 +    AVFilterLink **links = graph->sink_links;
 +
 +    while (index) {
 +        int parent = (index - 1) >> 1;
 +        if (links[parent]->current_pts >= link->current_pts)
 +            break;
 +        links[index] = links[parent];
 +        links[index]->age_index = index;
 +        index = parent;
 +    }
 +    links[index] = link;
 +    link->age_index = index;
 +}
 +
 +static void heap_bubble_down(AVFilterGraph *graph,
 +                             AVFilterLink *link, int index)
 +{
 +    AVFilterLink **links = graph->sink_links;
 +
 +    while (1) {
 +        int child = 2 * index + 1;
 +        if (child >= graph->sink_links_count)
 +            break;
 +        if (child + 1 < graph->sink_links_count &&
 +            links[child + 1]->current_pts < links[child]->current_pts)
 +            child++;
 +        if (link->current_pts < links[child]->current_pts)
 +            break;
 +        links[index] = links[child];
 +        links[index]->age_index = index;
 +        index = child;
 +    }
 +    links[index] = link;
 +    link->age_index = index;
 +}
 +
 +void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link)
 +{
 +    heap_bubble_up  (graph, link, link->age_index);
 +    heap_bubble_down(graph, link, link->age_index);
 +}
 +
 +
 +int avfilter_graph_request_oldest(AVFilterGraph *graph)
 +{
 +    while (graph->sink_links_count) {
 +        AVFilterLink *oldest = graph->sink_links[0];
 +        int r = ff_request_frame(oldest);
 +        if (r != AVERROR_EOF)
 +            return r;
 +        av_log(oldest->dst, AV_LOG_DEBUG, "EOF on sink link %s:%s.\n",
 +               oldest->dst ? oldest->dst->name : "unknown",
 +               oldest->dstpad ? oldest->dstpad->name : "unknown");
 +        /* EOF: remove the link from the heap */
 +        if (oldest->age_index < --graph->sink_links_count)
 +            heap_bubble_down(graph, graph->sink_links[graph->sink_links_count],
 +                             oldest->age_index);
 +        oldest->age_index = -1;
 +    }
 +    return AVERROR_EOF;
 +}
  
  typedef struct AVFilterGraph {
      const AVClass *av_class;
-     unsigned filter_count;
+ #if FF_API_FOO_COUNT
+     attribute_deprecated
 -    unsigned filter_count;
++    unsigned filter_count_unused;
+ #endif
      AVFilterContext **filters;
+ #if !FF_API_FOO_COUNT
+     unsigned nb_filters;
+ #endif
  
      char *scale_sws_opts; ///< sws options to use for the auto-inserted scale filters
      char *resample_lavr_opts;   ///< libavresample options to use for the auto-inserted resample filters
+ #if FF_API_FOO_COUNT
+     unsigned nb_filters;
+ #endif
 +    char *aresample_swr_opts; ///< swr options to use for the auto-inserted aresample filters, Access ONLY through AVOptions
 +
 +    /**
 +     * Private fields
 +     *
 +     * The following fields are for internal use only.
 +     * Their type, offset, number and semantic can change without notice.
 +     */
 +
 +    AVFilterLink **sink_links;
 +    int sink_links_count;
 +
 +    unsigned disable_auto_convert;
  } AVFilterGraph;
  
  /**
index 28e9bc9,0000000..756f63d
mode 100644,000000..100644
--- /dev/null
@@@ -1,164 -1,0 +1,164 @@@
-     for (i = 0; i < graph->filter_count; i++) {
 +/*
 + * Filter graphs to bad ASCII-art
 + * Copyright (c) 2012 Nicolas George
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +#include <string.h>
 +
 +#include "libavutil/channel_layout.h"
 +#include "libavutil/bprint.h"
 +#include "libavutil/pixdesc.h"
 +#include "avfilter.h"
 +#include "avfiltergraph.h"
 +
 +static int print_link_prop(AVBPrint *buf, AVFilterLink *link)
 +{
 +    char *format;
 +    char layout[64];
 +
 +    if (!buf)
 +        buf = &(AVBPrint){ 0 }; /* dummy buffer */
 +    switch (link->type) {
 +        case AVMEDIA_TYPE_VIDEO:
 +            format = av_x_if_null(av_get_pix_fmt_name(link->format), "?");
 +            av_bprintf(buf, "[%dx%d %d:%d %s]", link->w, link->h,
 +                    link->sample_aspect_ratio.num,
 +                    link->sample_aspect_ratio.den,
 +                    format);
 +            break;
 +
 +        case AVMEDIA_TYPE_AUDIO:
 +            av_get_channel_layout_string(layout, sizeof(layout),
 +                                         link->channels, link->channel_layout);
 +            format = av_x_if_null(av_get_sample_fmt_name(link->format), "?");
 +            av_bprintf(buf, "[%dHz %s:%s]",
 +                       (int)link->sample_rate, format, layout);
 +            break;
 +
 +        default:
 +            av_bprintf(buf, "?");
 +            break;
 +    }
 +    return buf->len;
 +}
 +
 +static void avfilter_graph_dump_to_buf(AVBPrint *buf, AVFilterGraph *graph)
 +{
 +    unsigned i, j, x, e;
 +
++    for (i = 0; i < graph->nb_filters; i++) {
 +        AVFilterContext *filter = graph->filters[i];
 +        unsigned max_src_name = 0, max_dst_name = 0;
 +        unsigned max_in_name  = 0, max_out_name = 0;
 +        unsigned max_in_fmt   = 0, max_out_fmt  = 0;
 +        unsigned width, height, in_indent;
 +        unsigned lname = strlen(filter->name);
 +        unsigned ltype = strlen(filter->filter->name);
 +
 +        for (j = 0; j < filter->input_count; j++) {
 +            AVFilterLink *l = filter->inputs[j];
 +            unsigned ln = strlen(l->src->name) + 1 + strlen(l->srcpad->name);
 +            max_src_name = FFMAX(max_src_name, ln);
 +            max_in_name = FFMAX(max_in_name, strlen(l->dstpad->name));
 +            max_in_fmt = FFMAX(max_in_fmt, print_link_prop(NULL, l));
 +        }
 +        for (j = 0; j < filter->output_count; j++) {
 +            AVFilterLink *l = filter->outputs[j];
 +            unsigned ln = strlen(l->dst->name) + 1 + strlen(l->dstpad->name);
 +            max_dst_name = FFMAX(max_dst_name, ln);
 +            max_out_name = FFMAX(max_out_name, strlen(l->srcpad->name));
 +            max_out_fmt = FFMAX(max_out_fmt, print_link_prop(NULL, l));
 +        }
 +        in_indent = max_src_name + max_in_name + max_in_fmt;
 +        in_indent += in_indent ? 4 : 0;
 +        width = FFMAX(lname + 2, ltype + 4);
 +        height = FFMAX3(2, filter->input_count, filter->output_count);
 +        av_bprint_chars(buf, ' ', in_indent);
 +        av_bprintf(buf, "+");
 +        av_bprint_chars(buf, '-', width);
 +        av_bprintf(buf, "+\n");
 +        for (j = 0; j < height; j++) {
 +            unsigned in_no  = j - (height - filter->input_count ) / 2;
 +            unsigned out_no = j - (height - filter->output_count) / 2;
 +
 +            /* Input link */
 +            if (in_no < filter->input_count) {
 +                AVFilterLink *l = filter->inputs[in_no];
 +                e = buf->len + max_src_name + 2;
 +                av_bprintf(buf, "%s:%s", l->src->name, l->srcpad->name);
 +                av_bprint_chars(buf, '-', e - buf->len);
 +                e = buf->len + max_in_fmt + 2 +
 +                    max_in_name - strlen(l->dstpad->name);
 +                print_link_prop(buf, l);
 +                av_bprint_chars(buf, '-', e - buf->len);
 +                av_bprintf(buf, "%s", l->dstpad->name);
 +            } else {
 +                av_bprint_chars(buf, ' ', in_indent);
 +            }
 +
 +            /* Filter */
 +            av_bprintf(buf, "|");
 +            if (j == (height - 2) / 2) {
 +                x = (width - lname) / 2;
 +                av_bprintf(buf, "%*s%-*s", x, "", width - x, filter->name);
 +            } else if (j == (height - 2) / 2 + 1) {
 +                x = (width - ltype - 2) / 2;
 +                av_bprintf(buf, "%*s(%s)%*s", x, "", filter->filter->name,
 +                        width - ltype - 2 - x, "");
 +            } else {
 +                av_bprint_chars(buf, ' ', width);
 +            }
 +            av_bprintf(buf, "|");
 +
 +            /* Output link */
 +            if (out_no < filter->output_count) {
 +                AVFilterLink *l = filter->outputs[out_no];
 +                unsigned ln = strlen(l->dst->name) + 1 +
 +                              strlen(l->dstpad->name);
 +                e = buf->len + max_out_name + 2;
 +                av_bprintf(buf, "%s", l->srcpad->name);
 +                av_bprint_chars(buf, '-', e - buf->len);
 +                e = buf->len + max_out_fmt + 2 +
 +                    max_dst_name - ln;
 +                print_link_prop(buf, l);
 +                av_bprint_chars(buf, '-', e - buf->len);
 +                av_bprintf(buf, "%s:%s", l->dst->name, l->dstpad->name);
 +            }
 +            av_bprintf(buf, "\n");
 +        }
 +        av_bprint_chars(buf, ' ', in_indent);
 +        av_bprintf(buf, "+");
 +        av_bprint_chars(buf, '-', width);
 +        av_bprintf(buf, "+\n");
 +        av_bprintf(buf, "\n");
 +    }
 +}
 +
 +char *avfilter_graph_dump(AVFilterGraph *graph, const char *options)
 +{
 +    AVBPrint buf;
 +    char *dump;
 +
 +    av_bprint_init(&buf, 0, 0);
 +    avfilter_graph_dump_to_buf(&buf, graph);
 +    av_bprint_init(&buf, buf.len + 1, buf.len + 1);
 +    avfilter_graph_dump_to_buf(&buf, graph);
 +    av_bprint_finalize(&buf, &dump);
 +    return dump;
 +}
@@@ -435,9 -434,9 +435,9 @@@ int avfilter_graph_parse2(AVFilterGrap
      *outputs = open_outputs;
      return 0;
  
 - fail:
 + fail:end:
-     for (; graph->filter_count > 0; graph->filter_count--)
-         avfilter_free(graph->filters[graph->filter_count - 1]);
+     for (; graph->nb_filters > 0; graph->nb_filters--)
+         avfilter_free(graph->filters[graph->nb_filters - 1]);
      av_freep(&graph->filters);
      avfilter_inout_free(&open_inputs);
      avfilter_inout_free(&open_outputs);
@@@ -510,92 -506,7 +510,92 @@@ int avfilter_graph_parse(AVFilterGraph 
      }
      avfilter_inout_free(&inputs);
      avfilter_inout_free(&outputs);
 -    avfilter_inout_free(&open_inputs);
 -    avfilter_inout_free(&open_outputs);
 +    /* clear open_in/outputs only if not passed as parameters */
 +    if (open_inputs_ptr) *open_inputs_ptr = open_inputs;
 +    else avfilter_inout_free(&open_inputs);
 +    if (open_outputs_ptr) *open_outputs_ptr = open_outputs;
 +    else avfilter_inout_free(&open_outputs);
      return ret;
  }
-         for (; graph->filter_count > 0; graph->filter_count--)
-             avfilter_free(graph->filters[graph->filter_count - 1]);
 +#else
 +    int index = 0, ret = 0;
 +    char chr = 0;
 +
 +    AVFilterInOut *curr_inputs = NULL;
 +    AVFilterInOut *open_inputs  = open_inputs_ptr  ? *open_inputs_ptr  : NULL;
 +    AVFilterInOut *open_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL;
 +
 +    if ((ret = parse_sws_flags(&filters, graph)) < 0)
 +        goto end;
 +
 +    do {
 +        AVFilterContext *filter;
 +        const char *filterchain = filters;
 +        filters += strspn(filters, WHITESPACES);
 +
 +        if ((ret = parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx)) < 0)
 +            goto end;
 +
 +        if ((ret = parse_filter(&filter, &filters, graph, index, log_ctx)) < 0)
 +            goto end;
 +
 +        if (filter->input_count == 1 && !curr_inputs && !index) {
 +            /* First input pad, assume it is "[in]" if not specified */
 +            const char *tmp = "[in]";
 +            if ((ret = parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx)) < 0)
 +                goto end;
 +        }
 +
 +        if ((ret = link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx)) < 0)
 +            goto end;
 +
 +        if ((ret = parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
 +                                 log_ctx)) < 0)
 +            goto end;
 +
 +        filters += strspn(filters, WHITESPACES);
 +        chr = *filters++;
 +
 +        if (chr == ';' && curr_inputs) {
 +            av_log(log_ctx, AV_LOG_ERROR,
 +                   "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
 +                   filterchain);
 +            ret = AVERROR(EINVAL);
 +            goto end;
 +        }
 +        index++;
 +    } while (chr == ',' || chr == ';');
 +
 +    if (chr) {
 +        av_log(log_ctx, AV_LOG_ERROR,
 +               "Unable to parse graph description substring: \"%s\"\n",
 +               filters - 1);
 +        ret = AVERROR(EINVAL);
 +        goto end;
 +    }
 +
 +    if (curr_inputs) {
 +        /* Last output pad, assume it is "[out]" if not specified */
 +        const char *tmp = "[out]";
 +        if ((ret = parse_outputs(&tmp, &curr_inputs, &open_inputs, &open_outputs,
 +                                 log_ctx)) < 0)
 +            goto end;
 +    }
 +
 +end:
 +    /* clear open_in/outputs only if not passed as parameters */
 +    if (open_inputs_ptr) *open_inputs_ptr = open_inputs;
 +    else avfilter_inout_free(&open_inputs);
 +    if (open_outputs_ptr) *open_outputs_ptr = open_outputs;
 +    else avfilter_inout_free(&open_outputs);
 +    avfilter_inout_free(&curr_inputs);
 +
 +    if (ret < 0) {
++        for (; graph->nb_filters > 0; graph->nb_filters--)
++            avfilter_free(graph->filters[graph->nb_filters - 1]);
 +        av_freep(&graph->filters);
 +    }
 +    return ret;
 +}
 +
 +#endif
@@@ -29,8 -29,8 +29,8 @@@
  #include "libavutil/avutil.h"
  
  #define LIBAVFILTER_VERSION_MAJOR  3
- #define LIBAVFILTER_VERSION_MINOR  46
 -#define LIBAVFILTER_VERSION_MINOR  6
 -#define LIBAVFILTER_VERSION_MICRO  0
++#define LIBAVFILTER_VERSION_MINOR  47
 +#define LIBAVFILTER_VERSION_MICRO 100
  
  #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
                                                 LIBAVFILTER_VERSION_MINOR, \
@@@ -58,7 -58,7 +58,7 @@@ static void print_digraph(FILE *outfile
      fprintf(outfile, "node [shape=box]\n");
      fprintf(outfile, "rankdir=LR\n");
  
--    for (i = 0; i < graph->filter_count; i++) {
++    for (i = 0; i < graph->nb_filters; i++) {
          char filter_ctx_label[128];
          const AVFilterContext *filter_ctx = graph->filters[i];