[FFmpeg-cvslog] fftools/ffmpeg: parse forced keyframes in of_open()

Anton Khirnov git at videolan.org
Mon Nov 28 11:33:16 EET 2022


ffmpeg | branch: master | Anton Khirnov <anton at khirnov.net> | Thu Nov 17 14:22:58 2022 +0100| [334e52e09441213c9c391d7c0f5d0126eaa98396] | committer: Anton Khirnov

fftools/ffmpeg: parse forced keyframes in of_open()

Allows to remove the ugly of_get_chapters() wrapper.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=334e52e09441213c9c391d7c0f5d0126eaa98396
---

 fftools/ffmpeg.c          |  89 --------------------------------------
 fftools/ffmpeg.h          |   2 -
 fftools/ffmpeg_mux.c      |   8 ----
 fftools/ffmpeg_mux_init.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 106 insertions(+), 99 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 5d39d8f69b..12ce108cc6 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -113,15 +113,6 @@ const int program_birth_year = 2000;
 
 static FILE *vstats_file;
 
-const char *const forced_keyframes_const_names[] = {
-    "n",
-    "n_forced",
-    "prev_forced_n",
-    "prev_forced_t",
-    "t",
-    NULL
-};
-
 typedef struct BenchmarkTimeStamps {
     int64_t real_usec;
     int64_t user_usec;
@@ -2590,11 +2581,6 @@ static int init_input_stream(InputStream *ist, char *error, int error_len)
     return 0;
 }
 
-static int compare_int64(const void *a, const void *b)
-{
-    return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);
-}
-
 static int init_output_stream_streamcopy(OutputStream *ost)
 {
     OutputFile *of = output_files[ost->file_index];
@@ -2748,61 +2734,6 @@ static void set_encoder_id(OutputFile *of, OutputStream *ost)
                 AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
 }
 
-static void parse_forced_key_frames(KeyframeForceCtx *kf, OutputFile *of)
-{
-    const char *p;
-    int n = 1, i, size, index = 0;
-    int64_t t, *pts;
-
-    for (p = kf->forced_keyframes; *p; p++)
-        if (*p == ',')
-            n++;
-    size = n;
-    pts = av_malloc_array(size, sizeof(*pts));
-    if (!pts)
-        report_and_exit(AVERROR(ENOMEM));
-
-    p = kf->forced_keyframes;
-    for (i = 0; i < n; i++) {
-        char *next = strchr(p, ',');
-
-        if (next)
-            *next++ = 0;
-
-        if (!memcmp(p, "chapters", 8)) {
-            AVChapter * const *ch;
-            unsigned int    nb_ch;
-            int j;
-
-            ch = of_get_chapters(of, &nb_ch);
-
-            if (nb_ch > INT_MAX - size ||
-                !(pts = av_realloc_f(pts, size += nb_ch - 1,
-                                     sizeof(*pts))))
-                report_and_exit(AVERROR(ENOMEM));
-            t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0;
-
-            for (j = 0; j < nb_ch; j++) {
-                const AVChapter *c = ch[j];
-                av_assert1(index < size);
-                pts[index++] = av_rescale_q(c->start, c->time_base,
-                                            AV_TIME_BASE_Q) + t;
-            }
-
-        } else {
-            av_assert1(index < size);
-            pts[index++] = parse_time_or_die("force_key_frames", p, 1);
-        }
-
-        p = next;
-    }
-
-    av_assert0(index == size);
-    qsort(pts, size, sizeof(*pts), compare_int64);
-    kf->nb_pts = size;
-    kf->pts    = pts;
-}
-
 static void init_encoder_time_base(OutputStream *ost, AVRational default_time_base)
 {
     InputStream *ist = ost->ist;
@@ -2949,26 +2880,6 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame)
             enc_ctx->field_order = AV_FIELD_TT;
         }
 
-        if (ost->kf.forced_keyframes) {
-            if (!strncmp(ost->kf.forced_keyframes, "expr:", 5)) {
-                ret = av_expr_parse(&ost->kf.pexpr, ost->kf.forced_keyframes+5,
-                                    forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL);
-                if (ret < 0) {
-                    av_log(NULL, AV_LOG_ERROR,
-                           "Invalid force_key_frames expression '%s'\n", ost->kf.forced_keyframes+5);
-                    return ret;
-                }
-                ost->kf.expr_const_values[FKF_N]             = 0;
-                ost->kf.expr_const_values[FKF_N_FORCED]      = 0;
-                ost->kf.expr_const_values[FKF_PREV_FORCED_N] = NAN;
-                ost->kf.expr_const_values[FKF_PREV_FORCED_T] = NAN;
-
-                // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes',
-                // parse it only for static kf timings
-            } else if(strncmp(ost->kf.forced_keyframes, "source", 6)) {
-                parse_forced_key_frames(&ost->kf, of);
-            }
-        }
         break;
     case AVMEDIA_TYPE_SUBTITLE:
         enc_ctx->time_base = AV_TIME_BASE_Q;
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index f5d51b90ec..bf2abf55ee 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -757,8 +757,6 @@ void of_close(OutputFile **pof);
  */
 void of_output_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int eof);
 int64_t of_filesize(OutputFile *of);
