mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
feat(player): add frame counter when scrubbing and seeking
Show a timecode + frame readout above the timeline while dragging the playhead, and flash it for a moment on keyboard/button seeks so frame stepping is visible too. Position and text are written from the existing rAF/DOM path that drives the playhead, so the readout stays smooth without extra React renders. Two supporting fixes the count depends on: - Seed the frame rate from the HLS manifest FRAME-RATE attribute so a frame number is available before playback ever starts; previously the rate was only ever measured from requestVideoFrameCallback and stayed null until the video had played. - Snap the measured rate to the nearest broadcast standard and skip samples taken mid-seek. A drifting float slid the count by whole frames late in a long video, and re-publishing a slightly different float on every presented frame forced a re-render per video frame.
This commit is contained in:
@@ -43,7 +43,9 @@ interface PlayerCoreProps {
|
||||
timelineRef: RefObject<HTMLDivElement | null>;
|
||||
progressRef: RefObject<HTMLDivElement | null>;
|
||||
playheadRef: RefObject<HTMLDivElement | null>;
|
||||
scrubReadoutRef: RefObject<HTMLDivElement | null>;
|
||||
videoContainerRef: RefObject<HTMLDivElement | null>;
|
||||
showScrubReadout: boolean;
|
||||
isFullscreenMode: boolean;
|
||||
cursorIdle: boolean;
|
||||
isPlaying: boolean;
|
||||
@@ -109,7 +111,9 @@ export const PlayerCore = memo(function PlayerCore({
|
||||
timelineRef,
|
||||
progressRef,
|
||||
playheadRef,
|
||||
scrubReadoutRef,
|
||||
videoContainerRef,
|
||||
showScrubReadout,
|
||||
isFullscreenMode,
|
||||
cursorIdle,
|
||||
isPlaying,
|
||||
@@ -518,6 +522,19 @@ export const PlayerCore = memo(function PlayerCore({
|
||||
className="absolute top-0 left-0 h-full w-1 bg-primary rounded pointer-events-none will-change-[left]"
|
||||
/>
|
||||
|
||||
{/* Timecode + frame counter, shown while scrubbing and flashed on
|
||||
keyboard/button seeks. Kept mounted (only faded) so it already
|
||||
holds the right text the instant it appears; its position and
|
||||
content come from the same rAF loop that drives the playhead. */}
|
||||
<div
|
||||
ref={scrubReadoutRef}
|
||||
aria-hidden={!showScrubReadout}
|
||||
className={cn(
|
||||
'absolute bottom-full left-0 z-20 mb-2 -translate-x-1/2 whitespace-nowrap rounded-md border bg-popover px-2 py-1 text-xs font-medium tabular-nums text-popover-foreground shadow-md pointer-events-none will-change-[left] transition-opacity duration-150',
|
||||
showScrubReadout ? 'opacity-100' : 'opacity-0'
|
||||
)}
|
||||
/>
|
||||
|
||||
{commentMarkers.map((comment) => {
|
||||
const startPercent = duration > 0 ? (comment.timestamp / duration) * 100 : 0;
|
||||
const hasRange =
|
||||
|
||||
Reference in New Issue
Block a user