@ -33,8 +33,10 @@ using namespace std;
# define SRS_RTMP_ENCODER_COPY "copy"
# define SRS_RTMP_ENCODER_NO_VIDEO "vn"
# define SRS_RTMP_ENCODER_NO_AUDIO "an"
// only support libx264 encoder.
// only support libx264 , libx265 and h264_qsv encoder.
# define SRS_RTMP_ENCODER_VCODEC_LIBX264 "libx264"
# define SRS_RTMP_ENCODER_VCODEC_LIBX265 "libx265"
# define SRS_RTMP_ENCODER_VCODEC_H264QSV "h264_qsv"
# define SRS_RTMP_ENCODER_VCODEC_PNG "png"
// any aac encoder is ok which contains the aac,
// for example, libaacplus, aac, fdkaac
@ -45,7 +47,7 @@ using namespace std;
SrsFFMPEG : : SrsFFMPEG ( std : : string ffmpeg_bin )
{
ffmpeg = ffmpeg_bin ;
vbitrate = 0 ;
vfps = 0 ;
vwidth = 0 ;
@ -54,14 +56,14 @@ SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin)
abitrate = 0 ;
asample_rate = 0 ;
achannels = 0 ;
process = new SrsProcess ( ) ;
}
SrsFFMPEG : : ~ SrsFFMPEG ( )
{
stop ( ) ;
srs_freep ( process ) ;
}
@ -83,18 +85,18 @@ string SrsFFMPEG::output()
srs_error_t SrsFFMPEG : : initialize ( string in , string out , string log )
{
srs_error_t err = srs_success ;
input = in ;
_output = out ;
log_file = log ;
return err ;
}
srs_error_t SrsFFMPEG : : initialize_transcode ( SrsConfDirective * engine )
{
srs_error_t err = srs_success ;
perfile = _srs_config - > get_engine_perfile ( engine ) ;
iformat = _srs_config - > get_engine_iformat ( engine ) ;
vfilter = _srs_config - > get_engine_vfilter ( engine ) ;
@ -113,18 +115,20 @@ srs_error_t SrsFFMPEG::initialize_transcode(SrsConfDirective* engine)
achannels = _srs_config - > get_engine_achannels ( engine ) ;
aparams = _srs_config - > get_engine_aparams ( engine ) ;
oformat = _srs_config - > get_engine_oformat ( engine ) ;
// ensure the size is even.
vwidth - = vwidth % 2 ;
vheight - = vheight % 2 ;
if ( vcodec = = SRS_RTMP_ENCODER_NO_VIDEO & & acodec = = SRS_RTMP_ENCODER_NO_AUDIO ) {
return srs_error_new ( ERROR_ENCODER_VCODEC , " video and audio disabled " ) ;
}
if ( vcodec ! = SRS_RTMP_ENCODER_COPY & & vcodec ! = SRS_RTMP_ENCODER_NO_VIDEO & & vcodec ! = SRS_RTMP_ENCODER_VCODEC_PNG ) {
if ( vcodec ! = SRS_RTMP_ENCODER_VCODEC_LIBX264 ) {
return srs_error_new ( ERROR_ENCODER_VCODEC , " invalid vcodec, must be %s, actual %s " , SRS_RTMP_ENCODER_VCODEC_LIBX264 , vcodec . c_str ( ) ) ;
if ( vcodec ! = SRS_RTMP_ENCODER_VCODEC_LIBX264 & & vcodec ! = SRS_RTMP_ENCODER_VCODEC_LIBX265 & & vcodec ! = SRS_RTMP_ENCODER_VCODEC_H264QSV ) {
return srs_error_new (
ERROR_ENCODER_VCODEC , " invalid vcodec, must be %s, %s or %s, actual %s " ,
SRS_RTMP_ENCODER_VCODEC_LIBX264 , SRS_RTMP_ENCODER_VCODEC_LIBX265 , SRS_RTMP_ENCODER_VCODEC_H264QSV , vcodec . c_str ( ) ) ;
}
if ( vbitrate < 0 ) {
return srs_error_new ( ERROR_ENCODER_VBITRATE , " invalid vbitrate: %d " , vbitrate ) ;
@ -148,14 +152,14 @@ srs_error_t SrsFFMPEG::initialize_transcode(SrsConfDirective* engine)
return srs_error_new ( ERROR_ENCODER_VPRESET , " invalid vpreset: %s " , vpreset . c_str ( ) ) ;
}
}
// @see, https://github.com/ossrs/srs/issues/145
if ( acodec = = SRS_RTMP_ENCODER_LIBAACPLUS & & acodec ! = SRS_RTMP_ENCODER_LIBFDKAAC ) {
if ( abitrate ! = 0 & & ( abitrate < 16 | | abitrate > 72 ) ) {
return srs_error_new ( ERROR_ENCODER_ABITRATE , " invalid abitrate for aac: %d, must in [16, 72] " , abitrate ) ;
}
}
if ( acodec ! = SRS_RTMP_ENCODER_COPY & & acodec ! = SRS_RTMP_ENCODER_NO_AUDIO ) {
if ( abitrate < 0 ) {
return srs_error_new ( ERROR_ENCODER_ABITRATE , " invalid abitrate: %d " , abitrate ) ;
@ -170,47 +174,47 @@ srs_error_t SrsFFMPEG::initialize_transcode(SrsConfDirective* engine)
if ( _output . empty ( ) ) {
return srs_error_new ( ERROR_ENCODER_OUTPUT , " invalid empty output " ) ;
}
// for not rtmp input, donot append the iformat,
// for example, "-f flv" before "-i udp://192.168.1.252:2222"
if ( ! srs_string_starts_with ( input , " rtmp:// " ) ) {
iformat = " " ;
}
return err ;
}
srs_error_t SrsFFMPEG : : initialize_copy ( )
{
srs_error_t err = srs_success ;
vcodec = SRS_RTMP_ENCODER_COPY ;
acodec = SRS_RTMP_ENCODER_COPY ;
if ( _output . empty ( ) ) {
return srs_error_new ( ERROR_ENCODER_OUTPUT , " invalid empty output " ) ;
}
return err ;
}
srs_error_t SrsFFMPEG : : start ( )
{
srs_error_t err = srs_success ;
if ( process - > started ( ) ) {
return err ;
}
// the argv for process.
params . clear ( ) ;
// argv[0], set to ffmpeg bin.
// The execv() and execvp() functions ....
// The first argument, by convention, should point to
// the filename associated with the file being executed.
params . push_back ( ffmpeg ) ;
// input params
for ( int i = 0 ; i < ( int ) iparams . size ( ) ; i + + ) {
string iparam = iparams . at ( i ) ;
@ -218,7 +222,7 @@ srs_error_t SrsFFMPEG::start()
params . push_back ( iparam ) ;
}
}
// build the perfile
if ( ! perfile . empty ( ) ) {
std : : vector < std : : string > : : iterator it ;
@ -229,16 +233,16 @@ srs_error_t SrsFFMPEG::start()
}
}
}
// input.
if ( iformat ! = " off " & & ! iformat . empty ( ) ) {
params . push_back ( " -f " ) ;
params . push_back ( iformat ) ;
}
params . push_back ( " -i " ) ;
params . push_back ( input ) ;
// build the filter
if ( ! vfilter . empty ( ) ) {
std : : vector < std : : string > : : iterator it ;
@ -249,7 +253,7 @@ srs_error_t SrsFFMPEG::start()
}
}
}
// video specified.
if ( vcodec ! = SRS_RTMP_ENCODER_NO_VIDEO ) {
params . push_back ( " -vcodec " ) ;
@ -257,45 +261,45 @@ srs_error_t SrsFFMPEG::start()
} else {
params . push_back ( " -vn " ) ;
}
// the codec params is disabled when copy
if ( vcodec ! = SRS_RTMP_ENCODER_COPY & & vcodec ! = SRS_RTMP_ENCODER_NO_VIDEO ) {
if ( vbitrate > 0 ) {
params . push_back ( " -b:v " ) ;
params . push_back ( srs_int2str ( vbitrate * 1000 ) ) ;
}
if ( vfps > 0 ) {
params . push_back ( " -r " ) ;
params . push_back ( srs_float2str ( vfps ) ) ;
}
if ( vwidth > 0 & & vheight > 0 ) {
params . push_back ( " -s " ) ;
params . push_back ( srs_int2str ( vwidth ) + " x " + srs_int2str ( vheight ) ) ;
}
// TODO: add aspect if needed.
if ( vwidth > 0 & & vheight > 0 ) {
params . push_back ( " -aspect " ) ;
params . push_back ( srs_int2str ( vwidth ) + " : " + srs_int2str ( vheight ) ) ;
}
if ( vthreads > 0 ) {
params . push_back ( " -threads " ) ;
params . push_back ( srs_int2str ( vthreads ) ) ;
}
if ( ! vprofile . empty ( ) ) {
params . push_back ( " -profile:v " ) ;
params . push_back ( vprofile ) ;
}
if ( ! vpreset . empty ( ) ) {
params . push_back ( " -preset " ) ;
params . push_back ( vpreset ) ;
}
// vparams
if ( ! vparams . empty ( ) ) {
std : : vector < std : : string > : : iterator it ;
@ -307,7 +311,7 @@ srs_error_t SrsFFMPEG::start()
}
}
}
// audio specified.
if ( acodec ! = SRS_RTMP_ENCODER_NO_AUDIO ) {
params . push_back ( " -acodec " ) ;
@ -315,7 +319,7 @@ srs_error_t SrsFFMPEG::start()
} else {
params . push_back ( " -an " ) ;
}
// the codec params is disabled when copy
if ( acodec ! = SRS_RTMP_ENCODER_NO_AUDIO ) {
if ( acodec ! = SRS_RTMP_ENCODER_COPY ) {
@ -323,17 +327,17 @@ srs_error_t SrsFFMPEG::start()
params . push_back ( " -b:a " ) ;
params . push_back ( srs_int2str ( abitrate * 1000 ) ) ;
}
if ( asample_rate > 0 ) {
params . push_back ( " -ar " ) ;
params . push_back ( srs_int2str ( asample_rate ) ) ;
}
if ( achannels > 0 ) {
params . push_back ( " -ac " ) ;
params . push_back ( srs_int2str ( achannels ) ) ;
}
// aparams
std : : vector < std : : string > : : iterator it ;
for ( it = aparams . begin ( ) ; it ! = aparams . end ( ) ; + + it ) {
@ -346,7 +350,7 @@ srs_error_t SrsFFMPEG::start()
// for audio copy.
for ( int i = 0 ; i < ( int ) aparams . size ( ) ; ) {
std : : string pn = aparams [ i + + ] ;
// aparams, the adts to asc filter "-bsf:a aac_adtstoasc"
if ( pn = = " -bsf:a " & & i < ( int ) aparams . size ( ) ) {
std : : string pv = aparams [ i + + ] ;
@ -358,16 +362,16 @@ srs_error_t SrsFFMPEG::start()
}
}
}
// output
if ( oformat ! = " off " & & ! oformat . empty ( ) ) {
params . push_back ( " -f " ) ;
params . push_back ( oformat ) ;
}
params . push_back ( " -y " ) ;
params . push_back ( _output ) ;
// when specified the log file.
if ( ! log_file . empty ( ) ) {
// stdout
@ -379,12 +383,12 @@ srs_error_t SrsFFMPEG::start()
params . push_back ( " > " ) ;
params . push_back ( log_file ) ;
}
// initialize the process.
if ( ( err = process - > initialize ( ffmpeg , params ) ) ! = srs_success ) {
return srs_error_wrap ( err , " init process " ) ;
}
return process - > start ( ) ;
}