Dapatkan total durasi file video dalam direktori

30

Saya punya daftar .tsfile:

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

Bagaimana saya bisa mendapatkan total durasi (waktu berjalan) dari semua file ini?

k961
sumber
Bagaimana Anda mendapatkan durasi satu file?
Hauke ​​Laging
saya juga tidak tahu
k961
@ Hauke ​​Laging, saya menemukan program ini "mediainfo"
k961
Ini adalah file media, kemungkinan video.
slm
1
File media apa pun (mis: MP4, ASF & .264 ...) akan memiliki informasi header standar yang telah ditentukan, kami dapat memperoleh informasi dari file itu seperti resolusi, kecepatan bingkai, jumlah bingkai (GOP) & panjang file & durasi file media ...
Kantam Nagesh

Jawaban:

55

Saya tidak punya di .tssini tetapi ini berfungsi untuk .mp4. Gunakan ffprobe(bagian dari ffmpeg) untuk mendapatkan waktu dalam detik, misalnya:

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

jadi untuk semua .mp4file dalam direktori saat ini:

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

lalu gunakan pasteuntuk meneruskan output ke bcdan mendapatkan total waktu dalam detik:

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

Jadi, untuk .tsfile Anda dapat mencoba:

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

Alat lain yang berfungsi untuk file video yang saya miliki di sini adalah exiftool, misalnya:

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

Total panjang untuk semua .mp4file di direktori saat ini:

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

Anda juga dapat menyalurkan output ke perintah lain untuk mengonversi total menjadi DD:HH:MM:SS, lihat jawaban di sini .

Atau gunakan exiftoolinternal ConvertDurationuntuk itu (Anda memerlukan versi yang relatif baru):

exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
                    }' ./*.mp4| tail -n1
0:09:15
don_crissti
sumber
Bagus sekali, belum pernah melihat trik itu ffprobesebelumnya.
slm
1
Trik yang bagus dengan pastedan bc! jauh lebih bersih daripada dengan awkkatakanlah.
fduff
@fuff. Walaupun bcakan melakukan presisi yang sewenang-wenang, satu kelemahannya adalah apakah ...| paste -sd+ - | bcakan mencapai batas ukuran garis di beberapa bcimplementasi (misalnya seq 429 | paste -sd+ - | bcgagal dengan OpenSolaris bc) atau memiliki potensi untuk menggunakan semua memori pada yang lain.
Stéphane Chazelas
Bisakah Anda melakukan ini (metode ffprobe) dengan sesuatu seperti avconv? Saya tidak dapat menemukan ffmpeg di repos saya untuk Kubuntu 14.04 - jadi saya juga tidak memiliki ffprobe? Saya memang punya avprobe, tapi tidak suka argumen itu.
Joe
@ Jo - Tidak avprobedi Arch repo (prolly karena bertentangan dengan ffmpeg) jadi tidak bisa mencobanya ATM tetapi apakah itu memberi Anda durasi file jika Anda menjalankannya seperti ini: avprobe -show_format_entry duration myfile.mp4atau avprobe -loglevel quiet -show_format_entry duration myfile.mp4? Saya pikir salah satu dari perintah ini harus memberi Anda satu baris output dengan durasi file. Namun tidak yakin.
don_crissti
6

Ini menggunakan ffmpegdan mencetak waktu habis dalam total detik:

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

Penjelasan:

for f in *.ts; do iterates setiap file yang berakhiran ".ts"

ffmpeg -i "$f" 2>&1 pengalihan output ke stderr

grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' mengisolasi waktu

awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }' Mengubah waktu menjadi detik

times+=("$_t") menambahkan detik ke array

echo "${times[@]}" | sed 's/ /+/g' | bcmemperluas masing-masing argumen dan mengganti spasi dan menyalurkannya ke bckalkulator linux yang umum

