winlin

parse ffmpeg params

@@ -45,6 +45,7 @@ vhost all.transcode.vhost.com { @@ -45,6 +45,7 @@ vhost all.transcode.vhost.com {
45 transcode { 45 transcode {
46 # whether the transcode enabled. 46 # whether the transcode enabled.
47 # if off, donot transcode. 47 # if off, donot transcode.
  48 + # default: off.
48 enabled on; 49 enabled on;
49 # the ffmpeg 50 # the ffmpeg
50 ffmpeg ./objs/ffmpeg/bin/ffmpeg; 51 ffmpeg ./objs/ffmpeg/bin/ffmpeg;
@@ -53,6 +54,7 @@ vhost all.transcode.vhost.com { @@ -53,6 +54,7 @@ vhost all.transcode.vhost.com {
53 # the transcode set name(ie. hd) is optional and not used. 54 # the transcode set name(ie. hd) is optional and not used.
54 engine super{ 55 engine super{
55 # whether the engine is enabled 56 # whether the engine is enabled
  57 + # default: off.
56 enabled on; 58 enabled on;
57 # video encoder name 59 # video encoder name
58 vcodec libx264; 60 vcodec libx264;
@@ -43,3 +43,20 @@ void srs_update_system_time_ms() @@ -43,3 +43,20 @@ void srs_update_system_time_ms()
43 43
44 _srs_system_time_us_cache = srs_max(0, _srs_system_time_us_cache); 44 _srs_system_time_us_cache = srs_max(0, _srs_system_time_us_cache);
45 } 45 }
  46 +
  47 +std::string srs_replace(std::string str, std::string old_str, std::string new_str)
  48 +{
  49 + std::string ret = str;
  50 +
  51 + if (old_str == new_str) {
  52 + return ret;
  53 + }
  54 +
  55 + size_t pos = 0;
  56 + while ((pos = ret.find(old_str, pos)) != std::string::npos) {
  57 + ret = ret.replace(pos, old_str.length(), new_str);
  58 + pos += new_str.length();
  59 + }
  60 +
  61 + return ret;
  62 +}
@@ -91,4 +91,8 @@ extern void srs_update_system_time_ms(); @@ -91,4 +91,8 @@ extern void srs_update_system_time_ms();
91 // signal defines. 91 // signal defines.
92 #define SIGNAL_RELOAD SIGHUP 92 #define SIGNAL_RELOAD SIGHUP
93 93
  94 +#include <string>
  95 +// replace utility
  96 +extern std::string srs_replace(std::string str, std::string old_str, std::string new_str);
  97 +
94 #endif 98 #endif
@@ -231,8 +231,7 @@ int SrsClient::check_vhost() @@ -231,8 +231,7 @@ int SrsClient::check_vhost()
231 return ret; 231 return ret;
232 } 232 }
233 233
234 - SrsConfDirective* conf = NULL;  
235 - if ((conf = config->get_vhost_enabled(req->vhost)) != NULL && conf->arg0() != "on") { 234 + if (!config->get_vhost_enabled(req->vhost)) {
236 ret = ERROR_RTMP_VHOST_NOT_FOUND; 235 ret = ERROR_RTMP_VHOST_NOT_FOUND;
237 srs_error("vhost %s disabled. ret=%d", req->vhost.c_str(), ret); 236 srs_error("vhost %s disabled. ret=%d", req->vhost.c_str(), ret);
238 return ret; 237 return ret;
@@ -344,7 +343,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) @@ -344,7 +343,7 @@ int SrsClient::publish(SrsSource* source, bool is_fmle)
344 SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); 343 SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER);
345 344
346 // notify the hls to prepare when publish start. 345 // notify the hls to prepare when publish start.
347 - if ((ret = source->on_publish(req->vhost, req->app, req->stream)) != ERROR_SUCCESS) { 346 + if ((ret = source->on_publish(req->vhost, req->port, req->app, req->stream)) != ERROR_SUCCESS) {
348 srs_error("hls on_publish failed. ret=%d", ret); 347 srs_error("hls on_publish failed. ret=%d", ret);
349 return ret; 348 return ret;
350 } 349 }
@@ -557,15 +557,24 @@ SrsConfDirective* SrsConfig::get_vhost(std::string vhost) @@ -557,15 +557,24 @@ SrsConfDirective* SrsConfig::get_vhost(std::string vhost)
557 return NULL; 557 return NULL;
558 } 558 }
559 559
560 -SrsConfDirective* SrsConfig::get_vhost_enabled(std::string vhost) 560 +bool SrsConfig::get_vhost_enabled(std::string vhost)
561 { 561 {
562 - SrsConfDirective* conf = get_vhost(vhost); 562 + SrsConfDirective* vhost_conf = get_vhost(vhost);
563 563
  564 + if (!vhost_conf) {
  565 + return true;
  566 + }
  567 +
  568 + SrsConfDirective* conf = vhost_conf->get("enabled");
564 if (!conf) { 569 if (!conf) {
565 - return NULL; 570 + return true;
  571 + }
  572 +
  573 + if (conf->arg0() == "off") {
  574 + return false;
566 } 575 }
567 576
568 - return conf->get("enabled"); 577 + return true;
569 } 578 }
570 579
571 SrsConfDirective* SrsConfig::get_transcode(std::string vhost, std::string scope) 580 SrsConfDirective* SrsConfig::get_transcode(std::string vhost, std::string scope)
@@ -588,6 +597,300 @@ SrsConfDirective* SrsConfig::get_transcode(std::string vhost, std::string scope) @@ -588,6 +597,300 @@ SrsConfDirective* SrsConfig::get_transcode(std::string vhost, std::string scope)
588 return NULL; 597 return NULL;
589 } 598 }
590 599
  600 +bool SrsConfig::get_transcode_enabled(SrsConfDirective* transcode)
  601 +{
  602 + if (!transcode) {
  603 + return false;
  604 + }
  605 +
  606 + SrsConfDirective* conf = transcode->get("enabled");
  607 + if (!conf || conf->arg0() != "on") {
  608 + return false;
  609 + }
  610 +
  611 + return true;
  612 +}
  613 +
  614 +std::string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode)
  615 +{
  616 + if (!transcode) {
  617 + return "";
  618 + }
  619 +
  620 + SrsConfDirective* conf = transcode->get("ffmpeg");
  621 + if (!conf) {
  622 + return "";
  623 + }
  624 +
  625 + return conf->arg0();
  626 +}
  627 +
  628 +void SrsConfig::get_transcode_engines(SrsConfDirective* transcode, std::vector<SrsConfDirective*>& engines)
  629 +{
  630 + if (!transcode) {
  631 + return;
  632 + }
  633 +
  634 + for (int i = 0; i < (int)transcode->directives.size(); i++) {
  635 + SrsConfDirective* conf = transcode->directives[i];
  636 +
  637 + if (conf->name == "engine") {
  638 + engines.push_back(conf);
  639 + }
  640 + }
  641 +
  642 + return;
  643 +}
  644 +
  645 +bool SrsConfig::get_engine_enabled(SrsConfDirective* engine)
  646 +{
  647 + if (!engine) {
  648 + return false;
  649 + }
  650 +
  651 + SrsConfDirective* conf = engine->get("enabled");
  652 + if (!conf || conf->arg0() != "on") {
  653 + return false;
  654 + }
  655 +
  656 + return true;
  657 +}
  658 +
  659 +std::string SrsConfig::get_engine_vcodec(SrsConfDirective* engine)
  660 +{
  661 + if (!engine) {
  662 + return "";
  663 + }
  664 +
  665 + SrsConfDirective* conf = engine->get("vcodec");
  666 + if (!conf) {
  667 + return "";
  668 + }
  669 +
  670 + return conf->arg0();
  671 +}
  672 +
  673 +int SrsConfig::get_engine_vbitrate(SrsConfDirective* engine)
  674 +{
  675 + if (!engine) {
  676 + return 0;
  677 + }
  678 +
  679 + SrsConfDirective* conf = engine->get("vbitrate");
  680 + if (!conf) {
  681 + return 0;
  682 + }
  683 +
  684 + return ::atoi(conf->arg0().c_str());
  685 +}
  686 +
  687 +double SrsConfig::get_engine_vfps(SrsConfDirective* engine)
  688 +{
  689 + if (!engine) {
  690 + return 0;
  691 + }
  692 +
  693 + SrsConfDirective* conf = engine->get("vfps");
  694 + if (!conf) {
  695 + return 0;
  696 + }
  697 +
  698 + return ::atof(conf->arg0().c_str());
  699 +}
  700 +
  701 +int SrsConfig::get_engine_vwidth(SrsConfDirective* engine)
  702 +{
  703 + if (!engine) {
  704 + return 0;
  705 + }
  706 +
  707 + SrsConfDirective* conf = engine->get("vwidth");
  708 + if (!conf) {
  709 + return 0;
  710 + }
  711 +
  712 + return ::atoi(conf->arg0().c_str());
  713 +}
  714 +
  715 +int SrsConfig::get_engine_vheight(SrsConfDirective* engine)
  716 +{
  717 + if (!engine) {
  718 + return 0;
  719 + }
  720 +
  721 + SrsConfDirective* conf = engine->get("vheight");
  722 + if (!conf) {
  723 + return 0;
  724 + }
  725 +
  726 + return ::atoi(conf->arg0().c_str());
  727 +}
  728 +
  729 +int SrsConfig::get_engine_vthreads(SrsConfDirective* engine)
  730 +{
  731 + if (!engine) {
  732 + return 0;
  733 + }
  734 +
  735 + SrsConfDirective* conf = engine->get("vthreads");
  736 + if (!conf) {
  737 + return 0;
  738 + }
  739 +
  740 + return ::atoi(conf->arg0().c_str());
  741 +}
  742 +
  743 +std::string SrsConfig::get_engine_vprofile(SrsConfDirective* engine)
  744 +{
  745 + if (!engine) {
  746 + return "";
  747 + }
  748 +
  749 + SrsConfDirective* conf = engine->get("vprofile");
  750 + if (!conf) {
  751 + return "";
  752 + }
  753 +
  754 + return conf->arg0();
  755 +}
  756 +
  757 +std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine)
  758 +{
  759 + if (!engine) {
  760 + return "";
  761 + }
  762 +
  763 + SrsConfDirective* conf = engine->get("vpreset");
  764 + if (!conf) {
  765 + return "";
  766 + }
  767 +
  768 + return conf->arg0();
  769 +}
  770 +
  771 +std::string SrsConfig::get_engine_vparams(SrsConfDirective* engine)
  772 +{
  773 + if (!engine) {
  774 + return "";
  775 + }
  776 +
  777 + SrsConfDirective* conf = engine->get("vparams");
  778 + if (!conf) {
  779 + return "";
  780 + }
  781 +
  782 + std::string avparams;
  783 + for (int i = 0; i < (int)conf->directives.size(); i++) {
  784 + SrsConfDirective* p = conf->directives[i];
  785 + if (!p) {
  786 + continue;
  787 + }
  788 +
  789 + avparams += p->name;
  790 + avparams += " ";
  791 + avparams += p->arg0();
  792 + }
  793 +
  794 + return avparams;
  795 +}
  796 +
  797 +std::string SrsConfig::get_engine_acodec(SrsConfDirective* engine)
  798 +{
  799 + if (!engine) {
  800 + return "";
  801 + }
  802 +
  803 + SrsConfDirective* conf = engine->get("acodec");
  804 + if (!conf) {
  805 + return "";
  806 + }
  807 +
  808 + return conf->arg0();
  809 +}
  810 +
  811 +int SrsConfig::get_engine_abitrate(SrsConfDirective* engine)
  812 +{
  813 + if (!engine) {
  814 + return 0;
  815 + }
  816 +
  817 + SrsConfDirective* conf = engine->get("abitrate");
  818 + if (!conf) {
  819 + return 0;
  820 + }
  821 +
  822 + return ::atoi(conf->arg0().c_str());
  823 +}
  824 +
  825 +int SrsConfig::get_engine_asample_rate(SrsConfDirective* engine)
  826 +{
  827 + if (!engine) {
  828 + return 0;
  829 + }
  830 +
  831 + SrsConfDirective* conf = engine->get("asample_rate");
  832 + if (!conf) {
  833 + return 0;
  834 + }
  835 +
  836 + return ::atoi(conf->arg0().c_str());
  837 +}
  838 +
  839 +int SrsConfig::get_engine_achannels(SrsConfDirective* engine)
  840 +{
  841 + if (!engine) {
  842 + return 0;
  843 + }
  844 +
  845 + SrsConfDirective* conf = engine->get("achannels");
  846 + if (!conf) {
  847 + return 0;
  848 + }
  849 +
  850 + return ::atoi(conf->arg0().c_str());
  851 +}
  852 +
  853 +std::string SrsConfig::get_engine_aparams(SrsConfDirective* engine)
  854 +{
  855 + if (!engine) {
  856 + return "";
  857 + }
  858 +
  859 + SrsConfDirective* conf = engine->get("aparams");
  860 + if (!conf) {
  861 + return "";
  862 + }
  863 +
  864 + std::string avparams;
  865 + for (int i = 0; i < (int)conf->directives.size(); i++) {
  866 + SrsConfDirective* p = conf->directives[i];
  867 + if (!p) {
  868 + continue;
  869 + }
  870 +
  871 + avparams += p->name;
  872 + avparams += " ";
  873 + avparams += p->arg0();
  874 + }
  875 +
  876 + return avparams;
  877 +}
  878 +
  879 +std::string SrsConfig::get_engine_output(SrsConfDirective* engine)
  880 +{
  881 + if (!engine) {
  882 + return "";
  883 + }
  884 +
  885 + SrsConfDirective* conf = engine->get("output");
  886 + if (!conf) {
  887 + return "";
  888 + }
  889 +
  890 + return conf->arg0();
  891 +}
  892 +
  893 +
