使用Python获取视频属性,无需调用外部软件

2024-01-10

[更新:] 是的,有可能,现在大约 20 个月后了。请参阅下面的更新3! [/更新]

这真的不可能吗?我能找到的只是调用 FFmpeg(或其他软件)的变体。我当前的解决方案如下所示,但我真正想要的可移植性是一个仅 Python 的解决方案,不需要用户安装额外的软件。

毕竟,我可以使用 PyQt 的 Phonon 轻松播放视频,但我无法简单地获取视频的尺寸或持续时间等信息?

我的解决方案使用 ffmpy (http://ffmpy.readthedocs.io/en/latest/ffmpy.html http://ffmpy.readthedocs.io/en/latest/ffmpy.html) 这是 FFmpeg 和 FFprobe 的包装器 (http://trac.ffmpeg.org/wiki/FFprobeTips http://trac.ffmpeg.org/wiki/FFprobeTips)。比其他产品更流畅,但它仍然需要额外的 FFmpeg 安装。

    import ffmpy, subprocess, json
    ffprobe = ffmpy.FFprobe(global_options="-loglevel quiet -sexagesimal -of json -show_entries stream=width,height,duration -show_entries format=duration -select_streams v:0", inputs={"myvideo.mp4": None})
    print("ffprobe.cmd:", ffprobe.cmd)  # printout the resulting ffprobe shell command
    stdout, stderr = ffprobe.run(stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    # std* is byte sequence, but json in Python 3.5.2 requires str
    ff0string = str(stdout,'utf-8')

    ffinfo = json.loads(ff0string)
    print(json.dumps(ffinfo, indent=4)) # pretty print

    print("Video Dimensions: {}x{}".format(ffinfo["streams"][0]["width"], ffinfo["streams"][0]["height"]))
    print("Streams Duration:", ffinfo["streams"][0]["duration"])
    print("Format Duration: ", ffinfo["format"]["duration"])

输出结果:

    ffprobe.cmd: ffprobe -loglevel quiet -sexagesimal -of json -show_entries stream=width,height,duration -show_entries format=duration -select_streams v:0 -i myvideo.mp4
    {
        "streams": [
            {
                "duration": "0:00:32.033333",
                "width": 1920,
                "height": 1080
            }
        ],
        "programs": [],
        "format": {
            "duration": "0:00:32.064000"
        }
    }
    Video Dimensions: 1920x1080
    Streams Duration: 0:00:32.033333
    Format Duration:  0:00:32.064000

UPDATE经过几天的实验:下面由 Nick 提出的 hach​​oire 解决方案确实有效,但会给您带来很多麻烦,因为 hach​​oire 响应太不可预测了。不是我的选择。

使用 opencv 编码再简单不过了:

import cv2
vid = cv2.VideoCapture( picfilename)
height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT) # always 0 in Linux python3
width  = vid.get(cv2.CAP_PROP_FRAME_WIDTH)  # always 0 in Linux python3
print ("opencv: height:{} width:{}".format( height, width))

问题是它在 Python2 上运行良好,但在 Py3 上运行不佳。引用:“重要提示:MacOS 和 Linux 软件包不支持视频相关功能(未使用 FFmpeg 编译)” (https://pypi.python.org/pypi/opencv-python https://pypi.python.org/pypi/opencv-python).

除此之外,opencv 似乎需要在运行时存在 FFmeg 的二进制包(https://docs.opencv.org/3.3.1/d0/da7/videoio_overview.html https://docs.opencv.org/3.3.1/d0/da7/videoio_overview.html).

好吧,如果我无论如何都需要安装 FFmpeg,我可以坚持使用上面所示的原始 ffmpy 示例:-/

谢谢您的帮助。

UPDATE2:master_q(见下文)提出MediaInfo。虽然这在我的 Linux 系统上不起作用(请参阅我的评论),但使用 pymediainfo(MediaInfo 的 py 包装器)的替代方案确实有效。使用起来很简单,但是获取时长、宽度和高度的时间比我最初的 ffprobe 方法要长 4 倍,并且仍然需要外部软件,即 MediaInfo:

from pymediainfo import MediaInfo
media_info = MediaInfo.parse("myvideofile")
for track in media_info.tracks:
    if track.track_type == 'Video':
        print("duration (millisec):", track.duration)
        print("width, height:", track.width, track.height)

UPDATE3:OpenCV 终于可用于 Python3 了,据称可以在 Linux、Win 和 Mac 上运行!它使它变得非常简单,而且我证实不需要外部软件 - 特别是 ffmpeg!

首先通过 Pip 安装 OpenCV:

pip install opencv-python

在Python中运行:

import cv2
cv2video = cv2.VideoCapture( videofilename)
height = cv2video.get(cv2.CAP_PROP_FRAME_HEIGHT)
width  = cv2video.get(cv2.CAP_PROP_FRAME_WIDTH) 
print ("Video Dimension: height:{} width:{}".format( height, width))

framecount = cv2video.get(cv2.CAP_PROP_FRAME_COUNT ) 
frames_per_sec = cv2video.get(cv2.CAP_PROP_FPS)
print("Video duration (sec):", framecount / frames_per_sec)

# equally easy to get this info from images
cv2image = cv2.imread(imagefilename, flags=cv2.IMREAD_COLOR  )
height, width, channel  = cv2image.shape
print ("Image Dimension: height:{} width:{}".format( height, width))

我还需要视频的第一帧作为图像,并使用 ffmpeg 将图像保存在文件系统中。使用 OpenCV 也更容易:

hasFrames, cv2image = cv2video.read()   # reads 1st frame
cv2.imwrite("myfilename.png", cv2image) # extension defines image type

但更好的是,因为我只需要内存中的图像用于 PyQt5 工具包,所以我可以直接将 cv2 图像读取到 Qt 图像中:

bytesPerLine = 3 * width
# my_qt_image = QImage(cv2image, width, height, bytesPerLine, QImage.Format_RGB888) # may give false colors!
my_qt_image = QImage(cv2image.data, width, height, bytesPerLine, QImage.Format_RGB888).rgbSwapped() # correct colors on my systems

由于 OpenCV 是一个庞大的程序,我担心时间问题。事实证明,OpenCV 从未落后于其他替代方案。我阅读一张幻灯片大约需要 100 毫秒,其余的加起来不会超过 10 毫秒。

我在 Ubuntu Mate 16.04、18.04 和 19.04 以及 Windows 10 Pro 的两个不同安装上成功进行了测试。 (没有可用的 Mac)。我对 OpenCV 感到非常高兴!

您可以在我的 SlideSorter 程序中看到它的运行情况,该程序允许对图像和视频进行排序、保留排序顺序并以幻灯片形式呈现。可以在这里找到:https://sourceforge.net/projects/slidesorter/ https://sourceforge.net/projects/slidesorter/


好的,在我自己调查之后,因为我也需要它,看起来可以用hachoir。这是一个代码片段,可以为您提供 hach​​oir 可以读取的所有元数据:

import re
from hachoir.parser import createParser
from hachoir.metadata import extractMetadata

def get_video_metadata(path):
    """
        Given a path, returns a dictionary of the video's metadata, as parsed by hachoir.
        Keys vary by exact filetype, but for an MP4 file on my machine,
        I get the following keys (inside of "Common" subdict):
            "Duration", "Image width", "Image height", "Creation date",
            "Last modification", "MIME type", "Endianness"

        Dict is nested - common keys are inside of a subdict "Common",
        which will always exist, but some keys *may* be inside of
        video/audio specific stream subdicts, named "Video Stream #1"
        or "Audio Stream #1", etc. Not all formats result in this
        separation.

        :param path: str path to video file
        :return: dict of video metadata
    """

    if not os.path.exists(path):
        raise ValueError("Provided path to video ({}) does not exist".format(path))

    parser = createParser(path)
    if not parser:
        raise RuntimeError("Unable to get metadata from video file")

    with parser:
        metadata = extractMetadata(parser)

        if not metadata:
            raise RuntimeError("Unable to get metadata from video file")

    metadata_dict = {}
    line_matcher = re.compile("-\s(?P<key>.+):\s(?P<value>.+)")
    group_key = None  # group_key stores which group we're currently in for nesting subkeys
    for line in metadata.exportPlaintext():  # this is what hachoir offers for dumping readable information
        parts = line_matcher.match(line)  #
        if not parts:  # not all lines have metadata - at least one is a header
            if line == "Metadata:":  # if it's the generic header, set it to "Common: to match items with multiple streams, so there's always a Common key
                group_key = "Common"
            else:
                group_key = line[:-1]  # strip off the trailing colon of the group header and set it to be the current group we add other keys into
            metadata_dict[group_key] = {}  # initialize the group
            continue

        if group_key:  # if we're inside of a group, then nest this key inside it
            metadata_dict[group_key][parts.group("key")] = parts.group("value")
        else:  # otherwise, put it in the root of the dict
            metadata_dict[parts.group("key")] = parts.group("value")

    return metadata_dict

这似乎现在为我带来了良好的结果,并且不需要额外的安装。这些按键似乎因视频和视频类型而异,因此您需要进行一些检查,而不仅仅是假设存在任何特定的按键。此代码是为 Python 3 编写的,并且使用hachoir3 http://hachoir3.readthedocs.io并改编自hachoir3 文档 http://hachoir3.readthedocs.io/developer.html#hachoir-metadata-example- 我还没有研究过它是否适用于 Python 2 的 hach​​oir。

如果它有用,我还可以将基于文本的持续时间值转换为秒:

def length(duration_value):

    time_split = re.match("(?P<hours>\d+\shrs)?\s*(?P<minutes>\d+\smin)?\s*(?P<seconds>\d+\ssec)?\s*(?P<ms>\d+\sms)", duration_value)  # get the individual time components

    fields_and_multipliers = {  # multipliers to convert each value to seconds
        "hours": 3600,
        "minutes": 60,
        "seconds": 1,
        "ms": 1
    }

    total_time = 0
    for group in fields_and_multipliers:  # iterate through each portion of time, multiply until it's in seconds and add to total
        if time_split.group(group) is not None:  # not all groups will be defined for all videos (eg: "hrs" may be missing)
            total_time += float(time_split.group(group).split(" ")[0]) * fields_and_multipliers[group]  # get the number from the match and multiply it to make seconds


    return total_time
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用Python获取视频属性,无需调用外部软件 的相关文章

  • 在Python中不断寻找用户输入

    我将如何编写一个始终寻找用户输入的 Python 程序 我想我希望有一个等于输入的变量 然后根据该变量的等于值会发生不同的情况 因此 如果变量是 w 那么它将执行某个命令并继续执行 直到收到另一个输入 例如 d 然后会发生不同的情况 但直到
  • Pygame 让精灵按照给定的旋转行走

    很久以前我做了一个Scratch脚本 我想用Pygame将其转换为Python 有很多示例显示图像的旋转 但我想知道如何更改精灵的旋转以使其沿给定方向移动 而不更改图像 这是我的暂存代码 这是我的 Pygame 精灵类 class Star
  • 如何仅选择数组中的第一列并对其求和?

    这是我的代码 import numpy as np contrainte1 1080 0 65 minutes tous les jours contrainte2 720 0 55 minutes du lundi au vendredi
  • 录制视频和音频并上传到服务器

    我想为网站添加视频录制功能 我一直在搜索并尝试所有可能的可用解决方案 但还没有任何工作正常 我已经尝试过以下解决方案 WebRTC 我知道使用 WebRTC 我们可以从网络摄像头和麦克风获取流 我发现了很多关于相同内容的文章 但没有一篇解释
  • python blpapi安装错误

    我试图根据 README 中的说明为 python 安装 blpapi 3 5 5 但是在运行时 python setup py install 我收到以下错误 running install running build running b
  • 使用 Unity3D 解决 PnP

    我有一个真实 物理的棍子 上面连接有红外摄像头和一些红外 LED 它们形成了我正在使用的模式 以便使虚拟棍子以与物理棍子相同的方式移动 为此 我在 Python 中使用 OpenCV 并将由solvePnP 计算的旋转和平移向量发送到 Un
  • 如何使用 python http.server 运行 CGI“hello world”

    我使用的是 Windows 7 和 Python 3 4 3 我想在浏览器中运行这个简单的 helloworld py 文件 print Content Type text html print print print print h2 H
  • 更改 numpy 数组的结构强制给定值

    如何缩小栅格数据的比例4 X 6大小成2 X 3如果 2 2 像素内的任何元素包含 1 则大小强制选择 1 否则选择 0 import numpy as np data np array 0 0 1 1 0 0 1 0 0 1 0 0 1
  • 从 Spark 数据帧中过滤大量 ID

    我有一个大型数据框 其格式类似于 ID Cat date 12 A 201602 14 B 201601 19 A 201608 12 F 201605 11 G 201603 我需要根据大约 500 万个 Is 的列表来过滤行 最直接的方
  • 监控培训课程如何运作?

    我试图理解使用之间的区别tf Session and tf train MonitoredTrainingSession 以及我可能更喜欢其中之一 似乎当我使用后者时 我可以避免许多 杂务 例如初始化变量 启动队列运行程序或设置文件编写器以
  • Scapy:如何将新层(802.1q)插入现有数据包?

    我有一个数据包转储 想要将 VLAN 标记 802 1q 标头 注入到数据包中 怎么做 为了找到答案 我查看了Scapy 插入新层和记录问题 https stackoverflow com q 17259592 1381638 这确实很有帮
  • telethon 库:如何通过电话号码添加用户

    我正在研究 Telegram 的 Telethon 库 它可以使用 Telegram API 充当 Telegram 客户端 重要提示 这是电报客户端 API https core telegram org telegram api 而不是
  • 在 Qt 5 中嵌入 Python

    我想将 Python 解释器嵌入到 Qt 5 应用程序中 我在 Qt 5 中有一个工作应用程序 但是当我把 include
  • Django - 使 ModelForm(ImageField 的)仅接受某些类型的图像

    我将 Pillow 2 3 0 与 Django 一起使用 并且在 models py 中有一个 ImageField 如下所示 class UserImages models Model user models ForeignKey Us
  • 如何在自定义 django 命令中抽象出命令代码

    我正在我的应用程序下编写自定义 django 命令management commands目录 目前我在该目录中有 6 个不同的文件 每个文件都有不同的命令来解决独特的需求 然而 有一些实用程序是它们所共有的 抽象出这些公共代码的最佳方法是什
  • Django:显示管理员验证错误的自定义错误消息

    我正在使用 Django 1 2 4 我有一个模型 其中有一个需要验证的字段 当验证失败时 我想向用户显示自定义错误消息 模型编辑是在管理界面中完成的 这就是我目前正在做的事情 def clean fields self exclude N
  • 重写 PyGObject 中的虚拟方法

    我正在尝试实施高宽几何管理 http developer gnome org gtk3 3 2 GtkWidget html geometry management在 GTK 和 Python 中用于我的自定义小部件 我的小部件是来自的子类
  • scikit-learn kmeans 聚类的初始质心

    如果我已经有一个可以作为初始质心的 numpy 数组 我该如何正确初始化 kmeans 算法 我正在使用 scikit learn Kmeans 类 这个帖子 具有选定初始中心的 k 均值 https stackoverflow com q
  • AES 在 cryptojs 中加密并在 python Crypto.Cipher 中解密

    使用 js CryptoJS 加密并使用 python crypto Cipher 解密时出现问题 这是我在js中的实现 附加 iv 与加密消息并使用 base64 进行编码
  • Pandas 2 个字段中唯一值的数量

    我正在尝试查找覆盖 2 个字段的唯一值的数量 例如 一个典型的例子是姓氏和名字 我有一个数据框 当我执行以下操作时 我只获取每列的唯一字段数 在本例中为 最后一个 和 第一个 不是复合体 df Last Name First Name nu

随机推荐

  • ‘php.exe’不被识别为内部或外部命令、可运行程序或批处理文件

    php exe 不被识别为内部或外部命令 可运行的程序或批处理文件 即使我已将 PHP 添加到环境变量中 为什么仍会出现该错误 我的环境变量PATH如下所示 C Program Files NVIDIA Corporation PhysX
  • 如何在8086汇编中减去两个64位整数

    编写一个名为 SUB64 的程序 用 0x0160 和 0x0164 中的 64 位整数减去内存位置 0x0150 和 0x0154 中的 64 位整数 将结果存储在内存位置 0x0170 和 0x0174 中 我理解将其分成更小的部分背后
  • python re.findall() 与交替的子字符串

    如果我在正则表达式交替中有另一个字符串或模式的子字符串 或 子模式 如下所示 r abcd bc 预期的行为是什么re compile r abcd bc findall abcd bcd bc ab 尝试一下 我得到了 正如预期的那样 a
  • 使用 Square Connect API 访问客户信息

    是否可以使用 Square Connect API 访问有关商家客户的任何信息 最理想的信息是客户输入的收据电子邮件地址 但某种类型的唯一客户 ID 可以很好地确定回头客 纵观整个Square Connect API 文档 https co
  • 为什么通过提取方法进行重构会触发借用检查器错误?

    我的网络应用程序的架构可以简化为以下内容 use std collections HashMap Represents remote user Usually has fields but we omit them for the sake
  • UIStackview 左对齐

    我试图将 UIStackview 中的项目水平向左对齐 有没有办法以编程方式执行此操作 我尝试通过故事板来做到这一点 但没有成功 由于某种原因 UIStackView 中的项目会自行居中 如果您使用 StackView 将 axis 属性设
  • ASP.Net 应用程序作为 IIS_USR 执行 powershell 脚本

    我正在构建一个 asp net mvc 应用程序 它将作为我们编写的许多 powershell 脚本的包装器来运行 以管理日常任务 最终目标是让非技术人员轻松使用这些脚本 我已经设法让脚本很好地执行 var ctx System Web H
  • 用C++实现二阶低通滤波器,如何计算系数?

    我正在努力寻找合适的算法来生成低通滤波器的系数 我写了以下内容butterworthLowPass代码来自another https stackoverflow com a 20932062 2612235那么问题 class Filter
  • DialogFragment 已触发,但未显示导航架构组件中的布局

    在我的一个应用程序中 我使用 Android 导航架构组件 一切都很顺利 但当我想导航到 DialogFrgment 时 我陷入了困境 虽然触发了DialogFragment 但没有看到布局 只能看到重叠模糊背景 无法弄清楚实际问题 这是我
  • 如何使用 nvm-windows 同时运行两个不同的节点版本?

    问题 我们需要在两个不同的应用程序上同时运行和使用两个不同的节点版本 即 14 12 以支持使用 npm run dev npm install具有相应定义版本的命令 到目前为止我们尝试过的步骤 Created nvmrc每个应用程序上定义
  • 有关从一台设备到另一台设备的 Android 内核移植的指南

    我拥有一台 Samsung Galaxy 3 并且想要移植可用于其他 Android 设备的内核 我已经准备好了所有的建筑环境 我也有C知识 我到底不明白的是移植涉及什么以及如何以及什么 哪些代码应该以什么方式修改 如果有人可以帮助我 这会
  • 对象不继承原型函数

    我有一个构造函数 它充当超类 Bla function a this a a 我将其原型化为包含一个简单的方法 Bla prototype f function console log f 现在新的Bla 1 f 将在控制台中记录 f 但是
  • Pytorch 无法将训练好的模型导出为 ONNX

    我一直在使用多个卷积层 3x3 步长 1 填充相同 在 Pytorch 框架中训练模型 该模型表现良好 我想在 Matlab 中使用它进行推理 为此 框架之间的 NN 交换的 ONNX 格式似乎是 唯一的 解决方案 可以使用以下命令导出模型
  • 使用什么机器实例在 Google Cloud Platform 中运行 GPU 工作负载 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我正在尝试运行 Elasticsearch BERT 应用程序 并想了解使用 GPU 微调模型的最小配置 我应该使用什么机器配置 参考githu
  • C++ 操作符删除失败,如果不能,为什么?

    在内存解除分配期间 操作符删除是否可以抛出异常或以其他方式发出错误信号 以其他方式是否有可能operator delete失败 在这种情况下它的默认行为是什么 ISO 标准对此有何规定 例如在 Windows 操作系统中 C operato
  • SASS:生成的 CSS 不是最佳的

    我正在努力学习SASS 我让这个代码片段工作了 但在我看来生成的 css 很糟糕 我希望所有这些 css 都放在同一个 container 中 没有三个不同 如下所示 SASS container extend clearfix exten
  • 如何检查 json 中的所有键是否都等于 true

    如何检查 json 对象中的所有键是否都等于 true 我的对象看起来像这样 success first name false middle name false last name false d o b false sex false
  • ansible、命令模块和带管道的 jq

    我正在尝试运行一个返回容器列表及其大小的 docker 命令 命令是docker container ls format name Names size Size all jq slurp 当我尝试在 Ansible 剧本中运行它时 它会爆
  • SSIS 导入 Excel 日期时出错(截断错误)

    我很抱歉发布了一个看似非常简单的问题 但我找不到答案 而且我浪费了几天 此时不仅仅是几个小时 我对 SSIS 还很陌生 它只是让我感到不舒服 背景 非常简单的 SSIS 包 用于将 Excel 工作表导入 SQL Server 中的临时表
  • 使用Python获取视频属性,无需调用外部软件

    更新 是的 有可能 现在大约 20 个月后了 请参阅下面的更新3 更新 这真的不可能吗 我能找到的只是调用 FFmpeg 或其他软件 的变体 我当前的解决方案如下所示 但我真正想要的可移植性是一个仅 Python 的解决方案 不需要用户安装