java 视频断点播放,实现无卡顿

背景:前端一般展示页面播放视频都是从头加载视频,这样会使用户体现很差,网速不好快进的话就会卡顿,加载太慢,为了 解决这一问题,后台给前端提供的接口需要实现断点下载的功能

@ApiOperation(value = "视频播放一方法", notes = "视频播放一方法")
    @GetMapping(value = "/preview")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "url", value = "文件路径", required = true,paramType = "query")
    })
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        // TODO Auto-generated method stub
        HttpServletRequest request=(HttpServletRequest)req;
        HttpServletResponse response=(HttpServletResponse)res;
        System.out.println(req.getParameter("url"));
        String path = addMinioUrl.getObPath(req.getParameter("url"));
        //String path="E:/video/111.mp4";
        RandomAccessFile targetFile = null;
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            response.reset();
            //获取请求头中Range的值
            String rangeString = request.getHeader(HttpHeaders.RANGE);

            //打开文件
            File file = new File(path);
            if (file.exists()) {
                //使用RandomAccessFile读取文件
                targetFile = new RandomAccessFile(file, "r");
                long fileLength = targetFile.length();
                long requestSize = (int) fileLength;
                //分段下载视频
                if (StringUtils.hasText(rangeString)) {
                    //从Range中提取需要获取数据的开始和结束位置
                    long requestStart = 0, requestEnd = 0;
                    String[] ranges = rangeString.split("=");
                    if (ranges.length > 1) {
                        String[] rangeDatas = ranges[1].split("-");
                        requestStart = Integer.parseInt(rangeDatas[0]);
                        if (rangeDatas.length > 1) {
                            requestEnd = Integer.parseInt(rangeDatas[1]);
                        }
                    }
                    if (requestEnd != 0 && requestEnd > requestStart) {
                        requestSize = requestEnd - requestStart + 1;
                    }
                    //根据协议设置请求头
                    response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
                    response.setHeader(HttpHeaders.CONTENT_TYPE, "video/mp4");
                    if (!StringUtils.hasText(rangeString)) {
                        response.setHeader(HttpHeaders.CONTENT_LENGTH, fileLength + "");
                    } else {
                        long length;
                        if (requestEnd > 0) {
                            length = requestEnd - requestStart + 1;
                            response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length);
                            response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + requestEnd + "/" + fileLength);
                        } else {
                            length = fileLength - requestStart;
                            response.setHeader(HttpHeaders.CONTENT_LENGTH, "" + length);
                            response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + requestStart + "-" + (fileLength - 1) + "/"
                                    + fileLength);
                        }
                    }
                    //断点传输下载视频返回206
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                    //设置targetFile,从自定义位置开始读取数据
                    targetFile.seek(requestStart);
                } else {
                    //如果Range为空则下载整个视频
                    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=test.mp4");
                    //设置文件长度
                    response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength));
                }

                //从磁盘读取数据流返回
                byte[] cache = new byte[4096];
                try {
                    while (requestSize > 0) {
                        int len = targetFile.read(cache);
                        if (requestSize < cache.length) {
                            outputStream.write(cache, 0, (int) requestSize);
                        } else {
                            outputStream.write(cache, 0, len);
                            if (len < cache.length) {
                                break;
                            }
                        }
                        requestSize -= cache.length;
                    }
                } catch (IOException e) {
                    // tomcat原话。写操作IO异常几乎总是由于客户端主动关闭连接导致,所以直接吃掉异常打日志
                    //比如使用video播放视频时经常会发送Range为0- 的范围只是为了获取视频大小,之后就中断连接了
                    //log.info(e.getMessage());
                    //throw new RuntimeException(e);
                }
            } else {
                // throw new RuntimeException("文件路劲有误");
            }
            outputStream.flush();
        } catch (Exception e) {
            // e.printStackTrace();
            // throw new RuntimeException("文件传输错误");
        }finally {
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    //e.printStackTrace();
                    // throw new RuntimeException("流释放错误");

                }
            }
            if(targetFile != null){
                try {
                    targetFile.close();
                } catch (IOException e) {
                    //e.printStackTrace();
                    //    throw new RuntimeException("文件流释放错误");
                }
            }
        }

    }

前端要安装视频插件,需要的小伙伴可以@我

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
视频被暂停时,保存当前的播放进度。当用户需要恢复播放时,可以根据保存的播放进度来继续播放视频。 以下是用Java实现视频断点播放的代码示例: ```java import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.media.*; import javax.media.protocol.*; import javax.media.format.*; import javax.media.protocol.DataSource; import java.net.*; public class VideoPlayer extends JFrame implements ControllerListener { private MediaLocator mediaLocator = null; private Player player = null; private Component visualComponent = null; private Component controlComponent = null; private Container contentPane = null; private int pauseLocation; public VideoPlayer(String mediaURL) { super("Video Player"); try { mediaLocator = new MediaLocator(mediaURL); player = Manager.createPlayer(mediaLocator); player.addControllerListener(this); player.realize(); while (player.getState() != player.Realized) { Thread.sleep(10); } visualComponent = player.getVisualComponent(); if (visualComponent != null) { contentPane = getContentPane(); contentPane.add(visualComponent, BorderLayout.CENTER); } controlComponent = player.getControlPanelComponent(); if (controlComponent != null) { contentPane.add(controlComponent, BorderLayout.SOUTH); } setPreferredSize(new Dimension(640, 480)); pack(); setVisible(true); } catch (Exception e) { e.printStackTrace(); } } public void controllerUpdate(ControllerEvent event) { if (event instanceof EndOfMediaEvent) { player.setMediaTime(new Time(pauseLocation)); player.stop(); } } public void pause() { player.stop(); pauseLocation = (int)player.getMediaTime().getSeconds(); } public void play() { player.setMediaTime(new Time(pauseLocation)); player.start(); } public static void main(String[] args) { VideoPlayer player = new VideoPlayer(args[0]); JFrame frame = new JFrame("Video Player"); JPanel panel = new JPanel(); JButton playButton = new JButton("Play"); JButton pauseButton = new JButton("Pause"); playButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { player.play(); } }); pauseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { player.pause(); } }); panel.add(playButton); panel.add(pauseButton); frame.getContentPane().add(player); frame.getContentPane().add(panel, BorderLayout.NORTH); frame.pack(); frame.setVisible(true); } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值