From 72bbb50232d4cf80900f304925371c7ed8c3f4d7 Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Mon, 17 Apr 2023 14:57:07 +0300 Subject: [PATCH 1/7] Implements contribution 45 - MASA metadata HR encoding --- lib_com/ivas_cnst.h | 16 + lib_com/ivas_masa_com.c | 177 ++++ lib_com/ivas_prot.h | 58 ++ lib_com/ivas_rom_com.c | 48 +- lib_com/ivas_rom_com.h | 5 + lib_com/ivas_stat_com.h | 4 +- lib_com/options.h | 4 + lib_dec/ivas_masa_dec.c | 45 +- lib_dec/ivas_qmetadata_dec.c | 1593 ++++++++++++++++++++++++++++--- lib_enc/ivas_masa_enc.c | 331 ++++++- lib_enc/ivas_qmetadata_enc.c | 1683 ++++++++++++++++++++++++++++++--- lib_enc/ivas_qspherical_enc.c | 38 +- lib_util/masa_file_reader.c | 20 +- 13 files changed, 3716 insertions(+), 306 deletions(-) diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index 0b326ba8a5..8128224bbe 100644 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -1157,6 +1157,9 @@ enum #define MASA_DIRECTION_MAX_BITS 11 #define MASA_NO_INDEX 32767 #define MASA_BITS_ER 3 +#ifdef HR_METADATA +#define MASA_BITS_ER_HR 4 +#endif #define MASA_MIN_BITS_TF 4 #define MASA_LIMIT_2D 2 #define MASA_NO_CV_COH 8 @@ -1175,6 +1178,12 @@ enum #define MASA_COH_LIMIT_2IDX 144 /* limit for sum of values across components for having two joint indexes */ #define QMETADATA_MAX_NO_DIRECTIONS 2 #define MASA_MAX_BITS 1300 /* max. bit-budget for MASA metadata */ + +#ifdef HR_METADATA +#define MASA_MAX_BITS_HR 2000 /* max. bit-budget for MASA metadata in HR mode*/ +#define HR_MASA_ER_LEVELS 16 +#endif + #define LIMIT_ER_ELEVATION_ENC 4 #define LIMIT_ER_SIMPLE_ENC 6 #define LIMIT_USE_COMMON 3 @@ -1203,7 +1212,14 @@ enum #define MASA_STEREO_MIN_BITRATE IVAS_24k4 #define MASA_BIT_REDUCT_PARAM 10 +#ifdef HR_METADATA +#define MASA_MAXIMUM_TWO_DIR_BANDS 24 +#ifdef HR_METADATA_HR_COH +#define NBITS_HR_COH 4 +#endif +#else #define MASA_MAXIMUM_TWO_DIR_BANDS 18 +#endif typedef enum { MASA_STEREO_NOT_DEFINED, diff --git a/lib_com/ivas_masa_com.c b/lib_com/ivas_masa_com.c index 3a53b2c682..66b296eeb2 100644 --- a/lib_com/ivas_masa_com.c +++ b/lib_com/ivas_masa_com.c @@ -415,3 +415,180 @@ void masa_sample_rate_band_correction( return; } + +#ifdef HR_METADATA +/* !r: output index for direction */ +uint16_t index_theta_phi_16( + float *p_theta, /* i/o : input elevation to be indexed */ + float *p_phi, /* i/o : input azimuth to be indexed */ + SPHERICAL_GRID_DATA *gridData /* i : generated grid data */ +) +{ + float abs_theta; + int16_t sign_th, id_phi, id_th; + uint16_t idx_sph; + uint16_t cum_n; + float theta_hat, phi_hat; + float theta, phi; + + theta = *p_theta; + phi = *p_phi; + phi_hat = 0; + theta_hat = 0; + phi = phi + 180; + + if ( theta < 0 ) + { + abs_theta = -theta; + sign_th = -1; + } + else + { + abs_theta = theta; + sign_th = 1; + } + + id_th = quantize_theta( abs_theta, gridData->no_theta, &theta_hat ); + if ( gridData->no_theta > 1 ) + { + if ( gridData->no_phi[id_th] > 1 ) + { + id_phi = quantize_phi_masa( phi, ( id_th % 2 == 1 ), &phi_hat, gridData->no_phi[id_th] ); + } + else + { + id_phi = 0; + phi_hat = 180; + } + } + else + { + id_phi = quantize_phi_masa( phi, ( id_th % 2 == 1 ), &phi_hat, gridData->no_phi[id_th] ); + } + *p_theta = sign_th * theta_hat; + *p_phi = phi_hat - 180; + + /* Starting from Equator, alternating positive and negative */ + if ( id_th == 0 ) + { + idx_sph = id_phi; + } + else + { + if ( id_th == gridData->no_theta - 1 ) + { + idx_sph = 65534 + ( sign_th < 0 ); + } + else + { + theta = MASA_ANGLE_AT_EQUATOR * (float) ( id_th + 0.5f ); + if ( id_th == 1 ) + { + cum_n = 2 * (uint16_t) ceilf( MASA_NTOT2_FAC * ( sinf( theta ) - MASA_ASIN_OFFSET ) ); + } + else + { + cum_n = 2 * (uint16_t) roundf( MASA_NTOT2_FAC * ( sinf( theta ) - MASA_ASIN_OFFSET ) ); + } + + cum_n += gridData->no_phi[0]; + + if ( sign_th > 0 ) + { + cum_n -= 2 * gridData->no_phi[id_th]; + } + else + { + cum_n -= gridData->no_phi[id_th]; + } + idx_sph = cum_n + id_phi; + } + } + + + return idx_sph; +} + +int16_t quantize_theta( + float x, /* i : theta value to be quantized */ + int16_t no_cb, /* i : number of codewords */ + float *xhat /* o : quantized value */ +) +{ + int16_t imin; + float diff1, diff2; + + imin = (int16_t) ( x * MASA_INV_ANGLE_AT_EQUATOR_DEG + 0.5f ); + + if ( imin >= no_cb - 1 ) + { + imin = no_cb - 1; + diff1 = x - 90; + diff2 = x - MASA_ANGLE_AT_EQUATOR_DEG * ( imin - 1 ); + if ( fabsf( diff1 ) > fabsf( diff2 ) ) + { + imin--; + *xhat = imin * MASA_ANGLE_AT_EQUATOR_DEG; + } + else + { + *xhat = 90; + } + } + else + { + *xhat = imin * MASA_ANGLE_AT_EQUATOR_DEG; + } + + return imin; +} + + +/* !r: index azimuth */ +int16_t quantize_phi_masa( + float phi, /* i : azimuth value */ + int16_t flag_delta, /* i : flag indicating if the azimuth codebook is translated or not */ + float *phi_hat, /* o : quantized azimuth */ + const int16_t n /* i : azimuth codebook size */ +) +{ + int16_t id_phi; + float dd; + float delta_phi; + + delta_phi = 360.0f / (float) n; + + if ( n == 1 ) + { + *phi_hat = 0; + + return 0; + } + + if ( flag_delta == 1 ) + { + dd = delta_phi / 2.0f; + } + else + { + dd = 0; + } + + id_phi = (int16_t) ( ( phi - dd + delta_phi / 2.0f ) / (float) delta_phi ); + + if ( id_phi == n ) + { + id_phi = 0; + } + + if ( id_phi == -1 ) + { + id_phi = n - 1; + } + + *phi_hat = id_phi * delta_phi + dd; + + return id_phi; +} + +#endif \ No newline at end of file diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 2e7bc2799c..acf3a032b6 100755 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -2986,6 +2986,58 @@ ivas_error ivas_qmetadata_enc_encode( IVAS_QMETADATA *hQMetaData /* i/o: q_metadata handle */ ); +#ifdef HR_METADATA +ivas_error ivas_qmetadata_enc_encode_hr( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *hQMetaData /* i/o: q_metadata handle */ +); + +ivas_error ivas_qmetadata_enc_encode_hr_512( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *hQMetaData /* i/o: metadata handle */ +); + +void deindex_sph_idx( + const uint16_t sphIndex, /* i : Spherical index */ + const SPHERICAL_GRID_DATA *gridData, /* i : Prepared spherical grid */ + float *theta, /* o : Elevation */ + float *phi /* o : Azimuth */ +); + +int16_t ivas_qmetadata_dec_decode_hr_512( + IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, /* i/o: bitstream position */ + SPHERICAL_GRID_DATA *sph_grid16 /* i: spherical grid for deindexing */ +); + +int16_t ivas_qmetadata_dec_decode_hr( + IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ + uint16_t *bitstream, /* i : bitstream */ + int16_t *index /* i/o: bitstream position */ +); + +uint16_t index_theta_phi_16( + float * p_theta, /* i/o : input elevation to be indexed */ + float * p_phi, /* i/o : input azimuth to be indexed */ + SPHERICAL_GRID_DATA *gridData /* i : generated grid data */ +); + + int16_t quantize_theta( + float x, /* i : theta value to be quantized */ + int16_t no_cb, /* i : number of codewords */ + float *xhat /* o : quantized value */ +); + +/* !r: index azimuth */ + int16_t quantize_phi_masa( + float phi, /* i : azimuth value */ + int16_t flag_delta, /* i : flag indicating if the azimuth codebook is translated or not */ + float *phi_hat, /* o : quantized azimuth */ + const int16_t n /* i : azimuth codebook size */ +); +#endif + void reset_metadata_spatial( const IVAS_FORMAT ivas_format, /* i : IVAS format */ BSTR_ENC_HANDLE hMetaData, /* i/o: Metadata bitstream handle */ @@ -3012,6 +3064,8 @@ int16_t ivas_qmetadata_dec_decode( int16_t *index /* i/o: bitstream position */ ); + + /*! r: number of bits read */ int16_t ivas_qmetadata_dec_sid_decode( IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */ @@ -3086,6 +3140,10 @@ void quantize_direction_frame( IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */ float azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], float elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES] +#ifdef HR_METADATA + , + int16_t is_hr +#endif ); /* !r: quantized spherical index */ diff --git a/lib_com/ivas_rom_com.c b/lib_com/ivas_rom_com.c index f04538c479..b9e625238f 100644 --- a/lib_com/ivas_rom_com.c +++ b/lib_com/ivas_rom_com.c @@ -2531,7 +2531,48 @@ const uint16_t ivas_param_mc_sym_freq_ild_delta_combined_48_16bits[2 * PARAM_MC_ /*----------------------------------------------------------------------------------* * MASA ROM tables *----------------------------------------------------------------------------------*/ - +#ifdef HR_METADATA + +const float diffuseness_reconstructions_hr[HR_MASA_ER_LEVELS] = +{ + 0.00f, + 0.0142822265625f, + 0.030029296875f, + 0.052001953125f, + 0.07708740234375f, + 0.10528564453125f, + 0.14483642578125f, + 0.19573974609375f, + 0.26568603515625f, + 0.35467529296875f, + 0.436279296875f, + 0.510498046875f, + 0.5943603515625f, + 0.6878662109375f, + 0.80096435546875f, + 0.93365478515625f +}; +const float diffuseness_thresholds_hr[HR_MASA_ER_LEVELS + 1] = +{ + 0.0f, + 0.009521484375f, + 0.01904296875f, + 0.0410156250f, + 0.06298828125f, + 0.0911865234375f, + 0.119384765625f, + 0.1702880859375f, + 0.22119140625f, + 0.3101806640625f, + 0.399169921875f, + 0.473388671875f, + 0.547607421875f, + 0.641113281250f, + 0.734619140625f, + 0.8673095703125f, + 2.0f /* out-of-range large value to make searching easier */ +}; +#endif const int16_t bits_direction_masa[DIRAC_DIFFUSE_LEVELS] = { 11, @@ -2544,6 +2585,7 @@ const int16_t bits_direction_masa[DIRAC_DIFFUSE_LEVELS] = 3 }; + const float coherence_cb0_masa[DIRAC_DIFFUSE_LEVELS * 2 * MASA_NO_CV_COH] = { /* this is the same */ @@ -2726,7 +2768,11 @@ const uint8_t masa_joined_nbands[IVAS_NUM_ACTIVE_BRATES] = const uint8_t masa_twodir_bands[IVAS_NUM_ACTIVE_BRATES] = { +#ifdef HR_METADATA + 0, 0, 0, 0, 0, 1, 1, 1, 3, 4, 6, 6, 9, 24 +#else 0, 0, 0, 0, 0, 1, 1, 1, 3, 4, 6, 6, 9, 12 +#endif }; const uint8_t masa_twodir_bands_joined[IVAS_NUM_ACTIVE_BRATES] = diff --git a/lib_com/ivas_rom_com.h b/lib_com/ivas_rom_com.h index a095c9e4b4..374e508480 100644 --- a/lib_com/ivas_rom_com.h +++ b/lib_com/ivas_rom_com.h @@ -293,6 +293,11 @@ extern const uint8_t masa_joined_nbands[]; extern const uint8_t masa_twodir_bands[]; extern const uint8_t masa_twodir_bands_joined[]; +#ifdef HR_METADATA +extern const float diffuseness_reconstructions_hr[HR_MASA_ER_LEVELS]; +extern const float diffuseness_thresholds_hr[HR_MASA_ER_LEVELS + 1]; +#endif + /* Multi-channel input and output setups */ extern const float ls_azimuth_CICP2[2]; extern const float ls_elevation_CICP2[2]; diff --git a/lib_com/ivas_stat_com.h b/lib_com/ivas_stat_com.h index 041a589ee3..f3c132c906 100644 --- a/lib_com/ivas_stat_com.h +++ b/lib_com/ivas_stat_com.h @@ -435,6 +435,9 @@ typedef struct ivas_masa_directional_spatial_meta_struct float elevation[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; float energy_ratio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; float spread_coherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; +#ifdef HR_METADATA + uint16_t spherical_index[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; +#endif } MASA_DIRECTIONAL_SPATIAL_META; @@ -510,7 +513,6 @@ typedef struct ivas_qdirection_band_coherence_data_struct uint8_t spread_coherence[MAX_PARAM_SPATIAL_SUBFRAMES]; uint16_t spread_coherence_dct0_index; uint16_t spread_coherence_dct1_index; - } IVAS_QDIRECTION_BAND_COHERENCE_DATA; typedef struct ivas_surround_coherence_band_data_struct diff --git a/lib_com/options.h b/lib_com/options.h index cce0aff460..44cf4a5cb1 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -170,6 +170,10 @@ #define ISSUE_24_CLEANUP_MCT_LFE /* Issue 24: Cleanup LFE path withing MCT */ +#define HR_METADATA /* Nok: encode directional MASA metadata with more bits at 384k and 512k */ +#ifdef HR_METADATA +#define HR_METADATA_HR_COH +#endif /* ################## End DEVELOPMENT switches ######################### */ /* clang-format on */ #endif diff --git a/lib_dec/ivas_masa_dec.c b/lib_dec/ivas_masa_dec.c index 3c7e490cbc..346adc3b2c 100644 --- a/lib_dec/ivas_masa_dec.c +++ b/lib_dec/ivas_masa_dec.c @@ -55,10 +55,11 @@ /*-----------------------------------------------------------------------* * Local function prototypes *-----------------------------------------------------------------------*/ - +#ifndef HR_METADATA static int16_t quantize_theta( float x, int16_t no_cb, float *xhat ); static uint16_t index_theta_phi_16( float theta, float phi, SPHERICAL_GRID_DATA *Sph_Grid16 ); static int16_t quantize_phi_masa( float phi, int16_t flag_delta, float *phi_hat, const int16_t n ); +#endif static void index_16bits( IVAS_QMETADATA_HANDLE hQMetaData, SPHERICAL_GRID_DATA *Sph_Grid16 ); #ifdef FIX_350_MASA_DELAY_COMP static void create_masa_ext_out_meta( MASA_DECODER *hMasa, IVAS_QMETADATA_HANDLE hQMetaData, const int16_t nchan_transport ); @@ -195,9 +196,26 @@ ivas_error ivas_masa_decode( /* Remove already read bits from the bit budget */ hQMetaData->metadata_max_bits -= *nb_bits_read; +#ifdef HR_METADATA + if ( ivas_total_brate >= IVAS_384k ) + { + if ( ivas_total_brate == IVAS_512k ) + { + *nb_bits_read += ivas_qmetadata_dec_decode_hr_512( hQMetaData, st->bit_stream, &st->next_bit_pos, hMasa->data.sph_grid16 ); + } + else + { + *nb_bits_read += ivas_qmetadata_dec_decode_hr( hQMetaData, st->bit_stream, &st->next_bit_pos ); + } + } + else + { - *nb_bits_read += ivas_qmetadata_dec_decode( hQMetaData, st->bit_stream, &st->next_bit_pos ); - +#endif + *nb_bits_read += ivas_qmetadata_dec_decode( hQMetaData, st->bit_stream, &st->next_bit_pos ); +#ifdef HR_METADATA + } +#endif /* Get direction decoding quality. EC 1 and 2 are handled by the default value. */ if ( hQMetaData->ec_flag == 2 ) { @@ -472,6 +490,19 @@ static ivas_error ivas_masa_dec_config( ivas_masa_set_elements( st_ivas->hDecoderConfig->ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, st_ivas->hQMetaData, &st_ivas->element_mode_init, &st_ivas->nSCE, &st_ivas->nCPE ); ivas_masa_set_coding_config( &( hMasa->config ), hMasa->data.band_mapping, st_ivas->hDecoderConfig->ivas_total_brate, st_ivas->nchan_transport, ( st_ivas->ivas_format == MC_FORMAT && st_ivas->mc_mode == MC_MODE_MCMASA ) ); + +#ifdef HR_METADATA + if ( st_ivas->ivas_format == MASA_FORMAT && st_ivas->hDecoderConfig->ivas_total_brate == IVAS_512k ) + { + hMasa->config.mergeRatiosOverSubframes = 0; + /* initialize spherical grid */ + if ( hMasa->data.sph_grid16 == NULL ) + { + hMasa->data.sph_grid16 = (SPHERICAL_GRID_DATA *) malloc( sizeof( SPHERICAL_GRID_DATA ) ); + generate_gridEq( hMasa->data.sph_grid16 ); + } + } +#endif st_ivas->hQMetaData->metadata_max_bits = hMasa->config.max_metadata_bits; st_ivas->hQMetaData->bandMap = hMasa->data.band_mapping; st_ivas->hQMetaData->nchan_transport = st_ivas->nchan_transport; @@ -553,7 +584,7 @@ void ivas_masa_prerender( /*-------------------------------------------------------------------* * Local functions *-------------------------------------------------------------------*/ - +#ifndef HR_METADATA /* !r: index of quantized value */ static int16_t quantize_theta( float x, /* i : theta value to be quantized */ @@ -722,7 +753,7 @@ static uint16_t index_theta_phi_16( return idx_sph; } - +#endif static void index_16bits( IVAS_QMETADATA_HANDLE hQMetaData, @@ -737,8 +768,8 @@ static void index_16bits( { for ( block = 0; block < hQMetaData->q_direction[0].cfg.nblocks; block++ ) { - hQMetaData->q_direction[d].band_data[band].spherical_index[block] = index_theta_phi_16( hQMetaData->q_direction[d].band_data[band].elevation[block], - hQMetaData->q_direction[d].band_data[band].azimuth[block], Sph_Grid16 ); + hQMetaData->q_direction[d].band_data[band].spherical_index[block] = index_theta_phi_16( &( hQMetaData->q_direction[d].band_data[band].elevation[block] ), + &( hQMetaData->q_direction[d].band_data[band].azimuth[block] ), Sph_Grid16 ); } } } diff --git a/lib_dec/ivas_qmetadata_dec.c b/lib_dec/ivas_qmetadata_dec.c index 9c6597fdcb..c4940a65d9 100644 --- a/lib_dec/ivas_qmetadata_dec.c +++ b/lib_dec/ivas_qmetadata_dec.c @@ -49,9 +49,19 @@ static int16_t ivas_qmetadata_entropy_decode_diffuseness( uint16_t *bitstream, i static int16_t ivas_qmetadata_entropy_decode_df_ratio( uint16_t *bitstream, int16_t *index, IVAS_QDIRECTION *q_direction, int16_t *dfRatio_bits ); -static int16_t ivas_qmetadata_entropy_decode_dir( IVAS_QDIRECTION *q_direction, uint16_t *bitstream, int16_t *index, const uint16_t diffuseness_index_max_ec_frame, const int16_t nbands, const int16_t start_band ); +static int16_t ivas_qmetadata_entropy_decode_dir( IVAS_QDIRECTION *q_direction, uint16_t *bitstream, int16_t *index, const uint16_t diffuseness_index_max_ec_frame, const int16_t nbands, const int16_t start_band +#ifdef HR_METADATA + , + int16_t is_hr +#endif +); -static int16_t ivas_qmetadata_raw_decode_dir( IVAS_QDIRECTION *q_direction, uint16_t *bitstream, int16_t *index, const int16_t nbands, const int16_t start_band ); +static int16_t ivas_qmetadata_raw_decode_dir( IVAS_QDIRECTION *q_direction, uint16_t *bitstream, int16_t *index, const int16_t nbands, const int16_t start_band +#ifdef HR_METADATA + , + int16_t is_hr +#endif +); static uint16_t ivas_qmetadata_DecodeQuasiUniform( const uint16_t *bitstream, int16_t *index, const uint16_t alphabet_size ); @@ -77,11 +87,21 @@ static int16_t read_truncGR_azimuth( uint16_t *bitstream, IVAS_QDIRECTION *q_dir static ivas_error read_huf( int16_t *num_bits_read, const uint16_t *bitstream, uint16_t *out, const int16_t start_pos, const int16_t len, const int16_t *huff_code, const int16_t max_len ); -static int16_t read_coherence_data( uint16_t *bitstream, int16_t *p_bit_pos, IVAS_QMETADATA *hQMetaData, const int16_t idx_dir ); +static int16_t read_coherence_data( uint16_t *bitstream, int16_t *p_bit_pos, IVAS_QMETADATA *hQMetaData, const int16_t idx_dir +#ifdef HR_METADATA + , + int16_t is_hr +#endif +); static int16_t read_surround_coherence( uint16_t *bitstream, int16_t *p_bit_pos, IVAS_QMETADATA *hQMetaData ); -static void decode_spread_coherence( IVAS_QMETADATA_HANDLE hQMetaData, int16_t idx_d, const int16_t no_frames ); +static void decode_spread_coherence( IVAS_QMETADATA_HANDLE hQMetaData, int16_t idx_d, const int16_t no_frames +#ifdef HR_METADATA + , + int16_t is_hr +#endif +); static void decode_combined_index( uint64_t comb_index, const int16_t *no_cv_vec, uint16_t *index, const int16_t len ); @@ -91,6 +111,44 @@ static int16_t read_GR_min_removed_data( uint16_t *bitstream, int16_t *p_bit_pos static int16_t decode_fixed_rate_composed_index_coherence( uint16_t *bitstream, int16_t *p_bit_pos, const int16_t no_bands, int16_t *no_cv_vec, uint16_t *decoded_index, const int16_t no_symb ); +#ifdef HR_METADATA + +static int16_t ivas_qmetadata_entropy_decode_diffuseness_hr( + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, + IVAS_QDIRECTION *q_direction, + uint16_t *diffuseness_index_max_ec_frame ); + + +static int16_t ivas_qmetadata_entropy_decode_diffuseness_hr_512( + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, + IVAS_QDIRECTION *q_direction ); + +static int16_t ivas_qmetadata_raw_decode_dir_512( + IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */ + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, + const int16_t nbands, + const int16_t start_band, + SPHERICAL_GRID_DATA *sph_grid16 /* i: spherical grid for deindexing */ +); +static int16_t read_surround_coherence_hr( + uint16_t *bitstream, /* i : bitstream */ + int16_t *p_bit_pos, /* i : position in the bitstream */ + IVAS_QMETADATA *hQMetaData /* i/o: quantized metadata structure */ +); +#ifdef HR_METADATA_HR_COH +/* !r: number of bits read */ +static int16_t read_coherence_data_hr_512( + uint16_t *bitstream, /* i : bitstream */ + int16_t *p_bit_pos, /* i : position in the bitstream */ + IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata structure */ + const int16_t idx_dir /* i : direction index */ +); +#endif +#endif + /*-----------------------------------------------------------------------* * Global function definitions *-----------------------------------------------------------------------*/ @@ -101,6 +159,7 @@ static int16_t decode_fixed_rate_composed_index_coherence( uint16_t *bitstream, * Main function for decoding Spatial Metadata *-----------------------------------------------------------------------*/ + /*! r: number of bits read */ int16_t ivas_qmetadata_dec_decode( IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ @@ -385,9 +444,15 @@ int16_t ivas_qmetadata_dec_decode( /* Read coherence, if any */ bits_coherence = 0; + if ( all_coherence_zero == 0 ) { - bits_coherence = read_coherence_data( bitstream, index, hQMetaData, d ); + bits_coherence = read_coherence_data( bitstream, index, hQMetaData, d +#ifdef HR_METADATA + , + 0 +#endif + ); } else { @@ -435,11 +500,21 @@ int16_t ivas_qmetadata_dec_decode( if ( raw_flag[0] == 0 ) { - bits_dir += ivas_qmetadata_entropy_decode_dir( q_direction, bitstream, index, diffuseness_index_max_ec_frame, nbands, start_band ); + bits_dir += ivas_qmetadata_entropy_decode_dir( q_direction, bitstream, index, diffuseness_index_max_ec_frame, nbands, start_band +#ifdef HR_METADATA + , + 0 +#endif + ); } else { - bits_dir += ivas_qmetadata_raw_decode_dir( q_direction, bitstream, index, nbands, start_band ); + bits_dir += ivas_qmetadata_raw_decode_dir( q_direction, bitstream, index, nbands, start_band +#ifdef HR_METADATA + , + 0 +#endif + ); } } /* Decode quantized directions band-wise */ @@ -459,7 +534,12 @@ int16_t ivas_qmetadata_dec_decode( { if ( raw_flag[b] == 0 ) { - bits_dir += ivas_qmetadata_entropy_decode_dir( q_direction, bitstream, index, diffuseness_index_max_ec_frame, b + 1, b ); + bits_dir += ivas_qmetadata_entropy_decode_dir( q_direction, bitstream, index, diffuseness_index_max_ec_frame, b + 1, b +#ifdef HR_METADATA + , + 0 +#endif + ); } else { @@ -503,7 +583,12 @@ int16_t ivas_qmetadata_dec_decode( { if ( raw_flag[b] ) { - bits_dir += ivas_qmetadata_raw_decode_dir( q_direction, bitstream, index, b + 1, b ); + bits_dir += ivas_qmetadata_raw_decode_dir( q_direction, bitstream, index, b + 1, b +#ifdef HR_METADATA + , + 0 +#endif + ); } } } @@ -537,7 +622,12 @@ int16_t ivas_qmetadata_dec_decode( { if ( nblocks > 1 ) { - decode_spread_coherence( hQMetaData, d, nblocks ); + decode_spread_coherence( hQMetaData, d, nblocks +#ifdef HR_METADATA + , + 0 +#endif + ); } } else @@ -670,170 +760,894 @@ int16_t ivas_qmetadata_dec_decode( hQMetaData->dir_comp_ratio = 1.0f; } + return ( start_index_0 - *index ); } - -/*-----------------------------------------------------------------------* - * ivas_qmetadata_dec_sid_decode() - * - * Main function for decoding SID for Spatial Metadata - *-----------------------------------------------------------------------*/ - -/*! r: number of bits written */ -int16_t ivas_qmetadata_dec_sid_decode( - IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */ - uint16_t *bitstream, /* i : bitstream */ - int16_t *index, /* i/o: bitstream position */ - const int16_t nchan_transport, /* i : number of transport channels */ - int16_t *element_mode, /* o : element mode */ - const int16_t ivas_format, /* i : IVAS format */ - const SBA_MODE sba_mode /* i : SBA mode */ +#ifdef HR_METADATA +/*! r: number of bits read */ +int16_t ivas_qmetadata_dec_decode_hr( + IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ + uint16_t *bitstream, /* i : bitstream */ + int16_t *index /* i/o: bitstream position */ ) { - int16_t b, m, i; - uint16_t value; - uint16_t diffuseness_index[DIRAC_MAX_NBANDS]; + int16_t d, b, m; + uint16_t diffuseness_index_max_ec_frame; + uint16_t diffuseness_index_max_ec_frame_pre[QMETADATA_MAX_NO_DIRECTIONS]; + // int16_t bits_dir_raw_pre[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t dir2band; + int16_t bits_diff_sum; + int16_t bits_coherence; + int16_t nbands, nblocks, start_band; IVAS_QDIRECTION *q_direction; - int16_t start_index; - float avg_elevation, avg_azimuth; - float avg_direction_vector[3]; - float direction_vector[3]; - int16_t metadata_sid_bits; /* bits allocated to SID for metadata */ + int16_t start_index_0; + + int16_t signal_bits; + int16_t bits_no_dirs_coh, bits_sur_coherence; + uint16_t all_coherence_zero; + int16_t ec_flag; + int16_t dfRatio_bits[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t no_TF; + int16_t p[MASA_MAXIMUM_CODING_SUBBANDS], dif_p[MASA_MAXIMUM_CODING_SUBBANDS]; + + #ifdef DEBUG_MODE_QMETADATA static FILE *pF = NULL; static FILE *pF_azi = NULL; static FILE *pF_ele = NULL; static FILE *pF_ratio = NULL; + static FILE *pF_spcoh = NULL; + static FILE *pF_surcoh = NULL; if ( pF == NULL ) - pF = fopen( "./res/qmetadata_sid_dec.txt", "w" ); + pF = fopen( "./res/qmetadata_dec.txt", "w" ); if ( pF_azi == NULL ) - pF_azi = fopen( "./res/qmetadata_sid_azi_dec.txt", "w" ); + pF_azi = fopen( "./res/qmetadata_azi_dec.txt", "w" ); if ( pF_ele == NULL ) - pF_ele = fopen( "./res/qmetadata_sid_ele_dec.txt", "w" ); + pF_ele = fopen( "./res/qmetadata_ele_dec.txt", "w" ); if ( pF_ratio == NULL ) - pF_ratio = fopen( "./res/qmetadata_sid_ratio_dec.txt", "w" ); + pF_ratio = fopen( "./res/qmetadata_ratio_dec.txt", "w" ); + if ( pF_spcoh == NULL ) + pF_spcoh = fopen( "./res/qmetadata_spcoh_dec.txt", "w" ); + if ( pF_surcoh == NULL ) + pF_surcoh = fopen( "./res/qmetadata_surcoh_dec.txt", "w" ); #endif - if ( ivas_format == SBA_FORMAT ) - { - if ( sba_mode == SBA_MODE_SPAR ) - { - /* TODO: still use old sid frame size to keep bitexactness */ - metadata_sid_bits = (int16_t) ( 5000 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - ( SPAR_DTX_BANDS * 18 ) - 1; /* -1 for inactive mode header bit*/ - } - else - { - /* keep 13.2 and 16.4 sid bitrate as 4.4 kbps for now*/ - /* TODO: still use old sid frame size to keep bitexactness */ - metadata_sid_bits = ( 4400 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; - } - } - else + ec_flag = 0; + start_index_0 = *index; + + /*Coherence flag decoding*/ + bits_no_dirs_coh = 0; + all_coherence_zero = 1; + if ( hQMetaData->coherence_flag ) { - /* TODO: still use old sid frame size to keep bitexactness */ - metadata_sid_bits = ( 4400 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; + /* read if coherence is zero */ + all_coherence_zero = bitstream[( *index )--]; + bits_no_dirs_coh += 1; } - start_index = *index; + hQMetaData->all_coherence_zero = (uint8_t) all_coherence_zero; - /* read MASA SID descriptor */ - if ( ivas_format == MASA_FORMAT && nchan_transport == 2 ) /* corresponding to SID_MASA case; Todo: needs to be checked for SBA */ + if ( hQMetaData->no_directions == 2 ) { - b = bitstream[( *index )--]; - if ( b ) - { - *element_mode = IVAS_CPE_MDCT; - } - else + /* Read which bands have 2 directions */ + hQMetaData->q_direction[1].cfg.nbands = hQMetaData->numTwoDirBands; + set_c( (int8_t *) hQMetaData->twoDirBands, 0, hQMetaData->q_direction[0].cfg.nbands ); + d = *index; + dif_p[0] = ivas_qmetadata_DecodeExtendedGR( bitstream, index, MASA_MAXIMUM_CODING_SUBBANDS, 0 ); + p[0] = dif_p[0]; + hQMetaData->twoDirBands[p[0]] = 1; + for ( b = 1; b < hQMetaData->numTwoDirBands; b++ ) { - *element_mode = IVAS_CPE_DFT; + dif_p[b] = ivas_qmetadata_DecodeExtendedGR( bitstream, index, MASA_MAXIMUM_CODING_SUBBANDS, 0 ); + p[b] = p[b - 1] + dif_p[b] + 1; + hQMetaData->twoDirBands[p[b]] = 1; } + bits_no_dirs_coh += ( d - *index ); } - /* Fix configuration for SID */ - q_direction = &hQMetaData->q_direction[0]; /* only 1 direction */ - - if ( sba_mode == SBA_MODE_SPAR ) - { - nbands = DIRAC_DTX_BANDS; /* only 2 bands transmitted */ - } - else - { - nbands = 5; /* only 5 bands transmitted */ - } - - nblocks = q_direction->cfg.nblocks; /* only 1 block transmitted but up to 4 blocks re-generated */ - start_band = 0; /* start from band 0 */ - - /* Read 2D signaling*/ - if ( sba_mode != SBA_MODE_SPAR ) - { - q_direction->not_in_2D = bitstream[( *index )--]; - } - else - { - q_direction->not_in_2D = 1; - } - /* Decode diffuseness*/ - for ( b = start_band; b < nbands; b++ ) - { - diffuseness_index[b] = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, DIRAC_DIFFUSE_LEVELS - 4 ) + 4; - q_direction->band_data[b].energy_ratio_index[0] = diffuseness_index[b]; - q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[diffuseness_index[b]]; - q_direction->band_data[b].azimuth_m_alphabet[0] = no_phi_masa[q_direction->band_data[b].bits_sph_idx[0] - 1][0]; - } + bits_diff_sum = ivas_qmetadata_entropy_decode_diffuseness_hr( bitstream, index, &( hQMetaData->q_direction[0] ), &diffuseness_index_max_ec_frame_pre[0] ); - for ( b = start_band; b < nbands; b++ ) + if ( hQMetaData->no_directions == 2 ) { - q_direction->band_data[b].energy_ratio[0] = 1.0f - diffuseness_reconstructions[diffuseness_index[b]]; - for ( i = 0; i < nblocks; i++ ) + /* Calculate bits for dfRatio */ + dir2band = 0; + for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) { - q_direction->band_data[b].energy_ratio[i] = q_direction->band_data[b].energy_ratio[0]; + if ( hQMetaData->twoDirBands[b] == 1 ) + { + dfRatio_bits[dir2band] = ivas_get_df_ratio_bits( hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0] >> 1 ); + dir2band++; + } } + + bits_diff_sum += ivas_qmetadata_entropy_decode_df_ratio( bitstream, index, &( hQMetaData->q_direction[1] ), dfRatio_bits ); } - /* Decoder DOAs*/ - if ( q_direction->not_in_2D > 0 ) + /* Calculate direct-to-total energy ratios for both directions from diffuse-to-total ratio and distribution factor of direct-to-total ratios */ + if ( hQMetaData->no_directions == 2 ) { - for ( b = start_band; b < nbands; b++ ) + dir2band = 0; + for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) { - value = 0; - for ( i = 0; i < q_direction->band_data[b].bits_sph_idx[0]; i++ ) - { - value = ( value << 1 ) + bitstream[( *index )--]; - } - for ( i = 0; i < nblocks; i++ ) + if ( hQMetaData->twoDirBands[b] == 1 ) { - q_direction->band_data[b].spherical_index[i] = value; - } + float diffRatio, dfRatio, dir1ratio, dir2ratio; + int16_t dfRatio_qsteps; - deindex_spherical_component( q_direction->band_data[b].spherical_index[0], &avg_azimuth, &avg_elevation, - &q_direction->band_data[b].azimuth_index[0], &q_direction->band_data[b].elevation_index[0], q_direction->band_data[b].bits_sph_idx[0], - q_direction->cfg.mc_ls_setup ); + diffRatio = diffuseness_reconstructions_hr[hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]]; + dfRatio_qsteps = 1 << dfRatio_bits[dir2band]; + dfRatio = usdequant( hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[0], 0.5f, 0.5f / ( dfRatio_qsteps - 1 ) ); - ivas_qmetadata_azimuth_elevation_to_direction_vector( avg_azimuth, avg_elevation, avg_direction_vector ); - ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[b].azimuth[nblocks - 1], q_direction->band_data[b].elevation[nblocks - 1], direction_vector ); - for ( m = 0; m < nblocks - 1; m++ ) + dir1ratio = dfRatio * ( 1.0f - diffRatio ); + dir2ratio = ( 1.0f - diffRatio ) - dir1ratio; + + /* Requantize the 1 - dirRatio separately for each direction to obtain inverted dirRatio index. These are used in further decoding. */ + hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0] = masa_sq( 1.0f - dir1ratio, diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[0] = masa_sq( 1.0f - dir2ratio, diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + + for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio[m] = dir1ratio; + hQMetaData->q_direction[0].band_data[b].energy_ratio_index[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; + } + + for ( m = 0; m < hQMetaData->q_direction[1].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[m] = dir2ratio; + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[m] = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[0]; + } + + dir2band++; + } + else { - v_add( direction_vector, avg_direction_vector, direction_vector, 3 ); - ivas_qmetadata_direction_vector_to_azimuth_elevation( direction_vector, &q_direction->band_data[b].azimuth[m], &q_direction->band_data[b].elevation[m] ); + /* 1dir band */ + hQMetaData->q_direction[0].band_data[b].energy_ratio[0] = 1.0f - diffuseness_reconstructions_hr[hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]]; + for ( m = 1; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio[0]; + hQMetaData->q_direction[0].band_data[b].energy_ratio_index[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; + } } - ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector, &q_direction->band_data[b].azimuth[nblocks - 1], &q_direction->band_data[b].elevation[nblocks - 1] ); } } else { - for ( b = start_band; b < nbands; b++ ) + /* With 1dir band, the decoded index is directly diffuseness and we can decode to direct-to-total ratio with 1 - diff. */ + for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) { - q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 5, q_direction->band_data[b].bits_sph_idx[0] ) ); - q_direction->band_data[b].azimuth_index[0] = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, q_direction->band_data[b].azimuth_m_alphabet[0] ); - q_direction->band_data[b].azimuth_index[0] = ivas_qmetadata_dereorder_generic( q_direction->band_data[b].azimuth_index[0] ) + ( q_direction->band_data[b].azimuth_m_alphabet[0] >> 1 ); - avg_azimuth = 360.0f / (float) ( q_direction->band_data[b].azimuth_m_alphabet[0] ) * q_direction->band_data[b].azimuth_index[0] - 180; - + hQMetaData->q_direction[0].band_data[b].energy_ratio[0] = 1.0f - diffuseness_reconstructions_hr[hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]]; + for ( m = 1; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio[0]; + hQMetaData->q_direction[0].band_data[b].energy_ratio_index[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; + } + } + } + + /* To decode directions correctly for 2dir bands, we need to obtain the compensated direct-to-total ratios and their + * corresponding inverted indices. */ + + dir2band = 0; + for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + if ( hQMetaData->no_directions == 2 && hQMetaData->twoDirBands[b] == 1 ) + { + int16_t index_dirRatio1Inv, index_dirRatio2Inv, index_dirRatio1Inv_mod, index_dirRatio2Inv_mod; + + index_dirRatio1Inv = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; + index_dirRatio2Inv = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[0]; + + masa_compensate_two_dir_energy_ratio_index( index_dirRatio1Inv, index_dirRatio2Inv, &index_dirRatio1Inv_mod, &index_dirRatio2Inv_mod ); + + for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio_index_mod[m] = index_dirRatio1Inv_mod; + hQMetaData->q_direction[0].band_data[b].bits_sph_idx[m] = bits_direction_masa[0]; + } + + for ( m = 0; m < hQMetaData->q_direction[1].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index_mod[m] = index_dirRatio2Inv_mod; + hQMetaData->q_direction[1].band_data[dir2band].bits_sph_idx[m] = bits_direction_masa[0]; + } + + dir2band++; + } + else + { + for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio_index_mod[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; + hQMetaData->q_direction[0].band_data[b].bits_sph_idx[m] = bits_direction_masa[0]; + } + } + } + + if ( hQMetaData->no_directions == 2 ) + { + no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks + hQMetaData->q_direction[1].cfg.nbands * hQMetaData->q_direction[1].cfg.nblocks; + if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - bits_diff_sum >= MASA_MIN_BITS_SURR_COH ) ) + { + bits_sur_coherence = read_surround_coherence( bitstream, index, hQMetaData ); + } + else + { + bits_sur_coherence = 0; + /*Surround coherence*/ + for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[b].surround_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + } + } + } + bits_no_dirs_coh += bits_sur_coherence; + } + else + { + no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks; + if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - bits_diff_sum >= MASA_MIN_BITS_SURR_COH ) ) + { + bits_sur_coherence = read_surround_coherence( bitstream, index, hQMetaData ); + } + else + { + bits_sur_coherence = 0; + /*Surround coherence*/ + for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[b].surround_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + } + } + } + bits_no_dirs_coh += bits_sur_coherence; + } + + + for ( d = 0; d < hQMetaData->no_directions; d++ ) + { + q_direction = &hQMetaData->q_direction[d]; + nbands = q_direction->cfg.nbands; + nblocks = q_direction->cfg.nblocks; + start_band = q_direction->cfg.start_band; + + diffuseness_index_max_ec_frame = diffuseness_index_max_ec_frame_pre[0]; + + /* Read coherence, if any */ + bits_coherence = 0; + + if ( all_coherence_zero == 0 ) + { + bits_coherence = read_coherence_data( bitstream, index, hQMetaData, d, 1 ); + } + else + { + /*Surround coherence*/ + for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[b].surround_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + } + + if ( hQMetaData->q_direction[d].coherence_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->q_direction[d].coherence_band_data[b].spread_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + } + } + } + + /* Read 2D signaling*/ + q_direction->not_in_2D = bitstream[( *index )--]; + signal_bits = 1; + + /* Read EC signaling */ + ec_flag = 0; + /* if ( total_bits_1dir + bits_sur_coherence <= hQMetaData->qmetadata_max_bit_req ) */ + { + ec_flag = bitstream[( *index )--]; + signal_bits++; + } + + /* Decode quantized directions frame-wise */ + if ( ec_flag == 0 ) /* EC 1*/ + { + ivas_qmetadata_entropy_decode_dir( q_direction, bitstream, index, diffuseness_index_max_ec_frame, nbands, start_band, 1 ); + } + else + { + ivas_qmetadata_raw_decode_dir( q_direction, bitstream, index, nbands, start_band, 1 ); + } + + + if ( bits_coherence > 0 ) + { + if ( nblocks > 1 ) + { + decode_spread_coherence( hQMetaData, d, nblocks, 0 ); + } + } + else + { + for ( b = start_band; b < nbands; b++ ) + { + if ( q_direction->coherence_band_data != NULL ) + { + set_c( (int8_t *) q_direction->coherence_band_data[b].spread_coherence, 0, nblocks ); + } + } + } + + +#ifdef DEBUG_MODE_QMETADATA + fprintf( pF, "frame %d: coh %d surcoh %d ", frame, bits_coherence, bits_sur_coherence ); + fprintf( pF, "dir %d %d\n", ec_flag, start_index_0 - *index ); + + fprintf( pF_azi, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); + fprintf( pF_ele, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); + fprintf( pF_ratio, "frame %d/dir %d: ", frame, d ); + fprintf( pF_spcoh, "frame %d/dir %d: ", frame, d ); + if ( d == 0 ) + { + fprintf( pF_surcoh, "frame %d/dir %d: ", frame, d ); + } + for ( b = start_band; b < nbands; b++ ) + { + for ( m = 0; m < q_direction->cfg.nblocks; m++ ) + { + fprintf( pF_azi, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].azimuth[m] ) / 100.f ); + fprintf( pF_ele, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].elevation[m] ) / 100.f ); + fprintf( pF_ratio, " %1.3f ", q_direction->band_data[b].energy_ratio[m] ); + if ( q_direction->coherence_band_data != NULL ) + { + fprintf( pF_spcoh, " %d ", q_direction->coherence_band_data[b].spread_coherence[m] ); + } + if ( d == 0 && hQMetaData->surcoh_band_data != NULL ) + { + fprintf( pF_surcoh, " %d ", hQMetaData->surcoh_band_data[b].surround_coherence[m] ); + } + } + } + fprintf( pF_azi, "\n" ); + fprintf( pF_ele, "\n" ); + fprintf( pF_ratio, "\n" ); + fprintf( pF_spcoh, "\n" ); + if ( d == 0 ) + { + fprintf( pF_surcoh, "\n" ); + } +#endif + } + /* move 2 dir data to its correct subband */ + if ( hQMetaData->no_directions == 2 ) + { + d = hQMetaData->q_direction[1].cfg.nbands - 1; + nblocks = hQMetaData->q_direction[0].cfg.nblocks; + + for ( b = hQMetaData->q_direction[0].cfg.nbands - 1; b >= 0; b-- ) + { + if ( hQMetaData->twoDirBands[b] == 1 ) + { + mvr2r( hQMetaData->q_direction[1].band_data[d].azimuth, hQMetaData->q_direction[1].band_data[b].azimuth, nblocks ); + mvr2r( hQMetaData->q_direction[1].band_data[d].elevation, hQMetaData->q_direction[1].band_data[b].elevation, nblocks ); + mvr2r( hQMetaData->q_direction[1].band_data[d].energy_ratio, hQMetaData->q_direction[1].band_data[b].energy_ratio, nblocks ); + + if ( hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0] < 7 ) + { + for ( m = 0; m < nblocks; m++ ) + { + hQMetaData->q_direction[1].band_data[b].azimuth[m] += hQMetaData->q_direction[0].band_data[b].azimuth[m] - 180; + if ( hQMetaData->q_direction[1].band_data[b].azimuth[m] >= 180 ) + { + hQMetaData->q_direction[1].band_data[b].azimuth[m] -= 360; + } + if ( hQMetaData->q_direction[1].band_data[b].azimuth[m] < -180 ) + { + hQMetaData->q_direction[1].band_data[b].azimuth[m] += 360; + } + } + } + + if ( hQMetaData->q_direction[1].coherence_band_data != NULL ) + { + mvc2c( hQMetaData->q_direction[1].coherence_band_data[d].spread_coherence, hQMetaData->q_direction[1].coherence_band_data[b].spread_coherence, nblocks ); + } + d--; + } + else + { + set_f( hQMetaData->q_direction[1].band_data[b].azimuth, 0.0f, nblocks ); + set_f( hQMetaData->q_direction[1].band_data[b].elevation, 0.0f, nblocks ); + set_f( hQMetaData->q_direction[1].band_data[b].energy_ratio, 0.0f, nblocks ); + + if ( hQMetaData->q_direction[1].coherence_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->q_direction[1].coherence_band_data[b].spread_coherence, 0, nblocks ); + } + } + } + + /* Scale energy ratios that sum to over one */ + for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + float ratioSum; + + ratioSum = hQMetaData->q_direction[0].band_data[b].energy_ratio[0] + hQMetaData->q_direction[1].band_data[b].energy_ratio[0]; + + if ( ratioSum > 1.0f ) + { + set_f( hQMetaData->q_direction[0].band_data[b].energy_ratio, hQMetaData->q_direction[0].band_data[b].energy_ratio[0] / ratioSum, nblocks ); + set_f( hQMetaData->q_direction[1].band_data[b].energy_ratio, hQMetaData->q_direction[1].band_data[b].energy_ratio[0] / ratioSum, nblocks ); + } + } + } + + /* Store status information for renderer use */ + hQMetaData->ec_flag = ec_flag; + + hQMetaData->dir_comp_ratio = 1.0f; + + if ( hQMetaData->dir_comp_ratio > 1.0f ) + { + hQMetaData->dir_comp_ratio = 1.0f; + } + + + return ( start_index_0 - *index ); +} + +/*! r: number of bits read */ +int16_t ivas_qmetadata_dec_decode_hr_512( + IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, /* i/o: bitstream position */ + SPHERICAL_GRID_DATA *sph_grid16 /* i: sphericla grid for deindexing */ +) +{ + int16_t d, b, m; + + int16_t bits_diff_sum; +#ifndef HR_METADATA_HR_COH + int16_t bits_coherence; + int16_t nblocks; +#endif + int16_t nbands, start_band; + IVAS_QDIRECTION *q_direction; + int16_t start_index_0; + int16_t bits_no_dirs_coh, bits_sur_coherence; + uint16_t all_coherence_zero; + + +#ifdef DEBUG_MODE_QMETADATA + static FILE *pF = NULL; + static FILE *pF_azi = NULL; + static FILE *pF_ele = NULL; + static FILE *pF_ratio = NULL; + static FILE *pF_spcoh = NULL; + static FILE *pF_surcoh = NULL; + + if ( pF == NULL ) + pF = fopen( "./res/qmetadata_dec.txt", "w" ); + if ( pF_azi == NULL ) + pF_azi = fopen( "./res/qmetadata_azi_dec.txt", "w" ); + if ( pF_ele == NULL ) + pF_ele = fopen( "./res/qmetadata_ele_dec.txt", "w" ); + if ( pF_ratio == NULL ) + pF_ratio = fopen( "./res/qmetadata_ratio_dec.txt", "w" ); + if ( pF_spcoh == NULL ) + pF_spcoh = fopen( "./res/qmetadata_spcoh_dec.txt", "w" ); + if ( pF_surcoh == NULL ) + pF_surcoh = fopen( "./res/qmetadata_surcoh_dec.txt", "w" ); +#endif + + start_index_0 = *index; + + /*Coherence flag decoding*/ + bits_no_dirs_coh = 0; + all_coherence_zero = 1; + if ( hQMetaData->coherence_flag ) + { + /* read if coherence is zero */ + all_coherence_zero = bitstream[( *index )--]; + bits_no_dirs_coh += 1; + } + + hQMetaData->all_coherence_zero = (uint8_t) all_coherence_zero; + + if ( hQMetaData->no_directions == 2 ) + { + set_c( (int8_t *) hQMetaData->twoDirBands, 1, hQMetaData->q_direction[0].cfg.nbands ); + } + + + bits_diff_sum = ivas_qmetadata_entropy_decode_diffuseness_hr_512( bitstream, index, &( hQMetaData->q_direction[0] ) ); + + if ( hQMetaData->no_directions == 2 ) + { + bits_diff_sum += ivas_qmetadata_entropy_decode_diffuseness_hr_512( bitstream, index, &( hQMetaData->q_direction[1] ) ); + } + + + for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio[m] = 1.0f - diffuseness_reconstructions_hr[hQMetaData->q_direction[0].band_data[b].energy_ratio_index[m]]; + } + } + if ( hQMetaData->no_directions == 2 ) + { + for ( b = hQMetaData->q_direction[1].cfg.start_band; b < hQMetaData->q_direction[1].cfg.nbands; b++ ) + { + for ( m = 0; m < hQMetaData->q_direction[1].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[1].band_data[b].energy_ratio[m] = 1.0f - diffuseness_reconstructions_hr[hQMetaData->q_direction[1].band_data[b].energy_ratio_index[m]]; + if ( hQMetaData->q_direction[1].band_data[b].energy_ratio[m] > 1.0f - hQMetaData->q_direction[0].band_data[b].energy_ratio[m] ) + { + hQMetaData->q_direction[1].band_data[b].energy_ratio[m] = 1.0f - hQMetaData->q_direction[0].band_data[b].energy_ratio[m]; + } + } + } + } + + if ( hQMetaData->no_directions == 2 ) + { + for ( b = hQMetaData->q_direction[1].cfg.start_band; b < hQMetaData->q_direction[1].cfg.nbands; b++ ) + { + for ( m = 0; m < hQMetaData->q_direction[1].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[1].band_data[b].energy_ratio_index_mod[m] = hQMetaData->q_direction[1].band_data[b].energy_ratio_index[m]; + hQMetaData->q_direction[1].band_data[b].bits_sph_idx[m] = 16; + } + } + } + + for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio_index_mod[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; + hQMetaData->q_direction[0].band_data[b].bits_sph_idx[m] = 16; + } + } + + + if ( all_coherence_zero == 0 ) + { + bits_sur_coherence = read_surround_coherence_hr( bitstream, index, hQMetaData ); + } + else + { + bits_sur_coherence = 0; + /*Surround coherence*/ + for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[b].surround_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + } + } + } + bits_no_dirs_coh += bits_sur_coherence; + + + for ( d = 0; d < hQMetaData->no_directions; d++ ) + { + q_direction = &hQMetaData->q_direction[d]; + nbands = q_direction->cfg.nbands; + start_band = q_direction->cfg.start_band; + + + /* Read coherence, if any */ +#ifndef HR_METADATA_HR_COH + nblocks = q_direction->cfg.nblocks; + bits_coherence = 0; +#endif + if ( all_coherence_zero == 0 ) + { +#ifdef HR_METADATA_HR_COH + read_coherence_data_hr_512( bitstream, index, hQMetaData, d ); + +#else + bits_coherence = read_coherence_data( bitstream, index, hQMetaData, d, 1 ); +#endif + } + else + { + /*Surround coherence*/ + for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[b].surround_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + } + + if ( hQMetaData->q_direction[d].coherence_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->q_direction[d].coherence_band_data[b].spread_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + } + } + } + + + /* Decode quantized directions frame-wise */ + ivas_qmetadata_raw_decode_dir_512( q_direction, bitstream, index, nbands, start_band, sph_grid16 ); +#ifndef HR_METADATA_HR_COH + if ( bits_coherence > 0 ) + { + if ( nblocks > 1 ) + { + decode_spread_coherence( hQMetaData, d, nblocks, 1 ); + } + } + else + { + for ( b = start_band; b < nbands; b++ ) + { + if ( q_direction->coherence_band_data != NULL ) + { + set_c( (int8_t *) q_direction->coherence_band_data[b].spread_coherence, 0, nblocks ); + } + } + } +#endif + +#ifdef DEBUG_MODE_QMETADATA + + fprintf( pF, "frame %d: diff %d surcoh %d ", frame, bits_diff_sum, bits_sur_coherence ); + fprintf( pF, "dir %d\n", start_index_0 - *index ); +#endif + } + /* move 2 dir data to its correct subband */ + + if ( hQMetaData->no_directions == 2 ) + { + + /* Scale energy ratios that sum to over one */ + for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) + { + float ratioSum; + for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) + { + ratioSum = hQMetaData->q_direction[0].band_data[b].energy_ratio[m] + hQMetaData->q_direction[1].band_data[b].energy_ratio[m]; + + if ( ratioSum > 1.0f ) + { + hQMetaData->q_direction[0].band_data[b].energy_ratio[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio[m] / ratioSum; + hQMetaData->q_direction[1].band_data[b].energy_ratio[m] = hQMetaData->q_direction[1].band_data[b].energy_ratio[m] / ratioSum; + } + } + } + } + +#ifdef DEBUG_MODE_QMETADATA + for ( d = 0; d < hQMetaData->no_directions; d++ ) + { + q_direction = &hQMetaData->q_direction[d]; + nbands = q_direction->cfg.nbands; + start_band = q_direction->cfg.start_band; + + + fprintf( pF_azi, "frame %d/dir/ec %d: ", frame, d ); + fprintf( pF_ele, "frame %d/dir/ec %d: ", frame, d ); + fprintf( pF_ratio, "frame %d/dir %d: ", frame, d ); + fprintf( pF_spcoh, "frame %d/dir %d: ", frame, d ); + if ( d == 0 ) + { + fprintf( pF_surcoh, "frame %d/dir %d: ", frame, d ); + } + for ( b = start_band; b < nbands; b++ ) + { + for ( m = 0; m < q_direction->cfg.nblocks; m++ ) + { + fprintf( pF_azi, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].azimuth[m] ) / 100.f ); + fprintf( pF_ele, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].elevation[m] ) / 100.f ); + fprintf( pF_ratio, " %1.3f ", q_direction->band_data[b].energy_ratio[m] ); + if ( q_direction->coherence_band_data != NULL ) + { + fprintf( pF_spcoh, " %d ", q_direction->coherence_band_data[b].spread_coherence[m] ); + } + if ( d == 0 && hQMetaData->surcoh_band_data != NULL ) + { + fprintf( pF_surcoh, " %d ", hQMetaData->surcoh_band_data[b].surround_coherence[m] ); + } + } + } + fprintf( pF_azi, "\n" ); + fprintf( pF_ele, "\n" ); + fprintf( pF_ratio, "\n" ); + fprintf( pF_spcoh, "\n" ); + if ( d == 0 ) + { + fprintf( pF_surcoh, "\n" ); + } + } +#endif + /* Store status information for renderer use */ + hQMetaData->ec_flag = 0; + + hQMetaData->dir_comp_ratio = 1.0f; + + if ( hQMetaData->dir_comp_ratio > 1.0f ) + { + hQMetaData->dir_comp_ratio = 1.0f; + } + + + return ( start_index_0 - *index ); +} + +#endif + + +/*-----------------------------------------------------------------------* + * ivas_qmetadata_dec_sid_decode() + * + * Main function for decoding SID for Spatial Metadata + *-----------------------------------------------------------------------*/ + +/*! r: number of bits written */ +int16_t ivas_qmetadata_dec_sid_decode( + IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: q_metadata handle */ + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, /* i/o: bitstream position */ + const int16_t nchan_transport, /* i : number of transport channels */ + int16_t *element_mode, /* o : element mode */ + const int16_t ivas_format, /* i : IVAS format */ + const SBA_MODE sba_mode /* i : SBA mode */ +) +{ + int16_t b, m, i; + uint16_t value; + uint16_t diffuseness_index[DIRAC_MAX_NBANDS]; + int16_t nbands, nblocks, start_band; + IVAS_QDIRECTION *q_direction; + int16_t start_index; + float avg_elevation, avg_azimuth; + float avg_direction_vector[3]; + float direction_vector[3]; + int16_t metadata_sid_bits; /* bits allocated to SID for metadata */ +#ifdef DEBUG_MODE_QMETADATA + static FILE *pF = NULL; + static FILE *pF_azi = NULL; + static FILE *pF_ele = NULL; + static FILE *pF_ratio = NULL; + + if ( pF == NULL ) + pF = fopen( "./res/qmetadata_sid_dec.txt", "w" ); + if ( pF_azi == NULL ) + pF_azi = fopen( "./res/qmetadata_sid_azi_dec.txt", "w" ); + if ( pF_ele == NULL ) + pF_ele = fopen( "./res/qmetadata_sid_ele_dec.txt", "w" ); + if ( pF_ratio == NULL ) + pF_ratio = fopen( "./res/qmetadata_sid_ratio_dec.txt", "w" ); +#endif + + if ( ivas_format == SBA_FORMAT ) + { + if ( sba_mode == SBA_MODE_SPAR ) + { + /* TODO: still use old sid frame size to keep bitexactness */ + metadata_sid_bits = (int16_t) ( 5000 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - ( SPAR_DTX_BANDS * 18 ) - 1; /* -1 for inactive mode header bit*/ + } + else + { + /* keep 13.2 and 16.4 sid bitrate as 4.4 kbps for now*/ + /* TODO: still use old sid frame size to keep bitexactness */ + metadata_sid_bits = ( 4400 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; + } + } + else + { + /* TODO: still use old sid frame size to keep bitexactness */ + metadata_sid_bits = ( 4400 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; + } + + start_index = *index; + + /* read MASA SID descriptor */ + if ( ivas_format == MASA_FORMAT && nchan_transport == 2 ) /* corresponding to SID_MASA case; Todo: needs to be checked for SBA */ + { + b = bitstream[( *index )--]; + if ( b ) + { + *element_mode = IVAS_CPE_MDCT; + } + else + { + *element_mode = IVAS_CPE_DFT; + } + } + + /* Fix configuration for SID */ + q_direction = &hQMetaData->q_direction[0]; /* only 1 direction */ + + if ( sba_mode == SBA_MODE_SPAR ) + { + nbands = DIRAC_DTX_BANDS; /* only 2 bands transmitted */ + } + else + { + nbands = 5; /* only 5 bands transmitted */ + } + + nblocks = q_direction->cfg.nblocks; /* only 1 block transmitted but up to 4 blocks re-generated */ + start_band = 0; /* start from band 0 */ + + /* Read 2D signaling*/ + if ( sba_mode != SBA_MODE_SPAR ) + { + q_direction->not_in_2D = bitstream[( *index )--]; + } + else + { + q_direction->not_in_2D = 1; + } + + /* Decode diffuseness*/ + for ( b = start_band; b < nbands; b++ ) + { + diffuseness_index[b] = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, DIRAC_DIFFUSE_LEVELS - 4 ) + 4; + q_direction->band_data[b].energy_ratio_index[0] = diffuseness_index[b]; + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[diffuseness_index[b]]; + q_direction->band_data[b].azimuth_m_alphabet[0] = no_phi_masa[q_direction->band_data[b].bits_sph_idx[0] - 1][0]; + } + + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].energy_ratio[0] = 1.0f - diffuseness_reconstructions[diffuseness_index[b]]; + for ( i = 0; i < nblocks; i++ ) + { + q_direction->band_data[b].energy_ratio[i] = q_direction->band_data[b].energy_ratio[0]; + } + } + + /* Decoder DOAs*/ + if ( q_direction->not_in_2D > 0 ) + { + for ( b = start_band; b < nbands; b++ ) + { + value = 0; + for ( i = 0; i < q_direction->band_data[b].bits_sph_idx[0]; i++ ) + { + value = ( value << 1 ) + bitstream[( *index )--]; + } + for ( i = 0; i < nblocks; i++ ) + { + q_direction->band_data[b].spherical_index[i] = value; + } + + deindex_spherical_component( q_direction->band_data[b].spherical_index[0], &avg_azimuth, &avg_elevation, + &q_direction->band_data[b].azimuth_index[0], &q_direction->band_data[b].elevation_index[0], q_direction->band_data[b].bits_sph_idx[0], + q_direction->cfg.mc_ls_setup ); + + ivas_qmetadata_azimuth_elevation_to_direction_vector( avg_azimuth, avg_elevation, avg_direction_vector ); + ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[b].azimuth[nblocks - 1], q_direction->band_data[b].elevation[nblocks - 1], direction_vector ); + for ( m = 0; m < nblocks - 1; m++ ) + { + v_add( direction_vector, avg_direction_vector, direction_vector, 3 ); + ivas_qmetadata_direction_vector_to_azimuth_elevation( direction_vector, &q_direction->band_data[b].azimuth[m], &q_direction->band_data[b].elevation[m] ); + } + ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector, &q_direction->band_data[b].azimuth[nblocks - 1], &q_direction->band_data[b].elevation[nblocks - 1] ); + } + } + else + { + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 5, q_direction->band_data[b].bits_sph_idx[0] ) ); + q_direction->band_data[b].azimuth_index[0] = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, q_direction->band_data[b].azimuth_m_alphabet[0] ); + q_direction->band_data[b].azimuth_index[0] = ivas_qmetadata_dereorder_generic( q_direction->band_data[b].azimuth_index[0] ) + ( q_direction->band_data[b].azimuth_m_alphabet[0] >> 1 ); + avg_azimuth = 360.0f / (float) ( q_direction->band_data[b].azimuth_m_alphabet[0] ) * q_direction->band_data[b].azimuth_index[0] - 180; + avg_elevation = 0.f; ivas_qmetadata_azimuth_elevation_to_direction_vector( avg_azimuth, avg_elevation, avg_direction_vector ); @@ -1020,21 +1834,137 @@ static int16_t ivas_qmetadata_entropy_decode_diffuseness( for ( b = start_band; b < nbands; b++ ) { - q_direction->band_data[b].energy_ratio_index[0] = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, DIRAC_DIFFUSE_LEVELS ); - dif_min = min( dif_min, q_direction->band_data[b].energy_ratio_index[0] ); + q_direction->band_data[b].energy_ratio_index[0] = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, DIRAC_DIFFUSE_LEVELS ); + dif_min = min( dif_min, q_direction->band_data[b].energy_ratio_index[0] ); + } + } + + *diffuseness_index_max_ec_frame = 5; + /* adaptively select the diffuseness_index_max_ec threshold */ + if ( dif_min > 5 ) + { + *diffuseness_index_max_ec_frame = DIRAC_DIFFUSE_LEVELS - 1; + } + + return ( index_start - *index ); +} + +#ifdef HR_METADATA +static int16_t ivas_qmetadata_entropy_decode_diffuseness_hr( + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, + IVAS_QDIRECTION *q_direction, + uint16_t *diffuseness_index_max_ec_frame ) +{ + int16_t b; + uint16_t dif_min; + int16_t index_start; + int16_t nbands; + int16_t start_band; + + index_start = *index; + nbands = q_direction->cfg.nbands; + start_band = q_direction->cfg.start_band; + + /* diffuseness decoding */ + /* Handle one band as special case*/ + if ( nbands == 1 ) + { + q_direction->band_data[0].energy_ratio_index[0] = 0; + for ( b = 0; b < MASA_BITS_ER_HR; b++ ) + { + q_direction->band_data[0].energy_ratio_index[0] = ( q_direction->band_data[0].energy_ratio_index[0] << 1 ) + bitstream[( *index )--]; + } + *diffuseness_index_max_ec_frame = 5; + + return MASA_BITS_ER_HR; + } + + if ( bitstream[( *index )--] == 0 ) /* dif_use_raw_coding */ + { + /* Decode with similarity strategy with low band count. On higher band counts, decode with Huffman-coding strategy. */ + + if ( bitstream[( *index )--] != 0 ) /* dif_have_unique_value */ + { + dif_min = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, HR_MASA_ER_LEVELS ); /* dif_unique_value */ + + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].energy_ratio_index[0] = dif_min; + } + } + else /* all diffuseness values are dif_min_value or dif_min_value + 1 */ + { + dif_min = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, HR_MASA_ER_LEVELS - 1 ); /* dif_min_value */ + + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].energy_ratio_index[0] = dif_min + bitstream[( *index )--]; /* dif_bit_offset_values */ + } + } + } + else /* different values for diffuseness */ + { + dif_min = HR_MASA_ER_LEVELS; + + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].energy_ratio_index[0] = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, HR_MASA_ER_LEVELS ); + dif_min = min( dif_min, q_direction->band_data[b].energy_ratio_index[0] ); + } + } + + *diffuseness_index_max_ec_frame = 10; + /* adaptively select the diffuseness_index_max_ec threshold */ + if ( dif_min > 10 ) + { + *diffuseness_index_max_ec_frame = HR_MASA_ER_LEVELS - 1; + } + + return ( index_start - *index ); +} + +static int16_t ivas_qmetadata_entropy_decode_diffuseness_hr_512( + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, + IVAS_QDIRECTION *q_direction ) +{ + int16_t b, k; + + int16_t index_start; + int16_t nbands, nblocks; + int16_t start_band; + + index_start = *index; + nbands = q_direction->cfg.nbands; + nblocks = q_direction->cfg.nblocks; + start_band = q_direction->cfg.start_band; + + /* diffuseness decoding */ + /* Handle one band as special case*/ + if ( nbands == 1 ) + { + q_direction->band_data[0].energy_ratio_index[0] = 0; + for ( b = 0; b < MASA_BITS_ER_HR; b++ ) + { + q_direction->band_data[0].energy_ratio_index[0] = ( q_direction->band_data[0].energy_ratio_index[0] << 1 ) + bitstream[( *index )--]; } + + return MASA_BITS_ER_HR; } - *diffuseness_index_max_ec_frame = 5; - /* adaptively select the diffuseness_index_max_ec threshold */ - if ( dif_min > 5 ) + + for ( b = start_band; b < nbands; b++ ) { - *diffuseness_index_max_ec_frame = DIRAC_DIFFUSE_LEVELS - 1; + for ( k = 0; k < nblocks; k++ ) + { + q_direction->band_data[b].energy_ratio_index[k] = ivas_qmetadata_DecodeQuasiUniform( bitstream, index, HR_MASA_ER_LEVELS ); + } } return ( index_start - *index ); } - +#endif static int16_t ivas_qmetadata_entropy_decode_df_ratio( uint16_t *bitstream, @@ -1161,7 +2091,12 @@ static int16_t ivas_qmetadata_entropy_decode_dir( int16_t *index, const uint16_t diffuseness_index_max_ec_frame, const int16_t nbands, - const int16_t start_band ) + const int16_t start_band +#ifdef HR_METADATA + , + int16_t is_hr +#endif +) { int16_t b, m; int16_t diff_idx; @@ -1188,7 +2123,18 @@ static int16_t ivas_qmetadata_entropy_decode_dir( /*Raw coding for high diffuseness*/ for ( b = start_band; b < nbands; b++ ) { - diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + if ( is_hr ) + { + diff_idx = 0; + } + else + { +#endif + diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + } +#endif diff_idx_min = min( diff_idx_min, diff_idx ); if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) { @@ -1198,8 +2144,11 @@ static int16_t ivas_qmetadata_entropy_decode_dir( { elev_alph[b] = no_theta_masa[bits_direction_masa[diff_idx] - 3] * 2 - 1; } - +#ifdef HR_METADATA + if ( q_direction->band_data[b].energy_ratio_index_mod[0] > diffuseness_index_max_ec_frame ) +#else if ( diff_idx > diffuseness_index_max_ec_frame ) +#endif { bands_entropic[b] = 0; @@ -1252,7 +2201,18 @@ static int16_t ivas_qmetadata_entropy_decode_dir( if ( bands_entropic[b] ) { int16_t tmp_index; - diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + if ( is_hr ) + { + diff_idx = 0; + } + else + { +#endif + diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + } +#endif if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) { @@ -1300,7 +2260,19 @@ static int16_t ivas_qmetadata_entropy_decode_dir( { if ( bands_entropic[b] ) { - diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + if ( is_hr ) + { + diff_idx = 0; + } + else + { + +#endif + diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + } +#endif for ( m = 0; m < nblocks; m++ ) { int16_t tmp_index; @@ -1359,7 +2331,19 @@ static int16_t ivas_qmetadata_entropy_decode_dir( { if ( bands_entropic[b] ) { - diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + if ( is_hr ) + { + diff_idx = 0; + } + else + { + +#endif + diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + } +#endif for ( m = 0; m < nblocks; m++ ) { q_direction->band_data[b].elevation_index[m] = 0; @@ -1477,7 +2461,49 @@ static int16_t ivas_qmetadata_entropy_decode_dir( return ( index_start - *index ); } +#ifdef HR_METADATA +/*------------------------------------------------------------------------- + * ivas_qmetadata_raw_decode_dir() + * + * Main function for raw decoding of the directions + *------------------------------------------------------------------------*/ + +static int16_t ivas_qmetadata_raw_decode_dir_512( + IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */ + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, + const int16_t nbands, + const int16_t start_band, + SPHERICAL_GRID_DATA *sph_grid16 /* i: spherical grid for deindexing */ +) +{ + int16_t b, m, i; + int16_t nblocks; + int16_t index_start; + uint16_t value; + + index_start = *index; + nblocks = q_direction->cfg.nblocks; + + for ( b = start_band; b < nbands; b++ ) + { + for ( m = 0; m < nblocks; m++ ) + { + value = 0; + for ( i = 0; i < q_direction->band_data[b].bits_sph_idx[m]; i++ ) + { + value = ( value << 1 ) + bitstream[( *index )--]; + } + q_direction->band_data[b].spherical_index[m] = value; + deindex_sph_idx( value, sph_grid16, &( q_direction->band_data[b].elevation[m] ), &( q_direction->band_data[b].azimuth[m] ) ); + } + } + + + return ( index_start - *index ); +} +#endif /*------------------------------------------------------------------------- * ivas_qmetadata_raw_decode_dir() * @@ -1489,7 +2515,12 @@ static int16_t ivas_qmetadata_raw_decode_dir( uint16_t *bitstream, /* i : bitstream */ int16_t *index, const int16_t nbands, - const int16_t start_band ) + const int16_t start_band +#ifdef HR_METADATA + , + int16_t is_hr +#endif +) { int16_t b, m, azith_alph; int16_t diff_idx; @@ -1507,7 +2538,18 @@ static int16_t ivas_qmetadata_raw_decode_dir( } else { - diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + if ( is_hr ) + { + diff_idx = 0; + } + else + { +#endif + diff_idx = q_direction->band_data[b].energy_ratio_index_mod[0]; +#ifdef HR_METADATA + } +#endif for ( m = 0; m < nblocks; m++ ) { @@ -2548,6 +3590,10 @@ static void decode_spread_coherence( IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: quantized metadata structure */ int16_t idx_d, /* i : direction index */ const int16_t no_frames /* i : number of time subframes */ +#ifdef HR_METADATA + , + int16_t is_hr +#endif ) { int16_t i, j; @@ -2557,7 +3603,9 @@ static void decode_spread_coherence( int16_t MASA_grouping[MASA_MAXIMUM_CODING_SUBBANDS]; IVAS_QDIRECTION *q_direction; int16_t coding_subbands, coding_subbands_0, d, two_dir_band[MASA_MAXIMUM_CODING_SUBBANDS]; - +#ifdef HR_METADATA + int16_t min_index; +#endif coding_subbands_0 = hQMetaData->q_direction[0].cfg.nbands; coding_subbands = hQMetaData->q_direction[idx_d].cfg.nbands; if ( coding_subbands_0 <= 5 ) @@ -2612,7 +3660,26 @@ static void decode_spread_coherence( for ( i = 0; i < coding_subbands; i++ ) { var_azi = var( q_direction->band_data[i].azimuth, no_frames ); +#ifdef HR_METADATA + if ( is_hr ) + { + minimum_s( (int16_t *) ( q_direction->band_data[i].energy_ratio_index ), q_direction->cfg.nblocks, &min_index ); + min_index = min_index >> 1; + } + else + { + min_index = q_direction->band_data[i].energy_ratio_index[0]; + } + if ( var_azi < MASA_DELTA_AZI_DCT0 ) + { + idx_sub_cb = MASA_NO_CV_COH * min_index; + } + else + { + idx_sub_cb = MASA_NO_CV_COH * ( min_index + DIRAC_DIFFUSE_LEVELS ); /* NO_CV_COH = 8 */ + } +#else if ( var_azi < MASA_DELTA_AZI_DCT0 ) { idx_sub_cb = MASA_NO_CV_COH * q_direction->band_data[i].energy_ratio_index[0]; @@ -2621,7 +3688,7 @@ static void decode_spread_coherence( { idx_sub_cb = MASA_NO_CV_COH * ( q_direction->band_data[i].energy_ratio_index[0] + DIRAC_DIFFUSE_LEVELS ); /* NO_CV_COH = 8 */ } - +#endif dct_coh[i][0] = coherence_cb0_masa[idx_sub_cb + q_direction->coherence_band_data[i].spread_coherence_dct0_index]; if ( coding_subbands < coding_subbands_0 ) { @@ -2879,7 +3946,49 @@ static int16_t decode_fixed_rate_composed_index_coherence( return nbits; } +#ifdef HR_METADATA_HR_COH +/* !r: number of bits read */ +static int16_t read_coherence_data_hr_512( + uint16_t *bitstream, /* i : bitstream */ + int16_t *p_bit_pos, /* i : position in the bitstream */ + IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata structure */ + const int16_t idx_dir /* i : direction index */ +) +{ + int16_t j, k, i; + int16_t nbands, nblocks; + int16_t min_index, GR_param; + int16_t cb_size, nbits; + int16_t decoded_idx; + float delta; + + nbands = hQMetaData->q_direction[idx_dir].cfg.nbands; + nblocks = hQMetaData->q_direction[idx_dir].cfg.nblocks; + + cb_size = 1 << NBITS_HR_COH; + delta = 256.0f / cb_size; + nbits = *p_bit_pos; + for ( k = 0; k < nblocks; k++ ) + { + /* read min_index */ + min_index = 0; + for ( i = 0; i < NBITS_HR_COH; i++ ) + { + min_index = ( min_index << 1 ) + bitstream[( *p_bit_pos )--]; + } + /* read GR param */ + GR_param = bitstream[( *p_bit_pos )--]; + for ( j = 0; j < nbands; j++ ) + { + decoded_idx = ivas_qmetadata_DecodeExtendedGR( bitstream, p_bit_pos, cb_size - min_index - 1, GR_param ) + min_index; + hQMetaData->q_direction[idx_dir].coherence_band_data[j].spread_coherence[k] = (uint8_t) ( decoded_idx * delta + delta / 2.0f ); + } + } + nbits = nbits - *p_bit_pos; + return nbits; +} +#endif /*------------------------------------------------------------------ - * * read_coherence_data() * @@ -2892,6 +4001,10 @@ static int16_t read_coherence_data( int16_t *p_bit_pos, /* i : position in the bitstream */ IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata structure */ const int16_t idx_dir /* i : direction index */ +#ifdef HR_METADATA + , + int16_t is_hr +#endif ) { int16_t j; @@ -2909,6 +4022,9 @@ static int16_t read_coherence_data( int16_t decoded_idx[MASA_MAXIMUM_CODING_SUBBANDS]; uint16_t byteBuffer; int16_t idx_ER; +#ifdef HR_METADATA + int16_t min_index; +#endif coding_subbands = hQMetaData->q_direction[idx_dir].cfg.nbands; q_direction = &( hQMetaData->q_direction[idx_dir] ); @@ -2919,7 +4035,19 @@ static int16_t read_coherence_data( { for ( j = 0; j < coding_subbands; j++ ) { - idx_ER = 7 - q_direction->band_data[j].energy_ratio_index_mod[0] + coding_subbands / MASA_FACTOR_CV_COH; +#ifdef HR_METADATA + if ( is_hr ) + { + idx_ER = 7 - ( q_direction->band_data[j].energy_ratio_index_mod[0] >> 1 ) + coding_subbands / MASA_FACTOR_CV_COH; + } + else + { + +#endif + idx_ER = 7 - q_direction->band_data[j].energy_ratio_index_mod[0] + coding_subbands / MASA_FACTOR_CV_COH; +#ifdef HR_METADATA + } +#endif no_cv_vec[j] = idx_ER + 1; } @@ -2943,7 +4071,11 @@ static int16_t read_coherence_data( { if ( no_cv_vec[j] > 1 ) { +#ifdef HR_METADATA + q_direction->coherence_band_data[j].spread_coherence[0] = (uint8_t) roundf( decoded_idx[j] * ( 255.0f / (float) ( 7 - ( q_direction->band_data[j].energy_ratio_index_mod[0] >> ( is_hr ) ) + coding_subbands / MASA_FACTOR_CV_COH ) ) ); +#else q_direction->coherence_band_data[j].spread_coherence[0] = (uint8_t) roundf( decoded_idx[j] * ( 255.0f / (float) ( 7 - q_direction->band_data[j].energy_ratio_index_mod[0] + coding_subbands / MASA_FACTOR_CV_COH ) ) ); +#endif } else { @@ -2960,7 +4092,11 @@ static int16_t read_coherence_data( { if ( no_cv_vec[j] > 1 ) { +#ifdef HR_METADATA + q_direction->coherence_band_data[j].spread_coherence[0] = (uint8_t) roundf( decoded_index[j] * ( 255.0f / (float) ( 7 - ( q_direction->band_data[j].energy_ratio_index_mod[0] >> ( is_hr ) ) + coding_subbands / MASA_FACTOR_CV_COH ) ) ); +#else q_direction->coherence_band_data[j].spread_coherence[0] = (uint8_t) roundf( decoded_index[j] * ( 255.0f / (float) ( 7 - q_direction->band_data[j].energy_ratio_index_mod[0] + coding_subbands / MASA_FACTOR_CV_COH ) ) ); +#endif } else { @@ -2973,7 +4109,19 @@ static int16_t read_coherence_data( { for ( j = 0; j < coding_subbands; j++ ) { - no_cv_vec[j] = len_cb_dct0_masa[q_direction->band_data[j].energy_ratio_index[0]]; /* spread coherence DCT0*/ +#ifdef HR_METADATA + if ( is_hr ) + { + minimum_s( (int16_t *) ( q_direction->band_data[j].energy_ratio_index ), q_direction->cfg.nblocks, &min_index ); + no_cv_vec[j] = len_cb_dct0_masa[min_index >> 1]; /* spread coherence DCT0*/ + } + else + { +#endif + no_cv_vec[j] = len_cb_dct0_masa[q_direction->band_data[j].energy_ratio_index[0]]; /* spread coherence DCT0*/ +#ifdef HR_METADATA + } +#endif } if ( sum_s( no_cv_vec, coding_subbands ) > MASA_COH_LIMIT_2IDX ) @@ -3096,13 +4244,14 @@ static int16_t read_coherence_data( return nbits; } + /*-------------------------------------------------------------------* * read_surround_coherence() * * *-------------------------------------------------------------------*/ -int16_t read_surround_coherence( +static int16_t read_surround_coherence( uint16_t *bitstream, /* i : bitstream */ int16_t *p_bit_pos, /* i : position in the bitstream */ IVAS_QMETADATA *hQMetaData /* i/o: quantized metadata structure */ @@ -3256,7 +4405,157 @@ int16_t read_surround_coherence( return bits_sur_coherence; } +#ifdef HR_METADATA +static int16_t read_surround_coherence_hr( + uint16_t *bitstream, /* i : bitstream */ + int16_t *p_bit_pos, /* i : position in the bitstream */ + IVAS_QMETADATA *hQMetaData /* i/o: quantized metadata structure */ +) +{ + int16_t coding_subbands; + int16_t no_cv_vec[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t bit_pos; + float error_ratio_surr; + int16_t idx_ER[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t bits_sur_coherence, bits_GR; + int16_t j, k, sf; + uint16_t byteBuffer; + uint16_t idx_sur_coh[MASA_MAXIMUM_CODING_SUBBANDS]; + IVAS_QDIRECTION *q_direction; + int16_t min_index; + coding_subbands = hQMetaData->q_direction[0].cfg.nbands; + q_direction = hQMetaData->q_direction; + + bits_sur_coherence = 0; + bit_pos = *p_bit_pos; + for ( sf = 0; sf < hQMetaData->q_direction[0].cfg.nblocks; sf++ ) + { + for ( j = 0; j < coding_subbands; j++ ) + { + error_ratio_surr = 1.0f; + + if ( hQMetaData->no_directions == 2 ) + { + error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf] - q_direction[1].band_data[j].energy_ratio[sf] * hQMetaData->twoDirBands[j]; + } + else + { + error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf]; + } + + if ( error_ratio_surr <= 0 ) + { + error_ratio_surr = 0; + no_cv_vec[j] = 1; + idx_ER[j] = 0; + } + else + { + idx_ER[j] = 7; // masa_sq( error_ratio_surr, diffuseness_thresholds, DIRAC_DIFFUSE_LEVELS ); + no_cv_vec[j] = idx_cb_sur_coh_masa[idx_ER[j]] + 2; + } + } + + if ( sum_s( no_cv_vec, coding_subbands ) == coding_subbands ) + { + /* surround coherence is zero */ + for ( j = 0; j < coding_subbands; j++ ) + { + for ( k = 0; k < MAX_PARAM_SPATIAL_SUBFRAMES; k++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + hQMetaData->surcoh_band_data[j].surround_coherence[k] = 0; + } + } + } + } + else + { + + /* read how the surround coherence is encoded */ + byteBuffer = bitstream[bit_pos--]; + bits_sur_coherence += 1; + + if ( byteBuffer & 1 ) + { + /* GR decoding */ + /* read GR order */ + byteBuffer = bitstream[bit_pos--]; + bits_sur_coherence += 1; + + /* read min index */ + bits_GR = bit_pos; + min_index = ivas_qmetadata_DecodeExtendedGR( bitstream, &bit_pos, MASA_MAX_NO_CV_SUR_COH, 0 ); + bits_sur_coherence += bits_GR - bit_pos; + + /* read GR data */ + for ( j = 0; j < coding_subbands; j++ ) + { + bits_GR = bit_pos; + /* decoding for min removed */ + if ( no_cv_vec[j] > 1 ) + { + idx_sur_coh[j] = ivas_qmetadata_DecodeExtendedGR( bitstream, &bit_pos, no_cv_vec[j] - min_index, ( byteBuffer & 1 ) ); + bits_sur_coherence += bits_GR - bit_pos; + } + else + { + idx_sur_coh[j] = 0; + } + } + + for ( j = 0; j < coding_subbands; j++ ) + { + if ( no_cv_vec[j] > 1 ) + { + hQMetaData->surcoh_band_data[j].sur_coherence_index = idx_sur_coh[j] + min_index; + hQMetaData->surcoh_band_data[j].surround_coherence[sf] = sur_coherence_cb_masa[idx_cb_sur_coh_masa[idx_ER[j]] * MASA_MAX_NO_CV_SUR_COH + hQMetaData->surcoh_band_data[j].sur_coherence_index]; + } + else + { + hQMetaData->surcoh_band_data[j].sur_coherence_index = idx_sur_coh[j]; + hQMetaData->surcoh_band_data[j].surround_coherence[sf] = 0; + } + } + } + else + { + /* fixed rate */ + uint16_t sur_coh_temp_index[MASA_MAXIMUM_CODING_SUBBANDS]; + set_s( (int16_t *) sur_coh_temp_index, 0, MASA_MAXIMUM_CODING_SUBBANDS ); + + decode_fixed_rate_composed_index_coherence( bitstream, &bit_pos, coding_subbands, no_cv_vec, sur_coh_temp_index, MASA_MAX_NO_CV_SUR_COH ); + + for ( j = 0; j < coding_subbands; j++ ) + { + hQMetaData->surcoh_band_data[j].sur_coherence_index = sur_coh_temp_index[j]; + } + + /* deindex surround coherence */ + for ( j = 0; j < coding_subbands; j++ ) + { + if ( no_cv_vec[j] > 1 ) + { + hQMetaData->surcoh_band_data[j].surround_coherence[sf] = sur_coherence_cb_masa[idx_cb_sur_coh_masa[idx_ER[j]] * MASA_MAX_NO_CV_SUR_COH + hQMetaData->surcoh_band_data[j].sur_coherence_index]; + } + else + { + hQMetaData->surcoh_band_data[j].surround_coherence[sf] = 0; + } + } + } + } + } + + /* Replace return value with the actual read bits. bits_sur_coherence might show wrong count at this point. */ + bits_sur_coherence = *p_bit_pos - bit_pos; + *p_bit_pos = bit_pos; + + return bits_sur_coherence; +} +#endif /*-------------------------------------------------------------------* * decode_combined_index() diff --git a/lib_enc/ivas_masa_enc.c b/lib_enc/ivas_masa_enc.c index fbb7af9ab4..d262277d06 100644 --- a/lib_enc/ivas_masa_enc.c +++ b/lib_enc/ivas_masa_enc.c @@ -62,7 +62,12 @@ static int16_t encode_lfe_to_total_energy_ratio( MASA_ENCODER_HANDLE hMasa, BSTR static void reduce_metadata_further( MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hqmetadata, const IVAS_FORMAT ivas_format ); #ifdef FIX_382_MASA_META_FRAMING_ASYNC -static void average_masa_metadata( MASA_METADATA_FRAME *masaMetadata, float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] ); +static void average_masa_metadata( MASA_METADATA_FRAME *masaMetadata, float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] +#ifdef HR_METADATA + , + SPHERICAL_GRID_DATA *sphGrid +#endif +); static void copy_masa_metadata_subframe( const MASA_METADATA_HANDLE hMetaFrom, const uint8_t sfFrom, MASA_METADATA_HANDLE hMetaTo, const uint8_t sfTo ); @@ -263,10 +268,18 @@ ivas_error ivas_masa_encode( mvr2r( hMasa->masaMetadata.directional_meta[i].azimuth[j], h_orig_metadata[i].azimuth[j], MASA_FREQUENCY_BANDS ); mvr2r( hMasa->masaMetadata.directional_meta[i].elevation[j], h_orig_metadata[i].elevation[j], MASA_FREQUENCY_BANDS ); mvr2r( hMasa->masaMetadata.directional_meta[i].energy_ratio[j], h_orig_metadata[i].energy_ratio[j], MASA_FREQUENCY_BANDS ); +#ifdef HR_METADATA + mvs2s( (int16_t *) ( hMasa->masaMetadata.directional_meta[i].spherical_index[j] ), (int16_t *) ( h_orig_metadata[i].spherical_index[j] ), MASA_FREQUENCY_BANDS ); +#endif } } } - +#ifdef HR_METADATA + if ( ivas_format == MASA_FORMAT && ivas_total_brate == IVAS_512k ) + { + hMasa->config.mergeRatiosOverSubframes = 0; + } +#endif /* Combine frequency bands and sub-frames */ combine_freqbands_and_subframes( hMasa ); } @@ -330,7 +343,25 @@ ivas_error ivas_masa_encode( } /* Encode metadata */ - ivas_qmetadata_enc_encode( hMetaData, hQMetaData ); +#ifdef HR_METADATA + if ( ivas_total_brate >= IVAS_384k ) + { + if ( ivas_total_brate >= IVAS_512k ) + { + ivas_qmetadata_enc_encode_hr_512( hMetaData, hQMetaData ); + } + else + { + ivas_qmetadata_enc_encode_hr( hMetaData, hQMetaData ); + } + } + else + { +#endif + ivas_qmetadata_enc_encode( hMetaData, hQMetaData ); +#ifdef HR_METADATA + } +#endif *nb_bits_metadata = hMetaData->nb_bits_tot; @@ -511,6 +542,9 @@ ivas_error ivas_masa_enc_config( uint8_t isActualTwoDir; /* Flag to tell that when there are two directions present in metadata, they both contain meaningful information. */ int32_t ivas_total_brate; ivas_error error; +#ifdef HR_METADATA + SPHERICAL_GRID_DATA *sphGrid; +#endif error = IVAS_ERR_OK; @@ -526,11 +560,31 @@ ivas_error ivas_masa_enc_config( if ( ivas_format == MASA_FORMAT ) { #ifdef FIX_382_MASA_META_FRAMING_ASYNC + detect_framing_async( hMasa ); /* detect the offset, set 1sf/4sf mode based on this. potentially also shift the metadata using a history buffer */ if ( hMasa->data.sync_state.frame_mode == MASA_FRAME_1SF && hMasa->data.sync_state.prev_offset != 0 ) { +#ifdef HR_METADATA + if ( ( sphGrid = (SPHERICAL_GRID_DATA *) malloc( sizeof( SPHERICAL_GRID_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA spherical grid\n" ) ); + } + if ( ivas_total_brate == IVAS_512k ) + { + generate_gridEq( sphGrid ); + } + else + { + sphGrid->no_theta = 0; + } +#endif /* average over sub-frames */ - average_masa_metadata( &( hMasa->masaMetadata ), hMasa->data.energy ); + average_masa_metadata( &( hMasa->masaMetadata ), hMasa->data.energy +#ifdef HR_METADATA + , + sphGrid +#endif + ); } #endif @@ -1065,6 +1119,9 @@ static void move_metadata_to_qmetadata( hQMeta->q_direction[dir].band_data[band].azimuth[sf] = hMeta->directional_meta[dir].azimuth[sf][band]; hQMeta->q_direction[dir].band_data[band].elevation[sf] = hMeta->directional_meta[dir].elevation[sf][band]; hQMeta->q_direction[dir].band_data[band].energy_ratio[sf] = hMeta->directional_meta[dir].energy_ratio[sf][band]; +#ifdef HR_METADATA + hQMeta->q_direction[dir].band_data[band].spherical_index[sf] = hMeta->directional_meta[dir].spherical_index[sf][band]; +#endif if ( hQMeta->q_direction[dir].coherence_band_data != NULL ) { hQMeta->q_direction[dir].coherence_band_data[band].spread_coherence[sf] = (uint8_t) roundf( hMeta->directional_meta[dir].spread_coherence[sf][band] * UINT8_MAX ); @@ -1808,7 +1865,12 @@ void ivas_masa_enc_reconfigure( static void average_masa_metadata( MASA_METADATA_FRAME *hMeta, - float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] ) + float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] +#ifdef HR_METADATA + , + SPHERICAL_GRID_DATA *Sph_Grid16 +#endif +) { int16_t i, j, k; float azi_rad, ele_rad; @@ -1855,7 +1917,13 @@ static void average_masa_metadata( j = 0; hMeta->directional_meta[i].azimuth[j][k] = atan2f( y_sum, x_sum ) / EVS_PI * 180.0f; hMeta->directional_meta[i].elevation[j][k] = atan2f( z_sum, sqrtf( x_sum * x_sum + y_sum * y_sum ) ) / EVS_PI * 180.0f; - +#ifdef HR_METADATA + if ( Sph_Grid16->no_theta > 0 ) + { + hMeta->directional_meta[i].spherical_index[j][k] = index_theta_phi_16( &( hMeta->directional_meta[i].elevation[j][k] ), + &( hMeta->directional_meta[i].azimuth[j][k] ), Sph_Grid16 ); + } +#endif vec_len = sqrtf( x_sum * x_sum + y_sum * y_sum + z_sum * z_sum ); hMeta->directional_meta[i].energy_ratio[j][k] = vec_len / ( energy_sum + EPSILON ); @@ -2198,3 +2266,254 @@ static void detect_framing_async( return; } #endif + +#ifdef HR_METADATA1 +void indexDirection( + uint16_t *sphIndex, /* o : output index for direction */ + float theta, /* i : input elevation to be indexed */ + float phi, /* i : input azimuth to be indexed */ + const SPHERICAL_GRID_DATA *gridData /* i : generated grid data */ +) +{ + float abs_theta, phi_q; + int16_t sign_th, id_phi, id_th; + int32_t idx_sph; + int32_t cum_n; + + phi = phi + 180; + if ( theta < 0 ) + { + abs_theta = -theta; + sign_th = -1; + } + else + { + abs_theta = theta; + sign_th = 1; + } + + quantize_theta_phi( gridData->no_theta, gridData->no_phi, abs_theta, &id_phi, + phi, &id_th, &phi_q ); + + /* Starting from Equator, alternating positive and negative */ + if ( id_th == 0 ) + { + idx_sph = id_phi; + } + else + { + if ( id_th == gridData->no_theta - 1 ) + { + idx_sph = 65534 + ( sign_th < 0 ); + } + else + { + theta = MASA_ANGLE_AT_EQUATOR * (float) ( id_th + 0.5f ); + if ( id_th == 1 ) + { + cum_n = 2 * (int16_t) ceilf( MASA_NTOT2_FAC * ( sinf( theta ) - MASA_ASIN_OFFSET ) ); + } + else + { + cum_n = 2 * (int16_t) roundf( MASA_NTOT2_FAC * ( sinf( theta ) - MASA_ASIN_OFFSET ) ); + } + cum_n += gridData->no_phi[0]; + if ( sign_th > 0 ) + { + cum_n -= 2 * gridData->no_phi[id_th]; + } + else + { + cum_n -= gridData->no_phi[id_th]; + } + idx_sph = cum_n + id_phi; + } + } + + *sphIndex = idx_sph; +} + +int16_t quantize_theta( /* o : index of quantized value */ + float x, /* i : theta value to be quantized */ + int16_t no_cb, /* i : number of codewords */ + float *xhat /* o : quantized value */ +) +{ + int16_t imin; + + float diff1, diff2; + + + imin = (int16_t) ( x * MASA_INV_ANGLE_AT_EQUATOR_DEG + 0.5f ); + + if ( imin >= no_cb - 1 ) + { + imin = no_cb - 1; + diff1 = x - 90; + diff2 = x - MASA_ANGLE_AT_EQUATOR_DEG * ( imin - 1 ); + if ( fabsf( diff1 ) > fabsf( diff2 ) ) + { + imin--; + *xhat = imin * MASA_ANGLE_AT_EQUATOR_DEG; + } + else + { + *xhat = 90; + } + } + else + { + *xhat = imin * MASA_ANGLE_AT_EQUATOR_DEG; + } + + return imin; +} + +void quantize_theta_phi( + const int16_t no_th, /* i : elevation codebook size */ + const int16_t *no_phi_loc, /* i : number of azimuth values for each elevation codeword */ + const float abs_theta, /* i : absolute value of elevation to be quantized */ + int16_t *id_phi, /* o : azimuth index */ + const float phi, /* i : input azimuth value; to be quantized */ + int16_t *id_theta, /* o : elevation index */ + float *phi_q /* o : rotated quantized azimuth */ +) +{ + float theta_hat, theta_hat1, phi_hat, phi_hat1; + int16_t id_th, id_th1, id_th2, id_ph, id_ph1; + float d, d1; + float diff1, diff2; + + theta_hat = 0; /* to remove warning */ + id_th = quantize_theta( abs_theta, no_th, &theta_hat ); + if ( no_th > 1 ) + { + if ( id_th == 0 ) + { + id_th1 = 1; + } + else if ( id_th == no_th - 1 ) + { + id_th1 = no_th - 2; + } + else + { + id_th1 = id_th - 1; + id_th2 = id_th + 1; + + diff1 = abs_theta - id_th1 * MASA_ANGLE_AT_EQUATOR_DEG; + diff2 = abs_theta - MASA_ANGLE_AT_EQUATOR_DEG * id_th2; + if ( id_th2 == no_th - 1 ) + { + diff2 = abs_theta - 90; + } + if ( fabsf( diff1 ) > fabsf( diff2 ) ) + { + id_th1 = id_th2; + } + } + + theta_hat1 = MASA_ANGLE_AT_EQUATOR_DEG * id_th1; + + if ( id_th1 == no_th - 1 ) + { + theta_hat1 = 90; + } + + + if ( no_phi_loc[id_th] > 1 ) + { + id_ph = quantize_phi( phi, ( id_th % 2 == 1 ), &phi_hat, no_phi_loc[id_th] ); + } + else + { + id_ph = MASA_NO_INDEX; + phi_hat = 180; + *phi_q = 0; + } + if ( ( no_phi_loc[id_th1] > 1 ) && ( id_ph < MASA_NO_INDEX ) ) + { + id_ph1 = quantize_phi( phi, ( id_th1 % 2 == 1 ), &phi_hat1, no_phi_loc[id_th1] ); + d = direction_distance( abs_theta, theta_hat, phi, phi_hat ); + d1 = direction_distance( abs_theta, theta_hat1, phi, phi_hat1 ); + if ( d1 > d ) + { + id_ph = id_ph1; + id_th = id_th1; /*theta_hat = ANGLE_AT_EQUATOR_DEG * id_th1; */ + } + } + } + else + { + id_ph = quantize_phi( phi, ( id_th % 2 == 1 ), &phi_hat, no_phi_loc[id_th] ); + } + + *id_phi = id_ph; + *id_theta = id_th; +} + +int16_t quantize_phi( /* o : index azimuth */ + float phi, /* i : azimuth value */ + int16_t flag_delta, /* i : flag indicating if the azimuth codebook is translated or not */ + float *phi_hat, /* o : quantized azimuth */ + const int16_t n /* i : azimuth codebook size */ +) +{ + int16_t id_phi; + float dd; + float delta_phi; + + delta_phi = 360.0f / (float) n; + + if ( n == 1 ) + { + *phi_hat = 0; + + return 0; + } + + if ( flag_delta == 1 ) + { + dd = delta_phi / 2.0f; + } + else + { + dd = 0; + } + + id_phi = (int16_t) ( ( phi - dd + delta_phi / 2.0f ) / (float) delta_phi ); + + if ( id_phi == n ) + { + id_phi = 0; + } + + if ( id_phi == -1 ) + { + id_phi = n - 1; + } + + *phi_hat = id_phi * delta_phi + dd; + + return id_phi; +} + +float direction_distance( /* o : distortion value */ + float theta, /* i : elevation absolute value */ + float theta_hat, /* i : quantized elevation value in absolute value */ + const float phi, /* i : azimuth value */ + const float phi_hat /* i : quantized azimuth value */ +) +{ + float d; + + theta *= EVS_PI / 180; + theta_hat *= EVS_PI / 180; + + d = sinf( theta ) * sinf( theta_hat ) + cosf( theta ) * cosf( theta_hat ) * cosf( ( phi - phi_hat ) * EVS_PI / 180 ); + + return d; +} + + +#endif \ No newline at end of file diff --git a/lib_enc/ivas_qmetadata_enc.c b/lib_enc/ivas_qmetadata_enc.c index ac4f83a657..00d53481a7 100644 --- a/lib_enc/ivas_qmetadata_enc.c +++ b/lib_enc/ivas_qmetadata_enc.c @@ -60,7 +60,12 @@ static void ivas_qmetadata_reorder_2dir_bands( IVAS_QMETADATA_HANDLE hQMetaData static int16_t ivas_qmetadata_entropy_encode_df_ratio( BSTR_ENC_HANDLE hMetaData, IVAS_QDIRECTION *q_direction, int16_t *df_ratio_bits ); -static int16_t ivas_qmetadata_entropy_encode_dir( BSTR_ENC_HANDLE hMetaData, IVAS_QDIRECTION *q_direction, const uint16_t diffuseness_index_max_ec_frame, const int16_t nbands, const int16_t start_band, const int16_t direction_bits_raw, int16_t max_bits ); +static int16_t ivas_qmetadata_entropy_encode_dir( BSTR_ENC_HANDLE hMetaData, IVAS_QDIRECTION *q_direction, const uint16_t diffuseness_index_max_ec_frame, const int16_t nbands, const int16_t start_band, const int16_t direction_bits_raw, int16_t max_bits +#ifdef HR_METADATA + , + int16_t is_hr +#endif +); static int16_t ivas_qmetadata_raw_encode_dir( BSTR_ENC_HANDLE hMetaData, IVAS_QDIRECTION *q_direction, const int16_t nbands, const int16_t start_band ); @@ -88,11 +93,21 @@ static ivas_error write_ec_direction( int16_t *num_bits_written, BSTR_ENC_HANDLE static int16_t write_fixed_rate_direction( BSTR_ENC_HANDLE hMetaData, IVAS_QDIRECTION *q_direction, const int16_t j_idx, const int16_t len ); -static int16_t ivas_qmetadata_quantize_coherence( IVAS_QMETADATA *hQMetaData, const int16_t idx_d, const int16_t all_coherence_zero, BSTR_ENC_HANDLE hMetaData, const int16_t write_flag, int16_t *indice_coherence ); +static int16_t ivas_qmetadata_quantize_coherence( IVAS_QMETADATA *hQMetaData, const int16_t idx_d, const int16_t all_coherence_zero, BSTR_ENC_HANDLE hMetaData, const int16_t write_flag, int16_t *indice_coherence +#ifdef HR_METADATA + , + int16_t is_hr +#endif +); static void dct4_transform( uint8_t *v, float *dct_v ); -static float quantize_DCT_0_coh( const float x, const int16_t j, const float *coherence_cb, const float delta_var, const int16_t no_cb, IVAS_QDIRECTION *q_direction, uint16_t *idx_x, int16_t *p_no_cb ); +static float quantize_DCT_0_coh( const float x, const int16_t j, const float *coherence_cb, const float delta_var, const int16_t no_cb, IVAS_QDIRECTION *q_direction, uint16_t *idx_x, int16_t *p_no_cb +#ifdef HR_METADATA + , + int16_t is_hr +#endif +); static int16_t encode_coherence_indexesDCT0( uint16_t *idx_dct, const int16_t len, int16_t *no_cb_vec, BSTR_ENC_HANDLE hMetaData, int16_t indice_coherence, const int16_t nbits, const int16_t nbits1 ); @@ -117,6 +132,41 @@ static int16_t write_2dir_info( BSTR_ENC_HANDLE hMetaData, uint8_t *twoDirBands, static void transform_azimuth_dir2( IVAS_QMETADATA_HANDLE hQMetaData, int16_t *dir2_bands ); static int16_t calc_var_azi( const IVAS_QDIRECTION *q_direction, const int16_t diffuseness_index_max_ec_frame, const float avg_azimuth, float *avg_azimuth_out ); +#ifdef HR_METADATA +static void ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr( + IVAS_QMETADATA_HANDLE hQMetaData, + int16_t *needed_bits, + int16_t *nbits_diff, + int16_t *dfRatioBits, + int16_t bits_dir_hr ); +static int16_t ivas_qmetadata_entropy_encode_diffuseness_hr( + BSTR_ENC_HANDLE hMetaData, + IVAS_QDIRECTION *q_direction, + uint16_t *diffuseness_index_max_ec_frame ); + +static void ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( + IVAS_QMETADATA_HANDLE hQMetaData, + int16_t *needed_bits, + int16_t bits_dir_hr, + BSTR_ENC_HANDLE hMetaData ); + +static int16_t encode_surround_coherence_hr( + IVAS_QMETADATA *hQMetaData, /* i : quantized metadata */ + BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle */ +); + +static void ivas_qmetadata_reorder_2dir_bands_hr( + IVAS_QMETADATA_HANDLE hQMetaData ); + +#ifdef HR_METADATA_HR_COH +static int16_t ivas_qmetadata_quantize_coherence_hr_512( + IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata */ + const int16_t idx_d, /* i : current direction index */ + const int16_t all_coherence_zero, /* i : all coherence is zero - flag */ + BSTR_ENC_HANDLE hMetaData /* i : metadata handle */ +); +#endif +#endif /*-----------------------------------------------------------------------* * ivas_qmetadata_enc_encode() @@ -185,6 +235,7 @@ ivas_error ivas_qmetadata_enc_encode( pF_surcoh = fopen( "./res/qmetadata_surcoh_enc.txt", "w" ); #endif + /* Save initial position in bitstream */ bit_pos_0 = hMetaData->nb_bits_tot; bit_pos_start = bit_pos_0; @@ -380,9 +431,15 @@ ivas_error ivas_qmetadata_enc_encode( /*Coherence */ bits_coherence[d] = 0; bit_pos_start_coh = hMetaData->nb_bits_tot; + if ( all_coherence_zero == 0 ) { - bits_coherence[d] = ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 0, &indice_coherence ); + bits_coherence[d] = ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 0, &indice_coherence +#ifdef HR_METADATA + , + 0 +#endif + ); } if ( q_direction->cfg.mc_ls_setup == MC_LS_SETUP_5_1 || q_direction->cfg.mc_ls_setup == MC_LS_SETUP_7_1 ) @@ -394,7 +451,12 @@ ivas_error ivas_qmetadata_enc_encode( else { /* Quantize directions*/ - quantize_direction_frame( q_direction, azimuth_orig, elevation_orig ); + quantize_direction_frame( q_direction, azimuth_orig, elevation_orig +#ifdef HR_METADATA + , + 0 +#endif + ); } /* Signalling 2D*/ @@ -420,7 +482,12 @@ ivas_error ivas_qmetadata_enc_encode( reduce_bits = hQMetaData->is_masa_ivas_format ? ( total_bits_1dir - ( bits_diff[d] + bits_coherence[d] + bits_signaling[d] ) - 1 ) : MASA_MAX_BITS; bits_ec = ivas_qmetadata_entropy_encode_dir( hMetaData, q_direction, diffuseness_index_max_ec_frame, - q_direction->cfg.nbands, q_direction->cfg.start_band, bits_dir_bands[0], reduce_bits ); + q_direction->cfg.nbands, q_direction->cfg.start_band, bits_dir_bands[0], reduce_bits +#ifdef HR_METADATA + , + 0 +#endif + ); if ( bits_ec < 0 ) { @@ -466,7 +533,12 @@ ivas_error ivas_qmetadata_enc_encode( bits_dir_bands[i] = ivas_qmetadata_raw_encode_dir( NULL, q_direction, i + 1, i ); /* Write ec bits */ - bits_ec = ivas_qmetadata_entropy_encode_dir( hMetaData, q_direction, diffuseness_index_max_ec_frame, i + 1, i, bits_dir_bands[i], MASA_MAX_BITS ); + bits_ec = ivas_qmetadata_entropy_encode_dir( hMetaData, q_direction, diffuseness_index_max_ec_frame, i + 1, i, bits_dir_bands[i], MASA_MAX_BITS +#ifdef HR_METADATA + , + 0 +#endif + ); if ( bits_ec >= 0 ) { @@ -565,7 +637,12 @@ ivas_error ivas_qmetadata_enc_encode( { bit_pos_start = hMetaData->nb_bits_tot; hMetaData->nb_bits_tot = bit_pos_start_coh; - ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 1, &indice_coherence ); + ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 1, &indice_coherence +#ifdef HR_METADATA + , + 0 +#endif + ); hMetaData->nb_bits_tot = bit_pos_start; } @@ -653,158 +730,790 @@ ivas_error ivas_qmetadata_enc_encode( return error; } - -/*-----------------------------------------------------------------------* - * ivas_qmetadata_enc_sid_encode() - * - * Main function for coding SID for Spatial Metadata - *-----------------------------------------------------------------------*/ - -/*! r: number of bits written */ -void ivas_qmetadata_enc_sid_encode( - BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ - IVAS_QMETADATA *q_metadata, /* i/o: metadata handle */ - const int16_t masa_sid_descriptor, /* i : description of MASA SID coding structure */ - const int16_t ivas_format, /* i : IVAS format */ - const SBA_MODE sba_mode /* i : SBA mode */ +#ifdef HR_METADATA +ivas_error ivas_qmetadata_enc_encode_hr( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *hQMetaData /* i/o: metadata handle */ ) { - int16_t b, m; - int16_t bit_pos_start; + int16_t i, bit_pos_start, bit_pos_start_coh; + + uint16_t diffuseness_index_max_ec_frame; + uint16_t diffuseness_index_max_ec_frame_pre[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t bits_dir_raw_pre[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t bits_diff_sum; + int16_t bits_diff[QMETADATA_MAX_NO_DIRECTIONS], bits_coherence[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t bits_dir[QMETADATA_MAX_NO_DIRECTIONS]; + IVAS_QDIRECTION *q_direction; int16_t nbands, nblocks, start_band; - float avg_direction_vector[3]; - float direction_vector[3]; - float avg_azimuth[MASA_MAXIMUM_CODING_SUBBANDS]; - float avg_elevation[MASA_MAXIMUM_CODING_SUBBANDS]; - int16_t bits_dir, bits_diff, bits_delta; - int16_t metadata_sid_bits; /* bits allocated to SID for metadata */ + int16_t ndirections, d; + float azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t all_coherence_zero; + int16_t bit_pos_0, bits_no_dirs_coh; + int16_t bits_signaling[QMETADATA_MAX_NO_DIRECTIONS]; + int16_t indice_coherence; + int16_t bits_dir_bands[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t bits_ec, next_ind_raw_flag; + int16_t dfRatio_bits[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t bits_surround_coh, no_TF; + int16_t dir2_bands[MASA_MAXIMUM_TWO_DIR_BANDS]; + int16_t reduce_bits; + ivas_error error; - if ( ivas_format == SBA_FORMAT ) - { - if ( sba_mode == SBA_MODE_SPAR ) - { - /* TODO: still use old sid frame size to keep bitexactness */ - metadata_sid_bits = (int16_t) ( 5000 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - ( SPAR_DTX_BANDS * SPAR_SID_BITS_TAR_PER_BAND ) - 1; /* -1 for inactive mode header bit*/ - } - else - { - /* keep 13.2 and 16.4 SID bitrate as 4.4 kbps for now*/ - /* TODO: still use old sid frame size to keep bitexactness */ - metadata_sid_bits = ( 4400 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; - } - } - else - { - /* TODO: still use old sid frame size to keep bitexactness */ - metadata_sid_bits = ( 4400 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; - } + error = IVAS_ERR_OK; #ifdef DEBUG_MODE_QMETADATA + int16_t ec_flag = 0; + + static FILE *pF = NULL; static FILE *pF_azi = NULL; static FILE *pF_ele = NULL; static FILE *pF_ratio = NULL; + static FILE *pF_spcoh = NULL; + static FILE *pF_spcoh_orig = NULL; + static FILE *pF_surcoh = NULL; + if ( pF == NULL ) + pF = fopen( "./res/qmetadata_enc.txt", "w" ); if ( pF_azi == NULL ) - pF_azi = fopen( "./res/qmetadata_sid_azi_enc.txt", "w" ); + pF_azi = fopen( "./res/qmetadata_azi_enc.txt", "w" ); if ( pF_ele == NULL ) - pF_ele = fopen( "./res/qmetadata_sid_ele_enc.txt", "w" ); + pF_ele = fopen( "./res/qmetadata_ele_enc.txt", "w" ); if ( pF_ratio == NULL ) - pF_ratio = fopen( "./res/qmetadata_sid_ratio_enc.txt", "w" ); - + pF_ratio = fopen( "./res/qmetadata_ratio_enc.txt", "w" ); + if ( pF_spcoh == NULL ) + pF_spcoh = fopen( "./res/qmetadata_spcoh_enc.txt", "w" ); + if ( pF_spcoh_orig == NULL ) + pF_spcoh_orig = fopen( "./res/qmetadata_spcoh_orig.txt", "w" ); + if ( pF_surcoh == NULL ) + pF_surcoh = fopen( "./res/qmetadata_surcoh_enc.txt", "w" ); #endif + /* Save initial position in bitstream */ - bit_pos_start = hMetaData->nb_bits_tot; + bit_pos_0 = hMetaData->nb_bits_tot; + bit_pos_start = bit_pos_0; - /* write for MASA the number of transport channels used at coding and the CPE mode DFT/MDCT */ - if ( masa_sid_descriptor > -1 ) - { - push_next_indice( hMetaData, masa_sid_descriptor, 1 ); - } + ndirections = hQMetaData->no_directions; - /* Code for one direction: diffuseness and average DOA(s)*/ - q_direction = &( q_metadata->q_direction[0] ); - nbands = q_direction->cfg.nbands; - nblocks = q_direction->cfg.nblocks; - start_band = 0; /*Start always with band 0 for SID*/ + /* Check if coherence should be encoded */ + all_coherence_zero = 1; + bits_no_dirs_coh = 0; - /* sanity checks*/ - assert( q_metadata->no_directions == 1 && "Qmetadata SID: only one direction supported!" ); - if ( sba_mode == SBA_MODE_SPAR ) - { - assert( ( q_direction->cfg.nbands == DIRAC_DTX_BANDS ) && "Qmetadata SID: only 2 bands supported!" ); - } - else + if ( hQMetaData->coherence_flag ) { - assert( ( q_direction->cfg.nbands == 5 ) && "Qmetadata SID: only 5 bands supported!" ); - } + all_coherence_zero = hQMetaData->all_coherence_zero; - if ( sba_mode != SBA_MODE_SPAR ) - { - /* Signalling 2D*/ - push_next_indice( hMetaData, ( q_direction->not_in_2D > 0 ), 1 ); /*2D flag*/ - } - else - { - q_direction->not_in_2D = 1; /* force for merged modes */ + push_next_indice( hMetaData, all_coherence_zero, 1 ); /* signal coherence */ + bits_no_dirs_coh += 1; } - /*Encode the quantized diffuseness in raw coding*/ - bits_dir = 0; - bits_diff = 0; - for ( b = start_band; b < nbands; b++ ) + if ( ndirections > 1 ) { - q_direction->band_data[b].energy_ratio_index[0] = max( q_direction->band_data[b].energy_ratio_index[0], 4 ); - bits_diff += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); - - q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; - if ( q_direction->not_in_2D == 0 ) +#ifdef DEBUGGING + assert( ndirections == 2 ); +#endif + /* Reorder 2dir bands for more efficient encoding. */ + ivas_qmetadata_reorder_2dir_bands( hQMetaData ); + d = 0; + for ( i = hQMetaData->q_direction[1].cfg.start_band; i < hQMetaData->q_direction[1].cfg.nbands; i++ ) { - q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 5, q_direction->band_data[b].bits_sph_idx[0] ) ); - bits_dir += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].azimuth_m_alphabet[0] - 1, q_direction->band_data[b].azimuth_m_alphabet[0] ); + if ( hQMetaData->twoDirBands[i] == 1 ) + { + mvr2r( hQMetaData->q_direction[1].band_data[i].azimuth, hQMetaData->q_direction[1].band_data[d].azimuth, hQMetaData->q_direction[1].cfg.nblocks ); + mvr2r( hQMetaData->q_direction[1].band_data[i].elevation, hQMetaData->q_direction[1].band_data[d].elevation, hQMetaData->q_direction[1].cfg.nblocks ); + mvr2r( hQMetaData->q_direction[1].band_data[i].energy_ratio, hQMetaData->q_direction[1].band_data[d].energy_ratio, hQMetaData->q_direction[1].cfg.nblocks ); + + dir2_bands[d] = i; + + if ( hQMetaData->coherence_flag ) + { + mvc2c( hQMetaData->q_direction[1].coherence_band_data[i].spread_coherence, hQMetaData->q_direction[1].coherence_band_data[d].spread_coherence, hQMetaData->q_direction[1].cfg.nblocks ); + } + d++; + } } - else + + bits_no_dirs_coh += write_2dir_info( hMetaData, hQMetaData->twoDirBands, hQMetaData->q_direction[0].cfg.nbands, hQMetaData->numTwoDirBands ); + + for ( i = d; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) { - bits_dir += q_direction->band_data[b].bits_sph_idx[0]; + set_f( hQMetaData->q_direction[1].band_data[i].energy_ratio, 0.0f, hQMetaData->q_direction[1].cfg.nblocks ); } +#ifdef DEBUGGING + assert( d == hQMetaData->numTwoDirBands ); +#endif + + hQMetaData->q_direction[1].cfg.nbands = hQMetaData->numTwoDirBands; } - /* Reduce bit demand by increasing diffuseness*/ - bits_delta = metadata_sid_bits - ( hMetaData->nb_bits_tot - bit_pos_start ) - bits_diff - bits_dir; + /*Quantization of the Diffuseness */ + ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr( hQMetaData, bits_dir_raw_pre, bits_diff, dfRatio_bits, 11 ); - while ( bits_delta < 0 && ( q_direction->not_in_2D > 0 ) ) + + bits_diff_sum = 0; + bits_diff[0] = ivas_qmetadata_entropy_encode_diffuseness_hr( hMetaData, &( hQMetaData->q_direction[0] ), &diffuseness_index_max_ec_frame_pre[0] ); + bits_diff_sum += bits_diff[0]; + + if ( ndirections == 2 ) { - for ( b = nbands - 1; b >= start_band && ( bits_delta < 0 ); b-- ) + bits_diff[1] = ivas_qmetadata_entropy_encode_df_ratio( hMetaData, &( hQMetaData->q_direction[1] ), dfRatio_bits ); + bits_diff_sum += bits_diff[1]; + } + + /* 2dir energy ratio encoding reuses index memory. Now that diffRatio and dFRatio have been encoded, + * we retrieve index_dirRatio1Inv and index_dirRatio1Inv for further parameter encoding. This is + * necessary only for bands that have two concurrent directions. */ + if ( hQMetaData->no_directions == 2 ) + { + int16_t j, k, dir2band, index_dirRatio1Inv, index_dirRatio2Inv; + + dir2band = 0; + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) { - if ( q_direction->band_data[b].energy_ratio_index[0] < ( DIRAC_DIFFUSE_LEVELS - 1 ) ) + if ( hQMetaData->twoDirBands[j] == 1 ) { - bits_delta += q_direction->band_data[b].bits_sph_idx[0]; - q_direction->band_data[b].energy_ratio_index[0]++; - q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; - bits_delta -= q_direction->band_data[b].bits_sph_idx[0]; + index_dirRatio1Inv = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + index_dirRatio2Inv = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_dirRatio1Inv; + } + + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[k] = index_dirRatio2Inv; + } + + dir2band++; } } } - assert( ( bits_delta >= 0 ) && "Bit budget in Qmetadata SID is violated!!!" ); - - /*Code diffuseness*/ - for ( b = start_band; b < nbands; b++ ) - { - ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); - } - /* Compute and Quantize an average direction per band*/ - for ( b = start_band; b < nbands; b++ ) + /* Encode surround coherence */ + if ( ndirections == 2 ) { - set_zero( avg_direction_vector, 3 ); - for ( m = 0; m < nblocks; m++ ) + no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks + hQMetaData->q_direction[1].cfg.nbands * hQMetaData->q_direction[1].cfg.nblocks; + if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - sum_s( bits_diff, ndirections ) >= MASA_MIN_BITS_SURR_COH ) ) { - /*compute the average direction */ - ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[b].azimuth[m], q_direction->band_data[b].elevation[m], direction_vector ); - v_add( avg_direction_vector, direction_vector, avg_direction_vector, 3 ); + bits_surround_coh = encode_surround_coherence( hQMetaData, hMetaData ); } - + else + { + bits_surround_coh = 0; + for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); + } + } + } + bits_no_dirs_coh += bits_surround_coh; + } + else + { + no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks; + if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - bits_diff[0] >= MASA_MIN_BITS_SURR_COH ) ) + { + bits_surround_coh = encode_surround_coherence( hQMetaData, hMetaData ); + } + else + { + bits_surround_coh = 0; + for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); + } + } + } + } + + /* Loop over number of directions*/ + for ( d = 0; d < ndirections; d++ ) + { + q_direction = &( hQMetaData->q_direction[d] ); + + if ( d == 1 ) + { + transform_azimuth_dir2( hQMetaData, dir2_bands ); + } + + nbands = q_direction->cfg.nbands; + nblocks = q_direction->cfg.nblocks; + start_band = q_direction->cfg.start_band; + diffuseness_index_max_ec_frame = diffuseness_index_max_ec_frame_pre[0]; + + + /* This sets bit budget correctly for the second direction */ + if ( d == 0 ) + { + bits_diff[d] = bits_diff_sum; + } + else + { + bits_diff[d] = 0; + } + +#ifdef DEBUG_MODE_QMETADATA + { + int16_t j, k; + k = 0; + fprintf( pF_spcoh_orig, "%d %d ", frame, k ); + + for ( i = start_band; i < nbands; i++ ) + { + for ( j = 0; j < nblocks; j++ ) + { + if ( q_direction->coherence_band_data != NULL ) + { + fprintf( pF_spcoh_orig, " %d ", q_direction->coherence_band_data[i].spread_coherence[j] ); + } + } + } + fprintf( pF_spcoh_orig, "\n" ); + } +#endif + + bits_signaling[d] = 0; + + /*Coherence */ + bits_coherence[d] = 0; + bit_pos_start_coh = hMetaData->nb_bits_tot; + + if ( all_coherence_zero == 0 ) + { + bits_coherence[d] = ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 0, &indice_coherence, 1 ); + } + + if ( q_direction->cfg.mc_ls_setup == MC_LS_SETUP_5_1 || q_direction->cfg.mc_ls_setup == MC_LS_SETUP_7_1 ) + { + q_direction->not_in_2D = 0; + /* Quantize directions*/ + quantize_direction_frame2D( q_direction, azimuth_orig, elevation_orig ); + } + else + { + /* Quantize directions*/ + quantize_direction_frame( q_direction, azimuth_orig, elevation_orig, 1 ); + } + + /* Signalling 2D*/ + push_next_indice( hMetaData, ( q_direction->not_in_2D > 0 ), 1 ); /*2D flag*/ + bits_signaling[d] = 1; + + /* Save state of metadata bitstream buffer after writing energy ratios, number of dirs and save space for coherence*/ + bit_pos_start = hMetaData->nb_bits_tot; + + + next_ind_raw_flag = hMetaData->next_ind; + push_next_indice( hMetaData, 0, 1 ); /* Raw coding flag*/ + + bits_dir_bands[0] = ivas_qmetadata_raw_encode_dir( NULL, q_direction, q_direction->cfg.nbands, q_direction->cfg.start_band ); + + reduce_bits = MASA_MAX_BITS_HR; + bits_ec = ivas_qmetadata_entropy_encode_dir( hMetaData, q_direction, diffuseness_index_max_ec_frame, + q_direction->cfg.nbands, q_direction->cfg.start_band, bits_dir_bands[0], reduce_bits, 1 ); + + if ( bits_ec < 0 ) + { + // printf( "%ld Not EC1\n", frame ); + hMetaData->ind_list[next_ind_raw_flag].value = 1; /*rewrite flag*/ + bits_ec = ivas_qmetadata_raw_encode_dir( hMetaData, q_direction, q_direction->cfg.nbands, q_direction->cfg.start_band ); +#ifdef DEBUGGING + assert( bits_dir_bands[0] == bits_ec ); +#endif + } + bits_dir[d] = bits_ec + 1; + + +#ifdef DEBUGGING + assert( bit_pos_start + bits_signaling[d] - 1 + bits_dir[d] == hMetaData->nb_bits_tot ); +#endif +#ifdef DEBUG_MODE_QMETADATA + ec_flag = 0; +#endif + + + /* finalize writing coherence */ + if ( ( bits_coherence[d] > 0 ) && ( all_coherence_zero == 0 ) && ( nblocks > 1 ) ) + { + bit_pos_start = hMetaData->nb_bits_tot; + hMetaData->nb_bits_tot = bit_pos_start_coh; + ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 1, &indice_coherence, 1 ); + hMetaData->nb_bits_tot = bit_pos_start; + } + +#ifdef DEBUG_MODE_QMETADATA + { + int16_t j; + float tmp_f, mat_dist[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; + + fprintf( pF, "frame %d: diff %d coh %d surcoh %d ", frame, bits_diff[d], bits_coherence[d], bits_surround_coh ); + fprintf( pF, "dir %d, %d %5.3f\n", ec_flag, hMetaData->nb_bits_tot - bit_pos_0, direction_distance( elevation_orig, azimuth_orig, q_direction, nbands, nblocks, mat_dist ) ); + fprintf( pF_azi, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); + fprintf( pF_ele, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); + fprintf( pF_ratio, "frame %d/dir %d: ", frame, d ); + /*fprintf( pF_spcoh, "frame %d/dir %d: ", frame, d ); */ + fprintf( pF_spcoh, " %d %d ", frame, d ); + if ( d == 0 ) + { + fprintf( pF_surcoh, "frame %d/dir %d: ", frame, d ); + } + + /* direction_distance( elevation_orig, azimuth_orig, q_direction, nbands, nblocks, mat_dist );*/ + for ( i = start_band; i < nbands; i++ ) + { + for ( j = 0; j < nblocks; j++ ) + { + fprintf( pF_azi, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[i].azimuth[j] ) / 100.f ); + fprintf( pF_ele, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[i].elevation[j] ) / 100.f ); + fprintf( pF_ratio, " %1.3f ", q_direction->band_data[i].energy_ratio[j] ); + if ( q_direction->coherence_band_data != NULL ) + { + fprintf( pF_spcoh, " %d ", q_direction->coherence_band_data[i].spread_coherence[j] ); + } + if ( d == 0 && hQMetaData->surcoh_band_data != NULL ) + { + fprintf( pF_surcoh, " %d ", hQMetaData->surcoh_band_data[i].surround_coherence[0] ); + } + } + } + fprintf( pF_azi, "\n" ); + fprintf( pF_ele, "\n" ); + fprintf( pF_ratio, "\n" ); + fprintf( pF_spcoh, "\n" ); + if ( d == 0 ) + { + fprintf( pF_surcoh, "\n" ); + } + + for ( i = 0; i < nblocks; i++ ) + { + for ( j = 0; j < nbands; j++ ) + { + dbgwrite( &( q_direction->band_data[j].azimuth[i] ), sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_azi.bin" ); + dbgwrite( &( q_direction->band_data[j].elevation[i] ), sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_ele.bin" ); + dbgwrite( &( mat_dist[j][i] ), sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_dist.bin" ); + dbgwrite( &( q_direction->band_data[j].energy_ratio_index[i] ), sizeof( uint16_t ), 1, 1, "./res/IVAS_QMETADATA_diffuseness_index.bin" ); + tmp_f = 1.f - q_direction->band_data[j].energy_ratio[i]; + dbgwrite( &tmp_f, sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_diffuseness.bin" ); + } + } + + j = (int16_t) ( hMetaData->nb_bits_tot ); + dbgwrite( &j, sizeof( int16_t ), 1, 1, "./res/IVAS_QMETADATA_bits.bin" ); + } +#endif + + /* Save quantized DOAs */ + for ( i = start_band; i < nbands; i++ ) + { + mvr2r( q_direction->band_data[i].azimuth, q_direction->band_data[i].q_azimuth, nblocks ); + mvr2r( q_direction->band_data[i].elevation, q_direction->band_data[i].q_elevation, nblocks ); + } + + /* Copy original DOAs back to q_direction*/ + for ( i = start_band; i < nbands; i++ ) + { + mvr2r( azimuth_orig[i], q_direction->band_data[i].azimuth, nblocks ); + mvr2r( elevation_orig[i], q_direction->band_data[i].elevation, nblocks ); + } + } + + return error; +} + + +ivas_error ivas_qmetadata_enc_encode_hr_512( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *hQMetaData /* i/o: metadata handle */ +) +{ + int16_t i, j; +#ifndef HR_METADATA_HR_COH + int16_t bit_pos_start_coh, bit_pos_start, bits_surround_coh, bits_coherence[QMETADATA_MAX_NO_DIRECTIONS], bit_pos_0; + int16_t indice_coherence; +#endif + int16_t bits_diff[QMETADATA_MAX_NO_DIRECTIONS]; + IVAS_QDIRECTION *q_direction; + int16_t nbands, nblocks, start_band; + int16_t ndirections, d; + int16_t all_coherence_zero; + int16_t bits_no_dirs_coh; + int16_t bits_ec; + + + ivas_error error; + + error = IVAS_ERR_OK; + +#ifdef DEBUG_MODE_QMETADATA + + static FILE *pF = NULL; + static FILE *pF_azi = NULL; + static FILE *pF_ele = NULL; + static FILE *pF_ratio = NULL; + static FILE *pF_spcoh = NULL; + static FILE *pF_spcoh_orig = NULL; + static FILE *pF_surcoh = NULL; + + if ( pF == NULL ) + pF = fopen( "./res/qmetadata_enc.txt", "w" ); + if ( pF_azi == NULL ) + pF_azi = fopen( "./res/qmetadata_azi_enc.txt", "w" ); + if ( pF_ele == NULL ) + pF_ele = fopen( "./res/qmetadata_ele_enc.txt", "w" ); + if ( pF_ratio == NULL ) + pF_ratio = fopen( "./res/qmetadata_ratio_enc.txt", "w" ); + if ( pF_spcoh == NULL ) + pF_spcoh = fopen( "./res/qmetadata_spcoh_enc.txt", "w" ); + if ( pF_spcoh_orig == NULL ) + pF_spcoh_orig = fopen( "./res/qmetadata_spcoh_orig.txt", "w" ); + if ( pF_surcoh == NULL ) + pF_surcoh = fopen( "./res/qmetadata_surcoh_enc.txt", "w" ); +#endif + + + /* Save initial position in bitstream */ + +#ifndef HR_METADATA_HR_COH + bit_pos_0 = hMetaData->nb_bits_tot; + bit_pos_start = bit_pos_0; +#endif + ndirections = hQMetaData->no_directions; + + + /* Check if coherence should be encoded */ + all_coherence_zero = 1; + bits_no_dirs_coh = 0; + + if ( hQMetaData->coherence_flag ) + { + all_coherence_zero = hQMetaData->all_coherence_zero; + push_next_indice( hMetaData, all_coherence_zero, 1 ); /* signal coherence */ + bits_no_dirs_coh += 1; + } + + /*Quantization and encoding of the Diffuseness */ + + ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( hQMetaData, bits_diff, 16, hMetaData ); + + /* Encode surround coherence */ + if ( all_coherence_zero == 0 ) + { + encode_surround_coherence_hr( hQMetaData, hMetaData ); + } + else + { +#ifndef HR_METADATA_HR_COH + bits_surround_coh = 0; +#endif + for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) + { + if ( hQMetaData->surcoh_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); + } + } + } + + + /* Loop over number of directions*/ + for ( d = 0; d < ndirections; d++ ) + { + q_direction = &( hQMetaData->q_direction[d] ); + + nbands = q_direction->cfg.nbands; + nblocks = q_direction->cfg.nblocks; + start_band = q_direction->cfg.start_band; + + +#ifdef DEBUG_MODE_QMETADATA + { + int16_t k; + k = 0; + fprintf( pF_spcoh_orig, "%d %d ", frame, k ); + + for ( i = start_band; i < nbands; i++ ) + { + for ( j = 0; j < nblocks; j++ ) + { + if ( q_direction->coherence_band_data != NULL ) + { + fprintf( pF_spcoh_orig, " %d ", q_direction->coherence_band_data[i].spread_coherence[j] ); + } + } + } + fprintf( pF_spcoh_orig, "\n" ); + } +#endif + + /*Coherence */ + +#ifndef HR_METADATA_HR_COH + bits_coherence[d] = 0; + bit_pos_start_coh = hMetaData->nb_bits_tot; +#endif + if ( all_coherence_zero == 0 ) + { +#ifdef HR_METADATA_HR_COH + ivas_qmetadata_quantize_coherence_hr_512( hQMetaData, d, all_coherence_zero, hMetaData ); +#else + bits_coherence[d] = ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 0, &indice_coherence, 1 ); +#endif + } + + /* write the 16bit spherical indexes */ + bits_ec = hMetaData->nb_bits_tot; + for ( i = start_band; i < nbands; i++ ) + { + for ( j = 0; j < nblocks; j++ ) + { + push_next_indice( hMetaData, q_direction->band_data[i].spherical_index[j], 16 ); + } + } + bits_ec = hMetaData->nb_bits_tot - bits_ec; + +#ifndef HR_METADATA_HR_COH + /* finalize writing coherence */ + if ( ( bits_coherence[d] > 0 ) && ( all_coherence_zero == 0 ) && ( nblocks > 1 ) ) + { + bit_pos_start = hMetaData->nb_bits_tot; + hMetaData->nb_bits_tot = bit_pos_start_coh; + ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 1, &indice_coherence, 1 ); + hMetaData->nb_bits_tot = bit_pos_start; + } +#endif + +#ifdef DEBUG_MODE_QMETADATA + { + float tmp_f; + fprintf( pF, "frame %d: diff %d ", frame, bits_diff[d] ); + fprintf( pF_azi, "frame %d/dir/ec %d: ", frame, d ); + fprintf( pF_ele, "frame %d/dir/ec %d: ", frame, d ); + fprintf( pF_ratio, "frame %d/dir %d: ", frame, d ); + /*fprintf( pF_spcoh, "frame %d/dir %d: ", frame, d ); */ + fprintf( pF_spcoh, " %d %d ", frame, d ); + + if ( d == 0 ) + { + fprintf( pF_surcoh, "frame %d/dir %d: ", frame, d ); + } + + /* direction_distance( elevation_orig, azimuth_orig, q_direction, nbands, nblocks, mat_dist );*/ + for ( i = start_band; i < nbands; i++ ) + { + for ( j = 0; j < nblocks; j++ ) + { + fprintf( pF_azi, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[i].azimuth[j] ) / 100.f ); + fprintf( pF_ele, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[i].elevation[j] ) / 100.f ); + fprintf( pF_ratio, " %1.3f ", q_direction->band_data[i].energy_ratio[j] ); + if ( q_direction->coherence_band_data != NULL ) + { + fprintf( pF_spcoh, " %d ", q_direction->coherence_band_data[i].spread_coherence[j] ); + } + if ( d == 0 && hQMetaData->surcoh_band_data != NULL ) + { + fprintf( pF_surcoh, " %d ", hQMetaData->surcoh_band_data[i].surround_coherence[j] ); + } + } + } + fprintf( pF, "\n" ); + fprintf( pF_azi, "\n" ); + fprintf( pF_ele, "\n" ); + fprintf( pF_ratio, "\n" ); + fprintf( pF_spcoh, "\n" ); + if ( d == 0 ) + { + fprintf( pF_surcoh, "\n" ); + } + + for ( i = 0; i < nblocks; i++ ) + { + for ( j = 0; j < nbands; j++ ) + { + dbgwrite( &( q_direction->band_data[j].azimuth[i] ), sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_azi.bin" ); + dbgwrite( &( q_direction->band_data[j].elevation[i] ), sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_ele.bin" ); + dbgwrite( &( q_direction->band_data[j].energy_ratio_index[i] ), sizeof( uint16_t ), 1, 1, "./res/IVAS_QMETADATA_diffuseness_index.bin" ); + tmp_f = 1.f - q_direction->band_data[j].energy_ratio[i]; + dbgwrite( &tmp_f, sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_diffuseness.bin" ); + } + } + + j = (int16_t) ( hMetaData->nb_bits_tot ); + dbgwrite( &j, sizeof( int16_t ), 1, 1, "./res/IVAS_QMETADATA_bits.bin" ); + } +#endif + + /* Save quantized DOAs */ + for ( i = start_band; i < nbands; i++ ) + { + mvr2r( q_direction->band_data[i].azimuth, q_direction->band_data[i].q_azimuth, nblocks ); + mvr2r( q_direction->band_data[i].elevation, q_direction->band_data[i].q_elevation, nblocks ); + } + } + + return error; +} + +#endif + +/*-----------------------------------------------------------------------* + * ivas_qmetadata_enc_sid_encode() + * + * Main function for coding SID for Spatial Metadata + *-----------------------------------------------------------------------*/ + +/*! r: number of bits written */ +void ivas_qmetadata_enc_sid_encode( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *q_metadata, /* i/o: metadata handle */ + const int16_t masa_sid_descriptor, /* i : description of MASA SID coding structure */ + const int16_t ivas_format, /* i : IVAS format */ + const SBA_MODE sba_mode /* i : SBA mode */ +) +{ + int16_t b, m; + int16_t bit_pos_start; + IVAS_QDIRECTION *q_direction; + int16_t nbands, nblocks, start_band; + float avg_direction_vector[3]; + float direction_vector[3]; + float avg_azimuth[MASA_MAXIMUM_CODING_SUBBANDS]; + float avg_elevation[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t bits_dir, bits_diff, bits_delta; + int16_t metadata_sid_bits; /* bits allocated to SID for metadata */ + + if ( ivas_format == SBA_FORMAT ) + { + if ( sba_mode == SBA_MODE_SPAR ) + { + /* TODO: still use old sid frame size to keep bitexactness */ + metadata_sid_bits = (int16_t) ( 5000 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - ( SPAR_DTX_BANDS * SPAR_SID_BITS_TAR_PER_BAND ) - 1; /* -1 for inactive mode header bit*/ + } + else + { + /* keep 13.2 and 16.4 SID bitrate as 4.4 kbps for now*/ + /* TODO: still use old sid frame size to keep bitexactness */ + metadata_sid_bits = ( 4400 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; + } + } + else + { + /* TODO: still use old sid frame size to keep bitexactness */ + metadata_sid_bits = ( 4400 /*IVAS_SID_5k2*/ - SID_2k40 ) / FRAMES_PER_SEC - SID_FORMAT_NBITS; + } + +#ifdef DEBUG_MODE_QMETADATA + static FILE *pF_azi = NULL; + static FILE *pF_ele = NULL; + static FILE *pF_ratio = NULL; + + if ( pF_azi == NULL ) + pF_azi = fopen( "./res/qmetadata_sid_azi_enc.txt", "w" ); + if ( pF_ele == NULL ) + pF_ele = fopen( "./res/qmetadata_sid_ele_enc.txt", "w" ); + if ( pF_ratio == NULL ) + pF_ratio = fopen( "./res/qmetadata_sid_ratio_enc.txt", "w" ); + +#endif + + /* Save initial position in bitstream */ + bit_pos_start = hMetaData->nb_bits_tot; + + /* write for MASA the number of transport channels used at coding and the CPE mode DFT/MDCT */ + if ( masa_sid_descriptor > -1 ) + { + push_next_indice( hMetaData, masa_sid_descriptor, 1 ); + } + + /* Code for one direction: diffuseness and average DOA(s)*/ + q_direction = &( q_metadata->q_direction[0] ); + nbands = q_direction->cfg.nbands; + nblocks = q_direction->cfg.nblocks; + start_band = 0; /*Start always with band 0 for SID*/ + + /* sanity checks*/ + assert( q_metadata->no_directions == 1 && "Qmetadata SID: only one direction supported!" ); + if ( sba_mode == SBA_MODE_SPAR ) + { + assert( ( q_direction->cfg.nbands == DIRAC_DTX_BANDS ) && "Qmetadata SID: only 2 bands supported!" ); + } + else + { + assert( ( q_direction->cfg.nbands == 5 ) && "Qmetadata SID: only 5 bands supported!" ); + } + + if ( sba_mode != SBA_MODE_SPAR ) + { + /* Signalling 2D*/ + push_next_indice( hMetaData, ( q_direction->not_in_2D > 0 ), 1 ); /*2D flag*/ + } + else + { + q_direction->not_in_2D = 1; /* force for merged modes */ + } + + /*Encode the quantized diffuseness in raw coding*/ + bits_dir = 0; + bits_diff = 0; + for ( b = start_band; b < nbands; b++ ) + { + q_direction->band_data[b].energy_ratio_index[0] = max( q_direction->band_data[b].energy_ratio_index[0], 4 ); + bits_diff += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); + + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; + if ( q_direction->not_in_2D == 0 ) + { + q_direction->band_data[b].azimuth_m_alphabet[0] = 1 << ( min( 5, q_direction->band_data[b].bits_sph_idx[0] ) ); + bits_dir += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].azimuth_m_alphabet[0] - 1, q_direction->band_data[b].azimuth_m_alphabet[0] ); + } + else + { + bits_dir += q_direction->band_data[b].bits_sph_idx[0]; + } + } + + /* Reduce bit demand by increasing diffuseness*/ + bits_delta = metadata_sid_bits - ( hMetaData->nb_bits_tot - bit_pos_start ) - bits_diff - bits_dir; + + while ( bits_delta < 0 && ( q_direction->not_in_2D > 0 ) ) + { + for ( b = nbands - 1; b >= start_band && ( bits_delta < 0 ); b-- ) + { + if ( q_direction->band_data[b].energy_ratio_index[0] < ( DIRAC_DIFFUSE_LEVELS - 1 ) ) + { + bits_delta += q_direction->band_data[b].bits_sph_idx[0]; + q_direction->band_data[b].energy_ratio_index[0]++; + q_direction->band_data[b].bits_sph_idx[0] = bits_direction_masa[q_direction->band_data[b].energy_ratio_index[0]]; + bits_delta -= q_direction->band_data[b].bits_sph_idx[0]; + } + } + } + assert( ( bits_delta >= 0 ) && "Bit budget in Qmetadata SID is violated!!!" ); + + /*Code diffuseness*/ + for ( b = start_band; b < nbands; b++ ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - 4, DIRAC_DIFFUSE_LEVELS - 4 ); + } + + /* Compute and Quantize an average direction per band*/ + for ( b = start_band; b < nbands; b++ ) + { + set_zero( avg_direction_vector, 3 ); + for ( m = 0; m < nblocks; m++ ) + { + /*compute the average direction */ + ivas_qmetadata_azimuth_elevation_to_direction_vector( q_direction->band_data[b].azimuth[m], q_direction->band_data[b].elevation[m], direction_vector ); + v_add( avg_direction_vector, direction_vector, avg_direction_vector, 3 ); + } + ivas_qmetadata_direction_vector_to_azimuth_elevation( avg_direction_vector, &avg_azimuth[b], &avg_elevation[b] ); /* Quantize the average direction */ @@ -1033,10 +1742,303 @@ int16_t quantize_direction2D( idx_sph = id_phi; - return idx_sph; + return idx_sph; +} + +#ifdef HR_METADATA +/*------------------------------------------------------------------------- + * ivas_qmetadata_quantize_diffuseness_nrg_ratios() + * + * Quantize diffuseness + *------------------------------------------------------------------------*/ + +static void ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr( + IVAS_QMETADATA_HANDLE hQMetaData, + int16_t *needed_bits, + int16_t *nbits_diff, + int16_t *dfRatioBits, + int16_t bits_dir_hr ) +{ + int16_t j, k, dir2band; + int16_t index_dirRatio1Inv, index_dirRatio2Inv, index_dirRatio1Inv_mod, index_dirRatio2Inv_mod; + int16_t index_diff; + + nbits_diff[0] = 0; + nbits_diff[1] = 0; + needed_bits[0] = 0; + needed_bits[1] = 0; + dir2band = 0; + + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) + { + if ( hQMetaData->no_directions == 2 && hQMetaData->twoDirBands[j] == 1 ) + { + float dirRatio1, dirRatio2, diffRatio, sumRatio, dfRatio, dfRatioQ, diffRatioQ, dirRatio1Q, dirRatio2Q; + int16_t dfRatio_index, dfRatio_qsteps, dfRatio_bits; + + /* With 2dir metadata, we quantize and transmit diffuse-to-total ratio (diffRatio) and + * distribution factor of direct-to-total ratios (dFRatio). This is more efficient and + * accurate than simple separate quantization of each direct-to-total ratio or their + * separate inverses. */ + dirRatio1 = hQMetaData->q_direction[0].band_data[j].energy_ratio[0]; + dirRatio2 = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0]; + sumRatio = dirRatio1 + dirRatio2; + diffRatio = 1.0f - sumRatio; + dfRatio = sumRatio < EPSILON ? 0.5f : dirRatio1 / sumRatio; + + index_diff = masa_sq( diffRatio, diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + diffRatioQ = diffuseness_reconstructions_hr[index_diff]; + + dfRatio_bits = ivas_get_df_ratio_bits( index_diff >> 1 ); + + dfRatioBits[dir2band] = dfRatio_bits; + + dfRatio_qsteps = ( 1 << dfRatio_bits ); + dfRatio_index = usquant( dfRatio, &dfRatioQ, 0.5f, 0.5f / ( dfRatio_qsteps - 1 ), dfRatio_qsteps ); + + /* Direction quantization requires also separately quantized direct-to-total ratios. Thus, we calculate them. */ + dirRatio1Q = dfRatioQ * ( 1.0f - diffRatioQ ); + dirRatio2Q = ( 1.0f - diffRatioQ ) - dirRatio1Q; + + index_dirRatio1Inv = masa_sq( 1.0f - dirRatio1Q, diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + + /* Note: To save memory, we store temporarily index_diff and dfRatio_index into first and second direction + * energy ratio index variables until they have been encoded. index_dirRatio1Inv and index_dirRatio2Inv are + * then later retrieved for further use in encoding. */ + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_diff; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = dirRatio1Q; + } + nbits_diff[0] += MASA_BITS_ER_HR; + + index_dirRatio2Inv = masa_sq( 1.0f - dirRatio2Q, diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[k] = dfRatio_index; + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[k] = dirRatio2Q; + } + nbits_diff[1] += dfRatio_bits; + + /* Obtain compensated direct-to-total ratios for direction quantization. This compensates for the + * fact that with 2dir data, it is harder to achieve separate high direct-to-total ratio values + * which are assumed by the direction quantization system. In practice, this improves direction + * accuracy when it is perceptual meaningful. */ + masa_compensate_two_dir_energy_ratio_index( index_dirRatio1Inv, index_dirRatio2Inv, &index_dirRatio1Inv_mod, &index_dirRatio2Inv_mod ); + + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index_dirRatio1Inv_mod; + + if ( bits_dir_hr > 0 ) + { + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + else + { + + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_direction_masa[index_dirRatio1Inv_mod]; + } + } + needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_direction_masa[index_dirRatio1Inv_mod]; + + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index_mod[k] = index_dirRatio2Inv_mod; + + if ( bits_dir_hr > 0 ) + { + hQMetaData->q_direction[1].band_data[dir2band].bits_sph_idx[k] = bits_dir_hr; + } + else + { + + hQMetaData->q_direction[1].band_data[dir2band].bits_sph_idx[k] = bits_direction_masa[index_dirRatio2Inv_mod]; + } + } + needed_bits[1] += hQMetaData->q_direction[1].cfg.nblocks * bits_direction_masa[index_dirRatio2Inv_mod]; + + dir2band++; + } + else + { + index_dirRatio1Inv = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_dirRatio1Inv; + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index_dirRatio1Inv; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index_dirRatio1Inv]; + + if ( bits_dir_hr > 0 ) + { + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + else + { + + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_direction_masa[index_dirRatio1Inv]; + } + } + + nbits_diff[0] += MASA_BITS_ER_HR; + + needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_dir_hr; + } + } + + return; +} + + +static void ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( + IVAS_QMETADATA_HANDLE hQMetaData, + int16_t *needed_bits, + int16_t bits_dir_hr, + BSTR_ENC_HANDLE hMetaData ) +{ + int16_t j, k; + int16_t index; + + + needed_bits[0] = 0; + needed_bits[1] = 0; + + + for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) + { + for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) + { + index = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[0].band_data[j].energy_ratio_index_mod[k] = index; + hQMetaData->q_direction[0].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + needed_bits[0] += MASA_BITS_ER_HR; + hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + } + for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; ++j ) + { + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + { + index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + if ( hQMetaData->q_direction[1].band_data[j].energy_ratio[k] > 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k] ) + { + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k]; + } + needed_bits[1] += MASA_BITS_ER_HR; + hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; + } + } + + return; +} + + +/*------------------------------------------------------------------------- + * ivas_qmetadata_entropy_encode_diffuseness() + * + * encode diffuseness + *------------------------------------------------------------------------*/ + +static int16_t ivas_qmetadata_entropy_encode_diffuseness_hr( + BSTR_ENC_HANDLE hMetaData, + IVAS_QDIRECTION *q_direction, + uint16_t *diffuseness_index_max_ec_frame ) +{ + int16_t start_bit_pos; + int16_t diffuseness_bits_raw; + int16_t b; + int16_t min_diffuseness_m_index, max_diffuseness_m_index; + int16_t nbands; + int16_t start_band; + + nbands = q_direction->cfg.nbands; + start_band = q_direction->cfg.start_band; + + start_bit_pos = hMetaData->nb_bits_tot; + + if ( nbands == 1 ) + { + /* If there is only one band, diffuseness should be coded directly as raw with no signaling. */ + push_next_indice( hMetaData, q_direction->band_data[0].energy_ratio_index[0], MASA_BITS_ER_HR ); + *diffuseness_index_max_ec_frame = 10; + return ( hMetaData->nb_bits_tot - start_bit_pos ); + } + + /* compute the number of raw coding bits */ + diffuseness_bits_raw = 0; + for ( b = start_band; b < nbands; b++ ) + { + diffuseness_bits_raw += ivas_qmetadata_encode_quasi_uniform_length( q_direction->band_data[b].energy_ratio_index[0], HR_MASA_ER_LEVELS ); + } + + min_diffuseness_m_index = q_direction->band_data[start_band].energy_ratio_index[0]; + max_diffuseness_m_index = q_direction->band_data[start_band].energy_ratio_index[0]; + + for ( b = start_band; b < nbands; b++ ) + { + if ( q_direction->band_data[b].energy_ratio_index[0] < min_diffuseness_m_index ) + { + min_diffuseness_m_index = q_direction->band_data[b].energy_ratio_index[0]; + } + + if ( q_direction->band_data[b].energy_ratio_index[0] > max_diffuseness_m_index ) + { + max_diffuseness_m_index = q_direction->band_data[b].energy_ratio_index[0]; + } + } + + + /* Use similarity coding approach or raw coding when there is a low number of bands. */ + /* one bit is used to indicate whether diffuseness values are entropy coded or coded raw */ + if ( min_diffuseness_m_index == max_diffuseness_m_index ) /* all values are equal */ + { + push_next_indice( hMetaData, 0, 1 ); /* dif_use_raw_coding */ + push_next_indice( hMetaData, 1, 1 ); /* dif_have_unique_value */ + ivas_qmetadata_encode_quasi_uniform( hMetaData, min_diffuseness_m_index, HR_MASA_ER_LEVELS ); /* dif_unique_value */ + } + else if ( min_diffuseness_m_index + 1 == max_diffuseness_m_index ) /* only two consecutive values are present */ + { + push_next_indice( hMetaData, 0, 1 ); /* dif_use_raw_coding */ + push_next_indice( hMetaData, 0, 1 ); /* dif_have_unique_value */ + ivas_qmetadata_encode_quasi_uniform( hMetaData, min_diffuseness_m_index, HR_MASA_ER_LEVELS - 1 ); /* dif_min_value */ + + for ( b = start_band; b < nbands; b++ ) + { + push_next_indice( hMetaData, q_direction->band_data[b].energy_ratio_index[0] - min_diffuseness_m_index, 1 ); /* dif_bit_offset_values */ + } + } + else /* raw coding */ + { + push_next_indice( hMetaData, 1, 1 ); /* dif_use_raw_coding */ + + for ( b = start_band; b < nbands; b++ ) + { + ivas_qmetadata_encode_quasi_uniform( hMetaData, q_direction->band_data[b].energy_ratio_index[0], HR_MASA_ER_LEVELS ); /* dif_values */ + } + } + + + *diffuseness_index_max_ec_frame = 10; + /* adaptively select the diffuseness_index_max_ec threshold */ + if ( min_diffuseness_m_index > 10 ) + { + *diffuseness_index_max_ec_frame = HR_MASA_ER_LEVELS - 1; + } + +#ifdef DEBUGGING + assert( ( hMetaData->nb_bits_tot - start_bit_pos ) <= 1 + diffuseness_bits_raw ); +#endif + + return ( hMetaData->nb_bits_tot - start_bit_pos ); } - +#endif /*------------------------------------------------------------------------- * ivas_qmetadata_quantize_diffuseness_nrg_ratios() * @@ -1145,6 +2147,7 @@ static void ivas_qmetadata_quantize_diffuseness_nrg_ratios( } nbits_diff[0] += MASA_BITS_ER; + needed_bits[0] += hQMetaData->q_direction[0].cfg.nblocks * bits_direction_masa[index_dirRatio1Inv]; } } @@ -1799,7 +2802,12 @@ static int16_t ivas_qmetadata_entropy_encode_dir( const int16_t nbands, const int16_t start_band, const int16_t direction_bits_raw, - int16_t max_bits ) + int16_t max_bits +#ifdef HR_METADATA + , + int16_t is_hr +#endif +) { uint16_t diff_idx_min; int16_t i, j; @@ -1845,7 +2853,18 @@ static int16_t ivas_qmetadata_entropy_encode_dir( set_zero( avg_direction_vector, 3 ); for ( i = start_band; i < nbands; i++ ) { - diff_idx_min = min( q_direction->band_data[i].energy_ratio_index_mod[0], diff_idx_min ); +#ifdef HR_METADATA + if ( is_hr ) + { + diff_idx_min = 0; // min( q_direction->band_data[i].energy_ratio_index_mod[0]>>1, diff_idx_min ); + } + else + { +#endif + diff_idx_min = min( q_direction->band_data[i].energy_ratio_index_mod[0], diff_idx_min ); +#ifdef HR_METADATA + } +#endif if ( q_direction->band_data[i].energy_ratio_index_mod[0] > diffuseness_index_max_ec_frame ) { @@ -1895,6 +2914,7 @@ static int16_t ivas_qmetadata_entropy_encode_dir( no_th = no_theta_masa[bits_direction_masa[diff_idx_min] - 3]; + for ( i = 0; i < no_th; i++ ) { theta_cb[i] = i * delta_theta_masa[bits_direction_masa[diff_idx_min] - 3]; @@ -4054,6 +5074,10 @@ static int16_t encode_spread_coherence_1sf( IVAS_QMETADATA *q_metadata, /* i : quantized metadata */ const int16_t idx_d, /* i : current direction index */ BSTR_ENC_HANDLE hMasaMetaData /* i/o: metadata bitstream handle */ +#ifdef HR_METADATA + , + int16_t is_hr +#endif ) { int16_t i, j, k; @@ -4079,11 +5103,23 @@ static int16_t encode_spread_coherence_1sf( GR_ord = 1; idx_shift = 0; + /* number of codevectors added dependent on number of subbands */ extra_cv = coding_subbands / MASA_FACTOR_CV_COH; for ( j = 0; j < coding_subbands; j++ ) { - idx_ER = 7 - q_direction->band_data[j].energy_ratio_index_mod[0] + extra_cv; +#ifdef HR_METADATA + if ( is_hr ) + { + idx_ER = 7 - ( q_direction->band_data[j].energy_ratio_index_mod[0] >> 1 ) + extra_cv; + } + else + { +#endif + idx_ER = 7 - q_direction->band_data[j].energy_ratio_index_mod[0] + extra_cv; +#ifdef HR_METADATA + } +#endif if ( idx_ER > 0 ) { idx_sp_coh[j] = (uint16_t) roundf( q_direction->coherence_band_data[j].spread_coherence[0] / ( 255.0f / (float) idx_ER ) ); @@ -4432,6 +5468,204 @@ static int16_t encode_surround_coherence( return nbits; } +#ifdef HR_METADATA +static int16_t encode_surround_coherence_hr( + IVAS_QMETADATA *hQMetaData, /* i : quantized metadata */ + BSTR_ENC_HANDLE hMetaData /* i/o: metadata bitstream handle */ +) +{ + int16_t i, j, k, sf; + int16_t nbits, nbits_fr, nbits_sf; + uint16_t idx_sur_coh[MASA_MAXIMUM_CODING_SUBBANDS]; + uint16_t mr_idx_sur_coh[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t GR_ord, bits_GR; + uint64_t idx, idx1; + int16_t no_idx16; + int16_t no_cv[MASA_MAXIMUM_CODING_SUBBANDS]; + float error_ratio_surr; + IVAS_QDIRECTION *q_direction; + int16_t half_coding_subbands, nbits_fr1, coding_subbands; + int16_t all_coherence_zero; + uint16_t idx_sur_coh_shift[MASA_MAXIMUM_CODING_SUBBANDS]; + uint8_t idx_shift; + int16_t max_val = 0, nbits_max; + int16_t no_cv_shift[MASA_MAXIMUM_CODING_SUBBANDS], min_idx; + + coding_subbands = hQMetaData->q_direction[0].cfg.nbands; + all_coherence_zero = hQMetaData->all_coherence_zero; + q_direction = &( hQMetaData->q_direction[0] ); + nbits = 0; + + if ( all_coherence_zero == 1 ) + { + nbits = 0; + } + else + { + for ( sf = 0; sf < hQMetaData->q_direction[0].cfg.nblocks; sf++ ) + { + GR_ord = 1; + k = 0; + idx_shift = 0; + for ( j = 0; j < coding_subbands; j++ ) + { + if ( hQMetaData->no_directions == 2 ) + { + error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf] - q_direction[1].band_data[j].energy_ratio[sf] * hQMetaData->twoDirBands[j]; + } + else + { + error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf]; + } + if ( error_ratio_surr <= 0 ) + { + error_ratio_surr = 0; + idx_sur_coh[j] = 0; + no_cv[j] = 1; + hQMetaData->surcoh_band_data[j].surround_coherence[sf] = 0; /* sur_coherence_cb_masa[idx_cb_sur_coh_masa[DIRAC_DIFFUSE_LEVELS - 1] * MASA_MAX_NO_CV_SUR_COH]; */ + } + else + { + idx_sur_coh[j] = squant_int( hQMetaData->surcoh_band_data[j].surround_coherence[sf], &hQMetaData->surcoh_band_data[j].surround_coherence[sf], + &sur_coherence_cb_masa[idx_cb_sur_coh_masa[7] * MASA_MAX_NO_CV_SUR_COH], idx_cb_sur_coh_masa[7] + 2 ); + no_cv[j] = idx_cb_sur_coh_masa[7] + 2; + no_cv_shift[idx_shift] = no_cv[j]; + idx_sur_coh_shift[idx_shift++] = idx_sur_coh[j]; + } + } + + if ( sum_s( no_cv, coding_subbands ) != coding_subbands ) + { + nbits_max = 0; + if ( coding_subbands > MASA_LIMIT_NO_BANDS_SUR_COH ) + { + j = maximum_s( (int16_t *) idx_sur_coh, coding_subbands, &max_val ); + for ( j = 0; j < coding_subbands; j++ ) + { + if ( no_cv[j] > max_val + 1 ) + { + no_cv[j] = max_val + 1; + } + } + nbits_max = MASA_MAX_NO_CV_SUR_COH - max_val; /* encoded with GR0 as max_no_vals - no_vals*/ + } + if ( max_val == 0 ) + { + for ( j = 0; j < coding_subbands; j++ ) + { + hQMetaData->surcoh_band_data[j].surround_coherence[sf] = 0; + } + } + nbits_sf = coherence_coding_length( idx_sur_coh_shift, idx_shift, coding_subbands, no_cv, + mr_idx_sur_coh, no_cv_shift, &min_idx, &GR_ord, &nbits_fr, &nbits_fr1 ); + half_coding_subbands = coding_subbands / 2; + idx1 = 0; + + /* should check how to encode the average - check distribution */ + if ( nbits_fr + nbits_fr1 + nbits_max < nbits_sf ) + { + /* write flag*/ + push_next_indice( hMetaData, 0, 1 ); + + /* create combined index */ + nbits += nbits_fr + nbits_fr1 + 1; + if ( coding_subbands > MASA_LIMIT_NO_BANDS_SUR_COH ) + { + /* write max value*/ + bits_GR = hMetaData->nb_bits_tot; + ivas_qmetadata_encode_extended_gr( hMetaData, MASA_MAX_NO_CV_SUR_COH - max_val - 1, MASA_MAX_NO_CV_SUR_COH, 0 ); + nbits += hMetaData->nb_bits_tot - bits_GR; + } + + if ( nbits_fr1 > 0 ) + { + idx = create_combined_index( idx_sur_coh, half_coding_subbands, no_cv ); + idx1 = create_combined_index( &idx_sur_coh[half_coding_subbands], half_coding_subbands, &no_cv[half_coding_subbands] ); + } + else + { + idx = create_combined_index( idx_sur_coh, coding_subbands, no_cv ); + } + + if ( nbits_fr % 16 == 0 ) + { + no_idx16 = nbits_fr / 16; + } + else + { + no_idx16 = (int16_t) round_f( ( nbits_fr / 16.0f + 0.5f ) ); + } + + /* write combined index */ + k = nbits_fr; + for ( i = 0; i < no_idx16 - 1; i++ ) + { + k -= 16; + push_next_indice( hMetaData, ( ( idx >> k ) & 65535 ), 16 ); /* 16 bits */ + } + + push_next_indice( hMetaData, ( idx & ( ( 1 << k ) - 1 ) ), k ); + + if ( nbits_fr1 > 0 ) + { + if ( nbits_fr1 % 16 == 0 ) + { + no_idx16 = nbits_fr1 / 16; + } + else + { + no_idx16 = (int16_t) round_f( ( nbits_fr1 / 16.0f + 0.5f ) ); + } + + assert( no_idx16 <= 4 ); + + k = nbits_fr1; + for ( i = 0; i < no_idx16 - 1; i++ ) + { + k -= 16; + push_next_indice( hMetaData, ( ( idx1 >> k ) & 65535 ), 16 ); /* 16 bits */ + } + + push_next_indice( hMetaData, ( idx1 & ( ( 1 << k ) - 1 ) ), k ); + } + } + else + { + /* write flag */ + nbits += 1; + + /* write flag*/ + push_next_indice( hMetaData, 1, 1 ); + + /* write GR_ord */ + push_next_indice( hMetaData, GR_ord, 1 ); + nbits += 1; + + /* write the min */ + bits_GR = hMetaData->nb_bits_tot; + ivas_qmetadata_encode_extended_gr( hMetaData, min_idx, MASA_MAX_NO_CV_SUR_COH, 0 ); + nbits += hMetaData->nb_bits_tot - bits_GR; + + /* write GR data */ + for ( j = 0; j < idx_shift; j++ ) + { + bits_GR = hMetaData->nb_bits_tot; + + ivas_qmetadata_encode_extended_gr( hMetaData, mr_idx_sur_coh[j], no_cv_shift[j], GR_ord ); + + nbits += hMetaData->nb_bits_tot - bits_GR; + } + } + } + } + } + + + return nbits; +} + +#endif + /*-------------------------------------------------------------------* * quantize_DCT_0_coh() @@ -4449,14 +5683,42 @@ static float quantize_DCT_0_coh( IVAS_QDIRECTION *q_direction, /* i : quantized metadata */ uint16_t *idx_x, /* o : codewords index */ int16_t *p_no_cb /* o : actual number of codewords dependent on energy ratio value */ +#ifdef HR_METADATA + , + int16_t is_hr +#endif ) { float var_azi, xhat; int16_t idx_sub_cb, idx; - +#ifdef HR_METADATA + int16_t min_index; +#endif /* quantize first DCT component */ var_azi = var( q_direction->band_data[j].azimuth, q_direction->cfg.nblocks ); +#ifdef HR_METADATA + if ( is_hr ) + { + minimum_s( (int16_t *) ( q_direction->band_data[j].energy_ratio_index ), q_direction->cfg.nblocks, &min_index ); + min_index = min_index >> 1; + } + else + { + min_index = q_direction->band_data[j].energy_ratio_index[0]; + } + if ( var_azi < delta_var ) + { + idx_sub_cb = no_cb * min_index; + } + else + { + idx_sub_cb = no_cb * ( min_index + DIRAC_DIFFUSE_LEVELS ); + } + idx = squant( x, &xhat, &coherence_cb[idx_sub_cb], len_cb_dct0_masa[min_index] ); + + *p_no_cb = len_cb_dct0_masa[min_index]; +#else if ( var_azi < delta_var ) { idx_sub_cb = no_cb * q_direction->band_data[j].energy_ratio_index[0]; @@ -4469,7 +5731,7 @@ static float quantize_DCT_0_coh( idx = squant( x, &xhat, &coherence_cb[idx_sub_cb], len_cb_dct0_masa[q_direction->band_data[j].energy_ratio_index[0]] ); *p_no_cb = len_cb_dct0_masa[q_direction->band_data[j].energy_ratio_index[0]]; - +#endif *idx_x = idx; return xhat; @@ -4537,6 +5799,80 @@ static void dct4_transform( return; } +#ifdef HR_METADATA_HR_COH +static int16_t ivas_qmetadata_quantize_coherence_hr_512( + IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata */ + const int16_t idx_d, /* i : current direction index */ + const int16_t all_coherence_zero, /* i : all coherence is zero - flag */ + BSTR_ENC_HANDLE hMetaData /* i : metadata handle */ +) +{ + int16_t j, k; + int16_t nbands, nblocks; + int16_t nbits; + int16_t nbits1, nbits0; + int16_t idx_coh[MASA_MAXIMUM_CODING_SUBBANDS]; + IVAS_QDIRECTION *q_direction; + int16_t cbsize; + float delta, tmp; + int16_t min_idx, GR_param; + + q_direction = &( hQMetaData->q_direction[idx_d] ); + nbands = q_direction->cfg.nbands; + nblocks = q_direction->cfg.nblocks; + nbits = 0; + + if ( all_coherence_zero == 1 ) + { + return nbits; + } + nbits = hMetaData->nb_bits_tot; + + cbsize = 1 << NBITS_HR_COH; + delta = 256.0f / cbsize; + + for ( k = 0; k < nblocks; k++ ) + { + min_idx = 0; + for ( j = 0; j < nbands; j++ ) + { + idx_coh[j] = usquant( (float) ( q_direction->coherence_band_data[j].spread_coherence[k] ), &tmp, delta / 2.0f, delta, cbsize ); + q_direction->coherence_band_data[j].spread_coherence[k] = (uint8_t) ( idx_coh[j] * delta + delta / 2.0f ); + if ( idx_coh[j] < min_idx ) + { + min_idx = idx_coh[j]; + } + } + nbits0 = 0; + nbits1 = 0; + for ( j = 0; j < nbands; j++ ) + { + idx_coh[j] = idx_coh[j] - min_idx; + nbits0 += ivas_qmetadata_encode_extended_gr_length( idx_coh[j], cbsize - min_idx - 1, 0 ); + nbits1 += ivas_qmetadata_encode_extended_gr_length( idx_coh[j], cbsize - min_idx - 1, 1 ); + } + if ( nbits0 < nbits1 ) + { + GR_param = 0; + } + else + { + GR_param = 1; + } + /* write min index */ + push_next_indice( hMetaData, min_idx, NBITS_HR_COH ); + /* write GR param */ + push_next_indice( hMetaData, GR_param, 1 ); + for ( j = 0; j < nbands; j++ ) + { + ivas_qmetadata_encode_extended_gr( hMetaData, idx_coh[j], cbsize - min_idx, GR_param ); + } + } + + nbits = hMetaData->nb_bits_tot - nbits; + return nbits; +} +#endif /*-------------------------------------------------------------------* * ivas_qmetadata_quantize_coherence() @@ -4551,7 +5887,12 @@ static int16_t ivas_qmetadata_quantize_coherence( const int16_t all_coherence_zero, /* i : all coherence is zero - flag */ BSTR_ENC_HANDLE hMetaData, /* i : metadata handle */ const int16_t write_flag, /* i : flag to actually write the data or not */ - int16_t *indice_coherence ) + int16_t *indice_coherence +#ifdef HR_METADATA + , + int16_t is_hr +#endif +) { int16_t j, k; float dct_coh[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; @@ -4565,7 +5906,10 @@ static int16_t ivas_qmetadata_quantize_coherence( int16_t two_dir_band[MASA_MAXIMUM_CODING_SUBBANDS]; int16_t no_cb_vec[MASA_MAXIMUM_CODING_SUBBANDS]; IVAS_QDIRECTION *q_direction; - +#ifdef HR_METADATA + int16_t min_index; + min_index = 0; +#endif q_direction = &( hQMetaData->q_direction[idx_d] ); coding_subbands = q_direction->cfg.nbands; nbits = 0; @@ -4577,7 +5921,12 @@ static int16_t ivas_qmetadata_quantize_coherence( if ( hQMetaData->q_direction[idx_d].cfg.nblocks == 1 ) { - nbits = encode_spread_coherence_1sf( hQMetaData, idx_d, hMetaData ); + nbits = encode_spread_coherence_1sf( hQMetaData, idx_d, hMetaData +#ifdef HR_METADATA + , + is_hr +#endif + ); return nbits; } @@ -4632,13 +5981,31 @@ static int16_t ivas_qmetadata_quantize_coherence( { /* DCT transform */ dct4_transform( hQMetaData->q_direction[idx_d].coherence_band_data[j].spread_coherence, dct_coh[j] ); - no_cb_vec[j] = len_cb_dct0_masa[q_direction->band_data[j].energy_ratio_index[0]]; +#ifdef HR_METADATA + if ( is_hr ) + { + minimum_s( (int16_t *) ( q_direction->band_data[j].energy_ratio_index ), q_direction->cfg.nblocks, &min_index ); + no_cb_vec[j] = len_cb_dct0_masa[min_index >> 1]; + } + else + { +#endif + no_cb_vec[j] = len_cb_dct0_masa[q_direction->band_data[j].energy_ratio_index[0]]; +#ifdef HR_METADATA + } +#endif if ( write_flag ) { /* quantize first DCT parameter */ - dct_coh[j][0] = quantize_DCT_0_coh( dct_coh[j][0], j, coherence_cb0_masa, MASA_DELTA_AZI_DCT0, MASA_NO_CV_COH, q_direction, &idx_dct[k], &no_cb_vec[j] ); + dct_coh[j][0] = quantize_DCT_0_coh( dct_coh[j][0], j, coherence_cb0_masa, MASA_DELTA_AZI_DCT0, MASA_NO_CV_COH, q_direction, &idx_dct[k], &no_cb_vec[j] +#ifdef HR_METADATA + , + is_hr +#endif + ); } + if ( coding_subbands < coding_subbands_0 ) { idx_dct[k + coding_subbands] = squant( dct_coh[j][1], &dct_coh[j][1], &coherence_cb1_masa[MASA_grouping[two_dir_band[j]] * MASA_NO_CV_COH1], MASA_NO_CV_COH1 ); @@ -4790,6 +6157,61 @@ static void ivas_qmetadata_reorder_2dir_bands( return; } +#ifdef HR_METADATA +static void ivas_qmetadata_reorder_2dir_bands_hr( + IVAS_QMETADATA_HANDLE hQMetaData ) +{ + int16_t nbands; + int16_t nsubframes; + int16_t band, sf; + + nbands = hQMetaData->q_direction[0].cfg.nbands; + nsubframes = hQMetaData->q_direction[0].cfg.nblocks; + + for ( band = 0; band < nbands; band++ ) + { + if ( hQMetaData->twoDirBands[band] == 1 ) + { + + for ( sf = 0; sf < nsubframes; sf++ ) + { + if ( hQMetaData->q_direction[0].band_data[band].energy_ratio[sf] < hQMetaData->q_direction[1].band_data[band].energy_ratio[sf] ) + { + uint16_t uint16_tmp = 0; + float flt_tmp = 0; + uint8_t uint8_tmp = 0; + uint16_tmp = hQMetaData->q_direction[0].band_data[band].spherical_index[sf]; + hQMetaData->q_direction[0].band_data[band].spherical_index[sf] = hQMetaData->q_direction[1].band_data[band].spherical_index[sf]; + hQMetaData->q_direction[1].band_data[band].spherical_index[sf] = uint16_tmp; + + flt_tmp = hQMetaData->q_direction[0].band_data[band].azimuth[sf]; + hQMetaData->q_direction[0].band_data[band].azimuth[sf] = hQMetaData->q_direction[1].band_data[band].azimuth[sf]; + hQMetaData->q_direction[1].band_data[band].azimuth[sf] = flt_tmp; + + flt_tmp = hQMetaData->q_direction[0].band_data[band].elevation[sf]; + hQMetaData->q_direction[0].band_data[band].elevation[sf] = hQMetaData->q_direction[1].band_data[band].elevation[sf]; + hQMetaData->q_direction[1].band_data[band].elevation[sf] = flt_tmp; + + uint8_tmp = hQMetaData->q_direction[0].band_data[band].distance[sf]; + hQMetaData->q_direction[0].band_data[band].distance[sf] = hQMetaData->q_direction[1].band_data[band].distance[sf]; + hQMetaData->q_direction[1].band_data[band].distance[sf] = uint8_tmp; + + uint8_tmp = hQMetaData->q_direction[0].coherence_band_data[band].spread_coherence[sf]; + hQMetaData->q_direction[0].coherence_band_data[band].spread_coherence[sf] = hQMetaData->q_direction[1].coherence_band_data[band].spread_coherence[sf]; + hQMetaData->q_direction[1].coherence_band_data[band].spread_coherence[sf] = uint8_tmp; + + + flt_tmp = hQMetaData->q_direction[0].band_data[band].energy_ratio[sf]; + hQMetaData->q_direction[0].band_data[band].energy_ratio[sf] = hQMetaData->q_direction[1].band_data[band].energy_ratio[sf]; + hQMetaData->q_direction[1].band_data[band].energy_ratio[sf] = flt_tmp; + } + } + } + } + + return; +} +#endif /*-------------------------------------------------------------------* * write_2dir_info() @@ -4808,6 +6230,7 @@ static int16_t write_2dir_info( uint16_t dif_p[MASA_MAXIMUM_CODING_SUBBANDS]; int16_t i, j; j = 0; + p[0] = 0; for ( i = 0; i < n; i++ ) { if ( twoDirBands[i] == 1 ) diff --git a/lib_enc/ivas_qspherical_enc.c b/lib_enc/ivas_qspherical_enc.c index 80a9d0064f..3d2df98217 100644 --- a/lib_enc/ivas_qspherical_enc.c +++ b/lib_enc/ivas_qspherical_enc.c @@ -59,7 +59,12 @@ static float direction_distance_cp( float theta, float theta_hat, float theta_ha void quantize_direction_frame( IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */ float azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], - float elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES] ) + float elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES] +#ifdef HR_METADATA + , + int16_t is_hr +#endif +) { int16_t i, j; int16_t idx; @@ -92,17 +97,36 @@ void quantize_direction_frame( q_direction->not_in_2D += q_direction->band_data[i].elevation_index[j]; - if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) +#ifdef HR_METADATA + if ( is_hr ) { - q_direction->band_data[i].elevation_m_alphabet[j] = no_theta_masa[bits_direction_masa[idx] - 3]; - q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[idx] - 1][q_direction->band_data[i].elevation_index[j]]; + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + q_direction->band_data[i].elevation_m_alphabet[j] = no_theta_masa[bits_direction_masa[0] - 3]; + q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[0] - 1][q_direction->band_data[i].elevation_index[j]]; + } + else + { + q_direction->band_data[i].elevation_m_alphabet[j] = no_theta_masa[bits_direction_masa[0] - 3] * 2 - 1; + q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[0] - 1][( q_direction->band_data[i].elevation_index[j] + 1 ) >> 1]; + } } else { - q_direction->band_data[i].elevation_m_alphabet[j] = no_theta_masa[bits_direction_masa[idx] - 3] * 2 - 1; - q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[idx] - 1][( q_direction->band_data[i].elevation_index[j] + 1 ) >> 1]; +#endif + if ( q_direction->cfg.mc_ls_setup != MC_LS_SETUP_INVALID ) + { + q_direction->band_data[i].elevation_m_alphabet[j] = no_theta_masa[bits_direction_masa[idx] - 3]; + q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[idx] - 1][q_direction->band_data[i].elevation_index[j]]; + } + else + { + q_direction->band_data[i].elevation_m_alphabet[j] = no_theta_masa[bits_direction_masa[idx] - 3] * 2 - 1; + q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[idx] - 1][( q_direction->band_data[i].elevation_index[j] + 1 ) >> 1]; + } +#ifdef HR_METADATA } - +#endif if ( q_direction->band_data[i].azimuth_index[j] == MASA_NO_INDEX ) { q_direction->band_data[i].azimuth_index[j] = 0; diff --git a/lib_util/masa_file_reader.c b/lib_util/masa_file_reader.c index 19f12182f3..95da7818e7 100644 --- a/lib_util/masa_file_reader.c +++ b/lib_util/masa_file_reader.c @@ -100,13 +100,16 @@ IVAS_MASA_METADATA_HANDLE MasaFileReader_getMetadataHandle( * * deindex the MASA metadata from the input metadata file *------------------------------------------------------------------------*/ - -static void deindex_sph_idx( - const uint16_t sphIndex, /* i : Spherical index */ - const SPHERICAL_GRID_DATA *gridData, /* i : Prepared spherical grid */ - float *theta, /* o : Elevation */ - float *phi /* o : Azimuth */ -) +#ifndef HR_METADATA +static +#endif + void + deindex_sph_idx( + const uint16_t sphIndex, /* i : Spherical index */ + const SPHERICAL_GRID_DATA *gridData, /* i : Prepared spherical grid */ + float *theta, /* o : Elevation */ + float *phi /* o : Azimuth */ + ) { float ba_crt, del_crt, div_crt, a4_crt; float estim; @@ -342,6 +345,9 @@ ivas_error MasaFileReader_readNextFrame( for ( b = 0; b < MASA_FREQUENCY_BANDS; b++ ) { deindex_sph_idx( readIndex[b], &self->sph_grid16, &( hMeta->directional_meta[i].elevation[j][b] ), &( hMeta->directional_meta[i].azimuth[j][b] ) ); +#ifdef HR_METADATA + hMeta->directional_meta[i].spherical_index[j][b] = readIndex[b]; +#endif } /* Direct-to-total ratio */ -- GitLab From 7facab4538a171d66ee3a42d68243baa01f1f82a Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 27 Apr 2023 09:37:55 +0300 Subject: [PATCH 2/7] Resolution tuning for 384k and cleaning --- lib_com/ivas_cnst.h | 2 - lib_com/ivas_prot.h | 30 +- lib_com/options.h | 6 +- lib_dec/ivas_masa_dec.c | 6 +- lib_dec/ivas_qmetadata_dec.c | 823 ++++++++++------------------------- lib_enc/ivas_masa_enc.c | 6 +- lib_enc/ivas_qmetadata_enc.c | 555 ++++------------------- 7 files changed, 347 insertions(+), 1081 deletions(-) diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index 8128224bbe..13ff5d7729 100644 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -1214,9 +1214,7 @@ enum #define MASA_BIT_REDUCT_PARAM 10 #ifdef HR_METADATA #define MASA_MAXIMUM_TWO_DIR_BANDS 24 -#ifdef HR_METADATA_HR_COH #define NBITS_HR_COH 4 -#endif #else #define MASA_MAXIMUM_TWO_DIR_BANDS 18 #endif diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index acf3a032b6..844dd18129 100755 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -2987,14 +2987,20 @@ ivas_error ivas_qmetadata_enc_encode( ); #ifdef HR_METADATA -ivas_error ivas_qmetadata_enc_encode_hr( - BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ - IVAS_QMETADATA *hQMetaData /* i/o: q_metadata handle */ -); -ivas_error ivas_qmetadata_enc_encode_hr_512( +ivas_error ivas_qmetadata_enc_encode_hr_384_512( BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ - IVAS_QMETADATA *hQMetaData /* i/o: metadata handle */ + IVAS_QMETADATA *hQMetaData, /* i/o: metadata handle */ + int16_t bits_sph_idx, + int16_t bits_sp_coh +); +int16_t ivas_qmetadata_dec_decode_hr_384_512( + IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ + uint16_t *bitstream, /* i : bitstream */ + int16_t *index, /* i/o: bitstream position */ + SPHERICAL_GRID_DATA *sph_grid16, /* i: spherical grid for deindexing */ + int16_t bits_sph_idx, + int16_t bits_sp_coh ); void deindex_sph_idx( @@ -3004,18 +3010,6 @@ void deindex_sph_idx( float *phi /* o : Azimuth */ ); -int16_t ivas_qmetadata_dec_decode_hr_512( - IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ - uint16_t *bitstream, /* i : bitstream */ - int16_t *index, /* i/o: bitstream position */ - SPHERICAL_GRID_DATA *sph_grid16 /* i: spherical grid for deindexing */ -); - -int16_t ivas_qmetadata_dec_decode_hr( - IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ - uint16_t *bitstream, /* i : bitstream */ - int16_t *index /* i/o: bitstream position */ -); uint16_t index_theta_phi_16( float * p_theta, /* i/o : input elevation to be indexed */ diff --git a/lib_com/options.h b/lib_com/options.h index 44cf4a5cb1..37a2d2abac 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -94,7 +94,7 @@ /*#define DEBUG_DISABLE_DIRAC_DELAY_COMP */ /* temporarily disable delay compensation on DirAC encoder */ /*#define DEBUG_BS_READ_WRITE*/ /*#define DEBUG_MODE_DIRAC_NOCORE*/ -/*#define DEBUG_MODE_QMETADATA*/ /* output q_metadata parameters */ +#define DEBUG_MODE_QMETADATA /* output q_metadata parameters */ /*MCT Debug switches*/ /*#define DEBUG_FORCE_MCT_CP*/ /* force MCT Stereo pairs for verification with SPAR */ @@ -171,9 +171,7 @@ #define HR_METADATA /* Nok: encode directional MASA metadata with more bits at 384k and 512k */ -#ifdef HR_METADATA -#define HR_METADATA_HR_COH -#endif + /* ################## End DEVELOPMENT switches ######################### */ /* clang-format on */ #endif diff --git a/lib_dec/ivas_masa_dec.c b/lib_dec/ivas_masa_dec.c index 346adc3b2c..f7523ddb2d 100644 --- a/lib_dec/ivas_masa_dec.c +++ b/lib_dec/ivas_masa_dec.c @@ -199,13 +199,13 @@ ivas_error ivas_masa_decode( #ifdef HR_METADATA if ( ivas_total_brate >= IVAS_384k ) { - if ( ivas_total_brate == IVAS_512k ) + if ( ivas_total_brate >= IVAS_512k ) { - *nb_bits_read += ivas_qmetadata_dec_decode_hr_512( hQMetaData, st->bit_stream, &st->next_bit_pos, hMasa->data.sph_grid16 ); + *nb_bits_read += ivas_qmetadata_dec_decode_hr_384_512( hQMetaData, st->bit_stream, &st->next_bit_pos, hMasa->data.sph_grid16, 16, 4 ); } else { - *nb_bits_read += ivas_qmetadata_dec_decode_hr( hQMetaData, st->bit_stream, &st->next_bit_pos ); + *nb_bits_read += ivas_qmetadata_dec_decode_hr_384_512( hQMetaData, st->bit_stream, &st->next_bit_pos, hMasa->data.sph_grid16, 11, 3 ); } } else diff --git a/lib_dec/ivas_qmetadata_dec.c b/lib_dec/ivas_qmetadata_dec.c index c4940a65d9..47eb7917c0 100644 --- a/lib_dec/ivas_qmetadata_dec.c +++ b/lib_dec/ivas_qmetadata_dec.c @@ -138,15 +138,15 @@ static int16_t read_surround_coherence_hr( int16_t *p_bit_pos, /* i : position in the bitstream */ IVAS_QMETADATA *hQMetaData /* i/o: quantized metadata structure */ ); -#ifdef HR_METADATA_HR_COH + /* !r: number of bits read */ static int16_t read_coherence_data_hr_512( uint16_t *bitstream, /* i : bitstream */ int16_t *p_bit_pos, /* i : position in the bitstream */ IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata structure */ - const int16_t idx_dir /* i : direction index */ -); -#endif + const int16_t idx_dir, /* i : direction index */ + int16_t nbits_coh ); + #endif /*-----------------------------------------------------------------------* @@ -538,541 +538,96 @@ int16_t ivas_qmetadata_dec_decode( #ifdef HR_METADATA , 0 -#endif - ); - } - else - { - diff_bits += q_direction->band_data[b].bits_sph_idx[0] * q_direction->cfg.nblocks; - } - } - diff_bits += bits_dir; - - /* Small requantization?*/ - if ( q_direction->not_in_2D > 0 ) - { - /* This is not an ideal solution but mirrors better encoder */ - int16_t i, j; - uint16_t bits_temp[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; - - for ( i = q_direction->cfg.start_band; i < q_direction->cfg.nbands; i++ ) - { - for ( j = 0; j < q_direction->cfg.nblocks; j++ ) - { - bits_temp[i][j] = q_direction->band_data[i].bits_sph_idx[j]; - } - } - - small_reduction_direction( q_direction, bits_temp, raw_flag, &diff_bits ); - - for ( i = q_direction->cfg.start_band; i < q_direction->cfg.nbands; i++ ) - { - for ( j = 0; j < q_direction->cfg.nblocks; j++ ) - { - q_direction->band_data[i].bits_sph_idx[j] = bits_temp[i][j]; - } - } - } - -#ifdef DEBUGGING - assert( ( diff_bits <= 0 ) || ( q_direction->not_in_2D == 0 ) ); -#endif - - /* Read raw-coded bits*/ - for ( b = start_band; b < nbands; b++ ) - { - if ( raw_flag[b] ) - { - bits_dir += ivas_qmetadata_raw_decode_dir( q_direction, bitstream, index, b + 1, b -#ifdef HR_METADATA - , - 0 -#endif - ); - } - } - } - /* Decode requantized directions */ - else /* EC3 */ - { - int16_t dummy; - ec_flag = 2; - - if ( hQMetaData->is_masa_ivas_format == 0 ) - { - reduce_bits = bits_dir_raw - ( total_bits_1dir - bits_diff - bits_coherence - signal_bits ); - ind_order[0] = -1; - } - else - { - ind_order[0] = 0; - reduce_bits = min( nbands * nblocks + MASA_BIT_REDUCT_PARAM, bits_dir_raw - ( total_bits_1dir - bits_diff - bits_coherence - signal_bits ) ); - if ( reduce_bits > bits_dir_raw - nbands * nblocks ) - { - reduce_bits = bits_dir_raw - nbands * nblocks; - } - } - only_reduce_bits_direction( &dummy, q_direction, reduce_bits, nbands, nblocks, ind_order ); - - /* Read directions */ - bits_dir = read_directions( q_direction, (uint8_t) nbands, (uint8_t) nblocks, bitstream, index, ind_order ); - } - - if ( bits_coherence > 0 ) - { - if ( nblocks > 1 ) - { - decode_spread_coherence( hQMetaData, d, nblocks -#ifdef HR_METADATA - , - 0 -#endif - ); - } - } - else - { - for ( b = start_band; b < nbands; b++ ) - { - if ( q_direction->coherence_band_data != NULL ) - { - set_c( (int8_t *) q_direction->coherence_band_data[b].spread_coherence, 0, nblocks ); - } - } - } - if ( d == 0 ) - { - total_bits_1dir = hQMetaData->metadata_max_bits - ( start_index_0 - *index ); - } - - bits_dir_target += bits_dir_raw; - bits_dir_used += bits_dir; -#ifdef DEBUG_MODE_QMETADATA - fprintf( pF, "frame %d: diff %d coh %d surcoh %d ", frame, bits_diff, bits_coherence, bits_sur_coherence ); - fprintf( pF, "dir %d %d,%d,%d\n", ec_flag, start_index_0 - *index, total_bits_1dir, bits_dir_raw ); - - fprintf( pF_azi, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); - fprintf( pF_ele, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); - fprintf( pF_ratio, "frame %d/dir %d: ", frame, d ); - fprintf( pF_spcoh, "frame %d/dir %d: ", frame, d ); - if ( d == 0 ) - { - fprintf( pF_surcoh, "frame %d/dir %d: ", frame, d ); - } - for ( b = start_band; b < nbands; b++ ) - { - for ( m = 0; m < q_direction->cfg.nblocks; m++ ) - { - fprintf( pF_azi, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].azimuth[m] ) / 100.f ); - fprintf( pF_ele, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].elevation[m] ) / 100.f ); - fprintf( pF_ratio, " %1.3f ", q_direction->band_data[b].energy_ratio[m] ); - if ( q_direction->coherence_band_data != NULL ) - { - fprintf( pF_spcoh, " %d ", q_direction->coherence_band_data[b].spread_coherence[m] ); - } - if ( d == 0 && hQMetaData->surcoh_band_data != NULL ) - { - fprintf( pF_surcoh, " %d ", hQMetaData->surcoh_band_data[b].surround_coherence[m] ); - } - } - } - fprintf( pF_azi, "\n" ); - fprintf( pF_ele, "\n" ); - fprintf( pF_ratio, "\n" ); - fprintf( pF_spcoh, "\n" ); - if ( d == 0 ) - { - fprintf( pF_surcoh, "\n" ); - } -#endif - } - /* move 2 dir data to its correct subband */ - if ( hQMetaData->no_directions == 2 ) - { - d = hQMetaData->q_direction[1].cfg.nbands - 1; - nblocks = hQMetaData->q_direction[0].cfg.nblocks; - - for ( b = hQMetaData->q_direction[0].cfg.nbands - 1; b >= 0; b-- ) - { - if ( hQMetaData->twoDirBands[b] == 1 ) - { - mvr2r( hQMetaData->q_direction[1].band_data[d].azimuth, hQMetaData->q_direction[1].band_data[b].azimuth, nblocks ); - mvr2r( hQMetaData->q_direction[1].band_data[d].elevation, hQMetaData->q_direction[1].band_data[b].elevation, nblocks ); - mvr2r( hQMetaData->q_direction[1].band_data[d].energy_ratio, hQMetaData->q_direction[1].band_data[b].energy_ratio, nblocks ); - - if ( hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0] < 7 ) - { - for ( m = 0; m < nblocks; m++ ) - { - hQMetaData->q_direction[1].band_data[b].azimuth[m] += hQMetaData->q_direction[0].band_data[b].azimuth[m] - 180; - if ( hQMetaData->q_direction[1].band_data[b].azimuth[m] >= 180 ) - { - hQMetaData->q_direction[1].band_data[b].azimuth[m] -= 360; - } - if ( hQMetaData->q_direction[1].band_data[b].azimuth[m] < -180 ) - { - hQMetaData->q_direction[1].band_data[b].azimuth[m] += 360; - } - } - } - - if ( hQMetaData->q_direction[1].coherence_band_data != NULL ) - { - mvc2c( hQMetaData->q_direction[1].coherence_band_data[d].spread_coherence, hQMetaData->q_direction[1].coherence_band_data[b].spread_coherence, nblocks ); - } - d--; - } - else - { - set_f( hQMetaData->q_direction[1].band_data[b].azimuth, 0.0f, nblocks ); - set_f( hQMetaData->q_direction[1].band_data[b].elevation, 0.0f, nblocks ); - set_f( hQMetaData->q_direction[1].band_data[b].energy_ratio, 0.0f, nblocks ); - - if ( hQMetaData->q_direction[1].coherence_band_data != NULL ) - { - set_c( (int8_t *) hQMetaData->q_direction[1].coherence_band_data[b].spread_coherence, 0, nblocks ); - } - } - } - - /* Scale energy ratios that sum to over one */ - for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) - { - float ratioSum; - - ratioSum = hQMetaData->q_direction[0].band_data[b].energy_ratio[0] + hQMetaData->q_direction[1].band_data[b].energy_ratio[0]; - - if ( ratioSum > 1.0f ) - { - set_f( hQMetaData->q_direction[0].band_data[b].energy_ratio, hQMetaData->q_direction[0].band_data[b].energy_ratio[0] / ratioSum, nblocks ); - set_f( hQMetaData->q_direction[1].band_data[b].energy_ratio, hQMetaData->q_direction[1].band_data[b].energy_ratio[0] / ratioSum, nblocks ); - } - } - } - - /* Store status information for renderer use */ - hQMetaData->ec_flag = ec_flag; - - hQMetaData->dir_comp_ratio = (float) bits_dir_used / (float) bits_dir_target; - - if ( hQMetaData->dir_comp_ratio > 1.0f ) - { - hQMetaData->dir_comp_ratio = 1.0f; - } - - - return ( start_index_0 - *index ); -} - -#ifdef HR_METADATA -/*! r: number of bits read */ -int16_t ivas_qmetadata_dec_decode_hr( - IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ - uint16_t *bitstream, /* i : bitstream */ - int16_t *index /* i/o: bitstream position */ -) -{ - int16_t d, b, m; - uint16_t diffuseness_index_max_ec_frame; - uint16_t diffuseness_index_max_ec_frame_pre[QMETADATA_MAX_NO_DIRECTIONS]; - // int16_t bits_dir_raw_pre[QMETADATA_MAX_NO_DIRECTIONS]; - int16_t dir2band; - int16_t bits_diff_sum; - int16_t bits_coherence; - - int16_t nbands, nblocks, start_band; - IVAS_QDIRECTION *q_direction; - int16_t start_index_0; - - int16_t signal_bits; - int16_t bits_no_dirs_coh, bits_sur_coherence; - uint16_t all_coherence_zero; - int16_t ec_flag; - int16_t dfRatio_bits[MASA_MAXIMUM_CODING_SUBBANDS]; - int16_t no_TF; - int16_t p[MASA_MAXIMUM_CODING_SUBBANDS], dif_p[MASA_MAXIMUM_CODING_SUBBANDS]; - - -#ifdef DEBUG_MODE_QMETADATA - static FILE *pF = NULL; - static FILE *pF_azi = NULL; - static FILE *pF_ele = NULL; - static FILE *pF_ratio = NULL; - static FILE *pF_spcoh = NULL; - static FILE *pF_surcoh = NULL; - - if ( pF == NULL ) - pF = fopen( "./res/qmetadata_dec.txt", "w" ); - if ( pF_azi == NULL ) - pF_azi = fopen( "./res/qmetadata_azi_dec.txt", "w" ); - if ( pF_ele == NULL ) - pF_ele = fopen( "./res/qmetadata_ele_dec.txt", "w" ); - if ( pF_ratio == NULL ) - pF_ratio = fopen( "./res/qmetadata_ratio_dec.txt", "w" ); - if ( pF_spcoh == NULL ) - pF_spcoh = fopen( "./res/qmetadata_spcoh_dec.txt", "w" ); - if ( pF_surcoh == NULL ) - pF_surcoh = fopen( "./res/qmetadata_surcoh_dec.txt", "w" ); -#endif - - ec_flag = 0; - start_index_0 = *index; - - /*Coherence flag decoding*/ - bits_no_dirs_coh = 0; - all_coherence_zero = 1; - if ( hQMetaData->coherence_flag ) - { - /* read if coherence is zero */ - all_coherence_zero = bitstream[( *index )--]; - bits_no_dirs_coh += 1; - } - - hQMetaData->all_coherence_zero = (uint8_t) all_coherence_zero; - - if ( hQMetaData->no_directions == 2 ) - { - /* Read which bands have 2 directions */ - hQMetaData->q_direction[1].cfg.nbands = hQMetaData->numTwoDirBands; - set_c( (int8_t *) hQMetaData->twoDirBands, 0, hQMetaData->q_direction[0].cfg.nbands ); - d = *index; - dif_p[0] = ivas_qmetadata_DecodeExtendedGR( bitstream, index, MASA_MAXIMUM_CODING_SUBBANDS, 0 ); - p[0] = dif_p[0]; - hQMetaData->twoDirBands[p[0]] = 1; - for ( b = 1; b < hQMetaData->numTwoDirBands; b++ ) - { - dif_p[b] = ivas_qmetadata_DecodeExtendedGR( bitstream, index, MASA_MAXIMUM_CODING_SUBBANDS, 0 ); - p[b] = p[b - 1] + dif_p[b] + 1; - hQMetaData->twoDirBands[p[b]] = 1; - } - bits_no_dirs_coh += ( d - *index ); - } - - - bits_diff_sum = ivas_qmetadata_entropy_decode_diffuseness_hr( bitstream, index, &( hQMetaData->q_direction[0] ), &diffuseness_index_max_ec_frame_pre[0] ); - - if ( hQMetaData->no_directions == 2 ) - { - /* Calculate bits for dfRatio */ - dir2band = 0; - for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) - { - if ( hQMetaData->twoDirBands[b] == 1 ) - { - dfRatio_bits[dir2band] = ivas_get_df_ratio_bits( hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0] >> 1 ); - dir2band++; - } - } - - bits_diff_sum += ivas_qmetadata_entropy_decode_df_ratio( bitstream, index, &( hQMetaData->q_direction[1] ), dfRatio_bits ); - } - - /* Calculate direct-to-total energy ratios for both directions from diffuse-to-total ratio and distribution factor of direct-to-total ratios */ - if ( hQMetaData->no_directions == 2 ) - { - dir2band = 0; - for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) - { - if ( hQMetaData->twoDirBands[b] == 1 ) - { - float diffRatio, dfRatio, dir1ratio, dir2ratio; - int16_t dfRatio_qsteps; - - diffRatio = diffuseness_reconstructions_hr[hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]]; - dfRatio_qsteps = 1 << dfRatio_bits[dir2band]; - dfRatio = usdequant( hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[0], 0.5f, 0.5f / ( dfRatio_qsteps - 1 ) ); - - dir1ratio = dfRatio * ( 1.0f - diffRatio ); - dir2ratio = ( 1.0f - diffRatio ) - dir1ratio; - - /* Requantize the 1 - dirRatio separately for each direction to obtain inverted dirRatio index. These are used in further decoding. */ - hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0] = masa_sq( 1.0f - dir1ratio, diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[0] = masa_sq( 1.0f - dir2ratio, diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); - - for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) - { - hQMetaData->q_direction[0].band_data[b].energy_ratio[m] = dir1ratio; - hQMetaData->q_direction[0].band_data[b].energy_ratio_index[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; - } - - for ( m = 0; m < hQMetaData->q_direction[1].cfg.nblocks; m++ ) - { - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[m] = dir2ratio; - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[m] = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[0]; - } - - dir2band++; - } - else - { - /* 1dir band */ - hQMetaData->q_direction[0].band_data[b].energy_ratio[0] = 1.0f - diffuseness_reconstructions_hr[hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]]; - for ( m = 1; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) - { - hQMetaData->q_direction[0].band_data[b].energy_ratio[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio[0]; - hQMetaData->q_direction[0].band_data[b].energy_ratio_index[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; - } - } - } - } - else - { - /* With 1dir band, the decoded index is directly diffuseness and we can decode to direct-to-total ratio with 1 - diff. */ - for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) - { - hQMetaData->q_direction[0].band_data[b].energy_ratio[0] = 1.0f - diffuseness_reconstructions_hr[hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]]; - for ( m = 1; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) - { - hQMetaData->q_direction[0].band_data[b].energy_ratio[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio[0]; - hQMetaData->q_direction[0].band_data[b].energy_ratio_index[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; - } - } - } - - /* To decode directions correctly for 2dir bands, we need to obtain the compensated direct-to-total ratios and their - * corresponding inverted indices. */ - - dir2band = 0; - for ( b = hQMetaData->q_direction[0].cfg.start_band; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) - { - if ( hQMetaData->no_directions == 2 && hQMetaData->twoDirBands[b] == 1 ) - { - int16_t index_dirRatio1Inv, index_dirRatio2Inv, index_dirRatio1Inv_mod, index_dirRatio2Inv_mod; - - index_dirRatio1Inv = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; - index_dirRatio2Inv = hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[0]; - - masa_compensate_two_dir_energy_ratio_index( index_dirRatio1Inv, index_dirRatio2Inv, &index_dirRatio1Inv_mod, &index_dirRatio2Inv_mod ); - - for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) - { - hQMetaData->q_direction[0].band_data[b].energy_ratio_index_mod[m] = index_dirRatio1Inv_mod; - hQMetaData->q_direction[0].band_data[b].bits_sph_idx[m] = bits_direction_masa[0]; - } - - for ( m = 0; m < hQMetaData->q_direction[1].cfg.nblocks; m++ ) - { - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index_mod[m] = index_dirRatio2Inv_mod; - hQMetaData->q_direction[1].band_data[dir2band].bits_sph_idx[m] = bits_direction_masa[0]; - } - - dir2band++; - } - else - { - for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) - { - hQMetaData->q_direction[0].band_data[b].energy_ratio_index_mod[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; - hQMetaData->q_direction[0].band_data[b].bits_sph_idx[m] = bits_direction_masa[0]; - } - } - } - - if ( hQMetaData->no_directions == 2 ) - { - no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks + hQMetaData->q_direction[1].cfg.nbands * hQMetaData->q_direction[1].cfg.nblocks; - if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - bits_diff_sum >= MASA_MIN_BITS_SURR_COH ) ) - { - bits_sur_coherence = read_surround_coherence( bitstream, index, hQMetaData ); - } - else - { - bits_sur_coherence = 0; - /*Surround coherence*/ - for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) - { - if ( hQMetaData->surcoh_band_data != NULL ) - { - set_c( (int8_t *) hQMetaData->surcoh_band_data[b].surround_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); - } - } - } - bits_no_dirs_coh += bits_sur_coherence; - } - else - { - no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks; - if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - bits_diff_sum >= MASA_MIN_BITS_SURR_COH ) ) - { - bits_sur_coherence = read_surround_coherence( bitstream, index, hQMetaData ); - } - else - { - bits_sur_coherence = 0; - /*Surround coherence*/ - for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) - { - if ( hQMetaData->surcoh_band_data != NULL ) +#endif + ); + } + else { - set_c( (int8_t *) hQMetaData->surcoh_band_data[b].surround_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + diff_bits += q_direction->band_data[b].bits_sph_idx[0] * q_direction->cfg.nblocks; } } - } - bits_no_dirs_coh += bits_sur_coherence; - } - + diff_bits += bits_dir; - for ( d = 0; d < hQMetaData->no_directions; d++ ) - { - q_direction = &hQMetaData->q_direction[d]; - nbands = q_direction->cfg.nbands; - nblocks = q_direction->cfg.nblocks; - start_band = q_direction->cfg.start_band; + /* Small requantization?*/ + if ( q_direction->not_in_2D > 0 ) + { + /* This is not an ideal solution but mirrors better encoder */ + int16_t i, j; + uint16_t bits_temp[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; - diffuseness_index_max_ec_frame = diffuseness_index_max_ec_frame_pre[0]; + for ( i = q_direction->cfg.start_band; i < q_direction->cfg.nbands; i++ ) + { + for ( j = 0; j < q_direction->cfg.nblocks; j++ ) + { + bits_temp[i][j] = q_direction->band_data[i].bits_sph_idx[j]; + } + } - /* Read coherence, if any */ - bits_coherence = 0; + small_reduction_direction( q_direction, bits_temp, raw_flag, &diff_bits ); - if ( all_coherence_zero == 0 ) - { - bits_coherence = read_coherence_data( bitstream, index, hQMetaData, d, 1 ); - } - else - { - /*Surround coherence*/ - for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) - { - if ( hQMetaData->surcoh_band_data != NULL ) + for ( i = q_direction->cfg.start_band; i < q_direction->cfg.nbands; i++ ) { - set_c( (int8_t *) hQMetaData->surcoh_band_data[b].surround_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + for ( j = 0; j < q_direction->cfg.nblocks; j++ ) + { + q_direction->band_data[i].bits_sph_idx[j] = bits_temp[i][j]; + } } + } - if ( hQMetaData->q_direction[d].coherence_band_data != NULL ) +#ifdef DEBUGGING + assert( ( diff_bits <= 0 ) || ( q_direction->not_in_2D == 0 ) ); +#endif + + /* Read raw-coded bits*/ + for ( b = start_band; b < nbands; b++ ) + { + if ( raw_flag[b] ) { - set_c( (int8_t *) hQMetaData->q_direction[d].coherence_band_data[b].spread_coherence, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + bits_dir += ivas_qmetadata_raw_decode_dir( q_direction, bitstream, index, b + 1, b +#ifdef HR_METADATA + , + 0 +#endif + ); } } } - - /* Read 2D signaling*/ - q_direction->not_in_2D = bitstream[( *index )--]; - signal_bits = 1; - - /* Read EC signaling */ - ec_flag = 0; - /* if ( total_bits_1dir + bits_sur_coherence <= hQMetaData->qmetadata_max_bit_req ) */ + /* Decode requantized directions */ + else /* EC3 */ { - ec_flag = bitstream[( *index )--]; - signal_bits++; - } + int16_t dummy; + ec_flag = 2; - /* Decode quantized directions frame-wise */ - if ( ec_flag == 0 ) /* EC 1*/ - { - ivas_qmetadata_entropy_decode_dir( q_direction, bitstream, index, diffuseness_index_max_ec_frame, nbands, start_band, 1 ); - } - else - { - ivas_qmetadata_raw_decode_dir( q_direction, bitstream, index, nbands, start_band, 1 ); - } + if ( hQMetaData->is_masa_ivas_format == 0 ) + { + reduce_bits = bits_dir_raw - ( total_bits_1dir - bits_diff - bits_coherence - signal_bits ); + ind_order[0] = -1; + } + else + { + ind_order[0] = 0; + reduce_bits = min( nbands * nblocks + MASA_BIT_REDUCT_PARAM, bits_dir_raw - ( total_bits_1dir - bits_diff - bits_coherence - signal_bits ) ); + if ( reduce_bits > bits_dir_raw - nbands * nblocks ) + { + reduce_bits = bits_dir_raw - nbands * nblocks; + } + } + only_reduce_bits_direction( &dummy, q_direction, reduce_bits, nbands, nblocks, ind_order ); + /* Read directions */ + bits_dir = read_directions( q_direction, (uint8_t) nbands, (uint8_t) nblocks, bitstream, index, ind_order ); + } if ( bits_coherence > 0 ) { if ( nblocks > 1 ) { - decode_spread_coherence( hQMetaData, d, nblocks, 0 ); + decode_spread_coherence( hQMetaData, d, nblocks +#ifdef HR_METADATA + , + 0 +#endif + ); } } else @@ -1085,11 +640,16 @@ int16_t ivas_qmetadata_dec_decode_hr( } } } + if ( d == 0 ) + { + total_bits_1dir = hQMetaData->metadata_max_bits - ( start_index_0 - *index ); + } - + bits_dir_target += bits_dir_raw; + bits_dir_used += bits_dir; #ifdef DEBUG_MODE_QMETADATA - fprintf( pF, "frame %d: coh %d surcoh %d ", frame, bits_coherence, bits_sur_coherence ); - fprintf( pF, "dir %d %d\n", ec_flag, start_index_0 - *index ); + fprintf( pF, "frame %d: diff %d coh %d surcoh %d ", frame, bits_diff, bits_coherence, bits_sur_coherence ); + fprintf( pF, "dir %d %d,%d,%d\n", ec_flag, start_index_0 - *index, total_bits_1dir, bits_dir_raw ); fprintf( pF_azi, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); fprintf( pF_ele, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); @@ -1193,7 +753,7 @@ int16_t ivas_qmetadata_dec_decode_hr( /* Store status information for renderer use */ hQMetaData->ec_flag = ec_flag; - hQMetaData->dir_comp_ratio = 1.0f; + hQMetaData->dir_comp_ratio = (float) bits_dir_used / (float) bits_dir_target; if ( hQMetaData->dir_comp_ratio > 1.0f ) { @@ -1204,27 +764,27 @@ int16_t ivas_qmetadata_dec_decode_hr( return ( start_index_0 - *index ); } + +#ifdef HR_METADATA + /*! r: number of bits read */ -int16_t ivas_qmetadata_dec_decode_hr_512( +int16_t ivas_qmetadata_dec_decode_hr_384_512( IVAS_QMETADATA_HANDLE hQMetaData, /* i/o: hQMetaData handle */ uint16_t *bitstream, /* i : bitstream */ int16_t *index, /* i/o: bitstream position */ - SPHERICAL_GRID_DATA *sph_grid16 /* i: sphericla grid for deindexing */ -) + SPHERICAL_GRID_DATA *sph_grid16, /* i: spherical grid for deindexing */ + int16_t bits_sph_idx, + int16_t bits_sp_coh ) { int16_t d, b, m; int16_t bits_diff_sum; -#ifndef HR_METADATA_HR_COH - int16_t bits_coherence; - int16_t nblocks; -#endif int16_t nbands, start_band; IVAS_QDIRECTION *q_direction; int16_t start_index_0; int16_t bits_no_dirs_coh, bits_sur_coherence; uint16_t all_coherence_zero; - + int16_t p[MASA_MAXIMUM_CODING_SUBBANDS], dif_p[MASA_MAXIMUM_CODING_SUBBANDS]; #ifdef DEBUG_MODE_QMETADATA static FILE *pF = NULL; @@ -1267,6 +827,23 @@ int16_t ivas_qmetadata_dec_decode_hr_512( set_c( (int8_t *) hQMetaData->twoDirBands, 1, hQMetaData->q_direction[0].cfg.nbands ); } + if ( bits_sph_idx == 11 && hQMetaData->no_directions == 2 ) + { + /* Read which bands have 2 directions */ + hQMetaData->q_direction[1].cfg.nbands = hQMetaData->numTwoDirBands; + set_c( (int8_t *) hQMetaData->twoDirBands, 0, hQMetaData->q_direction[0].cfg.nbands ); + d = *index; + dif_p[0] = ivas_qmetadata_DecodeExtendedGR( bitstream, index, MASA_MAXIMUM_CODING_SUBBANDS, 0 ); + p[0] = dif_p[0]; + hQMetaData->twoDirBands[p[0]] = 1; + for ( b = 1; b < hQMetaData->numTwoDirBands; b++ ) + { + dif_p[b] = ivas_qmetadata_DecodeExtendedGR( bitstream, index, MASA_MAXIMUM_CODING_SUBBANDS, 0 ); + p[b] = p[b - 1] + dif_p[b] + 1; + hQMetaData->twoDirBands[p[b]] = 1; + } + bits_no_dirs_coh += ( d - *index ); + } bits_diff_sum = ivas_qmetadata_entropy_decode_diffuseness_hr_512( bitstream, index, &( hQMetaData->q_direction[0] ) ); @@ -1305,7 +882,7 @@ int16_t ivas_qmetadata_dec_decode_hr_512( for ( m = 0; m < hQMetaData->q_direction[1].cfg.nblocks; m++ ) { hQMetaData->q_direction[1].band_data[b].energy_ratio_index_mod[m] = hQMetaData->q_direction[1].band_data[b].energy_ratio_index[m]; - hQMetaData->q_direction[1].band_data[b].bits_sph_idx[m] = 16; + hQMetaData->q_direction[1].band_data[b].bits_sph_idx[m] = bits_sph_idx; } } } @@ -1315,7 +892,7 @@ int16_t ivas_qmetadata_dec_decode_hr_512( for ( m = 0; m < hQMetaData->q_direction[0].cfg.nblocks; m++ ) { hQMetaData->q_direction[0].band_data[b].energy_ratio_index_mod[m] = hQMetaData->q_direction[0].band_data[b].energy_ratio_index[0]; - hQMetaData->q_direction[0].band_data[b].bits_sph_idx[m] = 16; + hQMetaData->q_direction[0].band_data[b].bits_sph_idx[m] = bits_sph_idx; } } @@ -1347,18 +924,9 @@ int16_t ivas_qmetadata_dec_decode_hr_512( /* Read coherence, if any */ -#ifndef HR_METADATA_HR_COH - nblocks = q_direction->cfg.nblocks; - bits_coherence = 0; -#endif if ( all_coherence_zero == 0 ) { -#ifdef HR_METADATA_HR_COH - read_coherence_data_hr_512( bitstream, index, hQMetaData, d ); - -#else - bits_coherence = read_coherence_data( bitstream, index, hQMetaData, d, 1 ); -#endif + read_coherence_data_hr_512( bitstream, index, hQMetaData, d, bits_sp_coh ); } else { @@ -1380,37 +948,77 @@ int16_t ivas_qmetadata_dec_decode_hr_512( /* Decode quantized directions frame-wise */ ivas_qmetadata_raw_decode_dir_512( q_direction, bitstream, index, nbands, start_band, sph_grid16 ); -#ifndef HR_METADATA_HR_COH - if ( bits_coherence > 0 ) - { - if ( nblocks > 1 ) - { - decode_spread_coherence( hQMetaData, d, nblocks, 1 ); - } - } - else + + +#ifdef DEBUG_MODE_QMETADATA + + fprintf( pF, "frame %d: diff %d surcoh %d ", frame, bits_diff_sum, bits_sur_coherence ); + fprintf( pF, "dir %d\n", start_index_0 - *index ); + fprintf( pF_azi, "frame %d/dir/ec %d: ", frame, d ); + fprintf( pF_ele, "frame %d/dir/ec %d: ", frame, d ); + fprintf( pF_spcoh, "frame %d/dir %d: ", frame, d ); + fprintf( pF_ratio, "frame %d/dir %d: ", frame, d ); + + + for ( b = start_band; b < nbands; b++ ) { - for ( b = start_band; b < nbands; b++ ) + for ( m = 0; m < q_direction->cfg.nblocks; m++ ) { + + fprintf( pF_ratio, " %1.3f ", q_direction->band_data[b].energy_ratio[m] ); + fprintf( pF_azi, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].azimuth[m] ) / 100.f ); + fprintf( pF_ele, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].elevation[m] ) / 100.f ); if ( q_direction->coherence_band_data != NULL ) { - set_c( (int8_t *) q_direction->coherence_band_data[b].spread_coherence, 0, nblocks ); + fprintf( pF_spcoh, " %d ", q_direction->coherence_band_data[b].spread_coherence[m] ); } } } -#endif - -#ifdef DEBUG_MODE_QMETADATA - - fprintf( pF, "frame %d: diff %d surcoh %d ", frame, bits_diff_sum, bits_sur_coherence ); - fprintf( pF, "dir %d\n", start_index_0 - *index ); + fprintf( pF_ratio, "\n" ); + fprintf( pF_azi, "\n" ); + fprintf( pF_ele, "\n" ); + fprintf( pF_spcoh, "\n" ); #endif } - /* move 2 dir data to its correct subband */ if ( hQMetaData->no_directions == 2 ) { + /* move 2 dir data to its correct subband */ + if ( bits_sph_idx == 11 ) + { + int16_t nblocks; + d = hQMetaData->q_direction[1].cfg.nbands - 1; + nblocks = hQMetaData->q_direction[0].cfg.nblocks; + + for ( b = hQMetaData->q_direction[0].cfg.nbands - 1; b >= 0; b-- ) + { + if ( hQMetaData->twoDirBands[b] == 1 ) + { + mvr2r( hQMetaData->q_direction[1].band_data[d].azimuth, hQMetaData->q_direction[1].band_data[b].azimuth, nblocks ); + mvr2r( hQMetaData->q_direction[1].band_data[d].elevation, hQMetaData->q_direction[1].band_data[b].elevation, nblocks ); + mvr2r( hQMetaData->q_direction[1].band_data[d].energy_ratio, hQMetaData->q_direction[1].band_data[b].energy_ratio, nblocks ); + + + if ( hQMetaData->q_direction[1].coherence_band_data != NULL ) + { + mvc2c( hQMetaData->q_direction[1].coherence_band_data[d].spread_coherence, hQMetaData->q_direction[1].coherence_band_data[b].spread_coherence, nblocks ); + } + d--; + } + else + { + set_f( hQMetaData->q_direction[1].band_data[b].azimuth, 0.0f, nblocks ); + set_f( hQMetaData->q_direction[1].band_data[b].elevation, 0.0f, nblocks ); + set_f( hQMetaData->q_direction[1].band_data[b].energy_ratio, 0.0f, nblocks ); + + if ( hQMetaData->q_direction[1].coherence_band_data != NULL ) + { + set_c( (int8_t *) hQMetaData->q_direction[1].coherence_band_data[b].spread_coherence, 0, nblocks ); + } + } + } + } /* Scale energy ratios that sum to over one */ for ( b = 0; b < hQMetaData->q_direction[0].cfg.nbands; b++ ) { @@ -1428,6 +1036,7 @@ int16_t ivas_qmetadata_dec_decode_hr_512( } } + #ifdef DEBUG_MODE_QMETADATA for ( d = 0; d < hQMetaData->no_directions; d++ ) { @@ -1436,10 +1045,6 @@ int16_t ivas_qmetadata_dec_decode_hr_512( start_band = q_direction->cfg.start_band; - fprintf( pF_azi, "frame %d/dir/ec %d: ", frame, d ); - fprintf( pF_ele, "frame %d/dir/ec %d: ", frame, d ); - fprintf( pF_ratio, "frame %d/dir %d: ", frame, d ); - fprintf( pF_spcoh, "frame %d/dir %d: ", frame, d ); if ( d == 0 ) { fprintf( pF_surcoh, "frame %d/dir %d: ", frame, d ); @@ -1448,23 +1053,16 @@ int16_t ivas_qmetadata_dec_decode_hr_512( { for ( m = 0; m < q_direction->cfg.nblocks; m++ ) { - fprintf( pF_azi, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].azimuth[m] ) / 100.f ); - fprintf( pF_ele, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[b].elevation[m] ) / 100.f ); - fprintf( pF_ratio, " %1.3f ", q_direction->band_data[b].energy_ratio[m] ); - if ( q_direction->coherence_band_data != NULL ) - { - fprintf( pF_spcoh, " %d ", q_direction->coherence_band_data[b].spread_coherence[m] ); - } + + if ( d == 0 && hQMetaData->surcoh_band_data != NULL ) { fprintf( pF_surcoh, " %d ", hQMetaData->surcoh_band_data[b].surround_coherence[m] ); } } } - fprintf( pF_azi, "\n" ); - fprintf( pF_ele, "\n" ); - fprintf( pF_ratio, "\n" ); - fprintf( pF_spcoh, "\n" ); + + if ( d == 0 ) { fprintf( pF_surcoh, "\n" ); @@ -1849,6 +1447,7 @@ static int16_t ivas_qmetadata_entropy_decode_diffuseness( return ( index_start - *index ); } + #ifdef HR_METADATA static int16_t ivas_qmetadata_entropy_decode_diffuseness_hr( uint16_t *bitstream, /* i : bitstream */ @@ -2495,7 +2094,16 @@ static int16_t ivas_qmetadata_raw_decode_dir_512( value = ( value << 1 ) + bitstream[( *index )--]; } q_direction->band_data[b].spherical_index[m] = value; - deindex_sph_idx( value, sph_grid16, &( q_direction->band_data[b].elevation[m] ), &( q_direction->band_data[b].azimuth[m] ) ); + if ( q_direction->band_data[b].bits_sph_idx[m] == 16 ) + { + deindex_sph_idx( value, sph_grid16, &( q_direction->band_data[b].elevation[m] ), &( q_direction->band_data[b].azimuth[m] ) ); + } + else + { + deindex_spherical_component( q_direction->band_data[b].spherical_index[m], &q_direction->band_data[b].azimuth[m], &q_direction->band_data[b].elevation[m], + &q_direction->band_data[b].azimuth_index[m], &q_direction->band_data[b].elevation_index[m], q_direction->band_data[b].bits_sph_idx[m], + q_direction->cfg.mc_ls_setup ); + } } } @@ -3946,14 +3554,14 @@ static int16_t decode_fixed_rate_composed_index_coherence( return nbits; } -#ifdef HR_METADATA_HR_COH +#ifdef HR_METADATA /* !r: number of bits read */ static int16_t read_coherence_data_hr_512( uint16_t *bitstream, /* i : bitstream */ int16_t *p_bit_pos, /* i : position in the bitstream */ IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata structure */ - const int16_t idx_dir /* i : direction index */ -) + const int16_t idx_dir, /* i : direction index */ + int16_t nbits_coh ) { int16_t j, k, i; int16_t nbands, nblocks; @@ -3966,23 +3574,53 @@ static int16_t read_coherence_data_hr_512( nblocks = hQMetaData->q_direction[idx_dir].cfg.nblocks; - cb_size = 1 << NBITS_HR_COH; + cb_size = 1 << nbits_coh; delta = 256.0f / cb_size; nbits = *p_bit_pos; for ( k = 0; k < nblocks; k++ ) { - /* read min_index */ - min_index = 0; - for ( i = 0; i < NBITS_HR_COH; i++ ) + /* read method */ + if ( bitstream[( *p_bit_pos )--] == 1 ) { - min_index = ( min_index << 1 ) + bitstream[( *p_bit_pos )--]; + /* average removed */ + /* read average index */ + min_index = 0; + for ( i = 0; i < nbits_coh; i++ ) + { + min_index = ( min_index << 1 ) + bitstream[( *p_bit_pos )--]; + } + /* read GR param */ + GR_param = bitstream[( *p_bit_pos )--]; + for ( j = 0; j < nbands; j++ ) + { + decoded_idx = ivas_qmetadata_DecodeExtendedGR( bitstream, p_bit_pos, 2 * cb_size, GR_param ); + if ( decoded_idx % 2 ) + { + decoded_idx = ( ( decoded_idx + 1 ) >> 1 ) + min_index; + } + else + { + decoded_idx = -( decoded_idx >> 1 ) + min_index; + } + hQMetaData->q_direction[idx_dir].coherence_band_data[j].spread_coherence[k] = (uint8_t) ( decoded_idx * delta + delta / 2.0f ); + } } - /* read GR param */ - GR_param = bitstream[( *p_bit_pos )--]; - for ( j = 0; j < nbands; j++ ) + else { - decoded_idx = ivas_qmetadata_DecodeExtendedGR( bitstream, p_bit_pos, cb_size - min_index - 1, GR_param ) + min_index; - hQMetaData->q_direction[idx_dir].coherence_band_data[j].spread_coherence[k] = (uint8_t) ( decoded_idx * delta + delta / 2.0f ); + + /* read min_index */ + min_index = 0; + for ( i = 0; i < nbits_coh; i++ ) + { + min_index = ( min_index << 1 ) + bitstream[( *p_bit_pos )--]; + } + /* read GR param */ + GR_param = bitstream[( *p_bit_pos )--]; + for ( j = 0; j < nbands; j++ ) + { + decoded_idx = ivas_qmetadata_DecodeExtendedGR( bitstream, p_bit_pos, cb_size - min_index, GR_param ) + min_index; + hQMetaData->q_direction[idx_dir].coherence_band_data[j].spread_coherence[k] = (uint8_t) ( decoded_idx * delta + delta / 2.0f ); + } } } nbits = nbits - *p_bit_pos; @@ -4423,26 +4061,31 @@ static int16_t read_surround_coherence_hr( uint16_t idx_sur_coh[MASA_MAXIMUM_CODING_SUBBANDS]; IVAS_QDIRECTION *q_direction; int16_t min_index; + int16_t d, idx; coding_subbands = hQMetaData->q_direction[0].cfg.nbands; q_direction = hQMetaData->q_direction; bits_sur_coherence = 0; bit_pos = *p_bit_pos; + for ( sf = 0; sf < hQMetaData->q_direction[0].cfg.nblocks; sf++ ) { + d = 0; for ( j = 0; j < coding_subbands; j++ ) { error_ratio_surr = 1.0f; - if ( hQMetaData->no_directions == 2 ) { - error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf] - q_direction[1].band_data[j].energy_ratio[sf] * hQMetaData->twoDirBands[j]; + d += hQMetaData->twoDirBands[j]; + idx = max( d - 1, 0 ); + error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf] - q_direction[1].band_data[idx].energy_ratio[sf] * hQMetaData->twoDirBands[j]; } else { error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf]; } + if ( error_ratio_surr <= 0 ) { error_ratio_surr = 0; diff --git a/lib_enc/ivas_masa_enc.c b/lib_enc/ivas_masa_enc.c index d262277d06..cb0d5a9a22 100644 --- a/lib_enc/ivas_masa_enc.c +++ b/lib_enc/ivas_masa_enc.c @@ -275,7 +275,7 @@ ivas_error ivas_masa_encode( } } #ifdef HR_METADATA - if ( ivas_format == MASA_FORMAT && ivas_total_brate == IVAS_512k ) + if ( ivas_format == MASA_FORMAT && ivas_total_brate >= IVAS_384k ) { hMasa->config.mergeRatiosOverSubframes = 0; } @@ -348,11 +348,11 @@ ivas_error ivas_masa_encode( { if ( ivas_total_brate >= IVAS_512k ) { - ivas_qmetadata_enc_encode_hr_512( hMetaData, hQMetaData ); + ivas_qmetadata_enc_encode_hr_384_512( hMetaData, hQMetaData, 16, 4 ); } else { - ivas_qmetadata_enc_encode_hr( hMetaData, hQMetaData ); + ivas_qmetadata_enc_encode_hr_384_512( hMetaData, hQMetaData, 11, 3 ); } } else diff --git a/lib_enc/ivas_qmetadata_enc.c b/lib_enc/ivas_qmetadata_enc.c index 00d53481a7..4fe2709528 100644 --- a/lib_enc/ivas_qmetadata_enc.c +++ b/lib_enc/ivas_qmetadata_enc.c @@ -158,14 +158,13 @@ static int16_t encode_surround_coherence_hr( static void ivas_qmetadata_reorder_2dir_bands_hr( IVAS_QMETADATA_HANDLE hQMetaData ); -#ifdef HR_METADATA_HR_COH static int16_t ivas_qmetadata_quantize_coherence_hr_512( IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata */ const int16_t idx_d, /* i : current direction index */ const int16_t all_coherence_zero, /* i : all coherence is zero - flag */ - BSTR_ENC_HANDLE hMetaData /* i : metadata handle */ -); -#endif + BSTR_ENC_HANDLE hMetaData, /* i : metadata handle */ + int16_t bits_coh ); + #endif /*-----------------------------------------------------------------------* @@ -731,40 +730,29 @@ ivas_error ivas_qmetadata_enc_encode( } #ifdef HR_METADATA -ivas_error ivas_qmetadata_enc_encode_hr( - BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ - IVAS_QMETADATA *hQMetaData /* i/o: metadata handle */ -) -{ - int16_t i, bit_pos_start, bit_pos_start_coh; - uint16_t diffuseness_index_max_ec_frame; - uint16_t diffuseness_index_max_ec_frame_pre[QMETADATA_MAX_NO_DIRECTIONS]; - int16_t bits_dir_raw_pre[QMETADATA_MAX_NO_DIRECTIONS]; - int16_t bits_diff_sum; - int16_t bits_diff[QMETADATA_MAX_NO_DIRECTIONS], bits_coherence[QMETADATA_MAX_NO_DIRECTIONS]; - int16_t bits_dir[QMETADATA_MAX_NO_DIRECTIONS]; +ivas_error ivas_qmetadata_enc_encode_hr_384_512( + BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ + IVAS_QMETADATA *hQMetaData, /* i/o: metadata handle */ + int16_t bits_sph_idx, + int16_t bits_sp_coh ) +{ + int16_t i, j; + int16_t bits_diff[QMETADATA_MAX_NO_DIRECTIONS]; IVAS_QDIRECTION *q_direction; int16_t nbands, nblocks, start_band; int16_t ndirections, d; - float azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; int16_t all_coherence_zero; - int16_t bit_pos_0, bits_no_dirs_coh; - int16_t bits_signaling[QMETADATA_MAX_NO_DIRECTIONS]; - int16_t indice_coherence; - int16_t bits_dir_bands[MASA_MAXIMUM_CODING_SUBBANDS]; - int16_t bits_ec, next_ind_raw_flag; - int16_t dfRatio_bits[MASA_MAXIMUM_CODING_SUBBANDS]; - int16_t bits_surround_coh, no_TF; - int16_t dir2_bands[MASA_MAXIMUM_TWO_DIR_BANDS]; - int16_t reduce_bits; + int16_t bits_no_dirs_coh; + int16_t bits_ec; + float azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; + ivas_error error; error = IVAS_ERR_OK; #ifdef DEBUG_MODE_QMETADATA - int16_t ec_flag = 0; static FILE *pF = NULL; static FILE *pF_azi = NULL; @@ -790,13 +778,9 @@ ivas_error ivas_qmetadata_enc_encode_hr( pF_surcoh = fopen( "./res/qmetadata_surcoh_enc.txt", "w" ); #endif - - /* Save initial position in bitstream */ - bit_pos_0 = hMetaData->nb_bits_tot; - bit_pos_start = bit_pos_0; - ndirections = hQMetaData->no_directions; + /* Check if coherence should be encoded */ all_coherence_zero = 1; bits_no_dirs_coh = 0; @@ -804,404 +788,24 @@ ivas_error ivas_qmetadata_enc_encode_hr( if ( hQMetaData->coherence_flag ) { all_coherence_zero = hQMetaData->all_coherence_zero; - push_next_indice( hMetaData, all_coherence_zero, 1 ); /* signal coherence */ bits_no_dirs_coh += 1; } - - if ( ndirections > 1 ) + /* encode 2 direction subbands position */ + if ( ndirections == 2 && bits_sph_idx == 11 ) { -#ifdef DEBUGGING - assert( ndirections == 2 ); -#endif - /* Reorder 2dir bands for more efficient encoding. */ - ivas_qmetadata_reorder_2dir_bands( hQMetaData ); - d = 0; - for ( i = hQMetaData->q_direction[1].cfg.start_band; i < hQMetaData->q_direction[1].cfg.nbands; i++ ) - { - if ( hQMetaData->twoDirBands[i] == 1 ) - { - mvr2r( hQMetaData->q_direction[1].band_data[i].azimuth, hQMetaData->q_direction[1].band_data[d].azimuth, hQMetaData->q_direction[1].cfg.nblocks ); - mvr2r( hQMetaData->q_direction[1].band_data[i].elevation, hQMetaData->q_direction[1].band_data[d].elevation, hQMetaData->q_direction[1].cfg.nblocks ); - mvr2r( hQMetaData->q_direction[1].band_data[i].energy_ratio, hQMetaData->q_direction[1].band_data[d].energy_ratio, hQMetaData->q_direction[1].cfg.nblocks ); - - dir2_bands[d] = i; - - if ( hQMetaData->coherence_flag ) - { - mvc2c( hQMetaData->q_direction[1].coherence_band_data[i].spread_coherence, hQMetaData->q_direction[1].coherence_band_data[d].spread_coherence, hQMetaData->q_direction[1].cfg.nblocks ); - } - d++; - } - } - bits_no_dirs_coh += write_2dir_info( hMetaData, hQMetaData->twoDirBands, hQMetaData->q_direction[0].cfg.nbands, hQMetaData->numTwoDirBands ); - for ( i = d; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) + for ( i = hQMetaData->numTwoDirBands; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) { set_f( hQMetaData->q_direction[1].band_data[i].energy_ratio, 0.0f, hQMetaData->q_direction[1].cfg.nblocks ); } -#ifdef DEBUGGING - assert( d == hQMetaData->numTwoDirBands ); -#endif hQMetaData->q_direction[1].cfg.nbands = hQMetaData->numTwoDirBands; } - - /*Quantization of the Diffuseness */ - ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr( hQMetaData, bits_dir_raw_pre, bits_diff, dfRatio_bits, 11 ); - - - bits_diff_sum = 0; - bits_diff[0] = ivas_qmetadata_entropy_encode_diffuseness_hr( hMetaData, &( hQMetaData->q_direction[0] ), &diffuseness_index_max_ec_frame_pre[0] ); - bits_diff_sum += bits_diff[0]; - - if ( ndirections == 2 ) - { - bits_diff[1] = ivas_qmetadata_entropy_encode_df_ratio( hMetaData, &( hQMetaData->q_direction[1] ), dfRatio_bits ); - bits_diff_sum += bits_diff[1]; - } - - /* 2dir energy ratio encoding reuses index memory. Now that diffRatio and dFRatio have been encoded, - * we retrieve index_dirRatio1Inv and index_dirRatio1Inv for further parameter encoding. This is - * necessary only for bands that have two concurrent directions. */ - if ( hQMetaData->no_directions == 2 ) - { - int16_t j, k, dir2band, index_dirRatio1Inv, index_dirRatio2Inv; - - dir2band = 0; - for ( j = hQMetaData->q_direction[0].cfg.start_band; j < hQMetaData->q_direction[0].cfg.nbands; ++j ) - { - if ( hQMetaData->twoDirBands[j] == 1 ) - { - index_dirRatio1Inv = masa_sq( 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[0], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); - index_dirRatio2Inv = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio[0], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); - - for ( k = 0; k < hQMetaData->q_direction[0].cfg.nblocks; k++ ) - { - hQMetaData->q_direction[0].band_data[j].energy_ratio_index[k] = index_dirRatio1Inv; - } - - for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) - { - hQMetaData->q_direction[1].band_data[dir2band].energy_ratio_index[k] = index_dirRatio2Inv; - } - - dir2band++; - } - } - } - - /* Encode surround coherence */ - if ( ndirections == 2 ) - { - no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks + hQMetaData->q_direction[1].cfg.nbands * hQMetaData->q_direction[1].cfg.nblocks; - if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - sum_s( bits_diff, ndirections ) >= MASA_MIN_BITS_SURR_COH ) ) - { - bits_surround_coh = encode_surround_coherence( hQMetaData, hMetaData ); - } - else - { - bits_surround_coh = 0; - for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) - { - if ( hQMetaData->surcoh_band_data != NULL ) - { - set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); - } - } - } - bits_no_dirs_coh += bits_surround_coh; - } - else - { - no_TF = hQMetaData->q_direction[0].cfg.nbands * hQMetaData->q_direction[0].cfg.nblocks; - if ( ( all_coherence_zero == 0 ) && ( hQMetaData->metadata_max_bits - bits_no_dirs_coh - 4.3f * no_TF - bits_diff[0] >= MASA_MIN_BITS_SURR_COH ) ) - { - bits_surround_coh = encode_surround_coherence( hQMetaData, hMetaData ); - } - else - { - bits_surround_coh = 0; - for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) - { - if ( hQMetaData->surcoh_band_data != NULL ) - { - set_c( (int8_t *) hQMetaData->surcoh_band_data[i].surround_coherence, 0, hQMetaData->q_direction[0].cfg.nblocks ); - } - } - } - } - - /* Loop over number of directions*/ - for ( d = 0; d < ndirections; d++ ) - { - q_direction = &( hQMetaData->q_direction[d] ); - - if ( d == 1 ) - { - transform_azimuth_dir2( hQMetaData, dir2_bands ); - } - - nbands = q_direction->cfg.nbands; - nblocks = q_direction->cfg.nblocks; - start_band = q_direction->cfg.start_band; - diffuseness_index_max_ec_frame = diffuseness_index_max_ec_frame_pre[0]; - - - /* This sets bit budget correctly for the second direction */ - if ( d == 0 ) - { - bits_diff[d] = bits_diff_sum; - } - else - { - bits_diff[d] = 0; - } - -#ifdef DEBUG_MODE_QMETADATA - { - int16_t j, k; - k = 0; - fprintf( pF_spcoh_orig, "%d %d ", frame, k ); - - for ( i = start_band; i < nbands; i++ ) - { - for ( j = 0; j < nblocks; j++ ) - { - if ( q_direction->coherence_band_data != NULL ) - { - fprintf( pF_spcoh_orig, " %d ", q_direction->coherence_band_data[i].spread_coherence[j] ); - } - } - } - fprintf( pF_spcoh_orig, "\n" ); - } -#endif - - bits_signaling[d] = 0; - - /*Coherence */ - bits_coherence[d] = 0; - bit_pos_start_coh = hMetaData->nb_bits_tot; - - if ( all_coherence_zero == 0 ) - { - bits_coherence[d] = ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 0, &indice_coherence, 1 ); - } - - if ( q_direction->cfg.mc_ls_setup == MC_LS_SETUP_5_1 || q_direction->cfg.mc_ls_setup == MC_LS_SETUP_7_1 ) - { - q_direction->not_in_2D = 0; - /* Quantize directions*/ - quantize_direction_frame2D( q_direction, azimuth_orig, elevation_orig ); - } - else - { - /* Quantize directions*/ - quantize_direction_frame( q_direction, azimuth_orig, elevation_orig, 1 ); - } - - /* Signalling 2D*/ - push_next_indice( hMetaData, ( q_direction->not_in_2D > 0 ), 1 ); /*2D flag*/ - bits_signaling[d] = 1; - - /* Save state of metadata bitstream buffer after writing energy ratios, number of dirs and save space for coherence*/ - bit_pos_start = hMetaData->nb_bits_tot; - - - next_ind_raw_flag = hMetaData->next_ind; - push_next_indice( hMetaData, 0, 1 ); /* Raw coding flag*/ - - bits_dir_bands[0] = ivas_qmetadata_raw_encode_dir( NULL, q_direction, q_direction->cfg.nbands, q_direction->cfg.start_band ); - - reduce_bits = MASA_MAX_BITS_HR; - bits_ec = ivas_qmetadata_entropy_encode_dir( hMetaData, q_direction, diffuseness_index_max_ec_frame, - q_direction->cfg.nbands, q_direction->cfg.start_band, bits_dir_bands[0], reduce_bits, 1 ); - - if ( bits_ec < 0 ) - { - // printf( "%ld Not EC1\n", frame ); - hMetaData->ind_list[next_ind_raw_flag].value = 1; /*rewrite flag*/ - bits_ec = ivas_qmetadata_raw_encode_dir( hMetaData, q_direction, q_direction->cfg.nbands, q_direction->cfg.start_band ); -#ifdef DEBUGGING - assert( bits_dir_bands[0] == bits_ec ); -#endif - } - bits_dir[d] = bits_ec + 1; - - -#ifdef DEBUGGING - assert( bit_pos_start + bits_signaling[d] - 1 + bits_dir[d] == hMetaData->nb_bits_tot ); -#endif -#ifdef DEBUG_MODE_QMETADATA - ec_flag = 0; -#endif - - - /* finalize writing coherence */ - if ( ( bits_coherence[d] > 0 ) && ( all_coherence_zero == 0 ) && ( nblocks > 1 ) ) - { - bit_pos_start = hMetaData->nb_bits_tot; - hMetaData->nb_bits_tot = bit_pos_start_coh; - ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 1, &indice_coherence, 1 ); - hMetaData->nb_bits_tot = bit_pos_start; - } - -#ifdef DEBUG_MODE_QMETADATA - { - int16_t j; - float tmp_f, mat_dist[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES]; - - fprintf( pF, "frame %d: diff %d coh %d surcoh %d ", frame, bits_diff[d], bits_coherence[d], bits_surround_coh ); - fprintf( pF, "dir %d, %d %5.3f\n", ec_flag, hMetaData->nb_bits_tot - bit_pos_0, direction_distance( elevation_orig, azimuth_orig, q_direction, nbands, nblocks, mat_dist ) ); - fprintf( pF_azi, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); - fprintf( pF_ele, "frame %d/dir/ec %d/%d: ", frame, d, ec_flag ); - fprintf( pF_ratio, "frame %d/dir %d: ", frame, d ); - /*fprintf( pF_spcoh, "frame %d/dir %d: ", frame, d ); */ - fprintf( pF_spcoh, " %d %d ", frame, d ); - if ( d == 0 ) - { - fprintf( pF_surcoh, "frame %d/dir %d: ", frame, d ); - } - - /* direction_distance( elevation_orig, azimuth_orig, q_direction, nbands, nblocks, mat_dist );*/ - for ( i = start_band; i < nbands; i++ ) - { - for ( j = 0; j < nblocks; j++ ) - { - fprintf( pF_azi, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[i].azimuth[j] ) / 100.f ); - fprintf( pF_ele, " %+5.2f ", (int16_t) ( 100.f * q_direction->band_data[i].elevation[j] ) / 100.f ); - fprintf( pF_ratio, " %1.3f ", q_direction->band_data[i].energy_ratio[j] ); - if ( q_direction->coherence_band_data != NULL ) - { - fprintf( pF_spcoh, " %d ", q_direction->coherence_band_data[i].spread_coherence[j] ); - } - if ( d == 0 && hQMetaData->surcoh_band_data != NULL ) - { - fprintf( pF_surcoh, " %d ", hQMetaData->surcoh_band_data[i].surround_coherence[0] ); - } - } - } - fprintf( pF_azi, "\n" ); - fprintf( pF_ele, "\n" ); - fprintf( pF_ratio, "\n" ); - fprintf( pF_spcoh, "\n" ); - if ( d == 0 ) - { - fprintf( pF_surcoh, "\n" ); - } - - for ( i = 0; i < nblocks; i++ ) - { - for ( j = 0; j < nbands; j++ ) - { - dbgwrite( &( q_direction->band_data[j].azimuth[i] ), sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_azi.bin" ); - dbgwrite( &( q_direction->band_data[j].elevation[i] ), sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_ele.bin" ); - dbgwrite( &( mat_dist[j][i] ), sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_dist.bin" ); - dbgwrite( &( q_direction->band_data[j].energy_ratio_index[i] ), sizeof( uint16_t ), 1, 1, "./res/IVAS_QMETADATA_diffuseness_index.bin" ); - tmp_f = 1.f - q_direction->band_data[j].energy_ratio[i]; - dbgwrite( &tmp_f, sizeof( float ), 1, 1, "./res/IVAS_QMETADATA_diffuseness.bin" ); - } - } - - j = (int16_t) ( hMetaData->nb_bits_tot ); - dbgwrite( &j, sizeof( int16_t ), 1, 1, "./res/IVAS_QMETADATA_bits.bin" ); - } -#endif - - /* Save quantized DOAs */ - for ( i = start_band; i < nbands; i++ ) - { - mvr2r( q_direction->band_data[i].azimuth, q_direction->band_data[i].q_azimuth, nblocks ); - mvr2r( q_direction->band_data[i].elevation, q_direction->band_data[i].q_elevation, nblocks ); - } - - /* Copy original DOAs back to q_direction*/ - for ( i = start_band; i < nbands; i++ ) - { - mvr2r( azimuth_orig[i], q_direction->band_data[i].azimuth, nblocks ); - mvr2r( elevation_orig[i], q_direction->band_data[i].elevation, nblocks ); - } - } - - return error; -} - - -ivas_error ivas_qmetadata_enc_encode_hr_512( - BSTR_ENC_HANDLE hMetaData, /* i/o: metadata bitstream handle */ - IVAS_QMETADATA *hQMetaData /* i/o: metadata handle */ -) -{ - int16_t i, j; -#ifndef HR_METADATA_HR_COH - int16_t bit_pos_start_coh, bit_pos_start, bits_surround_coh, bits_coherence[QMETADATA_MAX_NO_DIRECTIONS], bit_pos_0; - int16_t indice_coherence; -#endif - int16_t bits_diff[QMETADATA_MAX_NO_DIRECTIONS]; - IVAS_QDIRECTION *q_direction; - int16_t nbands, nblocks, start_band; - int16_t ndirections, d; - int16_t all_coherence_zero; - int16_t bits_no_dirs_coh; - int16_t bits_ec; - - - ivas_error error; - - error = IVAS_ERR_OK; - -#ifdef DEBUG_MODE_QMETADATA - - static FILE *pF = NULL; - static FILE *pF_azi = NULL; - static FILE *pF_ele = NULL; - static FILE *pF_ratio = NULL; - static FILE *pF_spcoh = NULL; - static FILE *pF_spcoh_orig = NULL; - static FILE *pF_surcoh = NULL; - - if ( pF == NULL ) - pF = fopen( "./res/qmetadata_enc.txt", "w" ); - if ( pF_azi == NULL ) - pF_azi = fopen( "./res/qmetadata_azi_enc.txt", "w" ); - if ( pF_ele == NULL ) - pF_ele = fopen( "./res/qmetadata_ele_enc.txt", "w" ); - if ( pF_ratio == NULL ) - pF_ratio = fopen( "./res/qmetadata_ratio_enc.txt", "w" ); - if ( pF_spcoh == NULL ) - pF_spcoh = fopen( "./res/qmetadata_spcoh_enc.txt", "w" ); - if ( pF_spcoh_orig == NULL ) - pF_spcoh_orig = fopen( "./res/qmetadata_spcoh_orig.txt", "w" ); - if ( pF_surcoh == NULL ) - pF_surcoh = fopen( "./res/qmetadata_surcoh_enc.txt", "w" ); -#endif - - - /* Save initial position in bitstream */ - -#ifndef HR_METADATA_HR_COH - bit_pos_0 = hMetaData->nb_bits_tot; - bit_pos_start = bit_pos_0; -#endif - ndirections = hQMetaData->no_directions; - - - /* Check if coherence should be encoded */ - all_coherence_zero = 1; - bits_no_dirs_coh = 0; - - if ( hQMetaData->coherence_flag ) - { - all_coherence_zero = hQMetaData->all_coherence_zero; - push_next_indice( hMetaData, all_coherence_zero, 1 ); /* signal coherence */ - bits_no_dirs_coh += 1; - } - /*Quantization and encoding of the Diffuseness */ - ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( hQMetaData, bits_diff, 16, hMetaData ); + ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( hQMetaData, bits_diff, bits_sph_idx, hMetaData ); /* Encode surround coherence */ if ( all_coherence_zero == 0 ) @@ -1210,9 +814,7 @@ ivas_error ivas_qmetadata_enc_encode_hr_512( } else { -#ifndef HR_METADATA_HR_COH - bits_surround_coh = 0; -#endif + for ( i = 0; i < hQMetaData->q_direction[0].cfg.nbands; i++ ) { if ( hQMetaData->surcoh_band_data != NULL ) @@ -1255,41 +857,27 @@ ivas_error ivas_qmetadata_enc_encode_hr_512( /*Coherence */ -#ifndef HR_METADATA_HR_COH - bits_coherence[d] = 0; - bit_pos_start_coh = hMetaData->nb_bits_tot; -#endif if ( all_coherence_zero == 0 ) { -#ifdef HR_METADATA_HR_COH - ivas_qmetadata_quantize_coherence_hr_512( hQMetaData, d, all_coherence_zero, hMetaData ); -#else - bits_coherence[d] = ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 0, &indice_coherence, 1 ); -#endif + ivas_qmetadata_quantize_coherence_hr_512( hQMetaData, d, all_coherence_zero, hMetaData, bits_sp_coh ); } - /* write the 16bit spherical indexes */ + /* write the spherical indexes */ bits_ec = hMetaData->nb_bits_tot; + if ( bits_sph_idx == 11 ) + { + /* do the quantization */ + quantize_direction_frame( q_direction, azimuth_orig, elevation_orig, 1 ); + } for ( i = start_band; i < nbands; i++ ) { for ( j = 0; j < nblocks; j++ ) { - push_next_indice( hMetaData, q_direction->band_data[i].spherical_index[j], 16 ); + push_next_indice( hMetaData, q_direction->band_data[i].spherical_index[j], bits_sph_idx ); } } bits_ec = hMetaData->nb_bits_tot - bits_ec; -#ifndef HR_METADATA_HR_COH - /* finalize writing coherence */ - if ( ( bits_coherence[d] > 0 ) && ( all_coherence_zero == 0 ) && ( nblocks > 1 ) ) - { - bit_pos_start = hMetaData->nb_bits_tot; - hMetaData->nb_bits_tot = bit_pos_start_coh; - ivas_qmetadata_quantize_coherence( hQMetaData, d, all_coherence_zero, hMetaData, 1, &indice_coherence, 1 ); - hMetaData->nb_bits_tot = bit_pos_start; - } -#endif - #ifdef DEBUG_MODE_QMETADATA { float tmp_f; @@ -1351,18 +939,29 @@ ivas_error ivas_qmetadata_enc_encode_hr_512( #endif /* Save quantized DOAs */ - for ( i = start_band; i < nbands; i++ ) + if ( bits_sph_idx == 11 ) { - mvr2r( q_direction->band_data[i].azimuth, q_direction->band_data[i].q_azimuth, nblocks ); - mvr2r( q_direction->band_data[i].elevation, q_direction->band_data[i].q_elevation, nblocks ); + for ( i = start_band; i < nbands; i++ ) + { + mvr2r( azimuth_orig[i], q_direction->band_data[i].azimuth, nblocks ); + mvr2r( elevation_orig[i], q_direction->band_data[i].elevation, nblocks ); + } + } + else + { + for ( i = start_band; i < nbands; i++ ) + { + mvr2r( q_direction->band_data[i].azimuth, q_direction->band_data[i].q_azimuth, nblocks ); + mvr2r( q_direction->band_data[i].elevation, q_direction->band_data[i].q_elevation, nblocks ); + } } } return error; } - #endif + /*-----------------------------------------------------------------------* * ivas_qmetadata_enc_sid_encode() * @@ -2039,6 +1638,7 @@ static int16_t ivas_qmetadata_entropy_encode_diffuseness_hr( } #endif + /*------------------------------------------------------------------------- * ivas_qmetadata_quantize_diffuseness_nrg_ratios() * @@ -5468,6 +5068,7 @@ static int16_t encode_surround_coherence( return nbits; } + #ifdef HR_METADATA static int16_t encode_surround_coherence_hr( IVAS_QMETADATA *hQMetaData, /* i : quantized metadata */ @@ -5490,6 +5091,7 @@ static int16_t encode_surround_coherence_hr( uint8_t idx_shift; int16_t max_val = 0, nbits_max; int16_t no_cv_shift[MASA_MAXIMUM_CODING_SUBBANDS], min_idx; + int16_t idx16; coding_subbands = hQMetaData->q_direction[0].cfg.nbands; all_coherence_zero = hQMetaData->all_coherence_zero; @@ -5511,12 +5113,16 @@ static int16_t encode_surround_coherence_hr( { if ( hQMetaData->no_directions == 2 ) { - error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf] - q_direction[1].band_data[j].energy_ratio[sf] * hQMetaData->twoDirBands[j]; + k += hQMetaData->twoDirBands[j]; + idx16 = max( k - 1, 0 ); + error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf] - q_direction[1].band_data[idx16].energy_ratio[sf] * hQMetaData->twoDirBands[j]; } else { error_ratio_surr = 1.0f - q_direction[0].band_data[j].energy_ratio[sf]; } + + if ( error_ratio_surr <= 0 ) { error_ratio_surr = 0; @@ -5799,23 +5405,24 @@ static void dct4_transform( return; } -#ifdef HR_METADATA_HR_COH +#ifdef HR_METADATA static int16_t ivas_qmetadata_quantize_coherence_hr_512( IVAS_QMETADATA *hQMetaData, /* i/o: quantized metadata */ const int16_t idx_d, /* i : current direction index */ const int16_t all_coherence_zero, /* i : all coherence is zero - flag */ - BSTR_ENC_HANDLE hMetaData /* i : metadata handle */ -) + BSTR_ENC_HANDLE hMetaData, /* i : metadata handle */ + int16_t bits_coh ) { int16_t j, k; int16_t nbands, nblocks; int16_t nbits; - int16_t nbits1, nbits0; - int16_t idx_coh[MASA_MAXIMUM_CODING_SUBBANDS]; + int16_t nbits1, nbits0, nbits_av; + uint16_t idx_coh[MASA_MAXIMUM_CODING_SUBBANDS]; IVAS_QDIRECTION *q_direction; int16_t cbsize; float delta, tmp; - int16_t min_idx, GR_param; + int16_t min_idx, GR_param, GR_param_av; + uint16_t av, mr_idx[MASA_MAXIMUM_CODING_SUBBANDS]; q_direction = &( hQMetaData->q_direction[idx_d] ); nbands = q_direction->cfg.nbands; @@ -5828,7 +5435,7 @@ static int16_t ivas_qmetadata_quantize_coherence_hr_512( } nbits = hMetaData->nb_bits_tot; - cbsize = 1 << NBITS_HR_COH; + cbsize = 1 << bits_coh; delta = 256.0f / cbsize; for ( k = 0; k < nblocks; k++ ) @@ -5843,29 +5450,55 @@ static int16_t ivas_qmetadata_quantize_coherence_hr_512( min_idx = idx_coh[j]; } } + + nbits0 = 0; nbits1 = 0; for ( j = 0; j < nbands; j++ ) { idx_coh[j] = idx_coh[j] - min_idx; - nbits0 += ivas_qmetadata_encode_extended_gr_length( idx_coh[j], cbsize - min_idx - 1, 0 ); - nbits1 += ivas_qmetadata_encode_extended_gr_length( idx_coh[j], cbsize - min_idx - 1, 1 ); + nbits0 += ivas_qmetadata_encode_extended_gr_length( idx_coh[j], cbsize - min_idx, 0 ); + nbits1 += ivas_qmetadata_encode_extended_gr_length( idx_coh[j], cbsize - min_idx, 1 ); } if ( nbits0 < nbits1 ) { GR_param = 0; + nbits1 = nbits0; } else { GR_param = 1; } - /* write min index */ - push_next_indice( hMetaData, min_idx, NBITS_HR_COH ); - /* write GR param */ - push_next_indice( hMetaData, GR_param, 1 ); - for ( j = 0; j < nbands; j++ ) + GR_param_av = 1; + nbits_av = mean_removed_GR_new( idx_coh, cbsize, nbands, 1, &GR_param_av, &av, mr_idx ); + + if ( nbits_av < nbits1 ) + { + nbits1 = nbits_av; + GR_param = GR_param_av; + /* use average removed */ + push_next_indice( hMetaData, 1, 1 ); + /* write average */ + push_next_indice( hMetaData, av, bits_coh ); + /* write GR param */ + push_next_indice( hMetaData, GR_param, 1 ); + for ( j = 0; j < nbands; j++ ) + { + ivas_qmetadata_encode_extended_gr( hMetaData, mr_idx[j], 2 * cbsize, GR_param ); + } + } + else { - ivas_qmetadata_encode_extended_gr( hMetaData, idx_coh[j], cbsize - min_idx, GR_param ); + /* use min removed */ + push_next_indice( hMetaData, 0, 1 ); + /* write min index */ + push_next_indice( hMetaData, min_idx, bits_coh ); + /* write GR param */ + push_next_indice( hMetaData, GR_param, 1 ); + for ( j = 0; j < nbands; j++ ) + { + ivas_qmetadata_encode_extended_gr( hMetaData, idx_coh[j], cbsize - min_idx, GR_param ); + } } } -- GitLab From b8954042bf17c2f51965776ee9e7e902c1868dce Mon Sep 17 00:00:00 2001 From: Lauros Pajunen Date: Thu, 27 Apr 2023 14:00:55 +0300 Subject: [PATCH 3/7] Deactivate DEBUG_MODE_QMETADATA --- lib_com/options.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_com/options.h b/lib_com/options.h index 37a2d2abac..f30262bdd8 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -94,7 +94,7 @@ /*#define DEBUG_DISABLE_DIRAC_DELAY_COMP */ /* temporarily disable delay compensation on DirAC encoder */ /*#define DEBUG_BS_READ_WRITE*/ /*#define DEBUG_MODE_DIRAC_NOCORE*/ -#define DEBUG_MODE_QMETADATA /* output q_metadata parameters */ +/*#define DEBUG_MODE_QMETADATA*/ /* output q_metadata parameters */ /*MCT Debug switches*/ /*#define DEBUG_FORCE_MCT_CP*/ /* force MCT Stereo pairs for verification with SPAR */ -- GitLab From 62b2af4595c2977b9a4dd5a24c39f9eb8fb12cdf Mon Sep 17 00:00:00 2001 From: Tapani Pihlajakuja Date: Fri, 5 May 2023 09:28:55 +0300 Subject: [PATCH 4/7] Fix previous merge. --- lib_com/options.h | 4 ++-- lib_enc/ivas_masa_enc.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib_com/options.h b/lib_com/options.h index 053cbda3fd..a8e92c99bf 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -166,8 +166,6 @@ #define FIX_417_TD_DECORR_BRATE_SW /* VA: Issue 417: fix incorrect use of TD decorrelator in bitrate switching */ - -#define HR_METADATA /* Nok: encode directional MASA metadata with more bits at 384k and 512k */ #define LBR_SBA /* Contribution 47: Master macro for low bitrate SBA (SPAR+DirAC) */ #ifdef LBR_SBA #define LBR_SBA_BR_SWITCHING /* Clean up changes for SBA bitrate switching */ @@ -179,6 +177,8 @@ #define LBR_ADAP_SMOOTHING #endif +#define HR_METADATA /* Nok: encode directional MASA metadata with more bits at 384k and 512k */ + /* ################## End DEVELOPMENT switches ######################### */ /* clang-format on */ #endif diff --git a/lib_enc/ivas_masa_enc.c b/lib_enc/ivas_masa_enc.c index 6b9d69d66f..7f7c7ca6f7 100644 --- a/lib_enc/ivas_masa_enc.c +++ b/lib_enc/ivas_masa_enc.c @@ -61,8 +61,6 @@ static int16_t encode_lfe_to_total_energy_ratio( MASA_ENCODER_HANDLE hMasa, BSTR static void reduce_metadata_further( MASA_ENCODER_HANDLE hMasa, IVAS_QMETADATA_HANDLE hqmetadata, const IVAS_FORMAT ivas_format ); - -#ifdef FIX_382_MASA_META_FRAMING_ASYNC static void average_masa_metadata( MASA_METADATA_FRAME *masaMetadata, float energy[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS] #ifdef HR_METADATA , -- GitLab From 56351722b86e41d93fb01d186c980c22866a56ed Mon Sep 17 00:00:00 2001 From: Tapani Pihlajakuja Date: Fri, 5 May 2023 10:52:47 +0300 Subject: [PATCH 5/7] Remove extra code and fix sanitizer error. --- lib_enc/ivas_masa_enc.c | 250 ----------------------------------- lib_enc/ivas_qmetadata_enc.c | 23 ++-- 2 files changed, 13 insertions(+), 260 deletions(-) diff --git a/lib_enc/ivas_masa_enc.c b/lib_enc/ivas_masa_enc.c index 7f7c7ca6f7..3eda5e46ea 100644 --- a/lib_enc/ivas_masa_enc.c +++ b/lib_enc/ivas_masa_enc.c @@ -2332,253 +2332,3 @@ static void masa_metadata_direction_alignment( } #endif -#ifdef HR_METADATA1 -void indexDirection( - uint16_t *sphIndex, /* o : output index for direction */ - float theta, /* i : input elevation to be indexed */ - float phi, /* i : input azimuth to be indexed */ - const SPHERICAL_GRID_DATA *gridData /* i : generated grid data */ -) -{ - float abs_theta, phi_q; - int16_t sign_th, id_phi, id_th; - int32_t idx_sph; - int32_t cum_n; - - phi = phi + 180; - if ( theta < 0 ) - { - abs_theta = -theta; - sign_th = -1; - } - else - { - abs_theta = theta; - sign_th = 1; - } - - quantize_theta_phi( gridData->no_theta, gridData->no_phi, abs_theta, &id_phi, - phi, &id_th, &phi_q ); - - /* Starting from Equator, alternating positive and negative */ - if ( id_th == 0 ) - { - idx_sph = id_phi; - } - else - { - if ( id_th == gridData->no_theta - 1 ) - { - idx_sph = 65534 + ( sign_th < 0 ); - } - else - { - theta = MASA_ANGLE_AT_EQUATOR * (float) ( id_th + 0.5f ); - if ( id_th == 1 ) - { - cum_n = 2 * (int16_t) ceilf( MASA_NTOT2_FAC * ( sinf( theta ) - MASA_ASIN_OFFSET ) ); - } - else - { - cum_n = 2 * (int16_t) roundf( MASA_NTOT2_FAC * ( sinf( theta ) - MASA_ASIN_OFFSET ) ); - } - cum_n += gridData->no_phi[0]; - if ( sign_th > 0 ) - { - cum_n -= 2 * gridData->no_phi[id_th]; - } - else - { - cum_n -= gridData->no_phi[id_th]; - } - idx_sph = cum_n + id_phi; - } - } - - *sphIndex = idx_sph; -} - -int16_t quantize_theta( /* o : index of quantized value */ - float x, /* i : theta value to be quantized */ - int16_t no_cb, /* i : number of codewords */ - float *xhat /* o : quantized value */ -) -{ - int16_t imin; - - float diff1, diff2; - - - imin = (int16_t) ( x * MASA_INV_ANGLE_AT_EQUATOR_DEG + 0.5f ); - - if ( imin >= no_cb - 1 ) - { - imin = no_cb - 1; - diff1 = x - 90; - diff2 = x - MASA_ANGLE_AT_EQUATOR_DEG * ( imin - 1 ); - if ( fabsf( diff1 ) > fabsf( diff2 ) ) - { - imin--; - *xhat = imin * MASA_ANGLE_AT_EQUATOR_DEG; - } - else - { - *xhat = 90; - } - } - else - { - *xhat = imin * MASA_ANGLE_AT_EQUATOR_DEG; - } - - return imin; -} - -void quantize_theta_phi( - const int16_t no_th, /* i : elevation codebook size */ - const int16_t *no_phi_loc, /* i : number of azimuth values for each elevation codeword */ - const float abs_theta, /* i : absolute value of elevation to be quantized */ - int16_t *id_phi, /* o : azimuth index */ - const float phi, /* i : input azimuth value; to be quantized */ - int16_t *id_theta, /* o : elevation index */ - float *phi_q /* o : rotated quantized azimuth */ -) -{ - float theta_hat, theta_hat1, phi_hat, phi_hat1; - int16_t id_th, id_th1, id_th2, id_ph, id_ph1; - float d, d1; - float diff1, diff2; - - theta_hat = 0; /* to remove warning */ - id_th = quantize_theta( abs_theta, no_th, &theta_hat ); - if ( no_th > 1 ) - { - if ( id_th == 0 ) - { - id_th1 = 1; - } - else if ( id_th == no_th - 1 ) - { - id_th1 = no_th - 2; - } - else - { - id_th1 = id_th - 1; - id_th2 = id_th + 1; - - diff1 = abs_theta - id_th1 * MASA_ANGLE_AT_EQUATOR_DEG; - diff2 = abs_theta - MASA_ANGLE_AT_EQUATOR_DEG * id_th2; - if ( id_th2 == no_th - 1 ) - { - diff2 = abs_theta - 90; - } - if ( fabsf( diff1 ) > fabsf( diff2 ) ) - { - id_th1 = id_th2; - } - } - - theta_hat1 = MASA_ANGLE_AT_EQUATOR_DEG * id_th1; - - if ( id_th1 == no_th - 1 ) - { - theta_hat1 = 90; - } - - - if ( no_phi_loc[id_th] > 1 ) - { - id_ph = quantize_phi( phi, ( id_th % 2 == 1 ), &phi_hat, no_phi_loc[id_th] ); - } - else - { - id_ph = MASA_NO_INDEX; - phi_hat = 180; - *phi_q = 0; - } - if ( ( no_phi_loc[id_th1] > 1 ) && ( id_ph < MASA_NO_INDEX ) ) - { - id_ph1 = quantize_phi( phi, ( id_th1 % 2 == 1 ), &phi_hat1, no_phi_loc[id_th1] ); - d = direction_distance( abs_theta, theta_hat, phi, phi_hat ); - d1 = direction_distance( abs_theta, theta_hat1, phi, phi_hat1 ); - if ( d1 > d ) - { - id_ph = id_ph1; - id_th = id_th1; /*theta_hat = ANGLE_AT_EQUATOR_DEG * id_th1; */ - } - } - } - else - { - id_ph = quantize_phi( phi, ( id_th % 2 == 1 ), &phi_hat, no_phi_loc[id_th] ); - } - - *id_phi = id_ph; - *id_theta = id_th; -} - -int16_t quantize_phi( /* o : index azimuth */ - float phi, /* i : azimuth value */ - int16_t flag_delta, /* i : flag indicating if the azimuth codebook is translated or not */ - float *phi_hat, /* o : quantized azimuth */ - const int16_t n /* i : azimuth codebook size */ -) -{ - int16_t id_phi; - float dd; - float delta_phi; - - delta_phi = 360.0f / (float) n; - - if ( n == 1 ) - { - *phi_hat = 0; - - return 0; - } - - if ( flag_delta == 1 ) - { - dd = delta_phi / 2.0f; - } - else - { - dd = 0; - } - - id_phi = (int16_t) ( ( phi - dd + delta_phi / 2.0f ) / (float) delta_phi ); - - if ( id_phi == n ) - { - id_phi = 0; - } - - if ( id_phi == -1 ) - { - id_phi = n - 1; - } - - *phi_hat = id_phi * delta_phi + dd; - - return id_phi; -} - -float direction_distance( /* o : distortion value */ - float theta, /* i : elevation absolute value */ - float theta_hat, /* i : quantized elevation value in absolute value */ - const float phi, /* i : azimuth value */ - const float phi_hat /* i : quantized azimuth value */ -) -{ - float d; - - theta *= EVS_PI / 180; - theta_hat *= EVS_PI / 180; - - d = sinf( theta ) * sinf( theta_hat ) + cosf( theta ) * cosf( theta_hat ) * cosf( ( phi - phi_hat ) * EVS_PI / 180 ); - - return d; -} - - -#endif \ No newline at end of file diff --git a/lib_enc/ivas_qmetadata_enc.c b/lib_enc/ivas_qmetadata_enc.c index 4fe2709528..3a947584e9 100644 --- a/lib_enc/ivas_qmetadata_enc.c +++ b/lib_enc/ivas_qmetadata_enc.c @@ -1517,20 +1517,23 @@ static void ivas_qmetadata_quantize_diffuseness_nrg_ratios_hr_512( hQMetaData->q_direction[0].band_data[j].bits_sph_idx[k] = bits_dir_hr; } } - for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; ++j ) + if ( hQMetaData->no_directions == 2 ) { - for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) + for ( j = hQMetaData->q_direction[1].cfg.start_band; j < hQMetaData->q_direction[1].cfg.nbands; ++j ) { - index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); - push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); - hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; - hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; - if ( hQMetaData->q_direction[1].band_data[j].energy_ratio[k] > 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k] ) + for ( k = 0; k < hQMetaData->q_direction[1].cfg.nblocks; k++ ) { - hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k]; + index = masa_sq( 1.0f - hQMetaData->q_direction[1].band_data[j].energy_ratio[k], diffuseness_thresholds_hr, HR_MASA_ER_LEVELS ); + push_next_indice( hMetaData, index, MASA_BITS_ER_HR ); + hQMetaData->q_direction[1].band_data[j].energy_ratio_index[k] = index; + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - diffuseness_reconstructions_hr[index]; + if ( hQMetaData->q_direction[1].band_data[j].energy_ratio[k] > 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k] ) + { + hQMetaData->q_direction[1].band_data[j].energy_ratio[k] = 1.0f - hQMetaData->q_direction[0].band_data[j].energy_ratio[k]; + } + needed_bits[1] += MASA_BITS_ER_HR; + hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; } - needed_bits[1] += MASA_BITS_ER_HR; - hQMetaData->q_direction[1].band_data[j].bits_sph_idx[k] = bits_dir_hr; } } -- GitLab From b70435bbc4d06dda2ab4046af9842bdd5eedbff9 Mon Sep 17 00:00:00 2001 From: advasila Date: Fri, 5 May 2023 11:44:10 +0300 Subject: [PATCH 6/7] formatting --- lib_enc/ivas_masa_enc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib_enc/ivas_masa_enc.c b/lib_enc/ivas_masa_enc.c index 3eda5e46ea..5b5363efb3 100644 --- a/lib_enc/ivas_masa_enc.c +++ b/lib_enc/ivas_masa_enc.c @@ -2331,4 +2331,3 @@ static void masa_metadata_direction_alignment( return; } #endif - -- GitLab From df086053016cdbf4f818c9257fcb1c0ab7b213fe Mon Sep 17 00:00:00 2001 From: Tapani Pihlajakuja Date: Fri, 5 May 2023 12:09:12 +0300 Subject: [PATCH 7/7] Add missing new line. --- lib_com/ivas_masa_com.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_com/ivas_masa_com.c b/lib_com/ivas_masa_com.c index b1181b0d96..02d9939dc4 100644 --- a/lib_com/ivas_masa_com.c +++ b/lib_com/ivas_masa_com.c @@ -587,4 +587,4 @@ int16_t quantize_phi_masa( return id_phi; } -#endif \ No newline at end of file +#endif -- GitLab