• 售前

  • 售后

热门帖子
入门百科

Html5通过数据流方式播放视频的实现

[复制链接]
刘冠华 显示全部楼层 发表于 2021-8-14 14:48:21 |阅读模式 打印 上一主题 下一主题
本文先容怎样通过H5页面通过数据流的方式播放服务端的视频文件,可以兼容PC、Android和IOS情况。
H5页面可以通过<video> 标签来播放视频。一样平常的方式如下:
  1. <!DOCTYPE HTML>
  2. <html>
  3. <body>
  4. <video src="/i/movie.mp4" controls="controls">
  5. your browser does not support the video tag
  6. </video>
  7. </body>
  8. </html>
复制代码
src中指定了要播放的视频的URL,为具体的视频文件路径。当将访问哀求变为getVideo.do?fileId=xxx 这种情势,服务端返回字节流的时间后端实现须要一些更改。
一样平常的方式是读本地文件然后写到response中,代码实现如下:
  1. public void downFile(File downloadFile,
  2.       HttpServletResponse response,
  3.       HttpServletRequest request) throws Exception {
  4. response.reset();
  5. response.setContentType("video/mp4;charset=UTF-8");
  6. InputStream in = null;
  7. ServletOutputStream out = null;
  8. try {
  9.   out = response.getOutputStream();
  10.   
  11.   in = new FileInputStream(downloadFile);
  12.   if(in !=null){
  13.     byte[] b = new byte[1024];  
  14.      int i = 0;  
  15.      while((i = in.read(b)) > 0){  
  16.     out.write(b, 0, i);  
  17.      }  
  18.      out.flush();   
  19.      in.close();
  20.    
  21.   }
  22. } catch (Exception e) {
  23.   
  24.    e.printStackTrace();
  25. }finally{
  26.   if(in != null) {  
  27.    try { in.close(); } catch (IOException e) { }  
  28.    in = null;  
  29.   }
  30.   if(out != null) {  
  31.    try { out.close(); } catch (IOException e) { }  
  32.    out = null;  
  33.   }
  34. }
  35. }
复制代码
这种方式在PC端和Android手机上都能正常显示,但在IOS手机上通过Safari欣赏器就不能播放。ios目前获取视频的时间哀求头会带一个与断点续传有关的信息。对于ios来说,他不是一次性请责备部文件的,一样平常起首会哀求0-1字节,这个会写在request header的"range"字段中:range:‘bytes=0-1’。
而服务端必须满意range的要求:分析range字段,然后按照range字段的要求返回对应的数据。
在相应头中response header至少要包罗三个字段:
       
  • Content-Type:明确指定视频格式,有"video/mp4", “video/ogg”, "video/mov"等等。   
  • Content-Range:格式是 “bytes <start>-<end>/<total>”,其中start和end必须对应request header里的range字段,total是文件总巨细。   
  • Content-Length:返回的二进制长度。