591 SrsConfDirective* SrsConfig::get_gop_cache(std::string vhost) 894 SrsConfDirective* SrsConfig::get_gop_cache(std::string vhost)
592 { 895 {
593 SrsConfDirective* conf = get_vhost(vhost); 896 SrsConfDirective* conf = get_vhost(vhost);
@@ -621,6 +924,21 @@ SrsConfDirective* SrsConfig::get_hls(std::string vhost) @@ -621,6 +924,21 @@ SrsConfDirective* SrsConfig::get_hls(std::string vhost)
621 return conf->get("hls"); 924 return conf->get("hls");
622 } 925 }
623 926
  927 +bool SrsConfig::get_hls_enabled(std::string vhost)
  928 +{
  929 + SrsConfDirective* hls = get_hls(vhost);
  930 +
  931 + if (!hls) {
  932 + return true;
  933 + }
  934 +
  935 + if (hls->arg0() == "off") {
  936 + return false;
  937 + }
  938 +
  939 + return true;
  940 +}
  941 +
624 SrsConfDirective* SrsConfig::get_hls_path(std::string vhost) 942 SrsConfDirective* SrsConfig::get_hls_path(std::string vhost)
625 { 943 {
626 SrsConfDirective* conf = get_vhost(vhost); 944 SrsConfDirective* conf = get_vhost(vhost);
@@ -112,12 +112,33 @@ public: @@ -112,12 +112,33 @@ public:
112 virtual void unsubscribe(SrsReloadHandler* handler); 112 virtual void unsubscribe(SrsReloadHandler* handler);
113 public: 113 public:
114 virtual int parse_options(int argc, char** argv); 114 virtual int parse_options(int argc, char** argv);
  115 +public:
115 virtual SrsConfDirective* get_vhost(std::string vhost); 116 virtual SrsConfDirective* get_vhost(std::string vhost);
116 - virtual SrsConfDirective* get_vhost_enabled(std::string vhost); 117 + virtual bool get_vhost_enabled(std::string vhost);
117 virtual SrsConfDirective* get_transcode(std::string vhost, std::string scope); 118 virtual SrsConfDirective* get_transcode(std::string vhost, std::string scope);
  119 + virtual bool get_transcode_enabled(SrsConfDirective* transcode);
  120 + virtual std::string get_transcode_ffmpeg(SrsConfDirective* transcode);
  121 + virtual void get_transcode_engines(SrsConfDirective* transcode, std::vector<SrsConfDirective*>& engines);
  122 + virtual bool get_engine_enabled(SrsConfDirective* engine);
  123 + virtual std::string get_engine_vcodec(SrsConfDirective* engine);
  124 + virtual int get_engine_vbitrate(SrsConfDirective* engine);
  125 + virtual double get_engine_vfps(SrsConfDirective* engine);
  126 + virtual int get_engine_vwidth(SrsConfDirective* engine);
  127 + virtual int get_engine_vheight(SrsConfDirective* engine);
  128 + virtual int get_engine_vthreads(SrsConfDirective* engine);
  129 + virtual std::string get_engine_vprofile(SrsConfDirective* engine);
  130 + virtual std::string get_engine_vpreset(SrsConfDirective* engine);
  131 + virtual std::string get_engine_vparams(SrsConfDirective* engine);
  132 + virtual std::string get_engine_acodec(SrsConfDirective* engine);
  133 + virtual int get_engine_abitrate(SrsConfDirective* engine);
  134 + virtual int get_engine_asample_rate(SrsConfDirective* engine);
  135 + virtual int get_engine_achannels(SrsConfDirective* engine);
  136 + virtual std::string get_engine_aparams(SrsConfDirective* engine);
  137 + virtual std::string get_engine_output(SrsConfDirective* engine);
118 virtual SrsConfDirective* get_gop_cache(std::string vhost); 138 virtual SrsConfDirective* get_gop_cache(std::string vhost);
119 virtual SrsConfDirective* get_forward(std::string vhost); 139 virtual SrsConfDirective* get_forward(std::string vhost);
120 virtual SrsConfDirective* get_hls(std::string vhost); 140 virtual SrsConfDirective* get_hls(std::string vhost);
  141 + virtual bool get_hls_enabled(std::string vhost);
121 virtual SrsConfDirective* get_hls_path(std::string vhost); 142 virtual SrsConfDirective* get_hls_path(std::string vhost);
122 virtual SrsConfDirective* get_hls_fragment(std::string vhost); 143 virtual SrsConfDirective* get_hls_fragment(std::string vhost);
123 virtual SrsConfDirective* get_hls_window(std::string vhost); 144 virtual SrsConfDirective* get_hls_window(std::string vhost);
@@ -29,6 +29,154 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -29,6 +29,154 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 29
30 #define SRS_ENCODER_SLEEP_MS 2000 30 #define SRS_ENCODER_SLEEP_MS 2000
31 31
  32 +#define SRS_ENCODER_VCODEC "libx264"
  33 +#define SRS_ENCODER_ACODEC "libaacplus"
  34 +
  35 +SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin)
  36 +{
  37 + started = false;
  38 + ffmpeg = ffmpeg_bin;
  39 +
  40 + vbitrate = 0;
  41 + vfps = 0;
  42 + vwidth = 0;
  43 + vheight = 0;
  44 + vthreads = 0;
  45 + abitrate = 0;
  46 + asample_rate = 0;
  47 + achannels = 0;
  48 +}
  49 +
  50 +SrsFFMPEG::~SrsFFMPEG()
  51 +{
  52 + stop();
  53 +}
  54 +
  55 +int SrsFFMPEG::initialize(std::string vhost, std::string port, std::string app, std::string stream, SrsConfDirective* engine)
  56 +{
  57 + int ret = ERROR_SUCCESS;
  58 +
  59 + vcodec = config->get_engine_vcodec(engine);
  60 + vbitrate = config->get_engine_vbitrate(engine);
  61 + vfps = config->get_engine_vfps(engine);
  62 + vwidth = config->get_engine_vwidth(engine);
  63 + vheight = config->get_engine_vheight(engine);
  64 + vthreads = config->get_engine_vthreads(engine);
  65 + vprofile = config->get_engine_vprofile(engine);
  66 + vpreset = config->get_engine_vpreset(engine);
  67 + vparams = config->get_engine_vparams(engine);
  68 + acodec = config->get_engine_acodec(engine);
  69 + abitrate = config->get_engine_abitrate(engine);
  70 + asample_rate = config->get_engine_asample_rate(engine);
  71 + achannels = config->get_engine_achannels(engine);
  72 + aparams = config->get_engine_aparams(engine);
  73 + output = config->get_engine_output(engine);
  74 +
  75 + // ensure the size is even.
  76 + vwidth -= vwidth % 2;
  77 + vheight -= vheight % 2;
  78 +
  79 + if (vhost == RTMP_VHOST_DEFAULT) {
  80 + output = srs_replace(output, "[vhost]", "127.0.0.1");
  81 + } else {
  82 + output = srs_replace(output, "[vhost]", vhost);
  83 + }
  84 + output = srs_replace(output, "[port]", port);
  85 + output = srs_replace(output, "[app]", app);
  86 + output = srs_replace(output, "[stream]", stream);
  87 +
  88 + if (vcodec != SRS_ENCODER_VCODEC) {
  89 + ret = ERROR_ENCODER_VCODEC;
  90 + srs_error("invalid vcodec, must be %s, actual %s, ret=%d",
  91 + SRS_ENCODER_VCODEC, vcodec.c_str(), ret);
  92 + return ret;
  93 + }
  94 + if (vbitrate <= 0) {
  95 + ret = ERROR_ENCODER_VBITRATE;
  96 + srs_error("invalid vbitrate: %d, ret=%d", vbitrate, ret);
  97 + return ret;
  98 + }
  99 + if (vfps <= 0) {
  100 + ret = ERROR_ENCODER_VFPS;
  101 + srs_error("invalid vfps: %.2f, ret=%d", vfps, ret);
  102 + return ret;
  103 + }
  104 + if (vwidth <= 0) {
  105 + ret = ERROR_ENCODER_VWIDTH;
  106 + srs_error("invalid vwidth: %d, ret=%d", vwidth, ret);
  107 + return ret;
  108 + }
  109 + if (vheight <= 0) {
  110 + ret = ERROR_ENCODER_VHEIGHT;
  111 + srs_error("invalid vheight: %d, ret=%d", vheight, ret);
  112 + return ret;
  113 + }
  114 + if (vthreads < 0) {
  115 + ret = ERROR_ENCODER_VTHREADS;
  116 + srs_error("invalid vthreads: %d, ret=%d", vthreads, ret);
  117 + return ret;
  118 + }
  119 + if (vprofile.empty()) {
  120 + ret = ERROR_ENCODER_VPROFILE;
  121 + srs_error("invalid vprofile: %s, ret=%d", vprofile.c_str(), ret);
  122 + return ret;
  123 + }
  124 + if (vpreset.empty()) {
  125 + ret = ERROR_ENCODER_VPRESET;
  126 + srs_error("invalid vpreset: %s, ret=%d", vpreset.c_str(), ret);
  127 + return ret;
  128 + }
  129 + if (acodec != SRS_ENCODER_ACODEC) {
  130 + ret = ERROR_ENCODER_ACODEC;
  131 + srs_error("invalid acodec, must be %s, actual %s, ret=%d",
  132 + SRS_ENCODER_ACODEC, acodec.c_str(), ret);
  133 + return ret;
  134 + }
  135 + if (abitrate <= 0) {
  136 + ret = ERROR_ENCODER_ABITRATE;
  137 + srs_error("invalid abitrate: %d, ret=%d",
  138 + abitrate, ret);
  139 + return ret;
  140 + }
  141 + if (asample_rate <= 0) {
  142 + ret = ERROR_ENCODER_ASAMPLE_RATE;
  143 + srs_error("invalid sample rate: %d, ret=%d",
  144 + asample_rate, ret);
  145 + return ret;
  146 + }
  147 + if (achannels != 1 && achannels != 2) {
  148 + ret = ERROR_ENCODER_ACHANNELS;
  149 + srs_error("invalid achannels, must be 1 or 2, actual %d, ret=%d",
  150 + achannels, ret);
  151 + return ret;
  152 + }
  153 + if (output.empty()) {
  154 + ret = ERROR_ENCODER_OUTPUT;
  155 + srs_error("invalid empty output, ret=%d", ret);
  156 + return ret;
  157 + }
  158 +
  159 + return ret;
  160 +}
  161 +
  162 +int SrsFFMPEG::start()
  163 +{
  164 + int ret = ERROR_SUCCESS;
  165 +
  166 + if (started) {
  167 + return ret;
  168 + }
  169 +
  170 + return ret;
  171 +}
  172 +
  173 +void SrsFFMPEG::stop()
  174 +{
  175 + if (!started) {
  176 + return;
  177 + }
  178 +}
  179 +
32 SrsEncoder::SrsEncoder() 180 SrsEncoder::SrsEncoder()
33 { 181 {
34 tid = NULL; 182 tid = NULL;
@@ -40,16 +188,50 @@ SrsEncoder::~SrsEncoder() @@ -40,16 +188,50 @@ SrsEncoder::~SrsEncoder()
40 on_unpublish(); 188 on_unpublish();
41 } 189 }
42 190
43 -int SrsEncoder::on_publish(std::string _vhost, std::string _app, std::string _stream) 191 +int SrsEncoder::on_publish(std::string _vhost, std::string _port, std::string _app, std::string _stream)
44 { 192 {
45 int ret = ERROR_SUCCESS; 193 int ret = ERROR_SUCCESS;
46 194
47 vhost = _vhost; 195 vhost = _vhost;
  196 + port = _port;
48 app = _app; 197 app = _app;
49 stream = _stream; 198 stream = _stream;
  199 +
  200 + // parse all transcode engines.
  201 + SrsConfDirective* conf = NULL;
  202 +
  203 + // parse vhost scope engines
  204 + std::string scope = "";
  205 + if ((conf = config->get_transcode(vhost, "")) != NULL) {
  206 + if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) {
  207 + srs_error("parse vhost scope=%s transcode engines failed. "
  208 + "ret=%d", scope.c_str(), ret);
  209 + return ret;
  210 + }
  211 + }
  212 + // parse app scope engines
  213 + scope = app;
  214 + if ((conf = config->get_transcode(vhost, app)) != NULL) {
  215 + if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) {
  216 + srs_error("parse app scope=%s transcode engines failed. "
  217 + "ret=%d", scope.c_str(), ret);
  218 + return ret;
  219 + }
  220 + }
  221 + // parse stream scope engines
  222 + scope += "/";
  223 + scope += stream;
  224 + if ((conf = config->get_transcode(vhost, app + "/" + stream)) != NULL) {
  225 + if ((ret = parse_transcode(conf)) != ERROR_SUCCESS) {
  226 + srs_error("parse stream scope=%s transcode engines failed. "
  227 + "ret=%d", scope.c_str(), ret);
  228 + return ret;
  229 + }
  230 + }
50 231
  232 + // start thread to run all encoding engines.
51 srs_assert(!tid); 233 srs_assert(!tid);
52 - if((tid = st_thread_create(encoder_thread, this, 1, 0)) == NULL){ 234 + if((tid = st_thread_create(encoder_thread, this, 1, 0)) == NULL) {
53 ret = ERROR_ST_CREATE_FORWARD_THREAD; 235 ret = ERROR_ST_CREATE_FORWARD_THREAD;
54 srs_error("st_thread_create failed. ret=%d", ret); 236 srs_error("st_thread_create failed. ret=%d", ret);
55 return ret; 237 return ret;
@@ -66,11 +248,89 @@ void SrsEncoder::on_unpublish() @@ -66,11 +248,89 @@ void SrsEncoder::on_unpublish()
66 st_thread_join(tid, NULL); 248 st_thread_join(tid, NULL);
67 tid = NULL; 249 tid = NULL;
68 } 250 }
  251 +
  252 + std::vector<SrsFFMPEG*>::iterator it;
  253 + for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
  254 + SrsFFMPEG* ffmpeg = *it;
  255 + srs_freep(ffmpeg);
  256 + }
  257 + ffmpegs.clear();
  258 +}
  259 +
  260 +SrsFFMPEG* SrsEncoder::at(int index)
  261 +{
  262 + return ffmpegs[index];
  263 +}
  264 +
  265 +int SrsEncoder::parse_transcode(SrsConfDirective* conf)
  266 +{
  267 + int ret = ERROR_SUCCESS;
  268 +
  269 + srs_assert(conf);
  270 +
  271 + // enabled
  272 + if (!config->get_transcode_enabled(conf)) {
  273 + srs_trace("ignore the disabled transcode: %s",
  274 + conf->arg0().c_str());
  275 + return ret;
  276 + }
  277 +
  278 + // ffmpeg
  279 + std::string ffmpeg_bin = config->get_transcode_ffmpeg(conf);
  280 + if (ffmpeg_bin.empty()) {
  281 + srs_trace("ignore the empty ffmpeg transcode: %s",
  282 + conf->arg0().c_str());
  283 + return ret;
  284 + }
  285 +
  286 + // get all engines.
  287 + std::vector<SrsConfDirective*> engines;
  288 + config->get_transcode_engines(conf, engines);
  289 + if (engines.empty()) {
  290 + srs_trace("ignore the empty transcode engine: %s",
  291 + conf->arg0().c_str());
  292 + return ret;
  293 + }
  294 +
  295 + // create engine
  296 + for (int i = 0; i < (int)engines.size(); i++) {
  297 + SrsConfDirective* engine = engines[i];
  298 + if (!config->get_engine_enabled(engine)) {
  299 + srs_trace("ignore the diabled transcode engine: %s %s",
  300 + conf->arg0().c_str(), engine->arg0().c_str());
  301 + continue;
  302 + }
  303 +
  304 + SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin);
  305 +
  306 + if ((ret = ffmpeg->initialize(vhost, port, app, stream, engine)) != ERROR_SUCCESS) {
  307 + srs_freep(ffmpeg);
  308 +
  309 + srs_error("invalid transcode engine: %s %s",
  310 + conf->arg0().c_str(), engine->arg0().c_str());
  311 + return ret;
  312 + }
  313 +
  314 + ffmpegs.push_back(ffmpeg);
  315 + }
  316 +
  317 + return ret;
