我有一个.ts
文件列表:
out1.ts ... out749.ts out8159.ts out8818.ts
如何获得所有这些文件的总持续时间(运行时间)?
我有一个.ts
文件列表:
out1.ts ... out749.ts out8159.ts out8818.ts
如何获得所有这些文件的总持续时间(运行时间)?
Answers:
我在.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
。
paste
和的妙招bc
!比awk
说的清洁得多。
bc
可以做到任意精度,但一个缺点是,...| paste -sd+ - | bc
要么在某些bc
实现中达到行大小限制(例如seq 429 | paste -sd+ - | bc
OpenSolaris失败bc
),要么有可能耗尽其他实现中的所有内存。
avprobe
在Arch存储库中没有((因为与冲突ffmpeg
),所以很麻烦),因此无法尝试ATM,但是如果您按以下方式运行它,它是否为您提供文件的持续时间:avprobe -show_format_entry duration myfile.mp4
或avprobe -loglevel quiet -show_format_entry duration myfile.mp4
?我认为这些命令之一应该为您提供文件持续时间的单行输出。虽然不确定。
这将使用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
在打印持续时间,忽略有关缺少输出文件的错误,而是在错误输出中搜索持续时间行。我调用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,以使夏时制不会干扰真正的大型视频集。但是,如果您拥有超过一年的视频,这种方法仍然行不通。
我不熟悉.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.mp4
,2.mp4
和3.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
得出所有文件的总持续时间(以秒为单位)。当然,如果需要,可以将其转换为其他格式。
date
如果ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
返回类似26:33:21.68
(即持续时间≥24小时/ 86400秒),则可能会窒息
paste
是我最喜欢的命令8
$ 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船libav而不是ffmpeg:
#!/bin/sh
for f in *.mp4; do
avprobe -v quiet -show_format_entry duration "$f"
done | paste -sd+ | bc
大量基于MvG想法
好吧,所有这些解决方案都需要一些工作,我所做的非常简单,1)
转到所需的文件夹,然后右键单击->使用其他应用程序打开
然后选择VLC媒体播放器,
这是例子
您可以在工具栏下方看到写入的播放列表[10:35:51],因此该文件夹包含10小时35分钟和51秒的总视频时长