zoukankan      html  css  js  c++  java
  • Re:从零开始学流媒体(一):视频跳转、206、chunked、动态URL、断点续传

    一、静态路由视频播放

    首先,不考虑用最新的技术,不考虑m3u8,用最传统的方式,如何实现页面播放视频?

    最简单的是直接引用资源路径。

    Demo如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link href="https://vjs.zencdn.net/7.5.4/video-js.css" rel="stylesheet">
    </head>
    <body>
    <video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" width="640" height="264"
           poster="http://vjs.zencdn.net/v/oceans.png">
    <!--    <source src="/frag_bunny.mp4" type="video/mp4">-->
        <source src="/getMovie" type="video/mp4">
    
    </video>
    </body>
    </html>
    <script src='https://vjs.zencdn.net/7.5.4/video.js'></script>
    <script type="text/javascript">
        var player1 = videojs('example_video_1');
        player1.play();
    </script>

    其中src填入的是你项目静态资源路由根目录.

    二、动态URL播放视频

    由于不是所有资源都在静态路由的,资源可能是云存储,可能是其他文件路径。

    使用静态路由,太不方便,nginx可以映射到其他位置。

    但考虑到权限、云存储等问题。动态路由很有必要。

    如何实现动态路由?

    看上去很简单,我只需要设置HttpResponse的表头setContentType、 FileInputStream填入文件,用OutputStream读取文件就可以了

    网上有很多例子。

    但是这样做有个弊端:按顺序读取文件。也就是视频你无法跳转播放!他只能按顺序缓冲。

    为什么使用动态URL无法跳转视频,静态URL却可以跳转播放?

    这就涉及到了Http协议的问题了。

    通过对比静态Url和动态Url的HttpResponse,我们知道:

    如果是动态路由,默认的传输方式是Transfer-Encoding为chunked,成功类型为200,这样的方式是无法支持视频跳转和断点续传等功能的。

    所以我们需要手动修改返回类型和请求头。

    我们只需要设置Content-Length和Content-Range,并设置状态为206,之后Transfer-Encoding:chunked就会自动被取消掉(需要注意的一个细节,设置Content-Length和Content-Range必须要在inputStream执行之前)

    而Range需要根据HttpRequest来具体的数字处理和拼接。

    服务器端代码如下:

    @ResponseBody
        @RequestMapping("getMovie")
        public void getMovie(HttpServletRequest request, HttpServletResponse response) throws IOException {
            String path = "/Users/Desktop/movie/aaa.mp4";
            response.setContentType("video/mp4");
            response.setHeader("Accept-Ranges", "bytes");
            response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
    
            long fSize=new File(path).length();
    
            long pos = 0, last = fSize - 1, sum = 0;//pos开始读取位置;  last最后读取位置;  sum记录总共已经读取了多少字节
            if (null != request.getHeader("Range")) {
             response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                try {
                    String numRang = request.getHeader("Range").replaceAll("bytes=", "");
                    String[] strRange = numRang.split("-");
                    if (strRange.length == 2) {
                        pos = Long.parseLong(strRange[0].trim());
                        last = Long.parseLong(strRange[1].trim());
                    } else {
                        pos = Long.parseLong(numRang.replaceAll("-", "").trim());
                    }
                } catch (NumberFormatException e) {
                    pos = 0;
                }
            }
            long rangLength = last - pos + 1;// 总共需要读取的字节
    
            response.setHeader("Content-Range", "bytes " + pos + "-" + last + "/" + fSize);
            response.setHeader("Content-Length", String.valueOf(rangLength));
    
            FileInputStream in = new FileInputStream(new File(path));
            in.skip(pos);
            OutputStream out = response.getOutputStream();
    
            byte[] b = new byte[512];
    
            int length = 0;
            while (sum < rangLength) {
                length = in.read(b, 0, ((rangLength - sum) <= b.length ? ((int) (rangLength - sum)) : b.length));
                sum = sum + length;
                out.write(b, 0, length);
            }
    
            out.flush();
            in.close();
            out.close();

    然后,就可以通过/getMovie来随意读取文件,可以实现跳转播放了。

  • 相关阅读:
    git技能
    iOS 命名规则
    iOS crash 报错类型
    iOS 面试相关
    【转】app后端如何选择合适的数据库产品
    App的token机制
    【转】Spring注解详解
    spring mvc ModelAndView 404的原因
    ibatis 环境搭建(1)
    Android中的Selector的用法
  • 原文地址:https://www.cnblogs.com/pghcx/p/15147729.html
Copyright © 2011-2022 走看看