@videojs/spf 10.0.0-beta.30 → 10.0.0-beta.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (520) hide show
  1. package/dist/default/core/actors/create-machine-actor.js +23 -25
  2. package/dist/default/core/actors/create-machine-actor.js.map +1 -1
  3. package/dist/default/core/actors/create-transition-actor.js +7 -9
  4. package/dist/default/core/actors/create-transition-actor.js.map +1 -1
  5. package/dist/default/core/composition/create-composition.js +26 -29
  6. package/dist/default/core/composition/create-composition.js.map +1 -1
  7. package/dist/default/core/composition/share-signals.js +12 -17
  8. package/dist/default/core/composition/share-signals.js.map +1 -1
  9. package/dist/default/core/machine.js +3 -4
  10. package/dist/default/core/machine.js.map +1 -1
  11. package/dist/default/core/reactors/create-machine-reactor.js +20 -19
  12. package/dist/default/core/reactors/create-machine-reactor.js.map +1 -1
  13. package/dist/default/core/signals/effect.js +24 -4
  14. package/dist/default/core/signals/effect.js.map +1 -1
  15. package/dist/default/core/signals/primitives.js +10 -14
  16. package/dist/default/core/signals/primitives.js.map +1 -1
  17. package/dist/default/core/signals/when.js +6 -8
  18. package/dist/default/core/signals/when.js.map +1 -1
  19. package/dist/default/core/tasks/delayed-reschedule.js +7 -11
  20. package/dist/default/core/tasks/delayed-reschedule.js.map +1 -1
  21. package/dist/default/core/tasks/task.js +59 -82
  22. package/dist/default/core/tasks/task.js.map +1 -1
  23. package/dist/default/hls.js +3 -1
  24. package/dist/default/index.js +2 -3
  25. package/dist/default/index.js.map +1 -1
  26. package/dist/default/media/abr/quality-selection.js +3 -7
  27. package/dist/default/media/abr/quality-selection.js.map +1 -1
  28. package/dist/default/media/buffer/back-buffer.js +15 -19
  29. package/dist/default/media/buffer/back-buffer.js.map +1 -1
  30. package/dist/default/media/buffer/forward-buffer.js +32 -41
  31. package/dist/default/media/buffer/forward-buffer.js.map +1 -1
  32. package/dist/default/media/dom/capabilities.js +26 -37
  33. package/dist/default/media/dom/capabilities.js.map +1 -1
  34. package/dist/default/media/dom/mse/append-segment.js +3 -5
  35. package/dist/default/media/dom/mse/append-segment.js.map +1 -1
  36. package/dist/default/media/dom/mse/buffer-flusher.js +5 -5
  37. package/dist/default/media/dom/mse/buffer-flusher.js.map +1 -1
  38. package/dist/default/media/dom/mse/duration.js +23 -31
  39. package/dist/default/media/dom/mse/duration.js.map +1 -1
  40. package/dist/default/media/dom/mse/end-of-stream.js +3 -6
  41. package/dist/default/media/dom/mse/end-of-stream.js.map +1 -1
  42. package/dist/default/media/dom/mse/mediasource-setup.js +65 -81
  43. package/dist/default/media/dom/mse/mediasource-setup.js.map +1 -1
  44. package/dist/default/media/dom/screen.js +37 -54
  45. package/dist/default/media/dom/screen.js.map +1 -1
  46. package/dist/default/media/dom/text/resolve-vtt-segment.js.map +1 -1
  47. package/dist/default/media/dom/text/text-track-slots.js +15 -23
  48. package/dist/default/media/dom/text/text-track-slots.js.map +1 -1
  49. package/dist/default/media/errors.js +25 -34
  50. package/dist/default/media/errors.js.map +1 -1
  51. package/dist/default/media/hls/parse-attributes.js +9 -26
  52. package/dist/default/media/hls/parse-attributes.js.map +1 -1
  53. package/dist/default/media/hls/parse-media-playlist.js +25 -33
  54. package/dist/default/media/hls/parse-media-playlist.js.map +1 -1
  55. package/dist/default/media/hls/parse-multivariant.js +3 -3
  56. package/dist/default/media/hls/parse-multivariant.js.map +1 -1
  57. package/dist/default/media/hls/reload-policy.js +19 -27
  58. package/dist/default/media/hls/reload-policy.js.map +1 -1
  59. package/dist/default/media/hls/resolve-url.js +1 -3
  60. package/dist/default/media/hls/resolve-url.js.map +1 -1
  61. package/dist/default/media/live-window.js +9 -13
  62. package/dist/default/media/live-window.js.map +1 -1
  63. package/dist/default/media/media-tracks/media-tracks.js +12 -17
  64. package/dist/default/media/media-tracks/media-tracks.js.map +1 -1
  65. package/dist/default/media/mp4/box.js +4 -5
  66. package/dist/default/media/mp4/box.js.map +1 -1
  67. package/dist/default/media/mp4/timestamp-origin.js +30 -42
  68. package/dist/default/media/mp4/timestamp-origin.js.map +1 -1
  69. package/dist/default/media/primitives/resolution.js +5 -8
  70. package/dist/default/media/primitives/resolution.js.map +1 -1
  71. package/dist/default/media/primitives/select-tracks.js +24 -34
  72. package/dist/default/media/primitives/select-tracks.js.map +1 -1
  73. package/dist/default/media/text/parse-vtt-timestamp-map.js +6 -8
  74. package/dist/default/media/text/parse-vtt-timestamp-map.js.map +1 -1
  75. package/dist/default/media/text/resolve-vtt-metadata.js +8 -9
  76. package/dist/default/media/text/resolve-vtt-metadata.js.map +1 -1
  77. package/dist/default/media/types/index.js +10 -18
  78. package/dist/default/media/types/index.js.map +1 -1
  79. package/dist/default/media/utils/cdn.js +10 -16
  80. package/dist/default/media/utils/cdn.js.map +1 -1
  81. package/dist/default/media/utils/preload.js +4 -6
  82. package/dist/default/media/utils/preload.js.map +1 -1
  83. package/dist/default/media/utils/track-selection.js +10 -14
  84. package/dist/default/media/utils/track-selection.js.map +1 -1
  85. package/dist/default/media/utils/tracks.js +56 -54
  86. package/dist/default/media/utils/tracks.js.map +1 -1
  87. package/dist/default/network/bandwidth-estimator.js +18 -19
  88. package/dist/default/network/bandwidth-estimator.js.map +1 -1
  89. package/dist/default/network/chunked-stream-iterable.js +4 -6
  90. package/dist/default/network/chunked-stream-iterable.js.map +1 -1
  91. package/dist/default/network/ewma.js +22 -25
  92. package/dist/default/network/ewma.js.map +1 -1
  93. package/dist/default/network/fetch.js +30 -37
  94. package/dist/default/network/fetch.js.map +1 -1
  95. package/dist/default/playback/actors/dom/segment-loader.js +28 -44
  96. package/dist/default/playback/actors/dom/segment-loader.js.map +1 -1
  97. package/dist/default/playback/actors/dom/source-buffer.js.map +1 -1
  98. package/dist/default/playback/actors/dom/text-tracks.js.map +1 -1
  99. package/dist/default/playback/actors/text-track-segment-loader.js +24 -35
  100. package/dist/default/playback/actors/text-track-segment-loader.js.map +1 -1
  101. package/dist/default/playback/adapters/hls-audio/adapter.js +23 -31
  102. package/dist/default/playback/adapters/hls-audio/adapter.js.map +1 -1
  103. package/dist/default/playback/adapters/hls-audio/media.js.map +1 -1
  104. package/dist/default/playback/adapters/hls-background-video/adapter.js +50 -70
  105. package/dist/default/playback/adapters/hls-background-video/adapter.js.map +1 -1
  106. package/dist/default/playback/adapters/hls-background-video/host.js +12 -16
  107. package/dist/default/playback/adapters/hls-background-video/host.js.map +1 -1
  108. package/dist/default/playback/adapters/hls-background-video/media.js +5 -8
  109. package/dist/default/playback/adapters/hls-background-video/media.js.map +1 -1
  110. package/dist/default/playback/adapters/hls-video/adapter.js +43 -60
  111. package/dist/default/playback/adapters/hls-video/adapter.js.map +1 -1
  112. package/dist/default/playback/adapters/hls-video/error-surface.js +13 -18
  113. package/dist/default/playback/adapters/hls-video/error-surface.js.map +1 -1
  114. package/dist/default/playback/adapters/hls-video/media-tracks.js +4 -5
  115. package/dist/default/playback/adapters/hls-video/media-tracks.js.map +1 -1
  116. package/dist/default/playback/adapters/hls-video/media.js.map +1 -1
  117. package/dist/default/playback/adapters/mux-audio/media.js +8 -12
  118. package/dist/default/playback/adapters/mux-audio/media.js.map +1 -1
  119. package/dist/default/playback/adapters/mux-video/adapter.js +25 -33
  120. package/dist/default/playback/adapters/mux-video/adapter.js.map +1 -1
  121. package/dist/default/playback/adapters/mux-video/media.js +7 -9
  122. package/dist/default/playback/adapters/mux-video/media.js.map +1 -1
  123. package/dist/default/playback/behaviors/calculate-presentation-duration.js +5 -8
  124. package/dist/default/playback/behaviors/calculate-presentation-duration.js.map +1 -1
  125. package/dist/default/playback/behaviors/collect-errors.js +39 -52
  126. package/dist/default/playback/behaviors/collect-errors.js.map +1 -1
  127. package/dist/default/playback/behaviors/derive-cdn-priority.js +16 -23
  128. package/dist/default/playback/behaviors/derive-cdn-priority.js.map +1 -1
  129. package/dist/default/playback/behaviors/dom/airplay.js +38 -61
  130. package/dist/default/playback/behaviors/dom/airplay.js.map +1 -1
  131. package/dist/default/playback/behaviors/dom/apply-start-position.js +23 -35
  132. package/dist/default/playback/behaviors/dom/apply-start-position.js.map +1 -1
  133. package/dist/default/playback/behaviors/dom/end-of-stream.js +11 -16
  134. package/dist/default/playback/behaviors/dom/end-of-stream.js.map +1 -1
  135. package/dist/default/playback/behaviors/dom/load-segments.js +27 -39
  136. package/dist/default/playback/behaviors/dom/load-segments.js.map +1 -1
  137. package/dist/default/playback/behaviors/dom/recover-end-stall.js +21 -26
  138. package/dist/default/playback/behaviors/dom/recover-end-stall.js.map +1 -1
  139. package/dist/default/playback/behaviors/dom/seek-to-live-edge.js +41 -60
  140. package/dist/default/playback/behaviors/dom/seek-to-live-edge.js.map +1 -1
  141. package/dist/default/playback/behaviors/dom/setup-buffer-actors.js +50 -74
  142. package/dist/default/playback/behaviors/dom/setup-buffer-actors.js.map +1 -1
  143. package/dist/default/playback/behaviors/dom/setup-mediasource.js +29 -43
  144. package/dist/default/playback/behaviors/dom/setup-mediasource.js.map +1 -1
  145. package/dist/default/playback/behaviors/dom/setup-text-track-actors.js.map +1 -1
  146. package/dist/default/playback/behaviors/dom/sync-live-seekable-range.js +3 -4
  147. package/dist/default/playback/behaviors/dom/sync-live-seekable-range.js.map +1 -1
  148. package/dist/default/playback/behaviors/dom/sync-text-tracks.js +30 -45
  149. package/dist/default/playback/behaviors/dom/sync-text-tracks.js.map +1 -1
  150. package/dist/default/playback/behaviors/dom/track-current-time.js +9 -11
  151. package/dist/default/playback/behaviors/dom/track-current-time.js.map +1 -1
  152. package/dist/default/playback/behaviors/dom/track-load-triggers.js +24 -32
  153. package/dist/default/playback/behaviors/dom/track-load-triggers.js.map +1 -1
  154. package/dist/default/playback/behaviors/dom/track-playback-rate.js +6 -8
  155. package/dist/default/playback/behaviors/dom/track-playback-rate.js.map +1 -1
  156. package/dist/default/playback/behaviors/dom/track-player-resolution.js +10 -14
  157. package/dist/default/playback/behaviors/dom/track-player-resolution.js.map +1 -1
  158. package/dist/default/playback/behaviors/dom/track-screen-resolution.js +8 -9
  159. package/dist/default/playback/behaviors/dom/track-screen-resolution.js.map +1 -1
  160. package/dist/default/playback/behaviors/dom/update-mediasource-duration.js +28 -43
  161. package/dist/default/playback/behaviors/dom/update-mediasource-duration.js.map +1 -1
  162. package/dist/default/playback/behaviors/establish-start-media-time.js +32 -42
  163. package/dist/default/playback/behaviors/establish-start-media-time.js.map +1 -1
  164. package/dist/default/playback/behaviors/resolve-presentation.js +13 -22
  165. package/dist/default/playback/behaviors/resolve-presentation.js.map +1 -1
  166. package/dist/default/playback/behaviors/resolve-track.js +5 -12
  167. package/dist/default/playback/behaviors/resolve-track.js.map +1 -1
  168. package/dist/default/playback/behaviors/select-tracks.js +77 -104
  169. package/dist/default/playback/behaviors/select-tracks.js.map +1 -1
  170. package/dist/default/playback/behaviors/setup-failover-monitor.js +11 -16
  171. package/dist/default/playback/behaviors/setup-failover-monitor.js.map +1 -1
  172. package/dist/default/playback/behaviors/sync-preload.js +9 -13
  173. package/dist/default/playback/behaviors/sync-preload.js.map +1 -1
  174. package/dist/default/playback/behaviors/track-switching.js +189 -173
  175. package/dist/default/playback/behaviors/track-switching.js.map +1 -1
  176. package/dist/default/playback/engines/hls/engine-audio-only.js +20 -24
  177. package/dist/default/playback/engines/hls/engine-audio-only.js.map +1 -1
  178. package/dist/default/playback/engines/hls/engine-background-video.js +22 -27
  179. package/dist/default/playback/engines/hls/engine-background-video.js.map +1 -1
  180. package/dist/default/playback/engines/hls/engine.js +22 -25
  181. package/dist/default/playback/engines/hls/engine.js.map +1 -1
  182. package/dist/default/playback/primitives/error-messages.js +16 -25
  183. package/dist/default/playback/primitives/error-messages.js.map +1 -1
  184. package/dist/default/playback/primitives/failover-fetch.js +9 -14
  185. package/dist/default/playback/primitives/failover-fetch.js.map +1 -1
  186. package/dist/default/playback/primitives/head-peek.js +7 -10
  187. package/dist/default/playback/primitives/head-peek.js.map +1 -1
  188. package/dist/default/playback/primitives/live-window.js +12 -15
  189. package/dist/default/playback/primitives/live-window.js.map +1 -1
  190. package/dist/default/playback/primitives/relocation-pipelines.js +34 -46
  191. package/dist/default/playback/primitives/relocation-pipelines.js.map +1 -1
  192. package/dist/default/playback/primitives/report-track-conditions.js +26 -38
  193. package/dist/default/playback/primitives/report-track-conditions.js.map +1 -1
  194. package/dist/default/playback/primitives/segment-load-pipeline.js +15 -15
  195. package/dist/default/playback/primitives/segment-load-pipeline.js.map +1 -1
  196. package/dist/default/playback/primitives/selection-rules.js +65 -36
  197. package/dist/default/playback/primitives/selection-rules.js.map +1 -1
  198. package/dist/default/playback/primitives/text-segment-load-pipeline.js +4 -5
  199. package/dist/default/playback/primitives/text-segment-load-pipeline.js.map +1 -1
  200. package/dist/default/playback/primitives/track-types.js +10 -18
  201. package/dist/default/playback/primitives/track-types.js.map +1 -1
  202. package/dist/dev/core/actors/actor.d.ts +4 -4
  203. package/dist/dev/core/actors/actor.d.ts.map +1 -1
  204. package/dist/dev/core/actors/create-machine-actor.d.ts +38 -47
  205. package/dist/dev/core/actors/create-machine-actor.d.ts.map +1 -1
  206. package/dist/dev/core/actors/create-machine-actor.js +23 -25
  207. package/dist/dev/core/actors/create-machine-actor.js.map +1 -1
  208. package/dist/dev/core/actors/create-transition-actor.d.ts +11 -15
  209. package/dist/dev/core/actors/create-transition-actor.d.ts.map +1 -1
  210. package/dist/dev/core/actors/create-transition-actor.js +7 -9
  211. package/dist/dev/core/actors/create-transition-actor.js.map +1 -1
  212. package/dist/dev/core/composition/create-composition.d.ts +70 -102
  213. package/dist/dev/core/composition/create-composition.d.ts.map +1 -1
  214. package/dist/dev/core/composition/create-composition.js +26 -29
  215. package/dist/dev/core/composition/create-composition.js.map +1 -1
  216. package/dist/dev/core/composition/share-signals.d.ts +17 -24
  217. package/dist/dev/core/composition/share-signals.d.ts.map +1 -1
  218. package/dist/dev/core/composition/share-signals.js +12 -17
  219. package/dist/dev/core/composition/share-signals.js.map +1 -1
  220. package/dist/dev/core/machine.d.ts +4 -4
  221. package/dist/dev/core/machine.js +3 -4
  222. package/dist/dev/core/machine.js.map +1 -1
  223. package/dist/dev/core/reactors/create-machine-reactor.d.ts +33 -39
  224. package/dist/dev/core/reactors/create-machine-reactor.d.ts.map +1 -1
  225. package/dist/dev/core/reactors/create-machine-reactor.js +20 -19
  226. package/dist/dev/core/reactors/create-machine-reactor.js.map +1 -1
  227. package/dist/dev/core/signals/effect.d.ts +3 -4
  228. package/dist/dev/core/signals/effect.d.ts.map +1 -1
  229. package/dist/dev/core/signals/effect.js +24 -4
  230. package/dist/dev/core/signals/effect.js.map +1 -1
  231. package/dist/dev/core/signals/primitives.d.ts +10 -12
  232. package/dist/dev/core/signals/primitives.d.ts.map +1 -1
  233. package/dist/dev/core/signals/primitives.js +10 -14
  234. package/dist/dev/core/signals/primitives.js.map +1 -1
  235. package/dist/dev/core/signals/when.js +6 -8
  236. package/dist/dev/core/signals/when.js.map +1 -1
  237. package/dist/dev/core/tasks/delayed-reschedule.js +7 -11
  238. package/dist/dev/core/tasks/delayed-reschedule.js.map +1 -1
  239. package/dist/dev/core/tasks/task.d.ts +51 -73
  240. package/dist/dev/core/tasks/task.d.ts.map +1 -1
  241. package/dist/dev/core/tasks/task.js +59 -82
  242. package/dist/dev/core/tasks/task.js.map +1 -1
  243. package/dist/dev/hls.d.ts +3 -1
  244. package/dist/dev/hls.js +3 -1
  245. package/dist/dev/index.d.ts +2 -3
  246. package/dist/dev/index.d.ts.map +1 -1
  247. package/dist/dev/index.js +2 -3
  248. package/dist/dev/index.js.map +1 -1
  249. package/dist/dev/media/abr/quality-selection.d.ts +7 -10
  250. package/dist/dev/media/abr/quality-selection.d.ts.map +1 -1
  251. package/dist/dev/media/abr/quality-selection.js +3 -7
  252. package/dist/dev/media/abr/quality-selection.js.map +1 -1
  253. package/dist/dev/media/buffer/back-buffer.d.ts +2 -7
  254. package/dist/dev/media/buffer/back-buffer.d.ts.map +1 -1
  255. package/dist/dev/media/buffer/back-buffer.js +15 -19
  256. package/dist/dev/media/buffer/back-buffer.js.map +1 -1
  257. package/dist/dev/media/buffer/forward-buffer.d.ts +2 -7
  258. package/dist/dev/media/buffer/forward-buffer.d.ts.map +1 -1
  259. package/dist/dev/media/buffer/forward-buffer.js +32 -41
  260. package/dist/dev/media/buffer/forward-buffer.js.map +1 -1
  261. package/dist/dev/media/dom/capabilities.js +26 -37
  262. package/dist/dev/media/dom/capabilities.js.map +1 -1
  263. package/dist/dev/media/dom/mse/append-segment.d.ts +3 -5
  264. package/dist/dev/media/dom/mse/append-segment.d.ts.map +1 -1
  265. package/dist/dev/media/dom/mse/append-segment.js +3 -5
  266. package/dist/dev/media/dom/mse/append-segment.js.map +1 -1
  267. package/dist/dev/media/dom/mse/buffer-flusher.d.ts +5 -5
  268. package/dist/dev/media/dom/mse/buffer-flusher.js +5 -5
  269. package/dist/dev/media/dom/mse/buffer-flusher.js.map +1 -1
  270. package/dist/dev/media/dom/mse/duration.js +23 -31
  271. package/dist/dev/media/dom/mse/duration.js.map +1 -1
  272. package/dist/dev/media/dom/mse/end-of-stream.js +3 -6
  273. package/dist/dev/media/dom/mse/end-of-stream.js.map +1 -1
  274. package/dist/dev/media/dom/mse/mediasource-setup.js +65 -81
  275. package/dist/dev/media/dom/mse/mediasource-setup.js.map +1 -1
  276. package/dist/dev/media/dom/screen.d.ts.map +1 -1
  277. package/dist/dev/media/dom/screen.js +37 -54
  278. package/dist/dev/media/dom/screen.js.map +1 -1
  279. package/dist/dev/media/dom/text/resolve-vtt-segment.d.ts.map +1 -1
  280. package/dist/dev/media/dom/text/resolve-vtt-segment.js.map +1 -1
  281. package/dist/dev/media/dom/text/text-track-slots.d.ts +10 -16
  282. package/dist/dev/media/dom/text/text-track-slots.d.ts.map +1 -1
  283. package/dist/dev/media/dom/text/text-track-slots.js +15 -23
  284. package/dist/dev/media/dom/text/text-track-slots.js.map +1 -1
  285. package/dist/dev/media/errors.d.ts +32 -46
  286. package/dist/dev/media/errors.d.ts.map +1 -1
  287. package/dist/dev/media/errors.js +25 -34
  288. package/dist/dev/media/errors.js.map +1 -1
  289. package/dist/dev/media/hls/parse-attributes.js +9 -26
  290. package/dist/dev/media/hls/parse-attributes.js.map +1 -1
  291. package/dist/dev/media/hls/parse-media-playlist.js +25 -33
  292. package/dist/dev/media/hls/parse-media-playlist.js.map +1 -1
  293. package/dist/dev/media/hls/parse-multivariant.js +3 -3
  294. package/dist/dev/media/hls/parse-multivariant.js.map +1 -1
  295. package/dist/dev/media/hls/reload-policy.js +19 -27
  296. package/dist/dev/media/hls/reload-policy.js.map +1 -1
  297. package/dist/dev/media/hls/resolve-url.js +1 -3
  298. package/dist/dev/media/hls/resolve-url.js.map +1 -1
  299. package/dist/dev/media/live-window.js +9 -13
  300. package/dist/dev/media/live-window.js.map +1 -1
  301. package/dist/dev/media/media-tracks/media-tracks.d.ts +8 -13
  302. package/dist/dev/media/media-tracks/media-tracks.d.ts.map +1 -1
  303. package/dist/dev/media/media-tracks/media-tracks.js +12 -17
  304. package/dist/dev/media/media-tracks/media-tracks.js.map +1 -1
  305. package/dist/dev/media/mp4/box.js +4 -5
  306. package/dist/dev/media/mp4/box.js.map +1 -1
  307. package/dist/dev/media/mp4/timestamp-origin.js +30 -42
  308. package/dist/dev/media/mp4/timestamp-origin.js.map +1 -1
  309. package/dist/dev/media/primitives/resolution.d.ts +6 -8
  310. package/dist/dev/media/primitives/resolution.d.ts.map +1 -1
  311. package/dist/dev/media/primitives/resolution.js +5 -8
  312. package/dist/dev/media/primitives/resolution.js.map +1 -1
  313. package/dist/dev/media/primitives/select-tracks.js +24 -34
  314. package/dist/dev/media/primitives/select-tracks.js.map +1 -1
  315. package/dist/dev/media/text/parse-vtt-timestamp-map.js +6 -8
  316. package/dist/dev/media/text/parse-vtt-timestamp-map.js.map +1 -1
  317. package/dist/dev/media/text/resolve-vtt-metadata.js +8 -9
  318. package/dist/dev/media/text/resolve-vtt-metadata.js.map +1 -1
  319. package/dist/dev/media/types/index.d.ts +106 -177
  320. package/dist/dev/media/types/index.d.ts.map +1 -1
  321. package/dist/dev/media/types/index.js +10 -18
  322. package/dist/dev/media/types/index.js.map +1 -1
  323. package/dist/dev/media/utils/cdn.d.ts +4 -6
  324. package/dist/dev/media/utils/cdn.d.ts.map +1 -1
  325. package/dist/dev/media/utils/cdn.js +10 -16
  326. package/dist/dev/media/utils/cdn.js.map +1 -1
  327. package/dist/dev/media/utils/preload.js +4 -6
  328. package/dist/dev/media/utils/preload.js.map +1 -1
  329. package/dist/dev/media/utils/track-selection.js +10 -14
  330. package/dist/dev/media/utils/track-selection.js.map +1 -1
  331. package/dist/dev/media/utils/tracks.js +56 -54
  332. package/dist/dev/media/utils/tracks.js.map +1 -1
  333. package/dist/dev/network/bandwidth-estimator.d.ts +7 -9
  334. package/dist/dev/network/bandwidth-estimator.d.ts.map +1 -1
  335. package/dist/dev/network/bandwidth-estimator.js +18 -19
  336. package/dist/dev/network/bandwidth-estimator.js.map +1 -1
  337. package/dist/dev/network/chunked-stream-iterable.js +4 -6
  338. package/dist/dev/network/chunked-stream-iterable.js.map +1 -1
  339. package/dist/dev/network/ewma.js +22 -25
  340. package/dist/dev/network/ewma.js.map +1 -1
  341. package/dist/dev/network/fetch.js +30 -37
  342. package/dist/dev/network/fetch.js.map +1 -1
  343. package/dist/dev/playback/actors/dom/segment-loader.d.ts +7 -11
  344. package/dist/dev/playback/actors/dom/segment-loader.d.ts.map +1 -1
  345. package/dist/dev/playback/actors/dom/segment-loader.js +28 -44
  346. package/dist/dev/playback/actors/dom/segment-loader.js.map +1 -1
  347. package/dist/dev/playback/actors/dom/source-buffer.d.ts +5 -7
  348. package/dist/dev/playback/actors/dom/source-buffer.d.ts.map +1 -1
  349. package/dist/dev/playback/actors/dom/source-buffer.js.map +1 -1
  350. package/dist/dev/playback/actors/dom/text-tracks.js.map +1 -1
  351. package/dist/dev/playback/actors/text-track-segment-loader.d.ts +10 -16
  352. package/dist/dev/playback/actors/text-track-segment-loader.d.ts.map +1 -1
  353. package/dist/dev/playback/actors/text-track-segment-loader.js +24 -35
  354. package/dist/dev/playback/actors/text-track-segment-loader.js.map +1 -1
  355. package/dist/dev/playback/actors/text-tracks.d.ts +5 -8
  356. package/dist/dev/playback/actors/text-tracks.d.ts.map +1 -1
  357. package/dist/dev/playback/adapters/hls-audio/adapter.d.ts +11 -14
  358. package/dist/dev/playback/adapters/hls-audio/adapter.d.ts.map +1 -1
  359. package/dist/dev/playback/adapters/hls-audio/adapter.js +23 -31
  360. package/dist/dev/playback/adapters/hls-audio/adapter.js.map +1 -1
  361. package/dist/dev/playback/adapters/hls-audio/media.d.ts.map +1 -1
  362. package/dist/dev/playback/adapters/hls-audio/media.js.map +1 -1
  363. package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts +28 -39
  364. package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts.map +1 -1
  365. package/dist/dev/playback/adapters/hls-background-video/adapter.js +50 -70
  366. package/dist/dev/playback/adapters/hls-background-video/adapter.js.map +1 -1
  367. package/dist/dev/playback/adapters/hls-background-video/host.d.ts +12 -16
  368. package/dist/dev/playback/adapters/hls-background-video/host.d.ts.map +1 -1
  369. package/dist/dev/playback/adapters/hls-background-video/host.js +12 -16
  370. package/dist/dev/playback/adapters/hls-background-video/host.js.map +1 -1
  371. package/dist/dev/playback/adapters/hls-background-video/media.d.ts +5 -8
  372. package/dist/dev/playback/adapters/hls-background-video/media.d.ts.map +1 -1
  373. package/dist/dev/playback/adapters/hls-background-video/media.js +5 -8
  374. package/dist/dev/playback/adapters/hls-background-video/media.js.map +1 -1
  375. package/dist/dev/playback/adapters/hls-video/adapter.d.ts +12 -14
  376. package/dist/dev/playback/adapters/hls-video/adapter.d.ts.map +1 -1
  377. package/dist/dev/playback/adapters/hls-video/adapter.js +43 -60
  378. package/dist/dev/playback/adapters/hls-video/adapter.js.map +1 -1
  379. package/dist/dev/playback/adapters/hls-video/error-surface.d.ts +4 -5
  380. package/dist/dev/playback/adapters/hls-video/error-surface.d.ts.map +1 -1
  381. package/dist/dev/playback/adapters/hls-video/error-surface.js +13 -18
  382. package/dist/dev/playback/adapters/hls-video/error-surface.js.map +1 -1
  383. package/dist/dev/playback/adapters/hls-video/media-tracks.d.ts +4 -5
  384. package/dist/dev/playback/adapters/hls-video/media-tracks.d.ts.map +1 -1
  385. package/dist/dev/playback/adapters/hls-video/media-tracks.js +4 -5
  386. package/dist/dev/playback/adapters/hls-video/media-tracks.js.map +1 -1
  387. package/dist/dev/playback/adapters/hls-video/media.d.ts.map +1 -1
  388. package/dist/dev/playback/adapters/hls-video/media.js.map +1 -1
  389. package/dist/dev/playback/adapters/mux-audio/media.d.ts +8 -12
  390. package/dist/dev/playback/adapters/mux-audio/media.d.ts.map +1 -1
  391. package/dist/dev/playback/adapters/mux-audio/media.js +8 -12
  392. package/dist/dev/playback/adapters/mux-audio/media.js.map +1 -1
  393. package/dist/dev/playback/adapters/mux-video/adapter.d.ts +9 -11
  394. package/dist/dev/playback/adapters/mux-video/adapter.d.ts.map +1 -1
  395. package/dist/dev/playback/adapters/mux-video/adapter.js +25 -33
  396. package/dist/dev/playback/adapters/mux-video/adapter.js.map +1 -1
  397. package/dist/dev/playback/adapters/mux-video/media.d.ts +7 -9
  398. package/dist/dev/playback/adapters/mux-video/media.d.ts.map +1 -1
  399. package/dist/dev/playback/adapters/mux-video/media.js +7 -9
  400. package/dist/dev/playback/adapters/mux-video/media.js.map +1 -1
  401. package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts +5 -8
  402. package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts.map +1 -1
  403. package/dist/dev/playback/behaviors/calculate-presentation-duration.js +5 -8
  404. package/dist/dev/playback/behaviors/calculate-presentation-duration.js.map +1 -1
  405. package/dist/dev/playback/behaviors/collect-errors.d.ts +2 -0
  406. package/dist/dev/playback/behaviors/collect-errors.js +39 -52
  407. package/dist/dev/playback/behaviors/collect-errors.js.map +1 -1
  408. package/dist/dev/playback/behaviors/derive-cdn-priority.js +16 -23
  409. package/dist/dev/playback/behaviors/derive-cdn-priority.js.map +1 -1
  410. package/dist/dev/playback/behaviors/dom/airplay.js +38 -61
  411. package/dist/dev/playback/behaviors/dom/airplay.js.map +1 -1
  412. package/dist/dev/playback/behaviors/dom/apply-start-position.js +23 -35
  413. package/dist/dev/playback/behaviors/dom/apply-start-position.js.map +1 -1
  414. package/dist/dev/playback/behaviors/dom/end-of-stream.js +11 -16
  415. package/dist/dev/playback/behaviors/dom/end-of-stream.js.map +1 -1
  416. package/dist/dev/playback/behaviors/dom/load-segments.d.ts +5 -8
  417. package/dist/dev/playback/behaviors/dom/load-segments.d.ts.map +1 -1
  418. package/dist/dev/playback/behaviors/dom/load-segments.js +27 -39
  419. package/dist/dev/playback/behaviors/dom/load-segments.js.map +1 -1
  420. package/dist/dev/playback/behaviors/dom/recover-end-stall.js +21 -26
  421. package/dist/dev/playback/behaviors/dom/recover-end-stall.js.map +1 -1
  422. package/dist/dev/playback/behaviors/dom/seek-to-live-edge.js +41 -60
  423. package/dist/dev/playback/behaviors/dom/seek-to-live-edge.js.map +1 -1
  424. package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js +50 -74
  425. package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js.map +1 -1
  426. package/dist/dev/playback/behaviors/dom/setup-mediasource.js +29 -43
  427. package/dist/dev/playback/behaviors/dom/setup-mediasource.js.map +1 -1
  428. package/dist/dev/playback/behaviors/dom/setup-text-track-actors.d.ts +3 -3
  429. package/dist/dev/playback/behaviors/dom/setup-text-track-actors.d.ts.map +1 -1
  430. package/dist/dev/playback/behaviors/dom/setup-text-track-actors.js.map +1 -1
  431. package/dist/dev/playback/behaviors/dom/sync-live-seekable-range.js +3 -4
  432. package/dist/dev/playback/behaviors/dom/sync-live-seekable-range.js.map +1 -1
  433. package/dist/dev/playback/behaviors/dom/sync-text-tracks.js +30 -45
  434. package/dist/dev/playback/behaviors/dom/sync-text-tracks.js.map +1 -1
  435. package/dist/dev/playback/behaviors/dom/track-current-time.d.ts +2 -2
  436. package/dist/dev/playback/behaviors/dom/track-current-time.d.ts.map +1 -1
  437. package/dist/dev/playback/behaviors/dom/track-current-time.js +9 -11
  438. package/dist/dev/playback/behaviors/dom/track-current-time.js.map +1 -1
  439. package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts +6 -12
  440. package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts.map +1 -1
  441. package/dist/dev/playback/behaviors/dom/track-load-triggers.js +24 -32
  442. package/dist/dev/playback/behaviors/dom/track-load-triggers.js.map +1 -1
  443. package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts +2 -2
  444. package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts.map +1 -1
  445. package/dist/dev/playback/behaviors/dom/track-playback-rate.js +6 -8
  446. package/dist/dev/playback/behaviors/dom/track-playback-rate.js.map +1 -1
  447. package/dist/dev/playback/behaviors/dom/track-player-resolution.d.ts.map +1 -1
  448. package/dist/dev/playback/behaviors/dom/track-player-resolution.js +10 -14
  449. package/dist/dev/playback/behaviors/dom/track-player-resolution.js.map +1 -1
  450. package/dist/dev/playback/behaviors/dom/track-screen-resolution.js +8 -9
  451. package/dist/dev/playback/behaviors/dom/track-screen-resolution.js.map +1 -1
  452. package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js +28 -43
  453. package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js.map +1 -1
  454. package/dist/dev/playback/behaviors/establish-start-media-time.d.ts +15 -19
  455. package/dist/dev/playback/behaviors/establish-start-media-time.d.ts.map +1 -1
  456. package/dist/dev/playback/behaviors/establish-start-media-time.js +32 -42
  457. package/dist/dev/playback/behaviors/establish-start-media-time.js.map +1 -1
  458. package/dist/dev/playback/behaviors/resolve-presentation.d.ts.map +1 -1
  459. package/dist/dev/playback/behaviors/resolve-presentation.js +13 -22
  460. package/dist/dev/playback/behaviors/resolve-presentation.js.map +1 -1
  461. package/dist/dev/playback/behaviors/resolve-track.js +5 -12
  462. package/dist/dev/playback/behaviors/resolve-track.js.map +1 -1
  463. package/dist/dev/playback/behaviors/select-tracks.d.ts +28 -39
  464. package/dist/dev/playback/behaviors/select-tracks.d.ts.map +1 -1
  465. package/dist/dev/playback/behaviors/select-tracks.js +77 -104
  466. package/dist/dev/playback/behaviors/select-tracks.js.map +1 -1
  467. package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts +1 -4
  468. package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts.map +1 -1
  469. package/dist/dev/playback/behaviors/setup-failover-monitor.js +11 -16
  470. package/dist/dev/playback/behaviors/setup-failover-monitor.js.map +1 -1
  471. package/dist/dev/playback/behaviors/sync-preload.js +9 -13
  472. package/dist/dev/playback/behaviors/sync-preload.js.map +1 -1
  473. package/dist/dev/playback/behaviors/track-switching.d.ts +110 -0
  474. package/dist/dev/playback/behaviors/track-switching.d.ts.map +1 -0
  475. package/dist/dev/playback/behaviors/track-switching.js +189 -173
  476. package/dist/dev/playback/behaviors/track-switching.js.map +1 -1
  477. package/dist/dev/playback/engines/hls/engine-audio-only.d.ts +59 -72
  478. package/dist/dev/playback/engines/hls/engine-audio-only.d.ts.map +1 -1
  479. package/dist/dev/playback/engines/hls/engine-audio-only.js +20 -24
  480. package/dist/dev/playback/engines/hls/engine-audio-only.js.map +1 -1
  481. package/dist/dev/playback/engines/hls/engine-background-video.d.ts +51 -78
  482. package/dist/dev/playback/engines/hls/engine-background-video.d.ts.map +1 -1
  483. package/dist/dev/playback/engines/hls/engine-background-video.js +22 -27
  484. package/dist/dev/playback/engines/hls/engine-background-video.js.map +1 -1
  485. package/dist/dev/playback/engines/hls/engine.d.ts +115 -155
  486. package/dist/dev/playback/engines/hls/engine.d.ts.map +1 -1
  487. package/dist/dev/playback/engines/hls/engine.js +22 -25
  488. package/dist/dev/playback/engines/hls/engine.js.map +1 -1
  489. package/dist/dev/playback/primitives/derive-start-media-time.d.ts +3 -3
  490. package/dist/dev/playback/primitives/derive-start-media-time.d.ts.map +1 -1
  491. package/dist/dev/playback/primitives/error-messages.js +16 -25
  492. package/dist/dev/playback/primitives/error-messages.js.map +1 -1
  493. package/dist/dev/playback/primitives/failover-fetch.js +9 -14
  494. package/dist/dev/playback/primitives/failover-fetch.js.map +1 -1
  495. package/dist/dev/playback/primitives/head-peek.js +7 -10
  496. package/dist/dev/playback/primitives/head-peek.js.map +1 -1
  497. package/dist/dev/playback/primitives/live-window.js +12 -15
  498. package/dist/dev/playback/primitives/live-window.js.map +1 -1
  499. package/dist/dev/playback/primitives/relocation-pipelines.js +34 -46
  500. package/dist/dev/playback/primitives/relocation-pipelines.js.map +1 -1
  501. package/dist/dev/playback/primitives/report-track-conditions.d.ts +1 -4
  502. package/dist/dev/playback/primitives/report-track-conditions.d.ts.map +1 -1
  503. package/dist/dev/playback/primitives/report-track-conditions.js +26 -38
  504. package/dist/dev/playback/primitives/report-track-conditions.js.map +1 -1
  505. package/dist/dev/playback/primitives/segment-load-pipeline.js +15 -15
  506. package/dist/dev/playback/primitives/segment-load-pipeline.js.map +1 -1
  507. package/dist/dev/playback/primitives/selection-rules.d.ts +45 -17
  508. package/dist/dev/playback/primitives/selection-rules.d.ts.map +1 -1
  509. package/dist/dev/playback/primitives/selection-rules.js +65 -36
  510. package/dist/dev/playback/primitives/selection-rules.js.map +1 -1
  511. package/dist/dev/playback/primitives/source-buffer-messages.d.ts +6 -9
  512. package/dist/dev/playback/primitives/source-buffer-messages.d.ts.map +1 -1
  513. package/dist/dev/playback/primitives/text-segment-load-pipeline.d.ts +20 -29
  514. package/dist/dev/playback/primitives/text-segment-load-pipeline.d.ts.map +1 -1
  515. package/dist/dev/playback/primitives/text-segment-load-pipeline.js +4 -5
  516. package/dist/dev/playback/primitives/text-segment-load-pipeline.js.map +1 -1
  517. package/dist/dev/playback/primitives/text-track-messages.d.ts.map +1 -1
  518. package/dist/dev/playback/primitives/track-types.js +10 -18
  519. package/dist/dev/playback/primitives/track-types.js.map +1 -1
  520. package/package.json +25 -28
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-url.js","names":[],"sources":["../../../../src/media/hls/resolve-url.ts"],"sourcesContent":["/**\n * Resolve a potentially relative URL against a base URL using native URL API.\n */\nexport function resolveUrl(url: string, baseUrl: string): string {\n return new URL(url, baseUrl).href;\n}\n"],"mappings":";;;;AAGA,SAAgB,WAAW,KAAa,SAAyB;CAC/D,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC;AAC/B"}
1
+ {"version":3,"file":"resolve-url.js","names":[],"sources":["../../../../src/media/hls/resolve-url.ts"],"sourcesContent":["/** Resolve a potentially relative URL against a base URL using native URL API. */\nexport function resolveUrl(url: string, baseUrl: string): string {\n return new URL(url, baseUrl).href;\n}\n"],"mappings":";;AACA,SAAgB,WAAW,KAAa,SAAyB;CAC/D,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC;AAC/B"}
@@ -2,21 +2,17 @@ import { isResolvedPresentation, isResolvedTrack } from "./types/index.js";
2
2
  import { findTrackById } from "./utils/tracks.js";
