[FFmpeg-devel] [PATCH 33/47] fftools: remove parse_time_or_die()

Anton Khirnov anton at khirnov.net
Sat Jul 15 13:45:57 EEST 2023


Replace it with calling av_parse_time() directly, which provides
graceful error handling and more accurate error messages.
---
 fftools/cmdutils.c        | 19 ++++++-------------
 fftools/cmdutils.h        | 17 -----------------
 fftools/ffmpeg_mux_init.c | 30 ++++++++++++++++++++++++------
 fftools/ffmpeg_opt.c      | 17 ++++++++++++++---
 fftools/ffplay.c          | 16 ++--------------
 5 files changed, 46 insertions(+), 53 deletions(-)

diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index 48a81ca201..b401b8fb89 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -127,18 +127,6 @@ int parse_number(const char *context, const char *numstr, int type,
     return AVERROR(EINVAL);
 }
 
-int64_t parse_time_or_die(const char *context, const char *timestr,
-                          int is_duration)
-{
-    int64_t us;
-    if (av_parse_time(&us, timestr, is_duration) < 0) {
-        av_log(NULL, AV_LOG_FATAL, "Invalid %s specification for %s: %s\n",
-               is_duration ? "duration" : "date", context, timestr);
-        exit_program(1);
-    }
-    return us;
-}
-
 void show_help_options(const OptionDef *options, const char *msg, int req_flags,
                        int rej_flags, int alt_flags)
 {
@@ -304,7 +292,12 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
 
         *(int64_t *)dst = num;
     } else if (po->flags & OPT_TIME) {
-        *(int64_t *)dst = parse_time_or_die(opt, arg, 1);
+        ret = av_parse_time(dst, arg, 1);
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_ERROR, "Invalid duration for option %s: %s\n",
+                   opt, arg);
+            return ret;
+        }
     } else if (po->flags & OPT_FLOAT) {
         ret = parse_number(opt, arg, OPT_FLOAT, -INFINITY, INFINITY, &num);
         if (ret < 0)
diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h
index 68de0bcb7f..dc041d9fa2 100644
--- a/fftools/cmdutils.h
+++ b/fftools/cmdutils.h
@@ -112,23 +112,6 @@ int opt_timelimit(void *optctx, const char *opt, const char *arg);
 int parse_number(const char *context, const char *numstr, int type,
                            double min, double max, double *dst);
 
-/**
- * Parse a string specifying a time and return its corresponding
- * value as a number of microseconds. Exit from the application if
- * the string cannot be correctly parsed.
- *
- * @param context the context of the value to be set (e.g. the
- * corresponding command line option name)
- * @param timestr the string to be parsed
- * @param is_duration a flag which tells how to interpret timestr, if
- * not zero timestr is interpreted as a duration, otherwise as a
- * date
- *
- * @see av_parse_time()
- */
-int64_t parse_time_or_die(const char *context, const char *timestr,
-                          int is_duration);
-
 typedef struct SpecifierOpt {
     char *specifier;    /**< stream/chapter/program/... specifier */
     union {
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 02d71588ad..92d62c7b89 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -2410,11 +2410,11 @@ static int compare_int64(const void *a, const void *b)
     return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);
 }
 
-static int parse_forced_key_frames(KeyframeForceCtx *kf, const Muxer *mux,
-                                   const char *spec)
+static int parse_forced_key_frames(void *log, KeyframeForceCtx *kf,
+                                   const Muxer *mux, const char *spec)
 {
     const char *p;
-    int n = 1, i, size, index = 0;
+    int n = 1, i, ret, size, index = 0;
     int64_t t, *pts;
 
     for (p = spec; *p; p++)
@@ -2441,7 +2441,16 @@ static int parse_forced_key_frames(KeyframeForceCtx *kf, const Muxer *mux,
                 !(pts = av_realloc_f(pts, size += nb_ch - 1,
                                      sizeof(*pts))))
                 return AVERROR(ENOMEM);
-            t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0;
+
+            if (p[8]) {
+                ret = av_parse_time(&t, p + 8, 1);
+                if (ret < 0) {
+                    av_log(log, AV_LOG_ERROR,
+                           "Invalid chapter time offset: %s\n", p + 8);
+                    goto fail;
+                }
+            } else
+                t = 0;
 
             for (j = 0; j < nb_ch; j++) {
                 const AVChapter *c = ch[j];
@@ -2452,7 +2461,13 @@ static int parse_forced_key_frames(KeyframeForceCtx *kf, const Muxer *mux,
 
         } else {
             av_assert1(index < size);
-            pts[index++] = parse_time_or_die("force_key_frames", p, 1);
+            ret = av_parse_time(&t, p, 1);
+            if (ret < 0) {
+                av_log(log, AV_LOG_ERROR, "Invalid keyframe time: %s\n", p);
+                goto fail;
+            }
+
+            pts[index++] = t;
         }
 
         p = next;
@@ -2464,6 +2479,9 @@ static int parse_forced_key_frames(KeyframeForceCtx *kf, const Muxer *mux,
     kf->pts    = pts;
 
     return 0;
+fail:
+    av_freep(&pts);
+    return ret;
 }
 
 static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
@@ -2498,7 +2516,7 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
         } else if (!strcmp(forced_keyframes, "source_no_drop")) {
             ost->kf.type = KF_FORCE_SOURCE_NO_DROP;
         } else {
-            int ret = parse_forced_key_frames(&ost->kf, mux, forced_keyframes);
+            int ret = parse_forced_key_frames(ost, &ost->kf, mux, forced_keyframes);
             if (ret < 0)
                 return ret;
         }
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index e1696cdd59..44a6b49ed7 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -326,7 +326,10 @@ static int opt_abort_on(void *optctx, const char *opt, const char *arg)
 
 static int opt_stats_period(void *optctx, const char *opt, const char *arg)
 {
-    int64_t user_stats_period = parse_time_or_die(opt, arg, 1);
+    int64_t user_stats_period;
+    int ret = av_parse_time(&user_stats_period, arg, 1);
+    if (ret < 0)
+        return ret;
 
     if (user_stats_period <= 0) {
         av_log(NULL, AV_LOG_ERROR, "stats_period %s must be positive.\n", arg);
@@ -636,8 +639,16 @@ static int opt_recording_timestamp(void *optctx, const char *opt, const char *ar
 {
     OptionsContext *o = optctx;
     char buf[128];
-    int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
-    struct tm time = *gmtime((time_t*)&recording_timestamp);
+    int64_t recording_timestamp;
+    int ret;
+    struct tm time;
+
+    ret = av_parse_time(&recording_timestamp, arg, 0);
+    if (ret < 0)
+        return ret;
+
+    recording_timestamp /= 1e6;
+    time = *gmtime((time_t*)&recording_timestamp);
     if (!strftime(buf, sizeof(buf), "creation_time=%Y-%m-%dT%H:%M:%S%z", &time))
         return -1;
     parse_option(o, "metadata", buf, options);
diff --git a/fftools/ffplay.c b/fftools/ffplay.c
index 6ca1ad98bf..89cea4d876 100644
--- a/fftools/ffplay.c
+++ b/fftools/ffplay.c
@@ -3485,18 +3485,6 @@ static int opt_sync(void *optctx, const char *opt, const char *arg)
     return 0;
 }
 
-static int opt_seek(void *optctx, const char *opt, const char *arg)
-{
-    start_time = parse_time_or_die(opt, arg, 1);
-    return 0;
-}
-
-static int opt_duration(void *optctx, const char *opt, const char *arg)
-{
-    duration = parse_time_or_die(opt, arg, 1);
-    return 0;
-}
-
 static int opt_show_mode(void *optctx, const char *opt, const char *arg)
 {
     show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
@@ -3561,8 +3549,8 @@ static const OptionDef options[] = {
     { "ast", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_specifier" },
     { "vst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_specifier" },
     { "sst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_specifier" },
-    { "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" },
-    { "t", HAS_ARG, { .func_arg = opt_duration }, "play  \"duration\" seconds of audio/video", "duration" },
+    { "ss", HAS_ARG | OPT_TIME, { &start_time }, "seek to a given position in seconds", "pos" },
+    { "t",  HAS_ARG | OPT_TIME, { &duration }, "play  \"duration\" seconds of audio/video", "duration" },
     { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
     { "seek_interval", OPT_FLOAT | HAS_ARG, { &seek_interval }, "set seek interval for left/right keys, in seconds", "seconds" },
     { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" },
-- 
2.40.1



More information about the ffmpeg-devel mailing list