给女朋友做的视频播放平台,播放视频很卡,有几张方案解决

232 天前
 KuAoaoaoao

1.首先,介绍场景:视频播放平台,系统使用 Springboot 和 Vue 编写。拥有前台和后台,前台进行视频播放,后台进行视频的上传,也可以上传音乐和图片,功能顺手都做了。

2.问题:浏览器播放视频卡顿。视频卡顿问题需要攻克 2 关。

3.解决过程: 1 )第一关:视频文件太大,浏览器加载时间长。采用后端对文件分块读取。 场景:编写完成文件的上传与下载接口,在浏览器使用<video>组件绑定 url 进行观看视频。按照以上步骤,浏览器是能正常播放视频的,但是我把项目发布到服务器后,就出现另一个情况了。我发现浏览器会一直加载视频,浏览器中心呈现转圈动画,进度条会一点一点增长,但是没有画面出现。直到进度条加载完,才会出现画面。 原因:后端的下载接口是把整个视频文件一下子发送到浏览器,所以浏览器一直在接收文件,接收完文件后,浏览器的 video 组件才能进行播放。 解决:后端接口使用 randomAccessFile 类读取文件,这个类取到 file 的信息后,你便可以设置从文件的哪个位置开始读取,读取多少字节,然后把数据响应到浏览器。 这样就解决了浏览器一直加载视频的问题。例子代码在末尾。 2 )第二关:服务器带宽太低,视频下载赶不上视频播放,造成视频播放卡顿。采用 ffmpeg 组件进行画质压缩。 场景:假如有一个 30 秒 90M 的视频(我手机录的),上传到服务器了,然后在浏览器进行播放,那么播放视频就会卡顿了。 原因:因为服务器的带宽是 1M/s ,每秒能传送 1M 文件到浏览器,但是浏览器要想流畅播放那个视频,浏览器需要每秒接收 3M 文件,90M 的视频,30 秒,每秒需要播放 3M ,所以这就造成视频播放卡顿了。 解决:使用 ffmepg 组件,把 90M 的视频压缩到 30M ,可以压缩视频的比率和分辨率,最好进行相同比例的压缩,不然画质会变糊。

代码: 1 )第一关: /** * 斷點播放 * @param request * @param response * @throws IOException */ public void play(HttpServletRequest request, HttpServletResponse response) throws IOException{ response.reset(); File file = new File("本地的一個視頻地址"); long fileLength = file.length(); // 随机读文件 RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");

    //获取从那个字节开始读取文件
    String rangeString = request.getHeader("Range");
    long range=0;
    if (StrUtil.isNotBlank(rangeString)) {
        range = Long.valueOf(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
    }
    //获取响应的输出流
    OutputStream outputStream = response.getOutputStream();
    //设置内容类型
    response.setHeader("Content-Type", "video/mp4");
    //返回码需要为 206 ,代表只处理了部分请求,响应了部分数据
    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
    // 移动访问指针到指定位置
    randomAccessFile.seek(range);
    // 每次请求只返回 1MB 的视频流
    byte[] bytes = new byte[1024 * 1024];
    int len = randomAccessFile.read(bytes);
    //设置此次相应返回的数据长度
    response.setContentLength(len);
    //设置此次相应返回的数据范围
    response.setHeader("Content-Range", "bytes "+range+"-"+(fileLength-1)+"/"+fileLength);
    // 将这 1MB 的视频流响应给客户端
    outputStream.write(bytes, 0, len);
    outputStream.close();
    randomAccessFile.close();

// System.out.println("返回数据区间: ["+range+"-"+(range+len)+"] "); }

2 )第二关: ffmepg 依赖 <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.5.3</version> </dependency> 代码: /**

4268 次点击
所在节点    Java
48 条回复
fengci
232 天前
视频切片。m3u8 ,然后你就不需要做其他任何处理了。
flyqie
232 天前
@fengci #1

是的,楼主这个需求可以转画质后通过 m3u8 实现。。。
kiduu
232 天前
判断一下视频时长,1 分钟以内的 MP4 直链,中长视频直接无脑切片就行。
Elissa
232 天前
要不试试用 cdn 顶上?感觉是服务器带宽不够
chaoschick
232 天前
如果使用 video 标签绑定 url 播放可以试试 videojs 这个库,但是这个有点问题就是视频不能过大 谷歌浏览器好像是不能超过 150MB
JensenQian
232 天前
直接 emby ,plex
chaoschick
232 天前
前端流式播放视频的技术 感觉还不太成熟,还没有统一,PC 端与安卓端现在大部分都是才用的不同技术,安卓那边一般是用 m3u8 ,PC 这边一般是 flv
leaflxh
232 天前
b 站是转成 dash ,腾讯视频是 hls

不切片 1M 的小水管估计够呛,因为比如拖动进度条到第 60 秒,但上个关键帧是在第 30 秒,结果就是浏览器要从 30 秒的地方开始下载,这 30 秒的视频大小可能超过 10M ,这样就导致要等待 10 秒的时间才能开始播放第 60 秒的视频
KuAoaoaoao
232 天前
@Elissa cdn 加速应该可以 但是需要付费哦,商业项目可以加
KuAoaoaoao
232 天前
@chaoschick 如果只上传项目定位是只播放 150M 以下大小的视频 有机会试试
KuAoaoaoao
232 天前
@fengci 知识盲区了 我去学习一下
KuAoaoaoao
232 天前
@flyqie 我瞅瞅
KuAoaoaoao
232 天前
@JensenQian 知识盲区了 俺学习下
KuAoaoaoao
232 天前
@chaoschick 原来简简单单的文件下载 涉及到视频文件时便成了流式传输领域
KuAoaoaoao
232 天前
@leaflxh 醍醐灌顶
ltyj2003
232 天前
硬盘寄过去不好吗?
Maerd
232 天前
你和我当时犯的错误一样,就是把视频通过后端处理然后返回给前端,这个对服务的影响其实蛮大的。楼上的几个老哥也说复杂了,实际上视频无论是 mp4 还是 flv ,套一层 nginx ,把静态链接丢给前端就可以流式播放了,不需要手动处理。另外就是,视频这种的大静态文件最好不要直接丢在服务器上
Bingchunmoli
232 天前
直接对象存储 mp4 默认支持流式传输
herozzm
232 天前
文件太大,不应该要压缩一下吗?光切片没啥用
KuAoaoaoao
232 天前
@Maerd 需要考虑一下项目的定位,小项目小视频就放自己服务器。大项目可以采用 oss 提高用户体验。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/975960

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX