Ecco due script di PowerShell per dividere lunghi video in capitoli più piccoli per scene nere.
Salvali come Detect_black.ps1 e Cut_black.ps1. Scarica ffmpeg per Windows e indica allo script il percorso di ffmpeg.exe e della cartella video nella sezione delle opzioni.
Entrambi gli script non toccano i file video esistenti, rimangono intatti.
Tuttavia, otterrai un paio di nuovi file nello stesso punto in cui si trovano i tuoi video di input
- Un file di log per video con l'output della console per entrambi i comandi ffmpeg utilizzati
- Un file CSV per video con tutti i timestamp delle scene nere per la regolazione fine manuale
- Un paio di nuovi video a seconda di quante scene nere sono state precedentemente rilevate
Primo script da eseguire: 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
}
Come funziona
Il primo script scorre attraverso tutti i file video che corrispondono a un'estensione specificata e non corrispondono al modello *_???.*
, poiché sono stati nominati nuovi capitoli video <filename>_###.<ext>
e vogliamo escluderli.
Cerca tutte le scene nere e scrive la data e l'ora di inizio e la durata della scena nera in un nuovo file CSV denominato <video_name>_cutpoints.txt
Si calcola anche punti di taglio come illustrato: cutpoint = black_start + black_duration / 2
. Successivamente, il video viene segmentato in questi timestamp.
Il file cutpoints.txt per il tuo video di esempio mostrerebbe:
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
Dopo una corsa, è possibile manipolare manualmente i punti di taglio se lo si desidera. Se si esegue nuovamente lo script, tutto il vecchio contenuto viene sovrascritto. Fai attenzione quando modifichi manualmente e salva il tuo lavoro altrove.
Per il video di esempio è il comando ffmpeg per rilevare le scene nere
$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null
Ci sono 3 numeri importanti che sono modificabili nella sezione delle opzioni dello script
d=4
significa che vengono rilevate solo scene nere più lunghe di 4 secondi
pic_th=0.98
è la soglia per considerare un'immagine come "nera" (in percentuale)
pix=0.15
imposta la soglia per considerare un pixel come "nero" (in luminanza). Dato che hai vecchi video VHS, non hai scene completamente nere nei tuoi video. Il valore predefinito 10 non funzionerà e ho dovuto aumentare leggermente la soglia
Se qualcosa va storto, controlla il file di registro corrispondente chiamato <video_name>__ffmpeg.log
. Se mancano le seguenti righe, aumentare i numeri sopra menzionati fino a rilevare tutte le scene nere:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Secondo script da eseguire: 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
}
Come funziona
Il secondo script scorre su tutti i file video allo stesso modo del primo script. Legge solo i timestamp tagliati dalla corrispondente cutpoints.txt
di un video.
Successivamente, mette insieme un nome file adatto per i file dei capitoli e dice a ffmpeg di segmentare il video. Attualmente i video vengono suddivisi senza ricodifica (superveloce e senza perdita di dati). Per questo motivo, potrebbe esserci un'inesattezza di 1-2 secondi con i timestamp del punto di taglio perché ffmpeg può tagliare solo in key_frames. Dato che copiamo e non ricodifichiamo, non possiamo inserire key_frames da soli.
Il comando per il video di esempio sarebbe
$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"
Se qualcosa va storto, dai un'occhiata al corrispondente ffmpeg.log
Riferimenti
Fare
Chiedi a OP se il formato CSV è migliore di un file di testo come file di punti di taglio, quindi puoi modificarli con Excel un po 'più facilmente
»Implementato
Implementa un modo per formattare i timestamp come [hh]: [mm]: [ss], [millisecondi] anziché solo secondi
»Implementato
Implementa un comando ffmpeg per creare file png mosaik per ogni capitolo
»Implementato
Elaborare se -c copy
è sufficiente per lo scenario di OP o di abbiamo bisogno di ricodificare completamente.
Sembra che Ryan ci sia già .