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.
Showing the changes to libavfilter (1 of 3 files). Show all
Unified · Split
| @@ -59,6 +59,17 @@ static const char *const var_names[] = { · 58 unmodified lines | |||
| 59 | #if FF_API_FRAME_PKT | 59 | #if FF_API_FRAME_PKT |
| 60 | "pos", | 60 | "pos", |
| 61 | #endif | 61 | #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_PKT | 100 | #if FF_API_FRAME_PKT |
| 90 | VAR_POS, | 101 | VAR_POS, |
| 91 | #endif | 102 | #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 paletted | 152 | 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 paletted | 153 | 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 string | 157 | char *w_expr; ///< width expression string |
| 136 | char *h_expr; ///< height expression string | 158 | 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 | |||
| 919 | static int do_scale(FFFrameSync *fs) | 997 | static 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 | ||
| 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 | } | ||
| 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 | ||
| 1056 | err: | ||
| 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 | ||