feat(perception): add DDRNet full-video vegetation replay
This commit is contained in:
@@ -3,15 +3,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import zipfile
|
||||
from collections.abc import Callable
|
||||
from functools import lru_cache
|
||||
from pathlib import Path, PurePosixPath
|
||||
from typing import Any, Final
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
from fastapi.responses import FileResponse, Response
|
||||
|
||||
from k1link.laboratory.evidence_registry import LaboratoryEvidenceDefinition
|
||||
from k1link.laboratory.evidence_report import (
|
||||
@@ -86,6 +88,48 @@ def build_vegetation_shadow_lab_router(
|
||||
},
|
||||
)
|
||||
|
||||
@router.get("/{result_id}/masks/{sequence}")
|
||||
def get_video_mask(result_id: str, sequence: int) -> Response:
|
||||
candidate = _resolve_candidate(root_provider, result_id)
|
||||
manifest = _read_verified(candidate)
|
||||
route_video = manifest.get("route_video")
|
||||
if not isinstance(route_video, dict) or not 0 <= sequence < 4489:
|
||||
raise HTTPException(status_code=404, detail="Vegetation video mask not found")
|
||||
archive = route_video.get("mask_archive")
|
||||
if not isinstance(archive, dict) or archive.get("path") != "video/ddrnet-semantic-masks.zip":
|
||||
raise HTTPException(status_code=404, detail="Vegetation video mask not found")
|
||||
archive_path = candidate / "video" / "ddrnet-semantic-masks.zip"
|
||||
member = f"masks/frame-{sequence + 1:06d}.png"
|
||||
try:
|
||||
before = archive_path.stat()
|
||||
with zipfile.ZipFile(archive_path) as frozen:
|
||||
info = frozen.getinfo(member)
|
||||
if info.is_dir() or info.file_size < 8 or info.file_size > 1024 * 1024:
|
||||
raise ValueError("Vegetation video mask member is invalid")
|
||||
payload = frozen.read(info)
|
||||
after = archive_path.stat()
|
||||
if (
|
||||
before.st_size != after.st_size
|
||||
or before.st_mtime_ns != after.st_mtime_ns
|
||||
or len(payload) != info.file_size
|
||||
):
|
||||
raise ValueError("Vegetation video mask archive changed during read")
|
||||
except (KeyError, OSError, ValueError, zipfile.BadZipFile):
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="Vegetation video mask failed verification",
|
||||
) from None
|
||||
digest = hashlib.sha256(payload).hexdigest()
|
||||
return Response(
|
||||
content=payload,
|
||||
media_type="image/png",
|
||||
headers={
|
||||
"Cache-Control": "private, max-age=31536000, immutable",
|
||||
"ETag": f'"{digest}"',
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
},
|
||||
)
|
||||
|
||||
return router
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user