• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

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

    发布者: 山止川行 | 发布时间: 2025-6-16 12:20| 查看数: 171| 评论数: 0|帖子模式

    本文介绍如何通过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数据流播放视频内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!

    来源:https://www.jb51.net/html5/773384.html
    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

    最新评论

    浏览过的版块

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表