Commit Graph

1436 Commits

Author SHA1 Message Date
Álvaro Velad Galván c306ac3501 feat(Cast): Dynamically proxy player and ad events using FakeEventTarget.ALL_EVENTS (#10168)
- Exposed and renamed `shaka.util.FakeEventTarget.ALL_EVENTS_` to
`ALL_EVENTS`, updating its value to `__shaka_all_events__` to prevent
string collisions.
- Refactored `CastProxy` and `CastReceiver` to subscribe directly to
this wildcard event for both the Player and the AdManager instances.
- Removed the hardcoded `shaka.cast.CastUtils.AdManagerEvents` array and
eliminated the loops that iterated over static event lists.

This makes the casting event proxy layer completely dynamic, cleaner,
and future-proof against new event additions to either the Player or the
AdManager.
2026-06-02 14:07:22 +02:00
Ivan 921206dc1d feat: transmux in a worker (#9914)
This PR introduces a Web Worker for transmuxing resolving
https://github.com/shaka-project/shaka-player/issues/1735

- The worker bundle is compiled separately
- The build output is embedded as a string constant and then wrapped in
a Blob to create an inline Worker URL (HLS.js does this very similarly)
- `TransmuxerProxy` is created wrapping a real transmuxer, but no worker
is started yet - on the first `transmux()` call, it checks if the device
supports worker transmuxing
- For each transmux() call: the buffer is copied, then zero-copy
transferred to the worker. A PublicPromise is stored under a reqId with
a timeout timer, and the main thread awaits it.
- The worker transmuxes and posts back transmuxed (or error). The shared
message listener routes the response to the right proxy instance by id,
which resolves the promise and cancels the timer.
- When the last proxy instance is destroyed, the worker is terminated
and the blob URL is revoked.
  loaded inside the worker.
- Some low-end devices have been excluded since their Worker support is
questionable

There most likely is a better way to do this - please let me know
2026-05-27 21:51:03 +02:00
Álvaro Velad Galván ce7ee4b76f fix: Map the "audio/x-mpegurl" MIME type as HLS (#10114) 2026-05-21 09:41:45 +02:00
Álvaro Velad Galván 67b0a177b4 feat: Add support for ID3v1 and IDv2.3 (#10108)
v2.3 support is required for some HLS streams.
v1 support is not yet needed in this pull request, but it may be in a
future one.
2026-05-20 10:35:29 +02:00
Ivan 5492f31b1a perf(Mp4Generator): assemble segment data in a single allocation (#10101)
This PR reduces allocation pressure in MP4 segment generation by writing
mdat data directly into the final segment buffer - this avoids one full
media-payload copy per segment
2026-05-18 10:59:39 +02:00
absidue de30b7003a perf(transmuxer): Avoid repeatedly creating empty Uint8Arrays (#10100)
In `H264.getVideoSamples()` `lastVideoSample.data` is initialized with
an empty `Uint8Array` which is always replaced before the sample is
pushed into the `videoSamples` array, so to avoid creating a new empty
placeholder `Uint8Array` for each sample, the empty `Uint8Array` can be
created once and then use to initialize all `lastVideoSample` objects in
that segment.

`TSParser.parsePES_` had a similar placeholder empty `Uint8Array` issue,
which I was able to resolve by creating the PES object in the return
statement instead of upfront, that way it can be initialized with the
final data, avoiding the placeholder.

While yes empty Uint8Arrays definitely need less memory than larger
ones, it is still better to not create 100+ unnecessary objects in rapid
succession which then need to be cleaned up by the garbage collector
later on.
2026-05-18 09:49:44 +02:00
absidue 12308b5a73 chore: Tidy up array pop() with subsequent re-push() (#10099) 2026-05-18 09:14:52 +02:00
Álvaro Velad Galván 2c4499f153 chore(Mp4Parser): introduce boxes() for multiple box registration (#10091) 2026-05-14 22:56:06 +02:00
absidue 2ac1c3c4fd chore: Make Mp4Generator.allocBox_ private and use it more (#10092) 2026-05-14 18:04:07 +02:00
Álvaro Velad Galván e9551b3ee2 feat(MSF): Add accessibility parsing in the catalog (CEA-608/708) (#10040)
Related to https://github.com/moq-wg/msf/pull/133
2026-05-12 21:15:17 +02:00
Álvaro Velad Galván 19b2c10bd4 feat: Add timeToFirstFrame to stats (#10065) 2026-05-07 20:28:17 +02:00
absidue b5ad8ccc8c perf: Remove unnecessary Uint8Array allocations in Mp4Generator (#10069)
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
2026-05-07 09:49:07 +02:00
Álvaro Velad Galván 71ccb11cd6 perf: Remove unnecessary allocations in Mp4Generator (#10059) 2026-05-06 09:41:28 +02:00
Karim Laham 27ed71e791 feat(UITextDisplayer): add suspendRenderingWhenHidden config (#10043)
Closes #10042

Adds a `textDisplayer.suspendRenderingWhenHidden` config flag that gates
the IntersectionObserver-based render suspension introduced in #9545.

- Defaults to `true` (existing behavior preserved for browsers/desktop).
- Defaults to `false` on TV devices (detected via
`shaka.device.DeviceFactory.getDevice().getDeviceType() ===
DeviceType.TV`).

Some TV browsers (e.g. older Tizen WebKit) misreport
`IntersectionObserver` visibility for transformed/absolute-positioned
player containers, leading to permanently suspended caption rendering.
Disabling suspension on TVs sidesteps the platform bug at the cost of
running one DOM update per `captionsUpdatePeriod` (default 0.25s) while
the player is off-screen.

Externs updated at `externs/shaka/player.js`. When the flag is `false`,
`applyVisibility_` short-circuits to "always visible" so the IO observer
can never suspend rendering.

---------

Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
2026-05-06 08:51:25 +02:00
absidue f7309534fb perf: Remove unnecessary Uint8ArrayUtils.concat calls in Mp4Generator (#10047)
`Mp4Generator.box()` merges all arguments into one `Uint8Array`, so
arrays of `Uint8Arrays` can be spread directly into the
`Mp4Generator.box()` calls instead of doing the extra step of merging
them into a single `Uint8Array` first. I also included a drive-by change
to simplify `array.push(...[x, y])` into `array.push(x, y)` in the
`segmentData` method.
2026-05-01 14:49:34 -07:00
Álvaro Velad Galván 4c544efc84 chore: Simplify shaka.util.Mp4Generator.StreamInfo info (#10029) 2026-04-24 10:23:09 +02:00
Álvaro Velad Galván fa2c4dface chore: Remove videoNalus of shaka.util.Mp4Generator.StreamInfo (#10028)
This was used only for MSS, but we have now removed support for it.
2026-04-23 16:47:00 +02:00
Álvaro Velad Galván 13d6efd55d chore: Remove appspot references from source (#10015)
Issue https://github.com/shaka-project/shaka-player/issues/9984
2026-04-22 10:14:02 +02:00
Matthias Van Parijs 09b6c94ad8 fix: Bail out on initial text preference when a user selected one manually. (#10010)
```js
player.addTextTrackAsync("...", "en", "subtitles");
const textTracks = player.getTextTracks();
// Text tracks has a length of 1, but immediately selecting it would fail.
player.selectTextTrack(textTracks[0]);
```

Text track preference runs after we manually selected a text track, in
`src=` we'd wait for `loadeddata` before figuring out which initial text
track should be selected. The fix is to bail out when we already have a
text track active when trying to select an initial text track.
2026-04-20 23:32:00 +02:00
Álvaro Velad Galván ef83be209f feat(MSF): Add catalogPreprocessor config (#9990) 2026-04-17 10:29:10 +02:00
dong-heun 0f322b08bb fix: include unencrypted decodingConfigs in preferredKeySystems loop (#9975)
HLS SUPPLEMENTAL-CODECS (e.g. Dolby Vision dvh1) creates duplicate
variant tags with different codecs but the same media playlist URI. Due
to lazy-loading, only one variant gets its drmInfos populated via
createSegmentIndex(). The other variant remains with empty drmInfos and
is treated as unencrypted by getDecodingConfigs_().

In the preferredKeySystems loop, the filter rejected these unencrypted
configs (undefined !== preferredKeySystem), leaving the variant with no
decodingInfo and causing it to be dropped.

Fix: allow unencrypted configs (!keySystem) to pass through, matching
the pattern already used in the second (fallback) loop.

Propagating drmInfos in HLS parser would be more correct but is complex
because stream duplication happens at the tag level with separate cache
keys (URI + codecs) in createStreamInfoFromVariantTags_.
2026-04-15 12:39:19 +02:00
Álvaro Velad Galván 90a737961f feat(MSF): Add MoQT draft-16 support (#9966)
A new config is added to config the version: 'auto', 'draft-14',
'draft-16'

---------

Co-authored-by: Wojciech Tyczyński <tykus160@gmail.com>
2026-04-15 12:34:33 +02:00
Álvaro Velad Galván aa2dfaec3f feat(MSF): Add CMSF contentProtection signaling support (#9972)
See https://github.com/moq-wg/cmsf/pull/18
2026-04-14 17:43:45 +02:00
Edward-x f48bd96197 fix: Limit recursion depth in TXml to prevent stack overflow DoS (#9964) 2026-04-14 15:26:15 +02:00
Álvaro Velad Galván d435f9bf15 feat(MSF): Add FETCH support for catalog (#9965) 2026-04-13 13:07:08 +02:00
Álvaro Velad Galván 406729873b chore: Add shaka.util.VideoFrameCallbackHandler helper (#9950)
It encapsulates and simplifies the use of requestVideoFrameCallback and
cancelVideoFrameCallback

---------

Co-authored-by: Wojciech Tyczyński <tykus160@gmail.com>
2026-04-09 14:28:40 +02:00
Andy(김규회) c3d82bea1d feat(ABR): Monitor dropped frames to influence decisions (#9918)
Close https://github.com/shaka-project/shaka-player/issues/745

The ratio is checked periodically, and when the threshold is exceeded,
the current stream is 'disableStream' if possible, and a new decission
is taken

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
Co-authored-by: Matthias Van Parijs <matvp91@gmail.com>
2026-04-09 11:37:13 +02:00
Álvaro Velad Galván ccb4b1472e feat(net): Add commonAccessTokenHeaderName config (#9949)
Both CTA-5007-A and CTA-5007-B now specifies that the default header
name should be "cta-common-access-token", but it also provides a path
for using a custom header name.

Close https://github.com/shaka-project/shaka-player/issues/9948
2026-04-09 11:24:21 +02:00
Wojciech Tyczyński e2cf6a1724 chore: Replace PublicPromise with Promise.withResolvers (#9925)
Stop using `shaka.util.PublicPromise` and replace it with modern
`Promise.withResolvers()` API, that is [widely implemented
already](https://caniuse.com/wf-promise-withresolvers).

Polyfill is already included by Closure Compiler:
https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/js/es6/promise/withResolvers.js

---------

Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
2026-04-07 16:11:29 +02:00
Álvaro Velad Galván 4706d5f286 feat: Add subtitleDelay config for manual subtitle timing offset (#9939) 2026-04-07 12:15:21 +02:00
Álvaro Velad Galván 0522d0b1dc feat(MSF): Make subscribe filter type configurable (#9941) 2026-04-07 10:47:23 +02:00
Álvaro Velad Galván 83cc35161e feat(MSF): Add authorizationToken support (#9916) 2026-04-07 09:54:45 +02:00
Wojciech Tyczyński 2d2228bbd8 chore: Remove DelayedTick (#9927)
DelayedTick in reality was used directly only in StreamingEngine for no
particular reason. Move this functionality directly to Timer class.
2026-04-02 18:45:26 +02:00
Wojciech Tyczyński 6509d9b7ac chore: Remove rarely used Functional methods (#9928) 2026-04-02 18:43:37 +02:00
Sakura501 586ce0636e chore(Demo): demo assetBase64 prototype pollution to DOM XSS (#9906)
## Summary

This PR fixes a demo asset parsing and configuration merge vulnerability
where a
malicious `assetBase64` payload could abuse `__proto__`, `constructor`,
or
`prototype` keys to pollute object prototypes and later reach DOM XSS
gadgets in
Shaka Player Demo.

## Vulnerability details

The vulnerable path was:

1. `demo/main.js` reads attacker-controlled `assetBase64` from the URL
hash.
2. `demo/common/asset.js` copies `extraConfig` into a player config
object with
   `for..in`, which allows dangerous magic keys to be applied.
3. `lib/util/config_utils.js` merges config objects with another
`for..in`
   traversal and no explicit rejection of `__proto__`, `constructor`, or
   `prototype`.
4. The resulting prototype pollution can be turned into DOM XSS when
later demo
   UI rebuild paths consume inherited properties.

## Fix approach

This change hardens both the demo entry point and the shared merge
utility:

- `demo/common/asset.js`
  - filter dangerous keys when copying `extraConfig`
  - restrict `toJSON()` and `fromJSON()` to own properties only
- prevent dangerous keys from being serialized into or restored from
saved demo
    assets
- `lib/util/config_utils.js`
  - switch config merging from `for..in` to `Object.keys()`
  - explicitly reject `__proto__`, `constructor`, and `prototype`

## Regression coverage

Added tests that verify:

- dangerous `extraConfig` keys do not alter the generated player config
- inherited demo asset properties are not serialized into JSON
- dangerous keys are ignored when parsing saved assets back into demo
objects
- inherited magic keys are not traversed during config merges

## Verification

- `python3 build/test.py --quick --filter 'Demo|ConfigUtils' --browsers
ChromeHeadless`
- `python3 build/check.py`
2026-03-30 10:40:10 +02:00
Ivan 2c8cfd20f3 perf(TS): Eliminate per-PES wrapper array allocations in parse loop (#9883)
This PR reduces GC pressure during MPEG-TS segment parsing - it replaces
nested PES packet arrays with a flat array plus a PES-start index,
eliminating per-PES inner array allocations and avoiding spread-operator
overhead when concatenating packets - reduces allocations, hence reduces
GC pressure on low-end devices during long livestreams
2026-03-26 10:03:32 +01:00
Álvaro Velad Galván 76d655bed6 perf(MSF): Improve compatibility with the draft-14 (#9895)
More types of messages are now supported than before. 
SubscribeError handling has been improved.
A new error has been added when no catalog.
Existing messages have been reviewed to eliminate inconsistencies in the
migration from draft-11 to draft-14 support.
Fix log levels
2026-03-26 09:46:40 +01:00
Ivan c86ce869c3 perf(media): replace filter calls in SegmentIndex with binary search (#9880)
This PR replaces `Array.filter` calls in
`SegmentIndex.merge()`,`mergeAndEvict()`, and `evict()` with more
efficient alternatives. The key addition is `binarySearch` helper: it
repeatedly checks the midpoint and discards half the array each time.
The idea is the same as `Array.findIndex` but exploiting the sorted
order to skip most of the work. `merge()` and `evict()` use this to find
their truncation/expiry boundary; `mergeAndEvict()` uses a simple
forward scan that stops at the first valid reference since stale refs
are always bunched at the front. This is done to reduce iteration during
playback (especially livestream with DVR)

- no big new array creations by default - we don't create one when for
example there is nothing to evict
- fewer comparisons — binary search finds the cutoff without scanning
the whole array
- slice just copies the kept elements and that's it
2026-03-25 10:00:52 +01:00
gmamzn dd5b2dab21 fix(HLS): Add support for DTS and DTS-HD audio codec variants (#9863)
Add DTS (dts), DTS-HD (dtsh), DTS Digital Surround (dtsc), DTS Express
(dtse), and DTS:X (dtsx) to AUDIO_CODEC_REGEXPS using a single merged
regex /^dts[cehx]?$/.

Include regression tests for all new codec variants.
2026-03-20 16:01:02 +01:00
Ivan c9f8057f9a perf(DASH): loop over adaptation sets using the partition method (#9862) 2026-03-20 15:45:57 +01:00
gmamzn d15a0702ac fix(util): Add support for MPEG-2 video codec (#9860)
Add /^mp2v/ regex to VIDEO_CODEC_REGEXPS so that guessCodecsSafe
correctly recognizes MPEG-2 video codec strings. Without this, manifests
containing mp2v codec identifiers would fail codec detection, preventing
playback of MPEG-2 video content.

Includes regression tests verifying mp2v is recognized as a video codec
and not misidentified as audio.
2026-03-20 14:09:43 +01:00
Álvaro Velad Galván b9abb399bb fix(LCEVC): Fix multi-period VOD support (#9837)
A new integration test has been added.
The use of `stream` within `stream` in `periods.js` has been refactored
to simplify management and avoid duplicates.

---------

Co-authored-by: Wojciech Tyczyński <tykus160@gmail.com>
2026-03-19 10:07:14 +01:00
Álvaro Velad Galván 0c0a47c8d6 fix(MSF): Use bigint natively (#9826)
Many relays use large numbers and with the current implementation it
doesn't always work.

See Closure's limitations here:
https://github.com/google/closure-compiler/wiki/BigInt-support
2026-03-14 10:51:09 +01:00
Álvaro Velad Galván c92c3bddba feat(DASH): Add json format support (#9788)
This initial support is complete but not efficient, as it involves
conversion to XML and normal processing. It should only be used for
testing purposes. Improved support will be added in the future.

Tested with https://github.com/Dash-Industry-Forum/dash-json-schema

Note: This is only added to the experimental build.
2026-03-09 09:52:06 +01:00
vlazh 2e732b5392 feat: Add clampAppendWindowToDuration option (#9699)
Fixes #9674
2026-03-06 11:04:00 +01:00
Álvaro Velad Galván ac010c4159 perf: Improve performance of TsParser (#9783) 2026-03-04 12:47:11 +01:00
Álvaro Velad Galván cca8f504c2 fix: prevent negative times in Stats (#9784) 2026-03-04 10:51:45 +01:00
Álvaro Velad Galván 9575e2ae63 perf: Eliminate DataViewReader allocation and use native clz32 in ExpGolomb (#9779) 2026-03-03 11:06:32 +01:00
gmamzn 5b81f70eb0 fix(tXml): Return default value for a missing attribute (#9734)
If the attribute does NOT exist, getAttribute(name) on an element return
an empty string. Empty string '' is not equivalent to 'null'. As a
result 'defaultValue' is not returned, which leads to playback related
issues.
2026-03-02 10:54:20 -08:00
Álvaro Velad Galván e3781c493b feat(DASH): Enable automatic XLink processing with fast detection and performance improvements (#9764)
This PR modernizes and optimizes XLink handling in the DASH parser by
removing the legacy flag-based behavior and replacing it with a
standards‑aligned, fast, and deterministic workflow. The changes improve
performance on large MPDs, simplify configuration, and ensure correct
XLink expansion according to DASH/XLink rules.

XLink processing is now automatically enabled only when needed. If the
MPD contains no XLinks, the parser skips processXlinks entirely.
2026-02-26 14:05:32 +01:00