From 60781006c9f9c29311e60e48cd79b5b755e41218 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 11:56:46 +0100 Subject: [PATCH 01/30] unify --test-mode and --filter into --filter --- scripts/ivas_conformance/README.md | 86 ++++------------------ scripts/ivas_conformance/runConformance.py | 38 +++++++--- 2 files changed, 40 insertions(+), 84 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index d56974ef0..18ae5b25a 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -247,94 +247,34 @@ MLD Corridor passed for ISAR with max MLD diff of 0.0 ## Executing specific tests only -All CUT tests can be run specifically for IVAS Encoder,IVAS Decoder,IVAS Renderer, ISAR Encoder and ISAR Decoder only. The commandline allows for ```-test-mode=``` for this functionality, examples: +Use `--filter` to run or analyze a subset of tests. -- Run CUT IVAS Encoder Tests Only (on Target Platform) +- Tag selection is supported with comma-separated tags: `ENC`, `DEC`, `REND`, `ISAR`, `ISAR_ENC`. +- Command substring filtering is also supported. +- Matching is case-insensitive. - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --test-mode=ENC - ``` - -- Analyse BE conformance for CUT IVAS Encoder Outputs Only (on Reference Platform) - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --test-mode=ENC --analyse --be-test - ``` - -- Analyse NON-BE conformance for CUT IVAS Encoder Outputs Only (on Reference Platform) - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --test-mode=ENC --analyse - ``` - -- Run CUT IVAS Decoder Tests Only (on Target Platform) - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --test-mode=DEC - ``` - -- Analyse BE conformance for CUT IVAS Decoder Outputs Only - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --test-mode=DEC --analyse --be-test - ``` - -- Analyse NON-BE conformance CUT IVAS Decoder Outputs Only (on Reference Platform) - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --test-mode=DEC --analyse - ``` - -- Run CUT IVAS Renderer Tests Only (on Target Platform) - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --test-mode=REND - ``` - -- Analyse BE conformance for CUT Renderer Outputs Only - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --test-mode=REND --analyse --be-test - ``` - -- Analyse NON-BE conformance CUT Renderer Outputs Only - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --test-mode=REND --analyse - ``` - -- Run CUT ISAR Encoder Tests Only (on Target Platform) - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --test-mode=ISAR_ENC - ``` - -- Analyse BE conformance for CUT ISAR Encoder Outputs Only (on Reference Platform) - - ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --test-mode=ISAR_ENC --analyse --be-test - ``` +Examples: -- Analyse NON-BE conformance for CUT ISAR Encoder Outputs Only (on Reference Platform) +- Run all renderer tests only: ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --test-mode=ISAR_ENC --analyse + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter rend ``` -- Run CUT ISAR Decoder Tests Only (on Target Platform) +- Analyze BE conformance for encoder tests only: ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --test-mode=ISAR + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --be-test --filter enc ``` -- Analyse BE conformance for CUT ISAR Decoder Outputs Only +- Analyze non-BE conformance for DEC and REND tests that include `voip` in the command: ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --test-mode=ISAR --analyse --be-test + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter dec,rend voip ``` -- Analyse NON-BE conformance CUT ISAR Decoder Outputs Only +- Run only ISAR encoder tests: ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --test-mode=ISAR --analyse + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter isar_enc ``` diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index ecf964b73..967f89e29 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -935,8 +935,9 @@ class MLDConformance: failed_before = self.getFailedCommandCount() selectedTests = list() if self.filter: + filter_text = self.filter.lower() for pyTestsTag in self.TestDesc[tag].keys(): - if self.filter in self.TestDesc[tag][pyTestsTag].rawCmdline: + if filter_text in self.TestDesc[tag][pyTestsTag].rawCmdline.lower(): selectedTests.append(pyTestsTag) else: selectedTests = list(self.TestDesc[tag].keys()) @@ -1023,8 +1024,9 @@ class MLDConformance: selectedTests = [] if self.filter: + filter_text = self.filter.lower() for pyTestsTag in self.TestDesc[tag].keys(): - if self.filter in self.TestDesc[tag][pyTestsTag].rawCmdline: + if filter_text in self.TestDesc[tag][pyTestsTag].rawCmdline.lower(): selectedTests.append(pyTestsTag) else: selectedTests = list(self.TestDesc[tag].keys()) @@ -1634,14 +1636,10 @@ if __name__ == "__main__": "--filter", type=str, default=None, - help="Filter test based on text provided", - ) - parser.add_argument( - "--test-mode", - type=str, - default=None, - choices=["ENC", "DEC", "REND", "ISAR", "ISAR_ENC"], - help='Choose one test group to run ["ENC", "DEC", "REND", "ISAR", "ISAR_ENC"]. If omitted, all are run.', + help=( + "Filter tests. Supports tags ENC DEC REND ISAR ISAR_ENC (comma/space-separated) " + "and case-insensitive command substring filtering. Examples: '--filter rend' or '--filter REND binaural'." + ), ) parser.add_argument( "--be-test", @@ -1704,7 +1702,25 @@ if __name__ == "__main__": if args.regenerate_mld_ref: args.analyse = True - testTags = IVAS_Bins.keys() if args.test_mode is None else [args.test_mode] + # Parse --filter into optional tag selection + optional command substring filter. + raw_filter = args.filter or "" + filter_tokens = [tok for tok in re.split(r"[\s,]+", raw_filter.strip()) if tok] + valid_tags = set(IVAS_Bins.keys()) + tag_tokens = [] + non_tag_tokens = [] + for tok in filter_tokens: + upper_tok = tok.upper() + if upper_tok in valid_tags: + tag_tokens.append(upper_tok) + else: + non_tag_tokens.append(tok) + + # Preserve order while removing duplicates. + tag_tokens = list(dict.fromkeys(tag_tokens)) + + testTags = tag_tokens if tag_tokens else list(IVAS_Bins.keys()) + args.filter = " ".join(non_tag_tokens) if non_tag_tokens else None + tag_results = {} for tag in testTags: if args.report_only: -- GitLab From 5404bc765832e200d537dbd035de73055ea65860 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 13:32:30 +0100 Subject: [PATCH 02/30] add support for LEVEL1 and LEVEL3 --- scripts/ivas_conformance/README.md | 46 ++++-- scripts/ivas_conformance/runConformance.py | 155 ++++++++++++++++----- 2 files changed, 151 insertions(+), 50 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index 18ae5b25a..2f016a63d 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -247,34 +247,54 @@ MLD Corridor passed for ISAR with max MLD diff of 0.0 ## Executing specific tests only -Use `--filter` to run or analyze a subset of tests. - -- Tag selection is supported with comma-separated tags: `ENC`, `DEC`, `REND`, `ISAR`, `ISAR_ENC`. -- Command substring filtering is also supported. -- Matching is case-insensitive. +Use `--filter` to control test levels, tags and optional text/format filtering. + +- Levels: + - `LEVEL3` (default): no level-based restrictions. + - `LEVEL1`: applies the restrictions below. + - `LEVEL2`: currently unsupported; script exits with an error. +- Tag selection (case-insensitive): `ENC`, `DEC`, `REND`, `ISAR`, `ISAR_ENC`. +- Command substring filter is case-insensitive. + +### LEVEL1 behavior + +- Encoder (`ENC`) tests: only tests with bitrate up to 80 kbps (inclusive). +- Decoder (`DEC`) tests by default: + - `EXT` output format: only bitrate up to 80 kbps (inclusive). + - `MONO` output format: all bitrates. + - `STEREO` output format: all bitrates. +- Renderer and ISAR tests are not run by default in `LEVEL1`. + - Add `REND` and/or `ISAR` in `--filter` to include them. + - If `ISAR` is provided, both `ISAR` and `ISAR_ENC` test groups are run. Examples: -- Run all renderer tests only: +- Default behavior (same as LEVEL3): run all tags/tests + + ```shell + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR + ``` + +- LEVEL1 baseline (ENC+DEC with LEVEL1 restrictions) ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter rend + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 ``` -- Analyze BE conformance for encoder tests only: +- LEVEL1 plus renderer and ISAR test groups ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --be-test --filter enc + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 REND ISAR ``` -- Analyze non-BE conformance for DEC and REND tests that include `voip` in the command: +- LEVEL1 with additional case-insensitive command substring filtering ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter dec,rend voip + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 DEC voip ``` -- Run only ISAR encoder tests: +- Unsupported LEVEL2 example (will fail) ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter isar_enc + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL2 ``` diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 967f89e29..56ffd3c30 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -359,7 +359,7 @@ class MLDConformance: def setupDUT(self): self.cut_build_path = self.args.cut_build_path - self.filter = self.args.filter + self.filter = getattr(self.args, "filter_display", self.args.filter) exe_platform = platform.system() if exe_platform == "Windows": exe_platform = "Win64" @@ -931,16 +931,75 @@ class MLDConformance: def analyseOneCommandFromTuple(self, args): return self.analyseOneCommand(*args) + def _extractKbpsValues(self, rawCmdline: str) -> list[float]: + values = [] + for match in re.findall(r"(\d+(?:_\d+)?)_kbps", rawCmdline.lower()): + values.append(float(match.replace("_", "."))) + return values + + def _isBitrateAtMost80(self, rawCmdline: str) -> bool: + values = self._extractKbpsValues(rawCmdline) + return bool(values) and max(values) <= 80.0 + + def _decoderFormatsInCommand(self, rawCmdline: str) -> set[str]: + text = rawCmdline.upper() + formats = set() + + if "MONO" in text: + formats.add("MONO") + if "STEREO" in text: + formats.add("STEREO") + + # Avoid matching words like e.g. EXTENDED - do keying based on _OUT output only + if ( + "_EXT_OUT" in text + or "_EXTERNAL_OUT" in text + or " EXT_OUT" in text + or " EXTERNAL_OUT" in text + ): + formats.add("EXT") + + return formats + + def _matchesSubstringFilter(self, rawCmdline: str) -> bool: + filter_substring = getattr(self.args, "filter_substring", None) + if not filter_substring: + return True + return filter_substring.lower() in rawCmdline.lower() + + def _matchesLevel1(self, tag: str, rawCmdline: str) -> bool: + if tag == "ENC": + return self._isBitrateAtMost80(rawCmdline) + + if tag == "DEC": + formats = self._decoderFormatsInCommand(rawCmdline) + ext_ok = "EXT" in formats and self._isBitrateAtMost80(rawCmdline) + mono_ok = "MONO" in formats + stereo_ok = "STEREO" in formats + return ext_ok or mono_ok or stereo_ok + + # For REND/ISAR/ISAR_ENC under LEVEL1, tag-level inclusion is decided at testTags parsing. + return True + + def _testPassesFilter(self, tag: str, rawCmdline: str) -> bool: + level = getattr(self.args, "filter_level", "LEVEL3") + + if level == "LEVEL1" and not self._matchesLevel1(tag, rawCmdline): + return False + + return self._matchesSubstringFilter(rawCmdline) + + def getSelectedTestsForTag(self, tag: str) -> list[str]: + selected = [] + for pyTestsTag in self.TestDesc[tag].keys(): + rawCmdline = self.TestDesc[tag][pyTestsTag].rawCmdline + if self._testPassesFilter(tag, rawCmdline): + selected.append(pyTestsTag) + return selected + def runTag(self, tag: str) -> bool: failed_before = self.getFailedCommandCount() - selectedTests = list() - if self.filter: - filter_text = self.filter.lower() - for pyTestsTag in self.TestDesc[tag].keys(): - if filter_text in self.TestDesc[tag][pyTestsTag].rawCmdline.lower(): - selectedTests.append(pyTestsTag) - else: - selectedTests = list(self.TestDesc[tag].keys()) + selectedTests = self.getSelectedTestsForTag(tag) self.totalTests = len(selectedTests) print( @@ -1022,14 +1081,7 @@ class MLDConformance: with open(self.sampleStats[tag], "w") as f: f.write(f"PYTESTTAG, MAXDIFF, RMSdB, BEFRAMES_PERCENT, MAX_MLD\n") - selectedTests = [] - if self.filter: - filter_text = self.filter.lower() - for pyTestsTag in self.TestDesc[tag].keys(): - if filter_text in self.TestDesc[tag][pyTestsTag].rawCmdline.lower(): - selectedTests.append(pyTestsTag) - else: - selectedTests = list(self.TestDesc[tag].keys()) + selectedTests = self.getSelectedTestsForTag(tag) self.totalTests = len(selectedTests) print( @@ -1637,8 +1689,9 @@ if __name__ == "__main__": type=str, default=None, help=( - "Filter tests. Supports tags ENC DEC REND ISAR ISAR_ENC (comma/space-separated) " - "and case-insensitive command substring filtering. Examples: '--filter rend' or '--filter REND binaural'." + "Filter tests. Supports levels LEVEL1 LEVEL2 LEVEL3 and tags ENC DEC REND ISAR ISAR_ENC " + "(comma/space-separated), and case-insensitive command substring filtering. " + "LEVEL3 is default. LEVEL2 is currently unsupported." ), ) parser.add_argument( @@ -1690,36 +1743,64 @@ if __name__ == "__main__": if args.cut_build_path: validate_build_binaries(parser, args.cut_build_path, "CUT") - conformance = MLDConformance(args) - conformance.accumulateCommands() - - if args.regenerate_enc_refs: - conformance.runReferenceGeneration(encTag="ISAR_ENC") - conformance.runReferenceGeneration(encTag="ENC") - sys.exit(0) - - # If --regenerate-mld-ref is set, treat as --analyse - if args.regenerate_mld_ref: - args.analyse = True - - # Parse --filter into optional tag selection + optional command substring filter. + # Parse --filter into level + optional tag selection + optional format/substring filters. raw_filter = args.filter or "" filter_tokens = [tok for tok in re.split(r"[\s,]+", raw_filter.strip()) if tok] + valid_tags = set(IVAS_Bins.keys()) + valid_levels = {"LEVEL1", "LEVEL2", "LEVEL3"} + + level_tokens = [] tag_tokens = [] - non_tag_tokens = [] + non_special_tokens = [] + for tok in filter_tokens: upper_tok = tok.upper() - if upper_tok in valid_tags: + if upper_tok in valid_levels: + level_tokens.append(upper_tok) + elif upper_tok in valid_tags: tag_tokens.append(upper_tok) else: - non_tag_tokens.append(tok) + non_special_tokens.append(tok) + + if len(set(level_tokens)) > 1: + parser.error("Multiple filter levels specified. Use only one of LEVEL1, LEVEL2, LEVEL3.") + + filter_level = level_tokens[0] if level_tokens else "LEVEL3" + if filter_level == "LEVEL2": + parser.error("--filter LEVEL2 is currently unsupported.") # Preserve order while removing duplicates. tag_tokens = list(dict.fromkeys(tag_tokens)) - testTags = tag_tokens if tag_tokens else list(IVAS_Bins.keys()) - args.filter = " ".join(non_tag_tokens) if non_tag_tokens else None + # If ISAR is requested, run both ISAR and ISAR_ENC. + if "ISAR" in tag_tokens and "ISAR_ENC" not in tag_tokens: + tag_tokens.append("ISAR_ENC") + + if filter_level == "LEVEL1": + # LEVEL1 baseline: ENC + DEC; REND/ISAR only if explicitly requested. + selected_tag_set = {"ENC", "DEC"} + for tag in tag_tokens: + selected_tag_set.add(tag) + testTags = [tag for tag in IVAS_Bins.keys() if tag in selected_tag_set] + else: + testTags = tag_tokens if tag_tokens else list(IVAS_Bins.keys()) + + args.filter_display = raw_filter if raw_filter else None + args.filter_substring = " ".join(non_special_tokens) if non_special_tokens else None + args.filter_level = filter_level + + conformance = MLDConformance(args) + conformance.accumulateCommands() + + if args.regenerate_enc_refs: + conformance.runReferenceGeneration(encTag="ISAR_ENC") + conformance.runReferenceGeneration(encTag="ENC") + sys.exit(0) + + # If --regenerate-mld-ref is set, treat as --analyse + if args.regenerate_mld_ref: + args.analyse = True tag_results = {} for tag in testTags: -- GitLab From f70a9b64ea301c835d1c32da385108826896b268 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 13:34:10 +0100 Subject: [PATCH 03/30] add BINAURAL output format filter support --- scripts/ivas_conformance/README.md | 9 ++++++++ scripts/ivas_conformance/runConformance.py | 27 ++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index 2f016a63d..d7d18b31e 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -263,6 +263,9 @@ Use `--filter` to control test levels, tags and optional text/format filtering. - `EXT` output format: only bitrate up to 80 kbps (inclusive). - `MONO` output format: all bitrates. - `STEREO` output format: all bitrates. +- Decoder format tokens are additive to the default LEVEL1 decoder set. +- Any token containing `BINAURAL` matches decoder tests whose command contains `BINAURAL` + (for example, `BINAURAL`, `BINAURAL_IR`, `BINAURAL_ROOM_IR`, `BINAURAL_REVERB`). - Renderer and ISAR tests are not run by default in `LEVEL1`. - Add `REND` and/or `ISAR` in `--filter` to include them. - If `ISAR` is provided, both `ISAR` and `ISAR_ENC` test groups are run. @@ -293,6 +296,12 @@ Examples: PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 DEC voip ``` +- LEVEL1 with additive BINAURAL decoder matching + + ```shell + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 BINAURAL + ``` + - Unsupported LEVEL2 example (will fail) ```shell diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 56ffd3c30..870b34623 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -945,6 +945,8 @@ class MLDConformance: text = rawCmdline.upper() formats = set() + if "BINAURAL" in text: + formats.add("BINAURAL") if "MONO" in text: formats.add("MONO") if "STEREO" in text: @@ -973,10 +975,22 @@ class MLDConformance: if tag == "DEC": formats = self._decoderFormatsInCommand(rawCmdline) + requested_formats = set(getattr(self.args, "filter_decoder_formats", [])) + ext_ok = "EXT" in formats and self._isBitrateAtMost80(rawCmdline) mono_ok = "MONO" in formats stereo_ok = "STEREO" in formats - return ext_ok or mono_ok or stereo_ok + default_level1_dec_ok = ext_ok or mono_ok or stereo_ok + + if requested_formats: + requested_match = False + if "BINAURAL" in requested_formats and "BINAURAL" in rawCmdline.upper(): + requested_match = True + elif formats.intersection(requested_formats): + requested_match = True + return default_level1_dec_ok or requested_match + + return default_level1_dec_ok # For REND/ISAR/ISAR_ENC under LEVEL1, tag-level inclusion is decided at testTags parsing. return True @@ -1690,7 +1704,8 @@ if __name__ == "__main__": default=None, help=( "Filter tests. Supports levels LEVEL1 LEVEL2 LEVEL3 and tags ENC DEC REND ISAR ISAR_ENC " - "(comma/space-separated), and case-insensitive command substring filtering. " + "(comma/space-separated), decoder formats EXT MONO STEREO BINAURAL, " + "and case-insensitive command substring filtering. " "LEVEL3 is default. LEVEL2 is currently unsupported." ), ) @@ -1749,9 +1764,11 @@ if __name__ == "__main__": valid_tags = set(IVAS_Bins.keys()) valid_levels = {"LEVEL1", "LEVEL2", "LEVEL3"} + valid_decoder_formats = {"EXT", "MONO", "STEREO", "BINAURAL"} level_tokens = [] tag_tokens = [] + decoder_format_tokens = [] non_special_tokens = [] for tok in filter_tokens: @@ -1760,6 +1777,10 @@ if __name__ == "__main__": level_tokens.append(upper_tok) elif upper_tok in valid_tags: tag_tokens.append(upper_tok) + elif "BINAURAL" in upper_tok: + decoder_format_tokens.append("BINAURAL") + elif upper_tok in valid_decoder_formats: + decoder_format_tokens.append(upper_tok) else: non_special_tokens.append(tok) @@ -1772,6 +1793,7 @@ if __name__ == "__main__": # Preserve order while removing duplicates. tag_tokens = list(dict.fromkeys(tag_tokens)) + decoder_format_tokens = list(dict.fromkeys(decoder_format_tokens)) # If ISAR is requested, run both ISAR and ISAR_ENC. if "ISAR" in tag_tokens and "ISAR_ENC" not in tag_tokens: @@ -1788,6 +1810,7 @@ if __name__ == "__main__": args.filter_display = raw_filter if raw_filter else None args.filter_substring = " ".join(non_special_tokens) if non_special_tokens else None + args.filter_decoder_formats = decoder_format_tokens args.filter_level = filter_level conformance = MLDConformance(args) -- GitLab From 690f2be4df7ae52676311ed9d3f2b82a704c07ba Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:13:46 +0100 Subject: [PATCH 04/30] add support for adding/removoing tests using + or - symbol --- scripts/ivas_conformance/README.md | 37 +++++-- scripts/ivas_conformance/runConformance.py | 117 ++++++++++++++++----- 2 files changed, 117 insertions(+), 37 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index d7d18b31e..67d3fa292 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -247,28 +247,41 @@ MLD Corridor passed for ISAR with max MLD diff of 0.0 ## Executing specific tests only -Use `--filter` to control test levels, tags and optional text/format filtering. +Use `--filter` to control test levels, tags and optional text/out_format filtering. - Levels: - `LEVEL3` (default): no level-based restrictions. - `LEVEL1`: applies the restrictions below. - `LEVEL2`: currently unsupported; script exits with an error. - Tag selection (case-insensitive): `ENC`, `DEC`, `REND`, `ISAR`, `ISAR_ENC`. -- Command substring filter is case-insensitive. +- Command substring filtering is case-insensitive. +- Plain substring terms are restrictive and combined using logical AND. + - Example: `--filter DEC JBM` runs only decoder tests that contain `JBM`. +- `+TERM` adds matching tests to the selection. + - Example: `--filter LEVEL1 DEC +JBM` adds all `JBM` decoder tests to the default `LEVEL1 DEC` selection. +- `-TERM` removes matching tests from the selection. + - Example: `--filter DEC -JBM` runs decoder tests except those containing `JBM`. ### LEVEL1 behavior +When `--filter LEVEL1` is specified, the following default tests are run: + - Encoder (`ENC`) tests: only tests with bitrate up to 80 kbps (inclusive). -- Decoder (`DEC`) tests by default: +- Decoder (`DEC`) tests: - `EXT` output format: only bitrate up to 80 kbps (inclusive). - `MONO` output format: all bitrates. - `STEREO` output format: all bitrates. -- Decoder format tokens are additive to the default LEVEL1 decoder set. -- Any token containing `BINAURAL` matches decoder tests whose command contains `BINAURAL` - (for example, `BINAURAL`, `BINAURAL_IR`, `BINAURAL_ROOM_IR`, `BINAURAL_REVERB`). + +- The default `LEVEL1` tests may be restricted by adding more terms (acting as logical AND). + - Example: `--filter LEVEL1 DEC MONO` keeps only `MONO` tests from the LEVEL1-eligible DEC set. + - Example: `--filter LEVEL1 JBM` keeps all LEVEL1-eligible ENC tests but only JBM tests from the LEVEL1-eligible DEC tests. +- `+TERM` adds tests to the final LEVEL1 selection, even if they would otherwise be restricted. + - Example: `--filter LEVEL1 DEC JBM +BINAURAL` runs only JBM-matching LEVEL1 DEC tests and additionally includes DEC tests containing `BINAURAL` keyword, i.e. `BINAURAL`, `BINAURAL_IR`, `BINAURAL_ROOM_IR`, `BINAURAL_REVERB`. +- `-TERM` removes matching tests from the final LEVEL1 selection (including tests added via `+TERM`). + - Example: `--filter LEVEL1 DEC +JBM -VOIP` adds JBM-matching DEC tests and then excludes any DEC tests containing the keyword `VOIP`. - Renderer and ISAR tests are not run by default in `LEVEL1`. - - Add `REND` and/or `ISAR` in `--filter` to include them. - - If `ISAR` is provided, both `ISAR` and `ISAR_ENC` test groups are run. + - Add `+REND` and/or `+ISAR` in `--filter` to include them. + - If `+ISAR` is provided, both `ISAR` and `ISAR_ENC` test groups are run. Examples: @@ -299,7 +312,13 @@ Examples: - LEVEL1 with additive BINAURAL decoder matching ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 BINAURAL + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 +BINAURAL + ``` + +- LEVEL1 with restrictive and additive terms together + + ```shell + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 DEC JBM +BINAURAL ``` - Unsupported LEVEL2 example (will fail) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 870b34623..43f02f244 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -945,8 +945,6 @@ class MLDConformance: text = rawCmdline.upper() formats = set() - if "BINAURAL" in text: - formats.add("BINAURAL") if "MONO" in text: formats.add("MONO") if "STEREO" in text: @@ -963,11 +961,13 @@ class MLDConformance: return formats - def _matchesSubstringFilter(self, rawCmdline: str) -> bool: - filter_substring = getattr(self.args, "filter_substring", None) - if not filter_substring: - return True - return filter_substring.lower() in rawCmdline.lower() + def _matchesAllTerms(self, rawCmdline: str, terms: list[str]) -> bool: + text = rawCmdline.lower() + return all(term.lower() in text for term in terms) + + def _matchesAnyTerm(self, rawCmdline: str, terms: list[str]) -> bool: + text = rawCmdline.lower() + return any(term.lower() in text for term in terms) def _matchesLevel1(self, tag: str, rawCmdline: str) -> bool: if tag == "ENC": @@ -983,12 +983,8 @@ class MLDConformance: default_level1_dec_ok = ext_ok or mono_ok or stereo_ok if requested_formats: - requested_match = False - if "BINAURAL" in requested_formats and "BINAURAL" in rawCmdline.upper(): - requested_match = True - elif formats.intersection(requested_formats): - requested_match = True - return default_level1_dec_ok or requested_match + # Plain decoder format tokens are restrictive under LEVEL1. + return default_level1_dec_ok and bool(formats.intersection(requested_formats)) return default_level1_dec_ok @@ -997,11 +993,29 @@ class MLDConformance: def _testPassesFilter(self, tag: str, rawCmdline: str) -> bool: level = getattr(self.args, "filter_level", "LEVEL3") + restrictive_terms = getattr(self.args, "filter_restrictive_terms", []) + additive_terms = getattr(self.args, "filter_add_terms", []) + subtractive_terms = getattr(self.args, "filter_remove_terms", []) - if level == "LEVEL1" and not self._matchesLevel1(tag, rawCmdline): + # '-' terms always remove tests from the final selection. + if subtractive_terms and self._matchesAnyTerm(rawCmdline, subtractive_terms): return False - return self._matchesSubstringFilter(rawCmdline) + passes_level = True + if level == "LEVEL1": + passes_level = self._matchesLevel1(tag, rawCmdline) + + passes_restrictive_terms = self._matchesAllTerms(rawCmdline, restrictive_terms) + base_selected = passes_level and passes_restrictive_terms + + if base_selected: + return True + + # '+' terms add tests even if they fail restrictive filters. + if additive_terms and self._matchesAnyTerm(rawCmdline, additive_terms): + return True + + return False def getSelectedTestsForTag(self, tag: str) -> list[str]: selected = [] @@ -1704,8 +1718,9 @@ if __name__ == "__main__": default=None, help=( "Filter tests. Supports levels LEVEL1 LEVEL2 LEVEL3 and tags ENC DEC REND ISAR ISAR_ENC " - "(comma/space-separated), decoder formats EXT MONO STEREO BINAURAL, " - "and case-insensitive command substring filtering. " + "(comma/space-separated), decoder formats EXT MONO STEREO, " + "and case-insensitive command substring filtering. Plain terms are restrictive (AND). " + "Use +TERM to add matches and -TERM to remove matches. " "LEVEL3 is default. LEVEL2 is currently unsupported." ), ) @@ -1764,25 +1779,51 @@ if __name__ == "__main__": valid_tags = set(IVAS_Bins.keys()) valid_levels = {"LEVEL1", "LEVEL2", "LEVEL3"} - valid_decoder_formats = {"EXT", "MONO", "STEREO", "BINAURAL"} + valid_decoder_formats = {"EXT", "MONO", "STEREO"} level_tokens = [] tag_tokens = [] + tag_add_tokens = [] + tag_remove_tokens = [] decoder_format_tokens = [] - non_special_tokens = [] + restrictive_terms = [] + additive_terms = [] + subtractive_terms = [] for tok in filter_tokens: - upper_tok = tok.upper() + sign = "" + base_tok = tok + if len(tok) > 1 and tok[0] in {"+", "-"}: + sign = tok[0] + base_tok = tok[1:] + + upper_tok = base_tok.upper() + if upper_tok in valid_levels: + if sign: + parser.error(f"Level token '{tok}' cannot be prefixed with '+' or '-'.") level_tokens.append(upper_tok) elif upper_tok in valid_tags: - tag_tokens.append(upper_tok) - elif "BINAURAL" in upper_tok: - decoder_format_tokens.append("BINAURAL") + if sign == "+": + tag_add_tokens.append(upper_tok) + elif sign == "-": + tag_remove_tokens.append(upper_tok) + else: + tag_tokens.append(upper_tok) elif upper_tok in valid_decoder_formats: - decoder_format_tokens.append(upper_tok) + if sign == "+": + additive_terms.append(base_tok) + elif sign == "-": + subtractive_terms.append(base_tok) + else: + decoder_format_tokens.append(upper_tok) else: - non_special_tokens.append(tok) + if sign == "+": + additive_terms.append(base_tok) + elif sign == "-": + subtractive_terms.append(base_tok) + else: + restrictive_terms.append(base_tok) if len(set(level_tokens)) > 1: parser.error("Multiple filter levels specified. Use only one of LEVEL1, LEVEL2, LEVEL3.") @@ -1793,23 +1834,43 @@ if __name__ == "__main__": # Preserve order while removing duplicates. tag_tokens = list(dict.fromkeys(tag_tokens)) + tag_add_tokens = list(dict.fromkeys(tag_add_tokens)) + tag_remove_tokens = list(dict.fromkeys(tag_remove_tokens)) decoder_format_tokens = list(dict.fromkeys(decoder_format_tokens)) - # If ISAR is requested, run both ISAR and ISAR_ENC. + # If ISAR is requested/added/removed, apply same action to ISAR_ENC. if "ISAR" in tag_tokens and "ISAR_ENC" not in tag_tokens: tag_tokens.append("ISAR_ENC") + if "ISAR" in tag_add_tokens and "ISAR_ENC" not in tag_add_tokens: + tag_add_tokens.append("ISAR_ENC") + if "ISAR" in tag_remove_tokens and "ISAR_ENC" not in tag_remove_tokens: + tag_remove_tokens.append("ISAR_ENC") if filter_level == "LEVEL1": # LEVEL1 baseline: ENC + DEC; REND/ISAR only if explicitly requested. selected_tag_set = {"ENC", "DEC"} for tag in tag_tokens: selected_tag_set.add(tag) + for tag in tag_add_tokens: + selected_tag_set.add(tag) + for tag in tag_remove_tokens: + selected_tag_set.discard(tag) testTags = [tag for tag in IVAS_Bins.keys() if tag in selected_tag_set] else: - testTags = tag_tokens if tag_tokens else list(IVAS_Bins.keys()) + if tag_tokens: + selected_tag_set = set(tag_tokens) + else: + selected_tag_set = set(IVAS_Bins.keys()) + for tag in tag_add_tokens: + selected_tag_set.add(tag) + for tag in tag_remove_tokens: + selected_tag_set.discard(tag) + testTags = [tag for tag in IVAS_Bins.keys() if tag in selected_tag_set] args.filter_display = raw_filter if raw_filter else None - args.filter_substring = " ".join(non_special_tokens) if non_special_tokens else None + args.filter_restrictive_terms = restrictive_terms + args.filter_add_terms = additive_terms + args.filter_remove_terms = subtractive_terms args.filter_decoder_formats = decoder_format_tokens args.filter_level = filter_level -- GitLab From bfed7355f7902eaee32b65cdb3eac97882edd190 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:27:41 +0100 Subject: [PATCH 05/30] fix --filter to accept multiple space-separated tokens --- scripts/ivas_conformance/runConformance.py | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 43f02f244..7889f9037 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1714,14 +1714,28 @@ if __name__ == "__main__": parser.add_argument( "--filter", - type=str, + nargs="+", default=None, + metavar="TOKEN", help=( - "Filter tests. Supports levels LEVEL1 LEVEL2 LEVEL3 and tags ENC DEC REND ISAR ISAR_ENC " - "(comma/space-separated), decoder formats EXT MONO STEREO, " - "and case-insensitive command substring filtering. Plain terms are restrictive (AND). " - "Use +TERM to add matches and -TERM to remove matches. " - "LEVEL3 is default. LEVEL2 is currently unsupported." + "Select which tests to run. Accepts any combination of the following tokens: " + "(1) Level: LEVEL1, LEVEL3 (default: LEVEL3 = no restrictions). " + "LEVEL1 restricts ENC to <=80 kbps and DEC to EXT<=80 kbps, MONO and STEREO outputs. " + "(2) Tag: ENC, DEC, REND, ISAR, ISAR_ENC — selects specific test groups. " + "Under LEVEL1, +REND or +ISAR adds those groups to the default ENC+DEC set. " + "(3) Decoder format (LEVEL1 DEC only): EXT, MONO, STEREO — further restricts which " + "output formats are included within the already-restricted LEVEL1 DEC set. " + "(4) Substring: any other plain token is matched case-insensitively against the test " + "command line. Multiple plain tokens are combined with logical AND. " + "Prefix a token with + to add matching tests to the selection, " + "or with - to remove matching tests from the selection. " + "Examples: " + "'--filter LEVEL1' — run LEVEL1 ENC+DEC; " + "'--filter LEVEL1 DEC MONO' — run only MONO tests from the LEVEL1 DEC set; " + "'--filter LEVEL1 +REND' — run LEVEL1 ENC+DEC and also all REND tests; " + "'--filter DEC JBM' — run DEC tests containing 'JBM'; " + "'--filter DEC +BINAURAL' — run all DEC tests plus those containing 'BINAURAL'; " + "'--filter DEC -voip' — run all DEC tests except those containing 'voip'." ), ) parser.add_argument( @@ -1774,7 +1788,7 @@ if __name__ == "__main__": validate_build_binaries(parser, args.cut_build_path, "CUT") # Parse --filter into level + optional tag selection + optional format/substring filters. - raw_filter = args.filter or "" + raw_filter = " ".join(args.filter) if args.filter else "" filter_tokens = [tok for tok in re.split(r"[\s,]+", raw_filter.strip()) if tok] valid_tags = set(IVAS_Bins.keys()) -- GitLab From b69beaf21221ca8966ecfb2553c026984cd5338c Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:28:06 +0100 Subject: [PATCH 06/30] fix --filter LEVEL1 TAG ignoring TAG restriction and print filtered test counts --- scripts/ivas_conformance/runConformance.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 7889f9037..0bca926f4 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -588,7 +588,7 @@ class MLDConformance: ) else: print(f"{pyTestTag} not found in ISAR decoder") - print("No of tests :") + print("No of tests (total, before filtering):") for tag in testDesciptor.keys(): print(f" {tag} : {len(testDesciptor[tag])}") @@ -1862,9 +1862,11 @@ if __name__ == "__main__": if filter_level == "LEVEL1": # LEVEL1 baseline: ENC + DEC; REND/ISAR only if explicitly requested. - selected_tag_set = {"ENC", "DEC"} - for tag in tag_tokens: - selected_tag_set.add(tag) + # Plain tag_tokens restrict the baseline; +tag_tokens add beyond it. + if tag_tokens: + selected_tag_set = set(tag_tokens) + else: + selected_tag_set = {"ENC", "DEC"} for tag in tag_add_tokens: selected_tag_set.add(tag) for tag in tag_remove_tokens: @@ -1891,6 +1893,12 @@ if __name__ == "__main__": conformance = MLDConformance(args) conformance.accumulateCommands() + if testTags or args.filter_display: + print(f"Selected tests after filtering ({args.filter_display or 'no filter'}):") + for tag in testTags: + n = len(conformance.getSelectedTestsForTag(tag)) + print(f" {tag} : {n}") + if args.regenerate_enc_refs: conformance.runReferenceGeneration(encTag="ISAR_ENC") conformance.runReferenceGeneration(encTag="ENC") -- GitLab From 915b00a7a2c228f293e479593fa0026ea15653fe Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:29:23 +0100 Subject: [PATCH 07/30] fix --clean-output-dir help text --- scripts/ivas_conformance/runConformance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 0bca926f4..8722edc77 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1767,7 +1767,7 @@ if __name__ == "__main__": "--clean-output-dir", default=False, action="store_true", - help="Do not run DUT, use existing mld and bitdiff stats files to generate analysis only", + help="Delete and recreate the CUT_OUTPUTS directory before running, discarding any previous DUT outputs", ) parser.add_argument( "--regenerate-mld-ref", -- GitLab From 8842c2d9de834f9cab16b79f2ea36807d709267b Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:31:58 +0100 Subject: [PATCH 08/30] remove -c short option from --clean-output-dir --- scripts/ivas_conformance/runConformance.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 8722edc77..738a7ae10 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1763,7 +1763,6 @@ if __name__ == "__main__": help="Do not run DUT, use existing mld and bitdiff stats files to generate analysis only", ) parser.add_argument( - "-c", "--clean-output-dir", default=False, action="store_true", -- GitLab From d1a584afa65424533965d5884260fb81c1591a85 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:36:03 +0100 Subject: [PATCH 09/30] reformat startup output: show filter banner and all-tag test counts --- scripts/ivas_conformance/runConformance.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 738a7ae10..d4acbc12c 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -588,10 +588,6 @@ class MLDConformance: ) else: print(f"{pyTestTag} not found in ISAR decoder") - print("No of tests (total, before filtering):") - for tag in testDesciptor.keys(): - print(f" {tag} : {len(testDesciptor[tag])}") - return testDesciptor def genEncoderReferences(self, tag: str, encPytestTag: str): @@ -1892,11 +1888,14 @@ if __name__ == "__main__": conformance = MLDConformance(args) conformance.accumulateCommands() - if testTags or args.filter_display: - print(f"Selected tests after filtering ({args.filter_display or 'no filter'}):") - for tag in testTags: - n = len(conformance.getSelectedTestsForTag(tag)) - print(f" {tag} : {n}") + if args.filter_display: + print(f"Applying filter: {args.filter_display}") + print() + print("No of tests:") + for tag in IVAS_Bins.keys(): + n = len(conformance.getSelectedTestsForTag(tag)) if tag in testTags else 0 + print(f" {tag} : {n}") + print() if args.regenerate_enc_refs: conformance.runReferenceGeneration(encTag="ISAR_ENC") -- GitLab From 51587a69a344bb8161369fe3c436d0dc32c7f4b8 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:38:16 +0100 Subject: [PATCH 10/30] simplify tag execution/analysis header format and add separator --- scripts/ivas_conformance/runConformance.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index d4acbc12c..5a868796c 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1027,9 +1027,10 @@ class MLDConformance: self.totalTests = len(selectedTests) print( - f"Executing tests for {tag} {'Filter=' + self.filter if self.filter else ''} ({self.totalTests} tests)", + f"Executing tests for {tag} ({self.totalTests} tests):", flush=True, ) + print("---------------------------") if not self.args.no_multi_processing: with Pool() as pool: args = [ @@ -1109,9 +1110,10 @@ class MLDConformance: self.totalTests = len(selectedTests) print( - f"Analysing tests for {tag} {'Filter=' + self.filter if self.filter else ''} ({self.totalTests} tests)", + f"Analysing tests for {tag} ({self.totalTests} tests):", flush=True, ) + print("---------------------------") def handle_test_result( testPrefix, -- GitLab From 7103074aabbd0c676d10067bbd29ae7f219fec59 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:41:27 +0100 Subject: [PATCH 11/30] suppress corridor comparison warning when filters are active --- scripts/ivas_conformance/runConformance.py | 26 ++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 5a868796c..7ef7fd718 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1546,15 +1546,23 @@ class MLDConformance: else: ref_count = refMLD.shape[0] dut_count = dutMLD.shape[0] - ref_preview = ", ".join(refTags[:3]) if ref_count else "" - dut_preview = ", ".join(dutTags[:3]) if dut_count else "" - warn_msg = ( - f"Warning: {tag} corridor comparison skipped because reference and DUT frame tags do not match " - f"(ref_count={ref_count}, dut_count={dut_count}, ref_first=[{ref_preview}], dut_first=[{dut_preview}])." - ) - print(f"\033[93m{warn_msg}\033[00m") - self.appendRunlog(context=warn_msg) - self.appendFailed(context=warn_msg) + # If filters are active, frame count mismatch is expected (DUT has fewer tests than reference). + # Skip the warning in this case. + if getattr(self.args, "filter_display", None): + skip_msg = ( + f"[{tag}] Corridor comparison skipped (filtered test set: ref_count={ref_count}, dut_count={dut_count})" + ) + self.appendRunlog(context=skip_msg) + else: + ref_preview = ", ".join(refTags[:3]) if ref_count else "" + dut_preview = ", ".join(dutTags[:3]) if dut_count else "" + warn_msg = ( + f"Warning: {tag} corridor comparison skipped because reference and DUT frame tags do not match " + f"(ref_count={ref_count}, dut_count={dut_count}, ref_first=[{ref_preview}], dut_first=[{dut_preview}])." + ) + print(f"\033[93m{warn_msg}\033[00m") + self.appendRunlog(context=warn_msg) + self.appendFailed(context=warn_msg) corridor_failed = True return not corridor_failed -- GitLab From c00c551ef1bacd4ffd84ed47a5c2508fb0c06cf5 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:43:11 +0100 Subject: [PATCH 12/30] do not treat corridor mismatch as failure when filters are active --- scripts/ivas_conformance/runConformance.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 7ef7fd718..b38eb0563 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1547,12 +1547,13 @@ class MLDConformance: ref_count = refMLD.shape[0] dut_count = dutMLD.shape[0] # If filters are active, frame count mismatch is expected (DUT has fewer tests than reference). - # Skip the warning in this case. + # Skip the warning and don't treat it as a failure in this case. if getattr(self.args, "filter_display", None): skip_msg = ( f"[{tag}] Corridor comparison skipped (filtered test set: ref_count={ref_count}, dut_count={dut_count})" ) self.appendRunlog(context=skip_msg) + corridor_failed = False else: ref_preview = ", ".join(refTags[:3]) if ref_count else "" dut_preview = ", ".join(dutTags[:3]) if dut_count else "" @@ -1563,7 +1564,7 @@ class MLDConformance: print(f"\033[93m{warn_msg}\033[00m") self.appendRunlog(context=warn_msg) self.appendFailed(context=warn_msg) - corridor_failed = True + corridor_failed = True return not corridor_failed -- GitLab From 0ec3aa83e78bbcedf39d1a81359ba3aa1a699ad8 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:47:57 +0100 Subject: [PATCH 13/30] add blank line before tag analysis summary --- scripts/ivas_conformance/runConformance.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index b38eb0563..8bb6d701b 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1206,6 +1206,7 @@ class MLDConformance: if self.args.regenerate_mld_ref: return command_fail_count == 0 and analysis_ok + print() if command_fail_count == 0 and failure_count == 0 and analysis_ok: print( f"[{tag}] OK (ERRORS={command_fail_count}, BE={be_count}, NON-BE={non_be_count}, MLD CORRIDOR FAILURES={failure_count})\n" @@ -1517,10 +1518,10 @@ class MLDConformance: skiprows=1, usecols=1, ) - if np.sum(BEresult) > 0: - print(f"<{tag}> FAILED BE TEST, check {self.BEcsv[tag]}") - else: - print(f"<{tag}> PASSED BE TEST") + # if np.sum(BEresult) > 0: + # print(f"<{tag}> FAILED BE TEST, check {self.BEcsv[tag]}") + # else: + # print(f"<{tag}> PASSED BE TEST") def computeCorridor(self, mldRefWithTags, mldCutWithTags, tag, threshold=0.1): indRef = np.argsort(mldRefWithTags["pyTestTag"]) @@ -1934,4 +1935,5 @@ if __name__ == "__main__": for tag in testTags: tag_status = "OK" if tag_results.get(tag, False) else "FAILED" print(f"[{tag}] {tag_status}") + print("\n") -- GitLab From 3a19dd35820b344d04a6e7d9a1a6f7884f5a3e63 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 14:52:51 +0100 Subject: [PATCH 14/30] clarify bitrate checking includes upper bitrate in bitrate-switching tests --- scripts/ivas_conformance/runConformance.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 8bb6d701b..c536d9ac4 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -928,12 +928,17 @@ class MLDConformance: return self.analyseOneCommand(*args) def _extractKbpsValues(self, rawCmdline: str) -> list[float]: + """Extract all bitrate values from command line (e.g., from 'at_32_kbps' or 'from_32_kbps_to_96_kbps').""" values = [] for match in re.findall(r"(\d+(?:_\d+)?)_kbps", rawCmdline.lower()): values.append(float(match.replace("_", "."))) return values def _isBitrateAtMost80(self, rawCmdline: str) -> bool: + """Check if all bitrates in command line are <= 80 kbps. + + For bitrate switching tests (e.g., 'from_32_kbps_to_96_kbps'), this checks + that the upper (target) bitrate does not exceed 80 kbps.""" values = self._extractKbpsValues(rawCmdline) return bool(values) and max(values) <= 80.0 @@ -1935,5 +1940,5 @@ if __name__ == "__main__": for tag in testTags: tag_status = "OK" if tag_results.get(tag, False) else "FAILED" print(f"[{tag}] {tag_status}") - print("\n") + print() -- GitLab From 796e088e489f9243a8713d86248ade77bc109aef Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 15:02:37 +0100 Subject: [PATCH 15/30] fix --filter to accept minus-prefixed tokens like -JBM --- scripts/ivas_conformance/runConformance.py | 74 +++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index c536d9ac4..f33fa8fea 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -53,6 +53,64 @@ import time sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) + +def _preprocess_filter_args(): + """Preprocess sys.argv to handle --filter with minus-prefixed tokens. + + Argparse stops consuming args when it encounters e.g. '-TERM', treating it as a flag. + This function escapes filter tokens by wrapping minus-prefixed tokens with a marker, + allowing argparse to treat them as regular arguments. + + Stores the escape mapping in _FILTER_ESCAPES for later unescaping. + + Returns: modified sys.argv with filter tokens escaped + """ + global _FILTER_ESCAPES + _FILTER_ESCAPES = {} + marker_prefix = "@FILT_" + result_argv = [] + i = 0 + + while i < len(sys.argv): + arg = sys.argv[i] + + # When we see --filter, process all following tokens until next option (--) or end + if arg == "--filter": + result_argv.append(arg) + i += 1 + + # Collect all filter tokens, escaping those that look like flags + while i < len(sys.argv): + tok = sys.argv[i] + + # Stop if we hit the next option (--something or -X where X is not escaped) + if tok.startswith("--") or (tok.startswith("-") and len(tok) <= 2 and tok != "-"): + # Exception: stop only if it's a known argparse option + known_short_options = {"-h", "--help"} + if tok in known_short_options or tok.startswith("--"): + break + break + + # Escape tokens starting with - to protect them from argparse + if tok.startswith("-"): + escaped = f"{marker_prefix}{len(_FILTER_ESCAPES)}" + _FILTER_ESCAPES[escaped] = tok + result_argv.append(escaped) + else: + result_argv.append(tok) + + i += 1 + else: + result_argv.append(arg) + i += 1 + + + return result_argv + + +# Module-level dict to track filter token escapes +_FILTER_ESCAPES = {} + def readfile( filename: str, nchannels: int = 1, fs: int = 48000, outdtype="float" ) -> Tuple[np.ndarray, int]: @@ -1787,7 +1845,21 @@ if __name__ == "__main__": action="store_true", help="Run analysis and unconditionally regenerate mld_ref2 files for all tags", ) - args = parser.parse_args() + # Preprocess sys.argv to handle --filter with minus-prefixed tokens like -JBM + modified_argv = _preprocess_filter_args() + args = parser.parse_args(modified_argv[1:]) # Skip program name; parse_args expects args without it + + # Unescape filter tokens that were escaped during sys.argv preprocessing + if args.filter: + marker_prefix = "@FILT_" + unescaped_filter = [] + for tok in args.filter: + # Unescape any tokens that were wrapped by preprocessing + if tok in _FILTER_ESCAPES: + unescaped_filter.append(_FILTER_ESCAPES[tok]) + else: + unescaped_filter.append(tok) + args.filter = unescaped_filter if not os.path.isdir(args.testvecDir): parser.error( -- GitLab From 39c85c2bc6e8960c9f89d7dab13c7013bd36b2a7 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Sat, 28 Mar 2026 15:43:17 +0100 Subject: [PATCH 16/30] extend filter formats and tighten output-format matching --- scripts/ivas_conformance/runConformance.py | 75 ++++++++++++++++++---- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index f33fa8fea..f92b78703 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -255,6 +255,29 @@ IVAS_Bins = { "ISAR": "ISAR_post_rend", } +DECODER_OUTPUT_FORMATS = { + "MONO", + "STEREO", + "BINAURAL", + "BINAURAL_ROOM_IR", + "BINAURAL_ROOM_REVERB", + "5_1", + "7_1", + "5_1_4", + "5_1_2", + "7_1_4", + "FOA", + "HOA2", + "HOA3", + "EXT", +} + +DECODER_OUTPUT_FORMAT_ALIASES = { + "HOA": {"HOA2", "HOA3"}, + "SBA": {"FOA", "HOA2", "HOA3"}, + "MC": {"5_1", "7_1", "5_1_4", "5_1_2", "7_1_4"}, +} + def validate_build_binaries(parser, build_path: str, build_label: str) -> None: """Validate that a build path exists and contains all IVAS binaries.""" @@ -1000,16 +1023,20 @@ class MLDConformance: values = self._extractKbpsValues(rawCmdline) return bool(values) and max(values) <= 80.0 - def _decoderFormatsInCommand(self, rawCmdline: str) -> set[str]: + def _outputFormatsInCommand(self, rawCmdline: str) -> set[str]: text = rawCmdline.upper() formats = set() - if "MONO" in text: - formats.add("MONO") - if "STEREO" in text: - formats.add("STEREO") + # Match format token between '_out_' and '_out' to avoid matching input-format words. + # Example: '..._48kHz_out_MONO_out_...' -> captures MONO only. + for match in re.finditer(r"_OUT_([A-Z0-9_]+?)_OUT(?:\b|_)", text): + fmt = match.group(1) + if fmt == "EXTERNAL": + fmt = "EXT" + if fmt in DECODER_OUTPUT_FORMATS: + formats.add(fmt) - # Avoid matching words like e.g. EXTENDED - do keying based on _OUT output only + # Avoid matching words like EXTENDED; key on EXT_OUT style output naming. if ( "_EXT_OUT" in text or "_EXTERNAL_OUT" in text @@ -1033,7 +1060,7 @@ class MLDConformance: return self._isBitrateAtMost80(rawCmdline) if tag == "DEC": - formats = self._decoderFormatsInCommand(rawCmdline) + formats = self._outputFormatsInCommand(rawCmdline) requested_formats = set(getattr(self.args, "filter_decoder_formats", [])) ext_ok = "EXT" in formats and self._isBitrateAtMost80(rawCmdline) @@ -1055,6 +1082,7 @@ class MLDConformance: restrictive_terms = getattr(self.args, "filter_restrictive_terms", []) additive_terms = getattr(self.args, "filter_add_terms", []) subtractive_terms = getattr(self.args, "filter_remove_terms", []) + requested_formats = set(getattr(self.args, "filter_decoder_formats", [])) # '-' terms always remove tests from the final selection. if subtractive_terms and self._matchesAnyTerm(rawCmdline, subtractive_terms): @@ -1064,8 +1092,13 @@ class MLDConformance: if level == "LEVEL1": passes_level = self._matchesLevel1(tag, rawCmdline) + passes_requested_formats = True + if tag in {"ENC", "DEC"} and requested_formats: + cmd_formats = self._outputFormatsInCommand(rawCmdline) + passes_requested_formats = bool(cmd_formats.intersection(requested_formats)) + passes_restrictive_terms = self._matchesAllTerms(rawCmdline, restrictive_terms) - base_selected = passes_level and passes_restrictive_terms + base_selected = passes_level and passes_restrictive_terms and passes_requested_formats if base_selected: return True @@ -1574,6 +1607,12 @@ class MLDConformance: keys = IVAS_Bins.keys() if selectTag == "all" else [selectTag] for tag in keys: if os.path.exists(self.BEcsv[tag]): + # For filtered runs it is valid to have zero selected tests for a tag. + # In that case the BE csv contains only the header; skip loadtxt to avoid warnings. + with open(self.BEcsv[tag], "r") as f: + non_empty_lines = [line for line in f if line.strip()] + if len(non_empty_lines) <= 1: + continue BEresult = np.loadtxt( self.BEcsv[tag], delimiter=",", @@ -1793,9 +1832,12 @@ if __name__ == "__main__": "(1) Level: LEVEL1, LEVEL3 (default: LEVEL3 = no restrictions). " "LEVEL1 restricts ENC to <=80 kbps and DEC to EXT<=80 kbps, MONO and STEREO outputs. " "(2) Tag: ENC, DEC, REND, ISAR, ISAR_ENC — selects specific test groups. " - "Under LEVEL1, +REND or +ISAR adds those groups to the default ENC+DEC set. " - "(3) Decoder format (LEVEL1 DEC only): EXT, MONO, STEREO — further restricts which " - "output formats are included within the already-restricted LEVEL1 DEC set. " + "Prefix with + to add groups and with - to remove groups at any level. " + "Under LEVEL1, the default tag baseline is ENC+DEC when no plain tag is provided. " + "(3) Output format (ENC/DEC): MONO, STEREO, BINAURAL, BINAURAL_ROOM_IR, " + "BINAURAL_ROOM_REVERB, 5_1, 7_1, 5_1_4, 5_1_2, 7_1_4, FOA, HOA2, HOA3, EXT. " + "Aliases: HOA -> HOA2+HOA3, SBA -> FOA+HOA2+HOA3, MC -> 5_1+7_1+5_1_4+5_1_2+7_1_4. " + "These tokens restrict ENC/DEC tests at any level by output format; under LEVEL1 they apply on top of LEVEL1 constraints. " "(4) Substring: any other plain token is matched case-insensitively against the test " "command line. Multiple plain tokens are combined with logical AND. " "Prefix a token with + to add matching tests to the selection, " @@ -1803,7 +1845,11 @@ if __name__ == "__main__": "Examples: " "'--filter LEVEL1' — run LEVEL1 ENC+DEC; " "'--filter LEVEL1 DEC MONO' — run only MONO tests from the LEVEL1 DEC set; " + "'--filter +REND -ISAR' — at default LEVEL3, add all REND tests and remove all ISAR tests; " "'--filter LEVEL1 +REND' — run LEVEL1 ENC+DEC and also all REND tests; " + "'--filter DEC HOA' — run DEC tests with HOA2/HOA3 outputs; " + "'--filter DEC SBA' — run DEC tests with FOA/HOA2/HOA3 outputs; " + "'--filter DEC MC' — run DEC tests with multichannel outputs (5_1, 7_1, 5_1_4, 5_1_2, 7_1_4); " "'--filter DEC JBM' — run DEC tests containing 'JBM'; " "'--filter DEC +BINAURAL' — run all DEC tests plus those containing 'BINAURAL'; " "'--filter DEC -voip' — run all DEC tests except those containing 'voip'." @@ -1877,7 +1923,9 @@ if __name__ == "__main__": valid_tags = set(IVAS_Bins.keys()) valid_levels = {"LEVEL1", "LEVEL2", "LEVEL3"} - valid_decoder_formats = {"EXT", "MONO", "STEREO"} + valid_decoder_formats = set(DECODER_OUTPUT_FORMATS).union( + DECODER_OUTPUT_FORMAT_ALIASES.keys() + ) level_tokens = [] tag_tokens = [] @@ -1909,12 +1957,13 @@ if __name__ == "__main__": else: tag_tokens.append(upper_tok) elif upper_tok in valid_decoder_formats: + expanded_formats = DECODER_OUTPUT_FORMAT_ALIASES.get(upper_tok, {upper_tok}) if sign == "+": additive_terms.append(base_tok) elif sign == "-": subtractive_terms.append(base_tok) else: - decoder_format_tokens.append(upper_tok) + decoder_format_tokens.extend(sorted(expanded_formats)) else: if sign == "+": additive_terms.append(base_tok) -- GitLab From f97ad09c8583024693c6f7aba495d5979561f9ce Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Mon, 30 Mar 2026 10:19:01 +0200 Subject: [PATCH 17/30] docs: fix LEVEL1 +REND +ISAR example (plain tag tokens replace baseline) --- scripts/ivas_conformance/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index 67d3fa292..0d70e6f6f 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -300,7 +300,7 @@ Examples: - LEVEL1 plus renderer and ISAR test groups ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 REND ISAR + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 +REND +ISAR ``` - LEVEL1 with additional case-insensitive command substring filtering -- GitLab From a6cb5f5033e82d070bda9ed71826fdbd35f56b69 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Mon, 30 Mar 2026 10:30:41 +0200 Subject: [PATCH 18/30] docs: make filter examples non-BE with ref_build_path and --analyse --- scripts/ivas_conformance/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index 0d70e6f6f..4e6cd7c23 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -283,46 +283,46 @@ When `--filter LEVEL1` is specified, the following default tests are run: - Add `+REND` and/or `+ISAR` in `--filter` to include them. - If `+ISAR` is provided, both `ISAR` and `ISAR_ENC` test groups are run. -Examples: +Examples (non-BE): - Default behavior (same as LEVEL3): run all tags/tests ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse ``` - LEVEL1 baseline (ENC+DEC with LEVEL1 restrictions) ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL1 ``` - LEVEL1 plus renderer and ISAR test groups ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 +REND +ISAR + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL1 +REND +ISAR ``` - LEVEL1 with additional case-insensitive command substring filtering ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 DEC voip + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL1 DEC voip ``` - LEVEL1 with additive BINAURAL decoder matching ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 +BINAURAL + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL1 +BINAURAL ``` - LEVEL1 with restrictive and additive terms together ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL1 DEC JBM +BINAURAL + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL1 DEC JBM +BINAURAL ``` - Unsupported LEVEL2 example (will fail) ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --cut_build_path=CUT_BIN_DIR --filter LEVEL2 + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL2 ``` -- GitLab From 6e860438d586816552f8fe20d2dbbc3cd7861d0a Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Mon, 30 Mar 2026 10:35:14 +0200 Subject: [PATCH 19/30] docs: refresh non-BE sample output block to current format --- scripts/ivas_conformance/README.md | 37 ++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index 4e6cd7c23..1c1c54b0b 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -166,7 +166,8 @@ No of tests : REND : 911 ISAR_ENC : 1032 ISAR : 1252 -Analysing tests for ENC (374 tests) +Analysing tests for ENC (374 tests): +--------------------------- ########################################################## <ENC> Total Frames: 3074220 @@ -180,8 +181,10 @@ Analysing tests for ENC (374 tests) <ENC> max absolute diff = 0.0, sample range (-32768, 32767) ########################################################## -MLD Corridor passed for ENC with max MLD diff of 0.0 -Analysing tests for DEC (638 tests) +[ENC] OK (ERRORS=0, BE=374, NON-BE=0, MLD CORRIDOR FAILURES=0) + +Analysing tests for DEC (638 tests): +--------------------------- ########################################################## <DEC> Total Frames: 5079252 @@ -195,8 +198,10 @@ Analysing tests for DEC (638 tests) <DEC> max absolute diff = 0.0, sample range (-32768, 32767) ########################################################## -MLD Corridor passed for DEC with max MLD diff of 0.0 -Analysing tests for REND (911 tests) +[DEC] OK (ERRORS=0, BE=638, NON-BE=0, MLD CORRIDOR FAILURES=0) + +Analysing tests for REND (911 tests): +--------------------------- ########################################################## <REND> Total Frames: 5576907 @@ -210,8 +215,10 @@ Analysing tests for REND (911 tests) <REND> max absolute diff = 0.0, sample range (-32768, 32767) ########################################################## -MLD Corridor passed for REND with max MLD diff of 0.0 -Analysing tests for ISAR_ENC (1032 tests) +[REND] OK (ERRORS=0, BE=911, NON-BE=0, MLD CORRIDOR FAILURES=0) + +Analysing tests for ISAR_ENC (1032 tests): +--------------------------- ########################################################## <ISAR_ENC> Total Frames: 2125956 @@ -225,8 +232,10 @@ Analysing tests for ISAR_ENC (1032 tests) <ISAR_ENC> max absolute diff = 0.0, sample range (-32768, 32767) ########################################################## -MLD Corridor passed for ISAR_ENC with max MLD diff of 0.0 -Analysing tests for ISAR (1252 tests) +[ISAR_ENC] OK (ERRORS=0, BE=1032, NON-BE=0, MLD CORRIDOR FAILURES=0) + +Analysing tests for ISAR (1252 tests): +--------------------------- ########################################################## <ISAR> Total Frames: 2590956 @@ -240,7 +249,15 @@ Analysing tests for ISAR (1252 tests) <ISAR> max absolute diff = 0.0, sample range (-32768, 32767) ########################################################## -MLD Corridor passed for ISAR with max MLD diff of 0.0 +[ISAR] OK (ERRORS=0, BE=1252, NON-BE=0, MLD CORRIDOR FAILURES=0) + +Summary of results: +--------------------- +[ENC] OK +[DEC] OK +[REND] OK +[ISAR_ENC] OK +[ISAR] OK -- GitLab From 4c0f489c3f2eb65a7cef30ee842f486c32fa6f42 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Mon, 30 Mar 2026 10:43:15 +0200 Subject: [PATCH 20/30] docs: update CUT/BE/non-BE output examples to current script format --- scripts/ivas_conformance/README.md | 122 +++++++++-------------------- 1 file changed, 38 insertions(+), 84 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index 1c1c54b0b..6270c1ccb 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -75,17 +75,27 @@ Accumulating commands from Readme_IVAS_enc.txt Accumulating commands from Readme_IVAS_ISAR_post_rend.txt Accumulating commands from Readme_IVAS_ISAR_dec.txt Accumulating commands from Readme_IVAS_JBM_dec.txt + No of tests : ENC : 381 DEC : 637 REND : 666 ISAR_ENC : 1032 ISAR : 1032 -Executing tests for ENC (381 tests) -Executing tests for DEC (637 tests) -Executing tests for REND (666 tests) -Executing tests for ISAR_ENC (1032 tests) -Executing tests for ISAR (1032 tests) + +Executing tests for ENC (381 tests): +--------------------------- +[ENC] OK + +... + +Summary of results: +--------------------- +[ENC] OK +[DEC] OK +[REND] OK +[ISAR_ENC] OK +[ISAR] OK @@ -108,7 +118,7 @@ If CUT test execution is done on a different platform, the scripts/CUT_OUTPUTS m ### Perform the BE comparison on the CUT outputs on reference platform -The BE comparison is performed to the CUT outputs using the command below. Encoded outputs will be decoded using the reference decoder executables as part of the process. The BE comparison is then performed between the CUT and reference decoded outputs. This includes comparison of ".wav"-files, and ".csv" and ".met" metadata files. If any non-BE results are observed, this is reported on the command-line and link to an analysis ".csv" file is given. The analysis file shows which exact files were non-BE. An example passing output is shown below. If all test sets print `PASSED BE TEST`, then CUT outputs are BE-conformant. +The BE comparison is performed to the CUT outputs using the command below. Encoded outputs are decoded using the reference decoder executables as part of the process. The BE comparison is then performed between the CUT and reference decoded outputs. This includes comparison of `.wav` files and `.csv`/`.met` metadata files. If non-BE results are observed, this is reported on the command line and in the generated analysis CSV output. ```shell PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --be-test @@ -123,29 +133,37 @@ Accumulating commands from Readme_IVAS_rend.txt Accumulating commands from Readme_IVAS_JBM_dec.txt Accumulating commands from Readme_IVAS_ISAR_dec.txt Accumulating commands from Readme_IVAS_ISAR_post_rend.txt + No of tests : ENC : 374 DEC : 638 REND : 911 ISAR_ENC : 1032 ISAR : 1252 -Analysing tests for ENC (374 tests) -<ENC> PASSED BE TEST -Analysing tests for DEC (638 tests) -<DEC> PASSED BE TEST -Analysing tests for REND (911 tests) -<REND> PASSED BE TEST -Analysing tests for ISAR_ENC (1032 tests) -<ISAR_ENC> PASSED BE TEST -Analysing tests for ISAR (1252 tests) -<ISAR> PASSED BE TEST + +Analysing tests for ENC (374 tests): +--------------------------- + +[ENC] OK (ERRORS=0, BE=374, NON-BE=0, MLD CORRIDOR FAILURES=0) +[DEC] OK (ERRORS=0, BE=638, NON-BE=0, MLD CORRIDOR FAILURES=0) + +... + +Summary of results: +--------------------- +[ENC] OK +[DEC] OK +[REND] OK +[ISAR_ENC] OK +[ISAR] OK ### Perform the MLD based non-BE analysis on the CUT outputs on reference platform (Ubuntu 24.04) -The MLD-based non-BE analysis is performed to the CUT outputs with the command below. Encoded outputs will be decoded using the reference decoder executables as part of the process. The MLD analysis is then performed between the CUT and reference decoded outputs (only ".wav" files are compared). Comparison to MLD corridor is also done as part of this process. An example passing output is shown below. If all test sets print `MLD Corridor passed for...` and there were no non-BE metadata comparisons in BE-test, then CUT outputs are Non-BE conformant. +The non-BE analysis below compares CUT and reference outputs by running MLD on audio (`.wav`) and, when MASA metadata are generated, for the matching reference/CUT `.met` files. For encoder tests, encoded CUT bitstreams are first decoded with the reference decoder before analysis. Per-frame MLD and MASA metadata values are written to `scripts/CUT_OUTPUTS` and checked against corridor references in `testvec/testv/mld_ref` (`mld_ref_.csv` and `masa_ref_.csv`). + ```shell PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse @@ -160,12 +178,14 @@ Accumulating commands from Readme_IVAS_rend.txt Accumulating commands from Readme_IVAS_JBM_dec.txt Accumulating commands from Readme_IVAS_ISAR_dec.txt Accumulating commands from Readme_IVAS_ISAR_post_rend.txt + No of tests : ENC : 374 DEC : 638 REND : 911 ISAR_ENC : 1032 ISAR : 1252 + Analysing tests for ENC (374 tests): --------------------------- @@ -183,73 +203,7 @@ Analysing tests for ENC (374 tests): [ENC] OK (ERRORS=0, BE=374, NON-BE=0, MLD CORRIDOR FAILURES=0) -Analysing tests for DEC (638 tests): ---------------------------- - -########################################################## -<DEC> Total Frames: 5079252 -<DEC> MAX MLD across all frames : 0.0 -<DEC> Frames with MLD == 0 : 5079252 frames (100.0%) -<DEC> Frames with MLD <= 0.5 : 5079252 frames (100.0%) -<DEC> Frames with MLD <= 1 : 5079252 frames (100.0%) -<DEC> Frames with MLD <= 2 : 5079252 frames (100.0%) -<DEC> Frames with MLD <= 5 : 5079252 frames (100.0%) -<DEC> BE samples percentage = 100.0 -<DEC> max absolute diff = 0.0, sample range (-32768, 32767) -########################################################## - -[DEC] OK (ERRORS=0, BE=638, NON-BE=0, MLD CORRIDOR FAILURES=0) - -Analysing tests for REND (911 tests): ---------------------------- - -########################################################## -<REND> Total Frames: 5576907 -<REND> MAX MLD across all frames : 0.0 -<REND> Frames with MLD == 0 : 5576907 frames (100.0%) -<REND> Frames with MLD <= 0.5 : 5576907 frames (100.0%) -<REND> Frames with MLD <= 1 : 5576907 frames (100.0%) -<REND> Frames with MLD <= 2 : 5576907 frames (100.0%) -<REND> Frames with MLD <= 5 : 5576907 frames (100.0%) -<REND> BE samples percentage = 100.0 -<REND> max absolute diff = 0.0, sample range (-32768, 32767) -########################################################## - -[REND] OK (ERRORS=0, BE=911, NON-BE=0, MLD CORRIDOR FAILURES=0) - -Analysing tests for ISAR_ENC (1032 tests): ---------------------------- - -########################################################## -<ISAR_ENC> Total Frames: 2125956 -<ISAR_ENC> MAX MLD across all frames : 0.0 -<ISAR_ENC> Frames with MLD == 0 : 2125956 frames (100.0%) -<ISAR_ENC> Frames with MLD <= 0.5 : 2125956 frames (100.0%) -<ISAR_ENC> Frames with MLD <= 1 : 2125956 frames (100.0%) -<ISAR_ENC> Frames with MLD <= 2 : 2125956 frames (100.0%) -<ISAR_ENC> Frames with MLD <= 5 : 2125956 frames (100.0%) -<ISAR_ENC> BE samples percentage = 100.0 -<ISAR_ENC> max absolute diff = 0.0, sample range (-32768, 32767) -########################################################## - -[ISAR_ENC] OK (ERRORS=0, BE=1032, NON-BE=0, MLD CORRIDOR FAILURES=0) - -Analysing tests for ISAR (1252 tests): ---------------------------- - -########################################################## -<ISAR> Total Frames: 2590956 -<ISAR> MAX MLD across all frames : 0.0 -<ISAR> Frames with MLD == 0 : 2590956 frames (100.0%) -<ISAR> Frames with MLD <= 0.5 : 2590956 frames (100.0%) -<ISAR> Frames with MLD <= 1 : 2590956 frames (100.0%) -<ISAR> Frames with MLD <= 2 : 2590956 frames (100.0%) -<ISAR> Frames with MLD <= 5 : 2590956 frames (100.0%) -<ISAR> BE samples percentage = 100.0 -<ISAR> max absolute diff = 0.0, sample range (-32768, 32767) -########################################################## - -[ISAR] OK (ERRORS=0, BE=1252, NON-BE=0, MLD CORRIDOR FAILURES=0) +... Summary of results: --------------------- -- GitLab From a11ffb8505c025675f48fc613c732f7d7f31f945 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Mon, 30 Mar 2026 14:52:33 +0200 Subject: [PATCH 21/30] conformance: treat --filter LEVEL3 as no-op full default set --- scripts/ivas_conformance/runConformance.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index f92b78703..f2e0a58d5 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1907,6 +1907,10 @@ if __name__ == "__main__": unescaped_filter.append(tok) args.filter = unescaped_filter + # Explicit LEVEL3 means no restrictions: keep default full tag set. + if args.filter and len(args.filter) == 1 and args.filter[0].upper() == "LEVEL3": + args.filter = None + if not os.path.isdir(args.testvecDir): parser.error( f"--testvecDir does not exist or is not a directory: {os.path.abspath(args.testvecDir)}" -- GitLab From 38b519393470d1d2152b595875bdf1ef14732371 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Mon, 30 Mar 2026 15:41:47 +0200 Subject: [PATCH 22/30] docs: use code fences for collapsible example output blocks --- scripts/ivas_conformance/README.md | 36 +++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index 6270c1ccb..58d4a2d54 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -68,7 +68,8 @@ PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDi
Example Output of CUT execution -

