ディレクトリ内のビデオファイルの合計時間を取得する


30

.tsファイルのリストがあります:

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

これらすべてのファイルの合計期間(実行時間)を取得するにはどうすればよいですか?


単一のファイルの期間を取得するにはどうすればよいですか?
ホークレイジング14

私もそれを知らない
k961

@Hauke Lagingは、私はこのプログラムを見つけ、「MediaInfoを」
k961

これらはメディアファイル、おそらくビデオです。
slm

1
すべてのメディアファイル(例:MP4、ASF&.264 ...)には事前定義された標準ヘッダー情報があります。解像度、フレームレート、フレーム数(GOP)、ファイルの長さ、時間などの情報をそのファイルから取得できます。メディア...
Kantam Nagesh 14

回答:


55

.tsここにはありませんが、これはうまくいきます.mp4ffprobe(の一部ffmpeg)を使用して、秒単位の時間を取得します。例:

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

したがって.mp4、現在のディレクトリ内のすべてのファイルに対して:

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

その後、使用pasteする出力を渡すにはbc、秒の総時間を取得:

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

そのため、.tsファイルについては次のことを試すことができます。

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

私がここに持っているビデオファイルのために働く別のツールはexiftool、例えばです:

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

.mp4現在のディレクトリ内のすべてのファイルの合計長:

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

出力を別のコマンドにパイプして合計をに変換することもできDD:HH:MM:SSます。回答はこちら。。

または、そのためにexiftoolの内部ConvertDurationを使用します(ただし、比較的最近のバージョンが必要です)。

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

とても素敵で、ffprobe以前にそのトリックを見たことがありませんでした。
slm

1
ニーストリックpastebcawkと言うよりもずっときれいです。
fduff

@fduff。しながら、bc任意の精度を行います、一つの欠点は、それが...| paste -sd+ - | bcいずれかのいくつかの行のサイズ制限に到達するbc(インスタンスの実装seq 429 | paste -sd+ - | bcのOpenSolarisで失敗bc)、または他のすべてのメモリを使用する可能性を有します。
ステファンシャゼル14

あなたはavconvのようなものでこれを行うことができますか(ffprobeメソッド)?Kubuntu 14.04のレポジトリにffmpegが見つかりません-ffprobeもありませんか?私はavprobeを持っていますが、それらの議論は好きではありません。
ジョー14

@Joe- avprobeArchリポジトリにはありません(それはと競合するため、馬鹿げていますffmpeg)ので、ATMを試すことはできませんが、次のように実行するとファイルの期間がわかりますavprobe -show_format_entry duration myfile.mp4avprobe -loglevel quiet -show_format_entry duration myfile.mp4?これらのコマンドのいずれかを使用すると、ファイルの継続時間とともに1行の出力が得られるはずです。わからない。
don_crissti 14

6

これによりffmpeg、合計秒数でタイムアウトが使用および出力されます。

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

説明:

for f in *.ts; do 「.ts」で終わる各ファイルを反復処理します

ffmpeg -i "$f" 2>&1 出力をstderrにリダイレクトします

grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' 時間を隔離する

awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }' 時間を秒に変換します

times+=("$_t") 配列に秒を追加します

echo "${times[@]}" | sed 's/ /+/g' | bc各引数を展開し、スペースを置き換えてbc一般的なLinux計算機にパイプします


1
いいね!あなたのアイデアに大きく基づいている私のバージョンもご覧ください。
MVG

短くてエレガントなソリューション
Neo

4

@jmunschの回答を合理化しpaste@ slmの回答から学んだばかりのを使用すると、次のような結果になります。

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

jmunschがやったように、私は使っています ffmpeg出力ファイルの欠落に関するエラーを無視して、代わりに期間の行のエラー出力を検索し、期間の出力に使用しています。ffmpegロケールのすべての側面を標準Cロケールに強制して呼び出すので、ローカライズされた出力メッセージを心配する必要はありません。

次にawk、彼の代わりにシングルを使用していgrep | grep | head | tr | awkます。そのawk呼び出しは、を含む(願わくは一意の)行を探しますDuration:。コロンを区切り文字として使用すると、そのラベルはフィールド1、時間はフィールド2、分はフィールド3、秒はフィールド4です。秒の後のコンマはmyを気にしませんawkが、問題がある場合は、とのtr -d ,間のパイプラインにを含めることができます。ffmpegawk

今、slmからの部分が来ます:私はpaste改行をプラス記号に置き換えるために使用していますが、末尾の改行には影響しません(この回答の前のバージョンtr \\n +持っていたのとは反対です)。それはに与えることができる合計式を与えます。bc

