Merge commit '6b9b42cc5576e1819ad1e29d98940066fd14b2d6'
authorMichael Niedermayer <michaelni@gmx.at>
Sun, 26 Oct 2014 02:12:37 +0000 (03:12 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Sun, 26 Oct 2014 02:12:37 +0000 (03:12 +0100)
* commit '6b9b42cc5576e1819ad1e29d98940066fd14b2d6':
  drawtext: Remove the ifdef for localtime_r

Conflicts:
libavfilter/vf_drawtext.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavfilter/vf_drawtext.c

  #include "libavutil/file.h"
  #include "libavutil/eval.h"
  #include "libavutil/opt.h"
 -#include "libavutil/mathematics.h"
  #include "libavutil/random_seed.h"
  #include "libavutil/parseutils.h"
 -#include "libavutil/pixdesc.h"
 +#include "libavutil/timecode.h"
+ #include "libavutil/time_internal.h"
  #include "libavutil/tree.h"
  #include "libavutil/lfg.h"
  #include "avfilter.h"
@@@ -843,216 -643,165 +844,209 @@@ static int func_metadata(AVFilterContex
      return 0;
  }
  
- #if !HAVE_LOCALTIME_R
- static void localtime_r(const time_t *t, struct tm *tm)
- {
-     *tm = *localtime(t);
- }
- #endif
 +static int func_strftime(AVFilterContext *ctx, AVBPrint *bp,
 +                         char *fct, unsigned argc, char **argv, int tag)
 +{
 +    const char *fmt = argc ? argv[0] : "%Y-%m-%d %H:%M:%S";
 +    time_t now;
 +    struct tm tm;
  
 -static int config_input(AVFilterLink *inlink)
 +    time(&now);
 +    if (tag == 'L')
 +        localtime_r(&now, &tm);
 +    else
 +        tm = *gmtime(&now);
 +    av_bprint_strftime(bp, fmt, &tm);
 +    return 0;
 +}
 +
 +static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp,
 +                          char *fct, unsigned argc, char **argv, int tag)
  {
 -    AVFilterContext *ctx  = inlink->dst;
      DrawTextContext *s = ctx->priv;
 -    const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
 +    double res;
      int ret;
  
 -    s->hsub = pix_desc->log2_chroma_w;
 -    s->vsub = pix_desc->log2_chroma_h;
 +    ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
 +                                 NULL, NULL, fun2_names, fun2,
 +                                 &s->prng, 0, ctx);
 +    if (ret < 0)
 +        av_log(ctx, AV_LOG_ERROR,
 +               "Expression '%s' for the expr text expansion function is not valid\n",
 +               argv[0]);
 +    else
 +        av_bprintf(bp, "%f", res);
  
 -    s->var_values[VAR_E  ] = M_E;
 -    s->var_values[VAR_PHI] = M_PHI;
 -    s->var_values[VAR_PI ] = M_PI;
 +    return ret;
 +}
  
 -    s->var_values[VAR_MAIN_W] =
 -        s->var_values[VAR_MW] = ctx->inputs[0]->w;
 -    s->var_values[VAR_MAIN_H] =
 -        s->var_values[VAR_MH] = ctx->inputs[0]->h;
 +static int func_eval_expr_int_format(AVFilterContext *ctx, AVBPrint *bp,
 +                          char *fct, unsigned argc, char **argv, int tag)
 +{
 +    DrawTextContext *s = ctx->priv;
 +    double res;
 +    int intval;
 +    int ret;
 +    unsigned int positions = 0;
 +    char fmt_str[30] = "%";
 +
 +    /*
 +     * argv[0] expression to be converted to `int`
 +     * argv[1] format: 'x', 'X', 'd' or 'u'
 +     * argv[2] positions printed (optional)
 +     */
 +
 +    ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
 +                                 NULL, NULL, fun2_names, fun2,
 +                                 &s->prng, 0, ctx);
 +    if (ret < 0) {
 +        av_log(ctx, AV_LOG_ERROR,
 +               "Expression '%s' for the expr text expansion function is not valid\n",
 +               argv[0]);
 +        return ret;
 +    }
  
 -    s->var_values[VAR_X] = 0;
 -    s->var_values[VAR_Y] = 0;
 -    s->var_values[VAR_T] = NAN;
 +    if (!strchr("xXdu", argv[1][0])) {
 +        av_log(ctx, AV_LOG_ERROR, "Invalid format '%c' specified,"
 +                " allowed values: 'x', 'X', 'd', 'u'\n", argv[1][0]);
 +        return AVERROR(EINVAL);
 +    }
  
 -    av_lfg_init(&s->prng, av_get_random_seed());
 +    if (argc == 3) {
 +        ret = sscanf(argv[2], "%u", &positions);
 +        if (ret != 1) {
 +            av_log(ctx, AV_LOG_ERROR, "expr_int_format(): Invalid number of positions"
 +                    " to print: '%s'\n", argv[2]);
 +            return AVERROR(EINVAL);
 +        }
 +    }
  
 -    av_expr_free(s->x_pexpr);
 -    av_expr_free(s->y_pexpr);
 -    av_expr_free(s->d_pexpr);
 -    s->x_pexpr = s->y_pexpr = s->d_pexpr = NULL;
 -    if ((ret = av_expr_parse(&s->x_pexpr, s->x_expr, var_names,
 -                             NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
 -        (ret = av_expr_parse(&s->y_pexpr, s->y_expr, var_names,
 -                             NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
 -        (ret = av_expr_parse(&s->d_pexpr, s->d_expr, var_names,
 -                             NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
 +    feclearexcept(FE_ALL_EXCEPT);
 +    intval = res;
 +    if ((ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) {
 +        av_log(ctx, AV_LOG_ERROR, "Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n", ret, intval);
          return AVERROR(EINVAL);
 +    }
  
 -    if ((ret =
 -         ff_fill_line_with_color(s->box_line, s->pixel_step,
 -                                 inlink->w, s->boxcolor,
 -                                 inlink->format, s->boxcolor_rgba,
 -                                 &s->is_packed_rgb, s->rgba_map)) < 0)
 -        return ret;
 +    if (argc == 3)
 +        av_strlcatf(fmt_str, sizeof(fmt_str), "0%u", positions);
 +    av_strlcatf(fmt_str, sizeof(fmt_str), "%c", argv[1][0]);
  
 -    if (!s->is_packed_rgb) {
 -        uint8_t *rgba = s->fontcolor_rgba;
 -        s->fontcolor[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
 -        s->fontcolor[1] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
 -        s->fontcolor[2] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
 -        s->fontcolor[3] = rgba[3];
 -        rgba = s->shadowcolor_rgba;
 -        s->shadowcolor[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
 -        s->shadowcolor[1] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
 -        s->shadowcolor[2] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
 -        s->shadowcolor[3] = rgba[3];
 -    }
 +    av_log(ctx, AV_LOG_DEBUG, "Formatting value %f (expr '%s') with spec '%s'\n",
 +            res, argv[0], fmt_str);
  
 -    s->draw = 1;
 +    av_bprintf(bp, fmt_str, intval);
  
 -    return dtext_prepare_text(ctx);
 +    return 0;
  }
  
 -#define GET_BITMAP_VAL(r, c)                                            \
 -    bitmap->pixel_mode == FT_PIXEL_MODE_MONO ?                          \
 -        (bitmap->buffer[(r) * bitmap->pitch + ((c)>>3)] & (0x80 >> ((c)&7))) * 255 : \
 -         bitmap->buffer[(r) * bitmap->pitch +  (c)]
 -
 -#define SET_PIXEL_YUV(frame, yuva_color, val, x, y, hsub, vsub) {           \
 -    luma_pos    = ((x)          ) + ((y)          ) * frame->linesize[0]; \
 -    alpha = yuva_color[3] * (val) * 129;                               \
 -    frame->data[0][luma_pos]    = (alpha * yuva_color[0] + (255*255*129 - alpha) * frame->data[0][luma_pos]   ) >> 23; \
 -    if (((x) & ((1<<(hsub)) - 1)) == 0 && ((y) & ((1<<(vsub)) - 1)) == 0) {\
 -        chroma_pos1 = ((x) >> (hsub)) + ((y) >> (vsub)) * frame->linesize[1]; \
 -        chroma_pos2 = ((x) >> (hsub)) + ((y) >> (vsub)) * frame->linesize[2]; \
 -        frame->data[1][chroma_pos1] = (alpha * yuva_color[1] + (255*255*129 - alpha) * frame->data[1][chroma_pos1]) >> 23; \
 -        frame->data[2][chroma_pos2] = (alpha * yuva_color[2] + (255*255*129 - alpha) * frame->data[2][chroma_pos2]) >> 23; \
 -    }\
 -}
 +static const struct drawtext_function {
 +    const char *name;
 +    unsigned argc_min, argc_max;
 +    int tag;                            /**< opaque argument to func */
 +    int (*func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int);
 +} functions[] = {
 +    { "expr",      1, 1, 0,   func_eval_expr },
 +    { "e",         1, 1, 0,   func_eval_expr },
 +    { "expr_int_format", 2, 3, 0, func_eval_expr_int_format },
 +    { "eif",       2, 3, 0,   func_eval_expr_int_format },
 +    { "pict_type", 0, 0, 0,   func_pict_type },
 +    { "pts",       0, 2, 0,   func_pts      },
 +    { "gmtime",    0, 1, 'G', func_strftime },
 +    { "localtime", 0, 1, 'L', func_strftime },
 +    { "frame_num", 0, 0, 0,   func_frame_num },
 +    { "n",         0, 0, 0,   func_frame_num },
 +    { "metadata",  1, 1, 0,   func_metadata },
 +};
  
 -static inline int draw_glyph_yuv(AVFrame *frame, FT_Bitmap *bitmap, unsigned int x,
 -                                 unsigned int y, unsigned int width, unsigned int height,
 -                                 const uint8_t yuva_color[4], int hsub, int vsub)
 +static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct,
 +                         unsigned argc, char **argv)
  {
 -    int r, c, alpha;
 -    unsigned int luma_pos, chroma_pos1, chroma_pos2;
 -    uint8_t src_val;
 -
 -    for (r = 0; r < bitmap->rows && r+y < height; r++) {
 -        for (c = 0; c < bitmap->width && c+x < width; c++) {
 -            /* get intensity value in the glyph bitmap (source) */
 -            src_val = GET_BITMAP_VAL(r, c);
 -            if (!src_val)
 -                continue;
 -
 -            SET_PIXEL_YUV(frame, yuva_color, src_val, c+x, y+r, hsub, vsub);
 +    unsigned i;
 +
 +    for (i = 0; i < FF_ARRAY_ELEMS(functions); i++) {
 +        if (strcmp(fct, functions[i].name))
 +            continue;
 +        if (argc < functions[i].argc_min) {
 +            av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at least %d arguments\n",
 +                   fct, functions[i].argc_min);
 +            return AVERROR(EINVAL);
          }
 +        if (argc > functions[i].argc_max) {
 +            av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at most %d arguments\n",
 +                   fct, functions[i].argc_max);
 +            return AVERROR(EINVAL);
 +        }
 +        break;
      }
 -
 -    return 0;
 -}
 -
 -#define SET_PIXEL_RGB(frame, rgba_color, val, x, y, pixel_step, r_off, g_off, b_off, a_off) { \
 -    p   = frame->data[0] + (x) * pixel_step + ((y) * frame->linesize[0]); \
 -    alpha = rgba_color[3] * (val) * 129;                              \
 -    *(p+r_off) = (alpha * rgba_color[0] + (255*255*129 - alpha) * *(p+r_off)) >> 23; \
 -    *(p+g_off) = (alpha * rgba_color[1] + (255*255*129 - alpha) * *(p+g_off)) >> 23; \
 -    *(p+b_off) = (alpha * rgba_color[2] + (255*255*129 - alpha) * *(p+b_off)) >> 23; \
 +    if (i >= FF_ARRAY_ELEMS(functions)) {
 +        av_log(ctx, AV_LOG_ERROR, "%%{%s} is not known\n", fct);
 +        return AVERROR(EINVAL);
 +    }
 +    return functions[i].func(ctx, bp, fct, argc, argv, functions[i].tag);
  }
  
 -static inline int draw_glyph_rgb(AVFrame *frame, FT_Bitmap *bitmap,
 -                                 unsigned int x, unsigned int y,
 -                                 unsigned int width, unsigned int height, int pixel_step,
 -                                 const uint8_t rgba_color[4], const uint8_t rgba_map[4])
 +static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
  {
 -    int r, c, alpha;
 -    uint8_t *p;
 -    uint8_t src_val;
 -
 -    for (r = 0; r < bitmap->rows && r+y < height; r++) {
 -        for (c = 0; c < bitmap->width && c+x < width; c++) {
 -            /* get intensity value in the glyph bitmap (source) */
 -            src_val = GET_BITMAP_VAL(r, c);
 -            if (!src_val)
 -                continue;
 +    const char *text = *rtext;
 +    char *argv[16] = { NULL };
 +    unsigned argc = 0, i;
 +    int ret;
  
 -            SET_PIXEL_RGB(frame, rgba_color, src_val, c+x, y+r, pixel_step,
 -                          rgba_map[0], rgba_map[1], rgba_map[2], rgba_map[3]);
 +    if (*text != '{') {
 +        av_log(ctx, AV_LOG_ERROR, "Stray %% near '%s'\n", text);
 +        return AVERROR(EINVAL);
 +    }
 +    text++;
 +    while (1) {
 +        if (!(argv[argc++] = av_get_token(&text, ":}"))) {
 +            ret = AVERROR(ENOMEM);
 +            goto end;
 +        }
 +        if (!*text) {
 +            av_log(ctx, AV_LOG_ERROR, "Unterminated %%{} near '%s'\n", *rtext);
 +            ret = AVERROR(EINVAL);
 +            goto end;
          }
 +        if (argc == FF_ARRAY_ELEMS(argv))
 +            av_freep(&argv[--argc]); /* error will be caught later */
 +        if (*text == '}')
 +            break;
 +        text++;
      }
  
 -    return 0;
 +    if ((ret = eval_function(ctx, bp, argv[0], argc - 1, argv + 1)) < 0)
 +        goto end;
 +    ret = 0;
 +    *rtext = (char *)text + 1;
 +
 +end:
 +    for (i = 0; i < argc; i++)
 +        av_freep(&argv[i]);
 +    return ret;
  }
  
 -static inline void drawbox(AVFrame *frame, unsigned int x, unsigned int y,
 -                           unsigned int width, unsigned int height,
 -                           uint8_t *line[4], int pixel_step[4], uint8_t color[4],
 -                           int hsub, int vsub, int is_rgba_packed, uint8_t rgba_map[4])
 +static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
  {
 -    int i, j, alpha;
 -
 -    if (color[3] != 0xFF) {
 -        if (is_rgba_packed) {
 -            uint8_t *p;
 -            for (j = 0; j < height; j++)
 -                for (i = 0; i < width; i++)
 -                    SET_PIXEL_RGB(frame, color, 255, i+x, y+j, pixel_step[0],
 -                                  rgba_map[0], rgba_map[1], rgba_map[2], rgba_map[3]);
 +    int ret;
 +
 +    av_bprint_clear(bp);
 +    while (*text) {
 +        if (*text == '\\' && text[1]) {
 +            av_bprint_chars(bp, text[1], 1);
 +            text += 2;
 +        } else if (*text == '%') {
 +            text++;
 +            if ((ret = expand_function(ctx, bp, &text)) < 0)
 +                return ret;
          } else {
 -            unsigned int luma_pos, chroma_pos1, chroma_pos2;
 -            for (j = 0; j < height; j++)
 -                for (i = 0; i < width; i++)
 -                    SET_PIXEL_YUV(frame, color, 255, i+x, y+j, hsub, vsub);
 +            av_bprint_chars(bp, *text, 1);
 +            text++;
          }
 -    } else {
 -        ff_draw_rectangle(frame->data, frame->linesize,
 -                          line, pixel_step, hsub, vsub,
 -                          x, y, width, height);
      }
 +    if (!av_bprint_is_complete(bp))
 +        return AVERROR(ENOMEM);
 +    return 0;
  }
  
  static int draw_glyphs(DrawTextContext *s, AVFrame *frame,