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

查看 96|回复 7
作者:KuAoaoaoao   
1.首先,介绍场景:视频播放平台,系统使用 Springboot 和 Vue 编写。拥有前台和后台,前台进行视频播放,后台进行视频的上传,也可以上传音乐和图片,功能顺手都做了。
2.问题:浏览器播放视频卡顿。视频卡顿问题需要攻克 2 关。
3.解决过程:
1 )第一关:视频文件太大,浏览器加载时间长。采用后端对文件分块读取。
场景:编写完成文件的上传与下载接口,在浏览器使用组件绑定 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 依赖
org.bytedeco
javacv-platform
1.5.3
代码:
/**
  • 修改视频分辨率
  • @param imagePath 原视频地址
  • @param outputDir 输出目录
  • @param width 宽度
  • @param height 高度
  • @param bitRate 码率
  • @return 视频地址
  • @throws Exception 异常
    /
    public static String modifyResolution(
    String imagePath, String outputDir, Integer width, Integer height, Integer bitRate)
    throws Exception {
    if (bitRate == null) {
    bitRate = 2000;
    }
    List paths = Splitter.on(".").splitToList(imagePath);
    String ext = paths.get(paths.size() - 1);
    if (!Arrays.asList("mp4").contains(ext)) {
    throw new Exception("format error");
    }
    String resultPath =
    Joiner.on(File.separator).join(Arrays.asList(outputDir, IdUtil.simpleUUID() + "." + ext));
    String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
    ProcessBuilder builder =
    new ProcessBuilder(
    ffmpeg,
    "-i",
    imagePath,
    "-s",
    MessageFormat.format("{0}{1}", String.valueOf(width), String.valueOf(height)),
    "-b",
    MessageFormat.format("{0}k", String.valueOf(bitRate)),
    resultPath);
    builder.inheritIO().start().waitFor();
    return resultPath;
    }

    视频, 浏览器, string, 播放

  • fengci   
    视频切片。m3u8 ,然后你就不需要做其他任何处理了。
    flyqie   
    @fengci #1
    是的,楼主这个需求可以转画质后通过 m3u8 实现。。。
    kiduu   
    判断一下视频时长,1 分钟以内的 MP4 直链,中长视频直接无脑切片就行。
    Elissa   
    要不试试用 cdn 顶上?感觉是服务器带宽不够
    chaoschick   
    如果使用 video 标签绑定 url 播放可以试试 videojs 这个库,但是这个有点问题就是视频不能过大 谷歌浏览器好像是不能超过 150MB
    JensenQian   
    直接 emby ,plex
    chaoschick   
    前端流式播放视频的技术 感觉还不太成熟,还没有统一,PC 端与安卓端现在大部分都是才用的不同技术,安卓那边一般是用 m3u8 ,PC 这边一般是 flv
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部