Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / ffmpeg / libavfilter / avf_showcqt.c
index 60e8129..e650f74 100644 (file)
@@ -26,6 +26,7 @@
 #include "libavutil/xga_font_data.h"
 #include "libavutil/qsort.h"
 #include "libavutil/time.h"
+#include "libavutil/eval.h"
 #include "avfilter.h"
 #include "internal.h"
 
 #define SPECTOGRAM_START (VIDEO_HEIGHT-SPECTOGRAM_HEIGHT)
 #define BASE_FREQ 20.051392800492
 #define COEFF_CLAMP 1.0e-4
+#define TLENGTH_MIN 0.001
+#define TLENGTH_DEFAULT "384/f*tc/(384/f+tc)"
+#define VOLUME_MIN 1e-10
+#define VOLUME_MAX 100.0
+#define FONTCOLOR_DEFAULT "st(0, (midi(f)-59.5)/12);" \
+    "st(1, if(between(ld(0),0,1), 0.5-0.5*cos(2*PI*ld(0)), 0));" \
+    "r(1-ld(1)) + b(ld(1))"
 
 typedef struct {
     FFTSample value;
@@ -68,14 +76,16 @@ typedef struct {
     uint8_t *font_alpha;
     char *fontfile;     /* using freetype */
     int coeffs_len[VIDEO_WIDTH];
-    uint8_t font_color[VIDEO_WIDTH];
+    uint8_t fontcolor_value[VIDEO_WIDTH*3];  /* result of fontcolor option */
     int64_t frame_count;
     int spectogram_count;
     int spectogram_index;
     int fft_bits;
     int req_fullfilled;
     int remaining_fill;
-    double volume;
+    char *tlength;
+    char *volume;
+    char *fontcolor;
     double timeclamp;   /* lower timeclamp, time-accurate, higher timeclamp, freq-accurate (at low freq)*/
     float coeffclamp;   /* lower coeffclamp, more precise, higher coeffclamp, faster */
     int fullhd;         /* if true, output video is at full HD resolution, otherwise it will be halved */
@@ -88,7 +98,8 @@ typedef struct {
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 
 static const AVOption showcqt_options[] = {
-    { "volume", "set volume", OFFSET(volume), AV_OPT_TYPE_DOUBLE, { .dbl = 16 }, 0.1, 100, FLAGS },
+    { "volume", "set volume", OFFSET(volume), AV_OPT_TYPE_STRING, { .str = "16" }, CHAR_MIN, CHAR_MAX, FLAGS },
+    { "tlength", "set transform length", OFFSET(tlength), AV_OPT_TYPE_STRING, { .str = TLENGTH_DEFAULT }, CHAR_MIN, CHAR_MAX, FLAGS },
     { "timeclamp", "set timeclamp", OFFSET(timeclamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.17 }, 0.1, 1.0, FLAGS },
     { "coeffclamp", "set coeffclamp", OFFSET(coeffclamp), AV_OPT_TYPE_FLOAT, { .dbl = 1 }, 0.1, 10, FLAGS },
     { "gamma", "set gamma", OFFSET(gamma), AV_OPT_TYPE_FLOAT, { .dbl = 3 }, 1, 7, FLAGS },
@@ -96,6 +107,7 @@ static const AVOption showcqt_options[] = {
     { "fps", "set video fps", OFFSET(fps), AV_OPT_TYPE_INT, { .i64 = 25 }, 10, 100, FLAGS },
     { "count", "set number of transform per frame", OFFSET(count), AV_OPT_TYPE_INT, { .i64 = 6 }, 1, 30, FLAGS },
     { "fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS },
+    { "fontcolor", "set font color", OFFSET(fontcolor), AV_OPT_TYPE_STRING, { .str = FONTCOLOR_DEFAULT }, CHAR_MIN, CHAR_MAX, FLAGS },
     { NULL }
 };
 
@@ -246,6 +258,51 @@ static void load_freetype_font(AVFilterContext *ctx)
 }
 #endif
 
+static double a_weighting(void *p, double f)
+{
+    double ret = 12200.0*12200.0 * (f*f*f*f);
+    ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) *
+           sqrt((f*f + 107.7*107.7) * (f*f + 737.9*737.9));
+    return ret;
+}
+
+static double b_weighting(void *p, double f)
+{
+    double ret = 12200.0*12200.0 * (f*f*f);
+    ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) * sqrt(f*f + 158.5*158.5);
+    return ret;
+}
+
+static double c_weighting(void *p, double f)
+{
+    double ret = 12200.0*12200.0 * (f*f);
+    ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0);
+    return ret;
+}
+
+static double midi(void *p, double f)
+{
+    return log2(f/440.0) * 12.0 + 69.0;
+}
+
+static double r_func(void *p, double x)
+{
+    x = av_clipd(x, 0.0, 1.0);
+    return (int)(x*255.0+0.5) << 16;
+}
+
+static double g_func(void *p, double x)
+{
+    x = av_clipd(x, 0.0, 1.0);
+    return (int)(x*255.0+0.5) << 8;
+}
+
+static double b_func(void *p, double x)
+{
+    x = av_clipd(x, 0.0, 1.0);
+    return (int)(x*255.0+0.5);
+}
+
 static inline int qsort_sparsecoeff(const SparseCoeff *a, const SparseCoeff *b)
 {
     if (fabsf(a->value) >= fabsf(b->value))
@@ -259,7 +316,14 @@ static int config_output(AVFilterLink *outlink)
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowCQTContext *s = ctx->priv;
-    int fft_len, k, x, y;
+    AVExpr *tlength_expr = NULL, *volume_expr = NULL, *fontcolor_expr = NULL;
+    uint8_t *fontcolor_value = s->fontcolor_value;
+    static const char * const expr_vars[] = { "timeclamp", "tc", "frequency", "freq", "f", NULL };
+    static const char * const expr_func_names[] = { "a_weighting", "b_weighting", "c_weighting", NULL };
+    static const char * const expr_fontcolor_func_names[] = { "midi", "r", "g", "b", NULL };
+    static double (* const expr_funcs[])(void *, double) = { a_weighting, b_weighting, c_weighting, NULL };
+    static double (* const expr_fontcolor_funcs[])(void *, double) = { midi, r_func, g_func, b_func, NULL };
+    int fft_len, k, x, y, ret;
     int num_coeffs = 0;
     int rate = inlink->sample_rate;
     double max_len = rate * (double) s->timeclamp;
@@ -286,17 +350,6 @@ static int config_output(AVFilterLink *outlink)
     if (!s->fft_data || !s->coeff_sort || !s->fft_result_left || !s->fft_result_right || !s->fft_context)
         return AVERROR(ENOMEM);
 
-    /* initializing font */
-    for (x = 0; x < video_width; x++) {
-        if (x >= (12*3+8)*8*video_scale && x < (12*4+8)*8*video_scale) {
-            float fx = (x-(12*3+8)*8*video_scale) * (2.0f/(192.0f*video_scale));
-            float sv = sinf(M_PI*fx);
-            s->font_color[x] = sv*sv*255.0f + 0.5f;
-        } else {
-            s->font_color[x] = 0;
-        }
-    }
-
 #if CONFIG_LIBFREETYPE
     load_freetype_font(ctx);
 #else
@@ -307,12 +360,27 @@ static int config_output(AVFilterLink *outlink)
 
     av_log(ctx, AV_LOG_INFO, "Calculating spectral kernel, please wait\n");
     start_time = av_gettime_relative();
+    ret = av_expr_parse(&tlength_expr, s->tlength, expr_vars, NULL, NULL, NULL, NULL, 0, ctx);
+    if (ret < 0)
+        goto eval_error;
+
+    ret = av_expr_parse(&volume_expr, s->volume, expr_vars, expr_func_names,
+                        expr_funcs, NULL, NULL, 0, ctx);
+    if (ret < 0)
+        goto eval_error;
+
+    ret = av_expr_parse(&fontcolor_expr, s->fontcolor, expr_vars, expr_fontcolor_func_names,
+                        expr_fontcolor_funcs, NULL, NULL, 0, ctx);
+    if (ret < 0)
+        goto eval_error;
+
     for (k = 0; k < VIDEO_WIDTH; k++) {
         int hlen = fft_len >> 1;
         float total = 0;
         float partial = 0;
         double freq = BASE_FREQ * exp2(k * (1.0/192.0));
-        double tlen = rate * (24.0 * 16.0) /freq;
+        double tlen, tlength, volume;
+        double expr_vars_val[] = { s->timeclamp, s->timeclamp, freq, freq, freq, 0 };
         /* a window function from Albert H. Nuttall,
          * "Some Windows with Very Good Sidelobe Behavior"
          * -93.32 dB peak sidelobe and 18 dB/octave asymptotic decay
@@ -324,10 +392,41 @@ static int config_output(AVFilterLink *outlink)
         double sv_step, cv_step, sv, cv;
         double sw_step, cw_step, sw, cw, w;
 
-        tlen = tlen * max_len / (tlen + max_len);
+        tlength = av_expr_eval(tlength_expr, expr_vars_val, NULL);
+        if (isnan(tlength)) {
+            av_log(ctx, AV_LOG_WARNING, "at freq %g: tlength is nan, setting it to %g\n", freq, s->timeclamp);
+            tlength = s->timeclamp;
+        } else if (tlength < TLENGTH_MIN) {
+            av_log(ctx, AV_LOG_WARNING, "at freq %g: tlength is %g, setting it to %g\n", freq, tlength, TLENGTH_MIN);
+            tlength = TLENGTH_MIN;
+        } else if (tlength > s->timeclamp) {
+            av_log(ctx, AV_LOG_WARNING, "at freq %g: tlength is %g, setting it to %g\n", freq, tlength, s->timeclamp);
+            tlength = s->timeclamp;
+        }
+
+        volume = FFABS(av_expr_eval(volume_expr, expr_vars_val, NULL));
+        if (isnan(volume)) {
+            av_log(ctx, AV_LOG_WARNING, "at freq %g: volume is nan, setting it to 0\n", freq);
+            volume = VOLUME_MIN;
+        } else if (volume < VOLUME_MIN) {
+            volume = VOLUME_MIN;
+        } else if (volume > VOLUME_MAX) {
+            av_log(ctx, AV_LOG_WARNING, "at freq %g: volume is %g, setting it to %g\n", freq, volume, VOLUME_MAX);
+            volume = VOLUME_MAX;
+        }
+
+        if (s->fullhd || !(k & 1)) {
+            int fontcolor = av_expr_eval(fontcolor_expr, expr_vars_val, NULL);
+            fontcolor_value[0] = (fontcolor >> 16) & 0xFF;
+            fontcolor_value[1] = (fontcolor >> 8) & 0xFF;
+            fontcolor_value[2] = fontcolor & 0xFF;
+            fontcolor_value += 3;
+        }
+
+        tlen = tlength * rate;
         s->fft_data[0].re = 0;
         s->fft_data[0].im = 0;
-        s->fft_data[hlen].re = (1.0 + a1 + a2 + a3) * (1.0/tlen) * s->volume * (1.0/fft_len);
+        s->fft_data[hlen].re = (1.0 + a1 + a2 + a3) * (1.0/tlen) * volume * (1.0/fft_len);
         s->fft_data[hlen].im = 0;
         sv_step = sv = sin(2.0*M_PI*freq*(1.0/rate));
         cv_step = cv = cos(2.0*M_PI*freq*(1.0/rate));
@@ -341,7 +440,7 @@ static int config_output(AVFilterLink *outlink)
             cw2 = cw * cw - sw * sw;
             sw2 = cw * sw + sw * cw;
             cw3 = cw * cw2 - sw * sw2;
-            w = (1.0 + a1 * cw + a2 * cw2 + a3 * cw3) * (1.0/tlen) * s->volume * (1.0/fft_len);
+            w = (1.0 + a1 * cw + a2 * cw2 + a3 * cw3) * (1.0/tlen) * volume * (1.0/fft_len);
             s->fft_data[hlen + x].re = w * cv;
             s->fft_data[hlen + x].im = w * sv;
             s->fft_data[hlen - x].re = s->fft_data[hlen + x].re;
@@ -378,14 +477,19 @@ static int config_output(AVFilterLink *outlink)
                 s->coeffs_len[k] = fft_len - x;
                 num_coeffs += s->coeffs_len[k];
                 s->coeffs[k] = av_malloc_array(s->coeffs_len[k], sizeof(*s->coeffs[k]));
-                if (!s->coeffs[k])
-                    return AVERROR(ENOMEM);
+                if (!s->coeffs[k]) {
+                    ret = AVERROR(ENOMEM);
+                    goto eval_error;
+                }
                 for (y = 0; y < s->coeffs_len[k]; y++)
                     s->coeffs[k][y] = s->coeff_sort[x+y];
                 break;
             }
         }
     }
+    av_expr_free(fontcolor_expr);
+    av_expr_free(volume_expr);
+    av_expr_free(tlength_expr);
     end_time = av_gettime_relative();
     av_log(ctx, AV_LOG_INFO, "Elapsed time %.6f s (fft_len=%u, num_coeffs=%u)\n", 1e-6 * (end_time-start_time), fft_len, num_coeffs);
 
@@ -411,6 +515,12 @@ static int config_output(AVFilterLink *outlink)
     outlink->time_base = av_make_q(1, s->fps);
     outlink->frame_rate = av_make_q(s->fps, 1);
     return 0;
+
+eval_error:
+    av_expr_free(fontcolor_expr);
+    av_expr_free(volume_expr);
+    av_expr_free(tlength_expr);
+    return ret;
 }
 
 static int plot_cqt(AVFilterLink *inlink)
@@ -526,12 +636,13 @@ static int plot_cqt(AVFilterLink *inlink)
             for (y = 0; y < font_height; y++) {
                 uint8_t *lineptr = data + (spectogram_height + y) * linesize;
                 uint8_t *spectogram_src = s->spectogram + s->spectogram_index * linesize;
+                uint8_t *fontcolor_value = s->fontcolor_value;
                 for (x = 0; x < video_width; x++) {
                     uint8_t alpha = s->font_alpha[y*video_width+x];
-                    uint8_t color = s->font_color[x];
-                    lineptr[3*x] = (spectogram_src[3*x] * (255-alpha) + (255-color) * alpha + 255) >> 8;
-                    lineptr[3*x+1] = (spectogram_src[3*x+1] * (255-alpha) + 255) >> 8;
-                    lineptr[3*x+2] = (spectogram_src[3*x+2] * (255-alpha) + color * alpha + 255) >> 8;
+                    lineptr[3*x] = (spectogram_src[3*x] * (255-alpha) + fontcolor_value[0] * alpha + 255) >> 8;
+                    lineptr[3*x+1] = (spectogram_src[3*x+1] * (255-alpha) + fontcolor_value[1] * alpha + 255) >> 8;
+                    lineptr[3*x+2] = (spectogram_src[3*x+2] * (255-alpha) + fontcolor_value[2] * alpha + 255) >> 8;
+                    fontcolor_value += 3;
                 }
             }
         } else {
@@ -551,16 +662,16 @@ static int plot_cqt(AVFilterLink *inlink)
                         int mask;
                         for (mask = 0x80; mask; mask >>= 1) {
                             if (mask & avpriv_vga16_font[str[u] * 16 + v]) {
-                                p[0] = 255 - s->font_color[ux];
-                                p[1] = 0;
-                                p[2] = s->font_color[ux];
+                                p[0] = s->fontcolor_value[3*ux];
+                                p[1] = s->fontcolor_value[3*ux+1];
+                                p[2] = s->fontcolor_value[3*ux+2];
                                 if (video_scale == 2) {
                                     p[linesize] = p[0];
                                     p[linesize+1] = p[1];
                                     p[linesize+2] = p[2];
-                                    p[3] = p[linesize+3] = 255 - s->font_color[ux+1];
-                                    p[4] = p[linesize+4] = 0;
-                                    p[5] = p[linesize+5] = s->font_color[ux+1];
+                                    p[3] = p[linesize+3] = s->fontcolor_value[3*ux+3];
+                                    p[4] = p[linesize+4] = s->fontcolor_value[3*ux+4];
+                                    p[5] = p[linesize+5] = s->fontcolor_value[3*ux+5];
                                 }
                             }
                             p  += 3 * video_scale;