Skip to content

Commit 22fcfc9

Browse files
committed
perf(subtitle): Optimize subtitle display performance
1 parent 7fb4228 commit 22fcfc9

File tree

3 files changed

+74
-10
lines changed

3 files changed

+74
-10
lines changed

composeApp/src/commonMain/kotlin/com/jankinwu/fntv/client/ui/screen/PlayerScreen.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -520,17 +520,23 @@ fun PlayerOverlay(
520520
while (isActive) {
521521
val currentPos = mediaPlayer.getCurrentPositionMillis()
522522
val adjustedPos = currentPos - (subtitleSettings.offsetSeconds * 1000).toLong()
523-
subtitleCues = hlsSubtitleUtil.getCurrentSubtitle(adjustedPos)
524-
delay(50)
523+
val newCues = hlsSubtitleUtil.getCurrentSubtitle(adjustedPos)
524+
if (subtitleCues != newCues) {
525+
subtitleCues = newCues
526+
}
527+
delay(16)
525528
}
526529
}
527530
} else if (externalSubtitleUtil != null) {
528531
launch {
529532
while (isActive) {
530533
val currentPos = mediaPlayer.getCurrentPositionMillis()
531534
val adjustedPos = currentPos - (subtitleSettings.offsetSeconds * 1000).toLong()
532-
subtitleCues = externalSubtitleUtil.getCurrentSubtitle(adjustedPos)
533-
delay(50)
535+
val newCues = externalSubtitleUtil.getCurrentSubtitle(adjustedPos)
536+
if (subtitleCues != newCues) {
537+
subtitleCues = newCues
538+
}
539+
delay(16)
534540
}
535541
}
536542
} else {

composeApp/src/commonMain/kotlin/com/jankinwu/fntv/client/utils/ExternalSubtitleUtil.kt

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class ExternalSubtitleUtil(
8282

8383
cues.clear()
8484
cues.addAll(parsedCues)
85+
cues.sortBy { it.startTime }
8586
isInitialized = true
8687
logger.i { "Initialized ExternalSubtitleUtil with ${cues.size} cues (${subtitleStream.format})" }
8788
} catch (e: Exception) {
@@ -91,9 +92,41 @@ class ExternalSubtitleUtil(
9192
}
9293

9394
fun getCurrentSubtitle(currentPositionMs: Long): List<SubtitleCue> {
94-
return cues.filter { cue ->
95-
currentPositionMs >= cue.startTime && currentPositionMs < cue.endTime
96-
}.distinctBy { it.text to it.assProps }
95+
if (cues.isEmpty()) return emptyList()
96+
97+
var low = 0
98+
var high = cues.size - 1
99+
var index = -1
100+
101+
// Find the last cue that starts before or at currentPositionMs
102+
while (low <= high) {
103+
val mid = (low + high) / 2
104+
if (cues[mid].startTime <= currentPositionMs) {
105+
index = mid
106+
low = mid + 1
107+
} else {
108+
high = mid - 1
109+
}
110+
}
111+
112+
if (index == -1) return emptyList()
113+
114+
val result = mutableListOf<SubtitleCue>()
115+
116+
// Iterate backwards from the found index
117+
for (i in index downTo 0) {
118+
val cue = cues[i]
119+
if (currentPositionMs < cue.endTime) {
120+
result.add(cue)
121+
}
122+
123+
// Optimization: Stop if we go back too far (e.g., 5 minutes)
124+
if (currentPositionMs - cue.startTime > 300000) {
125+
break
126+
}
127+
}
128+
129+
return result.reversed().distinctBy { it.text to it.assProps }
97130
}
98131

99132
private fun parseSrt(content: String): List<SubtitleCue> {

composeApp/src/commonMain/kotlin/com/jankinwu/fntv/client/utils/HlsSubtitleUtil.kt

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,35 @@ class HlsSubtitleUtil(
180180

181181
suspend fun getCurrentSubtitle(currentPositionMs: Long): List<SubtitleCue> {
182182
mutex.withLock {
183-
val activeCues = cues.filter { cue ->
184-
currentPositionMs >= cue.startTime && currentPositionMs < cue.endTime
183+
if (cues.isEmpty()) return emptyList()
184+
185+
var low = 0
186+
var high = cues.size - 1
187+
var index = -1
188+
189+
while (low <= high) {
190+
val mid = (low + high) / 2
191+
if (cues[mid].startTime <= currentPositionMs) {
192+
index = mid
193+
low = mid + 1
194+
} else {
195+
high = mid - 1
196+
}
197+
}
198+
199+
if (index == -1) return emptyList()
200+
201+
val result = mutableListOf<SubtitleCue>()
202+
for (i in index downTo 0) {
203+
val cue = cues[i]
204+
if (currentPositionMs < cue.endTime) {
205+
result.add(cue)
206+
}
207+
if (currentPositionMs - cue.startTime > 300000) {
208+
break
209+
}
185210
}
186-
return activeCues
211+
return result.reversed()
187212
}
188213
}
189214

0 commit comments

Comments
 (0)