Skip to content

Commit 4e42502

Browse files
committed
Add lots of debug logging, limit render fps of events
1 parent 5430cc9 commit 4e42502

File tree

2 files changed

+97
-21
lines changed

2 files changed

+97
-21
lines changed

src/SubtitleOctopus.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,27 @@ double libassjs_find_next_event_start(double tm) {
102102
return closest / 1000.0;
103103
}
104104

105+
int _is_event_complex(ASS_Event *event) {
106+
// event is complex if it's animated in any way,
107+
// either by having non-empty Effect or
108+
// by having tags (enclosed in '{}' in Text)
109+
if (event->Effect && event->Effect[0] != '\0') return 1;
110+
111+
int escaped = 0;
112+
for (char *p = event->Text; *p != '\0'; p++) {
113+
switch (*p) {
114+
case '\\':
115+
escaped = !escaped;
116+
break;
117+
case '{':
118+
if (escaped) return 1;
119+
break;
120+
}
121+
}
122+
123+
return 0;
124+
}
125+
105126
void libassjs_find_event_stop_times(double tm, double *eventFinish, double *emptyFinish) {
106127
if (!track || track->n_events == 0) {
107128
*eventFinish = *emptyFinish = -1;
@@ -112,6 +133,7 @@ void libassjs_find_event_stop_times(double tm, double *eventFinish, double *empt
112133
long long now = (long long)(tm * 1000);
113134

114135
long long minFinish = -1, maxFinish = -1, minStart = -1;
136+
int current_animated = 0;
115137

116138
for (int i = 0; i < track->n_events; i++, cur++) {
117139
long long start = cur->Start;
@@ -124,12 +146,21 @@ void libassjs_find_event_stop_times(double tm, double *eventFinish, double *empt
124146
if (finish > maxFinish) {
125147
maxFinish = finish;
126148
}
149+
if (!current_animated && _is_event_complex(cur)) current_animated = 1;
127150
}
128151
} else if (start < minStart || minStart == -1) {
129152
minStart = start;
130153
}
131154
}
132155

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+
133164
if (minFinish != -1) {
134165
// some event is going on, so we need to re-draw either when it stops
135166
// or when some other event starts

src/subtitles-octopus.js

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ var SubtitlesOctopus = function (options) {
4343
self.oneshotState = {
4444
eventStart: null,
4545
eventOver: false,
46-
iteration: 0
46+
iteration: 0,
47+
renderRequested: false,
48+
requestNextTimestamp: -1
4749
}
4850

4951
self.hasAlphaBug = false;
@@ -175,6 +177,7 @@ var SubtitlesOctopus = function (options) {
175177
self.video = video;
176178
if (self.video) {
177179
if (self.renderAhead > 0) {
180+
console.debug('starting oneshot render because new video detected');
178181
window.requestAnimationFrame(oneshotRender);
179182
tryRequestOneshot();
180183
}
@@ -266,8 +269,9 @@ var SubtitlesOctopus = function (options) {
266269
return removed;
267270
}
268271

269-
function tryRequestOneshot(currentTime) {
272+
function tryRequestOneshot(currentTime, postIfBusy) {
270273
if (!self.renderAhead || self.renderAhead <= 0) return;
274+
if (self.oneshotState.renderRequested && !postIfBusy) return;
271275

272276
if (typeof currentTime === 'undefined') {
273277
if (!self.video) return;
@@ -277,31 +281,45 @@ var SubtitlesOctopus = function (options) {
277281
var size = 0;
278282
for (var i = 0, len = self.renderedItems.length; i < len; i++) {
279283
var item = self.renderedItems[i];
280-
if ((item.eventStart < 0 || currentTime >= item.eventStart) &&
281-
(item.emptyFinish < 0 || currentTime < item.emptyFinish)) {
284+
if (item.emptyFinish < 0) {
285+
console.info('oneshot already reached end-of-events');
286+
return;
287+
}
288+
if (currentTime >= item.eventStart && currentTime < item.emptyFinish) {
282289
// an event for requested time already exists
290+
console.debug('not requesting a render for ' + currentTime +
291+
' as event already covering it exists (start=' +
292+
item.eventStart + ', empty=' + item.emptyFinish + ')');
283293
return;
284294
}
285295
size += item.size;
286296
}
287297

288298
if (size <= self.renderAhead) {
289-
self.worker.postMessage({
290-
target: 'oneshot-render',
291-
lastRendered: currentTime - 0.001,
292-
renderNow: false,
293-
iteration: self.oneshotState.iteration
294-
});
299+
lastRendered = currentTime - 0.001;
300+
console.info('requesting new frame because current prerender size is less than limit (start=' + lastRendered + ')');
301+
if (!self.oneshotState.renderRequested) {
302+
self.oneshotState.renderRequested = true;
303+
self.worker.postMessage({
304+
target: 'oneshot-render',
305+
lastRendered: lastRendered,
306+
renderNow: false,
307+
iteration: self.oneshotState.iteration
308+
});
309+
} else {
310+
console.info('worker busy, requesting to seek');
311+
self.oneshotState.requestNextTimestamp = lastRendered;
312+
}
313+
} else {
314+
console.debug('not requesting new frame yet as prerender size is over limit');
295315
}
296316
}
297317

298318
function _renderSubtitleEvent(event, currentTime) {
299319
var eventOver = event.eventFinish < currentTime;
300320
if (self.oneshotState.eventStart == event.eventStart && self.oneshotState.eventOver == eventOver) return;
301-
self.oneshotState = {
302-
eventStart: event.eventStart,
303-
eventOver: eventOver
304-
};
321+
self.oneshotState.eventStart = event.eventStart;
322+
self.oneshotState.eventOver = eventOver;
305323

306324
var beforeDrawTime = performance.now();
307325
self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height);
@@ -325,25 +343,34 @@ var SubtitlesOctopus = function (options) {
325343
if (!self.video) return;
326344

327345
var currentTime = self.video.currentTime + self.timeOffset;
328-
var finishTime = -1;
346+
var finishTime = -1, eventShown = false;
329347
for (var i = 0, len = self.renderedItems.length; i < len; i++) {
330348
var item = self.renderedItems[i];
331-
if (item.eventStart <= currentTime && (item.emptyFinish < 0 || item.emptyFinish >= currentTime)) {
349+
if (!eventShown && item.eventStart <= currentTime && (item.emptyFinish < 0 || item.emptyFinish >= currentTime)) {
332350
_renderSubtitleEvent(item, currentTime);
351+
eventShown = true;
352+
}
353+
if (item.emptyFinish > finishTime) {
333354
finishTime = item.emptyFinish;
334-
break;
335355
}
336356
}
337357

338358
if (_cleanPastRendered(currentTime) && finishTime >= 0) {
339-
tryRequestOneshot(finishTime);
359+
console.debug('some prerendered frame retired, requesting new');
360+
if (eventShown) {
361+
tryRequestOneshot(finishTime);
362+
} else {
363+
tryRequestOneshot(currentTime, true);
364+
}
340365
}
341366
}
342367

343368
function resetRenderAheadCache() {
369+
console.debug('resetting prerender cache');
344370
self.renderedItems = [];
345371
self.oneshotState.eventStart = null;
346372
self.oneshotState.iteration++;
373+
self.oneshotState.renderRequested = false;
347374
tryRequestOneshot();
348375
}
349376

@@ -473,9 +500,14 @@ var SubtitlesOctopus = function (options) {
473500
}
474501
case 'oneshot-result': {
475502
if (data.iteration != self.oneshotState.iteration) {
476-
// stale render, ignore
503+
console.debug('received stale prerender, ignoring');
477504
return;
478505
}
506+
507+
console.info('oneshot received (start=' +
508+
data.eventStart + ', empty=' + data.emptyFinish +
509+
'), render: ' + Math.round(data.spentTime) + ' ms');
510+
self.oneshotState.renderRequested = false;
479511
var items = [];
480512
var size = 0;
481513
for (var i = 0, len = data.canvases.length; i < len; i++) {
@@ -489,6 +521,10 @@ var SubtitlesOctopus = function (options) {
489521
});
490522
size += item.buffer.byteLength;
491523
}
524+
if (data.emptyFinish > 0 && data.emptyFinish - data.eventStart < 1.0 / self.targetFps) {
525+
data.emptyFinish = data.eventStart + 1.0 / self.targetFps;
526+
data.eventFinish = data.emptyFinish;
527+
}
492528
self.renderedItems.push({
493529
eventStart: data.eventStart,
494530
eventFinish: data.eventFinish,
@@ -498,9 +534,18 @@ var SubtitlesOctopus = function (options) {
498534
items: items,
499535
size: size
500536
});
501-
if (data.emptyFinish >= 0) {
502-
// there's some more event to render, try doing so
537+
538+
if (self.oneshotState.requestNextTimestamp >= 0) {
539+
console.debug("requesting out of order event at " + self.oneshotState.requestNextTimestamp);
540+
tryRequestOneshot(self.oneshotState.requestNextTimestamp);
541+
self.oneshotState.requestNextTimestamp = -1;
542+
} else if (data.eventStart < 0) {
543+
console.info('oneshot received "end of frames" event');
544+
} else if (data.emptyFinish >= 0) {
545+
console.debug("there's some more event to render, try requesting next event");
503546
tryRequestOneshot(data.emptyFinish);
547+
} else {
548+
console.info('there are no more events to prerender');
504549
}
505550
break;
506551
}

0 commit comments

Comments
 (0)