History

avfilter/vf_scale: add optional "ref" input

This is automatically enabled if the width/height expressions reference any ref_* variable. This will ultimately serve as a more principled replacement for the fundamentally broken scale2ref.

Niklas Haas committed 2 years ago

Commit bb804451 parent e82a3993 files · +156 −3Browse files

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

Unified · Split

libavfilter/vf_scale.c+129−3
@@ -59,6 +59,17 @@ static const char *const var_names[] = { · 58 unmodified lines
59#if FF_API_FRAME_PKT59#if FF_API_FRAME_PKT
60 "pos",60 "pos",
61#endif61#endif
62 "ref_w", "rw",
63 "ref_h", "rh",
64 "ref_a",
65 "ref_sar",
66 "ref_dar", "rdar",
67 "ref_hsub",
68 "ref_vsub",
69 "ref_n",
70 "ref_t",
71 "ref_pos",
72 /* Legacy variables for scale2ref */
62 "main_w",73 "main_w",
63 "main_h",74 "main_h",
64 "main_a",75 "main_a",
@@ -89,6 +100,16 @@ enum var_name { · 24 unmodified lines
89#if FF_API_FRAME_PKT100#if FF_API_FRAME_PKT
90 VAR_POS,101 VAR_POS,
91#endif102#endif
103 VAR_REF_W, VAR_RW,
104 VAR_REF_H, VAR_RH,
105 VAR_REF_A,
106 VAR_REF_SAR,
107 VAR_REF_DAR, VAR_RDAR,
108 VAR_REF_HSUB,
109 VAR_REF_VSUB,
110 VAR_REF_N,
111 VAR_REF_T,
112 VAR_REF_POS,
92 VAR_S2R_MAIN_W,113 VAR_S2R_MAIN_W,
93 VAR_S2R_MAIN_H,114 VAR_S2R_MAIN_H,
94 VAR_S2R_MAIN_A,115 VAR_S2R_MAIN_A,
@@ -131,6 +152,7 @@ typedef struct ScaleContext { · 36 unmodified lines
131 int input_is_pal; ///< set to 1 if the input format is paletted152 int input_is_pal; ///< set to 1 if the input format is paletted
132 int output_is_pal; ///< set to 1 if the output format is paletted153 int output_is_pal; ///< set to 1 if the output format is paletted
133 int interlaced;154 int interlaced;
155 int uses_ref;
134 156
135 char *w_expr; ///< width expression string157 char *w_expr; ///< width expression string
136 char *h_expr; ///< height expression string158 char *h_expr; ///< height expression string
@@ -190,6 +212,38 @@ static int check_exprs(AVFilterContext *ctx) · 53 unmodified lines
190 av_log(ctx, AV_LOG_WARNING, "Circular references detected for width '%s' and height '%s' - possibly invalid.\n", scale->w_expr, scale->h_expr);212 av_log(ctx, AV_LOG_WARNING, "Circular references detected for width '%s' and height '%s' - possibly invalid.\n", scale->w_expr, scale->h_expr);
191 }213 }
192 214
215 if (vars_w[VAR_REF_W] || vars_h[VAR_REF_W] ||
216 vars_w[VAR_RW] || vars_h[VAR_RW] ||
217 vars_w[VAR_REF_H] || vars_h[VAR_REF_H] ||
218 vars_w[VAR_RH] || vars_h[VAR_RH] ||
219 vars_w[VAR_REF_A] || vars_h[VAR_REF_A] ||
220 vars_w[VAR_REF_SAR] || vars_h[VAR_REF_SAR] ||
221 vars_w[VAR_REF_DAR] || vars_h[VAR_REF_DAR] ||
222 vars_w[VAR_RDAR] || vars_h[VAR_RDAR] ||
223 vars_w[VAR_REF_HSUB] || vars_h[VAR_REF_HSUB] ||
224 vars_w[VAR_REF_VSUB] || vars_h[VAR_REF_VSUB] ||
225 vars_w[VAR_REF_N] || vars_h[VAR_REF_N] ||
226 vars_w[VAR_REF_T] || vars_h[VAR_REF_T] ||
227 vars_w[VAR_REF_POS] || vars_h[VAR_REF_POS]) {
228 scale->uses_ref = 1;
229 }
230
231 if (ctx->filter != &ff_vf_scale2ref &&
232 (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
233 vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||
234 vars_w[VAR_S2R_MAIN_A] || vars_h[VAR_S2R_MAIN_A] ||
235 vars_w[VAR_S2R_MAIN_SAR] || vars_h[VAR_S2R_MAIN_SAR] ||
236 vars_w[VAR_S2R_MAIN_DAR] || vars_h[VAR_S2R_MAIN_DAR] ||
237 vars_w[VAR_S2R_MDAR] || vars_h[VAR_S2R_MDAR] ||
238 vars_w[VAR_S2R_MAIN_HSUB] || vars_h[VAR_S2R_MAIN_HSUB] ||
239 vars_w[VAR_S2R_MAIN_VSUB] || vars_h[VAR_S2R_MAIN_VSUB] ||
240 vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
241 vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
242 vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) {
243 av_log(ctx, AV_LOG_ERROR, "Expressions with scale2ref variables are not valid in scale filter.\n");
244 return AVERROR(EINVAL);
245 }
246
193 if (ctx->filter != &ff_vf_scale2ref &&247 if (ctx->filter != &ff_vf_scale2ref &&
194 (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||248 (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
195 vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||249 vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||
@@ -385,6 +439,9 @@ static av_cold int init(AVFilterContext *ctx) · 189 unmodified lines
385 if (!threads)439 if (!threads)
386 av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0);440 av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0);
387 441
442 if (ctx->filter != &ff_vf_scale2ref)
443 ctx->nb_inputs = scale->uses_ref ? 2 : 1;
444
388 return 0;445 return 0;
389}446}
390 447
@@ -506,6 +563,20 @@ static int scale_eval_dimensions(AVFilterContext *ctx) · 115 unmodified lines
506 scale->var_values[VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h;563 scale->var_values[VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h;
507 }564 }
508 565
566 if (scale->uses_ref) {
567 const AVFilterLink *reflink = ctx->inputs[1];
568 const AVPixFmtDescriptor *ref_desc = av_pix_fmt_desc_get(reflink->format);
569 scale->var_values[VAR_REF_W] = scale->var_values[VAR_RW] = reflink->w;
570 scale->var_values[VAR_REF_H] = scale->var_values[VAR_RH] = reflink->h;
571 scale->var_values[VAR_REF_A] = (double) reflink->w / reflink->h;
572 scale->var_values[VAR_REF_SAR] = reflink->sample_aspect_ratio.num ?
573 (double) reflink->sample_aspect_ratio.num / reflink->sample_aspect_ratio.den : 1;
574 scale->var_values[VAR_REF_DAR] = scale->var_values[VAR_RDAR] =
575 scale->var_values[VAR_REF_A] * scale->var_values[VAR_REF_SAR];
576 scale->var_values[VAR_REF_HSUB] = 1 << ref_desc->log2_chroma_w;
577 scale->var_values[VAR_REF_VSUB] = 1 << ref_desc->log2_chroma_h;
578 }
579
509 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);580 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
510 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;581 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
511 582
@@ -693,6 +764,13 @@ static int config_props(AVFilterLink *outlink) · 181 unmodified lines
693 scale->fs.in[0].sync = 1;764 scale->fs.in[0].sync = 1;
694 scale->fs.in[0].before = EXT_STOP;765 scale->fs.in[0].before = EXT_STOP;
695 scale->fs.in[0].after = EXT_STOP;766 scale->fs.in[0].after = EXT_STOP;
767 if (scale->uses_ref) {
768 av_assert0(ctx->nb_inputs == 2);
769 scale->fs.in[1].time_base = ctx->inputs[1]->time_base;
770 scale->fs.in[1].sync = 0;
771 scale->fs.in[1].before = EXT_NULL;
772 scale->fs.in[1].after = EXT_INFINITY;
773 }
696 774
697 ret = ff_framesync_configure(&scale->fs);775 ret = ff_framesync_configure(&scale->fs);
698 if (ret < 0)776 if (ret < 0)
@@ -919,13 +997,55 @@ scale: · 220 unmodified lines
919static int do_scale(FFFrameSync *fs)997static int do_scale(FFFrameSync *fs)
920{998{
921 AVFilterContext *ctx = fs->parent;999 AVFilterContext *ctx = fs->parent;
1000 ScaleContext *scale = ctx->priv;
922 AVFilterLink *outlink = ctx->outputs[0];1001 AVFilterLink *outlink = ctx->outputs[0];
923 AVFrame *in, *out;1002 AVFrame *out, *in = NULL, *ref = NULL;
924 int ret;1003 int ret = 0, frame_changed;
925 1004
926 ret = ff_framesync_get_frame(fs, 0, &in, 1);1005 ret = ff_framesync_get_frame(fs, 0, &in, 1);
927 if (ret < 0)1006 if (ret < 0)
928 return ret;1007 goto err;
1008
1009 if (scale->uses_ref) {
1010 ret = ff_framesync_get_frame(fs, 1, &ref, 0);
1011 if (ret < 0)
1012 goto err;
1013 }
1014
1015 if (ref) {
1016 AVFilterLink *reflink = ctx->inputs[1];
1017 frame_changed = ref->width != reflink->w ||
1018 ref->height != reflink->h ||
1019 ref->format != reflink->format ||
1020 ref->sample_aspect_ratio.den != reflink->sample_aspect_ratio.den ||
1021 ref->sample_aspect_ratio.num != reflink->sample_aspect_ratio.num ||
1022 ref->colorspace != reflink->colorspace ||
1023 ref->color_range != reflink->color_range;
1024
1025 if (frame_changed) {
1026 reflink->format = ref->format;
1027 reflink->w = ref->width;
1028 reflink->h = ref->height;
1029 reflink->sample_aspect_ratio.num = ref->sample_aspect_ratio.num;
1030 reflink->sample_aspect_ratio.den = ref->sample_aspect_ratio.den;
1031 reflink->colorspace = ref->colorspace;
1032 reflink->color_range = ref->color_range;
1033
1034 ret = config_props(outlink);
1035 if (ret < 0)
1036 goto err;
1037 }
1038
1039 if (scale->eval_mode == EVAL_MODE_FRAME) {
1040 scale->var_values[VAR_REF_N] = reflink->frame_count_out;
1041 scale->var_values[VAR_REF_T] = TS2T(ref->pts, reflink->time_base);
1042#if FF_API_FRAME_PKT
1043FF_DISABLE_DEPRECATION_WARNINGS
1044 scale->var_values[VAR_REF_POS] = ref->pkt_pos == -1 ? NAN : ref->pkt_pos;
1045FF_ENABLE_DEPRECATION_WARNINGS
1046#endif
1047 }
1048 }
929 1049
930 ret = scale_frame(ctx->inputs[0], in, &out);1050 ret = scale_frame(ctx->inputs[0], in, &out);
931 if (out) {1051 if (out) {
@@ -933,6 +1053,9 @@ static int do_scale(FFFrameSync *fs) · 1 unmodified line
933 return ff_filter_frame(outlink, out);1053 return ff_filter_frame(outlink, out);
934 }1054 }
935 1055
1056err:
1057 if (ret < 0)
1058 av_frame_free(&in);
936 return ret;1059 return ret;
937}1060}
938 1061
@@ -1108,6 +1231,9 @@ static const AVFilterPad avfilter_vf_scale_inputs[] = { · 169 unmodified lines
1108 {1231 {
1109 .name = "default",1232 .name = "default",
1110 .type = AVMEDIA_TYPE_VIDEO,1233 .type = AVMEDIA_TYPE_VIDEO,
1234 }, {
1235 .name = "ref",
1236 .type = AVMEDIA_TYPE_VIDEO,
1111 },1237 },
1112};1238};
1113 1239

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