รับระยะเวลารวมของไฟล์วิดีโอในไดเรกทอรี


30

ฉันมีรายการ.tsไฟล์:

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

ฉันจะรับระยะเวลาทั้งหมด (เวลาทำงาน) ของไฟล์ทั้งหมดเหล่านี้ได้อย่างไร


คุณจะได้รับระยะเวลาของไฟล์เดียวได้อย่างไร
Hauke ​​Laging

ฉันก็ไม่รู้เหมือนกันว่า
k961

@Hauke ​​Laging ฉันพบโปรแกรมนี้ "mediainfo"
k961

นี่คือไฟล์สื่อวิดีโอที่น่าจะเป็น
slm

1
ไฟล์สื่อใด ๆ (เช่น: MP4, ASF & .264 ... ) จะมีข้อมูลส่วนหัวมาตรฐานที่กำหนดไว้ล่วงหน้าเราสามารถรับข้อมูลจากไฟล์เช่นความละเอียดอัตราเฟรมจำนวนเฟรม (GOP) และความยาว & ระยะเวลาของไฟล์ สื่อ ...
Kantam Nagesh

คำตอบ:


55

ผมไม่มี.tsนี่ .mp4แต่งานนี้สำหรับ ใช้ffprobe(บางส่วนffmpeg) เพื่อให้ได้เวลาเป็นวินาทีเช่น:

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

ดังนั้นสำหรับ.mp4ไฟล์ทั้งหมดใน dir ปัจจุบัน:

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

@fduff ในขณะที่bcจะมีความแม่นยำโดยพลการหนึ่งข้อเสียเปรียบก็คือว่า...| paste -sd+ - | bcจะถึงขีด จำกัด ขนาดบรรทัดในbcการใช้งานบางอย่าง(เช่นseq 429 | paste -sd+ - | bcล้มเหลวด้วย OpenSolaris bc) หรือมีศักยภาพในการใช้หน่วยความจำทั้งหมดในคนอื่น ๆ
Stéphane Chazelas

คุณสามารถทำได้ (วิธี ffprobe) กับสิ่งที่ชอบ avconv หรือไม่? ฉันหา ffmpeg ใน repos ของฉันไม่ได้สำหรับ Kubuntu 14.04 - ดังนั้นฉันไม่มี ffprobe เหมือนกัน? ฉันมี avprobe แต่ไม่ชอบข้อโต้แย้งเหล่านั้น
โจ

@Joe - ไม่มีavprobeใน repos Arch (prolly เพราะมันขัดแย้งกับffmpeg) ดังนั้นจึงไม่สามารถลองใช้ ATM ได้ แต่จะให้ระยะเวลาของไฟล์หากคุณเรียกใช้เช่นนี้: avprobe -show_format_entry duration myfile.mp4หรือavprobe -loglevel quiet -show_format_entry duration myfile.mp4 ? ฉันคิดว่าหนึ่งในคำสั่งเหล่านี้ควรให้เอาต์พุตบรรทัดเดียวกับระยะเวลาของไฟล์ ไม่แน่ใจว่า
don_crissti

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เครื่องคิดเลขลินุกซ์ทั่วไป


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 เครื่องหมายจุลภาคต่อท้ายหลังจากวินาทีดูเหมือนจะไม่รบกวนฉันawkแต่ถ้ามีคนที่มีปัญหาอยู่ที่นั่น อาจรวมถึงtr -d ,ในไปป์ไลน์ระหว่างffmpegawkและ

ส่วนนี้มาจาก 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]*$//'

ส่วนที่อยู่ภายใน$(…)เป็นเหมือนก่อน การใช้@ตัวละครเป็นตัวบ่งชี้เราใช้สิ่งนี้เป็นจำนวนวินาทีตั้งแต่วันที่ 1 มกราคม 1970 "วันที่" ที่ได้รับนั้นได้รับการจัดรูปแบบเป็นวันของปีเวลาและนาโนวินาที จากวันนั้นของปีเราลบหนึ่งอันเนื่องจากอินพุตของศูนย์วินาทีนำไปสู่วันที่ 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.mp4, และ2.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คำสั่งที่ใช้ในการคำนวณจำนวนวินาทีไซน์ยุคยูนิกซ์ (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

@don_crissti - ขอบคุณฉันไม่ได้ลองเกิน 20 ชั่วโมงแล้วตอนทดสอบ ฉันจะเพิ่มบันทึกแสดงวิธีการทางเลือก
slm

ขอบคุณสำหรับคำตอบ! มันไม่เพียงสร้างแรงบันดาลใจให้ฉันเท่านั้น แต่ยังทำให้pasteฉันสนใจอีกด้วย ผมคิดว่าjava -classpath $(find -name \*.jar | paste -sd:)เป็นไปได้มากประโยชน์เพื่อให้ฉันพิจารณา hacks ที่ฉันต้องการใช้สำหรับการนี้ในอดีต
MvG

@MvG - pasteเป็นคำสั่งที่ฉันโปรดปราน 8-)
slm

1

ออกคำตอบที่ยอมรับและใช้เครื่องมือ UNIX reverse-polish คลาสสิก:

{ 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ได้รับความรักมากเกินไป คุณกำลังใส่+เครื่องหมายระหว่างแต่ละบรรทัด (เข้าร่วม+) ในขณะที่มีการขัดกลับคุณสามารถโยน+ปลายและprint มันออก)
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


มันไม่ให้ผลใด ๆ กับฉันเลย
k961

คุณติดตั้ง mplayer และ perl แล้วหรือยัง
ryanmjacobs

ใช่ฉันติดตั้ง mplayer และ perl ได้รับการติดตั้งแล้ว
k961

1
ขออภัยฉันไม่รู้ว่าทำไมมันไม่ทำงาน แต่คุณมีคำตอบที่ดีพออยู่แล้ว :)
ryanmjacobs

0

ในฐานะที่เป็น ubuntu ship 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 media player

  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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.