dash.js
Open Source Media Player
Seamless and reliable DASH streaming on any browser-based device
View onGitHub
5506
1728
504.2k
Sponsors
Trusted by the industry leaders
Latest updates from GitHub
parseXml: optimize DASH SegmentTimeline <S> parsing**Is your feature request related to a problem? Please describe.**
Yes.
Large DASH live DVR manifests block the main thread during parsing.
This issue is about the XML parser project [`@svta/cml-xml`](https://github.com/streaming-video-technology-alliance/common-media-library/tree/main/libs/xml), not about changing dash.js itself. dash.js is only the workload used to measure the problem.
On an XL synthetic manifest (50 Periods x 4 AdaptationSets x 500 `S` entries, about 102k XML nodes), the full dash.js manifest parse takes about 40 ms on an M1. The XML parser alone takes about 30.5 ms of that total, or 62%.
About 98% of the nodes in these manifests are `SegmentTimeline` `<S>` entries. They are simple self-closing nodes with only integer attributes like `t`, `d`, `r`, and `k`, but they still go through the full generic parsing path.
**Describe the solution you'd like**
Add a specialized fast path in `parseXml()` for self-closing DASH `SegmentTimeline` `<S>` nodes.
The proposed implementation should happen in [`@svta/cml-xml`](https://github.com/streaming-video-technology-alliance/common-media-library/tree/main/libs/xml), inside `parseXml()`.
**Expected behavior**
- detect `<S ... />` nodes while parsing
- parse `t`, `d`, `r`, and `k` directly as integers
- skip `unescapeHtml()` for numeric attributes
- avoid unnecessary generic attribute parsing work for these nodes
- reuse a shared empty `childNodes` array for self-closing nodes when safe
- preserve the current output shape
In a synthetic benchmark, a specialized eager parser for `<S>` nodes reduced the XML parsing cost from about 39.8 ms to about 19.1 ms on the XL manifest, a reduction of about 52% (`~2.1x` faster).
**Describe alternatives you've considered**
- Lazy parsing of `SegmentTimeline.S`
Rejected. These entries are typically consumed immediately after manifest parsing for duration calculation, segment counting, and segment lookup.
- A local XML parser variant inside dash.js
Rejected. A local clone was slower than the current `@svta/cml-xml` implementation in synthetic benchmarks.
- A downstream dash.js optimization in `DashParser.processNode()`
Useful, but secondary. For example, replacing `arrayNodes.indexOf()` with `Set.has()` helps, but the main bottleneck is still `cmlParseXml()`.
**Additional context**
**Example hot-case nodes**
```xml
<S t="123456" d="180000" />
<S d="180000" r="14" />
<S d="180000" r="-1" k="3" />
```
**Reproduction**
```bash
node test/bench-manifest-parsing.mjs
node test/bench-parsexml.mjs
```
**Real public live DVR example**
- `https://livesim2.dashif.org/livesim2/segtimeline_1/tsbd_21600/testpic_2s/Manifest.mpd`
- verified on March 10, 2026
- `timeShiftBufferDepth="PT6H"`
- about 170 KB
- about 5402 literal `<S>` nodes in the fetched MPD
**Larger multi-period variant**
- `https://livesim2.dashif.org/livesim2/segtimeline_1/tsbd_21600/periods_60/continuous_1/testpic_2s/Manifest.mpd`
- `timeShiftBufferDepth="PT6H"`
- about 901 KB
- 361 periods
- about 5942 literal `<S>` nodes in the fetched MPD
**Why this matters for users**
- on desktop, `39.8 ms -> 19.1 ms` still means about 52% less XML parsing work on the main thread
- on lower-end Smart TV / STB class hardware, that same reduction can translate to roughly 100-200 ms less blocking per manifest refresh
- on live DVR streams, this cost repeats on every manifest update cycle, so users can experience recurring UI hitching rather than a one-time delay
**Environment used for the measurements above**
- dash.js v5.2.0
- [`@svta/cml-xml`](https://github.com/streaming-video-technology-alliance/common-media-library/tree/main/libs/xml) 1.0.1
**What would make this complete**
- no observable output change for current consumers
- measurable improvement on large DASH manifests with dense `SegmentTimeline`
- no regression on non-DASH XML inputs
- benchmark or test coverage proving both correctness and performance
Opened by PascalThuet—22 hours ago
DVBSelector: last BaseURL never selected with equal weights (off-by-one in weighted random)##### Environment
- [x] The MPD passes the DASH-IF Conformance Tool on https://conformance.dashif.org/
- [x] The stream has correct Access-Control-Allow-Origin headers (CORS)
- [x] There are no network errors such as 404s in the browser console when trying to play the stream
- [x] The issue observed is not mentioned on https://github.com/Dash-Industry-Forum/dash.js/wiki/FAQ
- [x] The issue occurs in the latest reference client on http://reference.dashif.org/dash.js/ and not just on my page
* Link to playable MPD file: `samples/advanced/mpds/basic-cmcd-config.mpd` (3 BaseURLs, no `dvb:weight`) — remove the `<ContentSteering>` element to expose the bug (Content Steering overrides DVB selection)
* Dash.js version: 5.2.0 (development branch)
* Browser name/version: all (logic bug, not browser-specific)
* OS name/version: all
##### Steps to reproduce
1. Load an MPD with 2+ `<BaseURL>` elements at the same priority, without `dvb:weight` (defaults to 1) and without `<ContentSteering>`
2. Observe which CDN is selected across multiple sessions
> **Note:** `samples/advanced/mpds/basic-cmcd-config.mpd` has 3 BaseURLs without `dvb:weight` but uses Content Steering, which overrides DVB selection and masks the bug.
##### Observed behavior
The last BaseURL in a weighted group is never selected.
`DVBSelector.js` line 114:
```javascript
rn = Math.floor(Math.random() * (totalWeight - 1));
```
`Math.random()` returns `[0, 1)`, so `Math.floor(Math.random() * totalWeight)` already produces `[0, totalWeight-1]`. The extra `- 1` shrinks the range and excludes the last CDN.
**Example : 2 equal-weight CDNs** (most common multi-CDN setup):
`totalWeight = 2`, `cumulWeights = [1, 2]`:
```
rn = Math.floor(Math.random() * 1) = always 0 → always cdn-a, cdn-b never selected
```
##### Console output
```
No error — the bug is silent.
```
##### Expected behavior
Each BaseURL selected with probability proportional to its weight (RFC 2782). With equal weights: ~50/50 for 2 CDNs, ~33/33/33 for 3 CDNs.
Opened by PascalThuet—3 days ago
[DASH] MEDIA_ERR_DECODE when manifest transitions from dynamic to static (live-to-VOD)Description:
When a DASH manifest transitions from type="dynamic" (live) to type="static" (VOD),
VHS detects excessive audio segment downloading and blacklists all available playlists,
resulting in a fatal MEDIA_ERR_DECODE with no recovery path.
Steps to Reproduce:
Load a DASH stream with type="dynamic" (live stream)
Wait for the manifest to transition to type="static" (VOD/live-to-VOD)
Audio segments are repeatedly re-downloaded
Player throws fatal error
Expected Behavior:
Automatically re-parse manifest as VOD
Resume playback without fatal error
Actual Behavior
Excessive audio segment downloading detected.
Switching to playlist 0-placeholder-uri-0.
Playback cannot continue. No available working or supported playlists.
MediaError { code: 3, message: 'Playback cannot continue...' }
Opened by rakeshLogituit—6 days ago






