diff --git a/trunk/research/players/img/tooltip.png b/trunk/research/players/img/tooltip.png
new file mode 100644
index 000000000..eaee2aebc
Binary files /dev/null and b/trunk/research/players/img/tooltip.png differ
diff --git a/trunk/research/players/js/srs.js b/trunk/research/players/js/srs.js
index 47b9bcf7c..13b3acc0e 100755
--- a/trunk/research/players/js/srs.js
+++ b/trunk/research/players/js/srs.js
@@ -1,3 +1,6 @@
+/**
+* update the navigator, add same query string.
+*/
function update_nav() {
$("#nav_srs_player").attr("href", "srs_player.html" + window.location.search);
$("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search);
@@ -7,6 +10,9 @@ function update_nav() {
$("#nav_vlc").attr("href", "vlc.html" + window.location.search);
}
+/**
+* parse the query string to object.
+*/
function parse_query_string(){
var query_string = String(window.location.search).replace(" ", "").split("?")[1];
if(query_string == undefined){
@@ -60,6 +66,11 @@ function build_default_hls_url() {
return "http://" + vhost + ":" + port + "/" + app + "/" + stream + ".m3u8";
}
+/**
+* initialize the page.
+* @param rtmp_url the rtmp stream url to play
+* @param hls_url the hls stream url to play
+*/
function srs_init(rtmp_url, hls_url) {
update_nav();
@@ -70,3 +81,146 @@ function srs_init(rtmp_url, hls_url) {
$(hls_url).val(build_default_hls_url());
}
}
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/**
+* the SrsPlayer object.
+*/
+function SrsPlayer(container, stream_url, width, height, buffer_time) {
+ if (!SrsPlayer.__id) {
+ SrsPlayer.__id = 100;
+ }
+ if (!SrsPlayer.__players) {
+ SrsPlayer.__players = [];
+ }
+
+ SrsPlayer.__players.push(this);
+
+ this.container = container;
+ this.stream_url = stream_url;
+ this.width = width;
+ this.height = height;
+ this.buffer_time = buffer_time;
+ this.id = SrsPlayer.__id++;
+ this.callbackObj = null;
+
+ // callback set the following values.
+ this.meatadata = {}; // for on_player_metadata
+}
+/**
+* user can set some callback, then start the player.
+* callbacks:
+* on_player_ready():int, when srs player ready, user can play.
+* on_player_metadata(metadata:Object):int, when srs player get metadata.
+*/
+SrsPlayer.prototype.start = function() {
+ // embed the flash.
+ var flashvars = {};
+ flashvars.id = this.id;
+ flashvars.on_player_ready = "__srs_on_player_ready";
+ flashvars.on_player_metadata = "__srs_on_player_metadata";
+
+ var params = {};
+ params.wmode = "opaque";
+ params.allowFullScreen = "true";
+ params.allowScriptAccess = "always";
+
+ var attributes = {};
+
+ var self = this;
+
+ swfobject.embedSWF(
+ "srs_player/release/srs_player.swf", this.container,
+ this.width, this.height,
+ "11.1", "js/AdobeFlashPlayerInstall.swf",
+ flashvars, params, attributes,
+ function(callbackObj){
+ self.callbackObj = callbackObj;
+ }
+ );
+
+ return this;
+}
+SrsPlayer.prototype.play = function() {
+ return 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++) {
+ var player = SrsPlayer.__players[i];
+
+ if (player.id != this.id) {
+ continue;
+ }
+
+ SrsPlayer.__players.splice(i, 1);
+ break;
+ }
+ return this.callbackObj.ref.__stop();
+}
+SrsPlayer.prototype.pause = function() {
+ return this.callbackObj.ref.__pause();
+}
+SrsPlayer.prototype.resume = function() {
+ return this.callbackObj.ref.__resume();
+}
+/**
+* to set the DAR, for example, DAR=16:9
+* @param num, for example, 9.
+* use metadata height if 0.
+* use user specified height if -1.
+* @param den, for example, 16.
+* use metadata width if 0.
+* use user specified width if -1.
+*/
+SrsPlayer.prototype.dar = function(num, den) {
+ return this.callbackObj.ref.__dar(num, den);
+}
+/**
+* set the fullscreen size data.
+* @refer the refer fullscreen mode. it can be:
+* video: use video orignal size.
+* screen: use screen size to rescale video.
+* @param percent, the rescale percent, where
+* 100 means 100%.
+*/
+SrsPlayer.prototype.set_fs = function(refer, percent) {
+ return this.callbackObj.ref.__set_fs(refer, percent);
+}
+SrsPlayer.prototype.on_player_ready = function() {
+ return this.play();
+}
+SrsPlayer.prototype.on_player_metadata = function(metadata) {
+ return 0;
+}
+function __srs_on_player_ready(id) {
+ for (var i = 0; i < SrsPlayer.__players.length; i++) {
+ var player = SrsPlayer.__players[i];
+
+ if (player.id != id) {
+ continue;
+ }
+
+ return player.on_player_ready();
+ }
+
+ throw new Error("player not found. id=" + id);
+}
+function __srs_on_player_metadata(id, metadata) {
+ for (var i = 0; i < SrsPlayer.__players.length; i++) {
+ var player = SrsPlayer.__players[i];
+
+ if (player.id != id) {
+ continue;
+ }
+
+ // user may override the on_player_metadata,
+ // so set the data before invoke it.
+ player.metadata = metadata;
+
+ return player.on_player_metadata(metadata);
+ }
+
+ throw new Error("player not found. id=" + id);
+}
diff --git a/trunk/research/players/srs_player.html b/trunk/research/players/srs_player.html
index 988ae3ba4..2ec9c81ed 100755
--- a/trunk/research/players/srs_player.html
+++ b/trunk/research/players/srs_player.html
@@ -14,13 +14,30 @@
}
@@ -278,17 +184,37 @@
diff --git a/trunk/research/players/srs_player/release/srs_player.swf b/trunk/research/players/srs_player/release/srs_player.swf
index 69e20cfb1..02f1ae84c 100755
Binary files a/trunk/research/players/srs_player/release/srs_player.swf and b/trunk/research/players/srs_player/release/srs_player.swf differ
diff --git a/trunk/research/players/srs_player/src/srs_player.as b/trunk/research/players/srs_player/src/srs_player.as
index 54ddcd651..1f4b3691a 100755
--- a/trunk/research/players/srs_player/src/srs_player.as
+++ b/trunk/research/players/srs_player/src/srs_player.as
@@ -2,13 +2,17 @@ package
{
import flash.display.Sprite;
import flash.display.StageAlign;
+ import flash.display.StageDisplayState;
import flash.display.StageScaleMode;
import flash.events.Event;
+ import flash.events.FullScreenEvent;
+ import flash.events.MouseEvent;
import flash.events.NetStatusEvent;
import flash.external.ExternalInterface;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
+ import flash.system.Security;
import flash.ui.ContextMenu;
import flash.ui.ContextMenuItem;
import flash.utils.setTimeout;
@@ -23,18 +27,29 @@ package
// play param url.
private var url:String = null;
- // play param, user set width
+ // play param, user set width and height
private var w:int = 0;
- // play param, user set height.
private var h:int = 0;
+ // user set dar den:num
+ private var dar_num:int = 0;
+ private var dar_den:int = 0;
+ // user set fs(fullscreen) refer and percent.
+ private var fs_refer:String = null;
+ private var fs_percent:int = 0;
private var conn:NetConnection = null;
private var stream:NetStream = null;
private var video:Video = null;
private var metadata:Object = {};
+ // flash donot allow js to set to fullscreen,
+ // only allow user click to enter fullscreen.
+ private var fs_mask:Sprite = new Sprite();
+
public function srs_player()
{
+ flash.system.Security.allowDomain("*");
+
if (!this.stage) {
this.addEventListener(Event.ADDED_TO_STAGE, this.onAddToStage);
} else {
@@ -46,6 +61,12 @@ package
this.stage.align = StageAlign.TOP_LEFT;
this.stage.scaleMode = StageScaleMode.NO_SCALE;
+ this.stage.addEventListener(FullScreenEvent.FULL_SCREEN, this.on_stage_fullscreen);
+
+ this.addChild(this.fs_mask);
+ this.fs_mask.buttonMode = true;
+ this.fs_mask.addEventListener(MouseEvent.CLICK, on_user_click_video);
+
this.contextMenu = new ContextMenu();
this.contextMenu.hideBuiltInItems();
@@ -62,13 +83,21 @@ package
this.on_player_ready = flashvars.on_player_ready;
this.on_player_metadata = flashvars.on_player_metadata;
- flash.utils.setTimeout(this.onJsReady, 0);
+ flash.utils.setTimeout(this.on_js_ready, 0);
}
- private function onJsReady():void {
+ private function on_stage_fullscreen(evt:FullScreenEvent):void {
+ if (!evt.fullScreen) {
+ execute_user_set_dar();
+ } else {
+ execute_user_enter_fullscreen();
+ }
+ }
+
+ private function on_js_ready():void {
if (!flash.external.ExternalInterface.available) {
trace("js not ready, try later.");
- flash.utils.setTimeout(this.onJsReady, 100);
+ flash.utils.setTimeout(this.on_js_ready, 100);
return;
}
@@ -77,6 +106,7 @@ package
flash.external.ExternalInterface.addCallback("__pause", this.js_call_pause);
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);
var code:int = flash.external.ExternalInterface.call(this.on_player_ready, this.id);
if (code != 0) {
@@ -84,14 +114,14 @@ package
}
}
- public function js_call_pause():int {
+ private function js_call_pause():int {
if (this.stream) {
this.stream.pause();
}
return 0;
}
- public function js_call_resume():int {
+ private function js_call_resume():int {
if (this.stream) {
this.stream.resume();
}
@@ -99,34 +129,54 @@ package
}
/**
- * to set the DAR, for example, DAR=16:9
- * @param num, for example, 9.
- * @param den, for example, 16.
+ * to set the DAR, for example, DAR=16:9
+ * @param num, for example, 9.
+ * use metadata height if 0.
+ * use user specified height if -1.
+ * @param den, for example, 16.
+ * use metadata width if 0.
+ * use user specified width if -1.
+ */
+ private function js_call_dar(num:int, den:int):int {
+ dar_num = num;
+ dar_den = den;
+
+ flash.utils.setTimeout(execute_user_set_dar, 0);
+ return 0;
+ }
+
+ /**
+ * set the fullscreen size data.
+ * @refer the refer fullscreen mode. it can be:
+ * video: use video orignal size.
+ * screen: use screen size to rescale video.
+ * @param percent, the rescale percent, where
+ * 100 means 100%.
+ */
+ private function js_call_set_fs_size(refer:String, percent:int):int {
+ fs_refer = refer;
+ fs_percent = percent;
+
+ return 0;
+ }
+ /**
+ * js cannot enter the fullscreen mode, user must click to.
*/
- public function js_call_dar(num:int, den:int):int {
- if (this.video && num > 0 && den > 0 && this.video.width > 0) {
- // set DAR.
- // calc the height by DAR
- var _height:int = this.w * num / den;
- if (_height <= this.h) {
- this.video.width = this.w;
- this.video.height = _height;
- } else {
- // height overflow, calc the width by DAR
- var _width:int = this.h * den / num;
-
- this.video.width = _width;
- this.video.height = this.h;
- }
-
- // align center.
- this.video.y = (this.h - this.video.height) / 2;
- this.video.x = (this.w - this.video.width) / 2;
+ private function on_user_click_video(evt:MouseEvent):void {
+ if (!this.stage.allowsFullScreen) {
+ trace("donot allow fullscreen.");
+ return;
+ }
+
+ // enter fullscreen to get the fullscreen size correctly.
+ if (this.stage.displayState == StageDisplayState.FULL_SCREEN) {
+ this.stage.displayState = StageDisplayState.NORMAL;
+ } else {
+ this.stage.displayState = StageDisplayState.FULL_SCREEN;
}
- return 0;
}
- public function js_call_stop():int {
+ private function js_call_stop():int {
if (this.stream) {
this.stream.close();
this.stream = null;
@@ -143,17 +193,24 @@ package
return 0;
}
- public function js_call_play(url:String, _width:int, _height:int, _buffer_time:Number):int {
+ private function draw_black_background(_width:int, _height:int):void {
+ // draw black bg.
+ this.graphics.beginFill(0x00, 1.0);
+ this.graphics.drawRect(0, 0, _width, _height);
+ this.graphics.endFill();
+
+ // draw the fs mask.
+ this.fs_mask.graphics.beginFill(0xff0000, 0);
+ this.fs_mask.graphics.drawRect(0, 0, _width, _height);
+ this.fs_mask.graphics.endFill();
+ }
+
+ private function js_call_play(url:String, _width:int, _height:int, _buffer_time:Number):int {
this.url = url;
this.w = _width;
this.h = _height;
trace("start to play url: " + this.url + ", w=" + this.w + ", h=" + this.h);
- // draw black bg.
- this.graphics.beginFill(0x00, 1.0);
- this.graphics.drawRect(0, 0, this.w, this.h);
- this.graphics.endFill();
-
js_call_stop();
this.conn = new NetConnection();
@@ -184,6 +241,11 @@ package
video.attachNetStream(stream);
video.smoothing = true;
addChild(video);
+
+ draw_black_background(_width, _height);
+
+ // lowest layer, for mask to cover it.
+ setChildIndex(video, 0);
});
this.conn.connect(this.url.substr(0, this.url.lastIndexOf("/")));
@@ -204,13 +266,37 @@ package
contextMenu.customItems = customItems;
// for js.
+ var obj:Object = get_video_size_object();
+
+ obj.server = 'srs';
+ obj.contributor = 'winlin';
+
+ if (metadata.hasOwnProperty("server")) {
+ obj.server = metadata.server;
+ }
+ if (metadata.hasOwnProperty("contributor")) {
+ obj.contributor = metadata.contributor;
+ }
+
+ var code:int = flash.external.ExternalInterface.call(on_player_metadata, id, obj);
+ if (code != 0) {
+ throw new Error("callback on_player_metadata failed. code=" + code);
+ }
+ }
+
+ /**
+ * get the "right" size of video,
+ * 1. initialize with the original video object size.
+ * 2. override with metadata size if specified.
+ * 3. override with codec size if specified.
+ */
+ private function get_video_size_object():Object {
var obj:Object = {
width: video.width,
- height: video.height,
- server: 'srs',
- contributor: 'winlin'
+ height: video.height
};
+ // override with metadata size.
if (metadata.hasOwnProperty("width")) {
obj.width = metadata.width;
}
@@ -218,6 +304,7 @@ package
obj.height = metadata.height;
}
+ // override with codec size.
if (video.videoWidth > 0) {
obj.width = video.videoWidth;
}
@@ -225,17 +312,110 @@ package
obj.height = video.videoHeight;
}
- if (metadata.hasOwnProperty("server")) {
- obj.server = metadata.server;
+ return obj;
+ }
+
+ /**
+ * execute the enter fullscreen action.
+ */
+ private function execute_user_enter_fullscreen():void {
+ if (!fs_refer || fs_percent <= 0) {
+ return;
}
- if (metadata.hasOwnProperty("contributor")) {
- obj.contributor = metadata.contributor;
+
+ // change to video size if refer to video.
+ var obj:Object = get_video_size_object();
+
+ // get the DAR
+ var num:int = dar_num;
+ var den:int = dar_den;
+
+ if (num == 0) {
+ num = obj.height;
+ }
+ if (num == -1) {
+ num = this.stage.fullScreenHeight;
}
- var code:int = flash.external.ExternalInterface.call(on_player_metadata, id, obj);
- if (code != 0) {
- throw new Error("callback on_player_metadata failed. code=" + code);
+ if (den == 0) {
+ den = obj.width;
+ }
+ if (den == -1) {
+ den = this.stage.fullScreenWidth;
+ }
+
+ // for refer is screen.
+ if (fs_refer == "screen") {
+ obj = {
+ width: this.stage.fullScreenWidth,
+ height: this.stage.fullScreenHeight
+ };
}
+
+ // rescale to fs
+ update_video_size(num, den, obj.width * fs_percent / 100, obj.height * fs_percent / 100, this.stage.fullScreenWidth, this.stage.fullScreenHeight);
+ }
+
+ /**
+ * for user set dar, or leave fullscreen to recover the dar.
+ */
+ private function execute_user_set_dar():void {
+ // get the DAR
+ var num:int = dar_num;
+ var den:int = dar_den;
+
+ var obj:Object = get_video_size_object();
+
+ if (num == 0) {
+ num = obj.height;
+ }
+ if (num == -1) {
+ num = this.h;
+ }
+
+ if (den == 0) {
+ den = obj.width;
+ }
+ if (den == -1) {
+ den = this.w;
+ }
+
+ update_video_size(num, den, this.w, this.h, this.w, this.h);
+ }
+
+ /**
+ * update the video width and height,
+ * according to the specifies DAR(den:num) and max size(w:h).
+ * set the position of video(x,y) specifies by size(sw:sh),
+ * and update the bg to size(sw:sh).
+ * @param _num/_den the DAR. use to rescale the player together with paper size.
+ * @param _w/_h the video draw paper size. used to rescale the player together with DAR.
+ * @param _sw/_wh the stage size, >= paper size. used to center the player.
+ */
+ private function update_video_size(_num:int, _den:int, _w:int, _h:int, _sw:int, _sh:int):void {
+ if (!this.video || _num <= 0 || _den <= 0) {
+ return;
+ }
+
+ // set DAR.
+ // calc the height by DAR
+ var _height:int = _w * _num / _den;
+ if (_height <= _h) {
+ this.video.width = _w;
+ this.video.height = _height;
+ } else {
+ // height overflow, calc the width by DAR
+ var _width:int = _h * _den / _num;
+
+ this.video.width = _width;
+ this.video.height = _h;
+ }
+
+ // align center.
+ this.video.x = (_sw - this.video.width) / 2;
+ this.video.y = (_sh - this.video.height) / 2;
+
+ draw_black_background(_sw, _sh);
}
}
}
\ No newline at end of file