### Version Media3 main branch ### More version details Reproduced on main at commit 18ae2a419f. Also affects released versions that use the extraction-time subtitle path (TtmlParser / application/x-media3-cues). ### Devices that reproduce the issue Any device — the problem is in TTML parsing, not device-specific. Observed on a physical Android phone running the Media3 demo app and in a small native Media3 sample app. ### Devices that do not reproduce the issue Not applicable (parsing issue, independent of device).Not applicable (parsing issue, independent of device). ### Reproducible in the demo app? Yes ### Reproduction steps 1Take a DASH or HLS stream (or a standalone sidecar) whose TTML/IMSC subtitle carries the cue timing on a that wraps the , instead of on the itself. A minimal document that reproduces it: ``` Lara. Stil. ``` 2 Play it in the demo app and enable the subtitle track. 3 Observe the subtitles (or attach an onCues listener / Player.Listener.onCues). For comparison, the same content with the timing moved onto the renders correctly: ``` Lara. Stil. ``` ### Spec references - TTML2 §8.1.4 — default timeContainer is par: https://www.w3.org/TR/ttml2/ - TTML2 §12.2.1 — absent begin defaults to 0s relative to the nearest time container. - IMSC1.1 §6 feature table — #nested-div permitted in the Text profile: https://www.w3.org/TR/ttml-imsc1.1/ ### Expected result The cues are shown at their interval, e.g. "Lara." from 00:01:09.583 to 00:01:11.125 and "Stil." from 00:01:27.208 to 00:01:28.833 — the same as when the timing is on the . This is what the spec requires. A is a parallel time container by default (TTML2 §8.1.4), and a child with no begin defaults to begin = 0s relative to that container (TTML2 §12.2.1, citing SMIL 3.0 §5.4.3). So the should inherit the wrapping 's start time. The construct is valid IMSC1.1 Text profile (nested is permitted — IMSC1.1 §6 feature table, #nested-div). ### Actual result No subtitles are shown. When testing in a reference Media3 app with an onCues listener: On the default extraction-time path (MediaItem parsing, MIME application/x-media3-cues), onCues is called with 0 cues for the whole track. After forcing the legacy TtmlDecoder path, onCues does fire with the text, but every cue is active from the start of playback (out of sync) instead of at its interval: ``` onCues @ 1935063ms — 1 cue: "Pardon, c'est la première fois que je suis en cavale." onCues @ 1944000ms — 1 cue: "Tu as pris la main jusqu'ici." ``` Root cause: `TtmlParser.parseNode` only inherits end from a timed parent, not begin. When the has no begin, its startTimeUs is left unset. The extraction-time path (LegacySubtitleUtil#toCuesWithTiming) then never registers a start event for the cue, so no CuesWithTiming is emitted; the legacy path (TtmlNode#isActive) treats an unset start as "active from time 0", which is the out-of-sync behaviour. ### Media See the inline TTML above (self-contained, no DRM). Real-world example: AWS MediaConvert IMSC (application/ttml+xml) output for some titles emits the -wraps- shape; other titles emit timing directly on and play fine. Stripped reference TTML we used to reproduce the issue: ```xml Lorum. Ipsum. Demo line! Closing statement. ``` A small fix in `TtmlParser.parseNode` (inherit the parent's resolved start when the child's own begin is absent) resolves both symptoms. PR to follow. ### Bug Report - [ ] You will email the zip file produced by `adb bugreport` to android-media-github@google.com after filing this issue.