quality preset
This commit is contained in:
@@ -28,6 +28,13 @@ export function ExtractMode({ username, settings }: Props) {
|
||||
useEffect(() => {
|
||||
frameSkipRef.current = Math.max(1, settings?.frame_skip ?? 1);
|
||||
}, [settings?.frame_skip]);
|
||||
// Preview-quality cap (in px height; 0 = original). Read per-draw via ref
|
||||
// so a settings change triggers an immediate redraw of the current frame
|
||||
// without rebuilding the playback effect.
|
||||
const previewMaxHRef = useRef<number>(settings?.preview_max_height ?? 0);
|
||||
useEffect(() => {
|
||||
previewMaxHRef.current = settings?.preview_max_height ?? 0;
|
||||
}, [settings?.preview_max_height]);
|
||||
const [video, setVideo] = useState<VideoInfo | null>(null);
|
||||
const [frameIdx, setFrameIdx] = useState(0);
|
||||
const [playing, setPlaying] = useState(false);
|
||||
@@ -120,20 +127,27 @@ export function ExtractMode({ username, settings }: Props) {
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
// Backing store = displayed CSS rect × DPR, capped at video native
|
||||
// resolution (anything above is upsampling for no benefit). Halves
|
||||
// drawImage cost on 4K-into-1080p, which is the common slow-system
|
||||
// case. Coords below are in image-pixel space — the transform handles
|
||||
// the mapping to backing pixels, so overlay.ts is unchanged.
|
||||
// Backing store = displayed CSS rect × DPR, capped at video native and
|
||||
// optionally at the user's Preview-quality preset. Halves drawImage
|
||||
// cost on 4K-into-1080p (the common slow-system case). Coords below
|
||||
// are in image-pixel space — the transform maps to backing pixels so
|
||||
// overlay.ts is unchanged.
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
let maxW = video.width;
|
||||
let maxH = video.height;
|
||||
const previewMaxH = previewMaxHRef.current;
|
||||
if (previewMaxH > 0 && previewMaxH < video.height) {
|
||||
maxH = previewMaxH;
|
||||
maxW = Math.round(previewMaxH * (video.width / video.height));
|
||||
}
|
||||
const targetW = Math.max(
|
||||
1,
|
||||
Math.min(video.width, Math.round(rect.width * dpr))
|
||||
Math.min(maxW, Math.round(rect.width * dpr))
|
||||
);
|
||||
const targetH = Math.max(
|
||||
1,
|
||||
Math.min(video.height, Math.round(rect.height * dpr))
|
||||
Math.min(maxH, Math.round(rect.height * dpr))
|
||||
);
|
||||
if (canvas.width !== targetW) canvas.width = targetW;
|
||||
if (canvas.height !== targetH) canvas.height = targetH;
|
||||
@@ -249,6 +263,17 @@ export function ExtractMode({ username, settings }: Props) {
|
||||
|
||||
useEffect(() => clearBitmapCache, [clearBitmapCache]);
|
||||
|
||||
// Live re-render when the preview-quality cap changes so the user sees the
|
||||
// resolution swap immediately on Settings save instead of having to seek.
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas || !video) return;
|
||||
const idx = frameIdxRef.current;
|
||||
const cached = getCachedBitmap(idx);
|
||||
if (cached) drawBitmap(cached, idx);
|
||||
// If not cached, the next pump invocation picks up the new cap naturally.
|
||||
}, [settings?.preview_max_height, video, drawBitmap, getCachedBitmap]);
|
||||
|
||||
// Redraw on canvas resize: backing-store is sized from CSS rect × DPR, so
|
||||
// a window resize/maximize would otherwise leave the old backing dimensions
|
||||
// until the next decode landed. Cheap — just re-runs drawBitmap on the
|
||||
|
||||
Reference in New Issue
Block a user