Aquí hay dos scripts de PowerShell para dividir videos largos en capítulos más pequeños por escenas negras.
Guárdelos como Detect_black.ps1 y Cut_black.ps1. Descarga ffmpeg para Windows y dile al script la ruta a tu ffmpeg.exe y a tu carpeta de video en la sección de opciones.

Ambas secuencias de comandos no tocarán los archivos de video existentes, permanecen intactos.
Sin embargo, obtendrá un par de archivos nuevos en el mismo lugar donde están sus videos de entrada
- Un archivo de registro por video con la salida de la consola para ambos comandos ffmpeg utilizados
- Un archivo CSV por video con todas las marcas de tiempo de escenas negras para un ajuste manual
- Un par de videos nuevos dependiendo de cuántas escenas negras se detecten previamente

Primer script que se ejecuta: 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
}
Como funciona
El primer script recorre todos los archivos de video que coinciden con una extensión especificada y no coinciden con el patrón *_???.*
, ya que se nombraron nuevos capítulos de video <filename>_###.<ext>
y queremos excluirlos.
Busca en todas las escenas negras y escribe la marca de tiempo de inicio y la duración de la escena negra en un nuevo archivo CSV llamado <video_name>_cutpoints.txt
También calcula puntos de corte como se muestra: cutpoint = black_start + black_duration / 2
. Más tarde, el video se segmenta en estas marcas de tiempo.
El archivo cutpoints.txt para su video de muestra mostrará:
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
Después de una carrera, puede manipular los puntos de corte manualmente si lo desea. Si ejecuta el script nuevamente, todo el contenido antiguo se sobrescribe. Tenga cuidado al editar manualmente y guardar su trabajo en otro lugar.
Para el video de muestra, el comando ffmpeg para detectar escenas negras es
$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null
Hay 3 números importantes que se pueden editar en la sección de opciones del script
d=4
significa que solo se detectan escenas negras de más de 4 segundos
pic_th=0.98
es el umbral para considerar una imagen como "negra" (en porcentaje)
pix=0.15
establece el umbral para considerar un píxel como "negro" (en luminancia). Como tiene videos antiguos de VHS, no tiene escenas completamente negras en sus videos. El valor predeterminado 10 no funcionará y tuve que aumentar ligeramente el umbral
Si algo sale mal, verifique el archivo de registro correspondiente llamado <video_name>__ffmpeg.log
. Si faltan las siguientes líneas, aumente los números mencionados anteriormente hasta que detecte todas las escenas negras:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Segundo script que se ejecuta: 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
}
Como funciona
El segundo script itera sobre todos los archivos de video de la misma manera que lo hizo el primer script. Lee solo las marcas de tiempo cortadas del correspondiente cutpoints.txt
de un video.
Luego, reúne un nombre de archivo adecuado para los archivos de capítulos y le dice a ffmpeg que segmente el video. Actualmente, los videos se cortan sin volver a codificar (superrápidos y sin pérdidas). Debido a esto, puede haber una imprecisión de 1-2 segundos con las marcas de tiempo del punto de corte porque ffmpeg solo puede cortar en fotogramas clave. Como solo copiamos y no volvemos a codificar, no podemos insertar fotogramas clave por nuestra cuenta.
El comando para el video de muestra sería
$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"
Si algo sale mal, eche un vistazo al ffmpeg.log correspondiente
Referencias
Que hacer
Pregunte a OP si el formato CSV es mejor que un archivo de texto como archivo de punto de corte, para que pueda editarlos con Excel un poco más fácil
»Implementado
Implemente una forma de formatear marcas de tiempo como [hh]: [mm]: [ss], [milisegundos] en lugar de solo segundos
»Implementado
Implemente un comando ffmpeg para crear archivos png mosaik para cada capítulo
»Implementado
Elabore si -c copy
es suficiente para el escenario de OP o si necesitamos volver a codificar por completo.
Parece que Ryan ya está en eso .