From 996f9f0c3280552d293c3dbe4266938927fd5908 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 18 Mar 2012 11:27:38 +0100 Subject: avfiltergraph: add an AVClass to AVFilterGraph on next major bump. It will be used for logging, possibly also AVOptions. --- libavfilter/avfiltergraph.c | 16 +++++++++++++++- libavfilter/avfiltergraph.h | 4 ++++ libavfilter/version.h | 8 ++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'libavfilter') diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 8c43251c4c..9b73cc95ab 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -27,9 +27,23 @@ #include "avfiltergraph.h" #include "internal.h" +#include "libavutil/log.h" + +static const AVClass filtergraph_class = { + .class_name = "AVFilterGraph", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + AVFilterGraph *avfilter_graph_alloc(void) { - return av_mallocz(sizeof(AVFilterGraph)); + AVFilterGraph *ret = av_mallocz(sizeof(AVFilterGraph)); + if (!ret) + return NULL; +#if FF_API_GRAPH_AVCLASS + ret->av_class = &filtergraph_class; +#endif + return ret; } void avfilter_graph_free(AVFilterGraph **graph) diff --git a/libavfilter/avfiltergraph.h b/libavfilter/avfiltergraph.h index f9cf5cd3f9..733d1c4a51 100644 --- a/libavfilter/avfiltergraph.h +++ b/libavfilter/avfiltergraph.h @@ -23,8 +23,12 @@ #define AVFILTER_AVFILTERGRAPH_H #include "avfilter.h" +#include "libavutil/log.h" typedef struct AVFilterGraph { +#if FF_API_GRAPH_AVCLASS + const AVClass *av_class; +#endif unsigned filter_count; AVFilterContext **filters; diff --git a/libavfilter/version.h b/libavfilter/version.h index 09d6700d12..d84b67ff76 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -40,4 +40,12 @@ LIBAVFILTER_VERSION_MICRO) #define LIBAVFILTER_BUILD LIBAVFILTER_VERSION_INT +/** + * Those FF_API_* defines are not part of public API. + * They may change, break or disappear at any time. + */ +#ifndef FF_API_GRAPH_AVCLASS +#define FF_API_GRAPH_AVCLASS (LIBAVFILTER_VERSION_MAJOR > 2) +#endif + #endif // AVFILTER_VERSION_H -- cgit v1.2.3 From 63736fe48c30c5db313c3a25d1462ad31b2a1671 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 23 Mar 2012 15:14:40 +0100 Subject: avfiltergraph: try to reduce format conversions in filters. Current code, with a filterchain such as (input - yuv411) -> (scale - any) -> (sink - any) will result in yuv420 being chosen for the second link, which is clearly not right. This commit attempts to improve in the following way: repeat until convergence: loop over all filters find input link with exactly one format force this format on all output links of the same type (if possible) --- libavfilter/avfiltergraph.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'libavfilter') diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 9b73cc95ab..04d9027527 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -214,6 +214,49 @@ static void pick_format(AVFilterLink *link) avfilter_formats_unref(&link->out_formats); } +static int reduce_formats_on_filter(AVFilterContext *filter) +{ + int i, j, k, ret = 0; + + for (i = 0; i < filter->input_count; i++) { + AVFilterLink *link = filter->inputs[i]; + int format = link->out_formats->formats[0]; + + if (link->out_formats->format_count != 1) + continue; + + for (j = 0; j < filter->output_count; j++) { + AVFilterLink *out_link = filter->outputs[j]; + AVFilterFormats *fmts = out_link->in_formats; + + if (link->type != out_link->type || + out_link->in_formats->format_count == 1) + continue; + + for (k = 0; k < out_link->in_formats->format_count; k++) + if (fmts->formats[k] == format) { + fmts->formats[0] = format; + fmts->format_count = 1; + ret = 1; + break; + } + } + } + return ret; +} + +static void reduce_formats(AVFilterGraph *graph) +{ + int i, reduced; + + do { + reduced = 0; + + for (i = 0; i < graph->filter_count; i++) + reduced |= reduce_formats_on_filter(graph->filters[i]); + } while (reduced); +} + static void pick_formats(AVFilterGraph *graph) { int i, j; @@ -237,7 +280,10 @@ int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx) return ret; /* Once everything is merged, it's possible that we'll still have - * multiple valid media format choices. We pick the first one. */ + * multiple valid media format choices. We try to minimize the amount + * of format conversion inside filters */ + reduce_formats(graph); + pick_formats(graph); return 0; -- cgit v1.2.3 From 416fd90ead0cdea962a1319a1b20b9272be4fb49 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 29 Mar 2012 07:02:27 +0200 Subject: vf_scale: avoid a pointless memcpy in no-op conversion. I.e. just pass the buffer along when src parameters == dst parameters. --- libavfilter/vf_scale.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 46009a7daa..a4da088936 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -213,11 +213,16 @@ static int config_props(AVFilterLink *outlink) if (scale->sws) sws_freeContext(scale->sws); - scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format, - outlink->w, outlink->h, outlink->format, - scale->flags, NULL, NULL, NULL); - if (!scale->sws) - return AVERROR(EINVAL); + if (inlink->w == outlink->w && inlink->h == outlink->h && + inlink->format == outlink->format) + scale->sws = NULL; + else { + scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format, + outlink->w, outlink->h, outlink->format, + scale->flags, NULL, NULL, NULL); + if (!scale->sws) + return AVERROR(EINVAL); + } if (inlink->sample_aspect_ratio.num) @@ -241,6 +246,11 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref) AVFilterLink *outlink = link->dst->outputs[0]; AVFilterBufferRef *outpicref; + if (!scale->sws) { + avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0)); + return; + } + scale->hsub = av_pix_fmt_descriptors[link->format].log2_chroma_w; scale->vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h; @@ -267,6 +277,11 @@ static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir) AVFilterBufferRef *cur_pic = link->cur_buf; const uint8_t *data[4]; + if (!scale->sws) { + avfilter_draw_slice(link->dst->outputs[0], y, h, slice_dir); + return; + } + if (scale->slice_y == 0 && slice_dir == -1) scale->slice_y = link->dst->outputs[0]->h; -- cgit v1.2.3 From 95587d29d73c5cdf39062fde3f21436f8abf3e79 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 29 Mar 2012 11:22:40 +0200 Subject: vsrc_buffer: allow buffering arbitrary number of frames. --- libavfilter/vsrc_buffer.c | 72 +++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 30 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/vsrc_buffer.c b/libavfilter/vsrc_buffer.c index e5b96a60cf..665b33c1d4 100644 --- a/libavfilter/vsrc_buffer.c +++ b/libavfilter/vsrc_buffer.c @@ -26,10 +26,11 @@ #include "avfilter.h" #include "buffersrc.h" #include "vsrc_buffer.h" +#include "libavutil/fifo.h" #include "libavutil/imgutils.h" typedef struct { - AVFilterBufferRef *buf; + AVFifoBuffer *fifo; int h, w; enum PixelFormat pix_fmt; AVRational time_base; ///< time_base to set in the output link @@ -46,25 +47,29 @@ int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int64_t pts, AVRational pixel_aspect) { BufferSourceContext *c = buffer_filter->priv; + AVFilterBufferRef *buf; + int ret; - if (c->buf) { - av_log(buffer_filter, AV_LOG_ERROR, - "Buffering several frames is not supported. " - "Please consume all available frames before adding a new one.\n" - ); - //return -1; - } + if (!av_fifo_space(c->fifo) && + (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) + + sizeof(buf))) < 0) + return ret; CHECK_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, frame->format); - c->buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, - c->w, c->h); - av_image_copy(c->buf->data, c->buf->linesize, frame->data, frame->linesize, + buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE, + c->w, c->h); + av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize, c->pix_fmt, c->w, c->h); - avfilter_copy_frame_props(c->buf, frame); - c->buf->pts = pts; - c->buf->video->pixel_aspect = pixel_aspect; + avfilter_copy_frame_props(buf, frame); + buf->pts = pts; + buf->video->pixel_aspect = pixel_aspect; + + if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) { + avfilter_unref_buffer(buf); + return ret; + } return 0; } @@ -72,18 +77,17 @@ int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf) { BufferSourceContext *c = s->priv; + int ret; - if (c->buf) { - av_log(s, AV_LOG_ERROR, - "Buffering several frames is not supported. " - "Please consume all available frames before adding a new one.\n" - ); - return AVERROR(EINVAL); - } + if (!av_fifo_space(c->fifo) && + (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) + + sizeof(buf))) < 0) + return ret; CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format); - c->buf = buf; + if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) + return ret; return 0; } @@ -110,6 +114,9 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) } } + if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) + return AVERROR(ENOMEM); + av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name); return 0; } @@ -117,9 +124,13 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) static av_cold void uninit(AVFilterContext *ctx) { BufferSourceContext *s = ctx->priv; - if (s->buf) - avfilter_unref_buffer(s->buf); - s->buf = NULL; + while (av_fifo_size(s->fifo)) { + AVFilterBufferRef *buf; + av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL); + avfilter_unref_buffer(buf); + } + av_fifo_free(s->fifo); + s->fifo = NULL; } static int query_formats(AVFilterContext *ctx) @@ -146,18 +157,19 @@ static int config_props(AVFilterLink *link) static int request_frame(AVFilterLink *link) { BufferSourceContext *c = link->src->priv; + AVFilterBufferRef *buf; - if (!c->buf) { + if (!av_fifo_size(c->fifo)) { av_log(link->src, AV_LOG_ERROR, "request_frame() called with no available frame!\n"); //return -1; } + av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL); - avfilter_start_frame(link, avfilter_ref_buffer(c->buf, ~0)); + avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0)); avfilter_draw_slice(link, 0, link->h, 1); avfilter_end_frame(link); - avfilter_unref_buffer(c->buf); - c->buf = NULL; + avfilter_unref_buffer(buf); return 0; } @@ -165,7 +177,7 @@ static int request_frame(AVFilterLink *link) static int poll_frame(AVFilterLink *link) { BufferSourceContext *c = link->src->priv; - return !!c->buf; + return !!av_fifo_size(c->fifo); } AVFilter avfilter_vsrc_buffer = { -- cgit v1.2.3