@ -1,4 +1,3 @@
/**
* The MIT License ( MIT )
*
@ -22,12 +21,11 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*/
# include <srs_kernel_codec.hpp>
# include <srs_kernel_error.hpp>
# include <srs_app_rtc_codec.hpp>
static const int kFrameBufMax = 40960 ;
static const int kPacketBufMax = 8192 ;
# include <srs_kernel_codec.hpp>
# include <srs_kernel_error.hpp>
# include <srs_kernel_log.hpp>
static const char * id2codec_name ( SrsAudioCodecId id )
{
@ -41,506 +39,379 @@ static const char* id2codec_name(SrsAudioCodecId id)
}
}
SrsAudioDecoder : : SrsAudioDecoder ( SrsAudioCodecId codec )
: codec_id_ ( codec )
SrsAudioTranscoder : : SrsAudioTranscoder ( )
{
frame_ = NULL ;
packet_ = NULL ;
codec_ctx_ = NULL ;
dec_ = NULL ;
dec_frame_ = NULL ;
dec_packet_ = NULL ;
enc_ = NULL ;
enc_frame_ = NULL ;
enc_packet_ = NULL ;
swr_ = NULL ;
swr_data_ = NULL ;
fifo_ = NULL ;
new_pkt_pts_ = AV_NOPTS_VALUE ;
next_out_pts_ = AV_NOPTS_VALUE ;
}
SrsAudioDecoder : : ~ SrsAudioDecoder ( )
SrsAudio Transcoder: : ~ SrsAudioTrans coder( )
{
if ( codec_ctx_ ) {
avcodec_free_context ( & codec_ctx_ ) ;
codec_ctx_ = NULL ;
}
if ( frame_ ) {
av_frame_free ( & frame_ ) ;
frame_ = NULL ;
}
if ( packet_ ) {
av_packet_free ( & packet_ ) ;
packet_ = NULL ;
}
if ( dec_ ) {
avcodec_free_context ( & dec_ ) ;
}
srs_error_t SrsAudioDecoder : : initialize ( )
{
srs_error_t err = srs_success ;
//check codec name,only support "aac","opus"
if ( codec_id_ ! = SrsAudioCodecIdAAC & & codec_id_ ! = SrsAudioCodecIdOpus ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Invalid codec name %d " , codec_id_ ) ;
if ( dec_frame_ ) {
av_frame_free ( & dec_frame_ ) ;
}
const char * codec_name = id2codec_name ( codec_id_ ) ;
const AVCodec * codec = avcodec_find_decoder_by_name ( codec_name ) ;
if ( ! codec ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Codec not found by name %d(%s) " , codec_id_, codec_name) ;
if ( dec_packet_ ) {
av_packet_free ( & dec_packet_ ) ;
}
codec_ctx_ = avcodec_alloc_context3 ( codec ) ;
if ( ! codec_ctx_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio codec context " ) ;
if ( swr_ ) {
swr_free ( & swr_ ) ;
}
if ( avcodec_open2 ( codec_ctx_ , codec , NULL ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not open codec " ) ;
free_swr_samples ( ) ;
if ( enc_ ) {
avcodec_free_context ( & enc_ ) ;
}
frame_ = av_frame_alloc ( ) ;
if ( ! frame_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio frame " ) ;
if ( enc_frame_ ) {
av_frame_free ( & enc_frame_ ) ;
}
packet_ = av_packet_alloc ( ) ;
if ( ! packet_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio packet " ) ;
if ( enc_packet_ ) {
av_packet_free ( & enc_packet_ ) ;
}
return err ;
if ( fifo_ ) {
av_audio_fifo_free ( fifo_ ) ;
fifo_ = NULL ;
}
}
srs_error_t SrsAudioDecoder : : decode ( SrsSample * pkt , char * buf , int & size )
srs_error_t SrsAudio Transcoder: : initialize ( SrsAudioCodecId src_codec , SrsAudioCodecId dst_codec , int dst_channels , int dst_samplerate , int dst_bit_rat e)
{
srs_error_t err = srs_success ;
packet_ - > data = ( uint8_t * ) pkt - > bytes ;
packet_ - > size = pkt - > size ;
if ( ( err = init_dec ( src_codec ) ) ! = srs_success ) {
return srs_error_wrap ( err , " dec init codec:%d " , src_codec ) ;
}
int ret = avcodec_send_packet ( codec_ctx_ , packet_ ) ;
if ( ret < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Error submitting the packet to the decoder " ) ;
if ( ( err = init_enc ( dst_codec , dst_channels , dst_samplerate , dst_bit_rate ) ) ! = srs_success ) {
return srs_error_wrap ( err , " enc init codec:%d, channels:%d, samplerate:%d, bitrate:%d " ,
dst_codec , dst_channels , dst_samplerate , dst_bit_rate ) ;
}
int max = size ;
size = 0 ;
if ( ( err = init_fifo ( ) ) ! = srs_success ) {
return srs_error_wrap ( err , " fifo init " ) ;
}
while ( ret > = 0 ) {
ret = avcodec_receive_frame ( codec_ctx_ , frame_ ) ;
if ( ret = = AVERROR ( EAGAIN ) | | ret = = AVERROR_EOF ) {
return err ;
} else if ( ret < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Error during decoding " ) ;
}
int pcm_size = av_get_bytes_per_sample ( codec_ctx_ - > sample_fmt ) ;
if ( pcm_size < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Failed to calculate data size " ) ;
}
srs_error_t SrsAudioTranscoder : : transcode ( SrsAudioFrame * in_pkt , std : : vector < SrsAudioFrame * > & out_pkts )
{
srs_error_t err = srs_success ;
// @see https://github.com/ossrs/srs/pull/2011/files
for ( int i = 0 ; i < codec_ctx_ - > channels ; i + + ) {
if ( size + pcm_size * frame_ - > nb_samples < = max ) {
memcpy ( buf + size , frame_ - > data [ i ] , pcm_size * frame_ - > nb_samples ) ;
size + = pcm_size * frame_ - > nb_samples ;
}
if ( ( err = decode_and_resample ( in_pkt ) ) ! = srs_success ) {
return srs_error_wrap ( err , " decode and resample " ) ;
}
if ( ( err = encode ( out_pkts ) ) ! = srs_success ) {
return srs_error_wrap ( err , " encode " ) ;
}
return err ;
}
AVCodecContext * SrsAudioDecoder : : codec_ctx ( )
void SrsAudioTranscoder : : free_frames ( std : : vector < SrsAudioFrame * > & frames )
{
return codec_ctx_ ;
for ( std : : vector < SrsAudioFrame * > : : iterator it = frames . begin ( ) ; it ! = frames . end ( ) ; + + it ) {
SrsAudioFrame * p = * it ;
for ( int i = 0 ; i < p - > nb_samples ; i + + ) {
char * pa = p - > samples [ i ] . bytes ;
srs_freepa ( pa ) ;
}
SrsAudioEncoder : : SrsAudioEncoder ( SrsAudioCodecId codec , int samplerate , int channels )
: channels_ ( channels ) ,
sampling_rate_ ( samplerate ) ,
codec_id_ ( codec ) ,
want_bytes_ ( 0 )
srs_freep ( p ) ;
}
}
void SrsAudioTranscoder : : aac_codec_header ( uint8_t * * data , int * len )
{
codec_ctx_ = NULL ;
//srs_assert(dst_codec == SrsAudioCodecIdAAC);
* len = enc_ - > extradata_size ;
* data = enc_ - > extradata ;
}
SrsAudioEncoder: : ~ SrsAudioEncoder ( )
srs_error_t SrsAudioTranscoder : : init_dec ( SrsAudioCodecId src_codec )
{
if ( codec_ctx_ ) {
avcodec_free_context ( & codec_ctx_ ) ;
const char * codec_name = id2codec_name ( src_codec ) ;
const AVCodec * codec = avcodec_find_decoder_by_name ( codec_name ) ;
if ( ! codec ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Codec not found by name(%d,%s) " , src_codec, codec_name) ;
}
if ( frame_ ) {
av_frame_free ( & frame_ ) ;
dec_ = avcodec_alloc_context3 ( codec ) ;
if ( ! dec_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio codec context " ) ;
}
if ( avcodec_open2 ( dec_ , codec , NULL ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not open codec " ) ;
}
srs_error_t SrsAudioEncoder : : initialize ( )
{
srs_error_t err = srs_success ;
dec_frame_ = av_frame_alloc ( ) ;
if ( ! dec_frame_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio decode out frame " ) ;
}
if ( codec_id_ ! = SrsAudioCodecIdAAC & & codec_id_ ! = SrsAudioCodecIdOpus ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Invalid codec name %d " , codec_id_ ) ;
dec_packet_ = av_packet_alloc ( ) ;
if ( ! dec_packet_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio decode in packet " ) ;
}
frame_ = av_frame_alloc ( ) ;
if ( ! frame_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio frame " ) ;
new_pkt_pts_ = AV_NOPTS_VALUE ;
return srs_success ;
}
const char * codec_name = id2codec_name ( codec_id_ ) ;
srs_error_t SrsAudioTranscoder : : init_enc ( SrsAudioCodecId dst_codec , int dst_channels , int dst_samplerate , int dst_bit_rate )
{
const char * codec_name = id2codec_name ( dst_codec ) ;
const AVCodec * codec = avcodec_find_encoder_by_name ( codec_name ) ;
if ( ! codec ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Codec not found by name %d(%s)" , codec_id_ , codec_name);
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Codec not found by name (%d,%s)" , dst_codec , codec_name);
}
codec_ctx _ = avcodec_alloc_context3 ( codec ) ;
if ( ! codec_ctx _) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio codec context " );
enc _ = avcodec_alloc_context3 ( codec ) ;
if ( ! enc _) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio codec context (%d,%s)" , dst_codec, codec_name );
}
codec_ctx_ - > sample_rate = sampling_rate_ ;
codec_ctx_ - > channels = channels_ ;
codec_ctx_ - > channel_layout = av_get_default_channel_layout ( channels_ ) ;
codec_ctx_ - > bit_rate = 48000 ;
if ( codec_id_ = = SrsAudioCodecIdOpus ) {
codec_ctx_ - > sample_fmt = AV_SAMPLE_FMT_S16 ;
enc_ - > sample_rate = dst_samplerate ;
enc_ - > channels = dst_channels ;
enc_ - > channel_layout = av_get_default_channel_layout ( dst_channels ) ;
enc_ - > bit_rate = dst_bit_rate ;
enc_ - > sample_fmt = codec - > sample_fmts [ 0 ] ;
enc_ - > time_base . num = 1 ; enc_ - > time_base . den = 1000 ; // {1, 1000}
if ( dst_codec = = SrsAudioCodecIdOpus ) {
//TODO: for more level setting
codec_ctx _- > compression_level = 1 ;
} else if ( codec_id_ = = SrsAudioCodecIdAAC ) {
codec_ctx_- > sample_fmt = AV_SAMPLE_FMT_FLTP ;
enc _- > compression_level = 1 ;
} else if ( dst_ codec = = SrsAudioCodecIdAAC ) {
enc_- > strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL ;
}
// TODO: FIXME: Show detail error.
if ( avcodec_open2 ( codec_ctx _, codec , NULL ) < 0 ) {
if ( avcodec_open2 ( enc _, codec , NULL ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not open codec " ) ;
}
want_bytes_ = codec_ctx_ - > channels * codec_ctx_ - > frame_size * av_get_bytes_per_sample ( codec_ctx_ - > sample_fmt ) ;
enc_frame_ = av_frame_alloc ( ) ;
if ( ! enc_frame_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio encode in frame " ) ;
}
frame_ - > format = codec_ctx_ - > sample_fmt ;
frame_ - > nb_samples = codec_ctx_ - > frame_size ;
frame_- > channel_layout = codec_ctx _- > channel_layout ;
enc_ frame_- > format = enc _- > sample_fmt ;
enc_ frame_- > nb_samples = enc _- > frame_size ;
enc_ frame_- > channel_layout = enc _- > channel_layout ;
if ( av_frame_get_buffer ( frame_, 0 ) < 0 ) {
if ( av_frame_get_buffer ( enc_ frame_, 0 ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not get audio frame buffer " ) ;
}
return err ;
enc_packet_ = av_packet_alloc ( ) ;
if ( ! enc_packet_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate audio encode out packet " ) ;
}
int SrsAudioEncoder : : want_bytes ( )
{
return want_bytes_ ;
next_out_pts_ = AV_NOPTS_VALUE ;
return srs_success ;
}
srs_error_t SrsAudio Encoder: : encode ( SrsSample * frame , char * buf , int & size )
srs_error_t SrsAudio Transcoder: : init_swr ( AVCodecContext * decoder )
{
srs_error_t err = srs_success ;
if ( want_bytes_ > 0 & & frame - > size ! = want_bytes_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " invalid frame size %d, should be %d " , frame - > size , want_bytes_ ) ;
}
// TODO: Directly use frame?
memcpy ( frame_ - > data [ 0 ] , frame - > bytes , frame - > size ) ;
/* send the frame for encoding */
int r0 = avcodec_send_frame ( codec_ctx_ , frame_ ) ;
if ( r0 < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Error sending the frame to the encoder, %d " , r0 ) ;
swr_ = swr_alloc_set_opts ( NULL , enc_ - > channel_layout , enc_ - > sample_fmt , enc_ - > sample_rate ,
decoder - > channel_layout , decoder - > sample_fmt , decoder - > sample_rate , 0 , NULL ) ;
if ( ! swr_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " alloc swr " ) ;
}
AVPacket pkt ;
av_init_packet ( & pkt ) ;
pkt . data = NULL ;
pkt . size = 0 ;
/* read all the available output packets (in general there may be any
* number of them */
size = 0 ;
while ( r0 > = 0 ) {
r0 = avcodec_receive_packet ( codec_ctx_ , & pkt ) ;
if ( r0 = = AVERROR ( EAGAIN ) | | r0 = = AVERROR_EOF ) {
break ;
} else if ( r0 < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Error during decoding %d " , r0 ) ;
int error ;
char err_buf [ AV_ERROR_MAX_STRING_SIZE ] = { 0 } ;
if ( ( error = swr_init ( swr_ ) ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " open swr(%d:%s) " , error ,
av_make_error_string ( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
//TODO: fit encoder out more pkt
memcpy ( buf , pkt . data , pkt . size ) ;
size = pkt . size ;
av_packet_unref ( & pkt ) ;
// TODO: FIXME: Refine api, got more than one packets.
/* Allocate as many pointers as there are audio channels.
* Each pointer will later point to the audio samples of the corresponding
* channels ( although it may be NULL for interleaved formats ) .
*/
if ( ! ( swr_data_ = ( uint8_t * * ) calloc ( enc_ - > channels , sizeof ( * swr_data_ ) ) ) ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " alloc swr buffer " ) ;
}
return err ;
/* Allocate memory for the samples of all channels in one consecutive
* block for convenience . */
if ( ( error = av_samples_alloc ( swr_data_ , NULL , enc_ - > channels , enc_ - > frame_size , enc_ - > sample_fmt , 0 ) ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " alloc swr buffer(%d:%s) " , error ,
av_make_error_string ( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
AVCodecContext * SrsAudioEncoder : : codec_ctx ( )
{
return codec_ctx_ ;
}
SrsAudioResample : : SrsAudioResample ( int src_rate , int src_layout , enum AVSampleFormat src_fmt ,
int src_nb , int dst_rate , int dst_layout , AVSampleFormat dst_fmt )
: src_rate_ ( src_rate ) ,
src_ch_layout_ ( src_layout ) ,
src_sample_fmt_ ( src_fmt ) ,
src_nb_samples_ ( src_nb ) ,
dst_rate_ ( dst_rate ) ,
dst_ch_layout_ ( dst_layout ) ,
dst_sample_fmt_ ( dst_fmt )
{
src_nb_channels_ = 0 ;
dst_nb_channels_ = 0 ;
src_linesize_ = 0 ;
dst_linesize_ = 0 ;
dst_nb_samples_ = 0 ;
src_data_ = NULL ;
dst_data_ = 0 ;
max_dst_nb_samples_ = 0 ;
swr_ctx_ = NULL ;
return srs_success ;
}
SrsAudioResample: : ~ SrsAudioResample ( )
srs_error_t SrsAudioTranscoder : : init_fifo ( )
{
if ( src_data_ ) {
av_freep ( & src_data_ [ 0 ] ) ;
av_freep ( & src_data_ ) ;
src_data_ = NULL ;
}
if ( dst_data_ ) {
av_freep ( & dst_data_ [ 0 ] ) ;
av_freep ( & dst_data_ ) ;
dst_data_ = NULL ;
}
if ( swr_ctx_ ) {
swr_free ( & swr_ctx_ ) ;
swr_ctx_ = NULL ;
if ( ! ( fifo_ = av_audio_fifo_alloc ( enc_ - > sample_fmt , enc_ - > channels , 1 ) ) ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate FIFO " ) ;
}
return srs_success ;
}
srs_error_t SrsAudio Resample: : initialize ( )
srs_error_t SrsAudioTranscoder : : decode_and_resample ( SrsAudioFrame * pkt )
{
srs_error_t err = srs_success ;
swr_ctx_ = swr_alloc ( ) ;
if ( ! swr_ctx_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate resampler context " ) ;
}
av_opt_set_int ( swr_ctx_ , " in_channel_layout " , src_ch_layout_ , 0 ) ;
av_opt_set_int ( swr_ctx_ , " in_sample_rate " , src_rate_ , 0 ) ;
av_opt_set_sample_fmt ( swr_ctx_ , " in_sample_fmt " , src_sample_fmt_ , 0 ) ;
dec_packet_ - > data = ( uint8_t * ) pkt - > samples [ 0 ] . bytes ;
dec_packet_ - > size = pkt - > samples [ 0 ] . size ;
av_opt_set_int ( swr_ctx_ , " out_channel_layout " , dst_ch_layout_ , 0 ) ;
av_opt_set_int ( swr_ctx_ , " out_sample_rate " , dst_rate_ , 0 ) ;
av_opt_set_sample_fmt ( swr_ctx_ , " out_sample_fmt " , dst_sample_fmt_ , 0 ) ;
char err_buf [ AV_ERROR_MAX_STRING_SIZE ] = { 0 } ;
int ret ;
if ( ( ret = swr_init ( swr_ctx_ ) ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Failed to initialize the resampling context " ) ;
}
src_nb_channels_ = av_get_channel_layout_nb_channels ( src_ch_layout_ ) ;
ret = av_samples_alloc_array_and_samples ( & src_data_ , & src_linesize_ , src_nb_channels_ ,
src_nb_samples_ , src_sample_fmt_ , 0 ) ;
if ( ret < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate source samples " ) ;
}
max_dst_nb_samples_ = dst_nb_samples_ =
av_rescale_rnd ( src_nb_samples_ , dst_rate_ , src_rate_ , AV_ROUND_UP ) ;
dst_nb_channels_ = av_get_channel_layout_nb_channels ( dst_ch_layout_ ) ;
ret = av_samples_alloc_array_and_samples ( & dst_data_ , & dst_linesize_ , dst_nb_channels_ ,
dst_nb_samples_ , dst_sample_fmt_ , 0 ) ;
if ( ret < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not allocate destination samples " ) ;
int error = avcodec_send_packet ( dec_ , dec_packet_ ) ;
if ( error < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " submit to dec(%d,%s) " , error ,
av_make_error_string ( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
new_pkt_pts_ = pkt - > dts + pkt - > cts ;
while ( error > = 0 ) {
error = avcodec_receive_frame ( dec_ , dec_frame_ ) ;
if ( error = = AVERROR ( EAGAIN ) | | error = = AVERROR_EOF ) {
return err ;
} else if ( error < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Error during decoding(%d,%s) " , error ,
av_make_error_string ( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
srs_error_t SrsAudioResample : : resample ( SrsSample * pcm , char * buf , int & size )
{
srs_error_t err = srs_success ;
int ret , plane = 1 ;
if ( src_sample_fmt_ = = AV_SAMPLE_FMT_FLTP ) {
plane = 2 ;
// Decoder is OK now, try to init swr if not initialized.
if ( ! swr_ & & ( err = init_swr ( dec_ ) ) ! = srs_success ) {
return srs_error_wrap ( err , " resample init " ) ;
}
if ( src_linesize_ * plane < pcm - > size | | pcm - > size < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " size not ok " ) ;
}
memcpy ( src_data_ [ 0 ] , pcm - > bytes , pcm - > size ) ;
dst_nb_samples_ = av_rescale_rnd ( swr_get_delay ( swr_ctx_ , src_rate_ ) +
src_nb_samples_ , dst_rate_ , src_rate_ , AV_ROUND_UP ) ;
if ( dst_nb_samples_ > max_dst_nb_samples_ ) {
av_freep ( & dst_data_ [ 0 ] ) ;
ret = av_samples_alloc ( dst_data_ , & dst_linesize_ , dst_nb_channels_ ,
dst_nb_samples_ , dst_sample_fmt_ , 1 ) ;
if ( ret < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " alloc error " ) ;
}
max_dst_nb_samples_ = dst_nb_samples_ ;
int in_samples = dec_frame_ - > nb_samples ;
const uint8_t * * in_data = ( const uint8_t * * ) dec_frame_ - > extended_data ;
do {
/* Convert the samples using the resampler. */
int frame_size = swr_convert ( swr_ , swr_data_ , enc_ - > frame_size , in_data , in_samples ) ;
if ( ( error = frame_size ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not convert input samples(%d,%s) " , error ,
av_make_error_string ( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
ret = swr_convert ( swr_ctx_ , dst_data_ , dst_nb_samples_ , ( const uint8_t * * ) src_data_ , src_nb_samples_ ) ;
if ( ret < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Error while converting " ) ;
in_data = NULL ; in_samples = 0 ;
if ( ( err = add_samples_to_fifo ( swr_data_ , frame_size ) ) ! = srs_success ) {
return srs_error_wrap ( err , " write samples " ) ;
}
int dst_bufsize = av_samples_get_buffer_size ( & dst_linesize_ , dst_nb_channels_ ,
ret , dst_sample_fmt_ , 1 ) ;
if ( dst_bufsize < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not get sample buffer size " ) ;
}
int max = size ;
size = 0 ;
if ( max > = dst_bufsize ) {
memcpy ( buf , dst_data_ [ 0 ] , dst_bufsize ) ;
size = dst_bufsize ;
} while ( swr_get_out_samples ( swr_ , in_samples ) > = enc_ - > frame_size ) ;
}
return err ;
}
SrsAudioRecode : : SrsAudioRecode ( SrsAudioCodecId src_codec , SrsAudioCodecId dst_codec , int channels , int samplerate )
: dst_channels_ ( channels ) ,
dst_samplerate_ ( samplerate ) ,
src_codec_ ( src_codec ) ,
dst_codec_ ( dst_codec )
srs_error_t SrsAudioTranscoder : : encode ( std : : vector < SrsAudioFrame * > & pkts )
{
size_ = 0 ;
data_ = NULL ;
dec_ = NULL ;
enc_ = NULL ;
resample_ = NULL ;
}
char err_buf [ AV_ERROR_MAX_STRING_SIZE ] = { 0 } ;
SrsAudioRecode : : ~ SrsAudioRecode ( )
{
srs_freep ( dec_ ) ;
srs_freep ( enc_ ) ;
srs_freep ( resample_ ) ;
srs_freepa ( data_ ) ;
if ( next_out_pts_ = = AV_NOPTS_VALUE ) {
next_out_pts_ = new_pkt_pts_ ;
} else {
int64_t diff = llabs ( new_pkt_pts_ - next_out_pts_ ) ;
if ( diff > 1000 ) {
srs_trace ( " time diff to large=%lld, next out=%lld, new pkt=%lld, set to new pkt " ,
diff , next_out_pts_ , new_pkt_pts_ ) ;
next_out_pts_ = new_pkt_pts_ ;
}
srs_error_t SrsAudioRecode : : initialize ( )
{
srs_error_t err = srs_success ;
dec_ = new SrsAudioDecoder ( src_codec_ ) ;
if ( ( err = dec_ - > initialize ( ) ) ! = srs_success ) {
return srs_error_wrap ( err , " dec init " ) ;
}
enc_ = new SrsAudioEncoder ( dst_codec_ , dst_samplerate_ , dst_channels_ ) ;
if ( ( err = enc_ - > initialize ( ) ) ! = srs_success ) {
return srs_error_wrap ( err , " enc init " ) ;
int frame_cnt = 0 ;
while ( av_audio_fifo_size ( fifo_ ) > = enc_ - > frame_size ) {
/* Read as many samples from the FIFO buffer as required to fill the frame.
* The samples are stored in the frame temporarily . */
if ( av_audio_fifo_read ( fifo_ , ( void * * ) enc_frame_ - > data , enc_ - > frame_size ) < enc_ - > frame_size ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not read data from FIFO " ) ;
}
enc_want_bytes_ = enc_ - > want_bytes ( ) ;
if ( enc_want_bytes_ > 0 ) {
data_ = new char [ enc_want_bytes_ ] ;
srs_assert ( data_ ) ;
}
return err ;
}
srs_error_t SrsAudioRecode : : transcode ( SrsSample * pkt , char * * buf , int * buf_len , int & n )
{
srs_error_t err = srs_success ;
if ( ! dec_ ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " dec_ nullptr " ) ;
}
int decode_len = kPacketBufMax ;
static char decode_buffer [ kPacketBufMax ] ;
if ( ( err = dec_ - > decode ( pkt , decode_buffer , decode_len ) ) ! = srs_success ) {
return srs_error_wrap ( err , " decode error " ) ;
/* send the frame for encoding */
enc_frame_ - > pts = next_out_pts_ + av_rescale ( enc_ - > frame_size * frame_cnt , 1000 , enc_ - > sample_rate ) ;
+ + frame_cnt ;
int error = avcodec_send_frame ( enc_ , enc_frame_ ) ;
if ( error < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Error sending the frame to the encoder(%d,%s) " , error ,
av_make_error_string ( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
if ( ! resample_ ) {
int channel_layout = av_get_default_channel_layout ( dst_channels_ ) ;
AVCodecContext * codec_ctx = dec_ - > codec_ctx ( ) ;
resample_ = new SrsAudioResample ( codec_ctx - > sample_rate , ( int ) codec_ctx - > channel_layout , \
codec_ctx - > sample_fmt , codec_ctx - > frame_size , dst_samplerate_ , channel_layout , \
enc_ - > codec_ctx ( ) - > sample_fmt ) ;
if ( ( err = resample_ - > initialize ( ) ) ! = srs_success ) {
return srs_error_wrap ( err , " init resample " ) ;
}
av_init_packet ( enc_packet_ ) ;
enc_packet_ - > data = NULL ;
enc_packet_ - > size = 0 ;
/* read all the available output packets (in general there may be any
* number of them */
while ( error > = 0 ) {
error = avcodec_receive_packet ( enc_ , enc_packet_ ) ;
if ( error = = AVERROR ( EAGAIN ) | | error = = AVERROR_EOF ) {
break ;
} else if ( error < 0 ) {
free_frames ( pkts ) ;
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Error during decoding(%d,%s) " , error ,
av_make_error_string ( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
SrsSample pcm ;
pcm . bytes = decode_buffer ;
pcm . size = decode_len ;
int resample_len = kFrameBufMax ;
static char resample_buffer [ kFrameBufMax ] ;
static char encode_buffer [ kPacketBufMax ] ;
if ( ( err = resample_ - > resample ( & pcm , resample_buffer , resample_len ) ) ! = srs_success ) {
return srs_error_wrap ( err , " resample error " ) ;
SrsAudioFrame * out_frame = new SrsAudioFrame ;
char * buf = new char [ enc_packet_ - > size ] ;
memcpy ( buf , enc_packet_ - > data , enc_packet_ - > size ) ;
out_frame - > add_sample ( buf , enc_packet_ - > size ) ;
out_frame - > dts = enc_packet_ - > dts ;
out_frame - > cts = enc_packet_ - > pts - enc_packet_ - > dts ;
pkts . push_back ( out_frame ) ;
}
n = 0 ;
// We can encode it in one time.
if ( enc_want_bytes_ < = 0 ) {
int encode_len ;
pcm . bytes = ( char * ) data_ ;
pcm . size = size_ ;
if ( ( err = enc_ - > encode ( & pcm , encode_buffer , encode_len ) ) ! = srs_success ) {
return srs_error_wrap ( err , " encode error " ) ;
}
memcpy ( buf [ n ] , encode_buffer , encode_len ) ;
buf_len [ n ] = encode_len ;
n + + ;
next_out_pts_ + = av_rescale ( enc_ - > frame_size * frame_cnt , 1000 , enc_ - > sample_rate ) ;
return err ;
return srs_success ;
}
// Need to refill the sample to data, because the frame size is not matched to encoder.
int data_left = resample_len ;
if ( size_ + data_left < enc_want_bytes_ ) {
memcpy ( data_ + size_ , resample_buffer , data_left ) ;
size_ + = data_left ;
return err ;
}
srs_error_t SrsAudioTranscoder : : add_samples_to_fifo ( uint8_t * * samples , int frame_size )
{
char err_buf [ AV_ERROR_MAX_STRING_SIZE ] = { 0 } ;
int index = 0 ;
while ( 1 ) {
data_left = data_left - ( enc_want_bytes_ - size_ ) ;
memcpy ( data_ + size_ , resample_buffer + index , enc_want_bytes_ - size_ ) ;
index + = enc_want_bytes_ - size_ ;
size_ + = enc_want_bytes_ - size_ ;
int error ;
int encode_len ;
pcm . bytes = ( char * ) data_ ;
pcm . size = size_ ;
if ( ( err = enc_ - > encode ( & pcm , encode_buffer , encode_len ) ) ! = srs_success ) {
return srs_error_wrap ( err , " encode error " ) ;
/* Make the FIFO as large as it needs to be to hold both,
* the old and the new samples . */
if ( ( error = av_audio_fifo_realloc ( fifo_ , av_audio_fifo_size ( fifo_ ) + frame_size ) ) < 0 ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not reallocate FIFO(%d,%s) " , error ,
av_make_error_string ( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
if ( encode_len > 0 ) {
memcpy ( buf [ n ] , encode_buffer , encode_len ) ;
buf_len [ n ] = encode_len ;
n+ + ;
/* Store the new samples in the FIFO buffer. */
if ( ( error = av_audio_fifo_write ( fifo_ , ( void * * ) samples , frame_size ) ) < frame_size ) {
return srs_error_new ( ERROR_RTC_RTP_MUXER , " Could not write data to FIFO(%d,%s) " , error ,
av_make_error_string( err_buf , AV_ERROR_MAX_STRING_SIZE , error ) ) ;
}
size_ = 0 ;
if ( ! data_left ) {
break ;
return srs_success ;
}
if ( data_left < enc_want_bytes_ ) {
memcpy ( data_ + size_ , resample_buffer + index , data_left ) ;
size_ + = data_left ;
break ;
void SrsAudioTranscoder : : free_swr_samples ( )
{
if ( swr_data_ ) {
av_freep ( & swr_data_ [ 0 ] ) ;
free ( swr_data_ ) ;
swr_data_ = NULL ;
}
}
return err ;
}