From f72f5c100badb8ad744a20b9110f9f5e7a9bf774 Mon Sep 17 00:00:00 2001 From: StarKnightt Date: Mon, 23 Jun 2025 20:01:12 +0530 Subject: Add video speed control and improve playback smoothness Added a speed control dropdown in the timeline toolbar that lets users change video playback speed between 0.5x to 2x. The dropdown shows the current speed and offers preset options. Made video playback smoother by: - Using better timing for speed changes - Improving video synchronization - Reducing playback stutters - Making speed changes more responsive The speed control is now easily accessible while editing and works smoothly with all video clips. --- apps/web/src/stores/playback-store.ts | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'apps/web/src/stores') diff --git a/apps/web/src/stores/playback-store.ts b/apps/web/src/stores/playback-store.ts index 3c0bfdec..a4794b7f 100644 --- a/apps/web/src/stores/playback-store.ts +++ b/apps/web/src/stores/playback-store.ts @@ -6,15 +6,20 @@ interface PlaybackStore extends PlaybackState, PlaybackControls { setCurrentTime: (time: number) => void; } -let playbackTimer: NodeJS.Timeout | null = null; +let playbackTimer: number | null = null; const startTimer = (store: any) => { - if (playbackTimer) clearInterval(playbackTimer); + if (playbackTimer) cancelAnimationFrame(playbackTimer); - playbackTimer = setInterval(() => { + // Use requestAnimationFrame for smoother updates + const updateTime = () => { const state = store(); if (state.isPlaying && state.currentTime < state.duration) { - const newTime = state.currentTime + 0.1; + const now = performance.now(); + const delta = (now - lastUpdate) / 1000; // Convert to seconds + lastUpdate = now; + + const newTime = state.currentTime + (delta * state.speed); if (newTime >= state.duration) { state.pause(); } else { @@ -23,12 +28,16 @@ const startTimer = (store: any) => { window.dispatchEvent(new CustomEvent('playback-update', { detail: { time: newTime } })); } } - }, 100); + playbackTimer = requestAnimationFrame(updateTime); + }; + + let lastUpdate = performance.now(); + playbackTimer = requestAnimationFrame(updateTime); }; const stopTimer = () => { if (playbackTimer) { - clearInterval(playbackTimer); + cancelAnimationFrame(playbackTimer); playbackTimer = null; } }; @@ -38,6 +47,7 @@ export const usePlaybackStore = create((set, get) => ({ currentTime: 0, duration: 0, volume: 1, + speed: 1.0, play: () => { set({ isPlaying: true }); @@ -64,10 +74,20 @@ export const usePlaybackStore = create((set, get) => ({ set({ currentTime: clampedTime }); // Notify video elements to seek - window.dispatchEvent(new CustomEvent('playback-seek', { detail: { time: clampedTime } })); + const event = new CustomEvent('playback-seek', { detail: { time: clampedTime } }); + window.dispatchEvent(event); }, setVolume: (volume: number) => set({ volume: Math.max(0, Math.min(1, volume)) }), + + setSpeed: (speed: number) => { + const newSpeed = Math.max(0.1, Math.min(2.0, speed)); + set({ speed: newSpeed }); + + const event = new CustomEvent('playback-speed', { detail: { speed: newSpeed } }); + window.dispatchEvent(event); + }, + setDuration: (duration: number) => set({ duration }), setCurrentTime: (time: number) => set({ currentTime: time }), })); \ No newline at end of file -- cgit v1.3.1