winlin

Merge branch '2.0release' into develop

@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script> 6 <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>
7 <script type="text/javascript" src="players/js/srs.page.js"></script> 7 <script type="text/javascript" src="players/js/srs.page.js"></script>
8 <script type="text/javascript" src="players/js/srs.utility.js"></script> 8 <script type="text/javascript" src="players/js/srs.utility.js"></script>
  9 + <script type="text/javascript" src="players/js/winlin.utility.js"></script>
9 </head> 10 </head>
10 <body> 11 <body>
11 <script type="text/javascript"> 12 <script type="text/javascript">
@@ -4,35 +4,11 @@ @@ -4,35 +4,11 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/srs.page.js"></script>  
11 - <script type="text/javascript" src="js/srs.utility.js"></script>  
12 <style> 7 <style>
13 body{ 8 body{
14 padding-top: 55px; 9 padding-top: 55px;
15 } 10 }
16 </style> 11 </style>
17 - <script type="text/javascript">  
18 - $(function(){  
19 - update_nav();  
20 -  
21 - var query = parse_query_string();  
22 - var url = "srs_chat.html?vhost=" + srs_get_player_vhost();  
23 -  
24 - for (var key in query.user_query) {  
25 - if (key == "vhost") {  
26 - continue;  
27 - }  
28 - url += "&" + key + "=" + query[key];  
29 - }  
30 -  
31 - setTimeout(function(){  
32 - window.location.href = url;  
33 - }, 100);  
34 - });  
35 - </script>  
36 </head> 12 </head>
37 <body> 13 <body>
38 <div class="navbar navbar-fixed-top"> 14 <div class="navbar navbar-fixed-top">
@@ -59,5 +35,30 @@ @@ -59,5 +35,30 @@
59 <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p> 35 <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p>
60 </footer> 36 </footer>
61 </div> 37 </div>
  38 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  39 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  40 +<script type="text/javascript" src="js/swfobject.js"></script>
  41 +<script type="text/javascript" src="js/srs.page.js"></script>
  42 +<script type="text/javascript" src="js/srs.utility.js"></script>
  43 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  44 +<script type="text/javascript">
  45 + $(function(){
  46 + update_nav();
  47 +
  48 + var query = parse_query_string();
  49 + var url = "srs_chat.html?vhost=" + srs_get_player_vhost();
  50 +
  51 + for (var key in query.user_query) {
  52 + if (key == "vhost") {
  53 + continue;
  54 + }
  55 + url += "&" + key + "=" + query[key];
  56 + }
  57 +
  58 + setTimeout(function(){
  59 + window.location.href = url;
  60 + }, 100);
  61 + });
  62 +</script>
62 </body> 63 </body>
63 64
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 ////////////////////////////////////////////////////////////////////////////////// 3 //////////////////////////////////////////////////////////////////////////////////
4 4
5 // to query the swf anti cache. 5 // to query the swf anti cache.
6 -function srs_get_version_code() { return "1.23"; } 6 +function srs_get_version_code() { return "1.25"; }
7 7
8 /** 8 /**
9 * player specified size. 9 * player specified size.
@@ -135,6 +135,12 @@ function build_default_hls_url() { @@ -135,6 +135,12 @@ function build_default_hls_url() {
135 * @param hls_url the div id contains the hls stream url to play 135 * @param hls_url the div id contains the hls stream url to play
136 * @param modal_player the div id contains the modal player 136 * @param modal_player the div id contains the modal player
137 */ 137 */
  138 +function srs_init_rtmp(rtmp_url, modal_player) {
  139 + srs_init(rtmp_url, null, modal_player);
  140 +}
  141 +function srs_init_hls(hls_url, modal_player) {
  142 + srs_init(null, hls_url, modal_player);
  143 +}
