ffmpeg: Removendo partes com silêncio: Remova com eficiência várias partes de um Vídeo

3

Estou tentando remover partes de um vídeo, onde não há (ou pouco) áudio. Para isso eu uso audácia ( Analisar- > Localizador de som ) e exportar a Faixa de etiquetas . Isso resulta em algo parecido com isto:

0.000000    5.170000    1
12.520000   12.630000   2
14.400000   15.660000   3
17.430000   22.150000   4
...

Com esta regex: ([\d]+.[\d]{6})\t([\d]+.[\d]{6})\t([\d]+)\n > ffmpeg -i VL1.mp4 -strict -2 -ss -to buff.mp4\nffmpeg -f concat -i <(echo "file '/home/rene/videotest/output.mp4'\nfile '/home/rene/videotest/buff.mp4'") -c copy output2.mp4\nrm buff.mp4\nmv output2.mp4 output.mp4\n e alguma edição manual eu recebo isto:

#!/bin/bash

ffmpeg -i VL1.mp4 -strict -2 -ss 0.000000 -to 5.170000 output.mp4
ffmpeg -i VL1.mp4 -strict -2 -ss 12.520000 -to 12.630000 buff.mp4
ffmpeg -f concat -i <(echo "file '/home/rene/videotest/output.mp4'
file '/home/rene/videotest/buff.mp4'") -c copy output2.mp4
rm buff.mp4
mv output2.mp4 output.mp4
ffmpeg -i VL1.mp4 -strict -2 -ss 14.400000 -to 15.660000 buff.mp4
ffmpeg -f concat -i <(echo "file '/home/rene/videotest/output.mp4'
file '/home/rene/videotest/buff.mp4'") -c copy output2.mp4
rm buff.mp4
mv output2.mp4 output.mp4
ffmpeg -i VL1.mp4 -strict -2 -ss 17.430000 -to 22.150000 buff.mp4
ffmpeg -f concat -i <(echo "file '/home/rene/videotest/output.mp4'
file '/home/rene/videotest/buff.mp4'") -c copy output2.mp4
rm buff.mp4
mv output2.mp4 output.mp4
...

Isso funciona muito bem e eu recebo um arquivo output.mp4 que contém apenas as partes que eu quero.

Infelizmente isso é incrivelmente lento - e temo que destrua meu HDD (já que para cada parte existe um arquivo buff.mp4 criado, um novo arquivo contendo todas as partes existentes mais este pequeno clipe é gravado no HDD e o arquivo antigo contendo as partes existentes é eliminado). Já que a maioria dos clipes é REALMENTE curta (geralmente menos que alguns segundos) minha idéia era não gravar o arquivo buff.mp4 no HDD mas passar isso para o ffmpeg via < (então mantenha isso na RAM?). A segunda coisa foi anexar a output.mp4 e não reescrever o arquivo a cada vez.

Infelizmente, para ambas as coisas, meu conhecimento de ffmpeg e bash em geral é muito pequeno. Alguém poderia me ajudar?

Eu deveria ser capaz de escrever um bom script sem o material regex manual. E é claro que vou publicar isso depois.

    
por 3244611user 22.10.2015 / 16:58

1 resposta

0

A solução que eu uso agora examina o arquivo de entrada de lista e cria pequenos arquivos com trechos "no-silence" a partir desta informação. Todos os arquivos são gravados no arquivo temp na ordem correta. Quando isso for feito, as partes serão mescladas e os arquivos temporários serão limpos. Isso é não muito rápido. Um total de cerca de 1000 cortes em um clipe de 90 minutos leva cerca de 5 horas em um processador i7, 10 GB de RAM.

Eu acho que uma solução com filtros ffmpeg seria muito mais rápido. Mas foi muito complicado no momento. Outra solução poderia ser este exemplo de código . Ambos provavelmente seriam mais eficientes porque não criam os arquivos tmp (com cabeçalhos, gravação de arquivos, etc.).

De qualquer forma, aqui está o código de trabalho em seu estado atual:

#!/bin/bash
echo "">temp

# File or Directory selection menu with dialog
function fileDialog {
    read -p "$2: " fileselection
    echo "You've selected $fileselection"
}


WORKPATH=$(pwd)

echo "Arbeitsverzeichnis: $WORKPATH"

fileDialog "$WORKPATH" "Select original Video-File"
INFILE=$fileselection
ff=$(ffmpeg -i "$INFILE" 2>&1)
d="${ff#*Duration: }"
LENGTH="${d%%,*}"
echo "Arbeitsverzeichnis: $WORKPATH"
echo "Videodatei: $INFILE"
echo "Gesamtvideolänge $LENGTH"

fileDialog "$WORKPATH" "Select Label-List-File (exported from Audacity)"
LABELFILE=$fileselection
NUMLINES=$(awk 'END { print NR }' "$LABELFILE")
clear
echo "Arbeitsverzeichnis: $WORKPATH"
echo "Videodatei: $INFILE"
echo "Gesamtvideolänge $LENGTH"
echo "Sequence-Label-Datei: $LABELFILE"
echo $NUMLINES lines/sequences found in \'$LABELFILE\'
echo ""
echo "Start processing..."
awk '{d=sprintf("echo Processing Part "NR"/'"$NUMLINES"' named "$3" from "$1"s to "$2"s..."); system(d); s=sprintf("ffmpeg -hide_banner -loglevel panic -accurate_seek -y -i '"$INFILE"' -strict -2 -ss "$1" -to "$2" tmp-"NR".mp4>/dev/null"); system(s); p=sprintf("echo \"$(cat temp)\nfile '"$WORKPATH"'/tmp-"NR".mp4\">temp"); system(p);}' "$LABELFILE"

echo "Merging all "$NUMLINES" parts."
ffmpeg -f concat -i temp -c copy "short-$INFILE.mp4"

echo "Cleaning up..."
rm tmp-*.mp4
rm temp
rm "$INFILE"

Mais duas coisas pequenas que devem ser feitas: atualmente, isso converterá seu vídeo em mp4. Isso não é realmente necessário e, provavelmente, requer apenas muito tempo de CPU.

    
por 23.10.2015 / 14:28