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

Unified · Split

3 files
  1. Changelog +1 −0
  2. doc/filters.texi +26 −0
  3. libavfilter/vf_scale.c +129 −3
Changelog+1−0
@@ -7,6 +7,7 @@ version <next>: · 6 unmodified lines
77 - ffmpeg CLI filtergraph chaining
88 - LC3/LC3plus demuxer and muxer
99 - pad_vaapi, drawbox_vaapi filters
10+- vf_scale supports secondary ref input and framesync options
1011
1112
1213 version 7.0:
doc/filters.texi+26−0
@@ -21562,8 +21562,34 @@ The position (byte offset) of the frame in the input stream, or NaN if · 21561 unmodified lines
2156221562 this information is unavailable and/or meaningless (for example in case of synthetic video).
2156321563 Only available with @code{eval=frame}.
2156421564 Deprecated, do not use.
21565+
21566+@item ref_w, rw
21567+@item ref_h, rh
21568+@item ref_a
21569+@item ref_dar, rdar
21570+@item ref_n
21571+@item ref_t
21572+@item ref_pos
21573+Eqvuialent to the above, but for a second reference input. If any of these
21574+variables are present, this filter accepts two inputs.
2156521575 @end table
2156621576
21577+@subsection Examples
21578+
21579+@itemize
21580+@item
21581+Scale a subtitle stream (sub) to match the main video (main) in size before overlaying
21582+@example
21583+'[main]split[a][b]; [ref][a]scale=rw:rh[c]; [b][c]overlay'
21584+@end example
21585+
21586+@item
21587+Scale a logo to 1/10th the height of a video, while preserving its display aspect ratio.
21588+@example
21589+[logo-in][video-in]scale=w=oh*dar:h=rh/10[logo-out]
21590+@end example
21591+@end itemize
21592+
2156721593 @section scale2ref
2156821594
2156921595 Scale (resize) the input video, based on a reference video.
libavfilter/vf_scale.c+129−3
@@ -59,6 +59,17 @@ static const char *const var_names[] = { · 58 unmodified lines
5959 #if FF_API_FRAME_PKT
6060 "pos",
6161 #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 */
6273 "main_w",
6374 "main_h",
6475 "main_a",
@@ -89,6 +100,16 @@ enum var_name { · 24 unmodified lines
89100 #if FF_API_FRAME_PKT
90101 VAR_POS,
91102 #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,
92113 VAR_S2R_MAIN_W,
93114 VAR_S2R_MAIN_H,
94115 VAR_S2R_MAIN_A,
@@ -131,6 +152,7 @@ typedef struct ScaleContext { · 36 unmodified lines
131152 int input_is_pal; ///< set to 1 if the input format is paletted
132153 int output_is_pal; ///< set to 1 if the output format is paletted
133154 int interlaced;
155+ int uses_ref;
134156
135157 char *w_expr; ///< width expression string
136158 char *h_expr; ///< height expression string
@@ -190,6 +212,38 @@ static int check_exprs(AVFilterContext *ctx) · 53 unmodified lines
190212 av_log(ctx, AV_LOG_WARNING, "Circular references detected for width '%s' and height '%s' - possibly invalid.\n", scale->w_expr, scale->h_expr);
191213 }
192214
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+
193247 if (ctx->filter != &ff_vf_scale2ref &&
194248 (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
195249 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
385439 if (!threads)
386440 av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0);
387441
442+ if (ctx->filter != &ff_vf_scale2ref)
443+ ctx->nb_inputs = scale->uses_ref ? 2 : 1;
444+
388445 return 0;
389446 }
390447
@@ -506,6 +563,20 @@ static int scale_eval_dimensions(AVFilterContext *ctx) · 115 unmodified lines
506563 scale->var_values[VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h;
507564 }
508565
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+
509580 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
510581 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
511582
@@ -693,6 +764,13 @@ static int config_props(AVFilterLink *outlink) · 181 unmodified lines
693764 scale->fs.in[0].sync = 1;
694765 scale->fs.in[0].before = EXT_STOP;
695766 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+ }
696774
697775 ret = ff_framesync_configure(&scale->fs);
698776 if (ret < 0)
@@ -919,13 +997,55 @@ scale: · 220 unmodified lines
919997 static int do_scale(FFFrameSync *fs)
920998 {
921999 AVFilterContext *ctx = fs->parent;
1000+ ScaleContext *scale = ctx->priv;
9221001 AVFilterLink *outlink = ctx->outputs[0];
923− AVFrame *in, *out;
924− int ret;
1002+ AVFrame *out, *in = NULL, *ref = NULL;
1003+ int ret = 0, frame_changed;
9251004
9261005 ret = ff_framesync_get_frame(fs, 0, &in, 1);
9271006 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
1043+FF_DISABLE_DEPRECATION_WARNINGS
1044+ scale->var_values[VAR_REF_POS] = ref->pkt_pos == -1 ? NAN : ref->pkt_pos;
1045+FF_ENABLE_DEPRECATION_WARNINGS
1046+#endif
1047+ }
1048+ }
9291049
9301050 ret = scale_frame(ctx->inputs[0], in, &out);
9311051 if (out) {
@@ -933,6 +1053,9 @@ static int do_scale(FFFrameSync *fs) · 1 unmodified line
9331053 return ff_filter_frame(outlink, out);
9341054 }
9351055
1056+err:
1057+ if (ret < 0)
1058+ av_frame_free(&in);
9361059 return ret;
9371060 }
9381061
@@ -1108,6 +1231,9 @@ static const AVFilterPad avfilter_vf_scale_inputs[] = { · 169 unmodified lines
11081231 {
11091232 .name = "default",
11101233 .type = AVMEDIA_TYPE_VIDEO,
1234+ }, {
1235+ .name = "ref",
1236+ .type = AVMEDIA_TYPE_VIDEO,
11111237 },
11121238 };
11131239

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