以下は、長いビデオを黒いシーンで小さな章に分割する2つのPowerShellスクリプトです。
それらをDetect_black.ps1およびCut_black.ps1として保存します。Windows用のffmpegをダウンロードし、オプションセクションの下の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
実行する2番目のスクリプト: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
}
それはどのように機能しますか
2番目のスクリプトは、最初のスクリプトと同じ方法ですべてのビデオファイルを反復処理します。それはビデオの対応からカットタイムスタンプのみを読み込みますcutpoints.txt
。
次に、チャプターファイルに適したファイル名をまとめ、ffmpegにビデオをセグメント化するように指示します。現在、ビデオは再エンコードなしでスライスされています(超高速でロスレス)。このため、ffmpegはkey_framesでしかカットできないため、カットポイントのタイムスタンプが1〜2秒不正確になる可能性があります。コピーして再エンコードしないため、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形式がカットポイントファイルとしてのテキストファイルよりも優れているかどうかOPに尋ね、Excelで少し簡単に編集できるようにする
»実装済み
タイムスタンプを秒だけではなく[hh]:[mm]:[ss]、[milliseconds]にフォーマットする方法を実装する
»実装済み
ffmpegコマンドを実装して、各章のmosaik pngファイルを作成
»実装
場合は精巧な-c copy
OPのシナリオのために十分であるか、我々は完全に再エンコードする必要があります。
ライアンはすでにそれに参加しているようです。