blob: 50cd442849bfd3a161f638e15b3f45b393b25bfe
1 | /* |
2 | * Copyright (c) 2007 Bobby Bingham |
3 | * |
4 | * This file is part of FFmpeg. |
5 | * |
6 | * FFmpeg is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2.1 of the License, or (at your option) any later version. |
10 | * |
11 | * FFmpeg is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with FFmpeg; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | */ |
20 | |
21 | #include <stdint.h> |
22 | #include "scale.h" |
23 | #include "libavutil/eval.h" |
24 | #include "libavutil/mathematics.h" |
25 | #include "libavutil/pixdesc.h" |
26 | |
27 | static const char *const var_names[] = { |
28 | "PI", |
29 | "PHI", |
30 | "E", |
31 | "in_w", "iw", |
32 | "in_h", "ih", |
33 | "out_w", "ow", |
34 | "out_h", "oh", |
35 | "a", |
36 | "sar", |
37 | "dar", |
38 | "hsub", |
39 | "vsub", |
40 | "ohsub", |
41 | "ovsub", |
42 | NULL |
43 | }; |
44 | |
45 | enum var_name { |
46 | VAR_PI, |
47 | VAR_PHI, |
48 | VAR_E, |
49 | VAR_IN_W, VAR_IW, |
50 | VAR_IN_H, VAR_IH, |
51 | VAR_OUT_W, VAR_OW, |
52 | VAR_OUT_H, VAR_OH, |
53 | VAR_A, |
54 | VAR_SAR, |
55 | VAR_DAR, |
56 | VAR_HSUB, |
57 | VAR_VSUB, |
58 | VAR_OHSUB, |
59 | VAR_OVSUB, |
60 | VARS_NB |
61 | }; |
62 | |
63 | int ff_scale_eval_dimensions(void *log_ctx, |
64 | const char *w_expr, const char *h_expr, |
65 | AVFilterLink *inlink, AVFilterLink *outlink, |
66 | int *ret_w, int *ret_h) |
67 | { |
68 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); |
69 | const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format); |
70 | const char *expr; |
71 | int w, h; |
72 | int factor_w, factor_h; |
73 | int eval_w, eval_h; |
74 | int ret; |
75 | double var_values[VARS_NB], res; |
76 | |
77 | var_values[VAR_PI] = M_PI; |
78 | var_values[VAR_PHI] = M_PHI; |
79 | var_values[VAR_E] = M_E; |
80 | var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; |
81 | var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; |
82 | var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN; |
83 | var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN; |
84 | var_values[VAR_A] = (double) inlink->w / inlink->h; |
85 | var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? |
86 | (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1; |
87 | var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR]; |
88 | var_values[VAR_HSUB] = 1 << desc->log2_chroma_w; |
89 | var_values[VAR_VSUB] = 1 << desc->log2_chroma_h; |
90 | var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w; |
91 | var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h; |
92 | |
93 | /* evaluate width and height */ |
94 | av_expr_parse_and_eval(&res, (expr = w_expr), |
95 | var_names, var_values, |
96 | NULL, NULL, NULL, NULL, NULL, 0, log_ctx); |
97 | eval_w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; |
98 | |
99 | if ((ret = av_expr_parse_and_eval(&res, (expr = h_expr), |
100 | var_names, var_values, |
101 | NULL, NULL, NULL, NULL, NULL, 0, log_ctx)) < 0) |
102 | goto fail; |
103 | eval_h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res; |
104 | /* evaluate again the width, as it may depend on the output height */ |
105 | if ((ret = av_expr_parse_and_eval(&res, (expr = w_expr), |
106 | var_names, var_values, |
107 | NULL, NULL, NULL, NULL, NULL, 0, log_ctx)) < 0) |
108 | goto fail; |
109 | eval_w = res; |
110 | |
111 | w = eval_w; |
112 | h = eval_h; |
113 | |
114 | /* Check if it is requested that the result has to be divisible by a some |
115 | * factor (w or h = -n with n being the factor). */ |
116 | factor_w = 1; |
117 | factor_h = 1; |
118 | if (w < -1) { |
119 | factor_w = -w; |
120 | } |
121 | if (h < -1) { |
122 | factor_h = -h; |
123 | } |
124 | |
125 | if (w < 0 && h < 0) |
126 | eval_w = eval_h = 0; |
127 | |
128 | if (!(w = eval_w)) |
129 | w = inlink->w; |
130 | if (!(h = eval_h)) |
131 | h = inlink->h; |
132 | |
133 | /* Make sure that the result is divisible by the factor we determined |
134 | * earlier. If no factor was set, it is nothing will happen as the default |
135 | * factor is 1 */ |
136 | if (w < 0) |
137 | w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w; |
138 | if (h < 0) |
139 | h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h; |
140 | |
141 | *ret_w = w; |
142 | *ret_h = h; |
143 | |
144 | return 0; |
145 | |
146 | fail: |
147 | av_log(log_ctx, AV_LOG_ERROR, |
148 | "Error when evaluating the expression '%s'.\n" |
149 | "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n", |
150 | expr, w_expr, h_expr); |
151 | return ret; |
152 | } |
153 |