@remotion/media-parser 4.0.270 → 4.0.272

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 (338) hide show
  1. package/dist/aac-codecprivate.js +6 -13
  2. package/dist/add-avc-profile-to-track.js +5 -9
  3. package/dist/buffer-iterator.js +8 -13
  4. package/dist/combine-uint8-arrays.js +1 -5
  5. package/dist/containers/aac/parse-aac.js +9 -13
  6. package/dist/containers/aac/types.js +1 -2
  7. package/dist/containers/avc/codec-string.js +1 -5
  8. package/dist/containers/avc/color.js +3 -9
  9. package/dist/containers/avc/create-sps-pps-data.js +5 -9
  10. package/dist/containers/avc/interpret-sps.js +7 -13
  11. package/dist/containers/avc/key.js +1 -5
  12. package/dist/containers/avc/parse-avc.js +3 -7
  13. package/dist/containers/avc/sps-and-pps.js +1 -5
  14. package/dist/containers/flac/get-block-size.js +1 -5
  15. package/dist/containers/flac/get-channel-count.d.ts +1 -1
  16. package/dist/containers/flac/get-channel-count.js +1 -5
  17. package/dist/containers/flac/get-duration-from-flac.js +1 -5
  18. package/dist/containers/flac/get-metadata-from-flac.d.ts +1 -1
  19. package/dist/containers/flac/get-metadata-from-flac.js +1 -5
  20. package/dist/containers/flac/get-sample-rate.js +1 -5
  21. package/dist/containers/flac/parse-flac-frame.js +14 -19
  22. package/dist/containers/flac/parse-flac.js +15 -19
  23. package/dist/containers/flac/parse-header.js +1 -5
  24. package/dist/containers/flac/parse-metadata.js +1 -5
  25. package/dist/containers/flac/parse-streaminfo.js +3 -7
  26. package/dist/containers/flac/parse-unknown-block.js +1 -5
  27. package/dist/containers/flac/types.d.ts +2 -2
  28. package/dist/containers/flac/types.js +1 -2
  29. package/dist/containers/iso-base-media/base-media-box.js +1 -2
  30. package/dist/containers/iso-base-media/base-type.js +1 -2
  31. package/dist/containers/iso-base-media/esds/decoder-specific-config.js +1 -5
  32. package/dist/containers/iso-base-media/esds/esds-descriptors.js +5 -10
  33. package/dist/containers/iso-base-media/esds/esds.js +3 -7
  34. package/dist/containers/iso-base-media/ftyp.js +1 -5
  35. package/dist/containers/iso-base-media/get-actual-number-of-channels.js +4 -8
  36. package/dist/containers/iso-base-media/get-children.js +3 -7
  37. package/dist/containers/iso-base-media/get-keyframes.js +7 -11
  38. package/dist/containers/iso-base-media/get-moov-atom.js +21 -15
  39. package/dist/containers/iso-base-media/get-sample-positions-from-track.js +20 -24
  40. package/dist/containers/iso-base-media/get-video-codec-from-iso-track.d.ts +1 -1
  41. package/dist/containers/iso-base-media/get-video-codec-from-iso-track.js +3 -7
  42. package/dist/containers/iso-base-media/make-track.js +30 -34
  43. package/dist/containers/iso-base-media/mdat/mdat.js +16 -20
  44. package/dist/containers/iso-base-media/mdhd.js +1 -5
  45. package/dist/containers/iso-base-media/meta/hdlr.js +1 -5
  46. package/dist/containers/iso-base-media/meta/ilst.js +1 -5
  47. package/dist/containers/iso-base-media/moov/moov.js +3 -7
  48. package/dist/containers/iso-base-media/mvhd.js +7 -11
  49. package/dist/containers/iso-base-media/parse-boxes.js +5 -9
  50. package/dist/containers/iso-base-media/parse-icc-profile.js +4 -8
  51. package/dist/containers/iso-base-media/process-box.js +63 -67
  52. package/dist/containers/iso-base-media/stsd/av1c.js +1 -5
  53. package/dist/containers/iso-base-media/stsd/avcc.js +1 -5
  54. package/dist/containers/iso-base-media/stsd/colr.js +3 -7
  55. package/dist/containers/iso-base-media/stsd/ctts.js +1 -5
  56. package/dist/containers/iso-base-media/stsd/hvcc.js +3 -7
  57. package/dist/containers/iso-base-media/stsd/keys.js +1 -5
  58. package/dist/containers/iso-base-media/stsd/mebx.js +3 -7
  59. package/dist/containers/iso-base-media/stsd/pasp.js +1 -5
  60. package/dist/containers/iso-base-media/stsd/samples.js +8 -13
  61. package/dist/containers/iso-base-media/stsd/stco.js +1 -5
  62. package/dist/containers/iso-base-media/stsd/stsc.js +1 -5
  63. package/dist/containers/iso-base-media/stsd/stsd.js +3 -7
  64. package/dist/containers/iso-base-media/stsd/stss.js +1 -5
  65. package/dist/containers/iso-base-media/stsd/stsz.js +1 -5
  66. package/dist/containers/iso-base-media/stsd/stts.js +1 -5
  67. package/dist/containers/iso-base-media/tfdt.js +1 -5
  68. package/dist/containers/iso-base-media/tfhd.js +1 -5
  69. package/dist/containers/iso-base-media/tkhd.js +4 -8
  70. package/dist/containers/iso-base-media/to-date.js +1 -5
  71. package/dist/containers/iso-base-media/trak/trak.js +3 -7
  72. package/dist/containers/iso-base-media/traversal.d.ts +3 -2
  73. package/dist/containers/iso-base-media/traversal.js +42 -57
  74. package/dist/containers/iso-base-media/trun.js +2 -6
  75. package/dist/containers/iso-base-media/void-box.js +1 -2
  76. package/dist/containers/m3u/after-manifest-fetch.d.ts +5 -3
  77. package/dist/containers/m3u/after-manifest-fetch.js +13 -17
  78. package/dist/containers/m3u/fetch-m3u8-stream.d.ts +5 -1
  79. package/dist/containers/m3u/fetch-m3u8-stream.js +4 -12
  80. package/dist/containers/m3u/get-chunks.d.ts +1 -0
  81. package/dist/containers/m3u/get-chunks.js +6 -6
  82. package/dist/containers/m3u/get-duration-from-m3u.js +4 -8
  83. package/dist/containers/m3u/get-playlist.js +6 -12
  84. package/dist/containers/m3u/get-streams.d.ts +11 -5
  85. package/dist/containers/m3u/get-streams.js +5 -15
  86. package/dist/containers/m3u/iterate-over-segment-files.d.ts +19 -0
  87. package/dist/containers/m3u/iterate-over-segment-files.js +110 -0
  88. package/dist/containers/m3u/parse-directive.js +24 -10
  89. package/dist/containers/m3u/parse-m3u-manifest.js +3 -7
  90. package/dist/containers/m3u/parse-m3u-media-directive.d.ts +1 -0
  91. package/dist/containers/m3u/parse-m3u-media-directive.js +7 -7
  92. package/dist/containers/m3u/parse-m3u.js +13 -13
  93. package/dist/containers/m3u/parse-m3u8-text.js +3 -7
  94. package/dist/containers/m3u/parse-stream-inf.js +2 -7
  95. package/dist/containers/m3u/return-packets.d.ts +1 -1
  96. package/dist/containers/m3u/return-packets.js +14 -5
  97. package/dist/containers/m3u/run-over-m3u.js +68 -57
  98. package/dist/containers/m3u/sample-sorter.d.ts +2 -0
  99. package/dist/containers/m3u/sample-sorter.js +17 -9
  100. package/dist/containers/m3u/select-stream.d.ts +3 -2
  101. package/dist/containers/m3u/select-stream.js +9 -13
  102. package/dist/containers/m3u/types.d.ts +9 -2
  103. package/dist/containers/m3u/types.js +1 -2
  104. package/dist/containers/mp3/get-duration.js +5 -9
  105. package/dist/containers/mp3/get-frame-length.js +2 -7
  106. package/dist/containers/mp3/get-metadata-from-mp3.d.ts +2 -2
  107. package/dist/containers/mp3/get-metadata-from-mp3.js +1 -5
  108. package/dist/containers/mp3/id3-v1.js +1 -5
  109. package/dist/containers/mp3/id3.js +1 -5
  110. package/dist/containers/mp3/parse-mp3.js +7 -11
  111. package/dist/containers/mp3/parse-mpeg-header.js +10 -14
  112. package/dist/containers/mp3/samples-per-mpeg-file.js +1 -5
  113. package/dist/containers/riff/expect-riff-box.js +11 -15
  114. package/dist/containers/riff/get-duration.js +7 -12
  115. package/dist/containers/riff/get-tracks-from-avi.js +20 -28
  116. package/dist/containers/riff/is-movi.js +1 -5
  117. package/dist/containers/riff/parse-avih.js +1 -5
  118. package/dist/containers/riff/parse-isft.js +1 -5
  119. package/dist/containers/riff/parse-list-box.js +3 -7
  120. package/dist/containers/riff/parse-movi.js +13 -18
  121. package/dist/containers/riff/parse-riff-body.js +9 -13
  122. package/dist/containers/riff/parse-riff-box.js +9 -13
  123. package/dist/containers/riff/parse-riff-header.js +1 -5
  124. package/dist/containers/riff/parse-riff.js +5 -9
  125. package/dist/containers/riff/parse-strf.js +1 -5
  126. package/dist/containers/riff/parse-strh.js +3 -7
  127. package/dist/containers/riff/parse-video-section.js +7 -11
  128. package/dist/containers/riff/riff-box.js +1 -2
  129. package/dist/containers/riff/timescale.js +1 -4
  130. package/dist/containers/riff/traversal.js +7 -15
  131. package/dist/containers/transport-stream/adts-header.js +6 -10
  132. package/dist/containers/transport-stream/boxes.js +1 -2
  133. package/dist/containers/transport-stream/discard-rest-of-packet.js +2 -7
  134. package/dist/containers/transport-stream/find-separator.js +1 -4
  135. package/dist/containers/transport-stream/get-tracks.d.ts +2 -0
  136. package/dist/containers/transport-stream/get-tracks.js +13 -14
  137. package/dist/containers/transport-stream/handle-aac-packet.js +12 -16
  138. package/dist/containers/transport-stream/handle-avc-packet.js +22 -26
  139. package/dist/containers/transport-stream/next-pes-header-store.js +1 -5
  140. package/dist/containers/transport-stream/parse-packet.js +13 -17
  141. package/dist/containers/transport-stream/parse-pat.js +5 -10
  142. package/dist/containers/transport-stream/parse-pes.js +1 -5
  143. package/dist/containers/transport-stream/parse-pmt.js +8 -12
  144. package/dist/containers/transport-stream/parse-stream-packet.js +13 -17
  145. package/dist/containers/transport-stream/parse-transport-stream.js +5 -9
  146. package/dist/containers/transport-stream/process-stream-buffers.js +12 -16
  147. package/dist/containers/transport-stream/traversal.js +4 -10
  148. package/dist/containers/wav/get-duration-from-wav.js +3 -8
  149. package/dist/containers/wav/get-metadata-from-wav.d.ts +2 -2
  150. package/dist/containers/wav/get-metadata-from-wav.js +1 -5
  151. package/dist/containers/wav/parse-data.js +5 -9
  152. package/dist/containers/wav/parse-fmt.js +3 -7
  153. package/dist/containers/wav/parse-header.js +1 -5
  154. package/dist/containers/wav/parse-id3.js +1 -5
  155. package/dist/containers/wav/parse-list.js +1 -5
  156. package/dist/containers/wav/parse-video-section.js +3 -7
  157. package/dist/containers/wav/parse-wav.js +15 -19
  158. package/dist/containers/wav/types.d.ts +2 -2
  159. package/dist/containers/wav/types.js +1 -2
  160. package/dist/containers/webm/allowed-partial-segments.js +1 -4
  161. package/dist/containers/webm/av1-codec-private.js +3 -7
  162. package/dist/containers/webm/color.js +6 -10
  163. package/dist/containers/webm/description.js +6 -10
  164. package/dist/containers/webm/get-ready-tracks.js +13 -18
  165. package/dist/containers/webm/get-sample-from-block.js +12 -16
  166. package/dist/containers/webm/make-track.js +43 -48
  167. package/dist/containers/webm/parse-ebml.js +14 -19
  168. package/dist/containers/webm/parse-webm-header.js +3 -7
  169. package/dist/containers/webm/segments/all-segments.js +168 -173
  170. package/dist/containers/webm/segments/block-simple-block-flags.js +4 -8
  171. package/dist/containers/webm/segments/track-entry.js +1 -5
  172. package/dist/containers/webm/segments.js +9 -13
  173. package/dist/containers/webm/traversal.js +37 -67
  174. package/dist/convert-audio-or-video-sample.js +1 -5
  175. package/dist/download-and-parse-media.js +44 -47
  176. package/dist/emit-available-info.js +38 -38
  177. package/dist/emitter.js +1 -5
  178. package/dist/errors.d.ts +2 -17
  179. package/dist/errors.js +10 -30
  180. package/dist/esm/fetch.mjs +93 -67
  181. package/dist/esm/index.mjs +742 -194
  182. package/dist/esm/node.mjs +59 -36
  183. package/dist/esm/universal.mjs +323 -0
  184. package/dist/esm/web-file.mjs +55 -43
  185. package/dist/esm/web.mjs +257 -0
  186. package/dist/esm/worker-server-entry.mjs +13100 -0
  187. package/dist/esm/worker-server.mjs +12914 -0
  188. package/dist/esm/worker-web-entry.mjs +13013 -0
  189. package/dist/esm/worker.mjs +439 -0
  190. package/dist/fetch.js +1 -17
  191. package/dist/file-types/bmp.js +3 -7
  192. package/dist/file-types/detect-file-type.js +24 -38
  193. package/dist/file-types/index.js +22 -26
  194. package/dist/file-types/jpeg.js +4 -9
  195. package/dist/file-types/pdf.js +3 -7
  196. package/dist/file-types/png.js +4 -9
  197. package/dist/file-types/webp.js +3 -7
  198. package/dist/forward-controller.js +1 -5
  199. package/dist/get-audio-codec.js +25 -38
  200. package/dist/get-container.d.ts +3 -3
  201. package/dist/get-container.js +5 -10
  202. package/dist/get-dimensions.js +8 -13
  203. package/dist/get-duration.js +27 -34
  204. package/dist/get-fields-from-callbacks.js +1 -5
  205. package/dist/get-fps.js +24 -34
  206. package/dist/get-is-hdr.js +5 -10
  207. package/dist/get-keyframes.js +6 -11
  208. package/dist/get-location.js +4 -9
  209. package/dist/get-number-of-audio-channels.js +2 -7
  210. package/dist/get-sample-aspect-ratio.js +17 -30
  211. package/dist/get-sample-positions-from-lpcm.js +5 -9
  212. package/dist/get-sample-positions.js +1 -5
  213. package/dist/get-sample-rate.js +2 -7
  214. package/dist/get-tracks.d.ts +5 -0
  215. package/dist/get-tracks.js +37 -44
  216. package/dist/get-video-codec.js +26 -34
  217. package/dist/has-all-info.js +33 -38
  218. package/dist/index.d.ts +18 -11
  219. package/dist/index.js +34 -48
  220. package/dist/init-video.d.ts +1 -1
  221. package/dist/init-video.js +47 -20
  222. package/dist/internal-parse-media.js +36 -40
  223. package/dist/is-audio-structure.d.ts +2 -2
  224. package/dist/is-audio-structure.js +1 -5
  225. package/dist/log.js +8 -12
  226. package/dist/make-hvc1-codec-strings.js +1 -5
  227. package/dist/media-parser-controller.js +7 -11
  228. package/dist/metadata/get-metadata.d.ts +4 -4
  229. package/dist/metadata/get-metadata.js +17 -22
  230. package/dist/metadata/metadata-from-iso.d.ts +3 -3
  231. package/dist/metadata/metadata-from-iso.js +12 -17
  232. package/dist/metadata/metadata-from-matroska.d.ts +2 -2
  233. package/dist/metadata/metadata-from-matroska.js +3 -7
  234. package/dist/metadata/metadata-from-riff.d.ts +2 -2
  235. package/dist/metadata/metadata-from-riff.js +3 -7
  236. package/dist/node-writer.js +1 -17
  237. package/dist/node.js +1 -17
  238. package/dist/options.d.ts +30 -24
  239. package/dist/options.js +1 -2
  240. package/dist/parse-media-on-browser-worker.d.ts +2 -0
  241. package/dist/parse-media-on-browser-worker.js +4 -0
  242. package/dist/parse-media-on-server-worker.d.ts +2 -0
  243. package/dist/parse-media-on-server-worker.js +4 -0
  244. package/dist/parse-media-on-web-worker.d.ts +2 -0
  245. package/dist/parse-media-on-web-worker.js +4 -0
  246. package/dist/parse-media-on-worker-entry.d.ts +2 -0
  247. package/dist/parse-media-on-worker-entry.js +269 -0
  248. package/dist/parse-media-on-worker.d.ts +2 -0
  249. package/dist/parse-media-on-worker.js +4 -0
  250. package/dist/parse-media.js +10 -13
  251. package/dist/parse-result.d.ts +3 -3
  252. package/dist/parse-result.js +1 -2
  253. package/dist/pause-signal.js +1 -5
  254. package/dist/perform-seek.js +6 -10
  255. package/dist/readers/fetch/get-body-and-reader.js +1 -5
  256. package/dist/readers/fetch/resolve-url.d.ts +1 -1
  257. package/dist/readers/fetch/resolve-url.js +1 -5
  258. package/dist/readers/from-fetch.d.ts +4 -1
  259. package/dist/readers/from-fetch.js +109 -94
  260. package/dist/readers/from-node.d.ts +4 -1
  261. package/dist/readers/from-node.js +58 -41
  262. package/dist/readers/from-web-file.d.ts +4 -1
  263. package/dist/readers/from-web-file.js +55 -49
  264. package/dist/readers/reader.d.ts +5 -1
  265. package/dist/readers/reader.js +1 -2
  266. package/dist/readers/universal.d.ts +2 -0
  267. package/dist/readers/universal.js +35 -0
  268. package/dist/readers/web.d.ts +2 -0
  269. package/dist/readers/web.js +22 -0
  270. package/dist/register-track.js +9 -15
  271. package/dist/remotion-license-acknowledge.js +4 -8
  272. package/dist/run-parse-iteration.js +26 -25
  273. package/dist/samples-from-moof.js +8 -12
  274. package/dist/skip.js +1 -5
  275. package/dist/state/aac-state.js +1 -5
  276. package/dist/state/can-skip-tracks.d.ts +2 -2
  277. package/dist/state/can-skip-tracks.js +3 -8
  278. package/dist/state/emitted-fields.js +1 -5
  279. package/dist/state/flac-state.js +1 -5
  280. package/dist/state/has-tracks-section.d.ts +2 -2
  281. package/dist/state/has-tracks-section.js +6 -8
  282. package/dist/state/images.js +1 -5
  283. package/dist/state/iso-base-media/cached-sample-positions.js +8 -13
  284. package/dist/state/iso-base-media/iso-state.js +5 -9
  285. package/dist/state/iso-base-media/moov-box.js +1 -5
  286. package/dist/state/keyframes.js +1 -5
  287. package/dist/state/last-eventloop-break.js +3 -7
  288. package/dist/state/m3u-state.d.ts +6 -0
  289. package/dist/state/m3u-state.js +20 -12
  290. package/dist/state/may-skip-video-data.js +3 -7
  291. package/dist/state/mp3.js +1 -5
  292. package/dist/state/need-samples-for-fields.js +1 -5
  293. package/dist/state/parser-state.d.ts +15 -10
  294. package/dist/state/parser-state.js +37 -41
  295. package/dist/state/riff.js +1 -5
  296. package/dist/state/sample-callbacks.d.ts +3 -2
  297. package/dist/state/sample-callbacks.js +8 -12
  298. package/dist/state/slow-duration-fps.js +1 -5
  299. package/dist/state/structure.d.ts +4 -4
  300. package/dist/state/structure.js +1 -5
  301. package/dist/state/transport-stream.js +3 -7
  302. package/dist/state/video-section.js +1 -5
  303. package/dist/state/webm.js +5 -9
  304. package/dist/throttled-progress.js +1 -5
  305. package/dist/truthy.js +1 -4
  306. package/dist/universal.d.ts +1 -0
  307. package/dist/universal.js +1 -0
  308. package/dist/version.d.ts +1 -1
  309. package/dist/version.js +1 -4
  310. package/dist/web-file.js +1 -17
  311. package/dist/web.d.ts +1 -0
  312. package/dist/web.js +1 -0
  313. package/dist/webcodec-sample-types.d.ts +6 -4
  314. package/dist/webcodec-sample-types.js +1 -2
  315. package/dist/worker/forward-controller.d.ts +3 -0
  316. package/dist/worker/forward-controller.js +20 -0
  317. package/dist/worker/serialize-error.d.ts +4 -0
  318. package/dist/worker/serialize-error.js +95 -0
  319. package/dist/worker/worker-types.d.ts +243 -0
  320. package/dist/worker/worker-types.js +1 -0
  321. package/dist/worker-bun-entry.d.ts +1 -0
  322. package/dist/worker-bun-entry.js +5 -0
  323. package/dist/worker-entry.d.ts +1 -0
  324. package/dist/worker-entry.js +5 -0
  325. package/dist/worker-server-entry.d.ts +1 -0
  326. package/dist/worker-server-entry.js +5 -0
  327. package/dist/worker-server.d.ts +2 -0
  328. package/dist/worker-server.js +381 -0
  329. package/dist/worker-web-entry.d.ts +1 -0
  330. package/dist/worker-web-entry.js +5 -0
  331. package/dist/worker.d.ts +2 -0
  332. package/dist/worker.js +267 -0
  333. package/dist/writers/node.js +16 -23
  334. package/dist/writers/writer.js +1 -2
  335. package/package.json +40 -21
  336. package/fetch.js +0 -2
  337. package/test.json +0 -663
  338. package/web-file.js +0 -2
