- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
[更新:] 是的,有可能,现在大约 20 个月后。请参阅下面的 Update3! [/更新]
这真的不可能吗?我所能找到的只是调用 FFmpeg(或其他软件)的变体。我当前的解决方案如下所示,但为了可移植性,我真正想要的是一个不需要用户安装额外软件的纯 Python 解决方案。
毕竟,我可以使用 PyQt 的 Phonon 轻松播放视频,但我无法简单地获取视频的尺寸或持续时间等信息?
我的解决方案使用 ffmpy ( http://ffmpy.readthedocs.io/en/latest/ffmpy.html ),它是 FFmpeg 和 FFprobe ( 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
更新 经过几天的实验:下面 Nick 提出的 hachoire 解决方案确实有效,但会让您很头疼,因为 hachoire 的 react 太不可预测了。不是我的选择。
使用 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)。
除此之外,opencv 似乎需要在运行时存在 FFmeg 的二进制包(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)
更新 3: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-image 读入 Qt-image:
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/
最佳答案
好的,在我自己调查之后因为我也需要它,看起来可以用 hachoir
来完成。这是一个代码片段,可以为您提供 hachoir 可以阅读的所有元数据:
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
这似乎立即为我返回了良好的结果,并且不需要额外的安装。 key 似乎因视频和视频类型而异,因此您需要进行一些检查,而不是假设任何特定的 key 都在那里。此代码是为 Python 3 编写的,使用的是 hachoir3改编自 hachoir3 documentation - 我还没有调查它是否适用于 Python 2 的 hachoir。
如果它有用,我还有以下用于将基于文本的持续时间值转换为秒的方法:
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
关于python - 使用 Python 获取视频属性而不调用外部软件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47454317/
为了让我的代码几乎完全用 Jquery 编写,我想用 Jquery 重写 AJAX 调用。 这是从网页到 Tomcat servlet 的调用。 我目前情况的类似代码: var http = new
我想使用 JNI 从 Java 调用 C 函数。在 C 函数中,我想创建一个 JVM 并调用一些 Java 对象。当我尝试创建 JVM 时,JNI_CreateJavaVM 返回 -1。 所以,我想知
环顾四周,我发现从 HTML 调用 Javascript 函数的最佳方法是将函数本身放在 HTML 中,而不是外部 Javascript 文件。所以我一直在网上四处寻找,找到了一些简短的教程,我可以根
我有这个组件: import {Component} from 'angular2/core'; import {UserServices} from '../services/UserService
我正在尝试用 C 实现一个简单的 OpenSSL 客户端/服务器模型,并且对 BIO_* 调用的使用感到好奇,与原始 SSL_* 调用相比,它允许一些不错的功能。 我对此比较陌生,所以我可能会完全错误
我正在处理有关异步调用的难题: 一个 JQuery 函数在用户点击时执行,然后调用一个 php 文件来检查用户输入是否与数据库中已有的信息重叠。如果是这样,则应提示用户确认是否要继续或取消,如果他单击
我有以下类(class)。 public Task { public static Task getInstance(String taskName) { return new
嘿,我正在构建一个小游戏,我正在通过制作一个数字 vector 来创建关卡,该数字 vector 通过枚举与 1-4 种颜色相关联。问题是循环(在 Simon::loadChallenge 中)我将颜
我有一个java spring boot api(数据接收器),客户端调用它来保存一些数据。一旦我完成了数据的持久化,我想进行另一个 api 调用(应该处理持久化的数据 - 数据聚合器),它应该自行异
首先,这涉及桌面应用程序而不是 ASP .Net 应用程序。 我已经为我的项目添加了一个 Web 引用,并构建了各种数据对象,例如 PayerInfo、Address 和 CreditCard。但问题
我如何告诉 FAKE 编译 .fs文件使用 fsc ? 解释如何传递参数的奖励积分,如 -a和 -target:dll . 编辑:我应该澄清一下,我正在尝试在没有 MSBuild/xbuild/.sl
我使用下划线模板配置了一个简单的主干模型和 View 。两个单独的 API 使用完全相同的配置。 API 1 按预期工作。 要重现该问题,请注释掉 API 1 的 URL,并取消注释 API 2 的
我不确定什么是更好的做法或更现实的做法。我希望从头开始创建目录系统,但不确定最佳方法是什么。 我想我在需要显示信息时使用对象,例如 info.php?id=100。有这样的代码用于显示 Game.cl
from datetime import timedelta class A: def __abs__(self): return -self class B1(A):
我在操作此生命游戏示例代码中的数组时遇到问题。 情况: “生命游戏”是约翰·康威发明的一种细胞自动化技术。它由一个细胞网格组成,这些细胞可以根据数学规则生存/死亡/繁殖。该网格中的活细胞和死细胞通过
如果我像这样调用 read() 来读取文件: unsigned char buf[512]; memset(buf, 0, sizeof(unsigned char) * 512); int fd;
我用 C 编写了一个简单的服务器,并希望调用它的功能与调用其他 C 守护程序的功能相同(例如使用 ./ftpd start 调用它并使用 ./ftpd stop 关闭该实例)。显然我遇到的问题是我不知
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
我希望能够从 cmd 在我的 Windows 10 计算机上调用 python3。 我已重新安装 Python3.7 以确保选择“添加到路径”选项,但仍无法调用 python3 并使 CMD 启动 P
我是一名优秀的程序员,十分优秀!