You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1174 lines
38KB

  1. /*
  2. * Copyright (C) 2010-2011 Kevin Stone
  3. * Copyright (C) 2016 Paul B Mahol
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. */
  21. #include <float.h>
  22. #include "libavutil/avassert.h"
  23. #include "libavutil/common.h"
  24. #include "libavutil/float_dsp.h"
  25. #include "libavutil/imgutils.h"
  26. #include "libavutil/mem_internal.h"
  27. #include "libavutil/opt.h"
  28. #include "libavutil/pixdesc.h"
  29. #include "avfilter.h"
  30. #include "formats.h"
  31. #include "internal.h"
  32. #include "video.h"
  33. static const size_t NNEDI_WEIGHTS_SIZE = 13574928;
  34. static const uint8_t NNEDI_XDIM[] = { 8, 16, 32, 48, 8, 16, 32 };
  35. static const uint8_t NNEDI_YDIM[] = { 6, 6, 6, 6, 4, 4, 4 };
  36. static const uint16_t NNEDI_NNS[] = { 16, 32, 64, 128, 256 };
  37. typedef struct PrescreenerCoefficients {
  38. DECLARE_ALIGNED(32, float, kernel_l0)[4][16 * 4];
  39. DECLARE_ALIGNED(32, float, bias_l0)[4];
  40. DECLARE_ALIGNED(32, float, kernel_l1)[4][4];
  41. DECLARE_ALIGNED(32, float, bias_l1)[4];
  42. DECLARE_ALIGNED(32, float, kernel_l2)[4][8];
  43. DECLARE_ALIGNED(32, float, bias_l2)[4];
  44. } PrescreenerCoefficients;
  45. typedef struct PredictorCoefficients {
  46. int xdim, ydim, nns, nsize;
  47. float *data;
  48. float *softmax_q1;
  49. float *elliott_q1;
  50. float *softmax_bias_q1;
  51. float *elliott_bias_q1;
  52. float *softmax_q2;
  53. float *elliott_q2;
  54. float *softmax_bias_q2;
  55. float *elliott_bias_q2;
  56. } PredictorCoefficients;
  57. typedef struct NNEDIContext {
  58. const AVClass *class;
  59. char *weights_file;
  60. AVFrame *prev;
  61. int eof;
  62. int64_t pts;
  63. AVFloatDSPContext *fdsp;
  64. int depth;
  65. int nb_planes;
  66. int nb_threads;
  67. int linesize[4];
  68. int planewidth[4];
  69. int planeheight[4];
  70. int field_n;
  71. PrescreenerCoefficients prescreener[4];
  72. PredictorCoefficients coeffs[2][5][7];
  73. float half;
  74. float in_scale;
  75. float out_scale;
  76. // Parameters
  77. int deint;
  78. int field;
  79. int process_plane;
  80. int nsize;
  81. int nnsparam;
  82. int qual;
  83. int etype;
  84. int pscrn;
  85. int input_size;
  86. uint8_t **prescreen_buf;
  87. float **input_buf;
  88. float **output_buf;
  89. void (*read)(const uint8_t *src, float *dst,
  90. int src_stride, int dst_stride,
  91. int width, int height, float scale);
  92. void (*write)(const float *src, uint8_t *dst,
  93. int src_stride, int dst_stride,
  94. int width, int height, int depth, float scale);
  95. void (*prescreen[2])(AVFilterContext *ctx,
  96. const void *src, ptrdiff_t src_stride,
  97. uint8_t *prescreen, int N,
  98. const PrescreenerCoefficients *const coeffs);
  99. } NNEDIContext;
  100. #define OFFSET(x) offsetof(NNEDIContext, x)
  101. #define RFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
  102. #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
  103. static const AVOption nnedi_options[] = {
  104. {"weights", "set weights file", OFFSET(weights_file), AV_OPT_TYPE_STRING, {.str="nnedi3_weights.bin"}, 0, 0, FLAGS },
  105. {"deint", "set which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, RFLAGS, "deint" },
  106. {"all", "deinterlace all frames", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, RFLAGS, "deint" },
  107. {"interlaced", "only deinterlace frames marked as interlaced", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, RFLAGS, "deint" },
  108. {"field", "set mode of operation", OFFSET(field), AV_OPT_TYPE_INT, {.i64=-1}, -2, 3, RFLAGS, "field" },
  109. {"af", "use frame flags, both fields", 0, AV_OPT_TYPE_CONST, {.i64=-2}, 0, 0, RFLAGS, "field" },
  110. {"a", "use frame flags, single field", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, RFLAGS, "field" },
  111. {"t", "use top field only", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, RFLAGS, "field" },
  112. {"b", "use bottom field only", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, RFLAGS, "field" },
  113. {"tf", "use both fields, top first", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, RFLAGS, "field" },
  114. {"bf", "use both fields, bottom first", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, RFLAGS, "field" },
  115. {"planes", "set which planes to process", OFFSET(process_plane), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, RFLAGS },
  116. {"nsize", "set size of local neighborhood around each pixel, used by the predictor neural network", OFFSET(nsize), AV_OPT_TYPE_INT, {.i64=6}, 0, 6, RFLAGS, "nsize" },
  117. {"s8x6", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, RFLAGS, "nsize" },
  118. {"s16x6", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, RFLAGS, "nsize" },
  119. {"s32x6", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, RFLAGS, "nsize" },
  120. {"s48x6", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, RFLAGS, "nsize" },
  121. {"s8x4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, RFLAGS, "nsize" },
  122. {"s16x4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=5}, 0, 0, RFLAGS, "nsize" },
  123. {"s32x4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=6}, 0, 0, RFLAGS, "nsize" },
  124. {"nns", "set number of neurons in predictor neural network", OFFSET(nnsparam), AV_OPT_TYPE_INT, {.i64=1}, 0, 4, RFLAGS, "nns" },
  125. {"n16", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, RFLAGS, "nns" },
  126. {"n32", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, RFLAGS, "nns" },
  127. {"n64", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, RFLAGS, "nns" },
  128. {"n128", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, RFLAGS, "nns" },
  129. {"n256", NULL, 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, RFLAGS, "nns" },
  130. {"qual", "set quality", OFFSET(qual), AV_OPT_TYPE_INT, {.i64=1}, 1, 2, RFLAGS, "qual" },
  131. {"fast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, RFLAGS, "qual" },
  132. {"slow", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, RFLAGS, "qual" },
  133. {"etype", "set which set of weights to use in the predictor", OFFSET(etype), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, RFLAGS, "etype" },
  134. {"a", "weights trained to minimize absolute error", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, RFLAGS, "etype" },
  135. {"abs","weights trained to minimize absolute error", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, RFLAGS, "etype" },
  136. {"s", "weights trained to minimize squared error", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, RFLAGS, "etype" },
  137. {"mse","weights trained to minimize squared error", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, RFLAGS, "etype" },
  138. {"pscrn", "set prescreening", OFFSET(pscrn), AV_OPT_TYPE_INT, {.i64=2}, 0, 4, RFLAGS, "pscrn" },
  139. {"none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, RFLAGS, "pscrn" },
  140. {"original", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, RFLAGS, "pscrn" },
  141. {"new", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, RFLAGS, "pscrn" },
  142. {"new2", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, RFLAGS, "pscrn" },
  143. {"new3", NULL, 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, RFLAGS, "pscrn" },
  144. { NULL }
  145. };
  146. AVFILTER_DEFINE_CLASS(nnedi);
  147. static int config_output(AVFilterLink *outlink)
  148. {
  149. AVFilterContext *ctx = outlink->src;
  150. outlink->time_base.num = ctx->inputs[0]->time_base.num;
  151. outlink->time_base.den = ctx->inputs[0]->time_base.den * 2;
  152. outlink->w = ctx->inputs[0]->w;
  153. outlink->h = ctx->inputs[0]->h;
  154. outlink->frame_rate = av_mul_q(ctx->inputs[0]->frame_rate,
  155. (AVRational){2, 1});
  156. return 0;
  157. }
  158. static int query_formats(AVFilterContext *ctx)
  159. {
  160. static const enum AVPixelFormat pix_fmts[] = {
  161. AV_PIX_FMT_GRAY8,
  162. AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
  163. AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
  164. AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
  165. AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
  166. AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
  167. AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
  168. AV_PIX_FMT_YUVJ411P,
  169. AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
  170. AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
  171. AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
  172. AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
  173. AV_PIX_FMT_YUV440P10,
  174. AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12,
  175. AV_PIX_FMT_YUV440P12,
  176. AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
  177. AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
  178. AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
  179. AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16,
  180. AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16,
  181. AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16,
  182. AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
  183. AV_PIX_FMT_NONE
  184. };
  185. AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
  186. if (!fmts_list)
  187. return AVERROR(ENOMEM);
  188. return ff_set_common_formats(ctx, fmts_list);
  189. }
  190. static float dot_dsp(const NNEDIContext *const s, const float *kernel, const float *input,
  191. int n, float scale, float bias)
  192. {
  193. float sum, y;
  194. sum = s->fdsp->scalarproduct_float(kernel, input, n);
  195. y = sum * scale + bias + 1e-20f;
  196. return y;
  197. }
  198. static float elliott(float x)
  199. {
  200. return x / (1.0f + fabsf(x));
  201. }
  202. static void transform_elliott(float *input, int size)
  203. {
  204. for (int i = 0; i < size; i++)
  205. input[i] = elliott(input[i]);
  206. }
  207. static void process_old(AVFilterContext *ctx,
  208. const void *src, ptrdiff_t src_stride,
  209. uint8_t *prescreen, int N,
  210. const PrescreenerCoefficients *const m_data)
  211. {
  212. NNEDIContext *s = ctx->priv;
  213. const float *src_p = src;
  214. // Adjust source pointer to point to top-left of filter window.
  215. const float *window = src_p - 2 * src_stride - 5;
  216. for (int j = 0; j < N; j++) {
  217. LOCAL_ALIGNED_32(float, input, [48]);
  218. float state[12];
  219. for (int i = 0; i < 4; i++)
  220. memcpy(input + i * 12, window + i * src_stride + j, 12 * sizeof(float));
  221. // Layer 0.
  222. for (int n = 0; n < 4; n++)
  223. state[n] = dot_dsp(s, m_data->kernel_l0[n], input, 48, 1.0f, m_data->bias_l0[n]);
  224. transform_elliott(state + 1, 3);
  225. // Layer 1.
  226. for (int n = 0; n < 4; n++)
  227. state[n + 4] = dot_dsp(s, m_data->kernel_l1[n], state, 4, 1.0f, m_data->bias_l1[n]);
  228. transform_elliott(state + 4, 3);
  229. // Layer 2.
  230. for (int n = 0; n < 4; n++)
  231. state[n + 8] = dot_dsp(s, m_data->kernel_l2[n], state, 8, 1.0f, m_data->bias_l2[n]);
  232. prescreen[j] = FFMAX(state[10], state[11]) <= FFMAX(state[8], state[9]) ? 255 : 0;
  233. }
  234. }
  235. static void process_new(AVFilterContext *ctx,
  236. const void *src, ptrdiff_t src_stride,
  237. uint8_t *prescreen, int N,
  238. const PrescreenerCoefficients *const m_data)
  239. {
  240. NNEDIContext *s = ctx->priv;
  241. const float *src_p = src;
  242. // Adjust source pointer to point to top-left of filter window.
  243. const float *window = src_p - 2 * src_stride - 6;
  244. for (int j = 0; j < N; j += 4) {
  245. LOCAL_ALIGNED_32(float, input, [64]);
  246. float state[8];
  247. for (int i = 0; i < 4; i++)
  248. memcpy(input + i * 16, window + i * src_stride + j, 16 * sizeof(float));
  249. for (int n = 0; n < 4; n++)
  250. state[n] = dot_dsp(s, m_data->kernel_l0[n], input, 64, 1.0f, m_data->bias_l0[n]);
  251. transform_elliott(state, 4);
  252. for (int n = 0; n < 4; n++)
  253. state[n + 4] = dot_dsp(s, m_data->kernel_l1[n], state, 4, 1.0f, m_data->bias_l1[n]);
  254. for (int n = 0; n < 4; n++)
  255. prescreen[j + n] = state[n + 4] > 0.f;
  256. }
  257. }
  258. static int filter_offset(int nn, const PredictorCoefficients *const model)
  259. {
  260. return nn * model->nsize;
  261. }
  262. static const float *softmax_q1_filter(int nn,
  263. const PredictorCoefficients *const model)
  264. {
  265. return model->softmax_q1 + filter_offset(nn, model);
  266. }
  267. static const float *elliott_q1_filter(int nn,
  268. const PredictorCoefficients *const model)
  269. {
  270. return model->elliott_q1 + filter_offset(nn, model);
  271. }
  272. static const float *softmax_q2_filter(int nn,
  273. const PredictorCoefficients *const model)
  274. {
  275. return model->softmax_q2 + filter_offset(nn, model);
  276. }
  277. static const float *elliott_q2_filter(int nn,
  278. const PredictorCoefficients *const model)
  279. {
  280. return model->elliott_q2 + filter_offset(nn, model);
  281. }
  282. static void gather_input(const float *src, ptrdiff_t src_stride,
  283. float *buf, float mstd[4],
  284. const PredictorCoefficients *const model)
  285. {
  286. const float scale = 1.f / model->nsize;
  287. float sum = 0.f;
  288. float sum_sq = 0.f;
  289. float tmp;
  290. for (int i = 0; i < model->ydim; i++) {
  291. memcpy(buf, src, model->xdim * sizeof(float));
  292. for (int j = 0; j < model->xdim; j++) {
  293. const float val = src[j];
  294. sum += val;
  295. sum_sq += val * val;
  296. }
  297. src += src_stride;
  298. buf += model->xdim;
  299. }
  300. mstd[0] = sum * scale;
  301. mstd[3] = 0.f;
  302. tmp = sum_sq * scale - mstd[0] * mstd[0];
  303. if (tmp < FLT_EPSILON) {
  304. mstd[1] = 0.0f;
  305. mstd[2] = 0.0f;
  306. } else {
  307. mstd[1] = sqrtf(tmp);
  308. mstd[2] = 1.0f / mstd[1];
  309. }
  310. }
  311. static float softmax_exp(float x)
  312. {
  313. return expf(av_clipf(x, -80.f, 80.f));
  314. }
  315. static void transform_softmax_exp(float *input, int size)
  316. {
  317. for (int i = 0; i < size; i++)
  318. input[i] = softmax_exp(input[i]);
  319. }
  320. static void wae5(const float *softmax, const float *el,
  321. int n, float mstd[4])
  322. {
  323. float vsum = 0.0f, wsum = 0.0f;
  324. for (int i = 0; i < n; i++) {
  325. vsum += softmax[i] * elliott(el[i]);
  326. wsum += softmax[i];
  327. }
  328. if (wsum > 1e-10f)
  329. mstd[3] += (5.0f * vsum) / wsum * mstd[1] + mstd[0];
  330. else
  331. mstd[3] += mstd[0];
  332. }
  333. static void predictor(AVFilterContext *ctx,
  334. const void *src, ptrdiff_t src_stride, void *dst,
  335. const uint8_t *prescreen, int N,
  336. const PredictorCoefficients *const model, int use_q2)
  337. {
  338. const NNEDIContext *const s = ctx->priv;
  339. const float *src_p = src;
  340. float *dst_p = dst;
  341. // Adjust source pointer to point to top-left of filter window.
  342. const float *window = src_p - (model->ydim / 2) * src_stride - (model->xdim / 2 - 1);
  343. const int filter_size = model->nsize;
  344. const int nns = model->nns;
  345. for (int i = 0; i < N; i++) {
  346. LOCAL_ALIGNED_32(float, input, [48 * 6]);
  347. float activation[256 * 2];
  348. float mstd[4];
  349. float scale;
  350. if (prescreen[i])
  351. continue;
  352. gather_input(window + i, src_stride, input, mstd, model);
  353. scale = mstd[2];
  354. for (int nn = 0; nn < nns; nn++)
  355. activation[nn] = dot_dsp(s, softmax_q1_filter(nn, model), input, filter_size, scale, model->softmax_bias_q1[nn]);
  356. for (int nn = 0; nn < nns; nn++)
  357. activation[nns + nn] = dot_dsp(s, elliott_q1_filter(nn, model), input, filter_size, scale, model->elliott_bias_q1[nn]);
  358. transform_softmax_exp(activation, nns);
  359. wae5(activation, activation + nns, nns, mstd);
  360. if (use_q2) {
  361. for (int nn = 0; nn < nns; nn++)
  362. activation[nn] = dot_dsp(s, softmax_q2_filter(nn, model), input, filter_size, scale, model->softmax_bias_q2[nn]);
  363. for (int nn = 0; nn < nns; nn++)
  364. activation[nns + nn] = dot_dsp(s, elliott_q2_filter(nn, model), input, filter_size, scale, model->elliott_bias_q2[nn]);
  365. transform_softmax_exp(activation, nns);
  366. wae5(activation, activation + nns, nns, mstd);
  367. }
  368. dst_p[i] = mstd[3] * (use_q2 ? 0.5f : 1.f);
  369. }
  370. }
  371. static void read_bytes(const uint8_t *src, float *dst,
  372. int src_stride, int dst_stride,
  373. int width, int height, float scale)
  374. {
  375. for (int y = 0; y < height; y++) {
  376. for (int x = 0; x < 32; x++)
  377. dst[-x - 1] = src[x];
  378. for (int x = 0; x < width; x++)
  379. dst[x] = src[x];
  380. for (int x = 0; x < 32; x++)
  381. dst[width + x] = src[width - x - 1];
  382. dst += dst_stride;
  383. src += src_stride;
  384. }
  385. }
  386. static void read_words(const uint8_t *srcp, float *dst,
  387. int src_stride, int dst_stride,
  388. int width, int height, float scale)
  389. {
  390. const uint16_t *src = (const uint16_t *)srcp;
  391. src_stride /= 2;
  392. for (int y = 0; y < height; y++) {
  393. for (int x = 0; x < 32; x++)
  394. dst[-x - 1] = src[x] * scale;
  395. for (int x = 0; x < width; x++)
  396. dst[x] = src[x] * scale;
  397. for (int x = 0; x < 32; x++)
  398. dst[width + x] = src[width - x - 1] * scale;
  399. dst += dst_stride;
  400. src += src_stride;
  401. }
  402. }
  403. static void write_bytes(const float *src, uint8_t *dst,
  404. int src_stride, int dst_stride,
  405. int width, int height, int depth,
  406. float scale)
  407. {
  408. for (int y = 0; y < height; y++) {
  409. for (int x = 0; x < width; x++)
  410. dst[x] = av_clip_uint8(src[x]);
  411. dst += dst_stride;
  412. src += src_stride;
  413. }
  414. }
  415. static void write_words(const float *src, uint8_t *dstp,
  416. int src_stride, int dst_stride,
  417. int width, int height, int depth,
  418. float scale)
  419. {
  420. uint16_t *dst = (uint16_t *)dstp;
  421. dst_stride /= 2;
  422. for (int y = 0; y < height; y++) {
  423. for (int x = 0; x < width; x++)
  424. dst[x] = av_clip_uintp2_c(src[x] * scale, depth);
  425. dst += dst_stride;
  426. src += src_stride;
  427. }
  428. }
  429. static void interpolation(const void *src, ptrdiff_t src_stride,
  430. void *dst, const uint8_t *prescreen, int n)
  431. {
  432. const float *src_p = src;
  433. float *dst_p = dst;
  434. const float *window = src_p - 2 * src_stride;
  435. for (int i = 0; i < n; i++) {
  436. float accum = 0.0f;
  437. if (!prescreen[i])
  438. continue;
  439. accum += (-3.0f / 32.0f) * window[0 * src_stride + i];
  440. accum += (19.0f / 32.0f) * window[1 * src_stride + i];
  441. accum += (19.0f / 32.0f) * window[2 * src_stride + i];
  442. accum += (-3.0f / 32.0f) * window[3 * src_stride + i];
  443. dst_p[i] = accum;
  444. }
  445. }
  446. static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  447. {
  448. const NNEDIContext *const s = ctx->priv;
  449. AVFrame *out = arg;
  450. AVFrame *in = s->prev;
  451. const float in_scale = s->in_scale;
  452. const float out_scale = s->out_scale;
  453. const int depth = s->depth;
  454. const int interlaced = in->interlaced_frame;
  455. const int tff = s->field_n == (s->field < 0 ? interlaced ? in->top_field_first : 1 :
  456. (s->field & 1) ^ 1);
  457. for (int p = 0; p < s->nb_planes; p++) {
  458. const int height = s->planeheight[p];
  459. const int width = s->planewidth[p];
  460. const int slice_start = 2 * ((height / 2 * jobnr) / nb_jobs);
  461. const int slice_end = 2 * ((height / 2 * (jobnr+1)) / nb_jobs);
  462. const uint8_t *src_data = in->data[p];
  463. uint8_t *dst_data = out->data[p];
  464. uint8_t *dst = out->data[p] + slice_start * out->linesize[p];
  465. const int src_linesize = in->linesize[p];
  466. const int dst_linesize = out->linesize[p];
  467. uint8_t *prescreen_buf = s->prescreen_buf[jobnr];
  468. float *srcbuf = s->input_buf[jobnr];
  469. const int srcbuf_stride = width + 64;
  470. float *dstbuf = s->output_buf[jobnr];
  471. const int dstbuf_stride = width;
  472. const int slice_height = (slice_end - slice_start) / 2;
  473. const int last_slice = slice_end == height;
  474. const uint8_t *in_line;
  475. uint8_t *out_line;
  476. int y_out;
  477. if (!(s->process_plane & (1 << p))) {
  478. av_image_copy_plane(dst, out->linesize[p],
  479. in->data[p] + slice_start * in->linesize[p],
  480. in->linesize[p],
  481. s->linesize[p], slice_end - slice_start);
  482. continue;
  483. }
  484. y_out = slice_start + (tff ^ (slice_start & 1));
  485. in_line = src_data + (y_out * src_linesize);
  486. out_line = dst_data + (y_out * dst_linesize);
  487. while (y_out < slice_end) {
  488. memcpy(out_line, in_line, s->linesize[p]);
  489. y_out += 2;
  490. in_line += src_linesize * 2;
  491. out_line += dst_linesize * 2;
  492. }
  493. y_out = slice_start + ((!tff) ^ (slice_start & 1));
  494. s->read(src_data + FFMAX(y_out - 5, tff) * src_linesize,
  495. srcbuf + 32,
  496. src_linesize * 2, srcbuf_stride,
  497. width, 1, in_scale);
  498. srcbuf += srcbuf_stride;
  499. s->read(src_data + FFMAX(y_out - 3, tff) * src_linesize,
  500. srcbuf + 32,
  501. src_linesize * 2, srcbuf_stride,
  502. width, 1, in_scale);
  503. srcbuf += srcbuf_stride;
  504. s->read(src_data + FFMAX(y_out - 1, tff) * src_linesize,
  505. srcbuf + 32,
  506. src_linesize * 2, srcbuf_stride,
  507. width, 1, in_scale);
  508. srcbuf += srcbuf_stride;
  509. in_line = src_data + FFMIN(y_out + 1, height - 1 - !tff) * src_linesize;
  510. out_line = dst_data + (y_out * dst_linesize);
  511. s->read(in_line, srcbuf + 32, src_linesize * 2, srcbuf_stride,
  512. width, slice_height - last_slice, in_scale);
  513. y_out += (slice_height - last_slice) * 2;
  514. s->read(src_data + FFMIN(y_out + 1, height - 1 - !tff) * src_linesize,
  515. srcbuf + 32 + srcbuf_stride * (slice_height - last_slice),
  516. src_linesize * 2, srcbuf_stride,
  517. width, 1, in_scale);
  518. s->read(src_data + FFMIN(y_out + 3, height - 1 - !tff) * src_linesize,
  519. srcbuf + 32 + srcbuf_stride * (slice_height + 1 - last_slice),
  520. src_linesize * 2, srcbuf_stride,
  521. width, 1, in_scale);
  522. s->read(src_data + FFMIN(y_out + 5, height - 1 - !tff) * src_linesize,
  523. srcbuf + 32 + srcbuf_stride * (slice_height + 2 - last_slice),
  524. src_linesize * 2, srcbuf_stride,
  525. width, 1, in_scale);
  526. for (int y = 0; y < slice_end - slice_start; y += 2) {
  527. if (s->pscrn > 0)
  528. s->prescreen[s->pscrn > 1](ctx, srcbuf + (y / 2) * srcbuf_stride + 32,
  529. srcbuf_stride, prescreen_buf, width,
  530. &s->prescreener[s->pscrn - 1]);
  531. predictor(ctx,
  532. srcbuf + (y / 2) * srcbuf_stride + 32,
  533. srcbuf_stride,
  534. dstbuf + (y / 2) * dstbuf_stride,
  535. prescreen_buf, width,
  536. &s->coeffs[s->etype][s->nnsparam][s->nsize], s->qual == 2);
  537. if (s->pscrn > 0)
  538. interpolation(srcbuf + (y / 2) * srcbuf_stride + 32,
  539. srcbuf_stride,
  540. dstbuf + (y / 2) * dstbuf_stride,
  541. prescreen_buf, width);
  542. }
  543. s->write(dstbuf, out_line, dstbuf_stride, dst_linesize * 2,
  544. width, slice_height, depth, out_scale);
  545. }
  546. return 0;
  547. }
  548. static int get_frame(AVFilterContext *ctx, int is_second)
  549. {
  550. NNEDIContext *s = ctx->priv;
  551. AVFilterLink *outlink = ctx->outputs[0];
  552. AVFrame *dst;
  553. dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  554. if (!dst)
  555. return AVERROR(ENOMEM);
  556. av_frame_copy_props(dst, s->prev);
  557. dst->interlaced_frame = 0;
  558. dst->pts = s->pts;
  559. ctx->internal->execute(ctx, filter_slice, dst, NULL, FFMIN(s->planeheight[1] / 2, s->nb_threads));
  560. if (s->field == -2 || s->field > 1)
  561. s->field_n = !s->field_n;
  562. return ff_filter_frame(outlink, dst);
  563. }
  564. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  565. {
  566. AVFilterContext *ctx = inlink->dst;
  567. NNEDIContext *s = ctx->priv;
  568. int ret;
  569. if (!s->prev) {
  570. s->prev = in;
  571. return 0;
  572. }
  573. if ((s->deint && !in->interlaced_frame) || ctx->is_disabled) {
  574. s->prev->pts *= 2;
  575. ret = ff_filter_frame(ctx->outputs[0], s->prev);
  576. s->prev = in;
  577. return ret;
  578. }
  579. s->pts = s->prev->pts * 2;
  580. ret = get_frame(ctx, 0);
  581. if (ret < 0 || (s->field > -2 && s->field < 2)) {
  582. av_frame_free(&s->prev);
  583. s->prev = in;
  584. return ret;
  585. }
  586. s->pts = s->prev->pts + in->pts;
  587. ret = get_frame(ctx, 1);
  588. av_frame_free(&s->prev);
  589. s->prev = in;
  590. return ret;
  591. }
  592. static int request_frame(AVFilterLink *link)
  593. {
  594. AVFilterContext *ctx = link->src;
  595. NNEDIContext *s = ctx->priv;
  596. int ret;
  597. if (s->eof)
  598. return AVERROR_EOF;
  599. ret = ff_request_frame(ctx->inputs[0]);
  600. if (ret == AVERROR_EOF && s->prev) {
  601. AVFrame *next = av_frame_clone(s->prev);
  602. if (!next)
  603. return AVERROR(ENOMEM);
  604. next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(ctx->outputs[0]->frame_rate),
  605. ctx->outputs[0]->time_base);
  606. s->eof = 1;
  607. ret = filter_frame(ctx->inputs[0], next);
  608. } else if (ret < 0) {
  609. return ret;
  610. }
  611. return ret;
  612. }
  613. static void copy_weights(float *dst, int n, const float **data)
  614. {
  615. memcpy(dst, *data, n * sizeof(float));
  616. *data += n;
  617. }
  618. static float *allocate(float **ptr, int size)
  619. {
  620. float *ret = *ptr;
  621. *ptr += size;
  622. return ret;
  623. }
  624. static int allocate_model(PredictorCoefficients *coeffs, int xdim, int ydim, int nns)
  625. {
  626. int filter_size = nns * xdim * ydim;
  627. int bias_size = nns;
  628. float *data;
  629. data = av_calloc(filter_size + bias_size, 4 * sizeof(float));
  630. if (!data)
  631. return AVERROR(ENOMEM);
  632. coeffs->data = data;
  633. coeffs->xdim = xdim;
  634. coeffs->ydim = ydim;
  635. coeffs->nsize = xdim * ydim;
  636. coeffs->nns = nns;
  637. coeffs->softmax_q1 = allocate(&data, filter_size);
  638. coeffs->elliott_q1 = allocate(&data, filter_size);
  639. coeffs->softmax_bias_q1 = allocate(&data, bias_size);
  640. coeffs->elliott_bias_q1 = allocate(&data, bias_size);
  641. coeffs->softmax_q2 = allocate(&data, filter_size);
  642. coeffs->elliott_q2 = allocate(&data, filter_size);
  643. coeffs->softmax_bias_q2 = allocate(&data, bias_size);
  644. coeffs->elliott_bias_q2 = allocate(&data, bias_size);
  645. return 0;
  646. }
  647. static int read_weights(AVFilterContext *ctx, const float *bdata)
  648. {
  649. NNEDIContext *s = ctx->priv;
  650. int ret;
  651. copy_weights(&s->prescreener[0].kernel_l0[0][0], 4 * 48, &bdata);
  652. copy_weights(s->prescreener[0].bias_l0, 4, &bdata);
  653. copy_weights(&s->prescreener[0].kernel_l1[0][0], 4 * 4, &bdata);
  654. copy_weights(s->prescreener[0].bias_l1, 4, &bdata);
  655. copy_weights(&s->prescreener[0].kernel_l2[0][0], 4 * 8, &bdata);
  656. copy_weights(s->prescreener[0].bias_l2, 4, &bdata);
  657. for (int i = 0; i < 3; i++) {
  658. PrescreenerCoefficients *data = &s->prescreener[i + 1];
  659. float kernel_l0_shuffled[4 * 64];
  660. float kernel_l1_shuffled[4 * 4];
  661. copy_weights(kernel_l0_shuffled, 4 * 64, &bdata);
  662. copy_weights(data->bias_l0, 4, &bdata);
  663. copy_weights(kernel_l1_shuffled, 4 * 4, &bdata);
  664. copy_weights(data->bias_l1, 4, &bdata);
  665. for (int n = 0; n < 4; n++) {
  666. for (int k = 0; k < 64; k++)
  667. data->kernel_l0[n][k] = kernel_l0_shuffled[(k / 8) * 32 + n * 8 + k % 8];
  668. for (int k = 0; k < 4; k++)
  669. data->kernel_l1[n][k] = kernel_l1_shuffled[k * 4 + n];
  670. }
  671. }
  672. for (int m = 0; m < 2; m++) {
  673. // Grouping by neuron count.
  674. for (int i = 0; i < 5; i++) {
  675. const int nns = NNEDI_NNS[i];
  676. // Grouping by window size.
  677. for (int j = 0; j < 7; j++) {
  678. PredictorCoefficients *model = &s->coeffs[m][i][j];
  679. const int xdim = NNEDI_XDIM[j];
  680. const int ydim = NNEDI_YDIM[j];
  681. const int filter_size = xdim * ydim;
  682. ret = allocate_model(model, xdim, ydim, nns);
  683. if (ret < 0)
  684. return ret;
  685. // Quality 1 model. NNS[i] * (XDIM[j] * YDIM[j]) * 2 coefficients.
  686. copy_weights(model->softmax_q1, nns * filter_size, &bdata);
  687. copy_weights(model->elliott_q1, nns * filter_size, &bdata);
  688. // Quality 1 model bias. NNS[i] * 2 coefficients.
  689. copy_weights(model->softmax_bias_q1, nns, &bdata);
  690. copy_weights(model->elliott_bias_q1, nns, &bdata);
  691. // Quality 2 model. NNS[i] * (XDIM[j] * YDIM[j]) * 2 coefficients.
  692. copy_weights(model->softmax_q2, nns * filter_size, &bdata);
  693. copy_weights(model->elliott_q2, nns * filter_size, &bdata);
  694. // Quality 2 model bias. NNS[i] * 2 coefficients.
  695. copy_weights(model->softmax_bias_q2, nns, &bdata);
  696. copy_weights(model->elliott_bias_q2, nns, &bdata);
  697. }
  698. }
  699. }
  700. return 0;
  701. }
  702. static float mean(const float *input, int size)
  703. {
  704. float sum = 0.f;
  705. for (int i = 0; i < size; i++)
  706. sum += input[i];
  707. return sum / size;
  708. }
  709. static void transform(float *input, int size, float mean, float half)
  710. {
  711. for (int i = 0; i < size; i++)
  712. input[i] = (input[i] - mean) / half;
  713. }
  714. static void subtract_mean_old(PrescreenerCoefficients *coeffs, float half)
  715. {
  716. for (int n = 0; n < 4; n++) {
  717. float m = mean(coeffs->kernel_l0[n], 48);
  718. transform(coeffs->kernel_l0[n], 48, m, half);
  719. }
  720. }
  721. static void subtract_mean_new(PrescreenerCoefficients *coeffs, float half)
  722. {
  723. for (int n = 0; n < 4; n++) {
  724. float m = mean(coeffs->kernel_l0[n], 64);
  725. transform(coeffs->kernel_l0[n], 64, m, half);
  726. }
  727. }
  728. static void subtract_mean_predictor(PredictorCoefficients *model)
  729. {
  730. const int filter_size = model->nsize;
  731. const int nns = model->nns;
  732. const float scale = 1.f / nns;
  733. double softmax_means[256]; // Average of individual softmax filters.
  734. double elliott_means[256]; // Average of individual elliott filters.
  735. double mean_filter[48 * 6] = { 0 }; // Pointwise average of all softmax filters.
  736. double mean_bias;
  737. // Quality 1.
  738. for (int nn = 0; nn < nns; nn++) {
  739. softmax_means[nn] = mean(model->softmax_q1 + nn * filter_size, filter_size);
  740. elliott_means[nn] = mean(model->elliott_q1 + nn * filter_size, filter_size);
  741. for (int k = 0; k < filter_size; k++)
  742. mean_filter[k] += model->softmax_q1[nn * filter_size + k] - softmax_means[nn];
  743. }
  744. for (int k = 0; k < filter_size; k++)
  745. mean_filter[k] *= scale;
  746. mean_bias = mean(model->softmax_bias_q1, nns);
  747. for (int nn = 0; nn < nns; nn++) {
  748. for (int k = 0; k < filter_size; k++) {
  749. model->softmax_q1[nn * filter_size + k] -= softmax_means[nn] + mean_filter[k];
  750. model->elliott_q1[nn * filter_size + k] -= elliott_means[nn];
  751. }
  752. model->softmax_bias_q1[nn] -= mean_bias;
  753. }
  754. // Quality 2.
  755. memset(mean_filter, 0, sizeof(mean_filter));
  756. for (int nn = 0; nn < nns; nn++) {
  757. softmax_means[nn] = mean(model->softmax_q2 + nn * filter_size, filter_size);
  758. elliott_means[nn] = mean(model->elliott_q2 + nn * filter_size, filter_size);
  759. for (int k = 0; k < filter_size; k++) {
  760. mean_filter[k] += model->softmax_q2[nn * filter_size + k] - softmax_means[nn];
  761. }
  762. }
  763. for (int k = 0; k < filter_size; k++)
  764. mean_filter[k] *= scale;
  765. mean_bias = mean(model->softmax_bias_q2, nns);
  766. for (int nn = 0; nn < nns; nn++) {
  767. for (int k = 0; k < filter_size; k++) {
  768. model->softmax_q2[nn * filter_size + k] -= softmax_means[nn] + mean_filter[k];
  769. model->elliott_q2[nn * filter_size + k] -= elliott_means[nn];
  770. }
  771. model->softmax_bias_q2[nn] -= mean_bias;
  772. }
  773. }
  774. static av_cold int init(AVFilterContext *ctx)
  775. {
  776. NNEDIContext *s = ctx->priv;
  777. FILE *weights_file = NULL;
  778. int64_t weights_size;
  779. float *bdata;
  780. size_t bytes_read;
  781. int ret = 0;
  782. weights_file = av_fopen_utf8(s->weights_file, "rb");
  783. if (!weights_file) {
  784. av_log(ctx, AV_LOG_ERROR, "No weights file provided, aborting!\n");
  785. return AVERROR(EINVAL);
  786. }
  787. if (fseek(weights_file, 0, SEEK_END)) {
  788. av_log(ctx, AV_LOG_ERROR, "Couldn't seek to the end of weights file.\n");
  789. fclose(weights_file);
  790. return AVERROR(EINVAL);
  791. }
  792. weights_size = ftell(weights_file);
  793. if (weights_size == -1) {
  794. fclose(weights_file);
  795. av_log(ctx, AV_LOG_ERROR, "Couldn't get size of weights file.\n");
  796. return AVERROR(EINVAL);
  797. } else if (weights_size != NNEDI_WEIGHTS_SIZE) {
  798. fclose(weights_file);
  799. av_log(ctx, AV_LOG_ERROR, "Unexpected weights file size.\n");
  800. return AVERROR(EINVAL);
  801. }
  802. if (fseek(weights_file, 0, SEEK_SET)) {
  803. fclose(weights_file);
  804. av_log(ctx, AV_LOG_ERROR, "Couldn't seek to the start of weights file.\n");
  805. return AVERROR(EINVAL);
  806. }
  807. bdata = av_malloc(NNEDI_WEIGHTS_SIZE);
  808. if (!bdata) {
  809. fclose(weights_file);
  810. return AVERROR(ENOMEM);
  811. }
  812. bytes_read = fread(bdata, 1, NNEDI_WEIGHTS_SIZE, weights_file);
  813. if (bytes_read != NNEDI_WEIGHTS_SIZE) {
  814. fclose(weights_file);
  815. ret = AVERROR_INVALIDDATA;
  816. av_log(ctx, AV_LOG_ERROR, "Couldn't read weights file.\n");
  817. goto fail;
  818. }
  819. fclose(weights_file);
  820. s->fdsp = avpriv_float_dsp_alloc(0);
  821. if (!s->fdsp) {
  822. ret = AVERROR(ENOMEM);
  823. goto fail;
  824. }
  825. ret = read_weights(ctx, bdata);
  826. if (ret < 0)
  827. goto fail;
  828. fail:
  829. av_free(bdata);
  830. return ret;
  831. }
  832. static int config_input(AVFilterLink *inlink)
  833. {
  834. AVFilterContext *ctx = inlink->dst;
  835. NNEDIContext *s = ctx->priv;
  836. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  837. int ret;
  838. s->depth = desc->comp[0].depth;
  839. s->nb_threads = ff_filter_get_nb_threads(ctx);
  840. s->nb_planes = av_pix_fmt_count_planes(inlink->format);
  841. if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
  842. return ret;
  843. s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
  844. s->planewidth[0] = s->planewidth[3] = inlink->w;
  845. s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
  846. s->planeheight[0] = s->planeheight[3] = inlink->h;
  847. s->half = ((1 << 8) - 1) / 2.f;
  848. s->out_scale = 1 << (s->depth - 8);
  849. s->in_scale = 1.f / s->out_scale;
  850. switch (s->depth) {
  851. case 8:
  852. s->read = read_bytes;
  853. s->write = write_bytes;
  854. break;
  855. default:
  856. s->read = read_words;
  857. s->write = write_words;
  858. break;
  859. }
  860. subtract_mean_old(&s->prescreener[0], s->half);
  861. subtract_mean_new(&s->prescreener[1], s->half);
  862. subtract_mean_new(&s->prescreener[2], s->half);
  863. subtract_mean_new(&s->prescreener[3], s->half);
  864. s->prescreen[0] = process_old;
  865. s->prescreen[1] = process_new;
  866. for (int i = 0; i < 2; i++) {
  867. for (int j = 0; j < 5; j++) {
  868. for (int k = 0; k < 7; k++)
  869. subtract_mean_predictor(&s->coeffs[i][j][k]);
  870. }
  871. }
  872. s->input_size = (s->planewidth[0] + 64) * (s->planeheight[0] + 6);
  873. s->input_buf = av_calloc(s->nb_threads, sizeof(*s->input_buf));
  874. if (!s->input_buf)
  875. return AVERROR(ENOMEM);
  876. for (int i = 0; i < s->nb_threads; i++) {
  877. s->input_buf[i] = av_calloc(s->input_size, sizeof(**s->input_buf));
  878. if (!s->input_buf[i])
  879. return AVERROR(ENOMEM);
  880. }
  881. s->output_buf = av_calloc(s->nb_threads, sizeof(*s->output_buf));
  882. if (!s->output_buf)
  883. return AVERROR(ENOMEM);
  884. for (int i = 0; i < s->nb_threads; i++) {
  885. s->output_buf[i] = av_calloc(s->input_size, sizeof(**s->output_buf));
  886. if (!s->output_buf[i])
  887. return AVERROR(ENOMEM);
  888. }
  889. s->prescreen_buf = av_calloc(s->nb_threads, sizeof(*s->prescreen_buf));
  890. if (!s->prescreen_buf)
  891. return AVERROR(ENOMEM);
  892. for (int i = 0; i < s->nb_threads; i++) {
  893. s->prescreen_buf[i] = av_calloc(s->planewidth[0], sizeof(**s->prescreen_buf));
  894. if (!s->prescreen_buf[i])
  895. return AVERROR(ENOMEM);
  896. }
  897. return 0;
  898. }
  899. static av_cold void uninit(AVFilterContext *ctx)
  900. {
  901. NNEDIContext *s = ctx->priv;
  902. for (int i = 0; i < s->nb_threads && s->prescreen_buf; i++)
  903. av_freep(&s->prescreen_buf[i]);
  904. av_freep(&s->prescreen_buf);
  905. for (int i = 0; i < s->nb_threads && s->input_buf; i++)
  906. av_freep(&s->input_buf[i]);
  907. av_freep(&s->input_buf);
  908. for (int i = 0; i < s->nb_threads && s->output_buf; i++)
  909. av_freep(&s->output_buf[i]);
  910. av_freep(&s->output_buf);
  911. av_freep(&s->fdsp);
  912. for (int i = 0; i < 2; i++) {
  913. for (int j = 0; j < 5; j++) {
  914. for (int k = 0; k < 7; k++) {
  915. av_freep(&s->coeffs[i][j][k].data);
  916. }
  917. }
  918. }
  919. av_frame_free(&s->prev);
  920. }
  921. static const AVFilterPad inputs[] = {
  922. {
  923. .name = "default",
  924. .type = AVMEDIA_TYPE_VIDEO,
  925. .filter_frame = filter_frame,
  926. .config_props = config_input,
  927. },
  928. { NULL }
  929. };
  930. static const AVFilterPad outputs[] = {
  931. {
  932. .name = "default",
  933. .type = AVMEDIA_TYPE_VIDEO,
  934. .config_props = config_output,
  935. .request_frame = request_frame,
  936. },
  937. { NULL }
  938. };
  939. AVFilter ff_vf_nnedi = {
  940. .name = "nnedi",
  941. .description = NULL_IF_CONFIG_SMALL("Apply neural network edge directed interpolation intra-only deinterlacer."),
  942. .priv_size = sizeof(NNEDIContext),
  943. .priv_class = &nnedi_class,
  944. .init = init,
  945. .uninit = uninit,
  946. .query_formats = query_formats,
  947. .inputs = inputs,
  948. .outputs = outputs,
  949. .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
  950. .process_command = ff_filter_process_command,
  951. };