History

lavfi/vf_scale: allow passing options to swscale directly

Avoid using the dictionary mechanism, which is non-introspectable. As this is the only user of AVFilter.init_dict(), this callback can now be removed.

Anton Khirnov committed 3 years ago

Commit 018a8b91 parent 260f3911 file · +66 −29Browse files

Showing the changes to libavfilter (1 of 1 file). Show all

Unified · Split

libavfilter/vf_scale.c+66−29
@@ -23,6 +23,7 @@ · 22 unmodified lines
23 * scale video filter23 * scale video filter
24 */24 */
25 25
26#include <float.h>
26#include <stdio.h>27#include <stdio.h>
27#include <string.h>28#include <string.h>
28 29
@@ -107,7 +108,8 @@ typedef struct ScaleContext { · 78 unmodified lines
107 const AVClass *class;108 const AVClass *class;
108 struct SwsContext *sws; ///< software scaler context109 struct SwsContext *sws; ///< software scaler context
109 struct SwsContext *isws[2]; ///< software scaler context for interlaced material110 struct SwsContext *isws[2]; ///< software scaler context for interlaced material
110 AVDictionary *opts;111 // context used for forwarding options to sws
112 struct SwsContext *sws_opts;
111 113
112 /**114 /**
113 * New dimensions. Special values are:115 * New dimensions. Special values are:
@@ -117,7 +119,6 @@ typedef struct ScaleContext { · 3 unmodified lines
117 */119 */
118 int w, h;120 int w, h;
119 char *size_str;121 char *size_str;
120 unsigned int flags; ///sws flags
121 double param[2]; // sws params122 double param[2]; // sws params
122 123
123 int hsub, vsub; ///< chroma subsampling124 int hsub, vsub; ///< chroma subsampling
@@ -268,11 +269,29 @@ revert: · 144 unmodified lines
268 return ret;269 return ret;
269}270}
270 271
271static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts)272static av_cold int preinit(AVFilterContext *ctx)
272{273{
273 ScaleContext *scale = ctx->priv;274 ScaleContext *scale = ctx->priv;
274 int ret;275 int ret;
275 276
277 scale->sws_opts = sws_alloc_context();
278 if (!scale->sws_opts)
279 return AVERROR(ENOMEM);
280
281 // set threads=0, so we can later check whether the user modified it
282 ret = av_opt_set_int(scale->sws_opts, "threads", 0, 0);
283 if (ret < 0)
284 return ret;
285
286 return 0;
287}
288
289static av_cold int init(AVFilterContext *ctx)
290{
291 ScaleContext *scale = ctx->priv;
292 int64_t threads;
293 int ret;
294
276 if (scale->size_str && (scale->w_expr || scale->h_expr)) {295 if (scale->size_str && (scale->w_expr || scale->h_expr)) {
277 av_log(ctx, AV_LOG_ERROR,296 av_log(ctx, AV_LOG_ERROR,
278 "Size and width/height expressions cannot be set at the same time.\n");297 "Size and width/height expressions cannot be set at the same time.\n");
@@ -310,18 +329,26 @@ static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts) · 31 unmodified lines
310 av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n",329 av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n",
311 scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced);330 scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced);
312 331
313 scale->flags = 0;
314
315 if (scale->flags_str && *scale->flags_str) {332 if (scale->flags_str && *scale->flags_str) {
316 const AVClass *class = sws_get_class();333 ret = av_opt_set(scale->sws_opts, "sws_flags", scale->flags_str, 0);
317 const AVOption *o = av_opt_find(&class, "sws_flags", NULL, 0,
318 AV_OPT_SEARCH_FAKE_OBJ);
319 int ret = av_opt_eval_flags(&class, o, scale->flags_str, &scale->flags);
320 if (ret < 0)334 if (ret < 0)
321 return ret;335 return ret;
322 }336 }
323 scale->opts = *opts;337
324 *opts = NULL;338 for (int i = 0; i < FF_ARRAY_ELEMS(scale->param); i++)
339 if (scale->param[i] != DBL_MAX) {
340 ret = av_opt_set_double(scale->sws_opts, i ? "param1" : "param0",
341 scale->param[i], 0);
342 if (ret < 0)
343 return ret;
344 }
345
346 // use generic thread-count if the user did not set it explicitly
347 ret = av_opt_get_int(scale->sws_opts, "threads", 0, &threads);
348 if (ret < 0)
349 return ret;
350 if (!threads)
351 av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0);
325 352
326 scale->in_frame_range = AVCOL_RANGE_UNSPECIFIED;353 scale->in_frame_range = AVCOL_RANGE_UNSPECIFIED;
327 354
@@ -334,11 +361,11 @@ static av_cold void uninit(AVFilterContext *ctx) · 6 unmodified lines
334 av_expr_free(scale->w_pexpr);361 av_expr_free(scale->w_pexpr);
335 av_expr_free(scale->h_pexpr);362 av_expr_free(scale->h_pexpr);
336 scale->w_pexpr = scale->h_pexpr = NULL;363 scale->w_pexpr = scale->h_pexpr = NULL;
364 sws_freeContext(scale->sws_opts);
337 sws_freeContext(scale->sws);365 sws_freeContext(scale->sws);
338 sws_freeContext(scale->isws[0]);366 sws_freeContext(scale->isws[0]);
339 sws_freeContext(scale->isws[1]);367 sws_freeContext(scale->isws[1]);
340 scale->sws = NULL;368 scale->sws = NULL;
341 av_dict_free(&scale->opts);
342}369}
343 370
344static int query_formats(AVFilterContext *ctx)371static int query_formats(AVFilterContext *ctx)
@@ -486,6 +513,7 @@ static int config_props(AVFilterLink *outlink) · 141 unmodified lines
486 enum AVPixelFormat outfmt = outlink->format;513 enum AVPixelFormat outfmt = outlink->format;
487 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);514 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
488 ScaleContext *scale = ctx->priv;515 ScaleContext *scale = ctx->priv;
516 uint8_t *flags_val = NULL;
489 int ret;517 int ret;
490 518
491 if ((ret = scale_eval_dimensions(ctx)) < 0)519 if ((ret = scale_eval_dimensions(ctx)) < 0)
@@ -534,16 +562,16 @@ static int config_props(AVFilterLink *outlink) · 42 unmodified lines
534 return AVERROR(ENOMEM);562 return AVERROR(ENOMEM);
535 *swscs[i] = s;563 *swscs[i] = s;
536 564
565 ret = av_opt_copy(s, scale->sws_opts);
566 if (ret < 0)
567 return ret;
568
537 av_opt_set_int(s, "srcw", inlink0 ->w, 0);569 av_opt_set_int(s, "srcw", inlink0 ->w, 0);
538 av_opt_set_int(s, "srch", inlink0 ->h >> !!i, 0);570 av_opt_set_int(s, "srch", inlink0 ->h >> !!i, 0);
539 av_opt_set_int(s, "src_format", inlink0->format, 0);571 av_opt_set_int(s, "src_format", inlink0->format, 0);
540 av_opt_set_int(s, "dstw", outlink->w, 0);572 av_opt_set_int(s, "dstw", outlink->w, 0);
541 av_opt_set_int(s, "dsth", outlink->h >> !!i, 0);573 av_opt_set_int(s, "dsth", outlink->h >> !!i, 0);
542 av_opt_set_int(s, "dst_format", outfmt, 0);574 av_opt_set_int(s, "dst_format", outfmt, 0);
543 av_opt_set_int(s, "sws_flags", scale->flags, 0);
544 av_opt_set_int(s, "param0", scale->param[0], 0);
545 av_opt_set_int(s, "param1", scale->param[1], 0);
546 av_opt_set_int(s, "threads", ff_filter_get_nb_threads(ctx), 0);
547 if (scale->in_range != AVCOL_RANGE_UNSPECIFIED)575 if (scale->in_range != AVCOL_RANGE_UNSPECIFIED)
548 av_opt_set_int(s, "src_range",576 av_opt_set_int(s, "src_range",
549 scale->in_range == AVCOL_RANGE_JPEG, 0);577 scale->in_range == AVCOL_RANGE_JPEG, 0);
@@ -554,13 +582,6 @@ static int config_props(AVFilterLink *outlink) · 4 unmodified lines
554 av_opt_set_int(s, "dst_range",582 av_opt_set_int(s, "dst_range",
555 scale->out_range == AVCOL_RANGE_JPEG, 0);583 scale->out_range == AVCOL_RANGE_JPEG, 0);
556 584
557 if (scale->opts) {
558 const AVDictionaryEntry *e = NULL;
559 while ((e = av_dict_iterate(scale->opts, e))) {
560 if ((ret = av_opt_set(s, e->key, e->value, 0)) < 0)
561 return ret;
562 }
563 }
564 /* Override YUV420P default settings to have the correct (MPEG-2) chroma positions585 /* Override YUV420P default settings to have the correct (MPEG-2) chroma positions
565 * MPEG-2 chroma positions are used by convention586 * MPEG-2 chroma positions are used by convention
566 * XXX: support other 4:2:0 pixel formats */587 * XXX: support other 4:2:0 pixel formats */
@@ -589,12 +610,17 @@ static int config_props(AVFilterLink *outlink) · 22 unmodified lines
589 } else610 } else
590 outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;611 outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
591 612
592 av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n",613 if (scale->sws)
614 av_opt_get(scale->sws, "sws_flags", 0, &flags_val);
615
616 av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:%s\n",
593 inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),617 inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
594 inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,618 inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
595 outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),619 outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
596 outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,620 outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
597 scale->flags);621 flags_val);
622 av_freep(&flags_val);
623
598 return 0;624 return 0;
599 625
600fail:626fail:
@@ -927,6 +953,14 @@ static const AVClass *child_class_iterate(void **iter) · 326 unmodified lines
927 return c;953 return c;
928}954}
929 955
956static void *child_next(void *obj, void *prev)
957{
958 ScaleContext *s = obj;
959 if (!prev)
960 return s->sws_opts;
961 return NULL;
962}
963
930#define OFFSET(x) offsetof(ScaleContext, x)964#define OFFSET(x) offsetof(ScaleContext, x)
931#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM965#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
932#define TFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM966#define TFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
@@ -969,8 +1003,8 @@ static const AVOption scale_options[] = { · 36 unmodified lines
969 { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" },1003 { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" },
970 { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" },1004 { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" },
971 { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },1005 { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
972 { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, FLAGS },1006 { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
973 { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, FLAGS },1007 { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
974 { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" },1008 { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" },
975 { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },1009 { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
976 { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },1010 { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
@@ -984,6 +1018,7 @@ static const AVClass scale_class = { · 7 unmodified lines
984 .version = LIBAVUTIL_VERSION_INT,1018 .version = LIBAVUTIL_VERSION_INT,
985 .category = AV_CLASS_CATEGORY_FILTER,1019 .category = AV_CLASS_CATEGORY_FILTER,
986 .child_class_iterate = child_class_iterate,1020 .child_class_iterate = child_class_iterate,
1021 .child_next = child_next,
987};1022};
988 1023
989static const AVFilterPad avfilter_vf_scale_inputs[] = {1024static const AVFilterPad avfilter_vf_scale_inputs[] = {
@@ -1005,7 +1040,8 @@ static const AVFilterPad avfilter_vf_scale_outputs[] = { · 15 unmodified lines
1005const AVFilter ff_vf_scale = {1040const AVFilter ff_vf_scale = {
1006 .name = "scale",1041 .name = "scale",
1007 .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."),1042 .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."),
1008 .init_dict = init_dict,1043 .preinit = preinit,
1044 .init = init,
1009 .uninit = uninit,1045 .uninit = uninit,
1010 .priv_size = sizeof(ScaleContext),1046 .priv_size = sizeof(ScaleContext),
1011 .priv_class = &scale_class,1047 .priv_class = &scale_class,
@@ -1046,7 +1082,8 @@ static const AVFilterPad avfilter_vf_scale2ref_outputs[] = { · 34 unmodified lines
1046const AVFilter ff_vf_scale2ref = {1082const AVFilter ff_vf_scale2ref = {
1047 .name = "scale2ref",1083 .name = "scale2ref",
1048 .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format to the given reference."),1084 .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format to the given reference."),
1049 .init_dict = init_dict,1085 .preinit = preinit,
1086 .init = init,
1050 .uninit = uninit,1087 .uninit = uninit,
1051 .priv_size = sizeof(ScaleContext),1088 .priv_size = sizeof(ScaleContext),
1052 .priv_class = &scale_class,1089 .priv_class = &scale_class,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t