balluf

Batch Bearbeitung von MKV Dateien mit FFMPEG

Hallo zusammen!
Ich versuche ein Batch-Skript zu erstellen, das die folgenden Eigenschaften enthalten soll:

Suche nach allen MKV Dateien im Ordner und erstelle eine neue MKV Datei
mit dem selben Dateinamen in einem anderen Ordner.

Die Videospur soll kopiert werden.
Die erste Audiospur soll mit bestimmten Eigenschaften neu erstellt werden.
Die erste Untertitelspur soll, falls vorhanden, nur kopiert werden, wenn sie als default markiert ist.
Alles andere soll ignoriert werden.

Hier ist mein bisher erstellter Code.

FOR /F "tokens=*" %%G IN ('dir /b *.mkv') DO "D:\Progs\ffmpeg\bin\ffmpeg.exe" -i "%%G" -map 0:v:0 -map 0:a:0 -map 0:s:0? -c:v copy -c:a eac3 -b:a 640k -ar 48000 -c:s copy "E:\%%~nG.mkv"  

Soweit funktioniert alles einwandfrei, ich finde jedoch keinen Befehl,
um nur den ersten Untertitel zu kopieren wenn dieser als default geflaggt ist.
Es wäre toll, wenn mir jemand dabei helfen könnte.
Auf Facebook teilen
Auf X (Twitter) teilen
Auf Reddit teilen
Auf Linkedin teilen

Content-ID: 672913

Url: https://administrator.de/forum/batch-bearbeitung-von-mkv-dateien-mit-ffmpeg-672913.html

Ausgedruckt am: 28.06.2025 um 11:06 Uhr

DivideByZero
DivideByZero 17.05.2025 aktualisiert um 22:24:50 Uhr
Goto Top
Moin,

das wäre ein klassischer Fall für ChatGPT oä


Hier ist die Windows-Version des Skripts (für die Eingabe über die Eingabeaufforderung (CMD)), mit denselben Funktionen: Es kopiert nur die erste Untertitelspur, wenn sie als default=1 markiert ist.

@echo off
setlocal EnableDelayedExpansion

:: Eingabedatei prüfen
if "%~1"=="" (  
    echo Usage: copy_default_subs.bat input.mkv
    exit /b 1
)

set "INPUT=%~1"  
set "OUTPUT=%~dpn1_with_default_subs.mkv"  

:: ffprobe aufrufen und nach default-Flag der ersten Untertitelspur suchen
for /f "delims=" %%A in ('ffprobe -v error -select_streams s:0 -show_entries stream^=disposition -of default^=nw^=1:nk^=1 "%INPUT%" ^| findstr "default="') do (  
    set "LINE=%%A"  
)

:: Extrahiere den Wert hinter "default=" 
for /f "tokens=2 delims==" %%B in ("!LINE!") do set "DEFAULT_FLAG=%%B"  

:: Prüfen, ob default=1
if "!DEFAULT_FLAG!"=="1" (  
    echo Default subtitle track found. Copying video, audio, and subtitle track 0...
    ffmpeg -i "%INPUT%" -map 0:v -map 0:a -map 0:s:0 -c copy "%OUTPUT%"  
) else (
    echo No default subtitle track. Copying only video and audio...
    ffmpeg -i "%INPUT%" -map 0:v -map 0:a -c copy "%OUTPUT%"  
)

endlocal

(ungetestet, aber damit kannst Du Dich dann weiter vor arbeiten)

Gruß

DivideByZero
Balluf
Balluf 18.05.2025 um 14:30:32 Uhr
Goto Top
Danke für den Ansatz.
Habe mich damit mal befasst, komme aber nicht wirklich weiter.
Kenne mich mit diesen Verschachtelungen nicht aus.

Grüße

Balluf
Crusher79
Crusher79 18.05.2025 um 17:14:52 Uhr
Goto Top
Hallo,

https://mkvtoolnix.download/downloads.html

Gibt es auch für Windows als GUI.

Du könntest da alles einstellen und es dann in die Batch Queue schieben. Einstellungen in der GUI via Haken, DropDown Menüs etc.

Standard Audio Spur, usw.

https://mkvtoolnix.org/

Kostenlos und du kannst mehrere Filme in die Queue schieben und dann entspannt einen Kaffee trinken.

