Aqui estão dois scripts do PowerShell para dividir vídeos longos em capítulos menores em cenas pretas.
Salve-os como Detect_black.ps1 e Cut_black.ps1. Faça o download do ffmpeg para Windows e diga ao script o caminho para o ffmpeg.exe e sua pasta de vídeo na seção de opções.
Ambososscriptsnãotocamnosarquivosdevídeoexistentes,elespermaneceminalterados.
Noentanto,vocêreceberáalgunsarquivosnovosnomesmolocalemqueseusvídeosdeentradasão
- Umarquivodelogporvídeocomasaídadoconsoleparaosdoiscomandosffmpegusados
- UmarquivoCSVporvídeocomtodososcarimbosdedataehoradecenasempretoparaajustemanual
- Algunsnovosvídeos,dependendodequantascenasnegrasforamdetectadasanteriormente
Primeiro script a ser executado: 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
}
Como funciona
O primeiro script percorre todos os arquivos de vídeo que correspondem a uma extensão especificada e não corresponde ao padrão *_???.*
, pois os novos capítulos de vídeo foram nomeados <filename>_###.<ext>
e queremos excluí-los.
Ele pesquisa todas as cenas em preto e grava a data e hora de início e a duração da cena em preto em um novo arquivo CSV chamado <video_name>_cutpoints.txt
Ele também calcula os pontos de corte conforme mostrado: cutpoint = black_start + black_duration / 2
. Mais tarde, o vídeo é segmentado nesses timestamps.
O arquivo cutpoints.txt para o seu vídeo de amostra seria exibido:
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
Após uma corrida, você pode manipular manualmente os pontos de corte, se desejar. Se você executar o script novamente, todo o conteúdo antigo será substituído. Tenha cuidado ao editar manualmente e salvar seu trabalho em outro lugar.
Para o vídeo de exemplo, o comando ffmpeg para detectar cenas pretas é
$ffmpeg -i "Tape_10_3b.mp4" -vf blackdetect=d=4:pic_th=0.98:pix_th=0.15 -an -f null
Existem 3 números importantes que são editáveis na seção de opções do script
-
d=4
significa que apenas cenas negras com mais de 4 segundos são detectadas -
pic_th=0.98
é o limite para considerar uma imagem como "preto" (em porcentagem) -
pix=0.15
define o limite para considerar um pixel como "preto" (em luminância). Como você tem vídeos VHS antigos, não há cenas completamente pretas em seus vídeos. O valor padrão 10 não funcionará e eu tive que aumentar ligeiramente o limite
Se algo der errado, verifique o arquivo de log correspondente chamado <video_name>__ffmpeg.log
. Se as seguintes linhas estiverem faltando, aumente os números mencionados acima até detectar todas as cenas pretas:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Segundo script para executar: 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
}
Como funciona
O segundo script interage sobre todos os arquivos de vídeo da mesma maneira que o primeiro script fez. Ele lê somente os timestamps cut do cutpoints.txt
correspondente de um vídeo.
Em seguida, ele reúne um nome de arquivo adequado para arquivos de capítulo e diz ao ffmpeg para segmentar o vídeo. Atualmente, os vídeos são cortados sem recodificação (super rápida e sem perdas). Devido a isso, pode haver uma imprecisão de 1 a 2 segundos com carimbos de data e hora de ponto de corte, pois o ffmpeg só pode cortar em key_frames. Como apenas copiamos e não recodificamos, não podemos inserir key_frames sozinhos.
O comando para o vídeo de amostra seria
$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"
Se algo der errado, dê uma olhada no ffmpeg.log correspondente
Referências
- Download do FFmpeg para Windows
- Documentação do segmento : segment_times e segment_frames são opções
Todo
-
Pergunte ao OP se o formato CSV é melhor que um arquivo de texto como um arquivo de ponto de corte, para que você possa editá-los com o Excel um pouco mais fácil
»Implementado -
Implemente uma maneira de formatar carimbos de hora como [hh]: [mm]: [ss], [milissegundos] em vez de apenas segundos
»Implementado -
Implementar um comando ffmpeg para criar arquivos mosaik png para cada capítulo
»Implementado -
Elabore se-c copy
for suficiente para o cenário do OP ou se precisarmos recodificar totalmente.
Parece que Ryan já está nele .