PR #21618 opened by Niklas Haas (haasn) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21618 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21618.patch
Currently, protocols like `cache:` or `http:` just log all messages under the default identifier `cache`, which is a bit nondescriptive and presents ambiguity when using multiple such protocols at the same time. This series of changes adds some ability for URLContexts to influence their own log output; and adds a proof of concept to `cache`, `file` and `http`. Results in log output like: ``` [cache:http:V9b0kRNUty7WwP.ts @ 0x224a15c0] Statistics, cache hits:10 cache misses:87 ``` For what used to be just: ``` [cache @ 0x224a15c0] Statistics, cache hits:10 cache misses:87 ``` >From 3d09d265fd9ffc22fceb04d37f8583c7dd97e642 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Sat, 31 Jan 2026 12:36:52 +0100 Subject: [PATCH 1/4] avformat/avio: add ffurl_item_name() And use it for logging. The reason I decided to expose this as a helper is because it will allow URL protocols that wrap other URL protocols to more easily create "recursive" names that reflect the hierarchy. This change also allows URL protocols to attach custom names to a URLContext by overriding the priv_data class item_name() method. --- libavformat/avio.c | 16 ++++++++++++---- libavformat/url.h | 5 +++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/libavformat/avio.c b/libavformat/avio.c index b146ac9f19..7b1b0f13bf 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -37,13 +37,21 @@ /** @name Logging context. */ /*@{*/ +const char *ffurl_item_name(URLContext *h) +{ + if (h->priv_data) { + const AVClass *c = *(AVClass **) h->priv_data; + return c->item_name(h->priv_data); + } else if (h->prot) { + return h->prot->name; + } else + return "NULL"; +} + static const char *urlcontext_to_name(void *ptr) { URLContext *h = (URLContext *)ptr; - if (h->prot) - return h->prot->name; - else - return "NULL"; + return ffurl_item_name(h); } static void *urlcontext_child_next(void *obj, void *prev) diff --git a/libavformat/url.h b/libavformat/url.h index 0784d77b64..eb1f285958 100644 --- a/libavformat/url.h +++ b/libavformat/url.h @@ -48,6 +48,11 @@ typedef struct URLContext { int min_packet_size; /**< if non zero, the stream is packetized with this min packet size */ } URLContext; +/** + * Get the (friendly) name of a URLContext, for debugging / logging purposes. + */ +const char *ffurl_item_name(URLContext *h); + typedef struct URLProtocol { const char *name; int (*url_open)( URLContext *h, const char *url, int flags); -- 2.52.0 >From ea7cea342d6cde590f5eef4af886dbaced93f104 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Sat, 31 Jan 2026 12:41:06 +0100 Subject: [PATCH 2/4] avformat/file: use file basename for logging purposes This is perhaps not immediately useful on its own, since file.c does not really log anything, but is useful when accessed recursively via other protocols like cache: --- libavformat/file.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/libavformat/file.c b/libavformat/file.c index 3ceddc8c25..1bd8b72d9a 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -91,6 +91,7 @@ typedef struct FileContext { const AVClass *class; + char *name; int fd; int trunc; int blocksize; @@ -117,23 +118,29 @@ static const AVOption pipe_options[] = { { NULL } }; +static const char *file_item_name(void *ctx) +{ + FileContext *c = ctx; + return c->name ? c->name : av_default_item_name(ctx); +} + static const AVClass file_class = { .class_name = "file", - .item_name = av_default_item_name, + .item_name = file_item_name, .option = file_options, .version = LIBAVUTIL_VERSION_INT, }; static const AVClass pipe_class = { .class_name = "pipe", - .item_name = av_default_item_name, + .item_name = file_item_name, .option = pipe_options, .version = LIBAVUTIL_VERSION_INT, }; static const AVClass fd_class = { .class_name = "fd", - .item_name = av_default_item_name, + .item_name = file_item_name, .option = pipe_options, .version = LIBAVUTIL_VERSION_INT, }; @@ -223,6 +230,7 @@ static int fd_dup(URLContext *h, int oldfd) static int file_close(URLContext *h) { FileContext *c = h->priv_data; + av_freep(&c->name); int ret = close(c->fd); return (ret == -1) ? AVERROR(errno) : 0; } @@ -290,6 +298,7 @@ static int file_open(URLContext *h, const char *filename, int flags) struct stat st; av_strstart(filename, "file:", &filename); + c->name = av_asprintf("file:%s", av_basename(filename)); if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) { access = O_CREAT | O_RDWR; @@ -445,6 +454,7 @@ static int pipe_open(URLContext *h, const char *filename, int flags) char *final; if (c->fd < 0) { + c->name = av_strdup(filename); av_strstart(filename, "pipe:", &filename); if (!*filename) { @@ -507,6 +517,7 @@ static int fd_open(URLContext *h, const char *filename, int flags) return AVERROR(errno); h->is_streamed = !(S_ISREG(st.st_mode) || S_ISBLK(st.st_mode)); c->fd = fd_dup(h, c->fd); + c->name = av_strdup(filename); if (c->fd == -1) return AVERROR(errno); -- 2.52.0 >From 05c3fc5150ba48d0d3d08f85e6966bfe2bb6d6b5 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Sat, 31 Jan 2026 13:09:00 +0100 Subject: [PATCH 3/4] avformat/cache: use inner URL context name for logging Reflecting/forwarding the item name of the underlying protocol. --- libavformat/cache.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/libavformat/cache.c b/libavformat/cache.c index 0d682213d5..09c5161871 100644 --- a/libavformat/cache.c +++ b/libavformat/cache.c @@ -54,6 +54,7 @@ typedef struct CacheEntry { typedef struct CacheContext { AVClass *class; + char *name; int fd; char *filename; struct AVTreeNode *root; @@ -67,6 +68,12 @@ typedef struct CacheContext { int read_ahead_limit; } CacheContext; +static const char *cache_item_name(void *ptr) +{ + CacheContext *c = ptr; + return c->name ? c->name : av_default_item_name(ptr); +} + static int cmp(const void *key, const void *node) { return FFDIFFSIGN(*(const int64_t *)key, ((const CacheEntry *) node)->logical_pos); @@ -93,8 +100,13 @@ static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary ** else c->filename = buffername; - return ffurl_open_whitelist(&c->inner, arg, flags, &h->interrupt_callback, - options, h->protocol_whitelist, h->protocol_blacklist, h); + ret = ffurl_open_whitelist(&c->inner, arg, flags, &h->interrupt_callback, + options, h->protocol_whitelist, h->protocol_blacklist, h); + if (ret < 0) + return ret; + + c->name = av_asprintf("cache:%s", ffurl_item_name(c->inner)); + return ret; } static int add_entry(URLContext *h, const unsigned char *buf, int size) @@ -314,6 +326,7 @@ static int cache_close(URLContext *h) ffurl_closep(&c->inner); av_tree_enumerate(c->root, NULL, NULL, enu_free); av_tree_destroy(c->root); + av_freep(&c->name); return 0; } @@ -328,7 +341,7 @@ static const AVOption options[] = { static const AVClass cache_context_class = { .class_name = "cache", - .item_name = av_default_item_name, + .item_name = cache_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; -- 2.52.0 >From ec0a0f19717de4604878651569f8e6614eba7130 Mon Sep 17 00:00:00 2001 From: Niklas Haas <[email protected]> Date: Sat, 31 Jan 2026 13:18:38 +0100 Subject: [PATCH 4/4] avformat/http: use basename of URL for logging This is not as verbose as printing the full URL every time, but still gives some context about which resource is being referred to. --- libavformat/http.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/libavformat/http.c b/libavformat/http.c index 6ee498b4df..e515ac04ec 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -71,6 +71,7 @@ typedef enum { typedef struct HTTPContext { const AVClass *class; + char *name; URLContext *hd; unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end; int line_count; @@ -743,6 +744,20 @@ fail: return ret; } +static char *uri_basename(const char *uri) +{ + /* Strip anything after a '?' or '#' */ + const char *end = uri + strcspn(uri, "?#"); + + /* Find the last '/' before that */ + const char *start = end; + while (start > uri && start[-1] != '/') + start--; + + const int len = end - start; + return len ? av_asprintf("http:%.*s", len, start) : av_strdup("http"); +} + static int http_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { @@ -764,6 +779,10 @@ static int http_open(URLContext *h, const char *uri, int flags, if (!s->uri) return AVERROR(ENOMEM); + s->name = uri_basename(uri); + if (!s->name) + return AVERROR(ENOMEM); + if (options) av_dict_copy(&s->chained_options, *options, 0); @@ -1994,6 +2013,7 @@ static int http_close(URLContext *h) av_dict_free(&s->redirect_cache); av_freep(&s->new_location); av_freep(&s->uri); + av_freep(&s->name); return ret; } @@ -2084,10 +2104,16 @@ static int http_get_short_seek(URLContext *h) return ffurl_get_short_seek(s->hd); } +static const char *http_item_name(void *ctx) +{ + HTTPContext *s = ctx; + return s->name ? s->name : av_default_item_name(ctx); +} + #define HTTP_CLASS(flavor) \ static const AVClass flavor ## _context_class = { \ .class_name = # flavor, \ - .item_name = av_default_item_name, \ + .item_name = http_item_name, \ .option = options, \ .version = LIBAVUTIL_VERSION_INT, \ } -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
