Imported Upstream version 6.1
[platform/upstream/ffmpeg.git] / libavfilter / af_afade.c
index 0445bb7..3de673f 100644 (file)
@@ -39,21 +39,26 @@ typedef struct AudioFadeContext {
     int64_t start_sample;
     int64_t duration;
     int64_t start_time;
+    double silence;
+    double unity;
     int overlap;
-    int cf0_eof;
-    int crossfade_is_over;
+    int status[2];
+    int passthrough;
     int64_t pts;
 
     void (*fade_samples)(uint8_t **dst, uint8_t * const *src,
                          int nb_samples, int channels, int direction,
-                         int64_t start, int64_t range, int curve);
+                         int64_t start, int64_t range, int curve,
+                         double silence, double unity);
+    void (*scale_samples)(uint8_t **dst, uint8_t * const *src,
+                          int nb_samples, int channels, double unity);
     void (*crossfade_samples)(uint8_t **dst, uint8_t * const *cf0,
                               uint8_t * const *cf1,
                               int nb_samples, int channels,
                               int curve0, int curve1);
 } AudioFadeContext;
 
-enum CurveType { NONE = -1, TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP, IQSIN, IHSIN, DESE, DESI, LOSI, SINC, ISINC, NB_CURVES };
+enum CurveType { NONE = -1, TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP, IQSIN, IHSIN, DESE, DESI, LOSI, SINC, ISINC, QUAT, QUATR, QSIN2, HSIN2, NB_CURVES };
 
 #define OFFSET(x) offsetof(AudioFadeContext, x)
 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
@@ -67,7 +72,7 @@ enum CurveType { NONE = -1, TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR
         AV_SAMPLE_FMT_NONE
     };
 
-static double fade_gain(int curve, int64_t index, int64_t range)
+static double fade_gain(int curve, int64_t index, int64_t range, double silence, double unity)
 {
 #define CUBE(a) ((a)*(a)*(a))
     double gain;
@@ -137,23 +142,36 @@ static double fade_gain(int curve, int64_t index, int64_t range)
     case ISINC:
         gain = gain <= 0.0 ? 0.0 : 1.0 - sin(M_PI * gain) / (M_PI * gain);
         break;
+    case QUAT:
+        gain = gain * gain * gain * gain;
+        break;
+    case QUATR:
+        gain = pow(gain, 0.25);
+        break;
+    case QSIN2:
+        gain = sin(gain * M_PI / 2.0) * sin(gain * M_PI / 2.0);
+        break;
+    case HSIN2:
+        gain = pow((1.0 - cos(gain * M_PI)) / 2.0, 2.0);
+        break;
     case NONE:
         gain = 1.0;
         break;
     }
 
-    return gain;
+    return silence + (unity - silence) * gain;
 }
 
 #define FADE_PLANAR(name, type)                                             \
 static void fade_samples_## name ##p(uint8_t **dst, uint8_t * const *src,   \
                                      int nb_samples, int channels, int dir, \
