GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavfilter/scale_eval.c Lines: 15 62 24.2 %
Date: 2020-08-14 10:39:37 Branches: 7 32 21.9 %

Line Branch Exec Source
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_eval.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
    "in_w",   "iw",
29
    "in_h",   "ih",
30
    "out_w",  "ow",
31
    "out_h",  "oh",
32
    "a",
33
    "sar",
34
    "dar",
35
    "hsub",
36
    "vsub",
37
    "ohsub",
38
    "ovsub",
39
    NULL
40
};
41
42
enum var_name {
43
    VAR_IN_W,   VAR_IW,
44
    VAR_IN_H,   VAR_IH,
45
    VAR_OUT_W,  VAR_OW,
46
    VAR_OUT_H,  VAR_OH,
47
    VAR_A,
48
    VAR_SAR,
49
    VAR_DAR,
50
    VAR_HSUB,
51
    VAR_VSUB,
52
    VAR_OHSUB,
53
    VAR_OVSUB,
54
    VARS_NB
55
};
56
57
int ff_scale_eval_dimensions(void *log_ctx,
58
    const char *w_expr, const char *h_expr,
59
    AVFilterLink *inlink, AVFilterLink *outlink,
60
    int *ret_w, int *ret_h)
61
{
62
    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
63
    const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
64
    const char *expr;
65
    int eval_w, eval_h;
66
    int ret;
67
    double var_values[VARS_NB], res;
68
69
    var_values[VAR_IN_W]  = var_values[VAR_IW] = inlink->w;
70
    var_values[VAR_IN_H]  = var_values[VAR_IH] = inlink->h;
71
    var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN;
72
    var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN;
73
    var_values[VAR_A]     = (double) inlink->w / inlink->h;
74
    var_values[VAR_SAR]   = inlink->sample_aspect_ratio.num ?
75
        (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
76
    var_values[VAR_DAR]   = var_values[VAR_A] * var_values[VAR_SAR];
77
    var_values[VAR_HSUB]  = 1 << desc->log2_chroma_w;
78
    var_values[VAR_VSUB]  = 1 << desc->log2_chroma_h;
79
    var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w;
80
    var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h;
81
82
    /* evaluate width and height */
83
    av_expr_parse_and_eval(&res, (expr = w_expr),
84
                           var_names, var_values,
85
                           NULL, NULL, NULL, NULL, NULL, 0, log_ctx);
86
    eval_w = var_values[VAR_OUT_W] = var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
87
88
    if ((ret = av_expr_parse_and_eval(&res, (expr = h_expr),
89
                                      var_names, var_values,
90
                                      NULL, NULL, NULL, NULL, NULL, 0, log_ctx)) < 0)
91
        goto fail;
92
    eval_h = var_values[VAR_OUT_H] = var_values[VAR_OH] = (int) res == 0 ? inlink->h : (int) res;
93
    /* evaluate again the width, as it may depend on the output height */
94
    if ((ret = av_expr_parse_and_eval(&res, (expr = w_expr),
95
                                      var_names, var_values,
96
                                      NULL, NULL, NULL, NULL, NULL, 0, log_ctx)) < 0)
97
        goto fail;
98
    eval_w = (int) res == 0 ? inlink->w : (int) res;
99
100
    *ret_w = eval_w;
101
    *ret_h = eval_h;
102
103
    return 0;
104
105
fail:
106
    av_log(log_ctx, AV_LOG_ERROR,
107
           "Error when evaluating the expression '%s'.\n"
108
           "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
109
           expr, w_expr, h_expr);
110
    return ret;
111
}
112
113
3412
int ff_scale_adjust_dimensions(AVFilterLink *inlink,
114
    int *ret_w, int *ret_h,
115
    int force_original_aspect_ratio, int force_divisible_by)
116
{
117
    int w, h;
118
    int factor_w, factor_h;
119
120
3412
    w = *ret_w;
121
3412
    h = *ret_h;
122
123
    /* Check if it is requested that the result has to be divisible by some
124
     * factor (w or h = -n with n being the factor). */
125
3412
    factor_w = 1;
126
3412
    factor_h = 1;
127
3412
    if (w < -1) {
128
        factor_w = -w;
129
    }
130
3412
    if (h < -1) {
131
        factor_h = -h;
132
    }
133
134

3412
    if (w < 0 && h < 0) {
135
        w = inlink->w;
136
        h = inlink->h;
137
    }
138
139
    /* Make sure that the result is divisible by the factor we determined
140
     * earlier. If no factor was set, nothing will happen as the default
141
     * factor is 1 */
142
3412
    if (w < 0)
143
        w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w;
144
3412
    if (h < 0)
145
1
        h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h;
146
147
    /* Note that force_original_aspect_ratio may overwrite the previous set
148
     * dimensions so that it is not divisible by the set factors anymore
149
     * unless force_divisible_by is defined as well */
150
3412
    if (force_original_aspect_ratio) {
151
        int tmp_w = av_rescale(h, inlink->w, inlink->h);
152
        int tmp_h = av_rescale(w, inlink->h, inlink->w);
153
154
        if (force_original_aspect_ratio == 1) {
155
             w = FFMIN(tmp_w, w);
156
             h = FFMIN(tmp_h, h);
157
             if (force_divisible_by > 1) {
158
                 // round down
159
                 w = w / force_divisible_by * force_divisible_by;
160
                 h = h / force_divisible_by * force_divisible_by;
161
             }
162
        } else {
163
             w = FFMAX(tmp_w, w);
164
             h = FFMAX(tmp_h, h);
165
             if (force_divisible_by > 1) {
166
                 // round up
167
                 w = (w + force_divisible_by - 1) / force_divisible_by * force_divisible_by;
168
                 h = (h + force_divisible_by - 1) / force_divisible_by * force_divisible_by;
169
             }
170
        }
171
    }
172
173
3412
    *ret_w = w;
174
3412
    *ret_h = h;
175
176
3412
    return 0;
177
}