Skip to content

Commit

Permalink
Sub second marker timestamp precision (#5431)
Browse files Browse the repository at this point in the history
* Allow DurationInput to accept/format timestamps with milliseconds
* Get current frame at sub-second precision
  • Loading branch information
WithoutPants authored Nov 2, 2024
1 parent 0d40056 commit e8125d0
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 19 deletions.
8 changes: 6 additions & 2 deletions ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,13 @@ export const ScenePlayer: React.FC<IScenePlayerProps> = ({
sendSetTimestamp((value: number) => {
const player = getPlayer();
if (player && value >= 0) {
player.play()?.then(() => {
if (player.hasStarted() && player.paused()) {
player.currentTime(value);
});
} else {
player.play()?.then(() => {
player.currentTime(value);
});
}
}
});
}, [sendSetTimestamp, getPlayer]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export const SceneMarkerForm: React.FC<ISceneMarkerForm> = ({
value={formik.values.seconds}
setValue={(v) => formik.setFieldValue("seconds", v)}
onReset={() =>
formik.setFieldValue("seconds", Math.round(getPlayerPosition() ?? 0))
formik.setFieldValue("seconds", getPlayerPosition() ?? 0)
}
error={error}
/>
Expand Down
23 changes: 14 additions & 9 deletions ui/v2.5/src/components/Shared/DurationInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
faChevronUp,
faClock,
} from "@fortawesome/free-solid-svg-icons";
import React, { useState } from "react";
import React, { useMemo, useState } from "react";
import { Button, ButtonGroup, InputGroup, Form } from "react-bootstrap";
import { Icon } from "./Icon";
import TextUtils from "src/utils/text";
Expand All @@ -19,6 +19,8 @@ interface IProps {
allowNegative?: boolean;
}

const includeMS = true;

export const DurationInput: React.FC<IProps> = ({
disabled,
value,
Expand Down Expand Up @@ -96,17 +98,20 @@ export const DurationInput: React.FC<IProps> = ({
}
}

let inputValue = "";
if (tmpValue !== undefined) {
inputValue = tmpValue;
} else if (value !== null && value !== undefined) {
inputValue = TextUtils.secondsToTimestamp(value);
}
const inputValue = useMemo(() => {
if (tmpValue !== undefined) {
return tmpValue;
} else if (value !== null && value !== undefined) {
return TextUtils.secondsToTimestamp(value, includeMS);
}
}, [value, tmpValue]);

const format = "hh:mm:ss.ms";

if (placeholder) {
placeholder = `${placeholder} (hh:mm:ss)`;
placeholder = `${placeholder} (${format})`;
} else {
placeholder = "hh:mm:ss";
placeholder = format;
}

return (
Expand Down
41 changes: 34 additions & 7 deletions ui/v2.5/src/utils/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,20 @@ const fileSizeFractionalDigits = (unit: Unit) => {
return 0;
};

// Converts seconds to a hh:mm:ss or mm:ss timestamp.
// Converts seconds to a [hh:]mm:ss[.ffff] where hh is only shown if hours is non-zero,
// and ffff is shown only if frameRate is set, and the seconds includes a fractional component.
// A negative input will result in a -hh:mm:ss or -mm:ss output.
// Fractional inputs are truncated.
const secondsToTimestamp = (seconds: number) => {
const secondsToTimestamp = (secondsInput: number, includeMS?: boolean) => {
let neg = false;
if (seconds < 0) {
if (secondsInput < 0) {
neg = true;
seconds = -seconds;
secondsInput = -secondsInput;
}
seconds = Math.trunc(seconds);

const fracSeconds = secondsInput % 1;
const ms = Math.round(fracSeconds * 1000);

let seconds = Math.trunc(secondsInput);

const s = seconds % 60;
seconds = (seconds - s) / 60;
Expand All @@ -177,6 +181,11 @@ const secondsToTimestamp = (seconds: number) => {
ret = String(m).padStart(2, "0") + ":" + ret;
ret = String(h) + ":" + ret;
}

if (includeMS && ms > 0) {
ret += "." + ms.toString().padStart(3, "0");
}

if (neg) {
return "-" + ret;
} else {
Expand All @@ -202,6 +211,24 @@ const timestampToSeconds = (v: string | null | undefined) => {
return null;
}

let secondsPart = splits[splits.length - 1];
let msFrac = 0;
if (secondsPart.includes(".")) {
const secondsParts = secondsPart.split(".");
if (secondsParts.length !== 2) {
return null;
}

secondsPart = secondsParts[0];

const msPart = parseInt(secondsParts[1], 10);
if (Number.isNaN(msPart)) {
return null;
}

msFrac = msPart / 1000;
}

let seconds = 0;
let factor = 1;
while (splits.length > 0) {
Expand All @@ -219,7 +246,7 @@ const timestampToSeconds = (v: string | null | undefined) => {
factor *= 60;
}

return seconds;
return seconds + msFrac;
};

const fileNameFromPath = (path: string) => {
Expand Down

0 comments on commit e8125d0

Please sign in to comment.