Tôi có một danh sách các .ts
tập tin:
out1.ts ... out749.ts out8159.ts out8818.ts
Làm cách nào tôi có thể nhận được tổng thời lượng (thời gian chạy) của tất cả các tệp này?
Tôi có một danh sách các .ts
tập tin:
out1.ts ... out749.ts out8159.ts out8818.ts
Làm cách nào tôi có thể nhận được tổng thời lượng (thời gian chạy) của tất cả các tệp này?
Câu trả lời:
Tôi không có .ts
ở đây nhưng điều này làm việc cho .mp4
. Sử dụng ffprobe
(một phần ffmpeg
) để lấy thời gian tính bằng giây, ví dụ:
ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4
275.690000
vì vậy đối với tất cả .mp4
các tệp trong thư mục hiện tại:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000
sau đó sử dụng paste
để chuyển đầu ra đến bc
và nhận tổng thời gian tính bằng giây:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000
Vì vậy, đối với .ts
các tệp bạn có thể thử:
find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
Một công cụ khác hoạt động cho các tập tin video tôi có ở đây là exiftool
, ví dụ:
exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69
Tổng chiều dài cho tất cả .mp4
các tệp trong thư mục hiện tại:
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
Bạn cũng có thể chuyển đầu ra sang một lệnh khác để chuyển đổi tổng thành DD:HH:MM:SS
, xem câu trả lời ở đây .
Hoặc sử dụng exiftool
nội bộ ConvertDuration
cho điều đó (mặc dù bạn cần một phiên bản tương đối gần đây):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobe
đó trước đây.
paste
và bc
! sạch sẽ hơn nhiều so với awk
giả sử.
bc
sẽ có độ chính xác tùy ý, một nhược điểm là ...| paste -sd+ - | bc
sẽ đạt đến giới hạn kích thước dòng trong một số bc
triển khai (ví dụ như seq 429 | paste -sd+ - | bc
thất bại với OpenSolaris bc
) hoặc có khả năng sử dụng hết bộ nhớ trong các bộ nhớ khác.
avprobe
trong Arch repos (prolly vì nó xung đột với ffmpeg
) vì vậy không thể dùng thử ATM nhưng nó có cung cấp cho bạn thời lượng của tệp nếu bạn chạy nó như thế này: avprobe -show_format_entry duration myfile.mp4
hay avprobe -loglevel quiet -show_format_entry duration myfile.mp4
? Tôi nghĩ rằng một trong những lệnh này sẽ cung cấp cho bạn một dòng đầu ra duy nhất với thời lượng của tệp. Không chắc chắn mặc dù.
Điều này sử dụng ffmpeg
và in thời gian ra trong tổng số giây:
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
Giải trình:
for f in *.ts; do
lặp lại từng tệp kết thúc bằng ".ts"
ffmpeg -i "$f" 2>&1
chuyển hướng đầu ra cho thiết bị lỗi chuẩn
grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' '
cô lập thời gian
awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'
Chuyển đổi thời gian thành giây
times+=("$_t")
thêm giây vào một mảng
echo "${times[@]}" | sed 's/ /+/g' | bc
mở rộng từng đối số và thay thế khoảng trắng và chuyển nó sang bc
một máy tính linux phổ biến
Sắp xếp hợp lý câu trả lời của @ jmunsch và sử dụng câu trả lờipaste
tôi vừa học được từ câu trả lời của @ slm , bạn có thể kết thúc bằng một câu như thế này:
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
Giống như jmunsch đã làm, tôi đang sử dụng ffmpeg
để in thời lượng, bỏ qua lỗi về một tệp đầu ra bị thiếu và thay vào đó tìm kiếm đầu ra lỗi cho dòng thời lượng. Tôi gọiffmpeg
với tất cả các khía cạnh của miền địa phương buộc phải đến miền địa phương C tiêu chuẩn, do đó tôi sẽ không phải lo lắng về các thông điệp đầu ra được bản địa hóa.
Tiếp theo tôi đang sử dụng một awk
thay vì của mình grep | grep | head | tr | awk
. Lời mời đó awk
tìm kiếm dòng (hy vọng duy nhất) có chứa Duration:
. Sử dụng dấu hai chấm làm dấu phân cách, nhãn đó là trường 1, giờ là trường 2, phút nộp 3 và trường giây 4. Dấu phẩy sau giây dường như không làm phiền tôi awk
, nhưng nếu ai đó có vấn đề ở đó, anh ta có thể bao gồm một tr -d ,
trong các đường ống giữa ffmpeg
và awk
.
Bây giờ đến phần từ slm: Tôi đang sử dụng paste
để thay thế dòng mới bằng dấu cộng, nhưng không ảnh hưởng đến dòng mới (trái với câu tr \\n +
tôi đã có trong phiên bản trước của câu trả lời này). Điều đó đưa ra biểu thức tổng có thể được cung cấp chobc
.
Lấy cảm hứng từ ý tưởng sử dụng slm date
để xử lý các định dạng giống như thời gian, đây là phiên bản sử dụng nó để định dạng các giây kết quả là ngày, giờ, phút và giây với phần phân số:
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]*$//'
Phần bên trong $(…)
chính xác như trước. Sử dụng@
ký tự làm chỉ dẫn, chúng tôi sử dụng số này làm số giây kể từ ngày 1 tháng 1 năm 1970. Kết quả là ngày NGÀY được định dạng là ngày trong năm, thời gian và nano giây. Từ ngày đó trong năm, chúng tôi trừ đi một, vì đầu vào bằng 0 giây đã dẫn đến ngày 1 của năm 1970. Tôi không nghĩ có cách nào để có được số ngày trong năm bắt đầu từ 0.
Trận chung kết sed
được loại bỏ các số 0 thêm. Các TZ
thiết lập hy vọng sẽ buộc việc sử dụng UTC, do đó tiết kiệm thời gian ban ngày sẽ không gây trở ngại cho sự sưu tập video lớn. Tuy nhiên, nếu bạn có video có giá trị hơn một năm, thì phương pháp này vẫn không hiệu quả.
Tôi không quen thuộc với .ts
tiện ích mở rộng, nhưng giả sử chúng là một loại tệp video bạn có thể sử dụng ffmpeg
để xác định thời lượng của tệp như vậy:
$ ffmpeg -i some.mp4 2>&1 | grep Dura
Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s
Sau đó chúng ta có thể tách đầu ra này lên, chỉ chọn thời lượng.
$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01
Vì vậy, bây giờ chúng ta chỉ cần một cách để lặp qua các tệp của mình và thu thập các giá trị thời lượng này.
$ 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
LƯU Ý: Ở đây ví dụ của tôi, tôi chỉ đơn giản là sao chép tập tin mẫu của tôi some.mp4
và đặt tên cho nó 1.mp4
, 2.mp4
và 3.mp4
.
Đoạn mã sau sẽ lấy thời lượng từ phía trên và chuyển đổi chúng thành giây.
$ 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
Điều này có thời lượng của chúng tôi và đặt chúng trong một biến $dur
, khi chúng tôi lặp qua các tệp. Các date
sau đó lệnh được sử dụng để tính toán số giây sin kỷ nguyên Unix (1970/01/01). Đây là date
lệnh trên được chia ra để dễ nhìn hơn:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
LƯU Ý: Sử dụng date
theo cách này sẽ chỉ hoạt động nếu tất cả các tệp của bạn có thời lượng <24 giờ (tức là 86400 giây). Nếu bạn cần một cái gì đó có thể xử lý thời lượng lớn hơn, bạn có thể sử dụng nó như là một thay thế:
sed 's/^/((/; s/:/)*60+/g' | bc
Thí dụ
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01
Sau đó, chúng ta có thể lấy đầu ra của for
vòng lặp của mình và chạy nó thành một paste
lệnh sẽ kết hợp +
các dấu hiệu ở giữa mỗi số, như vậy:
$ 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
Cuối cùng, chúng tôi chạy nó vào máy tính dòng lệnh, bc
để tổng hợp chúng:
$ 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
Kết quả là tổng thời lượng của tất cả các tệp, tính bằng giây. Điều này tất nhiên có thể được chuyển đổi sang một số định dạng khác nếu cần.
date
có thể bị nghẹt nếu ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
trả về một cái gì đó như 26:33:21.68
(nghĩa là thời lượng ≥ 24 giờ / 86400 giây)
paste
là lệnh ưa thích của tôi 8-)
Bỏ qua câu trả lời được chấp nhận và sử dụng công cụ đánh bóng ngược UNIX cổ điển:
{ find . -maxdepth 2 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 \
-show_entries format=duration {} \; ; printf '+\n60\n*\np'; } | dc
783.493000
Tức là: Xuất hiện +
và p
sau đó chuyển nó vào dc
và bạn sẽ nhận được số tiền của mình.
$ 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'
Hãy chắc chắn rằng bạn đã cài đặt MPlayer .
Chà, tất cả những giải pháp này cần một chút công việc, những gì tôi đã làm rất đơn giản, 1)
đi đến thư mục mong muốn và nhấp chuột phải -> mở với ứng dụng khác
Sau đó chọn trình phát phương tiện VLC,
đây là ví dụ
Bạn có thể thấy ngay dưới thanh công cụ, có Playlist [10:35:51] được viết, vì vậy thư mục chứa 10 giờ 35 phút và thời lượng 51 giây của tổng số video