.ts
ファイルのリストがあります。
out1.ts ... out749.ts out8159.ts out8818.ts
これらのすべてのファイルの合計時間(実行時間)を取得するにはどうすればよいですか?
ここには.ts
がありませんが、これは.mp4
で機能します。 ffprobe
(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
to 出力を渡す を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
これは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計算機にパイプします
@ 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
を使用して期間を出力し、欠落している出力ファイルに関するエラーを無視して、代わりに期間の行のエラー出力を検索します。ロケールのすべての側面を標準Cロケールに強制してffmpeg
を呼び出すので、ローカライズされた出力メッセージについて心配する必要はありません。
次に、_grep | grep | head | tr | awk
_の代わりに単一のawk
を使用しています。そのawk
呼び出しは、_Duration:
_を含む(できれば一意の)行を探します。コロンをセパレータとして使用すると、そのラベルはフィールド1、時間はフィールド2、提出された分3、秒フィールド4になります。秒の後のコンマは、awk
を気にしないようですが、誰かがそこで問題を抱えている場合、ffmpeg
とawk
の間のパイプラインに_tr -d ,
_を含めることができます。
ここでslmからの部分です:paste
を使用して改行をプラス記号に置き換えていますが、末尾の改行に影響を与えていません(_tr \\n +
_とは異なり、 aこの回答の以前のバージョン )。これにより、bc
に入力できる合計式が得られます。
Slmのdate
を使用して時間のような形式を処理するというアイデアに触発されたもので、これを使用して、結果の秒を日、時、分、秒の小数部としてフォーマットします。
_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の使用を強制し、夏時間がreally大規模なビデオコレクションに干渉しないようにします。 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
にパイプすると、合計が得られます。
現在のフォルダーにサブディレクトリがあるので、期間を再帰的に計算する必要がありました。
find . -iname '*.mp4' -print0 | xargs --null exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)}' | tail -n1
$ 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がインストールされていることを確認してください。
Ubuntuがffmpegの代わりにlibavを出荷するので:
#!/bin/sh
for f in *.mp4; do
avprobe -v quiet -show_format_entry duration "$f"
done | paste -sd+ | bc
MvG のアイデアに大きく基づいています