Вот два сценария PowerShell для разделения длинных видеороликов на более мелкие главы черными сценами.
Сохраните их как Detect_black.ps1 и Cut_black.ps1. Загрузите ffmpeg для Windows и сообщите сценарию путь к файлу ffmpeg.exe и папке с видео в разделе параметров.
Оба сценария не затрагивают существующие видеофайлы, они остаются нетронутыми.
Тем не менее, вы получите несколько новых файлов в том же месте, где находятся ваши входные видео
- Файл журнала для каждого видео с консольным выводом для обеих используемых команд ffmpeg
- Файл CSV для каждого видео со всеми временными метками черных сцен для ручной тонкой настройки
- Пара новых видео в зависимости от того, сколько черных сцен было обнаружено ранее
Первый скрипт для запуска: 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
}
Как это работает
Первый скрипт перебирает все видеофайлы, которые соответствуют указанному расширению и не соответствуют шаблону *_???.*
, Так как новые видео главы были названы <filename>_###.<ext>
и мы хотим исключить их.
Он ищет все черные сцены и записывает метку времени начала и длительность черной сцены в новый CSV-файл с именем <video_name>_cutpoints.txt
Он также вычисляет точки среза, как показано: cutpoint = black_start + black_duration / 2
. Позже, видео становится сегментированным в эти временные метки.
Файл cutpoints.txt для вашего примера видео будет отображать:
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
После прогона вы можете при желании манипулировать точками среза вручную. Если вы снова запустите скрипт, весь старый контент будет перезаписан. Будьте осторожны при ручном редактировании и сохраняйте свою работу в другом месте.
Для примера видео команда ffmpeg для обнаружения черных сцен
$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null
В разделе опций скрипта есть 3 важных номера, которые можно редактировать.
d=4
означает, что обнаружены только черные сцены длительностью более 4 секунд
pic_th=0.98
- это порог для того, чтобы считать изображение "черным" (в процентах).
pix=0.15
устанавливает порог для рассмотрения пикселя как "черного" (по яркости). Поскольку у вас есть старые видео VHS, в ваших видео нет полностью черных сцен. Значение по умолчанию 10 не будет работать, и мне пришлось немного увеличить порог
Если что-то пойдет не так, проверьте соответствующий файл журнала с именем <video_name>__ffmpeg.log
. Если следующие строки отсутствуют, увеличивайте числа, упомянутые выше, пока не обнаружите все черные сцены:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Второй скрипт для запуска: 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
}
Как это работает
Второй скрипт перебирает все видеофайлы так же, как первый скрипт. Он считывает только вырезанные временные метки из соответствующих cutpoints.txt
видео.
Затем он собирает подходящее имя файла для файлов главы и сообщает ffmpeg о сегментации видео. В настоящее время видео нарезано без перекодирования (сверхбыстрое и без потерь). Из-за этого может быть неточность 1-2 с с временными метками точки вырезания, потому что ffmpeg может вырезать только в key_frames. Поскольку мы просто копируем и не перекодируем, мы не можем вставить key_frames самостоятельно.
Команда для примера видео будет
$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"
Если что-то пойдет не так, взгляните на соответствующий файл ffmpeg.log
Рекомендации
Сделать
Спросите у OP, лучше ли формат CSV, чем текстовый файл в качестве файла точки обрезки, чтобы вы могли редактировать их в Excel немного проще
»Реализовано
Реализуйте способ форматировать метки времени как [чч]:[мм]:[сс], [миллисекунды], а не только секунды
»Реализовано
Реализуйте команду ffmpeg для создания png-файлов мозаики для каждой главы
»Реализовано
Уточните, если -c copy
достаточно для сценария OP или нам нужно полностью перекодировать.
Похоже, Райан уже на нем.