diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index e2d40e74dfd96fc57f96c0ef0675fa5824e5026f..6efd67fd39296832300d1f205b8d900dcd7da9e6 100755 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -172,8 +172,13 @@ typedef enum #define JBM_CLDFB_SLOTS_IN_SUBFRAME 4 #define MAX_JBM_CLDFB_TIMESLOTS 32 #define DEFAULT_JBM_CLDFB_TIMESLOTS 16 +#ifdef JBM_MEMORY_OPT +#define MAX_JBM_L_FRAME48k ( IVAS_MAX_FRAME_SIZE * 2 ) /* 1920: max. time-scaled frame buffer length (per channel) in samples */ +#define MAX_JBM_L_FRAME_NS 40000000L /* 40 ms: time-scaled frame size in ns, proportional to MAX_JBM_L_FRAME48k */ +#else #define MAX_JBM_L_FRAME48k 1920 #define MAX_JBM_L_FRAME_NS 40000000L +#endif #define MAX_SPAR_INTERNAL_CHANNELS IVAS_SPAR_MAX_CH #define MAX_CLDFB_DIGEST_CHANNELS 3 /* == maximum of ParamISM TCs and ParamMC TCs */ diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index b8c3b2bd9d57f81279fe837f0274471bdab1807b..ab768eb1e0ab7b55b8446b3eef1b22afbe806775 100755 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -259,12 +259,28 @@ uint32_t ivas_syn_output( int16_t *synth_out /* o : integer 16 bits synthesis signal */ ); +#ifdef JBM_MEMORY_OPT +void ivas_buffer_interleaved_to_deinterleaved( + float *audio, /* i/o: audio buffer */ + const int16_t n_channels, /* i : number of channels */ + const int16_t frame_length, /* i : frame length (one channel) */ + const int16_t n_samp_full /* i : full frame length (one channel) */ +); + +void ivas_buffer_deinterleaved_to_interleaved( + float *audio[], /* i : deinterleaved audio buffer */ + const int16_t n_channels, /* i : number of channels */ + const int16_t frame_length, /* i : frame length (one channel) */ + float *audio_out /* o : interleaved audio buffer */ +); +#else void ivas_syn_output_f( float *synth[], /* i/o: float synthesis signal */ const int16_t output_frame, /* i : output frame length (one channel) */ const int16_t n_channels, /* i : number of output channels */ float *synth_out /* o : integer 16 bits synthesis signal */ ); +#endif void ivas_initialize_handles_enc( Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */ @@ -832,8 +848,11 @@ ivas_error ivas_jbm_dec_flush_renderer( void ivas_jbm_dec_feed_tc_to_renderer( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ const int16_t nSamplesForRendering, /* i : number of TC samples available for rendering */ - int16_t *nSamplesResidual, /* o : number of samples not fitting into the renderer grid and buffer for the next call*/ - float *data /* i/o: transport channels/output synthesis signal */ + int16_t *nSamplesResidual /* o : number of samples not fitting into the renderer grid and buffer for the next call*/ +#ifndef JBM_MEMORY_OPT + , + float *data /* i/o: time-scaled transport channels */ +#endif ); void ivas_dec_prepare_renderer( diff --git a/lib_com/ivas_tools.c b/lib_com/ivas_tools.c index 36c626daa74a4f5b7d9338bc76f34ec45f1662c9..a4b414b96da03fc7cb5fa3c8bde64e733db93c91 100644 --- a/lib_com/ivas_tools.c +++ b/lib_com/ivas_tools.c @@ -148,6 +148,70 @@ uint32_t ivas_syn_output( return noClipping; } +#ifdef JBM_MEMORY_OPT + +/*-------------------------------------------------------------------* + * ivas_buffer_interleaved_to_deinterleaved() + * + * Convert an interleaved buffer of audio channels to deinterleaved one + *-------------------------------------------------------------------*/ + +void ivas_buffer_interleaved_to_deinterleaved( + float *audio, /* i/o: audio buffer */ + const int16_t n_channels, /* i : number of channels */ + const int16_t frame_length, /* i : frame length (one channel) */ + const int16_t n_samp_full /* i : full frame length (one channel) */ +) +{ + int16_t offset, ch, m; + float buffer[MAX_TRANSPORT_CHANNELS][MAX_JBM_L_FRAME48k]; + + for ( ch = 0; ch < n_channels; ch++ ) + { + for ( m = 0; m < frame_length; m++ ) + { + buffer[ch][m] = audio[m * n_channels + ch]; + } + } + + offset = 0; + for ( ch = 0; ch < n_channels; ch++ ) + { + mvr2r( buffer[ch], audio + offset, frame_length ); + offset += n_samp_full; + } + + return; +} + + +/*-------------------------------------------------------------------* + * ivas_buffer_deinterleaved_to_interleaved() + * + * Convert a deinterleaved buffer of audio channels to interleaved one + *-------------------------------------------------------------------*/ + +void ivas_buffer_deinterleaved_to_interleaved( + float *audio[], /* i/o: deinterleaved audio buffer */ + const int16_t n_channels, /* i : number of channels */ + const int16_t frame_length, /* i : frame length (one channel) */ + float *audio_out /* o : interleaved audio buffer */ +) +{ + int16_t ch, m; + + for ( ch = 0; ch < n_channels; ch++ ) + { + for ( m = 0; m < frame_length; m++ ) + { + audio_out[m * n_channels + ch] = audio[ch][m]; + } + } + + return; +} + +#else /*-------------------------------------------------------------------* * ivas_syn_output_f() @@ -181,6 +245,7 @@ void ivas_syn_output_f( return; } +#endif /*-------------------------------------------------------------------* * mvr2r_inc() diff --git a/lib_com/options.h b/lib_com/options.h index 11771a0523da5a4fcab5cf4d9318f41044c8509c..a768aa7deb8ec7d9161338e826e3f218b155a471 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -165,6 +165,7 @@ #define FIX_NCHAN_BUFFERS /* VA: issue 1322: Correct the number of float buffers (channels) at the decoder */ #define FIX_RENDERER_STACK /* VA: issue 1322: reduction of renderers' buffers size */ #define FIX_1319_STACK_SBA_DECODER /* VA: issue 1319: Optimize the definition of buffer lengths in the SBA decoder */ +#define JBM_MEMORY_OPT /* VA: issue 916: optimization of RAM in the JBM decoder */ /* #################### End BE switches ################################## */ diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index 649cb15bbb728f44030211f2d3037b037063f539..31e6178c48c0a4043c03e49bfdef613ee911c3c2 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -757,12 +757,20 @@ ivas_error ivas_jbm_dec_tc( void ivas_jbm_dec_feed_tc_to_renderer( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ const int16_t nSamplesForRendering, /* i : number of TC samples available for rendering */ - int16_t *nSamplesResidual, /* o : number of samples not fitting into the renderer grid and buffer for the next call*/ - float *data /* i : transport channels */ + int16_t *nSamplesResidual /* o : number of samples not fitting into the renderer grid and buffer for the next call*/ +#ifndef JBM_MEMORY_OPT + , + float *data /* i : transport channels */ +#endif ) { +#ifdef JBM_MEMORY_OPT + float tmp_buf[MAX_JBM_L_FRAME48k]; + float *p_data_f[FOA_CHANNELS + MAX_NUM_OBJECTS]; +#else float data_f[MAX_CLDFB_DIGEST_CHANNELS][MAX_JBM_L_FRAME48k]; /* 'float' buffer for transport channels that will be directly converted with the CLDFB */ float *p_data_f[MAX_CLDFB_DIGEST_CHANNELS]; +#endif int16_t n, n_render_timeslots, n_ch_cldfb; int16_t ch; DECODER_TC_BUFFER_HANDLE hTcBuffer; @@ -772,6 +780,38 @@ void ivas_jbm_dec_feed_tc_to_renderer( if ( st_ivas->hDecoderConfig->Opt_tsm ) { +#ifdef JBM_MEMORY_OPT + int16_t n_samples_still_available; + int16_t n_ch_full_copy, n_ch_res_copy; + + n_samples_still_available = hTcBuffer->n_samples_buffered - hTcBuffer->n_samples_rendered; + hTcBuffer->n_samples_buffered = n_samples_still_available + nSamplesForRendering + hTcBuffer->n_samples_discard; + hTcBuffer->n_samples_available = hTcBuffer->n_samples_granularity * ( hTcBuffer->n_samples_buffered / hTcBuffer->n_samples_granularity ); + *nSamplesResidual = hTcBuffer->n_samples_buffered - hTcBuffer->n_samples_available; + n_ch_full_copy = min( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ); + n_ch_res_copy = hTcBuffer->nchan_transport_jbm - hTcBuffer->nchan_buffer_full; + + for ( ch = 0; ch < n_ch_full_copy; ch++ ) + { + mvr2r( hTcBuffer->tc[ch], tmp_buf, nSamplesForRendering ); + set_zero( hTcBuffer->tc[ch], hTcBuffer->n_samples_discard ); + mvr2r( hTcBuffer->tc_buffer_old[ch], hTcBuffer->tc[ch] + hTcBuffer->n_samples_discard, n_samples_still_available ); + mvr2r( tmp_buf, hTcBuffer->tc[ch] + n_samples_still_available + hTcBuffer->n_samples_discard, nSamplesForRendering - *nSamplesResidual ); + mvr2r( tmp_buf + nSamplesForRendering - *nSamplesResidual, hTcBuffer->tc_buffer_old[ch], *nSamplesResidual ); + } + + if ( n_ch_res_copy > 0 ) + { + for ( ; ch < hTcBuffer->nchan_transport_jbm; ch++ ) + { + p_data_f[ch] = hTcBuffer->tc[ch]; + mvr2r( hTcBuffer->tc[ch], tmp_buf, nSamplesForRendering ); + mvr2r( hTcBuffer->tc_buffer_old[ch], p_data_f[ch], n_samples_still_available ); + mvr2r( tmp_buf, p_data_f[ch] + n_samples_still_available, nSamplesForRendering - *nSamplesResidual ); + mvr2r( tmp_buf + nSamplesForRendering - *nSamplesResidual, hTcBuffer->tc_buffer_old[ch], *nSamplesResidual ); + } + } +#else int16_t n_samples_still_available, m; int16_t n_ch_full_copy; int16_t n_ch_res_copy; @@ -811,6 +851,7 @@ void ivas_jbm_dec_feed_tc_to_renderer( mvr2r( p_data_f[ch] + hTcBuffer->n_samples_available, hTcBuffer->tc[ch], *nSamplesResidual ); } } +#endif n_render_timeslots = hTcBuffer->n_samples_available / hTcBuffer->n_samples_granularity; } @@ -822,7 +863,11 @@ void ivas_jbm_dec_feed_tc_to_renderer( } #ifdef FIX_NCHAN_BUFFERS +#ifdef JBM_MEMORY_OPT + ch = max( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ); +#else ch = ivas_get_nchan_buffers_dec( st_ivas, st_ivas->sba_analysis_order, st_ivas->hDecoderConfig->ivas_total_brate ); +#endif for ( n = 0; n < ch; n++ ) #else for ( n = 0; n < ivas_get_nchan_buffers_dec( st_ivas, st_ivas->sba_analysis_order, st_ivas->hDecoderConfig->ivas_total_brate ); n++ ) @@ -899,7 +944,11 @@ ivas_error ivas_jbm_dec_render( if ( !st_ivas->hDecoderConfig->Opt_tsm ) { +#ifdef JBM_MEMORY_OPT + for ( n = 0; n < MAX_INTERN_CHANNELS; n++ ) +#else for ( n = 0; n < MAX_TRANSPORT_CHANNELS + MAX_NUM_OBJECTS; n++ ) +#endif { st_ivas->hTcBuffer->tc[n] = p_output[n]; } @@ -1352,7 +1401,11 @@ ivas_error ivas_jbm_dec_render( break; case PCM_FLOAT32: +#ifdef JBM_MEMORY_OPT + ivas_buffer_deinterleaved_to_interleaved( p_output, nchan_out_syn_output, *nSamplesRendered, (float *) data ); +#else ivas_syn_output_f( p_output, *nSamplesRendered, nchan_out_syn_output, (float *) data ); +#endif break; default: error = IVAS_ERR_UNKNOWN; @@ -1415,6 +1468,15 @@ ivas_error ivas_jbm_dec_flush_renderer( { int16_t ch_idx; +#ifdef JBM_MEMORY_OPT + /* render available full slots (with new lower granularity) */ + for ( ch_idx = 0; ch_idx < max( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ); ch_idx++ ) + { + /* move it at the beginning of the TC buffer with zero padding */ + mvr2r( hTcBuffer->tc_buffer_old[ch_idx], hTcBuffer->tc[ch_idx], n_samples_to_render ); + set_zero( hTcBuffer->tc[ch_idx] + n_samples_to_render, hTcBuffer->n_samples_granularity - n_samples_to_render ); + } +#else /* render what is still there with zero padding */ for ( ch_idx = 0; ch_idx < hTcBuffer->nchan_buffer_full; ch_idx++ ) { @@ -1423,6 +1485,7 @@ ivas_error ivas_jbm_dec_flush_renderer( set_zero( hTcBuffer->tc[ch_idx] + n_samples_to_render, hTcBuffer->n_samples_granularity - n_samples_to_render ); mvr2r( hTcBuffer->tc[ch_idx] + hTcBuffer->n_samples_rendered + n_samples_to_render, hTcBuffer->tc[ch_idx] + hTcBuffer->n_samples_granularity, n_samples_still_available ); } +#endif /* simple change of the slot info */ hTcBuffer->num_slots = 1; @@ -1624,7 +1687,11 @@ ivas_error ivas_jbm_dec_flush_renderer( ivas_syn_output( p_output, *nSamplesRendered, st_ivas->hDecoderConfig->nchan_out, (int16_t *) data ); break; case PCM_FLOAT32: +#ifdef JBM_MEMORY_OPT + ivas_buffer_deinterleaved_to_interleaved( p_output, st_ivas->hDecoderConfig->nchan_out, *nSamplesRendered, (float *) data ); +#else ivas_syn_output_f( p_output, *nSamplesRendered, st_ivas->hDecoderConfig->nchan_out, (float *) data ); +#endif break; default: error = IVAS_ERR_UNKNOWN; @@ -2045,6 +2112,127 @@ int16_t ivas_jbm_dec_get_render_granularity( return render_granularity; } +#ifdef JBM_MEMORY_OPT + +/*--------------------------------------------------------------------------* + * ivas_jbm_dec_tc_audio_allocate() + * + * allocate and initialize TC audio buffer + *--------------------------------------------------------------------------*/ + +static ivas_error ivas_jbm_dec_tc_audio_allocate( + DECODER_TC_BUFFER_HANDLE hTcBuffer, /* i/o: JBM TSM buffer handle */ + const int32_t output_Fs, /* i : output sampling rate */ + const int16_t Opt_tsm /* i : TSM option flag */ +) +{ + int16_t nsamp_to_allocate; + int16_t ch_idx, n_samp_full, n_samp_residual, offset; + + if ( Opt_tsm ) + { + n_samp_full = ( NS2SA( output_Fs, MAX_JBM_L_FRAME_NS ) ); + n_samp_residual = hTcBuffer->n_samples_granularity - 1; + } + else + { + n_samp_full = (int16_t) ( output_Fs / FRAMES_PER_SEC ); + n_samp_residual = 0; + } + + nsamp_to_allocate = max( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ) * n_samp_full; + + if ( Opt_tsm ) + { + /* note: this is stack memory buffer for time-scale modified audio signals */ + if ( ( hTcBuffer->tc_buffer = (float *) malloc( nsamp_to_allocate * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM TC Buffer\n" ) ); + } + set_zero( hTcBuffer->tc_buffer, nsamp_to_allocate ); + + offset = 0; + for ( ch_idx = 0; ch_idx < max( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ); ch_idx++ ) + { + hTcBuffer->tc[ch_idx] = &hTcBuffer->tc_buffer[offset]; + offset += n_samp_full; + } + for ( ; ch_idx < MAX_INTERN_CHANNELS; ch_idx++ ) + { + hTcBuffer->tc[ch_idx] = NULL; + } + + /* memory buffer for TC audio samples not rendered in the previous frame */ + for ( ch_idx = 0; ch_idx < hTcBuffer->nchan_transport_internal; ch_idx++ ) + { + if ( ( hTcBuffer->tc_buffer_old[ch_idx] = (float *) malloc( n_samp_residual * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM TC Buffer\n" ) ); + } + set_zero( hTcBuffer->tc_buffer_old[ch_idx], n_samp_residual ); + } + for ( ; ch_idx < MAX_INTERN_CHANNELS; ch_idx++ ) + { + hTcBuffer->tc_buffer_old[ch_idx] = NULL; + } + } + else + { + hTcBuffer->tc_buffer = NULL; + + for ( ch_idx = 0; ch_idx < MAX_INTERN_CHANNELS; ch_idx++ ) + { + hTcBuffer->tc[ch_idx] = NULL; + } + + for ( ch_idx = 0; ch_idx < MAX_INTERN_CHANNELS; ch_idx++ ) + { + hTcBuffer->tc_buffer_old[ch_idx] = NULL; + } + } + + return IVAS_ERR_OK; +} + + +/*--------------------------------------------------------------------------* + * ivas_jbm_dec_tc_audio_deallocate() + * + * deallocate TC audio buffer + *--------------------------------------------------------------------------*/ + +static void ivas_jbm_dec_tc_audio_deallocate( + DECODER_TC_BUFFER_HANDLE hTcBuffer /* i/o: JBM TSM buffer handle */ +) +{ + int16_t ch_idx; + + if ( hTcBuffer != NULL ) + { + if ( hTcBuffer->tc_buffer != NULL ) + { + for ( ch_idx = 0; ch_idx < MAX_INTERN_CHANNELS; ch_idx++ ) + { + hTcBuffer->tc[ch_idx] = NULL; + } + + free( hTcBuffer->tc_buffer ); + hTcBuffer->tc_buffer = NULL; + } + + for ( ch_idx = 0; ch_idx < MAX_INTERN_CHANNELS; ch_idx++ ) + { + if ( hTcBuffer->tc_buffer_old[ch_idx] != NULL ) + { + free( hTcBuffer->tc_buffer_old[ch_idx] ); + hTcBuffer->tc_buffer_old[ch_idx] = NULL; + } + } + } + + return; +} +#endif /*--------------------------------------------------------------------------* * ivas_jbm_dec_tc_buffer_open() @@ -2061,11 +2249,17 @@ ivas_error ivas_jbm_dec_tc_buffer_open( const int16_t n_samples_granularity /* i : granularity of the renderer/buffer */ ) { +#ifndef JBM_MEMORY_OPT int16_t nsamp_to_allocate; +#endif DECODER_TC_BUFFER_HANDLE hTcBuffer; int16_t nMaxSlotsPerSubframe; +#ifdef JBM_MEMORY_OPT + ivas_error error; +#else int16_t nchan_residual; int16_t ch_idx; +#endif /*-----------------------------------------------------------------* * prepare library opening @@ -2080,7 +2274,9 @@ ivas_error ivas_jbm_dec_tc_buffer_open( hTcBuffer->nchan_transport_jbm = nchan_transport_jbm; hTcBuffer->nchan_transport_internal = nchan_transport_internal; hTcBuffer->nchan_buffer_full = nchan_full; +#ifndef JBM_MEMORY_OPT nchan_residual = nchan_transport_internal - nchan_full; +#endif hTcBuffer->n_samples_granularity = n_samples_granularity; hTcBuffer->n_samples_available = 0; hTcBuffer->n_samples_buffered = 0; @@ -2090,12 +2286,20 @@ ivas_error ivas_jbm_dec_tc_buffer_open( hTcBuffer->n_samples_discard = 0; hTcBuffer->n_samples_flushed = 0; hTcBuffer->nb_subframes = MAX_PARAM_SPATIAL_SUBFRAMES; +#ifndef JBM_MEMORY_OPT nsamp_to_allocate = 0; +#endif nMaxSlotsPerSubframe = (int16_t) ( st_ivas->hDecoderConfig->output_Fs / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ) / hTcBuffer->n_samples_granularity; hTcBuffer->num_slots = nMaxSlotsPerSubframe * MAX_PARAM_SPATIAL_SUBFRAMES; set_s( hTcBuffer->subframe_nbslots, 0, MAX_JBM_SUBFRAMES_5MS ); set_s( hTcBuffer->subframe_nbslots, nMaxSlotsPerSubframe, MAX_PARAM_SPATIAL_SUBFRAMES ); +#ifdef JBM_MEMORY_OPT + if ( ( error = ivas_jbm_dec_tc_audio_allocate( hTcBuffer, st_ivas->hDecoderConfig->output_Fs, st_ivas->hDecoderConfig->Opt_tsm ) ) != IVAS_ERR_OK ) + { + return error; + } +#else { int16_t n_samp_full, n_samp_residual; int32_t offset; @@ -2155,6 +2359,7 @@ ivas_error ivas_jbm_dec_tc_buffer_open( } } } +#endif st_ivas->hTcBuffer = hTcBuffer; @@ -2177,8 +2382,12 @@ ivas_error ivas_jbm_dec_tc_buffer_reconfigure( const int16_t n_samples_granularity /* i : new granularity of the renderer/buffer */ ) { +#ifdef JBM_MEMORY_OPT + ivas_error error; +#else int16_t nsamp_to_allocate, n_samp_full, n_samp_residual, offset, nchan_residual; int16_t ch_idx; +#endif DECODER_TC_BUFFER_HANDLE hTcBuffer; hTcBuffer = st_ivas->hTcBuffer; @@ -2220,13 +2429,26 @@ ivas_error ivas_jbm_dec_tc_buffer_reconfigure( hTcBuffer->nchan_transport_jbm = nchan_transport_jbm; hTcBuffer->nchan_transport_internal = nchan_transport_internal; hTcBuffer->nchan_buffer_full = nchan_full; +#ifndef JBM_MEMORY_OPT nchan_residual = nchan_transport_internal - nchan_full; +#endif hTcBuffer->n_samples_granularity = n_samples_granularity; #ifdef DEBUGGING /* what is remaining from last frames needs always be smaller than n_samples_granularity */ assert( ( hTcBuffer->n_samples_buffered - hTcBuffer->n_samples_rendered ) < n_samples_granularity ); #endif + +#ifdef JBM_MEMORY_OPT + /* reallocate TC audio buffers */ + + ivas_jbm_dec_tc_audio_deallocate( hTcBuffer ); + + if ( ( error = ivas_jbm_dec_tc_audio_allocate( hTcBuffer, st_ivas->hDecoderConfig->output_Fs, st_ivas->hDecoderConfig->Opt_tsm ) ) != IVAS_ERR_OK ) + { + return error; + } +#else /* realloc buffers */ if ( hTcBuffer->tc_buffer != NULL ) { @@ -2286,6 +2508,7 @@ ivas_error ivas_jbm_dec_tc_buffer_reconfigure( hTcBuffer->tc_buffer = NULL; } } +#endif return IVAS_ERR_OK; } @@ -2344,10 +2567,15 @@ void ivas_jbm_dec_tc_buffer_close( DECODER_TC_BUFFER_HANDLE *phTcBuffer /* i/o: TC buffer handle */ ) { +#ifndef JBM_MEMORY_OPT int16_t i; +#endif if ( *phTcBuffer != NULL ) { +#ifdef JBM_MEMORY_OPT + ivas_jbm_dec_tc_audio_deallocate( *phTcBuffer ); +#else for ( i = 0; i < MAX_TRANSPORT_CHANNELS + MAX_NUM_OBJECTS; i++ ) { ( *phTcBuffer )->tc[i] = NULL; @@ -2358,6 +2586,7 @@ void ivas_jbm_dec_tc_buffer_close( free( ( *phTcBuffer )->tc_buffer ); ( *phTcBuffer )->tc_buffer = NULL; } +#endif free( *phTcBuffer ); *phTcBuffer = NULL; diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index 89d53452bb5c449e2577ccf17c2a48ee2fcddae3..28de5d73400e33af41ed14c216474e1ee7b22d1a 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -944,16 +944,23 @@ typedef struct ivas_masa_ism_data_structure typedef struct decoder_tc_buffer_structure { - float *tc_buffer; /* the buffer itself */ - float *tc[MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS]; /* pointers into the buffer to the beginning of each tc */ - TC_BUFFER_MODE tc_buffer_mode; /* mode of the buffer (no buffering, render buffering, out buffering) */ - int16_t nchan_transport_jbm; /* number of TCs after TC decoding */ - int16_t nchan_transport_internal; /* total number of TC buffer channels, can include e.g. TD decorr data */ - int16_t nchan_buffer_full; /* number of channels to be fully buffered */ - int16_t n_samples_available; /* samples still available for rendering in the current frame */ - int16_t n_samples_buffered; /* full number of samples in the buffer (including spill to next frame) */ - int16_t n_samples_rendered; /* samples already rendered in the current frame */ - int16_t n_samples_granularity; /* render granularity */ +#ifdef JBM_MEMORY_OPT + float *tc_buffer_old[MAX_INTERN_CHANNELS]; /* TC audio samples not rendered in the previous frame */ +#endif + float *tc_buffer; /* the buffer itself */ +#ifdef JBM_MEMORY_OPT + float *tc[MAX_INTERN_CHANNELS]; /* pointers into the buffer to the beginning of each tc */ +#else + float *tc[MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS]; /* pointers into the buffer to the beginning of each tc */ // VE2SB: TBV +#endif + TC_BUFFER_MODE tc_buffer_mode; /* mode of the buffer (no buffering, render buffering, out buffering) */ + int16_t nchan_transport_jbm; /* number of TCs after TC decoding */ + int16_t nchan_transport_internal; /* total number of TC buffer channels, can include e.g. TD decorr data */ + int16_t nchan_buffer_full; /* number of channels to be fully buffered */ + int16_t n_samples_available; /* samples still available for rendering in the current frame */ + int16_t n_samples_buffered; /* full number of samples in the buffer (including spill to next frame) */ + int16_t n_samples_rendered; /* samples already rendered in the current frame */ + int16_t n_samples_granularity; /* render granularity */ int16_t n_samples_flushed; int16_t subframe_nbslots[MAX_JBM_SUBFRAMES_5MS]; int16_t nb_subframes; diff --git a/lib_dec/jbm_pcmdsp_apa.c b/lib_dec/jbm_pcmdsp_apa.c index 3305a1e48d6601bb5489d3f38a23c27e0ba00f66..fdb41a3cb23bf8a46847710e8e2366cd65fc7c68 100644 --- a/lib_dec/jbm_pcmdsp_apa.c +++ b/lib_dec/jbm_pcmdsp_apa.c @@ -562,7 +562,11 @@ uint8_t apa_exec( ) { uint16_t i; +#ifdef JBM_MEMORY_OPT + float frm_in[APA_BUF]; /* NOTE: this buffer could be smaller if alocated dynamically based on the actual sampling rate and number of channels */ +#else float frm_in[APA_BUF]; /* TODO(mcjbm): this buffer could be smaller - always allocates space for 16 channels */ +#endif uint16_t l_frm_out; int16_t l_rem; int32_t dl_scaled, dl_copied, l_frm_out_target; diff --git a/lib_dec/jbm_pcmdsp_apa.h b/lib_dec/jbm_pcmdsp_apa.h index a728cb53d346366279f716c756017a71eda89711..6d35fa8b505e1641a631ff6708aa4a01fd06cdd1 100644 --- a/lib_dec/jbm_pcmdsp_apa.h +++ b/lib_dec/jbm_pcmdsp_apa.h @@ -50,9 +50,14 @@ */ /* size of IO buffers (a_in[], a_out[]) for apa_exec() */ +#ifdef JBM_MEMORY_OPT +#define APA_BUF_PER_CHANNEL ( IVAS_MAX_FRAME_SIZE * 2 ) /* == twice the max. frame length */ +#define APA_MAX_NUM_CHANNELS ( 12 ) /* == MAX_TRANSPORT_CHANNELS */ +#else #define APA_BUF_PER_CHANNEL ( IVAS_MAX_FRAME_SIZE * 3 ) #define APA_MAX_NUM_CHANNELS 16 -#define APA_BUF ( APA_BUF_PER_CHANNEL * APA_MAX_NUM_CHANNELS ) +#endif +#define APA_BUF ( APA_BUF_PER_CHANNEL * APA_MAX_NUM_CHANNELS ) /* min/max sampling rate [Hz] */ #define APA_MIN_RATE 1000 diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index eb4ae461959c06b15438e3b0d5f113406c4b32ff..4a31ff2e75cd3292226ae9be1fed107b694dfca7 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -85,7 +85,9 @@ struct IVAS_DEC int16_t tsm_max_scaling; int16_t timeScalingDone; /* have we done already one TSM in a 20ms frame? */ float tsm_quality; +#ifndef JBM_MEMORY_OPT float *apaExecBuffer; /* Buffer for APA scaling */ +#endif PCMDSP_APA_HANDLE hTimeScaler; bool needNewFrame; bool hasBeenFedFrame; @@ -159,7 +161,9 @@ ivas_error IVAS_DEC_Open( } hIvasDec = *phIvasDec; hIvasDec->hVoIP = NULL; +#ifndef JBM_MEMORY_OPT hIvasDec->apaExecBuffer = NULL; +#endif hIvasDec->hTimeScaler = NULL; hIvasDec->tsm_scale = 100; hIvasDec->tsm_max_scaling = 0; @@ -350,11 +354,12 @@ void IVAS_DEC_Close( apa_exit( &( *phIvasDec )->hTimeScaler ); +#ifndef JBM_MEMORY_OPT if ( ( *phIvasDec )->apaExecBuffer != NULL ) { free( ( *phIvasDec )->apaExecBuffer ); } - +#endif if ( ( *phIvasDec )->flushbuffer != NULL ) { free( ( *phIvasDec )->flushbuffer ); @@ -953,8 +958,9 @@ static IVAS_BIN_RENDERER_TYPE renderer_type_to_mode( * IVAS_DEC_ReadFormat( ) * * Read main parameters from the bitstream to set-up the decoder: - * - IVAS fromat + * - IVAS format * - IVAS format specific signaling + * - compensate for renderer granularity change in JBM *---------------------------------------------------------------------*/ ivas_error IVAS_DEC_ReadFormat( @@ -1137,7 +1143,11 @@ ivas_error IVAS_DEC_GetSamplesDecoder( } st_ivas = hIvasDec->st_ivas; +#ifdef JBM_MEMORY_OPT + isInitialized_voip = hIvasDec->hTimeScaler != NULL; +#else isInitialized_voip = hIvasDec->apaExecBuffer != NULL; +#endif if ( !hIvasDec->isInitialized || hIvasDec->hasBeenFedFrame ) /* wait for the first good frame */ { @@ -1195,9 +1205,17 @@ ivas_error IVAS_DEC_GetSamplesDecoder( return IVAS_ERR_UNKNOWN; } - ivas_syn_output_f( hIvasDec->st_ivas->p_output_f, hIvasDec->nSamplesFrame, nTransportChannels, hIvasDec->apaExecBuffer ); +#ifdef JBM_MEMORY_OPT + /* convert deinterleaved decoded TC audio channels buffer to an interleaved one */ + ivas_buffer_deinterleaved_to_interleaved( st_ivas->p_output_f, nTransportChannels, hIvasDec->nSamplesFrame, st_ivas->hTcBuffer->tc_buffer ); + + /* time-scale modification */ + if ( apa_exec( hIvasDec->hTimeScaler, st_ivas->hTcBuffer->tc_buffer, hIvasDec->nSamplesFrame * nTransportChannels, (uint16_t) hIvasDec->tsm_max_scaling, st_ivas->hTcBuffer->tc_buffer, &nTimeScalerOutSamples ) != 0 ) +#else + ivas_syn_output_f( st_ivas->p_output_f, hIvasDec->nSamplesFrame, nTransportChannels, hIvasDec->apaExecBuffer ); if ( apa_exec( hIvasDec->hTimeScaler, hIvasDec->apaExecBuffer, hIvasDec->nSamplesFrame * nTransportChannels, (uint16_t) hIvasDec->tsm_max_scaling, hIvasDec->apaExecBuffer, &nTimeScalerOutSamples ) != 0 ) +#endif { return IVAS_ERR_UNKNOWN; } @@ -1205,6 +1223,11 @@ ivas_error IVAS_DEC_GetSamplesDecoder( assert( nTimeScalerOutSamples <= APA_BUF ); nSamplesTcsScaled = nTimeScalerOutSamples / nTransportChannels; hIvasDec->timeScalingDone = 1; +#ifdef JBM_MEMORY_OPT + + /* convert interleaved time-scaled TC audio channels buffer to deinterleaved one */ + ivas_buffer_interleaved_to_deinterleaved( st_ivas->hTcBuffer->tc_buffer, nTransportChannels, nSamplesTcsScaled, NS2SA( st_ivas->hDecoderConfig->output_Fs, MAX_JBM_L_FRAME_NS ) ); +#endif } else { @@ -1215,7 +1238,11 @@ ivas_error IVAS_DEC_GetSamplesDecoder( * Feed decoded transport channels samples to the renderer *-----------------------------------------------------------------*/ +#ifdef JBM_MEMORY_OPT + ivas_jbm_dec_feed_tc_to_renderer( st_ivas, nSamplesTcsScaled, &nResidualSamples ); +#else ivas_jbm_dec_feed_tc_to_renderer( st_ivas, nSamplesTcsScaled, &nResidualSamples, hIvasDec->apaExecBuffer ); +#endif if ( st_ivas->hDecoderConfig->Opt_tsm ) { @@ -1225,6 +1252,7 @@ ivas_error IVAS_DEC_GetSamplesDecoder( return IVAS_ERR_UNKNOWN; } } + hIvasDec->hasBeenFedFrame = false; } @@ -4481,7 +4509,9 @@ static ivas_error apa_setup( const bool isInitialized_voip, const uint16_t nTransportChannels ) { +#ifndef JBM_MEMORY_OPT int16_t apa_buffer_size; +#endif uint16_t l_ts; l_ts = (uint16_t) hIvasDec->st_ivas->hTcBuffer->n_samples_granularity; @@ -4493,9 +4523,11 @@ static ivas_error apa_setup( float startQuality; startQuality = hIvasDec->tsm_quality; +#ifndef JBM_MEMORY_OPT apa_buffer_size = APA_BUF_PER_CHANNEL; - /* get current renderer type*/ + +#endif hDecoderConfig = hIvasDec->st_ivas->hDecoderConfig; if ( hDecoderConfig->output_Fs == 8000 ) @@ -4539,6 +4571,7 @@ static ivas_error apa_setup( return IVAS_ERR_INIT_ERROR; } } +#ifndef JBM_MEMORY_OPT if ( ( hIvasDec->apaExecBuffer = malloc( sizeof( float ) * apa_buffer_size * nTransportChannels ) ) == NULL ) { @@ -4546,6 +4579,7 @@ static ivas_error apa_setup( } set_zero( hIvasDec->apaExecBuffer, apa_buffer_size * nTransportChannels ); +#endif } else { @@ -4553,15 +4587,15 @@ static ivas_error apa_setup( { return IVAS_ERR_INIT_ERROR; } - +#ifndef JBM_MEMORY_OPT /* realloc apa_exe_buffer */ - apa_buffer_size = APA_BUF_PER_CHANNEL; free( hIvasDec->apaExecBuffer ); if ( ( hIvasDec->apaExecBuffer = malloc( sizeof( float ) * apa_buffer_size * nTransportChannels ) ) == NULL ) { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Could not allocate VoIP handle" ); } set_zero( hIvasDec->apaExecBuffer, apa_buffer_size * nTransportChannels ); +#endif } hIvasDec->nTransportChannelsOld = nTransportChannels;