#include <float.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/float_dsp.h"
#include "libavutil/imgutils.h"
char *weights_file;
- AVFrame *src;
- AVFrame *second;
- AVFrame *dst;
+ AVFrame *prev;
int eof;
- int64_t cur_pts;
+ int64_t pts;
AVFloatDSPContext *fdsp;
int depth;
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)
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;
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;
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;
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]);
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,
{
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)
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)
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;
- float softmax_means[256]; // Average of individual softmax filters.
- float elliott_means[256]; // Average of individual elliott filters.
- float mean_filter[48 * 6]; // Pointwise average of all softmax filters.
- float mean_bias;
+ double softmax_means[256]; // Average of individual softmax filters.
+ double elliott_means[256]; // Average of individual elliott filters.
+ double mean_filter[48 * 6] = { 0 }; // Pointwise average of all softmax filters.
+ double mean_bias;
// Quality 1.
for (int nn = 0; nn < nns; nn++) {
}
for (int k = 0; k < filter_size; k++)
- mean_filter[k] /= nns;
+ mean_filter[k] *= scale;
mean_bias = mean(model->softmax_bias_q1, nns);
}
// Quality 2.
- memset(mean_filter, 0, 48 * 6 * sizeof(float));
+ memset(mean_filter, 0, sizeof(mean_filter));
for (int nn = 0; nn < nns; nn++) {
softmax_means[nn] = mean(model->softmax_q2 + nn * filter_size, filter_size);
}
for (int k = 0; k < filter_size; k++)
- mean_filter[k] /= nns;
+ mean_filter[k] *= scale;
mean_bias = mean(model->softmax_bias_q2, nns);
}
}
- av_frame_free(&s->second);
+ av_frame_free(&s->prev);
}
static const AVFilterPad inputs[] = {
{ 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),