Browse code

drawtext: manage memory allocation better

Call dtext_prepare_text as early as possible
Do not draw if the memory allocation failed

Luca Barbato authored on 2011/12/01 19:27:19
Showing 1 changed files
... ...
@@ -369,9 +369,135 @@ static av_cold void uninit(AVFilterContext *ctx)
369 369
 
370 370
 }
371 371
 
372
+static inline int is_newline(uint32_t c)
373
+{
374
+    return (c == '\n' || c == '\r' || c == '\f' || c == '\v');
375
+}
376
+
377
+static int dtext_prepare_text(AVFilterContext *ctx, int width, int height)
378
+{
379
+    DrawTextContext *dtext = ctx->priv;
380
+    uint32_t code = 0, prev_code = 0;
381
+    int x = 0, y = 0, i = 0, ret;
382
+    int text_height, baseline;
383
+    char *text = dtext->text;
384
+    uint8_t *p;
385
+    int str_w = 0, len;
386
+    int y_min = 32000, y_max = -32000;
387
+    FT_Vector delta;
388
+    Glyph *glyph = NULL, *prev_glyph = NULL;
389
+    Glyph dummy = { 0 };
390
+
391
+#if HAVE_LOCALTIME_R
392
+    time_t now = time(0);
393
+    struct tm ltime;
394
+    uint8_t *buf = dtext->expanded_text;
395
+    int buf_size = dtext->expanded_text_size;
396
+
397
+    if (!buf)
398
+        buf_size = 2*strlen(dtext->text)+1;
399
+
400
+    localtime_r(&now, &ltime);
401
+
402
+    while ((buf = av_realloc(buf, buf_size))) {
403
+        *buf = 1;
404
+        if (strftime(buf, buf_size, dtext->text, &ltime) != 0 || *buf == 0)
405
+            break;
406
+        buf_size *= 2;
407
+    }
408
+
409
+    if (!buf)
410
+        return AVERROR(ENOMEM);
411
+    text = dtext->expanded_text = buf;
412
+    dtext->expanded_text_size = buf_size;
413
+#endif
414
+
415
+    if ((len = strlen(text)) > dtext->nb_positions) {
416
+        FT_Vector *p = av_realloc(dtext->positions,
417
+                                  len * sizeof(*dtext->positions));
418
+        if (!p) {
419
+            av_freep(dtext->positions);
420
+            dtext->nb_positions = 0;
421
+            return AVERROR(ENOMEM);
422
+        } else {
423
+            dtext->positions = p;
424
+            dtext->nb_positions = len;
425
+        }
426
+    }
427
+
428
+    /* load and cache glyphs */
429
+    for (i = 0, p = text; *p; i++) {
430
+        GET_UTF8(code, *p++, continue;);
431
+
432
+        /* get glyph */
433
+        dummy.code = code;
434
+        glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL);
435
+        if (!glyph)
436
+            ret = load_glyph(ctx, &glyph, code);
437
+        if (ret) return ret;
438
+
439
+        y_min = FFMIN(glyph->bbox.yMin, y_min);
440
+        y_max = FFMAX(glyph->bbox.yMax, y_max);
441
+    }
442
+    text_height = y_max - y_min;
443
+    baseline    = y_max;
444
+
445
+    /* compute and save position for each glyph */
446
+    glyph = NULL;
447
+    for (i = 0, p = text; *p; i++) {
448
+        GET_UTF8(code, *p++, continue;);
449
+
450
+        /* skip the \n in the sequence \r\n */
451
+        if (prev_code == '\r' && code == '\n')
452
+            continue;
453
+
454
+        prev_code = code;
455
+        if (is_newline(code)) {
456
+            str_w = FFMAX(str_w, x - dtext->x);
457
+            y += text_height;
458
+            x = 0;
459
+            continue;
460
+        }
461
+
462
+        /* get glyph */
463
+        prev_glyph = glyph;
464
+        dummy.code = code;
465
+        glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL);
466
+
467
+        /* kerning */
468
+        if (dtext->use_kerning && prev_glyph && glyph->code) {
469
+            FT_Get_Kerning(dtext->face, prev_glyph->code, glyph->code,
470
+                           ft_kerning_default, &delta);
471
+            x += delta.x >> 6;
472
+        }
473
+
474
+        if (x + glyph->bbox.xMax >= width) {
475
+            str_w = FFMAX(str_w, x);
476
+            y += text_height;
477
+            x = 0;
478
+        }
479
+
480
+        /* save position */
481
+        dtext->positions[i].x = x + glyph->bitmap_left;
482
+        dtext->positions[i].y = y - glyph->bitmap_top + baseline;
483
+        if (code == '\t') x  = (x / dtext->tabsize + 1)*dtext->tabsize;
484
+        else              x += glyph->advance;
485
+    }
486
+
487
+    str_w = FFMIN(width - 1, FFMAX(str_w, x));
488
+    y     = FFMIN(y + text_height, height - 1);
489
+
490
+    dtext->w = str_w;
491
+    dtext->h = y;
492
+
493
+    return 0;
494
+}
495
+
496
+
372 497
 static int config_input(AVFilterLink *inlink)
