On Thu, May 15, 2025 at 11:11 PM softworkz <g...@videolan.org> wrote: > > ffmpeg | branch: master | softworkz <softwo...@hotmail.com> | Thu May 15 > 23:07:54 2025 +0200| [517a8055655798970d94a4c5ea912511362520ea] | committer: > softworkz > > fftools/resources: Add resource manager files with build-time compression > > Compression requires zlib to be available, otherwise resources will > be included uncompressed - in either case via BIN2C. > > It can also be disabled via > > ./configure --disable-resource-compression > > Size figures: > > graph.css 7752 > graph.css.min 6655 (css is always minified) > graph.html 2153 > > No Compression > > graph.css.c 40026 > graph.css.o 9344 (6688) > graph.html.c 13016 > graph.html.o 4848 (2186) > > With Compression > > graph.css.c 10206 > graph.css.o 4368 (1718) > graph.html.c 5725 > graph.html.o 3632 (971) > > Numbers in brackets: .rodata size from 'size -Ax -d *.o' > > Signed-off-by: softworkz <softwo...@hotmail.com> > > > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=517a8055655798970d94a4c5ea912511362520ea > --- > > configure | 5 + > ffbuild/common.mak | 43 +++++- > fftools/Makefile | 3 +- > fftools/resources/.gitignore | 4 + > fftools/resources/Makefile | 13 ++ > fftools/resources/graph.css | 353 > +++++++++++++++++++++++++++++++++++++++++++ > fftools/resources/graph.html | 86 +++++++++++ > fftools/resources/resman.c | 231 ++++++++++++++++++++++++++++ > fftools/resources/resman.h | 50 ++++++ > 9 files changed, 785 insertions(+), 3 deletions(-)
[...] > diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c > new file mode 100644 > index 0000000000..a9e21626fa > --- /dev/null > +++ b/fftools/resources/resman.c > @@ -0,0 +1,231 @@ > +/* > + * Copyright (c) 2025 - softworkz > + * > + * 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 > + */ > + > +/** > + * @file > + * output writers for filtergraph details > + */ > + > +#include "config.h" > + > +#include <string.h> > + > +#if CONFIG_RESOURCE_COMPRESSION > +#include <zlib.h> > +#endif > + > +#include "resman.h" > +#include "fftools/ffmpeg_filter.h" > +#include "libavutil/avassert.h" > +#include "libavutil/pixdesc.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; > + > +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 }, > +}; > + > + > +static const AVClass resman_class = { > + .class_name = "ResourceManager", > +}; > + > +typedef struct ResourceManagerContext { > + const AVClass *class; > + AVDictionary *resource_dic; > +} ResourceManagerContext; > + > +static AVMutex mutex = AV_MUTEX_INITIALIZER; > + > +ResourceManagerContext *resman_ctx = NULL; static > +#if CONFIG_RESOURCE_COMPRESSION > + > +static int decompress_gzip(ResourceManagerContext *ctx, uint8_t *in, > unsigned in_len, char **out, size_t *out_len) > +{ > + 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); Unnecessary cast. > + 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 = inflateInit2(&strm, 15 + 16); > + 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); > + av_free(buf); > + return (ret == Z_STREAM_END) ? Z_OK : ((ret == Z_OK) ? Z_BUF_ERROR : > ret); > + } > + > + if (strm.avail_out == 0) { > + // TODO: Error or loop decoding? ^^ > + 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 > + > + inflateEnd(&strm); > + *out = (char *)buf; > + return Z_OK; > +} > +#endif > + > +static ResourceManagerContext *get_resman_context(void) > +{ > + ResourceManagerContext *res = resman_ctx; > + > + ff_mutex_lock(&mutex); > + > + if (res) > + goto end; > + > + res = av_mallocz(sizeof(ResourceManagerContext)); > + if (!res) { > + av_log(NULL, AV_LOG_ERROR, "Failed to allocate resource manager > context\n"); > + goto end; > + } > + > + res->class = &resman_class; > + resman_ctx = res; > + > +end: > + ff_mutex_unlock(&mutex); > + return res; > +} > + > + > +void ff_resman_uninit(void) > +{ > + ff_mutex_lock(&mutex); > + > + if (resman_ctx) { > + if (resman_ctx->resource_dic) > + av_dict_free(&resman_ctx->resource_dic); > + av_freep(&resman_ctx); > + } > + > + ff_mutex_unlock(&mutex); > +} > + > + > +char *ff_resman_get_string(FFResourceId resource_id) const char * > +{ > + ResourceManagerContext *ctx = get_resman_context(); > + FFResourceDefinition resource_definition = { 0 }; > + AVDictionaryEntry *dic_entry; > + char *res = NULL; > + > + if (!ctx) > + return NULL; > + > + for (unsigned i = 0; i < FF_ARRAY_ELEMS(resource_definitions); ++i) { > + FFResourceDefinition def = resource_definitions[i]; > + if (def.resource_id == resource_id) { > + resource_definition = def; > + break; > + } > + } > + > + if (!resource_definition.name) { > + av_log(ctx, AV_LOG_ERROR, "Unable to find resource with ID %d\n", > resource_id); > + return NULL; > + } > + > + 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 > + > + char *out = NULL; > + size_t out_len; > + > + int ret = decompress_gzip(ctx, (uint8_t *)resource_definition.data, > *resource_definition.data_len, &out, &out_len); > + > + if (ret) { > + av_log(NULL, 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(NULL, 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(NULL, 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(NULL, AV_LOG_ERROR, "Failed to retrieve resource from > dictionary after storing it\n"); > + goto end; > + } > + } > + > + res = dic_entry->value; > + > +end: > + ff_mutex_unlock(&mutex); > + return res; > +} > diff --git a/fftools/resources/resman.h b/fftools/resources/resman.h > new file mode 100644 > index 0000000000..6485db5091 > --- /dev/null > +++ b/fftools/resources/resman.h > @@ -0,0 +1,50 @@ > +/* > + * Copyright (c) 2025 - softworkz > + * > + * 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 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" All includes in this file are unnecessary. > + > +typedef enum { > + FF_RESOURCE_GRAPH_CSS, > + FF_RESOURCE_GRAPH_HTML, > +} FFResourceId; > + > +typedef struct FFResourceDefinition { > + FFResourceId resource_id; > + const char *name; > + > + const unsigned char *data; > + const unsigned *data_len; > + > +} FFResourceDefinition; > + > +void ff_resman_uninit(void); > + > +char *ff_resman_get_string(FFResourceId resource_id); > + > +#endif /* FFTOOLS_RESOURCES_RESMAN_H */ _______________________________________________ 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".