aboutsummaryrefslogtreecommitdiffstats
path: root/libavfilter/f_drawgraph.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2016-07-26 13:10:27 +0200
committerPaul B Mahol <onemda@gmail.com>2016-07-28 10:30:06 +0200
commitd7ae4f79d364031be8a2209ee8de60c991aeb0b3 (patch)
tree1760aa95bd2cc522329d0353002d9259a396cbb0 /libavfilter/f_drawgraph.c
parent37abc8cca2565eed7e1b1ff2560774faa371eb63 (diff)
downloadffmpeg-d7ae4f79d364031be8a2209ee8de60c991aeb0b3.tar.gz
avfilter/f_drawgraph: add another slide mode
Diffstat (limited to 'libavfilter/f_drawgraph.c')
-rw-r--r--libavfilter/f_drawgraph.c170
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 }
};