vf_vpp_qsv.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. ** Hardware accelerated common filters based on Intel Quick Sync Video VPP
  21. **/
  22. #include <float.h>
  23. #include "libavutil/opt.h"
  24. #include "libavutil/eval.h"
  25. #include "libavutil/avassert.h"
  26. #include "libavutil/pixdesc.h"
  27. #include "libavutil/mathematics.h"
  28. #include "formats.h"
  29. #include "internal.h"
  30. #include "avfilter.h"
  31. #include "libavcodec/avcodec.h"
  32. #include "libavformat/avformat.h"
  33. #include "qsvvpp.h"
  34. #define OFFSET(x) offsetof(VPPContext, x)
  35. #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM)
  36. /* number of video enhancement filters */
  37. #define ENH_FILTERS_COUNT (5)
  38. typedef struct VPPContext{
  39. const AVClass *class;
  40. QSVVPPContext *qsv;
  41. /* Video Enhancement Algorithms */
  42. mfxExtVPPDeinterlacing deinterlace_conf;
  43. mfxExtVPPFrameRateConversion frc_conf;
  44. mfxExtVPPDenoise denoise_conf;
  45. mfxExtVPPDetail detail_conf;
  46. mfxExtVPPProcAmp procamp_conf;
  47. int out_width;
  48. int out_height;
  49. /**
  50. * Output sw format. AV_PIX_FMT_NONE for no conversion.
  51. */
  52. enum AVPixelFormat out_format;
  53. AVRational framerate; /* target framerate */
  54. int use_frc; /* use framerate conversion */
  55. int deinterlace; /* deinterlace mode : 0=off, 1=bob, 2=advanced */
  56. int denoise; /* Enable Denoise algorithm. Value [0, 100] */
  57. int detail; /* Enable Detail Enhancement algorithm. */
  58. /* Level is the optional, value [0, 100] */
  59. int use_crop; /* 1 = use crop; 0=none */
  60. int crop_w;
  61. int crop_h;
  62. int crop_x;
  63. int crop_y;
  64. /* param for the procamp */
  65. int procamp; /* enable procamp */
  66. float hue;
  67. float saturation;
  68. float contrast;
  69. float brightness;
  70. char *cx, *cy, *cw, *ch;
  71. char *ow, *oh;
  72. char *output_format_str;
  73. } VPPContext;
  74. static const AVOption options[] = {
  75. { "deinterlace", "deinterlace mode: 0=off, 1=bob, 2=advanced", OFFSET(deinterlace), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MFX_DEINTERLACING_ADVANCED, .flags = FLAGS, "deinterlace" },
  76. { "bob", "Bob deinterlace mode.", 0, AV_OPT_TYPE_CONST, { .i64 = MFX_DEINTERLACING_BOB }, .flags = FLAGS, "deinterlace" },
  77. { "advanced", "Advanced deinterlace mode. ", 0, AV_OPT_TYPE_CONST, { .i64 = MFX_DEINTERLACING_ADVANCED }, .flags = FLAGS, "deinterlace" },
  78. { "denoise", "denoise level [0, 100]", OFFSET(denoise), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, .flags = FLAGS },
  79. { "detail", "enhancement level [0, 100]", OFFSET(detail), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, .flags = FLAGS },
  80. { "framerate", "output framerate", OFFSET(framerate), AV_OPT_TYPE_RATIONAL, { .dbl = 0.0 },0, DBL_MAX, .flags = FLAGS },
  81. { "procamp", "Enable ProcAmp", OFFSET(procamp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = FLAGS},
  82. { "hue", "ProcAmp hue", OFFSET(hue), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, -180.0, 180.0, .flags = FLAGS},
  83. { "saturation", "ProcAmp saturation", OFFSET(saturation), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.0, 10.0, .flags = FLAGS},
  84. { "contrast", "ProcAmp contrast", OFFSET(contrast), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.0, 10.0, .flags = FLAGS},
  85. { "brightness", "ProcAmp brightness", OFFSET(brightness), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, -100.0, 100.0, .flags = FLAGS},
  86. { "cw", "set the width crop area expression", OFFSET(cw), AV_OPT_TYPE_STRING, { .str = "iw" }, CHAR_MIN, CHAR_MAX, FLAGS },
  87. { "ch", "set the height crop area expression", OFFSET(ch), AV_OPT_TYPE_STRING, { .str = "ih" }, CHAR_MIN, CHAR_MAX, FLAGS },
  88. { "cx", "set the x crop area expression", OFFSET(cx), AV_OPT_TYPE_STRING, { .str = "(in_w-out_w)/2" }, CHAR_MIN, CHAR_MAX, FLAGS },
  89. { "cy", "set the y crop area expression", OFFSET(cy), AV_OPT_TYPE_STRING, { .str = "(in_h-out_h)/2" }, CHAR_MIN, CHAR_MAX, FLAGS },
  90. { "w", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str="cw" }, 0, 255, .flags = FLAGS },
  91. { "width", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str="cw" }, 0, 255, .flags = FLAGS },
  92. { "h", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str="w*ch/cw" }, 0, 255, .flags = FLAGS },
  93. { "height", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str="w*ch/cw" }, 0, 255, .flags = FLAGS },
  94. { "format", "Output pixel format", OFFSET(output_format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS },
  95. { NULL }
  96. };
  97. static const char *const var_names[] = {
  98. "iw", "in_w",
  99. "ih", "in_h",
  100. "ow", "out_w", "w",
  101. "oh", "out_h", "h",
  102. "cw",
  103. "ch",
  104. "cx",
  105. "cy",
  106. NULL
  107. };
  108. enum var_name {
  109. VAR_iW, VAR_IN_W,
  110. VAR_iH, VAR_IN_H,
  111. VAR_oW, VAR_OUT_W, VAR_W,
  112. VAR_oH, VAR_OUT_H, VAR_H,
  113. CW,
  114. CH,
  115. CX,
  116. CY,
  117. VAR_VARS_NB
  118. };
  119. static int eval_expr(AVFilterContext *ctx)
  120. {
  121. #define PASS_EXPR(e, s) {\
  122. ret = av_expr_parse(&e, s, var_names, NULL, NULL, NULL, NULL, 0, ctx); \
  123. if (ret < 0) {\
  124. av_log(ctx, AV_LOG_ERROR, "Error when passing '%s'.\n", s);\
  125. goto release;\
  126. }\
  127. }
  128. #define CALC_EXPR(e, v, i) {\
  129. i = v = av_expr_eval(e, var_values, NULL); \
  130. }
  131. VPPContext *vpp = ctx->priv;
  132. double var_values[VAR_VARS_NB] = { NAN };
  133. AVExpr *w_expr = NULL, *h_expr = NULL;
  134. AVExpr *cw_expr = NULL, *ch_expr = NULL;
  135. AVExpr *cx_expr = NULL, *cy_expr = NULL;
  136. int ret = 0;
  137. PASS_EXPR(cw_expr, vpp->cw);
  138. PASS_EXPR(ch_expr, vpp->ch);
  139. PASS_EXPR(w_expr, vpp->ow);
  140. PASS_EXPR(h_expr, vpp->oh);
  141. PASS_EXPR(cx_expr, vpp->cx);
  142. PASS_EXPR(cy_expr, vpp->cy);
  143. var_values[VAR_iW] =
  144. var_values[VAR_IN_W] = ctx->inputs[0]->w;
  145. var_values[VAR_iH] =
  146. var_values[VAR_IN_H] = ctx->inputs[0]->h;
  147. /* crop params */
  148. CALC_EXPR(cw_expr, var_values[CW], vpp->crop_w);
  149. CALC_EXPR(ch_expr, var_values[CH], vpp->crop_h);
  150. /* calc again in case cw is relative to ch */
  151. CALC_EXPR(cw_expr, var_values[CW], vpp->crop_w);
  152. CALC_EXPR(w_expr,
  153. var_values[VAR_OUT_W] = var_values[VAR_oW] = var_values[VAR_W],
  154. vpp->out_width);
  155. CALC_EXPR(h_expr,
  156. var_values[VAR_OUT_H] = var_values[VAR_oH] = var_values[VAR_H],
  157. vpp->out_height);
  158. /* calc again in case ow is relative to oh */
  159. CALC_EXPR(w_expr,
  160. var_values[VAR_OUT_W] = var_values[VAR_oW] = var_values[VAR_W],
  161. vpp->out_width);
  162. CALC_EXPR(cx_expr, var_values[CX], vpp->crop_x);
  163. CALC_EXPR(cy_expr, var_values[CY], vpp->crop_y);
  164. /* calc again in case cx is relative to cy */
  165. CALC_EXPR(cx_expr, var_values[CX], vpp->crop_x);
  166. if ((vpp->crop_w != var_values[VAR_iW]) || (vpp->crop_h != var_values[VAR_iH]))
  167. vpp->use_crop = 1;
  168. release:
  169. av_expr_free(w_expr);
  170. av_expr_free(h_expr);
  171. av_expr_free(cw_expr);
  172. av_expr_free(ch_expr);
  173. av_expr_free(cx_expr);
  174. av_expr_free(cy_expr);
  175. #undef PASS_EXPR
  176. #undef CALC_EXPR
  177. return ret;
  178. }
  179. static av_cold int vpp_init(AVFilterContext *ctx)
  180. {
  181. VPPContext *vpp = ctx->priv;
  182. if (!strcmp(vpp->output_format_str, "same")) {
  183. vpp->out_format = AV_PIX_FMT_NONE;
  184. } else {
  185. vpp->out_format = av_get_pix_fmt(vpp->output_format_str);
  186. if (vpp->out_format == AV_PIX_FMT_NONE) {
  187. av_log(ctx, AV_LOG_ERROR, "Unrecognized output pixel format: %s\n", vpp->output_format_str);
  188. return AVERROR(EINVAL);
  189. }
  190. }
  191. return 0;
  192. }
  193. static int config_input(AVFilterLink *inlink)
  194. {
  195. AVFilterContext *ctx = inlink->dst;
  196. VPPContext *vpp = ctx->priv;
  197. int ret;
  198. if (vpp->framerate.den == 0 || vpp->framerate.num == 0)
  199. vpp->framerate = inlink->frame_rate;
  200. if (av_cmp_q(vpp->framerate, inlink->frame_rate))
  201. vpp->use_frc = 1;
  202. ret = eval_expr(ctx);
  203. if (ret != 0) {
  204. av_log(ctx, AV_LOG_ERROR, "Fail to eval expr.\n");
  205. return ret;
  206. }
  207. if (vpp->out_height == 0 || vpp->out_width == 0) {
  208. vpp->out_width = inlink->w;
  209. vpp->out_height = inlink->h;
  210. }
  211. if (vpp->use_crop) {
  212. vpp->crop_x = FFMAX(vpp->crop_x, 0);
  213. vpp->crop_y = FFMAX(vpp->crop_y, 0);
  214. if(vpp->crop_w + vpp->crop_x > inlink->w)
  215. vpp->crop_x = inlink->w - vpp->crop_w;
  216. if(vpp->crop_h + vpp->crop_y > inlink->h)
  217. vpp->crop_y = inlink->h - vpp->crop_h;
  218. }
  219. return 0;
  220. }
  221. static int config_output(AVFilterLink *outlink)
  222. {
  223. AVFilterContext *ctx = outlink->src;
  224. VPPContext *vpp = ctx->priv;
  225. QSVVPPParam param = { NULL };
  226. QSVVPPCrop crop = { 0 };
  227. mfxExtBuffer *ext_buf[ENH_FILTERS_COUNT];
  228. AVFilterLink *inlink = ctx->inputs[0];
  229. enum AVPixelFormat in_format;
  230. outlink->w = vpp->out_width;
  231. outlink->h = vpp->out_height;
  232. outlink->frame_rate = vpp->framerate;
  233. outlink->time_base = av_inv_q(vpp->framerate);
  234. param.filter_frame = NULL;
  235. param.num_ext_buf = 0;
  236. param.ext_buf = ext_buf;
  237. if (inlink->format == AV_PIX_FMT_QSV) {
  238. if (!inlink->hw_frames_ctx || !inlink->hw_frames_ctx->data)
  239. return AVERROR(EINVAL);
  240. else
  241. in_format = ((AVHWFramesContext*)inlink->hw_frames_ctx->data)->sw_format;
  242. } else
  243. in_format = inlink->format;
  244. param.out_sw_format = (vpp->out_format == AV_PIX_FMT_NONE) ? in_format : vpp->out_format;
  245. if (vpp->use_crop) {
  246. crop.in_idx = 0;
  247. crop.x = vpp->crop_x;
  248. crop.y = vpp->crop_y;
  249. crop.w = vpp->crop_w;
  250. crop.h = vpp->crop_h;
  251. param.num_crop = 1;
  252. param.crop = &crop;
  253. }
  254. if (vpp->deinterlace) {
  255. memset(&vpp->deinterlace_conf, 0, sizeof(mfxExtVPPDeinterlacing));
  256. vpp->deinterlace_conf.Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING;
  257. vpp->deinterlace_conf.Header.BufferSz = sizeof(mfxExtVPPDeinterlacing);
  258. vpp->deinterlace_conf.Mode = vpp->deinterlace == 1 ?
  259. MFX_DEINTERLACING_BOB : MFX_DEINTERLACING_ADVANCED;
  260. param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->deinterlace_conf;
  261. }
  262. if (vpp->use_frc) {
  263. memset(&vpp->frc_conf, 0, sizeof(mfxExtVPPFrameRateConversion));
  264. vpp->frc_conf.Header.BufferId = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION;
  265. vpp->frc_conf.Header.BufferSz = sizeof(mfxExtVPPFrameRateConversion);
  266. vpp->frc_conf.Algorithm = MFX_FRCALGM_DISTRIBUTED_TIMESTAMP;
  267. param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->frc_conf;
  268. }
  269. if (vpp->denoise) {
  270. memset(&vpp->denoise_conf, 0, sizeof(mfxExtVPPDenoise));
  271. vpp->denoise_conf.Header.BufferId = MFX_EXTBUFF_VPP_DENOISE;
  272. vpp->denoise_conf.Header.BufferSz = sizeof(mfxExtVPPDenoise);
  273. vpp->denoise_conf.DenoiseFactor = vpp->denoise;
  274. param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->denoise_conf;
  275. }
  276. if (vpp->detail) {
  277. memset(&vpp->detail_conf, 0, sizeof(mfxExtVPPDetail));
  278. vpp->detail_conf.Header.BufferId = MFX_EXTBUFF_VPP_DETAIL;
  279. vpp->detail_conf.Header.BufferSz = sizeof(mfxExtVPPDetail);
  280. vpp->detail_conf.DetailFactor = vpp->detail;
  281. param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->detail_conf;
  282. }
  283. if (vpp->procamp) {
  284. memset(&vpp->procamp_conf, 0, sizeof(mfxExtVPPProcAmp));
  285. vpp->procamp_conf.Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP;
  286. vpp->procamp_conf.Header.BufferSz = sizeof(mfxExtVPPProcAmp);
  287. vpp->procamp_conf.Hue = vpp->hue;
  288. vpp->procamp_conf.Saturation = vpp->saturation;
  289. vpp->procamp_conf.Contrast = vpp->contrast;
  290. vpp->procamp_conf.Brightness = vpp->brightness;
  291. param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->procamp_conf;
  292. }
  293. if (vpp->use_frc || vpp->use_crop || vpp->deinterlace || vpp->denoise ||
  294. vpp->detail || vpp->procamp || inlink->w != outlink->w || inlink->h != outlink->h)
  295. return ff_qsvvpp_create(ctx, &vpp->qsv, &param);
  296. else {
  297. av_log(ctx, AV_LOG_VERBOSE, "qsv vpp pass through mode.\n");
  298. if (inlink->hw_frames_ctx)
  299. outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
  300. }
  301. return 0;
  302. }
  303. static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
  304. {
  305. int ret = 0;
  306. AVFilterContext *ctx = inlink->dst;
  307. VPPContext *vpp = inlink->dst->priv;
  308. AVFilterLink *outlink = ctx->outputs[0];
  309. if (vpp->qsv) {
  310. ret = ff_qsvvpp_filter_frame(vpp->qsv, inlink, picref);
  311. av_frame_free(&picref);
  312. } else {
  313. if (picref->pts != AV_NOPTS_VALUE)
  314. picref->pts = av_rescale_q(picref->pts, inlink->time_base, outlink->time_base);
  315. ret = ff_filter_frame(outlink, picref);
  316. }
  317. return ret;
  318. }
  319. static int query_formats(AVFilterContext *ctx)
  320. {
  321. int ret;
  322. AVFilterFormats *in_fmts, *out_fmts;
  323. static const enum AVPixelFormat in_pix_fmts[] = {
  324. AV_PIX_FMT_YUV420P,
  325. AV_PIX_FMT_NV12,
  326. AV_PIX_FMT_YUYV422,
  327. AV_PIX_FMT_RGB32,
  328. AV_PIX_FMT_QSV,
  329. AV_PIX_FMT_NONE
  330. };
  331. static const enum AVPixelFormat out_pix_fmts[] = {
  332. AV_PIX_FMT_NV12,
  333. AV_PIX_FMT_P010,
  334. AV_PIX_FMT_QSV,
  335. AV_PIX_FMT_NONE
  336. };
  337. in_fmts = ff_make_format_list(in_pix_fmts);
  338. out_fmts = ff_make_format_list(out_pix_fmts);
  339. ret = ff_formats_ref(in_fmts, &ctx->inputs[0]->out_formats);
  340. if (ret < 0)
  341. return ret;
  342. ret = ff_formats_ref(out_fmts, &ctx->outputs[0]->in_formats);
  343. if (ret < 0)
  344. return ret;
  345. return 0;
  346. }
  347. static av_cold void vpp_uninit(AVFilterContext *ctx)
  348. {
  349. VPPContext *vpp = ctx->priv;
  350. ff_qsvvpp_free(&vpp->qsv);
  351. }
  352. static const AVClass vpp_class = {
  353. .class_name = "vpp_qsv",
  354. .item_name = av_default_item_name,
  355. .option = options,
  356. .version = LIBAVUTIL_VERSION_INT,
  357. };
  358. static const AVFilterPad vpp_inputs[] = {
  359. {
  360. .name = "default",
  361. .type = AVMEDIA_TYPE_VIDEO,
  362. .config_props = config_input,
  363. .filter_frame = filter_frame,
  364. },
  365. { NULL }
  366. };
  367. static const AVFilterPad vpp_outputs[] = {
  368. {
  369. .name = "default",
  370. .type = AVMEDIA_TYPE_VIDEO,
  371. .config_props = config_output,
  372. },
  373. { NULL }
  374. };
  375. AVFilter ff_vf_vpp_qsv = {
  376. .name = "vpp_qsv",
  377. .description = NULL_IF_CONFIG_SMALL("Quick Sync Video VPP."),
  378. .priv_size = sizeof(VPPContext),
  379. .query_formats = query_formats,
  380. .init = vpp_init,
  381. .uninit = vpp_uninit,
  382. .inputs = vpp_inputs,
  383. .outputs = vpp_outputs,
  384. .priv_class = &vpp_class,
  385. .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
  386. };