feat(k1): complete primary acquisition lifecycle

This commit is contained in:
DCCONSTRUCTIONS
2026-07-17 23:03:59 +03:00
parent 9d51080d2e
commit aa3680948f
66 changed files with 6093 additions and 544 deletions
+82 -59
View File
@@ -94,6 +94,16 @@ class _Mp4VideoTiming:
default_sample_duration: int | None
@dataclass(frozen=True, slots=True)
class _Mp4VideoFragmentTiming:
base_decode_time: int
duration_units: int
@property
def end_decode_time(self) -> int:
return self.base_decode_time + self.duration_units
@dataclass(slots=True)
class _Mp4ParseBudget:
boxes_remaining: int = MAX_MP4_BOXES
@@ -170,10 +180,13 @@ class RecordedMediaInspector:
artifact: RecordedMediaArtifact,
replay: ReplayCommand,
epoch_paths: tuple[Path, ...],
) -> tuple[
RecordedMediaManifest,
tuple[tuple[int, int, int, int], ...],
] | None:
) -> (
tuple[
RecordedMediaManifest,
tuple[tuple[int, int, int, int], ...],
]
| None
):
root = self._cache_root
if root is None:
return None
@@ -406,8 +419,7 @@ def _manifest_from_sidecar(
)
_validate_epoch_timeline(epochs)
byte_length = sum(
epoch.init_byte_length
+ sum(segment.byte_length for segment in epoch.segments)
epoch.init_byte_length + sum(segment.byte_length for segment in epoch.segments)
for epoch in epochs
)
timeline_start_seconds = min(epoch.timeline_start_seconds for epoch in epochs)
@@ -515,11 +527,7 @@ def _sidecar_identity(
expected_length: int,
) -> tuple[tuple[int, int, int, int], ...]:
value = document.get("source_identity")
if (
not isinstance(value, list)
or expected_length < 1
or len(value) != expected_length
):
if not isinstance(value, list) or expected_length < 1 or len(value) != expected_length:
raise SessionIntegrityError("recorded media preparation source identity is invalid")
identity: list[tuple[int, int, int, int]] = []
for item in value:
@@ -561,10 +569,7 @@ def _write_sidecar_atomic(root: Path, filename: str, payload: bytes) -> None:
try:
descriptor = os.open(
temporary,
os.O_WRONLY
| os.O_CREAT
| os.O_EXCL
| getattr(os, "O_NOFOLLOW", 0),
os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_NOFOLLOW", 0),
0o600,
dir_fd=directory_fd,
)
@@ -637,9 +642,7 @@ def _prepared_source_identity(
identity: list[tuple[int, int, int, int]] = []
for artifact in replay.artifacts:
metadata = _session_artifact_stat(artifact.path, replay.session_root)
identity.append(
(metadata.st_dev, metadata.st_ino, metadata.st_size, metadata.st_mtime_ns)
)
identity.append((metadata.st_dev, metadata.st_ino, metadata.st_size, metadata.st_mtime_ns))
for expected_ordinal, (epoch_path, epoch) in enumerate(
zip(epoch_paths, epochs, strict=True),
start=1,
@@ -698,8 +701,7 @@ def _read_manifest(
)
_validate_epoch_timeline(epochs)
byte_length = sum(
epoch.init_byte_length
+ sum(segment.byte_length for segment in epoch.segments)
epoch.init_byte_length + sum(segment.byte_length for segment in epoch.segments)
for epoch in epochs
)
if not 0 < byte_length <= MAX_SAFE_INTEGER:
@@ -737,8 +739,7 @@ def _manifest_generation_sha256(
timeline_start_seconds = min(epoch.timeline_start_seconds for epoch in epochs)
timeline_end_seconds = max(epoch.timeline_end_seconds for epoch in epochs)
byte_length = sum(
epoch.init_byte_length
+ sum(segment.byte_length for segment in epoch.segments)
epoch.init_byte_length + sum(segment.byte_length for segment in epoch.segments)
for epoch in epochs
)
descriptor = {
@@ -798,11 +799,15 @@ def _read_epoch(
raise SessionIntegrityError("recorded media segment count is invalid")
try:
raw_lines = _read_confined_file(
epoch / "index.jsonl",
epoch,
MAX_MEDIA_INDEX_BYTES,
).decode("utf-8").splitlines()
raw_lines = (
_read_confined_file(
epoch / "index.jsonl",
epoch,
MAX_MEDIA_INDEX_BYTES,
)
.decode("utf-8")
.splitlines()
)
except UnicodeDecodeError as exc:
raise SessionIntegrityError("recorded media index is unavailable") from exc
if len(raw_lines) != int(segment_count):
@@ -886,14 +891,11 @@ def _read_epoch(
init_payload = _read_confined_file(init_path, epoch, MAX_INIT_BYTES)
init_sha256 = hashlib.sha256(init_payload).hexdigest()
expected_init_sha256 = summary.get("init_sha256")
if (
not isinstance(expected_init_sha256, str)
or expected_init_sha256 != init_sha256
):
if not isinstance(expected_init_sha256, str) or expected_init_sha256 != init_sha256:
raise SessionIntegrityError("recorded media init digest changed")
media_type = _mp4_media_type(init_payload)
timing = _mp4_video_timing(init_payload, _Mp4ParseBudget())
duration_units: list[int] = []
fragment_timings: list[_Mp4VideoFragmentTiming] = []
for segment in segments:
payload = _read_confined_file(
segment.path,
@@ -902,13 +904,21 @@ def _read_epoch(
)
if hashlib.sha256(payload).hexdigest() != segment.sha256:
raise SessionIntegrityError("recorded media segment digest changed")
duration_units.append(
_mp4_video_fragment_duration_units(
fragment_timings.append(
_mp4_video_fragment_timing(
payload,
timing,
_Mp4ParseBudget(),
)
)
for previous, current in zip(
fragment_timings,
fragment_timings[1:],
strict=False,
):
if current.base_decode_time != previous.end_decode_time:
raise SessionIntegrityError("recorded media fragment decode timeline is discontinuous")
duration_units = [timing.duration_units for timing in fragment_timings]
first_duration_seconds = _checked_fragment_duration_seconds(
duration_units[0],
timing.timescale,
@@ -919,10 +929,7 @@ def _read_epoch(
total_duration_seconds = total_duration_units / timing.timescale
timeline_start_seconds = max(0.0, timeline_points[0] - first_duration_seconds)
timeline_end_seconds = timeline_start_seconds + total_duration_seconds
if (
not math.isfinite(timeline_end_seconds)
or timeline_end_seconds < timeline_start_seconds
):
if not math.isfinite(timeline_end_seconds) or timeline_end_seconds < timeline_start_seconds:
raise SessionIntegrityError("recorded media epoch timeline is invalid")
return RecordedMediaEpoch(
ordinal=ordinal,
@@ -984,23 +991,22 @@ def _mp4_fragment_duration_seconds(init_payload: bytes, fragment_payload: bytes)
budget = _Mp4ParseBudget()
timing = _mp4_video_timing(init_payload, budget)
duration_units = _mp4_video_fragment_duration_units(
fragment_timing = _mp4_video_fragment_timing(
fragment_payload,
timing,
budget,
)
return _checked_fragment_duration_seconds(duration_units, timing.timescale)
return _checked_fragment_duration_seconds(
fragment_timing.duration_units,
timing.timescale,
)
def _checked_fragment_duration_seconds(duration_units: int, timescale: int) -> float:
if duration_units <= 0:
raise SessionIntegrityError("recorded media fragment has no positive duration")
duration = duration_units / timescale
if (
not math.isfinite(duration)
or duration <= 0
or duration > MAX_MP4_FRAGMENT_DURATION_SECONDS
):
if not math.isfinite(duration) or duration <= 0 or duration > MAX_MP4_FRAGMENT_DURATION_SECONDS:
raise SessionIntegrityError("recorded media fragment duration is outside bounds")
return duration
@@ -1069,9 +1075,7 @@ def _trak_media_timing(payload: bytes, budget: _Mp4ParseBudget) -> int | None:
raise SessionIntegrityError("recorded media track has no unique mdia box")
children = tuple(_iter_mp4_boxes(media_boxes[0], budget))
handlers = [
_parse_hdlr_type(box_payload)
for box_type, box_payload in children
if box_type == b"hdlr"
_parse_hdlr_type(box_payload) for box_type, box_payload in children if box_type == b"hdlr"
]
if len(handlers) != 1:
raise SessionIntegrityError("recorded media track handler is ambiguous")
@@ -1087,11 +1091,11 @@ def _trak_media_timing(payload: bytes, budget: _Mp4ParseBudget) -> int | None:
return timescales[0]
def _mp4_video_fragment_duration_units(
def _mp4_video_fragment_timing(
payload: bytes,
timing: _Mp4VideoTiming,
budget: _Mp4ParseBudget,
) -> int:
) -> _Mp4VideoFragmentTiming:
moof_payloads = [
box_payload
for box_type, box_payload in _iter_mp4_boxes(payload, budget)
@@ -1099,7 +1103,7 @@ def _mp4_video_fragment_duration_units(
]
if len(moof_payloads) != 1:
raise SessionIntegrityError("recorded media fragment has no unique moof box")
matching_durations: list[int] = []
matching_timings: list[_Mp4VideoFragmentTiming] = []
for box_type, traf_payload in _iter_mp4_boxes(moof_payloads[0], budget):
if box_type != b"traf":
continue
@@ -1110,18 +1114,28 @@ def _mp4_video_fragment_duration_units(
track_id, fragment_default_duration = _parse_tfhd(tfhd_payloads[0])
if track_id != timing.track_id:
continue
tfdt_payloads = [box for kind, box in boxes if kind == b"tfdt"]
if len(tfdt_payloads) != 1:
raise SessionIntegrityError("recorded media fragment tfdt is ambiguous")
base_decode_time = _parse_tfdt(tfdt_payloads[0])
trun_payloads = [box for kind, box in boxes if kind == b"trun"]
if not trun_payloads:
raise SessionIntegrityError("recorded media video fragment has no trun box")
default_duration = fragment_default_duration or timing.default_sample_duration
duration = sum(
_parse_trun_duration_units(trun, default_duration, budget)
for trun in trun_payloads
_parse_trun_duration_units(trun, default_duration, budget) for trun in trun_payloads
)
matching_durations.append(duration)
if len(matching_durations) != 1:
if base_decode_time > MAX_SAFE_INTEGER - duration:
raise SessionIntegrityError("recorded media fragment decode time is outside bounds")
matching_timings.append(
_Mp4VideoFragmentTiming(
base_decode_time=base_decode_time,
duration_units=duration,
)
)
if len(matching_timings) != 1:
raise SessionIntegrityError("recorded media fragment video track is ambiguous")
return matching_durations[0]
return matching_timings[0]
def _iter_mp4_boxes(
@@ -1195,6 +1209,17 @@ def _parse_tfhd(payload: bytes) -> tuple[int, int | None]:
return track_id, default_duration if default_duration and default_duration > 0 else None
def _parse_tfdt(payload: bytes) -> int:
version = _full_box_version(payload)
if version == 0:
return _read_u32(payload, 4, "tfdt base decode time")
if version == 1:
if len(payload) < 12:
raise SessionIntegrityError("recorded media tfdt base decode time is truncated")
return int.from_bytes(payload[4:12], "big")
raise SessionIntegrityError("recorded media tfdt version is unsupported")
def _parse_trun_duration_units(
payload: bytes,
default_duration: int | None,
@@ -1210,9 +1235,7 @@ def _parse_trun_duration_units(
cursor = _advance_box_cursor(payload, cursor, 4, "trun data offset")
if flags & 0x000004:
cursor = _advance_box_cursor(payload, cursor, 4, "trun first sample flags")
per_sample_width = sum(
4 for flag in (0x000100, 0x000200, 0x000400, 0x000800) if flags & flag
)
per_sample_width = sum(4 for flag in (0x000100, 0x000200, 0x000400, 0x000800) if flags & flag)
if per_sample_width and sample_count > (len(payload) - cursor) // per_sample_width:
raise SessionIntegrityError("recorded media trun samples are truncated")
if flags & 0x000100: