PR #21040 opened by Zhao Zhili (quink)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21040
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21040.patch

For example:

./ffmpeg -hwaccel videotoolbox \
        -i input.mp4 -c:a copy \
        -vf scdet=threshold=10 \
        -c:v h264_videotoolbox \
        -force_key_frames scd_metadata \
        -g 1000 -t 30 output.mp4


>From c07193ae1b9bba6131c9292e6c92a5bdd95fff4e Mon Sep 17 00:00:00 2001
From: Zhao Zhili <[email protected]>
Date: Fri, 28 Nov 2025 11:17:05 +0800
Subject: [PATCH] fftools/ffmpeg: add force key frame by scdet metadata support

For example:

./ffmpeg -hwaccel videotoolbox \
        -i input.mp4 -c:a copy \
        -vf scdet=threshold=10 \
        -c:v h264_videotoolbox \
        -force_key_frames scd_metadata \
        -g 1000 -t 30 output.mp4
---
 doc/ffmpeg.texi           | 9 +++++++++
 fftools/ffmpeg.h          | 2 ++
 fftools/ffmpeg_enc.c      | 3 +++
 fftools/ffmpeg_mux_init.c | 2 ++
 4 files changed, 16 insertions(+)

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 3daf2f7ec2..2dae6632bc 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1665,6 +1665,7 @@ Force video tag/fourcc. This is an alias for 
@code{-tag:v}.
 @item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] 
(@emph{output,per-stream})
 @item -force_key_frames[:@var{stream_specifier}] expr:@var{expr} 
(@emph{output,per-stream})
 @item -force_key_frames[:@var{stream_specifier}] source 
(@emph{output,per-stream})
+@item -force_key_frames[:@var{stream_specifier}] scd_metadata 
(@emph{output,per-stream})
 
 @var{force_key_frames} can take arguments of the following form:
 
@@ -1728,6 +1729,14 @@ the current frame being encoded is marked as a key frame 
in its source.
 In cases where this particular source frame has to be dropped,
 enforce the next available frame to become a key frame instead.
 
+@item scd_metadata
+If the argument is @code{scd_metadata}, ffmpeg will force a key frame if
+the current frame contains a metadata entry with the key @code{lavfi.scd.time}.
+The metadata can be added by filters like @code{scdet} and @code{scdet_vulkan}.
+Avoid inserting filters that duplicate frames after @code{scdet}, as this can
+cause duplicate metadata for multiple frames and repeated insertion of key
+frames.
+
 @end table
 
 Note that forcing too many keyframes is very harmful for the lookahead
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index cc2ea1a56e..7720dd9c59 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -602,6 +602,8 @@ enum {
 #if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP
     KF_FORCE_SOURCE_NO_DROP = 2,
 #endif
+    // force keyframe if lavfi.scd.time metadata is set
+    KF_FORCE_SCD_METADATA = 3,
 };
 
 typedef struct KeyframeForceCtx {
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 8f07a10848..0f7d961472 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -768,6 +768,9 @@ static enum AVPictureType forced_kf_apply(void *logctx, 
KeyframeForceCtx *kf,
         }
     } else if (kf->type == KF_FORCE_SOURCE && (frame->flags & 
AV_FRAME_FLAG_KEY)) {
         goto force_keyframe;
+    } else if (kf->type == KF_FORCE_SCD_METADATA &&
+               av_dict_get(frame->metadata, "lavfi.scd.time", NULL, 0)) {
+        goto force_keyframe;
     }
 
     return AV_PICTURE_TYPE_NONE;
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index bcbbee9126..194a87875d 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -3279,6 +3279,8 @@ static int process_forced_keyframes(Muxer *mux, const 
OptionsContext *o)
                    "-force_key_frames is deprecated, use just 'source'\n");
             ost->kf.type = KF_FORCE_SOURCE;
 #endif
+        } else if (!strcmp(forced_keyframes, "scd_metadata")) {
+            ost->kf.type = KF_FORCE_SCD_METADATA;
         } else {
             int ret = parse_forced_key_frames(ost, &ost->kf, mux, 
forced_keyframes);
             if (ret < 0)
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to