fix(mpv): Add progress throttling for mpv (#1366)
Some checks failed
🏗️ Build Apps / 🤖 Build Android APK (Phone) (push) Has been cancelled
🏗️ Build Apps / 🤖 Build Android APK (TV) (push) Has been cancelled
🏗️ Build Apps / 🍎 Build iOS IPA (Phone) (push) Has been cancelled
🏗️ Build Apps / 🍎 Build iOS IPA (Phone - Unsigned) (push) Has been cancelled
🔒 Lockfile Consistency Check / 🔍 Check bun.lock and package.json consistency (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (actions) (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (javascript-typescript) (push) Has been cancelled
🏷️🔀Merge Conflict Labeler / 🏷️ Labeling Merge Conflicts (push) Has been cancelled
🚦 Security & Quality Gate / 📝 Validate PR Title (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Vulnerable Dependencies (push) Has been cancelled
🚦 Security & Quality Gate / 🚑 Expo Doctor Check (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (check) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (format) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (lint) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (typecheck) (push) Has been cancelled

This commit is contained in:
Alex
2026-01-14 23:14:52 +11:00
committed by GitHub
parent ca1b640a61
commit 81f79a54af
2 changed files with 60 additions and 6 deletions

View File

@@ -50,6 +50,23 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver {
private var _isLoading: Boolean = false
private var _playbackSpeed: Double = 1.0
private var isReadyToSeek: Boolean = false
// Progress update throttling - CRITICAL for performance!
// DO NOT REMOVE THIS THROTTLE - it is essential for battery life and CPU efficiency.
//
// Without throttling, time-pos fires every video frame (24+ times/sec at 24fps).
// Each update crosses the React Native JS bridge, which is expensive on mobile.
// Even if the JS side does nothing, 24+ bridge calls/sec wastes CPU and battery.
//
// Throttling to 1 update/sec during normal playback is sufficient for:
// - Progress bar updates (users can't perceive 1-second granularity)
// - Playback position tracking
// - Any JS-side logic that needs current position
//
// During seeking, we bypass the throttle for responsive scrubbing.
// This optimization reduced CPU usage by ~50% for downloaded file playback.
private var lastProgressUpdateTime: Long = 0
private var _isSeeking: Boolean = false
// Video dimensions
private var _videoWidth: Int = 0
@@ -548,7 +565,13 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver {
}
"time-pos" -> {
cachedPosition = value
mainHandler.post { delegate?.onPositionChanged(cachedPosition, cachedDuration) }
// Always update immediately when seeking, otherwise throttle to once per second
val now = System.currentTimeMillis()
val shouldUpdate = _isSeeking || (now - lastProgressUpdateTime >= 1000)
if (shouldUpdate) {
lastProgressUpdateTime = now
mainHandler.post { delegate?.onPositionChanged(cachedPosition, cachedDuration) }
}
}
}
}
@@ -580,7 +603,8 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver {
}
}
MPVLib.MPV_EVENT_SEEK -> {
// Seek started - show loading indicator
// Seek started - show loading indicator and enable immediate progress updates
_isSeeking = true
if (!_isLoading) {
_isLoading = true
mainHandler.post { delegate?.onLoadingChanged(true) }
@@ -588,6 +612,7 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver {
}
MPVLib.MPV_EVENT_PLAYBACK_RESTART -> {
// Video playback has started/restarted (including after seek)
_isSeeking = false
if (_isLoading) {
_isLoading = false
mainHandler.post { delegate?.onLoadingChanged(false) }