diff --git a/apps/decoder.c b/apps/decoder.c index 5b0193cb7c57c375908f24d25792a8e28c4358d6..10a8ce23705d30e0326c0b008a69db37a7d3ed35 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -3425,7 +3425,14 @@ static ivas_error decodeVoIP( } vec_pos_update = ( vec_pos_update + 1 ) % vec_pos_len; frame++; +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + if ( vec_pos_update == 0 ) + { + systemTime_ms += vec_pos_len * systemTimeInc_ms; + } +#else systemTime_ms += systemTimeInc_ms; +#endif #ifdef WMOPS update_mem(); @@ -3433,6 +3440,93 @@ static ivas_error decodeVoIP( #endif } + +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + int16_t nSamplesFlushed = 0; + + /* decode and get samples */ +#ifdef SPLIT_REND_WITH_HEAD_ROT + if ( ( error = IVAS_DEC_Flush( hIvasDec, nOutSamples, IVAS_DEC_PCM_INT16, (void *) pcmBuf, &nSamplesFlushed ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_DEC_Flush( hIvasDec, nOutSamples, pcmBuf, &nSamplesFlushed ) ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nError in IVAS_DEC_VoIP_Flush: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( nSamplesFlushed ) + { + /* Write current frame */ + if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, nSamplesFlushed * nOutChannels ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nOutput audio file writer error\n" ); + goto cleanup; + } + + /* Write ISm metadata to external file(s) */ + if ( decodedGoodFrame && arg.outputConfig == IVAS_AUDIO_CONFIG_EXTERNAL ) + { + if ( bsFormat == IVAS_DEC_BS_OBJ || bsFormat == IVAS_DEC_BS_MASA_ISM || bsFormat == IVAS_DEC_BS_SBA_ISM ) + { + if ( ( error = IVAS_DEC_GetNumObjects( hIvasDec, &numObj ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetNumObjects: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + for ( i = 0; i < numObj; ++i ) + { + IVAS_ISM_METADATA IsmMetadata; + + if ( ( error = IVAS_DEC_GetObjectMetadata( hIvasDec, &IsmMetadata, 0, i ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetObjectMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( ( IsmFileWriter_writeFrame( IsmMetadata, ismWriters[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing ISM metadata to file %s\n", IsmFileWriter_getFilePath( ismWriters[i] ) ); + goto cleanup; + } + } + } + + if ( bsFormat == IVAS_DEC_BS_MASA || bsFormat == IVAS_DEC_BS_MASA_ISM ) + { + IVAS_MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + int16_t fullDelayNumSamples[3]; + float delayMs; + + /* delayNumSamples is zeroed, and delayNumSamples_orig is updated only on first good frame, so need to re-fetch delay info */ + if ( ( error = IVAS_DEC_GetDelay( hIvasDec, fullDelayNumSamples, &delayTimeScale ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nUnable to get delay of decoder: %s\n", ivas_error_to_string( error ) ); + } +#endif + if ( ( error = IVAS_DEC_GetMasaMetadata( hIvasDec, &hMasaExtOutMeta, 0 ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetMasaMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + delayMs = (float) ( fullDelayNumSamples[0] ) / (float) ( delayTimeScale ); + if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta, &delayMs ) ) != IVAS_ERR_OK ) +#else + if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta ) ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nError writing MASA metadata to file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); + goto cleanup; + } + } + } + } +#endif + /*------------------------------------------------------------------------------------------* * Add zeros at the end to have equal length of synthesized signals *------------------------------------------------------------------------------------------*/ diff --git a/lib_com/options.h b/lib_com/options.h old mode 100755 new mode 100644 index 9924ed184d7d28d496dd5ed0e48d31504fee3357..f79b3468396f65f777e1dc2fd031e0ecab217607 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -57,7 +57,7 @@ /*#define MEM_COUNT_DETAILS*/ /* Output detailed memory analysis for the worst-case frame (writes to the file "mem_analysis.csv") */ #ifdef DEBUGGING -/*#define DEBUG_MODE_INFO*/ /* output most important parameters to the subdirectory "res/" */ +/*#define DEBUG_MODE_INFO*/ /* output most important parameters to the subdirectory "res/" */ #ifdef DEBUG_MODE_INFO /*#define DEBUG_MODE_ACELP*/ /* output most important ACELP core parameters to the subdirectory "res/" */ /*#define DEBUG_MODE_TCX*/ /* output most important TCX core parameters to the subdirectory "res/" */ @@ -72,6 +72,7 @@ /*#define DEBUG_MODE_INFO_ALLRAD*/ /* define to output generated HOA decoding mtx */ /*#define DEBUG_MODE_LFE */ /* define to output LFE relevant parameters */ /*#define DEBUG_MODE_ORIENTATION */ /* define to output combined orientation relevant parameters */ +/*#define DEBUG_MODE_JBM */ /* define to output JBM relevant parameters */ #endif #ifdef DEBUG_MODE_MDCT @@ -128,6 +129,7 @@ /*#define DEBUG_AGC_ENCODER_CMD_OPTION*/ /* Ability to force enable or disable AGC behaviour in DIRAC/SPAR via command line option */ /*#define DEBUG_JBM_CMD_OPTION*/ /* ability for telling the decoder the frontend fetch size and to not delay compensate for bad frames at the beginning */ /*#define VARIABLE_SPEED_DECODING*/ /* variable speed decoding employing the JBM functioniality; move to DEBUGGING after build for disabled is fixed */ +/*#define DISABLE_LIMITER*/ /* disable the limiter */ /*Split Rendering Debug switches*/ /*#define DBG_WAV_WRITER*/ /* add debugging function dbgwrite_wav() */ @@ -181,7 +183,7 @@ #define NONBE_FIX_999_JBM_MCT_FLUSH /* FhG: issue #999: fix wrong flushing for MCT at a JBM rate switch */ #define NONBE_FIX_991_PARAMBIN_BINARY_HRTF /* Nokia: issue #991: fix using of binary file HRTF in ParamBin */ #define NONBE_FIX_1005_MC_RS_TCBUFFER_UPDATE /* FhG: issue #1005: fix TC Buffer update at a MC rate switch */ - +#define NONBE_FIX_864_JBM_RENDER_FRAMESIZE /* FhG: issue #864: fix different behaviour of JBM TSM with different render frame sizes */ /* ##################### End NON-BE switches ########################### */ /* ################## End DEVELOPMENT switches ######################### */ diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index b3e63c5962d959c970e33cdd3df80472e311d6e1..61d452d9da43cdf0a81ef57b940755867552fd23 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -57,6 +57,9 @@ struct IVAS_DEC_VOIP uint16_t lastDecodedWasActive; JB4_DATAUNIT_HANDLE hCurrentDataUnit; /* Points to the currently processed data unit */ uint16_t *bs_conversion_buf; /* Buffer for bitstream conversion from packed to serial */ +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + int16_t nSamplesRendered20ms; /* how many samples have been rendered since the last 20ms render border*/ +#endif #ifdef SUPPORT_JBM_TRACEFILE IVAS_JBM_TRACE_DATA JbmTraceData; #endif @@ -78,6 +81,9 @@ struct IVAS_DEC bool Opt_VOIP; /* flag indicating VOIP mode with JBM */ int16_t tsm_scale; /* scale for TSM operation */ int16_t tsm_max_scaling; +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + int16_t timeScalingDone; /* have we done already one TSM in a 20ms frame? */ +#endif float tsm_quality; float *apaExecBuffer; /* Buffer for APA scaling */ PCMDSP_APA_HANDLE hTimeScaler; @@ -125,7 +131,9 @@ static void *pcm_buffer_offset( void *buffer, const IVAS_DEC_PCM_TYPE pcmType, c static ivas_error set_pcm_buffer_to_zero( void *buffer, const IVAS_DEC_PCM_TYPE pcmType, const int16_t nZeroSamples ); #endif static int16_t get_render_frame_size_ms( IVAS_RENDER_FRAMESIZE render_framesize ); - +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE +static void update_voip_rendered20ms( IVAS_DEC_HANDLE hIvasDec, const int16_t nSamplesRendered ); +#endif /*---------------------------------------------------------------------* * IVAS_DEC_Open() @@ -162,6 +170,9 @@ ivas_error IVAS_DEC_Open( hIvasDec->tsm_scale = 100; hIvasDec->tsm_max_scaling = 0; hIvasDec->tsm_quality = 1.0f; +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + hIvasDec->timeScalingDone = 0; +#endif hIvasDec->needNewFrame = false; hIvasDec->nTransportChannelsOld = 0; hIvasDec->nSamplesAvailableNext = 0; @@ -707,6 +718,9 @@ ivas_error IVAS_DEC_EnableVoIP( hIvasDec->hVoIP->lastDecodedWasActive = 0; hIvasDec->hVoIP->hCurrentDataUnit = NULL; hIvasDec->hVoIP->nSamplesFrame = (uint16_t) ( hDecoderConfig->output_Fs / FRAMES_PER_SEC ); +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + hIvasDec->hVoIP->nSamplesRendered20ms = 0; +#endif #define WMC_TOOL_SKIP /* Bitstream conversion is not counted towards complexity and memory usage */ @@ -965,18 +979,25 @@ ivas_error IVAS_DEC_GetSamples( assert( nTimeScalerOutSamples <= APA_BUF ); nSamplesTcsScaled = nTimeScalerOutSamples / nTransportChannels; +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + hIvasDec->timeScalingDone = 1; +#endif } else { nSamplesTcsScaled = hIvasDec->nSamplesFrame; } - +#ifdef DEBUG_MODE_JBM + dbgwrite( &nTimeScalerOutSamples, sizeof( uint16_t ), 1, 1, "./res/JBM_nTimeScaleOutSamples.dat" ); +#endif /* Feed decoded transport channels samples to the renderer */ if ( ( error = IVAS_DEC_RendererFeedTcSamples( hIvasDec, nSamplesTcsScaled, &nResidualSamples, hIvasDec->apaExecBuffer ) ) != IVAS_ERR_OK ) { return error; } - +#ifdef DEBUG_MODE_JBM + dbgwrite( &nResidualSamples, sizeof( int16_t ), 1, 1, "./res/JBM_nResidualSamples.dat" ); +#endif if ( hIvasDec->st_ivas->hDecoderConfig->Opt_tsm ) { /* feed residual samples to TSM for the next call */ @@ -1496,6 +1517,9 @@ static ivas_error IVAS_DEC_GetBufferedNumberOfSamples( if ( hIvasDec->st_ivas->hTcBuffer != NULL ) { *nSamplesBuffered = hIvasDec->st_ivas->hTcBuffer->n_samples_buffered - hIvasDec->st_ivas->hTcBuffer->n_samples_rendered; +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + *nSamplesBuffered += hIvasDec->hVoIP->nSamplesRendered20ms; +#endif } return IVAS_ERR_OK; @@ -2605,7 +2629,9 @@ ivas_error IVAS_DEC_VoIP_GetSamples( uint32_t extBufferedTime_ms, scale, maxScaling; JB4_DATAUNIT_HANDLE dataUnit; uint16_t extBufferedSamples; +#ifndef NONBE_FIX_864_JBM_RENDER_FRAMESIZE int16_t timeScalingDone; +#endif int16_t result; ivas_error error; int16_t nSamplesRendered; @@ -2614,7 +2640,9 @@ ivas_error IVAS_DEC_VoIP_GetSamples( st_ivas = hIvasDec->st_ivas; hDecoderConfig = st_ivas->hDecoderConfig; hVoIP = hIvasDec->hVoIP; +#ifndef NONBE_FIX_864_JBM_RENDER_FRAMESIZE timeScalingDone = 0; +#endif nOutChannels = (uint8_t) st_ivas->hDecoderConfig->nchan_out; nSamplesRendered = 0; @@ -2638,10 +2666,15 @@ ivas_error IVAS_DEC_VoIP_GetSamples( } } +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + extBufferedSamples = nSamplesBuffered; +#else extBufferedSamples = nSamplesRendered + nSamplesBuffered; +#endif extBufferedTime_ms = extBufferedSamples * 1000 / hDecoderConfig->output_Fs; dataUnit = NULL; + /* pop one access unit from the jitter buffer */ result = JB4_PopDataUnit( hVoIP->hJBM, systemTimestamp_ms, extBufferedTime_ms, &dataUnit, &scale, &maxScaling ); if ( result != 0 ) @@ -2650,17 +2683,30 @@ ivas_error IVAS_DEC_VoIP_GetSamples( } maxScaling = maxScaling * hDecoderConfig->output_Fs / 1000; - /* avoid time scaling multiple times in one sound card slot */ +#ifdef DEBUG_MODE_JBM + dbgwrite( &extBufferedSamples, sizeof( uint16_t ), 1, 1, "./res/JBM_extBufferedSamples.dat" ); + dbgwrite( &systemTimestamp_ms, sizeof( uint32_t ), 1, 1, "./res/JBM_systemTimestamp.dat" ); + dbgwrite( &scale, sizeof( uint32_t ), 1, 1, "./res/JBM_scale.dat" ); + dbgwrite( &maxScaling, sizeof( uint32_t ), 1, 1, "./res/JBM_maxScale.dat" ); +#endif + + /* avoid time scaling multiple times within one 20ms frame*/ if ( scale != 100U ) { +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + if ( hIvasDec->timeScalingDone ) +#else if ( timeScalingDone ) +#endif { scale = 100; } +#ifndef NONBE_FIX_864_JBM_RENDER_FRAMESIZE else { timeScalingDone = 1; } +#endif } /* limit scale to range supported by time scaler */ @@ -2749,6 +2795,9 @@ ivas_error IVAS_DEC_VoIP_GetSamples( nSamplesRendered += nSamplesToZero; hIvasDec->nSamplesRendered += nSamplesToZero; hIvasDec->nSamplesAvailableNext -= nSamplesToZero; +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + update_voip_rendered20ms( hIvasDec, nSamplesToZero ); +#endif } else { @@ -2767,12 +2816,37 @@ ivas_error IVAS_DEC_VoIP_GetSamples( } nSamplesRendered += nSamplesRendered_loop; +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + update_voip_rendered20ms( hIvasDec, nSamplesRendered_loop ); +#endif } } return IVAS_ERR_OK; } +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE +/*---------------------------------------------------------------------* + * update_voip_rendered20ms( ) + * + * Function to flush remaining audio in VoIP + *---------------------------------------------------------------------*/ + +static void update_voip_rendered20ms( + IVAS_DEC_HANDLE hIvasDec, + const int16_t nSamplesRendered ) +{ + int16_t nSamplesRenderedTotal; + nSamplesRenderedTotal = hIvasDec->hVoIP->nSamplesRendered20ms + nSamplesRendered; + /* we have crossed a 20ms border, reset the time scaling done flag */ + if ( nSamplesRenderedTotal >= hIvasDec->hVoIP->nSamplesFrame ) + { + hIvasDec->timeScalingDone = 0; + } + hIvasDec->hVoIP->nSamplesRendered20ms = nSamplesRenderedTotal % hIvasDec->hVoIP->nSamplesFrame; +} + +#endif /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_Flush( ) @@ -2801,12 +2875,23 @@ ivas_error IVAS_DEC_Flush( nSamplesToRender = (uint16_t) *nSamplesFlushed; /* render IVAS frames */ +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + error = IVAS_ERR_OK; + if ( nSamplesToRender > 0 && hIvasDec->st_ivas->ivas_format != MONO_FORMAT ) + { +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT - error = IVAS_DEC_GetRenderedSamples( hIvasDec, nSamplesToRender, &nSamplesFlushedLocal, &hIvasDec->nSamplesAvailableNext, pcmType, pcmBuf ); + error = IVAS_DEC_GetRenderedSamples( hIvasDec, nSamplesToRender, &nSamplesFlushedLocal, &hIvasDec->nSamplesAvailableNext, pcmType, pcmBuf ); #else error = IVAS_DEC_GetRenderedSamples( hIvasDec, nSamplesToRender, &nSamplesFlushedLocal, &hIvasDec->nSamplesAvailableNext, pcmBuf ); #endif - +#ifdef NONBE_FIX_864_JBM_RENDER_FRAMESIZE + } + else + { + *nSamplesFlushed = 0; + } +#endif return error; }