From ec11ff8407eadc65f4225f83e778c504c00ce037 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Thu, 1 Dec 2011 11:27:19 +0100 Subject: drawtext: manage memory allocation better Call dtext_prepare_text as early as possible Do not draw if the memory allocation failed --- libavfilter/vf_drawtext.c | 264 +++++++++++++++++++++++----------------------- 1 file changed, 132 insertions(+), 132 deletions(-) (limited to 'libavfilter/vf_drawtext.c') diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c index 3d6b7b0486..06b5dc0ba1 100644 --- a/libavfilter/vf_drawtext.c +++ b/libavfilter/vf_drawtext.c @@ -369,9 +369,135 @@ static av_cold void uninit(AVFilterContext *ctx) } +static inline int is_newline(uint32_t c) +{ + return (c == '\n' || c == '\r' || c == '\f' || c == '\v'); +} + +static int dtext_prepare_text(AVFilterContext *ctx, int width, int height) +{ + DrawTextContext *dtext = ctx->priv; + uint32_t code = 0, prev_code = 0; + int x = 0, y = 0, i = 0, ret; + int text_height, baseline; + char *text = dtext->text; + uint8_t *p; + int str_w = 0, len; + int y_min = 32000, y_max = -32000; + FT_Vector delta; + Glyph *glyph = NULL, *prev_glyph = NULL; + Glyph dummy = { 0 }; + +#if HAVE_LOCALTIME_R + time_t now = time(0); + struct tm ltime; + uint8_t *buf = dtext->expanded_text; + int buf_size = dtext->expanded_text_size; + + if (!buf) + buf_size = 2*strlen(dtext->text)+1; + + localtime_r(&now, <ime); + + while ((buf = av_realloc(buf, buf_size))) { + *buf = 1; + if (strftime(buf, buf_size, dtext->text, <ime) != 0 || *buf == 0) + break; + buf_size *= 2; + } + + if (!buf) + return AVERROR(ENOMEM); + text = dtext->expanded_text = buf; + dtext->expanded_text_size = buf_size; +#endif + + if ((len = strlen(text)) > dtext->nb_positions) { + FT_Vector *p = av_realloc(dtext->positions, + len * sizeof(*dtext->positions)); + if (!p) { + av_freep(dtext->positions); + dtext->nb_positions = 0; + return AVERROR(ENOMEM); + } else { + dtext->positions = p; + dtext->nb_positions = len; + } + } + + /* load and cache glyphs */ + for (i = 0, p = text; *p; i++) { + GET_UTF8(code, *p++, continue;); + + /* get glyph */ + dummy.code = code; + glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL); + if (!glyph) + ret = load_glyph(ctx, &glyph, code); + if (ret) return ret; + + y_min = FFMIN(glyph->bbox.yMin, y_min); + y_max = FFMAX(glyph->bbox.yMax, y_max); + } + text_height = y_max - y_min; + baseline = y_max; + + /* compute and save position for each glyph */ + glyph = NULL; + for (i = 0, p = text; *p; i++) { + GET_UTF8(code, *p++, continue;); + + /* skip the \n in the sequence \r\n */ + if (prev_code == '\r' && code == '\n') + continue; + + prev_code = code; + if (is_newline(code)) { + str_w = FFMAX(str_w, x - dtext->x); + y += text_height; + x = 0; + continue; + } + + /* get glyph */ + prev_glyph = glyph; + dummy.code = code; + glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL); + + /* kerning */ + if (dtext->use_kerning && prev_glyph && glyph->code) { + FT_Get_Kerning(dtext->face, prev_glyph->code, glyph->code, + ft_kerning_default, &delta); + x += delta.x >> 6; + } + + if (x + glyph->bbox.xMax >= width) { + str_w = FFMAX(str_w, x); + y += text_height; + x = 0; + } + + /* save position */ + dtext->positions[i].x = x + glyph->bitmap_left; + dtext->positions[i].y = y - glyph->bitmap_top + baseline; + if (code == '\t') x = (x / dtext->tabsize + 1)*dtext->tabsize; + else x += glyph->advance; + } + + str_w = FFMIN(width - 1, FFMAX(str_w, x)); + y = FFMIN(y + text_height, height - 1); + + dtext->w = str_w; + dtext->h = y; + + return 0; +} + + static int config_input(AVFilterLink *inlink) { - DrawTextContext *dtext = inlink->dst->priv; + AVFilterContext *ctx = inlink->dst; + DrawTextContext *dtext = ctx->priv; const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format]; int ret; @@ -398,7 +524,7 @@ static int config_input(AVFilterLink *inlink) dtext->shadowcolor[3] = rgba[3]; } - return 0; + return dtext_prepare_text(ctx, ctx->inputs[0]->w, ctx->inputs[0]->h); } #define GET_BITMAP_VAL(r, c) \ @@ -499,11 +625,6 @@ static inline void drawbox(AVFilterBufferRef *picref, unsigned int x, unsigned i } } -static inline int is_newline(uint32_t c) -{ - return (c == '\n' || c == '\r' || c == '\f' || c == '\v'); -} - static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref, int width, int height, const uint8_t rgbcolor[4], const uint8_t yuvcolor[4], int x, int y) { @@ -542,128 +663,6 @@ static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref, return 0; } -static int dtext_prepare_text(AVFilterContext *ctx, int width, int height) -{ - DrawTextContext *dtext = ctx->priv; - uint32_t code = 0, prev_code = 0; - int x = 0, y = 0, i = 0, ret; - int text_height, baseline; - char *text = dtext->text; - uint8_t *p; - int str_w = 0, len; - int y_min = 32000, y_max = -32000; - FT_Vector delta; - Glyph *glyph = NULL, *prev_glyph = NULL; - Glyph dummy = { 0 }; - -#if HAVE_LOCALTIME_R - time_t now = time(0); - struct tm ltime; - uint8_t *buf = dtext->expanded_text; - int buf_size = dtext->expanded_text_size; - - if (!buf) { - buf_size = 2*strlen(dtext->text)+1; - buf = av_malloc(buf_size); - } - - localtime_r(&now, <ime); - - do { - *buf = 1; - if (strftime(buf, buf_size, dtext->text, <ime) != 0 || *buf == 0) - break; - buf_size *= 2; - } while ((buf = av_realloc(buf, buf_size))); - - if (!buf) - return AVERROR(ENOMEM); - text = dtext->expanded_text = buf; - dtext->expanded_text_size = buf_size; -#endif - - if ((len = strlen(text)) > dtext->nb_positions) { - FT_Vector *p = av_realloc(dtext->positions, - len * sizeof(*dtext->positions)); - if (!p) { - av_freep(dtext->positions); - dtext->nb_positions = 0; - return AVERROR(ENOMEM); - } else { - dtext->positions = p; - dtext->nb_positions = len; - } - } - - /* load and cache glyphs */ - for (i = 0, p = text; *p; i++) { - GET_UTF8(code, *p++, continue;); - - /* get glyph */ - dummy.code = code; - glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL); - if (!glyph) - ret = load_glyph(ctx, &glyph, code); - if (ret) return ret; - - y_min = FFMIN(glyph->bbox.yMin, y_min); - y_max = FFMAX(glyph->bbox.yMax, y_max); - } - text_height = y_max - y_min; - baseline = y_max; - - /* compute and save position for each glyph */ - glyph = NULL; - for (i = 0, p = text; *p; i++) { - GET_UTF8(code, *p++, continue;); - - /* skip the \n in the sequence \r\n */ - if (prev_code == '\r' && code == '\n') - continue; - - prev_code = code; - if (is_newline(code)) { - str_w = FFMAX(str_w, x - dtext->x); - y += text_height; - x = 0; - continue; - } - - /* get glyph */ - prev_glyph = glyph; - dummy.code = code; - glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL); - - /* kerning */ - if (dtext->use_kerning && prev_glyph && glyph->code) { - FT_Get_Kerning(dtext->face, prev_glyph->code, glyph->code, - ft_kerning_default, &delta); - x += delta.x >> 6; - } - - if (x + glyph->bbox.xMax >= width) { - str_w = FFMAX(str_w, x); - y += text_height; - x = 0; - } - - /* save position */ - dtext->positions[i].x = x + glyph->bitmap_left; - dtext->positions[i].y = y - glyph->bitmap_top + baseline; - if (code == '\t') x = (x / dtext->tabsize + 1)*dtext->tabsize; - else x += glyph->advance; - } - - str_w = FFMIN(width - 1, FFMAX(str_w, x)); - y = FFMIN(y + text_height, height - 1); - - dtext->w = str_w; - dtext->h = y; - - return 0; -} - - static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref, int width, int height) { @@ -702,9 +701,10 @@ static void end_frame(AVFilterLink *inlink) { AVFilterLink *outlink = inlink->dst->outputs[0]; AVFilterBufferRef *picref = inlink->cur_buf; - - dtext_prepare_text(inlink->dst, picref->video->w, picref->video->h); - draw_text(inlink->dst, picref, picref->video->w, picref->video->h); + int err = dtext_prepare_text(inlink->dst, + picref->video->w, picref->video->h); + if (!err) + draw_text(inlink->dst, picref, picref->video->w, picref->video->h); avfilter_draw_slice(outlink, 0, picref->video->h, 1); avfilter_end_frame(outlink); -- cgit v1.2.3