-                                     int64_t start, int64_t range, int curve) \
+                                     int64_t start, int64_t range,int curve,\
+                                     double silence, double unity)          \
 {                                                                           \
     int i, c;                                                               \
                                                                             \
     for (i = 0; i < nb_samples; i++) {                                      \
-        double gain = fade_gain(curve, start + i * dir, range);             \
+        double gain = fade_gain(curve, start + i * dir,range,silence,unity);\
         for (c = 0; c < channels; c++) {                                    \
             type *d = (type *)dst[c];                                       \
             const type *s = (type *)src[c];                                 \
@@ -166,14 +184,15 @@ static void fade_samples_## name ##p(uint8_t **dst, uint8_t * const *src,   \
 #define FADE(name, type)                                                    \
 static void fade_samples_## name (uint8_t **dst, uint8_t * const *src,      \
                                   int nb_samples, int channels, int dir,    \
-                                  int64_t start, int64_t range, int curve)  \
+                                  int64_t start, int64_t range, int curve,  \
+                                  double silence, double unity)             \
 {                                                                           \
     type *d = (type *)dst[0];                                               \
     const type *s = (type *)src[0];                                         \
     int i, c, k = 0;                                                        \
                                                                             \
     for (i = 0; i < nb_samples; i++) {                                      \
-        double gain = fade_gain(curve, start + i * dir, range);             \
+        double gain = fade_gain(curve, start + i * dir,range,silence,unity);\
         for (c = 0; c < channels; c++, k++)                                 \
             d[k] = s[k] * gain;                                             \
     }                                                                       \
@@ -189,20 +208,77 @@ FADE(flt, float)
 FADE(s16, int16_t)
 FADE(s32, int32_t)
 
+#define SCALE_PLANAR(name, type)                                            \
+static void scale_samples_## name ##p(uint8_t **dst, uint8_t * const *src,  \
+                                     int nb_samples, int channels,          \
+                                     double gain)                           \
+{                                                                           \
+    int i, c;                                                               \
+                                                                            \
+    for (i = 0; i < nb_samples; i++) {                                      \
+        for (c = 0; c < channels; c++) {                                    \
+            type *d = (type *)dst[c];                                       \
+            const type *s = (type *)src[c];                                 \
+                                                                            \
+            d[i] = s[i] * gain;                                             \
+        }                                                                   \
+    }                                                                       \
+}
+
+#define SCALE(name, type)                                                   \
+static void scale_samples_## name (uint8_t **dst, uint8_t * const *src,     \
+                                  int nb_samples, int channels, double gain)\
+{                                                                           \
+    type *d = (type *)dst[0];                                               \
+    const type *s = (type *)src[0];                                         \
+    int i, c, k = 0;                                                        \
+                                                                            \
+    for (i = 0; i < nb_samples; i++) {                                      \
+        for (c = 0; c < channels; c++, k++)                                 \
+            d[k] = s[k] * gain;                                             \
+    }                                                                       \
+}
+
+SCALE_PLANAR(dbl, double)
+SCALE_PLANAR(flt, float)
+SCALE_PLANAR(s16, int16_t)
+SCALE_PLANAR(s32, int32_t)
+
+SCALE(dbl, double)
+SCALE(flt, float)
+SCALE(s16, int16_t)
+SCALE(s32, int32_t)
+
 static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AudioFadeContext *s  = ctx->priv;
 
     switch (outlink->format) {
-    case AV_SAMPLE_FMT_DBL:  s->fade_samples = fade_samples_dbl;  break;
-    case AV_SAMPLE_FMT_DBLP: s->fade_samples = fade_samples_dblp; break;
-    case AV_SAMPLE_FMT_FLT:  s->fade_samples = fade_samples_flt;  break;
-    case AV_SAMPLE_FMT_FLTP: s->fade_samples = fade_samples_fltp; break;
-    case AV_SAMPLE_FMT_S16:  s->fade_samples = fade_samples_s16;  break;
-    case AV_SAMPLE_FMT_S16P: s->fade_samples = fade_samples_s16p; break;
-    case AV_SAMPLE_FMT_S32:  s->fade_samples = fade_samples_s32;  break;
-    case AV_SAMPLE_FMT_S32P: s->fade_samples = fade_samples_s32p; break;
+    case AV_SAMPLE_FMT_DBL:  s->fade_samples = fade_samples_dbl;
+                             s->scale_samples = scale_samples_dbl;
+                             break;
+    case AV_SAMPLE_FMT_DBLP: s->fade_samples = fade_samples_dblp;
+                             s->scale_samples = scale_samples_dblp;
+                             break;
+    case AV_SAMPLE_FMT_FLT:  s->fade_samples = fade_samples_flt;
+                             s->scale_samples = scale_samples_flt;
+                             break;
+    case AV_SAMPLE_FMT_FLTP: s->fade_samples = fade_samples_fltp;
+                             s->scale_samples = scale_samples_fltp;
+                             break;
+    case AV_SAMPLE_FMT_S16:  s->fade_samples = fade_samples_s16;
+                             s->scale_samples = scale_samples_s16;
+                             break;
+    case AV_SAMPLE_FMT_S16P: s->fade_samples = fade_samples_s16p;
+                             s->scale_samples = scale_samples_s16p;
+                             break;
+    case AV_SAMPLE_FMT_S32:  s->fade_samples = fade_samples_s32;
+                             s->scale_samples = scale_samples_s32;
+                             break;
+    case AV_SAMPLE_FMT_S32P: s->fade_samples = fade_samples_s32p;
+                             s->scale_samples = scale_samples_s32p;
+                             break;
     }
 
     if (s->duration)
@@ -252,6 +328,12 @@ static const AVOption afade_options[] = {
     { "losi",         "logistic sigmoid",                            0,                    AV_OPT_TYPE_CONST,  {.i64 = LOSI }, 0, 0, TFLAGS, "curve" },
     { "sinc",         "sine cardinal function",                      0,                    AV_OPT_TYPE_CONST,  {.i64 = SINC }, 0, 0, TFLAGS, "curve" },
     { "isinc",        "inverted sine cardinal function",             0,                    AV_OPT_TYPE_CONST,  {.i64 = ISINC}, 0, 0, TFLAGS, "curve" },
+    { "quat",         "quartic",                                     0,                    AV_OPT_TYPE_CONST,  {.i64 = QUAT }, 0, 0, TFLAGS, "curve" },
+    { "quatr",        "quartic root",                                0,                    AV_OPT_TYPE_CONST,  {.i64 = QUATR}, 0, 0, TFLAGS, "curve" },
+    { "qsin2",        "squared quarter of sine wave",                0,                    AV_OPT_TYPE_CONST,  {.i64 = QSIN2}, 0, 0, TFLAGS, "curve" },
+    { "hsin2",        "squared half of sine wave",                   0,                    AV_OPT_TYPE_CONST,  {.i64 = HSIN2}, 0, 0, TFLAGS, "curve" },
+    { "silence",      "set the silence gain",                        OFFSET(silence),      AV_OPT_TYPE_DOUBLE, {.dbl = 0 },    0, 1, TFLAGS },
+    { "unity",        "set the unity gain",                          OFFSET(unity),        AV_OPT_TYPE_DOUBLE, {.dbl = 1 },    0, 1, TFLAGS },
     { NULL }
 };
 
@@ -275,8 +357,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     AVFrame *out_buf;
     int64_t cur_sample = av_rescale_q(buf->pts, inlink->time_base, (AVRational){1, inlink->sample_rate});
 
-    if ((!s->type && (s->start_sample + s->nb_samples < cur_sample)) ||
-        ( s->type && (cur_sample + nb_samples < s->start_sample)))
+    if (s->unity == 1.0 &&
+        ((!s->type && (s->start_sample + s->nb_samples < cur_sample)) ||
+         ( s->type && (cur_sample + nb_samples < s->start_sample))))
         return ff_filter_frame(outlink, buf);
 
     if (av_frame_is_writable(buf)) {
@@ -290,8 +373,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 
     if ((!s->type && (cur_sample + nb_samples < s->start_sample)) ||
         ( s->type && (s->start_sample + s->nb_samples < cur_sample))) {
-        av_samples_set_silence(out_buf->extended_data, 0, nb_samples,
-                               out_buf->ch_layout.nb_channels, out_buf->format);
+        if (s->silence == 0.) {
+            av_samples_set_silence(out_buf->extended_data, 0, nb_samples,
+                                   out_buf->ch_layout.nb_channels, out_buf->format);
+        } else {
+            s->scale_samples(out_buf->extended_data, buf->extended_data,
+                             nb_samples, buf->ch_layout.nb_channels,
+                             s->silence);
+        }
+    } else if (( s->type && (cur_sample + nb_samples < s->start_sample)) ||
+               (!s->type && (s->start_sample + s->nb_samples < cur_sample))) {
+        s->scale_samples(out_buf->extended_data, buf->extended_data,
+                         nb_samples, buf->ch_layout.nb_channels,
+                         s->unity);
     } else {
         int64_t start;
 
@@ -303,7 +397,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
         s->fade_samples(out_buf->extended_data, buf->extended_data,
                         nb_samples, buf->ch_layout.nb_channels,
                         s->type ? -1 : 1, start,
-                        s->nb_samples, s->curve);
+                        s->nb_samples, s->curve, s->silence, s->unity);
     }
 
     if (buf != out_buf)
