获取目录中视频文件的总时长


30

我有一个.ts文件列表:

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

如何获得所有这些文件的总持续时间(运行时间)?


您如何获得单个文件的持续时间?
Hauke Laging

我也不知道
k96114年

@Hauke Laging我发现此程序为“ mediainfo”
k96114年

这些是媒体文件,可能是视频。
slm

1
任何媒体文件(例如:MP4,ASF和.264 ...)都将具有预定义的标准标头信息,我们可以从该文件中获取信息,例如分辨率,帧速率,帧数(GOP),文件长度和持续时间。媒体...
Kantam Nagesh 2014年

Answers:


55

我在.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输出传递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
paste和的妙招bc!比awk说的清洁得多。
fduff 2014年

@fduff。尽管bc可以做到任意精度,但一个缺点是,...| paste -sd+ - | bc要么在某些bc实现中达到行大小限制(例如seq 429 | paste -sd+ - | bcOpenSolaris失败bc),要么有可能耗尽其他实现中的所有内存。
斯特凡Chazelas

您可以使用avconv之类的方法(ffprobe方法)吗?我在Kubuntu 14.04的回购中找不到ffmpeg-所以我也没有ffprobe?我确实有avprobe,但它不喜欢这些参数。
2014年

@Joe- avprobe在Arch存储库中没有((因为与冲突ffmpeg),所以很麻烦),因此无法尝试ATM,但是如果您按以下方式运行它,它是否为您提供文件的持续时间:avprobe -show_format_entry duration myfile.mp4avprobe -loglevel quiet -show_format_entry duration myfile.mp4?我认为这些命令之一应该为您提供文件持续时间的单行输出。虽然不确定。
don_crissti 2014年

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 2014年

简短而优雅的解决方案

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。秒后的尾部逗号似乎并不困扰我awk,但是如果有人在那儿遇到问题,他可以tr -d ,ffmpeg和之间建立管道awk

现在来自slm:我正在用paste加号替换换行符,但不影响尾随的换行符(与该答案的上一版本中的tr \\n +我相反)。这给出了可以求和的和表达式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年那一天的第一天。我认为没有办法使一年中的天数从零开始。

决赛sed摆脱了多余的尾随零。该TZ设置有望强制使用UTC,以使夏时制不会干扰真正的大型视频集。但是,如果您拥有超过一年的视频,这种方法仍然行不通。


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(即持续时间≥24小时/ 86400秒),则可能会窒息
don_crissti 2014年

@don_crissti-谢谢,测试时我没有尝试超过20个小时。我将添加一条注释,显示另一种方法。
slm

感谢您的回答!它不仅启发了,也引起paste了我的注意。我的猜测java -classpath $(find -name \*.jar | paste -sd:)将是非常有用的我,考虑到我已经在过去用于此的黑客。
MvG 2014年

@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

即:Appening +p然后管道到这一点dc,你会得到你的总和。


2
bc得到太多的爱。大家都+在每条线之间+插入了符号(在上连接),而通过反向抛光,您可以+在最后端夹一个p); RINT出来
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


它没有任何输出
k96114年

您是否已安装mplayer和perl?
ryanmjacobs 2014年

是的,我已经安装了mplayer并且已经安装了perl
k961 2014年

1
抱歉,我不知道为什么它不起作用。但是,无论如何,您已经有足够的体面的答案。:)
ryanmjacobs 2014年

0

作为ubuntu船libav而不是ffmpeg:

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

大量基于MvG想法


0

好吧,所有这些解决方案都需要一些工作,我所做的非常简单,1)

  1. 转到所需的文件夹,然后右键单击->使用其他应用程序打开

  2. 然后选择VLC媒体播放器,

  3. 这将开始播放其中一个视频, 但随后
  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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.