Bir dizindeki toplam video dosyalarının süresini alma


30

Bir .tsdosya listem var :

out1.ts ... out749.ts   out8159.ts  out8818.ts

Tüm bu dosyaların toplam süresini (çalışma süresini) nasıl alabilirim?


Tek bir dosyanın süresini nasıl elde edersiniz?
Hauke

Ben de bilmiyorum
k961

@Hauke ​​Laging, bu programı "mediainfo" yu buldum
k961

Bunlar medya dosyaları, muhtemelen video.
slm

1
Herhangi bir medya dosyası (örneğin: MP4, ASF & .264 ...) önceden tanımlanmış standart başlık bilgisine sahip olacaktır, bu dosyadan çözünürlük, kare hızı, kare sayısı (GOP) ve dosya uzunluğu ve süresi gibi bilgileri alabiliriz. medya ...
Kantam Nagesh

Yanıtlar:


55

Hiç var .tsburada ama bunun için çalışır .mp4. Kullanım ffprobe(parçası ffmpeg) saniye, örneğin zaman almak için:

ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4 
275.690000

.mp4geçerli dizindeki tüm dosyalar için :

find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000

Daha sonra kullanmak pasteüzere çıktıyı geçmesi için bcve saniye cinsinden toplam zaman olsun:

find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000

Yani, .tsdeneyebileceğiniz dosyalar için :

find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc

Burada sahip olduğum video dosyaları için çalışan başka bir araç exiftool, örneğin:

exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69

.mp4Geçerli dizindeki tüm dosyaların toplam uzunluğu :

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

Ayrıca başka bir komuta çıkış için toplam dönüştürmek olabilir DD:HH:MM:SS, cevapları görmek burada .

Ya kullanımı exiftool'iç s ConvertDuration(gerçi nispeten yeni bir sürümü gerekir) bunun için:

exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
                    }' ./*.mp4| tail -n1
0:09:15

Çok hoş, daha önce bu numarayı görmemiştim ffprobe.
slm

1
Güzel numara ile pasteve bc! awkDiyelim ki çok daha temiz .
fduff

@fduff. bcİsteğe bağlı bir kesinliği olsa da, bazı dezavantajlar ...| paste -sd+ - | bcbazı bcuygulamalarda (örneğin seq 429 | paste -sd+ - | bcOpenSolaris ile başarısız bc) satır boyut sınırına ulaşması veya diğerlerinde tüm belleği kullanma potansiyeline sahip olmasıdır.
Stéphane Chazelas

Bunu (ffprobe yöntemi) avconv gibi bir şeyle yapabilir misiniz? Kubuntu 14.04 için depolarımda ffmpeg bulamıyorum - bu yüzden ffprobe da yok mu? Avprobe'um var ama bu iddiaları beğenmiyor.
Joe,

@Joe - Hayır avprobe, Arch depolarında (bununla çakıştığı için ffmpeg) çünkü ATM'yi deneyemezsiniz, ancak eğer böyle çalıştırırsanız dosyanın süresini veriyor mu : avprobe -show_format_entry duration myfile.mp4veya avprobe -loglevel quiet -show_format_entry duration myfile.mp4? Bence bu komutlardan biri size dosyanın süresi boyunca tek bir çıktı satırı vermeli. Emin değilim.
don_crissti

6

Bu ffmpeg, zaman aşımını toplam saniye olarak kullanır ve yazdırır:

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

Açıklama:

for f in *.ts; do ".ts" ile biten her bir dosyayı yineler

ffmpeg -i "$f" 2>&1 çıktıyı stderr'ye yönlendirir

grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' zamanı izole eder

awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }' Zamanı saniye'ye çevirir

times+=("$_t") bir diziye saniye ekler

echo "${times[@]}" | sed 's/ /+/g' | bcArgümanların her birini genişletir ve boşlukları değiştirir ve onu bcortak bir linux hesaplayıcısına aktarır


1
Güzel! Ayrıca ağırlıklı olarak fikirlerinizi temel alan versiyonuma bakın .
MvG

