121 lines
4.0 KiB
JavaScript
121 lines
4.0 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import { after, before, test } from "node:test";
|
|
|
|
import { createServer } from "vite";
|
|
|
|
let server;
|
|
let fetchE46CVideoOverlay;
|
|
let selectE46CVideoFrame;
|
|
|
|
before(async () => {
|
|
server = await createServer({
|
|
appType: "custom",
|
|
logLevel: "silent",
|
|
server: { middlewareMode: true },
|
|
});
|
|
({ fetchE46CVideoOverlay, selectE46CVideoFrame } = await server.ssrLoadModule(
|
|
"/src/core/laboratory/e46cFullReplayWorldTracks.ts",
|
|
));
|
|
});
|
|
|
|
after(async () => {
|
|
await server?.close();
|
|
});
|
|
|
|
test("E46C decodes the complete path-free temporal video overlay", async () => {
|
|
const resultId = `e46c-full-replay-world-tracks-${"a".repeat(64)}`;
|
|
const start = 35.421857292;
|
|
const end = 484.044857292;
|
|
const step = (end - start) / 4488;
|
|
const frames = Array.from({ length: 4489 }, (_, frameIndex) => ({
|
|
frame_index: frameIndex,
|
|
session_seconds: frameIndex === 4488 ? end : start + frameIndex * step,
|
|
fusion_state: "fused",
|
|
objects: frameIndex === 20
|
|
? [{
|
|
bbox_xyxy: [100, 120, 240, 360],
|
|
category: "person",
|
|
score: 0.91,
|
|
route_track_id: 83,
|
|
world_track_id: 240001,
|
|
motion_state: "dynamic",
|
|
motion_confidence: 0.88,
|
|
track_hits: 12,
|
|
track_age_seconds: 1.2,
|
|
camera_evidence_current: true,
|
|
world_evidence_current: false,
|
|
}]
|
|
: [],
|
|
}));
|
|
const fetcher = async (input) => {
|
|
assert.equal(
|
|
String(input),
|
|
`/api/v1/laboratory/e46c/results/${resultId}/video-overlay`,
|
|
);
|
|
return new Response(JSON.stringify({
|
|
schema_version: "missioncore.e46c-recorded-video-overlay/v1",
|
|
result_id: resultId,
|
|
recorded_source: {
|
|
session_id: "20260720T065719Z_viewer_live",
|
|
source_id: "sensor.camera.right",
|
|
input_sha256: "4".repeat(64),
|
|
synchronization: "host-arrival-best-effort",
|
|
},
|
|
image_width: 800,
|
|
image_height: 600,
|
|
timeline_start_seconds: start,
|
|
timeline_end_seconds: end,
|
|
frame_count: 4489,
|
|
frames,
|
|
review_windows: [{
|
|
id: "dynamic-person-window",
|
|
kind: "target-motion",
|
|
class_group: "person",
|
|
start_seconds: 54,
|
|
end_seconds: 62,
|
|
target_source_track_ids: [83],
|
|
}],
|
|
ground_truth: false,
|
|
access: "read-only-full-route-diagnostic-video",
|
|
}), { status: 200, headers: { "Content-Type": "application/json" } });
|
|
};
|
|
|
|
const overlay = await fetchE46CVideoOverlay(resultId, { fetcher });
|
|
assert.equal(overlay.frameCount, 4489);
|
|
assert.equal(overlay.recordedSourceSessionId, "20260720T065719Z_viewer_live");
|
|
assert.equal(overlay.frames[20].objects[0].routeTrackId, 83);
|
|
assert.equal(overlay.frames[20].objects[0].displayCategory, "Человек");
|
|
assert.equal(overlay.reviewWindows[0].targetSourceTrackIds[0], 83);
|
|
assert.equal(JSON.stringify(overlay).includes("/Users/"), false);
|
|
assert.equal(selectE46CVideoFrame(overlay.frames, overlay.frames[20].sessionSeconds).frameIndex, 20);
|
|
});
|
|
|
|
test("E46C viewer opens with full VIDEO and reuses the admitted recorded player", async () => {
|
|
const [visual, videoScene, player] = await Promise.all([
|
|
readFile(
|
|
new URL(
|
|
"../src/workspaces/laboratory/E46CFullReplayWorldTracksVisual.tsx",
|
|
import.meta.url,
|
|
),
|
|
"utf8",
|
|
),
|
|
readFile(
|
|
new URL(
|
|
"../src/workspaces/laboratory/E46CRecordedVideoScene.tsx",
|
|
import.meta.url,
|
|
),
|
|
"utf8",
|
|
),
|
|
readFile(new URL("../src/components/RecordedFmp4Player.tsx", import.meta.url), "utf8"),
|
|
]);
|
|
|
|
assert.match(visual, /useState<E46CViewMode>\("video"\)/);
|
|
assert.match(visual, /\{ value: "video", label: "VIDEO" \}/);
|
|
assert.match(visual, /replayObservationSession\(overlay\.recordedSourceSessionId/);
|
|
assert.match(videoScene, /<RecordedFmp4Player/);
|
|
assert.match(videoScene, /selectE46CVideoFrame/);
|
|
assert.match(player, /requestVideoFrameCallback/);
|
|
assert.match(player, /controls=\{interactive\}/);
|
|
});
|