diff options
author | Paul B Mahol <onemda@gmail.com> | 2016-07-26 13:10:27 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2016-07-28 10:30:06 +0200 |
commit | d7ae4f79d364031be8a2209ee8de60c991aeb0b3 (patch) | |
tree | 1760aa95bd2cc522329d0353002d9259a396cbb0 /libavfilter/f_drawgraph.c | |
parent | 37abc8cca2565eed7e1b1ff2560774faa371eb63 (diff) | |
download | ffmpeg-d7ae4f79d364031be8a2209ee8de60c991aeb0b3.tar.gz |
avfilter/f_drawgraph: add another slide mode
Diffstat (limited to 'libavfilter/f_drawgraph.c')
-rw-r--r-- | libavfilter/f_drawgraph.c | 170 |
1 files changed, 158 insertions, 12 deletions
diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c index 0ca0d229ed..4c705fe851 100644 --- a/libavfilter/f_drawgraph.c +++ b/libavfilter/f_drawgraph.c @@ -44,6 +44,9 @@ typedef struct DrawGraphContext { int x; int prev_y[4]; int first; + float *values[4]; + int values_size[4]; + int nb_values; } DrawGraphContext; #define OFFSET(x) offsetof(DrawGraphContext, x) @@ -65,11 +68,12 @@ static const AVOption drawgraph_options[] = { {"bar", "draw bars", OFFSET(mode), AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode"}, {"dot", "draw dots", OFFSET(mode), AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode"}, {"line", "draw lines", OFFSET(mode), AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mode"}, - { "slide", "set slide mode", OFFSET(slide), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "slide" }, + { "slide", "set slide mode", OFFSET(slide), AV_OPT_TYPE_INT, {.i64=0}, 0, 4, FLAGS, "slide" }, {"frame", "draw new frames", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "slide"}, {"replace", "replace old columns with new", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "slide"}, {"scroll", "scroll from right to left", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "slide"}, {"rscroll", "scroll from left to right", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "slide"}, + {"picture", "display graph in single frame", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, FLAGS, "slide"}, { "size", "set graph size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="900x256"}, 0, 0, FLAGS }, { "s", "set graph size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="900x256"}, 0, 0, FLAGS }, { NULL } @@ -100,6 +104,18 @@ static av_cold int init(AVFilterContext *ctx) s->first = 1; + if (s->slide == 4) { + s->values[0] = av_fast_realloc(NULL, &s->values_size[0], 2000); + s->values[1] = av_fast_realloc(NULL, &s->values_size[1], 2000); + s->values[2] = av_fast_realloc(NULL, &s->values_size[2], 2000); + s->values[3] = av_fast_realloc(NULL, &s->values_size[3], 2000); + + if (!s->values[0] || !s->values[1] || + !s->values[2] || !s->values[3]) { + return AVERROR(ENOMEM); + } + } + return 0; } @@ -144,19 +160,45 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFrame *out = s->out; int i; - if (!s->out || s->out->width != outlink->w || - s->out->height != outlink->h) { - av_frame_free(&s->out); - s->out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - out = s->out; - if (!s->out) { - av_frame_free(&in); + if (s->slide == 4 && s->nb_values >= s->values_size[0] / sizeof(float)) { + float *ptr; + + ptr = av_fast_realloc(s->values[0], &s->values_size[0], s->values_size[0] * 2); + if (!ptr) return AVERROR(ENOMEM); - } + s->values[0] = ptr; + + ptr = av_fast_realloc(s->values[1], &s->values_size[1], s->values_size[1] * 2); + if (!ptr) + return AVERROR(ENOMEM); + s->values[1] = ptr; + + ptr = av_fast_realloc(s->values[2], &s->values_size[2], s->values_size[2] * 2); + if (!ptr) + return AVERROR(ENOMEM); + s->values[2] = ptr; - clear_image(s, out, outlink); + ptr = av_fast_realloc(s->values[3], &s->values_size[3], s->values_size[3] * 2); + if (!ptr) + return AVERROR(ENOMEM); + s->values[3] = ptr; + } + + if (s->slide != 4 || s->nb_values == 0) { + if (!s->out || s->out->width != outlink->w || + s->out->height != outlink->h) { + av_frame_free(&s->out); + s->out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + out = s->out; + if (!s->out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + + clear_image(s, out, outlink); + } + av_frame_copy_props(out, in); } - av_frame_copy_props(out, in); metadata = av_frame_get_metadata(in); @@ -166,6 +208,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) uint32_t fg, bg; float vf; + if (s->slide == 4) + s->values[i][s->nb_values] = NAN; + e = av_dict_get(metadata, s->key[i], NULL, 0); if (!e || !e->value) continue; @@ -175,6 +220,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) vf = av_clipf(vf, s->min, s->max); + if (s->slide == 4) { + s->values[i][s->nb_values] = vf; + continue; + } + values[VAR_MIN] = s->min; values[VAR_MAX] = s->max; values[VAR_VAL] = vf; @@ -255,12 +305,99 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } } + s->nb_values++; s->x++; av_frame_free(&in); + + if (s->slide == 4) + return 0; + return ff_filter_frame(outlink, av_frame_clone(s->out)); } +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + DrawGraphContext *s = ctx->priv; + AVFrame *out = s->out; + int ret, i, k, step, l; + + ret = ff_request_frame(ctx->inputs[0]); + + if (s->slide == 4 && ret == AVERROR_EOF && s->nb_values > 0) { + s->x = l = 0; + step = ceil(s->nb_values / (float)s->w); + + for (k = 0; k < s->nb_values; k++) { + for (i = 0; i < 4; i++) { + double values[VAR_VARS_NB]; + int j, y, x, old; + uint32_t fg, bg; + float vf = s->values[i][k]; + + if (isnan(vf)) + continue; + + values[VAR_MIN] = s->min; + values[VAR_MAX] = s->max; + values[VAR_VAL] = vf; + + fg = av_expr_eval(s->fg_expr[i], values, NULL); + bg = AV_RN32(s->bg); + + x = s->x; + y = (outlink->h - 1) * (1 - ((vf - s->min) / (s->max - s->min))); + + switch (s->mode) { + case 0: + old = AV_RN32(out->data[0] + y * out->linesize[0] + x * 4); + for (j = y; j < outlink->h; j++) { + if (old != bg && + (AV_RN32(out->data[0] + j * out->linesize[0] + x * 4) != old) || + AV_RN32(out->data[0] + FFMIN(j+1, outlink->h - 1) * out->linesize[0] + x * 4) != old) { + draw_dot(fg, x, j, out); + break; + } + draw_dot(fg, x, j, out); + } + break; + case 1: + draw_dot(fg, x, y, out); + break; + case 2: + if (s->first) { + s->first = 0; + s->prev_y[i] = y; + } + + if (y <= s->prev_y[i]) { + for (j = y; j <= s->prev_y[i]; j++) + draw_dot(fg, x, j, out); + } else { + for (j = s->prev_y[i]; j <= y; j++) + draw_dot(fg, x, j, out); + } + s->prev_y[i] = y; + break; + } + } + + l++; + if (l >= step) { + l = 0; + s->x++; + } + } + + s->nb_values = 0; + out->pts = 0; + ret = ff_filter_frame(ctx->outputs[0], s->out); + } + + return ret; +} + static int config_output(AVFilterLink *outlink) { DrawGraphContext *s = outlink->src->priv; @@ -279,7 +416,14 @@ static av_cold void uninit(AVFilterContext *ctx) for (i = 0; i < 4; i++) av_expr_free(s->fg_expr[i]); - av_frame_free(&s->out); + + if (s->slide != 4) + av_frame_free(&s->out); + + av_freep(&s->values[0]); + av_freep(&s->values[1]); + av_freep(&s->values[2]); + av_freep(&s->values[3]); } #if CONFIG_DRAWGRAPH_FILTER @@ -300,6 +444,7 @@ static const AVFilterPad drawgraph_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, + .request_frame = request_frame, }, { NULL } }; @@ -337,6 +482,7 @@ static const AVFilterPad adrawgraph_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, + .request_frame = request_frame, }, { NULL } }; |