-AVChapter * const *
-of_get_chapters(OutputFile *of, unsigned int *nb_chapters);
 
 int ifile_open(const OptionsContext *o, const char *filename);
 void ifile_close(InputFile **f);
diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
index 7da29db8f4..de5facbdc0 100644
--- a/fftools/ffmpeg_mux.c
+++ b/fftools/ffmpeg_mux.c
@@ -736,11 +736,3 @@ int64_t of_filesize(OutputFile *of)
     Muxer *mux = mux_from_of(of);
     return atomic_load(&mux->last_filesize);
 }
-
-AVChapter * const *
-of_get_chapters(OutputFile *of, unsigned int *nb_chapters)
-{
-    Muxer *mux = mux_from_of(of);
-    *nb_chapters = mux->fc->nb_chapters;
-    return mux->fc->chapters;
-}
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index bdec0744a9..25e2ab8631 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -1745,6 +1745,104 @@ finish:
     return ret;
 }
 
+const char *const forced_keyframes_const_names[] = {
+    "n",
+    "n_forced",
+    "prev_forced_n",
+    "prev_forced_t",
+    "t",
+    NULL
+};
+
+static int compare_int64(const void *a, const void *b)
+{
+    return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);
+}
+
+static void parse_forced_key_frames(KeyframeForceCtx *kf, const Muxer *mux)
+{
+    const char *p;
+    int n = 1, i, size, index = 0;
+    int64_t t, *pts;
+
+    for (p = kf->forced_keyframes; *p; p++)
+        if (*p == ',')
+            n++;
+    size = n;
+    pts = av_malloc_array(size, sizeof(*pts));
+    if (!pts)
+        report_and_exit(AVERROR(ENOMEM));
+
+    p = kf->forced_keyframes;
+    for (i = 0; i < n; i++) {
+        char *next = strchr(p, ',');
+
+        if (next)
+            *next++ = 0;
+
+        if (!memcmp(p, "chapters", 8)) {
+            AVChapter * const *ch = mux->fc->chapters;
+            unsigned int    nb_ch = mux->fc->nb_chapters;
+            int j;
+
+            if (nb_ch > INT_MAX - size ||
+                !(pts = av_realloc_f(pts, size += nb_ch - 1,
+                                     sizeof(*pts))))
+                report_and_exit(AVERROR(ENOMEM));
+            t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0;
+
+            for (j = 0; j < nb_ch; j++) {
+                const AVChapter *c = ch[j];
+                av_assert1(index < size);
+                pts[index++] = av_rescale_q(c->start, c->time_base,
+                                            AV_TIME_BASE_Q) + t;
+            }
+
+        } else {
+            av_assert1(index < size);
+            pts[index++] = parse_time_or_die("force_key_frames", p, 1);
+        }
+
+        p = next;
+    }
+
+    av_assert0(index == size);
+    qsort(pts, size, sizeof(*pts), compare_int64);
+    kf->nb_pts = size;
+    kf->pts    = pts;
+}
+
+static int process_forced_keyframes(Muxer *mux)
+{
+    for (int i = 0; i < mux->of.nb_streams; i++) {
+        OutputStream *ost = mux->of.streams[i];
+
+        if (!ost->kf.forced_keyframes)
+            continue;
+
+        if (!strncmp(ost->kf.forced_keyframes, "expr:", 5)) {
+            int ret = av_expr_parse(&ost->kf.pexpr, ost->kf.forced_keyframes+5,
+                                    forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL);
+            if (ret < 0) {
+                av_log(NULL, AV_LOG_ERROR,
+                       "Invalid force_key_frames expression '%s'\n", ost->kf.forced_keyframes+5);
+                return ret;
+            }
+            ost->kf.expr_const_values[FKF_N]             = 0;
+            ost->kf.expr_const_values[FKF_N_FORCED]      = 0;
+            ost->kf.expr_const_values[FKF_PREV_FORCED_N] = NAN;
+            ost->kf.expr_const_values[FKF_PREV_FORCED_T] = NAN;
+
+            // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes',
+            // parse it only for static kf timings
+        } else if (strncmp(ost->kf.forced_keyframes, "source", 6)) {
+            parse_forced_key_frames(&ost->kf, mux);
+        }
+    }
+
+    return 0;
+}
+
 static void validate_enc_avopt(const Muxer *mux, const AVDictionary *codec_avopt)
 {
     const AVClass *class  = avcodec_get_class();
@@ -1961,6 +2059,14 @@ int of_open(const OptionsContext *o, const char *filename)
         exit_program(1);
     }
 
+    // parse forced keyframe specifications;
+    // must be done after chapters are created
+    err = process_forced_keyframes(mux);
+    if (err < 0) {
+        av_log(NULL, AV_LOG_FATAL, "Error processing forced keyframes\n");
+        exit_program(1);
+    }
+
     err = setup_sync_queues(mux, oc, o->shortest_buf_duration * AV_TIME_BASE);
     if (err < 0) {
         av_log(NULL, AV_LOG_FATAL, "Error setting up output sync queues\n");



More information about the ffmpeg-cvslog mailing list