3
3
  //#region src/media/live-window.ts
4
4
  /**
5
- * Derive the live window of the track with the given id — the single source of
6
- * truth for "where is live," consumed (via `liveWindowFromState`) by the
7
- * seek-to-live-edge and live-seekable-range behaviors so neither re-derives (or
8
- * re-presumes) the window shape. Type-agnostic: the caller decides which track
9
- * bears the timeline (video when present, else audio).
5
+ * Derive the live window of the track with the given id — the single source of truth for "where is live," consumed (via
6
+ * `liveWindowFromState`) by the seek-to-live-edge and live-seekable-range behaviors so neither re-derives (or
7
+ * re-presumes) the window shape. Type-agnostic: the caller decides which track bears the timeline (video when present,
8
+ * else audio).
10
9
  *
11
- * The window is a **live read** over the current `segments` array — never
12
- * stored on the track. The anchor triple is frozen per source; per-segment
13
- * `startTime` values are re-derived against it on every reload, so the edge
14
- * here slides while the origin stays fixed (see
15
- * `internal/design/spf/live-presentation-timeline-model.md`).
10
+ * The window is a **live read** over the current `segments` array — never stored on the track. The anchor triple is
11
+ * frozen per source; per-segment `startTime` values are re-derived against it on every reload, so the edge here slides
12
+ * while the origin stays fixed (see `internal/design/spf/live-presentation-timeline-model.md`).
16
13
  *
17
- * Returns `null` when there is no live edge to track: an unresolved
18
- * presentation or track, a track with no segments, or a **complete** playlist
19
- * (VoD, or live that has ended — a finite `Track.duration`).
14
+ * Returns `null` when there is no live edge to track: an unresolved presentation or track, a track with no segments, or
15
+ * a **complete** playlist (VoD, or live that has ended a finite `Track.duration`).
20
16
  */
