Hier sind zwei PowerShell-Skripte, mit denen Sie lange Videos nach schwarzen Szenen in kleinere Kapitel aufteilen können.
Speichern Sie sie als Detect_black.ps1 und Cut_black.ps1. Laden Sie ffmpeg für Windows herunter und teilen Sie dem Skript den Pfad zu Ihrer Datei ffmpeg.exe und Ihrem Videoordner im Optionsbereich mit.
Beide Skripte berühren vorhandene Videodateien nicht, sie bleiben unberührt.
Sie erhalten jedoch einige neue Dateien an derselben Stelle, an der sich Ihre Eingabevideos befinden
- Eine Protokolldatei pro Video mit der Konsolenausgabe für beide verwendeten ffmpeg-Befehle
- Eine CSV-Datei pro Video mit allen Zeitstempeln schwarzer Szenen zur manuellen Feinabstimmung
- Ein paar neue Videos, je nachdem, wie viele schwarze Szenen zuvor erkannt wurden
Erstes Skript, das ausgeführt wird: Detect_black.ps1
### Options __________________________________________________________________________________________________________
$ffmpeg = ".\ffmpeg.exe" # Set path to your ffmpeg.exe; Build Version: git-45581ed (2014-02-16)
$folder = ".\Videos\*" # Set path to your video folder; '\*' must be appended
$filter = @("*.mov","*.mp4") # Set which file extensions should be processed
$dur = 4 # Set the minimum detected black duration (in seconds)
$pic = 0.98 # Set the threshold for considering a picture as "black" (in percent)
$pix = 0.15 # Set the threshold for considering a pixel "black" (in luminance)
### Main Program ______________________________________________________________________________________________________
foreach ($video in dir $folder -include $filter -exclude "*_???.*" -r){
### Set path to logfile
$logfile = "$($video.FullName)_ffmpeg.log"
### analyse each video with ffmpeg and search for black scenes
& $ffmpeg -i $video -vf blackdetect=d=`"$dur`":pic_th=`"$pic`":pix_th=`"$pix`" -an -f null - 2> $logfile
### Use regex to extract timings from logfile
$report = @()
Select-String 'black_start:.*black_end:' $logfile | % {
$black = "" | Select start, end, cut
# extract start time of black scene
$start_s = $_.line -match '(?<=black_start:)\S*(?= black_end:)' | % {$matches[0]}
$start_ts = [timespan]::fromseconds($start_s)
$black.start = "{0:HH:mm:ss.fff}" -f ([datetime]$start_ts.Ticks)
# extract duration of black scene
$end_s = $_.line -match '(?<=black_end:)\S*(?= black_duration:)' | % {$matches[0]}
$end_ts = [timespan]::fromseconds($end_s)
$black.end = "{0:HH:mm:ss.fff}" -f ([datetime]$end_ts.Ticks)
# calculate cut point: black start time + black duration / 2
$cut_s = ([double]$start_s + [double]$end_s) / 2
$cut_ts = [timespan]::fromseconds($cut_s)
$black.cut = "{0:HH:mm:ss.fff}" -f ([datetime]$cut_ts.Ticks)
$report += $black
}
### Write start time, duration and the cut point for each black scene to a seperate CSV
$report | Export-Csv -path "$($video.FullName)_cutpoints.csv" –NoTypeInformation
}
Wie funktioniert es
Das erste Skript durchläuft alle Videodateien, die einer bestimmten Erweiterung entsprechen und nicht mit dem Muster übereinstimmen *_???.*
, da neue Videokapitel benannt wurden <filename>_###.<ext>
und wir sie ausschließen möchten.
Es durchsucht alle schwarzen Szenen und schreibt den Startzeitstempel und die Dauer der schwarzen Szene in eine neue CSV-Datei mit dem Namen <video_name>_cutpoints.txt
Außerdem werden Schnittpunkte wie folgt berechnet : cutpoint = black_start + black_duration / 2
. Später wird das Video zu diesen Zeitstempeln segmentiert.
Die Datei cutpoints.txt für Ihr Beispielvideo würde Folgendes anzeigen :
start end cut
00:03:56.908 00:04:02.247 00:03:59.578
00:08:02.525 00:08:10.233 00:08:06.379
Nach einem Lauf können Sie die Schnittpunkte bei Bedarf manuell bearbeiten. Wenn Sie das Skript erneut ausführen, werden alle alten Inhalte überschrieben. Seien Sie vorsichtig beim manuellen Bearbeiten und speichern Sie Ihre Arbeit an einem anderen Ort.
Für das Beispielvideo lautet der Befehl ffmpeg zum Erkennen schwarzer Szenen
$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null
Es gibt 3 wichtige Nummern, die im Optionsbereich des Skripts bearbeitet werden können
d=4
bedeutet, dass nur schwarze Szenen erkannt werden, die länger als 4 Sekunden sind
pic_th=0.98
ist die Schwelle für die Betrachtung eines Bildes als "schwarz" (in Prozent)
pix=0.15
Legt den Schwellenwert für die Betrachtung eines Pixels als "schwarz" (in Luminanz) fest. Da Sie alte VHS-Videos haben, haben Ihre Videos keine vollständig schwarzen Szenen. Der Standardwert 10 funktioniert nicht und ich musste den Schwellenwert leicht erhöhen
Wenn etwas schief geht, überprüfen Sie die entsprechende aufgerufene Protokolldatei <video_name>__ffmpeg.log
. Wenn die folgenden Zeilen fehlen, erhöhen Sie die oben genannten Zahlen, bis Sie alle schwarzen Szenen erkennen:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Zweites Skript, das ausgeführt werden soll: cut_black.ps1
### Options __________________________________________________________________________________________________________
$ffmpeg = ".\ffmpeg.exe" # Set path to your ffmpeg.exe; Build Version: git-45581ed (2014-02-16)
$folder = ".\Videos\*" # Set path to your video folder; '\*' must be appended
$filter = @("*.mov","*.mp4") # Set which file extensions should be processed
### Main Program ______________________________________________________________________________________________________
foreach ($video in dir $folder -include $filter -exclude "*_???.*" -r){
### Set path to logfile
$logfile = "$($video.FullName)_ffmpeg.log"
### Read in all cutpoints from *_cutpoints.csv; concat to string e.g "00:03:23.014,00:06:32.289,..."
$cuts = ( Import-Csv "$($video.FullName)_cutpoints.csv" | % {$_.cut} ) -join ","
### put together the correct new name, "%03d" is a generic number placeholder for ffmpeg
$output = $video.directory.Fullname + "\" + $video.basename + "_%03d" + $video.extension
### use ffmpeg to split current video in parts according to their cut points
& $ffmpeg -i $video -f segment -segment_times $cuts -c copy -map 0 $output 2> $logfile
}
Wie funktioniert es
Das zweite Skript durchläuft alle Videodateien auf dieselbe Weise wie das erste Skript. Es werden nur die ausgeschnittenen Zeitstempel aus dem entsprechenden cutpoints.txt
Video eingelesen .
Als nächstes wird ein geeigneter Dateiname für Kapiteldateien zusammengestellt und ffmpeg angewiesen, das Video zu segmentieren. Derzeit werden die Videos ohne Neucodierung geschnitten (superschnell und verlustfrei). Aus diesem Grund kann es bei Schnittpunkt-Zeitstempeln zu Ungenauigkeiten von 1 bis 2 Sekunden kommen, da ffmpeg nur bei key_frames schneiden kann. Da wir nur kopieren und nicht neu codieren, können wir key_frames nicht alleine einfügen.
Der Befehl für das Beispielvideo wäre
$ffmpeg -i "Tape_10_3b.mp4" -f segment -segment_times "00:03:59.578,00:08:06.379" -c copy -map 0 "Tape_10_3b_(%03d).mp4"
Wenn etwas schief geht, schauen Sie sich das entsprechende ffmpeg.log an
Verweise
Machen
Fragen Sie OP, ob das CSV-Format besser ist als eine Textdatei als Schnittpunktdatei, damit Sie sie mit Excel etwas einfacher bearbeiten können.
»Implementiert
Implementieren Sie eine Möglichkeit zum Formatieren von Zeitstempeln als [hh]: [mm]: [ss], [Millisekunden] und nicht nur als Sekunden
»Implementiert
Implementieren Sie einen Befehl ffmpeg, um Mosaik-PNG-Dateien für jedes Kapitel zu erstellen.
»Implementiert
Überlegen Sie, ob dies -c copy
für das OP-Szenario ausreicht oder ob wir es vollständig neu codieren müssen.
Scheint, als wäre Ryan schon dabei .