[FFmpeg-cvslog] avfilter/vf_zoompan: rewrite so it doesn't cache all output frames
Paul B Mahol
git at videolan.org
Sun Jan 24 17:53:06 CET 2016
ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sun Jan 24 11:38:15 2016 +0100| [3b9f41a9c681386e6a73c56debcd70ff47744123] | committer: Paul B Mahol
avfilter/vf_zoompan: rewrite so it doesn't cache all output frames
Signed-off-by: Paul B Mahol <onemda at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=3b9f41a9c681386e6a73c56debcd70ff47744123
---
libavfilter/vf_zoompan.c | 258 ++++++++++++++++++++++++++++------------------
1 file changed, 155 insertions(+), 103 deletions(-)
diff --git a/libavfilter/vf_zoompan.c b/libavfilter/vf_zoompan.c
index c65ce56..0dc5f37 100644
--- a/libavfilter/vf_zoompan.c
+++ b/libavfilter/vf_zoompan.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/avassert.h"
#include "libavutil/eval.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
@@ -85,6 +86,12 @@ typedef struct ZPcontext {
int prev_nb_frames;
struct SwsContext *sws;
int64_t frame_count;
+ const AVPixFmtDescriptor *desc;
+ AVFrame *in;
+ double var_values[VARS_NB];
+ int nb_frames;
+ int current_frame;
+ int finished;
} ZPContext;
#define OFFSET(x) offsetof(ZPContext, x)
@@ -116,141 +123,184 @@ static int config_output(AVFilterLink *outlink)
outlink->w = s->w;
outlink->h = s->h;
+ s->desc = av_pix_fmt_desc_get(outlink->format);
return 0;
}
-static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+static int output_single_frame(AVFilterContext *ctx, AVFrame *in, double *var_values, int i,
+ double *zoom, double *dx, double *dy)
{
- AVFilterContext *ctx = inlink->dst;
- AVFilterLink *outlink = ctx->outputs[0];
ZPContext *s = ctx->priv;
- double var_values[VARS_NB], nb_frames, zoom, dx, dy;
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(in->format);
- AVFrame *out = NULL;
- int i, k, x, y, w, h, ret = 0;
-
- var_values[VAR_IN_W] = var_values[VAR_IW] = in->width;
- var_values[VAR_IN_H] = var_values[VAR_IH] = in->height;
- var_values[VAR_OUT_W] = var_values[VAR_OW] = s->w;
- var_values[VAR_OUT_H] = var_values[VAR_OH] = s->h;
- var_values[VAR_IN] = inlink->frame_count + 1;
- var_values[VAR_ON] = outlink->frame_count + 1;
- var_values[VAR_PX] = s->x;
- var_values[VAR_PY] = s->y;
- var_values[VAR_X] = 0;
- var_values[VAR_Y] = 0;
- var_values[VAR_PZOOM] = s->prev_zoom;
- var_values[VAR_ZOOM] = 1;
- var_values[VAR_PDURATION] = s->prev_nb_frames;
- var_values[VAR_A] = (double) in->width / in->height;
- var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
- (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
- var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR];
- var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
- var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
+ AVFilterLink *outlink = ctx->outputs[0];
+ int64_t pts = av_rescale_q(in->pts, ctx->inputs[0]->time_base,
+ outlink->time_base) + s->frame_count;
+ int k, x, y, w, h, ret = 0;
+ uint8_t *input[4];
+ int px[4], py[4];
+ AVFrame *out;
+
+ var_values[VAR_TIME] = pts * av_q2d(outlink->time_base);
+ var_values[VAR_FRAME] = i;
+ var_values[VAR_ON] = outlink->frame_count + 1;
+ if ((ret = av_expr_parse_and_eval(zoom, s->zoom_expr_str,
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
+ return ret;
- if ((ret = av_expr_parse_and_eval(&nb_frames, s->duration_expr_str,
+ *zoom = av_clipd(*zoom, 1, 10);
+ var_values[VAR_ZOOM] = *zoom;
+ w = in->width * (1.0 / *zoom);
+ h = in->height * (1.0 / *zoom);
+
+ if ((ret = av_expr_parse_and_eval(dx, s->x_expr_str,
var_names, var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
- goto fail;
-
- var_values[VAR_DURATION] = nb_frames;
- for (i = 0; i < nb_frames; i++) {
- int px[4];
- int py[4];
- uint8_t *input[4];
- int64_t pts = av_rescale_q(in->pts, inlink->time_base,
- outlink->time_base) + s->frame_count;
-
- var_values[VAR_TIME] = pts * av_q2d(outlink->time_base);
- var_values[VAR_FRAME] = i;
- var_values[VAR_ON] = outlink->frame_count + 1;
- if ((ret = av_expr_parse_and_eval(&zoom, s->zoom_expr_str,
- var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
- goto fail;
+ return ret;
+ x = *dx = av_clipd(*dx, 0, FFMAX(in->width - w, 0));
+ var_values[VAR_X] = *dx;
+ x &= ~((1 << s->desc->log2_chroma_w) - 1);
- zoom = av_clipd(zoom, 1, 10);
- var_values[VAR_ZOOM] = zoom;
- w = in->width * (1.0 / zoom);
- h = in->height * (1.0 / zoom);
+ if ((ret = av_expr_parse_and_eval(dy, s->y_expr_str,
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
+ return ret;
+ y = *dy = av_clipd(*dy, 0, FFMAX(in->height - h, 0));
+ var_values[VAR_Y] = *dy;
+ y &= ~((1 << s->desc->log2_chroma_h) - 1);
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ ret = AVERROR(ENOMEM);
+ return ret;
+ }
- if ((ret = av_expr_parse_and_eval(&dx, s->x_expr_str,
- var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
- goto fail;
- x = dx = av_clipd(dx, 0, FFMAX(in->width - w, 0));
- var_values[VAR_X] = dx;
- x &= ~((1 << desc->log2_chroma_w) - 1);
+ px[1] = px[2] = FF_CEIL_RSHIFT(x, s->desc->log2_chroma_w);
+ px[0] = px[3] = x;
- if ((ret = av_expr_parse_and_eval(&dy, s->y_expr_str,
- var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
- goto fail;
- y = dy = av_clipd(dy, 0, FFMAX(in->height - h, 0));
- var_values[VAR_Y] = dy;
- y &= ~((1 << desc->log2_chroma_h) - 1);
+ py[1] = py[2] = FF_CEIL_RSHIFT(y, s->desc->log2_chroma_h);
+ py[0] = py[3] = y;
- out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
- if (!out) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
+ s->sws = sws_alloc_context();
+ if (!s->sws) {
+ ret = AVERROR(ENOMEM);
+ return ret;
+ }
- px[1] = px[2] = FF_CEIL_RSHIFT(x, desc->log2_chroma_w);
- px[0] = px[3] = x;
+ for (k = 0; in->data[k]; k++)
+ input[k] = in->data[k] + py[k] * in->linesize[k] + px[k];
- py[1] = py[2] = FF_CEIL_RSHIFT(y, desc->log2_chroma_h);
- py[0] = py[3] = y;
+ av_opt_set_int(s->sws, "srcw", w, 0);
+ av_opt_set_int(s->sws, "srch", h, 0);
+ av_opt_set_int(s->sws, "src_format", in->format, 0);
+ av_opt_set_int(s->sws, "dstw", outlink->w, 0);
+ av_opt_set_int(s->sws, "dsth", outlink->h, 0);
+ av_opt_set_int(s->sws, "dst_format", outlink->format, 0);
+ av_opt_set_int(s->sws, "sws_flags", SWS_BICUBIC, 0);
- s->sws = sws_alloc_context();
- if (!s->sws) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
+ if ((ret = sws_init_context(s->sws, NULL, NULL)) < 0)
+ return ret;
- for (k = 0; in->data[k]; k++)
- input[k] = in->data[k] + py[k] * in->linesize[k] + px[k];
+ sws_scale(s->sws, (const uint8_t *const *)&input, in->linesize, 0, h, out->data, out->linesize);
- av_opt_set_int(s->sws, "srcw", w, 0);
- av_opt_set_int(s->sws, "srch", h, 0);
- av_opt_set_int(s->sws, "src_format", in->format, 0);
- av_opt_set_int(s->sws, "dstw", outlink->w, 0);
- av_opt_set_int(s->sws, "dsth", outlink->h, 0);
- av_opt_set_int(s->sws, "dst_format", outlink->format, 0);
- av_opt_set_int(s->sws, "sws_flags", SWS_BICUBIC, 0);
+ out->pts = pts;
+ s->frame_count++;
- if ((ret = sws_init_context(s->sws, NULL, NULL)) < 0)
- goto fail;
+ ret = ff_filter_frame(outlink, out);
+ sws_freeContext(s->sws);
+ s->sws = NULL;
+ s->current_frame++;
+ return ret;
+}
- sws_scale(s->sws, (const uint8_t *const *)&input, in->linesize, 0, h, out->data, out->linesize);
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ZPContext *s = ctx->priv;
+ double nb_frames;
+ int ret;
- out->pts = pts;
- s->frame_count++;
+ if (s->in) {
+ av_frame_free(&in);
+ return 0;
+ }
- ret = ff_filter_frame(outlink, out);
- out = NULL;
- if (ret < 0)
- break;
+ s->finished = 0;
+ s->var_values[VAR_IN_W] = s->var_values[VAR_IW] = in->width;
+ s->var_values[VAR_IN_H] = s->var_values[VAR_IH] = in->height;
+ s->var_values[VAR_OUT_W] = s->var_values[VAR_OW] = s->w;
+ s->var_values[VAR_OUT_H] = s->var_values[VAR_OH] = s->h;
+ s->var_values[VAR_IN] = inlink->frame_count + 1;
+ s->var_values[VAR_ON] = outlink->frame_count + 1;
+ s->var_values[VAR_PX] = s->x;
+ s->var_values[VAR_PY] = s->y;
+ s->var_values[VAR_X] = 0;
+ s->var_values[VAR_Y] = 0;
+ s->var_values[VAR_PZOOM] = s->prev_zoom;
+ s->var_values[VAR_ZOOM] = 1;
+ s->var_values[VAR_PDURATION] = s->prev_nb_frames;
+ s->var_values[VAR_A] = (double) in->width / in->height;
+ s->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
+ (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
+ s->var_values[VAR_DAR] = s->var_values[VAR_A] * s->var_values[VAR_SAR];
+ s->var_values[VAR_HSUB] = 1 << s->desc->log2_chroma_w;
+ s->var_values[VAR_VSUB] = 1 << s->desc->log2_chroma_h;
+
+ if ((ret = av_expr_parse_and_eval(&nb_frames, s->duration_expr_str,
+ var_names, s->var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
+ av_frame_free(&in);
+ return ret;
+ }
+
+ s->var_values[VAR_DURATION] = s->nb_frames = nb_frames;
+ s->in = in;
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ZPContext *s = ctx->priv;
+ AVFrame *in = s->in;
+ double zoom, dx, dy;
+ int ret;
- sws_freeContext(s->sws);
- s->sws = NULL;
+ if (in) {
+ ret = output_single_frame(ctx, in, s->var_values, s->current_frame,
+ &zoom, &dx, &dy);
+ if (ret < 0)
+ goto fail;
}
- s->x = dx;
- s->y = dy;
- s->prev_zoom = zoom;
- s->prev_nb_frames = nb_frames;
+ if (s->current_frame >= s->nb_frames) {
+ s->x = dx;
+ s->y = dy;
+ s->prev_zoom = zoom;
+ s->prev_nb_frames = s->nb_frames;
+ s->nb_frames = 0;
+ s->current_frame = 0;
+ av_frame_free(&s->in);
+ ret = 0;
+ s->finished = 1;
+ ret = ff_request_frame(ctx->inputs[0]);
+ }
fail:
sws_freeContext(s->sws);
s->sws = NULL;
- av_frame_free(&out);
- av_frame_free(&in);
+
return ret;
}
+static int poll_frame(AVFilterLink *link)
+{
+ ZPContext *s = link->src->priv;
+ return s->nb_frames - s->current_frame;
+}
+
static int query_formats(AVFilterContext *ctx)
{
static const enum AVPixelFormat pix_fmts[] = {
@@ -295,6 +345,8 @@ static const AVFilterPad outputs[] = {
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.config_props = config_output,
+ .poll_frame = poll_frame,
+ .request_frame = request_frame,
},
{ NULL }
};
More information about the ffmpeg-cvslog
mailing list