Eu tenho uma lista de .tsarquivos:
out1.ts ... out749.ts out8159.ts out8818.ts
Como posso obter a duração total (tempo de execução) de todos esses arquivos?
Eu tenho uma lista de .tsarquivos:
out1.ts ... out749.ts out8159.ts out8818.ts
Como posso obter a duração total (tempo de execução) de todos esses arquivos?
Respostas:
Eu não tenho .tsaqui, mas isso funciona para .mp4. Use ffprobe(parte de ffmpeg) para obter o tempo em segundos, por exemplo:
ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4
275.690000
assim, para todos os .mp4arquivos no diretório atual:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000
em seguida, usar pastepara passar a saída para bce obter o tempo total em segundos:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000
Portanto, para .tsarquivos, você pode tentar:
find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
Outra ferramenta que funciona para os arquivos de vídeo que tenho aqui é exiftool, por exemplo:
exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69
Comprimento total para todos os .mp4arquivos no diretório atual:
exiftool -S -n ./*.mp4 | awk '/^Duration/ {print $2}' | paste -sd+ -| bc
555.070000000000
exiftool -q -p '$Duration#' ./*.mp4 | awk '{sum += $0}; END{print sum}'
555.070000000000
Você também pode canalizar a saída para outro comando para o qual converter o total DD:HH:MM:SS, veja as respostas aqui .
Ou use exiftoolinterno ConvertDurationpara isso (você precisa de uma versão relativamente recente):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobeantes.
pastee bc! muito mais limpo do que com awk, digamos.
bcfaça precisão arbitrária, uma desvantagem é que ...| paste -sd+ - | bcatingirá o limite de tamanho da linha em algumas bcimplementações (por exemplo, seq 429 | paste -sd+ - | bcfalha no OpenSolaris bc) ou terá o potencial de usar toda a memória em outras.
avprobeno repositório do Arch (prolly porque entra em conflito com ffmpeg), portanto, não é possível experimentá-lo em caixas eletrônicos, mas fornece a duração do arquivo se você o executar dessa maneira: avprobe -show_format_entry duration myfile.mp4ou avprobe -loglevel quiet -show_format_entry duration myfile.mp4? Eu acho que um desses comandos deve fornecer uma única linha de saída com a duração do arquivo. Não tenho certeza.
Isso usa ffmpege imprime o tempo limite em segundos totais:
times=()
for f in *.ts; do
_t=$(ffmpeg -i "$f" 2>&1 | grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
times+=("$_t")
done
echo "${times[@]}" | sed 's/ /+/g' | bc
Explicação:
for f in *.ts; do itera cada um dos arquivos que termina em ".ts"
ffmpeg -i "$f" 2>&1 redireciona a saída para o stderr
grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' isola o tempo
awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }' Converte o tempo em segundos
times+=("$_t") adiciona os segundos a uma matriz
echo "${times[@]}" | sed 's/ /+/g' | bcexpande cada um dos argumentos e substitui os espaços e os canaliza para bcuma calculadora linux comum
Simplificando a resposta de @ jmunsch e usando o pasteque acabei de aprender com a resposta de @ slm , você pode terminar com algo assim:
for i in *.ts; do LC_ALL=C ffmpeg -i "$i" 2>&1 | \
awk -F: '/Duration:/{print $2*3600+$3*60+$4}'; done | paste -sd+ | bc
Assim como jmunsch, estou usando ffmpegpara imprimir a duração, ignorando o erro sobre um arquivo de saída ausente e procurando a linha de duração na saída de erro. Chamo ffmpegcom todos os aspectos do código do idioma forçados para o código C padrão, para que não precise me preocupar com mensagens de saída localizadas.
Em seguida, estou usando um único em awkvez do dele grep | grep | head | tr | awk. Essa awkinvocação procura a linha (espero que única) que contém Duration:. Usando dois pontos como separador, esse rótulo é o campo 1, as horas são o campo 2, os minutos são arquivados 3 e o campo de segundos 4. A vírgula final após os segundos não parece incomodar o meu awk, mas se alguém tiver problemas, ele pode incluir um tr -d ,no pipeline entre ffmpege awk.
Agora vem a parte do slm: estou usando pastepara substituir novas linhas por sinais de mais, mas sem afetar a nova linha à direita (ao contrário do que tr \\n +eu tinha na versão anterior desta resposta). Isso fornece a expressão sum que pode ser fornecida bc.
Inspirada na idéia do slm de usar datepara manipular formatos semelhantes ao tempo, aqui está uma versão que o usa para formatar os segundos resultantes como dias, horas, minutos e segundos com parte fracionária:
TZ=UTC+0 date +'%j %T.%N' --date=@$(for i in *.ts; do LC_ALL=C \
ffmpeg -i "$i" 2>&1 | awk -F: '/Duration:/{print $2*3600+$3*60+$4}'; done \
| paste -sd+ | bc) | awk '{print $1-1 "d",$2}' | sed 's/[.0]*$//'
A parte interna $(…)é exatamente como antes. Utilizando o @caractere como indicação, usamos esse número como o número de segundos desde 1º de janeiro de 1970. A "data" resultante é formatada como dia do ano, hora e nanossegundos. A partir desse dia do ano, subtraímos um, uma vez que uma entrada de zero segundos já leva ao dia 1 daquele ano de 1970. Não acho que haja uma maneira de obter as contagens do dia do ano começando em zero.
A final sedse livra de zeros à direita extras. A TZdefinição deve esperamos forçar o uso de UTC, de modo que o horário de verão não vai interferir com realmente coleções de vídeo grandes. Se você tiver mais de um ano de vídeo, essa abordagem ainda não funcionará.
Não estou familiarizado com a .tsextensão, mas supondo que eles sejam algum tipo de arquivo de vídeo que você possa usar ffmpegpara identificar a duração de um arquivo da seguinte forma:
$ ffmpeg -i some.mp4 2>&1 | grep Dura
Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s
Podemos então dividir essa saída, selecionando apenas o tempo de duração.
$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01
Portanto, agora precisamos apenas de uma maneira de percorrer nossos arquivos e coletar esses valores de duração.
$ for i in *.mp4; do
ffmpeg -i "$i" 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"; done
00:23:17.01
00:23:17.01
00:23:17.01
NOTA: Aqui para o meu exemplo, eu simplesmente copiou o meu arquivo de amostra some.mp4e nomeou-o 1.mp4, 2.mp4e 3.mp4.
O seguinte snippet pega as durações de cima e as converte em segundos.
$ for i in *.mp4; do
dur=$(ffmpeg -i "$i" 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)");
date -ud "1970/01/01 $dur" +%s; done
1397
1397
1397
Isso leva nossas durações e as coloca em uma variável $dur, conforme percorremos os arquivos. O datecomando é então usado para calcular o número de segundos sine a época do Unix (01/01/1970). Aqui está o datecomando acima dividido, para que seja mais fácil ver:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
NOTA: O uso datedessa maneira funcionará apenas se todos os seus arquivos tiverem uma duração inferior a 24 horas (ou seja, 86400 segundos). Se você precisar de algo que possa lidar com durações maiores, use-o como uma alternativa:
sed 's/^/((/; s/:/)*60+/g' | bc
Exemplo
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01
Podemos então pegar a saída do nosso forloop e executá-lo em um pastecomando que incorporará +sinais entre cada número, da seguinte forma:
$ for i in *.mp4; do
dur=$(ffmpeg -i "$i" 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)");
date -ud "1970/01/01 $dur" +%s; done | paste -s -d+
1397+1397+1397
Finalmente, executamos isso na calculadora da linha de comando, bcpara resumir:
$ for i in *.mp4; do
dur=$(ffmpeg -i "$i" 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)");
date -ud "1970/01/01 $dur" +%s; done | paste -s -d+ | bc
4191
Resultando na duração total de todos os arquivos, em segundos. Obviamente, isso pode ser convertido para outro formato, se necessário.
datechoke poder se ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"retorna algo como 26:33:21.68(isto é, duração ≥ 24 horas / 86400 segundos)
pasteis my favorite command 8-)
Saindo da resposta aceita e usando a ferramenta clássica de polimento reverso UNIX:
{ find . -maxdepth 2 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 \
-show_entries format=duration {} \; ; printf '+\n60\n*\np'; } | dc
783.493000
Ou seja: Appening +e, em pseguida, canalizando isso dce você receberá sua soma.
$ find -iname '*.ts' -print0 |\
xargs -0 mplayer -vo dummy -ao dummy -identify 2>/dev/null |\
perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t += $1) && printf "%02d:%02d:%02d:%02d\n",$t/86400,$t/3600%24,$t/60%60,$t%60'
Certifique-se de ter o MPlayer instalado.
Bem, todas essas soluções precisam de um pouco de trabalho, o que eu fiz foi muito simples, 1)
foi para a pasta desejada e clique com o botão direito do mouse -> abrir com outro aplicativo
Em seguida, selecione VLC media player,
aqui está um exemplo
Você pode ver logo abaixo da barra de ferramentas, a lista de reprodução [10:35:51] gravada, para que a pasta contenha 10 horas e 35 minutos e 51 segundos de duração do total de vídeos