断点续传实现如下:
  1. public void downRangeFile(File downloadFile,
  2.        HttpServletResponse response,
  3.        HttpServletRequest request) throws Exception {
  4. if (!downloadFile.exists()) {
  5.   response.sendError(HttpServletResponse.SC_NOT_FOUND);
  6.   return;
  7. }
  8. long fileLength = downloadFile.length();// 记录文件大小  
  9. long pastLength = 0;// 记录已下载文件大小  
  10. int rangeSwitch = 0;// 0:从头开始的全文下载;1:从某字节开始的下载(bytes=27000-);2:从某字节开始到某字节结束的下载(bytes=27000-39000)  
  11. long contentLength = 0;// 客户端请求的字节总量  
  12. String rangeBytes = "";// 记录客户端传来的形如“bytes=27000-”或者“bytes=27000-39000”的内容  
  13. RandomAccessFile raf = null;// 负责读取数据  
  14. OutputStream os = null;// 写出数据  
  15. OutputStream out = null;// 缓冲  
  16. int bsize = 1024;// 缓冲区大小  
  17. byte b[] = new byte[bsize];// 暂存容器  
  18. String range = request.getHeader("Range");
  19. int responseStatus = 206;
  20. if (range != null && range.trim().length() > 0 && !"null".equals(range)) {// 客户端请求的下载的文件块的开始字节  
  21.   responseStatus = javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT;
  22.   System.out.println("request.getHeader("Range")=" + range);
  23.   rangeBytes = range.replaceAll("bytes=", "");
  24.   if (rangeBytes.endsWith("-")) {
  25.    rangeSwitch = 1;
  26.    rangeBytes = rangeBytes.substring(0, rangeBytes.indexOf('-'));
  27.    pastLength = Long.parseLong(rangeBytes.trim());
  28.    contentLength = fileLength - pastLength;
  29.   } else {
  30.    rangeSwitch = 2;
  31.    String temp0 = rangeBytes.substring(0, rangeBytes.indexOf('-'));
  32.    String temp2 = rangeBytes.substring(rangeBytes.indexOf('-') + 1, rangeBytes.length());
  33.    pastLength = Long.parseLong(temp0.trim());
  34.   }
  35. } else {
  36.   contentLength = fileLength;// 客户端要求全文下载  
  37. }
  38. // 清除首部的空白行  
  39. response.reset();
  40. // 告诉客户端允许断点续传多线程连接下载,响应的格式是:Accept-Ranges: bytes  
  41. response.setHeader("Accept-Ranges", "bytes");
  42. // 如果是第一次下,还没有断点续传,状态是默认的 200,无需显式设置;响应的格式是:HTTP/1.1  
  43. if (rangeSwitch != 0) {
  44.   response.setStatus(responseStatus);
  45.   // 不是从最开始下载,断点下载响应号为206  
  46.   // 响应的格式是:  
  47.   // Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]  
  48.   switch (rangeSwitch) {
  49.    case 1: {
  50.     String contentRange = new StringBuffer("bytes ")
  51.       .append(new Long(pastLength).toString()).append("-")
  52.       .append(new Long(fileLength - 1).toString())
  53.       .append("/").append(new Long(fileLength).toString())
  54.       .toString();
  55.     response.setHeader("Content-Range", contentRange);
  56.     break;
  57.    }
  58.    case 2: {
  59.     String contentRange = range.replace("=", " ") + "/"
  60.       + new Long(fileLength).toString();
  61.     response.setHeader("Content-Range", contentRange);
  62.     break;
  63.    }
  64.    default: {
  65.     break;
  66.    }
  67.   }
  68. } else {
  69.   String contentRange = new StringBuffer("bytes ").append("0-")
  70.     .append(fileLength - 1).append("/").append(fileLength)
  71.     .toString();
  72.   response.setHeader("Content-Range", contentRange);
  73. }
  74. try {
  75.   response.setContentType("video/mp4;charset=UTF-8");
  76.   response.setHeader("Content-Length", String.valueOf(contentLength));
  77.   os = response.getOutputStream();
  78.   out = new BufferedOutputStream(os);
  79.   raf = new RandomAccessFile(downloadFile, "r");
  80.   try {
  81.    long outLength = 0;// 实际输出字节数  
  82.    switch (rangeSwitch) {
  83.     case 0: {
  84.     }
  85.     case 1: {
  86.      raf.seek(pastLength);
  87.      int n = 0;
  88.      while ((n = raf.read(b)) != -1) {
  89.       out.write(b, 0, n);
  90.       outLength += n;
  91.      }
  92.      break;
  93.     }
  94.     case 2: {
  95.      raf.seek(pastLength);
  96.      int n = 0;
  97.      long readLength = 0;// 记录已读字节数  
  98.      while (readLength <= contentLength - bsize) {// 大部分字节在这里读取  
  99.       n = raf.read(b);
  100.       readLength += n;
  101.       out.write(b, 0, n);
  102.       outLength += n;
  103.      }
  104.      if (readLength <= contentLength) {// 余下的不足 1024 个字节在这里读取  
  105.       n = raf.read(b, 0, (int) (contentLength - readLength));
  106.       out.write(b, 0, n);
  107.       outLength += n;
  108.      }
  109.      break;
  110.     }
  111.     default: {
  112.      break;
  113.     }
  114.    }
  115.    System.out.println("Content-Length为:" + contentLength + ";实际输出字节数:" + outLength);
  116.    out.flush();
  117.   } catch (IOException ie) {
  118.    // ignore  
  119.   }
  120. } catch (Exception e) {
  121.   e.printStackTrace();
  122. } finally {
  123.   if (out != null) {
  124.    try {
  125.     out.close();
  126.    } catch (IOException e) {
  127.     e.printStackTrace();
  128.    }
  129.   }
  130.   if (raf != null) {
  131.    try {
  132.     raf.close();
  133.    } catch (IOException e) {
  134.     e.printStackTrace();
  135.    }
  136.   }
  137. }
  138. }
复制代码
H5页面:
  1. <!DOCTYPE HTML>
  2. <html>
  3. <body>
  4. <video width="100%" height="200" rel="preload" x5-video-player-type="h5" playsinline="true" webkit-playsinline="true" controls="controls">
  5. <source src="http://127.0.0.1:8080/XXX/getVideo.do?fileId=16" type="video/mp4">
  6. </video>
  7. </script>
  8. </body>
  9. </html>
复制代码
通过上述断点续传方式H5可正常播放视频数据流,并且支持各种平台。
到此这篇关于Html5通过数据流方式播放视频的实现的文章就先容到这了,更多相干Html5数据流播放视频内容请搜索草根技术分享以前的文章或继续欣赏下面的相干文章,希望各人以后多多支持草根技术分享!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作