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 .
Voici le bonus: ce 3e script PowerShell génère une image miniature de mosaïque
Vous recevrez une image par chapitre vidéo qui ressemble à l'exemple ci-dessous.
L'idée principale est d'obtenir un flux continu d'images sur la vidéo complète. Nous le faisons avec l' option de sélection de ffmpeg .
Tout d'abord, nous récupérons le nombre total de trames avec une méthode ingénieuse (par exemple 2000) et le divisons par le biais de notre nombre de vignettes par défaut (par exemple 5 x 4 = 20). Nous voulons donc générer une image toutes les 100 images depuis
2000 / 20 = 100
La commande ffmpeg résultante pour générer la miniature pourrait ressembler à
Dans le code ci-dessus, vous voyez 9
-vf
combinaisons différentes comprenantselect=not(mod(n\,XXX))
où XXX est une fréquence d'images calculéethumbnail
qui sélectionne automatiquement les cadres les plus représentatifsselect='gt(scene\,XXX)
+-vsync vfr
où XXX est un seuil avec lequel vous devez jouermpdecimate
- Supprimez les cadres presque dupliqués. Bon contre les scènes noiresyadif
- Désentrelacer l'image d'entrée. Je ne sais pas pourquoi, mais ça marcheLa version 3 est le meilleur choix à mon avis. Tous les autres sont commentés, mais vous pouvez toujours les essayer. J'ai pu éliminer la plupart des vignettes floues à l' aide
mpdecimate
,yadif
etselect=not(mod(n\,XXX))
. Ouais!Pour votre exemple de vidéo, je reçois ces aperçus
Cliquez pour agrandir
Cliquez pour agrandir
J'ai téléchargé toutes les vignettes créées par ces versions. Jetez-y un œil pour une comparaison complète.
la source
select='gt(scene\,0.4)'
au travail. Et je ne pouvais pas non plus me mettrefps="fps=1/600"
au travail. Au fait, avez-vous une idée de superuser.com/questions/725734 ? Merci beaucoup pour toute votre aide. J'ai hâte d'aider ma famille à découvrir des tonnes de vieux souvenirs.Appréciez les deux scripts, un excellent moyen de diviser des vidéos.
Pourtant, j'ai eu quelques problèmes avec des vidéos ne montrant pas l'heure correcte par la suite et je n'ai pas pu sauter à une heure précise. Une solution consistait à démultiplexer puis à multiplexer les flux à l'aide de Mp4Box.
Un autre moyen plus simple pour moi était d'utiliser mkvmerge pour le fractionnement. Par conséquent, les deux scripts ont dû être modifiés. Pour detect_black.ps1, seul le "* .mkv" devait être ajouté à l'option de filtrage, mais ce n'est pas nécessairement si vous ne commencez qu'avec des fichiers mp4.
La fonction est la même, mais aucun problème avec les temps vidéo jusqu'à présent. Merci pour l'inspiration.
la source
J'espère que je me trompe, mais je ne pense pas que ce que vous demandez soit possible. Cela pourrait être possible lors du réencodage de la vidéo, mais en tant que "simple tranche sans perte", je ne connais aucun moyen.
De nombreux programmes de montage vidéo auront une fonction d'analyse automatique ou quelque chose d'équivalent qui pourrait diviser vos vidéos sur les cadres noirs, mais cela nécessitera un ré-encodage de la vidéo.
Bonne chance!
la source