diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d1a34b194ae8c139e5d62426e62cbb8368050881..c92459d23910b9d5233536516a3e66ef675d69a8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -658,6 +658,32 @@ clang-format-check: name: "$ARTIFACT_BASE_NAME" expose_as: 'formatting patch' +# check for crashes if first received frame on decoder side is an SID +check-first-frame-is-sid: + extends: + - .test-job-linux-needs-testv-dir + - .rules-merge-request + tags: + - ivas-linux + stage: test + needs: ["build-codec-linux-cmake"] + script: + - *print-common-info + - *update-ltv-repo + - cmake . + - make -j + + # TODO: for some MASA modes, we currently do not have testvectors that actually trigger DTX + - modes=$(scripts/runIvasCodec.py -l | grep dtx | grep -v MASA) + - echo $modes + - scripts/runIvasCodec.py -p scripts/config/ci_linux_sidstart_test.json -m $modes -s --bs_length 500 + artifacts: + paths: + - out/logs + when: on_failure + name: "$CI_JOB_NAME--$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--sidstart" + expose_as: "logs-sidstart" + # --------------------------------------------------------------- # Test jobs for main branch # --------------------------------------------------------------- diff --git a/scripts/config/ci_linux_sidstart_test.json b/scripts/config/ci_linux_sidstart_test.json new file mode 100644 index 0000000000000000000000000000000000000000..3436d9eaea7fe55a06f705250065e3e1c4930e07 --- /dev/null +++ b/scripts/config/ci_linux_sidstart_test.json @@ -0,0 +1,25 @@ +{ + "afspPath": "not_needed", + "utilPath": "/tools", + "inpaths": { + "MONO": "/usr/local/testv/test_mono.wav", + "STEREO": "/usr/local/testv/test_stereo.wav", + "FOA": "/usr/local/ltv/ltv48_FOA.wav", + "HOA2": "/usr/local/ltv/ltv48_HOA2.wav", + "HOA3": "/usr/local/ltv/ltv48_HOA3.wav", + "SBA": "/usr/local/ltv/ltv48_HOA3.wav", + "MASA1TC1DIR": "/usr/local/testv/test_MASA_1dir1TC.wav", + "MASA1TC2DIR": "/usr/local/testv/test_MASA_2dir1TC.wav", + "MASA2TC1DIR": "/usr/local/testv/test_MASA_1dir2TC.wav", + "MASA2TC2DIR": "/usr/local/testv/test_MASA_2dir2TC.wav", + "5_1": "/usr/local/testv/test_MC51.wav", + "5_1_2": "/usr/local/testv/test_MC51p2.wav", + "5_1_4": "/usr/local/testv/test_MC51p4.wav", + "7_1": "/usr/local/testv/test_MC71.wav", + "7_1_4": "/usr/local/testv/test_MC71p4.wav", + "ISM1": "/usr/local/testv/test_mono.wav", + "ISM2": "/usr/local/testv/test_ISM_2obj.wav", + "ISM3": "/usr/local/testv/test_ISM_3obj.wav", + "ISM4": "/usr/local/testv/test_ISM_4obj.wav" + } +} diff --git a/scripts/cut_bs.py b/scripts/cut_bs.py index c0ae6e19330bd70f8e04ee7e67a56e062689043d..4986ccec21ecbe7cf73b8ffd444de75b52cb42b1 100755 --- a/scripts/cut_bs.py +++ b/scripts/cut_bs.py @@ -35,12 +35,32 @@ import argparse import os.path import sys -#SID_BITS = {35, 48, 88, 100} SID_BITS = {35, 48, 104} SYNC_WORDS = {b"!k", b" k"} -def cut_bs(fp, fp_out, start_frame = 0, start_with_sid = False): +def cut_to_length(fp, fp_out, length): + assert length > 0 + + fr_cnt = 0 + + for f in range(length): + sync_word = fp.read(2) + if sync_word == b"": + return fr_cnt + if sync_word not in SYNC_WORDS: + raise ValueError("Bad Sync word!") + n_bits_bs = fp.read(2) + n_bits = struct.unpack("h", n_bits_bs)[0] + fp_out.write(sync_word) + fp_out.write(n_bits_bs) + fp_out.write(fp.read(n_bits * 2)) + fr_cnt += 1 + + return fr_cnt + + +def cut_from_start(fp, fp_out, start_frame=0, start_with_sid=False): # cut until start frame fr_cnt = 0 cut_cnt = 0 @@ -92,14 +112,15 @@ def cut_bs(fp, fp_out, start_frame = 0, start_with_sid = False): if __name__ == "__main__": my_parser = argparse.ArgumentParser( - description="Cut frames from the beginning of a G.192 bit stream file" + description="Cut a G.192 bit stream file" ) my_parser.add_argument( - "--sid", "-s", help="Cut until the first SID frame", action="store_true" + "--sid", "-s", help="Cut away all frames before the first SID frame", action="store_true" ) my_parser.add_argument( - "--frame", "-f", type=int, help="Number of frames to cut.", default=0 + "--frame", "-f", type=int, help="Number of frames to cut from the start of the file.", default=0 ) + my_parser.add_argument("--length", "-l", type=int, help="Cut bitstream to this length (in frames)", default=-1) my_parser.add_argument("bs_in", type=str, help="G.192 bit stream file name to cut") my_parser.add_argument("bs_out", type=str, help="Cut G.192 bit stream file name") my_args = my_parser.parse_args() @@ -113,10 +134,16 @@ if __name__ == "__main__": with open(my_args.bs_in, "rb") as fp_in: with open(my_args.bs_out, "wb") as fp_out: - fr_cnt, cut_cnt = cut_bs( - fp_in, fp_out, start_frame=my_args.frame, start_with_sid=my_args.sid - ) + if my_args.sid or my_args.frame: + fr_cnt, cut_cnt = cut_from_start( + fp_in, fp_out, start_frame=my_args.frame, start_with_sid=my_args.sid + ) + if my_args.sid and (fr_cnt == cut_cnt): + print("Warning! No SID frame found in bitstream!") + print(f"Cut {cut_cnt} of {fr_cnt} frames from {my_args.bs_in}") + elif my_args.length: + fr_cnt = cut_to_length(fp_in, fp_out, my_args.length) + if fr_cnt != my_args.length: + print(f"Warning! Could not cut to length {my_args.length} as bitstream only contained {fr_cnt} frames!") + print(f"Cut {my_args.bs_in} to {fr_cnt} frames") - if my_args.sid and (fr_cnt == cut_cnt): - print("Warning! No SID frame found in bitstream!") - print(f"Cut {cut_cnt} of {fr_cnt} frames from {my_args.bs_in}") diff --git a/scripts/pyivastest/IvasScriptsCommon.py b/scripts/pyivastest/IvasScriptsCommon.py index 681e6b1b7f4c1a0b35122be3467464223631db8b..a3876a2b4ee73d429b39a3e90deb17e267449dbe 100644 --- a/scripts/pyivastest/IvasScriptsCommon.py +++ b/scripts/pyivastest/IvasScriptsCommon.py @@ -276,6 +276,12 @@ class IvasScriptArgParser(argparse.ArgumentParser): help="Cut frames from the beginning of the encoded bit stream until the first SID frame", action="store_true", ) + self.add_argument( + "--bs_length", + help="Cut bitstream to this (maximum) length. Is applied AFTER --sidstart processing, if this is given", + type=int, + default=-1, + ) self.add_argument( "--info", help="Ouput debug info in subfolders of /res (use with caution, this can generate a huge amount of data)", @@ -613,6 +619,18 @@ def runner_setup(runner, args): ] add_to_proc_chain(bs_proc_chain, sidstart_cmd) + if args["bs_length"] > 0: + bs_len = args["bs_length"] + bs_cut_cmd = [ + os.path.join(constants.SCRIPTS_BASE_DIR, "cut_bs.py"), + "--length", + f"{bs_len}", + "{in_file}", + "{out_file}", + f"{bs_len}frames", + ] + add_to_proc_chain(bs_proc_chain, bs_cut_cmd) + if bs_proc_chain != {}: runner.global_bitstream_processing = bs_proc_chain diff --git a/scripts/runIvasCodec.py b/scripts/runIvasCodec.py index f96758e5be8d99b7fece0049e027eef277b40e4f..7cf1d64a6b130b52ad00a317c78dc2bea7a94bc0 100755 --- a/scripts/runIvasCodec.py +++ b/scripts/runIvasCodec.py @@ -158,7 +158,11 @@ class RunIvasCodec(IvasScriptsCommon.IvasScript): self.logger.console(" ") + encs_failed = len(runner.failed_modes["enc"]) > 0 + decs_failed = len(runner.failed_modes["dec"]) > 0 + return encs_failed or decs_failed + if __name__ == "__main__": script = RunIvasCodec() - script.run() + sys.exit(script.run()) diff --git a/tests/test_sba_bs_enc.py b/tests/test_sba_bs_enc.py index 09baebc9e1ecfb0eb16c6d4b3c9b44c03c492b34..759e1cce4fe44fa63babaed35c91c2d28d90f3d6 100644 --- a/tests/test_sba_bs_enc.py +++ b/tests/test_sba_bs_enc.py @@ -42,7 +42,7 @@ import pytest from cmp_pcm import cmp_pcm from cut_pcm import cut_samples from conftest import EncoderFrontend, DecoderFrontend -from cut_bs import cut_bs +from cut_bs import cut_from_start # params tag_list = ['stvFOA'] @@ -569,16 +569,16 @@ def sba_enc( if ref_encoder_path: with open(ref_pkt_file, "rb") as fp_in: with open(ref_pkt_file_cut, "wb") as fp_out: - fr_cnt, cut_cnt = cut_bs(fp_in, fp_out, 0, True) + fr_cnt, cut_cnt = cut_from_start(fp_in, fp_out, 0, True) with open(ref_pkt_file_dutenc, "rb") as fp_in: with open(ref_pkt_file_dutenc_cut, "wb") as fp_out: - fr_cnt, cut_cnt = cut_bs(fp_in, fp_out, 0, True) + fr_cnt, cut_cnt = cut_from_start(fp_in, fp_out, 0, True) os.remove(ref_pkt_file) os.remove(ref_pkt_file_dutenc) if update_ref == 0: with open(dut_pkt_file, "rb") as fp_in: with open(dut_pkt_file_cut, "wb") as fp_out: - fr_cnt, cut_cnt = cut_bs(fp_in, fp_out, 0, True) + fr_cnt, cut_cnt = cut_from_start(fp_in, fp_out, 0, True) os.remove(dut_pkt_file) def sba_dec( decoder_frontend,