138 function srs_init(rtmp_url, hls_url, modal_player) { 144 function srs_init(rtmp_url, hls_url, modal_player) {
139 update_nav(); 145 update_nav();
140 146
@@ -30,6 +30,32 @@ function SrsPlayer(container, width, height, private_object) { @@ -30,6 +30,32 @@ function SrsPlayer(container, width, height, private_object) {
30 this.meatadata = {}; // for on_player_metadata 30 this.meatadata = {}; // for on_player_metadata
31 this.time = 0; // current stream time. 31 this.time = 0; // current stream time.
32 this.buffer_length = 0; // current stream buffer length. 32 this.buffer_length = 0; // current stream buffer length.
  33 + this.kbps = 0; // current stream bitrate(video+audio) in kbps.
  34 + this.fps = 0; // current stream video fps.
  35 + this.rtime = 0; // flash relative time in ms.
  36 +
  37 + this.__fluency = {
  38 + total_empty_count: 0,
  39 + total_empty_time: 0,
  40 + current_empty_time: 0
  41 + };
  42 + this.__fluency.on_stream_empty = function(time) {
  43 + this.total_empty_count++;
  44 + this.current_empty_time = time;
  45 + };
  46 + this.__fluency.on_stream_full = function(time) {
  47 + if (this.current_empty_time > 0) {
  48 + this.total_empty_time += time - this.current_empty_time;
  49 + this.current_empty_time = 0;
  50 + }
  51 + };
  52 + this.__fluency.calc = function(time) {
  53 + var den = this.total_empty_count * 4 + this.total_empty_time * 2 + time;
  54 + if (den > 0) {
  55 + return time * 100 / den;
  56 + }
  57 + return 0;
  58 + };
33 } 59 }
34 /** 60 /**
35 * user can set some callback, then start the player. 61 * user can set some callback, then start the player.
@@ -49,6 +75,8 @@ SrsPlayer.prototype.start = function(url) { @@ -49,6 +75,8 @@ SrsPlayer.prototype.start = function(url) {
49 flashvars.on_player_ready = "__srs_on_player_ready"; 75 flashvars.on_player_ready = "__srs_on_player_ready";
50 flashvars.on_player_metadata = "__srs_on_player_metadata"; 76 flashvars.on_player_metadata = "__srs_on_player_metadata";
51 flashvars.on_player_timer = "__srs_on_player_timer"; 77 flashvars.on_player_timer = "__srs_on_player_timer";
  78 + flashvars.on_player_empty = "__srs_on_player_empty";
  79 + flashvars.on_player_full = "__srs_on_player_full";
52 80
53 var params = {}; 81 var params = {};
54 params.wmode = "opaque"; 82 params.wmode = "opaque";
@@ -113,6 +141,18 @@ SrsPlayer.prototype.resume = function() { @@ -113,6 +141,18 @@ SrsPlayer.prototype.resume = function() {
113 this.callbackObj.ref.__resume(); 141 this.callbackObj.ref.__resume();
114 } 142 }
115 /** 143 /**
  144 + * get the stream fluency, where 100 is 100%.
  145 + */
  146 +SrsPlayer.prototype.fluency = function() {
  147 + return this.__fluency.calc(this.rtime);
  148 +}
  149 +/**
  150 + * get the stream empty count.
  151 + */
  152 +SrsPlayer.prototype.empty_count = function() {
  153 + return this.__fluency.total_empty_count;
  154 +}
  155 +/**
116 * to set the DAR, for example, DAR=16:9 where num=16,den=9. 156 * to set the DAR, for example, DAR=16:9 where num=16,den=9.
117 * @param num, for example, 16. 157 * @param num, for example, 16.
118 * use metadata width if 0. 158 * use metadata width if 0.
@@ -148,7 +188,13 @@ SrsPlayer.prototype.on_player_ready = function() { @@ -148,7 +188,13 @@ SrsPlayer.prototype.on_player_ready = function() {
148 SrsPlayer.prototype.on_player_metadata = function(metadata) { 188 SrsPlayer.prototype.on_player_metadata = function(metadata) {
149 // ignore. 189 // ignore.
150 } 190 }
151 -SrsPlayer.prototype.on_player_timer = function(time, buffer_length) { 191 +SrsPlayer.prototype.on_player_timer = function(time, buffer_length, kbps, fps, rtime) {
  192 + // ignore.
  193 +}
  194 +SrsPlayer.prototype.on_player_empty = function(time) {
  195 + // ignore.
  196 +}
  197 +SrsPlayer.prototype.on_player_full = function(time) {
152 // ignore. 198 // ignore.
153 } 199 }
154 function __srs_find_player(id) { 200 function __srs_find_player(id) {
@@ -177,7 +223,7 @@ function __srs_on_player_metadata(id, metadata) { @@ -177,7 +223,7 @@ function __srs_on_player_metadata(id, metadata) {
177 223
178 player.on_player_metadata(metadata); 224 player.on_player_metadata(metadata);
179 } 225 }
180 -function __srs_on_player_timer(id, time, buffer_length) { 226 +function __srs_on_player_timer(id, time, buffer_length, kbps, fps, rtime) {
181 var player = __srs_find_player(id); 227 var player = __srs_find_player(id);
182 228
183 buffer_length = Math.max(0, buffer_length); 229 buffer_length = Math.max(0, buffer_length);
@@ -189,6 +235,19 @@ function __srs_on_player_timer(id, time, buffer_length) { @@ -189,6 +235,19 @@ function __srs_on_player_timer(id, time, buffer_length) {
189 // so set the data before invoke it. 235 // so set the data before invoke it.
190 player.time = time; 236 player.time = time;
191 player.buffer_length = buffer_length; 237 player.buffer_length = buffer_length;
  238 + player.kbps = kbps;
  239 + player.fps = fps;
  240 + player.rtime = rtime;
192 241
193 - player.on_player_timer(time, buffer_length); 242 + player.on_player_timer(time, buffer_length, kbps, fps, rtime);
  243 +}
  244 +function __srs_on_player_empty(id, time) {
  245 + var player = __srs_find_player(id);
  246 + player.__fluency.on_stream_empty(time);
  247 + player.on_player_empty(time);
  248 +}
  249 +function __srs_on_player_full(id, time) {
  250 + var player = __srs_find_player(id);
  251 + player.__fluency.on_stream_full(time);
  252 + player.on_player_full(time);
194 } 253 }
1 /** 1 /**
2 -* padding the output.  
3 -* padding(3, 5, '0') is 00003  
4 -* padding(3, 5, 'x') is xxxx3  
5 -* @see http://blog.csdn.net/win_lin/article/details/12065413  
6 -*/  
7 -function padding(number, length, prefix) {  
8 - if(String(number).length >= length){  
9 - return String(number);  
10 - }  
11 - return padding(prefix+number, length, prefix);  
12 -}  
13 -  
14 -/**  
15 -* parse the query string to object.  
16 -* parse the url location object as: host(hostname:http_port), pathname(dir/filename)  
17 -* for example, url http://192.168.1.168:1980/ui/players.html?vhost=player.vhost.com&app=test&stream=livestream  
18 -* parsed to object:  
19 -{  
20 - host : "192.168.1.168:1980",  
21 - hostname : "192.168.1.168",  
22 - http_port : 1980,  
23 - pathname : "/ui/players.html",  
24 - dir : "/ui",  
25 - filename : "/players.html",  
26 -  
27 - vhost : "player.vhost.com",  
28 - app : "test",  
29 - stream : "livestream"  
30 -}  
31 -*/  
32 -function parse_query_string(){  
33 - var obj = {};  
34 -  
35 - // add the uri object.  
36 - // parse the host(hostname:http_port), pathname(dir/filename)  
37 - obj.host = window.location.host;  
38 - obj.hostname = window.location.hostname;  
39 - obj.http_port = (window.location.port == "")? 80:window.location.port;  
40 - obj.pathname = window.location.pathname;  
41 - if (obj.pathname.lastIndexOf("/") <= 0) {  
42 - obj.dir = "/";  
43 - obj.filename = "";  
44 - } else {  
45 - obj.dir = obj.pathname.substr(0, obj.pathname.lastIndexOf("/"));  
46 - obj.filename = obj.pathname.substr(obj.pathname.lastIndexOf("/"));  
47 - }  
48 -  
49 - // pure user query object.  
50 - obj.user_query = {};  
51 -  
52 - // parse the query string.  
53 - var query_string = String(window.location.search).replace(" ", "").split("?")[1];  
54 - if(query_string == undefined){  
55 - return obj;  
56 - }  
57 -  
58 - var queries = query_string.split("&");  
59 - $(queries).each(function(){  
60 - var query = this.split("=");  
61 - obj[query[0]] = query[1];  
62 - obj.user_query[query[0]] = query[1];  
63 - });  
64 -  
65 - return obj;  
66 -}  
67 -  
68 -/**  
69 * parse the rtmp url, 2 * parse the rtmp url,
70 * for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream 3 * for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
71 * @return object {server, port, vhost, app, stream} 4 * @return object {server, port, vhost, app, stream}
72 */ 5 */
73 function srs_parse_rtmp_url(rtmp_url) { 6 function srs_parse_rtmp_url(rtmp_url) {
74 - // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri  
75 - var a = document.createElement("a");  
76 - a.href = rtmp_url.replace("rtmp://", "http://");  
77 -  
78 - var vhost = a.hostname;  
79 - var port = (a.port == "")? "1935":a.port;  
80 - var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);  
81 - var stream = a.pathname.substr(a.pathname.lastIndexOf("/") + 1);  
82 -  
83 - // parse the vhost in the params of app, that srs supports.  
84 - app = app.replace("...vhost...", "?vhost=");  
85 - if (app.indexOf("?") >= 0) {  
86 - var params = app.substr(app.indexOf("?"));  
87 - app = app.substr(0, app.indexOf("?"));  
88 -  
89 - if (params.indexOf("vhost=") > 0) {  
90 - vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);  
91 - if (vhost.indexOf("&") > 0) {  
92 - vhost = vhost.substr(0, vhost.indexOf("&"));  
93 - }  
94 - }  
95 - }  
96 -  
97 - var ret = {  
98 - server: a.hostname, port: port,  
99 - vhost: vhost, app: app, stream: stream  
100 - };  
101 -  
102 - return ret;  
103 -}  
104 -  
105 -/**  
106 -* get the agent.  
107 -* @return an object specifies some browser.  
108 -* for example, get_browser_agents().MSIE  
109 -*/  
110 -function get_browser_agents() {  
111 - var agent = navigator.userAgent;  
112 -  
113 - /**  
114 - WindowsPC platform, Win7:  
115 - chrome 31.0.1650.63:  
116 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36  
117 - (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36  
118 - firefox 23.0.1:  
119 - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101  
120 - Firefox/23.0  
121 - safari 5.1.7(7534.57.2):  
122 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2  
123 - (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2  
124 - opera 15.0.1147.153:  
125 - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36  
126 - (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36  
127 - OPR/15.0.1147.153  
128 - 360 6.2.1.272:  
129 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;  
130 - Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;  
131 - .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;  
132 - .NET4.0E)  
133 - IE 10.0.9200.16750(update: 10.0.12):  
134 - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;  
135 - Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;  
136 - .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;  
137 - .NET4.0E)  
138 - */  
139 -  
140 - return {  
141 - // platform  
142 - Android: agent.indexOf("Android") != -1,  
143 - Windows: agent.indexOf("Windows") != -1,  
144 - iPhone: agent.indexOf("iPhone") != -1,  
145 - // Windows Browsers  
146 - Chrome: agent.indexOf("Chrome") != -1,  
147 - Firefox: agent.indexOf("Firefox") != -1,  
148 - QQBrowser: agent.indexOf("QQBrowser") != -1,  
149 - MSIE: agent.indexOf("MSIE") != -1,  
150 - // Android Browsers  
151 - Opera: agent.indexOf("Presto") != -1,  
152 - MQQBrowser: agent.indexOf("MQQBrowser") != -1  
153 - }; 7 + return parse_rtmp_url(rtmp_url);
154 } 8 }
  1 +// winlin.utility.js
  2 +
  3 +/**
  4 + * common utilities
  5 + * depends: jquery1.10
  6 + * https://code.csdn.net/snippets/147103
  7 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  8 + * v 1.0.11
  9 + */
  10 +
  11 +/**
  12 + * padding the output.
  13 + * padding(3, 5, '0') is 00003
  14 + * padding(3, 5, 'x') is xxxx3
  15 + * @see http://blog.csdn.net/win_lin/article/details/12065413
  16 + */
  17 +function padding(number, length, prefix) {
  18 + if(String(number).length >= length){
  19 + return String(number);
  20 + }
  21 + return padding(prefix+number, length, prefix);
  22 +}
  23 +
  24 +/**
  25 + * extends system array, to remove all specified elem.
  26 + * @param arr the array to remove elem from.
  27 + * @param elem the elem to remove.
  28 + * @remark all elem will be removed.
  29 + * for example,
  30 + * arr = [10, 15, 20, 30, 20, 40]
  31 + * system_array_remove(arr, 10) // arr=[15, 20, 30, 20, 40]
  32 + * system_array_remove(arr, 20) // arr=[15, 30, 40]
  33 + */
  34 +function system_array_remove(arr, elem) {
  35 + if (!arr) {
  36 + return;
  37 + }
  38 +
  39 + var removed = true;
  40 + var i = 0;
  41 + while (removed) {
  42 + removed = false;
  43 + for (; i < arr.length; i++) {
  44 + if (elem == arr[i]) {
  45 + arr.splice(i, 1);
  46 + removed = true;
  47 + break;
  48 + }
  49 + }
  50 + }
  51 +}
  52 +
  53 +/**
  54 + * whether the array contains specified element.
  55 + * @param arr the array to find.
  56 + * @param elem_or_function the element value or compare function.
  57 + * @returns true contains elem; otherwise false.
  58 + * for example,
  59 + * arr = [10, 15, 20, 30, 20, 40]
  60 + * system_array_contains(arr, 10) // true
  61 + * system_array_contains(arr, 11) // false
  62 + * system_array_contains(arr, function(elem){return elem == 30;}); // true
  63 + * system_array_contains(arr, function(elem){return elem == 60;}); // false
  64 + */
  65 +function system_array_contains(arr, elem_or_function) {
  66 + return system_array_get(arr, elem_or_function) != null;
  67 +}
  68 +
  69 +/**
  70 + * get the specified element from array
  71 + * @param arr the array to find.
  72 + * @param elem_or_function the element value or compare function.
  73 + * @returns the matched elem; otherwise null.
  74 + * for example,
  75 + * arr = [10, 15, 20, 30, 20, 40]
  76 + * system_array_get(arr, 10) // 10
  77 + * system_array_get(arr, 11) // null
  78 + * system_array_get(arr, function(elem){return elem == 30;}); // 30
  79 + * system_array_get(arr, function(elem){return elem == 60;}); // null
  80 + */
  81 +function system_array_get(arr, elem_or_function) {
  82 + for (var i = 0; i < arr.length; i++) {
  83 + if (typeof elem_or_function == "function") {
  84 + if (elem_or_function(arr[i])) {
  85 + return arr[i];
  86 + }
  87 + } else {
  88 + if (elem_or_function == arr[i]) {
  89 + return arr[i];
  90 + }
  91 + }
  92 + }
  93 + return null;
  94 +}
  95 +
  96 +/**
  97 + * to iterate on array.
  98 + * @param arr the array to iterate on.
  99 + * @param pfn the function to apply on it
  100 + * for example,
  101 + * arr = [10, 15, 20, 30, 20, 40]
  102 + * system_array_foreach(arr, function(elem, index){
  103 + * console.log('index=' + index + ',elem=' + elem);
  104 + * });
  105 + */
  106 +function system_array_foreach(arr, pfn) {
  107 + for (var i = 0; i < arr.length; i++) {
  108 + if (pfn) {
  109 + pfn(arr[i], i)
  110 + }
  111 + }
  112 +}
  113 +
  114 +/**
  115 + * array sort asc, for example:
  116 + * [a, b] in [10, 11, 9]
  117 + * then sort to: [9, 10, 11]
  118 + * Usage, for example:
  119 + obj.data.data.sort(function(a, b){
  120 + return array_sort_asc(a.metadata.meta_id, b.metadata.meta_id);
  121 + });
  122 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  123 + * @remark, if need desc, use -1*array_sort_asc(a,b)
  124 + */
  125 +function array_sort_asc(elem_a, elem_b) {
  126 + if (elem_a > elem_b) {
  127 + return 1;
  128 + }
  129 + return (elem_a < elem_b)? -1 : 0;
  130 +}
  131 +function array_sort_desc(elem_a, elem_b) {
  132 + return -1 * array_sort_asc(elem_a, elem_b);
  133 +}
  134 +function system_array_sort_asc(elem_a, elem_b) {
  135 + return array_sort_asc(elem_a, elem_b);
  136 +}
  137 +function system_array_sort_desc(elem_a, elem_b) {
  138 + return -1 * array_sort_asc(elem_a, elem_b);
  139 +}
  140 +
  141 +/**
  142 + * parse the query string to object.
  143 + * parse the url location object as: host(hostname:http_port), pathname(dir/filename)
  144 + * for example, url http://192.168.1.168:1980/ui/players.html?vhost=player.vhost.com&app=test&stream=livestream
  145 + * parsed to object:
  146 + {
  147 + host : "192.168.1.168:1980",
  148 + hostname : "192.168.1.168",
  149 + http_port : 1980,
  150 + pathname : "/ui/players.html",
  151 + dir : "/ui",
  152 + filename : "/players.html",
  153 +
  154 + vhost : "player.vhost.com",
  155 + app : "test",
  156 + stream : "livestream"
  157 + }
  158 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  159 + */
  160 +function parse_query_string(){
  161 + var obj = {};
  162 +
  163 + // add the uri object.
  164 + // parse the host(hostname:http_port), pathname(dir/filename)
  165 + obj.host = window.location.host;
  166 + obj.hostname = window.location.hostname;
  167 + obj.http_port = (window.location.port == "")? 80:window.location.port;
  168 + obj.pathname = window.location.pathname;
  169 + if (obj.pathname.lastIndexOf("/") <= 0) {
  170 + obj.dir = "/";
  171 + obj.filename = "";
  172 + } else {
  173 + obj.dir = obj.pathname.substr(0, obj.pathname.lastIndexOf("/"));
  174 + obj.filename = obj.pathname.substr(obj.pathname.lastIndexOf("/"));
  175 + }
  176 +
  177 + // pure user query object.
  178 + obj.user_query = {};
  179 +
  180 + // parse the query string.
  181 + var query_string = String(window.location.search).replace(" ", "").split("?")[1];
  182 + if(query_string == undefined){
  183 + query_string = String(window.location.hash).replace(" ", "").split("#")[1];
  184 + if(query_string == undefined){
  185 + return obj;
  186 + }
  187 + }
  188 +
  189 + var queries = query_string.split("&");
  190 + $(queries).each(function(){
  191 + var query = this.split("=");
  192 + obj[query[0]] = query[1];
  193 + obj.user_query[query[0]] = query[1];
  194 + });
  195 +
  196 + return obj;
  197 +}
  198 +
  199 +/**
  200 + * parse the rtmp url,
  201 + * for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
  202 + * @return object {server, port, vhost, app, stream}
  203 + * for exmaple, rtmp_url is rtmp://demo.srs.com:1935/live...vhost...players/livestream
  204 + * parsed to object:
  205 + {
  206 + server: "demo.srs.com",
  207 + port: 1935,
  208 + vhost: "players",
  209 + app: "live",
  210 + stream: "livestream"
  211 + }
  212 + */
  213 +function parse_rtmp_url(rtmp_url) {
  214 + // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
  215 + var a = document.createElement("a");
  216 + a.href = rtmp_url.replace("rtmp://", "http://").replace("?", "...").replace("=", "...");
  217 +
  218 + var vhost = a.hostname;
  219 + var port = (a.port == "")? "1935":a.port;
  220 + var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);
  221 + var stream = a.pathname.substr(a.pathname.lastIndexOf("/") + 1);
  222 +
  223 + // parse the vhost in the params of app, that srs supports.
  224 + app = app.replace("...vhost...", "?vhost=");
  225 + if (app.indexOf("?") >= 0) {
  226 + var params = app.substr(app.indexOf("?"));
  227 + app = app.substr(0, app.indexOf("?"));
  228 +
  229 + if (params.indexOf("vhost=") > 0) {
  230 + vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);
  231 + if (vhost.indexOf("&") > 0) {
  232 + vhost = vhost.substr(0, vhost.indexOf("&"));
  233 + }
  234 + }
  235 + }
  236 +
  237 + // when vhost equals to server, and server is ip,
  238 + // the vhost is __defaultVhost__
  239 + if (a.hostname == vhost) {
  240 + var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
  241 + if (re.test(a.hostname)) {
  242 + vhost = "__defaultVhost__";
  243 + }
  244 + }
  245 +
  246 + var ret = {
  247 + server: a.hostname, port: port,
  248 + vhost: vhost, app: app, stream: stream
  249 + };
  250 +
  251 + return ret;
  252 +}
  253 +
  254 +/**
  255 + * get the agent.
  256 + * @return an object specifies some browser.
  257 + * for example, get_browser_agents().MSIE
  258 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  259 + */
  260 +function get_browser_agents() {
  261 + var agent = navigator.userAgent;
  262 +
  263 + /**
  264 + WindowsPC platform, Win7:
  265 + chrome 31.0.1650.63:
  266 + Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
  267 + (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
  268 + firefox 23.0.1:
  269 + Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101
  270 + Firefox/23.0
  271 + safari 5.1.7(7534.57.2):
  272 + Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2
  273 + (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2
  274 + opera 15.0.1147.153:
  275 + Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
  276 + (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
  277 + OPR/15.0.1147.153
  278 + 360 6.2.1.272:
  279 + Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
  280 + Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
  281 + .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
  282 + .NET4.0E)
  283 + IE 10.0.9200.16750(update: 10.0.12):
  284 + Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
  285 + Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
  286 + .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
  287 + .NET4.0E)
  288 + */
  289 +
  290 + return {
  291 + // platform
  292 + Android: agent.indexOf("Android") != -1,
  293 + Windows: agent.indexOf("Windows") != -1,
  294 + iPhone: agent.indexOf("iPhone") != -1,
  295 + // Windows Browsers
  296 + Chrome: agent.indexOf("Chrome") != -1,
  297 + Firefox: agent.indexOf("Firefox") != -1,
  298 + QQBrowser: agent.indexOf("QQBrowser") != -1,
  299 + MSIE: agent.indexOf("MSIE") != -1,
  300 + // Android Browsers
  301 + Opera: agent.indexOf("Presto") != -1,
  302 + MQQBrowser: agent.indexOf("MQQBrowser") != -1
  303 + };
  304 +}
  305 +
  306 +/**
  307 + * format relative seconds to HH:MM:SS,
  308 + * for example, 210s formated to 00:03:30
  309 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  310 + * @usage relative_seconds_to_HHMMSS(210)
  311 + */
  312 +function relative_seconds_to_HHMMSS(seconds){
  313 + var date = new Date();
  314 + date.setTime(Number(seconds) * 1000);
  315 +
  316 + var ret = padding(date.getUTCHours(), 2, '0')
  317 + + ":" + padding(date.getUTCMinutes(), 2, '0')
  318 + + ":" + padding(date.getUTCSeconds(), 2, '0');
  319 +
  320 + return ret;
  321 +}
  322 +
  323 +/**
  324 + * format absolute seconds to HH:MM:SS,
  325 + * for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 10:01:20
  326 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  327 + * @usage absolute_seconds_to_HHMMSS(new Date().getTime() / 1000)
  328 + */
  329 +function absolute_seconds_to_HHMMSS(seconds){
  330 + var date = new Date();
  331 + date.setTime(Number(seconds) * 1000);
  332 +
  333 + var ret = padding(date.getHours(), 2, '0')
  334 + + ":" + padding(date.getMinutes(), 2, '0')
  335 + + ":" + padding(date.getSeconds(), 2, '0');
  336 +
  337 + return ret;
  338 +}
  339 +
  340 +/**
  341 + * format absolute seconds to YYYY-mm-dd,
  342 + * for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 2014-01-08
  343 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  344 + * @usage absolute_seconds_to_YYYYmmdd(new Date().getTime() / 1000)
  345 + */
  346 +function absolute_seconds_to_YYYYmmdd(seconds) {
  347 + var date = new Date();
  348 + date.setTime(Number(seconds) * 1000);
  349 +
  350 + var ret = date.getFullYear()
  351 + + "-" + padding(date.getMonth() + 1, 2, '0')
  352 + + "-" + padding(date.getDate(), 2, '0');
  353 +
  354 + return ret;
  355 +}
  356 +
  357 +/**
  358 + * parse the date in str to Date object.
  359 + * @param str the date in str, format as "YYYY-mm-dd", for example, 2014-12-11
  360 + * @returns a date object.
  361 + * @usage YYYYmmdd_parse("2014-12-11")
  362 + */
  363 +function YYYYmmdd_parse(str) {
  364 + var date = new Date();
  365 + date.setTime(Date.parse(str));
  366 + return date;
  367 +}
  368 +
  369 +/**
  370 + * async refresh function call. to avoid multiple call.
  371 + * @remark AsyncRefresh is for jquery to refresh the speicified pfn in a page;
  372 + * if angularjs, use AsyncRefresh2 to change pfn, cancel previous request for angularjs use singleton object.
  373 + * @param refresh_interval the default refresh interval ms.
  374 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  375 + * the pfn can be implements as following:
  376 + var async_refresh = new AsyncRefresh(pfn, 3000);
  377 + function pfn() {
  378 + if (!async_refresh.refresh_is_enabled()) {
  379 + async_refresh.request(100);
  380 + return;
  381 + }
  382 + $.ajax({
  383 + type: 'GET', async: true, url: 'xxxxx',
  384 + complete: function(){
  385 + if (!async_refresh.refresh_is_enabled()) {
  386 + async_refresh.request(0);
  387 + } else {
  388 + async_refresh.request(async_refresh.refresh_interval);
  389 + }
  390 + },
  391 + success: function(res){
  392 + // if donot allow refresh, directly return.
  393 + if (!async_refresh.refresh_is_enabled()) {
  394 + return;
  395 + }
  396 +
  397 + // render the res.
  398 + }
  399 + });
  400 + }
  401 + */
  402 +function AsyncRefresh(pfn, refresh_interval) {
  403 + this.refresh_interval = refresh_interval;
  404 +
  405 + this.__handler = null;
  406 + this.__pfn = pfn;
  407 +
  408 + this.__enabled = true;
  409 +}
  410 +/**
  411 + * disable the refresher, the pfn must check the refresh state.
  412 + */
  413 +AsyncRefresh.prototype.refresh_disable = function() {
  414 + this.__enabled = false;
  415 +}
  416 +AsyncRefresh.prototype.refresh_enable = function() {
  417 + this.__enabled = true;
  418 +}
  419 +AsyncRefresh.prototype.refresh_is_enabled = function() {
  420 + return this.__enabled;
  421 +}
  422 +/**
  423 + * start new async request
  424 + * @param timeout the timeout in ms.
  425 + * user can use the refresh_interval of the AsyncRefresh object,
  426 + * which initialized in constructor.
  427 + */
  428 +AsyncRefresh.prototype.request = function(timeout) {
  429 + if (this.__handler) {
  430 + clearTimeout(this.__handler);
  431 + }
  432 +
  433 + this.__handler = setTimeout(this.__pfn, timeout);
  434 +}
  435 +
  436 +/**
  437 + * async refresh v2, support cancellable refresh, and change the refresh pfn.
  438 + * @remakr for angularjs. if user only need jquery, maybe AsyncRefresh is better.
  439 + * @see: http://blog.csdn.net/win_lin/article/details/17994347
  440 + * Usage:
  441 + bsmControllers.controller('CServers', ['$scope', 'MServer', function($scope, MServer){
  442 + async_refresh2.refresh_change(function(){
  443 + // 获取服务器列表
  444 + MServer.servers_load({}, function(data){
  445 + $scope.servers = data.data.servers;
  446 + async_refresh2.request();
  447 + });
  448 + }, 3000);
  449 +
  450 + async_refresh2.request(0);
  451 + }]);
  452 + bsmControllers.controller('CStreams', ['$scope', 'MStream', function($scope, MStream){
  453 + async_refresh2.refresh_change(function(){
  454 + // 获取流列表
  455 + MStream.streams_load({}, function(data){
  456 + $scope.streams = data.data.streams;
  457 + async_refresh2.request();
  458 + });
  459 + }, 3000);
  460 +
  461 + async_refresh2.request(0);
  462 + }]);
  463 + */
  464 +function AsyncRefresh2() {
  465 + /**
  466 + * the function callback before call the pfn.
  467 + * the protype is function():bool, which return true to invoke, false to abort the call.
  468 + * null to ignore this callback.
  469 + *
  470 + * for example, user can abort the refresh by find the class popover:
  471 + * async_refresh2.on_before_call_pfn = function() {
  472 + * if ($(".popover").length > 0) {
  473 + * async_refresh2.request();
  474 + * return false;
  475 + * }
  476 + * return true;
  477 + * };
  478 + */
  479 + this.on_before_call_pfn = null;
  480 +
  481 + // use a anonymous function to call, and check the enabled when actually invoke.
  482 + this.__call = {
  483 + pfn: null,
  484 + timeout: 0,
  485 + __enabled: false,
  486 + __handler: null
  487 + };
  488 +}
  489 +// singleton
  490 +var async_refresh2 = new AsyncRefresh2();
  491 +/**
  492 + * initialize or refresh change. cancel previous request, setup new request.
  493 + * @param pfn a function():void to request after timeout. null to disable refresher.
  494 + * @param timeout the timeout in ms, to call pfn. null to disable refresher.
  495 + */
  496 +AsyncRefresh2.prototype.initialize = function(pfn, timeout) {
  497 + this.refresh_change(pfn, timeout);
  498 +}
  499 +/**
  500 + * stop refresh, the refresh pfn is set to null.
  501 + */
  502 +AsyncRefresh2.prototype.stop = function() {
  503 + this.refresh_change(null, null);
  504 +}
  505 +/**
  506 + * change refresh pfn, the old pfn will set to disabled.
  507 + */
  508 +AsyncRefresh2.prototype.refresh_change = function(pfn, timeout) {
  509 + // cancel the previous call.
  510 + if (this.__call.__handler) {
  511 + clearTimeout(this.__handler);
  512 + }
  513 + this.__call.__enabled = false;
  514 +
  515 + // setup new call.
  516 + this.__call = {
  517 + pfn: pfn,
  518 + timeout: timeout,
  519 + __enabled: true,
  520 + __handler: null
  521 + };
  522 +}
  523 +/**
  524 + * start new request, we never auto start the request,
  525 + * user must start new request when previous completed.
  526 + * @param timeout [optional] if not specified, use the timeout in initialize or refresh_change.
  527 + */
  528 +AsyncRefresh2.prototype.request = function(timeout) {
  529 + var self = this;
  530 + var this_call = this.__call;
  531 +
  532 + // clear previous timeout.
  533 + if (this_call.__handler) {
  534 + clearTimeout(this_call.__handler);
  535 + }
  536 +
  537 + // override the timeout
  538 + if (timeout == undefined) {
  539 + timeout = this_call.timeout;
  540 + }
  541 +
  542 + // if user disabled refresher.
  543 + if (this_call.pfn == null || timeout == null) {
  544 + return;
  545 + }
  546 +
  547 + this_call.__handler = setTimeout(function(){
  548 + // cancelled by refresh_change, ignore.
  549 + if (!this_call.__enabled) {
  550 + return;
  551 + }
  552 +
  553 + // callback if the handler installled.
  554 + if (self.on_before_call_pfn) {
  555 + if (!self.on_before_call_pfn()) {
  556 + return;
  557 + }
  558 + }
  559 +
  560 + // do the actual call.
  561 + this_call.pfn();
  562 + }, timeout);
  563 +}
  564 +
  565 +// other components.
  566 +/**
  567 + * jquery/bootstrap pager.
  568 + * depends: jquery1.10, boostrap2
  569 + * https://code.csdn.net/snippets/146160
  570 + * @see: http://blog.csdn.net/win_lin/article/details/17628631
  571 + */
