This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

The following commit(s) were added to refs/heads/master by this push:
     new 11b68cce09 avfilter/af_whisper: Add 'lock', 'eval' lang modes
11b68cce09 is described below

commit 11b68cce09900f8a4a25ceba42055094af00bf37
Author:     WyattBlue <[email protected]>
AuthorDate: Wed Jul 1 00:33:54 2026 -0400
Commit:     michaelni <[email protected]>
CommitDate: Sat Aug 22 17:41:51 2026 +0000

    avfilter/af_whisper: Add 'lock', 'eval' lang modes
    
    Add 'lock' and 'eval' languages modes. With autodetection, whisper
    reruns language detection on every queued chunk, an extra encoder pass
    that can also drift to a different language mid-file.
    
    Add two explicit values for the language option: 'eval' keeps the
    per-chunk reevaluation, 'lock' caches the language detected by the
    first chunk that produces transcribed text and reuses it for the
    following chunks. Requiring actual text means a silent, musical or
    [BLANK_AUDIO]-only opening chunk leaves detection to a later one.
    
    'auto' remains an alias for 'eval' so existing behavior is unchanged.
---
 doc/filters.texi         | 18 +++++++++++++++++-
 libavfilter/af_whisper.c | 30 ++++++++++++++++++++++++++----
 2 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 51885fddde..8425382225 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -7740,7 +7740,23 @@ The filter has following options:
 The file path of the downloaded whisper.cpp model (mandatory).
 
 @item language
-The language to use for transcription ('auto' for auto-detect).
+The language to use for transcription. Besides a language code, the following
+special values enable auto-detection:
+
+@table @samp
+@item eval
+Re-run language detection on every queued chunk. This costs an extra encoder
+pass per chunk and the detected language may change mid-file.
+
+@item lock
+Detect the language on the first chunk that produces transcribed text, then
+reuse it for the remaining chunks.
+
+@item auto
+Currently an alias for @samp{eval}. This may change in a future version, so use
+@samp{eval} or @samp{lock} if the behavior matters.
+@end table
+
 Default value: @code{"auto"}
 
 @item translate
diff --git a/libavfilter/af_whisper.c b/libavfilter/af_whisper.c
index 75103ced0c..33d8a2112a 100644
--- a/libavfilter/af_whisper.c
+++ b/libavfilter/af_whisper.c
@@ -43,6 +43,8 @@ typedef struct WhisperContext {
     char *model_path;
     const char *language;
     char *language_str;
+    char *locked_language;
+    bool lock_language;
     bool translate;
     bool use_gpu;
     int gpu_device;
@@ -152,18 +154,25 @@ static int init(AVFilterContext *ctx)
         wctx->avio_context->direct = AVIO_FLAG_DIRECT;
     }
 
+    // 'eval' and 'lock' both auto-detect; they differ only in whether the
+    // detected language is reused for the following chunks
+    const char *lang = wctx->language_str;
+    wctx->lock_language = !strcmp(lang, "lock");
+    if (wctx->lock_language || !strcmp(lang, "eval"))
+        lang = "auto";
+
     if (!whisper_is_multilingual(wctx->ctx_wsp)) {
-        if (!wctx->translate && strcmp(wctx->language_str, "auto") == 0) {
+        if (!wctx->translate && strcmp(lang, "auto") == 0) {
             av_log(ctx, AV_LOG_WARNING,
                    "Multilingual model not provided. Non-English audio may not 
be correctly transcribed.\n");
-        } else if (wctx->translate || (strcmp(wctx->language_str, "auto") != 0 
&& strcmp(wctx->language_str, "en") != 0)) {
+        } else if (wctx->translate || (strcmp(lang, "auto") != 0 && 
strcmp(lang, "en") != 0)) {
             av_log(ctx, AV_LOG_ERROR,
                    "%s requested but multilingual model not provided.\n", 
wctx->translate ? "Translation" : "Transcription");
             return AVERROR(ENOSYS);
         }
         wctx->language = "en";
     } else
-        wctx->language = wctx->language_str;
+        wctx->language = lang;
 
     av_log(ctx, AV_LOG_INFO,
            "Whisper filter initialized: model: %s lang: %s queue: %" PRId64 " 
ms\n",
@@ -193,6 +202,7 @@ static void uninit(AVFilterContext *ctx)
     }
 
     av_freep(&wctx->audio_buffer);
+    av_freep(&wctx->locked_language);
 
     if (wctx->avio_context)
         avio_closep(&wctx->avio_context);
@@ -295,6 +305,18 @@ static void run_transcription(AVFilterContext *ctx, 
AVFrame *frame, int samples)
         av_freep(&text_cleaned);
     }
 
+    if (wctx->lock_language && segments_text && !av_strcasecmp(wctx->language, 
"auto")) {
+        const int lang_id = whisper_full_lang_id(wctx->ctx_wsp);
+        if (lang_id >= 0) {
+            char *detected = av_strdup(whisper_lang_str(lang_id));
+            if (detected) {
+                wctx->locked_language = detected;
+                wctx->language        = detected;
+                av_log(ctx, AV_LOG_INFO, "Locked auto-detected language: 
%s\n", detected);
+            }
+        }
+    }
+
     AVDictionary **metadata = &frame->metadata;
     if (metadata && segments_text) {
         av_dict_set(metadata, "lavfi.whisper.text", segments_text, 0);
@@ -459,7 +481,7 @@ static int query_formats(const AVFilterContext *ctx,
 
 static const AVOption whisper_options[] = {
     { "model", "Path to the whisper.cpp model file", OFFSET(model_path), 
AV_OPT_TYPE_STRING,.flags = FLAGS },
-    { "language", "Language for transcription ('auto' for auto-detect)", 
OFFSET(language_str), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = FLAGS },
+    { "language", "Language for transcription ('auto', 'eval' or 'lock' for 
auto-detect)", OFFSET(language_str), AV_OPT_TYPE_STRING, {.str = "auto"}, 
.flags = FLAGS },
     { "translate", "Translate from source language to English", 
OFFSET(translate), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = FLAGS },
     { "queue", "Audio queue size", OFFSET(queue), AV_OPT_TYPE_DURATION, {.i64 
= 3000000}, 20000, HOURS, .flags = FLAGS },
     { "use_gpu", "Use GPU for processing", OFFSET(use_gpu), AV_OPT_TYPE_BOOL, 
{.i64 = 1}, 0, 1, .flags = FLAGS },

-- 
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to