1. 程式人生 > >HTTP協議下可拖動時間軸播放FLV的實現(偽流媒體)

HTTP協議下可拖動時間軸播放FLV的實現(偽流媒體)

prot pac -m method bytes encoding 編寫 時間軸 delay

HTTP協議下實現FLV的播放其實並不復雜,當初實現的原理是使用了flowPlayer插件實現的,效果還不錯。但仍有兩大問題影響著客戶的訪問情緒:

1.預加載時頁面卡死,似乎沒有邊下邊播。

2.偶爾邊下邊播,卻無法拖動時間軸至未下載的部分。相信很多人也遇到該問題。

一度想采用專門的媒體服務器如Adobe的FMS去實現該功能,後多方查找資料,發現采用媒體服務器成本較高,且效率並不是很好,各大視頻網站也未采用該方式。而實現HTTP協議下播放flv並可拖動時間軸並非沒有可能,關鍵在於以下幾點:

  1. Flv視頻文件包含metadata信息,大多數轉碼工具生成的FLV不包含該信息。可用工具增加(flvtool2,yamdi[速度很快,效率高])。
  2. Web端播放器需支持拖動時間軸時發送請求的連接中帶有字節參數,或時間參數。
  3. 服務器端實現對flv文件的讀取和流式輸出。

一、給FLV文件加入metadata信息

flvtool2和yamdi都可以實現該功能,但yamdi工具的效率要高出很多,400M左右的FLV處理時間大概2分鐘,推薦使用。實現方式是在cmd命令窗口下執行如下命令:

yamdi -i 源文件名 -o 新文件名

二、flowPlayer的使用與配置

flowPlayer是一款web端播放flv等視頻的利器,功能比較強大,采用的版本3.2.2,可支持多種插件,此次實現可拖動時間軸的功能也是使用了它的一款插件, 該插件名為:flowplayer.pseudostreaming-byterange-3.2.9.swf,采用的版本是3.2.9,3.2.10不可作為flowPlayer3.2.2的插件使用, 測試未有圖像顯示。頁面中的編寫方式是,紅色標出的是重要部分:

<%@ page language=“Java” import=“java.util.*;” pageEncoding=“UTF-8″%>

<%@ taglib prefix=“c” uri=“http://java.sun.com/jstl/core”%>

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>

<html>

<head>

<title>FLV</title>

<script type=”text/JavaScript”

src=”<c:url value=“/script/jQuery-1.5.2.min.js” />”></script>

<script type=“text/javascript”

src=”<c:url value=“/_flowplayer/flowplayer-3.2.4.min.js”/>”></script>

</head>

<body>

<script type=“text/javascript”>

<!–

var p;

$(function(){

p = $(“.player”).flowplayer(

{

src:’<c:url value=”/_flowplayer/flowplayer.commercial.swf”/>’,

wmode: “opaque”

},

{

clip:{

//scaling: ‘orig’, 設置播放器讀取原始視頻高寬比

autoPlay: true,

autoBuffering: true,

bufferLength: 1,

provider: ‘lighttpd’

},

plugins: {

controls: {

url: ‘<c:url value=”/_flowplayer/flowplayer.controls-air-3.2.2.swf”/>’,

opacity: 0.8,

backgroundColor: ‘#000′,

scrubber : true,

buttonColor: ‘#000′,

buttonOverColor: ‘#4c4c4c’,

autoHide: {

enabled: true,

fullscreenOnly: false,

hideDelay: 1000,

mouseOutDelay: 2000,

hideStyle: ‘fade’

}

},

lighttpd: {

url: “<c:url value=”/_flowplayer/flowplayer.pseudostreaming-byterange-3.2.9.swf”/>”

,queryString: escape(‘?target=${“${start}”}&secretToken=1235oh8qewr5uweynkc’)

// queryString配置了拖動時間軸後發送到後臺的參數。${start}為固定格式。

}

},

play: { replayLabel : “再次播放”, width:120 , height: 50}

})

})

//à

</script>

<!—視頻展示區域à

<div class=”left_video_areaBg clearWrap”>

<!—視頻限制高寬 W:451px H:252pxà

<a class=”player”

href=”<c:url value=”/movie/131201174437530567C.flv”/>”

style=”display: block; width: 429px; height: 252px;” id=”player1”>

</a>

</div>

<div class=”left_video_dotLine”></div>

<div class=”blank8”></div>

<button onclick=”$f().seek(60);”>1分鐘</button>

<button onclick=”$f().seek(180);”>3分鐘</button>

<button onclick=”alert($f().getTime());”>獲取當前時間點</button>

</body>

</html>

三、實現流式輸出的Servlet的編寫

package flv.laukin.NET;

import java.io.IOException;

import java.io.RandomAccessFile;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class FlvStreamServlet extends HttpServlet{

protected void doGet(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

// TODO Auto-generated method stub

resp.reset();

resp.setContentType(“Video/x-flv”);

String target = req.getParameter(“target”); //接收參數,為字節數

int targetInt = 0;

System.out.println(“Target:” + target);

System.out.println(“Target:” + req.getServletPath());

String flvPath = req.getSession().getServletContext().getRealPath(req.getServletPath());

System.out.println(flvPath);

RandomAccessFile raf = null;

int totalByte = 0;

try{

raf = new RandomAccessFile(flvPath, “r”);

totalByte = (int)raf.length();

if (target != null && !”".equals(target)) {

try {

targetInt = Integer.parseInt(target);

byte[] headData = new byte[]{‘F’,‘L’,‘V’,1,1,0,0,0,9,0,0,0,9}; //拖動時間軸後的response中頭信息需寫入該字節

resp.getOutputStream().write(headData);

resp.setContentLength(totalByte – targetInt + 13);

} catch (NumberFormatException e) {

targetInt = 0;

}

} else {

resp.setContentLength(totalByte – targetInt);

}

raf.skipBytes(targetInt);//跳過時間軸前面的字節;

byte[] b = new byte[4096];

while(raf.read(b) != -1) {

resp.getOutputStream().write(b);

}

resp.getOutputStream().flush();

} catch (Exception e) {

String simplename = e.getClass().getSimpleName();

if(!”ClientAbortException”.equals(simplename)){

e.printStackTrace();

}//web端拖動時間軸總有連接被重置的異常,暫時還不知如何解決,可以此方式不輸出異常

} finally {

if(raf != null){

raf.close();

}

}

}

}

web.xml中增加配置:

<servlet>

<servlet-name>FlvStream</servlet-name>

<servlet-class>flv.laukin.net.FlvStreamServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>FlvStream</servlet-name>

<url-pattern>*.flv</url-pattern>

</servlet-mapping>

至此Tomcat下的FLV播放就可實現任意拖動了。

下面的連接為項目代碼,可下載交流,測試可自己制作 flv 放到 movie目錄下。

FLVstreaming

來源:http://www.laukin.net/wordpress/archives/191

HTTP協議下可拖動時間軸播放FLV的實現(偽流媒體)