diff --git a/3rdparty/libpng/CHANGES b/3rdparty/libpng/CHANGES index 441b57ecf1..3f37f3f393 100644 --- a/3rdparty/libpng/CHANGES +++ b/3rdparty/libpng/CHANGES @@ -6196,6 +6196,39 @@ Version 1.6.43 [February 23, 2024] consistency verification and text linting. Added version consistency verification to pngtest.c also. +Version 1.6.44 [September 12, 2024] + Hardened calculations in chroma handling to prevent overflows, and + relaxed a constraint in cHRM validation to accomodate the standard + ACES AP1 set of color primaries. + (Contributed by John Bowler) + Removed the ASM implementation of ARM Neon optimizations and updated + the build accordingly. Only the remaining C implementation shall be + used from now on, thus ensuring the support of the PAC/BTI security + features on ARM64. + (Contributed by Ross Burton and John Bowler) + Fixed the pickup of the PNG_HARDWARE_OPTIMIZATIONS option in the + CMake build on FreeBSD/amd64. This is an important performance fix + on this platform. + Applied various fixes and improvements to the CMake build. + (Contributed by Eric Riff, Benjamin Buch and Erik Scholz) + Added fuzzing targets for the simplified read API. + (Contributed by Mikhail Khachayants) + Fixed a build error involving pngtest.c under a custom config. + This was a regression introduced in a code cleanup in libpng-1.6.43. + (Contributed by Ben Wagner) + Fixed and improved the config files for AppVeyor CI and Travis CI. + +Version 1.6.45 [January 7, 2025] + Added support for the cICP chunk. + (Contributed by Lucas Chollet and John Bowler) + Adjusted and improved various checks in colorspace calculations. + (Contributed by John Bowler) + Rearranged the write order of colorspace chunks for better conformance + with the PNG v3 draft specification. + (Contributed by John Bowler) + Raised the minimum required CMake version from 3.6 to 3.14. + Forked off a development branch for libpng version 1.8. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net. Subscription is required; visit https://lists.sourceforge.net/lists/listinfo/png-mng-implement diff --git a/3rdparty/libpng/LICENSE b/3rdparty/libpng/LICENSE index 25f298f0fc..ea6df986cb 100644 --- a/3rdparty/libpng/LICENSE +++ b/3rdparty/libpng/LICENSE @@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE PNG Reference Library License version 2 --------------------------------------- - * Copyright (c) 1995-2024 The PNG Reference Library Authors. - * Copyright (c) 2018-2024 Cosmin Truta. + * Copyright (c) 1995-2025 The PNG Reference Library Authors. + * Copyright (c) 2018-2025 Cosmin Truta. * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * Copyright (c) 1996-1997 Andreas Dilger. * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. diff --git a/3rdparty/libpng/README b/3rdparty/libpng/README index a6ca3ae9f9..1f73eb58cf 100644 --- a/3rdparty/libpng/README +++ b/3rdparty/libpng/README @@ -1,4 +1,4 @@ -README for libpng version 1.6.43 +README for libpng version 1.6.45 ================================ See the note about version numbers near the top of `png.h`. @@ -157,8 +157,6 @@ Files included in this distribution "PNG: The Definitive Guide" by Greg Roelofs, O'Reilly, 1999 libtests/ => Test programs - oss-fuzz/ => Files used by the OSS-Fuzz project for fuzz-testing - libpng pngexif/ => Program to inspect the EXIF information in PNG files pngminim/ => Minimal decoder, encoder, and progressive decoder programs demonstrating the use of pngusr.dfa diff --git a/3rdparty/libpng/arm/arm_init.c b/3rdparty/libpng/arm/arm_init.c index 84d05556f8..50376081a3 100644 --- a/3rdparty/libpng/arm/arm_init.c +++ b/3rdparty/libpng/arm/arm_init.c @@ -1,4 +1,3 @@ - /* arm_init.c - NEON optimised filter functions * * Copyright (c) 2018-2022 Cosmin Truta diff --git a/3rdparty/libpng/arm/filter_neon.S b/3rdparty/libpng/arm/filter_neon.S index 2308aad13e..0cbd372cb1 100644 --- a/3rdparty/libpng/arm/filter_neon.S +++ b/3rdparty/libpng/arm/filter_neon.S @@ -1,253 +1,60 @@ - -/* filter_neon.S - NEON optimised filter functions +/* filter_neon.S - placeholder file * - * Copyright (c) 2018 Cosmin Truta - * Copyright (c) 2014,2017 Glenn Randers-Pehrson - * Written by Mans Rullgard, 2011. + * Copyright (c) 2024 Cosmin Truta * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ +/* IMPORTANT NOTE: + * + * Historically, the hand-coded assembler implementation of Neon optimizations + * in this module had not been in sync with the intrinsics-based implementation + * in filter_neon_intrinsics.c and palette_neon_intrinsics.c, at least since + * the introduction of riffled palette optimizations. Moreover, the assembler + * code used to work on 32-bit ARM only, and it caused problems, even if empty, + * on 64-bit ARM. + * + * All references to this module from our internal build scripts and projects + * have been removed. + * + * For the external projects that might still expect this module to be present, + * we leave this stub in place, for the remaining lifetime of libpng-1.6.x. + * Everything should continue to function normally, as long as there are no + * deliberate attempts to use the old hand-made assembler code. A build error + * will be raised otherwise. + */ + /* This is required to get the symbol renames, which are #defines, and the * definitions (or not) of PNG_ARM_NEON_OPT and PNG_ARM_NEON_IMPLEMENTATION. */ #define PNG_VERSION_INFO_ONLY #include "../pngpriv.h" -#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__ELF__) -.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */ -#endif - #ifdef PNG_READ_SUPPORTED - -/* Assembler NEON support - only works for 32-bit ARM (i.e. it does not work for - * ARM64). The code in arm/filter_neon_intrinsics.c supports ARM64, however it - * only works if -mfpu=neon is specified on the GCC command line. See pngpriv.h - * for the logic which sets PNG_USE_ARM_NEON_ASM: - */ #if PNG_ARM_NEON_IMPLEMENTATION == 2 /* hand-coded assembler */ - #if PNG_ARM_NEON_OPT > 0 -#ifdef __ELF__ -# define ELF +#if defined(__clang__) +#define GNUC_VERSION 0 /* not gcc, although it might pretend to be */ +#elif defined(__GNUC__) +#define GNUC_MAJOR (__GNUC__ + 0) +#define GNUC_MINOR (__GNUC_MINOR__ + 0) +#define GNUC_PATCHLEVEL (__GNUC_PATCHLEVEL__ + 0) +#define GNUC_VERSION (GNUC_MAJOR * 10000 + GNUC_MINOR * 100 + GNUC_PATCHLEVEL) #else -# define ELF @ +#define GNUC_VERSION 0 /* not gcc */ #endif - .arch armv7-a - .fpu neon +#if (GNUC_VERSION > 0) && (GNUC_VERSION < 40300) +#error "PNG_ARM_NEON is not supported with gcc versions earlier than 4.3.0" +#elif GNUC_VERSION == 40504 +#error "PNG_ARM_NEON is not supported with gcc version 4.5.4" +#else +#error "Please use 'arm/*_neon_intrinsics.c' for PNG_ARM_NEON support" +#endif -.macro func name, export=0 - .macro endfunc -ELF .size \name, . - \name - .endfunc - .purgem endfunc - .endm - .text - - /* Explicitly specifying alignment here because some versions of - * GAS don't align code correctly. This is harmless in correctly - * written versions of GAS. - */ - .align 2 - - .if \export - .global \name - .endif -ELF .type \name, STT_FUNC - .func \name -\name: -.endm - -func png_read_filter_row_sub4_neon, export=1 - ldr r3, [r0, #4] @ rowbytes - vmov.i8 d3, #0 -1: - vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128] - vadd.u8 d0, d3, d4 - vadd.u8 d1, d0, d5 - vadd.u8 d2, d1, d6 - vadd.u8 d3, d2, d7 - vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]! - subs r3, r3, #16 - bgt 1b - - bx lr -endfunc - -func png_read_filter_row_sub3_neon, export=1 - ldr r3, [r0, #4] @ rowbytes - vmov.i8 d3, #0 - mov r0, r1 - mov r2, #3 - mov r12, #12 - vld1.8 {q11}, [r0], r12 -1: - vext.8 d5, d22, d23, #3 - vadd.u8 d0, d3, d22 - vext.8 d6, d22, d23, #6 - vadd.u8 d1, d0, d5 - vext.8 d7, d23, d23, #1 - vld1.8 {q11}, [r0], r12 - vst1.32 {d0[0]}, [r1,:32], r2 - vadd.u8 d2, d1, d6 - vst1.32 {d1[0]}, [r1], r2 - vadd.u8 d3, d2, d7 - vst1.32 {d2[0]}, [r1], r2 - vst1.32 {d3[0]}, [r1], r2 - subs r3, r3, #12 - bgt 1b - - bx lr -endfunc - -func png_read_filter_row_up_neon, export=1 - ldr r3, [r0, #4] @ rowbytes -1: - vld1.8 {q0}, [r1,:128] - vld1.8 {q1}, [r2,:128]! - vadd.u8 q0, q0, q1 - vst1.8 {q0}, [r1,:128]! - subs r3, r3, #16 - bgt 1b - - bx lr -endfunc - -func png_read_filter_row_avg4_neon, export=1 - ldr r12, [r0, #4] @ rowbytes - vmov.i8 d3, #0 -1: - vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128] - vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]! - vhadd.u8 d0, d3, d16 - vadd.u8 d0, d0, d4 - vhadd.u8 d1, d0, d17 - vadd.u8 d1, d1, d5 - vhadd.u8 d2, d1, d18 - vadd.u8 d2, d2, d6 - vhadd.u8 d3, d2, d19 - vadd.u8 d3, d3, d7 - vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]! - subs r12, r12, #16 - bgt 1b - - bx lr -endfunc - -func png_read_filter_row_avg3_neon, export=1 - push {r4,lr} - ldr r12, [r0, #4] @ rowbytes - vmov.i8 d3, #0 - mov r0, r1 - mov r4, #3 - mov lr, #12 - vld1.8 {q11}, [r0], lr -1: - vld1.8 {q10}, [r2], lr - vext.8 d5, d22, d23, #3 - vhadd.u8 d0, d3, d20 - vext.8 d17, d20, d21, #3 - vadd.u8 d0, d0, d22 - vext.8 d6, d22, d23, #6 - vhadd.u8 d1, d0, d17 - vext.8 d18, d20, d21, #6 - vadd.u8 d1, d1, d5 - vext.8 d7, d23, d23, #1 - vld1.8 {q11}, [r0], lr - vst1.32 {d0[0]}, [r1,:32], r4 - vhadd.u8 d2, d1, d18 - vst1.32 {d1[0]}, [r1], r4 - vext.8 d19, d21, d21, #1 - vadd.u8 d2, d2, d6 - vhadd.u8 d3, d2, d19 - vst1.32 {d2[0]}, [r1], r4 - vadd.u8 d3, d3, d7 - vst1.32 {d3[0]}, [r1], r4 - subs r12, r12, #12 - bgt 1b - - pop {r4,pc} -endfunc - -.macro paeth rx, ra, rb, rc - vaddl.u8 q12, \ra, \rb @ a + b - vaddl.u8 q15, \rc, \rc @ 2*c - vabdl.u8 q13, \rb, \rc @ pa - vabdl.u8 q14, \ra, \rc @ pb - vabd.u16 q15, q12, q15 @ pc - vcle.u16 q12, q13, q14 @ pa <= pb - vcle.u16 q13, q13, q15 @ pa <= pc - vcle.u16 q14, q14, q15 @ pb <= pc - vand q12, q12, q13 @ pa <= pb && pa <= pc - vmovn.u16 d28, q14 - vmovn.u16 \rx, q12 - vbsl d28, \rb, \rc - vbsl \rx, \ra, d28 -.endm - -func png_read_filter_row_paeth4_neon, export=1 - ldr r12, [r0, #4] @ rowbytes - vmov.i8 d3, #0 - vmov.i8 d20, #0 -1: - vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128] - vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]! - paeth d0, d3, d16, d20 - vadd.u8 d0, d0, d4 - paeth d1, d0, d17, d16 - vadd.u8 d1, d1, d5 - paeth d2, d1, d18, d17 - vadd.u8 d2, d2, d6 - paeth d3, d2, d19, d18 - vmov d20, d19 - vadd.u8 d3, d3, d7 - vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]! - subs r12, r12, #16 - bgt 1b - - bx lr -endfunc - -func png_read_filter_row_paeth3_neon, export=1 - push {r4,lr} - ldr r12, [r0, #4] @ rowbytes - vmov.i8 d3, #0 - vmov.i8 d4, #0 - mov r0, r1 - mov r4, #3 - mov lr, #12 - vld1.8 {q11}, [r0], lr -1: - vld1.8 {q10}, [r2], lr - paeth d0, d3, d20, d4 - vext.8 d5, d22, d23, #3 - vadd.u8 d0, d0, d22 - vext.8 d17, d20, d21, #3 - paeth d1, d0, d17, d20 - vst1.32 {d0[0]}, [r1,:32], r4 - vext.8 d6, d22, d23, #6 - vadd.u8 d1, d1, d5 - vext.8 d18, d20, d21, #6 - paeth d2, d1, d18, d17 - vext.8 d7, d23, d23, #1 - vld1.8 {q11}, [r0], lr - vst1.32 {d1[0]}, [r1], r4 - vadd.u8 d2, d2, d6 - vext.8 d19, d21, d21, #1 - paeth d3, d2, d19, d18 - vst1.32 {d2[0]}, [r1], r4 - vmov d4, d19 - vadd.u8 d3, d3, d7 - vst1.32 {d3[0]}, [r1], r4 - subs r12, r12, #12 - bgt 1b - - pop {r4,pc} -endfunc #endif /* PNG_ARM_NEON_OPT > 0 */ -#endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 (assembler) */ +#endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 */ #endif /* READ */ diff --git a/3rdparty/libpng/arm/filter_neon_intrinsics.c b/3rdparty/libpng/arm/filter_neon_intrinsics.c index 4466d48b20..7c3e0da4d8 100644 --- a/3rdparty/libpng/arm/filter_neon_intrinsics.c +++ b/3rdparty/libpng/arm/filter_neon_intrinsics.c @@ -1,4 +1,3 @@ - /* filter_neon_intrinsics.c - NEON optimised filter functions * * Copyright (c) 2018 Cosmin Truta diff --git a/3rdparty/libpng/arm/palette_neon_intrinsics.c b/3rdparty/libpng/arm/palette_neon_intrinsics.c index 92c7d6f9f6..3068e9b6e6 100644 --- a/3rdparty/libpng/arm/palette_neon_intrinsics.c +++ b/3rdparty/libpng/arm/palette_neon_intrinsics.c @@ -1,4 +1,3 @@ - /* palette_neon_intrinsics.c - NEON optimised palette expansion functions * * Copyright (c) 2018-2019 Cosmin Truta @@ -64,7 +63,7 @@ png_do_expand_palette_rgba8_neon(png_structrp png_ptr, png_row_infop row_info, { png_uint_32 row_width = row_info->width; const png_uint_32 *riffled_palette = - (const png_uint_32 *)png_ptr->riffled_palette; + png_aligncastconst(png_const_uint_32p, png_ptr->riffled_palette); const png_uint_32 pixels_per_chunk = 4; png_uint_32 i; diff --git a/3rdparty/libpng/intel/filter_sse2_intrinsics.c b/3rdparty/libpng/intel/filter_sse2_intrinsics.c index d3c0fe9e2d..2993f650b7 100644 --- a/3rdparty/libpng/intel/filter_sse2_intrinsics.c +++ b/3rdparty/libpng/intel/filter_sse2_intrinsics.c @@ -1,4 +1,3 @@ - /* filter_sse2_intrinsics.c - SSE2 optimized filter functions * * Copyright (c) 2018 Cosmin Truta diff --git a/3rdparty/libpng/intel/intel_init.c b/3rdparty/libpng/intel/intel_init.c index 2f8168b7c4..9e4610d25b 100644 --- a/3rdparty/libpng/intel/intel_init.c +++ b/3rdparty/libpng/intel/intel_init.c @@ -1,4 +1,3 @@ - /* intel_init.c - SSE2 optimized filter functions * * Copyright (c) 2018 Cosmin Truta diff --git a/3rdparty/libpng/mips/filter_msa_intrinsics.c b/3rdparty/libpng/mips/filter_msa_intrinsics.c index 1b734f4d9a..a294f55130 100644 --- a/3rdparty/libpng/mips/filter_msa_intrinsics.c +++ b/3rdparty/libpng/mips/filter_msa_intrinsics.c @@ -1,4 +1,3 @@ - /* filter_msa_intrinsics.c - MSA optimised filter functions * * Copyright (c) 2018-2024 Cosmin Truta @@ -47,7 +46,7 @@ uint8_t *psrc_lw_m = (uint8_t *) (psrc); \ uint32_t val_m; \ \ - asm volatile ( \ + __asm__ volatile ( \ "lw %[val_m], %[psrc_lw_m] \n\t" \ \ : [val_m] "=r" (val_m) \ @@ -62,7 +61,7 @@ uint8_t *pdst_sh_m = (uint8_t *) (pdst); \ uint16_t val_m = (val); \ \ - asm volatile ( \ + __asm__ volatile ( \ "sh %[val_m], %[pdst_sh_m] \n\t" \ \ : [pdst_sh_m] "=m" (*pdst_sh_m) \ @@ -75,7 +74,7 @@ uint8_t *pdst_sw_m = (uint8_t *) (pdst); \ uint32_t val_m = (val); \ \ - asm volatile ( \ + __asm__ volatile ( \ "sw %[val_m], %[pdst_sw_m] \n\t" \ \ : [pdst_sw_m] "=m" (*pdst_sw_m) \ @@ -83,20 +82,20 @@ ); \ } - #if (__mips == 64) + #if __mips == 64 #define SD(val, pdst) \ { \ uint8_t *pdst_sd_m = (uint8_t *) (pdst); \ uint64_t val_m = (val); \ \ - asm volatile ( \ + __asm__ volatile ( \ "sd %[val_m], %[pdst_sd_m] \n\t" \ \ : [pdst_sd_m] "=m" (*pdst_sd_m) \ : [val_m] "r" (val_m) \ ); \ } - #else + #else #define SD(val, pdst) \ { \ uint8_t *pdst_sd_m = (uint8_t *) (pdst); \ @@ -108,17 +107,17 @@ SW(val0_m, pdst_sd_m); \ SW(val1_m, pdst_sd_m + 4); \ } - #endif + #endif /* __mips == 64 */ #else #define MSA_SRLI_B(a, b) (a >> b) -#if (__mips_isa_rev >= 6) +#if __mips_isa_rev >= 6 #define LW(psrc) \ ( { \ uint8_t *psrc_lw_m = (uint8_t *) (psrc); \ uint32_t val_m; \ \ - asm volatile ( \ + __asm__ volatile ( \ "lw %[val_m], %[psrc_lw_m] \n\t" \ \ : [val_m] "=r" (val_m) \ @@ -133,7 +132,7 @@ uint8_t *pdst_sh_m = (uint8_t *) (pdst); \ uint16_t val_m = (val); \ \ - asm volatile ( \ + __asm__ volatile ( \ "sh %[val_m], %[pdst_sh_m] \n\t" \ \ : [pdst_sh_m] "=m" (*pdst_sh_m) \ @@ -146,7 +145,7 @@ uint8_t *pdst_sw_m = (uint8_t *) (pdst); \ uint32_t val_m = (val); \ \ - asm volatile ( \ + __asm__ volatile ( \ "sw %[val_m], %[pdst_sw_m] \n\t" \ \ : [pdst_sw_m] "=m" (*pdst_sw_m) \ @@ -154,20 +153,20 @@ ); \ } - #if (__mips == 64) + #if __mips == 64 #define SD(val, pdst) \ { \ uint8_t *pdst_sd_m = (uint8_t *) (pdst); \ uint64_t val_m = (val); \ \ - asm volatile ( \ + __asm__ volatile ( \ "sd %[val_m], %[pdst_sd_m] \n\t" \ \ : [pdst_sd_m] "=m" (*pdst_sd_m) \ : [val_m] "r" (val_m) \ ); \ } - #else + #else #define SD(val, pdst) \ { \ uint8_t *pdst_sd_m = (uint8_t *) (pdst); \ @@ -179,14 +178,14 @@ SW(val0_m, pdst_sd_m); \ SW(val1_m, pdst_sd_m + 4); \ } - #endif -#else // !(__mips_isa_rev >= 6) + #endif /* __mips == 64 */ +#else #define LW(psrc) \ ( { \ uint8_t *psrc_lw_m = (uint8_t *) (psrc); \ uint32_t val_m; \ \ - asm volatile ( \ + __asm__ volatile ( \ "ulw %[val_m], %[psrc_lw_m] \n\t" \ \ : [val_m] "=r" (val_m) \ @@ -201,7 +200,7 @@ uint8_t *pdst_sh_m = (uint8_t *) (pdst); \ uint16_t val_m = (val); \ \ - asm volatile ( \ + __asm__ volatile ( \ "ush %[val_m], %[pdst_sh_m] \n\t" \ \ : [pdst_sh_m] "=m" (*pdst_sh_m) \ @@ -214,7 +213,7 @@ uint8_t *pdst_sw_m = (uint8_t *) (pdst); \ uint32_t val_m = (val); \ \ - asm volatile ( \ + __asm__ volatile ( \ "usw %[val_m], %[pdst_sw_m] \n\t" \ \ : [pdst_sw_m] "=m" (*pdst_sw_m) \ @@ -222,7 +221,7 @@ ); \ } - #define SD(val, pdst) \ + #define SD(val, pdst) \ { \ uint8_t *pdst_sd_m = (uint8_t *) (pdst); \ uint32_t val0_m, val1_m; \ @@ -238,14 +237,14 @@ { \ uint8_t *pdst_m = (uint8_t *) (pdst); \ \ - asm volatile ( \ + __asm__ volatile ( \ "usw $0, %[pdst_m] \n\t" \ \ : [pdst_m] "=m" (*pdst_m) \ : \ ); \ } -#endif // (__mips_isa_rev >= 6) +#endif /* __mips_isa_rev >= 6 */ #endif #define LD_B(RTYPE, psrc) *((RTYPE *) (psrc)) diff --git a/3rdparty/libpng/mips/mips_init.c b/3rdparty/libpng/mips/mips_init.c index 5c6fa1dbf1..143f0a3714 100644 --- a/3rdparty/libpng/mips/mips_init.c +++ b/3rdparty/libpng/mips/mips_init.c @@ -1,4 +1,3 @@ - /* mips_init.c - MSA optimised filter functions * * Copyright (c) 2018-2024 Cosmin Truta diff --git a/3rdparty/libpng/png.c b/3rdparty/libpng/png.c index 9ed3157009..466af7d992 100644 --- a/3rdparty/libpng/png.c +++ b/3rdparty/libpng/png.c @@ -1,7 +1,6 @@ - /* png.c - location for general purpose libpng functions * - * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -14,7 +13,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_43 Your_png_h_is_not_version_1_6_43; +typedef png_libpng_version_1_6_45 Your_png_h_is_not_version_1_6_45; /* Tells libpng that we have already handled the first "num_bytes" bytes * of the PNG file signature. If the PNG data is embedded into another @@ -794,8 +793,8 @@ png_get_copyright(png_const_structrp png_ptr) return PNG_STRING_COPYRIGHT #else return PNG_STRING_NEWLINE \ - "libpng version 1.6.43" PNG_STRING_NEWLINE \ - "Copyright (c) 2018-2024 Cosmin Truta" PNG_STRING_NEWLINE \ + "libpng version 1.6.45" PNG_STRING_NEWLINE \ + "Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \ PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ @@ -1203,6 +1202,68 @@ png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) #endif /* GAMMA */ #ifdef PNG_COLORSPACE_SUPPORTED +static png_int_32 +png_fp_add(png_int_32 addend0, png_int_32 addend1, int *error) +{ + /* Safely add two fixed point values setting an error flag and returning 0.5 + * on overflow. + * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore + * relying on addition of two positive values producing a negative one is not + * safe. + */ + if (addend0 > 0) + { + if (0x7fffffff - addend0 >= addend1) + return addend0+addend1; + } + else if (addend0 < 0) + { + if (-0x7fffffff - addend0 <= addend1) + return addend0+addend1; + } + else + return addend1; + + *error = 1; + return PNG_FP_1/2; +} + +static png_int_32 +png_fp_sub(png_int_32 addend0, png_int_32 addend1, int *error) +{ + /* As above but calculate addend0-addend1. */ + if (addend1 > 0) + { + if (-0x7fffffff + addend1 <= addend0) + return addend0-addend1; + } + else if (addend1 < 0) + { + if (0x7fffffff + addend1 >= addend0) + return addend0-addend1; + } + else + return addend0; + + *error = 1; + return PNG_FP_1/2; +} + +static int +png_safe_add(png_int_32 *addend0_and_result, png_int_32 addend1, + png_int_32 addend2) +{ + /* Safely add three integers. Returns 0 on success, 1 on overflow. Does not + * set the result on overflow. + */ + int error = 0; + int result = png_fp_add(*addend0_and_result, + png_fp_add(addend1, addend2, &error), + &error); + if (!error) *addend0_and_result = result; + return error; +} + /* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for * cHRM, as opposed to using chromaticities. These internal APIs return * non-zero on a parameter error. The X, Y and Z values are required to be @@ -1211,38 +1272,60 @@ png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) static int png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) { - png_int_32 d, dwhite, whiteX, whiteY; + png_int_32 d, dred, dgreen, dblue, dwhite, whiteX, whiteY; - d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z; - if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0) + /* 'd' in each of the blocks below is just X+Y+Z for each component, + * x, y and z are X,Y,Z/(X+Y+Z). + */ + d = XYZ->red_X; + if (png_safe_add(&d, XYZ->red_Y, XYZ->red_Z)) return 1; - if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0) + dred = d; + if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, dred) == 0) + return 1; + if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, dred) == 0) + return 1; + + d = XYZ->green_X; + if (png_safe_add(&d, XYZ->green_Y, XYZ->green_Z)) + return 1; + dgreen = d; + if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, dgreen) == 0) + return 1; + if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, dgreen) == 0) + return 1; + + d = XYZ->blue_X; + if (png_safe_add(&d, XYZ->blue_Y, XYZ->blue_Z)) + return 1; + dblue = d; + if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, dblue) == 0) + return 1; + if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, dblue) == 0) + return 1; + + /* The reference white is simply the sum of the end-point (X,Y,Z) vectors so + * the fillowing calculates (X+Y+Z) of the reference white (media white, + * encoding white) itself: + */ + d = dblue; + if (png_safe_add(&d, dred, dgreen)) return 1; dwhite = d; - whiteX = XYZ->red_X; - whiteY = XYZ->red_Y; - d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z; - if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0) - return 1; - if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0) - return 1; - dwhite += d; - whiteX += XYZ->green_X; - whiteY += XYZ->green_Y; - - d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z; - if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0) - return 1; - if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0) - return 1; - dwhite += d; - whiteX += XYZ->blue_X; - whiteY += XYZ->blue_Y; - - /* The reference white is simply the sum of the end-point (X,Y,Z) vectors, - * thus: + /* Find the white X,Y values from the sum of the red, green and blue X,Y + * values. */ + d = XYZ->red_X; + if (png_safe_add(&d, XYZ->green_X, XYZ->blue_X)) + return 1; + whiteX = d; + + d = XYZ->red_Y; + if (png_safe_add(&d, XYZ->green_Y, XYZ->blue_Y)) + return 1; + whiteY = d; + if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0) return 1; if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0) @@ -1261,15 +1344,24 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) * have end points with 0 tristimulus values (these are impossible end * points, but they are used to cover the possible colors). We check * xy->whitey against 5, not 0, to avoid a possible integer overflow. + * + * The limits here will *not* accept ACES AP0, where bluey is -7700 + * (-0.0770) because the PNG spec itself requires the xy values to be + * unsigned. whitey is also required to be 5 or more to avoid overflow. + * + * Instead the upper limits have been relaxed to accomodate ACES AP1 where + * redz ends up as -600 (-0.006). ProPhotoRGB was already "in range." + * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy. */ - if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1; - if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1; - if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1; - if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1; - if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1; - if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1; - if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1; - if (xy->whitey < 5 || xy->whitey > PNG_FP_1-xy->whitex) return 1; + const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10); + if (xy->redx < 0 || xy->redx > fpLimit) return 1; + if (xy->redy < 0 || xy->redy > fpLimit-xy->redx) return 1; + if (xy->greenx < 0 || xy->greenx > fpLimit) return 1; + if (xy->greeny < 0 || xy->greeny > fpLimit-xy->greenx) return 1; + if (xy->bluex < 0 || xy->bluex > fpLimit) return 1; + if (xy->bluey < 0 || xy->bluey > fpLimit-xy->bluex) return 1; + if (xy->whitex < 0 || xy->whitex > fpLimit) return 1; + if (xy->whitey < 5 || xy->whitey > fpLimit-xy->whitex) return 1; /* The reverse calculation is more difficult because the original tristimulus * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 @@ -1414,18 +1506,23 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) * * Accuracy: - * The input values have 5 decimal digits of accuracy. The values are all in - * the range 0 < value < 1, so simple products are in the same range but may - * need up to 10 decimal digits to preserve the original precision and avoid - * underflow. Because we are using a 32-bit signed representation we cannot - * match this; the best is a little over 9 decimal digits, less than 10. + * The input values have 5 decimal digits of accuracy. + * + * In the previous implementation the values were all in the range 0 < value + * < 1, so simple products are in the same range but may need up to 10 + * decimal digits to preserve the original precision and avoid underflow. + * Because we are using a 32-bit signed representation we cannot match this; + * the best is a little over 9 decimal digits, less than 10. + * + * This range has now been extended to allow values up to 1.1, or 110,000 in + * fixed point. * * The approach used here is to preserve the maximum precision within the * signed representation. Because the red-scale calculation above uses the - * difference between two products of values that must be in the range -1..+1 - * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The - * factor is irrelevant in the calculation because it is applied to both - * numerator and denominator. + * difference between two products of values that must be in the range + * -1.1..+1.1 it is sufficient to divide the product by 8; + * ceil(121,000/32767*2). The factor is irrelevant in the calculation + * because it is applied to both numerator and denominator. * * Note that the values of the differences of the products of the * chromaticities in the above equations tend to be small, for example for @@ -1447,49 +1544,61 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) * Adobe Wide Gamut RGB * 0.258728243040113 0.724682314948566 0.016589442011321 */ - /* By the argument, above overflow should be impossible here. The return - * value of 2 indicates an internal error to the caller. + int error = 0; + + /* By the argument above overflow should be impossible here, however the + * code now simply returns a failure code. The xy subtracts in the arguments + * to png_muldiv are *not* checked for overflow because the checks at the + * start guarantee they are in the range 0..110000 and png_fixed_point is a + * 32-bit signed number. */ - if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0) - return 2; - if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0) - return 2; - denominator = left - right; + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 8) == 0) + return 1; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 8) == 0) + return 1; + denominator = png_fp_sub(left, right, &error); + if (error) return 1; /* Now find the red numerator. */ - if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) - return 2; - if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0) - return 2; + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 8) == 0) + return 1; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 8) == 0) + return 1; /* Overflow is possible here and it indicates an extreme set of PNG cHRM * chunk values. This calculation actually returns the reciprocal of the * scale value because this allows us to delay the multiplication of white-y * into the denominator, which tends to produce a small number. */ - if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 || + if (png_muldiv(&red_inverse, xy->whitey, denominator, + png_fp_sub(left, right, &error)) == 0 || error || red_inverse <= xy->whitey /* r+g+b scales = white scale */) return 1; /* Similarly for green_inverse: */ - if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0) - return 2; - if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) - return 2; - if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 || + if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 8) == 0) + return 1; + if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 8) == 0) + return 1; + if (png_muldiv(&green_inverse, xy->whitey, denominator, + png_fp_sub(left, right, &error)) == 0 || error || green_inverse <= xy->whitey) return 1; /* And the blue scale, the checks above guarantee this can't overflow but it * can still produce 0 for extreme cHRM values. */ - blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) - - png_reciprocal(green_inverse); - if (blue_scale <= 0) + blue_scale = png_fp_sub(png_fp_sub(png_reciprocal(xy->whitey), + png_reciprocal(red_inverse), &error), + png_reciprocal(green_inverse), &error); + if (error || blue_scale <= 0) return 1; - /* And fill in the png_XYZ: */ + /* And fill in the png_XYZ. Again the subtracts are safe because of the + * checks on the xy values at the start (the subtracts just calculate the + * corresponding z values.) + */ if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0) return 1; if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0) @@ -1520,25 +1629,14 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) static int png_XYZ_normalize(png_XYZ *XYZ) { - png_int_32 Y; + png_int_32 Y, Ytemp; - if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 || - XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 || - XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0) + /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. */ + Ytemp = XYZ->red_Y; + if (png_safe_add(&Ytemp, XYZ->green_Y, XYZ->blue_Y)) return 1; - /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. - * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore - * relying on addition of two positive values producing a negative one is not - * safe. - */ - Y = XYZ->red_Y; - if (0x7fffffff - Y < XYZ->green_X) - return 1; - Y += XYZ->green_Y; - if (0x7fffffff - Y < XYZ->blue_X) - return 1; - Y += XYZ->blue_Y; + Y = Ytemp; if (Y != PNG_FP_1) { diff --git a/3rdparty/libpng/png.h b/3rdparty/libpng/png.h index 83d3903126..d25fbe9ed3 100644 --- a/3rdparty/libpng/png.h +++ b/3rdparty/libpng/png.h @@ -1,9 +1,8 @@ - /* png.h - header file for PNG reference library * - * libpng version 1.6.43 + * libpng version 1.6.45 * - * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -15,7 +14,7 @@ * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger * libpng versions 0.97, January 1998, through 1.6.35, July 2018: * Glenn Randers-Pehrson - * libpng versions 1.6.36, December 2018, through 1.6.43, February 2024: + * libpng versions 1.6.36, December 2018, through 1.6.45, January 2025: * Cosmin Truta * See also "Contributing Authors", below. */ @@ -27,8 +26,8 @@ * PNG Reference Library License version 2 * --------------------------------------- * - * * Copyright (c) 1995-2024 The PNG Reference Library Authors. - * * Copyright (c) 2018-2024 Cosmin Truta. + * * Copyright (c) 1995-2025 The PNG Reference Library Authors. + * * Copyright (c) 2018-2025 Cosmin Truta. * * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * * Copyright (c) 1996-1997 Andreas Dilger. * * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -239,7 +238,7 @@ * ... * 1.5.30 15 10530 15.so.15.30[.0] * ... - * 1.6.43 16 10643 16.so.16.43[.0] + * 1.6.45 16 10645 16.so.16.45[.0] * * Henceforth the source version will match the shared-library major and * minor numbers; the shared-library major version number will be used for @@ -275,7 +274,7 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.43" +#define PNG_LIBPNG_VER_STRING "1.6.45" #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n" /* The versions of shared library builds should stay in sync, going forward */ @@ -286,18 +285,18 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 43 +#define PNG_LIBPNG_VER_RELEASE 45 /* This should be zero for a public release, or non-zero for a * development version. */ -#define PNG_LIBPNG_VER_BUILD 0 +#define PNG_LIBPNG_VER_BUILD 0 /* Release Status */ -#define PNG_LIBPNG_BUILD_ALPHA 1 -#define PNG_LIBPNG_BUILD_BETA 2 -#define PNG_LIBPNG_BUILD_RC 3 -#define PNG_LIBPNG_BUILD_STABLE 4 +#define PNG_LIBPNG_BUILD_ALPHA 1 +#define PNG_LIBPNG_BUILD_BETA 2 +#define PNG_LIBPNG_BUILD_RC 3 +#define PNG_LIBPNG_BUILD_STABLE 4 #define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7 /* Release-Specific Flags */ @@ -317,7 +316,7 @@ * From version 1.0.1 it is: * XXYYZZ, where XX=major, YY=minor, ZZ=release */ -#define PNG_LIBPNG_VER 10643 /* 1.6.43 */ +#define PNG_LIBPNG_VER 10645 /* 1.6.45 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -427,7 +426,7 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char* png_libpng_version_1_6_43; +typedef char* png_libpng_version_1_6_45; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * @@ -745,6 +744,7 @@ typedef png_unknown_chunk * * png_unknown_chunkpp; #define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */ #define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */ #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */ +#define PNG_INFO_cICP 0x20000U /* This is used for the transformation routines, as some of them * change these values for the row. It also should enable using @@ -824,7 +824,7 @@ typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, * your compiler. This may be very difficult - try using a different compiler * to build the library! */ -PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), (jmp_buf, int), typedef); #endif /* Transform masks for the high-level interface */ @@ -1974,6 +1974,17 @@ PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, png_fixed_point int_blue_Z)) #endif +#ifdef PNG_cICP_SUPPORTED +PNG_EXPORT(250, png_uint_32, png_get_cICP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep colour_primaries, + png_bytep transfer_function, png_bytep matrix_coefficients, + png_bytep video_full_range_flag)); +PNG_EXPORT(251, void, png_set_cICP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_byte colour_primaries, + png_byte transfer_function, png_byte matrix_coefficients, + png_byte video_full_range_flag)); +#endif + #ifdef PNG_eXIf_SUPPORTED PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *exif)); @@ -3238,7 +3249,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, * one to use is one more than this.) */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(249); + PNG_EXPORT_LAST_ORDINAL(251); #endif #ifdef __cplusplus diff --git a/3rdparty/libpng/pngconf.h b/3rdparty/libpng/pngconf.h index 000d7b1a8a..11a40b8d81 100644 --- a/3rdparty/libpng/pngconf.h +++ b/3rdparty/libpng/pngconf.h @@ -1,9 +1,8 @@ - /* pngconf.h - machine-configurable file for libpng * - * libpng version 1.6.43 + * libpng version 1.6.45 * - * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -88,7 +87,7 @@ /* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect * against legacy (pre ISOC90) compilers that did not understand function - * prototypes. It is not required for modern C compilers. + * prototypes. [Deprecated.] */ #ifndef PNGARG # define PNGARG(arglist) arglist @@ -298,7 +297,7 @@ #ifndef PNG_EXPORTA # define PNG_EXPORTA(ordinal, type, name, args, attributes) \ - PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), PNGARG(args), \ + PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), args, \ PNG_LINKAGE_API attributes) #endif @@ -316,7 +315,7 @@ #endif #ifndef PNG_CALLBACK -# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) args #endif /* Support for compiler specific function attributes. These are used diff --git a/3rdparty/libpng/pngdebug.h b/3rdparty/libpng/pngdebug.h index 00d5a4569e..ab9ea632d9 100644 --- a/3rdparty/libpng/pngdebug.h +++ b/3rdparty/libpng/pngdebug.h @@ -1,4 +1,3 @@ - /* pngdebug.h - Debugging macros for libpng, also used in pngtest.c * * Copyright (c) 2018 Cosmin Truta diff --git a/3rdparty/libpng/pngerror.c b/3rdparty/libpng/pngerror.c index 29ebda7943..aa0ae58e15 100644 --- a/3rdparty/libpng/pngerror.c +++ b/3rdparty/libpng/pngerror.c @@ -1,4 +1,3 @@ - /* pngerror.c - stub functions for i/o and memory allocation * * Copyright (c) 2018-2024 Cosmin Truta @@ -20,13 +19,14 @@ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr, - png_const_charp error_message)),PNG_NORETURN); +static PNG_FUNCTION(void /* PRIVATE */, +png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN); #ifdef PNG_WARNINGS_SUPPORTED static void /* PRIVATE */ -png_default_warning PNGARG((png_const_structrp png_ptr, - png_const_charp warning_message)); +png_default_warning(png_const_structrp png_ptr, + png_const_charp warning_message); #endif /* WARNINGS */ /* This function is called whenever there is a fatal error. This function diff --git a/3rdparty/libpng/pngget.c b/3rdparty/libpng/pngget.c index 1084b268ff..9be8814322 100644 --- a/3rdparty/libpng/pngget.c +++ b/3rdparty/libpng/pngget.c @@ -1,4 +1,3 @@ - /* pngget.c - retrieval of values from info struct * * Copyright (c) 2018-2024 Cosmin Truta @@ -785,6 +784,31 @@ png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, } #endif +#ifdef PNG_cICP_SUPPORTED +png_uint_32 PNGAPI +png_get_cICP(png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep colour_primaries, + png_bytep transfer_function, png_bytep matrix_coefficients, + png_bytep video_full_range_flag) +{ + png_debug1(1, "in %s retrieval function", "cICP"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_cICP) != 0 && + colour_primaries != NULL && transfer_function != NULL && + matrix_coefficients != NULL && video_full_range_flag != NULL) + { + *colour_primaries = info_ptr->cicp_colour_primaries; + *transfer_function = info_ptr->cicp_transfer_function; + *matrix_coefficients = info_ptr->cicp_matrix_coefficients; + *video_full_range_flag = info_ptr->cicp_video_full_range_flag; + return (PNG_INFO_cICP); + } + + return (0); +} +#endif + #ifdef PNG_eXIf_SUPPORTED png_uint_32 PNGAPI png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, diff --git a/3rdparty/libpng/pnginfo.h b/3rdparty/libpng/pnginfo.h index 1f98dedc42..e85420c1ad 100644 --- a/3rdparty/libpng/pnginfo.h +++ b/3rdparty/libpng/pnginfo.h @@ -1,4 +1,3 @@ - /* pnginfo.h - header file for PNG reference library * * Copyright (c) 2018 Cosmin Truta @@ -101,6 +100,14 @@ struct png_info_def png_colorspace colorspace; #endif +#ifdef PNG_cICP_SUPPORTED + /* cICP chunk data */ + png_byte cicp_colour_primaries; + png_byte cicp_transfer_function; + png_byte cicp_matrix_coefficients; + png_byte cicp_video_full_range_flag; +#endif + #ifdef PNG_iCCP_SUPPORTED /* iCCP chunk data. */ png_charp iccp_name; /* profile name */ diff --git a/3rdparty/libpng/pnglibconf.h b/3rdparty/libpng/pnglibconf.h index e1e27e957e..695aae6fed 100644 --- a/3rdparty/libpng/pnglibconf.h +++ b/3rdparty/libpng/pnglibconf.h @@ -1,8 +1,8 @@ /* pnglibconf.h - library build configuration */ -/* libpng version 1.6.37 */ +/* libpng version 1.6.45 */ -/* Copyright (c) 2018-2019 Cosmin Truta */ +/* Copyright (c) 2018-2025 Cosmin Truta */ /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */ /* This code is released under the libpng license. */ @@ -27,6 +27,7 @@ #define PNG_COLORSPACE_SUPPORTED #define PNG_CONSOLE_IO_SUPPORTED #define PNG_CONVERT_tIME_SUPPORTED +/*#undef PNG_DISABLE_ADLER32_CHECK_SUPPORTED*/ #define PNG_EASY_ACCESS_SUPPORTED /*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ #define PNG_ERROR_TEXT_SUPPORTED @@ -41,6 +42,10 @@ #define PNG_INCH_CONVERSIONS_SUPPORTED #define PNG_INFO_IMAGE_SUPPORTED #define PNG_IO_STATE_SUPPORTED +/*#undef PNG_MIPS_MMI_API_SUPPORTED*/ +/*#undef PNG_MIPS_MMI_CHECK_SUPPORTED*/ +/*#undef PNG_MIPS_MSA_API_SUPPORTED*/ +/*#undef PNG_MIPS_MSA_CHECK_SUPPORTED*/ #define PNG_MNG_FEATURES_SUPPORTED #define PNG_POINTER_INDEXING_SUPPORTED /*#undef PNG_POWERPC_VSX_API_SUPPORTED*/ @@ -83,6 +88,7 @@ #define PNG_READ_USER_TRANSFORM_SUPPORTED #define PNG_READ_bKGD_SUPPORTED #define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_cICP_SUPPORTED #define PNG_READ_eXIf_SUPPORTED #define PNG_READ_gAMA_SUPPORTED #define PNG_READ_hIST_SUPPORTED @@ -153,6 +159,7 @@ #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED #define PNG_WRITE_bKGD_SUPPORTED #define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_cICP_SUPPORTED #define PNG_WRITE_eXIf_SUPPORTED #define PNG_WRITE_gAMA_SUPPORTED #define PNG_WRITE_hIST_SUPPORTED @@ -171,6 +178,7 @@ #define PNG_WRITE_zTXt_SUPPORTED #define PNG_bKGD_SUPPORTED #define PNG_cHRM_SUPPORTED +#define PNG_cICP_SUPPORTED #define PNG_eXIf_SUPPORTED #define PNG_gAMA_SUPPORTED #define PNG_hIST_SUPPORTED diff --git a/3rdparty/libpng/pngmem.c b/3rdparty/libpng/pngmem.c index 09ed9c1c99..d391c13ff4 100644 --- a/3rdparty/libpng/pngmem.c +++ b/3rdparty/libpng/pngmem.c @@ -1,4 +1,3 @@ - /* pngmem.c - stub functions for memory allocation * * Copyright (c) 2018 Cosmin Truta diff --git a/3rdparty/libpng/pngpread.c b/3rdparty/libpng/pngpread.c index ffab19c08c..1bf880eabb 100644 --- a/3rdparty/libpng/pngpread.c +++ b/3rdparty/libpng/pngpread.c @@ -1,4 +1,3 @@ - /* pngpread.c - read a png file in push mode * * Copyright (c) 2018-2024 Cosmin Truta @@ -32,6 +31,21 @@ if (png_ptr->push_length + 4 > png_ptr->buffer_size) \ if (png_ptr->buffer_size < N) \ { png_push_save_buffer(png_ptr); return; } +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ + +/* Start of interlace block */ +static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; +/* Offset to next interlace block */ +static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +/* Start of interlace block in the y direction */ +static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; +/* Offset to next interlace block in the y direction */ +static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + +/* TODO: Move these arrays to a common utility module to avoid duplication. */ +#endif + void PNGAPI png_process_data(png_structrp png_ptr, png_inforp info_ptr, png_bytep buffer, size_t buffer_size) @@ -294,6 +308,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } +#endif +#ifdef PNG_READ_cICP_SUPPORTED + else if (png_ptr->chunk_name == png_cICP) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_cICP(png_ptr, info_ptr, png_ptr->push_length); + } + #endif #ifdef PNG_READ_eXIf_SUPPORTED else if (png_ptr->chunk_name == png_eXIf) @@ -976,27 +998,6 @@ png_push_process_row(png_structrp png_ptr) void /* PRIVATE */ png_read_push_finish_row(png_structrp png_ptr) { -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static const png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static const png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static const png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static const png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; - - /* Height of interlace block. This is not currently used - if you need - * it, uncomment it here and in png.h - static const png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; - */ -#endif - png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; diff --git a/3rdparty/libpng/pngpriv.h b/3rdparty/libpng/pngpriv.h index 9bfdb71342..84f77c3508 100644 --- a/3rdparty/libpng/pngpriv.h +++ b/3rdparty/libpng/pngpriv.h @@ -1,4 +1,3 @@ - /* pngpriv.h - private declarations for use inside libpng * * Copyright (c) 2018-2024 Cosmin Truta @@ -140,47 +139,6 @@ * callbacks to do this. */ # define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon - - /* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used - * if possible - if __ARM_NEON__ is set and the compiler version is not known - * to be broken. This is controlled by PNG_ARM_NEON_IMPLEMENTATION which can - * be: - * - * 1 The intrinsics code (the default with __ARM_NEON__) - * 2 The hand coded assembler (the default without __ARM_NEON__) - * - * It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however - * this is *NOT* supported and may cease to work even after a minor revision - * to libpng. It *is* valid to do this for testing purposes, e.g. speed - * testing or a new compiler, but the results should be communicated to the - * libpng implementation list for incorporation in the next minor release. - */ -# ifndef PNG_ARM_NEON_IMPLEMENTATION -# if defined(__ARM_NEON__) || defined(__ARM_NEON) -# if defined(__clang__) - /* At present it is unknown by the libpng developers which versions - * of clang support the intrinsics, however some or perhaps all - * versions do not work with the assembler so this may be - * irrelevant, so just use the default (do nothing here.) - */ -# elif defined(__GNUC__) - /* GCC 4.5.4 NEON support is known to be broken. 4.6.3 is known to - * work, so if this *is* GCC, or G++, look for a version >4.5 - */ -# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) -# define PNG_ARM_NEON_IMPLEMENTATION 2 -# endif /* no GNUC support */ -# endif /* __GNUC__ */ -# else /* !defined __ARM_NEON__ */ - /* The 'intrinsics' code simply won't compile without this -mfpu=neon: - */ -# if !defined(__aarch64__) && !defined(_M_ARM64) - /* The assembler code currently does not work on ARM64 */ -# define PNG_ARM_NEON_IMPLEMENTATION 2 -# endif /* __aarch64__ */ -# endif /* __ARM_NEON__ */ -# endif /* !PNG_ARM_NEON_IMPLEMENTATION */ - # ifndef PNG_ARM_NEON_IMPLEMENTATION /* Use the intrinsics code by default. */ # define PNG_ARM_NEON_IMPLEMENTATION 1 @@ -876,6 +834,7 @@ #define png_PLTE PNG_U32( 80, 76, 84, 69) #define png_bKGD PNG_U32( 98, 75, 71, 68) #define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_cICP PNG_U32( 99, 73, 67, 80) #define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */ #define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ #define png_gAMA PNG_U32(103, 65, 77, 65) @@ -1172,6 +1131,12 @@ PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, /* The xy value must have been previously validated */ #endif +#ifdef PNG_WRITE_cICP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_cICP,(png_structrp png_ptr, + png_byte colour_primaries, png_byte transfer_function, + png_byte matrix_coefficients, png_byte video_full_range_flag), PNG_EMPTY); +#endif + #ifdef PNG_WRITE_sRGB_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, int intent),PNG_EMPTY); @@ -1515,6 +1480,11 @@ PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif +#ifdef PNG_READ_cICP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_cICP,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + #ifdef PNG_READ_eXIf_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); diff --git a/3rdparty/libpng/pngread.c b/3rdparty/libpng/pngread.c index 07a39df6e2..49e19a4960 100644 --- a/3rdparty/libpng/pngread.c +++ b/3rdparty/libpng/pngread.c @@ -1,7 +1,6 @@ - /* pngread.c - read a PNG file * - * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -175,6 +174,11 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) png_handle_cHRM(png_ptr, info_ptr, length); #endif +#ifdef PNG_READ_cICP_SUPPORTED + else if (chunk_name == png_cICP) + png_handle_cICP(png_ptr, info_ptr, length); +#endif + #ifdef PNG_READ_eXIf_SUPPORTED else if (chunk_name == png_eXIf) png_handle_eXIf(png_ptr, info_ptr, length); @@ -852,6 +856,11 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) png_handle_cHRM(png_ptr, info_ptr, length); #endif +#ifdef PNG_READ_cICP_SUPPORTED + else if (chunk_name == png_cICP) + png_handle_cICP(png_ptr, info_ptr, length); +#endif + #ifdef PNG_READ_eXIf_SUPPORTED else if (chunk_name == png_eXIf) png_handle_eXIf(png_ptr, info_ptr, length); diff --git a/3rdparty/libpng/pngrio.c b/3rdparty/libpng/pngrio.c index 7946358101..3b137f275f 100644 --- a/3rdparty/libpng/pngrio.c +++ b/3rdparty/libpng/pngrio.c @@ -1,4 +1,3 @@ - /* pngrio.c - functions for data input * * Copyright (c) 2018 Cosmin Truta diff --git a/3rdparty/libpng/pngrtran.c b/3rdparty/libpng/pngrtran.c index 1526123e02..124906635b 100644 --- a/3rdparty/libpng/pngrtran.c +++ b/3rdparty/libpng/pngrtran.c @@ -1,4 +1,3 @@ - /* pngrtran.c - transforms the data in a row for PNG readers * * Copyright (c) 2018-2024 Cosmin Truta diff --git a/3rdparty/libpng/pngrutil.c b/3rdparty/libpng/pngrutil.c index d31dc21dae..7c609b4b48 100644 --- a/3rdparty/libpng/pngrutil.c +++ b/3rdparty/libpng/pngrutil.c @@ -1,4 +1,3 @@ - /* pngrutil.c - utilities to read a PNG file * * Copyright (c) 2018-2024 Cosmin Truta @@ -18,6 +17,21 @@ #ifdef PNG_READ_SUPPORTED +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ + +/* Start of interlace block */ +static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; +/* Offset to next interlace block */ +static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +/* Start of interlace block in the y direction */ +static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; +/* Offset to next interlace block in the y direction */ +static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + +/* TODO: Move these arrays to a common utility module to avoid duplication. */ +#endif + png_uint_32 PNGAPI png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) { @@ -2032,6 +2046,47 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } #endif +#ifdef PNG_READ_cICP_SUPPORTED +void /* PRIVATE */ +png_handle_cICP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[4]; + + png_debug(1, "in png_handle_cICP"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cICP) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + else if (length != 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 4); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + png_set_cICP(png_ptr, info_ptr, buf[0], buf[1], buf[2], buf[3]); +} +#endif + #ifdef PNG_READ_eXIf_SUPPORTED void /* PRIVATE */ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) @@ -3684,10 +3739,6 @@ void /* PRIVATE */ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, png_uint_32 transformations /* Because these may affect the byte layout */) { - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - /* Offset to next interlace block */ - static const unsigned int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - png_debug(1, "in png_do_read_interlace"); if (row != NULL && row_info != NULL) { @@ -4325,20 +4376,6 @@ png_read_finish_IDAT(png_structrp png_ptr) void /* PRIVATE */ png_read_finish_row(png_structrp png_ptr) { - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; - png_debug(1, "in png_read_finish_row"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) @@ -4390,20 +4427,6 @@ png_read_finish_row(png_structrp png_ptr) void /* PRIVATE */ png_read_start_row(png_structrp png_ptr) { - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; - unsigned int max_pixel_depth; size_t row_bytes; diff --git a/3rdparty/libpng/pngset.c b/3rdparty/libpng/pngset.c index eb1c8c7a35..462b50cf2a 100644 --- a/3rdparty/libpng/pngset.c +++ b/3rdparty/libpng/pngset.c @@ -1,7 +1,6 @@ - /* pngset.c - storage of image information into info struct * - * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -134,6 +133,32 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, #endif /* cHRM */ +#ifdef PNG_cICP_SUPPORTED +void PNGAPI +png_set_cICP(png_const_structrp png_ptr, png_inforp info_ptr, + png_byte colour_primaries, png_byte transfer_function, + png_byte matrix_coefficients, png_byte video_full_range_flag) +{ + png_debug1(1, "in %s storage function", "cICP"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->cicp_colour_primaries = colour_primaries; + info_ptr->cicp_transfer_function = transfer_function; + info_ptr->cicp_matrix_coefficients = matrix_coefficients; + info_ptr->cicp_video_full_range_flag = video_full_range_flag; + + if (info_ptr->cicp_matrix_coefficients != 0) + { + png_warning(png_ptr, "Invalid cICP matrix coefficients"); + return; + } + + info_ptr->valid |= PNG_INFO_cICP; +} +#endif /* cICP */ + #ifdef PNG_eXIf_SUPPORTED void PNGAPI png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, @@ -1395,6 +1420,7 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, static const png_byte chunks_to_ignore[] = { 98, 75, 71, 68, '\0', /* bKGD */ 99, 72, 82, 77, '\0', /* cHRM */ + 99, 73, 67, 80, '\0', /* cICP */ 101, 88, 73, 102, '\0', /* eXIf */ 103, 65, 77, 65, '\0', /* gAMA */ 104, 73, 83, 84, '\0', /* hIST */ diff --git a/3rdparty/libpng/pngstruct.h b/3rdparty/libpng/pngstruct.h index e591d94d58..7e919d0a37 100644 --- a/3rdparty/libpng/pngstruct.h +++ b/3rdparty/libpng/pngstruct.h @@ -1,4 +1,3 @@ - /* pngstruct.h - header file for PNG reference library * * Copyright (c) 2018-2022 Cosmin Truta diff --git a/3rdparty/libpng/pngtrans.c b/3rdparty/libpng/pngtrans.c index 62cb21edf1..222b4987f9 100644 --- a/3rdparty/libpng/pngtrans.c +++ b/3rdparty/libpng/pngtrans.c @@ -1,4 +1,3 @@ - /* pngtrans.c - transforms the data in a row (used by both readers and writers) * * Copyright (c) 2018-2024 Cosmin Truta diff --git a/3rdparty/libpng/pngwio.c b/3rdparty/libpng/pngwio.c index 10e919dd03..38c9c006cb 100644 --- a/3rdparty/libpng/pngwio.c +++ b/3rdparty/libpng/pngwio.c @@ -1,4 +1,3 @@ - /* pngwio.c - functions for data output * * Copyright (c) 2018 Cosmin Truta diff --git a/3rdparty/libpng/pngwrite.c b/3rdparty/libpng/pngwrite.c index 77e412f43d..8b1b06c20c 100644 --- a/3rdparty/libpng/pngwrite.c +++ b/3rdparty/libpng/pngwrite.c @@ -1,7 +1,6 @@ - /* pngwrite.c - general routines to write a PNG file * - * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -128,29 +127,61 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) * the application continues writing the PNG. So check the 'invalid' * flag here too. */ -#ifdef PNG_GAMMA_SUPPORTED -# ifdef PNG_WRITE_gAMA_SUPPORTED - if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && - (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 && - (info_ptr->valid & PNG_INFO_gAMA) != 0) - png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); -# endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + /* Write unknown chunks first; PNG v3 establishes a precedence order + * for colourspace chunks. It is certain therefore that new + * colourspace chunks will have a precedence and very likely it will be + * higher than all known so far. Writing the unknown chunks here is + * most likely to present the chunks in the most convenient order. + * + * FUTURE: maybe write chunks in the order the app calls png_set_chnk + * to give the app control. + */ + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); #endif +#ifdef PNG_WRITE_sBIT_SUPPORTED + /* PNG v3: a streaming app will need to see this before cICP because + * the information is helpful in handling HLG encoding (which is + * natively 10 bits but gets expanded to 16 in PNG.) + * + * The app shouldn't care about the order ideally, but it might have + * no choice. In PNG v3, apps are allowed to reject PNGs where the + * APNG chunks are out of order so it behooves libpng to be nice here. + */ + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#endif + + /* PNG v3: the July 2004 version of the TR introduced the concept of colour + * space priority. As above it therefore behooves libpng to write the colour + * space chunks in the priority order so that a streaming app need not buffer + * them. + */ #ifdef PNG_COLORSPACE_SUPPORTED - /* Write only one of sRGB or an ICC profile. If a profile was supplied - * and it matches one of the known sRGB ones issue a warning. +# ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */ + if ((info_ptr->valid & PNG_INFO_cICP) != 0) + { + png_write_cICP(png_ptr, + info_ptr->cicp_colour_primaries, + info_ptr->cicp_transfer_function, + info_ptr->cicp_matrix_coefficients, + info_ptr->cicp_video_full_range_flag); + } +# endif + + /* PNG v3 change: it is now permitted to write both sRGB and ICC profiles, + * however because the libpng code auto-generates an sRGB for the + * corresponding ICC profiles and because PNG v2 disallowed this we need + * to only write one. + * + * Remove the PNG v2 warning about writing an sRGB ICC profile as well + * because it's invalid with PNG v3. */ -# ifdef PNG_WRITE_iCCP_SUPPORTED +# ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && (info_ptr->valid & PNG_INFO_iCCP) != 0) { -# ifdef PNG_WRITE_sRGB_SUPPORTED - if ((info_ptr->valid & PNG_INFO_sRGB) != 0) - png_app_warning(png_ptr, - "profile matches sRGB but writing iCCP instead"); -# endif - png_write_iCCP(png_ptr, info_ptr->iccp_name, info_ptr->iccp_profile); } @@ -159,20 +190,24 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) # endif # endif -# ifdef PNG_WRITE_sRGB_SUPPORTED +# ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && (info_ptr->valid & PNG_INFO_sRGB) != 0) png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); # endif /* WRITE_sRGB */ #endif /* COLORSPACE */ -#ifdef PNG_WRITE_sBIT_SUPPORTED - if ((info_ptr->valid & PNG_INFO_sBIT) != 0) - png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#ifdef PNG_GAMMA_SUPPORTED +# ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */ + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 && + (info_ptr->valid & PNG_INFO_gAMA) != 0) + png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); +# endif #endif #ifdef PNG_COLORSPACE_SUPPORTED -# ifdef PNG_WRITE_cHRM_SUPPORTED +# ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 && (info_ptr->valid & PNG_INFO_cHRM) != 0) @@ -180,10 +215,6 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) # endif #endif -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); -#endif - png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; } } diff --git a/3rdparty/libpng/pngwtran.c b/3rdparty/libpng/pngwtran.c index 49a13c1e98..a20847023f 100644 --- a/3rdparty/libpng/pngwtran.c +++ b/3rdparty/libpng/pngwtran.c @@ -1,4 +1,3 @@ - /* pngwtran.c - transforms the data in a row for PNG writers * * Copyright (c) 2018 Cosmin Truta diff --git a/3rdparty/libpng/pngwutil.c b/3rdparty/libpng/pngwutil.c index 14cc4ce367..8b2bf4e6d6 100644 --- a/3rdparty/libpng/pngwutil.c +++ b/3rdparty/libpng/pngwutil.c @@ -1,4 +1,3 @@ - /* pngwutil.c - utilities to write a PNG file * * Copyright (c) 2018-2024 Cosmin Truta @@ -9,12 +8,30 @@ * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h + * + * This file contains routines that are only called from within + * libpng itself during the course of writing an image. */ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ + +/* Start of interlace block */ +static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; +/* Offset to next interlace block */ +static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +/* Start of interlace block in the y direction */ +static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; +/* Offset to next interlace block in the y direction */ +static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + +/* TODO: Move these arrays to a common utility module to avoid duplication. */ +#endif + #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED /* Place a 32-bit number into a buffer in PNG byte order. We work * with unsigned numbers for convenience, although one supported @@ -1471,6 +1488,29 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) } #endif +#ifdef PNG_WRITE_cICP_SUPPORTED +/* Write the cICP data */ +void /* PRIVATE */ +png_write_cICP(png_structrp png_ptr, + png_byte colour_primaries, png_byte transfer_function, + png_byte matrix_coefficients, png_byte video_full_range_flag) +{ + png_byte buf[4]; + + png_debug(1, "in png_write_cICP"); + + png_write_chunk_header(png_ptr, png_cICP, 4); + + buf[0] = colour_primaries; + buf[1] = transfer_function; + buf[2] = matrix_coefficients; + buf[3] = video_full_range_flag; + png_write_chunk_data(png_ptr, buf, 4); + + png_write_chunk_end(png_ptr); +} +#endif + #ifdef PNG_WRITE_eXIf_SUPPORTED /* Write the Exif data */ void /* PRIVATE */ @@ -1889,22 +1929,6 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) void /* PRIVATE */ png_write_start_row(png_structrp png_ptr) { -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif - png_alloc_size_t buf_size; int usr_pixel_depth; @@ -2004,22 +2028,6 @@ png_write_start_row(png_structrp png_ptr) void /* PRIVATE */ png_write_finish_row(png_structrp png_ptr) { -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif - png_debug(1, "in png_write_finish_row"); /* Next row */ @@ -2095,14 +2103,6 @@ png_write_finish_row(png_structrp png_ptr) void /* PRIVATE */ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) { - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - png_debug(1, "in png_do_write_interlace"); /* We don't have to do anything on the last pass (6) */ diff --git a/3rdparty/libpng/powerpc/powerpc_init.c b/3rdparty/libpng/powerpc/powerpc_init.c index 54426c558e..9027480098 100644 --- a/3rdparty/libpng/powerpc/powerpc_init.c +++ b/3rdparty/libpng/powerpc/powerpc_init.c @@ -1,4 +1,3 @@ - /* powerpc_init.c - POWERPC optimised filter functions * * Copyright (c) 2018 Cosmin Truta diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b756718b3..8f56c0413c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1552,7 +1552,6 @@ if(WITH_FFMPEG OR HAVE_FFMPEG) status(" avformat:" FFMPEG_libavformat_VERSION THEN "YES (${FFMPEG_libavformat_VERSION})" ELSE NO) status(" avutil:" FFMPEG_libavutil_VERSION THEN "YES (${FFMPEG_libavutil_VERSION})" ELSE NO) status(" swscale:" FFMPEG_libswscale_VERSION THEN "YES (${FFMPEG_libswscale_VERSION})" ELSE NO) - status(" avresample:" FFMPEG_libavresample_VERSION THEN "YES (${FFMPEG_libavresample_VERSION})" ELSE NO) if(OPENCV_FFMPEG_ENABLE_LIBAVDEVICE) status(" avdevice:" FFMPEG_libavdevice_VERSION THEN "YES (${FFMPEG_libavdevice_VERSION})" ELSE NO) endif() diff --git a/cmake/OpenCVDetectCUDAUtils.cmake b/cmake/OpenCVDetectCUDAUtils.cmake index eb666bc715..13eaf874dd 100644 --- a/cmake/OpenCVDetectCUDAUtils.cmake +++ b/cmake/OpenCVDetectCUDAUtils.cmake @@ -388,6 +388,7 @@ macro(ocv_nvcc_flags) endif() if(WIN32) + set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler=/wd4505) if (NOT (CUDA_VERSION VERSION_LESS "11.2")) set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcudafe --display_error_number --diag-suppress 1394,1388) endif() diff --git a/doc/opencv.bib b/doc/opencv.bib index 5b5bd98fbe..64f5fa9715 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -1310,13 +1310,26 @@ title = {QR Factorization}, url = {https://www.seas.ucla.edu/~vandenbe/133A/lectures/qr.pdf} } -@inproceedings{wang2016iros, - author = {John Wang and Edwin Olson}, - title = {{AprilTag} 2: Efficient and robust fiducial detection}, - booktitle = {Proceedings of the {IEEE/RSJ} International Conference on Intelligent Robots and Systems {(IROS)}}, - year = {2016}, - month = {October}, - url = {https://april.eecs.umich.edu/pdfs/wang2016iros.pdf} +@inproceedings{Viola01, + author = {Viola, Paul and Jones, Michael J.}, + title = {Rapid object detection using a boosted cascade of simple features}, + booktitle = {Computer Vision and Pattern Recognition, 2001. CVPR 2001. Proceedings of the 2001 IEEE Computer Society Conference on}, + year = {2001}, + pages = {I--511}, + volume = {1}, + publisher = {IEEE}, + url = {https://www.researchgate.net/publication/3940582_Rapid_Object_Detection_using_a_Boosted_Cascade_of_Simple_Features} +} +@article{Viola04, + author = {Viola, Paul and Jones, Michael J.}, + title = {Robust real-time face detection}, + journal = {International Journal of Computer Vision}, + year = {2004}, + volume = {57}, + number = {2}, + pages = {137--154}, + publisher = {Kluwer Academic Publishers}, + url = {https://www.face-rec.org/algorithms/Boosting-Ensemble/16981346.pdf} } @misc{Welch95, author = {Welch, Greg and Bishop, Gary}, diff --git a/doc/tutorials/introduction/general_install/general_install.markdown b/doc/tutorials/introduction/general_install/general_install.markdown index 7b0c5d2b06..e8c679e508 100644 --- a/doc/tutorials/introduction/general_install/general_install.markdown +++ b/doc/tutorials/introduction/general_install/general_install.markdown @@ -26,7 +26,7 @@ Other organizations and people maintain their own binary distributions of OpenCV - System packages in popular Linux distributions (https://pkgs.org/search/?q=opencv) - PyPI (https://pypi.org/search/?q=opencv) - Conda (https://anaconda.org/search?q=opencv) -- Conan (https://github.com/conan-community/conan-opencv) +- Conan (https://conan.io/center/recipes/opencv) - vcpkg (https://github.com/microsoft/vcpkg/tree/master/ports/opencv) - NuGet (https://www.nuget.org/packages?q=opencv) - Brew (https://formulae.brew.sh/formula/opencv) diff --git a/modules/core/include/opencv2/core/cuda/cuda_compat.hpp b/modules/core/include/opencv2/core/cuda/cuda_compat.hpp new file mode 100644 index 0000000000..b40b2ea4f9 --- /dev/null +++ b/modules/core/include/opencv2/core/cuda/cuda_compat.hpp @@ -0,0 +1,38 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_CUDA_CUDA_COMPAT_HPP +#define OPENCV_CUDA_CUDA_COMPAT_HPP + +#include + +namespace cv { namespace cuda { namespace device { namespace compat +{ +#if CUDA_VERSION >= 13000 + using ulonglong4 = ::ulonglong4_16a; + using double4 = ::double4_16a; + __host__ __device__ __forceinline__ + double4 make_double4(double x, double y, double z, double w) + { + return ::make_double4_16a(x, y, z, w); + } +#else + using ulonglong4 = ::ulonglong4; + using double4 = ::double4; + __host__ __device__ __forceinline__ + double4 make_double4(double x, double y, double z, double w) + { + return ::make_double4(x, y, z, w); + } +#endif + using ulonglong4Compat = ulonglong4; + using double4Compat = double4; + __host__ __device__ __forceinline__ + double4Compat make_double4_compat(double x, double y, double z, double w) + { + return make_double4(x, y, z, w); + } +}}}} + +#endif // OPENCV_CUDA_CUDA_COMPAT_HPP \ No newline at end of file diff --git a/modules/core/include/opencv2/core/cuda/vec_math.hpp b/modules/core/include/opencv2/core/cuda/vec_math.hpp index 80b1303681..afb8cc0c4c 100644 --- a/modules/core/include/opencv2/core/cuda/vec_math.hpp +++ b/modules/core/include/opencv2/core/cuda/vec_math.hpp @@ -45,6 +45,7 @@ #include "vec_traits.hpp" #include "saturate_cast.hpp" +#include "cuda_compat.hpp" /** @file * @deprecated Use @ref cudev instead. @@ -54,6 +55,8 @@ namespace cv { namespace cuda { namespace device { + using cv::cuda::device::compat::double4; + using cv::cuda::device::compat::make_double4; // saturate_cast diff --git a/modules/core/include/opencv2/core/cuda/vec_traits.hpp b/modules/core/include/opencv2/core/cuda/vec_traits.hpp index b5ff281a0b..786a9314a7 100644 --- a/modules/core/include/opencv2/core/cuda/vec_traits.hpp +++ b/modules/core/include/opencv2/core/cuda/vec_traits.hpp @@ -44,6 +44,7 @@ #define OPENCV_CUDA_VEC_TRAITS_HPP #include "common.hpp" +#include "cuda_compat.hpp" /** @file * @deprecated Use @ref cudev instead. @@ -53,6 +54,9 @@ namespace cv { namespace cuda { namespace device { + using cv::cuda::device::compat::double4; + using cv::cuda::device::compat::make_double4; + template struct TypeVec; struct __align__(8) uchar8 diff --git a/modules/core/src/cuda/gpu_mat.cu b/modules/core/src/cuda/gpu_mat.cu index 0d80721ee7..7eccc6cdfe 100644 --- a/modules/core/src/cuda/gpu_mat.cu +++ b/modules/core/src/cuda/gpu_mat.cu @@ -51,10 +51,12 @@ #include "opencv2/core/cuda.hpp" #include "opencv2/cudev.hpp" #include "opencv2/core/cuda/utility.hpp" +#include "opencv2/core/cuda/cuda_compat.hpp" using namespace cv; using namespace cv::cuda; using namespace cv::cudev; +using cv::cuda::device::compat::double4Compat; device::ThrustAllocator::~ThrustAllocator() { @@ -343,7 +345,7 @@ void cv::cuda::GpuMat::copyTo(OutputArray _dst, InputArray _mask, Stream& stream {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, - {copyWithMask, copyWithMask, copyWithMask, copyWithMask} + {copyWithMask, copyWithMask, copyWithMask, copyWithMask} }; if (mask.channels() == channels()) @@ -426,7 +428,7 @@ GpuMat& cv::cuda::GpuMat::setTo(Scalar value, Stream& stream) {setToWithOutMask,setToWithOutMask,setToWithOutMask,setToWithOutMask}, {setToWithOutMask,setToWithOutMask,setToWithOutMask,setToWithOutMask}, {setToWithOutMask,setToWithOutMask,setToWithOutMask,setToWithOutMask}, - {setToWithOutMask,setToWithOutMask,setToWithOutMask,setToWithOutMask} + {setToWithOutMask,setToWithOutMask,setToWithOutMask,setToWithOutMask} }; funcs[depth()][channels() - 1](*this, value, stream); @@ -457,7 +459,7 @@ GpuMat& cv::cuda::GpuMat::setTo(Scalar value, InputArray _mask, Stream& stream) {setToWithMask,setToWithMask,setToWithMask,setToWithMask}, {setToWithMask,setToWithMask,setToWithMask,setToWithMask}, {setToWithMask,setToWithMask,setToWithMask,setToWithMask}, - {setToWithMask,setToWithMask,setToWithMask,setToWithMask} + {setToWithMask,setToWithMask,setToWithMask,setToWithMask} }; funcs[depth()][channels() - 1](*this, mask, value, stream); diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index bc6f9aefad..5aca984378 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -3499,8 +3499,10 @@ struct Kernel::Impl void addUMat(const UMat& m, bool dst) { + // TSAN false positive: see #27638 CV_Assert(nu < MAX_ARRS && m.u && m.u->urefcount > 0); u[nu] = m.u; + // TSAN false positive: see #27638 CV_XADD(&m.u->urefcount, 1); nu++; if(dst && m.u->tempUMat()) @@ -5651,6 +5653,7 @@ public: if(!u) return; + // Next two lines: TSAN false positive: see #27638 CV_Assert(u->urefcount == 0); CV_Assert(u->refcount == 0 && "UMat deallocation error: some derived Mat is still alive"); @@ -6583,11 +6586,13 @@ public: void flushCleanupQueue() const { + // TSAN false positive: see #27638 if (!cleanupQueue.empty()) { std::deque q; { cv::AutoLock lock(cleanupQueueMutex); + // TSAN false positive: see #27638 q.swap(cleanupQueue); } for (std::deque::const_iterator i = q.begin(); i != q.end(); ++i) diff --git a/modules/dnn/src/cuda/vector_traits.hpp b/modules/dnn/src/cuda/vector_traits.hpp index 1b9b76980c..d7d2214035 100644 --- a/modules/dnn/src/cuda/vector_traits.hpp +++ b/modules/dnn/src/cuda/vector_traits.hpp @@ -11,6 +11,7 @@ #include "memory.hpp" #include "../cuda4dnn/csl/pointer.hpp" +#include "opencv2/core/cuda/cuda_compat.hpp" #include @@ -34,9 +35,11 @@ namespace cv { namespace dnn { namespace cuda4dnn { namespace csl { namespace de * v_store(output_vPtr, vec); */ + using cv::cuda::device::compat::ulonglong4Compat; + namespace detail { template struct raw_type_ { }; - template <> struct raw_type_<256> { typedef ulonglong4 type; }; + template <> struct raw_type_<256> { typedef ulonglong4Compat type; }; template <> struct raw_type_<128> { typedef uint4 type; }; template <> struct raw_type_<64> { typedef uint2 type; }; template <> struct raw_type_<32> { typedef uint1 type; }; diff --git a/modules/dnn/src/layers/einsum_layer.cpp b/modules/dnn/src/layers/einsum_layer.cpp index 4a50526460..ceb5c2d662 100644 --- a/modules/dnn/src/layers/einsum_layer.cpp +++ b/modules/dnn/src/layers/einsum_layer.cpp @@ -232,7 +232,7 @@ Mat Diagonal(const Mat& input, int dim1, int dim2) } } - // Permutate the input so that the dims from which we need the diagonal forms the innermost dims + // Permute the input so that the dims from which we need the diagonal form the innermost dims Mat transposed = Transpose(input, input_dims, permutation); // Parse the diagonal from the innermost dims @@ -246,7 +246,7 @@ Mat Diagonal(const Mat& input, int dim1, int dim2) reverse_permutation[perm] = iter++; } - // Permutate using the reverse permutation to get back the original axes ordering + // Permute using the reverse permutation to get back the original axes ordering // (Pass in CPU Transpose function here as this Diagonal method will only be used for CPU based diagonal parsing) output = Transpose(output, shape(output), reverse_permutation); } else { @@ -299,19 +299,19 @@ public: // Preprocessed inputs std::vector preProcessedInputs; - // This is container for preporcessed inputs + // This container holds preprocessed inputs std::vector homogenizedInputDims; - // Collect outpus dimentions - MatShape einsumOutDims; // vector to store output dimentions + // Collect output dimensions + MatShape einsumOutDims; // vector to store output dimensions - // These hold equation subring, left hand side and right it of + // These hold equation substrings: the left-hand side, right-hand side, and the full equation String lhs_eq, rhs_eq, equation; - // Holds token from left hand side of the equation + // Holds tokens from the left-hand side of the equation std::vector lhs_eq_tokens; - // Idicates if equation substring is defined in explit way such as "ij, jk->ik" + // Indicates if the equation substring is defined in an explicit way such as "ij, jk->ik" // as opposed to "ij->" bool explicitEquation = false; @@ -330,14 +330,14 @@ public: // A value of -1 means the corresponding subscript index is not found in the output std::vector subscriptIndicesToOutputIndices; - // Hold max number of alphabetic numbers + // Holds the max number of alphabetic characters static const size_t numOfLetters = 52; // Stores the count corresponding to each letter encountered // A value of `0` indicates that the corresponding letter hasn't been seen at all std::array letter2count; - // Hold the assigned index corresponding to the letter seen + // Holds the assigned index corresponding to the letter seen // `-1` means the corresponding letter wasn't seen at all std::array letter2index; @@ -363,7 +363,7 @@ public: void calculateOutputShape(); void preProcessInputs(InputArrayOfArrays& inputs); Mat reduceSum(Mat& src, MatShape& reduceAxis); - Mat FinalizeOutput(const Mat& candidateOuput, const MatShape& ordered_subscript_indices_in_candidate); + Mat FinalizeOutput(const Mat& candidateOutput, const MatShape& ordered_subscript_indices_in_candidate); Mat pairwiseOperandProcess( const Mat& left, const MatShape& leftShapeOverride, @@ -410,8 +410,8 @@ public: letter2count.fill(0); letter2index.fill(-1); - // parser equation and extract tokens from the equation - // save token to lhs_eq_tokens variable + // parse equation and extract tokens from the equation + // save tokens to lhs_eq_tokens vector parseEquation(equation); // TODO: return lhs_eq_tokens } @@ -420,7 +420,7 @@ public: backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH; } - // getMeoryShapes + // getMemoryShapes bool getMemoryShapes(const std::vector &inputs, const int requiredOutputs, std::vector &outputs, @@ -456,7 +456,7 @@ public: { CV_TRACE_FUNCTION(); CV_TRACE_ARG_VALUE(name, "name", name.c_str()); - CV_CheckEQ((size_t)inputs_arr.total(), (size_t)numInputs, "Number of inputs in forward and inputs during graph constructions do not match"); + CV_CheckEQ((size_t)inputs_arr.total(), (size_t)numInputs, "Number of inputs in forward and inputs during graph construction do not match"); if (inputs_arr.depth() == CV_16F) { @@ -546,14 +546,14 @@ public: } } - // check of product of output dimentions and computed output dimentions match + // check that product of output dimensions and computed output dimensions match size_t reqProd = std::accumulate(einsumOutDims.begin(), einsumOutDims.end(), 1, std::multiplies()); MatShape realOutputDims = shape(result); size_t realProd = std::accumulate(realOutputDims.begin(), realOutputDims.end(), 1, std::multiplies()); CV_CheckEQ(reqProd, realProd, "Real output can not be shaped in to required output"); - // reduce dimentions + // reduce dimensions result = result.reshape(1, einsumOutDims.size(), einsumOutDims.data()); result.copyTo(outputs[0]); } // forward @@ -630,20 +630,20 @@ void LayerEinsumImpl::preProcessInputs(InputArrayOfArrays& inputs_arr) // same axes order MatShape homogenizedInputDims_(numLetterIndices, 1); - int dimIndexInIreprocessedInput = 0; + int dimIndexInPreprocessedInput = 0; int dimIndexInOriginalInput = 0; for (const auto& subscriptIndex : currSubscriptIndices) { if(subscriptIndicesToInputIndex[subscriptIndex] == -1){ - subscriptIndicesToInputIndex[subscriptIndex] = dimIndexInIreprocessedInput++; + subscriptIndicesToInputIndex[subscriptIndex] = dimIndexInPreprocessedInput++; homogenizedInputDims_[subscriptIndex] = input_dims[dimIndexInOriginalInput]; } else { // Call diagonal preprocessed = Diagonal( !preprocessed.empty() ? preprocessed : inputs[inputIter], subscriptIndicesToInputIndex[subscriptIndex], - dimIndexInIreprocessedInput); + dimIndexInPreprocessedInput); } ++dimIndexInOriginalInput; } @@ -686,7 +686,7 @@ void LayerEinsumImpl::parseEquation(String equation) std::size_t arrow_idx = equation.find("->"); if (arrow_idx != std::string::npos) { - // split left and righ hand sides of the equation + // split left- and right-hand sides of the equation lhs_eq = equation.substr(0, arrow_idx); rhs_eq = equation.substr(arrow_idx + 2); explicitEquation = true; @@ -762,7 +762,7 @@ void LayerEinsumImpl::calculateOutputShape() CV_CheckNE(letterIndex, -1, "The only permissible subscript labels are lowercase letters (a-z) and uppercase letters (A-Z)."); CV_CheckEQ(outputLetterToCount[letterIndex], 0, - "Output subscript constains repeated letters"); + "Output subscript contains repeated letters"); ++outputLetterToCount[letterIndex]; auto mappedIndex = letter2index[letterIndex]; @@ -770,7 +770,7 @@ void LayerEinsumImpl::calculateOutputShape() CV_CheckNE(mappedIndex, -1, "Output subscript has letters that were not encountered in the inputs"); - // Push output dimention + // Push output dimension // Einsum layer only has one output vector einsumOutDims.emplace_back(subscriptIndicesToDimValue[mappedIndex]); @@ -797,7 +797,7 @@ void LayerEinsumImpl::validateOutputSubscript() if(rhs_eq.find("...") == std::string::npos) { CV_Error(Error::StsError, - "Provided output subscript does not include ellipsis while Inputs subscrits constain ellipsis"); + "Provided output subscript does not include ellipsis while input subscripts contain ellipsis"); } } } @@ -1006,7 +1006,7 @@ void LayerEinsumImpl::processEquation(const std::vector& inputs) CV_Error(Error::StsError, cv::format("Einsum operands can not be broadcasted." "Check input shapes/equation passed." "Input shape of operand [%d]", inputIdx) + - cv::format(" is incompatible in the dimention [%zu].", static_cast(dim_count))); + cv::format(" is incompatible in the dimension [%zu].", static_cast(dim_count))); } } } @@ -1113,7 +1113,7 @@ Mat LayerEinsumImpl::pairwiseOperandProcess( Mat currentLeft; Mat currentRight; - CV_CheckEQ(leftRank, rightRank, "Raks of pair-wise operands must be equal"); + CV_CheckEQ(leftRank, rightRank, "Ranks of pair-wise operands must be equal"); // Following vectors hold: // lro: dim indices that are present in left, right, and reduce_dims @@ -1192,7 +1192,7 @@ Mat LayerEinsumImpl::pairwiseOperandProcess( } - // Permutate the left operand so that the axes order go like this: [lro, lo, reduce_dims, ro] + // Permute the left operand so that the axes order go like this: [lro, lo, reduce_dims, ro] MatShape reshaped_dims; std::vector left_permutation; left_permutation.reserve(lro.size() + lo.size() + reduceDims.size() + ro.size()); @@ -1225,7 +1225,7 @@ Mat LayerEinsumImpl::pairwiseOperandProcess( } } - // Permutate the right operand so that the axes order go like this: [lro, reduce_dims, ro, lo] + // Permute the right operand so that the axes order go like this: [lro, reduce_dims, ro, lo] std::vector right_permutation; right_permutation.reserve(lro.size() + lo.size() + reduceDims.size() + ro.size()); right_permutation.insert(right_permutation.end(), lro.begin(), lro.end()); diff --git a/modules/flann/include/opencv2/flann/general.h b/modules/flann/include/opencv2/flann/general.h index e65cba2f8a..11ea2af645 100644 --- a/modules/flann/include/opencv2/flann/general.h +++ b/modules/flann/include/opencv2/flann/general.h @@ -54,12 +54,12 @@ public: #define FLANN_THROW(TYPE, STR) throw FLANNException(STR) +//! @endcond + #else #define FLANN_THROW(TYPE, STR) CV_Error(TYPE, STR) #endif -//! @endcond - #endif /* OPENCV_FLANN_GENERAL_H_ */ diff --git a/modules/imgcodecs/include/opencv2/imgcodecs.hpp b/modules/imgcodecs/include/opencv2/imgcodecs.hpp index 09b4a2715c..7d43e7f07b 100644 --- a/modules/imgcodecs/include/opencv2/imgcodecs.hpp +++ b/modules/imgcodecs/include/opencv2/imgcodecs.hpp @@ -119,6 +119,7 @@ enum ImwriteFlags { IMWRITE_JPEGXL_EFFORT = 641,//!< For JPEG XL, encoder effort/speed level without affecting decoding speed; it is between 1 (fastest) and 10 (slowest). Default is 7. IMWRITE_JPEGXL_DISTANCE = 642,//!< For JPEG XL, distance level for lossy compression: target max butteraugli distance, lower = higher quality, 0 = lossless; range: 0 .. 25. Default is 1. IMWRITE_JPEGXL_DECODING_SPEED = 643,//!< For JPEG XL, decoding speed tier for the provided options; minimum is 0 (slowest to decode, best quality/density), and maximum is 4 (fastest to decode, at the cost of some quality/density). Default is 0. + IMWRITE_BMP_COMPRESSION = 768, //!< For BMP, use to specify compress parameter for 32bpp image. Default is IMWRITE_BMP_COMPRESSION_BITFIELDS. See cv::ImwriteBMPCompressionFlags. IMWRITE_GIF_LOOP = 1024, //!< Not functional since 4.12.0. Replaced by cv::Animation::loop_count. IMWRITE_GIF_SPEED = 1025, //!< Not functional since 4.12.0. Replaced by cv::Animation::durations. IMWRITE_GIF_QUALITY = 1026, //!< For GIF, it can be a quality from 1 to 8. Default is 2. See cv::ImwriteGifCompressionFlags. @@ -184,7 +185,7 @@ enum ImwriteTiffResolutionUnitFlags { }; enum ImwriteEXRTypeFlags { - /*IMWRITE_EXR_TYPE_UNIT = 0, //!< not supported */ + // IMWRITE_EXR_TYPE_UNIT = 0, // not supported IMWRITE_EXR_TYPE_HALF = 1, //!< store as HALF (FP16) IMWRITE_EXR_TYPE_FLOAT = 2 //!< store as FP32 (default) }; @@ -245,6 +246,12 @@ enum ImwriteHDRCompressionFlags { IMWRITE_HDR_COMPRESSION_RLE = 1 }; +//! Imwrite BMP specific values for IMWRITE_BMP_COMPRESSION parameter key. +enum ImwriteBMPCompressionFlags { + IMWRITE_BMP_COMPRESSION_RGB = 0, //!< Use BI_RGB. OpenCV v4.12.0 or before supports to encode with this compression only. + IMWRITE_BMP_COMPRESSION_BITFIELDS = 3, //!< Use BI_BITFIELDS. OpenCV v4.13.0 or later can support to encode with this compression. (only for 32 BPP images) +}; + //! Imwrite GIF specific values for IMWRITE_GIF_QUALITY parameter key, if larger than 3, then its related to the size of the color table. enum ImwriteGIFCompressionFlags { IMWRITE_GIF_FAST_NO_DITHER = 1, @@ -264,8 +271,9 @@ enum ImageMetadataType IMAGE_METADATA_EXIF = 0, // EXIF metadata (e.g., camera info, GPS, orientation) IMAGE_METADATA_XMP = 1, // XMP metadata (eXtensible Metadata Platform - Adobe format) IMAGE_METADATA_ICCP = 2, // ICC Profile (color profile for color management) + IMAGE_METADATA_CICP = 3, // cICP Profile (video signal type) - IMAGE_METADATA_MAX = 2 // Highest valid index (usually used for bounds checking) + IMAGE_METADATA_MAX = 3 // Highest valid index (usually used for bounds checking) }; //! @} imgcodecs_flags @@ -498,6 +506,11 @@ filename extension (see cv::imread for the list of extensions). In general, only single-channel or 3-channel (with 'BGR' channel order) images can be saved using this function, with these exceptions: +- With BMP encoder, 8-bit unsigned (CV_8U) images can be saved. + - BMP images with an alpha channel can be saved using this function. + To achieve this, create an 8-bit 4-channel (CV_8UC4) BGRA image, ensuring the alpha channel is the last component. + Fully transparent pixels should have an alpha value of 0, while fully opaque pixels should have an alpha value of 255. + OpenCV v4.13.0 or later use BI_BITFIELDS compression as default. See IMWRITE_BMP_COMPRESSION. - With OpenEXR encoder, only 32-bit float (CV_32F) images can be saved. More than 4 channels can be saved. (imread can load it then.) - 8-bit unsigned (CV_8U) images are not supported. - With Radiance HDR encoder, non 64-bit float (CV_64F) images can be saved. diff --git a/modules/imgcodecs/src/grfmt_bmp.cpp b/modules/imgcodecs/src/grfmt_bmp.cpp index a8ca6a046a..faff17811e 100644 --- a/modules/imgcodecs/src/grfmt_bmp.cpp +++ b/modules/imgcodecs/src/grfmt_bmp.cpp @@ -42,6 +42,7 @@ #include "precomp.hpp" #include "grfmt_bmp.hpp" +#include "opencv2/core/utils/logger.hpp" namespace cv { @@ -603,6 +604,7 @@ BmpEncoder::BmpEncoder() { m_description = "Windows bitmap (*.bmp;*.dib)"; m_buf_supported = true; + m_supported_encode_key = {IMWRITE_BMP_COMPRESSION}; } @@ -615,11 +617,12 @@ ImageEncoder BmpEncoder::newEncoder() const return makePtr(); } -bool BmpEncoder::write( const Mat& img, const std::vector& ) +bool BmpEncoder::write( const Mat& img, const std::vector& params ) { int width = img.cols, height = img.rows, channels = img.channels(); int fileStep = (width*channels + 3) & -4; uchar zeropad[] = "\0\0\0\0"; + WLByteStream strm; if( m_buf ) @@ -630,7 +633,35 @@ bool BmpEncoder::write( const Mat& img, const std::vector& ) else if( !strm.open( m_filename )) return false; - int bitmapHeaderSize = 40; + // sRGB colorspace requires BITMAPV5HEADER. + // See https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapv5header + bool useV5BitFields = true; + for(size_t i = 0 ; i < params.size(); i++) + { + const int value = params[i+1]; + switch(params[i]) + { + case IMWRITE_BMP_COMPRESSION: + { + switch(value) { + case IMWRITE_BMP_COMPRESSION_RGB: + useV5BitFields = false; + break; + case IMWRITE_BMP_COMPRESSION_BITFIELDS: + useV5BitFields = true; + break; + default: + useV5BitFields = true; + CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_BMP_COMPRESSION must be one of ImwriteBMPCompressionFlags. It is fallbacked to true", value)); + break; + } + } + break; + } + } + useV5BitFields &= (channels == 4); // BMP_BITFIELDS requires 32 bit per pixel. + + int bitmapHeaderSize = useV5BitFields ? 124 : 40; int paletteSize = channels > 1 ? 0 : 1024; int headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize; size_t fileSize = (size_t)fileStep*height + headerSize; @@ -653,13 +684,36 @@ bool BmpEncoder::write( const Mat& img, const std::vector& ) CHECK_WRITE(strm.putDWord( height )); CHECK_WRITE(strm.putWord( 1 )); CHECK_WRITE(strm.putWord( channels << 3 )); - CHECK_WRITE(strm.putDWord( BMP_RGB )); + CHECK_WRITE(strm.putDWord( useV5BitFields ? BMP_BITFIELDS : BMP_RGB )); CHECK_WRITE(strm.putDWord( 0 )); CHECK_WRITE(strm.putDWord( 0 )); CHECK_WRITE(strm.putDWord( 0 )); CHECK_WRITE(strm.putDWord( 0 )); CHECK_WRITE(strm.putDWord( 0 )); + if( useV5BitFields ) + { + CHECK_WRITE(strm.putDWord( 0x00FF0000 )); // bV5RedMask + CHECK_WRITE(strm.putDWord( 0x0000FF00 )); // bV5GreenMask + CHECK_WRITE(strm.putDWord( 0x000000FF )); // bV5BlueMask + CHECK_WRITE(strm.putDWord( 0xFF000000 )); // bV5AlphaMask + CHECK_WRITE(strm.putBytes( "BGRs", 4)); // bV5CSType (sRGB) + { // bV5Endpoints + for(int index_rgb = 0; index_rgb < 3; index_rgb ++ ){ // Red/Green/Blue + CHECK_WRITE(strm.putDWord( 0 )); // ciexyzX + CHECK_WRITE(strm.putDWord( 0 )); // ciexyzY + CHECK_WRITE(strm.putDWord( 0 )); // ciexyzZ + } + } + CHECK_WRITE(strm.putDWord( 0 )); // bV5GammaRed + CHECK_WRITE(strm.putDWord( 0 )); // bV5GammaGreen + CHECK_WRITE(strm.putDWord( 0 )); // bV5GammaBlue + CHECK_WRITE(strm.putDWord( 0 )); // bV5Intent + CHECK_WRITE(strm.putDWord( 0 )); // bV5ProfileData + CHECK_WRITE(strm.putDWord( 0 )); // bV5ProfileSize + CHECK_WRITE(strm.putDWord( 0 )); // bV5Reserved + } + if( channels == 1 ) { FillGrayPalette( palette, 8 ); diff --git a/modules/imgcodecs/src/grfmt_png.cpp b/modules/imgcodecs/src/grfmt_png.cpp index 9a93f68b70..4ae933e2bb 100644 --- a/modules/imgcodecs/src/grfmt_png.cpp +++ b/modules/imgcodecs/src/grfmt_png.cpp @@ -901,6 +901,7 @@ PngEncoder::PngEncoder() m_support_metadata[IMAGE_METADATA_EXIF] = true; m_support_metadata[IMAGE_METADATA_XMP] = true; m_support_metadata[IMAGE_METADATA_ICCP] = true; + m_support_metadata[IMAGE_METADATA_CICP] = true; op_zstream1.zalloc = NULL; op_zstream2.zalloc = NULL; next_seq_num = 0; @@ -1116,6 +1117,16 @@ bool PngEncoder::write( const Mat& img, const std::vector& params ) #endif static_cast(iccp.size())); } + + std::vector& cicp = m_metadata[IMAGE_METADATA_CICP]; + if (!cicp.empty()) { +#ifdef PNG_cICP_SUPPORTED + CV_CheckEQ((size_t)4, cicp.size(), "The cICP chunk consists of four 1-byte unsigned integers"); + png_set_cICP(png_ptr, info_ptr, cicp[0], cicp[1], cicp[2], cicp[3]); +#else + CV_LOG_WARNING(NULL, "Libpng is too old and does not support cICP."); +#endif + } } png_write_info( png_ptr, info_ptr ); diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp index ac1ecb4b8e..08accd3bbd 100644 --- a/modules/imgcodecs/test/test_grfmt.cpp +++ b/modules/imgcodecs/test/test_grfmt.cpp @@ -360,7 +360,16 @@ TEST(Imgcodecs_Bmp, read_32bit_rgb) const string root = cvtest::TS::ptr()->get_data_path(); const string filenameInput = root + "readwrite/test_32bit_rgb.bmp"; - const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED); + Mat img; + ASSERT_NO_THROW(img = cv::imread(filenameInput)); + ASSERT_FALSE(img.empty()); + ASSERT_EQ(CV_8UC3, img.type()); + + ASSERT_NO_THROW(img = cv::imread(filenameInput, IMREAD_UNCHANGED)); + ASSERT_FALSE(img.empty()); + ASSERT_EQ(CV_8UC3, img.type()); + + ASSERT_NO_THROW(img = cv::imread(filenameInput, IMREAD_COLOR | IMREAD_ANYCOLOR | IMREAD_ANYDEPTH)); ASSERT_FALSE(img.empty()); ASSERT_EQ(CV_8UC3, img.type()); } @@ -427,6 +436,55 @@ TEST(Imgcodecs_Bmp, rgba_scale) ASSERT_EQ(data[0], 255); } +typedef testing::TestWithParam Imgcodecs_bmp_compress; +TEST_P(Imgcodecs_bmp_compress, rgba32bpp) +{ + const ImwriteBMPCompressionFlags comp = GetParam(); + + RNG rng = theRNG(); + Mat src(256, 256, CV_8UC4); + rng.fill(src, RNG::UNIFORM, Scalar(0,0,0,0), Scalar(255,255,255,255)); + + vector buf; + bool ret = false; + ASSERT_NO_THROW(ret = cv::imencode(".bmp", src, buf, {IMWRITE_BMP_COMPRESSION, static_cast(comp)})); + ASSERT_TRUE(ret); + + ASSERT_EQ(buf[0x0e], comp == IMWRITE_BMP_COMPRESSION_RGB ? 40 : 124 ); // the size of header + ASSERT_EQ(buf[0x0f], 0); + ASSERT_EQ(buf[0x1c], 32); // the number of bits per pixel = 32 + ASSERT_EQ(buf[0x1d], 0); + ASSERT_EQ(buf[0x1e], static_cast(comp)); // the compression method + ASSERT_EQ(buf[0x1f], 0); + ASSERT_EQ(buf[0x20], 0); + ASSERT_EQ(buf[0x21], 0); + + Mat dst; + ASSERT_NO_THROW(dst = cv::imdecode(buf, IMREAD_UNCHANGED)); + ASSERT_FALSE(dst.empty()); + + if(comp == IMWRITE_BMP_COMPRESSION_RGB) + { + // If BI_RGB is used, output BMP file stores RGB image. + ASSERT_EQ(CV_8UC3, dst.type()); + Mat srcBGR; + cv::cvtColor(src, srcBGR, cv::COLOR_BGRA2BGR); + EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), srcBGR, dst); + } + else + { + // If BI_BITFIELDS is used, output BMP file stores RGBA image. + ASSERT_EQ(CV_8UC4, dst.type()); + EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), src, dst); + } + +} +INSTANTIATE_TEST_CASE_P(All, + Imgcodecs_bmp_compress, + testing::Values( + IMWRITE_BMP_COMPRESSION_RGB, + IMWRITE_BMP_COMPRESSION_BITFIELDS)); + #ifdef HAVE_IMGCODEC_HDR TEST(Imgcodecs_Hdr, regression) { diff --git a/modules/imgcodecs/test/test_precomp.hpp b/modules/imgcodecs/test/test_precomp.hpp index d2095932e8..67c5e95168 100644 --- a/modules/imgcodecs/test/test_precomp.hpp +++ b/modules/imgcodecs/test/test_precomp.hpp @@ -80,6 +80,23 @@ void PrintTo(const ImreadModes& val, std::ostream* os) *os << "IMREAD_UNKNOWN(" << (int)v << ")"; } +static inline +void PrintTo(const ImwriteBMPCompressionFlags& val, std::ostream* os) +{ + switch(val) + { + case IMWRITE_BMP_COMPRESSION_RGB: + *os << "IMWRITE_BMP_COMPRESSION_RGB"; + break; + case IMWRITE_BMP_COMPRESSION_BITFIELDS: + *os << "IMWRITE_BMP_COMPRESSION_BITFIELDS"; + break; + default: + *os << "IMWRITE_BMP_COMPRESSION_UNKNOWN(" << (int)val << ")"; + break; + } +} + } // namespace #endif diff --git a/modules/imgproc/src/bilateral_filter.dispatch.cpp b/modules/imgproc/src/bilateral_filter.dispatch.cpp index 9ac499f685..8e0f1f5a95 100644 --- a/modules/imgproc/src/bilateral_filter.dispatch.cpp +++ b/modules/imgproc/src/bilateral_filter.dispatch.cpp @@ -410,7 +410,16 @@ static bool ipp_bilateralFilter(Mat &src, Mat &dst, int d, double sigmaColor, do if(!ok) return false; - parallel_for_(range, invoker, threads*4); + // Tile height can't be smaller than the radius. + // Otherwise, the second tile has mixed top border (pixels from both + // inmem and outside should be used), which is not supported in IPP. + int maxTiles = (int)iwDst.m_size.height / radius; + int numTiles = threads * 4; + if (numTiles > maxTiles) { + // Keep the tiles number as multiple of threads for the better workload balance. + numTiles = (maxTiles / threads) * threads; + } + parallel_for_(range, invoker, numTiles); if(!ok) return false; diff --git a/modules/imgproc/test/test_fitellipse.cpp b/modules/imgproc/test/test_fitellipse.cpp index cb3afea3d7..215b318e26 100644 --- a/modules/imgproc/test/test_fitellipse.cpp +++ b/modules/imgproc/test/test_fitellipse.cpp @@ -8,31 +8,22 @@ namespace opencv_test { namespace { -// return true if point lies inside ellipse -static bool check_pt_in_ellipse(const Point2f& pt, const RotatedRect& el) { - Point2f to_pt = pt - el.center; - double el_angle = el.angle * CV_PI / 180; +static double algebraic_dist(const Point2f& pt, const RotatedRect& el) { + const Point2d to_pt = pt - el.center; + const double el_angle = el.angle * CV_PI / 180; const Point2d to_pt_el( to_pt.x * cos(-el_angle) - to_pt.y * sin(-el_angle), to_pt.x * sin(-el_angle) + to_pt.y * cos(-el_angle)); - const double pt_angle = atan2(to_pt_el.y / el.size.height, to_pt_el.x / el.size.width); - const double x_dist = 0.5 * el.size.width * cos(pt_angle); - const double y_dist = 0.5 * el.size.height * sin(pt_angle); - double el_dist = sqrt(x_dist * x_dist + y_dist * y_dist); - return cv::norm(to_pt) < el_dist; + return normL2Sqr(Point2d(2 * to_pt_el.x / el.size.width, 2 * to_pt_el.y / el.size.height)) - 1; } -// Return true if mass center of fitted points lies inside ellipse -static bool fit_and_check_ellipse(const vector& pts) { - RotatedRect ellipse = fitEllipseDirect(pts); // fitEllipseAMS() also works fine - - Point2f mass_center; - for (size_t i = 0; i < pts.size(); i++) { - mass_center += pts[i]; +static double rms_algebraic_dist(const vector& pts, const RotatedRect& el) { + double sum_algebraic_dists_sqr = 0; + for (const auto& pt : pts) { + const auto pt_algebraic_dist = algebraic_dist(pt, el); + sum_algebraic_dists_sqr += pt_algebraic_dist * pt_algebraic_dist; } - mass_center /= (float)pts.size(); - - return check_pt_in_ellipse(mass_center, ellipse); + return sqrt(sum_algebraic_dists_sqr / pts.size()); } TEST(Imgproc_FitEllipse_Issue_4515, accuracy) { @@ -50,7 +41,8 @@ TEST(Imgproc_FitEllipse_Issue_4515, accuracy) { pts.push_back(Point2f(333, 319)); pts.push_back(Point2f(333, 320)); - EXPECT_TRUE(fit_and_check_ellipse(pts)); + const RotatedRect ellipse = fitEllipseDirect(pts); // fitEllipseAMS() also works fine + EXPECT_LT(rms_algebraic_dist(pts, ellipse), 1e-1); } TEST(Imgproc_FitEllipse_Issue_6544, accuracy) { @@ -66,18 +58,17 @@ TEST(Imgproc_FitEllipse_Issue_6544, accuracy) { pts.push_back(Point2f(929.145f, 744.976f)); pts.push_back(Point2f(917.474f, 791.823f)); - EXPECT_TRUE(fit_and_check_ellipse(pts)); + const RotatedRect ellipse = fitEllipseDirect(pts); // fitEllipseAMS() also works fine + EXPECT_LT(rms_algebraic_dist(pts, ellipse), 5e-2); } TEST(Imgproc_FitEllipse_Issue_10270, accuracy) { vector pts; - float scale = 1; - Point2f shift(0, 0); - pts.push_back(Point2f(0, 1)*scale+shift); - pts.push_back(Point2f(0, 2)*scale+shift); - pts.push_back(Point2f(0, 3)*scale+shift); - pts.push_back(Point2f(2, 3)*scale+shift); - pts.push_back(Point2f(0, 4)*scale+shift); + pts.push_back(Point2f(0, 1)); + pts.push_back(Point2f(0, 2)); + pts.push_back(Point2f(0, 3)); + pts.push_back(Point2f(2, 3)); + pts.push_back(Point2f(0, 4)); // check that we get almost vertical ellipse centered around (1, 3) RotatedRect e = fitEllipse(pts); @@ -89,13 +80,11 @@ TEST(Imgproc_FitEllipse_Issue_10270, accuracy) { TEST(Imgproc_FitEllipse_JavaCase, accuracy) { vector pts; - float scale = 1; - Point2f shift(0, 0); - pts.push_back(Point2f(0, 0)*scale+shift); - pts.push_back(Point2f(1, 1)*scale+shift); - pts.push_back(Point2f(-1, 1)*scale+shift); - pts.push_back(Point2f(-1, -1)*scale+shift); - pts.push_back(Point2f(1, -1)*scale+shift); + pts.push_back(Point2f(0, 0)); + pts.push_back(Point2f(1, 1)); + pts.push_back(Point2f(-1, 1)); + pts.push_back(Point2f(-1, -1)); + pts.push_back(Point2f(1, -1)); // check that we get almost circle centered around (0, 0) RotatedRect e = fitEllipse(pts); diff --git a/modules/objdetect/doc/objdetect.bib b/modules/objdetect/doc/objdetect.bib index f3623732d5..9f7f06e672 100644 --- a/modules/objdetect/doc/objdetect.bib +++ b/modules/objdetect/doc/objdetect.bib @@ -16,7 +16,8 @@ title = {{AprilTag} 2: Efficient and robust fiducial detection}, booktitle = {Proceedings of the {IEEE/RSJ} International Conference on Intelligent Robots and Systems {(IROS)}}, year = {2016}, - month = {October} + month = {October}, + url = {https://april.eecs.umich.edu/pdfs/wang2016iros.pdf} } @mastersthesis{Xiangmin2015research, diff --git a/modules/python/src2/cv2_convert.cpp b/modules/python/src2/cv2_convert.cpp index 8ce800d785..b27cd5e048 100644 --- a/modules/python/src2/cv2_convert.cpp +++ b/modules/python/src2/cv2_convert.cpp @@ -270,10 +270,12 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info) const int sz2 = 4; // Scalar has 4 elements. m = Mat::zeros(sz2, 1, CV_64F); + // Fill the Mat with array elements + bool filled = true; const char *base_ptr = PyArray_BYTES(oarr); - for(int i = 0; i < sz; i++ ) + for(int i = 0; i < sz && filled; i++ ) { - PyObject* oi = PyArray_GETITEM(oarr, base_ptr + step[0] * i); + PyObject* oi = PyArray_GETITEM(oarr, base_ptr + step[0] * i); // new object if( PyInt_Check(oi) ) m.at(i) = (double)PyInt_AsLong(oi); else if( PyFloat_Check(oi) ) @@ -282,10 +284,16 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info) { failmsg("%s has some non-numerical elements", info.name); m.release(); - return false; + filled = false; } + + Py_DECREF(oi); } - return true; + + if(needcopy) + Py_DECREF(o); + + return filled; } // handle degenerate case diff --git a/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp b/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp index 9554d7117f..8b169e7476 100644 --- a/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp @@ -188,7 +188,7 @@ public: protected: template - void feed(const std::vector &corners, const std::vector &images, + void feedWithStrategy(const std::vector &corners, const std::vector &images, const std::vector > &masks); private: diff --git a/modules/stitching/src/exposure_compensate.cpp b/modules/stitching/src/exposure_compensate.cpp index 40cb58fd15..3d693d136c 100644 --- a/modules/stitching/src/exposure_compensate.cpp +++ b/modules/stitching/src/exposure_compensate.cpp @@ -460,7 +460,7 @@ void ChannelsCompensator::setMatGains(std::vector& umv) template -void BlocksCompensator::feed(const std::vector &corners, const std::vector &images, +void BlocksCompensator::feedWithStrategy(const std::vector &corners, const std::vector &images, const std::vector > &masks) { CV_Assert(corners.size() == images.size() && images.size() == masks.size()); @@ -605,13 +605,13 @@ void BlocksCompensator::setMatGains(std::vector& umv) void BlocksGainCompensator::feed(const std::vector &corners, const std::vector &images, const std::vector > &masks) { - BlocksCompensator::feed(corners, images, masks); + BlocksCompensator::feedWithStrategy(corners, images, masks); } void BlocksChannelsCompensator::feed(const std::vector &corners, const std::vector &images, const std::vector > &masks) { - BlocksCompensator::feed(corners, images, masks); + BlocksCompensator::feedWithStrategy(corners, images, masks); } diff --git a/modules/videoio/cmake/detect_ffmpeg.cmake b/modules/videoio/cmake/detect_ffmpeg.cmake index aa669f36b0..1d4faa8394 100644 --- a/modules/videoio/cmake/detect_ffmpeg.cmake +++ b/modules/videoio/cmake/detect_ffmpeg.cmake @@ -27,11 +27,6 @@ set(_used_ffmpeg_libraries ${_required_ffmpeg_libraries}) if(NOT HAVE_FFMPEG AND PKG_CONFIG_FOUND) ocv_check_modules(FFMPEG libavcodec libavformat libavutil libswscale) if(FFMPEG_FOUND) - ocv_check_modules(FFMPEG_libavresample libavresample) # optional - if(FFMPEG_libavresample_FOUND) - list(APPEND FFMPEG_LIBRARIES ${FFMPEG_libavresample_LIBRARIES}) - list(APPEND _used_ffmpeg_libraries libavresample) - endif() if(OPENCV_FFMPEG_ENABLE_LIBAVDEVICE) ocv_check_modules(FFMPEG_libavdevice libavdevice) # optional if(FFMPEG_libavdevice_FOUND) @@ -60,7 +55,6 @@ if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER) set(_min_libavformat_version 54.20.4) set(_min_libavutil_version 52.3.0) set(_min_libswscale_version 2.1.1) - set(_min_libavresample_version 1.0.1) set(_min_libavdevice_version 53.2.0) foreach(ffmpeg_lib ${_used_ffmpeg_libraries}) if(FFMPEG_${ffmpeg_lib}_VERSION VERSION_LESS _min_${ffmpeg_lib}_version) @@ -77,7 +71,6 @@ if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER) unset(_min_libavformat_version) unset(_min_libavutil_version) unset(_min_libswscale_version) - unset(_min_libavresample_version) unset(_min_libavdevice_version) endif() diff --git a/modules/videoio/doc/videoio_overview.markdown b/modules/videoio/doc/videoio_overview.markdown index 8dcc923efb..73adbff7c8 100644 --- a/modules/videoio/doc/videoio_overview.markdown +++ b/modules/videoio/doc/videoio_overview.markdown @@ -81,7 +81,7 @@ Use 3rd party drivers or cameras Many industrial cameras or some video I/O devices don't provide standard driver interfaces for the operating system. Thus you can't use VideoCapture or VideoWriter with these devices. -To get access to their devices, manufactures provide their own C++ API and library that you have to +To get access to their devices, manufacturers provide their own C++ API and library that you have to include and link with your OpenCV application. It is a common case that these libraries read/write images from/to a memory buffer. If so, it is possible to make a `Mat` header for memory buffer (user-allocated data) and process it diff --git a/modules/videoio/misc/plugin_ffmpeg/CMakeLists.txt b/modules/videoio/misc/plugin_ffmpeg/CMakeLists.txt index fa8b277e00..cdd948c51e 100644 --- a/modules/videoio/misc/plugin_ffmpeg/CMakeLists.txt +++ b/modules/videoio/misc/plugin_ffmpeg/CMakeLists.txt @@ -15,7 +15,6 @@ message(STATUS "FFMPEG_libavcodec_VERSION=${FFMPEG_libavcodec_VERSION}") message(STATUS "FFMPEG_libavformat_VERSION=${FFMPEG_libavformat_VERSION}") message(STATUS "FFMPEG_libavutil_VERSION=${FFMPEG_libavutil_VERSION}") message(STATUS "FFMPEG_libswscale_VERSION=${FFMPEG_libswscale_VERSION}") -message(STATUS "FFMPEG_libavresample_VERSION=${FFMPEG_libavresample_VERSION}") if(OPENCV_FFMPEG_ENABLE_LIBAVDEVICE) message(STATUS "FFMPEG_libavdevice_VERSION=${FFMPEG_libavdevice_VERSION}") endif() diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp index 5780b4c113..7ce18fdfbf 100644 --- a/modules/videoio/src/cap_ffmpeg_impl.hpp +++ b/modules/videoio/src/cap_ffmpeg_impl.hpp @@ -607,6 +607,7 @@ struct CvCapture_FFMPEG int hw_device; int use_opencl; int extraDataIdx; + int requestedThreads; }; void CvCapture_FFMPEG::init() @@ -658,6 +659,7 @@ void CvCapture_FFMPEG::init() hw_device = -1; use_opencl = 0; extraDataIdx = 1; + requestedThreads = cv::getNumberOfCPUs(); } @@ -686,7 +688,7 @@ void CvCapture_FFMPEG::close() { #ifdef CV_FFMPEG_CODECPAR // avcodec_close removed in FFmpeg release 8.0 -# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(62, 11, 100)) +# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(61, 9, 108)) avcodec_close( context ); # endif #endif @@ -993,13 +995,7 @@ inline void fill_codec_context(AVCodecContext * enc, AVDictionary * dict) if (!enc->thread_count) { int nCpus = cv::getNumberOfCPUs(); - int requestedThreads = std::min(nCpus, 16); // [OPENCV:FFMPEG:24] Application has requested XX threads. Using a thread count greater than 16 is not recommended. - std::string threads_option = utils::getConfigurationParameterString("OPENCV_FFMPEG_THREADS"); - if (!threads_option.empty()) - { - requestedThreads = atoi(threads_option.c_str()); - } - enc->thread_count = requestedThreads; + enc->thread_count = std::min(nCpus, 16); // [OPENCV:FFMPEG:24] Application has requested XX threads. Using a thread count greater than 16 is not recommended. } AVDictionaryEntry* avdiscard_entry = av_dict_get(dict, "avdiscard", NULL, 0); @@ -1120,7 +1116,7 @@ bool CvCapture_FFMPEG::open(const char* _filename, const Ptr& str #endif if (params.has(CAP_PROP_N_THREADS)) { - nThreads = params.get(CAP_PROP_N_THREADS); + nThreads = requestedThreads = params.get(CAP_PROP_N_THREADS); } if (params.warnUnusedParameters()) { @@ -1129,6 +1125,15 @@ bool CvCapture_FFMPEG::open(const char* _filename, const Ptr& str } } + if (params.empty() || !params.has(CAP_PROP_N_THREADS)) + { + std::string threads_option = utils::getConfigurationParameterString("OPENCV_FFMPEG_THREADS"); + if (!threads_option.empty()) + { + nThreads = requestedThreads = atoi(threads_option.c_str()); + } + } + #if USE_AV_INTERRUPT_CALLBACK /* interrupt callback */ interrupt_metadata.timeout_after_ms = open_timeout; @@ -1719,7 +1724,17 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, if (!sw_picture || !sw_picture->data[0]) return false; - CV_LOG_DEBUG(NULL, "Input picture format: " << av_get_pix_fmt_name((AVPixelFormat)sw_picture->format)); +#if LIBAVUTIL_BUILD >= CALC_FFMPEG_VERSION(56, 72, 0) + const char* color_space_name = av_color_space_name(sw_picture->colorspace); +#else + const char* color_space_name = av_get_colorspace_name(sw_picture->colorspace); +#endif + CV_LOG_DEBUG(NULL, "Input picture format: " << av_get_pix_fmt_name((AVPixelFormat)sw_picture->format) + << ", colorspace: " << color_space_name + << ", range: " << av_color_range_name(sw_picture->color_range) + << ", primaries: " << av_color_primaries_name(sw_picture->color_primaries) + << ", transfer: " << av_color_transfer_name(sw_picture->color_trc) + ); const AVPixelFormat result_format = convertRGB ? AV_PIX_FMT_BGR24 : (AVPixelFormat)sw_picture->format; switch (result_format) { @@ -1739,6 +1754,51 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, frame.height != video_st->CV_FFMPEG_CODEC_FIELD->height || frame.data == NULL ) { +#if LIBSWSCALE_BUILD >= CALC_FFMPEG_VERSION(6, 4, 100) + int buffer_width = video_st->CV_FFMPEG_CODEC_FIELD->width; + int buffer_height = video_st->CV_FFMPEG_CODEC_FIELD->height; + + // Reproduce sws_getCachedContext but with threads option + int64_t src_h_chr_pos = -513, dst_h_chr_pos = -513, + src_v_chr_pos = -513, dst_v_chr_pos = -513; + if (img_convert_ctx) + { + av_opt_get_int(img_convert_ctx, "src_h_chr_pos", 0, &src_h_chr_pos); + av_opt_get_int(img_convert_ctx, "src_v_chr_pos", 0, &src_v_chr_pos); + av_opt_get_int(img_convert_ctx, "dst_h_chr_pos", 0, &dst_h_chr_pos); + av_opt_get_int(img_convert_ctx, "dst_v_chr_pos", 0, &dst_v_chr_pos); + sws_freeContext(img_convert_ctx); + img_convert_ctx = NULL; + } + + img_convert_ctx = sws_alloc_context(); + if (img_convert_ctx == NULL) + return false;//CV_Error(0, "Cannot initialize the conversion context!"); + + av_opt_set_int(img_convert_ctx, "sws_flags", SWS_BICUBIC, 0); + av_opt_set_int(img_convert_ctx, "threads", requestedThreads, 0); + + if (swscale_version() < CALC_FFMPEG_VERSION(8, 12, 100)) + { + av_opt_set_int(img_convert_ctx, "src_h_chr_pos", src_h_chr_pos, 0); + av_opt_set_int(img_convert_ctx, "src_v_chr_pos", src_v_chr_pos, 0); + av_opt_set_int(img_convert_ctx, "dst_h_chr_pos", dst_h_chr_pos, 0); + av_opt_set_int(img_convert_ctx, "dst_v_chr_pos", dst_v_chr_pos, 0); + av_opt_set_int(img_convert_ctx, "srcw", buffer_width, 0); + av_opt_set_int(img_convert_ctx, "srch", buffer_height, 0); + av_opt_set_int(img_convert_ctx, "dstw", buffer_width, 0); + av_opt_set_int(img_convert_ctx, "dsth", buffer_height, 0); + av_opt_set_pixel_fmt(img_convert_ctx, "src_format", (AVPixelFormat)sw_picture->format, 0); + av_opt_set_pixel_fmt(img_convert_ctx, "dst_format", result_format, 0); + av_opt_set_double(img_convert_ctx, "param0", SWS_PARAM_DEFAULT, 0); + av_opt_set_double(img_convert_ctx, "param1", SWS_PARAM_DEFAULT, 0); + + if (sws_init_context(img_convert_ctx, NULL, NULL) < 0) { + sws_freeContext(img_convert_ctx); + img_convert_ctx = NULL; + } + } +#else // Some sws_scale optimizations have some assumptions about alignment of data/step/width/height // Also we use coded_width/height to workaround problem with legacy ffmpeg versions (like n0.8) int buffer_width = context->coded_width, buffer_height = context->coded_height; @@ -1752,6 +1812,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, SWS_BICUBIC, NULL, NULL, NULL ); +#endif if (img_convert_ctx == NULL) return false;//CV_Error(0, "Cannot initialize the conversion context!"); @@ -1781,6 +1842,9 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, frame.step = rgb_picture.linesize[0]; } +#if LIBSWSCALE_BUILD >= CALC_FFMPEG_VERSION(6, 4, 100) + sws_scale_frame(img_convert_ctx, &rgb_picture, sw_picture); +#else sws_scale( img_convert_ctx, sw_picture->data, @@ -1789,6 +1853,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, rgb_picture.data, rgb_picture.linesize ); +#endif *data = frame.data; *step = frame.step; @@ -2009,7 +2074,7 @@ void CvCapture_FFMPEG::get_rotation_angle() #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(57, 68, 100) const uint8_t *data = 0; // av_stream_get_side_data removed in FFmpeg release 8.0 -# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(62, 11, 100)) +# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(61, 9, 108)) data = av_stream_get_side_data(video_st, AV_PKT_DATA_DISPLAYMATRIX, NULL); # else AVPacketSideData* sd = video_st->codecpar->coded_side_data; @@ -2017,7 +2082,10 @@ void CvCapture_FFMPEG::get_rotation_angle() if (sd && nb_sd > 0) { const AVPacketSideData* mtx = av_packet_side_data_get(sd, nb_sd, AV_PKT_DATA_DISPLAYMATRIX); - data = mtx->data; + if (mtx) + { + data = mtx->data; + } } # endif if (data) @@ -2519,9 +2587,9 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int if (!encode_video) { CV_Assert(cn == 1 && ((width > 0 && height == 1) || (width == 1 && height > 0 && step == 1))); const bool set_key_frame = key_frame ? key_frame : idr_period ? frame_idx % idr_period == 0 : 1; - bool ret = icv_av_encapsulate_video_FFMPEG(oc, video_st, context, (uint8_t*)data, width, frame_idx, pts_index, b_frame_dts_delay, set_key_frame); + int ret = icv_av_encapsulate_video_FFMPEG(oc, video_st, context, (uint8_t*)data, width, frame_idx, pts_index, b_frame_dts_delay, set_key_frame); frame_idx++; - return ret; + return ret == 0; } // check parameters