vf_scale_npp.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. /**
  19. * @file
  20. * scale video filter
  21. */
  22. #include <nppi.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include "libavutil/avstring.h"
  26. #include "libavutil/common.h"
  27. #include "libavutil/eval.h"
  28. #include "libavutil/hwcontext.h"
  29. #include "libavutil/hwcontext_cuda.h"
  30. #include "libavutil/internal.h"
  31. #include "libavutil/mathematics.h"
  32. #include "libavutil/opt.h"
  33. #include "libavutil/pixdesc.h"
  34. #include "avfilter.h"
  35. #include "formats.h"
  36. #include "internal.h"
  37. #include "video.h"
  38. static const enum AVPixelFormat supported_formats[] = {
  39. AV_PIX_FMT_YUV420P,
  40. AV_PIX_FMT_NV12,
  41. AV_PIX_FMT_YUV444P,
  42. };
  43. static const enum AVPixelFormat deinterleaved_formats[][2] = {
  44. { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P },
  45. };
  46. static const char *const var_names[] = {
  47. "PI",
  48. "PHI",
  49. "E",
  50. "in_w", "iw",
  51. "in_h", "ih",
  52. "out_w", "ow",
  53. "out_h", "oh",
  54. "a", "dar",
  55. "sar",
  56. NULL
  57. };
  58. enum var_name {
  59. VAR_PI,
  60. VAR_PHI,
  61. VAR_E,
  62. VAR_IN_W, VAR_IW,
  63. VAR_IN_H, VAR_IH,
  64. VAR_OUT_W, VAR_OW,
  65. VAR_OUT_H, VAR_OH,
  66. VAR_A, VAR_DAR,
  67. VAR_SAR,
  68. VARS_NB
  69. };
  70. enum ScaleStage {
  71. STAGE_DEINTERLEAVE,
  72. STAGE_RESIZE,
  73. STAGE_INTERLEAVE,
  74. STAGE_NB,
  75. };
  76. typedef struct NPPScaleStageContext {
  77. int stage_needed;
  78. enum AVPixelFormat in_fmt;
  79. enum AVPixelFormat out_fmt;
  80. struct {
  81. int width;
  82. int height;
  83. } planes_in[3], planes_out[3];
  84. AVBufferRef *frames_ctx;
  85. AVFrame *frame;
  86. } NPPScaleStageContext;
  87. typedef struct NPPScaleContext {
  88. const AVClass *class;
  89. NPPScaleStageContext stages[STAGE_NB];
  90. AVFrame *tmp_frame;
  91. int passthrough;
  92. int shift_width, shift_height;
  93. /**
  94. * New dimensions. Special values are:
  95. * 0 = original width/height
  96. * -1 = keep original aspect
  97. */
  98. int w, h;
  99. /**
  100. * Output sw format. AV_PIX_FMT_NONE for no conversion.
  101. */
  102. enum AVPixelFormat format;
  103. char *w_expr; ///< width expression string
  104. char *h_expr; ///< height expression string
  105. char *format_str;
  106. int interp_algo;
  107. } NPPScaleContext;
  108. static int nppscale_init(AVFilterContext *ctx)
  109. {
  110. NPPScaleContext *s = ctx->priv;
  111. int i;
  112. if (!strcmp(s->format_str, "same")) {
  113. s->format = AV_PIX_FMT_NONE;
  114. } else {
  115. s->format = av_get_pix_fmt(s->format_str);
  116. if (s->format == AV_PIX_FMT_NONE) {
  117. av_log(ctx, AV_LOG_ERROR, "Unrecognized pixel format: %s\n", s->format_str);
  118. return AVERROR(EINVAL);
  119. }
  120. }
  121. for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) {
  122. s->stages[i].frame = av_frame_alloc();
  123. if (!s->stages[i].frame)
  124. return AVERROR(ENOMEM);
  125. }
  126. s->tmp_frame = av_frame_alloc();
  127. if (!s->tmp_frame)
  128. return AVERROR(ENOMEM);
  129. return 0;
  130. }
  131. static void nppscale_uninit(AVFilterContext *ctx)
  132. {
  133. NPPScaleContext *s = ctx->priv;
  134. int i;
  135. for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) {
  136. av_frame_free(&s->stages[i].frame);
  137. av_buffer_unref(&s->stages[i].frames_ctx);
  138. }
  139. av_frame_free(&s->tmp_frame);
  140. }
  141. static int nppscale_query_formats(AVFilterContext *ctx)
  142. {
  143. static const enum AVPixelFormat pixel_formats[] = {
  144. AV_PIX_FMT_CUDA, AV_PIX_FMT_NONE,
  145. };
  146. AVFilterFormats *pix_fmts = ff_make_format_list(pixel_formats);
  147. ff_set_common_formats(ctx, pix_fmts);
  148. return 0;
  149. }
  150. static int init_stage(NPPScaleStageContext *stage, AVBufferRef *device_ctx)
  151. {
  152. AVBufferRef *out_ref = NULL;
  153. AVHWFramesContext *out_ctx;
  154. int in_sw, in_sh, out_sw, out_sh;
  155. int ret, i;
  156. av_pix_fmt_get_chroma_sub_sample(stage->in_fmt, &in_sw, &in_sh);
  157. av_pix_fmt_get_chroma_sub_sample(stage->out_fmt, &out_sw, &out_sh);
  158. if (!stage->planes_out[0].width) {
  159. stage->planes_out[0].width = stage->planes_in[0].width;
  160. stage->planes_out[0].height = stage->planes_in[0].height;
  161. }
  162. for (i = 1; i < FF_ARRAY_ELEMS(stage->planes_in); i++) {
  163. stage->planes_in[i].width = stage->planes_in[0].width >> in_sw;
  164. stage->planes_in[i].height = stage->planes_in[0].height >> in_sh;
  165. stage->planes_out[i].width = stage->planes_out[0].width >> out_sw;
  166. stage->planes_out[i].height = stage->planes_out[0].height >> out_sh;
  167. }
  168. out_ref = av_hwframe_ctx_alloc(device_ctx);
  169. if (!out_ref)
  170. return AVERROR(ENOMEM);
  171. out_ctx = (AVHWFramesContext*)out_ref->data;
  172. out_ctx->format = AV_PIX_FMT_CUDA;
  173. out_ctx->sw_format = stage->out_fmt;
  174. out_ctx->width = FFALIGN(stage->planes_out[0].width, 32);
  175. out_ctx->height = FFALIGN(stage->planes_out[0].height, 32);
  176. ret = av_hwframe_ctx_init(out_ref);
  177. if (ret < 0)
  178. goto fail;
  179. av_frame_unref(stage->frame);
  180. ret = av_hwframe_get_buffer(out_ref, stage->frame, 0);
  181. if (ret < 0)
  182. goto fail;
  183. stage->frame->width = stage->planes_out[0].width;
  184. stage->frame->height = stage->planes_out[0].height;
  185. av_buffer_unref(&stage->frames_ctx);
  186. stage->frames_ctx = out_ref;
  187. return 0;
  188. fail:
  189. av_buffer_unref(&out_ref);
  190. return ret;
  191. }
  192. static int format_is_supported(enum AVPixelFormat fmt)
  193. {
  194. int i;
  195. for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
  196. if (supported_formats[i] == fmt)
  197. return 1;
  198. return 0;
  199. }
  200. static enum AVPixelFormat get_deinterleaved_format(enum AVPixelFormat fmt)
  201. {
  202. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
  203. int i, planes;
  204. planes = av_pix_fmt_count_planes(fmt);
  205. if (planes == desc->nb_components)
  206. return fmt;
  207. for (i = 0; i < FF_ARRAY_ELEMS(deinterleaved_formats); i++)
  208. if (deinterleaved_formats[i][0] == fmt)
  209. return deinterleaved_formats[i][1];
  210. return AV_PIX_FMT_NONE;
  211. }
  212. static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_height,
  213. int out_width, int out_height)
  214. {
  215. NPPScaleContext *s = ctx->priv;
  216. AVHWFramesContext *in_frames_ctx;
  217. enum AVPixelFormat in_format;
  218. enum AVPixelFormat out_format;
  219. enum AVPixelFormat in_deinterleaved_format;
  220. enum AVPixelFormat out_deinterleaved_format;
  221. int i, ret, last_stage = -1;
  222. /* check that we have a hw context */
  223. if (!ctx->inputs[0]->hw_frames_ctx) {
  224. av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
  225. return AVERROR(EINVAL);
  226. }
  227. in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data;
  228. in_format = in_frames_ctx->sw_format;
  229. out_format = (s->format == AV_PIX_FMT_NONE) ? in_format : s->format;
  230. if (!format_is_supported(in_format)) {
  231. av_log(ctx, AV_LOG_ERROR, "Unsupported input format: %s\n",
  232. av_get_pix_fmt_name(in_format));
  233. return AVERROR(ENOSYS);
  234. }
  235. if (!format_is_supported(out_format)) {
  236. av_log(ctx, AV_LOG_ERROR, "Unsupported output format: %s\n",
  237. av_get_pix_fmt_name(out_format));
  238. return AVERROR(ENOSYS);
  239. }
  240. in_deinterleaved_format = get_deinterleaved_format(in_format);
  241. out_deinterleaved_format = get_deinterleaved_format(out_format);
  242. if (in_deinterleaved_format == AV_PIX_FMT_NONE ||
  243. out_deinterleaved_format == AV_PIX_FMT_NONE)
  244. return AVERROR_BUG;
  245. /* figure out which stages need to be done */
  246. if (in_width != out_width || in_height != out_height ||
  247. in_deinterleaved_format != out_deinterleaved_format)
  248. s->stages[STAGE_RESIZE].stage_needed = 1;
  249. if (!s->stages[STAGE_RESIZE].stage_needed && in_format == out_format)
  250. s->passthrough = 1;
  251. if (!s->passthrough) {
  252. if (in_format != in_deinterleaved_format)
  253. s->stages[STAGE_DEINTERLEAVE].stage_needed = 1;
  254. if (out_format != out_deinterleaved_format)
  255. s->stages[STAGE_INTERLEAVE].stage_needed = 1;
  256. }
  257. s->stages[STAGE_DEINTERLEAVE].in_fmt = in_format;
  258. s->stages[STAGE_DEINTERLEAVE].out_fmt = in_deinterleaved_format;
  259. s->stages[STAGE_DEINTERLEAVE].planes_in[0].width = in_width;
  260. s->stages[STAGE_DEINTERLEAVE].planes_in[0].height = in_height;
  261. s->stages[STAGE_RESIZE].in_fmt = in_deinterleaved_format;
  262. s->stages[STAGE_RESIZE].out_fmt = out_deinterleaved_format;
  263. s->stages[STAGE_RESIZE].planes_in[0].width = in_width;
  264. s->stages[STAGE_RESIZE].planes_in[0].height = in_height;
  265. s->stages[STAGE_RESIZE].planes_out[0].width = out_width;
  266. s->stages[STAGE_RESIZE].planes_out[0].height = out_height;
  267. s->stages[STAGE_INTERLEAVE].in_fmt = out_deinterleaved_format;
  268. s->stages[STAGE_INTERLEAVE].out_fmt = out_format;
  269. s->stages[STAGE_INTERLEAVE].planes_in[0].width = out_width;
  270. s->stages[STAGE_INTERLEAVE].planes_in[0].height = out_height;
  271. /* init the hardware contexts */
  272. for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) {
  273. if (!s->stages[i].stage_needed)
  274. continue;
  275. ret = init_stage(&s->stages[i], in_frames_ctx->device_ref);
  276. if (ret < 0)
  277. return ret;
  278. last_stage = i;
  279. }
  280. if (last_stage < 0)
  281. return AVERROR_BUG;
  282. ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx);
  283. if (!ctx->outputs[0]->hw_frames_ctx)
  284. return AVERROR(ENOMEM);
  285. return 0;
  286. }
  287. static int nppscale_config_props(AVFilterLink *outlink)
  288. {
  289. AVFilterContext *ctx = outlink->src;
  290. AVFilterLink *inlink = outlink->src->inputs[0];
  291. NPPScaleContext *s = ctx->priv;
  292. int64_t w, h;
  293. double var_values[VARS_NB], res;
  294. char *expr;
  295. int ret;
  296. var_values[VAR_PI] = M_PI;
  297. var_values[VAR_PHI] = M_PHI;
  298. var_values[VAR_E] = M_E;
  299. var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w;
  300. var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h;
  301. var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN;
  302. var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN;
  303. var_values[VAR_A] = (double) inlink->w / inlink->h;
  304. var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
  305. (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
  306. var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR];
  307. /* evaluate width and height */
  308. av_expr_parse_and_eval(&res, (expr = s->w_expr),
  309. var_names, var_values,
  310. NULL, NULL, NULL, NULL, NULL, 0, ctx);
  311. s->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res;
  312. if ((ret = av_expr_parse_and_eval(&res, (expr = s->h_expr),
  313. var_names, var_values,
  314. NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
  315. goto fail;
  316. s->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res;
  317. /* evaluate again the width, as it may depend on the output height */
  318. if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr),
  319. var_names, var_values,
  320. NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
  321. goto fail;
  322. s->w = res;
  323. w = s->w;
  324. h = s->h;
  325. /* sanity check params */
  326. if (w < -1 || h < -1) {
  327. av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not acceptable.\n");
  328. return AVERROR(EINVAL);
  329. }
  330. if (w == -1 && h == -1)
  331. s->w = s->h = 0;
  332. if (!(w = s->w))
  333. w = inlink->w;
  334. if (!(h = s->h))
  335. h = inlink->h;
  336. if (w == -1)
  337. w = av_rescale(h, inlink->w, inlink->h);
  338. if (h == -1)
  339. h = av_rescale(w, inlink->h, inlink->w);
  340. if (w > INT_MAX || h > INT_MAX ||
  341. (h * inlink->w) > INT_MAX ||
  342. (w * inlink->h) > INT_MAX)
  343. av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
  344. outlink->w = w;
  345. outlink->h = h;
  346. ret = init_processing_chain(ctx, inlink->w, inlink->h, w, h);
  347. if (ret < 0)
  348. return ret;
  349. av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d\n",
  350. inlink->w, inlink->h, outlink->w, outlink->h);
  351. if (inlink->sample_aspect_ratio.num)
  352. outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
  353. outlink->w*inlink->h},
  354. inlink->sample_aspect_ratio);
  355. else
  356. outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
  357. return 0;
  358. fail:
  359. av_log(NULL, AV_LOG_ERROR,
  360. "Error when evaluating the expression '%s'\n", expr);
  361. return ret;
  362. }
  363. static int nppscale_deinterleave(AVFilterContext *ctx, NPPScaleStageContext *stage,
  364. AVFrame *out, AVFrame *in)
  365. {
  366. AVHWFramesContext *in_frames_ctx = (AVHWFramesContext*)in->hw_frames_ctx->data;
  367. NppStatus err;
  368. switch (in_frames_ctx->sw_format) {
  369. case AV_PIX_FMT_NV12:
  370. err = nppiYCbCr420_8u_P2P3R(in->data[0], in->linesize[0],
  371. in->data[1], in->linesize[1],
  372. out->data, out->linesize,
  373. (NppiSize){ in->width, in->height });
  374. break;
  375. default:
  376. return AVERROR_BUG;
  377. }
  378. if (err != NPP_SUCCESS) {
  379. av_log(ctx, AV_LOG_ERROR, "NPP deinterleave error: %d\n", err);
  380. return AVERROR_UNKNOWN;
  381. }
  382. return 0;
  383. }
  384. static int nppscale_resize(AVFilterContext *ctx, NPPScaleStageContext *stage,
  385. AVFrame *out, AVFrame *in)
  386. {
  387. NPPScaleContext *s = ctx->priv;
  388. NppStatus err;
  389. int i;
  390. for (i = 0; i < FF_ARRAY_ELEMS(in->data) && in->data[i]; i++) {
  391. int iw = stage->planes_in[i].width;
  392. int ih = stage->planes_in[i].height;
  393. int ow = stage->planes_out[i].width;
  394. int oh = stage->planes_out[i].height;
  395. err = nppiResizeSqrPixel_8u_C1R(in->data[i], (NppiSize){ iw, ih },
  396. in->linesize[i], (NppiRect){ 0, 0, iw, ih },
  397. out->data[i], out->linesize[i],
  398. (NppiRect){ 0, 0, ow, oh },
  399. (double)ow / iw, (double)oh / ih,
  400. 0.0, 0.0, s->interp_algo);
  401. if (err != NPP_SUCCESS) {
  402. av_log(ctx, AV_LOG_ERROR, "NPP resize error: %d\n", err);
  403. return AVERROR_UNKNOWN;
  404. }
  405. }
  406. return 0;
  407. }
  408. static int nppscale_interleave(AVFilterContext *ctx, NPPScaleStageContext *stage,
  409. AVFrame *out, AVFrame *in)
  410. {
  411. AVHWFramesContext *out_frames_ctx = (AVHWFramesContext*)out->hw_frames_ctx->data;
  412. NppStatus err;
  413. switch (out_frames_ctx->sw_format) {
  414. case AV_PIX_FMT_NV12:
  415. err = nppiYCbCr420_8u_P3P2R((const uint8_t**)in->data,
  416. in->linesize,
  417. out->data[0], out->linesize[0],
  418. out->data[1], out->linesize[1],
  419. (NppiSize){ in->width, in->height });
  420. break;
  421. default:
  422. return AVERROR_BUG;
  423. }
  424. if (err != NPP_SUCCESS) {
  425. av_log(ctx, AV_LOG_ERROR, "NPP deinterleave error: %d\n", err);
  426. return AVERROR_UNKNOWN;
  427. }
  428. return 0;
  429. }
  430. static int (*const nppscale_process[])(AVFilterContext *ctx, NPPScaleStageContext *stage,
  431. AVFrame *out, AVFrame *in) = {
  432. [STAGE_DEINTERLEAVE] = nppscale_deinterleave,
  433. [STAGE_RESIZE] = nppscale_resize,
  434. [STAGE_INTERLEAVE] = nppscale_interleave,
  435. };
  436. static int nppscale_scale(AVFilterContext *ctx, AVFrame *out, AVFrame *in)
  437. {
  438. NPPScaleContext *s = ctx->priv;
  439. AVFrame *src = in;
  440. int i, ret, last_stage = -1;
  441. for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) {
  442. if (!s->stages[i].stage_needed)
  443. continue;
  444. ret = nppscale_process[i](ctx, &s->stages[i], s->stages[i].frame, src);
  445. if (ret < 0)
  446. return ret;
  447. src = s->stages[i].frame;
  448. last_stage = i;
  449. }
  450. if (last_stage < 0)
  451. return AVERROR_BUG;
  452. ret = av_hwframe_get_buffer(src->hw_frames_ctx, s->tmp_frame, 0);
  453. if (ret < 0)
  454. return ret;
  455. av_frame_move_ref(out, src);
  456. av_frame_move_ref(src, s->tmp_frame);
  457. ret = av_frame_copy_props(out, in);
  458. if (ret < 0)
  459. return ret;
  460. return 0;
  461. }
  462. static int nppscale_filter_frame(AVFilterLink *link, AVFrame *in)
  463. {
  464. AVFilterContext *ctx = link->dst;
  465. NPPScaleContext *s = ctx->priv;
  466. AVFilterLink *outlink = ctx->outputs[0];
  467. AVHWFramesContext *frames_ctx = (AVHWFramesContext*)outlink->hw_frames_ctx->data;
  468. AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
  469. AVFrame *out = NULL;
  470. CUresult err;
  471. CUcontext dummy;
  472. int ret = 0;
  473. if (s->passthrough)
  474. return ff_filter_frame(outlink, in);
  475. out = av_frame_alloc();
  476. if (!out) {
  477. ret = AVERROR(ENOMEM);
  478. goto fail;
  479. }
  480. av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
  481. (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
  482. (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
  483. INT_MAX);
  484. err = cuCtxPushCurrent(device_hwctx->cuda_ctx);
  485. if (err != CUDA_SUCCESS) {
  486. ret = AVERROR_UNKNOWN;
  487. goto fail;
  488. }
  489. ret = nppscale_scale(ctx, out, in);
  490. cuCtxPopCurrent(&dummy);
  491. if (ret < 0)
  492. goto fail;
  493. av_frame_free(&in);
  494. return ff_filter_frame(outlink, out);
  495. fail:
  496. av_frame_free(&in);
  497. av_frame_free(&out);
  498. return ret;
  499. }
  500. #define OFFSET(x) offsetof(NPPScaleContext, x)
  501. #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
  502. static const AVOption options[] = {
  503. { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS },
  504. { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS },
  505. { "format", "Output pixel format", OFFSET(format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS },
  506. { "interp_algo", "Interpolation algorithm used for resizing", OFFSET(interp_algo), AV_OPT_TYPE_INT, { .i64 = NPPI_INTER_CUBIC }, 0, INT_MAX, FLAGS, "interp_algo" },
  507. { "nn", "nearest neighbour", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_NN }, 0, 0, FLAGS, "interp_algo" },
  508. { "linear", "linear", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_LINEAR }, 0, 0, FLAGS, "interp_algo" },
  509. { "cubic", "cubic", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_CUBIC }, 0, 0, FLAGS, "interp_algo" },
  510. { "cubic2p_bspline", "2-parameter cubic (B=1, C=0)", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_CUBIC2P_BSPLINE }, 0, 0, FLAGS, "interp_algo" },
  511. { "cubic2p_catmullrom", "2-parameter cubic (B=0, C=1/2)", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_CUBIC2P_CATMULLROM }, 0, 0, FLAGS, "interp_algo" },
  512. { "cubic2p_b05c03", "2-parameter cubic (B=1/2, C=3/10)", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_CUBIC2P_B05C03 }, 0, 0, FLAGS, "interp_algo" },
  513. { "super", "supersampling", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_SUPER }, 0, 0, FLAGS, "interp_algo" },
  514. { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_LANCZOS }, 0, 0, FLAGS, "interp_algo" },
  515. { NULL },
  516. };
  517. static const AVClass nppscale_class = {
  518. .class_name = "nppscale",
  519. .item_name = av_default_item_name,
  520. .option = options,
  521. .version = LIBAVUTIL_VERSION_INT,
  522. };
  523. static const AVFilterPad nppscale_inputs[] = {
  524. {
  525. .name = "default",
  526. .type = AVMEDIA_TYPE_VIDEO,
  527. .filter_frame = nppscale_filter_frame,
  528. },
  529. { NULL }
  530. };
  531. static const AVFilterPad nppscale_outputs[] = {
  532. {
  533. .name = "default",
  534. .type = AVMEDIA_TYPE_VIDEO,
  535. .config_props = nppscale_config_props,
  536. },
  537. { NULL }
  538. };
  539. AVFilter ff_vf_scale_npp = {
  540. .name = "scale_npp",
  541. .description = NULL_IF_CONFIG_SMALL("NVIDIA Performance Primitives video "
  542. "scaling and format conversion"),
  543. .init = nppscale_init,
  544. .uninit = nppscale_uninit,
  545. .query_formats = nppscale_query_formats,
  546. .priv_size = sizeof(NPPScaleContext),
  547. .priv_class = &nppscale_class,
  548. .inputs = nppscale_inputs,
  549. .outputs = nppscale_outputs,
  550. };