winlin

update the conf, add demo.srs.com, add players and players_pub, add __defaultVhost__ for rtmp

@@ -49,7 +49,7 @@ For example, use ffmpeg to publish: @@ -49,7 +49,7 @@ For example, use ffmpeg to publish:
49 for((;;)); do \ 49 for((;;)); do \
50 ./objs/ffmpeg/bin/ffmpeg -re -i ./doc/source.200kbps.768x320.flv \ 50 ./objs/ffmpeg/bin/ffmpeg -re -i ./doc/source.200kbps.768x320.flv \
51 -vcodec copy -acodec copy \ 51 -vcodec copy -acodec copy \
52 - -f flv -y rtmp://127.0.0.1/live/livestream; \ 52 + -f flv -y rtmp://127.0.0.1/live?vhost=demo.srs.com/livestream; \
53 sleep 1; \ 53 sleep 1; \
54 done 54 done
55 </pre> 55 </pre>
@@ -3,9 +3,11 @@ chunk_size 65000; @@ -3,9 +3,11 @@ chunk_size 65000;
3 vhost __defaultVhost__ { 3 vhost __defaultVhost__ {
4 enabled on; 4 enabled on;
5 gop_cache on; 5 gop_cache on;
6 - hls on;  
7 - hls_path ./objs/nginx/html/forward;  
8 - hls_fragment 5;  
9 - hls_window 30; 6 + hls {
  7 + enabled on;
  8 + hls_path ./objs/nginx/html/forward;
  9 + hls_fragment 5;
  10 + hls_window 30;
  11 + }
10 } 12 }
11 13
@@ -17,10 +17,17 @@ max_connections 2000; @@ -17,10 +17,17 @@ max_connections 2000;
17 # vhost list, the __defaultVhost__ is the default vhost 17 # vhost list, the __defaultVhost__ is the default vhost
18 # for example, user use ip to access the stream: rtmp://192.168.1.2/live/livestream. 18 # for example, user use ip to access the stream: rtmp://192.168.1.2/live/livestream.
19 # for which cannot identify the required vhost. 19 # for which cannot identify the required vhost.
20 -# for default demo.  
21 vhost __defaultVhost__ { 20 vhost __defaultVhost__ {
22 enabled on; 21 enabled on;
23 gop_cache on; 22 gop_cache on;
  23 +}
  24 +# vhost list, the __defaultVhost__ is the default vhost
  25 +# for example, user use ip to access the stream: rtmp://192.168.1.2/live/livestream.
  26 +# for which cannot identify the required vhost.
  27 +# for default demo.
  28 +vhost demo.srs.com {
  29 + enabled on;
  30 + gop_cache on;
24 queue_length 30; 31 queue_length 30;
25 forward 127.0.0.1:19350; 32 forward 127.0.0.1:19350;
26 hls { 33 hls {
@@ -44,7 +51,7 @@ vhost __defaultVhost__ { @@ -44,7 +51,7 @@ vhost __defaultVhost__ {
44 engine ld { 51 engine ld {
45 enabled on; 52 enabled on;
46 vfilter { 53 vfilter {
47 - vf 'drawtext=text=SimpleRtmpServer(SRS):x=10:y=10:fontcolor=#cccccc:fontfile=./doc/FreeSerifBold.ttf'; 54 + vf 'drawtext=text=SimpleRtmpServer(SRS):x=10:y=10:fontsize=30:fontcolor=#cccccc:fontfile=./doc/FreeSerifBold.ttf';
48 } 55 }
49 vcodec libx264; 56 vcodec libx264;
50 vbitrate 300; 57 vbitrate 300;
@@ -89,6 +96,48 @@ vhost __defaultVhost__ { @@ -89,6 +96,48 @@ vhost __defaultVhost__ {
89 } 96 }
90 } 97 }
91 } 98 }
  99 +# for the players site, to play or publish.
  100 +# the flash player publisher need to transcode to support hls,
  101 +# we add players_hls vhost to support it.
  102 +vhost players {
  103 + enabled on;
  104 + gop_cache on;
  105 + transcode {
  106 + enabled on;
  107 + ffmpeg ./objs/ffmpeg/bin/ffmpeg;
  108 + engine hls {
  109 + enabled on;
  110 + vfilter {
  111 + vf 'drawtext=text=SRS(SimpleRtmpServer):x=10:y=10:fontcolor=#cccccc:fontfile=./doc/FreeSerifBold.ttf';
  112 + }
  113 + vcodec libx264;
  114 + vbitrate 300;
  115 + vfps 20;
  116 + vwidth 768;
  117 + vheight 320;
  118 + vthreads 1;
  119 + vprofile baseline;
  120 + vpreset superfast;
  121 + vparams {
  122 + }
  123 + acodec libaacplus;
  124 + abitrate 30;
  125 + asample_rate 44100;
  126 + achannels 2;
  127 + aparams {
  128 + }
  129 + output rtmp://127.0.0.1:[port]/[app]?vhost=players_pub/[stream];
  130 + }
  131 + }
  132 +}
  133 +vhost players_pub {
  134 + hls {
  135 + enabled on;
  136 + hls_path ./objs/nginx/html;
  137 + hls_fragment 5;
  138 + hls_window 30;
  139 + }
  140 +}
92 # for development 141 # for development
93 vhost dev { 142 vhost dev {
94 enabled on; 143 enabled on;
@@ -17,7 +17,8 @@ @@ -17,7 +17,8 @@
17 $(function(){ 17 $(function(){
18 update_nav(); 18 update_nav();
19 19
20 - window.location.href = "srs_player.html"; 20 + // direct to the default vhost for players.
  21 + window.location.href = "srs_player.html?vhost=" + srs_get_player_vhost();
21 }); 22 });
22 </script> 23 </script>
23 </head> 24 </head>
@@ -25,7 +26,7 @@ @@ -25,7 +26,7 @@
25 <div class="navbar navbar-fixed-top"> 26 <div class="navbar navbar-fixed-top">
26 <div class="navbar-inner"> 27 <div class="navbar-inner">
27 <div class="container"> 28 <div class="container">
28 - <a class="brand" href="#">SRS</a> 29 + <a class="brand" href="index.html">SRS</a>
29 <div class="nav-collapse collapse"> 30 <div class="nav-collapse collapse">
30 <ul class="nav"> 31 <ul class="nav">
31 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> 32 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
@@ -30,13 +30,28 @@ function update_nav() { @@ -30,13 +30,28 @@ function update_nav() {
30 * parse the query string to object. 30 * parse the query string to object.
31 */ 31 */
32 function parse_query_string(){ 32 function parse_query_string(){
  33 + var obj = {};
  34 +
  35 + // parse the host(hostname:http_port), pathname(dir/filename)
  36 + obj.host = window.location.host;
  37 + obj.hostname = window.location.hostname;
  38 + obj.http_port = (window.location.port == "")? 80:window.location.port;
  39 + obj.pathname = window.location.pathname;
  40 + if (obj.pathname.lastIndexOf("/") <= 0) {
  41 + obj.dir = "/";
  42 + obj.filename = "";
  43 + } else {
  44 + obj.dir = obj.pathname.substr(0, obj.pathname.lastIndexOf("/"));
  45 + obj.filename = obj.pathname.substr(obj.pathname.lastIndexOf("/"));
  46 + }
  47 +
  48 + // parse the query string.
33 var query_string = String(window.location.search).replace(" ", "").split("?")[1]; 49 var query_string = String(window.location.search).replace(" ", "").split("?")[1];
34 if(query_string == undefined){ 50 if(query_string == undefined){
35 - return {}; 51 + return obj;
36 } 52 }
37 53
38 var queries = query_string.split("&"); 54 var queries = query_string.split("&");
39 - var obj = {};  
40 $(queries).each(function(){ 55 $(queries).each(function(){
41 var query = this.split("="); 56 var query = this.split("=");
42 obj[query[0]] = query[1]; 57 obj[query[0]] = query[1];
@@ -46,6 +61,7 @@ function parse_query_string(){ @@ -46,6 +61,7 @@ function parse_query_string(){
46 } 61 }
47 62
48 /** 63 /**
  64 +@param server the ip of server. default to window.location.hostname
49 @param vhost the vhost of rtmp. default to window.location.hostname 65 @param vhost the vhost of rtmp. default to window.location.hostname
50 @param port the port of rtmp. default to 1935 66 @param port the port of rtmp. default to 1935
51 @param app the app of rtmp. default to live. 67 @param app the app of rtmp. default to live.
@@ -54,16 +70,23 @@ function parse_query_string(){ @@ -54,16 +70,23 @@ function parse_query_string(){
54 function build_default_rtmp_url() { 70 function build_default_rtmp_url() {
55 var query = parse_query_string(); 71 var query = parse_query_string();
56 72
  73 + var server = (query.server == undefined)? window.location.hostname:query.server;
57 var port = (query.port == undefined)? 1935:query.port; 74 var port = (query.port == undefined)? 1935:query.port;
58 var vhost = (query.vhost == undefined)? window.location.hostname:query.vhost; 75 var vhost = (query.vhost == undefined)? window.location.hostname:query.vhost;
59 var app = (query.app == undefined)? "live":query.app; 76 var app = (query.app == undefined)? "live":query.app;
60 var stream = (query.stream == undefined)? "livestream":query.stream; 77 var stream = (query.stream == undefined)? "livestream":query.stream;
61 78
62 - return "rtmp://" + vhost + ":" + port + "/" + app + "/" + stream; 79 + if (server == vhost || vhost == "") {
  80 + return "rtmp://" + server + ":" + port + "/" + app + "/" + stream;
  81 + } else {
  82 + return "rtmp://" + server + ":" + port + "/" + app + "...vhost..." + vhost + "/" + stream;
  83 + }
63 } 84 }
64 85
65 /** 86 /**
  87 +@param server the ip of server. default to window.location.hostname
66 @param vhost the vhost of hls. default to window.location.hostname 88 @param vhost the vhost of hls. default to window.location.hostname
  89 +@param hls_vhost the vhost of hls. override the server if specified.
67 @param hls_port the port of hls. default to window.location.port 90 @param hls_port the port of hls. default to window.location.port
68 @param app the app of hls. default to live. 91 @param app the app of hls. default to live.
69 @param stream the stream of hls. default to livestream. 92 @param stream the stream of hls. default to livestream.
@@ -71,7 +94,14 @@ function build_default_rtmp_url() { @@ -71,7 +94,14 @@ function build_default_rtmp_url() {
71 function build_default_hls_url() { 94 function build_default_hls_url() {
72 var query = parse_query_string(); 95 var query = parse_query_string();
73 96
74 - var vhost = (query.vhost == undefined)? window.location.hostname:query.vhost; 97 + // for http, use hls_vhost to override server if specified.
  98 + var server = window.location.hostname;
  99 + if (query.server != undefined) {
  100 + server = query.server;
  101 + } else if (query.hls_vhost != undefined) {
  102 + server = query.hls_vhost;
  103 + }
  104 +
75 var port = (query.hls_port == undefined)? window.location.port:query.hls_port; 105 var port = (query.hls_port == undefined)? window.location.port:query.hls_port;
76 var app = (query.app == undefined)? "live":query.app; 106 var app = (query.app == undefined)? "live":query.app;
77 var stream = (query.stream == undefined)? "livestream":query.stream; 107 var stream = (query.stream == undefined)? "livestream":query.stream;
@@ -79,7 +109,45 @@ function build_default_hls_url() { @@ -79,7 +109,45 @@ function build_default_hls_url() {
79 if (port == "" || port == null || port == undefined) { 109 if (port == "" || port == null || port == undefined) {
80 port = 80; 110 port = 80;
81 } 111 }
82 - return "http://" + vhost + ":" + port + "/" + app + "/" + stream + ".m3u8"; 112 +
  113 + return "http://" + server + ":" + port + "/" + app + "/" + stream + ".m3u8";
  114 +}
  115 +
  116 +/**
  117 +* parse the rtmp url,
  118 +* for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
  119 +* @return object {server, port, vhost, app, stream}
  120 +*/
  121 +function srs_parse_rtmp_url(rtmp_url) {
  122 + // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
  123 + var a = document.createElement("a");
  124 + a.href = rtmp_url.replace("rtmp://", "http://");
  125 +
  126 + var vhost = a.hostname;
  127 + var port = (a.port == "")? "1935":a.port;
  128 + var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);
  129 + var stream = a.pathname.substr(a.pathname.lastIndexOf("/") + 1);
  130 +
  131 + // parse the vhost in the params of app, that srs supports.
  132 + app = app.replace("...vhost...", "?vhost=");
  133 + if (app.indexOf("?") >= 0) {
  134 + var params = app.substr(app.indexOf("?"));
  135 + app = app.substr(0, app.indexOf("?"));
  136 +
  137 + if (params.indexOf("vhost=") > 0) {
  138 + vhost = params.substr(params.indexOf("vhost=") + "vhost=".length);
  139 + if (vhost.indexOf("&") > 0) {
  140 + vhost = vhost.substr(0, vhost.indexOf("&"));
  141 + }
  142 + }
  143 + }
  144 +
  145 + var ret = {
  146 + server: a.hostname, port: port,
  147 + vhost: vhost, app: app, stream: stream
  148 + };
  149 +
  150 + return ret;
83 } 151 }
84 152
85 /** 153 /**
@@ -91,6 +159,13 @@ function srs_get_player_height() { return srs_get_player_width() * 9 / 19; } @@ -91,6 +159,13 @@ function srs_get_player_height() { return srs_get_player_width() * 9 / 19; }
91 159
92 // to query the swf anti cache. 160 // to query the swf anti cache.
93 function srs_get_version_code() { return "1.1"; } 161 function srs_get_version_code() { return "1.1"; }
  162 +// get the default vhost for players.
  163 +function srs_get_player_vhost() { return "players"; }
  164 +// get the stream published to vhost,
  165 +// generally we need to transcode the stream to support HLS and filters.
  166 +// for example, src_vhost is "players", we transcode stream to vhost "players_pub".
  167 +// if not equals to the player vhost, return the orignal vhost.
  168 +function srs_get_player_publish_vhost(src_vhost) { return (src_vhost != srs_get_player_vhost())? src_vhost:(src_vhost + "_pub"); }
94 169
95 /** 170 /**
96 * initialize the page. 171 * initialize the page.
@@ -62,6 +62,15 @@ @@ -62,6 +62,15 @@
62 _url = $("#txt_hls_url").val(); 62 _url = $("#txt_hls_url").val();
63 $("#main_modal").modal({show:true, keyboard:false}); 63 $("#main_modal").modal({show:true, keyboard:false});
64 }); 64 });
  65 +
  66 + var query = parse_query_string();
  67 + if (query.hls_autostart == "true") {
  68 + _url = $("#txt_hls_url").val();
  69 + $("#main_modal").modal({show:true, keyboard:false});
  70 + } else if (query.rtmp_autostart == "true") {
  71 + _url = $("#txt_rtmp_url").val();
  72 + $("#main_modal").modal({show:true, keyboard:false});
  73 + }
65 }); 74 });
66 </script> 75 </script>
67 </head> 76 </head>
@@ -69,7 +78,7 @@ @@ -69,7 +78,7 @@
69 <div class="navbar navbar-fixed-top"> 78 <div class="navbar navbar-fixed-top">
70 <div class="navbar-inner"> 79 <div class="navbar-inner">
71 <div class="container"> 80 <div class="container">
72 - <a class="brand" href="#">SRS</a> 81 + <a class="brand" href="index.html">SRS</a>
73 <div class="nav-collapse collapse"> 82 <div class="nav-collapse collapse">
74 <ul class="nav"> 83 <ul class="nav">
75 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> 84 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
@@ -74,7 +74,7 @@ @@ -74,7 +74,7 @@
74 <div class="navbar navbar-fixed-top"> 74 <div class="navbar navbar-fixed-top">
75 <div class="navbar-inner"> 75 <div class="navbar-inner">
76 <div class="container"> 76 <div class="container">
77 - <a class="brand" href="#">SRS</a> 77 + <a class="brand" href="index.html">SRS</a>
78 <div class="nav-collapse collapse"> 78 <div class="nav-collapse collapse">
79 <ul class="nav"> 79 <ul class="nav">
80 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> 80 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 <div class="navbar navbar-fixed-top"> 23 <div class="navbar navbar-fixed-top">
24 <div class="navbar-inner"> 24 <div class="navbar-inner">
25 <div class="container"> 25 <div class="container">
26 - <a class="brand" href="#">SRS</a> 26 + <a class="brand" href="index.html">SRS</a>
27 <div class="nav-collapse collapse"> 27 <div class="nav-collapse collapse">
28 <ul class="nav"> 28 <ul class="nav">
29 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> 29 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
@@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
26 </style> 26 </style>
27 <script type="text/javascript"> 27 <script type="text/javascript">
28 var srs_player = null; 28 var srs_player = null;
  29 + var url = null;
29 30
30 var __active_dar = null; 31 var __active_dar = null;
31 function select_dar(dar_id, num, den) { 32 function select_dar(dar_id, num, den) {
@@ -88,8 +89,6 @@ @@ -88,8 +89,6 @@
88 $(player).attr("id", "player_id"); 89 $(player).attr("id", "player_id");
89 $(div_container).append(player); 90 $(div_container).append(player);
90 91
91 - var url = $("#txt_url").val();  
92 -  
93 srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height()); 92 srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height());
94 srs_player.on_player_ready = function() { 93 srs_player.on_player_ready = function() {
95 select_buffer_time("#btn_bt_0_8", 0.8); 94 select_buffer_time("#btn_bt_0_8", 0.8);
@@ -138,6 +137,7 @@ @@ -138,6 +137,7 @@
138 }); 137 });
139 138
140 $("#btn_play").click(function(){ 139 $("#btn_play").click(function(){
  140 + url = $("#txt_url").val();
141 $("#main_modal").modal({show:true, keyboard:false}); 141 $("#main_modal").modal({show:true, keyboard:false});
142 }); 142 });
143 143
@@ -151,6 +151,41 @@ @@ -151,6 +151,41 @@
151 } 151 }
152 }); 152 });
153 153
  154 + $("#srs_publish").click(function(){
  155 + url = $("#srs_publish").text();
  156 + $("#main_modal").modal({show:true, keyboard:false});
  157 + });
  158 + $("#srs_publish_ld").click(function(){
  159 + url = $("#srs_publish_ld").text();
  160 + $("#main_modal").modal({show:true, keyboard:false});
  161 + });
  162 + $("#srs_publish_sd").click(function(){
  163 + url = $("#srs_publish_sd").text();
  164 + $("#main_modal").modal({show:true, keyboard:false});
  165 + });
  166 + $("#srs_publish_fw").click(function(){
  167 + url = $("#srs_publish_fw").text();
  168 + $("#main_modal").modal({show:true, keyboard:false});
  169 + });
  170 + $("#srs_publish_fw_ld").click(function(){
  171 + url = $("#srs_publish_fw_ld").text();
  172 + $("#main_modal").modal({show:true, keyboard:false});
  173 + });
  174 + $("#srs_publish_fw_sd").click(function(){
  175 + url = $("#srs_publish_fw_sd").text();
  176 + $("#main_modal").modal({show:true, keyboard:false});
  177 + });
  178 +
  179 + var query = parse_query_string();
  180 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=live&hls_autostart=true";
  181 + $("#srs_publish_hls").attr("href", jwplayer_url + "&stream=livestream");
  182 + $("#srs_publish_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
  183 + $("#srs_publish_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
  184 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?vhost=demo.srs.com&app=forward/live&hls_autostart=true";
  185 + $("#srs_publish_fw_hls").attr("href", jwplayer_url + "&stream=livestream");
  186 + $("#srs_publish_fw_ld_hls").attr("href", jwplayer_url + "&stream=livestream_ld");
  187 + $("#srs_publish_fw_sd_hls").attr("href", jwplayer_url + "&stream=livestream_sd");
  188 +
154 if (true) { 189 if (true) {
155 $("#btn_dar_original").click(function(){ 190 $("#btn_dar_original").click(function(){
156 select_dar("#btn_dar_original", 0, 0); 191 select_dar("#btn_dar_original", 0, 0);
@@ -228,7 +263,7 @@ @@ -228,7 +263,7 @@
228 <div class="navbar navbar-fixed-top"> 263 <div class="navbar navbar-fixed-top">
229 <div class="navbar-inner"> 264 <div class="navbar-inner">
230 <div class="container"> 265 <div class="container">
231 - <a class="brand" href="#">SRS</a> 266 + <a class="brand" href="index.html">SRS</a>
232 <div class="nav-collapse collapse"> 267 <div class="nav-collapse collapse">
233 <ul class="nav"> 268 <ul class="nav">
234 <li class="active"><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> 269 <li class="active"><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
@@ -252,6 +287,171 @@ @@ -252,6 +287,171 @@
252 <input type="text" id="txt_url" class="input-xxlarge" value=""></input> 287 <input type="text" id="txt_url" class="input-xxlarge" value=""></input>
253 <button class="btn btn-primary" id="btn_play">播放视频</button> 288 <button class="btn btn-primary" id="btn_play">播放视频</button>
254 </div> 289 </div>
  290 + <div class="container">
  291 + <hr/>
  292 + <span>
  293 + 注意:必须按照<a href="https://github.com/winlinvip/simple-rtmp-server/blob/master/README.md">SRS README.md</a>
  294 + 中的11个Step做完,下面所有的链接才能观看。
  295 + </span>
  296 + <div class="accordion" id="main_accordion">
  297 + <div class="accordion-group">
  298 + <div class="accordion-heading">
  299 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse1">
  300 + <strong>[1] SRS示例播放流: 原始流</strong>
  301 + </span>
  302 + </div>
  303 + <div id="collapse1" class="accordion-body collapse">
  304 + <div class="accordion-inner">
  305 + <a href="#" id="srs_publish">rtmp://demo.srs.com/live/livestream</a> <br/>
  306 + <span>用户推送过来的唯一一路流,经过服务器的多种变换和再转发。</span>
  307 + </div>
  308 + </div>
  309 + </div>
  310 + <div class="accordion-group">
  311 + <div class="accordion-heading">
  312 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse10">
  313 + <strong>[2] SRS示例播放流: 原始流HLS</strong>
  314 + </span>
  315 + </div>
  316 + <div id="collapse10" class="accordion-body collapse">
  317 + <div class="accordion-inner">
  318 + <a href="#" id="srs_publish_hls">http://demo.srs.com/live/livestream.m3u8</a> <br/>
  319 + <span>对用户的流进行HLS切片(若编码为非H264/AAC,HLS流会自动禁用)。</span>
  320 + </div>
  321 + </div>
  322 + </div>
  323 + <div class="accordion-group">
  324 + <div class="accordion-heading">
  325 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse2">
  326 + <strong>[3] SRS示例播放流: 转码配置LD流</strong>
  327 + </span>
  328 + </div>
  329 + <div id="collapse2" class="accordion-body collapse">
  330 + <div class="accordion-inner">
  331 + <a href="#" id="srs_publish_ld">rtmp://demo.srs.com/live/livestream_ld</a> <br/>
  332 + <span>对原始流加了<a href="http://ffmpeg.org/ffmpeg-filters.html#drawtext-1">FFMPEG文字水印</a></span>
  333 + </div>
  334 + </div>
  335 + </div>
  336 + <div class="accordion-group">
  337 + <div class="accordion-heading">
  338 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse11">
  339 + <strong>[4] SRS示例播放流: 转码配置LD流HLS</strong>
  340 + </span>
  341 + </div>
  342 + <div id="collapse11" class="accordion-body collapse">
  343 + <div class="accordion-inner">
  344 + <a href="#" id="srs_publish_ld_hls">http://demo.srs.com/live/livestream_ld.m3u8</a> <br/>
  345 + <span>对转码配置LD流进行HLS切片。</span>
  346 + </div>
  347 + </div>
  348 + </div>
  349 + <div class="accordion-group">
  350 + <div class="accordion-heading">
  351 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse3">
  352 + <strong>[5] SRS示例播放流: 转码配置SD流</strong>
  353 + </span>
  354 + </div>
  355 + <div id="collapse3" class="accordion-body collapse">
  356 + <div class="accordion-inner">
  357 + <a href="#" id="srs_publish_sd">rtmp://demo.srs.com/live/livestream_sd</a> <br/>
  358 + <span>对原始流应用了<a href="http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction">FFMPEG翻转滤镜</a></span>
  359 + </div>
  360 + </div>
  361 + </div>
  362 + <div class="accordion-group">
  363 + <div class="accordion-heading">
  364 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse12">
  365 + <strong>[6] SRS示例播放流: 转码配置SD流HLS</strong>
  366 + </span>
  367 + </div>
  368 + <div id="collapse12" class="accordion-body collapse">
  369 + <div class="accordion-inner">
  370 + <a href="#" id="srs_publish_sd_hls">http://demo.srs.com/live/livestream_sd.m3u8</a> <br/>
  371 + <span>对转码配置SD流进行HLS切片。</span>
  372 + </div>
  373 + </div>
  374 + </div>
  375 + <div class="accordion-group">
  376 + <div class="accordion-heading">
  377 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse4">
  378 + <strong>[7] SRS示例播放流: 转发原始流</strong>
  379 + </span>
  380 + </div>
  381 + <div id="collapse4" class="accordion-body collapse">
  382 + <div class="accordion-inner">
  383 + <a href="#" id="srs_publish_fw">rtmp://demo.srs.com:19350/live/livestream</a> <br/>
  384 + <span>将用户推送的流转发到另外的vhost或服务器,做热备用。</span>
  385 + </div>
  386 + </div>
  387 + </div>
  388 + <div class="accordion-group">
  389 + <div class="accordion-heading">
  390 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse13">
  391 + <strong>[8] SRS示例播放流: 转发原始流HLS</strong>
  392 + </span>
  393 + </div>
  394 + <div id="collapse13" class="accordion-body collapse">
  395 + <div class="accordion-inner">
  396 + <a href="#" id="srs_publish_fw_hls">http://demo.srs.com/forward/live/livestream.m3u8</a> <br/>
  397 + <span>对转发原始流进行HLS切片(若编码为非H264/AAC,HLS流会自动禁用)。</span>
  398 + </div>
  399 + </div>
  400 + </div>
  401 + <div class="accordion-group">
  402 + <div class="accordion-heading">
  403 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse5">
  404 + <strong>[9] SRS示例播放流: 转发转码配置LD流</strong>
  405 + </span>
  406 + </div>
  407 + <div id="collapse5" class="accordion-body collapse">
  408 + <div class="accordion-inner">
  409 + <a href="#" id="srs_publish_fw_ld">rtmp://demo.srs.com:19350/live/livestream_ld</a> <br/>
  410 + <span>FFMPEG加水印后的流也会自动转发。</span>
  411 + </div>
  412 + </div>
  413 + </div>
  414 + <div class="accordion-group">
  415 + <div class="accordion-heading">
  416 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse14">
  417 + <strong>[10] SRS示例播放流: 转发转码配置LD流HLS</strong>
  418 + </span>
  419 + </div>
  420 + <div id="collapse14" class="accordion-body collapse">
  421 + <div class="accordion-inner">
  422 + <a href="#" id="srs_publish_fw_ld_hls">http://demo.srs.com/forward/live/livestream_ld.m3u8</a> <br/>
  423 + <span>对转发转码配置LD流进行HLS切片,所有转发的流会自动支持HLS。</span>
  424 + </div>
  425 + </div>
  426 + </div>
  427 + <div class="accordion-group">
  428 + <div class="accordion-heading">
  429 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse6">
  430 + <strong>[11] SRS示例播放流: 转发转码配置SD流</strong>
  431 + </span>
  432 + </div>
  433 + <div id="collapse6" class="accordion-body collapse">
  434 + <div class="accordion-inner">
  435 + <a href="#" id="srs_publish_fw_sd">rtmp://demo.srs.com:19350/live/livestream_sd</a> <br/>
  436 + <span>FFMPEG翻转后的流也会自动转发。</span>
  437 + </div>
  438 + </div>
  439 + </div>
  440 + <div class="accordion-group">
  441 + <div class="accordion-heading">
  442 + <span class="accordion-toggle" data-toggle="collapse" data-parent="#main_accordion" href="#collapse15">
  443 + <strong>[12] SRS示例播放流: 转发转码配置SD流HLS</strong>
  444 + </span>
  445 + </div>
  446 + <div id="collapse15" class="accordion-body collapse">
  447 + <div class="accordion-inner">
  448 + <a href="#" id="srs_publish_fw_sd_hls">http://demo.srs.com/forward/live/livestream_sd.m3u8</a> <br/>
  449 + <span>对转发转码配置SD流进行HLS切片,所有转发的流会自动支持HLS。</span>
  450 + </div>
  451 + </div>
  452 + </div>
  453 + </div>
  454 + </div>
255 <div id="main_modal" class="modal hide fade"> 455 <div id="main_modal" class="modal hide fade">
256 <div class="modal-header"> 456 <div class="modal-header">
257 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 457 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
@@ -140,15 +140,17 @@ package @@ -140,15 +140,17 @@ package
140 private function system_on_metadata(metadata:Object):void { 140 private function system_on_metadata(metadata:Object):void {
141 this.media_metadata = metadata; 141 this.media_metadata = metadata;
142 142
143 - // for context menu  
144 - var customItems:Array = [new ContextMenuItem("SrsPlayer")];  
145 if (metadata.hasOwnProperty("server")) { 143 if (metadata.hasOwnProperty("server")) {
146 - customItems.push(new ContextMenuItem("Server: " + metadata.server));  
147 - }  
148 - if (metadata.hasOwnProperty("contributor")) {  
149 - customItems.push(new ContextMenuItem("Contributor: " + metadata.contributor)); 144 + // for context menu
  145 + var customItems:Array = [new ContextMenuItem("SrsPlayer")];
  146 + if (metadata.hasOwnProperty("server")) {
  147 + customItems.push(new ContextMenuItem("Server: " + metadata.server));
  148 + }
  149 + if (metadata.hasOwnProperty("contributor")) {
  150 + customItems.push(new ContextMenuItem("Contributor: " + metadata.contributor));
  151 + }
  152 + contextMenu.customItems = customItems;
150 } 153 }
151 - contextMenu.customItems = customItems;  
152 154
153 // for js. 155 // for js.
154 var obj:Object = __get_video_size_object(); 156 var obj:Object = __get_video_size_object();
@@ -123,32 +123,39 @@ @@ -123,32 +123,39 @@
123 remote_player.start(); 123 remote_player.start();
124 }); 124 });
125 125
  126 + /**
  127 + * we generate the transcoded stream url for flash publish donot support HLS
  128 + * which requires aac, so the publish vhost maybe players for example, we
  129 + * use players_pub vhost(transcoded stream to which) for all clients,
  130 + * both players and players_pub are write HLS to the sample dir,
  131 + * it's ok for the players vhost disabled the HLS, only the
  132 + * players_pub enalbed HLS.
  133 + */
126 function update_play_url() { 134 function update_play_url() {
127 - // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri  
128 - var a = document.createElement("a");  
129 - a.href = $("#txt_url").val().replace("rtmp://", "http://"); 135 + var ret = srs_parse_rtmp_url($("#txt_url").val());
  136 + var query = parse_query_string();
130 137
131 - var url = "http://" + window.location.host;  
132 - url += window.location.pathname.substr(0, window.location.pathname.lastIndexOf("/"));  
133 - url += "/srs_player.html?"; 138 + var srs_player_url = "http://" + query.host + query.dir + "/srs_player.html?";
  139 + srs_player_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
  140 + srs_player_url += "&autostart=true";
134 141
135 - url += "vhost=" + a.hostname;  
136 - url += "&port=" + a.port;  
137 - url += "&app=" + a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1);  
138 - url += "&stream=" + a.pathname.substr(a.pathname.lastIndexOf("/") + 1); 142 + var jwplayer_url = "http://" + query.host + query.dir + "/jwplayer6.html?";
  143 + jwplayer_url += "vhost=" + srs_get_player_publish_vhost(ret.vhost) + "&port=" + ret.port + "&app=" + ret.app + "&stream=" + ret.stream;
  144 + jwplayer_url += "&hls_autostart=true";
139 145
140 - // autostart  
141 - url += "&autostart=true"; 146 + var hls_url = "http://" + ret.server + ":" + query.http_port + "/" + ret.app + "/" + ret.stream + ".m3u8";
142 147
143 - $("#txt_play_url").text(url);  
144 - $("#txt_play_url").attr("href", url);  
145 - $("#txt_play_url").attr("target", "_blank"); 148 + $("#txt_play_url").text("点击或右键复制").attr("href", srs_player_url).attr("target", "_blank");
  149 + $("#txt_play_hls").text("点击或右键复制").attr("href", hls_url).attr("target", "_blank");
  150 + $("#txt_play_jwplayer").text("点击或右键复制").attr("href", jwplayer_url).attr("target", "_blank");
146 } 151 }
147 function on_user_publish() { 152 function on_user_publish() {
148 if ($("#btn_publish").text() == "停止发布") { 153 if ($("#btn_publish").text() == "停止发布") {
149 srs_publisher.stop(); 154 srs_publisher.stop();
150 $("#btn_publish").text("发布视频"); 155 $("#btn_publish").text("发布视频");
151 $("#txt_play_url").text("请发布视频").attr("href", "#").attr("target", "_self"); 156 $("#txt_play_url").text("请发布视频").attr("href", "#").attr("target", "_self");
  157 + $("#txt_play_hls").text("请发布视频").attr("href", "#").attr("target", "_self");
  158 + $("#txt_play_jwplayer").text("请发布视频").attr("href", "#").attr("target", "_self");
152 return; 159 return;
153 } 160 }
154 161
@@ -178,8 +185,11 @@ @@ -178,8 +185,11 @@
178 srs_publisher.publish(url, vcodec, acodec); 185 srs_publisher.publish(url, vcodec, acodec);
179 186
180 // replay the url. 187 // replay the url.
  188 + var ret = srs_parse_rtmp_url(url);
  189 + var pub_url = "rtmp://" + ret.server + ":" + ret.port + "/" + ret.app;
  190 + pub_url += "?vhost=" + srs_get_player_publish_vhost(ret.vhost) + "/" + ret.stream;
181 remote_player.stop(); 191 remote_player.stop();
182 - remote_player.play(url); 192 + remote_player.play(pub_url);
183 } 193 }
184 194
185 function info(desc) { 195 function info(desc) {
@@ -198,7 +208,7 @@ @@ -198,7 +208,7 @@
198 <div class="navbar navbar-fixed-top"> 208 <div class="navbar navbar-fixed-top">
199 <div class="navbar-inner"> 209 <div class="navbar-inner">
200 <div class="container"> 210 <div class="container">
201 - <a class="brand" href="#">SRS</a> 211 + <a class="brand" href="index.html">SRS</a>
202 <div class="nav-collapse collapse"> 212 <div class="nav-collapse collapse">
203 <ul class="nav"> 213 <ul class="nav">
204 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> 214 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
@@ -233,10 +243,22 @@ @@ -233,10 +243,22 @@
233 </div> 243 </div>
234 <div class="control-group"> 244 <div class="control-group">
235 <div class="form-inline"> 245 <div class="form-inline">
236 - 观看地址: 246 + 观看地址(rtmp地址):
237 <a id="txt_play_url" class="input-xxlarge" href="#">请发布视频</a> 247 <a id="txt_play_url" class="input-xxlarge" href="#">请发布视频</a>
238 </div> 248 </div>
239 </div> 249 </div>
  250 + <div class="control-group">
  251 + <div class="form-inline">
  252 + HLS地址(m3u8地址):
  253 + <a id="txt_play_hls" class="input-xxlarge" href="#">请发布视频</a>
  254 + </div>
  255 + </div>
  256 + <div class="control-group">
  257 + <div class="form-inline">
  258 + HLS地址(JWPlayer):
  259 + <a id="txt_play_jwplayer" class="input-xxlarge" href="#">请发布视频</a>
  260 + </div>
  261 + </div>
240 <div id="video_modal" class="modal hide fade"> 262 <div id="video_modal" class="modal hide fade">
241 <div class="modal-header"> 263 <div class="modal-header">
242 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 264 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 <div class="navbar navbar-fixed-top"> 24 <div class="navbar navbar-fixed-top">
25 <div class="navbar-inner"> 25 <div class="navbar-inner">
26 <div class="container"> 26 <div class="container">
27 - <a class="brand" href="#">SRS</a> 27 + <a class="brand" href="index.html">SRS</a>
28 <div class="nav-collapse collapse"> 28 <div class="nav-collapse collapse">
29 <ul class="nav"> 29 <ul class="nav">
30 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li> 30 <li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>