winlin

add buffer time and play time display

/**
* padding the output.
* padding(3, 5, '0') is 00003
* padding(3, 5, 'x') is xxxx3
* @see http://blog.csdn.net/win_lin/article/details/12065413
*/
function padding(number, length, prefix) {
if(String(number).length >= length){
return String(number);
}
return padding(prefix+number, length, prefix);
}
/**
* update the navigator, add same query string.
*/
function update_nav() {
... ... @@ -88,7 +101,7 @@ function srs_init(rtmp_url, hls_url) {
/**
* the SrsPlayer object.
*/
function SrsPlayer(container, stream_url, width, height, buffer_time) {
function SrsPlayer(container, stream_url, width, height) {
if (!SrsPlayer.__id) {
SrsPlayer.__id = 100;
}
... ... @@ -102,12 +115,14 @@ function SrsPlayer(container, stream_url, width, height, buffer_time) {
this.stream_url = stream_url;
this.width = width;
this.height = height;
this.buffer_time = buffer_time;
this.id = SrsPlayer.__id++;
this.callbackObj = null;
this.buffer_time = 0.8; // default to 0.8
// callback set the following values.
this.meatadata = {}; // for on_player_metadata
this.time = 0; // current stream time.
this.buffer_length = 0; // current stream buffer length.
}
/**
* user can set some callback, then start the player.
... ... @@ -121,6 +136,7 @@ SrsPlayer.prototype.start = function() {
flashvars.id = this.id;
flashvars.on_player_ready = "__srs_on_player_ready";
flashvars.on_player_metadata = "__srs_on_player_metadata";
flashvars.on_player_timer = "__srs_on_player_timer";
var params = {};
params.wmode = "opaque";
... ... @@ -144,7 +160,7 @@ SrsPlayer.prototype.start = function() {
return this;
}
SrsPlayer.prototype.play = function() {
return this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time);
this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time);
}
SrsPlayer.prototype.stop = function() {
for (var i = 0; i < SrsPlayer.__players.length; i++) {
... ... @@ -157,13 +173,14 @@ SrsPlayer.prototype.stop = function() {
SrsPlayer.__players.splice(i, 1);
break;
}
return this.callbackObj.ref.__stop();
this.callbackObj.ref.__stop();
}
SrsPlayer.prototype.pause = function() {
return this.callbackObj.ref.__pause();
this.callbackObj.ref.__pause();
}
SrsPlayer.prototype.resume = function() {
return this.callbackObj.ref.__resume();
this.callbackObj.ref.__resume();
}
/**
* to set the DAR, for example, DAR=16:9
... ... @@ -175,7 +192,7 @@ SrsPlayer.prototype.resume = function() {
* use user specified width if -1.
*/
SrsPlayer.prototype.dar = function(num, den) {
return this.callbackObj.ref.__dar(num, den);
this.callbackObj.ref.__dar(num, den);
}
/**
* set the fullscreen size data.
... ... @@ -186,13 +203,24 @@ SrsPlayer.prototype.dar = function(num, den) {
* 100 means 100%.
*/
SrsPlayer.prototype.set_fs = function(refer, percent) {
return this.callbackObj.ref.__set_fs(refer, percent);
this.callbackObj.ref.__set_fs(refer, percent);
}
/**
* set the stream buffer time in seconds.
* @buffer_time the buffer time in seconds.
*/
SrsPlayer.prototype.set_bt = function(buffer_time) {
this.buffer_time = buffer_time;
this.callbackObj.ref.__set_bt(buffer_time);
}
SrsPlayer.prototype.on_player_ready = function() {
return this.play();
this.play();
}
SrsPlayer.prototype.on_player_metadata = function(metadata) {
return 0;
// ignore.
}
SrsPlayer.prototype.on_player_timer = function(time, buffer_length) {
// ignore.
}
function __srs_on_player_ready(id) {
for (var i = 0; i < SrsPlayer.__players.length; i++) {
... ... @@ -202,7 +230,8 @@ function __srs_on_player_ready(id) {
continue;
}
return player.on_player_ready();
player.on_player_ready();
return;
}
throw new Error("player not found. id=" + id);
... ... @@ -219,7 +248,30 @@ function __srs_on_player_metadata(id, metadata) {
// so set the data before invoke it.
player.metadata = metadata;
return player.on_player_metadata(metadata);
player.on_player_metadata(metadata);
return;
}
throw new Error("player not found. id=" + id);
}
function __srs_on_player_timer(id, time, buffer_length) {
for (var i = 0; i < SrsPlayer.__players.length; i++) {
var player = SrsPlayer.__players[i];
if (player.id != id) {
continue;
}
buffer_length = Math.max(0, buffer_length);
buffer_length = Math.min(player.buffer_time, buffer_length);
// user may override the on_player_timer,
// so set the data before invoke it.
player.time = time;
player.buffer_length = buffer_length;
player.on_player_timer(time, buffer_length);
return;
}
throw new Error("player not found. id=" + id);
... ...
... ... @@ -40,6 +40,18 @@
__active_size.addClass("active");
}
var __active_bt = null;
function select_buffer_time(bt_id, buffer_time) {
srs_player.set_bt(buffer_time);
if (__active_bt) {
__active_bt.removeClass("active");
}
__active_bt = $(bt_id).parent();
__active_bt.addClass("active");
}
$(function(){
// get the vhost and port to set the default url.
// for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
... ... @@ -68,15 +80,38 @@
var url = $("#txt_url").val();
srs_player = new SrsPlayer("player_id", url, 530, 300, 0.8);
srs_player = new SrsPlayer("player_id", url, 530, 300);
srs_player.on_player_ready = function() {
return srs_player.play();
srs_player.play();
}
srs_player.on_player_metadata = function(metadata) {
$("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")");
select_dar("#btn_dar_original", 0, 0);
select_fs_size("#btn_fs_size_screen_100", "screen", 100);
return 0;
select_buffer_time("#btn_bt_0_8", 0.8);
}
srs_player.on_player_timer = function(time, buffer_length) {
var buffer = buffer_length / srs_player.buffer_time * 100;
$("#pb_buffer").width(Number(buffer).toFixed(1) + "%");
$("#pb_buffer_bg").attr("title",
"缓冲区长度:" + Number(buffer_length).toFixed(1) + "秒("
+ Number(buffer).toFixed(1) + "%)");
var time_str = "";
// day
time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " ";
// hour
time = time % (24 * 3600);
time_str += padding(parseInt(time / 3600), 2, '0') + ":";
// minute
time = time % (3600);
time_str += padding(parseInt(time / 60), 2, '0') + ":";
// seconds
time = time % (60);
time_str += padding(parseInt(time), 2, '0');
// show
$("#txt_time").val(time_str);
}
srs_player.start();
});
... ... @@ -97,11 +132,11 @@
});
$("#btn_pause").click(function(){
if ($("#btn_pause").text() == "暂停播放") {
$("#btn_pause").text("继续播放");
if ($("#btn_pause").text() == "暂停") {
$("#btn_pause").text("继续");
srs_player.pause();
} else {
$("#btn_pause").text("暂停播放");
$("#btn_pause").text("暂停");
srs_player.resume();
}
});
... ... @@ -144,6 +179,33 @@
select_fs_size("#btn_fs_size_screen_50", "screen", 50);
});
}
if (true) {
$("#btn_bt_0_5").click(function(){
select_buffer_time("#btn_bt_0_5", 0.5);
});
$("#btn_bt_0_8").click(function(){
select_buffer_time("#btn_bt_0_8", 0.8);
});
$("#btn_bt_1").click(function(){
select_buffer_time("#btn_bt_1", 1);
});
$("#btn_bt_2").click(function(){
select_buffer_time("#btn_bt_2", 2);
});
$("#btn_bt_3").click(function(){
select_buffer_time("#btn_bt_3", 3);
});
$("#btn_bt_5").click(function(){
select_buffer_time("#btn_bt_5", 5);
});
$("#btn_bt_10").click(function(){
select_buffer_time("#btn_bt_10", 10);
});
$("#btn_bt_30").click(function(){
select_buffer_time("#btn_bt_30", 30);
});
}
});
</script>
</head>
... ... @@ -180,15 +242,23 @@
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>SrsPlayer</h3>
</div>
<div class="modal-body" id="player">
<div class="modal-body">
<div id="player"></div>
<div class="progress progress-striped active" id="pb_buffer_bg">
<div class="bar" style="width: 0%;" id="pb_buffer"></div>
</div>
</div>
<div class="modal-footer">
<div class="modal-footer" style="margin-top:-20px;">
<div class="input-prepend" style="margin-top: 10px;">
<span class="add-on" title="播放时长">@T</span>
<input class="span2" style="width:85px" id="txt_time" type="text" placeholder="天 时:分:秒">
</div>
<div class="btn-group dropup">
<button class="btn dropdown-toggle" data-toggle="dropdown">
<a id="fs_tips" href="#" data-toggle="tooltip" data-placement="top" title="">
<img src="img/tooltip.png"/>
</a>
全屏大小<span class="caret"></span>
大小<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a id="btn_fs_size_screen_100" href="#">屏幕大小(100%)</a></li>
... ... @@ -200,7 +270,7 @@
</ul>
</div>
<div class="btn-group dropup">
<button class="btn dropdown-toggle" data-toggle="dropdown">显示比例<span class="caret"></span></button>
<button class="btn dropdown-toggle" data-toggle="dropdown">比例<span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a id="btn_dar_original" href="#">视频原始比例</a></li>
<li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li>
... ... @@ -210,7 +280,20 @@
</ul>
</div>
<div class="btn-group dropup">
<button id="btn_pause" class="btn">暂停播放</button>
<button class="btn dropdown-toggle" data-toggle="dropdown">缓冲区<span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a id="btn_bt_0_5" href="#">0.5秒(实时)</a></li>
<li><a id="btn_bt_0_8" href="#">0.8秒(会议)</a></li>
<li><a id="btn_bt_1" href="#">1秒(低延迟)</a></li>
<li><a id="btn_bt_2" href="#">2秒(较低延时)</a></li>
<li><a id="btn_bt_3" href="#">3秒(流畅播放)</a></li>
<li><a id="btn_bt_5" href="#">5秒(网速较低)</a></li>
<li><a id="btn_bt_10" href="#">10秒(无所谓延迟)</a></li>
<li><a id="btn_bt_30" href="#">30秒(流畅第一)</a></li>
</ul>
</div>
<div class="btn-group dropup">
<button id="btn_pause" class="btn">暂停</button>
</div>
<div class="btn-group dropup">
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭</button>
... ...
... ... @@ -8,6 +8,7 @@ package
import flash.events.FullScreenEvent;
import flash.events.MouseEvent;
import flash.events.NetStatusEvent;
import flash.events.TimerEvent;
import flash.external.ExternalInterface;
import flash.media.Video;
import flash.net.NetConnection;
... ... @@ -15,6 +16,7 @@ package
import flash.system.Security;
import flash.ui.ContextMenu;
import flash.ui.ContextMenuItem;
import flash.utils.Timer;
import flash.utils.setTimeout;
public class srs_player extends Sprite
... ... @@ -24,6 +26,7 @@ package
// user set callback
private var on_player_ready:String = null;
private var on_player_metadata:String = null;
private var on_player_timer:String = null;
// play param url.
private var url:String = null;
... ... @@ -41,6 +44,7 @@ package
private var stream:NetStream = null;
private var video:Video = null;
private var metadata:Object = {};
private var timer:Timer = new Timer(300);
// flash donot allow js to set to fullscreen,
// only allow user click to enter fullscreen.
... ... @@ -82,10 +86,25 @@ package
this.id = flashvars.id;
this.on_player_ready = flashvars.on_player_ready;
this.on_player_metadata = flashvars.on_player_metadata;
this.on_player_timer = flashvars.on_player_timer;
this.timer.addEventListener(TimerEvent.TIMER, this.on_timer);
this.timer.start();
flash.utils.setTimeout(this.on_js_ready, 0);
}
private function on_timer(evt:TimerEvent):void {
if (!this.stream) {
trace("stream is null, ignore timer event.");
return;
}
trace("notify js the timer event.");
flash.external.ExternalInterface.call(
this.on_player_timer, this.id, this.stream.time, this.stream.bufferLength);
}
private function on_stage_fullscreen(evt:FullScreenEvent):void {
if (!evt.fullScreen) {
execute_user_set_dar();
... ... @@ -107,25 +126,21 @@ package
flash.external.ExternalInterface.addCallback("__resume", this.js_call_resume);
flash.external.ExternalInterface.addCallback("__dar", this.js_call_dar);
flash.external.ExternalInterface.addCallback("__set_fs", this.js_call_set_fs_size);
flash.external.ExternalInterface.addCallback("__set_bt", this.js_call_set_bt);
var code:int = flash.external.ExternalInterface.call(this.on_player_ready, this.id);
if (code != 0) {
throw new Error("callback on_player_ready failed. code=" + code);
}
flash.external.ExternalInterface.call(this.on_player_ready, this.id);
}
private function js_call_pause():int {
private function js_call_pause():void {
if (this.stream) {
this.stream.pause();
}
return 0;
}
private function js_call_resume():int {
private function js_call_resume():void {
if (this.stream) {
this.stream.resume();
}
return 0;
}
/**
... ... @@ -137,12 +152,11 @@ package
* use metadata width if 0.
* use user specified width if -1.
*/
private function js_call_dar(num:int, den:int):int {
private function js_call_dar(num:int, den:int):void {
dar_num = num;
dar_den = den;
flash.utils.setTimeout(execute_user_set_dar, 0);
return 0;
}
/**
... ... @@ -153,11 +167,9 @@ package
* @param percent, the rescale percent, where
* 100 means 100%.
*/
private function js_call_set_fs_size(refer:String, percent:int):int {
private function js_call_set_fs_size(refer:String, percent:int):void {
fs_refer = refer;
fs_percent = percent;
return 0;
}
/**
* js cannot enter the fullscreen mode, user must click to.
... ... @@ -176,7 +188,17 @@ package
}
}
private function js_call_stop():int {
/**
* set the stream buffer time in seconds.
* @buffer_time the buffer time in seconds.
*/
private function js_call_set_bt(buffer_time:Number):void {
if (this.stream) {
this.stream.bufferTime = buffer_time;
}
}
private function js_call_stop():void {
if (this.stream) {
this.stream.close();
this.stream = null;
... ... @@ -189,8 +211,6 @@ package
this.removeChild(this.video);
this.video = null;
}
return 0;
}
private function draw_black_background(_width:int, _height:int):void {
... ... @@ -205,7 +225,7 @@ package
this.fs_mask.graphics.endFill();
}
private function js_call_play(url:String, _width:int, _height:int, _buffer_time:Number):int {
private function js_call_play(url:String, _width:int, _height:int, _buffer_time:Number):void {
this.url = url;
this.w = _width;
this.h = _height;
... ... @@ -218,6 +238,8 @@ package
this.conn.client.onBWDone = function():void {};
this.conn.addEventListener(NetStatusEvent.NET_STATUS, function(evt:NetStatusEvent):void {
trace ("NetConnection: code=" + evt.info.code);
// TODO: FIXME: failed event.
if (evt.info.code != "NetConnection.Connect.Success") {
return;
}
... ... @@ -232,8 +254,12 @@ package
if (evt.info.code == "NetStream.Video.DimensionChange") {
on_metadata(metadata);
}
// TODO: FIXME: failed event.
});
stream.play(url.substr(url.lastIndexOf("/")));
var streamName:String = url.substr(url.lastIndexOf("/"));
stream.play(streamName);
video = new Video();
video.width = _width;
... ... @@ -247,9 +273,9 @@ package
// lowest layer, for mask to cover it.
setChildIndex(video, 0);
});
this.conn.connect(this.url.substr(0, this.url.lastIndexOf("/")));
return 0;
var tcUrl:String = this.url.substr(0, this.url.lastIndexOf("/"));
this.conn.connect(tcUrl);
}
private function on_metadata(metadata:Object):void {
... ...