@@ -1996,17 +1996,25 @@ var parseEsds = ({
1996
1996
  };
1997
1997
 
1998
1998
  // src/containers/iso-base-media/traversal.ts
1999
- var getMoovBox = (state) => {
2000
- if (state.iso.moov.getMoovBox()) {
2001
- return state.iso.moov.getMoovBox();
2002
- }
2003
- const structure = state.getIsoStructure();
1999
+ var getMoovFromFromIsoStructure = (structure) => {
2004
2000
  const moovBox = structure.boxes.find((s) => s.type === "moov-box");
2005
2001
  if (!moovBox || moovBox.type !== "moov-box") {
2006
2002
  return null;
2007
2003
  }
2008
2004
  return moovBox;
2009
2005
  };
2006
+ var getMoovBoxFromState = (state) => {
2007
+ const got = state.iso.moov.getMoovBox();
2008
+ if (got) {
2009
+ return got;
2010
+ }
2011
+ const a = state.mp4HeaderSegment;
2012
+ if (a) {
2013
+ return getMoovFromFromIsoStructure(a);
2014
+ }
2015
+ const structure = state.getIsoStructure();
2016
+ return getMoovFromFromIsoStructure(structure);
2017
+ };
2010
2018
  var getMoofBoxes = (main) => {
2011
2019
  const moofBoxes = main.filter((s) => s.type === "regular-box" && s.boxType === "moof");
2012
2020
  return moofBoxes;
@@ -2270,7 +2278,7 @@ var getFpsFromMp4TrakBox = (trakBox) => {
2270
2278
  });
2271
2279
  };
2272
2280
  var getFpsFromIsoMaseMedia = (state) => {
2273
- const moovBox = getMoovBox(state);
2281
+ const moovBox = getMoovBoxFromState(state);
2274
2282
  if (!moovBox) {
2275
2283
  return null;
2276
2284
  }
@@ -2471,14 +2479,17 @@ var getStreamForId = (structure, packetIdentifier) => {
2471
2479
  };
2472
2480
 
2473
2481
  // src/containers/transport-stream/get-tracks.ts
2482
+ var filterStreamsBySupportedTypes = (streams) => {
2483
+ return streams.filter((stream) => stream.streamType === 27 || stream.streamType === 15);
2484
+ };
2474
2485
  var getTracksFromTransportStream = (parserState) => {
2475
2486
  const structure = parserState.getTsStructure();
2476
2487
  const programMapTable = findProgramMapTableOrThrow(structure);
2477
2488
  const parserTracks = parserState.callbacks.tracks.getTracks();
2478
- const mapped = programMapTable.streams.map((stream) => {
2489
+ const mapped = filterStreamsBySupportedTypes(programMapTable.streams).map((stream) => {
2479
2490
  return parserTracks.find((track) => track.trackId === stream.pid);
2480
2491
  }).filter(truthy);
2481
- if (mapped.length !== programMapTable.streams.length) {
2492
+ if (mapped.length !== filterStreamsBySupportedTypes(programMapTable.streams).length) {
2482
2493
  throw new Error("Not all tracks found");
2483
2494
  }
2484
2495
  return {
@@ -3189,7 +3200,7 @@ var matroskaHasTracks = (state) => {
3189
3200
 
3190
3201
  // src/get-tracks.ts
3191
3202
  var isoBaseMediaHasTracks = (state) => {
3192
- return Boolean(getMoovBox(state));
3203
+ return Boolean(getMoovBoxFromState(state));
3193
3204
  };
3194
3205
  var getHasTracks = (state) => {
3195
3206
  const structure = state.getStructure();
@@ -3244,18 +3255,10 @@ var getCategorizedTracksFromMatroska = (state) => {
3244
3255
  otherTracks
3245
3256
  };
3246
3257
  };
3247
- var getTracksFromIsoBaseMedia = (state) => {
3258
+ var getTracksFromMoovBox = (moovBox) => {
3248
3259
  const videoTracks = [];
3249
3260
  const audioTracks = [];
3250
3261
  const otherTracks = [];
3251
- const moovBox = getMoovBox(state);
3252
- if (!moovBox) {
3253
- return {
3254
- videoTracks,
3255
- audioTracks,
3256
- otherTracks
3257
- };
3258
- }
3259
3262
  const tracks2 = getTraks(moovBox);
3260
3263
  for (const trakBox of tracks2) {
3261
3264
  const track = makeBaseMediaTrack(trakBox);
@@ -3276,6 +3279,17 @@ var getTracksFromIsoBaseMedia = (state) => {
3276
3279
  otherTracks
3277
3280
  };
3278
3281
  };
3282
+ var getTracksFromIsoBaseMedia = (state) => {
3283
+ const moovBox = getMoovBoxFromState(state);
3284
+ if (!moovBox) {
3285
+ return {
3286
+ videoTracks: [],
3287
+ audioTracks: [],
3288
+ otherTracks: []
3289
+ };
3290
+ }
3291
+ return getTracksFromMoovBox(moovBox);
3292
+ };
3279
3293
  var defaultGetTracks = (parserState) => {
3280
3294
  const tracks2 = parserState.callbacks.tracks.getTracks();
3281
3295
  if (tracks2.length === 0) {
@@ -4727,7 +4741,7 @@ var parseTrun = ({
4727
4741
  const sampleDuration = flags & 256 ? iterator.getUint32() : null;
4728
4742
  const sampleSize = flags & 512 ? iterator.getUint32() : null;
4729
4743
  const sampleFlags = flags & 1024 ? iterator.getUint32() : null;
4730
- const sampleCompositionTimeOffset = flags & 2048 ? version === 0 ? iterator.getUint32() : iterator.getInt32Le() : null;
4744
+ const sampleCompositionTimeOffset = flags & 2048 ? version === 0 ? iterator.getUint32() : iterator.getInt32() : null;
4731
4745
  samples.push({
4732
4746
  sampleDuration,
4733
4747
  sampleSize,
@@ -5812,7 +5826,11 @@ var isIndependentSegments = (structure) => {
5812
5826
  }
5813
5827
  return structure.boxes.some((box) => box.type === "m3u-independent-segments" || box.type === "m3u-stream-info");
5814
5828
  };
5815
- var getM3uStreams = (structure, originalSrc) => {
5829
+ var getM3uStreams = ({
5830
+ structure,
5831
+ originalSrc,
5832
+ readerInterface
5833
+ }) => {
5816
5834
  if (structure === null || structure.type !== "m3u") {
5817
5835
  return null;
5818
5836
  }
@@ -5837,13 +5855,13 @@ var getM3uStreams = (structure, originalSrc) => {
5837
5855
  groupId: audioTrack.groupId,
5838
5856
  language: audioTrack.language,
5839
5857
  name: audioTrack.name,
5840
- url: originalSrc && originalSrc.startsWith("http") ? new URL(audioTrack.uri, originalSrc).href : audioTrack.uri,
5858
+ src: readerInterface.createAdjacentFileSource(audioTrack.uri, originalSrc),
5841
5859
  id: associatedPlaylists.length
5842
5860
  });
5843
5861
  }
5844
5862
  }
5845
5863
  boxes.push({
5846
- url: originalSrc && originalSrc.startsWith("http") ? new URL(next.value, originalSrc).href : next.value,
5864
+ src: readerInterface.createAdjacentFileSource(next.value, originalSrc),
5847
5865
  averageBandwidth: str.averageBandwidth,
5848
5866
  bandwidth: str.bandwidth,
5849
5867
  codecs: str.codecs,
@@ -6097,7 +6115,7 @@ var getSamplesFromTraf = (trafSegment, moofOffset) => {
6097
6115
  const samplePosition = {
6098
6116
  offset: offset + (moofOffset ?? 0) + (dataOffset ?? 0),
6099
6117
  dts,
6100
- cts: dts,
6118
+ cts: dts + (sample.sampleCompositionTimeOffset ?? 0),
6101
6119
  duration: duration2,
6102
6120
  isKeyframe: keyframe,
6103
6121
  size,
@@ -6376,7 +6394,7 @@ var getDurationFromMatroska = (segments) => {
6376
6394
  };
6377
6395
  var isoHasDuration = (parserState) => {
6378
6396
  const structure = parserState.getIsoStructure();
6379
- const moovBox = getMoovBox(parserState);
6397
+ const moovBox = getMoovBoxFromState(parserState);
6380
6398
  if (!moovBox) {
6381
6399
  return false;
6382
6400
  }
@@ -6397,7 +6415,7 @@ var isoHasDuration = (parserState) => {
6397
6415
  };
6398
6416
  var getDurationFromIsoBaseMedia = (parserState) => {
6399
6417
  const structure = parserState.getIsoStructure();
6400
- const moovBox = getMoovBox(parserState);
6418
+ const moovBox = getMoovBoxFromState(parserState);
6401
6419
  if (!moovBox) {
6402
6420
  return null;
6403
6421
  }
@@ -6639,7 +6657,7 @@ var parseIsoMetaBox = (meta, trackId) => {
6639
6657
  return entries;
6640
6658
  };
6641
6659
  var getMetadataFromIsoBase = (state) => {
6642
- const moov = getMoovBox(state);
6660
+ const moov = getMoovBoxFromState(state);
6643
6661
  if (!moov) {
6644
6662
  return [];
6645
6663
  }
@@ -7173,7 +7191,11 @@ var emitAvailableInfo = async ({
7173
7191
  }
7174
7192
  if (key === "m3uStreams") {
7175
7193
  if (!emittedFields.m3uStreams && hasInfo.m3uStreams) {
7176
- const streams = getM3uStreams(state.getStructureOrNull(), typeof state.src === "string" ? state.src : null);
7194
+ const streams = getM3uStreams({
7195
+ structure: state.getStructureOrNull(),
7196
+ originalSrc: state.src,
7197
+ readerInterface: state.readerInterface
7198
+ });
7177
7199
  await callbacks.onM3uStreams?.(streams);
7178
7200
  if (fieldsInReturnValue.m3uStreams) {
7179
7201
  returnValue.m3uStreams = streams;
@@ -7418,6 +7440,7 @@ class IsAGifError extends Error {
7418
7440
  fileName
7419
7441
  }) {
7420
7442
  super(message);
7443
+ this.name = "IsAGifError";
7421
7444
  this.fileName = "IsAGifError";
7422
7445
  this.mimeType = mimeType;
7423
7446
  this.sizeInBytes = sizeInBytes;
@@ -7497,30 +7520,6 @@ class IsAnUnsupportedFileTypeError extends Error {
7497
7520
  }
7498
7521
  }
7499
7522
 
7500
- class IsAnUnsupportedAudioTypeError extends Error {
7501
- mimeType;
7502
- sizeInBytes;
7503
- fileName;
7504
- audioType;
7505
- constructor({
7506
- message,
7507
- mimeType,
7508
- sizeInBytes,
7509
- fileName,
7510
- audioType
7511
- }) {
7512
- super(message);
7513
- this.name = "IsAnUnsupportedAudioTypeError";
7514
- this.mimeType = mimeType;
7515
- this.sizeInBytes = sizeInBytes;
7516
- this.fileName = fileName;
7517
- this.audioType = audioType;
7518
- if (Error.captureStackTrace) {
7519
- Error.captureStackTrace(this, IsAnUnsupportedAudioTypeError);
7520
- }
7521
- }
7522
- }
7523
-
7524
7523
  class MediaParserAbortError extends Error {
7525
7524
  constructor(message) {
7526
7525
  super(message);
@@ -7529,7 +7528,7 @@ class MediaParserAbortError extends Error {
7529
7528
  }
7530
7529
  }
7531
7530
  var hasBeenAborted = (error) => {
7532
- return error instanceof MediaParserAbortError;
7531
+ return error instanceof MediaParserAbortError || error.name === "MediaParserAbortError";
7533
7532
  };
7534
7533
 
7535
7534
  // src/pause-signal.ts
@@ -8307,21 +8306,6 @@ var keyframesState = () => {
8307
8306
  };
8308
8307
  };
8309
8308
 
8310
- // src/state/last-eventloop-break.ts
8311
- var eventLoopState = (logLevel) => {
8312
- let lastEventLoopBreak = Date.now();
8313
- const eventLoopBreakIfNeeded = async () => {
8314
- if (Date.now() - lastEventLoopBreak > 2000) {
8315
- await new Promise((resolve) => {
8316
- setTimeout(() => resolve(), 50);
8317
- });
8318
- Log.verbose(logLevel, "10ms event loop break");
8319
- lastEventLoopBreak = Date.now();
8320
- }
8321
- };
8322
- return { eventLoopBreakIfNeeded };
8323
- };
8324
-
8325
8309
  // src/containers/m3u/sample-sorter.ts
8326
8310
  var sampleSorter = ({
8327
8311
  logLevel,
@@ -8341,6 +8325,12 @@ var sampleSorter = ({
8341
8325
  addAudioStreamToConsider: (src, callback) => {
8342
8326
  audioCallbacks[src] = callback;
8343
8327
  },
8328
+ hasAudioStreamToConsider: (src) => {
8329
+ return Boolean(audioCallbacks[src]);
8330
+ },
8331
+ hasVideoStreamToConsider: (src) => {
8332
+ return Boolean(videoCallbacks[src]);
8333
+ },
8344
8334
  addAudioSample: async (src, sample) => {
8345
8335
  const callback = audioCallbacks[src];
8346
8336
  if (!callback) {
@@ -8352,13 +8342,16 @@ var sampleSorter = ({
8352
8342
  addVideoSample: async (src, sample) => {
8353
8343
  const callback = videoCallbacks[src];
8354
8344
  if (!callback) {
8355
- throw new Error("No callback found for audio sample");
8345
+ throw new Error("No callback found for video sample.");
8356
8346
  }
8357
8347
  latestSample[src] = sample.dts;
8358
8348
  await callback(sample);
8359
8349
  },
8360
8350
  getNextStreamToRun: (streams) => {
8361
8351
  for (const stream of streams) {
8352
+ if (getAllChunksProcessedForPlaylist(stream)) {
8353
+ continue;
8354
+ }
8362
8355
  if (!streamsWithTracks.includes(stream)) {
8363
8356
  Log.trace(logLevel, `Did not yet detect track of ${stream}, working on that`);
8364
8357
  return stream;
@@ -8374,6 +8367,9 @@ var sampleSorter = ({
8374
8367
  }
8375
8368
  }
8376
8369
  for (const stream of streams) {
8370
+ if (getAllChunksProcessedForPlaylist(stream)) {
8371
+ continue;
8372
+ }
8377
8373
  if ((latestSample[stream] ?? 0) === smallestDts) {
8378
8374
  Log.trace(logLevel, `Working on ${stream} because it has the smallest DTS`);
8379
8375
  return stream;
@@ -8400,16 +8396,23 @@ var m3uState = (logLevel) => {
8400
8396
  if (!selectedMainPlaylist) {
8401
8397
  throw new Error("No main playlist selected");
8402
8398
  }
8403
- const playlistUrl = selectedMainPlaylist.type === "initial-url" ? selectedMainPlaylist.url : selectedMainPlaylist.stream.url;
8399
+ const playlistUrl = selectedMainPlaylist.type === "initial-url" ? selectedMainPlaylist.url : selectedMainPlaylist.stream.src;
8404
8400
  return playlistUrl;
8405
8401
  };
8406
8402
  const getSelectedPlaylists = () => {
8407
8403
  return [
8408
8404
  getMainPlaylistUrl(),
8409
- ...(associatedPlaylists ?? []).map((p) => p.url)
8405
+ ...(associatedPlaylists ?? []).map((p) => p.src)
8410
8406
  ];
8411
8407
  };
8412
8408
  const getAllChunksProcessedForPlaylist = (src) => allChunksProcessed[src];
8409
+ const mp4HeaderSegments = {};
8410
+ const setMp4HeaderSegment = (playlistUrl, structure) => {
8411
+ mp4HeaderSegments[playlistUrl] = structure;
8412
+ };
8413
+ const getMp4HeaderSegment = (playlistUrl) => {
8414
+ return mp4HeaderSegments[playlistUrl];
8415
+ };
8413
8416
  return {
8414
8417
  setSelectedMainPlaylist: (stream) => {
8415
8418
  selectedMainPlaylist = stream;
@@ -8438,7 +8441,7 @@ var m3uState = (logLevel) => {
8438
8441
  setHasEmittedDoneWithTracks: (src) => {
8439
8442
  hasEmittedDoneWithTracks[src] = true;
8440
8443
  },
8441
- hasEmittedDoneWithTracks: (src) => hasEmittedDoneWithTracks[src],
8444
+ hasEmittedDoneWithTracks: (src) => hasEmittedDoneWithTracks[src] !== undefined,
8442
8445
  setReadyToIterateOverM3u: () => {
8443
8446
  readyToIterateOverM3u = true;
8444
8447
  },
@@ -8470,6 +8473,9 @@ var m3uState = (logLevel) => {
8470
8473
  const selectedPlaylists = getSelectedPlaylists();
8471
8474
  return selectedPlaylists.every((url) => tracksDone[url]);
8472
8475
  },
8476
+ getTrackDone: (playlistUrl) => {
8477
+ return tracksDone[playlistUrl];
8478
+ },
8473
8479
  getM3uStreamRun: (playlistUrl) => m3uStreamRuns[playlistUrl] ?? null,
8474
8480
  abortM3UStreamRuns: () => {
8475
8481
  const values = Object.values(m3uStreamRuns);
@@ -8486,7 +8492,9 @@ var m3uState = (logLevel) => {
8486
8492
  },
8487
8493
  getAssociatedPlaylists: () => associatedPlaylists,
8488
8494
  getSelectedPlaylists,
8489
- sampleSorter: sampleSorter({ logLevel, getAllChunksProcessedForPlaylist })
8495
+ sampleSorter: sampleSorter({ logLevel, getAllChunksProcessedForPlaylist }),
8496
+ setMp4HeaderSegment,
8497
+ getMp4HeaderSegment
8490
8498
  };
8491
8499
  };
8492
8500
 
@@ -8574,7 +8582,7 @@ var makeCanSkipTracksState = ({
8574
8582
  };
8575
8583
 
8576
8584
  // src/state/has-tracks-section.ts
8577
- var makeTracksSectionState = (canSkipTracksState) => {
8585
+ var makeTracksSectionState = (canSkipTracksState, src) => {
8578
8586
  const tracks2 = [];
8579
8587
  let doneWithTracks = false;
8580
8588
  return {
@@ -8599,7 +8607,7 @@ var makeTracksSectionState = (canSkipTracksState) => {
8599
8607
  return;
8600
8608
  }
8601
8609
  if (!doneWithTracks) {
8602
- throw new Error("Error in Media Parser: End of parsing has been reached, but no tracks have been found");
8610
+ throw new Error("Error in Media Parser: End of parsing of " + src + " has been reached, but no tracks have been found ");
8603
8611
  }
8604
8612
  }
8605
8613
  };
@@ -8614,7 +8622,8 @@ var sampleCallback = ({
8614
8622
  keyframes,
8615
8623
  emittedFields,
8616
8624
  slowDurationAndFpsState,
8617
- structure
8625
+ structure,
8626
+ src
8618
8627
  }) => {
8619
8628
  const videoSampleCallbacks = {};
8620
8629
  const audioSampleCallbacks = {};
@@ -8626,7 +8635,7 @@ var sampleCallback = ({
8626
8635
  hasVideoTrackHandlers,
8627
8636
  structure
8628
8637
  });
8629
- const tracksState = makeTracksSectionState(canSkipTracksState);
8638
+ const tracksState = makeTracksSectionState(canSkipTracksState, src);
8630
8639
  const samplesForTrack = {};
8631
8640
  return {
8632
8641
  registerVideoSampleCallback: async (id, callback) => {
@@ -9035,7 +9044,8 @@ var makeParserState = ({
9035
9044
  readerInterface,
9036
9045
  onDiscardedData,
9037
9046
  selectM3uStreamFn,
9038
- selectM3uAssociatedPlaylistsFn
9047
+ selectM3uAssociatedPlaylistsFn,
9048
+ mp4HeaderSegment
9039
9049
  }) => {
9040
9050
  let skippedBytes = 0;
9041
9051
  const iterator = getArrayBufferIterator(new Uint8Array([]), contentLength);
@@ -9074,7 +9084,8 @@ var makeParserState = ({
9074
9084
  keyframes,
9075
9085
  emittedFields,
9076
9086
  slowDurationAndFpsState: slowDurationAndFps,
9077
- structure
9087
+ structure,
9088
+ src
9078
9089
  }),
9079
9090
  getInternalStats: () => ({
9080
9091
  skippedBytes,
@@ -9096,12 +9107,12 @@ var makeParserState = ({
9096
9107
  iterator,
9097
9108
  controller,
9098
9109
  mode,
9099
- eventLoop: eventLoopState(logLevel),
9100
9110
  src,
9101
9111
  readerInterface,
9102
9112
  discardReadBytes,
9103
9113
  selectM3uStreamFn,
9104
- selectM3uAssociatedPlaylistsFn
9114
+ selectM3uAssociatedPlaylistsFn,
9115
+ mp4HeaderSegment
9105
9116
  };
9106
9117
  };
9107
9118
 
@@ -9110,6 +9121,14 @@ var getMoovAtom = async ({
9110
9121
  endOfMdat,
9111
9122
  state
9112
9123
  }) => {
9124
+ const headerSegment = state.mp4HeaderSegment;
9125
+ if (headerSegment) {
9126
+ const segment = getMoovFromFromIsoStructure(headerSegment);
9127
+ if (!segment) {
9128
+ throw new Error("No moov box found in header segment");
9129
+ }
9130
+ return segment;
9131
+ }
9113
9132
  const start = Date.now();
9114
9133
  Log.verbose(state.logLevel, "Starting second fetch to get moov atom");
9115
9134
  const { reader } = await state.readerInterface.read({
@@ -9139,7 +9158,8 @@ var getMoovAtom = async ({
9139
9158
  src: state.src,
9140
9159
  onDiscardedData: null,
9141
9160
  selectM3uStreamFn: state.selectM3uStreamFn,
9142
- selectM3uAssociatedPlaylistsFn: state.selectM3uAssociatedPlaylistsFn
9161
+ selectM3uAssociatedPlaylistsFn: state.selectM3uAssociatedPlaylistsFn,
9162
+ mp4HeaderSegment: state.mp4HeaderSegment
9143
9163
  });
9144
9164
  while (true) {
9145
9165
  const result = await reader.reader.read();
@@ -9308,7 +9328,7 @@ var parseStreamInf = (str) => {
9308
9328
  };
9309
9329
 
9310
9330
  // src/containers/m3u/parse-m3u-media-directive.ts
9311
- var parseM3uMediaDirective = (str) => {
9331
+ var parseM3uKeyValue = (str) => {
9312
9332
  const quotes = splitRespectingQuotes(str);
9313
9333
  const map = {};
9314
9334
  for (const quote of quotes) {
@@ -9321,6 +9341,10 @@ var parseM3uMediaDirective = (str) => {
9321
9341
  const actualValue = value?.startsWith('"') && value?.endsWith('"') ? value.slice(1, -1) : value;
9322
9342
  map[key] = actualValue;
9323
9343
  }
9344
+ return map;
9345
+ };
9346
+ var parseM3uMediaDirective = (str) => {
9347
+ const map = parseM3uKeyValue(str);
9324
9348
  return {
9325
9349
  type: "m3u-media-info",
9326
9350
  autoselect: map.AUTOSELECT === "YES",
@@ -9416,13 +9440,31 @@ var parseM3uDirective = (str) => {
9416
9440
  const res = parseStreamInf(value);
9417
9441
  return res;
9418
9442
  }
9443
+ if (directive === "#EXT-X-I-FRAME-STREAM-INF") {
9444
+ return {
9445
+ type: "m3u-i-frame-stream-info"
9446
+ };
9447
+ }
9448
+ if (directive === "#EXT-X-ALLOW-CACHE") {
9449
+ if (!value) {
9450
+ throw new Error("#EXT-X-ALLOW-CACHE directive must have a value");
9451
+ }
9452
+ return {
9453
+ type: "m3u-allow-cache",
9454
+ allowsCache: value === "YES"
9455
+ };
9456
+ }
9419
9457
  if (directive === "#EXT-X-MAP") {
9420
9458
  if (!value) {
9421
9459
  throw new Error("#EXT-X-MAP directive must have a value");
9422
9460
  }
9461
+ const p = parseM3uKeyValue(value);
9462
+ if (!p.URI) {
9463
+ throw new Error("EXT-X-MAP directive must have a URI");
9464
+ }
9423
9465
  return {
9424
9466
  type: "m3u-map",
9425
- value: Number(value)
9467
+ value: p.URI
9426
9468
  };
9427
9469
  }
9428
9470
  throw new Error(`Unknown directive ${directive}. Value: ${value}`);
@@ -9449,12 +9491,11 @@ var parseM3u8Text = (line, boxes) => {
9449
9491
  };
9450
9492
 
9451
9493
  // src/containers/m3u/fetch-m3u8-stream.ts
9452
- var fetchM3u8Stream = async (url) => {
9453
- const res = await fetch(url);
9454
- if (!res.ok) {
9455
- throw new Error(`Failed to fetch ${url} (HTTP code: ${res.status})`);
9456
- }
9457
- const text = await res.text();
9494
+ var fetchM3u8Stream = async ({
9495
+ url,
9496
+ readerInterface
9497
+ }) => {
9498
+ const text = await readerInterface.readWholeAsText(url);
9458
9499
  const lines = text.split(`
9459
9500
  `);
9460
9501
  const boxes = [];
@@ -9477,14 +9518,17 @@ var selectAssociatedPlaylists = async ({
9477
9518
  throw new Error("Expected an array of associated playlists");
9478
9519
  }
9479
9520
  for (const stream of streams) {
9480
- if (!playlists.find((playlist) => playlist.url === stream.url)) {
9521
+ if (!playlists.find((playlist) => playlist.src === stream.src)) {
9481
9522
  throw new Error(`The associated playlist ${JSON.stringify(streams)} cannot be selected because it was not in the list of selectable playlists`);
9482
9523
  }
9483
9524
  }
9484
9525
  return streams;
9485
9526
  };
9486
9527
  var defaultSelectM3uAssociatedPlaylists = ({ associatedPlaylists }) => {
9487
- return Promise.resolve(associatedPlaylists.filter((playlist) => playlist.default));
9528
+ if (associatedPlaylists.length === 1) {
9529
+ return associatedPlaylists;
9530
+ }
9531
+ return associatedPlaylists.filter((playlist) => playlist.default);
9488
9532
  };
9489
9533
  var selectStream = async ({
9490
9534
  streams,
@@ -9511,7 +9555,8 @@ var afterManifestFetch = async ({
9511
9555
  src,
9512
9556
  selectM3uStreamFn,
9513
9557
  logLevel,
9514
- selectAssociatedPlaylists: selectAssociatedPlaylistsFn
9558
+ selectAssociatedPlaylistsFn,
9559
+ readerInterface
9515
9560
  }) => {
9516
9561
  const independentSegments = isIndependentSegments(structure);
9517
9562
  if (!independentSegments) {
@@ -9524,7 +9569,7 @@ var afterManifestFetch = async ({
9524
9569
  });
9525
9570
  return m3uState2.setReadyToIterateOverM3u();
9526
9571
  }
9527
- const streams = getM3uStreams(structure, src);
9572
+ const streams = getM3uStreams({ structure, originalSrc: src, readerInterface });
9528
9573
  if (streams === null) {
9529
9574
  throw new Error("No streams found");
9530
9575
  }
@@ -9542,12 +9587,12 @@ var afterManifestFetch = async ({
9542
9587
  });
9543
9588
  m3uState2.setAssociatedPlaylists(associatedPlaylists);
9544
9589
  const playlistUrls = [
9545
- selectedPlaylist.url,
9546
- ...associatedPlaylists.map((p) => p.url)
9590
+ selectedPlaylist.src,
9591
+ ...associatedPlaylists.map((p) => p.src)
9547
9592
  ];
9548
9593
  const struc = await Promise.all(playlistUrls.map(async (url) => {
9549
9594
  Log.verbose(logLevel, `Fetching playlist ${url}`);
9550
- const boxes = await fetchM3u8Stream(url);
9595
+ const boxes = await fetchM3u8Stream({ url, readerInterface });
9551
9596
  return {
9552
9597
  type: "m3u-playlist",
9553
9598
  boxes,
@@ -9676,89 +9721,178 @@ function parseContentRange(input) {
9676
9721
  return range2;
9677
9722
  }
9678
9723
  var validateContentRangeAndDetectIfSupported = ({
9679
- actualRange,
9724
+ requestedRange,
9680
9725
  parsedContentRange,
9681
9726
  statusCode
9682
9727
  }) => {
9683
9728
  if (statusCode === 206) {
9684
9729
  return { supportsContentRange: true };
9685
9730
  }
9686
- if (typeof actualRange === "number" && parsedContentRange?.start !== actualRange) {
9687
- if (actualRange === 0) {
9731
+ if (typeof requestedRange === "number" && parsedContentRange?.start !== requestedRange) {
9732
+ if (requestedRange === 0) {
9688
9733
  return { supportsContentRange: false };
9689
9734
  }
9690
- throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange?.start})`);
9735
+ throw new Error(`Range header (${requestedRange}) does not match content-range header (${parsedContentRange?.start})`);
9691
9736
  }
9692
- if (actualRange !== null && typeof actualRange !== "number" && (parsedContentRange?.start !== actualRange[0] || parsedContentRange?.end !== actualRange[1])) {
9693
- throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange?.start})`);
9737
+ if (requestedRange !== null && typeof requestedRange !== "number" && (parsedContentRange?.start !== requestedRange[0] || parsedContentRange?.end !== requestedRange[1])) {
9738
+ throw new Error(`Range header (${requestedRange}) does not match content-range header (${parsedContentRange?.start})`);
9694
9739
  }
9695
9740
  return { supportsContentRange: true };
9696
9741
  };
9697
- var fetchReader = {
9698
- read: async ({ src, range: range2, controller }) => {
9699
- if (typeof src !== "string") {
9700
- throw new Error("src must be a string when using `fetchReader`");
9701
- }
9702
- const resolvedUrl = resolveUrl(src);
9703
- const resolvedUrlString = resolvedUrl.toString();
9704
- if (!resolvedUrlString.startsWith("https://") && !resolvedUrlString.startsWith("blob:") && !resolvedUrlString.startsWith("http://")) {
9705
- return Promise.reject(new Error(`${resolvedUrlString} is not a URL - needs to start with http:// or https:// or blob:. If you want to read a local file, pass \`reader: nodeReader\` to parseMedia().`));
9706
- }
9707
- const ownController = new AbortController;
9708
- const cache = typeof navigator !== "undefined" && navigator.userAgent.includes("Cloudflare-Workers") ? undefined : "no-store";
9709
- const actualRange = range2 === null ? 0 : range2;
9710
- const asString = typeof resolvedUrl === "string" ? resolvedUrl : resolvedUrl.pathname;
9711
- const requestWithoutRange = asString.endsWith(".m3u8");
9712
- const canLiveWithoutContentLength = asString.endsWith(".m3u8") || asString.endsWith(".ts");
9713
- const headers = actualRange === 0 && requestWithoutRange ? {} : typeof actualRange === "number" ? {
9714
- Range: `bytes=${actualRange}-`
9715
- } : {
9716
- Range: `bytes=${`${actualRange[0]}-${actualRange[1]}`}`
9717
- };
9718
- const res = await fetch(resolvedUrl, {
9719
- headers,
9720
- signal: ownController.signal,
9721
- cache
9722
- });
9723
- const contentRange = res.headers.get("content-range");
9724
- const parsedContentRange = contentRange ? parseContentRange(contentRange) : null;
9725
- const { supportsContentRange } = validateContentRangeAndDetectIfSupported({
9726
- actualRange,
9727
- parsedContentRange,
9728
- statusCode: res.status
9729
- });
9742
+ var fetchReadContent = async ({
9743
+ src,
9744
+ range: range2,
9745
+ controller
9746
+ }) => {
9747
+ if (typeof src !== "string" && src instanceof URL === false) {
9748
+ throw new Error("src must be a string when using `fetchReader`");
9749
+ }
9750
+ const resolvedUrl = resolveUrl(src);
9751
+ const resolvedUrlString = resolvedUrl.toString();
9752
+ if (!resolvedUrlString.startsWith("https://") && !resolvedUrlString.startsWith("blob:") && !resolvedUrlString.startsWith("http://")) {
9753
+ return Promise.reject(new Error(`${resolvedUrlString} is not a URL - needs to start with http:// or https:// or blob:. If you want to read a local file, pass \`reader: nodeReader\` to parseMedia().`));
9754
+ }
9755
+ const ownController = new AbortController;
9756
+ const cache = typeof navigator !== "undefined" && navigator.userAgent.includes("Cloudflare-Workers") ? undefined : "no-store";
9757
+ const requestedRange = range2 === null ? 0 : range2;
9758
+ const asString = typeof resolvedUrl === "string" ? resolvedUrl : resolvedUrl.pathname;
9759
+ const requestWithoutRange = asString.endsWith(".m3u8");
9760
+ const canLiveWithoutContentLength = asString.endsWith(".m3u8") || asString.endsWith(".ts");
9761
+ const headers = requestedRange === 0 && requestWithoutRange ? {} : typeof requestedRange === "number" ? {
9762
+ Range: `bytes=${requestedRange}-`
9763
+ } : {
9764
+ Range: `bytes=${`${requestedRange[0]}-${requestedRange[1]}`}`
9765
+ };
9766
+ const res = await fetch(resolvedUrl, {
9767
+ headers,
9768
+ signal: ownController.signal,
9769
+ cache
9770
+ });
9771
+ const contentRange = res.headers.get("content-range");
9772
+ const parsedContentRange = contentRange ? parseContentRange(contentRange) : null;
9773
+ const { supportsContentRange } = validateContentRangeAndDetectIfSupported({
9774
+ requestedRange,
9775
+ parsedContentRange,
9776
+ statusCode: res.status
9777
+ });
9778
+ controller._internals.signal.addEventListener("abort", () => {
9779
+ ownController.abort(new MediaParserAbortError("Aborted by user"));
9780
+ }, { once: true });
9781
+ if (res.status.toString().startsWith("4") || res.status.toString().startsWith("5")) {
9782
+ throw new Error(`Server returned status code ${res.status} for ${src} and range ${requestedRange}`);
9783
+ }
9784
+ const contentDisposition = res.headers.get("content-disposition");
9785
+ const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
9786
+ const fallbackName = src.toString().split("/").pop();
9787
+ const { contentLength, needsContentRange, reader } = await getLengthAndReader({
9788
+ canLiveWithoutContentLength,
9789
+ res,
9790
+ ownController,
9791
+ requestedWithoutRange: requestWithoutRange
9792
+ });
9793
+ if (controller) {
9730
9794
  controller._internals.signal.addEventListener("abort", () => {
9731
- ownController.abort(new MediaParserAbortError("Aborted by user"));
9795
+ reader.reader.cancel().catch(() => {
9796
+ });
9732
9797
  }, { once: true });
9733
- if (res.status.toString().startsWith("4") || res.status.toString().startsWith("5")) {
9734
- throw new Error(`Server returned status code ${res.status} for ${src} and range ${actualRange}`);
9735
- }
9736
- const contentDisposition = res.headers.get("content-disposition");
9737
- const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
9738
- const fallbackName = src.split("/").pop();
9739
- const { contentLength, needsContentRange, reader } = await getLengthAndReader({
9740
- canLiveWithoutContentLength,
9741
- res,
9742
- ownController,
9743
- requestedWithoutRange: requestWithoutRange
9744
- });
9745
- if (controller) {
9746
- controller._internals.signal.addEventListener("abort", () => {
9747
- reader.reader.cancel().catch(() => {
9748
- });
9749
- }, { once: true });
9750
- }
9751
- return {
9752
- reader,
9753
- contentLength,
9754
- contentType: res.headers.get("content-type"),
9755
- name: name ?? fallbackName,
9756
- supportsContentRange,
9757
- needsContentRange
9758
- };
9759
9798
  }
9799
+ return {
9800
+ reader,
9801
+ contentLength,
9802
+ contentType: res.headers.get("content-type"),
9803
+ name: name ?? fallbackName,
9804
+ supportsContentRange,
9805
+ needsContentRange
9806
+ };
9807
+ };
9808
+ var fetchReadWholeAsText = async (src) => {
9809
+ if (typeof src !== "string" && src instanceof URL === false) {
9810
+ throw new Error("src must be a string when using `fetchReader`");
9811
+ }
9812
+ const res = await fetch(src);
9813
+ if (!res.ok) {
9814
+ throw new Error(`Failed to fetch ${src} (HTTP code: ${res.status})`);
9815
+ }
9816
+ return res.text();
9817
+ };
9818
+ var fetchCreateAdjacentFileSource = (relativePath, src) => {
9819
+ if (typeof src !== "string" && src instanceof URL === false) {
9820
+ throw new Error("src must be a string or URL when using `fetchReader`");
9821
+ }
9822
+ return new URL(relativePath, src).toString();
9823
+ };
9824
+
9825
+ // src/readers/from-web-file.ts
9826
+ var webFileReadContent = ({ src, range: range2, controller }) => {
9827
+ if (typeof src === "string" || src instanceof URL) {
9828
+ throw new Error("`inputTypeFileReader` only supports `File` objects");
9829
+ }
9830
+ const part = range2 === null ? src : typeof range2 === "number" ? src.slice(range2) : src.slice(range2[0], range2[1]);
9831
+ const reader = new FileReader;
9832
+ reader.readAsArrayBuffer(src);
9833
+ const ownController = new AbortController;
9834
+ if (ownController) {
9835
+ ownController.signal.addEventListener("abort", () => {
9836
+ reader.abort();
9837
+ }, { once: true });
9838
+ }
9839
+ if (controller) {
9840
+ controller._internals.signal.addEventListener("abort", () => {
9841
+ ownController.abort();
9842
+ }, { once: true });
9843
+ }
9844
+ return new Promise((resolve, reject) => {
9845
+ reader.onload = () => {
9846
+ const stream = part.stream();
9847
+ const streamReader = stream.getReader();
9848
+ resolve({
9849
+ reader: {
9850
+ reader: streamReader,
9851
+ abort() {
9852
+ streamReader.cancel();
9853
+ ownController.abort();
9854
+ }
9855
+ },
9856
+ contentLength: src.size,
9857
+ name: src.name,
9858
+ supportsContentRange: true,
9859
+ contentType: src.type,
9860
+ needsContentRange: true
9861
+ });
9862
+ };
9863
+ reader.onerror = () => {
9864
+ reject(reader.error);
9865
+ };
9866
+ });
9867
+ };
9868
+ var webFileReadWholeAsText = () => {
9869
+ throw new Error("`webFileReader` cannot read auxiliary files.");
9870
+ };
9871
+ var webFileCreateAdjacentFileSource = () => {
9872
+ throw new Error("`webFileReader` cannot create adjacent file sources.");
9760
9873
  };
9761
9874
 
9875
+ // src/readers/web.ts
9876
+ var webReader = {
9877
+ read: (params) => {
9878
+ if (params.src instanceof Blob) {
9879
+ return webFileReadContent(params);
9880
+ }
9881
+ return fetchReadContent(params);
9882
+ },
9883
+ createAdjacentFileSource: (relativePath, src) => {
9884
+ if (src instanceof Blob) {
9885
+ return webFileCreateAdjacentFileSource(relativePath, src);
9886
+ }
9887
+ return fetchCreateAdjacentFileSource(relativePath, src);
9888
+ },
9889
+ readWholeAsText: (src) => {
9890
+ if (src instanceof Blob) {
9891
+ return webFileReadWholeAsText(src);
9892
+ }
9893
+ return fetchReadWholeAsText(src);
9894
+ }
9895
+ };
9762
9896
  // src/parse-media.ts
9763
9897
  var parseMedia = (options) => {
9764
9898
  return internalParseMedia({
@@ -9796,10 +9930,11 @@ var parseMedia = (options) => {
9796
9930
  onVideoCodec: options.onVideoCodec ?? null,
9797
9931
  onVideoTrack: options.onVideoTrack ?? null,
9798
9932
  progressIntervalInMs: options.progressIntervalInMs ?? null,
9799
- reader: options.reader ?? fetchReader,
9933
+ reader: options.reader ?? webReader,
9800
9934
  controller: options.controller ?? undefined,
9801
9935
  selectM3uStream: options.selectM3uStream ?? defaultSelectM3uStreamFn,
9802
9936
  selectM3uAssociatedPlaylists: options.selectM3uAssociatedPlaylists ?? defaultSelectM3uAssociatedPlaylists,
9937
+ mp4HeaderSegment: options.mp4HeaderSegment ?? null,
9803
9938
  src: options.src,
9804
9939
  mode: "query",
9805
9940
  onDiscardedData: null,
@@ -9814,21 +9949,25 @@ var getChunks = (playlist) => {
9814
9949
  const chunks = [];
9815
9950
  for (let i = 0;i < playlist.boxes.length; i++) {
9816
9951
  const box = playlist.boxes[i];
9952
+ if (box.type === "m3u-map") {
9953
+ chunks.push({ duration: 0, url: box.value, isHeader: true });
9954
+ continue;
9955
+ }
9817
9956
  if (box.type === "m3u-extinf") {
9818
9957
  const nextBox = playlist.boxes[i + 1];
9819
9958
  i++;
9820
9959
  if (nextBox.type !== "m3u-text-value") {
9821
9960
  throw new Error("Expected m3u-text-value");
9822
9961
  }
9823
- chunks.push({ duration: box.value, url: nextBox.value });
9962
+ chunks.push({ duration: box.value, url: nextBox.value, isHeader: false });
9824
9963
  }
9825
9964
  continue;
9826
9965
  }
9827
9966
  return chunks;
9828
9967
  };
9829
9968
 
9830
- // src/containers/m3u/return-packets.ts
9831
- var iteratorOverTsFiles = async ({
9969
+ // src/containers/m3u/iterate-over-segment-files.ts
9970
+ var iteratorOverSegmentFiles = async ({
9832
9971
  structure,
9833
9972
  onVideoTrack,
9834
9973
  m3uState: m3uState2,
@@ -9837,7 +9976,8 @@ var iteratorOverTsFiles = async ({
9837
9976
  playlistUrl,
9838
9977
  logLevel,
9839
9978
  parentController,
9840
- onInitialProgress
9979
+ onInitialProgress,
9980
+ readerInterface
9841
9981
  }) => {
9842
9982
  const playlist = getPlaylist(structure, playlistUrl);
9843
9983
  const chunks = getChunks(playlist);
@@ -9866,9 +10006,10 @@ var iteratorOverTsFiles = async ({
9866
10006
  for (const chunk of chunks) {
9867
10007
  const isLastChunk = chunk === chunks[chunks.length - 1];
9868
10008
  await childController._internals.checkForAbortAndPause();
9869
- const src = new URL(chunk.url, playlistUrl).toString();
10009
+ const src = readerInterface.createAdjacentFileSource(chunk.url, playlistUrl);
9870
10010
  try {
9871
- await parseMedia({
10011
+ const mp4HeaderSegment = m3uState2.getMp4HeaderSegment(playlistUrl);
10012
+ const data = await parseMedia({
9872
10013
  src,
9873
10014
  acknowledgeRemotionLicense: true,
9874
10015
  logLevel,
@@ -9878,6 +10019,7 @@ var iteratorOverTsFiles = async ({
9878
10019
  childController.pause();
9879
10020
  resolver(makeContinuationFn());
9880
10021
  },
10022
+ fields: chunk.isHeader ? { structure: true } : undefined,
9881
10023
  onTracks: () => {
9882
10024
  if (!m3uState2.hasEmittedDoneWithTracks(playlistUrl)) {
9883
10025
  m3uState2.setHasEmittedDoneWithTracks(playlistUrl);
@@ -9885,7 +10027,7 @@ var iteratorOverTsFiles = async ({
9885
10027
  return null;
9886
10028
  }
9887
10029
  },
9888
- onAudioTrack: async ({ track }) => {
10030
+ onAudioTrack: onAudioTrack === null ? null : async ({ track }) => {
9889
10031
  const callbackOrFalse = m3uState2.hasEmittedAudioTrack(playlistUrl);
9890
10032
  if (callbackOrFalse === false) {
9891
10033
  const callback = await onAudioTrack(track);
@@ -9900,7 +10042,7 @@ var iteratorOverTsFiles = async ({
9900
10042
  }
9901
10043
  return callbackOrFalse;
9902
10044
  },
9903
- onVideoTrack: async ({ track }) => {
10045
+ onVideoTrack: onVideoTrack === null ? null : async ({ track }) => {
9904
10046
  const callbackOrFalse = m3uState2.hasEmittedVideoTrack(playlistUrl);
9905
10047
  if (callbackOrFalse === false) {
9906
10048
  const callback = await onVideoTrack(track);
@@ -9914,8 +10056,16 @@ var iteratorOverTsFiles = async ({
9914
10056
  };
9915
10057
  }
9916
10058
  return callbackOrFalse;
9917
- }
10059
+ },
10060
+ reader: readerInterface,
10061
+ mp4HeaderSegment
9918
10062
  });
10063
+ if (chunk.isHeader) {
10064
+ if (data.structure.type !== "iso-base-media") {
10065
+ throw new Error("Expected an mp4 file");
10066
+ }
10067
+ m3uState2.setMp4HeaderSegment(playlistUrl, data.structure);
10068
+ }
9919
10069
  } catch (e) {
9920
10070
  rejector(e);
9921
10071
  throw e;
@@ -9936,6 +10086,16 @@ var runOverM3u = async ({
9936
10086
  playlistUrl,
9937
10087
  logLevel
9938
10088
  }) => {
10089
+ const tracksDone = state.m3u.getTrackDone(playlistUrl);
10090
+ const hasAudioStreamToConsider = state.m3u.sampleSorter.hasAudioStreamToConsider(playlistUrl);
10091
+ const hasVideoStreamToConsider = state.m3u.sampleSorter.hasVideoStreamToConsider(playlistUrl);
10092
+ const audioDone = !hasAudioStreamToConsider && tracksDone;
10093
+ const videoDone = !hasVideoStreamToConsider && tracksDone;
10094
+ const bothDone = audioDone && videoDone;
10095
+ if (bothDone) {
10096
+ state.m3u.setAllChunksProcessed(playlistUrl);
10097
+ return;
10098
+ }
9939
10099
  const existingRun = state.m3u.getM3uStreamRun(playlistUrl);
9940
10100
  if (existingRun) {
9941
10101
  Log.trace(logLevel, "Existing M3U parsing process found for", playlistUrl);
@@ -9948,7 +10108,7 @@ var runOverM3u = async ({
9948
10108
  }
9949
10109
  Log.trace(logLevel, "Starting new M3U parsing process for", playlistUrl);
9950
10110
  return new Promise((resolve, reject) => {
9951
- const run = iteratorOverTsFiles({
10111
+ const run = iteratorOverSegmentFiles({
9952
10112
  playlistUrl,
9953
10113
  structure,
9954
10114
  onInitialProgress: (newRun) => {
@@ -9962,7 +10122,7 @@ var runOverM3u = async ({
9962
10122
  state.callbacks.tracks.setIsDone(state.logLevel);
9963
10123
  }
9964
10124
  },
9965
- onAudioTrack: async (track) => {
10125
+ onAudioTrack: audioDone ? null : async (track) => {
9966
10126
  const existingTracks = state.callbacks.tracks.getTracks();
9967
10127
  let { trackId } = track;
9968
10128
  while (existingTracks.find((t) => t.trackId === trackId)) {
@@ -9985,7 +10145,7 @@ var runOverM3u = async ({
9985
10145
  await state.m3u.sampleSorter.addAudioSample(playlistUrl, sample);
9986
10146
  };
9987
10147
  },
9988
- onVideoTrack: async (track) => {
10148
+ onVideoTrack: videoDone ? null : async (track) => {
9989
10149
  const existingTracks = state.callbacks.tracks.getTracks();
9990
10150
  let { trackId } = track;
9991
10151
  while (existingTracks.find((t) => t.trackId === trackId)) {
@@ -10009,7 +10169,8 @@ var runOverM3u = async ({
10009
10169
  };
10010
10170
  },
10011
10171
  m3uState: state.m3u,
10012
- parentController: state.controller
10172
+ parentController: state.controller,
10173
+ readerInterface: state.readerInterface
10013
10174
  });
10014
10175
  run.catch((err) => {
10015
10176
  reject(err);
@@ -10032,13 +10193,17 @@ var parseM3u = async ({ state }) => {
10032
10193
  return null;
10033
10194
  }
10034
10195
  if (state.m3u.hasFinishedManifest()) {
10196
+ if (typeof state.src !== "string" && !(state.src instanceof URL)) {
10197
+ throw new Error("Expected src to be a string");
10198
+ }
10035
10199
  await afterManifestFetch({
10036
10200
  structure,
10037
10201
  m3uState: state.m3u,
10038
- src: typeof state.src === "string" ? state.src : null,
10202
+ src: state.src.toString(),
10039
10203
  selectM3uStreamFn: state.selectM3uStreamFn,
10040
10204
  logLevel: state.logLevel,
10041
- selectAssociatedPlaylists: state.selectM3uAssociatedPlaylistsFn
10205
+ selectAssociatedPlaylistsFn: state.selectM3uAssociatedPlaylistsFn,
10206
+ readerInterface: state.readerInterface
10042
10207
  });
10043
10208
  return null;
10044
10209
  }
@@ -11054,11 +11219,12 @@ var parsePmtTable = ({
11054
11219
  const sectionNumber = iterator.getBits(8);
11055
11220
  const lastSectionNumber = iterator.getBits(8);
11056
11221
  const tables = [];
11222
+ iterator.getBits(3);
11223
+ iterator.getBits(13);
11224
+ iterator.getBits(4);
11225
+ const programInfoLength = iterator.getBits(12);
11226
+ iterator.getBits(programInfoLength * 8);
11057
11227
  for (let i = sectionNumber;i <= lastSectionNumber; i++) {
11058
- iterator.getBits(3);
11059
- iterator.getBits(13);
11060
- iterator.getBits(4);
11061
- const programInfoLength = iterator.getBits(12);
11062
11228
  const streams = [];
11063
11229
  while (true) {
11064
11230
  const streamType = iterator.getBits(8);
@@ -11068,7 +11234,6 @@ var parsePmtTable = ({
11068
11234
  const esInfoLength = iterator.getBits(12);
11069
11235
  iterator.getBits(esInfoLength * 8);
11070
11236
  streams.push({ streamType, pid: elementaryPid });
11071
- iterator.getBits(programInfoLength * 8);
11072
11237
  const remaining = sectionLength - (iterator.counter.getOffset() - start);
11073
11238
  if (remaining <= 4) {
11074
11239
  break;
@@ -11355,7 +11520,7 @@ var processStreamBuffer = async ({
11355
11520
  if (!state.callbacks.tracks.hasAllTracks()) {
11356
11521
  const tracksRegistered = state.callbacks.tracks.getTracks().length;
11357
11522
  const { streams } = findProgramMapTableOrThrow(structure);
11358
- if (streams.length === tracksRegistered) {
11523
+ if (filterStreamsBySupportedTypes(streams).length === tracksRegistered) {
11359
11524
  state.callbacks.tracks.setIsDone(state.logLevel);
11360
11525
  }
11361
11526
  }
@@ -11924,7 +12089,7 @@ var parseWebm = async (state) => {
11924
12089
  };
11925
12090
 
11926
12091
  // src/init-video.ts
11927
- var initVideo = ({
12092
+ var initVideo = async ({
11928
12093
  state,
11929
12094
  mimeType,
11930
12095
  name,
@@ -11939,6 +12104,34 @@ var initVideo = ({
11939
12104
  });
11940
12105
  return;
11941
12106
  }
12107
+ if (state.mp4HeaderSegment) {
12108
+ Log.verbose(state.logLevel, "Detected ISO Base Media segment");
12109
+ const moovAtom = getMoovFromFromIsoStructure(state.mp4HeaderSegment);
12110
+ if (!moovAtom) {
12111
+ throw new Error("No moov box found");
12112
+ }
12113
+ const tracks2 = getTracksFromMoovBox(moovAtom);
12114
+ for (const track of tracks2.videoTracks) {
12115
+ await registerVideoTrack({
12116
+ state,
12117
+ track,
12118
+ container: "mp4"
12119
+ });
12120
+ }
12121
+ for (const track of tracks2.audioTracks) {
12122
+ await registerAudioTrack({
12123
+ state,
12124
+ track,
12125
+ container: "mp4"
12126
+ });
12127
+ }
12128
+ state.callbacks.tracks.setIsDone(state.logLevel);
12129
+ state.setStructure({
12130
+ type: "iso-base-media",
12131
+ boxes: []
12132
+ });
12133
+ return;
12134
+ }
11942
12135
  if (fileType.type === "iso-base-media") {
11943
12136
  Log.verbose(state.logLevel, "Detected ISO Base Media container");
11944
12137
  state.setStructure({
@@ -12058,7 +12251,12 @@ var runParseIteration = async ({
12058
12251
  return Promise.reject(new Error("no bytes"));
12059
12252
  }
12060
12253
  if (structure === null) {
12061
- await initVideo({ state, mimeType, name, contentLength });
12254
+ await initVideo({
12255
+ state,
12256
+ mimeType,
12257
+ name,
12258
+ contentLength
12259
+ });
12062
12260
  return null;
12063
12261
  }
12064
12262
  if (structure.type === "riff") {
@@ -12165,6 +12363,7 @@ var internalParseMedia = async function({
12165
12363
  apiName,
12166
12364
  selectM3uStream: selectM3uStreamFn,
12167
12365
  selectM3uAssociatedPlaylists: selectM3uAssociatedPlaylistsFn,
12366
+ mp4HeaderSegment,
12168
12367
  ...more
12169
12368
  }) {
12170
12369
  warnIfRemotionLicenseNotAcknowledged({
@@ -12177,7 +12376,7 @@ var internalParseMedia = async function({
12177
12376
  fields: fieldsInReturnValue,
12178
12377
  callbacks: more
12179
12378
  });
12180
- Log.verbose(logLevel, `Reading ${typeof src === "string" ? src : src.name}`);
12379
+ Log.verbose(logLevel, `Reading ${typeof src === "string" ? src : src instanceof URL ? src.toString() : src.name}`);
12181
12380
  const {
12182
12381
  reader: readerInstance,
12183
12382
  contentLength,
@@ -12217,7 +12416,8 @@ var internalParseMedia = async function({
12217
12416
  src,
12218
12417
  onDiscardedData,
12219
12418
  selectM3uStreamFn,
12220
- selectM3uAssociatedPlaylistsFn
12419
+ selectM3uAssociatedPlaylistsFn,
12420
+ mp4HeaderSegment
12221
12421
  });
12222
12422
  const { iterator } = state;
12223
12423
  let currentReader = readerInstance;
@@ -12294,7 +12494,6 @@ var internalParseMedia = async function({
12294
12494
  if (iterationWithThisOffset > 0 || !hasBigBuffer) {
12295
12495
  await fetchMoreData();
12296
12496
  }
12297
- await state.eventLoop.eventLoopBreakIfNeeded();
12298
12497
  timeReadingData += Date.now() - readStart;
12299
12498
  throttledState.update?.(() => ({
12300
12499
  bytes: iterator.counter.getOffset(),
@@ -12386,6 +12585,353 @@ var internalParseMedia = async function({
12386
12585
  }
12387
12586
  return returnValue;
12388
12587
  };
12588
+ // src/worker/serialize-error.ts
12589
+ var deserializeError = (error) => {
12590
+ switch (error.errorName) {
12591
+ case "IsAGifError":
12592
+ return new IsAGifError({
12593
+ fileName: error.fileName,
12594
+ mimeType: error.mimeType,
12595
+ sizeInBytes: error.sizeInBytes,
12596
+ message: error.errorMessage
12597
+ });
12598
+ case "IsAnImageError":
12599
+ return new IsAnImageError({
12600
+ dimensions: error.dimensions,
12601
+ fileName: error.fileName,
12602
+ imageType: error.imageType,
12603
+ mimeType: error.mimeType,
12604
+ sizeInBytes: error.sizeInBytes,
12605
+ message: error.errorMessage
12606
+ });
12607
+ case "IsAPdfError":
12608
+ return new IsAPdfError({
12609
+ fileName: error.fileName,
12610
+ mimeType: error.mimeType,
12611
+ sizeInBytes: error.sizeInBytes,
12612
+ message: error.errorMessage
12613
+ });
12614
+ case "IsAnUnsupportedFileTypeError":
12615
+ return new IsAnUnsupportedFileTypeError({
12616
+ fileName: error.fileName,
12617
+ mimeType: error.mimeType,
12618
+ sizeInBytes: error.sizeInBytes,
12619
+ message: error.errorMessage
12620
+ });
12621
+ case "MediaParserAbortError":
12622
+ return new MediaParserAbortError(error.errorMessage);
12623
+ default:
12624
+ return new Error(error.errorMessage);
12625
+ }
12626
+ };
12627
+
12628
+ // src/parse-media-on-worker-entry.ts
12629
+ var convertToWorkerPayload = (payload) => {
12630
+ const {
12631
+ onAudioCodec,
12632
+ onContainer,
12633
+ onDimensions,
12634
+ onUnrotatedDimensions,
12635
+ onVideoCodec,
12636
+ onFps,
12637
+ onAudioTrack,
12638
+ onDurationInSeconds,
12639
+ onImages,
12640
+ onInternalStats,
12641
+ onIsHdr,
12642
+ onKeyframes,
12643
+ onLocation,
12644
+ onM3uStreams,
12645
+ onMetadata,
12646
+ onMimeType,
12647
+ onName,
12648
+ onNumberOfAudioChannels,
12649
+ onParseProgress,
12650
+ onRotation,
12651
+ onSampleRate,
12652
+ onSlowAudioBitrate,
12653
+ onSize,
12654
+ onSlowDurationInSeconds,
12655
+ onSlowFps,
12656
+ onSlowKeyframes,
12657
+ onSlowNumberOfFrames,
12658
+ onSlowVideoBitrate,
12659
+ onStructure,
12660
+ onTracks,
12661
+ onVideoTrack,
12662
+ selectM3uStream,
12663
+ selectM3uAssociatedPlaylists,
12664
+ src,
12665
+ ...others
12666
+ } = payload;
12667
+ return {
12668
+ type: "request-worker",
12669
+ payload: others,
12670
+ postAudioCodec: Boolean(onAudioCodec),
12671
+ postContainer: Boolean(onContainer),
12672
+ postDimensions: Boolean(onDimensions),
12673
+ postDurationInSeconds: Boolean(onDurationInSeconds),
12674
+ postFps: Boolean(onFps),
12675
+ postImages: Boolean(onImages),
12676
+ postInternalStats: Boolean(onInternalStats),
12677
+ postIsHdr: Boolean(onIsHdr),
12678
+ postKeyframes: Boolean(onKeyframes),
12679
+ postLocation: Boolean(onLocation),
12680
+ postM3uStreams: Boolean(onM3uStreams),
12681
+ postMetadata: Boolean(onMetadata),
12682
+ postMimeType: Boolean(onMimeType),
12683
+ postName: Boolean(onName),
12684
+ postNumberOfAudioChannels: Boolean(onNumberOfAudioChannels),
12685
+ postRotation: Boolean(onRotation),
12686
+ postSampleRate: Boolean(onSampleRate),
12687
+ postSlowAudioBitrate: Boolean(onSlowAudioBitrate),
12688
+ postSlowDurationInSeconds: Boolean(onSlowDurationInSeconds),
12689
+ postSlowFps: Boolean(onSlowFps),
12690
+ postSlowKeyframes: Boolean(onSlowKeyframes),
12691
+ postSlowNumberOfFrames: Boolean(onSlowNumberOfFrames),
12692
+ postSlowVideoBitrate: Boolean(onSlowVideoBitrate),
12693
+ postStructure: Boolean(onStructure),
12694
+ postTracks: Boolean(onTracks),
12695
+ postUnrotatedDimensions: Boolean(onUnrotatedDimensions),
12696
+ postVideoCodec: Boolean(onVideoCodec),
12697
+ postSize: Boolean(onSize),
12698
+ postParseProgress: Boolean(onParseProgress),
12699
+ postM3uStreamSelection: Boolean(selectM3uStream),
12700
+ postM3uAssociatedPlaylistsSelection: Boolean(selectM3uAssociatedPlaylists),
12701
+ postOnAudioTrack: Boolean(onAudioTrack),
12702
+ postOnVideoTrack: Boolean(onVideoTrack),
12703
+ src
12704
+ };
12705
+ };
12706
+ var post = (worker, payload) => {
12707
+ worker.postMessage(payload);
12708
+ };
12709
+ var parseMediaOnWorkerImplementation = async ({ controller, reader, ...params }, workerUrlEntry, apiName) => {
12710
+ if (typeof Worker === "undefined") {
12711
+ throw new Error('"Worker" is not available. Cannot call workerClient()');
12712
+ }
12713
+ if (reader) {
12714
+ throw new Error(`\`reader\` should not be provided to \`${apiName}\`. If you want to use it in the browser, use parseMediaOnWorker(). If you also want to read files from the file system, use parseMediaOnServerWorker().`);
12715
+ }
12716
+ const worker = new Worker(workerUrlEntry);
12717
+ post(worker, convertToWorkerPayload(params));
12718
+ const { promise, resolve, reject } = Promise.withResolvers();
12719
+ const onAbort = () => {
12720
+ post(worker, { type: "request-abort" });
12721
+ };
12722
+ const onResume = () => {
12723
+ post(worker, { type: "request-resume" });
12724
+ };
12725
+ const onPause = () => {
12726
+ post(worker, { type: "request-pause" });
12727
+ };
12728
+ const callbacks = {};
12729
+ function onMessage(message) {
12730
+ const data = message.data;
12731
+ if (data.type === "response-done") {
12732
+ resolve(data.payload);
12733
+ }
12734
+ if (data.type === "response-error") {
12735
+ cleanup();
12736
+ reject(deserializeError(data));
12737
+ }
12738
+ if (data.type === "response-on-callback-request") {
12739
+ Promise.resolve().then(async () => {
12740
+ if (data.payload.callbackType === "audio-codec") {
12741
+ await params.onAudioCodec?.(data.payload.value);
12742
+ return { payloadType: "void" };
12743
+ }
12744
+ if (data.payload.callbackType === "container") {
12745
+ await params.onContainer?.(data.payload.value);
12746
+ return { payloadType: "void" };
12747
+ }
12748
+ if (data.payload.callbackType === "dimensions") {
12749
+ await params.onDimensions?.(data.payload.value);
12750
+ return { payloadType: "void" };
12751
+ }
12752
+ if (data.payload.callbackType === "unrotated-dimensions") {
12753
+ await params.onUnrotatedDimensions?.(data.payload.value);
12754
+ return { payloadType: "void" };
12755
+ }
12756
+ if (data.payload.callbackType === "video-codec") {
12757
+ await params.onVideoCodec?.(data.payload.value);
12758
+ return { payloadType: "void" };
12759
+ }
12760
+ if (data.payload.callbackType === "tracks") {
12761
+ await params.onTracks?.(data.payload.value);
12762
+ return { payloadType: "void" };
12763
+ }
12764
+ if (data.payload.callbackType === "rotation") {
12765
+ await params.onRotation?.(data.payload.value);
12766
+ return { payloadType: "void" };
12767
+ }
12768
+ if (data.payload.callbackType === "sample-rate") {
12769
+ await params.onSampleRate?.(data.payload.value);
12770
+ return { payloadType: "void" };
12771
+ }
12772
+ if (data.payload.callbackType === "slow-audio-bitrate") {
12773
+ await params.onSlowAudioBitrate?.(data.payload.value);
12774
+ return { payloadType: "void" };
12775
+ }
12776
+ if (data.payload.callbackType === "slow-duration-in-seconds") {
12777
+ await params.onSlowDurationInSeconds?.(data.payload.value);
12778
+ return { payloadType: "void" };
12779
+ }
12780
+ if (data.payload.callbackType === "slow-fps") {
12781
+ await params.onSlowFps?.(data.payload.value);
12782
+ return { payloadType: "void" };
12783
+ }
12784
+ if (data.payload.callbackType === "slow-keyframes") {
12785
+ await params.onSlowKeyframes?.(data.payload.value);
12786
+ return { payloadType: "void" };
12787
+ }
12788
+ if (data.payload.callbackType === "slow-number-of-frames") {
12789
+ await params.onSlowNumberOfFrames?.(data.payload.value);
12790
+ return { payloadType: "void" };
12791
+ }
12792
+ if (data.payload.callbackType === "slow-video-bitrate") {
12793
+ await params.onSlowVideoBitrate?.(data.payload.value);
12794
+ return { payloadType: "void" };
12795
+ }
12796
+ if (data.payload.callbackType === "structure") {
12797
+ await params.onStructure?.(data.payload.value);
12798
+ return { payloadType: "void" };
12799
+ }
12800
+ if (data.payload.callbackType === "fps") {
12801
+ await params.onFps?.(data.payload.value);
12802
+ return { payloadType: "void" };
12803
+ }
12804
+ if (data.payload.callbackType === "images") {
12805
+ await params.onImages?.(data.payload.value);
12806
+ return { payloadType: "void" };
12807
+ }
12808
+ if (data.payload.callbackType === "internal-stats") {
12809
+ await params.onInternalStats?.(data.payload.value);
12810
+ return { payloadType: "void" };
12811
+ }
12812
+ if (data.payload.callbackType === "is-hdr") {
12813
+ await params.onIsHdr?.(data.payload.value);
12814
+ return { payloadType: "void" };
12815
+ }
12816
+ if (data.payload.callbackType === "keyframes") {
12817
+ await params.onKeyframes?.(data.payload.value);
12818
+ return { payloadType: "void" };
12819
+ }
12820
+ if (data.payload.callbackType === "location") {
12821
+ await params.onLocation?.(data.payload.value);
12822
+ return { payloadType: "void" };
12823
+ }
12824
+ if (data.payload.callbackType === "m3u-streams") {
12825
+ await params.onM3uStreams?.(data.payload.value);
12826
+ return { payloadType: "void" };
12827
+ }
12828
+ if (data.payload.callbackType === "metadata") {
12829
+ await params.onMetadata?.(data.payload.value);
12830
+ return { payloadType: "void" };
12831
+ }
12832
+ if (data.payload.callbackType === "mime-type") {
12833
+ await params.onMimeType?.(data.payload.value);
12834
+ return { payloadType: "void" };
12835
+ }
12836
+ if (data.payload.callbackType === "name") {
12837
+ await params.onName?.(data.payload.value);
12838
+ return { payloadType: "void" };
12839
+ }
12840
+ if (data.payload.callbackType === "number-of-audio-channels") {
12841
+ await params.onNumberOfAudioChannels?.(data.payload.value);
12842
+ return { payloadType: "void" };
12843
+ }
12844
+ if (data.payload.callbackType === "size") {
12845
+ await params.onSize?.(data.payload.value);
12846
+ return { payloadType: "void" };
12847
+ }
12848
+ if (data.payload.callbackType === "duration-in-seconds") {
12849
+ await params.onDurationInSeconds?.(data.payload.value);
12850
+ return { payloadType: "void" };
12851
+ }
12852
+ if (data.payload.callbackType === "parse-progress") {
12853
+ await params.onParseProgress?.(data.payload.value);
12854
+ return { payloadType: "void" };
12855
+ }
12856
+ if (data.payload.callbackType === "m3u-stream-selection") {
12857
+ const selection = await params.selectM3uStream(data.payload.value);
12858
+ return { payloadType: "m3u-stream-selection", value: selection };
12859
+ }
12860
+ if (data.payload.callbackType === "m3u-associated-playlists-selection") {
12861
+ const selection = await params.selectM3uAssociatedPlaylists(data.payload.value);
12862
+ return {
12863
+ payloadType: "m3u-associated-playlists-selection",
12864
+ value: selection
12865
+ };
12866
+ }
12867
+ if (data.payload.callbackType === "on-audio-track") {
12868
+ const possibleCallback = await params.onAudioTrack?.(data.payload.value);
12869
+ if (possibleCallback) {
12870
+ callbacks[data.payload.value.track.trackId] = possibleCallback;
12871
+ }
12872
+ return {
12873
+ payloadType: "on-audio-track-response",
12874
+ registeredCallback: Boolean(possibleCallback)
12875
+ };
12876
+ }
12877
+ if (data.payload.callbackType === "on-video-track") {
12878
+ const possibleCallback = await params.onVideoTrack?.(data.payload.value);
12879
+ if (possibleCallback) {
12880
+ callbacks[data.payload.value.track.trackId] = possibleCallback;
12881
+ }
12882
+ return {
12883
+ payloadType: "on-video-track-response",
12884
+ registeredCallback: Boolean(possibleCallback)
12885
+ };
12886
+ }
12887
+ if (data.payload.callbackType === "on-audio-video-sample") {
12888
+ const callback = callbacks[data.payload.trackId];
12889
+ if (!callback) {
12890
+ throw new Error(`No callback registered for track ${data.payload.trackId}`);
12891
+ }
12892
+ await callback(data.payload.value);
12893
+ return { payloadType: "void" };
12894
+ }
12895
+ throw new Error(`Unknown callback type: ${data.payload}`);
12896
+ }).then((payload) => {
12897
+ post(worker, {
12898
+ type: "acknowledge-callback",
12899
+ nonce: data.nonce,
12900
+ ...payload
12901
+ });
12902
+ }).catch((err) => {
12903
+ reject(err);
12904
+ post(worker, {
12905
+ type: "signal-error-in-callback",
12906
+ nonce: data.nonce
12907
+ });
12908
+ });
12909
+ }
12910
+ }
12911
+ worker.addEventListener("message", onMessage);
12912
+ controller?.addEventListener("abort", onAbort);
12913
+ controller?.addEventListener("resume", onResume);
12914
+ controller?.addEventListener("pause", onPause);
12915
+ function cleanup() {
12916
+ worker.removeEventListener("message", onMessage);
12917
+ controller?.removeEventListener("abort", onAbort);
12918
+ controller?.removeEventListener("resume", onResume);
12919
+ controller?.removeEventListener("pause", onPause);
12920
+ worker.terminate();
12921
+ }
12922
+ const val = await promise;
12923
+ cleanup();
12924
+ return val;
12925
+ };
12926
+
12927
+ // src/parse-media-on-server-worker.ts
12928
+ var parseMediaOnServerWorker = (params) => {
12929
+ return parseMediaOnWorkerImplementation(params, new URL("./worker-server-entry", import.meta.url), "parseMediaOnServerWorker");
12930
+ };
12931
+ // src/parse-media-on-web-worker.ts
12932
+ var parseMediaOnWebWorker = (params) => {
12933
+ return parseMediaOnWorkerImplementation(params, new URL("./worker-web-entry", import.meta.url), "parseMediaOnWebWorker");
12934
+ };
12389
12935
  // src/download-and-parse-media.ts
12390
12936
  var downloadAndParseMedia = async (options) => {
12391
12937
  const logLevel = options.logLevel ?? "info";
@@ -12399,11 +12945,12 @@ var downloadAndParseMedia = async (options) => {
12399
12945
  logLevel,
12400
12946
  mode: "download",
12401
12947
  onAudioCodec: options.onAudioCodec ?? null,
12402
- onAudioTrack: null,
12948
+ onAudioTrack: options.onAudioTrack ?? null,
12403
12949
  onContainer: options.onContainer ?? null,
12404
12950
  onDimensions: options.onDimensions ?? null,
12405
12951
  selectM3uStream: options.selectM3uStream ?? defaultSelectM3uStreamFn,
12406
12952
  selectM3uAssociatedPlaylists: options.selectM3uAssociatedPlaylists ?? defaultSelectM3uAssociatedPlaylists,
12953
+ mp4HeaderSegment: options.mp4HeaderSegment ?? null,
12407
12954
  onDiscardedData: async (data) => {
12408
12955
  await content.write(data);
12409
12956
  },
@@ -12433,9 +12980,9 @@ var downloadAndParseMedia = async (options) => {
12433
12980
  onTracks: options.onTracks ?? null,
12434
12981
  onUnrotatedDimensions: options.onUnrotatedDimensions ?? null,
12435
12982
  onVideoCodec: options.onVideoCodec ?? null,
12436
- onVideoTrack: null,
12983
+ onVideoTrack: options.onVideoTrack ?? null,
12437
12984
  progressIntervalInMs: options.progressIntervalInMs ?? null,
12438
- reader: options.reader ?? fetchReader,
12985
+ reader: options.reader ?? webReader,
12439
12986
  controller: options.controller ?? undefined,
12440
12987
  src: options.src,
12441
12988
  onError: async (err) => {
@@ -12454,7 +13001,7 @@ var downloadAndParseMedia = async (options) => {
12454
13001
  return returnValue;
12455
13002
  };
12456
13003
  // src/version.ts
12457
- var VERSION = "4.0.270";
13004
+ var VERSION = "4.0.272";
12458
13005
 
12459
13006
  // src/index.ts
12460
13007
  var MediaParserInternals = {
@@ -12473,6 +13020,8 @@ var MediaParserInternals = {
12473
13020
  internalParseMedia
12474
13021
  };
12475
13022
  export {
13023
+ parseMediaOnWebWorker,
13024
+ parseMediaOnServerWorker,
12476
13025
  parseMedia,
12477
13026
  mediaParserController,
12478
13027
  hasBeenAborted,
@@ -12483,7 +13032,6 @@ export {
12483
13032
  MediaParserInternals,
12484
13033
  MediaParserAbortError,
12485
13034
  IsAnUnsupportedFileTypeError,
12486
- IsAnUnsupportedAudioTypeError,
12487
13035
  IsAnImageError,
12488
13036
  IsAPdfError,
12489
13037
  IsAGifError