我想知道远处视频文件(比如 mp4)的持续时间。
我已经知道如何获取本地视频文件的时长:
import xml.etree.ElementTree as eltt, subprocess as spr
def size_from_fn(file_name):
size = eltt.fromstring(
spr.run(["ffprobe",
"-i", file_name,
"-show_format", "-output_format", "xml"
], stdout = spr.PIPE, stderr = spr.STDOUT).stdout.decode()
).find("format").get("duration")
return size
def size_from_fd(file_descriptor):
size = eltt.fromstring(
spr.run(["ffprobe",
"-i", "pipe:0",
"-show_format", "-output_format", "xml"
], stdin = file_descriptor, stdout = spr.PIPE, stderr = spr.STDOUT).stdout.decode()
).find("format").get("duration")
return size
def size_from_data(file_name):
size = eltt.fromstring(
spr.run(["ffprobe",
"-i", "pipe:0",
"-show_format", "-output_format", "xml"
], input = data, stdout = spr.PIPE, stderr = spr.STDOUT).stdout.decode()
).find("format").get("duration")
return size
一切运行正常
我还知道如何将 HTTP 请求作为文件描述符获取:
import requests as rq
def url_to_fd(url):
req = rq.get(url, stream = True)
return req.raw
它也有效
然而,两者的结合失败,并显示以下消息ffprobe
:Invalid data found when processing input
我不知道为什么,我只知道从 URL 返回的文件描述符的区别在于不可搜索(单向读取),但是通过替换普通文件描述符的这种方法:
with open("test.mp4", "rb") as f:
f.seek = None
size_of_fd(f)
这是有效的,因此表明ffprobe
不需要任何寻求
这样做也是可行的,所以我不知道发生了什么:
def get_duration(url):
complete_data = url_to_fd(url).read()
return size_of_data(complete_data)
我的问题是视频文件可能非常大,所以我无法下载整个视频。
正如@tepalia 已经提到的,你可以
URL
直接使用ffprobe
我只补充一点,您还可以添加其他参数来直接获取持续时间
结果:
-v quiet
- 删除有关程序、库等的信息。-show_entries format=duration
- 仅显示持续时间[FORMAT]duration=596.474195[/FORMAT]
-output_format default=noprint_wrappers=1:nokey=1
- 删除包装器[FORMAT][/FORMAT]
和密钥duration=
如果您同时需要其他值(即
size
),那么您可以使用format=duration,size
并且每个值将在单独的行中还有
-hide_banner
类似的-v quiet
,只隐藏部分信息。(
-v
意味着-verbose
它也适用于其他值 - 即-v debug
)您可以在类似门户网站SuperUser或VideoProduction上找到更多信息
例如:ffmpeg - 如何获取视频时长(以秒为单位)? - 超级用户
还有ffprobe 文档