Jonunsch
sumber
1
Bagus! Lihat juga versi saya yang sangat didasarkan pada ide-ide Anda.
MvG
Solusi singkat dan elegan
Neo
4

Merampingkan jawaban @ jmunsch , dan menggunakan pasteSaya baru belajar dari jawaban @ slm , Anda bisa berakhir dengan sesuatu seperti 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

Seperti yang dilakukan jmunsch, saya menggunakan ffmpeguntuk mencetak durasinya, mengabaikan kesalahan tentang file output yang hilang dan mencari output error untuk garis durasi. Saya memohon ffmpegdengan semua aspek lokal yang dipaksa ke lokal C standar, sehingga saya tidak perlu khawatir tentang pesan output lokal.

Selanjutnya saya menggunakan satu awkbukan miliknya grep | grep | head | tr | awk. Itu awkdoa mencari garis (mudah-mudahan unik) mengandung Duration:. Menggunakan titik dua sebagai pemisah, label itu adalah bidang 1, jamnya adalah bidang 2, menit yang diajukan 3 dan bidang detik 4. Tanda koma setelah detik tampaknya tidak mengganggu saya awk, tetapi jika seseorang memiliki masalah di sana, ia dapat termasuk tr -d ,dalam jalur pipa antara ffmpegdan awk.

Sekarang bagian dari slm: Saya menggunakan pasteuntuk mengganti baris baru dengan tanda tambah, tetapi tanpa mempengaruhi baris baru (bertentangan dengan yang tr \\n +saya miliki di versi sebelumnya dari jawaban ini). Itu memberikan ekspresi jumlah yang dapat diumpankan bc.

Terinspirasi oleh ide slm tentang penggunaan dateuntuk menangani format seperti waktu, berikut adalah versi yang menggunakannya untuk memformat detik yang dihasilkan sebagai hari, jam, menit, dan detik dengan bagian pecahan:

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

Bagian dalam $(…)persis seperti sebelumnya. Menggunakan @karakter sebagai indikasi, kami menggunakan ini sebagai jumlah detik sejak 1 Januari 1970. "Tanggal" yang dihasilkan akan diformat sebagai hari dalam setahun, waktu dan nanodetik. Sejak hari itu tahun kita mengurangi satu, karena input nol detik sudah mengarah ke hari 1 tahun itu tahun 1970. Saya tidak berpikir ada cara untuk mendapatkan hari dalam hitungan tahun mulai dari nol.

Final sedmenyingkirkan nol tambahan trailing. The TZPengaturan mudah-mudahan harus memaksa penggunaan UTC, sehingga daylight saving time tidak akan mengganggu benar-benar koleksi video besar. Jika Anda memiliki video lebih dari satu tahun, pendekatan ini tetap tidak akan berhasil.

MvG
sumber
3

Saya tidak terbiasa dengan .tsekstensi, tetapi dengan asumsi mereka adalah beberapa jenis file video yang dapat Anda gunakan ffmpeguntuk mengidentifikasi durasi file seperti:

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

Kami kemudian dapat membagi output ini ke atas, memilih hanya durasi waktu.

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

Jadi sekarang kita hanya perlu cara untuk mengulangi file-file kita dan mengumpulkan nilai durasi ini.

$ 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

CATATAN: Di sini untuk contoh saya hanya menyalin file sampel saya some.mp4dan menamakannya 1.mp4, 2.mp4, dan 3.mp4.

Mengkonversi waktu menjadi detik

Cuplikan berikut akan mengambil durasi dari atas dan mengubahnya menjadi detik.

$ 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

Ini mengambil durasi kami dan menempatkannya dalam variabel $dur,, saat kami menelusuri file. The dateperintah kemudian digunakan untuk menghitung jumlah detik sinus zaman Unix (1970/01/01). Inilah dateperintah di atas yang pecah sehingga lebih mudah dilihat:

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