mfg Crusher
Balluf
Balluf 18.05.2025 um 17:49:26 Uhr
Goto Top
Das ist richtig,
aber genau das möchte ich ja mit einem Batch Script umgehen
bzw. automatisieren.

Grüße
Balluf
DivideByZero
DivideByZero 18.05.2025 um 18:22:13 Uhr
Goto Top
Is there a command-line version of MKVToolNix?
Yes, MKVToolNix includes a command-line interface (CLI) for advanced users who prefer scripting or automation.
Du wirst Dich dann nur einmal damit beschäftigen müssen, wie das auf der Kommandozeile so geht.

Für o.g. Code z.B. weiterführend:

www.tutorialspoint.com/batch_script/batch_script_if_statement.htm und zur For-Schleife hier aus dem Forum Tutorial zur FOR-Schleife
Balluf
Balluf 18.05.2025 um 19:44:19 Uhr
Goto Top
Ich habe mich extra hier an die Experten gerichtet,
damit ich nicht noch ein Studium zum Thema FFMPEG und Batch Dateien machen muss.
Es wäre nett wenn nur die eine Lösung anbieten würden, die sich auch damit auskennen
und das ohne großen Aufwand niederschreiben können.

Grüße
Balluf
DivideByZero
DivideByZero 18.05.2025, aktualisiert am 19.05.2025 um 00:09:54 Uhr
Goto Top
Da hast Du wohl den Sinn eines solchen Forums falsch verstanden. Wir sind Ehrenamtler, investieren unsere (Frei-)Zeit, warum sollen wir Dir ein komplettes Skript schreiben, ohne dass Du bereit bist, Zeit in Verständnis zu investieren? So etwas geht über in den Bereich Dienstleistung.
Ein Studium ist auch schlicht eine maßlose Übertreibung. Wenn Du Dir die Links anschaust, den Code oben nimmst, ggf. auch ein weiteres Tool mit ins Boot nimmst, dann - heutzutage geht das super - KI mit befragst, dann lernst Du was und kannst das auch selbst machen.
Crusher79
Crusher79 18.05.2025 um 19:57:02 Uhr
Goto Top
Es gibt video Foren die nix anderes machen! Hier ist es eher was für Hobbyisten.

Ich hätte auch nur powershell angeboten...
DivideByZero
DivideByZero 18.05.2025 aktualisiert um 21:24:01 Uhr
Goto Top
...hier ein weiterer ungetesteter Code, der per ChatGPT verfeinert ist:

@echo off
setlocal enabledelayedexpansion

:: Eingabe- und Ausgabeordner definieren
set "input_folder=C:\Pfad\Zu\Eingabeordner"  
set "output_folder=C:\Pfad\Zu\Ausgabeordner"  

:: Sicherstellen, dass der Ausgabeordner existiert
if not exist "%output_folder%" (  
    mkdir "%output_folder%"  
)

:: Durchlaufe alle .mkv-Dateien im Eingabeordner
for %%F in ("%input_folder%\*.mkv") do (  
    echo ===============================
    echo Verarbeite: %%~nxF

    set "input_file=%%F"  
    set "output_file=%output_folder%\%%~nxF"  
    set "subtitle_index="  

    :: Suche nach Subtitle-Streams mit default=1
    for /f "delims=" %%S in ('ffprobe -v error -select_streams s -show_entries stream=index:tags -of default=noprint_wrappers=1:nokey=1 "%%F"') do (  
        echo Prüfe Subtitle: %%S
        echo %%S | findstr /c:"default=1" >nul  
        if !errorlevel! == 0 (
            set "subtitle_index=1"  
        )
    )

    :: Baue ffmpeg-Befehl zusammen
	set "ffmpeg_cmd=ffmpeg -i "%%F" -map 0:v:0 -c:v copy -map 0:a:0 -c:a eac3 -b:a 640k -ar 48000"  

    if defined subtitle_index (
        set "ffmpeg_cmd=!ffmpeg_cmd! -map 0:s:0 -c:s copy"  
    ) else (
        echo Keine default Untertitelspur gefunden.
    )

    set "ffmpeg_cmd=!ffmpeg_cmd! -map_metadata -1 -map_chapters -1 -y "!output_file!""  

    echo Starte Verarbeitung:
    echo !ffmpeg_cmd!
    call !ffmpeg_cmd!
)

