winlin

support audio transcode only, speex/mp3 to aac

@@ -126,7 +126,7 @@ Supported operating systems and hardware: @@ -126,7 +126,7 @@ Supported operating systems and hardware:
126 16. support live stream transcoding by ffmpeg.<br/> 126 16. support live stream transcoding by ffmpeg.<br/>
127 17. support live stream transcoding by ffmpeg.<br/> 127 17. support live stream transcoding by ffmpeg.<br/>
128 18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/> 128 18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/>
129 -19. [dev] support audio transcode only, speex/mp3 to aac<br/> 129 +19. support audio transcode only, speex/mp3 to aac<br/>
130 20. [plan] support network based cli and json result.<br/> 130 20. [plan] support network based cli and json result.<br/>
131 21. [plan] support http callback api hooks(for authentication).<br/> 131 21. [plan] support http callback api hooks(for authentication).<br/>
132 22. [plan] support bandwidth test api and flash client.<br/> 132 22. [plan] support bandwidth test api and flash client.<br/>
@@ -15,6 +15,7 @@ log_dir ./objs/logs; @@ -15,6 +15,7 @@ log_dir ./objs/logs;
15 # default: 2000 15 # default: 2000
16 max_connections 2000; 16 max_connections 2000;
17 # vhost list, the __defaultVhost__ is the default vhost 17 # vhost list, the __defaultVhost__ is the default vhost
  18 +# for example, user use ip to access the stream: rtmp://192.168.1.2/live/livestream.
