PR #24668 opened by James Almer (jamrial) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24668 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24668.patch
It's specific to sws, so no reason to have it in avutil. >From 1433217d4feed300a839651fdd68f8767d6da04e Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 24 Sep 2026 11:03:22 -0300 Subject: [PATCH 1/2] swscale/rational64: replace av_ prefix with ff_ Even if not exported in sws, av_ prefixes are normally reserved for public functions. Signed-off-by: James Almer <[email protected]> --- libswscale/format.c | 22 +++++++++---------- libswscale/ops.c | 44 +++++++++++++++++++------------------- libswscale/ops_optimizer.c | 16 +++++++------- libswscale/rational64.c | 12 +++++------ libswscale/rational64.h | 16 +++++++------- 5 files changed, 55 insertions(+), 55 deletions(-) diff --git a/libswscale/format.c b/libswscale/format.c index 8c53832159..254b9353c4 100644 --- a/libswscale/format.c +++ b/libswscale/format.c @@ -1284,7 +1284,7 @@ static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete) if (fmt->format == AV_PIX_FMT_MONOWHITE) { /* This format is inverted, 0 = white, 1 = black */ - c.m[0][4] = av_add_q64(c.m[0][4], c.m[0][0]); + c.m[0][4] = ff_add_q64(c.m[0][4], c.m[0][0]); c.m[0][0] = av_neg_q64(c.m[0][0]); } @@ -1298,8 +1298,8 @@ static SwsLinearOp fmt_decode_range(const SwsFormat *fmt, bool *incomplete) /* Invert main diagonal + offset: x = s * y + k ==> y = (x - k) / s */ for (int i = 0; i < 4; i++) { av_assert1(c.m[i][i].num); - c.m[i][i] = av_inv_q64(c.m[i][i]); - c.m[i][4] = av_mul_q64(c.m[i][4], av_neg_q64(c.m[i][i])); + c.m[i][i] = ff_inv_q64(c.m[i][i]); + c.m[i][4] = ff_mul_q64(c.m[i][4], av_neg_q64(c.m[i][i])); } /* Explicitly initialize alpha for sanity */ @@ -1327,9 +1327,9 @@ static AVRational64 *generate_bayer_matrix(const int size_log2) for (int y = 0; y < sz; y++) { for (int x = 0; x < sz; x++) { const AVRational64 cur = m[y * size + x]; - m[(y + sz) * size + x + sz] = av_add_q64(cur, av_make_q64(1, den)); - m[(y ) * size + x + sz] = av_add_q64(cur, av_make_q64(2, den)); - m[(y + sz) * size + x ] = av_add_q64(cur, av_make_q64(3, den)); + m[(y + sz) * size + x + sz] = ff_add_q64(cur, ff_make_q64(1, den)); + m[(y ) * size + x + sz] = ff_add_q64(cur, ff_make_q64(2, den)); + m[(y + sz) * size + x ] = ff_add_q64(cur, ff_make_q64(3, den)); } } } @@ -1345,7 +1345,7 @@ static AVRational64 *generate_bayer_matrix(const int size_log2) * To make the average value equal to 1/2 = N/(2N), add a bias of 1/(2N). */ for (int i = 0; i < num_entries; i++) - m[i] = av_add_q64(m[i], av_make_q64(1, 2 * num_entries)); + m[i] = ff_add_q64(m[i], ff_make_q64(1, 2 * num_entries)); return m; } @@ -1412,9 +1412,9 @@ static int fmt_dither(SwsContext *ctx, SwsOpList *ops, const int size = 1 << dither.size_log2; dither.min = dither.max = dither.matrix[0]; for (int i = 1; i < size * size; i++) { - if (av_cmp_q64(dither.min, dither.matrix[i]) > 0) + if (ff_cmp_q64(dither.min, dither.matrix[i]) > 0) dither.min = dither.matrix[i]; - if (av_cmp_q64(dither.matrix[i], dither.max) > 0) + if (ff_cmp_q64(dither.matrix[i], dither.max) > 0) dither.max = dither.matrix[i]; } @@ -1460,7 +1460,7 @@ static int fmt_dither(SwsContext *ctx, SwsOpList *ops, return AVERROR(EINVAL); } -#define Q64(x) av_make_q64((x).num, (x).den) +#define Q64(x) ff_make_q64((x).num, (x).den) static inline SwsLinearOp linear_mat3(const AVRational m00, const AVRational m01, const AVRational m02, @@ -1788,7 +1788,7 @@ int ff_sws_apply_lut3d(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, })); /* Normalize back to [0, 1] */ - const AVRational64 inv = av_inv_q64(Q(UINT16_MAX)); + const AVRational64 inv = ff_inv_q64(Q(UINT16_MAX)); RET(ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, diff --git a/libswscale/ops.c b/libswscale/ops.c index 5590915e30..4d2343f9ed 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -146,12 +146,12 @@ int ff_sws_rw_op_planes(const SwsOp *op) /* biased towards `a` */ static AVRational64 av_min_q64(AVRational64 a, AVRational64 b) { - return av_cmp_q64(a, b) == 1 ? b : a; + return ff_cmp_q64(a, b) == 1 ? b : a; } static AVRational64 av_max_q64(AVRational64 a, AVRational64 b) { - return av_cmp_q64(a, b) == -1 ? b : a; + return ff_cmp_q64(a, b) == -1 ? b : a; } void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4]) @@ -207,7 +207,7 @@ void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4]) av_assert1(ff_sws_pixel_type_is_int(op->type)); AVRational64 mult = Q(1 << op->shift.amount); for (int i = 0; i < 4; i++) - x[i] = x[i].den ? av_mul_q64(x[i], mult) : x[i]; + x[i] = x[i].den ? ff_mul_q64(x[i], mult) : x[i]; return; } case SWS_OP_RSHIFT: { @@ -228,7 +228,7 @@ void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4]) for (int i = 0; i < 4; i++) { x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i]; if (op->convert.expand) - x[i] = av_mul_q64(x[i], scale); + x[i] = ff_mul_q64(x[i], scale); } } return; @@ -236,7 +236,7 @@ void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4]) av_assert1(!ff_sws_pixel_type_is_int(op->type)); for (int i = 0; i < 4; i++) { if (op->dither.y_offset[i] >= 0 && x[i].den) - x[i] = av_add_q64(x[i], av_make_q64(1, 2)); + x[i] = ff_add_q64(x[i], ff_make_q64(1, 2)); } return; case SWS_OP_MIN: @@ -253,14 +253,14 @@ void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4]) for (int i = 0; i < 4; i++) { AVRational64 sum = op->lin.m[i][4]; for (int j = 0; j < 4; j++) - sum = av_add_q64(sum, av_mul_q64(orig[j], op->lin.m[i][j])); + sum = ff_add_q64(sum, ff_mul_q64(orig[j], op->lin.m[i][j])); x[i] = sum; } return; } case SWS_OP_SCALE: for (int i = 0; i < 4; i++) - x[i] = x[i].den ? av_mul_q64(x[i], op->scale.factor) : x[i]; + x[i] = x[i].den ? ff_mul_q64(x[i], op->scale.factor) : x[i]; return; case SWS_OP_FILTER_H: case SWS_OP_FILTER_V: @@ -304,10 +304,10 @@ static void apply_filter_weights(SwsComps *comps, const SwsComps *prev, if (weights->filter_size != 1) comps->flags[i] &= ~SWS_COMP_EXACT; /* Update min/max assuming extremes */ - comps->min[i] = av_add_q64(av_mul_q64(prev->min[i], posw), - av_mul_q64(prev->max[i], negw)); - comps->max[i] = av_add_q64(av_mul_q64(prev->min[i], negw), - av_mul_q64(prev->max[i], posw)); + comps->min[i] = ff_add_q64(ff_mul_q64(prev->min[i], posw), + ff_mul_q64(prev->max[i], negw)); + comps->max[i] = ff_add_q64(ff_mul_q64(prev->min[i], negw), + ff_mul_q64(prev->max[i], posw)); } } @@ -429,8 +429,8 @@ void ff_sws_op_list_update_comps(SwsOpList *ops) continue; /* Strip zero flag because of the nonzero dithering offset */ op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY; - op->comps.min[i] = av_add_q64(op->comps.min[i], op->dither.min); - op->comps.max[i] = av_add_q64(op->comps.max[i], op->dither.max); + op->comps.min[i] = ff_add_q64(op->comps.min[i], op->dither.min); + op->comps.max[i] = ff_add_q64(op->comps.max[i], op->dither.max); } break; case SWS_OP_UNPACK: @@ -485,17 +485,17 @@ void ff_sws_op_list_update_comps(SwsOpList *ops) bool first = true; for (int j = 0; j < 4; j++) { const AVRational64 k = op->lin.m[i][j]; - AVRational64 mink = av_mul_q64(prev.min[j], k); - AVRational64 maxk = av_mul_q64(prev.max[j], k); + AVRational64 mink = ff_mul_q64(prev.min[j], k); + AVRational64 maxk = ff_mul_q64(prev.max[j], k); if (k.num) { FORWARD(i, j, flags); if (k.den != 1) /* fractional coefficient */ op->comps.flags[i] &= ~SWS_COMP_EXACT; if (k.num < 0) FFSWAP(AVRational64, mink, maxk); - min = av_add_q64(min, mink); - max = av_add_q64(max, maxk); - if (!first || av_cmp_q64(k, Q(1))) + min = ff_add_q64(min, mink); + max = ff_add_q64(max, maxk); + if (!first || ff_cmp_q64(k, Q(1))) op->comps.flags[i] &= SWS_COMP_DIRTY; first = false; } @@ -504,8 +504,8 @@ void ff_sws_op_list_update_comps(SwsOpList *ops) op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY; if (op->lin.m[i][4].den != 1) /* fractional offset */ op->comps.flags[i] &= ~SWS_COMP_EXACT; - min = av_add_q64(min, op->lin.m[i][4]); - max = av_add_q64(max, op->lin.m[i][4]); + min = ff_add_q64(min, op->lin.m[i][4]); + max = ff_add_q64(max, op->lin.m[i][4]); } op->comps.min[i] = min; op->comps.max[i] = max; @@ -804,7 +804,7 @@ uint32_t ff_sws_linear_mask(const SwsLinearOp *c) uint32_t mask = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) { - if (av_cmp_q64(c->m[i][j], Q(i == j))) + if (ff_cmp_q64(c->m[i][j], Q(i == j))) mask |= SWS_MASK(i, j); } } @@ -847,7 +847,7 @@ static void print_q(AVBPrint *bp, const AVRational64 q) } else if (q.den == 1) { av_bprintf(bp, "%"PRId64, q.num); } else if (q.num > 1000 || q.num < -1000 || q.den > 1000 || q.den < -1000) { - av_bprintf(bp, "%f", av_q2d_64(q)); + av_bprintf(bp, "%f", ff_q2d_64(q)); } else { av_bprintf(bp, "%"PRId64"/%"PRId64, q.num, q.den); } diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c index 9cc5db9717..3945de2034 100644 --- a/libswscale/ops_optimizer.c +++ b/libswscale/ops_optimizer.c @@ -128,7 +128,7 @@ static bool op_commute_swizzle(SwsOp *op, SwsOp *next) if (!SWS_OP_NEEDED(op, i)) continue; const int j = op->swizzle.in[i]; - if (seen[j] && av_cmp_q64(next->clamp.limit[j], c.limit[i])) + if (seen[j] && ff_cmp_q64(next->clamp.limit[j], c.limit[i])) return false; next->clamp.limit[j] = c.limit[i]; seen[j] = true; @@ -249,7 +249,7 @@ static bool extract_scalar(const SwsLinearOp *c, if ((prev->flags[i] & SWS_COMP_ZERO) || (comps->flags[i] & SWS_COMP_GARBAGE)) continue; - if (scale.factor.den && av_cmp_q64(s, scale.factor)) + if (scale.factor.den && ff_cmp_q64(s, scale.factor)) return false; scale.factor = s; } @@ -568,7 +568,7 @@ retry: if (next->op == SWS_OP_SCALE && !op->convert.expand && ff_sws_pixel_type_is_int(op->type) && ff_sws_pixel_type_is_int(op->convert.to) && - !av_cmp_q64(next->scale.factor, + !ff_cmp_q64(next->scale.factor, ff_sws_pixel_expand(op->type, op->convert.to))) { op->convert.expand = true; @@ -581,7 +581,7 @@ retry: for (int i = 0; i < 4; i++) { if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den) continue; - if (av_cmp_q64(op->clamp.limit[i], prev->comps.max[i]) >= 0) + if (ff_cmp_q64(op->clamp.limit[i], prev->comps.max[i]) >= 0) op->clamp.limit[i] = (AVRational64) {0}; /* no-op */ else noop = false; @@ -597,7 +597,7 @@ retry: for (int i = 0; i < 4; i++) { if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den) continue; - if (av_cmp_q64(prev->comps.min[i], op->clamp.limit[i]) >= 0) + if (ff_cmp_q64(prev->comps.min[i], op->clamp.limit[i]) >= 0) op->clamp.limit[i] = (AVRational64) {0}; else noop = false; @@ -647,9 +647,9 @@ retry: for (int j = 0; j < 5; j++) { AVRational64 sum = Q(0); for (int k = 0; k < 4; k++) - sum = av_add_q64(sum, av_mul_q64(m2.m[i][k], m1.m[k][j])); + sum = ff_add_q64(sum, ff_mul_q64(m2.m[i][k], m1.m[k][j])); if (j == 4) /* m1.m[4][j] == 1 */ - sum = av_add_q64(sum, m2.m[i][4]); + sum = ff_add_q64(sum, m2.m[i][4]); op->lin.m[i][j] = sum; } } @@ -718,7 +718,7 @@ retry: /* Merge consecutive scaling operations */ if (next->op == SWS_OP_SCALE) { - op->scale.factor = av_mul_q64(op->scale.factor, next->scale.factor); + op->scale.factor = ff_mul_q64(op->scale.factor, next->scale.factor); ff_sws_op_list_remove_at(ops, n + 1, 1); goto retry; } diff --git a/libswscale/rational64.c b/libswscale/rational64.c index 998e46c572..6577a66613 100644 --- a/libswscale/rational64.c +++ b/libswscale/rational64.c @@ -105,7 +105,7 @@ done:; return res; } -int av_cmp_q64(AVRational64 a, AVRational64 b) +int ff_cmp_q64(AVRational64 a, AVRational64 b) { const av_int128 p = av_mul128(av_to128i(a.num), av_to128i(b.den)); const av_int128 q = av_mul128(av_to128i(b.num), av_to128i(a.den)); @@ -121,24 +121,24 @@ int av_cmp_q64(AVRational64 a, AVRational64 b) return INT_MIN; } -AVRational64 av_mul_q64(AVRational64 b, AVRational64 c) +AVRational64 ff_mul_q64(AVRational64 b, AVRational64 c) { return reduce64(av_mul128(av_to128i(b.num), av_to128i(c.num)), av_mul128(av_to128i(b.den), av_to128i(c.den))); } -AVRational64 av_div_q64(AVRational64 b, AVRational64 c) +AVRational64 ff_div_q64(AVRational64 b, AVRational64 c) { - return av_mul_q64(b, av_inv_q64(c)); + return ff_mul_q64(b, ff_inv_q64(c)); } -AVRational64 av_add_q64(AVRational64 b, AVRational64 c) { +AVRational64 ff_add_q64(AVRational64 b, AVRational64 c) { return reduce64(av_add128(av_mul128(av_to128i(b.num), av_to128i(c.den)), av_mul128(av_to128i(c.num), av_to128i(b.den))), av_mul128(av_to128i(b.den), av_to128i(c.den))); } -AVRational64 av_sub_q64(AVRational64 b, AVRational64 c) +AVRational64 ff_sub_q64(AVRational64 b, AVRational64 c) { return reduce64(av_sub128(av_mul128(av_to128i(b.num), av_to128i(c.den)), av_mul128(av_to128i(c.num), av_to128i(b.den))), diff --git a/libswscale/rational64.h b/libswscale/rational64.h index 03c952b0c2..edd0b958c0 100644 --- a/libswscale/rational64.h +++ b/libswscale/rational64.h @@ -61,7 +61,7 @@ typedef struct AVRational64 { * * @note The return value is not reduced. */ -static inline AVRational64 av_make_q64(int64_t num, int64_t den) +static inline AVRational64 ff_make_q64(int64_t num, int64_t den) { AVRational64 r = { num, den }; return r; @@ -79,7 +79,7 @@ static inline AVRational64 av_make_q64(int64_t num, int64_t den) * - -1 if `a < b` * - `INT_MIN` if one of the values is of the form `0 / 0` */ -int av_cmp_q64(AVRational64 a, AVRational64 b); +int ff_cmp_q64(AVRational64 a, AVRational64 b); /** * Convert an AVRational64 to a `double`. @@ -87,7 +87,7 @@ int av_cmp_q64(AVRational64 a, AVRational64 b); * @return `a` in floating-point form * @see av_d2q() */ -static inline double av_q2d_64(AVRational64 a){ +static inline double ff_q2d_64(AVRational64 a){ return a.num / (double) a.den; } @@ -97,7 +97,7 @@ static inline double av_q2d_64(AVRational64 a){ * @param c Second multiplicant * @return b*c */ -AVRational64 av_mul_q64(AVRational64 b, AVRational64 c) av_const; +AVRational64 ff_mul_q64(AVRational64 b, AVRational64 c) av_const; /** * Divide one 64-bit rational by another. @@ -105,7 +105,7 @@ AVRational64 av_mul_q64(AVRational64 b, AVRational64 c) av_const; * @param c Divisor * @return b/c */ -AVRational64 av_div_q64(AVRational64 b, AVRational64 c) av_const; +AVRational64 ff_div_q64(AVRational64 b, AVRational64 c) av_const; /** * Add two 64-bit rationals. @@ -113,7 +113,7 @@ AVRational64 av_div_q64(AVRational64 b, AVRational64 c) av_const; * @param c Second addend * @return b+c */ -AVRational64 av_add_q64(AVRational64 b, AVRational64 c) av_const; +AVRational64 ff_add_q64(AVRational64 b, AVRational64 c) av_const; /** * Subtract one 64-bit rational from another. @@ -121,14 +121,14 @@ AVRational64 av_add_q64(AVRational64 b, AVRational64 c) av_const; * @param c Subtrahend * @return b-c */ -AVRational64 av_sub_q64(AVRational64 b, AVRational64 c) av_const; +AVRational64 ff_sub_q64(AVRational64 b, AVRational64 c) av_const; /** * Invert a 64-bit rational. * @param q value * @return 1 / q */ -static av_always_inline AVRational64 av_inv_q64(AVRational64 q) +static av_always_inline AVRational64 ff_inv_q64(AVRational64 q) { AVRational64 r = { q.den, q.num }; return r; -- 2.52.0 >From bf9cb9f396c3f2afa4a1538e822495a7dae43217 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 24 Sep 2026 11:10:18 -0300 Subject: [PATCH 2/2] swscale/tests: move rational64 test from avutil Signed-off-by: James Almer <[email protected]> --- libavutil/tests/rational.c | 123 --------------------------- libswscale/Makefile | 1 + libswscale/tests/rational64.c | 155 ++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 123 deletions(-) create mode 100644 libswscale/tests/rational64.c diff --git a/libavutil/tests/rational.c b/libavutil/tests/rational.c index 69a8e896f7..2c9ca947fc 100644 --- a/libavutil/tests/rational.c +++ b/libavutil/tests/rational.c @@ -20,14 +20,12 @@ */ #include "libavutil/rational.c" -#include "libswscale/rational64.c" #include "libavutil/integer.h" #include "libavutil/intfloat.h" int main(void) { AVRational a,b,r; - AVRational64 a64,b64,r64; int i,j,k; static const int64_t numlist[] = { INT64_MIN, INT64_MIN+1, INT64_MAX, INT32_MIN, INT32_MAX, 1,0,-1, @@ -55,69 +53,6 @@ int main(void) } } - for (a64.num = -2; a64.num <= 2; a64.num++) { - for (a64.den = -2; a64.den <= 2; a64.den++) { - for (b64.num = -2; b64.num <= 2; b64.num++) { - for (b64.den = -2; b64.den <= 2; b64.den++) { - const double adbl = av_q2d_64(a64); - const double bdbl = av_q2d_64(b64); - const int c = av_cmp_q64(a64,b64); - const int d = adbl == bdbl ? 0 : - adbl > bdbl ? 1 : - adbl < bdbl ? -1 : INT_MIN; - - if (c != d) - av_log(NULL, AV_LOG_ERROR, "%lld/%lld %lld/%lld, %d != %d\n", - (long long) a64.num, (long long) a64.den, - (long long) b64.num, (long long) b64.den, c,d); - - // Check arithmetic result - if (a64.den && b64.den) { - double rdbl; - - r64 = av_add_q64(a64, b64); - rdbl = av_q2d_64(r64); - if (rdbl != adbl + bdbl) { - av_log(NULL, AV_LOG_ERROR, "%f + %f = %f != %f\n", - adbl, bdbl, rdbl, adbl + bdbl); - } - - r64 = av_mul_q64(a64, b64); - rdbl = av_q2d_64(r64); - if (rdbl != adbl * bdbl) { - av_log(NULL, AV_LOG_ERROR, "%f * %f = %f != %f\n", - adbl, bdbl, rdbl, adbl * bdbl); - } - } - - // Check addition round-trip - r64 = av_sub_q64(av_add_q64(a64, b64), b64); - if (b64.den && (r64.num*a64.den != a64.num*r64.den || - !r64.num != !a64.num || - !r64.den != !a64.den)) - { - av_log(NULL, AV_LOG_ERROR, "%lld/%lld != %lld/%lld\n", - (long long) a64.num, (long long) a64.den, - (long long) r64.num, (long long) r64.den); - } - - if (b64.num) { - // Check multiplication round-trip - r64 = av_div_q64(av_mul_q64(a64, b64), b64); - if (b64.den && (r64.num*a64.den != a64.num*r64.den || - !r64.num != !a64.num || - !r64.den != !a64.den)) - { - av_log(NULL, AV_LOG_ERROR, "%lld/%lld != %lld/%lld\n", - (long long) a64.num, (long long) a64.den, - (long long) r64.num, (long long) r64.den); - } - } - } - } - } - } - /* Check overflow behavior and edge cases */ static const AVRational unit_mul_q[][3] = { {{INT_MAX, 2}, { 2, 1}, { INT_MAX, 1}}, @@ -171,64 +106,6 @@ int main(void) } } - static const AVRational64 unit_mul_q64[][3] = { - {{INT64_MAX, 2}, { 2, 1}, { INT64_MAX, 1}}, - {{INT64_MAX, 2}, {-2, 1}, {-INT64_MAX, 1}}, - {{INT64_MAX, 2}, { 0, 1}, {0, 1}}, - {{INT64_MIN, 2}, { 2, 1}, {-INT64_MAX, 1}}, /* not INT64_MIN */ - {{INT64_MIN, 2}, {-2, 1}, { INT64_MAX, 1}}, - {{INT64_MIN, 2}, { 0, 1}, {0, 1}}, - {{INT64_MAX >> 8, 1}, {INT64_MAX >> 8, 1}, {INT64_MAX, 1}}, - {{1, INT64_MAX >> 8}, {1, INT64_MAX >> 8}, {0, 1}}, - {{1, 1}, {0, 0}, {0, 0}}, - {{0, 1}, {0, 0}, {0, 0}}, - }; - - for (i = 0; i < FF_ARRAY_ELEMS(unit_mul_q64); i++) { - for (int c = 0; c < 2; c++) { /* test commutativity */ - AVRational64 a = unit_mul_q64[i][c ? 1 : 0]; - AVRational64 b = unit_mul_q64[i][c ? 0 : 1]; - AVRational64 c = unit_mul_q64[i][2]; - AVRational64 r = av_mul_q64(a, b); - if (r.num != c.num || r.den != c.den) { - av_log(NULL, AV_LOG_ERROR, "%lld/%lld * %lld/%lld = %lld/%lld, expected %lld/%lld\n", - (long long) a.num, (long long) a.den, - (long long) b.num, (long long) b.den, - (long long) r.num, (long long) r.den, - (long long) c.num, (long long) c.den); - } - } - } - - static const AVRational64 unit_add_q64[][3] = { - {{INT64_MAX, 1}, { 2, 2}, { INT64_MAX, 1}}, - {{INT64_MAX, 1}, {-2, 2}, { INT64_MAX - 1, 1}}, - {{INT64_MAX, 1}, { 0, 2}, { INT64_MAX, 1}}, - {{INT64_MIN, 1}, { 2, 2}, {-INT64_MAX, 1}}, - {{INT64_MIN, 1}, {-2, 2}, {-INT64_MAX, 1}}, - {{INT64_MIN, 1}, { 0, 2}, {-INT64_MAX, 1}}, - {{INT64_MAX - 10, 1}, {20, 1}, { INT64_MAX, 1}}, - {{2, INT64_MAX}, {2, INT64_MAX}, {4, INT64_MAX}}, - {{1, 1}, {0, 0}, {0, 0}}, - {{0, 1}, {0, 0}, {0, 0}}, - }; - - for (i = 0; i < FF_ARRAY_ELEMS(unit_add_q64); i++) { - for (int c = 0; c < 2; c++) { /* test commutativity */ - AVRational64 a = unit_add_q64[i][c ? 1 : 0]; - AVRational64 b = unit_add_q64[i][c ? 0 : 1]; - AVRational64 c = unit_add_q64[i][2]; - AVRational64 r = av_add_q64(a, b); - if (r.num != c.num || r.den != c.den) { - av_log(NULL, AV_LOG_ERROR, "%lld/%lld + %lld/%lld = %lld/%lld, expected %lld/%lld\n", - (long long) a.num, (long long) a.den, - (long long) b.num, (long long) b.den, - (long long) r.num, (long long) r.den, - (long long) c.num, (long long) c.den); - } - } - } - for (i = 0; i < FF_ARRAY_ELEMS(numlist); i++) { int64_t a = numlist[i]; diff --git a/libswscale/Makefile b/libswscale/Makefile index b53b815309..f6dbed3c08 100644 --- a/libswscale/Makefile +++ b/libswscale/Makefile @@ -56,5 +56,6 @@ TESTPROGS = colorspace \ TESTPROGS-$(CONFIG_UNSTABLE) = sws_ops \ sws_ops_aarch64 \ + rational64 \ DEVPROGS-$(CONFIG_UNSTABLE) = uops_macros_gen \ diff --git a/libswscale/tests/rational64.c b/libswscale/tests/rational64.c new file mode 100644 index 0000000000..ed24b97094 --- /dev/null +++ b/libswscale/tests/rational64.c @@ -0,0 +1,155 @@ +/* + * rational numbers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libswscale/rational64.c" +#include "libavutil/integer.h" +#include "libavutil/intfloat.h" +#include "libavutil/log.h" +#include "libavutil/macros.h" + +int main(void) +{ + AVRational64 a64,b64,r64; + int i; + + for (a64.num = -2; a64.num <= 2; a64.num++) { + for (a64.den = -2; a64.den <= 2; a64.den++) { + for (b64.num = -2; b64.num <= 2; b64.num++) { + for (b64.den = -2; b64.den <= 2; b64.den++) { + const double adbl = ff_q2d_64(a64); + const double bdbl = ff_q2d_64(b64); + const int c = ff_cmp_q64(a64,b64); + const int d = adbl == bdbl ? 0 : + adbl > bdbl ? 1 : + adbl < bdbl ? -1 : INT_MIN; + + if (c != d) + av_log(NULL, AV_LOG_ERROR, "%lld/%lld %lld/%lld, %d != %d\n", + (long long) a64.num, (long long) a64.den, + (long long) b64.num, (long long) b64.den, c,d); + + // Check arithmetic result + if (a64.den && b64.den) { + double rdbl; + + r64 = ff_add_q64(a64, b64); + rdbl = ff_q2d_64(r64); + if (rdbl != adbl + bdbl) { + av_log(NULL, AV_LOG_ERROR, "%f + %f = %f != %f\n", + adbl, bdbl, rdbl, adbl + bdbl); + } + + r64 = ff_mul_q64(a64, b64); + rdbl = ff_q2d_64(r64); + if (rdbl != adbl * bdbl) { + av_log(NULL, AV_LOG_ERROR, "%f * %f = %f != %f\n", + adbl, bdbl, rdbl, adbl * bdbl); + } + } + + // Check addition round-trip + r64 = ff_sub_q64(ff_add_q64(a64, b64), b64); + if (b64.den && (r64.num*a64.den != a64.num*r64.den || + !r64.num != !a64.num || + !r64.den != !a64.den)) + { + av_log(NULL, AV_LOG_ERROR, "%lld/%lld != %lld/%lld\n", + (long long) a64.num, (long long) a64.den, + (long long) r64.num, (long long) r64.den); + } + + if (b64.num) { + // Check multiplication round-trip + r64 = ff_div_q64(ff_mul_q64(a64, b64), b64); + if (b64.den && (r64.num*a64.den != a64.num*r64.den || + !r64.num != !a64.num || + !r64.den != !a64.den)) + { + av_log(NULL, AV_LOG_ERROR, "%lld/%lld != %lld/%lld\n", + (long long) a64.num, (long long) a64.den, + (long long) r64.num, (long long) r64.den); + } + } + } + } + } + } + + /* Check overflow behavior and edge cases */ + static const AVRational64 unit_mul_q64[][3] = { + {{INT64_MAX, 2}, { 2, 1}, { INT64_MAX, 1}}, + {{INT64_MAX, 2}, {-2, 1}, {-INT64_MAX, 1}}, + {{INT64_MAX, 2}, { 0, 1}, {0, 1}}, + {{INT64_MIN, 2}, { 2, 1}, {-INT64_MAX, 1}}, /* not INT64_MIN */ + {{INT64_MIN, 2}, {-2, 1}, { INT64_MAX, 1}}, + {{INT64_MIN, 2}, { 0, 1}, {0, 1}}, + {{INT64_MAX >> 8, 1}, {INT64_MAX >> 8, 1}, {INT64_MAX, 1}}, + {{1, INT64_MAX >> 8}, {1, INT64_MAX >> 8}, {0, 1}}, + {{1, 1}, {0, 0}, {0, 0}}, + {{0, 1}, {0, 0}, {0, 0}}, + }; + + for (i = 0; i < FF_ARRAY_ELEMS(unit_mul_q64); i++) { + for (int c = 0; c < 2; c++) { /* test commutativity */ + AVRational64 a = unit_mul_q64[i][c ? 1 : 0]; + AVRational64 b = unit_mul_q64[i][c ? 0 : 1]; + AVRational64 c = unit_mul_q64[i][2]; + AVRational64 r = ff_mul_q64(a, b); + if (r.num != c.num || r.den != c.den) { + av_log(NULL, AV_LOG_ERROR, "%lld/%lld * %lld/%lld = %lld/%lld, expected %lld/%lld\n", + (long long) a.num, (long long) a.den, + (long long) b.num, (long long) b.den, + (long long) r.num, (long long) r.den, + (long long) c.num, (long long) c.den); + } + } + } + + static const AVRational64 unit_add_q64[][3] = { + {{INT64_MAX, 1}, { 2, 2}, { INT64_MAX, 1}}, + {{INT64_MAX, 1}, {-2, 2}, { INT64_MAX - 1, 1}}, + {{INT64_MAX, 1}, { 0, 2}, { INT64_MAX, 1}}, + {{INT64_MIN, 1}, { 2, 2}, {-INT64_MAX, 1}}, + {{INT64_MIN, 1}, {-2, 2}, {-INT64_MAX, 1}}, + {{INT64_MIN, 1}, { 0, 2}, {-INT64_MAX, 1}}, + {{INT64_MAX - 10, 1}, {20, 1}, { INT64_MAX, 1}}, + {{2, INT64_MAX}, {2, INT64_MAX}, {4, INT64_MAX}}, + {{1, 1}, {0, 0}, {0, 0}}, + {{0, 1}, {0, 0}, {0, 0}}, + }; + + for (i = 0; i < FF_ARRAY_ELEMS(unit_add_q64); i++) { + for (int c = 0; c < 2; c++) { /* test commutativity */ + AVRational64 a = unit_add_q64[i][c ? 1 : 0]; + AVRational64 b = unit_add_q64[i][c ? 0 : 1]; + AVRational64 c = unit_add_q64[i][2]; + AVRational64 r = ff_add_q64(a, b); + if (r.num != c.num || r.den != c.den) { + av_log(NULL, AV_LOG_ERROR, "%lld/%lld + %lld/%lld = %lld/%lld, expected %lld/%lld\n", + (long long) a.num, (long long) a.den, + (long long) b.num, (long long) b.den, + (long long) r.num, (long long) r.den, + (long long) c.num, (long long) c.den); + } + } + } + + return 0; +} -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
