fix: prevent concurrent frame fetching in VideoEngine

Added a flag to manage the fetching state of video frames in the VideoEngine class. This change ensures that the updateNextFrame method does not attempt to fetch new frames while a previous fetch is still in progress, preventing potential race conditions and improving stability during playback.
This commit is contained in:
Harvey Zhao committed 2026-01-01 17:32:21 +08:00
1 parent 9d760a2f59
commit d892685a25
4 files changed
+114 -101

No files matched your search

@@ -52,6 +52,7 @@ export default class VideoEngine {
this.stalled = false
this.playbackRate = 1
this.posterDrawn = false
this.isFetching = false
}
normalizeSource(src) {
@@ -197,37 +198,43 @@ export default class VideoEngine {
}
async updateNextFrame(localId) {
if (!this.videoIterator)
if (!this.videoIterator || this.isFetching)
return
while (true) {
const frame = (await this.videoIterator.next()).value ?? null
if (!frame || localId !== this.asyncId)
return
this.isFetching = true
try {
while (true) {
const frame = (await this.videoIterator.next()).value ?? null
if (!frame || localId !== this.asyncId)
return
const t = this.audioClock.currentTime
const tolerance = this.dropLateFrames
? Math.max(0.06, this.avSyncTolerance / Math.max(1, this.playbackRate))
: 0
const t = this.audioClock.currentTime
const tolerance = this.dropLateFrames
? Math.max(0.06, this.avSyncTolerance / Math.max(1, this.playbackRate))
: 0
if (this.dropLateFrames && frame.timestamp < t - tolerance) {
// Skip late frame
continue
}
if (this.dropLateFrames && frame.timestamp < t - tolerance) {
// Skip late frame
continue
}
if (frame.timestamp <= t + tolerance) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.ctx.drawImage(frame.canvas, 0, 0)
if (frame.timestamp <= t + tolerance) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.ctx.drawImage(frame.canvas, 0, 0)
if (!this.dropLateFrames && frame.timestamp > t) {
this.nextFrame = null
if (!this.dropLateFrames && frame.timestamp > t) {
this.nextFrame = null
return
}
}
else {
this.nextFrame = frame
return
}
}
else {
this.nextFrame = frame
return
}
}
finally {
this.isFetching = false
}
}