Kısa ve zarif çözüm
Neo

4

Düzene jmunsch cevabı @ ve kullanma pastesadece öğrenilen I @ slm cevabı , böyle bir şey ile bitebileceğini:

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

Tıpkı jmunsch gibi, ffmpegsüreyi yazdırmak için kullanıyorum , eksik bir çıktı dosyası ile ilgili hatayı görmezden geliyorum ve bunun yerine süre satırı için hata çıktısını araştırıyorum. Ben çağırmak ffmpegben lokalize çıkış mesajları hakkında endişe zorunda kalmazsınız böylece, Standart C yerelinde zorla yerel ayar tüm yönleri ile.

Sonra awkonun yerine bir tane kullanıyorum grep | grep | head | tr | awk. Bu awkçağrı içeren (umarım benzersiz) bir çizgi arar Duration:. Ayırıcı olarak iki nokta üst üste kullanarak, bu etiket alanı 1, saatleri alanı 2, dakika Sondaki virgül gözlerimi rahatsız görünmüyor saniye sonra 3 ve saniye alanını 4. dosyalanmış olan awk, ancak birileri sorunları varsa, o ve tr -d ,arasındaki boru hattına bir içerebilir .ffmpegawk

Şimdi slm'den gelen bölüm geliyor: pasteyeni satırları artı işaretleriyle değiştirmek için kullanıyorum , ancak sondaki yeni satırı etkilemeden kullanıyorum (aksine bu cevabın önceki sürümündetr \\n + bulundum ). Bu, beslenebilecek toplam ifadesini verir .bc

Slm'in datezamana benzer formatları kullanmak için kullanma fikrinden esinlenerek , burada elde edilen saniyeleri kesirli kısımlarla gün, saat, dakika ve saniye olarak formatlamak için kullanan bir versiyon:

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]*$//'

İçindeki kısım $(…)tam olarak eskisi gibi. @Karakteri bir gösterge olarak kullanarak , bunu 1 Ocak 1970'ten bu yana geçen saniye sayısı olarak kullanırız. Sonuçta ortaya çıkan “tarih”, yılın günü, saati ve nanosaniye olarak biçimlendirilir. Yılın o gününden bir tanesini çıkardık, çünkü sıfır saniyelik bir girdi zaten o yılın 1970'in 1. gününe yol açtı. Sıfırdan başlayarak yılın gününü almanın bir yolu olduğunu sanmıyorum.

Final sed, sondaki sıfırlardan kurtulur. Bu TZayar UTC kullanımını zorlamalıdır, böylece gün ışığından yararlanma saati gerçekten büyük video koleksiyonlarına engel olmaz . Bir yıldan fazla video değeriniz varsa, bu yaklaşım yine de işe yaramaz.


3

Uzantıya aşina değilim .ts, ancak ffmpegböyle bir dosyanın süresini belirlemek için kullanabileceğiniz bir tür video dosyası olduğunu varsayalım:

$ ffmpeg -i some.mp4 2>&1 | grep Dura
  Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s

Daha sonra sadece süreyi seçerek bu çıktıyı bölebiliriz.

$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01

Şimdi sadece dosyalarımızı gözden geçirmek ve bu süre değerlerini toplamak için bir yola ihtiyacımız var.

$ 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

NOT: İşte benim mesela ben sadece benim örnek dosyayı kopyalanmış some.mp4ve onu adlandırılmış 1.mp4, 2.mp4ve 3.mp4.

Süreleri saniyeye dönüştürme

Aşağıdaki kod parçası süreleri yukarıdan alacak ve saniyelere çevirecektir.

$ 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

Bu bizim sürelerimizi alır $durve dosyaları değiştirirken bunları değişkene koyar . dateKomut daha sonra UNIX dönemine (1970/01/01) sinüs saniye sayısını hesaplamak için kullanılır. İşte yukarıdaki datekomut dağıldı, bu yüzden görülmesi daha kolay:

$ date -ud "1970/01/01 00:23:17.01" +%s
1397

