From 80a81b16618e985e676ef9a9019c0430fa952346 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 30 Nov 2013 21:02:21 +0800 Subject: [PATCH] parse ffmpeg params --- trunk/conf/srs.conf | 2 + trunk/src/core/srs_core.cpp | 17 ++ trunk/src/core/srs_core.hpp | 4 + trunk/src/core/srs_core_client.cpp | 5 +- trunk/src/core/srs_core_config.cpp | 328 +++++++++++++++++++++++++++- trunk/src/core/srs_core_config.hpp | 23 +- trunk/src/core/srs_core_encoder.cpp | 271 ++++++++++++++++++++++- trunk/src/core/srs_core_encoder.hpp | 48 +++- trunk/src/core/srs_core_error.hpp | 14 ++ trunk/src/core/srs_core_hls.cpp | 4 +- trunk/src/core/srs_core_source.cpp | 4 +- trunk/src/core/srs_core_source.hpp | 2 +- 12 files changed, 704 insertions(+), 18 deletions(-) diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index 087b921b7..c41214fa9 100755 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -45,6 +45,7 @@ vhost all.transcode.vhost.com { transcode { # whether the transcode enabled. # if off, donot transcode. + # default: off. enabled on; # the ffmpeg ffmpeg ./objs/ffmpeg/bin/ffmpeg; @@ -53,6 +54,7 @@ vhost all.transcode.vhost.com { # the transcode set name(ie. hd) is optional and not used. engine super{ # whether the engine is enabled + # default: off. enabled on; # video encoder name vcodec libx264; diff --git a/trunk/src/core/srs_core.cpp b/trunk/src/core/srs_core.cpp index 88da2ef58..aeab709e1 100644 --- a/trunk/src/core/srs_core.cpp +++ b/trunk/src/core/srs_core.cpp @@ -43,3 +43,20 @@ void srs_update_system_time_ms() _srs_system_time_us_cache = srs_max(0, _srs_system_time_us_cache); } + +std::string srs_replace(std::string str, std::string old_str, std::string new_str) +{ + std::string ret = str; + + if (old_str == new_str) { + return ret; + } + + size_t pos = 0; + while ((pos = ret.find(old_str, pos)) != std::string::npos) { + ret = ret.replace(pos, old_str.length(), new_str); + pos += new_str.length(); + } + + return ret; +} diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 57a597c7b..2168dbd53 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -91,4 +91,8 @@ extern void srs_update_system_time_ms(); // signal defines. #define SIGNAL_RELOAD SIGHUP +#include +// replace utility +extern std::string srs_replace(std::string str, std::string old_str, std::string new_str); + #endif \ No newline at end of file diff --git a/trunk/src/core/srs_core_client.cpp b/trunk/src/core/srs_core_client.cpp index 2db43bbba..6b8062d9d 100644 --- a/trunk/src/core/srs_core_client.cpp +++ b/trunk/src/core/srs_core_client.cpp @@ -231,8 +231,7 @@ int SrsClient::check_vhost() return ret; } - SrsConfDirective* conf = NULL; - if ((conf = config->get_vhost_enabled(req->vhost)) != NULL && conf->arg0() != "on") { + if (!config->get_vhost_enabled(req->vhost)) { ret = ERROR_RTMP_VHOST_NOT_FOUND; srs_error("vhost %s disabled. ret=%d", req->vhost.c_str(), ret); return ret; @@ -344,7 +343,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); // notify the hls to prepare when publish start. - if ((ret = source->on_publish(req->vhost, req->app, req->stream)) != ERROR_SUCCESS) { + if ((ret = source->on_publish(req->vhost, req->port, req->app, req->stream)) != ERROR_SUCCESS) { srs_error("hls on_publish failed. ret=%d", ret); return ret; } diff --git a/trunk/src/core/srs_core_config.cpp b/trunk/src/core/srs_core_config.cpp index 055aac146..a517449c0 100644 --- a/trunk/src/core/srs_core_config.cpp +++ b/trunk/src/core/srs_core_config.cpp @@ -557,15 +557,24 @@ SrsConfDirective* SrsConfig::get_vhost(std::string vhost) return NULL; } -SrsConfDirective* SrsConfig::get_vhost_enabled(std::string vhost) +bool SrsConfig::get_vhost_enabled(std::string vhost) { - SrsConfDirective* conf = get_vhost(vhost); + SrsConfDirective* vhost_conf = get_vhost(vhost); - if (!conf) { - return NULL; + if (!vhost_conf) { + return true; } - return conf->get("enabled"); + SrsConfDirective* conf = vhost_conf->get("enabled"); + if (!conf) { + return true; + } + + if (conf->arg0() == "off") { + return false; + } + + return true; } SrsConfDirective* SrsConfig::get_transcode(std::string vhost, std::string scope) @@ -588,6 +597,300 @@ SrsConfDirective* SrsConfig::get_transcode(std::string vhost, std::string scope) return NULL; } +bool SrsConfig::get_transcode_enabled(SrsConfDirective* transcode) +{ + if (!transcode) { + return false; + } + + SrsConfDirective* conf = transcode->get("enabled"); + if (!conf || conf->arg0() != "on") { + return false; + } + + return true; +} + +std::string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode) +{ + if (!transcode) { + return ""; + } + + SrsConfDirective* conf = transcode->get("ffmpeg"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +void SrsConfig::get_transcode_engines(SrsConfDirective* transcode, std::vector& engines) +{ + if (!transcode) { + return; + } + + for (int i = 0; i < (int)transcode->directives.size(); i++) { + SrsConfDirective* conf = transcode->directives[i]; + + if (conf->name == "engine") { + engines.push_back(conf); + } + } + + return; +} + +bool SrsConfig::get_engine_enabled(SrsConfDirective* engine) +{ + if (!engine) { + return false; + } + + SrsConfDirective* conf = engine->get("enabled"); + if (!conf || conf->arg0() != "on") { + return false; + } + + return true; +} + +std::string SrsConfig::get_engine_vcodec(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("vcodec"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +int SrsConfig::get_engine_vbitrate(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vbitrate"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +double SrsConfig::get_engine_vfps(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vfps"); + if (!conf) { + return 0; + } + + return ::atof(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_vwidth(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vwidth"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_vheight(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vheight"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_vthreads(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vthreads"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +std::string SrsConfig::get_engine_vprofile(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("vprofile"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("vpreset"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +std::string SrsConfig::get_engine_vparams(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("vparams"); + if (!conf) { + return ""; + } + + std::string avparams; + for (int i = 0; i < (int)conf->directives.size(); i++) { + SrsConfDirective* p = conf->directives[i]; + if (!p) { + continue; + } + + avparams += p->name; + avparams += " "; + avparams += p->arg0(); + } + + return avparams; +} + +std::string SrsConfig::get_engine_acodec(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("acodec"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +int SrsConfig::get_engine_abitrate(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("abitrate"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_asample_rate(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("asample_rate"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_achannels(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("achannels"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +std::string SrsConfig::get_engine_aparams(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("aparams"); + if (!conf) { + return ""; + } + + std::string avparams; + for (int i = 0; i < (int)conf->directives.size(); i++) { + SrsConfDirective* p = conf->directives[i]; + if (!p) { + continue; + } + + avparams += p->name; + avparams += " "; + avparams += p->arg0(); + } + + return avparams; +} + +std::string SrsConfig::get_engine_output(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("output"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + + SrsConfDirective* SrsConfig::get_gop_cache(std::string vhost) { SrsConfDirective* conf = get_vhost(vhost); @@ -621,6 +924,21 @@ SrsConfDirective* SrsConfig::get_hls(std::string vhost) return conf->get("hls"); } +bool SrsConfig::get_hls_enabled(std::string vhost) +{ + SrsConfDirective* hls = get_hls(vhost); + + if (!hls) { + return true; + } + + if (hls->arg0() == "off") { + return false; + } + + return true; +} + SrsConfDirective* SrsConfig::get_hls_path(std::string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/core/srs_core_config.hpp b/trunk/src/core/srs_core_config.hpp index ba62618d7..7935262b0 100644 --- a/trunk/src/core/srs_core_config.hpp +++ b/trunk/src/core/srs_core_config.hpp @@ -112,12 +112,33 @@ public: virtual void unsubscribe(SrsReloadHandler* handler); public: virtual int parse_options(int argc, char** argv); +public: virtual SrsConfDirective* get_vhost(std::string vhost); - virtual SrsConfDirective* get_vhost_enabled(std::string vhost); + virtual bool get_vhost_enabled(std::string vhost); virtual SrsConfDirective* get_transcode(std::string vhost, std::string scope); + virtual bool get_transcode_enabled(SrsConfDirective* transcode); + virtual std::string get_transcode_ffmpeg(SrsConfDirective* transcode); + virtual void get_transcode_engines(SrsConfDirective* transcode, std::vector& engines); + virtual bool get_engine_enabled(SrsConfDirective* engine); + virtual std::string get_engine_vcodec(SrsConfDirective* engine); + virtual int get_engine_vbitrate(SrsConfDirective* engine); + virtual double get_engine_vfps(SrsConfDirective* engine); + virtual int get_engine_vwidth(SrsConfDirective* engine); + virtual int get_engine_vheight(SrsConfDirective* engine); + virtual int get_engine_vthreads(SrsConfDirective* engine); + virtual std::string get_engine_vprofile(SrsConfDirective* engine); + virtual std::string get_engine_vpreset(SrsConfDirective* engine); + virtual std::string get_engine_vparams(SrsConfDirective* engine); + virtual std::string get_engine_acodec(SrsConfDirective* engine); + virtual int get_engine_abitrate(SrsConfDirective* engine); + virtual int get_engine_asample_rate(SrsConfDirective* engine); + virtual int get_engine_achannels(SrsConfDirective* engine); + virtual std::string get_engine_aparams(SrsConfDirective* engine); + virtual std::string get_engine_output(SrsConfDirective* engine); virtual SrsConfDirective* get_gop_cache(std::string vhost); virtual SrsConfDirective* get_forward(std::string vhost); virtual SrsConfDirective* get_hls(std::string vhost); + virtual bool get_hls_enabled(std::string vhost); virtual SrsConfDirective* get_hls_path(std::string vhost); virtual SrsConfDirective* get_hls_fragment(std::string vhost); virtual SrsConfDirective* get_hls_window(std::string vhost); diff --git a/trunk/src/core/srs_core_encoder.cpp b/trunk/src/core/srs_core_encoder.cpp index 577b58f2a..ce7fde6cb 100644 --- a/trunk/src/core/srs_core_encoder.cpp +++ b/trunk/src/core/srs_core_encoder.cpp @@ -29,6 +29,154 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define SRS_ENCODER_SLEEP_MS 2000 +#define SRS_ENCODER_VCODEC "libx264" +#define SRS_ENCODER_ACODEC "libaacplus" + +SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin) +{ + started = false; + ffmpeg = ffmpeg_bin; + + vbitrate = 0; + vfps = 0; + vwidth = 0; + vheight = 0; + vthreads = 0; + abitrate = 0; + asample_rate = 0; + achannels = 0; +} + +SrsFFMPEG::~SrsFFMPEG() +{ + stop(); +} + +int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, std::string stream, SrsConfDirective* engine) +{ + int ret = ERROR_SUCCESS; + + vcodec = config->get_engine_vcodec(engine); + vbitrate = config->get_engine_vbitrate(engine); + vfps = config->get_engine_vfps(engine); + vwidth = config->get_engine_vwidth(engine); + vheight = config->get_engine_vheight(engine); + vthreads = config->get_engine_vthreads(engine); + vprofile = config->get_engine_vprofile(engine); + vpreset = config->get_engine_vpreset(engine); + vparams = config->get_engine_vparams(engine); + acodec = config->get_engine_acodec(engine); + abitrate = config->get_engine_abitrate(engine); + asample_rate = config->get_engine_asample_rate(engine); + achannels = config->get_engine_achannels(engine); + aparams = config->get_engine_aparams(engine); + output = config->get_engine_output(engine); + + // ensure the size is even. + vwidth -= vwidth % 2; + vheight -= vheight % 2; + + if (vhost == RTMP_VHOST_DEFAULT) { + output = srs_replace(output, "[vhost]", "127.0.0.1"); + } else { + output = srs_replace(output, "[vhost]", vhost); + } + output = srs_replace(output, "[port]", port); + output = srs_replace(output, "[app]", app); + output = srs_replace(output, "[stream]", stream); + + if (vcodec != SRS_ENCODER_VCODEC) { + ret = ERROR_ENCODER_VCODEC; + srs_error("invalid vcodec, must be %s, actual %s, ret=%d", + SRS_ENCODER_VCODEC, vcodec.c_str(), ret); + return ret; + } + if (vbitrate <= 0) { + ret = ERROR_ENCODER_VBITRATE; + srs_error("invalid vbitrate: %d, ret=%d", vbitrate, ret); + return ret; + } + if (vfps <= 0) { + ret = ERROR_ENCODER_VFPS; + srs_error("invalid vfps: %.2f, ret=%d", vfps, ret); + return ret; + } + if (vwidth <= 0) { + ret = ERROR_ENCODER_VWIDTH; + srs_error("invalid vwidth: %d, ret=%d", vwidth, ret); + return ret; + } + if (vheight <= 0) { + ret = ERROR_ENCODER_VHEIGHT; + srs_error("invalid vheight: %d, ret=%d", vheight, ret); + return ret; + } + if (vthreads < 0) { + ret = ERROR_ENCODER_VTHREADS; + srs_error("invalid vthreads: %d, ret=%d", vthreads, ret); + return ret; + } + if (vprofile.empty()) { + ret = ERROR_ENCODER_VPROFILE; + srs_error("invalid vprofile: %s, ret=%d", vprofile.c_str(), ret); + return ret; + } + if (vpreset.empty()) { + ret = ERROR_ENCODER_VPRESET; + srs_error("invalid vpreset: %s, ret=%d", vpreset.c_str(), ret); + return ret; + } + if (acodec != SRS_ENCODER_ACODEC) { + ret = ERROR_ENCODER_ACODEC; + srs_error("invalid acodec, must be %s, actual %s, ret=%d", + SRS_ENCODER_ACODEC, acodec.c_str(), ret); + return ret; + } + if (abitrate <= 0) { + ret = ERROR_ENCODER_ABITRATE; + srs_error("invalid abitrate: %d, ret=%d", + abitrate, ret); + return ret; + } + if (asample_rate <= 0) { + ret = ERROR_ENCODER_ASAMPLE_RATE; + srs_error("invalid sample rate: %d, ret=%d", + asample_rate, ret); + return ret; + } + if (achannels != 1 && achannels != 2) { + ret = ERROR_ENCODER_ACHANNELS; + srs_error("invalid achannels, must be 1 or 2, actual %d, ret=%d", + achannels, ret); + return ret; + } + if (output.empty()) { + ret = ERROR_ENCODER_OUTPUT; + srs_error("invalid empty output, ret=%d", ret); + return ret; + } + + return ret; +} + +int SrsFFMPEG::start() +{ + int ret = ERROR_SUCCESS; + + if (started) { + return ret; + } + + return ret; +} + +void SrsFFMPEG::stop() +{ + if (!started) { + return; + } +} + SrsEncoder::SrsEncoder() { tid = NULL; @@ -40,16 +188,50 @@ SrsEncoder::~SrsEncoder() on_unpublish(); } -int SrsEncoder::on_publish(std::string _vhost, std::string _app, std::string _stream) +int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _app, std::string _stream) { int ret = ERROR_SUCCESS; vhost = _vhost; + port = _port; app = _app; stream = _stream; + + // parse all transcode engines. + SrsConfDirective* conf = NULL; + + // parse vhost scope engines + std::string scope = ""; + if ((conf = config->get_transcode(vhost, "")) != NULL) { + if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { + srs_error("parse vhost scope=%s transcode engines failed. " + "ret=%d", scope.c_str(), ret); + return ret; + } + } + // parse app scope engines + scope = app; + if ((conf = config->get_transcode(vhost, app)) != NULL) { + if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { + srs_error("parse app scope=%s transcode engines failed. " + "ret=%d", scope.c_str(), ret); + return ret; + } + } + // parse stream scope engines + scope += "/"; + scope += stream; + if ((conf = config->get_transcode(vhost, app + "/" + stream)) != NULL) { + if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) { + srs_error("parse stream scope=%s transcode engines failed. " + "ret=%d", scope.c_str(), ret); + return ret; + } + } + // start thread to run all encoding engines. srs_assert(!tid); - if((tid = st_thread_create(encoder_thread, this, 1, 0)) == NULL){ + if((tid = st_thread_create(encoder_thread, this, 1, 0)) == NULL) { ret = ERROR_ST_CREATE_FORWARD_THREAD; srs_error("st_thread_create failed. ret=%d", ret); return ret; @@ -66,11 +248,89 @@ void SrsEncoder::on_unpublish() st_thread_join(tid, NULL); tid = NULL; } + + std::vector::iterator it; + for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) { + SrsFFMPEG* ffmpeg = *it; + srs_freep(ffmpeg); + } + ffmpegs.clear(); +} + +SrsFFMPEG* SrsEncoder::at(int index) +{ + return ffmpegs[index]; +} + +int SrsEncoder::parse_transcode(SrsConfDirective* conf) +{ + int ret = ERROR_SUCCESS; + + srs_assert(conf); + + // enabled + if (!config->get_transcode_enabled(conf)) { + srs_trace("ignore the disabled transcode: %s", + conf->arg0().c_str()); + return ret; + } + + // ffmpeg + std::string ffmpeg_bin = config->get_transcode_ffmpeg(conf); + if (ffmpeg_bin.empty()) { + srs_trace("ignore the empty ffmpeg transcode: %s", + conf->arg0().c_str()); + return ret; + } + + // get all engines. + std::vector engines; + config->get_transcode_engines(conf, engines); + if (engines.empty()) { + srs_trace("ignore the empty transcode engine: %s", + conf->arg0().c_str()); + return ret; + } + + // create engine + for (int i = 0; i < (int)engines.size(); i++) { + SrsConfDirective* engine = engines[i]; + if (!config->get_engine_enabled(engine)) { + srs_trace("ignore the diabled transcode engine: %s %s", + conf->arg0().c_str(), engine->arg0().c_str()); + continue; + } + + SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin); + + if ((ret = ffmpeg->initialize(vhost, port, app, stream, engine)) != ERROR_SUCCESS) { + srs_freep(ffmpeg); + + srs_error("invalid transcode engine: %s %s", + conf->arg0().c_str(), engine->arg0().c_str()); + return ret; + } + + ffmpegs.push_back(ffmpeg); + } + + return ret; } int SrsEncoder::cycle() { int ret = ERROR_SUCCESS; + + // start all ffmpegs. + std::vector::iterator it; + for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) { + SrsFFMPEG* ffmpeg = *it; + if ((ret = ffmpeg->start()) != ERROR_SUCCESS) { + srs_error("ffmpeg start failed. ret=%d", ret); + return ret; + } + } + return ret; } @@ -95,7 +355,12 @@ void SrsEncoder::encoder_cycle() st_usleep(SRS_ENCODER_SLEEP_MS * 1000); } - // TODO: kill ffmpeg when finished and it alive + // kill ffmpeg when finished and it alive + std::vector::iterator it; + for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) { + SrsFFMPEG* ffmpeg = *it; + ffmpeg->stop(); + } srs_trace("encoder cycle finished"); } diff --git a/trunk/src/core/srs_core_encoder.hpp b/trunk/src/core/srs_core_encoder.hpp index d4932d442..beda2d392 100644 --- a/trunk/src/core/srs_core_encoder.hpp +++ b/trunk/src/core/srs_core_encoder.hpp @@ -30,15 +30,59 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include #include +class SrsConfDirective; + +/** +* a transcode engine: ffmepg, +* used to transcode a stream to another. +*/ +class SrsFFMPEG +{ +private: + bool started; +private: + std::string ffmpeg; + std::string vcodec; + int vbitrate; + double vfps; + int vwidth; + int vheight; + int vthreads; + std::string vprofile; + std::string vpreset; + std::string vparams; + std::string acodec; + int abitrate; + int asample_rate; + int achannels; + std::string aparams; + std::string output; +public: + SrsFFMPEG(std::string ffmpeg_bin); + virtual ~SrsFFMPEG(); +public: + virtual int initialize(std::string vhost, std::string port, std::string app, std::string stream, SrsConfDirective* engine); + virtual int start(); + virtual void stop(); +}; + +/** +* the encoder for a stream, +* may use multiple ffmpegs to transcode the specified stream. +*/ class SrsEncoder { private: std::string vhost; + std::string port; std::string app; std::string stream; +private: + std::vector ffmpegs; private: st_thread_t tid; bool loop; @@ -46,9 +90,11 @@ public: SrsEncoder(); virtual ~SrsEncoder(); public: - virtual int on_publish(std::string vhost, std::string app, std::string stream); + virtual int on_publish(std::string vhost, std::string port, std::string app, std::string stream); virtual void on_unpublish(); private: + virtual SrsFFMPEG* at(int index); + virtual int parse_transcode(SrsConfDirective* conf); virtual int cycle(); virtual void encoder_cycle(); static void* encoder_thread(void* arg); diff --git a/trunk/src/core/srs_core_error.hpp b/trunk/src/core/srs_core_error.hpp index 738e7f26e..c027a01ff 100644 --- a/trunk/src/core/srs_core_error.hpp +++ b/trunk/src/core/srs_core_error.hpp @@ -122,4 +122,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_HLS_AAC_FRAME_LENGTH 605 #define ERROR_HLS_AVC_SAMPLE_SIZE 606 +#define ERROR_ENCODER_VCODEC 700 +#define ERROR_ENCODER_OUTPUT 701 +#define ERROR_ENCODER_ACHANNELS 702 +#define ERROR_ENCODER_ASAMPLE_RATE 703 +#define ERROR_ENCODER_ABITRATE 704 +#define ERROR_ENCODER_ACODEC 705 +#define ERROR_ENCODER_VPRESET 706 +#define ERROR_ENCODER_VPROFILE 707 +#define ERROR_ENCODER_VTHREADS 708 +#define ERROR_ENCODER_VHEIGHT 709 +#define ERROR_ENCODER_VWIDTH 710 +#define ERROR_ENCODER_VFPS 711 +#define ERROR_ENCODER_VBITRATE 712 + #endif \ No newline at end of file diff --git a/trunk/src/core/srs_core_hls.cpp b/trunk/src/core/srs_core_hls.cpp index b3509ce77..8b7f2a4ac 100644 --- a/trunk/src/core/srs_core_hls.cpp +++ b/trunk/src/core/srs_core_hls.cpp @@ -688,8 +688,7 @@ int SrsHls::reopen() int ret = ERROR_SUCCESS; // try to open the HLS muxer - SrsConfDirective* conf = config->get_hls(vhost); - if (conf && conf->arg0() == "off") { + if (!config->get_hls_enabled(vhost)) { return ret; } @@ -698,6 +697,7 @@ int SrsHls::reopen() hls_enabled = true; + SrsConfDirective* conf = NULL; hls_path = SRS_CONF_DEFAULT_HLS_PATH; if ((conf = config->get_hls_path(vhost)) != NULL) { hls_path = conf->arg0(); diff --git a/trunk/src/core/srs_core_source.cpp b/trunk/src/core/srs_core_source.cpp index 1dd7cd6d5..0055913d1 100644 --- a/trunk/src/core/srs_core_source.cpp +++ b/trunk/src/core/srs_core_source.cpp @@ -612,7 +612,7 @@ int SrsSource::on_video(SrsCommonMessage* video) return ret; } -int SrsSource::on_publish(std::string vhost, std::string app, std::string stream) +int SrsSource::on_publish(std::string vhost, std::string port, std::string app, std::string stream) { int ret = ERROR_SUCCESS; @@ -625,7 +625,7 @@ int SrsSource::on_publish(std::string vhost, std::string app, std::string stream #endif #ifdef SRS_FFMPEG - if ((ret = encoder->on_publish(vhost, app, stream)) != ERROR_SUCCESS) { + if ((ret = encoder->on_publish(vhost, port, app, stream)) != ERROR_SUCCESS) { return ret; } #endif diff --git a/trunk/src/core/srs_core_source.hpp b/trunk/src/core/srs_core_source.hpp index d449dba48..6fc41c919 100644 --- a/trunk/src/core/srs_core_source.hpp +++ b/trunk/src/core/srs_core_source.hpp @@ -210,7 +210,7 @@ public: virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); virtual int on_audio(SrsCommonMessage* audio); virtual int on_video(SrsCommonMessage* video); - virtual int on_publish(std::string vhost, std::string app, std::string stream); + virtual int on_publish(std::string vhost, std::string port, std::string app, std::string stream); virtual void on_unpublish(); public: virtual int create_consumer(SrsConsumer*& consumer);