]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_nnedi.c
avfilter/vf_identity: fix typo
[ffmpeg] / libavfilter / vf_nnedi.c
index e7f975d8d1fa2f883489a4df3c8a041ae07f686f..6096e88812b900cd7a27093ed23024f80690b040 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <float.h>
 
+#include "libavutil/avassert.h"
 #include "libavutil/common.h"
 #include "libavutil/float_dsp.h"
 #include "libavutil/imgutils.h"
@@ -66,11 +67,9 @@ typedef struct NNEDIContext {
 
     char *weights_file;
 
-    AVFrame *src;
-    AVFrame *second;
-    AVFrame *dst;
+    AVFrame *prev;
     int eof;
-    int64_t cur_pts;
+    int64_t pts;
 
     AVFloatDSPContext *fdsp;
     int depth;
@@ -217,11 +216,13 @@ static int query_formats(AVFilterContext *ctx)
 static float dot_dsp(const NNEDIContext *const s, const float *kernel, const float *input,
                      int n, float scale, float bias)
 {
-    float sum;
+    float sum, y;
 
     sum = s->fdsp->scalarproduct_float(kernel, input, n);
 
-    return sum * scale + bias;
+    y = sum * scale + bias + 1e-20f;
+
+    return y;
 }
 
 static float elliott(float x)
@@ -334,6 +335,7 @@ static void gather_input(const float *src, ptrdiff_t src_stride,
                          float *buf, float mstd[4],
                          const PredictorCoefficients *const model)
 {
+    const float scale = 1.f / model->nsize;
     float sum = 0.f;
     float sum_sq = 0.f;
     float tmp;
@@ -352,10 +354,10 @@ static void gather_input(const float *src, ptrdiff_t src_stride,
         buf += model->xdim;
     }
 
-    mstd[0] = sum / model->nsize;
+    mstd[0] = sum * scale;
     mstd[3] = 0.f;
 
-    tmp = sum_sq / model->nsize - mstd[0] * mstd[0];
+    tmp = sum_sq * scale - mstd[0] * mstd[0];
     if (tmp < FLT_EPSILON) {
         mstd[1] = 0.0f;
         mstd[2] = 0.0f;
@@ -541,8 +543,8 @@ static void interpolation(const void *src, ptrdiff_t src_stride,
 static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
 {
     const NNEDIContext *const s = ctx->priv;
-    AVFrame *out = s->dst;
-    AVFrame *in = s->src;
+    AVFrame *out = arg;
+    AVFrame *in = s->prev;
     const float in_scale = s->in_scale;
     const float out_scale = s->out_scale;
     const int depth = s->depth;
@@ -635,7 +637,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
                 width, 1, in_scale);
 
         for (int y = 0; y < slice_end - slice_start; y += 2) {
-            if (s->prescreen > 0)
+            if (s->pscrn > 0)
                 s->prescreen[s->pscrn > 1](ctx, srcbuf + (y / 2) * srcbuf_stride + 32,
                              srcbuf_stride, prescreen_buf, width,
                              &s->prescreener[s->pscrn - 1]);
@@ -647,7 +649,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
                       prescreen_buf, width,
                       &s->coeffs[s->etype][s->nnsparam][s->nsize], s->qual == 2);
 
-            if (s->prescreen > 0)
+            if (s->pscrn > 0)
                 interpolation(srcbuf + (y / 2) * srcbuf_stride + 32,
                               srcbuf_stride,
                               dstbuf + (y / 2) * dstbuf_stride,
@@ -665,105 +667,54 @@ static int get_frame(AVFilterContext *ctx, int is_second)
 {
     NNEDIContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFrame *src = s->src;
+    AVFrame *dst;
 
-    s->dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
-    if (!s->dst)
+    dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+    if (!dst)
         return AVERROR(ENOMEM);
-    av_frame_copy_props(s->dst, src);
-    s->dst->interlaced_frame = 0;
+    av_frame_copy_props(dst, s->prev);
+    dst->interlaced_frame = 0;
+    dst->pts = s->pts;
 
-    ctx->internal->execute(ctx, filter_slice, NULL, NULL, FFMIN(s->planeheight[1] / 2, s->nb_threads));
+    ctx->internal->execute(ctx, filter_slice, dst, NULL, FFMIN(s->planeheight[1] / 2, s->nb_threads));
 
     if (s->field == -2 || s->field > 1)
         s->field_n = !s->field_n;
 
-    return 0;
+    return ff_filter_frame(outlink, dst);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFrame *src)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
-    AVFilterLink *outlink = ctx->outputs[0];
     NNEDIContext *s = ctx->priv;
     int ret;
 
-    if ((s->field > 1 ||
-         s->field == -2) && !s->second) {
-        goto second;
-    } else if (s->field > 1 ||
-               s->field == -2) {
-        AVFrame *dst;
-
-        s->src = s->second;
-        ret = get_frame(ctx, 1);
-        if (ret < 0) {
-            av_frame_free(&s->dst);
-            av_frame_free(&s->second);
-            s->src = NULL;
-            return ret;
-        }
-        dst = s->dst;
-
-        if (src->pts != AV_NOPTS_VALUE &&
-            dst->pts != AV_NOPTS_VALUE)
-            dst->pts += src->pts;
-        else
-            dst->pts = AV_NOPTS_VALUE;
-
-        ret = ff_filter_frame(outlink, dst);
-        if (ret < 0)
-            return ret;
-        if (s->eof)
-            return 0;
-        s->cur_pts = s->second->pts;
-        av_frame_free(&s->second);
-second:
-        if ((s->deint && src->interlaced_frame &&
-             !ctx->is_disabled) ||
-            (!s->deint && !ctx->is_disabled)) {
-            s->second = src;
-        }
+    if (!s->prev) {
+        s->prev = in;
+        return 0;
     }
 
-    if ((s->deint && !src->interlaced_frame) || ctx->is_disabled) {
-        AVFrame *dst = av_frame_clone(src);
-        if (!dst) {
-            av_frame_free(&src);
-            av_frame_free(&s->second);
-            return AVERROR(ENOMEM);
-        }
-
-        if (s->field > 1 || s->field == -2) {
-            av_frame_free(&s->second);
-            if ((s->deint && src->interlaced_frame) ||
-                (!s->deint))
-                s->second = src;
-        } else {
-            av_frame_free(&src);
-        }
-        if (dst->pts != AV_NOPTS_VALUE)
-            dst->pts *= 2;
-        return ff_filter_frame(outlink, dst);
+    if ((s->deint && !in->interlaced_frame) || ctx->is_disabled) {
+        s->prev->pts *= 2;
+        ret = ff_filter_frame(ctx->outputs[0], s->prev);
+        s->prev = in;
+        return ret;
     }
 
-    s->src = src;
+    s->pts = s->prev->pts * 2;
     ret = get_frame(ctx, 0);
-    if (ret < 0) {
-        av_frame_free(&s->dst);
-        av_frame_free(&s->src);
-        av_frame_free(&s->second);
+    if (ret < 0 || (s->field > -2 && s->field < 2)) {
+        av_frame_free(&s->prev);
+        s->prev = in;
         return ret;
     }
 
-    if (src->pts != AV_NOPTS_VALUE)
-        s->dst->pts = src->pts * 2;
-    if (s->field <= 1 && s->field > -2) {
-        av_frame_free(&src);
-        s->src = NULL;
-    }
-
-    return ff_filter_frame(outlink, s->dst);
+    s->pts = s->prev->pts + in->pts;
+    ret = get_frame(ctx, 1);
+    av_frame_free(&s->prev);
+    s->prev = in;
+    return ret;
 }
 
 static int request_frame(AVFilterLink *link)
@@ -777,21 +728,22 @@ static int request_frame(AVFilterLink *link)
 
     ret  = ff_request_frame(ctx->inputs[0]);
 
-    if (ret == AVERROR_EOF && s->second) {
-        AVFrame *next = av_frame_clone(s->second);
+    if (ret == AVERROR_EOF && s->prev) {
+        AVFrame *next = av_frame_clone(s->prev);
 
         if (!next)
             return AVERROR(ENOMEM);
 
-        next->pts = s->second->pts * 2 - s->cur_pts;
+        next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(ctx->outputs[0]->frame_rate),
+                                                ctx->outputs[0]->time_base);
         s->eof = 1;
 
-        filter_frame(ctx->inputs[0], next);
+        ret = filter_frame(ctx->inputs[0], next);
     } else if (ret < 0) {
         return ret;
     }
 
-    return 0;
+    return ret;
 }
 
 static void copy_weights(float *dst, int n, const float **data)
@@ -945,12 +897,13 @@ static void subtract_mean_new(PrescreenerCoefficients *coeffs, float half)
 
 static void subtract_mean_predictor(PredictorCoefficients *model)
 {
-    int filter_size = model->nsize;
-    int nns = model->nns;
+    const int filter_size = model->nsize;
+    const int nns = model->nns;
+    const float scale = 1.f / nns;
 
     double softmax_means[256]; // Average of individual softmax filters.
     double elliott_means[256]; // Average of individual elliott filters.
-    double mean_filter[48 * 6]; // Pointwise average of all softmax filters.
+    double mean_filter[48 * 6] = { 0 }; // Pointwise average of all softmax filters.
     double mean_bias;
 
     // Quality 1.
@@ -963,7 +916,7 @@ static void subtract_mean_predictor(PredictorCoefficients *model)
     }
 
     for (int k = 0; k < filter_size; k++)
-        mean_filter[k] /= nns;
+        mean_filter[k] *= scale;
 
     mean_bias = mean(model->softmax_bias_q1, nns);
 
@@ -988,7 +941,7 @@ static void subtract_mean_predictor(PredictorCoefficients *model)
     }
 
     for (int k = 0; k < filter_size; k++)
-        mean_filter[k] /= nns;
+        mean_filter[k] *= scale;
 
     mean_bias = mean(model->softmax_bias_q2, nns);
 
@@ -1182,7 +1135,7 @@ static av_cold void uninit(AVFilterContext *ctx)
         }
     }
 
-    av_frame_free(&s->second);
+    av_frame_free(&s->prev);
 }
 
 static const AVFilterPad inputs[] = {
@@ -1205,7 +1158,7 @@ static const AVFilterPad outputs[] = {
     { NULL }
 };
 
-AVFilter ff_vf_nnedi = {
+const AVFilter ff_vf_nnedi = {
     .name          = "nnedi",
     .description   = NULL_IF_CONFIG_SMALL("Apply neural network edge directed interpolation intra-only deinterlacer."),
     .priv_size     = sizeof(NNEDIContext),