"""DASH.resolve_representation must continue a track into a later Period without crossing codec, size or language.""" from __future__ import annotations from typing import Any import pytest from tests.core.test_manifest_corpus import CORPUS, INDEX, KNOWN_FAILURES, parse from unshackle.core.manifests import DASH from unshackle.core.utils.xml import load_xml RENUMBERED = b""" """ def video(rep_id: str, bandwidth: str, codecs: str = "avc1.640028") -> str: return f'' def audio(rep_id: str) -> str: return f'' def two_periods(first: str, second: str) -> bytes: return f'{first}{second}'.encode() def resolve(mpd: bytes, set_index: int, rep_id: str) -> tuple[str | None, str | None, str | None] | None: p0, p1 = load_xml(mpd).findall("Period") found = DASH.resolve_representation(p1, rep_id, p0.findall("AdaptationSet")[set_index]) if found is None: return None adaptation_set, rep = found return adaptation_set.get("lang"), rep.get("id"), DASH.get_attr("codecs", adaptation_set, rep) def test_renumbered_audio_continues_into_audio_not_a_video_rep_with_its_id(): assert resolve(RENUMBERED, 2, "3") == ("en", "0", "mp4a.40.2") def test_renumbered_video_continues_into_the_same_size(): assert resolve(RENUMBERED, 1, "1") == (None, "2", "avc1") assert resolve(RENUMBERED, 1, "2") == (None, "1", "avc1") def test_track_missing_from_the_period_is_not_matched_to_another_type(): assert resolve(RENUMBERED, 0, "0") is None def test_untyped_sets_that_swap_order_keep_audio_on_audio(): mpd = two_periods( f"{video('v', '5000000')}{audio('a')}", f"{audio('a')}{video('v', '5000000')}", ) assert resolve(mpd, 1, "a") == (None, "a", "mp4a.40.2") def test_codec_missing_from_the_period_is_skipped_not_swapped(): mpd = two_periods( f'{video("avc", "5000000")}' f'{video("hevc", "3000000", "hvc1.2.4.L150")}', f'{video("avc", "5000000")}', ) assert resolve(mpd, 1, "hevc") is None def test_renumbered_sets_that_swap_order_keep_the_codec(): mpd = two_periods( f'{video("0", "8000000", "hvc1.2.4.L150")}' f'{video("1", "8000000", "dvh1.08.06")}', f'{video("0", "8000000", "dvh1.08.06")}' f'{video("1", "8000000", "hvc1.2.4.L150")}', ) assert resolve(mpd, 1, "1") == (None, "0", "dvh1.08.06") @pytest.mark.parametrize("content", ["audio", "text"]) def test_language_missing_from_the_period_is_skipped_not_swapped(content: str): def rep(rep_id: str) -> str: return ( audio(rep_id) if content == "audio" else f'' ) mpd = two_periods( f'{rep("x")}', f'{rep("y")}', ) assert resolve(mpd, 0, "x") is None def test_regional_tag_continues_into_the_same_language(): mpd = two_periods( f'{audio("a")}', f'{audio("b")}', ) assert resolve(mpd, 0, "a") == ("en-US", "b", "mp4a.40.2") def test_same_identity_sets_that_swap_order_follow_the_rep_id(): dialog = f'{audio("dialog")}' described = f'{audio("ad")}' assert resolve(two_periods(dialog + described, described + dialog), 0, "dialog") == ("en", "dialog", "mp4a.40.2") def test_stable_ladder_follows_bandwidth_rank_when_every_rung_drifts(): mpd = two_periods( f'{video("v1", "5000000")}{video("v2", "6000000")}', f'{video("v1", "3000000")}{video("v2", "4500000")}', ) assert resolve(mpd, 0, "v1") == (None, "v1", "avc1.640028") assert resolve(mpd, 0, "v2") == (None, "v2", "avc1.640028") def test_non_integer_bandwidth_does_not_raise(): mpd = two_periods( f'{video("v1", "5000000")}', f'{video("v1", "5e6")}', ) assert resolve(mpd, 0, "v1") == (None, "v1", "avc1.640028") def multi_period(entry: dict[str, Any]) -> bool: periods = load_xml((CORPUS / entry["file"]).read_bytes()).findall("Period") return sum(DASH.is_content_period(p, []) for p in periods) > 1 @pytest.mark.parametrize( "entry", [e for e in INDEX if e["kind"] == "dash" and e["file"] not in KNOWN_FAILURES and multi_period(e)], ids=lambda e: e["file"], ) def test_corpus_matches_never_cross_codec_or_size(entry: dict[str, Any]): shape = ("codecs", "width", "height") for track in parse(entry): data = track.data["dash"] want = tuple(DASH.get_attr(a, data["adaptation_set"], data["representation"]) for a in shape) for period in data["manifest"].findall("Period"): if period is data["period"] or not DASH.is_content_period(period, []): continue found = DASH.resolve_representation(period, data["representation_id"], data["adaptation_set"]) if found is not None: assert tuple(DASH.get_attr(a, *found) for a in shape) == want