Voici deux scripts PowerShell pour diviser de longues vidéos en petits chapitres par scènes noires.
Enregistrez-les sous Detect_black.ps1 et Cut_black.ps1. Téléchargez ffmpeg pour Windows et indiquez au script le chemin d'accès à votre ffmpeg.exe et à votre dossier vidéo dans la section des options.
Les deux scripts ne toucheront pas les fichiers vidéo existants, ils restent intacts.
Cependant, vous obtiendrez quelques nouveaux fichiers au même endroit où vos vidéos d'entrée sont
- Un fichier journal par vidéo avec la sortie de la console pour les deux commandes ffmpeg utilisées
- Un fichier CSV par vidéo avec tous les horodatages des scènes noires pour un réglage fin manuel
- Quelques nouvelles vidéos en fonction du nombre de scènes noires détectées précédemment
Premier script à exécuter: 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
}
Comment ça marche
Le premier script parcourt tous les fichiers vidéo qui correspondent à une extension spécifiée et ne correspondent pas au modèle *_???.*
, car de nouveaux chapitres vidéo ont été nommés <filename>_###.<ext>
et nous voulons les exclure.
Il recherche toutes les scènes noires et écrit l'horodatage de début et la durée de la scène noire dans un nouveau fichier CSV nommé <video_name>_cutpoints.txt
Il calcule également des points de coupe comme indiqué: cutpoint = black_start + black_duration / 2
. Plus tard, la vidéo est segmentée à ces horodatages.
Le fichier cutpoints.txt de votre exemple de vidéo afficherait:
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
Après une analyse, vous pouvez manipuler les points de coupe manuellement si vous le souhaitez. Si vous réexécutez le script, tout l'ancien contenu est écrasé. Soyez prudent lorsque vous modifiez manuellement et enregistrez votre travail ailleurs.
Pour l'exemple de vidéo, la commande ffmpeg pour détecter les scènes noires est
$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null
Il y a 3 nombres importants qui sont modifiables dans la section des options du script
d=4
signifie que seules les scènes noires de plus de 4 secondes sont détectées
pic_th=0.98
est le seuil pour considérer une image comme "noire" (en pourcentage)
pix=0.15
définit le seuil pour considérer un pixel comme "noir" (en luminance). Étant donné que vous avez d'anciennes vidéos VHS, vous n'avez pas de scènes complètement noires dans vos vidéos. La valeur par défaut 10 ne fonctionnera pas et j'ai dû augmenter légèrement le seuil
En cas de problème, vérifiez le fichier journal correspondant appelé <video_name>__ffmpeg.log
. Si les lignes suivantes sont manquantes, augmentez les nombres mentionnés ci-dessus jusqu'à ce que vous détectiez toutes les scènes noires:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Deuxième script à exécuter: 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
}
Comment ça marche
Le deuxième script parcourt tous les fichiers vidéo de la même manière que le premier script. Il lit uniquement les horodatages coupés du correspondant cutpoints.txt
d'une vidéo.
Ensuite, il rassemble un nom de fichier approprié pour les fichiers de chapitre et indique à ffmpeg de segmenter la vidéo. Actuellement, les vidéos sont découpées sans ré-encodage (ultra-rapide et sans perte). Pour cette raison, il peut y avoir une imprécision de 1 à 2 avec les horodatages des points de coupure car ffmpeg ne peut couper que sur les images clés. Comme nous copions et ne réencodons pas, nous ne pouvons pas insérer les images clés par nous-mêmes.
La commande pour l'exemple de vidéo serait
$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"
En cas de problème, consultez le ffmpeg.log correspondant
Références
Faire
Demandez à OP si le format CSV est meilleur qu'un fichier texte comme fichier de point de coupure, afin que vous puissiez les modifier avec Excel un peu plus facilement
»
Implémentez un moyen de formater les horodatages comme [hh]: [mm]: [ss], [millisecondes] plutôt que seulement quelques secondes
»
Implémentez une commande ffmpeg pour créer des fichiers png mosaik pour chaque chapitre
»Implémenté
Élaborez si cela -c copy
suffit pour le scénario OP ou si nous devons ré-encoder complètement.
On dirait que Ryan est déjà dessus .