Debug replay (#22212)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions

* debug replay implementation

* fix masks after dev rebase

* fix squash merge issues

* fix

* fix

* fix

* no need to write debug replay camera to config

* camera and filter button and dropdown

* add filters

* add ability to edit motion and object config for debug replay

* add debug draw overlay to debug replay

* add guard to prevent crash when camera is no longer in camera_states

* fix overflow due to radix absolutely positioned elements

* increase number of messages

* ensure deep_merge replaces existing list values when override is true

* add back button

* add debug replay to explore and review menus

* clean up

* clean up

* update instructions to prevent exposing exception info

* fix typing

* refactor output logic

* refactor with helper function

* move init to function for consistency
This commit is contained in:
Josh Hawkins
2026-03-04 10:07:34 -06:00
committed by GitHub
parent 5e7d426768
commit 95956a690b
68 changed files with 4572 additions and 519 deletions
+80 -7
View File
@@ -1,6 +1,8 @@
import ReviewCard from "@/components/card/ReviewCard";
import ReviewFilterGroup from "@/components/filter/ReviewFilterGroup";
import DebugReplayDialog from "@/components/overlay/DebugReplayDialog";
import ExportDialog from "@/components/overlay/ExportDialog";
import ActionsDropdown from "@/components/overlay/ActionsDropdown";
import PreviewPlayer, {
PreviewController,
} from "@/components/player/PreviewPlayer";
@@ -199,6 +201,11 @@ export function RecordingView({
const [exportRange, setExportRange] = useState<TimeRange>();
const [showExportPreview, setShowExportPreview] = useState(false);
// debug replay
const [debugReplayMode, setDebugReplayMode] = useState<ExportMode>("none");
const [debugReplayRange, setDebugReplayRange] = useState<TimeRange>();
// move to next clip
const onClipEnded = useCallback(() => {
@@ -269,7 +276,7 @@ export function RecordingView({
);
useEffect(() => {
if (scrubbing || exportRange) {
if (scrubbing || exportRange || debugReplayRange) {
if (
currentTime > currentTimeRange.before + 60 ||
currentTime < currentTimeRange.after - 60
@@ -591,6 +598,23 @@ export function RecordingView({
selected={mainCamera}
onSelectCamera={onSelectCamera}
/>
{isDesktop && (
<DebugReplayDialog
camera={mainCamera}
currentTime={currentTime}
latestTime={timeRange.before}
mode={debugReplayMode}
range={debugReplayRange}
setRange={(range: TimeRange | undefined) => {
setDebugReplayRange(range);
if (range != undefined) {
mainControllerRef.current?.pause();
}
}}
setMode={setDebugReplayMode}
/>
)}
{isDesktop && (
<ExportDialog
camera={mainCamera}
@@ -639,6 +663,28 @@ export function RecordingView({
setMotionOnly={() => {}}
/>
)}
{isDesktop && (
<ActionsDropdown
onDebugReplayClick={() => {
const now = new Date(timeRange.before * 1000);
now.setHours(now.getHours() - 1);
setDebugReplayRange({
after: now.getTime() / 1000,
before: timeRange.before,
});
setDebugReplayMode("select");
}}
onExportClick={() => {
const now = new Date(timeRange.before * 1000);
now.setHours(now.getHours() - 1);
setExportRange({
before: timeRange.before,
after: now.getTime() / 1000,
});
setExportMode("select");
}}
/>
)}
{isDesktop ? (
<ToggleGroup
className="*:rounded-md *:px-3 *:py-4"
@@ -688,6 +734,16 @@ export function RecordingView({
showExportPreview={showExportPreview}
allLabels={reviewFilterList.labels}
allZones={reviewFilterList.zones}
debugReplayMode={debugReplayMode}
debugReplayRange={debugReplayRange}
setDebugReplayMode={setDebugReplayMode}
setDebugReplayRange={(range: TimeRange | undefined) => {
setDebugReplayRange(range);
if (range != undefined) {
mainControllerRef.current?.pause();
}
}}
onUpdateFilter={updateFilter}
setRange={setExportRange}
setMode={setExportMode}
@@ -758,7 +814,9 @@ export function RecordingView({
timeRange={currentTimeRange}
cameraPreviews={allPreviews ?? []}
startTimestamp={playbackStart}
hotKeys={exportMode != "select"}
hotKeys={
exportMode != "select" && debugReplayMode != "select"
}
fullscreen={fullscreen}
onTimestampUpdate={(timestamp) => {
setPlayerTime(timestamp);
@@ -772,7 +830,11 @@ export function RecordingView({
onControllerReady={(controller) => {
mainControllerRef.current = controller;
}}
isScrubbing={scrubbing || exportMode == "timeline"}
isScrubbing={
scrubbing ||
exportMode == "timeline" ||
debugReplayMode == "timeline"
}
supportsFullscreen={supportsFullScreen}
setFullResolution={setFullResolution}
toggleFullscreen={toggleFullscreen}
@@ -840,18 +902,29 @@ export function RecordingView({
contentRef={contentRef}
mainCamera={mainCamera}
timelineType={
(exportRange == undefined ? timelineType : "timeline") ??
"timeline"
(exportRange == undefined && debugReplayRange == undefined
? timelineType
: "timeline") ?? "timeline"
}
timeRange={timeRange}
mainCameraReviewItems={mainCameraReviewItems}
activeReviewItem={activeReviewItem}
currentTime={currentTime}
exportRange={exportMode == "timeline" ? exportRange : undefined}
exportRange={
exportMode == "timeline"
? exportRange
: debugReplayMode == "timeline"
? debugReplayRange
: undefined
}
setCurrentTime={setCurrentTime}
manuallySetCurrentTime={manuallySetCurrentTime}
setScrubbing={setScrubbing}
setExportRange={setExportRange}
setExportRange={
debugReplayMode == "timeline"
? setDebugReplayRange
: setExportRange
}
onAnalysisOpen={onAnalysisOpen}
isPlaying={mainControllerRef?.current?.isPlaying() ?? false}
/>