373 498
 {
374
-    DrawTextContext *dtext = inlink->dst->priv;
499
+    AVFilterContext *ctx  = inlink->dst;
500
+    DrawTextContext *dtext = ctx->priv;
375 501
     const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format];
376 502
     int ret;
377 503
 
... ...
@@ -398,7 +524,7 @@ static int config_input(AVFilterLink *inlink)
398 398
         dtext->shadowcolor[3] = rgba[3];
399 399
     }
400 400
 
401
-    return 0;
401
+    return dtext_prepare_text(ctx, ctx->inputs[0]->w, ctx->inputs[0]->h);
402 402
 }
403 403
 
404 404
 #define GET_BITMAP_VAL(r, c)                                            \
... ...
@@ -499,11 +625,6 @@ static inline void drawbox(AVFilterBufferRef *picref, unsigned int x, unsigned i
499 499
     }
500 500
 }
501 501
 
502
-static inline int is_newline(uint32_t c)
503
-{
504
-    return (c == '\n' || c == '\r' || c == '\f' || c == '\v');
505
-}
506
-
507 502
 static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref,
508 503
                        int width, int height, const uint8_t rgbcolor[4], const uint8_t yuvcolor[4], int x, int y)
509 504
 {
... ...
@@ -542,128 +663,6 @@ static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref,
542 542
     return 0;
543 543
 }
544 544
 
