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 .
Aqui está o bônus: este terceiro script do PowerShell gera uma imagem em miniatura de mosaico
Você receberá uma imagem por vídeo do capítulo, semelhante ao exemplo abaixo.
A idéia principal é obter um fluxo contínuo de imagens em todo o vídeo. Fazemos isso com a opção de seleção do ffmpeg .
Primeiro, recuperamos a contagem total de quadros com um método engenhoso (por exemplo, 2000) e dividimos por nossa contagem de miniaturas padrão (por exemplo, 5 x 4 = 20). Então, queremos gerar uma imagem a cada 100 quadros desde
2000 / 20 = 100
O comando ffmpeg resultante para gerar a miniatura pode parecer
No código acima, você vê 9
-vf
combinações diferentes que consistem emselect=not(mod(n\,XXX))
onde XXX é uma taxa de quadros computadathumbnail
que seleciona os quadros mais representativos automaticamenteselect='gt(scene\,XXX)
+-vsync vfr
onde XXX é um limite com o qual você precisa brincarmpdecimate
- Remova os quadros quase duplicados. Bom contra cenas negrasyadif
- Desentrelaçar a imagem de entrada. Não sei por que, mas funcionaVersão 3 é a melhor escolha na minha opinião. Todos os outros são comentados, mas você ainda pode experimentá-los. Consegui remover a maioria das miniaturas embaçadas usando
mpdecimate
,yadif
eselect=not(mod(n\,XXX))
. sim!Para o seu exemplo de vídeo , recebo essas visualizações
Clique para ampliar
Clique para ampliar
Carreguei todas as miniaturas criadas por essas versões. Dê uma olhada neles para uma comparação completa.
fonte
select='gt(scene\,0.4)'
ao trabalho. E também não conseguifps="fps=1/600"
trabalhar. A propósito, você tem alguma idéia sobre superuser.com/questions/725734 ? Muito obrigado por toda a sua ajuda. Estou super empolgado em ajudar minha família a descobrir toneladas de memórias antigas.Aprecie os dois scripts, ótima maneira de dividir vídeos.
Ainda assim, tive alguns problemas com os vídeos que não mostravam a hora correta posteriormente e não pude ir para uma hora específica. Uma solução foi desmontar e, em seguida, compactar os fluxos usando o Mp4Box.
Outra maneira mais fácil para mim era usar o mkvmerge para dividir. Portanto, os dois scripts tiveram que ser alterados. Para detect_black.ps1, apenas o "* .mkv" tinha que ser adicionado à opção de filtro, mas isso não é necessariamente se você iniciar apenas com arquivos mp4.
A função é a mesma, mas sem problemas com os tempos de vídeo até agora. Obrigado pela inspiração.
fonte
Espero estar errado, mas não acho que seja possível sua pergunta. Pode ser possível ao recodificar o vídeo, mas como uma "fatia simples e sem perdas" eu não conheço nenhuma maneira.
Muitos programas de edição de vídeo terão um recurso de análise automática ou algo equivalente que poderá dividir seus vídeos nos quadros em preto, mas isso exigirá a recodificação do vídeo.
Boa sorte!
fonte