V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Triump
V2EX  ›  程序员

Java 实现大文件(视频)的高效下载,并让前端播放,有什么思路吗?

  •  
  •   Triump · 2023-02-16 11:12:57 +08:00 · 4999 次点击
    这是一个创建于 638 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求背景:

    要在网页上播放视频,视频是存储在文件系统( minIO )上,现在的做法是,前端请求后台的文件下载接口,将整个文件下载后返回给前端进行播放。但是这个视频大概有 140M ,整个过程耗时大概 1 分钟了。用户体验很差。

    我的思路:

    后端提供一个支持文件分片下载的方法,前端通过请求头设置 Range 参数传入指定的范围。比如一个 100M 的文件,每次请求 10M, 但是我不确定前端拿到这 10M 文件后,是否能够播放。。。 如果这个思路可行的话,前端需要用到哪些技术呢?

    有没有大佬能够提供一下思路啊?

    38 条回复    2023-02-17 17:52:00 +08:00
    fiveStarLaoliang
        1
    fiveStarLaoliang  
       2023-02-16 11:17:00 +08:00
    走 nginx 转发不就行了,顶多加个鉴权,不需要自己去写切片播放
    weixiaoyun
        2
    weixiaoyun  
       2023-02-16 11:17:04 +08:00
    不用下载,minio 支持视频拉流的,给个视频预览源地址给前端播放器调用就好了
    Triump
        3
    Triump  
    OP
       2023-02-16 11:22:35 +08:00
    @weixiaoyun 就是让前端直接去访问 minio 吗?这样的话要把 桶的权限设置为公开,会不会很危险,因为这个项目要支持外网访问的。
    tool2d
        4
    tool2d  
       2023-02-16 11:28:39 +08:00
    "但是我不确定前端拿到这 10M 文件后,是否能够播放"

    本来就无法确定。

    MP4 有两种格式,头格式和尾格式。头格式把具体播放信息都放在头部,可以流式播放。尾格式是把详细信息都放在文件末尾,你比如下载视频 BT ,必须把整个文件拖下来后,才能播放。

    当然有工具可以在这两种格式之间切换。
    MoonWalker
        5
    MoonWalker  
       2023-02-16 11:29:48 +08:00
    返回 206 状态码然后按 Range 解析字节范围就好了吧?
    MoYi123
        6
    MoYi123  
       2023-02-16 11:30:10 +08:00
    @Triump 用 presignedGetObjectUrl
    registerrr
        7
    registerrr  
       2023-02-16 11:31:00 +08:00
    @Triump
    不用,把桶权限设置成 download (共有读私有写)就行了

    返回视频流时候你有业务要处理么?没有就是直接访问啊,前端只写个 video 标签都可以了
    registerrr
        8
    registerrr  
       2023-02-16 11:34:28 +08:00
    要是访问也需要授权就用 6#的这个方法
    duckyrain
        9
    duckyrain  
       2023-02-16 11:35:29 +08:00
    走公有云 CDN ?
    边下边播是视频格式决定的,和下载服务没关系。
    Triump
        10
    Triump  
    OP
       2023-02-16 11:37:26 +08:00
    @MoonWalker 我现在的思路就是这样,和前端小哥沟通了一下,他还不知道这种方式要怎么处理,所以不知道前端能不能去这个实现。
    Triump
        11
    Triump  
    OP
       2023-02-16 11:38:41 +08:00
    @registerrr 感谢,这个思路也可以。
    okakuyang
        12
    okakuyang  
       2023-02-16 11:59:15 +08:00
    边下边播要 Range 支持,不然苹果系可能播放不了。
    niushuai
        13
    niushuai  
       2023-02-16 13:31:03 +08:00
    还是做切片比较合适
    rqxiao
        14
    rqxiao  
       2023-02-16 13:39:41 +08:00
    m3u8 文件
    opengg
        15
    opengg  
       2023-02-16 13:44:47 +08:00
    luob
        16
    luob  
       2023-02-16 13:46:17 +08:00
    后端调用 ffmpeg 切成 dash ,然后前端直接 plyr 播放器,都是成熟方案不用自己写什么
    luob
        17
    luob  
       2023-02-16 13:48:16 +08:00   ❤️ 1
    唯一缺点是担心客户看到 plyr 播放器的界面会不有什么奇怪的反应(
    spike76
        18
    spike76  
       2023-02-16 13:50:43 +08:00
    用 ffmpeg 将 mp4 转成流格式
    ffmpeg -i #{video_path} -codec: copy -start_number 0 -hls_time 16 -hls_list_size 0 -f hls #{hls_index_path}
    每个小块文件只有 16 秒内容,前端下载应该足够快了
    wxd21020
        19
    wxd21020  
       2023-02-16 13:53:35 +08:00
    学习学习,看大佬们有啥解决方案
    cheng6563
        20
    cheng6563  
       2023-02-16 14:16:33 +08:00
    前端播放很难说的,你别看这些文件都是.mp4 ,其实内部差异大得很。
    有必要的话还是要上 ffmpeg 重新封包(不是转码)
    mmdsun
        21
    mmdsun  
       2023-02-16 14:32:46 +08:00
    你是不是用 Java 先 download 文件,然后再 Response 写返回给页面的?
    你应该用 gateway 代理直接转发给页面,这样后端你就需要先下载了
    mmdsun
        22
    mmdsun  
       2023-02-16 14:37:17 +08:00
    var file = downloadFile("http://xxxxxxxxxx");
    Response.write(file);

    上面这种换成:

    /gateway/download/xxxxxxxxxx => http://file.download/xxxxxxxxxx

    要是云存储那边要鉴权加什么请求头的,你网关直接给加上就好。
    zzl22100048
        23
    zzl22100048  
       2023-02-16 15:11:35 +08:00
    能用 m3u8 是最好
    最省事就 presignedGetObjectUrl 期限设置一天
    mouyong
        24
    mouyong  
       2023-02-16 15:20:14 +08:00
    我有解决方案,可付费提供,见下方图。本地大文件视频在线播放。
    1. 大文件视频在线播放不卡顿
    2. 大文件视频本地存储,不用担心昂贵的云存储费用

    mouyong
        25
    mouyong  
       2023-02-16 15:22:39 +08:00
    在线预览与管理管理本地文件、视频。

    renmu
        26
    renmu  
       2023-02-16 15:23:38 +08:00 via Android
    走 m3u8 ,很成熟了
    qfdk
        27
    qfdk  
       2023-02-16 15:24:31 +08:00
    m3u8 吧 多简单 流方案.
    m3u8 视频格式原理:将完整的视频拆分成多个.ts 视频碎片,.m3u8 文件详细记录每个视频片段的地址。 视频播放时,会先读取.m3u8 文件,再逐个下载播放.ts 视频片段
    HTML001
        28
    HTML001  
       2023-02-16 17:16:25 +08:00
    后端将视频转 m3u8, 前端用 hls.js 或者 video.js 播放应该就可以满足
    wqhui
        29
    wqhui  
       2023-02-16 17:31:26 +08:00
    m3u8 ,大的在线视频网站都这样玩
    HtPM
        30
    HtPM  
       2023-02-16 18:00:02 +08:00
    #16 楼是正规方案,现在基本上都是用 MPEG-DASH 方案,Youtube 采用的这种
    123zouwen
        31
    123zouwen  
       2023-02-16 19:04:53 +08:00
    前段时间刚做了类似需求, 简单做法就是后端返回给前端 mp4 的视频链接(如果桶不是 public 的话, 后端调用 minio 生成一个临时访问链接), 前端拿到链接即可播放视频, 快进等功能正常
    xylxAdai
        32
    xylxAdai  
       2023-02-16 19:10:09 +08:00
    m3u8 啊。切成流格式,直接播放。
    q1angch0u
        33
    q1angch0u  
       2023-02-17 00:24:03 +08:00
    转 dash + 1
    q1angch0u
        34
    q1angch0u  
       2023-02-17 00:24:16 +08:00
    @q1angch0u 转完存一下,下次接着播
    cephei
        35
    cephei  
       2023-02-17 10:49:38 +08:00
    可以在后台做一层代理,把前端的 Http Range 请求转发到 MinIO
    Sum0l
        36
    Sum0l  
       2023-02-17 13:25:32 +08:00
    推荐一个 java 版的 ffmpeg https://github.com/bytedeco/javacv
    dudubaba
        37
    dudubaba  
       2023-02-17 14:53:08 +08:00
    好像除了直接访问,没有一劳永逸的方法,得后端改造一下。
    lbunderway
        38
    lbunderway  
       2023-02-17 17:52:00 +08:00
    ffmpeg 这个靠谱
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5302 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 53ms · UTC 07:18 · PVG 15:18 · LAX 23:18 · JFK 02:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.