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的实现(伪流媒体)的更多相关文章

  1. winform中的时间轴控件

    我现在做的项目遇到一个需求,就是有没有类似的控件: 我要实现的功能是:播放录像. 某个时间段内假如有2个录像,这个坐标表示的是时间,假如我现在拖动时间轴,拖到第一个录像里面开始播放第一个录像,拖到2个 ...

  2. 看看我做的一款 时间轴 插件 timegliderJs

    TimegliderJs 是一款基于jQuery的时间轴插件.完成后效果. 介绍 Timeglider JS是一个由javascript支持缩放,数据驱动的时间轴组件.非常适合显示项目历史,项目计划及 ...

  3. 使用canvas编写时间轴插件

    使用canvas编写时间轴插件 背景 项目中有一个视频广场的功能,需要一个时间轴类似视频播放中进度条功能一样显示录像情况,并且可以点击.拖动.放大缩小展示时间轴,获取到时间轴的某个时间.原来的时间轴是 ...

  4. 使用css3伪元素制作时间轴并且实现鼠标选中高亮效果

    利用css3来制作时间轴的知识要点:伪元素,以及如何在伪元素上添加锚伪类 1)::before 在元素之前添加内容. 2)::after 在元素之后添加内容. 提示:亦可写成 :before :aft ...

  5. 请教DotNetBar控件中的CalendarView控件如何拖动当前的时间轴

    本人想拖动那个当前的时间轴或者让时间轴变动,因为那个时间轴默认的是当前时间.(就是那个黄色的线)

  6. echart 时间轴、以及y轴值过大但是变化不大显示感觉不出变化的问题+弹出框拖动div事件

    1.时间轴 echart 提供了一种图表,如果x轴是一个时间范围,并且是连续的,如果用传统的数据驱动会很慢,所以用时间轴的方式 function initCurve(_data){ var resul ...

  7. [原创]首次制作JQueryUI插件-Timeline时间轴

    特点: 1. 支持多左右滚动,左右拖动. 2. 时间轴可上下两种显示方式. 3. 支持两种模式的平滑滚动/拖动. 4. 行压缩(后续版本此处可设置是否开启,上传的代码不带这个功能). 5. 支持hov ...

  8. Android 类似时间轴的实现

    想要实现图片中的的时间轴的效果,设定了三种颜色,但是出来的只有一个黑色,还不是设定好的,而且长度很长的话不能滚动,下面上代码: 布局文件: <LinearLayout xmlns:android ...

  9. 用javascript快速清空你的人人时间轴、状态和分享

    博客已经迁移到www.imyzf.com,本站不再更新,请谅解! 现在玩人人的人越来越少了,很多人担心不玩以后东西放上面不安全..我也有同样的想法,但是手动删除上百条东西,太累了,于是写了些javas ...

随机推荐

  1. xmpp聊天室(5)

    聊天室 //初始化聊天室 XMPPJID *roomJID = [XMPPJID jidWithString:ROOM_JID]; xmppRoom = [[XMPPRoom alloc] initW ...

  2. mysql如何将一个字段多个类型串成一个字符串?

    结论 先说结论,可以使用group_concat group by的组合实现多行变一行,将一个字段的多个类型串成一个字段 需求: 如题,一个字段如电影类别,一部电影可以是多个类别,如喜剧.动作片等,其 ...

  3. MySql-了解存储引擎

    怎么应对不同版本 在不同的 mysql 版本中,很多特性和语法有可能是不一样的,我们怎么样才能知道当前版本的语法是什么样呢?最好的办法是学会使用 mysql 的帮助. A.按照层次看帮助 例如:mys ...

  4. 转载:SpringMVC的工作原理图

    SpringMVC的工作原理图: SpringMVC流程 1.  用户发送请求至前端控制器DispatcherServlet. 2.  DispatcherServlet收到请求调用HandlerMa ...

  5. [bzoj3671][Noi2014][随机数生成器] (贪心+位运算+卡空间)

    Description Input 第1行包含5个整数,依次为 x_0,a,b,c,d ,描述小H采用的随机数生成算法所需的随机种子.第2行包含三个整数 N,M,Q ,表示小H希望生成一个1到 N×M ...

  6. RequestMapping_Ant 路径

    [使用@RequestMapping映射请求] [Ant风格资源地址支持3种匹配符] (1)? :匹配文件名中的一个字符. (2) * :匹配文件名中的任意字符. (3) ** :**匹配多层路径. ...

  7. 对百词斩&可可英语的测试

    第六周小组作业 基本任务:功能测试和测试管理 温馨提示:本篇博客中,看不清的图片,可以按住Ctrl同时滚动鼠标滚轮查看:也可以点击图片下方的链接,在新选项卡打开后,点击小加号查看. (1)计划说明 本 ...

  8. ansible plugins简介

    ansible插件是增强ansible的核心功能的代码片段,ansible使用插件架构来实现丰富,灵活和可扩展的功能集. Ansible提供了许多方便的插件,您可以轻松编写自己的插件. 下边简单介绍A ...

  9. validate针对checkbox、radio、select标签的验证

    jQuery.validate 是jquery的一个插件,用来辅助开发者在客户端方便快捷的实现表单验证,最终达到提高用户体验的目的. 示例代码 <form id="formLogin& ...

  10. noip模拟赛 whzzt-Confidence

    分析:做着感觉像脑筋急转弯一样......因为空间的限制,存不下每一个数,所以用数学方法来解. 设t1=Σai - Σbi = aj - bj,t2=Σi*ai - Σi*bi = j*(aj - b ...