import type { Edl } from "@rakazo/contracts"; import { cn } from "@rakazo/ui-web"; import { useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"; import { assetFileUrl, useMediaObjectUrl } from "./media-files"; import { clipLengthMs, clipOutputStartMs, edlDurationMs, locateOutputTime } from "./timeline"; export interface PlayerHandle { /** Jump to an output timestamp in ms. */ seek(ms: number): void; } /** What the source player currently shows, in source coordinates. */ export interface SourceFrame { outputMs: number; clipId: string; assetId: string; sourceMs: number; } /** Plays a finished render. Reports the playhead in output ms. */ export function RenderVideo({ src, poster, handleRef, onTime, className, label, }: { src: string | null; poster?: string | null; handleRef?: React.Ref; onTime?: (ms: number) => void; className?: string; label: string; }) { const video = useRef(null); const pending = useRef(null); useImperativeHandle(handleRef, () => ({ seek(ms) { const element = video.current; if (!element || element.readyState < 1) { pending.current = ms; return; } element.currentTime = ms / 1000; onTime?.(ms); }, })); return ( // biome-ignore lint/a11y/useMediaCaption: renders carry burned-in or sidecar captions.