[FFmpeg-devel] [PATCH 16/33] fftools/ffmpeg_mux_init: improve of_add_programs()

Anton Khirnov anton at khirnov.net
Thu Jul 13 13:55:36 EEST 2023


Replace duplicated(!) and broken* custom string parsing with
av_dict_parse_string(). Return error codes instead of aborting.

* e.g. it treats NULL returned from av_get_token() as "separator not
  found", when in fact av_get_token() only returns NULL on memory
  allocation failure
---
 fftools/ffmpeg_mux_init.c | 111 ++++++++++++++++++--------------------
 1 file changed, 52 insertions(+), 59 deletions(-)

diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 3a327048bb..b0befb8924 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -1782,76 +1782,66 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u
     return 0;
 }
 
-static void of_add_programs(Muxer *mux, const OptionsContext *o)
+static int of_add_programs(Muxer *mux, const OptionsContext *o)
 {
     AVFormatContext *oc = mux->fc;
     /* process manually set programs */
     for (int i = 0; i < o->nb_program; i++) {
-        const char *p = o->program[i].u.str;
-        int progid = i+1;
+        AVDictionary *dict = NULL;
+        const AVDictionaryEntry *e;
         AVProgram *program;
+        int ret, progid = i + 1;
 
-        while(*p) {
-            const char *p2 = av_get_token(&p, ":");
-            const char *to_dealloc = p2;
-            char *key;
-            if (!p2)
-                break;
+        ret = av_dict_parse_string(&dict, o->program[i].u.str, "=", ":",
+                                   AV_DICT_MULTIKEY);
+        if (ret < 0) {
+            av_log(mux, AV_LOG_ERROR, "Error parsing program specification %s\n",
+                   o->program[i].u.str);
+            return ret;
+        }
 
-            if(*p) p++;
-
-            key = av_get_token(&p2, "=");
-            if (!key || !*p2) {
-                av_freep(&to_dealloc);
-                av_freep(&key);
-                break;
-            }
-            p2++;
-
-            if (!strcmp(key, "program_num"))
-                progid = strtol(p2, NULL, 0);
-            av_freep(&to_dealloc);
-            av_freep(&key);
+        e = av_dict_get(dict, "program_num", NULL, 0);
+        if (e) {
+            progid = strtol(e->value, NULL, 0);
+            av_dict_set(&dict, e->key, NULL, 0);
         }
 
         program = av_new_program(oc, progid);
-        if (!program)
-            report_and_exit(AVERROR(ENOMEM));
-
-        p = o->program[i].u.str;
-        while(*p) {
-            const char *p2 = av_get_token(&p, ":");
-            const char *to_dealloc = p2;
-            char *key;
-            if (!p2)
-                break;
-            if(*p) p++;
-
-            key = av_get_token(&p2, "=");
-            if (!key) {
-                av_log(mux, AV_LOG_FATAL,
-                       "No '=' character in program string %s.\n",
-                       p2);
-                exit_program(1);
-            }
-            if (!*p2)
-                exit_program(1);
-            p2++;
-
-            if (!strcmp(key, "title")) {
-                av_dict_set(&program->metadata, "title", p2, 0);
-            } else if (!strcmp(key, "program_num")) {
-            } else if (!strcmp(key, "st")) {
-                int st_num = strtol(p2, NULL, 0);
-                av_program_add_stream_index(oc, progid, st_num);
-            } else {
-                av_log(mux, AV_LOG_FATAL, "Unknown program key %s.\n", key);
-                exit_program(1);
-            }
-            av_freep(&to_dealloc);
-            av_freep(&key);
+        if (!program) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
         }
+
+        e = av_dict_get(dict, "title", NULL, 0);
+        if (e) {
+            av_dict_set(&program->metadata, e->key, e->value, 0);
+            av_dict_set(&dict, e->key, NULL, 0);
+        }
+
+        e = NULL;
+        while (e = av_dict_get(dict, "st", e, 0)) {
+            int st_num = strtol(e->value, NULL, 0);
+            av_program_add_stream_index(oc, progid, st_num);
+        }
+
+        // make sure that nothing but "st" entries are left in the dict
+        e = NULL;
+        while (e = av_dict_iterate(dict, e)) {
+            if (!strcmp(e->key, "st"))
+                continue;
+
+            av_log(mux, AV_LOG_FATAL, "Unknown program key %s.\n", e->key);
+            ret = AVERROR(EINVAL);
+            goto fail;
+        }
+
+fail:
+        av_dict_free(&dict);
+        if (ret < 0)
+            return ret;
     }
+
+    return 0;
 }
 
 /**
@@ -2547,7 +2537,10 @@ int of_open(const OptionsContext *o, const char *filename)
     if (err < 0)
         return err;
 
-    of_add_programs(mux, o);
+    err = of_add_programs(mux, o);
+    if (err < 0)
+        return err;
+
     of_add_metadata(of, oc, o);
 
     err = set_dispositions(mux, o);
-- 
2.40.1



More information about the ffmpeg-devel mailing list