获取Python中特定目录视频的总时长
我从coursera.org下载了一堆视频,并把它们存放在一个特定的文件夹里。这个文件夹里有很多单独的视频(因为Coursera把一节课分成了多个短视频)。我想要一个Python脚本,能够计算出这个文件夹里所有视频的总时长。这些视频文件都是.mp4格式的。
6 个回答
除了Janus Troelsen上面的回答,我想提到一个我在实现他的方法时遇到的小问题。我按照他的步骤一步步操作,但在Windows(7)和Linux(Ubuntu)上得到的结果却不一样。他的方法在Linux上运行得很好,但在Windows上我不得不做一些小改动才能让它工作。我在Windows上使用的是32位的Python 2.7.2解释器,所以我用了MediaInfoDLL.py。但这还不够,我在这个过程中遇到了一个错误:
“WindowsError: [Error 193] %1 不是一个有效的 Win32 应用程序”。
这意味着我使用的某个资源不是32位的,问题可能出在MediaInfoDLL.py加载的DLL文件上。如果你查看MediaInfo的安装目录,会看到有三个DLL文件,其中MediaInfo.dll是64位的,而MediaInfo_i386.dll是32位的。由于我的Python环境是32位的,所以我必须使用MediaInfo_i386.dll。我打开了MediaInfoDLL.py(我已经把它包含在我的项目里),并修改了这一行:
MediaInfoDLL_Handler = windll.MediaInfo
改成
MediaInfoDLL_Handler = WinDLL("C:\Program Files (x86)\MediaInfo\MediaInfo_i386.dll")
在Linux上我没有做任何改动就能正常工作。
- 首先,下载并安装 MediaInfo(注意不要安装里面捆绑的广告软件)
- 接着,去 MediaInfo的源代码下载页面,在“源代码,全部包含”那一行,选择“libmediainfo”旁边的链接。
- 在下载的压缩包里找到
MediaInfoDLL3.py
文件,并把它解压到你想要的地方。 比如可以放在:libmediainfo_0.7.62_AllInclusive.7z\MediaInfoLib\Source\MediaInfoDLL\MediaInfoDLL3.py
。 - 然后在同一个目录下创建一个测试脚本(下面有示例)。
- 最后,运行这个脚本。
MediaInfo也可以在POSIX系统上运行。唯一的区别是它会加载一个 so
文件,而不是DLL。
测试脚本(Python 3!)
import os
os.chdir(os.environ["PROGRAMFILES"] + "\\mediainfo")
from MediaInfoDLL3 import MediaInfo, Stream
MI = MediaInfo()
def get_lengths_in_milliseconds_of_directory(prefix):
for f in os.listdir(prefix):
MI.Open(prefix + f)
duration_string = MI.Get(Stream.Video, 0, "Duration")
try:
duration = int(duration_string)
yield duration
print("{} is {} milliseconds long".format(f, duration))
except ValueError:
print("{} ain't no media file!".format(f))
MI.Close()
print(sum(get_lengths_in_milliseconds_of_directory(os.environ["windir"] + "\\Performance\\WinSAT\\"
)), "milliseconds of content in total")
首先,安装 ffprobe
命令(它是 FFmpeg 的一部分),可以通过以下命令进行安装:
sudo apt install ffmpeg
然后使用 subprocess.run()
来运行这个 bash 命令:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 -- <filename>
(这个命令我是在 http://trac.ffmpeg.org/wiki/FFprobeTips#Formatcontainerduration 找到的),像这样:
from pathlib import Path
import subprocess
def video_length_seconds(filename):
result = subprocess.run(
[
"ffprobe",
"-v",
"error",
"-show_entries",
"format=duration",
"-of",
"default=noprint_wrappers=1:nokey=1",
"--",
filename,
],
capture_output=True,
text=True,
)
try:
return float(result.stdout)
except ValueError:
raise ValueError(result.stderr.rstrip("\n"))
# a single video
video_length_seconds('your_video.webm')
# all mp4 files in the current directory (seconds)
print(sum(video_length_seconds(f) for f in Path(".").glob("*.mp4")))
# all mp4 files in the current directory and all its subdirectories
# `rglob` instead of `glob`
print(sum(video_length_seconds(f) for f in Path(".").rglob("*.mp4")))
# all files in the current directory
print(sum(video_length_seconds(f) for f in Path(".").iterdir() if f.is_file()))
这段代码需要 Python 3.7 及以上版本,因为 text=
和 capture_output=
是在这个版本中添加到 subprocess.run
的。如果你使用的是旧版本的 Python,可以查看这个回答的 编辑历史。