You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	avfilter/f_drawgraph: add another slide mode
This commit is contained in:
		| @@ -6438,6 +6438,9 @@ Scroll from right to left. | ||||
|  | ||||
| @item rscroll | ||||
| Scroll from left to right. | ||||
|  | ||||
| @item picture | ||||
| Draw single picture. | ||||
| @end table | ||||
|  | ||||
| Default is @code{frame}. | ||||
|   | ||||
| @@ -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); | ||||
|             return AVERROR(ENOMEM); | ||||
|         } | ||||
|     if (s->slide == 4 && s->nb_values >= s->values_size[0] / sizeof(float)) { | ||||
|         float *ptr; | ||||
|  | ||||
|         clear_image(s, out, outlink); | ||||
|         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; | ||||
|  | ||||
|         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 } | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user