From 3b09f9bea9dad201b28be9be9bc5af775cbed202 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 6 Dec 2013 14:35:03 +0800 Subject: [PATCH] support audio transcode only, speex/mp3 to aac --- README.md | 2 +- trunk/conf/srs.conf | 104 ++++++++++-- trunk/src/core/srs_core_encoder.cpp | 248 +++++++++++++++------------- 3 files changed, 224 insertions(+), 130 deletions(-) diff --git a/README.md b/README.md index c2af1518b..374ee7a72 100755 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Supported operating systems and hardware: 16. support live stream transcoding by ffmpeg.
17. support live stream transcoding by ffmpeg.
18. support ffmpeg filters(logo/overlay/crop), x264 params.
-19. [dev] support audio transcode only, speex/mp3 to aac
+19. support audio transcode only, speex/mp3 to aac
20. [plan] support network based cli and json result.
21. [plan] support http callback api hooks(for authentication).
22. [plan] support bandwidth test api and flash client.
diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index 94c385c67..5d6864bc9 100755 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -15,6 +15,7 @@ log_dir ./objs/logs; # default: 2000 max_connections 2000; # vhost list, the __defaultVhost__ is the default vhost +# for example, user use ip to access the stream: rtmp://192.168.1.2/live/livestream. # for which cannot identify the required vhost. # for default demo. vhost __defaultVhost__ { @@ -44,7 +45,7 @@ vhost __defaultVhost__ { vparams { } acodec libaacplus; - abitrate 30; + abitrate 45; asample_rate 44100; achannels 2; aparams { @@ -90,7 +91,7 @@ vhost dev { enabled on; ffmpeg ./objs/ffmpeg/bin/ffmpeg; engine dev { - enabled on; + enabled off; vfilter { } vcodec libx264; @@ -104,7 +105,18 @@ vhost dev { vparams { } acodec libaacplus; - abitrate 30; + abitrate 45; + asample_rate 44100; + achannels 2; + aparams { + } + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; + } + engine dev_acodec { + enabled on; + vcodec copy; + acodec libaacplus; + abitrate 45; asample_rate 44100; achannels 2; aparams { @@ -134,7 +146,7 @@ vhost mirror.transcode.vhost.com { vparams { } acodec libaacplus; - abitrate 30; + abitrate 45; asample_rate 44100; achannels 2; aparams { @@ -164,7 +176,7 @@ vhost drawtext.transcode.vhost.com { vparams { } acodec libaacplus; - abitrate 30; + abitrate 45; asample_rate 44100; achannels 2; aparams { @@ -194,7 +206,7 @@ vhost crop.transcode.vhost.com { vparams { } acodec libaacplus; - abitrate 30; + abitrate 45; asample_rate 44100; achannels 2; aparams { @@ -224,7 +236,7 @@ vhost logo.transcode.vhost.com { vparams { } acodec libaacplus; - abitrate 30; + abitrate 45; asample_rate 44100; achannels 2; aparams { @@ -233,6 +245,40 @@ vhost logo.transcode.vhost.com { } } } +# audio transcode only. +# for example, FMLE publish audio codec in mp3, and donot support HLS output, +# we can transcode the audio to aac and copy video to the new stream with HLS. +vhost audio.transcode.vhost.com { + transcode { + enabled on; + ffmpeg ./objs/ffmpeg/bin/ffmpeg; + engine acodec { + enabled on; + vcodec copy; + acodec libaacplus; + abitrate 45; + asample_rate 44100; + achannels 2; + aparams { + } + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; + } + } +} +# ffmpeg-copy(forward implements by ffmpeg). +# copy the video and audio to a new stream. +vhost copy.transcode.vhost.com { + transcode { + enabled on; + ffmpeg ./objs/ffmpeg/bin/ffmpeg; + engine copy { + enabled on; + vcodec copy; + acodec copy; + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; + } + } +} # transcode all app and stream of vhost vhost all.transcode.vhost.com { # the streaming transcode configs. @@ -258,7 +304,9 @@ vhost all.transcode.vhost.com { # for filters, @see: http://ffmpeg.org/ffmpeg-filters.html filter_complex 'overlay=10:10'; } - # video encoder name + # video encoder name. can be: + # libx264: use h.264(libx264) video encoder. + # copy: donot encoder the video stream, copy it. vcodec libx264; # video bitrate, in kbps vbitrate 1500; @@ -287,7 +335,9 @@ vhost all.transcode.vhost.com { bf 3; refs 10; } - # audio encoder name + # audio encoder name. can be: + # libaacplus: use aac(libaacplus) audio encoder. + # copy: donot encoder the audio stream, copy it. acodec libaacplus; # audio bitrate, in kbps. [16, 72] for libaacplus. abitrate 70; @@ -362,13 +412,45 @@ vhost all.transcode.vhost.com { vparams { } acodec libaacplus; - abitrate 30; + abitrate 45; asample_rate 44100; achannels 2; aparams { } output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; } + engine vcopy { + enabled on; + vcodec copy; + acodec libaacplus; + abitrate 45; + asample_rate 44100; + achannels 2; + aparams { + } + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; + } + engine acopy { + enabled on; + vcodec libx264; + vbitrate 300; + vfps 20; + vwidth 768; + vheight 320; + vthreads 2; + vprofile baseline; + vpreset superfast; + vparams { + } + acodec copy; + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; + } + engine copy { + enabled on; + vcodec copy; + acodec copy; + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; + } } } # transcode all stream using the empty ffmpeg demo, donothing. @@ -389,7 +471,7 @@ vhost ffempty.transcode.vhost.com { vparams { } acodec libaacplus; - abitrate 30; + abitrate 45; asample_rate 44100; achannels 2; aparams { diff --git a/trunk/src/core/srs_core_encoder.cpp b/trunk/src/core/srs_core_encoder.cpp index d0be700dd..3400948a5 100644 --- a/trunk/src/core/srs_core_encoder.cpp +++ b/trunk/src/core/srs_core_encoder.cpp @@ -42,8 +42,9 @@ 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" +#define SRS_ENCODER_COPY "copy" +#define SRS_ENCODER_VCODEC "libx264" +#define SRS_ENCODER_ACODEC "libaacplus" // for encoder to detect the dead loop static std::vector _transcoded_url; @@ -138,70 +139,75 @@ int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine) } _transcoded_url.push_back(output); - 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 (vcodec != SRS_ENCODER_COPY) { + 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 (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 (acodec != SRS_ENCODER_COPY) { + 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; @@ -252,40 +258,43 @@ int SrsFFMPEG::start() params.push_back("-vcodec"); params.push_back(vcodec); - params.push_back("-b:v"); - snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000); - params.push_back(tmp); - - params.push_back("-r"); - snprintf(tmp, sizeof(tmp), "%.2f", vfps); - params.push_back(tmp); - - params.push_back("-s"); - snprintf(tmp, sizeof(tmp), "%dx%d", vwidth, vheight); - params.push_back(tmp); - - // TODO: add aspect if needed. - params.push_back("-aspect"); - snprintf(tmp, sizeof(tmp), "%d:%d", vwidth, vheight); - params.push_back(tmp); - - params.push_back("-threads"); - snprintf(tmp, sizeof(tmp), "%d", vthreads); - params.push_back(tmp); - - params.push_back("-profile:v"); - params.push_back(vprofile); - - params.push_back("-preset"); - params.push_back(vpreset); - - // vparams - if (!vparams.empty()) { - std::vector::iterator it; - for (it = vparams.begin(); it != vparams.end(); ++it) { - std::string p = *it; - if (!p.empty()) { - params.push_back(p); + // the codec params is disabled when copy + if (vcodec != SRS_ENCODER_COPY) { + params.push_back("-b:v"); + snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000); + params.push_back(tmp); + + params.push_back("-r"); + snprintf(tmp, sizeof(tmp), "%.2f", vfps); + params.push_back(tmp); + + params.push_back("-s"); + snprintf(tmp, sizeof(tmp), "%dx%d", vwidth, vheight); + params.push_back(tmp); + + // TODO: add aspect if needed. + params.push_back("-aspect"); + snprintf(tmp, sizeof(tmp), "%d:%d", vwidth, vheight); + params.push_back(tmp); + + params.push_back("-threads"); + snprintf(tmp, sizeof(tmp), "%d", vthreads); + params.push_back(tmp); + + params.push_back("-profile:v"); + params.push_back(vprofile); + + params.push_back("-preset"); + params.push_back(vpreset); + + // vparams + if (!vparams.empty()) { + std::vector::iterator it; + for (it = vparams.begin(); it != vparams.end(); ++it) { + std::string p = *it; + if (!p.empty()) { + params.push_back(p); + } } } } @@ -294,25 +303,28 @@ int SrsFFMPEG::start() params.push_back("-acodec"); params.push_back(acodec); - params.push_back("-b:a"); - snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000); - params.push_back(tmp); - - params.push_back("-ar"); - snprintf(tmp, sizeof(tmp), "%d", asample_rate); - params.push_back(tmp); - - params.push_back("-ac"); - snprintf(tmp, sizeof(tmp), "%d", achannels); - params.push_back(tmp); - - // aparams - if (!aparams.empty()) { - std::vector::iterator it; - for (it = aparams.begin(); it != aparams.end(); ++it) { - std::string p = *it; - if (!p.empty()) { - params.push_back(p); + // the codec params is disabled when copy + if (acodec != SRS_ENCODER_COPY) { + params.push_back("-b:a"); + snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000); + params.push_back(tmp); + + params.push_back("-ar"); + snprintf(tmp, sizeof(tmp), "%d", asample_rate); + params.push_back(tmp); + + params.push_back("-ac"); + snprintf(tmp, sizeof(tmp), "%d", achannels); + params.push_back(tmp); + + // aparams + if (!aparams.empty()) { + std::vector::iterator it; + for (it = aparams.begin(); it != aparams.end(); ++it) { + std::string p = *it; + if (!p.empty()) { + params.push_back(p); + } } } }