天天看點

java支援html5視訊流技術Pseudostreaming

僞流技術是一種能在常見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 檔案

java支援html5視訊流技術Pseudostreaming
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 = L;

  private static final int BUFFER_LENGTH =  * ;
  private static final long EXPIRE_TIME =  *  *  * ;
  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 = ;
    int end = length - ;

    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 <  ?  : start;

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

    int contentLength = end - start + ;

    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)) != - && bytesLeft > ) {
        buffer.clear();
        output.write(buffer.array(), , bytesLeft < bytesRead ? bytesLeft : bytesRead);
        bytesLeft -= bytesRead;
      }
    }
  }
}
           

由于使用了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>
           

注意此處配置了視訊檔案的儲存目錄,需要根據實際情況進行修改

<!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[].play();  }); 
        $("#pause").click(function(){ video[].pause(); });
        $("#go10").click(function(){  video[].currentTime+=;  });
        $("#back10").click(function(){  video[].currentTime-=;  });
        $("#rate1").click(function(){  video[].playbackRate+=;  });
        $("#rate0").click(function(){  video[].playbackRate-=;  });
        $("#volume1").click(function(){  video[].volume+=;  });
        $("#volume0").click(function(){  video[].volume-=;  });
        $("#muted1").click(function(){  video[].muted=true;  });
        $("#muted0").click(function(){  video[].muted=false;  });
        $("#full").click(function(){  
          video[].webkitEnterFullscreen(); // webkit類型的浏覽器
          video[].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> 
           

注意根據目錄下的檔案修改請求檔案名 示例中為美麗的風景

由于IE對html5的相容性較差,ie9以上才支援mp4格式,其它版本可以使用flash進行播放