545
-static int dtext_prepare_text(AVFilterContext *ctx, int width, int height)
546
-{
547
-    DrawTextContext *dtext = ctx->priv;
548
-    uint32_t code = 0, prev_code = 0;
549
-    int x = 0, y = 0, i = 0, ret;
550
-    int text_height, baseline;
551
-    char *text = dtext->text;
552
-    uint8_t *p;
553
-    int str_w = 0, len;
554
-    int y_min = 32000, y_max = -32000;
555
-    FT_Vector delta;
556
-    Glyph *glyph = NULL, *prev_glyph = NULL;
557
-    Glyph dummy = { 0 };
558
-
559
-#if HAVE_LOCALTIME_R
560
-    time_t now = time(0);
561
-    struct tm ltime;
562
-    uint8_t *buf = dtext->expanded_text;
563
-    int buf_size = dtext->expanded_text_size;
564
-
565
-    if (!buf) {
566
-        buf_size = 2*strlen(dtext->text)+1;
567
-        buf = av_malloc(buf_size);
568
-    }
569
-
570
-    localtime_r(&now, &ltime);
571
-
572
-    do {
573
-        *buf = 1;
574
-        if (strftime(buf, buf_size, dtext->text, &ltime) != 0 || *buf == 0)
575
-            break;
576
-        buf_size *= 2;
577
-    } while ((buf = av_realloc(buf, buf_size)));
578
-
579
-    if (!buf)
580
-        return AVERROR(ENOMEM);
581
-    text = dtext->expanded_text = buf;
582
-    dtext->expanded_text_size = buf_size;
583
-#endif
584
-
585
-    if ((len = strlen(text)) > dtext->nb_positions) {
586
-        FT_Vector *p = av_realloc(dtext->positions,
587
-                                  len * sizeof(*dtext->positions));
588
-        if (!p) {
589
-            av_freep(dtext->positions);
590
-            dtext->nb_positions = 0;
591
-            return AVERROR(ENOMEM);
592
-        } else {
593
-            dtext->positions = p;
594
-            dtext->nb_positions = len;
595
-        }
596
-    }
597
-
598
-    /* load and cache glyphs */
599
-    for (i = 0, p = text; *p; i++) {
600
-        GET_UTF8(code, *p++, continue;);
601
-
602
-        /* get glyph */
603
-        dummy.code = code;
604
-        glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL);
605
-        if (!glyph)
606
-            ret = load_glyph(ctx, &glyph, code);
607
-        if (ret) return ret;
608
-
609
-        y_min = FFMIN(glyph->bbox.yMin, y_min);
610
-        y_max = FFMAX(glyph->bbox.yMax, y_max);
611
-    }
612
-    text_height = y_max - y_min;
613
-    baseline    = y_max;
614
-
615
-    /* compute and save position for each glyph */
616
-    glyph = NULL;
617
-    for (i = 0, p = text; *p; i++) {
618
-        GET_UTF8(code, *p++, continue;);
619
-
620
-        /* skip the \n in the sequence \r\n */
621
-        if (prev_code == '\r' && code == '\n')
622
-            continue;
623
-
624
-        prev_code = code;
625
-        if (is_newline(code)) {
626
-            str_w = FFMAX(str_w, x - dtext->x);
627
-            y += text_height;
628
-            x = 0;
629
-            continue;
630
-        }
631
-
632
-        /* get glyph */
633
-        prev_glyph = glyph;
634
-        dummy.code = code;
635
-        glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL);
636
-
637
-        /* kerning */
638
-        if (dtext->use_kerning && prev_glyph && glyph->code) {
639
-            FT_Get_Kerning(dtext->face, prev_glyph->code, glyph->code,
640
-                           ft_kerning_default, &delta);
641
-            x += delta.x >> 6;
642
-        }
643
-
644
-        if (x + glyph->bbox.xMax >= width) {
645
-            str_w = FFMAX(str_w, x);
646
-            y += text_height;
647
-            x = 0;
648
-        }
649
-
650
-        /* save position */
651
-        dtext->positions[i].x = x + glyph->bitmap_left;
652
-        dtext->positions[i].y = y - glyph->bitmap_top + baseline;
653
-        if (code == '\t') x  = (x / dtext->tabsize + 1)*dtext->tabsize;
654
-        else              x += glyph->advance;
655
-    }
656
-
657
-    str_w = FFMIN(width - 1, FFMAX(str_w, x));
658
-    y     = FFMIN(y + text_height, height - 1);
659
-
660
-    dtext->w = str_w;
661
-    dtext->h = y;
662
-
663
-    return 0;
664
-}
665
-
666
-
667 545
 static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
668 546
                      int width, int height)
669 547
 {
... ...
@@ -702,9 +701,10 @@ static void end_frame(AVFilterLink *inlink)
702 702
 {
703 703
     AVFilterLink *outlink = inlink->dst->outputs[0];
704 704
     AVFilterBufferRef *picref = inlink->cur_buf;
705
-
706
-    dtext_prepare_text(inlink->dst, picref->video->w, picref->video->h);
707
-    draw_text(inlink->dst, picref, picref->video->w, picref->video->h);
705
+    int err = dtext_prepare_text(inlink->dst,
706
+                                 picref->video->w, picref->video->h);
707
+    if (!err)
708
+        draw_text(inlink->dst, picref, picref->video->w, picref->video->h);
708 709
 
709 710
     avfilter_draw_slice(outlink, 0, picref->video->h, 1);
710 711
     avfilter_end_frame(outlink);