HTTP协议下可拖动时间轴播放FLV的实现(伪流媒体)
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目录下。
来源:http://www.laukin.net/wordpress/archives/191
HTTP协议下可拖动时间轴播放FLV的实现(伪流媒体)的更多相关文章
- winform中的时间轴控件
我现在做的项目遇到一个需求,就是有没有类似的控件: 我要实现的功能是:播放录像. 某个时间段内假如有2个录像,这个坐标表示的是时间,假如我现在拖动时间轴,拖到第一个录像里面开始播放第一个录像,拖到2个 ...
- 看看我做的一款 时间轴 插件 timegliderJs
TimegliderJs 是一款基于jQuery的时间轴插件.完成后效果. 介绍 Timeglider JS是一个由javascript支持缩放,数据驱动的时间轴组件.非常适合显示项目历史,项目计划及 ...
- 使用canvas编写时间轴插件
使用canvas编写时间轴插件 背景 项目中有一个视频广场的功能,需要一个时间轴类似视频播放中进度条功能一样显示录像情况,并且可以点击.拖动.放大缩小展示时间轴,获取到时间轴的某个时间.原来的时间轴是 ...
- 使用css3伪元素制作时间轴并且实现鼠标选中高亮效果
利用css3来制作时间轴的知识要点:伪元素,以及如何在伪元素上添加锚伪类 1)::before 在元素之前添加内容. 2)::after 在元素之后添加内容. 提示:亦可写成 :before :aft ...
- 请教DotNetBar控件中的CalendarView控件如何拖动当前的时间轴
本人想拖动那个当前的时间轴或者让时间轴变动,因为那个时间轴默认的是当前时间.(就是那个黄色的线)
- echart 时间轴、以及y轴值过大但是变化不大显示感觉不出变化的问题+弹出框拖动div事件
1.时间轴 echart 提供了一种图表,如果x轴是一个时间范围,并且是连续的,如果用传统的数据驱动会很慢,所以用时间轴的方式 function initCurve(_data){ var resul ...
- [原创]首次制作JQueryUI插件-Timeline时间轴
特点: 1. 支持多左右滚动,左右拖动. 2. 时间轴可上下两种显示方式. 3. 支持两种模式的平滑滚动/拖动. 4. 行压缩(后续版本此处可设置是否开启,上传的代码不带这个功能). 5. 支持hov ...
- Android 类似时间轴的实现
想要实现图片中的的时间轴的效果,设定了三种颜色,但是出来的只有一个黑色,还不是设定好的,而且长度很长的话不能滚动,下面上代码: 布局文件: <LinearLayout xmlns:android ...
- 用javascript快速清空你的人人时间轴、状态和分享
博客已经迁移到www.imyzf.com,本站不再更新,请谅解! 现在玩人人的人越来越少了,很多人担心不玩以后东西放上面不安全..我也有同样的想法,但是手动删除上百条东西,太累了,于是写了些javas ...
随机推荐
- 迭代器,生成器(generator)和Promise的“微妙”关系
需要Promise源码版的朋友:传送链接 本文主要讲述(iterator)和生成器*/yield之间的联系和各自的用法,以及生成器的高配版本aysnc/await的使用. 大纲: 迭代器(iterat ...
- canvas练手项目(三)——Canvas中的Text文本
Canvas中的Text文本也是一个知识点~,我们需要掌握一下几个基本的Text操作方法 首先是重要参数textAlign和textBaseline: textAlign left center ri ...
- 1054.求平均数-PAT乙级真题
从其他博客优秀代码中学到了些技巧,记录一下. 思路:使用sscanf和sprintf函数. sscanf() – 从一个字符串中读进与指定格式相符的数据 sprintf() – 字符串格式化命令,主要 ...
- Django-F和Q函数作用与使用
F函数 能够解析对现有查询对象的引用的对象. obj = Score.objects.get(stuid=') obj.score += 1 obj.order.save() 执行出的SQL语句 wh ...
- 返回通知&异常通知&环绕通知
[返回通知] LoggingAspect.java: @Aspect @Component public class LoggingAspect { /* * 在方法正常执行后执行的通知叫返回通知 * ...
- Leetcode 89.格雷编码
格雷编码 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 0 开头. 示例 1: 输入: 2 ...
- Swift对象创建过程(PUT Object)——纠删码策略(二)
相应Object使用纠删码(EC)作为存储策略时,BaseObjectController类中PUT和GET需要调用的一些方法会被ECObjectController中相应函数覆盖. 在GET Obj ...
- 关于 Neo4j 属性个数的限制
关于 Neo4j 属性个数的限制 目前累积统计它有34.4亿个节点,344亿的关系,和6870亿条属性. 社区版,Neo4j对 数据库内 节点.关系 上的属性名个数是有限制的.数据库中至多存在687亿 ...
- java多线程编程核心技术(四)--Lock的使用
1.jdk1.5中新增了ReentrantLock类,该类也可以实现synchronized线程之间同步互斥的效果. 2.jdk1.5中新增了Condition类.在Lock对象中可以创建多个Cond ...
- git远程上传文件
[第一步]建立先仓库 第一步的话看一般的提示就知道了,在github新建一个repository(谷歌可以解决),都是可视化的界面操作,所以难度不大.或者看这里:https://help.github ...