@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
11 <script type="text/javascript" src="js/srs.player.js"></script> 11 <script type="text/javascript" src="js/srs.player.js"></script>
12 <script type="text/javascript" src="js/srs.publisher.js"></script> 12 <script type="text/javascript" src="js/srs.publisher.js"></script>
13 <script type="text/javascript" src="js/srs.utility.js"></script> 13 <script type="text/javascript" src="js/srs.utility.js"></script>
  14 + <script type="text/javascript" src="js/winlin.utility.js"></script>
14 <style> 15 <style>
15 body{ 16 body{
16 padding-top: 55px; 17 padding-top: 55px;
@@ -5,9 +5,10 @@ @@ -5,9 +5,10 @@
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 </head> 6 </head>
7 <body> 7 <body>
8 - <script type="text/javascript"> 8 +</body>
  9 +<script type="text/javascript">
9 setTimeout(function(){ 10 setTimeout(function(){
10 window.location.href = "players/index.html" + window.location.search; 11 window.location.href = "players/index.html" + window.location.search;
11 }, 500); 12 }, 500);
12 - </script>  
13 -</body>  
  13 +</script>
  14 +</html>
@@ -4,14 +4,6 @@ @@ -4,14 +4,6 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/srs.page.js"></script>  
11 - <script type="text/javascript" src="js/srs.log.js"></script>  
12 - <script type="text/javascript" src="js/srs.player.js"></script>  
13 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
14 - <script type="text/javascript" src="js/srs.utility.js"></script>  
15 <style> 7 <style>
16 body{ 8 body{
17 padding-top: 55px; 9 padding-top: 55px;
@@ -21,7 +13,63 @@ @@ -21,7 +13,63 @@
21 margin-left: -350px; 13 margin-left: -350px;
22 } 14 }
23 </style> 15 </style>
24 - <script type="text/javascript"> 16 +</head>
  17 +<body>
  18 +<div class="navbar navbar-fixed-top">
  19 + <div class="navbar-inner">
  20 + <div class="container">
  21 + <a id="srs_index" class="brand" href="#">SRS</a>
  22 + <div class="nav-collapse collapse">
  23 + <ul class="nav">
  24 + <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
  25 + <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
  26 + <li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
  27 + <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
  28 + <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
  29 + <li class="active"><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
  30 + <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
  31 + </ul>
  32 + </div>
  33 + </div>
  34 + </div>
  35 +</div>
  36 +<div class="container">
  37 + <div class="alert alert-info fade in">
  38 + <button type="button" class="close" data-dismiss="alert">×</button>
  39 + <strong><span>Usage:</span></strong> <span>输入地址后点击播放按钮</span>
  40 + </div>
  41 + <div class="form-inline">
  42 + URL:
  43 + <input type="text" id="txt_url" class="input-xxlarge" value=""></input>
  44 + <button class="btn btn-primary" id="btn_play">播放视频</button>
  45 + </div>
  46 + <div id="main_modal" class="modal hide fade">
  47 + <div class="modal-header">
  48 + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
  49 + <h3>AdobeOSMF</h3>
  50 + </div>
  51 + <div class="modal-body" id="player">
  52 + </div>
  53 + <div class="modal-footer">
  54 + <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true"> 关闭 </button>
  55 + </div>
  56 + </div>
  57 + <hr>
  58 + <footer>
  59 + <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p>
  60 + </footer>
  61 +</div>
  62 +</body>
  63 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  64 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  65 +<script type="text/javascript" src="js/swfobject.js"></script>
  66 +<script type="text/javascript" src="js/srs.page.js"></script>
  67 +<script type="text/javascript" src="js/srs.log.js"></script>
  68 +<script type="text/javascript" src="js/srs.player.js"></script>
  69 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  70 +<script type="text/javascript" src="js/srs.utility.js"></script>
  71 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  72 +<script type="text/javascript">
25 function osmf_play(url) { 73 function osmf_play(url) {
26 $("#div_container").remove(); 74 $("#div_container").remove();
27 75
@@ -57,7 +105,7 @@ @@ -57,7 +105,7 @@
57 // get the vhost and port to set the default url. 105 // get the vhost and port to set the default url.
58 // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo 106 // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
59 // url set to: rtmp://demo:1935/live/livestream 107 // url set to: rtmp://demo:1935/live/livestream
60 - srs_init("#txt_url", null, "#main_modal"); 108 + srs_init_rtmp("#txt_url", "#main_modal");
61 109
62 $("#main_modal").on("hide", function(){ 110 $("#main_modal").on("hide", function(){
63 osmf_play("http://localhost"); 111 osmf_play("http://localhost");
@@ -72,51 +120,5 @@ @@ -72,51 +120,5 @@
72 $("#main_modal").modal({show:true, keyboard:false}); 120 $("#main_modal").modal({show:true, keyboard:false});
73 }); 121 });
74 }); 122 });
75 - </script>  
76 -</head>  
77 -<body>  
78 -<div class="navbar navbar-fixed-top">  
79 - <div class="navbar-inner">  
80 - <div class="container">  
81 - <a id="srs_index" class="brand" href="#">SRS</a>  
82 - <div class="nav-collapse collapse">  
83 - <ul class="nav">  
84 - <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>  
85 - <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>  
86 - <li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>  
87 - <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>  
88 - <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>  
89 - <li class="active"><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>  
90 - <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>  
91 - </ul>  
92 - </div>  
93 - </div>  
94 - </div>  
95 -</div>  
96 -<div class="container">  
97 - <div class="alert alert-info fade in">  
98 - <button type="button" class="close" data-dismiss="alert">×</button>  
99 - <strong><span>Usage:</span></strong> <span>输入地址后点击播放按钮</span>  
100 - </div>  
101 - <div class="form-inline">  
102 - URL:  
103 - <input type="text" id="txt_url" class="input-xxlarge" value=""></input>  
104 - <button class="btn btn-primary" id="btn_play">播放视频</button>  
105 - </div>  
106 - <div id="main_modal" class="modal hide fade">  
107 - <div class="modal-header">  
108 - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>  
109 - <h3>AdobeOSMF</h3>  
110 - </div>  
111 - <div class="modal-body" id="player">  
112 - </div>  
113 - <div class="modal-footer">  
114 - <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true"> 关闭 </button>  
115 - </div>  
116 - </div>  
117 - <hr>  
118 - <footer>  
119 - <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p>  
120 - </footer>  
121 -</div>  
122 -</body> 123 +</script>
  124 +</html>
@@ -3,14 +3,16 @@ @@ -3,14 +3,16 @@
3 <head> 3 <head>
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 - <script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>  
7 - <script type="text/javascript" src="players/js/srs.page.js"></script>  
8 - <script type="text/javascript" src="players/js/srs.utility.js"></script>  
9 </head> 6 </head>
10 <body> 7 <body>
11 - <script type="text/javascript"> 8 +</body>
  9 +<script type="text/javascript" src="players/js/jquery-1.10.2.min.js"></script>
  10 +<script type="text/javascript" src="players/js/srs.page.js"></script>
  11 +<script type="text/javascript" src="players/js/srs.utility.js"></script>
  12 +<script type="text/javascript" src="players/js/winlin.utility.js"></script>
  13 +<script type="text/javascript">
12 setTimeout(function(){ 14 setTimeout(function(){
13 window.location.href = "players/index.html" + window.location.search; 15 window.location.href = "players/index.html" + window.location.search;
14 }, 500); 16 }, 500);
15 - </script>  
16 -</body> 17 +</script>
  18 +</html>
@@ -4,15 +4,6 @@ @@ -4,15 +4,6 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/srs.page.js"></script>  
11 - <script type="text/javascript" src="js/srs.log.js"></script>  
12 - <script type="text/javascript" src="js/srs.player.js"></script>  
13 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
14 - <script type="text/javascript" src="js/srs.utility.js"></script>  
15 - <script type="text/javascript" src="srs_bwt/src/srs.bandwidth.js"></script>  
16 <style> 7 <style>
17 body{ 8 body{
18 padding-top: 55px; 9 padding-top: 55px;
@@ -22,62 +13,6 @@ @@ -22,62 +13,6 @@
22 margin-left: -350px; 13 margin-left: -350px;
23 } 14 }
24 </style> 15 </style>
25 - <script type="text/javascript">  
26 - var bandwidth = null;  
27 -  
28 - $(function(){  
29 - srs_init_bwt("#txt_url");  
30 -  
31 - $("#btn_play").click(on_click_play);  
32 - $("#main_modal").on("show", on_start_bandwidth_test);  
33 - $("#main_modal").on("hide", on_stop_bandwidth_test);  
34 - });  
35 -  
36 - function on_click_play() {  
37 - $("#check_status").text("");  
38 - $("#check_info").text("");  
39 - $("#progress_bar").width("0%");  
40 - $("#main_modal").modal({show:true, keyboard:false});  
41 - }  
42 - function on_start_bandwidth_test() {  
43 - $("#div_container").remove();  
44 - $("#progress_bar").removeClass("bar-danger");  
45 -  
46 - var div_container = $("<div/>");  
47 - $(div_container).attr("id", "div_container");  
48 - $("#player").append(div_container);  
49 -  
50 - var player = $("<div/>");  
51 - $(player).attr("id", "player_id");  
52 - $(div_container).append(player);  
53 -  
54 - var url = $("#txt_url").val();  
55 -  
56 - bandwidth = new SrsBandwidth("player_id", 100, 1);  
57 - bandwidth.on_bandwidth_ready = function() {  
58 - this.check_bandwidth(url);  
59 - }  
60 - bandwidth.on_update_progress = function(percent) {  
61 - $("#progress_bar").width(percent + "%");  
62 - }  
63 - bandwidth.on_update_status = function(status) {  
64 - $("#check_status").text(status);  
65 - }  
66 - bandwidth.on_srs_info = function(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip) {  
67 - $("#check_info").text(  
68 - "server:" + srs_server + ", primary:" + srs_primary + ", authors:" + srs_authors +  
69 - ", srs_id:" + srs_id + ", srs_pid:" + srs_pid + ", ip:" + srs_server_ip  
70 - );  
71 - }  
72 - bandwidth.on_error = function(code) {  
73 - $("#progress_bar").addClass("bar-danger");  
74 - }  
75 - bandwidth.render(url);  
76 - }  
77 - function on_stop_bandwidth_test() {  
78 - bandwidth.stop();  
79 - }  
80 - </script>  
81 </head> 16 </head>
82 <body> 17 <body>
83 <div class="navbar navbar-fixed-top"> 18 <div class="navbar navbar-fixed-top">
@@ -139,4 +74,70 @@ @@ -139,4 +74,70 @@
139 </div> 74 </div>
140 </div> 75 </div>
141 </body> 76 </body>
  77 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  78 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  79 +<script type="text/javascript" src="js/swfobject.js"></script>
  80 +<script type="text/javascript" src="js/srs.page.js"></script>
  81 +<script type="text/javascript" src="js/srs.log.js"></script>
  82 +<script type="text/javascript" src="js/srs.player.js"></script>
  83 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  84 +<script type="text/javascript" src="js/srs.utility.js"></script>
  85 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  86 +<script type="text/javascript" src="srs_bwt/src/srs.bandwidth.js"></script>
  87 +<script type="text/javascript">
  88 + var bandwidth = null;
  89 +
  90 + $(function(){
  91 + srs_init_bwt("#txt_url");
  92 +
  93 + $("#btn_play").click(on_click_play);
  94 + $("#main_modal").on("show", on_start_bandwidth_test);
  95 + $("#main_modal").on("hide", on_stop_bandwidth_test);
  96 + });
  97 +
  98 + function on_click_play() {
  99 + $("#check_status").text("");
  100 + $("#check_info").text("");
  101 + $("#progress_bar").width("0%");
  102 + $("#main_modal").modal({show:true, keyboard:false});
  103 + }
  104 + function on_start_bandwidth_test() {
  105 + $("#div_container").remove();
  106 + $("#progress_bar").removeClass("bar-danger");
  107 +
  108 + var div_container = $("<div/>");
  109 + $(div_container).attr("id", "div_container");
  110 + $("#player").append(div_container);
  111 +
  112 + var player = $("<div/>");
  113 + $(player).attr("id", "player_id");
  114 + $(div_container).append(player);
142 115
  116 + var url = $("#txt_url").val();
  117 +
  118 + bandwidth = new SrsBandwidth("player_id", 100, 1);
  119 + bandwidth.on_bandwidth_ready = function() {
  120 + this.check_bandwidth(url);
  121 + }
  122 + bandwidth.on_update_progress = function(percent) {
  123 + $("#progress_bar").width(percent + "%");
  124 + }
  125 + bandwidth.on_update_status = function(status) {
  126 + $("#check_status").text(status);
  127 + }
  128 + bandwidth.on_srs_info = function(srs_server, srs_primary, srs_authors, srs_id, srs_pid, srs_server_ip) {
  129 + $("#check_info").text(
  130 + "server:" + srs_server + ", primary:" + srs_primary + ", authors:" + srs_authors +
  131 + ", srs_id:" + srs_id + ", srs_pid:" + srs_pid + ", ip:" + srs_server_ip
  132 + );
  133 + }
  134 + bandwidth.on_error = function(code) {
  135 + $("#progress_bar").addClass("bar-danger");
  136 + }
  137 + bandwidth.render(url);
  138 + }
  139 + function on_stop_bandwidth_test() {
  140 + bandwidth.stop();
  141 + }
  142 +</script>
  143 +</html>
