Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
@ 2023-05-01 11:44 Marvin Scholz
  2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 2/3] avformat/tee: use av_dict_pop Marvin Scholz
                   ` (4 more replies)
  0 siblings, 5 replies; 32+ messages in thread
From: Marvin Scholz @ 2023-05-01 11:44 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marvin Scholz

This new API allows to remove an entry and obtain ownership of the
key/value that was associated with the removed entry.
---
 doc/APIchanges         |  4 ++++
 libavutil/dict.c       | 27 +++++++++++++++++++++++++++
 libavutil/dict.h       | 20 ++++++++++++++++++++
 libavutil/tests/dict.c | 34 ++++++++++++++++++++++++++++++++++
 libavutil/version.h    |  2 +-
 tests/ref/fate/dict    | 12 ++++++++++++
 6 files changed, 98 insertions(+), 1 deletion(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 0b609e3d3b..5b807873b7 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
 
 API changes, most recent first:
 
+2023-04-29 - xxxxxxxxxx - lavu 58.7.100 - dict.c
+  Add av_dict_pop() to remove an entry from a dict
+  and get ownership of the removed key/value.
+
 2023-04-10 - xxxxxxxxxx - lavu 58.6.100 - frame.h
   av_frame_get_plane_buffer() now accepts const AVFrame*.
 
diff --git a/libavutil/dict.c b/libavutil/dict.c
index f673977a98..ac41771994 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
     return av_dict_set(pm, key, valuestr, flags);
 }
 
+int av_dict_pop(AVDictionary **pm, const char *key,
+                char **out_key, char **out_value, int flags)
+{
+    AVDictionary *m = *pm;
+    AVDictionaryEntry *entry = NULL;
+    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
+    if (!entry)
+        return AVERROR(ENOENT);
+
+    if (out_key)
+        *out_key = entry->key;
+    else
+        av_free(entry->key);
+
+    if (out_value)
+        *out_value = entry->value;
+    else
+        av_free(entry->value);
+
+    *entry = m->elems[--m->count];
+    if (m && !m->count) {
+        av_freep(&m->elems);
+        av_freep(pm);
+    }
+    return 0;
+}
+
 static int parse_key_value_pair(AVDictionary **pm, const char **buf,
                                 const char *key_val_sep, const char *pairs_sep,
                                 int flags)
diff --git a/libavutil/dict.h b/libavutil/dict.h
index 713c9e361a..b2ab55a026 100644
--- a/libavutil/dict.h
+++ b/libavutil/dict.h
@@ -172,6 +172,26 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
  */
 int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
 
+/**
+ * Remove the entry with the given key from the dictionary.
+ *
+ * Search for an entry matching `key` and remove it, if found. Optionally
+ * the found key and/or value can be returned using the `out_key`/`out_value`
+ * arguments.
+ *
+ * If more than one entry matches, only one entry is removed and returned
+ * on each call. Which entry is returned first in that case is undefined.
+ *
+ * @param pm        Pointer to a pointer to a dictionary struct.
+ * @param key       Entry key to match.
+ * @param out_key   Pointer whose pointee will be set to the matched
+ *                  entry key. Must be freed by the caller. May be NULL.
+ * @param out_value Pointer whose pointee will be set to the matched
+ *                  entry value. Must be freed by the caller. May be NULL.
+ */
+int av_dict_pop(AVDictionary **pm, const char *key,
+                char **out_key, char **out_value, int flags);
+
 /**
  * Parse the key/value pairs list and add the parsed entries to a dictionary.
  *
diff --git a/libavutil/tests/dict.c b/libavutil/tests/dict.c
index bececefb31..0652794b97 100644
--- a/libavutil/tests/dict.c
+++ b/libavutil/tests/dict.c
@@ -158,5 +158,39 @@ int main(void)
     printf("%s\n", e->value);
     av_dict_free(&dict);
 
+    char *key, *val = NULL;
+    int ret;
+    printf("\nTesting av_dict_pop() with existing AVDictionaryEntry.key as key\n");
+    av_dict_set(&dict, "test-key", "test-value", 0);
+    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
+    printf("%s: %s (Return code: %i)\n",
+        (key) ? key : "(null)",
+        (val) ? val : "(null)", ret);
+    e = av_dict_get(dict, "test-key", NULL, 0);
+    printf("%s\n", (e) ? e->value : "(null)");
+    av_freep(&key);
+    av_freep(&val);
+
+    printf("\nTesting av_dict_pop() with nonexistent key\n");
+    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
+    printf("%s: %s (Return code: %i)\n",
+        (key) ? key : "(null)",
+        (val) ? val : "(null)", ret);
+    e = av_dict_get(dict, "test-key", NULL, 0);
+    printf("%s\n", (e) ? e->value : "(null)");
+    av_freep(&key);
+    av_freep(&val);
+
+    printf("\nTesting av_dict_pop() with prefix key match\n");
+    av_dict_set(&dict, "prefix-test-key", "test-value", 0);
+    ret = av_dict_pop(&dict, "prefix-test", &key, &val, AV_DICT_IGNORE_SUFFIX);
+    printf("%s: %s (Return code: %i)\n",
+        (key) ? key : "(null)",
+        (val) ? val : "(null)", ret);
+    e = av_dict_get(dict, "prefix-test", NULL, AV_DICT_IGNORE_SUFFIX);
+    printf("%s\n", (e) ? e->value : "(null)");
+    av_freep(&key);
+    av_freep(&val);
+
     return 0;
 }
diff --git a/libavutil/version.h b/libavutil/version.h
index 40f92af055..b8d1ef06a8 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR  58
-#define LIBAVUTIL_VERSION_MINOR   6
+#define LIBAVUTIL_VERSION_MINOR   7
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
diff --git a/tests/ref/fate/dict b/tests/ref/fate/dict
index 7205e4c845..bdb097cb03 100644
--- a/tests/ref/fate/dict
+++ b/tests/ref/fate/dict
@@ -48,3 +48,15 @@ Testing av_dict_set_int()
 Testing av_dict_set() with existing AVDictionaryEntry.key as key
 new val OK
 new val OK
+
+Testing av_dict_pop() with existing AVDictionaryEntry.key as key
+test-key: test-value (Return code: 0)
+(null)
+
+Testing av_dict_pop() with nonexistent key
+(null): (null) (Return code: -2)
+(null)
+
+Testing av_dict_pop() with prefix key match
+prefix-test-key: test-value (Return code: 0)
+(null)
-- 
2.37.0 (Apple Git-136)

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [FFmpeg-devel] [PATCH 2/3] avformat/tee: use av_dict_pop
  2023-05-01 11:44 [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Marvin Scholz
@ 2023-05-01 11:44 ` Marvin Scholz
  2023-06-25 12:07   ` "zhilizhao(赵志立)"
  2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 3/3] avutil/dict: constify av_dict_get return Marvin Scholz
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 32+ messages in thread
From: Marvin Scholz @ 2023-05-01 11:44 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marvin Scholz

This is a well-defined way to "steal" the value of the dict entry.
---
 libavformat/tee.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index cb555f52fd..70f3f2eb29 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -157,6 +157,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
 {
     int i, ret;
     AVDictionary *options = NULL, *bsf_options = NULL;
+    char *entry_val = NULL;
     AVDictionaryEntry *entry;
     char *filename;
     char *format = NULL, *select = NULL, *on_fail = NULL;
@@ -171,15 +172,15 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
         return ret;
 
 #define CONSUME_OPTION(option, field, action) do {                      \
-        if ((entry = av_dict_get(options, option, NULL, 0))) {          \
-            field = entry->value;                                       \
+        if ((!av_dict_pop(&options, option, NULL, &entry_val, 0))) {    \
+            field = entry_val;                                          \
             { action }                                                  \
-            av_dict_set(&options, option, NULL, 0);                     \
+            av_freep(&entry_val);                                       \
         }                                                               \
     } while (0)
 #define STEAL_OPTION(option, field)                                     \
     CONSUME_OPTION(option, field,                                       \
-                   entry->value = NULL; /* prevent it from being freed */)
+                   entry_val = NULL; /* prevent it from being freed */)
 #define PROCESS_OPTION(option, field, function, on_error)               \
     CONSUME_OPTION(option, field, if ((ret = function) < 0) { { on_error } goto end; })
 
-- 
2.37.0 (Apple Git-136)

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [FFmpeg-devel] [PATCH 3/3] avutil/dict: constify av_dict_get return
  2023-05-01 11:44 [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Marvin Scholz
  2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 2/3] avformat/tee: use av_dict_pop Marvin Scholz
@ 2023-05-01 11:44 ` Marvin Scholz
  2023-06-05 10:05   ` Anton Khirnov
  2023-05-21 23:52 ` [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Stefano Sabatini
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 32+ messages in thread
From: Marvin Scholz @ 2023-05-01 11:44 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marvin Scholz

---
 doc/examples/qsv_transcode.c       |  2 +-
 libavcodec/libaomenc.c             |  2 +-
 libavcodec/libkvazaar.c            |  2 +-
 libavcodec/libsvtav1.c             |  2 +-
 libavcodec/libvpxenc.c             |  2 +-
 libavcodec/libx264.c               |  2 +-
 libavcodec/libx265.c               |  2 +-
 libavcodec/mjpegdec.c              |  2 +-
 libavcodec/qsvenc.c                |  2 +-
 libavfilter/avfilter.c             |  2 +-
 libavfilter/f_bench.c              |  2 +-
 libavfilter/f_drawgraph.c          |  2 +-
 libavfilter/f_select.c             |  4 +--
 libavfilter/vf_cover_rect.c        |  2 +-
 libavfilter/vf_drawtext.c          |  2 +-
 libavformat/aiffenc.c              |  2 +-
 libavformat/argo_asf.c             |  2 +-
 libavformat/asfenc.c               |  6 ++--
 libavformat/au.c                   |  2 +-
 libavformat/avformat.h             |  2 +-
 libavformat/avidec.c               |  2 +-
 libavformat/avienc.c               |  2 +-
 libavformat/avio.c                 |  4 +--
 libavformat/dashenc.c              |  6 ++--
 libavformat/dvenc.c                |  2 +-
 libavformat/flacdec.c              |  2 +-
 libavformat/flacenc.c              |  6 ++--
 libavformat/flvdec.c               |  2 +-
 libavformat/gxfenc.c               |  2 +-
 libavformat/http.c                 |  8 +++---
 libavformat/id3v2.c                |  6 ++--
 libavformat/id3v2enc.c             |  2 +-
 libavformat/imfdec.c               |  2 +-
 libavformat/matroskadec.c          |  2 +-
 libavformat/mov.c                  |  6 ++--
 libavformat/movenc.c               | 46 +++++++++++++++---------------
 libavformat/mp3enc.c               |  6 ++--
 libavformat/mpegtsenc.c            |  6 ++--
 libavformat/mux.c                  |  2 +-
 libavformat/mux_utils.c            |  2 +-
 libavformat/mxfenc.c               | 14 ++++-----
 libavformat/riffenc.c              |  2 +-
 libavformat/rmenc.c                |  2 +-
 libavformat/sapenc.c               |  2 +-
 libavformat/sdp.c                  |  2 +-
 libavformat/segment.c              |  4 +--
 libavformat/soxenc.c               |  2 +-
 libavformat/tee.c                  |  2 +-
 libavformat/ttmlenc.c              |  4 +--
 libavformat/wavenc.c               |  4 +--
 libavformat/webmdashenc.c          | 30 +++++++++----------
 libavutil/dict.c                   |  9 +++++-
 libavutil/dict.h                   |  5 ++++
 libavutil/hwcontext_cuda.c         |  2 +-
 libavutil/hwcontext_qsv.c          |  2 +-
 libavutil/hwcontext_vulkan.c       |  8 +++---
 libavutil/version.h                |  1 +
 tests/api/api-threadmessage-test.c |  2 +-
 58 files changed, 136 insertions(+), 123 deletions(-)

diff --git a/doc/examples/qsv_transcode.c b/doc/examples/qsv_transcode.c
index 48128b200c..cc4c203d94 100644
--- a/doc/examples/qsv_transcode.c
+++ b/doc/examples/qsv_transcode.c
@@ -87,7 +87,7 @@ static int dynamic_set_parameter(AVCodecContext *avctx)
     frame_number++;
     if (current_setting_number < setting_number &&
         frame_number == dynamic_setting[current_setting_number].frame_number) {
-        AVDictionaryEntry *e = NULL;
+        const AVDictionaryEntry *e = NULL;
         ret = str_to_dict(dynamic_setting[current_setting_number++].optstr, &opts);
         if (ret < 0) {
             fprintf(stderr, "The dynamic parameter is wrong\n");
diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c
index 0b88102c77..8a32f31677 100644
--- a/libavcodec/libaomenc.c
+++ b/libavcodec/libaomenc.c
@@ -999,7 +999,7 @@ static av_cold int aom_init(AVCodecContext *avctx,
 
 #if AOM_ENCODER_ABI_VERSION >= 23
     {
-        AVDictionaryEntry *en = NULL;
+        const AVDictionaryEntry *en = NULL;
 
         while ((en = av_dict_get(ctx->aom_params, "", en, AV_DICT_IGNORE_SUFFIX))) {
             int ret = aom_codec_set_option(&ctx->encoder, en->key, en->value);
diff --git a/libavcodec/libkvazaar.c b/libavcodec/libkvazaar.c
index 168486f4ec..f9f3ce8e52 100644
--- a/libavcodec/libkvazaar.c
+++ b/libavcodec/libkvazaar.c
@@ -103,7 +103,7 @@ static av_cold int libkvazaar_init(AVCodecContext *avctx)
     if (ctx->kvz_params) {
         AVDictionary *dict = NULL;
         if (!av_dict_parse_string(&dict, ctx->kvz_params, "=", ",", 0)) {
-            AVDictionaryEntry *entry = NULL;
+            const AVDictionaryEntry *entry = NULL;
             while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX))) {
                 if (!api->config_parse(cfg, entry->key, entry->value)) {
                     av_log(avctx, AV_LOG_WARNING, "Invalid option: %s=%s.\n",
diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c
index 9174e2753c..e959c1cab0 100644
--- a/libavcodec/libsvtav1.c
+++ b/libavcodec/libsvtav1.c
@@ -151,7 +151,7 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param,
 {
     SvtContext *svt_enc = avctx->priv_data;
     const AVPixFmtDescriptor *desc;
-    AVDictionaryEntry *en = NULL;
+    const AVDictionaryEntry *en = NULL;
 
     // Update param from options
 #if FF_API_SVTAV1_OPTS
diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c
index a20e949842..29fdc3f9d4 100644
--- a/libavcodec/libvpxenc.c
+++ b/libavcodec/libvpxenc.c
@@ -1734,7 +1734,7 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt,
         if (frame->pict_type == AV_PICTURE_TYPE_I)
             flags |= VPX_EFLAG_FORCE_KF;
         if (frame->metadata) {
-            AVDictionaryEntry* en = av_dict_get(frame->metadata, "vp8-flags", NULL, 0);
+            const AVDictionaryEntry* en = av_dict_get(frame->metadata, "vp8-flags", NULL, 0);
             if (en) {
                 flags |= strtoul(en->value, NULL, 10);
             }
diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index cfdd422236..2eec1c0913 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -1082,7 +1082,7 @@ static av_cold int X264_init(AVCodecContext *avctx)
 #endif
 
     {
-        AVDictionaryEntry *en = NULL;
+        const AVDictionaryEntry *en = NULL;
         while (en = av_dict_get(x4->x264_params, "", en, AV_DICT_IGNORE_SUFFIX)) {
            if ((ret = x264_param_parse(&x4->params, en->key, en->value)) < 0) {
                av_log(avctx, AV_LOG_WARNING,
diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c
index 420d0953af..ddba5c6dbc 100644
--- a/libavcodec/libx265.c
+++ b/libavcodec/libx265.c
@@ -421,7 +421,7 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx)
     }
 
     {
-        AVDictionaryEntry *en = NULL;
+        const AVDictionaryEntry *en = NULL;
         while ((en = av_dict_get(ctx->x265_opts, "", en, AV_DICT_IGNORE_SUFFIX))) {
             int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value);
 
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index 01537d4774..04c3cf0430 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -2359,7 +2359,7 @@ int ff_mjpeg_decode_frame_from_buf(AVCodecContext *avctx, AVFrame *frame,
     int i, index;
     int ret = 0;
     int is16bit;
-    AVDictionaryEntry *e = NULL;
+    const AVDictionaryEntry *e = NULL;
 
     s->force_pal8 = 0;
 
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index c975302b4f..cf411ca520 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -2046,7 +2046,7 @@ static int set_roi_encode_ctrl(AVCodecContext *avctx, const AVFrame *frame,
 static void set_skip_frame_encode_ctrl(AVCodecContext *avctx, const AVFrame *frame,
                                mfxEncodeCtrl *enc_ctrl)
 {
-    AVDictionaryEntry* skip_frame_dict = NULL;
+    const AVDictionaryEntry* skip_frame_dict = NULL;
     if (!frame->metadata)
         return;
     skip_frame_dict = av_dict_get(frame->metadata, "qsv_skip_frame", NULL, 0);
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 8d5702a0c8..60224c93ef 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -897,7 +897,7 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options)
 int avfilter_init_str(AVFilterContext *filter, const char *args)
 {
     AVDictionary *options = NULL;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     int ret = 0;
 
     if (args && *args) {
diff --git a/libavfilter/f_bench.c b/libavfilter/f_bench.c
index 9b55194dbc..ca1adf4ae6 100644
--- a/libavfilter/f_bench.c
+++ b/libavfilter/f_bench.c
@@ -71,7 +71,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     if (s->action == ACTION_START) {
         av_dict_set_int(&in->metadata, START_TIME_KEY, t, 0);
     } else if (s->action == ACTION_STOP) {
-        AVDictionaryEntry *e = av_dict_get(in->metadata, START_TIME_KEY, NULL, 0);
+        const AVDictionaryEntry *e = av_dict_get(in->metadata, START_TIME_KEY, NULL, 0);
         if (e) {
             const int64_t start = strtoll(e->value, NULL, 0);
             const int64_t diff = t - start;
diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c
index d29a7fb60a..69d8ba9993 100644
--- a/libavfilter/f_drawgraph.c
+++ b/libavfilter/f_drawgraph.c
@@ -165,7 +165,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     DrawGraphContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
     AVDictionary *metadata;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     AVFrame *out = s->out;
     AVFrame *clone = NULL;
     int64_t in_pts, out_pts, in_duration;
diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
index d76c248fc5..b01526371a 100644
--- a/libavfilter/f_select.c
+++ b/libavfilter/f_select.c
@@ -308,8 +308,8 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *frame)
 static double get_concatdec_select(AVFrame *frame, int64_t pts)
 {
     AVDictionary *metadata = frame->metadata;
-    AVDictionaryEntry *start_time_entry = av_dict_get(metadata, "lavf.concatdec.start_time", NULL, 0);
-    AVDictionaryEntry *duration_entry = av_dict_get(metadata, "lavf.concatdec.duration", NULL, 0);
+    const AVDictionaryEntry *start_time_entry = av_dict_get(metadata, "lavf.concatdec.start_time", NULL, 0);
+    const AVDictionaryEntry *duration_entry = av_dict_get(metadata, "lavf.concatdec.duration", NULL, 0);
     if (start_time_entry) {
         int64_t start_time = strtoll(start_time_entry->value, NULL, 10);
         if (pts >= start_time) {
diff --git a/libavfilter/vf_cover_rect.c b/libavfilter/vf_cover_rect.c
index 642747a351..b219ae2948 100644
--- a/libavfilter/vf_cover_rect.c
+++ b/libavfilter/vf_cover_rect.c
@@ -125,7 +125,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
     CoverContext *cover = ctx->priv;
-    AVDictionaryEntry *ex, *ey, *ew, *eh;
+    const AVDictionaryEntry *ex, *ey, *ew, *eh;
     int ret, x = -1, y = -1, w = -1, h = -1;
     char *xendptr = NULL, *yendptr = NULL, *wendptr = NULL, *hendptr = NULL;
 
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 71ab851462..d2973f2d96 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -1047,7 +1047,7 @@ static int func_metadata(AVFilterContext *ctx, AVBPrint *bp,
                          char *fct, unsigned argc, char **argv, int tag)
 {
     DrawTextContext *s = ctx->priv;
-    AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
+    const AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
 
     if (e && e->value)
         av_bprintf(bp, "%s", e->value);
diff --git a/libavformat/aiffenc.c b/libavformat/aiffenc.c
index 11a5b18d57..b2ca6c9ce7 100644
--- a/libavformat/aiffenc.c
+++ b/libavformat/aiffenc.c
@@ -83,7 +83,7 @@ static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff)
 
 static void put_meta(AVFormatContext *s, const char *key, uint32_t id)
 {
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
     AVIOContext *pb = s->pb;
 
     if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
diff --git a/libavformat/argo_asf.c b/libavformat/argo_asf.c
index 5f38b68b6a..f83f9b2e2a 100644
--- a/libavformat/argo_asf.c
+++ b/libavformat/argo_asf.c
@@ -360,7 +360,7 @@ static int argo_asf_write_header(AVFormatContext *s)
         .num_chunks    = 1,
         .chunk_offset  = ASF_FILE_HEADER_SIZE
     };
-    AVDictionaryEntry *t;
+    const AVDictionaryEntry *t;
     const char *name, *end;
     size_t len;
 
diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c
index 244c7e7a27..8810d64980 100644
--- a/libavformat/asfenc.c
+++ b/libavformat/asfenc.c
@@ -331,7 +331,7 @@ static void asf_write_markers(AVFormatContext *s, AVIOContext *dyn_buf)
 
     for (unsigned i = 0; i < s->nb_chapters; i++) {
         AVChapter *c = s->chapters[i];
-        AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0);
+        const AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0);
         int64_t pres_time = av_rescale_q(c->start, c->time_base, scale);
         uint64_t offset;
         int32_t send_time = get_send_time(asf, pres_time, &offset);
@@ -361,7 +361,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
 {
     ASFContext *asf = s->priv_data;
     AVIOContext *pb = s->pb, *dyn_buf;
-    AVDictionaryEntry *tags[5];
+    const AVDictionaryEntry *tags[5];
     int header_size, extra_size, extra_size2, wav_extra_size;
     int has_title, has_aspect_ratio = 0;
     int metadata_count;
@@ -392,7 +392,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
     for (unsigned n = 0; n < s->nb_streams; n++) {
         AVStream *const st = s->streams[n];
         AVCodecParameters *const par = st->codecpar;
-        AVDictionaryEntry *entry;
+        const AVDictionaryEntry *entry;
 
         avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */
 
diff --git a/libavformat/au.c b/libavformat/au.c
index 3bf2150258..68b665aeb7 100644
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@ -261,7 +261,7 @@ static int au_get_annotations(AVFormatContext *s, AVBPrint *annotations)
     };
     int cnt = 0;
     AVDictionary *m = s->metadata;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
 
     for (int i = 0; i < FF_ARRAY_ELEMS(keys); i++) {
         t = av_dict_get(m, keys[i], NULL, 0);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 1916aa2dc5..95f52a639c 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -146,7 +146,7 @@
  * consumed). The calling program can handle such unrecognized options as it
  * wishes, e.g.
  * @code
- * AVDictionaryEntry *e;
+ * const AVDictionaryEntry *e;
  * if (e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
  *     fprintf(stderr, "Option %s not recognized by the demuxer.\n", e->key);
  *     abort();
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index 7a3fad6392..0cf9174013 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -507,7 +507,7 @@ static int avi_read_header(AVFormatContext *s)
     uint64_t list_end   = 0;
     int64_t pos;
     int ret;
-    AVDictionaryEntry *dict_entry;
+    const AVDictionaryEntry *dict_entry;
 
     avi->stream_index = -1;
 
diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index a61e5c3109..b62258f693 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -266,7 +266,7 @@ static int avi_write_header(AVFormatContext *s)
     AVCodecParameters *video_par;
     AVStream *video_st = NULL;
     int64_t list1, list2, strh, strf;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
     int padding;
 
     if (s->nb_streams > AVI_MAX_STREAM_COUNT) {
diff --git a/libavformat/avio.c b/libavformat/avio.c
index ab1c19a58d..0082977f2d 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -167,7 +167,7 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
 {
     int err;
     AVDictionary *tmp_opts = NULL;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
 
     if (!options)
         options = &tmp_opts;
@@ -309,7 +309,7 @@ int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,
                          URLContext *parent)
 {
     AVDictionary *tmp_opts = NULL;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     int ret = ffurl_alloc(puc, filename, flags, int_cb);
     if (ret < 0)
         return ret;
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 17fe5f430c..283747c63d 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -800,7 +800,7 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
 {
     DASHContext *c = s->priv_data;
     AdaptationSet *as = &c->as[as_index];
-    AVDictionaryEntry *lang, *role;
+    const AVDictionaryEntry *lang, *role;
     int i;
 
     avio_printf(out, "\t\t<AdaptationSet id=\"%d\" contentType=\"%s\" startWithSAP=\"1\" segmentAlignment=\"true\" bitstreamSwitching=\"true\"",
@@ -1144,7 +1144,7 @@ static int write_manifest(AVFormatContext *s, int final)
     const char *proto = avio_find_protocol_name(s->url);
     int use_rename = proto && !strcmp(proto, "file");
     static unsigned int warned_non_file = 0;
-    AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
+    const AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
     AVDictionary *opts = NULL;
 
     if (!use_rename && !warned_non_file++)
@@ -1372,7 +1372,7 @@ static int write_manifest(AVFormatContext *s, int final)
 
 static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key)
 {
-    AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0);
+    const AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0);
     if (entry)
         av_dict_set(dst, key, entry->value, AV_DICT_DONT_OVERWRITE);
     return 0;
diff --git a/libavformat/dvenc.c b/libavformat/dvenc.c
index 29d2dc47ac..246d190961 100644
--- a/libavformat/dvenc.c
+++ b/libavformat/dvenc.c
@@ -390,7 +390,7 @@ static int dv_write_header(AVFormatContext *s)
 {
     AVRational rate;
     DVMuxContext *dvc = s->priv_data;
-    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+    const AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
 
     if (!dv_init_mux(s)) {
         av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n"
diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c
index b58ec03963..773fddc4fd 100644
--- a/libavformat/flacdec.c
+++ b/libavformat/flacdec.c
@@ -176,7 +176,7 @@ static int flac_read_header(AVFormatContext *s)
             }
             /* process supported blocks other than STREAMINFO */
             if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
-                AVDictionaryEntry *chmask;
+                const AVDictionaryEntry *chmask;
 
                 ret = ff_vorbis_comment(s, &s->metadata, buffer, metadata_size, 1);
                 if (ret < 0) {
diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c
index a8beec7750..fab7b34fa8 100644
--- a/libavformat/flacenc.c
+++ b/libavformat/flacenc.c
@@ -85,7 +85,7 @@ static int flac_write_picture(struct AVFormatContext *s, AVPacket *pkt)
     AVIOContext *pb = s->pb;
     const AVPixFmtDescriptor *pixdesc;
     const CodecMime *mime = ff_id3v2_mime_tags;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     const char *mimetype = NULL, *desc = "";
     const AVStream *st = s->streams[pkt->stream_index];
     int i, mimelen, desclen, type = 0, blocklen;
@@ -243,8 +243,8 @@ static int flac_init(struct AVFormatContext *s)
     if (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE &&
         !(par->ch_layout.u.mask & ~0x3ffffULL) &&
         !ff_flac_is_native_layout(par->ch_layout.u.mask)) {
-        AVDictionaryEntry *chmask = av_dict_get(s->metadata, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK",
-                                                NULL, 0);
+        const AVDictionaryEntry *chmask = av_dict_get(s->metadata, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK",
+                                                      NULL, 0);
 
         if (chmask) {
             av_log(s, AV_LOG_WARNING, "A WAVEFORMATEXTENSIBLE_CHANNEL_MASK is "
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index d83edff727..abb282da56 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -1268,7 +1268,7 @@ retry_duration:
         }
         if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
             st->codecpar->codec_id == AV_CODEC_ID_H264)) {
-            AVDictionaryEntry *t;
+            const AVDictionaryEntry *t;
 
             if (st->codecpar->extradata) {
                 if ((ret = flv_queue_extradata(flv, s->pb, stream_type, size)) < 0)
diff --git a/libavformat/gxfenc.c b/libavformat/gxfenc.c
index 7495924722..93bfed8246 100644
--- a/libavformat/gxfenc.c
+++ b/libavformat/gxfenc.c
@@ -688,7 +688,7 @@ static int gxf_write_header(AVFormatContext *s)
     uint8_t tracks[255] = {0};
     int i, media_info = 0;
     int ret;
-    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+    const AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
 
     if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
         av_log(s, AV_LOG_ERROR, "gxf muxer does not support streamed output, patch welcome\n");
diff --git a/libavformat/http.c b/libavformat/http.c
index 0817aafb5b..c18a4d7e58 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -309,7 +309,7 @@ static int http_should_reconnect(HTTPContext *s, int err)
 
 static char *redirect_cache_get(HTTPContext *s)
 {
-    AVDictionaryEntry *re;
+    const AVDictionaryEntry *re;
     int64_t expiry;
     char *delim;
 
@@ -960,7 +960,7 @@ static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
 static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
 {
     AVDictionary *new_params = NULL;
-    AVDictionaryEntry *e, *cookie_entry;
+    const AVDictionaryEntry *e, *cookie_entry;
     char *eql, *name;
 
     // ensure the cookie is parsable
@@ -978,7 +978,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
     if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) {
         struct tm new_tm = {0};
         if (!parse_set_cookie_expiry_time(e->value, &new_tm)) {
-            AVDictionaryEntry *e2;
+            const AVDictionaryEntry *e2;
 
             // if the cookie has already expired ignore it
             if (av_timegm(&new_tm) < av_gettime() / 1000000) {
@@ -1256,7 +1256,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path,
     *cookies = NULL;
     while ((cookie = av_strtok(next, "\n", &saveptr)) && !ret) {
         AVDictionary *cookie_params = NULL;
-        AVDictionaryEntry *cookie_entry, *e;
+        const AVDictionaryEntry *cookie_entry, *e;
 
         next = NULL;
         // store the cookie in a dict in case it is updated in the response
diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index cb31864045..8d201cb63a 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -536,9 +536,9 @@ static int is_number(const char *str)
     return !*str;
 }
 
-static AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag)
+static const AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag)
 {
-    AVDictionaryEntry *t;
+    const AVDictionaryEntry *t;
     if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
         strlen(t->value) == 4 && is_number(t->value))
         return t;
@@ -547,7 +547,7 @@ static AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag)
 
 static void merge_date(AVDictionary **m)
 {
-    AVDictionaryEntry *t;
+    const AVDictionaryEntry *t;
     char date[17] = { 0 };      // YYYY-MM-DD hh:mm
 
     if (!(t = get_date_tag(*m, "TYER")) &&
diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c
index ac907c2758..6d646e3f29 100644
--- a/libavformat/id3v2enc.c
+++ b/libavformat/id3v2enc.c
@@ -352,7 +352,7 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
 int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
 {
     AVStream *st = s->streams[pkt->stream_index];
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
 
     AVIOContext *dyn_buf;
     uint8_t     *buf;
diff --git a/libavformat/imfdec.c b/libavformat/imfdec.c
index 7d04d0d853..a7c39ee4f3 100644
--- a/libavformat/imfdec.c
+++ b/libavformat/imfdec.c
@@ -631,7 +631,7 @@ static int imf_read_header(AVFormatContext *s)
     IMFContext *c = s->priv_data;
     char *asset_map_path;
     char *tmp_str;
-    AVDictionaryEntry* tcr;
+    const AVDictionaryEntry* tcr;
     char tc_buf[AV_TIMECODE_STR_SIZE];
     int ret = 0;
 
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 49950956b6..9af4900814 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -2083,7 +2083,7 @@ static int matroska_parse_flac(AVFormatContext *s,
         /* check for the channel mask */
         if (block_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
             AVDictionary *dict = NULL;
-            AVDictionaryEntry *chmask;
+            const AVDictionaryEntry *chmask;
 
             ff_vorbis_comment(s, &dict, p, block_size, 0);
             chmask = av_dict_get(dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", NULL, 0);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 057fd872b1..40f4749ea8 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2340,7 +2340,7 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
     int bits_per_sample, flags;
     uint16_t version = avio_rb16(pb);
     uint32_t id = 0;
-    AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE);
+    const AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE);
     int channel_count;
 
     avio_rb16(pb); /* revision level */
@@ -8462,7 +8462,7 @@ static void export_orphan_timecode(AVFormatContext *s)
 
         if (st->codecpar->codec_tag  == MKTAG('t','m','c','d') &&
             !tmcd_is_referenced(s, i + 1)) {
-            AVDictionaryEntry *tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
+            const AVDictionaryEntry *tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
             if (tcr) {
                 av_dict_set(&s->metadata, "timecode", tcr->value, 0);
                 break;
@@ -8625,7 +8625,7 @@ static int mov_read_header(AVFormatContext *s)
         AVStream *st = s->streams[i];
         MOVStreamContext *sc = st->priv_data;
         if (sc->timecode_track > 0) {
-            AVDictionaryEntry *tcr;
+            const AVDictionaryEntry *tcr;
             int tmcd_st_id = -1;
 
             for (j = 0; j < s->nb_streams; j++)
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index c370922c7d..f5f3299cf1 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -2194,7 +2194,7 @@ static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
 
 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
 {
-    AVDictionaryEntry *encoder;
+    const AVDictionaryEntry *encoder;
     int xdcam_res =  (track->par->width == 1280 && track->par->height == 720)
                   || (track->par->width == 1440 && track->par->height == 1080)
                   || (track->par->width == 1920 && track->par->height == 1080);
@@ -2490,7 +2490,7 @@ static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
 #if 1
     int frame_duration;
     int nb_frames;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
 
     if (!track->st->avg_frame_rate.num || !track->st->avg_frame_rate.den) {
         av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
@@ -2988,7 +2988,7 @@ static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
             // hdlr.name is used by some players to identify the content title
             // of the track. So if an alternate handler description is
             // specified, use it.
-            AVDictionaryEntry *t;
+            const AVDictionaryEntry *t;
             t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
             if (t && utf8len(t->value))
                 descr = t->value;
@@ -3639,7 +3639,7 @@ static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
                                     const char *tag, const char *str)
 {
     int64_t pos = avio_tell(pb);
-    AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
+    const AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
     if (!t || !utf8len(t->value))
         return 0;
 
@@ -3952,11 +3952,11 @@ static int mov_write_string_tag(AVIOContext *pb, const char *name,
     return size;
 }
 
-static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
+static const AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
                                             const char *tag, int *lang)
 {
     int l, len, len2;
-    AVDictionaryEntry *t, *t2 = NULL;
+    const AVDictionaryEntry *t, *t2 = NULL;
     char tag2[16];
 
     *lang = 0;
@@ -3982,7 +3982,7 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
                                      int long_style)
 {
     int lang;
-    AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
+    const AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
     if (!t)
         return 0;
     return mov_write_string_tag(pb, name, t->value, lang, long_style);
@@ -3991,7 +3991,7 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
 /* iTunes bpm number */
 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
 {
-    AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
+    const AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
     int size = 0, tmpo = t ? atoi(t->value) : 0;
     if (tmpo) {
         size = 26;
@@ -4013,7 +4013,7 @@ static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
     int64_t pos = avio_tell(pb);
     double latitude, longitude, altitude;
     int32_t latitude_fix, longitude_fix, altitude_fix;
-    AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
+    const AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
     const char *ptr, *place = "";
     char *end;
     static const char *astronomical_body = "earth";
@@ -4061,9 +4061,9 @@ static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
                               AVFormatContext *s, int disc)
 {
-    AVDictionaryEntry *t = av_dict_get(s->metadata,
-                                       disc ? "disc" : "track",
-                                       NULL, 0);
+    const AVDictionaryEntry *t = av_dict_get(s->metadata,
+                                             disc ? "disc" : "track",
+                                             NULL, 0);
     int size = 0, track = t ? atoi(t->value) : 0;
     if (track) {
         int tracks = 0;
@@ -4089,7 +4089,7 @@ static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
                                    const char *name, const char *tag,
                                    int len)
 {
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
     uint8_t num;
     int size = 24 + len;
 
@@ -4281,7 +4281,7 @@ static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
                                       const char *name, const char *key)
 {
     int len;
-    AVDictionaryEntry *t;
+    const AVDictionaryEntry *t;
 
     if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
         return 0;
@@ -4319,7 +4319,7 @@ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
                                   const char *tag, const char *str)
 {
     int64_t pos = avio_tell(pb);
-    AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
+    const AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
     if (!t || !utf8len(t->value))
         return 0;
     avio_wb32(pb, 0);   /* size */
@@ -4350,7 +4350,7 @@ static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
 
     for (i = 0; i < nb_chapters; i++) {
         AVChapter *c = s->chapters[i];
-        AVDictionaryEntry *t;
+        const AVDictionaryEntry *t;
         avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
 
         if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
@@ -4436,7 +4436,7 @@ static void mov_write_psp_udta_tag(AVIOContext *pb,
 
 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
 {
-    AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
+    const AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
     int64_t pos, pos2;
 
     if (title) {
@@ -4673,7 +4673,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormat
         char track_name_buf[32] = { 0 };
 
         AVStream *st = track->st;
-        AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
+        const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
 
         if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
             type = "video";
@@ -6673,7 +6673,7 @@ static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
 
     for (i = 0; i < s->nb_chapters; i++) {
         AVChapter *c = s->chapters[i];
-        AVDictionaryEntry *t;
+        const AVDictionaryEntry *t;
 
         int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
         pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
@@ -7068,13 +7068,13 @@ static int mov_init(AVFormatContext *s)
 
     if (   mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
         || mov->write_tmcd == 1) {
-        AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
-                                                    NULL, 0);
+        const AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
+                                                          NULL, 0);
 
         /* +1 tmcd track for each video stream with a timecode */
         for (i = 0; i < s->nb_streams; i++) {
             AVStream *st = s->streams[i];
-            AVDictionaryEntry *t = global_tcr;
+            const AVDictionaryEntry *t = global_tcr;
             if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
                 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
                 AVTimecode tc;
@@ -7130,7 +7130,7 @@ static int mov_init(AVFormatContext *s)
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st= s->streams[i];
         MOVTrack *track= &mov->tracks[i];
-        AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
+        const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
 
         track->st  = st;
         track->par = st->codecpar;
diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c
index 5e81f72a59..41ade128ed 100644
--- a/libavformat/mp3enc.c
+++ b/libavformat/mp3enc.c
@@ -41,7 +41,7 @@
 static int id3v1_set_string(AVFormatContext *s, const char *key,
                             uint8_t *buf, int buf_size)
 {
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
     if ((tag = av_dict_get(s->metadata, key, NULL, 0)))
         av_strlcpy(buf, tag->value, buf_size);
     return !!tag;
@@ -50,7 +50,7 @@ static int id3v1_set_string(AVFormatContext *s, const char *key,
 // refer to: http://id3.org/ID3v1
 static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf)
 {
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
     int i, count = 0;
 
     memset(buf, 0, ID3v1_TAG_SIZE); /* fail safe */
@@ -145,7 +145,7 @@ static int mp3_write_xing(AVFormatContext *s)
 {
     MP3Context       *mp3 = s->priv_data;
     AVCodecParameters *par = s->streams[mp3->audio_stream_idx]->codecpar;
-    AVDictionaryEntry *enc = av_dict_get(s->streams[mp3->audio_stream_idx]->metadata, "encoder", NULL, 0);
+    const AVDictionaryEntry *enc = av_dict_get(s->streams[mp3->audio_stream_idx]->metadata, "encoder", NULL, 0);
     AVIOContext *dyn_ctx;
     int32_t        header;
     MPADecodeHeader  mpah;
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 700fc549df..6f1062b2d9 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -529,7 +529,7 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st = s->streams[i];
         MpegTSWriteStream *ts_st = st->priv_data;
-        AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
+        const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
         const char default_language[] = "und";
         const char *language = lang && strlen(lang->value) >= 3 ? lang->value : default_language;
         enum AVCodecID codec_id = st->codecpar->codec_id;
@@ -986,7 +986,7 @@ static MpegTSService *mpegts_add_service(AVFormatContext *s, int sid,
 {
     MpegTSWrite *ts = s->priv_data;
     MpegTSService *service;
-    AVDictionaryEntry *title, *provider;
+    const AVDictionaryEntry *title, *provider;
     char default_service_name[32];
     const char *service_name;
     const char *provider_name;
@@ -1088,7 +1088,7 @@ static void select_pcr_streams(AVFormatContext *s)
 static int mpegts_init(AVFormatContext *s)
 {
     MpegTSWrite *ts = s->priv_data;
-    AVDictionaryEntry *provider;
+    const AVDictionaryEntry *provider;
     const char *provider_name;
     int i, j;
     int ret;
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 415bd3948f..cfb1269ff5 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -185,7 +185,7 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
     FFFormatContext *const si = ffformatcontext(s);
     AVDictionary *tmp = NULL;
     const FFOutputFormat *of = ffofmt(s->oformat);
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     int ret = 0;
 
     if (options)
diff --git a/libavformat/mux_utils.c b/libavformat/mux_utils.c
index 3e63b8039a..af1ce420e7 100644
--- a/libavformat/mux_utils.c
+++ b/libavformat/mux_utils.c
@@ -125,7 +125,7 @@ int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary **op
 
 int ff_parse_creation_time_metadata(AVFormatContext *s, int64_t *timestamp, int return_seconds)
 {
-    AVDictionaryEntry *entry;
+    const AVDictionaryEntry *entry;
     int64_t parsed_timestamp;
     int ret;
     if ((entry = av_dict_get(s->metadata, "creation_time", NULL, 0))) {
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index d8252ed68f..e9eb801aa5 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -799,9 +799,9 @@ static void mxf_write_identification(AVFormatContext *s)
 {
     MXFContext *mxf = s->priv_data;
     AVIOContext *pb = s->pb;
-    AVDictionaryEntry *com_entry = av_dict_get(s->metadata, "company_name", NULL, 0);
-    AVDictionaryEntry *product_entry = av_dict_get(s->metadata, "product_name", NULL, 0);
-    AVDictionaryEntry *version_entry = av_dict_get(s->metadata, "product_version", NULL, 0);
+    const AVDictionaryEntry *com_entry = av_dict_get(s->metadata, "company_name", NULL, 0);
+    const AVDictionaryEntry *product_entry = av_dict_get(s->metadata, "product_name", NULL, 0);
+    const AVDictionaryEntry *version_entry = av_dict_get(s->metadata, "product_version", NULL, 0);
     const char *company = com_entry ? com_entry->value : "FFmpeg";
     const char *product = product_entry ? product_entry->value : !IS_OPATOM(s) ? "OP1a Muxer" : "OPAtom Muxer";
     const char *platform = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : PLATFORM_IDENT;
@@ -1649,7 +1649,7 @@ static int mxf_write_tagged_value(AVFormatContext *s, const char* name, const ch
 static int mxf_write_user_comments(AVFormatContext *s, const AVDictionary *m)
 {
     MXFContext *mxf = s->priv_data;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
     int count = 0;
 
     while ((t = av_dict_get(m, "comment_", t, AV_DICT_IGNORE_SUFFIX))) {
@@ -1789,7 +1789,7 @@ static int mxf_write_essence_container_data(AVFormatContext *s)
 static int mxf_write_header_metadata_sets(AVFormatContext *s)
 {
     MXFContext *mxf = s->priv_data;
-    AVDictionaryEntry *entry = NULL;
+    const AVDictionaryEntry *entry = NULL;
     AVStream *st = NULL;
     int i;
     MXFPackage packages[3] = {{0}};
@@ -2652,7 +2652,7 @@ static void mxf_gen_umid(AVFormatContext *s)
 static int mxf_init_timecode(AVFormatContext *s, AVStream *st, AVRational tbc)
 {
     MXFContext *mxf = s->priv_data;
-    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+    const AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
 
     if (!ff_mxf_get_content_package_rate(tbc)) {
         if (s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
@@ -2854,7 +2854,7 @@ static int mxf_init(AVFormatContext *s)
             if (ret < 0)
                 return ret;
         } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
-            AVDictionaryEntry *e = av_dict_get(st->metadata, "data_type", NULL, 0);
+            const AVDictionaryEntry *e = av_dict_get(st->metadata, "data_type", NULL, 0);
             if (e && !strcmp(e->value, "vbi_vanc_smpte_436M")) {
                 sc->index = INDEX_S436M;
             } else {
diff --git a/libavformat/riffenc.c b/libavformat/riffenc.c
index 179b0f12cb..d5c9eb8c2e 100644
--- a/libavformat/riffenc.c
+++ b/libavformat/riffenc.c
@@ -336,7 +336,7 @@ void ff_riff_write_info(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     int i;
     int64_t list_pos;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
 
     ff_metadata_conv(&s->metadata, ff_riff_info_conv, NULL);
 
diff --git a/libavformat/rmenc.c b/libavformat/rmenc.c
index 0d001224cb..a1f9d9ee15 100644
--- a/libavformat/rmenc.c
+++ b/libavformat/rmenc.c
@@ -77,7 +77,7 @@ static int rv10_write_header(AVFormatContext *ctx,
     int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i;
     int bit_rate, v, duration, flags;
     int data_offset;
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
 
     ffio_wfourcc(s, ".RMF");
     avio_wb32(s,18); /* header size */
diff --git a/libavformat/sapenc.c b/libavformat/sapenc.c
index 28839b837f..714ff1e148 100644
--- a/libavformat/sapenc.c
+++ b/libavformat/sapenc.c
@@ -77,7 +77,7 @@ static int sap_write_header(AVFormatContext *s)
     struct sockaddr_storage localaddr;
     socklen_t addrlen = sizeof(localaddr);
     int udp_fd;
-    AVDictionaryEntry* title = av_dict_get(s->metadata, "title", NULL, 0);
+    const AVDictionaryEntry* title = av_dict_get(s->metadata, "title", NULL, 0);
 
     if (!ff_network_init())
         return AVERROR(EIO);
diff --git a/libavformat/sdp.c b/libavformat/sdp.c
index 6888936290..61e57894a0 100644
--- a/libavformat/sdp.c
+++ b/libavformat/sdp.c
@@ -837,7 +837,7 @@ int ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx,
 
 int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size)
 {
-    AVDictionaryEntry *title = av_dict_get(ac[0]->metadata, "title", NULL, 0);
+    const AVDictionaryEntry *title = av_dict_get(ac[0]->metadata, "title", NULL, 0);
     struct sdp_session_level s = { 0 };
     int i, j, port, ttl, is_multicast, index = 0;
     char dst[32], dst_type[5];
diff --git a/libavformat/segment.c b/libavformat/segment.c
index 2a82f39f31..1fb52c7f16 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -355,7 +355,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
     int ret = 0;
     AVTimecode tc;
     AVRational rate;
-    AVDictionaryEntry *tcr;
+    const AVDictionaryEntry *tcr;
     char buf[AV_TIMECODE_STR_SIZE];
     int i;
     int err;
@@ -441,7 +441,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
                 char st_buf[AV_TIMECODE_STR_SIZE];
                 AVTimecode st_tc;
                 AVRational st_rate = s->streams[i]->avg_frame_rate;
-                AVDictionaryEntry *st_tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0);
+                const AVDictionaryEntry *st_tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0);
                 if (st_tcr) {
                     if ((av_timecode_init_from_string(&st_tc, st_rate, st_tcr->value, s) < 0)) {
                         av_log(s, AV_LOG_WARNING, "Could not increment stream %d timecode, error occurred during timecode creation.\n", i);
diff --git a/libavformat/soxenc.c b/libavformat/soxenc.c
index 062b4a3fae..b10168c91f 100644
--- a/libavformat/soxenc.c
+++ b/libavformat/soxenc.c
@@ -47,7 +47,7 @@ static int sox_write_header(AVFormatContext *s)
     SoXContext *sox = s->priv_data;
     AVIOContext *pb = s->pb;
     AVCodecParameters *par = s->streams[0]->codecpar;
-    AVDictionaryEntry *comment;
+    const AVDictionaryEntry *comment;
     size_t comment_len = 0, comment_size;
 
     comment = av_dict_get(s->metadata, "comment", NULL, 0);
diff --git a/libavformat/tee.c b/libavformat/tee.c
index 70f3f2eb29..2aa2934677 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -158,7 +158,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
     int i, ret;
     AVDictionary *options = NULL, *bsf_options = NULL;
     char *entry_val = NULL;
-    AVDictionaryEntry *entry;
+    const AVDictionaryEntry *entry;
     char *filename;
     char *format = NULL, *select = NULL, *on_fail = NULL;
     char *use_fifo = NULL, *fifo_options_str = NULL;
diff --git a/libavformat/ttmlenc.c b/libavformat/ttmlenc.c
index 212994be50..41020c2537 100644
--- a/libavformat/ttmlenc.c
+++ b/libavformat/ttmlenc.c
@@ -136,8 +136,8 @@ static int ttml_write_header(AVFormatContext *ctx)
         AVStream    *st = ctx->streams[0];
         AVIOContext *pb = ctx->pb;
 
-        AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,
-                                              0);
+        const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,
+                                                    0);
         const char *printed_lang = (lang && lang->value) ? lang->value : "";
 
         ttml_ctx->input_type = ff_is_ttml_stream_paragraph_based(st->codecpar) ?
diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index c12c090934..345f21293c 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -91,7 +91,7 @@ typedef struct WAVMuxContext {
 #if CONFIG_WAV_MUXER
 static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, int maxlen)
 {
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
     size_t len = 0;
 
     if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
@@ -105,7 +105,7 @@ static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, in
 
 static void bwf_write_bext_chunk(AVFormatContext *s)
 {
-    AVDictionaryEntry *tmp_tag;
+    const AVDictionaryEntry *tmp_tag;
     uint64_t time_reference = 0;
     int64_t bext = ff_start_tag(s->pb, "bext");
 
diff --git a/libavformat/webmdashenc.c b/libavformat/webmdashenc.c
index 0d6c4a2072..e085227ddd 100644
--- a/libavformat/webmdashenc.c
+++ b/libavformat/webmdashenc.c
@@ -71,7 +71,7 @@ static double get_duration(AVFormatContext *s)
     int i = 0;
     double max = 0.0;
     for (i = 0; i < s->nb_streams; i++) {
-        AVDictionaryEntry *duration = av_dict_get(s->streams[i]->metadata,
+        const AVDictionaryEntry *duration = av_dict_get(s->streams[i]->metadata,
                                                   DURATION, NULL, 0);
         if (!duration || atof(duration->value) < 0) continue;
         if (atof(duration->value) > max) max = atof(duration->value);
@@ -130,11 +130,11 @@ static void write_footer(AVFormatContext *s)
 static int subsegment_alignment(AVFormatContext *s, const AdaptationSet *as)
 {
     int i;
-    AVDictionaryEntry *gold = av_dict_get(s->streams[as->streams[0]]->metadata,
+    const AVDictionaryEntry *gold = av_dict_get(s->streams[as->streams[0]]->metadata,
                                           CUE_TIMESTAMPS, NULL, 0);
     if (!gold) return 0;
     for (i = 1; i < as->nb_streams; i++) {
-        AVDictionaryEntry *ts = av_dict_get(s->streams[as->streams[i]]->metadata,
+        const AVDictionaryEntry *ts = av_dict_get(s->streams[as->streams[i]]->metadata,
                                             CUE_TIMESTAMPS, NULL, 0);
         if (!ts || !av_strstart(ts->value, gold->value, NULL)) return 0;
     }
@@ -145,13 +145,13 @@ static int bitstream_switching(AVFormatContext *s, const AdaptationSet *as)
 {
     int i;
     const AVStream *gold_st = s->streams[as->streams[0]];
-    AVDictionaryEntry *gold_track_num = av_dict_get(gold_st->metadata,
+    const AVDictionaryEntry *gold_track_num = av_dict_get(gold_st->metadata,
                                                     TRACK_NUMBER, NULL, 0);
     AVCodecParameters *gold_par = gold_st->codecpar;
     if (!gold_track_num) return 0;
     for (i = 1; i < as->nb_streams; i++) {
         const AVStream *st = s->streams[as->streams[i]];
-        AVDictionaryEntry *track_num = av_dict_get(st->metadata,
+        const AVDictionaryEntry *track_num = av_dict_get(st->metadata,
                                                    TRACK_NUMBER, NULL, 0);
         AVCodecParameters *par = st->codecpar;
         if (!track_num ||
@@ -177,7 +177,7 @@ static int write_representation(AVFormatContext *s, AVStream *st, char *id,
     WebMDashMuxContext *w = s->priv_data;
     AVIOContext *pb = s->pb;
     const AVCodecParameters *par = st->codecpar;
-    AVDictionaryEntry *bandwidth = av_dict_get(st->metadata, BANDWIDTH, NULL, 0);
+    const AVDictionaryEntry *bandwidth = av_dict_get(st->metadata, BANDWIDTH, NULL, 0);
     const char *bandwidth_str;
     avio_printf(pb, "<Representation id=\"%s\"", id);
     if (bandwidth) {
@@ -205,10 +205,10 @@ static int write_representation(AVFormatContext *s, AVStream *st, char *id,
         avio_printf(pb, " startsWithSAP=\"1\"");
         avio_printf(pb, ">");
     } else {
-        AVDictionaryEntry *irange = av_dict_get(st->metadata, INITIALIZATION_RANGE, NULL, 0);
-        AVDictionaryEntry *cues_start = av_dict_get(st->metadata, CUES_START, NULL, 0);
-        AVDictionaryEntry *cues_end = av_dict_get(st->metadata, CUES_END, NULL, 0);
-        AVDictionaryEntry *filename = av_dict_get(st->metadata, FILENAME, NULL, 0);
+        const AVDictionaryEntry *irange = av_dict_get(st->metadata, INITIALIZATION_RANGE, NULL, 0);
+        const AVDictionaryEntry *cues_start = av_dict_get(st->metadata, CUES_START, NULL, 0);
+        const AVDictionaryEntry *cues_end = av_dict_get(st->metadata, CUES_END, NULL, 0);
+        const AVDictionaryEntry *filename = av_dict_get(st->metadata, FILENAME, NULL, 0);
         if (!irange || !cues_start || !cues_end || !filename)
             return AVERROR(EINVAL);
 
@@ -307,7 +307,7 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
     AdaptationSet *as = &w->as[as_index];
     const AVStream *st = s->streams[as->streams[0]];
     AVCodecParameters *par = st->codecpar;
-    AVDictionaryEntry *lang;
+    const AVDictionaryEntry *lang;
     AVIOContext *pb = s->pb;
     int i;
     static const char boolean[2][6] = { "false", "true" };
@@ -347,15 +347,15 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
                 boolean[w->is_live || subsegment_alignment(s, as)]);
 
     for (i = 0; i < as->nb_streams; i++) {
-        AVDictionaryEntry *kf = av_dict_get(s->streams[as->streams[i]]->metadata,
-                                            CLUSTER_KEYFRAME, NULL, 0);
+        const AVDictionaryEntry *kf = av_dict_get(s->streams[as->streams[i]]->metadata,
+                                                  CLUSTER_KEYFRAME, NULL, 0);
         if (!w->is_live && (!kf || !strncmp(kf->value, "0", 1))) subsegmentStartsWithSAP = 0;
     }
     avio_printf(pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP);
     avio_printf(pb, ">\n");
 
     if (w->is_live) {
-        AVDictionaryEntry *filename =
+        const AVDictionaryEntry *filename =
             av_dict_get(st->metadata, FILENAME, NULL, 0);
         char *underscore_pos, *period_pos;
         int ret;
@@ -383,7 +383,7 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
         AVStream *st = s->streams[as->streams[i]];
         int ret;
         if (w->is_live) {
-            AVDictionaryEntry *filename =
+            const AVDictionaryEntry *filename =
                 av_dict_get(st->metadata, FILENAME, NULL, 0);
             if (!filename)
                 return AVERROR(EINVAL);
diff --git a/libavutil/dict.c b/libavutil/dict.c
index ac41771994..ca5026905c 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -57,6 +57,9 @@ const AVDictionaryEntry *av_dict_iterate(const AVDictionary *m,
     return &m->elems[i];
 }
 
+#if !FF_API_AV_DICT_GET_NOT_CONST
+const
+#endif
 AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
                                const AVDictionaryEntry *prev, int flags)
 {
@@ -78,7 +81,11 @@ AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
             continue;
         if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
             continue;
+        #if FF_API_AV_DICT_GET_NOT_CONST
         return (AVDictionaryEntry *)entry;
+        #else
+        return entry;
+        #endif
     }
     return NULL;
 }
@@ -100,7 +107,7 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value,
         goto err_out;
     }
     if (!(flags & AV_DICT_MULTIKEY)) {
-        tag = av_dict_get(m, key, NULL, flags);
+        tag = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
     }
     if (flags & AV_DICT_DONT_STRDUP_KEY)
         copy_key = (void *)key;
diff --git a/libavutil/dict.h b/libavutil/dict.h
index b2ab55a026..984c12311b 100644
--- a/libavutil/dict.h
+++ b/libavutil/dict.h
@@ -32,6 +32,8 @@
 
 #include <stdint.h>
 
+#include "version.h"
+
 /**
  * @addtogroup lavu_dict AVDictionary
  * @ingroup lavu_data
@@ -107,6 +109,9 @@ typedef struct AVDictionary AVDictionary;
  *
  * @return      Found entry or NULL in case no matching entry was found in the dictionary
  */
+#if !FF_API_AV_DICT_GET_NOT_CONST
+const
+#endif
 AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
                                const AVDictionaryEntry *prev, int flags);
 
diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c
index 5ae7711c94..ed698aa6f7 100644
--- a/libavutil/hwcontext_cuda.c
+++ b/libavutil/hwcontext_cuda.c
@@ -379,7 +379,7 @@ static int cuda_context_init(AVHWDeviceContext *device_ctx, int flags) {
 static int cuda_flags_from_opts(AVHWDeviceContext *device_ctx,
                                 AVDictionary *opts, int *flags)
 {
-    AVDictionaryEntry *primary_ctx_opt = av_dict_get(opts, "primary_ctx", NULL, 0);
+    const AVDictionaryEntry *primary_ctx_opt = av_dict_get(opts, "primary_ctx", NULL, 0);
 
     if (primary_ctx_opt && strtol(primary_ctx_opt->value, NULL, 10)) {
         av_log(device_ctx, AV_LOG_VERBOSE, "Using CUDA primary device context\n");
diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index 6780428875..a00bec89ec 100644
--- a/libavutil/hwcontext_qsv.c
+++ b/libavutil/hwcontext_qsv.c
@@ -2106,7 +2106,7 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
     enum AVHWDeviceType child_device_type;
     AVHWDeviceContext *child_device;
     AVDictionary *child_device_opts;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
 
     mfxIMPL impl;
     int ret;
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index ffd4f5dec4..f3429fc39f 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -438,7 +438,7 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts,
     int optional_exts_num;
     uint32_t sup_ext_count;
     char *user_exts_str = NULL;
-    AVDictionaryEntry *user_exts;
+    const AVDictionaryEntry *user_exts;
     VkExtensionProperties *sup_ext;
     const VulkanOptExtension *optional_exts;
 
@@ -566,14 +566,14 @@ static int check_validation_layers(AVHWDeviceContext *ctx, AVDictionary *opts,
     uint32_t sup_layer_count;
     VkLayerProperties *sup_layers;
 
-    AVDictionaryEntry *user_layers;
+    const AVDictionaryEntry *user_layers;
     char *user_layers_str = NULL;
     char *save, *token;
 
     const char **enabled_layers = NULL;
     uint32_t enabled_layers_count = 0;
 
-    AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0);
+    const AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0);
     int debug = debug_opt && strtol(debug_opt->value, NULL, 10);
 
     /* If `debug=0`, enable no layers at all. */
@@ -1313,7 +1313,7 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx,
 {
     int err = 0;
     VkResult ret;
-    AVDictionaryEntry *opt_d;
+    const AVDictionaryEntry *opt_d;
     VulkanDevicePriv *p = ctx->internal->priv;
     FFVulkanFunctions *vk = &p->vkfn;
     AVVulkanDeviceContext *hwctx = ctx->hwctx;
diff --git a/libavutil/version.h b/libavutil/version.h
index b8d1ef06a8..31c0403466 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -115,6 +115,7 @@
 #define FF_API_FRAME_PICTURE_NUMBER     (LIBAVUTIL_VERSION_MAJOR < 59)
 #define FF_API_HDR_VIVID_THREE_SPLINE   (LIBAVUTIL_VERSION_MAJOR < 59)
 #define FF_API_FRAME_PKT                (LIBAVUTIL_VERSION_MAJOR < 59)
+#define FF_API_AV_DICT_GET_NOT_CONST    (LIBAVUTIL_VERSION_MAJOR < 59)
 
 /**
  * @}
diff --git a/tests/api/api-threadmessage-test.c b/tests/api/api-threadmessage-test.c
index c96b473c43..c37c081249 100644
--- a/tests/api/api-threadmessage-test.c
+++ b/tests/api/api-threadmessage-test.c
@@ -137,7 +137,7 @@ static void *receiver_thread(void *arg)
         } else {
             struct message msg;
             AVDictionary *meta;
-            AVDictionaryEntry *e;
+            const AVDictionaryEntry *e;
 
             ret = av_thread_message_queue_recv(rd->queue, &msg, 0);
             if (ret < 0)
-- 
2.37.0 (Apple Git-136)

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-01 11:44 [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Marvin Scholz
  2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 2/3] avformat/tee: use av_dict_pop Marvin Scholz
  2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 3/3] avutil/dict: constify av_dict_get return Marvin Scholz
@ 2023-05-21 23:52 ` Stefano Sabatini
  2023-05-22  9:23   ` Marvin Scholz
  2023-06-05 10:04 ` Anton Khirnov
  2023-06-25 10:49 ` [FFmpeg-devel] [PATCH v2 " Marvin Scholz
  4 siblings, 1 reply; 32+ messages in thread
From: Stefano Sabatini @ 2023-05-21 23:52 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On date Monday 2023-05-01 13:44:54 +0200, Marvin Scholz wrote:
> This new API allows to remove an entry and obtain ownership of the
> key/value that was associated with the removed entry.
> ---
>  doc/APIchanges         |  4 ++++
>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>  libavutil/dict.h       | 20 ++++++++++++++++++++
>  libavutil/tests/dict.c | 34 ++++++++++++++++++++++++++++++++++
>  libavutil/version.h    |  2 +-
>  tests/ref/fate/dict    | 12 ++++++++++++
>  6 files changed, 98 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 0b609e3d3b..5b807873b7 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>  
>  API changes, most recent first:
>  
> +2023-04-29 - xxxxxxxxxx - lavu 58.7.100 - dict.c
> +  Add av_dict_pop() to remove an entry from a dict
> +  and get ownership of the removed key/value.
> +
>  2023-04-10 - xxxxxxxxxx - lavu 58.6.100 - frame.h
>    av_frame_get_plane_buffer() now accepts const AVFrame*.
>  
> diff --git a/libavutil/dict.c b/libavutil/dict.c
> index f673977a98..ac41771994 100644
> --- a/libavutil/dict.c
> +++ b/libavutil/dict.c
> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>      return av_dict_set(pm, key, valuestr, flags);
>  }
>  
> +int av_dict_pop(AVDictionary **pm, const char *key,
> +                char **out_key, char **out_value, int flags)
> +{
> +    AVDictionary *m = *pm;
> +    AVDictionaryEntry *entry = NULL;
> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
> +    if (!entry)
> +        return AVERROR(ENOENT);
> +
> +    if (out_key)
> +        *out_key = entry->key;
> +    else
> +        av_free(entry->key);
> +
> +    if (out_value)
> +        *out_value = entry->value;
> +    else
> +        av_free(entry->value);
> +
> +    *entry = m->elems[--m->count];

> +    if (m && !m->count) {
> +        av_freep(&m->elems);
> +        av_freep(pm);
> +    }

I'm not sure this is the right behavior. Should we clear the
dictionary when it is empty? What if you need to refill it later?

> +    return 0;
> +}
> +
>  static int parse_key_value_pair(AVDictionary **pm, const char **buf,
>                                  const char *key_val_sep, const char *pairs_sep,
>                                  int flags)
> diff --git a/libavutil/dict.h b/libavutil/dict.h
> index 713c9e361a..b2ab55a026 100644
> --- a/libavutil/dict.h
> +++ b/libavutil/dict.h
> @@ -172,6 +172,26 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>   */
>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>  
> +/**
> + * Remove the entry with the given key from the dictionary.
> + *

> + * Search for an entry matching `key` and remove it, if found. Optionally

Not sure the `foo` syntax is supported by doxygen (and probably we
should eschew it for consistency with the other doxys).

> + * the found key and/or value can be returned using the `out_key`/`out_value`
> + * arguments.

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-21 23:52 ` [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Stefano Sabatini
@ 2023-05-22  9:23   ` Marvin Scholz
  2023-05-26  6:05     ` Stefano Sabatini
  0 siblings, 1 reply; 32+ messages in thread
From: Marvin Scholz @ 2023-05-22  9:23 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



On 22 May 2023, at 1:52, Stefano Sabatini wrote:

> On date Monday 2023-05-01 13:44:54 +0200, Marvin Scholz wrote:
>> This new API allows to remove an entry and obtain ownership of the
>> key/value that was associated with the removed entry.

Thanks for the review!

>> ---
>>  doc/APIchanges         |  4 ++++
>>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>>  libavutil/dict.h       | 20 ++++++++++++++++++++
>>  libavutil/tests/dict.c | 34 ++++++++++++++++++++++++++++++++++
>>  libavutil/version.h    |  2 +-
>>  tests/ref/fate/dict    | 12 ++++++++++++
>>  6 files changed, 98 insertions(+), 1 deletion(-)
>>
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index 0b609e3d3b..5b807873b7 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>>
>>  API changes, most recent first:
>>
>> +2023-04-29 - xxxxxxxxxx - lavu 58.7.100 - dict.c
>> +  Add av_dict_pop() to remove an entry from a dict
>> +  and get ownership of the removed key/value.
>> +
>>  2023-04-10 - xxxxxxxxxx - lavu 58.6.100 - frame.h
>>    av_frame_get_plane_buffer() now accepts const AVFrame*.
>>
>> diff --git a/libavutil/dict.c b/libavutil/dict.c
>> index f673977a98..ac41771994 100644
>> --- a/libavutil/dict.c
>> +++ b/libavutil/dict.c
>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>>      return av_dict_set(pm, key, valuestr, flags);
>>  }
>>
>> +int av_dict_pop(AVDictionary **pm, const char *key,
>> +                char **out_key, char **out_value, int flags)
>> +{
>> +    AVDictionary *m = *pm;
>> +    AVDictionaryEntry *entry = NULL;
>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
>> +    if (!entry)
>> +        return AVERROR(ENOENT);
>> +
>> +    if (out_key)
>> +        *out_key = entry->key;
>> +    else
>> +        av_free(entry->key);
>> +
>> +    if (out_value)
>> +        *out_value = entry->value;
>> +    else
>> +        av_free(entry->value);
>> +
>> +    *entry = m->elems[--m->count];
>
>> +    if (m && !m->count) {
>> +        av_freep(&m->elems);
>> +        av_freep(pm);
>> +    }
>
> I'm not sure this is the right behavior. Should we clear the
> dictionary when it is empty? What if you need to refill it later?
>

Thats the same behaviour as if you use av_dict_set to remove all items
and IMO this should be consistent.
Additionally NULL means an empty AVDictionary, suddenly
having a non-NULL but empty dictionary seems like a very bad idea.

>> +    return 0;
>> +}
>> +
>>  static int parse_key_value_pair(AVDictionary **pm, const char **buf,
>>                                  const char *key_val_sep, const char *pairs_sep,
>>                                  int flags)
>> diff --git a/libavutil/dict.h b/libavutil/dict.h
>> index 713c9e361a..b2ab55a026 100644
>> --- a/libavutil/dict.h
>> +++ b/libavutil/dict.h
>> @@ -172,6 +172,26 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>>   */
>>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>>
>> +/**
>> + * Remove the entry with the given key from the dictionary.
>> + *
>
>> + * Search for an entry matching `key` and remove it, if found. Optionally
>
> Not sure the `foo` syntax is supported by doxygen (and probably we
> should eschew it for consistency with the other doxys).
>

I tested it locally and it works fine and its much more readable than the
alternatives.

However if you feel it should be removed I am happy to do that, I have no
strong opinions there.

>> + * the found key and/or value can be returned using the `out_key`/`out_value`
>> + * arguments.
>
> _______________________________________________
> 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".
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-22  9:23   ` Marvin Scholz
@ 2023-05-26  6:05     ` Stefano Sabatini
  2023-05-26  9:11       ` Marvin Scholz
  0 siblings, 1 reply; 32+ messages in thread
From: Stefano Sabatini @ 2023-05-26  6:05 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On date Monday 2023-05-22 11:23:24 +0200, Marvin Scholz wrote:
> On 22 May 2023, at 1:52, Stefano Sabatini wrote:
> 
> > On date Monday 2023-05-01 13:44:54 +0200, Marvin Scholz wrote:
> >> This new API allows to remove an entry and obtain ownership of the
> >> key/value that was associated with the removed entry.
> 
> Thanks for the review!
> 
> >> ---
> >>  doc/APIchanges         |  4 ++++
> >>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
> >>  libavutil/dict.h       | 20 ++++++++++++++++++++
> >>  libavutil/tests/dict.c | 34 ++++++++++++++++++++++++++++++++++
> >>  libavutil/version.h    |  2 +-
> >>  tests/ref/fate/dict    | 12 ++++++++++++
> >>  6 files changed, 98 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/doc/APIchanges b/doc/APIchanges
> >> index 0b609e3d3b..5b807873b7 100644
> >> --- a/doc/APIchanges
> >> +++ b/doc/APIchanges
> >> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
> >>
> >>  API changes, most recent first:
> >>
> >> +2023-04-29 - xxxxxxxxxx - lavu 58.7.100 - dict.c
> >> +  Add av_dict_pop() to remove an entry from a dict
> >> +  and get ownership of the removed key/value.
> >> +
> >>  2023-04-10 - xxxxxxxxxx - lavu 58.6.100 - frame.h
> >>    av_frame_get_plane_buffer() now accepts const AVFrame*.
> >>
> >> diff --git a/libavutil/dict.c b/libavutil/dict.c
> >> index f673977a98..ac41771994 100644
> >> --- a/libavutil/dict.c
> >> +++ b/libavutil/dict.c
> >> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
> >>      return av_dict_set(pm, key, valuestr, flags);
> >>  }
> >>
> >> +int av_dict_pop(AVDictionary **pm, const char *key,
> >> +                char **out_key, char **out_value, int flags)
> >> +{
> >> +    AVDictionary *m = *pm;
> >> +    AVDictionaryEntry *entry = NULL;
> >> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
> >> +    if (!entry)
> >> +        return AVERROR(ENOENT);
> >> +
> >> +    if (out_key)
> >> +        *out_key = entry->key;
> >> +    else
> >> +        av_free(entry->key);
> >> +
> >> +    if (out_value)
> >> +        *out_value = entry->value;
> >> +    else
> >> +        av_free(entry->value);
> >> +
> >> +    *entry = m->elems[--m->count];
> >
> >> +    if (m && !m->count) {
> >> +        av_freep(&m->elems);
> >> +        av_freep(pm);
> >> +    }
> >
> > I'm not sure this is the right behavior. Should we clear the
> > dictionary when it is empty? What if you need to refill it later?
> >
> 

> Thats the same behaviour as if you use av_dict_set to remove all items
> and IMO this should be consistent.

> Additionally NULL means an empty AVDictionary, suddenly
> having a non-NULL but empty dictionary seems like a very bad idea.

Sorry for the slow reply, I see.

[...]
> >> +/**
> >> + * Remove the entry with the given key from the dictionary.
> >> + *
> >
> >> + * Search for an entry matching `key` and remove it, if found. Optionally
> >
> > Not sure the `foo` syntax is supported by doxygen (and probably we
> > should eschew it for consistency with the other doxys).
> >
> 
> I tested it locally and it works fine and its much more readable than the
> alternatives.
> 
> However if you feel it should be removed I am happy to do that, I have no
> strong opinions there.

Please let's avoid to add more syntax variance (also I'm not sure when
the `var` syntax was introduced).

[...]

Should we also support the case with multiple same-key values?

Also maybe we should mention that this operation might alterate the
order of the entries (unless we add a new flag to shift the
trailing data when an entry is removed).

Another general question, since I see that dict.h is deprecated, do
you think it might be possible to switch to tree.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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-26  6:05     ` Stefano Sabatini
@ 2023-05-26  9:11       ` Marvin Scholz
  2023-05-26 20:02         ` Michael Niedermayer
                           ` (2 more replies)
  0 siblings, 3 replies; 32+ messages in thread
From: Marvin Scholz @ 2023-05-26  9:11 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



On 26 May 2023, at 8:05, Stefano Sabatini wrote:

> On date Monday 2023-05-22 11:23:24 +0200, Marvin Scholz wrote:
>> On 22 May 2023, at 1:52, Stefano Sabatini wrote:
>>
>>> On date Monday 2023-05-01 13:44:54 +0200, Marvin Scholz wrote:
>>>> This new API allows to remove an entry and obtain ownership of the
>>>> key/value that was associated with the removed entry.
>>
>> Thanks for the review!
>>
>>>> ---
>>>>  doc/APIchanges         |  4 ++++
>>>>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>>>>  libavutil/dict.h       | 20 ++++++++++++++++++++
>>>>  libavutil/tests/dict.c | 34 ++++++++++++++++++++++++++++++++++
>>>>  libavutil/version.h    |  2 +-
>>>>  tests/ref/fate/dict    | 12 ++++++++++++
>>>>  6 files changed, 98 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/doc/APIchanges b/doc/APIchanges
>>>> index 0b609e3d3b..5b807873b7 100644
>>>> --- a/doc/APIchanges
>>>> +++ b/doc/APIchanges
>>>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>>>>
>>>>  API changes, most recent first:
>>>>
>>>> +2023-04-29 - xxxxxxxxxx - lavu 58.7.100 - dict.c
>>>> +  Add av_dict_pop() to remove an entry from a dict
>>>> +  and get ownership of the removed key/value.
>>>> +
>>>>  2023-04-10 - xxxxxxxxxx - lavu 58.6.100 - frame.h
>>>>    av_frame_get_plane_buffer() now accepts const AVFrame*.
>>>>
>>>> diff --git a/libavutil/dict.c b/libavutil/dict.c
>>>> index f673977a98..ac41771994 100644
>>>> --- a/libavutil/dict.c
>>>> +++ b/libavutil/dict.c
>>>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>>>>      return av_dict_set(pm, key, valuestr, flags);
>>>>  }
>>>>
>>>> +int av_dict_pop(AVDictionary **pm, const char *key,
>>>> +                char **out_key, char **out_value, int flags)
>>>> +{
>>>> +    AVDictionary *m = *pm;
>>>> +    AVDictionaryEntry *entry = NULL;
>>>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
>>>> +    if (!entry)
>>>> +        return AVERROR(ENOENT);
>>>> +
>>>> +    if (out_key)
>>>> +        *out_key = entry->key;
>>>> +    else
>>>> +        av_free(entry->key);
>>>> +
>>>> +    if (out_value)
>>>> +        *out_value = entry->value;
>>>> +    else
>>>> +        av_free(entry->value);
>>>> +
>>>> +    *entry = m->elems[--m->count];
>>>
>>>> +    if (m && !m->count) {
>>>> +        av_freep(&m->elems);
>>>> +        av_freep(pm);
>>>> +    }
>>>
>>> I'm not sure this is the right behavior. Should we clear the
>>> dictionary when it is empty? What if you need to refill it later?
>>>
>>
>
>> Thats the same behaviour as if you use av_dict_set to remove all items
>> and IMO this should be consistent.
>
>> Additionally NULL means an empty AVDictionary, suddenly
>> having a non-NULL but empty dictionary seems like a very bad idea.
>
> Sorry for the slow reply, I see.
>
> [...]
>>>> +/**
>>>> + * Remove the entry with the given key from the dictionary.
>>>> + *
>>>
>>>> + * Search for an entry matching `key` and remove it, if found. Optionally
>>>
>>> Not sure the `foo` syntax is supported by doxygen (and probably we
>>> should eschew it for consistency with the other doxys).
>>>
>>
>> I tested it locally and it works fine and its much more readable than the
>> alternatives.
>>
>> However if you feel it should be removed I am happy to do that, I have no
>> strong opinions there.
>
> Please let's avoid to add more syntax variance (also I'm not sure when
> the `var` syntax was introduced).
>

Ok I will submit a new patch with it removed.

> [...]
>
> Should we also support the case with multiple same-key values?

I don't see what could be improved there. You just call it multiple times,
or what do you mean?

>
> Also maybe we should mention that this operation might alterate the
> order of the entries (unless we add a new flag to shift the
> trailing data when an entry is removed).

We currently IIRC nowhere give guarantees on the order of items in the
dict, which we probably should keep that way especially in regards to
your next point.

>
> Another general question, since I see that dict.h is deprecated, do
> you think it might be possible to switch to tree.h?

To internally use more efficient ways to handle entries would require
some big changes and lots of tests with all users to ensure they do not
rely on current undocumented behaviours like insertion order being preserved
in most cases…

Generally completely deprecating AVDictionary does not sound feasible at all
and the tree API is way too cumbersome and low-level right now to use it
as a replacement IMO.

> _______________________________________________
> 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".
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-26  9:11       ` Marvin Scholz
@ 2023-05-26 20:02         ` Michael Niedermayer
  2023-05-26 20:51           ` Marvin Scholz
  2023-05-26 20:06         ` James Almer
  2023-06-04 14:25         ` Stefano Sabatini
  2 siblings, 1 reply; 32+ messages in thread
From: Michael Niedermayer @ 2023-05-26 20:02 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 5721 bytes --]

On Fri, May 26, 2023 at 11:11:48AM +0200, Marvin Scholz wrote:
> 
> 
> On 26 May 2023, at 8:05, Stefano Sabatini wrote:
> 
> > On date Monday 2023-05-22 11:23:24 +0200, Marvin Scholz wrote:
> >> On 22 May 2023, at 1:52, Stefano Sabatini wrote:
> >>
> >>> On date Monday 2023-05-01 13:44:54 +0200, Marvin Scholz wrote:
> >>>> This new API allows to remove an entry and obtain ownership of the
> >>>> key/value that was associated with the removed entry.
> >>
> >> Thanks for the review!
> >>
> >>>> ---
> >>>>  doc/APIchanges         |  4 ++++
> >>>>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
> >>>>  libavutil/dict.h       | 20 ++++++++++++++++++++
> >>>>  libavutil/tests/dict.c | 34 ++++++++++++++++++++++++++++++++++
> >>>>  libavutil/version.h    |  2 +-
> >>>>  tests/ref/fate/dict    | 12 ++++++++++++
> >>>>  6 files changed, 98 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/doc/APIchanges b/doc/APIchanges
> >>>> index 0b609e3d3b..5b807873b7 100644
> >>>> --- a/doc/APIchanges
> >>>> +++ b/doc/APIchanges
> >>>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
> >>>>
> >>>>  API changes, most recent first:
> >>>>
> >>>> +2023-04-29 - xxxxxxxxxx - lavu 58.7.100 - dict.c
> >>>> +  Add av_dict_pop() to remove an entry from a dict
> >>>> +  and get ownership of the removed key/value.
> >>>> +
> >>>>  2023-04-10 - xxxxxxxxxx - lavu 58.6.100 - frame.h
> >>>>    av_frame_get_plane_buffer() now accepts const AVFrame*.
> >>>>
> >>>> diff --git a/libavutil/dict.c b/libavutil/dict.c
> >>>> index f673977a98..ac41771994 100644
> >>>> --- a/libavutil/dict.c
> >>>> +++ b/libavutil/dict.c
> >>>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
> >>>>      return av_dict_set(pm, key, valuestr, flags);
> >>>>  }
> >>>>
> >>>> +int av_dict_pop(AVDictionary **pm, const char *key,
> >>>> +                char **out_key, char **out_value, int flags)
> >>>> +{
> >>>> +    AVDictionary *m = *pm;
> >>>> +    AVDictionaryEntry *entry = NULL;
> >>>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
> >>>> +    if (!entry)
> >>>> +        return AVERROR(ENOENT);
> >>>> +
> >>>> +    if (out_key)
> >>>> +        *out_key = entry->key;
> >>>> +    else
> >>>> +        av_free(entry->key);
> >>>> +
> >>>> +    if (out_value)
> >>>> +        *out_value = entry->value;
> >>>> +    else
> >>>> +        av_free(entry->value);
> >>>> +
> >>>> +    *entry = m->elems[--m->count];
> >>>
> >>>> +    if (m && !m->count) {
> >>>> +        av_freep(&m->elems);
> >>>> +        av_freep(pm);
> >>>> +    }
> >>>
> >>> I'm not sure this is the right behavior. Should we clear the
> >>> dictionary when it is empty? What if you need to refill it later?
> >>>
> >>
> >
> >> Thats the same behaviour as if you use av_dict_set to remove all items
> >> and IMO this should be consistent.
> >
> >> Additionally NULL means an empty AVDictionary, suddenly
> >> having a non-NULL but empty dictionary seems like a very bad idea.
> >
> > Sorry for the slow reply, I see.
> >
> > [...]
> >>>> +/**
> >>>> + * Remove the entry with the given key from the dictionary.
> >>>> + *
> >>>
> >>>> + * Search for an entry matching `key` and remove it, if found. Optionally
> >>>
> >>> Not sure the `foo` syntax is supported by doxygen (and probably we
> >>> should eschew it for consistency with the other doxys).
> >>>
> >>
> >> I tested it locally and it works fine and its much more readable than the
> >> alternatives.
> >>
> >> However if you feel it should be removed I am happy to do that, I have no
> >> strong opinions there.
> >
> > Please let's avoid to add more syntax variance (also I'm not sure when
> > the `var` syntax was introduced).
> >
> 
> Ok I will submit a new patch with it removed.
> 
> > [...]
> >
> > Should we also support the case with multiple same-key values?
> 
> I don't see what could be improved there. You just call it multiple times,
> or what do you mean?
> 
> >
> > Also maybe we should mention that this operation might alterate the
> > order of the entries (unless we add a new flag to shift the
> > trailing data when an entry is removed).
> 
> We currently IIRC nowhere give guarantees on the order of items in the
> dict, which we probably should keep that way especially in regards to
> your next point.
> 

> >
> > Another general question, since I see that dict.h is deprecated, do
> > you think it might be possible to switch to tree.h?
> 
> To internally use more efficient ways to handle entries would require
> some big changes

> and lots of tests with all users to ensure they do not
> rely on current undocumented behaviours like insertion order being preserved
> in most cases…

There is no gurantee on insertion order preservation. And even with the
current implementation any code depening on that is broken.
It may be a good idea to allow randomizing the order for fate tests though
independant of any change to AVDictionary


> 
> Generally completely deprecating AVDictionary does not sound feasible at all
> and the tree API is way too cumbersome and low-level right now to use it
> as a replacement IMO.

I think AVDictionary should be made to internally use something more efficient
like tree.c/h if possible.

Only if its not possible within the API of AVDictionary would a new API be
needed. That new API must be similarly easy to use as AVDictionary

thx

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

No snowflake in an avalanche ever feels responsible. -- Voltaire

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: 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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-26  9:11       ` Marvin Scholz
  2023-05-26 20:02         ` Michael Niedermayer
@ 2023-05-26 20:06         ` James Almer
  2023-06-04 14:25         ` Stefano Sabatini
  2 siblings, 0 replies; 32+ messages in thread
From: James Almer @ 2023-05-26 20:06 UTC (permalink / raw)
  To: ffmpeg-devel

On 5/26/2023 6:11 AM, Marvin Scholz wrote:
> 
> 
> On 26 May 2023, at 8:05, Stefano Sabatini wrote:
> 
>> On date Monday 2023-05-22 11:23:24 +0200, Marvin Scholz wrote:
>>> On 22 May 2023, at 1:52, Stefano Sabatini wrote:
>>>
>>>> On date Monday 2023-05-01 13:44:54 +0200, Marvin Scholz wrote:
>>>>> This new API allows to remove an entry and obtain ownership of the
>>>>> key/value that was associated with the removed entry.
>>>
>>> Thanks for the review!
>>>
>>>>> ---
>>>>>   doc/APIchanges         |  4 ++++
>>>>>   libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>>>>>   libavutil/dict.h       | 20 ++++++++++++++++++++
>>>>>   libavutil/tests/dict.c | 34 ++++++++++++++++++++++++++++++++++
>>>>>   libavutil/version.h    |  2 +-
>>>>>   tests/ref/fate/dict    | 12 ++++++++++++
>>>>>   6 files changed, 98 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/doc/APIchanges b/doc/APIchanges
>>>>> index 0b609e3d3b..5b807873b7 100644
>>>>> --- a/doc/APIchanges
>>>>> +++ b/doc/APIchanges
>>>>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>>>>>
>>>>>   API changes, most recent first:
>>>>>
>>>>> +2023-04-29 - xxxxxxxxxx - lavu 58.7.100 - dict.c
>>>>> +  Add av_dict_pop() to remove an entry from a dict
>>>>> +  and get ownership of the removed key/value.
>>>>> +
>>>>>   2023-04-10 - xxxxxxxxxx - lavu 58.6.100 - frame.h
>>>>>     av_frame_get_plane_buffer() now accepts const AVFrame*.
>>>>>
>>>>> diff --git a/libavutil/dict.c b/libavutil/dict.c
>>>>> index f673977a98..ac41771994 100644
>>>>> --- a/libavutil/dict.c
>>>>> +++ b/libavutil/dict.c
>>>>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>>>>>       return av_dict_set(pm, key, valuestr, flags);
>>>>>   }
>>>>>
>>>>> +int av_dict_pop(AVDictionary **pm, const char *key,
>>>>> +                char **out_key, char **out_value, int flags)
>>>>> +{
>>>>> +    AVDictionary *m = *pm;
>>>>> +    AVDictionaryEntry *entry = NULL;
>>>>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
>>>>> +    if (!entry)
>>>>> +        return AVERROR(ENOENT);
>>>>> +
>>>>> +    if (out_key)
>>>>> +        *out_key = entry->key;
>>>>> +    else
>>>>> +        av_free(entry->key);
>>>>> +
>>>>> +    if (out_value)
>>>>> +        *out_value = entry->value;
>>>>> +    else
>>>>> +        av_free(entry->value);
>>>>> +
>>>>> +    *entry = m->elems[--m->count];
>>>>
>>>>> +    if (m && !m->count) {
>>>>> +        av_freep(&m->elems);
>>>>> +        av_freep(pm);
>>>>> +    }
>>>>
>>>> I'm not sure this is the right behavior. Should we clear the
>>>> dictionary when it is empty? What if you need to refill it later?
>>>>
>>>
>>
>>> Thats the same behaviour as if you use av_dict_set to remove all items
>>> and IMO this should be consistent.
>>
>>> Additionally NULL means an empty AVDictionary, suddenly
>>> having a non-NULL but empty dictionary seems like a very bad idea.
>>
>> Sorry for the slow reply, I see.
>>
>> [...]
>>>>> +/**
>>>>> + * Remove the entry with the given key from the dictionary.
>>>>> + *
>>>>
>>>>> + * Search for an entry matching `key` and remove it, if found. Optionally
>>>>
>>>> Not sure the `foo` syntax is supported by doxygen (and probably we
>>>> should eschew it for consistency with the other doxys).
>>>>
>>>
>>> I tested it locally and it works fine and its much more readable than the
>>> alternatives.
>>>
>>> However if you feel it should be removed I am happy to do that, I have no
>>> strong opinions there.
>>
>> Please let's avoid to add more syntax variance (also I'm not sure when
>> the `var` syntax was introduced).
>>
> 
> Ok I will submit a new patch with it removed.
> 
>> [...]
>>
>> Should we also support the case with multiple same-key values?
> 
> I don't see what could be improved there. You just call it multiple times,
> or what do you mean?
> 
>>
>> Also maybe we should mention that this operation might alterate the
>> order of the entries (unless we add a new flag to shift the
>> trailing data when an entry is removed).
> 
> We currently IIRC nowhere give guarantees on the order of items in the
> dict, which we probably should keep that way especially in regards to
> your next point.
> 
>>
>> Another general question, since I see that dict.h is deprecated, do
>> you think it might be possible to switch to tree.h?
> 
> To internally use more efficient ways to handle entries would require
> some big changes and lots of tests with all users to ensure they do not
> rely on current undocumented behaviours like insertion order being preserved
> in most cases…
> 
> Generally completely deprecating AVDictionary does not sound feasible at all
> and the tree API is way too cumbersome and low-level right now to use it
> as a replacement IMO.

I found it pretty powerful and useful. It's currently used in the 
dts2pts bsf, and i wrote a dynamic size AVBufferPool implementation with 
it that was never upstreamed.
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-26 20:02         ` Michael Niedermayer
@ 2023-05-26 20:51           ` Marvin Scholz
  0 siblings, 0 replies; 32+ messages in thread
From: Marvin Scholz @ 2023-05-26 20:51 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



On 26 May 2023, at 22:02, Michael Niedermayer wrote:

> On Fri, May 26, 2023 at 11:11:48AM +0200, Marvin Scholz wrote:
>>
>>
>> On 26 May 2023, at 8:05, Stefano Sabatini wrote:
>>
>>> On date Monday 2023-05-22 11:23:24 +0200, Marvin Scholz wrote:
>>>> On 22 May 2023, at 1:52, Stefano Sabatini wrote:
>>>>
>>>>> On date Monday 2023-05-01 13:44:54 +0200, Marvin Scholz wrote:
>>>>>> This new API allows to remove an entry and obtain ownership of the
>>>>>> key/value that was associated with the removed entry.
>>>>
>>>> Thanks for the review!
>>>>
>>>>>> ---
>>>>>>  doc/APIchanges         |  4 ++++
>>>>>>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>>>>>>  libavutil/dict.h       | 20 ++++++++++++++++++++
>>>>>>  libavutil/tests/dict.c | 34 ++++++++++++++++++++++++++++++++++
>>>>>>  libavutil/version.h    |  2 +-
>>>>>>  tests/ref/fate/dict    | 12 ++++++++++++
>>>>>>  6 files changed, 98 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/doc/APIchanges b/doc/APIchanges
>>>>>> index 0b609e3d3b..5b807873b7 100644
>>>>>> --- a/doc/APIchanges
>>>>>> +++ b/doc/APIchanges
>>>>>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>>>>>>
>>>>>>  API changes, most recent first:
>>>>>>
>>>>>> +2023-04-29 - xxxxxxxxxx - lavu 58.7.100 - dict.c
>>>>>> +  Add av_dict_pop() to remove an entry from a dict
>>>>>> +  and get ownership of the removed key/value.
>>>>>> +
>>>>>>  2023-04-10 - xxxxxxxxxx - lavu 58.6.100 - frame.h
>>>>>>    av_frame_get_plane_buffer() now accepts const AVFrame*.
>>>>>>
>>>>>> diff --git a/libavutil/dict.c b/libavutil/dict.c
>>>>>> index f673977a98..ac41771994 100644
>>>>>> --- a/libavutil/dict.c
>>>>>> +++ b/libavutil/dict.c
>>>>>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>>>>>>      return av_dict_set(pm, key, valuestr, flags);
>>>>>>  }
>>>>>>
>>>>>> +int av_dict_pop(AVDictionary **pm, const char *key,
>>>>>> +                char **out_key, char **out_value, int flags)
>>>>>> +{
>>>>>> +    AVDictionary *m = *pm;
>>>>>> +    AVDictionaryEntry *entry = NULL;
>>>>>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
>>>>>> +    if (!entry)
>>>>>> +        return AVERROR(ENOENT);
>>>>>> +
>>>>>> +    if (out_key)
>>>>>> +        *out_key = entry->key;
>>>>>> +    else
>>>>>> +        av_free(entry->key);
>>>>>> +
>>>>>> +    if (out_value)
>>>>>> +        *out_value = entry->value;
>>>>>> +    else
>>>>>> +        av_free(entry->value);
>>>>>> +
>>>>>> +    *entry = m->elems[--m->count];
>>>>>
>>>>>> +    if (m && !m->count) {
>>>>>> +        av_freep(&m->elems);
>>>>>> +        av_freep(pm);
>>>>>> +    }
>>>>>
>>>>> I'm not sure this is the right behavior. Should we clear the
>>>>> dictionary when it is empty? What if you need to refill it later?
>>>>>
>>>>
>>>
>>>> Thats the same behaviour as if you use av_dict_set to remove all items
>>>> and IMO this should be consistent.
>>>
>>>> Additionally NULL means an empty AVDictionary, suddenly
>>>> having a non-NULL but empty dictionary seems like a very bad idea.
>>>
>>> Sorry for the slow reply, I see.
>>>
>>> [...]
>>>>>> +/**
>>>>>> + * Remove the entry with the given key from the dictionary.
>>>>>> + *
>>>>>
>>>>>> + * Search for an entry matching `key` and remove it, if found. Optionally
>>>>>
>>>>> Not sure the `foo` syntax is supported by doxygen (and probably we
>>>>> should eschew it for consistency with the other doxys).
>>>>>
>>>>
>>>> I tested it locally and it works fine and its much more readable than the
>>>> alternatives.
>>>>
>>>> However if you feel it should be removed I am happy to do that, I have no
>>>> strong opinions there.
>>>
>>> Please let's avoid to add more syntax variance (also I'm not sure when
>>> the `var` syntax was introduced).
>>>
>>
>> Ok I will submit a new patch with it removed.
>>
>>> [...]
>>>
>>> Should we also support the case with multiple same-key values?
>>
>> I don't see what could be improved there. You just call it multiple times,
>> or what do you mean?
>>
>>>
>>> Also maybe we should mention that this operation might alterate the
>>> order of the entries (unless we add a new flag to shift the
>>> trailing data when an entry is removed).
>>
>> We currently IIRC nowhere give guarantees on the order of items in the
>> dict, which we probably should keep that way especially in regards to
>> your next point.
>>
>
>>>
>>> Another general question, since I see that dict.h is deprecated, do
>>> you think it might be possible to switch to tree.h?
>>
>> To internally use more efficient ways to handle entries would require
>> some big changes
>
>> and lots of tests with all users to ensure they do not
>> rely on current undocumented behaviours like insertion order being preserved
>> in most cases…
>
> There is no gurantee on insertion order preservation. And even with the
> current implementation any code depening on that is broken.

Good to know

> It may be a good idea to allow randomizing the order for fate tests though
> independant of any change to AVDictionary
>

Good idea

>
>>
>> Generally completely deprecating AVDictionary does not sound feasible at all
>> and the tree API is way too cumbersome and low-level right now to use it
>> as a replacement IMO.
>
> I think AVDictionary should be made to internally use something more efficient
> like tree.c/h if possible.
>
> Only if its not possible within the API of AVDictionary would a new API be
> needed. That new API must be similarly easy to use as AVDictionary
>

I agree with that, I just meant it is not possible to replace usages of
AVDictionary with tree.h functions directly easily.

Regarding if all use-cases of AVDictionary can be covered if we use the
tree functions internally, I would probably need to discuss on IRC with
you.

Anyway though this discussion seems to derail a bit from the patch
at hand which is unrelated to a possible change of AVDictionary internals
in the future.

> thx
>
> [...]
> -- 
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> No snowflake in an avalanche ever feels responsible. -- Voltaire
> _______________________________________________
> 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".
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-26  9:11       ` Marvin Scholz
  2023-05-26 20:02         ` Michael Niedermayer
  2023-05-26 20:06         ` James Almer
@ 2023-06-04 14:25         ` Stefano Sabatini
  2023-06-04 14:34           ` Marvin Scholz
  2 siblings, 1 reply; 32+ messages in thread
From: Stefano Sabatini @ 2023-06-04 14:25 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On date Friday 2023-05-26 11:11:48 +0200, Marvin Scholz wrote:
> On 26 May 2023, at 8:05, Stefano Sabatini wrote:
> 
> > On date Monday 2023-05-22 11:23:24 +0200, Marvin Scholz wrote:
> >> On 22 May 2023, at 1:52, Stefano Sabatini wrote:
[...]
> > Should we also support the case with multiple same-key values?
> 
> I don't see what could be improved there. You just call it multiple times,
> or what do you mean?
> >

> > Also maybe we should mention that this operation might alterate the
> > order of the entries (unless we add a new flag to shift the
> > trailing data when an entry is removed).
> 

> We currently IIRC nowhere give guarantees on the order of items in the
> dict, which we probably should keep that way especially in regards to
> your next point.

OK, anyway this is pretty unrelated to the current patch (might be
done as a followup). I was checking the current documentation and it's
missing some important information (I'll try to send a patch to fix
that later).

[...]

About your patch, please mention that the pop operation is
destructive. We probably want to make that behavior configurable
through flags, but I'm fine to keep the current behavior for
consistency with the set(NULL) operation.

[...]

Thanks (sorry again for the slow reply).
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-06-04 14:25         ` Stefano Sabatini
@ 2023-06-04 14:34           ` Marvin Scholz
  2023-06-05  8:08             ` Stefano Sabatini
  0 siblings, 1 reply; 32+ messages in thread
From: Marvin Scholz @ 2023-06-04 14:34 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



On 4 Jun 2023, at 16:25, Stefano Sabatini wrote:

> On date Friday 2023-05-26 11:11:48 +0200, Marvin Scholz wrote:
>> On 26 May 2023, at 8:05, Stefano Sabatini wrote:
>>
>>> On date Monday 2023-05-22 11:23:24 +0200, Marvin Scholz wrote:
>>>> On 22 May 2023, at 1:52, Stefano Sabatini wrote:
> [...]
>>> Should we also support the case with multiple same-key values?
>>
>> I don't see what could be improved there. You just call it multiple times,
>> or what do you mean?
>>>
>
>>> Also maybe we should mention that this operation might alterate the
>>> order of the entries (unless we add a new flag to shift the
>>> trailing data when an entry is removed).
>>
>
>> We currently IIRC nowhere give guarantees on the order of items in the
>> dict, which we probably should keep that way especially in regards to
>> your next point.
>
> OK, anyway this is pretty unrelated to the current patch (might be
> done as a followup). I was checking the current documentation and it's
> missing some important information (I'll try to send a patch to fix
> that later).
>
> [...]
>
> About your patch, please mention that the pop operation is
> destructive. We probably want to make that behavior configurable
> through flags, but I'm fine to keep the current behavior for
> consistency with the set(NULL) operation.

What do you mean by "destructive"?

>
> [...]
>
> Thanks (sorry again for the slow reply).
> _______________________________________________
> 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".
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-06-04 14:34           ` Marvin Scholz
@ 2023-06-05  8:08             ` Stefano Sabatini
  2023-06-05 10:09               ` Anton Khirnov
  0 siblings, 1 reply; 32+ messages in thread
From: Stefano Sabatini @ 2023-06-05  8:08 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Il dom 4 giu 2023, 16:34 Marvin Scholz <epirat07@gmail.com> ha scritto:

> On 4 Jun 2023, at 16:25, Stefano Sabatini wrote:
> [...]
> > About your patch, please mention that the pop operation is
> > destructive. We probably want to make that behavior configurable
> > through flags, but I'm fine to keep the current behavior for
> > consistency with the set(NULL) operation.
>
> What do you mean by "destructive"?
>

 I mean that the dictionary structure will be freed when the last element
is popped.
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-05-01 11:44 [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Marvin Scholz
                   ` (2 preceding siblings ...)
  2023-05-21 23:52 ` [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Stefano Sabatini
@ 2023-06-05 10:04 ` Anton Khirnov
  2023-06-25 10:49 ` [FFmpeg-devel] [PATCH v2 " Marvin Scholz
  4 siblings, 0 replies; 32+ messages in thread
From: Anton Khirnov @ 2023-06-05 10:04 UTC (permalink / raw)
  To: FFmpeg development discussions and patches; +Cc: Marvin Scholz

Quoting Marvin Scholz (2023-05-01 13:44:54)
> diff --git a/libavutil/dict.h b/libavutil/dict.h
> index 713c9e361a..b2ab55a026 100644
> --- a/libavutil/dict.h
> +++ b/libavutil/dict.h
> @@ -172,6 +172,26 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>   */
>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>  
> +/**
> + * Remove the entry with the given key from the dictionary.
> + *
> + * Search for an entry matching `key` and remove it, if found. Optionally
> + * the found key and/or value can be returned using the `out_key`/`out_value`
> + * arguments.
> + *
> + * If more than one entry matches, only one entry is removed and returned
> + * on each call. Which entry is returned first in that case is undefined.
> + *
> + * @param pm        Pointer to a pointer to a dictionary struct.
> + * @param key       Entry key to match.
> + * @param out_key   Pointer whose pointee will be set to the matched
> + *                  entry key. Must be freed by the caller. May be NULL.
> + * @param out_value Pointer whose pointee will be set to the matched
> + *                  entry value. Must be freed by the caller. May be NULL.

freed using av_free()

Should also mention what the function's return value is.


> diff --git a/tests/ref/fate/dict b/tests/ref/fate/dict
> index 7205e4c845..bdb097cb03 100644
> --- a/tests/ref/fate/dict
> +++ b/tests/ref/fate/dict
> @@ -48,3 +48,15 @@ Testing av_dict_set_int()
>  Testing av_dict_set() with existing AVDictionaryEntry.key as key
>  new val OK
>  new val OK
> +
> +Testing av_dict_pop() with existing AVDictionaryEntry.key as key
> +test-key: test-value (Return code: 0)
> +(null)
> +
> +Testing av_dict_pop() with nonexistent key
> +(null): (null) (Return code: -2)

I don't think anything guarantees that ENOENT has to be -2 on all
platforms we support.

-- 
Anton Khirnov
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 3/3] avutil/dict: constify av_dict_get return
  2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 3/3] avutil/dict: constify av_dict_get return Marvin Scholz
@ 2023-06-05 10:05   ` Anton Khirnov
  0 siblings, 0 replies; 32+ messages in thread
From: Anton Khirnov @ 2023-06-05 10:05 UTC (permalink / raw)
  To: FFmpeg development discussions and patches; +Cc: Marvin Scholz

Quoting Marvin Scholz (2023-05-01 13:44:56)
> ---
>  doc/examples/qsv_transcode.c       |  2 +-
>  libavcodec/libaomenc.c             |  2 +-
>  libavcodec/libkvazaar.c            |  2 +-
>  libavcodec/libsvtav1.c             |  2 +-
>  libavcodec/libvpxenc.c             |  2 +-
>  libavcodec/libx264.c               |  2 +-
>  libavcodec/libx265.c               |  2 +-
>  libavcodec/mjpegdec.c              |  2 +-
>  libavcodec/qsvenc.c                |  2 +-
>  libavfilter/avfilter.c             |  2 +-
>  libavfilter/f_bench.c              |  2 +-
>  libavfilter/f_drawgraph.c          |  2 +-
>  libavfilter/f_select.c             |  4 +--
>  libavfilter/vf_cover_rect.c        |  2 +-
>  libavfilter/vf_drawtext.c          |  2 +-
>  libavformat/aiffenc.c              |  2 +-
>  libavformat/argo_asf.c             |  2 +-
>  libavformat/asfenc.c               |  6 ++--
>  libavformat/au.c                   |  2 +-
>  libavformat/avformat.h             |  2 +-
>  libavformat/avidec.c               |  2 +-
>  libavformat/avienc.c               |  2 +-
>  libavformat/avio.c                 |  4 +--
>  libavformat/dashenc.c              |  6 ++--
>  libavformat/dvenc.c                |  2 +-
>  libavformat/flacdec.c              |  2 +-
>  libavformat/flacenc.c              |  6 ++--
>  libavformat/flvdec.c               |  2 +-
>  libavformat/gxfenc.c               |  2 +-
>  libavformat/http.c                 |  8 +++---
>  libavformat/id3v2.c                |  6 ++--
>  libavformat/id3v2enc.c             |  2 +-
>  libavformat/imfdec.c               |  2 +-
>  libavformat/matroskadec.c          |  2 +-
>  libavformat/mov.c                  |  6 ++--
>  libavformat/movenc.c               | 46 +++++++++++++++---------------
>  libavformat/mp3enc.c               |  6 ++--
>  libavformat/mpegtsenc.c            |  6 ++--
>  libavformat/mux.c                  |  2 +-
>  libavformat/mux_utils.c            |  2 +-
>  libavformat/mxfenc.c               | 14 ++++-----
>  libavformat/riffenc.c              |  2 +-
>  libavformat/rmenc.c                |  2 +-
>  libavformat/sapenc.c               |  2 +-
>  libavformat/sdp.c                  |  2 +-
>  libavformat/segment.c              |  4 +--
>  libavformat/soxenc.c               |  2 +-
>  libavformat/tee.c                  |  2 +-
>  libavformat/ttmlenc.c              |  4 +--
>  libavformat/wavenc.c               |  4 +--
>  libavformat/webmdashenc.c          | 30 +++++++++----------
>  libavutil/dict.c                   |  9 +++++-
>  libavutil/dict.h                   |  5 ++++
>  libavutil/hwcontext_cuda.c         |  2 +-
>  libavutil/hwcontext_qsv.c          |  2 +-
>  libavutil/hwcontext_vulkan.c       |  8 +++---
>  libavutil/version.h                |  1 +
>  tests/api/api-threadmessage-test.c |  2 +-
>  58 files changed, 136 insertions(+), 123 deletions(-)

IMO this is an API break, and so should be postponed until the next
major bump.

-- 
Anton Khirnov
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop
  2023-06-05  8:08             ` Stefano Sabatini
@ 2023-06-05 10:09               ` Anton Khirnov
  0 siblings, 0 replies; 32+ messages in thread
From: Anton Khirnov @ 2023-06-05 10:09 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Quoting Stefano Sabatini (2023-06-05 10:08:07)
> Il dom 4 giu 2023, 16:34 Marvin Scholz <epirat07@gmail.com> ha scritto:
> 
> > On 4 Jun 2023, at 16:25, Stefano Sabatini wrote:
> > [...]
> > > About your patch, please mention that the pop operation is
> > > destructive. We probably want to make that behavior configurable
> > > through flags, but I'm fine to keep the current behavior for
> > > consistency with the set(NULL) operation.
> >
> > What do you mean by "destructive"?
> >
> 
>  I mean that the dictionary structure will be freed when the last element
> is popped.

It is explicitly mentioned in the documentation that NULL is a valid
representation of an empty dictionary, so I don't think there's anything
destructive here.

-- 
Anton Khirnov
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-05-01 11:44 [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Marvin Scholz
                   ` (3 preceding siblings ...)
  2023-06-05 10:04 ` Anton Khirnov
@ 2023-06-25 10:49 ` Marvin Scholz
  2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 2/3] avformat/tee: use av_dict_pop Marvin Scholz
                     ` (3 more replies)
  4 siblings, 4 replies; 32+ messages in thread
From: Marvin Scholz @ 2023-06-25 10:49 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marvin Scholz

This new API allows to remove an entry and obtain ownership of the
key/value that was associated with the removed entry.
---

Changes since v1:
- Clarify documentation about av_free having to be used.
- Fix fate test to not rely on specific error code value

 doc/APIchanges         |  4 ++++
 libavutil/dict.c       | 27 +++++++++++++++++++++++++++
 libavutil/dict.h       | 26 ++++++++++++++++++++++++++
 libavutil/tests/dict.c | 38 ++++++++++++++++++++++++++++++++++++++
 libavutil/version.h    |  4 ++--
 tests/ref/fate/dict    | 12 ++++++++++++
 6 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index f040211f7d..d55821f682 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
 
 API changes, most recent first:
 
+2023-06-02 - xxxxxxxxxx - lavu 58.14.100 - dict.h
+  Add av_dict_pop() to remove an entry from a dict
+  and get ownership of the removed key/value.
+
 2023-05-29 - xxxxxxxxxx - lavc 60.16.100 - avcodec.h codec_id.h
   Add AV_CODEC_ID_EVC, FF_PROFILE_EVC_BASELINE, and FF_PROFILE_EVC_MAIN.
 
diff --git a/libavutil/dict.c b/libavutil/dict.c
index f673977a98..ac41771994 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
     return av_dict_set(pm, key, valuestr, flags);
 }
 
+int av_dict_pop(AVDictionary **pm, const char *key,
+                char **out_key, char **out_value, int flags)
+{
+    AVDictionary *m = *pm;
+    AVDictionaryEntry *entry = NULL;
+    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
+    if (!entry)
+        return AVERROR(ENOENT);
+
+    if (out_key)
+        *out_key = entry->key;
+    else
+        av_free(entry->key);
+
+    if (out_value)
+        *out_value = entry->value;
+    else
+        av_free(entry->value);
+
+    *entry = m->elems[--m->count];
+    if (m && !m->count) {
+        av_freep(&m->elems);
+        av_freep(pm);
+    }
+    return 0;
+}
+
 static int parse_key_value_pair(AVDictionary **pm, const char **buf,
                                 const char *key_val_sep, const char *pairs_sep,
                                 int flags)
diff --git a/libavutil/dict.h b/libavutil/dict.h
index 713c9e361a..31d38dabec 100644
--- a/libavutil/dict.h
+++ b/libavutil/dict.h
@@ -172,6 +172,32 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
  */
 int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
 
+/**
+ * Remove the entry with the given key from the dictionary.
+ *
+ * Search for an entry matching @p key and remove it, if found. Optionally
+ * the found key and/or value can be returned using the @p out_key and
+ * @p out_value arguments.
+ *
+ * If more than one entry matches, only one entry is removed and returned
+ * on each call. Which entry is returned first in that case is undefined.
+ *
+ * @param pm        Pointer to a pointer to a dictionary struct.
+ * @param key       Entry key to match.
+ * @param out_key   Pointer whose pointee will be set to the matched
+ *                  entry key. Must be freed using av_dict_free() by
+ *                  the caller. May be NULL.
+ * @param out_value Pointer whose pointee will be set to the matched
+ *                  entry value. Must be freed using av_dict_free() by
+ *                  the caller. May be NULL.
+ *
+ * @retval 0                            Success
+ * @retval AVERROR(ENOENT)              No item for the given key found
+ * @retval "Other (negative) AVERROR"   Other failure
+ */
+int av_dict_pop(AVDictionary **pm, const char *key,
+                char **out_key, char **out_value, int flags);
+
 /**
  * Parse the key/value pairs list and add the parsed entries to a dictionary.
  *
diff --git a/libavutil/tests/dict.c b/libavutil/tests/dict.c
index bececefb31..06d94ecc9a 100644
--- a/libavutil/tests/dict.c
+++ b/libavutil/tests/dict.c
@@ -158,5 +158,43 @@ int main(void)
     printf("%s\n", e->value);
     av_dict_free(&dict);
 
+    char *key, *val = NULL;
+    int ret;
+    printf("\nTesting av_dict_pop() with existing AVDictionaryEntry.key as key\n");
+    av_dict_set(&dict, "test-key", "test-value", 0);
+    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
+    printf("%s: %s (Return code: %i)\n",
+        (key) ? key : "(null)",
+        (val) ? val : "(null)", ret);
+    e = av_dict_get(dict, "test-key", NULL, 0);
+    printf("%s\n", (e) ? e->value : "(null)");
+    av_freep(&key);
+    av_freep(&val);
+
+    printf("\nTesting av_dict_pop() with nonexistent key\n");
+    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
+    printf("%s: %s ",
+        (key) ? key : "(null)",
+        (val) ? val : "(null)");
+    if (ret == AVERROR(ENOENT))
+        printf("(Return code: ENOENT)\n");
+    else
+        printf("(Return code: Unexpected error: %i)\n", ret);
+    e = av_dict_get(dict, "test-key", NULL, 0);
+    printf("%s\n", (e) ? e->value : "(null)");
+    av_freep(&key);
+    av_freep(&val);
+
+    printf("\nTesting av_dict_pop() with prefix key match\n");
+    av_dict_set(&dict, "prefix-test-key", "test-value", 0);
+    ret = av_dict_pop(&dict, "prefix-test", &key, &val, AV_DICT_IGNORE_SUFFIX);
+    printf("%s: %s (Return code: %i)\n",
+        (key) ? key : "(null)",
+        (val) ? val : "(null)", ret);
+    e = av_dict_get(dict, "prefix-test", NULL, AV_DICT_IGNORE_SUFFIX);
+    printf("%s\n", (e) ? e->value : "(null)");
+    av_freep(&key);
+    av_freep(&val);
+
     return 0;
 }
diff --git a/libavutil/version.h b/libavutil/version.h
index 17a6d296a6..24af520e08 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,8 +79,8 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR  58
-#define LIBAVUTIL_VERSION_MINOR  13
-#define LIBAVUTIL_VERSION_MICRO 101
+#define LIBAVUTIL_VERSION_MINOR  14
+#define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
                                                LIBAVUTIL_VERSION_MINOR, \
diff --git a/tests/ref/fate/dict b/tests/ref/fate/dict
index 7205e4c845..afa87aca5f 100644
--- a/tests/ref/fate/dict
+++ b/tests/ref/fate/dict
@@ -48,3 +48,15 @@ Testing av_dict_set_int()
 Testing av_dict_set() with existing AVDictionaryEntry.key as key
 new val OK
 new val OK
+
+Testing av_dict_pop() with existing AVDictionaryEntry.key as key
+test-key: test-value (Return code: 0)
+(null)
+
+Testing av_dict_pop() with nonexistent key
+(null): (null) (Return code: ENOENT)
+(null)
+
+Testing av_dict_pop() with prefix key match
+prefix-test-key: test-value (Return code: 0)
+(null)
-- 
2.37.0 (Apple Git-136)

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [FFmpeg-devel] [PATCH v2 2/3] avformat/tee: use av_dict_pop
  2023-06-25 10:49 ` [FFmpeg-devel] [PATCH v2 " Marvin Scholz
@ 2023-06-25 10:49   ` Marvin Scholz
  2023-07-02  8:47     ` Stefano Sabatini
  2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 3/3] avutil/dict: constify av_dict_get return Marvin Scholz
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 32+ messages in thread
From: Marvin Scholz @ 2023-06-25 10:49 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marvin Scholz

This is a well-defined way to "steal" the value of the dict entry.
---
 libavformat/tee.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/libavformat/tee.c b/libavformat/tee.c
index cb555f52fd..70f3f2eb29 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -157,6 +157,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
 {
     int i, ret;
     AVDictionary *options = NULL, *bsf_options = NULL;
+    char *entry_val = NULL;
     AVDictionaryEntry *entry;
     char *filename;
     char *format = NULL, *select = NULL, *on_fail = NULL;
@@ -171,15 +172,15 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
         return ret;
 
 #define CONSUME_OPTION(option, field, action) do {                      \
-        if ((entry = av_dict_get(options, option, NULL, 0))) {          \
-            field = entry->value;                                       \
+        if ((!av_dict_pop(&options, option, NULL, &entry_val, 0))) {    \
+            field = entry_val;                                          \
             { action }                                                  \
-            av_dict_set(&options, option, NULL, 0);                     \
+            av_freep(&entry_val);                                       \
         }                                                               \
     } while (0)
 #define STEAL_OPTION(option, field)                                     \
     CONSUME_OPTION(option, field,                                       \
-                   entry->value = NULL; /* prevent it from being freed */)
+                   entry_val = NULL; /* prevent it from being freed */)
 #define PROCESS_OPTION(option, field, function, on_error)               \
     CONSUME_OPTION(option, field, if ((ret = function) < 0) { { on_error } goto end; })
 
-- 
2.37.0 (Apple Git-136)

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [FFmpeg-devel] [PATCH v2 3/3] avutil/dict: constify av_dict_get return
  2023-06-25 10:49 ` [FFmpeg-devel] [PATCH v2 " Marvin Scholz
  2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 2/3] avformat/tee: use av_dict_pop Marvin Scholz
@ 2023-06-25 10:49   ` Marvin Scholz
  2023-07-02  9:06     ` Stefano Sabatini
  2023-07-02  8:43   ` [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop Stefano Sabatini
  2023-07-03  0:18   ` Andreas Rheinhardt
  3 siblings, 1 reply; 32+ messages in thread
From: Marvin Scholz @ 2023-06-25 10:49 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Marvin Scholz

---
 doc/examples/qsv_transcode.c       |  2 +-
 libavcodec/libaomenc.c             |  2 +-
 libavcodec/libkvazaar.c            |  2 +-
 libavcodec/libsvtav1.c             |  2 +-
 libavcodec/libvpxenc.c             |  2 +-
 libavcodec/libx264.c               |  2 +-
 libavcodec/libx265.c               |  2 +-
 libavcodec/mjpegdec.c              |  2 +-
 libavcodec/qsvenc.c                |  2 +-
 libavfilter/avfilter.c             |  2 +-
 libavfilter/f_bench.c              |  2 +-
 libavfilter/f_drawgraph.c          |  2 +-
 libavfilter/f_select.c             |  4 +--
 libavfilter/vf_cover_rect.c        |  2 +-
 libavfilter/vf_drawtext.c          |  2 +-
 libavformat/aiffenc.c              |  2 +-
 libavformat/argo_asf.c             |  2 +-
 libavformat/asfenc.c               |  6 ++--
 libavformat/au.c                   |  2 +-
 libavformat/avformat.h             |  2 +-
 libavformat/avidec.c               |  2 +-
 libavformat/avienc.c               |  2 +-
 libavformat/avio.c                 |  4 +--
 libavformat/dashenc.c              |  6 ++--
 libavformat/dvenc.c                |  2 +-
 libavformat/flacdec.c              |  2 +-
 libavformat/flacenc.c              |  6 ++--
 libavformat/flvdec.c               |  2 +-
 libavformat/gxfenc.c               |  2 +-
 libavformat/http.c                 |  8 +++---
 libavformat/id3v2.c                |  6 ++--
 libavformat/id3v2enc.c             |  2 +-
 libavformat/imfdec.c               |  2 +-
 libavformat/matroskadec.c          |  2 +-
 libavformat/mov.c                  |  6 ++--
 libavformat/movenc.c               | 46 +++++++++++++++---------------
 libavformat/mp3enc.c               |  6 ++--
 libavformat/mpegtsenc.c            |  6 ++--
 libavformat/mux.c                  |  2 +-
 libavformat/mux_utils.c            |  2 +-
 libavformat/mxfenc.c               | 14 ++++-----
 libavformat/riffenc.c              |  2 +-
 libavformat/rmenc.c                |  2 +-
 libavformat/sapenc.c               |  2 +-
 libavformat/sdp.c                  |  2 +-
 libavformat/segment.c              |  4 +--
 libavformat/soxenc.c               |  2 +-
 libavformat/tee.c                  |  2 +-
 libavformat/ttmlenc.c              |  4 +--
 libavformat/wavenc.c               |  4 +--
 libavformat/webmdashenc.c          | 30 +++++++++----------
 libavutil/dict.c                   |  9 +++++-
 libavutil/dict.h                   |  5 ++++
 libavutil/hwcontext_cuda.c         |  2 +-
 libavutil/hwcontext_qsv.c          |  2 +-
 libavutil/hwcontext_vulkan.c       |  8 +++---
 libavutil/version.h                |  1 +
 tests/api/api-threadmessage-test.c |  2 +-
 58 files changed, 136 insertions(+), 123 deletions(-)

diff --git a/doc/examples/qsv_transcode.c b/doc/examples/qsv_transcode.c
index 48128b200c..cc4c203d94 100644
--- a/doc/examples/qsv_transcode.c
+++ b/doc/examples/qsv_transcode.c
@@ -87,7 +87,7 @@ static int dynamic_set_parameter(AVCodecContext *avctx)
     frame_number++;
     if (current_setting_number < setting_number &&
         frame_number == dynamic_setting[current_setting_number].frame_number) {
-        AVDictionaryEntry *e = NULL;
+        const AVDictionaryEntry *e = NULL;
         ret = str_to_dict(dynamic_setting[current_setting_number++].optstr, &opts);
         if (ret < 0) {
             fprintf(stderr, "The dynamic parameter is wrong\n");
diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c
index 16747e7e92..af6d50f9e3 100644
--- a/libavcodec/libaomenc.c
+++ b/libavcodec/libaomenc.c
@@ -999,7 +999,7 @@ static av_cold int aom_init(AVCodecContext *avctx,
 
 #if AOM_ENCODER_ABI_VERSION >= 23
     {
-        AVDictionaryEntry *en = NULL;
+        const AVDictionaryEntry *en = NULL;
 
         while ((en = av_dict_get(ctx->aom_params, "", en, AV_DICT_IGNORE_SUFFIX))) {
             int ret = aom_codec_set_option(&ctx->encoder, en->key, en->value);
diff --git a/libavcodec/libkvazaar.c b/libavcodec/libkvazaar.c
index 2ef34dd82e..2178f7ec45 100644
--- a/libavcodec/libkvazaar.c
+++ b/libavcodec/libkvazaar.c
@@ -104,7 +104,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
     if (ctx->kvz_params) {
         AVDictionary *dict = NULL;
         if (!av_dict_parse_string(&dict, ctx->kvz_params, "=", ",", 0)) {
-            AVDictionaryEntry *entry = NULL;
+            const AVDictionaryEntry *entry = NULL;
             while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX))) {
                 if (!api->config_parse(cfg, entry->key, entry->value)) {
                     av_log(avctx, AV_LOG_WARNING, "Invalid option: %s=%s.\n",
diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c
index 718a04d221..0f423cdbb8 100644
--- a/libavcodec/libsvtav1.c
+++ b/libavcodec/libsvtav1.c
@@ -151,7 +151,7 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param,
 {
     SvtContext *svt_enc = avctx->priv_data;
     const AVPixFmtDescriptor *desc;
-    AVDictionaryEntry *en = NULL;
+    const AVDictionaryEntry *en = NULL;
 
     // Update param from options
 #if FF_API_SVTAV1_OPTS
diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c
index 8833df2d68..15144c91ee 100644
--- a/libavcodec/libvpxenc.c
+++ b/libavcodec/libvpxenc.c
@@ -1735,7 +1735,7 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt,
         if (frame->pict_type == AV_PICTURE_TYPE_I)
             flags |= VPX_EFLAG_FORCE_KF;
         if (frame->metadata) {
-            AVDictionaryEntry* en = av_dict_get(frame->metadata, "vp8-flags", NULL, 0);
+            const AVDictionaryEntry* en = av_dict_get(frame->metadata, "vp8-flags", NULL, 0);
             if (en) {
                 flags |= strtoul(en->value, NULL, 10);
             }
diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index 5736f1efa7..cf73fc3c25 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -1088,7 +1088,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
 #endif
 
     {
-        AVDictionaryEntry *en = NULL;
+        const AVDictionaryEntry *en = NULL;
         while (en = av_dict_get(x4->x264_params, "", en, AV_DICT_IGNORE_SUFFIX)) {
            if ((ret = x264_param_parse(&x4->params, en->key, en->value)) < 0) {
                av_log(avctx, AV_LOG_WARNING,
diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c
index 873b3021ee..2d485170be 100644
--- a/libavcodec/libx265.c
+++ b/libavcodec/libx265.c
@@ -427,7 +427,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
     }
 
     {
-        AVDictionaryEntry *en = NULL;
+        const AVDictionaryEntry *en = NULL;
         while ((en = av_dict_get(ctx->x265_opts, "", en, AV_DICT_IGNORE_SUFFIX))) {
             int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value);
 
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index ab7fa73819..70068b5767 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -2378,7 +2378,7 @@ int ff_mjpeg_decode_frame_from_buf(AVCodecContext *avctx, AVFrame *frame,
     int i, index;
     int ret = 0;
     int is16bit;
-    AVDictionaryEntry *e = NULL;
+    const AVDictionaryEntry *e = NULL;
 
     s->force_pal8 = 0;
 
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index df63c182b0..bebb8fb6e1 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -2105,7 +2105,7 @@ static int set_roi_encode_ctrl(AVCodecContext *avctx, const AVFrame *frame,
 static void set_skip_frame_encode_ctrl(AVCodecContext *avctx, const AVFrame *frame,
                                mfxEncodeCtrl *enc_ctrl)
 {
-    AVDictionaryEntry* skip_frame_dict = NULL;
+    const AVDictionaryEntry* skip_frame_dict = NULL;
     if (!frame->metadata)
         return;
     skip_frame_dict = av_dict_get(frame->metadata, "qsv_skip_frame", NULL, 0);
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 0141b64cbc..af2f6dd36d 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -897,7 +897,7 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options)
 int avfilter_init_str(AVFilterContext *filter, const char *args)
 {
     AVDictionary *options = NULL;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     int ret = 0;
 
     if (args && *args) {
diff --git a/libavfilter/f_bench.c b/libavfilter/f_bench.c
index 9b55194dbc..ca1adf4ae6 100644
--- a/libavfilter/f_bench.c
+++ b/libavfilter/f_bench.c
@@ -71,7 +71,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     if (s->action == ACTION_START) {
         av_dict_set_int(&in->metadata, START_TIME_KEY, t, 0);
     } else if (s->action == ACTION_STOP) {
-        AVDictionaryEntry *e = av_dict_get(in->metadata, START_TIME_KEY, NULL, 0);
+        const AVDictionaryEntry *e = av_dict_get(in->metadata, START_TIME_KEY, NULL, 0);
         if (e) {
             const int64_t start = strtoll(e->value, NULL, 0);
             const int64_t diff = t - start;
diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c
index d29a7fb60a..69d8ba9993 100644
--- a/libavfilter/f_drawgraph.c
+++ b/libavfilter/f_drawgraph.c
@@ -165,7 +165,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     DrawGraphContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
     AVDictionary *metadata;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     AVFrame *out = s->out;
     AVFrame *clone = NULL;
     int64_t in_pts, out_pts, in_duration;
diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
index 49fcdc31ff..175334aded 100644
--- a/libavfilter/f_select.c
+++ b/libavfilter/f_select.c
@@ -308,8 +308,8 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *frame)
 static double get_concatdec_select(AVFrame *frame, int64_t pts)
 {
     AVDictionary *metadata = frame->metadata;
-    AVDictionaryEntry *start_time_entry = av_dict_get(metadata, "lavf.concatdec.start_time", NULL, 0);
-    AVDictionaryEntry *duration_entry = av_dict_get(metadata, "lavf.concatdec.duration", NULL, 0);
+    const AVDictionaryEntry *start_time_entry = av_dict_get(metadata, "lavf.concatdec.start_time", NULL, 0);
+    const AVDictionaryEntry *duration_entry = av_dict_get(metadata, "lavf.concatdec.duration", NULL, 0);
     if (start_time_entry) {
         int64_t start_time = strtoll(start_time_entry->value, NULL, 10);
         if (pts >= start_time) {
diff --git a/libavfilter/vf_cover_rect.c b/libavfilter/vf_cover_rect.c
index 642747a351..b219ae2948 100644
--- a/libavfilter/vf_cover_rect.c
+++ b/libavfilter/vf_cover_rect.c
@@ -125,7 +125,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
     CoverContext *cover = ctx->priv;
-    AVDictionaryEntry *ex, *ey, *ew, *eh;
+    const AVDictionaryEntry *ex, *ey, *ew, *eh;
     int ret, x = -1, y = -1, w = -1, h = -1;
     char *xendptr = NULL, *yendptr = NULL, *wendptr = NULL, *hendptr = NULL;
 
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 7854362eab..463ea905be 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -1242,7 +1242,7 @@ static int func_metadata(AVFilterContext *ctx, AVBPrint *bp,
                          char *fct, unsigned argc, char **argv, int tag)
 {
     DrawTextContext *s = ctx->priv;
-    AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
+    const AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
 
     if (e && e->value)
         av_bprintf(bp, "%s", e->value);
diff --git a/libavformat/aiffenc.c b/libavformat/aiffenc.c
index 11a5b18d57..b2ca6c9ce7 100644
--- a/libavformat/aiffenc.c
+++ b/libavformat/aiffenc.c
@@ -83,7 +83,7 @@ static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff)
 
 static void put_meta(AVFormatContext *s, const char *key, uint32_t id)
 {
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
     AVIOContext *pb = s->pb;
 
     if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
diff --git a/libavformat/argo_asf.c b/libavformat/argo_asf.c
index 5f38b68b6a..f83f9b2e2a 100644
--- a/libavformat/argo_asf.c
+++ b/libavformat/argo_asf.c
@@ -360,7 +360,7 @@ static int argo_asf_write_header(AVFormatContext *s)
         .num_chunks    = 1,
         .chunk_offset  = ASF_FILE_HEADER_SIZE
     };
-    AVDictionaryEntry *t;
+    const AVDictionaryEntry *t;
     const char *name, *end;
     size_t len;
 
diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c
index 244c7e7a27..8810d64980 100644
--- a/libavformat/asfenc.c
+++ b/libavformat/asfenc.c
@@ -331,7 +331,7 @@ static void asf_write_markers(AVFormatContext *s, AVIOContext *dyn_buf)
 
     for (unsigned i = 0; i < s->nb_chapters; i++) {
         AVChapter *c = s->chapters[i];
-        AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0);
+        const AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0);
         int64_t pres_time = av_rescale_q(c->start, c->time_base, scale);
         uint64_t offset;
         int32_t send_time = get_send_time(asf, pres_time, &offset);
@@ -361,7 +361,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
 {
     ASFContext *asf = s->priv_data;
     AVIOContext *pb = s->pb, *dyn_buf;
-    AVDictionaryEntry *tags[5];
+    const AVDictionaryEntry *tags[5];
     int header_size, extra_size, extra_size2, wav_extra_size;
     int has_title, has_aspect_ratio = 0;
     int metadata_count;
@@ -392,7 +392,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
     for (unsigned n = 0; n < s->nb_streams; n++) {
         AVStream *const st = s->streams[n];
         AVCodecParameters *const par = st->codecpar;
-        AVDictionaryEntry *entry;
+        const AVDictionaryEntry *entry;
 
         avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */
 
diff --git a/libavformat/au.c b/libavformat/au.c
index 3bf2150258..68b665aeb7 100644
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@ -261,7 +261,7 @@ static int au_get_annotations(AVFormatContext *s, AVBPrint *annotations)
     };
     int cnt = 0;
     AVDictionary *m = s->metadata;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
 
     for (int i = 0; i < FF_ARRAY_ELEMS(keys); i++) {
         t = av_dict_get(m, keys[i], NULL, 0);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 1916aa2dc5..95f52a639c 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -146,7 +146,7 @@
  * consumed). The calling program can handle such unrecognized options as it
  * wishes, e.g.
  * @code
- * AVDictionaryEntry *e;
+ * const AVDictionaryEntry *e;
  * if (e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
  *     fprintf(stderr, "Option %s not recognized by the demuxer.\n", e->key);
  *     abort();
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index 00bd7a98a9..fc3379c228 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -507,7 +507,7 @@ static int avi_read_header(AVFormatContext *s)
     uint64_t list_end   = 0;
     int64_t pos;
     int ret;
-    AVDictionaryEntry *dict_entry;
+    const AVDictionaryEntry *dict_entry;
 
     avi->stream_index = -1;
 
diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index a61e5c3109..b62258f693 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -266,7 +266,7 @@ static int avi_write_header(AVFormatContext *s)
     AVCodecParameters *video_par;
     AVStream *video_st = NULL;
     int64_t list1, list2, strh, strf;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
     int padding;
 
     if (s->nb_streams > AVI_MAX_STREAM_COUNT) {
diff --git a/libavformat/avio.c b/libavformat/avio.c
index ab1c19a58d..0082977f2d 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -167,7 +167,7 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
 {
     int err;
     AVDictionary *tmp_opts = NULL;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
 
     if (!options)
         options = &tmp_opts;
@@ -309,7 +309,7 @@ int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,
                          URLContext *parent)
 {
     AVDictionary *tmp_opts = NULL;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     int ret = ffurl_alloc(puc, filename, flags, int_cb);
     if (ret < 0)
         return ret;
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 17fe5f430c..283747c63d 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -800,7 +800,7 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
 {
     DASHContext *c = s->priv_data;
     AdaptationSet *as = &c->as[as_index];
-    AVDictionaryEntry *lang, *role;
+    const AVDictionaryEntry *lang, *role;
     int i;
 
     avio_printf(out, "\t\t<AdaptationSet id=\"%d\" contentType=\"%s\" startWithSAP=\"1\" segmentAlignment=\"true\" bitstreamSwitching=\"true\"",
@@ -1144,7 +1144,7 @@ static int write_manifest(AVFormatContext *s, int final)
     const char *proto = avio_find_protocol_name(s->url);
     int use_rename = proto && !strcmp(proto, "file");
     static unsigned int warned_non_file = 0;
-    AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
+    const AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
     AVDictionary *opts = NULL;
 
     if (!use_rename && !warned_non_file++)
@@ -1372,7 +1372,7 @@ static int write_manifest(AVFormatContext *s, int final)
 
 static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key)
 {
-    AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0);
+    const AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0);
     if (entry)
         av_dict_set(dst, key, entry->value, AV_DICT_DONT_OVERWRITE);
     return 0;
diff --git a/libavformat/dvenc.c b/libavformat/dvenc.c
index 29d2dc47ac..246d190961 100644
--- a/libavformat/dvenc.c
+++ b/libavformat/dvenc.c
@@ -390,7 +390,7 @@ static int dv_write_header(AVFormatContext *s)
 {
     AVRational rate;
     DVMuxContext *dvc = s->priv_data;
-    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+    const AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
 
     if (!dv_init_mux(s)) {
         av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n"
diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c
index b58ec03963..773fddc4fd 100644
--- a/libavformat/flacdec.c
+++ b/libavformat/flacdec.c
@@ -176,7 +176,7 @@ static int flac_read_header(AVFormatContext *s)
             }
             /* process supported blocks other than STREAMINFO */
             if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
-                AVDictionaryEntry *chmask;
+                const AVDictionaryEntry *chmask;
 
                 ret = ff_vorbis_comment(s, &s->metadata, buffer, metadata_size, 1);
                 if (ret < 0) {
diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c
index a8beec7750..fab7b34fa8 100644
--- a/libavformat/flacenc.c
+++ b/libavformat/flacenc.c
@@ -85,7 +85,7 @@ static int flac_write_picture(struct AVFormatContext *s, AVPacket *pkt)
     AVIOContext *pb = s->pb;
     const AVPixFmtDescriptor *pixdesc;
     const CodecMime *mime = ff_id3v2_mime_tags;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     const char *mimetype = NULL, *desc = "";
     const AVStream *st = s->streams[pkt->stream_index];
     int i, mimelen, desclen, type = 0, blocklen;
@@ -243,8 +243,8 @@ static int flac_init(struct AVFormatContext *s)
     if (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE &&
         !(par->ch_layout.u.mask & ~0x3ffffULL) &&
         !ff_flac_is_native_layout(par->ch_layout.u.mask)) {
-        AVDictionaryEntry *chmask = av_dict_get(s->metadata, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK",
-                                                NULL, 0);
+        const AVDictionaryEntry *chmask = av_dict_get(s->metadata, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK",
+                                                      NULL, 0);
 
         if (chmask) {
             av_log(s, AV_LOG_WARNING, "A WAVEFORMATEXTENSIBLE_CHANNEL_MASK is "
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index d83edff727..abb282da56 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -1268,7 +1268,7 @@ retry_duration:
         }
         if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
             st->codecpar->codec_id == AV_CODEC_ID_H264)) {
-            AVDictionaryEntry *t;
+            const AVDictionaryEntry *t;
 
             if (st->codecpar->extradata) {
                 if ((ret = flv_queue_extradata(flv, s->pb, stream_type, size)) < 0)
diff --git a/libavformat/gxfenc.c b/libavformat/gxfenc.c
index 7495924722..93bfed8246 100644
--- a/libavformat/gxfenc.c
+++ b/libavformat/gxfenc.c
@@ -688,7 +688,7 @@ static int gxf_write_header(AVFormatContext *s)
     uint8_t tracks[255] = {0};
     int i, media_info = 0;
     int ret;
-    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+    const AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
 
     if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
         av_log(s, AV_LOG_ERROR, "gxf muxer does not support streamed output, patch welcome\n");
diff --git a/libavformat/http.c b/libavformat/http.c
index 0817aafb5b..c18a4d7e58 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -309,7 +309,7 @@ static int http_should_reconnect(HTTPContext *s, int err)
 
 static char *redirect_cache_get(HTTPContext *s)
 {
-    AVDictionaryEntry *re;
+    const AVDictionaryEntry *re;
     int64_t expiry;
     char *delim;
 
@@ -960,7 +960,7 @@ static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
 static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
 {
     AVDictionary *new_params = NULL;
-    AVDictionaryEntry *e, *cookie_entry;
+    const AVDictionaryEntry *e, *cookie_entry;
     char *eql, *name;
 
     // ensure the cookie is parsable
@@ -978,7 +978,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
     if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) {
         struct tm new_tm = {0};
         if (!parse_set_cookie_expiry_time(e->value, &new_tm)) {
-            AVDictionaryEntry *e2;
+            const AVDictionaryEntry *e2;
 
             // if the cookie has already expired ignore it
             if (av_timegm(&new_tm) < av_gettime() / 1000000) {
@@ -1256,7 +1256,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path,
     *cookies = NULL;
     while ((cookie = av_strtok(next, "\n", &saveptr)) && !ret) {
         AVDictionary *cookie_params = NULL;
-        AVDictionaryEntry *cookie_entry, *e;
+        const AVDictionaryEntry *cookie_entry, *e;
 
         next = NULL;
         // store the cookie in a dict in case it is updated in the response
diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 38c86a8e79..d938633e36 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -538,9 +538,9 @@ static int is_number(const char *str)
     return !*str;
 }
 
-static AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag)
+static const AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag)
 {
-    AVDictionaryEntry *t;
+    const AVDictionaryEntry *t;
     if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
         strlen(t->value) == 4 && is_number(t->value))
         return t;
@@ -549,7 +549,7 @@ static AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag)
 
 static void merge_date(AVDictionary **m)
 {
-    AVDictionaryEntry *t;
+    const AVDictionaryEntry *t;
     char date[17] = { 0 };      // YYYY-MM-DD hh:mm
 
     if (!(t = get_date_tag(*m, "TYER")) &&
diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c
index ac907c2758..6d646e3f29 100644
--- a/libavformat/id3v2enc.c
+++ b/libavformat/id3v2enc.c
@@ -352,7 +352,7 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
 int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
 {
     AVStream *st = s->streams[pkt->stream_index];
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
 
     AVIOContext *dyn_buf;
     uint8_t     *buf;
diff --git a/libavformat/imfdec.c b/libavformat/imfdec.c
index 818b5e590b..1fae996079 100644
--- a/libavformat/imfdec.c
+++ b/libavformat/imfdec.c
@@ -631,7 +631,7 @@ static int imf_read_header(AVFormatContext *s)
     IMFContext *c = s->priv_data;
     char *asset_map_path;
     char *tmp_str;
-    AVDictionaryEntry* tcr;
+    const AVDictionaryEntry* tcr;
     char tc_buf[AV_TIMECODE_STR_SIZE];
     int ret = 0;
 
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 49950956b6..9af4900814 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -2083,7 +2083,7 @@ static int matroska_parse_flac(AVFormatContext *s,
         /* check for the channel mask */
         if (block_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
             AVDictionary *dict = NULL;
-            AVDictionaryEntry *chmask;
+            const AVDictionaryEntry *chmask;
 
             ff_vorbis_comment(s, &dict, p, block_size, 0);
             chmask = av_dict_get(dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", NULL, 0);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 444aca5235..07a4510b38 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2339,7 +2339,7 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
     int bits_per_sample, flags;
     uint16_t version = avio_rb16(pb);
     uint32_t id = 0;
-    AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE);
+    const AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE);
     int channel_count;
 
     avio_rb16(pb); /* revision level */
@@ -8448,7 +8448,7 @@ static void export_orphan_timecode(AVFormatContext *s)
 
         if (st->codecpar->codec_tag  == MKTAG('t','m','c','d') &&
             !tmcd_is_referenced(s, i + 1)) {
-            AVDictionaryEntry *tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
+            const AVDictionaryEntry *tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
             if (tcr) {
                 av_dict_set(&s->metadata, "timecode", tcr->value, 0);
                 break;
@@ -8611,7 +8611,7 @@ static int mov_read_header(AVFormatContext *s)
         AVStream *st = s->streams[i];
         MOVStreamContext *sc = st->priv_data;
         if (sc->timecode_track > 0) {
-            AVDictionaryEntry *tcr;
+            const AVDictionaryEntry *tcr;
             int tmcd_st_id = -1;
 
             for (j = 0; j < s->nb_streams; j++)
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index f1cc80b1b3..518b98b2ce 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -2222,7 +2222,7 @@ static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
 
 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
 {
-    AVDictionaryEntry *encoder;
+    const AVDictionaryEntry *encoder;
     int xdcam_res =  (track->par->width == 1280 && track->par->height == 720)
                   || (track->par->width == 1440 && track->par->height == 1080)
                   || (track->par->width == 1920 && track->par->height == 1080);
@@ -2521,7 +2521,7 @@ static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
 #if 1
     int frame_duration;
     int nb_frames;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
 
     if (!track->st->avg_frame_rate.num || !track->st->avg_frame_rate.den) {
         av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
@@ -3019,7 +3019,7 @@ static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
             // hdlr.name is used by some players to identify the content title
             // of the track. So if an alternate handler description is
             // specified, use it.
-            AVDictionaryEntry *t;
+            const AVDictionaryEntry *t;
             t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
             if (t && utf8len(t->value))
                 descr = t->value;
@@ -3673,7 +3673,7 @@ static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
                                     const char *tag, const char *str)
 {
     int64_t pos = avio_tell(pb);
-    AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
+    const AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
     if (!t || !utf8len(t->value))
         return 0;
 
@@ -3986,11 +3986,11 @@ static int mov_write_string_tag(AVIOContext *pb, const char *name,
     return size;
 }
 
-static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
+static const AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
                                             const char *tag, int *lang)
 {
     int l, len, len2;
-    AVDictionaryEntry *t, *t2 = NULL;
+    const AVDictionaryEntry *t, *t2 = NULL;
     char tag2[16];
 
     *lang = 0;
@@ -4016,7 +4016,7 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
                                      int long_style)
 {
     int lang;
-    AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
+    const AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
     if (!t)
         return 0;
     return mov_write_string_tag(pb, name, t->value, lang, long_style);
@@ -4025,7 +4025,7 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
 /* iTunes bpm number */
 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
 {
-    AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
+    const AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
     int size = 0, tmpo = t ? atoi(t->value) : 0;
     if (tmpo) {
         size = 26;
@@ -4047,7 +4047,7 @@ static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
     int64_t pos = avio_tell(pb);
     double latitude, longitude, altitude;
     int32_t latitude_fix, longitude_fix, altitude_fix;
-    AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
+    const AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
     const char *ptr, *place = "";
     char *end;
     static const char *astronomical_body = "earth";
@@ -4095,9 +4095,9 @@ static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
                               AVFormatContext *s, int disc)
 {
-    AVDictionaryEntry *t = av_dict_get(s->metadata,
-                                       disc ? "disc" : "track",
-                                       NULL, 0);
+    const AVDictionaryEntry *t = av_dict_get(s->metadata,
+                                             disc ? "disc" : "track",
+                                             NULL, 0);
     int size = 0, track = t ? atoi(t->value) : 0;
     if (track) {
         int tracks = 0;
@@ -4123,7 +4123,7 @@ static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
                                    const char *name, const char *tag,
                                    int len)
 {
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
     uint8_t num;
     int size = 24 + len;
 
@@ -4315,7 +4315,7 @@ static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
                                       const char *name, const char *key)
 {
     int len;
-    AVDictionaryEntry *t;
+    const AVDictionaryEntry *t;
 
     if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
         return 0;
@@ -4353,7 +4353,7 @@ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
                                   const char *tag, const char *str)
 {
     int64_t pos = avio_tell(pb);
-    AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
+    const AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
     if (!t || !utf8len(t->value))
         return 0;
     avio_wb32(pb, 0);   /* size */
@@ -4384,7 +4384,7 @@ static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
 
     for (i = 0; i < nb_chapters; i++) {
         AVChapter *c = s->chapters[i];
-        AVDictionaryEntry *t;
+        const AVDictionaryEntry *t;
         avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
 
         if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
@@ -4470,7 +4470,7 @@ static void mov_write_psp_udta_tag(AVIOContext *pb,
 
 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
 {
-    AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
+    const AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
     int64_t pos, pos2;
 
     if (title) {
@@ -4707,7 +4707,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormat
         char track_name_buf[32] = { 0 };
 
         AVStream *st = track->st;
-        AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
+        const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
 
         if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
             type = "video";
@@ -6708,7 +6708,7 @@ static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
 
     for (i = 0; i < s->nb_chapters; i++) {
         AVChapter *c = s->chapters[i];
-        AVDictionaryEntry *t;
+        const AVDictionaryEntry *t;
 
         int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
         pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
@@ -7103,13 +7103,13 @@ static int mov_init(AVFormatContext *s)
 
     if (   mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
         || mov->write_tmcd == 1) {
-        AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
-                                                    NULL, 0);
+        const AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
+                                                          NULL, 0);
 
         /* +1 tmcd track for each video stream with a timecode */
         for (i = 0; i < s->nb_streams; i++) {
             AVStream *st = s->streams[i];
-            AVDictionaryEntry *t = global_tcr;
+            const AVDictionaryEntry *t = global_tcr;
             if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
                 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
                 AVTimecode tc;
@@ -7165,7 +7165,7 @@ static int mov_init(AVFormatContext *s)
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st= s->streams[i];
         MOVTrack *track= &mov->tracks[i];
-        AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
+        const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
 
         track->st  = st;
         track->par = st->codecpar;
diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c
index 5e81f72a59..41ade128ed 100644
--- a/libavformat/mp3enc.c
+++ b/libavformat/mp3enc.c
@@ -41,7 +41,7 @@
 static int id3v1_set_string(AVFormatContext *s, const char *key,
                             uint8_t *buf, int buf_size)
 {
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
     if ((tag = av_dict_get(s->metadata, key, NULL, 0)))
         av_strlcpy(buf, tag->value, buf_size);
     return !!tag;
@@ -50,7 +50,7 @@ static int id3v1_set_string(AVFormatContext *s, const char *key,
 // refer to: http://id3.org/ID3v1
 static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf)
 {
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
     int i, count = 0;
 
     memset(buf, 0, ID3v1_TAG_SIZE); /* fail safe */
@@ -145,7 +145,7 @@ static int mp3_write_xing(AVFormatContext *s)
 {
     MP3Context       *mp3 = s->priv_data;
     AVCodecParameters *par = s->streams[mp3->audio_stream_idx]->codecpar;
-    AVDictionaryEntry *enc = av_dict_get(s->streams[mp3->audio_stream_idx]->metadata, "encoder", NULL, 0);
+    const AVDictionaryEntry *enc = av_dict_get(s->streams[mp3->audio_stream_idx]->metadata, "encoder", NULL, 0);
     AVIOContext *dyn_ctx;
     int32_t        header;
     MPADecodeHeader  mpah;
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 700fc549df..6f1062b2d9 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -529,7 +529,7 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st = s->streams[i];
         MpegTSWriteStream *ts_st = st->priv_data;
-        AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
+        const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
         const char default_language[] = "und";
         const char *language = lang && strlen(lang->value) >= 3 ? lang->value : default_language;
         enum AVCodecID codec_id = st->codecpar->codec_id;
@@ -986,7 +986,7 @@ static MpegTSService *mpegts_add_service(AVFormatContext *s, int sid,
 {
     MpegTSWrite *ts = s->priv_data;
     MpegTSService *service;
-    AVDictionaryEntry *title, *provider;
+    const AVDictionaryEntry *title, *provider;
     char default_service_name[32];
     const char *service_name;
     const char *provider_name;
@@ -1088,7 +1088,7 @@ static void select_pcr_streams(AVFormatContext *s)
 static int mpegts_init(AVFormatContext *s)
 {
     MpegTSWrite *ts = s->priv_data;
-    AVDictionaryEntry *provider;
+    const AVDictionaryEntry *provider;
     const char *provider_name;
     int i, j;
     int ret;
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 415bd3948f..cfb1269ff5 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -185,7 +185,7 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
     FFFormatContext *const si = ffformatcontext(s);
     AVDictionary *tmp = NULL;
     const FFOutputFormat *of = ffofmt(s->oformat);
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
     int ret = 0;
 
     if (options)
diff --git a/libavformat/mux_utils.c b/libavformat/mux_utils.c
index 3e63b8039a..af1ce420e7 100644
--- a/libavformat/mux_utils.c
+++ b/libavformat/mux_utils.c
@@ -125,7 +125,7 @@ int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary **op
 
 int ff_parse_creation_time_metadata(AVFormatContext *s, int64_t *timestamp, int return_seconds)
 {
-    AVDictionaryEntry *entry;
+    const AVDictionaryEntry *entry;
     int64_t parsed_timestamp;
     int ret;
     if ((entry = av_dict_get(s->metadata, "creation_time", NULL, 0))) {
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index d8252ed68f..e9eb801aa5 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -799,9 +799,9 @@ static void mxf_write_identification(AVFormatContext *s)
 {
     MXFContext *mxf = s->priv_data;
     AVIOContext *pb = s->pb;
-    AVDictionaryEntry *com_entry = av_dict_get(s->metadata, "company_name", NULL, 0);
-    AVDictionaryEntry *product_entry = av_dict_get(s->metadata, "product_name", NULL, 0);
-    AVDictionaryEntry *version_entry = av_dict_get(s->metadata, "product_version", NULL, 0);
+    const AVDictionaryEntry *com_entry = av_dict_get(s->metadata, "company_name", NULL, 0);
+    const AVDictionaryEntry *product_entry = av_dict_get(s->metadata, "product_name", NULL, 0);
+    const AVDictionaryEntry *version_entry = av_dict_get(s->metadata, "product_version", NULL, 0);
     const char *company = com_entry ? com_entry->value : "FFmpeg";
     const char *product = product_entry ? product_entry->value : !IS_OPATOM(s) ? "OP1a Muxer" : "OPAtom Muxer";
     const char *platform = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : PLATFORM_IDENT;
@@ -1649,7 +1649,7 @@ static int mxf_write_tagged_value(AVFormatContext *s, const char* name, const ch
 static int mxf_write_user_comments(AVFormatContext *s, const AVDictionary *m)
 {
     MXFContext *mxf = s->priv_data;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
     int count = 0;
 
     while ((t = av_dict_get(m, "comment_", t, AV_DICT_IGNORE_SUFFIX))) {
@@ -1789,7 +1789,7 @@ static int mxf_write_essence_container_data(AVFormatContext *s)
 static int mxf_write_header_metadata_sets(AVFormatContext *s)
 {
     MXFContext *mxf = s->priv_data;
-    AVDictionaryEntry *entry = NULL;
+    const AVDictionaryEntry *entry = NULL;
     AVStream *st = NULL;
     int i;
     MXFPackage packages[3] = {{0}};
@@ -2652,7 +2652,7 @@ static void mxf_gen_umid(AVFormatContext *s)
 static int mxf_init_timecode(AVFormatContext *s, AVStream *st, AVRational tbc)
 {
     MXFContext *mxf = s->priv_data;
-    AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+    const AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
 
     if (!ff_mxf_get_content_package_rate(tbc)) {
         if (s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
@@ -2854,7 +2854,7 @@ static int mxf_init(AVFormatContext *s)
             if (ret < 0)
                 return ret;
         } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
-            AVDictionaryEntry *e = av_dict_get(st->metadata, "data_type", NULL, 0);
+            const AVDictionaryEntry *e = av_dict_get(st->metadata, "data_type", NULL, 0);
             if (e && !strcmp(e->value, "vbi_vanc_smpte_436M")) {
                 sc->index = INDEX_S436M;
             } else {
diff --git a/libavformat/riffenc.c b/libavformat/riffenc.c
index 3325419b94..309032be9b 100644
--- a/libavformat/riffenc.c
+++ b/libavformat/riffenc.c
@@ -338,7 +338,7 @@ void ff_riff_write_info(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     int i;
     int64_t list_pos;
-    AVDictionaryEntry *t = NULL;
+    const AVDictionaryEntry *t = NULL;
 
     ff_metadata_conv(&s->metadata, ff_riff_info_conv, NULL);
 
diff --git a/libavformat/rmenc.c b/libavformat/rmenc.c
index 0d001224cb..a1f9d9ee15 100644
--- a/libavformat/rmenc.c
+++ b/libavformat/rmenc.c
@@ -77,7 +77,7 @@ static int rv10_write_header(AVFormatContext *ctx,
     int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i;
     int bit_rate, v, duration, flags;
     int data_offset;
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
 
     ffio_wfourcc(s, ".RMF");
     avio_wb32(s,18); /* header size */
diff --git a/libavformat/sapenc.c b/libavformat/sapenc.c
index 28839b837f..714ff1e148 100644
--- a/libavformat/sapenc.c
+++ b/libavformat/sapenc.c
@@ -77,7 +77,7 @@ static int sap_write_header(AVFormatContext *s)
     struct sockaddr_storage localaddr;
     socklen_t addrlen = sizeof(localaddr);
     int udp_fd;
-    AVDictionaryEntry* title = av_dict_get(s->metadata, "title", NULL, 0);
+    const AVDictionaryEntry* title = av_dict_get(s->metadata, "title", NULL, 0);
 
     if (!ff_network_init())
         return AVERROR(EIO);
diff --git a/libavformat/sdp.c b/libavformat/sdp.c
index 6888936290..61e57894a0 100644
--- a/libavformat/sdp.c
+++ b/libavformat/sdp.c
@@ -837,7 +837,7 @@ int ff_sdp_write_media(char *buff, int size, const AVStream *st, int idx,
 
 int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size)
 {
-    AVDictionaryEntry *title = av_dict_get(ac[0]->metadata, "title", NULL, 0);
+    const AVDictionaryEntry *title = av_dict_get(ac[0]->metadata, "title", NULL, 0);
     struct sdp_session_level s = { 0 };
     int i, j, port, ttl, is_multicast, index = 0;
     char dst[32], dst_type[5];
diff --git a/libavformat/segment.c b/libavformat/segment.c
index 2a82f39f31..1fb52c7f16 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -355,7 +355,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
     int ret = 0;
     AVTimecode tc;
     AVRational rate;
-    AVDictionaryEntry *tcr;
+    const AVDictionaryEntry *tcr;
     char buf[AV_TIMECODE_STR_SIZE];
     int i;
     int err;
@@ -441,7 +441,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
                 char st_buf[AV_TIMECODE_STR_SIZE];
                 AVTimecode st_tc;
                 AVRational st_rate = s->streams[i]->avg_frame_rate;
-                AVDictionaryEntry *st_tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0);
+                const AVDictionaryEntry *st_tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0);
                 if (st_tcr) {
                     if ((av_timecode_init_from_string(&st_tc, st_rate, st_tcr->value, s) < 0)) {
                         av_log(s, AV_LOG_WARNING, "Could not increment stream %d timecode, error occurred during timecode creation.\n", i);
diff --git a/libavformat/soxenc.c b/libavformat/soxenc.c
index 062b4a3fae..b10168c91f 100644
--- a/libavformat/soxenc.c
+++ b/libavformat/soxenc.c
@@ -47,7 +47,7 @@ static int sox_write_header(AVFormatContext *s)
     SoXContext *sox = s->priv_data;
     AVIOContext *pb = s->pb;
     AVCodecParameters *par = s->streams[0]->codecpar;
-    AVDictionaryEntry *comment;
+    const AVDictionaryEntry *comment;
     size_t comment_len = 0, comment_size;
 
     comment = av_dict_get(s->metadata, "comment", NULL, 0);
diff --git a/libavformat/tee.c b/libavformat/tee.c
index 70f3f2eb29..2aa2934677 100644
--- a/libavformat/tee.c
+++ b/libavformat/tee.c
@@ -158,7 +158,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
     int i, ret;
     AVDictionary *options = NULL, *bsf_options = NULL;
     char *entry_val = NULL;
-    AVDictionaryEntry *entry;
+    const AVDictionaryEntry *entry;
     char *filename;
     char *format = NULL, *select = NULL, *on_fail = NULL;
     char *use_fifo = NULL, *fifo_options_str = NULL;
diff --git a/libavformat/ttmlenc.c b/libavformat/ttmlenc.c
index 212994be50..41020c2537 100644
--- a/libavformat/ttmlenc.c
+++ b/libavformat/ttmlenc.c
@@ -136,8 +136,8 @@ static int ttml_write_header(AVFormatContext *ctx)
         AVStream    *st = ctx->streams[0];
         AVIOContext *pb = ctx->pb;
 
-        AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,
-                                              0);
+        const AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,
+                                                    0);
         const char *printed_lang = (lang && lang->value) ? lang->value : "";
 
         ttml_ctx->input_type = ff_is_ttml_stream_paragraph_based(st->codecpar) ?
diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index c12c090934..345f21293c 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -91,7 +91,7 @@ typedef struct WAVMuxContext {
 #if CONFIG_WAV_MUXER
 static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, int maxlen)
 {
-    AVDictionaryEntry *tag;
+    const AVDictionaryEntry *tag;
     size_t len = 0;
 
     if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
@@ -105,7 +105,7 @@ static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, in
 
 static void bwf_write_bext_chunk(AVFormatContext *s)
 {
-    AVDictionaryEntry *tmp_tag;
+    const AVDictionaryEntry *tmp_tag;
     uint64_t time_reference = 0;
     int64_t bext = ff_start_tag(s->pb, "bext");
 
diff --git a/libavformat/webmdashenc.c b/libavformat/webmdashenc.c
index 0d6c4a2072..e085227ddd 100644
--- a/libavformat/webmdashenc.c
+++ b/libavformat/webmdashenc.c
@@ -71,7 +71,7 @@ static double get_duration(AVFormatContext *s)
     int i = 0;
     double max = 0.0;
     for (i = 0; i < s->nb_streams; i++) {
-        AVDictionaryEntry *duration = av_dict_get(s->streams[i]->metadata,
+        const AVDictionaryEntry *duration = av_dict_get(s->streams[i]->metadata,
                                                   DURATION, NULL, 0);
         if (!duration || atof(duration->value) < 0) continue;
         if (atof(duration->value) > max) max = atof(duration->value);
@@ -130,11 +130,11 @@ static void write_footer(AVFormatContext *s)
 static int subsegment_alignment(AVFormatContext *s, const AdaptationSet *as)
 {
     int i;
-    AVDictionaryEntry *gold = av_dict_get(s->streams[as->streams[0]]->metadata,
+    const AVDictionaryEntry *gold = av_dict_get(s->streams[as->streams[0]]->metadata,
                                           CUE_TIMESTAMPS, NULL, 0);
     if (!gold) return 0;
     for (i = 1; i < as->nb_streams; i++) {
-        AVDictionaryEntry *ts = av_dict_get(s->streams[as->streams[i]]->metadata,
+        const AVDictionaryEntry *ts = av_dict_get(s->streams[as->streams[i]]->metadata,
                                             CUE_TIMESTAMPS, NULL, 0);
         if (!ts || !av_strstart(ts->value, gold->value, NULL)) return 0;
     }
@@ -145,13 +145,13 @@ static int bitstream_switching(AVFormatContext *s, const AdaptationSet *as)
 {
     int i;
     const AVStream *gold_st = s->streams[as->streams[0]];
-    AVDictionaryEntry *gold_track_num = av_dict_get(gold_st->metadata,
+    const AVDictionaryEntry *gold_track_num = av_dict_get(gold_st->metadata,
                                                     TRACK_NUMBER, NULL, 0);
     AVCodecParameters *gold_par = gold_st->codecpar;
     if (!gold_track_num) return 0;
     for (i = 1; i < as->nb_streams; i++) {
         const AVStream *st = s->streams[as->streams[i]];
-        AVDictionaryEntry *track_num = av_dict_get(st->metadata,
+        const AVDictionaryEntry *track_num = av_dict_get(st->metadata,
                                                    TRACK_NUMBER, NULL, 0);
         AVCodecParameters *par = st->codecpar;
         if (!track_num ||
@@ -177,7 +177,7 @@ static int write_representation(AVFormatContext *s, AVStream *st, char *id,
     WebMDashMuxContext *w = s->priv_data;
     AVIOContext *pb = s->pb;
     const AVCodecParameters *par = st->codecpar;
-    AVDictionaryEntry *bandwidth = av_dict_get(st->metadata, BANDWIDTH, NULL, 0);
+    const AVDictionaryEntry *bandwidth = av_dict_get(st->metadata, BANDWIDTH, NULL, 0);
     const char *bandwidth_str;
     avio_printf(pb, "<Representation id=\"%s\"", id);
     if (bandwidth) {
@@ -205,10 +205,10 @@ static int write_representation(AVFormatContext *s, AVStream *st, char *id,
         avio_printf(pb, " startsWithSAP=\"1\"");
         avio_printf(pb, ">");
     } else {
-        AVDictionaryEntry *irange = av_dict_get(st->metadata, INITIALIZATION_RANGE, NULL, 0);
-        AVDictionaryEntry *cues_start = av_dict_get(st->metadata, CUES_START, NULL, 0);
-        AVDictionaryEntry *cues_end = av_dict_get(st->metadata, CUES_END, NULL, 0);
-        AVDictionaryEntry *filename = av_dict_get(st->metadata, FILENAME, NULL, 0);
+        const AVDictionaryEntry *irange = av_dict_get(st->metadata, INITIALIZATION_RANGE, NULL, 0);
+        const AVDictionaryEntry *cues_start = av_dict_get(st->metadata, CUES_START, NULL, 0);
+        const AVDictionaryEntry *cues_end = av_dict_get(st->metadata, CUES_END, NULL, 0);
+        const AVDictionaryEntry *filename = av_dict_get(st->metadata, FILENAME, NULL, 0);
         if (!irange || !cues_start || !cues_end || !filename)
             return AVERROR(EINVAL);
 
@@ -307,7 +307,7 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
     AdaptationSet *as = &w->as[as_index];
     const AVStream *st = s->streams[as->streams[0]];
     AVCodecParameters *par = st->codecpar;
-    AVDictionaryEntry *lang;
+    const AVDictionaryEntry *lang;
     AVIOContext *pb = s->pb;
     int i;
     static const char boolean[2][6] = { "false", "true" };
@@ -347,15 +347,15 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
                 boolean[w->is_live || subsegment_alignment(s, as)]);
 
     for (i = 0; i < as->nb_streams; i++) {
-        AVDictionaryEntry *kf = av_dict_get(s->streams[as->streams[i]]->metadata,
-                                            CLUSTER_KEYFRAME, NULL, 0);
+        const AVDictionaryEntry *kf = av_dict_get(s->streams[as->streams[i]]->metadata,
+                                                  CLUSTER_KEYFRAME, NULL, 0);
         if (!w->is_live && (!kf || !strncmp(kf->value, "0", 1))) subsegmentStartsWithSAP = 0;
     }
     avio_printf(pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP);
     avio_printf(pb, ">\n");
 
     if (w->is_live) {
-        AVDictionaryEntry *filename =
+        const AVDictionaryEntry *filename =
             av_dict_get(st->metadata, FILENAME, NULL, 0);
         char *underscore_pos, *period_pos;
         int ret;
@@ -383,7 +383,7 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
         AVStream *st = s->streams[as->streams[i]];
         int ret;
         if (w->is_live) {
-            AVDictionaryEntry *filename =
+            const AVDictionaryEntry *filename =
                 av_dict_get(st->metadata, FILENAME, NULL, 0);
             if (!filename)
                 return AVERROR(EINVAL);
diff --git a/libavutil/dict.c b/libavutil/dict.c
index ac41771994..ca5026905c 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -57,6 +57,9 @@ const AVDictionaryEntry *av_dict_iterate(const AVDictionary *m,
     return &m->elems[i];
 }
 
+#if !FF_API_AV_DICT_GET_NOT_CONST
+const
+#endif
 AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
                                const AVDictionaryEntry *prev, int flags)
 {
@@ -78,7 +81,11 @@ AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
             continue;
         if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
             continue;
+        #if FF_API_AV_DICT_GET_NOT_CONST
         return (AVDictionaryEntry *)entry;
+        #else
+        return entry;
+        #endif
     }
     return NULL;
 }
@@ -100,7 +107,7 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value,
         goto err_out;
     }
     if (!(flags & AV_DICT_MULTIKEY)) {
-        tag = av_dict_get(m, key, NULL, flags);
+        tag = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
     }
     if (flags & AV_DICT_DONT_STRDUP_KEY)
         copy_key = (void *)key;
diff --git a/libavutil/dict.h b/libavutil/dict.h
index 31d38dabec..22e95d6c2b 100644
--- a/libavutil/dict.h
+++ b/libavutil/dict.h
@@ -32,6 +32,8 @@
 
 #include <stdint.h>
 
+#include "version.h"
+
 /**
  * @addtogroup lavu_dict AVDictionary
  * @ingroup lavu_data
@@ -107,6 +109,9 @@ typedef struct AVDictionary AVDictionary;
  *
  * @return      Found entry or NULL in case no matching entry was found in the dictionary
  */
+#if !FF_API_AV_DICT_GET_NOT_CONST
+const
+#endif
 AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
                                const AVDictionaryEntry *prev, int flags);
 
diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c
index 4b298fa93e..c219dcd53e 100644
--- a/libavutil/hwcontext_cuda.c
+++ b/libavutil/hwcontext_cuda.c
@@ -381,7 +381,7 @@ static int cuda_context_init(AVHWDeviceContext *device_ctx, int flags) {
 static int cuda_flags_from_opts(AVHWDeviceContext *device_ctx,
                                 AVDictionary *opts, int *flags)
 {
-    AVDictionaryEntry *primary_ctx_opt = av_dict_get(opts, "primary_ctx", NULL, 0);
+    const AVDictionaryEntry *primary_ctx_opt = av_dict_get(opts, "primary_ctx", NULL, 0);
 
     if (primary_ctx_opt && strtol(primary_ctx_opt->value, NULL, 10)) {
         av_log(device_ctx, AV_LOG_VERBOSE, "Using CUDA primary device context\n");
diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c
index d4b564ba2d..4d91e97670 100644
--- a/libavutil/hwcontext_qsv.c
+++ b/libavutil/hwcontext_qsv.c
@@ -2127,7 +2127,7 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device,
     enum AVHWDeviceType child_device_type;
     AVHWDeviceContext *child_device;
     AVDictionary *child_device_opts;
-    AVDictionaryEntry *e;
+    const AVDictionaryEntry *e;
 
     mfxIMPL impl;
     int ret;
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index ca802cc86e..1d1e69ef3d 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -481,7 +481,7 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts,
     int optional_exts_num;
     uint32_t sup_ext_count;
     char *user_exts_str = NULL;
-    AVDictionaryEntry *user_exts;
+    const AVDictionaryEntry *user_exts;
     VkExtensionProperties *sup_ext;
     const VulkanOptExtension *optional_exts;
 
@@ -609,14 +609,14 @@ static int check_validation_layers(AVHWDeviceContext *ctx, AVDictionary *opts,
     uint32_t sup_layer_count;
     VkLayerProperties *sup_layers;
 
-    AVDictionaryEntry *user_layers;
+    const AVDictionaryEntry *user_layers;
     char *user_layers_str = NULL;
     char *save, *token;
 
     const char **enabled_layers = NULL;
     uint32_t enabled_layers_count = 0;
 
-    AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0);
+    const AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0);
     int debug = debug_opt && strtol(debug_opt->value, NULL, 10);
 
     /* If `debug=0`, enable no layers at all. */
@@ -1187,7 +1187,7 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx,
 {
     int err = 0;
     VkResult ret;
-    AVDictionaryEntry *opt_d;
+    const AVDictionaryEntry *opt_d;
     VulkanDevicePriv *p = ctx->internal->priv;
     FFVulkanFunctions *vk = &p->vkctx.vkfn;
     AVVulkanDeviceContext *hwctx = ctx->hwctx;
diff --git a/libavutil/version.h b/libavutil/version.h
index 24af520e08..3ac7ff2606 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -119,6 +119,7 @@
 #define FF_API_FRAME_KEY                (LIBAVUTIL_VERSION_MAJOR < 59)
 #define FF_API_PALETTE_HAS_CHANGED      (LIBAVUTIL_VERSION_MAJOR < 59)
 #define FF_API_VULKAN_CONTIGUOUS_MEMORY (LIBAVUTIL_VERSION_MAJOR < 59)
+#define FF_API_AV_DICT_GET_NOT_CONST    (LIBAVUTIL_VERSION_MAJOR < 59)
 
 /**
  * @}
diff --git a/tests/api/api-threadmessage-test.c b/tests/api/api-threadmessage-test.c
index c96b473c43..c37c081249 100644
--- a/tests/api/api-threadmessage-test.c
+++ b/tests/api/api-threadmessage-test.c
@@ -137,7 +137,7 @@ static void *receiver_thread(void *arg)
         } else {
             struct message msg;
             AVDictionary *meta;
-            AVDictionaryEntry *e;
+            const AVDictionaryEntry *e;
 
             ret = av_thread_message_queue_recv(rd->queue, &msg, 0);
             if (ret < 0)
-- 
2.37.0 (Apple Git-136)

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH 2/3] avformat/tee: use av_dict_pop
  2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 2/3] avformat/tee: use av_dict_pop Marvin Scholz
@ 2023-06-25 12:07   ` "zhilizhao(赵志立)"
  0 siblings, 0 replies; 32+ messages in thread
From: "zhilizhao(赵志立)" @ 2023-06-25 12:07 UTC (permalink / raw)
  To: FFmpeg development discussions and patches; +Cc: Marvin Scholz



> On May 1, 2023, at 19:44, Marvin Scholz <epirat07@gmail.com> wrote:
> 
> This is a well-defined way to "steal" the value of the dict entry.
> ---
> libavformat/tee.c | 9 +++++----
> 1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/libavformat/tee.c b/libavformat/tee.c
> index cb555f52fd..70f3f2eb29 100644
> --- a/libavformat/tee.c
> +++ b/libavformat/tee.c
> @@ -157,6 +157,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
> {
>     int i, ret;
>     AVDictionary *options = NULL, *bsf_options = NULL;
> +    char *entry_val = NULL;
>     AVDictionaryEntry *entry;
>     char *filename;
>     char *format = NULL, *select = NULL, *on_fail = NULL;
> @@ -171,15 +172,15 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
>         return ret;
> 
> #define CONSUME_OPTION(option, field, action) do {                      \
> -        if ((entry = av_dict_get(options, option, NULL, 0))) {          \
> -            field = entry->value;                                       \
> +        if ((!av_dict_pop(&options, option, NULL, &entry_val, 0))) {    \
> +            field = entry_val;                                          \

Nit: You can remove the extra level of parentheses now.

>             { action }                                                  \
> -            av_dict_set(&options, option, NULL, 0);                     \
> +            av_freep(&entry_val);                                       \
>         }                                                               \
>     } while (0)
> #define STEAL_OPTION(option, field)                                     \
>     CONSUME_OPTION(option, field,                                       \
> -                   entry->value = NULL; /* prevent it from being freed */)
> +                   entry_val = NULL; /* prevent it from being freed */)
> #define PROCESS_OPTION(option, field, function, on_error)               \
>     CONSUME_OPTION(option, field, if ((ret = function) < 0) { { on_error } goto end; })
> 
> -- 
> 2.37.0 (Apple Git-136)
> 
> _______________________________________________
> 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".

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-06-25 10:49 ` [FFmpeg-devel] [PATCH v2 " Marvin Scholz
  2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 2/3] avformat/tee: use av_dict_pop Marvin Scholz
  2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 3/3] avutil/dict: constify av_dict_get return Marvin Scholz
@ 2023-07-02  8:43   ` Stefano Sabatini
  2023-07-02 11:49     ` Marvin Scholz
  2023-07-03  0:18   ` Andreas Rheinhardt
  3 siblings, 1 reply; 32+ messages in thread
From: Stefano Sabatini @ 2023-07-02  8:43 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On date Sunday 2023-06-25 12:49:05 +0200, Marvin Scholz wrote:
> This new API allows to remove an entry and obtain ownership of the
> key/value that was associated with the removed entry.
> ---
> 
> Changes since v1:
> - Clarify documentation about av_free having to be used.
> - Fix fate test to not rely on specific error code value
> 
>  doc/APIchanges         |  4 ++++
>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>  libavutil/dict.h       | 26 ++++++++++++++++++++++++++
>  libavutil/tests/dict.c | 38 ++++++++++++++++++++++++++++++++++++++
>  libavutil/version.h    |  4 ++--
>  tests/ref/fate/dict    | 12 ++++++++++++
>  6 files changed, 109 insertions(+), 2 deletions(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index f040211f7d..d55821f682 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>  
>  API changes, most recent first:
>  
> +2023-06-02 - xxxxxxxxxx - lavu 58.14.100 - dict.h
> +  Add av_dict_pop() to remove an entry from a dict
> +  and get ownership of the removed key/value.
> +
>  2023-05-29 - xxxxxxxxxx - lavc 60.16.100 - avcodec.h codec_id.h
>    Add AV_CODEC_ID_EVC, FF_PROFILE_EVC_BASELINE, and FF_PROFILE_EVC_MAIN.
>  
> diff --git a/libavutil/dict.c b/libavutil/dict.c
> index f673977a98..ac41771994 100644
> --- a/libavutil/dict.c
> +++ b/libavutil/dict.c
> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>      return av_dict_set(pm, key, valuestr, flags);
>  }
>  
> +int av_dict_pop(AVDictionary **pm, const char *key,
> +                char **out_key, char **out_value, int flags)
> +{
> +    AVDictionary *m = *pm;
> +    AVDictionaryEntry *entry = NULL;
> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
> +    if (!entry)
> +        return AVERROR(ENOENT);
> +
> +    if (out_key)
> +        *out_key = entry->key;
> +    else
> +        av_free(entry->key);
> +
> +    if (out_value)
> +        *out_value = entry->value;
> +    else
> +        av_free(entry->value);
> +
> +    *entry = m->elems[--m->count];
> +    if (m && !m->count) {
> +        av_freep(&m->elems);
> +        av_freep(pm);
> +    }
> +    return 0;
> +}
> +
>  static int parse_key_value_pair(AVDictionary **pm, const char **buf,
>                                  const char *key_val_sep, const char *pairs_sep,
>                                  int flags)
> diff --git a/libavutil/dict.h b/libavutil/dict.h
> index 713c9e361a..31d38dabec 100644
> --- a/libavutil/dict.h
> +++ b/libavutil/dict.h
> @@ -172,6 +172,32 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>   */
>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>  
> +/**
> + * Remove the entry with the given key from the dictionary.
> + *
> + * Search for an entry matching @p key and remove it, if found. Optionally
> + * the found key and/or value can be returned using the @p out_key and
> + * @p out_value arguments.

Note: I checked the code and we see that in some cases we use `param`
(e.g. in mem.h) but I prefer this format (although apparently not used
in other places) since it looks more consistent with the doxygen
syntax.

> + *
> + * If more than one entry matches, only one entry is removed and returned
> + * on each call. Which entry is returned first in that case is undefined.
> + *
> + * @param pm        Pointer to a pointer to a dictionary struct.
> + * @param key       Entry key to match.
> + * @param out_key   Pointer whose pointee will be set to the matched
> + *                  entry key. Must be freed using av_dict_free() by
> + *                  the caller. May be NULL.
> + * @param out_value Pointer whose pointee will be set to the matched
> + *                  entry value. Must be freed using av_dict_free() by
> + *                  the caller. May be NULL.

missing docs for flags, something like:
@param flags flags passed to av_dict_get to look for the entry

should be fine

[...]

Looks good otherwise, thanks. 

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 2/3] avformat/tee: use av_dict_pop
  2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 2/3] avformat/tee: use av_dict_pop Marvin Scholz
@ 2023-07-02  8:47     ` Stefano Sabatini
  0 siblings, 0 replies; 32+ messages in thread
From: Stefano Sabatini @ 2023-07-02  8:47 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On date Sunday 2023-06-25 12:49:06 +0200, Marvin Scholz wrote:
> This is a well-defined way to "steal" the value of the dict entry.
> ---
>  libavformat/tee.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/libavformat/tee.c b/libavformat/tee.c
> index cb555f52fd..70f3f2eb29 100644
> --- a/libavformat/tee.c
> +++ b/libavformat/tee.c
> @@ -157,6 +157,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
>  {
>      int i, ret;
>      AVDictionary *options = NULL, *bsf_options = NULL;
> +    char *entry_val = NULL;
>      AVDictionaryEntry *entry;
>      char *filename;
>      char *format = NULL, *select = NULL, *on_fail = NULL;
> @@ -171,15 +172,15 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
>          return ret;
>  
>  #define CONSUME_OPTION(option, field, action) do {                      \
> -        if ((entry = av_dict_get(options, option, NULL, 0))) {          \
> -            field = entry->value;                                       \
> +        if ((!av_dict_pop(&options, option, NULL, &entry_val, 0))) {    \
> +            field = entry_val;                                          \
>              { action }                                                  \
> -            av_dict_set(&options, option, NULL, 0);                     \
> +            av_freep(&entry_val);                                       \
>          }                                                               \
>      } while (0)
>  #define STEAL_OPTION(option, field)                                     \
>      CONSUME_OPTION(option, field,                                       \
> -                   entry->value = NULL; /* prevent it from being freed */)
> +                   entry_val = NULL; /* prevent it from being freed */)
>  #define PROCESS_OPTION(option, field, function, on_error)               \
>      CONSUME_OPTION(option, field, if ((ret = function) < 0) { { on_error } goto end; })

LGTM.
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 3/3] avutil/dict: constify av_dict_get return
  2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 3/3] avutil/dict: constify av_dict_get return Marvin Scholz
@ 2023-07-02  9:06     ` Stefano Sabatini
  0 siblings, 0 replies; 32+ messages in thread
From: Stefano Sabatini @ 2023-07-02  9:06 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On date Sunday 2023-06-25 12:49:07 +0200, Marvin Scholz wrote:
> ---
>  doc/examples/qsv_transcode.c       |  2 +-
>  libavcodec/libaomenc.c             |  2 +-
>  libavcodec/libkvazaar.c            |  2 +-
>  libavcodec/libsvtav1.c             |  2 +-
>  libavcodec/libvpxenc.c             |  2 +-
>  libavcodec/libx264.c               |  2 +-
>  libavcodec/libx265.c               |  2 +-
>  libavcodec/mjpegdec.c              |  2 +-
>  libavcodec/qsvenc.c                |  2 +-
>  libavfilter/avfilter.c             |  2 +-
>  libavfilter/f_bench.c              |  2 +-
>  libavfilter/f_drawgraph.c          |  2 +-
>  libavfilter/f_select.c             |  4 +--
>  libavfilter/vf_cover_rect.c        |  2 +-
>  libavfilter/vf_drawtext.c          |  2 +-
>  libavformat/aiffenc.c              |  2 +-
>  libavformat/argo_asf.c             |  2 +-
>  libavformat/asfenc.c               |  6 ++--
>  libavformat/au.c                   |  2 +-
>  libavformat/avformat.h             |  2 +-
>  libavformat/avidec.c               |  2 +-
>  libavformat/avienc.c               |  2 +-
>  libavformat/avio.c                 |  4 +--
>  libavformat/dashenc.c              |  6 ++--
>  libavformat/dvenc.c                |  2 +-
>  libavformat/flacdec.c              |  2 +-
>  libavformat/flacenc.c              |  6 ++--
>  libavformat/flvdec.c               |  2 +-
>  libavformat/gxfenc.c               |  2 +-
>  libavformat/http.c                 |  8 +++---
>  libavformat/id3v2.c                |  6 ++--
>  libavformat/id3v2enc.c             |  2 +-
>  libavformat/imfdec.c               |  2 +-
>  libavformat/matroskadec.c          |  2 +-
>  libavformat/mov.c                  |  6 ++--
>  libavformat/movenc.c               | 46 +++++++++++++++---------------
>  libavformat/mp3enc.c               |  6 ++--
>  libavformat/mpegtsenc.c            |  6 ++--
>  libavformat/mux.c                  |  2 +-
>  libavformat/mux_utils.c            |  2 +-
>  libavformat/mxfenc.c               | 14 ++++-----
>  libavformat/riffenc.c              |  2 +-
>  libavformat/rmenc.c                |  2 +-
>  libavformat/sapenc.c               |  2 +-
>  libavformat/sdp.c                  |  2 +-
>  libavformat/segment.c              |  4 +--
>  libavformat/soxenc.c               |  2 +-
>  libavformat/tee.c                  |  2 +-
>  libavformat/ttmlenc.c              |  4 +--
>  libavformat/wavenc.c               |  4 +--
>  libavformat/webmdashenc.c          | 30 +++++++++----------
>  libavutil/dict.c                   |  9 +++++-
>  libavutil/dict.h                   |  5 ++++
>  libavutil/hwcontext_cuda.c         |  2 +-
>  libavutil/hwcontext_qsv.c          |  2 +-
>  libavutil/hwcontext_vulkan.c       |  8 +++---
>  libavutil/version.h                |  1 +
>  tests/api/api-threadmessage-test.c |  2 +-
>  58 files changed, 136 insertions(+), 123 deletions(-)

LGTM

Note: how does FFmpeg document major bump changes? I wonder if we
should add a section in APIChanges to simplify users' transition.

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-07-02  8:43   ` [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop Stefano Sabatini
@ 2023-07-02 11:49     ` Marvin Scholz
  0 siblings, 0 replies; 32+ messages in thread
From: Marvin Scholz @ 2023-07-02 11:49 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

On 2 Jul 2023, at 10:43, Stefano Sabatini wrote:

> On date Sunday 2023-06-25 12:49:05 +0200, Marvin Scholz wrote:
>> This new API allows to remove an entry and obtain ownership of the
>> key/value that was associated with the removed entry.
>> ---
>>
>> Changes since v1:
>> - Clarify documentation about av_free having to be used.
>> - Fix fate test to not rely on specific error code value
>>
>>  doc/APIchanges         |  4 ++++
>>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>>  libavutil/dict.h       | 26 ++++++++++++++++++++++++++
>>  libavutil/tests/dict.c | 38 ++++++++++++++++++++++++++++++++++++++
>>  libavutil/version.h    |  4 ++--
>>  tests/ref/fate/dict    | 12 ++++++++++++
>>  6 files changed, 109 insertions(+), 2 deletions(-)
>>
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index f040211f7d..d55821f682 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>>
>>  API changes, most recent first:
>>
>> +2023-06-02 - xxxxxxxxxx - lavu 58.14.100 - dict.h
>> +  Add av_dict_pop() to remove an entry from a dict
>> +  and get ownership of the removed key/value.
>> +
>>  2023-05-29 - xxxxxxxxxx - lavc 60.16.100 - avcodec.h codec_id.h
>>    Add AV_CODEC_ID_EVC, FF_PROFILE_EVC_BASELINE, and FF_PROFILE_EVC_MAIN.
>>
>> diff --git a/libavutil/dict.c b/libavutil/dict.c
>> index f673977a98..ac41771994 100644
>> --- a/libavutil/dict.c
>> +++ b/libavutil/dict.c
>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>>      return av_dict_set(pm, key, valuestr, flags);
>>  }
>>
>> +int av_dict_pop(AVDictionary **pm, const char *key,
>> +                char **out_key, char **out_value, int flags)
>> +{
>> +    AVDictionary *m = *pm;
>> +    AVDictionaryEntry *entry = NULL;
>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
>> +    if (!entry)
>> +        return AVERROR(ENOENT);
>> +
>> +    if (out_key)
>> +        *out_key = entry->key;
>> +    else
>> +        av_free(entry->key);
>> +
>> +    if (out_value)
>> +        *out_value = entry->value;
>> +    else
>> +        av_free(entry->value);
>> +
>> +    *entry = m->elems[--m->count];
>> +    if (m && !m->count) {
>> +        av_freep(&m->elems);
>> +        av_freep(pm);
>> +    }
>> +    return 0;
>> +}
>> +
>>  static int parse_key_value_pair(AVDictionary **pm, const char **buf,
>>                                  const char *key_val_sep, const char *pairs_sep,
>>                                  int flags)
>> diff --git a/libavutil/dict.h b/libavutil/dict.h
>> index 713c9e361a..31d38dabec 100644
>> --- a/libavutil/dict.h
>> +++ b/libavutil/dict.h
>> @@ -172,6 +172,32 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>>   */
>>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>>
>> +/**
>> + * Remove the entry with the given key from the dictionary.
>> + *
>> + * Search for an entry matching @p key and remove it, if found. Optionally
>> + * the found key and/or value can be returned using the @p out_key and
>> + * @p out_value arguments.
>
> Note: I checked the code and we see that in some cases we use `param`
> (e.g. in mem.h) but I prefer this format (although apparently not used
> in other places) since it looks more consistent with the doxygen
> syntax.
>
>> + *
>> + * If more than one entry matches, only one entry is removed and returned
>> + * on each call. Which entry is returned first in that case is undefined.
>> + *
>> + * @param pm        Pointer to a pointer to a dictionary struct.
>> + * @param key       Entry key to match.
>> + * @param out_key   Pointer whose pointee will be set to the matched
>> + *                  entry key. Must be freed using av_dict_free() by
>> + *                  the caller. May be NULL.
>> + * @param out_value Pointer whose pointee will be set to the matched
>> + *                  entry value. Must be freed using av_dict_free() by
>> + *                  the caller. May be NULL.
>
> missing docs for flags, something like:
> @param flags flags passed to av_dict_get to look for the entry
>
> should be fine
>

Can whoever ends up merging this maybe add that?
If not, I can send a new revision with this change next weekend or so.

> [...]
>
> Looks good otherwise, thanks.
>
> _______________________________________________
> 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".
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-06-25 10:49 ` [FFmpeg-devel] [PATCH v2 " Marvin Scholz
                     ` (2 preceding siblings ...)
  2023-07-02  8:43   ` [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop Stefano Sabatini
@ 2023-07-03  0:18   ` Andreas Rheinhardt
  2023-07-03  9:11     ` Marvin Scholz
  3 siblings, 1 reply; 32+ messages in thread
From: Andreas Rheinhardt @ 2023-07-03  0:18 UTC (permalink / raw)
  To: ffmpeg-devel

Marvin Scholz:
> This new API allows to remove an entry and obtain ownership of the
> key/value that was associated with the removed entry.
> ---
> 
> Changes since v1:
> - Clarify documentation about av_free having to be used.
> - Fix fate test to not rely on specific error code value
> 
>  doc/APIchanges         |  4 ++++
>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>  libavutil/dict.h       | 26 ++++++++++++++++++++++++++
>  libavutil/tests/dict.c | 38 ++++++++++++++++++++++++++++++++++++++
>  libavutil/version.h    |  4 ++--
>  tests/ref/fate/dict    | 12 ++++++++++++
>  6 files changed, 109 insertions(+), 2 deletions(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index f040211f7d..d55821f682 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>  
>  API changes, most recent first:
>  
> +2023-06-02 - xxxxxxxxxx - lavu 58.14.100 - dict.h
> +  Add av_dict_pop() to remove an entry from a dict
> +  and get ownership of the removed key/value.
> +
>  2023-05-29 - xxxxxxxxxx - lavc 60.16.100 - avcodec.h codec_id.h
>    Add AV_CODEC_ID_EVC, FF_PROFILE_EVC_BASELINE, and FF_PROFILE_EVC_MAIN.
>  
> diff --git a/libavutil/dict.c b/libavutil/dict.c
> index f673977a98..ac41771994 100644
> --- a/libavutil/dict.c
> +++ b/libavutil/dict.c
> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>      return av_dict_set(pm, key, valuestr, flags);
>  }
>  
> +int av_dict_pop(AVDictionary **pm, const char *key,
> +                char **out_key, char **out_value, int flags)
> +{
> +    AVDictionary *m = *pm;
> +    AVDictionaryEntry *entry = NULL;
Why don't you merge this initialization and the assignment below?

> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
> +    if (!entry)
> +        return AVERROR(ENOENT);
> +
> +    if (out_key)
> +        *out_key = entry->key;
> +    else
> +        av_free(entry->key);
> +
> +    if (out_value)
> +        *out_value = entry->value;
> +    else
> +        av_free(entry->value);
> +
> +    *entry = m->elems[--m->count];
> +    if (m && !m->count) {

The check for m is completely unnecessary; Coverity will probably
complain about this (because this check implies that m can be NULL, but
then the line above the check would crash).

> +        av_freep(&m->elems);
> +        av_freep(pm);
> +    }
> +    return 0;
> +}
> +
>  static int parse_key_value_pair(AVDictionary **pm, const char **buf,
>                                  const char *key_val_sep, const char *pairs_sep,
>                                  int flags)
> diff --git a/libavutil/dict.h b/libavutil/dict.h
> index 713c9e361a..31d38dabec 100644
> --- a/libavutil/dict.h
> +++ b/libavutil/dict.h
> @@ -172,6 +172,32 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>   */
>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>  
> +/**
> + * Remove the entry with the given key from the dictionary.
> + *
> + * Search for an entry matching @p key and remove it, if found. Optionally
> + * the found key and/or value can be returned using the @p out_key and
> + * @p out_value arguments.
> + *
> + * If more than one entry matches, only one entry is removed and returned
> + * on each call. Which entry is returned first in that case is undefined.
> + *
> + * @param pm        Pointer to a pointer to a dictionary struct.
> + * @param key       Entry key to match.
> + * @param out_key   Pointer whose pointee will be set to the matched
> + *                  entry key. Must be freed using av_dict_free() by

This is wrong: It must be freed using av_free() (or av_freep()); same below.

> + *                  the caller. May be NULL.
> + * @param out_value Pointer whose pointee will be set to the matched
> + *                  entry value. Must be freed using av_dict_free() by
> + *                  the caller. May be NULL.
> + *
> + * @retval 0                            Success
> + * @retval AVERROR(ENOENT)              No item for the given key found
> + * @retval "Other (negative) AVERROR"   Other failure
> + */
> +int av_dict_pop(AVDictionary **pm, const char *key,
> +                char **out_key, char **out_value, int flags);

It is possible to store multiple entries with the same value in an
AVDictionary. This function is not designed to handle this case, as one
can't tell it which one one wants to pop (IIRC the rest of the API does
not properly support this either, but that is not a reason to add a new
API with this limitation).

Furthermore, while this may be used to avoid a few allocations with the
current implementation, said implementation is not guaranteed to stay
this way.

Finally, are there more intended uses than the one in the second patch?
If so, this could also be simply fixed by strduping the value without
any need for a further API addition.

> +
>  /**
>   * Parse the key/value pairs list and add the parsed entries to a dictionary.
>   *
> diff --git a/libavutil/tests/dict.c b/libavutil/tests/dict.c
> index bececefb31..06d94ecc9a 100644
> --- a/libavutil/tests/dict.c
> +++ b/libavutil/tests/dict.c
> @@ -158,5 +158,43 @@ int main(void)
>      printf("%s\n", e->value);
>      av_dict_free(&dict);
>  
> +    char *key, *val = NULL;
> +    int ret;
> +    printf("\nTesting av_dict_pop() with existing AVDictionaryEntry.key as key\n");
> +    av_dict_set(&dict, "test-key", "test-value", 0);
> +    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
> +    printf("%s: %s (Return code: %i)\n",
> +        (key) ? key : "(null)",
> +        (val) ? val : "(null)", ret);
> +    e = av_dict_get(dict, "test-key", NULL, 0);
> +    printf("%s\n", (e) ? e->value : "(null)");
> +    av_freep(&key);
> +    av_freep(&val);
> +
> +    printf("\nTesting av_dict_pop() with nonexistent key\n");
> +    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
> +    printf("%s: %s ",
> +        (key) ? key : "(null)",
> +        (val) ? val : "(null)");
> +    if (ret == AVERROR(ENOENT))
> +        printf("(Return code: ENOENT)\n");
> +    else
> +        printf("(Return code: Unexpected error: %i)\n", ret);
> +    e = av_dict_get(dict, "test-key", NULL, 0);
> +    printf("%s\n", (e) ? e->value : "(null)");
> +    av_freep(&key);
> +    av_freep(&val);
> +
> +    printf("\nTesting av_dict_pop() with prefix key match\n");
> +    av_dict_set(&dict, "prefix-test-key", "test-value", 0);
> +    ret = av_dict_pop(&dict, "prefix-test", &key, &val, AV_DICT_IGNORE_SUFFIX);
> +    printf("%s: %s (Return code: %i)\n",
> +        (key) ? key : "(null)",
> +        (val) ? val : "(null)", ret);
> +    e = av_dict_get(dict, "prefix-test", NULL, AV_DICT_IGNORE_SUFFIX);
> +    printf("%s\n", (e) ? e->value : "(null)");
> +    av_freep(&key);
> +    av_freep(&val);
> +
>      return 0;
>  }
> diff --git a/libavutil/version.h b/libavutil/version.h
> index 17a6d296a6..24af520e08 100644
> --- a/libavutil/version.h
> +++ b/libavutil/version.h
> @@ -79,8 +79,8 @@
>   */
>  
>  #define LIBAVUTIL_VERSION_MAJOR  58
> -#define LIBAVUTIL_VERSION_MINOR  13
> -#define LIBAVUTIL_VERSION_MICRO 101
> +#define LIBAVUTIL_VERSION_MINOR  14
> +#define LIBAVUTIL_VERSION_MICRO 100
>  
>  #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
>                                                 LIBAVUTIL_VERSION_MINOR, \
> diff --git a/tests/ref/fate/dict b/tests/ref/fate/dict
> index 7205e4c845..afa87aca5f 100644
> --- a/tests/ref/fate/dict
> +++ b/tests/ref/fate/dict
> @@ -48,3 +48,15 @@ Testing av_dict_set_int()
>  Testing av_dict_set() with existing AVDictionaryEntry.key as key
>  new val OK
>  new val OK
> +
> +Testing av_dict_pop() with existing AVDictionaryEntry.key as key
> +test-key: test-value (Return code: 0)
> +(null)
> +
> +Testing av_dict_pop() with nonexistent key
> +(null): (null) (Return code: ENOENT)
> +(null)
> +
> +Testing av_dict_pop() with prefix key match
> +prefix-test-key: test-value (Return code: 0)
> +(null)

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-07-03  0:18   ` Andreas Rheinhardt
@ 2023-07-03  9:11     ` Marvin Scholz
  2023-07-03 18:02       ` Andreas Rheinhardt
  0 siblings, 1 reply; 32+ messages in thread
From: Marvin Scholz @ 2023-07-03  9:11 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



On 3 Jul 2023, at 2:18, Andreas Rheinhardt wrote:

> Marvin Scholz:
>> This new API allows to remove an entry and obtain ownership of the
>> key/value that was associated with the removed entry.
>> ---
>>
>> Changes since v1:
>> - Clarify documentation about av_free having to be used.
>> - Fix fate test to not rely on specific error code value
>>
>>  doc/APIchanges         |  4 ++++
>>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>>  libavutil/dict.h       | 26 ++++++++++++++++++++++++++
>>  libavutil/tests/dict.c | 38 ++++++++++++++++++++++++++++++++++++++
>>  libavutil/version.h    |  4 ++--
>>  tests/ref/fate/dict    | 12 ++++++++++++
>>  6 files changed, 109 insertions(+), 2 deletions(-)
>>
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index f040211f7d..d55821f682 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>>
>>  API changes, most recent first:
>>
>> +2023-06-02 - xxxxxxxxxx - lavu 58.14.100 - dict.h
>> +  Add av_dict_pop() to remove an entry from a dict
>> +  and get ownership of the removed key/value.
>> +
>>  2023-05-29 - xxxxxxxxxx - lavc 60.16.100 - avcodec.h codec_id.h
>>    Add AV_CODEC_ID_EVC, FF_PROFILE_EVC_BASELINE, and FF_PROFILE_EVC_MAIN.
>>
>> diff --git a/libavutil/dict.c b/libavutil/dict.c
>> index f673977a98..ac41771994 100644
>> --- a/libavutil/dict.c
>> +++ b/libavutil/dict.c
>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>>      return av_dict_set(pm, key, valuestr, flags);
>>  }
>>
>> +int av_dict_pop(AVDictionary **pm, const char *key,
>> +                char **out_key, char **out_value, int flags)
>> +{
>> +    AVDictionary *m = *pm;
>> +    AVDictionaryEntry *entry = NULL;
> Why don't you merge this initialization and the assignment below?
>
>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
>> +    if (!entry)
>> +        return AVERROR(ENOENT);
>> +
>> +    if (out_key)
>> +        *out_key = entry->key;
>> +    else
>> +        av_free(entry->key);
>> +
>> +    if (out_value)
>> +        *out_value = entry->value;
>> +    else
>> +        av_free(entry->value);
>> +
>> +    *entry = m->elems[--m->count];
>> +    if (m && !m->count) {
>
> The check for m is completely unnecessary; Coverity will probably
> complain about this (because this check implies that m can be NULL, but
> then the line above the check would crash).
>
>> +        av_freep(&m->elems);
>> +        av_freep(pm);
>> +    }
>> +    return 0;
>> +}
>> +
>>  static int parse_key_value_pair(AVDictionary **pm, const char **buf,
>>                                  const char *key_val_sep, const char *pairs_sep,
>>                                  int flags)
>> diff --git a/libavutil/dict.h b/libavutil/dict.h
>> index 713c9e361a..31d38dabec 100644
>> --- a/libavutil/dict.h
>> +++ b/libavutil/dict.h
>> @@ -172,6 +172,32 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>>   */
>>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>>
>> +/**
>> + * Remove the entry with the given key from the dictionary.
>> + *
>> + * Search for an entry matching @p key and remove it, if found. Optionally
>> + * the found key and/or value can be returned using the @p out_key and
>> + * @p out_value arguments.
>> + *
>> + * If more than one entry matches, only one entry is removed and returned
>> + * on each call. Which entry is returned first in that case is undefined.
>> + *
>> + * @param pm        Pointer to a pointer to a dictionary struct.
>> + * @param key       Entry key to match.
>> + * @param out_key   Pointer whose pointee will be set to the matched
>> + *                  entry key. Must be freed using av_dict_free() by
>
> This is wrong: It must be freed using av_free() (or av_freep()); same below.

Indeed, copy paste mistake, sorry.

>
>> + *                  the caller. May be NULL.
>> + * @param out_value Pointer whose pointee will be set to the matched
>> + *                  entry value. Must be freed using av_dict_free() by
>> + *                  the caller. May be NULL.
>> + *
>> + * @retval 0                            Success
>> + * @retval AVERROR(ENOENT)              No item for the given key found
>> + * @retval "Other (negative) AVERROR"   Other failure
>> + */
>> +int av_dict_pop(AVDictionary **pm, const char *key,
>> +                char **out_key, char **out_value, int flags);
>
> It is possible to store multiple entries with the same value in an
> AVDictionary. This function is not designed to handle this case, as one
> can't tell it which one one wants to pop (IIRC the rest of the API does
> not properly support this either, but that is not a reason to add a new
> API with this limitation).

I honestly can't think of a sensible API design for this,
if you have any idea feel free to share.

If the value is known before, using av_dict_pop is useless anyway
as there would be not need to obtain the value if it's already known?

>
> Furthermore, while this may be used to avoid a few allocations with the
> current implementation, said implementation is not guaranteed to stay
> this way.
>

I would assume whatever future changes we do, the dictionary would continue
to hold ownership of the items so a way to remove it from the dict
and transferring ownership seems useful to me.

However indeed there are not really any places in code where this is
done, but then again there was no official way to do it before, so
there might be more cases that benefit from this.

> Finally, are there more intended uses than the one in the second patch?
> If so, this could also be simply fixed by strduping the value without
> any need for a further API addition.
>
>> +
>>  /**
>>   * Parse the key/value pairs list and add the parsed entries to a dictionary.
>>   *
>> diff --git a/libavutil/tests/dict.c b/libavutil/tests/dict.c
>> index bececefb31..06d94ecc9a 100644
>> --- a/libavutil/tests/dict.c
>> +++ b/libavutil/tests/dict.c
>> @@ -158,5 +158,43 @@ int main(void)
>>      printf("%s\n", e->value);
>>      av_dict_free(&dict);
>>
>> +    char *key, *val = NULL;
>> +    int ret;
>> +    printf("\nTesting av_dict_pop() with existing AVDictionaryEntry.key as key\n");
>> +    av_dict_set(&dict, "test-key", "test-value", 0);
>> +    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
>> +    printf("%s: %s (Return code: %i)\n",
>> +        (key) ? key : "(null)",
>> +        (val) ? val : "(null)", ret);
>> +    e = av_dict_get(dict, "test-key", NULL, 0);
>> +    printf("%s\n", (e) ? e->value : "(null)");
>> +    av_freep(&key);
>> +    av_freep(&val);
>> +
>> +    printf("\nTesting av_dict_pop() with nonexistent key\n");
>> +    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
>> +    printf("%s: %s ",
>> +        (key) ? key : "(null)",
>> +        (val) ? val : "(null)");
>> +    if (ret == AVERROR(ENOENT))
>> +        printf("(Return code: ENOENT)\n");
>> +    else
>> +        printf("(Return code: Unexpected error: %i)\n", ret);
>> +    e = av_dict_get(dict, "test-key", NULL, 0);
>> +    printf("%s\n", (e) ? e->value : "(null)");
>> +    av_freep(&key);
>> +    av_freep(&val);
>> +
>> +    printf("\nTesting av_dict_pop() with prefix key match\n");
>> +    av_dict_set(&dict, "prefix-test-key", "test-value", 0);
>> +    ret = av_dict_pop(&dict, "prefix-test", &key, &val, AV_DICT_IGNORE_SUFFIX);
>> +    printf("%s: %s (Return code: %i)\n",
>> +        (key) ? key : "(null)",
>> +        (val) ? val : "(null)", ret);
>> +    e = av_dict_get(dict, "prefix-test", NULL, AV_DICT_IGNORE_SUFFIX);
>> +    printf("%s\n", (e) ? e->value : "(null)");
>> +    av_freep(&key);
>> +    av_freep(&val);
>> +
>>      return 0;
>>  }
>> diff --git a/libavutil/version.h b/libavutil/version.h
>> index 17a6d296a6..24af520e08 100644
>> --- a/libavutil/version.h
>> +++ b/libavutil/version.h
>> @@ -79,8 +79,8 @@
>>   */
>>
>>  #define LIBAVUTIL_VERSION_MAJOR  58
>> -#define LIBAVUTIL_VERSION_MINOR  13
>> -#define LIBAVUTIL_VERSION_MICRO 101
>> +#define LIBAVUTIL_VERSION_MINOR  14
>> +#define LIBAVUTIL_VERSION_MICRO 100
>>
>>  #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
>>                                                 LIBAVUTIL_VERSION_MINOR, \
>> diff --git a/tests/ref/fate/dict b/tests/ref/fate/dict
>> index 7205e4c845..afa87aca5f 100644
>> --- a/tests/ref/fate/dict
>> +++ b/tests/ref/fate/dict
>> @@ -48,3 +48,15 @@ Testing av_dict_set_int()
>>  Testing av_dict_set() with existing AVDictionaryEntry.key as key
>>  new val OK
>>  new val OK
>> +
>> +Testing av_dict_pop() with existing AVDictionaryEntry.key as key
>> +test-key: test-value (Return code: 0)
>> +(null)
>> +
>> +Testing av_dict_pop() with nonexistent key
>> +(null): (null) (Return code: ENOENT)
>> +(null)
>> +
>> +Testing av_dict_pop() with prefix key match
>> +prefix-test-key: test-value (Return code: 0)
>> +(null)
>
> _______________________________________________
> 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".
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-07-03  9:11     ` Marvin Scholz
@ 2023-07-03 18:02       ` Andreas Rheinhardt
  2023-07-03 22:41         ` Marvin Scholz
  2023-10-20  8:18         ` Anton Khirnov
  0 siblings, 2 replies; 32+ messages in thread
From: Andreas Rheinhardt @ 2023-07-03 18:02 UTC (permalink / raw)
  To: ffmpeg-devel

Marvin Scholz:
> 
> 
> On 3 Jul 2023, at 2:18, Andreas Rheinhardt wrote:
> 
>> Marvin Scholz:
>>> This new API allows to remove an entry and obtain ownership of the
>>> key/value that was associated with the removed entry.
>>> ---
>>>
>>> Changes since v1:
>>> - Clarify documentation about av_free having to be used.
>>> - Fix fate test to not rely on specific error code value
>>>
>>>  doc/APIchanges         |  4 ++++
>>>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>>>  libavutil/dict.h       | 26 ++++++++++++++++++++++++++
>>>  libavutil/tests/dict.c | 38 ++++++++++++++++++++++++++++++++++++++
>>>  libavutil/version.h    |  4 ++--
>>>  tests/ref/fate/dict    | 12 ++++++++++++
>>>  6 files changed, 109 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/doc/APIchanges b/doc/APIchanges
>>> index f040211f7d..d55821f682 100644
>>> --- a/doc/APIchanges
>>> +++ b/doc/APIchanges
>>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>>>
>>>  API changes, most recent first:
>>>
>>> +2023-06-02 - xxxxxxxxxx - lavu 58.14.100 - dict.h
>>> +  Add av_dict_pop() to remove an entry from a dict
>>> +  and get ownership of the removed key/value.
>>> +
>>>  2023-05-29 - xxxxxxxxxx - lavc 60.16.100 - avcodec.h codec_id.h
>>>    Add AV_CODEC_ID_EVC, FF_PROFILE_EVC_BASELINE, and FF_PROFILE_EVC_MAIN.
>>>
>>> diff --git a/libavutil/dict.c b/libavutil/dict.c
>>> index f673977a98..ac41771994 100644
>>> --- a/libavutil/dict.c
>>> +++ b/libavutil/dict.c
>>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>>>      return av_dict_set(pm, key, valuestr, flags);
>>>  }
>>>
>>> +int av_dict_pop(AVDictionary **pm, const char *key,
>>> +                char **out_key, char **out_value, int flags)
>>> +{
>>> +    AVDictionary *m = *pm;
>>> +    AVDictionaryEntry *entry = NULL;
>> Why don't you merge this initialization and the assignment below?
>>
>>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
>>> +    if (!entry)
>>> +        return AVERROR(ENOENT);
>>> +
>>> +    if (out_key)
>>> +        *out_key = entry->key;
>>> +    else
>>> +        av_free(entry->key);
>>> +
>>> +    if (out_value)
>>> +        *out_value = entry->value;
>>> +    else
>>> +        av_free(entry->value);
>>> +
>>> +    *entry = m->elems[--m->count];
>>> +    if (m && !m->count) {
>>
>> The check for m is completely unnecessary; Coverity will probably
>> complain about this (because this check implies that m can be NULL, but
>> then the line above the check would crash).
>>
>>> +        av_freep(&m->elems);
>>> +        av_freep(pm);
>>> +    }
>>> +    return 0;
>>> +}
>>> +
>>>  static int parse_key_value_pair(AVDictionary **pm, const char **buf,
>>>                                  const char *key_val_sep, const char *pairs_sep,
>>>                                  int flags)
>>> diff --git a/libavutil/dict.h b/libavutil/dict.h
>>> index 713c9e361a..31d38dabec 100644
>>> --- a/libavutil/dict.h
>>> +++ b/libavutil/dict.h
>>> @@ -172,6 +172,32 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>>>   */
>>>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>>>
>>> +/**
>>> + * Remove the entry with the given key from the dictionary.
>>> + *
>>> + * Search for an entry matching @p key and remove it, if found. Optionally
>>> + * the found key and/or value can be returned using the @p out_key and
>>> + * @p out_value arguments.
>>> + *
>>> + * If more than one entry matches, only one entry is removed and returned
>>> + * on each call. Which entry is returned first in that case is undefined.
>>> + *
>>> + * @param pm        Pointer to a pointer to a dictionary struct.
>>> + * @param key       Entry key to match.
>>> + * @param out_key   Pointer whose pointee will be set to the matched
>>> + *                  entry key. Must be freed using av_dict_free() by
>>
>> This is wrong: It must be freed using av_free() (or av_freep()); same below.
> 
> Indeed, copy paste mistake, sorry.
> 
>>
>>> + *                  the caller. May be NULL.
>>> + * @param out_value Pointer whose pointee will be set to the matched
>>> + *                  entry value. Must be freed using av_dict_free() by
>>> + *                  the caller. May be NULL.
>>> + *
>>> + * @retval 0                            Success
>>> + * @retval AVERROR(ENOENT)              No item for the given key found
>>> + * @retval "Other (negative) AVERROR"   Other failure
>>> + */
>>> +int av_dict_pop(AVDictionary **pm, const char *key,
>>> +                char **out_key, char **out_value, int flags);
>>
>> It is possible to store multiple entries with the same value in an
>> AVDictionary. This function is not designed to handle this case, as one
>> can't tell it which one one wants to pop (IIRC the rest of the API does
>> not properly support this either, but that is not a reason to add a new
>> API with this limitation).
> 
> I honestly can't think of a sensible API design for this,
> if you have any idea feel free to share.
> 

The only way I can think of that allows this is for the user to pass a
pointer to a (const) AVDictionaryEntry, namely the entry that the user
wishes to pop. This is of course cumbersome, because it would be two
function calls.

> If the value is known before, using av_dict_pop is useless anyway
> as there would be not need to obtain the value if it's already known?
> 

I don't really understand this. Having pointers to the strings is not
the same as owning the strings.

>>
>> Furthermore, while this may be used to avoid a few allocations with the
>> current implementation, said implementation is not guaranteed to stay
>> this way.
>>
> 
> I would assume whatever future changes we do, the dictionary would continue
> to hold ownership of the items so a way to remove it from the dict
> and transferring ownership seems useful to me.
> 

Of course the dict has ownership of the strings referred to by the
dictionary. But for this function to work as you wrote it, the strings
referred to by each entry need to be e.g. separately allocated; this may
or may not change (e.g. we may only allocate one key for all the
AVDictionaryEntries with the same key in the future).

> However indeed there are not really any places in code where this is
> done, but then again there was no official way to do it before, so
> there might be more cases that benefit from this.

Do you know whether there are library users that would benefit from this?

> 
>> Finally, are there more intended uses than the one in the second patch?
>> If so, this could also be simply fixed by strduping the value without
>> any need for a further API addition.
>>
>>> +
>>>  /**
>>>   * Parse the key/value pairs list and add the parsed entries to a dictionary.
>>>   *
>>> diff --git a/libavutil/tests/dict.c b/libavutil/tests/dict.c
>>> index bececefb31..06d94ecc9a 100644
>>> --- a/libavutil/tests/dict.c
>>> +++ b/libavutil/tests/dict.c
>>> @@ -158,5 +158,43 @@ int main(void)
>>>      printf("%s\n", e->value);
>>>      av_dict_free(&dict);
>>>
>>> +    char *key, *val = NULL;
>>> +    int ret;
>>> +    printf("\nTesting av_dict_pop() with existing AVDictionaryEntry.key as key\n");
>>> +    av_dict_set(&dict, "test-key", "test-value", 0);
>>> +    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
>>> +    printf("%s: %s (Return code: %i)\n",
>>> +        (key) ? key : "(null)",
>>> +        (val) ? val : "(null)", ret);
>>> +    e = av_dict_get(dict, "test-key", NULL, 0);
>>> +    printf("%s\n", (e) ? e->value : "(null)");
>>> +    av_freep(&key);
>>> +    av_freep(&val);
>>> +
>>> +    printf("\nTesting av_dict_pop() with nonexistent key\n");
>>> +    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
>>> +    printf("%s: %s ",
>>> +        (key) ? key : "(null)",
>>> +        (val) ? val : "(null)");
>>> +    if (ret == AVERROR(ENOENT))
>>> +        printf("(Return code: ENOENT)\n");
>>> +    else
>>> +        printf("(Return code: Unexpected error: %i)\n", ret);
>>> +    e = av_dict_get(dict, "test-key", NULL, 0);
>>> +    printf("%s\n", (e) ? e->value : "(null)");
>>> +    av_freep(&key);
>>> +    av_freep(&val);
>>> +
>>> +    printf("\nTesting av_dict_pop() with prefix key match\n");
>>> +    av_dict_set(&dict, "prefix-test-key", "test-value", 0);
>>> +    ret = av_dict_pop(&dict, "prefix-test", &key, &val, AV_DICT_IGNORE_SUFFIX);
>>> +    printf("%s: %s (Return code: %i)\n",
>>> +        (key) ? key : "(null)",
>>> +        (val) ? val : "(null)", ret);
>>> +    e = av_dict_get(dict, "prefix-test", NULL, AV_DICT_IGNORE_SUFFIX);
>>> +    printf("%s\n", (e) ? e->value : "(null)");
>>> +    av_freep(&key);
>>> +    av_freep(&val);
>>> +
>>>      return 0;
>>>  }
>>> diff --git a/libavutil/version.h b/libavutil/version.h
>>> index 17a6d296a6..24af520e08 100644
>>> --- a/libavutil/version.h
>>> +++ b/libavutil/version.h
>>> @@ -79,8 +79,8 @@
>>>   */
>>>
>>>  #define LIBAVUTIL_VERSION_MAJOR  58
>>> -#define LIBAVUTIL_VERSION_MINOR  13
>>> -#define LIBAVUTIL_VERSION_MICRO 101
>>> +#define LIBAVUTIL_VERSION_MINOR  14
>>> +#define LIBAVUTIL_VERSION_MICRO 100
>>>
>>>  #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
>>>                                                 LIBAVUTIL_VERSION_MINOR, \
>>> diff --git a/tests/ref/fate/dict b/tests/ref/fate/dict
>>> index 7205e4c845..afa87aca5f 100644
>>> --- a/tests/ref/fate/dict
>>> +++ b/tests/ref/fate/dict
>>> @@ -48,3 +48,15 @@ Testing av_dict_set_int()
>>>  Testing av_dict_set() with existing AVDictionaryEntry.key as key
>>>  new val OK
>>>  new val OK
>>> +
>>> +Testing av_dict_pop() with existing AVDictionaryEntry.key as key
>>> +test-key: test-value (Return code: 0)
>>> +(null)
>>> +
>>> +Testing av_dict_pop() with nonexistent key
>>> +(null): (null) (Return code: ENOENT)
>>> +(null)
>>> +
>>> +Testing av_dict_pop() with prefix key match
>>> +prefix-test-key: test-value (Return code: 0)
>>> +(null)
>>

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-07-03 18:02       ` Andreas Rheinhardt
@ 2023-07-03 22:41         ` Marvin Scholz
  2023-10-20  8:18         ` Anton Khirnov
  1 sibling, 0 replies; 32+ messages in thread
From: Marvin Scholz @ 2023-07-03 22:41 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



On 3 Jul 2023, at 20:02, Andreas Rheinhardt wrote:

> Marvin Scholz:
>>
>>
>> On 3 Jul 2023, at 2:18, Andreas Rheinhardt wrote:
>>
>>> Marvin Scholz:
>>>> This new API allows to remove an entry and obtain ownership of the
>>>> key/value that was associated with the removed entry.
>>>> ---
>>>>
>>>> Changes since v1:
>>>> - Clarify documentation about av_free having to be used.
>>>> - Fix fate test to not rely on specific error code value
>>>>
>>>>  doc/APIchanges         |  4 ++++
>>>>  libavutil/dict.c       | 27 +++++++++++++++++++++++++++
>>>>  libavutil/dict.h       | 26 ++++++++++++++++++++++++++
>>>>  libavutil/tests/dict.c | 38 ++++++++++++++++++++++++++++++++++++++
>>>>  libavutil/version.h    |  4 ++--
>>>>  tests/ref/fate/dict    | 12 ++++++++++++
>>>>  6 files changed, 109 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/doc/APIchanges b/doc/APIchanges
>>>> index f040211f7d..d55821f682 100644
>>>> --- a/doc/APIchanges
>>>> +++ b/doc/APIchanges
>>>> @@ -2,6 +2,10 @@ The last version increases of all libraries were on 2023-02-09
>>>>
>>>>  API changes, most recent first:
>>>>
>>>> +2023-06-02 - xxxxxxxxxx - lavu 58.14.100 - dict.h
>>>> +  Add av_dict_pop() to remove an entry from a dict
>>>> +  and get ownership of the removed key/value.
>>>> +
>>>>  2023-05-29 - xxxxxxxxxx - lavc 60.16.100 - avcodec.h codec_id.h
>>>>    Add AV_CODEC_ID_EVC, FF_PROFILE_EVC_BASELINE, and FF_PROFILE_EVC_MAIN.
>>>>
>>>> diff --git a/libavutil/dict.c b/libavutil/dict.c
>>>> index f673977a98..ac41771994 100644
>>>> --- a/libavutil/dict.c
>>>> +++ b/libavutil/dict.c
>>>> @@ -173,6 +173,33 @@ int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
>>>>      return av_dict_set(pm, key, valuestr, flags);
>>>>  }
>>>>
>>>> +int av_dict_pop(AVDictionary **pm, const char *key,
>>>> +                char **out_key, char **out_value, int flags)
>>>> +{
>>>> +    AVDictionary *m = *pm;
>>>> +    AVDictionaryEntry *entry = NULL;
>>> Why don't you merge this initialization and the assignment below?
>>>
>>>> +    entry = (AVDictionaryEntry *)av_dict_get(m, key, NULL, flags);
>>>> +    if (!entry)
>>>> +        return AVERROR(ENOENT);
>>>> +
>>>> +    if (out_key)
>>>> +        *out_key = entry->key;
>>>> +    else
>>>> +        av_free(entry->key);
>>>> +
>>>> +    if (out_value)
>>>> +        *out_value = entry->value;
>>>> +    else
>>>> +        av_free(entry->value);
>>>> +
>>>> +    *entry = m->elems[--m->count];
>>>> +    if (m && !m->count) {
>>>
>>> The check for m is completely unnecessary; Coverity will probably
>>> complain about this (because this check implies that m can be NULL, but
>>> then the line above the check would crash).
>>>
>>>> +        av_freep(&m->elems);
>>>> +        av_freep(pm);
>>>> +    }
>>>> +    return 0;
>>>> +}
>>>> +
>>>>  static int parse_key_value_pair(AVDictionary **pm, const char **buf,
>>>>                                  const char *key_val_sep, const char *pairs_sep,
>>>>                                  int flags)
>>>> diff --git a/libavutil/dict.h b/libavutil/dict.h
>>>> index 713c9e361a..31d38dabec 100644
>>>> --- a/libavutil/dict.h
>>>> +++ b/libavutil/dict.h
>>>> @@ -172,6 +172,32 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags
>>>>   */
>>>>  int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
>>>>
>>>> +/**
>>>> + * Remove the entry with the given key from the dictionary.
>>>> + *
>>>> + * Search for an entry matching @p key and remove it, if found. Optionally
>>>> + * the found key and/or value can be returned using the @p out_key and
>>>> + * @p out_value arguments.
>>>> + *
>>>> + * If more than one entry matches, only one entry is removed and returned
>>>> + * on each call. Which entry is returned first in that case is undefined.
>>>> + *
>>>> + * @param pm        Pointer to a pointer to a dictionary struct.
>>>> + * @param key       Entry key to match.
>>>> + * @param out_key   Pointer whose pointee will be set to the matched
>>>> + *                  entry key. Must be freed using av_dict_free() by
>>>
>>> This is wrong: It must be freed using av_free() (or av_freep()); same below.
>>
>> Indeed, copy paste mistake, sorry.
>>
>>>
>>>> + *                  the caller. May be NULL.
>>>> + * @param out_value Pointer whose pointee will be set to the matched
>>>> + *                  entry value. Must be freed using av_dict_free() by
>>>> + *                  the caller. May be NULL.
>>>> + *
>>>> + * @retval 0                            Success
>>>> + * @retval AVERROR(ENOENT)              No item for the given key found
>>>> + * @retval "Other (negative) AVERROR"   Other failure
>>>> + */
>>>> +int av_dict_pop(AVDictionary **pm, const char *key,
>>>> +                char **out_key, char **out_value, int flags);
>>>
>>> It is possible to store multiple entries with the same value in an
>>> AVDictionary. This function is not designed to handle this case, as one
>>> can't tell it which one one wants to pop (IIRC the rest of the API does
>>> not properly support this either, but that is not a reason to add a new
>>> API with this limitation).
>>
>> I honestly can't think of a sensible API design for this,
>> if you have any idea feel free to share.
>>
>
> The only way I can think of that allows this is for the user to pass a
> pointer to a (const) AVDictionaryEntry, namely the entry that the user
> wishes to pop. This is of course cumbersome, because it would be two
> function calls.
>
>> If the value is known before, using av_dict_pop is useless anyway
>> as there would be not need to obtain the value if it's already known?
>>
>
> I don't really understand this. Having pointers to the strings is not
> the same as owning the strings.
>

Indeed, I get what you mean now, that looking up and popping could
be two separate steps, then it would make sense but somewhat annoying
to use API wise.

>>>
>>> Furthermore, while this may be used to avoid a few allocations with the
>>> current implementation, said implementation is not guaranteed to stay
>>> this way.
>>>
>>
>> I would assume whatever future changes we do, the dictionary would continue
>> to hold ownership of the items so a way to remove it from the dict
>> and transferring ownership seems useful to me.
>>
>
> Of course the dict has ownership of the strings referred to by the
> dictionary. But for this function to work as you wrote it, the strings
> referred to by each entry need to be e.g. separately allocated; this may
> or may not change (e.g. we may only allocate one key for all the
> AVDictionaryEntries with the same key in the future).

Thats a good point, the main reason I included the key at all
was that with some flag values it is possible to pop values
for which you don't match the whole key and might want to know
it.

>
>> However indeed there are not really any places in code where this is
>> done, but then again there was no official way to do it before, so
>> there might be more cases that benefit from this.
>
> Do you know whether there are library users that would benefit from this?
>

No,
main reason for proposing this API was so I can make the av_dict_get
return const as it should be. I can strdup instead, if you think thats
better. But given we have a way to hand over string values to the dictionary
without copy, it just seemed logical to have some API for the reverse.

So I am open for new API proposals/designs or can use strdup, it just would
be good if we can agree on something before I spend more time on this and have
fundamentally changed things several times.

>>
>>> Finally, are there more intended uses than the one in the second patch?
>>> If so, this could also be simply fixed by strduping the value without
>>> any need for a further API addition.
>>>
>>>> +
>>>>  /**
>>>>   * Parse the key/value pairs list and add the parsed entries to a dictionary.
>>>>   *
>>>> diff --git a/libavutil/tests/dict.c b/libavutil/tests/dict.c
>>>> index bececefb31..06d94ecc9a 100644
>>>> --- a/libavutil/tests/dict.c
>>>> +++ b/libavutil/tests/dict.c
>>>> @@ -158,5 +158,43 @@ int main(void)
>>>>      printf("%s\n", e->value);
>>>>      av_dict_free(&dict);
>>>>
>>>> +    char *key, *val = NULL;
>>>> +    int ret;
>>>> +    printf("\nTesting av_dict_pop() with existing AVDictionaryEntry.key as key\n");
>>>> +    av_dict_set(&dict, "test-key", "test-value", 0);
>>>> +    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
>>>> +    printf("%s: %s (Return code: %i)\n",
>>>> +        (key) ? key : "(null)",
>>>> +        (val) ? val : "(null)", ret);
>>>> +    e = av_dict_get(dict, "test-key", NULL, 0);
>>>> +    printf("%s\n", (e) ? e->value : "(null)");
>>>> +    av_freep(&key);
>>>> +    av_freep(&val);
>>>> +
>>>> +    printf("\nTesting av_dict_pop() with nonexistent key\n");
>>>> +    ret = av_dict_pop(&dict, "test-key", &key, &val, 0);
>>>> +    printf("%s: %s ",
>>>> +        (key) ? key : "(null)",
>>>> +        (val) ? val : "(null)");
>>>> +    if (ret == AVERROR(ENOENT))
>>>> +        printf("(Return code: ENOENT)\n");
>>>> +    else
>>>> +        printf("(Return code: Unexpected error: %i)\n", ret);
>>>> +    e = av_dict_get(dict, "test-key", NULL, 0);
>>>> +    printf("%s\n", (e) ? e->value : "(null)");
>>>> +    av_freep(&key);
>>>> +    av_freep(&val);
>>>> +
>>>> +    printf("\nTesting av_dict_pop() with prefix key match\n");
>>>> +    av_dict_set(&dict, "prefix-test-key", "test-value", 0);
>>>> +    ret = av_dict_pop(&dict, "prefix-test", &key, &val, AV_DICT_IGNORE_SUFFIX);
>>>> +    printf("%s: %s (Return code: %i)\n",
>>>> +        (key) ? key : "(null)",
>>>> +        (val) ? val : "(null)", ret);
>>>> +    e = av_dict_get(dict, "prefix-test", NULL, AV_DICT_IGNORE_SUFFIX);
>>>> +    printf("%s\n", (e) ? e->value : "(null)");
>>>> +    av_freep(&key);
>>>> +    av_freep(&val);
>>>> +
>>>>      return 0;
>>>>  }
>>>> diff --git a/libavutil/version.h b/libavutil/version.h
>>>> index 17a6d296a6..24af520e08 100644
>>>> --- a/libavutil/version.h
>>>> +++ b/libavutil/version.h
>>>> @@ -79,8 +79,8 @@
>>>>   */
>>>>
>>>>  #define LIBAVUTIL_VERSION_MAJOR  58
>>>> -#define LIBAVUTIL_VERSION_MINOR  13
>>>> -#define LIBAVUTIL_VERSION_MICRO 101
>>>> +#define LIBAVUTIL_VERSION_MINOR  14
>>>> +#define LIBAVUTIL_VERSION_MICRO 100
>>>>
>>>>  #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
>>>>                                                 LIBAVUTIL_VERSION_MINOR, \
>>>> diff --git a/tests/ref/fate/dict b/tests/ref/fate/dict
>>>> index 7205e4c845..afa87aca5f 100644
>>>> --- a/tests/ref/fate/dict
>>>> +++ b/tests/ref/fate/dict
>>>> @@ -48,3 +48,15 @@ Testing av_dict_set_int()
>>>>  Testing av_dict_set() with existing AVDictionaryEntry.key as key
>>>>  new val OK
>>>>  new val OK
>>>> +
>>>> +Testing av_dict_pop() with existing AVDictionaryEntry.key as key
>>>> +test-key: test-value (Return code: 0)
>>>> +(null)
>>>> +
>>>> +Testing av_dict_pop() with nonexistent key
>>>> +(null): (null) (Return code: ENOENT)
>>>> +(null)
>>>> +
>>>> +Testing av_dict_pop() with prefix key match
>>>> +prefix-test-key: test-value (Return code: 0)
>>>> +(null)
>>>
>
> _______________________________________________
> 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".
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-07-03 18:02       ` Andreas Rheinhardt
  2023-07-03 22:41         ` Marvin Scholz
@ 2023-10-20  8:18         ` Anton Khirnov
  2023-10-20 14:00           ` Andreas Rheinhardt
  1 sibling, 1 reply; 32+ messages in thread
From: Anton Khirnov @ 2023-10-20  8:18 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Quoting Andreas Rheinhardt (2023-07-03 20:02:25)
> Marvin Scholz:
> > I honestly can't think of a sensible API design for this,
> > if you have any idea feel free to share.
> > 
> 
> The only way I can think of that allows this is for the user to pass a
> pointer to a (const) AVDictionaryEntry, namely the entry that the user
> wishes to pop. This is of course cumbersome, because it would be two
> function calls.

We could start guaranteeing that entries with the same key are always
returned in insertion order. Now that I think of it there's some code in
ffmpeg CLI that relies on that.

-- 
Anton Khirnov
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-10-20  8:18         ` Anton Khirnov
@ 2023-10-20 14:00           ` Andreas Rheinhardt
  2023-10-20 14:33             ` Anton Khirnov
  0 siblings, 1 reply; 32+ messages in thread
From: Andreas Rheinhardt @ 2023-10-20 14:00 UTC (permalink / raw)
  To: ffmpeg-devel

Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-07-03 20:02:25)
>> Marvin Scholz:
>>> I honestly can't think of a sensible API design for this,
>>> if you have any idea feel free to share.
>>>
>>
>> The only way I can think of that allows this is for the user to pass a
>> pointer to a (const) AVDictionaryEntry, namely the entry that the user
>> wishes to pop. This is of course cumbersome, because it would be two
>> function calls.
> 
> We could start guaranteeing that entries with the same key are always
> returned in insertion order. Now that I think of it there's some code in
> ffmpeg CLI that relies on that.
> 

IIRC this is not true correctly, because removing an entry changes the
order of the remaining entries (we don't memmove the remaining entries
into the new position; instead we move the last entry to the now vacant
slot).

- 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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-10-20 14:00           ` Andreas Rheinhardt
@ 2023-10-20 14:33             ` Anton Khirnov
  2023-10-20 15:42               ` Andreas Rheinhardt
  0 siblings, 1 reply; 32+ messages in thread
From: Anton Khirnov @ 2023-10-20 14:33 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Quoting Andreas Rheinhardt (2023-10-20 16:00:45)
> Anton Khirnov:
> > Quoting Andreas Rheinhardt (2023-07-03 20:02:25)
> >> Marvin Scholz:
> >>> I honestly can't think of a sensible API design for this,
> >>> if you have any idea feel free to share.
> >>>
> >>
> >> The only way I can think of that allows this is for the user to pass a
> >> pointer to a (const) AVDictionaryEntry, namely the entry that the user
> >> wishes to pop. This is of course cumbersome, because it would be two
> >> function calls.
> > 
> > We could start guaranteeing that entries with the same key are always
> > returned in insertion order. Now that I think of it there's some code in
> > ffmpeg CLI that relies on that.
> > 
> 
> IIRC this is not true correctly, because removing an entry changes the
> order of the remaining entries (we don't memmove the remaining entries
> into the new position; instead we move the last entry to the now vacant
> slot).

I am aware - that code is strictly speaking incorrect. It happens to
work because nothing ever gets removed from the option dicts. We could
consider changing the internal representation somehow, so that all
values for a key are grouped together.

-- 
Anton Khirnov
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop
  2023-10-20 14:33             ` Anton Khirnov
@ 2023-10-20 15:42               ` Andreas Rheinhardt
  0 siblings, 0 replies; 32+ messages in thread
From: Andreas Rheinhardt @ 2023-10-20 15:42 UTC (permalink / raw)
  To: ffmpeg-devel

Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-10-20 16:00:45)
>> Anton Khirnov:
>>> Quoting Andreas Rheinhardt (2023-07-03 20:02:25)
>>>> Marvin Scholz:
>>>>> I honestly can't think of a sensible API design for this,
>>>>> if you have any idea feel free to share.
>>>>>
>>>>
>>>> The only way I can think of that allows this is for the user to pass a
>>>> pointer to a (const) AVDictionaryEntry, namely the entry that the user
>>>> wishes to pop. This is of course cumbersome, because it would be two
>>>> function calls.
>>>
>>> We could start guaranteeing that entries with the same key are always
>>> returned in insertion order. Now that I think of it there's some code in
>>> ffmpeg CLI that relies on that.
>>>
>>
>> IIRC this is not true correctly, because removing an entry changes the
>> order of the remaining entries (we don't memmove the remaining entries
>> into the new position; instead we move the last entry to the now vacant
>> slot).
> 
> I am aware - that code is strictly speaking incorrect. It happens to
> work because nothing ever gets removed from the option dicts. We could
> consider changing the internal representation somehow, so that all
> values for a key are grouped together.
> 

We could also just memmove the remaining entries.

- 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-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2023-10-20 15:41 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-01 11:44 [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Marvin Scholz
2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 2/3] avformat/tee: use av_dict_pop Marvin Scholz
2023-06-25 12:07   ` "zhilizhao(赵志立)"
2023-05-01 11:44 ` [FFmpeg-devel] [PATCH 3/3] avutil/dict: constify av_dict_get return Marvin Scholz
2023-06-05 10:05   ` Anton Khirnov
2023-05-21 23:52 ` [FFmpeg-devel] [PATCH 1/3] avutil/dict: add av_dict_pop Stefano Sabatini
2023-05-22  9:23   ` Marvin Scholz
2023-05-26  6:05     ` Stefano Sabatini
2023-05-26  9:11       ` Marvin Scholz
2023-05-26 20:02         ` Michael Niedermayer
2023-05-26 20:51           ` Marvin Scholz
2023-05-26 20:06         ` James Almer
2023-06-04 14:25         ` Stefano Sabatini
2023-06-04 14:34           ` Marvin Scholz
2023-06-05  8:08             ` Stefano Sabatini
2023-06-05 10:09               ` Anton Khirnov
2023-06-05 10:04 ` Anton Khirnov
2023-06-25 10:49 ` [FFmpeg-devel] [PATCH v2 " Marvin Scholz
2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 2/3] avformat/tee: use av_dict_pop Marvin Scholz
2023-07-02  8:47     ` Stefano Sabatini
2023-06-25 10:49   ` [FFmpeg-devel] [PATCH v2 3/3] avutil/dict: constify av_dict_get return Marvin Scholz
2023-07-02  9:06     ` Stefano Sabatini
2023-07-02  8:43   ` [FFmpeg-devel] [PATCH v2 1/3] avutil/dict: add av_dict_pop Stefano Sabatini
2023-07-02 11:49     ` Marvin Scholz
2023-07-03  0:18   ` Andreas Rheinhardt
2023-07-03  9:11     ` Marvin Scholz
2023-07-03 18:02       ` Andreas Rheinhardt
2023-07-03 22:41         ` Marvin Scholz
2023-10-20  8:18         ` Anton Khirnov
2023-10-20 14:00           ` Andreas Rheinhardt
2023-10-20 14:33             ` Anton Khirnov
2023-10-20 15:42               ` Andreas Rheinhardt

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