21
17
  function liveWindowFor(presentation, trackId) {
22
18
  if (!isResolvedPresentation(presentation) || !trackId) return null;
@@ -1 +1 @@
1
- {"version":3,"file":"live-window.js","names":[],"sources":["../../../src/media/live-window.ts"],"sourcesContent":["/**\n * Derive the live window of the track with the given id — the single source of\n * truth for \"where is live,\" consumed (via `liveWindowFromState`) by the\n * seek-to-live-edge and live-seekable-range behaviors so neither re-derives (or\n * re-presumes) the window shape. Type-agnostic: the caller decides which track\n * bears the timeline (video when present, else audio).\n *\n * The window is a **live read** over the current `segments` array — never\n * stored on the track. The anchor triple is frozen per source; per-segment\n * `startTime` values are re-derived against it on every reload, so the edge\n * here slides while the origin stays fixed (see\n * `internal/design/spf/live-presentation-timeline-model.md`).\n *\n * Returns `null` when there is no live edge to track: an unresolved\n * presentation or track, a track with no segments, or a **complete** playlist\n * (VoD, or live that has ended — a finite `Track.duration`).\n */\nimport { isResolvedPresentation, isResolvedTrack, type MaybeResolvedPresentation } from './types';\nimport { findTrackById } from './utils/tracks';\n\nexport interface LiveWindow {\n /** Earliest time still in the window (seconds, presentation timeline). */\n start: number;\n /** The live edge — latest time in the window (seconds). */\n end: number;\n}\n\nexport function liveWindowFor(\n presentation: MaybeResolvedPresentation | undefined,\n trackId: string | undefined\n): LiveWindow | null {\n if (!isResolvedPresentation(presentation) || !trackId) return null;\n\n const track = findTrackById(presentation, trackId);\n if (!track || !isResolvedTrack(track) || track.segments.length === 0) return null;\n\n // Complete playlist (VoD, or live that has ended) → no live edge. `Track.duration`\n // is the parser's completeness signal (finite = complete, Infinity = still growing).\n if (Number.isFinite(track.duration)) return null;\n\n const { segments } = track;\n const last = segments[segments.length - 1]!;\n return {\n start: segments[0]!.startTime,\n end: last.startTime + last.duration,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,cACd,cACA,SACmB;CACnB,IAAI,CAAC,uBAAuB,YAAY,KAAK,CAAC,SAAS,OAAO;CAE9D,MAAM,QAAQ,cAAc,cAAc,OAAO;CACjD,IAAI,CAAC,SAAS,CAAC,gBAAgB,KAAK,KAAK,MAAM,SAAS,WAAW,GAAG,OAAO;CAI7E,IAAI,OAAO,SAAS,MAAM,QAAQ,GAAG,OAAO;CAE5C,MAAM,EAAE,aAAa;CACrB,MAAM,OAAO,SAAS,SAAS,SAAS;CACxC,OAAO;EACL,OAAO,SAAS,EAAE,CAAE;EACpB,KAAK,KAAK,YAAY,KAAK;CAC7B;AACF"}
1
+ {"version":3,"file":"live-window.js","names":[],"sources":["../../../src/media/live-window.ts"],"sourcesContent":["/**\n * Derive the live window of the track with the given id — the single source of truth for \"where is live,\" consumed (via\n * `liveWindowFromState`) by the seek-to-live-edge and live-seekable-range behaviors so neither re-derives (or\n * re-presumes) the window shape. Type-agnostic: the caller decides which track bears the timeline (video when present,\n * else audio).\n *\n * The window is a **live read** over the current `segments` array — never stored on the track. The anchor triple is\n * frozen per source; per-segment `startTime` values are re-derived against it on every reload, so the edge here slides\n * while the origin stays fixed (see `internal/design/spf/live-presentation-timeline-model.md`).\n *\n * Returns `null` when there is no live edge to track: an unresolved presentation or track, a track with no segments, or\n * a **complete** playlist (VoD, or live that has ended — a finite `Track.duration`).\n */\nimport { isResolvedPresentation, isResolvedTrack, type MaybeResolvedPresentation } from './types';\nimport { findTrackById } from './utils/tracks';\n\nexport interface LiveWindow {\n /** Earliest time still in the window (seconds, presentation timeline). */\n start: number;\n /** The live edge — latest time in the window (seconds). */\n end: number;\n}\n\nexport function liveWindowFor(\n presentation: MaybeResolvedPresentation | undefined,\n trackId: string | undefined\n): LiveWindow | null {\n if (!isResolvedPresentation(presentation) || !trackId) return null;\n\n const track = findTrackById(presentation, trackId);\n if (!track || !isResolvedTrack(track) || track.segments.length === 0) return null;\n\n // Complete playlist (VoD, or live that has ended) → no live edge. `Track.duration`\n // is the parser's completeness signal (finite = complete, Infinity = still growing).\n if (Number.isFinite(track.duration)) return null;\n\n const { segments } = track;\n const last = segments[segments.length - 1]!;\n\n return {\n start: segments[0]!.startTime,\n end: last.startTime + last.duration,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAuBA,SAAgB,cACd,cACA,SACmB;CACnB,IAAI,CAAC,uBAAuB,YAAY,KAAK,CAAC,SAAS,OAAO;CAE9D,MAAM,QAAQ,cAAc,cAAc,OAAO;CACjD,IAAI,CAAC,SAAS,CAAC,gBAAgB,KAAK,KAAK,MAAM,SAAS,WAAW,GAAG,OAAO;CAI7E,IAAI,OAAO,SAAS,MAAM,QAAQ,GAAG,OAAO;CAE5C,MAAM,EAAE,aAAa;CACrB,MAAM,OAAO,SAAS,SAAS,SAAS;CAExC,OAAO;EACL,OAAO,SAAS,EAAE,CAAE;EACpB,KAAK,KAAK,YAAY,KAAK;CAC7B;AACF"}
@@ -18,27 +18,22 @@ interface AudioDedupeKey {
18
18
  */
19
19
  declare function dedupedVideoTracks(presentation: MaybeResolvedPresentation | undefined): VideoTrack[];
20
20
  /**
21
- * The distinct audio tracks of a presentation, deduped by `language` + `name`
22
- * (first occurrence wins). Returns `[]` when the presentation is unresolved or has no audio tracks.
21
+ * The distinct audio tracks of a presentation, deduped by `language` + `name` (first occurrence wins). Returns `[]`
22
+ * when the presentation is unresolved or has no audio tracks.
23
23
  */
24
24
  declare function dedupedAudioTracks(presentation: MaybeResolvedPresentation | undefined): AudioTrack[];
25
25
  /**
26
- * Find a video track by id, searching the same candidate set the engine resolves
27
- * against ({@link dedupedVideoTracks}'s pre-dedupe source). Returns `undefined`
28
- * when absent. Maps the engine's resolved `selectedVideoTrackId` back to its
29
- * properties for `active` reflection — the resolved id may be a per-CDN copy that
30
- * isn't the representative {@link dedupedVideoTracks} kept.
26
+ * Find a video track by id, searching the same candidate set the engine resolves against ({@link dedupedVideoTracks}'s
27
+ * pre-dedupe source). Returns `undefined` when absent. Maps the engine's resolved `selectedVideoTrackId` back to its
28
+ * properties for `active` reflection — the resolved id may be a per-CDN copy that isn't the representative
29
+ * {@link dedupedVideoTracks} kept.
31
30
  */
32
31
  declare function findVideoTrackById(presentation: MaybeResolvedPresentation | undefined, id: string | undefined): VideoTrack | undefined;
33
32
  /** Audio counterpart of {@link findVideoTrackById}, for `enabled` reflection. */
34
33
  declare function findAudioTrackById(presentation: MaybeResolvedPresentation | undefined, id: string | undefined): AudioTrack | undefined;
35
- /**
36
- * Build a partial video track that can be used as `userVideoTrackSelection`.
37
- */
34
+ /** Build a partial video track that can be used as `userVideoTrackSelection`. */
38
35
  declare function toUserVideoTrackSelection<T extends VideoDedupeKey>(rendition?: T): Partial<VideoTrack> | undefined;
39
- /**
40
- * Build a partial audio track that can be used as a `userAudioTrackSelection`.
41
- */
36
+ /** Build a partial audio track that can be used as a `userAudioTrackSelection`. */
42
37
  declare function toUserAudioTrackSelection<T extends AudioDedupeKey>(track?: T): Partial<AudioTrack> | undefined;
43
38
  /** Whether two video tracks are the same by dedupe key */
44
39
  declare function isSameVideoTrack(a: VideoDedupeKey, b: VideoDedupeKey | undefined): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"media-tracks.d.ts","names":[],"sources":["../../../../src/media/media-tracks/media-tracks.ts"],"mappings":";;;UA0BiB;EACf,QAAQ;EACR,SAAS;EACT,YAAY;;;UAIG;EACf,WAAW;EACX,OAAO;;;;;;;iBAQO,mBAAmB,cAAc,wCAAwC;;;;;iBAazE,mBAAmB,cAAc,wCAAwC;;;;;;;;iBAgBzE,mBACd,cAAc,uCACd,yBACC;;iBAOa,mBACd,cAAc,uCACd,yBACC;;;;iBA2Ca,0BAA0B,UAAU,gBAAgB,YAAY,IAAI,QAAQ;;;;iBAO5E,0BAA0B,UAAU,gBAAgB,QAAQ,IAAI,QAAQ;;iBAKxE,iBAAiB,GAAG,gBAAgB,GAAG;;iBAKvC,iBAAiB,GAAG,gBAAgB,GAAG;;cAK1C,oBAAiB,WAAe"}
1
+ {"version":3,"file":"media-tracks.d.ts","names":[],"sources":["../../../../src/media/media-tracks/media-tracks.ts"],"mappings":";;;UAuBiB;EACf,QAAQ;EACR,SAAS;EACT,YAAY;;;UAIG;EACf,WAAW;EACX,OAAO;;;;;;;iBAQO,mBAAmB,cAAc,wCAAwC;;;;;iBAazE,mBAAmB,cAAc,wCAAwC;;;;;;;iBAezE,mBACd,cAAc,uCACd,yBACC;;iBASa,mBACd,cAAc,uCACd,yBACC;;iBA8Ca,0BAA0B,UAAU,gBAAgB,YAAY,IAAI,QAAQ;;iBAK5E,0BAA0B,UAAU,gBAAgB,QAAQ,IAAI,QAAQ;;iBAKxE,iBAAiB,GAAG,gBAAgB,GAAG;;iBAKvC,iBAAiB,GAAG,gBAAgB,GAAG;;cAK1C,oBAAiB,WAAe"}
@@ -13,8 +13,8 @@ function dedupedVideoTracks(presentation) {
13
13
  });
14
14
  }
15
15
  /**
16
- * The distinct audio tracks of a presentation, deduped by `language` + `name`
17
- * (first occurrence wins). Returns `[]` when the presentation is unresolved or has no audio tracks.
16
+ * The distinct audio tracks of a presentation, deduped by `language` + `name` (first occurrence wins). Returns `[]`
17
+ * when the presentation is unresolved or has no audio tracks.
18
18
  */
19
19
  function dedupedAudioTracks(presentation) {
20
20
  if (!presentation) return [];
@@ -24,11 +24,10 @@ function dedupedAudioTracks(presentation) {
24
24
  });
25
25
  }