@@ -4,15 +4,6 @@ @@ -4,15 +4,6 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/json2.js"></script>  
11 - <script type="text/javascript" src="js/srs.page.js"></script>  
12 - <script type="text/javascript" src="js/srs.log.js"></script>  
13 - <script type="text/javascript" src="js/srs.player.js"></script>  
14 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
15 - <script type="text/javascript" src="js/srs.utility.js"></script>  
16 <style> 7 <style>
17 body{ 8 body{
18 padding-top: 55px; 9 padding-top: 55px;
@@ -21,7 +12,255 @@ @@ -21,7 +12,255 @@
21 width: 310px; 12 width: 310px;
22 } 13 }
23 </style> 14 </style>
24 - <script type="text/javascript"> 15 +</head>
  16 +<body>
  17 +<div class="navbar navbar-fixed-top">
  18 + <div class="navbar-inner">
  19 + <div class="container">
  20 + <a id="srs_index" class="brand" href="#">SRS</a>
  21 + <div class="nav-collapse collapse">
  22 + <ul class="nav">
  23 + <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
  24 + <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
  25 + <li class="active"><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
  26 + <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
  27 + <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
  28 + <li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
  29 + <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
  30 + </ul>
  31 + </div>
  32 + </div>
  33 + </div>
  34 +</div>
  35 +<div class="container">
  36 + <!-- for the log -->
  37 + <div class="alert alert-info fade in" id="txt_log">
  38 + <button type="button" class="close" data-dismiss="alert">×</button>
  39 + <strong><span id="txt_log_title">Usage:</span></strong>
  40 + <span id="txt_log_msg">输入名字,设点“加入会议”按钮</span>
  41 + </div>
  42 +
  43 + <div class="control-group">
  44 + <div class="form-inline">
  45 + <button class="btn input-small" id="btn_video_settings">摄像头</button>
  46 + <button class="btn input-small" id="btn_audio_settings">麦克风</button>
  47 + <input type="text" id="txt_name" class="input-large" placeholder="请输入您的名字..." value=""></input>
  48 + <button class="btn input-small" id="btn_join">加入会议</button>
  49 + <input type="text" id="txt_url" class="input-mini hide" value=""></input>
  50 + </div>
  51 + </div>
  52 + <table id="lst_chats" class="table">
  53 + <tr>
  54 + <td id="td_0">
  55 + <div class="accordion-group">
  56 + <div class="accordion-heading">
  57 + <span class="accordion-toggle">
  58 + <strong>[我的] 本地摄像头</strong>
  59 + </span>
  60 + </div>
  61 + <div class="accordion-body collapse in">
  62 + <div class="accordion-inner">
  63 + <div id="local_publisher"></div>
  64 + </div>
  65 + </div>
  66 + </div>
  67 + </td>
  68 + <td id="td_1">
  69 + <div class="accordion-group">
  70 + <div class="accordion-heading">
  71 + <span class="accordion-toggle">
  72 + <strong>[我的] 远程服务器流</strong>
  73 + <a id="realtime_player_url" href="#" data-toggle="tooltip" data-placement="top" title="">
  74 + 播放地址<img src="img/tooltip.png"/>
  75 + </a>
  76 + </span>
  77 + </div>
  78 + <div class="accordion-body collapse in">
  79 + <div class="accordion-inner">
  80 + <div id="realtime_player"></div>
  81 + </div>
  82 + </div>
  83 + </div>
  84 + </td>
  85 + <td id="td_2"></td>
  86 + </tr>
  87 + </table>
  88 + <div class="container hide" id="template">
  89 + <div class="accordion-group" id="collapse_main">
  90 + <div class="accordion-heading" title="点击展开或收起,收起后停止播放流,展开时从服务器请求流">
  91 + <span id="headerN" class="accordion-toggle" data-toggle="collapse" href="#collapseN">
  92 + <strong>[<a href="#"><span id="user_name">XX</span></a>]</strong>
  93 + <strong>加入时间</strong>[<span id="join_date"></span>]
  94 + <a id="user_player_url" href="#" data-toggle="tooltip" data-placement="top" title="">
  95 + 播放地址<img src="img/tooltip.png"/>
  96 + </a>
  97 + </span>
  98 + </div>
  99 + <div id="collapseM" class="accordion-body collapse in">
  100 + <div class="accordion-inner">
  101 + <div id="chat_player">
  102 + <div id="chat_player_raw">
  103 + </div>
  104 + </div>
  105 + </div>
  106 + </div>
  107 + </div>
  108 + </div>
  109 + <table class="table">
  110 + </table>
  111 + <div id="video_modal" class="modal hide fade">
  112 + <div class="modal-header">
  113 + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
  114 + <h3>视频编码</h3>
  115 + </div>
  116 + <div class="modal-body">
  117 + <div class="form-horizontal">
  118 + <div class="control-group">
  119 + <label class="control-label" for="sl_cameras">
  120 + 摄像头
  121 + <a id="sl_cameras_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  122 + <img src="img/tooltip.png"/>
  123 + </a>
  124 + </label>
  125 + <div class="controls">
  126 + <select class="span4" id="sl_cameras"></select>
  127 + </div>
  128 + </div>
  129 + <div class="control-group">
  130 + <label class="control-label" for="sl_vcodec">
  131 + Codec
  132 + <a id="sl_cameras_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  133 + <img src="img/tooltip.png"/>
  134 + </a>
  135 + </label>
  136 + <div class="controls">
  137 + <select class="span2" id="sl_vcodec"></select>
  138 + </div>
  139 + </div>
  140 + <div class="control-group">
  141 + <label class="control-label" for="sl_profile">
  142 + Profile
  143 + <a id="sl_profile_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  144 + <img src="img/tooltip.png"/>
  145 + </a>
  146 + </label>
  147 + <div class="controls">
  148 + <select class="span2" id="sl_profile"></select>
  149 + </div>
  150 + </div>
  151 + <div class="control-group">
  152 + <label class="control-label" for="sl_level">
  153 + Level
  154 + <a id="sl_level_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  155 + <img src="img/tooltip.png"/>
  156 + </a>
  157 + </label>
  158 + <div class="controls">
  159 + <select class="span2" id="sl_level"></select>
  160 + </div>
  161 + </div>
  162 + <div class="control-group">
  163 + <label class="control-label" for="sl_gop">
  164 + GOP
  165 + <a id="sl_gop_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  166 + <img src="img/tooltip.png"/>
  167 + </a>
  168 + </label>
  169 + <div class="controls">
  170 + <select class="span2" id="sl_gop"></select>
  171 + </div>
  172 + </div>
  173 + <div class="control-group">
  174 + <label class="control-label" for="sl_size">
  175 + 尺寸
  176 + <a id="sl_size_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  177 + <img src="img/tooltip.png"/>
  178 + </a>
  179 + </label>
  180 + <div class="controls">
  181 + <select class="span2" id="sl_size"></select>
  182 + </div>
  183 + </div>
  184 + <div class="control-group">
  185 + <label class="control-label" for="sl_fps">
  186 + 帧率
  187 + <a id="sl_fps_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  188 + <img src="img/tooltip.png"/>
  189 + </a>
  190 + </label>
  191 + <div class="controls">
  192 + <select class="span2" id="sl_fps"></select>
  193 + </div>
  194 + </div>
  195 + <div class="control-group">
  196 + <label class="control-label" for="sl_bitrate">
  197 + 码率
  198 + <a id="sl_bitrate_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  199 + <img src="img/tooltip.png"/>
  200 + </a>
  201 + </label>
  202 + <div class="controls">
  203 + <select class="span2" id="sl_bitrate"></select>
  204 + </div>
  205 + </div>
  206 + </div>
  207 + </div>
  208 + <div class="modal-footer">
  209 + <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">设置</button>
  210 + </div>
  211 + </div>
  212 + <div id="audio_modal" class="modal hide fade">
  213 + <div class="modal-header">
  214 + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
  215 + <h3>音频编码</h3>
  216 + </div>
  217 + <div class="modal-body">
  218 + <div class="form-horizontal">
  219 + <div class="control-group">
  220 + <label class="control-label" for="sl_microphones">
  221 + 麦克风
  222 + <a id="worker_id_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  223 + <img src="img/tooltip.png"/>
  224 + </a>
  225 + </label>
  226 + <div class="controls">
  227 + <select class="span4" id="sl_microphones"></select>
  228 + </div>
  229 + </div>
  230 + <div class="control-group">
  231 + <label class="control-label" for="sl_acodec">
  232 + 编码
  233 + <a id="sl_acodec_tips" href="#" data-toggle="tooltip" data-placement="right" title="">
  234 + <img src="img/tooltip.png"/>
  235 + </a>
  236 + </label>
  237 + <div class="controls">
  238 + <select class="span2" id="sl_acodec"></select>
  239 + </div>
  240 + </div>
  241 + </div>
  242 + </div>
  243 + <div class="modal-footer">
  244 + <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">设置</button>
  245 + </div>
  246 + </div>
  247 + <hr/>
  248 + <footer>
  249 + <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p>
  250 + </footer>
  251 +</div>
  252 +</body>
  253 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  254 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  255 +<script type="text/javascript" src="js/swfobject.js"></script>
  256 +<script type="text/javascript" src="js/json2.js"></script>
  257 +<script type="text/javascript" src="js/srs.page.js"></script>
  258 +<script type="text/javascript" src="js/srs.log.js"></script>
  259 +<script type="text/javascript" src="js/srs.player.js"></script>
  260 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  261 +<script type="text/javascript" src="js/srs.utility.js"></script>
  262 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  263 +<script type="text/javascript">
25 var srs_publisher = null; 264 var srs_publisher = null;
26 var realtime_player = null; 265 var realtime_player = null;
27 var api_server = null; 266 var api_server = null;
@@ -546,243 +785,6 @@ @@ -546,243 +785,6 @@
546 } 785 }
547 }); 786 });
548 } 787 }
549 - </script>  
550 -</head>  
551 -<body>  
552 -<div class="navbar navbar-fixed-top">  
553 - <div class="navbar-inner">  
554 - <div class="container">  
555 - <a id="srs_index" class="brand" href="#">SRS</a>  
556 - <div class="nav-collapse collapse">  
557 - <ul class="nav">  
558 - <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>  
559 - <li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>  
560 - <li class="active"><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>  
561 - <li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>  
562 - <li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>  
563 - <li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>  
564 - <li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>  
565 - </ul>  
566 - </div>  
567 - </div>  
568 - </div>  
569 -</div>  
570 -<div class="container">  
571 - <!-- for the log -->  
572 - <div class="alert alert-info fade in" id="txt_log">  
573 - <button type="button" class="close" data-dismiss="alert">×</button>  
574 - <strong><span id="txt_log_title">Usage:</span></strong>  
575 - <span id="txt_log_msg">输入名字,设点“加入会议”按钮</span>  
576 - </div>  
577 -  
578 - <div class="control-group">  
579 - <div class="form-inline">  
580 - <button class="btn input-small" id="btn_video_settings">摄像头</button>  
581 - <button class="btn input-small" id="btn_audio_settings">麦克风</button>  
582 - <input type="text" id="txt_name" class="input-large" placeholder="请输入您的名字..." value=""></input>  
583 - <button class="btn input-small" id="btn_join">加入会议</button>  
584 - <input type="text" id="txt_url" class="input-mini hide" value=""></input>  
585 - </div>  
586 - </div>  
587 - <table id="lst_chats" class="table">  
588 - <tr>  
589 - <td id="td_0">  
590 - <div class="accordion-group">  
591 - <div class="accordion-heading">  
592 - <span class="accordion-toggle">  
593 - <strong>[我的] 本地摄像头</strong>  
594 - </span>  
595 - </div>  
596 - <div class="accordion-body collapse in">  
597 - <div class="accordion-inner">  
598 - <div id="local_publisher"></div>  
599 - </div>  
600 - </div>  
601 - </div>  
602 - </td>  
603 - <td id="td_1">  
604 - <div class="accordion-group">  
605 - <div class="accordion-heading">  
606 - <span class="accordion-toggle">  
607 - <strong>[我的] 远程服务器流</strong>  
608 - <a id="realtime_player_url" href="#" data-toggle="tooltip" data-placement="top" title="">  
609 - 播放地址<img src="img/tooltip.png"/>  
610 - </a>  
611 - </span>  
612 - </div>  
613 - <div class="accordion-body collapse in">  
614 - <div class="accordion-inner">  
615 - <div id="realtime_player"></div>  
616 - </div>  
617 - </div>  
618 - </div>  
619 - </td>  
620 - <td id="td_2"></td>  
621 - </tr>  
622 - </table>  
623 - <div class="container hide" id="template">  
624 - <div class="accordion-group" id="collapse_main">  
625 - <div class="accordion-heading" title="点击展开或收起,收起后停止播放流,展开时从服务器请求流">  
626 - <span id="headerN" class="accordion-toggle" data-toggle="collapse" href="#collapseN">  
627 - <strong>[<a href="#"><span id="user_name">XX</span></a>]</strong>  
628 - <strong>加入时间</strong>[<span id="join_date"></span>]  
629 - <a id="user_player_url" href="#" data-toggle="tooltip" data-placement="top" title="">  
630 - 播放地址<img src="img/tooltip.png"/>  
631 - </a>  
632 - </span>  
633 - </div>  
634 - <div id="collapseM" class="accordion-body collapse in">  
635 - <div class="accordion-inner">  
636 - <div id="chat_player">  
637 - <div id="chat_player_raw">  
638 - </div>  
639 - </div>  
640 - </div>  
641 - </div>  
642 - </div>  
643 - </div>  
644 - <table class="table">  
645 - </table>  
646 - <div id="video_modal" class="modal hide fade">  
647 - <div class="modal-header">  
648 - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>  
649 - <h3>视频编码</h3>  
650 - </div>  
651 - <div class="modal-body">  
652 - <div class="form-horizontal">  
653 - <div class="control-group">  
654 - <label class="control-label" for="sl_cameras">  
655 - 摄像头  
656 - <a id="sl_cameras_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
657 - <img src="img/tooltip.png"/>  
658 - </a>  
659 - </label>  
660 - <div class="controls">  
661 - <select class="span4" id="sl_cameras"></select>  
662 - </div>  
663 - </div>  
664 - <div class="control-group">  
665 - <label class="control-label" for="sl_vcodec">  
666 - Codec  
667 - <a id="sl_cameras_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
668 - <img src="img/tooltip.png"/>  
669 - </a>  
670 - </label>  
671 - <div class="controls">  
672 - <select class="span2" id="sl_vcodec"></select>  
673 - </div>  
674 - </div>  
675 - <div class="control-group">  
676 - <label class="control-label" for="sl_profile">  
677 - Profile  
678 - <a id="sl_profile_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
679 - <img src="img/tooltip.png"/>  
680 - </a>  
681 - </label>  
682 - <div class="controls">  
683 - <select class="span2" id="sl_profile"></select>  
684 - </div>  
685 - </div>  
686 - <div class="control-group">  
687 - <label class="control-label" for="sl_level">  
688 - Level  
689 - <a id="sl_level_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
690 - <img src="img/tooltip.png"/>  
691 - </a>  
692 - </label>  
693 - <div class="controls">  
694 - <select class="span2" id="sl_level"></select>  
695 - </div>  
696 - </div>  
697 - <div class="control-group">  
698 - <label class="control-label" for="sl_gop">  
699 - GOP  
700 - <a id="sl_gop_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
701 - <img src="img/tooltip.png"/>  
702 - </a>  
703 - </label>  
704 - <div class="controls">  
705 - <select class="span2" id="sl_gop"></select>  
706 - </div>  
707 - </div>  
708 - <div class="control-group">  
709 - <label class="control-label" for="sl_size">  
710 - 尺寸  
711 - <a id="sl_size_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
712 - <img src="img/tooltip.png"/>  
713 - </a>  
714 - </label>  
715 - <div class="controls">  
716 - <select class="span2" id="sl_size"></select>  
717 - </div>  
718 - </div>  
719 - <div class="control-group">  
720 - <label class="control-label" for="sl_fps">  
721 - 帧率  
722 - <a id="sl_fps_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
723 - <img src="img/tooltip.png"/>  
724 - </a>  
725 - </label>  
726 - <div class="controls">  
727 - <select class="span2" id="sl_fps"></select>  
728 - </div>  
729 - </div>  
730 - <div class="control-group">  
731 - <label class="control-label" for="sl_bitrate">  
732 - 码率  
733 - <a id="sl_bitrate_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
734 - <img src="img/tooltip.png"/>  
735 - </a>  
736 - </label>  
737 - <div class="controls">  
738 - <select class="span2" id="sl_bitrate"></select>  
739 - </div>  
740 - </div>  
741 - </div>  
742 - </div>  
743 - <div class="modal-footer">  
744 - <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">设置</button>  
745 - </div>  
746 - </div>  
747 - <div id="audio_modal" class="modal hide fade">  
748 - <div class="modal-header">  
749 - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>  
750 - <h3>音频编码</h3>  
751 - </div>  
752 - <div class="modal-body">  
753 - <div class="form-horizontal">  
754 - <div class="control-group">  
755 - <label class="control-label" for="sl_microphones">  
756 - 麦克风  
757 - <a id="worker_id_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
758 - <img src="img/tooltip.png"/>  
759 - </a>  
760 - </label>  
761 - <div class="controls">  
762 - <select class="span4" id="sl_microphones"></select>  
763 - </div>  
764 - </div>  
765 - <div class="control-group">  
766 - <label class="control-label" for="sl_acodec">  
767 - 编码  
768 - <a id="sl_acodec_tips" href="#" data-toggle="tooltip" data-placement="right" title="">  
769 - <img src="img/tooltip.png"/>  
770 - </a>  
771 - </label>  
772 - <div class="controls">  
773 - <select class="span2" id="sl_acodec"></select>  
774 - </div>  
775 - </div>  
776 - </div>  
777 - </div>  
778 - <div class="modal-footer">  
779 - <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">设置</button>  
780 - </div>  
781 - </div>  
782 - <hr/>  
783 - <footer>  
784 - <p><a href="https://github.com/simple-rtmp-server/srs">SRS Team &copy; 2013</a></p>  
785 - </footer>  
786 -</div>  
787 -</body> 788 +</script>
  789 +</html>