NOT:date Bu şekilde kullanmak , tüm dosyalarınızın <24 saat (yani 86400 saniye) süresine sahip olması durumunda işe yarar. Daha büyük sürelerle başa çıkabilecek bir şeye ihtiyacınız olursa, bunu alternatif olarak kullanabilirsiniz:

sed 's/^/((/; s/:/)*60+/g' | bc
Örnek
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01

Kez toplanıyor

Daha sonra fordöngümüzün çıktısını alabilir ve her sayı arasında işaretleri pasteiçeren bir komuta girebiliriz +, şöyle:

$ 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

Sonunda, bcbunları özetlemek için komut satırı hesap makinesine koyarız :

$ 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

Tüm dosyaların toplam süresi içinde saniye cinsinden sonuç. Elbette gerekirse bu başka bir formata dönüştürülebilir.


@DamenSalvatore - sorun değil, umarım görevi çeşitli adımlara nasıl ayıracağınızı gösterir, böylece gerektiği gibi özelleştirebilirsiniz.
slm

@slm - Video süresini saniyeye dönüştürmek için başka bir yol kullanırım ( örneğin , datemight 24 saat / 86400 saniyedir)ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"26:33:21.68
don_crissti

@ don_crissti - teşekkürler, test ederken 20 saatten fazla denememiştim. Alternatif bir yöntem gösteren bir not ekleyeceğim.
slm

Cevabınız için teşekkürler! Sadece benim için ilham vermekle kalmadı , aynı zamanda pastedikkatimi çekti. Sanırım geçmişte bunun için kullandığım korsanları göz önünde bulundurarak benim java -classpath $(find -name \*.jar | paste -sd:)için çok faydalı olacak .
MvG

@MvG - pastebenim en sevdiğim komut 8-)
slm

1

Kabul edilen cevabı iptal etmek ve klasik UNIX ters parlatma aracını kullanmak:

{ find . -maxdepth 2 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 \
         -show_entries format=duration {} \; ; printf '+\n60\n*\np'; } | dc

783.493000

Yani: Eklemek +ve psonra onu boruya sokmak dc, toplamı elde etmek.


2
bcçok fazla aşk alır. Hepiniz +her bir çizginin arasına işaretler koyuyorsunuz (katılıyorsunuz +), oysa ters cila ile sadece bir +ucunu tutabilir ve pdizebilirsiniz;)
AT

0
$ 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'

MPlayer'ın kurulu olduğundan emin olun .


bana herhangi bir çıktı vermez
k961

yüklü mplayer ve perl var mı?
ryanmjacobs

evet,
mplayer'ı

1
Üzgünüm, neden işe yaramadığını bilmiyorum; ama zaten zaten yeterince iyi cevapların var. :)
ryanmjacobs

0

Ubuntu olarak ffmpeg yerine libav gemisi:

#!/bin/sh
for f in *.mp4; do
    avprobe -v quiet -show_format_entry duration "$f"
done | paste -sd+ | bc

Ağır MvG fikirlerine dayalı


0

Eh, tüm bu çözümler biraz işe ihtiyaç duyuyor, yaptığım şey çok basitti, 1)

  1. İstediğiniz klasöre gidip sağ tıklayın -> diğer uygulamalarla açın

  2. Ardından VLC media player'ı seçin.

  3. bu, videolardan birini oynatmaya başlayacaktır, ancak sonra
  4. ctrl + L tuşlarına basın , videoların oynatma listesini göreceksiniz ve sol üst köşede bir yerde toplam süreyi göreceksiniz.

işte örnek

1. Liste öğesi

2.görüntü tanımını buraya girin

3.görüntü tanımını buraya girin

Araç çubuğunun hemen altında görebilirsiniz, Oynatma Listesi [10:35:51] yazılı, bu nedenle klasörde 10 saat 35 dakika ve 51 saniye toplam video süresi var


0

Geçerli klasörde alt dizinler vardı, bu yüzden tekrarlı bir şekilde süreyi hesaplamak zorunda kaldım:

find . -iname '*.mp4' -print0 | xargs --null exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)}' | tail -n1

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.