Re: [FFmpeg-devel] [PATCH WIP 01/10] ffbuild/bin2c: Use zlib directly instead of gzip
> -Original Message- > From: ffmpeg-devel On Behalf Of > Andreas Rheinhardt > Sent: Dienstag, 3. Juni 2025 16:34 > To: ffmpeg-devel@ffmpeg.org > Subject: Re: [FFmpeg-devel] [PATCH WIP 01/10] ffbuild/bin2c: Use zlib > directly instead of gzip > Hi Andreas, thinking about the direction of this patchset, I came to this idea: How about ditching zlib altogether for this and replace it with some compact compression code right away? Something like these might be suitable: https://github.com/ariya/FastLZ/blob/master/fastlz.c https://github.com/richgel999/miniz/blob/master/miniz.c (licenses should be compatible for including the code) This would solve both problems: - zlib detection during build - zlib being unavailable at runtime when linked dynamically How do you think about this? I think it wouldn't matter when the compression is slightly less effective.. Best regards sw ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
Hi Pavel On Tue, Jun 10, 2025 at 11:27:37AM -0600, Pavel Koshevoy wrote: > On Tue, Jun 10, 2025 at 9:29 AM Michael Niedermayer [...] > I have never had any intention of introducing a > security vulnerability. do you agree that the patch should be reverted ? (and also the 2 backports of it) > If people want to keep this, it should be behind a flag and > > disabled by default. > > > I am not familiar with such flags ... are you suggesting a compile-time > flag, or a run-time flag? > A runtime flag would be preferable, because that would save me from having > to cross-compile win64 ffmpeg libs myself. runtime > > > Its not enough to fix our code that crashes, other applications > > similarly wont expect such id and type changes mid stream > > > IDK how likely a media type change is outside the 1_poc.mp4. 100% likelyness an exploit of this will use it > The sample > files I have don't do that. Your sample files are not exploits i assume. So obviously they dont > I can provide a 61MB clip of one such file, just a few seconds of SDR mpeg2 > video/audio slate followed by a few seconds of HDR10 hevc video and eac3 > audio... in case someone wants to work on making fftools support this. This file certainly is valuable and should be added to samples.ffmpeg.org BUT this security issue needs to be fixed, regardless of anyone adding support for such samples I dont think backporting midstream codec_id/type changes is a good idea btw. IMHO this should all be reverted (its a small 3 line patch) and then again start from scratch with review, testing, fuzzing, and runtime flag. PS: The researcher also wants a CVE# for this issue. thx [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB What is money laundering? Its paying someone and not telling the government. signature.asc Description: PGP signature ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 2/3] avutil/aes: remove superfluous rounds argument
It's set during int and never changed. Signed-off-by: James Almer --- libavutil/aes.c | 10 +- libavutil/aes_internal.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libavutil/aes.c b/libavutil/aes.c index 3c8ac1c349..7fe42a5548 100644 --- a/libavutil/aes.c +++ b/libavutil/aes.c @@ -137,10 +137,10 @@ static inline void aes_crypt(AVAES *a, int s, const uint8_t *sbox, } static void aes_encrypt(AVAES *a, uint8_t *dst, const uint8_t *src, -int count, uint8_t *iv, int rounds) +int count, uint8_t *iv) { while (count--) { -addkey_s(&a->state[1], src, &a->round_key[rounds]); +addkey_s(&a->state[1], src, &a->round_key[a->rounds]); if (iv) addkey_s(&a->state[1], iv, &a->state[1]); aes_crypt(a, 2, sbox, enc_multbl); @@ -153,10 +153,10 @@ static void aes_encrypt(AVAES *a, uint8_t *dst, const uint8_t *src, } static void aes_decrypt(AVAES *a, uint8_t *dst, const uint8_t *src, -int count, uint8_t *iv, int rounds) +int count, uint8_t *iv) { while (count--) { -addkey_s(&a->state[1], src, &a->round_key[rounds]); +addkey_s(&a->state[1], src, &a->round_key[a->rounds]); aes_crypt(a, 0, inv_sbox, dec_multbl); if (iv) { addkey_s(&a->state[0], iv, &a->state[0]); @@ -171,7 +171,7 @@ static void aes_decrypt(AVAES *a, uint8_t *dst, const uint8_t *src, void av_aes_crypt(AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt) { -a->crypt(a, dst, src, count, iv, a->rounds); +a->crypt(a, dst, src, count, iv); } static void init_multbl2(uint32_t tbl[][256], const int c[4], diff --git a/libavutil/aes_internal.h b/libavutil/aes_internal.h index 17f79d3ce3..e2de382f26 100644 --- a/libavutil/aes_internal.h +++ b/libavutil/aes_internal.h @@ -37,7 +37,7 @@ typedef struct AVAES { DECLARE_ALIGNED(16, av_aes_block, round_key)[15]; DECLARE_ALIGNED(16, av_aes_block, state)[2]; int rounds; -void (*crypt)(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int rounds); +void (*crypt)(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv); } AVAES; void ff_init_aes_x86(AVAES *a, int decrypt); -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 1/3] avutil/aes_ctr: rename AES_BLOCK_SIZE to FF_AES_BLOCK_SIZE
This is in preparation for the following commit, to prevent redefinitions from namespace collisions. Signed-off-by: James Almer --- libavutil/aes_ctr.c | 18 +- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libavutil/aes_ctr.c b/libavutil/aes_ctr.c index 63dcb20d3a..76333ede33 100644 --- a/libavutil/aes_ctr.c +++ b/libavutil/aes_ctr.c @@ -29,11 +29,11 @@ #include "mem.h" #include "random_seed.h" -#define AES_BLOCK_SIZE (16) +#define FF_AES_BLOCK_SIZE (16) typedef struct AVAESCTR { -DECLARE_ALIGNED(8, uint8_t, counter)[AES_BLOCK_SIZE]; -DECLARE_ALIGNED(8, uint8_t, encrypted_counter)[AES_BLOCK_SIZE]; +DECLARE_ALIGNED(8, uint8_t, counter)[FF_AES_BLOCK_SIZE]; +DECLARE_ALIGNED(8, uint8_t, encrypted_counter)[FF_AES_BLOCK_SIZE]; AVAES aes; } AVAESCTR; @@ -96,19 +96,19 @@ void av_aes_ctr_increment_iv(struct AVAESCTR *a) void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int count) { -while (count >= AES_BLOCK_SIZE) { +while (count >= FF_AES_BLOCK_SIZE) { av_aes_crypt(&a->aes, a->encrypted_counter, a->counter, 1, NULL, 0); av_aes_ctr_increment_be64(a->counter + 8); #if HAVE_FAST_64BIT -for (int len = 0; len < AES_BLOCK_SIZE; len += 8) +for (int len = 0; len < FF_AES_BLOCK_SIZE; len += 8) AV_WN64(&dst[len], AV_RN64(&src[len]) ^ AV_RN64A(&a->encrypted_counter[len])); #else -for (int len = 0; len < AES_BLOCK_SIZE; len += 4) +for (int len = 0; len < FF_AES_BLOCK_SIZE; len += 4) AV_WN32(&dst[len], AV_RN32(&src[len]) ^ AV_RN32A(&a->encrypted_counter[len])); #endif -dst += AES_BLOCK_SIZE; -src += AES_BLOCK_SIZE; -count -= AES_BLOCK_SIZE; +dst += FF_AES_BLOCK_SIZE; +src += FF_AES_BLOCK_SIZE; +count -= FF_AES_BLOCK_SIZE; } if (count > 0) { -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 3/3] avutil/aes: add an OpenSSL-libcrypto backed implementation
OpenSSL has optimizations for more architectures than x86-AESNI, so use it if libavutil is configured with libcrypto explicitly (Enabling OpenSSL alone will not make use of it). Signed-off-by: James Almer --- configure| 8 +++- libavutil/aes.c | 37 ++--- libavutil/aes_internal.h | 11 ++- libavutil/x86/aes_init.c | 2 ++ 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 534b443f7d..c7b4fbb2fe 100755 --- a/configure +++ b/configure @@ -223,6 +223,7 @@ External library support: --enable-libcelt enable CELT decoding via libcelt [no] --enable-libcdio enable audio CD grabbing with libcdio [no] --enable-libcodec2 enable codec2 en/decoding using libcodec2 [no] + --enable-libcrypto enable crypto via libcrypto (AES only) [no] --enable-libdav1denable AV1 decoding via libdav1d [no] --enable-libdavs2enable AVS2 decoding via libdavs2 [no] --enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 @@ -1931,6 +1932,7 @@ EXTERNAL_LIBRARY_LIST=" libcaca libcelt libcodec2 +libcrypto libdav1d libdc1394 libflite @@ -4091,7 +4093,7 @@ avfilter_deps="avutil" avfilter_suggest="libm stdatomic spirv_compiler" avformat_deps="avcodec avutil" avformat_suggest="libm network zlib stdatomic" -avutil_suggest="clock_gettime ffnvcodec gcrypt libm libdrm libmfx opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic" +avutil_suggest="clock_gettime ffnvcodec gcrypt libcrypto libm libdrm libmfx opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic" swresample_deps="avutil" swresample_suggest="libm libsoxr stdatomic" swscale_deps="avutil" @@ -7193,6 +7195,10 @@ enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" ope check_lib openssl openssl/ssl.h SSL_library_init -lssl32 -leay32 || check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 || die "ERROR: openssl not found"; } +enabled libcrypto && { { check_pkg_config libcrypto "libcrypto >= 3.0.0" openssl/aes.h AES_set_encrypt_key && + { enabled gplv3 || ! enabled gpl || enabled nonfree || die "ERROR: OpenSSL-libcrypto >= 3.0.0 requires --enable-version3"; }; } || + { enabled gpl && ! enabled nonfree && die "ERROR: OpenSSL-libcrypto < 3.0.0 is incompatible with the gpl"; } || + require_pkg_config libcrypto libcrypto openssl/aes.h AES_set_encrypt_key; } enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create && require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create && diff --git a/libavutil/aes.c b/libavutil/aes.c index 7fe42a5548..3a0d4e1385 100644 --- a/libavutil/aes.c +++ b/libavutil/aes.c @@ -39,6 +39,7 @@ struct AVAES *av_aes_alloc(void) return av_mallocz(sizeof(struct AVAES)); } +#if !CONFIG_LIBCRYPTO static const uint8_t rcon[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; @@ -137,7 +138,7 @@ static inline void aes_crypt(AVAES *a, int s, const uint8_t *sbox, } static void aes_encrypt(AVAES *a, uint8_t *dst, const uint8_t *src, -int count, uint8_t *iv) +int count, uint8_t *iv, int decrypt) { while (count--) { addkey_s(&a->state[1], src, &a->round_key[a->rounds]); @@ -153,7 +154,7 @@ static void aes_encrypt(AVAES *a, uint8_t *dst, const uint8_t *src, } static void aes_decrypt(AVAES *a, uint8_t *dst, const uint8_t *src, -int count, uint8_t *iv) +int count, uint8_t *iv, int decrypt) { while (count--) { addkey_s(&a->state[1], src, &a->round_key[a->rounds]); @@ -168,12 +169,32 @@ static void aes_decrypt(AVAES *a, uint8_t *dst, const uint8_t *src, } } +#else + +static void aes_libcrypto(AVAES *a, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt) +{ +if (iv) +AES_cbc_encrypt((const unsigned char *)src, +(unsigned char *)dst, +count, &a->key, +(unsigned char *)iv, !decrypt); +else { +for (int i = 0; i < count; i++) +AES_ecb_encrypt((const unsigned char *)&src[i*16], +(unsigned char *)&dst[i*16], +&a->key, !decrypt); +} +} +#endif + void av_aes_crypt(AVAES *a, uint8_t *dst, const uint8_t *src, int count, uin
Re: [FFmpeg-devel] [PATCH 1/2] avcodec/decode: Workaround for media100 decoding failure issue
> On Jun 11, 2025, at 13:55, Andreas Rheinhardt > wrote: > > Zhao Zhili: >> From: Zhao Zhili >> >> This is a regression since 1c170613. >> --- >> libavcodec/decode.c | 11 --- >> 1 file changed, 8 insertions(+), 3 deletions(-) >> >> diff --git a/libavcodec/decode.c b/libavcodec/decode.c >> index ef09568381..7e47a2971c 100644 >> --- a/libavcodec/decode.c >> +++ b/libavcodec/decode.c >> @@ -204,9 +204,14 @@ static int decode_bsfs_init(AVCodecContext *avctx) >> ret = av_bsf_init(avci->bsf); >> if (ret < 0) >> goto fail; >> -ret = avcodec_parameters_to_context(avctx, avci->bsf->par_out); >> -if (ret < 0) >> -goto fail; >> +/* Don't copy par_out to avcodec context if bsf changed codec ID, >> + * e.g., media100_to_mjpegb >> + */ >> +if (avctx->codec_id == avci->bsf->par_out->codec_id) { >> +ret = avcodec_parameters_to_context(avctx, avci->bsf->par_out); >> +if (ret < 0) >> +goto fail; >> +} >> >> return 0; >> fail: > > We should rather use a clean revert; after all, the internal BSF is > supposed to be internal and not change the user-visible extradata etc. Then how to let decoder see new extradata? Access bsf directly? I’m OK to revert this after extradata can be synced to decoder properly. AVCodecContext::extradata is owned by codec. Updating extradata can be a little surprise, but it’s less surprise than change codec id in bsf. What are the boundaries/limits of bsf’s functionality? Is it allowed for a bsf to update media type? I remember there is a trac with samples which can be handled with a video to audio bsf. > > - Andreas > > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 2/2] tests: Add media100 decoder test
Zhao Zhili: > From: Zhao Zhili > > --- > The sample comes from > https://trac.ffmpeg.org/attachment/ticket/959/12%2027_Volcano%20Zoom-Dissolve-F-8.mov > put it to mjpegb/media100.mov > > tests/fate/video.mak| 3 +++ > tests/ref/fate/media100 | 30 ++ > 2 files changed, 33 insertions(+) > create mode 100644 tests/ref/fate/media100 > > diff --git a/tests/fate/video.mak b/tests/fate/video.mak > index dd886843e7..24889824b4 100644 > --- a/tests/fate/video.mak > +++ b/tests/fate/video.mak > @@ -257,6 +257,9 @@ fate-mimic: CMD = framecrc -idct simple -i > $(TARGET_SAMPLES)/mimic/mimic2-womanl > FATE_VIDEO-$(call FRAMECRC, MOV, MJPEGB) += fate-mjpegb > fate-mjpegb: CMD = framecrc -idct simple -fflags +bitexact -i > $(TARGET_SAMPLES)/mjpegb/mjpegb_part.mov -an > > +FATE_VIDEO-$(call FRAMECRC, MOV, MEDIA100) += fate-media100 > +fate-media100: CMD = framecrc -idct simple -fflags +bitexact -i > $(TARGET_SAMPLES)/mjpegb/media100.mov > + > FATE_VIDEO-$(call FRAMECRC, AVI, MJPEG) += fate-mjpeg-ticket3229 > fate-mjpeg-ticket3229: CMD = framecrc -idct simple -fflags +bitexact -i > $(TARGET_SAMPLES)/mjpeg/mjpeg_field_order.avi -an > > diff --git a/tests/ref/fate/media100 b/tests/ref/fate/media100 > new file mode 100644 > index 00..7a92c5cc21 > --- /dev/null > +++ b/tests/ref/fate/media100 > @@ -0,0 +1,30 @@ > +#tb 0: 1/25 > +#media_type 0: video > +#codec_id 0: rawvideo > +#dimensions 0: 768x576 > +#sar 0: 0/1 > +0, 0, 0,1, 884736, 0x22304315 > +0, 1, 1,1, 884736, 0x896fcaf0 > +0, 2, 2,1, 884736, 0x2e25b031 > +0, 3, 3,1, 884736, 0x9d0cdf84 > +0, 4, 4,1, 884736, 0x90c799b6 > +0, 5, 5,1, 884736, 0x80ac6b03 > +0, 6, 6,1, 884736, 0x46cfbd02 > +0, 7, 7,1, 884736, 0xee2b4bdb > +0, 8, 8,1, 884736, 0x7876581e > +0, 9, 9,1, 884736, 0x19490d15 > +0, 10, 10,1, 884736, 0x6c37db8d > +0, 11, 11,1, 884736, 0xe6a198ae > +0, 12, 12,1, 884736, 0x893d08af > +0, 13, 13,1, 884736, 0xb52bd038 > +0, 14, 14,1, 884736, 0x7074bb1b > +0, 15, 15,1, 884736, 0xd32ed044 > +0, 16, 16,1, 884736, 0x9592d482 > +0, 17, 17,1, 884736, 0x9fcd144b > +0, 18, 18,1, 884736, 0xba1c73a2 > +0, 19, 19,1, 884736, 0x5fd7c0e7 > +0, 20, 20,1, 884736, 0xc3f05ed4 > +0, 21, 21,1, 884736, 0x333d0e9c > +0, 22, 22,1, 884736, 0x9063fd20 > +0, 23, 23,1, 884736, 0xc4508928 > +0, 24, 24,1, 884736, 0x1428b800 That sample is way too big; only one packet is needed (the last, smallest one). - Andreas ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 1/2] avcodec/decode: Workaround for media100 decoding failure issue
Zhao Zhili: > From: Zhao Zhili > > This is a regression since 1c170613. > --- > libavcodec/decode.c | 11 --- > 1 file changed, 8 insertions(+), 3 deletions(-) > > diff --git a/libavcodec/decode.c b/libavcodec/decode.c > index ef09568381..7e47a2971c 100644 > --- a/libavcodec/decode.c > +++ b/libavcodec/decode.c > @@ -204,9 +204,14 @@ static int decode_bsfs_init(AVCodecContext *avctx) > ret = av_bsf_init(avci->bsf); > if (ret < 0) > goto fail; > -ret = avcodec_parameters_to_context(avctx, avci->bsf->par_out); > -if (ret < 0) > -goto fail; > +/* Don't copy par_out to avcodec context if bsf changed codec ID, > + * e.g., media100_to_mjpegb > + */ > +if (avctx->codec_id == avci->bsf->par_out->codec_id) { > +ret = avcodec_parameters_to_context(avctx, avci->bsf->par_out); > +if (ret < 0) > +goto fail; > +} > > return 0; > fail: We should rather use a clean revert; after all, the internal BSF is supposed to be internal and not change the user-visible extradata etc. - Andreas ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 3/3] avutil/aes: add an OpenSSL-libcrypto backed implementation
James Almer: > OpenSSL has optimizations for more architectures than x86-AESNI, so use it if > libavutil is configured with libcrypto explicitly (Enabling OpenSSL alone will > not make use of it). > > Signed-off-by: James Almer > --- > configure| 8 +++- > libavutil/aes.c | 37 ++--- > libavutil/aes_internal.h | 11 ++- > libavutil/x86/aes_init.c | 2 ++ > 4 files changed, 53 insertions(+), 5 deletions(-) > > diff --git a/configure b/configure > index 534b443f7d..c7b4fbb2fe 100755 > --- a/configure > +++ b/configure > @@ -223,6 +223,7 @@ External library support: >--enable-libcelt enable CELT decoding via libcelt [no] >--enable-libcdio enable audio CD grabbing with libcdio [no] >--enable-libcodec2 enable codec2 en/decoding using libcodec2 [no] > + --enable-libcrypto enable crypto via libcrypto (AES only) [no] >--enable-libdav1denable AV1 decoding via libdav1d [no] >--enable-libdavs2enable AVS2 decoding via libdavs2 [no] >--enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 > @@ -1931,6 +1932,7 @@ EXTERNAL_LIBRARY_LIST=" > libcaca > libcelt > libcodec2 > +libcrypto > libdav1d > libdc1394 > libflite > @@ -4091,7 +4093,7 @@ avfilter_deps="avutil" > avfilter_suggest="libm stdatomic spirv_compiler" > avformat_deps="avcodec avutil" > avformat_suggest="libm network zlib stdatomic" > -avutil_suggest="clock_gettime ffnvcodec gcrypt libm libdrm libmfx opencl > openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia > bcrypt stdatomic" > +avutil_suggest="clock_gettime ffnvcodec gcrypt libcrypto libm libdrm libmfx > opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo > coremedia bcrypt stdatomic" > swresample_deps="avutil" > swresample_suggest="libm libsoxr stdatomic" > swscale_deps="avutil" > @@ -7193,6 +7195,10 @@ enabled openssl && { { check_pkg_config > openssl "openssl >= 3.0.0" ope > check_lib openssl openssl/ssl.h > SSL_library_init -lssl32 -leay32 || > check_lib openssl openssl/ssl.h > SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 || > die "ERROR: openssl not found"; } > +enabled libcrypto && { { check_pkg_config libcrypto "libcrypto >= > 3.0.0" openssl/aes.h AES_set_encrypt_key && > + { enabled gplv3 || ! enabled gpl || enabled > nonfree || die "ERROR: OpenSSL-libcrypto >= 3.0.0 requires > --enable-version3"; }; } || > + { enabled gpl && ! enabled nonfree && die > "ERROR: OpenSSL-libcrypto < 3.0.0 is incompatible with the gpl"; } || > + require_pkg_config libcrypto libcrypto > openssl/aes.h AES_set_encrypt_key; } > enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx > pocketsphinx/pocketsphinx.h ps_init > enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp > rockchip/rk_mpi.h mpp_create && > require_pkg_config rockchip_mpp "rockchip_mpp > >= 1.3.7" rockchip/rk_mpi.h mpp_create && > diff --git a/libavutil/aes.c b/libavutil/aes.c > index 7fe42a5548..3a0d4e1385 100644 > --- a/libavutil/aes.c > +++ b/libavutil/aes.c > @@ -39,6 +39,7 @@ struct AVAES *av_aes_alloc(void) > return av_mallocz(sizeof(struct AVAES)); > } > > +#if !CONFIG_LIBCRYPTO > static const uint8_t rcon[10] = { > 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 > }; > @@ -137,7 +138,7 @@ static inline void aes_crypt(AVAES *a, int s, const > uint8_t *sbox, > } > > static void aes_encrypt(AVAES *a, uint8_t *dst, const uint8_t *src, > -int count, uint8_t *iv) > +int count, uint8_t *iv, int decrypt) > { > while (count--) { > addkey_s(&a->state[1], src, &a->round_key[a->rounds]); > @@ -153,7 +154,7 @@ static void aes_encrypt(AVAES *a, uint8_t *dst, const > uint8_t *src, > } > > static void aes_decrypt(AVAES *a, uint8_t *dst, const uint8_t *src, > -int count, uint8_t *iv) > +int count, uint8_t *iv, int decrypt) > { > while (count--) { > addkey_s(&a->state[1], src, &a->round_key[a->rounds]); > @@ -168,12 +169,32 @@ static void aes_decrypt(AVAES *a, uint8_t *dst, const > uint8_t *src, > } > } > > +#else > + > +static void aes_libcrypto(AVAES *a, uint8_t *dst, const uint8_t *src, > + int count, uint8_t *iv, int decrypt) > +{ > +if (iv) > +AES_cbc_encrypt((const unsigned char *)src, > +(unsigned char *)dst, > +count, &a->key, > +(unsigned char *)iv, !decrypt); > +else { > +for (int i = 0; i < count; i++) > +AES_ecb_encrypt((const unsi
[FFmpeg-devel] [PATCH v5 02/19] swscale/format: rename legacy format conversion table
From: Niklas Haas --- libswscale/format.c | 18 +- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libswscale/format.c b/libswscale/format.c index e4c1348b90..b77081dd7a 100644 --- a/libswscale/format.c +++ b/libswscale/format.c @@ -24,14 +24,14 @@ #include "format.h" -typedef struct FormatEntry { +typedef struct LegacyFormatEntry { uint8_t is_supported_in :1; uint8_t is_supported_out:1; uint8_t is_supported_endianness :1; -} FormatEntry; +} LegacyFormatEntry; /* Format support table for legacy swscale */ -static const FormatEntry format_entries[] = { +static const LegacyFormatEntry legacy_format_entries[] = { [AV_PIX_FMT_YUV420P]= { 1, 1 }, [AV_PIX_FMT_YUYV422]= { 1, 1 }, [AV_PIX_FMT_RGB24] = { 1, 1 }, @@ -262,20 +262,20 @@ static const FormatEntry format_entries[] = { int sws_isSupportedInput(enum AVPixelFormat pix_fmt) { -return (unsigned)pix_fmt < FF_ARRAY_ELEMS(format_entries) ? - format_entries[pix_fmt].is_supported_in : 0; +return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ? +legacy_format_entries[pix_fmt].is_supported_in : 0; } int sws_isSupportedOutput(enum AVPixelFormat pix_fmt) { -return (unsigned)pix_fmt < FF_ARRAY_ELEMS(format_entries) ? - format_entries[pix_fmt].is_supported_out : 0; +return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ? +legacy_format_entries[pix_fmt].is_supported_out : 0; } int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt) { -return (unsigned)pix_fmt < FF_ARRAY_ELEMS(format_entries) ? - format_entries[pix_fmt].is_supported_endianness : 0; +return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ? +legacy_format_entries[pix_fmt].is_supported_endianness : 0; } /** -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 11/19] swscale/ops: add dispatch layer
From: Niklas Haas This handles the low-level execution of an op list, and integration into the SwsGraph infrastructure. To handle frames with insufficient padding in the stride (or a width smaller than one block size), we use a fallback loop that pads the last column of pixels using `memcpy` into an appropriately sized buffer. --- libswscale/ops.c | 269 ++ libswscale/ops.h | 14 ++ libswscale/ops_internal.h | 18 ++- 3 files changed, 294 insertions(+), 7 deletions(-) diff --git a/libswscale/ops.c b/libswscale/ops.c index c71601a0d1..5330b37b22 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -583,3 +583,272 @@ int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out ff_sws_op_list_print(ctx, AV_LOG_WARNING, ops); return AVERROR(ENOTSUP); } + +typedef struct SwsOpPass { +SwsCompiledOp comp; +SwsOpExec exec_base; +int num_blocks; +int tail_off_in; +int tail_off_out; +int tail_size_in; +int tail_size_out; +int pixel_bits_in; +int pixel_bits_out; +bool memcpy_in; +bool memcpy_out; +} SwsOpPass; + +static void op_pass_free(void *ptr) +{ +SwsOpPass *p = ptr; +if (!p) +return; + +if (p->comp.free) +p->comp.free(p->comp.priv); + +av_free(p); +} + +static void op_pass_setup(const SwsImg *out, const SwsImg *in, const SwsPass *pass) +{ +const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->fmt); +const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->fmt); + +SwsOpPass *p = pass->priv; +SwsOpExec *exec = &p->exec_base; +const SwsCompiledOp *comp = &p->comp; +const int block_size = comp->block_size; +p->num_blocks = (pass->width + block_size - 1) / block_size; + +/* Set up main loop parameters */ +const int aligned_w = p->num_blocks * block_size; +const int safe_width = (p->num_blocks - 1) * block_size; +const int tail_size = pass->width - safe_width; +p->tail_off_in = safe_width * p->pixel_bits_in >> 3; +p->tail_off_out = safe_width * p->pixel_bits_out >> 3; +p->tail_size_in = tail_size * p->pixel_bits_in >> 3; +p->tail_size_out = tail_size * p->pixel_bits_out >> 3; +p->memcpy_in = false; +p->memcpy_out= false; + +for (int i = 0; i < 4 && in->data[i]; i++) { +const int sub_x = (i == 1 || i == 2) ? indesc->log2_chroma_w : 0; +const int plane_w= (aligned_w + sub_x) >> sub_x; +const int plane_pad = (comp->over_read + sub_x) >> sub_x; +const int plane_size = plane_w * p->pixel_bits_in >> 3; +p->memcpy_in |= plane_size + plane_pad > in->linesize[i]; +exec->in_stride[i] = in->linesize[i]; +} + +for (int i = 0; i < 4 && out->data[i]; i++) { +const int sub_x = (i == 1 || i == 2) ? outdesc->log2_chroma_w : 0; +const int plane_w= (aligned_w + sub_x) >> sub_x; +const int plane_pad = (comp->over_write + sub_x) >> sub_x; +const int plane_size = plane_w * p->pixel_bits_out >> 3; +p->memcpy_out |= plane_size + plane_pad > out->linesize[i]; +exec->out_stride[i] = out->linesize[i]; +} + +/* Pre-fill pointer bump for the main section only; this value does not + * matter at all for the tail / last row handlers because they only ever + * process a single line */ +const int blocks_main = p->num_blocks - p->memcpy_out; +for (int i = 0; i < 4; i++) { +exec->in_bump[i] = in->linesize[i] - blocks_main * exec->block_size_in; +exec->out_bump[i] = out->linesize[i] - blocks_main * exec->block_size_out; +} +} + +/* Dispatch kernel over the last column of the image using memcpy */ +static av_always_inline void +handle_tail(const SwsOpPass *p, SwsOpExec *exec, +const SwsImg *out_base, const bool copy_out, +const SwsImg *in_base, const bool copy_in, +int y, const int h) +{ +DECLARE_ALIGNED_64(uint8_t, tmp)[2][4][sizeof(uint32_t[128])]; + +const SwsCompiledOp *comp = &p->comp; +const int tail_size_in = p->tail_size_in; +const int tail_size_out = p->tail_size_out; +const int bx = p->num_blocks - 1; + +SwsImg in = ff_sws_img_shift(in_base, y); +SwsImg out = ff_sws_img_shift(out_base, y); +for (int i = 0; i < 4 && in.data[i]; i++) { +in.data[i] += p->tail_off_in; +if (copy_in) { +exec->in[i] = (void *) tmp[0][i]; +exec->in_stride[i] = sizeof(tmp[0][i]); +} else { +exec->in[i] = in.data[i]; +} +} + +for (int i = 0; i < 4 && out.data[i]; i++) { +out.data[i] += p->tail_off_out; +if (copy_out) { +exec->out[i] = (void *) tmp[1][i]; +exec->out_stride[i] = sizeof(tmp[1][i]); +} else { +exec->out[i] = out.data[i]; +} +} + +for (int y_end = y + h; y < y_end; y++) { +if (copy_in) { +
[FFmpeg-devel] [PATCH v5 09/19] swscale/optimizer: add high-level ops optimizer
From: Niklas Haas This is responsible for taking a "naive" ops list and optimizing it as much as possible. Also includes a small analyzer that generates component metadata for use by the optimizer. --- libswscale/Makefile| 1 + libswscale/ops.h | 12 + libswscale/ops_optimizer.c | 782 + 3 files changed, 795 insertions(+) create mode 100644 libswscale/ops_optimizer.c diff --git a/libswscale/Makefile b/libswscale/Makefile index e0beef4e69..810c9dee78 100644 --- a/libswscale/Makefile +++ b/libswscale/Makefile @@ -16,6 +16,7 @@ OBJS = alphablend.o \ input.o \ lut3d.o \ ops.o\ + ops_optimizer.o \ options.o\ output.o \ rgb2rgb.o\ diff --git a/libswscale/ops.h b/libswscale/ops.h index 71841c1572..a90701cf50 100644 --- a/libswscale/ops.h +++ b/libswscale/ops.h @@ -237,4 +237,16 @@ void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count); */ void ff_sws_op_list_print(void *log_ctx, int log_level, const SwsOpList *ops); +/** + * Infer + propagate known information about components. Called automatically + * when needed by the optimizer and compiler. + */ +void ff_sws_op_list_update_comps(SwsOpList *ops); + +/** + * Fuse compatible and eliminate redundant operations, as well as replacing + * some operations with more efficient alternatives. + */ +int ff_sws_op_list_optimize(SwsOpList *ops); + #endif diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c new file mode 100644 index 00..80e75ed34b --- /dev/null +++ b/libswscale/ops_optimizer.c @@ -0,0 +1,782 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/rational.h" + +#include "ops.h" + +#define Q(N) ((AVRational) { N, 1 }) + +#define RET(x) \ +do { \ +if ((ret = (x)) < 0) \ +return ret; \ +} while (0) + +/* Returns true for operations that are independent per channel. These can + * usually be commuted freely other such operations. */ +static bool op_type_is_independent(SwsOpType op) +{ +switch (op) { +case SWS_OP_SWAP_BYTES: +case SWS_OP_LSHIFT: +case SWS_OP_RSHIFT: +case SWS_OP_CONVERT: +case SWS_OP_DITHER: +case SWS_OP_MIN: +case SWS_OP_MAX: +case SWS_OP_SCALE: +return true; +case SWS_OP_INVALID: +case SWS_OP_READ: +case SWS_OP_WRITE: +case SWS_OP_SWIZZLE: +case SWS_OP_CLEAR: +case SWS_OP_LINEAR: +case SWS_OP_PACK: +case SWS_OP_UNPACK: +return false; +case SWS_OP_TYPE_NB: +break; +} + +av_assert0(!"Invalid operation type!"); +return false; +} + +static AVRational expand_factor(SwsPixelType from, SwsPixelType to) +{ +const int src = ff_sws_pixel_type_size(from); +const int dst = ff_sws_pixel_type_size(to); +int scale = 0; +for (int i = 0; i < dst / src; i++) +scale = scale << src * 8 | 1; +return Q(scale); +} + +/* merge_comp_flags() forms a monoid with flags_identity as the null element */ +static const unsigned flags_identity = SWS_COMP_ZERO | SWS_COMP_EXACT; +static unsigned merge_comp_flags(unsigned a, unsigned b) +{ +const unsigned flags_or = SWS_COMP_GARBAGE; +const unsigned flags_and = SWS_COMP_ZERO | SWS_COMP_EXACT; +return ((a & b) & flags_and) | ((a | b) & flags_or); +} + +/* Infer + propagate known information about components */ +void ff_sws_op_list_update_comps(SwsOpList *ops) +{ +SwsComps next = { .unused = {true, true, true, true} }; +SwsComps prev = { .flags = { +SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, +}}; + +
[FFmpeg-devel] [PATCH v5 04/19] tests/checkasm: increase number of runs in between measurements
From: Niklas Haas Sometimes, when measuring very small functions, rdtsc is not accurate enough to get a reliable measurement. This increases the number of runs inside the inner loop from 4 to 32, which should help a lot. Less important when using the more precise linux-perf API, but still useful. There should be no user-visible change since the number of runs is adjusted to keep the total time spent measuring the same. --- tests/checkasm/checkasm.c | 2 +- tests/checkasm/checkasm.h | 24 +++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index 0734cd26bf..71d1e5766c 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -628,7 +628,7 @@ static inline double avg_cycles_per_call(const CheckasmPerf *const p) if (p->iterations) { const double cycles = (double)(10 * p->cycles) / p->iterations - state.nop_time; if (cycles > 0.0) -return cycles / 4.0; /* 4 calls per iteration */ +return cycles / 32.0; /* 32 calls per iteration */ } return 0.0; } diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h index 146bfdec35..ad7ed10613 100644 --- a/tests/checkasm/checkasm.h +++ b/tests/checkasm/checkasm.h @@ -342,6 +342,22 @@ typedef struct CheckasmPerf { #define PERF_STOP(t) t = AV_READ_TIME() - t #endif +#define CALL4(...)\ +do {\ +tfunc(__VA_ARGS__); \ +tfunc(__VA_ARGS__); \ +tfunc(__VA_ARGS__); \ +tfunc(__VA_ARGS__); \ +} while (0) + +#define CALL16(...)\ +do {\ +CALL4(__VA_ARGS__); \ +CALL4(__VA_ARGS__); \ +CALL4(__VA_ARGS__); \ +CALL4(__VA_ARGS__); \ +} while (0) + /* Benchmark the function */ #define bench_new(...)\ do {\ @@ -352,14 +368,12 @@ typedef struct CheckasmPerf { uint64_t tsum = 0;\ uint64_t ti, tcount = 0;\ uint64_t t = 0; \ -const uint64_t truns = bench_runs;\ +const uint64_t truns = FFMAX(bench_runs >> 3, 1);\ checkasm_set_signal_handler_state(1);\ for (ti = 0; ti < truns; ti++) {\ PERF_START(t);\ -tfunc(__VA_ARGS__);\ -tfunc(__VA_ARGS__);\ -tfunc(__VA_ARGS__);\ -tfunc(__VA_ARGS__);\ +CALL16(__VA_ARGS__);\ +CALL16(__VA_ARGS__);\ PERF_STOP(t);\ if (t*tcount <= tsum*4 && ti > 0) {\ tsum += t;\ -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 08/19] swscale/ops: introduce new low level framework
From: Niklas Haas See docs/swscale-v2.txt for an in-depth introduction to the new approach. This commit merely introduces the ops definitions and boilerplate functions. The subsequent commits will flesh out the underlying implementation. --- libswscale/Makefile | 1 + libswscale/ops.c| 520 libswscale/ops.h| 240 3 files changed, 761 insertions(+) create mode 100644 libswscale/ops.c create mode 100644 libswscale/ops.h diff --git a/libswscale/Makefile b/libswscale/Makefile index d5e10d17dc..e0beef4e69 100644 --- a/libswscale/Makefile +++ b/libswscale/Makefile @@ -15,6 +15,7 @@ OBJS = alphablend.o \ graph.o \ input.o \ lut3d.o \ + ops.o\ options.o\ output.o \ rgb2rgb.o\ diff --git a/libswscale/ops.c b/libswscale/ops.c new file mode 100644 index 00..c6e8f691cb --- /dev/null +++ b/libswscale/ops.c @@ -0,0 +1,520 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/bswap.h" +#include "libavutil/mem.h" +#include "libavutil/rational.h" +#include "libavutil/refstruct.h" + +#include "ops.h" + +#define Q(N) ((AVRational) { N, 1 }) + +const char *ff_sws_pixel_type_name(SwsPixelType type) +{ +switch (type) { +case SWS_PIXEL_U8: return "u8"; +case SWS_PIXEL_U16: return "u16"; +case SWS_PIXEL_U32: return "u32"; +case SWS_PIXEL_F32: return "f32"; +case SWS_PIXEL_NONE: return "none"; +case SWS_PIXEL_TYPE_NB: break; +} + +av_assert0(!"Invalid pixel type!"); +return "ERR"; +} + +int ff_sws_pixel_type_size(SwsPixelType type) +{ +switch (type) { +case SWS_PIXEL_U8: return sizeof(uint8_t); +case SWS_PIXEL_U16: return sizeof(uint16_t); +case SWS_PIXEL_U32: return sizeof(uint32_t); +case SWS_PIXEL_F32: return sizeof(float); +case SWS_PIXEL_NONE: break; +case SWS_PIXEL_TYPE_NB: break; +} + +av_assert0(!"Invalid pixel type!"); +return 0; +} + +bool ff_sws_pixel_type_is_int(SwsPixelType type) +{ +switch (type) { +case SWS_PIXEL_U8: +case SWS_PIXEL_U16: +case SWS_PIXEL_U32: +return true; +case SWS_PIXEL_F32: +return false; +case SWS_PIXEL_NONE: +case SWS_PIXEL_TYPE_NB: break; +} + +av_assert0(!"Invalid pixel type!"); +return false; +} + +SwsPixelType ff_sws_pixel_type_to_uint(SwsPixelType type) +{ +if (!type) +return type; + +switch (ff_sws_pixel_type_size(type)) { +case 8: return SWS_PIXEL_U8; +case 16: return SWS_PIXEL_U16; +case 32: return SWS_PIXEL_U32; +} + +av_assert0(!"Invalid pixel type!"); +return SWS_PIXEL_NONE; +} + +/* biased towards `a` */ +static AVRational av_min_q(AVRational a, AVRational b) +{ +return av_cmp_q(a, b) == 1 ? b : a; +} + +static AVRational av_max_q(AVRational a, AVRational b) +{ +return av_cmp_q(a, b) == -1 ? b : a; +} + +static AVRational expand_factor(SwsPixelType from, SwsPixelType to) +{ +const int src = ff_sws_pixel_type_size(from); +const int dst = ff_sws_pixel_type_size(to); +int scale = 0; +for (int i = 0; i < dst / src; i++) +scale = scale << src * 8 | 1; +return Q(scale); +} + +void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4]) +{ +switch (op->op) { +case SWS_OP_READ: +case SWS_OP_WRITE: +return; +case SWS_OP_UNPACK: { +unsigned val = x[0].num; +int shift = ff_sws_pixel_type_size(op->type) * 8; +for (int i = 0; i < 4; i++) { +const unsigned mask = (1 << op->pack.pattern[i]) - 1; +shift -= op->pack.pattern[i]; +x[i] = Q((val >> shift) & mask); +} +return; +} +case SWS_OP_PACK: { +unsigned val = 0; +int shift = ff_sws_pixel_type_size(op->type) * 8; +for (int i = 0; i < 4; i++
[FFmpeg-devel] [PATCH v5 12/19] swscale/optimizer: add packed shuffle solver
From: Niklas Haas This can turn any compatible sequence of operations into a single packed shuffle, including packed swizzling, grayscale->RGB conversion, endianness swapping, RGB bit depth conversions, rgb24->rgb0 alpha clearing and more. --- libswscale/ops_internal.h | 28 +++ libswscale/ops_optimizer.c | 96 ++ 2 files changed, 124 insertions(+) diff --git a/libswscale/ops_internal.h b/libswscale/ops_internal.h index 2fbd8a55d0..e7b6fb1c4c 100644 --- a/libswscale/ops_internal.h +++ b/libswscale/ops_internal.h @@ -109,4 +109,32 @@ int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, */ int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out); +/** + * "Solve" an op list into a fixed shuffle mask, with an optional ability to + * also directly clear the output value (for e.g. rgb24 -> rgb0). This can + * accept any operation chain that only consists of the following operations: + * + * - SWS_OP_READ (non-planar, non-fractional) + * - SWS_OP_SWIZZLE + * - SWS_OP_SWAP_BYTES + * - SWS_OP_CLEAR to zero (when clear_val is specified) + * - SWS_OP_CONVERT (integer expand) + * - SWS_OP_WRITE (non-planar, non-fractional) + * + * Basically, any operation that purely consists of moving around and reording + * bytes within a single plane, can be turned into a shuffle mask. + * + * @param ops The operation list to decompose. + * @param shuffle The output shuffle mask. + * @param sizeThe size (in bytes) of the output shuffle mask. + * @param clear_val If nonzero, this index will be used to clear the output. + * @param read_bytes Returns the number of bytes read per shuffle iteration. + * @param write_bytes Returns the number of bytes written per shuffle iteration. + * + * @return The number of pixels processed per iteration, or a negative error +code; in particular AVERROR(ENOTSUP) for unsupported operations. + */ +int ff_sws_solve_shuffle(const SwsOpList *ops, uint8_t shuffle[], int size, + uint8_t clear_val, int *read_bytes, int *write_bytes); + #endif diff --git a/libswscale/ops_optimizer.c b/libswscale/ops_optimizer.c index 80e75ed34b..23c9aae76d 100644 --- a/libswscale/ops_optimizer.c +++ b/libswscale/ops_optimizer.c @@ -19,9 +19,11 @@ */ #include "libavutil/avassert.h" +#include #include "libavutil/rational.h" #include "ops.h" +#include "ops_internal.h" #define Q(N) ((AVRational) { N, 1 }) @@ -780,3 +782,97 @@ retry: return 0; } + +int ff_sws_solve_shuffle(const SwsOpList *const ops, uint8_t shuffle[], + int shuffle_size, uint8_t clear_val, + int *out_read_bytes, int *out_write_bytes) +{ +const SwsOp read = ops->ops[0]; +const int read_size = ff_sws_pixel_type_size(read.type); +uint32_t mask[4] = {0}; + +if (!ops->num_ops || read.op != SWS_OP_READ) +return AVERROR(EINVAL); +if (read.rw.frac || (!read.rw.packed && read.rw.elems > 1)) +return AVERROR(ENOTSUP); + +for (int i = 0; i < read.rw.elems; i++) +mask[i] = 0x01010101 * i * read_size + 0x03020100; + +for (int opidx = 1; opidx < ops->num_ops; opidx++) { +const SwsOp *op = &ops->ops[opidx]; +switch (op->op) { +case SWS_OP_SWIZZLE: { +uint32_t orig[4] = { mask[0], mask[1], mask[2], mask[3] }; +for (int i = 0; i < 4; i++) +mask[i] = orig[op->swizzle.in[i]]; +break; +} + +case SWS_OP_SWAP_BYTES: +for (int i = 0; i < 4; i++) { +switch (ff_sws_pixel_type_size(op->type)) { +case 2: mask[i] = av_bswap16(mask[i]); break; +case 4: mask[i] = av_bswap32(mask[i]); break; +} +} +break; + +case SWS_OP_CLEAR: +for (int i = 0; i < 4; i++) { +if (!op->c.q4[i].den) +continue; +if (op->c.q4[i].num != 0 || !clear_val) +return AVERROR(ENOTSUP); +mask[i] = 0x1010101ul * clear_val; +} +break; + +case SWS_OP_CONVERT: { +if (!op->convert.expand) +return AVERROR(ENOTSUP); +for (int i = 0; i < 4; i++) { +switch (ff_sws_pixel_type_size(op->type)) { +case 1: mask[i] = 0x01010101 * (mask[i] & 0xFF); break; +case 2: mask[i] = 0x00010001 * (mask[i] & 0x); break; +} +} +break; +} + +case SWS_OP_WRITE: { +if (op->rw.frac || (!op->rw.packed && op->rw.elems > 1)) +return AVERROR(ENOTSUP); + +/* Initialize to no-op */ +memset(shuffle, clear_val, shuffle_size); + +const int write_size = ff_sws_pixel_type_size(op->type); +const int read_chunk = read.rw.elems * read_s
[FFmpeg-devel] [PATCH v5 06/19] avutil/mem: add av_dynarray2_dup
From: Niklas Haas Like av_memdup() but correctly rounds up to the nearest power of two so that av_dynarray2_add() will continue to work on the duplicated list. --- libavutil/mem.c | 9 + libavutil/mem.h | 14 ++ 2 files changed, 23 insertions(+) diff --git a/libavutil/mem.c b/libavutil/mem.c index b205d3fb25..2ed4553069 100644 --- a/libavutil/mem.c +++ b/libavutil/mem.c @@ -39,6 +39,7 @@ #include "attributes.h" #include "avassert.h" +#include "common.h" #include "dynarray.h" #include "error.h" #include "internal.h" @@ -358,6 +359,14 @@ void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, return tab_elem_data; } +void *av_dynarray2_dup(void *tab, int nb, size_t elem_size) +{ +if (nb) +nb = 1 << av_ceil_log2(nb); + +return av_memdup(tab, nb * elem_size); +} + static void fill16(uint8_t *dst, int len) { uint32_t v = AV_RN16(dst - 2); diff --git a/libavutil/mem.h b/libavutil/mem.h index ab7648ac57..7815327a88 100644 --- a/libavutil/mem.h +++ b/libavutil/mem.h @@ -562,6 +562,20 @@ int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem); void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data); +/** + * Duplicate an array allocated by `av_dynarray2_add`. Preserves the size of + * the underlying allocation, so that the returned array can be again modified + * using `av_dynarray2_add`. + * + * @param[in] tab Pointer to the array to duplicate + * @param[in] nbNumber of elements in the array + * @param[in] elem_size Size in bytes of an element in the array + * + * @return Pointer to the newly allocated array, or `NULL` on failure. + * @see av_dynarray2_add() + */ +void *av_dynarray2_dup(void *tab, int nb, size_t elem_size); + /** * @} */ -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 10/19] swscale/ops_internal: add internal ops backend API
From: Niklas Haas This adds an internal API for ops backends, which are responsible for compiling op lists into executable functions. --- libswscale/ops.c | 65 +++ libswscale/ops_internal.h | 108 ++ 2 files changed, 173 insertions(+) create mode 100644 libswscale/ops_internal.h diff --git a/libswscale/ops.c b/libswscale/ops.c index c6e8f691cb..c71601a0d1 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -25,9 +25,22 @@ #include "libavutil/refstruct.h" #include "ops.h" +#include "ops_internal.h" + +const SwsOpBackend * const ff_sws_op_backends[] = { +NULL +}; + +const int ff_sws_num_op_backends = FF_ARRAY_ELEMS(ff_sws_op_backends) - 1; #define Q(N) ((AVRational) { N, 1 }) +#define RET(x) \ +do { \ +if ((ret = (x)) < 0) \ +return ret; \ +} while (0) + const char *ff_sws_pixel_type_name(SwsPixelType type) { switch (type) { @@ -518,3 +531,55 @@ void ff_sws_op_list_print(void *log, int lev, const SwsOpList *ops) av_log(log, lev, "(X = unused, + = exact, 0 = zero)\n"); } + +int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, + const SwsOpList *ops, SwsCompiledOp *out) +{ +SwsOpList *copy, rest; +SwsCompiledOp compiled = {0}; +int ret = 0; + +copy = ff_sws_op_list_duplicate(ops); +if (!copy) +return AVERROR(ENOMEM); + +/* Ensure these are always set during compilation */ +ff_sws_op_list_update_comps(copy); + +/* Make an on-stack copy of `ops` to ensure we can still properly clean up + * the copy afterwards */ +rest = *copy; + +ret = backend->compile(ctx, &rest, &compiled); +if (ret == AVERROR(ENOTSUP)) { +av_log(ctx, AV_LOG_TRACE, "Backend '%s' does not support operations:\n", backend->name); +ff_sws_op_list_print(ctx, AV_LOG_TRACE, &rest); +} else if (ret < 0) { +av_log(ctx, AV_LOG_ERROR, "Failed to compile operations: %s\n", av_err2str(ret)); +ff_sws_op_list_print(ctx, AV_LOG_ERROR, &rest); +} else { +*out = compiled; +} + +ff_sws_op_list_free(©); +return ret; +} + +int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out) +{ +for (int n = 0; ff_sws_op_backends[n]; n++) { +const SwsOpBackend *backend = ff_sws_op_backends[n]; +if (ff_sws_ops_compile_backend(ctx, backend, ops, out) < 0) +continue; + +av_log(ctx, AV_LOG_VERBOSE, "Compiled using backend '%s': " + "block size = %d, over-read = %d, over-write = %d, cpu flags = 0x%x\n", + backend->name, out->block_size, out->over_read, out->over_write, + out->cpu_flags); +return 0; +} + +av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n"); +ff_sws_op_list_print(ctx, AV_LOG_WARNING, ops); +return AVERROR(ENOTSUP); +} diff --git a/libswscale/ops_internal.h b/libswscale/ops_internal.h new file mode 100644 index 00..9fd866430b --- /dev/null +++ b/libswscale/ops_internal.h @@ -0,0 +1,108 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_OPS_INTERNAL_H +#define SWSCALE_OPS_INTERNAL_H + +#include "libavutil/mem_internal.h" + +#include "ops.h" + +/** + * Global execution context for all compiled functions. + * + * Note: This struct is hard-coded in assembly, so do not change the layout + * without updating the corresponding assembly definitions. + */ +typedef struct SwsOpExec { +/* The data pointers point to the first pixel to process */ +DECLARE_ALIGNED_32(const uint8_t, *in[4]); +DECLARE_ALIGNED_32(uint8_t, *out[4]); + +/* Separation between lines in bytes */ +DECLARE_ALIGNED_32(ptrdiff_t, in_stride[4]); +DECLARE_ALIGNED_32(ptrdiff_t, out_stride[4]); + +/* Extra metadata, may or may not be useful */ +int32_t width, height; /* Overall image dimensions */ +int32_
[FFmpeg-devel] [PATCH v5 13/19] swscale/ops_chain: add internal abstraction for kernel linking
From: Niklas Haas See doc/swscale-v2.txt for design details. --- libswscale/Makefile| 1 + libswscale/ops_chain.c | 291 + libswscale/ops_chain.h | 134 +++ 3 files changed, 426 insertions(+) create mode 100644 libswscale/ops_chain.c create mode 100644 libswscale/ops_chain.h diff --git a/libswscale/Makefile b/libswscale/Makefile index 810c9dee78..c9dfa78c89 100644 --- a/libswscale/Makefile +++ b/libswscale/Makefile @@ -16,6 +16,7 @@ OBJS = alphablend.o \ input.o \ lut3d.o \ ops.o\ + ops_chain.o \ ops_optimizer.o \ options.o\ output.o \ diff --git a/libswscale/ops_chain.c b/libswscale/ops_chain.c new file mode 100644 index 00..09a7a195ad --- /dev/null +++ b/libswscale/ops_chain.c @@ -0,0 +1,291 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" +#include "libavutil/rational.h" + +#include "ops_chain.h" + +#define Q(N) ((AVRational) { N, 1 }) + +SwsOpChain *ff_sws_op_chain_alloc(void) +{ +return av_mallocz(sizeof(SwsOpChain)); +} + +void ff_sws_op_chain_free(SwsOpChain *chain) +{ +if (!chain) +return; + +for (int i = 0; i < chain->num_impl + 1; i++) { +if (chain->free[i]) +chain->free[i](chain->impl[i].priv.ptr); +} + +av_free(chain); +} + +int ff_sws_op_chain_append(SwsOpChain *chain, SwsFuncPtr func, + void (*free)(void *), SwsOpPriv priv) +{ +const int idx = chain->num_impl; +if (idx == SWS_MAX_OPS) +return AVERROR(EINVAL); + +av_assert1(func); +chain->impl[idx].cont = func; +chain->impl[idx + 1].priv = priv; +chain->free[idx + 1] = free; +chain->num_impl++; +return 0; +} + +/** + * Match an operation against a reference operation. Returns a score for how + * well the reference matches the operation, or 0 if there is no match. + * + * If `ref->comps` has any flags set, they must be set in `op` as well. + * Likewise, if `ref->comps` has any components marked as unused, they must be + * marked as as unused in `ops` as well. + * + * For SWS_OP_LINEAR, `ref->linear.mask` must be a strict superset of + * `op->linear.mask`, but may not contain any columns explicitly ignored by + * `op->comps.unused`. + * + * For SWS_OP_READ, SWS_OP_WRITE, SWS_OP_SWAP_BYTES and SWS_OP_SWIZZLE, the + * exact type is not checked, just the size. + * + * Components set in `next.unused` are ignored when matching. If `flexible` + * is true, the op body is ignored - only the operation, pixel type, and + * component masks are checked. + */ +static int op_match(const SwsOp *op, const SwsOpEntry *entry, const SwsComps next) +{ +int score = 10; +if (op->op != entry->op) +return 0; + +switch (op->op) { +case SWS_OP_READ: +case SWS_OP_WRITE: +case SWS_OP_SWAP_BYTES: +case SWS_OP_SWIZZLE: +/* Only the size matters for these operations */ +if (ff_sws_pixel_type_size(op->type) != ff_sws_pixel_type_size(entry->type)) +return 0; +break; +default: +if (op->type != entry->type) +return 0; +break; +} + +for (int i = 0; i < 4; i++) { +if (entry->unused[i]) { +if (op->comps.unused[i]) +score += 1; /* Operating on fewer components is better .. */ +else +return false; /* .. but not too few! */ +} +} + +if (op->op == SWS_OP_CLEAR) { +/* Clear pattern must match exactly, regardless of `entry->flexible` */ +for (int i = 0; i < 4; i++) { +if (entry->unused[i] != !!op->c.q4[i].den) +return 0; +} +} + +/* Flexible variants always match, but lower the score to prioritize more + * specific implementations if they exist */ +if (entry->flexib
[FFmpeg-devel] [PATCH v5 15/19] swscale/ops_memcpy: add 'memcpy' backend for plane->plane copies
From: Niklas Haas Provides a generic fast path for any operation list that can be decomposed into a series of memcpy and memset operations. 25% faster than the x86 backend for yuv444p -> yuva444p 33% faster than the x86 backend for gray -> yuvj444p --- libswscale/Makefile | 1 + libswscale/ops.c| 2 + libswscale/ops_memcpy.c | 132 3 files changed, 135 insertions(+) create mode 100644 libswscale/ops_memcpy.c diff --git a/libswscale/Makefile b/libswscale/Makefile index d3cb7bc555..0fed799542 100644 --- a/libswscale/Makefile +++ b/libswscale/Makefile @@ -18,6 +18,7 @@ OBJS = alphablend.o \ ops.o\ ops_backend.o\ ops_chain.o \ + ops_memcpy.o \ ops_optimizer.o \ options.o\ output.o \ diff --git a/libswscale/ops.c b/libswscale/ops.c index 5b259e13be..6a5b4f4158 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -28,8 +28,10 @@ #include "ops_internal.h" extern SwsOpBackend backend_c; +extern SwsOpBackend backend_murder; const SwsOpBackend * const ff_sws_op_backends[] = { +&backend_murder, &backend_c, NULL }; diff --git a/libswscale/ops_memcpy.c b/libswscale/ops_memcpy.c new file mode 100644 index 00..ef4784faa4 --- /dev/null +++ b/libswscale/ops_memcpy.c @@ -0,0 +1,132 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" + +#include "ops_backend.h" + +typedef struct MemcpyPriv { +int num_planes; +int index[4]; /* or -1 to clear plane */ +uint8_t clear_value[4]; +} MemcpyPriv; + +/* Memcpy backend for trivial cases */ + +static void process(const SwsOpExec *exec, const void *priv, +int x_start, int y_start, int x_end, int y_end) +{ +const MemcpyPriv *p = priv; +const int lines = y_end - y_start; +av_assert1(x_start == 0 && x_end == exec->width); + +for (int i = 0; i < p->num_planes; i++) { +uint8_t *out = exec->out[i]; +const int idx = p->index[i]; +if (idx < 0) { +memset(out, p->clear_value[i], exec->out_stride[i] * lines); +} else if (exec->out_stride[i] == exec->in_stride[idx]) { +memcpy(out, exec->in[idx], exec->out_stride[i] * lines); +} else { +const int bytes = x_end * exec->block_size_out; +const uint8_t *in = exec->in[idx]; +for (int y = y_start; y < y_end; y++) { +memcpy(out, in, bytes); +out += exec->out_stride[i]; +in += exec->in_stride[idx]; +} +} +} +} + +static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out) +{ +MemcpyPriv p = {0}; + +for (int n = 0; n < ops->num_ops; n++) { +const SwsOp *op = &ops->ops[n]; +switch (op->op) { +case SWS_OP_READ: +if ((op->rw.packed && op->rw.elems != 1) || op->rw.frac) +return AVERROR(ENOTSUP); +for (int i = 0; i < op->rw.elems; i++) +p.index[i] = i; +break; + +case SWS_OP_SWIZZLE: { +const MemcpyPriv orig = p; +for (int i = 0; i < 4; i++) { +/* Explicitly exclude swizzle masks that contain duplicates, + * because these are wasteful to implement as a memcpy */ +for (int j = 0; j < i; j++) { +if (op->swizzle.in[i] == op->swizzle.in[j]) +return AVERROR(ENOTSUP); +} +p.index[i] = orig.index[op->swizzle.in[i]]; +} +break; +} + +case SWS_OP_CLEAR: +for (int i = 0; i < 4; i++) { +if (!op->c.q4[i].den) +continue; +if (op->c.q4[i].den != 1) +return AVERROR(ENOTSUP); + +/* Ensure all bytes to be cleared are the same, be
[FFmpeg-devel] [PATCH v5 07/19] swscale: add SWS_UNSTABLE flag
From: Niklas Haas Give users and developers a way to opt in to the new format conversion code, and more code from the swscale rewrite in general, even while development is still ongoing. --- doc/APIchanges | 3 +++ doc/scaler.texi | 4 libswscale/options.c | 1 + libswscale/swscale.h | 7 +++ libswscale/version.h | 2 +- 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index 91710bb27d..ae5e4b366b 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28 API changes, most recent first: +2025-04-xx - xx - lsws 9.1.100 - swscale.h + Add SWS_UNSTABLE flag. + 2025-05-21 - xx - lavu 60.3.100 - avassert.h Add av_unreachable() and av_assume() macros. diff --git a/doc/scaler.texi b/doc/scaler.texi index eb045de6b7..42b2377761 100644 --- a/doc/scaler.texi +++ b/doc/scaler.texi @@ -68,6 +68,10 @@ Select full chroma input. @item bitexact Enable bitexact output. + +@item unstable +Allow the use of experimental new code. May subtly affect the output or even +produce wrong results. For testing only. @end table @item srcw @var{(API only)} diff --git a/libswscale/options.c b/libswscale/options.c index feecae8c89..06e51dcfe9 100644 --- a/libswscale/options.c +++ b/libswscale/options.c @@ -50,6 +50,7 @@ static const AVOption swscale_options[] = { { "full_chroma_inp", "full chroma input", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_FULL_CHR_H_INP }, .flags = VE, .unit = "sws_flags" }, { "bitexact","bit-exact mode",0, AV_OPT_TYPE_CONST, { .i64 = SWS_BITEXACT }, .flags = VE, .unit = "sws_flags" }, { "error_diffusion", "error diffusion dither",0, AV_OPT_TYPE_CONST, { .i64 = SWS_ERROR_DIFFUSION}, .flags = VE, .unit = "sws_flags" }, +{ "unstable","allow experimental new code", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_UNSTABLE }, .flags = VE, .unit = "sws_flags" }, { "param0", "scaler param 0", OFFSET(scaler_params[0]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, VE }, { "param1", "scaler param 1", OFFSET(scaler_params[1]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, VE }, diff --git a/libswscale/swscale.h b/libswscale/swscale.h index b04aa182d2..4aa072009c 100644 --- a/libswscale/swscale.h +++ b/libswscale/swscale.h @@ -155,6 +155,13 @@ typedef enum SwsFlags { SWS_ACCURATE_RND = 1 << 18, SWS_BITEXACT = 1 << 19, +/** + * Allow using experimental new code paths. This may be faster, slower, + * or produce different output, with semantics subject to change at any + * point in time. For testing and debugging purposes only. + */ +SWS_UNSTABLE = 1 << 20, + /** * Deprecated flags. */ diff --git a/libswscale/version.h b/libswscale/version.h index 148efd83eb..4e54701aba 100644 --- a/libswscale/version.h +++ b/libswscale/version.h @@ -28,7 +28,7 @@ #include "version_major.h" -#define LIBSWSCALE_VERSION_MINOR 0 +#define LIBSWSCALE_VERSION_MINOR 1 #define LIBSWSCALE_VERSION_MICRO 100 #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 19/19] swscale/graph: allow experimental use of new format handler
From: Niklas Haas Now, make it a Killer-Feature! --- libswscale/graph.c | 84 -- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index edf243823f..c72bc6540f 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -34,6 +34,7 @@ #include "lut3d.h" #include "swscale_internal.h" #include "graph.h" +#include "ops.h" static int pass_alloc_output(SwsPass *pass) { @@ -455,6 +456,85 @@ static int add_legacy_sws_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst, return 0; } +/* + * Format conversion * + */ + +static int add_convert_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst, +SwsPass *input, SwsPass **output) +{ +const SwsPixelType type = SWS_PIXEL_F32; + +SwsContext *ctx = graph->ctx; +SwsOpList *ops = NULL; +int ret = AVERROR(ENOTSUP); + +/* Mark the entire new ops infrastructure as experimental for now */ +if (!(ctx->flags & SWS_UNSTABLE)) +goto fail; + +/* The new format conversion layer cannot scale for now */ +if (src.width != dst.width || src.height != dst.height || +src.desc->log2_chroma_h || src.desc->log2_chroma_w || +dst.desc->log2_chroma_h || dst.desc->log2_chroma_w) +goto fail; + +/* The new code does not yet support alpha blending */ +if (src.desc->flags & AV_PIX_FMT_FLAG_ALPHA && +ctx->alpha_blend != SWS_ALPHA_BLEND_NONE) +goto fail; + +ops = ff_sws_op_list_alloc(); +if (!ops) +return AVERROR(ENOMEM); +ops->src = src; +ops->dst = dst; + +ret = ff_sws_decode_pixfmt(ops, src.format); +if (ret < 0) +goto fail; +ret = ff_sws_decode_colors(ctx, type, ops, src, &graph->incomplete); +if (ret < 0) +goto fail; +ret = ff_sws_encode_colors(ctx, type, ops, dst, &graph->incomplete); +if (ret < 0) +goto fail; +ret = ff_sws_encode_pixfmt(ops, dst.format); +if (ret < 0) +goto fail; + +av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n", + av_get_pix_fmt_name(src.format), av_get_pix_fmt_name(dst.format)); + +av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n"); +ff_sws_op_list_print(ctx, AV_LOG_DEBUG, ops); +av_log(ctx, AV_LOG_DEBUG, "Optimized operation list:\n"); + +ff_sws_op_list_optimize(ops); +if (ops->num_ops == 0) { +av_log(ctx, AV_LOG_VERBOSE, " optimized into memcpy\n"); +ff_sws_op_list_free(&ops); +*output = input; +return 0; +} + +ff_sws_op_list_print(ctx, AV_LOG_VERBOSE, ops); + +ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output); +if (ret < 0) +goto fail; + +ret = 0; +/* fall through */ + +fail: +ff_sws_op_list_free(&ops); +if (ret == AVERROR(ENOTSUP)) +return add_legacy_sws_pass(graph, src, dst, input, output); +return ret; +} + + /** * Gamut and tone mapping * **/ @@ -524,7 +604,7 @@ static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, if (fmt_in != src.format) { SwsFormat tmp = src; tmp.format = fmt_in; -ret = add_legacy_sws_pass(graph, src, tmp, input, &input); +ret = add_convert_pass(graph, src, tmp, input, &input); if (ret < 0) return ret; } @@ -566,7 +646,7 @@ static int init_passes(SwsGraph *graph) src.color = dst.color; if (!ff_fmt_equal(&src, &dst)) { -ret = add_legacy_sws_pass(graph, src, dst, pass, &pass); +ret = add_convert_pass(graph, src, dst, pass, &pass); if (ret < 0) return ret; } -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v5 06/19] avutil/mem: add av_dynarray2_dup
Niklas Haas: > On Tue, 10 Jun 2025 15:04:57 +0200 Niklas Haas wrote: >> From: Niklas Haas >> >> Like av_memdup() but correctly rounds up to the nearest power of two so that >> av_dynarray2_add() will continue to work on the duplicated list. > > Just realized this is public, will add a Changelog entry and bump the API > version before merging. Is this version supposed to be merged? Anyway, this function seems way too specialised to me. - Andreas ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v5 06/19] avutil/mem: add av_dynarray2_dup
On Tue, 10 Jun 2025 15:04:57 +0200 Niklas Haas wrote: > From: Niklas Haas > > Like av_memdup() but correctly rounds up to the nearest power of two so that > av_dynarray2_add() will continue to work on the duplicated list. Just realized this is public, will add a Changelog entry and bump the API version before merging. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v5 06/19] avutil/mem: add av_dynarray2_dup
Niklas Haas: > On Tue, 10 Jun 2025 15:55:35 +0200 Andreas Rheinhardt > wrote: >> Niklas Haas: >>> On Tue, 10 Jun 2025 15:04:57 +0200 Niklas Haas wrote: From: Niklas Haas Like av_memdup() but correctly rounds up to the nearest power of two so that av_dynarray2_add() will continue to work on the duplicated list. >>> >>> Just realized this is public, will add a Changelog entry and bump the API >>> version before merging. >> Is this version supposed to be merged? >> Anyway, this function seems way too specialised to me. > > What would you prefer? Simply having this logic inside swscale? I'm not > very happy making cross-library assumptions about the exact resizing schedule. > The behavior is documented: " * The array is reallocated when its number of elements reaches powers of 2." Alternatively, you could call add the elements in a loop. > Alternatively, we could ditch the use of av_dynarray2 entirely. > Fine by me. - Andreas ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] ffprobe: add -codec: option
--- Begin Message --- opt_codec() is mostly copied over from ffplay.c Signed-off-by: Maryla Ustarroz-Calonge --- Changelog | 2 +- fftools/ffprobe.c | 114 +- 2 files changed, 103 insertions(+), 13 deletions(-) diff --git a/Changelog b/Changelog index 4217449438..ae73611222 100644 --- a/Changelog +++ b/Changelog @@ -18,7 +18,7 @@ version : - APV encoding support through a libopenapv wrapper - VVC decoder supports all content of SCC (Screen Content Coding): IBC (Inter Block Copy), Palette Mode and ACT (Adaptive Color Transform - +- ffprobe -codec option version 7.1: - Raw Captions with Time (RCWT) closed caption demuxer diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index 1346ed33c5..0124ce114c 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -36,6 +36,7 @@ #include "libavutil/ambient_viewing_environment.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/avutil.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" #include "libavutil/display.h" @@ -130,6 +131,11 @@ static int use_byte_value_binary_prefix = 0; static int use_value_sexagesimal_format = 0; static int show_private_data= 1; +static const char *audio_codec_name = NULL; +static const char *data_codec_name = NULL; +static const char *subtitle_codec_name = NULL; +static const char *video_codec_name = NULL; + #define SHOW_OPTIONAL_FIELDS_AUTO -1 #define SHOW_OPTIONAL_FIELDS_NEVER 0 #define SHOW_OPTIONAL_FIELDS_ALWAYS 1 @@ -2284,6 +2290,64 @@ static void show_error(AVTextFormatContext *tfc, int err) avtext_print_section_footer(tfc); } +static int get_decoder_by_name(const char *codec_name, const AVCodec **codec) +{ +if (codec_name == NULL) +return 0; + +*codec = avcodec_find_decoder_by_name(codec_name); +if (*codec == NULL) { +av_log(NULL, AV_LOG_ERROR, +"No codec could be found with name '%s'\n", codec_name); +return AVERROR(EINVAL);; +} +return 0; +} + +static int set_decoders(AVFormatContext *fmt_ctx) +{ +int ret; +ret = get_decoder_by_name(audio_codec_name, &fmt_ctx->audio_codec); +if (ret < 0) return ret; +ret = get_decoder_by_name(data_codec_name, &fmt_ctx->data_codec); +if (ret < 0) return ret; +ret = get_decoder_by_name(subtitle_codec_name, &fmt_ctx->subtitle_codec); +if (ret < 0) return ret; +ret = get_decoder_by_name(video_codec_name, &fmt_ctx->video_codec); +if (ret < 0) return ret; +return 0; +} + +static const AVCodec *get_decoder_for_stream(AVFormatContext *fmt_ctx, AVStream *stream) +{ +const AVCodec *codec = NULL; +switch (stream->codecpar->codec_type) { +case AVMEDIA_TYPE_VIDEO:codec = fmt_ctx->video_codec; break; +case AVMEDIA_TYPE_AUDIO:codec = fmt_ctx->audio_codec; break; +case AVMEDIA_TYPE_SUBTITLE: codec = fmt_ctx->subtitle_codec; break; +case AVMEDIA_TYPE_DATA: codec = fmt_ctx->data_codec; break; +} + +if (codec != NULL) +return codec; + +if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) { +av_log(NULL, AV_LOG_WARNING, + "Failed to probe codec for input stream %d\n", stream->index); +return NULL; +} + +codec = avcodec_find_decoder(stream->codecpar->codec_id); +if (codec == NULL) { +av_log(NULL, AV_LOG_WARNING, + "Unsupported codec with id %d for input stream %d\n", + stream->codecpar->codec_id, stream->index); +return NULL; +} + +return codec; +} + static int open_input_file(InputFile *ifile, const char *filename, const char *print_filename) { @@ -2296,6 +2360,9 @@ static int open_input_file(InputFile *ifile, const char *filename, if (!fmt_ctx) return AVERROR(ENOMEM); +err = set_decoders(fmt_ctx); +if (err < 0) +return err; if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); scan_all_pmts_set = 1; @@ -2350,20 +2417,10 @@ static int open_input_file(InputFile *ifile, const char *filename, ist->st = stream; -if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) { -av_log(NULL, AV_LOG_WARNING, - "Failed to probe codec for input stream %d\n", -stream->index); +codec = get_decoder_for_stream(fmt_ctx, stream); +if (!codec) continue; -} -codec = avcodec_find_decoder(stream->codecpar->codec_id); -if (!codec) { -av_log(NULL, AV_LOG_WARNING, -"Unsupported codec with id %d for input stream %d\n", -stream->codecpar->codec_id, stream->index); -continue; -} { AVDictionary *opts; @@ -2510,6 +2567,
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
On Tue, Jun 10, 2025 at 4:11 PM Michael Niedermayer wrote: > Hi Pavel > > On Tue, Jun 10, 2025 at 11:27:37AM -0600, Pavel Koshevoy wrote: > > On Tue, Jun 10, 2025 at 9:29 AM Michael Niedermayer < > mich...@niedermayer.cc> > [...] > > > I have never had any intention of introducing a > > security vulnerability. > > do you agree that the patch should be reverted ? > (and also the 2 backports of it) > No, since I already provided a fix -- I would cherry-pick it to the release/6.1 and release/7.1 as well, but you do as you wish. > > > > If people want to keep this, it should be behind a flag and > > > disabled by default. > > > > > > I am not familiar with such flags ... are you suggesting a compile-time > > flag, or a run-time flag? > > A runtime flag would be preferable, because that would save me from > having > > to cross-compile win64 ffmpeg libs myself. > > runtime > > > > > > > > Its not enough to fix our code that crashes, other applications > > > similarly wont expect such id and type changes mid stream > > > > > > IDK how likely a media type change is outside the 1_poc.mp4. > > 100% likelyness an exploit of this will use it > > > > The sample > > files I have don't do that. > > Your sample files are not exploits i assume. So obviously > they dont > > > > I can provide a 61MB clip of one such file, just a few seconds of SDR > mpeg2 > > video/audio slate followed by a few seconds of HDR10 hevc video and eac3 > > audio... in case someone wants to work on making fftools support this. > > This file certainly is valuable and should be added to samples.ffmpeg.org > > BUT this security issue needs to be fixed, regardless of > anyone adding support for such samples > > I dont think backporting midstream codec_id/type changes is a good > idea btw. > > IMHO this should all be reverted (its a small 3 line patch) > and then again start from scratch with review, testing, fuzzing, and > runtime flag. > > PS: The researcher also wants a CVE# for this issue. > IDK what this means. > > thx > > [...] > -- > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB > > What is money laundering? Its paying someone and not telling the > government. > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 1/3] vulkan: fix leak in FFVkExecPool
--- libavutil/vulkan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c index a989e080abd372b8977dce107100b9370fac8305..eea80d0775a87ed6683cb58d30ba9ba8d6c1dd26 100644 --- a/libavutil/vulkan.c +++ b/libavutil/vulkan.c @@ -298,6 +298,8 @@ void ff_vk_exec_pool_free(FFVulkanContext *s, FFVkExecPool *pool) av_freep(&sd->desc_sets); } +av_freep(&pool->reg_shd); + for (int i = 0; i < pool->pool_size; i++) { if (pool->cmd_buf_pools[i]) vk->FreeCommandBuffers(s->hwctx->act_dev, pool->cmd_buf_pools[i], -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 0/3] Fix memory leaks in vulkan ffv1 decoding
This fixes a few leaks reported by LeakSanitizer. I tested this on my Intel laptop running anv, with these patches no more leaks are detected. Signed-off-by: averne --- averne (3): vulkan: fix leak in FFVkExecPool vulkan/ffv1dec: fix leak in FFVulkanDecodeShared vulkan/ffv1dec: fix FFVkSPIRVCompiler leak libavcodec/vulkan_ffv1.c | 60 libavutil/vulkan.c | 2 ++ 2 files changed, 27 insertions(+), 35 deletions(-) --- base-commit: 4059bce713118f961d24b5f08a4881c5e7214f9b change-id: 20250610-vk-ffv1-leaks-7f0722236745 Best regards, -- averne ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 3/3] vulkan/ffv1dec: fix FFVkSPIRVCompiler leak
--- libavcodec/vulkan_ffv1.c | 58 +++- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c index 8329b5d7dfad18de96884ea2c1f6f186682e430c..b02bc71683fd7d06dad3f4cf667ee3e8c57f3c83 100644 --- a/libavcodec/vulkan_ffv1.c +++ b/libavcodec/vulkan_ffv1.c @@ -1033,23 +1033,17 @@ static int vk_decode_ffv1_init(AVCodecContext *avctx) /* Intermediate frame pool for RCT */ for (int i = 0; i < 2; i++) { /* 16/32 bit */ -err = init_indirect(avctx, &ctx->s, &fv->intermediate_frames_ref[i], -i ? AV_PIX_FMT_GBRAP32 : AV_PIX_FMT_GBRAP16); -if (err < 0) -return err; +RET(init_indirect(avctx, &ctx->s, &fv->intermediate_frames_ref[i], + i ? AV_PIX_FMT_GBRAP32 : AV_PIX_FMT_GBRAP16)); } /* Setup shader */ -err = init_setup_shader(f, &ctx->s, &ctx->exec_pool, spv, &fv->setup); -if (err < 0) -return err; +RET(init_setup_shader(f, &ctx->s, &ctx->exec_pool, spv, &fv->setup)); /* Reset shaders */ for (int i = 0; i < 2; i++) { /* AC/Golomb */ -err = init_reset_shader(f, &ctx->s, &ctx->exec_pool, -spv, &fv->reset[i], !i ? AC_RANGE_CUSTOM_TAB : 0); -if (err < 0) -return err; +RET(init_reset_shader(f, &ctx->s, &ctx->exec_pool, + spv, &fv->reset[i], !i ? AC_RANGE_CUSTOM_TAB : 0)); } /* Decode shaders */ @@ -1059,39 +1053,31 @@ static int vk_decode_ffv1_init(AVCodecContext *avctx) AVHWFramesContext *dec_frames_ctx; dec_frames_ctx = k ? (AVHWFramesContext *)fv->intermediate_frames_ref[i]->data : (AVHWFramesContext *)avctx->hw_frames_ctx->data; -err = init_decode_shader(f, &ctx->s, &ctx->exec_pool, - spv, &fv->decode[i][j][k], - dec_frames_ctx, - (AVHWFramesContext *)avctx->hw_frames_ctx->data, - i, - !j ? AC_RANGE_CUSTOM_TAB : AC_GOLOMB_RICE, - k); -if (err < 0) -return err; +RET(init_decode_shader(f, &ctx->s, &ctx->exec_pool, + spv, &fv->decode[i][j][k], + dec_frames_ctx, + (AVHWFramesContext *)avctx->hw_frames_ctx->data, + i, + !j ? AC_RANGE_CUSTOM_TAB : AC_GOLOMB_RICE, + k)); } } } /* Range coder data */ -err = ff_ffv1_vk_init_state_transition_data(&ctx->s, -&fv->rangecoder_static_buf, -f); -if (err < 0) -return err; +RET(ff_ffv1_vk_init_state_transition_data(&ctx->s, + &fv->rangecoder_static_buf, + f)); /* Quantization table data */ -err = ff_ffv1_vk_init_quant_table_data(&ctx->s, - &fv->quant_buf, - f); -if (err < 0) -return err; +RET(ff_ffv1_vk_init_quant_table_data(&ctx->s, + &fv->quant_buf, + f)); /* CRC table buffer */ -err = ff_ffv1_vk_init_crc_table_data(&ctx->s, - &fv->crc_tab_buf, - f); -if (err < 0) -return err; +RET(ff_ffv1_vk_init_crc_table_data(&ctx->s, + &fv->crc_tab_buf, + f)); /* Update setup global descriptors */ RET(ff_vk_shader_update_desc_buffer(&ctx->s, &ctx->exec_pool.contexts[0], @@ -1124,6 +1110,8 @@ static int vk_decode_ffv1_init(AVCodecContext *avctx) } fail: +spv->uninit(&spv); + return err; } -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 2/3] vulkan/ffv1dec: fix leak in FFVulkanDecodeShared
--- libavcodec/vulkan_ffv1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavcodec/vulkan_ffv1.c b/libavcodec/vulkan_ffv1.c index c839f4c3879e158e0c0bfb4f5a833fff0b83d2f0..8329b5d7dfad18de96884ea2c1f6f186682e430c 100644 --- a/libavcodec/vulkan_ffv1.c +++ b/libavcodec/vulkan_ffv1.c @@ -995,6 +995,8 @@ static void vk_decode_ffv1_uninit(FFVulkanDecodeShared *ctx) av_buffer_pool_uninit(&fv->slice_state_pool); av_buffer_pool_uninit(&fv->slice_offset_pool); av_buffer_pool_uninit(&fv->slice_status_pool); + +av_freep(&fv); } static int vk_decode_ffv1_init(AVCodecContext *avctx) -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 1/2] lavf/webvttenc: avio_flush() output
On Tue, 10 Jun 2025, Andreas Rheinhardt wrote: Tomas Härdin: Hi These two patches are a bit of a warmup for another pass at streamable subtitles. FATE passes. /Tomas Users who want this should set the generic flush_packets options appropriately. Agreed, explicit avio_flush() in packet writer functions is a bad idea because it flushes IO even on not latency critical outputs. There is some magic in the flush_if_needed() function of mux.c, which by default uses avio_write_marker() to flush after every packet for streaming outputs only. Regards, Marton ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 0/3] Fix memory leaks in vulkan ffv1 decoding
On 11/06/2025 03:58, averne wrote: This fixes a few leaks reported by LeakSanitizer. I tested this on my Intel laptop running anv, with these patches no more leaks are detected. Signed-off-by: averne --- averne (3): vulkan: fix leak in FFVkExecPool vulkan/ffv1dec: fix leak in FFVulkanDecodeShared vulkan/ffv1dec: fix FFVkSPIRVCompiler leak libavcodec/vulkan_ffv1.c | 60 libavutil/vulkan.c | 2 ++ 2 files changed, 27 insertions(+), 35 deletions(-) --- base-commit: 4059bce713118f961d24b5f08a4881c5e7214f9b change-id: 20250610-vk-ffv1-leaks-7f0722236745 Best regards, LGTM Thanks, pushed the patchset. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 03/19] swscale/format: add ff_fmt_clear()
From: Niklas Haas Reset an SwsFormat to its fully unset/invalid state. --- libswscale/format.h | 14 ++ 1 file changed, 14 insertions(+) diff --git a/libswscale/format.h b/libswscale/format.h index 3b6d745159..be92038f4f 100644 --- a/libswscale/format.h +++ b/libswscale/format.h @@ -85,6 +85,20 @@ typedef struct SwsFormat { SwsColor color; } SwsFormat; +static inline void ff_fmt_clear(SwsFormat *fmt) +{ +*fmt = (SwsFormat) { +.format = AV_PIX_FMT_NONE, +.range = AVCOL_RANGE_UNSPECIFIED, +.csp= AVCOL_SPC_UNSPECIFIED, +.loc= AVCHROMA_LOC_UNSPECIFIED, +.color = { +.prim = AVCOL_PRI_UNSPECIFIED, +.trc = AVCOL_TRC_UNSPECIFIED, +}, +}; +} + /** * This function also sanitizes and strips the input data, removing irrelevant * fields for certain formats. -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 05/19] tests/checkasm: generalize DEF_CHECKASM_CHECK_FUNC to floats
From: Niklas Haas We split the standard macro into its body (implementation) and declaration, and use a macro argument in place of the raw `memcmp` call, with the major difference that we now take the number of pixels to compare instead of the number of bytes (to match the signature of float_near_ulp_array). --- tests/checkasm/checkasm.c | 52 ++- tests/checkasm/checkasm.h | 7 ++ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index 71d1e5766c..f393a0cb96 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -1187,14 +1187,8 @@ static int check_err(const char *file, int line, return 0; } -#define DEF_CHECKASM_CHECK_FUNC(type, fmt) \ -int checkasm_check_##type(const char *file, int line, \ - const type *buf1, ptrdiff_t stride1, \ - const type *buf2, ptrdiff_t stride2, \ - int w, int h, const char *name, \ - int align_w, int align_h, \ - int padding) \ -{ \ +#define DEF_CHECKASM_CHECK_BODY(compare, type, fmt) \ +do { \ int64_t aligned_w = (w - 1LL + align_w) & ~(align_w - 1); \ int64_t aligned_h = (h - 1LL + align_h) & ~(align_h - 1); \ int err = 0; \ @@ -1204,7 +1198,7 @@ int checkasm_check_##type(const char *file, int line, \ stride1 /= sizeof(*buf1); \ stride2 /= sizeof(*buf2); \ for (y = 0; y < h; y++) \ -if (memcmp(&buf1[y*stride1], &buf2[y*stride2], w*sizeof(*buf1))) \ +if (!compare(&buf1[y*stride1], &buf2[y*stride2], w)) \ break; \ if (y != h) { \ if (check_err(file, line, name, w, h, &err)) \ @@ -1226,38 +1220,50 @@ int checkasm_check_##type(const char *file, int line, \ buf2 -= h*stride2; \ } \ for (y = -padding; y < 0; y++) \ -if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \ - (w + 2*padding)*sizeof(*buf1))) { \ +if (!compare(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \ + w + 2*padding)) { \ if (check_err(file, line, name, w, h, &err)) \ return 1; \ fprintf(stderr, " overwrite above\n"); \ break; \ } \ for (y = aligned_h; y < aligned_h + padding; y++) \ -if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \ - (w + 2*padding)*sizeof(*buf1))) { \ +if (!compare(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \ + w + 2*padding)) { \ if (check_err(file, line, name, w, h, &err)) \ return 1; \ fprintf(stderr, " overwrite below\n"); \ break; \ } \ for (y = 0; y < h; y++) \ -if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \ - padding*sizeof(*buf1))) { \ +if (!compare(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \ + padding)) { \ if (check_err(file, line, name, w, h, &err)) \ return 1; \ fprintf(stderr, " overwrite left\n"); \ break; \ } \ for (y = 0; y < h; y++) \ -if (memcmp(&buf1[y*stride1 + aligned_w], &buf2[y*stride2 + aligned_w], \ - padding*sizeof(*buf1))) { \ +if (!compare(&buf1[y*stride1 + aligned_w], &buf2[y*stride2 + aligned_w], \ + padding)) { \ if (check_err(file, line, name, w, h, &err)) \ return 1; \ fprintf(stderr, " overwrite right\n"); \ break; \ } \ return err; \ +} while (0) + +#define cmp_int(a, b, len) (!memcmp(a, b, (len) * sizeof(*(a +#define DEF_CHECKASM_CHECK_FUNC(type, fmt) \ +int checkasm_check_##type(const char *file, int line, \ + const type *buf1, ptrdiff_t stride1, \ + const type *buf2, ptrdiff_t stride2, \ + int w, int h, const char *name, \ + int align_w, int align_h, \ + int padding) \ +{ \ +DEF_CHECKASM_CHECK_BODY(cmp_int, type, fmt); \ } DEF_CHECKASM_CHECK_FUNC(uint8_t, "%02x") @@ -1265,3 +1271,15 @@ DEF_CHECKASM_CHECK_FUNC(uint16_t, "%04x") DEF_CHECKASM_CHECK_FUNC(uint32_t, "%08x") DEF_CHECKASM_CHECK_FUNC(int16_t, "%6d") DEF_CHECKASM_CHECK_FUNC(int32_t, "%9d") + +int checkasm_check_float_ulp(const char *file, int line, + const float *buf1, ptrdiff_t stride1, + const float *buf2, ptrdiff_t stride2, + int w, int h, const char *name, + unsigned max_ulp, int align_w, int align_h, + int padding) +{ +#define cmp_float(a, b, len) float_near_ulp_array(a, b, max_ulp, len)
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
On Mon, Jun 09, 2025 at 09:45:28PM -0600, Pavel Koshevoy wrote: > Fixes 'ffprobe 1_poc.mp4' segfault introduced with > commit 0021484d05f9b0f032fa319399de6e24eea0c04f > > codec_close should not assume that the codec_id did not change. > --- > libavformat/demux.c | 8 +++- > 1 file changed, 7 insertions(+), 1 deletion(-) > > diff --git a/libavformat/demux.c b/libavformat/demux.c > index ecd4f40da9..3749ab67a3 100644 > --- a/libavformat/demux.c > +++ b/libavformat/demux.c > @@ -1292,9 +1292,15 @@ static int codec_close(FFStream *sti) > { > AVCodecContext *avctx_new = NULL; > AVCodecParameters *par_tmp = NULL; > +const AVCodec *new_codec = NULL; > int ret; > > -avctx_new = avcodec_alloc_context3(sti->avctx->codec); > +new_codec = > + (sti->avctx->codec_id != sti->pub.codecpar->codec_id) ? > + avcodec_find_decoder(sti->pub.codecpar->codec_id) : > + sti->avctx->codec; > + > +avctx_new = avcodec_alloc_context3(new_codec); > if (!avctx_new) { > ret = AVERROR(ENOMEM); > goto fail; This is not about request_probe but about the mpegts demuxer randomly changeing codec id midstream I belive the patch should be reverted that causes this. I dont think applications expect such mid stream changes either I hope andreas can take a look and correct me if iam missing something but it looks a bit sketchy to me If a codec changes mid stream i belive a new AVStream should be created. It could be a audio stream switches to video or data or subtitle. If any stream as detected initially can become any other type later this complicates user applications and filter graphs Also the management of AVPackets is probably rather non trivial if the stream_index is not enough to identify which decoder it belongs to thx [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Old school: Use the lowest level language in which you can solve the problem conveniently. New school: Use the highest level language in which the latest supercomputer can solve the problem without the user falling asleep waiting. signature.asc Description: PGP signature ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 0/3] tools/ffmpeg-sg: Add show-graph wrapper scripts (aka killer feature)
> -Original Message- > From: Kieran Kunhya > Sent: Dienstag, 10. Juni 2025 00:49 > To: FFmpeg development discussions and patches de...@ffmpeg.org> > Cc: softworkz > Subject: Re: [FFmpeg-devel] [PATCH 0/3] tools/ffmpeg-sg: Add show- > graph wrapper scripts (aka killer feature) > > On Mon, 9 Jun 2025, 20:24 ffmpegagent, gmail@ffmpeg.org> > wrote: > > > The "killer feature" returns! > > > > Different approach - same procedure: > > > > * Add -sg to your FFmpeg command line > > * But now it's not > >* ./ffmpeg -sg x but > >* ./ffmpeg-sg x > > > > Why does this need to be part of FFmpeg if it's a wrapper script to > spawn a > web browser (nothing to do with FFmpeg's actual purpose of processing > multimedia). > > Kieran Hi Kieran, of course that's a legitimate question, and a question that could be asked for almost any new feature in FFmpeg. Obviously, there is no forcing reason for which it would _need_ to be included, so I can only say why it _should_ be included in FFmpeg IMHO: - Highly Useful If you haven't seen what it is and what it does, than I would suggest to everybody to try it out or to look at some of the examples: https://softworkz.github.io/ffmpeg_output_apis/2_hwa_qsv.html https://softworkz.github.io/ffmpeg_output_apis/3_complex_graphs.html This should also answer your question about what it has to do with "FFmpeg' actual purpose of processing multimedia": FFmpeg has a command line interface and it's often not clear to everybody how a certain command line is actually interpreted and executed by FFmpeg. This is helpful for both beginners and advanced users of FFmpeg (e.g. when things get complex like in the second example). Even Michael said he finds it useful and Niklas Haas had voiced a need for visualizing the negotiated image formats between filters, earlier this year. - Highly Convenient This core functionality for the above is already merged into master, but it's rather painful to make use of it - You need to remember the command line parameters - You need to type them - You need to determined a name for the output html file - You need to change it each time when you want to compare commands - You need to manually open the output in a browser It becomes highly convenient when the only thing you need to do and remember is to append "-sg" to any command whenever you need it and everything else happens automatically. You can try many command variations and it creates tabs in your browser between you can switch can compare the different graphs. - Instant Availability This simply means that whenever and wherever you need it... => it's already there It is part of the build output, which means all developers that you can compile, test your work and when you want to visualize the graph you just need to append -sg and it works - without doing any extra work. Same for make install and all kinds of distribution packages. When this is given, we can add a note to the documentation and make this available to Millions of users. If it would be just scripts for download from "somewhere", then it wouldn't be a feature available to Millions, but just something for a few dozens of people who would ever know about it. Those considerations combined is what had originally brought me to the tag line that some found funny and others rather "immature": Highly Useful + Convenient + Instant Availability = "Killer Feature" It's helpful for the masses => it should be available to the masses. This is why I believe that it should be included in FFmpeg. Best regards, softworkz ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 2/2] tests: Add media100 decoder test
From: Zhao Zhili --- The sample comes from https://trac.ffmpeg.org/attachment/ticket/959/12%2027_Volcano%20Zoom-Dissolve-F-8.mov put it to mjpegb/media100.mov tests/fate/video.mak| 3 +++ tests/ref/fate/media100 | 30 ++ 2 files changed, 33 insertions(+) create mode 100644 tests/ref/fate/media100 diff --git a/tests/fate/video.mak b/tests/fate/video.mak index dd886843e7..24889824b4 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -257,6 +257,9 @@ fate-mimic: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/mimic/mimic2-womanl FATE_VIDEO-$(call FRAMECRC, MOV, MJPEGB) += fate-mjpegb fate-mjpegb: CMD = framecrc -idct simple -fflags +bitexact -i $(TARGET_SAMPLES)/mjpegb/mjpegb_part.mov -an +FATE_VIDEO-$(call FRAMECRC, MOV, MEDIA100) += fate-media100 +fate-media100: CMD = framecrc -idct simple -fflags +bitexact -i $(TARGET_SAMPLES)/mjpegb/media100.mov + FATE_VIDEO-$(call FRAMECRC, AVI, MJPEG) += fate-mjpeg-ticket3229 fate-mjpeg-ticket3229: CMD = framecrc -idct simple -fflags +bitexact -i $(TARGET_SAMPLES)/mjpeg/mjpeg_field_order.avi -an diff --git a/tests/ref/fate/media100 b/tests/ref/fate/media100 new file mode 100644 index 00..7a92c5cc21 --- /dev/null +++ b/tests/ref/fate/media100 @@ -0,0 +1,30 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 768x576 +#sar 0: 0/1 +0, 0, 0,1, 884736, 0x22304315 +0, 1, 1,1, 884736, 0x896fcaf0 +0, 2, 2,1, 884736, 0x2e25b031 +0, 3, 3,1, 884736, 0x9d0cdf84 +0, 4, 4,1, 884736, 0x90c799b6 +0, 5, 5,1, 884736, 0x80ac6b03 +0, 6, 6,1, 884736, 0x46cfbd02 +0, 7, 7,1, 884736, 0xee2b4bdb +0, 8, 8,1, 884736, 0x7876581e +0, 9, 9,1, 884736, 0x19490d15 +0, 10, 10,1, 884736, 0x6c37db8d +0, 11, 11,1, 884736, 0xe6a198ae +0, 12, 12,1, 884736, 0x893d08af +0, 13, 13,1, 884736, 0xb52bd038 +0, 14, 14,1, 884736, 0x7074bb1b +0, 15, 15,1, 884736, 0xd32ed044 +0, 16, 16,1, 884736, 0x9592d482 +0, 17, 17,1, 884736, 0x9fcd144b +0, 18, 18,1, 884736, 0xba1c73a2 +0, 19, 19,1, 884736, 0x5fd7c0e7 +0, 20, 20,1, 884736, 0xc3f05ed4 +0, 21, 21,1, 884736, 0x333d0e9c +0, 22, 22,1, 884736, 0x9063fd20 +0, 23, 23,1, 884736, 0xc4508928 +0, 24, 24,1, 884736, 0x1428b800 -- 2.46.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 1/2] avcodec/decode: Workaround for media100 decoding failure issue
From: Zhao Zhili This is a regression since 1c170613. --- libavcodec/decode.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libavcodec/decode.c b/libavcodec/decode.c index ef09568381..7e47a2971c 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -204,9 +204,14 @@ static int decode_bsfs_init(AVCodecContext *avctx) ret = av_bsf_init(avci->bsf); if (ret < 0) goto fail; -ret = avcodec_parameters_to_context(avctx, avci->bsf->par_out); -if (ret < 0) -goto fail; +/* Don't copy par_out to avcodec context if bsf changed codec ID, + * e.g., media100_to_mjpegb + */ +if (avctx->codec_id == avci->bsf->par_out->codec_id) { +ret = avcodec_parameters_to_context(avctx, avci->bsf->par_out); +if (ret < 0) +goto fail; +} return 0; fail: -- 2.46.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 00/19] swscale: new ops framework
Changes since v4: - minor cosmetic fixes - drop unneeded -Wno-uninitialized (breaks on MSVC) - change semantics of SwsGraph.setup() to make more sense (and fix a bug where it would not work correctly with multiple passes) - introduce and use av_dynarray2_dup() instead of av_memdup() for safely duplicating SwsOpList - fix a double free when no backend was found for an SwsOpList - fix insufficient logic on matching SWS_OP_CLEAR - avoid the use of periods in asm globals called from C (breaks on macOS) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 01/19] swscale/graph: pass per-pass image pointers to setup()
From: Niklas Haas This behavior had no real justification and was just incredibly confusing, since the in/out pointers passet to setup() did not match those passed to run(), all for what is arguably an exception anyways (the palette setup). --- libswscale/graph.c | 12 libswscale/graph.h | 2 -- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libswscale/graph.c b/libswscale/graph.c index dc7784aa49..edf243823f 100644 --- a/libswscale/graph.c +++ b/libswscale/graph.c @@ -169,6 +169,8 @@ static void free_legacy_swscale(void *priv) static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in, const SwsPass *pass) { +const SwsGraph *graph = pass->graph; +const SwsImg *in_orig = &graph->exec.input; SwsContext *sws = pass->priv; SwsInternal *c = sws_internal(sws); if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) { @@ -177,7 +179,7 @@ static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in, } if (usePal(sws->src_format)) -ff_update_palette(c, (const uint32_t *) in->data[1]); +ff_update_palette(c, (const uint32_t *) in_orig->data[1]); } static inline SwsContext *slice_ctx(const SwsPass *pass, int y) @@ -710,10 +712,12 @@ void ff_sws_graph_run(SwsGraph *graph, uint8_t *const out_data[4], memcpy(in->linesize, in_linesize, sizeof(in->linesize)); for (int i = 0; i < graph->num_passes; i++) { -const SwsPass *pass = graph->passes[i]; +const SwsPass *pass= graph->passes[i]; graph->exec.pass = pass; -if (pass->setup) -pass->setup(out, in, pass); +if (pass->setup) { +pass->setup(pass->output.fmt != AV_PIX_FMT_NONE ? &pass->output : out, +pass->input ? &pass->input->output : in, pass); +} avpriv_slicethread_execute(graph->slicethread, pass->num_slices, 0); } } diff --git a/libswscale/graph.h b/libswscale/graph.h index 0630b31ce6..b829bac88c 100644 --- a/libswscale/graph.h +++ b/libswscale/graph.h @@ -92,8 +92,6 @@ struct SwsPass { /** * Called once from the main thread before running the filter. Optional. - * `out` and `in` always point to the main image input/output, regardless - * of `input` and `output` fields. */ void (*setup)(const SwsImg *out, const SwsImg *in, const SwsPass *pass); -- 2.49.0 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 0/3] tools/ffmpeg-sg: Add show-graph wrapper scripts (aka killer feature)
> -Original Message- > From: ffmpeg-devel On Behalf Of > softworkz . > Sent: Dienstag, 10. Juni 2025 15:32 > To: Kieran Kunhya ; FFmpeg development > discussions and patches > Subject: Re: [FFmpeg-devel] [PATCH 0/3] tools/ffmpeg-sg: Add show- > graph wrapper scripts (aka killer feature) > > > -Original Message- > > From: Kieran Kunhya > > Sent: Dienstag, 10. Juni 2025 00:49 > > To: FFmpeg development discussions and patches > de...@ffmpeg.org> > > Cc: softworkz > > Subject: Re: [FFmpeg-devel] [PATCH 0/3] tools/ffmpeg-sg: Add show- > > graph wrapper scripts (aka killer feature) > > > > On Mon, 9 Jun 2025, 20:24 ffmpegagent, > gmail@ffmpeg.org> > > wrote: > > > > > The "killer feature" returns! > > > > > > Different approach - same procedure: > > > > > > * Add -sg to your FFmpeg command line > > > * But now it's not > > >* ./ffmpeg -sg x but > > >* ./ffmpeg-sg x > > > > > > > Why does this need to be part of FFmpeg if it's a wrapper script to > > spawn a > > web browser (nothing to do with FFmpeg's actual purpose of > processing > > multimedia). > > > > Kieran > > > Hi Kieran, > > of course that's a legitimate question, and a question that could be > asked > for almost any new feature in FFmpeg. > Obviously, there is no forcing reason for which it would _need_ to be > included, > so I can only say why it _should_ be included in FFmpeg IMHO: > > > - Highly Useful > > If you haven't seen what it is and what it does, than I would > suggest to > everybody to try it out or to look at some of the examples: > > https://softworkz.github.io/ffmpeg_output_apis/2_hwa_qsv.html > > https://softworkz.github.io/ffmpeg_output_apis/3_complex_graphs.html > > This should also answer your question about what it has to do with > "FFmpeg' > actual purpose of processing multimedia": FFmpeg has a command line > interface and it's often not clear to everybody how a certain > command line > is actually interpreted and executed by FFmpeg. This is helpful for > both beginners and advanced users of FFmpeg (e.g. when things get > complex > like in the second example). > Even Michael said he finds it useful and Niklas Haas had voiced a > need > for visualizing the negotiated image formats between filters, > earlier this > year. > > > - Highly Convenient > > This core functionality for the above is already merged into > master, but > it's rather painful to make use of it > - You need to remember the command line parameters > - You need to type them > - You need to determined a name for the output html file > - You need to change it each time when you want to compare commands > - You need to manually open the output in a browser > > It becomes highly convenient when the only thing you need to do and > remember is to append "-sg" to any command whenever you need it and > everything else happens automatically. > You can try many command variations and it creates tabs in your > browser between you can switch can compare the different graphs. > > > - Instant Availability > > This simply means that whenever and wherever you need it... > => it's already there > > It is part of the build output, which means all developers that you > can compile, test your work and when you want to visualize the > graph > you just need to append -sg and it works - without doing any extra > work. > Same for make install and all kinds of distribution packages. > When this is given, we can add a note to the documentation and make > this available to Millions of users. > If it would be just scripts for download from "somewhere", then it > wouldn't be a feature available to Millions, but just something > for a few dozens of people who would ever know about it. > > > Those considerations combined is what had originally brought me > to the tag line that some found funny and others rather "immature": > > Highly Useful + Convenient + Instant Availability = "Killer Feature" > > > It's helpful for the masses => it should be available to the masses. > This is why I believe that it should be included in FFmpeg. > > Best regards, > softworkz > > ___ There's also once another angle of view that should be considered when assessing the relevance of the feature: Learning and Understanding FFmpeg Looking at the documentation under https://ffmpeg.org/ffmpeg.html we can see that a lot of effort has been taken to make FFmpeg's ways of operation transparent and understandable to all new users. Don't all those ASCII graphics look familiar? Essentially, the show- graph feature gives you exactly the same insights than the introductory topics of the documentation - not just in an exemplary way but for the exact command lines that you are supplying to FFmpeg. This helps to reduce the learning curve for using of FFmpeg - which is non-trivial - by a magnitude. Even those who don't think that they would
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
Hi Pavel On Tue, Jun 10, 2025 at 08:42:08AM -0600, Pavel Koshevoy wrote: > On Tue, Jun 10, 2025, 07:39 Michael Niedermayer > wrote: > > > On Mon, Jun 09, 2025 at 09:45:28PM -0600, Pavel Koshevoy wrote: > > > Fixes 'ffprobe 1_poc.mp4' segfault introduced with > > > commit 0021484d05f9b0f032fa319399de6e24eea0c04f > > > > > > codec_close should not assume that the codec_id did not change. > > > --- > > > libavformat/demux.c | 8 +++- > > > 1 file changed, 7 insertions(+), 1 deletion(-) > > > > > > diff --git a/libavformat/demux.c b/libavformat/demux.c > > > index ecd4f40da9..3749ab67a3 100644 > > > --- a/libavformat/demux.c > > > +++ b/libavformat/demux.c > > > @@ -1292,9 +1292,15 @@ static int codec_close(FFStream *sti) > > > { > > > AVCodecContext *avctx_new = NULL; > > > AVCodecParameters *par_tmp = NULL; > > > +const AVCodec *new_codec = NULL; > > > int ret; > > > > > > -avctx_new = avcodec_alloc_context3(sti->avctx->codec); > > > +new_codec = > > > + (sti->avctx->codec_id != sti->pub.codecpar->codec_id) ? > > > + avcodec_find_decoder(sti->pub.codecpar->codec_id) : > > > + sti->avctx->codec; > > > + > > > +avctx_new = avcodec_alloc_context3(new_codec); > > > if (!avctx_new) { > > > ret = AVERROR(ENOMEM); > > > goto fail; > > > > This is not about request_probe > > but about the mpegts demuxer randomly changeing codec id midstream > > > > > I have several real (not crafted like 1_poc.mp4 is) .ts files where codec > changes from mpeg2video to hevc, from mpeg2audio to eac3 -- while remaining > on the same PIDs. I also have .ts files where codec switches between > mpeg2video and h264. VLC was able to play such files, but my ffmpeg based > player (apprenticevideo) could not even see that the codecs changed prior > to 0021484d05f9b0f032fa319399de6e24eea0c04f. do these work ? (work here means the result is a complete file with all frames from the input and is playable and seekable) ./ffmpeg -i input.ts -codec copy output.ts ./ffmpeg -i input.ts -codec copy output.mp4 ./ffmpeg -i input.ts -vcodec libx264 -acodec libopus output.mkv > Reverting isn't really an > option for me, not unless there is a better solution presented. is adding an exploitable security issue an option for you ? If people want to keep this, it should be behind a flag and disabled by default. Its not enough to fix our code that crashes, other applications similarly wont expect such id and type changes mid stream > > As I am primarily a public ffmpeg API user -- I am well out of my depth > when it comes to making non-trivial changes to ffmpegs internals. Thats ok, but you applied this change to ffmpeg internals, and here you say "I am well out of my depth when it comes to making non-trivial changes to ffmpegs internals." Did someone review this ? commit 0021484d05f9b0f032fa319399de6e24eea0c04f Author: Pavel Koshevoy AuthorDate: Sun May 18 08:57:31 2025 -0600 Commit: Pavel Koshevoy CommitDate: Sun May 18 08:57:31 2025 -0600 thx [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB The greatest way to live with honor in this world is to be what we pretend to be. -- Socrates signature.asc Description: PGP signature ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
On Tue, Jun 10, 2025 at 9:29 AM Michael Niedermayer wrote: > Hi Pavel > > On Tue, Jun 10, 2025 at 08:42:08AM -0600, Pavel Koshevoy wrote: > > On Tue, Jun 10, 2025, 07:39 Michael Niedermayer > > wrote: > > > > > On Mon, Jun 09, 2025 at 09:45:28PM -0600, Pavel Koshevoy wrote: > > > > Fixes 'ffprobe 1_poc.mp4' segfault introduced with > > > > commit 0021484d05f9b0f032fa319399de6e24eea0c04f > > > > > > > > codec_close should not assume that the codec_id did not change. > > > > --- > > > > libavformat/demux.c | 8 +++- > > > > 1 file changed, 7 insertions(+), 1 deletion(-) > > > > > > > > diff --git a/libavformat/demux.c b/libavformat/demux.c > > > > index ecd4f40da9..3749ab67a3 100644 > > > > --- a/libavformat/demux.c > > > > +++ b/libavformat/demux.c > > > > @@ -1292,9 +1292,15 @@ static int codec_close(FFStream *sti) > > > > { > > > > AVCodecContext *avctx_new = NULL; > > > > AVCodecParameters *par_tmp = NULL; > > > > +const AVCodec *new_codec = NULL; > > > > int ret; > > > > > > > > -avctx_new = avcodec_alloc_context3(sti->avctx->codec); > > > > +new_codec = > > > > + (sti->avctx->codec_id != sti->pub.codecpar->codec_id) ? > > > > + avcodec_find_decoder(sti->pub.codecpar->codec_id) : > > > > + sti->avctx->codec; > > > > + > > > > +avctx_new = avcodec_alloc_context3(new_codec); > > > > if (!avctx_new) { > > > > ret = AVERROR(ENOMEM); > > > > goto fail; > > > > > > This is not about request_probe > > > but about the mpegts demuxer randomly changeing codec id midstream > > > > > > > > > I have several real (not crafted like 1_poc.mp4 is) .ts files where codec > > changes from mpeg2video to hevc, from mpeg2audio to eac3 -- while > remaining > > on the same PIDs. I also have .ts files where codec switches between > > mpeg2video and h264. VLC was able to play such files, but my ffmpeg > based > > player (apprenticevideo) could not even see that the codecs changed prior > > to 0021484d05f9b0f032fa319399de6e24eea0c04f. > > do these work ? > (work here means the result is a complete file with all frames from the > input > and is playable and seekable) > ./ffmpeg -i input.ts -codec copy output.ts > ./ffmpeg -i input.ts -codec copy output.mp4 > ./ffmpeg -i input.ts -vcodec libx264 -acodec libopus output.mkv > not really relevant because if they don't work -- it's a defect in the command line tool, not the demuxer. I need the libavformat API to work with mpeg-ts data I have, I don't actually care if ffprobe/ffplay/ffmpeg can handle these files ... they couldn't handle them before and they still can't, but I'm not an fftools maintainer so I don't think I'll be taking on a 3rd job to fix fftools as well. > > > Reverting isn't really an > > option for me, not unless there is a better solution presented. > > is adding an exploitable security issue an option for you ? > I'm not a security expert, but IIRC the patch I've posted here fixes the segfault you are referring to? > > If people want to keep this, it should be behind a flag and > disabled by default. > > Its not enough to fix our code that crashes, other applications > similarly wont expect such id and type changes mid stream > If mpeg-ts allows the codecs to change at any time -- it's a bug in the application if it doesn't support that. > > > > > > As I am primarily a public ffmpeg API user -- I am well out of my depth > > when it comes to making non-trivial changes to ffmpegs internals. > > Thats ok, but you applied this change to ffmpeg internals, and here > you say "I am well out of my depth when it comes to making non-trivial > changes to ffmpegs internals." > > Did someone review this ? > No, it was ignored for weeks. > > commit 0021484d05f9b0f032fa319399de6e24eea0c04f > Author: Pavel Koshevoy > AuthorDate: Sun May 18 08:57:31 2025 -0600 > Commit: Pavel Koshevoy > CommitDate: Sun May 18 08:57:31 2025 -0600 > > > thx > > [...] > > -- > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB > > The greatest way to live with honor in this world is to be what we pretend > to be. -- Socrates > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 14/19] swscale/ops_backend: add reference backend basend on C templates
From: Niklas Haas This will serve as a reference for the SIMD backends to come. That said, with auto-vectorization enabled, the performance of this is not atrocious. It easily beats the old C code and sometimes even the old SIMD. In theory, we can dramatically speed it up by using GCC vectors instead of arrays, but the performance gains from this are too dependent on exact GCC versions and flags, so it practice it's not a substitute for a SIMD implementation. --- libswscale/Makefile | 5 + libswscale/ops.c | 3 + libswscale/ops_backend.c | 105 ++ libswscale/ops_backend.h | 167 ++ libswscale/ops_tmpl_common.c | 176 ++ libswscale/ops_tmpl_float.c | 257 +++ libswscale/ops_tmpl_int.c| 603 +++ 7 files changed, 1316 insertions(+) create mode 100644 libswscale/ops_backend.c create mode 100644 libswscale/ops_backend.h create mode 100644 libswscale/ops_tmpl_common.c create mode 100644 libswscale/ops_tmpl_float.c create mode 100644 libswscale/ops_tmpl_int.c diff --git a/libswscale/Makefile b/libswscale/Makefile index c9dfa78c89..d3cb7bc555 100644 --- a/libswscale/Makefile +++ b/libswscale/Makefile @@ -16,6 +16,7 @@ OBJS = alphablend.o \ input.o \ lut3d.o \ ops.o\ + ops_backend.o\ ops_chain.o \ ops_optimizer.o \ options.o\ @@ -29,6 +30,10 @@ OBJS = alphablend.o \ yuv2rgb.o\ vscale.o \ +OPS-CFLAGS = -ffinite-math-only + +$(SUBDIR)ops_backend.o: CFLAGS += $(OPS-CFLAGS) + # Objects duplicated from other libraries for shared builds SHLIBOBJS+= log2_tab.o half2float.o diff --git a/libswscale/ops.c b/libswscale/ops.c index 5330b37b22..5b259e13be 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -27,7 +27,10 @@ #include "ops.h" #include "ops_internal.h" +extern SwsOpBackend backend_c; + const SwsOpBackend * const ff_sws_op_backends[] = { +&backend_c, NULL }; diff --git a/libswscale/ops_backend.c b/libswscale/ops_backend.c new file mode 100644 index 00..47ce992bb3 --- /dev/null +++ b/libswscale/ops_backend.c @@ -0,0 +1,105 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ops_backend.h" + +/* Array-based reference implementation */ + +#ifndef SWS_BLOCK_SIZE +# define SWS_BLOCK_SIZE 32 +#endif + +typedef uint8_t u8block_t[SWS_BLOCK_SIZE]; +typedef uint16_t u16block_t[SWS_BLOCK_SIZE]; +typedef uint32_t u32block_t[SWS_BLOCK_SIZE]; +typedeffloat f32block_t[SWS_BLOCK_SIZE]; + +#define BIT_DEPTH 8 +# include "ops_tmpl_int.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 16 +# include "ops_tmpl_int.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 32 +# include "ops_tmpl_int.c" +# include "ops_tmpl_float.c" +#undef BIT_DEPTH + +static void process(const SwsOpExec *exec, const void *priv, +const int bx_start, const int y_start, int bx_end, int y_end) +{ +const SwsOpChain *chain = priv; +const SwsOpImpl *impl = chain->impl; +SwsOpIter iter; + +for (iter.y = y_start; iter.y < y_end; iter.y++) { +for (int i = 0; i < 4; i++) { +iter.in[i] = exec->in[i] + (iter.y - y_start) * exec->in_stride[i]; +iter.out[i] = exec->out[i] + (iter.y - y_start) * exec->out_stride[i]; +} + +for (int block = bx_start; block < bx_end; block++) { +iter.x = block * SWS_BLOCK_SIZE; +((void (*)(SwsOpIter *, const SwsOpImpl *)) impl->cont) +(&iter, &impl[1]); +} +} +} + +static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out) +{ +int ret; + +SwsOpChain *chain = ff_sws_op_chain_alloc(); +if (!chain) +return AVERROR(ENOMEM); + +static const SwsOpTable *const tables[] =
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
On Tue, Jun 10, 2025 at 9:29 AM Michael Niedermayer wrote: > Hi Pavel > > > > is adding an exploitable security issue an option for you ? > > ^ that's inflammatory, I have never had any intention of introducing a security vulnerability. If people want to keep this, it should be behind a flag and > disabled by default. I am not familiar with such flags ... are you suggesting a compile-time flag, or a run-time flag? A runtime flag would be preferable, because that would save me from having to cross-compile win64 ffmpeg libs myself. Its not enough to fix our code that crashes, other applications > similarly wont expect such id and type changes mid stream IDK how likely a media type change is outside the 1_poc.mp4. The sample files I have don't do that. I can provide a 61MB clip of one such file, just a few seconds of SDR mpeg2 video/audio slate followed by a few seconds of HDR10 hevc video and eac3 audio... in case someone wants to work on making fftools support this. Pavel. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
Pavel Koshevoy (HE12025-06-10): > ^ that's inflammatory No, that is just sarcastic. -- Nicolas George ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
On Tue, Jun 10, 2025 at 11:31 AM Nicolas George wrote: > Pavel Koshevoy (HE12025-06-10): > > ^ that's inflammatory > > No, that is just sarcastic. > > it managed to ruin my morning ... no matter what you call it. Pavel. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] ogg/vorbis: implement header packet skip in chained ogg bitstreams.
Hi all, Le mer. 4 juin 2025 à 11:58, Romain Beauxis a écrit : > > This is a redo of 574f634e49847e2225ee50013afebf0de03ef013 using a flat > memory storage for the extradata. > > PR review comments addressed: > * Use flat memory bytestream > * Re-use existing xiph extradata layout Is there any interest in reviewing this patch? It's holding the second series that fixes chained ogg stream metadata parsing. Better support for chained ogg streams would really make life easier for a bunch of ffmpeg and ffmpeg libraries users. Thanks, -- Romain > --- > libavcodec/vorbisdec.c | 42 --- > libavformat/oggparsevorbis.c | 83 +- > tests/ref/fate/ogg-vorbis-chained-meta.txt | 3 - > 3 files changed, 114 insertions(+), 14 deletions(-) > > diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c > index adbd726183..84879462a1 100644 > --- a/libavcodec/vorbisdec.c > +++ b/libavcodec/vorbisdec.c > @@ -1778,11 +1778,40 @@ static int vorbis_decode_frame(AVCodecContext *avctx, > AVFrame *frame, > GetBitContext *gb = &vc->gb; > float *channel_ptrs[255]; > int i, len, ret; > +size_t new_extradata_size; > +const uint8_t *new_extradata; > +const uint8_t *header_start[3]; > +int header_len[3] = {0, 0, 0}; > +const uint8_t *header; > +int header_size = 0; > +const uint8_t *comment; > +int comment_size = 0; > +const uint8_t *setup; > +int setup_size = 0; > > ff_dlog(NULL, "packet length %d \n", buf_size); > > -if (*buf == 1 && buf_size > 7) { > -if ((ret = init_get_bits8(gb, buf + 1, buf_size - 1)) < 0) > +new_extradata = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, > +&new_extradata_size); > + > +if (new_extradata) { > +ret = avpriv_split_xiph_headers(new_extradata, new_extradata_size, > +30, header_start, header_len); > +if (ret < 0) > +return ret; > + > +header = header_start[0]; > +header_size = header_len[0]; > + > +comment = header_start[1]; > +comment_size = header_len[1]; > + > +setup = header_start[2]; > +setup_size = header_len[2]; > +} > + > +if (header_size > 7 && *header == 1) { > +if ((ret = init_get_bits8(gb, header + 1, header_size - 1)) < 0) > return ret; > > vorbis_free(vc); > @@ -1801,16 +1830,14 @@ static int vorbis_decode_frame(AVCodecContext *avctx, > AVFrame *frame, > } > > avctx->sample_rate = vc->audio_samplerate; > -return buf_size; > } > > -if (*buf == 3 && buf_size > 7) { > +if (comment_size > 7 && *comment == 3) { > av_log(avctx, AV_LOG_DEBUG, "Ignoring comment header\n"); > -return buf_size; > } > > -if (*buf == 5 && buf_size > 7 && vc->channel_residues && !vc->modes) { > -if ((ret = init_get_bits8(gb, buf + 1, buf_size - 1)) < 0) > +if (setup_size > 7 && *setup == 5 && vc->channel_residues && !vc->modes) > { > +if ((ret = init_get_bits8(gb, setup + 1, setup_size - 1)) < 0) > return ret; > > if ((ret = vorbis_parse_setup_hdr(vc))) { > @@ -1818,7 +1845,6 @@ static int vorbis_decode_frame(AVCodecContext *avctx, > AVFrame *frame, > vorbis_free(vc); > return ret; > } > -return buf_size; > } > > if (!vc->channel_residues || !vc->modes) { > diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c > index 62cc2da6de..7859ec5a51 100644 > --- a/libavformat/oggparsevorbis.c > +++ b/libavformat/oggparsevorbis.c > @@ -215,6 +215,12 @@ struct oggvorbis_private { > AVVorbisParseContext *vp; > int64_t final_pts; > int final_duration; > +uint8_t *header; > +int header_size; > +uint8_t *comment; > +int comment_size; > +uint8_t *setup; > +int setup_size; > }; > > static int fixup_vorbis_headers(AVFormatContext *as, > @@ -260,6 +266,10 @@ static void vorbis_cleanup(AVFormatContext *s, int idx) > av_vorbis_parse_free(&priv->vp); > for (i = 0; i < 3; i++) > av_freep(&priv->packet[i]); > + > +av_freep(&priv->header); > +av_freep(&priv->comment); > +av_freep(&priv->setup); > } > } > > @@ -434,6 +444,9 @@ static int vorbis_packet(AVFormatContext *s, int idx) > struct ogg_stream *os = ogg->streams + idx; > struct oggvorbis_private *priv = os->private; > int duration, flags = 0; > +int skip_packet = 0; > +int ret, new_extradata_size; > +PutByteContext pb; > > if (!priv->vp) > return AVERROR_INVALIDDATA; > @@ -496,10 +509,50 @@ static int vorbis_packet(AVFormatContext *s, int idx) > if (duration < 0) { > os->pflags |= AV_PKT_FLAG_CORRUPT; > return 0; > -} else if (flags & VORBIS_FLAG_COMMENT) { > -vorbis_update_metadat
Re: [FFmpeg-devel] [PATCH] avformat/webvttdec: improve WebVTT parsing
> WebVTT is supposed to be an extensible format. Limiting to a small set of > known values and silently aborting when anything new is introduced does > not seem like the best option to me. Web browsers do not stop rendering > pages when they see a new, unknown HTML tag or CSS option. About this, for interoperability reasons I've checked other multiple implementations of WebVTT parsers and these all follow the approach of silently ignoring unknown chunks: - WebKit (https://github.com/WebKit/WebKit/blob/main/Source/WebCore/html/track/WebVTTParser.cpp#L224-L227) - Chromium's Blink parser (https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc#199) - Mozilla's Gecko (https://searchfox.org/mozilla-central/source/dom/media/webvtt/vtt.sys.mjs#1674-1677) - VLC (https://code.videolan.org/videolan/vlc/-/blob/master/modules/codec/webvtt/webvtt.c) The only one that would report an error, but will still keep parsing anyway, is W3C's own WebVTT.js parser (https://github.com/w3c/webvtt.js/blob/main/parser.js#L150-L153). If that's not enough, I found also in part 2.1 of the WebVTT specification, also copied verbatim: "The parsing rules are more tolerant to author errors than the syntax allows, in order to provide for extensibility and to still render cues that have some syntax errors." Basically, the standard asks to follow Postel's law: "Be conservative in what you send, be liberal in what you accept". ffmpeg should do that. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v5 16/19] swscale/x86: add SIMD backend
From: Niklas Haas This covers most 8-bit and 16-bit ops, and some 32-bit ops. It also covers all floating point operations. While this is not yet 100% coverage, it's good enough for the vast majority of formats out there. Of special note is the packed shuffle fast path, which uses pshufb at vector sizes up to AVX512. --- libswscale/ops.c |4 + libswscale/x86/Makefile |6 + libswscale/x86/ops.c | 723 ++ libswscale/x86/ops_common.asm | 305 ++ libswscale/x86/ops_float.asm | 389 libswscale/x86/ops_int.asm| 1062 + 6 files changed, 2489 insertions(+) create mode 100644 libswscale/x86/ops.c create mode 100644 libswscale/x86/ops_common.asm create mode 100644 libswscale/x86/ops_float.asm create mode 100644 libswscale/x86/ops_int.asm diff --git a/libswscale/ops.c b/libswscale/ops.c index 6a5b4f4158..a9cde2e5b8 100644 --- a/libswscale/ops.c +++ b/libswscale/ops.c @@ -29,9 +29,13 @@ extern SwsOpBackend backend_c; extern SwsOpBackend backend_murder; +extern SwsOpBackend backend_x86; const SwsOpBackend * const ff_sws_op_backends[] = { &backend_murder, +#if ARCH_X86_64 +&backend_x86, +#endif &backend_c, NULL }; diff --git a/libswscale/x86/Makefile b/libswscale/x86/Makefile index f00154941d..f1d6255549 100644 --- a/libswscale/x86/Makefile +++ b/libswscale/x86/Makefile @@ -16,3 +16,9 @@ X86ASM-OBJS += x86/input.o \ x86/rgb_2_rgb.o \ x86/yuv_2_rgb.o \ x86/yuv2yuvX.o \ + +ifdef ARCH_X86_64 +X86ASM-OBJS += x86/ops_int.o\ + x86/ops_float.o \ + x86/ops.o +endif diff --git a/libswscale/x86/ops.c b/libswscale/x86/ops.c new file mode 100644 index 00..f427fb1d28 --- /dev/null +++ b/libswscale/x86/ops.c @@ -0,0 +1,723 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include + +#include "../ops_chain.h" + +#define DECL_ENTRY(TYPE, NAME, ...) \ +static const SwsOpEntry op_##NAME = { \ +.type = SWS_PIXEL_##TYPE, \ +__VA_ARGS__ \ +} + +#define DECL_ASM(TYPE, NAME, ...) \ +void ff_##NAME(void); \ +DECL_ENTRY(TYPE, NAME, \ +.func = ff_##NAME, \ +__VA_ARGS__) + +#define DECL_PATTERN(TYPE, NAME, X, Y, Z, W, ...) \ +DECL_ASM(TYPE, p##X##Y##Z##W##_##NAME, \ +.unused = { !X, !Y, !Z, !W }, \ +__VA_ARGS__ \ +) + +#define REF_PATTERN(NAME, X, Y, Z, W) \ +&op_p##X##Y##Z##W##_##NAME + +#define DECL_COMMON_PATTERNS(TYPE, NAME, ...) \ +DECL_PATTERN(TYPE, NAME, 1, 0, 0, 0, __VA_ARGS__); \ +DECL_PATTERN(TYPE, NAME, 1, 0, 0, 1, __VA_ARGS__); \ +DECL_PATTERN(TYPE, NAME, 1, 1, 1, 0, __VA_ARGS__); \ +DECL_PATTERN(TYPE, NAME, 1, 1, 1, 1, __VA_ARGS__) \ + +#define REF_COMMON_PATTERNS(NAME) \ +REF_PATTERN(NAME, 1, 0, 0, 0), \ +REF_PATTERN(NAME, 1, 0, 0, 1), \ +REF_PATTERN(NAME, 1, 1, 1, 0), \ +REF_PATTERN(NAME, 1, 1, 1, 1) + +#define D
[FFmpeg-devel] [PATCH v5 17/19] tests/checkasm: add checkasm tests for swscale ops
From: Niklas Haas Because of the lack of an external ABI on low-level kernels, we cannot directly test internal functions. Instead, we construct a minimal op chain consisting of a read, the op to be tested, and a write. The bigger complication arises from the fact that the backend may generate arbitrary internal state that needs to be passed back to the implementation, which means we cannot directly call `func_ref` on the generated chain. To get around this, always compile the op chain twice - once using the backend to be tested, and once using the reference C backend. The actual entry point may also just be a shared wrapper, so we need to be very careful to run checkasm_check_func() on a pseudo-pointer that will actually be unique for each combination of backend and active CPU flags. --- tests/checkasm/Makefile | 8 +- tests/checkasm/checkasm.c | 1 + tests/checkasm/checkasm.h | 1 + tests/checkasm/sw_ops.c | 776 ++ tests/fate/checkasm.mak | 1 + 5 files changed, 786 insertions(+), 1 deletion(-) create mode 100644 tests/checkasm/sw_ops.c diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile index fabbf595b4..d38ec371df 100644 --- a/tests/checkasm/Makefile +++ b/tests/checkasm/Makefile @@ -66,7 +66,13 @@ AVFILTEROBJS-$(CONFIG_SOBEL_FILTER) += vf_convolution.o CHECKASMOBJS-$(CONFIG_AVFILTER) += $(AVFILTEROBJS-yes) # swscale tests -SWSCALEOBJS += sw_gbrp.o sw_range_convert.o sw_rgb.o sw_scale.o sw_yuv2rgb.o sw_yuv2yuv.o +SWSCALEOBJS += sw_gbrp.o\ + sw_ops.o \ + sw_range_convert.o \ + sw_rgb.o \ + sw_scale.o \ + sw_yuv2rgb.o \ + sw_yuv2yuv.o CHECKASMOBJS-$(CONFIG_SWSCALE) += $(SWSCALEOBJS) diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index f393a0cb96..11bd5668cf 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -298,6 +298,7 @@ static const struct { { "sw_scale", checkasm_check_sw_scale }, { "sw_yuv2rgb", checkasm_check_sw_yuv2rgb }, { "sw_yuv2yuv", checkasm_check_sw_yuv2yuv }, +{ "sw_ops", checkasm_check_sw_ops }, #endif #if CONFIG_AVUTIL { "aes", checkasm_check_aes }, diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h index 9be9b47d58..678d6cc1d9 100644 --- a/tests/checkasm/checkasm.h +++ b/tests/checkasm/checkasm.h @@ -132,6 +132,7 @@ void checkasm_check_sw_rgb(void); void checkasm_check_sw_scale(void); void checkasm_check_sw_yuv2rgb(void); void checkasm_check_sw_yuv2yuv(void); +void checkasm_check_sw_ops(void); void checkasm_check_takdsp(void); void checkasm_check_utvideodsp(void); void checkasm_check_v210dec(void); diff --git a/tests/checkasm/sw_ops.c b/tests/checkasm/sw_ops.c new file mode 100644 index 00..c8cba96879 --- /dev/null +++ b/tests/checkasm/sw_ops.c @@ -0,0 +1,776 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/mem_internal.h" +#include "libavutil/refstruct.h" + +#include "libswscale/ops.h" +#include "libswscale/ops_internal.h" + +#include "checkasm.h" + +enum { +LINES = 2, +PLANES = 4, +PIXELS = 64, +}; + +enum { +U8 = SWS_PIXEL_U8, +U16 = SWS_PIXEL_U16, +U32 = SWS_PIXEL_U32, +F32 = SWS_PIXEL_F32, +}; + +#define FMT(fmt, ...) tprintf((char[256]) {0}, 256, fmt, __VA_ARGS__) +static const char *tprintf(char buf[], size_t size, const char *fmt, ...) +{ +va_list ap; +va_start(ap, fmt); +vsnprintf(buf, size, fmt, ap); +va_end(ap); +return buf; +} + +static int rw_pixel_bits(const SwsOp *op) +{ +const int elems = op->rw.packed ? op->rw.elems : 1; +const int size = ff_sws_pixel_type_size(op->type); +const int bits = 8 >> op->rw.frac; +av_assert1(bits >= 1); +return elems * size * bits; +} + +static float rndf(void) +{ +union { uint32_t u; float f; } x; +do { +
[FFmpeg-devel] [PATCH v5 18/19] swscale/format: add new format decode/encode logic
From: Niklas Haas This patch adds format handling code for the new operations. This entails fully decoding a format to standardized RGB, and the inverse. Handling it this way means we can always guarantee that a conversion path exists from A to B without having to explicitly cover logic for each path; and choosing RGB instead of YUV as the intermediate (as was done in swscale v1) is more flexible with regards to enabling further operations such as primaries conversions, linear scaling, etc. In the case of YUV->YUV transform, the redundant matrix multiplication will be canceled out anyways. --- libswscale/format.c | 926 libswscale/format.h | 23 ++ 2 files changed, 949 insertions(+) diff --git a/libswscale/format.c b/libswscale/format.c index b77081dd7a..7cbc5b37db 100644 --- a/libswscale/format.c +++ b/libswscale/format.c @@ -21,8 +21,22 @@ #include "libavutil/avassert.h" #include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/mastering_display_metadata.h" +#include "libavutil/refstruct.h" #include "format.h" +#include "csputils.h" +#include "ops_internal.h" + +#define Q(N) ((AVRational) { N, 1 }) +#define Q0 Q(0) +#define Q1 Q(1) + +#define RET(x) \ +do { \ +int __ret = (x); \ +if (__ret < 0) \ +return __ret; \ +} while (0) typedef struct LegacyFormatEntry { uint8_t is_supported_in :1; @@ -582,3 +596,915 @@ int sws_is_noop(const AVFrame *dst, const AVFrame *src) return 1; } + +/* Returns the type suitable for a pixel after fully decoding/unpacking it */ +static SwsPixelType fmt_pixel_type(enum AVPixelFormat fmt) +{ +const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); +const int bits = FFALIGN(desc->comp[0].depth, 8); +if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { +switch (bits) { +case 32: return SWS_PIXEL_F32; +} +} else { +switch (bits) { +case 8: return SWS_PIXEL_U8; +case 16: return SWS_PIXEL_U16; +case 32: return SWS_PIXEL_U32; +} +} + +return SWS_PIXEL_NONE; +} + +static SwsSwizzleOp fmt_swizzle(enum AVPixelFormat fmt) +{ +switch (fmt) { +case AV_PIX_FMT_ARGB: +case AV_PIX_FMT_0RGB: +case AV_PIX_FMT_AYUV64LE: +case AV_PIX_FMT_AYUV64BE: +case AV_PIX_FMT_AYUV: +case AV_PIX_FMT_X2RGB10LE: +case AV_PIX_FMT_X2RGB10BE: +return (SwsSwizzleOp) {{ .x = 3, 0, 1, 2 }}; +case AV_PIX_FMT_BGR24: +case AV_PIX_FMT_BGR8: +case AV_PIX_FMT_BGR4: +case AV_PIX_FMT_BGR4_BYTE: +case AV_PIX_FMT_BGRA: +case AV_PIX_FMT_BGR565BE: +case AV_PIX_FMT_BGR565LE: +case AV_PIX_FMT_BGR555BE: +case AV_PIX_FMT_BGR555LE: +case AV_PIX_FMT_BGR444BE: +case AV_PIX_FMT_BGR444LE: +case AV_PIX_FMT_BGR48BE: +case AV_PIX_FMT_BGR48LE: +case AV_PIX_FMT_BGRA64BE: +case AV_PIX_FMT_BGRA64LE: +case AV_PIX_FMT_BGR0: +case AV_PIX_FMT_VUYA: +case AV_PIX_FMT_VUYX: +return (SwsSwizzleOp) {{ .x = 2, 1, 0, 3 }}; +case AV_PIX_FMT_ABGR: +case AV_PIX_FMT_0BGR: +case AV_PIX_FMT_X2BGR10LE: +case AV_PIX_FMT_X2BGR10BE: +return (SwsSwizzleOp) {{ .x = 3, 2, 1, 0 }}; +case AV_PIX_FMT_YA8: +case AV_PIX_FMT_YA16BE: +case AV_PIX_FMT_YA16LE: +return (SwsSwizzleOp) {{ .x = 0, 3, 1, 2 }}; +case AV_PIX_FMT_XV30BE: +case AV_PIX_FMT_XV30LE: +return (SwsSwizzleOp) {{ .x = 3, 2, 0, 1 }}; +case AV_PIX_FMT_VYU444: +case AV_PIX_FMT_V30XBE: +case AV_PIX_FMT_V30XLE: +return (SwsSwizzleOp) {{ .x = 2, 0, 1, 3 }}; +case AV_PIX_FMT_XV36BE: +case AV_PIX_FMT_XV36LE: +case AV_PIX_FMT_XV48BE: +case AV_PIX_FMT_XV48LE: +case AV_PIX_FMT_UYVA: +return (SwsSwizzleOp) {{ .x = 1, 0, 2, 3 }}; +case AV_PIX_FMT_GBRP: +case AV_PIX_FMT_GBRP9BE: +case AV_PIX_FMT_GBRP9LE: +case AV_PIX_FMT_GBRP10BE: +case AV_PIX_FMT_GBRP10LE: +case AV_PIX_FMT_GBRP12BE: +case AV_PIX_FMT_GBRP12LE: +case AV_PIX_FMT_GBRP14BE: +case AV_PIX_FMT_GBRP14LE: +case AV_PIX_FMT_GBRP16BE: +case AV_PIX_FMT_GBRP16LE: +case AV_PIX_FMT_GBRPF16BE: +case AV_PIX_FMT_GBRPF16LE: +case AV_PIX_FMT_GBRAP: +case AV_PIX_FMT_GBRAP10LE: +case AV_PIX_FMT_GBRAP10BE: +case AV_PIX_FMT_GBRAP12LE: +case AV_PIX_FMT_GBRAP12BE: +case AV_PIX_FMT_GBRAP14LE: +case AV_PIX_FMT_GBRAP14BE: +case AV_PIX_FMT_GBRAP16LE: +case AV_PIX_FMT_GBRAP16BE: +case AV_PIX_FMT_GBRPF32BE: +case AV_PIX_FMT_GBRPF32LE: +case AV_PIX_FMT_GBRAPF16BE: +case AV_PIX_FMT_GBRAPF16LE: +case AV_PIX_FMT_GBRAPF32BE: +case AV_PIX_FMT_GBRAPF32LE: +
Re: [FFmpeg-devel] [PATCH v5 06/19] avutil/mem: add av_dynarray2_dup
On Tue, 10 Jun 2025 15:55:35 +0200 Andreas Rheinhardt wrote: > Niklas Haas: > > On Tue, 10 Jun 2025 15:04:57 +0200 Niklas Haas wrote: > >> From: Niklas Haas > >> > >> Like av_memdup() but correctly rounds up to the nearest power of two so > >> that > >> av_dynarray2_add() will continue to work on the duplicated list. > > > > Just realized this is public, will add a Changelog entry and bump the API > > version before merging. > Is this version supposed to be merged? > Anyway, this function seems way too specialised to me. What would you prefer? Simply having this logic inside swscale? I'm not very happy making cross-library assumptions about the exact resizing schedule. Alternatively, we could ditch the use of av_dynarray2 entirely. > > - Andreas > > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] avformat/demux: Fix segfault due to avcodec_open2 failure (v2)
On Tue, Jun 10, 2025, 07:39 Michael Niedermayer wrote: > On Mon, Jun 09, 2025 at 09:45:28PM -0600, Pavel Koshevoy wrote: > > Fixes 'ffprobe 1_poc.mp4' segfault introduced with > > commit 0021484d05f9b0f032fa319399de6e24eea0c04f > > > > codec_close should not assume that the codec_id did not change. > > --- > > libavformat/demux.c | 8 +++- > > 1 file changed, 7 insertions(+), 1 deletion(-) > > > > diff --git a/libavformat/demux.c b/libavformat/demux.c > > index ecd4f40da9..3749ab67a3 100644 > > --- a/libavformat/demux.c > > +++ b/libavformat/demux.c > > @@ -1292,9 +1292,15 @@ static int codec_close(FFStream *sti) > > { > > AVCodecContext *avctx_new = NULL; > > AVCodecParameters *par_tmp = NULL; > > +const AVCodec *new_codec = NULL; > > int ret; > > > > -avctx_new = avcodec_alloc_context3(sti->avctx->codec); > > +new_codec = > > + (sti->avctx->codec_id != sti->pub.codecpar->codec_id) ? > > + avcodec_find_decoder(sti->pub.codecpar->codec_id) : > > + sti->avctx->codec; > > + > > +avctx_new = avcodec_alloc_context3(new_codec); > > if (!avctx_new) { > > ret = AVERROR(ENOMEM); > > goto fail; > > This is not about request_probe > but about the mpegts demuxer randomly changeing codec id midstream > I have several real (not crafted like 1_poc.mp4 is) .ts files where codec changes from mpeg2video to hevc, from mpeg2audio to eac3 -- while remaining on the same PIDs. I also have .ts files where codec switches between mpeg2video and h264. VLC was able to play such files, but my ffmpeg based player (apprenticevideo) could not even see that the codecs changed prior to 0021484d05f9b0f032fa319399de6e24eea0c04f. Reverting isn't really an option for me, not unless there is a better solution presented. As I am primarily a public ffmpeg API user -- I am well out of my depth when it comes to making non-trivial changes to ffmpegs internals. > I belive the patch should be reverted that causes this. I dont think > applications expect such mid stream changes either > I have 2 applications that expect such behavior. > I hope andreas can take a look and correct me if iam missing something > but it looks a bit sketchy to me > > If a codec changes mid stream i belive a new AVStream > should be created. It could be a audio stream switches to video > or data or subtitle. > In my player I support video/audio track selection. MPEG-TS tracks are associated with a PID. If the PID did not change but the codec changed -- it's still the same track, and I axpect my player to play it out -- I don't expect the user to go search for some new track because the codec changed. > If any stream as detected initially can become any other type later > this complicates user applications and filter graphs > I think this is mostly a issue with the crafted 1_poc.mp4 file. Also the management of AVPackets is probably rather non trivial > if the stream_index is not enough to identify which decoder it belongs to > In my player I monitor AVCodecParameters for changes, and I attach a shared_ptr to AVCodecParameters to each packet, so when time comes to decode a packet I can check if its codecpar matches the current decoder, and open a new decoder if the codec has changed. It's not trivial, but not complicated either. > thx > > [...] > -- > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB > > Old school: Use the lowest level language in which you can solve the > problem > conveniently. > New school: Use the highest level language in which the latest > supercomputer > can solve the problem without the user falling asleep waiting. > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] avformat/whip: mark as experimental
--- Begin Message --- This muxer has been marked AVFMT_EXPERIMENTAL. Add a note in muxers.texi that WHIP is an experimental feature This patch doesn't effect WHIP usage command, as WHIP always needs to be explicitly specified The details as follows: https://ffmpeg.org/pipermail/ffmpeg-devel/2025-June/344705.html Signed-off-by: Jack Lau --- doc/muxers.texi| 2 ++ libavformat/whip.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index 30c95c3d34..d2ee90bf33 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -3885,6 +3885,8 @@ ffmpeg -f webm_dash_manifest -i video1.webm \ WebRTC (Real-Time Communication) muxer that supports sub-second latency streaming according to the WHIP (WebRTC-HTTP ingestion protocol) specification. +This is an experimental feature. + It uses HTTP as a signaling protocol to exchange SDP capabilities and ICE lite candidates. Then, it uses STUN binding requests and responses to establish a session over UDP. Subsequently, it initiates a DTLS handshake to exchange the SRTP encryption keys. Lastly, it splits video and diff --git a/libavformat/whip.c b/libavformat/whip.c index 710f24fc5a..bb7b8657dc 100644 --- a/libavformat/whip.c +++ b/libavformat/whip.c @@ -1907,7 +1907,7 @@ const FFOutputFormat ff_whip_muxer = { .p.long_name= NULL_IF_CONFIG_SMALL("WHIP(WebRTC-HTTP ingestion protocol) muxer"), .p.audio_codec = AV_CODEC_ID_OPUS, .p.video_codec = AV_CODEC_ID_H264, -.p.flags= AVFMT_GLOBALHEADER | AVFMT_NOFILE, +.p.flags= AVFMT_GLOBALHEADER | AVFMT_NOFILE | AVFMT_EXPERIMENTAL, .p.priv_class = &whip_muxer_class, .priv_data_size = sizeof(WHIPContext), .init = whip_init, -- 2.49.0 --- End Message --- ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".