69 } 318 }
70 319
71 int SrsEncoder::cycle() 320 int SrsEncoder::cycle()
72 { 321 {
73 int ret = ERROR_SUCCESS; 322 int ret = ERROR_SUCCESS;
  323 +
  324 + // start all ffmpegs.
  325 + std::vector<SrsFFMPEG*>::iterator it;
  326 + for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
  327 + SrsFFMPEG* ffmpeg = *it;
  328 + if ((ret = ffmpeg->start()) != ERROR_SUCCESS) {
  329 + srs_error("ffmpeg start failed. ret=%d", ret);
  330 + return ret;
  331 + }
  332 + }
  333 +
74 return ret; 334 return ret;
75 } 335 }
76 336
@@ -95,7 +355,12 @@ void SrsEncoder::encoder_cycle() @@ -95,7 +355,12 @@ void SrsEncoder::encoder_cycle()
95 st_usleep(SRS_ENCODER_SLEEP_MS * 1000); 355 st_usleep(SRS_ENCODER_SLEEP_MS * 1000);
96 } 356 }
97 357
98 - // TODO: kill ffmpeg when finished and it alive 358 + // kill ffmpeg when finished and it alive
  359 + std::vector<SrsFFMPEG*>::iterator it;
  360 + for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
  361 + SrsFFMPEG* ffmpeg = *it;
  362 + ffmpeg->stop();
  363 + }
