From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> To: ffmpeg-devel@ffmpeg.org Subject: Re: [FFmpeg-devel] [PATCH WIP 01/10] ffbuild/bin2c: Use zlib directly instead of gzip Date: Tue, 3 Jun 2025 16:33:52 +0200 Message-ID: <GV1P250MB073793B6D428D364887AC5DD8F6DA@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM> (raw) In-Reply-To: <BN0P223MB0358CD236DC575DF1DFCA599BA62A@BN0P223MB0358.NAMP223.PROD.OUTLOOK.COM> [-- Attachment #1: Type: text/plain, Size: 1934 bytes --] softworkz .: > > >> -----Original Message----- >> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of Andreas >> Rheinhardt >> Sent: Montag, 2. Juni 2025 04:39 >> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> >> Subject: [FFmpeg-devel] [PATCH WIP 01/10] ffbuild/bin2c: Use zlib directly >> instead of gzip >> >> This is a WIP patchset to further improve the resource manager. The >> configure bits are the one that need more work: How do we detect zlib >> (and the required library to link to) on the host system? >> > > Hi, > > I ran CI builds for the whole Patchset > https://github.com/ffstaging/FFmpeg/pull/91 > > > Mac build fails (all others are fine) > https://dev.azure.com/githubsync/ffmpeg/_build/results?buildId=91751&view=logs > > > > Undefined symbols for architecture x86_64: > Undefined symbols for architecture x86_64: > "_ff_vf_yadif_videotoolbox_metallib_len", referenced from: > _do_init in libavfilter.a[397](vf_yadif_videotoolbox.o) > ld: symbol(s) not found for architecture x86_64 > clang: error: linker command failed with exit code 1 (use -v to see invocation) > make: *** [ffprobe_g] Error 1 > "_ff_vf_yadif_videotoolbox_metallib_len", referenced from: > _do_init in libavfilter.a[397](vf_yadif_videotoolbox.o) > ld: symbol(s) not found for architecture x86_64 > clang: error: linker command failed with exit code 1 (use -v to see invocation) > make: *** [ffplay_g] Error 1 > Thanks for the test. I overlooked that this was also used by metal. Updated version attached and also available at https://github.com/mkver/FFmpeg/tree/bin2c. Btw: The non-bin2c patches are actually logically independent from the bin2c patches and don't need to wait for them (there will be rebase conflicts when changing the order, but fixing them would be on me). The metal bits are untested, but should work. I have not worked on the configure bits. - Andreas [-- Attachment #2: v2-0001-ffbuild-bin2c-Use-zlib-directly-instead-of-gzip.patch --] [-- Type: text/x-patch, Size: 12817 bytes --] From b8cfe2dbece9c94b277dd30c212ef6d67599c1fa Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Sun, 1 Jun 2025 22:38:28 +0200 Subject: [PATCH WIP v2 01/10] ffbuild/bin2c: Use zlib directly instead of gzip Perform zlib compression directly in bin2c.c instead of using gzip for compression, followed by bin2c to put the file in the binary. This has the advantage of avoiding intermediate files and also saves a few bytes (the gzip header is longer than the zlib header). It also avoids the hypothetical problem of the build system supporting gzip with the zlib version used at runtime not supporting gzip. But the real advantages will become apparent in future commits. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- .gitignore | 1 - ffbuild/bin2c.c | 154 ++++++++++++++++++++++++++++++--- ffbuild/common.mak | 44 ++-------- fftools/resources/.gitignore | 3 - fftools/resources/Makefile | 2 +- fftools/resources/resman.c | 6 +- libavfilter/cuda/load_helper.c | 2 +- 7 files changed, 151 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index 59c89da5e0..901b47e76b 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,6 @@ *.metallib.c *.ptx *.ptx.c -*.ptx.gz *_g \#* .\#* diff --git a/ffbuild/bin2c.c b/ffbuild/bin2c.c index 91f2d81e5b..21bd5ecb75 100644 --- a/ffbuild/bin2c.c +++ b/ffbuild/bin2c.c @@ -20,48 +20,174 @@ * DEALINGS IN THE SOFTWARE. */ +#include "config.h" + +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> #include <string.h> #include <stdio.h> +#include "libavutil/attributes.h" +#include "libavutil/macros.h" + +#if CONFIG_PTX_COMPRESSION || CONFIG_RESOURCE_COMPRESSION +#include <zlib.h> + +#define MAX_BUF_SIZE UINT32_MAX + +static int read_file_and_compress(unsigned char **compressed_datap, uint32_t *compressed_sizep, + FILE *input) +{ + z_stream zstream = { 0 }; + int ret, zret = deflateInit(&zstream, 9); + + if (zret != Z_OK) + return -1; + + uint32_t buffer_size = 0, compressed_size = 0; + unsigned char *compressed_data = NULL; + int flush = Z_NO_FLUSH; + + do { + unsigned char tmp[4096]; + size_t read = fread(tmp, 1, sizeof(tmp), input); + if (read < sizeof(tmp)) + flush = Z_FINISH; + + zstream.next_in = tmp; + zstream.avail_in = read; + + do { + if (compressed_size >= buffer_size) { + if (buffer_size == MAX_BUF_SIZE) { + ret = -1; + goto fail; + } + + buffer_size = buffer_size ? FFMIN(compressed_size * 2ll, MAX_BUF_SIZE) : 4096; + void *tmp_ptr = realloc(compressed_data, buffer_size); + if (!tmp_ptr) { + ret = -1; + goto fail; + } + compressed_data = tmp_ptr; + } + + zstream.next_out = compressed_data + compressed_size; + zstream.avail_out = buffer_size - compressed_size; + + zret = deflate(&zstream, flush); + compressed_size = buffer_size - zstream.avail_out; + if (zret == Z_STREAM_END) + break; + if (zret != Z_OK) { + ret = -1; + goto fail; + } + } while (zstream.avail_in > 0 || zstream.avail_out == 0); + } while (flush != Z_FINISH); + + deflateEnd(&zstream); + *compressed_datap = compressed_data; + *compressed_sizep = compressed_size; + + return 0; +fail: + free(compressed_data); + deflateEnd(&zstream); + + return ret; +} + +static int handle_compressed_file(FILE *input, FILE *output, unsigned *compressed_sizep) +{ + unsigned char *compressed_data; + uint32_t compressed_size; + + int err = read_file_and_compress(&compressed_data, &compressed_size, input); + if (err) + return err; + + *compressed_sizep = compressed_size; + + for (unsigned i = 0; i < compressed_size; ++i) + fprintf(output, "0x%02x, ", compressed_data[i]); + + free(compressed_data); + + return 0; +} +#endif + int main(int argc, char **argv) { const char *name; FILE *input, *output; unsigned int length = 0; unsigned char data; + av_unused int compression = 0; + int arg_idx = 1; - if (argc < 3 || argc > 4) + if (argc < 3) return 1; - input = fopen(argv[1], "rb"); + if (!strcmp(argv[arg_idx], "--compress")) { +#if !CONFIG_PTX_COMPRESSION && !CONFIG_RESOURCE_COMPRESSION + fprintf(stderr, "Compression unsupported in this configuration. " + "This is a bug. Please report it.\n"); + return -1; +#endif + compression = 1; + ++arg_idx; + } + + if (argc - arg_idx < 2 || argc - arg_idx > 3) + return 1; + + char *input_name = argv[arg_idx++]; + input = fopen(input_name, "rb"); if (!input) return -1; - output = fopen(argv[2], "wb"); + output = fopen(argv[arg_idx++], "wb"); if (!output) { fclose(input); return -1; } - if (argc == 4) { - name = argv[3]; + if (arg_idx < argc) { + name = argv[arg_idx++]; } else { - size_t arglen = strlen(argv[1]); - name = argv[1]; + size_t arglen = strlen(input_name); + name = input_name; for (int i = 0; i < arglen; i++) { - if (argv[1][i] == '.') - argv[1][i] = '_'; - else if (argv[1][i] == '/') - name = &argv[1][i+1]; + if (input_name[i] == '.') + input_name[i] = '_'; + else if (input_name[i] == '/') + name = &input_name[i+1]; } } fprintf(output, "const unsigned char ff_%s_data[] = { ", name); - while (fread(&data, 1, 1, input) > 0) { - fprintf(output, "0x%02x, ", data); - length++; +#if CONFIG_PTX_COMPRESSION || CONFIG_RESOURCE_COMPRESSION + if (compression) { + int err = handle_compressed_file(input, output, &length); + if (err) { + fclose(input); + fclose(output); + return err; + } + } else +#endif + { + while (fread(&data, 1, 1, input) > 0) { + fprintf(output, "0x%02x, ", data); + length++; + } } fprintf(output, "0x00 };\n"); diff --git a/ffbuild/common.mak b/ffbuild/common.mak index ddf48923ea..b830f9862b 100644 --- a/ffbuild/common.mak +++ b/ffbuild/common.mak @@ -113,7 +113,7 @@ COMPILE_LASX = $(call COMPILE,CC,LASXFLAGS) $(Q)echo '#include "$*.h"' >$@ $(BIN2CEXE): ffbuild/bin2c_host.o - $(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTEXTRALIBS) + $(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTEXTRALIBS) $(if $(CONFIG_PTX_COMPRESSION)$(CONFIG_RESOURCE_COMPRESSION),-lz) %.metal.air: %.metal $(METALCC) $< -o $@ @@ -127,17 +127,8 @@ $(BIN2CEXE): ffbuild/bin2c_host.o %.ptx: %.cu $(SRC_PATH)/compat/cuda/cuda_runtime.h $(COMPILE_NVCC) -ifdef CONFIG_PTX_COMPRESSION -%.ptx.gz: TAG = GZIP -%.ptx.gz: %.ptx - $(M)gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@ - -%.ptx.c: %.ptx.gz $(BIN2CEXE) - $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@))) -else %.ptx.c: %.ptx $(BIN2CEXE) - $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@))) -endif + $(BIN2C) $(if $(CONFIG_PTX_COMPRESSION),--compress) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@))) # 1) Preprocess CSS to a minified version %.css.min: TAG = SED @@ -148,36 +139,13 @@ endif | sed 's/^ //; s/ $$//' \ > $@ -ifdef CONFIG_RESOURCE_COMPRESSION - -# 2) Gzip the minified CSS -%.css.min.gz: TAG = GZIP -%.css.min.gz: %.css.min - $(M)gzip -nc9 $< > $@ - -# 3) Convert the gzipped CSS to a .c array -%.css.c: %.css.min.gz $(BIN2CEXE) - $(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@))) - -# 4) Gzip the HTML file (no minification needed) -%.html.gz: TAG = GZIP -%.html.gz: %.html - $(M)gzip -nc9 $< > $@ - -# 5) Convert the gzipped HTML to a .c array -%.html.c: %.html.gz $(BIN2CEXE) - $(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@))) - -else # NO COMPRESSION - # 2) Convert the minified CSS to a .c array %.css.c: %.css.min $(BIN2CEXE) - $(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@))) + $(BIN2C) $(if $(CONFIG_RESOURCE_COMPRESSION),--compress) $< $@ $(subst .,_,$(basename $(notdir $@))) # 3) Convert the plain HTML to a .c array %.html.c: %.html $(BIN2CEXE) - $(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@))) -endif + $(BIN2C) $(if $(CONFIG_RESOURCE_COMPRESSION),--compress) $< $@ $(subst .,_,$(basename $(notdir $@))) clean:: $(RM) $(BIN2CEXE) $(CLEANSUFFIXES:%=ffbuild/%) @@ -232,7 +200,7 @@ PTXOBJS = $(filter %.ptx.o,$(OBJS)) RESOURCEOBJS = $(filter %.css.o %.html.o,$(OBJS)) $(HOBJS): CCFLAGS += $(CFLAGS_HEADERS) checkheaders: $(HOBJS) -.SECONDARY: $(HOBJS:.o=.c) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=.gz) $(PTXOBJS:.o=) $(RESOURCEOBJS:.o=.c) $(RESOURCEOBJS:%.css.o=%.css.min) $(RESOURCEOBJS:%.css.o=%.css.min.gz) $(RESOURCEOBJS:%.html.o=%.html.gz) $(RESOURCEOBJS:.o=) +.SECONDARY: $(HOBJS:.o=.c) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=) $(RESOURCEOBJS:.o=.c) $(RESOURCEOBJS:%.css.o=%.css.min) $(RESOURCEOBJS:.o=) alltools: $(TOOLS) @@ -252,7 +220,7 @@ $(TOOLOBJS): | tools OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SHLIBOBJS) $(STLIBOBJS) $(TESTOBJS)) -CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.ver *.version *.html.gz *.html.c *.css.gz *.css.c *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb +CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.c *.ver *.version *.html.c *.css.c *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a define RULES diff --git a/fftools/resources/.gitignore b/fftools/resources/.gitignore index bda2c59a1c..65febdf13b 100644 --- a/fftools/resources/.gitignore +++ b/fftools/resources/.gitignore @@ -1,6 +1,3 @@ *.html.c *.css.c -*.html.gz -*.css.gz *.min -*.min.gz diff --git a/fftools/resources/Makefile b/fftools/resources/Makefile index 8579a52678..aeb631f206 100644 --- a/fftools/resources/Makefile +++ b/fftools/resources/Makefile @@ -5,7 +5,7 @@ vpath %.html $(SRC_PATH) vpath %.css $(SRC_PATH) # Uncomment to prevent deletion during build -#.PRECIOUS: %.css.c %.css.min %.css.gz %.css.min.gz %.html.gz %.html.c +#.PRECIOUS: %.css.c %.css.min %.html.c OBJS-resman += \ fftools/resources/resman.o \ diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index aa53e96bf4..fdf73c36d5 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -65,7 +65,7 @@ static ResourceManagerContext resman_ctx = { .class = &resman_class }; #if CONFIG_RESOURCE_COMPRESSION -static int decompress_gzip(ResourceManagerContext *ctx, uint8_t *in, unsigned in_len, char **out, size_t *out_len) +static int decompress_zlib(ResourceManagerContext *ctx, uint8_t *in, unsigned in_len, char **out, size_t *out_len) { z_stream strm; unsigned chunk = 65534; @@ -83,7 +83,7 @@ static int decompress_gzip(ResourceManagerContext *ctx, uint8_t *in, unsigned in } // 15 + 16 tells zlib to detect GZIP or zlib automatically - ret = inflateInit2(&strm, 15 + 16); + ret = inflateInit(&strm); if (ret != Z_OK) { av_log(ctx, AV_LOG_ERROR, "Error during zlib initialization: %s\n", strm.msg); av_free(buf); @@ -156,7 +156,7 @@ char *ff_resman_get_string(FFResourceId resource_id) char *out = NULL; size_t out_len; - int ret = decompress_gzip(ctx, (uint8_t *)resource_definition.data, *resource_definition.data_len, &out, &out_len); + int ret = decompress_zlib(ctx, (uint8_t *)resource_definition.data, *resource_definition.data_len, &out, &out_len); if (ret) { av_log(ctx, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id); diff --git a/libavfilter/cuda/load_helper.c b/libavfilter/cuda/load_helper.c index b049ec7130..7c62793077 100644 --- a/libavfilter/cuda/load_helper.c +++ b/libavfilter/cuda/load_helper.c @@ -43,7 +43,7 @@ int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_mo uint64_t buf_size; int ret; - if (inflateInit2(&stream, 32 + 15) != Z_OK) { + if (inflateInit(&stream) != Z_OK) { av_log(avctx, AV_LOG_ERROR, "Error during zlib initialisation: %s\n", stream.msg); return AVERROR(ENOSYS); } -- 2.45.2 [-- Attachment #3: v2-0002-fftools-resources-resman-Don-t-mix-FFmpeg-and-zli.patch --] [-- Type: text/x-patch, Size: 1225 bytes --] From 2adb0b7eeaefd50a2f7a300b118f34bafe7bfa9f Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Mon, 2 Jun 2025 02:46:58 +0200 Subject: [PATCH WIP v2 02/10] fftools/resources/resman: Don't mix FFmpeg and zlib errors Also remove some always-false checks. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- fftools/resources/resman.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index fdf73c36d5..f910535750 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -100,7 +100,7 @@ static int decompress_zlib(ResourceManagerContext *ctx, uint8_t *in, unsigned in av_log(ctx, AV_LOG_ERROR, "Inflate failed: %d, %s\n", ret, strm.msg); inflateEnd(&strm); av_free(buf); - return (ret == Z_STREAM_END) ? Z_OK : ((ret == Z_OK) ? Z_BUF_ERROR : ret); + return AVERROR_EXTERNAL; } if (strm.avail_out == 0) { @@ -113,7 +113,7 @@ static int decompress_zlib(ResourceManagerContext *ctx, uint8_t *in, unsigned in inflateEnd(&strm); *out = (char *)buf; - return Z_OK; + return 0; } #endif -- 2.45.2 [-- Attachment #4: v2-0003-fftools-resources-resman-Remove-unused-function-p.patch --] [-- Type: text/x-patch, Size: 1934 bytes --] From 264ce990145b9bb7d2cf831ecf48807264dc6bc3 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Mon, 2 Jun 2025 02:53:24 +0200 Subject: [PATCH WIP v2 03/10] fftools/resources/resman: Remove unused function parameter Also constify in. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- fftools/resources/resman.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index f910535750..99d312bad8 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -65,7 +65,7 @@ static ResourceManagerContext resman_ctx = { .class = &resman_class }; #if CONFIG_RESOURCE_COMPRESSION -static int decompress_zlib(ResourceManagerContext *ctx, uint8_t *in, unsigned in_len, char **out, size_t *out_len) +static int decompress_zlib(ResourceManagerContext *ctx, const uint8_t *in, unsigned in_len, char **out) { z_stream strm; unsigned chunk = 65534; @@ -108,8 +108,7 @@ static int decompress_zlib(ResourceManagerContext *ctx, uint8_t *in, unsigned in av_log(ctx, AV_LOG_WARNING, "Decompression buffer may be too small\n"); } - *out_len = chunk - strm.avail_out; - buf[*out_len] = 0; // Ensure null termination + buf[chunk - strm.avail_out] = 0; // Ensure null termination inflateEnd(&strm); *out = (char *)buf; @@ -154,9 +153,8 @@ char *ff_resman_get_string(FFResourceId resource_id) #if CONFIG_RESOURCE_COMPRESSION char *out = NULL; - size_t out_len; - int ret = decompress_zlib(ctx, (uint8_t *)resource_definition.data, *resource_definition.data_len, &out, &out_len); + int ret = decompress_zlib(ctx, resource_definition.data, *resource_definition.data_len, &out); if (ret) { av_log(ctx, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id); -- 2.45.2 [-- Attachment #5: v2-0004-ffbuild-bin2c-Avoid-reallocations-when-uncompress.patch --] [-- Type: text/x-patch, Size: 8364 bytes --] From 1d49944d7e1d89d8e2d2f8472b08b69ffa2c1f26 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Sun, 1 Jun 2025 23:19:29 +0200 Subject: [PATCH WIP v2 04/10] ffbuild/bin2c: Avoid reallocations when uncompressing code,resources This can be easily achieved by storing the uncompressed size together with the actual zlib data. It also allows to use zlib's uncompress() utility function. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- ffbuild/bin2c.c | 26 ++++++++++++--- fftools/resources/resman.c | 44 +++++-------------------- libavfilter/cuda/load_helper.c | 60 ++++++++-------------------------- 3 files changed, 43 insertions(+), 87 deletions(-) diff --git a/ffbuild/bin2c.c b/ffbuild/bin2c.c index 21bd5ecb75..b4581f9872 100644 --- a/ffbuild/bin2c.c +++ b/ffbuild/bin2c.c @@ -38,7 +38,7 @@ #define MAX_BUF_SIZE UINT32_MAX static int read_file_and_compress(unsigned char **compressed_datap, uint32_t *compressed_sizep, - FILE *input) + uint32_t *uncompressed_sizep, FILE *input) { z_stream zstream = { 0 }; int ret, zret = deflateInit(&zstream, 9); @@ -46,7 +46,7 @@ static int read_file_and_compress(unsigned char **compressed_datap, uint32_t *co if (zret != Z_OK) return -1; - uint32_t buffer_size = 0, compressed_size = 0; + uint32_t buffer_size = 0, compressed_size = 0, uncompressed_size = 0; unsigned char *compressed_data = NULL; int flush = Z_NO_FLUSH; @@ -56,6 +56,12 @@ static int read_file_and_compress(unsigned char **compressed_datap, uint32_t *co if (read < sizeof(tmp)) flush = Z_FINISH; + uncompressed_size += read; + if (uncompressed_size < read) { // overflow + ret = -1; + goto fail; + } + zstream.next_in = tmp; zstream.avail_in = read; @@ -92,6 +98,7 @@ static int read_file_and_compress(unsigned char **compressed_datap, uint32_t *co deflateEnd(&zstream); *compressed_datap = compressed_data; *compressed_sizep = compressed_size; + *uncompressed_sizep = uncompressed_size; return 0; fail: @@ -101,17 +108,28 @@ fail: return ret; } +/// Write a 32bit integer according to the target's endianness. +static void write_u32(FILE *output, uint32_t num) +{ + for (int i = 0; i < 4; ++i) + fprintf(output, "0x%02x, ", + (num >> (HAVE_BIGENDIAN ? (24 - 8 * i) : 8 * i)) & 0xff); +} + static int handle_compressed_file(FILE *input, FILE *output, unsigned *compressed_sizep) { unsigned char *compressed_data; - uint32_t compressed_size; + uint32_t compressed_size, uncompressed_size; - int err = read_file_and_compress(&compressed_data, &compressed_size, input); + int err = read_file_and_compress(&compressed_data, &compressed_size, + &uncompressed_size, input); if (err) return err; *compressed_sizep = compressed_size; + write_u32(output, uncompressed_size); + for (unsigned i = 0; i < compressed_size; ++i) fprintf(output, "0x%02x, ", compressed_data[i]); diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index 99d312bad8..698529aca1 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -33,9 +33,8 @@ #include "resman.h" #include "libavutil/avassert.h" -#include "libavutil/pixdesc.h" +#include "libavutil/intreadwrite.h" #include "libavutil/dict.h" -#include "libavutil/common.h" extern const unsigned char ff_graph_html_data[]; extern const unsigned int ff_graph_html_len; @@ -67,50 +66,23 @@ static ResourceManagerContext resman_ctx = { .class = &resman_class }; static int decompress_zlib(ResourceManagerContext *ctx, const uint8_t *in, unsigned in_len, char **out) { - z_stream strm; - unsigned chunk = 65534; - int ret; - uint8_t *buf; - - *out = NULL; - memset(&strm, 0, sizeof(strm)); - // Allocate output buffer with extra byte for null termination - buf = (uint8_t *)av_mallocz(chunk + 1); + uint32_t uncompressed_size = AV_RN32(in); + uint8_t *buf = av_malloc(uncompressed_size + 1); if (!buf) { av_log(ctx, AV_LOG_ERROR, "Failed to allocate decompression buffer\n"); return AVERROR(ENOMEM); } - - // 15 + 16 tells zlib to detect GZIP or zlib automatically - ret = inflateInit(&strm); - if (ret != Z_OK) { - av_log(ctx, AV_LOG_ERROR, "Error during zlib initialization: %s\n", strm.msg); - av_free(buf); - return AVERROR(ENOSYS); - } - - strm.avail_in = in_len; - strm.next_in = in; - strm.avail_out = chunk; - strm.next_out = buf; - - ret = inflate(&strm, Z_FINISH); - if (ret != Z_OK && ret != Z_STREAM_END) { - av_log(ctx, AV_LOG_ERROR, "Inflate failed: %d, %s\n", ret, strm.msg); - inflateEnd(&strm); + uLongf buf_size = uncompressed_size; + int ret = uncompress(buf, &buf_size, in + 4, in_len); + if (ret != Z_OK || uncompressed_size != buf_size) { + av_log(ctx, AV_LOG_ERROR, "Error uncompressing resource. zlib returned %d\n", ret); av_free(buf); return AVERROR_EXTERNAL; } - if (strm.avail_out == 0) { - // TODO: Error or loop decoding? - av_log(ctx, AV_LOG_WARNING, "Decompression buffer may be too small\n"); - } - - buf[chunk - strm.avail_out] = 0; // Ensure null termination + buf[uncompressed_size] = 0; // Ensure null termination - inflateEnd(&strm); *out = (char *)buf; return 0; } diff --git a/libavfilter/cuda/load_helper.c b/libavfilter/cuda/load_helper.c index 7c62793077..0288ea49bb 100644 --- a/libavfilter/cuda/load_helper.c +++ b/libavfilter/cuda/load_helper.c @@ -21,11 +21,11 @@ #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" #include "libavutil/cuda_check.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #if CONFIG_PTX_COMPRESSION #include <zlib.h> -#define CHUNK_SIZE 1024 * 64 #endif #include "load_helper.h" @@ -38,57 +38,23 @@ int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_mo CudaFunctions *cu = hwctx->internal->cuda_dl; #if CONFIG_PTX_COMPRESSION - z_stream stream = { 0 }; - uint8_t *buf, *tmp; - uint64_t buf_size; - int ret; - - if (inflateInit(&stream) != Z_OK) { - av_log(avctx, AV_LOG_ERROR, "Error during zlib initialisation: %s\n", stream.msg); - return AVERROR(ENOSYS); - } - - buf_size = CHUNK_SIZE * 4; - buf = av_realloc(NULL, buf_size); - if (!buf) { - inflateEnd(&stream); + uint32_t uncompressed_size = AV_RN32(data); + uint8_t *buf = av_realloc(NULL, uncompressed_size + 1); + if (!buf) return AVERROR(ENOMEM); - } - - stream.next_in = data; - stream.avail_in = length; - - do { - stream.avail_out = buf_size - stream.total_out; - stream.next_out = buf + stream.total_out; - - ret = inflate(&stream, Z_FINISH); - if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) { - av_log(avctx, AV_LOG_ERROR, "zlib inflate error(%d): %s\n", ret, stream.msg); - inflateEnd(&stream); - av_free(buf); - return AVERROR(EINVAL); - } - - if (stream.avail_out == 0) { - buf_size += CHUNK_SIZE; - tmp = av_realloc(buf, buf_size); - if (!tmp) { - inflateEnd(&stream); - av_free(buf); - return AVERROR(ENOMEM); - } - buf = tmp; - } - } while (ret != Z_STREAM_END); + uLongf buf_size = uncompressed_size; + int ret = uncompress(buf, &buf_size, data + 4, length); + if (ret != Z_OK || uncompressed_size != buf_size) { + av_log(avctx, AV_LOG_ERROR, "Error uncompressing cuda code. zlib returned %d\n", ret); + ret = AVERROR_EXTERNAL; + goto fail; + } // NULL-terminate string - // there is guaranteed to be space for this, due to condition in loop - buf[stream.total_out] = 0; - - inflateEnd(&stream); + buf[uncompressed_size] = 0; ret = CHECK_CU(cu->cuModuleLoadData(cu_module, buf)); +fail: av_free(buf); return ret; #else -- 2.45.2 [-- Attachment #6: v2-0005-ffbuild-bin2c-Store-compressed-size-in-band.patch --] [-- Type: text/x-patch, Size: 16058 bytes --] From a24b6e897fc5049e38ca4082033984869625965d Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Sun, 1 Jun 2025 23:37:54 +0200 Subject: [PATCH WIP v2 05/10] ffbuild/bin2c: Store compressed size in-band There are three types of users of bin2c: a) Users that want to embed a C-string. The resources for the fftools as well as cuda modules can be of this type (if compression is disabled). b) If compression is not disabled, the same users want to store compressed data. c) Users that just want to store arbitrary binary data. This is currently only the videotoolbox yadif filter for its metal shaders. Up until now, bin2c unconditionally created a length field for the data. Users of type a) didn't need it (and in fact actually didn't use it); for users of type b), putting the size of the compressed data in-band (i.e. before the actual compressed data) is simpler. Users of type c) could currently use either an in-band size field or an external size field. This commit changes the cases a) and b) to no longer output an external length field; in case b) the size is stored in-band instead (and the data is no longer zero-terminated). Nothing changes for c), as there is no real benefit in doing so and I wanted to retain the ability of using external sizes just in case. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- ffbuild/bin2c.c | 30 +++++++++++++++++++----------- ffbuild/common.mak | 2 +- fftools/resources/resman.c | 14 +++++--------- fftools/resources/resman.h | 2 -- libavfilter/cuda/load_helper.c | 4 ++-- libavfilter/cuda/load_helper.h | 2 +- libavfilter/vf_bilateral_cuda.c | 3 +-- libavfilter/vf_bwdif_cuda.c | 3 +-- libavfilter/vf_chromakey_cuda.c | 3 +-- libavfilter/vf_colorspace_cuda.c | 4 +--- libavfilter/vf_overlay_cuda.c | 3 +-- libavfilter/vf_scale_cuda.c | 3 +-- libavfilter/vf_thumbnail_cuda.c | 3 +-- libavfilter/vf_yadif_cuda.c | 3 +-- 14 files changed, 36 insertions(+), 43 deletions(-) diff --git a/ffbuild/bin2c.c b/ffbuild/bin2c.c index b4581f9872..e8643ca792 100644 --- a/ffbuild/bin2c.c +++ b/ffbuild/bin2c.c @@ -29,7 +29,6 @@ #include <string.h> #include <stdio.h> -#include "libavutil/attributes.h" #include "libavutil/macros.h" #if CONFIG_PTX_COMPRESSION || CONFIG_RESOURCE_COMPRESSION @@ -116,7 +115,7 @@ static void write_u32(FILE *output, uint32_t num) (num >> (HAVE_BIGENDIAN ? (24 - 8 * i) : 8 * i)) & 0xff); } -static int handle_compressed_file(FILE *input, FILE *output, unsigned *compressed_sizep) +static int handle_compressed_file(FILE *input, FILE *output) { unsigned char *compressed_data; uint32_t compressed_size, uncompressed_size; @@ -126,9 +125,8 @@ static int handle_compressed_file(FILE *input, FILE *output, unsigned *compresse if (err) return err; - *compressed_sizep = compressed_size; - write_u32(output, uncompressed_size); + write_u32(output, compressed_size); for (unsigned i = 0; i < compressed_size; ++i) fprintf(output, "0x%02x, ", compressed_data[i]); @@ -143,10 +141,9 @@ int main(int argc, char **argv) { const char *name; FILE *input, *output; - unsigned int length = 0; unsigned char data; - av_unused int compression = 0; - int arg_idx = 1; + int compression = 0; + int arg_idx = 1, external_size = 0; if (argc < 3) return 1; @@ -160,6 +157,14 @@ int main(int argc, char **argv) compression = 1; ++arg_idx; } + if (!strcmp(argv[arg_idx], "--external-size")) { + if (compression) { + fprintf(stderr, "Compression and external size make no sense.\n"); + return -1; + } + external_size = 1; + ++arg_idx; + } if (argc - arg_idx < 2 || argc - arg_idx > 3) return 1; @@ -193,24 +198,27 @@ int main(int argc, char **argv) #if CONFIG_PTX_COMPRESSION || CONFIG_RESOURCE_COMPRESSION if (compression) { - int err = handle_compressed_file(input, output, &length); + int err = handle_compressed_file(input, output); if (err) { fclose(input); fclose(output); return err; } + fprintf(output, "};\n"); } else #endif { + unsigned int length = 0; + while (fread(&data, 1, 1, input) > 0) { fprintf(output, "0x%02x, ", data); length++; } + fprintf(output, "0x00 };\n"); + if (external_size) + fprintf(output, "const unsigned int ff_%s_len = %u;\n", name, length); } - fprintf(output, "0x00 };\n"); - fprintf(output, "const unsigned int ff_%s_len = %u;\n", name, length); - fclose(output); if (ferror(input) || !feof(input)) { diff --git a/ffbuild/common.mak b/ffbuild/common.mak index b830f9862b..021bb521d8 100644 --- a/ffbuild/common.mak +++ b/ffbuild/common.mak @@ -122,7 +122,7 @@ $(BIN2CEXE): ffbuild/bin2c_host.o $(METALLIB) --split-module-without-linking $< -o $@ %.metallib.c: %.metallib $(BIN2CEXE) - $(BIN2C) $< $@ $(subst .,_,$(basename $(notdir $@))) + $(BIN2C) --external-size $< $@ $(subst .,_,$(basename $(notdir $@))) %.ptx: %.cu $(SRC_PATH)/compat/cuda/cuda_runtime.h $(COMPILE_NVCC) diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index 698529aca1..fc00465775 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -37,14 +37,11 @@ #include "libavutil/dict.h" extern const unsigned char ff_graph_html_data[]; -extern const unsigned int ff_graph_html_len; - extern const unsigned char ff_graph_css_data[]; -extern const unsigned ff_graph_css_len; static const FFResourceDefinition resource_definitions[] = { - [FF_RESOURCE_GRAPH_CSS] = { FF_RESOURCE_GRAPH_CSS, "graph.css", &ff_graph_css_data[0], &ff_graph_css_len }, - [FF_RESOURCE_GRAPH_HTML] = { FF_RESOURCE_GRAPH_HTML, "graph.html", &ff_graph_html_data[0], &ff_graph_html_len }, + [FF_RESOURCE_GRAPH_CSS] = { FF_RESOURCE_GRAPH_CSS, "graph.css", ff_graph_css_data }, + [FF_RESOURCE_GRAPH_HTML] = { FF_RESOURCE_GRAPH_HTML, "graph.html", ff_graph_html_data }, }; @@ -64,7 +61,7 @@ static ResourceManagerContext resman_ctx = { .class = &resman_class }; #if CONFIG_RESOURCE_COMPRESSION -static int decompress_zlib(ResourceManagerContext *ctx, const uint8_t *in, unsigned in_len, char **out) +static int decompress_zlib(ResourceManagerContext *ctx, const uint8_t *in, char **out) { // Allocate output buffer with extra byte for null termination uint32_t uncompressed_size = AV_RN32(in); @@ -74,7 +71,7 @@ static int decompress_zlib(ResourceManagerContext *ctx, const uint8_t *in, unsig return AVERROR(ENOMEM); } uLongf buf_size = uncompressed_size; - int ret = uncompress(buf, &buf_size, in + 4, in_len); + int ret = uncompress(buf, &buf_size, in + 8, AV_RN32(in + 4)); if (ret != Z_OK || uncompressed_size != buf_size) { av_log(ctx, AV_LOG_ERROR, "Error uncompressing resource. zlib returned %d\n", ret); av_free(buf); @@ -126,8 +123,7 @@ char *ff_resman_get_string(FFResourceId resource_id) char *out = NULL; - int ret = decompress_zlib(ctx, resource_definition.data, *resource_definition.data_len, &out); - + int ret = decompress_zlib(ctx, resource_definition.data, &out); if (ret) { av_log(ctx, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id); goto end; diff --git a/fftools/resources/resman.h b/fftools/resources/resman.h index 6485db5091..ad57a10204 100644 --- a/fftools/resources/resman.h +++ b/fftools/resources/resman.h @@ -39,8 +39,6 @@ typedef struct FFResourceDefinition { const char *name; const unsigned char *data; - const unsigned *data_len; - } FFResourceDefinition; void ff_resman_uninit(void); diff --git a/libavfilter/cuda/load_helper.c b/libavfilter/cuda/load_helper.c index 0288ea49bb..e47f0421ef 100644 --- a/libavfilter/cuda/load_helper.c +++ b/libavfilter/cuda/load_helper.c @@ -33,7 +33,7 @@ #define CHECK_CU(x) FF_CUDA_CHECK_DL(avctx, cu, x) int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_module, - const unsigned char *data, const unsigned int length) + const unsigned char *data) { CudaFunctions *cu = hwctx->internal->cuda_dl; @@ -44,7 +44,7 @@ int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_mo return AVERROR(ENOMEM); uLongf buf_size = uncompressed_size; - int ret = uncompress(buf, &buf_size, data + 4, length); + int ret = uncompress(buf, &buf_size, data + 8, AV_RN32(data + 4)); if (ret != Z_OK || uncompressed_size != buf_size) { av_log(avctx, AV_LOG_ERROR, "Error uncompressing cuda code. zlib returned %d\n", ret); ret = AVERROR_EXTERNAL; diff --git a/libavfilter/cuda/load_helper.h b/libavfilter/cuda/load_helper.h index 455bf36a23..d25aa0ae27 100644 --- a/libavfilter/cuda/load_helper.h +++ b/libavfilter/cuda/load_helper.h @@ -23,6 +23,6 @@ * Loads a CUDA module and applies any decompression, if necessary. */ int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_module, - const unsigned char *data, const unsigned int length); + const unsigned char *data); #endif /* AVFILTER_CUDA_LOAD_HELPER_H */ diff --git a/libavfilter/vf_bilateral_cuda.c b/libavfilter/vf_bilateral_cuda.c index 7115fa9e05..50ddaad213 100644 --- a/libavfilter/vf_bilateral_cuda.c +++ b/libavfilter/vf_bilateral_cuda.c @@ -217,14 +217,13 @@ static av_cold int cuda_bilateral_load_functions(AVFilterContext *ctx) int ret; extern const unsigned char ff_vf_bilateral_cuda_ptx_data[]; - extern const unsigned int ff_vf_bilateral_cuda_ptx_len; ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx)); if (ret < 0) return ret; ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module, - ff_vf_bilateral_cuda_ptx_data, ff_vf_bilateral_cuda_ptx_len); + ff_vf_bilateral_cuda_ptx_data); if (ret < 0) goto fail; diff --git a/libavfilter/vf_bwdif_cuda.c b/libavfilter/vf_bwdif_cuda.c index cc954ab1d3..82c46886f3 100644 --- a/libavfilter/vf_bwdif_cuda.c +++ b/libavfilter/vf_bwdif_cuda.c @@ -29,7 +29,6 @@ #include "cuda/load_helper.h" extern const unsigned char ff_vf_bwdif_cuda_ptx_data[]; -extern const unsigned int ff_vf_bwdif_cuda_ptx_len; typedef struct DeintCUDAContext { YADIFContext yadif; @@ -305,7 +304,7 @@ static int config_output(AVFilterLink *link) if (ret < 0) goto exit; - ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module, ff_vf_bwdif_cuda_ptx_data, ff_vf_bwdif_cuda_ptx_len); + ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module, ff_vf_bwdif_cuda_ptx_data); if (ret < 0) goto exit; diff --git a/libavfilter/vf_chromakey_cuda.c b/libavfilter/vf_chromakey_cuda.c index 43f50c5a9a..e606da01ac 100644 --- a/libavfilter/vf_chromakey_cuda.c +++ b/libavfilter/vf_chromakey_cuda.c @@ -220,14 +220,13 @@ static av_cold int cudachromakey_load_functions(AVFilterContext *ctx) int ret; extern const unsigned char ff_vf_chromakey_cuda_ptx_data[]; - extern const unsigned int ff_vf_chromakey_cuda_ptx_len; ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx)); if (ret < 0) return ret; ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module, - ff_vf_chromakey_cuda_ptx_data, ff_vf_chromakey_cuda_ptx_len); + ff_vf_chromakey_cuda_ptx_data); if (ret < 0) goto fail; diff --git a/libavfilter/vf_colorspace_cuda.c b/libavfilter/vf_colorspace_cuda.c index 54d6228cd1..2d922430e4 100644 --- a/libavfilter/vf_colorspace_cuda.c +++ b/libavfilter/vf_colorspace_cuda.c @@ -198,15 +198,13 @@ static av_cold int cudacolorspace_load_functions(AVFilterContext* ctx) int ret; extern const unsigned char ff_vf_colorspace_cuda_ptx_data[]; - extern const unsigned int ff_vf_colorspace_cuda_ptx_len; ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx)); if (ret < 0) return ret; ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module, - ff_vf_colorspace_cuda_ptx_data, - ff_vf_colorspace_cuda_ptx_len); + ff_vf_colorspace_cuda_ptx_data); if (ret < 0) goto fail; diff --git a/libavfilter/vf_overlay_cuda.c b/libavfilter/vf_overlay_cuda.c index 4708b34d30..77da5b5e01 100644 --- a/libavfilter/vf_overlay_cuda.c +++ b/libavfilter/vf_overlay_cuda.c @@ -415,7 +415,6 @@ static int overlay_cuda_activate(AVFilterContext *avctx) static int overlay_cuda_config_output(AVFilterLink *outlink) { extern const unsigned char ff_vf_overlay_cuda_ptx_data[]; - extern const unsigned int ff_vf_overlay_cuda_ptx_len; int err; FilterLink *outl = ff_filter_link(outlink); @@ -494,7 +493,7 @@ static int overlay_cuda_config_output(AVFilterLink *outlink) return err; } - err = ff_cuda_load_module(ctx, ctx->hwctx, &ctx->cu_module, ff_vf_overlay_cuda_ptx_data, ff_vf_overlay_cuda_ptx_len); + err = ff_cuda_load_module(ctx, ctx->hwctx, &ctx->cu_module, ff_vf_overlay_cuda_ptx_data); if (err < 0) { CHECK_CU(cu->cuCtxPopCurrent(&dummy)); return err; diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c index 44eef207ca..6e238c7c73 100644 --- a/libavfilter/vf_scale_cuda.c +++ b/libavfilter/vf_scale_cuda.c @@ -290,7 +290,6 @@ static av_cold int cudascale_load_functions(AVFilterContext *ctx) const char *function_infix = ""; extern const unsigned char ff_vf_scale_cuda_ptx_data[]; - extern const unsigned int ff_vf_scale_cuda_ptx_len; switch(s->interp_algo) { case INTERP_ALGO_NEAREST: @@ -324,7 +323,7 @@ static av_cold int cudascale_load_functions(AVFilterContext *ctx) return ret; ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module, - ff_vf_scale_cuda_ptx_data, ff_vf_scale_cuda_ptx_len); + ff_vf_scale_cuda_ptx_data); if (ret < 0) goto fail; diff --git a/libavfilter/vf_thumbnail_cuda.c b/libavfilter/vf_thumbnail_cuda.c index 121274de11..bea07f7041 100644 --- a/libavfilter/vf_thumbnail_cuda.c +++ b/libavfilter/vf_thumbnail_cuda.c @@ -368,7 +368,6 @@ static int config_props(AVFilterLink *inlink) int ret; extern const unsigned char ff_vf_thumbnail_cuda_ptx_data[]; - extern const unsigned int ff_vf_thumbnail_cuda_ptx_len; s->hwctx = device_hwctx; s->cu_stream = s->hwctx->stream; @@ -377,7 +376,7 @@ static int config_props(AVFilterLink *inlink) if (ret < 0) return ret; - ret = ff_cuda_load_module(ctx, device_hwctx, &s->cu_module, ff_vf_thumbnail_cuda_ptx_data, ff_vf_thumbnail_cuda_ptx_len); + ret = ff_cuda_load_module(ctx, device_hwctx, &s->cu_module, ff_vf_thumbnail_cuda_ptx_data); if (ret < 0) return ret; diff --git a/libavfilter/vf_yadif_cuda.c b/libavfilter/vf_yadif_cuda.c index 50ac61ad8a..cd9a5ba2e7 100644 --- a/libavfilter/vf_yadif_cuda.c +++ b/libavfilter/vf_yadif_cuda.c @@ -29,7 +29,6 @@ #include "cuda/load_helper.h" extern const unsigned char ff_vf_yadif_cuda_ptx_data[]; -extern const unsigned int ff_vf_yadif_cuda_ptx_len; typedef struct DeintCUDAContext { YADIFContext yadif; @@ -291,7 +290,7 @@ static int config_output(AVFilterLink *link) if (ret < 0) goto exit; - ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module, ff_vf_yadif_cuda_ptx_data, ff_vf_yadif_cuda_ptx_len); + ret = ff_cuda_load_module(ctx, s->hwctx, &s->cu_module, ff_vf_yadif_cuda_ptx_data); if (ret < 0) goto exit; -- 2.45.2 [-- Attachment #7: v2-0006-ffbuild-bin2c-Allow-to-use-aligned-reads.patch --] [-- Type: text/x-patch, Size: 4091 bytes --] From e3d2be1ec0a2b7bb4beebc4c2a3cbede4bbbf436 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Mon, 2 Jun 2025 00:08:31 +0200 Subject: [PATCH WIP v2 06/10] ffbuild/bin2c: Allow to use aligned reads Possible if one aligns the buffer. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- ffbuild/bin2c.c | 10 ++++++---- fftools/resources/resman.c | 4 ++-- libavfilter/cuda/load_helper.c | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ffbuild/bin2c.c b/ffbuild/bin2c.c index e8643ca792..c380a0ac43 100644 --- a/ffbuild/bin2c.c +++ b/ffbuild/bin2c.c @@ -115,11 +115,14 @@ static void write_u32(FILE *output, uint32_t num) (num >> (HAVE_BIGENDIAN ? (24 - 8 * i) : 8 * i)) & 0xff); } -static int handle_compressed_file(FILE *input, FILE *output) +static int handle_compressed_file(FILE *input, FILE *output, const char *name) { unsigned char *compressed_data; uint32_t compressed_size, uncompressed_size; + fprintf(output, "#include \"libavutil/mem_internal.h\"\n"); + fprintf(output, "DECLARE_ALIGNED_4(const unsigned char, ff_%s_data)[] = { ", name); + int err = read_file_and_compress(&compressed_data, &compressed_size, &uncompressed_size, input); if (err) @@ -194,11 +197,9 @@ int main(int argc, char **argv) } } - fprintf(output, "const unsigned char ff_%s_data[] = { ", name); - #if CONFIG_PTX_COMPRESSION || CONFIG_RESOURCE_COMPRESSION if (compression) { - int err = handle_compressed_file(input, output); + int err = handle_compressed_file(input, output, name); if (err) { fclose(input); fclose(output); @@ -210,6 +211,7 @@ int main(int argc, char **argv) { unsigned int length = 0; + fprintf(output, "const unsigned char ff_%s_data[] = { ", name); while (fread(&data, 1, 1, input) > 0) { fprintf(output, "0x%02x, ", data); length++; diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index fc00465775..0094ecd4c5 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -64,14 +64,14 @@ static ResourceManagerContext resman_ctx = { .class = &resman_class }; static int decompress_zlib(ResourceManagerContext *ctx, const uint8_t *in, char **out) { // Allocate output buffer with extra byte for null termination - uint32_t uncompressed_size = AV_RN32(in); + uint32_t uncompressed_size = AV_RN32A(in); uint8_t *buf = av_malloc(uncompressed_size + 1); if (!buf) { av_log(ctx, AV_LOG_ERROR, "Failed to allocate decompression buffer\n"); return AVERROR(ENOMEM); } uLongf buf_size = uncompressed_size; - int ret = uncompress(buf, &buf_size, in + 8, AV_RN32(in + 4)); + int ret = uncompress(buf, &buf_size, in + 8, AV_RN32A(in + 4)); if (ret != Z_OK || uncompressed_size != buf_size) { av_log(ctx, AV_LOG_ERROR, "Error uncompressing resource. zlib returned %d\n", ret); av_free(buf); diff --git a/libavfilter/cuda/load_helper.c b/libavfilter/cuda/load_helper.c index e47f0421ef..79ec37c7cd 100644 --- a/libavfilter/cuda/load_helper.c +++ b/libavfilter/cuda/load_helper.c @@ -38,13 +38,13 @@ int ff_cuda_load_module(void *avctx, AVCUDADeviceContext *hwctx, CUmodule *cu_mo CudaFunctions *cu = hwctx->internal->cuda_dl; #if CONFIG_PTX_COMPRESSION - uint32_t uncompressed_size = AV_RN32(data); + uint32_t uncompressed_size = AV_RN32A(data); uint8_t *buf = av_realloc(NULL, uncompressed_size + 1); if (!buf) return AVERROR(ENOMEM); uLongf buf_size = uncompressed_size; - int ret = uncompress(buf, &buf_size, data + 8, AV_RN32(data + 4)); + int ret = uncompress(buf, &buf_size, data + 8, AV_RN32A(data + 4)); if (ret != Z_OK || uncompressed_size != buf_size) { av_log(avctx, AV_LOG_ERROR, "Error uncompressing cuda code. zlib returned %d\n", ret); ret = AVERROR_EXTERNAL; -- 2.45.2 [-- Attachment #8: v2-0007-fftools-resources-resman-Use-pointer-to-resource-.patch --] [-- Type: text/x-patch, Size: 3380 bytes --] From 0708e8aa396166bb98b5754de4876f1b129b9e97 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Mon, 2 Jun 2025 03:09:45 +0200 Subject: [PATCH WIP v2 07/10] fftools/resources/resman: Use pointer to resource definition It does not really matter on its own given that FFResourceDefinition is so small; it is mostly in preparation for the next commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- fftools/resources/resman.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index 0094ecd4c5..1de98475c3 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -98,23 +98,23 @@ void ff_resman_uninit(void) char *ff_resman_get_string(FFResourceId resource_id) { ResourceManagerContext *ctx = &resman_ctx; - FFResourceDefinition resource_definition = { 0 }; + const FFResourceDefinition *resource_definition = NULL; AVDictionaryEntry *dic_entry; char *res = NULL; for (unsigned i = 0; i < FF_ARRAY_ELEMS(resource_definitions); ++i) { - FFResourceDefinition def = resource_definitions[i]; - if (def.resource_id == resource_id) { + const FFResourceDefinition *def = &resource_definitions[i]; + if (def->resource_id == resource_id) { resource_definition = def; break; } } - av_assert1(resource_definition.name); + av_assert1(resource_definition); ff_mutex_lock(&mutex); - dic_entry = av_dict_get(ctx->resource_dic, resource_definition.name, NULL, 0); + dic_entry = av_dict_get(ctx->resource_dic, resource_definition->name, NULL, 0); if (!dic_entry) { int dict_ret; @@ -123,13 +123,13 @@ char *ff_resman_get_string(FFResourceId resource_id) char *out = NULL; - int ret = decompress_zlib(ctx, resource_definition.data, &out); + int ret = decompress_zlib(ctx, resource_definition->data, &out); if (ret) { av_log(ctx, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id); goto end; } - dict_ret = av_dict_set(&ctx->resource_dic, resource_definition.name, out, 0); + dict_ret = av_dict_set(&ctx->resource_dic, resource_definition->name, out, 0); if (dict_ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failed to store decompressed resource in dictionary: %d\n", dict_ret); av_freep(&out); @@ -139,14 +139,14 @@ char *ff_resman_get_string(FFResourceId resource_id) av_freep(&out); #else - dict_ret = av_dict_set(&ctx->resource_dic, resource_definition.name, (const char *)resource_definition.data, 0); + dict_ret = av_dict_set(&ctx->resource_dic, resource_definition->name, (const char *)resource_definition->data, 0); if (dict_ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failed to store resource in dictionary: %d\n", dict_ret); goto end; } #endif - dic_entry = av_dict_get(ctx->resource_dic, resource_definition.name, NULL, 0); + dic_entry = av_dict_get(ctx->resource_dic, resource_definition->name, NULL, 0); if (!dic_entry) { av_log(ctx, AV_LOG_ERROR, "Failed to retrieve resource from dictionary after storing it\n"); -- 2.45.2 [-- Attachment #9: v2-0008-fftools-resources-resman-Constify-ret-of-ff_resma.patch --] [-- Type: text/x-patch, Size: 1574 bytes --] From 975a08f9b988cfc628d1941ae8fec5e6b46ba949 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Mon, 2 Jun 2025 03:14:36 +0200 Subject: [PATCH WIP v2 08/10] fftools/resources/resman: Constify ret of ff_resman_get_string() Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- fftools/resources/resman.c | 4 ++-- fftools/resources/resman.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index 1de98475c3..aa99e07f50 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -95,12 +95,12 @@ void ff_resman_uninit(void) } -char *ff_resman_get_string(FFResourceId resource_id) +const char *ff_resman_get_string(FFResourceId resource_id) { ResourceManagerContext *ctx = &resman_ctx; const FFResourceDefinition *resource_definition = NULL; AVDictionaryEntry *dic_entry; - char *res = NULL; + const char *res = NULL; for (unsigned i = 0; i < FF_ARRAY_ELEMS(resource_definitions); ++i) { const FFResourceDefinition *def = &resource_definitions[i]; diff --git a/fftools/resources/resman.h b/fftools/resources/resman.h index ad57a10204..d41c89ce37 100644 --- a/fftools/resources/resman.h +++ b/fftools/resources/resman.h @@ -43,6 +43,6 @@ typedef struct FFResourceDefinition { void ff_resman_uninit(void); -char *ff_resman_get_string(FFResourceId resource_id); +const char *ff_resman_get_string(FFResourceId resource_id); #endif /* FFTOOLS_RESOURCES_RESMAN_H */ -- 2.45.2 [-- Attachment #10: v2-0009-fftools-resources-resman-Avoid-AVDictionary.patch --] [-- Type: text/x-patch, Size: 5284 bytes --] From 46afbe31fd5156b6d84da607a6304dfa767147e9 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Mon, 2 Jun 2025 03:37:43 +0200 Subject: [PATCH WIP v2 09/10] fftools/resources/resman: Avoid AVDictionary Using it incurs an unnecessary duplication (temporary when compression is enabled). It furthermore incurs checks for av_dict_set()/av_dict_get(). Using an array of pointers is simpler. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- fftools/resources/resman.c | 64 +++++++++++--------------------------- fftools/resources/resman.h | 1 - 2 files changed, 18 insertions(+), 47 deletions(-) diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index aa99e07f50..4497d65f3d 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -34,24 +34,23 @@ #include "resman.h" #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" -#include "libavutil/dict.h" extern const unsigned char ff_graph_html_data[]; extern const unsigned char ff_graph_css_data[]; static const FFResourceDefinition resource_definitions[] = { - [FF_RESOURCE_GRAPH_CSS] = { FF_RESOURCE_GRAPH_CSS, "graph.css", ff_graph_css_data }, - [FF_RESOURCE_GRAPH_HTML] = { FF_RESOURCE_GRAPH_HTML, "graph.html", ff_graph_html_data }, + [FF_RESOURCE_GRAPH_CSS] = { FF_RESOURCE_GRAPH_CSS, ff_graph_css_data }, + [FF_RESOURCE_GRAPH_HTML] = { FF_RESOURCE_GRAPH_HTML, ff_graph_html_data }, }; - +#if CONFIG_RESOURCE_COMPRESSION static const AVClass resman_class = { .class_name = "ResourceManager", }; typedef struct ResourceManagerContext { const AVClass *class; - AVDictionary *resource_dic; + char *resources[FF_ARRAY_ELEMS(resource_definitions)]; } ResourceManagerContext; static AVMutex mutex = AV_MUTEX_INITIALIZER; @@ -59,8 +58,6 @@ static AVMutex mutex = AV_MUTEX_INITIALIZER; static ResourceManagerContext resman_ctx = { .class = &resman_class }; -#if CONFIG_RESOURCE_COMPRESSION - static int decompress_zlib(ResourceManagerContext *ctx, const uint8_t *in, char **out) { // Allocate output buffer with extra byte for null termination @@ -87,76 +84,51 @@ static int decompress_zlib(ResourceManagerContext *ctx, const uint8_t *in, char void ff_resman_uninit(void) { +#if CONFIG_RESOURCE_COMPRESSION ff_mutex_lock(&mutex); - av_dict_free(&resman_ctx.resource_dic); + for (size_t i = 0; i < FF_ARRAY_ELEMS(resman_ctx.resources); ++i) + av_freep(&resman_ctx.resources[i]); ff_mutex_unlock(&mutex); +#endif } const char *ff_resman_get_string(FFResourceId resource_id) { - ResourceManagerContext *ctx = &resman_ctx; const FFResourceDefinition *resource_definition = NULL; - AVDictionaryEntry *dic_entry; const char *res = NULL; + av_unused unsigned idx; for (unsigned i = 0; i < FF_ARRAY_ELEMS(resource_definitions); ++i) { const FFResourceDefinition *def = &resource_definitions[i]; if (def->resource_id == resource_id) { resource_definition = def; + idx = i; break; } } av_assert1(resource_definition); - ff_mutex_lock(&mutex); - - dic_entry = av_dict_get(ctx->resource_dic, resource_definition->name, NULL, 0); - - if (!dic_entry) { - int dict_ret; - #if CONFIG_RESOURCE_COMPRESSION + ff_mutex_lock(&mutex); - char *out = NULL; + ResourceManagerContext *ctx = &resman_ctx; - int ret = decompress_zlib(ctx, resource_definition->data, &out); + if (!ctx->resources[idx]) { + int ret = decompress_zlib(ctx, resource_definition->data, &ctx->resources[idx]); if (ret) { av_log(ctx, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id); goto end; } - - dict_ret = av_dict_set(&ctx->resource_dic, resource_definition->name, out, 0); - if (dict_ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Failed to store decompressed resource in dictionary: %d\n", dict_ret); - av_freep(&out); - goto end; - } - - av_freep(&out); -#else - - dict_ret = av_dict_set(&ctx->resource_dic, resource_definition->name, (const char *)resource_definition->data, 0); - if (dict_ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Failed to store resource in dictionary: %d\n", dict_ret); - goto end; - } - -#endif - dic_entry = av_dict_get(ctx->resource_dic, resource_definition->name, NULL, 0); - - if (!dic_entry) { - av_log(ctx, AV_LOG_ERROR, "Failed to retrieve resource from dictionary after storing it\n"); - goto end; - } } - - res = dic_entry->value; - + res = ctx->resources[idx]; end: ff_mutex_unlock(&mutex); +#else + res = resource_definition->data; +#endif return res; } diff --git a/fftools/resources/resman.h b/fftools/resources/resman.h index d41c89ce37..ee22e960d3 100644 --- a/fftools/resources/resman.h +++ b/fftools/resources/resman.h @@ -36,7 +36,6 @@ typedef enum { typedef struct FFResourceDefinition { FFResourceId resource_id; - const char *name; const unsigned char *data; } FFResourceDefinition; -- 2.45.2 [-- Attachment #11: v2-0010-fftools-resources-resman-Improve-headers.patch --] [-- Type: text/x-patch, Size: 1479 bytes --] From d9c700993c281d1037e0283d187920e6df0f9885 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Mon, 2 Jun 2025 03:48:50 +0200 Subject: [PATCH WIP v2 10/10] fftools/resources/resman: Improve headers Don't rely on implicit inclusions of lavu/thread.h and lavu/mem.h. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- fftools/resources/resman.c | 5 ++++- fftools/resources/resman.h | 8 -------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c index 4497d65f3d..9b8f6e406a 100644 --- a/fftools/resources/resman.c +++ b/fftools/resources/resman.c @@ -25,10 +25,13 @@ #include "config.h" -#include <string.h> +#include <stddef.h> #if CONFIG_RESOURCE_COMPRESSION #include <zlib.h> +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" +#include "libavutil/thread.h" #endif #include "resman.h" diff --git a/fftools/resources/resman.h b/fftools/resources/resman.h index ee22e960d3..20e6b1037c 100644 --- a/fftools/resources/resman.h +++ b/fftools/resources/resman.h @@ -21,14 +21,6 @@ #ifndef FFTOOLS_RESOURCES_RESMAN_H #define FFTOOLS_RESOURCES_RESMAN_H -#include <stdint.h> - -#include "config.h" -#include "fftools/ffmpeg.h" -#include "libavutil/avutil.h" -#include "libavutil/bprint.h" -#include "fftools/textformat/avtextformat.h" - typedef enum { FF_RESOURCE_GRAPH_CSS, FF_RESOURCE_GRAPH_HTML, -- 2.45.2 [-- Attachment #12: Type: text/plain, Size: 251 bytes --] _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2025-06-03 14:34 UTC|newest] Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top 2025-06-02 2:38 Andreas Rheinhardt 2025-06-02 3:22 ` softworkz . 2025-06-02 22:33 ` softworkz . 2025-06-03 14:33 ` Andreas Rheinhardt [this message] 2025-06-03 14:47 ` softworkz . 2025-06-11 3:05 ` softworkz . 2025-06-16 18:51 ` Andreas Rheinhardt 2025-06-16 19:15 ` softworkz . 2025-06-16 19:24 ` Andreas Rheinhardt 2025-06-16 20:18 ` softworkz . 2025-06-16 22:15 ` Andreas Rheinhardt 2025-06-17 9:29 ` Nicolas George 2025-06-17 13:23 ` softworkz . 2025-06-17 14:09 ` Nicolas George 2025-06-17 14:35 ` softworkz . 2025-06-17 14:40 ` Nicolas George 2025-06-17 14:41 ` James Almer 2025-06-17 14:51 ` softworkz . 2025-06-18 7:09 ` Nicolas George
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=GV1P250MB073793B6D428D364887AC5DD8F6DA@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM \ --to=andreas.rheinhardt@outlook.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git