CATATAN: Menggunakan datecara ini hanya akan berfungsi jika semua file Anda memiliki durasi yang <24 jam (yaitu 86400 detik). Jika Anda membutuhkan sesuatu yang dapat menangani durasi yang lebih besar, Anda dapat menggunakan ini sebagai alternatif:

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

Menaikkan waktu

Kita kemudian dapat mengambil output dari forloop kita dan menjalankannya menjadi pasteperintah yang akan menggabungkan +tanda - tanda di antara setiap angka, seperti:

$ 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

Akhirnya kami menjalankan ini ke dalam kalkulator baris perintah, bcuntuk menjumlahkannya:

$ 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

Menghasilkan total durasi semua file, dalam detik. Ini tentu saja dapat dikonversi ke beberapa format lain jika diperlukan.

slm
sumber
@DamenSalvatore - tidak masalah, semoga ini menunjukkan kepada Anda bagaimana Anda dapat membagi tugas menjadi berbagai langkah, sehingga Anda dapat menyesuaikannya sesuai kebutuhan.
slm
@slm - Saya akan menggunakan cara lain untuk mengonversi durasi video menjadi detik seperti datetercekik jika ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"mengembalikan sesuatu seperti 26:33:21.68(yaitu, durasi ≥ 24 jam / 86400 detik)
don_crissti
@don_crissti - terima kasih, saya belum mencobanya lebih dari 20 jam saat mengujinya. Saya akan menambahkan catatan yang menunjukkan metode alternatif.
slm
Terima kasih atas jawaban anda! Tidak hanya itu menginspirasi saya , tetapi juga pastemenarik perhatian saya. Saya kira java -classpath $(find -name \*.jar | paste -sd:)akan sangat berguna bagi saya, mengingat peretasan yang saya gunakan untuk ini di masa lalu.
MvG
@MvG - pasteadalah perintah favorit saya 8-)
slm
1

Keluar dari jawaban yang diterima dan menggunakan alat reverse-polish UNIX klasik:

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

783.493000

Yaitu: Menambah +dan pkemudian memasukkannya ke dalam dcdan Anda akan mendapatkan jumlah Anda.

DI
sumber
2
bcmendapat terlalu banyak cinta. Anda semua meletakkan +tanda di antara setiap baris (bergabung di +), sedangkan dengan reverse-polish Anda bisa membuangnya +di ujung dan pmembuangnya;)
PADA
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'

Pastikan Anda telah menginstal MPlayer .

ryanmjacobs
sumber
itu tidak memberi saya output apa pun
k961
apakah Anda memiliki mplayer dan perl yang diinstal?
ryanmjacobs
ya saya menginstal mplayer dan perl sudah diinstal
k961
1
Maaf, saya tidak tahu mengapa itu tidak berhasil; tetapi, Anda sudah memiliki cukup jawaban yang layak. :)
ryanmjacobs
0

Sebagai libav ubuntu, bukan ffmpeg:

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

Sangat didasarkan pada ide-ide MvG

Ahed Idul Fitri
sumber
0

Nah, semua solusi ini perlu sedikit usaha, apa yang saya lakukan sangat sederhana, 1)

  1. pergi ke folder yang diinginkan dan klik kanan -> buka dengan aplikasi lain

  2. Kemudian pilih VLC media player,

  3. ini akan mulai memutar salah satu video, tetapi kemudian
  4. tekan ctrl + L , dan Anda akan melihat daftar putar video dan di suatu tempat di sudut kiri atas Anda akan melihat durasi total

di sini adalah contoh

1. Daftar barang

2.masukkan deskripsi gambar di sini

3.masukkan deskripsi gambar di sini

Anda dapat melihat tepat di bawah bilah alat, ada Playlist [10:35:51] tertulis, sehingga folder berisi 10 jam 35 menit dan durasi total video 51 detik

Patel Ujjval Rajeshbhai
sumber
0

Saya memiliki sub-direktori pada folder saat ini sehingga saya harus menghitung durasi secara rekursif:

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

iMitwe
sumber