99 364
100 srs_trace("encoder cycle finished"); 365 srs_trace("encoder cycle finished");
101 } 366 }
@@ -30,25 +30,71 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,25 +30,71 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <srs_core.hpp> 30 #include <srs_core.hpp>
31 31
32 #include <string> 32 #include <string>
  33 +#include <vector>
33 34
34 #include <st.h> 35 #include <st.h>
35 36
  37 +class SrsConfDirective;
  38 +
  39 +/**
  40 +* a transcode engine: ffmepg,
  41 +* used to transcode a stream to another.
  42 +*/
  43 +class SrsFFMPEG
  44 +{
  45 +private:
  46 + bool started;
  47 +private:
  48 + std::string ffmpeg;
  49 + std::string vcodec;
  50 + int vbitrate;
  51 + double vfps;
  52 + int vwidth;
  53 + int vheight;
  54 + int vthreads;
  55 + std::string vprofile;
  56 + std::string vpreset;
  57 + std::string vparams;
  58 + std::string acodec;
  59 + int abitrate;
  60 + int asample_rate;
  61 + int achannels;
  62 + std::string aparams;
  63 + std::string output;
  64 +public:
  65 + SrsFFMPEG(std::string ffmpeg_bin);
  66 + virtual ~SrsFFMPEG();
  67 +public:
  68 + virtual int initialize(std::string vhost, std::string port, std::string app, std::string stream, SrsConfDirective* engine);
  69 + virtual int start();
  70 + virtual void stop();
  71 +};
  72 +
  73 +/**
  74 +* the encoder for a stream,
  75 +* may use multiple ffmpegs to transcode the specified stream.
  76 +*/
