Re:从零开始学流媒体(一):视频跳转、206、chunked、动态URL、断点续传
2021-08-16 14:33 查士丁尼 阅读(633) 评论(0) 编辑 收藏 举报一、静态路由视频播放
首先,不考虑用最新的技术,不考虑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来随意读取文件,可以实现跳转播放了。