+
+```console
 Accumulating commands from Readme_IVAS_dec.txt
 Accumulating commands from Readme_IVAS_rend.txt   
 Accumulating commands from Readme_IVAS_enc.txt
@@ -96,7 +97,8 @@ Summary of results:
 [REND] OK
 [ISAR_ENC] OK
 [ISAR] OK
-
+``` +
This should generate outputs in scripts/CUT_OUTPUTS folder which looks like below:- @@ -126,7 +128,8 @@ PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDi
Example Output of BE comparison -

+
+```console
 Accumulating commands from Readme_IVAS_dec.txt
 Accumulating commands from Readme_IVAS_enc.txt
 Accumulating commands from Readme_IVAS_rend.txt
@@ -156,7 +159,8 @@ Summary of results:
 [REND] OK
 [ISAR_ENC] OK
 [ISAR] OK
-
+``` +
@@ -171,7 +175,8 @@ PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDi
Example Output of non-BE analysis -

+
+```console
 Accumulating commands from Readme_IVAS_dec.txt
 Accumulating commands from Readme_IVAS_enc.txt
 Accumulating commands from Readme_IVAS_rend.txt
@@ -190,15 +195,15 @@ Analysing tests for ENC  (374 tests):
 ---------------------------
 
 ##########################################################
-<ENC> Total Frames: 3074220
-<ENC> MAX MLD across all frames : 0.0
-<ENC> Frames with MLD == 0 : 3074220 frames (100.0%)
-<ENC> Frames with MLD <= 0.5 : 3074220 frames (100.0%)
-<ENC> Frames with MLD <= 1 : 3074220 frames (100.0%)
-<ENC> Frames with MLD <= 2 : 3074220 frames (100.0%)
-<ENC> Frames with MLD <= 5 : 3074220 frames (100.0%)
-<ENC> BE samples percentage = 100.0
-<ENC> max absolute diff = 0.0, sample range (-32768, 32767)
+ Total Frames: 3074220
+ MAX MLD across all frames : 0.0
+ Frames with MLD == 0 : 3074220 frames (100.0%)
+ Frames with MLD <= 0.5 : 3074220 frames (100.0%)
+ Frames with MLD <= 1 : 3074220 frames (100.0%)
+ Frames with MLD <= 2 : 3074220 frames (100.0%)
+ Frames with MLD <= 5 : 3074220 frames (100.0%)
+ BE samples percentage = 100.0
+ max absolute diff = 0.0, sample range (-32768, 32767)
 ##########################################################
 
 [ENC] OK (ERRORS=0, BE=374, NON-BE=0, MLD CORRIDOR FAILURES=0)
@@ -212,7 +217,8 @@ Summary of results:
 [REND] OK
 [ISAR_ENC] OK
 [ISAR] OK
-
+``` +
-- GitLab From 52c8ab256a599015c095fd213f7241c089c25cac Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Tue, 31 Mar 2026 10:00:50 +0200 Subject: [PATCH 23/30] Fix nested renderer output directories --- scripts/ivas_conformance/runConformance.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index f2e0a58d5..bc27803d0 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -390,6 +390,14 @@ class MLDConformance: os.makedirs(os.path.join(self.testvDir, odir), exist_ok=True) os.makedirs(os.path.join(self.outputDir, odir), exist_ok=True) + nested_subdirs = [ + os.path.join("renderer_short", "ref"), + os.path.join("split_rendering", "cut"), + os.path.join("split_rendering", "ref"), + ] + for odir in nested_subdirs: + os.makedirs(os.path.join(self.outputDir, odir), exist_ok=True) + self.logFile = os.path.join(self.outputDir, "runlog.txt") self.failedCmdsFile = os.path.join(self.outputDir, "failedCmds.txt") self.errorBlocksDir = os.path.join(self.outputDir, "error_blocks") -- GitLab From 432102387e88dd268fc93993d1e077b0e7f156b2 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Mon, 13 Apr 2026 10:13:06 +0200 Subject: [PATCH 24/30] support wildcard aliases in filter tokens --- scripts/ivas_conformance/runConformance.py | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index b8b62ff16..2f0842767 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1850,6 +1850,7 @@ if __name__ == "__main__": "(3) Output format (ENC/DEC): MONO, STEREO, BINAURAL, BINAURAL_ROOM_IR, " "BINAURAL_ROOM_REVERB, 5_1, 7_1, 5_1_4, 5_1_2, 7_1_4, FOA, HOA2, HOA3, EXT. " "Aliases: HOA -> HOA2+HOA3, SBA -> FOA+HOA2+HOA3, MC -> 5_1+7_1+5_1_4+5_1_2+7_1_4. " + "Wildcard prefixes are also supported for tags/formats (e.g., ISAR*, BINAURAL*). " "These tokens restrict ENC/DEC tests at any level by output format; under LEVEL1 they apply on top of LEVEL1 constraints. " "(4) Substring: any other plain token is matched case-insensitively against the test " "command line. Multiple plain tokens are combined with logical AND. " @@ -1863,6 +1864,8 @@ if __name__ == "__main__": "'--filter DEC HOA' — run DEC tests with HOA2/HOA3 outputs; " "'--filter DEC SBA' — run DEC tests with FOA/HOA2/HOA3 outputs; " "'--filter DEC MC' — run DEC tests with multichannel outputs (5_1, 7_1, 5_1_4, 5_1_2, 7_1_4); " + "'--filter ISAR*' — run ISAR and ISAR_ENC groups; " + "'--filter DEC BINAURAL*' — run DEC tests for all BINAURAL* output formats; " "'--filter DEC JBM' — run DEC tests containing 'JBM'; " "'--filter DEC +BINAURAL' — run all DEC tests plus those containing 'BINAURAL'; " "'--filter DEC -voip' — run all DEC tests except those containing 'voip'." @@ -1962,6 +1965,41 @@ if __name__ == "__main__": upper_tok = base_tok.upper() + # Prefix wildcard selection for tags and decoder output formats, e.g. ISAR*, BINAURAL*. + if upper_tok.endswith("*") and len(upper_tok) > 1: + prefix = upper_tok[:-1] + matched_tags = sorted(t for t in valid_tags if t.startswith(prefix)) + matched_format_tokens = sorted( + f for f in valid_decoder_formats if f.startswith(prefix) + ) + + if not matched_tags and not matched_format_tokens: + parser.error( + f"Wildcard token '{tok}' did not match any known tag or decoder output format." + ) + + if sign == "+": + tag_add_tokens.extend(matched_tags) + elif sign == "-": + tag_remove_tokens.extend(matched_tags) + else: + tag_tokens.extend(matched_tags) + + expanded_wildcard_formats = [] + for fmt in matched_format_tokens: + expanded_wildcard_formats.extend( + sorted(DECODER_OUTPUT_FORMAT_ALIASES.get(fmt, {fmt})) + ) + + if sign == "+": + additive_terms.extend(expanded_wildcard_formats) + elif sign == "-": + subtractive_terms.extend(expanded_wildcard_formats) + else: + decoder_format_tokens.extend(expanded_wildcard_formats) + + continue + if upper_tok in valid_levels: if sign: parser.error(f"Level token '{tok}' cannot be prefixed with '+' or '-'.") -- GitLab From 003c43da2fc10ae830376404ced743bfea1a1db3 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Wed, 15 Apr 2026 15:05:02 +0200 Subject: [PATCH 25/30] add LEVEL2 filter support and make non-ENC/DEC tags optional across levels --- scripts/ivas_conformance/README.md | 46 +++++++++-- scripts/ivas_conformance/runConformance.py | 88 ++++++++++++++-------- 2 files changed, 95 insertions(+), 39 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index 58d4a2d54..e15de67b3 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -224,12 +224,12 @@ Summary of results: ## Executing specific tests only -Use `--filter` to control test levels, tags and optional text/out_format filtering. +Use `--filter` to control test levels, tags or output format filtering. - Levels: - - `LEVEL3` (default): no level-based restrictions. + - `LEVEL3` (default): no bitrate restrictions. - `LEVEL1`: applies the restrictions below. - - `LEVEL2`: currently unsupported; script exits with an error. + - `LEVEL2`: same rules as `LEVEL1`, but with bitrate cap increased from 80 kbps to 192 kbps. - Tag selection (case-insensitive): `ENC`, `DEC`, `REND`, `ISAR`, `ISAR_ENC`. - Command substring filtering is case-insensitive. - Plain substring terms are restrictive and combined using logical AND. @@ -239,7 +239,11 @@ Use `--filter` to control test levels, tags and optional text/out_format filteri - `-TERM` removes matching tests from the selection. - Example: `--filter DEC -JBM` runs decoder tests except those containing `JBM`. -### LEVEL1 behavior +### LEVEL1, LEVEL2 and LEVEL3 behavior + +For all levels, the default tag baseline is `ENC` + `DEC`. +`REND`, `ISAR`, and `ISAR_ENC` are optional and are only included if explicitly selected +as plain tags or added via `+REND` and/or `+ISAR`. When `--filter LEVEL1` is specified, the following default tests are run: @@ -260,14 +264,38 @@ When `--filter LEVEL1` is specified, the following default tests are run: - Add `+REND` and/or `+ISAR` in `--filter` to include them. - If `+ISAR` is provided, both `ISAR` and `ISAR_ENC` test groups are run. +When `--filter LEVEL2` is specified, all selection rules above remain the same, +except bitrate caps are relaxed to 192 kbps: + +- Encoder (`ENC`) tests: only tests with bitrate up to 192 kbps (inclusive). +- Decoder (`DEC`) tests: + - `EXT` output format: only bitrate up to 192 kbps (inclusive). + - `MONO` output format: all bitrates. + - `STEREO` output format: all bitrates. + +When `--filter LEVEL3` is specified, all selection rules above remain the same, +with no bitrate caps: + +- Encoder (`ENC`) tests: all bitrates. +- Decoder (`DEC`) tests: + - `EXT` output format: all bitrates. + - `MONO` output format: all bitrates. + - `STEREO` output format: all bitrates. + Examples (non-BE): -- Default behavior (same as LEVEL3): run all tags/tests +- Default behavior (same as LEVEL3 baseline): run only ENC and DEC test groups ```shell PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse ``` +- LEVEL3 plus renderer and ISAR test groups + + ```shell + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL3 +REND +ISAR + ``` + - LEVEL1 baseline (ENC+DEC with LEVEL1 restrictions) ```shell @@ -298,8 +326,14 @@ Examples (non-BE): PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL1 DEC JBM +BINAURAL ``` -- Unsupported LEVEL2 example (will fail) +- LEVEL2 baseline (ENC+DEC with LEVEL2 restrictions) ```shell PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL2 ``` + +- LEVEL2 plus renderer and ISAR test groups + + ```shell + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL2 +REND +ISAR + ``` diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 2f0842767..22ad2274b 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1015,13 +1015,19 @@ class MLDConformance: values.append(float(match.replace("_", "."))) return values - def _isBitrateAtMost80(self, rawCmdline: str) -> bool: - """Check if all bitrates in command line are <= 80 kbps. - - For bitrate switching tests (e.g., 'from_32_kbps_to_96_kbps'), this checks - that the upper (target) bitrate does not exceed 80 kbps.""" + def _isBitrateAtMost(self, rawCmdline: str, max_kbps: float) -> bool: + """Check if all bitrates in command line are <= max_kbps. + + For bitrate switching tests (e.g., 'from_32_kbps_to_96_kbps'), this checks + that the upper (target) bitrate does not exceed max_kbps.""" values = self._extractKbpsValues(rawCmdline) - return bool(values) and max(values) <= 80.0 + return bool(values) and max(values) <= float(max_kbps) + + def _isBitrateAtMost80(self, rawCmdline: str) -> bool: + return self._isBitrateAtMost(rawCmdline, 80.0) + + def _isBitrateAtMost192(self, rawCmdline: str) -> bool: + return self._isBitrateAtMost(rawCmdline, 192.0) def _outputFormatsInCommand(self, rawCmdline: str) -> set[str]: text = rawCmdline.upper() @@ -1077,6 +1083,28 @@ class MLDConformance: # For REND/ISAR/ISAR_ENC under LEVEL1, tag-level inclusion is decided at testTags parsing. return True + def _matchesLevel2(self, tag: str, rawCmdline: str) -> bool: + if tag == "ENC": + return self._isBitrateAtMost192(rawCmdline) + + if tag == "DEC": + formats = self._outputFormatsInCommand(rawCmdline) + requested_formats = set(getattr(self.args, "filter_decoder_formats", [])) + + ext_ok = "EXT" in formats and self._isBitrateAtMost192(rawCmdline) + mono_ok = "MONO" in formats + stereo_ok = "STEREO" in formats + default_level2_dec_ok = ext_ok or mono_ok or stereo_ok + + if requested_formats: + # Plain decoder format tokens are restrictive under LEVEL2. + return default_level2_dec_ok and bool(formats.intersection(requested_formats)) + + return default_level2_dec_ok + + # For REND/ISAR/ISAR_ENC under LEVEL2, tag-level inclusion is decided at testTags parsing. + return True + def _testPassesFilter(self, tag: str, rawCmdline: str) -> bool: level = getattr(self.args, "filter_level", "LEVEL3") restrictive_terms = getattr(self.args, "filter_restrictive_terms", []) @@ -1091,6 +1119,8 @@ class MLDConformance: passes_level = True if level == "LEVEL1": passes_level = self._matchesLevel1(tag, rawCmdline) + elif level == "LEVEL2": + passes_level = self._matchesLevel2(tag, rawCmdline) passes_requested_formats = True if tag in {"ENC", "DEC"} and requested_formats: @@ -1842,8 +1872,9 @@ if __name__ == "__main__": metavar="TOKEN", help=( "Select which tests to run. Accepts any combination of the following tokens: " - "(1) Level: LEVEL1, LEVEL3 (default: LEVEL3 = no restrictions). " + "(1) Level: LEVEL1, LEVEL2, LEVEL3 (default: LEVEL3 = no bitrate restrictions). " "LEVEL1 restricts ENC to <=80 kbps and DEC to EXT<=80 kbps, MONO and STEREO outputs. " + "LEVEL2 uses the same rules as LEVEL1 but with <=192 kbps for ENC and DEC EXT. " "(2) Tag: ENC, DEC, REND, ISAR, ISAR_ENC — selects specific test groups. " "Prefix with + to add groups and with - to remove groups at any level. " "Under LEVEL1, the default tag baseline is ENC+DEC when no plain tag is provided. " @@ -1851,16 +1882,19 @@ if __name__ == "__main__": "BINAURAL_ROOM_REVERB, 5_1, 7_1, 5_1_4, 5_1_2, 7_1_4, FOA, HOA2, HOA3, EXT. " "Aliases: HOA -> HOA2+HOA3, SBA -> FOA+HOA2+HOA3, MC -> 5_1+7_1+5_1_4+5_1_2+7_1_4. " "Wildcard prefixes are also supported for tags/formats (e.g., ISAR*, BINAURAL*). " - "These tokens restrict ENC/DEC tests at any level by output format; under LEVEL1 they apply on top of LEVEL1 constraints. " + "These tokens restrict ENC/DEC tests at any level by output format; under LEVEL1/LEVEL2 they apply on top of level constraints. " "(4) Substring: any other plain token is matched case-insensitively against the test " "command line. Multiple plain tokens are combined with logical AND. " "Prefix a token with + to add matching tests to the selection, " "or with - to remove matching tests from the selection. " "Examples: " "'--filter LEVEL1' — run LEVEL1 ENC+DEC; " + "'--filter LEVEL2' — run LEVEL2 ENC+DEC; " "'--filter LEVEL1 DEC MONO' — run only MONO tests from the LEVEL1 DEC set; " - "'--filter +REND -ISAR' — at default LEVEL3, add all REND tests and remove all ISAR tests; " + "'--filter LEVEL2 DEC MONO' — run only MONO tests from the LEVEL2 DEC set; " + "'--filter +REND -ISAR' — at default LEVEL3 baseline (ENC+DEC), add all REND tests and remove all ISAR tests; " "'--filter LEVEL1 +REND' — run LEVEL1 ENC+DEC and also all REND tests; " + "'--filter LEVEL2 +REND' — run LEVEL2 ENC+DEC and also all REND tests; " "'--filter DEC HOA' — run DEC tests with HOA2/HOA3 outputs; " "'--filter DEC SBA' — run DEC tests with FOA/HOA2/HOA3 outputs; " "'--filter DEC MC' — run DEC tests with multichannel outputs (5_1, 7_1, 5_1_4, 5_1_2, 7_1_4); " @@ -1923,7 +1957,7 @@ if __name__ == "__main__": unescaped_filter.append(tok) args.filter = unescaped_filter - # Explicit LEVEL3 means no restrictions: keep default full tag set. + # Explicit LEVEL3 means default level behavior (same as no explicit level token). if args.filter and len(args.filter) == 1 and args.filter[0].upper() == "LEVEL3": args.filter = None @@ -2031,8 +2065,6 @@ if __name__ == "__main__": parser.error("Multiple filter levels specified. Use only one of LEVEL1, LEVEL2, LEVEL3.") filter_level = level_tokens[0] if level_tokens else "LEVEL3" - if filter_level == "LEVEL2": - parser.error("--filter LEVEL2 is currently unsupported.") # Preserve order while removing duplicates. tag_tokens = list(dict.fromkeys(tag_tokens)) @@ -2048,28 +2080,18 @@ if __name__ == "__main__": if "ISAR" in tag_remove_tokens and "ISAR_ENC" not in tag_remove_tokens: tag_remove_tokens.append("ISAR_ENC") - if filter_level == "LEVEL1": - # LEVEL1 baseline: ENC + DEC; REND/ISAR only if explicitly requested. - # Plain tag_tokens restrict the baseline; +tag_tokens add beyond it. - if tag_tokens: - selected_tag_set = set(tag_tokens) - else: - selected_tag_set = {"ENC", "DEC"} - for tag in tag_add_tokens: - selected_tag_set.add(tag) - for tag in tag_remove_tokens: - selected_tag_set.discard(tag) - testTags = [tag for tag in IVAS_Bins.keys() if tag in selected_tag_set] + # All levels share the same default tag baseline: ENC + DEC. + # REND/ISAR/ISAR_ENC are optional and must be explicitly selected or added. + # Plain tag_tokens restrict the baseline; +tag_tokens add beyond it. + if tag_tokens: + selected_tag_set = set(tag_tokens) else: - if tag_tokens: - selected_tag_set = set(tag_tokens) - else: - selected_tag_set = set(IVAS_Bins.keys()) - for tag in tag_add_tokens: - selected_tag_set.add(tag) - for tag in tag_remove_tokens: - selected_tag_set.discard(tag) - testTags = [tag for tag in IVAS_Bins.keys() if tag in selected_tag_set] + selected_tag_set = {"ENC", "DEC"} + for tag in tag_add_tokens: + selected_tag_set.add(tag) + for tag in tag_remove_tokens: + selected_tag_set.discard(tag) + testTags = [tag for tag in IVAS_Bins.keys() if tag in selected_tag_set] args.filter_display = raw_filter if raw_filter else None args.filter_restrictive_terms = restrictive_terms -- GitLab From e360320fe26a24264e6a61d68a8c00b961a2c578 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Wed, 15 Apr 2026 15:13:56 +0200 Subject: [PATCH 26/30] fix process() return type in dryrun path when returnOutput=True --- scripts/ivas_conformance/runConformance.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 22ad2274b..a597c6ce0 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1362,7 +1362,7 @@ class MLDConformance: contextPrefix: str = "", emitConsole: bool = True, returnOutput: bool = False, - ) -> int: + ) -> Union[int, Tuple[int, str]]: contextPrefix = contextPrefix or (f"[{tag}]" if tag else "") return self._process( command, @@ -1381,12 +1381,14 @@ class MLDConformance: contextPrefix: str = "", emitConsole: bool = True, returnOutput: bool = False, - ) -> int: + ) -> Union[int, Tuple[int, str]]: prefix = (contextPrefix + " ") if contextPrefix else "" if self.args.verbose and emitConsole: print(f"{prefix}Command: {command}", flush=True) if self.args.dryrun: self.appendRunlog(command=command) + if returnOutput: + return 0, "" return 0 c = subprocess.run( -- GitLab From 190b85c4313f92e0527ffc169f3599d114ab4d7e Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Wed, 15 Apr 2026 15:17:51 +0200 Subject: [PATCH 27/30] improve --filter help text readability with sections and examples --- scripts/ivas_conformance/runConformance.py | 50 ++++++++-------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index a597c6ce0..d0d25bc97 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1873,38 +1873,24 @@ if __name__ == "__main__": default=None, metavar="TOKEN", help=( - "Select which tests to run. Accepts any combination of the following tokens: " - "(1) Level: LEVEL1, LEVEL2, LEVEL3 (default: LEVEL3 = no bitrate restrictions). " - "LEVEL1 restricts ENC to <=80 kbps and DEC to EXT<=80 kbps, MONO and STEREO outputs. " - "LEVEL2 uses the same rules as LEVEL1 but with <=192 kbps for ENC and DEC EXT. " - "(2) Tag: ENC, DEC, REND, ISAR, ISAR_ENC — selects specific test groups. " - "Prefix with + to add groups and with - to remove groups at any level. " - "Under LEVEL1, the default tag baseline is ENC+DEC when no plain tag is provided. " - "(3) Output format (ENC/DEC): MONO, STEREO, BINAURAL, BINAURAL_ROOM_IR, " - "BINAURAL_ROOM_REVERB, 5_1, 7_1, 5_1_4, 5_1_2, 7_1_4, FOA, HOA2, HOA3, EXT. " - "Aliases: HOA -> HOA2+HOA3, SBA -> FOA+HOA2+HOA3, MC -> 5_1+7_1+5_1_4+5_1_2+7_1_4. " - "Wildcard prefixes are also supported for tags/formats (e.g., ISAR*, BINAURAL*). " - "These tokens restrict ENC/DEC tests at any level by output format; under LEVEL1/LEVEL2 they apply on top of level constraints. " - "(4) Substring: any other plain token is matched case-insensitively against the test " - "command line. Multiple plain tokens are combined with logical AND. " - "Prefix a token with + to add matching tests to the selection, " - "or with - to remove matching tests from the selection. " - "Examples: " - "'--filter LEVEL1' — run LEVEL1 ENC+DEC; " - "'--filter LEVEL2' — run LEVEL2 ENC+DEC; " - "'--filter LEVEL1 DEC MONO' — run only MONO tests from the LEVEL1 DEC set; " - "'--filter LEVEL2 DEC MONO' — run only MONO tests from the LEVEL2 DEC set; " - "'--filter +REND -ISAR' — at default LEVEL3 baseline (ENC+DEC), add all REND tests and remove all ISAR tests; " - "'--filter LEVEL1 +REND' — run LEVEL1 ENC+DEC and also all REND tests; " - "'--filter LEVEL2 +REND' — run LEVEL2 ENC+DEC and also all REND tests; " - "'--filter DEC HOA' — run DEC tests with HOA2/HOA3 outputs; " - "'--filter DEC SBA' — run DEC tests with FOA/HOA2/HOA3 outputs; " - "'--filter DEC MC' — run DEC tests with multichannel outputs (5_1, 7_1, 5_1_4, 5_1_2, 7_1_4); " - "'--filter ISAR*' — run ISAR and ISAR_ENC groups; " - "'--filter DEC BINAURAL*' — run DEC tests for all BINAURAL* output formats; " - "'--filter DEC JBM' — run DEC tests containing 'JBM'; " - "'--filter DEC +BINAURAL' — run all DEC tests plus those containing 'BINAURAL'; " - "'--filter DEC -voip' — run all DEC tests except those containing 'voip'." + "Select which tests to run. Default baseline: ENC+DEC tests.\n" + "\n" + "TOKEN TYPES:\n" + " LEVEL1, LEVEL2, LEVEL3 — Test level (default: LEVEL3). LEVEL1: ≤80 kbps; LEVEL2: ≤192 kbps; LEVEL3: unlimited.\n" + " ENC, DEC, REND, ISAR* — Test groups (∗=optional). Prefix +/- to add/remove.\n" + " MONO, STEREO, EXT, HOA*, SBA, MC — Output format (ENC/DEC only). Aliases: HOA→HOA2+HOA3, SBA→FOA+HOA2+HOA3, MC→{5_1,7_1,…}.\n" + " (other) — Substring (case-insensitive, matched against command). Multiple terms use AND logic. Prefix +/- to add/remove.\n" + " *, +*, -* — Wildcard tags/formats (e.g., ISAR*, BINAURAL*). Prefix +/- to add/remove.\n" + "\n" + "EXAMPLES:\n" + " --filter LEVEL1 Run LEVEL1 ENC+DEC (≤80 kbps).\n" + " --filter LEVEL2 Run LEVEL2 ENC+DEC (≤192 kbps).\n" + " --filter LEVEL1 DEC MONO Run LEVEL1 DEC MONO tests only.\n" + " --filter +REND +ISAR Add REND and ISAR to default ENC+DEC.\n" + " --filter DEC HOA Run DEC tests with HOA2/HOA3 outputs.\n" + " --filter DEC +BINAURAL Run all LEVEL3 DEC tests plus BINAURAL variant matches.\n" + " --filter DEC JBM +BINAURAL Run JBM DEC tests + BINAURAL-variant tests.\n" + " --filter DEC -voip Run all LEVEL3 DEC tests except those matching 'voip'.\n" ), ) parser.add_argument( -- GitLab From 950b130fe8ca21996ff3156bac7fae03b438b452 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Wed, 15 Apr 2026 15:19:41 +0200 Subject: [PATCH 28/30] preserve newlines in --filter help using RawTextHelpFormatter --- scripts/ivas_conformance/runConformance.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index d0d25bc97..4309a6ccd 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1821,7 +1821,8 @@ class MLDConformance: if __name__ == "__main__": parser = argparse.ArgumentParser( - description="Compare .wav files in two folders using mld per frame" + description="Compare .wav files in two folders using mld per frame", + formatter_class=argparse.RawTextHelpFormatter, ) parser.add_argument( -- GitLab From e9df032cf9fdb83d999d5be61b88b3a587f6afdd Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Wed, 15 Apr 2026 15:27:21 +0200 Subject: [PATCH 29/30] improve --filter help: separate token types, modifiers, and add wildcard examples --- scripts/ivas_conformance/runConformance.py | 34 +++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 4309a6ccd..3ee4b151d 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1874,24 +1874,30 @@ if __name__ == "__main__": default=None, metavar="TOKEN", help=( - "Select which tests to run. Default baseline: ENC+DEC tests.\n" + "Select which tests to run. Default baseline: ENC+DEC tests (REND/ISAR optional).\n" "\n" "TOKEN TYPES:\n" - " LEVEL1, LEVEL2, LEVEL3 — Test level (default: LEVEL3). LEVEL1: ≤80 kbps; LEVEL2: ≤192 kbps; LEVEL3: unlimited.\n" - " ENC, DEC, REND, ISAR* — Test groups (∗=optional). Prefix +/- to add/remove.\n" - " MONO, STEREO, EXT, HOA*, SBA, MC — Output format (ENC/DEC only). Aliases: HOA→HOA2+HOA3, SBA→FOA+HOA2+HOA3, MC→{5_1,7_1,…}.\n" - " (other) — Substring (case-insensitive, matched against command). Multiple terms use AND logic. Prefix +/- to add/remove.\n" - " *, +*, -* — Wildcard tags/formats (e.g., ISAR*, BINAURAL*). Prefix +/- to add/remove.\n" + " LEVEL1, LEVEL2, LEVEL3 — Conformance level. LEVEL1: ≤80 kbps; LEVEL2: ≤192 kbps; LEVEL3: unlimited (default).\n" + " ENC, DEC, REND, ISAR, ISAR_ENC — Test groups (ENC+DEC are baseline; REND/ISAR optional).\n" + " MONO, STEREO, EXT, HOA, SBA, MC — Output formats (ENC/DEC only). Aliases: HOA→{HOA2,HOA3}, SBA→{FOA,HOA2,HOA3}, MC→{5_1,7_1,5_1_4,5_1_2,7_1_4}.\n" + " (any other) — Substring match (case-insensitive). Multiple terms combine with AND.\n" + "\n" + "TOKEN MODIFIERS:\n" + " +TOKEN — Add matching tests to selection (even if they would be excluded).\n" + " -TOKEN — Remove matching tests from selection.\n" + " TOKEN* — Wildcard: match all tokens starting with TOKEN (e.g., ISAR* → {ISAR, ISAR_ENC}; BINAURAL* → {BINAURAL, BINAURAL_IR, BINAURAL_ROOM_IR, ...}).\n" + " +TOKEN*, -TOKEN* — Wildcard with add/remove modifiers (e.g., +ISAR*, -BINAURAL*).\n" "\n" "EXAMPLES:\n" - " --filter LEVEL1 Run LEVEL1 ENC+DEC (≤80 kbps).\n" - " --filter LEVEL2 Run LEVEL2 ENC+DEC (≤192 kbps).\n" - " --filter LEVEL1 DEC MONO Run LEVEL1 DEC MONO tests only.\n" - " --filter +REND +ISAR Add REND and ISAR to default ENC+DEC.\n" - " --filter DEC HOA Run DEC tests with HOA2/HOA3 outputs.\n" - " --filter DEC +BINAURAL Run all LEVEL3 DEC tests plus BINAURAL variant matches.\n" - " --filter DEC JBM +BINAURAL Run JBM DEC tests + BINAURAL-variant tests.\n" - " --filter DEC -voip Run all LEVEL3 DEC tests except those matching 'voip'.\n" + " --filter LEVEL1 Run LEVEL1 ENC+DEC (≤80 kbps).\n" + " --filter LEVEL2 Run LEVEL2 ENC+DEC (≤192 kbps).\n" + " --filter LEVEL1 DEC MONO Restrict to DEC MONO tests at LEVEL1.\n" + " --filter +REND +ISAR Add REND and ISAR to baseline ENC+DEC.\n" + " --filter DEC HOA Run DEC tests with HOA2/HOA3 outputs.\n" + " --filter DEC -voip Run DEC tests except those matching 'voip'.\n" + " --filter ISAR* Add ISAR and ISAR_ENC (wildcard expansion).\n" + " --filter DEC +BINAURAL* Run LEVEL3 DEC + all BINAURAL variant outputs.\n" + " --filter +ISAR* -voip Add ISAR/ISAR_ENC groups then remove 'voip' tests.\n" ), ) parser.add_argument( -- GitLab From 15461140ec0405a1b8aa161628f5635b1b6ea942 Mon Sep 17 00:00:00 2001 From: Vladimir Malenovsky Date: Wed, 15 Apr 2026 15:59:05 +0200 Subject: [PATCH 30/30] align filter terminology and ISAR selection docs --- scripts/ivas_conformance/README.md | 62 ++++++++++------------ scripts/ivas_conformance/runConformance.py | 20 +++---- 2 files changed, 34 insertions(+), 48 deletions(-) diff --git a/scripts/ivas_conformance/README.md b/scripts/ivas_conformance/README.md index e15de67b3..6f57b4d11 100644 --- a/scripts/ivas_conformance/README.md +++ b/scripts/ivas_conformance/README.md @@ -224,26 +224,27 @@ Summary of results: ## Executing specific tests only -Use `--filter` to control test levels, tags or output format filtering. - -- Levels: - - `LEVEL3` (default): no bitrate restrictions. - - `LEVEL1`: applies the restrictions below. - - `LEVEL2`: same rules as `LEVEL1`, but with bitrate cap increased from 80 kbps to 192 kbps. -- Tag selection (case-insensitive): `ENC`, `DEC`, `REND`, `ISAR`, `ISAR_ENC`. -- Command substring filtering is case-insensitive. -- Plain substring terms are restrictive and combined using logical AND. - - Example: `--filter DEC JBM` runs only decoder tests that contain `JBM`. -- `+TERM` adds matching tests to the selection. - - Example: `--filter LEVEL1 DEC +JBM` adds all `JBM` decoder tests to the default `LEVEL1 DEC` selection. -- `-TERM` removes matching tests from the selection. - - Example: `--filter DEC -JBM` runs decoder tests except those containing `JBM`. +Use `--filter TOKEN` to control conformance level, test groups, output formats, and substring matching. + +- Token types: + - `LEVEL1`, `LEVEL2`, `LEVEL3`: conformance levels. `LEVEL3` is the default. + - `ENC`, `DEC`, `REND`, `ISAR`, `ISAR_ENC`: test groups. + - `MONO`, `STEREO`, `EXT`, `HOA`, `SBA`, `MC`: output-format tokens. + - `HOA` expands to `HOA2`, `HOA3`. + - `SBA` expands to `FOA`, `HOA2`, `HOA3`. + - `MC` expands to `5_1`, `7_1`, `5_1_4`, `5_1_2`, `7_1_4`. + - Any other token is treated as a case-insensitive substring match. +- Token modifiers: + - `TOKEN`: restrictive token. Multiple restrictive tokens combine with logical AND. + - `+TOKEN`: additive token. Adds matching tests even if they would otherwise be excluded. + - `-TOKEN`: subtractive token. Removes matching tests from the final selection. + - `TOKEN*`: wildcard token. Matches all known tokens starting with the given prefix. + - `+TOKEN*`, `-TOKEN*`: wildcard token with add/remove behavior. ### LEVEL1, LEVEL2 and LEVEL3 behavior -For all levels, the default tag baseline is `ENC` + `DEC`. -`REND`, `ISAR`, and `ISAR_ENC` are optional and are only included if explicitly selected -as plain tags or added via `+REND` and/or `+ISAR`. +For all levels, the default test-group baseline is `ENC` + `DEC`. +`REND`, `ISAR`, and `ISAR_ENC` are optional and are only included if explicitly selected as plain test-group tokens or added via `+REND`, `+ISAR`, `+ISAR_ENC`, or `+ISAR*`. When `--filter LEVEL1` is specified, the following default tests are run: @@ -253,19 +254,19 @@ When `--filter LEVEL1` is specified, the following default tests are run: - `MONO` output format: all bitrates. - `STEREO` output format: all bitrates. -- The default `LEVEL1` tests may be restricted by adding more terms (acting as logical AND). +- The default `LEVEL1` tests may be restricted by adding more tokens (acting as logical AND). - Example: `--filter LEVEL1 DEC MONO` keeps only `MONO` tests from the LEVEL1-eligible DEC set. - Example: `--filter LEVEL1 JBM` keeps all LEVEL1-eligible ENC tests but only JBM tests from the LEVEL1-eligible DEC tests. -- `+TERM` adds tests to the final LEVEL1 selection, even if they would otherwise be restricted. +- `+TOKEN` adds tests to the final LEVEL1 selection, even if they would otherwise be restricted. - Example: `--filter LEVEL1 DEC JBM +BINAURAL` runs only JBM-matching LEVEL1 DEC tests and additionally includes DEC tests containing `BINAURAL` keyword, i.e. `BINAURAL`, `BINAURAL_IR`, `BINAURAL_ROOM_IR`, `BINAURAL_REVERB`. -- `-TERM` removes matching tests from the final LEVEL1 selection (including tests added via `+TERM`). +- `-TOKEN` removes matching tests from the final LEVEL1 selection (including tests added via `+TOKEN`). - Example: `--filter LEVEL1 DEC +JBM -VOIP` adds JBM-matching DEC tests and then excludes any DEC tests containing the keyword `VOIP`. - Renderer and ISAR tests are not run by default in `LEVEL1`. - - Add `+REND` and/or `+ISAR` in `--filter` to include them. - - If `+ISAR` is provided, both `ISAR` and `ISAR_ENC` test groups are run. + - Add `+REND`, `+ISAR`, and/or `+ISAR_ENC` in `--filter` to include them. + - Use `+ISAR*` if you want wildcard expansion across all `ISAR*`-prefixed test-group tokens. When `--filter LEVEL2` is specified, all selection rules above remain the same, -except bitrate caps are relaxed to 192 kbps: +except the bitrate cap is set to 192 kbps: - Encoder (`ENC`) tests: only tests with bitrate up to 192 kbps (inclusive). - Decoder (`DEC`) tests: @@ -273,14 +274,7 @@ except bitrate caps are relaxed to 192 kbps: - `MONO` output format: all bitrates. - `STEREO` output format: all bitrates. -When `--filter LEVEL3` is specified, all selection rules above remain the same, -with no bitrate caps: - -- Encoder (`ENC`) tests: all bitrates. -- Decoder (`DEC`) tests: - - `EXT` output format: all bitrates. - - `MONO` output format: all bitrates. - - `STEREO` output format: all bitrates. +When `--filter LEVEL3` is specified, there are no restrictions on the bitrate or output formats. Examples (non-BE): @@ -293,7 +287,7 @@ Examples (non-BE): - LEVEL3 plus renderer and ISAR test groups ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL3 +REND +ISAR + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL3 +REND +ISAR +ISAR_ENC ``` - LEVEL1 baseline (ENC+DEC with LEVEL1 restrictions) @@ -305,7 +299,7 @@ Examples (non-BE): - LEVEL1 plus renderer and ISAR test groups ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL1 +REND +ISAR + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL1 +REND +ISAR +ISAR_ENC ``` - LEVEL1 with additional case-insensitive command substring filtering @@ -335,5 +329,5 @@ Examples (non-BE): - LEVEL2 plus renderer and ISAR test groups ```shell - PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL2 +REND +ISAR + PYTHONPATH=scripts python scripts/ivas_conformance/runConformance.py --testvecDir $PWD/testvec --ref_build_path=testvec/bin --analyse --filter LEVEL2 +REND +ISAR +ISAR_ENC ``` diff --git a/scripts/ivas_conformance/runConformance.py b/scripts/ivas_conformance/runConformance.py index 3ee4b151d..d066a3092 100644 --- a/scripts/ivas_conformance/runConformance.py +++ b/scripts/ivas_conformance/runConformance.py @@ -1123,7 +1123,7 @@ class MLDConformance: passes_level = self._matchesLevel2(tag, rawCmdline) passes_requested_formats = True - if tag in {"ENC", "DEC"} and requested_formats: + if requested_formats: cmd_formats = self._outputFormatsInCommand(rawCmdline) passes_requested_formats = bool(cmd_formats.intersection(requested_formats)) @@ -1876,19 +1876,19 @@ if __name__ == "__main__": help=( "Select which tests to run. Default baseline: ENC+DEC tests (REND/ISAR optional).\n" "\n" - "TOKEN TYPES:\n" + "Token types:\n" " LEVEL1, LEVEL2, LEVEL3 — Conformance level. LEVEL1: ≤80 kbps; LEVEL2: ≤192 kbps; LEVEL3: unlimited (default).\n" - " ENC, DEC, REND, ISAR, ISAR_ENC — Test groups (ENC+DEC are baseline; REND/ISAR optional).\n" - " MONO, STEREO, EXT, HOA, SBA, MC — Output formats (ENC/DEC only). Aliases: HOA→{HOA2,HOA3}, SBA→{FOA,HOA2,HOA3}, MC→{5_1,7_1,5_1_4,5_1_2,7_1_4}.\n" + " ENC, DEC, REND, ISAR, ISAR_ENC — Test groups.\n" + " MONO, STEREO, EXT, HOA, SBA, MC — Output formats. Aliases: HOA→{HOA2,HOA3}, SBA→{FOA,HOA2,HOA3}, MC→{5_1,7_1,5_1_4,5_1_2,7_1_4}.\n" " (any other) — Substring match (case-insensitive). Multiple terms combine with AND.\n" "\n" - "TOKEN MODIFIERS:\n" + "Token modifiers:\n" " +TOKEN — Add matching tests to selection (even if they would be excluded).\n" " -TOKEN — Remove matching tests from selection.\n" " TOKEN* — Wildcard: match all tokens starting with TOKEN (e.g., ISAR* → {ISAR, ISAR_ENC}; BINAURAL* → {BINAURAL, BINAURAL_IR, BINAURAL_ROOM_IR, ...}).\n" " +TOKEN*, -TOKEN* — Wildcard with add/remove modifiers (e.g., +ISAR*, -BINAURAL*).\n" "\n" - "EXAMPLES:\n" + "Examples:\n" " --filter LEVEL1 Run LEVEL1 ENC+DEC (≤80 kbps).\n" " --filter LEVEL2 Run LEVEL2 ENC+DEC (≤192 kbps).\n" " --filter LEVEL1 DEC MONO Restrict to DEC MONO tests at LEVEL1.\n" @@ -2067,14 +2067,6 @@ if __name__ == "__main__": tag_remove_tokens = list(dict.fromkeys(tag_remove_tokens)) decoder_format_tokens = list(dict.fromkeys(decoder_format_tokens)) - # If ISAR is requested/added/removed, apply same action to ISAR_ENC. - if "ISAR" in tag_tokens and "ISAR_ENC" not in tag_tokens: - tag_tokens.append("ISAR_ENC") - if "ISAR" in tag_add_tokens and "ISAR_ENC" not in tag_add_tokens: - tag_add_tokens.append("ISAR_ENC") - if "ISAR" in tag_remove_tokens and "ISAR_ENC" not in tag_remove_tokens: - tag_remove_tokens.append("ISAR_ENC") - # All levels share the same default tag baseline: ENC + DEC. # REND/ISAR/ISAR_ENC are optional and must be explicitly selected or added. # Plain tag_tokens restrict the baseline; +tag_tokens add beyond it. -- GitLab