Ось два сценарії 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
Список літератури
Зробити
Запитайте ОП, чи формат CSV кращий, ніж текстовий файл, як файл зрізу, так що ви можете редагувати їх за допомогою Excel трохи простіше
»Реалізовано
Реалізуйте спосіб форматування часових позначок у вигляді [год]: [мм]: [сс], [мілісекунд], а не лише секунди
»
Реалізуйте команду ffmpeg для створення mosaik png-файлів для кожної глави
»Реалізовано
Розробіть, якщо -c copy
цього достатньо для сценарію ОП або нам потрібно повністю перекодувати.
Здається, Райан уже на ньому .