26
26
  /**
27
- * Find a video track by id, searching the same candidate set the engine resolves
28
- * against ({@link dedupedVideoTracks}'s pre-dedupe source). Returns `undefined`
29
- * when absent. Maps the engine's resolved `selectedVideoTrackId` back to its
30
- * properties for `active` reflection — the resolved id may be a per-CDN copy that
31
- * isn't the representative {@link dedupedVideoTracks} kept.
27
+ * Find a video track by id, searching the same candidate set the engine resolves against ({@link dedupedVideoTracks}'s
28
+ * pre-dedupe source). Returns `undefined` when absent. Maps the engine's resolved `selectedVideoTrackId` back to its
29
+ * properties for `active` reflection — the resolved id may be a per-CDN copy that isn't the representative
30
+ * {@link dedupedVideoTracks} kept.
32
31
  */
33
32
  function findVideoTrackById(presentation, id) {
34
33
  if (!presentation || !id) return void 0;
@@ -42,16 +41,16 @@ function findAudioTrackById(presentation, id) {
42
41
  return track?.type === "audio" ? track : void 0;
43
42
  }
44
43
  /**
45
- * Shallow-equal two key objects by their own properties. Both come from the same
46
- * key builder, so they carry the same keys — a one-directional scan suffices.
44
+ * Shallow-equal two key objects by their own properties. Both come from the same key builder, so they carry the same
45
+ * keys — a one-directional scan suffices.
47
46
  */
48
47
  function sameKey(a, b) {
49
48
  for (const attr in a) if (a[attr] !== b[attr]) return false;
50
49
  return true;
51
50
  }
52
51
  /**
53
- * Dedupe tracks by a key function, keeping the first occurrence of each key.
54
- * Keys are compared field-by-field ({@link sameKey}).
52
+ * Dedupe tracks by a key function, keeping the first occurrence of each key. Keys are compared field-by-field ({@link
53
+ * sameKey}).
55
54
  */
56
55
  function dedupe({ tracks, keyFn }) {
57
56
  const seen = [];
@@ -64,9 +63,7 @@ function dedupe({ tracks, keyFn }) {
64
63
  }
65
64
  return kept;
66
65
  }
67
- /**
68
- * Build a partial video track that can be used as `userVideoTrackSelection`.
69
- */
66
+ /** Build a partial video track that can be used as `userVideoTrackSelection`. */
70
67
  function toUserVideoTrackSelection(rendition) {
71
68
  return rendition ? {
72
69
  width: rendition.width,
@@ -74,9 +71,7 @@ function toUserVideoTrackSelection(rendition) {
74
71
  bandwidth: rendition.bandwidth
75
72
  } : void 0;
76
73
  }
77
- /**
78
- * Build a partial audio track that can be used as a `userAudioTrackSelection`.
79
- */
74
+ /** Build a partial audio track that can be used as a `userAudioTrackSelection`. */
80
75
  function toUserAudioTrackSelection(track) {
81
76
  return track ? {
82
77
  language: track.language,
@@ -1 +1 @@
1
- {"version":3,"file":"media-tracks.js","names":[],"sources":["../../../../src/media/media-tracks/media-tracks.ts"],"sourcesContent":["/**\n * Media-track translation utilities.\n *\n * Pure, DOM-free transforms from SPF's CMAF-HAM track model onto the deduped\n * lists a media-element adapter exposes (video renditions, audio tracks), plus\n * the selection-criteria builders that turn a chosen rendition/track back into a\n * `user*TrackSelection` partial the engine's track-switching reads.\n *\n * These return SPF *model vocabulary* (`bandwidth`, `codecs: string[]`,\n * `frameRate` as a rational `FrameRate`); the consuming adapter owns the\n * mapping (e.g. for DOM `bandwidth` -> `bitrate`, `codecs.join(',')` -> `codec`,\n * `name` -> `label`).\n *\n * Deduplication is by *properties*, never URL, so a multi-CDN source that lists\n * the same rendition on several hosts collapses to one entry: video renditions\n * by `width` + `height` + `bandwidth`, audio tracks by `language` + `name`.\n * The selection builders emit those same properties as the match criteria, so\n * selecting a collapsed entry re-selects, for example, every underlying per-CDN track.\n */\n\nimport type { AudioTrack, FrameRate, MaybeResolvedPresentation, VideoTrack } from '../types';\nimport { findTrackById, getTracksByType } from '../utils/tracks';\n\nexport type { AudioTrack, VideoTrack };\n\n/** Properties that identify a distinct video rendition (multi-CDN copies share them). */\nexport interface VideoDedupeKey {\n width?: VideoTrack['width'];\n height?: VideoTrack['height'];\n bandwidth?: VideoTrack['bandwidth'];\n}\n\n/** Properties that identify a distinct audio track (multi-CDN copies share them). */\nexport interface AudioDedupeKey {\n language?: AudioTrack['language'];\n name?: AudioTrack['name'];\n}\n\n/**\n * The distinct video tracks of a presentation, deduped by {@link VideoDedupeKey} (first occurrence wins).\n *\n * Returns `[]` when the presentation is unresolved or has no video tracks.\n */\nexport function dedupedVideoTracks(presentation: MaybeResolvedPresentation | undefined): VideoTrack[] {\n if (!presentation) return [];\n\n return dedupe({\n tracks: getTracksByType(presentation, 'video') as readonly VideoTrack[],\n keyFn: toUserVideoTrackSelection,\n });\n}\n\n/**\n * The distinct audio tracks of a presentation, deduped by `language` + `name`\n * (first occurrence wins). Returns `[]` when the presentation is unresolved or has no audio tracks.\n */\nexport function dedupedAudioTracks(presentation: MaybeResolvedPresentation | undefined): AudioTrack[] {\n if (!presentation) return [];\n\n return dedupe({\n tracks: getTracksByType(presentation, 'audio') as readonly AudioTrack[],\n keyFn: toUserAudioTrackSelection,\n });\n}\n\n/**\n * Find a video track by id, searching the same candidate set the engine resolves\n * against ({@link dedupedVideoTracks}'s pre-dedupe source). Returns `undefined`\n * when absent. Maps the engine's resolved `selectedVideoTrackId` back to its\n * properties for `active` reflection — the resolved id may be a per-CDN copy that\n * isn't the representative {@link dedupedVideoTracks} kept.\n */\nexport function findVideoTrackById(\n presentation: MaybeResolvedPresentation | undefined,\n id: string | undefined\n): VideoTrack | undefined {\n if (!presentation || !id) return undefined;\n const track = findTrackById(presentation, id);\n return track?.type === 'video' ? (track as VideoTrack) : undefined;\n}\n\n/** Audio counterpart of {@link findVideoTrackById}, for `enabled` reflection. */\nexport function findAudioTrackById(\n presentation: MaybeResolvedPresentation | undefined,\n id: string | undefined\n): AudioTrack | undefined {\n if (!presentation || !id) return undefined;\n const track = findTrackById(presentation, id);\n return track?.type === 'audio' ? (track as AudioTrack) : undefined;\n}\n\n/**\n * Shallow-equal two key objects by their own properties. Both come from the same\n * key builder, so they carry the same keys — a one-directional scan suffices.\n */\nfunction sameKey<K extends object>(a: K, b: K): boolean {\n for (const attr in a) {\n if (a[attr] !== b[attr]) return false;\n }\n return true;\n}\n\n/**\n * Dedupe tracks by a key function, keeping the first occurrence of each key.\n * Keys are compared field-by-field ({@link sameKey}).\n */\nfunction dedupe<T, K extends object>({\n tracks,\n keyFn,\n}: {\n tracks: readonly T[];\n keyFn: (track: T) => K | undefined;\n}): T[] {\n const seen: K[] = [];\n const kept: T[] = [];\n for (const track of tracks) {\n const key = keyFn(track);\n if (!key || seen.some((other) => sameKey(other, key))) continue;\n seen.push(key);\n kept.push(track);\n }\n\n return kept;\n}\n\n/**\n * Build a partial video track that can be used as `userVideoTrackSelection`.\n */\nexport function toUserVideoTrackSelection<T extends VideoDedupeKey>(rendition?: T): Partial<VideoTrack> | undefined {\n return rendition ? { width: rendition.width, height: rendition.height, bandwidth: rendition.bandwidth } : undefined;\n}\n\n/**\n * Build a partial audio track that can be used as a `userAudioTrackSelection`.\n */\nexport function toUserAudioTrackSelection<T extends AudioDedupeKey>(track?: T): Partial<AudioTrack> | undefined {\n return track ? { language: track.language, name: track.name } : undefined;\n}\n\n/** Whether two video tracks are the same by dedupe key */\nexport function isSameVideoTrack(a: VideoDedupeKey, b: VideoDedupeKey | undefined): boolean {\n return !!b && a.width === b.width && a.height === b.height && a.bandwidth === b.bandwidth;\n}\n\n/** Whether two audio tracks are the same by dedupe key */\nexport function isSameAudioTrack(a: AudioDedupeKey, b: AudioDedupeKey | undefined): boolean {\n return !!b && (a.language ?? '') === (b.language ?? '') && a.name === b.name;\n}\n\n/** Collapse a rational frame rate (numerator/denominator) to frames per second. */\nexport const frameRateToNumber = (frameRate: FrameRate) => {\n return frameRate.frameRateNumerator / (frameRate.frameRateDenominator ?? 1);\n};\n"],"mappings":";;;;;;;AA2CA,SAAgB,mBAAmB,cAAmE;CACpG,IAAI,CAAC,cAAc,OAAO,CAAC;CAE3B,OAAO,OAAO;EACZ,QAAQ,gBAAgB,cAAc,OAAO;EAC7C,OAAO;CACT,CAAC;AACH;;;;;AAMA,SAAgB,mBAAmB,cAAmE;CACpG,IAAI,CAAC,cAAc,OAAO,CAAC;CAE3B,OAAO,OAAO;EACZ,QAAQ,gBAAgB,cAAc,OAAO;EAC7C,OAAO;CACT,CAAC;AACH;;;;;;;;AASA,SAAgB,mBACd,cACA,IACwB;CACxB,IAAI,CAAC,gBAAgB,CAAC,IAAI,OAAO,KAAA;CACjC,MAAM,QAAQ,cAAc,cAAc,EAAE;CAC5C,OAAO,OAAO,SAAS,UAAW,QAAuB,KAAA;AAC3D;;AAGA,SAAgB,mBACd,cACA,IACwB;CACxB,IAAI,CAAC,gBAAgB,CAAC,IAAI,OAAO,KAAA;CACjC,MAAM,QAAQ,cAAc,cAAc,EAAE;CAC5C,OAAO,OAAO,SAAS,UAAW,QAAuB,KAAA;AAC3D;;;;;AAMA,SAAS,QAA0B,GAAM,GAAe;CACtD,KAAK,MAAM,QAAQ,GACjB,IAAI,EAAE,UAAU,EAAE,OAAO,OAAO;CAElC,OAAO;AACT;;;;;AAMA,SAAS,OAA4B,EACnC,QACA,SAIM;CACN,MAAM,OAAY,CAAC;CACnB,MAAM,OAAY,CAAC;CACnB,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,MAAM,MAAM,KAAK;EACvB,IAAI,CAAC,OAAO,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG,CAAC,GAAG;EACvD,KAAK,KAAK,GAAG;EACb,KAAK,KAAK,KAAK;CACjB;CAEA,OAAO;AACT;;;;AAKA,SAAgB,0BAAoD,WAAgD;CAClH,OAAO,YAAY;EAAE,OAAO,UAAU;EAAO,QAAQ,UAAU;EAAQ,WAAW,UAAU;CAAU,IAAI,KAAA;AAC5G;;;;AAKA,SAAgB,0BAAoD,OAA4C;CAC9G,OAAO,QAAQ;EAAE,UAAU,MAAM;EAAU,MAAM,MAAM;CAAK,IAAI,KAAA;AAClE;;AAGA,SAAgB,iBAAiB,GAAmB,GAAwC;CAC1F,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE;AAClF;;AAGA,SAAgB,iBAAiB,GAAmB,GAAwC;CAC1F,OAAO,CAAC,CAAC,MAAM,EAAE,YAAY,SAAS,EAAE,YAAY,OAAO,EAAE,SAAS,EAAE;AAC1E;;AAGA,MAAa,qBAAqB,cAAyB;CACzD,OAAO,UAAU,sBAAsB,UAAU,wBAAwB;AAC3E"}
1
+ {"version":3,"file":"media-tracks.js","names":[],"sources":["../../../../src/media/media-tracks/media-tracks.ts"],"sourcesContent":["/**\n * Media-track translation utilities.\n *\n * Pure, DOM-free transforms from SPF's CMAF-HAM track model onto the deduped lists a media-element adapter exposes\n * (video renditions, audio tracks), plus the selection-criteria builders that turn a chosen rendition/track back into a\n * `user*TrackSelection` partial the engine's track-switching reads.\n *\n * These return SPF _model vocabulary_ (`bandwidth`, `codecs: string[]`, `frameRate` as a rational `FrameRate`); the\n * consuming adapter owns the mapping (e.g. for DOM `bandwidth` -> `bitrate`, `codecs.join(',')` -> `codec`, `name` ->\n * `label`).\n *\n * Deduplication is by _properties_, never URL, so a multi-CDN source that lists the same rendition on several hosts\n * collapses to one entry: video renditions by `width` + `height` + `bandwidth`, audio tracks by `language` + `name`.\n * The selection builders emit those same properties as the match criteria, so selecting a collapsed entry re-selects,\n * for example, every underlying per-CDN track.\n */\n\nimport type { AudioTrack, FrameRate, MaybeResolvedPresentation, VideoTrack } from '../types';\nimport { findTrackById, getTracksByType } from '../utils/tracks';\n\nexport type { AudioTrack, VideoTrack };\n\n/** Properties that identify a distinct video rendition (multi-CDN copies share them). */\nexport interface VideoDedupeKey {\n width?: VideoTrack['width'];\n height?: VideoTrack['height'];\n bandwidth?: VideoTrack['bandwidth'];\n}\n\n/** Properties that identify a distinct audio track (multi-CDN copies share them). */\nexport interface AudioDedupeKey {\n language?: AudioTrack['language'];\n name?: AudioTrack['name'];\n}\n\n/**\n * The distinct video tracks of a presentation, deduped by {@link VideoDedupeKey} (first occurrence wins).\n *\n * Returns `[]` when the presentation is unresolved or has no video tracks.\n */\nexport function dedupedVideoTracks(presentation: MaybeResolvedPresentation | undefined): VideoTrack[] {\n if (!presentation) return [];\n\n return dedupe({\n tracks: getTracksByType(presentation, 'video') as readonly VideoTrack[],\n keyFn: toUserVideoTrackSelection,\n });\n}\n\n/**\n * The distinct audio tracks of a presentation, deduped by `language` + `name` (first occurrence wins). Returns `[]`\n * when the presentation is unresolved or has no audio tracks.\n */\nexport function dedupedAudioTracks(presentation: MaybeResolvedPresentation | undefined): AudioTrack[] {\n if (!presentation) return [];\n\n return dedupe({\n tracks: getTracksByType(presentation, 'audio') as readonly AudioTrack[],\n keyFn: toUserAudioTrackSelection,\n });\n}\n\n/**\n * Find a video track by id, searching the same candidate set the engine resolves against ({@link dedupedVideoTracks}'s\n * pre-dedupe source). Returns `undefined` when absent. Maps the engine's resolved `selectedVideoTrackId` back to its\n * properties for `active` reflection — the resolved id may be a per-CDN copy that isn't the representative\n * {@link dedupedVideoTracks} kept.\n */\nexport function findVideoTrackById(\n presentation: MaybeResolvedPresentation | undefined,\n id: string | undefined\n): VideoTrack | undefined {\n if (!presentation || !id) return undefined;\n\n const track = findTrackById(presentation, id);\n\n return track?.type === 'video' ? (track as VideoTrack) : undefined;\n}\n\n/** Audio counterpart of {@link findVideoTrackById}, for `enabled` reflection. */\nexport function findAudioTrackById(\n presentation: MaybeResolvedPresentation | undefined,\n id: string | undefined\n): AudioTrack | undefined {\n if (!presentation || !id) return undefined;\n\n const track = findTrackById(presentation, id);\n\n return track?.type === 'audio' ? (track as AudioTrack) : undefined;\n}\n\n/**\n * Shallow-equal two key objects by their own properties. Both come from the same key builder, so they carry the same\n * keys — a one-directional scan suffices.\n */\nfunction sameKey<K extends object>(a: K, b: K): boolean {\n for (const attr in a) {\n if (a[attr] !== b[attr]) return false;\n }\n\n return true;\n}\n\n/**\n * Dedupe tracks by a key function, keeping the first occurrence of each key. Keys are compared field-by-field ({@link\n * sameKey}).\n */\nfunction dedupe<T, K extends object>({\n tracks,\n keyFn,\n}: {\n tracks: readonly T[];\n keyFn: (track: T) => K | undefined;\n}): T[] {\n const seen: K[] = [];\n const kept: T[] = [];\n\n for (const track of tracks) {\n const key = keyFn(track);\n if (!key || seen.some((other) => sameKey(other, key))) continue;\n\n seen.push(key);\n kept.push(track);\n }\n\n return kept;\n}\n\n/** Build a partial video track that can be used as `userVideoTrackSelection`. */\nexport function toUserVideoTrackSelection<T extends VideoDedupeKey>(rendition?: T): Partial<VideoTrack> | undefined {\n return rendition ? { width: rendition.width, height: rendition.height, bandwidth: rendition.bandwidth } : undefined;\n}\n\n/** Build a partial audio track that can be used as a `userAudioTrackSelection`. */\nexport function toUserAudioTrackSelection<T extends AudioDedupeKey>(track?: T): Partial<AudioTrack> | undefined {\n return track ? { language: track.language, name: track.name } : undefined;\n}\n\n/** Whether two video tracks are the same by dedupe key */\nexport function isSameVideoTrack(a: VideoDedupeKey, b: VideoDedupeKey | undefined): boolean {\n return !!b && a.width === b.width && a.height === b.height && a.bandwidth === b.bandwidth;\n}\n\n/** Whether two audio tracks are the same by dedupe key */\nexport function isSameAudioTrack(a: AudioDedupeKey, b: AudioDedupeKey | undefined): boolean {\n return !!b && (a.language ?? '') === (b.language ?? '') && a.name === b.name;\n}\n\n/** Collapse a rational frame rate (numerator/denominator) to frames per second. */\nexport const frameRateToNumber = (frameRate: FrameRate) => {\n return frameRate.frameRateNumerator / (frameRate.frameRateDenominator ?? 1);\n};\n"],"mappings":";;;;;;;AAwCA,SAAgB,mBAAmB,cAAmE;CACpG,IAAI,CAAC,cAAc,OAAO,CAAC;CAE3B,OAAO,OAAO;EACZ,QAAQ,gBAAgB,cAAc,OAAO;EAC7C,OAAO;CACT,CAAC;AACH;;;;;AAMA,SAAgB,mBAAmB,cAAmE;CACpG,IAAI,CAAC,cAAc,OAAO,CAAC;CAE3B,OAAO,OAAO;EACZ,QAAQ,gBAAgB,cAAc,OAAO;EAC7C,OAAO;CACT,CAAC;AACH;;;;;;;AAQA,SAAgB,mBACd,cACA,IACwB;CACxB,IAAI,CAAC,gBAAgB,CAAC,IAAI,OAAO,KAAA;CAEjC,MAAM,QAAQ,cAAc,cAAc,EAAE;CAE5C,OAAO,OAAO,SAAS,UAAW,QAAuB,KAAA;AAC3D;;AAGA,SAAgB,mBACd,cACA,IACwB;CACxB,IAAI,CAAC,gBAAgB,CAAC,IAAI,OAAO,KAAA;CAEjC,MAAM,QAAQ,cAAc,cAAc,EAAE;CAE5C,OAAO,OAAO,SAAS,UAAW,QAAuB,KAAA;AAC3D;;;;;AAMA,SAAS,QAA0B,GAAM,GAAe;CACtD,KAAK,MAAM,QAAQ,GACjB,IAAI,EAAE,UAAU,EAAE,OAAO,OAAO;CAGlC,OAAO;AACT;;;;;AAMA,SAAS,OAA4B,EACnC,QACA,SAIM;CACN,MAAM,OAAY,CAAC;CACnB,MAAM,OAAY,CAAC;CAEnB,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,MAAM,MAAM,KAAK;EACvB,IAAI,CAAC,OAAO,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG,CAAC,GAAG;EAEvD,KAAK,KAAK,GAAG;EACb,KAAK,KAAK,KAAK;CACjB;CAEA,OAAO;AACT;;AAGA,SAAgB,0BAAoD,WAAgD;CAClH,OAAO,YAAY;EAAE,OAAO,UAAU;EAAO,QAAQ,UAAU;EAAQ,WAAW,UAAU;CAAU,IAAI,KAAA;AAC5G;;AAGA,SAAgB,0BAAoD,OAA4C;CAC9G,OAAO,QAAQ;EAAE,UAAU,MAAM;EAAU,MAAM,MAAM;CAAK,IAAI,KAAA;AAClE;;AAGA,SAAgB,iBAAiB,GAAmB,GAAwC;CAC1F,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE;AAClF;;AAGA,SAAgB,iBAAiB,GAAmB,GAAwC;CAC1F,OAAO,CAAC,CAAC,MAAM,EAAE,YAAY,SAAS,EAAE,YAAY,OAAO,EAAE,SAAS,EAAE;AAC1E;;AAGA,MAAa,qBAAqB,cAAyB;CACzD,OAAO,UAAU,sBAAsB,UAAU,wBAAwB;AAC3E"}
@@ -32,9 +32,8 @@ function* iterateBoxesOfType(view, type, start = 0, end = view.byteLength) {
32
32
  for (const box of iterateBoxes(view, start, end)) if (box.type === type) yield box;
33
33
  }
34
34
  /**
35
- * Depth-first descent to the first box matching a nested path, e.g.
36
- * `['moov', 'trak', 'mdia', 'mdhd']`. Returns `undefined` if any level is
37
- * absent.
35
+ * Depth-first descent to the first box matching a nested path, e.g. `['moov', 'trak', 'mdia', 'mdhd']`. Returns
36
+ * `undefined` if any level is absent.
38
37
  */
39
38
  function findBox(view, path, start = 0, end = view.byteLength) {
40
39
  const [head, ...rest] = path;
@@ -46,8 +45,8 @@ function findBox(view, path, start = 0, end = view.byteLength) {
46
45
  }
47
46
  }
48
47
  /**
49
- * Read the version byte of a FullBox — the `version(1) + flags(3)` header at the
50
- * start of the payload of `mdhd` / `tkhd` / `tfdt` / `hdlr` / `elst` / etc.
48
+ * Read the version byte of a FullBox — the `version(1) + flags(3)` header at the start of the payload of `mdhd` /
49
+ * `tkhd` / `tfdt` / `hdlr` / `elst` / etc.
51
50
  */
52
51
  function readFullBoxVersion(view, dataStart) {
53
52
  return view.getUint8(dataStart);
@@ -1 +1 @@
1
- {"version":3,"file":"box.js","names":[],"sources":["../../../../src/media/mp4/box.ts"],"sourcesContent":["/**\n * Minimal ISO-BMFF (MP4/CMAF) box walker.\n *\n * Just enough to locate boxes by nested path — the framework needs a couple of\n * leaf fields (`mdhd` timescale, `tfdt` baseMediaDecodeTime) to derive a\n * segment's decode-time origin, not a full demuxer. DOM-free: operates on an\n * `ArrayBuffer` / `Uint8Array` via `DataView`.\n *\n * Box layout: `[u32 size][u32 type][payload]`. `size === 1` means a `u64\n * largesize` follows the type (payload after it); `size === 0` means the box\n * runs to the end of its container.\n */\n\n/** A located box: its 4-char type and byte offsets within the buffer. */\nexport interface Box {\n type: string;\n /** Offset of the box's first byte (its size field). */\n start: number;\n /** Offset of the box's payload — after `size` + `type` (+ `largesize`). */\n dataStart: number;\n /** Offset one past the box's last byte. */\n end: number;\n}\n\nexport function toDataView(data: ArrayBuffer | Uint8Array): DataView {\n return data instanceof Uint8Array ? new DataView(data.buffer, data.byteOffset, data.byteLength) : new DataView(data);\n}\n\n/** Read a 4-character box type / FourCC at `offset`. */\nexport function readFourCC(view: DataView, offset: number): string {\n return String.fromCharCode(\n view.getUint8(offset),\n view.getUint8(offset + 1),\n view.getUint8(offset + 2),\n view.getUint8(offset + 3)\n );\n}\n\n/** Iterate the boxes directly contained in `[start, end)`. */\nexport function* iterateBoxes(view: DataView, start = 0, end = view.byteLength): Generator<Box> {\n let offset = start;\n while (offset + 8 <= end) {\n let size = view.getUint32(offset);\n const type = readFourCC(view, offset + 4);\n let dataStart = offset + 8;\n if (size === 1) {\n size = Number(view.getBigUint64(offset + 8));\n dataStart = offset + 16;\n } else if (size === 0) {\n size = end - offset;\n }\n // A size smaller than its own header is malformed — stop rather than loop.\n if (size < dataStart - offset) return;\n yield { type, start: offset, dataStart, end: offset + size };\n offset += size;\n }\n}\n\n/** Iterate the direct child boxes of a given `type` within `[start, end)`. */\nexport function* iterateBoxesOfType(view: DataView, type: string, start = 0, end = view.byteLength): Generator<Box> {\n for (const box of iterateBoxes(view, start, end)) {\n if (box.type === type) yield box;\n }\n}\n\n/**\n * Depth-first descent to the first box matching a nested path, e.g.\n * `['moov', 'trak', 'mdia', 'mdhd']`. Returns `undefined` if any level is\n * absent.\n */\nexport function findBox(view: DataView, path: readonly string[], start = 0, end = view.byteLength): Box | undefined {\n const [head, ...rest] = path;\n for (const box of iterateBoxes(view, start, end)) {\n if (box.type !== head) continue;\n if (rest.length === 0) return box;\n const found = findBox(view, rest, box.dataStart, box.end);\n if (found) return found;\n }\n return undefined;\n}\n\n/**\n * Read the version byte of a FullBox — the `version(1) + flags(3)` header at the\n * start of the payload of `mdhd` / `tkhd` / `tfdt` / `hdlr` / `elst` / etc.\n */\nexport function readFullBoxVersion(view: DataView, dataStart: number): number {\n return view.getUint8(dataStart);\n}\n"],"mappings":";AAwBA,SAAgB,WAAW,MAA0C;CACnE,OAAO,gBAAgB,aAAa,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,IAAI,IAAI,SAAS,IAAI;AACrH;;AAGA,SAAgB,WAAW,MAAgB,QAAwB;CACjE,OAAO,OAAO,aACZ,KAAK,SAAS,MAAM,GACpB,KAAK,SAAS,SAAS,CAAC,GACxB,KAAK,SAAS,SAAS,CAAC,GACxB,KAAK,SAAS,SAAS,CAAC,CAC1B;AACF;;AAGA,UAAiB,aAAa,MAAgB,QAAQ,GAAG,MAAM,KAAK,YAA4B;CAC9F,IAAI,SAAS;CACb,OAAO,SAAS,KAAK,KAAK;EACxB,IAAI,OAAO,KAAK,UAAU,MAAM;EAChC,MAAM,OAAO,WAAW,MAAM,SAAS,CAAC;EACxC,IAAI,YAAY,SAAS;EACzB,IAAI,SAAS,GAAG;GACd,OAAO,OAAO,KAAK,aAAa,SAAS,CAAC,CAAC;GAC3C,YAAY,SAAS;EACvB,OAAO,IAAI,SAAS,GAClB,OAAO,MAAM;EAGf,IAAI,OAAO,YAAY,QAAQ;EAC/B,MAAM;GAAE;GAAM,OAAO;GAAQ;GAAW,KAAK,SAAS;EAAK;EAC3D,UAAU;CACZ;AACF;;AAGA,UAAiB,mBAAmB,MAAgB,MAAc,QAAQ,GAAG,MAAM,KAAK,YAA4B;CAClH,KAAK,MAAM,OAAO,aAAa,MAAM,OAAO,GAAG,GAC7C,IAAI,IAAI,SAAS,MAAM,MAAM;AAEjC;;;;;;AAOA,SAAgB,QAAQ,MAAgB,MAAyB,QAAQ,GAAG,MAAM,KAAK,YAA6B;CAClH,MAAM,CAAC,MAAM,GAAG,QAAQ;CACxB,KAAK,MAAM,OAAO,aAAa,MAAM,OAAO,GAAG,GAAG;EAChD,IAAI,IAAI,SAAS,MAAM;EACvB,IAAI,KAAK,WAAW,GAAG,OAAO;EAC9B,MAAM,QAAQ,QAAQ,MAAM,MAAM,IAAI,WAAW,IAAI,GAAG;EACxD,IAAI,OAAO,OAAO;CACpB;AAEF;;;;;AAMA,SAAgB,mBAAmB,MAAgB,WAA2B;CAC5E,OAAO,KAAK,SAAS,SAAS;AAChC"}
1
+ {"version":3,"file":"box.js","names":[],"sources":["../../../../src/media/mp4/box.ts"],"sourcesContent":["/**\n * Minimal ISO-BMFF (MP4/CMAF) box walker.\n *\n * Just enough to locate boxes by nested path — the framework needs a couple of leaf fields (`mdhd` timescale, `tfdt`\n * baseMediaDecodeTime) to derive a segment's decode-time origin, not a full demuxer. DOM-free: operates on an\n * `ArrayBuffer` / `Uint8Array` via `DataView`.\n *\n * Box layout: `[u32 size][u32 type][payload]`. `size === 1` means a `u64 largesize` follows the type (payload after\n * it); `size === 0` means the box runs to the end of its container.\n */\n\n/** A located box: its 4-char type and byte offsets within the buffer. */\nexport interface Box {\n type: string;\n /** Offset of the box's first byte (its size field). */\n start: number;\n /** Offset of the box's payload — after `size` + `type` (+ `largesize`). */\n dataStart: number;\n /** Offset one past the box's last byte. */\n end: number;\n}\n\nexport function toDataView(data: ArrayBuffer | Uint8Array): DataView {\n return data instanceof Uint8Array ? new DataView(data.buffer, data.byteOffset, data.byteLength) : new DataView(data);\n}\n\n/** Read a 4-character box type / FourCC at `offset`. */\nexport function readFourCC(view: DataView, offset: number): string {\n return String.fromCharCode(\n view.getUint8(offset),\n view.getUint8(offset + 1),\n view.getUint8(offset + 2),\n view.getUint8(offset + 3)\n );\n}\n\n/** Iterate the boxes directly contained in `[start, end)`. */\nexport function* iterateBoxes(view: DataView, start = 0, end = view.byteLength): Generator<Box> {\n let offset = start;\n\n while (offset + 8 <= end) {\n let size = view.getUint32(offset);\n const type = readFourCC(view, offset + 4);\n let dataStart = offset + 8;\n\n if (size === 1) {\n size = Number(view.getBigUint64(offset + 8));\n dataStart = offset + 16;\n } else if (size === 0) {\n size = end - offset;\n }\n\n // A size smaller than its own header is malformed — stop rather than loop.\n if (size < dataStart - offset) return;\n\n yield { type, start: offset, dataStart, end: offset + size };\n offset += size;\n }\n}\n\n/** Iterate the direct child boxes of a given `type` within `[start, end)`. */\nexport function* iterateBoxesOfType(view: DataView, type: string, start = 0, end = view.byteLength): Generator<Box> {\n for (const box of iterateBoxes(view, start, end)) {\n if (box.type === type) yield box;\n }\n}\n\n/**\n * Depth-first descent to the first box matching a nested path, e.g. `['moov', 'trak', 'mdia', 'mdhd']`. Returns\n * `undefined` if any level is absent.\n */\nexport function findBox(view: DataView, path: readonly string[], start = 0, end = view.byteLength): Box | undefined {\n const [head, ...rest] = path;\n\n for (const box of iterateBoxes(view, start, end)) {\n if (box.type !== head) continue;\n\n if (rest.length === 0) return box;\n\n const found = findBox(view, rest, box.dataStart, box.end);\n if (found) return found;\n }\n\n return undefined;\n}\n\n/**\n * Read the version byte of a FullBox — the `version(1) + flags(3)` header at the start of the payload of `mdhd` /\n * `tkhd` / `tfdt` / `hdlr` / `elst` / etc.\n */\nexport function readFullBoxVersion(view: DataView, dataStart: number): number {\n return view.getUint8(dataStart);\n}\n"],"mappings":";AAsBA,SAAgB,WAAW,MAA0C;CACnE,OAAO,gBAAgB,aAAa,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,IAAI,IAAI,SAAS,IAAI;AACrH;;AAGA,SAAgB,WAAW,MAAgB,QAAwB;CACjE,OAAO,OAAO,aACZ,KAAK,SAAS,MAAM,GACpB,KAAK,SAAS,SAAS,CAAC,GACxB,KAAK,SAAS,SAAS,CAAC,GACxB,KAAK,SAAS,SAAS,CAAC,CAC1B;AACF;;AAGA,UAAiB,aAAa,MAAgB,QAAQ,GAAG,MAAM,KAAK,YAA4B;CAC9F,IAAI,SAAS;CAEb,OAAO,SAAS,KAAK,KAAK;EACxB,IAAI,OAAO,KAAK,UAAU,MAAM;EAChC,MAAM,OAAO,WAAW,MAAM,SAAS,CAAC;EACxC,IAAI,YAAY,SAAS;EAEzB,IAAI,SAAS,GAAG;GACd,OAAO,OAAO,KAAK,aAAa,SAAS,CAAC,CAAC;GAC3C,YAAY,SAAS;EACvB,OAAO,IAAI,SAAS,GAClB,OAAO,MAAM;EAIf,IAAI,OAAO,YAAY,QAAQ;EAE/B,MAAM;GAAE;GAAM,OAAO;GAAQ;GAAW,KAAK,SAAS;EAAK;EAC3D,UAAU;CACZ;AACF;;AAGA,UAAiB,mBAAmB,MAAgB,MAAc,QAAQ,GAAG,MAAM,KAAK,YAA4B;CAClH,KAAK,MAAM,OAAO,aAAa,MAAM,OAAO,GAAG,GAC7C,IAAI,IAAI,SAAS,MAAM,MAAM;AAEjC;;;;;AAMA,SAAgB,QAAQ,MAAgB,MAAyB,QAAQ,GAAG,MAAM,KAAK,YAA6B;CAClH,MAAM,CAAC,MAAM,GAAG,QAAQ;CAExB,KAAK,MAAM,OAAO,aAAa,MAAM,OAAO,GAAG,GAAG;EAChD,IAAI,IAAI,SAAS,MAAM;EAEvB,IAAI,KAAK,WAAW,GAAG,OAAO;EAE9B,MAAM,QAAQ,QAAQ,MAAM,MAAM,IAAI,WAAW,IAAI,GAAG;EACxD,IAAI,OAAO,OAAO;CACpB;AAGF;;;;;AAMA,SAAgB,mBAAmB,MAAgB,WAA2B;CAC5E,OAAO,KAAK,SAAS,SAAS;AAChC"}
@@ -3,54 +3,43 @@ import { findBox, iterateBoxesOfType, readFourCC, readFullBoxVersion, toDataView
3
3
  /**
4
4
  * Decode-time origin extraction from fMP4/CMAF segments.
5
5
  *
6
- * Non-zero-PTS sources encode media at a non-zero start time (an instant clip
7
- * starting at asset second 60, an Apple bipbop asset starting at 10s, …). To
8
- * relocate such a source onto a 0-based presentation timeline via
9
- * `SourceBuffer.timestampOffset`, the engine needs that start time — the
10
- * **decode-time origin** — read straight from the container:
6
+ * Non-zero-PTS sources encode media at a non-zero start time (an instant clip starting at asset second 60, an Apple
7
+ * bipbop asset starting at 10s, …). To relocate such a source onto a 0-based presentation timeline via
8
+ * `SourceBuffer.timestampOffset`, the engine needs that start time — the **decode-time origin** read straight from
9
+ * the container:
11
10
  *
12
- * - `tfdt.baseMediaDecodeTime` (from a media segment's `moof`) — the decode
13
- * time of the segment's first sample, in the track's media timescale. This is
14
- * a DTS: relocating by `−(baseMediaDecodeTime / timescale)` lands the earliest
15
- * DTS at exactly 0, so a negative-DTS append failure on Chromium is impossible
16
- * by construction.
17
- * - `mdhd.timescale` (from the init segment's `moov`) — ticks per second for
18
- * that track, needed to convert the raw tick count to seconds.
11
+ * - `tfdt.baseMediaDecodeTime` (from a media segment's `moof`) — the decode time of the segment's first sample, in the
12
+ * track's media timescale. This is a DTS: relocating by `−(baseMediaDecodeTime / timescale)` lands the earliest DTS
13
+ * at exactly 0, so a negative-DTS append failure on Chromium is impossible by construction.
14
+ * - `mdhd.timescale` (from the init segment's `moov`) ticks per second for that track, needed to convert the raw tick
15
+ * count to seconds.
19
16
  *
20
17
  * ## Presumptive vs. track-selected reads
21
18
  *
22
- * The two variants share only the leaf field-readers (`mdhd` timescale, `tfdt`
23
- * baseMediaDecodeTime) and the box walker. Everything else differs, and the
24
- * split is deliberate so the presumptive pair is *proportionally* smaller under
19
+ * The two variants share only the leaf field-readers (`mdhd` timescale, `tfdt` baseMediaDecodeTime) and the box walker.
20
+ * Everything else differs, and the split is deliberate so the presumptive pair is _proportionally_ smaller under
25
21
  * tree-shaking:
26
22
  *
27
- * - **Presumptive** — {@link readFirstMediaTimescale} / {@link readFirstBaseMediaDecodeTime}
28
- * read the first `mdhd` timescale and first `tfdt` baseMediaDecodeTime. There's
29
- * no `track_id` (nothing to match against) and no `trak`/`traf` iteration a
30
- * direct `findBox` to the first leaf. Correct when the init/segment holds a
31
- * single media track (the common CMAF case). A caption-free platform imports
32
- * only this pair and tree-shakes away all the matching machinery below.
33
- * - **Track-selected** {@link findMediaTrack} / {@link readBaseMediaDecodeTime}.
34
- * `findMediaTrack` returns `{ trackId, timescale }` for the `trak` whose `hdlr`
35
- * handler matches; `readBaseMediaDecodeTime` takes that `trackId` and reads the
36
- * `traf` whose `tfhd.track_id` matches. The `track_id` is the join that ties one
37
- * track's timescale to the *same* track's baseMediaDecodeTime required when a
38
- * source muxes CEA-608/708 captions (a `clcp` track shares the same `moov` and
39
- * `moof`, each track with its own timescale + baseMediaDecodeTime, so a
40
- * presumptive read there risks `300000 / 6000 = 50s` instead of
41
- * `60000 / 6000 = 10s`). This pair adds `trak`/`traf` iteration plus the handler
42
- * and `track_id` reads. We only ever ask for buffered media handlers
43
- * (`vide` / `soun`); the caption track is never selected — we read the origin,
44
- * not the captions (caption *rendering* is out of scope).
23
+ * - **Presumptive** — {@link readFirstMediaTimescale} / {@link readFirstBaseMediaDecodeTime} read the first `mdhd`
24
+ * timescale and first `tfdt` baseMediaDecodeTime. There's no `track_id` (nothing to match against) and no
25
+ * `trak`/`traf` iteration — a direct `findBox` to the first leaf. Correct when the init/segment holds a single media
26
+ * track (the common CMAF case). A caption-free platform imports only this pair and tree-shakes away all the matching
27
+ * machinery below.
28
+ * - **Track-selected** {@link findMediaTrack} / {@link readBaseMediaDecodeTime}. `findMediaTrack` returns `{ trackId,
29
+ * timescale }` for the `trak` whose `hdlr` handler matches; `readBaseMediaDecodeTime` takes that `trackId` and reads
30
+ * the `traf` whose `tfhd.track_id` matches. The `track_id` is the join that ties one track's timescale to the _same_
31
+ * track's baseMediaDecodeTime required when a source muxes CEA-608/708 captions (a `clcp` track shares the same
32
+ * `moov` and `moof`, each track with its own timescale + baseMediaDecodeTime, so a presumptive read there risks
33
+ * `300000 / 6000 = 50s` instead of `60000 / 6000 = 10s`). This pair adds `trak`/`traf` iteration plus the handler and
34
+ * `track_id` reads. We only ever ask for buffered media handlers (`vide` / `soun`); the caption track is never
35
+ * selected we read the origin, not the captions (caption _rendering_ is out of scope).
45
36
  *
46
- * Both raw values are returned un-divided to leave room for an edit-list (`elst`)
47
- * presentation-time correction term if a source ever carries one — the validated
48
- * streams do not.
37
+ * Both raw values are returned un-divided to leave room for an edit-list (`elst`) presentation-time correction term if
38
+ * a source ever carries one — the validated streams do not.
49
39
  */
50
40
  /**
51
- * The `track_ID` + timescale of the `trak` whose `mdhd` handler matches
52
- * `handlerType`, skipping a muxed `clcp` caption track. `undefined` if no
53
- * matching track exists.
41
+ * The `track_ID` + timescale of the `trak` whose `mdhd` handler matches `handlerType`, skipping a muxed `clcp` caption
42
+ * track. `undefined` if no matching track exists.
54
43
  */
55
44
  function findMediaTrack(initSegment, handlerType) {
56
45
  const view = toDataView(initSegment);
@@ -68,9 +57,8 @@ function findMediaTrack(initSegment, handlerType) {
68
57
  }
69
58
  }
70
59
  /**
71
- * `baseMediaDecodeTime` (in the track's media timescale) from the `traf` matching
72
- * `trackId` (via `tfhd.track_id`) — required for muxed multi-`traf` segments.
73
- * `undefined` if no matching `tfdt` exists.
60
+ * `baseMediaDecodeTime` (in the track's media timescale) from the `traf` matching `trackId` (via `tfhd.track_id`) —
61
+ * required for muxed multi-`traf` segments. `undefined` if no matching `tfdt` exists.
74
62
  */
75
63
  function readBaseMediaDecodeTime(mediaSegment, trackId) {
76
64
  const view = toDataView(mediaSegment);
@@ -1 +1 @@
1
- {"version":3,"file":"timestamp-origin.js","names":[],"sources":["../../../../src/media/mp4/timestamp-origin.ts"],"sourcesContent":["/**\n * Decode-time origin extraction from fMP4/CMAF segments.\n *\n * Non-zero-PTS sources encode media at a non-zero start time (an instant clip\n * starting at asset second 60, an Apple bipbop asset starting at 10s, …). To\n * relocate such a source onto a 0-based presentation timeline via\n * `SourceBuffer.timestampOffset`, the engine needs that start time — the\n * **decode-time origin** — read straight from the container:\n *\n * - `tfdt.baseMediaDecodeTime` (from a media segment's `moof`) — the decode\n * time of the segment's first sample, in the track's media timescale. This is\n * a DTS: relocating by `−(baseMediaDecodeTime / timescale)` lands the earliest\n * DTS at exactly 0, so a negative-DTS append failure on Chromium is impossible\n * by construction.\n * - `mdhd.timescale` (from the init segment's `moov`) — ticks per second for\n * that track, needed to convert the raw tick count to seconds.\n *\n * ## Presumptive vs. track-selected reads\n *\n * The two variants share only the leaf field-readers (`mdhd` timescale, `tfdt`\n * baseMediaDecodeTime) and the box walker. Everything else differs, and the\n * split is deliberate so the presumptive pair is *proportionally* smaller under\n * tree-shaking:\n *\n * - **Presumptive** — {@link readFirstMediaTimescale} / {@link readFirstBaseMediaDecodeTime}\n * read the first `mdhd` timescale and first `tfdt` baseMediaDecodeTime. There's\n * no `track_id` (nothing to match against) and no `trak`/`traf` iteration — a\n * direct `findBox` to the first leaf. Correct when the init/segment holds a\n * single media track (the common CMAF case). A caption-free platform imports\n * only this pair and tree-shakes away all the matching machinery below.\n * - **Track-selected** — {@link findMediaTrack} / {@link readBaseMediaDecodeTime}.\n * `findMediaTrack` returns `{ trackId, timescale }` for the `trak` whose `hdlr`\n * handler matches; `readBaseMediaDecodeTime` takes that `trackId` and reads the\n * `traf` whose `tfhd.track_id` matches. The `track_id` is the join that ties one\n * track's timescale to the *same* track's baseMediaDecodeTime — required when a\n * source muxes CEA-608/708 captions (a `clcp` track shares the same `moov` and\n * `moof`, each track with its own timescale + baseMediaDecodeTime, so a\n * presumptive read there risks `300000 / 6000 = 50s` instead of\n * `60000 / 6000 = 10s`). This pair adds `trak`/`traf` iteration plus the handler\n * and `track_id` reads. We only ever ask for buffered media handlers\n * (`vide` / `soun`); the caption track is never selected — we read the origin,\n * not the captions (caption *rendering* is out of scope).\n *\n * Both raw values are returned un-divided to leave room for an edit-list (`elst`)\n * presentation-time correction term if a source ever carries one — the validated\n * streams do not.\n */\nimport { type Box, findBox, iterateBoxesOfType, readFourCC, readFullBoxVersion, toDataView } from './box';\n\n/** MSE-buffered media handler types (`mdhd`/`hdlr`). Captions/subtitles excluded. */\nexport type MediaHandlerType = 'vide' | 'soun';\n\nexport interface MediaTrackInfo {\n /** `tkhd.track_id` — used to match the corresponding `traf` in media segments. */\n trackId: number;\n /** `mdhd.timescale` — ticks per second for this track. */\n timescale: number;\n}\n\n// --- presumptive: first leaf, no track_id, no iteration -----------------------\n\n/**\n * Presumptive: the `timescale` of the **first** `mdhd` in an init segment.\n * Correct only for single-media-track inits for muxed captions use\n * {@link findMediaTrack}. `undefined` if no `mdhd` exists.\n */\nexport function readFirstMediaTimescale(initSegment: ArrayBuffer | Uint8Array): number | undefined {\n const view = toDataView(initSegment);\n const mdhd = findBox(view, ['moov', 'trak', 'mdia', 'mdhd']);\n return mdhd ? readMdhdTimescale(view, mdhd) : undefined;\n}\n\n/**\n * Presumptive: `baseMediaDecodeTime` from the **first** `tfdt` of a media\n * segment. Correct only for single-`traf` segments — for muxed captions use\n * {@link readBaseMediaDecodeTime}. `undefined` if no `tfdt` exists.\n */\nexport function readFirstBaseMediaDecodeTime(mediaSegment: ArrayBuffer | Uint8Array): number | undefined {\n const view = toDataView(mediaSegment);\n const tfdt = findBox(view, ['moof', 'traf', 'tfdt']);\n return tfdt ? readTfdtBaseMediaDecodeTime(view, tfdt) : undefined;\n}\n\n// --- track-selected: iterate + match by handler / track_id --------------------\n\n/**\n * The `track_ID` + timescale of the `trak` whose `mdhd` handler matches\n * `handlerType`, skipping a muxed `clcp` caption track. `undefined` if no\n * matching track exists.\n */\nexport function findMediaTrack(\n initSegment: ArrayBuffer | Uint8Array,\n handlerType: MediaHandlerType\n): MediaTrackInfo | undefined {\n const view = toDataView(initSegment);\n const moov = findBox(view, ['moov']);\n if (!moov) return undefined;\n\n for (const trak of iterateBoxesOfType(view, 'trak', moov.dataStart, moov.end)) {\n if (readTrakHandler(view, trak) !== handlerType) continue;\n const tkhd = findBox(view, ['tkhd'], trak.dataStart, trak.end);\n const mdhd = findBox(view, ['mdia', 'mdhd'], trak.dataStart, trak.end);\n if (!tkhd || !mdhd) return undefined;\n // tkhd FullBox: version(1)+flags(3), creation/modification dates (v0: 4+4, v1:\n // 8+8), then track_id.\n const trackId = view.getUint32(tkhd.dataStart + 4 + (readFullBoxVersion(view, tkhd.dataStart) === 1 ? 16 : 8));\n return { trackId, timescale: readMdhdTimescale(view, mdhd) };\n }\n return undefined;\n}\n\n/**\n * `baseMediaDecodeTime` (in the track's media timescale) from the `traf` matching\n * `trackId` (via `tfhd.track_id`) required for muxed multi-`traf` segments.\n * `undefined` if no matching `tfdt` exists.\n */\nexport function readBaseMediaDecodeTime(mediaSegment: ArrayBuffer | Uint8Array, trackId: number): number | undefined {\n const view = toDataView(mediaSegment);\n const moof = findBox(view, ['moof']);\n if (!moof) return undefined;\n\n for (const traf of iterateBoxesOfType(view, 'traf', moof.dataStart, moof.end)) {\n if (readTrafTrackId(view, traf) !== trackId) continue;\n const tfdt = findBox(view, ['tfdt'], traf.dataStart, traf.end);\n return tfdt ? readTfdtBaseMediaDecodeTime(view, tfdt) : undefined;\n }\n return undefined;\n}\n\n// --- shared leaf field-readers ------------------------------------------------\n\n/** `mdhd.timescale`: FullBox version(1)+flags(3) + dates (v0: 4+4, v1: 8+8) + timescale. */\nfunction readMdhdTimescale(view: DataView, mdhd: Box): number {\n return view.getUint32(mdhd.dataStart + 4 + (readFullBoxVersion(view, mdhd.dataStart) === 1 ? 16 : 8));\n}\n\n/** `tfdt.baseMediaDecodeTime`: FullBox, then the value — v0: (4), v1: (8). */\nfunction readTfdtBaseMediaDecodeTime(view: DataView, tfdt: Box): number {\n const at = tfdt.dataStart + 4;\n return readFullBoxVersion(view, tfdt.dataStart) === 1 ? Number(view.getBigUint64(at)) : view.getUint32(at);\n}\n\n// --- track-selection readers (referenced only by the track-selected variants) -\n\n/** `hdlr.handler_type` for a `trak`: FullBox version(1)+flags(3) + pre_defined(4) + handler_type(4). */\nfunction readTrakHandler(view: DataView, trak: Box): string | undefined {\n const hdlr = findBox(view, ['mdia', 'hdlr'], trak.dataStart, trak.end);\n return hdlr ? readFourCC(view, hdlr.dataStart + 8) : undefined;\n}\n\n/** `tfhd.track_id` for a `traf`: FullBox version(1)+flags(3) + track_id(4). */\nfunction readTrafTrackId(view: DataView, traf: Box): number | undefined {\n const tfhd = findBox(view, ['tfhd'], traf.dataStart, traf.end);\n return tfhd ? view.getUint32(tfhd.dataStart + 4) : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0FA,SAAgB,eACd,aACA,aAC4B;CAC5B,MAAM,OAAO,WAAW,WAAW;CACnC,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,CAAC;CACnC,IAAI,CAAC,MAAM,OAAO,KAAA;CAElB,KAAK,MAAM,QAAQ,mBAAmB,MAAM,QAAQ,KAAK,WAAW,KAAK,GAAG,GAAG;EAC7E,IAAI,gBAAgB,MAAM,IAAI,MAAM,aAAa;EACjD,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;EAC7D,MAAM,OAAO,QAAQ,MAAM,CAAC,QAAQ,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;EACrE,IAAI,CAAC,QAAQ,CAAC,MAAM,OAAO,KAAA;EAI3B,OAAO;GAAE,SADO,KAAK,UAAU,KAAK,YAAY,KAAK,mBAAmB,MAAM,KAAK,SAAS,MAAM,IAAI,KAAK,EAC5F;GAAG,WAAW,kBAAkB,MAAM,IAAI;EAAE;CAC7D;AAEF;;;;;;AAOA,SAAgB,wBAAwB,cAAwC,SAAqC;CACnH,MAAM,OAAO,WAAW,YAAY;CACpC,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,CAAC;CACnC,IAAI,CAAC,MAAM,OAAO,KAAA;CAElB,KAAK,MAAM,QAAQ,mBAAmB,MAAM,QAAQ,KAAK,WAAW,KAAK,GAAG,GAAG;EAC7E,IAAI,gBAAgB,MAAM,IAAI,MAAM,SAAS;EAC7C,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;EAC7D,OAAO,OAAO,4BAA4B,MAAM,IAAI,IAAI,KAAA;CAC1D;AAEF;;AAKA,SAAS,kBAAkB,MAAgB,MAAmB;CAC5D,OAAO,KAAK,UAAU,KAAK,YAAY,KAAK,mBAAmB,MAAM,KAAK,SAAS,MAAM,IAAI,KAAK,EAAE;AACtG;;AAGA,SAAS,4BAA4B,MAAgB,MAAmB;CACtE,MAAM,KAAK,KAAK,YAAY;CAC5B,OAAO,mBAAmB,MAAM,KAAK,SAAS,MAAM,IAAI,OAAO,KAAK,aAAa,EAAE,CAAC,IAAI,KAAK,UAAU,EAAE;AAC3G;;AAKA,SAAS,gBAAgB,MAAgB,MAA+B;CACtE,MAAM,OAAO,QAAQ,MAAM,CAAC,QAAQ,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;CACrE,OAAO,OAAO,WAAW,MAAM,KAAK,YAAY,CAAC,IAAI,KAAA;AACvD;;AAGA,SAAS,gBAAgB,MAAgB,MAA+B;CACtE,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;CAC7D,OAAO,OAAO,KAAK,UAAU,KAAK,YAAY,CAAC,IAAI,KAAA;AACrD"}
1
+ {"version":3,"file":"timestamp-origin.js","names":[],"sources":["../../../../src/media/mp4/timestamp-origin.ts"],"sourcesContent":["/**\n * Decode-time origin extraction from fMP4/CMAF segments.\n *\n * Non-zero-PTS sources encode media at a non-zero start time (an instant clip starting at asset second 60, an Apple\n * bipbop asset starting at 10s, …). To relocate such a source onto a 0-based presentation timeline via\n * `SourceBuffer.timestampOffset`, the engine needs that start time — the **decode-time origin** — read straight from\n * the container:\n *\n * - `tfdt.baseMediaDecodeTime` (from a media segment's `moof`) — the decode time of the segment's first sample, in the\n * track's media timescale. This is a DTS: relocating by `−(baseMediaDecodeTime / timescale)` lands the earliest DTS\n * at exactly 0, so a negative-DTS append failure on Chromium is impossible by construction.\n * - `mdhd.timescale` (from the init segment's `moov`) — ticks per second for that track, needed to convert the raw tick\n * count to seconds.\n *\n * ## Presumptive vs. track-selected reads\n *\n * The two variants share only the leaf field-readers (`mdhd` timescale, `tfdt` baseMediaDecodeTime) and the box walker.\n * Everything else differs, and the split is deliberate so the presumptive pair is _proportionally_ smaller under\n * tree-shaking:\n *\n * - **Presumptive** — {@link readFirstMediaTimescale} / {@link readFirstBaseMediaDecodeTime} read the first `mdhd`\n * timescale and first `tfdt` baseMediaDecodeTime. There's no `track_id` (nothing to match against) and no\n * `trak`/`traf` iteration — a direct `findBox` to the first leaf. Correct when the init/segment holds a single media\n * track (the common CMAF case). A caption-free platform imports only this pair and tree-shakes away all the matching\n * machinery below.\n * - **Track-selected** — {@link findMediaTrack} / {@link readBaseMediaDecodeTime}. `findMediaTrack` returns `{ trackId,\n * timescale }` for the `trak` whose `hdlr` handler matches; `readBaseMediaDecodeTime` takes that `trackId` and reads\n * the `traf` whose `tfhd.track_id` matches. The `track_id` is the join that ties one track's timescale to the _same_\n * track's baseMediaDecodeTime — required when a source muxes CEA-608/708 captions (a `clcp` track shares the same\n * `moov` and `moof`, each track with its own timescale + baseMediaDecodeTime, so a presumptive read there risks\n * `300000 / 6000 = 50s` instead of `60000 / 6000 = 10s`). This pair adds `trak`/`traf` iteration plus the handler and\n * `track_id` reads. We only ever ask for buffered media handlers (`vide` / `soun`); the caption track is never\n * selected — we read the origin, not the captions (caption _rendering_ is out of scope).\n *\n * Both raw values are returned un-divided to leave room for an edit-list (`elst`) presentation-time correction term if\n * a source ever carries one — the validated streams do not.\n */\nimport { type Box, findBox, iterateBoxesOfType, readFourCC, readFullBoxVersion, toDataView } from './box';\n\n/** MSE-buffered media handler types (`mdhd`/`hdlr`). Captions/subtitles excluded. */\nexport type MediaHandlerType = 'vide' | 'soun';\n\nexport interface MediaTrackInfo {\n /** `tkhd.track_id` — used to match the corresponding `traf` in media segments. */\n trackId: number;\n /** `mdhd.timescale` — ticks per second for this track. */\n timescale: number;\n}\n\n// --- presumptive: first leaf, no track_id, no iteration -----------------------\n\n/**\n * Presumptive: the `timescale` of the **first** `mdhd` in an init segment. Correct only for single-media-track inits —\n * for muxed captions use {@link findMediaTrack}. `undefined` if no `mdhd` exists.\n */\nexport function readFirstMediaTimescale(initSegment: ArrayBuffer | Uint8Array): number | undefined {\n const view = toDataView(initSegment);\n const mdhd = findBox(view, ['moov', 'trak', 'mdia', 'mdhd']);\n\n return mdhd ? readMdhdTimescale(view, mdhd) : undefined;\n}\n\n/**\n * Presumptive: `baseMediaDecodeTime` from the **first** `tfdt` of a media segment. Correct only for single-`traf`\n * segments — for muxed captions use {@link readBaseMediaDecodeTime}. `undefined` if no `tfdt` exists.\n */\nexport function readFirstBaseMediaDecodeTime(mediaSegment: ArrayBuffer | Uint8Array): number | undefined {\n const view = toDataView(mediaSegment);\n const tfdt = findBox(view, ['moof', 'traf', 'tfdt']);\n\n return tfdt ? readTfdtBaseMediaDecodeTime(view, tfdt) : undefined;\n}\n\n// --- track-selected: iterate + match by handler / track_id --------------------\n\n/**\n * The `track_ID` + timescale of the `trak` whose `mdhd` handler matches `handlerType`, skipping a muxed `clcp` caption\n * track. `undefined` if no matching track exists.\n */\nexport function findMediaTrack(\n initSegment: ArrayBuffer | Uint8Array,\n handlerType: MediaHandlerType\n): MediaTrackInfo | undefined {\n const view = toDataView(initSegment);\n const moov = findBox(view, ['moov']);\n if (!moov) return undefined;\n\n for (const trak of iterateBoxesOfType(view, 'trak', moov.dataStart, moov.end)) {\n if (readTrakHandler(view, trak) !== handlerType) continue;\n\n const tkhd = findBox(view, ['tkhd'], trak.dataStart, trak.end);\n const mdhd = findBox(view, ['mdia', 'mdhd'], trak.dataStart, trak.end);\n if (!tkhd || !mdhd) return undefined;\n\n // tkhd FullBox: version(1)+flags(3), creation/modification dates (v0: 4+4, v1:\n // 8+8), then track_id.\n const trackId = view.getUint32(tkhd.dataStart + 4 + (readFullBoxVersion(view, tkhd.dataStart) === 1 ? 16 : 8));\n\n return { trackId, timescale: readMdhdTimescale(view, mdhd) };\n }\n\n return undefined;\n}\n\n/**\n * `baseMediaDecodeTime` (in the track's media timescale) from the `traf` matching `trackId` (via `tfhd.track_id`) —\n * required for muxed multi-`traf` segments. `undefined` if no matching `tfdt` exists.\n */\nexport function readBaseMediaDecodeTime(mediaSegment: ArrayBuffer | Uint8Array, trackId: number): number | undefined {\n const view = toDataView(mediaSegment);\n const moof = findBox(view, ['moof']);\n if (!moof) return undefined;\n\n for (const traf of iterateBoxesOfType(view, 'traf', moof.dataStart, moof.end)) {\n if (readTrafTrackId(view, traf) !== trackId) continue;\n\n const tfdt = findBox(view, ['tfdt'], traf.dataStart, traf.end);\n\n return tfdt ? readTfdtBaseMediaDecodeTime(view, tfdt) : undefined;\n }\n\n return undefined;\n}\n\n// --- shared leaf field-readers ------------------------------------------------\n\n/** `mdhd.timescale`: FullBox version(1)+flags(3) + dates (v0: 4+4, v1: 8+8) + timescale. */\nfunction readMdhdTimescale(view: DataView, mdhd: Box): number {\n return view.getUint32(mdhd.dataStart + 4 + (readFullBoxVersion(view, mdhd.dataStart) === 1 ? 16 : 8));\n}\n\n/** `tfdt.baseMediaDecodeTime`: FullBox, then the value — v0: (4), v1: (8). */\nfunction readTfdtBaseMediaDecodeTime(view: DataView, tfdt: Box): number {\n const at = tfdt.dataStart + 4;\n\n return readFullBoxVersion(view, tfdt.dataStart) === 1 ? Number(view.getBigUint64(at)) : view.getUint32(at);\n}\n\n// --- track-selection readers (referenced only by the track-selected variants) -\n\n/** `hdlr.handler_type` for a `trak`: FullBox version(1)+flags(3) + pre_defined(4) + handler_type(4). */\nfunction readTrakHandler(view: DataView, trak: Box): string | undefined {\n const hdlr = findBox(view, ['mdia', 'hdlr'], trak.dataStart, trak.end);\n\n return hdlr ? readFourCC(view, hdlr.dataStart + 8) : undefined;\n}\n\n/** `tfhd.track_id` for a `traf`: FullBox version(1)+flags(3) + track_id(4). */\nfunction readTrafTrackId(view: DataView, traf: Box): number | undefined {\n const tfhd = findBox(view, ['tfhd'], traf.dataStart, traf.end);\n\n return tfhd ? view.getUint32(tfhd.dataStart + 4) : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+EA,SAAgB,eACd,aACA,aAC4B;CAC5B,MAAM,OAAO,WAAW,WAAW;CACnC,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,CAAC;CACnC,IAAI,CAAC,MAAM,OAAO,KAAA;CAElB,KAAK,MAAM,QAAQ,mBAAmB,MAAM,QAAQ,KAAK,WAAW,KAAK,GAAG,GAAG;EAC7E,IAAI,gBAAgB,MAAM,IAAI,MAAM,aAAa;EAEjD,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;EAC7D,MAAM,OAAO,QAAQ,MAAM,CAAC,QAAQ,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;EACrE,IAAI,CAAC,QAAQ,CAAC,MAAM,OAAO,KAAA;EAM3B,OAAO;GAAE,SAFO,KAAK,UAAU,KAAK,YAAY,KAAK,mBAAmB,MAAM,KAAK,SAAS,MAAM,IAAI,KAAK,EAE5F;GAAG,WAAW,kBAAkB,MAAM,IAAI;EAAE;CAC7D;AAGF;;;;;AAMA,SAAgB,wBAAwB,cAAwC,SAAqC;CACnH,MAAM,OAAO,WAAW,YAAY;CACpC,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,CAAC;CACnC,IAAI,CAAC,MAAM,OAAO,KAAA;CAElB,KAAK,MAAM,QAAQ,mBAAmB,MAAM,QAAQ,KAAK,WAAW,KAAK,GAAG,GAAG;EAC7E,IAAI,gBAAgB,MAAM,IAAI,MAAM,SAAS;EAE7C,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;EAE7D,OAAO,OAAO,4BAA4B,MAAM,IAAI,IAAI,KAAA;CAC1D;AAGF;;AAKA,SAAS,kBAAkB,MAAgB,MAAmB;CAC5D,OAAO,KAAK,UAAU,KAAK,YAAY,KAAK,mBAAmB,MAAM,KAAK,SAAS,MAAM,IAAI,KAAK,EAAE;AACtG;;AAGA,SAAS,4BAA4B,MAAgB,MAAmB;CACtE,MAAM,KAAK,KAAK,YAAY;CAE5B,OAAO,mBAAmB,MAAM,KAAK,SAAS,MAAM,IAAI,OAAO,KAAK,aAAa,EAAE,CAAC,IAAI,KAAK,UAAU,EAAE;AAC3G;;AAKA,SAAS,gBAAgB,MAAgB,MAA+B;CACtE,MAAM,OAAO,QAAQ,MAAM,CAAC,QAAQ,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;CAErE,OAAO,OAAO,WAAW,MAAM,KAAK,YAAY,CAAC,IAAI,KAAA;AACvD;;AAGA,SAAS,gBAAgB,MAAgB,MAA+B;CACtE,MAAM,OAAO,QAAQ,MAAM,CAAC,MAAM,GAAG,KAAK,WAAW,KAAK,GAAG;CAE7D,OAAO,OAAO,KAAK,UAAU,KAAK,YAAY,CAAC,IAAI,KAAA;AACrD"}
@@ -2,18 +2,16 @@
2
2
  /**
3
3
  * Pixel dimensions, and the one projection every reader of them needs.
4
4
  *
5
- * Shared by the surfaces a rendition cap measures — a screen (`media/dom/screen`),
6
- * a player element (`behaviors/dom/track-player-resolution`) — and by the caps
7
- * that compare renditions against them. Lives outside the DOM layer because
8
- * scaling and rounding two numbers needs no DOM, which is also what lets the
9
- * DOM-free selection rules name the type they read instead of restating its shape.
5
+ * Shared by the surfaces a rendition cap measures — a screen (`media/dom/screen`), a player element
6
+ * (`behaviors/dom/track-player-resolution`) — and by the caps that compare renditions against them. Lives outside the
7
+ * DOM layer because scaling and rounding two numbers needs no DOM, which is also what lets the DOM-free selection rules
8
+ * name the type they read instead of restating its shape.
10
9
  */
11
10
  /**
12
11
  * A surface's pixel dimensions.
13
12
  *
14
- * A width and a height rather than a `"720p"`-style tier, because a tier only
15
- * describes a surface once you assume its aspect ratio the assumption that
16
- * mis-measures an anamorphic or otherwise non-16:9 rendition.
13
+ * A width and a height rather than a `"720p"`-style tier, because a tier only describes a surface once you assume its
14
+ * aspect ratio the assumption that mis-measures an anamorphic or otherwise non-16:9 rendition.
17
15
  */
18
16
  interface Resolution {
19
17
  readonly width: number;
@@ -1 +1 @@
1
- {"version":3,"file":"resolution.d.ts","names":[],"sources":["../../../../src/media/primitives/resolution.ts"],"mappings":";;;;;;;;;;;;;;;;;UAiBiB;WACN;WACA"}
1
+ {"version":3,"file":"resolution.d.ts","names":[],"sources":["../../../../src/media/primitives/resolution.ts"],"mappings":";;;;;;;;;;;;;;;UAeiB;WACN;WACA"}
@@ -1,14 +1,11 @@
1
1
  //#region src/media/primitives/resolution.ts
2
2
  /**
3
- * Apply `scale` to a size and normalize it to whole pixels, or `undefined` where
4
- * that leaves nothing to describe.
3
+ * Apply `scale` to a size and normalize it to whole pixels, or `undefined` where that leaves nothing to describe.
5
4
  *
6
- * Rounded because pixels are whole and a fractional scale doesn't divide a
7
- * surface evenly. A non-positive or non-finite axis yields `undefined` rather
8
- * than a zero-area reading: an element that isn't being rendered reports `0 × 0`
9
- * and a nonsense dimension reports `NaN`, and the caps consuming this read
10
- * absence as "unknown, don't cap" while an area of zero would read as a cap of
11
- * zero — pinning every source to its smallest rendition.
5
+ * Rounded because pixels are whole and a fractional scale doesn't divide a surface evenly. A non-positive or non-finite
6
+ * axis yields `undefined` rather than a zero-area reading: an element that isn't being rendered reports `0 × 0` and a
7
+ * nonsense dimension reports `NaN`, and the caps consuming this read absence as "unknown, don't cap" while an area of
8
+ * zero would read as a cap of zero pinning every source to its smallest rendition.
12
9
  *
13
10
  * @param size - Dimensions to project, in the units `scale` converts from
14
11
  * @param scale - Multiplier for both axes, e.g. `devicePixelRatio`; defaults to 1
@@ -1 +1 @@
1
- {"version":3,"file":"resolution.js","names":[],"sources":["../../../../src/media/primitives/resolution.ts"],"sourcesContent":["/**\n * Pixel dimensions, and the one projection every reader of them needs.\n *\n * Shared by the surfaces a rendition cap measures — a screen (`media/dom/screen`),\n * a player element (`behaviors/dom/track-player-resolution`) — and by the caps\n * that compare renditions against them. Lives outside the DOM layer because\n * scaling and rounding two numbers needs no DOM, which is also what lets the\n * DOM-free selection rules name the type they read instead of restating its shape.\n */\n\n/**\n * A surface's pixel dimensions.\n *\n * A width and a height rather than a `\"720p\"`-style tier, because a tier only\n * describes a surface once you assume its aspect ratio — the assumption that\n * mis-measures an anamorphic or otherwise non-16:9 rendition.\n */\nexport interface Resolution {\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * Apply `scale` to a size and normalize it to whole pixels, or `undefined` where\n * that leaves nothing to describe.\n *\n * Rounded because pixels are whole and a fractional scale doesn't divide a\n * surface evenly. A non-positive or non-finite axis yields `undefined` rather\n * than a zero-area reading: an element that isn't being rendered reports `0 × 0`\n * and a nonsense dimension reports `NaN`, and the caps consuming this read\n * absence as \"unknown, don't cap\" while an area of zero would read as a cap of\n * zero — pinning every source to its smallest rendition.\n *\n * @param size - Dimensions to project, in the units `scale` converts from\n * @param scale - Multiplier for both axes, e.g. `devicePixelRatio`; defaults to 1\n * @returns The scaled, whole-pixel resolution, or `undefined` when either axis\n * doesn't survive it\n */\nexport function scaleResolution(size: Resolution, scale = 1): Resolution | undefined {\n const width = Math.round(size.width * scale);\n const height = Math.round(size.height * scale);\n\n return width > 0 && height > 0 ? { width, height } : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAsCA,SAAgB,gBAAgB,MAAkB,QAAQ,GAA2B;CACnF,MAAM,QAAQ,KAAK,MAAM,KAAK,QAAQ,KAAK;CAC3C,MAAM,SAAS,KAAK,MAAM,KAAK,SAAS,KAAK;CAE7C,OAAO,QAAQ,KAAK,SAAS,IAAI;EAAE;EAAO;CAAO,IAAI,KAAA;AACvD"}
1
+ {"version":3,"file":"resolution.js","names":[],"sources":["../../../../src/media/primitives/resolution.ts"],"sourcesContent":["/**\n * Pixel dimensions, and the one projection every reader of them needs.\n *\n * Shared by the surfaces a rendition cap measures — a screen (`media/dom/screen`), a player element\n * (`behaviors/dom/track-player-resolution`) — and by the caps that compare renditions against them. Lives outside the\n * DOM layer because scaling and rounding two numbers needs no DOM, which is also what lets the DOM-free selection rules\n * name the type they read instead of restating its shape.\n */\n\n/**\n * A surface's pixel dimensions.\n *\n * A width and a height rather than a `\"720p\"`-style tier, because a tier only describes a surface once you assume its\n * aspect ratio — the assumption that mis-measures an anamorphic or otherwise non-16:9 rendition.\n */\nexport interface Resolution {\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * Apply `scale` to a size and normalize it to whole pixels, or `undefined` where that leaves nothing to describe.\n *\n * Rounded because pixels are whole and a fractional scale doesn't divide a surface evenly. A non-positive or non-finite\n * axis yields `undefined` rather than a zero-area reading: an element that isn't being rendered reports `0 × 0` and a\n * nonsense dimension reports `NaN`, and the caps consuming this read absence as \"unknown, don't cap\" while an area of\n * zero would read as a cap of zero — pinning every source to its smallest rendition.\n *\n * @param size - Dimensions to project, in the units `scale` converts from\n * @param scale - Multiplier for both axes, e.g. `devicePixelRatio`; defaults to 1\n * @returns The scaled, whole-pixel resolution, or `undefined` when either axis\n * doesn't survive it\n */\nexport function scaleResolution(size: Resolution, scale = 1): Resolution | undefined {\n const width = Math.round(size.width * scale);\n const height = Math.round(size.height * scale);\n\n return width > 0 && height > 0 ? { width, height } : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;AAiCA,SAAgB,gBAAgB,MAAkB,QAAQ,GAA2B;CACnF,MAAM,QAAQ,KAAK,MAAM,KAAK,QAAQ,KAAK;CAC3C,MAAM,SAAS,KAAK,MAAM,KAAK,SAAS,KAAK;CAE7C,OAAO,QAAQ,KAAK,SAAS,IAAI;EAAE;EAAO;CAAO,IAAI,KAAA;AACvD"}
@@ -1,9 +1,8 @@
1
1
  //#region src/media/primitives/select-tracks.ts
2
2
  /**
3
- * Test whether a track matches a partial-track description: every present,
4
- * defined field of `filter` equals the track's. Absent or `undefined` filter
5
- * fields don't constrain. Used to narrow candidates by a user selection
6
- * (`{ id }`, `{ language }`, `{ height }`, …).
3
+ * Test whether a track matches a partial-track description: every present, defined field of `filter` equals the
4
+ * track's. Absent or `undefined` filter fields don't constrain. Used to narrow candidates by a user selection (`{ id
5
+ * }`, `{ language }`, `{ height }`, …).
7
6
  *
8
7
  * @param track - The track to test
9
8
  * @param filter - Partial-track description; only present, defined fields constrain
@@ -21,51 +20,44 @@ function pixelArea(track) {
21
20
  return (track.width ?? 0) * (track.height ?? 0);
22
21
  }
23
22
  /**
24
- * Narrow to the tracks at or below `maxPixelArea`, and nothing else: no ordering,
25
- * no fallback. Survivors keep their incoming order, and an empty result is a real
26
- * answer — "none of these fit".
23
+ * Narrow to the tracks at or below `maxPixelArea`, and nothing else: no ordering, no fallback. Survivors keep their
24
+ * incoming order, and an empty result is a real answer — "none of these fit".
27
25
  *
28
- * Deliberately only the filter, because as a selection rule this composes under
29
- * `applyRules`, which already owns both halves a caller might expect here: an empty
30
- * result is skipped, so a preference can never narrow the candidate set to nothing;
31
- * and ordering the survivors is a separate rule's job
32
- * ({@link byDescendingResolution}, bandwidth ABR). Doing either here would duplicate
33
- * the composer and give one rule two responsibilities.
26
+ * Deliberately only the filter, because as a selection rule this composes under `applyRules`, which already owns both
27
+ * halves a caller might expect here: an empty result is skipped, so a preference can never narrow the candidate set to
28
+ * nothing; and ordering the survivors is a separate rule's job ({@link byDescendingResolution}, bandwidth ABR). Doing
29
+ * either here would duplicate the composer and give one rule two responsibilities.
34
30
  */
35
31
  function tracksUnderPixelArea(tracks, maxPixelArea = Number.POSITIVE_INFINITY) {
36
32
  return tracks.filter((track) => pixelArea(track) <= maxPixelArea);
37
33
  }
38
34
  /**
39
- * The smallest track area that still covers `minPixelArea`, or `undefined` when
40
- * no track reaches it.
35
+ * The smallest track area that still covers `minPixelArea`, or `undefined` when no track reaches it.
41
36
  *
42
- * The cap a surface-size rule wants when it should round *up* to the ladder: a
43
- * surface between two tiers is covered by the upper one, and capping at the
44
- * surface's own area instead would serve a picture smaller than the surface and
37
+ * The cap a surface-size rule wants when it should round _up_ to the ladder: a surface between two tiers is covered by
38
+ * the upper one, and capping at the surface's own area instead would serve a picture smaller than the surface and
45
39
  * upscale it.
46
40
  *
47
- * Tracks declaring no dimensions compare as area `0` and so never cover anything,
48
- * which keeps them out of the cap rather than pinning it to zero.
41
+ * Tracks declaring no dimensions compare as area `0` and so never cover anything, which keeps them out of the cap
42
+ * rather than pinning it to zero.
49
43
  */
50
44
  function smallestCoveringPixelArea(tracks, minPixelArea) {
51
45
  const covering = tracks.map(pixelArea).filter((area) => area >= minPixelArea);
52
46
  return covering.length ? Math.min(...covering) : void 0;
53
47
  }
54
48
  /**
55
- * Compare two tracks by resolution, largest first, with bandwidth as the tiebreak
56
- * for renditions of identical dimensions. Missing dimensions are treated as area
57
- * `0`, so a track without them sorts last.
49
+ * Compare two tracks by resolution, largest first, with bandwidth as the tiebreak for renditions of identical
50
+ * dimensions. Missing dimensions are treated as area `0`, so a track without them sorts last.
58
51
  *
59
- * A comparator rather than a "highest track" function: the selection-rule chain
60
- * takes the head of the list it produces, so ranking never has to collapse to a
61
- * single track. `preferHighestResolution` is `sort` over this and nothing more.
52
+ * A comparator rather than a "highest track" function: the selection-rule chain takes the head of the list it produces,
53
+ * so ranking never has to collapse to a single track. `preferHighestResolution` is `sort` over this and nothing more.
62
54
  */
63
55
  function byDescendingResolution(a, b) {
64
56
  return pixelArea(b) - pixelArea(a) || (b.bandwidth ?? 0) - (a.bandwidth ?? 0);
65
57
  }
66
58
  /**
67
- * Default audio policy over a candidate list: the three-tier pick a selection-rule
68
- * chain applies once it has narrowed the candidates.
59
+ * Default audio policy over a candidate list: the three-tier pick a selection-rule chain applies once it has narrowed
60
+ * the candidates.
69
61
  *
70
62
  * Priority: `preferredAudioLanguage` match → `DEFAULT=YES` → first track.
71
63
  */
@@ -79,13 +71,11 @@ function pickAudioTrackFromTracks(tracks, config) {
79
71
  return tracks[0]?.id;
80
72
  }
81
73
  /**
82
- * Default text-track policy over a candidate list: the opt-in three-tier pick
83
- * `switchTextTrack`'s terminal applies once it has narrowed the renditions to the
84
- * constrained, CDN-scoped set.
74
+ * Default text-track policy over a candidate list: the opt-in three-tier pick `switchTextTrack`'s terminal applies once
75
+ * it has narrowed the renditions to the constrained, CDN-scoped set.
85
76
  *
86
- * Priority: `preferredSubtitleLanguage` match → `DEFAULT=YES + AUTOSELECT=YES`
87
- * (only when `enableDefaultTrack`) → `undefined` (opt-in). FORCED tracks are
88
- * excluded unless `includeForcedTracks` (Apple-spec: a regular track must carry
77
+ * Priority: `preferredSubtitleLanguage` match → `DEFAULT=YES + AUTOSELECT=YES` (only when `enableDefaultTrack`) →
78
+ * `undefined` (opt-in). FORCED tracks are excluded unless `includeForcedTracks` (Apple-spec: a regular track must carry
89
79
  * forced content when both exist, so a forced-only track is redundant).
90
80
  */
91
81
  function pickTextTrackFromTracks(tracks, config) {