ios的Safari浏览器下视频播放问题

ios的Safari浏览器下视频播放问题

起因

最近在做手机端接口对接,后端使用java,前端使用vue开发,在提供给前端视频接口时出现了个问题:

视频在安卓上可以播放,在ios的Safari浏览器就是不能播放;

原因:
  1. 在安卓上,请求一个视频链接,返回一整个视频文件。
  2. 对于ios来说,他不是一次性请求全部文件的,一般首先会请求0-1字节,这个写在request header的"range"字段中:range:‘bytes=0-1’

如果想要传输视频,必须要解析range字段,然后按照range字段的要求返回对应的数据,同时response header至少要包含三个字段:“Content-Type”, “Content-Range”, “Content-Length”
Content-Type"必需明确指定视频格式,有"video/mp4”, “video/ogg”, "video/mov"等等。
"Content-Range"格式是 “bytes -/”,其中start和end必需对应request header里的range字段,total是文件总大小,不是返回的数据长度
"Content-Length"指定返回的二进制长度

解决方案:

解决方案: 后端根据视频请求流字节进行拆分返回,不要直接返回一个整个视频

示例代码

下面代码主要显示mp4格式

import cn.hutool.core.io.FileUtil;

    @GetMapping("/video/{pictureId:.+}")
    public void renderVideo(@PathVariable("pictureId") String pictureId, HttpServletResponse response,HttpServletRequest request) {
        try {
            //根据id 获取文件信息
            DwzdFileInfo dwzdFileInfo = dwzdFileInfoService.get(pictureId);
            //获取文件真实路径
            String filePath = dwzdFileInfo.getFilePath();
            File file = FileUtil.file(filePath);
            //只读模式
            RandomAccessFile randomFile = new RandomAccessFile(file, "r");
            long contentLength = randomFile.length();
            String range = request.getHeader("Range");
            int start = 0, end = 0;
            if(range != null && range.startsWith("bytes=")){
                String[] values = range.split("=")[1].split("-");
                start = Integer.parseInt(values[0]);
                if(values.length > 1){
                    end = Integer.parseInt(values[1]);
                }
            }
            int requestSize = 0;
            if(end != 0 && end > start){
                requestSize = end - start + 1;
            } else {
                requestSize = Integer.MAX_VALUE;
            }

            byte[] buffer = new byte[4096];
            response.setContentType("video/mp4");
            response.setHeader("Accept-Ranges", "bytes");
            response.setHeader("ETag", dwzdFileInfo.getFileName());
            response.setHeader("Last-Modified", new Date().toString());
            //第一次请求只返回content length来让客户端请求多次实际数据
            if(range == null){
                response.setHeader("Content-length", contentLength + "");
            }else{
                //以后的多次以断点续传的方式来返回视频数据  //206
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                long requestStart = 0, requestEnd = 0;
                String[] ranges = range.split("=");
                if(ranges.length > 1){
                    String[] rangeDatas = ranges[1].split("-");
                    requestStart = Integer.parseInt(rangeDatas[0]);
                    if(rangeDatas.length > 1){
                        requestEnd = Integer.parseInt(rangeDatas[1]);
                    }
                }
                long length = 0;
                if(requestEnd > 0){
                    length = requestEnd - requestStart + 1;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
                }else{
                    length = contentLength - requestStart;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range", "bytes "+ requestStart + "-" + (contentLength - 1) + "/" + contentLength);
                }
            }
            ServletOutputStream out = response.getOutputStream();
            int needSize = requestSize;
            randomFile.seek(start);
            while(needSize > 0){
                int len = randomFile.read(buffer);
                if(needSize < buffer.length){
                    out.write(buffer, 0, needSize);
                } else {
                    out.write(buffer, 0, len);
                    if(len < buffer.length){
                        break;
                    }
                }
                needSize -= buffer.length;
            }
            randomFile.close();
            out.close();
        } catch (Exception e) {
            //如果找不到图片就返回一个默认图片
            try {
                String path404 = request.getSession().getServletContext().getRealPath("/static/404.png");
                byte[] bytes = FileUtil.readBytes(path404);
                response.getOutputStream().write(bytes);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

参考链接:
https://blog.csdn.net/qq_27800521/article/details/88247301

https://blog.csdn.net/zhengbin6072/article/details/78235004

https://blog.csdn.net/bangbDIV/article/details/81912892

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值