Skip to content

Commit

Permalink
Fix subtitle disappearing after discontinuity for non-live/vod streams
Browse files Browse the repository at this point in the history
  • Loading branch information
gar7and committed Nov 15, 2018
1 parent c1f254c commit 689c4dc
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
20 changes: 11 additions & 9 deletions src/controller/timeline-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class TimelineController extends EventHandler {
this.textTracks = [];
this.tracks = [];
this.unparsedVttFrags = [];
this.initPTS = undefined;
this.initPTS = [];
this.cueRanges = [];
this.captionsTracks = {};

Expand Down Expand Up @@ -85,17 +85,19 @@ class TimelineController extends EventHandler {

// Triggered when an initial PTS is found; used for synchronisation of WebVTT.
onInitPtsFound (data) {
if (typeof this.initPTS === 'undefined') {
this.initPTS = data.initPTS;
let demuxerId = data.id, cc = data.frag.cc, initPTS = data.initPTS;
if (demuxerId === 'main') {
this.initPTS[cc] = initPTS;
}

// Due to asynchrony, initial PTS may arrive later than the first VTT fragments are loaded.
// Parse any unparsed fragments upon receiving the initial PTS.
if (this.unparsedVttFrags.length) {
this.unparsedVttFrags.forEach(frag => {
const unparsedVttFrags = this.unparsedVttFrags;
this.unparsedVttFrags = [];
unparsedVttFrags.forEach(frag => {
this.onFragLoaded(frag);
});
this.unparsedVttFrags = [];
}
}

Expand Down Expand Up @@ -180,7 +182,7 @@ class TimelineController extends EventHandler {
onManifestLoaded (data) {
this.textTracks = [];
this.unparsedVttFrags = this.unparsedVttFrags || [];
this.initPTS = undefined;
this.initPTS = [];
this.cueRanges = [];

if (this.config.enableWebVTT) {
Expand Down Expand Up @@ -233,7 +235,7 @@ class TimelineController extends EventHandler {
else if (frag.type === 'subtitle') {
if (payload.byteLength) {
// We need an initial synchronisation PTS. Store fragments as long as none has arrived.
if (typeof this.initPTS === 'undefined') {
if (this.initPTS[frag.cc] === undefined) {
this.unparsedVttFrags.push(data);
return;
}
Expand All @@ -260,7 +262,7 @@ class TimelineController extends EventHandler {
hls = this.hls;

// Parse the WebVTT file contents.
WebVTTParser.parse(payload, this.initPTS, vttCCs, frag.cc, function (cues) {
WebVTTParser.parse(payload, this.initPTS[frag.cc], vttCCs, frag.cc, function (cues) {
const currentTrack = textTracks[frag.trackId];
// WebVTTParser.parse is an async method and if the currently selected text track mode is set to "disabled"
// before parsing is done then don't try to access currentTrack.cues.getCueById as cues will be null
Expand Down Expand Up @@ -299,7 +301,7 @@ class TimelineController extends EventHandler {
frag = data.frag;

if (frag.type === 'subtitle') {
if (typeof this.initPTS === 'undefined') {
if (this.initPTS[frag.cc] === undefined) {
this.unparsedVttFrags.push(data);
return;
}
Expand Down
29 changes: 25 additions & 4 deletions src/utils/webvtt-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,29 @@ const calculateOffset = function (vttCCs, cc, presentationTime) {
vttCCs.presentationOffset = presentationTime;
};

const ptsNormalize = function (value, reference) {
let offset;
if (reference === undefined) {
return value;
}

if (reference < value) {
// - 2^33
offset = -8589934592;
} else {
// + 2^33
offset = 8589934592;
}
/* PTS is 33bit (from 0 to 2^33 -1)
if diff between value and reference is bigger than half of the amplitude (2^32) then it means that
PTS looping occured. fill the gap */
while (Math.abs(value - reference) > 4294967296) {
value += offset;
}

return value;
};

const WebVTTParser = {
parse: function (vttByteArray, syncPTS, vttCCs, cc, callBack, errorCallBack) {
// Convert byteArray into string, replacing any somewhat exotic linefeeds with "\n", then split on that character.
Expand Down Expand Up @@ -94,7 +117,7 @@ const WebVTTParser = {

if (presentationTime) {
// If we have MPEGTS, offset = presentation time + discontinuity offset
cueOffset = presentationTime + vttCCs.ccOffset - vttCCs.presentationOffset;
cueOffset = presentationTime - vttCCs.presentationOffset;
}

cue.startTime += cueOffset - localTime;
Expand Down Expand Up @@ -141,9 +164,7 @@ const WebVTTParser = {
try {
// Calculate subtitle offset in milliseconds.
// If sync PTS is less than zero, we have a 33-bit wraparound, which is fixed by adding 2^33 = 8589934592.
syncPTS = syncPTS < 0 ? syncPTS + 8589934592 : syncPTS;
// Adjust MPEGTS by sync PTS.
mpegTs -= syncPTS;
mpegTs = ptsNormalize(mpegTs - syncPTS, vttCCs.ccOffset * 90000);
// Convert cue time to seconds
localTime = cueString2millis(cueTime) / 1000;
// Convert MPEGTS to seconds from 90kHz.
Expand Down

0 comments on commit 689c4dc

Please sign in to comment.