date時間のような形式を処理するために使用するというslmのアイデアに触発され、ここでは結果の秒を小数部で日、時間、分、秒としてフォーマットするバージョンを使用します。

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

中の部分 $(…)は以前とまったく同じです。使用して@1970年1月1日以降指標として文字を、私たちは秒数としてこれを使用して得られた「日付」は今年、時間とナノ秒の日としてフォーマットされます。その年の日から1を減算します。ゼロ秒の入力はすでにその年の1970年の1日目につながっているためです。年の日数をゼロから開始する方法はないと思います。

最後sedは余分な末尾のゼロを取り除きます。このTZ設定により、UTCが強制的に使用されるようになります。これにより、サマータイムが非常に大きなビデオコレクションに干渉することはありません。ただし、1年以上のビデオがある場合、このアプローチはまだ機能しません。


3

私は.ts拡張子に精通していませんが、それらが次のffmpegようにファイルの期間を識別するために使用できるビデオファイルのタイプであると仮定します:

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

次に、この出力を分割して、継続時間だけを選択できます。

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

したがって、ファイルを反復処理し、これらの期間値を収集する方法が必要になります。

$ 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

注:ここに私の例のために、私は単に私のサンプルファイルをコピーしsome.mp4て、それを名付け1.mp42.mp43.mp4

時間を秒に変換する

次のスニペットは、上記の期間を取得し、それらを秒に変換します。

$ 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

$durファイルをループする際に、これは期間をとり、変数に入れます。次に、このdateコマンドを使用して、UNIXエポック(1970/01/01)の正弦秒数を計算します。上記のdateコマンドは次のように分割されているため、見やすくなっています。

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

注:dateこの方法での使用は、すべてのファイルの期間が24時間(86400秒)未満の場合にのみ機能します。より長い期間を処理できるものが必要な場合は、これを代替として使用できます。

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

時間を合計する

次に、forループの出力を取得して、次のように各数値の間に符号pasteを組み込むコマンドに実行できます+

$ 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

最後に、これをコマンドライン計算機で実行して、bc合計します。

$ 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

その結果、すべてのファイルの合計期間が秒単位で表示されます。もちろん、これは必要に応じて他の形式に変換できます。


@DamenSalvatore-問題ありません。タスクをさまざまなステップに分割する方法を示してくれるので、必要に応じてカスタマイズできます。
slm

@slm -私はと秒にビデオ再生時間を変換するための別の方法を使用しdateている場合かもしれないチョークffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"返しますのようなもの26:33:21.68(、/ 86400秒の持続時間≥24時間です)
don_crissti

@don_crissti-おかげで、テストするときに20時間以上試していない。別の方法を示すメモを追加します。
slm

ご回答有難うございます!だけでなく、それを鼓舞したの鉱山を、それももたらしたpaste私の注意を。私は推測java -classpath $(find -name \*.jar | paste -sd:)になるだろう非常に私は過去にこのために使用されるのだハックを考慮すると、私には便利。
MVG

@MvG- paste私のお気に入りのコマンド8
slm

1

受け入れられた答えを出して、古典的な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

すなわち:それを追加し+pそれをパイプするdcと、合計が得られます。


2
bcあまりにも多くの愛を得る。あなたはすべて+各行の間にサインを入れています(に参加+)、逆研磨ではあなたはちょうど+最後にチャックしてpそれをリントすることができます;)
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がインストールされていることを確認してください。


それは私に任意の出力を与えるdoes notの
k961

mplayerとperlがインストールされていますか?
ryanmjacobs

はい、mplayerをインストールし、perlは既にインストールされています
k961 14

1
申し訳ありませんが、なぜ機能しないのかわかりません。とにかく、あなたはすでに十分なまともな答えをすでに持っています。:)
ryanmjacobs 14

0

Ubuntuはffmpegではなくlibavを出荷します:

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

MvGのアイデアに大きく基づいている


0

さて、これらのすべてのソリューションには少し作業が必要です。

  1. 目的のフォルダに移動し、右クリック->他のアプリケーションで開く

  2. 次に、VLCメディアプレーヤーを選択し、

  3. これにより、ビデオの1つが再生されますが、
  4. ctrl + Lを押すと、ビデオのプレイリストが表示され、左上のどこかに合計時間が表示されます

ここに例があります

1。 リストアイテム

2。ここに画像の説明を入力してください

3。ここに画像の説明を入力してください

ツールバーのすぐ下に、プレイリスト[10:35:51]と書かれているので、フォルダーには合計10時間35分51秒間のビデオが含まれています


0

現在のフォルダーにサブディレクトリがあるため、継続時間を再帰的に計算する必要がありました。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.