Skip to content

fix: delay appending vtt subtitles depending on presence of discontinuity sequence and timestamp offset#9676

Open
gkatsev wants to merge 6 commits intoshaka-project:mainfrom
sky-hugolima:vtt-timing-fix
Open

fix: delay appending vtt subtitles depending on presence of discontinuity sequence and timestamp offset#9676
gkatsev wants to merge 6 commits intoshaka-project:mainfrom
sky-hugolima:vtt-timing-fix

Conversation

@gkatsev
Copy link
Contributor

@gkatsev gkatsev commented Feb 5, 2026

This PR changes the way that timestamp offsets are stored in the media source engine. Instead of a single value, it now has a map of values. For DASH, it should contain a single value, which is the last timestamp offset available. For HLS, it'll keep track of the timestamp offsets per discontinuity sequence. If content is appended and we don't yet have a timestamp offset for that discontinuity sequence number, it'll defer creating the cues until the timestamp offset is set, otherwise, the times for the cues may not be correct.

Fixes #9470

@google-cla
Copy link

google-cla bot commented Feb 5, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 5, 2026

the PR build is failing because there's a leading space character but seems like I can't edit the PR title.

@avelad
Copy link
Member

avelad commented Feb 5, 2026

@shaka-bot test

@shaka-bot
Copy link
Collaborator

@avelad: Lab tests started with arguments:

  • pr=9676

@avelad avelad added type: bug Something isn't working correctly priority: P1 Big impact or workaround impractical; resolve before feature release component: WebVTT The issue involves WebVTT subtitles specifically labels Feb 5, 2026
@avelad avelad added this to the v5.0 milestone Feb 5, 2026
@shaka-bot
Copy link
Collaborator

shaka-bot commented Feb 5, 2026

Bundle Size Report for PR #9676

File HEAD Base Diff
build_state.json 0.8 KiB (0.5 KiB) 0.8 KiB (0.5 KiB) 0.0 KiB
controls.css 23.3 KiB (4.9 KiB) 23.3 KiB (4.9 KiB) 0.0 KiB
demo.compiled.debug.js 239.2 KiB (48.2 KiB) 239.2 KiB (48.2 KiB) 0.0 KiB
demo.compiled.js 239.2 KiB (48.2 KiB) 239.2 KiB (48.2 KiB) 0.0 KiB
demo.css 169.9 KiB (27.7 KiB) 169.9 KiB (27.7 KiB) 0.0 KiB
locales.js 42.6 KiB (10.6 KiB) 42.6 KiB (10.6 KiB) 0.0 KiB
receiver.compiled.debug.js 143.2 KiB (23.7 KiB) 143.2 KiB (23.7 KiB) 0.0 KiB
receiver.compiled.js 143.2 KiB (23.7 KiB) 143.2 KiB (23.7 KiB) 0.0 KiB
shaka-player.compiled.debug.js 1491.3 KiB (340.8 KiB) 1490.4 KiB (340.5 KiB) +0.9 KiB
shaka-player.compiled.js 747.3 KiB (241.9 KiB) 746.7 KiB (241.7 KiB) +0.6 KiB
shaka-player.dash.debug.js 1090.6 KiB (254.6 KiB) 1089.7 KiB (254.3 KiB) +0.9 KiB
shaka-player.dash.js 513.5 KiB (170.1 KiB) 512.9 KiB (169.8 KiB) +0.6 KiB
shaka-player.experimental.debug.js 1873.5 KiB (420.9 KiB) 1872.7 KiB (420.6 KiB) +0.9 KiB
shaka-player.experimental.js 982.8 KiB (306.4 KiB) 982.2 KiB (306.1 KiB) +0.6 KiB
shaka-player.hls.debug.js 1127.8 KiB (260.9 KiB) 1126.9 KiB (260.6 KiB) +0.9 KiB
shaka-player.hls.js 551.9 KiB (181.7 KiB) 551.3 KiB (181.5 KiB) +0.6 KiB
shaka-player.ui.debug.js 1812.5 KiB (407.9 KiB) 1811.7 KiB (407.6 KiB) +0.9 KiB
shaka-player.ui.js 956.5 KiB (298.4 KiB) 955.9 KiB (298.2 KiB) +0.6 KiB

@shaka-bot
Copy link
Collaborator

shaka-bot commented Feb 5, 2026

Incremental code coverage: 90.77%