36 class SrsEncoder 77 class SrsEncoder
37 { 78 {
38 private: 79 private:
39 std::string vhost; 80 std::string vhost;
  81 + std::string port;
40 std::string app; 82 std::string app;
41 std::string stream; 83 std::string stream;
42 private: 84 private:
  85 + std::vector<SrsFFMPEG*> ffmpegs;
  86 +private:
43 st_thread_t tid; 87 st_thread_t tid;
44 bool loop; 88 bool loop;
45 public: 89 public:
46 SrsEncoder(); 90 SrsEncoder();
47 virtual ~SrsEncoder(); 91 virtual ~SrsEncoder();
48 public: 92 public:
49 - virtual int on_publish(std::string vhost, std::string app, std::string stream); 93 + virtual int on_publish(std::string vhost, std::string port, std::string app, std::string stream);
50 virtual void on_unpublish(); 94 virtual void on_unpublish();
51 private: 95 private:
  96 + virtual SrsFFMPEG* at(int index);
  97 + virtual int parse_transcode(SrsConfDirective* conf);
52 virtual int cycle(); 98 virtual int cycle();
53 virtual void encoder_cycle(); 99 virtual void encoder_cycle();
54 static void* encoder_thread(void* arg); 100 static void* encoder_thread(void* arg);
@@ -122,4 +122,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -122,4 +122,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
122 #define ERROR_HLS_AAC_FRAME_LENGTH 605 122 #define ERROR_HLS_AAC_FRAME_LENGTH 605
123 #define ERROR_HLS_AVC_SAMPLE_SIZE 606 123 #define ERROR_HLS_AVC_SAMPLE_SIZE 606
124 124
  125 +#define ERROR_ENCODER_VCODEC 700
  126 +#define ERROR_ENCODER_OUTPUT 701
  127 +#define ERROR_ENCODER_ACHANNELS 702
  128 +#define ERROR_ENCODER_ASAMPLE_RATE 703
  129 +#define ERROR_ENCODER_ABITRATE 704
  130 +#define ERROR_ENCODER_ACODEC 705
  131 +#define ERROR_ENCODER_VPRESET 706
  132 +#define ERROR_ENCODER_VPROFILE 707
  133 +#define ERROR_ENCODER_VTHREADS 708
  134 +#define ERROR_ENCODER_VHEIGHT 709
  135 +#define ERROR_ENCODER_VWIDTH 710
  136 +#define ERROR_ENCODER_VFPS 711
  137 +#define ERROR_ENCODER_VBITRATE 712
  138 +
125 #endif 139 #endif
@@ -688,8 +688,7 @@ int SrsHls::reopen() @@ -688,8 +688,7 @@ int SrsHls::reopen()
688 int ret = ERROR_SUCCESS; 688 int ret = ERROR_SUCCESS;
689 689
690 // try to open the HLS muxer 690 // try to open the HLS muxer
691 - SrsConfDirective* conf = config->get_hls(vhost);  
692 - if (conf && conf->arg0() == "off") { 691 + if (!config->get_hls_enabled(vhost)) {
693 return ret; 692 return ret;
694 } 693 }
695 694
@@ -698,6 +697,7 @@ int SrsHls::reopen() @@ -698,6 +697,7 @@ int SrsHls::reopen()
698 697
699 hls_enabled = true; 698 hls_enabled = true;
700 699
  700 + SrsConfDirective* conf = NULL;
701 hls_path = SRS_CONF_DEFAULT_HLS_PATH; 701 hls_path = SRS_CONF_DEFAULT_HLS_PATH;
702 if ((conf = config->get_hls_path(vhost)) != NULL) { 702 if ((conf = config->get_hls_path(vhost)) != NULL) {
703 hls_path = conf->arg0(); 703 hls_path = conf->arg0();
@@ -612,7 +612,7 @@ int SrsSource::on_video(SrsCommonMessage* video) @@ -612,7 +612,7 @@ int SrsSource::on_video(SrsCommonMessage* video)
612 return ret; 612 return ret;
613 } 613 }
614 614
615 -int SrsSource::on_publish(std::string vhost, std::string app, std::string stream) 615 +int SrsSource::on_publish(std::string vhost, std::string port, std::string app, std::string stream)
616 { 616 {
617 int ret = ERROR_SUCCESS; 617 int ret = ERROR_SUCCESS;
618 618
@@ -625,7 +625,7 @@ int SrsSource::on_publish(std::string vhost, std::string app, std::string stream @@ -625,7 +625,7 @@ int SrsSource::on_publish(std::string vhost, std::string app, std::string stream
625 #endif 625 #endif
626 626
627 #ifdef SRS_FFMPEG 627 #ifdef SRS_FFMPEG
628 - if ((ret = encoder->on_publish(vhost, app, stream)) != ERROR_SUCCESS) { 628 + if ((ret = encoder->on_publish(vhost, port, app, stream)) != ERROR_SUCCESS) {
629 return ret; 629 return ret;
630 } 630 }
631 #endif 631 #endif
@@ -210,7 +210,7 @@ public: @@ -210,7 +210,7 @@ public:
210 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); 210 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
211 virtual int on_audio(SrsCommonMessage* audio); 211 virtual int on_audio(SrsCommonMessage* audio);
212 virtual int on_video(SrsCommonMessage* video); 212 virtual int on_video(SrsCommonMessage* video);
213 - virtual int on_publish(std::string vhost, std::string app, std::string stream); 213 + virtual int on_publish(std::string vhost, std::string port, std::string app, std::string stream);
214 virtual void on_unpublish(); 214 virtual void on_unpublish();
215 public: 215 public:
216 virtual int create_consumer(SrsConsumer*& consumer); 216 virtual int create_consumer(SrsConsumer*& consumer);