java支持html5视频流技术Pseudostreaming – Roden的专栏 – CSDN博客

工具搬运 专栏收录该内容
109 篇文章 0 订阅

java支持html5视频流技术Pseudostreaming

2016年03月15日 15:13:57
Roden
阅读数 5377
svg%3e

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010605082/article/details/50896685

svg%3e

伪流技术是一种能在常见HTTP服务器如APACHE、tomcat、IIS或lighttpd上安装提供的一种协议。它使用服务端脚本来提供客户端到服务器的视频交互。播放器在URL上携带start time的参数发送HTTP请求到服务端,服务端的脚本处理视频流并且给予回复,保证提供的视频流起始位置与START TIME参数所对应。这个start time的参数通常命名为“start”,这个技术同样被风靡全球的youtube所使用,它使用的是lighttpd WEB服务器。

对于播放器来说,使用伪流或其他流式的解决方案最大的好处是:能跳转到尚未下载到的视频部分。这种情况在很符合大文件播放需求,比如2个小时的视频,用户想立刻跳转到它的后面部分开始播放,(这样不需要下载中间用户不关心的部分了)。好处如下:

  1. 能够随机跳转到视频的任意时间
  2. 从视频的中间开始播放
  3. 提供客户方流媒体服务器和服务端脚本集成的可能
  4. 支持FLV和H.264的视频
    直到现在,仍然不存在一项旨在网页上显示视频的标准。
    今天,大多数视频是通过插件(比如 Flash)来显示的。然而,并非所有浏览器都拥有同样的插件。
    HTML5 规定了一种通过 video 元素来包含视频的标准方法。
    Ogg = 带有 Theora 视频编码和 Vorbis 音频编码的 Ogg 文件
    MPEG4 = 带有 H.264 视频编码和 AAC 音频编码的 MPEG 4 文件
    WebM = 带有 VP8 视频编码和 Vorbis 音频编码的 WebM 文件

resize,m_fill,w_1704,h_1122#

package com.roden.video;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.StandardOpenOption.READ;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public final class PseudostreamingServlet extends HttpServlet {

  private static final long serialVersionUID = 1L;

  private static final int BUFFER_LENGTH = 1024 * 16;
  private static final long EXPIRE_TIME = 1000 * 60 * 60 * 24;
  private static final Pattern RANGE_PATTERN = Pattern.compile("bytes=(?<start>\d*)-(?<end>\d*)");
  private String videoPath;

  @Override
  public void init() throws ServletException {
    videoPath = getInitParameter("videoPath");
  }

  @Override
  protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
    processRequest(request, response);
  }

  private void processRequest(final HttpServletRequest request, final HttpServletResponse response) throws IOException {

    String videoFilename = URLDecoder.decode(request.getParameter("video"), "UTF-8");
    Path video = Paths.get(videoPath, videoFilename);

    int length = (int) Files.size(video);
    int start = 0;
    int end = length - 1;

    String range = request.getHeader("Range");
    range=range==null?"":range;
    Matcher matcher = RANGE_PATTERN.matcher(range);

    if (matcher.matches()) {
      String startGroup = matcher.group("start");
      start = startGroup.isEmpty() ? start : Integer.valueOf(startGroup);
      start = start < 0 ? 0 : start;

      String endGroup = matcher.group("end");
      end = endGroup.isEmpty() ? end : Integer.valueOf(endGroup);
      end = end > length - 1 ? length - 1 : end;
    }

    int contentLength = end - start + 1;

    response.reset();
    response.setBufferSize(BUFFER_LENGTH);
    response.setHeader("Content-Disposition", String.format("inline;filename="%s"", videoFilename));
    response.setHeader("Accept-Ranges", "bytes");
    response.setDateHeader("Last-Modified", Files.getLastModifiedTime(video).toMillis());
    response.setDateHeader("Expires", System.currentTimeMillis() + EXPIRE_TIME);
    response.setContentType(Files.probeContentType(video));
    response.setHeader("Content-Range", String.format("bytes %s-%s/%s", start, end, length));
    response.setHeader("Content-Length", String.format("%s", contentLength));
    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

    int bytesRead;
    int bytesLeft = contentLength;
    ByteBuffer buffer = ByteBuffer.allocate(BUFFER_LENGTH);

    try (SeekableByteChannel input = Files.newByteChannel(video, READ);
            OutputStream output = response.getOutputStream()) {

      input.position(start);

      while ((bytesRead = input.read(buffer)) != -1 && bytesLeft > 0) {
        buffer.clear();
        output.write(buffer.array(), 0, bytesLeft < bytesRead ? bytesLeft : bytesRead);
        bytesLeft -= bytesRead;
      }
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

由于使用了Nio请使用jdk7以上版本

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <servlet>
    <servlet-name>stream</servlet-name>
    <servlet-class>com.roden.video.PseudostreamingServlet</servlet-class>
    <init-param>
      <param-name>videoPath</param-name>
      <param-value>F:/BaiduYunDownload/</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>stream</servlet-name>
    <url-pattern>/stream</url-pattern>
  </servlet-mapping>
  <session-config>
    <session-timeout>30</session-timeout>
  </session-config>
</web-app>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

注意此处配置了视频文件的保存目录,需要根据实际情况进行修改

<!DOCTYPE html>
<html>
  <head>
    <title>HTML5 Video Pseudostreaming</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="//code.jquery.com/jquery-1.12.0.min.js"></script>
    <script>
    $(document).ready(function(){   
        var video = $('#myvideo');

        $("#play").click(function(){  video[0].play();  }); 
        $("#pause").click(function(){ video[0].pause(); });
        $("#go10").click(function(){  video[0].currentTime+=10;  });
        $("#back10").click(function(){  video[0].currentTime-=10;  });
        $("#rate1").click(function(){  video[0].playbackRate+=2;  });
        $("#rate0").click(function(){  video[0].playbackRate-=2;  });
        $("#volume1").click(function(){  video[0].volume+=0.1;  });
        $("#volume0").click(function(){  video[0].volume-=0.1;  });
        $("#muted1").click(function(){  video[0].muted=true;  });
        $("#muted0").click(function(){  video[0].muted=false;  });
        $("#full").click(function(){  
          video[0].webkitEnterFullscreen(); // webkit类型的浏览器
          video[0].mozRequestFullScreen();  // FireFox浏览器
        });
    });

    </script>
</head> 
<body>
<video id="myvideo" width="80%" height="80%" controls="controls">
    <source src="stream?video=美丽的风景.mp4"  />
    <!--<source src="stream?video=美丽的风景.mp4" type="video/mp4" />
    <source src="stream?video=美丽的风景.mp4" type="video/webM" />
    <source src="stream?video=美丽的风景.mp4" type="video/ogg" />-->
        你的浏览器不支持html5
</video>
<hr>
<button id="play">播放</button>
<button id="pause">暂停</button>
<button id="go10">快进10秒</button>
<button id="back10">快退10秒</button>
<button id="rate1">播放速度+</button>
<button id="rate0">播放速度-</button>
<button id="volume1">声音+</button>
<button id="volume0">声音-</button>
<button id="muted1">静音</button>
<button id="muted0">解除静音</button>
<button id="full">全屏</button> 
</body> 
</html> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

注意根据目录下的文件修改请求文件名 示例中为美丽的风景

由于IE对html5的兼容性较差,ie9以上才支持mp4格式,其它版本可以使用flash进行播放


resize,m_fill,w_46,h_46#

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页

打赏作者

Shensgのblog

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值