vf_scale_vaapi.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. #include <string.h>
  19. #include "libavutil/avassert.h"
  20. #include "libavutil/mem.h"
  21. #include "libavutil/opt.h"
  22. #include "libavutil/pixdesc.h"
  23. #include "avfilter.h"
  24. #include "formats.h"
  25. #include "internal.h"
  26. #include "scale.h"
  27. #include "video.h"
  28. #include "vaapi_vpp.h"
  29. typedef struct ScaleVAAPIContext {
  30. VAAPIVPPContext vpp_ctx; // must be the first field
  31. char *output_format_string;
  32. int mode;
  33. char *w_expr; // width expression string
  34. char *h_expr; // height expression string
  35. char *colour_primaries_string;
  36. char *colour_transfer_string;
  37. char *colour_matrix_string;
  38. int colour_range;
  39. char *chroma_location_string;
  40. enum AVColorPrimaries colour_primaries;
  41. enum AVColorTransferCharacteristic colour_transfer;
  42. enum AVColorSpace colour_matrix;
  43. enum AVChromaLocation chroma_location;
  44. } ScaleVAAPIContext;
  45. static const char *scale_vaapi_mode_name(int mode)
  46. {
  47. switch (mode) {
  48. #define D(name) case VA_FILTER_SCALING_ ## name: return #name
  49. D(DEFAULT);
  50. D(FAST);
  51. D(HQ);
  52. D(NL_ANAMORPHIC);
  53. #undef D
  54. default:
  55. return "Invalid";
  56. }
  57. }
  58. static int scale_vaapi_config_output(AVFilterLink *outlink)
  59. {
  60. AVFilterLink *inlink = outlink->src->inputs[0];
  61. AVFilterContext *avctx = outlink->src;
  62. VAAPIVPPContext *vpp_ctx = avctx->priv;
  63. ScaleVAAPIContext *ctx = avctx->priv;
  64. int err;
  65. if ((err = ff_scale_eval_dimensions(ctx,
  66. ctx->w_expr, ctx->h_expr,
  67. inlink, outlink,
  68. &vpp_ctx->output_width, &vpp_ctx->output_height)) < 0)
  69. return err;
  70. err = ff_vaapi_vpp_config_output(outlink);
  71. if (err < 0)
  72. return err;
  73. if (inlink->sample_aspect_ratio.num)
  74. outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio);
  75. else
  76. outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
  77. return 0;
  78. }
  79. static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
  80. {
  81. AVFilterContext *avctx = inlink->dst;
  82. AVFilterLink *outlink = avctx->outputs[0];
  83. VAAPIVPPContext *vpp_ctx = avctx->priv;
  84. ScaleVAAPIContext *ctx = avctx->priv;
  85. AVFrame *output_frame = NULL;
  86. VAProcPipelineParameterBuffer params;
  87. int err;
  88. av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
  89. av_get_pix_fmt_name(input_frame->format),
  90. input_frame->width, input_frame->height, input_frame->pts);
  91. if (vpp_ctx->va_context == VA_INVALID_ID)
  92. return AVERROR(EINVAL);
  93. output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width,
  94. vpp_ctx->output_height);
  95. if (!output_frame) {
  96. err = AVERROR(ENOMEM);
  97. goto fail;
  98. }
  99. err = av_frame_copy_props(output_frame, input_frame);
  100. if (err < 0)
  101. return err;
  102. if (ctx->colour_primaries != AVCOL_PRI_UNSPECIFIED)
  103. output_frame->color_primaries = ctx->colour_primaries;
  104. if (ctx->colour_transfer != AVCOL_TRC_UNSPECIFIED)
  105. output_frame->color_trc = ctx->colour_transfer;
  106. if (ctx->colour_matrix != AVCOL_SPC_UNSPECIFIED)
  107. output_frame->colorspace = ctx->colour_matrix;
  108. if (ctx->colour_range != AVCOL_RANGE_UNSPECIFIED)
  109. output_frame->color_range = ctx->colour_range;
  110. if (ctx->chroma_location != AVCHROMA_LOC_UNSPECIFIED)
  111. output_frame->chroma_location = ctx->chroma_location;
  112. err = ff_vaapi_vpp_init_params(avctx, &params,
  113. input_frame, output_frame);
  114. if (err < 0)
  115. goto fail;
  116. params.filter_flags |= ctx->mode;
  117. err = ff_vaapi_vpp_render_picture(avctx, &params, output_frame);
  118. if (err < 0)
  119. goto fail;
  120. av_frame_free(&input_frame);
  121. av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64"), mode: %s.\n",
  122. av_get_pix_fmt_name(output_frame->format),
  123. output_frame->width, output_frame->height, output_frame->pts,
  124. scale_vaapi_mode_name(ctx->mode));
  125. return ff_filter_frame(outlink, output_frame);
  126. fail:
  127. av_frame_free(&input_frame);
  128. av_frame_free(&output_frame);
  129. return err;
  130. }
  131. static av_cold int scale_vaapi_init(AVFilterContext *avctx)
  132. {
  133. VAAPIVPPContext *vpp_ctx = avctx->priv;
  134. ScaleVAAPIContext *ctx = avctx->priv;
  135. ff_vaapi_vpp_ctx_init(avctx);
  136. vpp_ctx->pipeline_uninit = ff_vaapi_vpp_pipeline_uninit;
  137. if (ctx->output_format_string) {
  138. vpp_ctx->output_format = av_get_pix_fmt(ctx->output_format_string);
  139. if (vpp_ctx->output_format == AV_PIX_FMT_NONE) {
  140. av_log(avctx, AV_LOG_ERROR, "Invalid output format.\n");
  141. return AVERROR(EINVAL);
  142. }
  143. } else {
  144. // Use the input format once that is configured.
  145. vpp_ctx->output_format = AV_PIX_FMT_NONE;
  146. }
  147. #define STRING_OPTION(var_name, func_name, default_value) do { \
  148. if (ctx->var_name ## _string) { \
  149. int var = av_ ## func_name ## _from_name(ctx->var_name ## _string); \
  150. if (var < 0) { \
  151. av_log(avctx, AV_LOG_ERROR, "Invalid %s.\n", #var_name); \
  152. return AVERROR(EINVAL); \
  153. } \
  154. ctx->var_name = var; \
  155. } else { \
  156. ctx->var_name = default_value; \
  157. } \
  158. } while (0)
  159. STRING_OPTION(colour_primaries, color_primaries, AVCOL_PRI_UNSPECIFIED);
  160. STRING_OPTION(colour_transfer, color_transfer, AVCOL_TRC_UNSPECIFIED);
  161. STRING_OPTION(colour_matrix, color_space, AVCOL_SPC_UNSPECIFIED);
  162. STRING_OPTION(chroma_location, chroma_location, AVCHROMA_LOC_UNSPECIFIED);
  163. return 0;
  164. }
  165. #define OFFSET(x) offsetof(ScaleVAAPIContext, x)
  166. #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
  167. static const AVOption scale_vaapi_options[] = {
  168. { "w", "Output video width",
  169. OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = FLAGS },
  170. { "h", "Output video height",
  171. OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = FLAGS },
  172. { "format", "Output video format (software format of hardware frames)",
  173. OFFSET(output_format_string), AV_OPT_TYPE_STRING, .flags = FLAGS },
  174. { "mode", "Scaling mode",
  175. OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = VA_FILTER_SCALING_HQ },
  176. 0, VA_FILTER_SCALING_NL_ANAMORPHIC, FLAGS, "mode" },
  177. { "default", "Use the default (depend on the driver) scaling algorithm",
  178. 0, AV_OPT_TYPE_CONST, { .i64 = VA_FILTER_SCALING_DEFAULT }, 0, 0, FLAGS, "mode" },
  179. { "fast", "Use fast scaling algorithm",
  180. 0, AV_OPT_TYPE_CONST, { .i64 = VA_FILTER_SCALING_FAST }, 0, 0, FLAGS, "mode" },
  181. { "hq", "Use high quality scaling algorithm",
  182. 0, AV_OPT_TYPE_CONST, { .i64 = VA_FILTER_SCALING_HQ }, 0, 0, FLAGS, "mode" },
  183. { "nl_anamorphic", "Use nolinear anamorphic scaling algorithm",
  184. 0, AV_OPT_TYPE_CONST, { .i64 = VA_FILTER_SCALING_NL_ANAMORPHIC }, 0, 0, FLAGS, "mode" },
  185. // These colour properties match the ones of the same name in vf_scale.
  186. { "out_color_matrix", "Output colour matrix coefficient set",
  187. OFFSET(colour_matrix_string), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
  188. { "out_range", "Output colour range",
  189. OFFSET(colour_range), AV_OPT_TYPE_INT, { .i64 = AVCOL_RANGE_UNSPECIFIED },
  190. AVCOL_RANGE_UNSPECIFIED, AVCOL_RANGE_JPEG, FLAGS, "range" },
  191. { "full", "Full range",
  192. 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
  193. { "limited", "Limited range",
  194. 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
  195. { "jpeg", "Full range",
  196. 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
  197. { "mpeg", "Limited range",
  198. 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
  199. { "tv", "Limited range",
  200. 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" },
  201. { "pc", "Full range",
  202. 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" },
  203. // These colour properties are new here.
  204. { "out_color_primaries", "Output colour primaries",
  205. OFFSET(colour_primaries_string), AV_OPT_TYPE_STRING,
  206. { .str = NULL }, .flags = FLAGS },
  207. { "out_color_transfer", "Output colour transfer characteristics",
  208. OFFSET(colour_transfer_string), AV_OPT_TYPE_STRING,
  209. { .str = NULL }, .flags = FLAGS },
  210. { "out_chroma_location", "Output chroma sample location",
  211. OFFSET(chroma_location_string), AV_OPT_TYPE_STRING,
  212. { .str = NULL }, .flags = FLAGS },
  213. { NULL },
  214. };
  215. AVFILTER_DEFINE_CLASS(scale_vaapi);
  216. static const AVFilterPad scale_vaapi_inputs[] = {
  217. {
  218. .name = "default",
  219. .type = AVMEDIA_TYPE_VIDEO,
  220. .filter_frame = &scale_vaapi_filter_frame,
  221. .config_props = &ff_vaapi_vpp_config_input,
  222. },
  223. { NULL }
  224. };
  225. static const AVFilterPad scale_vaapi_outputs[] = {
  226. {
  227. .name = "default",
  228. .type = AVMEDIA_TYPE_VIDEO,
  229. .config_props = &scale_vaapi_config_output,
  230. },
  231. { NULL }
  232. };
  233. AVFilter ff_vf_scale_vaapi = {
  234. .name = "scale_vaapi",
  235. .description = NULL_IF_CONFIG_SMALL("Scale to/from VAAPI surfaces."),
  236. .priv_size = sizeof(ScaleVAAPIContext),
  237. .init = &scale_vaapi_init,
  238. .uninit = &ff_vaapi_vpp_ctx_uninit,
  239. .query_formats = &ff_vaapi_vpp_query_formats,
  240. .inputs = scale_vaapi_inputs,
  241. .outputs = scale_vaapi_outputs,
  242. .priv_class = &scale_vaapi_class,
  243. .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
  244. };