Skip to content

Commit 21c84cc

Browse files
committed
* Start rendering only when video size is determined (e.g. video loaded or resized)
* Add bogus events covering timeline where there is no subtitles displayed * Fix seeking support
1 parent 90910bd commit 21c84cc

File tree

3 files changed

+66
-43
lines changed

3 files changed

+66
-43
lines changed

src/SubtitleOctopus.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ int _is_event_complex(ASS_Event *event) {
123123
return 0;
124124
}
125125

126-
void libassjs_find_event_stop_times(double tm, double *eventFinish, double *emptyFinish) {
126+
int libassjs_find_event_stop_times(double tm, double *eventFinish, double *emptyFinish) {
127127
if (!track || track->n_events == 0) {
128128
*eventFinish = *emptyFinish = -1;
129-
return;
129+
return 0;
130130
}
131131

132132
ASS_Event *cur = track->events;
@@ -153,14 +153,6 @@ void libassjs_find_event_stop_times(double tm, double *eventFinish, double *empt
153153
}
154154
}
155155

156-
if (current_animated) {
157-
printf("libass: detected animated event, forcing finish times to be +5ms from %f\n", tm);
158-
// what plays now is animated, so consider this event border to be
159-
// after 5ms from now, so it's properly redrawn afterwards
160-
*eventFinish = *emptyFinish = tm + 0.005;
161-
return;
162-
}
163-
164156
if (minFinish != -1) {
165157
// some event is going on, so we need to re-draw either when it stops
166158
// or when some other event starts
@@ -177,6 +169,8 @@ void libassjs_find_event_stop_times(double tm, double *eventFinish, double *empt
177169
// there's no empty space after eventFinish happens
178170
*emptyFinish = *eventFinish;
179171
}
172+
173+
return current_animated;
180174
}
181175

182176
class SubtitleOctopus {

src/post-worker.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,10 @@ self.blendRender = function (force) {
248248

249249
self.oneshotRender = function (lastRenderedTime, renderNow, iteration) {
250250
var eventStart = renderNow ? lastRenderedTime : self._find_next_event_start(lastRenderedTime);
251-
var eventFinish = -1.0, emptyFinish = -1.0;
251+
var eventFinish = -1.0, emptyFinish = -1.0, animated = false;
252252
var rendered = {};
253253
if (eventStart >= 0) {
254-
self._libassjs_find_event_stop_times(eventStart, self.eventFinish, self.emptyFinish);
254+
animated = self._find_event_stop_times(eventStart, self.eventFinish, self.emptyFinish) != 0;
255255
eventFinish = Module.getValue(self.eventFinish, 'double');
256256
emptyFinish = Module.getValue(self.emptyFinish, 'double');
257257

@@ -266,6 +266,7 @@ self.oneshotRender = function (lastRenderedTime, renderNow, iteration) {
266266
eventStart: eventStart,
267267
eventFinish: eventFinish,
268268
emptyFinish: emptyFinish,
269+
animated: animated,
269270
spentTime: rendered.spentTime || 0,
270271
blendTime: rendered.blendTime || 0,
271272
canvases: rendered.canvases || []

src/subtitles-octopus.js

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,6 @@ var SubtitlesOctopus = function (options) {
176176
self.setVideo = function (video) {
177177
self.video = video;
178178
if (self.video) {
179-
if (self.renderAhead > 0) {
180-
console.debug('starting oneshot render because new video detected');
181-
window.requestAnimationFrame(oneshotRender);
182-
tryRequestOneshot();
183-
}
184179
var timeupdate = function () {
185180
self.setCurrentTime(video.currentTime + self.timeOffset);
186181
}
@@ -267,11 +262,10 @@ var SubtitlesOctopus = function (options) {
267262
retainedItems.push(item);
268263
}
269264
}
265+
270266
if (seekClean && retainedItems.length > 0) {
271-
// order items by event start time
272-
retainedItems.sort(function (a, b) {
273-
return a.eventStart - b.eventStart;
274-
});
267+
// items are ordered by event start time when we push to self.renderedItems,
268+
// so first item is the earliest
275269
if (currentTime < retainedItems[0].eventStart) {
276270
if (retainedItems[0].eventStart - currentTime > 60) {
277271
console.info("seeked back too far, cleaning prerender buffer");
@@ -290,14 +284,15 @@ var SubtitlesOctopus = function (options) {
290284
}
291285
}
292286
}
293-
var removed = retainedItems.length != self.renderedItems.length;
287+
288+
var removed = retainedItems.length < self.renderedItems;
294289
self.renderedItems = retainedItems;
295290
return removed;
296291
}
297292

298-
function tryRequestOneshot(currentTime, postIfBusy) {
293+
function tryRequestOneshot(currentTime, renderNow) {
299294
if (!self.renderAhead || self.renderAhead <= 0) return;
300-
if (self.oneshotState.renderRequested && !postIfBusy) return;
295+
if (self.oneshotState.renderRequested && !renderNow) return;
301296

302297
if (typeof currentTime === 'undefined') {
303298
if (!self.video) return;
@@ -322,14 +317,14 @@ var SubtitlesOctopus = function (options) {
322317
}
323318

324319
if (size <= self.renderAhead) {
325-
lastRendered = currentTime - 0.001;
320+
lastRendered = currentTime - (renderNow ? 0 : 0.001);
326321
console.info('requesting new frame because current prerender size is less than limit (start=' + lastRendered + ')');
327322
if (!self.oneshotState.renderRequested) {
328323
self.oneshotState.renderRequested = true;
329324
self.worker.postMessage({
330325
target: 'oneshot-render',
331326
lastRendered: lastRendered,
332-
renderNow: false,
327+
renderNow: renderNow,
333328
iteration: self.oneshotState.iteration
334329
});
335330
} else {
@@ -369,35 +364,47 @@ var SubtitlesOctopus = function (options) {
369364
if (!self.video) return;
370365

371366
var currentTime = self.video.currentTime + self.timeOffset;
372-
var finishTime = -1, eventShown = false;
367+
var finishTime = -1, eventShown = false, animated = false;
373368
for (var i = 0, len = self.renderedItems.length; i < len; i++) {
374369
var item = self.renderedItems[i];
375370
if (!eventShown && item.eventStart <= currentTime && (item.emptyFinish < 0 || item.emptyFinish >= currentTime)) {
376371
_renderSubtitleEvent(item, currentTime);
377372
eventShown = true;
378-
}
379-
if (item.emptyFinish > finishTime) {
380373
finishTime = item.emptyFinish;
374+
} else if (finishTime >= 0) {
375+
// we've already found a known event, now find
376+
// the farthest point of consequent events
377+
// NOTE: self.renderedItems may have gaps due to seeking
378+
if (item.eventStart - finishTime < 0.01) {
379+
finishTime = item.emptyFinish;
380+
animated = item.animated;
381+
} else {
382+
break;
383+
}
381384
}
382385
}
383386

384387
if (!eventShown) {
385-
if (Math.abs(self.oneshotState.requestNextTimestamp - currentTime) > 0.1) {
388+
if (Math.abs(self.oneshotState.requestNextTimestamp - currentTime) > 0.01) {
386389
tryRequestOneshot(currentTime, true);
387390
}
388391
} else if (_cleanPastRendered(currentTime) && finishTime >= 0) {
389392
console.debug('some prerendered frame retired, requesting new');
390-
tryRequestOneshot(finishTime);
393+
tryRequestOneshot(finishTime, animated);
391394
}
392395
}
393396

394397
function resetRenderAheadCache() {
395-
console.debug('resetting prerender cache');
396-
self.renderedItems = [];
397-
self.oneshotState.eventStart = null;
398-
self.oneshotState.iteration++;
399-
self.oneshotState.renderRequested = false;
400-
tryRequestOneshot();
398+
if (self.renderAhead > 0) {
399+
console.debug('resetting prerender cache');
400+
self.renderedItems = [];
401+
self.oneshotState.eventStart = null;
402+
self.oneshotState.iteration++;
403+
self.oneshotState.renderRequested = false;
404+
405+
window.requestAnimationFrame(oneshotRender);
406+
tryRequestOneshot(undefined, true);
407+
}
401408
}
402409

403410
self.renderFrameData = null;
@@ -534,9 +541,22 @@ var SubtitlesOctopus = function (options) {
534541
data.eventStart + ', empty=' + data.emptyFinish +
535542
'), render: ' + Math.round(data.spentTime) + ' ms');
536543
self.oneshotState.renderRequested = false;
537-
if (data.lastRenderedTime == self.oneshotState.requestNextTimestamp) {
544+
if (Math.abs(data.lastRenderedTime - self.oneshotState.requestNextTimestamp) < 0.01) {
538545
self.oneshotState.requestNextTimestamp = -1;
539546
}
547+
if (data.eventStart - data.lastRenderedTime > 0.01) {
548+
// generate bogus empty element, so all timeline is covered anyway
549+
self.renderedItems.push({
550+
eventStart: data.lastRenderedTime,
551+
eventFinish: data.lastRenderedTime - 0.001,
552+
emptyFinish: data.eventStart,
553+
spentTime: 0,
554+
blendTime: 0,
555+
items: [],
556+
animated: false,
557+
size: 0
558+
});
559+
}
540560

541561
var items = [];
542562
var size = 0;
@@ -551,9 +571,12 @@ var SubtitlesOctopus = function (options) {
551571
});
552572
size += item.buffer.byteLength;
553573
}
554-
if (data.emptyFinish > 0 && data.emptyFinish - data.eventStart < 1.0 / self.targetFps) {
555-
data.emptyFinish = data.eventStart + 1.0 / self.targetFps;
556-
data.eventFinish = data.emptyFinish;
574+
if ((data.emptyFinish > 0 && data.emptyFinish - data.eventStart < 1.0 / self.targetFps) || data.animated) {
575+
newFinish = data.eventStart + 1.0 / self.targetFps;
576+
if (newFinish < data.emptyFinish) {
577+
data.emptyFinish = newFinish;
578+
data.eventFinish = (data.eventFinish > newFinish) ? newFinish : data.eventFinish;
579+
}
557580
}
558581
self.renderedItems.push({
559582
eventStart: data.eventStart,
@@ -562,17 +585,22 @@ var SubtitlesOctopus = function (options) {
562585
spentTime: data.spentTime,
563586
blendTime: data.blendTime,
564587
items: items,
588+
animated: data.animated,
565589
size: size
566590
});
591+
592+
self.renderedItems.sort(function (a, b) {
593+
return a.eventStart - b.eventStart;
594+
});
567595

568596
if (self.oneshotState.requestNextTimestamp >= 0) {
569597
console.debug("requesting out of order event at " + self.oneshotState.requestNextTimestamp);
570-
tryRequestOneshot(self.oneshotState.requestNextTimestamp);
598+
tryRequestOneshot(self.oneshotState.requestNextTimestamp, true);
571599
} else if (data.eventStart < 0) {
572600
console.info('oneshot received "end of frames" event');
573601
} else if (data.emptyFinish >= 0) {
574602
console.debug("there's some more event to render, try requesting next event");
575-
tryRequestOneshot(data.emptyFinish);
603+
tryRequestOneshot(data.emptyFinish, data.animated);
576604
} else {
577605
console.info('there are no more events to prerender');
578606
}

0 commit comments

Comments
 (0)