Dưới đây là hai tập lệnh PowerShell để chia các video dài thành các chương nhỏ hơn bằng các cảnh đen.
Lưu chúng dưới dạng Detect_black.ps1 và Cut_black.ps1. Tải xuống ffmpeg cho Windows và cho kịch bản đường dẫn đến ffmpeg.exe và thư mục video của bạn trong phần tùy chọn.
Cả hai tập lệnh sẽ không chạm vào các tập tin video hiện có, chúng vẫn còn nguyên.
Tuy nhiên, bạn sẽ nhận được một vài tệp mới tại cùng một nơi có video đầu vào của bạn
- Một logfile cho mỗi video với đầu ra giao diện điều khiển cho cả hai lệnh ffmpeg được sử dụng
- Tệp CSV trên mỗi video có tất cả dấu thời gian của cảnh đen để tinh chỉnh thủ công
- Một vài video mới tùy thuộc vào số lượng cảnh đen được phát hiện trước đó
Kịch bản đầu tiên để chạy: 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
}
Làm thế nào nó hoạt động
Tập lệnh đầu tiên lặp qua tất cả các tệp video khớp với phần mở rộng được chỉ định và không khớp với mẫu *_???.*
, vì các chương video mới được đặt tên <filename>_###.<ext>
và chúng tôi muốn loại trừ chúng.
Nó tìm kiếm tất cả các cảnh đen và ghi thời gian bắt đầu và thời lượng cảnh đen vào một tệp CSV mới có tên <video_name>_cutpoints.txt
Nó cũng tính toán các điểm cắt như hình : cutpoint = black_start + black_duration / 2
. Sau đó, video được phân đoạn tại các dấu thời gian này.
Tệp cutpoint.txt cho video mẫu của bạn sẽ hiển thị:
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
Sau khi chạy, bạn có thể thao tác các điểm cắt bằng tay nếu muốn. Nếu bạn chạy lại tập lệnh, tất cả nội dung cũ sẽ bị ghi đè. Hãy cẩn thận khi chỉnh sửa thủ công và lưu công việc của bạn ở nơi khác.
Đối với video mẫu, lệnh ffmpeg để phát hiện cảnh đen là
$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null
Có 3 số quan trọng có thể chỉnh sửa trong phần tùy chọn của tập lệnh
d=4
có nghĩa là chỉ những cảnh đen dài hơn 4 giây được phát hiện
pic_th=0.98
là ngưỡng để xem ảnh là "đen" (tính bằng phần trăm)
pix=0.15
đặt ngưỡng để xem xét pixel là "đen" (độ chói). Vì bạn có video VHS cũ, bạn không có cảnh đen hoàn toàn trong video của mình. Giá trị mặc định 10 sẽ không hoạt động và tôi phải tăng ngưỡng một chút
Nếu có gì sai, hãy kiểm tra logfile tương ứng được gọi <video_name>__ffmpeg.log
. Nếu thiếu các dòng sau, hãy tăng các số được đề cập ở trên cho đến khi bạn phát hiện tất cả các cảnh đen:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Kịch bản thứ hai để chạy: 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
}
Làm thế nào nó hoạt động
Tập lệnh thứ hai lặp lại trên tất cả các tệp video theo cùng một cách tập lệnh đầu tiên đã thực hiện. Nó chỉ đọc các dấu thời gian cắt từ tương ứng cutpoints.txt
của video.
Tiếp theo, nó đặt một tên tệp phù hợp cho các tệp chương và yêu cầu ffmpeg phân đoạn video. Hiện tại các video được cắt mà không cần mã hóa lại (cực nhanh và không mất dữ liệu). Do đó, có thể có 1-2 giây không chính xác với dấu thời gian điểm cắt vì ffmpeg chỉ có thể cắt tại key_frames. Vì chúng tôi chỉ sao chép và không mã hóa lại, chúng tôi không thể tự chèn key_frames.
Lệnh cho video mẫu sẽ là
$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"
Nếu có gì sai, hãy xem ffmpeg.log tương ứng
Người giới thiệu
Làm
Hỏi OP nếu định dạng CSV tốt hơn tệp văn bản dưới dạng tệp điểm cắt, để bạn có thể chỉnh sửa chúng bằng Excel dễ dàng hơn một chút
»Đã triển khai
Thực hiện một cách định dạng dấu thời gian là [hh]: [mm]: [ss], [mili giây] thay vì chỉ vài giây
»Đã triển khai
Thực hiện lệnh ffmpeg để tạo các tệp png mosaik cho mỗi chương
»Đã triển khai
Xây dựng nếu -c copy
đủ cho kịch bản của OP hoặc chúng ta cần mã hóa lại hoàn toàn.
Có vẻ như Ryan đã ở trên đó .