update the conf, add demo.srs.com, add players and players_pub, add __defaultVhost__ for rtmp
正在显示
13 个修改的文件
包含
406 行增加
和
46 行删除
| @@ -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> |
-
请 注册 或 登录 后发表评论