HTTP協議下實現FLV的播放其實並不復雜,當初實現的原理是使用了flowPlayer插件實現的,效果還不錯。但仍有兩大問題影響着客戶的訪問情緒:
1.預加載時頁面卡死,似乎沒有邊下邊播。
2.偶爾邊下邊播,卻無法拖動時間軸至未下載的部分。相信很多人也遇到該問題。
一度想采用專門的媒體服務器如Adobe的FMS去實現該功能,后多方查找資料,發現采用媒體服務器成本較高,且效率並不是很好,各大視頻網站也未采用該方式。而實現HTTP協議下播放flv並可拖動時間軸並非沒有可能,關鍵在於以下幾點:
- Flv視頻文件包含metadata信息,大多數轉碼工具生成的FLV不包含該信息。可用工具增加(flvtool2,yamdi[速度很快,效率高])。
- Web端播放器需支持拖動時間軸時發送請求的連接中帶有字節參數,或時間參數。
- 服務器端實現對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目錄下。