echo ===============================
echo Alle Dateien verarbeitet.
pause
Balluf
Balluf 19.05.2025 um 21:28:09 Uhr
Goto Top
Vielen Dank für das zweite Script.
Da dieses sehr vielversprechend aussah,
habe ich mich nochmal damit beschäftigt und versucht es zum laufen zu bringen.

Der erste Test ergab nach Anpassung von "input_folder" und "output_folder"
sowie Pfadangabe zu ffprobe folgendes Ergebnis:

Argument 'noprint_wrappers' provided as input filename, but 'index:tags' was already specified.  

Stunden später, nachdem ich herausgefunden habe was diese Meldung überhaupt bedeutet,
habe ich folgende Zeile angepasst und tatsächlich eine Ausgabe erhalten.

   :: Suche nach Subtitle-Streams mit default=1
   for /f "delims=" %%S in ('D:\Progs\ffmpeg\bin\ffprobe.exe -v error -select_streams s -show_entries stream^=index:tags -of default^=noprint_wrappers^=1:nokey^=1 "%%F"') do (    

Ausgabe:

===============================
Verarbeite: input.mit.sub.mkv
Pr├╝fe Subtitle: 3
Pr├╝fe Subtitle: ger
Pr├╝fe Subtitle: German forced
Pr├╝fe Subtitle: 0
Pr├╝fe Subtitle: 00:46:05.920000000
Pr├╝fe Subtitle: 6
Pr├╝fe Subtitle: 174
Pr├╝fe Subtitle: mkvmerge v81.0 ('Milliontown') 64-bit  
Pr├╝fe Subtitle: 2024-08-08 07:00:26
Pr├╝fe Subtitle: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Pr├╝fe Subtitle: libebml v1.4.4 + libmatroska v1.7.1
Pr├╝fe Subtitle: 2024-08-08T07:00:26.000000Z
Keine default Untertitelspur gefunden.

Das Script lief weiter durch und machte was es sollte,
da keine default Untertitelspur gefunden wurde,
wurde auch keine kopiert.

Wenn man sich die Ausgabe mal ansieht,
fällt einem sehr schnell auf, dass keine Zeile für die default Flag zu sehen ist.

Genau das ist jetzt ein neues Problem,
welches ich in stundenlanger Recherche versucht habe zu lösen.

Das Ergebnis ist, dass die Ausgabe im json Format erfolgen sollte,
da diese viel preziser ist.

Hier die angepasste Zeile:

    :: Suche nach Subtitle-Streams mit default=1
    for /f "delims=" %%S in ('D:\Progs\ffmpeg\bin\ffprobe.exe -v error -select_streams s:0 -print_format json -show_streams "%%F"') do (    
        echo Pruefe Subtitle: %%S
        echo %%S | findstr /r "'default'= 1" >nul  
        if !errorlevel! == 0 (
            set "subtitle_index=1"  
        )
    )


Ausgabe:

===============================
Verarbeite: input.mit.sub.mkv
Pruefe Subtitle: {
Pruefe Subtitle:     "streams": [  
Pruefe Subtitle:         {
Pruefe Subtitle:             "index": 3,  
Pruefe Subtitle:             "codec_name": "subrip",  
Pruefe Subtitle:             "codec_long_name": "SubRip subtitle",  
Pruefe Subtitle:             "codec_type": "subtitle",  
Pruefe Subtitle:             "codec_tag_string": "[0][0][0][0]",  
Pruefe Subtitle:             "codec_tag": "0x0000",  
Pruefe Subtitle:             "r_frame_rate": "0/0",  
Pruefe Subtitle:             "avg_frame_rate": "0/0",  
Pruefe Subtitle:             "time_base": "1/1000",  
Pruefe Subtitle:             "start_pts": 0,  
Pruefe Subtitle:             "start_time": "0.000000",  
Pruefe Subtitle:             "duration_ts": 3200384,  
Pruefe Subtitle:             "duration": "3200.384000",  
Pruefe Subtitle:             "disposition": {  
Pruefe Subtitle:                 "default": 1,  
Pruefe Subtitle:                 "dub": 0,  
Pruefe Subtitle:                 "original": 0,  
Pruefe Subtitle:                 "comment": 0,  
Pruefe Subtitle:                 "lyrics": 0,  
Pruefe Subtitle:                 "karaoke": 0,  
Pruefe Subtitle:                 "forced": 1,  
Pruefe Subtitle:                 "hearing_impaired": 0,  
Pruefe Subtitle:                 "visual_impaired": 0,  
Pruefe Subtitle:                 "clean_effects": 0,  
Pruefe Subtitle:                 "attached_pic": 0,  
Pruefe Subtitle:                 "timed_thumbnails": 0,  
Pruefe Subtitle:                 "non_diegetic": 0,  
Pruefe Subtitle:                 "captions": 0,  
Pruefe Subtitle:                 "descriptions": 0,  
Pruefe Subtitle:                 "metadata": 0,  
Pruefe Subtitle:                 "dependent": 0,  
Pruefe Subtitle:                 "still_image": 0,  
Pruefe Subtitle:                 "multilayer": 0  
Pruefe Subtitle:             },
Pruefe Subtitle:             "tags": {  
Pruefe Subtitle:                 "language": "ger",  
Pruefe Subtitle:                 "title": "German forced",  
Pruefe Subtitle:                 "BPS": "0",  
Pruefe Subtitle:                 "DURATION": "00:46:05.920000000",  
Pruefe Subtitle:                 "NUMBER_OF_FRAMES": "6",  
Pruefe Subtitle:                 "NUMBER_OF_BYTES": "174",  
Pruefe Subtitle:                 "_STATISTICS_WRITING_APP": "mkvmerge v81.0 ('Milliontown') 64-bit",  
Pruefe Subtitle:                 "_STATISTICS_WRITING_DATE_UTC": "2024-08-08 07:00:26",  
Pruefe Subtitle:                 "_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"  
Pruefe Subtitle:             }
Pruefe Subtitle:         }
Pruefe Subtitle:     ]
Pruefe Subtitle: }
Starte Verarbeitung:

Und siehe da, die default Flag mit dem Wert 1 wird mir angezeigt,
aber leider nicht ausgelesen, dafür fehlt mir noch der richtige Code,
den ich seit gestern verzweifelt versuche zu finden.
Wenn du mir dabei nochmal helfen könntest,
wäre das super toll ;)
Balluf
Lösung Balluf 20.05.2025 um 18:52:19 Uhr
Goto Top
Ich habe es geschafft,
vielen Dank an alle, die mir geholfen haben.

