You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python Requests stream=True结合管道获取远程视频时长失败求助

解决远程MP4视频时长获取问题(无需全量下载)

问题背景

已实现三个本地视频时长获取函数(size_from_fn、size_from_fd、size_from_data),均能正常工作;使用requests.get(url, stream=True)获取req.raw并传入size_from_fd时,ffprobe报错:Invalid data found when processing input。测试确认ffprobe不依赖seek操作,全量下载视频后处理可成功,但大视频无法接受全量下载,需寻求高效解决方案。

解决方案思路

核心问题在于远程流的req.raw未提供ffprobe解析所需的完整MP4头部元数据(尤其是存储时长信息的moov原子),且HTTP流的传输特性导致ffprobe无法正确读取足够的初始数据。我们可以通过HTTP范围请求仅下载MP4的头部区域(通常前4MB足够包含关键元数据),再传给ffprobe解析,无需全量下载。

修正后的代码

1. 修正size_from_data函数的参数笔误

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(data):
    # 修正参数名:原参数file_name改为data
    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

2. 实现范围请求获取视频头部数据

import requests as rq

def get_remote_video_head(url, head_size=4*1024*1024):
    # 发送HTTP范围请求,仅获取前head_size字节的头部数据
    headers = {'Range': f'bytes=0-{head_size-1}'}
    req = rq.get(url, headers=headers, stream=True)
    # 若服务器不支持范围请求,退回到普通流模式
    if req.status_code != 206:
        req = rq.get(url, stream=True)
    return req.raw

3. 远程视频时长获取主函数

def get_remote_duration(url):
    try:
        # 先尝试用头部数据解析
        video_head_fd = get_remote_video_head(url)
        return size_from_fd(video_head_fd)
    except Exception as e:
        # 头部解析失败时,兜底使用全量下载
        complete_data = rq.get(url).content
        return size_from_data(complete_data)

补充说明

  • 部分流媒体MP4会将moov原子放在文件末尾,此时前4MB可能不包含元数据,这时候代码会自动触发全量下载兜底。
  • 可根据实际场景调整head_size的大小,比如调整为8MB,提升对特殊MP4文件的兼容性。

内容的提问来源于stack exchange,提问作者Rainbobow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:28:15