diff --git a/scripts/ivas_conformance/masa-diff-tool/CMakeLists.txt b/scripts/ivas_conformance/masa-diff-tool/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e908266ff3ee7ab5913caaecbc618a2fc5a6d24c --- /dev/null +++ b/scripts/ivas_conformance/masa-diff-tool/CMakeLists.txt @@ -0,0 +1,69 @@ +#------------------------------------------------------------------------------------------------------------ +# MASA conformance tools +# ---------------------------------- +# (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. +# +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. +# +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. +# +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. +# +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. +# +#------------------------------------------------------------------------------------------------------------ + +cmake_minimum_required(VERSION 3.10) +project(MasaDiffTool C) +set(MASA_DIFF_TOOL_NAME masaDiffTool) + +set(CMAKE_C_STANDARD 99) + +if(WIN32) + add_definitions( + -D_CRT_SECURE_NO_WARNINGS + -Drestrict=__restrict + /wd4028 + /wd4100 + /wd4244 + /wd4310 + /wd4996 + /MP + ) +endif() + +set(MASA_DIFF_TOOL_SOURCES + ivasParts.c + masaDiffTool.c + masa_file_reader.c +) + +set(MASA_DIFF_TOOL_HEADERS + ivasParts.h + masa_file_reader.h +) + + +add_executable(${MASA_DIFF_TOOL_NAME} ${MASA_DIFF_TOOL_SOURCES} ${MASA_DIFF_TOOL_HEADERS}) + +if(NOT WIN32) + target_link_libraries(${MASA_DIFF_TOOL_NAME} m) +endif() diff --git a/scripts/ivas_conformance/masa-diff-tool/README.md b/scripts/ivas_conformance/masa-diff-tool/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4933098ec09c5c19eb2245cab44a94d34e5f00c9 --- /dev/null +++ b/scripts/ivas_conformance/masa-diff-tool/README.md @@ -0,0 +1,117 @@ +# MASA-diff-tool + +Version: 0.2.1 + +## Usage + +``` +Usage: masaDiffTool [options] refMetaFile cutMetaFile +Options: +--report , produces frame-by-frame results in text format +--csv , produces most useful frame-by-frame results in csv format with header row and comma separation +--conformance, uses conformance tolerances instead of strict BE metadata comparison for final result +``` + +## Output data + +The tool provides always a summary of the differences to stdout at the end, and the return value is 0 only if the two +compared metadata files are identical. The summary contains: +- Overall status for metadata difference +- Total number of differing frames +- Status for descriptive metadata difference +- Overall status for spatial metadata difference +- Across all frames max ABS and mean difference values for spatial metadata + - Overall max ABS diff in spatial direction (degrees) + - Overall mean ABS diff in spatial direction (degrees) + - Overall max ABS diff in direct-to-total ratio + - Overall mean ABS diff in direct-to-total ratio + - Overall max ABS diff in diffuse-to-total ratio + - Overall mean ABS diff in diffuse-to-total ratio + - Overall max ABS diff in remainder-to-total ratio + - Overall mean ABS diff in remainder-to-total ratio + - Overall max ABS diff in spread coherence ratio + - Overall mean ABS diff in spread coherence ratio + - Overall max ABS diff in surround coherence ratio + - Overall mean ABS diff in surround coherence ratio + + +(Not implemented yet) If option `--conformance` is used, then the return value will be 0 also when the differences are +within conformance limits. + +If a file contains format descriptor that is not `IVASMASA`, then the file is considered non-conformant and comparison +does not continue. + +If a frame has differing number of directions in metadata, then spatial metadata comparison is not done and the frame is +considered to be completely different. + +When option `--report` is given, then a frame-by-frame printout is generated into the text file. This lists main +differences in spatial metadata and also detailed difference in descriptive metadata. + +When option `--csv` is given, then a frame-by-frame results is constructed in comma-separated CSV-file with headers for: +- Frame index +- Diff in descriptive metadata +- Diff in number of directions +- Max ABS diff: Direction (degrees spatial angle) +- Mean ABS diff: Direction (degrees spatial angle) +- Max ABS diff: Direct-to-total ratio +- Mean ABS diff: Direct-to-total ratio +- Max ABS diff: Diffuse-to-total ratio +- Mean ABS diff: Diffuse-to-total ratio +- Max ABS diff: Remainder-to-total ratio +- Mean ABS diff: Remainder-to-total ratio +- Max ABS diff: Spread coherence +- Mean ABS diff: Spread coherence +- Max ABS diff: Surround coherence +- Mean ABS diff: Surround coherence + +In the CSV-file, the spatial metadata diff values are considered invalid if "Diff in number of directions" is 1. + + +## Structure + +The program code is structured as follows + +- masaDiffTool.c, main application including comparison and reporting functions +- masa_file_reader.[c|h], MASA metadata reader from IVAS source code with minor changes +- ivasParts.[c|h], parts of code from several common IVAS headers and source files needed by MASA metadata reader + + + +## Todo + +- Set and check against conformance limits +- Test on different platforms + + + +## Notice + +(C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +contributors to this repository. All Rights Reserved. + +This software is protected by copyright law and by international treaties. +The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +contributors to this repository retain full ownership rights in their respective contributions in +the software. This notice grants no license of any kind, including but not limited to patent +license, nor is any license granted by implication, estoppel or otherwise. + +Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +contributions. + +This software is provided "AS IS", without any express or implied warranties. The software is in the +development stage. It is intended exclusively for experts who have experience with such software and +solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +and fitness for a particular purpose are hereby disclaimed and excluded. + +Any dispute, controversy or claim arising under or in relation to providing this software shall be +submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +the United Nations Convention on Contracts on the International Sales of Goods. + + diff --git a/scripts/ivas_conformance/masa-diff-tool/ivasParts.c b/scripts/ivas_conformance/masa-diff-tool/ivasParts.c new file mode 100644 index 0000000000000000000000000000000000000000..ce38fef83fa23e5a102eb03198b604f6b9a3f007 --- /dev/null +++ b/scripts/ivas_conformance/masa-diff-tool/ivasParts.c @@ -0,0 +1,237 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/****************************************************************************************************** + This file is adapted from IVAS source code files to support the specific task of this diff tool. + The sources for this file are: + - lib_com/ivas_masa_com.c +*******************************************************************************************************/ + + +#include +#include + +#include "ivasParts.h" + + +/*--------------------------------------------------------------- + * generate_gridEq() + * + * generate Spherical grid + *---------------------------------------------------------------*/ + +void generate_gridEq( + SPHERICAL_GRID_DATA *data /* o : data structure for grid */ +) +{ + int32_t cum_n, cum_n_prev; + float theta; + int16_t i; + int16_t *n; + + n = data->no_phi; + n[0] = MASA_NO_POINTS_EQUATOR; + + cum_n_prev = 0; + + for ( i = 1; i < MASA_NO_CIRCLES; i++ ) + { + theta = MASA_ANGLE_AT_EQUATOR * (float) ( i + 0.5f ); + if ( i == 1 ) + { + cum_n = 2 * (int32_t) ceilf( MASA_NTOT2_FAC * ( sinf( theta ) - MASA_ASIN_OFFSET ) ); + } + else + { + cum_n = 2 * (int32_t) roundf( MASA_NTOT2_FAC * ( sinf( theta ) - MASA_ASIN_OFFSET ) ); + } + n[i] = (int16_t) ( ( cum_n - cum_n_prev ) >> 1 ); + cum_n_prev = cum_n; + } + n[i] = 1; + data->no_theta = i + 1; + + return; +} + + +/*------------------------------------------------------------------------- + * deindex_sph_idx() + * + * deindex the MASA metadata from the input metadata file + *------------------------------------------------------------------------*/ + +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; + int32_t base_low, base_up; + int16_t n_crt; + int16_t id_th; + int16_t sign_theta; + int16_t id_phi; + int16_t no_th = gridData->no_theta; + const int16_t *n = gridData->no_phi; + const float ba[3] = { 2.137991118026424e+02f, 1.244854404591542e+02f, 1.228408647140870e+02f }; + const float del[3] = { 7.998262115303199e+05f, 1.300883976959332e+06f, 1.424072242426373e+06f }; + const float div[3] = { -0.237662341081474f, -0.100938185496887f, -0.092050209205032f }; + const float a4[3] = { -8.415300425381099f, -19.814106922515204f, -21.727272727270197f }; + const uint16_t limit_index1 = 64964, limit_index2 = 47870; + + if ( sphIndex >= limit_index1 ) + { + ba_crt = ba[2]; + div_crt = div[2]; + a4_crt = a4[2]; + del_crt = del[2]; + } + else if ( sphIndex >= limit_index2 ) + { + ba_crt = ba[1]; + div_crt = div[1]; + a4_crt = a4[1]; + del_crt = del[1]; + } + else + { + ba_crt = ba[0]; + div_crt = div[0]; + a4_crt = a4[0]; + del_crt = del[0]; + } + estim = ba_crt + div_crt * sqrtf( del_crt + a4_crt * sphIndex ); + + if ( estim > MASA_NO_CIRCLES ) + { + estim = MASA_NO_CIRCLES; + } + + assert( estim > 0 ); + id_th = (int16_t) roundf( estim ) - 1; + if ( id_th < 0 ) + { + id_th = 0; + } + + if ( id_th == 0 ) + { + base_low = 0; + base_up = n[0]; + } + else + { + estim = MASA_ANGLE_AT_EQUATOR * (float) ( id_th - 0.5f ); + base_low = n[0]; + if ( id_th >= 2 ) + { + if ( id_th == 2 ) + { + base_low += 2 * (int16_t) ceilf( MASA_NTOT2_FAC * ( sinf( estim ) - MASA_ASIN_OFFSET ) ); + } + else + { + base_low += 2 * (int16_t) roundf( MASA_NTOT2_FAC * ( sinf( estim ) - MASA_ASIN_OFFSET ) ); + } + } + base_up = base_low + 2 * n[id_th]; + } + + sign_theta = 1; + + n_crt = n[id_th]; + if ( sphIndex < base_low ) + { + id_th--; + n_crt = n[id_th]; + if ( id_th == 0 ) + { + base_low = 0; + base_up = n_crt; + } + else + { + base_up = base_low; + base_low -= 2 * n[id_th]; + } + assert( sphIndex >= base_low ); + } + else if ( sphIndex >= base_up ) + { + id_th++; + n_crt = n[id_th]; + base_low = base_up; + base_up += 2 * n_crt; + assert( sphIndex < base_up ); + } + + id_phi = (int16_t) ( sphIndex - base_low ); + if ( sphIndex - base_low >= n_crt ) + { + id_phi -= n_crt; + sign_theta = -1; + } + + if ( id_th == 0 ) + { + *theta = 0.f; + *phi = (float) sphIndex * 360 / (float) n_crt - 180; + } + else + { + if ( id_th == no_th - 1 ) + { + id_phi = 0; + *phi = -180; + *theta = 90 * (float) sign_theta; + } + else + { + *theta = id_th * MASA_ANGLE_AT_EQUATOR_DEG * (float) sign_theta; + if ( id_th % 2 == 0 ) + { + *phi = (float) id_phi * 360 / (float) n_crt - 180; + } + else + { + *phi = ( (float) id_phi + 0.5f ) * 360 / (float) n_crt - 180; + } + } + } + + return; +} + diff --git a/scripts/ivas_conformance/masa-diff-tool/ivasParts.h b/scripts/ivas_conformance/masa-diff-tool/ivasParts.h new file mode 100644 index 0000000000000000000000000000000000000000..0d38e0ae7250923e4f80ab76898cca63cd40f90e --- /dev/null +++ b/scripts/ivas_conformance/masa-diff-tool/ivasParts.h @@ -0,0 +1,268 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/****************************************************************************************************** + This file is adapted from IVAS source code files to support the specific task of this diff tool. + The sources for this file are: + - lib_com/cnst.h + - lib_com/common_api_types.h + - lib_com/ivas_cnst.h + - lib_com/ivas_error.h + - lib_com/ivas_stat_com.h +*******************************************************************************************************/ + +#ifndef MASACONFORMANCETOOL_IVASPARTS_H +#define MASACONFORMANCETOOL_IVASPARTS_H + +#include + + +// Constants +#define EVS_PI 3.14159265358979323846264338327950288f + +#define MAX_PARAM_SPATIAL_SUBFRAMES 4 /* Maximum number of subframes for parameteric spatial coding */ +#define MASA_FREQUENCY_BANDS 24 +#define MASA_MAXIMUM_DIRECTIONS 2 + +#define MAX_NO_THETA 19 +#define NO_THETA16_MAX 122 /* number of theta values for 16 bits */ +#define NO_SPHERICAL_GRIDS 11 /* number of spherical grid structures */ +#define MASA_NO_POINTS_EQUATOR 430 +#define MASA_NO_CIRCLES 121 +#define MASA_ASIN_OFFSET 0.0064471690266724975f +#define MASA_NTOT2_FAC 32768.00566947353f +#define MASA_ANGLE_AT_EQUATOR 0.012894427382667f +#define MASA_ANGLE_AT_EQUATOR_DEG 0.738796268264740f +#define MASA_INV_ANGLE_AT_EQUATOR_DEG 1.353553128183453f + + + +// enums +typedef enum +{ + /*----------------------------------------* + * no error * + *----------------------------------------*/ + IVAS_ERR_OK = 0x0000, + + /*----------------------------------------* + * API errors * + *----------------------------------------*/ + IVAS_ERR_INVALID_BANDWIDTH = 0x1000, + IVAS_ERR_INVALID_DTX_UPDATE_RATE, + IVAS_ERR_INVALID_SAMPLING_RATE, + IVAS_ERR_NOT_CONFIGURED, + IVAS_ERR_INVALID_STEREO_MODE, + IVAS_ERR_INVALID_MC_LAYOUT, + IVAS_ERR_INVALID_BITRATE, + IVAS_ERR_INVALID_MASA_CONFIG, + IVAS_ERR_TOO_MANY_INPUTS, + IVAS_ERR_MISSING_METADATA, + IVAS_ERR_RECONFIGURE_NOT_SUPPORTED, + IVAS_ERR_INVALID_FEC_CONFIG, + IVAS_ERR_INVALID_FEC_OFFSET, + IVAS_ERR_INVALID_INPUT_BUFFER_SIZE, + IVAS_ERR_INVALID_OUTPUT_BUFFER_SIZE, + IVAS_ERR_DTX_NOT_SUPPORTED, + IVAS_ERR_UNEXPECTED_NULL_POINTER, + IVAS_ERR_METADATA_NOT_EXPECTED, + IVAS_ERR_WRONG_PARAMS, + IVAS_ERR_INIT_ERROR, + IVAS_ERR_WRONG_MODE, + IVAS_ERR_INVALID_OUTPUT_FORMAT, + IVAS_ERR_HEAD_ROTATION_NOT_SUPPORTED, + IVAS_ERR_EXT_ORIENTATION_NOT_SUPPORTED, + IVAS_ERR_DIRECTIVITY_NOT_SUPPORTED, + IVAS_ERR_ACOUSTIC_ENVIRONMENT_NOT_SUPPORTED, + IVAS_ERR_OBJECTS_EDITING_NOT_SUPPORTED, + IVAS_ERR_OBJECTS_EDITING_AND_PANNING_NOT_SUPPORTED, + IVAS_ERR_INVALID_HRTF, + IVAS_ERR_INVALID_HRTF_SAMPLING_RATE, + IVAS_ERR_BINARY_FILE_WITHOUT_BINAURAL_RENDERER_DATA, + IVAS_ERR_INVALID_INPUT_FORMAT, + IVAS_ERR_INVALID_INDEX, + IVAS_ERR_NOT_SUPPORTED_OPTION, + IVAS_ERR_NOT_IMPLEMENTED, + IVAS_ERR_WAITING_FOR_BITSTREAM, + IVAS_ERR_ISM_FILE_READER_INVALID_METADATA_FORMAT, + IVAS_ERR_ISM_INVALID_METADATA_VALUE, + IVAS_ERR_INVALID_MASA_FORMAT_METADATA_FILE, + IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, + IVAS_ERR_TSM_NOT_ENABLED, + IVAS_ERR_FETCH_SIZE_NO_MULTIPLE_OF_5MS, +#ifdef DEBUGGING + IVAS_ERR_INVALID_FORCE_MODE, +#ifdef DEBUG_AGC_ENCODER_CMD_OPTION + IVAS_ERR_INVALID_AGC, +#endif +#ifdef VARIABLE_SPEED_DECODING + IVAS_ERR_VS_FRAME_NEEDED, +#endif +#endif + + /*----------------------------------------* + * input data errors * + *----------------------------------------*/ + IVAS_ERR_INVALID_BITSTREAM = 0x2000, + IVAS_ERR_UNEXPECTED_LC3PLUS_BITSTREAM, + IVAS_ERR_UNEXPECTED_LC3PLUS_BITSTREAM_CONFIG, + + /*----------------------------------------* + * hardware errors * + *----------------------------------------*/ + IVAS_ERR_FAILED_ALLOC = 0x3000, + + /*----------------------------------------* + * internal errors * + *----------------------------------------*/ + IVAS_ERR_INTERNAL = 0x4000, + IVAS_ERR_INTERNAL_FATAL, + + /*----------------------------------------* + * file I/O errors (lib_util only) * + *----------------------------------------*/ + IVAS_ERR_FAILED_FILE_OPEN = 0x5000, + IVAS_ERR_FAILED_FILE_WRITE, + IVAS_ERR_FAILED_FILE_READ, + IVAS_ERR_FAILED_FILE_PARSE, + IVAS_ERR_END_OF_FILE, + IVAS_ERR_BITSTREAM_WRITER_INVALID_FORMAT, + IVAS_ERR_BITSTREAM_READER_INVALID_DATA, + IVAS_ERR_BITSTREAM_READER_INVALID_FORMAT, + IVAS_ERR_NO_FILE_OPEN, + IVAS_ERR_SAMPLING_RATE_UNKNOWN, + IVAS_ERR_EXTERNAL_ORIENTATION_INVALID_FORMAT, + + /*----------------------------------------* + * renderer (lib_rend only) * + *----------------------------------------*/ + IVAS_ERR_NUM_CHANNELS_UNKNOWN = 0x6000, + IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT, + IVAS_ERR_INVALID_INPUT_ID, + IVAS_ERR_WRONG_NUM_CHANNELS, + IVAS_ERR_INVALID_BUFFER_SIZE, + IVAS_ERR_INVALID_RENDER_CONFIG, + IVAS_ERR_ACOUSTIC_ENVIRONMENT_MISSING, + IVAS_ERR_INVALID_ER_PARAM, + IVAS_ERR_DIRECTIVITY_PATTERN_ID_MISSING, + IVAS_ERR_LC3PLUS_INVALID_BITRATE, + IVAS_ERR_INVALID_SPLIT_REND_CONFIG, + + /*----------------------------------------* + * unknown error * + *----------------------------------------*/ + IVAS_ERR_UNKNOWN = 0xF000, /* fallback error code */ + +} ivas_error; + + + +// Structs + +typedef struct ivas_MASA_spherical_grid_deindexing +{ + float theta_cb[NO_THETA16_MAX]; + int16_t no_theta; + int16_t no_phi[NO_THETA16_MAX]; + +} SPHERICAL_GRID_DATA; + +typedef struct ivas_masa_descriptive_meta_struct +{ + uint8_t formatDescriptor[8]; /* 8x 8 bits */ + uint8_t numberOfDirections; /* 1 bit */ + uint8_t numberOfChannels; /* 1 bit */ + uint8_t sourceFormat; /* 2 bits */ + uint8_t transportDefinition; /* 3 bits */ + uint8_t channelAngle; /* 3 bits */ + uint8_t channelDistance; /* 6 bits */ + uint8_t channelLayout; /* 3 bits, used only when sourceFormat == bit value 10 */ + +} MASA_DECRIPTIVE_META; + +typedef struct ivas_masa_directional_spatial_meta_struct +{ + float azimuth[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + float elevation[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + float energy_ratio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + uint8_t energy_ratio_uint8[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + float spread_coherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + uint8_t spread_coherence_uint8[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + uint16_t spherical_index[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + +} MASA_DIRECTIONAL_SPATIAL_META; + +typedef struct ivas_masa_common_spatial_meta_struct +{ + float diffuse_to_total_ratio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + uint8_t diffuse_to_total_ratio_uint8[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + float surround_coherence[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + uint8_t surround_coherence_uint8[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + float remainder_to_total_ratio[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + uint8_t remainder_to_total_ratio_uint8[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + +} MASA_COMMON_SPATIAL_META; + +typedef struct ivas_omasa_meta_struct +{ + uint8_t num_dirs; + MASA_DIRECTIONAL_SPATIAL_META directional_meta[MASA_MAXIMUM_DIRECTIONS]; + MASA_COMMON_SPATIAL_META common_meta; + +} OMASA_SPATIAL_META, *OMASA_SPATIAL_META_HANDLE; + +typedef struct ivas_masa_metadata_frame_struct +{ + MASA_DECRIPTIVE_META descriptive_meta; + MASA_DIRECTIONAL_SPATIAL_META directional_meta[MASA_MAXIMUM_DIRECTIONS]; + MASA_COMMON_SPATIAL_META common_meta; + +} MASA_METADATA_FRAME, *MASA_METADATA_HANDLE; +typedef struct ivas_masa_metadata_frame_struct *IVAS_MASA_METADATA_HANDLE; + + +// Function prototypes + +void generate_gridEq( + SPHERICAL_GRID_DATA *data /* o : data structure for grid */ +); + + +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 */ +); + + +#endif // MASACONFORMANCETOOL_IVASPARTS_H diff --git a/scripts/ivas_conformance/masa-diff-tool/masaDiffTool.c b/scripts/ivas_conformance/masa-diff-tool/masaDiffTool.c new file mode 100644 index 0000000000000000000000000000000000000000..2a78da1146f6e62bfa085851e37710ddfb09e71f --- /dev/null +++ b/scripts/ivas_conformance/masa-diff-tool/masaDiffTool.c @@ -0,0 +1,823 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "ivasParts.h" +#include "masa_file_reader.h" + +// Local constants + +// Local structures + +typedef struct +{ + long frame; + + MasaFileReader *refReader; + MasaFileReader *cutReader; + FILE *reportFilePtr; + FILE *csvFilePtr; + + int isDiff_overall; + int isDiff_overall_spatialMeta; + int isDiff_overall_descriptiveMeta; + + long numberOfDiffFrames; + + float maxAbsDiffDirection_overall; + float maxAbsDiffDirRatio_overall; + float maxAbsDiffDiffRatio_overall; + float maxAbsDiffRemRatio_overall; + float maxAbsDiffSpreadCoh_overall; + float maxAbsDiffSurCoh_overall; + + float sumAbsDiffDirection; + float sumAbsDiffDirRatio; + float sumAbsDiffDiffRatio; + float sumAbsDiffRemRatio; + float sumAbsDiffSpreadCoh; + float sumAbsDiffSurCoh; + + long sumAbsDiffDirectionValueCount; + long sumAbsDiffDirRatioValueCount; + long sumAbsDiffDiffRatioValueCount; + long sumAbsDiffRemRatioValueCount; + long sumAbsDiffSpreadCohValueCount; + long sumAbsDiffSurCohValueCount; + +} MasaDiffToolState; + + +// Local function prototypes +static void openMasaDiffToolState( MasaDiffToolState *state ); +static void closeMasaDiffToolState( MasaDiffToolState *state ); + +static int compareMasaFrameDescriptiveMeta( const MasaDiffToolState *state ); +static int compareMasaFrameSpatialMeta( MasaDiffToolState *state, int isDiff_frame_descriptiveMeta ); + +static float getMaxAbsDiffSpatialAngle( float refAzi, float refEle, float cutAzi, float cutEle ); +static float getMaxAbsDiffRatio( float ref[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + float cut[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + uint8_t refInt[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + uint8_t cutInt[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + int *isDiff, + float *diffSum, + long *valueCount ); + +static void printSummary( const MasaDiffToolState *state ); + +static void writeCsvHeader( FILE *csvFilePtr ); +static void writeCsvLine( + FILE *csvFilePtr, + long frameIndex, + int isDiffDescriptiveMetadata, + int isDiffNumDir, + float maxAbsDiffDirection, + float meanAbsDiffDirection, + float maxAbsDiffDirRatio, + float meanAbsDiffDirRatio, + float maxAbsDiffDiffRatio, + float meanAbsDiffDiffRatio, + float maxAbsDiffRemRatio, + float meanAbsDiffRemRatio, + float maxAbsDiffSpreadCoh, + float meanAbsDiffSpreadCoh, + float maxAbsDiffSurCoh, + float meanAbsDiffSurCoh ); + +static void printUsage(); + +// masaDiffTool [options] ref_file cut_file +int main( int argc, char *argv[] ) +{ + // Check correct number of command line arguments + if ( argc < 3 ) + { + printUsage(); + exit( EXIT_FAILURE ); + } + + MasaDiffToolState state = { 0 }; + openMasaDiffToolState( &state ); + + for ( int n = 0; n < argc - 2; ++n ) + { + if (strcmp(argv[n], "-h") == 0 || strcmp(argv[n], "--help") == 0) + { + printUsage(); + exit( EXIT_FAILURE ); // Will report non-zero so scripts do not succeed accidentally + } + + if (strcmp(argv[n], "--report") == 0) + { + state.reportFilePtr = fopen( argv[n+1], "wt" ); + if ( state.reportFilePtr == NULL ) + { + fprintf( stderr, "Failed to open output report file for writing\n" ); + fprintf( stderr, "Path was: %s\n", argv[n+1] ); + exit( EXIT_FAILURE ); + } + } + + if (strcmp(argv[n], "--csv") == 0) + { + state.csvFilePtr = fopen( argv[n+1], "wt" ); + if ( state.csvFilePtr == NULL ) + { + fprintf( stderr, "Failed to open output CSV file for writing\n" ); + fprintf( stderr, "Path was: %s\n", argv[n+1] ); + exit( EXIT_FAILURE ); + } + } + } + + state.refReader = MasaFileReader_open( argv[argc-2] ); + if ( state.refReader == NULL ) + { + fprintf( stderr, "Failed to open ref file for reading\n" ); + exit( EXIT_FAILURE ); + } + + state.cutReader = MasaFileReader_open( argv[argc-1] ); + if ( state.cutReader == NULL ) + { + fprintf( stderr, "Failed to open cut file for reading\n" ); + exit( EXIT_FAILURE ); + } + + if (state.csvFilePtr != NULL) + { + writeCsvHeader( state.csvFilePtr ); + } + + // Main processing loop + ivas_error errorRef = IVAS_ERR_OK; + ivas_error errorCut = IVAS_ERR_OK; + ivas_error errorOverall = IVAS_ERR_OK; + while ( errorRef == IVAS_ERR_OK && errorCut == IVAS_ERR_OK ) + { + int isDiff_frame_overall = 0; + int isDiff_frame_spatialMeta = 0; + int isDiff_frame_descriptiveMeta = 0; + + errorRef = MasaFileReader_readNextFrame( state.refReader ); + errorCut = MasaFileReader_readNextFrame( state.cutReader ); + + if ( errorRef == IVAS_ERR_FAILED_FILE_READ && errorCut == IVAS_ERR_FAILED_FILE_READ ) + { + break; // Simple end of file condition. Could be improved. + } + + if ( errorRef == IVAS_ERR_FAILED_FILE_READ ) + { + errorOverall = errorRef; + fprintf( stderr, "Error in reading ref metadata. Possible early end of file.\n" ); + break; + } + + if ( errorCut == IVAS_ERR_FAILED_FILE_READ ) + { + errorOverall = errorCut; + fprintf( stderr, "Error in reading cut metadata. Possible early end of file.\n" ); + break; + } + + if ( errorRef == IVAS_ERR_INVALID_MASA_FORMAT_METADATA_FILE ) + { + errorOverall = errorRef; + fprintf( stderr, "Error, ref metadata format descriptor is not IVASMASA. Cannot compare further.\n" ); + break; + } + + if ( errorCut == IVAS_ERR_INVALID_MASA_FORMAT_METADATA_FILE ) + { + errorOverall = errorCut; + fprintf( stderr, "Error, cut metadata format descriptor is not IVASMASA. Cannot compare further.\n" ); + break; + } + + if (state.reportFilePtr != NULL) + { + fprintf( state.reportFilePtr, "Frame %d\n-----------\n", state.frame ); + } + + MASA_METADATA_HANDLE refMetadata = MasaFileReader_getMetadataHandle( state.refReader ); + MASA_METADATA_HANDLE cutMetadata = MasaFileReader_getMetadataHandle( state.cutReader ); + + isDiff_frame_descriptiveMeta = compareMasaFrameDescriptiveMeta( &state ); + + // If there is difference in number of directions, then we do not compare metadata + if ( isDiff_frame_descriptiveMeta && refMetadata->descriptive_meta.numberOfDirections != cutMetadata->descriptive_meta.numberOfDirections ) + { + isDiff_frame_spatialMeta = 1; + if (state.reportFilePtr != NULL) + { + fprintf( state.reportFilePtr, "Difference in spatial metadata, number of directions differ\n" ); + } + if ( state.csvFilePtr != NULL ) + { + writeCsvLine( state.csvFilePtr, + state.frame, + isDiff_frame_descriptiveMeta, + 1, // Always true here + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f ); + } + } + else + { + isDiff_frame_spatialMeta = compareMasaFrameSpatialMeta( &state, isDiff_frame_descriptiveMeta ); + } + + isDiff_frame_overall = isDiff_frame_descriptiveMeta || isDiff_frame_spatialMeta; + + if ( !isDiff_frame_overall ) + { + if (state.reportFilePtr != NULL) + { + fprintf( state.reportFilePtr, "Metadata is identical\n" ); + } + } + if (state.reportFilePtr != NULL) + { + fprintf( state.reportFilePtr, "\n" ); + } + + // Update overall diff states states + state.isDiff_overall_descriptiveMeta = state.isDiff_overall_descriptiveMeta || isDiff_frame_descriptiveMeta; + state.isDiff_overall_spatialMeta = state.isDiff_overall_spatialMeta || isDiff_frame_spatialMeta; + state.isDiff_overall = state.isDiff_overall || isDiff_frame_overall; + + // Update counters + if ( isDiff_frame_overall ) + { + state.numberOfDiffFrames++; + } + + state.frame++; + } + + if ( errorOverall == IVAS_ERR_OK ) + { + if ( state.isDiff_overall ) + { + errorOverall = 1; + } + printSummary( &state ); // Only print summary when no errors present. + } + + closeMasaDiffToolState( &state ); + + return errorOverall; +} + +static int compareMasaFrameDescriptiveMeta( const MasaDiffToolState *state ) +{ + int isDiff = 0; + + MASA_METADATA_HANDLE refMeta = MasaFileReader_getMetadataHandle( state->refReader ); + MASA_METADATA_HANDLE cutMeta = MasaFileReader_getMetadataHandle( state->cutReader ); + + for ( int n = 0; n < 8; n++ ) + { + if ( refMeta->descriptive_meta.formatDescriptor[n] != cutMeta->descriptive_meta.formatDescriptor[n] ) + { + if (state->reportFilePtr != NULL) + { + fprintf( state->reportFilePtr, "Difference in format descriptor: " ); + for ( int k = 0; k < 8; k++ ) + { + fprintf( state->reportFilePtr, "%c", refMeta->descriptive_meta.formatDescriptor[k] ); + } + fprintf( state->reportFilePtr, " != " ); + for ( int k = 0; k < 8; k++ ) + { + fprintf( state->reportFilePtr, "%c", cutMeta->descriptive_meta.formatDescriptor[k] ); + } + fprintf( state->reportFilePtr, "\n" ); + } + isDiff = 1; + break; + } + } + + if ( refMeta->descriptive_meta.numberOfDirections != cutMeta->descriptive_meta.numberOfDirections ) + { + if (state->reportFilePtr != NULL) + { + fprintf( state->reportFilePtr, "Difference in number of directions: %u != %u", refMeta->descriptive_meta.numberOfDirections, cutMeta->descriptive_meta.numberOfDirections ); + } + isDiff = 1; + } + + if ( refMeta->descriptive_meta.sourceFormat != cutMeta->descriptive_meta.sourceFormat ) + { + if (state->reportFilePtr != NULL) + { + fprintf( state->reportFilePtr, "Difference in source format: %u != %u", refMeta->descriptive_meta.sourceFormat, cutMeta->descriptive_meta.sourceFormat ); + } + isDiff = 1; + } + + if ( refMeta->descriptive_meta.transportDefinition != cutMeta->descriptive_meta.transportDefinition ) + { + if (state->reportFilePtr != NULL) + { + fprintf( state->reportFilePtr, "Difference in transport definition: %u != %u", refMeta->descriptive_meta.transportDefinition, cutMeta->descriptive_meta.transportDefinition ); + } + isDiff = 1; + } + + if ( refMeta->descriptive_meta.channelAngle != cutMeta->descriptive_meta.channelAngle ) + { + if (state->reportFilePtr != NULL) + { + fprintf( state->reportFilePtr, "Difference in channel angle: %u != %u", refMeta->descriptive_meta.channelAngle, cutMeta->descriptive_meta.channelAngle ); + } + isDiff = 1; + } + + if ( refMeta->descriptive_meta.channelDistance != cutMeta->descriptive_meta.channelDistance ) + { + if (state->reportFilePtr != NULL) + { + fprintf( state->reportFilePtr, "Difference in channel distance: %u != %u", refMeta->descriptive_meta.channelDistance, cutMeta->descriptive_meta.channelDistance ); + } + isDiff = 1; + } + + if ( refMeta->descriptive_meta.channelLayout != cutMeta->descriptive_meta.channelLayout ) + { + if (state->reportFilePtr != NULL) + { + fprintf( state->reportFilePtr, "Difference in channel layout: %u != %u", refMeta->descriptive_meta.channelLayout, cutMeta->descriptive_meta.channelLayout ); + } + isDiff = 1; + } + + return isDiff; +} + +static int compareMasaFrameSpatialMeta( MasaDiffToolState *state, const int isDiff_frame_descriptiveMeta ) +{ + int isDiff = 0; + + float temp1, temp2; + + MASA_METADATA_HANDLE refMeta = MasaFileReader_getMetadataHandle( state->refReader ); + MASA_METADATA_HANDLE cutMeta = MasaFileReader_getMetadataHandle( state->cutReader ); + + // Spatial direction + float maxAbsDiffDirection = 0.0f; + float sumAbsDiffDirection = 0.0f; + long sumAbsDiffDirectionValueCount = 0; + for ( int dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ ) + { + for ( int sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ ) + { + for ( int band = 0; band < MASA_FREQUENCY_BANDS; band++ ) + { + if ( refMeta->directional_meta[dir].spherical_index[sf][band] != cutMeta->directional_meta[dir].spherical_index[sf][band] ) + { + isDiff = 1; + float temp = getMaxAbsDiffSpatialAngle( refMeta->directional_meta[dir].azimuth[sf][band], + refMeta->directional_meta[dir].elevation[sf][band], + cutMeta->directional_meta[dir].azimuth[sf][band], + cutMeta->directional_meta[dir].elevation[sf][band] ); + maxAbsDiffDirection = temp > maxAbsDiffDirection ? temp : maxAbsDiffDirection; + sumAbsDiffDirection += temp; + } + sumAbsDiffDirectionValueCount++; + } + } + } + float meanAbsDiffDirection = sumAbsDiffDirection / (float) sumAbsDiffDirectionValueCount; + + // Direct-to-total ratio + float sumAbsDiffDirRatio = 0.0f; + long sumAbsDiffDirRatioValueCount = 0; + temp1 = getMaxAbsDiffRatio( refMeta->directional_meta[0].energy_ratio, + cutMeta->directional_meta[0].energy_ratio, + refMeta->directional_meta[0].energy_ratio_uint8, + cutMeta->directional_meta[0].energy_ratio_uint8, + &isDiff, &sumAbsDiffDirRatio, &sumAbsDiffDirRatioValueCount ); + temp2 = getMaxAbsDiffRatio( refMeta->directional_meta[1].energy_ratio, + cutMeta->directional_meta[1].energy_ratio, + refMeta->directional_meta[1].energy_ratio_uint8, + cutMeta->directional_meta[1].energy_ratio_uint8, + &isDiff, &sumAbsDiffDirRatio, &sumAbsDiffDirRatioValueCount ); + float maxAbsDiffDirRatio = temp1 > temp2 ? temp1 : temp2; + const float meanAbsDiffDirRatio = sumAbsDiffDirRatio / (float) sumAbsDiffDirRatioValueCount; + + // Spread coherence + float sumAbsDiffSpreadCoh = 0.0f; + long sumAbsDiffSpreadCohValueCount = 0; + temp1 = getMaxAbsDiffRatio( refMeta->directional_meta[0].spread_coherence, + cutMeta->directional_meta[0].spread_coherence, + refMeta->directional_meta[0].spread_coherence_uint8, + cutMeta->directional_meta[0].spread_coherence_uint8, + &isDiff, &sumAbsDiffSpreadCoh, &sumAbsDiffSpreadCohValueCount ); + temp2 = getMaxAbsDiffRatio( refMeta->directional_meta[1].spread_coherence, + cutMeta->directional_meta[1].spread_coherence, + refMeta->directional_meta[1].spread_coherence_uint8, + cutMeta->directional_meta[1].spread_coherence_uint8, + &isDiff, &sumAbsDiffSpreadCoh, &sumAbsDiffSpreadCohValueCount ); + float maxAbsDiffSpreadCoh = temp1 > temp2 ? temp1 : temp2; + const float meanAbsDiffSpreadCoh = sumAbsDiffSpreadCoh / (float) sumAbsDiffSpreadCohValueCount; + + // Diffuse-to-total ratio + float sumAbsDiffDiffRatio = 0.0f; + long sumAbsDiffDiffRatioValueCount = 0; + float maxAbsDiffDiffRatio = getMaxAbsDiffRatio( refMeta->common_meta.diffuse_to_total_ratio, + cutMeta->common_meta.diffuse_to_total_ratio, + refMeta->common_meta.diffuse_to_total_ratio_uint8, + cutMeta->common_meta.diffuse_to_total_ratio_uint8, + &isDiff, &sumAbsDiffDiffRatio, &sumAbsDiffDiffRatioValueCount ); + const float meanAbsDiffDiffRatio = sumAbsDiffDiffRatio / (float) sumAbsDiffDiffRatioValueCount; + + // Remainder-to-total ratio + float sumAbsDiffRemRatio = 0.0f; + long sumAbsDiffRemRatioValueCount = 0; + float maxAbsDiffRemRatio = getMaxAbsDiffRatio( refMeta->common_meta.remainder_to_total_ratio, + cutMeta->common_meta.remainder_to_total_ratio, + refMeta->common_meta.remainder_to_total_ratio_uint8, + cutMeta->common_meta.remainder_to_total_ratio_uint8, &isDiff, &sumAbsDiffRemRatio, &sumAbsDiffRemRatioValueCount ); + const float meanAbsDiffRemRatio = sumAbsDiffRemRatio / (float) sumAbsDiffRemRatioValueCount; + + // Surround coherence + float sumAbsDiffSurCoh = 0.0f; + long sumAbsDiffSurCohValueCount = 0; + float maxAbsDiffSurCoh = getMaxAbsDiffRatio( refMeta->common_meta.surround_coherence, + cutMeta->common_meta.surround_coherence, + refMeta->common_meta.surround_coherence_uint8, + cutMeta->common_meta.surround_coherence_uint8, &isDiff, &sumAbsDiffSurCoh, &sumAbsDiffSurCohValueCount ); + const float meanAbsDiffSurCoh = sumAbsDiffSurCoh / (float) sumAbsDiffSurCohValueCount; + + // Update mean tables (always so we get real mean) + state->sumAbsDiffDirection += sumAbsDiffDirection; + state->sumAbsDiffDirectionValueCount += sumAbsDiffDirectionValueCount; + state->sumAbsDiffDirRatio += sumAbsDiffDirRatio; + state->sumAbsDiffDirRatioValueCount += sumAbsDiffDirRatioValueCount; + state->sumAbsDiffDiffRatio += sumAbsDiffDiffRatio; + state->sumAbsDiffDiffRatioValueCount += sumAbsDiffDiffRatioValueCount; + state->sumAbsDiffRemRatio += sumAbsDiffRemRatio; + state->sumAbsDiffRemRatioValueCount += sumAbsDiffRemRatioValueCount; + state->sumAbsDiffSpreadCoh += sumAbsDiffSpreadCoh; + state->sumAbsDiffSpreadCohValueCount += sumAbsDiffSpreadCohValueCount; + state->sumAbsDiffSurCoh += sumAbsDiffSurCoh; + state->sumAbsDiffSurCohValueCount += sumAbsDiffSurCohValueCount; + + + if ( isDiff ) + { + if (state->reportFilePtr != NULL) + { + fprintf( state->reportFilePtr, "Difference in spatial metadata\n" ); + fprintf( state->reportFilePtr, "Max ABS diff in spatial direction (degrees): %f\n", maxAbsDiffDirection ); + fprintf( state->reportFilePtr, "Mean ABS diff in spatial direction (degrees): %f\n", meanAbsDiffDirection ); + fprintf( state->reportFilePtr, "Max ABS diff in direct-to-total ratio: %f\n", maxAbsDiffDirRatio ); + fprintf( state->reportFilePtr, "Mean ABS diff in direct-to-total ratio: %f\n", meanAbsDiffDirRatio ); + fprintf( state->reportFilePtr, "Max ABS diff in diffuse-to-total ratio: %f\n", maxAbsDiffDiffRatio ); + fprintf( state->reportFilePtr, "Mean ABS diff in diffuse-to-total ratio: %f\n", meanAbsDiffDiffRatio ); + fprintf( state->reportFilePtr, "Max ABS diff in remainder-to-total ratio: %f\n", maxAbsDiffRemRatio ); + fprintf( state->reportFilePtr, "Mean ABS diff in remainder-to-total ratio: %f\n", meanAbsDiffRemRatio ); + fprintf( state->reportFilePtr, "Max ABS diff in spread coherence: %f\n", maxAbsDiffSpreadCoh ); + fprintf( state->reportFilePtr, "Mean ABS diff in spread coherence: %f\n", meanAbsDiffSpreadCoh ); + fprintf( state->reportFilePtr, "Max ABS diff in surround coherence: %f\n", maxAbsDiffSurCoh ); + fprintf( state->reportFilePtr, "Mean ABS diff in surround coherence: %f\n", meanAbsDiffSurCoh ); + } + + state->maxAbsDiffDirection_overall = maxAbsDiffDirection > state->maxAbsDiffDirection_overall ? maxAbsDiffDirection : state->maxAbsDiffDirection_overall; + state->maxAbsDiffDirRatio_overall = maxAbsDiffDirRatio > state->maxAbsDiffDirRatio_overall ? maxAbsDiffDirRatio : state->maxAbsDiffDirRatio_overall; + state->maxAbsDiffDiffRatio_overall = maxAbsDiffDiffRatio > state->maxAbsDiffDiffRatio_overall ? maxAbsDiffDiffRatio : state->maxAbsDiffDiffRatio_overall; + state->maxAbsDiffRemRatio_overall = maxAbsDiffRemRatio > state->maxAbsDiffRemRatio_overall ? maxAbsDiffRemRatio : state->maxAbsDiffRemRatio_overall; + state->maxAbsDiffSpreadCoh_overall = maxAbsDiffSpreadCoh > state->maxAbsDiffSpreadCoh_overall ? maxAbsDiffSpreadCoh : state->maxAbsDiffSpreadCoh_overall; + state->maxAbsDiffSurCoh_overall = maxAbsDiffSurCoh > state->maxAbsDiffSurCoh_overall ? maxAbsDiffSurCoh : state->maxAbsDiffSurCoh_overall; + } + + if ( state->csvFilePtr != NULL ) + { + writeCsvLine( state->csvFilePtr, + state->frame, + isDiff_frame_descriptiveMeta, + 0, // Always identical in this function + maxAbsDiffDirection, + meanAbsDiffDirection, + maxAbsDiffDirRatio, + meanAbsDiffDirRatio, + maxAbsDiffDiffRatio, + meanAbsDiffDiffRatio, + maxAbsDiffRemRatio, + meanAbsDiffRemRatio, + maxAbsDiffSpreadCoh, + meanAbsDiffSpreadCoh, + maxAbsDiffSurCoh, + meanAbsDiffSurCoh ); + } + + return isDiff; +} + +static void sphToCart( const float azi, const float ele, float *x, float *y, float *z ) +{ + float aziRad = azi * EVS_PI / 180.0f; + float eleRad = ele * EVS_PI / 180.0f; + + *x = cosf( eleRad ) * cosf( aziRad ); + *y = cosf( eleRad ) * sinf( aziRad ); + *z = sinf( eleRad ); +} + + +static float getMaxAbsDiffSpatialAngle( const float refAzi, const float refEle, const float cutAzi, const float cutEle ) +{ + float x1, y1, z1, x2, y2, z2; + + sphToCart( refAzi, refEle, &x1, &y1, &z1 ); + sphToCart( cutAzi, cutEle, &x2, &y2, &z2 ); + + float dotp = x1 * x2 + y1 * y2 + z1 * z2; + + if ( dotp > 1.0f ) + { + dotp = 1.0f; + } + if ( dotp < -1.0f ) + { + dotp = -1.0f; + } + + return fabsf( acosf( dotp ) * 180.0f / EVS_PI ); +} + +static float getMaxAbsDiffRatio( float ref[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + float cut[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + uint8_t refInt[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + uint8_t cutInt[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS], + int *isDiff, + float *diffSum, + long *valueCount ) +{ + float maxAbsDiff = 0.0f; + + for ( int sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ ) + { + for ( int band = 0; band < MASA_FREQUENCY_BANDS; band++ ) + { + if ( refInt[sf][band] != cutInt[sf][band] ) + { + float temp = fabsf( ref[sf][band] - cut[sf][band] ); + maxAbsDiff = temp > maxAbsDiff ? temp : maxAbsDiff; + *diffSum += temp; + *isDiff = 1; + } + } + } + *valueCount += MAX_PARAM_SPATIAL_SUBFRAMES * MASA_FREQUENCY_BANDS; + + return maxAbsDiff; +} + + +static void openMasaDiffToolState( MasaDiffToolState *state ) +{ + state->frame = 0; + + state->refReader = NULL; + state->cutReader = NULL; + state->reportFilePtr = NULL; + state->csvFilePtr = NULL; + + state->isDiff_overall = 0; + state->isDiff_overall_spatialMeta = 0; + state->isDiff_overall_descriptiveMeta = 0; + + state->numberOfDiffFrames = 0L; + + state->maxAbsDiffDirection_overall = 0.0f; + state->maxAbsDiffDirRatio_overall = 0.0f; + state->maxAbsDiffDiffRatio_overall = 0.0f; + state->maxAbsDiffRemRatio_overall = 0.0f; + state->maxAbsDiffSpreadCoh_overall = 0.0f; + state->maxAbsDiffSurCoh_overall = 0.0f; + + state->sumAbsDiffDirection = 0.0f; + state->sumAbsDiffDirRatio = 0.0f; + state->sumAbsDiffDiffRatio = 0.0f; + state->sumAbsDiffRemRatio = 0.0f; + state->sumAbsDiffSpreadCoh = 0.0f; + state->sumAbsDiffSurCoh = 0.0f; + + state->sumAbsDiffDirectionValueCount = 0L; + state->sumAbsDiffDirRatioValueCount = 0L; + state->sumAbsDiffDiffRatioValueCount = 0L; + state->sumAbsDiffRemRatioValueCount = 0L; + state->sumAbsDiffSpreadCohValueCount = 0L; + state->sumAbsDiffSurCohValueCount = 0L; +} + + +static void closeMasaDiffToolState( MasaDiffToolState *state ) +{ + MasaFileReader_close( &state->refReader ); + MasaFileReader_close( &state->cutReader ); + if ( state->reportFilePtr != NULL ) + { + fclose( state->reportFilePtr ); + } + if ( state->csvFilePtr != NULL ) + { + fclose( state->csvFilePtr ); + } +} + + +static void printUsage() +{ + printf( "\n" ); + printf( "MASA diff tool for IVAS conformance\n\n" ); + printf( "Usage: masaDiffTool [options] refMetaFile cutMetaFile\n" ); + printf( "Options:\n" ); + printf( "--report , produces frame-by-frame results in text format\n" ); + printf( "--csv , produces most useful frame-by-frame results in csv format with header row and comma separation\n" ); + printf( "\n" ); + printf( "Check README.md for more information.\n\n" ); +} + + +static void writeCsvHeader( FILE *csvFilePtr ) +{ + if ( csvFilePtr == NULL ) + { + fprintf( stderr, "Fatal error: CSV writer not open.\n" ); + exit( EXIT_FAILURE ); + } + + fprintf( csvFilePtr, "Frame index" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Diff in descriptive metadata" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Diff in number of directions" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Max ABS diff: Direction (degrees spatial angle)" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Mean ABS diff: Direction (degrees spatial angle)" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Max ABS diff: Direct-to-total ratio" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Mean ABS diff: Direct-to-total ratio" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Max ABS diff: Diffuse-to-total ratio" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Mean ABS diff: Diffuse-to-total ratio" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Max ABS diff: Remainder-to-total ratio" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Mean ABS diff: Remainder-to-total ratio" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Max ABS diff: Spread coherence" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Mean ABS diff: Spread coherence" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Max ABS diff: Surround coherence" ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "Mean ABS diff: Surround coherence" ); + fprintf( csvFilePtr, "\n" ); +} + +static void writeCsvLine( + FILE *csvFilePtr, + long frameIndex, + int isDiffDescriptiveMetadata, + int isDiffNumDir, + float maxAbsDiffDirection, + float meanAbsDiffDirection, + float maxAbsDiffDirRatio, + float meanAbsDiffDirRatio, + float maxAbsDiffDiffRatio, + float meanAbsDiffDiffRatio, + float maxAbsDiffRemRatio, + float meanAbsDiffRemRatio, + float maxAbsDiffSpreadCoh, + float meanAbsDiffSpreadCoh, + float maxAbsDiffSurCoh, + float meanAbsDiffSurCoh ) +{ + if ( csvFilePtr == NULL ) + { + fprintf( stderr, "Fatal error: CSV writer not open.\n" ); + exit( EXIT_FAILURE ); + } + + fprintf( csvFilePtr, "%ld", frameIndex ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%d", isDiffDescriptiveMetadata ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%d", isDiffNumDir ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%3.2f", maxAbsDiffDirection ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%3.2f", meanAbsDiffDirection ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", maxAbsDiffDirRatio ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", meanAbsDiffDirRatio ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", maxAbsDiffDiffRatio ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", meanAbsDiffDiffRatio ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", maxAbsDiffRemRatio ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", meanAbsDiffRemRatio ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", maxAbsDiffSpreadCoh ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", meanAbsDiffSpreadCoh ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", maxAbsDiffSurCoh ); + fprintf( csvFilePtr, "," ); + fprintf( csvFilePtr, "%1.4f", meanAbsDiffSurCoh ); + fprintf( csvFilePtr, "\n" ); +} + +static void printSummary( const MasaDiffToolState *state ) +{ + if ( !state->isDiff_overall ) + { + fprintf( stdout, "Metadata files are identical.\n" ); + return; + } + + fprintf( stdout, "Metadata files differ.\n" ); + fprintf( stdout, "Total number of differing frames : %ld\n", state->numberOfDiffFrames ); + + if ( state->isDiff_overall_descriptiveMeta ) + { + fprintf( stdout, "Descriptive metadata is different.\n" ); + } + + if ( state->isDiff_overall_spatialMeta ) + { + fprintf( stdout, "Spatial metadata is different.\n" ); + fprintf( stdout, "Overall max ABS diff in spatial direction (degrees): %3.2f\n", state->maxAbsDiffDirection_overall ); + fprintf( stdout, "Overall mean ABS diff in spatial direction (degrees): %3.2f\n", state->sumAbsDiffDirection / (float) state->sumAbsDiffDirectionValueCount ); + fprintf( stdout, "Overall max ABS diff in direct-to-total ratio: %1.4f\n", state->maxAbsDiffDirRatio_overall ); + fprintf( stdout, "Overall mean ABS diff in direct-to-total ratio: %1.4f\n", state->sumAbsDiffDirRatio / (float) state->sumAbsDiffDirRatioValueCount ); + fprintf( stdout, "Overall max ABS diff in diffuse-to-total ratio: %1.4f\n", state->maxAbsDiffDiffRatio_overall ); + fprintf( stdout, "Overall mean ABS diff in diffuse-to-total ratio: %1.4f\n", state->sumAbsDiffDiffRatio / (float) state->sumAbsDiffDiffRatioValueCount ); + fprintf( stdout, "Overall max ABS diff in remainder-to-total ratio: %1.4f\n", state->maxAbsDiffRemRatio_overall ); + fprintf( stdout, "Overall mean ABS diff in remainder-to-total ratio: %1.4f\n", state->sumAbsDiffRemRatio / (float) state->sumAbsDiffRemRatioValueCount ); + fprintf( stdout, "Overall max ABS diff in spread coherence ratio: %1.4f\n", state->maxAbsDiffSpreadCoh_overall ); + fprintf( stdout, "Overall mean ABS diff in spread coherence ratio: %1.4f\n", state->sumAbsDiffSpreadCoh / (float) state->sumAbsDiffSpreadCohValueCount ); + fprintf( stdout, "Overall max ABS diff in surround coherence ratio: %1.4f\n", state->maxAbsDiffSurCoh_overall ); + fprintf( stdout, "Overall mean ABS diff in surround coherence ratio: %1.4f\n", state->sumAbsDiffSurCoh / (float) state->sumAbsDiffSurCohValueCount ); + } + + fprintf( stdout, "\n" ); +} diff --git a/scripts/ivas_conformance/masa-diff-tool/masa_file_reader.c b/scripts/ivas_conformance/masa-diff-tool/masa_file_reader.c new file mode 100644 index 0000000000000000000000000000000000000000..f80af06e87042182b6892c7b94faa6672f41bd7a --- /dev/null +++ b/scripts/ivas_conformance/masa-diff-tool/masa_file_reader.c @@ -0,0 +1,291 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/****************************************************************************************************** + This file is adapted from IVAS source code files to support the specific task of this diff tool. + The sources for this file are: + - lib_util/masa_file_reader.c + - lib_com/ivas_rom_com.c +*******************************************************************************************************/ + +#include +#include +#include + +#include "masa_file_reader.h" + +// Local definition +const uint8_t ivasmasaFormatDescriptor[8] = +{ + 0x49, 0x56, 0x41, 0x53, 0x4D, 0x41, 0x53, 0x41 /* "IVASMASA" */ +}; + + +struct MasaFileReader +{ + FILE *file; + MASA_METADATA_FRAME metadataFrame; + SPHERICAL_GRID_DATA sph_grid16; +}; + +/*------------------------------------------------------------------------- + * MasaFileReader_open() + * + * Allocate and open MasaFileReader handle + *------------------------------------------------------------------------*/ + +MasaFileReader *MasaFileReader_open( + const char *fileName /* i : path to MASA metadata file */ +) +{ + MasaFileReader *self; + FILE *file; + + if ( !fileName ) + { + return NULL; + } + + file = fopen( fileName, "rb" ); + + if ( !file ) + { + return NULL; + } + + self = calloc( 1, sizeof( MasaFileReader ) ); + self->file = file; + generate_gridEq( &self->sph_grid16 ); + + return self; +} + + +/*------------------------------------------------------------------------- + * MasaFileReader_getMetadataHandle() + * + * AGet MasaFileReader handle + *------------------------------------------------------------------------*/ + +IVAS_MASA_METADATA_HANDLE MasaFileReader_getMetadataHandle( + MasaFileReader *self /* i/o: MasaFileReader handle */ +) +{ + if ( self == NULL ) + { + return NULL; + } + + return &self->metadataFrame; +} + + +/*------------------------------------------------------------------------- + * MasaFileReader_readNextFrame() + * + * Read MASA data + *------------------------------------------------------------------------*/ + +ivas_error MasaFileReader_readNextFrame( + MasaFileReader *self /* i/o: MasaFileReader handle */ +) +{ + if ( self == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + uint16_t twoByteBuffer = 0; + int16_t i, j, b; + IVAS_MASA_METADATA_HANDLE hMeta; + FILE *metafile; + uint16_t readIndex[MASA_FREQUENCY_BANDS]; + uint8_t readOther[MASA_FREQUENCY_BANDS]; + + hMeta = &self->metadataFrame; + metafile = self->file; + + /* Read version */ + if ( fread( &hMeta->descriptive_meta.formatDescriptor, sizeof( uint8_t ), 8, metafile ) != 8 ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + + for ( i = 0; i < 8; i++ ) + { + if ( hMeta->descriptive_meta.formatDescriptor[i] != ivasmasaFormatDescriptor[i] ) + { +#ifdef DEBUGGING + fprintf( stderr, "Input format is not IVASMASA\n" ); +#endif + return IVAS_ERR_INVALID_MASA_FORMAT_METADATA_FILE; + } + } + + /* Read combined descriptive meta */ + if ( fread( &twoByteBuffer, sizeof( uint16_t ), 1, metafile ) != 1 ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + + /* Extract rest of the descriptive meta from the two-byte value */ + hMeta->descriptive_meta.numberOfDirections = ( twoByteBuffer >> 15u ) & 0x1u; + hMeta->descriptive_meta.numberOfChannels = ( twoByteBuffer >> 14u ) & 0x1u; + hMeta->descriptive_meta.sourceFormat = ( twoByteBuffer >> 12u ) & 0x3u; + if ( hMeta->descriptive_meta.sourceFormat == 0x0 || hMeta->descriptive_meta.sourceFormat == 0x1 ) + { + hMeta->descriptive_meta.transportDefinition = ( twoByteBuffer >> 9u ) & 0x7u; + hMeta->descriptive_meta.channelAngle = ( twoByteBuffer >> 6u ) & 0x7u; + hMeta->descriptive_meta.channelDistance = twoByteBuffer & 0x3Fu; + hMeta->descriptive_meta.channelLayout = 0; /* Set to zero as unused */ + } + else if ( hMeta->descriptive_meta.sourceFormat == 0x2 ) + { + hMeta->descriptive_meta.channelLayout = ( twoByteBuffer >> 9u ) & 0x7u; + /* 9 LSB unused */ + hMeta->descriptive_meta.transportDefinition = 0; /* Set to zero as unused */ + hMeta->descriptive_meta.channelAngle = 0; /* Set to zero as unused */ + hMeta->descriptive_meta.channelDistance = 0; /* Set to zero as unused */ + } + else if ( hMeta->descriptive_meta.sourceFormat == 0x3 ) + { + hMeta->descriptive_meta.transportDefinition = ( twoByteBuffer >> 9u ) & 0x7u; + hMeta->descriptive_meta.channelAngle = ( twoByteBuffer >> 6u ) & 0x7u; + /* 6 LSB unused */ + hMeta->descriptive_meta.channelDistance = 0; /* Set to zero as unused */ + hMeta->descriptive_meta.channelLayout = 0; /* Set to zero as unused */ + } + + for ( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; ++j ) + { + /* Read directional spatial meta */ + for ( i = 0; i < hMeta->descriptive_meta.numberOfDirections + 1; ++i ) + { + /* Spherical index */ + if ( fread( readIndex, sizeof( uint16_t ), MASA_FREQUENCY_BANDS, metafile ) != MASA_FREQUENCY_BANDS ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + + 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] ) ); + hMeta->directional_meta[i].spherical_index[j][b] = readIndex[b]; + } + + /* Direct-to-total ratio */ + if ( fread( readOther, sizeof( uint8_t ), MASA_FREQUENCY_BANDS, metafile ) != MASA_FREQUENCY_BANDS ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + + for ( b = 0; b < MASA_FREQUENCY_BANDS; b++ ) + { + hMeta->directional_meta[i].energy_ratio_uint8[j][b] = readOther[b]; + hMeta->directional_meta[i].energy_ratio[j][b] = ( (float) readOther[b] ) / UINT8_MAX; + } + + /* Spread coherence */ + if ( fread( readOther, sizeof( uint8_t ), MASA_FREQUENCY_BANDS, metafile ) != MASA_FREQUENCY_BANDS ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + + for ( b = 0; b < MASA_FREQUENCY_BANDS; b++ ) + { + hMeta->directional_meta[i].spread_coherence_uint8[j][b] = readOther[b]; + hMeta->directional_meta[i].spread_coherence[j][b] = ( (float) readOther[b] ) / UINT8_MAX; + } + } + + /* Read common spatial meta */ + /* Diffuse-to-total ratio */ + if ( fread( readOther, sizeof( uint8_t ), MASA_FREQUENCY_BANDS, metafile ) != MASA_FREQUENCY_BANDS ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + + for ( b = 0; b < MASA_FREQUENCY_BANDS; b++ ) + { + hMeta->common_meta.diffuse_to_total_ratio_uint8[j][b] = readOther[b]; + hMeta->common_meta.diffuse_to_total_ratio[j][b] = ( (float) readOther[b] ) / UINT8_MAX; + } + + /* Surround coherence */ + if ( fread( readOther, sizeof( uint8_t ), MASA_FREQUENCY_BANDS, metafile ) != MASA_FREQUENCY_BANDS ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + + for ( b = 0; b < MASA_FREQUENCY_BANDS; b++ ) + { + hMeta->common_meta.surround_coherence_uint8[j][b] = readOther[b]; + hMeta->common_meta.surround_coherence[j][b] = ( (float) readOther[b] ) / UINT8_MAX; + } + + /* Remainder-to-total ratio */ + if ( fread( readOther, sizeof( uint8_t ), MASA_FREQUENCY_BANDS, metafile ) != MASA_FREQUENCY_BANDS ) + { + return IVAS_ERR_FAILED_FILE_READ; + } + + for ( b = 0; b < MASA_FREQUENCY_BANDS; b++ ) + { + hMeta->common_meta.remainder_to_total_ratio_uint8[j][b] = readOther[b]; + hMeta->common_meta.remainder_to_total_ratio[j][b] = ( (float) readOther[b] ) / UINT8_MAX; + } + } + + return IVAS_ERR_OK; +} + +/*------------------------------------------------------------------------- + * MasaFileReader_close() + * + * Close MasaFileReader + *------------------------------------------------------------------------*/ + +void MasaFileReader_close( + MasaFileReader **selfPtr /* i/o: pointer to MasaFileReader handle */ +) +{ + if ( selfPtr == NULL || *selfPtr == NULL ) + { + return; + } + + fclose( ( *selfPtr )->file ); + free( *selfPtr ); + *selfPtr = NULL; + + return; +} diff --git a/scripts/ivas_conformance/masa-diff-tool/masa_file_reader.h b/scripts/ivas_conformance/masa-diff-tool/masa_file_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..9493c061610a54f3e7d02f7cdbd29fe0d9047dc9 --- /dev/null +++ b/scripts/ivas_conformance/masa-diff-tool/masa_file_reader.h @@ -0,0 +1,89 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/****************************************************************************************************** + This file is adapted from IVAS source code files to support the specific task of this diff tool. + The sources for this file are: + - lib_util/masa_file_reader.h +*******************************************************************************************************/ + +#ifndef IVAS_MASA_FILE_READER_H +#define IVAS_MASA_FILE_READER_H + +#include "ivasParts.h" + + +struct MasaFileReader; +typedef struct MasaFileReader MasaFileReader; + + +/*! r: MasaFileReader handle */ +MasaFileReader *MasaFileReader_open( + const char *fileName /* i : path to MASA metadata file */ +); + +/*---------------------------------------------------------------------* + * MasaFileReader_getMetadataHandle() + * + * Returns a handle to an already allocated MASA metadata frame struct. + * Metadata for each frame is available through this handle after + * MasaFileReader_readNextFrame is called. + *---------------------------------------------------------------------*/ +/*! r: handle to MASA metadata */ +IVAS_MASA_METADATA_HANDLE MasaFileReader_getMetadataHandle( + MasaFileReader *self /* i/o: MasaFileReader handle */ +); + +/*---------------------------------------------------------------------* + * MasaFileReader_readNextFrame() + * + * Reads MASA metadata for one frame from the opened file into the internal + * MASA metadata frame struct. The metadata is available through the struct + * handle returned by MasaFileReader_getMetadataHandle(). + *---------------------------------------------------------------------*/ +/*! r: error code */ +ivas_error MasaFileReader_readNextFrame( + MasaFileReader *self /* i/o: MasaFileReader handle */ +); + +/*---------------------------------------------------------------------* + * MasaFileReader_close() + * + * Deallocate the MasaFileReader. This also includes the MASA metadata + * frame struct available through MasaFileReader_getMetadataHandle. + *---------------------------------------------------------------------*/ +void MasaFileReader_close( + MasaFileReader **selfPtr /* i/o: pointer to MasaFileReader handle */ +); + + +#endif /* IVAS_MASA_FILE_READER_H */