正在显示
17 个修改的文件
包含
244 行增加
和
140 行删除
| @@ -97,13 +97,14 @@ Supported operating systems and hardware: | @@ -97,13 +97,14 @@ Supported operating systems and hardware: | ||
| 97 | 17. support live stream transcoding by ffmpeg.<br/> | 97 | 17. support live stream transcoding by ffmpeg.<br/> |
| 98 | 18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/> | 98 | 18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/> |
| 99 | 19. [plan] support network based cli and json result.<br/> | 99 | 19. [plan] support network based cli and json result.<br/> |
| 100 | -20. [plan] support bandwidth test api and flash client.<br/> | ||
| 101 | -21. [plan] support adobe flash refer/token/swf verification.<br/> | ||
| 102 | -22. [plan] support adobe amf3 codec.<br/> | ||
| 103 | -23. [plan] support dvr(record live to vod file)<br/> | ||
| 104 | -24. [plan] support FMS edge protocol<br/> | ||
| 105 | -25. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/> | ||
| 106 | -26. [plan] support RTMPT, http to tranverse firewalls<br/> | 100 | +20. [plan] support http callback api hooks.<br/> |
| 101 | +21. [plan] support bandwidth test api and flash client.<br/> | ||
| 102 | +22. [plan] support adobe flash refer/token/swf verification.<br/> | ||
| 103 | +23. [plan] support adobe amf3 codec.<br/> | ||
| 104 | +24. [plan] support dvr(record live to vod file)<br/> | ||
| 105 | +25. [plan] support FMS edge protocol<br/> | ||
| 106 | +26. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/> | ||
| 107 | +27. [plan] support RTMPT, http to tranverse firewalls<br/> | ||
| 107 | 108 | ||
| 108 | ### Performance | 109 | ### Performance |
| 109 | 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. | 110 | 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. |
| @@ -150,8 +151,9 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw | @@ -150,8 +151,9 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw | ||
| 150 | * nginx v1.5.0: 139524 lines <br/> | 151 | * nginx v1.5.0: 139524 lines <br/> |
| 151 | 152 | ||
| 152 | ### History | 153 | ### History |
| 154 | +* v0.7, 2013-12-01, support dead-loop detect for forwarder and transcoder. | ||
| 153 | * v0.7, 2013-12-01, support all ffmpeg filters and params. | 155 | * v0.7, 2013-12-01, support all ffmpeg filters and params. |
| 154 | -* v0.7, 2013-11-30, support live stream transcoding by ffmpeg. | 156 | +* v0.7, 2013-11-30, support live stream transcoder by ffmpeg. |
| 155 | * v0.7, 2013-11-30, support --with/without -ffmpeg, build ffmpeg-2.1. | 157 | * v0.7, 2013-11-30, support --with/without -ffmpeg, build ffmpeg-2.1. |
| 156 | * v0.7, 2013-11-30, add ffmpeg-2.1, x264-core138, lame-3.99.5, libaacplus-2.0.2. | 158 | * v0.7, 2013-11-30, add ffmpeg-2.1, x264-core138, lame-3.99.5, libaacplus-2.0.2. |
| 157 | * v0.6, 2013-11-29, v0.6 released. 16094 lines. | 159 | * v0.6, 2013-11-29, v0.6 released. 16094 lines. |
| @@ -41,7 +41,7 @@ vhost __defaultVhost__ { | @@ -41,7 +41,7 @@ vhost __defaultVhost__ { | ||
| 41 | achannels 2; | 41 | achannels 2; |
| 42 | aparams { | 42 | aparams { |
| 43 | } | 43 | } |
| 44 | - output rtmp://[vhost]:[port]/[app]/[stream]_ld; | 44 | + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; |
| 45 | } | 45 | } |
| 46 | engine sd{ | 46 | engine sd{ |
| 47 | enabled on; | 47 | enabled on; |
| @@ -64,7 +64,7 @@ vhost __defaultVhost__ { | @@ -64,7 +64,7 @@ vhost __defaultVhost__ { | ||
| 64 | achannels 2; | 64 | achannels 2; |
| 65 | aparams { | 65 | aparams { |
| 66 | } | 66 | } |
| 67 | - output rtmp://[vhost]:[port]/[app]/[stream]_sd; | 67 | + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; |
| 68 | } | 68 | } |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
| @@ -76,7 +76,7 @@ vhost dev { | @@ -76,7 +76,7 @@ vhost dev { | ||
| 76 | hls_path ./objs/nginx/html; | 76 | hls_path ./objs/nginx/html; |
| 77 | hls_fragment 5; | 77 | hls_fragment 5; |
| 78 | hls_window 30; | 78 | hls_window 30; |
| 79 | - #forward dev:19350; | 79 | + forward 127.0.0.1:19350?vhost=dev; |
| 80 | transcode { | 80 | transcode { |
| 81 | enabled on; | 81 | enabled on; |
| 82 | ffmpeg ./objs/ffmpeg/bin/ffmpeg; | 82 | ffmpeg ./objs/ffmpeg/bin/ffmpeg; |
| @@ -100,7 +100,7 @@ vhost dev { | @@ -100,7 +100,7 @@ vhost dev { | ||
| 100 | achannels 2; | 100 | achannels 2; |
| 101 | aparams { | 101 | aparams { |
| 102 | } | 102 | } |
| 103 | - output rtmp://127.0.0.1:[port]/[app]/[stream]_dev; | 103 | + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; |
| 104 | } | 104 | } |
| 105 | } | 105 | } |
| 106 | } | 106 | } |
| @@ -130,7 +130,7 @@ vhost mirror.transcode.vhost.com { | @@ -130,7 +130,7 @@ vhost mirror.transcode.vhost.com { | ||
| 130 | achannels 2; | 130 | achannels 2; |
| 131 | aparams { | 131 | aparams { |
| 132 | } | 132 | } |
| 133 | - output rtmp://[vhost]:[port]/[app]/[stream]_mirror; | 133 | + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; |
| 134 | } | 134 | } |
| 135 | } | 135 | } |
| 136 | } | 136 | } |
| @@ -160,7 +160,7 @@ vhost drawtext.transcode.vhost.com { | @@ -160,7 +160,7 @@ vhost drawtext.transcode.vhost.com { | ||
| 160 | achannels 2; | 160 | achannels 2; |
| 161 | aparams { | 161 | aparams { |
| 162 | } | 162 | } |
| 163 | - output rtmp://[vhost]:[port]/[app]/[stream]_drawtext; | 163 | + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; |
| 164 | } | 164 | } |
| 165 | } | 165 | } |
| 166 | } | 166 | } |
| @@ -190,7 +190,7 @@ vhost crop.transcode.vhost.com { | @@ -190,7 +190,7 @@ vhost crop.transcode.vhost.com { | ||
| 190 | achannels 2; | 190 | achannels 2; |
| 191 | aparams { | 191 | aparams { |
| 192 | } | 192 | } |
| 193 | - output rtmp://[vhost]:[port]/[app]/[stream]_crop; | 193 | + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; |
| 194 | } | 194 | } |
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| @@ -220,7 +220,7 @@ vhost logo.transcode.vhost.com { | @@ -220,7 +220,7 @@ vhost logo.transcode.vhost.com { | ||
| 220 | achannels 2; | 220 | achannels 2; |
| 221 | aparams { | 221 | aparams { |
| 222 | } | 222 | } |
| 223 | - output rtmp://[vhost]:[port]/[app]/[stream]_logo; | 223 | + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; |
| 224 | } | 224 | } |
| 225 | } | 225 | } |
| 226 | } | 226 | } |
| @@ -297,7 +297,8 @@ vhost all.transcode.vhost.com { | @@ -297,7 +297,8 @@ vhost all.transcode.vhost.com { | ||
| 297 | # [port] the intput stream port. | 297 | # [port] the intput stream port. |
| 298 | # [app] the input stream app. | 298 | # [app] the input stream app. |
| 299 | # [stream] the input stream name. | 299 | # [stream] the input stream name. |
| 300 | - output rtmp://[vhost]:[port]/[app]/[stream]_ffsuper; | 300 | + # [engine] the tanscode engine name. |
| 301 | + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; | ||
| 301 | } | 302 | } |
| 302 | engine ffhd{ | 303 | engine ffhd{ |
| 303 | enabled on; | 304 | enabled on; |
| @@ -418,15 +419,14 @@ vhost forward.vhost.com { | @@ -418,15 +419,14 @@ vhost forward.vhost.com { | ||
| 418 | # this used to split/forward the current stream for cluster active-standby, | 419 | # this used to split/forward the current stream for cluster active-standby, |
| 419 | # active-active for cdn to build high available fault tolerance system. | 420 | # active-active for cdn to build high available fault tolerance system. |
| 420 | # format: {ip}:{port} {ip_N}:{port_N} | 421 | # format: {ip}:{port} {ip_N}:{port_N} |
| 422 | + # or specify the vhost by: | ||
| 423 | + # format: {ip}:{port}?vhost={vhost} {ip_N}:{port_N}?vhost={vhost} | ||
| 424 | + # if vhost not specified, use the request vhost instead. | ||
| 421 | forward 127.0.0.1:1936 127.0.0.1:1937; | 425 | forward 127.0.0.1:1936 127.0.0.1:1937; |
| 422 | } | 426 | } |
| 423 | # the vhost which forward publish streams to other vhosts. | 427 | # the vhost which forward publish streams to other vhosts. |
| 424 | vhost forward1.vhost.com { | 428 | vhost forward1.vhost.com { |
| 425 | - # forward all publish stream to the specified server. | ||
| 426 | - # this used to split/forward the current stream for cluster active-standby, | ||
| 427 | - # active-active for cdn to build high available fault tolerance system. | ||
| 428 | - # format: {ip}:{port} {ip_N}:{port_N} | ||
| 429 | - forward forward.vhost.com:1936 forward.vhost.com:1937; | 429 | + forward 127.0.0.1:1936?vhost=forward2.vhost.com 127.0.0.1:1937?vhost=forward3.vhost.com; |
| 430 | } | 430 | } |
| 431 | # the vhost disabled. | 431 | # the vhost disabled. |
| 432 | vhost removed.vhost.com { | 432 | vhost removed.vhost.com { |
| @@ -24,6 +24,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -24,6 +24,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 24 | #include <srs_core.hpp> | 24 | #include <srs_core.hpp> |
| 25 | 25 | ||
| 26 | #include <sys/time.h> | 26 | #include <sys/time.h> |
| 27 | +#include <netdb.h> | ||
| 28 | +#include <arpa/inet.h> | ||
| 29 | + | ||
| 30 | +#include <srs_core_log.hpp> | ||
| 27 | 31 | ||
| 28 | static int64_t _srs_system_time_us_cache = 0; | 32 | static int64_t _srs_system_time_us_cache = 0; |
| 29 | 33 | ||
| @@ -60,3 +64,49 @@ std::string srs_replace(std::string str, std::string old_str, std::string new_st | @@ -60,3 +64,49 @@ std::string srs_replace(std::string str, std::string old_str, std::string new_st | ||
| 60 | 64 | ||
| 61 | return ret; | 65 | return ret; |
| 62 | } | 66 | } |
| 67 | + | ||
| 68 | +std::string srs_dns_resolve(std::string host) | ||
| 69 | +{ | ||
| 70 | + if (inet_addr(host.c_str()) != INADDR_NONE) { | ||
| 71 | + return host; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + hostent* answer = gethostbyname(host.c_str()); | ||
| 75 | + if (answer == NULL) { | ||
| 76 | + srs_error("dns resolve host %s error.", host.c_str()); | ||
| 77 | + return ""; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + char ipv4[16]; | ||
| 81 | + memset(ipv4, 0, sizeof(ipv4)); | ||
| 82 | + for (int i = 0; i < answer->h_length; i++) { | ||
| 83 | + inet_ntop(AF_INET, answer->h_addr_list[i], ipv4, sizeof(ipv4)); | ||
| 84 | + srs_info("dns resolve host %s to %s.", host.c_str(), ipv4); | ||
| 85 | + break; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + return ipv4; | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +void srs_vhost_resolve(std::string& vhost, std::string& app) | ||
| 92 | +{ | ||
| 93 | + app = srs_replace(app, "...", "?"); | ||
| 94 | + | ||
| 95 | + if ((pos = app.find("?")) == std::string::npos) { | ||
| 96 | + return; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + std::string query = app.substr(pos + 1); | ||
| 100 | + app = app.substr(0, pos); | ||
| 101 | + | ||
| 102 | + if ((pos = query.find("vhost?")) != std::string::npos | ||
| 103 | + || (pos = query.find("vhost=")) != std::string::npos | ||
| 104 | + || (pos = query.find("Vhost?")) != std::string::npos | ||
| 105 | + || (pos = query.find("Vhost=")) != std::string::npos | ||
| 106 | + ) { | ||
| 107 | + query = query.substr(pos + 6); | ||
| 108 | + if (!query.empty()) { | ||
| 109 | + vhost = query; | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | +} |
| @@ -94,5 +94,12 @@ extern void srs_update_system_time_ms(); | @@ -94,5 +94,12 @@ extern void srs_update_system_time_ms(); | ||
| 94 | #include <string> | 94 | #include <string> |
| 95 | // replace utility | 95 | // replace utility |
| 96 | extern std::string srs_replace(std::string str, std::string old_str, std::string new_str); | 96 | extern std::string srs_replace(std::string str, std::string old_str, std::string new_str); |
| 97 | +// dns resolve utility, return the resolved ip address. | ||
| 98 | +extern std::string srs_dns_resolve(std::string host); | ||
| 99 | +// resolve the vhost in query string | ||
| 100 | +// @param app, may contains the vhost in query string format: | ||
| 101 | +// app?vhost=request_vhost | ||
| 102 | +// app...vhost...request_vhost | ||
| 103 | +extern void srs_vhost_resolve(std::string& vhost, std::string& app); | ||
| 97 | 104 | ||
| 98 | #endif | 105 | #endif |
| @@ -343,7 +343,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) | @@ -343,7 +343,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) | ||
| 343 | SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); | 343 | SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); |
| 344 | 344 | ||
| 345 | // notify the hls to prepare when publish start. | 345 | // notify the hls to prepare when publish start. |
| 346 | - if ((ret = source->on_publish(req->vhost, req->port, req->app, req->stream)) != ERROR_SUCCESS) { | 346 | + if ((ret = source->on_publish(req)) != ERROR_SUCCESS) { |
| 347 | srs_error("hls on_publish failed. ret=%d", ret); | 347 | srs_error("hls on_publish failed. ret=%d", ret); |
| 348 | return ret; | 348 | return ret; |
| 349 | } | 349 | } |
| @@ -37,6 +37,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -37,6 +37,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 37 | // default vhost for rtmp | 37 | // default vhost for rtmp |
| 38 | #define RTMP_VHOST_DEFAULT "__defaultVhost__" | 38 | #define RTMP_VHOST_DEFAULT "__defaultVhost__" |
| 39 | 39 | ||
| 40 | +#define SRS_LOCALHOST "127.0.0.1" | ||
| 41 | +#define RTMP_DEFAULT_PORT 1935 | ||
| 42 | +#define RTMP_DEFAULT_PORTS "1935" | ||
| 43 | + | ||
| 40 | #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" | 44 | #define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html" |
| 41 | #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 | 45 | #define SRS_CONF_DEFAULT_HLS_FRAGMENT 10 |
| 42 | #define SRS_CONF_DEFAULT_HLS_WINDOW 60 | 46 | #define SRS_CONF_DEFAULT_HLS_WINDOW 60 |
| @@ -26,15 +26,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -26,15 +26,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 26 | #include <stdlib.h> | 26 | #include <stdlib.h> |
| 27 | #include <unistd.h> | 27 | #include <unistd.h> |
| 28 | 28 | ||
| 29 | +#include <algorithm> | ||
| 30 | + | ||
| 29 | #include <srs_core_error.hpp> | 31 | #include <srs_core_error.hpp> |
| 30 | #include <srs_core_log.hpp> | 32 | #include <srs_core_log.hpp> |
| 31 | #include <srs_core_config.hpp> | 33 | #include <srs_core_config.hpp> |
| 34 | +#include <srs_core_rtmp.hpp> | ||
| 35 | + | ||
| 36 | +#ifdef SRS_FFMPEG | ||
| 32 | 37 | ||
| 33 | #define SRS_ENCODER_SLEEP_MS 2000 | 38 | #define SRS_ENCODER_SLEEP_MS 2000 |
| 34 | 39 | ||
| 35 | #define SRS_ENCODER_VCODEC "libx264" | 40 | #define SRS_ENCODER_VCODEC "libx264" |
| 36 | #define SRS_ENCODER_ACODEC "libaacplus" | 41 | #define SRS_ENCODER_ACODEC "libaacplus" |
| 37 | 42 | ||
| 43 | +// for encoder to detect the dead loop | ||
| 44 | +static std::vector<std::string> _transcoded_url; | ||
| 45 | + | ||
| 38 | SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin) | 46 | SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin) |
| 39 | { | 47 | { |
| 40 | started = false; | 48 | started = false; |
| @@ -56,7 +64,7 @@ SrsFFMPEG::~SrsFFMPEG() | @@ -56,7 +64,7 @@ SrsFFMPEG::~SrsFFMPEG() | ||
| 56 | stop(); | 64 | stop(); |
| 57 | } | 65 | } |
| 58 | 66 | ||
| 59 | -int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, std::string stream, SrsConfDirective* engine) | 67 | +int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine) |
| 60 | { | 68 | { |
| 61 | int ret = ERROR_SUCCESS; | 69 | int ret = ERROR_SUCCESS; |
| 62 | 70 | ||
| @@ -84,39 +92,32 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, | @@ -84,39 +92,32 @@ int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, | ||
| 84 | // input stream, from local. | 92 | // input stream, from local. |
| 85 | // ie. rtmp://127.0.0.1:1935/live/livestream | 93 | // ie. rtmp://127.0.0.1:1935/live/livestream |
| 86 | input = "rtmp://127.0.0.1:"; | 94 | input = "rtmp://127.0.0.1:"; |
| 87 | - input += port; | 95 | + input += req->port; |
| 88 | input += "/"; | 96 | input += "/"; |
| 89 | - input += app; | 97 | + input += req->app; |
| 98 | + input += "?vhost="; | ||
| 99 | + input += req->vhost; | ||
| 90 | input += "/"; | 100 | input += "/"; |
| 91 | - input += stream; | 101 | + input += req->stream; |
| 92 | 102 | ||
| 93 | // output stream, to other/self server | 103 | // output stream, to other/self server |
| 94 | // ie. rtmp://127.0.0.1:1935/live/livestream_sd | 104 | // ie. rtmp://127.0.0.1:1935/live/livestream_sd |
| 95 | - if (vhost == RTMP_VHOST_DEFAULT) { | ||
| 96 | - output = srs_replace(output, "[vhost]", "127.0.0.1"); | ||
| 97 | - } else { | ||
| 98 | - output = srs_replace(output, "[vhost]", vhost); | ||
| 99 | - } | ||
| 100 | - output = srs_replace(output, "[port]", port); | ||
| 101 | - output = srs_replace(output, "[app]", app); | ||
| 102 | - output = srs_replace(output, "[stream]", stream); | 105 | + output = srs_replace(output, "[vhost]", req->vhost); |
| 106 | + output = srs_replace(output, "[port]", req->port); | ||
| 107 | + output = srs_replace(output, "[app]", req->app); | ||
| 108 | + output = srs_replace(output, "[stream]", req->stream); | ||
| 109 | + output = srs_replace(output, "[engine]", engine->arg0()); | ||
| 103 | 110 | ||
| 104 | // important: loop check, donot transcode again. | 111 | // important: loop check, donot transcode again. |
| 105 | - // we think the following is loop circle: | ||
| 106 | - // input: rtmp://127.0.0.1:1935/live/livestream_sd | ||
| 107 | - // output: rtmp://127.0.0.1:1935/live/livestream_sd_sd | ||
| 108 | - std::string tail = ""; // tail="_sd" | ||
| 109 | - if (output.length() > input.length()) { | ||
| 110 | - tail = output.substr(input.length()); | ||
| 111 | - } | ||
| 112 | - // TODO: better dead loop check. | ||
| 113 | - // if input also endwiths the tail, loop detected. | ||
| 114 | - if (!tail.empty() && input.rfind(tail) == input.length() - tail.length()) { | 112 | + std::vector<std::string>::iterator it; |
| 113 | + it = std::find(_transcoded_url.begin(), _transcoded_url.end(), input); | ||
| 114 | + if (it != _transcoded_url.end()) { | ||
| 115 | ret = ERROR_ENCODER_LOOP; | 115 | ret = ERROR_ENCODER_LOOP; |
| 116 | srs_info("detect a loop cycle, input=%s, output=%s, ignore it. ret=%d", | 116 | srs_info("detect a loop cycle, input=%s, output=%s, ignore it. ret=%d", |
| 117 | input.c_str(), output.c_str(), ret); | 117 | input.c_str(), output.c_str(), ret); |
| 118 | return ret; | 118 | return ret; |
| 119 | } | 119 | } |
| 120 | + _transcoded_url.push_back(output); | ||
| 120 | 121 | ||
| 121 | if (vcodec != SRS_ENCODER_VCODEC) { | 122 | if (vcodec != SRS_ENCODER_VCODEC) { |
| 122 | ret = ERROR_ENCODER_VCODEC; | 123 | ret = ERROR_ENCODER_VCODEC; |
| @@ -304,6 +305,20 @@ int SrsFFMPEG::start() | @@ -304,6 +305,20 @@ int SrsFFMPEG::start() | ||
| 304 | params.push_back("-y"); | 305 | params.push_back("-y"); |
| 305 | params.push_back(output); | 306 | params.push_back(output); |
| 306 | 307 | ||
| 308 | + if (true) { | ||
| 309 | + int pparam_size = 8 * 1024; | ||
| 310 | + char* pparam = new char[pparam_size]; | ||
| 311 | + char* p = pparam; | ||
| 312 | + char* last = pparam + pparam_size; | ||
| 313 | + for (int i = 0; i < (int)params.size(); i++) { | ||
| 314 | + std::string ffp = params[i]; | ||
| 315 | + snprintf(p, last - p, "%s ", ffp.c_str()); | ||
| 316 | + p += ffp.length() + 1; | ||
| 317 | + } | ||
| 318 | + srs_trace("start transcoder: %s", pparam); | ||
| 319 | + srs_freepa(pparam); | ||
| 320 | + } | ||
| 321 | + | ||
| 307 | // TODO: fork or vfork? | 322 | // TODO: fork or vfork? |
| 308 | if ((pid = fork()) < 0) { | 323 | if ((pid = fork()) < 0) { |
| 309 | ret = ERROR_ENCODER_FORK; | 324 | ret = ERROR_ENCODER_FORK; |
| @@ -346,6 +361,12 @@ void SrsFFMPEG::stop() | @@ -346,6 +361,12 @@ void SrsFFMPEG::stop() | ||
| 346 | if (!started) { | 361 | if (!started) { |
| 347 | return; | 362 | return; |
| 348 | } | 363 | } |
| 364 | + | ||
| 365 | + std::vector<std::string>::iterator it; | ||
| 366 | + it = std::find(_transcoded_url.begin(), _transcoded_url.end(), output); | ||
| 367 | + if (it != _transcoded_url.end()) { | ||
| 368 | + _transcoded_url.erase(it); | ||
| 369 | + } | ||
| 349 | } | 370 | } |
| 350 | 371 | ||
| 351 | SrsEncoder::SrsEncoder() | 372 | SrsEncoder::SrsEncoder() |
| @@ -359,7 +380,7 @@ SrsEncoder::~SrsEncoder() | @@ -359,7 +380,7 @@ SrsEncoder::~SrsEncoder() | ||
| 359 | on_unpublish(); | 380 | on_unpublish(); |
| 360 | } | 381 | } |
| 361 | 382 | ||
| 362 | -int SrsEncoder::parse_scope_engines() | 383 | +int SrsEncoder::parse_scope_engines(SrsRequest* req) |
| 363 | { | 384 | { |
| 364 | int ret = ERROR_SUCCESS; | 385 | int ret = ERROR_SUCCESS; |
| 365 | 386 | ||
| @@ -368,17 +389,17 @@ int SrsEncoder::parse_scope_engines() | @@ -368,17 +389,17 @@ int SrsEncoder::parse_scope_engines() | ||
| 368 | 389 | ||
| 369 | // parse vhost scope engines | 390 | // parse vhost scope engines |
| 370 | std::string scope = ""; | 391 | std::string scope = ""; |
| 371 | - if ((conf = config->get_transcode(vhost, "")) != NULL) { | ||
| 372 | - if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { | 392 | + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) { |
| 393 | + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) { | ||
| 373 | srs_error("parse vhost scope=%s transcode engines failed. " | 394 | srs_error("parse vhost scope=%s transcode engines failed. " |
| 374 | "ret=%d", scope.c_str(), ret); | 395 | "ret=%d", scope.c_str(), ret); |
| 375 | return ret; | 396 | return ret; |
| 376 | } | 397 | } |
| 377 | } | 398 | } |
| 378 | // parse app scope engines | 399 | // parse app scope engines |
| 379 | - scope = app; | ||
| 380 | - if ((conf = config->get_transcode(vhost, app)) != NULL) { | ||
| 381 | - if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { | 400 | + scope = req->app; |
| 401 | + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) { | ||
| 402 | + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) { | ||
| 382 | srs_error("parse app scope=%s transcode engines failed. " | 403 | srs_error("parse app scope=%s transcode engines failed. " |
| 383 | "ret=%d", scope.c_str(), ret); | 404 | "ret=%d", scope.c_str(), ret); |
| 384 | return ret; | 405 | return ret; |
| @@ -386,9 +407,9 @@ int SrsEncoder::parse_scope_engines() | @@ -386,9 +407,9 @@ int SrsEncoder::parse_scope_engines() | ||
| 386 | } | 407 | } |
| 387 | // parse stream scope engines | 408 | // parse stream scope engines |
| 388 | scope += "/"; | 409 | scope += "/"; |
| 389 | - scope += stream; | ||
| 390 | - if ((conf = config->get_transcode(vhost, app + "/" + stream)) != NULL) { | ||
| 391 | - if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { | 410 | + scope += req->stream; |
| 411 | + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) { | ||
| 412 | + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) { | ||
| 392 | srs_error("parse stream scope=%s transcode engines failed. " | 413 | srs_error("parse stream scope=%s transcode engines failed. " |
| 393 | "ret=%d", scope.c_str(), ret); | 414 | "ret=%d", scope.c_str(), ret); |
| 394 | return ret; | 415 | return ret; |
| @@ -398,16 +419,11 @@ int SrsEncoder::parse_scope_engines() | @@ -398,16 +419,11 @@ int SrsEncoder::parse_scope_engines() | ||
| 398 | return ret; | 419 | return ret; |
| 399 | } | 420 | } |
| 400 | 421 | ||
| 401 | -int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _app, std::string _stream) | 422 | +int SrsEncoder::on_publish(SrsRequest* req) |
| 402 | { | 423 | { |
| 403 | int ret = ERROR_SUCCESS; | 424 | int ret = ERROR_SUCCESS; |
| 404 | 425 | ||
| 405 | - vhost = _vhost; | ||
| 406 | - port = _port; | ||
| 407 | - app = _app; | ||
| 408 | - stream = _stream; | ||
| 409 | - | ||
| 410 | - ret = parse_scope_engines(); | 426 | + ret = parse_scope_engines(req); |
| 411 | 427 | ||
| 412 | // ignore the loop encoder | 428 | // ignore the loop encoder |
| 413 | if (ret == ERROR_ENCODER_LOOP) { | 429 | if (ret == ERROR_ENCODER_LOOP) { |
| @@ -457,7 +473,7 @@ SrsFFMPEG* SrsEncoder::at(int index) | @@ -457,7 +473,7 @@ SrsFFMPEG* SrsEncoder::at(int index) | ||
| 457 | return ffmpegs[index]; | 473 | return ffmpegs[index]; |
| 458 | } | 474 | } |
| 459 | 475 | ||
| 460 | -int SrsEncoder::parse_transcode(SrsConfDirective* conf) | 476 | +int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf) |
| 461 | { | 477 | { |
| 462 | int ret = ERROR_SUCCESS; | 478 | int ret = ERROR_SUCCESS; |
| 463 | 479 | ||
| @@ -498,7 +514,7 @@ int SrsEncoder::parse_transcode(SrsConfDirective* conf) | @@ -498,7 +514,7 @@ int SrsEncoder::parse_transcode(SrsConfDirective* conf) | ||
| 498 | 514 | ||
| 499 | SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin); | 515 | SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin); |
| 500 | 516 | ||
| 501 | - if ((ret = ffmpeg->initialize(vhost, port, app, stream, engine)) != ERROR_SUCCESS) { | 517 | + if ((ret = ffmpeg->initialize(req, engine)) != ERROR_SUCCESS) { |
| 502 | srs_freep(ffmpeg); | 518 | srs_freep(ffmpeg); |
| 503 | 519 | ||
| 504 | // if got a loop, donot transcode the whole stream. | 520 | // if got a loop, donot transcode the whole stream. |
| @@ -577,3 +593,5 @@ void* SrsEncoder::encoder_thread(void* arg) | @@ -577,3 +593,5 @@ void* SrsEncoder::encoder_thread(void* arg) | ||
| 577 | return NULL; | 593 | return NULL; |
| 578 | } | 594 | } |
| 579 | 595 | ||
| 596 | +#endif | ||
| 597 | + |
| @@ -35,6 +35,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -35,6 +35,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 35 | #include <st.h> | 35 | #include <st.h> |
| 36 | 36 | ||
| 37 | class SrsConfDirective; | 37 | class SrsConfDirective; |
| 38 | +class SrsRequest; | ||
| 39 | + | ||
| 40 | +#ifdef SRS_FFMPEG | ||
| 38 | 41 | ||
| 39 | /** | 42 | /** |
| 40 | * a transcode engine: ffmepg, | 43 | * a transcode engine: ffmepg, |
| @@ -68,7 +71,7 @@ public: | @@ -68,7 +71,7 @@ public: | ||
| 68 | SrsFFMPEG(std::string ffmpeg_bin); | 71 | SrsFFMPEG(std::string ffmpeg_bin); |
| 69 | virtual ~SrsFFMPEG(); | 72 | virtual ~SrsFFMPEG(); |
| 70 | public: | 73 | public: |
| 71 | - virtual int initialize(std::string vhost, std::string port, std::string app, std::string stream, SrsConfDirective* engine); | 74 | + virtual int initialize(SrsRequest* req, SrsConfDirective* engine); |
| 72 | virtual int start(); | 75 | virtual int start(); |
| 73 | virtual void stop(); | 76 | virtual void stop(); |
| 74 | }; | 77 | }; |
| @@ -80,11 +83,6 @@ public: | @@ -80,11 +83,6 @@ public: | ||
| 80 | class SrsEncoder | 83 | class SrsEncoder |
| 81 | { | 84 | { |
| 82 | private: | 85 | private: |
| 83 | - std::string vhost; | ||
| 84 | - std::string port; | ||
| 85 | - std::string app; | ||
| 86 | - std::string stream; | ||
| 87 | -private: | ||
| 88 | std::vector<SrsFFMPEG*> ffmpegs; | 86 | std::vector<SrsFFMPEG*> ffmpegs; |
| 89 | private: | 87 | private: |
| 90 | st_thread_t tid; | 88 | st_thread_t tid; |
| @@ -93,16 +91,18 @@ public: | @@ -93,16 +91,18 @@ public: | ||
| 93 | SrsEncoder(); | 91 | SrsEncoder(); |
| 94 | virtual ~SrsEncoder(); | 92 | virtual ~SrsEncoder(); |
| 95 | public: | 93 | public: |
| 96 | - virtual int on_publish(std::string vhost, std::string port, std::string app, std::string stream); | 94 | + virtual int on_publish(SrsRequest* req); |
| 97 | virtual void on_unpublish(); | 95 | virtual void on_unpublish(); |
| 98 | private: | 96 | private: |
| 99 | - virtual int parse_scope_engines(); | 97 | + virtual int parse_scope_engines(SrsRequest* req); |
| 100 | virtual void clear_engines(); | 98 | virtual void clear_engines(); |
| 101 | virtual SrsFFMPEG* at(int index); | 99 | virtual SrsFFMPEG* at(int index); |
| 102 | - virtual int parse_transcode(SrsConfDirective* conf); | 100 | + virtual int parse_transcode(SrsRequest* req, SrsConfDirective* conf); |
| 103 | virtual int cycle(); | 101 | virtual int cycle(); |
| 104 | virtual void encoder_cycle(); | 102 | virtual void encoder_cycle(); |
| 105 | static void* encoder_thread(void* arg); | 103 | static void* encoder_thread(void* arg); |
| 106 | }; | 104 | }; |
| 107 | 105 | ||
| 108 | #endif | 106 | #endif |
| 107 | + | ||
| 108 | +#endif |
| @@ -85,6 +85,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -85,6 +85,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 85 | #define ERROR_SYSTEM_STREAM_BUSY 410 | 85 | #define ERROR_SYSTEM_STREAM_BUSY 410 |
| 86 | #define ERROR_SYSTEM_IP_INVALID 411 | 86 | #define ERROR_SYSTEM_IP_INVALID 411 |
| 87 | #define ERROR_SYSTEM_CONFIG_TOO_LARGE 412 | 87 | #define ERROR_SYSTEM_CONFIG_TOO_LARGE 412 |
| 88 | +#define ERROR_SYSTEM_FORWARD_LOOP 413 | ||
| 88 | 89 | ||
| 89 | // see librtmp. | 90 | // see librtmp. |
| 90 | // failed when open ssl create the dh | 91 | // failed when open ssl create the dh |
| @@ -27,13 +27,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -27,13 +27,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 27 | #include <sys/socket.h> | 27 | #include <sys/socket.h> |
| 28 | #include <netinet/in.h> | 28 | #include <netinet/in.h> |
| 29 | #include <arpa/inet.h> | 29 | #include <arpa/inet.h> |
| 30 | -#include <netdb.h> | ||
| 31 | 30 | ||
| 32 | #include <srs_core_error.hpp> | 31 | #include <srs_core_error.hpp> |
| 33 | #include <srs_core_rtmp.hpp> | 32 | #include <srs_core_rtmp.hpp> |
| 34 | #include <srs_core_log.hpp> | 33 | #include <srs_core_log.hpp> |
| 35 | #include <srs_core_protocol.hpp> | 34 | #include <srs_core_protocol.hpp> |
| 36 | #include <srs_core_pithy_print.hpp> | 35 | #include <srs_core_pithy_print.hpp> |
| 36 | +#include <srs_core_rtmp.hpp> | ||
| 37 | +#include <srs_core_config.hpp> | ||
| 37 | 38 | ||
| 38 | #define SRS_PULSE_TIMEOUT_MS 100 | 39 | #define SRS_PULSE_TIMEOUT_MS 100 |
| 39 | #define SRS_FORWARDER_SLEEP_MS 2000 | 40 | #define SRS_FORWARDER_SLEEP_MS 2000 |
| @@ -62,29 +63,54 @@ SrsForwarder::~SrsForwarder() | @@ -62,29 +63,54 @@ SrsForwarder::~SrsForwarder() | ||
| 62 | msgs.clear(); | 63 | msgs.clear(); |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | -int SrsForwarder::on_publish(std::string vhost, std::string _app, std::string stream, std::string forward_server) | 66 | +int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server) |
| 66 | { | 67 | { |
| 67 | int ret = ERROR_SUCCESS; | 68 | int ret = ERROR_SUCCESS; |
| 68 | 69 | ||
| 69 | - app = _app; | 70 | + // forward app |
| 71 | + app = req->app; | ||
| 72 | + | ||
| 73 | + stream_name = req->stream; | ||
| 74 | + server = forward_server; | ||
| 75 | + std::string s_port = RTMP_DEFAULT_PORTS; | ||
| 76 | + port = RTMP_DEFAULT_PORT; | ||
| 77 | + | ||
| 78 | + size_t pos = forward_server.find(":"); | ||
| 79 | + if (pos != std::string::npos) { | ||
| 80 | + s_port = forward_server.substr(pos + 1); | ||
| 81 | + server = forward_server.substr(0, pos); | ||
| 82 | + } | ||
| 83 | + // discovery vhost | ||
| 84 | + std::string vhost = req->vhost; | ||
| 85 | + srs_vhost_resolve(vhost, s_port); | ||
| 86 | + port = ::atoi(s_port.c_str()); | ||
| 70 | 87 | ||
| 88 | + // generate tcUrl | ||
| 71 | tc_url = "rtmp://"; | 89 | tc_url = "rtmp://"; |
| 72 | tc_url += vhost; | 90 | tc_url += vhost; |
| 73 | tc_url += "/"; | 91 | tc_url += "/"; |
| 74 | - tc_url += app; | 92 | + tc_url += req->app; |
| 75 | 93 | ||
| 76 | - stream_name = stream; | ||
| 77 | - server = forward_server; | ||
| 78 | - port = 1935; | 94 | + // dead loop check |
| 95 | + std::string source_ep = req->vhost; | ||
| 96 | + source_ep += ":"; | ||
| 97 | + source_ep += req->port; | ||
| 79 | 98 | ||
| 80 | - // TODO: dead loop check. | 99 | + std::string dest_ep = vhost; |
| 100 | + dest_ep += ":"; | ||
| 101 | + dest_ep += s_port; | ||
| 81 | 102 | ||
| 82 | - size_t pos = forward_server.find(":"); | ||
| 83 | - if (pos != std::string::npos) { | ||
| 84 | - port = ::atoi(forward_server.substr(pos + 1).c_str()); | ||
| 85 | - server = forward_server.substr(0, pos); | 103 | + if (source_ep == dest_ep) { |
| 104 | + ret = ERROR_SYSTEM_FORWARD_LOOP; | ||
| 105 | + srs_warn("farder loop detected. src=%s, dest=%s, ret=%d", | ||
| 106 | + source_ep.c_str(), dest_ep.c_str(), ret); | ||
| 107 | + return ret; | ||
| 86 | } | 108 | } |
| 109 | + srs_trace("start forward %s to %s, stream: %s/%s", | ||
| 110 | + source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(), | ||
| 111 | + stream_name.c_str()); | ||
| 87 | 112 | ||
| 113 | + // start forward | ||
| 88 | if ((ret = open_socket()) != ERROR_SUCCESS) { | 114 | if ((ret = open_socket()) != ERROR_SUCCESS) { |
| 89 | return ret; | 115 | return ret; |
| 90 | } | 116 | } |
| @@ -179,7 +205,7 @@ int SrsForwarder::connect_server() | @@ -179,7 +205,7 @@ int SrsForwarder::connect_server() | ||
| 179 | { | 205 | { |
| 180 | int ret = ERROR_SUCCESS; | 206 | int ret = ERROR_SUCCESS; |
| 181 | 207 | ||
| 182 | - std::string ip = parse_server(server); | 208 | + std::string ip = srs_dns_resolve(server); |
| 183 | if (ip.empty()) { | 209 | if (ip.empty()) { |
| 184 | ret = ERROR_SYSTEM_IP_INVALID; | 210 | ret = ERROR_SYSTEM_IP_INVALID; |
| 185 | srs_error("dns resolve server error, ip empty. ret=%d", ret); | 211 | srs_error("dns resolve server error, ip empty. ret=%d", ret); |
| @@ -201,29 +227,6 @@ int SrsForwarder::connect_server() | @@ -201,29 +227,6 @@ int SrsForwarder::connect_server() | ||
| 201 | return ret; | 227 | return ret; |
| 202 | } | 228 | } |
| 203 | 229 | ||
| 204 | -std::string SrsForwarder::parse_server(std::string host) | ||
| 205 | -{ | ||
| 206 | - if (inet_addr(host.c_str()) != INADDR_NONE) { | ||
| 207 | - return host; | ||
| 208 | - } | ||
| 209 | - | ||
| 210 | - hostent* answer = gethostbyname(host.c_str()); | ||
| 211 | - if (answer == NULL) { | ||
| 212 | - srs_error("dns resolve host %s error.", host.c_str()); | ||
| 213 | - return ""; | ||
| 214 | - } | ||
| 215 | - | ||
| 216 | - char ipv4[16]; | ||
| 217 | - memset(ipv4, 0, sizeof(ipv4)); | ||
| 218 | - for (int i = 0; i < answer->h_length; i++) { | ||
| 219 | - inet_ntop(AF_INET, answer->h_addr_list[i], ipv4, sizeof(ipv4)); | ||
| 220 | - srs_info("dns resolve host %s to %s.", host.c_str(), ipv4); | ||
| 221 | - break; | ||
| 222 | - } | ||
| 223 | - | ||
| 224 | - return ipv4; | ||
| 225 | -} | ||
| 226 | - | ||
| 227 | int SrsForwarder::cycle() | 230 | int SrsForwarder::cycle() |
| 228 | { | 231 | { |
| 229 | int ret = ERROR_SUCCESS; | 232 | int ret = ERROR_SUCCESS; |
| @@ -37,6 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -37,6 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 37 | class SrsSharedPtrMessage; | 37 | class SrsSharedPtrMessage; |
| 38 | class SrsOnMetaDataPacket; | 38 | class SrsOnMetaDataPacket; |
| 39 | class SrsRtmpClient; | 39 | class SrsRtmpClient; |
| 40 | +class SrsRequest; | ||
| 40 | 41 | ||
| 41 | /** | 42 | /** |
| 42 | * forward the stream to other servers. | 43 | * forward the stream to other servers. |
| @@ -61,7 +62,7 @@ public: | @@ -61,7 +62,7 @@ public: | ||
| 61 | SrsForwarder(); | 62 | SrsForwarder(); |
| 62 | virtual ~SrsForwarder(); | 63 | virtual ~SrsForwarder(); |
| 63 | public: | 64 | public: |
| 64 | - virtual int on_publish(std::string vhost, std::string app, std::string stream, std::string forward_server); | 65 | + virtual int on_publish(SrsRequest* req, std::string forward_server); |
| 65 | virtual void on_unpublish(); | 66 | virtual void on_unpublish(); |
| 66 | virtual int on_meta_data(SrsSharedPtrMessage* metadata); | 67 | virtual int on_meta_data(SrsSharedPtrMessage* metadata); |
| 67 | virtual int on_audio(SrsSharedPtrMessage* msg); | 68 | virtual int on_audio(SrsSharedPtrMessage* msg); |
| @@ -69,7 +70,6 @@ public: | @@ -69,7 +70,6 @@ public: | ||
| 69 | private: | 70 | private: |
| 70 | virtual int open_socket(); | 71 | virtual int open_socket(); |
| 71 | virtual int connect_server(); | 72 | virtual int connect_server(); |
| 72 | - std::string parse_server(std::string host); | ||
| 73 | private: | 73 | private: |
| 74 | virtual int cycle(); | 74 | virtual int cycle(); |
| 75 | virtual int forward(); | 75 | virtual int forward(); |
| @@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 38 | #include <srs_core_config.hpp> | 38 | #include <srs_core_config.hpp> |
| 39 | #include <srs_core_source.hpp> | 39 | #include <srs_core_source.hpp> |
| 40 | #include <srs_core_autofree.hpp> | 40 | #include <srs_core_autofree.hpp> |
| 41 | +#include <srs_core_rtmp.hpp> | ||
| 41 | 42 | ||
| 42 | // @see: NGX_RTMP_HLS_DELAY, | 43 | // @see: NGX_RTMP_HLS_DELAY, |
| 43 | // 63000: 700ms, ts_tbn=90000 | 44 | // 63000: 700ms, ts_tbn=90000 |
| @@ -466,13 +467,13 @@ SrsHls::~SrsHls() | @@ -466,13 +467,13 @@ SrsHls::~SrsHls() | ||
| 466 | srs_freep(video_frame); | 467 | srs_freep(video_frame); |
| 467 | } | 468 | } |
| 468 | 469 | ||
| 469 | -int SrsHls::on_publish(std::string _vhost, std::string _app, std::string _stream) | 470 | +int SrsHls::on_publish(SrsRequest* req) |
| 470 | { | 471 | { |
| 471 | int ret = ERROR_SUCCESS; | 472 | int ret = ERROR_SUCCESS; |
| 472 | 473 | ||
| 473 | - vhost = _vhost; | ||
| 474 | - stream = _stream; | ||
| 475 | - app = _app; | 474 | + vhost = req->vhost; |
| 475 | + stream = req->stream; | ||
| 476 | + app = req->app; | ||
| 476 | 477 | ||
| 477 | // TODO: subscribe the reload event. | 478 | // TODO: subscribe the reload event. |
| 478 | 479 |
| @@ -42,6 +42,7 @@ class SrsMpegtsFrame; | @@ -42,6 +42,7 @@ class SrsMpegtsFrame; | ||
| 42 | class SrsRtmpJitter; | 42 | class SrsRtmpJitter; |
| 43 | class SrsTSMuxer; | 43 | class SrsTSMuxer; |
| 44 | class SrsCodec; | 44 | class SrsCodec; |
| 45 | +class SrsRequest; | ||
| 45 | 46 | ||
| 46 | /** | 47 | /** |
| 47 | * 3.3.2. EXTINF | 48 | * 3.3.2. EXTINF |
| @@ -142,7 +143,7 @@ public: | @@ -142,7 +143,7 @@ public: | ||
| 142 | SrsHls(); | 143 | SrsHls(); |
| 143 | virtual ~SrsHls(); | 144 | virtual ~SrsHls(); |
| 144 | public: | 145 | public: |
| 145 | - virtual int on_publish(std::string _vhost, std::string _app, std::string _stream); | 146 | + virtual int on_publish(SrsRequest* req); |
| 146 | virtual void on_unpublish(); | 147 | virtual void on_unpublish(); |
| 147 | virtual int on_meta_data(SrsOnMetaDataPacket* metadata); | 148 | virtual int on_meta_data(SrsOnMetaDataPacket* metadata); |
| 148 | virtual int on_audio(SrsSharedPtrMessage* audio); | 149 | virtual int on_audio(SrsSharedPtrMessage* audio); |
| @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 30 | #include <srs_core_autofree.hpp> | 30 | #include <srs_core_autofree.hpp> |
| 31 | #include <srs_core_amf0.hpp> | 31 | #include <srs_core_amf0.hpp> |
| 32 | #include <srs_core_handshake.hpp> | 32 | #include <srs_core_handshake.hpp> |
| 33 | +#include <srs_core_config.hpp> | ||
| 33 | 34 | ||
| 34 | /** | 35 | /** |
| 35 | * the signature for packets to client. | 36 | * the signature for packets to client. |
| @@ -93,7 +94,7 @@ int SrsRequest::discovery_app() | @@ -93,7 +94,7 @@ int SrsRequest::discovery_app() | ||
| 93 | srs_verbose("discovery vhost=%s", vhost.c_str()); | 94 | srs_verbose("discovery vhost=%s", vhost.c_str()); |
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | - port = "1935"; | 97 | + port = RTMP_DEFAULT_PORTS; |
| 97 | if ((pos = vhost.find(":")) != std::string::npos) { | 98 | if ((pos = vhost.find(":")) != std::string::npos) { |
| 98 | port = vhost.substr(pos + 1); | 99 | port = vhost.substr(pos + 1); |
| 99 | vhost = vhost.substr(0, pos); | 100 | vhost = vhost.substr(0, pos); |
| @@ -101,6 +102,14 @@ int SrsRequest::discovery_app() | @@ -101,6 +102,14 @@ int SrsRequest::discovery_app() | ||
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | app = url; | 104 | app = url; |
| 105 | + srs_vhost_resolve(vhost, app); | ||
| 106 | + | ||
| 107 | + // resolve the vhost from config | ||
| 108 | + SrsConfDirective* parsed_vhost = config->get_vhost(vhost); | ||
| 109 | + if (parsed_vhost) { | ||
| 110 | + vhost = parsed_vhost->arg0(); | ||
| 111 | + } | ||
| 112 | + | ||
| 104 | srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s", | 113 | srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s", |
| 105 | schema.c_str(), vhost.c_str(), port.c_str(), app.c_str()); | 114 | schema.c_str(), vhost.c_str(), port.c_str(), app.c_str()); |
| 106 | 115 |
| @@ -48,6 +48,12 @@ class SrsOnMetaDataPacket; | @@ -48,6 +48,12 @@ class SrsOnMetaDataPacket; | ||
| 48 | */ | 48 | */ |
| 49 | struct SrsRequest | 49 | struct SrsRequest |
| 50 | { | 50 | { |
| 51 | + /** | ||
| 52 | + * tcUrl: rtmp://request_vhost:port/app/stream | ||
| 53 | + * support pass vhost in query string, such as: | ||
| 54 | + * rtmp://ip:port/app?vhost=request_vhost/stream | ||
| 55 | + * rtmp://ip:port/app...vhost...request_vhost/stream | ||
| 56 | + */ | ||
| 51 | std::string tcUrl; | 57 | std::string tcUrl; |
| 52 | std::string pageUrl; | 58 | std::string pageUrl; |
| 53 | std::string swfUrl; | 59 | std::string swfUrl; |
| @@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 34 | #include <srs_core_forward.hpp> | 34 | #include <srs_core_forward.hpp> |
| 35 | #include <srs_core_config.hpp> | 35 | #include <srs_core_config.hpp> |
| 36 | #include <srs_core_encoder.hpp> | 36 | #include <srs_core_encoder.hpp> |
| 37 | +#include <srs_core_rtmp.hpp> | ||
| 37 | 38 | ||
| 38 | #define CONST_MAX_JITTER_MS 500 | 39 | #define CONST_MAX_JITTER_MS 500 |
| 39 | #define DEFAULT_FRAME_TIME_MS 10 | 40 | #define DEFAULT_FRAME_TIME_MS 10 |
| @@ -612,56 +613,48 @@ int SrsSource::on_video(SrsCommonMessage* video) | @@ -612,56 +613,48 @@ int SrsSource::on_video(SrsCommonMessage* video) | ||
| 612 | return ret; | 613 | return ret; |
| 613 | } | 614 | } |
| 614 | 615 | ||
| 615 | -int SrsSource::on_publish(std::string vhost, std::string port, std::string app, std::string stream) | 616 | +int SrsSource::on_publish(SrsRequest* req) |
| 616 | { | 617 | { |
| 617 | int ret = ERROR_SUCCESS; | 618 | int ret = ERROR_SUCCESS; |
| 618 | 619 | ||
| 619 | _can_publish = false; | 620 | _can_publish = false; |
| 620 | 621 | ||
| 621 | -#ifdef SRS_HLS | ||
| 622 | - if ((ret = hls->on_publish(vhost, app, stream)) != ERROR_SUCCESS) { | ||
| 623 | - return ret; | ||
| 624 | - } | ||
| 625 | -#endif | ||
| 626 | - | ||
| 627 | -#ifdef SRS_FFMPEG | ||
| 628 | - if ((ret = encoder->on_publish(vhost, port, app, stream)) != ERROR_SUCCESS) { | ||
| 629 | - return ret; | ||
| 630 | - } | ||
| 631 | -#endif | ||
| 632 | - | ||
| 633 | // TODO: support reload. | 622 | // TODO: support reload. |
| 634 | 623 | ||
| 635 | // create forwarders | 624 | // create forwarders |
| 636 | - SrsConfDirective* conf = config->get_forward(vhost); | 625 | + SrsConfDirective* conf = config->get_forward(req->vhost); |
| 637 | for (int i = 0; conf && i < (int)conf->args.size(); i++) { | 626 | for (int i = 0; conf && i < (int)conf->args.size(); i++) { |
| 638 | std::string forward_server = conf->args.at(i); | 627 | std::string forward_server = conf->args.at(i); |
| 639 | 628 | ||
| 640 | SrsForwarder* forwarder = new SrsForwarder(); | 629 | SrsForwarder* forwarder = new SrsForwarder(); |
| 641 | forwarders.push_back(forwarder); | 630 | forwarders.push_back(forwarder); |
| 642 | 631 | ||
| 643 | - if ((ret = forwarder->on_publish(vhost, app, stream, forward_server)) != ERROR_SUCCESS) { | 632 | + if ((ret = forwarder->on_publish(req, forward_server)) != ERROR_SUCCESS) { |
| 644 | srs_error("start forwarder failed. " | 633 | srs_error("start forwarder failed. " |
| 645 | "vhost=%s, app=%s, stream=%s, forward-to=%s", | 634 | "vhost=%s, app=%s, stream=%s, forward-to=%s", |
| 646 | - vhost.c_str(), app.c_str(), stream.c_str(), | 635 | + req->vhost.c_str(), req->app.c_str(), req->stream.c_str(), |
| 647 | forward_server.c_str()); | 636 | forward_server.c_str()); |
| 648 | return ret; | 637 | return ret; |
| 649 | } | 638 | } |
| 650 | } | 639 | } |
| 651 | 640 | ||
| 641 | +#ifdef SRS_FFMPEG | ||
| 642 | + if ((ret = encoder->on_publish(req)) != ERROR_SUCCESS) { | ||
| 652 | return ret; | 643 | return ret; |
| 653 | -} | 644 | + } |
| 645 | +#endif | ||
| 654 | 646 | ||
| 655 | -void SrsSource::on_unpublish() | ||
| 656 | -{ | ||
| 657 | #ifdef SRS_HLS | 647 | #ifdef SRS_HLS |
| 658 | - hls->on_unpublish(); | 648 | + if ((ret = hls->on_publish(req)) != ERROR_SUCCESS) { |
| 649 | + return ret; | ||
| 650 | + } | ||
| 659 | #endif | 651 | #endif |
| 660 | 652 | ||
| 661 | -#ifdef SRS_FFMPEG | ||
| 662 | - encoder->on_unpublish(); | ||
| 663 | -#endif | 653 | + return ret; |
| 654 | +} | ||
| 664 | 655 | ||
| 656 | +void SrsSource::on_unpublish() | ||
| 657 | +{ | ||
| 665 | // close all forwarders | 658 | // close all forwarders |
| 666 | std::vector<SrsForwarder*>::iterator it; | 659 | std::vector<SrsForwarder*>::iterator it; |
| 667 | for (it = forwarders.begin(); it != forwarders.end(); ++it) { | 660 | for (it = forwarders.begin(); it != forwarders.end(); ++it) { |
| @@ -671,6 +664,14 @@ void SrsSource::on_unpublish() | @@ -671,6 +664,14 @@ void SrsSource::on_unpublish() | ||
| 671 | } | 664 | } |
| 672 | forwarders.clear(); | 665 | forwarders.clear(); |
| 673 | 666 | ||
| 667 | +#ifdef SRS_FFMPEG | ||
| 668 | + encoder->on_unpublish(); | ||
| 669 | +#endif | ||
| 670 | + | ||
| 671 | +#ifdef SRS_HLS | ||
| 672 | + hls->on_unpublish(); | ||
| 673 | +#endif | ||
| 674 | + | ||
| 674 | gop_cache->clear(); | 675 | gop_cache->clear(); |
| 675 | 676 | ||
| 676 | srs_freep(cache_metadata); | 677 | srs_freep(cache_metadata); |
| @@ -39,6 +39,7 @@ class SrsCommonMessage; | @@ -39,6 +39,7 @@ class SrsCommonMessage; | ||
| 39 | class SrsOnMetaDataPacket; | 39 | class SrsOnMetaDataPacket; |
| 40 | class SrsSharedPtrMessage; | 40 | class SrsSharedPtrMessage; |
| 41 | class SrsForwarder; | 41 | class SrsForwarder; |
| 42 | +class SrsRequest; | ||
| 42 | #ifdef SRS_HLS | 43 | #ifdef SRS_HLS |
| 43 | class SrsHls; | 44 | class SrsHls; |
| 44 | #endif | 45 | #endif |
| @@ -210,7 +211,7 @@ public: | @@ -210,7 +211,7 @@ public: | ||
| 210 | virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); | 211 | virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); |
| 211 | virtual int on_audio(SrsCommonMessage* audio); | 212 | virtual int on_audio(SrsCommonMessage* audio); |
| 212 | virtual int on_video(SrsCommonMessage* video); | 213 | virtual int on_video(SrsCommonMessage* video); |
| 213 | - virtual int on_publish(std::string vhost, std::string port, std::string app, std::string stream); | 214 | + virtual int on_publish(SrsRequest* req); |
| 214 | virtual void on_unpublish(); | 215 | virtual void on_unpublish(); |
| 215 | public: | 216 | public: |
| 216 | virtual int create_consumer(SrsConsumer*& consumer); | 217 | virtual int create_consumer(SrsConsumer*& consumer); |
-
请 注册 或 登录 后发表评论