获取Python中特定目录视频的总时长

5 投票
6 回答
17975 浏览
提问于 2025-04-17 16:52

我从coursera.org下载了一堆视频,并把它们存放在一个特定的文件夹里。这个文件夹里有很多单独的视频(因为Coursera把一节课分成了多个短视频)。我想要一个Python脚本,能够计算出这个文件夹里所有视频的总时长。这些视频文件都是.mp4格式的。

6 个回答

2

除了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上我没有做任何改动就能正常工作。

3
  1. 首先,下载并安装 MediaInfo(注意不要安装里面捆绑的广告软件)
  2. 接着,去 MediaInfo的源代码下载页面,在“源代码,全部包含”那一行,选择“libmediainfo”旁边的链接。
  3. 在下载的压缩包里找到 MediaInfoDLL3.py 文件,并把它解压到你想要的地方。 比如可以放在:libmediainfo_0.7.62_AllInclusive.7z\MediaInfoLib\Source\MediaInfoDLL\MediaInfoDLL3.py
  4. 然后在同一个目录下创建一个测试脚本(下面有示例)。
  5. 最后,运行这个脚本。

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")
8

首先,安装 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,可以查看这个回答的 编辑历史

撰写回答