18 # for which cannot identify the required vhost. 19 # for which cannot identify the required vhost.
19 # for default demo. 20 # for default demo.
20 vhost __defaultVhost__ { 21 vhost __defaultVhost__ {
@@ -44,7 +45,7 @@ vhost __defaultVhost__ { @@ -44,7 +45,7 @@ vhost __defaultVhost__ {
44 vparams { 45 vparams {
45 } 46 }
46 acodec libaacplus; 47 acodec libaacplus;
47 - abitrate 30; 48 + abitrate 45;
48 asample_rate 44100; 49 asample_rate 44100;
49 achannels 2; 50 achannels 2;
50 aparams { 51 aparams {
@@ -90,7 +91,7 @@ vhost dev { @@ -90,7 +91,7 @@ vhost dev {
90 enabled on; 91 enabled on;
91 ffmpeg ./objs/ffmpeg/bin/ffmpeg; 92 ffmpeg ./objs/ffmpeg/bin/ffmpeg;
92 engine dev { 93 engine dev {
93 - enabled on; 94 + enabled off;
94 vfilter { 95 vfilter {
95 } 96 }
96 vcodec libx264; 97 vcodec libx264;
@@ -104,7 +105,18 @@ vhost dev { @@ -104,7 +105,18 @@ vhost dev {
104 vparams { 105 vparams {
105 } 106 }
106 acodec libaacplus; 107 acodec libaacplus;
107 - abitrate 30; 108 + abitrate 45;
  109 + asample_rate 44100;
  110 + achannels 2;
  111 + aparams {
  112 + }
  113 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
  114 + }
  115 + engine dev_acodec {
  116 + enabled on;
  117 + vcodec copy;
  118 + acodec libaacplus;
  119 + abitrate 45;
108 asample_rate 44100; 120 asample_rate 44100;
109 achannels 2; 121 achannels 2;
110 aparams { 122 aparams {
@@ -134,7 +146,7 @@ vhost mirror.transcode.vhost.com { @@ -134,7 +146,7 @@ vhost mirror.transcode.vhost.com {
134 vparams { 146 vparams {
135 } 147 }
136 acodec libaacplus; 148 acodec libaacplus;
137 - abitrate 30; 149 + abitrate 45;
138 asample_rate 44100; 150 asample_rate 44100;
139 achannels 2; 151 achannels 2;
140 aparams { 152 aparams {
@@ -164,7 +176,7 @@ vhost drawtext.transcode.vhost.com { @@ -164,7 +176,7 @@ vhost drawtext.transcode.vhost.com {
164 vparams { 176 vparams {
165 } 177 }
166 acodec libaacplus; 178 acodec libaacplus;
167 - abitrate 30; 179 + abitrate 45;
168 asample_rate 44100; 180 asample_rate 44100;
169 achannels 2; 181 achannels 2;
170 aparams { 182 aparams {
@@ -194,7 +206,7 @@ vhost crop.transcode.vhost.com { @@ -194,7 +206,7 @@ vhost crop.transcode.vhost.com {
194 vparams { 206 vparams {
195 } 207 }
196 acodec libaacplus; 208 acodec libaacplus;
197 - abitrate 30; 209 + abitrate 45;
198 asample_rate 44100; 210 asample_rate 44100;
199 achannels 2; 211 achannels 2;
200 aparams { 212 aparams {
@@ -224,7 +236,7 @@ vhost logo.transcode.vhost.com { @@ -224,7 +236,7 @@ vhost logo.transcode.vhost.com {
224 vparams { 236 vparams {
225 } 237 }
226 acodec libaacplus; 238 acodec libaacplus;
227 - abitrate 30; 239 + abitrate 45;
228 asample_rate 44100; 240 asample_rate 44100;
229 achannels 2; 241 achannels 2;
230 aparams { 242 aparams {
@@ -233,6 +245,40 @@ vhost logo.transcode.vhost.com { @@ -233,6 +245,40 @@ vhost logo.transcode.vhost.com {
233 } 245 }
234 } 246 }
235 } 247 }
  248 +# audio transcode only.
  249 +# for example, FMLE publish audio codec in mp3, and donot support HLS output,
  250 +# we can transcode the audio to aac and copy video to the new stream with HLS.
  251 +vhost audio.transcode.vhost.com {
  252 + transcode {
  253 + enabled on;
  254 + ffmpeg ./objs/ffmpeg/bin/ffmpeg;
  255 + engine acodec {
  256 + enabled on;
  257 + vcodec copy;
  258 + acodec libaacplus;
  259 + abitrate 45;
  260 + asample_rate 44100;
  261 + achannels 2;
  262 + aparams {
  263 + }
  264 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
  265 + }
  266 + }
  267 +}
  268 +# ffmpeg-copy(forward implements by ffmpeg).
  269 +# copy the video and audio to a new stream.
  270 +vhost copy.transcode.vhost.com {
  271 + transcode {
  272 + enabled on;
  273 + ffmpeg ./objs/ffmpeg/bin/ffmpeg;
  274 + engine copy {
  275 + enabled on;
  276 + vcodec copy;
  277 + acodec copy;
  278 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
  279 + }
  280 + }
  281 +}
236 # transcode all app and stream of vhost 282 # transcode all app and stream of vhost
237 vhost all.transcode.vhost.com { 283 vhost all.transcode.vhost.com {
238 # the streaming transcode configs. 284 # the streaming transcode configs.
@@ -258,7 +304,9 @@ vhost all.transcode.vhost.com { @@ -258,7 +304,9 @@ vhost all.transcode.vhost.com {
258 # for filters, @see: http://ffmpeg.org/ffmpeg-filters.html 304 # for filters, @see: http://ffmpeg.org/ffmpeg-filters.html
259 filter_complex 'overlay=10:10'; 305 filter_complex 'overlay=10:10';
260 } 306 }
261 - # video encoder name 307 + # video encoder name. can be:
  308 + # libx264: use h.264(libx264) video encoder.
  309 + # copy: donot encoder the video stream, copy it.
262 vcodec libx264; 310 vcodec libx264;
263 # video bitrate, in kbps 311 # video bitrate, in kbps
264 vbitrate 1500; 312 vbitrate 1500;
@@ -287,7 +335,9 @@ vhost all.transcode.vhost.com { @@ -287,7 +335,9 @@ vhost all.transcode.vhost.com {
287 bf 3; 335 bf 3;
288 refs 10; 336 refs 10;
289 } 337 }
290 - # audio encoder name 338 + # audio encoder name. can be:
  339 + # libaacplus: use aac(libaacplus) audio encoder.
  340 + # copy: donot encoder the audio stream, copy it.
291 acodec libaacplus; 341 acodec libaacplus;
292 # audio bitrate, in kbps. [16, 72] for libaacplus. 342 # audio bitrate, in kbps. [16, 72] for libaacplus.
293 abitrate 70; 343 abitrate 70;
@@ -362,13 +412,45 @@ vhost all.transcode.vhost.com { @@ -362,13 +412,45 @@ vhost all.transcode.vhost.com {
362 vparams { 412 vparams {
363 } 413 }
364 acodec libaacplus; 414 acodec libaacplus;
365 - abitrate 30; 415 + abitrate 45;
  416 + asample_rate 44100;
  417 + achannels 2;
  418 + aparams {
  419 + }
  420 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
  421 + }
  422 + engine vcopy {
  423 + enabled on;
  424 + vcodec copy;
  425 + acodec libaacplus;
  426 + abitrate 45;
366 asample_rate 44100; 427 asample_rate 44100;
367 achannels 2; 428 achannels 2;
368 aparams { 429 aparams {
369 } 430 }
370 output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; 431 output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
371 } 432 }
  433 + engine acopy {
  434 + enabled on;
  435 + vcodec libx264;
  436 + vbitrate 300;
  437 + vfps 20;
  438 + vwidth 768;
  439 + vheight 320;
  440 + vthreads 2;
  441 + vprofile baseline;
  442 + vpreset superfast;
  443 + vparams {
  444 + }
  445 + acodec copy;
  446 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
  447 + }
  448 + engine copy {
  449 + enabled on;
  450 + vcodec copy;
  451 + acodec copy;
  452 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
  453 + }
372 } 454 }
373 } 455 }
374 # transcode all stream using the empty ffmpeg demo, donothing. 456 # transcode all stream using the empty ffmpeg demo, donothing.
@@ -389,7 +471,7 @@ vhost ffempty.transcode.vhost.com { @@ -389,7 +471,7 @@ vhost ffempty.transcode.vhost.com {
389 vparams { 471 vparams {
390 } 472 }
391 acodec libaacplus; 473 acodec libaacplus;
392 - abitrate 30; 474 + abitrate 45;
393 asample_rate 44100; 475 asample_rate 44100;
394 achannels 2; 476 achannels 2;
395 aparams { 477 aparams {
@@ -42,8 +42,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -42,8 +42,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 42
43 #define SRS_ENCODER_SLEEP_MS 2000 43 #define SRS_ENCODER_SLEEP_MS 2000
44 44
45 -#define SRS_ENCODER_VCODEC "libx264"  
46 -#define SRS_ENCODER_ACODEC "libaacplus" 45 +#define SRS_ENCODER_COPY "copy"
  46 +#define SRS_ENCODER_VCODEC "libx264"
  47 +#define SRS_ENCODER_ACODEC "libaacplus"
47 48
48 // for encoder to detect the dead loop 49 // for encoder to detect the dead loop
49 static std::vector<std::string> _transcoded_url; 50 static std::vector<std::string> _transcoded_url;
@@ -138,70 +139,75 @@ int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine) @@ -138,70 +139,75 @@ int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine)
138 } 139 }
139 _transcoded_url.push_back(output); 140 _transcoded_url.push_back(output);
140 141
141 - if (vcodec != SRS_ENCODER_VCODEC) {  
142 - ret = ERROR_ENCODER_VCODEC;  
143 - srs_error("invalid vcodec, must be %s, actual %s, ret=%d",  
144 - SRS_ENCODER_VCODEC, vcodec.c_str(), ret);  
145 - return ret;  
146 - }  
147 - if (vbitrate <= 0) {  
148 - ret = ERROR_ENCODER_VBITRATE;  
149 - srs_error("invalid vbitrate: %d, ret=%d", vbitrate, ret);  
150 - return ret;  
151 - }  
152 - if (vfps <= 0) {  
153 - ret = ERROR_ENCODER_VFPS;  
154 - srs_error("invalid vfps: %.2f, ret=%d", vfps, ret);  
155 - return ret;  
156 - }  
157 - if (vwidth <= 0) {  
158 - ret = ERROR_ENCODER_VWIDTH;  
159 - srs_error("invalid vwidth: %d, ret=%d", vwidth, ret);  
160 - return ret;  
161 - }  
162 - if (vheight <= 0) {  
163 - ret = ERROR_ENCODER_VHEIGHT;  
164 - srs_error("invalid vheight: %d, ret=%d", vheight, ret);  
165 - return ret;  
166 - }  
167 - if (vthreads < 0) {  
168 - ret = ERROR_ENCODER_VTHREADS;  
169 - srs_error("invalid vthreads: %d, ret=%d", vthreads, ret);  
170 - return ret;  
171 - }  
172 - if (vprofile.empty()) {  
173 - ret = ERROR_ENCODER_VPROFILE;  
174 - srs_error("invalid vprofile: %s, ret=%d", vprofile.c_str(), ret);  
175 - return ret;  
176 - }  
177 - if (vpreset.empty()) {  
178 - ret = ERROR_ENCODER_VPRESET;  
179 - srs_error("invalid vpreset: %s, ret=%d", vpreset.c_str(), ret);  
180 - return ret;  
181 - }  
182 - if (acodec != SRS_ENCODER_ACODEC) {  
183 - ret = ERROR_ENCODER_ACODEC;  
184 - srs_error("invalid acodec, must be %s, actual %s, ret=%d",  
185 - SRS_ENCODER_ACODEC, acodec.c_str(), ret);  
186 - return ret;  
187 - }  
188 - if (abitrate <= 0) {  
189 - ret = ERROR_ENCODER_ABITRATE;  
190 - srs_error("invalid abitrate: %d, ret=%d",  
191 - abitrate, ret);  
192 - return ret;  
193 - }  
194 - if (asample_rate <= 0) {  
195 - ret = ERROR_ENCODER_ASAMPLE_RATE;  
196 - srs_error("invalid sample rate: %d, ret=%d",  
197 - asample_rate, ret);  
198 - return ret; 142 + if (vcodec != SRS_ENCODER_COPY) {
  143 + if (vcodec != SRS_ENCODER_VCODEC) {
  144 + ret = ERROR_ENCODER_VCODEC;
  145 + srs_error("invalid vcodec, must be %s, actual %s, ret=%d",
  146 + SRS_ENCODER_VCODEC, vcodec.c_str(), ret);
  147 + return ret;
  148 + }
  149 + if (vbitrate <= 0) {
  150 + ret = ERROR_ENCODER_VBITRATE;
  151 + srs_error("invalid vbitrate: %d, ret=%d", vbitrate, ret);
  152 + return ret;
  153 + }
  154 + if (vfps <= 0) {
  155 + ret = ERROR_ENCODER_VFPS;
  156 + srs_error("invalid vfps: %.2f, ret=%d", vfps, ret);
  157 + return ret;
  158 + }
  159 + if (vwidth <= 0) {
  160 + ret = ERROR_ENCODER_VWIDTH;
  161 + srs_error("invalid vwidth: %d, ret=%d", vwidth, ret);
  162 + return ret;
  163 + }
  164 + if (vheight <= 0) {
  165 + ret = ERROR_ENCODER_VHEIGHT;
  166 + srs_error("invalid vheight: %d, ret=%d", vheight, ret);
  167 + return ret;
  168 + }
  169 + if (vthreads < 0) {
  170 + ret = ERROR_ENCODER_VTHREADS;
  171 + srs_error("invalid vthreads: %d, ret=%d", vthreads, ret);
  172 + return ret;
  173 + }
  174 + if (vprofile.empty()) {
  175 + ret = ERROR_ENCODER_VPROFILE;
  176 + srs_error("invalid vprofile: %s, ret=%d", vprofile.c_str(), ret);
  177 + return ret;
  178 + }
  179 + if (vpreset.empty()) {
  180 + ret = ERROR_ENCODER_VPRESET;
  181 + srs_error("invalid vpreset: %s, ret=%d", vpreset.c_str(), ret);
  182 + return ret;
  183 + }
199 } 184 }
200 - if (achannels != 1 && achannels != 2) {  
201 - ret = ERROR_ENCODER_ACHANNELS;  
202 - srs_error("invalid achannels, must be 1 or 2, actual %d, ret=%d",  
203 - achannels, ret);  
204 - return ret; 185 +
  186 + if (acodec != SRS_ENCODER_COPY) {
  187 + if (acodec != SRS_ENCODER_ACODEC) {
  188 + ret = ERROR_ENCODER_ACODEC;
  189 + srs_error("invalid acodec, must be %s, actual %s, ret=%d",
  190 + SRS_ENCODER_ACODEC, acodec.c_str(), ret);
  191 + return ret;
  192 + }
  193 + if (abitrate <= 0) {
  194 + ret = ERROR_ENCODER_ABITRATE;
  195 + srs_error("invalid abitrate: %d, ret=%d",
  196 + abitrate, ret);
  197 + return ret;
  198 + }
  199 + if (asample_rate <= 0) {
  200 + ret = ERROR_ENCODER_ASAMPLE_RATE;
  201 + srs_error("invalid sample rate: %d, ret=%d",
  202 + asample_rate, ret);
  203 + return ret;
  204 + }
  205 + if (achannels != 1 && achannels != 2) {
  206 + ret = ERROR_ENCODER_ACHANNELS;
  207 + srs_error("invalid achannels, must be 1 or 2, actual %d, ret=%d",
  208 + achannels, ret);
  209 + return ret;
  210 + }
205 } 211 }
206 if (output.empty()) { 212 if (output.empty()) {
207 ret = ERROR_ENCODER_OUTPUT; 213 ret = ERROR_ENCODER_OUTPUT;
@@ -252,40 +258,43 @@ int SrsFFMPEG::start() @@ -252,40 +258,43 @@ int SrsFFMPEG::start()
252 params.push_back("-vcodec"); 258 params.push_back("-vcodec");
253 params.push_back(vcodec); 259 params.push_back(vcodec);
254 260
255 - params.push_back("-b:v");  
256 - snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000);  
257 - params.push_back(tmp);  
258 -  
259 - params.push_back("-r");  
260 - snprintf(tmp, sizeof(tmp), "%.2f", vfps);  
261 - params.push_back(tmp);  
262 -  
263 - params.push_back("-s");  
264 - snprintf(tmp, sizeof(tmp), "%dx%d", vwidth, vheight);  
265 - params.push_back(tmp);  
266 -  
267 - // TODO: add aspect if needed.  
268 - params.push_back("-aspect");  
269 - snprintf(tmp, sizeof(tmp), "%d:%d", vwidth, vheight);  
270 - params.push_back(tmp);  
271 -  
272 - params.push_back("-threads");  
273 - snprintf(tmp, sizeof(tmp), "%d", vthreads);  
274 - params.push_back(tmp);  
275 -  
276 - params.push_back("-profile:v");  
277 - params.push_back(vprofile);  
278 -  
279 - params.push_back("-preset");  
280 - params.push_back(vpreset);  
281 -  
282 - // vparams  
283 - if (!vparams.empty()) {  
284 - std::vector<std::string>::iterator it;  
285 - for (it = vparams.begin(); it != vparams.end(); ++it) {  
286 - std::string p = *it;  
287 - if (!p.empty()) {  
288 - params.push_back(p); 261 + // the codec params is disabled when copy
  262 + if (vcodec != SRS_ENCODER_COPY) {
  263 + params.push_back("-b:v");
  264 + snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000);
  265 + params.push_back(tmp);
  266 +
  267 + params.push_back("-r");
  268 + snprintf(tmp, sizeof(tmp), "%.2f", vfps);
  269 + params.push_back(tmp);
  270 +
  271 + params.push_back("-s");
  272 + snprintf(tmp, sizeof(tmp), "%dx%d", vwidth, vheight);
  273 + params.push_back(tmp);
  274 +
  275 + // TODO: add aspect if needed.
  276 + params.push_back("-aspect");
  277 + snprintf(tmp, sizeof(tmp), "%d:%d", vwidth, vheight);
  278 + params.push_back(tmp);
  279 +
  280 + params.push_back("-threads");
  281 + snprintf(tmp, sizeof(tmp), "%d", vthreads);
  282 + params.push_back(tmp);
  283 +
  284 + params.push_back("-profile:v");
  285 + params.push_back(vprofile);
  286 +
  287 + params.push_back("-preset");
  288 + params.push_back(vpreset);
  289 +
  290 + // vparams
  291 + if (!vparams.empty()) {
  292 + std::vector<std::string>::iterator it;
  293 + for (it = vparams.begin(); it != vparams.end(); ++it) {
  294 + std::string p = *it;
  295 + if (!p.empty()) {
  296 + params.push_back(p);
  297 + }
289 } 298 }
290 } 299 }
291 } 300 }
@@ -294,25 +303,28 @@ int SrsFFMPEG::start() @@ -294,25 +303,28 @@ int SrsFFMPEG::start()
294 params.push_back("-acodec"); 303 params.push_back("-acodec");
295 params.push_back(acodec); 304 params.push_back(acodec);
296 305
297 - params.push_back("-b:a");  
298 - snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000);  
299 - params.push_back(tmp);  
300 -  
301 - params.push_back("-ar");  
302 - snprintf(tmp, sizeof(tmp), "%d", asample_rate);  
303 - params.push_back(tmp);  
304 -  
305 - params.push_back("-ac");  
306 - snprintf(tmp, sizeof(tmp), "%d", achannels);  
307 - params.push_back(tmp);  
308 -  
309 - // aparams  
310 - if (!aparams.empty()) {  
311 - std::vector<std::string>::iterator it;  
312 - for (it = aparams.begin(); it != aparams.end(); ++it) {  
313 - std::string p = *it;  
314 - if (!p.empty()) {  
315 - params.push_back(p); 306 + // the codec params is disabled when copy
  307 + if (acodec != SRS_ENCODER_COPY) {
  308 + params.push_back("-b:a");
  309 + snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000);
  310 + params.push_back(tmp);
  311 +
  312 + params.push_back("-ar");
  313 + snprintf(tmp, sizeof(tmp), "%d", asample_rate);
  314 + params.push_back(tmp);
  315 +
  316 + params.push_back("-ac");
  317 + snprintf(tmp, sizeof(tmp), "%d", achannels);
  318 + params.push_back(tmp);
  319 +
  320 + // aparams
  321 + if (!aparams.empty()) {
  322 + std::vector<std::string>::iterator it;
  323 + for (it = aparams.begin(); it != aparams.end(); ++it) {
  324 + std::string p = *it;
  325 + if (!p.empty()) {
  326 + params.push_back(p);
  327 + }
316 } 328 }
317 } 329 }
318 } 330 }