[FFmpeg-devel] [PATCH] Modified force_key_frames command line option to accept frame numbers

Sylvester Zaluga sylvester.zaluga at gmail.com
Mon Nov 10 00:42:33 CET 2014


 @item -force_key_frames[:@var{stream_specifier}] @var{time}[, at var{time}...] (@emph{output,per-stream})
+ at item -force_key_frames[:@var{stream_specifier}] n:@var{number}[, at var{number}...] (@emph{output,per-stream})
 @item -force_key_frames[:@var{stream_specifier}] expr:@var{expr} (@emph{output,per-stream})
-Force key frames at the specified timestamps, more precisely at the first
-frames after each specified time.
+Force key frames at the specified timestamps (more precisely at the first
+frames after each specified time) or at the specified frame numbers.
+
+If the argument is prefixed with @code{n:}, the comma-separated @var{number}
+strings will be interpreted as numbers / indices of frames that should
+be forced to be key frames.
 
 If the argument is prefixed with @code{expr:}, the string @var{expr}
 is interpreted like an expression and is evaluated for each frame. A
@@ -606,6 +611,11 @@ before the beginning of every chapter:
 -force_key_frames 0:05:00,chapters-0.1
 @end example
 
+For example, to insert at predefined frame numbers:
+ at example
+-force_key_frames n:0,25,50,75,100,125,150,175,200,225,250
+ at end example
+
 The expression in @var{expr} can contain the following constants:
 @table @option
 @item n
diff --git a/ffmpeg.c b/ffmpeg.c
index 1fd0ece..969222d 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -1039,6 +1039,11 @@ static void do_video_out(AVFormatContext *s,
             }
 
             ost->forced_keyframes_expr_const_values[FKF_N] += 1;
+        } else if (ost->forced_kf_n_index < ost->forced_kf_n_count &&
+            ost->frame_number == ost->forced_kf_n_pts[ost->forced_kf_n_index]) {
+            av_dlog(NULL, "force_key_frame (number mode): n:%d\n", ost->frame_number);
+            ost->forced_kf_n_index++;
+            forced_keyframe = 1;
         }
 
         if (forced_keyframe) {
@@ -2333,6 +2338,12 @@ static InputStream *get_input_stream(OutputStream *ost)
     return NULL;
 }
 
+static int compare_int(const void *a, const void *b)
+{
+    int va = *(int *)a, vb = *(int *)b;
+    return va < vb ? -1 : va > vb ? +1 : 0;
+}
+
 static int compare_int64(const void *a, const void *b)
 {
     int64_t va = *(int64_t *)a, vb = *(int64_t *)b;
@@ -2402,6 +2413,53 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost,
     ost->forced_kf_pts   = pts;
 }
 
+static void parse_forced_key_frames_n(char *kf, OutputStream *ost,
+                                      AVCodecContext *avctx)
+{
+    char *p;
+    int n = 1, i, size, index = 0;
+    int kf_n, kf_n_prev, *pts;
+
+    for (p = kf; *p; p++)
+        if (*p == ',')
+            n++;
+    size = n;
+    pts = av_malloc_array(size, sizeof(*pts));
+    if (!pts) {
+        av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
+        exit_program(1);
+    }
+
+    p = kf;
+    for (i = 0; i < n; i++) {
+        char *next = strchr(p, ',');
+
+        if (next)
+            *next++ = 0;
+
+        kf_n = parse_number_or_die("force_key_frames (numbers)", p, OPT_INT, 0, INT_MAX);
+        av_assert1(index < size);
+        pts[index++] = kf_n;
+
+        p = next;
+    }
+
+    av_assert0(index == size);
+    qsort(pts, size, sizeof(*pts), compare_int);
+    
+    kf_n_prev = -1;
+    for (i = 0; i < n; i++) {
+        if (pts[i] == kf_n_prev) {
+            av_log(NULL, AV_LOG_FATAL, "Duplicated forced key frame number.\n");
+            exit_program(1);
+        }
+        kf_n_prev = pts[i];
+    }
+        
+    ost->forced_kf_n_count = size;
+    ost->forced_kf_n_pts   = pts;
+}
+
 static void report_new_stream(int input_index, AVPacket *pkt)
 {
     InputFile *file = input_files[input_index];
@@ -2815,6 +2873,8 @@ static int transcode_init(void)
                         ost->forced_keyframes_expr_const_values[FKF_N_FORCED] = 0;
                         ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = NAN;
                         ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = NAN;
+                    } else if (!strncmp(ost->forced_keyframes, "n:", 2)) {
+                        parse_forced_key_frames_n(ost->forced_keyframes+2, ost, ost->enc_ctx);
                     } else {
                         parse_forced_key_frames(ost->forced_keyframes, ost, ost->enc_ctx);
                     }
@@ -3775,6 +3835,7 @@ static int transcode(void)
                     ost->logfile = NULL;
                 }
                 av_freep(&ost->forced_kf_pts);
+                av_freep(&ost->forced_kf_n_pts);
                 av_freep(&ost->apad);
                 av_dict_free(&ost->encoder_opts);
                 av_dict_free(&ost->swr_opts);
diff --git a/ffmpeg.h b/ffmpeg.h
index c456603..539b8bd 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -400,6 +400,9 @@ typedef struct OutputStream {
     int64_t *forced_kf_pts;
     int forced_kf_count;
     int forced_kf_index;
+    int *forced_kf_n_pts;                /* list of forced key frame numbers / indices */
+    int forced_kf_n_count;               /* count of forced key frame numbers / indices */
+    int forced_kf_n_index;               /* current numbered forced key frame */
     char *forced_keyframes;
     AVExpr *forced_keyframes_pexpr;
     double forced_keyframes_expr_const_values[FKF_NB];
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index 77ef0c4..15c4813 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -2990,7 +2990,7 @@ const OptionDef options[] = {
         "set the value of an outfile streamid", "streamIndex:value" },
     { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
                           OPT_SPEC | OPT_OUTPUT,                                 { .off = OFFSET(forced_key_frames) },
-        "force key frames at specified timestamps", "timestamps" },
+        "force key frames at specified timestamps or frame numbers", "timestamps/frame numbers" },
     { "ab",           OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT,            { .func_arg = opt_bitrate },
         "audio bitrate (please use -b:a)", "bitrate" },
     { "b",            OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT,            { .func_arg = opt_bitrate },


More information about the ffmpeg-devel mailing list