Skip to content

Commit

Permalink
Fix blinking cues when segmented over multiple segments or chunks (co…
Browse files Browse the repository at this point in the history
…nt'd) (#4155)

* fix: extend last cue endTime in case of same cue but segmented over consecutive segments or chunks

* fix: extend last cue endTime in case of same cue but segmented over consecutive segments or chunks

* fix unit tests

* fix: extend last cue endTime in case of same cue but segmented over consecutive segments or chunks

* remove console.log

* Add setting parameters streaming.text.extendSegmentedCues to enable/disable patching of segmented cues

* Fix extendSegmentedCues jsdoc

* Fix blinking image cues

- resolve images urls in isd returned by imsc-1 lib before analysing and pushing the cues
- compare isd and not images and embeddedImages fields from TTML (since different images ids/references can refer to same image content)

* Fix contiguous cues management in case of some cues times overlap

* Fix blinking image cues

- fix regression for embedded cues

* TTMLParser: allow cue times not to be aligned with segment times
  • Loading branch information
bbert committed Apr 5, 2023
1 parent 93462ad commit 36af412
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 23 deletions.
61 changes: 40 additions & 21 deletions src/streaming/text/TextTracks.js
Expand Up @@ -38,8 +38,6 @@ import {renderHTML} from 'imsc';

const CUE_PROPS_TO_COMPARE = [
'text',
'images',
'embeddedImages',
'align',
'fontSize',
'id',
Expand Down Expand Up @@ -390,27 +388,31 @@ function TextTracks(config) {
}
}

function _resolveImageSrc(cue, src) {
const imsc1ImgUrnTester = /^(urn:)(mpeg:[a-z0-9][a-z0-9-]{0,31}:)(subs:)([0-9]+)$/;
const smpteImgUrnTester = /^#(.*)$/;
if (imsc1ImgUrnTester.test(src)) {
const match = imsc1ImgUrnTester.exec(src);
const imageId = parseInt(match[4], 10) - 1;
const imageData = btoa(cue.images[imageId]);
const imageSrc = 'data:image/png;base64,' + imageData;
return imageSrc;
} else if (smpteImgUrnTester.test(src)) {
const match = smpteImgUrnTester.exec(src);
const imageId = match[1];
const imageSrc = 'data:image/png;base64,' + cue.embeddedImages[imageId];
return imageSrc;
} else {
return src;
}
}

function _renderCaption(cue) {
if (captionContainer) {
const finalCue = document.createElement('div');
captionContainer.appendChild(finalCue);
previousISDState = renderHTML(cue.isd, finalCue, function (uri) {
const imsc1ImgUrnTester = /^(urn:)(mpeg:[a-z0-9][a-z0-9-]{0,31}:)(subs:)([0-9]+)$/;
const smpteImgUrnTester = /^#(.*)$/;
if (imsc1ImgUrnTester.test(uri)) {
const match = imsc1ImgUrnTester.exec(uri);
const imageId = parseInt(match[4], 10) - 1;
const imageData = btoa(cue.images[imageId]);
const dataUrl = 'data:image/png;base64,' + imageData;
return dataUrl;
} else if (smpteImgUrnTester.test(uri)) {
const match = smpteImgUrnTester.exec(uri);
const imageId = match[1];
const dataUrl = 'data:image/png;base64,' + cue.embeddedImages[imageId];
return dataUrl;
} else {
return null;
}
previousISDState = renderHTML(cue.isd, finalCue, function (src) {
return _resolveImageSrc(cue, src);
}, captionContainer.clientHeight, captionContainer.clientWidth, false/*displayForcedOnlyMode*/, function (err) {
logger.info('renderCaption :', err);
//TODO add ErrorHandler management
Expand All @@ -430,14 +432,14 @@ function TextTracks(config) {
const prevCue = track.cues[track.cues.length - 1];
// Check previous cue endTime with current cue startTime
// (should we consider an epsilon margin? for example to get around rounding issues)
if (prevCue.endTime !== cue.startTime) {
if (prevCue.endTime < cue.startTime) {
return false;
}
// Compare cues content
if (!_cuesContentAreEqual(prevCue, cue, CUE_PROPS_TO_COMPARE)) {
return false;
}
prevCue.endTime = cue.endTime;
prevCue.endTime = Math.max(prevCue.endTime, cue.endTime);
return true;
}

Expand All @@ -451,6 +453,18 @@ function TextTracks(config) {
return true;
}

function _resolveImagesInContents(cue, contents) {
if (!contents) {
return;
}
contents.forEach(c => {
if (c.kind && c.kind === 'image') {
c.src = _resolveImageSrc(cue, c.src);
}
_resolveImagesInContents(cue, c.contents);
});
}

/*
* Add captions to track, store for later adding, or add captions added before
*/
Expand Down Expand Up @@ -524,6 +538,11 @@ function TextTracks(config) {
captionContainer.style.width = actualVideoWidth + 'px';
captionContainer.style.height = actualVideoHeight + 'px';

// Resolve images sources
if (cue.isd) {
_resolveImagesInContents(cue, cue.isd.contents);
}

cue.onenter = function () {
if (track.mode === Constants.TEXT_SHOWING) {
if (this.isd) {
Expand Down
4 changes: 2 additions & 2 deletions src/streaming/utils/TTMLParser.js
Expand Up @@ -142,8 +142,8 @@ function TTMLParser() {

if (isd.contents.some(topLevelContents => topLevelContents.contents.length)) {
//be sure that mediaTimeEvents values are in the mp4 segment time ranges.
startTime = (mediaTimeEvents[i] + offsetTime) < startTimeSegment ? startTimeSegment : (mediaTimeEvents[i] + offsetTime);
endTime = (mediaTimeEvents[i + 1] + offsetTime) > endTimeSegment ? endTimeSegment : (mediaTimeEvents[i + 1] + offsetTime);
startTime = mediaTimeEvents[i] + offsetTime;
endTime = mediaTimeEvents[i + 1] + offsetTime;

if (startTime < endTime) {
captionArray.push({
Expand Down

0 comments on commit 36af412

Please sign in to comment.