This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 153a0ae7020edd9a81eb508ce275516ab6b89258 Author: Niklas Haas <[email protected]> AuthorDate: Fri Oct 2 20:53:14 2026 +0200 Commit: Niklas Haas <[email protected]> CommitDate: Tue Oct 20 21:33:01 2026 +0000 swscale/ops: add type[4] to SwsLinearOp Again, op->type is being replaced by more tightly scoped sources of truth. Generally, that means the output type of an op is implicit from its input type. However, SwsLinearOp represents a major challenge, because being an affine operation, it can express a constant offset with no corresponding input weight. As such, the *type* of such a constant output row is ambiguous. While in theory, we could hyper-specialize the type[] to only affect inputless constant rows, I think in practice it loses us little and buys us a lot of sanity to just pin the output type of each row explicitly. Signed-off-by: Niklas Haas <[email protected]> --- libswscale/format.c | 43 +++++++++++++++++++++++++------------------ libswscale/ops.h | 6 ++++++ libswscale/ops_optimizer.c | 12 +++++++++++- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/libswscale/format.c b/libswscale/format.c index cf37a5633d..a8988d00ba 100644 --- a/libswscale/format.c +++ b/libswscale/format.c @@ -1247,17 +1247,23 @@ static inline AVRational64 av_neg_q64(AVRational64 x) return (AVRational64) { -x.num, x.den }; } -static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete) +#define LINEAR_OP_DATA(TYPE, ...) ((SwsLinearOp) { \ + .type = { TYPE, TYPE, TYPE, TYPE }, \ + .m = { __VA_ARGS__ }, \ +}) + +static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, SwsPixelType type, + bool *incomplete) { const AVRational64 q0 = Q(0); const AVRational64 q1 = Q(1); - SwsLinearOp c = { .m = { + SwsLinearOp c = LINEAR_OP_DATA(type, { q1, q0, q0, q0, q0 }, { q0, q1, q0, q0, q0 }, { q0, q0, q1, q0, q0 }, { q0, q0, q0, q1, q0 }, - }}; + ); const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format); const int depth0 = desc->comp[0].depth; @@ -1311,9 +1317,9 @@ static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete) return c; } -static SwsLinearOp fmt_decode_range(const SwsFormat *fmt, bool *incomplete) +static SwsLinearOp fmt_decode_range(const SwsFormat *fmt, SwsPixelType type, bool *incomplete) { - SwsLinearOp c = fmt_encode_range(fmt, incomplete); + SwsLinearOp c = fmt_encode_range(fmt, type, incomplete); /* Invert main diagonal + offset: x = s * y + k ==> y = (x - k) / s */ for (int i = 0; i < 4; i++) { @@ -1483,16 +1489,17 @@ static int fmt_dither(SwsContext *ctx, SwsOpList *ops, #define Q64(x) ff_make_q64((x).num, (x).den) static inline SwsLinearOp -linear_mat3(const AVRational m00, const AVRational m01, const AVRational m02, +linear_mat3(const SwsPixelType type, + const AVRational m00, const AVRational m01, const AVRational m02, const AVRational m10, const AVRational m11, const AVRational m12, const AVRational m20, const AVRational m21, const AVRational m22) { - return (SwsLinearOp) {{ + return LINEAR_OP_DATA(type, { Q64(m00), Q64(m01), Q64(m02), Q(0), Q(0) }, { Q64(m10), Q64(m11), Q64(m12), Q(0), Q(0) }, { Q64(m20), Q64(m21), Q64(m22), Q(0), Q(0) }, { Q(0), Q(0), Q(0), Q(1), Q(0) }, - }}; + ); } /* Transform decoded pixel values to normalized RGB */ @@ -1518,7 +1525,7 @@ static int decode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, RET(ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, - .lin = fmt_decode_range(fmt, incomplete), + .lin = fmt_decode_range(fmt, type, incomplete), })); if (fmt->desc->flags & AV_PIX_FMT_FLAG_XYZ) @@ -1548,7 +1555,7 @@ static int decode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, return ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, - .lin = linear_mat3( + .lin = linear_mat3(type, q1, q0, m02, q1, m11, m12, q1, m21, q0 @@ -1560,7 +1567,7 @@ static int decode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, return ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, - .lin = linear_mat3( + .lin = linear_mat3(type, q1, av_make_q(-1, 1), av_make_q( 1, 1), q1, av_make_q( 1, 1), av_make_q( 0, 1), q1, av_make_q(-1, 1), av_make_q(-1, 1) @@ -1623,7 +1630,7 @@ static int encode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, RET(ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, - .lin = linear_mat3( + .lin = linear_mat3(type, c->cr, c->cg, c->cb, m10, m11, m20, m20, m21, m22 @@ -1636,7 +1643,7 @@ static int encode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, RET(ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, - .lin = linear_mat3( + .lin = linear_mat3(type, av_make_q( 1, 4), av_make_q(1, 2), av_make_q( 1, 4), av_make_q( 1, 2), av_make_q(0, 1), av_make_q(-1, 2), av_make_q(-1, 4), av_make_q(1, 2), av_make_q(-1, 4) @@ -1662,7 +1669,7 @@ static int encode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, RET(ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, - .lin = fmt_encode_range(dst, incomplete), + .lin = fmt_encode_range(dst, type, incomplete), })); if (!(dst->desc->flags & AV_PIX_FMT_FLAG_FLOAT)) { @@ -1786,12 +1793,12 @@ static int apply_lut3d(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, RET(ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, - .lin = {{ + .lin = LINEAR_OP_DATA(type, { domain, Q(0), Q(0), Q(0), Q(0) }, { Q(0), domain, Q(0), Q(0), Q(0) }, { Q(0), Q(0), domain, Q(0), Q(0) }, { Q(0), Q(0), Q(0), Q(1), Q(0) }, - }}, + ), })); RET(ff_sws_op_list_append(ops, &(SwsOp) { @@ -1819,12 +1826,12 @@ static int apply_lut3d(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, RET(ff_sws_op_list_append(ops, &(SwsOp) { .type = type, .op = SWS_OP_LINEAR, - .lin = {{ + .lin = LINEAR_OP_DATA(type, { inv, Q(0), Q(0), Q(0), Q(0) }, { Q(0), inv, Q(0), Q(0), Q(0) }, { Q(0), Q(0), inv, Q(0), Q(0) }, { Q(0), Q(0), Q(0), Q(1), Q(0) }, - }}, + ), })); return 0; diff --git a/libswscale/ops.h b/libswscale/ops.h index addfce7583..ec866f4914 100644 --- a/libswscale/ops.h +++ b/libswscale/ops.h @@ -170,6 +170,12 @@ typedef struct SwsDitherOp { } SwsDitherOp; typedef struct SwsLinearOp { + /** + * Pixel type per output component. This must match the type of incoming + * values, as determined by the weights matrix. + */ + SwsPixelType type[4]; + /** * Generalized 5x5 affine transformation: * [ Out.x ] = [ A B C D E ] diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c index a7ef19e086..0d7f2438df 100644 --- a/libswscale/ops_optimizer.c +++ b/libswscale/ops_optimizer.c @@ -182,10 +182,14 @@ static bool op_commute_filter(SwsOp *op, SwsOp *prev) switch (prev->op) { case SWS_OP_SWIZZLE: case SWS_OP_SCALE: - case SWS_OP_LINEAR: case SWS_OP_DITHER: prev->type = op->filter.type; return true; + case SWS_OP_LINEAR: + for (int i = 0; i < 4; i++) + prev->lin.type[i] = op->filter.type; + prev->type = op->filter.type; + return true; case SWS_OP_CONVERT: case SWS_OP_INVALID: case SWS_OP_READ: @@ -502,6 +506,9 @@ retry: const AVRational64 x = op->clear.value[j]; for (int i = 0; i < 4; i++) { + if (!next->lin.m[i][j].num) + continue; + av_assert0(next->lin.type[i] == op->type); const AVRational64 kx = ff_mul_q64(next->lin.m[i][j], x); next->lin.m[i][4] = ff_add_q64(next->lin.m[i][4], kx); next->lin.m[i][j] = Q(0); @@ -648,6 +655,7 @@ retry: const SwsLinearOp m1 = op->lin; const SwsLinearOp m2 = next->lin; for (int i = 0; i < 4; i++) { + op->lin.type[i] = m2.type[i]; for (int j = 0; j < 5; j++) { AVRational64 sum = Q(0); for (int k = 0; k < 4; k++) @@ -808,6 +816,8 @@ retry: ff_sws_pixel_type_is_int(next->convert.to) && op_result_is_exact(op)) { + for (int i = 0; i < 4; i++) + op->lin.type[i] = next->convert.to; op->type = next->convert.to; FFSWAP(SwsOp, *op, *next); goto retry; -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