788 790
@@ -4,15 +4,6 @@ @@ -4,15 +4,6 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/json2.js"></script>  
11 - <script type="text/javascript" src="js/srs.page.js"></script>  
12 - <script type="text/javascript" src="js/srs.log.js"></script>  
13 - <script type="text/javascript" src="js/srs.player.js"></script>  
14 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
15 - <script type="text/javascript" src="js/srs.utility.js"></script>  
16 <style> 7 <style>
17 body{ 8 body{
18 padding-top: 55px; 9 padding-top: 55px;
@@ -21,7 +12,7 @@ @@ -21,7 +12,7 @@
21 margin-top: -20px; 12 margin-top: -20px;
22 padding-top: 3px; 13 padding-top: 3px;
23 } 14 }
24 - #div_play_time { 15 + .div_play_time {
25 margin-top: 10px; 16 margin-top: 10px;
26 } 17 }
27 #pb_buffer_bg { 18 #pb_buffer_bg {
@@ -29,250 +20,6 @@ @@ -29,250 +20,6 @@
29 margin-bottom: 10px; 20 margin-bottom: 10px;
30 } 21 }
31 </style> 22 </style>
32 - <script type="text/javascript">  
33 - var srs_player = null;  
34 - var url = null;  
35 -  
36 - var __active_dar = null;  
37 - function select_dar(dar_id, num, den) {  
38 - srs_player.set_dar(num, den);  
39 -  
40 - if (__active_dar) {  
41 - __active_dar.removeClass("active");  
42 - }  
43 -  
44 - __active_dar = $(dar_id).parent();  
45 - __active_dar.addClass("active");  
46 - }  
47 -  
48 - var __active_size = null;  
49 - function select_fs_size(size_id, refer, percent) {  
50 - srs_player.set_fs(refer, percent);  
51 -  
52 - if (__active_size) {  
53 - __active_size.removeClass("active");  
54 - }  
55 -  
56 - __active_size = $(size_id).parent();  
57 - __active_size.addClass("active");  
58 - }  
59 -  
60 - var __active_bt = null;  
61 - function select_buffer_time(bt_id, buffer_time) {  
62 - srs_player.set_bt(buffer_time);  
63 -  
64 - if (__active_bt) {  
65 - __active_bt.removeClass("active");  
66 - }  
67 -  
68 - __active_bt = $(bt_id).parent();  
69 - __active_bt.addClass("active");  
70 - }  
71 -  
72 - $(function(){  
73 - // get the vhost and port to set the default url.  
74 - // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo  
75 - // url set to: rtmp://demo:1935/live/livestream  
76 - srs_init("#txt_url", null, "#main_modal");  
77 -  
78 - $("#fs_tips").tooltip({  
79 - title: "点击视频进入或退出全屏"  
80 - });  
81 -  
82 - $("#main_modal").on("show", function(){  
83 - if (srs_player) {  
84 - return;  
85 - }  
86 -  
87 - $("#div_container").remove();  
88 -  
89 - var div_container = $("<div/>");  
90 - $(div_container).attr("id", "div_container");  
91 - $("#player").append(div_container);  
92 -  
93 - var player = $("<div/>");  
94 - $(player).attr("id", "player_id");  
95 - $(div_container).append(player);  
96 -  
97 - srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height());  
98 - srs_player.on_player_ready = function() {  
99 - select_buffer_time("#btn_bt_0_1", 0.1);  
100 - this.play(url);  
101 - };  
102 - srs_player.on_player_metadata = function(metadata) {  
103 - $("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")");  
104 - select_dar("#btn_dar_original", 0, 0);  
105 - select_fs_size("#btn_fs_size_screen_100", "screen", 100);  
106 - };  
107 - srs_player.on_player_timer = function(time, buffer_length) {  
108 - var buffer = buffer_length / this.buffer_time * 100;  
109 - $("#pb_buffer").width(Number(buffer).toFixed(1) + "%");  
110 -  
111 - $("#pb_buffer_bg").attr("title",  
112 - "缓冲区长度:" + Number(buffer_length).toFixed(1) + "秒("  
113 - + Number(buffer).toFixed(1) + "%)");  
114 -  
115 - var time_str = "";  
116 - // day  
117 - time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " ";  
118 - // hour  
119 - time = time % (24 * 3600);  
120 - time_str += padding(parseInt(time / 3600), 2, '0') + ":";  
121 - // minute  
122 - time = time % (3600);  
123 - time_str += padding(parseInt(time / 60), 2, '0') + ":";  
124 - // seconds  
125 - time = time % (60);  
126 - time_str += padding(parseInt(time), 2, '0');  
127 - // show  
128 - $("#txt_time").val(time_str);  
129 - };  
130 - srs_player.start();  
131 - });  
132 -  
133 - $("#main_modal").on("hide", function(){  
134 - if ($("#main_modal").is(":visible")) {  
135 - return;  
136 - }  
137 -  
138 - if (srs_player) {  
139 - srs_player.stop();  
140 - srs_player = null;  
141 - }  
142 - });  
143 -  
144 - $("#btn_play").click(function(){  
145 - url = $("#txt_url").val();  
146 - $("#main_modal").modal({show:true, keyboard:false});  
147 - });  
148 -  
149 - $("#btn_pause").click(function(){  
150 - if ($("#btn_pause").text() == "暂停") {  
151 - $("#btn_pause").text("继续");  
152 - srs_player.pause();  
153 - } else {  
154 - $("#btn_pause").text("暂停");  
155 - srs_player.resume();  
156 - }  
157 - });  
158 -  
159 - $("#srs_publish").click(function(){  
160 - url = $("#srs_publish").text();  
161 - $("#main_modal").modal({show:true, keyboard:false});  
162 - });  
163 - $("#srs_publish_ld").click(function(){  
164 - url = $("#srs_publish_ld").text();  
165 - $("#main_modal").modal({show:true, keyboard:false});  
166 - });  
167 - $("#srs_publish_sd").click(function(){  
168 - url = $("#srs_publish_sd").text();  
169 - $("#main_modal").modal({show:true, keyboard:false});  
170 - });  
171 - $("#srs_publish_fw").click(function(){  
172 - url = $("#srs_publish_fw").text();  
173 - $("#main_modal").modal({show:true, keyboard:false});  
174 - });  
175 - $("#srs_publish_fw_ld").click(function(){  
176 - url = $("#srs_publish_fw_ld").text();  
177 - $("#main_modal").modal({show:true, keyboard:false});  
178 - });  
179 - $("#srs_publish_fw_sd").click(function(){  
180 - url = $("#srs_publish_fw_sd").text();  
181 - $("#main_modal").modal({show:true, keyboard:false});  
182 - });  
183 -  
184 - var query = parse_query_string();  
185 - var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=live&hls_autostart=true";  
186 - $("#srs_publish_hls").attr("href", jwplayer_url + "&stream=livestream");  
187 - $("#srs_publish_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");  
188 - $("#srs_publish_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");  
189 - var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=forward/live&hls_autostart=true";  
190 - $("#srs_publish_fw_hls").attr("href", jwplayer_url + "&stream=livestream");  
191 - $("#srs_publish_fw_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");  
192 - $("#srs_publish_fw_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");  
193 -  
194 - if (true) {  
195 - $("#btn_dar_original").click(function(){  
196 - select_dar("#btn_dar_original", 0, 0);  
197 - });  
198 - $("#btn_dar_21_9").click(function(){  
199 - select_dar("#btn_dar_21_9", 21, 9);  
200 - });  
201 - $("#btn_dar_16_9").click(function(){  
202 - select_dar("#btn_dar_16_9", 16, 9);  
203 - });  
204 - $("#btn_dar_4_3").click(function(){  
205 - select_dar("#btn_dar_4_3", 4, 3);  
206 - });  
207 - $("#btn_dar_fill").click(function(){  
208 - select_dar("#btn_dar_fill", -1, -1);  
209 - });  
210 - }  
211 -  
212 - if (true) {  
213 - $("#btn_fs_size_video_100").click(function(){  
214 - select_fs_size("#btn_fs_size_video_100", "video", 100);  
215 - });  
216 - $("#btn_fs_size_video_75").click(function(){  
217 - select_fs_size("#btn_fs_size_video_75", "video", 75);  
218 - });  
219 - $("#btn_fs_size_video_50").click(function(){  
220 - select_fs_size("#btn_fs_size_video_50", "video", 50);  
221 - });  
222 - $("#btn_fs_size_screen_100").click(function(){  
223 - select_fs_size("#btn_fs_size_screen_100", "screen", 100);  
224 - });  
225 - $("#btn_fs_size_screen_75").click(function(){  
226 - select_fs_size("#btn_fs_size_screen_75", "screen", 75);  
227 - });  
228 - $("#btn_fs_size_screen_50").click(function(){  
229 - select_fs_size("#btn_fs_size_screen_50", "screen", 50);  
230 - });  
231 - }  
232 -  
233 - if (true) {  
234 - $("#btn_bt_0_1").click(function(){  
235 - select_buffer_time("#btn_bt_0_1", 0.1);  
236 - });  
237 - $("#btn_bt_0_2").click(function(){  
238 - select_buffer_time("#btn_bt_0_2", 0.2);  
239 - });  
240 - $("#btn_bt_0_3").click(function(){  
241 - select_buffer_time("#btn_bt_0_3", 0.3);  
242 - });  
243 - $("#btn_bt_0_5").click(function(){  
244 - select_buffer_time("#btn_bt_0_5", 0.5);  
245 - });  
246 - $("#btn_bt_0_8").click(function(){  
247 - select_buffer_time("#btn_bt_0_8", 0.8);  
248 - });  
249 - $("#btn_bt_1").click(function(){  
250 - select_buffer_time("#btn_bt_1", 1);  
251 - });  
252 - $("#btn_bt_2").click(function(){  
253 - select_buffer_time("#btn_bt_2", 2);  
254 - });  
255 - $("#btn_bt_3").click(function(){  
256 - select_buffer_time("#btn_bt_3", 3);  
257 - });  
258 - $("#btn_bt_5").click(function(){  
259 - select_buffer_time("#btn_bt_5", 5);  
260 - });  
261 - $("#btn_bt_10").click(function(){  
262 - select_buffer_time("#btn_bt_10", 10);  
263 - });  
264 - $("#btn_bt_30").click(function(){  
265 - select_buffer_time("#btn_bt_30", 30);  
266 - });  
267 - }  
268 -  
269 - var query = parse_query_string();  
270 - if (query.autostart == "true") {  
271 - url = $("#txt_url").val();  
272 - $("#main_modal").modal({show:true, keyboard:false});  
273 - }  
274 - });  
275 - </script>  
276 </head> 23 </head>
277 <body> 24 <body>
278 <div class="navbar navbar-fixed-top"> 25 <div class="navbar navbar-fixed-top">
@@ -300,8 +47,62 @@ @@ -300,8 +47,62 @@
300 </div> 47 </div>
301 <div class="form-inline"> 48 <div class="form-inline">
302 URL: 49 URL:
303 - <input type="text" id="txt_url" class="input-xxlarge" value=""></input> 50 + <input type="text" id="txt_url" class="input-xxlarge" value="">
304 <button class="btn btn-primary" id="btn_play">播放视频</button> 51 <button class="btn btn-primary" id="btn_play">播放视频</button>
  52 + <button class="btn" id="btn_generate_link">生成链接</button>
  53 + </div>
  54 + <div id="link_modal" class="modal hide fade">
  55 + <div class="modal-header">
  56 + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
  57 + <h3><a href="https://github.com/simple-rtmp-server/srs">SRS Link Generator</a></h3>
  58 + </div>
  59 + <div class="modal-body">
  60 + <div class="form-horizontal">
  61 + <div class="control-group">
  62 + <label class="control-label" for="link_server">服务器地址</label>
  63 + <div class="controls">
  64 + <span id="link_server" class="span4 uneditable-input"></span>
  65 + </div>
  66 + </div>
  67 + <div class="control-group">
  68 + <label class="control-label" for="link_port">服务器端口</label>
  69 + <div class="controls">
  70 + <span id="link_port" class="span2 uneditable-input"></span>
  71 + </div>
  72 + </div>
  73 + <div class="control-group">
  74 + <label class="control-label" for="link_vhost">RTMP Vhost</label>
  75 + <div class="controls">
  76 + <span id="link_vhost" class="span4 uneditable-input"></span>
  77 + </div>
  78 + </div>
  79 + <div class="control-group">
  80 + <label class="control-label" for="link_app">RTMP App</label>
  81 + <div class="controls">
  82 + <span id="link_app" class="span4 uneditable-input"></span>
  83 + </div>
  84 + </div>
  85 + <div class="control-group">
  86 + <label class="control-label" for="link_stream">RTMP Stream</label>
  87 + <div class="controls">
  88 + <span id="link_stream" class="span4 uneditable-input"></span>
  89 + </div>
  90 + </div>
  91 + <div class="control-group">
  92 + <label class="control-label" for="link_rtmp">RTMP地址</label>
  93 + <div class="controls">
  94 + <span id="link_rtmp" class="span4 uneditable-input"></span>
  95 + </div>
  96 + </div>
  97 + <div class="control-group">
  98 + <label class="control-label" for="link_url">播放链接地址</label>
  99 + <div class="controls">
  100 + <div style="margin-top:5px;"><a href="#" id="link_url" target="_blank">请右键拷贝此链接地址.</a></div>
  101 + </div>
  102 + </div>
  103 + </div>
  104 + </div>
  105 + <div class="modal-footer"></div>
