Uzun videoları siyah sahnelerle daha küçük bölümlere ayırmak için iki PowerShell betiği.
Bunları Detect_black.ps1 ve Cut_black.ps1 olarak kaydedin. İndir Windows için ffmpeg ve komut dizisini seçeneği bölümünün altındaki FFMPEG.exe yolunu ve video klasörünü söyle.
Her iki komut dosyası da mevcut video dosyalarına dokunmaz, dokunulmaz.
Ancak, giriş videolarınızın olduğu yerde birkaç yeni dosya alacaksınız
- Her iki kullanılan ffmpeg komutu için konsol çıkışı ile video başına bir günlük dosyası
- Manuel ince ayar için tüm video sahnelerini içeren video başına bir CSV dosyası
- Daha önce tespit edilen siyah sahneye bağlı olarak birkaç yeni video
Çalıştırılacak ilk komut dosyası: 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
}
O nasıl çalışır
İlk komut dosyası, belirli video uzantılarıyla eşleşen ve kalıpla eşleşmeyen tüm video dosyaları üzerinden yinelenir *_???.*
, çünkü yeni video bölümleri adlandırılmıştır <filename>_###.<ext>
ve bunları hariç tutmak istiyoruz.
Tüm siyah sahneleri arar ve başlangıç zaman damgasını ve siyah sahne süresini adlı yeni bir CSV dosyasına yazar <video_name>_cutpoints.txt
Gösterildiği gibi, aynı zamanda kesim noktaları hesaplar: cutpoint = black_start + black_duration / 2
. Daha sonra video bu zaman damgalarında bölümlere ayrılır.
Örnek videonuz için cutpoints.txt dosyası şunu gösterir:
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
Bir koşudan sonra, istenirse kesme noktalarını elle değiştirebilirsiniz. Komut dosyasını tekrar çalıştırırsanız, tüm eski içeriğin üzerine yazılır. Elle düzenlerken dikkatli olun ve çalışmanızı başka bir yere kaydedin.
Örnek video için siyah sahneleri tespit etmek için ffmpeg komutu
$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null
Komut dosyasının seçenek bölümünde düzenlenebilir 3 önemli sayı vardır
d=4
sadece 4 saniyeden uzun siyah sahnelerin algılandığı anlamına gelir
pic_th=0.98
bir resmi "siyah" olarak kabul etme eşiğidir (yüzde olarak)
pix=0.15
(piksel cinsinden) bir pikseli "siyah" olarak kabul etme eşiğini ayarlar. Eski VHS videolarınız olduğundan, videolarınızda tamamen siyah sahneler yok. Varsayılan değer 10 çalışmaz ve eşiği biraz artırmak zorunda kaldım
Bir şeyler ters giderse, çağrılan ilgili günlük dosyasını kontrol edin <video_name>__ffmpeg.log
. Aşağıdaki satırlar eksikse, tüm siyah sahneleri algılayana kadar yukarıda belirtilen sayıları artırın:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Çalıştırılacak ikinci komut dosyası: 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
}
O nasıl çalışır
İkinci komut dosyası, tüm komut dosyalarında olduğu gibi, ilk komut dosyasında olduğu gibi yinelenir. Bir videonun karşılık gelen kesim zaman damgalarını yalnızca okur cutpoints.txt
.
Daha sonra, bölüm dosyaları için uygun bir dosya adı oluşturur ve ffmpeg'e videoyu segmentlere ayırmasını söyler. Şu anda videolar yeniden kodlanmadan dilimleniyor (süper hızlı ve kayıpsız). Bu nedenle, kesme noktası zaman damgalarında 1-2 saniye hatalı olabilir, çünkü ffmpeg yalnızca key_frames'de kesebilir. Sadece kopyaladığımız ve yeniden kodlamadığımız için, key_frames'i kendi başımıza ekleyemiyoruz.
Örnek video için komut
$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"
Bir şeyler ters giderse, ilgili ffmpeg.log dosyasına bir göz atın
Referanslar
- Windows için FFmpeg indir
- Segment dokümantasyonu: segment_times ve segment_frames seçeneklerdir
Yapmak
Kesim noktası dosyası olarak CSV biçiminin bir metin dosyasından daha iyi olup olmadığını OP'ye sorun, böylece bunları Excel ile biraz daha kolay düzenleyebilirsiniz
»
Zaman damgalarını yalnızca saniyeler yerine [ss]: [mm]: [ss], [milisaniye] olarak biçimlendirmenin bir yolunu uygulayın
»Uygulandı
Her bölüm için mozaik png dosyaları oluşturmak için bir ffmpeg komutu uygulayın
»
Eğer ayrıntılı -c copy
OP'ın senaryo için yeterli ya da biz tamamen yeniden kodlamak için gereken bir.
Görünüşe göre Ryan zaten üzerinde .