Grüße
Balluf


Hier mein Code:

@echo off
setlocal enabledelayedexpansion

:: Eingabe- und Ausgabeordner definieren
set "input_folder=D:\Input"    
set "output_folder=E:\Output"    

:: Sicherstellen, dass der Ausgabeordner existiert
if not exist "%output_folder%" (    
    mkdir "%output_folder%"    
)

:: Durchlaufe alle .mkv-Dateien im Eingabeordner
for %%F in ("%input_folder%\*.mkv") do (    
    echo ===============================
    echo Verarbeite: %%~nxF

    set "input_file=%%F"    
    set "output_file=%output_folder%\%%~nxF"    
    set "subtitle_index="    

    :: Suche nach Subtitle-Streams mit default=1
    for /f "delims=" %%S in ('D:\Progs\ffmpeg\bin\ffprobe.exe -v error -select_streams s:0 -print_format default -show_streams "%%F"') do (    
        echo Pruefe Subtitle: %%S
        echo %%S | findstr /c "default=1" >nul  
        if !errorlevel! == 0 (
            set "subtitle_index=1"  
        )
    )
	
    :: Baue ffmpeg-Befehl zusammen
	set "ffmpeg_cmd=D:\Progs\ffmpeg\bin\ffmpeg.exe -i "%%F" -map 0:v:0 -c:v copy -map 0:a:0 -c:a eac3 -b:a 640k -ar 48000"    

    if defined subtitle_index (
        echo Default wurde gefunden.	
        set "ffmpeg_cmd=!ffmpeg_cmd! -map 0:s:0 -c:s copy"    
    ) else (
        echo Keine default Untertitelspur gefunden.
    )

    set "ffmpeg_cmd=!ffmpeg_cmd! -map_metadata -1 -map_chapters -1 -y "!output_file!""    

    echo Starte Verarbeitung:
    echo !ffmpeg_cmd!
    call !ffmpeg_cmd!
)

echo ===============================
echo Alle Dateien verarbeitet.
pause
DivideByZero
DivideByZero 20.05.2025 um 21:27:49 Uhr
Goto Top
Danke für das Teilen der Lösung