@avelad
Copy link
Member

avelad commented Feb 6, 2026

It seems that fails in some platforms... can you review it? Thanks!

@TAhub TAhub changed the title fix: delay appending vtt subtitles depending on presence of discontinuity sequence and timestamp offset fix: delay appending vtt subtitles depending on presence of discontinuity sequence and timestamp offset Feb 6, 2026
@avelad avelad modified the milestones: v5.0, v5.1 Feb 6, 2026
return inside;
};

if (!this.deferredAppends_) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deferredAppends_ seems always truthy, making this condition dead code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! It must've stayed from an earlier version where it wasn't always set.

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 9, 2026

So, I think the test failures happen if the subtitles take a while to load and the second video segment ends up loading first, which changes the timestamp offset when they're parsed. During my testing previously, this is basically the same behavior as shaka had before this change.
At one point I experimented with not letting a timestamp offset get overridden once set but I think there were some scenarios that weren't correct.
A way to force this to happen for the one test is to add || this.timestampOffsetMap_.get(disco) != -1.4 to the .has(disco) in appendBuffer.

@avelad
Copy link
Member

avelad commented Feb 10, 2026

So, I think the test failures happen if the subtitles take a while to load and the second video segment ends up loading first, which changes the timestamp offset when they're parsed. During my testing previously, this is basically the same behavior as shaka had before this change. At one point I experimented with not letting a timestamp offset get overridden once set but I think there were some scenarios that weren't correct. A way to force this to happen for the one test is to add || this.timestampOffsetMap_.get(disco) != -1.4 to the .has(disco) in appendBuffer.

That sounds like a hack with a magic number... I think the ideal solution is to find the root cause and fix it. Modifying the test to wait a certain amount of time is also a solution.

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 10, 2026

Oh, yeah, I didn't mean it was a solution but rather a way to reliably trigger the conditions for the test failure. I'll continue investigating this today.

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 10, 2026

ok, I think the root cause is the change in media source engine where previously the promise only got reset in resync which is only called in some cases, like when a disco sequence changes but now the timestamp offset always gets updated. I'll need to do some more testing on this.

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 10, 2026

It seems like having the timestamp offset only get set once per discontinuity makes the tests pass. Potentially, would need a way to unset it in the case of a resync call.
Going to continue looking into it and run some more tests on our streams to make sure that it doesn't cause other issues.

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 13, 2026

ok, I added a check for whether the timestamp offset should get updated or not. In my testing it seems to be working fine for both multiperiod DASH and HLS content with discontinuities.

One thing to thing I noticed is that in DASH, when seeking back across a period, shaka inserts the init segment from the period we seeked away from resulting in the captions being offset. It doesn't always happen but it isn't hard to reproduce. This PR doesn't address that issue. While it may be possible to work around it on the text engine/MSE side, it might be nice to figure out why the incorrect init segments gets appended.

* @param {shaka.extern.TextDisplayer} displayer
* @param {string=} manifestType
*/
constructor(displayer, manifestType = shaka.media.ManifestParser.DASH) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that the manifest type is passed here, we technically don't need to pass it in initParser below. I didn't make that change yet, but happy to do so.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do it ! Thanks!

@avelad
Copy link
Member

avelad commented Feb 13, 2026

@shaka-bot test

@shaka-bot
Copy link
Collaborator

@avelad: Lab tests started with arguments:

  • pr=9676

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 13, 2026

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 13, 2026

running the test locally in safari via karma's debug page seems to pass. It's off by exactly the first timestamp offset still.

@gkatsev
Copy link
Contributor Author

gkatsev commented Feb 13, 2026

I can reproduce when running karma on safari directly, so, I guess I'll take another look at it next week.

/** @private {Map<number, number>} */
this.timestampOffsetMap_ = new Map();
// default timestamp offset for no discontinuities to 0
this.timestampOffsetMap_.set(-1, 0);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the root cause of the new failure is this change. While it seems to work for the most part, it means that there's a chance that we get text segments appended before a proper timestamp offset is set from the media source engine. It was initially added because a bunch of tests were failing and that worked around it. Instead, probably need to remove it and fixup the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: WebVTT The issue involves WebVTT subtitles specifically priority: P1 Big impact or workaround impractical; resolve before feature release type: bug Something isn't working correctly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VTT subtitles timing misalignment on HLS if the timestamp map doesn't account for discontinuity sequences

4 participants