@@ -386,6 +480,10 @@ static const AVOption acrossfade_options[] = {
     {     "losi",     "logistic sigmoid",                              0,                    AV_OPT_TYPE_CONST,  {.i64 = LOSI }, 0, 0, FLAGS, "curve" },
     {     "sinc",     "sine cardinal function",                        0,                    AV_OPT_TYPE_CONST,  {.i64 = SINC }, 0, 0, FLAGS, "curve" },
     {     "isinc",    "inverted sine cardinal function",               0,                    AV_OPT_TYPE_CONST,  {.i64 = ISINC}, 0, 0, FLAGS, "curve" },
+    {     "quat",     "quartic",                                       0,                    AV_OPT_TYPE_CONST,  {.i64 = QUAT }, 0, 0, FLAGS, "curve" },
+    {     "quatr",    "quartic root",                                  0,                    AV_OPT_TYPE_CONST,  {.i64 = QUATR}, 0, 0, FLAGS, "curve" },
+    {     "qsin2",    "squared quarter of sine wave",                  0,                    AV_OPT_TYPE_CONST,  {.i64 = QSIN2}, 0, 0, FLAGS, "curve" },
+    {     "hsin2",    "squared half of sine wave",                     0,                    AV_OPT_TYPE_CONST,  {.i64 = HSIN2}, 0, 0, FLAGS, "curve" },
     { "curve2",       "set fade curve type for 2nd stream",            OFFSET(curve2),       AV_OPT_TYPE_INT,    {.i64 = TRI  }, NONE, NB_CURVES - 1, FLAGS, "curve" },
     { "c2",           "set fade curve type for 2nd stream",            OFFSET(curve2),       AV_OPT_TYPE_INT,    {.i64 = TRI  }, NONE, NB_CURVES - 1, FLAGS, "curve" },
     { NULL }
@@ -402,8 +500,8 @@ static void crossfade_samples_## name ##p(uint8_t **dst, uint8_t * const *cf0, \
     int i, c;                                                                  \
                                                                                \
     for (i = 0; i < nb_samples; i++) {                                         \
-        double gain0 = fade_gain(curve0, nb_samples - 1 - i, nb_samples);      \
-        double gain1 = fade_gain(curve1, i, nb_samples);                       \
+        double gain0 = fade_gain(curve0, nb_samples - 1 - i, nb_samples,0.,1.);\
+        double gain1 = fade_gain(curve1, i, nb_samples, 0., 1.);               \
         for (c = 0; c < channels; c++) {                                       \
             type *d = (type *)dst[c];                                          \
             const type *s0 = (type *)cf0[c];                                   \
@@ -426,8 +524,8 @@ static void crossfade_samples_## name (uint8_t **dst, uint8_t * const *cf0, \
     int i, c, k = 0;                                                        \
                                                                             \
     for (i = 0; i < nb_samples; i++) {                                      \
-        double gain0 = fade_gain(curve0, nb_samples - 1 - i, nb_samples);   \
-        double gain1 = fade_gain(curve1, i, nb_samples);                    \
+        double gain0 = fade_gain(curve0, nb_samples - 1-i,nb_samples,0.,1.);\
+        double gain1 = fade_gain(curve1, i, nb_samples, 0., 1.);            \
         for (c = 0; c < channels; c++, k++)                                 \
             d[k] = s0[k] * gain0 + s1[k] * gain1;                           \
     }                                                                       \
@@ -443,6 +541,13 @@ CROSSFADE(flt, float)
 CROSSFADE(s16, int16_t)
 CROSSFADE(s32, int32_t)
 
+static int check_input(AVFilterLink *inlink)
+{
+    const int queued_samples = ff_inlink_queued_samples(inlink);
+
+    return ff_inlink_check_available_samples(inlink, queued_samples + 1) == 1;
+}
+
 static int activate(AVFilterContext *ctx)
 {
     AudioFadeContext *s   = ctx->priv;
@@ -453,7 +558,7 @@ static int activate(AVFilterContext *ctx)
 
     FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
 
-    if (s->crossfade_is_over) {
+    if (s->passthrough && s->status[0]) {
         ret = ff_inlink_consume_frame(ctx->inputs[1], &in);
         if (ret > 0) {
             in->pts = s->pts;
@@ -463,10 +568,10 @@ static int activate(AVFilterContext *ctx)
         } else if (ret < 0) {
             return ret;
         } else if (ff_inlink_acknowledge_status(ctx->inputs[1], &status, &pts)) {
-            ff_outlink_set_status(ctx->outputs[0], status, pts);
+            ff_outlink_set_status(outlink, status, pts);
             return 0;
         } else if (!ret) {
-            if (ff_outlink_frame_wanted(ctx->outputs[0])) {
+            if (ff_outlink_frame_wanted(outlink)) {
                 ff_inlink_request_frame(ctx->inputs[1]);
                 return 0;
             }
@@ -476,6 +581,7 @@ static int activate(AVFilterContext *ctx)
     nb_samples = ff_inlink_queued_samples(ctx->inputs[0]);
     if (nb_samples  > s->nb_samples) {
         nb_samples -= s->nb_samples;
+        s->passthrough = 1;
         ret = ff_inlink_consume_samples(ctx->inputs[0], nb_samples, nb_samples, &in);
         if (ret < 0)
             return ret;
@@ -483,7 +589,7 @@ static int activate(AVFilterContext *ctx)
         s->pts += av_rescale_q(in->nb_samples,
             (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
         return ff_filter_frame(outlink, in);
-    } else if (s->cf0_eof && nb_samples >= s->nb_samples &&
+    } else if (s->status[0] && nb_samples >= s->nb_samples &&
                ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) {
         if (s->overlap) {
             out = ff_get_audio_buffer(outlink, s->nb_samples);
@@ -509,7 +615,7 @@ static int activate(AVFilterContext *ctx)
             out->pts = s->pts;
             s->pts += av_rescale_q(s->nb_samples,
                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
-            s->crossfade_is_over = 1;
+            s->passthrough = 1;
             av_frame_free(&cf[0]);
             av_frame_free(&cf[1]);
             return ff_filter_frame(outlink, out);
@@ -525,7 +631,7 @@ static int activate(AVFilterContext *ctx)
             }
 
             s->fade_samples(out->extended_data, cf[0]->extended_data, s->nb_samples,
-                            outlink->ch_layout.nb_channels, -1, s->nb_samples - 1, s->nb_samples, s->curve);
+                            outlink->ch_layout.nb_channels, -1, s->nb_samples - 1, s->nb_samples, s->curve, 0., 1.);
             out->pts = s->pts;
             s->pts += av_rescale_q(s->nb_samples,
                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
@@ -545,23 +651,24 @@ static int activate(AVFilterContext *ctx)
             }
 
             s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples,
-                            outlink->ch_layout.nb_channels, 1, 0, s->nb_samples, s->curve2);
+                            outlink->ch_layout.nb_channels, 1, 0, s->nb_samples, s->curve2, 0., 1.);
             out->pts = s->pts;
             s->pts += av_rescale_q(s->nb_samples,
                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
-            s->crossfade_is_over = 1;
+            s->passthrough = 1;
             av_frame_free(&cf[1]);
             return ff_filter_frame(outlink, out);
         }
-    } else if (ff_outlink_frame_wanted(ctx->outputs[0])) {
-        if (!s->cf0_eof && ff_outlink_get_status(ctx->inputs[0])) {
-            s->cf0_eof = 1;
-        }
-        if (ff_outlink_get_status(ctx->inputs[1])) {
-            ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE);
+    } else if (ff_outlink_frame_wanted(outlink)) {
+        if (!s->status[0] && check_input(ctx->inputs[0]))
+            s->status[0] = AVERROR_EOF;
+        s->passthrough = !s->status[0];
+        if (check_input(ctx->inputs[1])) {
+            s->status[1] = AVERROR_EOF;
+            ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE);
             return 0;
         }
-        if (!s->cf0_eof)
+        if (!s->status[0])
             ff_inlink_request_frame(ctx->inputs[0]);
         else
             ff_inlink_request_frame(ctx->inputs[1]);
@@ -594,14 +701,26 @@ static int acrossfade_config_output(AVFilterLink *outlink)
     return 0;
 }
 
+static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples)
+{
+    AVFilterContext *ctx = inlink->dst;
+    AudioFadeContext *s = ctx->priv;
+
+    return s->passthrough ?
+        ff_null_get_audio_buffer   (inlink, nb_samples) :
+        ff_default_get_audio_buffer(inlink, nb_samples);
+}
+
 static const AVFilterPad avfilter_af_acrossfade_inputs[] = {
     {
         .name         = "crossfade0",
         .type         = AVMEDIA_TYPE_AUDIO,
+        .get_buffer.audio = get_audio_buffer,
     },
     {
         .name         = "crossfade1",
         .type         = AVMEDIA_TYPE_AUDIO,
+        .get_buffer.audio = get_audio_buffer,
     },
 };