305 </div> 106 </div>
306 <div class="container"> 107 <div class="container">
307 <hr/> 108 <hr/>
@@ -480,16 +281,10 @@ @@ -480,16 +281,10 @@
480 </div> 281 </div>
481 </div> 282 </div>
482 <div class="modal-footer" id="my_modal_footer"> 283 <div class="modal-footer" id="my_modal_footer">
483 - <div class="input-prepend" id="div_play_time">  
484 - <span class="add-on" title="播放时长">@T</span>  
485 - <input class="span2" style="width:85px" id="txt_time" type="text" placeholder="天 时:分:秒">  
486 - </div> 284 + <div>
487 <div class="btn-group dropup"> 285 <div class="btn-group dropup">
488 <button class="btn dropdown-toggle" data-toggle="dropdown"> 286 <button class="btn dropdown-toggle" data-toggle="dropdown">
489 - <a id="fs_tips" href="#" data-toggle="tooltip" data-placement="top" title="">  
490 - <img src="img/tooltip.png"/>  
491 - </a>  
492 - 全屏大小<span class="caret"></span> 287 + 设置全屏比例大小<span class="caret"></span>
493 </button> 288 </button>
494 <ul class="dropdown-menu"> 289 <ul class="dropdown-menu">
495 <li><a id="btn_fs_size_screen_100" href="#">屏幕大小(100%)</a></li> 290 <li><a id="btn_fs_size_screen_100" href="#">屏幕大小(100%)</a></li>
@@ -501,7 +296,7 @@ @@ -501,7 +296,7 @@
501 </ul> 296 </ul>
502 </div> 297 </div>
503 <div class="btn-group dropup"> 298 <div class="btn-group dropup">
504 - <button class="btn dropdown-toggle" data-toggle="dropdown">显示比例<span class="caret"></span></button> 299 + <button class="btn dropdown-toggle" data-toggle="dropdown">设置显示比例<span class="caret"></span></button>
505 <ul class="dropdown-menu"> 300 <ul class="dropdown-menu">
506 <li><a id="btn_dar_original" href="#">视频原始比例</a></li> 301 <li><a id="btn_dar_original" href="#">视频原始比例</a></li>
507 <li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li> 302 <li><a id="btn_dar_21_9" href="#">宽屏影院(21:9)</a></li>
@@ -511,7 +306,7 @@ @@ -511,7 +306,7 @@
511 </ul> 306 </ul>
512 </div> 307 </div>
513 <div class="btn-group dropup"> 308 <div class="btn-group dropup">
514 - <button class="btn dropdown-toggle" data-toggle="dropdown">缓冲区<span class="caret"></span></button> 309 + <button class="btn dropdown-toggle" data-toggle="dropdown">设置缓冲区大小<span class="caret"></span></button>
515 <ul class="dropdown-menu"> 310 <ul class="dropdown-menu">
516 <li><a id="btn_bt_0_1" href="#">0.1秒(实时)</a></li> 311 <li><a id="btn_bt_0_1" href="#">0.1秒(实时)</a></li>
517 <li><a id="btn_bt_0_2" href="#">0.2秒(实时)</a></li> 312 <li><a id="btn_bt_0_2" href="#">0.2秒(实时)</a></li>
@@ -527,10 +322,41 @@ @@ -527,10 +322,41 @@
527 </ul> 322 </ul>
528 </div> 323 </div>
529 <div class="btn-group dropup"> 324 <div class="btn-group dropup">
530 - <button id="btn_pause" class="btn">暂停</button> 325 + <a id="btn_fullscreen" class="btn">进入全屏</a>
  326 + </div>
  327 + <div class="btn-group dropup">
  328 + <button id="btn_pause" class="btn">暂停播放</button>
  329 + <button id="btn_resume" class="btn hide">继续播放</button>
531 </div> 330 </div>
532 <div class="btn-group dropup"> 331 <div class="btn-group dropup">
533 - <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭</button> 332 + <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">关闭播放器</button>
  333 + </div>
  334 + </div>
  335 + <div class="hide" id="fullscreen_tips">
  336 +<font color="red">点击视频</font>进入全屏模式~<br/>
  337 + 由于安全原因,Flash全屏无法使用JS触发
  338 + </div>
  339 + <div>
  340 + <div class="input-prepend div_play_time" title="视频的播放流畅度">
  341 + <span class="add-on">@F</span>
  342 + <input class="span2" style="width:57px" id="txt_fluency" type="text" placeholder="100%">
  343 + </div>
  344 + <div class="input-prepend div_play_time" title="视频总共卡顿次数">
  345 + <span class="add-on">@E</span>
  346 + <input class="span2" style="width:85px" id="txt_empty_count" type="text" placeholder="0">
  347 + </div>
  348 + <div class="input-prepend div_play_time" title="视频当前的帧率FPS">
  349 + <span class="add-on">@F</span>
  350 + <input class="span2" style="width:85px" id="txt_fps" type="text" placeholder="fps">
  351 + </div>
  352 + <div class="input-prepend div_play_time" title="视频当前的码率(视频+音频),单位:Kbps">
  353 + <span class="add-on">@B</span>
  354 + <input class="span2" style="width:85px" id="txt_bitrate" type="text" placeholder="kbps">
  355 + </div>
  356 + <div class="input-prepend div_play_time" title="播放时长,格式:天 时:分:秒">
  357 + <span class="add-on">@T</span>
  358 + <input class="span2" style="width:85px" id="txt_time" type="text" placeholder="天 时:分:秒">
  359 + </div>
