Aqui estão dois scripts do PowerShell para dividir vídeos longos em capítulos menores por cenas em preto.
Salve-os como Detect_black.ps1 e Cut_black.ps1. Faça o download do ffmpeg para Windows e informe ao script o caminho para o seu ffmpeg.exe e sua pasta de vídeo na seção de opções.
Ambos os scripts não tocam nos arquivos de vídeo existentes, permanecem intocados.
No entanto, você receberá alguns novos arquivos no mesmo local em que seus vídeos de entrada estão
- Um arquivo de log por vídeo com a saída do console para os dois comandos ffmpeg usados
- Um arquivo CSV por vídeo com todos os carimbos de data / hora de cenas em preto para ajuste fino manual
- Alguns vídeos novos, dependendo de quantas cenas em preto foram detectadas anteriormente
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 ao padrão *_???.*
, pois os novos capítulos foram nomeados <filename>_###.<ext>
e queremos excluí-los.
Ele pesquisa todas as cenas em preto e grava o carimbo de data e hora de início e a duração da cena em um novo arquivo CSV chamado <video_name>_cutpoints.txt
Ele também calcula pontos de corte, como mostrado: cutpoint = black_start + black_duration / 2
. Posteriormente, o vídeo é segmentado nesses timestamps.
O arquivo cutpoints.txt para o seu exemplo de vídeo mostraria:
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 execução, você pode manipular os pontos de corte manualmente, se desejar. Se você executar o script novamente, todo o conteúdo antigo será substituído. Tenha cuidado ao editar manualmente e salve seu trabalho em outro local.
Para o vídeo de amostra, o comando ffmpeg para detectar cenas em preto é
$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 pretas com mais de 4 segundos são detectadas
pic_th=0.98
é o limite para considerar uma imagem como "preta" (em porcentagem)
pix=0.15
define o limite para considerar um pixel como "preto" (em luminância). Como você possui vídeos VHS antigos, não há cenas completamente negras em seus vídeos. O valor padrão 10 não funcionará e eu tive que aumentar um pouco 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 em preto:
[blackdetect @ 0286ec80]
black_start:236.908 black_end:242.247 black_duration:5.33877
Segundo script a ser executado: 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 repete todos os arquivos de vídeo da mesma maneira que o primeiro script. Ele lê apenas os carimbos de data e hora cortados do correspondente cutpoints.txt
de um vídeo.
Em seguida, reúne um nome de arquivo adequado para os arquivos dos capítulos e informa 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-2s nos registros de data e hora do ponto de corte, porque o ffmpeg só pode cortar em quadros-chave. Como apenas copiamos e não recodificamos, não podemos inserir quadros-chave por conta própria.
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, consulte o arquivo ffmpeg.log correspondente
Referências
Façam
Pergunte à OP se o formato CSV é melhor que um arquivo de texto como 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 data e hora como [hh]: [mm]: [ss], [milissegundos] em vez de apenas segundos
»Implementado
Implemente um comando ffmpeg para criar arquivos png mosaik para cada capítulo
»Implementado
Elabore se -c copy
é suficiente para o cenário do OP ou se é necessário recodificar totalmente.
Parece que Ryan já está nele .