winlin

add fullscreen event and rescale

  1 +/**
  2 +* update the navigator, add same query string.
  3 +*/
1 function update_nav() { 4 function update_nav() {
2 $("#nav_srs_player").attr("href", "srs_player.html" + window.location.search); 5 $("#nav_srs_player").attr("href", "srs_player.html" + window.location.search);
3 $("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search); 6 $("#nav_srs_publisher").attr("href", "srs_publisher.html" + window.location.search);
@@ -7,6 +10,9 @@ function update_nav() { @@ -7,6 +10,9 @@ function update_nav() {
7 $("#nav_vlc").attr("href", "vlc.html" + window.location.search); 10 $("#nav_vlc").attr("href", "vlc.html" + window.location.search);
8 } 11 }
9 12
  13 +/**
  14 +* parse the query string to object.
  15 +*/
10 function parse_query_string(){ 16 function parse_query_string(){
11 var query_string = String(window.location.search).replace(" ", "").split("?")[1]; 17 var query_string = String(window.location.search).replace(" ", "").split("?")[1];
12 if(query_string == undefined){ 18 if(query_string == undefined){
@@ -60,6 +66,11 @@ function build_default_hls_url() { @@ -60,6 +66,11 @@ function build_default_hls_url() {
60 return "http://" + vhost + ":" + port + "/" + app + "/" + stream + ".m3u8"; 66 return "http://" + vhost + ":" + port + "/" + app + "/" + stream + ".m3u8";
61 } 67 }
62 68
  69 +/**
  70 +* initialize the page.
  71 +* @param rtmp_url the rtmp stream url to play
  72 +* @param hls_url the hls stream url to play
  73 +*/
63 function srs_init(rtmp_url, hls_url) { 74 function srs_init(rtmp_url, hls_url) {
64 update_nav(); 75 update_nav();
65 76
@@ -70,3 +81,146 @@ function srs_init(rtmp_url, hls_url) { @@ -70,3 +81,146 @@ function srs_init(rtmp_url, hls_url) {
70 $(hls_url).val(build_default_hls_url()); 81 $(hls_url).val(build_default_hls_url());
71 } 82 }
72 } 83 }
  84 +
  85 +//////////////////////////////////////////////////////////////////////////////////
  86 +//////////////////////////////////////////////////////////////////////////////////
  87 +//////////////////////////////////////////////////////////////////////////////////
  88 +/**
  89 +* the SrsPlayer object.
  90 +*/
  91 +function SrsPlayer(container, stream_url, width, height, buffer_time) {
  92 + if (!SrsPlayer.__id) {
  93 + SrsPlayer.__id = 100;
  94 + }
  95 + if (!SrsPlayer.__players) {
  96 + SrsPlayer.__players = [];
  97 + }
  98 +
  99 + SrsPlayer.__players.push(this);
  100 +
  101 + this.container = container;
  102 + this.stream_url = stream_url;
  103 + this.width = width;
  104 + this.height = height;
  105 + this.buffer_time = buffer_time;
  106 + this.id = SrsPlayer.__id++;
  107 + this.callbackObj = null;
  108 +
  109 + // callback set the following values.
  110 + this.meatadata = {}; // for on_player_metadata
  111 +}
  112 +/**
  113 +* user can set some callback, then start the player.
  114 +* callbacks:
  115 +* on_player_ready():int, when srs player ready, user can play.
  116 +* on_player_metadata(metadata:Object):int, when srs player get metadata.
  117 +*/
  118 +SrsPlayer.prototype.start = function() {
  119 + // embed the flash.
  120 + var flashvars = {};
  121 + flashvars.id = this.id;
  122 + flashvars.on_player_ready = "__srs_on_player_ready";
  123 + flashvars.on_player_metadata = "__srs_on_player_metadata";
  124 +
  125 + var params = {};
  126 + params.wmode = "opaque";
  127 + params.allowFullScreen = "true";
  128 + params.allowScriptAccess = "always";
  129 +
  130 + var attributes = {};
  131 +
  132 + var self = this;
  133 +
  134 + swfobject.embedSWF(
  135 + "srs_player/release/srs_player.swf", this.container,
  136 + this.width, this.height,
  137 + "11.1", "js/AdobeFlashPlayerInstall.swf",
  138 + flashvars, params, attributes,
  139 + function(callbackObj){
  140 + self.callbackObj = callbackObj;
  141 + }
  142 + );
  143 +
  144 + return this;
  145 +}
  146 +SrsPlayer.prototype.play = function() {
  147 + return this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time);
  148 +}
  149 +SrsPlayer.prototype.stop = function() {
  150 + for (var i = 0; i < SrsPlayer.__players.length; i++) {
  151 + var player = SrsPlayer.__players[i];
  152 +
  153 + if (player.id != this.id) {
  154 + continue;
  155 + }
  156 +
  157 + SrsPlayer.__players.splice(i, 1);
  158 + break;
  159 + }
  160 + return this.callbackObj.ref.__stop();
  161 +}
  162 +SrsPlayer.prototype.pause = function() {
  163 + return this.callbackObj.ref.__pause();
  164 +}
  165 +SrsPlayer.prototype.resume = function() {
  166 + return this.callbackObj.ref.__resume();
  167 +}
  168 +/**
  169 +* to set the DAR, for example, DAR=16:9
  170 +* @param num, for example, 9.
  171 +* use metadata height if 0.
  172 +* use user specified height if -1.
  173 +* @param den, for example, 16.
  174 +* use metadata width if 0.
  175 +* use user specified width if -1.
  176 +*/
  177 +SrsPlayer.prototype.dar = function(num, den) {
  178 + return this.callbackObj.ref.__dar(num, den);
  179 +}
  180 +/**
  181 +* set the fullscreen size data.
  182 +* @refer the refer fullscreen mode. it can be:
  183 +* video: use video orignal size.
  184 +* screen: use screen size to rescale video.
  185 +* @param percent, the rescale percent, where
  186 +* 100 means 100%.
  187 +*/
  188 +SrsPlayer.prototype.set_fs = function(refer, percent) {
  189 + return this.callbackObj.ref.__set_fs(refer, percent);
  190 +}
  191 +SrsPlayer.prototype.on_player_ready = function() {
  192 + return this.play();
  193 +}
  194 +SrsPlayer.prototype.on_player_metadata = function(metadata) {
  195 + return 0;
  196 +}
  197 +function __srs_on_player_ready(id) {
  198 + for (var i = 0; i < SrsPlayer.__players.length; i++) {
  199 + var player = SrsPlayer.__players[i];
  200 +
  201 + if (player.id != id) {
  202 + continue;
  203 + }
  204 +
  205 + return player.on_player_ready();
  206 + }
  207 +
  208 + throw new Error("player not found. id=" + id);
  209 +}
  210 +function __srs_on_player_metadata(id, metadata) {
  211 + for (var i = 0; i < SrsPlayer.__players.length; i++) {
  212 + var player = SrsPlayer.__players[i];
  213 +
  214 + if (player.id != id) {
  215 + continue;
  216 + }
  217 +
  218 + // user may override the on_player_metadata,
  219 + // so set the data before invoke it.
  220 + player.metadata = metadata;
  221 +
  222 + return player.on_player_metadata(metadata);
  223 + }
  224 +
  225 + throw new Error("player not found. id=" + id);
  226 +}
@@ -14,13 +14,30 @@ @@ -14,13 +14,30 @@
14 } 14 }
15 </style> 15 </style>
16 <script type="text/javascript"> 16 <script type="text/javascript">
17 - var active_dar = null;  
18 - function select_dar(dar_id) {  
19 - if (active_dar) {  
20 - active_dar.removeClass("active"); 17 + var srs_player = null;
  18 +
  19 + var __active_dar = null;
  20 + function select_dar(dar_id, num, den) {
  21 + srs_player.dar(num, den);
  22 +
  23 + if (__active_dar) {
  24 + __active_dar.removeClass("active");
21 } 25 }
22 - active_dar = $(dar_id).parent();  
23 - active_dar.addClass("active"); 26 +
  27 + __active_dar = $(dar_id).parent();
  28 + __active_dar.addClass("active");
  29 + }
  30 +
  31 + var __active_size = null;
  32 + function select_fs_size(size_id, refer, percent) {
  33 + srs_player.set_fs(refer, percent);
  34 +
  35 + if (__active_size) {
  36 + __active_size.removeClass("active");
  37 + }
  38 +
  39 + __active_size = $(size_id).parent();
  40 + __active_size.addClass("active");
24 } 41 }
25 42
26 $(function(){ 43 $(function(){
@@ -29,9 +46,15 @@ @@ -29,9 +46,15 @@
29 // url set to: rtmp://demo:1935/live/livestream 46 // url set to: rtmp://demo:1935/live/livestream
30 srs_init($("#txt_url")); 47 srs_init($("#txt_url"));
31 48
32 - var srs_player = null;  
33 - 49 + $("#fs_tips").tooltip({
  50 + title: "点击视频进入或退出全屏"
  51 + });
  52 +
34 $("#main_modal").on("show", function(){ 53 $("#main_modal").on("show", function(){
  54 + if (srs_player) {
  55 + return;
  56 + }
  57 +
35 $("#div_container").remove(); 58 $("#div_container").remove();
36 59
37 var obj = $("<div/>"); 60 var obj = $("<div/>");
@@ -51,16 +74,22 @@ @@ -51,16 +74,22 @@
51 } 74 }
52 srs_player.on_player_metadata = function(metadata) { 75 srs_player.on_player_metadata = function(metadata) {
53 $("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")"); 76 $("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")");
54 - srs_player.dar(0, 0);  
55 - select_dar("#btn_dar_original");  
56 - 77 + select_dar("#btn_dar_original", 0, 0);
  78 + select_fs_size("#btn_fs_size_screen_100", "screen", 100);
57 return 0; 79 return 0;
58 } 80 }
59 srs_player.start(); 81 srs_player.start();
60 }); 82 });
61 83
62 $("#main_modal").on("hide", function(){ 84 $("#main_modal").on("hide", function(){
63 - srs_player.stop(); 85 + if ($("#main_modal").is(":visible")) {
  86 + return;
  87 + }
  88 +
  89 + if (srs_player) {
  90 + srs_player.stop();
  91 + srs_player = null;
  92 + }
64 }); 93 });
65 94
66 $("#btn_play").click(function(){ 95 $("#btn_play").click(function(){
@@ -68,177 +97,54 @@ @@ -68,177 +97,54 @@
68 }); 97 });
69 98
70 $("#btn_pause").click(function(){ 99 $("#btn_pause").click(function(){
71 - if ($("#btn_pause").text() == "暂停") {  
72 - $("#btn_pause").text("继续"); 100 + if ($("#btn_pause").text() == "暂停播放") {
  101 + $("#btn_pause").text("继续播放");
73 srs_player.pause(); 102 srs_player.pause();
74 } else { 103 } else {
75 - $("#btn_pause").text("暂停"); 104 + $("#btn_pause").text("暂停播放");
76 srs_player.resume(); 105 srs_player.resume();
77 } 106 }
78 }); 107 });
79 108
80 - $("#btn_dar_original").click(function(){  
81 - srs_player.dar(0, 0);  
82 - select_dar("#btn_dar_original");  
83 - });  
84 - $("#btn_dar_21_9").click(function(){  
85 - srs_player.dar(9, 21);  
86 - select_dar("#btn_dar_21_9");  
87 - });  
88 - $("#btn_dar_16_9").click(function(){  
89 - srs_player.dar(9, 16);  
90 - select_dar("#btn_dar_16_9");  
91 - });  
92 - $("#btn_dar_4_3").click(function(){  
93 - srs_player.dar(3, 4);  
94 - select_dar("#btn_dar_4_3");  
95 - });  
96 - $("#btn_dar_fill").click(function(){  
97 - srs_player.dar(-1, -1);  
98 - select_dar("#btn_dar_fill");  
99 - });  
100 - });  
101 -  
102 - /*  
103 - * the SrsPlayer object.  
104 - */  
105 - function SrsPlayer(container, stream_url, width, height, buffer_time) {  
106 - if (!SrsPlayer.__id) {  
107 - SrsPlayer.__id = 100;  
108 - }  
109 - if (!SrsPlayer.__players) {  
110 - SrsPlayer.__players = [];  
111 - }  
112 -  
113 - SrsPlayer.__players.push(this);  
114 -  
115 - this.container = container;  
116 - this.stream_url = stream_url;  
117 - this.width = width;  
118 - this.height = height;  
119 - this.buffer_time = buffer_time;  
120 - this.id = SrsPlayer.__id++;  
121 - this.callbackObj = null;  
122 -  
123 - // callback set the following values.  
124 - this.meatadata = {}; // for on_player_metadata  
125 - }  
126 - /*  
127 - * user can set some callback, then start the player.  
128 - * callbacks:  
129 - * on_player_ready():int, when srs player ready, user can play.  
130 - * on_player_metadata(metadata:Object):int, when srs player get metadata.  
131 - */  
132 - SrsPlayer.prototype.start = function() {  
133 - // embed the flash.  
134 - var flashvars = {};  
135 - flashvars.id = this.id;  
136 - flashvars.on_player_ready = "__srs_on_player_ready";  
137 - flashvars.on_player_metadata = "__srs_on_player_metadata";  
138 -  
139 - var params = {};  
140 - params.wmode = "opaque";  
141 - params.allowFullScreen = true;  
142 - params.allowScriptAccess = "always";  
143 -  
144 - var attributes = {};  
145 -  
146 - var self = this;  
147 -  
148 - swfobject.embedSWF(  
149 - "srs_player/release/srs_player.swf", this.container,  
150 - this.width, this.height,  
151 - "11.1", "js/AdobeFlashPlayerInstall.swf",  
152 - flashvars, params, attributes,  
153 - function(callbackObj){  
154 - self.callbackObj = callbackObj;  
155 - }  
156 - );  
157 -  
158 - return this;  
159 - }  
160 - SrsPlayer.prototype.play = function() {  
161 - return this.callbackObj.ref.__play(this.stream_url, this.width, this.height, this.buffer_time);  
162 - }  
163 - SrsPlayer.prototype.stop = function() {  
164 - for (var i = 0; i < SrsPlayer.__players.length; i++) {  
165 - var player = SrsPlayer.__players[i];  
166 -  
167 - if (player.id != this.id) {  
168 - continue;  
169 - }  
170 -  
171 - SrsPlayer.__players.splice(i, 1);  
172 - break;  
173 - }  
174 - return this.callbackObj.ref.__stop();  
175 - }  
176 - SrsPlayer.prototype.pause = function() {  
177 - return this.callbackObj.ref.__pause();  
178 - }  
179 - SrsPlayer.prototype.resume = function() {  
180 - return this.callbackObj.ref.__resume();  
181 - }  
182 - /*  
183 - * to set the DAR, for example, DAR=16:9  
184 - * @param num, for example, 9.  
185 - * use metadata height if 0.  
186 - * use user specified height if -1.  
187 - * @param den, for example, 16.  
188 - * use metadata width if 0.  
189 - * use user specified width if -1.  
190 - */  
191 - SrsPlayer.prototype.dar = function(num, den) {  
192 - if (num == 0 && this.metadata) {  
193 - num = this.metadata.height;  
194 - } else if (num == -1) {  
195 - num = this.height; 109 + if (true) {
  110 + $("#btn_dar_original").click(function(){
  111 + select_dar("#btn_dar_original", 0, 0);
  112 + });
  113 + $("#btn_dar_21_9").click(function(){
  114 + select_dar("#btn_dar_21_9", 9, 21);
  115 + });
  116 + $("#btn_dar_16_9").click(function(){
  117 + select_dar("#btn_dar_16_9", 9, 16);
  118 + });
  119 + $("#btn_dar_4_3").click(function(){
  120 + select_dar("#btn_dar_4_3", 3, 4);
  121 + });
  122 + $("#btn_dar_fill").click(function(){
  123 + select_dar("#btn_dar_fill", -1, -1);
  124 + });
196 } 125 }
197 126
198 - if (den == 0 && this.metadata) {  
199 - den = this.metadata.width;  
200 - } else if (den == -1) {  
201 - den = this.width; 127 + if (true) {
  128 + $("#btn_fs_size_video_100").click(function(){
  129 + select_fs_size("#btn_fs_size_video_100", "video", 100);
  130 + });
  131 + $("#btn_fs_size_video_75").click(function(){
  132 + select_fs_size("#btn_fs_size_video_75", "video", 75);
  133 + });
  134 + $("#btn_fs_size_video_50").click(function(){
  135 + select_fs_size("#btn_fs_size_video_50", "video", 50);
  136 + });
  137 + $("#btn_fs_size_screen_100").click(function(){
  138 + select_fs_size("#btn_fs_size_screen_100", "screen", 100);
  139 + });
  140 + $("#btn_fs_size_screen_75").click(function(){
  141 + select_fs_size("#btn_fs_size_screen_75", "screen", 75);
  142 + });
  143 + $("#btn_fs_size_screen_50").click(function(){
  144 + select_fs_size("#btn_fs_size_screen_50", "screen", 50);
  145 + });
202 } 146 }
203 -  
204 - return this.callbackObj.ref.__dar(num, den);  
205 - }  
206 - SrsPlayer.prototype.on_player_ready = function() {  
207 - return this.play();  
208 - }  
209 - SrsPlayer.prototype.on_player_metadata = function(metadata) {  
210 - return 0;  
211 - }  
212 - function __srs_on_player_ready(id) {  
213 - for (var i = 0; i < SrsPlayer.__players.length; i++) {  
214 - var player = SrsPlayer.__players[i];  
215 -  
216 - if (player.id != id) {  
217 - continue;  
218 - }  
219 -  
220 - return player.on_player_ready();  
221 - }  
222 -  
223 - throw new Error("player not found. id=" + id);  
224 - }  
225 - function __srs_on_player_metadata(id, metadata) {  
226 - for (var i = 0; i < SrsPlayer.__players.length; i++) {  
227 - var player = SrsPlayer.__players[i];  
228 -  
229 - if (player.id != id) {  
230 - continue;  
231 - }  
232 -  
233 - // user may override the on_player_metadata,  
234 - // so set the data before invoke it.  
235 - player.metadata = metadata;  
236 -  
237 - return player.on_player_metadata(metadata);  
238 - }  
239 -  
240 - throw new Error("player not found. id=" + id);  
241 - } 147 + });
242 </script> 148 </script>
243 </head> 149 </head>
244 <body> 150 <body>
@@ -278,17 +184,37 @@ @@ -278,17 +184,37 @@
278 </div> 184 </div>
279 <div class="modal-footer"> 185 <div class="modal-footer">
280 <div class="btn-group dropup"> 186 <div class="btn-group dropup">
281 - <button class="btn dropdown-toggle" data-toggle="dropdown">宽高比 <span class="caret"></span></button> 187 + <button class="btn dropdown-toggle" data-toggle="dropdown">
  188 + <a id="fs_tips" href="#" data-toggle="tooltip" data-placement="top" title="">
  189 + <img src="img/tooltip.png"/>
  190 + </a>
  191 + 全屏大小<span class="caret"></span>
  192 + </button>
  193 + <ul class="dropdown-menu">
  194 + <li><a id="btn_fs_size_screen_100" href="#">屏幕大小(100%)</a></li>
  195 + <li><a id="btn_fs_size_screen_75" href="#">屏幕大小(75%)</a></li>
  196 + <li><a id="btn_fs_size_screen_50" href="#">屏幕大小(50%)</a></li>
  197 + <li><a id="btn_fs_size_video_100" href="#">视频大小(100%)</a></li>
  198 + <li><a id="btn_fs_size_video_75" href="#">视频大小(75%)</a></li>
  199 + <li><a id="btn_fs_size_video_50" href="#">视频大小(50%)</a></li>
  200 + </ul>
  201 + </div>
  202 + <div class="btn-group dropup">
  203 + <button class="btn dropdown-toggle" data-toggle="dropdown">显示比例<span class="caret"></span></button>
282 <ul class="dropdown-menu"> 204 <ul class="dropdown-menu">
283 <li><a id="btn_dar_original" href="#">视频原始比例</a></li> 205 <li><a id="btn_dar_original" href="#">视频原始比例</a></li>
284 <li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li> 206 <li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li>
285 <li><a id="btn_dar_16_9" href="#">宽屏电影(16:9)</a></li> 207 <li><a id="btn_dar_16_9" href="#">宽屏电影(16:9)</a></li>
286 <li><a id="btn_dar_4_3" href="#">窄屏(4:3)</a></li> 208 <li><a id="btn_dar_4_3" href="#">窄屏(4:3)</a></li>
287 - <li><a id="btn_dar_fill" href="#">填充</a></li> 209 + <li><a id="btn_dar_fill" href="#">填充(容器比例)</a></li>
288 </ul> 210 </ul>
289 </div> 211 </div>
290 - <button id="btn_pause" class="btn">暂停</button>  
291 - <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭</button> 212 + <div class="btn-group dropup">
  213 + <button id="btn_pause" class="btn">暂停播放</button>
  214 + </div>
  215 + <div class="btn-group dropup">
  216 + <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭</button>
  217 + </div>
292 </div> 218 </div>
293 </div> 219 </div>
294 <hr> 220 <hr>
@@ -2,13 +2,17 @@ package @@ -2,13 +2,17 @@ package
2 { 2 {
3 import flash.display.Sprite; 3 import flash.display.Sprite;
4 import flash.display.StageAlign; 4 import flash.display.StageAlign;
  5 + import flash.display.StageDisplayState;
5 import flash.display.StageScaleMode; 6 import flash.display.StageScaleMode;
6 import flash.events.Event; 7 import flash.events.Event;
  8 + import flash.events.FullScreenEvent;
  9 + import flash.events.MouseEvent;
7 import flash.events.NetStatusEvent; 10 import flash.events.NetStatusEvent;
8 import flash.external.ExternalInterface; 11 import flash.external.ExternalInterface;
9 import flash.media.Video; 12 import flash.media.Video;
10 import flash.net.NetConnection; 13 import flash.net.NetConnection;
11 import flash.net.NetStream; 14 import flash.net.NetStream;
  15 + import flash.system.Security;
12 import flash.ui.ContextMenu; 16 import flash.ui.ContextMenu;
13 import flash.ui.ContextMenuItem; 17 import flash.ui.ContextMenuItem;
14 import flash.utils.setTimeout; 18 import flash.utils.setTimeout;
@@ -23,18 +27,29 @@ package @@ -23,18 +27,29 @@ package
23 27
24 // play param url. 28 // play param url.
25 private var url:String = null; 29 private var url:String = null;
26 - // play param, user set width 30 + // play param, user set width and height
27 private var w:int = 0; 31 private var w:int = 0;
28 - // play param, user set height.  
29 private var h:int = 0; 32 private var h:int = 0;
  33 + // user set dar den:num
  34 + private var dar_num:int = 0;
  35 + private var dar_den:int = 0;
  36 + // user set fs(fullscreen) refer and percent.
  37 + private var fs_refer:String = null;
  38 + private var fs_percent:int = 0;
30 39
31 private var conn:NetConnection = null; 40 private var conn:NetConnection = null;
32 private var stream:NetStream = null; 41 private var stream:NetStream = null;
33 private var video:Video = null; 42 private var video:Video = null;
34 private var metadata:Object = {}; 43 private var metadata:Object = {};
35 44
  45 + // flash donot allow js to set to fullscreen,
  46 + // only allow user click to enter fullscreen.
  47 + private var fs_mask:Sprite = new Sprite();
  48 +
36 public function srs_player() 49 public function srs_player()
37 { 50 {
  51 + flash.system.Security.allowDomain("*");
  52 +
38 if (!this.stage) { 53 if (!this.stage) {
39 this.addEventListener(Event.ADDED_TO_STAGE, this.onAddToStage); 54 this.addEventListener(Event.ADDED_TO_STAGE, this.onAddToStage);
40 } else { 55 } else {
@@ -46,6 +61,12 @@ package @@ -46,6 +61,12 @@ package
46 this.stage.align = StageAlign.TOP_LEFT; 61 this.stage.align = StageAlign.TOP_LEFT;
47 this.stage.scaleMode = StageScaleMode.NO_SCALE; 62 this.stage.scaleMode = StageScaleMode.NO_SCALE;
48 63
  64 + this.stage.addEventListener(FullScreenEvent.FULL_SCREEN, this.on_stage_fullscreen);
  65 +
  66 + this.addChild(this.fs_mask);
  67 + this.fs_mask.buttonMode = true;
  68 + this.fs_mask.addEventListener(MouseEvent.CLICK, on_user_click_video);
  69 +
49 this.contextMenu = new ContextMenu(); 70 this.contextMenu = new ContextMenu();
50 this.contextMenu.hideBuiltInItems(); 71 this.contextMenu.hideBuiltInItems();
51 72
@@ -62,13 +83,21 @@ package @@ -62,13 +83,21 @@ package
62 this.on_player_ready = flashvars.on_player_ready; 83 this.on_player_ready = flashvars.on_player_ready;
63 this.on_player_metadata = flashvars.on_player_metadata; 84 this.on_player_metadata = flashvars.on_player_metadata;
64 85
65 - flash.utils.setTimeout(this.onJsReady, 0); 86 + flash.utils.setTimeout(this.on_js_ready, 0);
66 } 87 }
67 88
68 - private function onJsReady():void { 89 + private function on_stage_fullscreen(evt:FullScreenEvent):void {
  90 + if (!evt.fullScreen) {
  91 + execute_user_set_dar();
  92 + } else {
  93 + execute_user_enter_fullscreen();
  94 + }
  95 + }
  96 +
  97 + private function on_js_ready():void {
69 if (!flash.external.ExternalInterface.available) { 98 if (!flash.external.ExternalInterface.available) {
70 trace("js not ready, try later."); 99 trace("js not ready, try later.");
71 - flash.utils.setTimeout(this.onJsReady, 100); 100 + flash.utils.setTimeout(this.on_js_ready, 100);
72 return; 101 return;
73 } 102 }
74 103
@@ -77,6 +106,7 @@ package @@ -77,6 +106,7 @@ package
77 flash.external.ExternalInterface.addCallback("__pause", this.js_call_pause); 106 flash.external.ExternalInterface.addCallback("__pause", this.js_call_pause);
78 flash.external.ExternalInterface.addCallback("__resume", this.js_call_resume); 107 flash.external.ExternalInterface.addCallback("__resume", this.js_call_resume);
79 flash.external.ExternalInterface.addCallback("__dar", this.js_call_dar); 108 flash.external.ExternalInterface.addCallback("__dar", this.js_call_dar);
  109 + flash.external.ExternalInterface.addCallback("__set_fs", this.js_call_set_fs_size);
80 110
81 var code:int = flash.external.ExternalInterface.call(this.on_player_ready, this.id); 111 var code:int = flash.external.ExternalInterface.call(this.on_player_ready, this.id);
82 if (code != 0) { 112 if (code != 0) {
@@ -84,14 +114,14 @@ package @@ -84,14 +114,14 @@ package
84 } 114 }
85 } 115 }
86 116
87 - public function js_call_pause():int { 117 + private function js_call_pause():int {
88 if (this.stream) { 118 if (this.stream) {
89 this.stream.pause(); 119 this.stream.pause();
90 } 120 }
91 return 0; 121 return 0;
92 } 122 }
93 123
94 - public function js_call_resume():int { 124 + private function js_call_resume():int {
95 if (this.stream) { 125 if (this.stream) {
96 this.stream.resume(); 126 this.stream.resume();
97 } 127 }
@@ -99,34 +129,54 @@ package @@ -99,34 +129,54 @@ package
99 } 129 }
100 130
101 /** 131 /**
102 - * to set the DAR, for example, DAR=16:9  
103 - * @param num, for example, 9.  
104 - * @param den, for example, 16. 132 + * to set the DAR, for example, DAR=16:9
  133 + * @param num, for example, 9.
  134 + * use metadata height if 0.
  135 + * use user specified height if -1.
  136 + * @param den, for example, 16.
  137 + * use metadata width if 0.
  138 + * use user specified width if -1.
  139 + */
  140 + private function js_call_dar(num:int, den:int):int {
  141 + dar_num = num;
  142 + dar_den = den;
  143 +
  144 + flash.utils.setTimeout(execute_user_set_dar, 0);
  145 + return 0;
  146 + }
  147 +
  148 + /**
  149 + * set the fullscreen size data.
  150 + * @refer the refer fullscreen mode. it can be:
  151 + * video: use video orignal size.
  152 + * screen: use screen size to rescale video.
  153 + * @param percent, the rescale percent, where
  154 + * 100 means 100%.
  155 + */
  156 + private function js_call_set_fs_size(refer:String, percent:int):int {
  157 + fs_refer = refer;
  158 + fs_percent = percent;
  159 +
  160 + return 0;
  161 + }
  162 + /**
  163 + * js cannot enter the fullscreen mode, user must click to.
105 */ 164 */
106 - public function js_call_dar(num:int, den:int):int {  
107 - if (this.video && num > 0 && den > 0 && this.video.width > 0) {  
108 - // set DAR.  
109 - // calc the height by DAR  
110 - var _height:int = this.w * num / den;  
111 - if (_height <= this.h) {  
112 - this.video.width = this.w;  
113 - this.video.height = _height;  
114 - } else {  
115 - // height overflow, calc the width by DAR  
116 - var _width:int = this.h * den / num;  
117 -  
118 - this.video.width = _width;  
119 - this.video.height = this.h;  
120 - }  
121 -  
122 - // align center.  
123 - this.video.y = (this.h - this.video.height) / 2;  
124 - this.video.x = (this.w - this.video.width) / 2; 165 + private function on_user_click_video(evt:MouseEvent):void {
  166 + if (!this.stage.allowsFullScreen) {
  167 + trace("donot allow fullscreen.");
  168 + return;
  169 + }
  170 +
  171 + // enter fullscreen to get the fullscreen size correctly.
  172 + if (this.stage.displayState == StageDisplayState.FULL_SCREEN) {
  173 + this.stage.displayState = StageDisplayState.NORMAL;
  174 + } else {
  175 + this.stage.displayState = StageDisplayState.FULL_SCREEN;
125 } 176 }
126 - return 0;  
127 } 177 }
128 178
129 - public function js_call_stop():int { 179 + private function js_call_stop():int {
130 if (this.stream) { 180 if (this.stream) {
131 this.stream.close(); 181 this.stream.close();
132 this.stream = null; 182 this.stream = null;
@@ -143,17 +193,24 @@ package @@ -143,17 +193,24 @@ package
143 return 0; 193 return 0;
144 } 194 }
145 195
146 - public function js_call_play(url:String, _width:int, _height:int, _buffer_time:Number):int { 196 + private function draw_black_background(_width:int, _height:int):void {
  197 + // draw black bg.
  198 + this.graphics.beginFill(0x00, 1.0);
  199 + this.graphics.drawRect(0, 0, _width, _height);
  200 + this.graphics.endFill();
  201 +
  202 + // draw the fs mask.
  203 + this.fs_mask.graphics.beginFill(0xff0000, 0);
  204 + this.fs_mask.graphics.drawRect(0, 0, _width, _height);
  205 + this.fs_mask.graphics.endFill();
  206 + }
  207 +
  208 + private function js_call_play(url:String, _width:int, _height:int, _buffer_time:Number):int {
147 this.url = url; 209 this.url = url;
148 this.w = _width; 210 this.w = _width;
149 this.h = _height; 211 this.h = _height;
150 trace("start to play url: " + this.url + ", w=" + this.w + ", h=" + this.h); 212 trace("start to play url: " + this.url + ", w=" + this.w + ", h=" + this.h);
151 213
152 - // draw black bg.  
153 - this.graphics.beginFill(0x00, 1.0);  
154 - this.graphics.drawRect(0, 0, this.w, this.h);  
155 - this.graphics.endFill();  
156 -  
157 js_call_stop(); 214 js_call_stop();
158 215
159 this.conn = new NetConnection(); 216 this.conn = new NetConnection();
@@ -184,6 +241,11 @@ package @@ -184,6 +241,11 @@ package
184 video.attachNetStream(stream); 241 video.attachNetStream(stream);
185 video.smoothing = true; 242 video.smoothing = true;
186 addChild(video); 243 addChild(video);
  244 +
  245 + draw_black_background(_width, _height);
  246 +
  247 + // lowest layer, for mask to cover it.
  248 + setChildIndex(video, 0);
187 }); 249 });
188 this.conn.connect(this.url.substr(0, this.url.lastIndexOf("/"))); 250 this.conn.connect(this.url.substr(0, this.url.lastIndexOf("/")));
189 251
@@ -204,13 +266,37 @@ package @@ -204,13 +266,37 @@ package
204 contextMenu.customItems = customItems; 266 contextMenu.customItems = customItems;
205 267
206 // for js. 268 // for js.
  269 + var obj:Object = get_video_size_object();
  270 +
  271 + obj.server = 'srs';
  272 + obj.contributor = 'winlin';
  273 +
  274 + if (metadata.hasOwnProperty("server")) {
  275 + obj.server = metadata.server;
  276 + }
  277 + if (metadata.hasOwnProperty("contributor")) {
  278 + obj.contributor = metadata.contributor;
  279 + }
  280 +
  281 + var code:int = flash.external.ExternalInterface.call(on_player_metadata, id, obj);
  282 + if (code != 0) {
  283 + throw new Error("callback on_player_metadata failed. code=" + code);
  284 + }
  285 + }
  286 +
  287 + /**
  288 + * get the "right" size of video,
  289 + * 1. initialize with the original video object size.
  290 + * 2. override with metadata size if specified.
  291 + * 3. override with codec size if specified.
  292 + */
  293 + private function get_video_size_object():Object {
207 var obj:Object = { 294 var obj:Object = {
208 width: video.width, 295 width: video.width,
209 - height: video.height,  
210 - server: 'srs',  
211 - contributor: 'winlin' 296 + height: video.height
212 }; 297 };
213 298
  299 + // override with metadata size.
214 if (metadata.hasOwnProperty("width")) { 300 if (metadata.hasOwnProperty("width")) {
215 obj.width = metadata.width; 301 obj.width = metadata.width;
216 } 302 }
@@ -218,6 +304,7 @@ package @@ -218,6 +304,7 @@ package
218 obj.height = metadata.height; 304 obj.height = metadata.height;
219 } 305 }
220 306
  307 + // override with codec size.
221 if (video.videoWidth > 0) { 308 if (video.videoWidth > 0) {
222 obj.width = video.videoWidth; 309 obj.width = video.videoWidth;
223 } 310 }
@@ -225,17 +312,110 @@ package @@ -225,17 +312,110 @@ package
225 obj.height = video.videoHeight; 312 obj.height = video.videoHeight;
226 } 313 }
227 314
228 - if (metadata.hasOwnProperty("server")) {  
229 - obj.server = metadata.server; 315 + return obj;
  316 + }
  317 +
  318 + /**
  319 + * execute the enter fullscreen action.
  320 + */
  321 + private function execute_user_enter_fullscreen():void {
  322 + if (!fs_refer || fs_percent <= 0) {
  323 + return;
230 } 324 }
231 - if (metadata.hasOwnProperty("contributor")) {  
232 - obj.contributor = metadata.contributor; 325 +
  326 + // change to video size if refer to video.
  327 + var obj:Object = get_video_size_object();
  328 +
  329 + // get the DAR
  330 + var num:int = dar_num;
  331 + var den:int = dar_den;
  332 +
  333 + if (num == 0) {
  334 + num = obj.height;
  335 + }
  336 + if (num == -1) {
  337 + num = this.stage.fullScreenHeight;
233 } 338 }
234 339
235 - var code:int = flash.external.ExternalInterface.call(on_player_metadata, id, obj);  
236 - if (code != 0) {  
237 - throw new Error("callback on_player_metadata failed. code=" + code); 340 + if (den == 0) {
  341 + den = obj.width;
  342 + }
  343 + if (den == -1) {
  344 + den = this.stage.fullScreenWidth;
  345 + }
  346 +
  347 + // for refer is screen.
  348 + if (fs_refer == "screen") {
  349 + obj = {
  350 + width: this.stage.fullScreenWidth,
  351 + height: this.stage.fullScreenHeight
  352 + };
238 } 353 }
  354 +
  355 + // rescale to fs
  356 + update_video_size(num, den, obj.width * fs_percent / 100, obj.height * fs_percent / 100, this.stage.fullScreenWidth, this.stage.fullScreenHeight);
  357 + }
  358 +
  359 + /**
  360 + * for user set dar, or leave fullscreen to recover the dar.
  361 + */
  362 + private function execute_user_set_dar():void {
  363 + // get the DAR
  364 + var num:int = dar_num;
  365 + var den:int = dar_den;
  366 +
  367 + var obj:Object = get_video_size_object();
  368 +
  369 + if (num == 0) {
  370 + num = obj.height;
  371 + }
  372 + if (num == -1) {
  373 + num = this.h;
  374 + }
  375 +
  376 + if (den == 0) {
  377 + den = obj.width;
  378 + }
  379 + if (den == -1) {
  380 + den = this.w;
  381 + }
  382 +
  383 + update_video_size(num, den, this.w, this.h, this.w, this.h);
  384 + }
  385 +
  386 + /**
  387 + * update the video width and height,
  388 + * according to the specifies DAR(den:num) and max size(w:h).
  389 + * set the position of video(x,y) specifies by size(sw:sh),
  390 + * and update the bg to size(sw:sh).
  391 + * @param _num/_den the DAR. use to rescale the player together with paper size.
  392 + * @param _w/_h the video draw paper size. used to rescale the player together with DAR.
  393 + * @param _sw/_wh the stage size, >= paper size. used to center the player.
  394 + */
  395 + private function update_video_size(_num:int, _den:int, _w:int, _h:int, _sw:int, _sh:int):void {
  396 + if (!this.video || _num <= 0 || _den <= 0) {
  397 + return;
  398 + }
  399 +
  400 + // set DAR.
  401 + // calc the height by DAR
  402 + var _height:int = _w * _num / _den;
  403 + if (_height <= _h) {
  404 + this.video.width = _w;
  405 + this.video.height = _height;
  406 + } else {
  407 + // height overflow, calc the width by DAR
  408 + var _width:int = _h * _den / _num;
  409 +
  410 + this.video.width = _width;
  411 + this.video.height = _h;
  412 + }
  413 +
  414 + // align center.
  415 + this.video.x = (_sw - this.video.width) / 2;
  416 + this.video.y = (_sh - this.video.height) / 2;
  417 +
  418 + draw_black_background(_sw, _sh);
239 } 419 }
240 } 420 }
241 } 421 }