534 </div> 360 </div>
535 </div> 361 </div>
536 </div> 362 </div>
@@ -539,3 +365,281 @@ @@ -539,3 +365,281 @@
539 </footer> 365 </footer>
540 </div> 366 </div>
541 </body> 367 </body>
  368 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  369 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  370 +<script type="text/javascript" src="js/swfobject.js"></script>
  371 +<script type="text/javascript" src="js/json2.js"></script>
  372 +<script type="text/javascript" src="js/srs.page.js"></script>
  373 +<script type="text/javascript" src="js/srs.log.js"></script>
  374 +<script type="text/javascript" src="js/srs.player.js"></script>
  375 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  376 +<script type="text/javascript" src="js/srs.utility.js"></script>
  377 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  378 +<script type="text/javascript">
  379 + var srs_player = null;
  380 + var url = null;
  381 +
  382 + var __active_dar = null;
  383 + function select_dar(dar_id, num, den) {
  384 + srs_player.set_dar(num, den);
  385 +
  386 + if (__active_dar) {
  387 + __active_dar.removeClass("active");
  388 + }
  389 +
  390 + __active_dar = $(dar_id).parent();
  391 + __active_dar.addClass("active");
  392 + }
  393 +
  394 + var __active_size = null;
  395 + function select_fs_size(size_id, refer, percent) {
  396 + srs_player.set_fs(refer, percent);
  397 +
  398 + if (__active_size) {
  399 + __active_size.removeClass("active");
  400 + }
  401 +
  402 + __active_size = $(size_id).parent();
  403 + __active_size.addClass("active");
  404 + }
  405 +
  406 + var __active_bt = null;
  407 + function select_buffer_time(bt_id, buffer_time) {
  408 + srs_player.set_bt(buffer_time);
  409 +
  410 + if (__active_bt) {
  411 + __active_bt.removeClass("active");
  412 + }
  413 +
  414 + __active_bt = $(bt_id).parent();
  415 + __active_bt.addClass("active");
  416 + }
  417 +
  418 + $(function(){
  419 + var query = parse_query_string();
  420 +
  421 + // get the vhost and port to set the default url.
  422 + // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
  423 + // url set to: rtmp://demo:1935/live/livestream
  424 + srs_init_rtmp("#txt_url", "#main_modal");
  425 +
  426 + $("#main_modal").on("show", function(){
  427 + if (srs_player) {
  428 + return;
  429 + }
  430 +
  431 + $("#div_container").remove();
  432 +
  433 + var div_container = $("<div/>");
  434 + $(div_container).attr("id", "div_container");
  435 + $("#player").append(div_container);
  436 +
  437 + var player = $("<div/>");
  438 + $(player).attr("id", "player_id");
  439 + $(div_container).append(player);
  440 +
  441 + srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height());
  442 + srs_player.on_player_ready = function() {
  443 + select_buffer_time("#btn_bt_0_1", 0.1);
  444 + this.play(url);
  445 + };
  446 + srs_player.on_player_metadata = function(metadata) {
  447 + $("#btn_dar_original").text("视频原始比例" + "(" + metadata.width + ":" + metadata.height + ")");
  448 + select_dar("#btn_dar_original", 0, 0);
  449 + select_fs_size("#btn_fs_size_screen_100", "screen", 100);
  450 + };
  451 + srs_player.on_player_timer = function(time, buffer_length, kbps, fps, rtime) {
  452 + var buffer = buffer_length / this.buffer_time * 100;
  453 + $("#pb_buffer").width(Number(buffer).toFixed(1) + "%");
  454 +
  455 + $("#pb_buffer_bg").attr("title",
  456 + "缓冲区长度:" + Number(buffer_length).toFixed(1) + "秒("
  457 + + Number(buffer).toFixed(1) + "%)");
  458 +
  459 + $("#txt_bitrate").val(kbps.toFixed(1) + "kbps");
  460 + $("#txt_fps").val(fps.toFixed(1) + "fps");
  461 + $("#txt_empty_count").val(srs_player.empty_count() + "次卡顿");
  462 + $("#txt_fluency").val(srs_player.fluency().toFixed(2) + "%");
  463 +
  464 + var time_str = "";
  465 + // day
  466 + time_str = padding(parseInt(time / 24 / 3600), 2, '0') + " ";
  467 + // hour
  468 + time = time % (24 * 3600);
  469 + time_str += padding(parseInt(time / 3600), 2, '0') + ":";
  470 + // minute
  471 + time = time % (3600);
  472 + time_str += padding(parseInt(time / 60), 2, '0') + ":";
  473 + // seconds
  474 + time = time % (60);
  475 + time_str += padding(parseInt(time), 2, '0');
  476 + // show
  477 + $("#txt_time").val(time_str);
  478 + };
  479 + srs_player.start();
  480 + });
  481 +
  482 + $("#main_modal").on("hide", function(){
  483 + if (srs_player) {
  484 + srs_player.stop();
  485 + srs_player = null;
  486 + }
  487 + });
  488 +
  489 + $("#btn_generate_link").click(function(){
  490 + var rtmp = parse_rtmp_url($("#txt_url").val());
  491 + var url = "http://" + query.host + query.pathname + "?"
  492 + + "vhost=" + rtmp.vhost + "&app=" + rtmp.app + "&stream=" + rtmp.stream
  493 + + "&server=" + rtmp.server + "&port=" + rtmp.port
  494 + + "&autostart=true";
  495 + $("#link_server").text(rtmp.server);
  496 + $("#link_port").text(rtmp.port);
  497 + $("#link_vhost").text(rtmp.vhost);
  498 + $("#link_app").text(rtmp.app);
  499 + $("#link_stream").text(rtmp.stream);
  500 + $("#link_rtmp").text($("#txt_url").val());
  501 + $("#link_url").attr("href", url);
  502 + $("#link_modal").modal({show:true, keyboard:true});
  503 + });
  504 +
  505 + $("#btn_play").click(function(){
  506 + url = $("#txt_url").val();
  507 + $("#main_modal").modal({show:true, keyboard:true});
  508 + });
  509 +
  510 + $("#btn_fullscreen").click(function(){
  511 + $("#fullscreen_tips").toggle();
  512 + });
  513 +
  514 + $("#btn_pause").click(function() {
  515 + $("#btn_resume").toggle();
  516 + $("#btn_pause").toggle();
  517 + srs_player.pause();
  518 + });
  519 + $("#btn_resume").click(function(){
  520 + $("#btn_resume").toggle();
  521 + $("#btn_pause").toggle();
  522 + srs_player.resume();
  523 + });
  524 +
  525 + if (true) {
  526 + $("#srs_publish").click(function () {
  527 + url = $("#srs_publish").text();
  528 + $("#main_modal").modal({show: true, keyboard: false});
  529 + });
  530 + $("#srs_publish_ld").click(function () {
  531 + url = $("#srs_publish_ld").text();
  532 + $("#main_modal").modal({show: true, keyboard: false});
  533 + });
  534 + $("#srs_publish_sd").click(function () {
  535 + url = $("#srs_publish_sd").text();
  536 + $("#main_modal").modal({show: true, keyboard: false});
  537 + });
  538 + $("#srs_publish_fw").click(function () {
  539 + url = $("#srs_publish_fw").text();
  540 + $("#main_modal").modal({show: true, keyboard: false});
  541 + });
  542 + $("#srs_publish_fw_ld").click(function () {
  543 + url = $("#srs_publish_fw_ld").text();
  544 + $("#main_modal").modal({show: true, keyboard: false});
  545 + });
  546 + $("#srs_publish_fw_sd").click(function () {
  547 + url = $("#srs_publish_fw_sd").text();
  548 + $("#main_modal").modal({show: true, keyboard: false});
  549 + });
  550 + }
  551 +
  552 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=live&hls_autostart=true";
  553 + if (true) {
  554 + $("#srs_publish_hls").attr("href", jwplayer_url + "&stream=livestream");
  555 + $("#srs_publish_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
  556 + $("#srs_publish_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
  557 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=forward/live&hls_autostart=true";
  558 + $("#srs_publish_fw_hls").attr("href", jwplayer_url + "&stream=livestream");
  559 + $("#srs_publish_fw_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
  560 + $("#srs_publish_fw_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
  561 + }
  562 +
  563 + if (true) {
  564 + $("#btn_dar_original").click(function(){
  565 + select_dar("#btn_dar_original", 0, 0);
  566 + });
  567 + $("#btn_dar_21_9").click(function(){
  568 + select_dar("#btn_dar_21_9", 21, 9);
  569 + });
  570 + $("#btn_dar_16_9").click(function(){
  571 + select_dar("#btn_dar_16_9", 16, 9);
  572 + });
  573 + $("#btn_dar_4_3").click(function(){
  574 + select_dar("#btn_dar_4_3", 4, 3);
  575 + });
  576 + $("#btn_dar_fill").click(function(){
  577 + select_dar("#btn_dar_fill", -1, -1);
  578 + });
  579 + }
  580 +
  581 + if (true) {
  582 + $("#btn_fs_size_video_100").click(function(){
  583 + select_fs_size("#btn_fs_size_video_100", "video", 100);
  584 + });
  585 + $("#btn_fs_size_video_75").click(function(){
  586 + select_fs_size("#btn_fs_size_video_75", "video", 75);
  587 + });
  588 + $("#btn_fs_size_video_50").click(function(){
  589 + select_fs_size("#btn_fs_size_video_50", "video", 50);
  590 + });
  591 + $("#btn_fs_size_screen_100").click(function(){
  592 + select_fs_size("#btn_fs_size_screen_100", "screen", 100);
  593 + });
  594 + $("#btn_fs_size_screen_75").click(function(){
  595 + select_fs_size("#btn_fs_size_screen_75", "screen", 75);
  596 + });
  597 + $("#btn_fs_size_screen_50").click(function(){
  598 + select_fs_size("#btn_fs_size_screen_50", "screen", 50);
  599 + });
  600 + }
  601 +
  602 + if (true) {
  603 + $("#btn_bt_0_1").click(function(){
  604 + select_buffer_time("#btn_bt_0_1", 0.1);
  605 + });
  606 + $("#btn_bt_0_2").click(function(){
  607 + select_buffer_time("#btn_bt_0_2", 0.2);
  608 + });
  609 + $("#btn_bt_0_3").click(function(){
  610 + select_buffer_time("#btn_bt_0_3", 0.3);
  611 + });
  612 + $("#btn_bt_0_5").click(function(){
  613 + select_buffer_time("#btn_bt_0_5", 0.5);
  614 + });
  615 + $("#btn_bt_0_8").click(function(){
  616 + select_buffer_time("#btn_bt_0_8", 0.8);
  617 + });
  618 + $("#btn_bt_1").click(function(){
  619 + select_buffer_time("#btn_bt_1", 1);
  620 + });
  621 + $("#btn_bt_2").click(function(){
  622 + select_buffer_time("#btn_bt_2", 2);
  623 + });
  624 + $("#btn_bt_3").click(function(){
  625 + select_buffer_time("#btn_bt_3", 3);
  626 + });
  627 + $("#btn_bt_5").click(function(){
  628 + select_buffer_time("#btn_bt_5", 5);
  629 + });
  630 + $("#btn_bt_10").click(function(){
  631 + select_buffer_time("#btn_bt_10", 10);
  632 + });
  633 + $("#btn_bt_30").click(function(){
  634 + select_buffer_time("#btn_bt_30", 30);
  635 + });
  636 + }
  637 +
  638 + var query = parse_query_string();
  639 + if (query.autostart == "true") {
  640 + url = $("#txt_url").val();
  641 + $("#main_modal").modal({show:true, keyboard:false});
  642 + }
  643 + });
  644 +</script>
  645 +</html>
@@ -38,3 +38,4 @@ @@ -38,3 +38,4 @@
38 <buildCSSFiles/> 38 <buildCSSFiles/>
39 <flashCatalyst validateFlashCatalystCompatibility="false"/> 39 <flashCatalyst validateFlashCatalystCompatibility="false"/>
40 </actionScriptProperties> 40 </actionScriptProperties>
  41 +
@@ -18,6 +18,7 @@ package @@ -18,6 +18,7 @@ package
18 import flash.ui.ContextMenu; 18 import flash.ui.ContextMenu;
19 import flash.ui.ContextMenuItem; 19 import flash.ui.ContextMenuItem;
20 import flash.utils.Timer; 20 import flash.utils.Timer;
  21 + import flash.utils.getTimer;
21 import flash.utils.setTimeout; 22 import flash.utils.setTimeout;
22 23
23 import flashx.textLayout.formats.Float; 24 import flashx.textLayout.formats.Float;
@@ -30,6 +31,8 @@ package @@ -30,6 +31,8 @@ package
30 private var js_on_player_ready:String = null; 31 private var js_on_player_ready:String = null;
31 private var js_on_player_metadata:String = null; 32 private var js_on_player_metadata:String = null;
32 private var js_on_player_timer:String = null; 33 private var js_on_player_timer:String = null;
  34 + private var js_on_player_empty:String = null;
  35 + private var js_on_player_full:String = null;
33 36
34 // play param url. 37 // play param url.
35 private var user_url:String = null; 38 private var user_url:String = null;
@@ -93,6 +96,8 @@ package @@ -93,6 +96,8 @@ package
93 this.js_on_player_ready = flashvars.on_player_ready; 96 this.js_on_player_ready = flashvars.on_player_ready;
94 this.js_on_player_metadata = flashvars.on_player_metadata; 97 this.js_on_player_metadata = flashvars.on_player_metadata;
95 this.js_on_player_timer = flashvars.on_player_timer; 98 this.js_on_player_timer = flashvars.on_player_timer;
  99 + this.js_on_player_empty = flashvars.on_player_empty;
  100 + this.js_on_player_full = flashvars.on_player_full;
96 101
97 this.media_timer.addEventListener(TimerEvent.TIMER, this.system_on_timer); 102 this.media_timer.addEventListener(TimerEvent.TIMER, this.system_on_timer);
98 this.media_timer.start(); 103 this.media_timer.start();
@@ -106,7 +111,7 @@ package @@ -106,7 +111,7 @@ package
106 */ 111 */
107 private function system_on_js_ready():void { 112 private function system_on_js_ready():void {
108 if (!flash.external.ExternalInterface.available) { 113 if (!flash.external.ExternalInterface.available) {
109 - trace("js not ready, try later."); 114 + log("js not ready, try later.");
110 flash.utils.setTimeout(this.system_on_js_ready, 100); 115 flash.utils.setTimeout(this.system_on_js_ready, 100);
111 return; 116 return;
112 } 117 }
@@ -126,14 +131,38 @@ package @@ -126,14 +131,38 @@ package
126 * system callack event, timer to do some regular tasks. 131 * system callack event, timer to do some regular tasks.
127 */ 132 */
128 private function system_on_timer(evt:TimerEvent):void { 133 private function system_on_timer(evt:TimerEvent):void {
129 - if (!this.media_stream) {  
130 - trace("stream is null, ignore timer event."); 134 + var ms:NetStream = this.media_stream;
  135 +
  136 + if (!ms) {
  137 + log("stream is null, ignore timer event.");
131 return; 138 return;
132 } 139 }
133 140
134 - trace("notify js the timer event."); 141 + var rtime:Number = flash.utils.getTimer();
  142 + var bitrate:Number = Number((ms.info.videoBytesPerSecond + ms.info.audioBytesPerSecond) * 8 / 1000);
  143 + log("on timer, time=" + ms.time.toFixed(2) + "s, buffer=" + ms.bufferLength.toFixed(2) + "s"
  144 + + ", bitrate=" + bitrate.toFixed(1) + "kbps"
  145 + + ", fps=" + ms.currentFPS.toFixed(1)
  146 + + ", rtime=" + rtime.toFixed(0)
  147 + );
135 flash.external.ExternalInterface.call( 148 flash.external.ExternalInterface.call(
136 - this.js_on_player_timer, this.js_id, this.media_stream.time, this.media_stream.bufferLength); 149 + this.js_on_player_timer, this.js_id, ms.time, ms.bufferLength,
  150 + bitrate, ms.currentFPS, rtime
  151 + );
  152 + }
  153 +
  154 + /**
  155 + * system callback event, when stream is empty.
  156 + */
  157 + private function system_on_buffer_empty():void {
  158 + var time:Number = flash.utils.getTimer();
  159 + log("stream is empty at " + time + "ms");
  160 + flash.external.ExternalInterface.call(this.js_on_player_empty, this.js_id, time);
  161 + }
  162 + private function system_on_buffer_full():void {
  163 + var time:Number = flash.utils.getTimer();
  164 + log("stream is full at " + time + "ms");
  165 + flash.external.ExternalInterface.call(this.js_on_player_full, this.js_id, time);
137 } 166 }
138 167
139 /** 168 /**
@@ -181,7 +210,7 @@ package @@ -181,7 +210,7 @@ package
181 */ 210 */
182 private function user_on_click_video(evt:MouseEvent):void { 211 private function user_on_click_video(evt:MouseEvent):void {
183 if (!this.stage.allowsFullScreen) { 212 if (!this.stage.allowsFullScreen) {
184 - trace("donot allow fullscreen."); 213 + log("donot allow fullscreen.");
185 return; 214 return;
186 } 215 }
187 216
@@ -266,6 +295,7 @@ package @@ -266,6 +295,7 @@ package
266 this.media_conn.close(); 295 this.media_conn.close();
267 this.media_conn = null; 296 this.media_conn = null;
268 } 297 }
  298 + log("player stopped");
269 } 299 }
270 300
271 // srs infos 301 // srs infos
@@ -311,7 +341,7 @@ package @@ -311,7 +341,7 @@ package
311 this.user_url = url; 341 this.user_url = url;
312 this.user_w = _width; 342 this.user_w = _width;
313 this.user_h = _height; 343 this.user_h = _height;
314 - trace("start to play url: " + this.user_url + ", w=" + this.user_w + ", h=" + this.user_h); 344 + log("start to play url: " + this.user_url + ", w=" + this.user_w + ", h=" + this.user_h);
315 345
316 js_call_stop(); 346 js_call_stop();
317 347
@@ -358,6 +388,10 @@ package @@ -358,6 +388,10 @@ package
358 388
359 if (evt.info.code == "NetStream.Video.DimensionChange") { 389 if (evt.info.code == "NetStream.Video.DimensionChange") {
360 system_on_metadata(media_metadata); 390 system_on_metadata(media_metadata);
  391 + } else if (evt.info.code == "NetStream.Buffer.Empty") {
  392 + system_on_buffer_empty();
  393 + } else if (evt.info.code == "NetStream.Buffer.Full") {
  394 + system_on_buffer_full();
361 } 395 }
362 396
363 // TODO: FIXME: failed event. 397 // TODO: FIXME: failed event.
@@ -460,7 +494,11 @@ package @@ -460,7 +494,11 @@ package
460 } 494 }
461 495
462 // rescale to fs 496 // rescale to fs
463 - __update_video_size(num, den, obj.width * user_fs_percent / 100, obj.height * user_fs_percent / 100, this.stage.fullScreenWidth, this.stage.fullScreenHeight); 497 + __update_video_size(num, den,
  498 + obj.width * user_fs_percent / 100,
  499 + obj.height * user_fs_percent / 100,
  500 + this.stage.fullScreenWidth, this.stage.fullScreenHeight
  501 + );
464 } 502 }
465 503
466 /** 504 /**
@@ -539,5 +577,18 @@ package @@ -539,5 +577,18 @@ package
539 this.control_fs_mask.graphics.drawRect(0, 0, _width, _height); 577 this.control_fs_mask.graphics.drawRect(0, 0, _width, _height);
540 this.control_fs_mask.graphics.endFill(); 578 this.control_fs_mask.graphics.endFill();
541 } 579 }
  580 +
  581 + private function log(msg:String):void {
  582 + msg = "[" + new Date() +"][srs-player][" + js_id + "] " + msg;
  583 +
  584 + trace(msg);
  585 +
  586 + if (!flash.external.ExternalInterface.available) {
  587 + flash.utils.setTimeout(log, 300, msg);
  588 + return;
  589 + }
  590 +
  591 + ExternalInterface.call("console.log", msg);
  592 + }
542 } 593 }
543 } 594 }
@@ -4,213 +4,11 @@ @@ -4,213 +4,11 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/json2.js"></script>  
11 - <script type="text/javascript" src="js/srs.page.js"></script>  
12 - <script type="text/javascript" src="js/srs.log.js"></script>  
13 - <script type="text/javascript" src="js/srs.player.js"></script>  
14 - <script type="text/javascript" src="js/srs.publisher.js"></script>  
15 - <script type="text/javascript" src="js/srs.utility.js"></script>  
16 <style> 7 <style>
17 body{ 8 body{
18 padding-top: 55px; 9 padding-top: 55px;
19 } 10 }
20 </style> 11 </style>
21 - <script type="text/javascript">  
22 - var srs_publisher = null;  
23 - var remote_player = null;  
24 - var realtime_player = null;  
25 -  
26 - var query = parse_query_string();  
27 - $(function(){  
28 - // get the vhost and port to set the default url.  
29 - // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo  
30 - // url set to: rtmp://demo:1935/live/livestream  
31 - srs_init("#txt_url", null, null);  
32 -  
33 - if (query.agent == "true") {  
34 - document.write(navigator.userAgent);  
35 - return;  
36 - }  
37 -  
38 - $("#btn_video_settings").click(function(){  
39 - $("#video_modal").modal({show:true});  
40 - });  
41 - $("#btn_audio_settings").click(function(){  
42 - $("#audio_modal").modal({show:true});  
43 - });  
44 -  
45 - $("#remote_tips").tooltip({  
46 - title: "为了支持HLS输出,FLASH编码器输出的流需要经过转码(VP6=>H264,MP3=>aac),所以会黑屏较长时间,请耐心等待"  
47 - });  
48 - $("#low_latecy_tips").tooltip({  
49 - title: "服务器不转码直接转发FLASH编码器的流,所以延迟比支持HLS的流要低很多"  
50 - });  
51 - $("#realtime_player_url").tooltip({  
52 - title: "右键复制RTMP地址"  
53 - });  
54 - $("#remote_player_url").tooltip({  
55 - title: "右键复制RTMP地址"  
56 - });  
57 -  
58 - $("#btn_publish").click(on_user_publish);  
59 -  
60 - // for publish, we use randome stream name.  
61 - $("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());  
62 -  
63 - // start the publisher.  
64 - srs_publisher = new SrsPublisher("local_publisher", 430, 185);  
65 - srs_publisher.on_publisher_ready = function(cameras, microphones) {  
66 - srs_publisher_initialize_page(  
67 - cameras, microphones,  
68 - "#sl_cameras", "#sl_microphones",  
69 - "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",  
70 - "#sl_fps", "#sl_bitrate",  
71 - "#sl_acodec"  
72 - );  
73 - };  
74 - srs_publisher.on_publisher_error = function(code, desc) {  
75 - if (!on_publish_stop()) {  
76 - return;  
77 - }  
78 - error(code, desc + "请重试。");  
79 - };  
80 - srs_publisher.on_publisher_warn = function(code, desc) {  
81 - warn(code, desc);  
82 - };  
83 - srs_publisher.start();  
84 -  
85 - update_play_url();  
86 -  
87 - // if no play specified, donot show the player, for debug the publisher.  
88 - if (query.no_play != "true") {  
89 - // start the normal player with HLS supported.  
90 - remote_player = new SrsPlayer("remote_player", 430, 185);  
91 - remote_player.on_player_ready = function() {  
92 - this.set_bt(0.8);  
93 - };  
94 - remote_player.on_player_metadata = function(metadata) {  
95 - this.set_dar(0, 0);  
96 - this.set_fs("screen", 100);  
97 - }  
98 - remote_player.start();  
99 -  
100 - // start the realtime player.  
101 - realtime_player = new SrsPlayer("realtime_player", 430, 185);  
102 - realtime_player.on_player_ready = function() {  
103 - this.set_bt(0.8);  
104 - };  
105 - realtime_player.on_player_metadata = function(metadata) {  
106 - this.set_dar(0, 0);  
107 - this.set_fs("screen", 100);  
108 - }  
109 - realtime_player.start();  
110 - }  
111 - });  
112 -  
113 - function on_publish_stop() {  
114 - if (!srs_can_republish()) {  
115 - $("#btn_join").attr("disabled", true);  
116 - error(0, "您使用的浏览器很弱,请关闭页面后重新打开页面(刷新也不管用)。<br/>推荐使用Chrome/Firefox/Safari/Opera浏览器,支持重试");  
117 -  
118 - srs_log_disabled = true;  
119 - return false;  
120 - }  
121 -  
122 - return true;  
123 - }  
124 -  
125 - /**  
126 - * we generate the transcoded stream url for flash publish donot support HLS  
127 - * which requires aac, so the publish vhost maybe players for example, we  
128 - * use players_pub vhost(transcoded stream to which) for all clients,  
129 - * both players and players_pub are write HLS to the sample dir,  
130 - * it's ok for the players vhost disabled the HLS, only the  
131 - * players_pub enalbed HLS.  
132 - */  
133 - function update_play_url() {  
134 - var url = $("#txt_url").val();  
135 - var ret = srs_parse_rtmp_url(url);  
136 -  
137 - var remote_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app + "...vhost..." + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;  
138 - $("#realtime_player_url").attr("href", url).attr("target", "_blank");  
139 - $("#remote_player_url").attr("href", remote_url).attr("target", "_blank");  
140 -  
141 - var srs_player_url = "http://" + query.host + query.dir + "/srs_player.html?";  
142 - srs_player_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;  
143 - srs_player_url += "&autostart=true";  
144 -  
145 - var srs_player_rt_url = "http://" + query.host + query.dir + "/srs_player.html?";  
146 - srs_player_rt_url += "vhost=" + ret.vhost + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;  
147 - srs_player_rt_url += "&autostart=true";  
148 -  
149 - var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?";  
150 - jwplayer_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;  
151 - jwplayer_url += "&hls_autostart=true";  
152 -  
153 - var hls_url = "http://" + ret.server + ":" + query.http_port + "/" + ret.app + "/" + ret.stream + ".m3u8";  
154 -  
155 - $("#txt_play_realtime").text("RTMP低延时(点击打开)").attr("href", srs_player_rt_url).attr("target", "_blank");  
156 - $("#txt_play_url").text("RTMP已转码(点击打开)").attr("href", srs_player_url).attr("target", "_blank");  
157 - $("#txt_play_hls").text("HLS-m3u8(点击打开或右键复制)").attr("href", hls_url).attr("target", "_blank");  
158 - $("#txt_play_jwplayer").text("HLS-JWPlayer(点击打开)").attr("href", jwplayer_url).attr("target", "_blank");  
159 - }  
160 - function on_user_publish() {  
161 - if ($("#btn_publish").text() == "停止发布") {  
162 - srs_publisher.stop();  
163 - $("#btn_publish").text("发布视频");  
164 - //$("#txt_play_realtime").text("RTMP低延时(请发布视频)").attr("href", "#").attr("target", "_self");  
165 - //$("#txt_play_realtime").attr("href", "#").attr("target", "_self");  
166 - //$("#txt_play_url").text("RTMP已转码(请发布视频)").attr("href", "#").attr("target", "_self");  
167 - //$("#remote_player_url").attr("href", "#").attr("target", "_self");  
168 - //$("#txt_play_hls").text("HLS-m3u8(请发布视频)").attr("href", "#").attr("target", "_self");  
169 - //$("#txt_play_jwplayer").text("HLS-JWPlayer(请发布视频)").attr("href", "#").attr("target", "_self");  
170 -  
171 - if (!on_publish_stop()) {  
172 - return;  
173 - }  
174 - return;  
175 - }  
176 -  
177 - $("#btn_publish").text("停止发布");  
178 -  
179 - update_play_url();  
180 -  
181 - var url = $("#txt_url").val();  
182 - var vcodec = {};  
183 - var acodec = {};  
184 - srs_publiser_get_codec(  
185 - vcodec, acodec,  
186 - "#sl_cameras", "#sl_microphones",  
187 - "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",  
188 - "#sl_fps", "#sl_bitrate",  
189 - "#sl_acodec"  
190 - );  
191 -  
192 - info("开始推流到服务器");  
193 - srs_publisher.publish(url, vcodec, acodec);  
194 -  
195 - if (realtime_player) {  
196 - // directly play the url for the realtime player.  
197 - realtime_player.stop();  
198 - realtime_player.play(url);  
199 - }  
200 -  
201 - if (remote_player) {  
202 - // the normal player should play the transcoded stream in another vhost.  
203 - // for example, publish stream to vhost players,  
204 - // the realtime player play the vhost players, which may donot support HLS,  
205 - // the normal player play the vhost players_pub, which transcoded to h264/aac with HLS.  
206 - var ret = srs_parse_rtmp_url(url);  
207 - var pub_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app;  
208 - pub_url += "?vhost=" + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;  
209 - remote_player.stop();  
210 - remote_player.play(pub_url);  
211 - }  
212 - }  
213 - </script>  
214 </head> 12 </head>
215 <body> 13 <body>
216 <div class="navbar navbar-fixed-top"> 14 <div class="navbar navbar-fixed-top">
@@ -464,4 +262,208 @@ @@ -464,4 +262,208 @@
464 </footer> 262 </footer>
465 </div> 263 </div>
466 </body> 264 </body>
  265 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  266 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  267 +<script type="text/javascript" src="js/swfobject.js"></script>
  268 +<script type="text/javascript" src="js/json2.js"></script>
  269 +<script type="text/javascript" src="js/srs.page.js"></script>
  270 +<script type="text/javascript" src="js/srs.log.js"></script>
  271 +<script type="text/javascript" src="js/srs.player.js"></script>
  272 +<script type="text/javascript" src="js/srs.publisher.js"></script>
  273 +<script type="text/javascript" src="js/srs.utility.js"></script>
  274 +<script type="text/javascript" src="js/winlin.utility.js"></script>
  275 +<script type="text/javascript">
  276 + var srs_publisher = null;
  277 + var remote_player = null;
  278 + var realtime_player = null;
  279 +
  280 + var query = parse_query_string();
  281 + $(function(){
  282 + // get the vhost and port to set the default url.
  283 + // for example: http://192.168.1.213/players/jwplayer6.html?port=1935&vhost=demo
  284 + // url set to: rtmp://demo:1935/live/livestream
  285 + srs_init_rtmp("#txt_url", null);
  286 +
  287 + if (query.agent == "true") {
  288 + document.write(navigator.userAgent);
  289 + return;
  290 + }
  291 +
  292 + $("#btn_video_settings").click(function(){
  293 + $("#video_modal").modal({show:true});
  294 + });
  295 + $("#btn_audio_settings").click(function(){
  296 + $("#audio_modal").modal({show:true});
  297 + });
  298 +
  299 + $("#remote_tips").tooltip({
  300 + title: "为了支持HLS输出,FLASH编码器输出的流需要经过转码(VP6=>H264,MP3=>aac),所以会黑屏较长时间,请耐心等待"
  301 + });
  302 + $("#low_latecy_tips").tooltip({
  303 + title: "服务器不转码直接转发FLASH编码器的流,所以延迟比支持HLS的流要低很多"
  304 + });
  305 + $("#realtime_player_url").tooltip({
  306 + title: "右键复制RTMP地址"
  307 + });
  308 + $("#remote_player_url").tooltip({
  309 + title: "右键复制RTMP地址"
  310 + });
  311 +
  312 + $("#btn_publish").click(on_user_publish);
  313 +
  314 + // for publish, we use randome stream name.
  315 + $("#txt_url").val($("#txt_url").val() + "." + new Date().getTime());
  316 +
  317 + // start the publisher.
  318 + srs_publisher = new SrsPublisher("local_publisher", 430, 185);
  319 + srs_publisher.on_publisher_ready = function(cameras, microphones) {
  320 + srs_publisher_initialize_page(
  321 + cameras, microphones,
  322 + "#sl_cameras", "#sl_microphones",
  323 + "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",
  324 + "#sl_fps", "#sl_bitrate",
  325 + "#sl_acodec"
  326 + );
  327 + };
  328 + srs_publisher.on_publisher_error = function(code, desc) {
  329 + if (!on_publish_stop()) {
  330 + return;
  331 + }
  332 + error(code, desc + "请重试。");
  333 + };
  334 + srs_publisher.on_publisher_warn = function(code, desc) {
  335 + warn(code, desc);
  336 + };
  337 + srs_publisher.start();
  338 +
  339 + update_play_url();
  340 +
  341 + // if no play specified, donot show the player, for debug the publisher.
  342 + if (query.no_play != "true") {
  343 + // start the normal player with HLS supported.
  344 + remote_player = new SrsPlayer("remote_player", 430, 185);
  345 + remote_player.on_player_ready = function() {
  346 + this.set_bt(0.8);
  347 + };
  348 + remote_player.on_player_metadata = function(metadata) {
  349 + this.set_dar(0, 0);
  350 + this.set_fs("screen", 100);
  351 + }
  352 + remote_player.start();
  353 +
  354 + // start the realtime player.
  355 + realtime_player = new SrsPlayer("realtime_player", 430, 185);
  356 + realtime_player.on_player_ready = function() {
  357 + this.set_bt(0.8);
  358 + };
  359 + realtime_player.on_player_metadata = function(metadata) {
  360 + this.set_dar(0, 0);
  361 + this.set_fs("screen", 100);
  362 + }
  363 + realtime_player.start();
  364 + }
  365 + });
  366 +
  367 + function on_publish_stop() {
  368 + if (!srs_can_republish()) {
  369 + $("#btn_join").attr("disabled", true);
  370 + error(0, "您使用的浏览器很弱,请关闭页面后重新打开页面(刷新也不管用)。<br/>推荐使用Chrome/Firefox/Safari/Opera浏览器,支持重试");
  371 +
  372 + srs_log_disabled = true;
  373 + return false;
  374 + }
  375 +
  376 + return true;
  377 + }
  378 +
  379 + /**
  380 + * we generate the transcoded stream url for flash publish donot support HLS
  381 + * which requires aac, so the publish vhost maybe players for example, we
  382 + * use players_pub vhost(transcoded stream to which) for all clients,
  383 + * both players and players_pub are write HLS to the sample dir,
  384 + * it's ok for the players vhost disabled the HLS, only the
  385 + * players_pub enalbed HLS.
  386 + */
  387 + function update_play_url() {
  388 + var url = $("#txt_url").val();
  389 + var ret = srs_parse_rtmp_url(url);
  390 +
  391 + var remote_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app + "...vhost..." + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;
  392 + $("#realtime_player_url").attr("href", url).attr("target", "_blank");
  393 + $("#remote_player_url").attr("href", remote_url).attr("target", "_blank");
  394 +
  395 + var srs_player_url = "http://" + query.host + query.dir + "/srs_player.html?";
  396 + srs_player_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
  397 + srs_player_url += "&autostart=true";
  398 +
  399 + var srs_player_rt_url = "http://" + query.host + query.dir + "/srs_player.html?";
  400 + srs_player_rt_url += "vhost=" + ret.vhost + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
  401 + srs_player_rt_url += "&autostart=true";
  402 +
  403 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?";
  404 + jwplayer_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
  405 + jwplayer_url += "&hls_autostart=true";
  406 +
  407 + var hls_url = "http://" + ret.server + ":" + query.http_port + "/" + ret.app + "/" + ret.stream + ".m3u8";
  408 +
  409 + $("#txt_play_realtime").text("RTMP低延时(点击打开)").attr("href", srs_player_rt_url).attr("target", "_blank");
  410 + $("#txt_play_url").text("RTMP已转码(点击打开)").attr("href", srs_player_url).attr("target", "_blank");
  411 + $("#txt_play_hls").text("HLS-m3u8(点击打开或右键复制)").attr("href", hls_url).attr("target", "_blank");
  412 + $("#txt_play_jwplayer").text("HLS-JWPlayer(点击打开)").attr("href", jwplayer_url).attr("target", "_blank");
  413 + }
  414 + function on_user_publish() {
  415 + if ($("#btn_publish").text() == "停止发布") {
  416 + srs_publisher.stop();
  417 + $("#btn_publish").text("发布视频");
  418 + //$("#txt_play_realtime").text("RTMP低延时(请发布视频)").attr("href", "#").attr("target", "_self");
  419 + //$("#txt_play_realtime").attr("href", "#").attr("target", "_self");
  420 + //$("#txt_play_url").text("RTMP已转码(请发布视频)").attr("href", "#").attr("target", "_self");
  421 + //$("#remote_player_url").attr("href", "#").attr("target", "_self");
  422 + //$("#txt_play_hls").text("HLS-m3u8(请发布视频)").attr("href", "#").attr("target", "_self");
  423 + //$("#txt_play_jwplayer").text("HLS-JWPlayer(请发布视频)").attr("href", "#").attr("target", "_self");
  424 +
  425 + if (!on_publish_stop()) {
  426 + return;
  427 + }
  428 + return;
  429 + }
  430 +
  431 + $("#btn_publish").text("停止发布");
  432 +
  433 + update_play_url();
  434 +
  435 + var url = $("#txt_url").val();
  436 + var vcodec = {};
  437 + var acodec = {};
  438 + srs_publiser_get_codec(
  439 + vcodec, acodec,
  440 + "#sl_cameras", "#sl_microphones",
  441 + "#sl_vcodec", "#sl_profile", "#sl_level", "#sl_gop", "#sl_size",
  442 + "#sl_fps", "#sl_bitrate",
  443 + "#sl_acodec"
  444 + );
  445 +
  446 + info("开始推流到服务器");
  447 + srs_publisher.publish(url, vcodec, acodec);
  448 +
  449 + if (realtime_player) {
  450 + // directly play the url for the realtime player.
  451 + realtime_player.stop();
  452 + realtime_player.play(url);
  453 + }
  454 +
  455 + if (remote_player) {
  456 + // the normal player should play the transcoded stream in another vhost.
  457 + // for example, publish stream to vhost players,
  458 + // the realtime player play the vhost players, which may donot support HLS,
  459 + // the normal player play the vhost players_pub, which transcoded to h264/aac with HLS.
  460 + var ret = srs_parse_rtmp_url(url);
  461 + var pub_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app;
  462 + pub_url += "?vhost=" + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;
  463 + remote_player.stop();
  464 + remote_player.play(pub_url);
  465 + }
  466 + }
  467 +</script>
  468 +</html>
