| @@ -59,6 +59,17 @@ static const char *const var_names[] = { · 58 unmodified lines |
| 59 | 59 | #if FF_API_FRAME_PKT |
| 60 | 60 | "pos", |
| 61 | 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 | 73 | "main_w", |
| 63 | 74 | "main_h", |
| 64 | 75 | "main_a", |
| @@ -89,6 +100,16 @@ enum var_name { · 24 unmodified lines |
| 89 | 100 | #if FF_API_FRAME_PKT |
| 90 | 101 | VAR_POS, |
| 91 | 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 | 113 | VAR_S2R_MAIN_W, |
| 93 | 114 | VAR_S2R_MAIN_H, |
| 94 | 115 | VAR_S2R_MAIN_A, |
| @@ -131,6 +152,7 @@ typedef struct ScaleContext { · 36 unmodified lines |
| 131 | 152 | int input_is_pal; ///< set to 1 if the input format is paletted |
| 132 | 153 | int output_is_pal; ///< set to 1 if the output format is paletted |
| 133 | 154 | int interlaced; |
| 155 | + int uses_ref; |
| 134 | 156 | |
| 135 | 157 | char *w_expr; ///< width expression string |
| 136 | 158 | char *h_expr; ///< height expression string |
| @@ -190,6 +212,38 @@ static int check_exprs(AVFilterContext *ctx) · 53 unmodified lines |
| 190 | 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 | 247 | if (ctx->filter != &ff_vf_scale2ref && |
| 194 | 248 | (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] || |
| 195 | 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 | 439 | if (!threads) |
| 386 | 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 | 445 | return 0; |
| 389 | 446 | } |
| 390 | 447 | |
| @@ -506,6 +563,20 @@ static int scale_eval_dimensions(AVFilterContext *ctx) · 115 unmodified lines |
| 506 | 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 | 580 | res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL); |
| 510 | 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 | 764 | scale->fs.in[0].sync = 1; |
| 694 | 765 | scale->fs.in[0].before = EXT_STOP; |
| 695 | 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 | 775 | ret = ff_framesync_configure(&scale->fs); |
| 698 | 776 | if (ret < 0) |
| @@ -919,13 +997,55 @@ scale: · 220 unmodified lines |
| 919 | 997 | static int do_scale(FFFrameSync *fs) |
| 920 | 998 | { |
| 921 | 999 | AVFilterContext *ctx = fs->parent; |
| 1000 | + ScaleContext *scale = ctx->priv; |
| 922 | 1001 | 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; |
| 925 | 1004 | |
| 926 | 1005 | ret = ff_framesync_get_frame(fs, 0, &in, 1); |
| 927 | 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 | 1050 | ret = scale_frame(ctx->inputs[0], in, &out); |
| 931 | 1051 | if (out) { |
| @@ -933,6 +1053,9 @@ static int do_scale(FFFrameSync *fs) · 1 unmodified line |
| 933 | 1053 | return ff_filter_frame(outlink, out); |
| 934 | 1054 | } |
| 935 | 1055 | |
| 1056 | +err: |
| 1057 | + if (ret < 0) |
| 1058 | + av_frame_free(&in); |
| 936 | 1059 | return ret; |
| 937 | 1060 | } |
| 938 | 1061 | |
| @@ -1108,6 +1231,9 @@ static const AVFilterPad avfilter_vf_scale_inputs[] = { · 169 unmodified lines |
| 1108 | 1231 | { |
| 1109 | 1232 | .name = "default", |
| 1110 | 1233 | .type = AVMEDIA_TYPE_VIDEO, |
| 1234 | + }, { |
| 1235 | + .name = "ref", |
| 1236 | + .type = AVMEDIA_TYPE_VIDEO, |
| 1111 | 1237 | }, |
| 1112 | 1238 | }; |
| 1113 | 1239 | |