467 469
@@ -4,21 +4,11 @@ @@ -4,21 +4,11 @@
4 <title>SRS</title> 4 <title>SRS</title>
5 <meta charset="utf-8"> 5 <meta charset="utf-8">
6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/> 6 <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
7 - <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>  
8 - <script type="text/javascript" src="js/bootstrap.min.js"></script>  
9 - <script type="text/javascript" src="js/swfobject.js"></script>  
10 - <script type="text/javascript" src="js/srs.page.js"></script>  
11 <style> 7 <style>
12 body{ 8 body{
13 padding-top: 55px; 9 padding-top: 55px;
14 } 10 }
15 </style> 11 </style>
16 - <script type="text/javascript">  
17 - $(function(){  
18 - update_nav();  
19 - $("#main_frame").attr("src", "http://www.videolan.org/vlc/");  
20 - });  
21 - </script>  
22 </head> 12 </head>
23 <body> 13 <body>
24 <div class="navbar navbar-fixed-top"> 14 <div class="navbar navbar-fixed-top">
@@ -49,4 +39,15 @@ @@ -49,4 +39,15 @@
49 </footer> 39 </footer>
50 </div> 40 </div>
51 </body> 41 </body>
  42 +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
  43 +<script type="text/javascript" src="js/bootstrap.min.js"></script>
  44 +<script type="text/javascript" src="js/swfobject.js"></script>
  45 +<script type="text/javascript" src="js/srs.page.js"></script>
  46 +<script type="text/javascript">
  47 + $(function(){
  48 + update_nav();
  49 + $("#main_frame").attr("src", "http://www.videolan.org/vlc/");
  50 + });
  51 +</script>
  52 +</html>
52 53