From 26841c5b1c73bbe660d9371345035c1cc36422d6 Mon Sep 17 00:00:00 2001 From: Harvey Zhao Date: Mon, 4 May 2026 13:11:27 +0800 Subject: [PATCH] feat: enable fullscreenWeb option in Artplayer configuration feat: add danmuku plugin and i18n setup documentation - Introduced a new danmuku plugin with multiple run code options in the documentation. - Added language settings documentation for i18n, including default languages, import instructions, and examples for adding and modifying languages. - Implemented input handling for media sources in the artplayer-proxy-mediabunny package, supporting various formats including HLS. - Created m3u8 control functionalities for managing audio and video quality settings in the player. Update mediabunny.js --- AGENTS.md | 287 + docs/assets/example/mediabunny.js | 50 +- .../assets/ts/artplayer-proxy-mediabunny.d.ts | 30 + docs/compiled/artplayer-proxy-mediabunny.js | 4 +- .../artplayer-proxy-mediabunny.legacy.js | 4 +- docs/compiled/artplayer-proxy-mediabunny.mjs | 24612 +++++++++------ docs/compiled/artplayer.js | 2 +- docs/compiled/artplayer.legacy.js | 2 +- docs/compiled/artplayer.mjs | 2 +- docs/document/404.html | 4 +- docs/document/advanced/built-in.html | 6 +- docs/document/advanced/class.html | 6 +- docs/document/advanced/event.html | 6 +- docs/document/advanced/global.html | 6 +- docs/document/advanced/plugin.html | 6 +- docs/document/advanced/property.html | 6 +- .../{app.CDNxlRra.js => app.CkD0mcCX.js} | 2 +- .../{theme.DA2WZC55.js => theme.DqsiyDQE.js} | 2 +- .../chunks/virtual_search-data.B1Wl_n0C.js | 1404 - .../chunks/virtual_search-data.CYnorm-S.js | 1404 + ...md.DFeypQS9.js => en_index.md.Clwh28HI.js} | 8 +- ...9.lean.js => en_index.md.Clwh28HI.lean.js} | 2 +- ..._MHRXn.js => en_start_i18n.md.BLwUSSfJ.js} | 2 +- ...n.js => en_start_i18n.md.BLwUSSfJ.lean.js} | 0 ...ex.md.DhvU8bFi.js => index.md.CZIHn4-e.js} | 8 +- ...8bFi.lean.js => index.md.CZIHn4-e.lean.js} | 2 +- ...3kpeJ.js => plugin_danmuku.md.FiBSjkUz.js} | 2 +- ....js => plugin_danmuku.md.FiBSjkUz.lean.js} | 0 ....CWsZb7Vr.js => start_i18n.md.CDm9a8pv.js} | 2 +- ...lean.js => start_i18n.md.CDm9a8pv.lean.js} | 0 docs/document/component/contextmenu.html | 6 +- docs/document/component/controls.html | 6 +- docs/document/component/layers.html | 6 +- docs/document/component/setting.html | 6 +- docs/document/en/advanced/built-in.html | 6 +- docs/document/en/advanced/class.html | 6 +- docs/document/en/advanced/event.html | 6 +- docs/document/en/advanced/global.html | 6 +- docs/document/en/advanced/plugin.html | 6 +- docs/document/en/advanced/property.html | 6 +- docs/document/en/component/contextmenu.html | 6 +- docs/document/en/component/controls.html | 6 +- docs/document/en/component/layers.html | 6 +- docs/document/en/component/setting.html | 6 +- docs/document/en/index.html | 18 +- docs/document/en/start/i18n.html | 10 +- docs/document/en/start/option.html | 6 +- docs/document/hashmap.json | 2 +- docs/document/index.html | 18 +- docs/document/plugin/danmuku.html | 10 +- docs/document/start/i18n.html | 10 +- docs/document/start/option.html | 6 +- .../artplayer-proxy-mediabunny/index.js | 24620 ++++++++++------ packages/artplayer-proxy-mediabunny/README.md | 2 +- .../dist/artplayer-proxy-mediabunny.js | 4 +- .../dist/artplayer-proxy-mediabunny.legacy.js | 4 +- .../dist/artplayer-proxy-mediabunny.mjs | 24612 +++++++++------ .../artplayer-proxy-mediabunny/package.json | 4 +- .../src/AudioEngine.js | 44 +- .../src/MediaBunnyEngine.js | 153 +- .../src/VideoEngine.js | 47 +- .../src/VideoShim.js | 12 + .../artplayer-proxy-mediabunny/src/index.js | 4 + .../artplayer-proxy-mediabunny/src/input.js | 120 + .../artplayer-proxy-mediabunny/src/m3u8.js | 191 + .../types/artplayer-proxy-mediabunny.d.ts | 30 + packages/artplayer/dist/artplayer.js | 2 +- packages/artplayer/dist/artplayer.legacy.js | 2 +- packages/artplayer/dist/artplayer.mjs | 2 +- 69 files changed, 49762 insertions(+), 28126 deletions(-) create mode 100644 AGENTS.md rename docs/document/assets/{app.CDNxlRra.js => app.CkD0mcCX.js} (95%) rename docs/document/assets/chunks/{theme.DA2WZC55.js => theme.DqsiyDQE.js} (99%) delete mode 100644 docs/document/assets/chunks/virtual_search-data.B1Wl_n0C.js create mode 100644 docs/document/assets/chunks/virtual_search-data.CYnorm-S.js rename docs/document/assets/{en_index.md.DFeypQS9.js => en_index.md.Clwh28HI.js} (91%) rename docs/document/assets/{en_index.md.DFeypQS9.lean.js => en_index.md.Clwh28HI.lean.js} (84%) rename docs/document/assets/{en_start_i18n.md.Cg_MHRXn.js => en_start_i18n.md.BLwUSSfJ.js} (98%) rename docs/document/assets/{en_start_i18n.md.Cg_MHRXn.lean.js => en_start_i18n.md.BLwUSSfJ.lean.js} (100%) rename docs/document/assets/{index.md.DhvU8bFi.js => index.md.CZIHn4-e.js} (91%) rename docs/document/assets/{index.md.DhvU8bFi.lean.js => index.md.CZIHn4-e.lean.js} (84%) rename docs/document/assets/{plugin_danmuku.md.BVV3kpeJ.js => plugin_danmuku.md.FiBSjkUz.js} (99%) rename docs/document/assets/{plugin_danmuku.md.BVV3kpeJ.lean.js => plugin_danmuku.md.FiBSjkUz.lean.js} (100%) rename docs/document/assets/{start_i18n.md.CWsZb7Vr.js => start_i18n.md.CDm9a8pv.js} (98%) rename docs/document/assets/{start_i18n.md.CWsZb7Vr.lean.js => start_i18n.md.CDm9a8pv.lean.js} (100%) create mode 100644 packages/artplayer-proxy-mediabunny/src/input.js create mode 100644 packages/artplayer-proxy-mediabunny/src/m3u8.js diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..61b64c56a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,287 @@ +# AGENTS.md + +## Project Summary + +ArtPlayer is a monorepo for a modern HTML5 video player and its ecosystem packages. + +- Homepage: `https://artplayer.org` +- Local dev site: `http://localhost:8082` +- API docs: `https://artplayer.org/document` +- Packaging model: workspace monorepo with per-package versioning and per-package build output + +The repository contains: + +- `packages/artplayer`: the core player +- `packages/artplayer-plugin-*`: UI and playback plugins +- `packages/artplayer-proxy-*`: proxy renderers and playback adapters +- `packages/artplayer-tool-*`: helper tools +- `packages/artplayer-vitepress`: docs site package +- `docs/`: local demo site, examples, compiled assets, generated docs +- `scripts/`: custom build/dev/doc tooling + +## Working Style For This Repo + +- Verify the real implementation before editing docs or examples. +- Prefer changing the source package first, then regenerate build artifacts only when needed. +- Keep package APIs small and consistent with existing ArtPlayer plugin conventions. +- Preserve the existing visual and API style of sibling packages instead of inventing a new pattern. +- When touching demo examples, make sure the example still works in `http://localhost:8082`. +- Do not hand-edit `dist/`, `docs/compiled/`, or `docs/uncompiled/` unless a build step generated them. + +## Primary Commands + +Use the repo scripts rather than ad hoc bundler commands. + +### Development + +```bash +npm run dev +``` + +Starts the local dev site on port `8082` and interactively selects a package to watch. The selected package is built into: + +- `docs/uncompiled//` + +### Production Build + +```bash +npm run build +``` + +Interactive build for one package. Outputs: + +- `packages//dist/*.js|*.legacy.js|*.mjs` +- copied artifacts into `docs/compiled/` + +Build all packages: + +```bash +npm run build all +``` + +### Other Project Scripts + +```bash +npm run build:i18n +npm run build:ts +npm run build:docs +npm run build:llm +npm run build:test +npm run lint +npm run build:all +``` + +Notes: + +- `npm run lint` targets package source/types plus scripts and TypeScript demo assets. +- `npm run build:all` is expensive; use it when a change truly spans builds/docs/types/lint together. + +## Useful Local URLs + +- Root demo index: `http://localhost:8082` +- Demo by package/example: + - `http://localhost:8082/?libs=./uncompiled//index.js&example=` +- Docs: `http://localhost:8082/document/` + +For proxy/plugin work, prefer validating on the local demo page rather than reasoning only from source. + +## Repository Layout + +### Core package + +- `packages/artplayer/src/index.js`: player entry +- `packages/artplayer/src/player/`: playback mixins and player-facing behavior +- `packages/artplayer/src/control/`: bottom controls +- `packages/artplayer/src/setting/`: settings panel +- `packages/artplayer/src/contextmenu/`: context menu items +- `packages/artplayer/src/plugins/`: built-in plugins +- `packages/artplayer/src/utils/`: shared helpers, component base classes, DOM utilities +- `packages/artplayer/types/`: public TS declarations + +### Ecosystem packages + +Most ecosystem packages follow this pattern: + +```text +packages// + src/index.js + src/*.less # optional + types/*.d.ts # optional but preferred for public APIs + README.md + package.json + dist/* +``` + +### Demo and docs assets + +- `docs/assets/example/*.js`: runnable browser examples +- `docs/assets/ts/*.js`: TypeScript demo assets targeted by lint/docs flows +- `docs/uncompiled/`: dev output +- `docs/compiled/`: production-copied output +- `docs/document/`: generated docs content + +## Architecture Notes + +### Core player + +ArtPlayer composes many subsystems during construction. Common integration points: + +- `art.template` +- `art.events` +- `art.controls` +- `art.setting` +- `art.contextmenu` +- `art.layers` +- `art.plugins` +- `art.player` + +When extending behavior, prefer integrating with these existing systems rather than bypassing them. + +### Control and setting components + +Controls and setting entries are managed through component registries. + +Relevant implementation: + +- `packages/artplayer/src/control/index.js` +- `packages/artplayer/src/setting/index.js` +- `packages/artplayer/src/utils/component.js` + +Important behavior: + +- `art.controls.update(...)` and `art.setting.update(...)` replace existing entries by `name` +- `art.controls.remove(name)` and `art.setting.remove(name)` are the correct cleanup APIs +- selector-style controls rely on `default` flags to determine highlighted items + +If a plugin conditionally shows UI, it must also clean that UI up when the condition no longer holds. + +### Plugin shape + +Standard plugin/export shape: + +```js +export default function somePlugin(option = {}) { + return (art) => { + return { + name: 'somePlugin', + } + } +} +``` + +Naming conventions: + +- package: `artplayer-plugin-` +- global: `artplayerPlugin` +- exported function name should match the global naming convention + +### Proxy packages + +Proxy packages usually return a non-video element or video-like shim and emulate media element behavior for ArtPlayer. + +Examples: + +- `packages/artplayer-proxy-canvas` +- `packages/artplayer-proxy-mediabunny` + +When editing proxy packages: + +- keep the HTMLMediaElement-like surface coherent +- keep event ordering stable +- treat `loadedmetadata`, `loadeddata`, `canplay`, `seeked`, `waiting`, and `pause/play` semantics carefully +- ensure UI state is updated and cleaned up when source topology changes + +### HLS / adaptive playback controls + +The reference implementation for adaptive selector UI is: + +- `packages/artplayer-plugin-hls-control/src/index.js` + +If adding HLS-like quality/audio selection elsewhere: + +- follow the selector format used there +- derive highlighted items from actual current tracks, not only from mode flags +- avoid stale selectors when changing to streams without the same topology + +## Build and Artifact Rules + +- Always edit `src/` and `types/` first. +- Rebuild package artifacts after source changes that should ship. +- Do not treat `dist/` as source of truth. +- If a change affects demo behavior, also verify the matching file in `docs/assets/example/`. + +For package-specific builds, the normal flow is: + +1. `npm run dev` and pick the package for fast local iteration +2. validate in `http://localhost:8082` +3. `npm run build` and pick the package when ready to update shippable artifacts + +## Documentation Expectations + +If a public package API changes, check whether these also need updates: + +- the package `README.md` +- `docs/assets/example/.js` +- `types/.d.ts` +- any generated compiled outputs if you built the package + +Keep examples realistic and runnable. Prefer local demo URLs or stable public sample streams. + +## Code Quality Expectations + +- Follow existing plain JavaScript style in the repo. +- Use ASCII unless a file already requires otherwise. +- Match the minimal-comment style of neighboring files. +- Avoid unnecessary abstraction; this codebase generally prefers direct implementation. +- Respect current browser targets: + - modern build: `es2020` + - legacy build: `es2015` + +## Validation Checklist + +For most package changes, validate as many of these as apply: + +- source file lint passes +- local demo page loads +- expected events fire once and in the correct order +- controls/settings render correctly +- cleanup works after restart, source switch, or destroy +- package build succeeds + +For playback/proxy changes specifically: + +- test initial load +- test play/pause +- test seek +- test switching source or track topology +- test whether UI reflects the actual selected track/quality + +## Notes Specific To `artplayer-proxy-mediabunny` + +This package now depends on modern `mediabunny` and supports HLS through `mediabunny` input handling. + +Files to understand first: + +- `packages/artplayer-proxy-mediabunny/src/index.js` +- `packages/artplayer-proxy-mediabunny/src/VideoShim.js` +- `packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.js` +- `packages/artplayer-proxy-mediabunny/src/input.js` +- `packages/artplayer-proxy-mediabunny/src/m3u8.js` + +Key expectations: + +- HLS source detection should happen in `input.js` +- track selection should use actual pairable audio/video relationships +- selector UI should mirror the behavior of `artplayer-plugin-hls-control` +- selector cleanup is required when a later source no longer supports the same controls +- avoid duplicate readiness events during load and track switches + +## When Unsure + +Start with the nearest sibling implementation instead of inventing a new pattern: + +- control/setting UI: `artplayer-plugin-hls-control`, `artplayer-plugin-dash-control` +- proxy behavior: `artplayer-proxy-canvas`, `artplayer-proxy-mediabunny` +- component lifecycle: `packages/artplayer/src/utils/component.js` + +If a change spans source, examples, and packaging, make all three consistent in the same pass. diff --git a/docs/assets/example/mediabunny.js b/docs/assets/example/mediabunny.js index 716c174ed..9fe4e9558 100644 --- a/docs/assets/example/mediabunny.js +++ b/docs/assets/example/mediabunny.js @@ -2,24 +2,34 @@ // import artplayerProxyMediabunny from 'artplayer-proxy-mediabunny'; const art = new Artplayer({ - container: '.artplayer-app', - url: 'https://artplayer.org/assets/sample/frag_bunny.mp4', - autoSize: true, - screenshot: true, - setting: true, - loop: true, - flip: true, - playbackRate: true, - fullscreen: true, - fullscreenWeb: true, - miniProgressBar: true, - autoPlayback: true, - autoOrientation: true, - thumbnails: { - url: '/assets/sample/frag_bunny.png', - number: 60, - column: 10, - scale: 0.85, + container: '.artplayer-app', + url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8', + autoSize: true, + setting: true, + loop: true, + flip: true, + playbackRate: true, + fullscreen: true, + fullscreenWeb: true, + miniProgressBar: true, + autoPlayback: true, + autoOrientation: true, + proxy: artplayerProxyMediabunny({ + m3u8: { + quality: { + control: true, + setting: true, + getName: level => level.height ? `${level.height}P` : level.name, + title: 'Quality', + auto: 'Auto', + }, + audio: { + control: true, + setting: true, + getName: track => track.name || track.language, + title: 'Audio', + auto: 'Auto', + }, }, - proxy: artplayerProxyMediabunny(), -}) \ No newline at end of file + }), +}) diff --git a/docs/assets/ts/artplayer-proxy-mediabunny.d.ts b/docs/assets/ts/artplayer-proxy-mediabunny.d.ts index 823eb12ab..8c177aeee 100644 --- a/docs/assets/ts/artplayer-proxy-mediabunny.d.ts +++ b/docs/assets/ts/artplayer-proxy-mediabunny.d.ts @@ -1,4 +1,34 @@ interface Option { + m3u8?: { + quality?: { + control?: boolean + setting?: boolean + title?: string + auto?: string + getName?: (level: { + id: number + index: number + name: null | string + height: number + bitrate: number + }) => string + } + audio?: { + control?: boolean + setting?: boolean + title?: string + auto?: string + getName?: (track: { + id: number + index: number + name: null | string + lang: string + language: string + bitrate: number + }) => string + } + } + /** * Timeout for loading media in milliseconds * @default 0 diff --git a/docs/compiled/artplayer-proxy-mediabunny.js b/docs/compiled/artplayer-proxy-mediabunny.js index d783a9953..d2213fb12 100644 --- a/docs/compiled/artplayer-proxy-mediabunny.js +++ b/docs/compiled/artplayer-proxy-mediabunny.js @@ -1,7 +1,7 @@ /*! - * artplayer-proxy-mediabunny.js v1.1.0 + * artplayer-proxy-mediabunny.js v1.2.0 * Github: https://github.com/zhw2590582/ArtPlayer * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";class e{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const r=this.listeners.get(e);if(!r)return;const i=r.indexOf(t);i>=0&&r.splice(i,1)}emit(e,t){const r=new Event(e);r.detail=t;const i=this.listeners.get(e);i&&i.forEach(e=>e(r))}}function t(e){if(!e)throw new Error("Assertion failed.")}const r=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},i=e=>e&&e[e.length-1];class a{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){const e=Math.floor(this.pos/8),t=this.bytes[e]??0,r=7-(7&this.pos),i=(t&1<>r;return this.pos++,i}readBits(e){if(1===e)return this.readBit();let t=0;for(let r=0;r>r-i-1<{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<{const t=s(e);return 0===(1&t)?-(t>>1):t+1>>1},o=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),c=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),l=new TextDecoder,d=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),u={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},h=d(u),m={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},f=d(m),p={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},g=d(p),k=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class b{constructor(){this.currentPromise=Promise.resolve()}async acquire(){let e;const t=new Promise(t=>{e=t}),r=this.currentPromise;return this.currentPromise=t,await r,e}}const T=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),y=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,w=(e,t,r)=>{let i=0,a=e.length-1,s=-1;for(;i<=a;){const n=i+a>>1,o=r(e[n]);o===t?(s=n,a=n-1):o{let i=0,a=e.length-1,s=-1;for(;i<=a;){const n=i+(a-i+1)/2|0;r(e[n])<=t?(s=n,i=n+1):a=n-1}return s},I=(e,t,r)=>{const i=S(e,r(t),r);e.splice(i+1,0,t)},v=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},P=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return e[r]},x=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return r;return-1},C=e=>{throw new Error(`Unexpected value: ${e}`)},_=(e,t,r)=>{const i=e.getUint8(t),a=e.getUint8(t+1),s=e.getUint8(t+2);return r?i|a<<8|s<<16:i<<16|a<<8|s},B=(e,t,r,i)=>{r>>>=0,r&=16777215,e.setUint8(t,r>>>16&255),e.setUint8(t+1,r>>>8&255),e.setUint8(t+2,255&r)},E=(e,t)=>({async next(){const r=await e.next();return r.done?{value:void 0,done:!0}:{value:t(r.value),done:!1}},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),F=(e,t,r)=>Math.max(t,Math.min(r,e)),D="und",A=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},R=/^[a-z]{3}$/,M=e=>R.test(e),N=1e6*(1+Number.EPSILON),z=(e,t)=>{const r={...e,...t};if(e.headers||t.headers){const i=e.headers?O(e.headers):{},a=t.headers?O(t.headers):{},s={...i};Object.entries(a).forEach(([e,t])=>{const r=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());r&&delete s[r],s[e]=t}),r.headers=s}return r},O=e=>{if(e instanceof Headers){const t={};return e.forEach((e,r)=>{t[r]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,r])=>{t[e]=r}),t}return e},L=async(e,t,r,i,a)=>{let s=0;for(;;)try{return await e(t,r)}catch(n){if(a())throw n;s++;const e=i(s,n,t);if(null===e)throw n;if(console.error("Retrying failed fetch. Error:",n),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&await new Promise(t=>setTimeout(t,1e3*e)),a())throw n}};class U{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let V=null;const q=()=>null!==V?V:V=!("undefined"===typeof navigator||!(navigator.vendor?.match(/apple/i)||/AppleWebKit/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)||/\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent)));let H=null;const W=()=>null!==H?H:H="undefined"!==typeof navigator&&navigator.userAgent?.includes("Firefox");let j=null;const K=()=>null!==j?j:j=!("undefined"===typeof navigator||!navigator.vendor?.includes("Google Inc")&&!/Chrome/.test(navigator.userAgent));let $=null;const Q=(e,t)=>-1!==e?e:t,G=(e,t,r,i)=>e<=i&&r<=t,X=e=>{const t=atob(e),r=new Uint8Array(t.length);for(let i=0;i{Symbol.dispose??(Symbol.dispose=Symbol("Symbol.dispose"))},J=e=>"number"===typeof e&&!Number.isNaN(e);class Z{constructor(e,t){if(this.data=e,this.mimeType=t,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("string"!==typeof t)throw new TypeError("mimeType must be a string.")}}class ee{constructor(e,t,r,i){if(this.data=e,this.mimeType=t,this.name=r,this.description=i,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if(void 0!==t&&"string"!==typeof t)throw new TypeError("mimeType, when provided, must be a string.");if(void 0!==r&&"string"!==typeof r)throw new TypeError("name, when provided, must be a string.");if(void 0!==i&&"string"!==typeof i)throw new TypeError("description, when provided, must be a string.")}}const te={default:!0,forced:!1,original:!1,commentary:!1,hearingImpaired:!1,visuallyImpaired:!1},re=["pcm-s16","pcm-s16be","pcm-s24","pcm-s24be","pcm-s32","pcm-s32be","pcm-f32","pcm-f32be","pcm-f64","pcm-f64be","pcm-u8","pcm-s8","ulaw","alaw"],ie=[{maxPictureSize:36864,maxBitrate:2e5,level:10},{maxPictureSize:73728,maxBitrate:8e5,level:11},{maxPictureSize:122880,maxBitrate:18e5,level:20},{maxPictureSize:245760,maxBitrate:36e5,level:21},{maxPictureSize:552960,maxBitrate:72e5,level:30},{maxPictureSize:983040,maxBitrate:12e6,level:31},{maxPictureSize:2228224,maxBitrate:18e6,level:40},{maxPictureSize:2228224,maxBitrate:3e7,level:41},{maxPictureSize:8912896,maxBitrate:6e7,level:50},{maxPictureSize:8912896,maxBitrate:12e7,level:51},{maxPictureSize:8912896,maxBitrate:18e7,level:52},{maxPictureSize:35651584,maxBitrate:18e7,level:60},{maxPictureSize:35651584,maxBitrate:24e7,level:61},{maxPictureSize:35651584,maxBitrate:48e7,level:62}],ae=".01.01.01.01.00",se=".0.110.01.01.01.0",ne=e=>{const{codec:r,codecDescription:a,colorSpace:s,avcCodecInfo:n,hevcCodecInfo:o,vp9CodecInfo:l,av1CodecInfo:d}=e;if("avc"===r){if(t(null!==e.avcType),n){const t=new Uint8Array([n.avcProfileIndication,n.profileCompatibility,n.avcLevelIndication]);return`avc${e.avcType}.${T(t)}`}if(!a||a.byteLength<4)throw new TypeError("AVC decoder description is not provided or is not at least 4 bytes long.");return`avc${e.avcType}.${T(a.subarray(1,4))}`}if("hevc"===r){let e,t,r,i,s,n;if(o)e=o.generalProfileSpace,t=o.generalProfileIdc,r=y(o.generalProfileCompatibilityFlags),i=o.generalTierFlag,s=o.generalLevelIdc,n=[...o.generalConstraintIndicatorFlags];else{if(!a||a.byteLength<23)throw new TypeError("HEVC decoder description is not provided or is not at least 23 bytes long.");const o=c(a),l=o.getUint8(1);e=l>>6&3,t=31&l,r=y(o.getUint32(2)),i=l>>5&1,s=o.getUint8(12),n=[];for(let e=0;e<6;e++)n.push(o.getUint8(6+e))}let l="hev1.";for(l+=["","A","B","C"][e]+t,l+=".",l+=r.toString(16).toUpperCase(),l+=".",l+=0===i?"L":"H",l+=s;n.length>0&&0===n[n.length-1];)n.pop();return n.length>0&&(l+=".",l+=n.map(e=>e.toString(16).toUpperCase()).join(".")),l}if("vp8"===r)return"vp8";if("vp9"===r){if(!l){const t=e.width*e.height;let r=i(ie).level;for(const e of ie)if(t<=e.maxPictureSize){r=e.level;break}return`vp09.00.${r.toString().padStart(2,"0")}.08`}let t=`vp09.${l.profile.toString().padStart(2,"0")}.${l.level.toString().padStart(2,"0")}.${l.bitDepth.toString().padStart(2,"0")}.${l.chromaSubsampling.toString().padStart(2,"0")}`;return t+=`.${l.colourPrimaries.toString().padStart(2,"0")}.${l.transferCharacteristics.toString().padStart(2,"0")}.${l.matrixCoefficients.toString().padStart(2,"0")}.${l.videoFullRangeFlag.toString().padStart(2,"0")}`,t.endsWith(ae)&&(t=t.slice(0,-15)),t}if("av1"===r){if(!d){const t=e.width*e.height;let r=i(ie).level;for(const e of ie)if(t<=e.maxPictureSize){r=e.level;break}return`av01.0.${r.toString().padStart(2,"0")}M.08`}const t=d.profile,r=d.level.toString().padStart(2,"0"),a=d.tier?"H":"M",n=d.bitDepth.toString().padStart(2,"0"),o=d.monochrome?"1":"0",c=100*d.chromaSubsamplingX+10*d.chromaSubsamplingY+1*(d.chromaSubsamplingX&&d.chromaSubsamplingY?d.chromaSamplePosition:0),l=s?.primaries?u[s.primaries]:1,h=s?.transfer?m[s.transfer]:1,f=s?.matrix?p[s.matrix]:1,g=s?.fullRange?1:0;let k=`av01.${t}.${r}${a}.${n}`;return k+=`.${o}.${c.toString().padStart(3,"0")}`,k+=`.${l.toString().padStart(2,"0")}`,k+=`.${h.toString().padStart(2,"0")}`,k+=`.${f.toString().padStart(2,"0")}`,k+=`.${g}`,k.endsWith(se)&&(k=k.slice(0,-17)),k}throw new TypeError(`Unhandled codec '${r}'.`)},oe=e=>{const{codec:t,codecDescription:r,aacCodecInfo:i}=e;if("aac"===t){if(!i)throw new TypeError("AAC codec info must be provided.");if(i.isMpeg2)return"mp4a.67";return`mp4a.40.${de(r).objectType}`}if("mp3"===t)return"mp3";if("opus"===t)return"opus";if("vorbis"===t)return"vorbis";if("flac"===t)return"flac";if(t&&re.includes(t))return t;throw new TypeError(`Unhandled codec '${t}'.`)},ce=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350],le=[-1,1,2,3,4,5,6,8],de=e=>{if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");const t=new a(e);let r=t.readBits(5);31===r&&(r=32+t.readBits(6));const i=t.readBits(4);let s=null;15===i?s=t.readBits(24):i=1&&n<=7&&(o=le[n]),{objectType:r,frequencyIndex:i,sampleRate:s,channelConfiguration:n,numberOfChannels:o}},ue=48e3,he=/^pcm-([usf])(\d+)+(be)?$/,me=e=>{if(t(re.includes(e)),"ulaw"===e)return{dataType:"ulaw",sampleSize:1,littleEndian:!0,silentValue:255};if("alaw"===e)return{dataType:"alaw",sampleSize:1,littleEndian:!0,silentValue:213};const r=he.exec(e);let i;t(r),i="u"===r[1]?"unsigned":"s"===r[1]?"signed":"float";return{dataType:i,sampleSize:Number(r[2])/8,littleEndian:"be"!==r[3],silentValue:"pcm-u8"===e?128:0}};var fe,pe,ge,ke;(pe=fe||(fe={}))[pe.IDR=5]="IDR",pe[pe.SEI=6]="SEI",pe[pe.SPS=7]="SPS",pe[pe.PPS=8]="PPS",pe[pe.SPS_EXT=13]="SPS_EXT",(ke=ge||(ge={}))[ke.RASL_N=8]="RASL_N",ke[ke.RASL_R=9]="RASL_R",ke[ke.BLA_W_LP=16]="BLA_W_LP",ke[ke.RSV_IRAP_VCL23=23]="RSV_IRAP_VCL23",ke[ke.VPS_NUT=32]="VPS_NUT",ke[ke.SPS_NUT=33]="SPS_NUT",ke[ke.PPS_NUT=34]="PPS_NUT",ke[ke.PREFIX_SEI_NUT=39]="PREFIX_SEI_NUT",ke[ke.SUFFIX_SEI_NUT=40]="SUFFIX_SEI_NUT";const be=e=>{const t=[];let r=0;for(;r0&&i>r){const a=e.subarray(r,i);a.length>0&&t.push(a)}r=i+a}if(r0&&t.push(i)}return t},Te=(e,r)=>{const i=[];let a=0;const s=new DataView(e.buffer,e.byteOffset,e.byteLength);for(;a+r<=e.length;){let n;1===r?n=s.getUint8(a):2===r?n=s.getUint16(a,!1):3===r?n=_(s,a,!1):4===r?n=s.getUint32(a,!1):(C(r),t(!1)),a+=r;const o=e.subarray(a,a+n);i.push(o),a+=n}return i},ye=e=>{const t=[],r=e.length;for(let i=0;i{if(t.description){const r=3&o(t.description)[4];return Te(e,r+1)}return be(e)},Ie=(e,t)=>{if(t.description){return((e,t)=>{const r=e.reduce((e,r)=>e+t+r.byteLength,0),i=new Uint8Array(r);let a=0;for(const s of e){const e=new DataView(i.buffer,i.byteOffset,i.byteLength);switch(t){case 1:e.setUint8(a,s.byteLength);break;case 2:e.setUint16(a,s.byteLength,!1);break;case 3:B(e,a,s.byteLength);break;case 4:e.setUint32(a,s.byteLength,!1)}a+=t,i.set(s,a),a+=s.byteLength}return i})(e,(3&o(t.description)[4])+1)}return(e=>{const t=e.reduce((e,t)=>e+we.byteLength+t.byteLength,0),r=new Uint8Array(t);let i=0;for(const a of e)r.set(we,i),i+=we.byteLength,r.set(a,i),i+=a.byteLength;return r})(e)},ve=e=>31&e[0],Pe=e=>{try{const r=be(e),i=r.filter(e=>ve(e)===fe.SPS),a=r.filter(e=>ve(e)===fe.PPS),s=r.filter(e=>ve(e)===fe.SPS_EXT);if(0===i.length)return null;if(0===a.length)return null;const n=i[0],o=xe(n);t(null!==o);const c=100===o.profileIdc||110===o.profileIdc||122===o.profileIdc||144===o.profileIdc;return{configurationVersion:1,avcProfileIndication:o.profileIdc,profileCompatibility:o.constraintFlags,avcLevelIndication:o.levelIdc,lengthSizeMinusOne:3,sequenceParameterSets:i,pictureParameterSets:a,chromaFormat:c?o.chromaFormatIdc:null,bitDepthLumaMinus8:c?o.bitDepthLumaMinus8:null,bitDepthChromaMinus8:c?o.bitDepthChromaMinus8:null,sequenceParameterSetExt:c?s:null}}catch(r){return console.error("Error building AVC Decoder Configuration Record:",r),null}},xe=e=>{try{const t=new a(ye(e));t.skipBits(1),t.skipBits(2);if(7!==t.readBits(5))return null;const r=t.readAlignedByte(),i=t.readAlignedByte(),o=t.readAlignedByte();s(t);let c=null,l=null,d=null;if(100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r){c=s(t),3===c&&t.skipBits(1),l=s(t),d=s(t),t.skipBits(1);if(t.readBits(1))for(let e=0;e<(3!==c?8:12);e++){if(t.readBits(1)){const r=e<6?16:64;let i=8,a=8;for(let e=0;e{if(t.description){const r=3&o(t.description)[21];return Te(e,r+1)}return be(e)},_e=e=>e[0]>>1&63,Be=e=>{try{const t=be(e),r=t.filter(e=>_e(e)===ge.VPS_NUT),i=t.filter(e=>_e(e)===ge.SPS_NUT),o=t.filter(e=>_e(e)===ge.PPS_NUT),c=t.filter(e=>_e(e)===ge.PREFIX_SEI_NUT||_e(e)===ge.SUFFIX_SEI_NUT);if(0===i.length||0===o.length)return null;const l=i[0],d=new a(ye(l));d.skipBits(16),d.readBits(4);const u=d.readBits(3),h=d.readBits(1),{general_profile_space:m,general_tier_flag:f,general_profile_idc:p,general_profile_compatibility_flags:g,general_constraint_indicator_flags:k,general_level_idc:b}=Ee(d,u);s(d);const T=s(d);3===T&&d.skipBits(1),s(d),s(d),d.readBits(1)&&(s(d),s(d),s(d),s(d));const y=s(d),w=s(d);s(d);const S=d.readBits(1);for(let e=S?0:u;e<=u;e++)s(d),s(d),s(d);s(d),s(d),s(d),s(d),s(d),s(d),d.readBits(1)&&d.readBits(1)&&Fe(d),d.skipBits(1),d.skipBits(1),d.readBits(1)&&(d.skipBits(4),d.skipBits(4),s(d),s(d),d.skipBits(1));const I=s(d);if(De(d,I),d.readBits(1)){const e=s(d);for(let t=0;t0){const e=o[0],t=new a(ye(e));t.skipBits(16),s(t),s(t),t.skipBits(1),t.skipBits(1),t.skipBits(3),t.skipBits(1),t.skipBits(1),s(t),s(t),n(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&s(t),n(t),n(t),t.skipBits(1),t.skipBits(1),t.skipBits(1),t.skipBits(1);const r=t.readBits(1),i=t.readBits(1);P=r||i?r&&!i?2:!r&&i?3:0:0}const x=[...r.length?[{arrayCompleteness:1,nalUnitType:ge.VPS_NUT,nalUnits:r}]:[],...i.length?[{arrayCompleteness:1,nalUnitType:ge.SPS_NUT,nalUnits:i}]:[],...o.length?[{arrayCompleteness:1,nalUnitType:ge.PPS_NUT,nalUnits:o}]:[],...c.length?[{arrayCompleteness:1,nalUnitType:_e(c[0]),nalUnits:c}]:[]];return{configurationVersion:1,generalProfileSpace:m,generalTierFlag:f,generalProfileIdc:p,generalProfileCompatibilityFlags:g,generalConstraintIndicatorFlags:k,generalLevelIdc:b,minSpatialSegmentationIdc:v,parallelismType:P,chromaFormatIdc:T,bitDepthLumaMinus8:y,bitDepthChromaMinus8:w,avgFrameRate:0,constantFrameRate:0,numTemporalLayers:u+1,temporalIdNested:h,lengthSizeMinusOne:3,arrays:x}}catch(t){return console.error("Error building HEVC Decoder Configuration Record:",t),null}},Ee=(e,t)=>{const r=e.readBits(2),i=e.readBits(1),a=e.readBits(5);let s=0;for(let d=0;d<32;d++)s=s<<1|e.readBits(1);const n=new Uint8Array(6);for(let d=0;d<6;d++)n[d]=e.readBits(8);const o=e.readBits(8),c=[],l=[];for(let d=0;d0)for(let d=t;d<8;d++)e.skipBits(2);for(let d=0;d{for(let t=0;t<4;t++)for(let r=0;r<(3===t?2:6);r++){if(e.readBits(1)){const r=Math.min(64,1<<4+(t<<1));t>1&&n(e);for(let t=0;t{const r=[];for(let i=0;i{let a=0,n=0,o=0;if(0!==t&&(n=e.readBits(1)),n){if(t===r){o=t-(s(e)+1)}else o=t-1;e.readBits(1),s(e);const n=i[o]??0;for(let t=0;t<=n;t++){e.readBits(1)||e.readBits(1)}a=i[o]}else{const t=s(e),r=s(e);for(let i=0;i{if(e.readBits(1)){255===e.readBits(8)&&(e.readBits(16),e.readBits(16))}if(e.readBits(1)&&e.readBits(1),e.readBits(1)&&(e.readBits(3),e.readBits(1),e.readBits(1)&&(e.readBits(8),e.readBits(8),e.readBits(8))),e.readBits(1)&&(s(e),s(e)),e.readBits(1),e.readBits(1),e.readBits(1),e.readBits(1)&&(s(e),s(e),s(e),s(e)),e.readBits(1)&&(e.readBits(32),e.readBits(32),e.readBits(1)&&s(e),e.readBits(1)&&Me(e,!0,t)),e.readBits(1)){e.readBits(1),e.readBits(1),e.readBits(1);const t=s(e);return s(e),s(e),s(e),s(e),t}return 0},Me=(e,t,r)=>{let i=!1,a=!1,n=!1;i=1===e.readBits(1),a=1===e.readBits(1),(i||a)&&(n=1===e.readBits(1),n&&(e.readBits(8),e.readBits(5),e.readBits(1),e.readBits(5)),e.readBits(4),e.readBits(4),n&&e.readBits(4),e.readBits(5),e.readBits(5),e.readBits(5));for(let o=0;o<=r;o++){let t=!0;1===e.readBits(1)||(t=1===e.readBits(1));let r=!1;t?s(e):r=1===e.readBits(1);let o=1;if(!r){o=s(e)+1}i&&Ne(e,o,n),a&&Ne(e,o,n)}},Ne=(e,t,r)=>{for(let i=0;i{const t=new a(e);if(2!==t.readBits(2))return null;const r=t.readBits(1),s=(t.readBits(1)<<1)+r;3===s&&t.skipBits(1);if(1===t.readBits(1))return null;if(0!==t.readBits(1))return null;t.skipBits(2);if(4817730!==t.readBits(24))return null;let n=8;if(s>=2){n=t.readBits(1)?12:10}const o=t.readBits(3);let c=0,l=0;if(7!==o){if(l=t.readBits(1),1===s||3===s){const e=t.readBits(1),r=t.readBits(1);c=e||r?e&&!r?2:1:3,t.skipBits(1)}else c=1}else c=3,l=1;const d=(t.readBits(16)+1)*(t.readBits(16)+1);let u=i(ie).level;for(const i of ie)if(d<=i.maxPictureSize){u=i.level;break}return{profile:s,level:u,bitDepth:n,chromaSubsampling:c,videoFullRangeFlag:l,colourPrimaries:2===o?1:1===o?6:2,transferCharacteristics:2===o?1:1===o?6:2,matrixCoefficients:7===o?0:2===o?1:1===o?6:2}},Oe=function*(e){const r=new a(e),i=()=>{let e=0;for(let t=0;t<8;t++){const i=r.readAlignedByte();if(e|=(127&i)<<7*t,!(128&i))break;if(7===t&&128&i)return null}return e>=2**32-1?null:e};for(;r.getBitsLeft()>=8;){r.skipBits(1);const a=r.readBits(4),s=r.readBits(1),n=r.readBits(1);let o;if(r.skipBits(1),s&&r.skipBits(8),n){const e=i();if(null===e)return;o=e}else o=Math.floor(r.getBitsLeft()/8);t(r.pos%8===0),yield{type:a,data:e.subarray(r.pos/8,r.pos/8+o)},r.skipBits(8*o)}},Le=e=>{for(const{type:t,data:r}of Oe(e)){if(1!==t)continue;const e=new a(r),i=e.readBits(3);e.readBits(1);const s=e.readBits(1);let n=0,o=0,c=0;if(s)n=e.readBits(5);else{if(e.readBits(1)){e.skipBits(32),e.skipBits(32);if(e.readBits(1))return null}const t=e.readBits(1);t&&(c=e.readBits(5),e.skipBits(32),e.skipBits(5),e.skipBits(5));const r=e.readBits(5);for(let i=0;i<=r;i++){e.skipBits(12);const r=e.readBits(5);if(0===i&&(n=r),r>7){const t=e.readBits(1);0===i&&(o=t)}if(t){if(e.readBits(1)){const t=c+1;e.skipBits(t),e.skipBits(t),e.skipBits(1)}}e.readBits(1)&&e.skipBits(4)}}const l=e.readBits(4),d=e.readBits(4),u=l+1;e.skipBits(u);const h=d+1;e.skipBits(h);let m=0;if(m=s?0:e.readBits(1),m&&(e.skipBits(4),e.skipBits(3)),e.skipBits(1),e.skipBits(1),e.skipBits(1),!s){e.skipBits(1),e.skipBits(1),e.skipBits(1),e.skipBits(1);const t=e.readBits(1);t&&(e.skipBits(1),e.skipBits(1));let r=0;if(r=e.readBits(1)?2:e.readBits(1),r>0){e.readBits(1)||e.skipBits(1)}t&&e.skipBits(3)}e.skipBits(1),e.skipBits(1),e.skipBits(1);const f=e.readBits(1);let p=8;if(2===i&&f){p=e.readBits(1)?12:10}else i<=2&&(p=f?10:8);let g=0;1!==i&&(g=e.readBits(1));let k=1,b=1,T=0;return g||(0===i?(k=1,b=1):1===i?(k=0,b=0):12===p&&(k=e.readBits(1),k&&(b=e.readBits(1))),k&&b&&(T=e.readBits(2))),{profile:i,level:n,tier:o,bitDepth:p,monochrome:g,chromaSubsamplingX:k,chromaSubsamplingY:b,chromaSamplePosition:T}}return null},Ue=[480,960,1920,2880,480,960,1920,2880,480,960,1920,2880,480,960,480,960,120,240,480,960,120,240,480,960,120,240,480,960,120,240,480,960],Ve=e=>{if(e.length<7)throw new Error("Setup header is too short.");if(5!==e[0])throw new Error("Wrong packet type in Setup header.");if("vorbis"!==String.fromCharCode(...e.slice(1,7)))throw new Error("Invalid packet signature in Setup header.");const t=e.length,r=new Uint8Array(t);for(let a=0;a97;)if(1===i.readBits(1)){s=i.pos;break}if(0===s)throw new Error("Invalid Setup header: framing bit not found.");let n=0,o=!1,c=0;for(;i.getBitsLeft()>=97;){const e=i.pos,t=i.readBits(8),r=i.readBits(16),a=i.readBits(16);if(t>63||0!==r||0!==a){i.pos=e;break}if(i.skipBits(1),n++,n>64)break;i.clone().readBits(6)+1===n&&(o=!0,c=n)}if(!o)throw new Error("Invalid Setup header: mode header not found.");if(c>63)throw new Error(`Unsupported mode count: ${c}.`);const l=c;i.pos=0,i.skipBits(s);const d=Array(l).fill(0);for(let a=l-1;a>=0;a--)i.skipBits(40),d[a]=i.readBits(1);return{modeBlockflags:d}},qe=(e,r,i)=>{switch(e){case"avc":{const e=Se(i,r);let t=e.some(e=>ve(e)===fe.IDR);if(!t&&(!K()||(()=>{if(null!==$)return $;if("undefined"===typeof navigator)return null;const e=/\bChrome\/(\d+)/.exec(navigator.userAgent);return e?$=Number(e[1]):null})()>=144))for(const r of e){if(ve(r)!==fe.SEI)continue;const e=ye(r);let i=1;do{let r=0;for(;;){const t=e[i++];if(void 0===t)break;if(r+=t,t<255)break}let n=0;for(;;){const t=e[i++];if(void 0===t)break;if(n+=t,t<255)break}if(r===6){const r=new a(e);r.pos=8*i;const n=s(r),o=r.readBits(1);if(0===n&&1===o){t=!0;break}}i+=n}while(i{const t=_e(e);return ge.BLA_W_LP<=t&&t<=ge.RSV_IRAP_VCL23})?"key":"delta";case"vp8":return 0===(1&i[0])?"key":"delta";case"vp9":{const e=new a(i);if(2!==e.readBits(2))return null;const t=e.readBits(1);3===(e.readBits(1)<<1)+t&&e.skipBits(1);if(e.readBits(1))return null;return 0===e.readBits(1)?"key":"delta"}case"av1":{let e=!1;for(const{type:t,data:r}of Oe(i))if(1===t){const t=new a(r);t.skipBits(4),e=!!t.readBits(1)}else if(3===t||6===t||7===t){if(e)return"key";const t=new a(r);if(t.readBits(1))return null;return 0===t.readBits(2)?"key":"delta"}return null}default:C(e),t(!1)}};var He,We;(We=He||(He={}))[We.STREAMINFO=0]="STREAMINFO",We[We.VORBIS_COMMENT=4]="VORBIS_COMMENT",We[We.PICTURE=6]="PICTURE";const je=(e,t)=>{var r,i;const a=c(e);let s=0;const n=a.getUint32(s,!0);s+=4;const o=l.decode(e.subarray(s,s+n));s+=n,n>0&&(t.raw??(t.raw={}),(r=t.raw).vendor??(r.vendor=o));const d=a.getUint32(s,!0);s+=4;for(let u=0;u0&&(t.trackNumber??(t.trackNumber=r)),i&&Number.isInteger(i)&&i>0&&(t.tracksTotal??(t.tracksTotal=i))}break;case"TRACKTOTAL":{const e=Number.parseInt(u,10);Number.isInteger(e)&&e>0&&(t.tracksTotal??(t.tracksTotal=e))}break;case"DISCNUMBER":{const e=u.split("/"),r=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(t.discNumber??(t.discNumber=r)),i&&Number.isInteger(i)&&i>0&&(t.discsTotal??(t.discsTotal=i))}break;case"DISCTOTAL":{const e=Number.parseInt(u,10);Number.isInteger(e)&&e>0&&(t.discsTotal??(t.discsTotal=e))}break;case"DATE":{const e=new Date(u);Number.isNaN(e.getTime())||(t.date??(t.date=e))}break;case"GENRE":t.genre??(t.genre=u);break;case"METADATA_BLOCK_PICTURE":{const e=X(u),r=c(e),i=r.getUint32(0,!1),a=r.getUint32(4,!1),s=String.fromCharCode(...e.subarray(8,8+a)),n=r.getUint32(8+a,!1),o=l.decode(e.subarray(12+a,12+a+n)),d=r.getUint32(a+n+28),h=e.subarray(a+n+32,a+n+32+d);t.images??(t.images=[]),t.images.push({data:h,mimeType:s,kind:3===i?"coverFront":4===i?"coverBack":"unknown",name:void 0,description:o||void 0})}}}};class Ke{constructor(e){this.input=e}}const $e=[],Qe=[],Ge=new Uint8Array(0);class Xe{constructor(e,t,r,i,a=-1,s,n){if(this.data=e,this.type=t,this.timestamp=r,this.duration=i,this.sequenceNumber=a,e===Ge&&void 0===s)throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets.");if(void 0===s&&(s=e.byteLength),!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("key"!==t&&"delta"!==t)throw new TypeError('type must be either "key" or "delta".');if(!Number.isFinite(r))throw new TypeError("timestamp must be a number.");if(!Number.isFinite(i)||i<0)throw new TypeError("duration must be a non-negative number.");if(!Number.isFinite(a))throw new TypeError("sequenceNumber must be a number.");if(!Number.isInteger(s)||s<0)throw new TypeError("byteLength must be a non-negative integer.");if(void 0!==n&&("object"!==typeof n||!n))throw new TypeError("sideData, when provided, must be an object.");if(void 0!==n?.alpha&&!(n.alpha instanceof Uint8Array))throw new TypeError("sideData.alpha, when provided, must be a Uint8Array.");if(void 0!==n?.alphaByteLength&&(!Number.isInteger(n.alphaByteLength)||n.alphaByteLength<0))throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer.");this.byteLength=s,this.sideData=n??{},this.sideData.alpha&&void 0===this.sideData.alphaByteLength&&(this.sideData.alphaByteLength=this.sideData.alpha.byteLength)}get isMetadataOnly(){return this.data===Ge}get microsecondTimestamp(){return Math.trunc(N*this.timestamp)}get microsecondDuration(){return Math.trunc(N*this.duration)}toEncodedVideoChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}alphaToEncodedVideoChunk(e=this.type){if(!this.sideData.alpha)throw new TypeError("This packet does not contain alpha side data.");if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.sideData.alpha,type:e,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}toEncodedAudioChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to an audio chunk.");if("undefined"===typeof EncodedAudioChunk)throw new Error("Your browser does not support EncodedAudioChunk.");return new EncodedAudioChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}static fromEncodedChunk(e,t){if(!(e instanceof EncodedVideoChunk||e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk.");const r=new Uint8Array(e.byteLength);return e.copyTo(r),new Xe(r,e.type,e.timestamp/1e6,(e.duration??0)/1e6,void 0,void 0,t)}clone(e){if(void 0!==e&&("object"!==typeof e||null===e))throw new TypeError("options, when provided, must be an object.");if(void 0!==e?.timestamp&&!Number.isFinite(e.timestamp))throw new TypeError("options.timestamp, when provided, must be a number.");if(void 0!==e?.duration&&!Number.isFinite(e.duration))throw new TypeError("options.duration, when provided, must be a number.");return new Xe(this.data,this.type,e?.timestamp??this.timestamp,e?.duration??this.duration,this.sequenceNumber,this.byteLength)}}Y();let Ye=-1/0,Je=-1/0,Ze=null;"undefined"!==typeof FinalizationRegistry&&(Ze=new FinalizationRegistry(e=>{const t=Date.now();"video"===e.type?(t-Ye>=1e3&&(console.error("A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them."),Ye=t),"undefined"!==typeof VideoFrame&&e.data instanceof VideoFrame&&e.data.close()):(t-Je>=1e3&&(console.error("An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them."),Je=t),"undefined"!==typeof AudioData&&e.data instanceof AudioData&&e.data.close())}));const et=["I420","I420P10","I420P12","I420A","I420AP10","I420AP12","I422","I422P10","I422P12","I422A","I422AP10","I422AP12","I444","I444P10","I444P12","I444A","I444AP10","I444AP12","NV12","RGBA","RGBX","BGRA","BGRX"],tt=new Set(et);class rt{get displayWidth(){return this.rotation%180===0?this.codedWidth:this.codedHeight}get displayHeight(){return this.rotation%180===0?this.codedHeight:this.codedWidth}get microsecondTimestamp(){return Math.trunc(N*this.timestamp)}get microsecondDuration(){return Math.trunc(N*this.duration)}get hasAlpha(){return this.format&&this.format.includes("A")}constructor(e,r){if(this._closed=!1,e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e)){if(!r||"object"!==typeof r)throw new TypeError("init must be an object.");if(void 0===r.format||!tt.has(r.format))throw new TypeError("init.format must be one of: "+et.join(", "));if(!Number.isInteger(r.codedWidth)||r.codedWidth<=0)throw new TypeError("init.codedWidth must be a positive integer.");if(!Number.isInteger(r.codedHeight)||r.codedHeight<=0)throw new TypeError("init.codedHeight must be a positive integer.");if(void 0!==r.rotation&&![0,90,180,270].includes(r.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(r.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==r.duration&&(!Number.isFinite(r.duration)||r.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");this._data=o(e).slice(),this._layout=r.layout??ct(r.format,r.codedWidth,r.codedHeight),this.format=r.format,this.codedWidth=r.codedWidth,this.codedHeight=r.codedHeight,this.rotation=r.rotation??0,this.timestamp=r.timestamp,this.duration=r.duration??0,this.colorSpace=new it(r.colorSpace)}else if("undefined"!==typeof VideoFrame&&e instanceof VideoFrame){if(void 0!==r?.rotation&&![0,90,180,270].includes(r.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(void 0!==r?.timestamp&&!Number.isFinite(r?.timestamp))throw new TypeError("init.timestamp, when provided, must be a number.");if(void 0!==r?.duration&&(!Number.isFinite(r.duration)||r.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");this._data=e,this._layout=null,this.format=e.format,this.codedWidth=e.displayWidth,this.codedHeight=e.displayHeight,this.rotation=r?.rotation??0,this.timestamp=r?.timestamp??e.timestamp/1e6,this.duration=r?.duration??(e.duration??0)/1e6,this.colorSpace=new it(e.colorSpace)}else{if(!("undefined"!==typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!==typeof SVGImageElement&&e instanceof SVGImageElement||"undefined"!==typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!==typeof HTMLVideoElement&&e instanceof HTMLVideoElement||"undefined"!==typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!==typeof OffscreenCanvas&&e instanceof OffscreenCanvas))throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource.");{if(!r||"object"!==typeof r)throw new TypeError("init must be an object.");if(void 0!==r.rotation&&![0,90,180,270].includes(r.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(r.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==r.duration&&(!Number.isFinite(r.duration)||r.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if("undefined"!==typeof VideoFrame)return new rt(new VideoFrame(e,{timestamp:Math.trunc(r.timestamp*N),duration:Math.trunc((r.duration??0)*N)||void 0}),r);let i=0,a=0;if("naturalWidth"in e?(i=e.naturalWidth,a=e.naturalHeight):"videoWidth"in e?(i=e.videoWidth,a=e.videoHeight):"width"in e&&(i=Number(e.width),a=Number(e.height)),!i||!a)throw new TypeError("Could not determine dimensions.");const s=new OffscreenCanvas(i,a),n=s.getContext("2d",{alpha:W(),willReadFrequently:!0});t(n),n.drawImage(e,0,0),this._data=s,this._layout=null,this.format="RGBX",this.codedWidth=i,this.codedHeight=a,this.rotation=r.rotation??0,this.timestamp=r.timestamp,this.duration=r.duration??0,this.colorSpace=new it({matrix:"rgb",primaries:"bt709",transfer:"iec61966-2-1",fullRange:!0})}}Ze?.register(this,{type:"video",data:this._data},this)}clone(){if(this._closed)throw new Error("VideoSample is closed.");return t(null!==this._data),at(this._data)?new rt(this._data.clone(),{timestamp:this.timestamp,duration:this.duration,rotation:this.rotation}):this._data instanceof Uint8Array?(t(this._layout),new rt(this._data,{format:this.format,layout:this._layout,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation})):new rt(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation})}close(){this._closed||(Ze?.unregister(this),at(this._data)?this._data.close():this._data=null,this._closed=!0)}allocationSize(e={}){if(ot(e),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot get allocation size when format is null. Sorry!");if(t(null!==this._data),!at(this._data)&&(e.colorSpace||e.format&&e.format!==this.format||e.layout||e.rect)){const t=this.toVideoFrame(),r=t.allocationSize(e);return t.close(),r}return at(this._data)?this._data.allocationSize(e):this._data instanceof Uint8Array?this._data.byteLength:this.codedWidth*this.codedHeight*4}async copyTo(e,r={}){if(!k(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(ot(r),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot copy video sample data when format is null. Sorry!");if(t(null!==this._data),!at(this._data)&&(r.colorSpace||r.format&&r.format!==this.format||r.layout||r.rect)){const t=this.toVideoFrame(),i=await t.copyTo(e,r);return t.close(),i}if(at(this._data))return this._data.copyTo(e,r);if(this._data instanceof Uint8Array){t(this._layout);return o(e).set(this._data),this._layout}{const r=this._data.getContext("2d");t(r);const i=r.getImageData(0,0,this.codedWidth,this.codedHeight);return o(e).set(i.data),[{offset:0,stride:4*this.codedWidth}]}}toVideoFrame(){if(this._closed)throw new Error("VideoSample is closed.");return t(null!==this._data),at(this._data)?new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0}):this._data instanceof Uint8Array?new VideoFrame(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0,colorSpace:this.colorSpace}):new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0})}draw(e,t,r,i,a,s,n,o,c){let l=0,d=0,u=this.displayWidth,h=this.displayHeight,m=0,f=0,p=this.displayWidth,g=this.displayHeight;if(void 0!==s?(l=t,d=r,u=i,h=a,m=s,f=n,void 0!==o?(p=o,g=c):(p=u,g=h)):(m=t,f=r,void 0!==i&&(p=i,g=a)),!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!Number.isFinite(l))throw new TypeError("sx must be a number.");if(!Number.isFinite(d))throw new TypeError("sy must be a number.");if(!Number.isFinite(u)||u<0)throw new TypeError("sWidth must be a non-negative number.");if(!Number.isFinite(h)||h<0)throw new TypeError("sHeight must be a non-negative number.");if(!Number.isFinite(m))throw new TypeError("dx must be a number.");if(!Number.isFinite(f))throw new TypeError("dy must be a number.");if(!Number.isFinite(p)||p<0)throw new TypeError("dWidth must be a non-negative number.");if(!Number.isFinite(g)||g<0)throw new TypeError("dHeight must be a non-negative number.");if(this._closed)throw new Error("VideoSample is closed.");({sx:l,sy:d,sWidth:u,sHeight:h}=this._rotateSourceRegion(l,d,u,h,this.rotation));const k=this.toCanvasImageSource();e.save();const b=m+p/2,T=f+g/2;e.translate(b,T),e.rotate(this.rotation*Math.PI/180);const y=this.rotation%180===0?1:p/g;e.scale(1/y,y),e.drawImage(k,l,d,u,h,-p/2,-g/2,p,g),e.restore()}drawWithFit(e,t){if(!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!["fill","contain","cover"].includes(t.fit))throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270.");void 0!==t.crop&&nt(t.crop,"options.");const r=e.canvas.width,i=e.canvas.height,a=t.rotation??this.rotation,[s,n]=a%180===0?[this.codedWidth,this.codedHeight]:[this.codedHeight,this.codedWidth];let o,c,l,d;t.crop&&st(t.crop,s,n);const{sx:u,sy:h,sWidth:m,sHeight:f}=this._rotateSourceRegion(t.crop?.left??0,t.crop?.top??0,t.crop?.width??s,t.crop?.height??n,a);if("fill"===t.fit)o=0,c=0,l=r,d=i;else{const[e,a]=t.crop?[t.crop.width,t.crop.height]:[s,n],u="contain"===t.fit?Math.min(r/e,i/a):Math.max(r/e,i/a);l=e*u,d=a*u,o=(r-l)/2,c=(i-d)/2}e.save();const p=a%180===0?1:l/d;e.translate(r/2,i/2),e.rotate(a*Math.PI/180),e.scale(1/p,p),e.translate(-r/2,-i/2),e.drawImage(this.toCanvasImageSource(),u,h,m,f,o,c,l,d),e.restore()}_rotateSourceRegion(e,t,r,i,a){return 90===a?[e,t,r,i]=[t,this.codedHeight-e-r,i,r]:180===a?[e,t]=[this.codedWidth-e-r,this.codedHeight-t-i]:270===a&&([e,t,r,i]=[this.codedWidth-t-i,e,i,r]),{sx:e,sy:t,sWidth:r,sHeight:i}}toCanvasImageSource(){if(this._closed)throw new Error("VideoSample is closed.");if(t(null!==this._data),this._data instanceof Uint8Array){const e=this.toVideoFrame();return queueMicrotask(()=>e.close()),e}return this._data}setRotation(e){if(![0,90,180,270].includes(e))throw new TypeError("newRotation must be 0, 90, 180, or 270.");this.rotation=e}setTimestamp(e){if(!Number.isFinite(e))throw new TypeError("newTimestamp must be a number.");this.timestamp=e}setDuration(e){if(!Number.isFinite(e)||e<0)throw new TypeError("newDuration must be a non-negative number.");this.duration=e}[Symbol.dispose](){this.close()}}class it{constructor(e){this.primaries=e?.primaries??null,this.transfer=e?.transfer??null,this.matrix=e?.matrix??null,this.fullRange=e?.fullRange??null}toJSON(){return{primaries:this.primaries,transfer:this.transfer,matrix:this.matrix,fullRange:this.fullRange}}}const at=e=>"undefined"!==typeof VideoFrame&&e instanceof VideoFrame,st=(e,r,i)=>{e.left=Math.min(e.left,r),e.top=Math.min(e.top,i),e.width=Math.min(e.width,r-e.left),e.height=Math.min(e.height,i-e.top),t(e.width>=0),t(e.height>=0)},nt=(e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(t+"crop, when provided, must be an object.");if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(t+"crop.left must be a non-negative integer.");if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(t+"crop.top must be a non-negative integer.");if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(t+"crop.width must be a non-negative integer.");if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(t+"crop.height must be a non-negative integer.")},ot=e=>{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.colorSpace&&!["display-p3","srgb"].includes(e.colorSpace))throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");if(void 0!==e.format&&"string"!==typeof e.format)throw new TypeError("options.format, when provided, must be a string.");if(void 0!==e.layout){if(!Array.isArray(e.layout))throw new TypeError("options.layout, when provided, must be an array.");for(const t of e.layout){if(!t||"object"!==typeof t)throw new TypeError("Each entry in options.layout must be an object.");if(!Number.isInteger(t.offset)||t.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(t.stride)||t.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==e.rect){if(!e.rect||"object"!==typeof e.rect)throw new TypeError("options.rect, when provided, must be an object.");if(void 0!==e.rect.x&&(!Number.isInteger(e.rect.x)||e.rect.x<0))throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");if(void 0!==e.rect.y&&(!Number.isInteger(e.rect.y)||e.rect.y<0))throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");if(void 0!==e.rect.width&&(!Number.isInteger(e.rect.width)||e.rect.width<0))throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");if(void 0!==e.rect.height&&(!Number.isInteger(e.rect.height)||e.rect.height<0))throw new TypeError("options.rect.height, when provided, must be a non-negative integer.")}},ct=(e,t,r)=>{const i=lt(e),a=[];let s=0;for(const n of i){const e=Math.ceil(t/n.widthDivisor),i=Math.ceil(r/n.heightDivisor),o=e*n.sampleBytes,c=o*i;a.push({offset:s,stride:o}),s+=c}return a},lt=e=>{const r=(e,t,r,i,a)=>{const s=[{sampleBytes:e,widthDivisor:1,heightDivisor:1},{sampleBytes:t,widthDivisor:r,heightDivisor:i},{sampleBytes:t,widthDivisor:r,heightDivisor:i}];return a&&s.push({sampleBytes:e,widthDivisor:1,heightDivisor:1}),s};switch(e){case"I420":return r(1,1,2,2,!1);case"I420P10":case"I420P12":return r(2,2,2,2,!1);case"I420A":return r(1,1,2,2,!0);case"I420AP10":case"I420AP12":return r(2,2,2,2,!0);case"I422":return r(1,1,2,1,!1);case"I422P10":case"I422P12":return r(2,2,2,1,!1);case"I422A":return r(1,1,2,1,!0);case"I422AP10":case"I422AP12":return r(2,2,2,1,!0);case"I444":return r(1,1,1,1,!1);case"I444P10":case"I444P12":return r(2,2,1,1,!1);case"I444A":return r(1,1,1,1,!0);case"I444AP10":case"I444AP12":return r(2,2,1,1,!0);case"NV12":return[{sampleBytes:1,widthDivisor:1,heightDivisor:1},{sampleBytes:2,widthDivisor:2,heightDivisor:2}];case"RGBA":case"RGBX":case"BGRA":case"BGRX":return[{sampleBytes:4,widthDivisor:1,heightDivisor:1}];default:C(e),t(!1)}},dt=new Set(["f32","f32-planar","s16","s16-planar","s32","s32-planar","u8","u8-planar"]);class ut{get microsecondTimestamp(){return Math.trunc(N*this.timestamp)}get microsecondDuration(){return Math.trunc(N*this.duration)}constructor(e){if(this._closed=!1,gt(e)){if(null===e.format)throw new TypeError("AudioData with null format is not supported.");this._data=e,this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=e.numberOfFrames,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp/1e6,this.duration=e.numberOfFrames/e.sampleRate}else{if(!e||"object"!==typeof e)throw new TypeError("Invalid AudioDataInit: must be an object.");if(!dt.has(e.format))throw new TypeError("Invalid AudioDataInit: invalid format.");if(!Number.isFinite(e.sampleRate)||e.sampleRate<=0)throw new TypeError("Invalid AudioDataInit: sampleRate must be > 0.");if(!Number.isInteger(e.numberOfChannels)||0===e.numberOfChannels)throw new TypeError("Invalid AudioDataInit: numberOfChannels must be an integer > 0.");if(!Number.isFinite(e?.timestamp))throw new TypeError("init.timestamp must be a number.");const t=e.data.byteLength/(ht(e.format)*e.numberOfChannels);if(!Number.isInteger(t))throw new TypeError("Invalid AudioDataInit: data size is not a multiple of frame size.");let r;if(this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=t,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp,this.duration=t/e.sampleRate,e.data instanceof ArrayBuffer)r=new Uint8Array(e.data);else{if(!ArrayBuffer.isView(e.data))throw new TypeError("Invalid AudioDataInit: data is not a BufferSource.");r=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength)}const i=this.numberOfFrames*this.numberOfChannels*ht(this.format);if(r.byteLength=this.numberOfFrames)throw new RangeError("frameOffset out of range");const i=void 0!==e.frameCount?e.frameCount:this.numberOfFrames-r;if(i>this.numberOfFrames-r)throw new RangeError("frameCount out of range");const a=ht(t),s=mt(t);if(s&&e.planeIndex>=this.numberOfChannels)throw new RangeError("planeIndex out of range");if(!s&&0!==e.planeIndex)throw new RangeError("planeIndex out of range");return(s?i:i*this.numberOfChannels)*a}copyTo(e,t){if(!k(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!Number.isInteger(t.planeIndex)||t.planeIndex<0)throw new TypeError("planeIndex must be a non-negative integer.");if(void 0!==t.format&&!dt.has(t.format))throw new TypeError("Invalid format.");if(void 0!==t.frameOffset&&(!Number.isInteger(t.frameOffset)||t.frameOffset<0))throw new TypeError("frameOffset must be a non-negative integer.");if(void 0!==t.frameCount&&(!Number.isInteger(t.frameCount)||t.frameCount<0))throw new TypeError("frameCount must be a non-negative integer.");if(this._closed)throw new Error("AudioSample is closed.");const{planeIndex:r,format:i,frameCount:a,frameOffset:s}=t,n=this.format,o=i??this.format;if(!o)throw new Error("Destination format not determined");const l=this.numberOfFrames,d=this.numberOfChannels,u=s??0;if(u>=l)throw new RangeError("frameOffset out of range");const h=void 0!==a?a:l-u;if(h>l-u)throw new RangeError("frameCount out of range");const m=ht(o),f=mt(o);if(f&&r>=d)throw new RangeError("planeIndex out of range");if(!f&&0!==r)throw new RangeError("planeIndex out of range");const p=(f?h:h*d)*m;if(e.byteLength2&&o!==n?kt(this._data,g,n,o,d,r,u,h):this._data.copyTo(e,{planeIndex:r,frameOffset:u,frameCount:h,format:o});else{const e=this._data,t=c(e),i=ft(n),a=ht(n),s=mt(n);for(let n=0;n0;){const a=Math.min(s,o),c=new Float32Array(r*a);for(let t=0;t0;){const a=Math.min(s,o),l=new Float32Array(r*a);for(let t=0;t{switch(e){case"u8":case"u8-planar":return 1;case"s16":case"s16-planar":return 2;case"s32":case"s32-planar":case"f32":case"f32-planar":return 4;default:throw new Error("Unknown AudioSampleFormat")}},mt=e=>{switch(e){case"u8-planar":case"s16-planar":case"s32-planar":case"f32-planar":return!0;default:return!1}},ft=e=>{switch(e){case"u8":case"u8-planar":return(e,t)=>(e.getUint8(t)-128)/128;case"s16":case"s16-planar":return(e,t)=>e.getInt16(t,!0)/32768;case"s32":case"s32-planar":return(e,t)=>e.getInt32(t,!0)/2147483648;case"f32":case"f32-planar":return(e,t)=>e.getFloat32(t,!0)}},pt=e=>{switch(e){case"u8":case"u8-planar":return(e,t,r)=>e.setUint8(t,F(127.5*(r+1),0,255));case"s16":case"s16-planar":return(e,t,r)=>e.setInt16(t,F(Math.round(32767*r),-32768,32767),!0);case"s32":case"s32-planar":return(e,t,r)=>e.setInt32(t,F(Math.round(2147483647*r),-2147483648,2147483647),!0);case"f32":case"f32-planar":return(e,t,r)=>e.setFloat32(t,r,!0)}},gt=e=>"undefined"!==typeof AudioData&&e instanceof AudioData,kt=(e,t,r,i,a,s,n,o)=>{const l=ft(r),d=pt(i),u=ht(r),h=ht(i),m=mt(r);if(mt(i))if(m){const i=new ArrayBuffer(o*u),a=c(i);e.copyTo(i,{planeIndex:s,frameOffset:n,frameCount:o,format:r});for(let e=0;e{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.metadataOnly&&"boolean"!==typeof e.metadataOnly)throw new TypeError("options.metadataOnly, when defined, must be a boolean.");if(void 0!==e.verifyKeyPackets&&"boolean"!==typeof e.verifyKeyPackets)throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");if(e.verifyKeyPackets&&e.metadataOnly)throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.")},Tt=e=>{if(!J(e))throw new TypeError("timestamp must be a number.")},yt=(e,t,r)=>r.verifyKeyPackets?t.then(async t=>{if(!t||"delta"===t.type)return t;const r=await e.determinePacketType(t);return r&&(t.type=r),t}):t;class wt{constructor(e){if(!(e instanceof At))throw new TypeError("track must be an InputTrack.");this._track=e}getFirstPacket(e={}){if(bt(e),this._track.input._disposed)throw new ea;return yt(this._track,this._track._backing.getFirstPacket(e),e)}getPacket(e,t={}){if(Tt(e),bt(t),this._track.input._disposed)throw new ea;return yt(this._track,this._track._backing.getPacket(e,t),t)}getNextPacket(e,t={}){if(!(e instanceof Xe))throw new TypeError("packet must be an EncodedPacket.");if(bt(t),this._track.input._disposed)throw new ea;return yt(this._track,this._track._backing.getNextPacket(e,t),t)}async getKeyPacket(e,r={}){if(Tt(e),bt(r),this._track.input._disposed)throw new ea;if(!r.verifyKeyPackets)return this._track._backing.getKeyPacket(e,r);const i=await this._track._backing.getKeyPacket(e,r);if(!i)return i;t("key"===i.type);return"delta"===await this._track.determinePacketType(i)?this.getKeyPacket(i.timestamp-1/this._track.timeResolution,r):i}async getNextKeyPacket(e,r={}){if(!(e instanceof Xe))throw new TypeError("packet must be an EncodedPacket.");if(bt(r),this._track.input._disposed)throw new ea;if(!r.verifyKeyPackets)return this._track._backing.getNextKeyPacket(e,r);const i=await this._track._backing.getNextKeyPacket(e,r);if(!i)return i;t("key"===i.type);return"delta"===await this._track.determinePacketType(i)?this.getNextKeyPacket(i,r):i}packets(e,t,r={}){if(void 0!==e&&!(e instanceof Xe))throw new TypeError("startPacket must be an EncodedPacket.");if(void 0!==e&&e.isMetadataOnly&&!r?.metadataOnly)throw new TypeError("startPacket can only be metadata-only if options.metadataOnly is enabled.");if(void 0!==t&&!(t instanceof Xe))throw new TypeError("endPacket must be an EncodedPacket.");if(bt(r),this._track.input._disposed)throw new ea;const i=[];let{promise:a,resolve:s}=v(),{promise:n,resolve:o}=v(),c=!1,l=!1,d=null;const u=[],h=()=>Math.max(2,u.length);(async()=>{let d=e??await this.getFirstPacket(r);for(;d&&!l&&!this._track.input._disposed&&!(t&&d.sequenceNumber>=t?.sequenceNumber);)i.length>h()?(({promise:n,resolve:o}=v()),await n):(i.push(d),s(),({promise:a,resolve:s}=v()),d=await this.getNextPacket(d,r));c=!0,s()})().catch(e=>{d||(d=e,s())});const m=this._track;return{async next(){for(;;){if(m.input._disposed)throw new ea;if(l)return{value:void 0,done:!0};if(d)throw d;if(i.length>0){const e=i.shift(),t=performance.now();for(u.push(t);u.length>0&&t-u[0]>=1e3;)u.shift();return o(),{value:e,done:!1}}if(c)return{value:void 0,done:!0};await a}},return:async()=>(l=!0,o(),s(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}}class St{constructor(e,t){this.onSample=e,this.onError=t}}class It{mediaSamplesInRange(e=0,t=1/0){Tt(e),Tt(t);const r=[];let i=!1,a=null,{promise:s,resolve:n}=v(),{promise:o,resolve:c}=v(),l=!1,d=!1,u=!1,h=null;(async()=>{const m=await this._createDecoder(o=>{c(),o.timestamp>=t&&(d=!0),d?o.close():(a&&(o.timestamp>e?(r.push(a),i=!0):a.close()),o.timestamp>=e&&(r.push(o),i=!0),a=i?null:o,r.length>0&&(n(),({promise:s,resolve:n}=v())))},e=>{h||(h=e,n())}),f=this._createPacketSink(),p=await f.getKeyPacket(e,{verifyKeyPackets:!0})??await f.getFirstPacket();let g=p;const k=f.packets(p??void 0,void 0);for(await k.next();g&&!d&&!this._track.input._disposed;){const e=vt(r.length);if(r.length+m.getDecodeQueueSize()>e){({promise:o,resolve:c}=v()),await o;continue}m.decode(g);const t=await k.next();if(t.done)break;g=t.value}await k.return(),u||this._track.input._disposed||await m.flush(),m.close(),!i&&a&&r.push(a),l=!0,n()})().catch(e=>{h||(h=e,n())});const m=this._track,f=()=>{a?.close();for(const e of r)e.close()};return{async next(){for(;;){if(m.input._disposed)throw f(),new ea;if(u)return{value:void 0,done:!0};if(h)throw f(),h;if(r.length>0){const e=r.shift();return c(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};await s}},return:async()=>(u=!0,d=!0,c(),n(),f(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}mediaSamplesAtTimestamps(e){(e=>{if(!(Symbol.iterator in e)&&!(Symbol.asyncIterator in e))throw new TypeError("Argument must be an iterable or async iterable.")})(e);const r=async function*(e){Symbol.iterator in e?yield*e[Symbol.iterator]():yield*e[Symbol.asyncIterator]()}(e),i=[],a=[];let{promise:s,resolve:n}=v(),{promise:o,resolve:c}=v(),l=!1,d=!1,u=null;const h=e=>{a.push(e),n(),({promise:s,resolve:n}=v())};(async()=>{const e=await this._createDecoder(e=>{if(c(),d)return void e.close();let t=0;for(;i.length>0&&e.timestamp-i[0]>-1e-10;)t++,i.shift();if(t>0)for(let r=0;r{u||(u=e,n())}),s=this._createPacketSink();let m=null,f=null,p=-1;const g=async()=>{t(f);let r=f;for(e.decode(r);r.sequenceNumberi&&!d;)({promise:o,resolve:c}=v()),await o;if(d)break;const n=await s.getNextPacket(r);t(n),e.decode(n),r=n}p=-1},k=async()=>{await e.flush();for(let e=0;e{u||(u=e,n())});const m=this._track,f=()=>{for(const e of a)e?.close()};return{async next(){for(;;){if(m.input._disposed)throw f(),new ea;if(d)return{value:void 0,done:!0};if(u)throw f(),u;if(a.length>0){const e=a.shift();return t(void 0!==e),c(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};await s}},return:async()=>(d=!0,c(),n(),f(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}}const vt=e=>0===e?40:8;class Pt extends St{constructor(e,r,i,a,s,n){super(e,r),this.codec=i,this.decoderConfig=a,this.rotation=s,this.timeResolution=n,this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new U,this.customDecoderQueueSize=0,this.inputTimestamps=[],this.sampleQueue=[],this.currentPacketIndex=0,this.raslSkipped=!1,this.alphaDecoder=null,this.alphaHadKeyframe=!1,this.colorQueue=[],this.alphaQueue=[],this.merger=null,this.mergerCreationFailed=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue=[],this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1;const l=$e.find(e=>e.supports(i,a));if(l)this.customDecoder=new l,this.customDecoder.codec=i,this.customDecoder.config=a,this.customDecoder.onSample=e=>{if(!(e instanceof rt))throw new TypeError("The argument passed to onSample must be a VideoSample.");this.finalizeAndEmitSample(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=e=>{if(this.alphaQueue.length>0){const r=this.alphaQueue.shift();t(void 0!==r),this.mergeAlpha(e,r)}else this.colorQueue.push(e)};if("avc"===i&&this.decoderConfig.description&&K()){const e=(e=>{try{const t=c(e);let r=0;const i=t.getUint8(r++),a=t.getUint8(r++),s=t.getUint8(r++),n=t.getUint8(r++),o=3&t.getUint8(r++),l=31&t.getUint8(r++),d=[];for(let c=0;c0){const t=xe(e.sequenceParameterSets[0]);t&&0===t.frameMbsOnlyFlag&&(this.decoderConfig={...this.decoderConfig,hardwareAcceleration:"prefer-software"})}}const r=new Error("Decoding error").stack;this.decoder=new VideoDecoder({output:t=>{try{e(t)}catch(r){this.onError(r)}},error:e=>{e.stack=r,this.onError(e)}}),this.decoder.configure(this.decoderConfig)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(t(this.decoder),Math.max(this.decoder.decodeQueueSize,this.alphaDecoder?.decodeQueueSize??0))}decode(e){if("hevc"===this.codec&&this.currentPacketIndex>0&&!this.raslSkipped){if(this.hasHevcRaslPicture(e.data))return;this.raslSkipped=!0}if(this.customDecoder)this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--);else{if(t(this.decoder),q()||I(this.inputTimestamps,e.timestamp,e=>e),K()&&0===this.currentPacketIndex&&"avc"===this.codec){const t=Se(e.data,this.decoderConfig).filter(e=>{const t=ve(e);return!(t>=20&&t<=31)}),r=Ie(t,this.decoderConfig);e=new Xe(r,e.type,e.timestamp,e.duration)}this.decoder.decode(e.toEncodedVideoChunk()),this.decodeAlphaData(e)}this.currentPacketIndex++}decodeAlphaData(e){if(!e.sideData.alpha||this.mergerCreationFailed)return void this.pushNullAlphaFrame();if(!this.merger)try{this.merger=new xt}catch(i){return console.error("Due to an error, only color data will be decoded.",i),this.mergerCreationFailed=!0,void this.decodeAlphaData(e)}if(!this.alphaDecoder){const e=e=>{if(this.alphaDecoderQueueSize--,this.colorQueue.length>0){const r=this.colorQueue.shift();t(void 0!==r),this.mergeAlpha(r,e)}else this.alphaQueue.push(e);for(this.decodedAlphaChunkCount++;this.nullAlphaFrameQueue.length>0&&this.nullAlphaFrameQueue[0]===this.decodedAlphaChunkCount;)if(this.nullAlphaFrameQueue.shift(),this.colorQueue.length>0){const e=this.colorQueue.shift();t(void 0!==e),this.mergeAlpha(e,null)}else this.alphaQueue.push(null)},r=new Error("Decoding error").stack;this.alphaDecoder=new VideoDecoder({output:t=>{try{e(t)}catch(i){this.onError(i)}},error:e=>{e.stack=r,this.onError(e)}}),this.alphaDecoder.configure(this.decoderConfig)}const r=qe(this.codec,this.decoderConfig,e.sideData.alpha);if(this.alphaHadKeyframe||(this.alphaHadKeyframe="key"===r),this.alphaHadKeyframe){if("hevc"===this.codec&&this.currentAlphaPacketIndex>0&&!this.alphaRaslSkipped){if(this.hasHevcRaslPicture(e.sideData.alpha))return void this.pushNullAlphaFrame();this.alphaRaslSkipped=!0}this.currentAlphaPacketIndex++,this.alphaDecoder.decode(e.alphaToEncodedVideoChunk(r??e.type)),this.alphaDecoderQueueSize++}else this.pushNullAlphaFrame()}pushNullAlphaFrame(){0===this.alphaDecoderQueueSize?this.alphaQueue.push(null):this.nullAlphaFrameQueue.push(this.decodedAlphaChunkCount+this.alphaDecoderQueueSize)}hasHevcRaslPicture(e){return Ce(e,this.decoderConfig).some(e=>{const t=_e(e);return t===ge.RASL_N||t===ge.RASL_R})}sampleHandler(e){if(q()){if(this.sampleQueue.length>0&&e.timestamp>=i(this.sampleQueue).timestamp){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}I(this.sampleQueue,e,e=>e.timestamp)}else{const r=this.inputTimestamps.shift();t(void 0!==r),e.setTimestamp(r),this.finalizeAndEmitSample(e)}}finalizeAndEmitSample(e){e.setTimestamp(Math.round(e.timestamp*this.timeResolution)/this.timeResolution),e.setDuration(Math.round(e.duration*this.timeResolution)/this.timeResolution),e.setRotation(this.rotation),this.onSample(e)}mergeAlpha(e,r){if(!r){const t=new rt(e);return void this.sampleHandler(t)}t(this.merger),this.merger.update(e,r),e.close(),r.close();const i=new VideoFrame(this.merger.canvas,{timestamp:e.timestamp,duration:e.duration??void 0}),a=new rt(i);this.sampleHandler(a)}async flush(){if(this.customDecoder?await this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(t(this.decoder),await Promise.all([this.decoder.flush(),this.alphaDecoder?.flush()]),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>e?.close()),this.alphaQueue.length=0,this.alphaHadKeyframe=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue.length=0,this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1),q()){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}this.currentPacketIndex=0,this.raslSkipped=!1}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(t(this.decoder),this.decoder.close(),this.alphaDecoder?.close(),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>e?.close()),this.alphaQueue.length=0,this.merger?.close());for(const e of this.sampleQueue)e.close();this.sampleQueue.length=0}}class xt{constructor(){"undefined"!==typeof OffscreenCanvas?this.canvas=new OffscreenCanvas(300,150):this.canvas=document.createElement("canvas");const e=this.canvas.getContext("webgl2",{premultipliedAlpha:!1});if(!e)throw new Error("Couldn't acquire WebGL 2 context.");this.gl=e,this.program=this.createProgram(),this.vao=this.createVAO(),this.colorTexture=this.createTexture(),this.alphaTexture=this.createTexture(),this.gl.useProgram(this.program),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_colorTexture"),0),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_alphaTexture"),1)}createProgram(){const e=this.createShader(this.gl.VERTEX_SHADER,"#version 300 es\n\t\t\tin vec2 a_position;\n\t\t\tin vec2 a_texCoord;\n\t\t\tout vec2 v_texCoord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = vec4(a_position, 0.0, 1.0);\n\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t}\n\t\t"),t=this.createShader(this.gl.FRAGMENT_SHADER,"#version 300 es\n\t\t\tprecision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_colorTexture;\n\t\t\tuniform sampler2D u_alphaTexture;\n\t\t\tin vec2 v_texCoord;\n\t\t\tout vec4 fragColor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture(u_colorTexture, v_texCoord).rgb;\n\t\t\t\tfloat alpha = texture(u_alphaTexture, v_texCoord).r;\n\t\t\t\tfragColor = vec4(color, alpha);\n\t\t\t}\n\t\t"),r=this.gl.createProgram();return this.gl.attachShader(r,e),this.gl.attachShader(r,t),this.gl.linkProgram(r),r}createShader(e,t){const r=this.gl.createShader(e);return this.gl.shaderSource(r,t),this.gl.compileShader(r),r}createVAO(){const e=this.gl.createVertexArray();this.gl.bindVertexArray(e);const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),r=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,r),this.gl.bufferData(this.gl.ARRAY_BUFFER,t,this.gl.STATIC_DRAW);const i=this.gl.getAttribLocation(this.program,"a_position"),a=this.gl.getAttribLocation(this.program,"a_texCoord");return this.gl.enableVertexAttribArray(i),this.gl.vertexAttribPointer(i,2,this.gl.FLOAT,!1,16,0),this.gl.enableVertexAttribArray(a),this.gl.vertexAttribPointer(a,2,this.gl.FLOAT,!1,16,8),e}createTexture(){const e=this.gl.createTexture();return this.gl.bindTexture(this.gl.TEXTURE_2D,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),e}update(e,t){e.displayWidth===this.canvas.width&&e.displayHeight===this.canvas.height||(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colorTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),this.gl.activeTexture(this.gl.TEXTURE1),this.gl.bindTexture(this.gl.TEXTURE_2D,this.alphaTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.bindVertexArray(this.vao),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)}close(){this.gl.getExtension("WEBGL_lose_context")?.loseContext(),this.gl=null}}class Ct extends It{constructor(e){if(!(e instanceof Rt))throw new TypeError("videoTrack must be an InputVideoTrack.");super(),this._track=e}async _createDecoder(e,r){if(!(await this._track.canDecode()))throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track.");const i=this._track.codec,a=this._track.rotation,s=await this._track.getDecoderConfig(),n=this._track.timeResolution;return t(i&&s),new Pt(e,r,i,s,a,n)}_createPacketSink(){return new wt(this._track)}async getSample(e){Tt(e);for await(const t of this.mediaSamplesAtTimestamps([e]))return t;throw new Error("Internal error: Iterator returned nothing.")}samples(e=0,t=1/0){return this.mediaSamplesInRange(e,t)}samplesAtTimestamps(e){return this.mediaSamplesAtTimestamps(e)}}class _t{constructor(e,t={}){if(this._nextCanvasIndex=0,!(e instanceof Rt))throw new TypeError("videoTrack must be an InputVideoTrack.");if(t&&"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.alpha&&"boolean"!==typeof t.alpha)throw new TypeError("options.alpha, when provided, must be a boolean.");if(void 0!==t.width&&(!Number.isInteger(t.width)||t.width<=0))throw new TypeError("options.width, when defined, must be a positive integer.");if(void 0!==t.height&&(!Number.isInteger(t.height)||t.height<=0))throw new TypeError("options.height, when defined, must be a positive integer.");if(void 0!==t.fit&&!["fill","contain","cover"].includes(t.fit))throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".');if(void 0!==t.width&&void 0!==t.height&&void 0===t.fit)throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180 or 270.");if(void 0!==t.crop&&nt(t.crop,"options."),void 0!==t.poolSize&&("number"!==typeof t.poolSize||!Number.isInteger(t.poolSize)||t.poolSize<0))throw new TypeError("poolSize must be a non-negative integer.");const r=t.rotation??e.rotation,[i,a]=r%180===0?[e.codedWidth,e.codedHeight]:[e.codedHeight,e.codedWidth],s=t.crop;s&&st(s,i,a);let[n,o]=s?[s.width,s.height]:[i,a];const c=n/o;void 0!==t.width&&void 0===t.height?(n=t.width,o=Math.round(n/c)):void 0===t.width&&void 0!==t.height?(o=t.height,n=Math.round(o*c)):void 0!==t.width&&void 0!==t.height&&(n=t.width,o=t.height),this._videoTrack=e,this._alpha=t.alpha??!1,this._width=n,this._height=o,this._rotation=r,this._crop=s,this._fit=t.fit??"fill",this._videoSampleSink=new Ct(e),this._canvasPool=Array.from({length:t.poolSize??0},()=>null)}_videoSampleToWrappedCanvas(e){let r=this._canvasPool[this._nextCanvasIndex],i=!1;r||("undefined"!==typeof document?(r=document.createElement("canvas"),r.width=this._width,r.height=this._height):r=new OffscreenCanvas(this._width,this._height),this._canvasPool.length>0&&(this._canvasPool[this._nextCanvasIndex]=r),i=!0),this._canvasPool.length>0&&(this._nextCanvasIndex=(this._nextCanvasIndex+1)%this._canvasPool.length);const a=r.getContext("2d",{alpha:this._alpha||W()});t(a),a.resetTransform(),i||(!this._alpha&&W()?(a.fillStyle="black",a.fillRect(0,0,this._width,this._height)):a.clearRect(0,0,this._width,this._height)),e.drawWithFit(a,{fit:this._fit,rotation:this._rotation,crop:this._crop});const s={canvas:r,timestamp:e.timestamp,duration:e.duration};return e.close(),s}async getCanvas(e){Tt(e);const t=await this._videoSampleSink.getSample(e);return t&&this._videoSampleToWrappedCanvas(t)}canvases(e=0,t=1/0){return E(this._videoSampleSink.samples(e,t),e=>this._videoSampleToWrappedCanvas(e))}canvasesAtTimestamps(e){return E(this._videoSampleSink.samplesAtTimestamps(e),e=>e&&this._videoSampleToWrappedCanvas(e))}}class Bt extends St{constructor(e,t,r,i){super(e,t),this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new U,this.customDecoderQueueSize=0,this.currentTimestamp=null;const a=t=>{(null===this.currentTimestamp||Math.abs(t.timestamp-this.currentTimestamp)>=t.duration)&&(this.currentTimestamp=t.timestamp);const r=this.currentTimestamp;if(this.currentTimestamp+=t.duration,0===t.numberOfFrames)return void t.close();const a=i.sampleRate;t.setTimestamp(Math.round(r*a)/a),e(t)},s=Qe.find(e=>e.supports(r,i));if(s)this.customDecoder=new s,this.customDecoder.codec=r,this.customDecoder.config=i,this.customDecoder.onSample=e=>{if(!(e instanceof ut))throw new TypeError("The argument passed to onSample must be an AudioSample.");a(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=new Error("Decoding error").stack;this.decoder=new AudioDecoder({output:e=>{try{a(new ut(e))}catch(t){this.onError(t)}},error:t=>{t.stack=e,this.onError(t)}}),this.decoder.configure(i)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(t(this.decoder),this.decoder.decodeQueueSize)}decode(e){this.customDecoder?(this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--)):(t(this.decoder),this.decoder.decode(e.toEncodedAudioChunk()))}flush(){return this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(t(this.decoder),this.decoder.flush())}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(t(this.decoder),this.decoder.close())}}class Et extends St{constructor(e,r,i){super(e,r),this.decoderConfig=i,this.currentTimestamp=null,t(re.includes(i.codec)),this.codec=i.codec;const{dataType:a,sampleSize:s,littleEndian:n}=me(this.codec);switch(this.inputSampleSize=s,s){case 1:"unsigned"===a?this.readInputValue=(e,t)=>e.getUint8(t)-128:"signed"===a?this.readInputValue=(e,t)=>e.getInt8(t):"ulaw"===a?this.readInputValue=(e,t)=>(e=>{let t=0,r=0,i=~e;128&i&&(i&=-129,t=-1),r=5+((240&i)>>4);const a=(1<(e=>{let t=0,r=0,i=85^e;128&i&&(i&=-129,t=-1),r=4+((240&i)>>4);let a=0;return a=4!==r?1<e.getUint16(t,n)-32768:"signed"===a?this.readInputValue=(e,t)=>e.getInt16(t,n):t(!1);break;case 3:"unsigned"===a?this.readInputValue=(e,t)=>_(e,t,n)-2**23:"signed"===a?this.readInputValue=(e,t)=>((e,t,r)=>_(e,t,r)<<8>>8)(e,t,n):t(!1);break;case 4:"unsigned"===a?this.readInputValue=(e,t)=>e.getUint32(t,n)-2**31:"signed"===a?this.readInputValue=(e,t)=>e.getInt32(t,n):"float"===a?this.readInputValue=(e,t)=>e.getFloat32(t,n):t(!1);break;case 8:"float"===a?this.readInputValue=(e,t)=>e.getFloat64(t,n):t(!1);break;default:C(s),t(!1)}switch(s){case 1:"ulaw"===a||"alaw"===a?(this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,r)=>e.setInt16(t,r,!0)):(this.outputSampleSize=1,this.outputFormat="u8",this.writeOutputValue=(e,t,r)=>e.setUint8(t,r+128));break;case 2:this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,r)=>e.setInt16(t,r,!0);break;case 3:this.outputSampleSize=4,this.outputFormat="s32",this.writeOutputValue=(e,t,r)=>e.setInt32(t,r<<8,!0);break;case 4:this.outputSampleSize=4,"float"===a?(this.outputFormat="f32",this.writeOutputValue=(e,t,r)=>e.setFloat32(t,r,!0)):(this.outputFormat="s32",this.writeOutputValue=(e,t,r)=>e.setInt32(t,r,!0));break;case 8:this.outputSampleSize=4,this.outputFormat="f32",this.writeOutputValue=(e,t,r)=>e.setFloat32(t,r,!0);break;default:C(s),t(!1)}}getDecodeQueueSize(){return 0}decode(e){const t=c(e.data),r=e.byteLength/this.decoderConfig.numberOfChannels/this.inputSampleSize,i=r*this.decoderConfig.numberOfChannels*this.outputSampleSize,a=new ArrayBuffer(i),s=new DataView(a);for(let c=0;c=n)&&(this.currentTimestamp=e.timestamp);const o=this.currentTimestamp;this.currentTimestamp+=n;const l=new ut({format:this.outputFormat,data:a,numberOfChannels:this.decoderConfig.numberOfChannels,sampleRate:this.decoderConfig.sampleRate,numberOfFrames:r,timestamp:o});this.onSample(l)}async flush(){}close(){}}class Ft extends It{constructor(e){if(!(e instanceof Mt))throw new TypeError("audioTrack must be an InputAudioTrack.");super(),this._track=e}async _createDecoder(e,r){if(!(await this._track.canDecode()))throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track.");const i=this._track.codec,a=await this._track.getDecoderConfig();return t(i&&a),re.includes(a.codec)?new Et(e,r,a):new Bt(e,r,i,a)}_createPacketSink(){return new wt(this._track)}async getSample(e){Tt(e);for await(const t of this.mediaSamplesAtTimestamps([e]))return t;throw new Error("Internal error: Iterator returned nothing.")}samples(e=0,t=1/0){return this.mediaSamplesInRange(e,t)}samplesAtTimestamps(e){return this.mediaSamplesAtTimestamps(e)}}class Dt{constructor(e){if(!(e instanceof Mt))throw new TypeError("audioTrack must be an InputAudioTrack.");this._audioSampleSink=new Ft(e)}_audioSampleToWrappedArrayBuffer(e){const t={buffer:e.toAudioBuffer(),timestamp:e.timestamp,duration:e.duration};return e.close(),t}async getBuffer(e){Tt(e);const t=await this._audioSampleSink.getSample(e);return t&&this._audioSampleToWrappedArrayBuffer(t)}buffers(e=0,t=1/0){return E(this._audioSampleSink.samples(e,t),e=>this._audioSampleToWrappedArrayBuffer(e))}buffersAtTimestamps(e){return E(this._audioSampleSink.samplesAtTimestamps(e),e=>e&&this._audioSampleToWrappedArrayBuffer(e))}}class At{constructor(e,t){this.input=e,this._backing=t}isVideoTrack(){return this instanceof Rt}isAudioTrack(){return this instanceof Mt}get id(){return this._backing.getId()}get internalCodecId(){return this._backing.getInternalCodecId()}get languageCode(){return this._backing.getLanguageCode()}get name(){return this._backing.getName()}get timeResolution(){return this._backing.getTimeResolution()}get disposition(){return this._backing.getDisposition()}getFirstTimestamp(){return this._backing.getFirstTimestamp()}computeDuration(){return this._backing.computeDuration()}async computePacketStats(e=1/0){const t=new wt(this);let r=1/0,i=-1/0,a=0,s=0;for await(const n of t.packets(void 0,void 0,{metadataOnly:!0})){if(a>=e&&n.timestamp>=i)break;r=Math.min(r,n.timestamp),i=Math.max(i,n.timestamp+n.duration),a++,s+=n.byteLength}return{packetCount:a,averagePacketRate:a?Number((a/(i-r)).toPrecision(16)):0,averageBitrate:a?Number((8*s/(i-r)).toPrecision(16)):0}}}class Rt extends At{constructor(e,t){super(e,t),this._backing=t}get type(){return"video"}get codec(){return this._backing.getCodec()}get codedWidth(){return this._backing.getCodedWidth()}get codedHeight(){return this._backing.getCodedHeight()}get rotation(){return this._backing.getRotation()}get displayWidth(){return this._backing.getRotation()%180===0?this._backing.getCodedWidth():this._backing.getCodedHeight()}get displayHeight(){return this._backing.getRotation()%180===0?this._backing.getCodedHeight():this._backing.getCodedWidth()}getColorSpace(){return this._backing.getColorSpace()}async hasHighDynamicRange(){const e=await this._backing.getColorSpace();return"bt2020"===e.primaries||"smpte432"===e.primaries||"pg"===e.transfer||"hlg"===e.transfer||"bt2020-ncl"===e.matrix}canBeTransparent(){return this._backing.canBeTransparent()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecParameterString(){const e=await this._backing.getDecoderConfig();return e?.codec??null}async canDecode(){try{const e=await this._backing.getDecoderConfig();if(!e)return!1;const r=this._backing.getCodec();if(t(null!==r),$e.some(t=>t.supports(r,e)))return!0;if("undefined"===typeof VideoDecoder)return!1;return!0===(await VideoDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}}async determinePacketType(e){if(!(e instanceof Xe))throw new TypeError("packet must be an EncodedPacket.");if(e.isMetadataOnly)throw new TypeError("packet must not be metadata-only to determine its type.");if(null===this.codec)return null;const r=await this.getDecoderConfig();return t(r),qe(this.codec,r,e.data)}}class Mt extends At{constructor(e,t){super(e,t),this._backing=t}get type(){return"audio"}get codec(){return this._backing.getCodec()}get numberOfChannels(){return this._backing.getNumberOfChannels()}get sampleRate(){return this._backing.getSampleRate()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecParameterString(){const e=await this._backing.getDecoderConfig();return e?.codec??null}async canDecode(){try{const e=await this._backing.getDecoderConfig();if(!e)return!1;const r=this._backing.getCodec();if(t(null!==r),Qe.some(t=>t.supports(r,e)))return!0;if(e.codec.startsWith("pcm-"))return!0;if("undefined"===typeof AudioDecoder)return!1;return!0===(await AudioDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}}async determinePacketType(e){if(!(e instanceof Xe))throw new TypeError("packet must be an EncodedPacket.");return null===this.codec?null:"key"}}const Nt=e=>{let t=ua(e);const r=ya(e,4);let i=8;1===t&&(t=pa(e),i=16);const a=t-i;return a<0?null:{name:r,totalSize:t,headerSize:i,contentSize:a}},zt=e=>ma(e)/65536,Ot=e=>ma(e)/1073741824,Lt=e=>{let t=0;for(let r=0;r<4;r++){t<<=7;const r=sa(e);if(t|=127&r,0===(128&r))break}return t},Ut=e=>{let t=oa(e);return e.skip(2),t=Math.min(t,e.remainingLength),l.decode(aa(e,t))},Vt=e=>{const t=Nt(e);if(!t||"data"!==t.name)return null;if(e.remainingLength<8)return null;const r=ua(e);e.skip(4);const i=aa(e,t.contentSize-8);switch(r){case 1:return l.decode(i);case 2:return new TextDecoder("utf-16be").decode(i);case 13:return new Z(i,"image/jpeg");case 14:return new Z(i,"image/png");case 27:return new Z(i,"image/bmp");default:return i}};class qt extends Ke{constructor(e){super(e),this.moovSlice=null,this.currentTrack=null,this.tracks=[],this.metadataPromise=null,this.movieTimescale=-1,this.movieDurationInTimescale=-1,this.isQuickTime=!1,this.metadataTags={},this.currentMetadataKeys=null,this.isFragmented=!1,this.fragmentTrackDefaults=[],this.currentFragment=null,this.lastReadFragment=null,this.reader=e._reader}async computeDuration(){const e=await this.getTracks(),t=await Promise.all(e.map(e=>e.computeDuration()));return Math.max(0,...t)}async getTracks(){return await this.readMetadata(),this.tracks.map(e=>e.inputTrack)}async getMimeType(){await this.readMetadata();const e=await Promise.all(this.tracks.map(e=>e.inputTrack.getCodecParameterString()));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isQuickTime?"quicktime":"mp4");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({isQuickTime:this.isQuickTime,hasVideo:this.tracks.some(e=>"video"===e.info?.type),hasAudio:this.tracks.some(e=>"audio"===e.info?.type),codecStrings:e.filter(Boolean)})}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,8,16);if(t instanceof Promise&&(t=await t),!t)break;const r=e,i=Nt(t);if(!i)break;if("ftyp"===i.name){const e=ya(t,4);this.isQuickTime="qt "===e}else if("moov"===i.name){let e=this.reader.requestSlice(t.filePos,i.contentSize);if(e instanceof Promise&&(e=await e),!e)break;this.moovSlice=e,this.readContiguousBoxes(this.moovSlice),this.tracks.sort((e,t)=>Number(t.disposition.default)-Number(e.disposition.default));for(const t of this.tracks){const e=t.editListPreviousSegmentDurations/this.movieTimescale;t.editListOffset-=Math.round(e*t.timescale)}break}e=r+i.totalSize}if(this.isFragmented&&null!==this.reader.fileSize){let e=this.reader.requestSlice(this.reader.fileSize-4,4);e instanceof Promise&&(e=await e),t(e);const r=ua(e),i=this.reader.fileSize-r;if(i>=0&&i<=this.reader.fileSize-16){let e=this.reader.requestSliceRange(i,8,16);if(e instanceof Promise&&(e=await e),e){const t=Nt(e);if(t&&"mfra"===t.name){let r=this.reader.requestSlice(e.filePos,t.contentSize);r instanceof Promise&&(r=await r),r&&this.readContiguousBoxes(r)}}}}})())}getSampleTableForTrack(e){if(e.sampleTable)return e.sampleTable;const r={sampleTimingEntries:[],sampleCompositionTimeOffsets:[],sampleSizes:[],keySampleIndices:null,chunkOffsets:[],sampleToChunk:[],presentationTimestamps:null,presentationTimestampIndexMap:null};e.sampleTable=r,t(this.moovSlice);const a=this.moovSlice.slice(e.sampleTableByteOffset);this.currentTrack=e,this.traverseBox(a),this.currentTrack=null;if("audio"===e.info?.type&&e.info.codec&&re.includes(e.info.codec)&&0===r.sampleCompositionTimeOffsets.length){t("audio"===e.info?.type);const a=me(e.info.codec),s=[],n=[];for(let t=0;te.startIndex),u=r.sampleTimingEntries[d],h=S(r.sampleTimingEntries,l,e=>e.startIndex),m=r.sampleTimingEntries[h],f=u.startDecodeTimestamp+(c-u.startIndex)*u.delta,p=m.startDecodeTimestamp+(l-m.startIndex)*m.delta-f,g=i(s);g&&g.delta===p?g.count++:s.push({startIndex:o.startChunkIndex+t,startDecodeTimestamp:f,count:1,delta:p});const k=o.samplesPerChunk*a.sampleSize*e.info.numberOfChannels;n.push(k)}o.startSampleIndex=o.startChunkIndex,o.samplesPerChunk=1}r.sampleTimingEntries=s,r.sampleSizes=n}if(r.sampleCompositionTimeOffsets.length>0){r.presentationTimestamps=[];for(const e of r.sampleTimingEntries)for(let t=0;te.presentationTimestamp-t.presentationTimestamp),r.presentationTimestampIndexMap=Array(r.presentationTimestamps.length).fill(-1);for(let e=0;ee.moofOffset===s.moofOffset);if(i)Xt(t,i.timestamp);else{const e=S(r,s.moofOffset-1,e=>e.moofOffset);if(-1!==e){const i=r[e];Xt(t,i.endTimestamp)}}t.startTimestampIsFinal=!0}const i=S(r,t.startTimestamp,e=>e.startTimestamp);-1!==i&&r[i].moofOffset===s.moofOffset||r.splice(i+1,0,{moofOffset:s.moofOffset,startTimestamp:t.startTimestamp,endTimestamp:t.endTimestamp})}return s}readContiguousBoxes(e){const t=e.filePos;for(;e.filePos-t<=e.length-8;){if(!this.traverseBox(e))break}}*iterateContiguousBoxes(e){const t=e.filePos;for(;e.filePos-t<=e.length-8;){const t=e.filePos,r=Nt(e);if(!r)break;yield{boxInfo:r,slice:e},e.filePos=t+r.totalSize}}traverseBox(e){var s,n,o,d,u,m,p,k,b,T,y,w,S,I,v,P,x,C,_,B,E,F,A,R,N,z,O,L,U,V,q,H,W;const j=e.filePos,K=Nt(e);if(!K)return!1;const $=e.filePos,Q=j+K.totalSize;switch(K.name){case"mdia":case"minf":case"dinf":case"mfra":case"edts":case"wave":this.readContiguousBoxes(e.slice($,K.contentSize));break;case"mvhd":{const t=sa(e);e.skip(3),1===t?(e.skip(16),this.movieTimescale=ua(e),this.movieDurationInTimescale=pa(e)):(e.skip(8),this.movieTimescale=ua(e),this.movieDurationInTimescale=ua(e))}break;case"trak":{const t={id:-1,demuxer:this,inputTrack:null,disposition:{...te},info:null,timescale:-1,durationInMovieTimescale:-1,durationInMediaTimescale:-1,rotation:0,internalCodecId:null,name:null,languageCode:D,sampleTableByteOffset:-1,sampleTable:null,fragmentLookupTable:[],currentFragmentState:null,fragmentPositionCache:[],editListPreviousSegmentDurations:0,editListOffset:0};if(this.currentTrack=t,this.readContiguousBoxes(e.slice($,K.contentSize)),-1!==t.id&&-1!==t.timescale&&null!==t.info)if("video"===t.info.type&&-1!==t.info.width){const e=t;t.inputTrack=new Rt(this.input,new Wt(e)),this.tracks.push(t)}else if("audio"===t.info.type&&-1!==t.info.numberOfChannels){const e=t;t.inputTrack=new Mt(this.input,new jt(e)),this.tracks.push(t)}this.currentTrack=null}break;case"tkhd":{const i=this.currentTrack;if(!i)break;const a=sa(e),s=!!(1&ca(e));if(i.disposition.default=s,0===a)e.skip(8),i.id=ua(e),e.skip(4),i.durationInMovieTimescale=ua(e);else{if(1!==a)throw new Error(`Incorrect track header version ${a}.`);e.skip(16),i.id=ua(e),e.skip(4),i.durationInMovieTimescale=pa(e)}e.skip(16);const n=[zt(e),zt(e),Ot(e),zt(e),zt(e),Ot(e),zt(e),zt(e),Ot(e)],o=r((G=Yt(n),X=90,Math.round(G/X)*X));t(0===o||90===o||180===o||270===o),i.rotation=o}break;case"elst":{const t=this.currentTrack;if(!t)break;const r=sa(e);e.skip(3);let i=!1,a=0;const s=ua(e);for(let n=0;n0){t.languageCode="";for(let e=0;e<3;e++)t.languageCode=String.fromCharCode(96+(31&i))+t.languageCode,i>>=5;M(t.languageCode)||(t.languageCode=D)}}break;case"hdlr":{const t=this.currentTrack;if(!t)break;e.skip(8);const r=ya(e,4);"vide"===r?t.info={type:"video",width:-1,height:-1,codec:null,codecDescription:null,colorSpace:null,avcType:null,avcCodecInfo:null,hevcCodecInfo:null,vp9CodecInfo:null,av1CodecInfo:null}:"soun"===r&&(t.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case"stbl":{const t=this.currentTrack;if(!t)break;t.sampleTableByteOffset=j,this.readContiguousBoxes(e.slice($,K.contentSize))}break;case"stsd":{const t=this.currentTrack;if(!t)break;if(null===t.info||t.sampleTable)break;const r=sa(e);e.skip(3);const i=ua(e);for(let a=0;a0)if(1===n)e.skip(4),c=8*ua(e),e.skip(8);else if(2===n){e.skip(4),l=Ta(e),o=ua(e),e.skip(4),c=ua(e);const r=ua(e);if(e.skip(8),"lpcm"===s){const e=c+7>>3,i=Boolean(1&r),a=Boolean(2&r),s=4&r?-1:0;c>0&&c<=64&&(i?32===c&&(t.info.codec=a?"pcm-f32be":"pcm-f32"):s&1<>4,o=s>>1&7,c=1&s,l=sa(e),d=sa(e),u=sa(e);r.info.vp9CodecInfo={profile:i,level:a,bitDepth:n,chromaSubsampling:o,videoFullRangeFlag:c,colourPrimaries:l,transferCharacteristics:d,matrixCoefficients:u}}break;case"av1C":{const r=this.currentTrack;if(!r)break;t("video"===r.info?.type),e.skip(1);const i=sa(e),a=i>>5,s=31&i,n=sa(e),o=n>>7,c=n>>6&1,l=n>>4&1,d=n>>3&1,u=n>>2&1,h=3&n,m=2===a&&c?n>>5&1?12:10:c?10:8;r.info.av1CodecInfo={profile:a,level:s,tier:o,bitDepth:m,monochrome:l,chromaSubsamplingX:d,chromaSubsamplingY:u,chromaSamplePosition:h}}break;case"colr":{const r=this.currentTrack;if(!r)break;t("video"===r.info?.type);if("nclx"!==ya(e,4))break;const i=oa(e),a=oa(e),s=oa(e),n=Boolean(128&sa(e));r.info.colorSpace={primaries:h[i],transfer:f[a],matrix:g[s],fullRange:n}}break;case"esds":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type),e.skip(4);t(3===sa(e)),Lt(e),e.skip(2);const i=sa(e),a=0!==(64&i),s=0!==(32&i);if(0!==(128&i)&&e.skip(2),a){const t=sa(e);e.skip(t)}s&&e.skip(2);t(4===sa(e));const n=Lt(e),o=e.filePos,c=sa(e);if(64===c||103===c?(r.info.codec="aac",r.info.aacCodecInfo={isMpeg2:103===c}):105===c||107===c?r.info.codec="mp3":221===c?r.info.codec="vorbis":console.warn(`Unsupported audio codec (objectTypeIndication ${c}) - discarding track.`),e.skip(12),n>e.filePos-o){t(5===sa(e));const i=Lt(e);if(r.info.codecDescription=aa(e,i),"aac"===r.info.codec){const e=de(r.info.codecDescription);null!==e.numberOfChannels&&(r.info.numberOfChannels=e.numberOfChannels),null!==e.sampleRate&&(r.info.sampleRate=e.sampleRate)}}}break;case"enda":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type);255&oa(e)&&("pcm-s16be"===r.info.codec?r.info.codec="pcm-s16":"pcm-s24be"===r.info.codec?r.info.codec="pcm-s24":"pcm-s32be"===r.info.codec?r.info.codec="pcm-s32":"pcm-f32be"===r.info.codec?r.info.codec="pcm-f32":"pcm-f64be"===r.info.codec&&(r.info.codec="pcm-f64"))}break;case"pcmC":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type),e.skip(4);const i=sa(e),a=Boolean(1&i),s=sa(e);"pcm-s16be"===r.info.codec?a?16===s?r.info.codec="pcm-s16":24===s?r.info.codec="pcm-s24":32===s?r.info.codec="pcm-s32":(console.warn(`Invalid ipcm sample size ${s}.`),r.info.codec=null):16===s?r.info.codec="pcm-s16be":24===s?r.info.codec="pcm-s24be":32===s?r.info.codec="pcm-s32be":(console.warn(`Invalid ipcm sample size ${s}.`),r.info.codec=null):"pcm-f32be"===r.info.codec&&(a?32===s?r.info.codec="pcm-f32":64===s?r.info.codec="pcm-f64":(console.warn(`Invalid fpcm sample size ${s}.`),r.info.codec=null):32===s?r.info.codec="pcm-f32be":64===s?r.info.codec="pcm-f64be":(console.warn(`Invalid fpcm sample size ${s}.`),r.info.codec=null));break}case"dOps":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type),e.skip(1);const i=sa(e),a=oa(e),s=ua(e),n=la(e),o=sa(e);let c;c=0!==o?aa(e,2+i):new Uint8Array(0);const l=new Uint8Array(19+c.byteLength),d=new DataView(l.buffer);d.setUint32(0,1332770163,!1),d.setUint32(4,1214603620,!1),d.setUint8(8,1),d.setUint8(9,i),d.setUint16(10,a,!0),d.setUint32(12,s,!0),d.setInt16(16,n,!0),d.setUint8(18,o),l.set(c,19),r.info.codecDescription=l,r.info.numberOfChannels=i}break;case"dfLa":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type),e.skip(4);const i=127,a=128,s=e.filePos;for(;e.filePos>>12,a=1+(t>>9&7);r.info.sampleRate=i,r.info.numberOfChannels=a,e.skip(20)}else e.skip(s);if(t&a)break}const n=e.filePos;e.filePos=s;const o=aa(e,n-s),c=new Uint8Array(4+o.byteLength);new DataView(c.buffer).setUint32(0,1716281667,!1),c.set(o,4),r.info.codecDescription=c}break;case"stts":{const t=this.currentTrack;if(!t)break;if(!t.sampleTable)break;e.skip(4);const r=ua(e);let i=0,a=0;for(let s=0;se.id===r);if(!i)break;const a=ua(e),s=(12&a)>>2,n=3&a,o=[sa,oa,ca,ua],c=o[(48&a)>>4],l=o[s],d=o[n],u=ua(e);for(let h=0;he.timestamp-t.timestamp);for(let e=0;ee.id===d);if(!u)break;const h=this.fragmentTrackDefaults.find(e=>e.trackId===d);this.currentTrack=u,u.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:h?.defaultSampleDescriptionIndex??null,defaultSampleDuration:h?.defaultSampleDuration??null,defaultSampleSize:h?.defaultSampleSize??null,defaultSampleFlags:h?.defaultSampleFlags??null,startTimestamp:null},i?u.currentFragmentState.baseDataOffset=pa(e):l&&(u.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),a&&(u.currentFragmentState.sampleDescriptionIndex=ua(e)),s&&(u.currentFragmentState.defaultSampleDuration=ua(e)),n&&(u.currentFragmentState.defaultSampleSize=ua(e)),o&&(u.currentFragmentState.defaultSampleFlags=ua(e)),c&&(u.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{const r=this.currentTrack;if(!r)break;t(r.currentFragmentState);const i=sa(e);e.skip(3);const a=0===i?ua(e):pa(e);r.currentFragmentState.startTimestamp=a}break;case"trun":{const r=this.currentTrack;if(!r)break;if(t(this.currentFragment),t(r.currentFragmentState),this.currentFragment.trackData.has(r.id)){console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring...");break}const a=sa(e),s=ca(e),n=Boolean(1&s),o=Boolean(4&s),c=Boolean(256&s),l=Boolean(512&s),d=Boolean(1024&s),u=Boolean(2048&s),h=ua(e);let m=r.currentFragmentState.baseDataOffset;n&&(m+=ma(e));let f=null;o&&(f=ua(e));let p=m;if(0===h){this.currentFragment.implicitBaseDataOffset=p;break}let g=0;const k={track:r,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(r.id,k);for(let i=0;i({presentationTimestamp:e.presentationTimestamp,sampleIndex:t})).sort((e,t)=>e.presentationTimestamp-t.presentationTimestamp);for(let e=0;e0&&((L=this.metadataTags).trackNumber??(L.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&((U=this.metadataTags).tracksTotal??(U.tracksTotal=r))}break;case"trkn":if(a instanceof Uint8Array&&a.length>=6){const e=c(a),t=e.getUint16(2,!1),r=e.getUint16(4,!1);t>0&&((V=this.metadataTags).trackNumber??(V.trackNumber=t)),r>0&&((q=this.metadataTags).tracksTotal??(q.tracksTotal=r))}break;case"disc":case"disk":if(a instanceof Uint8Array&&a.length>=6){const e=c(a),t=e.getUint16(2,!1),r=e.getUint16(4,!1);t>0&&((H=this.metadataTags).discNumber??(H.discNumber=t)),r>0&&((W=this.metadataTags).discsTotal??(W.discsTotal=r))}}}}}var G,X;return e.filePos=Q,!0}}class Ht{constructor(e){this.internalTrack=e,this.packetToSampleIndex=new WeakMap,this.packetToFragmentLocation=new WeakMap}getId(){return this.internalTrack.id}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.internalCodecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.timescale}getDisposition(){return this.internalTrack.disposition}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}async getFirstTimestamp(){const e=await this.getFirstPacket({metadataOnly:!0});return e?.timestamp??0}async getFirstPacket(e){const t=await this.fetchPacketForSampleIndex(0,e);return t||!this.internalTrack.demuxer.isFragmented?t:this.performFragmentedLookup(null,e=>e.trackData.get(this.internalTrack.id)?{sampleIndex:0,correctSampleFound:!0}:{sampleIndex:-1,correctSampleFound:!1},-1/0,1/0,e)}mapTimestampIntoTimescale(e){return A(e*this.internalTrack.timescale)+this.internalTrack.editListOffset}async getPacket(e,t){const r=this.mapTimestampIntoTimescale(e),i=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),a=Kt(i,r),s=await this.fetchPacketForSampleIndex(a,t);return Jt(i)&&this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const i=S(t.presentationTimestamps,r,e=>e.presentationTimestamp);return{sampleIndex:-1!==i?t.presentationTimestamps[i].sampleIndex:-1,correctSampleFound:-1!==i&&r{if(e===i.fragment){const t=e.trackData.get(this.internalTrack.id);if(i.sampleIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const i=x(t.presentationTimestamps,e=>t.samples[e.sampleIndex].isKeyFrame&&e.presentationTimestamp<=r);return{sampleIndex:-1!==i?t.presentationTimestamps[i].sampleIndex:-1,correctSampleFound:-1!==i&&r{if(e===a.fragment){const t=e.trackData.get(this.internalTrack.id).samples.findIndex((e,t)=>e.isKeyFrame&&t>a.sampleIndex);if(-1!==t)return{sampleIndex:t,correctSampleFound:!0}}else{const r=e.trackData.get(this.internalTrack.id);if(r&&null!==r.firstKeyFrameTimestamp){const e=r.samples.findIndex(e=>e.isKeyFrame);return t(-1!==e),{sampleIndex:e,correctSampleFound:!0}}}return{sampleIndex:-1,correctSampleFound:!1}},-1/0,1/0,r)}async fetchPacketForSampleIndex(e,r){if(-1===e)return null;const i=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),a=Qt(i,e);if(!a)return null;let s;if(r.metadataOnly)s=Ge;else{let e=this.internalTrack.demuxer.reader.requestSlice(a.sampleOffset,a.sampleSize);e instanceof Promise&&(e=await e),t(e),s=aa(e,a.sampleSize)}const n=(a.presentationTimestamp-this.internalTrack.editListOffset)/this.internalTrack.timescale,o=a.duration/this.internalTrack.timescale,c=new Xe(s,a.isKeyFrame?"key":"delta",n,o,e,a.sampleSize);return this.packetToSampleIndex.set(c,e),c}async fetchPacketInFragment(e,r,i){if(-1===r)return null;const a=e.trackData.get(this.internalTrack.id).samples[r];let s;if(t(a),i.metadataOnly)s=Ge;else{let e=this.internalTrack.demuxer.reader.requestSlice(a.byteOffset,a.byteSize);e instanceof Promise&&(e=await e),t(e),s=aa(e,a.byteSize)}const n=(a.presentationTimestamp-this.internalTrack.editListOffset)/this.internalTrack.timescale,o=a.duration/this.internalTrack.timescale,c=new Xe(s,a.isKeyFrame?"key":"delta",n,o,e.moofOffset+r,a.byteSize);return this.packetToFragmentLocation.set(c,{fragment:e,sampleIndex:r}),c}async performFragmentedLookup(e,r,i,a,s){const n=this.internalTrack.demuxer;let o=null,c=null,l=-1;if(e){const{sampleIndex:t,correctSampleFound:i}=r(e);if(i)return this.fetchPacketInFragment(e,t,s);-1!==t&&(c=e,l=t)}const d=S(this.internalTrack.fragmentLookupTable,i,e=>e.timestamp),u=-1!==d?this.internalTrack.fragmentLookupTable[d]:null,h=S(this.internalTrack.fragmentPositionCache,i,e=>e.startTimestamp),m=-1!==h?this.internalTrack.fragmentPositionCache[h]:null,f=Math.max(u?.moofOffset??0,m?.moofOffset??0)||null;let p;for(e?null===f||e.moofOffset>=f?(p=e.moofOffset+e.moofSize,o=e):p=f:p=f??0;;){if(o){const e=o.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>a)break}let e=n.reader.requestSliceRange(p,8,16);if(e instanceof Promise&&(e=await e),!e)break;const t=p,i=Nt(e);if(!i)break;if("moof"===i.name){o=await n.readFragment(t);const{sampleIndex:e,correctSampleFound:i}=r(o);if(i)return this.fetchPacketInFragment(o,e,s);-1!==e&&(c=o,l=e)}p=t+i.totalSize}if(u&&(!c||c.moofOffset{if("vp9"!==this.internalTrack.info.codec||this.internalTrack.info.vp9CodecInfo){if("av1"===this.internalTrack.info.codec&&!this.internalTrack.info.av1CodecInfo){const e=await this.getFirstPacket({});this.internalTrack.info.av1CodecInfo=e&&Le(e.data)}}else{const e=await this.getFirstPacket({});this.internalTrack.info.vp9CodecInfo=e&&ze(e.data)}return{codec:ne(this.internalTrack.info),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0}})()):null}}class jt extends Ht{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return this.internalTrack.info.codec?this.decoderConfig??(this.decoderConfig={codec:oe(this.internalTrack.info),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}):null}}const Kt=(e,t)=>{if(e.presentationTimestamps){const r=S(e.presentationTimestamps,t,e=>e.presentationTimestamp);return-1===r?-1:e.presentationTimestamps[r].sampleIndex}{const r=S(e.sampleTimingEntries,t,e=>e.startDecodeTimestamp);if(-1===r)return-1;const i=e.sampleTimingEntries[r];return i.startIndex+Math.min(Math.floor((t-i.startDecodeTimestamp)/i.delta),i.count-1)}},$t=(e,t)=>{if(!e.keySampleIndices)return Kt(e,t);if(e.presentationTimestamps){const r=S(e.presentationTimestamps,t,e=>e.presentationTimestamp);if(-1===r)return-1;for(let t=r;t>=0;t--){const r=e.presentationTimestamps[t].sampleIndex;if(-1!==w(e.keySampleIndices,r,e=>e))return r}return-1}{const r=Kt(e,t),i=S(e.keySampleIndices,r,e=>e);return e.keySampleIndices[i]??-1}},Qt=(e,r)=>{const i=S(e.sampleTimingEntries,r,e=>e.startIndex),a=e.sampleTimingEntries[i];if(!a||a.startIndex+a.count<=r)return null;let s=a.startDecodeTimestamp+(r-a.startIndex)*a.delta;const n=S(e.sampleCompositionTimeOffsets,r,e=>e.startIndex),o=e.sampleCompositionTimeOffsets[n];o&&r-o.startIndexe.startSampleIndex),d=e.sampleToChunk[l];t(d);const u=d.startChunkIndex+Math.floor((r-d.startSampleIndex)/d.samplesPerChunk),h=e.chunkOffsets[u],m=d.startSampleIndex+(u-d.startChunkIndex)*d.samplesPerChunk;let f=0,p=h;if(1===e.sampleSizes.length)p+=c*(r-m),f+=c*d.samplesPerChunk;else for(let t=m;te)}},Gt=(e,t)=>{if(!e.keySampleIndices)return t+1;const r=S(e.keySampleIndices,t,e=>e);return e.keySampleIndices[r+1]??-1},Xt=(e,t)=>{e.startTimestamp+=t,e.endTimestamp+=t;for(const r of e.samples)r.presentationTimestamp+=t;for(const r of e.presentationTimestamps)r.presentationTimestamp+=t},Yt=e=>{const[t,,,r]=e,i=Math.hypot(t,r),a=t/i,s=r/i,n=-Math.atan2(s,a)*(180/Math.PI);return Number.isFinite(n)?n:0},Jt=e=>0===e.sampleSizes.length;var Zt,er;(er=Zt||(Zt={}))[er.EBML=440786851]="EBML",er[er.EBMLVersion=17030]="EBMLVersion",er[er.EBMLReadVersion=17143]="EBMLReadVersion",er[er.EBMLMaxIDLength=17138]="EBMLMaxIDLength",er[er.EBMLMaxSizeLength=17139]="EBMLMaxSizeLength",er[er.DocType=17026]="DocType",er[er.DocTypeVersion=17031]="DocTypeVersion",er[er.DocTypeReadVersion=17029]="DocTypeReadVersion",er[er.Void=236]="Void",er[er.Segment=408125543]="Segment",er[er.SeekHead=290298740]="SeekHead",er[er.Seek=19899]="Seek",er[er.SeekID=21419]="SeekID",er[er.SeekPosition=21420]="SeekPosition",er[er.Duration=17545]="Duration",er[er.Info=357149030]="Info",er[er.TimestampScale=2807729]="TimestampScale",er[er.MuxingApp=19840]="MuxingApp",er[er.WritingApp=22337]="WritingApp",er[er.Tracks=374648427]="Tracks",er[er.TrackEntry=174]="TrackEntry",er[er.TrackNumber=215]="TrackNumber",er[er.TrackUID=29637]="TrackUID",er[er.TrackType=131]="TrackType",er[er.FlagEnabled=185]="FlagEnabled",er[er.FlagDefault=136]="FlagDefault",er[er.FlagForced=21930]="FlagForced",er[er.FlagOriginal=21934]="FlagOriginal",er[er.FlagHearingImpaired=21931]="FlagHearingImpaired",er[er.FlagVisualImpaired=21932]="FlagVisualImpaired",er[er.FlagCommentary=21935]="FlagCommentary",er[er.FlagLacing=156]="FlagLacing",er[er.Name=21358]="Name",er[er.Language=2274716]="Language",er[er.LanguageBCP47=2274717]="LanguageBCP47",er[er.CodecID=134]="CodecID",er[er.CodecPrivate=25506]="CodecPrivate",er[er.CodecDelay=22186]="CodecDelay",er[er.SeekPreRoll=22203]="SeekPreRoll",er[er.DefaultDuration=2352003]="DefaultDuration",er[er.Video=224]="Video",er[er.PixelWidth=176]="PixelWidth",er[er.PixelHeight=186]="PixelHeight",er[er.AlphaMode=21440]="AlphaMode",er[er.Audio=225]="Audio",er[er.SamplingFrequency=181]="SamplingFrequency",er[er.Channels=159]="Channels",er[er.BitDepth=25188]="BitDepth",er[er.SimpleBlock=163]="SimpleBlock",er[er.BlockGroup=160]="BlockGroup",er[er.Block=161]="Block",er[er.BlockAdditions=30113]="BlockAdditions",er[er.BlockMore=166]="BlockMore",er[er.BlockAdditional=165]="BlockAdditional",er[er.BlockAddID=238]="BlockAddID",er[er.BlockDuration=155]="BlockDuration",er[er.ReferenceBlock=251]="ReferenceBlock",er[er.Cluster=524531317]="Cluster",er[er.Timestamp=231]="Timestamp",er[er.Cues=475249515]="Cues",er[er.CuePoint=187]="CuePoint",er[er.CueTime=179]="CueTime",er[er.CueTrackPositions=183]="CueTrackPositions",er[er.CueTrack=247]="CueTrack",er[er.CueClusterPosition=241]="CueClusterPosition",er[er.Colour=21936]="Colour",er[er.MatrixCoefficients=21937]="MatrixCoefficients",er[er.TransferCharacteristics=21946]="TransferCharacteristics",er[er.Primaries=21947]="Primaries",er[er.Range=21945]="Range",er[er.Projection=30320]="Projection",er[er.ProjectionType=30321]="ProjectionType",er[er.ProjectionPoseRoll=30325]="ProjectionPoseRoll",er[er.Attachments=423732329]="Attachments",er[er.AttachedFile=24999]="AttachedFile",er[er.FileDescription=18046]="FileDescription",er[er.FileName=18030]="FileName",er[er.FileMediaType=18016]="FileMediaType",er[er.FileData=18012]="FileData",er[er.FileUID=18094]="FileUID",er[er.Chapters=272869232]="Chapters",er[er.Tags=307544935]="Tags",er[er.Tag=29555]="Tag",er[er.Targets=25536]="Targets",er[er.TargetTypeValue=26826]="TargetTypeValue",er[er.TargetType=25546]="TargetType",er[er.TagTrackUID=25541]="TagTrackUID",er[er.TagEditionUID=25545]="TagEditionUID",er[er.TagChapterUID=25540]="TagChapterUID",er[er.TagAttachmentUID=25542]="TagAttachmentUID",er[er.SimpleTag=26568]="SimpleTag",er[er.TagName=17827]="TagName",er[er.TagLanguage=17530]="TagLanguage",er[er.TagString=17543]="TagString",er[er.TagBinary=17541]="TagBinary",er[er.ContentEncodings=28032]="ContentEncodings",er[er.ContentEncoding=25152]="ContentEncoding",er[er.ContentEncodingOrder=20529]="ContentEncodingOrder",er[er.ContentEncodingScope=20530]="ContentEncodingScope",er[er.ContentCompression=20532]="ContentCompression",er[er.ContentCompAlgo=16980]="ContentCompAlgo",er[er.ContentCompSettings=16981]="ContentCompSettings",er[er.ContentEncryption=20533]="ContentEncryption";const tr=[Zt.EBML,Zt.Segment],rr=[Zt.SeekHead,Zt.Info,Zt.Cluster,Zt.Tracks,Zt.Cues,Zt.Attachments,Zt.Chapters,Zt.Tags],ir=[...tr,...rr],ar=16,sr=e=>{if(e.remainingLength<1)return null;const t=sa(e);if(e.skip(-1),0===t)return null;let r=1,i=128;for(;0===(t&i);)r++,i>>=1;return e.remainingLength{if(e.remainingLength<1)return null;const t=sa(e);if(0===t)return null;let r=1,i=128;for(;0===(t&i);)r++,i>>=1;if(e.remainingLength{if(t<1||t>8)throw new Error("Bad unsigned int size "+t);let r=0;for(let i=0;i{const t=sr(e);if(null===t)return null;if(e.remainingLength{if(e.remainingLength<1)return null;if(255===sa(e))return;e.skip(-1);const t=nr(e);return null===t?null:72057594037927940!==t?t:void 0},dr=e=>{t(e.remainingLength>=2);const r=cr(e);if(null===r)return null;const i=lr(e);return null===i?null:{id:r,size:i}},ur=(e,t)=>{const r=aa(e,t);let i=0;for(;i{const r=aa(e,t);let i=0;for(;i{if(0===t)return 0;if(4!==t&&8!==t)throw new Error("Bad float size "+t);return 4===t?ba(e):Ta(e)},fr=async(e,t,r,i)=>{const a=new Set(r);let s=t;for(;null===i||ss?i:s,found:!1}},pr=async(e,t,r,i)=>{const a=new Set(r);let s=t;for(;se.computeDuration()));return Math.max(0,...t)}async getTracks(){return await this.readMetadata(),this.segments.flatMap(e=>e.tracks.map(e=>e.inputTrack))}async getMimeType(){await this.readMetadata();const e=await this.getTracks(),t=await Promise.all(e.map(e=>e.getCodecParameterString()));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isWebM?"webm":"x-matroska");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings.filter(Boolean))].join(", ")}"`);return t})({isWebM:this.isWebM,hasVideo:this.segments.some(e=>e.tracks.some(e=>"video"===e.info?.type)),hasAudio:this.segments.some(e=>e.tracks.some(e=>"audio"===e.info?.type)),codecStrings:t.filter(Boolean)})}async getMetadataTags(){await this.readMetadata();for(const t of this.segments)t.metadataTagsCollected||(null!==this.reader.fileSize&&await this.loadSegmentMetadata(t),t.metadataTagsCollected=!0);let e={};for(const t of this.segments)e={...e,...t.metadataTags};return e}readMetadata(){return this.readMetadataPromise??(this.readMetadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,2,ar);if(t instanceof Promise&&(t=await t),!t)break;const r=dr(t);if(!r)break;const a=r.id;let s=r.size;const n=t.filePos;if(a===Zt.EBML){xr(s);let e=this.reader.requestSlice(n,s);if(e instanceof Promise&&(e=await e),!e)break;this.readContiguousElements(e)}else if(a===Zt.Segment){if(await this.readSegment(n,s),void 0===s)break;if(null===this.reader.fileSize)break}else if(a===Zt.Cluster){if(null===this.reader.fileSize)break;if(void 0===s){s=(await fr(this.reader,n,ir,this.reader.fileSize)).pos-n}const e=i(this.segments);e&&(e.elementEndPos=n+s)}xr(s),e=n+s}})())}async readSegment(e,t){this.currentSegment={seekHeadSeen:!1,infoSeen:!1,tracksSeen:!1,cuesSeen:!1,tagsSeen:!1,attachmentsSeen:!1,timestampScale:-1,timestampFactor:-1,duration:-1,seekEntries:[],tracks:[],cuePoints:[],dataStartPos:e,elementEndPos:void 0===t?null:e+t,clusterSeekStartPos:e,lastReadCluster:null,metadataTags:{},metadataTagsCollected:!1},this.segments.push(this.currentSegment);let r=e;for(;null===this.currentSegment.elementEndPos||re.id===a);if(-1!==o){const e=Ar[o].flag;this.currentSegment[e]=!0,xr(s);let t=this.reader.requestSlice(n,s);t instanceof Promise&&(t=await t),t&&this.readContiguousElements(t)}else if(a===Zt.Tags||a===Zt.Attachments){a===Zt.Tags?this.currentSegment.tagsSeen=!0:this.currentSegment.attachmentsSeen=!0,xr(s);let e=this.reader.requestSlice(n,s);e instanceof Promise&&(e=await e),e&&this.readContiguousElements(e)}else if(a===Zt.Cluster){this.currentSegment.clusterSeekStartPos=t;break}if(void 0===s)break;r=n+s}if(this.currentSegment.seekEntries.sort((e,t)=>e.segmentPosition-t.segmentPosition),null!==this.reader.fileSize)for(const n of this.currentSegment.seekEntries){const t=Ar.find(e=>e.id===n.id);if(!t)continue;if(this.currentSegment[t.flag])continue;let r=this.reader.requestSliceRange(e+n.segmentPosition,2,ar);if(r instanceof Promise&&(r=await r),!r)continue;const i=dr(r);if(!i)continue;const{id:a,size:s}=i;if(a!==t.id)continue;xr(s),this.currentSegment[t.flag]=!0;let o=this.reader.requestSlice(r.filePos,s);o instanceof Promise&&(o=await o),o&&this.readContiguousElements(o)}-1===this.currentSegment.timestampScale&&(this.currentSegment.timestampScale=1e6,this.currentSegment.timestampFactor=1e3);for(const n of this.currentSegment.tracks)null!==n.defaultDurationNs&&(n.defaultDuration=this.currentSegment.timestampFactor*n.defaultDurationNs/1e9);this.currentSegment.tracks.sort((e,t)=>Number(t.disposition.default)-Number(e.disposition.default));const i=new Map(this.currentSegment.tracks.map(e=>[e.id,e]));for(const n of this.currentSegment.cuePoints){const e=i.get(n.trackId);e&&e.cuePoints.push(n)}for(const n of this.currentSegment.tracks){n.cuePoints.sort((e,t)=>e.time-t.time);for(let e=0;es&&(s=n.cuePoints.length,a=n);for(const n of this.currentSegment.tracks)0===n.cuePoints.length&&(n.cuePoints=a.cuePoints);this.currentSegment=null}async readCluster(e,r){if(r.lastReadCluster?.elementStartPos===e)return r.lastReadCluster;let a=this.reader.requestSliceRange(e,2,ar);a instanceof Promise&&(a=await a),t(a);const s=e,n=dr(a);t(n);t(n.id===Zt.Cluster);let o=n.size;const c=a.filePos;if(void 0===o){o=(await fr(this.reader,c,ir,r.elementEndPos)).pos-c}let l=this.reader.requestSlice(c,o);l instanceof Promise&&(l=await l);const d={segment:r,elementStartPos:s,elementEndPos:c+o,dataStartPos:c,timestamp:-1,trackData:new Map};if(this.currentCluster=d,l){const e=this.readContiguousElements(l,ir);d.elementEndPos=e}for(const[,u]of d.trackData){const e=u.track;t(u.blocks.length>0);let r=!1;for(let t=0;t({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp);for(let t=0;t({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp));const a=u.blocks[u.presentationTimestamps[0].blockIndex],n=u.blocks[i(u.presentationTimestamps).blockIndex];u.startTimestamp=a.timestamp,u.endTimestamp=n.timestamp+n.duration;const o=S(e.clusterPositionCache,u.startTimestamp,e=>e.startTimestamp);-1!==o&&e.clusterPositionCache[o].elementStartPos===s||e.clusterPositionCache.splice(o+1,0,{elementStartPos:d.elementStartPos,startTimestamp:u.startTimestamp})}return r.lastReadCluster=d,d}getTrackDataInCluster(e,t){let r=e.trackData.get(t);if(!r){const i=e.segment.tracks.find(e=>e.id===t);if(!i)return null;r={track:i,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,blocks:[],presentationTimestamps:[]},e.trackData.set(t,r)}return r}expandLacedBlocks(e,r){for(let i=0;i=2;){const r=e.filePos;if(!this.traverseElement(e,t))return r}return e.filePos}traverseElement(e,i){const a=dr(e);if(!a)return!1;if(i&&i.includes(a.id))return!1;const{id:s,size:n}=a,o=e.filePos;switch(xr(n),s){case Zt.DocType:this.isWebM="webm"===ur(e,n);break;case Zt.Seek:{if(!this.currentSegment)break;const t={id:-1,segmentPosition:-1};this.currentSegment.seekEntries.push(t),this.readContiguousElements(e.slice(o,n)),-1!==t.id&&-1!==t.segmentPosition||this.currentSegment.seekEntries.pop()}break;case Zt.SeekID:{const t=this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.id=or(e,n)}break;case Zt.SeekPosition:{const t=this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.segmentPosition=or(e,n)}break;case Zt.TimestampScale:if(!this.currentSegment)break;this.currentSegment.timestampScale=or(e,n),this.currentSegment.timestampFactor=1e9/this.currentSegment.timestampScale;break;case Zt.Duration:if(!this.currentSegment)break;this.currentSegment.duration=mr(e,n);break;case Zt.TrackEntry:if(!this.currentSegment)break;if(this.currentTrack={id:-1,segment:this.currentSegment,demuxer:this,clusterPositionCache:[],cuePoints:[],disposition:{...te},inputTrack:null,codecId:null,codecPrivate:null,defaultDuration:null,defaultDurationNs:null,name:null,languageCode:D,decodingInstructions:[],info:null},this.readContiguousElements(e.slice(o,n)),!this.currentTrack)break;if(this.currentTrack.decodingInstructions.some(e=>"decompress"!==e.data?.type||e.scope!==Br.Block||e.data.algorithm!==Fr.HeaderStripping)&&(console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`),this.currentTrack=null),this.currentTrack&&-1!==this.currentTrack.id&&this.currentTrack.codecId&&this.currentTrack.info){const e=this.currentTrack.codecId.indexOf("/"),t=-1===e?this.currentTrack.codecId:this.currentTrack.codecId.slice(0,e);if("video"===this.currentTrack.info.type&&-1!==this.currentTrack.info.width&&-1!==this.currentTrack.info.height){this.currentTrack.codecId===gr?(this.currentTrack.info.codec="avc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===kr?(this.currentTrack.info.codec="hevc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===br?this.currentTrack.info.codec="vp8":t===Tr?this.currentTrack.info.codec="vp9":t===yr&&(this.currentTrack.info.codec="av1");const e=this.currentTrack,r=new Rt(this.input,new zr(e));this.currentTrack.inputTrack=r,this.currentSegment.tracks.push(this.currentTrack)}else if("audio"===this.currentTrack.info.type&&-1!==this.currentTrack.info.numberOfChannels&&-1!==this.currentTrack.info.sampleRate){t===wr?(this.currentTrack.info.codec="aac",this.currentTrack.info.aacCodecInfo={isMpeg2:this.currentTrack.codecId.includes("MPEG2")},this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Sr?this.currentTrack.info.codec="mp3":t===Ir?(this.currentTrack.info.codec="opus",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate,this.currentTrack.info.sampleRate=ue):t===vr?(this.currentTrack.info.codec="vorbis",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Pr?(this.currentTrack.info.codec="flac",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):"A_PCM/INT/LIT"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32"):"A_PCM/INT/BIG"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16be":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24be":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32be"):"A_PCM/FLOAT/IEEE"===this.currentTrack.codecId&&(32===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-f32":64===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-f64"));const e=this.currentTrack,r=new Mt(this.input,new Or(e));this.currentTrack.inputTrack=r,this.currentSegment.tracks.push(this.currentTrack)}}this.currentTrack=null;break;case Zt.TrackNumber:if(!this.currentTrack)break;this.currentTrack.id=or(e,n);break;case Zt.TrackType:{if(!this.currentTrack)break;const t=or(e,n);1===t?this.currentTrack.info={type:"video",width:-1,height:-1,rotation:0,codec:null,codecDescription:null,colorSpace:null,alphaMode:!1}:2===t&&(this.currentTrack.info={type:"audio",numberOfChannels:-1,sampleRate:-1,bitDepth:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case Zt.FlagEnabled:if(!this.currentTrack)break;or(e,n)||(this.currentTrack=null);break;case Zt.FlagDefault:if(!this.currentTrack)break;this.currentTrack.disposition.default=!!or(e,n);break;case Zt.FlagForced:if(!this.currentTrack)break;this.currentTrack.disposition.forced=!!or(e,n);break;case Zt.FlagOriginal:if(!this.currentTrack)break;this.currentTrack.disposition.original=!!or(e,n);break;case Zt.FlagHearingImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.hearingImpaired=!!or(e,n);break;case Zt.FlagVisualImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.visuallyImpaired=!!or(e,n);break;case Zt.FlagCommentary:if(!this.currentTrack)break;this.currentTrack.disposition.commentary=!!or(e,n);break;case Zt.CodecID:if(!this.currentTrack)break;this.currentTrack.codecId=ur(e,n);break;case Zt.CodecPrivate:if(!this.currentTrack)break;this.currentTrack.codecPrivate=aa(e,n);break;case Zt.DefaultDuration:if(!this.currentTrack)break;this.currentTrack.defaultDurationNs=or(e,n);break;case Zt.Name:if(!this.currentTrack)break;this.currentTrack.name=hr(e,n);break;case Zt.Language:if(!this.currentTrack)break;if(this.currentTrack.languageCode!==D)break;this.currentTrack.languageCode=ur(e,n),M(this.currentTrack.languageCode)||(this.currentTrack.languageCode=D);break;case Zt.LanguageBCP47:{if(!this.currentTrack)break;const t=ur(e,n).split("-")[0];this.currentTrack.languageCode=t||D}break;case Zt.Video:if("video"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case Zt.PixelWidth:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.width=or(e,n);break;case Zt.PixelHeight:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.height=or(e,n);break;case Zt.AlphaMode:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.alphaMode=1===or(e,n);break;case Zt.Colour:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.colorSpace={},this.readContiguousElements(e.slice(o,n));break;case Zt.MatrixCoefficients:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=or(e,n),r=g[t]??null;this.currentTrack.info.colorSpace.matrix=r}break;case Zt.Range:if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;this.currentTrack.info.colorSpace.fullRange=2===or(e,n);break;case Zt.TransferCharacteristics:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=or(e,n),r=f[t]??null;this.currentTrack.info.colorSpace.transfer=r}break;case Zt.Primaries:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=or(e,n),r=h[t]??null;this.currentTrack.info.colorSpace.primaries=r}break;case Zt.Projection:if("video"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case Zt.ProjectionPoseRoll:{if("video"!==this.currentTrack?.info?.type)break;const t=-mr(e,n);try{this.currentTrack.info.rotation=r(t)}catch{}}break;case Zt.Audio:if("audio"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case Zt.SamplingFrequency:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.sampleRate=mr(e,n);break;case Zt.Channels:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.numberOfChannels=or(e,n);break;case Zt.BitDepth:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.bitDepth=or(e,n);break;case Zt.CuePoint:if(!this.currentSegment)break;this.readContiguousElements(e.slice(o,n)),this.currentCueTime=null;break;case Zt.CueTime:this.currentCueTime=or(e,n);break;case Zt.CueTrackPositions:{if(null===this.currentCueTime)break;t(this.currentSegment);const r={time:this.currentCueTime,trackId:-1,clusterPosition:-1};this.currentSegment.cuePoints.push(r),this.readContiguousElements(e.slice(o,n)),-1!==r.trackId&&-1!==r.clusterPosition||this.currentSegment.cuePoints.pop()}break;case Zt.CueTrack:{const t=this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;t.trackId=or(e,n)}break;case Zt.CueClusterPosition:{const r=this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length-1];if(!r)break;t(this.currentSegment),r.clusterPosition=this.currentSegment.dataStartPos+or(e,n)}break;case Zt.Timestamp:if(!this.currentCluster)break;this.currentCluster.timestamp=or(e,n);break;case Zt.SimpleBlock:{if(!this.currentCluster)break;const t=nr(e);if(null===t)break;const r=this.getTrackDataInCluster(this.currentCluster,t);if(!r)break;const i=la(e),a=sa(e),s=a>>1&3;let c=!!(128&a);"audio"===r.track.info?.type&&r.track.info.codec&&(c=!0);const l=aa(e,n-(e.filePos-o)),d=r.track.decodingInstructions.length>0;r.blocks.push({timestamp:i,duration:0,isKeyFrame:c,data:l,lacing:s,decoded:!d,mainAdditional:null})}break;case Zt.BlockGroup:if(!this.currentCluster)break;this.readContiguousElements(e.slice(o,n)),this.currentBlock=null;break;case Zt.Block:{if(!this.currentCluster)break;const t=nr(e);if(null===t)break;const r=this.getTrackDataInCluster(this.currentCluster,t);if(!r)break;const i=la(e),a=sa(e)>>1&3,s=aa(e,n-(e.filePos-o)),c=r.track.decodingInstructions.length>0;this.currentBlock={timestamp:i,duration:0,isKeyFrame:!0,data:s,lacing:a,decoded:!c,mainAdditional:null},r.blocks.push(this.currentBlock)}break;case Zt.BlockAdditions:this.readContiguousElements(e.slice(o,n));break;case Zt.BlockMore:if(!this.currentBlock)break;this.currentBlockAdditional={addId:1,data:null},this.readContiguousElements(e.slice(o,n)),this.currentBlockAdditional.data&&1===this.currentBlockAdditional.addId&&(this.currentBlock.mainAdditional=this.currentBlockAdditional.data),this.currentBlockAdditional=null;break;case Zt.BlockAdditional:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.data=aa(e,n);break;case Zt.BlockAddID:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.addId=or(e,n);break;case Zt.BlockDuration:if(!this.currentBlock)break;this.currentBlock.duration=or(e,n);break;case Zt.ReferenceBlock:if(!this.currentBlock)break;this.currentBlock.isKeyFrame=!1;break;case Zt.Tag:this.currentTagTargetIsMovie=!0,this.readContiguousElements(e.slice(o,n));break;case Zt.Targets:this.readContiguousElements(e.slice(o,n));break;case Zt.TargetTypeValue:50!==or(e,n)&&(this.currentTagTargetIsMovie=!1);break;case Zt.TagTrackUID:case Zt.TagEditionUID:case Zt.TagChapterUID:case Zt.TagAttachmentUID:this.currentTagTargetIsMovie=!1;break;case Zt.SimpleTag:if(!this.currentTagTargetIsMovie)break;this.currentSimpleTagName=null,this.readContiguousElements(e.slice(o,n));break;case Zt.TagName:this.currentSimpleTagName=hr(e,n);break;case Zt.TagString:{if(!this.currentSimpleTagName)break;const t=hr(e,n);this.processTagValue(this.currentSimpleTagName,t)}break;case Zt.TagBinary:{if(!this.currentSimpleTagName)break;const t=aa(e,n);this.processTagValue(this.currentSimpleTagName,t)}break;case Zt.AttachedFile:{if(!this.currentSegment)break;this.currentAttachedFile={fileUid:null,fileName:null,fileMediaType:null,fileData:null,fileDescription:null},this.readContiguousElements(e.slice(o,n));const t=this.currentSegment.metadataTags;if(this.currentAttachedFile.fileUid&&this.currentAttachedFile.fileData&&(t.raw??(t.raw={}),t.raw[this.currentAttachedFile.fileUid.toString()]=new ee(this.currentAttachedFile.fileData,this.currentAttachedFile.fileMediaType??void 0,this.currentAttachedFile.fileName??void 0,this.currentAttachedFile.fileDescription??void 0)),this.currentAttachedFile.fileMediaType?.startsWith("image/")&&this.currentAttachedFile.fileData){const e=this.currentAttachedFile.fileName;let r="unknown";if(e){const t=e.toLowerCase();t.startsWith("cover.")?r="coverFront":t.startsWith("back.")&&(r="coverBack")}t.images??(t.images=[]),t.images.push({data:this.currentAttachedFile.fileData,mimeType:this.currentAttachedFile.fileMediaType,kind:r,name:this.currentAttachedFile.fileName??void 0,description:this.currentAttachedFile.fileDescription??void 0})}this.currentAttachedFile=null}break;case Zt.FileUID:if(!this.currentAttachedFile)break;this.currentAttachedFile.fileUid=((e,t)=>{if(t<1)throw new Error("Bad unsigned int size "+t);let r=0n;for(let i=0;it.order-e.order);break;case Zt.ContentEncoding:this.currentDecodingInstruction={order:0,scope:Br.Block,data:null},this.readContiguousElements(e.slice(o,n)),this.currentDecodingInstruction.data&&this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction),this.currentDecodingInstruction=null;break;case Zt.ContentEncodingOrder:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.order=or(e,n);break;case Zt.ContentEncodingScope:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.scope=or(e,n);break;case Zt.ContentCompression:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decompress",algorithm:Fr.Zlib,settings:null},this.readContiguousElements(e.slice(o,n));break;case Zt.ContentCompAlgo:if("decompress"!==this.currentDecodingInstruction?.data?.type)break;this.currentDecodingInstruction.data.algorithm=or(e,n);break;case Zt.ContentCompSettings:if("decompress"!==this.currentDecodingInstruction?.data?.type)break;this.currentDecodingInstruction.data.settings=aa(e,n);break;case Zt.ContentEncryption:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decrypt"}}return e.filePos=o+n,!0}decodeBlockData(e,r){t(e.decodingInstructions.length>0);let i=r;for(const a of e.decodingInstructions)if(t(a.data),"decompress"===a.data.type)if(a.data.algorithm===Fr.HeaderStripping)if(a.data.settings&&a.data.settings.length>0){const e=a.data.settings,t=new Uint8Array(e.length+i.length);t.set(e,0),t.set(i,e.length),i=t}return i}processTagValue(e,t){var r;if(!this.currentSegment?.metadataTags)return;const i=this.currentSegment.metadataTags;if(i.raw??(i.raw={}),(r=i.raw)[e]??(r[e]=t),"string"===typeof t)switch(e.toLowerCase()){case"title":i.title??(i.title=t);break;case"description":i.description??(i.description=t);break;case"artist":i.artist??(i.artist=t);break;case"album":i.album??(i.album=t);break;case"album_artist":i.albumArtist??(i.albumArtist=t);break;case"genre":i.genre??(i.genre=t);break;case"comment":i.comment??(i.comment=t);break;case"lyrics":i.lyrics??(i.lyrics=t);break;case"date":{const e=new Date(t);Number.isNaN(e.getTime())||(i.date??(i.date=e))}break;case"track_number":case"part_number":{const e=t.split("/"),r=Number.parseInt(e[0],10),a=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(i.trackNumber??(i.trackNumber=r)),a&&Number.isInteger(a)&&a>0&&(i.tracksTotal??(i.tracksTotal=a))}break;case"disc_number":case"disc":{const e=t.split("/"),r=Number.parseInt(e[0],10),a=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(i.discNumber??(i.discNumber=r)),a&&Number.isInteger(a)&&a>0&&(i.discsTotal??(i.discsTotal=a))}}}}class Nr{constructor(e){this.internalTrack=e,this.packetToClusterLocation=new WeakMap}getId(){return this.internalTrack.id}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.codecId}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}async getFirstTimestamp(){const e=await this.getFirstPacket({metadataOnly:!0});return e?.timestamp??0}getTimeResolution(){return this.internalTrack.segment.timestampFactor}getDisposition(){return this.internalTrack.disposition}async getFirstPacket(e){return this.performClusterLookup(null,e=>e.trackData.get(this.internalTrack.id)?{blockIndex:0,correctBlockFound:!0}:{blockIndex:-1,correctBlockFound:!1},-1/0,1/0,e)}intoTimescale(e){return A(e*this.internalTrack.segment.timestampFactor)}async getPacket(e,t){const r=this.intoTimescale(e);return this.performClusterLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const i=S(t.presentationTimestamps,r,e=>e.timestamp);return{blockIndex:-1!==i?t.presentationTimestamps[i].blockIndex:-1,correctBlockFound:-1!==i&&r{if(e===r.cluster){const t=e.trackData.get(this.internalTrack.id);if(r.blockIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const i=x(t.presentationTimestamps,e=>t.blocks[e.blockIndex].isKeyFrame&&e.timestamp<=r);return{blockIndex:-1!==i?t.presentationTimestamps[i].blockIndex:-1,correctBlockFound:-1!==i&&r{if(e===i.cluster){const t=e.trackData.get(this.internalTrack.id).blocks.findIndex((e,t)=>e.isKeyFrame&&t>i.blockIndex);if(-1!==t)return{blockIndex:t,correctBlockFound:!0}}else{const r=e.trackData.get(this.internalTrack.id);if(r&&null!==r.firstKeyFrameTimestamp){const e=r.blocks.findIndex(e=>e.isKeyFrame);return t(-1!==e),{blockIndex:e,correctBlockFound:!0}}}return{blockIndex:-1,correctBlockFound:!1}},-1/0,1/0,r)}async fetchPacketInCluster(e,r,i){if(-1===r)return null;const a=e.trackData.get(this.internalTrack.id).blocks[r];t(a),a.decoded||(a.data=this.internalTrack.demuxer.decodeBlockData(this.internalTrack,a.data),a.decoded=!0);const s=i.metadataOnly?Ge:a.data,n=a.timestamp/this.internalTrack.segment.timestampFactor,o=a.duration/this.internalTrack.segment.timestampFactor,c={};a.mainAdditional&&"video"===this.internalTrack.info?.type&&this.internalTrack.info.alphaMode&&(c.alpha=i.metadataOnly?Ge:a.mainAdditional,c.alphaByteLength=a.mainAdditional.byteLength);const l=new Xe(s,a.isKeyFrame?"key":"delta",n,o,e.dataStartPos+r,a.data.byteLength,c);return this.packetToClusterLocation.set(l,{cluster:e,blockIndex:r}),l}async performClusterLookup(e,r,i,a,s){const{demuxer:n,segment:o}=this.internalTrack;let c=null,l=null,d=-1;if(e){const{blockIndex:t,correctBlockFound:i}=r(e);if(i)return this.fetchPacketInCluster(e,t,s);-1!==t&&(l=e,d=t)}const u=S(this.internalTrack.cuePoints,i,e=>e.time),h=-1!==u?this.internalTrack.cuePoints[u]:null,m=S(this.internalTrack.clusterPositionCache,i,e=>e.startTimestamp),f=-1!==m?this.internalTrack.clusterPositionCache[m]:null,p=Math.max(h?.clusterPosition??0,f?.elementStartPos??0)||null;let g;for(e?null===p||e.elementStartPos>=p?(g=e.elementEndPos,c=e):g=p:g=p??o.clusterSeekStartPos;null===o.elementEndPos||g<=o.elementEndPos-2;){if(c){const e=c.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>a)break}let e=n.reader.requestSliceRange(g,2,ar);if(e instanceof Promise&&(e=await e),!e)break;const i=g,u=dr(e);if(!u||!rr.includes(u.id)&&u.id!==Zt.Void){const e=await pr(n.reader,i,rr,Math.min(o.elementEndPos??1/0,i+Rr));if(e){g=e;continue}break}const h=u.id;let m=u.size;const f=e.filePos;if(h===Zt.Cluster){c=await n.readCluster(i,o),m=c.elementEndPos-f;const{blockIndex:e,correctBlockFound:t}=r(c);if(t)return this.fetchPacketInCluster(c,e,s);-1!==e&&(l=c,d=e)}if(void 0===m){t(h!==Zt.Cluster);m=(await fr(n.reader,f,ir,o.elementEndPos)).pos-f}const p=f+m;if(null===o.elementEndPos){let e=n.reader.requestSliceRange(p,2,ar);if(e instanceof Promise&&(e=await e),!e)break;if(cr(e)===Zt.Segment){o.elementEndPos=p;break}}g=p}if(h&&(!l||l.elementStartPos{let e=null;return("vp9"===this.internalTrack.info.codec||"av1"===this.internalTrack.info.codec||"avc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription||"hevc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription)&&(e=await this.getFirstPacket({})),{codec:ne({width:this.internalTrack.info.width,height:this.internalTrack.info.height,codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,colorSpace:this.internalTrack.info.colorSpace,avcType:1,avcCodecInfo:"avc"===this.internalTrack.info.codec&&e?Pe(e.data):null,hevcCodecInfo:"hevc"===this.internalTrack.info.codec&&e?Be(e.data):null,vp9CodecInfo:"vp9"===this.internalTrack.info.codec&&e?ze(e.data):null,av1CodecInfo:"av1"===this.internalTrack.info.codec&&e?Le(e.data):null}),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0}})()):null}}class Or extends Nr{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return this.internalTrack.info.codec?this.decoderConfig??(this.decoderConfig={codec:oe({codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,aacCodecInfo:this.internalTrack.info.aacCodecInfo}),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}):null}}const Lr=[44100,48e3,32e3],Ur=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1,-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1,-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1],Vr=(e,t)=>{const r=e>>>24,i=e>>>16&255,a=e>>>8&255,s=255&e;if(255!==r&&255!==i&&255!==a&&255!==s)return{header:null,bytesAdvanced:4};if(255!==r)return{header:null,bytesAdvanced:1};if(224!==(224&i))return{header:null,bytesAdvanced:1};let n=0,o=0;16&i?n=8&i?0:1:(n=1,o=1);const c=i>>3&3,l=i>>1&3,d=(a>>2&3)%3,u=s>>6&3,h=s>>4&3,m=s>>3&1,f=s>>2&1,p=3&s,g=Ur[16*n*4+16*l+(a>>4&15)];if(-1===g)return{header:null,bytesAdvanced:1};const k=1e3*g,b=Lr[d]>>n+o,T=((e,t,r,i,a)=>0===t?0:1===t?Math.floor(144*r/(i<>1&1);if(null!==t&&t{let t=2130706432,r=0;for(;0!==t;)r>>=1,r|=e&t,t>>=8;return r};var Hr,Wr,jr,Kr;(Wr=Hr||(Hr={}))[Wr.Unsynchronisation=128]="Unsynchronisation",Wr[Wr.ExtendedHeader=64]="ExtendedHeader",Wr[Wr.ExperimentalIndicator=32]="ExperimentalIndicator",Wr[Wr.Footer=16]="Footer",(Kr=jr||(jr={}))[Kr.ISO_8859_1=0]="ISO_8859_1",Kr[Kr.UTF_16_WITH_BOM=1]="UTF_16_WITH_BOM",Kr[Kr.UTF_16_BE_NO_BOM=2]="UTF_16_BE_NO_BOM",Kr[Kr.UTF_8=3]="UTF_8";const $r=128,Qr=["Blues","Classic rock","Country","Dance","Disco","Funk","Grunge","Hip-hop","Jazz","Metal","New age","Oldies","Other","Pop","Rhythm and blues","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death metal","Pranks","Soundtrack","Euro-techno","Ambient","Trip-hop","Vocal","Jazz & funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound clip","Gospel","Noise","Alternative rock","Bass","Soul","Punk","Space","Meditative","Instrumental pop","Instrumental rock","Ethnic","Gothic","Darkwave","Techno-industrial","Electronic","Pop-folk","Eurodance","Dream","Southern rock","Comedy","Cult","Gangsta","Top 40","Christian rap","Pop/funk","Jungle music","Native US","Cabaret","New wave","Psychedelic","Rave","Showtunes","Trailer","Lo-fi","Tribal","Acid punk","Acid jazz","Polka","Retro","Musical","Rock 'n' roll","Hard rock","Folk","Folk rock","National folk","Swing","Fast fusion","Bebop","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic rock","Progressive rock","Psychedelic rock","Symphonic rock","Slow rock","Big band","Chorus","Easy listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber music","Sonata","Symphony","Booty bass","Primus","Porn groove","Satire","Slow jam","Club","Tango","Samba","Folklore","Ballad","Power ballad","Rhythmic Soul","Freestyle","Duet","Punk rock","Drum solo","A cappella","Euro-house","Dance hall","Goa music","Drum & bass","Club-house","Hardcore techno","Terror","Indie","Britpop","Negerpunk","Polsk punk","Beat","Christian gangsta rap","Heavy metal","Black metal","Crossover","Contemporary Christian","Christian rock","Merengue","Salsa","Thrash metal","Anime","Jpop","Synthpop","Christmas","Art rock","Baroque","Bhangra","Big beat","Breakbeat","Chillout","Downtempo","Dub","EBM","Eclectic","Electro","Electroclash","Emo","Experimental","Garage","Global","IDM","Illbient","Industro-Goth","Jam Band","Krautrock","Leftfield","Lounge","Math rock","New romantic","Nu-breakz","Post-punk","Post-rock","Psytrance","Shoegaze","Space rock","Trop rock","World music","Neoclassical","Audiobook","Audio theatre","Neue Deutsche Welle","Podcast","Indie rock","G-Funk","Dubstep","Garage rock","Psybient"],Gr=(e,t)=>{const r=aa(e,t),i=Q(r.indexOf(0),r.length),a=r.subarray(0,i);let s="";for(let n=0;n{const t=e.filePos,r=ya(e,3),i=sa(e),a=sa(e),s=sa(e),n=ua(e);if("ID3"!==r||255===i||255===a||0!==(2155905152&n))return e.filePos=t,null;return{majorVersion:i,revision:a,flags:s,size:qr(n)}},Yr=(e,t,r)=>{var i,a,s,n;if(![2,3,4].includes(t.majorVersion))return void console.warn(`Unsupported ID3v2 major version: ${t.majorVersion}`);const o=aa(e,t.size),c=new Jr(t,o);if(t.flags&Hr.Footer&&c.removeFooter(),t.flags&Hr.Unsynchronisation&&3===t.majorVersion&&c.ununsynchronizeAll(),t.flags&Hr.ExtendedHeader){const e=c.readU32();3===t.majorVersion?c.pos+=e:c.pos+=e-4}for(;c.pos<=c.bytes.length-c.frameHeaderSize();){const e=c.readId3V2Frame();if(!e)break;const o=c.pos,l=c.pos+e.size;let d=!1,u=!1,h=!1;if(3===t.majorVersion?(d=!!(64&e.flags),u=!!(128&e.flags)):4===t.majorVersion&&(d=!!(4&e.flags),u=!!(8&e.flags),h=!!(2&e.flags)||!!(t.flags&Hr.Unsynchronisation)),d)console.warn(`Skipping encrypted ID3v2 frame ${e.id}`),c.pos=l;else if(u)console.warn(`Skipping compressed ID3v2 frame ${e.id}`),c.pos=l;else{switch(h&&c.ununsynchronizeRegion(c.pos,l),r.raw??(r.raw={}),"T"===e.id[0]?(i=r.raw)[a=e.id]??(i[a]=c.readId3V2EncodingAndText(l)):(s=r.raw)[n=e.id]??(s[n]=c.readBytes(e.size)),c.pos=o,e.id){case"TIT2":case"TT2":r.title??(r.title=c.readId3V2EncodingAndText(l));break;case"TIT3":case"TT3":r.description??(r.description=c.readId3V2EncodingAndText(l));break;case"TPE1":case"TP1":r.artist??(r.artist=c.readId3V2EncodingAndText(l));break;case"TALB":case"TAL":r.album??(r.album=c.readId3V2EncodingAndText(l));break;case"TPE2":case"TP2":r.albumArtist??(r.albumArtist=c.readId3V2EncodingAndText(l));break;case"TRCK":case"TRK":{const e=c.readId3V2EncodingAndText(l).split("/"),t=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(r.trackNumber??(r.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&(r.tracksTotal??(r.tracksTotal=i))}break;case"TPOS":case"TPA":{const e=c.readId3V2EncodingAndText(l).split("/"),t=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(r.discNumber??(r.discNumber=t)),i&&Number.isInteger(i)&&i>0&&(r.discsTotal??(r.discsTotal=i))}break;case"TCON":case"TCO":{const e=c.readId3V2EncodingAndText(l);let t=/^\((\d+)\)/.exec(e);if(t){const e=Number.parseInt(t[1]);if(void 0!==Qr[e]){r.genre??(r.genre=Qr[e]);break}}if(t=/^\d+$/.exec(e),t){const e=Number.parseInt(t[0]);if(void 0!==Qr[e]){r.genre??(r.genre=Qr[e]);break}}r.genre??(r.genre=e)}break;case"TDRC":case"TDAT":{const e=c.readId3V2EncodingAndText(l),t=new Date(e);Number.isNaN(t.getTime())||(r.date??(r.date=t))}break;case"TYER":case"TYE":{const e=c.readId3V2EncodingAndText(l),t=Number.parseInt(e,10);Number.isInteger(t)&&(r.date??(r.date=new Date(t,0,1)))}break;case"USLT":case"ULT":{const e=c.readU8();c.pos+=3,c.readId3V2Text(e,l),r.lyrics??(r.lyrics=c.readId3V2Text(e,l))}break;case"COMM":case"COM":{const e=c.readU8();c.pos+=3,c.readId3V2Text(e,l),r.comment??(r.comment=c.readId3V2Text(e,l))}break;case"APIC":case"PIC":{const e=c.readId3V2TextEncoding();let i;if(2===t.majorVersion){const e=c.readAscii(3);i="PNG"===e?"image/png":"JPG"===e?"image/jpeg":"image/*"}else i=c.readId3V2Text(e,l);const a=c.readU8(),s=c.readId3V2Text(e,l).trimEnd(),n=l-c.pos;if(n>=0){const e=c.readBytes(n);r.images||(r.images=[]),r.images.push({data:e,mimeType:i,kind:3===a?"coverFront":4===a?"coverBack":"unknown",description:s})}}break;default:c.pos+=e.size}c.pos=l}}};class Jr{constructor(e,t){this.header=e,this.bytes=t,this.pos=0,this.view=new DataView(t.buffer,t.byteOffset,t.byteLength)}frameHeaderSize(){return 2===this.header.majorVersion?6:10}ununsynchronizeAll(){const e=[];for(let t=0;t{const t=this.pos+e;if(t>this.bytes.length)return!1;if(t<=this.bytes.length-this.frameHeaderSize()){this.pos+=e;const t=this.readAscii(4);if("\0\0\0\0"!==t&&!/[0-9A-Z]{4}/.test(t))return!1}return!0};if(!s(r)){const e=4===this.header.majorVersion?t:qr(t);s(e)&&(r=e)}return this.pos=a,{id:e,size:r,flags:i}}}readId3V2TextEncoding(){const e=this.readU8();if(e>3)throw new Error(`Unsupported text encoding: ${e}`);return e}readId3V2Text(e,t){const r=this.pos,i=this.readBytes(t-this.pos);switch(e){case jr.ISO_8859_1:{let e="";for(let t=0;t0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(2,t))}if(254===i[0]&&255===i[1]){const e=new TextDecoder("utf-16be"),t=Q(i.findIndex((e,t)=>0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(2,t))}{const e=Q(i.findIndex(e=>0===e),i.length);return this.pos=r+Math.min(e+1,i.length),l.decode(i.subarray(0,e))}case jr.UTF_16_BE_NO_BOM:{const e=new TextDecoder("utf-16be"),t=Q(i.findIndex((e,t)=>0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(0,t))}case jr.UTF_8:{const e=Q(i.findIndex(e=>0===e),i.length);return this.pos=r+Math.min(e+1,i.length),l.decode(i.subarray(0,e))}}}readId3V2EncodingAndText(e){if(this.pos>=e)return"";const t=this.readId3V2TextEncoding();return this.readId3V2Text(t,e)}}const Zr=async(e,t,r)=>{let i=t;for(;null===r||i{for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)await this.advanceReader();if(!this.firstFrameHeader)throw new Error("No valid MP3 frame found.");this.tracks=[new Mt(this.input,new ti(this))]})())}async advanceReader(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,10);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const t=Xr(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}const e=await Zr(this.reader,this.lastLoadedPos,this.reader.fileSize);if(!e)return void(this.lastSampleLoaded=!0);const t=e.header;this.lastLoadedPos=e.startPos+t.totalSize-1;const r=(i=t.mpegVersionId,a=t.channel,3===i?3===a?21:36:3===a?13:21);var i,a;let s=this.reader.requestSlice(e.startPos+r,4);if(s instanceof Promise&&(s=await s),s){const e=ua(s);if(1483304551===e||1231971951===e)return}this.firstFrameHeader||(this.firstFrameHeader=t),t.sampleRate!==this.firstFrameHeader.sampleRate&&console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${t.sampleRate} Hz. Might be a bug, so please report this file.`);const n=t.audioSamplesInFrame/this.firstFrameHeader.sampleRate,o={timestamp:this.nextTimestampInSamples/this.firstFrameHeader.sampleRate,duration:n,dataStart:e.startPos,dataSize:t.totalSize};this.loadedSamples.push(o),this.nextTimestampInSamples+=t.audioSamplesInFrame}async getMimeType(){return"audio/mpeg"}async getTracks(){return await this.readMetadata(),this.tracks}async computeDuration(){await this.readMetadata();const e=this.tracks[0];return t(e),e.computeDuration()}async getMetadataTags(){const e=await this.readingMutex.acquire();try{if(await this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0,r=!1;for(;;){let t=this.reader.requestSlice(e,10);if(t instanceof Promise&&(t=await t),!t)break;const i=Xr(t);if(!i)break;r=!0;let a=this.reader.requestSlice(t.filePos,i.size);if(a instanceof Promise&&(a=await a),!a)break;Yr(a,i,this.metadataTags),e=t.filePos+i.size}if(!r&&null!==this.reader.fileSize&&this.reader.fileSize>=$r){let e=this.reader.requestSlice(this.reader.fileSize-$r,$r);e instanceof Promise&&(e=await e),t(e);"TAG"===ya(e,3)&&((e,t)=>{var r;const i=e.filePos;t.raw??(t.raw={}),(r=t.raw).TAG??(r.TAG=aa(e,125)),e.filePos=i;const a=Gr(e,30);a&&(t.title??(t.title=a));const s=Gr(e,30);s&&(t.artist??(t.artist=s));const n=Gr(e,30);n&&(t.album??(t.album=n));const o=Gr(e,4),c=Number.parseInt(o,10);Number.isInteger(c)&&c>0&&(t.date??(t.date=new Date(c,0,1)));const l=aa(e,30);let d;if(0===l[28]&&0!==l[29]){const r=l[29];r>0&&(t.trackNumber??(t.trackNumber=r)),e.skip(-30),d=Gr(e,28),e.skip(2)}else e.skip(-30),d=Gr(e,30);d&&(t.comment??(t.comment=d));const u=sa(e);ue.timestamp);if(-1===r)throw new Error("Packet was not created from this track.");const i=r+1;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{r()}}async getPacket(e,t){const r=await this.demuxer.readingMutex.acquire();try{for(;;){const r=S(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===r&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(r,t);if(r>=0&&r+1>>0&4294967295}const ai=e=>{const t=c(e),r=t.getUint32(22,!0);t.setUint32(22,0,!0);let i=0;for(let a=0;a>>24^t])>>>0}return t.setUint32(22,r,!0),i},si=(e,r,i)=>{let a=0,s=null;if(e.length>0)if("vorbis"===r.codec){t(r.vorbisInfo);const n=(1<<(e=>{let t=0;for(;e;)t++,e>>=1;return t})(r.vorbisInfo.modeBlockflags.length-1))-1<<1,o=(e[0]&n)>>1;if(o>=r.vorbisInfo.modeBlockflags.length)throw new Error("Invalid mode number.");let c=i;const l=r.vorbisInfo.modeBlockflags[o];if(s=r.vorbisInfo.blocksizes[l],1===l){const t=1+(1|n),i=e[0]&t?1:0;c=r.vorbisInfo.blocksizes[i]}a=null!==c?c+s>>2:0}else if("opus"===r.codec){a=(e=>{const t=e[0]>>3;return{durationInSamples:Ue[t]}})(e).durationInSamples}return{durationInSamples:a,vorbisBlockSize:s}},ni=27,oi=282,ci=e=>{const t=e.filePos;if(ha(e)!==ri)return null;e.skip(1);const r=sa(e),i=ka(e),a=ha(e),s=ha(e),n=ha(e),o=sa(e),c=new Uint8Array(o);for(let u=0;ue+t,0);return{headerStartPos:t,totalSize:l+d,dataStartPos:t+l,dataSize:d,headerType:r,granulePosition:i,serialNumber:a,sequenceNumber:s,checksum:n,lacingValues:c}},li=(e,t)=>{for(;e.filePos>>8&255)===r||(t>>>16&255)===r||(t>>>24&255)===r){if(e.skip(-4),t===ri)return!0;e.skip(1)}}return!1};class di extends Ke{constructor(e){super(e),this.metadataPromise=null,this.bitstreams=[],this.tracks=[],this.metadataTags={},this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,ni,oi);if(t instanceof Promise&&(t=await t),!t)break;const r=ci(t);if(!r)break;if(!!!(2&r.headerType))break;this.bitstreams.push({serialNumber:r.serialNumber,bosPage:r,description:null,numberOfChannels:-1,sampleRate:-1,codecInfo:{codec:null,vorbisInfo:null,opusInfo:null},lastMetadataPacket:null}),e=r.headerStartPos+r.totalSize}for(const t of this.bitstreams){const e=await this.readPacket(t.bosPage,0);e&&(e.data.byteLength>=7&&1===e.data[0]&&118===e.data[1]&&111===e.data[2]&&114===e.data[3]&&98===e.data[4]&&105===e.data[5]&&115===e.data[6]?await this.readVorbisMetadata(e,t):e.data.byteLength>=8&&79===e.data[0]&&112===e.data[1]&&117===e.data[2]&&115===e.data[3]&&72===e.data[4]&&101===e.data[5]&&97===e.data[6]&&100===e.data[7]&&await this.readOpusMetadata(e,t),null!==t.codecInfo.codec&&this.tracks.push(new Mt(this.input,new ui(t,this))))}})())}async readVorbisMetadata(e,t){let r=await this.findNextPacketStart(e);if(!r)return;const i=await this.readPacket(r.startPage,r.startSegmentIndex);if(!i)return;if(r=await this.findNextPacketStart(i),!r)return;const a=await this.readPacket(r.startPage,r.startSegmentIndex);if(!a)return;if(3!==i.data[0]||5!==a.data[0])return;const s=[],n=e=>{for(;s.push(Math.min(255,e)),!(e<255);)e-=255};n(e.data.length),n(i.data.length);const o=new Uint8Array(1+s.length+e.data.length+i.data.length+a.data.length);o[0]=2,o.set(s,1),o.set(e.data,1+s.length),o.set(i.data,1+s.length+e.data.length),o.set(a.data,1+s.length+e.data.length+i.data.length),t.codecInfo.codec="vorbis",t.description=o,t.lastMetadataPacket=a;const l=c(e.data);t.numberOfChannels=l.getUint8(11),t.sampleRate=l.getUint32(12,!0);const d=l.getUint8(28);t.codecInfo.vorbisInfo={blocksizes:[1<<(15&d),1<<(d>>4)],modeBlockflags:Ve(a.data).modeBlockflags},je(i.data.subarray(7),this.metadataTags)}async readOpusMetadata(e,t){const r=await this.findNextPacketStart(e);if(!r)return;const i=await this.readPacket(r.startPage,r.startSegmentIndex);if(!i)return;t.codecInfo.codec="opus",t.description=e.data,t.lastMetadataPacket=i;const a=(e=>{const t=c(e),r=t.getUint8(9),i=t.getUint16(10,!0),a=t.getUint32(12,!0),s=t.getInt16(16,!0),n=t.getUint8(18);let o=null;return n&&(o=e.subarray(19,21+r)),{outputChannelCount:r,preSkip:i,inputSampleRate:a,outputGain:s,channelMappingFamily:n,channelMappingTable:o}})(e.data);t.numberOfChannels=a.outputChannelCount,t.sampleRate=ue,t.codecInfo.opusInfo={preSkip:a.preSkip},je(i.data.subarray(8),this.metadataTags)}async readPacket(e,r){t(re+t.length,0);if(0===c)return null;const l=new Uint8Array(c);let d=0;for(let t=0;t{let t="audio/ogg";e.codecStrings&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({codecStrings:(await Promise.all(this.tracks.map(e=>e.getCodecParameterString()))).filter(Boolean)})}async getTracks(){return await this.readMetadata(),this.tracks}async computeDuration(){const e=await this.getTracks(),t=await Promise.all(e.map(e=>e.computeDuration()));return Math.max(0,...t)}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}}class ui{constructor(e,t){this.bitstream=e,this.demuxer=t,this.encodedPacketToMetadata=new WeakMap,this.sequentialScanCache=[],this.sequentialScanMutex=new b,this.internalSampleRate="opus"===e.codecInfo.codec?ue:e.sampleRate}getId(){return this.bitstream.serialNumber}getNumberOfChannels(){return this.bitstream.numberOfChannels}getSampleRate(){return this.bitstream.sampleRate}getTimeResolution(){return this.bitstream.sampleRate}getCodec(){return this.bitstream.codecInfo.codec}getInternalCodecId(){return null}async getDecoderConfig(){return t(this.bitstream.codecInfo.codec),{codec:this.bitstream.codecInfo.codec,numberOfChannels:this.bitstream.numberOfChannels,sampleRate:this.bitstream.sampleRate,description:this.bitstream.description??void 0}}getName(){return null}getLanguageCode(){return D}getDisposition(){return{...te}}async getFirstTimestamp(){return 0}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}granulePositionToTimestampInSamples(e){return"opus"===this.bitstream.codecInfo.codec?(t(this.bitstream.codecInfo.opusInfo),e-this.bitstream.codecInfo.opusInfo.preSkip):e}createEncodedPacketFromOggPacket(e,t,r){if(!e)return null;const{durationInSamples:i,vorbisBlockSize:a}=si(e.data,this.bitstream.codecInfo,t.vorbisLastBlocksize),s=new Xe(r.metadataOnly?Ge:e.data,"key",Math.max(0,t.timestampInSamples)/this.internalSampleRate,i/this.internalSampleRate,e.endPage.headerStartPos+e.endSegmentIndex,e.data.byteLength);return this.encodedPacketToMetadata.set(s,{packet:e,timestampInSamples:t.timestampInSamples,durationInSamples:i,vorbisLastBlockSize:t.vorbisLastBlocksize,vorbisBlockSize:a}),s}async getFirstPacket(e){t(this.bitstream.lastMetadataPacket);const r=await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!r)return null;let i=0;"opus"===this.bitstream.codecInfo.codec&&(t(this.bitstream.codecInfo.opusInfo),i-=this.bitstream.codecInfo.opusInfo.preSkip);const a=await this.demuxer.readPacket(r.startPage,r.startSegmentIndex);return this.createEncodedPacketFromOggPacket(a,{timestampInSamples:i,vorbisLastBlocksize:null},e)}async getNextPacket(e,t){const r=this.encodedPacketToMetadata.get(e);if(!r)throw new Error("Packet was not created from this track.");const i=await this.demuxer.findNextPacketStart(r.packet);if(!i)return null;const a=r.timestampInSamples+r.durationInSamples,s=await this.demuxer.readPacket(i.startPage,i.startSegmentIndex);return this.createEncodedPacketFromOggPacket(s,{timestampInSamples:a,vorbisLastBlocksize:r.vorbisBlockSize},t)}async getPacket(e,r){if(null===this.demuxer.reader.fileSize)return this.getPacketSequential(e,r);const i=A(e*this.internalSampleRate);if(0===i)return this.getFirstPacket(r);if(i<0)return null;t(this.bitstream.lastMetadataPacket);const a=await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!a)return null;let s=a.startPage,n=this.demuxer.reader.fileSize;const o=[s];e:for(;s.headerStartPos+s.totalSizei?n=d.headerStartPos:(s=d,o.push(d));continue e}a=d.headerStartPos+d.totalSize}}let c=a.startPage;for(const t of o){if(t.granulePosition===s.granulePosition)break;(!c||t.headerStartPos>c.headerStartPos)&&(c=t)}let l=c;const d=[l];for(;l.serialNumber!==this.bitstream.serialNumber||l.granulePosition!==s.granulePosition;){const e=l.headerStartPos+l.totalSize;let r=this.demuxer.reader.requestSliceRange(e,ni,oi);r instanceof Promise&&(r=await r),t(r);const i=ci(r);t(i),l=i,l.serialNumber===this.bitstream.serialNumber&&d.push(l)}t(-1!==l.granulePosition);let u,h,m=null,f=l,p=0;if(l.headerStartPos===a.startPage.headerStartPos)u=this.granulePositionToTimestampInSamples(0),h=!0,m=0;else{u=0,h=!1;for(let t=l.lacingValues.length-1;t>=0;t--){if(l.lacingValues[t]<255){m=t+1;break}}if(null===m)throw new Error("Invalid page with granule position: no packets end on this page.");p=m-1;const e={data:Ge,endPage:f,endSegmentIndex:p};if(await this.demuxer.findNextPacketStart(e)){const e=mi(d,l,m);t(e);const r=hi(d,e.page,e.segmentIndex);r&&(l=r.page,m=r.segmentIndex)}else for(;;){const e=mi(d,l,m);if(!e)break;const t=hi(d,e.page,e.segmentIndex);if(!t)break;if(l=t.page,m=t.segmentIndex,e.page.headerStartPos!==f.headerStartPos){f=e.page,p=e.segmentIndex;break}}}let g=null,k=null;for(;null!==l;){t(null!==m);const e=await this.demuxer.readPacket(l,m);if(!e)break;if(!(l.headerStartPos===a.startPage.headerStartPos&&mi||Math.max(s.timestampInSamples,0)===i))break}const s=await this.demuxer.findNextPacketStart(e);if(!s)break;l=s.startPage,m=s.startSegmentIndex}return g}async getPacketSequential(e,r){const a=await this.sequentialScanMutex.acquire();try{const a=A(e*this.internalSampleRate);e=a/this.internalSampleRate;const s=S(this.sequentialScanCache,a,e=>e.timestampInSamples);let n;if(-1!==s){const e=this.sequentialScanCache[s];n=this.createEncodedPacketFromOggPacket(e.packet,{timestampInSamples:e.timestampInSamples,vorbisLastBlocksize:e.vorbisLastBlockSize},r)}else n=await this.getFirstPacket(r);let o=0;for(;n&&n.timestampe)break;if(n=a,o++,100===o){o=0;const e=this.encodedPacketToMetadata.get(n);t(e),this.sequentialScanCache.length>0&&t(i(this.sequentialScanCache).timestampInSamples<=e.timestampInSamples),this.sequentialScanCache.push(e)}}return n}finally{a()}}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const hi=(e,r,i)=>{let a=r,s=i;e:for(;;){for(s--;s>=0;s--){if(a.lacingValues[s]<255){s++;break e}}t(-1===s);if(!(1&a.headerType)){s=0;break}const r=P(e,e=>e.headerStartPos{if(r>0)return{page:t,segmentIndex:r-1};const i=P(e,e=>e.headerStartPos{let e=this.reader.requestSlice(0,12);e instanceof Promise&&(e=await e),t(e);const r=ya(e,4),i="RIFX"!==r,a="RF64"===r,s=da(e,i);let n=a?this.reader.fileSize:Math.min(s+8,this.reader.fileSize??1/0);if("WAVE"!==ya(e,4))throw new Error("Invalid WAVE file - wrong format");let o=0,c=null,l=e.filePos;for(;null===n||l=18&&357!==a){const e=na(i,r),s=t-18;if(Math.min(s,e)>=22&&a===fi.EXTENSIBLE){i.skip(6);const e=aa(i,16);a=e[0]|e[1]<<8}}a!==fi.MULAW&&a!==fi.ALAW||(c=8),this.audioInfo={format:a,numberOfChannels:s,sampleRate:n,sampleSizeInBytes:Math.ceil(c/8),blockSizeInBytes:o}}async parseListChunk(e,t,r){var i,a,s,n,o,c,l,d,u,h,m;let f=this.reader.requestSlice(e,t);if(f instanceof Promise&&(f=await f),!f)return;const p=ya(f,4);if("INFO"!==p&&"INF0"!==p)return;let g=f.filePos;for(;g<=e+t-8;){f.filePos=g;const e=ya(f,4),t=da(f,r),p=aa(f,t);let k=0;for(let r=0;r0&&((c=this.metadataTags).trackNumber??(c.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&((l=this.metadataTags).tracksTotal??(l.tracksTotal=r))}break;case"ICRD":case"IDIT":{const e=new Date(b);Number.isNaN(e.getTime())||((d=this.metadataTags).date??(d.date=e))}break;case"YEAR":{const e=Number.parseInt(b,10);Number.isInteger(e)&&e>0&&((u=this.metadataTags).date??(u.date=new Date(e,0,1)))}break;case"IGNR":case"GENR":(h=this.metadataTags).genre??(h.genre=b);break;case"ICMT":case"CMNT":case"COMM":(m=this.metadataTags).comment??(m.comment=b)}g+=8+t+(1&t)}}async parseId3Chunk(e,t){let r=this.reader.requestSlice(e,t);if(r instanceof Promise&&(r=await r),!r)return;const i=Xr(r);if(i){const t=r.slice(e+10,i.size);Yr(t,i,this.metadataTags)}}getCodec(){if(t(this.audioInfo),this.audioInfo.format===fi.MULAW)return"ulaw";if(this.audioInfo.format===fi.ALAW)return"alaw";if(this.audioInfo.format===fi.PCM){if(1===this.audioInfo.sampleSizeInBytes)return"pcm-u8";if(2===this.audioInfo.sampleSizeInBytes)return"pcm-s16";if(3===this.audioInfo.sampleSizeInBytes)return"pcm-s24";if(4===this.audioInfo.sampleSizeInBytes)return"pcm-s32"}return this.audioInfo.format===fi.IEEE_FLOAT&&4===this.audioInfo.sampleSizeInBytes?"pcm-f32":null}async getMimeType(){return"audio/wav"}async computeDuration(){await this.readMetadata();const e=this.tracks[0];return t(e),e.computeDuration()}async getTracks(){return await this.readMetadata(),this.tracks}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}}const ki=2048;class bi{constructor(e){this.demuxer=e}getId(){return 1}getCodec(){return this.demuxer.getCodec()}getInternalCodecId(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.format}async getDecoderConfig(){const e=this.demuxer.getCodec();return e?(t(this.demuxer.audioInfo),{codec:e,numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate}):null}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}getNumberOfChannels(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getTimeResolution(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return D}getDisposition(){return{...te}}async getFirstTimestamp(){return 0}async getPacketAtIndex(e,r){t(this.demuxer.audioInfo);const i=e*ki*this.demuxer.audioInfo.blockSizeInBytes;if(i>=this.demuxer.dataSize)return null;const a=Math.min(ki*this.demuxer.audioInfo.blockSizeInBytes,this.demuxer.dataSize-i);if(null===this.demuxer.reader.fileSize){let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+i,a);if(e instanceof Promise&&(e=await e),!e)return null}let s;if(r.metadataOnly)s=Ge;else{let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+i,a);e instanceof Promise&&(e=await e),t(e),s=aa(e,a)}const n=e*ki/this.demuxer.audioInfo.sampleRate,o=a/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate;return this.demuxer.lastKnownPacketIndex=Math.max(e,n),new Xe(s,"key",n,o,e,a)}getFirstPacket(e){return this.getPacketAtIndex(0,e)}async getPacket(e,r){t(this.demuxer.audioInfo);const i=Math.floor(Math.min(e*this.demuxer.audioInfo.sampleRate/ki,(this.demuxer.dataSize-1)/(ki*this.demuxer.audioInfo.blockSizeInBytes))),a=await this.getPacketAtIndex(i,r);if(a)return a;if(0===i)return null;t(null===this.demuxer.reader.fileSize);let s=await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex,r);for(;s;){const e=await this.getNextPacket(s,r);if(!e)break;s=e}return s}getNextPacket(e,r){t(this.demuxer.audioInfo);const i=Math.round(e.timestamp*this.demuxer.audioInfo.sampleRate/ki);return this.getPacketAtIndex(i+1,r)}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Ti=e=>{const t=e.filePos,r=aa(e,9),i=new a(r);if(4095!==i.readBits(12))return null;i.skipBits(1);if(0!==i.readBits(2))return null;const s=i.readBits(1),n=i.readBits(2)+1,o=i.readBits(4);if(15===o)return null;i.skipBits(1);const c=i.readBits(3);if(0===c)throw new Error("ADTS frames with channel configuration 0 are not supported.");i.skipBits(1),i.skipBits(1),i.skipBits(1),i.skipBits(1);const l=i.readBits(13);i.skipBits(11);const d=i.readBits(2)+1;if(1!==d)throw new Error("ADTS frames with more than one AAC frame are not supported.");let u=null;return 1===s?e.filePos-=2:u=i.readBits(16),{objectType:n,samplingFrequencyIndex:o,channelConfiguration:c,frameLength:l,numberOfAacFrames:d,crcCheck:u,startPos:t}},yi=1024;class wi extends Ke{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.loadedSamples=[],this.tracks=[],this.readingMutex=new b,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)await this.advanceReader();t(this.firstFrameHeader),this.tracks=[new Mt(this.input,new Si(this))]})())}async advanceReader(){let e=this.reader.requestSliceRange(this.lastLoadedPos,7,9);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const r=Ti(e);if(!r)return void(this.lastSampleLoaded=!0);if(null!==this.reader.fileSize&&r.startPos+r.frameLength>this.reader.fileSize)return void(this.lastSampleLoaded=!0);this.firstFrameHeader||(this.firstFrameHeader=r);const i=ce[r.samplingFrequencyIndex];t(void 0!==i);const a=yi/i,s=r.crcCheck?9:7,n={timestamp:this.nextTimestampInSamples/i,duration:a,dataStart:r.startPos+s,dataSize:r.frameLength-s};this.loadedSamples.push(n),this.nextTimestampInSamples+=yi,this.lastLoadedPos=r.startPos+r.frameLength}async getMimeType(){return"audio/aac"}async getTracks(){return await this.readMetadata(),this.tracks}async computeDuration(){await this.readMetadata();const e=this.tracks[0];return t(e),e.computeDuration()}async getMetadataTags(){return{}}}class Si{constructor(e){this.demuxer=e}getId(){return 1}async getFirstTimestamp(){return 0}getTimeResolution(){return this.getSampleRate()/yi}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}getName(){return null}getLanguageCode(){return D}getCodec(){return"aac"}getInternalCodecId(){return t(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.objectType}getNumberOfChannels(){t(this.demuxer.firstFrameHeader);const e=le[this.demuxer.firstFrameHeader.channelConfiguration];return t(void 0!==e),e}getSampleRate(){t(this.demuxer.firstFrameHeader);const e=ce[this.demuxer.firstFrameHeader.samplingFrequencyIndex];return t(void 0!==e),e}getDisposition(){return{...te}}async getDecoderConfig(){t(this.demuxer.firstFrameHeader);const e=new Uint8Array(3),r=new a(e),{objectType:i,samplingFrequencyIndex:s,channelConfiguration:n}=this.demuxer.firstFrameHeader;return i>31?(r.writeBits(5,31),r.writeBits(6,i-32)):r.writeBits(5,i),r.writeBits(4,s),r.writeBits(4,n),{codec:`mp4a.40.${this.demuxer.firstFrameHeader.objectType}`,numberOfChannels:this.getNumberOfChannels(),sampleRate:this.getSampleRate(),description:e.subarray(0,Math.ceil((r.pos-1)/8))}}async getPacketAtIndex(e,t){if(-1===e)return null;const r=this.demuxer.loadedSamples[e];if(!r)return null;let i;if(t.metadataOnly)i=Ge;else{let e=this.demuxer.reader.requestSlice(r.dataStart,r.dataSize);if(e instanceof Promise&&(e=await e),!e)return null;i=aa(e,r.dataSize)}return new Xe(i,"key",r.timestamp,r.duration,e,r.dataSize)}getFirstPacket(e){return this.getPacketAtIndex(0,e)}async getNextPacket(e,t){const r=await this.demuxer.readingMutex.acquire();try{const r=w(this.demuxer.loadedSamples,e.timestamp,e=>e.timestamp);if(-1===r)throw new Error("Packet was not created from this track.");const i=r+1;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{r()}}async getPacket(e,t){const r=await this.demuxer.readingMutex.acquire();try{for(;;){const r=S(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===r&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(r,t);if(r>=0&&r+1{for(var r;null===this.reader.fileSize||ea.end-6)return{num:s.num,blockSize:s.blockSize,sampleRate:s.sampleRate,size:a.end-e,isLastFrame:!0};if(255===sa(a)){const t=a.filePos;if(sa(a)!==(1===this.blockingBit?249:248)){a.filePos=t;continue}a.skip(-2);const r=a.filePos-e,i=this.readFlacFrameHeader({slice:a,isFirstPacket:!1});if(!i){a.filePos=t;continue}if(0===this.blockingBit){if(i.num-s.num!==1){a.filePos=t;continue}}else if(i.num-s.num!==s.blockSize){a.filePos=t;continue}return{num:s.num,blockSize:s.blockSize,sampleRate:s.sampleRate,size:r,isLastFrame:!1}}}}readFlacFrameHeader({slice:e,isFirstPacket:r}){const i=e.filePos,s=aa(e,4),n=new a(s);if(32764!==n.readBits(15))return null;if(null===this.blockingBit){t(r);const e=n.readBits(1);this.blockingBit=e}else if(1===this.blockingBit){t(!r);if(1!==n.readBits(1))return null}else{if(0!==this.blockingBit)throw new Error("Invalid blocking bit");t(!r);if(0!==n.readBits(1))return null}const o=(e=>0===e?null:1===e?192:e>=2&&e<=5?144*2**e:6===e?"uncommon-u8":7===e?"uncommon-u16":e>=8&&e<=15?2**e:null)(n.readBits(4));if(!o)return null;t(this.audioInfo);const c=((e,t)=>{switch(e){case 0:return t;case 1:return 88200;case 2:return 176400;case 3:return 192e3;case 4:return 8e3;case 5:return 16e3;case 6:return 22050;case 7:return 24e3;case 8:return 32e3;case 9:return 44100;case 10:return 48e3;case 11:return 96e3;case 12:return"uncommon-u8";case 13:return"uncommon-u16";case 14:return"uncommon-u16-10";default:return null}})(n.readBits(4),this.audioInfo.sampleRate);if(!c)return null;n.readBits(4),n.readBits(3);if(0!==n.readBits(1))return null;const l=(e=>{let t=0;const r=new a(aa(e,1));for(;1===r.readBits(1);)t++;if(0===t)return r.readBits(7);const i=[],s=t-1,n=new a(aa(e,s)),o=8-t-1;for(let a=0;ae|t<"uncommon-u16"===r?oa(e)+1:"uncommon-u8"===r?sa(e)+1:"number"===typeof r?r:(C(r),void t(!1)))(e,o),u=((e,t)=>"uncommon-u16"===t?oa(e):"uncommon-u16-10"===t?10*oa(e):"uncommon-u8"===t?sa(e):"number"===typeof t?t:null)(e,c);if(null===u)return null;if(u!==this.audioInfo.sampleRate)return null;const h=e.filePos-i,m=sa(e);e.skip(-h),e.skip(-1);const f=(e=>{let t=0;for(const r of e){t^=r;for(let e=0;e<8;e++)0!==(128&t)?t=t<<1^7:t<<=1,t&=255}return t})(aa(e,h));return m!==f?null:{num:l,blockSize:d,sampleRate:u}}async advanceReader(){await this.readMetadata(),t(null!==this.lastLoadedPos),t(this.audioInfo);const e=this.lastLoadedPos,r=await this.readNextFlacFrame({startPos:e,isFirstPacket:0===this.loadedSamples.length});if(!r)return void(this.lastSampleLoaded=!0);const i=this.loadedSamples[this.loadedSamples.length-1],a={blockOffset:i?i.blockOffset+i.blockSize:0,blockSize:r.blockSize,byteOffset:e,byteSize:r.size};this.lastLoadedPos=this.lastLoadedPos+r.size,this.loadedSamples.push(a),r.isLastFrame&&(this.lastSampleLoaded=!0)}}class vi{constructor(e){this.demuxer=e}getId(){return 1}getCodec(){return"flac"}getInternalCodecId(){return null}getNumberOfChannels(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}getSampleRate(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return D}getTimeResolution(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getDisposition(){return{...te}}async getFirstTimestamp(){return 0}async getDecoderConfig(){return t(this.demuxer.audioInfo),{codec:"flac",numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate,description:this.demuxer.audioInfo.description}}async getPacket(e,r){if(t(this.demuxer.audioInfo),e<0)throw new Error("Timestamp cannot be negative");const i=await this.demuxer.readingMutex.acquire();try{for(;;){const t=S(this.demuxer.loadedSamples,e,e=>e.blockOffset/this.demuxer.audioInfo.sampleRate);if(-1===t){await this.demuxer.advanceReader();continue}const i=this.demuxer.loadedSamples[t],a=i.blockOffset/this.demuxer.audioInfo.sampleRate;if(!(a+i.blockSize/this.demuxer.audioInfo.sampleRate<=e))return this.getPacketAtIndex(t,r);if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(this.demuxer.loadedSamples.length-1,r);await this.demuxer.advanceReader()}}finally{i()}}async getNextPacket(e,t){const r=await this.demuxer.readingMutex.acquire();try{const r=e.sequenceNumber+1;if(this.demuxer.lastSampleLoaded&&r>=this.demuxer.loadedSamples.length)return null;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{r()}}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}async getPacketAtIndex(e,r){const i=this.demuxer.loadedSamples[e];if(!i)return null;let a;if(r.metadataOnly)a=Ge;else{let e=this.demuxer.reader.requestSlice(i.byteOffset,i.byteSize);if(e instanceof Promise&&(e=await e),!e)return null;a=aa(e,i.byteSize)}t(this.demuxer.audioInfo);const s=i.blockOffset/this.demuxer.audioInfo.sampleRate,n=i.blockSize/this.demuxer.audioInfo.sampleRate;return new Xe(a,"key",s,n,e,i.byteSize)}async getFirstPacket(e){for(;0===this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(0,e)}}class Pi{}class xi extends Pi{async _getMajorBrand(e){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=await t),!t)return null;t.skip(4);return"ftyp"!==ya(t,4)?null:ya(t,4)}_createDemuxer(e){return new qt(e)}}class Ci extends xi{async _canReadInput(e){const t=await this._getMajorBrand(e);return!!t&&"qt "!==t}get name(){return"MP4"}get mimeType(){return"video/mp4"}}class _i extends xi{async _canReadInput(e){return"qt "===await this._getMajorBrand(e)}get name(){return"QuickTime File Format"}get mimeType(){return"video/quicktime"}}class Bi extends Pi{async isSupportedEBMLOfDocType(e,t){let r=e._reader.requestSlice(0,ar);if(r instanceof Promise&&(r=await r),!r)return!1;const i=sr(r);if(null===i)return!1;if(i<1||i>8)return!1;if(or(r,i)!==Zt.EBML)return!1;const a=lr(r);if("number"!==typeof a)return!1;let s=e._reader.requestSlice(r.filePos,a);if(s instanceof Promise&&(s=await s),!s)return!1;const n=r.filePos;for(;s.filePos<=n+a-2;){const e=dr(s);if(!e)break;const{id:r,size:i}=e,a=s.filePos;if(void 0===i)return!1;switch(r){case Zt.EBMLVersion:if(1!==or(s,i))return!1;break;case Zt.EBMLReadVersion:if(1!==or(s,i))return!1;break;case Zt.DocType:if(ur(s,i)!==t)return!1;break;case Zt.DocTypeVersion:if(or(s,i)>4)return!1}s.filePos=a+i}return!0}_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"matroska")}_createDemuxer(e){return new Mr(e)}get name(){return"Matroska"}get mimeType(){return"video/x-matroska"}}class Ei extends Bi{_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"webm")}get name(){return"WebM"}get mimeType(){return"video/webm"}}class Fi extends Pi{async _canReadInput(e){let t=e._reader.requestSlice(0,10);if(t instanceof Promise&&(t=await t),!t)return!1;let r=0,i=!1;for(;;){let t=e._reader.requestSlice(r,10);if(t instanceof Promise&&(t=await t),!t)break;const a=Xr(t);if(!a)break;i=!0,r=t.filePos+a.size}const a=await Zr(e._reader,r,r+4096);if(!a)return!1;if(i)return!0;r=a.startPos+a.header.totalSize;const s=await Zr(e._reader,r,r+4);if(!s)return!1;const n=a.header,o=s.header;return n.channel===o.channel&&n.sampleRate===o.sampleRate}_createDemuxer(e){return new ei(e)}get name(){return"MP3"}get mimeType(){return"audio/mpeg"}}class Di extends Pi{async _canReadInput(e){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=await t),!t)return!1;const r=ya(t,4);if("RIFF"!==r&&"RIFX"!==r&&"RF64"!==r)return!1;t.skip(4);return"WAVE"===ya(t,4)}_createDemuxer(e){return new gi(e)}get name(){return"WAVE"}get mimeType(){return"audio/wav"}}class Ai extends Pi{async _canReadInput(e){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=await t),!!t&&"OggS"===ya(t,4)}_createDemuxer(e){return new di(e)}get name(){return"Ogg"}get mimeType(){return"application/ogg"}}class Ri extends Pi{async _canReadInput(e){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=await t),!!t&&"fLaC"===ya(t,4)}get name(){return"FLAC"}get mimeType(){return"audio/flac"}_createDemuxer(e){return new Ii(e)}}class Mi extends Pi{async _canReadInput(e){let t=e._reader.requestSliceRange(0,7,9);if(t instanceof Promise&&(t=await t),!t)return!1;const r=Ti(t);if(!r)return!1;if(t=e._reader.requestSliceRange(r.frameLength,7,9),t instanceof Promise&&(t=await t),!t)return!1;const i=Ti(t);return!!i&&(r.objectType===i.objectType&&r.samplingFrequencyIndex===i.samplingFrequencyIndex&&r.channelConfiguration===i.channelConfiguration)}_createDemuxer(e){return new wi(e)}get name(){return"ADTS"}get mimeType(){return"audio/aac"}}const Ni=new Ci,zi=new _i,Oi=new Bi,Li=new Ei,Ui=new Fi,Vi=new Di,qi=new Ai,Hi=new Mi,Wi=[Ni,zi,Oi,Li,Vi,qi,new Ri,Ui,Hi];class ji{constructor(){this._disposed=!1,this._sizePromise=null,this.onread=null}async getSizeOrNull(){if(this._disposed)throw new ea;return this._sizePromise??(this._sizePromise=Promise.resolve(this._retrieveSize()))}async getSize(){if(this._disposed)throw new ea;const e=await this.getSizeOrNull();if(null===e)throw new Error("Cannot determine the size of an unsized source.");return e}}class Ki extends ji{constructor(e,t={}){if(!(e instanceof Blob))throw new TypeError("blob must be a Blob.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!J(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._readers=new WeakMap,this._blob=e,this._orchestrator=new Ji({maxCacheSize:t.maxCacheSize??8388608,maxWorkerCount:4,runWorker:this._runWorker.bind(this),prefetchProfile:Yi.fileSystem})}_retrieveSize(){const e=this._blob.size;return this._orchestrator.fileSize=e,e}_read(e,t){return this._orchestrator.read(e,t)}async _runWorker(e){let t=this._readers.get(e);if(void 0===t){if("stream"in this._blob&&!q()){t=this._blob.slice(e.currentPos).stream().getReader()}else t=null;this._readers.set(e,t)}for(;e.currentPos{if(t instanceof Error&&(t.message.includes("Failed to fetch")||t.message.includes("Load failed")||t.message.includes("NetworkError when attempting to fetch resource"))){let e=null;try{"undefined"!==typeof window&&"undefined"!==typeof window.location&&(e=new URL(r instanceof Request?r.url:r,window.location.href).origin)}catch{}if(("undefined"===typeof navigator||"boolean"!==typeof navigator.onLine||navigator.onLine)&&null!==e&&e!==window.location.origin)return console.warn("Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option."),null}return Math.min(2**(e-2),16)};class Gi extends ji{constructor(e,t={}){if("string"!==typeof e&&!(e instanceof URL)&&!("undefined"!==typeof Request&&e instanceof Request))throw new TypeError("url must be a string, URL or Request.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.requestInit&&(!t.requestInit||"object"!==typeof t.requestInit))throw new TypeError("options.requestInit, when provided, must be an object.");if(void 0!==t.getRetryDelay&&"function"!==typeof t.getRetryDelay)throw new TypeError("options.getRetryDelay, when provided, must be a function.");if(void 0!==t.maxCacheSize&&(!J(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");if(void 0!==t.fetchFn&&"function"!==typeof t.fetchFn)throw new TypeError("options.fetchFn, when provided, must be a function.");super(),this._existingResponses=new WeakMap,this._url=e,this._options=t,this._getRetryDelay=t.getRetryDelay??Qi,this._orchestrator=new Ji({maxCacheSize:t.maxCacheSize??67108864,maxWorkerCount:2,runWorker:this._runWorker.bind(this),prefetchProfile:Yi.network})}async _retrieveSize(){const e=new AbortController,t=await L(this._options.fetchFn??fetch,this._url,z(this._options.requestInit??{},{headers:{Range:"bytes=0-"},signal:e.signal}),this._getRetryDelay,()=>this._disposed);if(!t.ok)throw new Error(`Error fetching ${String(this._url)}: ${t.status} ${t.statusText}`);let r,i;if(206===t.status)i=this._getTotalLengthFromRangeResponse(t),r=this._orchestrator.createWorker(0,Math.min(i,$i));else{const e=t.headers.get("Content-Length");if(!e)throw new Error(`HTTP response (status ${t.status}) must surface Content-Length header.`);i=Number(e),r=this._orchestrator.createWorker(0,i),this._orchestrator.options.maxCacheSize=1/0,console.warn("HTTP server did not respond with 206 Partial Content, meaning the entire remote resource now has to be downloaded. For efficient media file streaming across a network, please make sure your server supports range requests.")}return this._orchestrator.fileSize=i,this._existingResponses.set(r,{response:t,abortController:e}),this._orchestrator.runWorker(r),i}_read(e,t){return this._orchestrator.read(e,t)}async _runWorker(e){for(;;){const i=this._existingResponses.get(e);this._existingResponses.delete(e);let a=i?.abortController,s=i?.response;if(a||(a=new AbortController,s=await L(this._options.fetchFn??fetch,this._url,z(this._options.requestInit??{},{headers:{Range:`bytes=${e.currentPos}-`},signal:a.signal}),this._getRetryDelay,()=>this._disposed)),t(s),!s.ok)throw new Error(`Error fetching ${String(this._url)}: ${s.status} ${s.statusText}`);if(e.currentPos>0&&206!==s.status)throw new Error("HTTP server did not respond with 206 Partial Content to a range request. To enable efficient media file streaming across a network, please make sure your server supports range requests.");if(!s.body)throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream.");const n=s.body.getReader();for(;;){if(e.currentPos>=e.targetPos||e.aborted)return a.abort(),void(e.running=!1);let t;try{t=await n.read()}catch(r){if(this._disposed)throw r;const e=this._getRetryDelay(1,r,this._url);if(null!==e){console.error("Error while reading response stream. Attempting to resume.",r),await new Promise(t=>setTimeout(t,1e3*e));break}throw r}if(e.aborted)continue;const{done:i,value:s}=t;if(i){if(e.currentPos>=e.targetPos)return this._orchestrator.forgetWorker(e),void(e.running=!1);break}this.onread?.(e.currentPos,e.currentPos+s.length),this._orchestrator.supplyWorkerData(e,s)}}}_getTotalLengthFromRangeResponse(e){const t=e.headers.get("Content-Range");if(t){const e=/\/(\d+)/.exec(t);if(e)return Number(e[1])}const r=e.headers.get("Content-Length");if(r)return Number(r);throw new Error("Partial HTTP response (status 206) must surface either Content-Range or Content-Length header.")}_dispose(){this._orchestrator.dispose()}}class Xi extends ji{constructor(e,t={}){if(!(e instanceof ReadableStream))throw new TypeError("stream must be a ReadableStream.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!J(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._reader=null,this._cache=[],this._pendingSlices=[],this._currentIndex=0,this._targetIndex=0,this._maxRequestedIndex=0,this._endIndex=null,this._pulling=!1,this._stream=e,this._maxCacheSize=t.maxCacheSize??16777216}_retrieveSize(){return this._endIndex}_read(e,t){if(null!==this._endIndex&&t>this._endIndex)return null;this._maxRequestedIndex=Math.max(this._maxRequestedIndex,t);const r=S(this._cache,e,e=>e.start),i=-1!==r?this._cache[r]:null;if(i&&i.start<=e&&t<=i.end)return{bytes:i.bytes,view:i.view,offset:i.start};let a=e;const s=new Uint8Array(t-e);if(-1!==r)for(let c=r;c=t)break;const i=Math.max(e,r.start);i>a&&this._throwDueToCacheMiss();const n=Math.min(t,r.end);ia&&this._throwDueToCacheMiss();const{promise:n,resolve:o,reject:l}=v();return this._pendingSlices.push({start:e,end:t,bytes:s,resolve:o,reject:l}),this._targetIndex=Math.max(this._targetIndex,t),this._pulling||(this._pulling=!0,this._pull().catch(e=>{if(this._pulling=!1,!(this._pendingSlices.length>0))throw e;this._pendingSlices.forEach(t=>t.reject(e)),this._pendingSlices.length=0})),n}_throwDueToCacheMiss(){throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache.")}async _pull(){for(this._reader??(this._reader=this._stream.getReader());this._currentIndex0;){const e=this._cache[0];if(this._maxRequestedIndex-e.end<=this._maxCacheSize)break;this._cache.shift()}this._currentIndex+=t.byteLength}this._pulling=!1}_dispose(){this._pendingSlices.length=0,this._cache.length=0}}const Yi={fileSystem:(e,t)=>{const r=65536;return{start:e=Math.floor((e-r)/r)*r,end:t=Math.ceil((t+r)/r)*r}},network:(e,t,r)=>{const i=65536;e=Math.max(0,Math.floor((e-i)/i)*i);for(const a of r){const r=8388608,i=Math.max((a.startPos+a.targetPos)/2,a.targetPos-r);if(G(e,t,i,a.targetPos)){const e=a.targetPos-a.startPos,i=Math.ceil((e+1)/r)*r,s=2**Math.ceil(Math.log2(e+1)),n=Math.min(s,i);t=Math.max(t,a.startPos+n)}}return{start:e,end:t=Math.max(t,e+$i)}}};class Ji{constructor(e){this.options=e,this.fileSize=null,this.nextAge=0,this.workers=[],this.cache=[],this.currentCacheSize=0,this.disposed=!1}read(e,r){t(null!==this.fileSize);const i=this.options.prefetchProfile(e,r,this.workers),a=Math.max(i.start,0),s=Math.min(i.end,this.fileSize);t(a<=e&&r<=s);let n=null;const o=S(this.cache,e,e=>e.start),l=-1!==o?this.cache[o]:null;l&&l.start<=e&&r<=l.end&&(l.age=this.nextAge++,n={bytes:l.bytes,view:l.view,offset:l.start});const d=S(this.cache,a,e=>e.start),u=n?null:new Uint8Array(r-e);let h=0,m=a;const f=[];if(-1!==d){for(let i=d;i=s)break;if(n.end<=a)continue;const o=Math.max(a,n.start),c=Math.min(s,n.end);if(t(o<=c),m=u.length&&(n={bytes:u,view:c(u),offset:e}),0===f.length)return t(n),n;const{promise:p,resolve:g,reject:k}=v(),b=[];for(const t of f){const i=Math.max(e,t.start),a=Math.min(r,t.end);i===t.start&&a===t.end?b.push(t):i({bytes:t,view:c(t),offset:e}))),n}createWorker(e,t){const r={startPos:e,currentPos:e,targetPos:t,running:!1,aborted:this.disposed,pendingSlices:[],age:this.nextAge++};for(this.workers.push(r);this.workers.length>this.options.maxWorkerCount;){let e=0,t=this.workers[0];for(let r=1;r0)break;t.aborted=!0,this.workers.splice(e,1)}return r}runWorker(e){t(!e.running),t(e.currentPos{if(e.running=!1,!(e.pendingSlices.length>0))throw t;e.pendingSlices.forEach(e=>e.reject(t)),e.pendingSlices.length=0})}supplyWorkerData(e,r){t(!e.aborted);const i=e.currentPos,a=i+r.length;this.insertIntoCache({start:i,end:a,bytes:r,view:c(r),age:this.nextAge++}),e.currentPos+=r.length,e.targetPos=Math.max(e.targetPos,e.currentPos);for(let t=0;tt.start&&(t.start=a),t.end<=t.start&&(s.holes.splice(e,1),e--)}0===s.holes.length&&(s.resolve(s.bytes),e.pendingSlices.splice(t,1),t--)}for(let t=0;te.start)+1;if(t>0){const r=this.cache[t-1];if(r.end>=e.end)return;if(r.end>e.start){const i=new Uint8Array(e.end-r.start);i.set(r.bytes,0),i.set(e.bytes,e.start-r.start),this.currentCacheSize+=e.end-r.end,r.bytes=i,r.view=c(i),r.end=e.end,t--,e=r}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length;for(let r=t+1;r=t.end){this.cache.splice(r,1),this.currentCacheSize-=t.bytes.length,r--;continue}const i=new Uint8Array(t.end-e.start);i.set(e.bytes,0),i.set(t.bytes,t.start-e.start),this.currentCacheSize-=e.end-t.start,e.bytes=i,e.view=c(i),e.end=t.end,this.cache.splice(r,1);break}for(;this.currentCacheSize>this.options.maxCacheSize;){let e=0,t=this.cache[0];for(let r=1;r!(e instanceof Pi)))throw new TypeError("options.formats must be an array of InputFormat.");if(!(e.source instanceof ji))throw new TypeError("options.source must be a Source.");if(e.source._disposed)throw new Error("options.source must not be disposed.");this._formats=e.formats,this._source=e.source,this._reader=new ta(e.source)}_getDemuxer(){return this._demuxerPromise??(this._demuxerPromise=(async()=>{this._reader.fileSize=await this._source.getSizeOrNull();for(const e of this._formats){if(await e._canReadInput(this))return this._format=e,e._createDemuxer(this)}throw new Error("Input has an unsupported or unrecognizable format.")})())}get source(){return this._source}async getFormat(){return await this._getDemuxer(),t(this._format),this._format}async computeDuration(){return(await this._getDemuxer()).computeDuration()}async getTracks(){return(await this._getDemuxer()).getTracks()}async getVideoTracks(){return(await this.getTracks()).filter(e=>e.isVideoTrack())}async getAudioTracks(){return(await this.getTracks()).filter(e=>e.isAudioTrack())}async getPrimaryVideoTrack(){return(await this.getTracks()).find(e=>e.isVideoTrack())??null}async getPrimaryAudioTrack(){return(await this.getTracks()).find(e=>e.isAudioTrack())??null}async getMimeType(){return(await this._getDemuxer()).getMimeType()}async getMetadataTags(){return(await this._getDemuxer()).getMetadataTags()}dispose(){this._disposed||(this._disposed=!0,this._source._disposed=!0,this._source._dispose())}[Symbol.dispose](){this.dispose()}}class ea extends Error{constructor(e="Input has been disposed."){super(e),this.name="InputDisposedError"}}class ta{constructor(e){this.source=e}requestSlice(e,t){if(this.source._disposed)throw new ea;if(null!==this.fileSize&&e+t>this.fileSize)return null;const r=e+t,i=this.source._read(e,r);return i instanceof Promise?i.then(t=>t?new ra(t.bytes,t.view,t.offset,e,r):null):i?new ra(i.bytes,i.view,i.offset,e,r):null}requestSliceRange(e,r,i){if(this.source._disposed)throw new ea;if(null!==this.fileSize)return this.requestSlice(e,F(this.fileSize-e,r,i));{const a=this.requestSlice(e,i),s=a=>{if(a)return a;const s=a=>(t(null!==a),this.requestSlice(e,F(a-e,r,i))),n=this.source._retrieveSize();return n instanceof Promise?n.then(s):s(n)};return a instanceof Promise?a.then(s):s(a)}}}class ra{constructor(e,t,r,i,a){this.bytes=e,this.view=t,this.offset=r,this.start=i,this.end=a,this.bufferPos=i-r}static tempFromBytes(e){return new ra(e,c(e),0,0,e.length)}get length(){return this.end-this.start}get filePos(){return this.offset+this.bufferPos}set filePos(e){this.bufferPos=e-this.offset}get remainingLength(){return Math.max(this.end-this.filePos,0)}skip(e){this.bufferPos+=e}slice(e,t=this.end-e){if(ethis.end)throw new RangeError("Slicing outside of original slice.");return new ra(this.bytes,this.view,this.offset,e,e+t)}}const ia=(e,t)=>{if(e.filePose.end)throw new RangeError(`Tried reading [${e.filePos}, ${e.filePos+t}), but slice is [${e.start}, ${e.end}). This is likely an internal error, please report it alongside the file that caused it.`)},aa=(e,t)=>{ia(e,t);const r=e.bytes.subarray(e.bufferPos,e.bufferPos+t);return e.bufferPos+=t,r},sa=e=>(ia(e,1),e.view.getUint8(e.bufferPos++)),na=(e,t)=>{ia(e,2);const r=e.view.getUint16(e.bufferPos,t);return e.bufferPos+=2,r},oa=e=>{ia(e,2);const t=e.view.getUint16(e.bufferPos,!1);return e.bufferPos+=2,t},ca=e=>{ia(e,3);const t=_(e.view,e.bufferPos,!1);return e.bufferPos+=3,t},la=e=>{ia(e,2);const t=e.view.getInt16(e.bufferPos,!1);return e.bufferPos+=2,t},da=(e,t)=>{ia(e,4);const r=e.view.getUint32(e.bufferPos,t);return e.bufferPos+=4,r},ua=e=>{ia(e,4);const t=e.view.getUint32(e.bufferPos,!1);return e.bufferPos+=4,t},ha=e=>{ia(e,4);const t=e.view.getUint32(e.bufferPos,!0);return e.bufferPos+=4,t},ma=e=>{ia(e,4);const t=e.view.getInt32(e.bufferPos,!1);return e.bufferPos+=4,t},fa=(e,t)=>{let r,i;return t?(r=da(e,!0),i=da(e,!0)):(i=da(e,!1),r=da(e,!1)),4294967296*i+r},pa=e=>4294967296*ua(e)+ua(e),ga=e=>4294967296*ma(e)+ua(e),ka=e=>{const t=ha(e),r=(e=>{ia(e,4);const t=e.view.getInt32(e.bufferPos,!0);return e.bufferPos+=4,t})(e);return 4294967296*r+t},ba=e=>{ia(e,4);const t=e.view.getFloat32(e.bufferPos,!1);return e.bufferPos+=4,t},Ta=e=>{ia(e,8);const t=e.view.getFloat64(e.bufferPos,!1);return e.bufferPos+=8,t},ya=(e,t)=>{ia(e,t);let r="";for(let i=0;ie.stop()),this.queuedNodes.clear()}async stopIterator(){await(this.audioIterator?.return()),this.audioIterator=null}async load(e,t){const r=++this.asyncId;await this.stopIterator(),this.stopQueuedNodes(),this.paused=!0,this.playbackTimeAtStart=0,this.audioContextStartTime=0;const i=this.normalizeSource(e);if(!i)return;if(this.input=new Zi({source:i,formats:Wi}),this.duration=await this.input.computeDuration(),r!==this.asyncId)return;const a=await this.input.getPrimaryAudioTrack();return a&&null!==a.codec&&await a.canDecode()?(this.ensureAudioContext(a.sampleRate),this.audioSink=new Dt(a),void t?.()):(this.audioSink=null,this.ensureAudioContext(),void t?.())}async runIterator(e){if(this.audioSink)for(await this.stopIterator(),this.audioIterator=this.audioSink.buffers(this.currentTime);;){if(e!==this.asyncId||this.paused)return;const r=this.audioIterator.next(),i=setInterval(()=>{e!==this.asyncId||this.paused?clearInterval(i):"running"===this.audioContext.state&&this.audioContext.currentTime>=this.latestScheduledEndTime-.2&&(this.audioContext.suspend(),this.events.emit("waiting"))},50);let a;try{a=await r}catch(t){console.error("Audio iterator error:",t);break}finally{clearInterval(i)}if(e!==this.asyncId||this.paused)return;if("suspended"===this.audioContext.state&&(await this.audioContext.resume(),this.events.emit("canplay"),this.events.emit("playing")),a.done)break;const{buffer:s,timestamp:n}=a.value,o=this.audioContext.createBufferSource();o.buffer=s,o.connect(this.gainNode),o.playbackRate.value=this.playbackRate;const c=this.audioContextStartTime+(n-this.playbackTimeAtStart)/this.playbackRate,l=c+s.duration/this.playbackRate;l>this.latestScheduledEndTime&&(this.latestScheduledEndTime=l),c>=this.audioContext.currentTime?o.start(c):o.start(this.audioContext.currentTime,(this.audioContext.currentTime-c)*this.playbackRate),this.queuedNodes.add(o),o.onended=()=>this.queuedNodes.delete(o)}}async play(){if(!this.paused)return;this.audioContext||this.ensureAudioContext(),"suspended"===this.audioContext.state&&await this.audioContext.resume(),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime,this.paused=!1;const e=++this.asyncId;this.runIterator(e)}pause(){this.paused||(this.playbackTimeAtStart=this.currentTime,this.paused=!0,this.stopIterator(),this.stopQueuedNodes())}async seek(e){this.playbackTimeAtStart=Math.max(0,e),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime;const t=++this.asyncId;this.paused||this.runIterator(t)}setVolume(e,t){this.volume=e,this.muted=t,this.updateGain()}setPlaybackRate(e){if(e!==this.playbackRate&&(this.paused||(this.playbackTimeAtStart=this.currentTime,this.audioContextStartTime=this.audioContext.currentTime),this.playbackRate=e,!this.paused)){const e=++this.asyncId;this.runIterator(e)}}destroy(){this.asyncId++,this.pause(),this.audioContext?.close(),this.audioContext=null,this.input=null,this.audioSink=null}}class Sa{constructor({canvas:e,ctx:t,events:r,timeupdateInterval:i=250,avSyncTolerance:a=.12,dropLateFrames:s=!1,poster:n="",preflightRange:o=!1}){this.canvas=e,this.ctx=t,this.events=r,this.timeupdateInterval=i,this.avSyncTolerance=a,this.dropLateFrames=s,this.poster=n,this.preflightRange=o,this.input=null,this.videoSink=null,this.videoIterator=null,this.nextFrame=null,this.rafId=0,this.asyncId=0,this.width=0,this.height=0,this.duration=Number.NaN,this.audioClock=null,this.lastTimeUpdate=0,this.stalled=!1,this.playbackRate=1,this.posterDrawn=!1,this.isFetching=!1}normalizeSource(e){return"string"===typeof e?new Gi(e):e instanceof Blob?new Ki(e):"undefined"!==typeof ReadableStream&&e instanceof ReadableStream?new Xi(e):e}async preflight(e){if(!this.preflightRange||"string"!==typeof e)return!0;try{const t=(await fetch(e,{method:"HEAD"})).headers.get("accept-ranges");return!(!t||"none"===t)||(this.events.emit("error",new Event("RangeNotSupported")),!1)}catch(t){return console.warn("Preflight check failed:",t),!0}}drawPoster(){if(!this.poster||this.posterDrawn)return;const e=new Image;e.onload=()=>{this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width=e.naturalWidth||this.canvas.width,this.canvas.height=e.naturalHeight||this.canvas.height,this.ctx.drawImage(e,0,0,this.canvas.width,this.canvas.height),this.posterDrawn=!0},e.src=this.poster}async stopIterator(){await(this.videoIterator?.return()),this.videoIterator=null}clear(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}async load(e,t){const r=++this.asyncId;if(await this.stopIterator(),this.clear(),this.posterDrawn=!1,!(await this.preflight(e)))return;const i=this.normalizeSource(e);if(!i)return void this.drawPoster();if(this.input=new Zi({source:i,formats:Wi}),this.duration=await this.input.computeDuration(),r!==this.asyncId)return;const a=await this.input.getPrimaryVideoTrack();if(!a)return this.handleNoVideoTrack(),void t?.();if(null===a.codec||!(await a.canDecode()))return this.handleNoVideoTrack(),void t?.();const s=await a.canBeTransparent();this.videoSink=new _t(a,{poolSize:2,fit:"contain",alpha:s}),this.width=a.displayWidth,this.height=a.displayHeight,this.canvas.width=this.width,this.canvas.height=this.height,t?.(),await this.resetIterator(0)}handleNoVideoTrack(){this.videoSink=null,this.width=0,this.height=0,this.canvas.width=0,this.canvas.height=0,this.clear(),this.drawPoster()}async resetIterator(e){if(await this.stopIterator(),!this.videoSink)return;this.videoIterator=this.videoSink.canvases(e);const t=(await this.videoIterator.next()).value??null,r=(await this.videoIterator.next()).value??null;this.nextFrame=r,t?(this.ctx.drawImage(t.canvas,0,0),this.events.emit("loadeddata")):this.drawPoster()}async updateNextFrame(e){if(this.videoIterator&&!this.isFetching){this.isFetching=!0;try{for(;;){const t=(await this.videoIterator.next()).value??null;if(!t||e!==this.asyncId)return;const r=this.audioClock.currentTime,i=this.dropLateFrames?Math.max(.06,this.avSyncTolerance/Math.max(1,this.playbackRate)):0;if(!(this.dropLateFrames&&t.timestampr)return void(this.nextFrame=null)}}}finally{this.isFetching=!1}}}render(){if(!this.audioClock)return;const e=this.audioClock.currentTime,t=Date.now();if(t-this.lastTimeUpdate>=this.timeupdateInterval&&(this.events.emit("timeupdate"),this.lastTimeUpdate=t),Number.isFinite(this.duration)&&e>=this.duration)return this.stop(),this.stalled=!1,this.events.emit("ended"),this.events.emit("pause"),void this.events.emit("canplay");this.nextFrame&&this.nextFrame.timestamp<=e?(this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextFrame.canvas,0,0),this.nextFrame=null,this.updateNextFrame(this.asyncId),this.stalled&&(this.events.emit("canplay"),this.events.emit("playing"),this.stalled=!1)):this.nextFrame||(this.updateNextFrame(this.asyncId),!this.nextFrame&&Number.isFinite(this.duration)&&ethis.render())}start(e){this.audioClock=e,this.asyncId++,this.stalled=!1,this.updateNextFrame(this.asyncId),this.rafId=requestAnimationFrame(()=>this.render())}stop(){cancelAnimationFrame(this.rafId)}async seek(e){this.asyncId++,await this.resetIterator(e)}setPlaybackRate(e){this.playbackRate=Math.max(.1,Number(e)||1)}destroy(){this.asyncId++,this.stop(),this.stopIterator(),this.posterDrawn=!1,this.input=null,this.videoSink=null}}class Ia{constructor({canvas:e,ctx:t,events:r,option:i={}}){this.events=r,this.option=i,this.audio=new wa(r),this.video=new Sa({canvas:e,ctx:t,events:r,timeupdateInterval:i.timeupdateInterval??250,avSyncTolerance:i.avSyncTolerance??.12,dropLateFrames:i.dropLateFrames??!1,poster:i.poster??"",preflightRange:i.preflightRange??!1}),this.paused=!0,this.ended=!1,this.readyState=0,this.networkState=0,this.error=null,this.seeking=!1,this.loadSeq=0,r.addEventListener?.("ended",()=>{this.ended=!0,this.paused=!0})}async load(e){const t=++this.loadSeq;this.pause(),this.ended=!1,this.error=null,this.networkState=2,this.readyState=0,setTimeout(()=>this.events.emit("waiting"),0),setTimeout(()=>this.events.emit("loadstart"),0);const r=Number.isFinite(this.option.loadTimeout)?this.option.loadTimeout:0;try{await Promise.race([this.performLoad(e,t),r>0?this.createTimeout(r):new Promise(()=>{})])}catch(i){if(t!==this.loadSeq)return;this.loadSeq++,this.error={code:4,message:i.message},this.networkState=3,this.events.emit("error")}}async performLoad(e,t){let r=!1,i=!1;const a=()=>{r&&i&&(this.readyState=1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"))};try{if(await Promise.all([this.video.load(e,()=>{t===this.loadSeq&&(r=!0,a())}),this.audio.load(e,()=>{t===this.loadSeq&&(i=!0,a())})]),t!==this.loadSeq)return;this.readyState=4,this.networkState=1,this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("progress")}catch(s){if(t!==this.loadSeq)return;this.error={code:4,message:s.message},this.networkState=3,this.events.emit("error"),console.error("MediaBunny load error:",s)}}createTimeout(e){return new Promise((t,r)=>{setTimeout(()=>r(new Error("Load timeout")),e)})}async play(){this.paused&&(this.ended&&(this.ended=!1,await this.seek(0)),this.paused=!1,await this.audio.play(),this.video.start(this.audio),this.events.emit("play"),this.events.emit("playing"))}pause(){this.paused||(this.paused=!0,this.audio.pause(),this.video.stop(),this.events.emit("pause"))}async seek(e){const t=!this.paused;this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),this.pause(),await Promise.all([this.audio.seek(e),this.video.seek(e)]),this.seeking=!1,this.events.emit("seeked"),t&&!this.ended&&await this.play()}setVolume(e,t){this.audio.setVolume(e,t)}setPlaybackRate(e){this.audio.setPlaybackRate(e),this.video.setPlaybackRate(e)}destroy(){this.pause(),this.audio.destroy(),this.video.destroy()}get currentTime(){return this.audio.currentTime}get duration(){return this.audio.duration||this.video.duration}get videoWidth(){return this.video.width}get videoHeight(){return this.video.height}}class va{constructor({art:t,canvas:r,ctx:i,option:a}){this.art=t,this.canvas=r,this.option=a,this.events=new e,this.engine=new Ia({canvas:r,ctx:i,events:this.events,option:a}),this._src=null,this._volume=a.volume??.7,this._muted=!!a.muted,this._playbackRate=1,this.engine.setVolume(this._volume,this._muted),this.setupEventForwarding(),a.source?this.src=a.source:t.option?.url&&(this.src=t.option.url)}setupEventForwarding(){const{events:e}=this.art.constructor.config;e.forEach(e=>{this.events.addEventListener(e,e=>{this.art.emit(`video:${e.type}`,e)})})}addEventListener(e,t){this.events.addEventListener(e,t)}removeEventListener(e,t){this.events.removeEventListener(e,t)}get src(){return this._src}set src(e){this._src=e,e&&this.engine.load(e)}get currentSrc(){return this._src}get currentTime(){return this.engine.currentTime}set currentTime(e){this.engine.seek(Number(e)||0)}get duration(){return this.engine.duration}get buffered(){return this.createTimeRanges(0,this.engine.duration)}get played(){return this.createTimeRanges(0,this.engine.currentTime)}get seekable(){return this.createTimeRanges(0,this.engine.duration)}createTimeRanges(e,t){const r=this.engine.duration;return!r||Number.isNaN(r)||t<=0?{length:0,start:()=>0,end:()=>0}:{length:1,start:()=>e,end:()=>t}}get paused(){return this.engine.paused}get playing(){return!this.engine.paused&&!this.engine.ended}get ended(){return this.engine.ended}get seeking(){return this.engine.seeking}get readyState(){return this.engine.readyState}get networkState(){return this.engine.networkState}get error(){return this.engine.error}get playbackRate(){return this._playbackRate}set playbackRate(e){const t=Number(e);Number.isNaN(t)||t<=0||(this._playbackRate=t,this.engine.setPlaybackRate(t),this.events.emit("ratechange"))}get volume(){return this._volume}set volume(e){this._volume=function(e,t,r){return Math.max(t,Math.min(r,Number(e)||0))}(e,0,1),this._muted=!1,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}get muted(){return this._muted}set muted(e){this._muted=!!e,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}play(){return this.engine.play()}pause(){this.engine.pause()}load(){this._src&&this.engine.load(this._src)}get videoWidth(){return this.engine.videoWidth}get videoHeight(){return this.engine.videoHeight}get poster(){return this.option.poster||""}set poster(e){this.option.poster=e}get autoplay(){return this.option.autoplay||!1}set autoplay(e){}get loop(){return this.option.loop||!1}set loop(e){}get controls(){return!1}set controls(e){}get playsInline(){return!0}set playsInline(e){}get crossOrigin(){return this.option.crossOrigin||""}set crossOrigin(e){}get preload(){return"auto"}set preload(e){}get defaultMuted(){return!1}set defaultMuted(e){}get defaultPlaybackRate(){return 1}set defaultPlaybackRate(e){}canPlayType(e){return"maybe"}getBoundingClientRect(){return this.canvas.getBoundingClientRect()}requestVideoFrameCallback(e){return requestAnimationFrame(t=>{e(t,{presentationTime:this.engine.currentTime,expectedDisplayTime:t+16.6,width:this.engine.videoWidth,height:this.engine.videoHeight,mediaTime:this.engine.currentTime,presentedFrames:0,processingDuration:0,captureTime:t,receiveTime:t,rtpTimestamp:0})})}cancelVideoFrameCallback(e){cancelAnimationFrame(e)}setAttribute(e,t){"src"===e?this.src=t:"autoplay"===e?this.autoplay=t:"loop"===e?this.loop=t:"muted"===e?this.muted=!0:this.canvas.setAttribute(e,t)}destroy(){this.engine.destroy()}}return function(e={}){return t=>{const{constructor:r}=t,{createElement:i}=r.utils,a=i("canvas"),s=a.getContext("2d"),n=new va({art:t,canvas:a,ctx:s,option:e}),o={};for(const e in a)"function"===typeof a[e]&&(o[e]=a[e].bind(a));const c=new Set([...Object.getOwnPropertyNames(n),...Object.getOwnPropertyNames(Object.getPrototypeOf(n))]);for(const e of c)"constructor"!==e&&(e in a||Object.defineProperty(a,e,{get(){const t=n[e];return"function"===typeof t?t.bind(n):t},set(t){n[e]=t},configurable:!0,enumerable:!0}));for(const e in o)a[e]=(...t)=>o[e](...t);function l(){const e=t.template?.$player;e&&!t.option.autoSize&&Object.assign(a.style,{width:"100%",height:"100%",objectFit:"contain"})}return t.on("resize",l),t.on("video:loadedmetadata",l),t.on("destroy",()=>{n.destroy()}),a}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";function e(e,t){const i=new Map;return e.filter(e=>{const r=e[t];return void 0===r||!i.has(r)&&i.set(r,1)})}class t{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const i=this.listeners.get(e);if(!i)return;const r=i.indexOf(t);r>=0&&i.splice(r,1)}emit(e,t){const i=new Event(e);i.detail=t;const r=this.listeners.get(e);r&&r.forEach(e=>e(i))}}function i(e){if(!e)throw new Error("Assertion failed.")}const r=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},a=e=>e&&e[e.length-1],s=e=>{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<{const t=s(e);return 0===(1&t)?-(t>>1):t+1>>1},o=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),c=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),l=new TextDecoder,u=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),d={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},h=u(d),f={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},m=u(f),p={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},g=u(p),k=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class b{constructor(){this.currentPromise=Promise.resolve(),this.pending=0}async acquire(){let e;const t=new Promise(t=>{let i=!1;e=()=>{i||(t(),this.pending--,i=!0)}}),i=this.currentPromise;return this.currentPromise=t,this.pending++,await i,e}}const y=/^[0-9a-fA-F]+$/,w=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),T=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,S=(e,t,i)=>{let r=0,a=e.length-1,s=-1;for(;r<=a;){const n=r+a>>1,o=i(e[n]);o===t?(s=n,a=n-1):o{let r=0,a=e.length-1,s=-1;for(;r<=a;){const n=r+(a-r+1)/2|0;i(e[n])<=t?(s=n,r=n+1):a=n-1}return s},v=(e,t,i)=>{const r=P(e,i(t),i);e.splice(r+1,0,t)},I=()=>{let e,t;return{promise:new Promise((i,r)=>{e=i,t=r}),resolve:e,reject:t}},x=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return e[i]},C=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return i;return-1},B=e=>{throw new Error(`Unexpected value: ${e}`)},E=(e,t,i)=>{const r=e.getUint8(t),a=e.getUint8(t+1),s=e.getUint8(t+2);return i?r|a<<8|s<<16:r<<16|a<<8|s},_=(e,t,i,r)=>{i>>>=0,i&=16777215,e.setUint8(t,i>>>16&255),e.setUint8(t+1,i>>>8&255),e.setUint8(t+2,255&i)},A=(e,t)=>({async next(){const i=await e.next();return i.done?{value:void 0,done:!0}:{value:t(i.value),done:!1}},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),F=(e,t,i)=>Math.max(t,Math.min(i,e)),R="und",D=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},M=(e,t)=>Math.round(e*t)/t,N=(e,t)=>Math.floor(e/t)*t,O=/^[a-z]{3}$/,L=e=>O.test(e),z=1e6*(1+Number.EPSILON),U=(e,t)=>{const i={...e,...t};if(e.headers||t.headers){const r=e.headers?q(e.headers):{},a=t.headers?q(t.headers):{},s={...r};Object.entries(a).forEach(([e,t])=>{const i=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());i&&delete s[i],s[e]=t}),i.headers=s}return i},q=e=>{if(e instanceof Headers){const t={};return e.forEach((e,i)=>{t[i]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,i])=>{t[e]=i}),t}return e},W=async(e,t,i,r,a)=>{let s=0;for(;;)try{return await e(t,i)}catch(n){if(a())throw n;s++;const e=r(s,n,t);if(null===e)throw n;if(console.error("Retrying failed fetch. Error:",n),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&await ce(1e3*e),a())throw n}};class V{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let H=null;const K=()=>null!==H?H:H=!("undefined"===typeof navigator||!(navigator.vendor?.match(/apple/i)||/AppleWebKit/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)||/\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent)));let j=null;const X=()=>null!==j?j:j="undefined"!==typeof navigator&&navigator.userAgent?.includes("Firefox");let $=null;const Q=()=>null!==$?$:$=!("undefined"===typeof navigator||!navigator.vendor?.includes("Google Inc")&&!/Chrome/.test(navigator.userAgent));let G=null;const Y=()=>{if(null!==G)return G;if("undefined"===typeof navigator)return null;const e=/\bChrome\/(\d+)/.exec(navigator.userAgent);return e?G=Number(e[1]):null},J=(e,t)=>-1!==e?e:t,Z=(e,t,i,r)=>e<=r&&i<=t,ee=e=>{const t=atob(e),i=new Uint8Array(t.length);for(let r=0;r{Symbol.dispose??(Symbol.dispose=Symbol("Symbol.dispose"))},ie=e=>"number"===typeof e&&!Number.isNaN(e),re=(e,t)=>{if(t.includes("://"))return t;if(e.includes("://")){const t=e.indexOf("?");-1!==t&&(e=e.slice(0,t))}let i;if(t.startsWith("/")){const r=e.indexOf("://");if(-1===r)i=t;else{const a=e.indexOf("/",r+3);i=-1===a?e+t:e.slice(0,a)+t}}else{const r=e.lastIndexOf("/");i=-1===r?t:e.slice(0,r+1)+t}let r="";const a=i.indexOf("://");if(-1!==a){const e=i.indexOf("/",a+3);-1!==e&&(r=i.slice(0,e),i=i.slice(e))}const s=i.split("/"),n=[];for(const o of s)".."===o?n.pop():"."!==o&&n.push(o);return r+n.join("/")},ae=(e,t)=>{let i=0;for(let r=0;r{let i=-1,r=1/0;for(let a=0;a{i(Number.isInteger(e.num)),i(Number.isInteger(e.den)),i(0!==e.den);let t=Math.abs(e.num),r=Math.abs(e.den);for(;0!==r;){const e=t%r;t=r,r=e}const a=t||1;return{num:e.num/a,den:e.den/a}},oe=(e,t)=>{if("object"!==typeof e||!e)throw new TypeError(`${t} must be an object.`);if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(`${t}.left must be a non-negative integer.`);if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(`${t}.top must be a non-negative integer.`);if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(`${t}.width must be a non-negative integer.`);if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(`${t}.height must be a non-negative integer.`)},ce=e=>new Promise(t=>setTimeout(t,e));class le{constructor(){this._listeners=new Map}on(e,t,i){this._listeners.has(e)||this._listeners.set(e,new Set);const r={fn:t,once:i?.once??!1};return this._listeners.get(e).add(r),()=>{this._listeners.get(e)?.delete(r)}}_emit(...e){const[t,i]=e,r=this._listeners.get(t);if(r)for(const s of r){try{s.fn(i)}catch(a){console.error(a)}s.once&&r.delete(s)}}}class ue{constructor(e,t){if(this.data=e,this.mimeType=t,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("string"!==typeof t)throw new TypeError("mimeType must be a string.")}}class de{constructor(e,t,i,r){if(this.data=e,this.mimeType=t,this.name=i,this.description=r,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if(void 0!==t&&"string"!==typeof t)throw new TypeError("mimeType, when provided, must be a string.");if(void 0!==i&&"string"!==typeof i)throw new TypeError("name, when provided, must be a string.");if(void 0!==r&&"string"!==typeof r)throw new TypeError("description, when provided, must be a string.")}}const he={default:!0,primary:!0,forced:!1,original:!1,commentary:!1,hearingImpaired:!1,visuallyImpaired:!1};class fe{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){const e=Math.floor(this.pos/8),t=this.bytes[e]??0,i=7-(7&this.pos),r=(t&1<>i;return this.pos++,r}readBits(e){if(1===e)return this.readBit();let t=0;for(let i=0;i>i-r-1<{if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");const t=new fe(e);let i=t.readBits(5);31===i&&(i=32+t.readBits(6));const r=t.readBits(4);let a=null;15===r?a=t.readBits(24):r=1&&s<=7&&(n=pe[s]),{objectType:i,frequencyIndex:r,sampleRate:a,channelConfiguration:s,numberOfChannels:n}},ke=["avc","hevc","vp9","av1","vp8"],be=["pcm-s16","pcm-s16be","pcm-s24","pcm-s24be","pcm-s32","pcm-s32be","pcm-f32","pcm-f32be","pcm-f64","pcm-f64be","pcm-u8","pcm-s8","ulaw","alaw"],ye=["aac","opus","mp3","vorbis","flac","ac3","eac3",...be],we=[{maxMacroblocks:99,maxBitrate:64e3,maxDpbMbs:396,level:10},{maxMacroblocks:396,maxBitrate:192e3,maxDpbMbs:900,level:11},{maxMacroblocks:396,maxBitrate:384e3,maxDpbMbs:2376,level:12},{maxMacroblocks:396,maxBitrate:768e3,maxDpbMbs:2376,level:13},{maxMacroblocks:396,maxBitrate:2e6,maxDpbMbs:2376,level:20},{maxMacroblocks:792,maxBitrate:4e6,maxDpbMbs:4752,level:21},{maxMacroblocks:1620,maxBitrate:4e6,maxDpbMbs:8100,level:22},{maxMacroblocks:1620,maxBitrate:1e7,maxDpbMbs:8100,level:30},{maxMacroblocks:3600,maxBitrate:14e6,maxDpbMbs:18e3,level:31},{maxMacroblocks:5120,maxBitrate:2e7,maxDpbMbs:20480,level:32},{maxMacroblocks:8192,maxBitrate:2e7,maxDpbMbs:32768,level:40},{maxMacroblocks:8192,maxBitrate:5e7,maxDpbMbs:32768,level:41},{maxMacroblocks:8704,maxBitrate:5e7,maxDpbMbs:34816,level:42},{maxMacroblocks:22080,maxBitrate:135e6,maxDpbMbs:110400,level:50},{maxMacroblocks:36864,maxBitrate:24e7,maxDpbMbs:184320,level:51},{maxMacroblocks:36864,maxBitrate:24e7,maxDpbMbs:184320,level:52},{maxMacroblocks:139264,maxBitrate:24e7,maxDpbMbs:696320,level:60},{maxMacroblocks:139264,maxBitrate:48e7,maxDpbMbs:696320,level:61},{maxMacroblocks:139264,maxBitrate:8e8,maxDpbMbs:696320,level:62}],Te=[{maxPictureSize:36864,maxBitrate:2e5,level:10},{maxPictureSize:73728,maxBitrate:8e5,level:11},{maxPictureSize:122880,maxBitrate:18e5,level:20},{maxPictureSize:245760,maxBitrate:36e5,level:21},{maxPictureSize:552960,maxBitrate:72e5,level:30},{maxPictureSize:983040,maxBitrate:12e6,level:31},{maxPictureSize:2228224,maxBitrate:18e6,level:40},{maxPictureSize:2228224,maxBitrate:3e7,level:41},{maxPictureSize:8912896,maxBitrate:6e7,level:50},{maxPictureSize:8912896,maxBitrate:12e7,level:51},{maxPictureSize:8912896,maxBitrate:18e7,level:52},{maxPictureSize:35651584,maxBitrate:18e7,level:60},{maxPictureSize:35651584,maxBitrate:24e7,level:61},{maxPictureSize:35651584,maxBitrate:48e7,level:62}],Se=".01.01.01.01.00",Pe=".0.110.01.01.01.0",ve=e=>{const{codec:t,codecDescription:r,colorSpace:s,avcCodecInfo:n,hevcCodecInfo:o,vp9CodecInfo:l,av1CodecInfo:u}=e;if("avc"===t){if(i(null!==e.avcType),n){const t=new Uint8Array([n.avcProfileIndication,n.profileCompatibility,n.avcLevelIndication]);return`avc${e.avcType}.${w(t)}`}if(!r||r.byteLength<4)throw new TypeError("AVC decoder description is not provided or is not at least 4 bytes long.");return`avc${e.avcType}.${w(r.subarray(1,4))}`}if("hevc"===t){let e,t,i,a,s,n;if(o)e=o.generalProfileSpace,t=o.generalProfileIdc,i=T(o.generalProfileCompatibilityFlags),a=o.generalTierFlag,s=o.generalLevelIdc,n=[...o.generalConstraintIndicatorFlags];else{if(!r||r.byteLength<23)throw new TypeError("HEVC decoder description is not provided or is not at least 23 bytes long.");const o=c(r),l=o.getUint8(1);e=l>>6&3,t=31&l,i=T(o.getUint32(2)),a=l>>5&1,s=o.getUint8(12),n=[];for(let e=0;e<6;e++)n.push(o.getUint8(6+e))}let l="hev1.";for(l+=["","A","B","C"][e]+t,l+=".",l+=i.toString(16).toUpperCase(),l+=".",l+=0===a?"L":"H",l+=s;n.length>0&&0===n[n.length-1];)n.pop();return n.length>0&&(l+=".",l+=n.map(e=>e.toString(16).toUpperCase()).join(".")),l}if("vp8"===t)return"vp8";if("vp9"===t){if(!l){const t=e.width*e.height;let i=a(Te).level;for(const e of Te)if(t<=e.maxPictureSize){i=e.level;break}return`vp09.00.${i.toString().padStart(2,"0")}.08`}let t=`vp09.${l.profile.toString().padStart(2,"0")}.${l.level.toString().padStart(2,"0")}.${l.bitDepth.toString().padStart(2,"0")}.${l.chromaSubsampling.toString().padStart(2,"0")}`;return t+=`.${l.colourPrimaries.toString().padStart(2,"0")}.${l.transferCharacteristics.toString().padStart(2,"0")}.${l.matrixCoefficients.toString().padStart(2,"0")}.${l.videoFullRangeFlag.toString().padStart(2,"0")}`,t.endsWith(Se)&&(t=t.slice(0,-15)),t}if("av1"===t){if(!u){const t=e.width*e.height;let i=a(Te).level;for(const e of Te)if(t<=e.maxPictureSize){i=e.level;break}return`av01.0.${i.toString().padStart(2,"0")}M.08`}const t=u.profile,i=u.level.toString().padStart(2,"0"),r=u.tier?"H":"M",n=u.bitDepth.toString().padStart(2,"0"),o=u.monochrome?"1":"0",c=100*u.chromaSubsamplingX+10*u.chromaSubsamplingY+1*(u.chromaSubsamplingX&&u.chromaSubsamplingY?u.chromaSamplePosition:0),l=s?.primaries?d[s.primaries]:1,h=s?.transfer?f[s.transfer]:1,m=s?.matrix?p[s.matrix]:1,g=s?.fullRange?1:0;let k=`av01.${t}.${i}${r}.${n}`;return k+=`.${o}.${c.toString().padStart(3,"0")}`,k+=`.${l.toString().padStart(2,"0")}`,k+=`.${h.toString().padStart(2,"0")}`,k+=`.${m.toString().padStart(2,"0")}`,k+=`.${g}`,k.endsWith(Pe)&&(k=k.slice(0,-17)),k}throw new TypeError(`Unhandled codec '${t}'.`)},Ie=e=>{const{codec:t,codecDescription:i,aacCodecInfo:r}=e;if("aac"===t){if(!r)throw new TypeError("AAC codec info must be provided.");if(r.isMpeg2)return"mp4a.67";{let e;if(null!==r.objectType)e=r.objectType;else{e=ge(i).objectType}return`mp4a.40.${e}`}}if("mp3"===t)return"mp3";if("opus"===t)return"opus";if("vorbis"===t)return"vorbis";if("flac"===t)return"flac";if("ac3"===t)return"ac-3";if("eac3"===t)return"ec-3";if(t&&be.includes(t))return t;throw new TypeError(`Unhandled codec '${t}'.`)},xe=48e3,Ce=/^pcm-([usf])(\d+)+(be)?$/,Be=e=>{if(i(be.includes(e)),"ulaw"===e)return{dataType:"ulaw",sampleSize:1,littleEndian:!0,silentValue:255};if("alaw"===e)return{dataType:"alaw",sampleSize:1,littleEndian:!0,silentValue:213};const t=Ce.exec(e);let r;i(t),r="u"===t[1]?"unsigned":"s"===t[1]?"signed":"float";return{dataType:r,sampleSize:Number(t[2])/8,littleEndian:"be"!==t[3],silentValue:"pcm-u8"===e?128:0}},Ee=e=>e.startsWith("avc1")||e.startsWith("avc3")?"avc":e.startsWith("hev1")||e.startsWith("hvc1")?"hevc":"vp8"===e?"vp8":e.startsWith("vp09")?"vp9":e.startsWith("av01")?"av1":"mp3"===e||"mp4a.69"===e||"mp4a.6B"===e||"mp4a.6b"===e||"mp4a.40.34"===e?"mp3":e.startsWith("mp4a.40.")||"mp4a.67"===e?"aac":"opus"===e?"opus":"vorbis"===e?"vorbis":"flac"===e?"flac":"ac-3"===e||"ac3"===e?"ac3":"ec-3"===e||"eac3"===e?"eac3":"ulaw"===e?"ulaw":"alaw"===e?"alaw":Ce.test(e)?e:"webvtt"===e?"webvtt":null,_e=[44100,48e3,32e3],Ae=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1,-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1,-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1],Fe=1483304551,Re=1231971951,De=(e,t)=>3===e?3===t?21:36:3===t?13:21,Me=(e,t)=>{const i=e>>>24,r=e>>>16&255,a=e>>>8&255,s=255&e;if(255!==i&&255!==r&&255!==a&&255!==s)return{header:null,bytesAdvanced:4};if(255!==i)return{header:null,bytesAdvanced:1};if(224!==(224&r))return{header:null,bytesAdvanced:1};let n=0,o=0;16&r?n=8&r?0:1:(n=1,o=1);const c=r>>3&3,l=r>>1&3,u=(a>>2&3)%3,d=s>>6&3,h=s>>4&3,f=s>>3&1,m=s>>2&1,p=3&s,g=Ae[16*n*4+16*l+(a>>4&15)];if(-1===g)return{header:null,bytesAdvanced:1};const k=1e3*g,b=_e[u]>>n+o,y=((e,t,i,r,a)=>0===t?0:1===t?Math.floor(144*i/(r<>1&1);if(null!==t&&t{let t=2130706432,i=0;for(;0!==t;)i>>=1,i|=e&t,t>>=8;return i};var Oe,Le;(Le=Oe||(Oe={}))[Le.FrameCount=1]="FrameCount",Le[Le.FileSize=2]="FileSize",Le[Le.Toc=4]="Toc";const ze=[48e3,44100,32e3],Ue=[24e3,22050,16e3];var qe,We,Ve,He;(We=qe||(qe={}))[We.NON_IDR_SLICE=1]="NON_IDR_SLICE",We[We.SLICE_DPA=2]="SLICE_DPA",We[We.SLICE_DPB=3]="SLICE_DPB",We[We.SLICE_DPC=4]="SLICE_DPC",We[We.IDR=5]="IDR",We[We.SEI=6]="SEI",We[We.SPS=7]="SPS",We[We.PPS=8]="PPS",We[We.AUD=9]="AUD",We[We.SPS_EXT=13]="SPS_EXT",(He=Ve||(Ve={}))[He.RASL_N=8]="RASL_N",He[He.RASL_R=9]="RASL_R",He[He.BLA_W_LP=16]="BLA_W_LP",He[He.RSV_IRAP_VCL23=23]="RSV_IRAP_VCL23",He[He.VPS_NUT=32]="VPS_NUT",He[He.SPS_NUT=33]="SPS_NUT",He[He.PPS_NUT=34]="PPS_NUT",He[He.AUD_NUT=35]="AUD_NUT",He[He.PREFIX_SEI_NUT=39]="PREFIX_SEI_NUT",He[He.SUFFIX_SEI_NUT=40]="SUFFIX_SEI_NUT";const Ke=function*(e){let t=0,i=-1;for(;t=e.length-2)break;t=r;let a=0;t+3i&&(yield{offset:i,length:t-i}),i=t+a,t=i):t++}-1!==i&&i{if(t.description){const i=3&o(t.description)[4];return je(e,i+1)}return Ke(e)},$e=e=>31&e,Qe=e=>{const t=[],i=e.length;for(let r=0;r{const t=e.reduce((e,t)=>e+Ge.byteLength+t.byteLength,0),i=new Uint8Array(t);let r=0;for(const a of e)i.set(Ge,r),r+=Ge.byteLength,i.set(a,r),r+=a.byteLength;return i},Je=(e,t)=>{const i=e.reduce((e,i)=>e+t+i.byteLength,0),r=new Uint8Array(i);let a=0;for(const s of e){const e=new DataView(r.buffer,r.byteOffset,r.byteLength);switch(t){case 1:e.setUint8(a,s.byteLength);break;case 2:e.setUint16(a,s.byteLength,!1);break;case 3:_(e,a,s.byteLength);break;case 4:e.setUint32(a,s.byteLength,!1)}a+=t,r.set(s,a),a+=s.byteLength}return r},Ze=e=>{try{const t=[],r=[],a=[];for(const i of Ke(e)){const s=e.subarray(i.offset,i.offset+i.length),n=$e(s[0]);n===qe.SPS?t.push(s):n===qe.PPS?r.push(s):n===qe.SPS_EXT&&a.push(s)}if(0===t.length)return null;if(0===r.length)return null;const s=t[0],n=tt(s);i(null!==n);const o=100===n.profileIdc||110===n.profileIdc||122===n.profileIdc||144===n.profileIdc;return{configurationVersion:1,avcProfileIndication:n.profileIdc,profileCompatibility:n.constraintFlags,avcLevelIndication:n.levelIdc,lengthSizeMinusOne:3,sequenceParameterSets:t,pictureParameterSets:r,chromaFormat:o?n.chromaFormatIdc:null,bitDepthLumaMinus8:o?n.bitDepthLumaMinus8:null,bitDepthChromaMinus8:o?n.bitDepthChromaMinus8:null,sequenceParameterSetExt:o?a:null}}catch(t){return console.error("Error building AVC Decoder Configuration Record:",t),null}},et={1:{num:1,den:1},2:{num:12,den:11},3:{num:10,den:11},4:{num:16,den:11},5:{num:40,den:33},6:{num:24,den:11},7:{num:20,den:11},8:{num:32,den:11},9:{num:80,den:33},10:{num:18,den:11},11:{num:15,den:11},12:{num:64,den:33},13:{num:160,den:99},14:{num:4,den:3},15:{num:3,den:2},16:{num:2,den:1}},tt=e=>{try{const t=new fe(Qe(e));t.skipBits(1),t.skipBits(2);if(7!==t.readBits(5))return null;const r=t.readAlignedByte(),o=t.readAlignedByte(),c=t.readAlignedByte();s(t);let l=1,u=0,d=0,h=0;if(100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r){l=s(t),3===l&&(h=t.readBits(1)),u=s(t),d=s(t),t.skipBits(1);if(t.readBits(1))for(let e=0;e<(3!==l?8:12);e++){if(t.readBits(1)){const i=e<6?16:64;let r=8,a=8;for(let e=0;ee.level>=c)??a(we),r=Math.min(Math.floor(i.maxDpbMbs/(e*t)),16);x=r,C=r}else x=0,C=0}return i(null!==C),{profileIdc:r,constraintFlags:o,levelIdc:c,frameMbsOnlyFlag:w,chromaFormatIdc:l,bitDepthLumaMinus8:u,bitDepthChromaMinus8:d,codedWidth:g,codedHeight:k,displayWidth:b,displayHeight:y,pixelAspectRatio:I,colourPrimaries:T,matrixCoefficients:P,transferCharacteristics:S,fullRangeFlag:v,numReorderFrames:x,maxDecFrameBuffering:C}}catch(t){return console.error("Error parsing AVC SPS:",t),null}},it=e=>{const t=s(e);e.skipBits(4),e.skipBits(4);for(let i=0;i<=t;i++)s(e),s(e),e.skipBits(1);e.skipBits(5),e.skipBits(5),e.skipBits(5),e.skipBits(5)},rt=(e,t)=>{if(t.description){const i=3&o(t.description)[21];return je(e,i+1)}return Ke(e)},at=e=>e>>1&63,st=e=>{try{const t=new fe(Qe(e));t.skipBits(16),t.readBits(4);const i=t.readBits(3),r=t.readBits(1),{general_profile_space:a,general_tier_flag:n,general_profile_idc:o,general_profile_compatibility_flags:c,general_constraint_indicator_flags:l,general_level_idc:u}=ot(t,i);s(t);const d=s(t);let h=0;3===d&&(h=t.readBits(1));const f=s(t),m=s(t);let p=f,g=m;if(t.readBits(1)){const e=s(t),i=s(t),r=s(t),a=s(t);let n=1,o=1;const c=0===h?d:0;1===c?(n=2,o=2):2===c&&(n=2,o=1),p-=(e+i)*n,g-=(r+a)*o}const k=s(t),b=s(t);s(t);const y=t.readBits(1);let w=0;for(let e=y?0:i;e<=i;e++)s(t),w=s(t),s(t);s(t),s(t),s(t),s(t),s(t),s(t),t.readBits(1)&&t.readBits(1)&&ct(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&(t.skipBits(4),t.skipBits(4),s(t),s(t),t.skipBits(1));const T=s(t);if(lt(t,T),t.readBits(1)){const e=s(t);for(let i=0;i{try{const t=[],i=[],r=[],a=[];for(const s of Ke(e)){const n=e.subarray(s.offset,s.offset+s.length),o=at(n[0]);o===Ve.VPS_NUT?t.push(n):o===Ve.SPS_NUT?i.push(n):o===Ve.PPS_NUT?r.push(n):o!==Ve.PREFIX_SEI_NUT&&o!==Ve.SUFFIX_SEI_NUT||a.push(n)}if(0===i.length||0===r.length)return null;const o=st(i[0]);if(!o)return null;let c=0;if(r.length>0){const e=r[0],t=new fe(Qe(e));t.skipBits(16),s(t),s(t),t.skipBits(1),t.skipBits(1),t.skipBits(3),t.skipBits(1),t.skipBits(1),s(t),s(t),n(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&s(t),n(t),n(t),t.skipBits(1),t.skipBits(1),t.skipBits(1),t.skipBits(1);const i=t.readBits(1),a=t.readBits(1);c=i||a?i&&!a?2:!i&&a?3:0:0}const l=[...t.length?[{arrayCompleteness:1,nalUnitType:Ve.VPS_NUT,nalUnits:t}]:[],...i.length?[{arrayCompleteness:1,nalUnitType:Ve.SPS_NUT,nalUnits:i}]:[],...r.length?[{arrayCompleteness:1,nalUnitType:Ve.PPS_NUT,nalUnits:r}]:[],...a.length?[{arrayCompleteness:1,nalUnitType:at(a[0][0]),nalUnits:a}]:[]];return{configurationVersion:1,generalProfileSpace:o.generalProfileSpace,generalTierFlag:o.generalTierFlag,generalProfileIdc:o.generalProfileIdc,generalProfileCompatibilityFlags:o.generalProfileCompatibilityFlags,generalConstraintIndicatorFlags:o.generalConstraintIndicatorFlags,generalLevelIdc:o.generalLevelIdc,minSpatialSegmentationIdc:o.minSpatialSegmentationIdc,parallelismType:c,chromaFormatIdc:o.chromaFormatIdc,bitDepthLumaMinus8:o.bitDepthLumaMinus8,bitDepthChromaMinus8:o.bitDepthChromaMinus8,avgFrameRate:0,constantFrameRate:0,numTemporalLayers:o.spsMaxSubLayersMinus1+1,temporalIdNested:o.spsTemporalIdNestingFlag,lengthSizeMinusOne:3,arrays:l}}catch(t){return console.error("Error building HEVC Decoder Configuration Record:",t),null}},ot=(e,t)=>{const i=e.readBits(2),r=e.readBits(1),a=e.readBits(5);let s=0;for(let u=0;u<32;u++)s=s<<1|e.readBits(1);const n=new Uint8Array(6);for(let u=0;u<6;u++)n[u]=e.readBits(8);const o=e.readBits(8),c=[],l=[];for(let u=0;u0)for(let u=t;u<8;u++)e.skipBits(2);for(let u=0;u{for(let t=0;t<4;t++)for(let i=0;i<(3===t?2:6);i++){if(e.readBits(1)){const i=Math.min(64,1<<4+(t<<1));t>1&&n(e);for(let t=0;t{const i=[];for(let r=0;r{let a=0,n=0,o=0;if(0!==t&&(n=e.readBits(1)),n){if(t===i){o=t-(s(e)+1)}else o=t-1;e.readBits(1),s(e);const n=r[o]??0;for(let t=0;t<=n;t++){e.readBits(1)||e.readBits(1)}a=r[o]}else{const t=s(e),i=s(e);for(let r=0;r{let i=2,r=2,a=2,n=0,o=0,c={num:1,den:1};if(e.readBits(1)){const t=e.readBits(8);if(255===t)c={num:e.readBits(16),den:e.readBits(16)};else{const e=et[t];e&&(c=e)}}return e.readBits(1)&&e.readBits(1),e.readBits(1)&&(e.readBits(3),n=e.readBits(1),e.readBits(1)&&(i=e.readBits(8),r=e.readBits(8),a=e.readBits(8))),e.readBits(1)&&(s(e),s(e)),e.readBits(1),e.readBits(1),e.readBits(1),e.readBits(1)&&(s(e),s(e),s(e),s(e)),e.readBits(1)&&(e.readBits(32),e.readBits(32),e.readBits(1)&&s(e),e.readBits(1)&&ht(e,!0,t)),e.readBits(1)&&(e.readBits(1),e.readBits(1),e.readBits(1),o=s(e),s(e),s(e),s(e),s(e)),{pixelAspectRatio:c,colourPrimaries:i,transferCharacteristics:r,matrixCoefficients:a,fullRangeFlag:n,minSpatialSegmentationIdc:o}},ht=(e,t,i)=>{let r=!1,a=!1,n=!1;r=1===e.readBits(1),a=1===e.readBits(1),(r||a)&&(n=1===e.readBits(1),n&&(e.readBits(8),e.readBits(5),e.readBits(1),e.readBits(5)),e.readBits(4),e.readBits(4),n&&e.readBits(4),e.readBits(5),e.readBits(5),e.readBits(5));for(let o=0;o<=i;o++){let t=!0;1===e.readBits(1)||(t=1===e.readBits(1));let i=!1;t?s(e):i=1===e.readBits(1);let o=1;if(!i){o=s(e)+1}r&&ft(e,o,n),a&&ft(e,o,n)}},ft=(e,t,i)=>{for(let r=0;r{const i=new Set;let r=mt.audAllowed;for(const s of rt(e,t)){if(r===mt.noMoreDataAllowed){i.add(s.offset);continue}const t=at(e[s.offset]);if(r===mt.eoBitstreamAllowed&&37!==t){i.add(s.offset);continue}let a=!1;35===t?r>mt.audAllowed?a=!0:r=mt.beforeFirstVcl:t<=31?r>mt.afterFirstVcl?a=!0:r=mt.afterFirstVcl:36===t?r!==mt.afterFirstVcl?a=!0:r=mt.eoBitstreamAllowed:37===t?r=41&&t<=44||t>=48&&t<=55?r>mt.beforeFirstVcl?a=!0:r=mt.beforeFirstVcl:(38===t||40===t||t>=45&&t<=47||t>=56&&t<=63)&&r{if(t.description){const i=3&o(t.description)[21];return Je(e,i+1)}return Ye(e)})(a,t)},kt=e=>{const t=new fe(e);if(2!==t.readBits(2))return null;const i=t.readBits(1),r=(t.readBits(1)<<1)+i;3===r&&t.skipBits(1);if(1===t.readBits(1))return null;if(0!==t.readBits(1))return null;t.skipBits(2);if(4817730!==t.readBits(24))return null;let s=8;if(r>=2){s=t.readBits(1)?12:10}const n=t.readBits(3);let o=0,c=0;if(7!==n){if(c=t.readBits(1),1===r||3===r){const e=t.readBits(1),i=t.readBits(1);o=e||i?e&&!i?2:1:3,t.skipBits(1)}else o=1}else o=3,c=1;const l=(t.readBits(16)+1)*(t.readBits(16)+1);let u=a(Te).level;for(const a of Te)if(l<=a.maxPictureSize){u=a.level;break}return{profile:r,level:u,bitDepth:s,chromaSubsampling:o,videoFullRangeFlag:c,colourPrimaries:2===n?1:1===n?6:2,transferCharacteristics:2===n?1:1===n?6:2,matrixCoefficients:7===n?0:2===n?1:1===n?6:2}},bt=function*(e){const t=new fe(e),r=()=>{let e=0;for(let i=0;i<8;i++){const r=t.readAlignedByte();if(e|=(127&r)<<7*i,!(128&r))break;if(7===i&&128&r)return null}return e>=2**32-1?null:e};for(;t.getBitsLeft()>=8;){t.skipBits(1);const a=t.readBits(4),s=t.readBits(1),n=t.readBits(1);let o;if(t.skipBits(1),s&&t.skipBits(8),n){const e=r();if(null===e)return;o=e}else o=Math.floor(t.getBitsLeft()/8);i(t.pos%8===0),yield{type:a,data:e.subarray(t.pos/8,t.pos/8+o)},t.skipBits(8*o)}},yt=e=>{for(const{type:t,data:i}of bt(e)){if(1!==t)continue;const e=new fe(i),r=e.readBits(3);e.readBits(1);const a=e.readBits(1);let s=0,n=0,o=0;if(a)s=e.readBits(5);else{if(e.readBits(1)){e.skipBits(32),e.skipBits(32);if(e.readBits(1))return null}const t=e.readBits(1);t&&(o=e.readBits(5),e.skipBits(32),e.skipBits(5),e.skipBits(5));const i=e.readBits(5);for(let r=0;r<=i;r++){e.skipBits(12);const i=e.readBits(5);if(0===r&&(s=i),i>7){const t=e.readBits(1);0===r&&(n=t)}if(t){if(e.readBits(1)){const t=o+1;e.skipBits(t),e.skipBits(t),e.skipBits(1)}}e.readBits(1)&&e.skipBits(4)}}const c=e.readBits(4),l=e.readBits(4),u=c+1;e.skipBits(u);const d=l+1;e.skipBits(d);let h=0;if(h=a?0:e.readBits(1),h&&(e.skipBits(4),e.skipBits(3)),e.skipBits(1),e.skipBits(1),e.skipBits(1),!a){e.skipBits(1),e.skipBits(1),e.skipBits(1),e.skipBits(1);const t=e.readBits(1);t&&(e.skipBits(1),e.skipBits(1));let i=0;if(i=e.readBits(1)?2:e.readBits(1),i>0){e.readBits(1)||e.skipBits(1)}t&&e.skipBits(3)}e.skipBits(1),e.skipBits(1),e.skipBits(1);const f=e.readBits(1);let m=8;if(2===r&&f){m=e.readBits(1)?12:10}else r<=2&&(m=f?10:8);let p=0;1!==r&&(p=e.readBits(1));let g=1,k=1,b=0;return p||(0===r?(g=1,k=1):1===r?(g=0,k=0):12===m&&(g=e.readBits(1),g&&(k=e.readBits(1))),g&&k&&(b=e.readBits(2))),{profile:r,level:s,tier:n,bitDepth:m,monochrome:p,chromaSubsamplingX:g,chromaSubsamplingY:k,chromaSamplePosition:b}}return null},wt=[480,960,1920,2880,480,960,1920,2880,480,960,1920,2880,480,960,480,960,120,240,480,960,120,240,480,960,120,240,480,960,120,240,480,960],Tt=e=>{if(e.length<7)throw new Error("Setup header is too short.");if(5!==e[0])throw new Error("Wrong packet type in Setup header.");if("vorbis"!==String.fromCharCode(...e.slice(1,7)))throw new Error("Invalid packet signature in Setup header.");const t=e.length,i=new Uint8Array(t);for(let u=0;u97;)if(1===r.readBits(1)){a=r.pos;break}if(0===a)throw new Error("Invalid Setup header: framing bit not found.");let s=0,n=!1,o=0;for(;r.getBitsLeft()>=97;){const e=r.pos,t=r.readBits(8),i=r.readBits(16),a=r.readBits(16);if(t>63||0!==i||0!==a){r.pos=e;break}if(r.skipBits(1),s++,s>64)break;r.clone().readBits(6)+1===s&&(n=!0,o=s)}if(!n)throw new Error("Invalid Setup header: mode header not found.");if(o>63)throw new Error(`Unsupported mode count: ${o}.`);const c=o;r.pos=0,r.skipBits(a);const l=Array(c).fill(0);for(let u=c-1;u>=0;u--)r.skipBits(40),l[u]=r.readBits(1);return{modeBlockflags:l}},St=(e,t,r)=>{switch(e){case"avc":for(const e of Xe(r,t)){const t=r[e.offset],i=$e(t);if(i>=qe.NON_IDR_SLICE&&i<=qe.SLICE_DPC)return"delta";if(i===qe.IDR)return"key";if(i===qe.SEI&&(!Q()||Y()>=144)){const t=r.subarray(e.offset,e.offset+e.length),i=Qe(t);let a=1;do{let e=0;for(;;){const t=i[a++];if(void 0===t)break;if(e+=t,t<255)break}let t=0;for(;;){const e=i[a++];if(void 0===e)break;if(t+=e,e<255)break}if(e===6){const e=new fe(i);e.pos=8*a;const t=s(e),r=e.readBits(1);if(0===t&&1===r)return"key"}a+=t}while(a{var i,r;const a=c(e);let s=0;const n=a.getUint32(s,!0);s+=4;const o=l.decode(e.subarray(s,s+n));s+=n,n>0&&(t.raw??(t.raw={}),(i=t.raw).vendor??(i.vendor=o));const u=a.getUint32(s,!0);s+=4;for(let d=0;d0&&(t.trackNumber??(t.trackNumber=i)),r&&Number.isInteger(r)&&r>0&&(t.tracksTotal??(t.tracksTotal=r))}break;case"TRACKTOTAL":{const e=Number.parseInt(d,10);Number.isInteger(e)&&e>0&&(t.tracksTotal??(t.tracksTotal=e))}break;case"DISCNUMBER":{const e=d.split("/"),i=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(t.discNumber??(t.discNumber=i)),r&&Number.isInteger(r)&&r>0&&(t.discsTotal??(t.discsTotal=r))}break;case"DISCTOTAL":{const e=Number.parseInt(d,10);Number.isInteger(e)&&e>0&&(t.discsTotal??(t.discsTotal=e))}break;case"DATE":{const e=new Date(d);Number.isNaN(e.getTime())||(t.date??(t.date=e))}break;case"GENRE":t.genre??(t.genre=d);break;case"METADATA_BLOCK_PICTURE":{const e=ee(d),i=c(e),r=i.getUint32(0,!1),a=i.getUint32(4,!1),s=String.fromCharCode(...e.subarray(8,8+a)),n=i.getUint32(8+a,!1),o=l.decode(e.subarray(12+a,12+a+n)),u=i.getUint32(a+n+28),h=e.subarray(a+n+32,a+n+32+u);t.images??(t.images=[]),t.images.push({data:h,mimeType:s,kind:3===r?"coverFront":4===r?"coverBack":"unknown",name:void 0,description:o||void 0})}}}},xt=[2,1,2,3,3,4,4,5],Ct=e=>{if(e.length<7)return null;if(11!==e[0]||119!==e[1])return null;const t=new fe(e);t.skipBits(16),t.skipBits(16);const i=t.readBits(2);if(3===i)return null;const r=t.readBits(6),a=t.readBits(5);if(a>8)return null;const s=t.readBits(3),n=t.readBits(3);0!==(1&n)&&1!==n&&t.skipBits(2),0!==(4&n)&&t.skipBits(2),2===n&&t.skipBits(2);return{fscod:i,bsid:a,bsmod:s,acmod:n,lfeon:t.readBits(1),bitRateCode:Math.floor(r/2)}},Bt=[128,138,192,128,140,192,160,174,240,160,176,240,192,208,288,192,210,288,224,242,336,224,244,336,256,278,384,256,280,384,320,348,480,320,350,480,384,416,576,384,418,576,448,486,672,448,488,672,512,556,768,512,558,768,640,696,960,640,698,960,768,834,1152,768,836,1152,896,974,1344,896,976,1344,1024,1114,1536,1024,1116,1536,1280,1392,1920,1280,1394,1920,1536,1670,2304,1536,1672,2304,1792,1950,2688,1792,1952,2688,2048,2228,3072,2048,2230,3072,2304,2506,3456,2304,2508,3456,2560,2786,3840,2560,2788,3840],Et=[1,2,3,6],_t=e=>{if(e.length<6)return null;if(11!==e[0]||119!==e[1])return null;const t=new fe(e);t.skipBits(16);const i=t.readBits(2);if(t.skipBits(3),0!==i&&2!==i)return null;const r=t.readBits(11),a=t.readBits(2);let s,n=0;3===a?(n=t.readBits(2),s=3):s=t.readBits(2);const o=t.readBits(3),c=t.readBits(1),l=t.readBits(5);if(l<11||l>16)return null;const u=Et[s];let d;d=a<3?ze[a]/1e3:Ue[n]/1e3;return{dataRate:Math.round((r+1)*d/(16*u)),substreams:[{fscod:a,fscod2:n,bsid:l,bsmod:0,acmod:o,lfeon:c,numDepSub:0,chanLoc:0}]}},At=e=>{const t=e.substreams[0];return i(t),t.fscod<3?ze[t.fscod]:null!==t.fscod2&&t.fscod2<3?Ue[t.fscod2]:null},Ft=e=>{const t=e.substreams[0];i(t);let r=xt[t.acmod]+t.lfeon;if(t.numDepSub>0){const e=[2,2,1,1,2,2,2,1,1];for(let i=0;i<9;i++)t.chanLoc&1<<8-i&&(r+=e[i])}return r};class Rt{constructor(e){this.input=e}dispose(){}}const Dt=new Uint8Array(0);class Mt{constructor(e,t,i,r,a=-1,s,n){if(this.data=e,this.type=t,this.timestamp=i,this.duration=r,this.sequenceNumber=a,e===Dt&&void 0===s)throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets.");if(void 0===s&&(s=e.byteLength),!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("key"!==t&&"delta"!==t)throw new TypeError('type must be either "key" or "delta".');if(!Number.isFinite(i))throw new TypeError("timestamp must be a number.");if(!Number.isFinite(r)||r<0)throw new TypeError("duration must be a non-negative number.");if(!Number.isFinite(a))throw new TypeError("sequenceNumber must be a number.");if(!Number.isInteger(s)||s<0)throw new TypeError("byteLength must be a non-negative integer.");if(void 0!==n&&("object"!==typeof n||!n))throw new TypeError("sideData, when provided, must be an object.");if(void 0!==n?.alpha&&!(n.alpha instanceof Uint8Array))throw new TypeError("sideData.alpha, when provided, must be a Uint8Array.");if(void 0!==n?.alphaByteLength&&(!Number.isInteger(n.alphaByteLength)||n.alphaByteLength<0))throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer.");this.byteLength=s,this.sideData=n??{},this.sideData.alpha&&void 0===this.sideData.alphaByteLength&&(this.sideData.alphaByteLength=this.sideData.alpha.byteLength)}get isMetadataOnly(){return this.data===Dt}get microsecondTimestamp(){return Math.trunc(z*this.timestamp)}get microsecondDuration(){return Math.trunc(z*this.duration)}toEncodedVideoChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}alphaToEncodedVideoChunk(e=this.type){if(!this.sideData.alpha)throw new TypeError("This packet does not contain alpha side data.");if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.sideData.alpha,type:e,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}toEncodedAudioChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to an audio chunk.");if("undefined"===typeof EncodedAudioChunk)throw new Error("Your browser does not support EncodedAudioChunk.");return new EncodedAudioChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}static fromEncodedChunk(e,t){if(!(e instanceof EncodedVideoChunk||e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk.");const i=new Uint8Array(e.byteLength);return e.copyTo(i),new Mt(i,e.type,e.timestamp/1e6,(e.duration??0)/1e6,void 0,void 0,t)}clone(e){if(void 0!==e&&("object"!==typeof e||null===e))throw new TypeError("options, when provided, must be an object.");if(void 0!==e?.data&&!(e.data instanceof Uint8Array))throw new TypeError("options.data, when provided, must be a Uint8Array.");if(void 0!==e?.type&&"key"!==e.type&&"delta"!==e.type)throw new TypeError('options.type, when provided, must be either "key" or "delta".');if(void 0!==e?.timestamp&&!Number.isFinite(e.timestamp))throw new TypeError("options.timestamp, when provided, must be a number.");if(void 0!==e?.duration&&!Number.isFinite(e.duration))throw new TypeError("options.duration, when provided, must be a number.");if(void 0!==e?.sequenceNumber&&!Number.isFinite(e.sequenceNumber))throw new TypeError("options.sequenceNumber, when provided, must be a number.");if(void 0!==e?.sideData&&("object"!==typeof e.sideData||null===e.sideData))throw new TypeError("options.sideData, when provided, must be an object.");return new Mt(e?.data??this.data,e?.type??this.type,e?.timestamp??this.timestamp,e?.duration??this.duration,e?.sequenceNumber??this.sequenceNumber,this.byteLength,e?.sideData??this.sideData)}}const Nt=e=>{const t=c(e);let i=0;const r=t.getUint8(i);i+=1,i+=3;const a=w(e.subarray(i,i+16));i+=16;let s=null;if(r>0){const r=t.getUint32(i);if(i+=4,r>0){s=[];for(let t=0;te.systemId===t.systemId&&((e,t)=>{if(e.length!==t.length)return!1;for(let i=0;i{let t=gn(e);const i=In(e,4);let r=8;1===t&&(t=wn(e),r=16);const a=t-r;return a<0?null:{name:i,totalSize:t,headerSize:r,contentSize:a}},zt=e=>bn(e)/65536,Ut=e=>bn(e)/1073741824,qt=e=>{let t=0;for(let i=0;i<4;i++){t<<=7;const i=un(e);if(t|=127&i,0===(128&i))break}return t},Wt=e=>{let t=hn(e);return e.skip(2),t=Math.min(t,e.remainingLength),l.decode(ln(e,t))},Vt=e=>{const t=Lt(e);if(!t||"data"!==t.name)return null;if(e.remainingLength<8)return null;const i=gn(e);e.skip(4);const r=ln(e,t.contentSize-8);switch(i){case 1:return l.decode(r);case 2:return new TextDecoder("utf-16be").decode(r);case 13:return new ue(r,"image/jpeg");case 14:return new ue(r,"image/png");case 27:return new ue(r,"image/bmp");default:return r}},Ht=16,Kt=new Uint32Array(256),jt=new Uint32Array(256),Xt=new Uint32Array(256),$t=new Uint32Array(256),Qt=new Uint32Array(256),Gt=new Uint32Array(256),Yt=new Uint32Array(10);let Jt=!1;class Zt{constructor(){this.roundkey=new Uint32Array(44),this.iv=new Uint32Array(Ht/Uint32Array.BYTES_PER_ELEMENT),this.in=new Uint8Array(Ht),this.out=new Uint8Array(Ht),this.inView=new DataView(this.in.buffer),this.outView=new DataView(this.out.buffer)}init({key:e,iv:t}){i(16===e.byteLength),i(16===t.byteLength),Jt||(()=>{const e=new Uint8Array(256),t=new Uint8Array(256),i=new Uint8Array(256);for(let s=0,n=1;s<256;s++)i[s]=n,t[n]=s,n=n^n<<1^(128&n?283:0);const r=(e,r)=>e&&r?i[(t[e]+t[r])%255]:0;e[0]=99;for(let s=1;s<256;s++){const r=i[255-t[s]];let a=r^r<<1^r<<2^r<<3^r<<4;a=a>>>8^255&a^99,e[s]=a}for(let s=0;s<256;s++){const t=e[s],i=e.indexOf(s);Kt[s]=t<<24|t<<16|t<<8|t,Gt[s]=i<<24|i<<16|i<<8|i;const a=r(i,14)<<24|r(i,9)<<16|r(i,13)<<8|r(i,11);jt[s]=a,Xt[s]=a>>>8|a<<24,$t[s]=a>>>16|a<<16,Qt[s]=a>>>24|a<<8}let a=1;for(let s=0;s<10;s++)Yt[s]=a<<24,a=a<<1^(128&a?283:0);Jt=!0})();const r=new DataView(e.buffer,e.byteOffset,e.byteLength),a=new DataView(t.buffer,t.byteOffset,t.byteLength);this.roundkey[0]=r.getUint32(0,!1),this.roundkey[1]=r.getUint32(4,!1),this.roundkey[2]=r.getUint32(8,!1),this.roundkey[3]=r.getUint32(12,!1),this.iv[0]=a.getUint32(0,!1),this.iv[1]=a.getUint32(4,!1),this.iv[2]=a.getUint32(8,!1),this.iv[3]=a.getUint32(12,!1);for(let i=4;i<44;i+=4){const e=this.roundkey[i-1];this.roundkey[i]=this.roundkey[i-4]^4278190080&Kt[e>>>16&255]^16711680&Kt[e>>>8&255]^65280&Kt[e>>>0&255]^255&Kt[e>>>24&255]^Yt[i/4-1],this.roundkey[i+1]=this.roundkey[i-3]^this.roundkey[i],this.roundkey[i+2]=this.roundkey[i-2]^this.roundkey[i+1],this.roundkey[i+3]=this.roundkey[i-1]^this.roundkey[i+2]}for(let i=0,s=40;i>>24&255]]^Xt[255&Kt[t>>>16&255]]^$t[255&Kt[t>>>8&255]]^Qt[255&Kt[t>>>0&255]]}}decrypt(){let e=this.inView.getUint32(0,!1)^this.roundkey[0],t=this.inView.getUint32(4,!1)^this.roundkey[1],i=this.inView.getUint32(8,!1)^this.roundkey[2],r=this.inView.getUint32(12,!1)^this.roundkey[3];const a=this.inView.getUint32(0,!1),s=this.inView.getUint32(4,!1),n=this.inView.getUint32(8,!1),o=this.inView.getUint32(12,!1);let c,l,u,d;for(let g=1;g<10;g++){const a=4*g;c=jt[e>>>24]^Xt[r>>>16&255]^$t[i>>>8&255]^Qt[255&t]^this.roundkey[a],l=jt[t>>>24]^Xt[e>>>16&255]^$t[r>>>8&255]^Qt[255&i]^this.roundkey[a+1],u=jt[i>>>24]^Xt[t>>>16&255]^$t[e>>>8&255]^Qt[255&r]^this.roundkey[a+2],d=jt[r>>>24]^Xt[i>>>16&255]^$t[t>>>8&255]^Qt[255&e]^this.roundkey[a+3],e=c,t=l,i=u,r=d}const h=4278190080&Gt[e>>>24&255]^16711680&Gt[r>>>16&255]^65280&Gt[i>>>8&255]^255&Gt[t>>>0&255]^this.roundkey[40],f=4278190080&Gt[t>>>24&255]^16711680&Gt[e>>>16&255]^65280&Gt[r>>>8&255]^255&Gt[i>>>0&255]^this.roundkey[41],m=4278190080&Gt[i>>>24&255]^16711680&Gt[t>>>16&255]^65280&Gt[e>>>8&255]^255&Gt[r>>>0&255]^this.roundkey[42],p=4278190080&Gt[r>>>24&255]^16711680&Gt[i>>>16&255]^65280&Gt[t>>>8&255]^255&Gt[e>>>0&255]^this.roundkey[43];this.outView.setUint32(0,h^this.iv[0],!1),this.outView.setUint32(4,f^this.iv[1],!1),this.outView.setUint32(8,m^this.iv[2],!1),this.outView.setUint32(12,p^this.iv[3],!1),this.iv[0]=a,this.iv[1]=s,this.iv[2]=n,this.iv[3]=o}}class ei extends Rt{constructor(e){super(e),this.moovSlice=null,this.currentTrack=null,this.tracks=[],this.metadataPromise=null,this.movieTimescale=-1,this.movieDurationInTimescale=-1,this.isQuickTime=!1,this.metadataTags={},this.currentMetadataKeys=null,this.isFragmented=!1,this.fragmentTrackDefaults=[],this.psshBoxes=[],this.currentFragment=null,this.lastReadFragment=null,this.decryptionKeyCache=new Map,this.reader=e._reader}async getTrackBackings(){return await this.readMetadata(),this.tracks.map(e=>e.trackBacking)}async getMimeType(){await this.readMetadata();const e=await this.getTrackBackings(),t=await Promise.all(e.map(e=>e.getDecoderConfig().then(e=>e?.codec??null)));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isQuickTime?"quicktime":"mp4");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({isQuickTime:this.isQuickTime,hasVideo:this.tracks.some(e=>"video"===e.info?.type),hasAudio:this.tracks.some(e=>"audio"===e.info?.type),codecStrings:t.filter(Boolean)})}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=0,t=!1;for(;;){let r=this.reader.requestSliceRange(e,8,16);if(r instanceof Promise&&(r=await r),!r)break;const a=e,s=Lt(r);if(!s)break;if("ftyp"===s.name||"styp"===s.name){const e=In(r,4);this.isQuickTime="qt "===e}else{if("moov"===s.name){let e=this.reader.requestSlice(r.filePos,s.contentSize);if(e instanceof Promise&&(e=await e),!e)break;this.moovSlice=e,this.readContiguousBoxes(this.moovSlice);for(const t of this.tracks){const e=t.editListPreviousSegmentDurations/this.movieTimescale;t.editListOffset-=Math.round(e*t.timescale)}t=this.isFragmented&&null!==this.reader.fileSize&&this.reader.fileSize>a+s.totalSize;break}if("moof"===s.name){if(!this.input._initInput)throw new Error('"moof" box encountered with no "moov" box present; this file is likely a Segment as described in ISO/IEC 14496-12 Section 8.16. A separate init file that contains a "moov" box is required to read this file, please provide it using InputOptions.initInput.');const e=await this.input._initInput._getDemuxer();if(e.constructor!==ei)throw new Error("Init input must match the input's format.");await e.readMetadata(),this.movieTimescale=e.movieTimescale,this.movieDurationInTimescale=e.movieDurationInTimescale,this.metadataTags=e.metadataTags,this.isFragmented=!0,this.fragmentTrackDefaults=e.fragmentTrackDefaults,this.psshBoxes=e.psshBoxes;for(const t of e.tracks){const e={id:t.id,demuxer:this,trackBacking:null,disposition:t.disposition,timescale:t.timescale,durationInMediaTimescale:t.durationInMediaTimescale,durationInMovieTimescale:t.durationInMovieTimescale,rotation:t.rotation,internalCodecId:t.internalCodecId,name:t.name,languageCode:t.languageCode,sampleTableByteOffset:null,sampleTable:null,fragmentLookupTable:[],currentFragmentState:null,fragmentPositionCache:[],editListPreviousSegmentDurations:t.editListPreviousSegmentDurations,editListOffset:t.editListOffset,encryptionInfo:t.encryptionInfo,encryptionAuxInfo:null,frmaCodecString:null,info:t.info};if(t.trackBacking)if(i(e.info),"video"===e.info.type&&-1!==e.info.width){const t=e;e.trackBacking=new ii(t),this.tracks.push(e)}else if("audio"===e.info.type&&-1!==e.info.numberOfChannels){const t=e;e.trackBacking=new ri(t),this.tracks.push(e)}}t=!1;break}}e=a+s.totalSize}if(t){i(null!==this.reader.fileSize);let e=this.reader.requestSlice(this.reader.fileSize-4,4);e instanceof Promise&&(e=await e),i(e);const t=gn(e),r=this.reader.fileSize-t;if(r>=0&&r<=this.reader.fileSize-16){let e=this.reader.requestSliceRange(r,8,16);if(e instanceof Promise&&(e=await e),e){const t=Lt(e);if(t&&"mfra"===t.name){let i=this.reader.requestSlice(e.filePos,t.contentSize);i instanceof Promise&&(i=await i),i&&this.readContiguousBoxes(i)}}}}})())}getSampleTableForTrack(e){if(e.sampleTable)return e.sampleTable;const t={sampleTimingEntries:[],sampleCompositionTimeOffsets:[],sampleSizes:[],keySampleIndices:null,chunkOffsets:[],sampleToChunk:[],presentationTimestamps:null,presentationTimestampIndexMap:null};if(e.sampleTable=t,null===e.sampleTableByteOffset)return t;i(this.moovSlice);const r=this.moovSlice.slice(e.sampleTableByteOffset);this.currentTrack=e,this.traverseBox(r),this.currentTrack=null;if("audio"===e.info?.type&&e.info.codec&&be.includes(e.info.codec)&&0===t.sampleCompositionTimeOffsets.length){i("audio"===e.info?.type);const r=Be(e.info.codec),s=[],n=[];for(let i=0;ie.startIndex),d=t.sampleTimingEntries[u],h=P(t.sampleTimingEntries,l,e=>e.startIndex),f=t.sampleTimingEntries[h],m=d.startDecodeTimestamp+(c-d.startIndex)*d.delta,p=f.startDecodeTimestamp+(l-f.startIndex)*f.delta-m,g=a(s);g&&g.delta===p?g.count++:s.push({startIndex:o.startChunkIndex+i,startDecodeTimestamp:m,count:1,delta:p});const k=o.samplesPerChunk*r.sampleSize*e.info.numberOfChannels;n.push(k)}o.startSampleIndex=o.startChunkIndex,o.samplesPerChunk=1}t.sampleTimingEntries=s,t.sampleSizes=n}if(t.sampleCompositionTimeOffsets.length>0){t.presentationTimestamps=[];for(const e of t.sampleTimingEntries)for(let i=0;ie.presentationTimestamp-t.presentationTimestamp),t.presentationTimestampIndexMap=Array(t.presentationTimestamps.length).fill(-1);for(let e=0;ee.moofOffset===s.moofOffset);if(r)ci(i,r.timestamp);else{const e=P(t,s.moofOffset-1,e=>e.moofOffset);if(-1!==e){const r=t[e];ci(i,r.endTimestamp)}}i.startTimestampIsFinal=!0}const r=P(t,i.startTimestamp,e=>e.startTimestamp);if(-1!==r&&t[r].moofOffset===s.moofOffset||t.splice(r+1,0,{moofOffset:s.moofOffset,startTimestamp:i.startTimestamp,endTimestamp:i.endTimestamp}),i.encryptionAuxInfo&&e.encryptionInfo){const t=await hi(this.reader,e.encryptionInfo,i.encryptionAuxInfo);for(let e=0;e0){t.languageCode="";for(let e=0;e<3;e++)t.languageCode=String.fromCharCode(96+(31&r))+t.languageCode,r>>=5;L(t.languageCode)||(t.languageCode=R)}}break;case"hdlr":{const t=this.currentTrack;if(!t)break;e.skip(8);const i=In(e,4);"vide"===i?t.info={type:"video",width:-1,height:-1,squarePixelWidth:-1,squarePixelHeight:-1,codec:null,codecDescription:null,colorSpace:null,avcType:null,avcCodecInfo:null,hevcCodecInfo:null,vp9CodecInfo:null,av1CodecInfo:null}:"soun"===i&&(t.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null,aacCodecInfo:null,pcmLittleEndian:!1,pcmSampleSize:null})}break;case"stbl":{const t=this.currentTrack;if(!t)break;t.sampleTableByteOffset=K,this.readContiguousBoxes(e.slice(X,j.contentSize))}break;case"stsd":{const t=this.currentTrack;if(!t)break;if(null===t.info||t.sampleTable)break;const i=un(e);e.skip(3);const r=gn(e);for(let a=0;a0&&(1===n?(e.skip(4),c=8*gn(e),e.skip(8)):2===n&&(e.skip(4),l=vn(e),o=gn(e),e.skip(4),c=gn(e),u=gn(e),e.skip(8))),t.info.numberOfChannels=o,t.info.sampleRate=l,t.frmaCodecString=null,this.readContiguousBoxes(e.slice(e.filePos,r+a.totalSize-e.filePos));const d="enca"===s?t.frmaCodecString:s;if(t.frmaCodecString=null,"mp4a"===d);else if("opus"===d)t.info.codec="opus",t.info.sampleRate=xe;else if("flac"===d)t.info.codec="flac";else if("ulaw"===d)t.info.codec="ulaw";else if("alaw"===d)t.info.codec="alaw";else if("ac-3"===d)t.info.codec="ac3";else if("ec-3"===d)t.info.codec="eac3";else if("twos"===d)8===c?t.info.codec="pcm-s8":16===c?t.info.codec=t.info.pcmLittleEndian?"pcm-s16":"pcm-s16be":(console.warn(`Unsupported sample size ${c} for codec 'twos'.`),t.info.codec=null);else if("sowt"===d)8===c?t.info.codec="pcm-s8":16===c?t.info.codec="pcm-s16":(console.warn(`Unsupported sample size ${c} for codec 'sowt'.`),t.info.codec=null);else if("raw "===d)t.info.codec="pcm-u8";else if("in24"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-s24":"pcm-s24be";else if("in32"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-s32":"pcm-s32be";else if("fl32"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-f32":"pcm-f32be";else if("fl64"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-f64":"pcm-f64be";else if("ipcm"===d){const e=t.info.pcmSampleSize;t.info.pcmLittleEndian?16===e?t.info.codec="pcm-s16":24===e?t.info.codec="pcm-s24":32===e?t.info.codec="pcm-s32":(console.warn(`Invalid ipcm sample size ${e}.`),t.info.codec=null):16===e?t.info.codec="pcm-s16be":24===e?t.info.codec="pcm-s24be":32===e?t.info.codec="pcm-s32be":(console.warn(`Invalid ipcm sample size ${e}.`),t.info.codec=null)}else if("fpcm"===d){const e=t.info.pcmSampleSize;t.info.pcmLittleEndian?32===e?t.info.codec="pcm-f32":64===e?t.info.codec="pcm-f64":(console.warn(`Invalid fpcm sample size ${e}.`),t.info.codec=null):32===e?t.info.codec="pcm-f32be":64===e?t.info.codec="pcm-f64be":(console.warn(`Invalid fpcm sample size ${e}.`),t.info.codec=null)}else if("lpcm"===d&&null!==u){const e=c+7>>3,i=Boolean(1&u),r=Boolean(2&u),a=4&u?-1:0;c>0&&c<=64&&(i?32===c&&(t.info.codec=r?"pcm-f32be":"pcm-f32"):a&1<0?(t.encryptionInfo.defaultCryptByteBlock=r>>4,t.encryptionInfo.defaultSkipByteBlock=15&r):(t.encryptionInfo.defaultCryptByteBlock=0,t.encryptionInfo.defaultSkipByteBlock=0),t.encryptionInfo.defaultIsProtected=0!==un(e),t.encryptionInfo.defaultPerSampleIvSize=un(e),t.encryptionInfo.defaultKid=w(ln(e,16)),t.encryptionInfo.defaultIsProtected&&0===t.encryptionInfo.defaultPerSampleIvSize){const i=un(e),r=new Uint8Array(16);r.set(ln(e,i),0),t.encryptionInfo.defaultConstantIv=r}}break;case"avcC":{const t=this.currentTrack;if(!t)break;i(t.info),t.info.codecDescription=ln(e,j.contentSize)}break;case"hvcC":{const t=this.currentTrack;if(!t)break;i(t.info),t.info.codecDescription=ln(e,j.contentSize)}break;case"vpcC":{const t=this.currentTrack;if(!t)break;i("video"===t.info?.type),e.skip(4);const r=un(e),a=un(e),s=un(e),n=s>>4,o=s>>1&7,c=1&s,l=un(e),u=un(e),d=un(e);t.info.vp9CodecInfo={profile:r,level:a,bitDepth:n,chromaSubsampling:o,videoFullRangeFlag:c,colourPrimaries:l,transferCharacteristics:u,matrixCoefficients:d}}break;case"av1C":{const t=this.currentTrack;if(!t)break;i("video"===t.info?.type),e.skip(1);const r=un(e),a=r>>5,s=31&r,n=un(e),o=n>>7,c=n>>6&1,l=n>>4&1,u=n>>3&1,d=n>>2&1,h=3&n,f=2===a&&c?n>>5&1?12:10:c?10:8;t.info.av1CodecInfo={profile:a,level:s,tier:o,bitDepth:f,monochrome:l,chromaSubsamplingX:u,chromaSubsamplingY:d,chromaSamplePosition:h}}break;case"colr":{const t=this.currentTrack;if(!t)break;i("video"===t.info?.type);if("nclx"!==In(e,4))break;const r=hn(e),a=hn(e),s=hn(e),n=Boolean(128&un(e));t.info.colorSpace={primaries:h[r],transfer:m[a],matrix:g[s],fullRange:n}}break;case"pasp":{const t=this.currentTrack;if(!t)break;i("video"===t.info?.type);const r=gn(e),a=gn(e);r>0&&a>0&&(r>a?t.info.squarePixelWidth=Math.round(t.info.width*r/a):t.info.squarePixelHeight=Math.round(t.info.height*a/r))}break;case"esds":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),e.skip(4);i(3===un(e)),qt(e),e.skip(2);const r=un(e),a=0!==(64&r),s=0!==(32&r);if(0!==(128&r)&&e.skip(2),a){const t=un(e);e.skip(t)}s&&e.skip(2);i(4===un(e));const n=qt(e),o=e.filePos,c=un(e);if(64===c||103===c?(t.info.codec="aac",t.info.aacCodecInfo={isMpeg2:103===c,objectType:null}):105===c||107===c?t.info.codec="mp3":221===c?t.info.codec="vorbis":console.warn(`Unsupported audio codec (objectTypeIndication ${c}) - discarding track.`),e.skip(12),n>e.filePos-o){i(5===un(e));const r=qt(e);if(t.info.codecDescription=ln(e,r),"aac"===t.info.codec){const e=ge(t.info.codecDescription);null!==e.numberOfChannels&&(t.info.numberOfChannels=e.numberOfChannels),null!==e.sampleRate&&(t.info.sampleRate=e.sampleRate)}}}break;case"enda":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),t.info.pcmLittleEndian=!!(255&hn(e))}break;case"pcmC":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),e.skip(4);const r=un(e);t.info.pcmLittleEndian=Boolean(1&r),t.info.pcmSampleSize=un(e)}break;case"dOps":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),e.skip(1);const r=un(e),a=hn(e),s=gn(e),n=mn(e),o=un(e);let c;c=0!==o?ln(e,2+r):new Uint8Array(0);const l=new Uint8Array(19+c.byteLength),u=new DataView(l.buffer);u.setUint32(0,1332770163,!1),u.setUint32(4,1214603620,!1),u.setUint8(8,1),u.setUint8(9,r),u.setUint16(10,a,!0),u.setUint32(12,s,!0),u.setInt16(16,n,!0),u.setUint8(18,o),l.set(c,19),t.info.codecDescription=l,t.info.numberOfChannels=r}break;case"dfLa":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),e.skip(4);const r=127,a=128,s=e.filePos;for(;e.filePos<$;){const i=un(e),s=fn(e);if((i&r)===Pt.STREAMINFO){e.skip(10);const i=gn(e),r=i>>>12,a=1+(i>>9&7);t.info.sampleRate=r,t.info.numberOfChannels=a,e.skip(20)}else e.skip(s);if(i&a)break}const n=e.filePos;e.filePos=s;const o=ln(e,n-s),c=new Uint8Array(4+o.byteLength);new DataView(c.buffer).setUint32(0,1716281667,!1),c.set(o,4),t.info.codecDescription=c}break;case"dac3":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type);const r=ln(e,3),a=new fe(r),s=a.readBits(2);a.skipBits(8);const n=a.readBits(3),o=a.readBits(1);s<3&&(t.info.sampleRate=ze[s]),t.info.numberOfChannels=xt[n]+o}break;case"dec3":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type);const r=(e=>{if(e.length<2)return null;const t=new fe(e),i=t.readBits(13),r=t.readBits(3),a=[];for(let s=0;s<=r&&!(Math.ceil(t.pos/8)+3>e.length);s++){const e=t.readBits(2),i=t.readBits(5);t.skipBits(1),t.skipBits(1);const r=t.readBits(3),s=t.readBits(3),n=t.readBits(1);t.skipBits(3);const o=t.readBits(4);let c=0;o>0?c=t.readBits(9):t.skipBits(1),a.push({fscod:e,fscod2:null,bsid:i,bsmod:r,acmod:s,lfeon:n,numDepSub:o,chanLoc:c})}return 0===a.length?null:{dataRate:i,substreams:a}})(ln(e,j.contentSize));if(!r){console.warn("Invalid dec3 box contents, ignoring.");break}const a=At(r);null!==a&&(t.info.sampleRate=a),t.info.numberOfChannels=Ft(r)}break;case"stts":{const t=this.currentTrack;if(!t)break;if(!t.sampleTable)break;e.skip(4);const i=gn(e);let r=0,a=0;for(let s=0;se.id===i);if(!r)break;const a=gn(e),s=(12&a)>>2,n=3&a,o=[un,hn,fn,gn],c=o[(48&a)>>4],l=o[s],u=o[n],d=gn(e);for(let h=0;he.timestamp-t.timestamp);for(let e=0;e({presentationTimestamp:e.presentationTimestamp,sampleIndex:t})).sort((e,t)=>e.presentationTimestamp-t.presentationTimestamp);for(let i=0;ie.id===u);if(!d)break;const h=this.fragmentTrackDefaults.find(e=>e.trackId===u);this.currentTrack=d,d.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:h?.defaultSampleDescriptionIndex??null,defaultSampleDuration:h?.defaultSampleDuration??null,defaultSampleSize:h?.defaultSampleSize??null,defaultSampleFlags:h?.defaultSampleFlags??null,startTimestamp:null,encryptionAuxInfo:null},r?d.currentFragmentState.baseDataOffset=wn(e):l&&(d.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),a&&(d.currentFragmentState.sampleDescriptionIndex=gn(e)),s&&(d.currentFragmentState.defaultSampleDuration=gn(e)),n&&(d.currentFragmentState.defaultSampleSize=gn(e)),o&&(d.currentFragmentState.defaultSampleFlags=gn(e)),c&&(d.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{const t=this.currentTrack;if(!t)break;i(t.currentFragmentState);const r=un(e);e.skip(3);const a=0===r?gn(e):wn(e);t.currentFragmentState.startTimestamp=a}break;case"trun":{const t=this.currentTrack;if(!t)break;i(this.currentFragment),i(t.currentFragmentState);const r=un(e),a=fn(e),s=Boolean(1&a),n=Boolean(4&a),o=Boolean(256&a),c=Boolean(512&a),l=Boolean(1024&a),u=Boolean(2048&a),d=gn(e);let h=null;s&&(h=bn(e));let f,m=null;if(n&&(m=gn(e)),this.currentFragment.trackData.has(t.id)?(f=this.currentFragment.trackData.get(t.id),null!==h&&(f.currentOffset=t.currentFragmentState.baseDataOffset+h)):(f={track:t,currentTimestamp:0,currentOffset:t.currentFragmentState.baseDataOffset+(h??0),startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1,encryptionAuxInfo:null},this.currentFragment.trackData.set(t.id,f)),0===d){this.currentFragment.implicitBaseDataOffset=f.currentOffset;break}for(let p=0;p0&&(a=ln(e,r));const s=di(t);s.defaultSampleInfoSize=i,s.sampleSizes=a,s.sampleCount=r}break;case"saio":{const t=this.currentTrack;if(!t||!t.encryptionInfo)break;const i=un(e);if(1&fn(e)){const i=In(e,4),r=gn(e);if(i!==t.encryptionInfo.scheme||0!==r)break}const r=gn(e);if(0===r)break;r>1&&console.warn("Multiple saio entries are not supported; using the first offset only.");let a=0===i?gn(e):Number(wn(e));this.currentFragment&&(a+=this.currentFragment.moofOffset);di(t).offset=a}break;case"senc":{const t=this.currentTrack;if(!t||!t.encryptionInfo)break;i(this.currentFragment);const r=this.currentFragment.trackData.get(t.id);if(!r)break;e.skip(1);const a=fn(e),s=Boolean(2&a),n=gn(e),o=t.encryptionInfo.defaultPerSampleIvSize;i(null!==o);for(let i=0;i0?a.set(ln(e,o),0):a.set(t.encryptionInfo.defaultConstantIv,0);let n=null;if(s){const t=hn(e);n=[];for(let i=0;i0&&((z=this.metadataTags).trackNumber??(z.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&((U=this.metadataTags).tracksTotal??(U.tracksTotal=i))}break;case"trkn":if(a instanceof Uint8Array&&a.length>=6){const e=c(a),t=e.getUint16(2,!1),i=e.getUint16(4,!1);t>0&&((q=this.metadataTags).trackNumber??(q.trackNumber=t)),i>0&&((W=this.metadataTags).tracksTotal??(W.tracksTotal=i))}break;case"disc":case"disk":if(a instanceof Uint8Array&&a.length>=6){const e=c(a),t=e.getUint16(2,!1),i=e.getUint16(4,!1);t>0&&((V=this.metadataTags).discNumber??(V.discNumber=t)),i>0&&((H=this.metadataTags).discsTotal??(H.discsTotal=i))}}}}}var Q,G;return e.filePos=$,!0}}class ti{constructor(e){this.internalTrack=e,this.packetToSampleIndex=new WeakMap,this.packetToFragmentLocation=new WeakMap}getId(){return this.internalTrack.id}getNumber(){const e=this.internalTrack.demuxer,t=this.internalTrack.trackBacking.getType();let i=0;for(const r of e.tracks)if(r.trackBacking.getType()===t&&i++,r===this.internalTrack)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.internalCodecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.timescale}isRelativeToUnixEpoch(){return!1}getDisposition(){return this.internalTrack.disposition}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){const e=this.internalTrack;if(e.durationInMediaTimescale<=0)return null;i(e.trackBacking);const t=await e.trackBacking.getFirstPacket({metadataOnly:!0});return(t?.timestamp??0)+e.durationInMediaTimescale/e.timescale}async getLiveRefreshInterval(){return null}async getFirstPacket(e){const t=await this.fetchPacketForSampleIndex(0,e);return t||!this.internalTrack.demuxer.isFragmented?t:this.performFragmentedLookup(null,e=>e.trackData.get(this.internalTrack.id)?{sampleIndex:0,correctSampleFound:!0}:{sampleIndex:-1,correctSampleFound:!1},-1/0,1/0,e)}mapTimestampIntoTimescale(e){return D(e*this.internalTrack.timescale)+this.internalTrack.editListOffset}async getPacket(e,t){const i=this.mapTimestampIntoTimescale(e),r=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),a=ai(r,i),s=await this.fetchPacketForSampleIndex(a,t);return ui(r)&&this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const r=P(t.presentationTimestamps,i,e=>e.presentationTimestamp);return{sampleIndex:-1!==r?t.presentationTimestamps[r].sampleIndex:-1,correctSampleFound:-1!==r&&i{if(e===r.fragment){const t=e.trackData.get(this.internalTrack.id);if(r.sampleIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const r=C(t.presentationTimestamps,e=>t.samples[e.sampleIndex].isKeyFrame&&e.presentationTimestamp<=i);return{sampleIndex:-1!==r?t.presentationTimestamps[r].sampleIndex:-1,correctSampleFound:-1!==r&&i{if(e===a.fragment){const t=e.trackData.get(this.internalTrack.id).samples.findIndex((e,t)=>e.isKeyFrame&&t>a.sampleIndex);if(-1!==t)return{sampleIndex:t,correctSampleFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.samples.findIndex(e=>e.isKeyFrame);return i(-1!==e),{sampleIndex:e,correctSampleFound:!0}}}return{sampleIndex:-1,correctSampleFound:!1}},-1/0,1/0,t)}async fetchPacketForSampleIndex(e,t){if(-1===e)return null;const r=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),a=ni(r,e);if(!a)return null;let s;if(t.metadataOnly)s=Dt;else{let t=this.internalTrack.demuxer.reader.requestSlice(a.sampleOffset,a.sampleSize);if(t instanceof Promise&&(t=await t),!t)return null;if(s=ln(t,a.sampleSize),this.internalTrack.encryptionAuxInfo){i(this.internalTrack.encryptionInfo);const t=await hi(this.internalTrack.demuxer.reader,this.internalTrack.encryptionInfo,this.internalTrack.encryptionAuxInfo);ee.timestamp),d=-1!==u?this.internalTrack.fragmentLookupTable[u]:null,h=P(this.internalTrack.fragmentPositionCache,r,e=>e.startTimestamp),f=-1!==h?this.internalTrack.fragmentPositionCache[h]:null,m=Math.max(d?.moofOffset??0,f?.moofOffset??0)||null;let p;for(e?null===m||e.moofOffset>=m?(p=e.moofOffset+e.moofSize,o=e):p=m:p=m??0;;){if(o){const e=o.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>a)break}let e=n.reader.requestSliceRange(p,8,16);if(e instanceof Promise&&(e=await e),!e)break;const i=p,r=Lt(e);if(!r)break;if("moof"===r.name){o=await n.readFragment(i);const{sampleIndex:e,correctSampleFound:r}=t(o);if(r)return this.fetchPacketInFragment(o,e,s);-1!==e&&(c=o,l=e)}p=i+r.totalSize}if(d&&(!c||c.moofOffset{if("vp9"!==this.internalTrack.info.codec||this.internalTrack.info.vp9CodecInfo){if("av1"===this.internalTrack.info.codec&&!this.internalTrack.info.av1CodecInfo){const e=await this.getFirstPacket({});this.internalTrack.info.av1CodecInfo=e&&yt(e.data)}}else{const e=await this.getFirstPacket({});this.internalTrack.info.vp9CodecInfo=e&&kt(e.data)}const e={codec:ve(this.internalTrack.info),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0};return this.internalTrack.info.width===this.internalTrack.info.squarePixelWidth&&this.internalTrack.info.height===this.internalTrack.info.squarePixelHeight||(e.displayAspectWidth=this.internalTrack.info.squarePixelWidth,e.displayAspectHeight=this.internalTrack.info.squarePixelHeight),e})()):null}}class ri extends ti{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getType(){return"audio"}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return this.internalTrack.info.codec?this.decoderConfig??(this.decoderConfig={codec:Ie(this.internalTrack.info),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}):null}}const ai=(e,t)=>{if(e.presentationTimestamps){const i=P(e.presentationTimestamps,t,e=>e.presentationTimestamp);return-1===i?-1:e.presentationTimestamps[i].sampleIndex}{const i=P(e.sampleTimingEntries,t,e=>e.startDecodeTimestamp);if(-1===i)return-1;const r=e.sampleTimingEntries[i];return r.startIndex+Math.min(Math.floor((t-r.startDecodeTimestamp)/r.delta),r.count-1)}},si=(e,t)=>{if(!e.keySampleIndices)return ai(e,t);if(e.presentationTimestamps){const i=P(e.presentationTimestamps,t,e=>e.presentationTimestamp);if(-1===i)return-1;for(let t=i;t>=0;t--){const i=e.presentationTimestamps[t].sampleIndex;if(-1!==S(e.keySampleIndices,i,e=>e))return i}return-1}{const i=ai(e,t),r=P(e.keySampleIndices,i,e=>e);return e.keySampleIndices[r]??-1}},ni=(e,t)=>{const r=P(e.sampleTimingEntries,t,e=>e.startIndex),a=e.sampleTimingEntries[r];if(!a||a.startIndex+a.count<=t)return null;let s=a.startDecodeTimestamp+(t-a.startIndex)*a.delta;const n=P(e.sampleCompositionTimeOffsets,t,e=>e.startIndex),o=e.sampleCompositionTimeOffsets[n];o&&t-o.startIndexe.startSampleIndex),u=e.sampleToChunk[l];i(u);const d=u.startChunkIndex+Math.floor((t-u.startSampleIndex)/u.samplesPerChunk),h=e.chunkOffsets[d],f=u.startSampleIndex+(d-u.startChunkIndex)*u.samplesPerChunk;let m=0,p=h;if(1===e.sampleSizes.length)p+=c*(t-f),m+=c*u.samplesPerChunk;else for(let i=f;ie)}},oi=(e,t)=>{if(!e.keySampleIndices)return t+1;const i=P(e.keySampleIndices,t,e=>e);return e.keySampleIndices[i+1]??-1},ci=(e,t)=>{e.startTimestamp+=t,e.endTimestamp+=t;for(const i of e.samples)i.presentationTimestamp+=t;for(const i of e.presentationTimestamps)i.presentationTimestamp+=t},li=e=>{const[t,i]=e,r=Math.atan2(i,t);return Number.isFinite(r)?r*(180/Math.PI):0},ui=e=>0===e.sampleSizes.length,di=e=>{var t;return e.currentFragmentState?(t=e.currentFragmentState).encryptionAuxInfo??(t.encryptionAuxInfo={defaultSampleInfoSize:0,sampleSizes:null,sampleCount:0,offset:null,resolved:null}):e.encryptionAuxInfo??(e.encryptionAuxInfo={defaultSampleInfoSize:0,sampleSizes:null,sampleCount:0,offset:null,resolved:null})},hi=async(e,t,r)=>{if(r.resolved)return r.resolved;if(null===r.offset||0===r.sampleCount)throw new Error("Incomplete saiz/saio info; cannot resolve encryption data.");let a=0;if(r.defaultSampleInfoSize>0)a=r.defaultSampleInfoSize*r.sampleCount;else{i(r.sampleSizes);for(let e=0;e0?r.defaultSampleInfoSize:r.sampleSizes[i],a=new Uint8Array(16);n>0?a.set(ln(s,n),0):a.set(t.defaultConstantIv,0);let c=null;if(e>n){const e=hn(s);c=[];for(let t=0;t{i(e.encryptionInfo);const s=e.encryptionInfo;i(null!==s.defaultKid);const n=s.defaultKid;let o;const c=e.demuxer.decryptionKeyCache.get(n);if(c)o=await c;else{if(!e.demuxer.input._formatOptions.isobmff?.resolveKeyId)throw new Error("Encrypted media samples encountered. To decrypt them, please provide a callback for InputOptions.formatOptions.isobmff.resolveKeyId.");const t=(async()=>{let t=e.demuxer.psshBoxes;if(a){t=[...t,...a.psshBoxes].filter(e=>null===e.keyIds||e.keyIds.includes(n));for(let e=0;e{i(e.length%2===0);const t=new Uint8Array(e.length/2);for(let i=0;i{const s=new Uint8Array(16);s.set(r.iv,0);const n=await crypto.subtle.importKey("raw",e,{name:"AES-CTR"},!1,["decrypt"]),o=async e=>{const t=await crypto.subtle.decrypt({name:"AES-CTR",counter:s,length:64},n,e);return new Uint8Array(t)};if(!r.subsamples)return o(a);i(null!==t.defaultCryptByteBlock&&null!==t.defaultSkipByteBlock);const c=gi(r.subsamples,t.defaultCryptByteBlock,t.defaultSkipByteBlock);let l=0;for(const i of c)for(const e of i.perSubsample)l+=e.length;const u=new Uint8Array(l);let d=0;for(const i of c)for(const e of i.perSubsample)u.set(a.subarray(e.offset,e.offset+e.length),d),d+=e.length;const h=await o(u),f=new Uint8Array(a);let m=0;for(const i of c)for(const e of i.perSubsample)f.set(h.subarray(m,m+e.length),e.offset),m+=e.length;return f},pi=(e,t,r,a)=>{const s=new Zt;s.init({key:e,iv:r.iv});const n=t.defaultCryptByteBlock,o=t.defaultSkipByteBlock;if(i(null!==n&&null!==o),!r.subsamples){const e=new Uint8Array(a),t=Math.floor(a.length/16);for(let i=0;i{const r=[],a=0!==t||0!==i;let s=0;for(const n of e){s+=n.clearLen;const e=[];if(a){let r=n.protectedLen,a=s;for(;r>0&&!(r<16*t);){const s=16*t;e.push({offset:a,length:s}),a+=s,r-=s;const n=Math.min(16*i,r);a+=n,r-=n}s+=n.protectedLen}else n.protectedLen>0&&e.push({offset:s,length:n.protectedLen}),s+=n.protectedLen;r.push({perSubsample:e})}return r};var ki,bi;(bi=ki||(ki={}))[bi.EBML=440786851]="EBML",bi[bi.EBMLVersion=17030]="EBMLVersion",bi[bi.EBMLReadVersion=17143]="EBMLReadVersion",bi[bi.EBMLMaxIDLength=17138]="EBMLMaxIDLength",bi[bi.EBMLMaxSizeLength=17139]="EBMLMaxSizeLength",bi[bi.DocType=17026]="DocType",bi[bi.DocTypeVersion=17031]="DocTypeVersion",bi[bi.DocTypeReadVersion=17029]="DocTypeReadVersion",bi[bi.Void=236]="Void",bi[bi.Segment=408125543]="Segment",bi[bi.SeekHead=290298740]="SeekHead",bi[bi.Seek=19899]="Seek",bi[bi.SeekID=21419]="SeekID",bi[bi.SeekPosition=21420]="SeekPosition",bi[bi.Duration=17545]="Duration",bi[bi.Info=357149030]="Info",bi[bi.TimestampScale=2807729]="TimestampScale",bi[bi.MuxingApp=19840]="MuxingApp",bi[bi.WritingApp=22337]="WritingApp",bi[bi.Tracks=374648427]="Tracks",bi[bi.TrackEntry=174]="TrackEntry",bi[bi.TrackNumber=215]="TrackNumber",bi[bi.TrackUID=29637]="TrackUID",bi[bi.TrackType=131]="TrackType",bi[bi.FlagEnabled=185]="FlagEnabled",bi[bi.FlagDefault=136]="FlagDefault",bi[bi.FlagForced=21930]="FlagForced",bi[bi.FlagOriginal=21934]="FlagOriginal",bi[bi.FlagHearingImpaired=21931]="FlagHearingImpaired",bi[bi.FlagVisualImpaired=21932]="FlagVisualImpaired",bi[bi.FlagCommentary=21935]="FlagCommentary",bi[bi.FlagLacing=156]="FlagLacing",bi[bi.Name=21358]="Name",bi[bi.Language=2274716]="Language",bi[bi.LanguageBCP47=2274717]="LanguageBCP47",bi[bi.CodecID=134]="CodecID",bi[bi.CodecPrivate=25506]="CodecPrivate",bi[bi.CodecDelay=22186]="CodecDelay",bi[bi.SeekPreRoll=22203]="SeekPreRoll",bi[bi.DefaultDuration=2352003]="DefaultDuration",bi[bi.Video=224]="Video",bi[bi.PixelWidth=176]="PixelWidth",bi[bi.PixelHeight=186]="PixelHeight",bi[bi.DisplayWidth=21680]="DisplayWidth",bi[bi.DisplayHeight=21690]="DisplayHeight",bi[bi.DisplayUnit=21682]="DisplayUnit",bi[bi.AlphaMode=21440]="AlphaMode",bi[bi.Audio=225]="Audio",bi[bi.SamplingFrequency=181]="SamplingFrequency",bi[bi.Channels=159]="Channels",bi[bi.BitDepth=25188]="BitDepth",bi[bi.SimpleBlock=163]="SimpleBlock",bi[bi.BlockGroup=160]="BlockGroup",bi[bi.Block=161]="Block",bi[bi.BlockAdditions=30113]="BlockAdditions",bi[bi.BlockMore=166]="BlockMore",bi[bi.BlockAdditional=165]="BlockAdditional",bi[bi.BlockAddID=238]="BlockAddID",bi[bi.BlockDuration=155]="BlockDuration",bi[bi.ReferenceBlock=251]="ReferenceBlock",bi[bi.Cluster=524531317]="Cluster",bi[bi.Timestamp=231]="Timestamp",bi[bi.Cues=475249515]="Cues",bi[bi.CuePoint=187]="CuePoint",bi[bi.CueTime=179]="CueTime",bi[bi.CueTrackPositions=183]="CueTrackPositions",bi[bi.CueTrack=247]="CueTrack",bi[bi.CueClusterPosition=241]="CueClusterPosition",bi[bi.Colour=21936]="Colour",bi[bi.MatrixCoefficients=21937]="MatrixCoefficients",bi[bi.TransferCharacteristics=21946]="TransferCharacteristics",bi[bi.Primaries=21947]="Primaries",bi[bi.Range=21945]="Range",bi[bi.Projection=30320]="Projection",bi[bi.ProjectionType=30321]="ProjectionType",bi[bi.ProjectionPoseRoll=30325]="ProjectionPoseRoll",bi[bi.Attachments=423732329]="Attachments",bi[bi.AttachedFile=24999]="AttachedFile",bi[bi.FileDescription=18046]="FileDescription",bi[bi.FileName=18030]="FileName",bi[bi.FileMediaType=18016]="FileMediaType",bi[bi.FileData=18012]="FileData",bi[bi.FileUID=18094]="FileUID",bi[bi.Chapters=272869232]="Chapters",bi[bi.Tags=307544935]="Tags",bi[bi.Tag=29555]="Tag",bi[bi.Targets=25536]="Targets",bi[bi.TargetTypeValue=26826]="TargetTypeValue",bi[bi.TargetType=25546]="TargetType",bi[bi.TagTrackUID=25541]="TagTrackUID",bi[bi.TagEditionUID=25545]="TagEditionUID",bi[bi.TagChapterUID=25540]="TagChapterUID",bi[bi.TagAttachmentUID=25542]="TagAttachmentUID",bi[bi.SimpleTag=26568]="SimpleTag",bi[bi.TagName=17827]="TagName",bi[bi.TagLanguage=17530]="TagLanguage",bi[bi.TagString=17543]="TagString",bi[bi.TagBinary=17541]="TagBinary",bi[bi.ContentEncodings=28032]="ContentEncodings",bi[bi.ContentEncoding=25152]="ContentEncoding",bi[bi.ContentEncodingOrder=20529]="ContentEncodingOrder",bi[bi.ContentEncodingScope=20530]="ContentEncodingScope",bi[bi.ContentCompression=20532]="ContentCompression",bi[bi.ContentCompAlgo=16980]="ContentCompAlgo",bi[bi.ContentCompSettings=16981]="ContentCompSettings",bi[bi.ContentEncryption=20533]="ContentEncryption";const yi=[ki.EBML,ki.Segment],wi=[ki.SeekHead,ki.Info,ki.Cluster,ki.Tracks,ki.Cues,ki.Attachments,ki.Chapters,ki.Tags],Ti=[...yi,...wi],Si=16,Pi=e=>{if(e.remainingLength<1)return null;const t=un(e);if(e.skip(-1),0===t)return null;let i=1,r=128;for(;0===(t&r);)i++,r>>=1;return e.remainingLength{if(e.remainingLength<1)return null;const t=un(e);if(0===t)return null;let i=1,r=128;for(;0===(t&r);)i++,r>>=1;if(e.remainingLength{if(t<1||t>8)throw new Error("Bad unsigned int size "+t);let i=0;for(let r=0;r{const t=Pi(e);if(null===t)return null;if(e.remainingLength{if(e.remainingLength<1)return null;if(255===un(e))return;e.skip(-1);const t=vi(e);return null===t?null:72057594037927940!==t?t:void 0},Bi=e=>{i(e.remainingLength>=2);const t=xi(e);if(null===t)return null;const r=Ci(e);return null===r?null:{id:t,size:r}},Ei=(e,t)=>{const i=ln(e,t);let r=0;for(;r{const i=ln(e,t);let r=0;for(;r{if(0===t)return 0;if(4!==t&&8!==t)throw new Error("Bad float size "+t);return 4===t?Pn(e):vn(e)},Fi=async(e,t,i,r)=>{const a=new Set(i);let s=t;for(;null===r||ss?r:s,found:!1}},Ri=async(e,t,i,r)=>{const a=new Set(i);let s=t;for(;se.tracks.map(e=>e.trackBacking))}async getMimeType(){await this.readMetadata();const e=await this.getTrackBackings(),t=await Promise.all(e.map(e=>e.getDecoderConfig().then(e=>e?.codec??null)));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isWebM?"webm":"x-matroska");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings.filter(Boolean))].join(", ")}"`);return t})({isWebM:this.isWebM,hasVideo:this.segments.some(e=>e.tracks.some(e=>"video"===e.info?.type)),hasAudio:this.segments.some(e=>e.tracks.some(e=>"audio"===e.info?.type)),codecStrings:t.filter(Boolean)})}async getMetadataTags(){await this.readMetadata();for(const t of this.segments)t.metadataTagsCollected||(null!==this.reader.fileSize&&await this.loadSegmentMetadata(t),t.metadataTagsCollected=!0);let e={};for(const t of this.segments)e={...e,...t.metadataTags};return e}readMetadata(){return this.readMetadataPromise??(this.readMetadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,2,Si);if(t instanceof Promise&&(t=await t),!t)break;const i=Bi(t);if(!i)break;const r=i.id;let s=i.size;const n=t.filePos;if(r===ki.EBML){ji(s);let e=this.reader.requestSlice(n,s);if(e instanceof Promise&&(e=await e),!e)break;this.readContiguousElements(e)}else if(r===ki.Segment){if(await this.readSegment(n,s),void 0===s)break;if(null===this.reader.fileSize)break}else if(r===ki.Cluster){if(null===this.reader.fileSize)break;if(void 0===s){s=(await Fi(this.reader,n,Ti,this.reader.fileSize)).pos-n}const e=a(this.segments);e&&(e.elementEndPos=n+s)}ji(s),e=n+s}})())}async readSegment(e,t){this.currentSegment={seekHeadSeen:!1,infoSeen:!1,tracksSeen:!1,cuesSeen:!1,tagsSeen:!1,attachmentsSeen:!1,timestampScale:-1,timestampFactor:-1,duration:-1,seekEntries:[],tracks:[],cuePoints:[],dataStartPos:e,elementEndPos:void 0===t?null:e+t,clusterSeekStartPos:e,lastReadCluster:null,metadataTags:{},metadataTagsCollected:!1},this.segments.push(this.currentSegment);let i=e;for(;null===this.currentSegment.elementEndPos||ie.id===a);if(-1!==o){const e=Zi[o].flag;this.currentSegment[e]=!0,ji(s);let t=this.reader.requestSlice(n,s);t instanceof Promise&&(t=await t),t&&this.readContiguousElements(t)}else if(a===ki.Tags||a===ki.Attachments){a===ki.Tags?this.currentSegment.tagsSeen=!0:this.currentSegment.attachmentsSeen=!0,ji(s);let e=this.reader.requestSlice(n,s);e instanceof Promise&&(e=await e),e&&this.readContiguousElements(e)}else if(a===ki.Cluster){this.currentSegment.clusterSeekStartPos=t;break}if(void 0===s)break;i=n+s}if(this.currentSegment.seekEntries.sort((e,t)=>e.segmentPosition-t.segmentPosition),null!==this.reader.fileSize)for(const n of this.currentSegment.seekEntries){const t=Zi.find(e=>e.id===n.id);if(!t)continue;if(this.currentSegment[t.flag])continue;let i=this.reader.requestSliceRange(e+n.segmentPosition,2,Si);if(i instanceof Promise&&(i=await i),!i)continue;const r=Bi(i);if(!r)continue;const{id:a,size:s}=r;if(a!==t.id)continue;ji(s),this.currentSegment[t.flag]=!0;let o=this.reader.requestSlice(i.filePos,s);o instanceof Promise&&(o=await o),o&&this.readContiguousElements(o)}-1===this.currentSegment.timestampScale&&(this.currentSegment.timestampScale=1e6,this.currentSegment.timestampFactor=1e3);for(const n of this.currentSegment.tracks)null!==n.defaultDurationNs&&(n.defaultDuration=this.currentSegment.timestampFactor*n.defaultDurationNs/1e9);const r=new Map(this.currentSegment.tracks.map(e=>[e.id,e]));for(const n of this.currentSegment.cuePoints){const e=r.get(n.trackId);e&&e.cuePoints.push(n)}for(const n of this.currentSegment.tracks){n.cuePoints.sort((e,t)=>e.time-t.time);for(let e=0;es&&(s=n.cuePoints.length,a=n);for(const n of this.currentSegment.tracks)0===n.cuePoints.length&&(n.cuePoints=a.cuePoints);this.currentSegment=null}async readCluster(e,t){if(t.lastReadCluster?.elementStartPos===e)return t.lastReadCluster;let r=this.reader.requestSliceRange(e,2,Si);r instanceof Promise&&(r=await r),i(r);const s=e,n=Bi(r);i(n);i(n.id===ki.Cluster);let o=n.size;const c=r.filePos;if(void 0===o){o=(await Fi(this.reader,c,Ti,t.elementEndPos)).pos-c}let l=this.reader.requestSlice(c,o);l instanceof Promise&&(l=await l);const u={segment:t,elementStartPos:s,elementEndPos:c+o,dataStartPos:c,timestamp:-1,trackData:new Map};if(this.currentCluster=u,l){const e=this.readContiguousElements(l,Ti);u.elementEndPos=e}for(const[,d]of u.trackData){const e=d.track;i(d.blocks.length>0);let t=!1;for(let i=0;i({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp);for(let i=0;i({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp));const r=d.blocks[d.presentationTimestamps[0].blockIndex],n=d.blocks[a(d.presentationTimestamps).blockIndex];d.startTimestamp=r.timestamp,d.endTimestamp=n.timestamp+n.duration;const o=P(e.clusterPositionCache,d.startTimestamp,e=>e.startTimestamp);-1!==o&&e.clusterPositionCache[o].elementStartPos===s||e.clusterPositionCache.splice(o+1,0,{elementStartPos:u.elementStartPos,startTimestamp:d.startTimestamp})}return t.lastReadCluster=u,u}getTrackDataInCluster(e,t){let i=e.trackData.get(t);if(!i){const r=e.segment.tracks.find(e=>e.id===t);if(!r)return null;i={track:r,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,blocks:[],presentationTimestamps:[]},e.trackData.set(t,i)}return i}expandLacedBlocks(e,t){for(let r=0;r=2;){const i=e.filePos;if(!this.traverseElement(e,t))return i}return e.filePos}traverseElement(e,t){const a=Bi(e);if(!a)return!1;if(t&&t.includes(a.id))return!1;const{id:s,size:n}=a,o=e.filePos;switch(ji(n),s){case ki.DocType:this.isWebM="webm"===Ei(e,n);break;case ki.Seek:{if(!this.currentSegment)break;const t={id:-1,segmentPosition:-1};this.currentSegment.seekEntries.push(t),this.readContiguousElements(e.slice(o,n)),-1!==t.id&&-1!==t.segmentPosition||this.currentSegment.seekEntries.pop()}break;case ki.SeekID:{const t=this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.id=Ii(e,n)}break;case ki.SeekPosition:{const t=this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.segmentPosition=Ii(e,n)}break;case ki.TimestampScale:if(!this.currentSegment)break;this.currentSegment.timestampScale=Ii(e,n),this.currentSegment.timestampFactor=1e9/this.currentSegment.timestampScale;break;case ki.Duration:if(!this.currentSegment)break;this.currentSegment.duration=Ai(e,n);break;case ki.TrackEntry:if(!this.currentSegment)break;if(this.currentTrack={id:-1,segment:this.currentSegment,demuxer:this,clusterPositionCache:[],cuePoints:[],disposition:{...he,primary:!1},trackBacking:null,codecId:null,codecPrivate:null,defaultDuration:null,defaultDurationNs:null,name:null,languageCode:"eng",hasLanguageBcp47:!1,decodingInstructions:[],info:null},this.readContiguousElements(e.slice(o,n)),!this.currentTrack)break;if(this.currentTrack.decodingInstructions.some(e=>"decompress"!==e.data?.type||e.scope!==Qi.Block||e.data.algorithm!==Yi.HeaderStripping)&&(console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`),this.currentTrack=null),this.currentTrack&&-1!==this.currentTrack.id&&this.currentTrack.codecId&&this.currentTrack.info){const e=this.currentTrack.codecId.indexOf("/"),t=-1===e?this.currentTrack.codecId:this.currentTrack.codecId.slice(0,e);if("video"===this.currentTrack.info.type&&-1!==this.currentTrack.info.width&&-1!==this.currentTrack.info.height){if(this.currentTrack.info.squarePixelWidth=this.currentTrack.info.width,this.currentTrack.info.squarePixelHeight=this.currentTrack.info.height,null!==this.currentTrack.info.displayWidth&&null!==this.currentTrack.info.displayHeight){const e=this.currentTrack.info.displayWidth*this.currentTrack.info.height,t=this.currentTrack.info.displayHeight*this.currentTrack.info.width;e>0&&t>0&&(e>t?this.currentTrack.info.squarePixelWidth=Math.round(this.currentTrack.info.width*e/t):this.currentTrack.info.squarePixelHeight=Math.round(this.currentTrack.info.height*t/e))}this.currentTrack.codecId===Di?(this.currentTrack.info.codec="avc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Mi?(this.currentTrack.info.codec="hevc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ni?this.currentTrack.info.codec="vp8":t===Oi?this.currentTrack.info.codec="vp9":t===Li&&(this.currentTrack.info.codec="av1");const e=this.currentTrack;this.currentTrack.trackBacking=new rr(e),this.currentSegment.tracks.push(this.currentTrack)}else if("audio"===this.currentTrack.info.type){t===zi?(this.currentTrack.info.codec="aac",this.currentTrack.info.aacCodecInfo={isMpeg2:this.currentTrack.codecId.includes("MPEG2"),objectType:null},this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Ui?this.currentTrack.info.codec="mp3":t===qi?(this.currentTrack.info.codec="opus",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate,this.currentTrack.info.sampleRate=xe):t===Wi?(this.currentTrack.info.codec="vorbis",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Vi?(this.currentTrack.info.codec="flac",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Hi?(this.currentTrack.info.codec="ac3",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ki?(this.currentTrack.info.codec="eac3",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):"A_PCM/INT/LIT"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32"):"A_PCM/INT/BIG"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16be":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24be":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32be"):"A_PCM/FLOAT/IEEE"===this.currentTrack.codecId&&(32===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-f32":64===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-f64"));const e=this.currentTrack;this.currentTrack.trackBacking=new ar(e),this.currentSegment.tracks.push(this.currentTrack)}}this.currentTrack=null;break;case ki.TrackNumber:if(!this.currentTrack)break;this.currentTrack.id=Ii(e,n);break;case ki.TrackType:{if(!this.currentTrack)break;const t=Ii(e,n);1===t?this.currentTrack.info={type:"video",width:-1,height:-1,displayWidth:null,displayHeight:null,displayUnit:null,squarePixelWidth:-1,squarePixelHeight:-1,rotation:0,codec:null,codecDescription:null,colorSpace:null,alphaMode:!1}:2===t&&(this.currentTrack.info={type:"audio",numberOfChannels:1,sampleRate:8e3,bitDepth:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case ki.FlagEnabled:if(!this.currentTrack)break;Ii(e,n)||(this.currentTrack=null);break;case ki.FlagDefault:if(!this.currentTrack)break;this.currentTrack.disposition.default=!!Ii(e,n);break;case ki.FlagForced:if(!this.currentTrack)break;this.currentTrack.disposition.forced=!!Ii(e,n);break;case ki.FlagOriginal:if(!this.currentTrack)break;this.currentTrack.disposition.original=!!Ii(e,n);break;case ki.FlagHearingImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.hearingImpaired=!!Ii(e,n);break;case ki.FlagVisualImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.visuallyImpaired=!!Ii(e,n);break;case ki.FlagCommentary:if(!this.currentTrack)break;this.currentTrack.disposition.commentary=!!Ii(e,n);break;case ki.CodecID:if(!this.currentTrack)break;this.currentTrack.codecId=Ei(e,n);break;case ki.CodecPrivate:if(!this.currentTrack)break;this.currentTrack.codecPrivate=ln(e,n);break;case ki.DefaultDuration:if(!this.currentTrack)break;this.currentTrack.defaultDurationNs=Ii(e,n);break;case ki.Name:if(!this.currentTrack)break;this.currentTrack.name=_i(e,n);break;case ki.Language:if(!this.currentTrack)break;if(this.currentTrack.hasLanguageBcp47)break;this.currentTrack.languageCode=Ei(e,n),L(this.currentTrack.languageCode)||(this.currentTrack.languageCode=R);break;case ki.LanguageBCP47:{if(!this.currentTrack)break;const t=Ei(e,n).split("-")[0];this.currentTrack.languageCode=t||R,this.currentTrack.hasLanguageBcp47=!0}break;case ki.Video:if("video"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case ki.PixelWidth:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.width=Ii(e,n);break;case ki.PixelHeight:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.height=Ii(e,n);break;case ki.DisplayWidth:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.displayWidth=Ii(e,n);break;case ki.DisplayHeight:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.displayHeight=Ii(e,n);break;case ki.DisplayUnit:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.displayUnit=Ii(e,n);break;case ki.AlphaMode:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.alphaMode=1===Ii(e,n);break;case ki.Colour:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.colorSpace={},this.readContiguousElements(e.slice(o,n));break;case ki.MatrixCoefficients:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=Ii(e,n),i=g[t]??null;this.currentTrack.info.colorSpace.matrix=i}break;case ki.Range:if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;this.currentTrack.info.colorSpace.fullRange=2===Ii(e,n);break;case ki.TransferCharacteristics:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=Ii(e,n),i=m[t]??null;this.currentTrack.info.colorSpace.transfer=i}break;case ki.Primaries:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=Ii(e,n),i=h[t]??null;this.currentTrack.info.colorSpace.primaries=i}break;case ki.Projection:if("video"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case ki.ProjectionPoseRoll:{if("video"!==this.currentTrack?.info?.type)break;const t=-Ai(e,n);try{this.currentTrack.info.rotation=r(t)}catch{}}break;case ki.Audio:if("audio"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case ki.SamplingFrequency:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.sampleRate=Ai(e,n);break;case ki.Channels:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.numberOfChannels=Ii(e,n);break;case ki.BitDepth:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.bitDepth=Ii(e,n);break;case ki.CuePoint:if(!this.currentSegment)break;this.readContiguousElements(e.slice(o,n)),this.currentCueTime=null;break;case ki.CueTime:this.currentCueTime=Ii(e,n);break;case ki.CueTrackPositions:{if(null===this.currentCueTime)break;i(this.currentSegment);const t={time:this.currentCueTime,trackId:-1,clusterPosition:-1};this.currentSegment.cuePoints.push(t),this.readContiguousElements(e.slice(o,n)),-1!==t.trackId&&-1!==t.clusterPosition||this.currentSegment.cuePoints.pop()}break;case ki.CueTrack:{const t=this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;t.trackId=Ii(e,n)}break;case ki.CueClusterPosition:{const t=this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;i(this.currentSegment),t.clusterPosition=this.currentSegment.dataStartPos+Ii(e,n)}break;case ki.Timestamp:if(!this.currentCluster)break;this.currentCluster.timestamp=Ii(e,n);break;case ki.SimpleBlock:{if(!this.currentCluster)break;const t=vi(e);if(null===t)break;const i=this.getTrackDataInCluster(this.currentCluster,t);if(!i)break;const r=mn(e),a=un(e),s=a>>1&3;let c=!!(128&a);"audio"===i.track.info?.type&&i.track.info.codec&&(c=!0);const l=ln(e,n-(e.filePos-o)),u=i.track.decodingInstructions.length>0;i.blocks.push({timestamp:r,duration:0,isKeyFrame:c,data:l,lacing:s,decoded:!u,mainAdditional:null})}break;case ki.BlockGroup:if(!this.currentCluster)break;this.readContiguousElements(e.slice(o,n)),this.currentBlock=null;break;case ki.Block:{if(!this.currentCluster)break;const t=vi(e);if(null===t)break;const i=this.getTrackDataInCluster(this.currentCluster,t);if(!i)break;const r=mn(e),a=un(e)>>1&3,s=ln(e,n-(e.filePos-o)),c=i.track.decodingInstructions.length>0;this.currentBlock={timestamp:r,duration:0,isKeyFrame:!0,data:s,lacing:a,decoded:!c,mainAdditional:null},i.blocks.push(this.currentBlock)}break;case ki.BlockAdditions:this.readContiguousElements(e.slice(o,n));break;case ki.BlockMore:if(!this.currentBlock)break;this.currentBlockAdditional={addId:1,data:null},this.readContiguousElements(e.slice(o,n)),this.currentBlockAdditional.data&&1===this.currentBlockAdditional.addId&&(this.currentBlock.mainAdditional=this.currentBlockAdditional.data),this.currentBlockAdditional=null;break;case ki.BlockAdditional:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.data=ln(e,n);break;case ki.BlockAddID:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.addId=Ii(e,n);break;case ki.BlockDuration:if(!this.currentBlock)break;this.currentBlock.duration=Ii(e,n);break;case ki.ReferenceBlock:if(!this.currentBlock)break;this.currentBlock.isKeyFrame=!1;break;case ki.Tag:this.currentTagTargetIsMovie=!0,this.readContiguousElements(e.slice(o,n));break;case ki.Targets:this.readContiguousElements(e.slice(o,n));break;case ki.TargetTypeValue:50!==Ii(e,n)&&(this.currentTagTargetIsMovie=!1);break;case ki.TagTrackUID:case ki.TagEditionUID:case ki.TagChapterUID:case ki.TagAttachmentUID:this.currentTagTargetIsMovie=!1;break;case ki.SimpleTag:if(!this.currentTagTargetIsMovie)break;this.currentSimpleTagName=null,this.readContiguousElements(e.slice(o,n));break;case ki.TagName:this.currentSimpleTagName=_i(e,n);break;case ki.TagString:{if(!this.currentSimpleTagName)break;const t=_i(e,n);this.processTagValue(this.currentSimpleTagName,t)}break;case ki.TagBinary:{if(!this.currentSimpleTagName)break;const t=ln(e,n);this.processTagValue(this.currentSimpleTagName,t)}break;case ki.AttachedFile:{if(!this.currentSegment)break;this.currentAttachedFile={fileUid:null,fileName:null,fileMediaType:null,fileData:null,fileDescription:null},this.readContiguousElements(e.slice(o,n));const t=this.currentSegment.metadataTags;if(this.currentAttachedFile.fileUid&&this.currentAttachedFile.fileData&&(t.raw??(t.raw={}),t.raw[this.currentAttachedFile.fileUid.toString()]=new de(this.currentAttachedFile.fileData,this.currentAttachedFile.fileMediaType??void 0,this.currentAttachedFile.fileName??void 0,this.currentAttachedFile.fileDescription??void 0)),this.currentAttachedFile.fileMediaType?.startsWith("image/")&&this.currentAttachedFile.fileData){const e=this.currentAttachedFile.fileName;let i="unknown";if(e){const t=e.toLowerCase();t.startsWith("cover.")?i="coverFront":t.startsWith("back.")&&(i="coverBack")}t.images??(t.images=[]),t.images.push({data:this.currentAttachedFile.fileData,mimeType:this.currentAttachedFile.fileMediaType,kind:i,name:this.currentAttachedFile.fileName??void 0,description:this.currentAttachedFile.fileDescription??void 0})}this.currentAttachedFile=null}break;case ki.FileUID:if(!this.currentAttachedFile)break;this.currentAttachedFile.fileUid=((e,t)=>{if(t<1)throw new Error("Bad unsigned int size "+t);let i=0n;for(let r=0;rt.order-e.order);break;case ki.ContentEncoding:this.currentDecodingInstruction={order:0,scope:Qi.Block,data:null},this.readContiguousElements(e.slice(o,n)),this.currentDecodingInstruction.data&&this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction),this.currentDecodingInstruction=null;break;case ki.ContentEncodingOrder:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.order=Ii(e,n);break;case ki.ContentEncodingScope:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.scope=Ii(e,n);break;case ki.ContentCompression:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decompress",algorithm:Yi.Zlib,settings:null},this.readContiguousElements(e.slice(o,n));break;case ki.ContentCompAlgo:if("decompress"!==this.currentDecodingInstruction?.data?.type)break;this.currentDecodingInstruction.data.algorithm=Ii(e,n);break;case ki.ContentCompSettings:if("decompress"!==this.currentDecodingInstruction?.data?.type)break;this.currentDecodingInstruction.data.settings=ln(e,n);break;case ki.ContentEncryption:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decrypt"}}return e.filePos=o+n,!0}decodeBlockData(e,t){i(e.decodingInstructions.length>0);let r=t;for(const a of e.decodingInstructions)if(i(a.data),"decompress"===a.data.type)if(a.data.algorithm===Yi.HeaderStripping)if(a.data.settings&&a.data.settings.length>0){const e=a.data.settings,t=new Uint8Array(e.length+r.length);t.set(e,0),t.set(r,e.length),r=t}return r}processTagValue(e,t){var i;if(!this.currentSegment?.metadataTags)return;const r=this.currentSegment.metadataTags;if(r.raw??(r.raw={}),(i=r.raw)[e]??(i[e]=t),"string"===typeof t)switch(e.toLowerCase()){case"title":r.title??(r.title=t);break;case"description":r.description??(r.description=t);break;case"artist":r.artist??(r.artist=t);break;case"album":r.album??(r.album=t);break;case"album_artist":r.albumArtist??(r.albumArtist=t);break;case"genre":r.genre??(r.genre=t);break;case"comment":r.comment??(r.comment=t);break;case"lyrics":r.lyrics??(r.lyrics=t);break;case"date":{const e=new Date(t);Number.isNaN(e.getTime())||(r.date??(r.date=e))}break;case"track_number":case"part_number":{const e=t.split("/"),i=Number.parseInt(e[0],10),a=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(r.trackNumber??(r.trackNumber=i)),a&&Number.isInteger(a)&&a>0&&(r.tracksTotal??(r.tracksTotal=a))}break;case"disc_number":case"disc":{const e=t.split("/"),i=Number.parseInt(e[0],10),a=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(r.discNumber??(r.discNumber=i)),a&&Number.isInteger(a)&&a>0&&(r.discsTotal??(r.discsTotal=a))}}}}class ir{constructor(e){this.internalTrack=e,this.packetToClusterLocation=new WeakMap}getId(){return this.internalTrack.id}getNumber(){const e=this.internalTrack.demuxer,t=this.internalTrack.trackBacking.getType();let i=0;for(const r of e.segments)for(const e of r.tracks)if(e.trackBacking.getType()===t&&i++,e===this.internalTrack)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.codecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.segment.timestampFactor}isRelativeToUnixEpoch(){return!1}getDisposition(){return this.internalTrack.disposition}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){const e=this.internalTrack.segment;if(e.duration<=0)return null;let t=e.duration/e.timestampFactor;const i=await this.getFirstPacket({metadataOnly:!0});return t+=i?.timestamp??0,t}async getLiveRefreshInterval(){return null}async getFirstPacket(e){return this.performClusterLookup(null,e=>e.trackData.get(this.internalTrack.id)?{blockIndex:0,correctBlockFound:!0}:{blockIndex:-1,correctBlockFound:!1},-1/0,1/0,e)}intoTimescale(e){return D(e*this.internalTrack.segment.timestampFactor)}async getPacket(e,t){const i=this.intoTimescale(e);return this.performClusterLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const r=P(t.presentationTimestamps,i,e=>e.timestamp);return{blockIndex:-1!==r?t.presentationTimestamps[r].blockIndex:-1,correctBlockFound:-1!==r&&i{if(e===i.cluster){const t=e.trackData.get(this.internalTrack.id);if(i.blockIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const r=C(t.presentationTimestamps,e=>t.blocks[e.blockIndex].isKeyFrame&&e.timestamp<=i);return{blockIndex:-1!==r?t.presentationTimestamps[r].blockIndex:-1,correctBlockFound:-1!==r&&i{if(e===r.cluster){const t=e.trackData.get(this.internalTrack.id).blocks.findIndex((e,t)=>e.isKeyFrame&&t>r.blockIndex);if(-1!==t)return{blockIndex:t,correctBlockFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.blocks.findIndex(e=>e.isKeyFrame);return i(-1!==e),{blockIndex:e,correctBlockFound:!0}}}return{blockIndex:-1,correctBlockFound:!1}},-1/0,1/0,t)}async fetchPacketInCluster(e,t,r){if(-1===t)return null;const a=e.trackData.get(this.internalTrack.id).blocks[t];i(a),a.decoded||(a.data=this.internalTrack.demuxer.decodeBlockData(this.internalTrack,a.data),a.decoded=!0);const s=r.metadataOnly?Dt:a.data,n=a.timestamp/this.internalTrack.segment.timestampFactor,o=a.duration/this.internalTrack.segment.timestampFactor,c={};a.mainAdditional&&"video"===this.internalTrack.info?.type&&this.internalTrack.info.alphaMode&&(c.alpha=r.metadataOnly?Dt:a.mainAdditional,c.alphaByteLength=a.mainAdditional.byteLength);const l=new Mt(s,a.isKeyFrame?"key":"delta",n,o,e.dataStartPos+t,a.data.byteLength,c);return this.packetToClusterLocation.set(l,{cluster:e,blockIndex:t}),l}async performClusterLookup(e,t,r,a,s){const{demuxer:n,segment:o}=this.internalTrack;let c=null,l=null,u=-1;if(e){const{blockIndex:i,correctBlockFound:r}=t(e);if(r)return this.fetchPacketInCluster(e,i,s);-1!==i&&(l=e,u=i)}const d=P(this.internalTrack.cuePoints,r,e=>e.time),h=-1!==d?this.internalTrack.cuePoints[d]:null,f=P(this.internalTrack.clusterPositionCache,r,e=>e.startTimestamp),m=-1!==f?this.internalTrack.clusterPositionCache[f]:null,p=Math.max(h?.clusterPosition??0,m?.elementStartPos??0)||null;let g;for(e?null===p||e.elementStartPos>=p?(g=e.elementEndPos,c=e):g=p:g=p??o.clusterSeekStartPos;null===o.elementEndPos||g<=o.elementEndPos-2;){if(c){const e=c.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>a)break}let e=n.reader.requestSliceRange(g,2,Si);if(e instanceof Promise&&(e=await e),!e)break;const r=g,d=Bi(e);if(!d||!wi.includes(d.id)&&d.id!==ki.Void){const e=await Ri(n.reader,r,wi,Math.min(o.elementEndPos??1/0,r+er));if(e){g=e;continue}break}const h=d.id;let f=d.size;const m=e.filePos;if(h===ki.Cluster){c=await n.readCluster(r,o),f=c.elementEndPos-m;const{blockIndex:e,correctBlockFound:i}=t(c);if(i)return this.fetchPacketInCluster(c,e,s);-1!==e&&(l=c,u=e)}if(void 0===f){i(h!==ki.Cluster);f=(await Fi(n.reader,m,Ti,o.elementEndPos)).pos-m}const p=m+f;if(null===o.elementEndPos){let e=n.reader.requestSliceRange(p,2,Si);if(e instanceof Promise&&(e=await e),!e)break;if(xi(e)===ki.Segment){o.elementEndPos=p;break}}g=p}if(h&&(!l||l.elementStartPos{let e=null;("vp9"===this.internalTrack.info.codec||"av1"===this.internalTrack.info.codec||"avc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription||"hevc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription)&&(e=await this.getFirstPacket({}));const t={codec:ve({width:this.internalTrack.info.width,height:this.internalTrack.info.height,codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,colorSpace:this.internalTrack.info.colorSpace,avcType:1,avcCodecInfo:"avc"===this.internalTrack.info.codec&&e?Ze(e.data):null,hevcCodecInfo:"hevc"===this.internalTrack.info.codec&&e?nt(e.data):null,vp9CodecInfo:"vp9"===this.internalTrack.info.codec&&e?kt(e.data):null,av1CodecInfo:"av1"===this.internalTrack.info.codec&&e?yt(e.data):null}),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0};return this.internalTrack.info.width===this.internalTrack.info.squarePixelWidth&&this.internalTrack.info.height===this.internalTrack.info.squarePixelHeight||(t.displayAspectWidth=this.internalTrack.info.squarePixelWidth,t.displayAspectHeight=this.internalTrack.info.squarePixelHeight),t})()):null}}class ar extends ir{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getType(){return"audio"}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return this.internalTrack.info.codec?this.decoderConfig??(this.decoderConfig={codec:Ie({codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,aacCodecInfo:this.internalTrack.info.aacCodecInfo}),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}):null}}const sr=async(e,t,i)=>{let r=t;for(;null===i||r=4;){const t=a.filePos,i=gn(a),s=null!==e.fileSize?e.fileSize-r:null,n=Me(i,s);if(n.header)return{header:n.header,startPos:r};a.filePos=t+n.bytesAdvanced,r=a.filePos}}return null};class nr extends Rt{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.firstFrameHeaderPos=null,this.loadedSamples=[],this.metadataTags=null,this.xingData=null,this.trackBackings=[],this.readingMutex=new b,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)await this.advanceReader();if(!this.firstFrameHeader)throw new Error("No valid MP3 frame found.");this.trackBackings=[new or(this)]})())}async advanceReader(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,Fn);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const t=Nn(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}const e=await sr(this.reader,this.lastLoadedPos,this.reader.fileSize);if(!e)return void(this.lastSampleLoaded=!0);const t=e.header;this.lastLoadedPos=e.startPos+t.totalSize-1;const i=De(t.mpegVersionId,t.channel);let r=this.reader.requestSlice(e.startPos+i,4);if(r instanceof Promise&&(r=await r),r){const t=gn(r);if(t===Fe||t===Re){if(!this.xingData){let t=this.reader.requestSlice(e.startPos+i+4,12);if(t instanceof Promise&&(t=await t),t){const e=ln(t,12),i=c(e),r=i.getUint32(0,!1);this.xingData={frameCount:r&Oe.FrameCount?i.getUint32(4,!1):null,fileSize:r&Oe.FileSize?i.getUint32(8,!1):null}}}return}}this.firstFrameHeader||(this.firstFrameHeader=t,this.firstFrameHeaderPos=e.startPos),t.sampleRate!==this.firstFrameHeader.sampleRate&&console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${t.sampleRate} Hz. Might be a bug, so please report this file.`);const a=t.audioSamplesInFrame/this.firstFrameHeader.sampleRate,s={timestamp:this.nextTimestampInSamples/this.firstFrameHeader.sampleRate,duration:a,dataStart:e.startPos,dataSize:t.totalSize};this.loadedSamples.push(s),this.nextTimestampInSamples+=t.audioSamplesInFrame}async getMimeType(){return"audio/mpeg"}async getTrackBackings(){return await this.readMetadata(),this.trackBackings}async getMetadataTags(){const e=await this.readingMutex.acquire();try{if(await this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0,t=!1;for(;;){let i=this.reader.requestSlice(e,Fn);if(i instanceof Promise&&(i=await i),!i)break;const r=Nn(i);if(!r)break;t=!0;let a=this.reader.requestSlice(i.filePos,r.size);if(a instanceof Promise&&(a=await a),!a)break;On(a,r,this.metadataTags),e=i.filePos+r.size}if(!t&&null!==this.reader.fileSize&&this.reader.fileSize>=An){let e=this.reader.requestSlice(this.reader.fileSize-An,An);e instanceof Promise&&(e=await e),i(e);"TAG"===In(e,3)&&Dn(e,this.metadataTags)}return this.metadataTags}finally{e()}}}class or{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getTimeResolution(){return i(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.sampleRate/this.demuxer.firstFrameHeader.audioSamplesInFrame}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){const e=this.demuxer;if(i(null!==e.firstFrameHeader),i(null!==e.firstFrameHeaderPos),e.xingData){if(null!==e.xingData.frameCount)return e.xingData.frameCount*e.firstFrameHeader.audioSamplesInFrame/e.firstFrameHeader.sampleRate}else if(null!==e.reader.fileSize){const i=(t=e.firstFrameHeader.lowSamplingFrequency,r=e.firstFrameHeader.layer,a=e.firstFrameHeader.bitrate,s=e.firstFrameHeader.sampleRate,0===r?0:1===r?144*a/(s<e.timestamp);if(-1===i)throw new Error("Packet was not created from this track.");const r=i+1;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{i()}}async getPacket(e,t){const i=await this.demuxer.readingMutex.acquire();try{for(;;){const i=P(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===i&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(i,t);if(i>=0&&i+1>>0&4294967295}const ur=e=>{const t=c(e),i=t.getUint32(22,!0);t.setUint32(22,0,!0);let r=0;for(let a=0;a>>24^t])>>>0}return t.setUint32(22,i,!0),r},dr=(e,t,r)=>{let a=0,s=null;if(e.length>0)if("vorbis"===t.codec){i(t.vorbisInfo);const n=(1<<(e=>{let t=0;for(;e;)t++,e>>=1;return t})(t.vorbisInfo.modeBlockflags.length-1))-1<<1,o=(e[0]&n)>>1;if(o>=t.vorbisInfo.modeBlockflags.length)throw new Error("Invalid mode number.");let c=r;const l=t.vorbisInfo.modeBlockflags[o];if(s=t.vorbisInfo.blocksizes[l],1===l){const i=1+(1|n),r=e[0]&i?1:0;c=t.vorbisInfo.blocksizes[r]}a=null!==c?c+s>>2:0}else if("opus"===t.codec){a=(e=>{const t=e[0]>>3;return{durationInSamples:wt[t]}})(e).durationInSamples}return{durationInSamples:a,vorbisBlockSize:s}},hr=27,fr=282,mr=e=>{const t=e.filePos;if(kn(e)!==cr)return null;e.skip(1);const i=un(e),r=Sn(e),a=kn(e),s=kn(e),n=kn(e),o=un(e),c=new Uint8Array(o);for(let d=0;de+t,0);return{headerStartPos:t,totalSize:l+u,dataStartPos:t+l,dataSize:u,headerType:i,granulePosition:r,serialNumber:a,sequenceNumber:s,checksum:n,lacingValues:c}},pr=(e,t)=>{for(;e.filePos>>8&255)===i||(t>>>16&255)===i||(t>>>24&255)===i){if(e.skip(-4),t===cr)return!0;e.skip(1)}}return!1};class gr extends Rt{constructor(e){super(e),this.metadataPromise=null,this.bitstreams=[],this.trackBackings=[],this.metadataTags={},this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,hr,fr);if(t instanceof Promise&&(t=await t),!t)break;const i=mr(t);if(!i)break;if(!!!(2&i.headerType))break;this.bitstreams.push({serialNumber:i.serialNumber,bosPage:i,description:null,numberOfChannels:-1,sampleRate:-1,codecInfo:{codec:null,vorbisInfo:null,opusInfo:null},lastMetadataPacket:null}),e=i.headerStartPos+i.totalSize}for(const t of this.bitstreams){const e=await this.readPacket(t.bosPage,0);e&&(e.data.byteLength>=7&&1===e.data[0]&&118===e.data[1]&&111===e.data[2]&&114===e.data[3]&&98===e.data[4]&&105===e.data[5]&&115===e.data[6]?await this.readVorbisMetadata(e,t):e.data.byteLength>=8&&79===e.data[0]&&112===e.data[1]&&117===e.data[2]&&115===e.data[3]&&72===e.data[4]&&101===e.data[5]&&97===e.data[6]&&100===e.data[7]&&await this.readOpusMetadata(e,t),null!==t.codecInfo.codec&&this.trackBackings.push(new kr(t,this)))}})())}async readVorbisMetadata(e,t){let i=await this.findNextPacketStart(e);if(!i)return;const r=await this.readPacket(i.startPage,i.startSegmentIndex);if(!r)return;if(i=await this.findNextPacketStart(r),!i)return;const a=await this.readPacket(i.startPage,i.startSegmentIndex);if(!a)return;if(3!==r.data[0]||5!==a.data[0])return;const s=[],n=e=>{for(;s.push(Math.min(255,e)),!(e<255);)e-=255};n(e.data.length),n(r.data.length);const o=new Uint8Array(1+s.length+e.data.length+r.data.length+a.data.length);o[0]=2,o.set(s,1),o.set(e.data,1+s.length),o.set(r.data,1+s.length+e.data.length),o.set(a.data,1+s.length+e.data.length+r.data.length),t.codecInfo.codec="vorbis",t.description=o,t.lastMetadataPacket=a;const l=c(e.data);t.numberOfChannels=l.getUint8(11),t.sampleRate=l.getUint32(12,!0);const u=l.getUint8(28);t.codecInfo.vorbisInfo={blocksizes:[1<<(15&u),1<<(u>>4)],modeBlockflags:Tt(a.data).modeBlockflags},It(r.data.subarray(7),this.metadataTags)}async readOpusMetadata(e,t){const i=await this.findNextPacketStart(e);if(!i)return;const r=await this.readPacket(i.startPage,i.startSegmentIndex);if(!r)return;t.codecInfo.codec="opus",t.description=e.data,t.lastMetadataPacket=r;const a=(e=>{const t=c(e),i=t.getUint8(9),r=t.getUint16(10,!0),a=t.getUint32(12,!0),s=t.getInt16(16,!0),n=t.getUint8(18);let o=null;return n&&(o=e.subarray(19,21+i)),{outputChannelCount:i,preSkip:r,inputSampleRate:a,outputGain:s,channelMappingFamily:n,channelMappingTable:o}})(e.data);t.numberOfChannels=a.outputChannelCount,t.sampleRate=xe,t.codecInfo.opusInfo={preSkip:a.preSkip},It(r.data.subarray(8),this.metadataTags)}async readPacket(e,t){i(te+t.length,0);if(0===c)return null;const l=new Uint8Array(c);let u=0;for(let i=0;i{let t="audio/ogg";e.codecStrings&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({codecStrings:(await Promise.all(this.trackBackings.map(e=>e.getDecoderConfig().then(e=>e?.codec??null)))).filter(Boolean)})}async getTrackBackings(){return await this.readMetadata(),this.trackBackings}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}}class kr{constructor(e,t){this.bitstream=e,this.demuxer=t,this.encodedPacketToMetadata=new WeakMap,this.sequentialScanCache=[],this.sequentialScanMutex=new b,this.internalSampleRate="opus"===e.codecInfo.codec?xe:e.sampleRate}getType(){return"audio"}getId(){return this.bitstream.serialNumber}getNumber(){const e=this.demuxer.trackBackings.findIndex(e=>e.bitstream===this.bitstream);return i(-1!==e),e+1}getNumberOfChannels(){return this.bitstream.numberOfChannels}getSampleRate(){return this.bitstream.sampleRate}getTimeResolution(){return this.bitstream.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return null}async getLiveRefreshInterval(){return null}getCodec(){return this.bitstream.codecInfo.codec}getInternalCodecId(){return null}async getDecoderConfig(){return i(this.bitstream.codecInfo.codec),{codec:this.bitstream.codecInfo.codec,numberOfChannels:this.bitstream.numberOfChannels,sampleRate:this.bitstream.sampleRate,description:this.bitstream.description??void 0}}getName(){return null}getLanguageCode(){return R}getDisposition(){return{...he,primary:!1}}granulePositionToTimestampInSamples(e){return"opus"===this.bitstream.codecInfo.codec?(i(this.bitstream.codecInfo.opusInfo),e-this.bitstream.codecInfo.opusInfo.preSkip):e}createEncodedPacketFromOggPacket(e,t,i){if(!e)return null;const{durationInSamples:r,vorbisBlockSize:a}=dr(e.data,this.bitstream.codecInfo,t.vorbisLastBlocksize),s=new Mt(i.metadataOnly?Dt:e.data,"key",Math.max(0,t.timestampInSamples)/this.internalSampleRate,r/this.internalSampleRate,e.endPage.headerStartPos+e.endSegmentIndex,e.data.byteLength);return this.encodedPacketToMetadata.set(s,{packet:e,timestampInSamples:t.timestampInSamples,durationInSamples:r,vorbisLastBlockSize:t.vorbisLastBlocksize,vorbisBlockSize:a}),s}async getFirstPacket(e){i(this.bitstream.lastMetadataPacket);const t=await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!t)return null;let r=0;"opus"===this.bitstream.codecInfo.codec&&(i(this.bitstream.codecInfo.opusInfo),r-=this.bitstream.codecInfo.opusInfo.preSkip);const a=await this.demuxer.readPacket(t.startPage,t.startSegmentIndex);return this.createEncodedPacketFromOggPacket(a,{timestampInSamples:r,vorbisLastBlocksize:null},e)}async getNextPacket(e,t){const i=this.encodedPacketToMetadata.get(e);if(!i)throw new Error("Packet was not created from this track.");const r=await this.demuxer.findNextPacketStart(i.packet);if(!r)return null;const a=i.timestampInSamples+i.durationInSamples,s=await this.demuxer.readPacket(r.startPage,r.startSegmentIndex);return this.createEncodedPacketFromOggPacket(s,{timestampInSamples:a,vorbisLastBlocksize:i.vorbisBlockSize},t)}async getPacket(e,t){if(null===this.demuxer.reader.fileSize)return this.getPacketSequential(e,t);const r=D(e*this.internalSampleRate);if(0===r)return this.getFirstPacket(t);if(r<0)return null;i(this.bitstream.lastMetadataPacket);const a=await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!a)return null;let s=a.startPage,n=this.demuxer.reader.fileSize;const o=[s];e:for(;s.headerStartPos+s.totalSizer?n=u.headerStartPos:(s=u,o.push(u));continue e}a=u.headerStartPos+u.totalSize}}let c=a.startPage;for(const i of o){if(i.granulePosition===s.granulePosition)break;(!c||i.headerStartPos>c.headerStartPos)&&(c=i)}let l=c;const u=[l];for(;l.serialNumber!==this.bitstream.serialNumber||l.granulePosition!==s.granulePosition;){const e=l.headerStartPos+l.totalSize;let t=this.demuxer.reader.requestSliceRange(e,hr,fr);t instanceof Promise&&(t=await t),i(t);const r=mr(t);i(r),l=r,l.serialNumber===this.bitstream.serialNumber&&u.push(l)}i(-1!==l.granulePosition);let d,h,f=null,m=l,p=0;if(l.headerStartPos===a.startPage.headerStartPos)d=this.granulePositionToTimestampInSamples(0),h=!0,f=0;else{d=0,h=!1;for(let t=l.lacingValues.length-1;t>=0;t--){if(l.lacingValues[t]<255){f=t+1;break}}if(null===f)throw new Error("Invalid page with granule position: no packets end on this page.");p=f-1;const e={data:Dt,endPage:m,endSegmentIndex:p};if(await this.demuxer.findNextPacketStart(e)){const e=yr(u,l,f);i(e);const t=br(u,e.page,e.segmentIndex);t&&(l=t.page,f=t.segmentIndex)}else for(;;){const e=yr(u,l,f);if(!e)break;const t=br(u,e.page,e.segmentIndex);if(!t)break;if(l=t.page,f=t.segmentIndex,e.page.headerStartPos!==m.headerStartPos){m=e.page,p=e.segmentIndex;break}}}let g=null,k=null;for(;null!==l;){i(null!==f);const e=await this.demuxer.readPacket(l,f);if(!e)break;if(!(l.headerStartPos===a.startPage.headerStartPos&&fr||Math.max(s.timestampInSamples,0)===r))break}const s=await this.demuxer.findNextPacketStart(e);if(!s)break;l=s.startPage,f=s.startSegmentIndex}return g}async getPacketSequential(e,t){const r=await this.sequentialScanMutex.acquire();try{const r=D(e*this.internalSampleRate);e=r/this.internalSampleRate;const s=P(this.sequentialScanCache,r,e=>e.timestampInSamples);let n;if(-1!==s){const e=this.sequentialScanCache[s];n=this.createEncodedPacketFromOggPacket(e.packet,{timestampInSamples:e.timestampInSamples,vorbisLastBlocksize:e.vorbisLastBlockSize},t)}else n=await this.getFirstPacket(t);let o=0;for(;n&&n.timestampe)break;if(n=r,o++,100===o){o=0;const e=this.encodedPacketToMetadata.get(n);i(e),this.sequentialScanCache.length>0&&i(a(this.sequentialScanCache).timestampInSamples<=e.timestampInSamples),this.sequentialScanCache.push(e)}}return n}finally{r()}}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const br=(e,t,r)=>{let a=t,s=r;e:for(;;){for(s--;s>=0;s--){if(a.lacingValues[s]<255){s++;break e}}i(-1===s);if(!(1&a.headerType)){s=0;break}const t=x(e,e=>e.headerStartPos{if(i>0)return{page:t,segmentIndex:i-1};const r=x(e,e=>e.headerStartPos{let e=this.reader.requestSlice(0,12);e instanceof Promise&&(e=await e),i(e);const t=In(e,4),r="RIFX"!==t,a="RF64"===t,s=pn(e,r);let n=a?this.reader.fileSize:Math.min(s+8,this.reader.fileSize??1/0);if("WAVE"!==In(e,4))throw new Error("Invalid WAVE file - wrong format");let o=0,c=null,l=e.filePos;for(;null===n||l=18&&357!==a){const e=dn(r,i),s=t-18;if(Math.min(s,e)>=22&&a===wr.EXTENSIBLE){r.skip(6);const e=ln(r,16);a=e[0]|e[1]<<8}}a!==wr.MULAW&&a!==wr.ALAW||(c=8),this.audioInfo={format:a,numberOfChannels:s,sampleRate:n,sampleSizeInBytes:Math.ceil(c/8),blockSizeInBytes:o}}async parseListChunk(e,t,i){var r,a,s,n,o,c,l,u,d,h,f;let m=this.reader.requestSlice(e,t);if(m instanceof Promise&&(m=await m),!m)return;const p=In(m,4);if("INFO"!==p&&"INF0"!==p)return;let g=m.filePos;for(;g<=e+t-8;){m.filePos=g;const e=In(m,4),t=pn(m,i),p=ln(m,t);let k=0;for(let i=0;i0&&((c=this.metadataTags).trackNumber??(c.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&((l=this.metadataTags).tracksTotal??(l.tracksTotal=i))}break;case"ICRD":case"IDIT":{const e=new Date(b);Number.isNaN(e.getTime())||((u=this.metadataTags).date??(u.date=e))}break;case"YEAR":{const e=Number.parseInt(b,10);Number.isInteger(e)&&e>0&&((d=this.metadataTags).date??(d.date=new Date(e,0,1)))}break;case"IGNR":case"GENR":(h=this.metadataTags).genre??(h.genre=b);break;case"ICMT":case"CMNT":case"COMM":(f=this.metadataTags).comment??(f.comment=b)}g+=8+t+(1&t)}}async parseId3Chunk(e,t){let i=this.reader.requestSlice(e,t);if(i instanceof Promise&&(i=await i),!i)return;const r=Nn(i);if(r){const a=t-Fn;if(r.size=Math.min(r.size,a),r.size>0){const t=i.slice(e+Fn,r.size);On(t,r,this.metadataTags)}}}getCodec(){if(i(this.audioInfo),this.audioInfo.format===wr.MULAW)return"ulaw";if(this.audioInfo.format===wr.ALAW)return"alaw";if(this.audioInfo.format===wr.PCM){if(1===this.audioInfo.sampleSizeInBytes)return"pcm-u8";if(2===this.audioInfo.sampleSizeInBytes)return"pcm-s16";if(3===this.audioInfo.sampleSizeInBytes)return"pcm-s24";if(4===this.audioInfo.sampleSizeInBytes)return"pcm-s32"}return this.audioInfo.format===wr.IEEE_FLOAT&&4===this.audioInfo.sampleSizeInBytes?"pcm-f32":null}async getMimeType(){return"audio/wav"}async getTrackBackings(){return await this.readMetadata(),this.trackBackings}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}}const Pr=2048;class vr{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getCodec(){return this.demuxer.getCodec()}getInternalCodecId(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.format}async getDecoderConfig(){const e=this.demuxer.getCodec();return e?(i(this.demuxer.audioInfo),{codec:e,numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate}):null}getNumberOfChannels(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getTimeResolution(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return i(-1!==this.demuxer.dataSize),this.demuxer.dataSize/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate}async getLiveRefreshInterval(){return null}getName(){return null}getLanguageCode(){return R}getDisposition(){return{...he}}async getPacketAtIndex(e,t){i(e>=0),i(this.demuxer.audioInfo);const r=e*Pr*this.demuxer.audioInfo.blockSizeInBytes;if(r>=this.demuxer.dataSize)return null;const a=Math.min(Pr*this.demuxer.audioInfo.blockSizeInBytes,this.demuxer.dataSize-r);if(null===this.demuxer.reader.fileSize){let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+r,a);if(e instanceof Promise&&(e=await e),!e)return null}let s;if(t.metadataOnly)s=Dt;else{let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+r,a);e instanceof Promise&&(e=await e),i(e),s=ln(e,a)}const n=e*Pr/this.demuxer.audioInfo.sampleRate,o=a/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate;return this.demuxer.lastKnownPacketIndex=Math.max(e,this.demuxer.lastKnownPacketIndex),new Mt(s,"key",n,o,e,a)}getFirstPacket(e){return this.getPacketAtIndex(0,e)}async getPacket(e,t){i(this.demuxer.audioInfo);const r=Math.floor(Math.min(e*this.demuxer.audioInfo.sampleRate/Pr,(this.demuxer.dataSize-1)/(Pr*this.demuxer.audioInfo.blockSizeInBytes)));if(r<0)return null;const a=await this.getPacketAtIndex(r,t);if(a)return a;if(0===r)return null;i(null===this.demuxer.reader.fileSize);let s=await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex,t);for(;s;){const e=await this.getNextPacket(s,t);if(!e)break;s=e}return s}getNextPacket(e,t){i(this.demuxer.audioInfo);const r=Math.round(e.timestamp*this.demuxer.audioInfo.sampleRate/Pr);return this.getPacketAtIndex(r+1,t)}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Ir=e=>{const t=e.filePos,i=ln(e,9),r=new fe(i);if(4095!==r.readBits(12))return null;r.skipBits(1);if(0!==r.readBits(2))return null;const a=r.readBits(1),s=r.readBits(2)+1,n=r.readBits(4);if(15===n)return null;r.skipBits(1);const o=r.readBits(3);if(0===o)throw new Error("ADTS frames with channel configuration 0 are not supported.");r.skipBits(1),r.skipBits(1),r.skipBits(1),r.skipBits(1);const c=r.readBits(13);r.skipBits(11);const l=r.readBits(2)+1;if(1!==l)throw new Error("ADTS frames with more than one AAC frame are not supported.");let u=null;return 1===a?e.filePos-=2:u=r.readBits(16),{objectType:s,samplingFrequencyIndex:n,channelConfiguration:o,frameLength:c,numberOfAacFrames:l,crcCheck:u,startPos:t}},xr=1024;class Cr extends Rt{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.loadedSamples=[],this.metadataTags=null,this.trackBackings=[],this.readingMutex=new b,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)await this.advanceReader();i(this.firstFrameHeader),this.trackBackings=[new Br(this)]})())}async advanceReader(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,Fn);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const t=Nn(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}let e=this.reader.requestSliceRange(this.lastLoadedPos,7,9);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const t=Ir(e);if(!t)return void(this.lastSampleLoaded=!0);if(null!==this.reader.fileSize&&t.startPos+t.frameLength>this.reader.fileSize)return void(this.lastSampleLoaded=!0);this.firstFrameHeader||(this.firstFrameHeader=t);const r=me[t.samplingFrequencyIndex];i(void 0!==r);const a=xr/r,s={timestamp:this.nextTimestampInSamples/r,duration:a,dataStart:t.startPos,dataSize:t.frameLength};this.loadedSamples.push(s),this.nextTimestampInSamples+=xr,this.lastLoadedPos=t.startPos+t.frameLength}async getMimeType(){return"audio/aac"}async getTrackBackings(){return await this.readMetadata(),this.trackBackings}async getMetadataTags(){const e=await this.readingMutex.acquire();try{if(await this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0;for(;;){let t=this.reader.requestSlice(e,Fn);if(t instanceof Promise&&(t=await t),!t)break;const i=Nn(t);if(!i)break;let r=this.reader.requestSlice(t.filePos,i.size);if(r instanceof Promise&&(r=await r),!r)break;On(r,i,this.metadataTags),e=t.filePos+i.size}return this.metadataTags}finally{e()}}}class Br{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getTimeResolution(){return this.getSampleRate()/xr}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return null}async getLiveRefreshInterval(){return null}getName(){return null}getLanguageCode(){return R}getCodec(){return"aac"}getInternalCodecId(){return i(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.objectType}getNumberOfChannels(){i(this.demuxer.firstFrameHeader);const e=pe[this.demuxer.firstFrameHeader.channelConfiguration];return i(void 0!==e),e}getSampleRate(){i(this.demuxer.firstFrameHeader);const e=me[this.demuxer.firstFrameHeader.samplingFrequencyIndex];return i(void 0!==e),e}getDisposition(){return{...he}}async getDecoderConfig(){return i(this.demuxer.firstFrameHeader),{codec:`mp4a.40.${this.demuxer.firstFrameHeader.objectType}`,numberOfChannels:this.getNumberOfChannels(),sampleRate:this.getSampleRate()}}async getPacketAtIndex(e,t){if(-1===e)return null;const i=this.demuxer.loadedSamples[e];if(!i)return null;let r;if(t.metadataOnly)r=Dt;else{let e=this.demuxer.reader.requestSlice(i.dataStart,i.dataSize);if(e instanceof Promise&&(e=await e),!e)return null;r=ln(e,i.dataSize)}return new Mt(r,"key",i.timestamp,i.duration,e,i.dataSize)}getFirstPacket(e){return this.getPacketAtIndex(0,e)}async getNextPacket(e,t){const i=await this.demuxer.readingMutex.acquire();try{const i=S(this.demuxer.loadedSamples,e.timestamp,e=>e.timestamp);if(-1===i)throw new Error("Packet was not created from this track.");const r=i+1;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{i()}}async getPacket(e,t){const i=await this.demuxer.readingMutex.acquire();try{for(;;){const i=P(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===i&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(i,t);if(i>=0&&i+1{for(var t;null===this.reader.fileSize||en.end-6)return{num:o.num,blockSize:o.blockSize,sampleRate:o.sampleRate,size:n.end-e,isLastFrame:!0};if(255===un(n)){const t=n.filePos;if(un(n)!==(1===this.blockingBit?249:248)){n.filePos=t;continue}n.skip(-2);const i=n.filePos-e,r=this.readFlacFrameHeader({slice:n,isFirstPacket:!1});if(!r){n.filePos=t;continue}if(0===this.blockingBit){if(r.num-o.num!==1){n.filePos=t;continue}}else if(r.num-o.num!==o.blockSize){n.filePos=t;continue}return{num:o.num,blockSize:o.blockSize,sampleRate:o.sampleRate,size:i,isLastFrame:!1}}}}readFlacFrameHeader({slice:e,isFirstPacket:t}){const r=e.filePos,a=ln(e,4),s=new fe(a);if(32764!==s.readBits(15))return null;if(null===this.blockingBit){i(t);const e=s.readBits(1);this.blockingBit=e}else if(1===this.blockingBit){i(!t);if(1!==s.readBits(1))return null}else{if(0!==this.blockingBit)throw new Error("Invalid blocking bit");i(!t);if(0!==s.readBits(1))return null}const n=(e=>0===e?null:1===e?192:e>=2&&e<=5?144*2**e:6===e?"uncommon-u8":7===e?"uncommon-u16":e>=8&&e<=15?2**e:null)(s.readBits(4));if(!n)return null;i(this.audioInfo);const o=((e,t)=>{switch(e){case 0:return t;case 1:return 88200;case 2:return 176400;case 3:return 192e3;case 4:return 8e3;case 5:return 16e3;case 6:return 22050;case 7:return 24e3;case 8:return 32e3;case 9:return 44100;case 10:return 48e3;case 11:return 96e3;case 12:return"uncommon-u8";case 13:return"uncommon-u16";case 14:return"uncommon-u16-10";default:return null}})(s.readBits(4),this.audioInfo.sampleRate);if(!o)return null;s.readBits(4),s.readBits(3);if(0!==s.readBits(1))return null;const c=(e=>{let t=0;const i=new fe(ln(e,1));for(;1===i.readBits(1);)t++;if(0===t)return i.readBits(7);const r=[],a=t-1,s=new fe(ln(e,a)),n=8-t-1;for(let o=0;oe|t<"uncommon-u16"===t?hn(e)+1:"uncommon-u8"===t?un(e)+1:"number"===typeof t?t:(B(t),void i(!1)))(e,n),u=((e,t)=>"uncommon-u16"===t?hn(e):"uncommon-u16-10"===t?10*hn(e):"uncommon-u8"===t?un(e):"number"===typeof t?t:null)(e,o);if(null===u)return null;if(u!==this.audioInfo.sampleRate)return null;const d=e.filePos-r,h=un(e);e.skip(-d),e.skip(-1);const f=(e=>{let t=0;for(const i of e){t^=i;for(let e=0;e<8;e++)0!==(128&t)?t=t<<1^7:t<<=1,t&=255}return t})(ln(e,d));return h!==f?null:{num:c,blockSize:l,sampleRate:u}}async advanceReader(){await this.readMetadata(),i(null!==this.lastLoadedPos),i(this.audioInfo);const e=this.lastLoadedPos,t=await this.readNextFlacFrame({startPos:e,isFirstPacket:0===this.loadedSamples.length});if(!t)return void(this.lastSampleLoaded=!0);const r=this.loadedSamples[this.loadedSamples.length-1],a={blockOffset:r?r.blockOffset+r.blockSize:0,blockSize:t.blockSize,byteOffset:e,byteSize:t.size};this.lastLoadedPos=this.lastLoadedPos+t.size,this.loadedSamples.push(a),t.isLastFrame&&(this.lastSampleLoaded=!0)}}class _r{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getCodec(){return"flac"}getInternalCodecId(){return null}getNumberOfChannels(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return R}getTimeResolution(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return i(this.demuxer.audioInfo),0===this.demuxer.audioInfo.totalSamples?null:this.demuxer.audioInfo.totalSamples/this.demuxer.audioInfo.sampleRate}async getLiveRefreshInterval(){return null}getDisposition(){return{...he}}async getDecoderConfig(){return i(this.demuxer.audioInfo),{codec:"flac",numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate,description:this.demuxer.audioInfo.description}}async getPacket(e,t){if(i(this.demuxer.audioInfo),e<0)throw new Error("Timestamp cannot be negative");const r=await this.demuxer.readingMutex.acquire();try{for(;;){const i=P(this.demuxer.loadedSamples,e,e=>e.blockOffset/this.demuxer.audioInfo.sampleRate);if(-1===i){await this.demuxer.advanceReader();continue}const r=this.demuxer.loadedSamples[i],a=r.blockOffset/this.demuxer.audioInfo.sampleRate;if(!(a+r.blockSize/this.demuxer.audioInfo.sampleRate<=e))return this.getPacketAtIndex(i,t);if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(this.demuxer.loadedSamples.length-1,t);await this.demuxer.advanceReader()}}finally{r()}}async getNextPacket(e,t){const i=await this.demuxer.readingMutex.acquire();try{const i=e.sequenceNumber+1;if(this.demuxer.lastSampleLoaded&&i>=this.demuxer.loadedSamples.length)return null;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{i()}}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}async getPacketAtIndex(e,t){const r=this.demuxer.loadedSamples[e];if(!r)return null;let a;if(t.metadataOnly)a=Dt;else{let e=this.demuxer.reader.requestSlice(r.byteOffset,r.byteSize);if(e instanceof Promise&&(e=await e),!e)return null;a=ln(e,r.byteSize)}i(this.demuxer.audioInfo);const s=r.blockOffset/this.demuxer.audioInfo.sampleRate,n=r.blockSize/this.demuxer.audioInfo.sampleRate;return new Mt(a,"key",s,n,e,r.byteSize)}async getFirstPacket(e){for(;0===this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(0,e)}}const Ar=9e4,Fr=188,Rr="PES packet is missing PTS where it was expected. PES packets without PTS are not currently supported. If you think this file should be supported, please report it.",Dr=new Set;class Mr extends Rt{constructor(e){super(e),this.metadataPromise=null,this.elementaryStreams=[],this.trackBackingEntries=[],this.packetOffset=0,this.packetStride=-1,this.sectionEndPositions=[],this.seekChunkSize=5242880,this.minReferencePointByteDistance=-1,this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=this.reader.requestSlice(0,205);e instanceof Promise&&(e=await e),i(e);const t=ln(e,205);if(71===t[0]&&71===t[188])this.packetOffset=0,this.packetStride=Fr;else if(71===t[0]&&71===t[204])this.packetOffset=0,this.packetStride=204;else{if(71!==t[4]||71!==t[196])throw new Error("Unreachable.");this.packetOffset=4,this.packetStride=192}this.minReferencePointByteDistance=256*this.packetStride;let r=this.packetOffset,a=null,s=!1,n=!1;for(;;){const e=await this.readPacketHeader(r);if(!e)break;if(0===e.payloadUnitStartIndicator){r+=this.packetStride;continue}const t=await this.readSection(r,!0,!n);if(!t)break;const o=3,c=32;let l=!1;if(!n&&0!==t.pid){if(!(0===t.payload[0]&&0===t.payload[1]&&1===t.payload[2])){const e=new fe(t.payload),i=e.readAlignedByte();e.skipBits(8*i);l=2===e.readBits(8)}}if(0!==t.pid||s)if(t.pid!==a&&!l||n){const e=this.elementaryStreams.find(e=>e.pid===t.pid);e:if(e&&!e.initialized){const r=Or(t,!0);if(!r)throw new Error(`Couldn't read first PES packet for Elementary Stream with PID ${e.pid}`);if(e.firstSection=t,e.canBeTrustedWithKeyPackets=1===t.randomAccessIndicator,this.input._initInput){const i=(await this.input._initInput._getDemuxer()).elementaryStreams.find(i=>i.pid===t.pid&&i.info.codec===e.info.codec);if(i){e.info=i.info,e.initialized=!0;break e}}const a=new Wr(e,r);if("video"===e.info.type){for(;;){if(a.suppliedPacket=null,await a.markNextPacket(),"avc"===e.info.codec){if(!a.suppliedPacket)throw new Error("Invalid AVC video stream; could not extract AVCDecoderConfigurationRecord from any packet.");if(e.info.avcCodecInfo=Ze(a.suppliedPacket.data),!e.info.avcCodecInfo)continue;const t=e.info.avcCodecInfo.sequenceParameterSets[0];i(t);const r=tt(t);e.info.width=r.displayWidth,e.info.height=r.displayHeight;const s=r.pixelAspectRatio.num,n=r.pixelAspectRatio.den;s>0&&n>0&&(s>n?(e.info.squarePixelWidth=Math.round(e.info.width*s/n),e.info.squarePixelHeight=e.info.height):(e.info.squarePixelWidth=e.info.width,e.info.squarePixelHeight=Math.round(e.info.height*n/s))),e.info.colorSpace={primaries:h[r.colourPrimaries],transfer:m[r.transferCharacteristics],matrix:g[r.matrixCoefficients],fullRange:!!r.fullRangeFlag},e.info.reorderSize=r.maxDecFrameBuffering;break}if("hevc"===e.info.codec){if(!a.suppliedPacket)throw new Error("Invalid HEVC video stream; could not extract HVCDecoderConfigurationRecord from first packet.");if(e.info.hevcCodecInfo=nt(a.suppliedPacket.data),!e.info.hevcCodecInfo)continue;const t=e.info.hevcCodecInfo.arrays.find(e=>e.nalUnitType===Ve.SPS_NUT).nalUnits[0];i(t);const r=st(t);e.info.width=r.displayWidth,e.info.height=r.displayHeight,r.pixelAspectRatio.num>r.pixelAspectRatio.den?(e.info.squarePixelWidth=Math.round(e.info.width*r.pixelAspectRatio.num/r.pixelAspectRatio.den),e.info.squarePixelHeight=e.info.height):(e.info.squarePixelWidth=e.info.width,e.info.squarePixelHeight=Math.round(e.info.height*r.pixelAspectRatio.den/r.pixelAspectRatio.num)),e.info.colorSpace={primaries:h[r.colourPrimaries],transfer:m[r.transferCharacteristics],matrix:g[r.matrixCoefficients],fullRange:!!r.fullRangeFlag},e.info.reorderSize=r.maxDecFrameBuffering;break}throw new Error("Unhandled.")}e.info.decoderConfig={codec:ve({width:e.info.width,height:e.info.height,codec:e.info.codec,codecDescription:null,colorSpace:e.info.colorSpace,avcType:1,avcCodecInfo:e.info.avcCodecInfo,hevcCodecInfo:e.info.hevcCodecInfo,vp9CodecInfo:null,av1CodecInfo:null}),codedWidth:e.info.width,codedHeight:e.info.height,colorSpace:e.info.colorSpace},e.info.width===e.info.squarePixelWidth&&e.info.height===e.info.squarePixelHeight||(e.info.decoderConfig.displayAspectWidth=e.info.squarePixelWidth,e.info.decoderConfig.displayAspectHeight=e.info.squarePixelHeight),e.initialized=!0}else{if(await a.markNextPacket(),!a.suppliedPacket)throw new Error(`Couldn't parse first media packet for Elementary Stream with PID ${e.pid}`);if("aac"===e.info.codec){const t=on.tempFromBytes(a.suppliedPacket.data),i=Ir(t);if(!i)throw new Error("Invalid AAC audio stream; could not read ADTS frame header from first packet.");e.info.aacCodecInfo={isMpeg2:!1,objectType:i.objectType},e.info.numberOfChannels=pe[i.channelConfiguration],e.info.sampleRate=me[i.samplingFrequencyIndex]}else if("mp3"===e.info.codec){const t=gn(on.tempFromBytes(a.suppliedPacket.data)),i=Me(t,a.suppliedPacket.data.byteLength);if(!i.header)throw new Error("Invalid MP3 audio stream; could not read frame header from first packet.");e.info.numberOfChannels=3===i.header.channel?1:2,e.info.sampleRate=i.header.sampleRate}else if("ac3"===e.info.codec){const t=Ct(a.suppliedPacket.data);if(!t)throw new Error("Invalid AC-3 audio stream; could not read sync frame from first packet.");if(3===t.fscod)throw new Error("Invalid AC-3 audio stream; reserved sample rate code found in first packet.");e.info.numberOfChannels=xt[t.acmod]+t.lfeon,e.info.sampleRate=ze[t.fscod]}else{if("eac3"!==e.info.codec)throw new Error("Unhandled.");{const t=_t(a.suppliedPacket.data);if(!t)throw new Error("Invalid E-AC-3 audio stream; could not read sync frame from first packet.");const i=At(t);if(null===i)throw new Error("Invalid E-AC-3 audio stream; reserved sample rate code found in first packet.");e.info.numberOfChannels=Ft(t),e.info.sampleRate=i}}e.info.decoderConfig={codec:Ie({codec:e.info.codec,codecDescription:null,aacCodecInfo:e.info.aacCodecInfo}),numberOfChannels:e.info.numberOfChannels,sampleRate:e.info.sampleRate},e.initialized=!0}}}else{const e=new fe(t.payload),i=e.readAlignedByte();e.skipBits(8*i),e.skipBits(12);const r=e.readBits(12);e.skipBits(43),e.readBits(13),e.skipBits(6);const a=e.readBits(10);for(e.skipBits(8*a);8*(r+o)-e.pos>c;){const t=e.readBits(8);e.skipBits(3);const i=e.readBits(13);e.skipBits(6);const r=e.readBits(10),a=e.pos+8*r;let s=!1,n=!1;for(;e.posc;){const t=e.readBits(16);e.skipBits(3);const i=e.readBits(13);if(0!==t){if(null!==a)throw new Error("Only files with a single program are supported.");a=i}}if(null===a)throw new Error("Program Association Table must link to a Program Map Table.");s=!0}if(n&&this.elementaryStreams.every(e=>e.initialized))break;r+=this.packetStride}if(!n){if(!s)throw new Error("No Program Association Table found in the file.");throw new Error("No Program Map Table found in the file.")}for(const i of this.elementaryStreams)"video"===i.info.type?this.trackBackingEntries.push(new zr(i)):this.trackBackingEntries.push(new Ur(i))})())}async getTrackBackings(){return await this.readMetadata(),this.trackBackingEntries}async getMetadataTags(){return{}}async getMimeType(){await this.readMetadata();return(e=>{let t="video/MP2T";const i=[...new Set(e.filter(Boolean))];return i.length>0&&(t+=`; codecs="${i.join(", ")}"`),t})(await Promise.all(this.trackBackingEntries.map(e=>e.getDecoderConfig().then(e=>e?.codec??null))))}async readSection(e,t,i=!1){let r=e,a=e;const s=[];let n,o=0,c=null,l=!0,u=0;for(;;){const e=await this.readPacket(a);if(a+=this.packetStride,!e)break;if(c){if(e.pid!==c.pid){if(i)break;continue}if(1===e.payloadUnitStartIndicator)break}else{if(0===e.payloadUnitStartIndicator)break;c=e}const n=!!(2&e.adaptationFieldControl),d=!!(1&e.adaptationFieldControl);let h=0;if(n&&(h=1+e.body[0],e===c&&h>1&&(u=e.body[1]>>6&1)),d&&(0===h?(s.push(e.body),o+=e.body.byteLength):(s.push(e.body.subarray(h)),o+=e.body.byteLength-h)),r=a,!t&&o>=64){l=!1;break}if(-1!==S(this.sectionEndPositions,r,e=>e)){l=!1;break}}if(l){const e=P(this.sectionEndPositions,r,e=>e);this.sectionEndPositions.splice(e+1,0,r)}if(!c)return null;if(1===s.length)n=s[0];else{const e=s.reduce((e,t)=>e+t.length,0);n=new Uint8Array(e);let t=0;for(const i of s)n.set(i,t),t+=i.length}return{startPos:e,endPos:t?r:null,pid:c.pid,payload:n,randomAccessIndicator:u}}async readPacketHeader(e){let t=this.reader.requestSlice(e,4);if(t instanceof Promise&&(t=await t),!t)return null;if(71!==un(t))throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file.");const i=hn(t);return{payloadUnitStartIndicator:i>>14&1,pid:8191&i,adaptationFieldControl:un(t)>>4&3}}async readPacket(e){let t=this.reader.requestSlice(e,Fr);if(t instanceof Promise&&(t=await t),!t)return null;const i=ln(t,Fr);if(71!==i[0])throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file.");const r=(i[1]<<8)+i[2];return{payloadUnitStartIndicator:r>>14&1,pid:8191&r,adaptationFieldControl:i[3]>>4&3,body:i.subarray(4)}}}const Nr=(e,t)=>{if(e.payload.byteLength<3)return null;const i=new fe(e.payload);if(1!==i.readBits(24))return null;const r=i.readBits(8);if(i.skipBits(16),188===r||190===r||191===r||240===r||241===r||255===r||242===r||248===r)return null;i.skipBits(8);const a=i.readBits(2);i.skipBits(14);let s=null;if(2===a||3===a)s=0,i.skipBits(4),s+=i.readBits(3)*(1<<30),i.skipBits(1),s+=32768*i.readBits(15),i.skipBits(1),s+=i.readBits(15);else if(t)throw new Error(Rr);return{sectionStartPos:e.startPos,sectionEndPos:e.endPos,pts:s,randomAccessIndicator:e.randomAccessIndicator}},Or=(e,t)=>{i(null!==e.endPos);const r=Nr(e,t);if(!r)return null;const a=new fe(e.payload);a.skipBits(32);const s=a.readBits(16);a.skipBits(16);const n=a.readBits(8),o=a.pos+8*n;a.pos=o;const c=o/8;i(Number.isInteger(c));const l=e.payload.subarray(c,s>0?6+s:e.payload.byteLength);return{...r,data:l}};class Lr{constructor(e){this.elementaryStream=e,this.packetBuffers=new WeakMap,this.packetSectionStarts=new WeakMap}getId(){return this.elementaryStream.pid}getNumber(){const e=this.elementaryStream.demuxer,t=this.elementaryStream.info.type;let r=0;for(const a of e.trackBackingEntries)if(a.getType()===t&&r++,i(a instanceof Lr),a.elementaryStream===this.elementaryStream)break;return r}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.elementaryStream.streamType}getName(){return null}getLanguageCode(){return R}getDisposition(){return{...he,primary:!1}}getTimeResolution(){return Ar}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return null}async getLiveRefreshInterval(){return null}createEncodedPacket(e,t,i){let r;return r=this.allPacketsAreKeyPackets()||1===e.randomAccessIndicator?"key":"delta",new Mt(i.metadataOnly?Dt:e.data,r,e.pts/Ar,Math.max(t/Ar,0),e.sequenceNumber,e.data.byteLength)}async getFirstPacket(e){const t=this.elementaryStream.firstSection;i(t);const r=Or(t,!0);i(r);const a=new Wr(this.elementaryStream,r),s=new Vr(this,a),n=await s.readNext();if(!n)return null;const o=this.createEncodedPacket(n.packet,n.duration,e);return this.packetBuffers.set(o,s),this.packetSectionStarts.set(o,n.packet.sectionStartPos),o}async getNextPacket(e,t){let r=this.packetBuffers.get(e);if(r){const i=await r.readNext();if(!i)return null;this.packetBuffers.delete(e);const a=this.createEncodedPacket(i.packet,i.duration,t);return this.packetBuffers.set(a,r),this.packetSectionStarts.set(a,i.packet.sectionStartPos),a}const a=this.packetSectionStarts.get(e);if(void 0===a)throw new Error("Packet was not created from this track.");const s=this.elementaryStream.demuxer,n=await s.readSection(a,!0);i(n);const o=Or(n,!0);i(o);const c=new Wr(this.elementaryStream,o);r=new Vr(this,c);const l=e.sequenceNumber;for(;;){const e=await r.readNext();if(!e)return null;if(e.packet.sequenceNumber>l){const i=this.createEncodedPacket(e.packet,e.duration,t);return this.packetBuffers.set(i,r),this.packetSectionStarts.set(i,e.packet.sectionStartPos),i}}}async getNextKeyPacket(e,t){let i=e;for(;;){if(i=await this.getNextPacket(i,t),!i)return null;if("key"===i.type)return i}}getPacket(e,t){return this.doPacketLookup(e,!1,t)}getKeyPacket(e,t){return this.doPacketLookup(e,!0,t)}async doPacketLookup(e,t,r){const s=D(e*Ar),n=this.elementaryStream.demuxer,{reader:o,seekChunkSize:c}=n,l=this.elementaryStream.pid,u=async(e,t,i)=>{let r=e;for(;re.pts),g=-1!==p?m[p]:null;if(g&&s-g.pts<45e3)f=g.sectionStartPos;else{let e=0;if(null!==o.fileSize){const t=Math.ceil(o.fileSize/c);if(t>1){let i=0,r=t-1;for(e=i;i<=r;){const t=Math.floor((i+r)/2),a=N(t*c,n.packetStride)+h.sectionStartPos,o=a+c,l=await u(a,o,!1);l?l.pesPacketHeader.pts<=s?(e=t,i=t+1):r=t-1:r=t-1}}}f=N(e*c,n.packetStride)+h.sectionStartPos}const k=await u(f,o.fileSize??1/0,!1);let b=k?.pesPacketHeader??null;b||(b=h);const y=this.getReorderSize(),w=async(e,t)=>{const o=await n.readSection(e,!0);i(o);const c=Or(o,!0);i(c);const l=new Wr(this.elementaryStream,c),u=new Vr(this,l);for(;;){if((a(u.presentationOrderPackets)?.pts??-1/0)>=s)break;if(!(await u.readNextPacket()))break}const d=C(u.presentationOrderPackets,t);if(-1===d)return null;const h=u.presentationOrderPackets[d],f=0===d?0:h.pts-u.presentationOrderPackets[d-1].pts;for(;u.decodeOrderPackets[0]!==h;)u.decodeOrderPackets.shift();u.lastDuration=f;const m=await u.readNext();i(m);const p=this.createEncodedPacket(m.packet,m.duration,r);return this.packetBuffers.set(p,u),this.packetSectionStarts.set(p,m.packet.sectionStartPos),p};if(!t||this.allPacketsAreKeyPackets()){e:for(;;){let e=b.sectionStartPos+n.packetStride;for(;;){const t=await n.readPacketHeader(e);if(!t)break e;if(t.pid===l&&1===t.payloadUnitStartIndicator){const t=await n.readSection(e,!1);if(t){const e=Nr(t,!1);if(e&&null!==e.pts){if(e.pts>s)break e;b=e,qr(this.elementaryStream,b);break}}}e+=n.packetStride}}e:for(let e=0;e=n.packetOffset;){const t=await n.readPacketHeader(e);if(!t)break e;if(t.pid===l&&1===t.payloadUnitStartIndicator){const t=await n.readSection(e,!1);if(t){const e=Nr(t,!1);if(e&&null!==e.pts){b=e;break}}}e-=n.packetStride}}return w(b.sectionStartPos,e=>e.pts<=s)}{let e=f,t=null;const r=!this.elementaryStream.canBeTrustedWithKeyPackets;for(;;){let a=null;const f=e<=h.sectionStartPos;let m,p=null;if(f)m=h,p=d;else{const t=await u(e,o.fileSize??1/0,r);m=t?.pesPacketHeader??null,p=t?.section??null}let g=!1,k=0;e:for(;m&&!(null!==t&&m.sectionStartPos>=t);){if(m.pts<=s){let e;if(this.elementaryStream.canBeTrustedWithKeyPackets)e=1===m.randomAccessIndicator;else{i(p);const t=Or(p,!0);i(t);const r=new Wr(this.elementaryStream,t);await r.markNextPacket(),e=1===r.suppliedPacket?.randomAccessIndicator}e&&(a=m)}if(m.pts>s&&(g=!0),g&&(k++,k>y))break;let e=m.sectionStartPos+n.packetStride;for(;;){const t=await n.readPacketHeader(e);if(!t)break e;if(t.pid===l&&1===t.payloadUnitStartIndicator){const t=await n.readSection(e,r);if(t){const e=Nr(t,!1);if(e&&null!==e.pts){m=e,p=t,qr(this.elementaryStream,m);break}}}e+=n.packetStride}}if(a){let e=a;if(0===k)e:for(let i=0;i=n.packetOffset;){const i=await n.readPacketHeader(t);if(!i)break e;if(i.pid===l&&1===i.payloadUnitStartIndicator){const i=await n.readSection(t,r);if(i){const t=Nr(i,!1);if(t&&null!==t.pts){e=t;break}}}t-=n.packetStride}}const t=await w(e.sectionStartPos,e=>e.pts<=s&&1===e.randomAccessIndicator);return i(t),t}if(f)return null;t=e,e=Math.max(N(e-h.sectionStartPos-c,n.packetStride)+h.sectionStartPos,h.sectionStartPos)}}}}class zr extends Lr{getType(){return"video"}getCodec(){return this.elementaryStream.info.codec}getCodedWidth(){return this.elementaryStream.info.width}getCodedHeight(){return this.elementaryStream.info.height}getSquarePixelWidth(){return this.elementaryStream.info.squarePixelWidth}getSquarePixelHeight(){return this.elementaryStream.info.squarePixelHeight}getRotation(){return 0}async getColorSpace(){return this.elementaryStream.info.colorSpace}async canBeTransparent(){return!1}async getDecoderConfig(){return i(this.elementaryStream.info.decoderConfig),this.elementaryStream.info.decoderConfig}allPacketsAreKeyPackets(){return!1}getReorderSize(){return this.elementaryStream.info.reorderSize}}class Ur extends Lr{getType(){return"audio"}getCodec(){return this.elementaryStream.info.codec}getNumberOfChannels(){return this.elementaryStream.info.numberOfChannels}getSampleRate(){return this.elementaryStream.info.sampleRate}async getDecoderConfig(){return i(this.elementaryStream.info.decoderConfig),this.elementaryStream.info.decoderConfig}allPacketsAreKeyPackets(){return!0}getReorderSize(){return 0}}const qr=(e,t)=>{const i=e.referencePesPackets,r=P(i,t.sectionStartPos,e=>e.sectionStartPos);if(r>=0){const a=i[r];if(t.pts<=a.pts)return!1;const s=e.demuxer.minReferencePointByteDistance;if(t.sectionStartPos-a.sectionStartPos=e?e:this.bufferData(e-t).then(()=>Math.min(this.endPos-this.currentPos,e))}getCurrentPesPacket(){const e=this.pesPackets[this.currentPesPacketIndex];return i(e),e}async bufferData(e){const t=this.endPos+e;for(;this.endPos=n)break;o=e;const i=a+o;if(o+4>=n){this.seekTo(i);break}const c=s[o+1],l=s[o+2],u=s[o+3];let d=0,h=null;if(0===c&&0===l&&1===u?(d=4,h=s[o+4]):0===c&&1===l&&(d=3,h=u),0===d){o++;continue}const f=i;if(null!==r){if(null!==h){const e="avc"===t?$e(h):at(h);if("avc"===t?e===qe.AUD:e===Ve.AUD_NUT){const e=f-r;return this.seekTo(r),this.supplyPacket(e,0)}}o+=d}else r=f,o+=d}if(e>6,o=63&s[4];if(3===n||o>37){this.seekTo(t+1);continue}const c=Bt[3*o+n];i(void 0!==c),this.seekTo(t),a=this.ensureBuffered(c),a instanceof Promise&&(a=await a);const l=Math.round(13824e4/e.info.sampleRate);return this.supplyPacket(a,l)}if("eac3"===t){if(11!==r)continue;this.skip(-1);const t=this.currentPos;let i=this.ensureBuffered(5);if(i instanceof Promise&&(i=await i),i<5)return;const a=this.readBytes(5);if(11!==a[0]||119!==a[1]){this.seekTo(t+1);continue}const s=2*(((7&a[2])<<8|a[3])+1),n=3===a[4]>>6?3:a[4]>>4&3,o=Et[n];this.seekTo(t),i=this.ensureBuffered(s),i instanceof Promise&&(i=await i);const c=256*o,l=Math.round(c*Ar/e.info.sampleRate);return this.supplyPacket(i,l)}throw new Error("Unhandled.")}{if(255!==r)continue;this.skip(-1);const t=this.currentPos;let i=this.ensureBuffered(4);if(i instanceof Promise&&(i=await i),i<4)return;const a=this.readBytes(4),s=c(a).getUint32(0),n=Me(s,null);if(n.header){this.seekTo(t);let i=this.ensureBuffered(n.header.totalSize);i instanceof Promise&&(i=await i);const r=n.header.audioSamplesInFrame*Ar/e.info.sampleRate;return this.supplyPacket(i,Math.round(r))}this.seekTo(t+1)}}}if(a=0)}async readNext(){if(0===this.decodeOrderPackets.length){if(!(await this.readNextPacket()))return null}await this.ensureCurrentPacketHasNext();const e=this.decodeOrderPackets[0],t=this.presentationOrderPackets.indexOf(e);let r;if(i(-1!==t),t===this.presentationOrderPackets.length-1)r=this.lastDuration;else{r=this.presentationOrderPackets[t+1].pts-e.pts,this.lastDuration=r}for(this.decodeOrderPackets.shift();this.presentationOrderPackets.length>0;){const e=this.presentationOrderPackets[0];if(this.decodeOrderPackets.includes(e))break;this.presentationOrderPackets.shift()}return{packet:e,duration:r}}async readNextPacket(){if(this.reachedEnd)return!1;let e;return this.context.suppliedPacket||await this.context.markNextPacket(),e=this.context.suppliedPacket,this.context.suppliedPacket=null,e?(this.decodeOrderPackets.push(e),this.processPacketThroughReorderBuffer(e),!0):(this.reachedEnd=!0,this.flushReorderBuffer(),!1)}async ensureCurrentPacketHasNext(){const e=this.decodeOrderPackets[0];for(i(e);;){const t=this.presentationOrderPackets.indexOf(e);if(-1!==t&&t<=this.presentationOrderPackets.length-2)break;if(!(await this.readNextPacket()))break}}processPacketThroughReorderBuffer(e){if(this.reorderBuffer.push(e),this.reorderBuffer.length>this.reorderSize){let e=0;for(let i=1;ie.pts-t.pts),this.presentationOrderPackets.push(...this.reorderBuffer),this.reorderBuffer.length=0}}const Hr="application/vnd.apple.mpegurl",Kr="#EXT-X-STREAM-INF:",jr="#EXT-X-I-FRAME-STREAM-INF:",Xr="#EXT-X-MEDIA:",$r="#EXTINF:",Qr="#EXT-X-MAP:",Gr="#EXT-X-KEY:",Yr="#EXT-X-MEDIA-SEQUENCE:",Jr="#EXT-X-BYTERANGE:",Zr="#EXT-X-PROGRAM-DATE-TIME:",ea="#EXT-X-TARGETDURATION:",ta="#EXT-X-PLAYLIST-TYPE:",ia=e=>0===e.length||e.startsWith("#")&&!e.startsWith("#EXT");class ra{constructor(e){this._attributes={};let t="",i="",r=!1,a=!1;for(let s=0;s{const e=[];if(this.trackDeclarations){for(const t of this.trackDeclarations)if("video"===t.type){const i=ae(e,e=>"video"===e.getType())+1;e.push(new na(this,t,i))}else if("audio"===t.type){const i=ae(e,e=>"audio"===e.getType())+1;e.push(new oa(this,t,i))}}else{if(this.firstSegment=await this.getFirstSegment({}),!this.firstSegment)return[];const t=this.getInputForSegment(this.firstSegment),i=await t.getTracks();for(const r of i)if("video"===r.type){const t=ae(e,e=>"video"===e.getType())+1;e.push(new na(this,{id:e.length+1,type:"video"},t))}else if("audio"===r.type){const t=ae(e,e=>"audio"===e.getType())+1;e.push(new oa(this,{id:e.length+1,type:"audio"},t))}}return e})())}async getFirstTimestampForInput(e){const t=this.firstTimestampCache.get(e);if(void 0!==t)return t;const i=await e.getFirstTimestamp();return this.firstTimestampCache.set(e,i),i}async getMediaOffset(e,t){const i=e.firstSegment??e;let r;if(this.firstSegmentFirstTimestamps.has(i))r=this.firstSegmentFirstTimestamps.get(i);else{const e=this.getInputForSegment(i);r=await this.getFirstTimestampForInput(e),this.firstSegmentFirstTimestamps.set(i,r)}if(i===e)return i.timestamp-r;const a=await this.getFirstTimestampForInput(t),s=e.timestamp-i.timestamp,n=a-r-s;return Math.abs(n)<=Math.min(.25,s)?i.timestamp-r:e.timestamp-a}dispose(){for(const e of this.inputCache)e.input.dispose();this.inputCache.length=0}}class sa{constructor(e,t,i){this.packetInfos=new WeakMap,this.hydrationPromise=null,this.firstInputTrack=null,this.segmentedInput=e,this.decl=t,this.number=i}hydrate(){return this.hydrationPromise??(this.hydrationPromise=(async()=>{var e;if((e=this.segmentedInput).firstSegment??(e.firstSegment=await this.segmentedInput.getFirstSegment({})),!this.segmentedInput.firstSegment)throw new Error("Missing first segment, can't retrieve track.");const t=this.segmentedInput.getInputForSegment(this.segmentedInput.firstSegment),i=(await t.getTracks()).find(e=>e.type===this.decl.type&&e.number===this.number);if(!i)throw new Error("No matching track found in underlying media data.");this.firstInputTrack=i})())}getId(){return this.decl.id}getType(){return this.decl.type}getNumber(){return this.number}delegate(e){return this.firstInputTrack?e():this.hydrate().then(e)}async getDecoderConfig(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())}getHasOnlyKeyPackets(){return this.delegate(()=>this.firstInputTrack._backing.getHasOnlyKeyPackets?.()??null)}getPairingMask(){return 1n}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getInternalCodecId(){return this.delegate(()=>this.firstInputTrack._backing.getInternalCodecId())}getDisposition(){return this.delegate(()=>this.firstInputTrack._backing.getDisposition())}getLanguageCode(){return this.delegate(()=>this.firstInputTrack._backing.getLanguageCode())}getName(){return this.delegate(()=>this.firstInputTrack._backing.getName())}getTimeResolution(){return this.delegate(()=>this.firstInputTrack._backing.getTimeResolution())}async isRelativeToUnixEpoch(){return await this.hydrate(),i(this.segmentedInput.firstSegment),this.segmentedInput.firstSegment.relativeToUnixEpoch}getBitrate(){return this.delegate(()=>this.firstInputTrack._backing.getBitrate())}getAverageBitrate(){return this.delegate(()=>this.firstInputTrack._backing.getAverageBitrate())}getDurationFromMetadata(e){return this.segmentedInput.getDurationFromMetadata(e)}getLiveRefreshInterval(){return this.segmentedInput.getLiveRefreshInterval()}async createAdjustedPacket(e,t,r){i(e.sequenceNumber>=0),i(this.segmentedInput.firstSegment);const a=await this.segmentedInput.getMediaOffset(t,r.input),s=t.timestamp-this.segmentedInput.firstSegment.timestamp,n=e.clone({timestamp:M(e.timestamp+a,await r.getTimeResolution()),sequenceNumber:Math.floor(1e8*s)+e.sequenceNumber});return this.packetInfos.set(n,{segment:t,track:r,sourcePacket:e}),n}async getFirstPacket(e){await this.hydrate(),i(this.segmentedInput.firstSegment),i(this.firstInputTrack);const t=await this.firstInputTrack._backing.getFirstPacket(e);return t?this.createAdjustedPacket(t,this.segmentedInput.firstSegment,this.firstInputTrack):null}getNextPacket(e,t){return this._getNextInternal(e,t,!1)}getNextKeyPacket(e,t){return this._getNextInternal(e,t,!0)}async _getNextInternal(e,t,i){const r=this.packetInfos.get(e);if(!r)throw new Error("Packet was not created from this track.");const a=i?await r.track._backing.getNextKeyPacket(r.sourcePacket,t):await r.track._backing.getNextPacket(r.sourcePacket,t);if(a)return this.createAdjustedPacket(a,r.segment,r.track);let s=r.segment;for(;;){const e=await this.segmentedInput.getNextSegment(s,{skipLiveWait:t.skipLiveWait});if(!e)return null;const i=this.segmentedInput.getInputForSegment(e),a=(await i.getTracks()).find(e=>e.type===r.track.type&&e.number===r.track.number);if(!a){s=e;continue}const n=await a._backing.getFirstPacket(t);return n?this.createAdjustedPacket(n,e,a):null}}getPacket(e,t){return this._getPacketInternal(e,t,!1)}getKeyPacket(e,t){return this._getPacketInternal(e,t,!0)}async _getPacketInternal(e,t,i){let r=await this.segmentedInput.getSegmentAt(e,{skipLiveWait:t.skipLiveWait});if(!r)return null;for(await this.hydrate();r;){const a=this.segmentedInput.getInputForSegment(r),s=(await a.getTracks()).find(e=>e.type===this.firstInputTrack.type&&e.number===this.firstInputTrack.number);if(!s){r=await this.segmentedInput.getPreviousSegment(r,{skipLiveWait:t.skipLiveWait});continue}const n=e-await this.segmentedInput.getMediaOffset(r,a),o=i?await s._backing.getKeyPacket(n,t):await s._backing.getPacket(n,t);if(o)return this.createAdjustedPacket(o,r,s);r=await this.segmentedInput.getPreviousSegment(r,{skipLiveWait:t.skipLiveWait})}return null}}class na extends sa{getType(){return"video"}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getCodedWidth(){return this.delegate(()=>this.firstInputTrack._backing.getCodedWidth())}getCodedHeight(){return this.delegate(()=>this.firstInputTrack._backing.getCodedHeight())}getSquarePixelWidth(){return this.delegate(()=>this.firstInputTrack._backing.getSquarePixelWidth())}getSquarePixelHeight(){return this.delegate(()=>this.firstInputTrack._backing.getSquarePixelHeight())}getRotation(){return this.delegate(()=>this.firstInputTrack._backing.getRotation())}async getColorSpace(){return this.delegate(()=>this.firstInputTrack._backing.getColorSpace())}async canBeTransparent(){return this.delegate(()=>this.firstInputTrack._backing.canBeTransparent())}async getDecoderConfig(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())}}class oa extends sa{getType(){return"audio"}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getNumberOfChannels(){return this.delegate(()=>this.firstInputTrack._backing.getNumberOfChannels())}getSampleRate(){return this.delegate(()=>this.firstInputTrack._backing.getSampleRate())}async getDecoderConfig(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())}}te();const ca=1/0;class la extends le{constructor(){super(...arguments),this._disposed=!1,this._refCount=0,this._usedForHls=!1,this._sizePromise=null,this.onread=null}async getSizeOrNull(){if(this._disposed)throw new sn;return this._sizePromise??(this._sizePromise=(async()=>{let e=this._getFileSize();return void 0!==e||(await this._read(0,1,0,ca),e=this._getFileSize(),i(void 0!==e)),e})())}async getSize(){if(this._disposed)throw new sn;const e=await this.getSizeOrNull();if(null===e)throw new Error("Cannot determine the size of an unsized source.");return e}slice(e,t){if(!Number.isInteger(e)||e<0)throw new TypeError("offset must be a non-negative integer.");if(void 0!==t&&(!Number.isInteger(t)||t<0))throw new TypeError("length, when provided, must be a non-negative integer.");return new Ta(this,e,t)}_dispatchRead(e,t){this.onread?.(e,t),this._emit("read",{start:e,end:t})}ref(){return new ua(this)}}class ua{constructor(e){if(this._freed=!1,e._disposed)throw new Error("Cannot ref a disposed source.");e._refCount++,this._source=e}get source(){if(!this._source)throw new Error("Can't get source; ref has already been freed.");return this._source}get freed(){return this._freed}free(){if(this._freed)throw new Error("Illegal operation: double free on SourceRef.");const e=this.source;i(e._refCount>0),e._refCount--,0===e._refCount&&(e._dispose(),e._disposed=!0),this._freed=!0,this._source=null}[Symbol.dispose](){this.freed||this.free()}}class da extends la{constructor(e,t){if("string"!==typeof e)throw new TypeError("rootPath must be a string.");if("function"!==typeof t)throw new TypeError("requestHandler must be a function.");super(),this.rootPath=e,this.requestHandler=t}_resolveRequest(e){const t=this.requestHandler(e),i=e=>{var t;if(!(e instanceof la||e instanceof ua))throw new TypeError("requestHandler must return or resolve to a Source or SourceRef.");const i=e instanceof la?e.ref():e;return(t=i.source)._usedForHls||(t._usedForHls=this._usedForHls),i};return t instanceof Promise?t.then(i):i(t)}}const ha=(e,t)=>e.path===t.path;class fa extends da{constructor(){super(...arguments),this._root=null,this._rootRequest=null}_read(e,t,r,a){if(!this._root){if(!this._rootRequest){const e=this._resolveRequest({path:this.rootPath,isRoot:!0}),t=e=>{const t=e instanceof la?e.ref():e;return this._root=t,this._rootRequest=null,t};e instanceof Promise?this._rootRequest=e.then(t):(t(e),i(this._root))}if(this._rootRequest)return this._rootRequest.then(i=>i.source._read(e,t,r,a))}return this._root.source._read(e,t,r,a)}_getFileSize(){if(this._root)return this._root.source._getFileSize()}_dispose(){this._root?this._root.free():this._rootRequest&&this._rootRequest.then(e=>e.free())}}class ma extends la{constructor(e,t={}){if(!(e instanceof Blob))throw new TypeError("blob must be a Blob.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!ie(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._readers=new WeakMap,this._blob=e,this._orchestrator=new wa({maxCacheSize:t.maxCacheSize??8388608,maxWorkerCount:4,runWorker:this._runWorker.bind(this),prefetchProfile:ya.fileSystem}),this._orchestrator.fileSize=e.size}_getFileSize(){return this._orchestrator.fileSize}_read(e,t,i,r){return this._orchestrator.read(e,t,i,r)}async _runWorker(e){i(e.strictTarget);let t=this._readers.get(e);if(void 0===t){if("stream"in this._blob&&!K()){t=this._blob.slice(e.currentPos).stream().getReader()}else t=null;this._readers.set(e,t)}for(;e.currentPos{if(t instanceof Error&&(t.message.includes("Failed to fetch")||t.message.includes("Load failed")||t.message.includes("NetworkError when attempting to fetch resource"))){let e=null;try{"undefined"!==typeof window&&"undefined"!==typeof window.location&&(e=new URL(i instanceof Request?i.url:i,window.location.href).origin)}catch{}if(("undefined"===typeof navigator||"boolean"!==typeof navigator.onLine||navigator.onLine)&&null!==e&&e!==window.location.origin)return console.warn("Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option."),null}return Math.min(2**(e-2),16)},ga=new Set;class ka extends da{constructor(e,t={}){if("string"!==typeof e&&!(e instanceof URL)&&!("undefined"!==typeof Request&&e instanceof Request))throw new TypeError("url must be a string, URL or Request.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.requestInit&&(!t.requestInit||"object"!==typeof t.requestInit))throw new TypeError("options.requestInit, when provided, must be an object.");if(void 0!==t.getRetryDelay&&"function"!==typeof t.getRetryDelay)throw new TypeError("options.getRetryDelay, when provided, must be a function.");if(void 0!==t.maxCacheSize&&(!ie(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");if(void 0!==t.parallelism&&(!Number.isInteger(t.parallelism)||t.parallelism<1))throw new TypeError("options.parallelism, when provided, must be a positive number.");if(void 0!==t.fetchFn&&"function"!==typeof t.fetchFn)throw new TypeError("options.fetchFn, when provided, must be a function.");super(e instanceof Request?e.url:e instanceof URL?e.href:e,e=>new ka(e.path,this._options)),this._fileSizeDetermined=!1,this._url=e,this._options=t,this._getRetryDelay=t.getRetryDelay??pa;this._orchestrator=new wa({maxCacheSize:t.maxCacheSize??67108864,maxWorkerCount:t.parallelism??2,runWorker:this._runWorker.bind(this),prefetchProfile:ya.network})}_getFileSize(){return this._fileSizeDetermined?this._orchestrator.fileSize:void 0}_read(e,t,i,r){return this._orchestrator.read(e,t,i,r)}async _runWorker(e){for(;;){const i=new AbortController,r=await W(this._options.fetchFn??fetch,this._url,U(this._options.requestInit??{},{headers:{Range:`bytes=${e.currentPos}-`},signal:i.signal}),this._getRetryDelay,()=>this._disposed);if(!r.ok)throw new Error(`Error fetching ${String(this._url)}: ${r.status} ${r.statusText}`);e:if(null===this._orchestrator.fileSize){const t=r.headers.get("Content-Range");if(t){const e=/\/(\d+)/.exec(t);if(e){this._orchestrator.supplyFileSize(Number(e[1]));break e}}const i=r.headers.get("Content-Length");i&&this._orchestrator.supplyFileSize(e.currentPos+Number(i))}if(this._fileSizeDetermined=!0,206!==r.status){if(!this._usedForHls){const e=new URL(this._url instanceof Request?this._url.url:this._url,"undefined"!==typeof window?window.location.href:void 0);"null"===e.origin||e.pathname.endsWith(".m3u8")||e.pathname.endsWith(".m3u")||ga.has(e.origin)||(console.log(this._usedForHls,this._url,e.pathname),console.warn(`HTTP server (origin ${e.origin}) did not respond to a range request with 206 Partial Content, meaning the entire resource will now be downloaded. To enable efficient media file streaming across a network, please make sure your server supports range requests.`),ga.add(e.origin))}e.currentPos=0,this._orchestrator.options.maxCacheSize=1/0,null!==this._orchestrator.fileSize?e.targetPos=this._orchestrator.fileSize:(e.targetPos=1/0,e.strictTarget=!1),this._orchestrator.consolidateEverythingIntoOneWorker(e)}if(!r.body)throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream.");const a=r.body.getReader();for(;;){if(e.currentPos>=e.targetPos||e.aborted)return i.abort(),void this._orchestrator.signalWorkerStoppedRunning(e);let r;try{r=await a.read()}catch(t){if(this._disposed)throw t;const e=this._getRetryDelay(1,t,this._url);if(null!==e){console.error("Error while reading response stream. Attempting to resume.",t),await ce(1e3*e);break}throw t}if(e.aborted)continue;const{done:s,value:n}=r;if(s){if(e.currentPos>=e.targetPos)return void this._orchestrator.onWorkerFinished(e);if(e.strictTarget)break;return void this._orchestrator.onWorkerFinished(e)}this._dispatchRead(e.currentPos,e.currentPos+n.length),this._orchestrator.supplyWorkerData(e,n)}}}_dispose(){this._orchestrator.dispose()}}class ba extends la{constructor(e,t={}){if(!(e instanceof ReadableStream))throw new TypeError("stream must be a ReadableStream.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!ie(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._reader=null,this._cache=[],this._pendingSlices=[],this._currentIndex=0,this._targetIndex=0,this._maxRequestedIndex=0,this._endIndex=null,this._pulling=!1,this._stream=e,this._maxCacheSize=t.maxCacheSize??16777216}_getFileSize(){return this._endIndex}_read(e,t){if(null!==this._endIndex&&t>this._endIndex)return null;this._maxRequestedIndex=Math.max(this._maxRequestedIndex,t);const i=P(this._cache,e,e=>e.start),r=-1!==i?this._cache[i]:null;if(r&&r.start<=e&&t<=r.end)return{bytes:r.bytes,view:r.view,offset:r.start};let a=e;const s=new Uint8Array(t-e);if(-1!==i)for(let c=i;c=t)break;const r=Math.max(e,i.start);r>a&&this._throwDueToCacheMiss();const n=Math.min(t,i.end);ra&&this._throwDueToCacheMiss();const{promise:n,resolve:o,reject:l}=I();return this._pendingSlices.push({start:e,end:t,bytes:s,resolve:o,reject:l}),this._targetIndex=Math.max(this._targetIndex,t),this._pulling||(this._pulling=!0,this._pull().catch(e=>{if(this._pulling=!1,!(this._pendingSlices.length>0))throw e;this._pendingSlices.forEach(t=>t.reject(e)),this._pendingSlices.length=0})),n}_throwDueToCacheMiss(){throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache.")}async _pull(){for(this._reader??(this._reader=this._stream.getReader());this._currentIndex0;){const e=this._cache[0];if(this._maxRequestedIndex-e.end<=this._maxCacheSize)break;this._cache.shift()}this._currentIndex+=t.byteLength}this._pulling=!1}_dispose(){this._pendingSlices.length=0,this._cache.length=0,this._reader?.cancel()}}const ya={fileSystem:(e,t)=>{const i=65536;return{start:e=Math.floor((e-i)/i)*i,end:t=Math.ceil((t+i)/i)*i}},network:(e,t,i)=>{const r=65536;e=Math.max(0,Math.floor((e-r)/r)*r);for(const a of i){const i=8388608,r=Math.max((a.startPos+a.targetPos)/2,a.targetPos-i);if(Z(e,t,r,a.targetPos)){const e=a.targetPos-a.startPos,r=Math.ceil((e+1)/i)*i,s=2**Math.ceil(Math.log2(e+1)),n=Math.min(s,r);t=Math.max(t,a.startPos+n)}}return{start:e,end:t=Math.max(t,e+524288)}}};class wa{constructor(e){this.options=e,this.fileSize=null,this.nextAge=0,this.workers=[],this.cache=[],this.currentCacheSize=0,this.disposed=!1,this.queuedReads=[]}read(e,t,r,a){i(!this.disposed);const s=this.options.prefetchProfile(e,t,this.workers),n=Math.max(s.start,r),o=Math.min(s.end,this.fileSize??1/0,a);i(n<=e&&t<=o);let l=null;const u=P(this.cache,e,e=>e.start),d=-1!==u?this.cache[u]:null;d&&d.start<=e&&t<=d.end&&(d.age=this.nextAge++,l={bytes:d.bytes,view:d.view,offset:d.start});const h=P(this.cache,n,e=>e.start),f=l?null:new Uint8Array(t-e);let m=0,p=n;const g=[];if(-1!==h){for(let r=h;r=o)break;if(a.end<=n)continue;const s=Math.max(n,a.start),c=Math.min(o,a.end);if(i(s<=c),p=f.length&&(l={bytes:f,view:c(f),offset:e}),0===g.length)return i(l),l;const{promise:k,resolve:b,reject:y}=I(),w=[];for(const i of g){const r=Math.max(e,i.start),a=Math.min(t,i.end);r===i.start&&a===i.end?w.push(i):re.hole.start),r=-1!==t?this.queuedReads[t]:null;for(r&&i.start<=r.hole.end?(r.hole.end=Math.max(r.hole.end,i.end),r.strictTarget&&(r.strictTarget=e),T&&r.pendingSlices.push(T)):(t++,r={hole:{start:i.start,end:i.end},strictTarget:e,pendingSlices:T?[T]:[],age:this.nextAge++},this.queuedReads.splice(t,0,r));t+1r.hole.end)break;r.hole.end=Math.max(r.hole.end,e.hole.end),r.pendingSlices.push(...e.pendingSlices),r.strictTarget&&(r.strictTarget=e.strictTarget),r.age=Math.min(r.age,e.age),this.queuedReads.splice(t+1,1)}}}return l||(i(f),l=k.then(t=>t&&{bytes:t,view:c(t),offset:e})),l}checkHoleAgainstWorker(e,t,i){if(Z(t.start-2**17,t.start,e.currentPos,e.targetPos)){e.targetPos=Math.max(e.targetPos,t.end);for(let t=0;t=this.options.maxWorkerCount){let e=null,t=null;for(let i=0;i{if(e.running=!1,!(e.pendingSlices.length>0))throw t;e.pendingSlices.forEach(e=>e.reject(t)),e.pendingSlices.length=0}).finally(()=>{if(!e.running&&this.queuedReads.length>0){let e=0;for(let i=1;ie.targetPos&&(e.targetPos=e.currentPos,this.checkQueuedReadsAgainstWorker(e));for(let i=0;it.start&&(t.start=a),t.end<=t.start&&(s.holes.splice(e,1),e--)}0===s.holes.length&&(s.resolve(s.bytes),e.pendingSlices.splice(i,1),i--)}for(let i=0;ie){r.resolve(null),t.pendingSlices.splice(i,1),i--;break}}}for(let t=0;t=e){for(const e of i.pendingSlices)e.resolve(null);this.queuedReads.splice(t,1),t--}else if(i.hole.end>e){i.hole.end=e,i.strictTarget=!0;for(let t=0;t=e&&(r.resolve(null),i.pendingSlices.splice(t,1),t--)}}}}signalWorkerStoppedRunning(e){e.running=!1,e.pendingSlices.length=0}onWorkerFinished(e){const t=this.workers.indexOf(e);i(-1!==t),e.running=!1,this.workers.splice(t,1),null===this.fileSize&&this.supplyFileSize(e.currentPos);for(const i of e.pendingSlices)i.resolve(null)}insertIntoCache(e){if(0===this.options.maxCacheSize)return;let t=P(this.cache,e.start,e=>e.start)+1;if(t>0){const i=this.cache[t-1];if(i.end>=e.end)return;if(i.end>e.start){const r=new Uint8Array(e.end-i.start);r.set(i.bytes,0),r.set(e.bytes,e.start-i.start),this.currentCacheSize+=e.end-i.end,i.bytes=r,i.view=c(r),i.end=e.end,t--,e=i}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length;for(let i=t+1;i=t.end){this.cache.splice(i,1),this.currentCacheSize-=t.bytes.length,i--;continue}const r=new Uint8Array(t.end-e.start);r.set(e.bytes,0),r.set(t.bytes,t.start-e.start),this.currentCacheSize-=e.end-t.start,e.bytes=r,e.view=c(r),e.end=t.end,this.cache.splice(i,1);break}for(;this.currentCacheSize>this.options.maxCacheSize;){let e=0,t=this.cache[0];for(let i=1;ithis._length)return null;const a=this._baseSource._read(this._offset+e,this._offset+t,this._offset+i,this._offset+r);return a instanceof Promise?a.then(e=>e?(e.offset-=this._offset,e):null):a?(a.offset-=this._offset,a):null}_dispose(){this._ref?.free()}ref(){return this._ref??(this._ref=this._baseSource.ref()),super.ref()}}var Sa=function(e,t,i){if(null!==t&&void 0!==t){if("object"!==typeof t&&"function"!==typeof t)throw new TypeError("Object expected.");var r,a;if(i){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");r=t[Symbol.asyncDispose]}if(void 0===r){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");r=t[Symbol.dispose],i&&(a=r)}if("function"!==typeof r)throw new TypeError("Object not disposable.");a&&(r=function(){try{a.call(this)}catch(e){return Promise.reject(e)}}),e.stack.push({value:t,dispose:r,async:i})}else i&&e.stack.push({async:!0});return t},Pa=function(e){return function(t){function i(i){t.error=t.hasError?new e(i,t.error,"An error was suppressed during disposal."):i,t.hasError=!0}var r,a=0;return function e(){for(;r=t.stack.pop();)try{if(!r.async&&1===a)return a=0,t.stack.push(r),Promise.resolve().then(e);if(r.dispose){var s=r.dispose.call(r.value);if(r.async)return a|=2,Promise.resolve(s).then(e,function(t){return i(t),e()})}else a|=1}catch(n){i(n)}if(1===a)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}()}}("function"===typeof SuppressedError?SuppressedError:function(e,t,i){var r=new Error(i);return r.name="SuppressedError",r.error=e,r.suppressed=t,r});const va=/^0[xX][0-9a-fA-F]+$/,Ia=/^data:.*;base64,/i;class xa extends aa{constructor(e,t,i,r){super(e.input,t,i),this.segments=[],this.nextLines=null,this.currentUpdateSegmentsPromise=null,this.streamHasEnded=!1,this.lastSegmentUpdateTime=-1/0,this.refreshInterval=5,this.demuxer=e,this.nextLines=r}runUpdateSegments(){return this.currentUpdateSegmentsPromise??(this.currentUpdateSegmentsPromise=(async()=>{try{const e=this.getRemainingWaitTimeMs();e>0&&await ce(e),this.lastSegmentUpdateTime=performance.now(),await this.updateSegments()}finally{this.currentUpdateSegmentsPromise=null}})())}getRemainingWaitTimeMs(){const e=performance.now()-this.lastSegmentUpdateTime,t=Math.max(0,1e3*this.refreshInterval-e);return t<=50?0:t}async updateSegments(){let e=this.nextLines;if(this.nextLines=null,!e){const t={stack:[],error:void 0,hasError:!1};try{const r=Sa(t,await this.demuxer.input._getSourceUncached({path:this.path,isRoot:!1}),!1),a=new nn(r.source),s=await a.requestEntireFile();i(s),e=xn(s,s.length,{ignore:ia})}catch(y){t.error=y,t.hasError=!0}finally{Pa(t)}}let t=!1,r=0,s=null,n=null,o=0,l=null,u=null,d=null,h=null,f=null,m=null,p=!1,g=a(this.segments)??null;const k=e=>{const t=e.indexOf("@"),i=Number(-1===t?e:e.slice(0,t));if(!Number.isInteger(i)||i<0)throw new Error(`Invalid #EXT-X-BYTERANGE length '${e}'.`);let r=null;if(-1!==t&&(r=Number(e.slice(t+1)),!Number.isInteger(r)||r<0))throw new Error(`Invalid #EXT-X-BYTERANGE offset '${e}'.`);return{length:i,offset:r}},b=e=>{o=e,g&&(i(null!==g.sequenceNumber),g.sequenceNumber0&&null!==m&&(r=o*m),p=!0);const e=y.slice(8),t=e.indexOf(","),i=-1===t?e:e.slice(0,t),a=Number(i);if(!Number.isFinite(a)||a<0)throw new Error(`Invalid #EXTINF tag duration '${i}'.`);s=a}else if(y.startsWith(Qr)){const e=new ra(y.slice(11)),t=e.get("uri");if(!t)throw new Error("Invalid #EXT-X-MAP tag; missing URI attribute.");const i=e.get("byterange");let a=null;if(null!==i&&(a=k(i)),a&&null===a.offset)throw new Error("Invalid #EXT-X-MAP tag; BYTERANGE attribute must have a specified offset.");if(!g){const e={path:re(this.path,t),offset:a?.offset??0,length:a?.length??null};if("AES-128"===n?.method&&!n.iv)throw new Error("IV attribute must be set on #EXT-X-KEY tag preceding the #EXT-X-MAP tag.");u={timestamp:r,relativeToUnixEpoch:null!==f,firstSegment:null,sequenceNumber:null,location:e,duration:0,encryption:n,initSegment:null,lastProgramDateTimeSeconds:f}}s=null,null===h?d=null:h=null}else if(y.startsWith(Gr)){const e=new ra(y.slice(11)),t=e.get("method");if("NONE"===t)n=null;else if("AES-128"===t){const t=e.get("uri");if(!t)throw new Error("Invalid #EXT-X-KEY: AES-128 requires a URI attribute.");let i=null;const r=e.get("iv");if(r){if(!va.test(r))throw new Error(`Unsupported IV format '${r}'.`);let e=r.slice(2);e=e.padStart(32,"0"),i=new Uint8Array(Ht);for(let t=0;t=8&&112===t[4]&&115===t[5]&&115===t[6]&&104===t[7]){const e=c(t).getUint32(0);r=Nt(t.subarray(8,Math.min(e,t.length)))}}n={method:t,psshBox:r}}}}else if(y.startsWith(Yr)){const e=y.slice(22),t=Number(e);if(!Number.isInteger(t)||t<0)throw new Error(`Invalid EXT-X-MEDIA-SEQUENCE value '${e}'.`);b(t)}else if(y.startsWith(Jr)){const e=k(y.slice(17));if(null===e.offset){if(null===d)throw new Error("Invalid M3U8 file; #EXT-X-BYTERANGE without offset requires a previous byte range.");e.offset=d}h=e,d=e.offset+e.length}else if(y.startsWith(Zr)){if(g)continue;const e=y.slice(25),t=Date.parse(e);if(!Number.isFinite(t))continue;const i=t/1e3;if(f===i)continue;if(null===f&&this.segments.length>0){const e=a(this.segments),t=i-(e.timestamp+e.duration);for(const i of this.segments)i.timestamp+=t,i.relativeToUnixEpoch=!0;r+=t}f=i,r=i}else if("#EXT-X-DISCONTINUITY"===y)l=null;else if(y.startsWith(ea)){const e=y.slice(22),t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error(`Invalid EXT-X-TARGETDURATION value '${e}'.`);this.refreshInterval=t,m=t}else{if("#EXT-X-ENDLIST"===y){this.streamHasEnded=!0;break}if(y.startsWith(ta)){"vod"===y.slice(21).toLowerCase()&&(this.streamHasEnded=!0)}}}else{if("#EXTM3U"!==y)throw new Error("Invalid M3U8 file; expected first line to be #EXTM3U.");t=!0}}if(!t)throw new Error("Invalid M3U8 file; no #EXTM3U header.")}async getFirstSegment(){return 0===this.segments.length&&await this.runUpdateSegments(),this.segments[0]??null}async getSegmentAt(e,t){0===this.segments.length&&await this.runUpdateSegments();let i=!!t.skipLiveWait&&this.getRemainingWaitTimeMs()>0;for(;;){const r=P(this.segments,e,e=>e.timestamp);if(-1===r)return null;if(r0;for(;;){if(ae.segment===t);if(r)return r.age=this.nextInputCacheAge++,r.input;let a=null;(t.initSegment||t.firstSegment)&&(a=this.getInputForSegment(t.initSegment??t.firstSegment));const s={...this.input._formatOptions,isobmff:{...this.input._formatOptions.isobmff,resolveKeyId:this.input._formatOptions.isobmff?.resolveKeyId&&(e=>{if(!t.encryption||"SAMPLE-AES"!==t.encryption.method&&"SAMPLE-AES-CTR"!==t.encryption.method||!t.encryption.psshBox)return this.input._formatOptions.isobmff.resolveKeyId(e);let i=e.psshBoxes;const{psshBox:r}=t.encryption;return null!==r.keyIds&&!r.keyIds.includes(e.keyId)||i.some(e=>Ot(e,r))||(i=[...i,r]),this.input._formatOptions.isobmff.resolveKeyId({...e,psshBoxes:i})})}},n=new rn({source:new fa(t.location.path,async e=>{i(e.isRoot);const r={...e,isRoot:!1};let a;const s=t.location.offset>0||null!==t.location.length;if(t.encryption&&"SAMPLE-AES"!==t.encryption.method&&"SAMPLE-AES-CTR"!==t.encryption.method)if("AES-128"===t.encryption.method){const e=t.encryption;i(e.iv);let n=await this.input._getSourceCached(r);if(s){const e=n.source.slice(t.location.offset,t.location.length??void 0).ref();n.free(),n=e}const o=((e,t,i)=>{let r=!1,a=0;const s=new Zt;return new ReadableStream({pull:async n=>{r||(s.init(await t()),r=!0);let o=e.requestSliceRange(a,0,65552);if(o instanceof Promise&&(o=await o),!o||0===o.length)throw new Error("Invalid ciphertext.");const c=o.length;if(c%16!==0)throw new Error("Invalid ciphertext.");const l=65552===c?c-16:c,u=ln(o,l),d=new Uint8Array(l);for(let e=0;e16)throw new Error("Invalid PKCS#7 padding. Incorrect key or corrupted data.");const t=d.subarray(0,l-e);n.enqueue(t),n.close(),i()}},cancel:()=>{i()}})})(new nn(n.source),async()=>{const t={stack:[],error:void 0,hasError:!1};try{const i=Sa(t,await this.input._getSourceCached({path:e.keyUri,isRoot:!1},en),!1),r=new nn(i.source),a=await r.requestSlice(0,Ht);if(!a)throw new Error("Invalid AES-128 key; expected at least 16 bytes of data.");return{key:ln(a,Ht),iv:e.iv}}catch(i){t.error=i,t.hasError=!0}finally{Pa(t)}},()=>{n.free()});a=new ba(o).ref()}else i(!1);else if(a=await this.input._getSourceCached(r),s){const e=a.source.slice(t.location.offset,t.location.length??void 0).ref();a.free(),a=e}return a}),formats:this.input._formats.filter(e=>!(e instanceof ja)),initInput:a??void 0,formatOptions:s});n._onFormatDetermined=e=>{if(("SAMPLE-AES"===t.encryption?.method||"SAMPLE-AES-CTR"===t.encryption?.method)&&!e._isIsobmff)throw new Error("The SAMPLE-AES and SAMPLE-AES-CTR encryption methods are currently only supported for ISOBMFF files.")},this.inputCache.push({segment:t,input:n,age:this.nextInputCacheAge++});if(this.inputCache.length>4){const e=se(this.inputCache,e=>e.age);i(-1!==e),this.inputCache.splice(e,1)}return n}async getLiveRefreshInterval(){return 0===this.getRemainingWaitTimeMs()&&await this.runUpdateSegments(),this.streamHasEnded?null:this.refreshInterval}}class Ca extends Rt{constructor(e){super(e),this.metadataPromise=null,this.trackBackings=null,this.internalTracks=null,this.segmentedInputs=[],this.hasMasterPlaylist=!0}readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{i(this.input._rootSource instanceof da);const{rootPath:e}=this.input._rootSource,t=await this.input._reader.requestEntireFile();i(t);const r=xn(t,t.length,{ignore:ia}),a=[],s=[];for(let i=1;i"video"===e.attributes.get("type").toLowerCase()).map(e=>e.attributes.get("group-id")))],o=[...new Set(s.filter(e=>"audio"===e.attributes.get("type").toLowerCase()).map(e=>e.attributes.get("group-id")))],c=await Promise.all(a.map(async(t,r)=>{const a=[],c=t.attributes.get("codecs");let l;if(c)l=c.split(",").map(e=>e.trim());else{const e=this.getSegmentedInputForPath(t.fullPath),i=await e.getTrackBackings(),r=await Promise.all(i.map(async e=>({track:e,codec:await e.getCodec()})));l=await Promise.all(r.filter(e=>null!==e.codec).map(e=>e.track.getDecoderConfig().then(e=>e.codec)))}const u=t.attributes.get("video"),d=t.attributes.get("audio"),h=l.some(e=>ke.includes(Ee(e))),f=l.some(e=>ye.includes(Ee(e)));if(null!==u&&!h){if(!n.includes(u))throw new Error(`Invalid M3U8 file; variant stream references video group "${u}" which is not defined in any #EXT-X-MEDIA tags.`);const t=s.find(e=>{const t=e.attributes.get("group-id"),i=e.attributes.get("type");return t===u&&"video"===i.toLowerCase()});e:if(t){const r=t.attributes.get("uri");if(null===r)break e;const a=re(e,r),s=this.getSegmentedInputForPath(a),n=(await s.getTrackBackings()).find(e=>"video"===e.getType());if(!n||null===await n.getCodec())break e;const o=await n.getDecoderConfig().then(e=>e?.codec??null);i(null!==o),l.push(o)}}if(null!==d&&!f){if(!o.includes(d))throw new Error(`Invalid M3U8 file; variant stream references audio group "${d}" which is not defined in any #EXT-X-MEDIA tags.`);const t=s.find(e=>{const t=e.attributes.get("group-id"),i=e.attributes.get("type");return t===d&&"audio"===i.toLowerCase()});e:if(t){const r=t.attributes.get("uri");if(null===r)break e;const a=re(e,r),s=this.getSegmentedInputForPath(a),n=(await s.getTrackBackings()).find(e=>"audio"===e.getType());if(!n||null===await n.getCodec())break e;const o=await n.getDecoderConfig().then(e=>e?.codec??null);i(null!==o),l.push(o)}}l=[...new Set(l)];let m=null,p=null;const g=t.attributes.getAsNumber("bandwidth");i(null!==g);const k=t.attributes.getAsNumber("average-bandwidth"),b=t.attributes.get("name");for(const e of l){const i=Ee(e);if(null!==i)if(ke.includes(i)){if(null!==m)throw new Error("Unsupported M3U8 file; multiple video codecs found in the CODECS attribute of a variant stream.");m=e;const i=t.attributes.get("video");if(null===i){const e=t.attributes.get("resolution");let i=null,s=null;if(e){const t=e.match(/^(\d+)x(\d+)$/);t&&(i=Number(t[1]),s=Number(t[2]))}a.push({id:-1,demuxer:this,backingTrack:null,default:!0,autoselect:!0,languageCode:R,lineNumber:t.lineNumber,fullPath:t.fullPath,fullCodecString:m,pairingMask:1n<0?i:null}})}else{if(!o.includes(i))throw new Error(`Invalid M3U8 file; variant stream references audio group "${i}" which is not defined in any #EXT-X-MEDIA tags.`);for(const e of s){const s=e.attributes.get("group-id"),n=e.attributes.get("type");if(s!==i||"audio"!==n.toLowerCase())continue;const o=e.attributes.get("channels")??t.attributes.get("channels"),c=null!==o?Number(o.split("/")[0]):null;a.push({id:-1,demuxer:this,backingTrack:null,default:Aa(e.attributes),autoselect:Aa(e.attributes)||Fa(e.attributes),languageCode:Ra(e.attributes.get("language")),lineNumber:e.lineNumber,fullPath:e.fullPath??t.fullPath,fullCodecString:p,pairingMask:1n<0?c:null}})}}}}return a})),l=[],u=e=>{const t=l.find(t=>t.fullPath===e.fullPath&&t.info.type===e.info.type);t?(t.pairingMask|=e.pairingMask,t.default||(t.default=e.default),t.autoselect||(t.autoselect=e.autoselect),t.lineNumber=Math.min(t.lineNumber,e.lineNumber),null!==e.peakBitrate&&(t.peakBitrate=Math.max(t.peakBitrate??-1/0,e.peakBitrate)),null!==e.averageBitrate&&(t.averageBitrate=Math.max(t.averageBitrate??-1/0,e.averageBitrate)),t.languageCode===R&&(t.languageCode=e.languageCode)):(e.id=l.length+1,l.push(e))};for(const i of c)for(const e of i)u(e);l.sort((e,t)=>e.lineNumber-t.lineNumber),this.trackBackings=[];for(const i of l)"video"===i.info.type?this.trackBackings.push(new Ea(i)):this.trackBackings.push(new _a(i));this.internalTracks=l})())}async getTrackBackings(){return await this.readMetadata(),i(this.trackBackings),this.trackBackings}getSegmentedInputForPath(e){let t=this.segmentedInputs.find(t=>t.path===e);if(t)return t;let i=null;if(this.internalTracks){i=this.internalTracks.filter(t=>t.fullPath===e).map(e=>({id:e.id,type:e.info.type}))}return t=new xa(this,e,i,null),this.segmentedInputs.push(t),t}async getMetadataTags(){return{}}async getMimeType(){return Hr}dispose(){if(this.segmentedInputs){for(const e of this.segmentedInputs)e.dispose();this.segmentedInputs.length=0}}}class Ba{constructor(e){this.internalTrack=e,this.hydrationPromise=null}hydrate(){return this.hydrationPromise??(this.hydrationPromise=(async()=>{const e=this.internalTrack.demuxer.getSegmentedInputForPath(this.internalTrack.fullPath);let t=null;const r=(await e.getTrackBackings()).filter(e=>e.getType()===this.getType());if(1===r.length)t=r[0];else if(this instanceof Ea){for(const i of r)if(await i.getCodec()===this.getCodec()){t=i;break}}else{i(this instanceof _a);for(const e of r)if(await e.getCodec()===this.getCodec()){t=e;break}}if(!t)throw new Error("Could not find matching track in underlying media data.");this.internalTrack.backingTrack=t})())}delegate(e){return this.internalTrack.backingTrack?e():this.hydrate().then(e)}getCodec(){throw new Error("Not implemented on base class.")}getDisposition(){return{...he,default:this.internalTrack.autoselect,primary:this.internalTrack.default}}getId(){return this.internalTrack.id}getPairingMask(){return this.internalTrack.pairingMask}getInternalCodecId(){return null}getLanguageCode(){return this.internalTrack.languageCode}getName(){return this.internalTrack.name}getNumber(){i(this.internalTrack.demuxer.internalTracks);const e=this.internalTrack.info.type;let t=0;for(const i of this.internalTrack.demuxer.internalTracks)if(i.info.type===e&&t++,i===this.internalTrack)break;return t}getTimeResolution(){return this.delegate(()=>this.internalTrack.backingTrack.getTimeResolution())}isRelativeToUnixEpoch(){return this.delegate(()=>this.internalTrack.backingTrack.isRelativeToUnixEpoch())}getBitrate(){return this.internalTrack.peakBitrate}getAverageBitrate(){return this.internalTrack.averageBitrate}async getDurationFromMetadata(e){return await this.hydrate(),this.internalTrack.backingTrack.getDurationFromMetadata(e)}async getLiveRefreshInterval(){return await this.hydrate(),this.internalTrack.backingTrack.getLiveRefreshInterval()}getHasOnlyKeyPackets(){return this.internalTrack.hasOnlyKeyPackets||null}async getFirstPacket(e){return await this.hydrate(),this.internalTrack.backingTrack.getFirstPacket(e)}async getPacket(e,t){return await this.hydrate(),this.internalTrack.backingTrack.getPacket(e,t)}async getKeyPacket(e,t){return await this.hydrate(),this.internalTrack.backingTrack.getKeyPacket(e,t)}async getNextPacket(e,t){return await this.hydrate(),this.internalTrack.backingTrack.getNextPacket(e,t)}async getNextKeyPacket(e,t){return await this.hydrate(),this.internalTrack.backingTrack.getNextKeyPacket(e,t)}}class Ea extends Ba{constructor(e){super(e)}get backingVideoTrack(){return this.internalTrack.backingTrack}getType(){return"video"}getCodec(){return Ee(this.internalTrack.fullCodecString)}getCodedWidth(){return this.delegate(()=>this.backingVideoTrack.getCodedWidth())}getCodedHeight(){return this.delegate(()=>this.backingVideoTrack.getCodedHeight())}getSquarePixelWidth(){return this.delegate(()=>this.backingVideoTrack.getSquarePixelWidth())}getSquarePixelHeight(){return this.delegate(()=>this.backingVideoTrack.getSquarePixelHeight())}getMetadataDisplayWidth(){return this.backingVideoTrack?null:this.internalTrack.info.width}getMetadataDisplayHeight(){return this.backingVideoTrack?null:this.internalTrack.info.height}getRotation(){return this.delegate(()=>this.backingVideoTrack.getRotation())}async getColorSpace(){return await this.hydrate(),this.backingVideoTrack.getColorSpace()}async canBeTransparent(){return await this.hydrate(),this.backingVideoTrack.canBeTransparent()}getMetadataCodecParameterString(){return this.backingVideoTrack?null:this.internalTrack.fullCodecString}async getDecoderConfig(){return await this.hydrate(),this.backingVideoTrack.getDecoderConfig()}}class _a extends Ba{constructor(e){super(e)}get backingAudioTrack(){return this.internalTrack.backingTrack}getType(){return"audio"}getCodec(){return Ee(this.internalTrack.fullCodecString)}getNumberOfChannels(){return null!==this.internalTrack.info.numberOfChannels?this.internalTrack.info.numberOfChannels:this.delegate(()=>this.backingAudioTrack.getNumberOfChannels())}getSampleRate(){return this.delegate(()=>this.backingAudioTrack.getSampleRate())}getMetadataCodecParameterString(){return this.backingAudioTrack?null:this.internalTrack.fullCodecString}async getDecoderConfig(){return await this.hydrate(),this.backingAudioTrack.getDecoderConfig()}}const Aa=e=>{const t=e.get("default");if(null===t)return!1;const i=t.toUpperCase();if("YES"===i)return!0;if("NO"===i)return!1;throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA DEFAULT attribute must be YES or NO, got "${t}".`)},Fa=e=>{const t=e.get("autoselect");if(null===t)return!1;const i=t.toUpperCase();if("YES"===i)return!0;if("NO"===i)return!1;throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA AUTOSELECT attribute must be YES or NO, got "${t}".`)},Ra=e=>{if(null===e)return R;const t=e.split("-")[0];return t||R};class Da{constructor(){this._isIsobmff=!1}}class Ma extends Da{constructor(){super(...arguments),this._isIsobmff=!0}async _getMajorBrand(e){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=await t),!t)return null;t.skip(4);const i=In(t,4);return"ftyp"!==i&&"styp"!==i?null:In(t,4)}_createDemuxer(e){return new ei(e)}}class Na extends Ma{async _canReadInput(e){const t=await this._getMajorBrand(e);if(null!==t)return"qt "!==t;let i=e._reader.requestSlice(4,4);return i instanceof Promise&&(i=await i),!!i&&"moof"===In(i,4)}get name(){return"MP4"}get mimeType(){return"video/mp4"}}class Oa extends Ma{async _canReadInput(e){return"qt "===await this._getMajorBrand(e)}get name(){return"QuickTime File Format"}get mimeType(){return"video/quicktime"}}class La extends Da{async isSupportedEBMLOfDocType(e,t){let i=e._reader.requestSlice(0,Si);if(i instanceof Promise&&(i=await i),!i)return!1;const r=Pi(i);if(null===r)return!1;if(r<1||r>8)return!1;if(Ii(i,r)!==ki.EBML)return!1;const a=Ci(i);if("number"!==typeof a)return!1;let s=e._reader.requestSlice(i.filePos,a);if(s instanceof Promise&&(s=await s),!s)return!1;const n=i.filePos;for(;s.filePos<=n+a-2;){const e=Bi(s);if(!e)break;const{id:i,size:r}=e,a=s.filePos;if(void 0===r)return!1;switch(i){case ki.EBMLVersion:if(1!==Ii(s,r))return!1;break;case ki.EBMLReadVersion:if(1!==Ii(s,r))return!1;break;case ki.DocType:if(Ei(s,r)!==t)return!1;break;case ki.DocTypeVersion:if(Ii(s,r)>4)return!1}s.filePos=a+r}return!0}_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"matroska")}_createDemuxer(e){return new tr(e)}get name(){return"Matroska"}get mimeType(){return"video/x-matroska"}}class za extends La{_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"webm")}get name(){return"WebM"}get mimeType(){return"video/webm"}}class Ua extends Da{async _canReadInput(e){let t=0;for(;;){let i=e._reader.requestSlice(t,Fn);if(i instanceof Promise&&(i=await i),!i)break;const r=Nn(i);if(!r)break;t=i.filePos+r.size}const i=await sr(e._reader,t,t+4096);if(!i)return!1;const r=i.header,a=De(r.mpegVersionId,r.channel);let s=e._reader.requestSlice(i.startPos+a,4);if(s instanceof Promise&&(s=await s),!s)return!1;const n=gn(s);if(n===Fe||n===Re)return!0;t=i.startPos+i.header.totalSize;const o=await sr(e._reader,t,t+4);if(!o)return!1;const c=o.header;return r.channel===c.channel&&r.sampleRate===c.sampleRate}_createDemuxer(e){return new nr(e)}get name(){return"MP3"}get mimeType(){return"audio/mpeg"}}class qa extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=await t),!t)return!1;const i=In(t,4);if("RIFF"!==i&&"RIFX"!==i&&"RF64"!==i)return!1;t.skip(4);return"WAVE"===In(t,4)}_createDemuxer(e){return new Sr(e)}get name(){return"WAVE"}get mimeType(){return"audio/wav"}}class Wa extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=await t),!!t&&"OggS"===In(t,4)}_createDemuxer(e){return new gr(e)}get name(){return"Ogg"}get mimeType(){return"application/ogg"}}class Va extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=await t),!!t&&"fLaC"===In(t,4)}get name(){return"FLAC"}get mimeType(){return"audio/flac"}_createDemuxer(e){return new Er(e)}}class Ha extends Da{async _canReadInput(e){let t=0;for(;;){let i=e._reader.requestSlice(t,Fn);if(i instanceof Promise&&(i=await i),!i)break;const r=Nn(i);if(!r)break;t=i.filePos+r.size}let i=e._reader.requestSliceRange(t,7,9);if(i instanceof Promise&&(i=await i),!i)return!1;const r=Ir(i);if(!r)return!1;if(t+=r.frameLength,i=e._reader.requestSliceRange(t,7,9),i instanceof Promise&&(i=await i),!i)return!1;const a=Ir(i);return!!a&&(r.objectType===a.objectType&&r.samplingFrequencyIndex===a.samplingFrequencyIndex&&r.channelConfiguration===a.channelConfiguration)}_createDemuxer(e){return new Cr(e)}get name(){return"ADTS"}get mimeType(){return"audio/aac"}}class Ka extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,205);if(t instanceof Promise&&(t=await t),!t)return!1;const i=ln(t,205);return 71===i[0]&&71===i[188]||(71===i[0]&&71===i[204]||71===i[4]&&71===i[196])}_createDemuxer(e){return new Mr(e)}get name(){return"MPEG Transport Stream"}get mimeType(){return"video/MP2T"}}class ja extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,7);if(t instanceof Promise&&(t=await t),!t)return!1;if(!("#EXTM3U"===In(t,7)))return!1;if(!(e._rootSource instanceof da))throw new TypeError("HLS inputs require `InputOptions.source` to be a PathedSource or a ref to one.");return e._rootSource._usedForHls=!0,!0}_createDemuxer(e){return new Ca(e)}get name(){return"HTTP Live Streaming (HLS)"}get mimeType(){return Hr}}const Xa=new Na,$a=new Oa,Qa=new La,Ga=new za,Ya=new Ua,Ja=new qa,Za=new Wa,es=new Ha,ts=new Va,is=new Ka,rs=new ja,as=[rs,Xa,$a,Qa,Ga,Ja,Za,ts,Ya,es,is],ss=[rs,Xa,$a,Ya,es,is];te();let ns=-1/0,os=-1/0,cs=null;"undefined"!==typeof FinalizationRegistry&&(cs=new FinalizationRegistry(e=>{const t=performance.now();"video"===e.type?(t-ns>=1e3&&(console.error("A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them."),ns=t),"undefined"!==typeof VideoFrame&&e.data instanceof VideoFrame&&e.data.close()):(t-os>=1e3&&(console.error("An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them."),os=t),"undefined"!==typeof AudioData&&e.data instanceof AudioData&&e.data.close())}));const ls=["I420","I420P10","I420P12","I420A","I420AP10","I420AP12","I422","I422P10","I422P12","I422A","I422AP10","I422AP12","I444","I444P10","I444P12","I444A","I444AP10","I444AP12","NV12","RGBA","RGBX","BGRA","BGRX"],us=new Set(ls);class ds{get codedWidth(){return this.visibleRect.width}get codedHeight(){return this.visibleRect.height}get displayWidth(){return this.rotation%180===0?this.squarePixelWidth:this.squarePixelHeight}get displayHeight(){return this.rotation%180===0?this.squarePixelHeight:this.squarePixelWidth}get microsecondTimestamp(){return Math.trunc(z*this.timestamp)}get microsecondDuration(){return Math.trunc(z*this.duration)}get hasAlpha(){return this.format&&this.format.includes("A")}constructor(e,t){if(this._closed=!1,e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e)){if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0===t.format||!us.has(t.format))throw new TypeError("init.format must be one of: "+ls.join(", "));if(!Number.isInteger(t.codedWidth)||t.codedWidth<=0)throw new TypeError("init.codedWidth must be a positive integer.");if(!Number.isInteger(t.codedHeight)||t.codedHeight<=0)throw new TypeError("init.codedHeight must be a positive integer.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if(void 0!==t.layout){if(!Array.isArray(t.layout))throw new TypeError("init.layout, when provided, must be an array.");for(const e of t.layout){if(!e||"object"!==typeof e||Array.isArray(e))throw new TypeError("Each entry in init.layout must be an object.");if(!Number.isInteger(e.offset)||e.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(e.stride)||e.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==t.visibleRect&&oe(t.visibleRect,"init.visibleRect"),void 0!==t.displayWidth&&(!Number.isInteger(t.displayWidth)||t.displayWidth<=0))throw new TypeError("init.displayWidth, when provided, must be a positive integer.");if(void 0!==t.displayHeight&&(!Number.isInteger(t.displayHeight)||t.displayHeight<=0))throw new TypeError("init.displayHeight, when provided, must be a positive integer.");if(void 0!==t.displayWidth!==(void 0!==t.displayHeight))throw new TypeError("init.displayWidth and init.displayHeight must be either both provided or both omitted.");this._data=o(e).slice(),this._layout=t.layout??ks(t.format,t.codedWidth,t.codedHeight),this.format=t.format,this.rotation=t.rotation??0,this.timestamp=t.timestamp,this.duration=t.duration??0,this.colorSpace=new hs(t.colorSpace),this.visibleRect={left:t.visibleRect?.left??0,top:t.visibleRect?.top??0,width:t.visibleRect?.width??t.codedWidth,height:t.visibleRect?.height??t.codedHeight},void 0!==t.displayWidth?(this.squarePixelWidth=this.rotation%180===0?t.displayWidth:t.displayHeight,this.squarePixelHeight=this.rotation%180===0?t.displayHeight:t.displayWidth):(this.squarePixelWidth=this.codedWidth,this.squarePixelHeight=this.codedHeight)}else if("undefined"!==typeof VideoFrame&&e instanceof VideoFrame){if(void 0!==t?.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(void 0!==t?.timestamp&&!Number.isFinite(t?.timestamp))throw new TypeError("init.timestamp, when provided, must be a number.");if(void 0!==t?.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");void 0!==t?.visibleRect&&oe(t.visibleRect,"init.visibleRect"),this._data=e,this._layout=null,this.format=e.format,this.visibleRect={left:e.visibleRect?.x??0,top:e.visibleRect?.y??0,width:e.visibleRect?.width??e.codedWidth,height:e.visibleRect?.height??e.codedHeight},this.rotation=t?.rotation??0,this.squarePixelWidth=e.displayWidth,this.squarePixelHeight=e.displayHeight,this.timestamp=t?.timestamp??e.timestamp/1e6,this.duration=t?.duration??(e.duration??0)/1e6,this.colorSpace=new hs(e.colorSpace)}else{if(!("undefined"!==typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!==typeof SVGImageElement&&e instanceof SVGImageElement||"undefined"!==typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!==typeof HTMLVideoElement&&e instanceof HTMLVideoElement||"undefined"!==typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!==typeof OffscreenCanvas&&e instanceof OffscreenCanvas))throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource.");{if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if("undefined"!==typeof VideoFrame)return new ds(new VideoFrame(e,{timestamp:Math.trunc(t.timestamp*z),duration:Math.trunc((t.duration??0)*z)||void 0}),t);let r=0,a=0;if("naturalWidth"in e?(r=e.naturalWidth,a=e.naturalHeight):"videoWidth"in e?(r=e.videoWidth,a=e.videoHeight):"width"in e&&(r=Number(e.width),a=Number(e.height)),!r||!a)throw new TypeError("Could not determine dimensions.");const s=new OffscreenCanvas(r,a),n=s.getContext("2d",{alpha:X(),willReadFrequently:!0});i(n),n.drawImage(e,0,0),this._data=s,this._layout=null,this.format="RGBX",this.visibleRect={left:0,top:0,width:r,height:a},this.squarePixelWidth=r,this.squarePixelHeight=a,this.rotation=t.rotation??0,this.timestamp=t.timestamp,this.duration=t.duration??0,this.colorSpace=new hs({matrix:"rgb",primaries:"bt709",transfer:"iec61966-2-1",fullRange:!0})}}this.pixelAspectRatio=ne({num:this.squarePixelWidth*this.codedHeight,den:this.squarePixelHeight*this.codedWidth}),cs?.register(this,{type:"video",data:this._data},this)}clone(){if(this._closed)throw new Error("VideoSample is closed.");return i(null!==this._data),fs(this._data)?new ds(this._data.clone(),{timestamp:this.timestamp,duration:this.duration,rotation:this.rotation}):this._data instanceof Uint8Array?(i(this._layout),new ds(this._data,{format:this.format,layout:this._layout,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation,visibleRect:this.visibleRect,displayWidth:this.displayWidth,displayHeight:this.displayHeight})):new ds(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation,visibleRect:this.visibleRect,displayWidth:this.displayWidth,displayHeight:this.displayHeight})}close(){this._closed||(cs?.unregister(this),fs(this._data)?this._data.close():this._data=null,this._closed=!0)}allocationSize(e={}){if(gs(e),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot get allocation size when format is null. Sorry!");if(i(null!==this._data),!fs(this._data)&&(e.colorSpace||e.format&&e.format!==this.format||e.layout||e.rect)){const t=this.toVideoFrame(),i=t.allocationSize(e);return t.close(),i}return fs(this._data)?this._data.allocationSize(e):this._data instanceof Uint8Array?this._data.byteLength:this.codedWidth*this.codedHeight*4}async copyTo(e,t={}){if(!k(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(gs(t),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot copy video sample data when format is null. Sorry!");if(i(null!==this._data),!fs(this._data)&&(t.colorSpace||t.format&&t.format!==this.format||t.layout||t.rect)){const i=this.toVideoFrame(),r=await i.copyTo(e,t);return i.close(),r}if(fs(this._data))return this._data.copyTo(e,t);if(this._data instanceof Uint8Array){i(this._layout);return o(e).set(this._data),this._layout}{const t=this._data.getContext("2d");i(t);const r=t.getImageData(0,0,this.codedWidth,this.codedHeight);return o(e).set(r.data),[{offset:0,stride:4*this.codedWidth}]}}toVideoFrame(){if(this._closed)throw new Error("VideoSample is closed.");return i(null!==this._data),fs(this._data)?new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0}):this._data instanceof Uint8Array?new VideoFrame(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0,colorSpace:this.colorSpace}):new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0})}draw(e,t,i,r,a,s,n,o,c){let l=0,u=0,d=this.displayWidth,h=this.displayHeight,f=0,m=0,p=this.displayWidth,g=this.displayHeight;if(void 0!==s?(l=t,u=i,d=r,h=a,f=s,m=n,void 0!==o?(p=o,g=c):(p=d,g=h)):(f=t,m=i,void 0!==r&&(p=r,g=a)),!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!Number.isFinite(l))throw new TypeError("sx must be a number.");if(!Number.isFinite(u))throw new TypeError("sy must be a number.");if(!Number.isFinite(d)||d<0)throw new TypeError("sWidth must be a non-negative number.");if(!Number.isFinite(h)||h<0)throw new TypeError("sHeight must be a non-negative number.");if(!Number.isFinite(f))throw new TypeError("dx must be a number.");if(!Number.isFinite(m))throw new TypeError("dy must be a number.");if(!Number.isFinite(p)||p<0)throw new TypeError("dWidth must be a non-negative number.");if(!Number.isFinite(g)||g<0)throw new TypeError("dHeight must be a non-negative number.");if(this._closed)throw new Error("VideoSample is closed.");({sx:l,sy:u,sWidth:d,sHeight:h}=this._rotateSourceRegion(l,u,d,h,this.rotation));const k=this.toCanvasImageSource();e.save();const b=f+p/2,y=m+g/2;e.translate(b,y),e.rotate(this.rotation*Math.PI/180);const w=this.rotation%180===0?1:p/g;e.scale(1/w,w),e.drawImage(k,l,u,d,h,-p/2,-g/2,p,g),e.restore()}drawWithFit(e,t){if(!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!["fill","contain","cover"].includes(t.fit))throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270.");void 0!==t.crop&&ps(t.crop,"options.");const i=e.canvas.width,r=e.canvas.height,a=t.rotation??this.rotation,[s,n]=a%180===0?[this.squarePixelWidth,this.squarePixelHeight]:[this.squarePixelHeight,this.squarePixelWidth];let o,c,l,u;t.crop&&ms(t.crop,s,n);const{sx:d,sy:h,sWidth:f,sHeight:m}=this._rotateSourceRegion(t.crop?.left??0,t.crop?.top??0,t.crop?.width??s,t.crop?.height??n,a);if("fill"===t.fit)o=0,c=0,l=i,u=r;else{const[e,a]=t.crop?[t.crop.width,t.crop.height]:[s,n],d="contain"===t.fit?Math.min(i/e,r/a):Math.max(i/e,r/a);l=e*d,u=a*d,o=(i-l)/2,c=(r-u)/2}e.save();const p=a%180===0?1:l/u;e.translate(i/2,r/2),e.rotate(a*Math.PI/180),e.scale(1/p,p),e.translate(-i/2,-r/2),e.drawImage(this.toCanvasImageSource(),d,h,f,m,o,c,l,u),e.restore()}_rotateSourceRegion(e,t,i,r,a){return 90===a?[e,t,i,r]=[t,this.squarePixelHeight-e-i,r,i]:180===a?[e,t]=[this.squarePixelWidth-e-i,this.squarePixelHeight-t-r]:270===a&&([e,t,i,r]=[this.squarePixelWidth-t-r,e,r,i]),{sx:e,sy:t,sWidth:i,sHeight:r}}toCanvasImageSource(){if(this._closed)throw new Error("VideoSample is closed.");if(i(null!==this._data),this._data instanceof Uint8Array){const e=this.toVideoFrame();return queueMicrotask(()=>e.close()),e}return this._data}setRotation(e){if(![0,90,180,270].includes(e))throw new TypeError("newRotation must be 0, 90, 180, or 270.");this.rotation=e}setTimestamp(e){if(!Number.isFinite(e))throw new TypeError("newTimestamp must be a number.");this.timestamp=e}setDuration(e){if(!Number.isFinite(e)||e<0)throw new TypeError("newDuration must be a non-negative number.");this.duration=e}[Symbol.dispose](){this.close()}}class hs{constructor(e){if(void 0!==e){if(!e||"object"!==typeof e)throw new TypeError("init.colorSpace, when provided, must be an object.");const t=Object.keys(d);if(null!=e.primaries&&!t.includes(e.primaries))throw new TypeError(`init.colorSpace.primaries, when provided, must be one of ${t.join(", ")}.`);const i=Object.keys(f);if(null!=e.transfer&&!i.includes(e.transfer))throw new TypeError(`init.colorSpace.transfer, when provided, must be one of ${i.join(", ")}.`);const r=Object.keys(p);if(null!=e.matrix&&!r.includes(e.matrix))throw new TypeError(`init.colorSpace.matrix, when provided, must be one of ${r.join(", ")}.`);if(null!=e.fullRange&&"boolean"!==typeof e.fullRange)throw new TypeError("init.colorSpace.fullRange, when provided, must be a boolean.")}this.primaries=e?.primaries??null,this.transfer=e?.transfer??null,this.matrix=e?.matrix??null,this.fullRange=e?.fullRange??null}toJSON(){return{primaries:this.primaries,transfer:this.transfer,matrix:this.matrix,fullRange:this.fullRange}}}const fs=e=>"undefined"!==typeof VideoFrame&&e instanceof VideoFrame,ms=(e,t,r)=>{const a=Math.min(e.left,t),s=Math.min(e.top,r),n=Math.min(e.width,t-a),o=Math.min(e.height,r-s);return i(n>=0),i(o>=0),{left:a,top:s,width:n,height:o}},ps=(e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(t+"crop, when provided, must be an object.");if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(t+"crop.left must be a non-negative integer.");if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(t+"crop.top must be a non-negative integer.");if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(t+"crop.width must be a non-negative integer.");if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(t+"crop.height must be a non-negative integer.")},gs=e=>{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.colorSpace&&!["display-p3","srgb"].includes(e.colorSpace))throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");if(void 0!==e.format&&"string"!==typeof e.format)throw new TypeError("options.format, when provided, must be a string.");if(void 0!==e.layout){if(!Array.isArray(e.layout))throw new TypeError("options.layout, when provided, must be an array.");for(const t of e.layout){if(!t||"object"!==typeof t)throw new TypeError("Each entry in options.layout must be an object.");if(!Number.isInteger(t.offset)||t.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(t.stride)||t.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==e.rect){if(!e.rect||"object"!==typeof e.rect)throw new TypeError("options.rect, when provided, must be an object.");if(void 0!==e.rect.x&&(!Number.isInteger(e.rect.x)||e.rect.x<0))throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");if(void 0!==e.rect.y&&(!Number.isInteger(e.rect.y)||e.rect.y<0))throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");if(void 0!==e.rect.width&&(!Number.isInteger(e.rect.width)||e.rect.width<0))throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");if(void 0!==e.rect.height&&(!Number.isInteger(e.rect.height)||e.rect.height<0))throw new TypeError("options.rect.height, when provided, must be a non-negative integer.")}},ks=(e,t,i)=>{const r=bs(e),a=[];let s=0;for(const n of r){const e=Math.ceil(t/n.widthDivisor),r=Math.ceil(i/n.heightDivisor),o=e*n.sampleBytes,c=o*r;a.push({offset:s,stride:o}),s+=c}return a},bs=e=>{const t=(e,t,i,r,a)=>{const s=[{sampleBytes:e,widthDivisor:1,heightDivisor:1},{sampleBytes:t,widthDivisor:i,heightDivisor:r},{sampleBytes:t,widthDivisor:i,heightDivisor:r}];return a&&s.push({sampleBytes:e,widthDivisor:1,heightDivisor:1}),s};switch(e){case"I420":return t(1,1,2,2,!1);case"I420P10":case"I420P12":return t(2,2,2,2,!1);case"I420A":return t(1,1,2,2,!0);case"I420AP10":case"I420AP12":return t(2,2,2,2,!0);case"I422":return t(1,1,2,1,!1);case"I422P10":case"I422P12":return t(2,2,2,1,!1);case"I422A":return t(1,1,2,1,!0);case"I422AP10":case"I422AP12":return t(2,2,2,1,!0);case"I444":return t(1,1,1,1,!1);case"I444P10":case"I444P12":return t(2,2,1,1,!1);case"I444A":return t(1,1,1,1,!0);case"I444AP10":case"I444AP12":return t(2,2,1,1,!0);case"NV12":return[{sampleBytes:1,widthDivisor:1,heightDivisor:1},{sampleBytes:2,widthDivisor:2,heightDivisor:2}];case"RGBA":case"RGBX":case"BGRA":case"BGRX":return[{sampleBytes:4,widthDivisor:1,heightDivisor:1}];default:B(e),i(!1)}},ys=new Set(["f32","f32-planar","s16","s16-planar","s32","s32-planar","u8","u8-planar"]);class ws{get microsecondTimestamp(){return Math.trunc(z*this.timestamp)}get microsecondDuration(){return Math.trunc(z*this.duration)}constructor(e){if(this._closed=!1,Is(e)){if(null===e.format)throw new TypeError("AudioData with null format is not supported.");this._data=e,this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=e.numberOfFrames,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp/1e6,this.duration=e.numberOfFrames/e.sampleRate}else{if(!e||"object"!==typeof e)throw new TypeError("Invalid AudioDataInit: must be an object.");if(!ys.has(e.format))throw new TypeError("Invalid AudioDataInit: invalid format.");if(!Number.isFinite(e.sampleRate)||e.sampleRate<=0)throw new TypeError("Invalid AudioDataInit: sampleRate must be > 0.");if(!Number.isInteger(e.numberOfChannels)||0===e.numberOfChannels)throw new TypeError("Invalid AudioDataInit: numberOfChannels must be an integer > 0.");if(!Number.isFinite(e?.timestamp))throw new TypeError("init.timestamp must be a number.");const t=e.data.byteLength/(Ts(e.format)*e.numberOfChannels);if(!Number.isInteger(t))throw new TypeError("Invalid AudioDataInit: data size is not a multiple of frame size.");let i;if(this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=t,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp,this.duration=t/e.sampleRate,e.data instanceof ArrayBuffer)i=new Uint8Array(e.data);else{if(!ArrayBuffer.isView(e.data))throw new TypeError("Invalid AudioDataInit: data is not a BufferSource.");i=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength)}const r=this.numberOfFrames*this.numberOfChannels*Ts(this.format);if(i.byteLength=this.numberOfFrames)throw new RangeError("frameOffset out of range");const r=void 0!==e.frameCount?e.frameCount:this.numberOfFrames-i;if(r>this.numberOfFrames-i)throw new RangeError("frameCount out of range");const a=Ts(t),s=Ss(t);if(s&&e.planeIndex>=this.numberOfChannels)throw new RangeError("planeIndex out of range");if(!s&&0!==e.planeIndex)throw new RangeError("planeIndex out of range");return(s?r:r*this.numberOfChannels)*a}copyTo(e,t){if(!k(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!Number.isInteger(t.planeIndex)||t.planeIndex<0)throw new TypeError("planeIndex must be a non-negative integer.");if(void 0!==t.format&&!ys.has(t.format))throw new TypeError("Invalid format.");if(void 0!==t.frameOffset&&(!Number.isInteger(t.frameOffset)||t.frameOffset<0))throw new TypeError("frameOffset must be a non-negative integer.");if(void 0!==t.frameCount&&(!Number.isInteger(t.frameCount)||t.frameCount<0))throw new TypeError("frameCount must be a non-negative integer.");if(this._closed)throw new Error("AudioSample is closed.");const{planeIndex:i,format:r,frameCount:a,frameOffset:s}=t,n=this.format,o=r??this.format;if(!o)throw new Error("Destination format not determined");const l=this.numberOfFrames,u=this.numberOfChannels,d=s??0;if(d>=l)throw new RangeError("frameOffset out of range");const h=void 0!==a?a:l-d;if(h>l-d)throw new RangeError("frameCount out of range");const f=Ts(o),m=Ss(o);if(m&&i>=u)throw new RangeError("planeIndex out of range");if(!m&&0!==i)throw new RangeError("planeIndex out of range");const p=(m?h:h*u)*f;if(e.byteLength2&&o!==n?xs(this._data,g,n,o,u,i,d,h):this._data.copyTo(e,{planeIndex:i,frameOffset:d,frameCount:h,format:o});else{const e=this._data,t=c(e),r=Ps(n),a=Ts(n),s=Ss(n);for(let n=0;n0;){const a=Math.min(s,o),c=new Float32Array(i*a);for(let t=0;t0;){const a=Math.min(s,o),l=new Float32Array(i*a);for(let t=0;t{switch(e){case"u8":case"u8-planar":return 1;case"s16":case"s16-planar":return 2;case"s32":case"s32-planar":case"f32":case"f32-planar":return 4;default:throw new Error("Unknown AudioSampleFormat")}},Ss=e=>{switch(e){case"u8-planar":case"s16-planar":case"s32-planar":case"f32-planar":return!0;default:return!1}},Ps=e=>{switch(e){case"u8":case"u8-planar":return(e,t)=>(e.getUint8(t)-128)/128;case"s16":case"s16-planar":return(e,t)=>e.getInt16(t,!0)/32768;case"s32":case"s32-planar":return(e,t)=>e.getInt32(t,!0)/2147483648;case"f32":case"f32-planar":return(e,t)=>e.getFloat32(t,!0)}},vs=e=>{switch(e){case"u8":case"u8-planar":return(e,t,i)=>e.setUint8(t,F(127.5*(i+1),0,255));case"s16":case"s16-planar":return(e,t,i)=>e.setInt16(t,F(Math.round(32767*i),-32768,32767),!0);case"s32":case"s32-planar":return(e,t,i)=>e.setInt32(t,F(Math.round(2147483647*i),-2147483648,2147483647),!0);case"f32":case"f32-planar":return(e,t,i)=>e.setFloat32(t,i,!0)}},Is=e=>"undefined"!==typeof AudioData&&e instanceof AudioData,xs=(e,t,i,r,a,s,n,o)=>{const l=Ps(i),u=vs(r),d=Ts(i),h=Ts(r),f=Ss(i);if(Ss(r))if(f){const r=new ArrayBuffer(o*d),a=c(r);e.copyTo(r,{planeIndex:s,frameOffset:n,frameCount:o,format:i});for(let e=0;e{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.metadataOnly&&"boolean"!==typeof e.metadataOnly)throw new TypeError("options.metadataOnly, when defined, must be a boolean.");if(void 0!==e.verifyKeyPackets&&"boolean"!==typeof e.verifyKeyPackets)throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");if(e.verifyKeyPackets&&e.metadataOnly)throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.");if(void 0!==e.skipLiveWait&&"boolean"!==typeof e.skipLiveWait)throw new TypeError("options.skipLiveWait, when defined, must be a boolean.")},_s=e=>{if(!ie(e))throw new TypeError("timestamp must be a number.")},As=(e,t,i)=>i.verifyKeyPackets?t.then(async t=>{if(!t||"delta"===t.type)return t;const i=await e.determinePacketType(t);return i&&(t.type=i),t}):t;class Fs{constructor(e){if(!(e instanceof Hs))throw new TypeError("track must be an InputTrack.");this._track=e}async getFirstPacket(e={}){if(Es(e),this._track.input._disposed)throw new sn;return As(this._track,this._track._backing.getFirstPacket(e),e)}async getFirstKeyPacket(e={}){Es(e);const t=await this.getFirstPacket(e);return t?"key"===t.type?t:this.getNextKeyPacket(t,e):null}async getPacket(e,t={}){if(_s(e),Es(t),this._track.input._disposed)throw new sn;return As(this._track,this._track._backing.getPacket(e,t),t)}async getNextPacket(e,t={}){if(!(e instanceof Mt))throw new TypeError("packet must be an EncodedPacket.");if(Es(t),this._track.input._disposed)throw new sn;return As(this._track,this._track._backing.getNextPacket(e,t),t)}async getKeyPacket(e,t={}){if(_s(e),Es(t),this._track.input._disposed)throw new sn;if(!t.verifyKeyPackets)return this._track._backing.getKeyPacket(e,t);const r=await this._track._backing.getKeyPacket(e,t);if(!r)return r;i("key"===r.type);return"delta"===await this._track.determinePacketType(r)?this.getKeyPacket(r.timestamp-1/await this._track.getTimeResolution(),t):r}async getNextKeyPacket(e,t={}){if(!(e instanceof Mt))throw new TypeError("packet must be an EncodedPacket.");if(Es(t),this._track.input._disposed)throw new sn;if(!t.verifyKeyPackets)return this._track._backing.getNextKeyPacket(e,t);const r=await this._track._backing.getNextKeyPacket(e,t);if(!r)return r;i("key"===r.type);return"delta"===await this._track.determinePacketType(r)?this.getNextKeyPacket(r,t):r}packets(e,t,i={}){if(void 0!==e&&!(e instanceof Mt))throw new TypeError("startPacket must be an EncodedPacket.");if(void 0!==e&&e.isMetadataOnly&&!i?.metadataOnly)throw new TypeError("startPacket can only be metadata-only if options.metadataOnly is enabled.");if(void 0!==t&&!(t instanceof Mt))throw new TypeError("endPacket must be an EncodedPacket.");if(Es(i),this._track.input._disposed)throw new sn;const r=[];let{promise:a,resolve:s}=I(),{promise:n,resolve:o}=I(),c=!1,l=!1,u=null;const d=[],h=()=>Math.max(2,d.length);(async()=>{let u=e??await this.getFirstPacket(i);for(;u&&!l&&!this._track.input._disposed&&!(t&&u.sequenceNumber>=t?.sequenceNumber);)r.length>h()?(({promise:n,resolve:o}=I()),await n):(r.push(u),s(),({promise:a,resolve:s}=I()),u=await this.getNextPacket(u,i));c=!0,s()})().catch(e=>{u||(u=e,s())});const f=this._track;return{async next(){for(;;){if(f.input._disposed)throw new sn;if(l)return{value:void 0,done:!0};if(u)throw u;if(r.length>0){const e=r.shift(),t=performance.now();for(d.push(t);d.length>0&&t-d[0]>=1e3;)d.shift();return o(),{value:e,done:!1}}if(c)return{value:void 0,done:!0};await a}},return:async()=>(l=!0,o(),s(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}}class Rs{constructor(e,t){this.onSample=e,this.onError=t}}class Ds{mediaSamplesInRange(e=0,t=1/0,i){_s(e),_s(t);const r=[];let a=!1,s=null,{promise:n,resolve:o}=I(),{promise:c,resolve:l}=I(),u=!1,d=!1,h=!1,f=null;const m={...i,verifyKeyPackets:!0,metadataOnly:!1};(async()=>{const i=await this._createDecoder(i=>{l(),i.timestamp>=t&&(d=!0),d?i.close():(s&&(i.timestamp>e?(r.push(s),a=!0):s.close()),i.timestamp>=e&&(r.push(i),a=!0),s=a?null:i,r.length>0&&(o(),({promise:n,resolve:o}=I())))},e=>{f||(f=e,o())}),p=this._createPacketSink(),g=await p.getKeyPacket(e,m)??await p.getFirstKeyPacket(m);let k=g;const b=p.packets(g??void 0,void 0,m);for(await b.next();k&&!d&&!this._track.input._disposed;){const e=Ms(r.length);if(r.length+i.getDecodeQueueSize()>e){({promise:c,resolve:l}=I()),await c;continue}i.decode(k);const t=await b.next();if(t.done)break;k=t.value}await b.return(),h||this._track.input._disposed||await i.flush(),i.close(),!a&&s&&r.push(s),u=!0,o()})().catch(e=>{f||(f=e,o())});const p=this._track,g=()=>{s?.close();for(const e of r)e.close()};return{async next(){for(;;){if(p.input._disposed)throw g(),new sn;if(h)return{value:void 0,done:!0};if(f)throw g(),f;if(r.length>0){const e=r.shift();return l(),{value:e,done:!1}}if(u)return{value:void 0,done:!0};await n}},return:async()=>(h=!0,d=!0,l(),o(),g(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}mediaSamplesAtTimestamps(e,t){(e=>{if(!(Symbol.iterator in e)&&!(Symbol.asyncIterator in e))throw new TypeError("Argument must be an iterable or async iterable.")})(e);const r=async function*(e){Symbol.iterator in e?yield*e[Symbol.iterator]():yield*e[Symbol.asyncIterator]()}(e),a=[],s=[];let{promise:n,resolve:o}=I(),{promise:c,resolve:l}=I(),u=!1,d=!1,h=null;const f=e=>{s.push(e),o(),({promise:n,resolve:o}=I())},m={...t,verifyKeyPackets:!0,metadataOnly:!1};(async()=>{const e=await this._createDecoder(e=>{if(l(),d)return void e.close();let t=0;for(;a.length>0&&e.timestamp-a[0]>-1e-10;)t++,a.shift();if(t>0)for(let i=0;i{h||(h=e,o())}),t=this._createPacketSink();let n=null,p=null,g=-1;const k=async()=>{i(p);let r=p;for(e.decode(r);r.sequenceNumbera&&!d;)({promise:c,resolve:l}=I()),await c;if(d)break;const n=await t.getNextPacket(r,m);i(n),e.decode(n),r=n}g=-1},b=async()=>{await e.flush();for(let e=0;e{h||(h=e,o())});const p=this._track,g=()=>{for(const e of s)e?.close()};return{async next(){for(;;){if(p.input._disposed)throw g(),new sn;if(d)return{value:void 0,done:!0};if(h)throw g(),h;if(s.length>0){const e=s.shift();return i(void 0!==e),l(),{value:e,done:!1}}if(u)return{value:void 0,done:!0};await n}},return:async()=>(d=!0,l(),o(),g(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}}const Ms=e=>0===e?40:8;class Ns extends Rs{constructor(e,t,r,a,s,n){super(e,t),this.codec=r,this.decoderConfig=a,this.rotation=s,this.timeResolution=n,this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new V,this.customDecoderQueueSize=0,this.inputTimestamps=[],this.sampleQueue=[],this.currentPacketIndex=0,this.raslSkipped=!1,this.alphaDecoder=null,this.alphaHadKeyframe=!1,this.colorQueue=[],this.alphaQueue=[],this.merger=null,this.mergerCreationFailed=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue=[],this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1;const l=Cs.find(e=>e.supports(r,a));if(l)this.customDecoder=new l,this.customDecoder.codec=r,this.customDecoder.config=a,this.customDecoder.onSample=e=>{if(!(e instanceof ds))throw new TypeError("The argument passed to onSample must be a VideoSample.");this.finalizeAndEmitSample(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=e=>{if(this.alphaQueue.length>0){const t=this.alphaQueue.shift();i(void 0!==t),this.mergeAlpha(e,t)}else this.colorQueue.push(e)};if("avc"===r&&this.decoderConfig.description&&Q()){const e=(e=>{try{const t=c(e);let i=0;const r=t.getUint8(i++),a=t.getUint8(i++),s=t.getUint8(i++),n=t.getUint8(i++),o=3&t.getUint8(i++),l=31&t.getUint8(i++),u=[];for(let c=0;c0){const t=tt(e.sequenceParameterSets[0]);t&&0===t.frameMbsOnlyFlag&&(this.decoderConfig={...this.decoderConfig,hardwareAcceleration:"prefer-software"})}}const t=new Error("Decoding error").stack;this.decoder=new VideoDecoder({output:t=>{try{e(t)}catch(i){this.onError(i)}},error:e=>{e.stack=t,this.onError(e)}}),this.decoder.configure(this.decoderConfig)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(i(this.decoder),Math.max(this.decoder.decodeQueueSize,this.alphaDecoder?.decodeQueueSize??0))}decode(e){if("hevc"===this.codec&&this.currentPacketIndex>0&&!this.raslSkipped){if(this.hasHevcRaslPicture(e.data))return;this.raslSkipped=!0}if(this.customDecoder)this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--);else{if(i(this.decoder),K()||v(this.inputTimestamps,e.timestamp,e=>e),Q()&&0===this.currentPacketIndex)if("avc"===this.codec){const t=[];for(const r of Xe(e.data,this.decoderConfig)){const i=$e(e.data[r.offset]);i>=20&&i<=31||t.push(e.data.subarray(r.offset,r.offset+r.length))}const i=((e,t)=>{if(t.description){const i=3&o(t.description)[4];return Je(e,i+1)}return Ye(e)})(t,this.decoderConfig);e=new Mt(i,e.type,e.timestamp,e.duration)}else if("hevc"===this.codec){const t=gt(e.data,this.decoderConfig);t&&(e=new Mt(t,e.type,e.timestamp,e.duration))}this.decoder.decode(e.toEncodedVideoChunk()),this.decodeAlphaData(e)}this.currentPacketIndex++}decodeAlphaData(e){if(!e.sideData.alpha||this.mergerCreationFailed)return void this.pushNullAlphaFrame();if(!this.merger)try{this.merger=new Os}catch(r){return console.error("Due to an error, only color data will be decoded.",r),this.mergerCreationFailed=!0,void this.decodeAlphaData(e)}if(!this.alphaDecoder){const e=e=>{if(this.alphaDecoderQueueSize--,this.colorQueue.length>0){const t=this.colorQueue.shift();i(void 0!==t),this.mergeAlpha(t,e)}else this.alphaQueue.push(e);for(this.decodedAlphaChunkCount++;this.nullAlphaFrameQueue.length>0&&this.nullAlphaFrameQueue[0]===this.decodedAlphaChunkCount;)if(this.nullAlphaFrameQueue.shift(),this.colorQueue.length>0){const e=this.colorQueue.shift();i(void 0!==e),this.mergeAlpha(e,null)}else this.alphaQueue.push(null)},t=new Error("Decoding error").stack;this.alphaDecoder=new VideoDecoder({output:t=>{try{e(t)}catch(r){this.onError(r)}},error:e=>{e.stack=t,this.onError(e)}}),this.alphaDecoder.configure(this.decoderConfig)}const t=St(this.codec,this.decoderConfig,e.sideData.alpha);if(this.alphaHadKeyframe||(this.alphaHadKeyframe="key"===t),this.alphaHadKeyframe){if("hevc"===this.codec&&this.currentAlphaPacketIndex>0&&!this.alphaRaslSkipped){if(this.hasHevcRaslPicture(e.sideData.alpha))return void this.pushNullAlphaFrame();this.alphaRaslSkipped=!0}this.currentAlphaPacketIndex++,this.alphaDecoder.decode(e.alphaToEncodedVideoChunk(t??e.type)),this.alphaDecoderQueueSize++}else this.pushNullAlphaFrame()}pushNullAlphaFrame(){0===this.alphaDecoderQueueSize?this.alphaQueue.push(null):this.nullAlphaFrameQueue.push(this.decodedAlphaChunkCount+this.alphaDecoderQueueSize)}hasHevcRaslPicture(e){for(const t of rt(e,this.decoderConfig)){const i=at(e[t.offset]);if(i===Ve.RASL_N||i===Ve.RASL_R)return!0}return!1}sampleHandler(e){if(K()){if(this.sampleQueue.length>0&&e.timestamp>=a(this.sampleQueue).timestamp){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}v(this.sampleQueue,e,e=>e.timestamp)}else{const t=this.inputTimestamps.shift();i(void 0!==t),e.setTimestamp(t),this.finalizeAndEmitSample(e)}}finalizeAndEmitSample(e){e.setTimestamp(Math.round(e.timestamp*this.timeResolution)/this.timeResolution),e.setDuration(Math.round(e.duration*this.timeResolution)/this.timeResolution),e.setRotation(this.rotation),this.onSample(e)}mergeAlpha(e,t){if(!t){const t=new ds(e);return void this.sampleHandler(t)}i(this.merger),this.merger.update(e,t),e.close(),t.close();const r=new VideoFrame(this.merger.canvas,{timestamp:e.timestamp,duration:e.duration??void 0}),a=new ds(r);this.sampleHandler(a)}async flush(){if(this.customDecoder?await this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(i(this.decoder),await Promise.all([this.decoder.flush(),this.alphaDecoder?.flush()]),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>e?.close()),this.alphaQueue.length=0,this.alphaHadKeyframe=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue.length=0,this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1),K()){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}this.currentPacketIndex=0,this.raslSkipped=!1}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(i(this.decoder),this.decoder.close(),this.alphaDecoder?.close(),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>e?.close()),this.alphaQueue.length=0,this.merger?.close());for(const e of this.sampleQueue)e.close();this.sampleQueue.length=0}}class Os{constructor(){"undefined"!==typeof OffscreenCanvas?this.canvas=new OffscreenCanvas(300,150):this.canvas=document.createElement("canvas");const e=this.canvas.getContext("webgl2",{premultipliedAlpha:!1});if(!e)throw new Error("Couldn't acquire WebGL 2 context.");this.gl=e,this.program=this.createProgram(),this.vao=this.createVAO(),this.colorTexture=this.createTexture(),this.alphaTexture=this.createTexture(),this.gl.useProgram(this.program),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_colorTexture"),0),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_alphaTexture"),1)}createProgram(){const e=this.createShader(this.gl.VERTEX_SHADER,"#version 300 es\n\t\t\tin vec2 a_position;\n\t\t\tin vec2 a_texCoord;\n\t\t\tout vec2 v_texCoord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = vec4(a_position, 0.0, 1.0);\n\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t}\n\t\t"),t=this.createShader(this.gl.FRAGMENT_SHADER,"#version 300 es\n\t\t\tprecision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_colorTexture;\n\t\t\tuniform sampler2D u_alphaTexture;\n\t\t\tin vec2 v_texCoord;\n\t\t\tout vec4 fragColor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture(u_colorTexture, v_texCoord).rgb;\n\t\t\t\tfloat alpha = texture(u_alphaTexture, v_texCoord).r;\n\t\t\t\tfragColor = vec4(color, alpha);\n\t\t\t}\n\t\t"),i=this.gl.createProgram();return this.gl.attachShader(i,e),this.gl.attachShader(i,t),this.gl.linkProgram(i),i}createShader(e,t){const i=this.gl.createShader(e);return this.gl.shaderSource(i,t),this.gl.compileShader(i),i}createVAO(){const e=this.gl.createVertexArray();this.gl.bindVertexArray(e);const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,i),this.gl.bufferData(this.gl.ARRAY_BUFFER,t,this.gl.STATIC_DRAW);const r=this.gl.getAttribLocation(this.program,"a_position"),a=this.gl.getAttribLocation(this.program,"a_texCoord");return this.gl.enableVertexAttribArray(r),this.gl.vertexAttribPointer(r,2,this.gl.FLOAT,!1,16,0),this.gl.enableVertexAttribArray(a),this.gl.vertexAttribPointer(a,2,this.gl.FLOAT,!1,16,8),e}createTexture(){const e=this.gl.createTexture();return this.gl.bindTexture(this.gl.TEXTURE_2D,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),e}update(e,t){e.displayWidth===this.canvas.width&&e.displayHeight===this.canvas.height||(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colorTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),this.gl.activeTexture(this.gl.TEXTURE1),this.gl.bindTexture(this.gl.TEXTURE_2D,this.alphaTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.bindVertexArray(this.vao),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)}close(){this.gl.getExtension("WEBGL_lose_context")?.loseContext(),this.gl=null}}class Ls extends Ds{constructor(e){if(!(e instanceof Xs))throw new TypeError("videoTrack must be an InputVideoTrack.");super(),this._track=e}async _createDecoder(e,t){if(!(await this._track.canDecode()))throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track.");const r=await this._track.getCodec(),a=await this._track.getRotation(),s=await this._track.getDecoderConfig(),n=await this._track.getTimeResolution();return i(r&&s),new Ns(e,t,r,s,a,n)}_createPacketSink(){return new Fs(this._track)}async getSample(e,t={}){_s(e);for await(const i of this.mediaSamplesAtTimestamps([e],t))return i;throw new Error("Internal error: Iterator returned nothing.")}samples(e=0,t=1/0,i={}){return this.mediaSamplesInRange(e,t,i)}samplesAtTimestamps(e,t={}){return this.mediaSamplesAtTimestamps(e,t)}}class zs{constructor(e,t={}){if(this._rotation=0,this._initPromise=null,this._nextCanvasIndex=0,!(e instanceof Xs))throw new TypeError("videoTrack must be an InputVideoTrack.");if(t&&"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.alpha&&"boolean"!==typeof t.alpha)throw new TypeError("options.alpha, when provided, must be a boolean.");if(void 0!==t.width&&(!Number.isInteger(t.width)||t.width<=0))throw new TypeError("options.width, when defined, must be a positive integer.");if(void 0!==t.height&&(!Number.isInteger(t.height)||t.height<=0))throw new TypeError("options.height, when defined, must be a positive integer.");if(void 0!==t.fit&&!["fill","contain","cover"].includes(t.fit))throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".');if(void 0!==t.width&&void 0!==t.height&&void 0===t.fit)throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180 or 270.");if(void 0!==t.crop&&ps(t.crop,"options."),void 0!==t.poolSize&&("number"!==typeof t.poolSize||!Number.isInteger(t.poolSize)||t.poolSize<0))throw new TypeError("poolSize must be a non-negative integer.");this._videoTrack=e,this._alpha=t.alpha??!1,this._options=t,this._fit=t.fit??"fill",this._videoSampleSink=new Ls(e),this._canvasPool=Array.from({length:t.poolSize??0},()=>null)}_ensureInit(){return this._initPromise??(this._initPromise=(async()=>{const e=this._options,t=this._videoTrack,i=e.rotation??await t.getRotation(),r=await t.getSquarePixelWidth(),a=await t.getSquarePixelHeight(),[s,n]=i%180===0?[r,a]:[a,r];let o=e.crop;o&&(o=ms(o,s,n));let[c,l]=o?[o.width,o.height]:[s,n];const u=c/l;void 0!==e.width&&void 0===e.height?(c=e.width,l=Math.round(c/u)):void 0===e.width&&void 0!==e.height?(l=e.height,c=Math.round(l*u)):void 0!==e.width&&void 0!==e.height&&(c=e.width,l=e.height),this._width=c,this._height=l,this._rotation=i,this._crop=o})())}_videoSampleToWrappedCanvas(e){const t=this._width,r=this._height;let a=this._canvasPool[this._nextCanvasIndex],s=!1;a||("undefined"!==typeof document?(a=document.createElement("canvas"),a.width=t,a.height=r):a=new OffscreenCanvas(t,r),this._canvasPool.length>0&&(this._canvasPool[this._nextCanvasIndex]=a),s=!0),this._canvasPool.length>0&&(this._nextCanvasIndex=(this._nextCanvasIndex+1)%this._canvasPool.length);const n=a.getContext("2d",{alpha:this._alpha||X()});i(n),n.resetTransform(),s||(!this._alpha&&X()?(n.fillStyle="black",n.fillRect(0,0,t,r)):n.clearRect(0,0,t,r)),e.drawWithFit(n,{fit:this._fit,rotation:this._rotation,crop:this._crop});const o={canvas:a,timestamp:e.timestamp,duration:e.duration};return e.close(),o}async getCanvas(e,t){_s(e),await this._ensureInit();const i=await this._videoSampleSink.getSample(e,t);return i&&this._videoSampleToWrappedCanvas(i)}async*canvases(e=0,t=1/0,i){await this._ensureInit(),yield*A(this._videoSampleSink.samples(e,t,i),e=>this._videoSampleToWrappedCanvas(e))}async*canvasesAtTimestamps(e,t){await this._ensureInit(),yield*A(this._videoSampleSink.samplesAtTimestamps(e,t),e=>e&&this._videoSampleToWrappedCanvas(e))}}class Us extends Rs{constructor(e,t,i,r){super(e,t),this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new V,this.customDecoderQueueSize=0,this.currentTimestamp=null;const a=t=>{(null===this.currentTimestamp||Math.abs(t.timestamp-this.currentTimestamp)>=t.duration)&&(this.currentTimestamp=t.timestamp);const i=this.currentTimestamp;if(this.currentTimestamp+=t.duration,0===t.numberOfFrames)return void t.close();const a=r.sampleRate;t.setTimestamp(Math.round(i*a)/a),e(t)},s=Bs.find(e=>e.supports(i,r));if(s)this.customDecoder=new s,this.customDecoder.codec=i,this.customDecoder.config=r,this.customDecoder.onSample=e=>{if(!(e instanceof ws))throw new TypeError("The argument passed to onSample must be an AudioSample.");a(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=new Error("Decoding error").stack;this.decoder=new AudioDecoder({output:e=>{try{a(new ws(e))}catch(t){this.onError(t)}},error:t=>{t.stack=e,this.onError(t)}}),this.decoder.configure(r)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(i(this.decoder),this.decoder.decodeQueueSize)}decode(e){this.customDecoder?(this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--)):(i(this.decoder),this.decoder.decode(e.toEncodedAudioChunk()))}flush(){return this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(i(this.decoder),this.decoder.flush())}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(i(this.decoder),this.decoder.close())}}class qs extends Rs{constructor(e,t,r){super(e,t),this.decoderConfig=r,this.currentTimestamp=null,i(be.includes(r.codec)),this.codec=r.codec;const{dataType:a,sampleSize:s,littleEndian:n}=Be(this.codec);switch(this.inputSampleSize=s,s){case 1:"unsigned"===a?this.readInputValue=(e,t)=>e.getUint8(t)-128:"signed"===a?this.readInputValue=(e,t)=>e.getInt8(t):"ulaw"===a?this.readInputValue=(e,t)=>(e=>{let t=0,i=0,r=~e;128&r&&(r&=-129,t=-1),i=5+((240&r)>>4);const a=(1<(e=>{let t=0,i=0,r=85^e;128&r&&(r&=-129,t=-1),i=4+((240&r)>>4);let a=0;return a=4!==i?1<e.getUint16(t,n)-32768:"signed"===a?this.readInputValue=(e,t)=>e.getInt16(t,n):i(!1);break;case 3:"unsigned"===a?this.readInputValue=(e,t)=>E(e,t,n)-2**23:"signed"===a?this.readInputValue=(e,t)=>((e,t,i)=>E(e,t,i)<<8>>8)(e,t,n):i(!1);break;case 4:"unsigned"===a?this.readInputValue=(e,t)=>e.getUint32(t,n)-2**31:"signed"===a?this.readInputValue=(e,t)=>e.getInt32(t,n):"float"===a?this.readInputValue=(e,t)=>e.getFloat32(t,n):i(!1);break;case 8:"float"===a?this.readInputValue=(e,t)=>e.getFloat64(t,n):i(!1);break;default:B(s),i(!1)}switch(s){case 1:"ulaw"===a||"alaw"===a?(this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,i)=>e.setInt16(t,i,!0)):(this.outputSampleSize=1,this.outputFormat="u8",this.writeOutputValue=(e,t,i)=>e.setUint8(t,i+128));break;case 2:this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,i)=>e.setInt16(t,i,!0);break;case 3:this.outputSampleSize=4,this.outputFormat="s32",this.writeOutputValue=(e,t,i)=>e.setInt32(t,i<<8,!0);break;case 4:this.outputSampleSize=4,"float"===a?(this.outputFormat="f32",this.writeOutputValue=(e,t,i)=>e.setFloat32(t,i,!0)):(this.outputFormat="s32",this.writeOutputValue=(e,t,i)=>e.setInt32(t,i,!0));break;case 8:this.outputSampleSize=4,this.outputFormat="f32",this.writeOutputValue=(e,t,i)=>e.setFloat32(t,i,!0);break;default:B(s),i(!1)}}getDecodeQueueSize(){return 0}decode(e){const t=c(e.data),i=e.byteLength/this.decoderConfig.numberOfChannels/this.inputSampleSize,r=i*this.decoderConfig.numberOfChannels*this.outputSampleSize,a=new ArrayBuffer(r),s=new DataView(a);for(let c=0;c=n)&&(this.currentTimestamp=e.timestamp);const o=this.currentTimestamp;this.currentTimestamp+=n;const l=new ws({format:this.outputFormat,data:a,numberOfChannels:this.decoderConfig.numberOfChannels,sampleRate:this.decoderConfig.sampleRate,numberOfFrames:i,timestamp:o});this.onSample(l)}async flush(){}close(){}}class Ws extends Ds{constructor(e){if(!(e instanceof $s))throw new TypeError("audioTrack must be an InputAudioTrack.");super(),this._track=e}async _createDecoder(e,t){if(!(await this._track.canDecode()))throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track.");const r=await this._track.getCodec(),a=await this._track.getDecoderConfig();return i(r&&a),be.includes(a.codec)?new qs(e,t,a):new Us(e,t,r,a)}_createPacketSink(){return new Fs(this._track)}async getSample(e,t={}){_s(e);for await(const i of this.mediaSamplesAtTimestamps([e],t))return i;throw new Error("Internal error: Iterator returned nothing.")}samples(e=0,t=1/0,i={}){return this.mediaSamplesInRange(e,t,i)}samplesAtTimestamps(e,t={}){return this.mediaSamplesAtTimestamps(e,t)}}class Vs{constructor(e){if(!(e instanceof $s))throw new TypeError("audioTrack must be an InputAudioTrack.");this._audioSampleSink=new Ws(e)}_audioSampleToWrappedArrayBuffer(e){const t={buffer:e.toAudioBuffer(),timestamp:e.timestamp,duration:e.duration};return e.close(),t}async getBuffer(e,t){_s(e);const i=await this._audioSampleSink.getSample(e,t);return i&&this._audioSampleToWrappedArrayBuffer(i)}buffers(e=0,t=1/0,i){return A(this._audioSampleSink.samples(e,t,i),e=>this._audioSampleToWrappedArrayBuffer(e))}buffersAtTimestamps(e,t){return A(this._audioSampleSink.samplesAtTimestamps(e,t),e=>e&&this._audioSampleToWrappedArrayBuffer(e))}}class Hs{constructor(e,t){this.input=e,this._backing=t}isVideoTrack(){return this instanceof Xs}isAudioTrack(){return this instanceof $s}get id(){return this._backing.getId()}get number(){return this._backing.getNumber()}async getInternalCodecId(){return this._backing.getInternalCodecId()}get internalCodecId(){return Ks(this._backing.getInternalCodecId(),"internalCodecId","getInternalCodecId")}async getLanguageCode(){return this._backing.getLanguageCode()}get languageCode(){return Ks(this._backing.getLanguageCode(),"languageCode","getLanguageCode")}async getName(){return this._backing.getName()}get name(){return Ks(this._backing.getName(),"name","getName")}async getTimeResolution(){return this._backing.getTimeResolution()}get timeResolution(){return Ks(this._backing.getTimeResolution(),"timeResolution","getTimeResolution")}async isRelativeToUnixEpoch(){return this._backing.isRelativeToUnixEpoch()}async getDisposition(){return this._backing.getDisposition()}get disposition(){return Ks(this._backing.getDisposition(),"disposition","getDisposition")}async getBitrate(){return this._backing.getBitrate()}async getAverageBitrate(){return this._backing.getAverageBitrate()}async getFirstTimestamp(){const e=await this._backing.getFirstPacket({metadataOnly:!0});return e?.timestamp??0}async computeDuration(e){const t=await this._backing.getPacket(1/0,{metadataOnly:!0,...e});return M((t?.timestamp??0)+(t?.duration??0),await this.getTimeResolution())}async getDurationFromMetadata(e={}){return this._backing.getDurationFromMetadata(e)}async computePacketStats(e=1/0,t){const i=new Fs(this);let r=1/0,a=-1/0,s=0,n=0;for await(const o of i.packets(void 0,void 0,{metadataOnly:!0,...t})){if(s>=e&&o.timestamp>=a)break;r=Math.min(r,o.timestamp),a=Math.max(a,o.timestamp+o.duration),s++,n+=o.byteLength}return{packetCount:s,averagePacketRate:s?Number((s/(a-r)).toPrecision(16)):0,averageBitrate:s?Number((8*n/(a-r)).toPrecision(16)):0}}async isLive(){return null!==await this._backing.getLiveRefreshInterval()}async getLiveRefreshInterval(){return this._backing.getLiveRefreshInterval()}canBePairedWith(e){if(!(e instanceof Hs))throw new TypeError("other must be an InputTrack.");return this.input===e.input&&this!==e&&0n!==(this._backing.getPairingMask()&e._backing.getPairingMask())}async getPairableTracks(e){return this.input.getTracks(Js({filter:e=>e.canBePairedWith(this)},e))}async getPairableVideoTracks(e){return this.input.getVideoTracks(Js({filter:e=>e.canBePairedWith(this)},e))}async getPairableAudioTracks(e){return this.input.getAudioTracks(Js({filter:e=>e.canBePairedWith(this)},e))}async getPrimaryPairableVideoTrack(e){return this.input.getPrimaryVideoTrack(Js({filter:e=>e.canBePairedWith(this)},e))}async getPrimaryPairableAudioTrack(e){return this.input.getPrimaryAudioTrack(Js({filter:e=>e.canBePairedWith(this)},e))}async hasPairableTrack(e){e&&(e=js(e));const t=await this.input.getTracks();for(const i of t)if(this.canBePairedWith(i)&&(!e||await e(i)))return!0;return!1}hasPairableVideoTrack(e){return e&&(e=js(e)),this.hasPairableTrack(async t=>t.isVideoTrack()&&(!e||await e(t)))}hasPairableAudioTrack(e){return e&&(e=js(e)),this.hasPairableTrack(async t=>t.isAudioTrack()&&(!e||await e(t)))}}const Ks=(e,t,i)=>{if(e instanceof Promise)throw new Error(`'${t}' is deprecated and not available synchronously for this track. Use the preferred '${i}()' instead.`);return e},js=e=>{if(void 0!==e&&"function"!==typeof e)throw new TypeError("predicate, when provided, must be a function.");return e?t=>{const i=e=>{if("boolean"!==typeof e)throw new TypeError("predicate must return or resolve to a boolean value.");return e},r=e(t);return r instanceof Promise?r.then(i):i(r)}:void 0};class Xs extends Hs{constructor(e,t){super(e,t),this._pixelAspectRatioCache=null,this._backing=t}get type(){return"video"}async getCodec(){return this._backing.getCodec()}get codec(){return Ks(this._backing.getCodec(),"codec","getCodec")}async hasOnlyKeyPackets(){return await(this._backing.getHasOnlyKeyPackets?.())??!1}async getCodedWidth(){return this._backing.getCodedWidth()}get codedWidth(){return Ks(this._backing.getCodedWidth(),"codedWidth","getCodedWidth")}async getCodedHeight(){return this._backing.getCodedHeight()}get codedHeight(){return Ks(this._backing.getCodedHeight(),"codedHeight","getCodedHeight")}async getRotation(){return this._backing.getRotation()}get rotation(){return Ks(this._backing.getRotation(),"rotation","getRotation")}async getSquarePixelWidth(){return this._backing.getSquarePixelWidth()}get squarePixelWidth(){return Ks(this._backing.getSquarePixelWidth(),"squarePixelWidth","getSquarePixelWidth")}async getSquarePixelHeight(){return this._backing.getSquarePixelHeight()}get squarePixelHeight(){return Ks(this._backing.getSquarePixelHeight(),"squarePixelHeight","getSquarePixelHeight")}async getPixelAspectRatio(){return this._pixelAspectRatioCache??(this._pixelAspectRatioCache=ne({num:await this.getSquarePixelWidth()*await this.getCodedHeight(),den:await this.getSquarePixelHeight()*await this.getCodedWidth()}))}get pixelAspectRatio(){return this._pixelAspectRatioCache??(this._pixelAspectRatioCache=ne({num:Ks(this._backing.getSquarePixelWidth(),"pixelAspectRatio","getPixelAspectRatio")*Ks(this._backing.getCodedHeight(),"pixelAspectRatio","getPixelAspectRatio"),den:Ks(this._backing.getSquarePixelHeight(),"pixelAspectRatio","getPixelAspectRatio")*Ks(this._backing.getCodedWidth(),"pixelAspectRatio","getPixelAspectRatio")}))}async getDisplayWidth(){const e=await(this._backing.getMetadataDisplayWidth?.());if(null!=e)return e;return await this.getRotation()%180===0?this.getSquarePixelWidth():this.getSquarePixelHeight()}get displayWidth(){const e=this._backing.getMetadataDisplayWidth?.();if(void 0!==e){const t=Ks(e,"displayWidth","getDisplayWidth");if(null!==t)return t}const t=Ks(this._backing.getRotation(),"displayWidth","getDisplayWidth")%180===0?this._backing.getSquarePixelWidth():this._backing.getSquarePixelHeight();return Ks(t,"displayWidth","getDisplayWidth")}async getDisplayHeight(){const e=await(this._backing.getMetadataDisplayHeight?.());if(null!=e)return e;return await this.getRotation()%180===0?this.getSquarePixelHeight():this.getSquarePixelWidth()}get displayHeight(){const e=this._backing.getMetadataDisplayHeight?.();if(void 0!==e){const t=Ks(e,"displayHeight","getDisplayHeight");if(null!==t)return t}const t=Ks(this._backing.getRotation(),"displayHeight","getDisplayHeight")%180===0?this._backing.getSquarePixelHeight():this._backing.getSquarePixelWidth();return Ks(t,"displayHeight","getDisplayHeight")}async getColorSpace(){return this._backing.getColorSpace()}async hasHighDynamicRange(){const e=await this._backing.getColorSpace();return"bt2020"===e.primaries||"smpte432"===e.primaries||"pg"===e.transfer||"hlg"===e.transfer||"bt2020-ncl"===e.matrix}async canBeTransparent(){return this._backing.canBeTransparent()}async getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecParameterString(){const e=await(this._backing.getMetadataCodecParameterString?.());if(null!=e)return e;const t=await this._backing.getDecoderConfig();return t?.codec??null}async canDecode(){try{const e=await this._backing.getDecoderConfig();if(!e)return!1;const t=await this._backing.getCodec();if(i(null!==t),Cs.some(i=>i.supports(t,e)))return!0;if("undefined"===typeof VideoDecoder)return!1;return!0===(await VideoDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}}async determinePacketType(e){if(!(e instanceof Mt))throw new TypeError("packet must be an EncodedPacket.");if(e.isMetadataOnly)throw new TypeError("packet must not be metadata-only to determine its type.");const t=await this.getCodec();if(null===t)return null;const r=await this.getDecoderConfig();return i(r),St(t,r,e.data)}}class $s extends Hs{constructor(e,t){super(e,t),this._backing=t}get type(){return"audio"}async getCodec(){return this._backing.getCodec()}get codec(){return Ks(this._backing.getCodec(),"codec","getCodec")}async hasOnlyKeyPackets(){return await(this._backing.getHasOnlyKeyPackets?.())??!0}async getNumberOfChannels(){return this._backing.getNumberOfChannels()}get numberOfChannels(){return Ks(this._backing.getNumberOfChannels(),"numberOfChannels","getNumberOfChannels")}async getSampleRate(){return this._backing.getSampleRate()}get sampleRate(){return Ks(this._backing.getSampleRate(),"sampleRate","getSampleRate")}async getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecParameterString(){const e=await(this._backing.getMetadataCodecParameterString?.());if(null!=e)return e;const t=await this._backing.getDecoderConfig();return t?.codec??null}async canDecode(){try{const e=await this._backing.getDecoderConfig();if(!e)return!1;const t=await this._backing.getCodec();if(i(null!==t),Bs.some(i=>i.supports(t,e)))return!0;if(e.codec.startsWith("pcm-"))return!0;if("undefined"===typeof AudioDecoder)return!1;return!0===(await AudioDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}}async determinePacketType(e){if(!(e instanceof Mt))throw new TypeError("packet must be an EncodedPacket.");return null===await this.getCodec()?null:"key"}}const Qs=e=>-(e??-1/0),Gs=e=>-e,Ys=e=>{if("object"!==typeof e||!e)throw new TypeError("query must be an object.");if(void 0!==e.filter&&"function"!==typeof e.filter)throw new TypeError("query.filter, when provided, must be a function.");if(void 0!==e.sortBy&&"function"!==typeof e.sortBy)throw new TypeError("query.sortBy, when provided, must be a function.");return{filter:e.filter?t=>{const i=e=>{if("boolean"!==typeof e)throw new TypeError("query.filter must return or resolve to a boolean.");return e},r=e.filter(t);return r instanceof Promise?r.then(i):i(r)}:void 0,sortBy:e.sortBy?t=>{const i=e=>{if("number"!==typeof e&&(!Array.isArray(e)||!e.every(e=>"number"===typeof e)))throw new TypeError("query.sortBy must return or resolve to a number or an array of numbers.");return e},r=e.sortBy(t);return r instanceof Promise?r.then(i):i(r)}:void 0}},Js=(e,t)=>({filter:e?.filter||t?.filter?i=>{const r=e?.filter?.(i)??!0,a=e=>!1!==e&&(t?.filter?.(i)??!0);return r instanceof Promise?r.then(a):a(r)}:void 0,sortBy:e?.sortBy||t?.sortBy?i=>{const r=e?.sortBy?.(i)??[],a=t?.sortBy?.(i)??[],s=(e,t)=>[...Array.isArray(e)?e:[e],...Array.isArray(t)?t:[t]];return r instanceof Promise||a instanceof Promise?Promise.all([r,a]).then(([e,t])=>s(e,t)):s(r,a)}:void 0}),Zs=async(e,t)=>{let i=e;if(t?.filter){const r=e.map(e=>t.filter(e));if(r.some(e=>e instanceof Promise)){const t=await Promise.all(r);i=e.filter((e,i)=>t[i])}else i=e.filter((e,t)=>r[t])}if(!t?.sortBy)return i;const r=i.map(e=>t.sortBy(e)),a=r.some(e=>e instanceof Promise)?await Promise.all(r):r;return i.map((e,t)=>({track:e,sortValue:a[t]})).sort((e,t)=>{const i=Array.isArray(e.sortValue)?e.sortValue:[e.sortValue],r=Array.isArray(t.sortValue)?t.sortValue:[t.sortValue],a=Math.max(i.length,r.length);for(let s=0;se.track)};te();const en=2;let tn=null;"undefined"!==typeof FinalizationRegistry&&(tn=new FinalizationRegistry(e=>{for(const t of e)t.freed||t.free()}));class rn extends le{get disposed(){return this._disposed}constructor(e){if(super(),this._demuxerPromise=null,this._format=null,this._trackBackingsCache=null,this._backingToTrack=new Map,this._disposed=!1,this._nextSourceCacheAge=0,this._sourceRefs=[],this._sourceCache=[],this._sourceCachePromises=[],this._onFormatDetermined=null,!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(!Array.isArray(e.formats)||e.formats.some(e=>!(e instanceof Da)))throw new TypeError("options.formats must be an array of InputFormat.");if(!(e.source instanceof la||e.source instanceof ua))throw new TypeError("options.source must be a Source or SourceRef.");if(e.source instanceof la&&e.source._disposed)throw new TypeError("options.source must not be a disposed Source.");if(void 0!==e.initInput&&!(e.initInput instanceof rn))throw new TypeError("options.initInput, when provided, must be an Input.");void 0!==e.formatOptions&&((e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(`${t}, when provided, must be an object.`);if(void 0!==e.isobmff){if(!e.isobmff||"object"!==typeof e.isobmff)throw new TypeError(`${t}.isobmff, when provided, must be an object.`);if(void 0!==e.isobmff.resolveKeyId&&"function"!==typeof e.isobmff.resolveKeyId)throw new TypeError(`${t}.isobmff.resolveKeyId, when provided, must be a function.`)}})(e.formatOptions,"formatOptions"),this._formats=e.formats,this._initInput=e.initInput??null,this._formatOptions=e.formatOptions??{},e.source instanceof la?this._rootRef=e.source.ref():this._rootRef=e.source,this._sourceRefs.push(this._rootRef),tn?.register(this,this._sourceRefs,this)}get _rootSource(){return this._rootRef.source}async _getSourceUncached(e){i(this._rootSource instanceof da);const t=await this._rootSource._resolveRequest(e);return this._emit("source",{source:t.source,request:e,isRoot:e.isRoot}),t}_getSourceCached(e,t=1){const r=this._sourceCache.find(i=>i.cacheGroup===t&&ha(i.request,e));if(r)return r.age++,Promise.resolve(r.sourceRef.source.ref());const a=this._sourceCachePromises.find(i=>i.cacheGroup===t&&ha(i.request,e));if(a)return a.promise.then(e=>e.sourceRef.source.ref());const s=(async()=>{const r=await this._getSourceUncached(e);if(ae(this._sourceCache,e=>e.cacheGroup===t&&1===e.sourceRef.source._refCount)>=4){const e=se(this._sourceCache,e=>e.cacheGroup===t&&1===e.sourceRef.source._refCount?e.age:1/0);i(-1!==e);const r=this._sourceCache[e];this._sourceCache.splice(e,1),r.sourceRef.free(),((e,t)=>{const i=e.indexOf(t);-1!==i&&e.splice(i,1)})(this._sourceRefs,r.sourceRef)}this._sourceRefs.push(r);const a=this._sourceCachePromises.findIndex(t=>t.request===e);i(-1!==a),this._sourceCachePromises.splice(a,1);return{request:e,sourceRef:r,age:this._nextSourceCacheAge++,cacheGroup:t}})();return this._sourceCachePromises.push({request:e,cacheGroup:t,promise:s}),s.then(e=>{const t=e.sourceRef.source.ref();return this._sourceCache.push(e),t})}_getDemuxer(){return this._demuxerPromise??(this._demuxerPromise=(async()=>{this._reader=new nn(this._rootSource),this._emit("source",{source:this._rootSource,request:null,isRoot:!0});for(const e of this._formats){if(await e._canReadInput(this))return this._format=e,this._onFormatDetermined?.(e),e._createDemuxer(this)}throw new an})())}get source(){return this._rootSource}async getFormat(){return await this._getDemuxer(),i(this._format),this._format}async canRead(){try{return await this._getDemuxer(),!0}catch(e){if(e instanceof an)return!1;throw e}}async getFirstTimestamp(e){e??(e=await this.getTracks());const t=e.filter(e=>null!==e);if(0===t.length)return 0;const i=await Promise.all(t.map(e=>e.getFirstTimestamp()));return Math.min(...i)}async computeDuration(e,t){e??(e=await this.getTracks());const i=e.filter(e=>null!==e);if(0===i.length)return 0;const r=await Promise.all(i.map(e=>e.computeDuration(t)));return Math.max(...r)}async getDurationFromMetadata(e,t){e??(e=await this.getTracks());const i=e.filter(e=>null!==e),r=(await Promise.all(i.map(e=>e.getDurationFromMetadata(t)))).filter(e=>null!==e);return 0===r.length?null:Math.max(...r)}async getTracks(e){e&&(e=Ys(e));const t=(await this._getTrackBackings()).map(e=>this._wrapBackingAsTrack(e));return Zs(t,e)}async getVideoTracks(e){e&&(e=Ys(e));const t=(await this.getTracks()).filter(e=>e.isVideoTrack());return Zs(t,e)}async getAudioTracks(e){e&&(e=Ys(e));const t=(await this.getTracks()).filter(e=>e.isAudioTrack());return Zs(t,e)}async getPrimaryVideoTrack(e){e&&(e=Ys(e));const t=Js(e,{sortBy:async e=>[Gs((await e.getDisposition()).default),Gs(await e.hasPairableAudioTrack()),Gs(!(await e.hasOnlyKeyPackets())),Qs(await e.getBitrate())]});return(await this.getVideoTracks(t))[0]??null}async getPrimaryAudioTrack(e){e&&(e=Ys(e));const t=await this.getPrimaryVideoTrack(),i=Js(e,{sortBy:async e=>[Gs(!t||e.canBePairedWith(t)),Gs((await e.getDisposition()).default),Qs(await e.getBitrate())]});return(await this.getAudioTracks(i))[0]??null}async _getTrackBackings(){const e=await this._getDemuxer();return this._trackBackingsCache??(this._trackBackingsCache=await e.getTrackBackings())}_wrapBackingAsTrack(e){const t=this._backingToTrack.get(e);if(t)return t;const i="video"===e.getType()?new Xs(this,e):new $s(this,e);return this._backingToTrack.set(e,i),i}async getMimeType(){return(await this._getDemuxer()).getMimeType()}async getMetadataTags(){return(await this._getDemuxer()).getMetadataTags()}dispose(){if(!this._disposed){this._disposed=!0;for(const e of this._sourceRefs)e.free();this._sourceRefs.length=0,tn?.unregister(this),this._demuxerPromise?.then(e=>e.dispose())}}[Symbol.dispose](){this.dispose()}}class an extends Error{constructor(e="Input has an unsupported or unrecognizable format."){super(e),this.name="UnsupportedInputFormatError"}}class sn extends Error{constructor(e="Input has been disposed."){super(e),this.name="InputDisposedError"}}class nn{constructor(e){this.source=e}get fileSize(){const e=this.source._getFileSize();if(void 0===e)throw new Error("Reading file size too early; read required first.");return e}get fileSizeNonStrict(){return this.source._getFileSize()??null}requestSlice(e,t){if(this.source._disposed)throw new sn;if(e<0)return null;if(null!==this.fileSizeNonStrict&&e+t>this.fileSizeNonStrict)return null;if(0===t){const t=new Uint8Array(0);return new on(t,c(t),0,e,e)}const i=e+t,r=this.source._read(e,i,0,ca);return r instanceof Promise?r.then(t=>t?new on(t.bytes,t.view,t.offset,e,i):null):r?new on(r.bytes,r.view,r.offset,e,i):null}requestSliceRange(e,t,r){if(this.source._disposed)throw new sn;if(e<0)return null;if(null!==this.fileSizeNonStrict)return this.requestSlice(e,F(this.fileSizeNonStrict-e,t,r));{const a=this.requestSlice(e,r),s=a=>a||(i(null!==this.fileSizeNonStrict),this.requestSlice(e,F(this.fileSizeNonStrict-e,t,r)));return a instanceof Promise?a.then(s):s(a)}}requestEntireFile(){if(null!==this.fileSizeNonStrict)return this.requestSlice(0,this.fileSizeNonStrict);return(async()=>{const e=[];let t=0;for(;;){if(1===e.length&&null!==this.fileSizeNonStrict)return this.requestSlice(0,this.fileSizeNonStrict);const i=1024*e.length;let r=this.requestSliceRange(i,0,1024);if(r instanceof Promise&&(r=await r),!r)break;e.push(ln(r,r.length)),t+=r.length}const i=new Uint8Array(t);let r=0;for(const a of e)i.set(a,r),r+=a.length;return new on(i,c(i),0,0,t)})()}}class on{constructor(e,t,i,r,a){this.bytes=e,this.view=t,this.offset=i,this.start=r,this.end=a,this.bufferPos=r-i}static tempFromBytes(e){return new on(e,c(e),0,0,e.length)}get length(){return this.end-this.start}get filePos(){return this.offset+this.bufferPos}set filePos(e){this.bufferPos=e-this.offset}get remainingLength(){return Math.max(this.end-this.filePos,0)}skip(e){this.bufferPos+=e}slice(e,t=this.end-e){if(ethis.end)throw new RangeError("Slicing outside of original slice.");return new on(this.bytes,this.view,this.offset,e,e+t)}}const cn=(e,t)=>{if(e.filePose.end)throw new RangeError(`Tried reading [${e.filePos}, ${e.filePos+t}), but slice is [${e.start}, ${e.end}). This is likely an internal error, please report it alongside the file that caused it.`)},ln=(e,t)=>{cn(e,t);const i=e.bytes.subarray(e.bufferPos,e.bufferPos+t);return e.bufferPos+=t,i},un=e=>(cn(e,1),e.view.getUint8(e.bufferPos++)),dn=(e,t)=>{cn(e,2);const i=e.view.getUint16(e.bufferPos,t);return e.bufferPos+=2,i},hn=e=>{cn(e,2);const t=e.view.getUint16(e.bufferPos,!1);return e.bufferPos+=2,t},fn=e=>{cn(e,3);const t=E(e.view,e.bufferPos,!1);return e.bufferPos+=3,t},mn=e=>{cn(e,2);const t=e.view.getInt16(e.bufferPos,!1);return e.bufferPos+=2,t},pn=(e,t)=>{cn(e,4);const i=e.view.getUint32(e.bufferPos,t);return e.bufferPos+=4,i},gn=e=>{cn(e,4);const t=e.view.getUint32(e.bufferPos,!1);return e.bufferPos+=4,t},kn=e=>{cn(e,4);const t=e.view.getUint32(e.bufferPos,!0);return e.bufferPos+=4,t},bn=e=>{cn(e,4);const t=e.view.getInt32(e.bufferPos,!1);return e.bufferPos+=4,t},yn=(e,t)=>{let i,r;return t?(i=pn(e,!0),r=pn(e,!0)):(r=pn(e,!1),i=pn(e,!1)),4294967296*r+i},wn=e=>4294967296*gn(e)+gn(e),Tn=e=>4294967296*bn(e)+gn(e),Sn=e=>{const t=kn(e),i=(e=>{cn(e,4);const t=e.view.getInt32(e.bufferPos,!0);return e.bufferPos+=4,t})(e);return 4294967296*i+t},Pn=e=>{cn(e,4);const t=e.view.getFloat32(e.bufferPos,!1);return e.bufferPos+=4,t},vn=e=>{cn(e,8);const t=e.view.getFloat64(e.bufferPos,!1);return e.bufferPos+=8,t},In=(e,t)=>{cn(e,t);let i="";for(let r=0;rl.decode(ln(e,t)).split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!i?.ignore?.(e));var Cn,Bn,En,_n;(Bn=Cn||(Cn={}))[Bn.Unsynchronisation=128]="Unsynchronisation",Bn[Bn.ExtendedHeader=64]="ExtendedHeader",Bn[Bn.ExperimentalIndicator=32]="ExperimentalIndicator",Bn[Bn.Footer=16]="Footer",(_n=En||(En={}))[_n.ISO_8859_1=0]="ISO_8859_1",_n[_n.UTF_16_WITH_BOM=1]="UTF_16_WITH_BOM",_n[_n.UTF_16_BE_NO_BOM=2]="UTF_16_BE_NO_BOM",_n[_n.UTF_8=3]="UTF_8";const An=128,Fn=10,Rn=["Blues","Classic rock","Country","Dance","Disco","Funk","Grunge","Hip-hop","Jazz","Metal","New age","Oldies","Other","Pop","Rhythm and blues","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death metal","Pranks","Soundtrack","Euro-techno","Ambient","Trip-hop","Vocal","Jazz & funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound clip","Gospel","Noise","Alternative rock","Bass","Soul","Punk","Space","Meditative","Instrumental pop","Instrumental rock","Ethnic","Gothic","Darkwave","Techno-industrial","Electronic","Pop-folk","Eurodance","Dream","Southern rock","Comedy","Cult","Gangsta","Top 40","Christian rap","Pop/funk","Jungle music","Native US","Cabaret","New wave","Psychedelic","Rave","Showtunes","Trailer","Lo-fi","Tribal","Acid punk","Acid jazz","Polka","Retro","Musical","Rock 'n' roll","Hard rock","Folk","Folk rock","National folk","Swing","Fast fusion","Bebop","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic rock","Progressive rock","Psychedelic rock","Symphonic rock","Slow rock","Big band","Chorus","Easy listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber music","Sonata","Symphony","Booty bass","Primus","Porn groove","Satire","Slow jam","Club","Tango","Samba","Folklore","Ballad","Power ballad","Rhythmic Soul","Freestyle","Duet","Punk rock","Drum solo","A cappella","Euro-house","Dance hall","Goa music","Drum & bass","Club-house","Hardcore techno","Terror","Indie","Britpop","Negerpunk","Polsk punk","Beat","Christian gangsta rap","Heavy metal","Black metal","Crossover","Contemporary Christian","Christian rock","Merengue","Salsa","Thrash metal","Anime","Jpop","Synthpop","Christmas","Art rock","Baroque","Bhangra","Big beat","Breakbeat","Chillout","Downtempo","Dub","EBM","Eclectic","Electro","Electroclash","Emo","Experimental","Garage","Global","IDM","Illbient","Industro-Goth","Jam Band","Krautrock","Leftfield","Lounge","Math rock","New romantic","Nu-breakz","Post-punk","Post-rock","Psytrance","Shoegaze","Space rock","Trop rock","World music","Neoclassical","Audiobook","Audio theatre","Neue Deutsche Welle","Podcast","Indie rock","G-Funk","Dubstep","Garage rock","Psybient"],Dn=(e,t)=>{var i;const r=e.filePos;t.raw??(t.raw={}),(i=t.raw).TAG??(i.TAG=ln(e,An-3)),e.filePos=r;const a=Mn(e,30);a&&(t.title??(t.title=a));const s=Mn(e,30);s&&(t.artist??(t.artist=s));const n=Mn(e,30);n&&(t.album??(t.album=n));const o=Mn(e,4),c=Number.parseInt(o,10);Number.isInteger(c)&&c>0&&(t.date??(t.date=new Date(c,0,1)));const l=ln(e,30);let u;if(0===l[28]&&0!==l[29]){const i=l[29];i>0&&(t.trackNumber??(t.trackNumber=i)),e.skip(-30),u=Mn(e,28),e.skip(2)}else e.skip(-30),u=Mn(e,30);u&&(t.comment??(t.comment=u));const d=un(e);d{const i=ln(e,t),r=J(i.indexOf(0),i.length),a=i.subarray(0,r);let s="";for(let n=0;n{const t=e.filePos,i=In(e,3),r=un(e),a=un(e),s=un(e),n=gn(e);if("ID3"!==i||255===r||255===a||0!==(2155905152&n))return e.filePos=t,null;return{majorVersion:r,revision:a,flags:s,size:Ne(n)}},On=(e,t,i)=>{var r,a,s,n,o;if(![2,3,4].includes(t.majorVersion))return void console.warn(`Unsupported ID3v2 major version: ${t.majorVersion}`);const c=ln(e,t.size),l=new Ln(t,c);if(t.flags&Cn.Footer&&l.removeFooter(),t.flags&Cn.Unsynchronisation&&3===t.majorVersion&&l.ununsynchronizeAll(),t.flags&Cn.ExtendedHeader){const e=l.readU32();3===t.majorVersion?l.pos+=e:l.pos+=e-4}for(;l.pos<=l.bytes.length-l.frameHeaderSize();){const e=l.readId3V2Frame();if(!e)break;const c=l.pos,u=l.pos+e.size;let d=!1,h=!1,f=!1;if(3===t.majorVersion?(d=!!(64&e.flags),h=!!(128&e.flags)):4===t.majorVersion&&(d=!!(4&e.flags),h=!!(8&e.flags),f=!!(2&e.flags)||!!(t.flags&Cn.Unsynchronisation)),d)console.warn(`Skipping encrypted ID3v2 frame ${e.id}`),l.pos=u;else if(h)console.warn(`Skipping compressed ID3v2 frame ${e.id}`),l.pos=u;else{if(f&&l.ununsynchronizeRegion(l.pos,u),i.raw??(i.raw={}),"TXXX"===e.id){const e=(r=i.raw).TXXX??(r.TXXX={}),t=l.readId3V2TextEncoding(),a=l.readId3V2Text(t,u),s=l.readId3V2Text(t,u);e[a]??(e[a]=s)}else"T"===e.id[0]?(a=i.raw)[s=e.id]??(a[s]=l.readId3V2EncodingAndText(u)):(n=i.raw)[o=e.id]??(n[o]=l.readBytes(e.size));switch(l.pos=c,e.id){case"TIT2":case"TT2":i.title??(i.title=l.readId3V2EncodingAndText(u));break;case"TIT3":case"TT3":i.description??(i.description=l.readId3V2EncodingAndText(u));break;case"TPE1":case"TP1":i.artist??(i.artist=l.readId3V2EncodingAndText(u));break;case"TALB":case"TAL":i.album??(i.album=l.readId3V2EncodingAndText(u));break;case"TPE2":case"TP2":i.albumArtist??(i.albumArtist=l.readId3V2EncodingAndText(u));break;case"TRCK":case"TRK":{const e=l.readId3V2EncodingAndText(u).split("/"),t=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(i.trackNumber??(i.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&(i.tracksTotal??(i.tracksTotal=r))}break;case"TPOS":case"TPA":{const e=l.readId3V2EncodingAndText(u).split("/"),t=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(i.discNumber??(i.discNumber=t)),r&&Number.isInteger(r)&&r>0&&(i.discsTotal??(i.discsTotal=r))}break;case"TCON":case"TCO":{const e=l.readId3V2EncodingAndText(u);let t=/^\((\d+)\)/.exec(e);if(t){const e=Number.parseInt(t[1]);if(void 0!==Rn[e]){i.genre??(i.genre=Rn[e]);break}}if(t=/^\d+$/.exec(e),t){const e=Number.parseInt(t[0]);if(void 0!==Rn[e]){i.genre??(i.genre=Rn[e]);break}}i.genre??(i.genre=e)}break;case"TDRC":case"TDAT":{const e=l.readId3V2EncodingAndText(u),t=new Date(e);Number.isNaN(t.getTime())||(i.date??(i.date=t))}break;case"TYER":case"TYE":{const e=l.readId3V2EncodingAndText(u),t=Number.parseInt(e,10);Number.isInteger(t)&&(i.date??(i.date=new Date(t,0,1)))}break;case"USLT":case"ULT":{const e=l.readU8();l.pos+=3,l.readId3V2Text(e,u),i.lyrics??(i.lyrics=l.readId3V2Text(e,u))}break;case"COMM":case"COM":{const e=l.readU8();l.pos+=3,l.readId3V2Text(e,u),i.comment??(i.comment=l.readId3V2Text(e,u))}break;case"APIC":case"PIC":{const e=l.readId3V2TextEncoding();let r;if(2===t.majorVersion){const e=l.readAscii(3);r="PNG"===e?"image/png":"JPG"===e?"image/jpeg":"image/*"}else r=l.readId3V2Text(e,u);const a=l.readU8(),s=l.readId3V2Text(e,u).trimEnd(),n=u-l.pos;if(n>=0){const e=l.readBytes(n);i.images||(i.images=[]),i.images.push({data:e,mimeType:r,kind:3===a?"coverFront":4===a?"coverBack":"unknown",description:s})}}break;default:l.pos+=e.size}l.pos=u}}};class Ln{constructor(e,t){this.header=e,this.bytes=t,this.pos=0,this.view=new DataView(t.buffer,t.byteOffset,t.byteLength)}frameHeaderSize(){return 2===this.header.majorVersion?6:10}ununsynchronizeAll(){const e=[];for(let t=0;t{const t=this.pos+e;if(t>this.bytes.length)return!1;if(t<=this.bytes.length-this.frameHeaderSize()){this.pos+=e;const t=this.readAscii(4);if("\0\0\0\0"!==t&&!/[0-9A-Z]{4}/.test(t))return!1}return!0};if(!s(i)){const e=4===this.header.majorVersion?t:Ne(t);s(e)&&(i=e)}return this.pos=a,{id:e,size:i,flags:r}}}readId3V2TextEncoding(){const e=this.readU8();if(e>3)throw new Error(`Unsupported text encoding: ${e}`);return e}readId3V2Text(e,t){const i=this.pos,r=this.readBytes(t-this.pos);switch(e){case En.ISO_8859_1:{let e="";for(let t=0;t0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(2,t))}if(254===r[0]&&255===r[1]){const e=new TextDecoder("utf-16be"),t=J(r.findIndex((e,t)=>0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(2,t))}{const e=J(r.findIndex(e=>0===e),r.length);return this.pos=i+Math.min(e+1,r.length),l.decode(r.subarray(0,e))}case En.UTF_16_BE_NO_BOM:{const e=new TextDecoder("utf-16be"),t=J(r.findIndex((e,t)=>0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(0,t))}case En.UTF_8:{const e=J(r.findIndex(e=>0===e),r.length);return this.pos=i+Math.min(e+1,r.length),l.decode(r.subarray(0,e))}}}readId3V2EncodingAndText(e){if(this.pos>=e)return"";const t=this.readId3V2TextEncoding();return this.readId3V2Text(t,e)}}class zn{constructor(e){this.events=e,this.input=null,this.audioSink=null,this.audioIterator=null,this.audioContext=null,this.gainNode=null,this.audioContextStartTime=0,this.playbackTimeAtStart=0,this.latestScheduledEndTime=0,this.duration=Number.NaN,this.paused=!0,this.volume=.7,this.muted=!1,this.playbackRate=1,this.asyncId=0,this.queuedNodes=new Set}get currentTime(){return this.paused?this.playbackTimeAtStart:(this.audioContext.currentTime-this.audioContextStartTime)*this.playbackRate+this.playbackTimeAtStart}ensureAudioContext(e){if(this.audioContext)return;const t=window.AudioContext||window.webkitAudioContext;try{this.audioContext=new t({sampleRate:e})}catch{this.audioContext=new t}this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination),this.updateGain()}updateGain(){if(!this.gainNode)return;const e=this.muted?0:this.volume;this.gainNode.gain.value=e*e}stopQueuedNodes(){this.queuedNodes.forEach(e=>e.stop()),this.queuedNodes.clear()}async stopIterator(){await(this.audioIterator?.return()),this.audioIterator=null}handleNoAudioTrack(){this.audioSink=null,this.ensureAudioContext()}async load(e,t){++this.asyncId,await this.stopIterator(),this.stopQueuedNodes(),this.paused=!0,this.playbackTimeAtStart=0,this.audioContextStartTime=0;const{input:i,audioTrack:r,duration:a}=e;return this.input=i,this.duration=a,r?null!==r.codec&&await r.canDecode()?(this.ensureAudioContext(r.sampleRate),this.audioSink=new Vs(r),void t?.()):(this.audioSink=null,this.ensureAudioContext(),void t?.()):(this.handleNoAudioTrack(),void t?.())}async runIterator(e){if(this.audioSink)for(await this.stopIterator(),this.audioIterator=this.audioSink.buffers(this.currentTime);;){if(e!==this.asyncId||this.paused)return;const i=this.audioIterator.next(),r=setInterval(()=>{e!==this.asyncId||this.paused?clearInterval(r):"running"===this.audioContext.state&&this.audioContext.currentTime>=this.latestScheduledEndTime-.2&&(this.audioContext.suspend(),this.events.emit("waiting"))},50);let a;try{a=await i}catch(t){console.error("Audio iterator error:",t);break}finally{clearInterval(r)}if(e!==this.asyncId||this.paused)return;if("suspended"===this.audioContext.state&&(await this.audioContext.resume(),this.events.emit("canplay"),this.events.emit("playing")),a.done)break;const{buffer:s,timestamp:n}=a.value,o=this.audioContext.createBufferSource();o.buffer=s,o.connect(this.gainNode),o.playbackRate.value=this.playbackRate;const c=this.audioContextStartTime+(n-this.playbackTimeAtStart)/this.playbackRate,l=c+s.duration/this.playbackRate;l>this.latestScheduledEndTime&&(this.latestScheduledEndTime=l),c>=this.audioContext.currentTime?o.start(c):o.start(this.audioContext.currentTime,(this.audioContext.currentTime-c)*this.playbackRate),this.queuedNodes.add(o),o.onended=()=>this.queuedNodes.delete(o)}}async play(){if(!this.paused)return;this.audioContext||this.ensureAudioContext(),"suspended"===this.audioContext.state&&await this.audioContext.resume(),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime,this.paused=!1;const e=++this.asyncId;this.runIterator(e)}pause(){this.paused||(this.playbackTimeAtStart=this.currentTime,this.paused=!0,this.stopIterator(),this.stopQueuedNodes())}async seek(e){this.playbackTimeAtStart=Math.max(0,e),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime;const t=++this.asyncId;this.paused||this.runIterator(t)}setVolume(e,t){this.volume=e,this.muted=t,this.updateGain()}setPlaybackRate(e){if(e!==this.playbackRate&&(this.paused||(this.playbackTimeAtStart=this.currentTime,this.audioContextStartTime=this.audioContext.currentTime),this.playbackRate=e,!this.paused)){const e=++this.asyncId;this.runIterator(e)}}destroy(){this.asyncId++,this.pause(),this.audioContext?.close(),this.audioContext=null,this.input=null,this.audioSink=null}}const Un=/\.m3u8(?:$|[?#])/i;function qn(e){return"string"===typeof e&&Un.test(e)}function Wn(e){const t=function(e){return"string"===typeof e?new ka(e):e instanceof Blob?new ma(e):"undefined"!==typeof ReadableStream&&e instanceof ReadableStream?new ba(e):e??null}(e);return t?new rn({source:t,formats:qn(e)?ss:as}):null}async function Vn({input:e,videoTrack:t,audioTrack:i}){const r=[t,i].filter(Boolean),a=t||i,s=Boolean(a&&await a.isLive());let n=Number.NaN;return r.length>0&&(n=await e.getDurationFromMetadata(r,{skipLiveWait:!0}),null!==n||s||(n=await e.computeDuration(r,{skipLiveWait:!0}))),s?Number.POSITIVE_INFINITY:n??Number.NaN}async function Hn(e){return await e.getAverageBitrate()??await e.getBitrate()??0}class Kn{constructor({canvas:e,ctx:t,events:i,timeupdateInterval:r=250,avSyncTolerance:a=.12,dropLateFrames:s=!1,poster:n="",preflightRange:o=!1}){this.canvas=e,this.ctx=t,this.events=i,this.timeupdateInterval=r,this.avSyncTolerance=a,this.dropLateFrames=s,this.poster=n,this.preflightRange=o,this.input=null,this.videoSink=null,this.videoIterator=null,this.nextFrame=null,this.rafId=0,this.asyncId=0,this.width=0,this.height=0,this.duration=Number.NaN,this.audioClock=null,this.lastTimeUpdate=0,this.stalled=!1,this.playbackRate=1,this.posterDrawn=!1,this.isFetching=!1}async preflight(e){if(!this.preflightRange||"string"!==typeof e||qn(e))return!0;try{const t=(await fetch(e,{method:"HEAD"})).headers.get("accept-ranges");return!(!t||"none"===t)||(this.events.emit("error",new Event("RangeNotSupported")),!1)}catch(t){return console.warn("Preflight check failed:",t),!0}}drawPoster(){if(!this.poster||this.posterDrawn)return;const e=new Image;e.onload=()=>{this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width=e.naturalWidth||this.canvas.width,this.canvas.height=e.naturalHeight||this.canvas.height,this.ctx.drawImage(e,0,0,this.canvas.width,this.canvas.height),this.posterDrawn=!0},e.src=this.poster}async stopIterator(){await(this.videoIterator?.return()),this.videoIterator=null}clear(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}async load(e,t){++this.asyncId,await this.stopIterator(),this.clear(),this.posterDrawn=!1;const{input:i,videoTrack:r,duration:a}=e;if(this.input=i,this.duration=a,!r)return this.handleNoVideoTrack(),void t?.();if(null===r.codec||!(await r.canDecode()))return this.handleNoVideoTrack(),void t?.();const s=await r.canBeTransparent();this.videoSink=new zs(r,{poolSize:2,fit:"contain",alpha:s}),this.width=r.displayWidth,this.height=r.displayHeight,this.canvas.width=this.width,this.canvas.height=this.height,t?.(),await this.resetIterator(0)}handleNoVideoTrack(){this.videoSink=null,this.width=0,this.height=0,this.canvas.width=0,this.canvas.height=0,this.clear(),this.drawPoster()}async resetIterator(e){if(await this.stopIterator(),!this.videoSink)return;this.videoIterator=this.videoSink.canvases(e);const t=(await this.videoIterator.next()).value??null,i=(await this.videoIterator.next()).value??null;this.nextFrame=i,t?this.ctx.drawImage(t.canvas,0,0):this.drawPoster()}async updateNextFrame(e){if(this.videoIterator&&!this.isFetching){this.isFetching=!0;try{for(;;){const t=(await this.videoIterator.next()).value??null;if(!t||e!==this.asyncId)return;const i=this.audioClock.currentTime,r=this.dropLateFrames?Math.max(.06,this.avSyncTolerance/Math.max(1,this.playbackRate)):0;if(!(this.dropLateFrames&&t.timestampi)return void(this.nextFrame=null)}}}finally{this.isFetching=!1}}}render(){if(!this.audioClock)return;const e=this.audioClock.currentTime,t=Date.now();if(t-this.lastTimeUpdate>=this.timeupdateInterval&&(this.events.emit("timeupdate"),this.lastTimeUpdate=t),Number.isFinite(this.duration)&&e>=this.duration)return this.stop(),this.stalled=!1,this.events.emit("ended"),this.events.emit("pause"),void this.events.emit("canplay");this.nextFrame&&this.nextFrame.timestamp<=e?(this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextFrame.canvas,0,0),this.nextFrame=null,this.updateNextFrame(this.asyncId),this.stalled&&(this.events.emit("canplay"),this.events.emit("playing"),this.stalled=!1)):this.nextFrame||(this.updateNextFrame(this.asyncId),!this.nextFrame&&Number.isFinite(this.duration)&&ethis.render())}start(e){this.audioClock=e,this.asyncId++,this.stalled=!1,this.updateNextFrame(this.asyncId),this.rafId=requestAnimationFrame(()=>this.render())}stop(){cancelAnimationFrame(this.rafId)}async seek(e){this.asyncId++,await this.resetIterator(e)}setPlaybackRate(e){this.playbackRate=Math.max(.1,Number(e)||1)}destroy(){this.asyncId++,this.stop(),this.stopIterator(),this.posterDrawn=!1,this.videoSink=null,this.input=null}}class jn{constructor({canvas:e,ctx:t,events:i,option:r={}}){this.events=i,this.option=r,this.audio=new zn(i),this.video=new Kn({canvas:e,ctx:t,events:i,timeupdateInterval:r.timeupdateInterval??250,avSyncTolerance:r.avSyncTolerance??.12,dropLateFrames:r.dropLateFrames??!1,poster:r.poster??"",preflightRange:r.preflightRange??!1}),this.paused=!0,this.ended=!1,this.readyState=0,this.networkState=0,this.error=null,this.seeking=!1,this.loadSeq=0,this.input=null,this.media=null,i.addEventListener?.("ended",()=>{this.ended=!0,this.paused=!0})}async load(e){const t=++this.loadSeq;this.pause(),this.disposeInput(),this.ended=!1,this.error=null,this.networkState=2,this.readyState=0,setTimeout(()=>this.events.emit("waiting"),0),setTimeout(()=>this.events.emit("loadstart"),0);const i=Number.isFinite(this.option.loadTimeout)?this.option.loadTimeout:0;try{await Promise.race([this.performLoad(e,t),i>0?this.createTimeout(i):new Promise(()=>{})])}catch(r){if(t!==this.loadSeq)return;this.loadSeq++,this.error={code:4,message:r.message},this.networkState=3,this.events.emit("error")}}async performLoad(e,t){if(!(await this.video.preflight(e)))return;const i=Wn(e);if(!i)return this.video.handleNoVideoTrack(),void this.audio.handleNoAudioTrack();const r=await async function(e,t){const i=await e.getPrimaryVideoTrack(),r=i?await i.getPrimaryPairableAudioTrack():await e.getPrimaryAudioTrack(),a=await Vn({input:e,videoTrack:i,audioTrack:r});return{input:e,videoTrack:i,audioTrack:r,duration:a,isLive:!Number.isFinite(a)&&Boolean((i||r)&&await(i||r).isLive()),isHls:qn(t),videoMode:qn(t)?"auto":"manual",audioMode:qn(t)?"auto":"manual"}}(i,e);if(t!==this.loadSeq)return void i.dispose();this.disposeInput(),this.input=i,this.media=r;let a=!r.videoTrack,s=!r.audioTrack;const n=()=>{a&&s&&(this.readyState=1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"))};try{if(await Promise.all([this.video.load(r,()=>{t===this.loadSeq&&(a=!0,n())}),this.audio.load(r,()=>{t===this.loadSeq&&(s=!0,n())})]),t!==this.loadSeq)return;this.readyState=4,this.networkState=1,this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("progress")}catch(o){if(t!==this.loadSeq)return;this.error={code:4,message:o.message},this.networkState=3,this.events.emit("error"),console.error("MediaBunny load error:",o)}}createTimeout(e){return new Promise((t,i)=>{setTimeout(()=>i(new Error("Load timeout")),e)})}disposeInput(){this.input?.dispose(),this.input=null,this.media=null}async replaceTracks({videoTrack:e,audioTrack:t,videoMode:i,audioMode:r}){if(!this.media)return;const a={...this.media,videoTrack:e,audioTrack:t,videoMode:i,audioMode:r},s=!this.paused,n=this.currentTime;this.pause(),this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),a.duration=await Vn(a),this.media=a,await Promise.all([this.video.load(a),this.audio.load(a)]),await Promise.all([this.video.seek(n),this.audio.seek(n)]),this.readyState=4,this.networkState=1,this.seeking=!1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"),this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("seeked"),s&&await this.play()}async selectHlsQuality(e){if(!this.media?.isHls||!this.input)return;const t=await this.input.getVideoTracks(),i="auto"===e?await this.input.getPrimaryVideoTrack():t.find(t=>t.id===e)??this.media.videoTrack;if(!i)return;let r=this.media.audioTrack,a=this.media.audioMode;r&&i.canBePairedWith(r)||(r=await i.getPrimaryPairableAudioTrack(),a="auto"),await this.replaceTracks({videoTrack:i,audioTrack:r,videoMode:"auto"===e?"auto":"manual",audioMode:a})}async selectHlsAudio(e){if(!this.media?.isHls||!this.input)return;const t=await this.input.getAudioTracks(),i="auto"===e?this.media.videoTrack?await this.media.videoTrack.getPrimaryPairableAudioTrack():await this.input.getPrimaryAudioTrack():t.find(t=>t.id===e)??this.media.audioTrack;if(!i)return;let r=this.media.videoTrack,a=this.media.videoMode;r&&i.canBePairedWith(r)||(r=await i.getPrimaryPairableVideoTrack(),a="auto"),await this.replaceTracks({videoTrack:r,audioTrack:i,videoMode:a,audioMode:"auto"===e?"auto":"manual"})}getHlsState(){return async function(e){if(!e?.isHls||!e.input)return null;const[t,i]=await Promise.all([e.input.getVideoTracks(),e.videoTrack?e.videoTrack.getPairableAudioTracks():[]]),[r,a]=await Promise.all([Promise.all(t.map(async(e,t)=>({id:e.id,track:e,index:t,name:await e.getName(),height:await e.getDisplayHeight(),bitrate:await Hn(e)}))),Promise.all(i.map(async(e,t)=>{const i=await e.getName(),r=await e.getLanguageCode();return{id:e.id,track:e,index:t,name:i,lang:r,language:r,bitrate:await Hn(e)}}))]);return{levels:r,audios:a,currentLevel:e.videoTrack?r.find(t=>t.id===e.videoTrack.id)??null:null,currentAudio:e.audioTrack?a.find(t=>t.id===e.audioTrack.id)??null:null,videoMode:e.videoMode??"auto",audioMode:e.audioMode??"auto"}}(this.media)}async play(){this.paused&&(this.ended&&(this.ended=!1,await this.seek(0)),this.paused=!1,await this.audio.play(),this.video.start(this.audio),this.events.emit("play"),this.events.emit("playing"))}pause(){this.paused||(this.paused=!0,this.audio.pause(),this.video.stop(),this.events.emit("pause"))}async seek(e){const t=!this.paused;this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),this.pause(),await Promise.all([this.audio.seek(e),this.video.seek(e)]),this.seeking=!1,this.events.emit("seeked"),t&&!this.ended&&await this.play()}setVolume(e,t){this.audio.setVolume(e,t)}setPlaybackRate(e){this.audio.setPlaybackRate(e),this.video.setPlaybackRate(e)}destroy(){this.pause(),this.disposeInput(),this.audio.destroy(),this.video.destroy()}get currentTime(){return this.audio.currentTime}get duration(){return this.media?.duration??this.audio.duration??this.video.duration}get videoWidth(){return this.video.width}get videoHeight(){return this.video.height}}class Xn{constructor({art:e,canvas:i,ctx:r,option:a}){this.art=e,this.canvas=i,this.option=a,this.events=new t,this.engine=new jn({canvas:i,ctx:r,events:this.events,option:a}),this._src=null,this._volume=a.volume??.7,this._muted=!!a.muted,this._playbackRate=1,this.engine.setVolume(this._volume,this._muted),this.setupEventForwarding(),a.source?this.src=a.source:e.option?.url&&(this.src=e.option.url)}setupEventForwarding(){const{events:e}=this.art.constructor.config;e.forEach(e=>{this.events.addEventListener(e,e=>{this.art.emit(`video:${e.type}`,e)})})}addEventListener(e,t){this.events.addEventListener(e,t)}removeEventListener(e,t){this.events.removeEventListener(e,t)}get src(){return this._src}set src(e){this._src=e,e&&this.engine.load(e)}get currentSrc(){return this._src}get currentTime(){return this.engine.currentTime}set currentTime(e){this.engine.seek(Number(e)||0)}get duration(){return this.engine.duration}get buffered(){return this.createTimeRanges(0,this.engine.duration)}get played(){return this.createTimeRanges(0,this.engine.currentTime)}get seekable(){return this.createTimeRanges(0,this.engine.duration)}createTimeRanges(e,t){const i=this.engine.duration;return!i||Number.isNaN(i)||t<=0?{length:0,start:()=>0,end:()=>0}:{length:1,start:()=>e,end:()=>t}}get paused(){return this.engine.paused}get playing(){return!this.engine.paused&&!this.engine.ended}get ended(){return this.engine.ended}get seeking(){return this.engine.seeking}get readyState(){return this.engine.readyState}get networkState(){return this.engine.networkState}get error(){return this.engine.error}get playbackRate(){return this._playbackRate}set playbackRate(e){const t=Number(e);Number.isNaN(t)||t<=0||(this._playbackRate=t,this.engine.setPlaybackRate(t),this.events.emit("ratechange"))}get volume(){return this._volume}set volume(e){this._volume=function(e,t,i){return Math.max(t,Math.min(i,Number(e)||0))}(e,0,1),this._muted=!1,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}get muted(){return this._muted}set muted(e){this._muted=!!e,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}play(){return this.engine.play()}pause(){this.engine.pause()}load(){this._src&&this.engine.load(this._src)}getM3u8State(){return this.engine.getHlsState()}switchM3u8Quality(e){return this.engine.selectHlsQuality(e)}switchM3u8Audio(e){return this.engine.selectHlsAudio(e)}get videoWidth(){return this.engine.videoWidth}get videoHeight(){return this.engine.videoHeight}get poster(){return this.option.poster||""}set poster(e){this.option.poster=e}get autoplay(){return this.option.autoplay||!1}set autoplay(e){}get loop(){return this.option.loop||!1}set loop(e){}get controls(){return!1}set controls(e){}get playsInline(){return!0}set playsInline(e){}get crossOrigin(){return this.option.crossOrigin||""}set crossOrigin(e){}get preload(){return"auto"}set preload(e){}get defaultMuted(){return!1}set defaultMuted(e){}get defaultPlaybackRate(){return 1}set defaultPlaybackRate(e){}canPlayType(e){return"maybe"}getBoundingClientRect(){return this.canvas.getBoundingClientRect()}requestVideoFrameCallback(e){return requestAnimationFrame(t=>{e(t,{presentationTime:this.engine.currentTime,expectedDisplayTime:t+16.6,width:this.engine.videoWidth,height:this.engine.videoHeight,mediaTime:this.engine.currentTime,presentedFrames:0,processingDuration:0,captureTime:t,receiveTime:t,rtpTimestamp:0})})}cancelVideoFrameCallback(e){cancelAnimationFrame(e)}setAttribute(e,t){"src"===e?this.src=t:"autoplay"===e?this.autoplay=t:"loop"===e?this.loop=t:"muted"===e?this.muted=!0:this.canvas.setAttribute(e,t)}destroy(){this.engine.destroy()}}return function(t={}){return i=>{const{constructor:r}=i,{createElement:a}=r.utils,s=a("canvas"),n=s.getContext("2d"),o=new Xn({art:i,canvas:s,ctx:n,option:t});i.mediabunny=o;const c={};for(const e in s)"function"===typeof s[e]&&(c[e]=s[e].bind(s));const l=new Set([...Object.getOwnPropertyNames(o),...Object.getOwnPropertyNames(Object.getPrototypeOf(o))]);for(const e of l)"constructor"!==e&&(e in s||Object.defineProperty(s,e,{get(){const t=o[e];return"function"===typeof t?t.bind(o):t},set(t){o[e]=t},configurable:!0,enumerable:!0}));for(const e in c)s[e]=(...t)=>c[e](...t);function u(){const e=i.template?.$player;e&&!i.option.autoSize&&Object.assign(s.style,{width:"100%",height:"100%",objectFit:"contain"})}return i.on("resize",u),i.on("video:loadedmetadata",u),function({art:t,shim:i,option:r}){if(r.m3u8)return t.on("video:loadedmetadata",d),t.on("restart",d),{update:d};function a(e){t.controls.cache.has(e)&&t.controls.remove(e)}function s(e){t.setting.find(e)&&t.setting.remove(e)}function n(){a("mediabunny-quality"),s("mediabunny-quality")}function o(){a("mediabunny-audio"),s("mediabunny-audio")}function c(e={}){return e.control||e.setting}async function l(a){const s=r.m3u8?.quality||{};if(!c(s)||!a?.levels.length)return void n();const o=s.auto||"Auto",l=s.title||"Quality",u=s.getName||(e=>e.name||`${e.height}P`),h=a.currentLevel?u(a.currentLevel):o,f=e(a.levels.map(e=>({html:u(e),value:e.id,default:a.currentLevel?.id===e.id})),"html").sort((e,t)=>{const i=a.levels.find(t=>t.id===e.value),r=a.levels.find(e=>e.id===t.value);return(r?.height||0)-(i?.height||0)});f.push({html:o,value:"auto",default:!a.currentLevel});const m=async e=>(await i.switchM3u8Quality(e.value),t.notice.show=`${l}: ${e.html}`,await d(),e.html);s.control&&t.controls.update({name:"mediabunny-quality",position:"right",html:h,style:{padding:"0 10px"},selector:f,onSelect:m}),s.setting&&t.setting.update({name:"mediabunny-quality",tooltip:h,html:l,icon:'',width:200,selector:f,onSelect:m})}async function u(a){const s=r.m3u8?.audio||{};if(!c(s)||!a?.audios.length||a.audios.length<2)return void o();const n=s.auto||"Auto",l=s.title||"Audio",u=s.getName||(e=>e.name||e.lang||e.language),h=a.currentAudio?u(a.currentAudio):n,f=e(a.audios.map(e=>({html:u(e),value:e.id,default:a.currentAudio?.id===e.id})),"html");f.push({html:n,value:"auto",default:!a.currentAudio});const m=async e=>(await i.switchM3u8Audio(e.value),t.notice.show=`${l}: ${e.html}`,await d(),e.html);s.control&&t.controls.update({name:"mediabunny-audio",position:"right",html:h,style:{padding:"0 10px"},selector:f,onSelect:m}),s.setting&&t.setting.update({name:"mediabunny-audio",tooltip:h,html:l,icon:'',width:200,selector:f,onSelect:m})}async function d(){const e=await i.getM3u8State();if(!e)return n(),void o();await Promise.all([l(e),u(e)])}}({art:i,shim:o,option:t}),i.on("destroy",()=>{delete i.mediabunny,o.destroy()}),s}}}); diff --git a/docs/compiled/artplayer-proxy-mediabunny.legacy.js b/docs/compiled/artplayer-proxy-mediabunny.legacy.js index 979246864..7e89ad8c9 100644 --- a/docs/compiled/artplayer-proxy-mediabunny.legacy.js +++ b/docs/compiled/artplayer-proxy-mediabunny.legacy.js @@ -1,7 +1,7 @@ /*! - * artplayer-proxy-mediabunny.js v1.1.0 + * artplayer-proxy-mediabunny.js v1.2.0 * Github: https://github.com/zhw2590582/ArtPlayer * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,r=Object.getOwnPropertyDescriptors,i=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,a=(e,t)=>(t=Symbol[e])?t:Symbol.for("Symbol."+e),o=Math.pow,l=(t,r,i)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[r]=i,c=(e,t)=>{for(var r in t||(t={}))n.call(t,r)&&l(e,r,t[r]);if(i)for(var r of i(t))s.call(t,r)&&l(e,r,t[r]);return e},u=(e,t,r)=>new Promise((i,n)=>{var s=e=>{try{o(r.next(e))}catch(t){n(t)}},a=e=>{try{o(r.throw(e))}catch(t){n(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(s,a);o((r=r.apply(e,t)).next())}),d=function(e,t){this[0]=e,this[1]=t},h=e=>{var t,r=e[a("asyncIterator")],i=!1,n={};return null==r?(r=e[a("iterator")](),t=e=>n[e]=t=>r[e](t)):(r=r.call(e),t=e=>n[e]=t=>{if(i){if(i=!1,"throw"===e)throw t;return t}return i=!0,{done:!1,value:new d(new Promise(i=>{var n=r[e](t);n instanceof Object||(e=>{throw TypeError(e)})("Object expected"),i(n)}),1)}}),n[a("iterator")]=()=>n,t("next"),"throw"in r?t("throw"):n.throw=e=>{throw e},"return"in r&&t("return"),n},m=(e,t,r)=>(t=e[a("asyncIterator")])?t.call(e):(e=e[a("iterator")](),t={},(r=(r,i)=>(i=e[r])&&(t[r]=t=>new Promise((r,n,s)=>(t=i.call(e,t),s=t.done,Promise.resolve(t.value).then(e=>r({value:e,done:s}),n)))))("next"),r("return"),t);class f{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const r=this.listeners.get(e);if(!r)return;const i=r.indexOf(t);i>=0&&r.splice(i,1)}emit(e,t){const r=new Event(e);r.detail=t;const i=this.listeners.get(e);i&&i.forEach(e=>e(r))}}function p(e){if(!e)throw new Error("Assertion failed.")}const g=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},k=e=>e&&e[e.length-1];class b{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){var e;const t=Math.floor(this.pos/8),r=null!=(e=this.bytes[t])?e:0,i=7-(7&this.pos),n=(r&1<>i;return this.pos++,n}readBits(e){if(1===e)return this.readBit();let t=0;for(let r=0;r>r-i-1<{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<{const t=y(e);return 0===(1&t)?-(t>>1):t+1>>1},S=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),v=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),w=new TextDecoder,I=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),P={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},x=I(P),C={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},_=I(C),B={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},E=I(B),F=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class D{constructor(){this.currentPromise=Promise.resolve()}acquire(){return u(this,null,function*(){let e;const t=new Promise(t=>{e=t}),r=this.currentPromise;return this.currentPromise=t,yield r,e})}}const A=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),R=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,M=(e,t,r)=>{let i=0,n=e.length-1,s=-1;for(;i<=n;){const a=i+n>>1,o=r(e[a]);o===t?(s=a,n=a-1):o{let i=0,n=e.length-1,s=-1;for(;i<=n;){const a=i+(n-i+1)/2|0;r(e[a])<=t?(s=a,i=a+1):n=a-1}return s},z=(e,t,r)=>{const i=N(e,r(t),r);e.splice(i+1,0,t)},O=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},L=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return e[r]},U=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return r;return-1},V=function(e){return((e,t,r)=>{var i=(e,t,n,s)=>{try{var a=r[e](t),o=(t=a.value)instanceof d,l=a.done;Promise.resolve(o?t[0]:t).then(r=>o?i("return"===e?e:"next",t[1]?{done:r.done,value:r.value}:r,n,s):n({value:r,done:l})).catch(e=>i("throw",e,n,s))}catch(c){s(c)}},n=e=>s[e]=t=>new Promise((r,n)=>i(e,t,r,n)),s={};return r=r.apply(e,t),s[a("asyncIterator")]=()=>s,n("next"),n("throw"),n("return"),s})(this,null,function*(){Symbol.iterator in e?yield*h(e[Symbol.iterator]()):yield*h(e[Symbol.asyncIterator]())})},q=e=>{throw new Error(`Unexpected value: ${e}`)},H=(e,t,r)=>{const i=e.getUint8(t),n=e.getUint8(t+1),s=e.getUint8(t+2);return r?i|n<<8|s<<16:i<<16|n<<8|s},W=(e,t,r,i)=>{r>>>=0,r&=16777215,e.setUint8(t,r>>>16&255),e.setUint8(t+1,r>>>8&255),e.setUint8(t+2,255&r)},j=(e,t)=>({next(){return u(this,null,function*(){const r=yield e.next();return r.done?{value:void 0,done:!0}:{value:t(r.value),done:!1}})},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),K=(e,t,r)=>Math.max(t,Math.min(r,e)),$="und",Q=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},G=/^[a-z]{3}$/,X=e=>G.test(e),Y=1e6*(1+Number.EPSILON),J=(e,t)=>{const r=c(c({},e),t);if(e.headers||t.headers){const i=e.headers?Z(e.headers):{},n=t.headers?Z(t.headers):{},s=c({},i);Object.entries(n).forEach(([e,t])=>{const r=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());r&&delete s[r],s[e]=t}),r.headers=s}return r},Z=e=>{if(e instanceof Headers){const t={};return e.forEach((e,r)=>{t[r]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,r])=>{t[e]=r}),t}return e},ee=(e,t,r,i,n)=>u(null,null,function*(){let s=0;for(;;)try{return yield e(t,r)}catch(a){if(n())throw a;s++;const e=i(s,a,t);if(null===e)throw a;if(console.error("Retrying failed fetch. Error:",a),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&(yield new Promise(t=>setTimeout(t,1e3*e))),n())throw a}});class te{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let re=null;const ie=()=>{var e;return null!==re?re:re=!("undefined"===typeof navigator||!((null==(e=navigator.vendor)?void 0:e.match(/apple/i))||/AppleWebKit/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)||/\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent)))};let ne=null;const se=()=>{var e;return null!==ne?ne:ne="undefined"!==typeof navigator&&(null==(e=navigator.userAgent)?void 0:e.includes("Firefox"))};let ae=null;const oe=()=>{var e;return null!==ae?ae:ae=!("undefined"===typeof navigator||!(null==(e=navigator.vendor)?void 0:e.includes("Google Inc"))&&!/Chrome/.test(navigator.userAgent))};let le=null;const ce=(e,t)=>-1!==e?e:t,ue=(e,t,r,i)=>e<=i&&r<=t,de=e=>{const t=atob(e),r=new Uint8Array(t.length);for(let i=0;i{null!=Symbol.dispose||(Symbol.dispose=Symbol("Symbol.dispose"))},me=e=>"number"===typeof e&&!Number.isNaN(e);class fe{constructor(e,t){if(this.data=e,this.mimeType=t,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("string"!==typeof t)throw new TypeError("mimeType must be a string.")}}class pe{constructor(e,t,r,i){if(this.data=e,this.mimeType=t,this.name=r,this.description=i,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if(void 0!==t&&"string"!==typeof t)throw new TypeError("mimeType, when provided, must be a string.");if(void 0!==r&&"string"!==typeof r)throw new TypeError("name, when provided, must be a string.");if(void 0!==i&&"string"!==typeof i)throw new TypeError("description, when provided, must be a string.")}}const ge={default:!0,forced:!1,original:!1,commentary:!1,hearingImpaired:!1,visuallyImpaired:!1},ke=["pcm-s16","pcm-s16be","pcm-s24","pcm-s24be","pcm-s32","pcm-s32be","pcm-f32","pcm-f32be","pcm-f64","pcm-f64be","pcm-u8","pcm-s8","ulaw","alaw"],be=[{maxPictureSize:36864,maxBitrate:2e5,level:10},{maxPictureSize:73728,maxBitrate:8e5,level:11},{maxPictureSize:122880,maxBitrate:18e5,level:20},{maxPictureSize:245760,maxBitrate:36e5,level:21},{maxPictureSize:552960,maxBitrate:72e5,level:30},{maxPictureSize:983040,maxBitrate:12e6,level:31},{maxPictureSize:2228224,maxBitrate:18e6,level:40},{maxPictureSize:2228224,maxBitrate:3e7,level:41},{maxPictureSize:8912896,maxBitrate:6e7,level:50},{maxPictureSize:8912896,maxBitrate:12e7,level:51},{maxPictureSize:8912896,maxBitrate:18e7,level:52},{maxPictureSize:35651584,maxBitrate:18e7,level:60},{maxPictureSize:35651584,maxBitrate:24e7,level:61},{maxPictureSize:35651584,maxBitrate:48e7,level:62}],ye=".01.01.01.01.00",Te=".0.110.01.01.01.0",Se=e=>{const{codec:t,codecDescription:r,colorSpace:i,avcCodecInfo:n,hevcCodecInfo:s,vp9CodecInfo:a,av1CodecInfo:o}=e;if("avc"===t){if(p(null!==e.avcType),n){const t=new Uint8Array([n.avcProfileIndication,n.profileCompatibility,n.avcLevelIndication]);return`avc${e.avcType}.${A(t)}`}if(!r||r.byteLength<4)throw new TypeError("AVC decoder description is not provided or is not at least 4 bytes long.");return`avc${e.avcType}.${A(r.subarray(1,4))}`}if("hevc"===t){let e,t,i,n,a,o;if(s)e=s.generalProfileSpace,t=s.generalProfileIdc,i=R(s.generalProfileCompatibilityFlags),n=s.generalTierFlag,a=s.generalLevelIdc,o=[...s.generalConstraintIndicatorFlags];else{if(!r||r.byteLength<23)throw new TypeError("HEVC decoder description is not provided or is not at least 23 bytes long.");const s=v(r),l=s.getUint8(1);e=l>>6&3,t=31&l,i=R(s.getUint32(2)),n=l>>5&1,a=s.getUint8(12),o=[];for(let e=0;e<6;e++)o.push(s.getUint8(6+e))}let l="hev1.";for(l+=["","A","B","C"][e]+t,l+=".",l+=i.toString(16).toUpperCase(),l+=".",l+=0===n?"L":"H",l+=a;o.length>0&&0===o[o.length-1];)o.pop();return o.length>0&&(l+=".",l+=o.map(e=>e.toString(16).toUpperCase()).join(".")),l}if("vp8"===t)return"vp8";if("vp9"===t){if(!a){const t=e.width*e.height;let r=k(be).level;for(const e of be)if(t<=e.maxPictureSize){r=e.level;break}return`vp09.00.${r.toString().padStart(2,"0")}.08`}let t=`vp09.${a.profile.toString().padStart(2,"0")}.${a.level.toString().padStart(2,"0")}.${a.bitDepth.toString().padStart(2,"0")}.${a.chromaSubsampling.toString().padStart(2,"0")}`;return t+=`.${a.colourPrimaries.toString().padStart(2,"0")}.${a.transferCharacteristics.toString().padStart(2,"0")}.${a.matrixCoefficients.toString().padStart(2,"0")}.${a.videoFullRangeFlag.toString().padStart(2,"0")}`,t.endsWith(ye)&&(t=t.slice(0,-15)),t}if("av1"===t){if(!o){const t=e.width*e.height;let r=k(be).level;for(const e of be)if(t<=e.maxPictureSize){r=e.level;break}return`av01.0.${r.toString().padStart(2,"0")}M.08`}const t=o.profile,r=o.level.toString().padStart(2,"0"),n=o.tier?"H":"M",s=o.bitDepth.toString().padStart(2,"0"),a=o.monochrome?"1":"0",l=100*o.chromaSubsamplingX+10*o.chromaSubsamplingY+1*(o.chromaSubsamplingX&&o.chromaSubsamplingY?o.chromaSamplePosition:0),c=(null==i?void 0:i.primaries)?P[i.primaries]:1,u=(null==i?void 0:i.transfer)?C[i.transfer]:1,d=(null==i?void 0:i.matrix)?B[i.matrix]:1,h=(null==i?void 0:i.fullRange)?1:0;let m=`av01.${t}.${r}${n}.${s}`;return m+=`.${a}.${l.toString().padStart(3,"0")}`,m+=`.${c.toString().padStart(2,"0")}`,m+=`.${u.toString().padStart(2,"0")}`,m+=`.${d.toString().padStart(2,"0")}`,m+=`.${h}`,m.endsWith(Te)&&(m=m.slice(0,-17)),m}throw new TypeError(`Unhandled codec '${t}'.`)},ve=e=>{const{codec:t,codecDescription:r,aacCodecInfo:i}=e;if("aac"===t){if(!i)throw new TypeError("AAC codec info must be provided.");if(i.isMpeg2)return"mp4a.67";return`mp4a.40.${Pe(r).objectType}`}if("mp3"===t)return"mp3";if("opus"===t)return"opus";if("vorbis"===t)return"vorbis";if("flac"===t)return"flac";if(t&&ke.includes(t))return t;throw new TypeError(`Unhandled codec '${t}'.`)},we=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350],Ie=[-1,1,2,3,4,5,6,8],Pe=e=>{if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");const t=new b(e);let r=t.readBits(5);31===r&&(r=32+t.readBits(6));const i=t.readBits(4);let n=null;15===i?n=t.readBits(24):i=1&&s<=7&&(a=Ie[s]),{objectType:r,frequencyIndex:i,sampleRate:n,channelConfiguration:s,numberOfChannels:a}},xe=48e3,Ce=/^pcm-([usf])(\d+)+(be)?$/,_e=e=>{if(p(ke.includes(e)),"ulaw"===e)return{dataType:"ulaw",sampleSize:1,littleEndian:!0,silentValue:255};if("alaw"===e)return{dataType:"alaw",sampleSize:1,littleEndian:!0,silentValue:213};const t=Ce.exec(e);let r;p(t),r="u"===t[1]?"unsigned":"s"===t[1]?"signed":"float";return{dataType:r,sampleSize:Number(t[2])/8,littleEndian:"be"!==t[3],silentValue:"pcm-u8"===e?o(2,7):0}};var Be,Ee,Fe,De;(Ee=Be||(Be={}))[Ee.IDR=5]="IDR",Ee[Ee.SEI=6]="SEI",Ee[Ee.SPS=7]="SPS",Ee[Ee.PPS=8]="PPS",Ee[Ee.SPS_EXT=13]="SPS_EXT",(De=Fe||(Fe={}))[De.RASL_N=8]="RASL_N",De[De.RASL_R=9]="RASL_R",De[De.BLA_W_LP=16]="BLA_W_LP",De[De.RSV_IRAP_VCL23=23]="RSV_IRAP_VCL23",De[De.VPS_NUT=32]="VPS_NUT",De[De.SPS_NUT=33]="SPS_NUT",De[De.PPS_NUT=34]="PPS_NUT",De[De.PREFIX_SEI_NUT=39]="PREFIX_SEI_NUT",De[De.SUFFIX_SEI_NUT=40]="SUFFIX_SEI_NUT";const Ae=e=>{const t=[];let r=0;for(;r0&&i>r){const n=e.subarray(r,i);n.length>0&&t.push(n)}r=i+n}if(r0&&t.push(i)}return t},Re=(e,t)=>{const r=[];let i=0;const n=new DataView(e.buffer,e.byteOffset,e.byteLength);for(;i+t<=e.length;){let s;1===t?s=n.getUint8(i):2===t?s=n.getUint16(i,!1):3===t?s=H(n,i,!1):4===t?s=n.getUint32(i,!1):(q(t),p(!1)),i+=t;const a=e.subarray(i,i+s);r.push(a),i+=s}return r},Me=e=>{const t=[],r=e.length;for(let i=0;i{if(t.description){const r=3&S(t.description)[4];return Re(e,r+1)}return Ae(e)},Oe=(e,t)=>{if(t.description){return((e,t)=>{const r=e.reduce((e,r)=>e+t+r.byteLength,0),i=new Uint8Array(r);let n=0;for(const s of e){const e=new DataView(i.buffer,i.byteOffset,i.byteLength);switch(t){case 1:e.setUint8(n,s.byteLength);break;case 2:e.setUint16(n,s.byteLength,!1);break;case 3:W(e,n,s.byteLength);break;case 4:e.setUint32(n,s.byteLength,!1)}n+=t,i.set(s,n),n+=s.byteLength}return i})(e,(3&S(t.description)[4])+1)}return(e=>{const t=e.reduce((e,t)=>e+Ne.byteLength+t.byteLength,0),r=new Uint8Array(t);let i=0;for(const n of e)r.set(Ne,i),i+=Ne.byteLength,r.set(n,i),i+=n.byteLength;return r})(e)},Le=e=>31&e[0],Ue=e=>{try{const t=Ae(e),r=t.filter(e=>Le(e)===Be.SPS),i=t.filter(e=>Le(e)===Be.PPS),n=t.filter(e=>Le(e)===Be.SPS_EXT);if(0===r.length)return null;if(0===i.length)return null;const s=r[0],a=Ve(s);p(null!==a);const o=100===a.profileIdc||110===a.profileIdc||122===a.profileIdc||144===a.profileIdc;return{configurationVersion:1,avcProfileIndication:a.profileIdc,profileCompatibility:a.constraintFlags,avcLevelIndication:a.levelIdc,lengthSizeMinusOne:3,sequenceParameterSets:r,pictureParameterSets:i,chromaFormat:o?a.chromaFormatIdc:null,bitDepthLumaMinus8:o?a.bitDepthLumaMinus8:null,bitDepthChromaMinus8:o?a.bitDepthChromaMinus8:null,sequenceParameterSetExt:o?n:null}}catch(t){return console.error("Error building AVC Decoder Configuration Record:",t),null}},Ve=e=>{try{const t=new b(Me(e));t.skipBits(1),t.skipBits(2);if(7!==t.readBits(5))return null;const r=t.readAlignedByte(),i=t.readAlignedByte(),n=t.readAlignedByte();y(t);let s=null,a=null,o=null;if(100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r){s=y(t),3===s&&t.skipBits(1),a=y(t),o=y(t),t.skipBits(1);if(t.readBits(1))for(let e=0;e<(3!==s?8:12);e++){if(t.readBits(1)){const r=e<6?16:64;let i=8,n=8;for(let e=0;e{if(t.description){const r=3&S(t.description)[21];return Re(e,r+1)}return Ae(e)},He=e=>e[0]>>1&63,We=e=>{try{const t=Ae(e),r=t.filter(e=>He(e)===Fe.VPS_NUT),i=t.filter(e=>He(e)===Fe.SPS_NUT),n=t.filter(e=>He(e)===Fe.PPS_NUT),s=t.filter(e=>He(e)===Fe.PREFIX_SEI_NUT||He(e)===Fe.SUFFIX_SEI_NUT);if(0===i.length||0===n.length)return null;const a=i[0],o=new b(Me(a));o.skipBits(16),o.readBits(4);const l=o.readBits(3),c=o.readBits(1),{general_profile_space:u,general_tier_flag:d,general_profile_idc:h,general_profile_compatibility_flags:m,general_constraint_indicator_flags:f,general_level_idc:p}=je(o,l);y(o);const g=y(o);3===g&&o.skipBits(1),y(o),y(o),o.readBits(1)&&(y(o),y(o),y(o),y(o));const k=y(o),S=y(o);y(o);const v=o.readBits(1);for(let e=v?0:l;e<=l;e++)y(o),y(o),y(o);y(o),y(o),y(o),y(o),y(o),y(o),o.readBits(1)&&o.readBits(1)&&Ke(o),o.skipBits(1),o.skipBits(1),o.readBits(1)&&(o.skipBits(4),o.skipBits(4),y(o),y(o),o.skipBits(1));const w=y(o);if($e(o,w),o.readBits(1)){const e=y(o);for(let t=0;t0){const e=n[0],t=new b(Me(e));t.skipBits(16),y(t),y(t),t.skipBits(1),t.skipBits(1),t.skipBits(3),t.skipBits(1),t.skipBits(1),y(t),y(t),T(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&y(t),T(t),T(t),t.skipBits(1),t.skipBits(1),t.skipBits(1),t.skipBits(1);const r=t.readBits(1),i=t.readBits(1);P=r||i?r&&!i?2:!r&&i?3:0:0}const x=[...r.length?[{arrayCompleteness:1,nalUnitType:Fe.VPS_NUT,nalUnits:r}]:[],...i.length?[{arrayCompleteness:1,nalUnitType:Fe.SPS_NUT,nalUnits:i}]:[],...n.length?[{arrayCompleteness:1,nalUnitType:Fe.PPS_NUT,nalUnits:n}]:[],...s.length?[{arrayCompleteness:1,nalUnitType:He(s[0]),nalUnits:s}]:[]];return{configurationVersion:1,generalProfileSpace:u,generalTierFlag:d,generalProfileIdc:h,generalProfileCompatibilityFlags:m,generalConstraintIndicatorFlags:f,generalLevelIdc:p,minSpatialSegmentationIdc:I,parallelismType:P,chromaFormatIdc:g,bitDepthLumaMinus8:k,bitDepthChromaMinus8:S,avgFrameRate:0,constantFrameRate:0,numTemporalLayers:l+1,temporalIdNested:c,lengthSizeMinusOne:3,arrays:x}}catch(t){return console.error("Error building HEVC Decoder Configuration Record:",t),null}},je=(e,t)=>{const r=e.readBits(2),i=e.readBits(1),n=e.readBits(5);let s=0;for(let u=0;u<32;u++)s=s<<1|e.readBits(1);const a=new Uint8Array(6);for(let u=0;u<6;u++)a[u]=e.readBits(8);const o=e.readBits(8),l=[],c=[];for(let u=0;u0)for(let u=t;u<8;u++)e.skipBits(2);for(let u=0;u{for(let t=0;t<4;t++)for(let r=0;r<(3===t?2:6);r++){if(e.readBits(1)){const r=Math.min(64,1<<4+(t<<1));t>1&&T(e);for(let t=0;t{const r=[];for(let i=0;i{var n;let s=0,a=0,o=0;if(0!==t&&(a=e.readBits(1)),a){if(t===r){o=t-(y(e)+1)}else o=t-1;e.readBits(1),y(e);const a=null!=(n=i[o])?n:0;for(let t=0;t<=a;t++){e.readBits(1)||e.readBits(1)}s=i[o]}else{const t=y(e),r=y(e);for(let i=0;i{if(e.readBits(1)){255===e.readBits(8)&&(e.readBits(16),e.readBits(16))}if(e.readBits(1)&&e.readBits(1),e.readBits(1)&&(e.readBits(3),e.readBits(1),e.readBits(1)&&(e.readBits(8),e.readBits(8),e.readBits(8))),e.readBits(1)&&(y(e),y(e)),e.readBits(1),e.readBits(1),e.readBits(1),e.readBits(1)&&(y(e),y(e),y(e),y(e)),e.readBits(1)&&(e.readBits(32),e.readBits(32),e.readBits(1)&&y(e),e.readBits(1)&&Xe(e,!0,t)),e.readBits(1)){e.readBits(1),e.readBits(1),e.readBits(1);const t=y(e);return y(e),y(e),y(e),y(e),t}return 0},Xe=(e,t,r)=>{let i=!1,n=!1,s=!1;i=1===e.readBits(1),n=1===e.readBits(1),(i||n)&&(s=1===e.readBits(1),s&&(e.readBits(8),e.readBits(5),e.readBits(1),e.readBits(5)),e.readBits(4),e.readBits(4),s&&e.readBits(4),e.readBits(5),e.readBits(5),e.readBits(5));for(let a=0;a<=r;a++){let t=!0;1===e.readBits(1)||(t=1===e.readBits(1));let r=!1;t?y(e):r=1===e.readBits(1);let a=1;if(!r){a=y(e)+1}i&&Ye(e,a,s),n&&Ye(e,a,s)}},Ye=(e,t,r)=>{for(let i=0;i{const t=new b(e);if(2!==t.readBits(2))return null;const r=t.readBits(1),i=(t.readBits(1)<<1)+r;3===i&&t.skipBits(1);if(1===t.readBits(1))return null;if(0!==t.readBits(1))return null;t.skipBits(2);if(4817730!==t.readBits(24))return null;let n=8;if(i>=2){n=t.readBits(1)?12:10}const s=t.readBits(3);let a=0,o=0;if(7!==s){if(o=t.readBits(1),1===i||3===i){const e=t.readBits(1),r=t.readBits(1);a=e||r?e&&!r?2:1:3,t.skipBits(1)}else a=1}else a=3,o=1;const l=(t.readBits(16)+1)*(t.readBits(16)+1);let c=k(be).level;for(const u of be)if(l<=u.maxPictureSize){c=u.level;break}return{profile:i,level:c,bitDepth:n,chromaSubsampling:a,videoFullRangeFlag:o,colourPrimaries:2===s?1:1===s?6:2,transferCharacteristics:2===s?1:1===s?6:2,matrixCoefficients:7===s?0:2===s?1:1===s?6:2}},Ze=function*(e){const t=new b(e),r=()=>{let e=0;for(let r=0;r<8;r++){const i=t.readAlignedByte();if(e|=(127&i)<<7*r,!(128&i))break;if(7===r&&128&i)return null}return e>=o(2,32)-1?null:e};for(;t.getBitsLeft()>=8;){t.skipBits(1);const i=t.readBits(4),n=t.readBits(1),s=t.readBits(1);let a;if(t.skipBits(1),n&&t.skipBits(8),s){const e=r();if(null===e)return;a=e}else a=Math.floor(t.getBitsLeft()/8);p(t.pos%8===0),yield{type:i,data:e.subarray(t.pos/8,t.pos/8+a)},t.skipBits(8*a)}},et=e=>{for(const{type:t,data:r}of Ze(e)){if(1!==t)continue;const e=new b(r),i=e.readBits(3);e.readBits(1);const n=e.readBits(1);let s=0,a=0,o=0;if(n)s=e.readBits(5);else{if(e.readBits(1)){e.skipBits(32),e.skipBits(32);if(e.readBits(1))return null}const t=e.readBits(1);t&&(o=e.readBits(5),e.skipBits(32),e.skipBits(5),e.skipBits(5));const r=e.readBits(5);for(let i=0;i<=r;i++){e.skipBits(12);const r=e.readBits(5);if(0===i&&(s=r),r>7){const t=e.readBits(1);0===i&&(a=t)}if(t){if(e.readBits(1)){const t=o+1;e.skipBits(t),e.skipBits(t),e.skipBits(1)}}e.readBits(1)&&e.skipBits(4)}}const l=e.readBits(4),c=e.readBits(4),u=l+1;e.skipBits(u);const d=c+1;e.skipBits(d);let h=0;if(h=n?0:e.readBits(1),h&&(e.skipBits(4),e.skipBits(3)),e.skipBits(1),e.skipBits(1),e.skipBits(1),!n){e.skipBits(1),e.skipBits(1),e.skipBits(1),e.skipBits(1);const t=e.readBits(1);t&&(e.skipBits(1),e.skipBits(1));let r=0;if(r=e.readBits(1)?2:e.readBits(1),r>0){e.readBits(1)||e.skipBits(1)}t&&e.skipBits(3)}e.skipBits(1),e.skipBits(1),e.skipBits(1);const m=e.readBits(1);let f=8;if(2===i&&m){f=e.readBits(1)?12:10}else i<=2&&(f=m?10:8);let p=0;1!==i&&(p=e.readBits(1));let g=1,k=1,y=0;return p||(0===i?(g=1,k=1):1===i?(g=0,k=0):12===f&&(g=e.readBits(1),g&&(k=e.readBits(1))),g&&k&&(y=e.readBits(2))),{profile:i,level:s,tier:a,bitDepth:f,monochrome:p,chromaSubsamplingX:g,chromaSubsamplingY:k,chromaSamplePosition:y}}return null},tt=[480,960,1920,2880,480,960,1920,2880,480,960,1920,2880,480,960,480,960,120,240,480,960,120,240,480,960,120,240,480,960,120,240,480,960],rt=e=>{if(e.length<7)throw new Error("Setup header is too short.");if(5!==e[0])throw new Error("Wrong packet type in Setup header.");if("vorbis"!==String.fromCharCode(...e.slice(1,7)))throw new Error("Invalid packet signature in Setup header.");const t=e.length,r=new Uint8Array(t);for(let u=0;u97;)if(1===i.readBits(1)){n=i.pos;break}if(0===n)throw new Error("Invalid Setup header: framing bit not found.");let s=0,a=!1,o=0;for(;i.getBitsLeft()>=97;){const e=i.pos,t=i.readBits(8),r=i.readBits(16),n=i.readBits(16);if(t>63||0!==r||0!==n){i.pos=e;break}if(i.skipBits(1),s++,s>64)break;i.clone().readBits(6)+1===s&&(a=!0,o=s)}if(!a)throw new Error("Invalid Setup header: mode header not found.");if(o>63)throw new Error(`Unsupported mode count: ${o}.`);const l=o;i.pos=0,i.skipBits(n);const c=Array(l).fill(0);for(let u=l-1;u>=0;u--)i.skipBits(40),c[u]=i.readBits(1);return{modeBlockflags:c}},it=(e,t,r)=>{switch(e){case"avc":{const e=ze(r,t);let i=e.some(e=>Le(e)===Be.IDR);if(!i&&(!oe()||(()=>{if(null!==le)return le;if("undefined"===typeof navigator)return null;const e=/\bChrome\/(\d+)/.exec(navigator.userAgent);return e?le=Number(e[1]):null})()>=144))for(const t of e){if(Le(t)!==Be.SEI)continue;const e=Me(t);let r=1;do{let t=0;for(;;){const i=e[r++];if(void 0===i)break;if(t+=i,i<255)break}let n=0;for(;;){const t=e[r++];if(void 0===t)break;if(n+=t,t<255)break}if(t===6){const t=new b(e);t.pos=8*r;const n=y(t),s=t.readBits(1);if(0===n&&1===s){i=!0;break}}r+=n}while(r{const t=He(e);return Fe.BLA_W_LP<=t&&t<=Fe.RSV_IRAP_VCL23})?"key":"delta";case"vp8":return 0===(1&r[0])?"key":"delta";case"vp9":{const e=new b(r);if(2!==e.readBits(2))return null;const t=e.readBits(1);3===(e.readBits(1)<<1)+t&&e.skipBits(1);if(e.readBits(1))return null;return 0===e.readBits(1)?"key":"delta"}case"av1":{let e=!1;for(const{type:t,data:i}of Ze(r))if(1===t){const t=new b(i);t.skipBits(4),e=!!t.readBits(1)}else if(3===t||6===t||7===t){if(e)return"key";const t=new b(i);if(t.readBits(1))return null;return 0===t.readBits(2)?"key":"delta"}return null}default:q(e),p(!1)}};var nt,st;(st=nt||(nt={}))[st.STREAMINFO=0]="STREAMINFO",st[st.VORBIS_COMMENT=4]="VORBIS_COMMENT",st[st.PICTURE=6]="PICTURE";const at=(e,t)=>{var r,i;const n=v(e);let s=0;const a=n.getUint32(s,!0);s+=4;const o=w.decode(e.subarray(s,s+a));s+=a,a>0&&(null!=t.raw||(t.raw={}),null!=(r=t.raw).vendor||(r.vendor=o));const l=n.getUint32(s,!0);s+=4;for(let c=0;c0&&(null!=t.trackNumber||(t.trackNumber=r)),i&&Number.isInteger(i)&&i>0&&(null!=t.tracksTotal||(t.tracksTotal=i))}break;case"TRACKTOTAL":{const e=Number.parseInt(c,10);Number.isInteger(e)&&e>0&&(null!=t.tracksTotal||(t.tracksTotal=e))}break;case"DISCNUMBER":{const e=c.split("/"),r=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(null!=t.discNumber||(t.discNumber=r)),i&&Number.isInteger(i)&&i>0&&(null!=t.discsTotal||(t.discsTotal=i))}break;case"DISCTOTAL":{const e=Number.parseInt(c,10);Number.isInteger(e)&&e>0&&(null!=t.discsTotal||(t.discsTotal=e))}break;case"DATE":{const e=new Date(c);Number.isNaN(e.getTime())||null!=t.date||(t.date=e)}break;case"GENRE":null!=t.genre||(t.genre=c);break;case"METADATA_BLOCK_PICTURE":{const e=de(c),r=v(e),i=r.getUint32(0,!1),n=r.getUint32(4,!1),s=String.fromCharCode(...e.subarray(8,8+n)),a=r.getUint32(8+n,!1),o=w.decode(e.subarray(12+n,12+n+a)),l=r.getUint32(n+a+28),u=e.subarray(n+a+32,n+a+32+l);null!=t.images||(t.images=[]),t.images.push({data:u,mimeType:s,kind:3===i?"coverFront":4===i?"coverBack":"unknown",name:void 0,description:o||void 0})}}}};class ot{constructor(e){this.input=e}}const lt=[],ct=[],ut=new Uint8Array(0);class dt{constructor(e,t,r,i,n=-1,s,a){if(this.data=e,this.type=t,this.timestamp=r,this.duration=i,this.sequenceNumber=n,e===ut&&void 0===s)throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets.");if(void 0===s&&(s=e.byteLength),!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("key"!==t&&"delta"!==t)throw new TypeError('type must be either "key" or "delta".');if(!Number.isFinite(r))throw new TypeError("timestamp must be a number.");if(!Number.isFinite(i)||i<0)throw new TypeError("duration must be a non-negative number.");if(!Number.isFinite(n))throw new TypeError("sequenceNumber must be a number.");if(!Number.isInteger(s)||s<0)throw new TypeError("byteLength must be a non-negative integer.");if(void 0!==a&&("object"!==typeof a||!a))throw new TypeError("sideData, when provided, must be an object.");if(void 0!==(null==a?void 0:a.alpha)&&!(a.alpha instanceof Uint8Array))throw new TypeError("sideData.alpha, when provided, must be a Uint8Array.");if(void 0!==(null==a?void 0:a.alphaByteLength)&&(!Number.isInteger(a.alphaByteLength)||a.alphaByteLength<0))throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer.");this.byteLength=s,this.sideData=null!=a?a:{},this.sideData.alpha&&void 0===this.sideData.alphaByteLength&&(this.sideData.alphaByteLength=this.sideData.alpha.byteLength)}get isMetadataOnly(){return this.data===ut}get microsecondTimestamp(){return Math.trunc(Y*this.timestamp)}get microsecondDuration(){return Math.trunc(Y*this.duration)}toEncodedVideoChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}alphaToEncodedVideoChunk(e=this.type){if(!this.sideData.alpha)throw new TypeError("This packet does not contain alpha side data.");if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.sideData.alpha,type:e,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}toEncodedAudioChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to an audio chunk.");if("undefined"===typeof EncodedAudioChunk)throw new Error("Your browser does not support EncodedAudioChunk.");return new EncodedAudioChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}static fromEncodedChunk(e,t){var r;if(!(e instanceof EncodedVideoChunk||e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk.");const i=new Uint8Array(e.byteLength);return e.copyTo(i),new dt(i,e.type,e.timestamp/1e6,(null!=(r=e.duration)?r:0)/1e6,void 0,void 0,t)}clone(e){var t,r;if(void 0!==e&&("object"!==typeof e||null===e))throw new TypeError("options, when provided, must be an object.");if(void 0!==(null==e?void 0:e.timestamp)&&!Number.isFinite(e.timestamp))throw new TypeError("options.timestamp, when provided, must be a number.");if(void 0!==(null==e?void 0:e.duration)&&!Number.isFinite(e.duration))throw new TypeError("options.duration, when provided, must be a number.");return new dt(this.data,this.type,null!=(t=null==e?void 0:e.timestamp)?t:this.timestamp,null!=(r=null==e?void 0:e.duration)?r:this.duration,this.sequenceNumber,this.byteLength)}}he();let ht=-1/0,mt=-1/0,ft=null;"undefined"!==typeof FinalizationRegistry&&(ft=new FinalizationRegistry(e=>{const t=Date.now();"video"===e.type?(t-ht>=1e3&&(console.error("A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them."),ht=t),"undefined"!==typeof VideoFrame&&e.data instanceof VideoFrame&&e.data.close()):(t-mt>=1e3&&(console.error("An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them."),mt=t),"undefined"!==typeof AudioData&&e.data instanceof AudioData&&e.data.close())}));const pt=["I420","I420P10","I420P12","I420A","I420AP10","I420AP12","I422","I422P10","I422P12","I422A","I422AP10","I422AP12","I444","I444P10","I444P12","I444A","I444AP10","I444AP12","NV12","RGBA","RGBX","BGRA","BGRX"],gt=new Set(pt);class kt{get displayWidth(){return this.rotation%180===0?this.codedWidth:this.codedHeight}get displayHeight(){return this.rotation%180===0?this.codedHeight:this.codedWidth}get microsecondTimestamp(){return Math.trunc(Y*this.timestamp)}get microsecondDuration(){return Math.trunc(Y*this.duration)}get hasAlpha(){return this.format&&this.format.includes("A")}constructor(e,t){var r,i,n,s,a,o,l,c,u,d;if(this._closed=!1,e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e)){if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0===t.format||!gt.has(t.format))throw new TypeError("init.format must be one of: "+pt.join(", "));if(!Number.isInteger(t.codedWidth)||t.codedWidth<=0)throw new TypeError("init.codedWidth must be a positive integer.");if(!Number.isInteger(t.codedHeight)||t.codedHeight<=0)throw new TypeError("init.codedHeight must be a positive integer.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");this._data=S(e).slice(),this._layout=null!=(r=t.layout)?r:wt(t.format,t.codedWidth,t.codedHeight),this.format=t.format,this.codedWidth=t.codedWidth,this.codedHeight=t.codedHeight,this.rotation=null!=(i=t.rotation)?i:0,this.timestamp=t.timestamp,this.duration=null!=(n=t.duration)?n:0,this.colorSpace=new bt(t.colorSpace)}else if("undefined"!==typeof VideoFrame&&e instanceof VideoFrame){if(void 0!==(null==t?void 0:t.rotation)&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(void 0!==(null==t?void 0:t.timestamp)&&!Number.isFinite(null==t?void 0:t.timestamp))throw new TypeError("init.timestamp, when provided, must be a number.");if(void 0!==(null==t?void 0:t.duration)&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");this._data=e,this._layout=null,this.format=e.format,this.codedWidth=e.displayWidth,this.codedHeight=e.displayHeight,this.rotation=null!=(s=null==t?void 0:t.rotation)?s:0,this.timestamp=null!=(a=null==t?void 0:t.timestamp)?a:e.timestamp/1e6,this.duration=null!=(l=null==t?void 0:t.duration)?l:(null!=(o=e.duration)?o:0)/1e6,this.colorSpace=new bt(e.colorSpace)}else{if(!("undefined"!==typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!==typeof SVGImageElement&&e instanceof SVGImageElement||"undefined"!==typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!==typeof HTMLVideoElement&&e instanceof HTMLVideoElement||"undefined"!==typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!==typeof OffscreenCanvas&&e instanceof OffscreenCanvas))throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource.");{if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if("undefined"!==typeof VideoFrame)return new kt(new VideoFrame(e,{timestamp:Math.trunc(t.timestamp*Y),duration:Math.trunc((null!=(c=t.duration)?c:0)*Y)||void 0}),t);let r=0,i=0;if("naturalWidth"in e?(r=e.naturalWidth,i=e.naturalHeight):"videoWidth"in e?(r=e.videoWidth,i=e.videoHeight):"width"in e&&(r=Number(e.width),i=Number(e.height)),!r||!i)throw new TypeError("Could not determine dimensions.");const n=new OffscreenCanvas(r,i),s=n.getContext("2d",{alpha:se(),willReadFrequently:!0});p(s),s.drawImage(e,0,0),this._data=n,this._layout=null,this.format="RGBX",this.codedWidth=r,this.codedHeight=i,this.rotation=null!=(u=t.rotation)?u:0,this.timestamp=t.timestamp,this.duration=null!=(d=t.duration)?d:0,this.colorSpace=new bt({matrix:"rgb",primaries:"bt709",transfer:"iec61966-2-1",fullRange:!0})}}null==ft||ft.register(this,{type:"video",data:this._data},this)}clone(){if(this._closed)throw new Error("VideoSample is closed.");return p(null!==this._data),yt(this._data)?new kt(this._data.clone(),{timestamp:this.timestamp,duration:this.duration,rotation:this.rotation}):this._data instanceof Uint8Array?(p(this._layout),new kt(this._data,{format:this.format,layout:this._layout,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation})):new kt(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation})}close(){this._closed||(null==ft||ft.unregister(this),yt(this._data)?this._data.close():this._data=null,this._closed=!0)}allocationSize(e={}){if(vt(e),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot get allocation size when format is null. Sorry!");if(p(null!==this._data),!yt(this._data)&&(e.colorSpace||e.format&&e.format!==this.format||e.layout||e.rect)){const t=this.toVideoFrame(),r=t.allocationSize(e);return t.close(),r}return yt(this._data)?this._data.allocationSize(e):this._data instanceof Uint8Array?this._data.byteLength:this.codedWidth*this.codedHeight*4}copyTo(e){return u(this,arguments,function*(e,t={}){if(!F(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(vt(t),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot copy video sample data when format is null. Sorry!");if(p(null!==this._data),!yt(this._data)&&(t.colorSpace||t.format&&t.format!==this.format||t.layout||t.rect)){const r=this.toVideoFrame(),i=yield r.copyTo(e,t);return r.close(),i}if(yt(this._data))return this._data.copyTo(e,t);if(this._data instanceof Uint8Array){p(this._layout);return S(e).set(this._data),this._layout}{const t=this._data.getContext("2d");p(t);const r=t.getImageData(0,0,this.codedWidth,this.codedHeight);return S(e).set(r.data),[{offset:0,stride:4*this.codedWidth}]}})}toVideoFrame(){if(this._closed)throw new Error("VideoSample is closed.");return p(null!==this._data),yt(this._data)?new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0}):this._data instanceof Uint8Array?new VideoFrame(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0,colorSpace:this.colorSpace}):new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0})}draw(e,t,r,i,n,s,a,o,l){let c=0,u=0,d=this.displayWidth,h=this.displayHeight,m=0,f=0,p=this.displayWidth,g=this.displayHeight;if(void 0!==s?(c=t,u=r,d=i,h=n,m=s,f=a,void 0!==o?(p=o,g=l):(p=d,g=h)):(m=t,f=r,void 0!==i&&(p=i,g=n)),!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!Number.isFinite(c))throw new TypeError("sx must be a number.");if(!Number.isFinite(u))throw new TypeError("sy must be a number.");if(!Number.isFinite(d)||d<0)throw new TypeError("sWidth must be a non-negative number.");if(!Number.isFinite(h)||h<0)throw new TypeError("sHeight must be a non-negative number.");if(!Number.isFinite(m))throw new TypeError("dx must be a number.");if(!Number.isFinite(f))throw new TypeError("dy must be a number.");if(!Number.isFinite(p)||p<0)throw new TypeError("dWidth must be a non-negative number.");if(!Number.isFinite(g)||g<0)throw new TypeError("dHeight must be a non-negative number.");if(this._closed)throw new Error("VideoSample is closed.");({sx:c,sy:u,sWidth:d,sHeight:h}=this._rotateSourceRegion(c,u,d,h,this.rotation));const k=this.toCanvasImageSource();e.save();const b=m+p/2,y=f+g/2;e.translate(b,y),e.rotate(this.rotation*Math.PI/180);const T=this.rotation%180===0?1:p/g;e.scale(1/T,T),e.drawImage(k,c,u,d,h,-p/2,-g/2,p,g),e.restore()}drawWithFit(e,t){var r,i,n,s,a,o,l,c,u;if(!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!["fill","contain","cover"].includes(t.fit))throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270.");void 0!==t.crop&&St(t.crop,"options.");const d=e.canvas.width,h=e.canvas.height,m=null!=(r=t.rotation)?r:this.rotation,[f,p]=m%180===0?[this.codedWidth,this.codedHeight]:[this.codedHeight,this.codedWidth];let g,k,b,y;t.crop&&Tt(t.crop,f,p);const{sx:T,sy:S,sWidth:v,sHeight:w}=this._rotateSourceRegion(null!=(n=null==(i=t.crop)?void 0:i.left)?n:0,null!=(a=null==(s=t.crop)?void 0:s.top)?a:0,null!=(l=null==(o=t.crop)?void 0:o.width)?l:f,null!=(u=null==(c=t.crop)?void 0:c.height)?u:p,m);if("fill"===t.fit)g=0,k=0,b=d,y=h;else{const[e,r]=t.crop?[t.crop.width,t.crop.height]:[f,p],i="contain"===t.fit?Math.min(d/e,h/r):Math.max(d/e,h/r);b=e*i,y=r*i,g=(d-b)/2,k=(h-y)/2}e.save();const I=m%180===0?1:b/y;e.translate(d/2,h/2),e.rotate(m*Math.PI/180),e.scale(1/I,I),e.translate(-d/2,-h/2),e.drawImage(this.toCanvasImageSource(),T,S,v,w,g,k,b,y),e.restore()}_rotateSourceRegion(e,t,r,i,n){return 90===n?[e,t,r,i]=[t,this.codedHeight-e-r,i,r]:180===n?[e,t]=[this.codedWidth-e-r,this.codedHeight-t-i]:270===n&&([e,t,r,i]=[this.codedWidth-t-i,e,i,r]),{sx:e,sy:t,sWidth:r,sHeight:i}}toCanvasImageSource(){if(this._closed)throw new Error("VideoSample is closed.");if(p(null!==this._data),this._data instanceof Uint8Array){const e=this.toVideoFrame();return queueMicrotask(()=>e.close()),e}return this._data}setRotation(e){if(![0,90,180,270].includes(e))throw new TypeError("newRotation must be 0, 90, 180, or 270.");this.rotation=e}setTimestamp(e){if(!Number.isFinite(e))throw new TypeError("newTimestamp must be a number.");this.timestamp=e}setDuration(e){if(!Number.isFinite(e)||e<0)throw new TypeError("newDuration must be a non-negative number.");this.duration=e}[Symbol.dispose](){this.close()}}class bt{constructor(e){var t,r,i,n;this.primaries=null!=(t=null==e?void 0:e.primaries)?t:null,this.transfer=null!=(r=null==e?void 0:e.transfer)?r:null,this.matrix=null!=(i=null==e?void 0:e.matrix)?i:null,this.fullRange=null!=(n=null==e?void 0:e.fullRange)?n:null}toJSON(){return{primaries:this.primaries,transfer:this.transfer,matrix:this.matrix,fullRange:this.fullRange}}}const yt=e=>"undefined"!==typeof VideoFrame&&e instanceof VideoFrame,Tt=(e,t,r)=>{e.left=Math.min(e.left,t),e.top=Math.min(e.top,r),e.width=Math.min(e.width,t-e.left),e.height=Math.min(e.height,r-e.top),p(e.width>=0),p(e.height>=0)},St=(e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(t+"crop, when provided, must be an object.");if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(t+"crop.left must be a non-negative integer.");if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(t+"crop.top must be a non-negative integer.");if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(t+"crop.width must be a non-negative integer.");if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(t+"crop.height must be a non-negative integer.")},vt=e=>{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.colorSpace&&!["display-p3","srgb"].includes(e.colorSpace))throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");if(void 0!==e.format&&"string"!==typeof e.format)throw new TypeError("options.format, when provided, must be a string.");if(void 0!==e.layout){if(!Array.isArray(e.layout))throw new TypeError("options.layout, when provided, must be an array.");for(const t of e.layout){if(!t||"object"!==typeof t)throw new TypeError("Each entry in options.layout must be an object.");if(!Number.isInteger(t.offset)||t.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(t.stride)||t.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==e.rect){if(!e.rect||"object"!==typeof e.rect)throw new TypeError("options.rect, when provided, must be an object.");if(void 0!==e.rect.x&&(!Number.isInteger(e.rect.x)||e.rect.x<0))throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");if(void 0!==e.rect.y&&(!Number.isInteger(e.rect.y)||e.rect.y<0))throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");if(void 0!==e.rect.width&&(!Number.isInteger(e.rect.width)||e.rect.width<0))throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");if(void 0!==e.rect.height&&(!Number.isInteger(e.rect.height)||e.rect.height<0))throw new TypeError("options.rect.height, when provided, must be a non-negative integer.")}},wt=(e,t,r)=>{const i=It(e),n=[];let s=0;for(const a of i){const e=Math.ceil(t/a.widthDivisor),i=Math.ceil(r/a.heightDivisor),o=e*a.sampleBytes,l=o*i;n.push({offset:s,stride:o}),s+=l}return n},It=e=>{const t=(e,t,r,i,n)=>{const s=[{sampleBytes:e,widthDivisor:1,heightDivisor:1},{sampleBytes:t,widthDivisor:r,heightDivisor:i},{sampleBytes:t,widthDivisor:r,heightDivisor:i}];return n&&s.push({sampleBytes:e,widthDivisor:1,heightDivisor:1}),s};switch(e){case"I420":return t(1,1,2,2,!1);case"I420P10":case"I420P12":return t(2,2,2,2,!1);case"I420A":return t(1,1,2,2,!0);case"I420AP10":case"I420AP12":return t(2,2,2,2,!0);case"I422":return t(1,1,2,1,!1);case"I422P10":case"I422P12":return t(2,2,2,1,!1);case"I422A":return t(1,1,2,1,!0);case"I422AP10":case"I422AP12":return t(2,2,2,1,!0);case"I444":return t(1,1,1,1,!1);case"I444P10":case"I444P12":return t(2,2,1,1,!1);case"I444A":return t(1,1,1,1,!0);case"I444AP10":case"I444AP12":return t(2,2,1,1,!0);case"NV12":return[{sampleBytes:1,widthDivisor:1,heightDivisor:1},{sampleBytes:2,widthDivisor:2,heightDivisor:2}];case"RGBA":case"RGBX":case"BGRA":case"BGRX":return[{sampleBytes:4,widthDivisor:1,heightDivisor:1}];default:q(e),p(!1)}},Pt=new Set(["f32","f32-planar","s16","s16-planar","s32","s32-planar","u8","u8-planar"]);class xt{get microsecondTimestamp(){return Math.trunc(Y*this.timestamp)}get microsecondDuration(){return Math.trunc(Y*this.duration)}constructor(e){if(this._closed=!1,Ft(e)){if(null===e.format)throw new TypeError("AudioData with null format is not supported.");this._data=e,this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=e.numberOfFrames,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp/1e6,this.duration=e.numberOfFrames/e.sampleRate}else{if(!e||"object"!==typeof e)throw new TypeError("Invalid AudioDataInit: must be an object.");if(!Pt.has(e.format))throw new TypeError("Invalid AudioDataInit: invalid format.");if(!Number.isFinite(e.sampleRate)||e.sampleRate<=0)throw new TypeError("Invalid AudioDataInit: sampleRate must be > 0.");if(!Number.isInteger(e.numberOfChannels)||0===e.numberOfChannels)throw new TypeError("Invalid AudioDataInit: numberOfChannels must be an integer > 0.");if(!Number.isFinite(null==e?void 0:e.timestamp))throw new TypeError("init.timestamp must be a number.");const t=e.data.byteLength/(Ct(e.format)*e.numberOfChannels);if(!Number.isInteger(t))throw new TypeError("Invalid AudioDataInit: data size is not a multiple of frame size.");let r;if(this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=t,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp,this.duration=t/e.sampleRate,e.data instanceof ArrayBuffer)r=new Uint8Array(e.data);else{if(!ArrayBuffer.isView(e.data))throw new TypeError("Invalid AudioDataInit: data is not a BufferSource.");r=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength)}const i=this.numberOfFrames*this.numberOfChannels*Ct(this.format);if(r.byteLength=this.numberOfFrames)throw new RangeError("frameOffset out of range");const s=void 0!==e.frameCount?e.frameCount:this.numberOfFrames-n;if(s>this.numberOfFrames-n)throw new RangeError("frameCount out of range");const a=Ct(i),o=_t(i);if(o&&e.planeIndex>=this.numberOfChannels)throw new RangeError("planeIndex out of range");if(!o&&0!==e.planeIndex)throw new RangeError("planeIndex out of range");return(o?s:s*this.numberOfChannels)*a}copyTo(e,t){if(!F(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!Number.isInteger(t.planeIndex)||t.planeIndex<0)throw new TypeError("planeIndex must be a non-negative integer.");if(void 0!==t.format&&!Pt.has(t.format))throw new TypeError("Invalid format.");if(void 0!==t.frameOffset&&(!Number.isInteger(t.frameOffset)||t.frameOffset<0))throw new TypeError("frameOffset must be a non-negative integer.");if(void 0!==t.frameCount&&(!Number.isInteger(t.frameCount)||t.frameCount<0))throw new TypeError("frameCount must be a non-negative integer.");if(this._closed)throw new Error("AudioSample is closed.");const{planeIndex:r,format:i,frameCount:n,frameOffset:s}=t,a=this.format,o=null!=i?i:this.format;if(!o)throw new Error("Destination format not determined");const l=this.numberOfFrames,c=this.numberOfChannels,u=null!=s?s:0;if(u>=l)throw new RangeError("frameOffset out of range");const d=void 0!==n?n:l-u;if(d>l-u)throw new RangeError("frameCount out of range");const h=Ct(o),m=_t(o);if(m&&r>=c)throw new RangeError("planeIndex out of range");if(!m&&0!==r)throw new RangeError("planeIndex out of range");const f=(m?d:d*c)*h;if(e.byteLength2&&o!==a?Dt(this._data,p,a,o,c,r,u,d):this._data.copyTo(e,{planeIndex:r,frameOffset:u,frameCount:d,format:o});else{const e=this._data,t=v(e),i=Bt(a),n=Ct(a),s=_t(a);for(let a=0;a0;){const n=Math.min(s,o),l=new Float32Array(r*n);for(let t=0;t0;){const n=Math.min(s,o),c=new Float32Array(r*n);for(let t=0;t{switch(e){case"u8":case"u8-planar":return 1;case"s16":case"s16-planar":return 2;case"s32":case"s32-planar":case"f32":case"f32-planar":return 4;default:throw new Error("Unknown AudioSampleFormat")}},_t=e=>{switch(e){case"u8-planar":case"s16-planar":case"s32-planar":case"f32-planar":return!0;default:return!1}},Bt=e=>{switch(e){case"u8":case"u8-planar":return(e,t)=>(e.getUint8(t)-128)/128;case"s16":case"s16-planar":return(e,t)=>e.getInt16(t,!0)/32768;case"s32":case"s32-planar":return(e,t)=>e.getInt32(t,!0)/2147483648;case"f32":case"f32-planar":return(e,t)=>e.getFloat32(t,!0)}},Et=e=>{switch(e){case"u8":case"u8-planar":return(e,t,r)=>e.setUint8(t,K(127.5*(r+1),0,255));case"s16":case"s16-planar":return(e,t,r)=>e.setInt16(t,K(Math.round(32767*r),-32768,32767),!0);case"s32":case"s32-planar":return(e,t,r)=>e.setInt32(t,K(Math.round(2147483647*r),-2147483648,2147483647),!0);case"f32":case"f32-planar":return(e,t,r)=>e.setFloat32(t,r,!0)}},Ft=e=>"undefined"!==typeof AudioData&&e instanceof AudioData,Dt=(e,t,r,i,n,s,a,o)=>{const l=Bt(r),c=Et(i),u=Ct(r),d=Ct(i),h=_t(r);if(_t(i))if(h){const i=new ArrayBuffer(o*u),n=v(i);e.copyTo(i,{planeIndex:s,frameOffset:a,frameCount:o,format:r});for(let e=0;e{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.metadataOnly&&"boolean"!==typeof e.metadataOnly)throw new TypeError("options.metadataOnly, when defined, must be a boolean.");if(void 0!==e.verifyKeyPackets&&"boolean"!==typeof e.verifyKeyPackets)throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");if(e.verifyKeyPackets&&e.metadataOnly)throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.")},Rt=e=>{if(!me(e))throw new TypeError("timestamp must be a number.")},Mt=(e,t,r)=>r.verifyKeyPackets?t.then(t=>u(null,null,function*(){if(!t||"delta"===t.type)return t;const r=yield e.determinePacketType(t);return r&&(t.type=r),t})):t;class Nt{constructor(e){if(!(e instanceof Qt))throw new TypeError("track must be an InputTrack.");this._track=e}getFirstPacket(e={}){if(At(e),this._track.input._disposed)throw new gn;return Mt(this._track,this._track._backing.getFirstPacket(e),e)}getPacket(e,t={}){if(Rt(e),At(t),this._track.input._disposed)throw new gn;return Mt(this._track,this._track._backing.getPacket(e,t),t)}getNextPacket(e,t={}){if(!(e instanceof dt))throw new TypeError("packet must be an EncodedPacket.");if(At(t),this._track.input._disposed)throw new gn;return Mt(this._track,this._track._backing.getNextPacket(e,t),t)}getKeyPacket(e){return u(this,arguments,function*(e,t={}){if(Rt(e),At(t),this._track.input._disposed)throw new gn;if(!t.verifyKeyPackets)return this._track._backing.getKeyPacket(e,t);const r=yield this._track._backing.getKeyPacket(e,t);if(!r)return r;p("key"===r.type);return"delta"===(yield this._track.determinePacketType(r))?this.getKeyPacket(r.timestamp-1/this._track.timeResolution,t):r})}getNextKeyPacket(e){return u(this,arguments,function*(e,t={}){if(!(e instanceof dt))throw new TypeError("packet must be an EncodedPacket.");if(At(t),this._track.input._disposed)throw new gn;if(!t.verifyKeyPackets)return this._track._backing.getNextKeyPacket(e,t);const r=yield this._track._backing.getNextKeyPacket(e,t);if(!r)return r;p("key"===r.type);return"delta"===(yield this._track.determinePacketType(r))?this.getNextKeyPacket(r,t):r})}packets(e,t,r={}){if(void 0!==e&&!(e instanceof dt))throw new TypeError("startPacket must be an EncodedPacket.");if(void 0!==e&&e.isMetadataOnly&&!(null==r?void 0:r.metadataOnly))throw new TypeError("startPacket can only be metadata-only if options.metadataOnly is enabled.");if(void 0!==t&&!(t instanceof dt))throw new TypeError("endPacket must be an EncodedPacket.");if(At(r),this._track.input._disposed)throw new gn;const i=[];let{promise:n,resolve:s}=O(),{promise:a,resolve:o}=O(),l=!1,c=!1,d=null;const h=[],m=()=>Math.max(2,h.length);(()=>u(this,null,function*(){let u=null!=e?e:yield this.getFirstPacket(r);for(;u&&!c&&!this._track.input._disposed&&!(t&&u.sequenceNumber>=(null==t?void 0:t.sequenceNumber));)i.length>m()?(({promise:a,resolve:o}=O()),yield a):(i.push(u),s(),({promise:n,resolve:s}=O()),u=yield this.getNextPacket(u,r));l=!0,s()}))().catch(e=>{d||(d=e,s())});const f=this._track;return{next(){return u(this,null,function*(){for(;;){if(f.input._disposed)throw new gn;if(c)return{value:void 0,done:!0};if(d)throw d;if(i.length>0){const e=i.shift(),t=performance.now();for(h.push(t);h.length>0&&t-h[0]>=1e3;)h.shift();return o(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};yield n}})},return(){return u(this,null,function*(){return c=!0,o(),s(),{value:void 0,done:!0}})},throw(e){return u(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}}class zt{constructor(e,t){this.onSample=e,this.onError=t}}class Ot{mediaSamplesInRange(e=0,t=1/0){Rt(e),Rt(t);const r=[];let i=!1,n=null,{promise:s,resolve:a}=O(),{promise:o,resolve:l}=O(),c=!1,d=!1,h=!1,m=null;(()=>u(this,null,function*(){var u;const f=yield this._createDecoder(o=>{l(),o.timestamp>=t&&(d=!0),d?o.close():(n&&(o.timestamp>e?(r.push(n),i=!0):n.close()),o.timestamp>=e&&(r.push(o),i=!0),n=i?null:o,r.length>0&&(a(),({promise:s,resolve:a}=O())))},e=>{m||(m=e,a())}),p=this._createPacketSink(),g=null!=(u=yield p.getKeyPacket(e,{verifyKeyPackets:!0}))?u:yield p.getFirstPacket();let k=g;const b=p.packets(null!=g?g:void 0,void 0);for(yield b.next();k&&!d&&!this._track.input._disposed;){const e=Lt(r.length);if(r.length+f.getDecodeQueueSize()>e){({promise:o,resolve:l}=O()),yield o;continue}f.decode(k);const t=yield b.next();if(t.done)break;k=t.value}yield b.return(),h||this._track.input._disposed||(yield f.flush()),f.close(),!i&&n&&r.push(n),c=!0,a()}))().catch(e=>{m||(m=e,a())});const f=this._track,p=()=>{null==n||n.close();for(const e of r)e.close()};return{next(){return u(this,null,function*(){for(;;){if(f.input._disposed)throw p(),new gn;if(h)return{value:void 0,done:!0};if(m)throw p(),m;if(r.length>0){const e=r.shift();return l(),{value:e,done:!1}}if(c)return{value:void 0,done:!0};yield s}})},return(){return u(this,null,function*(){return h=!0,d=!0,l(),a(),p(),{value:void 0,done:!0}})},throw(e){return u(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}mediaSamplesAtTimestamps(e){(e=>{if(!(Symbol.iterator in e)&&!(Symbol.asyncIterator in e))throw new TypeError("Argument must be an iterable or async iterable.")})(e);const t=V(e),r=[],i=[];let{promise:n,resolve:s}=O(),{promise:a,resolve:o}=O(),l=!1,c=!1,d=null;const h=e=>{i.push(e),s(),({promise:n,resolve:s}=O())};(()=>u(this,null,function*(){const e=yield this._createDecoder(e=>{if(o(),c)return void e.close();let t=0;for(;r.length>0&&e.timestamp-r[0]>-1e-10;)t++,r.shift();if(t>0)for(let r=0;r{d||(d=e,s())}),n=this._createPacketSink();let f=null,g=null,k=-1;const b=()=>u(this,null,function*(){p(g);let t=g;for(e.decode(t);t.sequenceNumberr&&!c;)({promise:a,resolve:o}=O()),yield a;if(c)break;const s=yield n.getNextPacket(t);p(s),e.decode(s),t=s}k=-1}),y=()=>u(this,null,function*(){yield e.flush();for(let e=0;e{d||(d=e,s())});const f=this._track,g=()=>{for(const e of i)null==e||e.close()};return{next(){return u(this,null,function*(){for(;;){if(f.input._disposed)throw g(),new gn;if(c)return{value:void 0,done:!0};if(d)throw g(),d;if(i.length>0){const e=i.shift();return p(void 0!==e),o(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};yield n}})},return(){return u(this,null,function*(){return c=!0,o(),s(),g(),{value:void 0,done:!0}})},throw(e){return u(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}}const Lt=e=>0===e?40:8;class Ut extends zt{constructor(e,i,n,s,a,o){super(e,i),this.codec=n,this.decoderConfig=s,this.rotation=a,this.timeResolution=o,this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new te,this.customDecoderQueueSize=0,this.inputTimestamps=[],this.sampleQueue=[],this.currentPacketIndex=0,this.raslSkipped=!1,this.alphaDecoder=null,this.alphaHadKeyframe=!1,this.colorQueue=[],this.alphaQueue=[],this.merger=null,this.mergerCreationFailed=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue=[],this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1;const l=lt.find(e=>e.supports(n,s));if(l)this.customDecoder=new l,this.customDecoder.codec=n,this.customDecoder.config=s,this.customDecoder.onSample=e=>{if(!(e instanceof kt))throw new TypeError("The argument passed to onSample must be a VideoSample.");this.finalizeAndEmitSample(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=e=>{if(this.alphaQueue.length>0){const t=this.alphaQueue.shift();p(void 0!==t),this.mergeAlpha(e,t)}else this.colorQueue.push(e)};if("avc"===n&&this.decoderConfig.description&&oe()){const e=(e=>{try{const t=v(e);let r=0;const i=t.getUint8(r++),n=t.getUint8(r++),s=t.getUint8(r++),a=t.getUint8(r++),o=3&t.getUint8(r++),l=31&t.getUint8(r++),c=[];for(let m=0;m0){const i=Ve(e.sequenceParameterSets[0]);i&&0===i.frameMbsOnlyFlag&&(this.decoderConfig=(u=c({},this.decoderConfig),t(u,r({hardwareAcceleration:"prefer-software"}))))}}const i=new Error("Decoding error").stack;this.decoder=new VideoDecoder({output:t=>{try{e(t)}catch(r){this.onError(r)}},error:e=>{e.stack=i,this.onError(e)}}),this.decoder.configure(this.decoderConfig)}var u}getDecodeQueueSize(){var e,t;return this.customDecoder?this.customDecoderQueueSize:(p(this.decoder),Math.max(this.decoder.decodeQueueSize,null!=(t=null==(e=this.alphaDecoder)?void 0:e.decodeQueueSize)?t:0))}decode(e){if("hevc"===this.codec&&this.currentPacketIndex>0&&!this.raslSkipped){if(this.hasHevcRaslPicture(e.data))return;this.raslSkipped=!0}if(this.customDecoder)this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--);else{if(p(this.decoder),ie()||z(this.inputTimestamps,e.timestamp,e=>e),oe()&&0===this.currentPacketIndex&&"avc"===this.codec){const t=ze(e.data,this.decoderConfig).filter(e=>{const t=Le(e);return!(t>=20&&t<=31)}),r=Oe(t,this.decoderConfig);e=new dt(r,e.type,e.timestamp,e.duration)}this.decoder.decode(e.toEncodedVideoChunk()),this.decodeAlphaData(e)}this.currentPacketIndex++}decodeAlphaData(e){if(!e.sideData.alpha||this.mergerCreationFailed)return void this.pushNullAlphaFrame();if(!this.merger)try{this.merger=new Vt}catch(r){return console.error("Due to an error, only color data will be decoded.",r),this.mergerCreationFailed=!0,void this.decodeAlphaData(e)}if(!this.alphaDecoder){const e=e=>{if(this.alphaDecoderQueueSize--,this.colorQueue.length>0){const t=this.colorQueue.shift();p(void 0!==t),this.mergeAlpha(t,e)}else this.alphaQueue.push(e);for(this.decodedAlphaChunkCount++;this.nullAlphaFrameQueue.length>0&&this.nullAlphaFrameQueue[0]===this.decodedAlphaChunkCount;)if(this.nullAlphaFrameQueue.shift(),this.colorQueue.length>0){const e=this.colorQueue.shift();p(void 0!==e),this.mergeAlpha(e,null)}else this.alphaQueue.push(null)},t=new Error("Decoding error").stack;this.alphaDecoder=new VideoDecoder({output:t=>{try{e(t)}catch(r){this.onError(r)}},error:e=>{e.stack=t,this.onError(e)}}),this.alphaDecoder.configure(this.decoderConfig)}const t=it(this.codec,this.decoderConfig,e.sideData.alpha);if(this.alphaHadKeyframe||(this.alphaHadKeyframe="key"===t),this.alphaHadKeyframe){if("hevc"===this.codec&&this.currentAlphaPacketIndex>0&&!this.alphaRaslSkipped){if(this.hasHevcRaslPicture(e.sideData.alpha))return void this.pushNullAlphaFrame();this.alphaRaslSkipped=!0}this.currentAlphaPacketIndex++,this.alphaDecoder.decode(e.alphaToEncodedVideoChunk(null!=t?t:e.type)),this.alphaDecoderQueueSize++}else this.pushNullAlphaFrame()}pushNullAlphaFrame(){0===this.alphaDecoderQueueSize?this.alphaQueue.push(null):this.nullAlphaFrameQueue.push(this.decodedAlphaChunkCount+this.alphaDecoderQueueSize)}hasHevcRaslPicture(e){return qe(e,this.decoderConfig).some(e=>{const t=He(e);return t===Fe.RASL_N||t===Fe.RASL_R})}sampleHandler(e){if(ie()){if(this.sampleQueue.length>0&&e.timestamp>=k(this.sampleQueue).timestamp){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}z(this.sampleQueue,e,e=>e.timestamp)}else{const t=this.inputTimestamps.shift();p(void 0!==t),e.setTimestamp(t),this.finalizeAndEmitSample(e)}}finalizeAndEmitSample(e){e.setTimestamp(Math.round(e.timestamp*this.timeResolution)/this.timeResolution),e.setDuration(Math.round(e.duration*this.timeResolution)/this.timeResolution),e.setRotation(this.rotation),this.onSample(e)}mergeAlpha(e,t){var r;if(!t){const t=new kt(e);return void this.sampleHandler(t)}p(this.merger),this.merger.update(e,t),e.close(),t.close();const i=new VideoFrame(this.merger.canvas,{timestamp:e.timestamp,duration:null!=(r=e.duration)?r:void 0}),n=new kt(i);this.sampleHandler(n)}flush(){return u(this,null,function*(){var e;if(this.customDecoder?yield this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(p(this.decoder),yield Promise.all([this.decoder.flush(),null==(e=this.alphaDecoder)?void 0:e.flush()]),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>null==e?void 0:e.close()),this.alphaQueue.length=0,this.alphaHadKeyframe=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue.length=0,this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1),ie()){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}this.currentPacketIndex=0,this.raslSkipped=!1})}close(){var e,t;this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(p(this.decoder),this.decoder.close(),null==(e=this.alphaDecoder)||e.close(),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>null==e?void 0:e.close()),this.alphaQueue.length=0,null==(t=this.merger)||t.close());for(const r of this.sampleQueue)r.close();this.sampleQueue.length=0}}class Vt{constructor(){"undefined"!==typeof OffscreenCanvas?this.canvas=new OffscreenCanvas(300,150):this.canvas=document.createElement("canvas");const e=this.canvas.getContext("webgl2",{premultipliedAlpha:!1});if(!e)throw new Error("Couldn't acquire WebGL 2 context.");this.gl=e,this.program=this.createProgram(),this.vao=this.createVAO(),this.colorTexture=this.createTexture(),this.alphaTexture=this.createTexture(),this.gl.useProgram(this.program),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_colorTexture"),0),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_alphaTexture"),1)}createProgram(){const e=this.createShader(this.gl.VERTEX_SHADER,"#version 300 es\n\t\t\tin vec2 a_position;\n\t\t\tin vec2 a_texCoord;\n\t\t\tout vec2 v_texCoord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = vec4(a_position, 0.0, 1.0);\n\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t}\n\t\t"),t=this.createShader(this.gl.FRAGMENT_SHADER,"#version 300 es\n\t\t\tprecision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_colorTexture;\n\t\t\tuniform sampler2D u_alphaTexture;\n\t\t\tin vec2 v_texCoord;\n\t\t\tout vec4 fragColor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture(u_colorTexture, v_texCoord).rgb;\n\t\t\t\tfloat alpha = texture(u_alphaTexture, v_texCoord).r;\n\t\t\t\tfragColor = vec4(color, alpha);\n\t\t\t}\n\t\t"),r=this.gl.createProgram();return this.gl.attachShader(r,e),this.gl.attachShader(r,t),this.gl.linkProgram(r),r}createShader(e,t){const r=this.gl.createShader(e);return this.gl.shaderSource(r,t),this.gl.compileShader(r),r}createVAO(){const e=this.gl.createVertexArray();this.gl.bindVertexArray(e);const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),r=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,r),this.gl.bufferData(this.gl.ARRAY_BUFFER,t,this.gl.STATIC_DRAW);const i=this.gl.getAttribLocation(this.program,"a_position"),n=this.gl.getAttribLocation(this.program,"a_texCoord");return this.gl.enableVertexAttribArray(i),this.gl.vertexAttribPointer(i,2,this.gl.FLOAT,!1,16,0),this.gl.enableVertexAttribArray(n),this.gl.vertexAttribPointer(n,2,this.gl.FLOAT,!1,16,8),e}createTexture(){const e=this.gl.createTexture();return this.gl.bindTexture(this.gl.TEXTURE_2D,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),e}update(e,t){e.displayWidth===this.canvas.width&&e.displayHeight===this.canvas.height||(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colorTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),this.gl.activeTexture(this.gl.TEXTURE1),this.gl.bindTexture(this.gl.TEXTURE_2D,this.alphaTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.bindVertexArray(this.vao),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)}close(){var e;null==(e=this.gl.getExtension("WEBGL_lose_context"))||e.loseContext(),this.gl=null}}class qt extends Ot{constructor(e){if(!(e instanceof Gt))throw new TypeError("videoTrack must be an InputVideoTrack.");super(),this._track=e}_createDecoder(e,t){return u(this,null,function*(){if(!(yield this._track.canDecode()))throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track.");const r=this._track.codec,i=this._track.rotation,n=yield this._track.getDecoderConfig(),s=this._track.timeResolution;return p(r&&n),new Ut(e,t,r,n,i,s)})}_createPacketSink(){return new Nt(this._track)}getSample(e){return u(this,null,function*(){Rt(e);try{for(var t,r,i,n=m(this.mediaSamplesAtTimestamps([e]));t=!(r=yield n.next()).done;t=!1){return r.value}}catch(r){i=[r]}finally{try{t&&(r=n.return)&&(yield r.call(n))}finally{if(i)throw i[0]}}throw new Error("Internal error: Iterator returned nothing.")})}samples(e=0,t=1/0){return this.mediaSamplesInRange(e,t)}samplesAtTimestamps(e){return this.mediaSamplesAtTimestamps(e)}}class Ht{constructor(e,t={}){var r,i,n,s;if(this._nextCanvasIndex=0,!(e instanceof Gt))throw new TypeError("videoTrack must be an InputVideoTrack.");if(t&&"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.alpha&&"boolean"!==typeof t.alpha)throw new TypeError("options.alpha, when provided, must be a boolean.");if(void 0!==t.width&&(!Number.isInteger(t.width)||t.width<=0))throw new TypeError("options.width, when defined, must be a positive integer.");if(void 0!==t.height&&(!Number.isInteger(t.height)||t.height<=0))throw new TypeError("options.height, when defined, must be a positive integer.");if(void 0!==t.fit&&!["fill","contain","cover"].includes(t.fit))throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".');if(void 0!==t.width&&void 0!==t.height&&void 0===t.fit)throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180 or 270.");if(void 0!==t.crop&&St(t.crop,"options."),void 0!==t.poolSize&&("number"!==typeof t.poolSize||!Number.isInteger(t.poolSize)||t.poolSize<0))throw new TypeError("poolSize must be a non-negative integer.");const a=null!=(r=t.rotation)?r:e.rotation,[o,l]=a%180===0?[e.codedWidth,e.codedHeight]:[e.codedHeight,e.codedWidth],c=t.crop;c&&Tt(c,o,l);let[u,d]=c?[c.width,c.height]:[o,l];const h=u/d;void 0!==t.width&&void 0===t.height?(u=t.width,d=Math.round(u/h)):void 0===t.width&&void 0!==t.height?(d=t.height,u=Math.round(d*h)):void 0!==t.width&&void 0!==t.height&&(u=t.width,d=t.height),this._videoTrack=e,this._alpha=null!=(i=t.alpha)&&i,this._width=u,this._height=d,this._rotation=a,this._crop=c,this._fit=null!=(n=t.fit)?n:"fill",this._videoSampleSink=new qt(e),this._canvasPool=Array.from({length:null!=(s=t.poolSize)?s:0},()=>null)}_videoSampleToWrappedCanvas(e){let t=this._canvasPool[this._nextCanvasIndex],r=!1;t||("undefined"!==typeof document?(t=document.createElement("canvas"),t.width=this._width,t.height=this._height):t=new OffscreenCanvas(this._width,this._height),this._canvasPool.length>0&&(this._canvasPool[this._nextCanvasIndex]=t),r=!0),this._canvasPool.length>0&&(this._nextCanvasIndex=(this._nextCanvasIndex+1)%this._canvasPool.length);const i=t.getContext("2d",{alpha:this._alpha||se()});p(i),i.resetTransform(),r||(!this._alpha&&se()?(i.fillStyle="black",i.fillRect(0,0,this._width,this._height)):i.clearRect(0,0,this._width,this._height)),e.drawWithFit(i,{fit:this._fit,rotation:this._rotation,crop:this._crop});const n={canvas:t,timestamp:e.timestamp,duration:e.duration};return e.close(),n}getCanvas(e){return u(this,null,function*(){Rt(e);const t=yield this._videoSampleSink.getSample(e);return t&&this._videoSampleToWrappedCanvas(t)})}canvases(e=0,t=1/0){return j(this._videoSampleSink.samples(e,t),e=>this._videoSampleToWrappedCanvas(e))}canvasesAtTimestamps(e){return j(this._videoSampleSink.samplesAtTimestamps(e),e=>e&&this._videoSampleToWrappedCanvas(e))}}class Wt extends zt{constructor(e,t,r,i){super(e,t),this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new te,this.customDecoderQueueSize=0,this.currentTimestamp=null;const n=t=>{(null===this.currentTimestamp||Math.abs(t.timestamp-this.currentTimestamp)>=t.duration)&&(this.currentTimestamp=t.timestamp);const r=this.currentTimestamp;if(this.currentTimestamp+=t.duration,0===t.numberOfFrames)return void t.close();const n=i.sampleRate;t.setTimestamp(Math.round(r*n)/n),e(t)},s=ct.find(e=>e.supports(r,i));if(s)this.customDecoder=new s,this.customDecoder.codec=r,this.customDecoder.config=i,this.customDecoder.onSample=e=>{if(!(e instanceof xt))throw new TypeError("The argument passed to onSample must be an AudioSample.");n(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=new Error("Decoding error").stack;this.decoder=new AudioDecoder({output:e=>{try{n(new xt(e))}catch(t){this.onError(t)}},error:t=>{t.stack=e,this.onError(t)}}),this.decoder.configure(i)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(p(this.decoder),this.decoder.decodeQueueSize)}decode(e){this.customDecoder?(this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--)):(p(this.decoder),this.decoder.decode(e.toEncodedAudioChunk()))}flush(){return this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(p(this.decoder),this.decoder.flush())}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(p(this.decoder),this.decoder.close())}}class jt extends zt{constructor(e,t,r){super(e,t),this.decoderConfig=r,this.currentTimestamp=null,p(ke.includes(r.codec)),this.codec=r.codec;const{dataType:i,sampleSize:n,littleEndian:s}=_e(this.codec);switch(this.inputSampleSize=n,n){case 1:"unsigned"===i?this.readInputValue=(e,t)=>e.getUint8(t)-o(2,7):"signed"===i?this.readInputValue=(e,t)=>e.getInt8(t):"ulaw"===i?this.readInputValue=(e,t)=>(e=>{let t=0,r=0,i=~e;128&i&&(i&=-129,t=-1),r=5+((240&i)>>4);const n=(1<(e=>{let t=0,r=0,i=85^e;128&i&&(i&=-129,t=-1),r=4+((240&i)>>4);let n=0;return n=4!==r?1<e.getUint16(t,s)-o(2,15):"signed"===i?this.readInputValue=(e,t)=>e.getInt16(t,s):p(!1);break;case 3:"unsigned"===i?this.readInputValue=(e,t)=>H(e,t,s)-o(2,23):"signed"===i?this.readInputValue=(e,t)=>((e,t,r)=>H(e,t,r)<<8>>8)(e,t,s):p(!1);break;case 4:"unsigned"===i?this.readInputValue=(e,t)=>e.getUint32(t,s)-o(2,31):"signed"===i?this.readInputValue=(e,t)=>e.getInt32(t,s):"float"===i?this.readInputValue=(e,t)=>e.getFloat32(t,s):p(!1);break;case 8:"float"===i?this.readInputValue=(e,t)=>e.getFloat64(t,s):p(!1);break;default:q(n),p(!1)}switch(n){case 1:"ulaw"===i||"alaw"===i?(this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,r)=>e.setInt16(t,r,!0)):(this.outputSampleSize=1,this.outputFormat="u8",this.writeOutputValue=(e,t,r)=>e.setUint8(t,r+o(2,7)));break;case 2:this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,r)=>e.setInt16(t,r,!0);break;case 3:this.outputSampleSize=4,this.outputFormat="s32",this.writeOutputValue=(e,t,r)=>e.setInt32(t,r<<8,!0);break;case 4:this.outputSampleSize=4,"float"===i?(this.outputFormat="f32",this.writeOutputValue=(e,t,r)=>e.setFloat32(t,r,!0)):(this.outputFormat="s32",this.writeOutputValue=(e,t,r)=>e.setInt32(t,r,!0));break;case 8:this.outputSampleSize=4,this.outputFormat="f32",this.writeOutputValue=(e,t,r)=>e.setFloat32(t,r,!0);break;default:q(n),p(!1)}}getDecodeQueueSize(){return 0}decode(e){const t=v(e.data),r=e.byteLength/this.decoderConfig.numberOfChannels/this.inputSampleSize,i=r*this.decoderConfig.numberOfChannels*this.outputSampleSize,n=new ArrayBuffer(i),s=new DataView(n);for(let c=0;c=a)&&(this.currentTimestamp=e.timestamp);const o=this.currentTimestamp;this.currentTimestamp+=a;const l=new xt({format:this.outputFormat,data:n,numberOfChannels:this.decoderConfig.numberOfChannels,sampleRate:this.decoderConfig.sampleRate,numberOfFrames:r,timestamp:o});this.onSample(l)}flush(){return u(this,null,function*(){})}close(){}}class Kt extends Ot{constructor(e){if(!(e instanceof Xt))throw new TypeError("audioTrack must be an InputAudioTrack.");super(),this._track=e}_createDecoder(e,t){return u(this,null,function*(){if(!(yield this._track.canDecode()))throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track.");const r=this._track.codec,i=yield this._track.getDecoderConfig();return p(r&&i),ke.includes(i.codec)?new jt(e,t,i):new Wt(e,t,r,i)})}_createPacketSink(){return new Nt(this._track)}getSample(e){return u(this,null,function*(){Rt(e);try{for(var t,r,i,n=m(this.mediaSamplesAtTimestamps([e]));t=!(r=yield n.next()).done;t=!1){return r.value}}catch(r){i=[r]}finally{try{t&&(r=n.return)&&(yield r.call(n))}finally{if(i)throw i[0]}}throw new Error("Internal error: Iterator returned nothing.")})}samples(e=0,t=1/0){return this.mediaSamplesInRange(e,t)}samplesAtTimestamps(e){return this.mediaSamplesAtTimestamps(e)}}class $t{constructor(e){if(!(e instanceof Xt))throw new TypeError("audioTrack must be an InputAudioTrack.");this._audioSampleSink=new Kt(e)}_audioSampleToWrappedArrayBuffer(e){const t={buffer:e.toAudioBuffer(),timestamp:e.timestamp,duration:e.duration};return e.close(),t}getBuffer(e){return u(this,null,function*(){Rt(e);const t=yield this._audioSampleSink.getSample(e);return t&&this._audioSampleToWrappedArrayBuffer(t)})}buffers(e=0,t=1/0){return j(this._audioSampleSink.samples(e,t),e=>this._audioSampleToWrappedArrayBuffer(e))}buffersAtTimestamps(e){return j(this._audioSampleSink.samplesAtTimestamps(e),e=>e&&this._audioSampleToWrappedArrayBuffer(e))}}class Qt{constructor(e,t){this.input=e,this._backing=t}isVideoTrack(){return this instanceof Gt}isAudioTrack(){return this instanceof Xt}get id(){return this._backing.getId()}get internalCodecId(){return this._backing.getInternalCodecId()}get languageCode(){return this._backing.getLanguageCode()}get name(){return this._backing.getName()}get timeResolution(){return this._backing.getTimeResolution()}get disposition(){return this._backing.getDisposition()}getFirstTimestamp(){return this._backing.getFirstTimestamp()}computeDuration(){return this._backing.computeDuration()}computePacketStats(e=1/0){return u(this,null,function*(){const t=new Nt(this);let r=1/0,i=-1/0,n=0,s=0;try{for(var a,o,l,c=m(t.packets(void 0,void 0,{metadataOnly:!0}));a=!(o=yield c.next()).done;a=!1){const t=o.value;if(n>=e&&t.timestamp>=i)break;r=Math.min(r,t.timestamp),i=Math.max(i,t.timestamp+t.duration),n++,s+=t.byteLength}}catch(o){l=[o]}finally{try{a&&(o=c.return)&&(yield o.call(c))}finally{if(l)throw l[0]}}return{packetCount:n,averagePacketRate:n?Number((n/(i-r)).toPrecision(16)):0,averageBitrate:n?Number((8*s/(i-r)).toPrecision(16)):0}})}}class Gt extends Qt{constructor(e,t){super(e,t),this._backing=t}get type(){return"video"}get codec(){return this._backing.getCodec()}get codedWidth(){return this._backing.getCodedWidth()}get codedHeight(){return this._backing.getCodedHeight()}get rotation(){return this._backing.getRotation()}get displayWidth(){return this._backing.getRotation()%180===0?this._backing.getCodedWidth():this._backing.getCodedHeight()}get displayHeight(){return this._backing.getRotation()%180===0?this._backing.getCodedHeight():this._backing.getCodedWidth()}getColorSpace(){return this._backing.getColorSpace()}hasHighDynamicRange(){return u(this,null,function*(){const e=yield this._backing.getColorSpace();return"bt2020"===e.primaries||"smpte432"===e.primaries||"pg"===e.transfer||"hlg"===e.transfer||"bt2020-ncl"===e.matrix})}canBeTransparent(){return this._backing.canBeTransparent()}getDecoderConfig(){return this._backing.getDecoderConfig()}getCodecParameterString(){return u(this,null,function*(){var e;const t=yield this._backing.getDecoderConfig();return null!=(e=null==t?void 0:t.codec)?e:null})}canDecode(){return u(this,null,function*(){try{const e=yield this._backing.getDecoderConfig();if(!e)return!1;const t=this._backing.getCodec();if(p(null!==t),lt.some(r=>r.supports(t,e)))return!0;if("undefined"===typeof VideoDecoder)return!1;return!0===(yield VideoDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}})}determinePacketType(e){return u(this,null,function*(){if(!(e instanceof dt))throw new TypeError("packet must be an EncodedPacket.");if(e.isMetadataOnly)throw new TypeError("packet must not be metadata-only to determine its type.");if(null===this.codec)return null;const t=yield this.getDecoderConfig();return p(t),it(this.codec,t,e.data)})}}class Xt extends Qt{constructor(e,t){super(e,t),this._backing=t}get type(){return"audio"}get codec(){return this._backing.getCodec()}get numberOfChannels(){return this._backing.getNumberOfChannels()}get sampleRate(){return this._backing.getSampleRate()}getDecoderConfig(){return this._backing.getDecoderConfig()}getCodecParameterString(){return u(this,null,function*(){var e;const t=yield this._backing.getDecoderConfig();return null!=(e=null==t?void 0:t.codec)?e:null})}canDecode(){return u(this,null,function*(){try{const e=yield this._backing.getDecoderConfig();if(!e)return!1;const t=this._backing.getCodec();if(p(null!==t),ct.some(r=>r.supports(t,e)))return!0;if(e.codec.startsWith("pcm-"))return!0;if("undefined"===typeof AudioDecoder)return!1;return!0===(yield AudioDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}})}determinePacketType(e){return u(this,null,function*(){if(!(e instanceof dt))throw new TypeError("packet must be an EncodedPacket.");return null===this.codec?null:"key"})}}const Yt=e=>{let t=Cn(e);const r=Nn(e,4);let i=8;1===t&&(t=Fn(e),i=16);const n=t-i;return n<0?null:{name:r,totalSize:t,headerSize:i,contentSize:n}},Jt=e=>Bn(e)/65536,Zt=e=>Bn(e)/1073741824,er=e=>{let t=0;for(let r=0;r<4;r++){t<<=7;const r=Sn(e);if(t|=127&r,0===(128&r))break}return t},tr=e=>{let t=wn(e);return e.skip(2),t=Math.min(t,e.remainingLength),w.decode(Tn(e,t))},rr=e=>{const t=Yt(e);if(!t||"data"!==t.name)return null;if(e.remainingLength<8)return null;const r=Cn(e);e.skip(4);const i=Tn(e,t.contentSize-8);switch(r){case 1:return w.decode(i);case 2:return new TextDecoder("utf-16be").decode(i);case 13:return new fe(i,"image/jpeg");case 14:return new fe(i,"image/png");case 27:return new fe(i,"image/bmp");default:return i}};class ir extends ot{constructor(e){super(e),this.moovSlice=null,this.currentTrack=null,this.tracks=[],this.metadataPromise=null,this.movieTimescale=-1,this.movieDurationInTimescale=-1,this.isQuickTime=!1,this.metadataTags={},this.currentMetadataKeys=null,this.isFragmented=!1,this.fragmentTrackDefaults=[],this.currentFragment=null,this.lastReadFragment=null,this.reader=e._reader}computeDuration(){return u(this,null,function*(){const e=yield this.getTracks(),t=yield Promise.all(e.map(e=>e.computeDuration()));return Math.max(0,...t)})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks.map(e=>e.inputTrack)})}getMimeType(){return u(this,null,function*(){yield this.readMetadata();const e=yield Promise.all(this.tracks.map(e=>e.inputTrack.getCodecParameterString()));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isQuickTime?"quicktime":"mp4");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({isQuickTime:this.isQuickTime,hasVideo:this.tracks.some(e=>{var t;return"video"===(null==(t=e.info)?void 0:t.type)}),hasAudio:this.tracks.some(e=>{var t;return"audio"===(null==(t=e.info)?void 0:t.type)}),codecStrings:e.filter(Boolean)})})}getMetadataTags(){return u(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}readMetadata(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>u(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,8,16);if(t instanceof Promise&&(t=yield t),!t)break;const r=e,i=Yt(t);if(!i)break;if("ftyp"===i.name){const e=Nn(t,4);this.isQuickTime="qt "===e}else if("moov"===i.name){let e=this.reader.requestSlice(t.filePos,i.contentSize);if(e instanceof Promise&&(e=yield e),!e)break;this.moovSlice=e,this.readContiguousBoxes(this.moovSlice),this.tracks.sort((e,t)=>Number(t.disposition.default)-Number(e.disposition.default));for(const t of this.tracks){const e=t.editListPreviousSegmentDurations/this.movieTimescale;t.editListOffset-=Math.round(e*t.timescale)}break}e=r+i.totalSize}if(this.isFragmented&&null!==this.reader.fileSize){let e=this.reader.requestSlice(this.reader.fileSize-4,4);e instanceof Promise&&(e=yield e),p(e);const t=Cn(e),r=this.reader.fileSize-t;if(r>=0&&r<=this.reader.fileSize-16){let e=this.reader.requestSliceRange(r,8,16);if(e instanceof Promise&&(e=yield e),e){const t=Yt(e);if(t&&"mfra"===t.name){let r=this.reader.requestSlice(e.filePos,t.contentSize);r instanceof Promise&&(r=yield r),r&&this.readContiguousBoxes(r)}}}}}))()}getSampleTableForTrack(e){var t,r;if(e.sampleTable)return e.sampleTable;const i={sampleTimingEntries:[],sampleCompositionTimeOffsets:[],sampleSizes:[],keySampleIndices:null,chunkOffsets:[],sampleToChunk:[],presentationTimestamps:null,presentationTimestampIndexMap:null};e.sampleTable=i,p(this.moovSlice);const n=this.moovSlice.slice(e.sampleTableByteOffset);this.currentTrack=e,this.traverseBox(n),this.currentTrack=null;if("audio"===(null==(t=e.info)?void 0:t.type)&&e.info.codec&&ke.includes(e.info.codec)&&0===i.sampleCompositionTimeOffsets.length){p("audio"===(null==(r=e.info)?void 0:r.type));const t=_e(e.info.codec),n=[],s=[];for(let r=0;re.startIndex),u=i.sampleTimingEntries[c],d=N(i.sampleTimingEntries,l,e=>e.startIndex),h=i.sampleTimingEntries[d],m=u.startDecodeTimestamp+(o-u.startIndex)*u.delta,f=h.startDecodeTimestamp+(l-h.startIndex)*h.delta-m,p=k(n);p&&p.delta===f?p.count++:n.push({startIndex:a.startChunkIndex+r,startDecodeTimestamp:m,count:1,delta:f});const g=a.samplesPerChunk*t.sampleSize*e.info.numberOfChannels;s.push(g)}a.startSampleIndex=a.startChunkIndex,a.samplesPerChunk=1}i.sampleTimingEntries=n,i.sampleSizes=s}if(i.sampleCompositionTimeOffsets.length>0){i.presentationTimestamps=[];for(const e of i.sampleTimingEntries)for(let t=0;te.presentationTimestamp-t.presentationTimestamp),i.presentationTimestampIndexMap=Array(i.presentationTimestamps.length).fill(-1);for(let e=0;ee.moofOffset===s.moofOffset);if(i)dr(e,i.timestamp);else{const t=N(r,s.moofOffset-1,e=>e.moofOffset);if(-1!==t){const i=r[t];dr(e,i.endTimestamp)}}e.startTimestampIsFinal=!0}const i=N(r,e.startTimestamp,e=>e.startTimestamp);-1!==i&&r[i].moofOffset===s.moofOffset||r.splice(i+1,0,{moofOffset:s.moofOffset,startTimestamp:e.startTimestamp,endTimestamp:e.endTimestamp})}return s})}readContiguousBoxes(e){const t=e.filePos;for(;e.filePos-t<=e.length-8;){if(!this.traverseBox(e))break}}*iterateContiguousBoxes(e){const t=e.filePos;for(;e.filePos-t<=e.length-8;){const t=e.filePos,r=Yt(e);if(!r)break;yield{boxInfo:r,slice:e},e.filePos=t+r.totalSize}}traverseBox(e){var t,r,i,n,s,a,o,l,u,d,h,m,f,y,T,S,I,P,C,B,F,D,A,R,M,N,z,O,L,U,V,q,H,W,j,K,Q,G,Y,J,Z,ee,te,re,ie;const ne=e.filePos,se=Yt(e);if(!se)return!1;const ae=e.filePos,oe=ne+se.totalSize;switch(se.name){case"mdia":case"minf":case"dinf":case"mfra":case"edts":case"wave":this.readContiguousBoxes(e.slice(ae,se.contentSize));break;case"mvhd":{const t=Sn(e);e.skip(3),1===t?(e.skip(16),this.movieTimescale=Cn(e),this.movieDurationInTimescale=Fn(e)):(e.skip(8),this.movieTimescale=Cn(e),this.movieDurationInTimescale=Cn(e))}break;case"trak":{const t={id:-1,demuxer:this,inputTrack:null,disposition:c({},ge),info:null,timescale:-1,durationInMovieTimescale:-1,durationInMediaTimescale:-1,rotation:0,internalCodecId:null,name:null,languageCode:$,sampleTableByteOffset:-1,sampleTable:null,fragmentLookupTable:[],currentFragmentState:null,fragmentPositionCache:[],editListPreviousSegmentDurations:0,editListOffset:0};if(this.currentTrack=t,this.readContiguousBoxes(e.slice(ae,se.contentSize)),-1!==t.id&&-1!==t.timescale&&null!==t.info)if("video"===t.info.type&&-1!==t.info.width){const e=t;t.inputTrack=new Gt(this.input,new sr(e)),this.tracks.push(t)}else if("audio"===t.info.type&&-1!==t.info.numberOfChannels){const e=t;t.inputTrack=new Xt(this.input,new ar(e)),this.tracks.push(t)}this.currentTrack=null}break;case"tkhd":{const t=this.currentTrack;if(!t)break;const r=Sn(e),i=!!(1&In(e));if(t.disposition.default=i,0===r)e.skip(8),t.id=Cn(e),e.skip(4),t.durationInMovieTimescale=Cn(e);else{if(1!==r)throw new Error(`Incorrect track header version ${r}.`);e.skip(16),t.id=Cn(e),e.skip(4),t.durationInMovieTimescale=Fn(e)}e.skip(16);const n=[Jt(e),Jt(e),Zt(e),Jt(e),Jt(e),Zt(e),Jt(e),Jt(e),Zt(e)],s=g((le=hr(n),ce=90,Math.round(le/ce)*ce));p(0===s||90===s||180===s||270===s),t.rotation=s}break;case"elst":{const t=this.currentTrack;if(!t)break;const r=Sn(e);e.skip(3);let i=!1,n=0;const s=Cn(e);for(let a=0;a0){t.languageCode="";for(let e=0;e<3;e++)t.languageCode=String.fromCharCode(96+(31&i))+t.languageCode,i>>=5;X(t.languageCode)||(t.languageCode=$)}}break;case"hdlr":{const t=this.currentTrack;if(!t)break;e.skip(8);const r=Nn(e,4);"vide"===r?t.info={type:"video",width:-1,height:-1,codec:null,codecDescription:null,colorSpace:null,avcType:null,avcCodecInfo:null,hevcCodecInfo:null,vp9CodecInfo:null,av1CodecInfo:null}:"soun"===r&&(t.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case"stbl":{const t=this.currentTrack;if(!t)break;t.sampleTableByteOffset=ne,this.readContiguousBoxes(e.slice(ae,se.contentSize))}break;case"stsd":{const t=this.currentTrack;if(!t)break;if(null===t.info||t.sampleTable)break;const r=Sn(e);e.skip(3);const i=Cn(e);for(let n=0;n0)if(1===a)e.skip(4),l=8*Cn(e),e.skip(8);else if(2===a){e.skip(4),c=Mn(e),o=Cn(e),e.skip(4),l=Cn(e);const r=Cn(e);if(e.skip(8),"lpcm"===s){const e=l+7>>3,i=Boolean(1&r),n=Boolean(2&r),s=4&r?-1:0;l>0&&l<=64&&(i?32===l&&(t.info.codec=n?"pcm-f32be":"pcm-f32"):s&1<>4,o=s>>1&7,l=1&s,c=Sn(e),u=Sn(e),d=Sn(e);r.info.vp9CodecInfo={profile:i,level:n,bitDepth:a,chromaSubsampling:o,videoFullRangeFlag:l,colourPrimaries:c,transferCharacteristics:u,matrixCoefficients:d}}break;case"av1C":{const t=this.currentTrack;if(!t)break;p("video"===(null==(r=t.info)?void 0:r.type)),e.skip(1);const i=Sn(e),n=i>>5,s=31&i,a=Sn(e),o=a>>7,l=a>>6&1,c=a>>4&1,u=a>>3&1,d=a>>2&1,h=3&a,m=2===n&&l?a>>5&1?12:10:l?10:8;t.info.av1CodecInfo={profile:n,level:s,tier:o,bitDepth:m,monochrome:c,chromaSubsamplingX:u,chromaSubsamplingY:d,chromaSamplePosition:h}}break;case"colr":{const t=this.currentTrack;if(!t)break;p("video"===(null==(i=t.info)?void 0:i.type));if("nclx"!==Nn(e,4))break;const r=wn(e),n=wn(e),s=wn(e),a=Boolean(128&Sn(e));t.info.colorSpace={primaries:x[r],transfer:_[n],matrix:E[s],fullRange:a}}break;case"esds":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(n=t.info)?void 0:n.type)),e.skip(4);p(3===Sn(e)),er(e),e.skip(2);const r=Sn(e),i=0!==(64&r),s=0!==(32&r);if(0!==(128&r)&&e.skip(2),i){const t=Sn(e);e.skip(t)}s&&e.skip(2);p(4===Sn(e));const a=er(e),o=e.filePos,l=Sn(e);if(64===l||103===l?(t.info.codec="aac",t.info.aacCodecInfo={isMpeg2:103===l}):105===l||107===l?t.info.codec="mp3":221===l?t.info.codec="vorbis":console.warn(`Unsupported audio codec (objectTypeIndication ${l}) - discarding track.`),e.skip(12),a>e.filePos-o){p(5===Sn(e));const r=er(e);if(t.info.codecDescription=Tn(e,r),"aac"===t.info.codec){const e=Pe(t.info.codecDescription);null!==e.numberOfChannels&&(t.info.numberOfChannels=e.numberOfChannels),null!==e.sampleRate&&(t.info.sampleRate=e.sampleRate)}}}break;case"enda":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(s=t.info)?void 0:s.type));255&wn(e)&&("pcm-s16be"===t.info.codec?t.info.codec="pcm-s16":"pcm-s24be"===t.info.codec?t.info.codec="pcm-s24":"pcm-s32be"===t.info.codec?t.info.codec="pcm-s32":"pcm-f32be"===t.info.codec?t.info.codec="pcm-f32":"pcm-f64be"===t.info.codec&&(t.info.codec="pcm-f64"))}break;case"pcmC":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(a=t.info)?void 0:a.type)),e.skip(4);const r=Sn(e),i=Boolean(1&r),n=Sn(e);"pcm-s16be"===t.info.codec?i?16===n?t.info.codec="pcm-s16":24===n?t.info.codec="pcm-s24":32===n?t.info.codec="pcm-s32":(console.warn(`Invalid ipcm sample size ${n}.`),t.info.codec=null):16===n?t.info.codec="pcm-s16be":24===n?t.info.codec="pcm-s24be":32===n?t.info.codec="pcm-s32be":(console.warn(`Invalid ipcm sample size ${n}.`),t.info.codec=null):"pcm-f32be"===t.info.codec&&(i?32===n?t.info.codec="pcm-f32":64===n?t.info.codec="pcm-f64":(console.warn(`Invalid fpcm sample size ${n}.`),t.info.codec=null):32===n?t.info.codec="pcm-f32be":64===n?t.info.codec="pcm-f64be":(console.warn(`Invalid fpcm sample size ${n}.`),t.info.codec=null));break}case"dOps":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(o=t.info)?void 0:o.type)),e.skip(1);const r=Sn(e),i=wn(e),n=Cn(e),s=Pn(e),a=Sn(e);let l;l=0!==a?Tn(e,2+r):new Uint8Array(0);const c=new Uint8Array(19+l.byteLength),u=new DataView(c.buffer);u.setUint32(0,1332770163,!1),u.setUint32(4,1214603620,!1),u.setUint8(8,1),u.setUint8(9,r),u.setUint16(10,i,!0),u.setUint32(12,n,!0),u.setInt16(16,s,!0),u.setUint8(18,a),c.set(l,19),t.info.codecDescription=c,t.info.numberOfChannels=r}break;case"dfLa":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(l=t.info)?void 0:l.type)),e.skip(4);const r=127,i=128,n=e.filePos;for(;e.filePos>>12,n=1+(r>>9&7);t.info.sampleRate=i,t.info.numberOfChannels=n,e.skip(20)}else e.skip(s);if(n&i)break}const s=e.filePos;e.filePos=n;const a=Tn(e,s-n),o=new Uint8Array(4+a.byteLength);new DataView(o.buffer).setUint32(0,1716281667,!1),o.set(a,4),t.info.codecDescription=o}break;case"stts":{const t=this.currentTrack;if(!t)break;if(!t.sampleTable)break;e.skip(4);const r=Cn(e);let i=0,n=0;for(let s=0;se.id===r);if(!i)break;const n=Cn(e),s=(12&n)>>2,a=3&n,o=[Sn,wn,In,Cn],l=o[(48&n)>>4],c=o[s],u=o[a],d=Cn(e);for(let h=0;he.timestamp-t.timestamp);for(let e=0;ee.id===c);if(!f)break;const g=this.fragmentTrackDefaults.find(e=>e.trackId===c);this.currentTrack=f,f.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:null!=(u=null==g?void 0:g.defaultSampleDescriptionIndex)?u:null,defaultSampleDuration:null!=(d=null==g?void 0:g.defaultSampleDuration)?d:null,defaultSampleSize:null!=(h=null==g?void 0:g.defaultSampleSize)?h:null,defaultSampleFlags:null!=(m=null==g?void 0:g.defaultSampleFlags)?m:null,startTimestamp:null},r?f.currentFragmentState.baseDataOffset=Fn(e):l&&(f.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),i&&(f.currentFragmentState.sampleDescriptionIndex=Cn(e)),n&&(f.currentFragmentState.defaultSampleDuration=Cn(e)),s&&(f.currentFragmentState.defaultSampleSize=Cn(e)),a&&(f.currentFragmentState.defaultSampleFlags=Cn(e)),o&&(f.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{const t=this.currentTrack;if(!t)break;p(t.currentFragmentState);const r=Sn(e);e.skip(3);const i=0===r?Cn(e):Fn(e);t.currentFragmentState.startTimestamp=i}break;case"trun":{const t=this.currentTrack;if(!t)break;if(p(this.currentFragment),p(t.currentFragmentState),this.currentFragment.trackData.has(t.id)){console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring...");break}const r=Sn(e),i=In(e),n=Boolean(1&i),s=Boolean(4&i),a=Boolean(256&i),o=Boolean(512&i),l=Boolean(1024&i),c=Boolean(2048&i),u=Cn(e);let d=t.currentFragmentState.baseDataOffset;n&&(d+=Bn(e));let h=null;s&&(h=Cn(e));let m=d;if(0===u){this.currentFragment.implicitBaseDataOffset=m;break}let f=0;const g={track:t,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(t.id,g);for(let k=0;k({presentationTimestamp:e.presentationTimestamp,sampleIndex:t})).sort((e,t)=>e.presentationTimestamp-t.presentationTimestamp);for(let e=0;e0&&(null!=(J=this.metadataTags).trackNumber||(J.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&(null!=(Z=this.metadataTags).tracksTotal||(Z.tracksTotal=r))}break;case"trkn":if(n instanceof Uint8Array&&n.length>=6){const e=v(n),t=e.getUint16(2,!1),r=e.getUint16(4,!1);t>0&&(null!=(ee=this.metadataTags).trackNumber||(ee.trackNumber=t)),r>0&&(null!=(te=this.metadataTags).tracksTotal||(te.tracksTotal=r))}break;case"disc":case"disk":if(n instanceof Uint8Array&&n.length>=6){const e=v(n),t=e.getUint16(2,!1),r=e.getUint16(4,!1);t>0&&(null!=(re=this.metadataTags).discNumber||(re.discNumber=t)),r>0&&(null!=(ie=this.metadataTags).discsTotal||(ie.discsTotal=r))}}}}}var le,ce;return e.filePos=oe,!0}}class nr{constructor(e){this.internalTrack=e,this.packetToSampleIndex=new WeakMap,this.packetToFragmentLocation=new WeakMap}getId(){return this.internalTrack.id}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.internalCodecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.timescale}getDisposition(){return this.internalTrack.disposition}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getFirstTimestamp(){return u(this,null,function*(){var e;const t=yield this.getFirstPacket({metadataOnly:!0});return null!=(e=null==t?void 0:t.timestamp)?e:0})}getFirstPacket(e){return u(this,null,function*(){const t=yield this.fetchPacketForSampleIndex(0,e);return t||!this.internalTrack.demuxer.isFragmented?t:this.performFragmentedLookup(null,e=>e.trackData.get(this.internalTrack.id)?{sampleIndex:0,correctSampleFound:!0}:{sampleIndex:-1,correctSampleFound:!1},-1/0,1/0,e)})}mapTimestampIntoTimescale(e){return Q(e*this.internalTrack.timescale)+this.internalTrack.editListOffset}getPacket(e,t){return u(this,null,function*(){const r=this.mapTimestampIntoTimescale(e),i=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=or(i,r),s=yield this.fetchPacketForSampleIndex(n,t);return mr(i)&&this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const i=N(t.presentationTimestamps,r,e=>e.presentationTimestamp);return{sampleIndex:-1!==i?t.presentationTimestamps[i].sampleIndex:-1,correctSampleFound:-1!==i&&r{if(e===i.fragment){const t=e.trackData.get(this.internalTrack.id);if(i.sampleIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const i=U(t.presentationTimestamps,e=>t.samples[e.sampleIndex].isKeyFrame&&e.presentationTimestamp<=r);return{sampleIndex:-1!==i?t.presentationTimestamps[i].sampleIndex:-1,correctSampleFound:-1!==i&&r{if(e===i.fragment){const t=e.trackData.get(this.internalTrack.id).samples.findIndex((e,t)=>e.isKeyFrame&&t>i.sampleIndex);if(-1!==t)return{sampleIndex:t,correctSampleFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.samples.findIndex(e=>e.isKeyFrame);return p(-1!==e),{sampleIndex:e,correctSampleFound:!0}}}return{sampleIndex:-1,correctSampleFound:!1}},-1/0,1/0,t)})}fetchPacketForSampleIndex(e,t){return u(this,null,function*(){if(-1===e)return null;const r=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=cr(r,e);if(!i)return null;let n;if(t.metadataOnly)n=ut;else{let e=this.internalTrack.demuxer.reader.requestSlice(i.sampleOffset,i.sampleSize);e instanceof Promise&&(e=yield e),p(e),n=Tn(e,i.sampleSize)}const s=(i.presentationTimestamp-this.internalTrack.editListOffset)/this.internalTrack.timescale,a=i.duration/this.internalTrack.timescale,o=new dt(n,i.isKeyFrame?"key":"delta",s,a,e,i.sampleSize);return this.packetToSampleIndex.set(o,e),o})}fetchPacketInFragment(e,t,r){return u(this,null,function*(){if(-1===t)return null;const i=e.trackData.get(this.internalTrack.id).samples[t];let n;if(p(i),r.metadataOnly)n=ut;else{let e=this.internalTrack.demuxer.reader.requestSlice(i.byteOffset,i.byteSize);e instanceof Promise&&(e=yield e),p(e),n=Tn(e,i.byteSize)}const s=(i.presentationTimestamp-this.internalTrack.editListOffset)/this.internalTrack.timescale,a=i.duration/this.internalTrack.timescale,o=new dt(n,i.isKeyFrame?"key":"delta",s,a,e.moofOffset+t,i.byteSize);return this.packetToFragmentLocation.set(o,{fragment:e,sampleIndex:t}),o})}performFragmentedLookup(e,t,r,i,n){return u(this,null,function*(){var s,a,o;const l=this.internalTrack.demuxer;let c=null,u=null,d=-1;if(e){const{sampleIndex:r,correctSampleFound:i}=t(e);if(i)return this.fetchPacketInFragment(e,r,n);-1!==r&&(u=e,d=r)}const h=N(this.internalTrack.fragmentLookupTable,r,e=>e.timestamp),m=-1!==h?this.internalTrack.fragmentLookupTable[h]:null,f=N(this.internalTrack.fragmentPositionCache,r,e=>e.startTimestamp),g=-1!==f?this.internalTrack.fragmentPositionCache[f]:null,k=Math.max(null!=(s=null==m?void 0:m.moofOffset)?s:0,null!=(a=null==g?void 0:g.moofOffset)?a:0)||null;let b;for(e?null===k||e.moofOffset>=k?(b=e.moofOffset+e.moofSize,c=e):b=k:b=null!=k?k:0;;){if(c){const e=c.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>i)break}let e=l.reader.requestSliceRange(b,8,16);if(e instanceof Promise&&(e=yield e),!e)break;const r=b,s=Yt(e);if(!s)break;if("moof"===s.name){c=yield l.readFragment(r);const{sampleIndex:e,correctSampleFound:i}=t(c);if(i)return this.fetchPacketInFragment(c,e,n);-1!==e&&(u=c,d=e)}b=r+s.totalSize}if(m&&(!u||u.moofOffsetu(this,null,function*(){var e,t;if("vp9"!==this.internalTrack.info.codec||this.internalTrack.info.vp9CodecInfo){if("av1"===this.internalTrack.info.codec&&!this.internalTrack.info.av1CodecInfo){const e=yield this.getFirstPacket({});this.internalTrack.info.av1CodecInfo=e&&et(e.data)}}else{const e=yield this.getFirstPacket({});this.internalTrack.info.vp9CodecInfo=e&&Je(e.data)}return{codec:Se(this.internalTrack.info),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0,colorSpace:null!=(t=this.internalTrack.info.colorSpace)?t:void 0}}))():null})}}class ar extends nr{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}getDecoderConfig(){return u(this,null,function*(){var e,t;return this.internalTrack.info.codec?null!=(t=this.decoderConfig)?t:this.decoderConfig={codec:ve(this.internalTrack.info),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0}:null})}}const or=(e,t)=>{if(e.presentationTimestamps){const r=N(e.presentationTimestamps,t,e=>e.presentationTimestamp);return-1===r?-1:e.presentationTimestamps[r].sampleIndex}{const r=N(e.sampleTimingEntries,t,e=>e.startDecodeTimestamp);if(-1===r)return-1;const i=e.sampleTimingEntries[r];return i.startIndex+Math.min(Math.floor((t-i.startDecodeTimestamp)/i.delta),i.count-1)}},lr=(e,t)=>{var r;if(!e.keySampleIndices)return or(e,t);if(e.presentationTimestamps){const r=N(e.presentationTimestamps,t,e=>e.presentationTimestamp);if(-1===r)return-1;for(let t=r;t>=0;t--){const r=e.presentationTimestamps[t].sampleIndex;if(-1!==M(e.keySampleIndices,r,e=>e))return r}return-1}{const i=or(e,t),n=N(e.keySampleIndices,i,e=>e);return null!=(r=e.keySampleIndices[n])?r:-1}},cr=(e,t)=>{const r=N(e.sampleTimingEntries,t,e=>e.startIndex),i=e.sampleTimingEntries[r];if(!i||i.startIndex+i.count<=t)return null;let n=i.startDecodeTimestamp+(t-i.startIndex)*i.delta;const s=N(e.sampleCompositionTimeOffsets,t,e=>e.startIndex),a=e.sampleCompositionTimeOffsets[s];a&&t-a.startIndexe.startSampleIndex),c=e.sampleToChunk[l];p(c);const u=c.startChunkIndex+Math.floor((t-c.startSampleIndex)/c.samplesPerChunk),d=e.chunkOffsets[u],h=c.startSampleIndex+(u-c.startChunkIndex)*c.samplesPerChunk;let m=0,f=d;if(1===e.sampleSizes.length)f+=o*(t-h),m+=o*c.samplesPerChunk;else for(let p=h;pe)}},ur=(e,t)=>{var r;if(!e.keySampleIndices)return t+1;const i=N(e.keySampleIndices,t,e=>e);return null!=(r=e.keySampleIndices[i+1])?r:-1},dr=(e,t)=>{e.startTimestamp+=t,e.endTimestamp+=t;for(const r of e.samples)r.presentationTimestamp+=t;for(const r of e.presentationTimestamps)r.presentationTimestamp+=t},hr=e=>{const[t,,,r]=e,i=Math.hypot(t,r),n=t/i,s=r/i,a=-Math.atan2(s,n)*(180/Math.PI);return Number.isFinite(a)?a:0},mr=e=>0===e.sampleSizes.length;var fr,pr;(pr=fr||(fr={}))[pr.EBML=440786851]="EBML",pr[pr.EBMLVersion=17030]="EBMLVersion",pr[pr.EBMLReadVersion=17143]="EBMLReadVersion",pr[pr.EBMLMaxIDLength=17138]="EBMLMaxIDLength",pr[pr.EBMLMaxSizeLength=17139]="EBMLMaxSizeLength",pr[pr.DocType=17026]="DocType",pr[pr.DocTypeVersion=17031]="DocTypeVersion",pr[pr.DocTypeReadVersion=17029]="DocTypeReadVersion",pr[pr.Void=236]="Void",pr[pr.Segment=408125543]="Segment",pr[pr.SeekHead=290298740]="SeekHead",pr[pr.Seek=19899]="Seek",pr[pr.SeekID=21419]="SeekID",pr[pr.SeekPosition=21420]="SeekPosition",pr[pr.Duration=17545]="Duration",pr[pr.Info=357149030]="Info",pr[pr.TimestampScale=2807729]="TimestampScale",pr[pr.MuxingApp=19840]="MuxingApp",pr[pr.WritingApp=22337]="WritingApp",pr[pr.Tracks=374648427]="Tracks",pr[pr.TrackEntry=174]="TrackEntry",pr[pr.TrackNumber=215]="TrackNumber",pr[pr.TrackUID=29637]="TrackUID",pr[pr.TrackType=131]="TrackType",pr[pr.FlagEnabled=185]="FlagEnabled",pr[pr.FlagDefault=136]="FlagDefault",pr[pr.FlagForced=21930]="FlagForced",pr[pr.FlagOriginal=21934]="FlagOriginal",pr[pr.FlagHearingImpaired=21931]="FlagHearingImpaired",pr[pr.FlagVisualImpaired=21932]="FlagVisualImpaired",pr[pr.FlagCommentary=21935]="FlagCommentary",pr[pr.FlagLacing=156]="FlagLacing",pr[pr.Name=21358]="Name",pr[pr.Language=2274716]="Language",pr[pr.LanguageBCP47=2274717]="LanguageBCP47",pr[pr.CodecID=134]="CodecID",pr[pr.CodecPrivate=25506]="CodecPrivate",pr[pr.CodecDelay=22186]="CodecDelay",pr[pr.SeekPreRoll=22203]="SeekPreRoll",pr[pr.DefaultDuration=2352003]="DefaultDuration",pr[pr.Video=224]="Video",pr[pr.PixelWidth=176]="PixelWidth",pr[pr.PixelHeight=186]="PixelHeight",pr[pr.AlphaMode=21440]="AlphaMode",pr[pr.Audio=225]="Audio",pr[pr.SamplingFrequency=181]="SamplingFrequency",pr[pr.Channels=159]="Channels",pr[pr.BitDepth=25188]="BitDepth",pr[pr.SimpleBlock=163]="SimpleBlock",pr[pr.BlockGroup=160]="BlockGroup",pr[pr.Block=161]="Block",pr[pr.BlockAdditions=30113]="BlockAdditions",pr[pr.BlockMore=166]="BlockMore",pr[pr.BlockAdditional=165]="BlockAdditional",pr[pr.BlockAddID=238]="BlockAddID",pr[pr.BlockDuration=155]="BlockDuration",pr[pr.ReferenceBlock=251]="ReferenceBlock",pr[pr.Cluster=524531317]="Cluster",pr[pr.Timestamp=231]="Timestamp",pr[pr.Cues=475249515]="Cues",pr[pr.CuePoint=187]="CuePoint",pr[pr.CueTime=179]="CueTime",pr[pr.CueTrackPositions=183]="CueTrackPositions",pr[pr.CueTrack=247]="CueTrack",pr[pr.CueClusterPosition=241]="CueClusterPosition",pr[pr.Colour=21936]="Colour",pr[pr.MatrixCoefficients=21937]="MatrixCoefficients",pr[pr.TransferCharacteristics=21946]="TransferCharacteristics",pr[pr.Primaries=21947]="Primaries",pr[pr.Range=21945]="Range",pr[pr.Projection=30320]="Projection",pr[pr.ProjectionType=30321]="ProjectionType",pr[pr.ProjectionPoseRoll=30325]="ProjectionPoseRoll",pr[pr.Attachments=423732329]="Attachments",pr[pr.AttachedFile=24999]="AttachedFile",pr[pr.FileDescription=18046]="FileDescription",pr[pr.FileName=18030]="FileName",pr[pr.FileMediaType=18016]="FileMediaType",pr[pr.FileData=18012]="FileData",pr[pr.FileUID=18094]="FileUID",pr[pr.Chapters=272869232]="Chapters",pr[pr.Tags=307544935]="Tags",pr[pr.Tag=29555]="Tag",pr[pr.Targets=25536]="Targets",pr[pr.TargetTypeValue=26826]="TargetTypeValue",pr[pr.TargetType=25546]="TargetType",pr[pr.TagTrackUID=25541]="TagTrackUID",pr[pr.TagEditionUID=25545]="TagEditionUID",pr[pr.TagChapterUID=25540]="TagChapterUID",pr[pr.TagAttachmentUID=25542]="TagAttachmentUID",pr[pr.SimpleTag=26568]="SimpleTag",pr[pr.TagName=17827]="TagName",pr[pr.TagLanguage=17530]="TagLanguage",pr[pr.TagString=17543]="TagString",pr[pr.TagBinary=17541]="TagBinary",pr[pr.ContentEncodings=28032]="ContentEncodings",pr[pr.ContentEncoding=25152]="ContentEncoding",pr[pr.ContentEncodingOrder=20529]="ContentEncodingOrder",pr[pr.ContentEncodingScope=20530]="ContentEncodingScope",pr[pr.ContentCompression=20532]="ContentCompression",pr[pr.ContentCompAlgo=16980]="ContentCompAlgo",pr[pr.ContentCompSettings=16981]="ContentCompSettings",pr[pr.ContentEncryption=20533]="ContentEncryption";const gr=[fr.EBML,fr.Segment],kr=[fr.SeekHead,fr.Info,fr.Cluster,fr.Tracks,fr.Cues,fr.Attachments,fr.Chapters,fr.Tags],br=[...gr,...kr],yr=16,Tr=e=>{if(e.remainingLength<1)return null;const t=Sn(e);if(e.skip(-1),0===t)return null;let r=1,i=128;for(;0===(t&i);)r++,i>>=1;return e.remainingLength{if(e.remainingLength<1)return null;const t=Sn(e);if(0===t)return null;let r=1,i=128;for(;0===(t&i);)r++,i>>=1;if(e.remainingLength{if(t<1||t>8)throw new Error("Bad unsigned int size "+t);let r=0;for(let i=0;i{const t=Tr(e);if(null===t)return null;if(e.remainingLength{if(e.remainingLength<1)return null;if(255===Sn(e))return;e.skip(-1);const t=Sr(e);return null===t?null:72057594037927940!==t?t:void 0},Pr=e=>{p(e.remainingLength>=2);const t=wr(e);if(null===t)return null;const r=Ir(e);return null===r?null:{id:t,size:r}},xr=(e,t)=>{const r=Tn(e,t);let i=0;for(;i{const r=Tn(e,t);let i=0;for(;i{if(0===t)return 0;if(4!==t&&8!==t)throw new Error("Bad float size "+t);return 4===t?Rn(e):Mn(e)},Br=(e,t,r,i)=>u(null,null,function*(){const n=new Set(r);let s=t;for(;null===i||ss?i:s,found:!1}}),Er=(e,t,r,i)=>u(null,null,function*(){const n=o(2,16),s=new Set(r);let a=t;for(;ae.computeDuration()));return Math.max(0,...t)})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.segments.flatMap(e=>e.tracks.map(e=>e.inputTrack))})}getMimeType(){return u(this,null,function*(){yield this.readMetadata();const e=yield this.getTracks(),t=yield Promise.all(e.map(e=>e.getCodecParameterString()));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isWebM?"webm":"x-matroska");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings.filter(Boolean))].join(", ")}"`);return t})({isWebM:this.isWebM,hasVideo:this.segments.some(e=>e.tracks.some(e=>{var t;return"video"===(null==(t=e.info)?void 0:t.type)})),hasAudio:this.segments.some(e=>e.tracks.some(e=>{var t;return"audio"===(null==(t=e.info)?void 0:t.type)})),codecStrings:t.filter(Boolean)})})}getMetadataTags(){return u(this,null,function*(){yield this.readMetadata();for(const t of this.segments)t.metadataTagsCollected||(null!==this.reader.fileSize&&(yield this.loadSegmentMetadata(t)),t.metadataTagsCollected=!0);let e={};for(const t of this.segments)e=c(c({},e),t.metadataTags);return e})}readMetadata(){var e;return null!=(e=this.readMetadataPromise)?e:this.readMetadataPromise=(()=>u(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,2,yr);if(t instanceof Promise&&(t=yield t),!t)break;const r=Pr(t);if(!r)break;const i=r.id;let n=r.size;const s=t.filePos;if(i===fr.EBML){Vr(n);let e=this.reader.requestSlice(s,n);if(e instanceof Promise&&(e=yield e),!e)break;this.readContiguousElements(e)}else if(i===fr.Segment){if(yield this.readSegment(s,n),void 0===n)break;if(null===this.reader.fileSize)break}else if(i===fr.Cluster){if(null===this.reader.fileSize)break;if(void 0===n){n=(yield Br(this.reader,s,br,this.reader.fileSize)).pos-s}const e=k(this.segments);e&&(e.elementEndPos=s+n)}Vr(n),e=s+n}}))()}readSegment(e,t){return u(this,null,function*(){var r;this.currentSegment={seekHeadSeen:!1,infoSeen:!1,tracksSeen:!1,cuesSeen:!1,tagsSeen:!1,attachmentsSeen:!1,timestampScale:-1,timestampFactor:-1,duration:-1,seekEntries:[],tracks:[],cuePoints:[],dataStartPos:e,elementEndPos:void 0===t?null:e+t,clusterSeekStartPos:e,lastReadCluster:null,metadataTags:{},metadataTagsCollected:!1},this.segments.push(this.currentSegment);let i=e;for(;null===this.currentSegment.elementEndPos||ie.id===s);if(-1!==l){const e=Qr[l].flag;this.currentSegment[e]=!0,Vr(a);let t=this.reader.requestSlice(o,a);t instanceof Promise&&(t=yield t),t&&this.readContiguousElements(t)}else if(s===fr.Tags||s===fr.Attachments){s===fr.Tags?this.currentSegment.tagsSeen=!0:this.currentSegment.attachmentsSeen=!0,Vr(a);let e=this.reader.requestSlice(o,a);e instanceof Promise&&(e=yield e),e&&this.readContiguousElements(e)}else if(s===fr.Cluster){this.currentSegment.clusterSeekStartPos=t;break}if(void 0===a)break;i=o+a}if(this.currentSegment.seekEntries.sort((e,t)=>e.segmentPosition-t.segmentPosition),null!==this.reader.fileSize)for(const t of this.currentSegment.seekEntries){const r=Qr.find(e=>e.id===t.id);if(!r)continue;if(this.currentSegment[r.flag])continue;let i=this.reader.requestSliceRange(e+t.segmentPosition,2,yr);if(i instanceof Promise&&(i=yield i),!i)continue;const n=Pr(i);if(!n)continue;const{id:s,size:a}=n;if(s!==r.id)continue;Vr(a),this.currentSegment[r.flag]=!0;let o=this.reader.requestSlice(i.filePos,a);o instanceof Promise&&(o=yield o),o&&this.readContiguousElements(o)}-1===this.currentSegment.timestampScale&&(this.currentSegment.timestampScale=1e6,this.currentSegment.timestampFactor=1e3);for(const e of this.currentSegment.tracks)null!==e.defaultDurationNs&&(e.defaultDuration=this.currentSegment.timestampFactor*e.defaultDurationNs/1e9);this.currentSegment.tracks.sort((e,t)=>Number(t.disposition.default)-Number(e.disposition.default));const n=new Map(this.currentSegment.tracks.map(e=>[e.id,e]));for(const e of this.currentSegment.cuePoints){const t=n.get(e.trackId);t&&t.cuePoints.push(e)}for(const e of this.currentSegment.tracks){e.cuePoints.sort((e,t)=>e.time-t.time);for(let t=0;ta&&(a=e.cuePoints.length,s=e);for(const e of this.currentSegment.tracks)0===e.cuePoints.length&&(e.cuePoints=s.cuePoints);this.currentSegment=null})}readCluster(e,t){return u(this,null,function*(){var r;if((null==(r=t.lastReadCluster)?void 0:r.elementStartPos)===e)return t.lastReadCluster;let i=this.reader.requestSliceRange(e,2,yr);i instanceof Promise&&(i=yield i),p(i);const n=e,s=Pr(i);p(s);p(s.id===fr.Cluster);let a=s.size;const o=i.filePos;if(void 0===a){a=(yield Br(this.reader,o,br,t.elementEndPos)).pos-o}let l=this.reader.requestSlice(o,a);l instanceof Promise&&(l=yield l);const c={segment:t,elementStartPos:n,elementEndPos:o+a,dataStartPos:o,timestamp:-1,trackData:new Map};if(this.currentCluster=c,l){const e=this.readContiguousElements(l,br);c.elementEndPos=e}for(const[,e]of c.trackData){const t=e.track;p(e.blocks.length>0);let r=!1;for(let n=0;n({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp);for(let n=0;n({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp));const i=e.blocks[e.presentationTimestamps[0].blockIndex],s=e.blocks[k(e.presentationTimestamps).blockIndex];e.startTimestamp=i.timestamp,e.endTimestamp=s.timestamp+s.duration;const a=N(t.clusterPositionCache,e.startTimestamp,e=>e.startTimestamp);-1!==a&&t.clusterPositionCache[a].elementStartPos===n||t.clusterPositionCache.splice(a+1,0,{elementStartPos:c.elementStartPos,startTimestamp:e.startTimestamp})}return t.lastReadCluster=c,c})}getTrackDataInCluster(e,t){let r=e.trackData.get(t);if(!r){const i=e.segment.tracks.find(e=>e.id===t);if(!i)return null;r={track:i,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,blocks:[],presentationTimestamps:[]},e.trackData.set(t,r)}return r}expandLacedBlocks(e,t){var r;for(let i=0;i=2;){const r=e.filePos;if(!this.traverseElement(e,t))return r}return e.filePos}traverseElement(e,t){var r,i,n,s,a,o,l,u,d,h,m,f,k,b,y,T,S,v,w,I,P,C,B,F,D,A,R,M,N,z,O,L,U,V,q,H,W,j,K,Q,G,Y,J,Z,ee,te,re,ie;const ne=Pr(e);if(!ne)return!1;if(t&&t.includes(ne.id))return!1;const{id:se,size:ae}=ne,oe=e.filePos;switch(Vr(ae),se){case fr.DocType:this.isWebM="webm"===xr(e,ae);break;case fr.Seek:{if(!this.currentSegment)break;const t={id:-1,segmentPosition:-1};this.currentSegment.seekEntries.push(t),this.readContiguousElements(e.slice(oe,ae)),-1!==t.id&&-1!==t.segmentPosition||this.currentSegment.seekEntries.pop()}break;case fr.SeekID:{const t=null==(r=this.currentSegment)?void 0:r.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.id=vr(e,ae)}break;case fr.SeekPosition:{const t=null==(i=this.currentSegment)?void 0:i.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.segmentPosition=vr(e,ae)}break;case fr.TimestampScale:if(!this.currentSegment)break;this.currentSegment.timestampScale=vr(e,ae),this.currentSegment.timestampFactor=1e9/this.currentSegment.timestampScale;break;case fr.Duration:if(!this.currentSegment)break;this.currentSegment.duration=_r(e,ae);break;case fr.TrackEntry:if(!this.currentSegment)break;if(this.currentTrack={id:-1,segment:this.currentSegment,demuxer:this,clusterPositionCache:[],cuePoints:[],disposition:c({},ge),inputTrack:null,codecId:null,codecPrivate:null,defaultDuration:null,defaultDurationNs:null,name:null,languageCode:$,decodingInstructions:[],info:null},this.readContiguousElements(e.slice(oe,ae)),!this.currentTrack)break;if(this.currentTrack.decodingInstructions.some(e=>{var t;return"decompress"!==(null==(t=e.data)?void 0:t.type)||e.scope!==Wr.Block||e.data.algorithm!==Kr.HeaderStripping})&&(console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`),this.currentTrack=null),this.currentTrack&&-1!==this.currentTrack.id&&this.currentTrack.codecId&&this.currentTrack.info){const e=this.currentTrack.codecId.indexOf("/"),t=-1===e?this.currentTrack.codecId:this.currentTrack.codecId.slice(0,e);if("video"===this.currentTrack.info.type&&-1!==this.currentTrack.info.width&&-1!==this.currentTrack.info.height){this.currentTrack.codecId===Fr?(this.currentTrack.info.codec="avc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Dr?(this.currentTrack.info.codec="hevc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ar?this.currentTrack.info.codec="vp8":t===Rr?this.currentTrack.info.codec="vp9":t===Mr&&(this.currentTrack.info.codec="av1");const e=this.currentTrack,r=new Gt(this.input,new Jr(e));this.currentTrack.inputTrack=r,this.currentSegment.tracks.push(this.currentTrack)}else if("audio"===this.currentTrack.info.type&&-1!==this.currentTrack.info.numberOfChannels&&-1!==this.currentTrack.info.sampleRate){t===Nr?(this.currentTrack.info.codec="aac",this.currentTrack.info.aacCodecInfo={isMpeg2:this.currentTrack.codecId.includes("MPEG2")},this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===zr?this.currentTrack.info.codec="mp3":t===Or?(this.currentTrack.info.codec="opus",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate,this.currentTrack.info.sampleRate=xe):t===Lr?(this.currentTrack.info.codec="vorbis",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ur?(this.currentTrack.info.codec="flac",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):"A_PCM/INT/LIT"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32"):"A_PCM/INT/BIG"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16be":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24be":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32be"):"A_PCM/FLOAT/IEEE"===this.currentTrack.codecId&&(32===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-f32":64===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-f64"));const e=this.currentTrack,r=new Xt(this.input,new Zr(e));this.currentTrack.inputTrack=r,this.currentSegment.tracks.push(this.currentTrack)}}this.currentTrack=null;break;case fr.TrackNumber:if(!this.currentTrack)break;this.currentTrack.id=vr(e,ae);break;case fr.TrackType:{if(!this.currentTrack)break;const t=vr(e,ae);1===t?this.currentTrack.info={type:"video",width:-1,height:-1,rotation:0,codec:null,codecDescription:null,colorSpace:null,alphaMode:!1}:2===t&&(this.currentTrack.info={type:"audio",numberOfChannels:-1,sampleRate:-1,bitDepth:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case fr.FlagEnabled:if(!this.currentTrack)break;vr(e,ae)||(this.currentTrack=null);break;case fr.FlagDefault:if(!this.currentTrack)break;this.currentTrack.disposition.default=!!vr(e,ae);break;case fr.FlagForced:if(!this.currentTrack)break;this.currentTrack.disposition.forced=!!vr(e,ae);break;case fr.FlagOriginal:if(!this.currentTrack)break;this.currentTrack.disposition.original=!!vr(e,ae);break;case fr.FlagHearingImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.hearingImpaired=!!vr(e,ae);break;case fr.FlagVisualImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.visuallyImpaired=!!vr(e,ae);break;case fr.FlagCommentary:if(!this.currentTrack)break;this.currentTrack.disposition.commentary=!!vr(e,ae);break;case fr.CodecID:if(!this.currentTrack)break;this.currentTrack.codecId=xr(e,ae);break;case fr.CodecPrivate:if(!this.currentTrack)break;this.currentTrack.codecPrivate=Tn(e,ae);break;case fr.DefaultDuration:if(!this.currentTrack)break;this.currentTrack.defaultDurationNs=vr(e,ae);break;case fr.Name:if(!this.currentTrack)break;this.currentTrack.name=Cr(e,ae);break;case fr.Language:if(!this.currentTrack)break;if(this.currentTrack.languageCode!==$)break;this.currentTrack.languageCode=xr(e,ae),X(this.currentTrack.languageCode)||(this.currentTrack.languageCode=$);break;case fr.LanguageBCP47:{if(!this.currentTrack)break;const t=xr(e,ae).split("-")[0];this.currentTrack.languageCode=t||$}break;case fr.Video:if("video"!==(null==(s=null==(n=this.currentTrack)?void 0:n.info)?void 0:s.type))break;this.readContiguousElements(e.slice(oe,ae));break;case fr.PixelWidth:if("video"!==(null==(o=null==(a=this.currentTrack)?void 0:a.info)?void 0:o.type))break;this.currentTrack.info.width=vr(e,ae);break;case fr.PixelHeight:if("video"!==(null==(u=null==(l=this.currentTrack)?void 0:l.info)?void 0:u.type))break;this.currentTrack.info.height=vr(e,ae);break;case fr.AlphaMode:if("video"!==(null==(h=null==(d=this.currentTrack)?void 0:d.info)?void 0:h.type))break;this.currentTrack.info.alphaMode=1===vr(e,ae);break;case fr.Colour:if("video"!==(null==(f=null==(m=this.currentTrack)?void 0:m.info)?void 0:f.type))break;this.currentTrack.info.colorSpace={},this.readContiguousElements(e.slice(oe,ae));break;case fr.MatrixCoefficients:{if("video"!==(null==(b=null==(k=this.currentTrack)?void 0:k.info)?void 0:b.type)||!this.currentTrack.info.colorSpace)break;const t=vr(e,ae),r=null!=(y=E[t])?y:null;this.currentTrack.info.colorSpace.matrix=r}break;case fr.Range:if("video"!==(null==(S=null==(T=this.currentTrack)?void 0:T.info)?void 0:S.type)||!this.currentTrack.info.colorSpace)break;this.currentTrack.info.colorSpace.fullRange=2===vr(e,ae);break;case fr.TransferCharacteristics:{if("video"!==(null==(w=null==(v=this.currentTrack)?void 0:v.info)?void 0:w.type)||!this.currentTrack.info.colorSpace)break;const t=vr(e,ae),r=null!=(I=_[t])?I:null;this.currentTrack.info.colorSpace.transfer=r}break;case fr.Primaries:{if("video"!==(null==(C=null==(P=this.currentTrack)?void 0:P.info)?void 0:C.type)||!this.currentTrack.info.colorSpace)break;const t=vr(e,ae),r=null!=(B=x[t])?B:null;this.currentTrack.info.colorSpace.primaries=r}break;case fr.Projection:if("video"!==(null==(D=null==(F=this.currentTrack)?void 0:F.info)?void 0:D.type))break;this.readContiguousElements(e.slice(oe,ae));break;case fr.ProjectionPoseRoll:{if("video"!==(null==(R=null==(A=this.currentTrack)?void 0:A.info)?void 0:R.type))break;const t=-_r(e,ae);try{this.currentTrack.info.rotation=g(t)}catch(le){}}break;case fr.Audio:if("audio"!==(null==(N=null==(M=this.currentTrack)?void 0:M.info)?void 0:N.type))break;this.readContiguousElements(e.slice(oe,ae));break;case fr.SamplingFrequency:if("audio"!==(null==(O=null==(z=this.currentTrack)?void 0:z.info)?void 0:O.type))break;this.currentTrack.info.sampleRate=_r(e,ae);break;case fr.Channels:if("audio"!==(null==(U=null==(L=this.currentTrack)?void 0:L.info)?void 0:U.type))break;this.currentTrack.info.numberOfChannels=vr(e,ae);break;case fr.BitDepth:if("audio"!==(null==(q=null==(V=this.currentTrack)?void 0:V.info)?void 0:q.type))break;this.currentTrack.info.bitDepth=vr(e,ae);break;case fr.CuePoint:if(!this.currentSegment)break;this.readContiguousElements(e.slice(oe,ae)),this.currentCueTime=null;break;case fr.CueTime:this.currentCueTime=vr(e,ae);break;case fr.CueTrackPositions:{if(null===this.currentCueTime)break;p(this.currentSegment);const t={time:this.currentCueTime,trackId:-1,clusterPosition:-1};this.currentSegment.cuePoints.push(t),this.readContiguousElements(e.slice(oe,ae)),-1!==t.trackId&&-1!==t.clusterPosition||this.currentSegment.cuePoints.pop()}break;case fr.CueTrack:{const t=null==(H=this.currentSegment)?void 0:H.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;t.trackId=vr(e,ae)}break;case fr.CueClusterPosition:{const t=null==(W=this.currentSegment)?void 0:W.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;p(this.currentSegment),t.clusterPosition=this.currentSegment.dataStartPos+vr(e,ae)}break;case fr.Timestamp:if(!this.currentCluster)break;this.currentCluster.timestamp=vr(e,ae);break;case fr.SimpleBlock:{if(!this.currentCluster)break;const t=Sr(e);if(null===t)break;const r=this.getTrackDataInCluster(this.currentCluster,t);if(!r)break;const i=Pn(e),n=Sn(e),s=n>>1&3;let a=!!(128&n);"audio"===(null==(j=r.track.info)?void 0:j.type)&&r.track.info.codec&&(a=!0);const o=Tn(e,ae-(e.filePos-oe)),l=r.track.decodingInstructions.length>0;r.blocks.push({timestamp:i,duration:0,isKeyFrame:a,data:o,lacing:s,decoded:!l,mainAdditional:null})}break;case fr.BlockGroup:if(!this.currentCluster)break;this.readContiguousElements(e.slice(oe,ae)),this.currentBlock=null;break;case fr.Block:{if(!this.currentCluster)break;const t=Sr(e);if(null===t)break;const r=this.getTrackDataInCluster(this.currentCluster,t);if(!r)break;const i=Pn(e),n=Sn(e)>>1&3,s=Tn(e,ae-(e.filePos-oe)),a=r.track.decodingInstructions.length>0;this.currentBlock={timestamp:i,duration:0,isKeyFrame:!0,data:s,lacing:n,decoded:!a,mainAdditional:null},r.blocks.push(this.currentBlock)}break;case fr.BlockAdditions:this.readContiguousElements(e.slice(oe,ae));break;case fr.BlockMore:if(!this.currentBlock)break;this.currentBlockAdditional={addId:1,data:null},this.readContiguousElements(e.slice(oe,ae)),this.currentBlockAdditional.data&&1===this.currentBlockAdditional.addId&&(this.currentBlock.mainAdditional=this.currentBlockAdditional.data),this.currentBlockAdditional=null;break;case fr.BlockAdditional:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.data=Tn(e,ae);break;case fr.BlockAddID:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.addId=vr(e,ae);break;case fr.BlockDuration:if(!this.currentBlock)break;this.currentBlock.duration=vr(e,ae);break;case fr.ReferenceBlock:if(!this.currentBlock)break;this.currentBlock.isKeyFrame=!1;break;case fr.Tag:this.currentTagTargetIsMovie=!0,this.readContiguousElements(e.slice(oe,ae));break;case fr.Targets:this.readContiguousElements(e.slice(oe,ae));break;case fr.TargetTypeValue:50!==vr(e,ae)&&(this.currentTagTargetIsMovie=!1);break;case fr.TagTrackUID:case fr.TagEditionUID:case fr.TagChapterUID:case fr.TagAttachmentUID:this.currentTagTargetIsMovie=!1;break;case fr.SimpleTag:if(!this.currentTagTargetIsMovie)break;this.currentSimpleTagName=null,this.readContiguousElements(e.slice(oe,ae));break;case fr.TagName:this.currentSimpleTagName=Cr(e,ae);break;case fr.TagString:{if(!this.currentSimpleTagName)break;const t=Cr(e,ae);this.processTagValue(this.currentSimpleTagName,t)}break;case fr.TagBinary:{if(!this.currentSimpleTagName)break;const t=Tn(e,ae);this.processTagValue(this.currentSimpleTagName,t)}break;case fr.AttachedFile:{if(!this.currentSegment)break;this.currentAttachedFile={fileUid:null,fileName:null,fileMediaType:null,fileData:null,fileDescription:null},this.readContiguousElements(e.slice(oe,ae));const t=this.currentSegment.metadataTags;if(this.currentAttachedFile.fileUid&&this.currentAttachedFile.fileData&&(null!=t.raw||(t.raw={}),t.raw[this.currentAttachedFile.fileUid.toString()]=new pe(this.currentAttachedFile.fileData,null!=(K=this.currentAttachedFile.fileMediaType)?K:void 0,null!=(Q=this.currentAttachedFile.fileName)?Q:void 0,null!=(G=this.currentAttachedFile.fileDescription)?G:void 0)),(null==(Y=this.currentAttachedFile.fileMediaType)?void 0:Y.startsWith("image/"))&&this.currentAttachedFile.fileData){const e=this.currentAttachedFile.fileName;let r="unknown";if(e){const t=e.toLowerCase();t.startsWith("cover.")?r="coverFront":t.startsWith("back.")&&(r="coverBack")}null!=t.images||(t.images=[]),t.images.push({data:this.currentAttachedFile.fileData,mimeType:this.currentAttachedFile.fileMediaType,kind:r,name:null!=(J=this.currentAttachedFile.fileName)?J:void 0,description:null!=(Z=this.currentAttachedFile.fileDescription)?Z:void 0})}this.currentAttachedFile=null}break;case fr.FileUID:if(!this.currentAttachedFile)break;this.currentAttachedFile.fileUid=((e,t)=>{if(t<1)throw new Error("Bad unsigned int size "+t);let r=BigInt("0");for(let i=0;it.order-e.order);break;case fr.ContentEncoding:this.currentDecodingInstruction={order:0,scope:Wr.Block,data:null},this.readContiguousElements(e.slice(oe,ae)),this.currentDecodingInstruction.data&&this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction),this.currentDecodingInstruction=null;break;case fr.ContentEncodingOrder:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.order=vr(e,ae);break;case fr.ContentEncodingScope:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.scope=vr(e,ae);break;case fr.ContentCompression:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decompress",algorithm:Kr.Zlib,settings:null},this.readContiguousElements(e.slice(oe,ae));break;case fr.ContentCompAlgo:if("decompress"!==(null==(te=null==(ee=this.currentDecodingInstruction)?void 0:ee.data)?void 0:te.type))break;this.currentDecodingInstruction.data.algorithm=vr(e,ae);break;case fr.ContentCompSettings:if("decompress"!==(null==(ie=null==(re=this.currentDecodingInstruction)?void 0:re.data)?void 0:ie.type))break;this.currentDecodingInstruction.data.settings=Tn(e,ae);break;case fr.ContentEncryption:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decrypt"}}return e.filePos=oe+ae,!0}decodeBlockData(e,t){p(e.decodingInstructions.length>0);let r=t;for(const i of e.decodingInstructions)if(p(i.data),"decompress"===i.data.type)if(i.data.algorithm===Kr.HeaderStripping)if(i.data.settings&&i.data.settings.length>0){const e=i.data.settings,t=new Uint8Array(e.length+r.length);t.set(e,0),t.set(r,e.length),r=t}return r}processTagValue(e,t){var r,i;if(!(null==(r=this.currentSegment)?void 0:r.metadataTags))return;const n=this.currentSegment.metadataTags;if(null!=n.raw||(n.raw={}),null!=(i=n.raw)[e]||(i[e]=t),"string"===typeof t)switch(e.toLowerCase()){case"title":null!=n.title||(n.title=t);break;case"description":null!=n.description||(n.description=t);break;case"artist":null!=n.artist||(n.artist=t);break;case"album":null!=n.album||(n.album=t);break;case"album_artist":null!=n.albumArtist||(n.albumArtist=t);break;case"genre":null!=n.genre||(n.genre=t);break;case"comment":null!=n.comment||(n.comment=t);break;case"lyrics":null!=n.lyrics||(n.lyrics=t);break;case"date":{const e=new Date(t);Number.isNaN(e.getTime())||null!=n.date||(n.date=e)}break;case"track_number":case"part_number":{const e=t.split("/"),r=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(null!=n.trackNumber||(n.trackNumber=r)),i&&Number.isInteger(i)&&i>0&&(null!=n.tracksTotal||(n.tracksTotal=i))}break;case"disc_number":case"disc":{const e=t.split("/"),r=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(null!=n.discNumber||(n.discNumber=r)),i&&Number.isInteger(i)&&i>0&&(null!=n.discsTotal||(n.discsTotal=i))}}}}class Yr{constructor(e){this.internalTrack=e,this.packetToClusterLocation=new WeakMap}getId(){return this.internalTrack.id}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.codecId}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getFirstTimestamp(){return u(this,null,function*(){var e;const t=yield this.getFirstPacket({metadataOnly:!0});return null!=(e=null==t?void 0:t.timestamp)?e:0})}getTimeResolution(){return this.internalTrack.segment.timestampFactor}getDisposition(){return this.internalTrack.disposition}getFirstPacket(e){return u(this,null,function*(){return this.performClusterLookup(null,e=>e.trackData.get(this.internalTrack.id)?{blockIndex:0,correctBlockFound:!0}:{blockIndex:-1,correctBlockFound:!1},-1/0,1/0,e)})}intoTimescale(e){return Q(e*this.internalTrack.segment.timestampFactor)}getPacket(e,t){return u(this,null,function*(){const r=this.intoTimescale(e);return this.performClusterLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const i=N(t.presentationTimestamps,r,e=>e.timestamp);return{blockIndex:-1!==i?t.presentationTimestamps[i].blockIndex:-1,correctBlockFound:-1!==i&&r{if(e===r.cluster){const t=e.trackData.get(this.internalTrack.id);if(r.blockIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const i=U(t.presentationTimestamps,e=>t.blocks[e.blockIndex].isKeyFrame&&e.timestamp<=r);return{blockIndex:-1!==i?t.presentationTimestamps[i].blockIndex:-1,correctBlockFound:-1!==i&&r{if(e===r.cluster){const t=e.trackData.get(this.internalTrack.id).blocks.findIndex((e,t)=>e.isKeyFrame&&t>r.blockIndex);if(-1!==t)return{blockIndex:t,correctBlockFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.blocks.findIndex(e=>e.isKeyFrame);return p(-1!==e),{blockIndex:e,correctBlockFound:!0}}}return{blockIndex:-1,correctBlockFound:!1}},-1/0,1/0,t)})}fetchPacketInCluster(e,t,r){return u(this,null,function*(){var i;if(-1===t)return null;const n=e.trackData.get(this.internalTrack.id).blocks[t];p(n),n.decoded||(n.data=this.internalTrack.demuxer.decodeBlockData(this.internalTrack,n.data),n.decoded=!0);const s=r.metadataOnly?ut:n.data,a=n.timestamp/this.internalTrack.segment.timestampFactor,o=n.duration/this.internalTrack.segment.timestampFactor,l={};n.mainAdditional&&"video"===(null==(i=this.internalTrack.info)?void 0:i.type)&&this.internalTrack.info.alphaMode&&(l.alpha=r.metadataOnly?ut:n.mainAdditional,l.alphaByteLength=n.mainAdditional.byteLength);const c=new dt(s,n.isKeyFrame?"key":"delta",a,o,e.dataStartPos+t,n.data.byteLength,l);return this.packetToClusterLocation.set(c,{cluster:e,blockIndex:t}),c})}performClusterLookup(e,t,r,i,n){return u(this,null,function*(){var s,a,o,l;const{demuxer:c,segment:u}=this.internalTrack;let d=null,h=null,m=-1;if(e){const{blockIndex:r,correctBlockFound:i}=t(e);if(i)return this.fetchPacketInCluster(e,r,n);-1!==r&&(h=e,m=r)}const f=N(this.internalTrack.cuePoints,r,e=>e.time),g=-1!==f?this.internalTrack.cuePoints[f]:null,k=N(this.internalTrack.clusterPositionCache,r,e=>e.startTimestamp),b=-1!==k?this.internalTrack.clusterPositionCache[k]:null,y=Math.max(null!=(s=null==g?void 0:g.clusterPosition)?s:0,null!=(a=null==b?void 0:b.elementStartPos)?a:0)||null;let T;for(e?null===y||e.elementStartPos>=y?(T=e.elementEndPos,d=e):T=y:T=null!=y?y:u.clusterSeekStartPos;null===u.elementEndPos||T<=u.elementEndPos-2;){if(d){const e=d.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>i)break}let e=c.reader.requestSliceRange(T,2,yr);if(e instanceof Promise&&(e=yield e),!e)break;const r=T,s=Pr(e);if(!s||!kr.includes(s.id)&&s.id!==fr.Void){const e=yield Er(c.reader,r,kr,Math.min(null!=(o=u.elementEndPos)?o:1/0,r+Gr));if(e){T=e;continue}break}const a=s.id;let l=s.size;const f=e.filePos;if(a===fr.Cluster){d=yield c.readCluster(r,u),l=d.elementEndPos-f;const{blockIndex:e,correctBlockFound:i}=t(d);if(i)return this.fetchPacketInCluster(d,e,n);-1!==e&&(h=d,m=e)}if(void 0===l){p(a!==fr.Cluster);l=(yield Br(c.reader,f,br,u.elementEndPos)).pos-f}const g=f+l;if(null===u.elementEndPos){let e=c.reader.requestSliceRange(g,2,yr);if(e instanceof Promise&&(e=yield e),!e)break;if(wr(e)===fr.Segment){u.elementEndPos=g;break}}T=g}if(g&&(!h||h.elementStartPosu(this,null,function*(){var e,t;let r=null;return("vp9"===this.internalTrack.info.codec||"av1"===this.internalTrack.info.codec||"avc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription||"hevc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription)&&(r=yield this.getFirstPacket({})),{codec:Se({width:this.internalTrack.info.width,height:this.internalTrack.info.height,codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,colorSpace:this.internalTrack.info.colorSpace,avcType:1,avcCodecInfo:"avc"===this.internalTrack.info.codec&&r?Ue(r.data):null,hevcCodecInfo:"hevc"===this.internalTrack.info.codec&&r?We(r.data):null,vp9CodecInfo:"vp9"===this.internalTrack.info.codec&&r?Je(r.data):null,av1CodecInfo:"av1"===this.internalTrack.info.codec&&r?et(r.data):null}),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0,colorSpace:null!=(t=this.internalTrack.info.colorSpace)?t:void 0}}))():null})}}class Zr extends Yr{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}getDecoderConfig(){return u(this,null,function*(){var e,t;return this.internalTrack.info.codec?null!=(t=this.decoderConfig)?t:this.decoderConfig={codec:ve({codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,aacCodecInfo:this.internalTrack.info.aacCodecInfo}),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0}:null})}}const ei=[44100,48e3,32e3],ti=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1,-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1,-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1],ri=(e,t)=>{const r=e>>>24,i=e>>>16&255,n=e>>>8&255,s=255&e;if(255!==r&&255!==i&&255!==n&&255!==s)return{header:null,bytesAdvanced:4};if(255!==r)return{header:null,bytesAdvanced:1};if(224!==(224&i))return{header:null,bytesAdvanced:1};let a=0,o=0;16&i?a=8&i?0:1:(a=1,o=1);const l=i>>3&3,c=i>>1&3,u=(n>>2&3)%3,d=s>>6&3,h=s>>4&3,m=s>>3&1,f=s>>2&1,p=3&s,g=ti[16*a*4+16*c+(n>>4&15)];if(-1===g)return{header:null,bytesAdvanced:1};const k=1e3*g,b=ei[u]>>a+o,y=((e,t,r,i,n)=>0===t?0:1===t?Math.floor(144*r/(i<>1&1);if(null!==t&&t{let t=2130706432,r=0;for(;0!==t;)r>>=1,r|=e&t,t>>=8;return r};var ni,si,ai,oi;(si=ni||(ni={}))[si.Unsynchronisation=128]="Unsynchronisation",si[si.ExtendedHeader=64]="ExtendedHeader",si[si.ExperimentalIndicator=32]="ExperimentalIndicator",si[si.Footer=16]="Footer",(oi=ai||(ai={}))[oi.ISO_8859_1=0]="ISO_8859_1",oi[oi.UTF_16_WITH_BOM=1]="UTF_16_WITH_BOM",oi[oi.UTF_16_BE_NO_BOM=2]="UTF_16_BE_NO_BOM",oi[oi.UTF_8=3]="UTF_8";const li=128,ci=["Blues","Classic rock","Country","Dance","Disco","Funk","Grunge","Hip-hop","Jazz","Metal","New age","Oldies","Other","Pop","Rhythm and blues","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death metal","Pranks","Soundtrack","Euro-techno","Ambient","Trip-hop","Vocal","Jazz & funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound clip","Gospel","Noise","Alternative rock","Bass","Soul","Punk","Space","Meditative","Instrumental pop","Instrumental rock","Ethnic","Gothic","Darkwave","Techno-industrial","Electronic","Pop-folk","Eurodance","Dream","Southern rock","Comedy","Cult","Gangsta","Top 40","Christian rap","Pop/funk","Jungle music","Native US","Cabaret","New wave","Psychedelic","Rave","Showtunes","Trailer","Lo-fi","Tribal","Acid punk","Acid jazz","Polka","Retro","Musical","Rock 'n' roll","Hard rock","Folk","Folk rock","National folk","Swing","Fast fusion","Bebop","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic rock","Progressive rock","Psychedelic rock","Symphonic rock","Slow rock","Big band","Chorus","Easy listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber music","Sonata","Symphony","Booty bass","Primus","Porn groove","Satire","Slow jam","Club","Tango","Samba","Folklore","Ballad","Power ballad","Rhythmic Soul","Freestyle","Duet","Punk rock","Drum solo","A cappella","Euro-house","Dance hall","Goa music","Drum & bass","Club-house","Hardcore techno","Terror","Indie","Britpop","Negerpunk","Polsk punk","Beat","Christian gangsta rap","Heavy metal","Black metal","Crossover","Contemporary Christian","Christian rock","Merengue","Salsa","Thrash metal","Anime","Jpop","Synthpop","Christmas","Art rock","Baroque","Bhangra","Big beat","Breakbeat","Chillout","Downtempo","Dub","EBM","Eclectic","Electro","Electroclash","Emo","Experimental","Garage","Global","IDM","Illbient","Industro-Goth","Jam Band","Krautrock","Leftfield","Lounge","Math rock","New romantic","Nu-breakz","Post-punk","Post-rock","Psytrance","Shoegaze","Space rock","Trop rock","World music","Neoclassical","Audiobook","Audio theatre","Neue Deutsche Welle","Podcast","Indie rock","G-Funk","Dubstep","Garage rock","Psybient"],ui=(e,t)=>{const r=Tn(e,t),i=ce(r.indexOf(0),r.length),n=r.subarray(0,i);let s="";for(let a=0;a{const t=e.filePos,r=Nn(e,3),i=Sn(e),n=Sn(e),s=Sn(e),a=Cn(e);if("ID3"!==r||255===i||255===n||0!==(2155905152&a))return e.filePos=t,null;return{majorVersion:i,revision:n,flags:s,size:ii(a)}},hi=(e,t,r)=>{var i,n,s,a;if(![2,3,4].includes(t.majorVersion))return void console.warn(`Unsupported ID3v2 major version: ${t.majorVersion}`);const o=Tn(e,t.size),l=new mi(t,o);if(t.flags&ni.Footer&&l.removeFooter(),t.flags&ni.Unsynchronisation&&3===t.majorVersion&&l.ununsynchronizeAll(),t.flags&ni.ExtendedHeader){const e=l.readU32();3===t.majorVersion?l.pos+=e:l.pos+=e-4}for(;l.pos<=l.bytes.length-l.frameHeaderSize();){const e=l.readId3V2Frame();if(!e)break;const o=l.pos,c=l.pos+e.size;let u=!1,d=!1,h=!1;if(3===t.majorVersion?(u=!!(64&e.flags),d=!!(128&e.flags)):4===t.majorVersion&&(u=!!(4&e.flags),d=!!(8&e.flags),h=!!(2&e.flags)||!!(t.flags&ni.Unsynchronisation)),u)console.warn(`Skipping encrypted ID3v2 frame ${e.id}`),l.pos=c;else if(d)console.warn(`Skipping compressed ID3v2 frame ${e.id}`),l.pos=c;else{switch(h&&l.ununsynchronizeRegion(l.pos,c),null!=r.raw||(r.raw={}),"T"===e.id[0]?null!=(i=r.raw)[n=e.id]||(i[n]=l.readId3V2EncodingAndText(c)):null!=(s=r.raw)[a=e.id]||(s[a]=l.readBytes(e.size)),l.pos=o,e.id){case"TIT2":case"TT2":null!=r.title||(r.title=l.readId3V2EncodingAndText(c));break;case"TIT3":case"TT3":null!=r.description||(r.description=l.readId3V2EncodingAndText(c));break;case"TPE1":case"TP1":null!=r.artist||(r.artist=l.readId3V2EncodingAndText(c));break;case"TALB":case"TAL":null!=r.album||(r.album=l.readId3V2EncodingAndText(c));break;case"TPE2":case"TP2":null!=r.albumArtist||(r.albumArtist=l.readId3V2EncodingAndText(c));break;case"TRCK":case"TRK":{const e=l.readId3V2EncodingAndText(c).split("/"),t=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(null!=r.trackNumber||(r.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&(null!=r.tracksTotal||(r.tracksTotal=i))}break;case"TPOS":case"TPA":{const e=l.readId3V2EncodingAndText(c).split("/"),t=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(null!=r.discNumber||(r.discNumber=t)),i&&Number.isInteger(i)&&i>0&&(null!=r.discsTotal||(r.discsTotal=i))}break;case"TCON":case"TCO":{const e=l.readId3V2EncodingAndText(c);let t=/^\((\d+)\)/.exec(e);if(t){const e=Number.parseInt(t[1]);if(void 0!==ci[e]){null!=r.genre||(r.genre=ci[e]);break}}if(t=/^\d+$/.exec(e),t){const e=Number.parseInt(t[0]);if(void 0!==ci[e]){null!=r.genre||(r.genre=ci[e]);break}}null!=r.genre||(r.genre=e)}break;case"TDRC":case"TDAT":{const e=l.readId3V2EncodingAndText(c),t=new Date(e);Number.isNaN(t.getTime())||null!=r.date||(r.date=t)}break;case"TYER":case"TYE":{const e=l.readId3V2EncodingAndText(c),t=Number.parseInt(e,10);Number.isInteger(t)&&(null!=r.date||(r.date=new Date(t,0,1)))}break;case"USLT":case"ULT":{const e=l.readU8();l.pos+=3,l.readId3V2Text(e,c),null!=r.lyrics||(r.lyrics=l.readId3V2Text(e,c))}break;case"COMM":case"COM":{const e=l.readU8();l.pos+=3,l.readId3V2Text(e,c),null!=r.comment||(r.comment=l.readId3V2Text(e,c))}break;case"APIC":case"PIC":{const e=l.readId3V2TextEncoding();let i;if(2===t.majorVersion){const e=l.readAscii(3);i="PNG"===e?"image/png":"JPG"===e?"image/jpeg":"image/*"}else i=l.readId3V2Text(e,c);const n=l.readU8(),s=l.readId3V2Text(e,c).trimEnd(),a=c-l.pos;if(a>=0){const e=l.readBytes(a);r.images||(r.images=[]),r.images.push({data:e,mimeType:i,kind:3===n?"coverFront":4===n?"coverBack":"unknown",description:s})}}break;default:l.pos+=e.size}l.pos=c}}};class mi{constructor(e,t){this.header=e,this.bytes=t,this.pos=0,this.view=new DataView(t.buffer,t.byteOffset,t.byteLength)}frameHeaderSize(){return 2===this.header.majorVersion?6:10}ununsynchronizeAll(){const e=[];for(let t=0;t{const t=this.pos+e;if(t>this.bytes.length)return!1;if(t<=this.bytes.length-this.frameHeaderSize()){this.pos+=e;const t=this.readAscii(4);if("\0\0\0\0"!==t&&!/[0-9A-Z]{4}/.test(t))return!1}return!0};if(!s(r)){const e=4===this.header.majorVersion?t:ii(t);s(e)&&(r=e)}return this.pos=n,{id:e,size:r,flags:i}}}readId3V2TextEncoding(){const e=this.readU8();if(e>3)throw new Error(`Unsupported text encoding: ${e}`);return e}readId3V2Text(e,t){const r=this.pos,i=this.readBytes(t-this.pos);switch(e){case ai.ISO_8859_1:{let e="";for(let t=0;t0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(2,t))}if(254===i[0]&&255===i[1]){const e=new TextDecoder("utf-16be"),t=ce(i.findIndex((e,t)=>0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(2,t))}{const e=ce(i.findIndex(e=>0===e),i.length);return this.pos=r+Math.min(e+1,i.length),w.decode(i.subarray(0,e))}case ai.UTF_16_BE_NO_BOM:{const e=new TextDecoder("utf-16be"),t=ce(i.findIndex((e,t)=>0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(0,t))}case ai.UTF_8:{const e=ce(i.findIndex(e=>0===e),i.length);return this.pos=r+Math.min(e+1,i.length),w.decode(i.subarray(0,e))}}}readId3V2EncodingAndText(e){if(this.pos>=e)return"";const t=this.readId3V2TextEncoding();return this.readId3V2Text(t,e)}}const fi=(e,t,r)=>u(null,null,function*(){let i=t;for(;null===r||iu(this,null,function*(){for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)yield this.advanceReader();if(!this.firstFrameHeader)throw new Error("No valid MP3 frame found.");this.tracks=[new Xt(this.input,new gi(this))]}))()})}advanceReader(){return u(this,null,function*(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,10);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=di(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}const e=yield fi(this.reader,this.lastLoadedPos,this.reader.fileSize);if(!e)return void(this.lastSampleLoaded=!0);const t=e.header;this.lastLoadedPos=e.startPos+t.totalSize-1;const r=(i=t.mpegVersionId,n=t.channel,3===i?3===n?21:36:3===n?13:21);var i,n;let s=this.reader.requestSlice(e.startPos+r,4);if(s instanceof Promise&&(s=yield s),s){const e=Cn(s);if(1483304551===e||1231971951===e)return}this.firstFrameHeader||(this.firstFrameHeader=t),t.sampleRate!==this.firstFrameHeader.sampleRate&&console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${t.sampleRate} Hz. Might be a bug, so please report this file.`);const a=t.audioSamplesInFrame/this.firstFrameHeader.sampleRate,o={timestamp:this.nextTimestampInSamples/this.firstFrameHeader.sampleRate,duration:a,dataStart:e.startPos,dataSize:t.totalSize};this.loadedSamples.push(o),this.nextTimestampInSamples+=t.audioSamplesInFrame})}getMimeType(){return u(this,null,function*(){return"audio/mpeg"})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks})}computeDuration(){return u(this,null,function*(){yield this.readMetadata();const e=this.tracks[0];return p(e),e.computeDuration()})}getMetadataTags(){return u(this,null,function*(){const e=yield this.readingMutex.acquire();try{if(yield this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0,t=!1;for(;;){let r=this.reader.requestSlice(e,10);if(r instanceof Promise&&(r=yield r),!r)break;const i=di(r);if(!i)break;t=!0;let n=this.reader.requestSlice(r.filePos,i.size);if(n instanceof Promise&&(n=yield n),!n)break;hi(n,i,this.metadataTags),e=r.filePos+i.size}if(!t&&null!==this.reader.fileSize&&this.reader.fileSize>=li){let e=this.reader.requestSlice(this.reader.fileSize-li,li);e instanceof Promise&&(e=yield e),p(e);"TAG"===Nn(e,3)&&((e,t)=>{var r;const i=e.filePos;null!=t.raw||(t.raw={}),null!=(r=t.raw).TAG||(r.TAG=Tn(e,125)),e.filePos=i;const n=ui(e,30);n&&(null!=t.title||(t.title=n));const s=ui(e,30);s&&(null!=t.artist||(t.artist=s));const a=ui(e,30);a&&(null!=t.album||(t.album=a));const o=ui(e,4),l=Number.parseInt(o,10);Number.isInteger(l)&&l>0&&(null!=t.date||(t.date=new Date(l,0,1)));const c=Tn(e,30);let u;if(0===c[28]&&0!==c[29]){const r=c[29];r>0&&(null!=t.trackNumber||(t.trackNumber=r)),e.skip(-30),u=ui(e,28),e.skip(2)}else e.skip(-30),u=ui(e,30);u&&(null!=t.comment||(t.comment=u));const d=Sn(e);de.timestamp);if(-1===r)throw new Error("Packet was not created from this track.");const i=r+1;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{r()}})}getPacket(e,t){return u(this,null,function*(){const r=yield this.demuxer.readingMutex.acquire();try{for(;;){const r=N(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===r&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(r,t);if(r>=0&&r+1>>0&4294967295}const yi=e=>{const t=v(e),r=t.getUint32(22,!0);t.setUint32(22,0,!0);let i=0;for(let n=0;n>>24^t])>>>0}return t.setUint32(22,r,!0),i},Ti=(e,t,r)=>{let i=0,n=null;if(e.length>0)if("vorbis"===t.codec){p(t.vorbisInfo);const s=(1<<(e=>{let t=0;for(;e;)t++,e>>=1;return t})(t.vorbisInfo.modeBlockflags.length-1))-1<<1,a=(e[0]&s)>>1;if(a>=t.vorbisInfo.modeBlockflags.length)throw new Error("Invalid mode number.");let o=r;const l=t.vorbisInfo.modeBlockflags[a];if(n=t.vorbisInfo.blocksizes[l],1===l){const r=1+(1|s),i=e[0]&r?1:0;o=t.vorbisInfo.blocksizes[i]}i=null!==o?o+n>>2:0}else if("opus"===t.codec){i=(e=>{const t=e[0]>>3;return{durationInSamples:tt[t]}})(e).durationInSamples}return{durationInSamples:i,vorbisBlockSize:n}},Si=27,vi=282,wi=e=>{const t=e.filePos;if(_n(e)!==ki)return null;e.skip(1);const r=Sn(e),i=An(e),n=_n(e),s=_n(e),a=_n(e),o=Sn(e),l=new Uint8Array(o);for(let d=0;de+t,0);return{headerStartPos:t,totalSize:c+u,dataStartPos:t+c,dataSize:u,headerType:r,granulePosition:i,serialNumber:n,sequenceNumber:s,checksum:a,lacingValues:l}},Ii=(e,t)=>{for(;e.filePos>>8&255)===r||(t>>>16&255)===r||(t>>>24&255)===r){if(e.skip(-4),t===ki)return!0;e.skip(1)}}return!1};class Pi extends ot{constructor(e){super(e),this.metadataPromise=null,this.bitstreams=[],this.tracks=[],this.metadataTags={},this.reader=e._reader}readMetadata(){return u(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>u(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,Si,vi);if(t instanceof Promise&&(t=yield t),!t)break;const r=wi(t);if(!r)break;if(!!!(2&r.headerType))break;this.bitstreams.push({serialNumber:r.serialNumber,bosPage:r,description:null,numberOfChannels:-1,sampleRate:-1,codecInfo:{codec:null,vorbisInfo:null,opusInfo:null},lastMetadataPacket:null}),e=r.headerStartPos+r.totalSize}for(const t of this.bitstreams){const e=yield this.readPacket(t.bosPage,0);e&&(e.data.byteLength>=7&&1===e.data[0]&&118===e.data[1]&&111===e.data[2]&&114===e.data[3]&&98===e.data[4]&&105===e.data[5]&&115===e.data[6]?yield this.readVorbisMetadata(e,t):e.data.byteLength>=8&&79===e.data[0]&&112===e.data[1]&&117===e.data[2]&&115===e.data[3]&&72===e.data[4]&&101===e.data[5]&&97===e.data[6]&&100===e.data[7]&&(yield this.readOpusMetadata(e,t)),null!==t.codecInfo.codec&&this.tracks.push(new Xt(this.input,new xi(t,this))))}}))()})}readVorbisMetadata(e,t){return u(this,null,function*(){let r=yield this.findNextPacketStart(e);if(!r)return;const i=yield this.readPacket(r.startPage,r.startSegmentIndex);if(!i)return;if(r=yield this.findNextPacketStart(i),!r)return;const n=yield this.readPacket(r.startPage,r.startSegmentIndex);if(!n)return;if(3!==i.data[0]||5!==n.data[0])return;const s=[],a=e=>{for(;s.push(Math.min(255,e)),!(e<255);)e-=255};a(e.data.length),a(i.data.length);const o=new Uint8Array(1+s.length+e.data.length+i.data.length+n.data.length);o[0]=2,o.set(s,1),o.set(e.data,1+s.length),o.set(i.data,1+s.length+e.data.length),o.set(n.data,1+s.length+e.data.length+i.data.length),t.codecInfo.codec="vorbis",t.description=o,t.lastMetadataPacket=n;const l=v(e.data);t.numberOfChannels=l.getUint8(11),t.sampleRate=l.getUint32(12,!0);const c=l.getUint8(28);t.codecInfo.vorbisInfo={blocksizes:[1<<(15&c),1<<(c>>4)],modeBlockflags:rt(n.data).modeBlockflags},at(i.data.subarray(7),this.metadataTags)})}readOpusMetadata(e,t){return u(this,null,function*(){const r=yield this.findNextPacketStart(e);if(!r)return;const i=yield this.readPacket(r.startPage,r.startSegmentIndex);if(!i)return;t.codecInfo.codec="opus",t.description=e.data,t.lastMetadataPacket=i;const n=(e=>{const t=v(e),r=t.getUint8(9),i=t.getUint16(10,!0),n=t.getUint32(12,!0),s=t.getInt16(16,!0),a=t.getUint8(18);let o=null;return a&&(o=e.subarray(19,21+r)),{outputChannelCount:r,preSkip:i,inputSampleRate:n,outputGain:s,channelMappingFamily:a,channelMappingTable:o}})(e.data);t.numberOfChannels=n.outputChannelCount,t.sampleRate=xe,t.codecInfo.opusInfo={preSkip:n.preSkip},at(i.data.subarray(8),this.metadataTags)})}readPacket(e,t){return u(this,null,function*(){p(te+t.length,0);if(0===o)return null;const l=new Uint8Array(o);let c=0;for(let e=0;e{let t="audio/ogg";e.codecStrings&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({codecStrings:(yield Promise.all(this.tracks.map(e=>e.getCodecParameterString()))).filter(Boolean)})})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks})}computeDuration(){return u(this,null,function*(){const e=yield this.getTracks(),t=yield Promise.all(e.map(e=>e.computeDuration()));return Math.max(0,...t)})}getMetadataTags(){return u(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}}class xi{constructor(e,t){this.bitstream=e,this.demuxer=t,this.encodedPacketToMetadata=new WeakMap,this.sequentialScanCache=[],this.sequentialScanMutex=new D,this.internalSampleRate="opus"===e.codecInfo.codec?xe:e.sampleRate}getId(){return this.bitstream.serialNumber}getNumberOfChannels(){return this.bitstream.numberOfChannels}getSampleRate(){return this.bitstream.sampleRate}getTimeResolution(){return this.bitstream.sampleRate}getCodec(){return this.bitstream.codecInfo.codec}getInternalCodecId(){return null}getDecoderConfig(){return u(this,null,function*(){var e;return p(this.bitstream.codecInfo.codec),{codec:this.bitstream.codecInfo.codec,numberOfChannels:this.bitstream.numberOfChannels,sampleRate:this.bitstream.sampleRate,description:null!=(e=this.bitstream.description)?e:void 0}})}getName(){return null}getLanguageCode(){return $}getDisposition(){return c({},ge)}getFirstTimestamp(){return u(this,null,function*(){return 0})}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}granulePositionToTimestampInSamples(e){return"opus"===this.bitstream.codecInfo.codec?(p(this.bitstream.codecInfo.opusInfo),e-this.bitstream.codecInfo.opusInfo.preSkip):e}createEncodedPacketFromOggPacket(e,t,r){if(!e)return null;const{durationInSamples:i,vorbisBlockSize:n}=Ti(e.data,this.bitstream.codecInfo,t.vorbisLastBlocksize),s=new dt(r.metadataOnly?ut:e.data,"key",Math.max(0,t.timestampInSamples)/this.internalSampleRate,i/this.internalSampleRate,e.endPage.headerStartPos+e.endSegmentIndex,e.data.byteLength);return this.encodedPacketToMetadata.set(s,{packet:e,timestampInSamples:t.timestampInSamples,durationInSamples:i,vorbisLastBlockSize:t.vorbisLastBlocksize,vorbisBlockSize:n}),s}getFirstPacket(e){return u(this,null,function*(){p(this.bitstream.lastMetadataPacket);const t=yield this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!t)return null;let r=0;"opus"===this.bitstream.codecInfo.codec&&(p(this.bitstream.codecInfo.opusInfo),r-=this.bitstream.codecInfo.opusInfo.preSkip);const i=yield this.demuxer.readPacket(t.startPage,t.startSegmentIndex);return this.createEncodedPacketFromOggPacket(i,{timestampInSamples:r,vorbisLastBlocksize:null},e)})}getNextPacket(e,t){return u(this,null,function*(){const r=this.encodedPacketToMetadata.get(e);if(!r)throw new Error("Packet was not created from this track.");const i=yield this.demuxer.findNextPacketStart(r.packet);if(!i)return null;const n=r.timestampInSamples+r.durationInSamples,s=yield this.demuxer.readPacket(i.startPage,i.startSegmentIndex);return this.createEncodedPacketFromOggPacket(s,{timestampInSamples:n,vorbisLastBlocksize:r.vorbisBlockSize},t)})}getPacket(e,t){return u(this,null,function*(){var r,i;if(null===this.demuxer.reader.fileSize)return this.getPacketSequential(e,t);const n=Q(e*this.internalSampleRate);if(0===n)return this.getFirstPacket(t);if(n<0)return null;p(this.bitstream.lastMetadataPacket);const s=yield this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!s)return null;let a=s.startPage,o=this.demuxer.reader.fileSize;const l=[a];e:for(;a.headerStartPos+a.totalSizen?o=c.headerStartPos:(a=c,l.push(c));continue e}r=c.headerStartPos+c.totalSize}}let c=s.startPage;for(const e of l){if(e.granulePosition===a.granulePosition)break;(!c||e.headerStartPos>c.headerStartPos)&&(c=e)}let u=c;const d=[u];for(;u.serialNumber!==this.bitstream.serialNumber||u.granulePosition!==a.granulePosition;){const e=u.headerStartPos+u.totalSize;let t=this.demuxer.reader.requestSliceRange(e,Si,vi);t instanceof Promise&&(t=yield t),p(t);const r=wi(t);p(r),u=r,u.serialNumber===this.bitstream.serialNumber&&d.push(u)}p(-1!==u.granulePosition);let h,m,f=null,g=u,k=0;if(u.headerStartPos===s.startPage.headerStartPos)h=this.granulePositionToTimestampInSamples(0),m=!0,f=0;else{h=0,m=!1;for(let t=u.lacingValues.length-1;t>=0;t--){if(u.lacingValues[t]<255){f=t+1;break}}if(null===f)throw new Error("Invalid page with granule position: no packets end on this page.");k=f-1;const e={data:ut,endPage:g,endSegmentIndex:k};if(yield this.demuxer.findNextPacketStart(e)){const e=_i(d,u,f);p(e);const t=Ci(d,e.page,e.segmentIndex);t&&(u=t.page,f=t.segmentIndex)}else for(;;){const e=_i(d,u,f);if(!e)break;const t=Ci(d,e.page,e.segmentIndex);if(!t)break;if(u=t.page,f=t.segmentIndex,e.page.headerStartPos!==g.headerStartPos){g=e.page,k=e.segmentIndex;break}}}let b=null,y=null;for(;null!==u;){p(null!==f);const e=yield this.demuxer.readPacket(u,f);if(!e)break;if(!(u.headerStartPos===s.startPage.headerStartPos&&fn||Math.max(a.timestampInSamples,0)===n))break}const a=yield this.demuxer.findNextPacketStart(e);if(!a)break;u=a.startPage,f=a.startSegmentIndex}return b})}getPacketSequential(e,t){return u(this,null,function*(){const r=yield this.sequentialScanMutex.acquire();try{const r=Q(e*this.internalSampleRate);e=r/this.internalSampleRate;const i=N(this.sequentialScanCache,r,e=>e.timestampInSamples);let n;if(-1!==i){const e=this.sequentialScanCache[i];n=this.createEncodedPacketFromOggPacket(e.packet,{timestampInSamples:e.timestampInSamples,vorbisLastBlocksize:e.vorbisLastBlockSize},t)}else n=yield this.getFirstPacket(t);let s=0;for(;n&&n.timestampe)break;if(n=r,s++,100===s){s=0;const e=this.encodedPacketToMetadata.get(n);p(e),this.sequentialScanCache.length>0&&p(k(this.sequentialScanCache).timestampInSamples<=e.timestampInSamples),this.sequentialScanCache.push(e)}}return n}finally{r()}})}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Ci=(e,t,r)=>{let i=t,n=r;e:for(;;){for(n--;n>=0;n--){if(i.lacingValues[n]<255){n++;break e}}p(-1===n);if(!(1&i.headerType)){n=0;break}const t=L(e,e=>e.headerStartPos{if(r>0)return{page:t,segmentIndex:r-1};const i=L(e,e=>e.headerStartPosu(this,null,function*(){var e,t;let r=this.reader.requestSlice(0,12);r instanceof Promise&&(r=yield r),p(r);const i=Nn(r,4),n="RIFX"!==i,s="RF64"===i,a=xn(r,n);let o=s?this.reader.fileSize:Math.min(a+8,null!=(e=this.reader.fileSize)?e:1/0);if("WAVE"!==Nn(r,4))throw new Error("Invalid WAVE file - wrong format");let l=0,c=null,u=r.filePos;for(;null===o||u=18&&357!==n){const e=vn(i,r),s=t-18;if(Math.min(s,e)>=22&&n===Bi.EXTENSIBLE){i.skip(6);const e=Tn(i,16);n=e[0]|e[1]<<8}}n!==Bi.MULAW&&n!==Bi.ALAW||(l=8),this.audioInfo={format:n,numberOfChannels:s,sampleRate:a,sampleSizeInBytes:Math.ceil(l/8),blockSizeInBytes:o}})}parseListChunk(e,t,r){return u(this,null,function*(){var i,n,s,a,o,l,c,u,d,h,m;let f=this.reader.requestSlice(e,t);if(f instanceof Promise&&(f=yield f),!f)return;const p=Nn(f,4);if("INFO"!==p&&"INF0"!==p)return;let g=f.filePos;for(;g<=e+t-8;){f.filePos=g;const e=Nn(f,4),t=xn(f,r),p=Tn(f,t);let k=0;for(let r=0;r0&&(null!=(l=this.metadataTags).trackNumber||(l.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&(null!=(c=this.metadataTags).tracksTotal||(c.tracksTotal=r))}break;case"ICRD":case"IDIT":{const e=new Date(b);Number.isNaN(e.getTime())||null!=(u=this.metadataTags).date||(u.date=e)}break;case"YEAR":{const e=Number.parseInt(b,10);Number.isInteger(e)&&e>0&&(null!=(d=this.metadataTags).date||(d.date=new Date(e,0,1)))}break;case"IGNR":case"GENR":null!=(h=this.metadataTags).genre||(h.genre=b);break;case"ICMT":case"CMNT":case"COMM":null!=(m=this.metadataTags).comment||(m.comment=b)}g+=8+t+(1&t)}})}parseId3Chunk(e,t){return u(this,null,function*(){let r=this.reader.requestSlice(e,t);if(r instanceof Promise&&(r=yield r),!r)return;const i=di(r);if(i){const t=r.slice(e+10,i.size);hi(t,i,this.metadataTags)}})}getCodec(){if(p(this.audioInfo),this.audioInfo.format===Bi.MULAW)return"ulaw";if(this.audioInfo.format===Bi.ALAW)return"alaw";if(this.audioInfo.format===Bi.PCM){if(1===this.audioInfo.sampleSizeInBytes)return"pcm-u8";if(2===this.audioInfo.sampleSizeInBytes)return"pcm-s16";if(3===this.audioInfo.sampleSizeInBytes)return"pcm-s24";if(4===this.audioInfo.sampleSizeInBytes)return"pcm-s32"}return this.audioInfo.format===Bi.IEEE_FLOAT&&4===this.audioInfo.sampleSizeInBytes?"pcm-f32":null}getMimeType(){return u(this,null,function*(){return"audio/wav"})}computeDuration(){return u(this,null,function*(){yield this.readMetadata();const e=this.tracks[0];return p(e),e.computeDuration()})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks})}getMetadataTags(){return u(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}}const Di=2048;class Ai{constructor(e){this.demuxer=e}getId(){return 1}getCodec(){return this.demuxer.getCodec()}getInternalCodecId(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.format}getDecoderConfig(){return u(this,null,function*(){const e=this.demuxer.getCodec();return e?(p(this.demuxer.audioInfo),{codec:e,numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate}):null})}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getNumberOfChannels(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getTimeResolution(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return $}getDisposition(){return c({},ge)}getFirstTimestamp(){return u(this,null,function*(){return 0})}getPacketAtIndex(e,t){return u(this,null,function*(){p(this.demuxer.audioInfo);const r=e*Di*this.demuxer.audioInfo.blockSizeInBytes;if(r>=this.demuxer.dataSize)return null;const i=Math.min(Di*this.demuxer.audioInfo.blockSizeInBytes,this.demuxer.dataSize-r);if(null===this.demuxer.reader.fileSize){let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+r,i);if(e instanceof Promise&&(e=yield e),!e)return null}let n;if(t.metadataOnly)n=ut;else{let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+r,i);e instanceof Promise&&(e=yield e),p(e),n=Tn(e,i)}const s=e*Di/this.demuxer.audioInfo.sampleRate,a=i/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate;return this.demuxer.lastKnownPacketIndex=Math.max(e,s),new dt(n,"key",s,a,e,i)})}getFirstPacket(e){return this.getPacketAtIndex(0,e)}getPacket(e,t){return u(this,null,function*(){p(this.demuxer.audioInfo);const r=Math.floor(Math.min(e*this.demuxer.audioInfo.sampleRate/Di,(this.demuxer.dataSize-1)/(Di*this.demuxer.audioInfo.blockSizeInBytes))),i=yield this.getPacketAtIndex(r,t);if(i)return i;if(0===r)return null;p(null===this.demuxer.reader.fileSize);let n=yield this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex,t);for(;n;){const e=yield this.getNextPacket(n,t);if(!e)break;n=e}return n})}getNextPacket(e,t){p(this.demuxer.audioInfo);const r=Math.round(e.timestamp*this.demuxer.audioInfo.sampleRate/Di);return this.getPacketAtIndex(r+1,t)}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Ri=e=>{const t=e.filePos,r=Tn(e,9),i=new b(r);if(4095!==i.readBits(12))return null;i.skipBits(1);if(0!==i.readBits(2))return null;const n=i.readBits(1),s=i.readBits(2)+1,a=i.readBits(4);if(15===a)return null;i.skipBits(1);const o=i.readBits(3);if(0===o)throw new Error("ADTS frames with channel configuration 0 are not supported.");i.skipBits(1),i.skipBits(1),i.skipBits(1),i.skipBits(1);const l=i.readBits(13);i.skipBits(11);const c=i.readBits(2)+1;if(1!==c)throw new Error("ADTS frames with more than one AAC frame are not supported.");let u=null;return 1===n?e.filePos-=2:u=i.readBits(16),{objectType:s,samplingFrequencyIndex:a,channelConfiguration:o,frameLength:l,numberOfAacFrames:c,crcCheck:u,startPos:t}},Mi=1024;class Ni extends ot{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.loadedSamples=[],this.tracks=[],this.readingMutex=new D,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}readMetadata(){return u(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>u(this,null,function*(){for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)yield this.advanceReader();p(this.firstFrameHeader),this.tracks=[new Xt(this.input,new zi(this))]}))()})}advanceReader(){return u(this,null,function*(){let e=this.reader.requestSliceRange(this.lastLoadedPos,7,9);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=Ri(e);if(!t)return void(this.lastSampleLoaded=!0);if(null!==this.reader.fileSize&&t.startPos+t.frameLength>this.reader.fileSize)return void(this.lastSampleLoaded=!0);this.firstFrameHeader||(this.firstFrameHeader=t);const r=we[t.samplingFrequencyIndex];p(void 0!==r);const i=Mi/r,n=t.crcCheck?9:7,s={timestamp:this.nextTimestampInSamples/r,duration:i,dataStart:t.startPos+n,dataSize:t.frameLength-n};this.loadedSamples.push(s),this.nextTimestampInSamples+=Mi,this.lastLoadedPos=t.startPos+t.frameLength})}getMimeType(){return u(this,null,function*(){return"audio/aac"})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks})}computeDuration(){return u(this,null,function*(){yield this.readMetadata();const e=this.tracks[0];return p(e),e.computeDuration()})}getMetadataTags(){return u(this,null,function*(){return{}})}}class zi{constructor(e){this.demuxer=e}getId(){return 1}getFirstTimestamp(){return u(this,null,function*(){return 0})}getTimeResolution(){return this.getSampleRate()/Mi}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getName(){return null}getLanguageCode(){return $}getCodec(){return"aac"}getInternalCodecId(){return p(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.objectType}getNumberOfChannels(){p(this.demuxer.firstFrameHeader);const e=Ie[this.demuxer.firstFrameHeader.channelConfiguration];return p(void 0!==e),e}getSampleRate(){p(this.demuxer.firstFrameHeader);const e=we[this.demuxer.firstFrameHeader.samplingFrequencyIndex];return p(void 0!==e),e}getDisposition(){return c({},ge)}getDecoderConfig(){return u(this,null,function*(){p(this.demuxer.firstFrameHeader);const e=new Uint8Array(3),t=new b(e),{objectType:r,samplingFrequencyIndex:i,channelConfiguration:n}=this.demuxer.firstFrameHeader;return r>31?(t.writeBits(5,31),t.writeBits(6,r-32)):t.writeBits(5,r),t.writeBits(4,i),t.writeBits(4,n),{codec:`mp4a.40.${this.demuxer.firstFrameHeader.objectType}`,numberOfChannels:this.getNumberOfChannels(),sampleRate:this.getSampleRate(),description:e.subarray(0,Math.ceil((t.pos-1)/8))}})}getPacketAtIndex(e,t){return u(this,null,function*(){if(-1===e)return null;const r=this.demuxer.loadedSamples[e];if(!r)return null;let i;if(t.metadataOnly)i=ut;else{let e=this.demuxer.reader.requestSlice(r.dataStart,r.dataSize);if(e instanceof Promise&&(e=yield e),!e)return null;i=Tn(e,r.dataSize)}return new dt(i,"key",r.timestamp,r.duration,e,r.dataSize)})}getFirstPacket(e){return this.getPacketAtIndex(0,e)}getNextPacket(e,t){return u(this,null,function*(){const r=yield this.demuxer.readingMutex.acquire();try{const r=M(this.demuxer.loadedSamples,e.timestamp,e=>e.timestamp);if(-1===r)throw new Error("Packet was not created from this track.");const i=r+1;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{r()}})}getPacket(e,t){return u(this,null,function*(){const r=yield this.demuxer.readingMutex.acquire();try{for(;;){const r=N(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===r&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(r,t);if(r>=0&&r+1u(this,null,function*(){for(var e;null===this.reader.fileSize||ti.end-6)return{num:n.num,blockSize:n.blockSize,sampleRate:n.sampleRate,size:i.end-e,isLastFrame:!0};if(255===Sn(i)){const t=i.filePos;if(Sn(i)!==(1===this.blockingBit?249:248)){i.filePos=t;continue}i.skip(-2);const r=i.filePos-e,s=this.readFlacFrameHeader({slice:i,isFirstPacket:!1});if(!s){i.filePos=t;continue}if(0===this.blockingBit){if(s.num-n.num!==1){i.filePos=t;continue}}else if(s.num-n.num!==n.blockSize){i.filePos=t;continue}return{num:n.num,blockSize:n.blockSize,sampleRate:n.sampleRate,size:r,isLastFrame:!1}}}})}readFlacFrameHeader({slice:e,isFirstPacket:t}){const r=e.filePos,i=Tn(e,4),n=new b(i);if(32764!==n.readBits(15))return null;if(null===this.blockingBit){p(t);const e=n.readBits(1);this.blockingBit=e}else if(1===this.blockingBit){p(!t);if(1!==n.readBits(1))return null}else{if(0!==this.blockingBit)throw new Error("Invalid blocking bit");p(!t);if(0!==n.readBits(1))return null}const s=(e=>0===e?null:1===e?192:e>=2&&e<=5?144*o(2,e):6===e?"uncommon-u8":7===e?"uncommon-u16":e>=8&&e<=15?o(2,e):null)(n.readBits(4));if(!s)return null;p(this.audioInfo);const a=((e,t)=>{switch(e){case 0:return t;case 1:return 88200;case 2:return 176400;case 3:return 192e3;case 4:return 8e3;case 5:return 16e3;case 6:return 22050;case 7:return 24e3;case 8:return 32e3;case 9:return 44100;case 10:return 48e3;case 11:return 96e3;case 12:return"uncommon-u8";case 13:return"uncommon-u16";case 14:return"uncommon-u16-10";default:return null}})(n.readBits(4),this.audioInfo.sampleRate);if(!a)return null;n.readBits(4),n.readBits(3);if(0!==n.readBits(1))return null;const l=(e=>{let t=0;const r=new b(Tn(e,1));for(;1===r.readBits(1);)t++;if(0===t)return r.readBits(7);const i=[],n=t-1,s=new b(Tn(e,n)),a=8-t-1;for(let o=0;oe|t<"uncommon-u16"===t?wn(e)+1:"uncommon-u8"===t?Sn(e)+1:"number"===typeof t?t:(q(t),void p(!1)))(e,s),u=((e,t)=>"uncommon-u16"===t?wn(e):"uncommon-u16-10"===t?10*wn(e):"uncommon-u8"===t?Sn(e):"number"===typeof t?t:null)(e,a);if(null===u)return null;if(u!==this.audioInfo.sampleRate)return null;const d=e.filePos-r,h=Sn(e);e.skip(-d),e.skip(-1);const m=(e=>{let t=0;for(const r of e){t^=r;for(let e=0;e<8;e++)0!==(128&t)?t=t<<1^7:t<<=1,t&=255}return t})(Tn(e,d));return h!==m?null:{num:l,blockSize:c,sampleRate:u}}advanceReader(){return u(this,null,function*(){yield this.readMetadata(),p(null!==this.lastLoadedPos),p(this.audioInfo);const e=this.lastLoadedPos,t=yield this.readNextFlacFrame({startPos:e,isFirstPacket:0===this.loadedSamples.length});if(!t)return void(this.lastSampleLoaded=!0);const r=this.loadedSamples[this.loadedSamples.length-1],i={blockOffset:r?r.blockOffset+r.blockSize:0,blockSize:t.blockSize,byteOffset:e,byteSize:t.size};this.lastLoadedPos=this.lastLoadedPos+t.size,this.loadedSamples.push(i),t.isLastFrame&&(this.lastSampleLoaded=!0)})}}class Li{constructor(e){this.demuxer=e}getId(){return 1}getCodec(){return"flac"}getInternalCodecId(){return null}getNumberOfChannels(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getSampleRate(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return $}getTimeResolution(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getDisposition(){return c({},ge)}getFirstTimestamp(){return u(this,null,function*(){return 0})}getDecoderConfig(){return u(this,null,function*(){return p(this.demuxer.audioInfo),{codec:"flac",numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate,description:this.demuxer.audioInfo.description}})}getPacket(e,t){return u(this,null,function*(){if(p(this.demuxer.audioInfo),e<0)throw new Error("Timestamp cannot be negative");const r=yield this.demuxer.readingMutex.acquire();try{for(;;){const r=N(this.demuxer.loadedSamples,e,e=>e.blockOffset/this.demuxer.audioInfo.sampleRate);if(-1===r){yield this.demuxer.advanceReader();continue}const i=this.demuxer.loadedSamples[r],n=i.blockOffset/this.demuxer.audioInfo.sampleRate;if(!(n+i.blockSize/this.demuxer.audioInfo.sampleRate<=e))return this.getPacketAtIndex(r,t);if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(this.demuxer.loadedSamples.length-1,t);yield this.demuxer.advanceReader()}}finally{r()}})}getNextPacket(e,t){return u(this,null,function*(){const r=yield this.demuxer.readingMutex.acquire();try{const r=e.sequenceNumber+1;if(this.demuxer.lastSampleLoaded&&r>=this.demuxer.loadedSamples.length)return null;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{r()}})}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}getPacketAtIndex(e,t){return u(this,null,function*(){const r=this.demuxer.loadedSamples[e];if(!r)return null;let i;if(t.metadataOnly)i=ut;else{let e=this.demuxer.reader.requestSlice(r.byteOffset,r.byteSize);if(e instanceof Promise&&(e=yield e),!e)return null;i=Tn(e,r.byteSize)}p(this.demuxer.audioInfo);const n=r.blockOffset/this.demuxer.audioInfo.sampleRate,s=r.blockSize/this.demuxer.audioInfo.sampleRate;return new dt(i,"key",n,s,e,r.byteSize)})}getFirstPacket(e){return u(this,null,function*(){for(;0===this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(0,e)})}}class Ui{}class Vi extends Ui{_getMajorBrand(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=yield t),!t)return null;t.skip(4);return"ftyp"!==Nn(t,4)?null:Nn(t,4)})}_createDemuxer(e){return new ir(e)}}class qi extends Vi{_canReadInput(e){return u(this,null,function*(){const t=yield this._getMajorBrand(e);return!!t&&"qt "!==t})}get name(){return"MP4"}get mimeType(){return"video/mp4"}}class Hi extends Vi{_canReadInput(e){return u(this,null,function*(){return"qt "===(yield this._getMajorBrand(e))})}get name(){return"QuickTime File Format"}get mimeType(){return"video/quicktime"}}class Wi extends Ui{isSupportedEBMLOfDocType(e,t){return u(this,null,function*(){let r=e._reader.requestSlice(0,yr);if(r instanceof Promise&&(r=yield r),!r)return!1;const i=Tr(r);if(null===i)return!1;if(i<1||i>8)return!1;if(vr(r,i)!==fr.EBML)return!1;const n=Ir(r);if("number"!==typeof n)return!1;let s=e._reader.requestSlice(r.filePos,n);if(s instanceof Promise&&(s=yield s),!s)return!1;const a=r.filePos;for(;s.filePos<=a+n-2;){const e=Pr(s);if(!e)break;const{id:r,size:i}=e,n=s.filePos;if(void 0===i)return!1;switch(r){case fr.EBMLVersion:if(1!==vr(s,i))return!1;break;case fr.EBMLReadVersion:if(1!==vr(s,i))return!1;break;case fr.DocType:if(xr(s,i)!==t)return!1;break;case fr.DocTypeVersion:if(vr(s,i)>4)return!1}s.filePos=n+i}return!0})}_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"matroska")}_createDemuxer(e){return new Xr(e)}get name(){return"Matroska"}get mimeType(){return"video/x-matroska"}}class ji extends Wi{_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"webm")}get name(){return"WebM"}get mimeType(){return"video/webm"}}class Ki extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,10);if(t instanceof Promise&&(t=yield t),!t)return!1;let r=0,i=!1;for(;;){let t=e._reader.requestSlice(r,10);if(t instanceof Promise&&(t=yield t),!t)break;const n=di(t);if(!n)break;i=!0,r=t.filePos+n.size}const n=yield fi(e._reader,r,r+4096);if(!n)return!1;if(i)return!0;r=n.startPos+n.header.totalSize;const s=yield fi(e._reader,r,r+4);if(!s)return!1;const a=n.header,o=s.header;return a.channel===o.channel&&a.sampleRate===o.sampleRate})}_createDemuxer(e){return new pi(e)}get name(){return"MP3"}get mimeType(){return"audio/mpeg"}}class $i extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=yield t),!t)return!1;const r=Nn(t,4);if("RIFF"!==r&&"RIFX"!==r&&"RF64"!==r)return!1;t.skip(4);return"WAVE"===Nn(t,4)})}_createDemuxer(e){return new Fi(e)}get name(){return"WAVE"}get mimeType(){return"audio/wav"}}class Qi extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=yield t),!!t&&"OggS"===Nn(t,4)})}_createDemuxer(e){return new Pi(e)}get name(){return"Ogg"}get mimeType(){return"application/ogg"}}class Gi extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=yield t),!!t&&"fLaC"===Nn(t,4)})}get name(){return"FLAC"}get mimeType(){return"audio/flac"}_createDemuxer(e){return new Oi(e)}}class Xi extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSliceRange(0,7,9);if(t instanceof Promise&&(t=yield t),!t)return!1;const r=Ri(t);if(!r)return!1;if(t=e._reader.requestSliceRange(r.frameLength,7,9),t instanceof Promise&&(t=yield t),!t)return!1;const i=Ri(t);return!!i&&(r.objectType===i.objectType&&r.samplingFrequencyIndex===i.samplingFrequencyIndex&&r.channelConfiguration===i.channelConfiguration)})}_createDemuxer(e){return new Ni(e)}get name(){return"ADTS"}get mimeType(){return"audio/aac"}}const Yi=new qi,Ji=new Hi,Zi=new Wi,en=new ji,tn=new Ki,rn=new $i,nn=new Qi,sn=new Xi,an=[Yi,Ji,Zi,en,rn,nn,new Gi,tn,sn];class on{constructor(){this._disposed=!1,this._sizePromise=null,this.onread=null}getSizeOrNull(){return u(this,null,function*(){var e;if(this._disposed)throw new gn;return null!=(e=this._sizePromise)?e:this._sizePromise=Promise.resolve(this._retrieveSize())})}getSize(){return u(this,null,function*(){if(this._disposed)throw new gn;const e=yield this.getSizeOrNull();if(null===e)throw new Error("Cannot determine the size of an unsized source.");return e})}}class ln extends on{constructor(e,t={}){var r;if(!(e instanceof Blob))throw new TypeError("blob must be a Blob.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!me(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._readers=new WeakMap,this._blob=e,this._orchestrator=new fn({maxCacheSize:null!=(r=t.maxCacheSize)?r:8*o(2,20),maxWorkerCount:4,runWorker:this._runWorker.bind(this),prefetchProfile:mn.fileSystem})}_retrieveSize(){const e=this._blob.size;return this._orchestrator.fileSize=e,e}_read(e,t){return this._orchestrator.read(e,t)}_runWorker(e){return u(this,null,function*(){var t,r;let i=this._readers.get(e);if(void 0===i){if("stream"in this._blob&&!ie()){i=this._blob.slice(e.currentPos).stream().getReader()}else i=null;this._readers.set(e,i)}for(;e.currentPos{if(t instanceof Error&&(t.message.includes("Failed to fetch")||t.message.includes("Load failed")||t.message.includes("NetworkError when attempting to fetch resource"))){let e=null;try{"undefined"!==typeof window&&"undefined"!==typeof window.location&&(e=new URL(r instanceof Request?r.url:r,window.location.href).origin)}catch(i){}if(("undefined"===typeof navigator||"boolean"!==typeof navigator.onLine||navigator.onLine)&&null!==e&&e!==window.location.origin)return console.warn("Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option."),null}return Math.min(o(2,e-2),16)};class dn extends on{constructor(e,t={}){var r,i;if("string"!==typeof e&&!(e instanceof URL)&&!("undefined"!==typeof Request&&e instanceof Request))throw new TypeError("url must be a string, URL or Request.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.requestInit&&(!t.requestInit||"object"!==typeof t.requestInit))throw new TypeError("options.requestInit, when provided, must be an object.");if(void 0!==t.getRetryDelay&&"function"!==typeof t.getRetryDelay)throw new TypeError("options.getRetryDelay, when provided, must be a function.");if(void 0!==t.maxCacheSize&&(!me(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");if(void 0!==t.fetchFn&&"function"!==typeof t.fetchFn)throw new TypeError("options.fetchFn, when provided, must be a function.");super(),this._existingResponses=new WeakMap,this._url=e,this._options=t,this._getRetryDelay=null!=(r=t.getRetryDelay)?r:un,this._orchestrator=new fn({maxCacheSize:null!=(i=t.maxCacheSize)?i:64*o(2,20),maxWorkerCount:2,runWorker:this._runWorker.bind(this),prefetchProfile:mn.network})}_retrieveSize(){return u(this,null,function*(){var e,t;const r=new AbortController,i=yield ee(null!=(e=this._options.fetchFn)?e:fetch,this._url,J(null!=(t=this._options.requestInit)?t:{},{headers:{Range:"bytes=0-"},signal:r.signal}),this._getRetryDelay,()=>this._disposed);if(!i.ok)throw new Error(`Error fetching ${String(this._url)}: ${i.status} ${i.statusText}`);let n,s;if(206===i.status)s=this._getTotalLengthFromRangeResponse(i),n=this._orchestrator.createWorker(0,Math.min(s,cn));else{const e=i.headers.get("Content-Length");if(!e)throw new Error(`HTTP response (status ${i.status}) must surface Content-Length header.`);s=Number(e),n=this._orchestrator.createWorker(0,s),this._orchestrator.options.maxCacheSize=1/0,console.warn("HTTP server did not respond with 206 Partial Content, meaning the entire remote resource now has to be downloaded. For efficient media file streaming across a network, please make sure your server supports range requests.")}return this._orchestrator.fileSize=s,this._existingResponses.set(n,{response:i,abortController:r}),this._orchestrator.runWorker(n),s})}_read(e,t){return this._orchestrator.read(e,t)}_runWorker(e){return u(this,null,function*(){for(var t,r,i;;){const s=this._existingResponses.get(e);this._existingResponses.delete(e);let a=null==s?void 0:s.abortController,o=null==s?void 0:s.response;if(a||(a=new AbortController,o=yield ee(null!=(t=this._options.fetchFn)?t:fetch,this._url,J(null!=(r=this._options.requestInit)?r:{},{headers:{Range:`bytes=${e.currentPos}-`},signal:a.signal}),this._getRetryDelay,()=>this._disposed)),p(o),!o.ok)throw new Error(`Error fetching ${String(this._url)}: ${o.status} ${o.statusText}`);if(e.currentPos>0&&206!==o.status)throw new Error("HTTP server did not respond with 206 Partial Content to a range request. To enable efficient media file streaming across a network, please make sure your server supports range requests.");if(!o.body)throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream.");const l=o.body.getReader();for(;;){if(e.currentPos>=e.targetPos||e.aborted)return a.abort(),void(e.running=!1);let t;try{t=yield l.read()}catch(n){if(this._disposed)throw n;const e=this._getRetryDelay(1,n,this._url);if(null!==e){console.error("Error while reading response stream. Attempting to resume.",n),yield new Promise(t=>setTimeout(t,1e3*e));break}throw n}if(e.aborted)continue;const{done:r,value:s}=t;if(r){if(e.currentPos>=e.targetPos)return this._orchestrator.forgetWorker(e),void(e.running=!1);break}null==(i=this.onread)||i.call(this,e.currentPos,e.currentPos+s.length),this._orchestrator.supplyWorkerData(e,s)}}})}_getTotalLengthFromRangeResponse(e){const t=e.headers.get("Content-Range");if(t){const e=/\/(\d+)/.exec(t);if(e)return Number(e[1])}const r=e.headers.get("Content-Length");if(r)return Number(r);throw new Error("Partial HTTP response (status 206) must surface either Content-Range or Content-Length header.")}_dispose(){this._orchestrator.dispose()}}class hn extends on{constructor(e,t={}){var r;if(!(e instanceof ReadableStream))throw new TypeError("stream must be a ReadableStream.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!me(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._reader=null,this._cache=[],this._pendingSlices=[],this._currentIndex=0,this._targetIndex=0,this._maxRequestedIndex=0,this._endIndex=null,this._pulling=!1,this._stream=e,this._maxCacheSize=null!=(r=t.maxCacheSize)?r:16*o(2,20)}_retrieveSize(){return this._endIndex}_read(e,t){if(null!==this._endIndex&&t>this._endIndex)return null;this._maxRequestedIndex=Math.max(this._maxRequestedIndex,t);const r=N(this._cache,e,e=>e.start),i=-1!==r?this._cache[r]:null;if(i&&i.start<=e&&t<=i.end)return{bytes:i.bytes,view:i.view,offset:i.start};let n=e;const s=new Uint8Array(t-e);if(-1!==r)for(let c=r;c=t)break;const i=Math.max(e,r.start);i>n&&this._throwDueToCacheMiss();const a=Math.min(t,r.end);in&&this._throwDueToCacheMiss();const{promise:a,resolve:o,reject:l}=O();return this._pendingSlices.push({start:e,end:t,bytes:s,resolve:o,reject:l}),this._targetIndex=Math.max(this._targetIndex,t),this._pulling||(this._pulling=!0,this._pull().catch(e=>{if(this._pulling=!1,!(this._pendingSlices.length>0))throw e;this._pendingSlices.forEach(t=>t.reject(e)),this._pendingSlices.length=0})),a}_throwDueToCacheMiss(){throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache.")}_pull(){return u(this,null,function*(){for(null!=this._reader||(this._reader=this._stream.getReader());this._currentIndex0;){const e=this._cache[0];if(this._maxRequestedIndex-e.end<=this._maxCacheSize)break;this._cache.shift()}this._currentIndex+=t.byteLength}this._pulling=!1})}_dispose(){this._pendingSlices.length=0,this._cache.length=0}}const mn={fileSystem:(e,t)=>{const r=o(2,16);return{start:e=Math.floor((e-r)/r)*r,end:t=Math.ceil((t+r)/r)*r}},network:(e,t,r)=>{const i=o(2,16);e=Math.max(0,Math.floor((e-i)/i)*i);for(const n of r){const r=8*o(2,20),i=Math.max((n.startPos+n.targetPos)/2,n.targetPos-r);if(ue(e,t,i,n.targetPos)){const e=n.targetPos-n.startPos,i=Math.ceil((e+1)/r)*r,s=o(2,Math.ceil(Math.log2(e+1))),a=Math.min(s,i);t=Math.max(t,n.startPos+a)}}return{start:e,end:t=Math.max(t,e+cn)}}};class fn{constructor(e){this.options=e,this.fileSize=null,this.nextAge=0,this.workers=[],this.cache=[],this.currentCacheSize=0,this.disposed=!1}read(e,t){p(null!==this.fileSize);const r=this.options.prefetchProfile(e,t,this.workers),i=Math.max(r.start,0),n=Math.min(r.end,this.fileSize);p(i<=e&&t<=n);let s=null;const a=N(this.cache,e,e=>e.start),l=-1!==a?this.cache[a]:null;l&&l.start<=e&&t<=l.end&&(l.age=this.nextAge++,s={bytes:l.bytes,view:l.view,offset:l.start});const c=N(this.cache,i,e=>e.start),u=s?null:new Uint8Array(t-e);let d=0,h=i;const m=[];if(-1!==c){for(let r=c;r=n)break;if(s.end<=i)continue;const a=Math.max(i,s.start),o=Math.min(n,s.end);if(p(a<=o),h=u.length&&(s={bytes:u,view:v(u),offset:e}),0===m.length)return p(s),s;const{promise:f,resolve:g,reject:k}=O(),b=[];for(const o of m){const r=Math.max(e,o.start),i=Math.min(t,o.end);r===o.start&&i===o.end?b.push(o):r({bytes:t,view:v(t),offset:e}))),s}createWorker(e,t){const r={startPos:e,currentPos:e,targetPos:t,running:!1,aborted:this.disposed,pendingSlices:[],age:this.nextAge++};for(this.workers.push(r);this.workers.length>this.options.maxWorkerCount;){let e=0,t=this.workers[0];for(let r=1;r0)break;t.aborted=!0,this.workers.splice(e,1)}return r}runWorker(e){p(!e.running),p(e.currentPos{if(e.running=!1,!(e.pendingSlices.length>0))throw t;e.pendingSlices.forEach(e=>e.reject(t)),e.pendingSlices.length=0})}supplyWorkerData(e,t){p(!e.aborted);const r=e.currentPos,i=r+t.length;this.insertIntoCache({start:r,end:i,bytes:t,view:v(t),age:this.nextAge++}),e.currentPos+=t.length,e.targetPos=Math.max(e.targetPos,e.currentPos);for(let n=0;nt.start&&(t.start=i),t.end<=t.start&&(s.holes.splice(e,1),e--)}0===s.holes.length&&(s.resolve(s.bytes),e.pendingSlices.splice(n,1),n--)}for(let n=0;ne.start)+1;if(t>0){const r=this.cache[t-1];if(r.end>=e.end)return;if(r.end>e.start){const i=new Uint8Array(e.end-r.start);i.set(r.bytes,0),i.set(e.bytes,e.start-r.start),this.currentCacheSize+=e.end-r.end,r.bytes=i,r.view=v(i),r.end=e.end,t--,e=r}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length;for(let r=t+1;r=t.end){this.cache.splice(r,1),this.currentCacheSize-=t.bytes.length,r--;continue}const i=new Uint8Array(t.end-e.start);i.set(e.bytes,0),i.set(t.bytes,t.start-e.start),this.currentCacheSize-=e.end-t.start,e.bytes=i,e.view=v(i),e.end=t.end,this.cache.splice(r,1);break}for(;this.currentCacheSize>this.options.maxCacheSize;){let e=0,t=this.cache[0];for(let r=1;r!(e instanceof Ui)))throw new TypeError("options.formats must be an array of InputFormat.");if(!(e.source instanceof on))throw new TypeError("options.source must be a Source.");if(e.source._disposed)throw new Error("options.source must not be disposed.");this._formats=e.formats,this._source=e.source,this._reader=new kn(e.source)}_getDemuxer(){var e;return null!=(e=this._demuxerPromise)?e:this._demuxerPromise=(()=>u(this,null,function*(){this._reader.fileSize=yield this._source.getSizeOrNull();for(const e of this._formats){if(yield e._canReadInput(this))return this._format=e,e._createDemuxer(this)}throw new Error("Input has an unsupported or unrecognizable format.")}))()}get source(){return this._source}getFormat(){return u(this,null,function*(){return yield this._getDemuxer(),p(this._format),this._format})}computeDuration(){return u(this,null,function*(){return(yield this._getDemuxer()).computeDuration()})}getTracks(){return u(this,null,function*(){return(yield this._getDemuxer()).getTracks()})}getVideoTracks(){return u(this,null,function*(){return(yield this.getTracks()).filter(e=>e.isVideoTrack())})}getAudioTracks(){return u(this,null,function*(){return(yield this.getTracks()).filter(e=>e.isAudioTrack())})}getPrimaryVideoTrack(){return u(this,null,function*(){var e;return null!=(e=(yield this.getTracks()).find(e=>e.isVideoTrack()))?e:null})}getPrimaryAudioTrack(){return u(this,null,function*(){var e;return null!=(e=(yield this.getTracks()).find(e=>e.isAudioTrack()))?e:null})}getMimeType(){return u(this,null,function*(){return(yield this._getDemuxer()).getMimeType()})}getMetadataTags(){return u(this,null,function*(){return(yield this._getDemuxer()).getMetadataTags()})}dispose(){this._disposed||(this._disposed=!0,this._source._disposed=!0,this._source._dispose())}[Symbol.dispose](){this.dispose()}}class gn extends Error{constructor(e="Input has been disposed."){super(e),this.name="InputDisposedError"}}class kn{constructor(e){this.source=e}requestSlice(e,t){if(this.source._disposed)throw new gn;if(null!==this.fileSize&&e+t>this.fileSize)return null;const r=e+t,i=this.source._read(e,r);return i instanceof Promise?i.then(t=>t?new bn(t.bytes,t.view,t.offset,e,r):null):i?new bn(i.bytes,i.view,i.offset,e,r):null}requestSliceRange(e,t,r){if(this.source._disposed)throw new gn;if(null!==this.fileSize)return this.requestSlice(e,K(this.fileSize-e,t,r));{const i=this.requestSlice(e,r),n=i=>{if(i)return i;const n=i=>(p(null!==i),this.requestSlice(e,K(i-e,t,r))),s=this.source._retrieveSize();return s instanceof Promise?s.then(n):n(s)};return i instanceof Promise?i.then(n):n(i)}}}class bn{constructor(e,t,r,i,n){this.bytes=e,this.view=t,this.offset=r,this.start=i,this.end=n,this.bufferPos=i-r}static tempFromBytes(e){return new bn(e,v(e),0,0,e.length)}get length(){return this.end-this.start}get filePos(){return this.offset+this.bufferPos}set filePos(e){this.bufferPos=e-this.offset}get remainingLength(){return Math.max(this.end-this.filePos,0)}skip(e){this.bufferPos+=e}slice(e,t=this.end-e){if(ethis.end)throw new RangeError("Slicing outside of original slice.");return new bn(this.bytes,this.view,this.offset,e,e+t)}}const yn=(e,t)=>{if(e.filePose.end)throw new RangeError(`Tried reading [${e.filePos}, ${e.filePos+t}), but slice is [${e.start}, ${e.end}). This is likely an internal error, please report it alongside the file that caused it.`)},Tn=(e,t)=>{yn(e,t);const r=e.bytes.subarray(e.bufferPos,e.bufferPos+t);return e.bufferPos+=t,r},Sn=e=>(yn(e,1),e.view.getUint8(e.bufferPos++)),vn=(e,t)=>{yn(e,2);const r=e.view.getUint16(e.bufferPos,t);return e.bufferPos+=2,r},wn=e=>{yn(e,2);const t=e.view.getUint16(e.bufferPos,!1);return e.bufferPos+=2,t},In=e=>{yn(e,3);const t=H(e.view,e.bufferPos,!1);return e.bufferPos+=3,t},Pn=e=>{yn(e,2);const t=e.view.getInt16(e.bufferPos,!1);return e.bufferPos+=2,t},xn=(e,t)=>{yn(e,4);const r=e.view.getUint32(e.bufferPos,t);return e.bufferPos+=4,r},Cn=e=>{yn(e,4);const t=e.view.getUint32(e.bufferPos,!1);return e.bufferPos+=4,t},_n=e=>{yn(e,4);const t=e.view.getUint32(e.bufferPos,!0);return e.bufferPos+=4,t},Bn=e=>{yn(e,4);const t=e.view.getInt32(e.bufferPos,!1);return e.bufferPos+=4,t},En=(e,t)=>{let r,i;return t?(r=xn(e,!0),i=xn(e,!0)):(i=xn(e,!1),r=xn(e,!1)),4294967296*i+r},Fn=e=>4294967296*Cn(e)+Cn(e),Dn=e=>4294967296*Bn(e)+Cn(e),An=e=>{const t=_n(e),r=(e=>{yn(e,4);const t=e.view.getInt32(e.bufferPos,!0);return e.bufferPos+=4,t})(e);return 4294967296*r+t},Rn=e=>{yn(e,4);const t=e.view.getFloat32(e.bufferPos,!1);return e.bufferPos+=4,t},Mn=e=>{yn(e,8);const t=e.view.getFloat64(e.bufferPos,!1);return e.bufferPos+=8,t},Nn=(e,t)=>{yn(e,t);let r="";for(let i=0;ie.stop()),this.queuedNodes.clear()}stopIterator(){return u(this,null,function*(){var e;yield null==(e=this.audioIterator)?void 0:e.return(),this.audioIterator=null})}load(e,t){return u(this,null,function*(){const r=++this.asyncId;yield this.stopIterator(),this.stopQueuedNodes(),this.paused=!0,this.playbackTimeAtStart=0,this.audioContextStartTime=0;const i=this.normalizeSource(e);if(!i)return;if(this.input=new pn({source:i,formats:an}),this.duration=yield this.input.computeDuration(),r!==this.asyncId)return;const n=yield this.input.getPrimaryAudioTrack();return n&&null!==n.codec&&(yield n.canDecode())?(this.ensureAudioContext(n.sampleRate),this.audioSink=new $t(n),void(null==t||t())):(this.audioSink=null,this.ensureAudioContext(),void(null==t||t()))})}runIterator(e){return u(this,null,function*(){if(this.audioSink)for(yield this.stopIterator(),this.audioIterator=this.audioSink.buffers(this.currentTime);;){if(e!==this.asyncId||this.paused)return;const r=this.audioIterator.next(),i=setInterval(()=>{e!==this.asyncId||this.paused?clearInterval(i):"running"===this.audioContext.state&&this.audioContext.currentTime>=this.latestScheduledEndTime-.2&&(this.audioContext.suspend(),this.events.emit("waiting"))},50);let n;try{n=yield r}catch(t){console.error("Audio iterator error:",t);break}finally{clearInterval(i)}if(e!==this.asyncId||this.paused)return;if("suspended"===this.audioContext.state&&(yield this.audioContext.resume(),this.events.emit("canplay"),this.events.emit("playing")),n.done)break;const{buffer:s,timestamp:a}=n.value,o=this.audioContext.createBufferSource();o.buffer=s,o.connect(this.gainNode),o.playbackRate.value=this.playbackRate;const l=this.audioContextStartTime+(a-this.playbackTimeAtStart)/this.playbackRate,c=l+s.duration/this.playbackRate;c>this.latestScheduledEndTime&&(this.latestScheduledEndTime=c),l>=this.audioContext.currentTime?o.start(l):o.start(this.audioContext.currentTime,(this.audioContext.currentTime-l)*this.playbackRate),this.queuedNodes.add(o),o.onended=()=>this.queuedNodes.delete(o)}})}play(){return u(this,null,function*(){if(!this.paused)return;this.audioContext||this.ensureAudioContext(),"suspended"===this.audioContext.state&&(yield this.audioContext.resume()),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime,this.paused=!1;const e=++this.asyncId;this.runIterator(e)})}pause(){this.paused||(this.playbackTimeAtStart=this.currentTime,this.paused=!0,this.stopIterator(),this.stopQueuedNodes())}seek(e){return u(this,null,function*(){this.playbackTimeAtStart=Math.max(0,e),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime;const t=++this.asyncId;this.paused||this.runIterator(t)})}setVolume(e,t){this.volume=e,this.muted=t,this.updateGain()}setPlaybackRate(e){if(e!==this.playbackRate&&(this.paused||(this.playbackTimeAtStart=this.currentTime,this.audioContextStartTime=this.audioContext.currentTime),this.playbackRate=e,!this.paused)){const e=++this.asyncId;this.runIterator(e)}}destroy(){var e;this.asyncId++,this.pause(),null==(e=this.audioContext)||e.close(),this.audioContext=null,this.input=null,this.audioSink=null}}class On{constructor({canvas:e,ctx:t,events:r,timeupdateInterval:i=250,avSyncTolerance:n=.12,dropLateFrames:s=!1,poster:a="",preflightRange:o=!1}){this.canvas=e,this.ctx=t,this.events=r,this.timeupdateInterval=i,this.avSyncTolerance=n,this.dropLateFrames=s,this.poster=a,this.preflightRange=o,this.input=null,this.videoSink=null,this.videoIterator=null,this.nextFrame=null,this.rafId=0,this.asyncId=0,this.width=0,this.height=0,this.duration=Number.NaN,this.audioClock=null,this.lastTimeUpdate=0,this.stalled=!1,this.playbackRate=1,this.posterDrawn=!1,this.isFetching=!1}normalizeSource(e){return"string"===typeof e?new dn(e):e instanceof Blob?new ln(e):"undefined"!==typeof ReadableStream&&e instanceof ReadableStream?new hn(e):e}preflight(e){return u(this,null,function*(){if(!this.preflightRange||"string"!==typeof e)return!0;try{const t=(yield fetch(e,{method:"HEAD"})).headers.get("accept-ranges");return!(!t||"none"===t)||(this.events.emit("error",new Event("RangeNotSupported")),!1)}catch(t){return console.warn("Preflight check failed:",t),!0}})}drawPoster(){if(!this.poster||this.posterDrawn)return;const e=new Image;e.onload=()=>{this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width=e.naturalWidth||this.canvas.width,this.canvas.height=e.naturalHeight||this.canvas.height,this.ctx.drawImage(e,0,0,this.canvas.width,this.canvas.height),this.posterDrawn=!0},e.src=this.poster}stopIterator(){return u(this,null,function*(){var e;yield null==(e=this.videoIterator)?void 0:e.return(),this.videoIterator=null})}clear(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}load(e,t){return u(this,null,function*(){const r=++this.asyncId;if(yield this.stopIterator(),this.clear(),this.posterDrawn=!1,!(yield this.preflight(e)))return;const i=this.normalizeSource(e);if(!i)return void this.drawPoster();if(this.input=new pn({source:i,formats:an}),this.duration=yield this.input.computeDuration(),r!==this.asyncId)return;const n=yield this.input.getPrimaryVideoTrack();if(!n)return this.handleNoVideoTrack(),void(null==t||t());if(null===n.codec||!(yield n.canDecode()))return this.handleNoVideoTrack(),void(null==t||t());const s=yield n.canBeTransparent();this.videoSink=new Ht(n,{poolSize:2,fit:"contain",alpha:s}),this.width=n.displayWidth,this.height=n.displayHeight,this.canvas.width=this.width,this.canvas.height=this.height,null==t||t(),yield this.resetIterator(0)})}handleNoVideoTrack(){this.videoSink=null,this.width=0,this.height=0,this.canvas.width=0,this.canvas.height=0,this.clear(),this.drawPoster()}resetIterator(e){return u(this,null,function*(){var t,r;if(yield this.stopIterator(),!this.videoSink)return;this.videoIterator=this.videoSink.canvases(e);const i=null!=(t=(yield this.videoIterator.next()).value)?t:null,n=null!=(r=(yield this.videoIterator.next()).value)?r:null;this.nextFrame=n,i?(this.ctx.drawImage(i.canvas,0,0),this.events.emit("loadeddata")):this.drawPoster()})}updateNextFrame(e){return u(this,null,function*(){var t;if(this.videoIterator&&!this.isFetching){this.isFetching=!0;try{for(;;){const r=null!=(t=(yield this.videoIterator.next()).value)?t:null;if(!r||e!==this.asyncId)return;const i=this.audioClock.currentTime,n=this.dropLateFrames?Math.max(.06,this.avSyncTolerance/Math.max(1,this.playbackRate)):0;if(!(this.dropLateFrames&&r.timestampi)return void(this.nextFrame=null)}}}finally{this.isFetching=!1}}})}render(){if(!this.audioClock)return;const e=this.audioClock.currentTime,t=Date.now();if(t-this.lastTimeUpdate>=this.timeupdateInterval&&(this.events.emit("timeupdate"),this.lastTimeUpdate=t),Number.isFinite(this.duration)&&e>=this.duration)return this.stop(),this.stalled=!1,this.events.emit("ended"),this.events.emit("pause"),void this.events.emit("canplay");this.nextFrame&&this.nextFrame.timestamp<=e?(this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextFrame.canvas,0,0),this.nextFrame=null,this.updateNextFrame(this.asyncId),this.stalled&&(this.events.emit("canplay"),this.events.emit("playing"),this.stalled=!1)):this.nextFrame||(this.updateNextFrame(this.asyncId),!this.nextFrame&&Number.isFinite(this.duration)&&ethis.render())}start(e){this.audioClock=e,this.asyncId++,this.stalled=!1,this.updateNextFrame(this.asyncId),this.rafId=requestAnimationFrame(()=>this.render())}stop(){cancelAnimationFrame(this.rafId)}seek(e){return u(this,null,function*(){this.asyncId++,yield this.resetIterator(e)})}setPlaybackRate(e){this.playbackRate=Math.max(.1,Number(e)||1)}destroy(){this.asyncId++,this.stop(),this.stopIterator(),this.posterDrawn=!1,this.input=null,this.videoSink=null}}class Ln{constructor({canvas:e,ctx:t,events:r,option:i={}}){var n,s,a,o,l,c;this.events=r,this.option=i,this.audio=new zn(r),this.video=new On({canvas:e,ctx:t,events:r,timeupdateInterval:null!=(n=i.timeupdateInterval)?n:250,avSyncTolerance:null!=(s=i.avSyncTolerance)?s:.12,dropLateFrames:null!=(a=i.dropLateFrames)&&a,poster:null!=(o=i.poster)?o:"",preflightRange:null!=(l=i.preflightRange)&&l}),this.paused=!0,this.ended=!1,this.readyState=0,this.networkState=0,this.error=null,this.seeking=!1,this.loadSeq=0,null==(c=r.addEventListener)||c.call(r,"ended",()=>{this.ended=!0,this.paused=!0})}load(e){return u(this,null,function*(){const t=++this.loadSeq;this.pause(),this.ended=!1,this.error=null,this.networkState=2,this.readyState=0,setTimeout(()=>this.events.emit("waiting"),0),setTimeout(()=>this.events.emit("loadstart"),0);const r=Number.isFinite(this.option.loadTimeout)?this.option.loadTimeout:0;try{yield Promise.race([this.performLoad(e,t),r>0?this.createTimeout(r):new Promise(()=>{})])}catch(i){if(t!==this.loadSeq)return;this.loadSeq++,this.error={code:4,message:i.message},this.networkState=3,this.events.emit("error")}})}performLoad(e,t){return u(this,null,function*(){let r=!1,i=!1;const n=()=>{r&&i&&(this.readyState=1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"))};try{if(yield Promise.all([this.video.load(e,()=>{t===this.loadSeq&&(r=!0,n())}),this.audio.load(e,()=>{t===this.loadSeq&&(i=!0,n())})]),t!==this.loadSeq)return;this.readyState=4,this.networkState=1,this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("progress")}catch(s){if(t!==this.loadSeq)return;this.error={code:4,message:s.message},this.networkState=3,this.events.emit("error"),console.error("MediaBunny load error:",s)}})}createTimeout(e){return new Promise((t,r)=>{setTimeout(()=>r(new Error("Load timeout")),e)})}play(){return u(this,null,function*(){this.paused&&(this.ended&&(this.ended=!1,yield this.seek(0)),this.paused=!1,yield this.audio.play(),this.video.start(this.audio),this.events.emit("play"),this.events.emit("playing"))})}pause(){this.paused||(this.paused=!0,this.audio.pause(),this.video.stop(),this.events.emit("pause"))}seek(e){return u(this,null,function*(){const t=!this.paused;this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),this.pause(),yield Promise.all([this.audio.seek(e),this.video.seek(e)]),this.seeking=!1,this.events.emit("seeked"),t&&!this.ended&&(yield this.play())})}setVolume(e,t){this.audio.setVolume(e,t)}setPlaybackRate(e){this.audio.setPlaybackRate(e),this.video.setPlaybackRate(e)}destroy(){this.pause(),this.audio.destroy(),this.video.destroy()}get currentTime(){return this.audio.currentTime}get duration(){return this.audio.duration||this.video.duration}get videoWidth(){return this.video.width}get videoHeight(){return this.video.height}}class Un{constructor({art:e,canvas:t,ctx:r,option:i}){var n,s;this.art=e,this.canvas=t,this.option=i,this.events=new f,this.engine=new Ln({canvas:t,ctx:r,events:this.events,option:i}),this._src=null,this._volume=null!=(n=i.volume)?n:.7,this._muted=!!i.muted,this._playbackRate=1,this.engine.setVolume(this._volume,this._muted),this.setupEventForwarding(),i.source?this.src=i.source:(null==(s=e.option)?void 0:s.url)&&(this.src=e.option.url)}setupEventForwarding(){const{events:e}=this.art.constructor.config;e.forEach(e=>{this.events.addEventListener(e,e=>{this.art.emit(`video:${e.type}`,e)})})}addEventListener(e,t){this.events.addEventListener(e,t)}removeEventListener(e,t){this.events.removeEventListener(e,t)}get src(){return this._src}set src(e){this._src=e,e&&this.engine.load(e)}get currentSrc(){return this._src}get currentTime(){return this.engine.currentTime}set currentTime(e){this.engine.seek(Number(e)||0)}get duration(){return this.engine.duration}get buffered(){return this.createTimeRanges(0,this.engine.duration)}get played(){return this.createTimeRanges(0,this.engine.currentTime)}get seekable(){return this.createTimeRanges(0,this.engine.duration)}createTimeRanges(e,t){const r=this.engine.duration;return!r||Number.isNaN(r)||t<=0?{length:0,start:()=>0,end:()=>0}:{length:1,start:()=>e,end:()=>t}}get paused(){return this.engine.paused}get playing(){return!this.engine.paused&&!this.engine.ended}get ended(){return this.engine.ended}get seeking(){return this.engine.seeking}get readyState(){return this.engine.readyState}get networkState(){return this.engine.networkState}get error(){return this.engine.error}get playbackRate(){return this._playbackRate}set playbackRate(e){const t=Number(e);Number.isNaN(t)||t<=0||(this._playbackRate=t,this.engine.setPlaybackRate(t),this.events.emit("ratechange"))}get volume(){return this._volume}set volume(e){this._volume=function(e,t,r){return Math.max(t,Math.min(r,Number(e)||0))}(e,0,1),this._muted=!1,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}get muted(){return this._muted}set muted(e){this._muted=!!e,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}play(){return this.engine.play()}pause(){this.engine.pause()}load(){this._src&&this.engine.load(this._src)}get videoWidth(){return this.engine.videoWidth}get videoHeight(){return this.engine.videoHeight}get poster(){return this.option.poster||""}set poster(e){this.option.poster=e}get autoplay(){return this.option.autoplay||!1}set autoplay(e){}get loop(){return this.option.loop||!1}set loop(e){}get controls(){return!1}set controls(e){}get playsInline(){return!0}set playsInline(e){}get crossOrigin(){return this.option.crossOrigin||""}set crossOrigin(e){}get preload(){return"auto"}set preload(e){}get defaultMuted(){return!1}set defaultMuted(e){}get defaultPlaybackRate(){return 1}set defaultPlaybackRate(e){}canPlayType(e){return"maybe"}getBoundingClientRect(){return this.canvas.getBoundingClientRect()}requestVideoFrameCallback(e){return requestAnimationFrame(t=>{e(t,{presentationTime:this.engine.currentTime,expectedDisplayTime:t+16.6,width:this.engine.videoWidth,height:this.engine.videoHeight,mediaTime:this.engine.currentTime,presentedFrames:0,processingDuration:0,captureTime:t,receiveTime:t,rtpTimestamp:0})})}cancelVideoFrameCallback(e){cancelAnimationFrame(e)}setAttribute(e,t){"src"===e?this.src=t:"autoplay"===e?this.autoplay=t:"loop"===e?this.loop=t:"muted"===e?this.muted=!0:this.canvas.setAttribute(e,t)}destroy(){this.engine.destroy()}}return function(e={}){return t=>{const{constructor:r}=t,{createElement:i}=r.utils,n=i("canvas"),s=n.getContext("2d"),a=new Un({art:t,canvas:n,ctx:s,option:e}),o={};for(const e in n)"function"===typeof n[e]&&(o[e]=n[e].bind(n));const l=new Set([...Object.getOwnPropertyNames(a),...Object.getOwnPropertyNames(Object.getPrototypeOf(a))]);for(const e of l)"constructor"!==e&&(e in n||Object.defineProperty(n,e,{get(){const t=a[e];return"function"===typeof t?t.bind(a):t},set(t){a[e]=t},configurable:!0,enumerable:!0}));for(const e in o)n[e]=(...t)=>o[e](...t);function c(){var e;(null==(e=t.template)?void 0:e.$player)&&!t.option.autoSize&&Object.assign(n.style,{width:"100%",height:"100%",objectFit:"contain"})}return t.on("resize",c),t.on("video:loadedmetadata",c),t.on("destroy",()=>{a.destroy()}),n}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,i=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,a=(e,t)=>(t=Symbol[e])?t:Symbol.for("Symbol."+e),o=Math.pow,l=(t,i,r)=>i in t?e(t,i,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[i]=r,c=(e,t)=>{for(var i in t||(t={}))n.call(t,i)&&l(e,i,t[i]);if(r)for(var i of r(t))s.call(t,i)&&l(e,i,t[i]);return e},u=(e,r)=>t(e,i(r)),d=(e,t,i)=>new Promise((r,n)=>{var s=e=>{try{o(i.next(e))}catch(t){n(t)}},a=e=>{try{o(i.throw(e))}catch(t){n(t)}},o=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,a);o((i=i.apply(e,t)).next())}),h=function(e,t){this[0]=e,this[1]=t},f=(e,t,i)=>{var r=(e,t,n,s)=>{try{var a=i[e](t),o=(t=a.value)instanceof h,l=a.done;Promise.resolve(o?t[0]:t).then(i=>o?r("return"===e?e:"next",t[1]?{done:i.done,value:i.value}:i,n,s):n({value:i,done:l})).catch(e=>r("throw",e,n,s))}catch(c){s(c)}},n=e=>s[e]=t=>new Promise((i,n)=>r(e,t,i,n)),s={};return i=i.apply(e,t),s[a("asyncIterator")]=()=>s,n("next"),n("throw"),n("return"),s},m=e=>{var t,i=e[a("asyncIterator")],r=!1,n={};return null==i?(i=e[a("iterator")](),t=e=>n[e]=t=>i[e](t)):(i=i.call(e),t=e=>n[e]=t=>{if(r){if(r=!1,"throw"===e)throw t;return t}return r=!0,{done:!1,value:new h(new Promise(r=>{var n=i[e](t);n instanceof Object||(e=>{throw TypeError(e)})("Object expected"),r(n)}),1)}}),n[a("iterator")]=()=>n,t("next"),"throw"in i?t("throw"):n.throw=e=>{throw e},"return"in i&&t("return"),n},p=(e,t,i)=>(t=e[a("asyncIterator")])?t.call(e):(e=e[a("iterator")](),t={},(i=(i,r)=>(r=e[i])&&(t[i]=t=>new Promise((i,n,s)=>(t=r.call(e,t),s=t.done,Promise.resolve(t.value).then(e=>i({value:e,done:s}),n)))))("next"),i("return"),t);function g(e,t){const i=new Map;return e.filter(e=>{const r=e[t];return void 0===r||!i.has(r)&&i.set(r,1)})}class k{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const i=this.listeners.get(e);if(!i)return;const r=i.indexOf(t);r>=0&&i.splice(r,1)}emit(e,t){const i=new Event(e);i.detail=t;const r=this.listeners.get(e);r&&r.forEach(e=>e(i))}}function y(e){if(!e)throw new Error("Assertion failed.")}const b=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},T=e=>e&&e[e.length-1],S=e=>{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<{const t=S(e);return 0===(1&t)?-(t>>1):t+1>>1},w=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),P=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),I=new TextDecoder,x=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),C={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},B=x(C),E={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},_=x(E),A={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},F=x(A),R=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class D{constructor(){this.currentPromise=Promise.resolve(),this.pending=0}acquire(){return d(this,null,function*(){let e;const t=new Promise(t=>{let i=!1;e=()=>{i||(t(),this.pending--,i=!0)}}),i=this.currentPromise;return this.currentPromise=t,this.pending++,yield i,e})}}const M=/^[0-9a-fA-F]+$/,N=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),O=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,L=(e,t,i)=>{let r=0,n=e.length-1,s=-1;for(;r<=n;){const a=r+n>>1,o=i(e[a]);o===t?(s=a,n=a-1):o{let r=0,n=e.length-1,s=-1;for(;r<=n;){const a=r+(n-r+1)/2|0;i(e[a])<=t?(s=a,r=a+1):n=a-1}return s},U=(e,t,i)=>{const r=z(e,i(t),i);e.splice(r+1,0,t)},q=()=>{let e,t;return{promise:new Promise((i,r)=>{e=i,t=r}),resolve:e,reject:t}},W=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return e[i]},V=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return i;return-1},H=e=>{throw new Error(`Unexpected value: ${e}`)},K=(e,t,i)=>{const r=e.getUint8(t),n=e.getUint8(t+1),s=e.getUint8(t+2);return i?r|n<<8|s<<16:r<<16|n<<8|s},j=(e,t,i,r)=>{i>>>=0,i&=16777215,e.setUint8(t,i>>>16&255),e.setUint8(t+1,i>>>8&255),e.setUint8(t+2,255&i)},X=(e,t)=>({next(){return d(this,null,function*(){const i=yield e.next();return i.done?{value:void 0,done:!0}:{value:t(i.value),done:!1}})},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),$=(e,t,i)=>Math.max(t,Math.min(i,e)),Q="und",G=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},Y=(e,t)=>Math.round(e*t)/t,J=(e,t)=>Math.floor(e/t)*t,Z=/^[a-z]{3}$/,ee=e=>Z.test(e),te=1e6*(1+Number.EPSILON),ie=(e,t)=>{const i=c(c({},e),t);if(e.headers||t.headers){const r=e.headers?re(e.headers):{},n=t.headers?re(t.headers):{},s=c({},r);Object.entries(n).forEach(([e,t])=>{const i=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());i&&delete s[i],s[e]=t}),i.headers=s}return i},re=e=>{if(e instanceof Headers){const t={};return e.forEach((e,i)=>{t[i]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,i])=>{t[e]=i}),t}return e},ne=(e,t,i,r,n)=>d(null,null,function*(){let s=0;for(;;)try{return yield e(t,i)}catch(a){if(n())throw a;s++;const e=r(s,a,t);if(null===e)throw a;if(console.error("Retrying failed fetch. Error:",a),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&(yield Pe(1e3*e)),n())throw a}});class se{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let ae=null;const oe=()=>{var e;return null!==ae?ae:ae=!("undefined"===typeof navigator||!((null==(e=navigator.vendor)?void 0:e.match(/apple/i))||/AppleWebKit/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)||/\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent)))};let le=null;const ce=()=>{var e;return null!==le?le:le="undefined"!==typeof navigator&&(null==(e=navigator.userAgent)?void 0:e.includes("Firefox"))};let ue=null;const de=()=>{var e;return null!==ue?ue:ue=!("undefined"===typeof navigator||!(null==(e=navigator.vendor)?void 0:e.includes("Google Inc"))&&!/Chrome/.test(navigator.userAgent))};let he=null;const fe=()=>{if(null!==he)return he;if("undefined"===typeof navigator)return null;const e=/\bChrome\/(\d+)/.exec(navigator.userAgent);return e?he=Number(e[1]):null},me=(e,t)=>-1!==e?e:t,pe=(e,t,i,r)=>e<=r&&i<=t,ge=e=>{const t=atob(e),i=new Uint8Array(t.length);for(let r=0;r{null!=Symbol.dispose||(Symbol.dispose=Symbol("Symbol.dispose"))},ye=e=>"number"===typeof e&&!Number.isNaN(e),be=(e,t)=>{if(t.includes("://"))return t;if(e.includes("://")){const t=e.indexOf("?");-1!==t&&(e=e.slice(0,t))}let i;if(t.startsWith("/")){const r=e.indexOf("://");if(-1===r)i=t;else{const n=e.indexOf("/",r+3);i=-1===n?e+t:e.slice(0,n)+t}}else{const r=e.lastIndexOf("/");i=-1===r?t:e.slice(0,r+1)+t}let r="";const n=i.indexOf("://");if(-1!==n){const e=i.indexOf("/",n+3);-1!==e&&(r=i.slice(0,e),i=i.slice(e))}const s=i.split("/"),a=[];for(const o of s)".."===o?a.pop():"."!==o&&a.push(o);return r+a.join("/")},Te=(e,t)=>{let i=0;for(let r=0;r{let i=-1,r=1/0;for(let n=0;n{y(Number.isInteger(e.num)),y(Number.isInteger(e.den)),y(0!==e.den);let t=Math.abs(e.num),i=Math.abs(e.den);for(;0!==i;){const e=t%i;t=i,i=e}const r=t||1;return{num:e.num/r,den:e.den/r}},we=(e,t)=>{if("object"!==typeof e||!e)throw new TypeError(`${t} must be an object.`);if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(`${t}.left must be a non-negative integer.`);if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(`${t}.top must be a non-negative integer.`);if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(`${t}.width must be a non-negative integer.`);if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(`${t}.height must be a non-negative integer.`)},Pe=e=>new Promise(t=>setTimeout(t,e));class Ie{constructor(){this._listeners=new Map}on(e,t,i){var r;this._listeners.has(e)||this._listeners.set(e,new Set);const n={fn:t,once:null!=(r=null==i?void 0:i.once)&&r};return this._listeners.get(e).add(n),()=>{var t;null==(t=this._listeners.get(e))||t.delete(n)}}_emit(...e){const[t,i]=e,r=this._listeners.get(t);if(r)for(const s of r){try{s.fn(i)}catch(n){console.error(n)}s.once&&r.delete(s)}}}class xe{constructor(e,t){if(this.data=e,this.mimeType=t,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("string"!==typeof t)throw new TypeError("mimeType must be a string.")}}class Ce{constructor(e,t,i,r){if(this.data=e,this.mimeType=t,this.name=i,this.description=r,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if(void 0!==t&&"string"!==typeof t)throw new TypeError("mimeType, when provided, must be a string.");if(void 0!==i&&"string"!==typeof i)throw new TypeError("name, when provided, must be a string.");if(void 0!==r&&"string"!==typeof r)throw new TypeError("description, when provided, must be a string.")}}const Be={default:!0,primary:!0,forced:!1,original:!1,commentary:!1,hearingImpaired:!1,visuallyImpaired:!1};class Ee{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){var e;const t=Math.floor(this.pos/8),i=null!=(e=this.bytes[t])?e:0,r=7-(7&this.pos),n=(i&1<>r;return this.pos++,n}readBits(e){if(1===e)return this.readBit();let t=0;for(let i=0;i>i-r-1<{if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");const t=new Ee(e);let i=t.readBits(5);31===i&&(i=32+t.readBits(6));const r=t.readBits(4);let n=null;15===r?n=t.readBits(24):r<_e.length&&(n=_e[r]);const s=t.readBits(4);let a=null;return s>=1&&s<=7&&(a=Ae[s]),{objectType:i,frequencyIndex:r,sampleRate:n,channelConfiguration:s,numberOfChannels:a}},Re=["avc","hevc","vp9","av1","vp8"],De=["pcm-s16","pcm-s16be","pcm-s24","pcm-s24be","pcm-s32","pcm-s32be","pcm-f32","pcm-f32be","pcm-f64","pcm-f64be","pcm-u8","pcm-s8","ulaw","alaw"],Me=["aac","opus","mp3","vorbis","flac","ac3","eac3",...De],Ne=[{maxMacroblocks:99,maxBitrate:64e3,maxDpbMbs:396,level:10},{maxMacroblocks:396,maxBitrate:192e3,maxDpbMbs:900,level:11},{maxMacroblocks:396,maxBitrate:384e3,maxDpbMbs:2376,level:12},{maxMacroblocks:396,maxBitrate:768e3,maxDpbMbs:2376,level:13},{maxMacroblocks:396,maxBitrate:2e6,maxDpbMbs:2376,level:20},{maxMacroblocks:792,maxBitrate:4e6,maxDpbMbs:4752,level:21},{maxMacroblocks:1620,maxBitrate:4e6,maxDpbMbs:8100,level:22},{maxMacroblocks:1620,maxBitrate:1e7,maxDpbMbs:8100,level:30},{maxMacroblocks:3600,maxBitrate:14e6,maxDpbMbs:18e3,level:31},{maxMacroblocks:5120,maxBitrate:2e7,maxDpbMbs:20480,level:32},{maxMacroblocks:8192,maxBitrate:2e7,maxDpbMbs:32768,level:40},{maxMacroblocks:8192,maxBitrate:5e7,maxDpbMbs:32768,level:41},{maxMacroblocks:8704,maxBitrate:5e7,maxDpbMbs:34816,level:42},{maxMacroblocks:22080,maxBitrate:135e6,maxDpbMbs:110400,level:50},{maxMacroblocks:36864,maxBitrate:24e7,maxDpbMbs:184320,level:51},{maxMacroblocks:36864,maxBitrate:24e7,maxDpbMbs:184320,level:52},{maxMacroblocks:139264,maxBitrate:24e7,maxDpbMbs:696320,level:60},{maxMacroblocks:139264,maxBitrate:48e7,maxDpbMbs:696320,level:61},{maxMacroblocks:139264,maxBitrate:8e8,maxDpbMbs:696320,level:62}],Oe=[{maxPictureSize:36864,maxBitrate:2e5,level:10},{maxPictureSize:73728,maxBitrate:8e5,level:11},{maxPictureSize:122880,maxBitrate:18e5,level:20},{maxPictureSize:245760,maxBitrate:36e5,level:21},{maxPictureSize:552960,maxBitrate:72e5,level:30},{maxPictureSize:983040,maxBitrate:12e6,level:31},{maxPictureSize:2228224,maxBitrate:18e6,level:40},{maxPictureSize:2228224,maxBitrate:3e7,level:41},{maxPictureSize:8912896,maxBitrate:6e7,level:50},{maxPictureSize:8912896,maxBitrate:12e7,level:51},{maxPictureSize:8912896,maxBitrate:18e7,level:52},{maxPictureSize:35651584,maxBitrate:18e7,level:60},{maxPictureSize:35651584,maxBitrate:24e7,level:61},{maxPictureSize:35651584,maxBitrate:48e7,level:62}],Le=".01.01.01.01.00",ze=".0.110.01.01.01.0",Ue=e=>{const{codec:t,codecDescription:i,colorSpace:r,avcCodecInfo:n,hevcCodecInfo:s,vp9CodecInfo:a,av1CodecInfo:o}=e;if("avc"===t){if(y(null!==e.avcType),n){const t=new Uint8Array([n.avcProfileIndication,n.profileCompatibility,n.avcLevelIndication]);return`avc${e.avcType}.${N(t)}`}if(!i||i.byteLength<4)throw new TypeError("AVC decoder description is not provided or is not at least 4 bytes long.");return`avc${e.avcType}.${N(i.subarray(1,4))}`}if("hevc"===t){let e,t,r,n,a,o;if(s)e=s.generalProfileSpace,t=s.generalProfileIdc,r=O(s.generalProfileCompatibilityFlags),n=s.generalTierFlag,a=s.generalLevelIdc,o=[...s.generalConstraintIndicatorFlags];else{if(!i||i.byteLength<23)throw new TypeError("HEVC decoder description is not provided or is not at least 23 bytes long.");const s=P(i),l=s.getUint8(1);e=l>>6&3,t=31&l,r=O(s.getUint32(2)),n=l>>5&1,a=s.getUint8(12),o=[];for(let e=0;e<6;e++)o.push(s.getUint8(6+e))}let l="hev1.";for(l+=["","A","B","C"][e]+t,l+=".",l+=r.toString(16).toUpperCase(),l+=".",l+=0===n?"L":"H",l+=a;o.length>0&&0===o[o.length-1];)o.pop();return o.length>0&&(l+=".",l+=o.map(e=>e.toString(16).toUpperCase()).join(".")),l}if("vp8"===t)return"vp8";if("vp9"===t){if(!a){const t=e.width*e.height;let i=T(Oe).level;for(const e of Oe)if(t<=e.maxPictureSize){i=e.level;break}return`vp09.00.${i.toString().padStart(2,"0")}.08`}let t=`vp09.${a.profile.toString().padStart(2,"0")}.${a.level.toString().padStart(2,"0")}.${a.bitDepth.toString().padStart(2,"0")}.${a.chromaSubsampling.toString().padStart(2,"0")}`;return t+=`.${a.colourPrimaries.toString().padStart(2,"0")}.${a.transferCharacteristics.toString().padStart(2,"0")}.${a.matrixCoefficients.toString().padStart(2,"0")}.${a.videoFullRangeFlag.toString().padStart(2,"0")}`,t.endsWith(Le)&&(t=t.slice(0,-15)),t}if("av1"===t){if(!o){const t=e.width*e.height;let i=T(Oe).level;for(const e of Oe)if(t<=e.maxPictureSize){i=e.level;break}return`av01.0.${i.toString().padStart(2,"0")}M.08`}const t=o.profile,i=o.level.toString().padStart(2,"0"),n=o.tier?"H":"M",s=o.bitDepth.toString().padStart(2,"0"),a=o.monochrome?"1":"0",l=100*o.chromaSubsamplingX+10*o.chromaSubsamplingY+1*(o.chromaSubsamplingX&&o.chromaSubsamplingY?o.chromaSamplePosition:0),c=(null==r?void 0:r.primaries)?C[r.primaries]:1,u=(null==r?void 0:r.transfer)?E[r.transfer]:1,d=(null==r?void 0:r.matrix)?A[r.matrix]:1,h=(null==r?void 0:r.fullRange)?1:0;let f=`av01.${t}.${i}${n}.${s}`;return f+=`.${a}.${l.toString().padStart(3,"0")}`,f+=`.${c.toString().padStart(2,"0")}`,f+=`.${u.toString().padStart(2,"0")}`,f+=`.${d.toString().padStart(2,"0")}`,f+=`.${h}`,f.endsWith(ze)&&(f=f.slice(0,-17)),f}throw new TypeError(`Unhandled codec '${t}'.`)},qe=e=>{const{codec:t,codecDescription:i,aacCodecInfo:r}=e;if("aac"===t){if(!r)throw new TypeError("AAC codec info must be provided.");if(r.isMpeg2)return"mp4a.67";{let e;if(null!==r.objectType)e=r.objectType;else{e=Fe(i).objectType}return`mp4a.40.${e}`}}if("mp3"===t)return"mp3";if("opus"===t)return"opus";if("vorbis"===t)return"vorbis";if("flac"===t)return"flac";if("ac3"===t)return"ac-3";if("eac3"===t)return"ec-3";if(t&&De.includes(t))return t;throw new TypeError(`Unhandled codec '${t}'.`)},We=48e3,Ve=/^pcm-([usf])(\d+)+(be)?$/,He=e=>{if(y(De.includes(e)),"ulaw"===e)return{dataType:"ulaw",sampleSize:1,littleEndian:!0,silentValue:255};if("alaw"===e)return{dataType:"alaw",sampleSize:1,littleEndian:!0,silentValue:213};const t=Ve.exec(e);let i;y(t),i="u"===t[1]?"unsigned":"s"===t[1]?"signed":"float";return{dataType:i,sampleSize:Number(t[2])/8,littleEndian:"be"!==t[3],silentValue:"pcm-u8"===e?o(2,7):0}},Ke=e=>e.startsWith("avc1")||e.startsWith("avc3")?"avc":e.startsWith("hev1")||e.startsWith("hvc1")?"hevc":"vp8"===e?"vp8":e.startsWith("vp09")?"vp9":e.startsWith("av01")?"av1":"mp3"===e||"mp4a.69"===e||"mp4a.6B"===e||"mp4a.6b"===e||"mp4a.40.34"===e?"mp3":e.startsWith("mp4a.40.")||"mp4a.67"===e?"aac":"opus"===e?"opus":"vorbis"===e?"vorbis":"flac"===e?"flac":"ac-3"===e||"ac3"===e?"ac3":"ec-3"===e||"eac3"===e?"eac3":"ulaw"===e?"ulaw":"alaw"===e?"alaw":Ve.test(e)?e:"webvtt"===e?"webvtt":null,je=[44100,48e3,32e3],Xe=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1,-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1,-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1],$e=1483304551,Qe=1231971951,Ge=(e,t)=>3===e?3===t?21:36:3===t?13:21,Ye=(e,t)=>{const i=e>>>24,r=e>>>16&255,n=e>>>8&255,s=255&e;if(255!==i&&255!==r&&255!==n&&255!==s)return{header:null,bytesAdvanced:4};if(255!==i)return{header:null,bytesAdvanced:1};if(224!==(224&r))return{header:null,bytesAdvanced:1};let a=0,o=0;16&r?a=8&r?0:1:(a=1,o=1);const l=r>>3&3,c=r>>1&3,u=(n>>2&3)%3,d=s>>6&3,h=s>>4&3,f=s>>3&1,m=s>>2&1,p=3&s,g=Xe[16*a*4+16*c+(n>>4&15)];if(-1===g)return{header:null,bytesAdvanced:1};const k=1e3*g,y=je[u]>>a+o,b=((e,t,i,r,n)=>0===t?0:1===t?Math.floor(144*i/(r<>1&1);if(null!==t&&t{let t=2130706432,i=0;for(;0!==t;)i>>=1,i|=e&t,t>>=8;return i};var Ze,et;(et=Ze||(Ze={}))[et.FrameCount=1]="FrameCount",et[et.FileSize=2]="FileSize",et[et.Toc=4]="Toc";const tt=[48e3,44100,32e3],it=[24e3,22050,16e3];var rt,nt,st,at;(nt=rt||(rt={}))[nt.NON_IDR_SLICE=1]="NON_IDR_SLICE",nt[nt.SLICE_DPA=2]="SLICE_DPA",nt[nt.SLICE_DPB=3]="SLICE_DPB",nt[nt.SLICE_DPC=4]="SLICE_DPC",nt[nt.IDR=5]="IDR",nt[nt.SEI=6]="SEI",nt[nt.SPS=7]="SPS",nt[nt.PPS=8]="PPS",nt[nt.AUD=9]="AUD",nt[nt.SPS_EXT=13]="SPS_EXT",(at=st||(st={}))[at.RASL_N=8]="RASL_N",at[at.RASL_R=9]="RASL_R",at[at.BLA_W_LP=16]="BLA_W_LP",at[at.RSV_IRAP_VCL23=23]="RSV_IRAP_VCL23",at[at.VPS_NUT=32]="VPS_NUT",at[at.SPS_NUT=33]="SPS_NUT",at[at.PPS_NUT=34]="PPS_NUT",at[at.AUD_NUT=35]="AUD_NUT",at[at.PREFIX_SEI_NUT=39]="PREFIX_SEI_NUT",at[at.SUFFIX_SEI_NUT=40]="SUFFIX_SEI_NUT";const ot=function*(e){let t=0,i=-1;for(;t=e.length-2)break;t=r;let n=0;t+3i&&(yield{offset:i,length:t-i}),i=t+n,t=i):t++}-1!==i&&i{if(t.description){const i=3&w(t.description)[4];return lt(e,i+1)}return ot(e)},ut=e=>31&e,dt=e=>{const t=[],i=e.length;for(let r=0;r{const t=e.reduce((e,t)=>e+ht.byteLength+t.byteLength,0),i=new Uint8Array(t);let r=0;for(const n of e)i.set(ht,r),r+=ht.byteLength,i.set(n,r),r+=n.byteLength;return i},mt=(e,t)=>{const i=e.reduce((e,i)=>e+t+i.byteLength,0),r=new Uint8Array(i);let n=0;for(const s of e){const e=new DataView(r.buffer,r.byteOffset,r.byteLength);switch(t){case 1:e.setUint8(n,s.byteLength);break;case 2:e.setUint16(n,s.byteLength,!1);break;case 3:j(e,n,s.byteLength);break;case 4:e.setUint32(n,s.byteLength,!1)}n+=t,r.set(s,n),n+=s.byteLength}return r},pt=e=>{try{const t=[],i=[],r=[];for(const o of ot(e)){const n=e.subarray(o.offset,o.offset+o.length),s=ut(n[0]);s===rt.SPS?t.push(n):s===rt.PPS?i.push(n):s===rt.SPS_EXT&&r.push(n)}if(0===t.length)return null;if(0===i.length)return null;const n=t[0],s=kt(n);y(null!==s);const a=100===s.profileIdc||110===s.profileIdc||122===s.profileIdc||144===s.profileIdc;return{configurationVersion:1,avcProfileIndication:s.profileIdc,profileCompatibility:s.constraintFlags,avcLevelIndication:s.levelIdc,lengthSizeMinusOne:3,sequenceParameterSets:t,pictureParameterSets:i,chromaFormat:a?s.chromaFormatIdc:null,bitDepthLumaMinus8:a?s.bitDepthLumaMinus8:null,bitDepthChromaMinus8:a?s.bitDepthChromaMinus8:null,sequenceParameterSetExt:a?r:null}}catch(t){return console.error("Error building AVC Decoder Configuration Record:",t),null}},gt={1:{num:1,den:1},2:{num:12,den:11},3:{num:10,den:11},4:{num:16,den:11},5:{num:40,den:33},6:{num:24,den:11},7:{num:20,den:11},8:{num:32,den:11},9:{num:80,den:33},10:{num:18,den:11},11:{num:15,den:11},12:{num:64,den:33},13:{num:160,den:99},14:{num:4,den:3},15:{num:3,den:2},16:{num:2,den:1}},kt=e=>{var t;try{const i=new Ee(dt(e));i.skipBits(1),i.skipBits(2);if(7!==i.readBits(5))return null;const r=i.readAlignedByte(),n=i.readAlignedByte(),s=i.readAlignedByte();S(i);let a=1,o=0,l=0,c=0;if(100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r){a=S(i),3===a&&(c=i.readBits(1)),o=S(i),l=S(i),i.skipBits(1);if(i.readBits(1))for(let e=0;e<(3!==a?8:12);e++){if(i.readBits(1)){const t=e<6?16:64;let r=8,n=8;for(let e=0;ee.level>=s))?t:T(Ne),n=Math.min(Math.floor(r.maxDpbMbs/(e*i)),16);C=n,B=n}else C=0,B=0}return y(null!==B),{profileIdc:r,constraintFlags:n,levelIdc:s,frameMbsOnlyFlag:k,chromaFormatIdc:a,bitDepthLumaMinus8:o,bitDepthChromaMinus8:l,codedWidth:f,codedHeight:m,displayWidth:p,displayHeight:g,pixelAspectRatio:x,colourPrimaries:b,matrixCoefficients:P,transferCharacteristics:w,fullRangeFlag:I,numReorderFrames:C,maxDecFrameBuffering:B}}catch(i){return console.error("Error parsing AVC SPS:",i),null}},yt=e=>{const t=S(e);e.skipBits(4),e.skipBits(4);for(let i=0;i<=t;i++)S(e),S(e),e.skipBits(1);e.skipBits(5),e.skipBits(5),e.skipBits(5),e.skipBits(5)},bt=(e,t)=>{if(t.description){const i=3&w(t.description)[21];return lt(e,i+1)}return ot(e)},Tt=e=>e>>1&63,St=e=>{try{const t=new Ee(dt(e));t.skipBits(16),t.readBits(4);const i=t.readBits(3),r=t.readBits(1),{general_profile_space:n,general_tier_flag:s,general_profile_idc:a,general_profile_compatibility_flags:o,general_constraint_indicator_flags:l,general_level_idc:c}=wt(t,i);S(t);const u=S(t);let d=0;3===u&&(d=t.readBits(1));const h=S(t),f=S(t);let m=h,p=f;if(t.readBits(1)){const e=S(t),i=S(t),r=S(t),n=S(t);let s=1,a=1;const o=0===d?u:0;1===o?(s=2,a=2):2===o&&(s=2,a=1),m-=(e+i)*s,p-=(r+n)*a}const g=S(t),k=S(t);S(t);const y=t.readBits(1);let b=0;for(let e=y?0:i;e<=i;e++)S(t),b=S(t),S(t);S(t),S(t),S(t),S(t),S(t),S(t),t.readBits(1)&&t.readBits(1)&&Pt(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&(t.skipBits(4),t.skipBits(4),S(t),S(t),t.skipBits(1));const T=S(t);if(It(t,T),t.readBits(1)){const e=S(t);for(let i=0;i{try{const t=[],i=[],r=[],n=[];for(const l of ot(e)){const s=e.subarray(l.offset,l.offset+l.length),a=Tt(s[0]);a===st.VPS_NUT?t.push(s):a===st.SPS_NUT?i.push(s):a===st.PPS_NUT?r.push(s):a!==st.PREFIX_SEI_NUT&&a!==st.SUFFIX_SEI_NUT||n.push(s)}if(0===i.length||0===r.length)return null;const s=St(i[0]);if(!s)return null;let a=0;if(r.length>0){const e=r[0],t=new Ee(dt(e));t.skipBits(16),S(t),S(t),t.skipBits(1),t.skipBits(1),t.skipBits(3),t.skipBits(1),t.skipBits(1),S(t),S(t),v(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&S(t),v(t),v(t),t.skipBits(1),t.skipBits(1),t.skipBits(1),t.skipBits(1);const i=t.readBits(1),n=t.readBits(1);a=i||n?i&&!n?2:!i&&n?3:0:0}const o=[...t.length?[{arrayCompleteness:1,nalUnitType:st.VPS_NUT,nalUnits:t}]:[],...i.length?[{arrayCompleteness:1,nalUnitType:st.SPS_NUT,nalUnits:i}]:[],...r.length?[{arrayCompleteness:1,nalUnitType:st.PPS_NUT,nalUnits:r}]:[],...n.length?[{arrayCompleteness:1,nalUnitType:Tt(n[0][0]),nalUnits:n}]:[]];return{configurationVersion:1,generalProfileSpace:s.generalProfileSpace,generalTierFlag:s.generalTierFlag,generalProfileIdc:s.generalProfileIdc,generalProfileCompatibilityFlags:s.generalProfileCompatibilityFlags,generalConstraintIndicatorFlags:s.generalConstraintIndicatorFlags,generalLevelIdc:s.generalLevelIdc,minSpatialSegmentationIdc:s.minSpatialSegmentationIdc,parallelismType:a,chromaFormatIdc:s.chromaFormatIdc,bitDepthLumaMinus8:s.bitDepthLumaMinus8,bitDepthChromaMinus8:s.bitDepthChromaMinus8,avgFrameRate:0,constantFrameRate:0,numTemporalLayers:s.spsMaxSubLayersMinus1+1,temporalIdNested:s.spsTemporalIdNestingFlag,lengthSizeMinusOne:3,arrays:o}}catch(t){return console.error("Error building HEVC Decoder Configuration Record:",t),null}},wt=(e,t)=>{const i=e.readBits(2),r=e.readBits(1),n=e.readBits(5);let s=0;for(let u=0;u<32;u++)s=s<<1|e.readBits(1);const a=new Uint8Array(6);for(let u=0;u<6;u++)a[u]=e.readBits(8);const o=e.readBits(8),l=[],c=[];for(let u=0;u0)for(let u=t;u<8;u++)e.skipBits(2);for(let u=0;u{for(let t=0;t<4;t++)for(let i=0;i<(3===t?2:6);i++){if(e.readBits(1)){const i=Math.min(64,1<<4+(t<<1));t>1&&v(e);for(let t=0;t{const i=[];for(let r=0;r{var n;let s=0,a=0,o=0;if(0!==t&&(a=e.readBits(1)),a){if(t===i){o=t-(S(e)+1)}else o=t-1;e.readBits(1),S(e);const a=null!=(n=r[o])?n:0;for(let t=0;t<=a;t++){e.readBits(1)||e.readBits(1)}s=r[o]}else{const t=S(e),i=S(e);for(let r=0;r{let i=2,r=2,n=2,s=0,a=0,o={num:1,den:1};if(e.readBits(1)){const t=e.readBits(8);if(255===t)o={num:e.readBits(16),den:e.readBits(16)};else{const e=gt[t];e&&(o=e)}}return e.readBits(1)&&e.readBits(1),e.readBits(1)&&(e.readBits(3),s=e.readBits(1),e.readBits(1)&&(i=e.readBits(8),r=e.readBits(8),n=e.readBits(8))),e.readBits(1)&&(S(e),S(e)),e.readBits(1),e.readBits(1),e.readBits(1),e.readBits(1)&&(S(e),S(e),S(e),S(e)),e.readBits(1)&&(e.readBits(32),e.readBits(32),e.readBits(1)&&S(e),e.readBits(1)&&Bt(e,!0,t)),e.readBits(1)&&(e.readBits(1),e.readBits(1),e.readBits(1),a=S(e),S(e),S(e),S(e),S(e)),{pixelAspectRatio:o,colourPrimaries:i,transferCharacteristics:r,matrixCoefficients:n,fullRangeFlag:s,minSpatialSegmentationIdc:a}},Bt=(e,t,i)=>{let r=!1,n=!1,s=!1;r=1===e.readBits(1),n=1===e.readBits(1),(r||n)&&(s=1===e.readBits(1),s&&(e.readBits(8),e.readBits(5),e.readBits(1),e.readBits(5)),e.readBits(4),e.readBits(4),s&&e.readBits(4),e.readBits(5),e.readBits(5),e.readBits(5));for(let a=0;a<=i;a++){let t=!0;1===e.readBits(1)||(t=1===e.readBits(1));let i=!1;t?S(e):i=1===e.readBits(1);let a=1;if(!i){a=S(e)+1}r&&Et(e,a,s),n&&Et(e,a,s)}},Et=(e,t,i)=>{for(let r=0;r{const i=new Set;let r=_t.audAllowed;for(const s of bt(e,t)){if(r===_t.noMoreDataAllowed){i.add(s.offset);continue}const t=Tt(e[s.offset]);if(r===_t.eoBitstreamAllowed&&37!==t){i.add(s.offset);continue}let n=!1;35===t?r>_t.audAllowed?n=!0:r=_t.beforeFirstVcl:t<=31?r>_t.afterFirstVcl?n=!0:r=_t.afterFirstVcl:36===t?r!==_t.afterFirstVcl?n=!0:r=_t.eoBitstreamAllowed:37===t?r<_t.afterFirstVcl?n=!0:r=_t.noMoreDataAllowed:32===t||33===t||34===t||39===t||t>=41&&t<=44||t>=48&&t<=55?r>_t.beforeFirstVcl?n=!0:r=_t.beforeFirstVcl:(38===t||40===t||t>=45&&t<=47||t>=56&&t<=63)&&r<_t.afterFirstVcl&&(n=!0),n&&i.add(s.offset)}if(0===i.size)return null;const n=[];for(const s of bt(e,t))i.has(s.offset)||n.push(e.subarray(s.offset,s.offset+s.length));return((e,t)=>{if(t.description){const i=3&w(t.description)[21];return mt(e,i+1)}return ft(e)})(n,t)},Rt=e=>{const t=new Ee(e);if(2!==t.readBits(2))return null;const i=t.readBits(1),r=(t.readBits(1)<<1)+i;3===r&&t.skipBits(1);if(1===t.readBits(1))return null;if(0!==t.readBits(1))return null;t.skipBits(2);if(4817730!==t.readBits(24))return null;let n=8;if(r>=2){n=t.readBits(1)?12:10}const s=t.readBits(3);let a=0,o=0;if(7!==s){if(o=t.readBits(1),1===r||3===r){const e=t.readBits(1),i=t.readBits(1);a=e||i?e&&!i?2:1:3,t.skipBits(1)}else a=1}else a=3,o=1;const l=(t.readBits(16)+1)*(t.readBits(16)+1);let c=T(Oe).level;for(const u of Oe)if(l<=u.maxPictureSize){c=u.level;break}return{profile:r,level:c,bitDepth:n,chromaSubsampling:a,videoFullRangeFlag:o,colourPrimaries:2===s?1:1===s?6:2,transferCharacteristics:2===s?1:1===s?6:2,matrixCoefficients:7===s?0:2===s?1:1===s?6:2}},Dt=function*(e){const t=new Ee(e),i=()=>{let e=0;for(let i=0;i<8;i++){const r=t.readAlignedByte();if(e|=(127&r)<<7*i,!(128&r))break;if(7===i&&128&r)return null}return e>=o(2,32)-1?null:e};for(;t.getBitsLeft()>=8;){t.skipBits(1);const r=t.readBits(4),n=t.readBits(1),s=t.readBits(1);let a;if(t.skipBits(1),n&&t.skipBits(8),s){const e=i();if(null===e)return;a=e}else a=Math.floor(t.getBitsLeft()/8);y(t.pos%8===0),yield{type:r,data:e.subarray(t.pos/8,t.pos/8+a)},t.skipBits(8*a)}},Mt=e=>{for(const{type:t,data:i}of Dt(e)){if(1!==t)continue;const e=new Ee(i),r=e.readBits(3);e.readBits(1);const n=e.readBits(1);let s=0,a=0,o=0;if(n)s=e.readBits(5);else{if(e.readBits(1)){e.skipBits(32),e.skipBits(32);if(e.readBits(1))return null}const t=e.readBits(1);t&&(o=e.readBits(5),e.skipBits(32),e.skipBits(5),e.skipBits(5));const i=e.readBits(5);for(let r=0;r<=i;r++){e.skipBits(12);const i=e.readBits(5);if(0===r&&(s=i),i>7){const t=e.readBits(1);0===r&&(a=t)}if(t){if(e.readBits(1)){const t=o+1;e.skipBits(t),e.skipBits(t),e.skipBits(1)}}e.readBits(1)&&e.skipBits(4)}}const l=e.readBits(4),c=e.readBits(4),u=l+1;e.skipBits(u);const d=c+1;e.skipBits(d);let h=0;if(h=n?0:e.readBits(1),h&&(e.skipBits(4),e.skipBits(3)),e.skipBits(1),e.skipBits(1),e.skipBits(1),!n){e.skipBits(1),e.skipBits(1),e.skipBits(1),e.skipBits(1);const t=e.readBits(1);t&&(e.skipBits(1),e.skipBits(1));let i=0;if(i=e.readBits(1)?2:e.readBits(1),i>0){e.readBits(1)||e.skipBits(1)}t&&e.skipBits(3)}e.skipBits(1),e.skipBits(1),e.skipBits(1);const f=e.readBits(1);let m=8;if(2===r&&f){m=e.readBits(1)?12:10}else r<=2&&(m=f?10:8);let p=0;1!==r&&(p=e.readBits(1));let g=1,k=1,y=0;return p||(0===r?(g=1,k=1):1===r?(g=0,k=0):12===m&&(g=e.readBits(1),g&&(k=e.readBits(1))),g&&k&&(y=e.readBits(2))),{profile:r,level:s,tier:a,bitDepth:m,monochrome:p,chromaSubsamplingX:g,chromaSubsamplingY:k,chromaSamplePosition:y}}return null},Nt=[480,960,1920,2880,480,960,1920,2880,480,960,1920,2880,480,960,480,960,120,240,480,960,120,240,480,960,120,240,480,960,120,240,480,960],Ot=e=>{if(e.length<7)throw new Error("Setup header is too short.");if(5!==e[0])throw new Error("Wrong packet type in Setup header.");if("vorbis"!==String.fromCharCode(...e.slice(1,7)))throw new Error("Invalid packet signature in Setup header.");const t=e.length,i=new Uint8Array(t);for(let u=0;u97;)if(1===r.readBits(1)){n=r.pos;break}if(0===n)throw new Error("Invalid Setup header: framing bit not found.");let s=0,a=!1,o=0;for(;r.getBitsLeft()>=97;){const e=r.pos,t=r.readBits(8),i=r.readBits(16),n=r.readBits(16);if(t>63||0!==i||0!==n){r.pos=e;break}if(r.skipBits(1),s++,s>64)break;r.clone().readBits(6)+1===s&&(a=!0,o=s)}if(!a)throw new Error("Invalid Setup header: mode header not found.");if(o>63)throw new Error(`Unsupported mode count: ${o}.`);const l=o;r.pos=0,r.skipBits(n);const c=Array(l).fill(0);for(let u=l-1;u>=0;u--)r.skipBits(40),c[u]=r.readBits(1);return{modeBlockflags:c}},Lt=(e,t,i)=>{switch(e){case"avc":for(const e of ct(i,t)){const t=i[e.offset],r=ut(t);if(r>=rt.NON_IDR_SLICE&&r<=rt.SLICE_DPC)return"delta";if(r===rt.IDR)return"key";if(r===rt.SEI&&(!de()||fe()>=144)){const t=i.subarray(e.offset,e.offset+e.length),r=dt(t);let n=1;do{let e=0;for(;;){const t=r[n++];if(void 0===t)break;if(e+=t,t<255)break}let t=0;for(;;){const e=r[n++];if(void 0===e)break;if(t+=e,e<255)break}if(e===6){const e=new Ee(r);e.pos=8*n;const t=S(e),i=e.readBits(1);if(0===t&&1===i)return"key"}n+=t}while(n{var i,r;const n=P(e);let s=0;const a=n.getUint32(s,!0);s+=4;const o=I.decode(e.subarray(s,s+a));s+=a,a>0&&(null!=t.raw||(t.raw={}),null!=(i=t.raw).vendor||(i.vendor=o));const l=n.getUint32(s,!0);s+=4;for(let c=0;c0&&(null!=t.trackNumber||(t.trackNumber=i)),r&&Number.isInteger(r)&&r>0&&(null!=t.tracksTotal||(t.tracksTotal=r))}break;case"TRACKTOTAL":{const e=Number.parseInt(c,10);Number.isInteger(e)&&e>0&&(null!=t.tracksTotal||(t.tracksTotal=e))}break;case"DISCNUMBER":{const e=c.split("/"),i=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(null!=t.discNumber||(t.discNumber=i)),r&&Number.isInteger(r)&&r>0&&(null!=t.discsTotal||(t.discsTotal=r))}break;case"DISCTOTAL":{const e=Number.parseInt(c,10);Number.isInteger(e)&&e>0&&(null!=t.discsTotal||(t.discsTotal=e))}break;case"DATE":{const e=new Date(c);Number.isNaN(e.getTime())||null!=t.date||(t.date=e)}break;case"GENRE":null!=t.genre||(t.genre=c);break;case"METADATA_BLOCK_PICTURE":{const e=ge(c),i=P(e),r=i.getUint32(0,!1),n=i.getUint32(4,!1),s=String.fromCharCode(...e.subarray(8,8+n)),a=i.getUint32(8+n,!1),o=I.decode(e.subarray(12+n,12+n+a)),l=i.getUint32(n+a+28),u=e.subarray(n+a+32,n+a+32+l);null!=t.images||(t.images=[]),t.images.push({data:u,mimeType:s,kind:3===r?"coverFront":4===r?"coverBack":"unknown",name:void 0,description:o||void 0})}}}},Wt=[2,1,2,3,3,4,4,5],Vt=e=>{if(e.length<7)return null;if(11!==e[0]||119!==e[1])return null;const t=new Ee(e);t.skipBits(16),t.skipBits(16);const i=t.readBits(2);if(3===i)return null;const r=t.readBits(6),n=t.readBits(5);if(n>8)return null;const s=t.readBits(3),a=t.readBits(3);0!==(1&a)&&1!==a&&t.skipBits(2),0!==(4&a)&&t.skipBits(2),2===a&&t.skipBits(2);return{fscod:i,bsid:n,bsmod:s,acmod:a,lfeon:t.readBits(1),bitRateCode:Math.floor(r/2)}},Ht=[128,138,192,128,140,192,160,174,240,160,176,240,192,208,288,192,210,288,224,242,336,224,244,336,256,278,384,256,280,384,320,348,480,320,350,480,384,416,576,384,418,576,448,486,672,448,488,672,512,556,768,512,558,768,640,696,960,640,698,960,768,834,1152,768,836,1152,896,974,1344,896,976,1344,1024,1114,1536,1024,1116,1536,1280,1392,1920,1280,1394,1920,1536,1670,2304,1536,1672,2304,1792,1950,2688,1792,1952,2688,2048,2228,3072,2048,2230,3072,2304,2506,3456,2304,2508,3456,2560,2786,3840,2560,2788,3840],Kt=[1,2,3,6],jt=e=>{if(e.length<6)return null;if(11!==e[0]||119!==e[1])return null;const t=new Ee(e);t.skipBits(16);const i=t.readBits(2);if(t.skipBits(3),0!==i&&2!==i)return null;const r=t.readBits(11),n=t.readBits(2);let s,a=0;3===n?(a=t.readBits(2),s=3):s=t.readBits(2);const o=t.readBits(3),l=t.readBits(1),c=t.readBits(5);if(c<11||c>16)return null;const u=Kt[s];let d;d=n<3?tt[n]/1e3:it[a]/1e3;return{dataRate:Math.round((r+1)*d/(16*u)),substreams:[{fscod:n,fscod2:a,bsid:c,bsmod:0,acmod:o,lfeon:l,numDepSub:0,chanLoc:0}]}},Xt=e=>{const t=e.substreams[0];return y(t),t.fscod<3?tt[t.fscod]:null!==t.fscod2&&t.fscod2<3?it[t.fscod2]:null},$t=e=>{const t=e.substreams[0];y(t);let i=Wt[t.acmod]+t.lfeon;if(t.numDepSub>0){const e=[2,2,1,1,2,2,2,1,1];for(let r=0;r<9;r++)t.chanLoc&1<<8-r&&(i+=e[r])}return i};class Qt{constructor(e){this.input=e}dispose(){}}const Gt=new Uint8Array(0);class Yt{constructor(e,t,i,r,n=-1,s,a){if(this.data=e,this.type=t,this.timestamp=i,this.duration=r,this.sequenceNumber=n,e===Gt&&void 0===s)throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets.");if(void 0===s&&(s=e.byteLength),!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("key"!==t&&"delta"!==t)throw new TypeError('type must be either "key" or "delta".');if(!Number.isFinite(i))throw new TypeError("timestamp must be a number.");if(!Number.isFinite(r)||r<0)throw new TypeError("duration must be a non-negative number.");if(!Number.isFinite(n))throw new TypeError("sequenceNumber must be a number.");if(!Number.isInteger(s)||s<0)throw new TypeError("byteLength must be a non-negative integer.");if(void 0!==a&&("object"!==typeof a||!a))throw new TypeError("sideData, when provided, must be an object.");if(void 0!==(null==a?void 0:a.alpha)&&!(a.alpha instanceof Uint8Array))throw new TypeError("sideData.alpha, when provided, must be a Uint8Array.");if(void 0!==(null==a?void 0:a.alphaByteLength)&&(!Number.isInteger(a.alphaByteLength)||a.alphaByteLength<0))throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer.");this.byteLength=s,this.sideData=null!=a?a:{},this.sideData.alpha&&void 0===this.sideData.alphaByteLength&&(this.sideData.alphaByteLength=this.sideData.alpha.byteLength)}get isMetadataOnly(){return this.data===Gt}get microsecondTimestamp(){return Math.trunc(te*this.timestamp)}get microsecondDuration(){return Math.trunc(te*this.duration)}toEncodedVideoChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}alphaToEncodedVideoChunk(e=this.type){if(!this.sideData.alpha)throw new TypeError("This packet does not contain alpha side data.");if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.sideData.alpha,type:e,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}toEncodedAudioChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to an audio chunk.");if("undefined"===typeof EncodedAudioChunk)throw new Error("Your browser does not support EncodedAudioChunk.");return new EncodedAudioChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}static fromEncodedChunk(e,t){var i;if(!(e instanceof EncodedVideoChunk||e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk.");const r=new Uint8Array(e.byteLength);return e.copyTo(r),new Yt(r,e.type,e.timestamp/1e6,(null!=(i=e.duration)?i:0)/1e6,void 0,void 0,t)}clone(e){var t,i,r,n,s,a;if(void 0!==e&&("object"!==typeof e||null===e))throw new TypeError("options, when provided, must be an object.");if(void 0!==(null==e?void 0:e.data)&&!(e.data instanceof Uint8Array))throw new TypeError("options.data, when provided, must be a Uint8Array.");if(void 0!==(null==e?void 0:e.type)&&"key"!==e.type&&"delta"!==e.type)throw new TypeError('options.type, when provided, must be either "key" or "delta".');if(void 0!==(null==e?void 0:e.timestamp)&&!Number.isFinite(e.timestamp))throw new TypeError("options.timestamp, when provided, must be a number.");if(void 0!==(null==e?void 0:e.duration)&&!Number.isFinite(e.duration))throw new TypeError("options.duration, when provided, must be a number.");if(void 0!==(null==e?void 0:e.sequenceNumber)&&!Number.isFinite(e.sequenceNumber))throw new TypeError("options.sequenceNumber, when provided, must be a number.");if(void 0!==(null==e?void 0:e.sideData)&&("object"!==typeof e.sideData||null===e.sideData))throw new TypeError("options.sideData, when provided, must be an object.");return new Yt(null!=(t=null==e?void 0:e.data)?t:this.data,null!=(i=null==e?void 0:e.type)?i:this.type,null!=(r=null==e?void 0:e.timestamp)?r:this.timestamp,null!=(n=null==e?void 0:e.duration)?n:this.duration,null!=(s=null==e?void 0:e.sequenceNumber)?s:this.sequenceNumber,this.byteLength,null!=(a=null==e?void 0:e.sideData)?a:this.sideData)}}const Jt=e=>{const t=P(e);let i=0;const r=t.getUint8(i);i+=1,i+=3;const n=N(e.subarray(i,i+16));i+=16;let s=null;if(r>0){const r=t.getUint32(i);if(i+=4,r>0){s=[];for(let t=0;te.systemId===t.systemId&&((e,t)=>{if(e.length!==t.length)return!1;for(let i=0;i{let t=Ra(e);const i=Wa(e,4);let r=8;1===t&&(t=Oa(e),r=16);const n=t-r;return n<0?null:{name:i,totalSize:t,headerSize:r,contentSize:n}},ti=e=>Ma(e)/65536,ii=e=>Ma(e)/1073741824,ri=e=>{let t=0;for(let i=0;i<4;i++){t<<=7;const i=Ca(e);if(t|=127&i,0===(128&i))break}return t},ni=e=>{let t=Ea(e);return e.skip(2),t=Math.min(t,e.remainingLength),I.decode(xa(e,t))},si=e=>{const t=ei(e);if(!t||"data"!==t.name)return null;if(e.remainingLength<8)return null;const i=Ra(e);e.skip(4);const r=xa(e,t.contentSize-8);switch(i){case 1:return I.decode(r);case 2:return new TextDecoder("utf-16be").decode(r);case 13:return new xe(r,"image/jpeg");case 14:return new xe(r,"image/png");case 27:return new xe(r,"image/bmp");default:return r}},ai=16,oi=new Uint32Array(256),li=new Uint32Array(256),ci=new Uint32Array(256),ui=new Uint32Array(256),di=new Uint32Array(256),hi=new Uint32Array(256),fi=new Uint32Array(10);let mi=!1;class pi{constructor(){this.roundkey=new Uint32Array(44),this.iv=new Uint32Array(ai/Uint32Array.BYTES_PER_ELEMENT),this.in=new Uint8Array(ai),this.out=new Uint8Array(ai),this.inView=new DataView(this.in.buffer),this.outView=new DataView(this.out.buffer)}init({key:e,iv:t}){y(16===e.byteLength),y(16===t.byteLength),mi||(()=>{const e=new Uint8Array(256),t=new Uint8Array(256),i=new Uint8Array(256);for(let s=0,a=1;s<256;s++)i[s]=a,t[a]=s,a=a^a<<1^(128&a?283:0);const r=(e,r)=>e&&r?i[(t[e]+t[r])%255]:0;e[0]=99;for(let s=1;s<256;s++){const r=i[255-t[s]];let n=r^r<<1^r<<2^r<<3^r<<4;n=n>>>8^255&n^99,e[s]=n}for(let s=0;s<256;s++){const t=e[s],i=e.indexOf(s);oi[s]=t<<24|t<<16|t<<8|t,hi[s]=i<<24|i<<16|i<<8|i;const n=r(i,14)<<24|r(i,9)<<16|r(i,13)<<8|r(i,11);li[s]=n,ci[s]=n>>>8|n<<24,ui[s]=n>>>16|n<<16,di[s]=n>>>24|n<<8}let n=1;for(let s=0;s<10;s++)fi[s]=n<<24,n=n<<1^(128&n?283:0);mi=!0})();const i=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new DataView(t.buffer,t.byteOffset,t.byteLength);this.roundkey[0]=i.getUint32(0,!1),this.roundkey[1]=i.getUint32(4,!1),this.roundkey[2]=i.getUint32(8,!1),this.roundkey[3]=i.getUint32(12,!1),this.iv[0]=r.getUint32(0,!1),this.iv[1]=r.getUint32(4,!1),this.iv[2]=r.getUint32(8,!1),this.iv[3]=r.getUint32(12,!1);for(let n=4;n<44;n+=4){const e=this.roundkey[n-1];this.roundkey[n]=this.roundkey[n-4]^4278190080&oi[e>>>16&255]^16711680&oi[e>>>8&255]^65280&oi[e>>>0&255]^255&oi[e>>>24&255]^fi[n/4-1],this.roundkey[n+1]=this.roundkey[n-3]^this.roundkey[n],this.roundkey[n+2]=this.roundkey[n-2]^this.roundkey[n+1],this.roundkey[n+3]=this.roundkey[n-1]^this.roundkey[n+2]}for(let n=0,s=40;n>>24&255]]^ci[255&oi[t>>>16&255]]^ui[255&oi[t>>>8&255]]^di[255&oi[t>>>0&255]]}}decrypt(){let e=this.inView.getUint32(0,!1)^this.roundkey[0],t=this.inView.getUint32(4,!1)^this.roundkey[1],i=this.inView.getUint32(8,!1)^this.roundkey[2],r=this.inView.getUint32(12,!1)^this.roundkey[3];const n=this.inView.getUint32(0,!1),s=this.inView.getUint32(4,!1),a=this.inView.getUint32(8,!1),o=this.inView.getUint32(12,!1);let l,c,u,d;for(let g=1;g<10;g++){const n=4*g;l=li[e>>>24]^ci[r>>>16&255]^ui[i>>>8&255]^di[255&t]^this.roundkey[n],c=li[t>>>24]^ci[e>>>16&255]^ui[r>>>8&255]^di[255&i]^this.roundkey[n+1],u=li[i>>>24]^ci[t>>>16&255]^ui[e>>>8&255]^di[255&r]^this.roundkey[n+2],d=li[r>>>24]^ci[i>>>16&255]^ui[t>>>8&255]^di[255&e]^this.roundkey[n+3],e=l,t=c,i=u,r=d}const h=4278190080&hi[e>>>24&255]^16711680&hi[r>>>16&255]^65280&hi[i>>>8&255]^255&hi[t>>>0&255]^this.roundkey[40],f=4278190080&hi[t>>>24&255]^16711680&hi[e>>>16&255]^65280&hi[r>>>8&255]^255&hi[i>>>0&255]^this.roundkey[41],m=4278190080&hi[i>>>24&255]^16711680&hi[t>>>16&255]^65280&hi[e>>>8&255]^255&hi[r>>>0&255]^this.roundkey[42],p=4278190080&hi[r>>>24&255]^16711680&hi[i>>>16&255]^65280&hi[t>>>8&255]^255&hi[e>>>0&255]^this.roundkey[43];this.outView.setUint32(0,h^this.iv[0],!1),this.outView.setUint32(4,f^this.iv[1],!1),this.outView.setUint32(8,m^this.iv[2],!1),this.outView.setUint32(12,p^this.iv[3],!1),this.iv[0]=n,this.iv[1]=s,this.iv[2]=a,this.iv[3]=o}}class gi extends Qt{constructor(e){super(e),this.moovSlice=null,this.currentTrack=null,this.tracks=[],this.metadataPromise=null,this.movieTimescale=-1,this.movieDurationInTimescale=-1,this.isQuickTime=!1,this.metadataTags={},this.currentMetadataKeys=null,this.isFragmented=!1,this.fragmentTrackDefaults=[],this.psshBoxes=[],this.currentFragment=null,this.lastReadFragment=null,this.decryptionKeyCache=new Map,this.reader=e._reader}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.tracks.map(e=>e.trackBacking)})}getMimeType(){return d(this,null,function*(){yield this.readMetadata();const e=yield this.getTrackBackings(),t=yield Promise.all(e.map(e=>e.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null})));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isQuickTime?"quicktime":"mp4");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({isQuickTime:this.isQuickTime,hasVideo:this.tracks.some(e=>{var t;return"video"===(null==(t=e.info)?void 0:t.type)}),hasAudio:this.tracks.some(e=>{var t;return"audio"===(null==(t=e.info)?void 0:t.type)}),codecStrings:t.filter(Boolean)})})}getMetadataTags(){return d(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}readMetadata(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){let e=0,t=!1;for(;;){let i=this.reader.requestSliceRange(e,8,16);if(i instanceof Promise&&(i=yield i),!i)break;const r=e,n=ei(i);if(!n)break;if("ftyp"===n.name||"styp"===n.name){const e=Wa(i,4);this.isQuickTime="qt "===e}else{if("moov"===n.name){let e=this.reader.requestSlice(i.filePos,n.contentSize);if(e instanceof Promise&&(e=yield e),!e)break;this.moovSlice=e,this.readContiguousBoxes(this.moovSlice);for(const t of this.tracks){const e=t.editListPreviousSegmentDurations/this.movieTimescale;t.editListOffset-=Math.round(e*t.timescale)}t=this.isFragmented&&null!==this.reader.fileSize&&this.reader.fileSize>r+n.totalSize;break}if("moof"===n.name){if(!this.input._initInput)throw new Error('"moof" box encountered with no "moov" box present; this file is likely a Segment as described in ISO/IEC 14496-12 Section 8.16. A separate init file that contains a "moov" box is required to read this file, please provide it using InputOptions.initInput.');const e=yield this.input._initInput._getDemuxer();if(e.constructor!==gi)throw new Error("Init input must match the input's format.");yield e.readMetadata(),this.movieTimescale=e.movieTimescale,this.movieDurationInTimescale=e.movieDurationInTimescale,this.metadataTags=e.metadataTags,this.isFragmented=!0,this.fragmentTrackDefaults=e.fragmentTrackDefaults,this.psshBoxes=e.psshBoxes;for(const t of e.tracks){const e={id:t.id,demuxer:this,trackBacking:null,disposition:t.disposition,timescale:t.timescale,durationInMediaTimescale:t.durationInMediaTimescale,durationInMovieTimescale:t.durationInMovieTimescale,rotation:t.rotation,internalCodecId:t.internalCodecId,name:t.name,languageCode:t.languageCode,sampleTableByteOffset:null,sampleTable:null,fragmentLookupTable:[],currentFragmentState:null,fragmentPositionCache:[],editListPreviousSegmentDurations:t.editListPreviousSegmentDurations,editListOffset:t.editListOffset,encryptionInfo:t.encryptionInfo,encryptionAuxInfo:null,frmaCodecString:null,info:t.info};if(t.trackBacking)if(y(e.info),"video"===e.info.type&&-1!==e.info.width){const t=e;e.trackBacking=new yi(t),this.tracks.push(e)}else if("audio"===e.info.type&&-1!==e.info.numberOfChannels){const t=e;e.trackBacking=new bi(t),this.tracks.push(e)}}t=!1;break}}e=r+n.totalSize}if(t){y(null!==this.reader.fileSize);let e=this.reader.requestSlice(this.reader.fileSize-4,4);e instanceof Promise&&(e=yield e),y(e);const t=Ra(e),i=this.reader.fileSize-t;if(i>=0&&i<=this.reader.fileSize-16){let e=this.reader.requestSliceRange(i,8,16);if(e instanceof Promise&&(e=yield e),e){const t=ei(e);if(t&&"mfra"===t.name){let i=this.reader.requestSlice(e.filePos,t.contentSize);i instanceof Promise&&(i=yield i),i&&this.readContiguousBoxes(i)}}}}}))()}getSampleTableForTrack(e){var t,i;if(e.sampleTable)return e.sampleTable;const r={sampleTimingEntries:[],sampleCompositionTimeOffsets:[],sampleSizes:[],keySampleIndices:null,chunkOffsets:[],sampleToChunk:[],presentationTimestamps:null,presentationTimestampIndexMap:null};if(e.sampleTable=r,null===e.sampleTableByteOffset)return r;y(this.moovSlice);const n=this.moovSlice.slice(e.sampleTableByteOffset);this.currentTrack=e,this.traverseBox(n),this.currentTrack=null;if("audio"===(null==(t=e.info)?void 0:t.type)&&e.info.codec&&De.includes(e.info.codec)&&0===r.sampleCompositionTimeOffsets.length){y("audio"===(null==(i=e.info)?void 0:i.type));const t=He(e.info.codec),n=[],s=[];for(let i=0;ie.startIndex),u=r.sampleTimingEntries[c],d=z(r.sampleTimingEntries,l,e=>e.startIndex),h=r.sampleTimingEntries[d],f=u.startDecodeTimestamp+(o-u.startIndex)*u.delta,m=h.startDecodeTimestamp+(l-h.startIndex)*h.delta-f,p=T(n);p&&p.delta===m?p.count++:n.push({startIndex:a.startChunkIndex+i,startDecodeTimestamp:f,count:1,delta:m});const g=a.samplesPerChunk*t.sampleSize*e.info.numberOfChannels;s.push(g)}a.startSampleIndex=a.startChunkIndex,a.samplesPerChunk=1}r.sampleTimingEntries=n,r.sampleSizes=s}if(r.sampleCompositionTimeOffsets.length>0){r.presentationTimestamps=[];for(const e of r.sampleTimingEntries)for(let t=0;te.presentationTimestamp-t.presentationTimestamp),r.presentationTimestampIndexMap=Array(r.presentationTimestamps.length).fill(-1);for(let e=0;ee.moofOffset===s.moofOffset);if(r)Pi(e,r.timestamp);else{const t=z(i,s.moofOffset-1,e=>e.moofOffset);if(-1!==t){const r=i[t];Pi(e,r.endTimestamp)}}e.startTimestampIsFinal=!0}const r=z(i,e.startTimestamp,e=>e.startTimestamp);if(-1!==r&&i[r].moofOffset===s.moofOffset||i.splice(r+1,0,{moofOffset:s.moofOffset,startTimestamp:e.startTimestamp,endTimestamp:e.endTimestamp}),e.encryptionAuxInfo&&t.encryptionInfo){const i=yield Bi(this.reader,t.encryptionInfo,e.encryptionAuxInfo);for(let t=0;t0){t.languageCode="";for(let e=0;e<3;e++)t.languageCode=String.fromCharCode(96+(31&r))+t.languageCode,r>>=5;ee(t.languageCode)||(t.languageCode=Q)}}break;case"hdlr":{const t=this.currentTrack;if(!t)break;e.skip(8);const i=Wa(e,4);"vide"===i?t.info={type:"video",width:-1,height:-1,squarePixelWidth:-1,squarePixelHeight:-1,codec:null,codecDescription:null,colorSpace:null,avcType:null,avcCodecInfo:null,hevcCodecInfo:null,vp9CodecInfo:null,av1CodecInfo:null}:"soun"===i&&(t.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null,aacCodecInfo:null,pcmLittleEndian:!1,pcmSampleSize:null})}break;case"stbl":{const t=this.currentTrack;if(!t)break;t.sampleTableByteOffset=ce,this.readContiguousBoxes(e.slice(de,ue.contentSize))}break;case"stsd":{const t=this.currentTrack;if(!t)break;if(null===t.info||t.sampleTable)break;const i=Ca(e);e.skip(3);const r=Ra(e);for(let n=0;n0&&(1===a?(e.skip(4),l=8*Ra(e),e.skip(8)):2===a&&(e.skip(4),c=qa(e),o=Ra(e),e.skip(4),l=Ra(e),u=Ra(e),e.skip(8))),t.info.numberOfChannels=o,t.info.sampleRate=c,t.frmaCodecString=null,this.readContiguousBoxes(e.slice(e.filePos,r+n.totalSize-e.filePos));const d="enca"===s?t.frmaCodecString:s;if(t.frmaCodecString=null,"mp4a"===d);else if("opus"===d)t.info.codec="opus",t.info.sampleRate=We;else if("flac"===d)t.info.codec="flac";else if("ulaw"===d)t.info.codec="ulaw";else if("alaw"===d)t.info.codec="alaw";else if("ac-3"===d)t.info.codec="ac3";else if("ec-3"===d)t.info.codec="eac3";else if("twos"===d)8===l?t.info.codec="pcm-s8":16===l?t.info.codec=t.info.pcmLittleEndian?"pcm-s16":"pcm-s16be":(console.warn(`Unsupported sample size ${l} for codec 'twos'.`),t.info.codec=null);else if("sowt"===d)8===l?t.info.codec="pcm-s8":16===l?t.info.codec="pcm-s16":(console.warn(`Unsupported sample size ${l} for codec 'sowt'.`),t.info.codec=null);else if("raw "===d)t.info.codec="pcm-u8";else if("in24"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-s24":"pcm-s24be";else if("in32"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-s32":"pcm-s32be";else if("fl32"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-f32":"pcm-f32be";else if("fl64"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-f64":"pcm-f64be";else if("ipcm"===d){const e=t.info.pcmSampleSize;t.info.pcmLittleEndian?16===e?t.info.codec="pcm-s16":24===e?t.info.codec="pcm-s24":32===e?t.info.codec="pcm-s32":(console.warn(`Invalid ipcm sample size ${e}.`),t.info.codec=null):16===e?t.info.codec="pcm-s16be":24===e?t.info.codec="pcm-s24be":32===e?t.info.codec="pcm-s32be":(console.warn(`Invalid ipcm sample size ${e}.`),t.info.codec=null)}else if("fpcm"===d){const e=t.info.pcmSampleSize;t.info.pcmLittleEndian?32===e?t.info.codec="pcm-f32":64===e?t.info.codec="pcm-f64":(console.warn(`Invalid fpcm sample size ${e}.`),t.info.codec=null):32===e?t.info.codec="pcm-f32be":64===e?t.info.codec="pcm-f64be":(console.warn(`Invalid fpcm sample size ${e}.`),t.info.codec=null)}else if("lpcm"===d&&null!==u){const e=l+7>>3,i=Boolean(1&u),r=Boolean(2&u),n=4&u?-1:0;l>0&&l<=64&&(i?32===l&&(t.info.codec=r?"pcm-f32be":"pcm-f32"):n&1<0?(t.encryptionInfo.defaultCryptByteBlock=r>>4,t.encryptionInfo.defaultSkipByteBlock=15&r):(t.encryptionInfo.defaultCryptByteBlock=0,t.encryptionInfo.defaultSkipByteBlock=0),t.encryptionInfo.defaultIsProtected=0!==Ca(e),t.encryptionInfo.defaultPerSampleIvSize=Ca(e),t.encryptionInfo.defaultKid=N(xa(e,16)),t.encryptionInfo.defaultIsProtected&&0===t.encryptionInfo.defaultPerSampleIvSize){const i=Ca(e),r=new Uint8Array(16);r.set(xa(e,i),0),t.encryptionInfo.defaultConstantIv=r}}break;case"avcC":{const t=this.currentTrack;if(!t)break;y(t.info),t.info.codecDescription=xa(e,ue.contentSize)}break;case"hvcC":{const t=this.currentTrack;if(!t)break;y(t.info),t.info.codecDescription=xa(e,ue.contentSize)}break;case"vpcC":{const i=this.currentTrack;if(!i)break;y("video"===(null==(t=i.info)?void 0:t.type)),e.skip(4);const r=Ca(e),n=Ca(e),s=Ca(e),a=s>>4,o=s>>1&7,l=1&s,c=Ca(e),u=Ca(e),d=Ca(e);i.info.vp9CodecInfo={profile:r,level:n,bitDepth:a,chromaSubsampling:o,videoFullRangeFlag:l,colourPrimaries:c,transferCharacteristics:u,matrixCoefficients:d}}break;case"av1C":{const t=this.currentTrack;if(!t)break;y("video"===(null==(i=t.info)?void 0:i.type)),e.skip(1);const r=Ca(e),n=r>>5,s=31&r,a=Ca(e),o=a>>7,l=a>>6&1,c=a>>4&1,u=a>>3&1,d=a>>2&1,h=3&a,f=2===n&&l?a>>5&1?12:10:l?10:8;t.info.av1CodecInfo={profile:n,level:s,tier:o,bitDepth:f,monochrome:c,chromaSubsamplingX:u,chromaSubsamplingY:d,chromaSamplePosition:h}}break;case"colr":{const t=this.currentTrack;if(!t)break;y("video"===(null==(r=t.info)?void 0:r.type));if("nclx"!==Wa(e,4))break;const i=Ea(e),n=Ea(e),s=Ea(e),a=Boolean(128&Ca(e));t.info.colorSpace={primaries:B[i],transfer:_[n],matrix:F[s],fullRange:a}}break;case"pasp":{const t=this.currentTrack;if(!t)break;y("video"===(null==(n=t.info)?void 0:n.type));const i=Ra(e),r=Ra(e);i>0&&r>0&&(i>r?t.info.squarePixelWidth=Math.round(t.info.width*i/r):t.info.squarePixelHeight=Math.round(t.info.height*r/i))}break;case"esds":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(s=t.info)?void 0:s.type)),e.skip(4);y(3===Ca(e)),ri(e),e.skip(2);const i=Ca(e),r=0!==(64&i),n=0!==(32&i);if(0!==(128&i)&&e.skip(2),r){const t=Ca(e);e.skip(t)}n&&e.skip(2);y(4===Ca(e));const a=ri(e),o=e.filePos,l=Ca(e);if(64===l||103===l?(t.info.codec="aac",t.info.aacCodecInfo={isMpeg2:103===l,objectType:null}):105===l||107===l?t.info.codec="mp3":221===l?t.info.codec="vorbis":console.warn(`Unsupported audio codec (objectTypeIndication ${l}) - discarding track.`),e.skip(12),a>e.filePos-o){y(5===Ca(e));const i=ri(e);if(t.info.codecDescription=xa(e,i),"aac"===t.info.codec){const e=Fe(t.info.codecDescription);null!==e.numberOfChannels&&(t.info.numberOfChannels=e.numberOfChannels),null!==e.sampleRate&&(t.info.sampleRate=e.sampleRate)}}}break;case"enda":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(a=t.info)?void 0:a.type)),t.info.pcmLittleEndian=!!(255&Ea(e))}break;case"pcmC":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(o=t.info)?void 0:o.type)),e.skip(4);const i=Ca(e);t.info.pcmLittleEndian=Boolean(1&i),t.info.pcmSampleSize=Ca(e)}break;case"dOps":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(l=t.info)?void 0:l.type)),e.skip(1);const i=Ca(e),r=Ea(e),n=Ra(e),s=Aa(e),a=Ca(e);let o;o=0!==a?xa(e,2+i):new Uint8Array(0);const c=new Uint8Array(19+o.byteLength),u=new DataView(c.buffer);u.setUint32(0,1332770163,!1),u.setUint32(4,1214603620,!1),u.setUint8(8,1),u.setUint8(9,i),u.setUint16(10,r,!0),u.setUint32(12,n,!0),u.setInt16(16,s,!0),u.setUint8(18,a),c.set(o,19),t.info.codecDescription=c,t.info.numberOfChannels=i}break;case"dfLa":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(d=t.info)?void 0:d.type)),e.skip(4);const i=127,r=128,n=e.filePos;for(;e.filePos>>12,n=1+(i>>9&7);t.info.sampleRate=r,t.info.numberOfChannels=n,e.skip(20)}else e.skip(s);if(n&r)break}const s=e.filePos;e.filePos=n;const a=xa(e,s-n),o=new Uint8Array(4+a.byteLength);new DataView(o.buffer).setUint32(0,1716281667,!1),o.set(a,4),t.info.codecDescription=o}break;case"dac3":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(h=t.info)?void 0:h.type));const i=xa(e,3),r=new Ee(i),n=r.readBits(2);r.skipBits(8);const s=r.readBits(3),a=r.readBits(1);n<3&&(t.info.sampleRate=tt[n]),t.info.numberOfChannels=Wt[s]+a}break;case"dec3":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(f=t.info)?void 0:f.type));const i=(e=>{if(e.length<2)return null;const t=new Ee(e),i=t.readBits(13),r=t.readBits(3),n=[];for(let s=0;s<=r&&!(Math.ceil(t.pos/8)+3>e.length);s++){const e=t.readBits(2),i=t.readBits(5);t.skipBits(1),t.skipBits(1);const r=t.readBits(3),s=t.readBits(3),a=t.readBits(1);t.skipBits(3);const o=t.readBits(4);let l=0;o>0?l=t.readBits(9):t.skipBits(1),n.push({fscod:e,fscod2:null,bsid:i,bsmod:r,acmod:s,lfeon:a,numDepSub:o,chanLoc:l})}return 0===n.length?null:{dataRate:i,substreams:n}})(xa(e,ue.contentSize));if(!i){console.warn("Invalid dec3 box contents, ignoring.");break}const r=Xt(i);null!==r&&(t.info.sampleRate=r),t.info.numberOfChannels=$t(i)}break;case"stts":{const t=this.currentTrack;if(!t)break;if(!t.sampleTable)break;e.skip(4);const i=Ra(e);let r=0,n=0;for(let s=0;se.id===i);if(!r)break;const n=Ra(e),s=(12&n)>>2,a=3&n,o=[Ca,Ea,_a,Ra],l=o[(48&n)>>4],c=o[s],u=o[a],d=Ra(e);for(let h=0;he.timestamp-t.timestamp);for(let e=0;e({presentationTimestamp:e.presentationTimestamp,sampleIndex:t})).sort((e,t)=>e.presentationTimestamp-t.presentationTimestamp);for(let n=0;ne.id===c);if(!u)break;const d=this.fragmentTrackDefaults.find(e=>e.trackId===c);this.currentTrack=u,u.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:null!=(p=null==d?void 0:d.defaultSampleDescriptionIndex)?p:null,defaultSampleDuration:null!=(g=null==d?void 0:d.defaultSampleDuration)?g:null,defaultSampleSize:null!=(k=null==d?void 0:d.defaultSampleSize)?k:null,defaultSampleFlags:null!=(S=null==d?void 0:d.defaultSampleFlags)?S:null,startTimestamp:null,encryptionAuxInfo:null},i?u.currentFragmentState.baseDataOffset=Oa(e):l&&(u.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),r&&(u.currentFragmentState.sampleDescriptionIndex=Ra(e)),n&&(u.currentFragmentState.defaultSampleDuration=Ra(e)),s&&(u.currentFragmentState.defaultSampleSize=Ra(e)),a&&(u.currentFragmentState.defaultSampleFlags=Ra(e)),o&&(u.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{const t=this.currentTrack;if(!t)break;y(t.currentFragmentState);const i=Ca(e);e.skip(3);const r=0===i?Ra(e):Oa(e);t.currentFragmentState.startTimestamp=r}break;case"trun":{const t=this.currentTrack;if(!t)break;y(this.currentFragment),y(t.currentFragmentState);const i=Ca(e),r=_a(e),n=Boolean(1&r),s=Boolean(4&r),a=Boolean(256&r),o=Boolean(512&r),l=Boolean(1024&r),c=Boolean(2048&r),u=Ra(e);let d=null;n&&(d=Ma(e));let h,f=null;if(s&&(f=Ra(e)),this.currentFragment.trackData.has(t.id)?(h=this.currentFragment.trackData.get(t.id),null!==d&&(h.currentOffset=t.currentFragmentState.baseDataOffset+d)):(h={track:t,currentTimestamp:0,currentOffset:t.currentFragmentState.baseDataOffset+(null!=d?d:0),startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1,encryptionAuxInfo:null},this.currentFragment.trackData.set(t.id,h)),0===u){this.currentFragment.implicitBaseDataOffset=h.currentOffset;break}for(let m=0;m0&&(n=xa(e,r));const s=Ci(t);s.defaultSampleInfoSize=i,s.sampleSizes=n,s.sampleCount=r}break;case"saio":{const t=this.currentTrack;if(!t||!t.encryptionInfo)break;const i=Ca(e);if(1&_a(e)){const i=Wa(e,4),r=Ra(e);if(i!==t.encryptionInfo.scheme||0!==r)break}const r=Ra(e);if(0===r)break;r>1&&console.warn("Multiple saio entries are not supported; using the first offset only.");let n=0===i?Ra(e):Number(Oa(e));this.currentFragment&&(n+=this.currentFragment.moofOffset);Ci(t).offset=n}break;case"senc":{const t=this.currentTrack;if(!t||!t.encryptionInfo)break;y(this.currentFragment);const i=this.currentFragment.trackData.get(t.id);if(!i)break;e.skip(1);const r=_a(e),n=Boolean(2&r),s=Ra(e),a=t.encryptionInfo.defaultPerSampleIvSize;y(null!==a);for(let o=0;o0?r.set(xa(e,a),0):r.set(t.encryptionInfo.defaultConstantIv,0);let s=null;if(n){const t=Ea(e);s=[];for(let i=0;i0&&(null!=(re=this.metadataTags).trackNumber||(re.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&(null!=(ne=this.metadataTags).tracksTotal||(ne.tracksTotal=i))}break;case"trkn":if(n instanceof Uint8Array&&n.length>=6){const e=P(n),t=e.getUint16(2,!1),i=e.getUint16(4,!1);t>0&&(null!=(se=this.metadataTags).trackNumber||(se.trackNumber=t)),i>0&&(null!=(ae=this.metadataTags).tracksTotal||(ae.tracksTotal=i))}break;case"disc":case"disk":if(n instanceof Uint8Array&&n.length>=6){const e=P(n),t=e.getUint16(2,!1),i=e.getUint16(4,!1);t>0&&(null!=(oe=this.metadataTags).discNumber||(oe.discNumber=t)),i>0&&(null!=(le=this.metadataTags).discsTotal||(le.discsTotal=i))}}}}}var fe,me;return e.filePos=he,!0}}class ki{constructor(e){this.internalTrack=e,this.packetToSampleIndex=new WeakMap,this.packetToFragmentLocation=new WeakMap}getId(){return this.internalTrack.id}getNumber(){const e=this.internalTrack.demuxer,t=this.internalTrack.trackBacking.getType();let i=0;for(const r of e.tracks)if(r.trackBacking.getType()===t&&i++,r===this.internalTrack)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.internalCodecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.timescale}isRelativeToUnixEpoch(){return!1}getDisposition(){return this.internalTrack.disposition}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){var e;const t=this.internalTrack;if(t.durationInMediaTimescale<=0)return null;y(t.trackBacking);const i=yield t.trackBacking.getFirstPacket({metadataOnly:!0});return(null!=(e=null==i?void 0:i.timestamp)?e:0)+t.durationInMediaTimescale/t.timescale})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getFirstPacket(e){return d(this,null,function*(){const t=yield this.fetchPacketForSampleIndex(0,e);return t||!this.internalTrack.demuxer.isFragmented?t:this.performFragmentedLookup(null,e=>e.trackData.get(this.internalTrack.id)?{sampleIndex:0,correctSampleFound:!0}:{sampleIndex:-1,correctSampleFound:!1},-1/0,1/0,e)})}mapTimestampIntoTimescale(e){return G(e*this.internalTrack.timescale)+this.internalTrack.editListOffset}getPacket(e,t){return d(this,null,function*(){const i=this.mapTimestampIntoTimescale(e),r=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=Ti(r,i),s=yield this.fetchPacketForSampleIndex(n,t);return xi(r)&&this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const r=z(t.presentationTimestamps,i,e=>e.presentationTimestamp);return{sampleIndex:-1!==r?t.presentationTimestamps[r].sampleIndex:-1,correctSampleFound:-1!==r&&i{if(e===r.fragment){const t=e.trackData.get(this.internalTrack.id);if(r.sampleIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const r=V(t.presentationTimestamps,e=>t.samples[e.sampleIndex].isKeyFrame&&e.presentationTimestamp<=i);return{sampleIndex:-1!==r?t.presentationTimestamps[r].sampleIndex:-1,correctSampleFound:-1!==r&&i{if(e===r.fragment){const t=e.trackData.get(this.internalTrack.id).samples.findIndex((e,t)=>e.isKeyFrame&&t>r.sampleIndex);if(-1!==t)return{sampleIndex:t,correctSampleFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.samples.findIndex(e=>e.isKeyFrame);return y(-1!==e),{sampleIndex:e,correctSampleFound:!0}}}return{sampleIndex:-1,correctSampleFound:!1}},-1/0,1/0,t)})}fetchPacketForSampleIndex(e,t){return d(this,null,function*(){if(-1===e)return null;const i=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),r=vi(i,e);if(!r)return null;let n;if(t.metadataOnly)n=Gt;else{let t=this.internalTrack.demuxer.reader.requestSlice(r.sampleOffset,r.sampleSize);if(t instanceof Promise&&(t=yield t),!t)return null;if(n=xa(t,r.sampleSize),this.internalTrack.encryptionAuxInfo){y(this.internalTrack.encryptionInfo);const t=yield Bi(this.internalTrack.demuxer.reader,this.internalTrack.encryptionInfo,this.internalTrack.encryptionAuxInfo);ee.timestamp),f=-1!==h?this.internalTrack.fragmentLookupTable[h]:null,m=z(this.internalTrack.fragmentPositionCache,i,e=>e.startTimestamp),p=-1!==m?this.internalTrack.fragmentPositionCache[m]:null,g=Math.max(null!=(s=null==f?void 0:f.moofOffset)?s:0,null!=(a=null==p?void 0:p.moofOffset)?a:0)||null;let k;for(e?null===g||e.moofOffset>=g?(k=e.moofOffset+e.moofSize,c=e):k=g:k=null!=g?g:0;;){if(c){const e=c.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>r)break}let e=l.reader.requestSliceRange(k,8,16);if(e instanceof Promise&&(e=yield e),!e)break;const i=k,s=ei(e);if(!s)break;if("moof"===s.name){c=yield l.readFragment(i);const{sampleIndex:e,correctSampleFound:r}=t(c);if(r)return this.fetchPacketInFragment(c,e,n);-1!==e&&(u=c,d=e)}k=i+s.totalSize}if(f&&(!u||u.moofOffsetd(this,null,function*(){var e,t;if("vp9"!==this.internalTrack.info.codec||this.internalTrack.info.vp9CodecInfo){if("av1"===this.internalTrack.info.codec&&!this.internalTrack.info.av1CodecInfo){const e=yield this.getFirstPacket({});this.internalTrack.info.av1CodecInfo=e&&Mt(e.data)}}else{const e=yield this.getFirstPacket({});this.internalTrack.info.vp9CodecInfo=e&&Rt(e.data)}const i={codec:Ue(this.internalTrack.info),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0,colorSpace:null!=(t=this.internalTrack.info.colorSpace)?t:void 0};return this.internalTrack.info.width===this.internalTrack.info.squarePixelWidth&&this.internalTrack.info.height===this.internalTrack.info.squarePixelHeight||(i.displayAspectWidth=this.internalTrack.info.squarePixelWidth,i.displayAspectHeight=this.internalTrack.info.squarePixelHeight),i}))():null})}}class bi extends ki{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getType(){return"audio"}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}getDecoderConfig(){return d(this,null,function*(){var e,t;return this.internalTrack.info.codec?null!=(t=this.decoderConfig)?t:this.decoderConfig={codec:qe(this.internalTrack.info),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0}:null})}}const Ti=(e,t)=>{if(e.presentationTimestamps){const i=z(e.presentationTimestamps,t,e=>e.presentationTimestamp);return-1===i?-1:e.presentationTimestamps[i].sampleIndex}{const i=z(e.sampleTimingEntries,t,e=>e.startDecodeTimestamp);if(-1===i)return-1;const r=e.sampleTimingEntries[i];return r.startIndex+Math.min(Math.floor((t-r.startDecodeTimestamp)/r.delta),r.count-1)}},Si=(e,t)=>{var i;if(!e.keySampleIndices)return Ti(e,t);if(e.presentationTimestamps){const i=z(e.presentationTimestamps,t,e=>e.presentationTimestamp);if(-1===i)return-1;for(let t=i;t>=0;t--){const i=e.presentationTimestamps[t].sampleIndex;if(-1!==L(e.keySampleIndices,i,e=>e))return i}return-1}{const r=Ti(e,t),n=z(e.keySampleIndices,r,e=>e);return null!=(i=e.keySampleIndices[n])?i:-1}},vi=(e,t)=>{const i=z(e.sampleTimingEntries,t,e=>e.startIndex),r=e.sampleTimingEntries[i];if(!r||r.startIndex+r.count<=t)return null;let n=r.startDecodeTimestamp+(t-r.startIndex)*r.delta;const s=z(e.sampleCompositionTimeOffsets,t,e=>e.startIndex),a=e.sampleCompositionTimeOffsets[s];a&&t-a.startIndexe.startSampleIndex),c=e.sampleToChunk[l];y(c);const u=c.startChunkIndex+Math.floor((t-c.startSampleIndex)/c.samplesPerChunk),d=e.chunkOffsets[u],h=c.startSampleIndex+(u-c.startChunkIndex)*c.samplesPerChunk;let f=0,m=d;if(1===e.sampleSizes.length)m+=o*(t-h),f+=o*c.samplesPerChunk;else for(let g=h;ge)}},wi=(e,t)=>{var i;if(!e.keySampleIndices)return t+1;const r=z(e.keySampleIndices,t,e=>e);return null!=(i=e.keySampleIndices[r+1])?i:-1},Pi=(e,t)=>{e.startTimestamp+=t,e.endTimestamp+=t;for(const i of e.samples)i.presentationTimestamp+=t;for(const i of e.presentationTimestamps)i.presentationTimestamp+=t},Ii=e=>{const[t,i]=e,r=Math.atan2(i,t);return Number.isFinite(r)?r*(180/Math.PI):0},xi=e=>0===e.sampleSizes.length,Ci=e=>{var t,i,r;return e.currentFragmentState?null!=(i=(t=e.currentFragmentState).encryptionAuxInfo)?i:t.encryptionAuxInfo={defaultSampleInfoSize:0,sampleSizes:null,sampleCount:0,offset:null,resolved:null}:null!=(r=e.encryptionAuxInfo)?r:e.encryptionAuxInfo={defaultSampleInfoSize:0,sampleSizes:null,sampleCount:0,offset:null,resolved:null}},Bi=(e,t,i)=>d(null,null,function*(){if(i.resolved)return i.resolved;if(null===i.offset||0===i.sampleCount)throw new Error("Incomplete saiz/saio info; cannot resolve encryption data.");let r=0;if(i.defaultSampleInfoSize>0)r=i.defaultSampleInfoSize*i.sampleCount;else{y(i.sampleSizes);for(let e=0;e0?i.defaultSampleInfoSize:i.sampleSizes[e],o=new Uint8Array(16);s>0?o.set(xa(n,s),0):o.set(t.defaultConstantIv,0);let l=null;if(r>s){const e=Ea(n);l=[];for(let t=0;td(null,null,function*(){var n;y(e.encryptionInfo);const s=e.encryptionInfo;y(null!==s.defaultKid);const a=s.defaultKid;let o;const l=e.demuxer.decryptionKeyCache.get(a);if(l)o=yield l;else{if(!(null==(n=e.demuxer.input._formatOptions.isobmff)?void 0:n.resolveKeyId))throw new Error("Encrypted media samples encountered. To decrypt them, please provide a callback for InputOptions.formatOptions.isobmff.resolveKeyId.");const t=d(null,null,function*(){let t=e.demuxer.psshBoxes;if(r){t=[...t,...r.psshBoxes].filter(e=>null===e.keyIds||e.keyIds.includes(a));for(let e=0;e{y(e.length%2===0);const t=new Uint8Array(e.length/2);for(let i=0;id(null,null,function*(){const n=new Uint8Array(16);n.set(i.iv,0);const s=yield crypto.subtle.importKey("raw",e,{name:"AES-CTR"},!1,["decrypt"]),a=e=>d(null,null,function*(){const t=yield crypto.subtle.decrypt({name:"AES-CTR",counter:n,length:64},s,e);return new Uint8Array(t)});if(!i.subsamples)return a(r);y(null!==t.defaultCryptByteBlock&&null!==t.defaultSkipByteBlock);const o=Fi(i.subsamples,t.defaultCryptByteBlock,t.defaultSkipByteBlock);let l=0;for(const e of o)for(const t of e.perSubsample)l+=t.length;const c=new Uint8Array(l);let u=0;for(const e of o)for(const t of e.perSubsample)c.set(r.subarray(t.offset,t.offset+t.length),u),u+=t.length;const h=yield a(c),f=new Uint8Array(r);let m=0;for(const e of o)for(const t of e.perSubsample)f.set(h.subarray(m,m+t.length),t.offset),m+=t.length;return f}),Ai=(e,t,i,r)=>{const n=new pi;n.init({key:e,iv:i.iv});const s=t.defaultCryptByteBlock,a=t.defaultSkipByteBlock;if(y(null!==s&&null!==a),!i.subsamples){const e=new Uint8Array(r),t=Math.floor(r.length/16);for(let i=0;i{const r=[],n=0!==t||0!==i;let s=0;for(const a of e){s+=a.clearLen;const e=[];if(n){let r=a.protectedLen,n=s;for(;r>0&&!(r<16*t);){const s=16*t;e.push({offset:n,length:s}),n+=s,r-=s;const a=Math.min(16*i,r);n+=a,r-=a}s+=a.protectedLen}else a.protectedLen>0&&e.push({offset:s,length:a.protectedLen}),s+=a.protectedLen;r.push({perSubsample:e})}return r};var Ri,Di;(Di=Ri||(Ri={}))[Di.EBML=440786851]="EBML",Di[Di.EBMLVersion=17030]="EBMLVersion",Di[Di.EBMLReadVersion=17143]="EBMLReadVersion",Di[Di.EBMLMaxIDLength=17138]="EBMLMaxIDLength",Di[Di.EBMLMaxSizeLength=17139]="EBMLMaxSizeLength",Di[Di.DocType=17026]="DocType",Di[Di.DocTypeVersion=17031]="DocTypeVersion",Di[Di.DocTypeReadVersion=17029]="DocTypeReadVersion",Di[Di.Void=236]="Void",Di[Di.Segment=408125543]="Segment",Di[Di.SeekHead=290298740]="SeekHead",Di[Di.Seek=19899]="Seek",Di[Di.SeekID=21419]="SeekID",Di[Di.SeekPosition=21420]="SeekPosition",Di[Di.Duration=17545]="Duration",Di[Di.Info=357149030]="Info",Di[Di.TimestampScale=2807729]="TimestampScale",Di[Di.MuxingApp=19840]="MuxingApp",Di[Di.WritingApp=22337]="WritingApp",Di[Di.Tracks=374648427]="Tracks",Di[Di.TrackEntry=174]="TrackEntry",Di[Di.TrackNumber=215]="TrackNumber",Di[Di.TrackUID=29637]="TrackUID",Di[Di.TrackType=131]="TrackType",Di[Di.FlagEnabled=185]="FlagEnabled",Di[Di.FlagDefault=136]="FlagDefault",Di[Di.FlagForced=21930]="FlagForced",Di[Di.FlagOriginal=21934]="FlagOriginal",Di[Di.FlagHearingImpaired=21931]="FlagHearingImpaired",Di[Di.FlagVisualImpaired=21932]="FlagVisualImpaired",Di[Di.FlagCommentary=21935]="FlagCommentary",Di[Di.FlagLacing=156]="FlagLacing",Di[Di.Name=21358]="Name",Di[Di.Language=2274716]="Language",Di[Di.LanguageBCP47=2274717]="LanguageBCP47",Di[Di.CodecID=134]="CodecID",Di[Di.CodecPrivate=25506]="CodecPrivate",Di[Di.CodecDelay=22186]="CodecDelay",Di[Di.SeekPreRoll=22203]="SeekPreRoll",Di[Di.DefaultDuration=2352003]="DefaultDuration",Di[Di.Video=224]="Video",Di[Di.PixelWidth=176]="PixelWidth",Di[Di.PixelHeight=186]="PixelHeight",Di[Di.DisplayWidth=21680]="DisplayWidth",Di[Di.DisplayHeight=21690]="DisplayHeight",Di[Di.DisplayUnit=21682]="DisplayUnit",Di[Di.AlphaMode=21440]="AlphaMode",Di[Di.Audio=225]="Audio",Di[Di.SamplingFrequency=181]="SamplingFrequency",Di[Di.Channels=159]="Channels",Di[Di.BitDepth=25188]="BitDepth",Di[Di.SimpleBlock=163]="SimpleBlock",Di[Di.BlockGroup=160]="BlockGroup",Di[Di.Block=161]="Block",Di[Di.BlockAdditions=30113]="BlockAdditions",Di[Di.BlockMore=166]="BlockMore",Di[Di.BlockAdditional=165]="BlockAdditional",Di[Di.BlockAddID=238]="BlockAddID",Di[Di.BlockDuration=155]="BlockDuration",Di[Di.ReferenceBlock=251]="ReferenceBlock",Di[Di.Cluster=524531317]="Cluster",Di[Di.Timestamp=231]="Timestamp",Di[Di.Cues=475249515]="Cues",Di[Di.CuePoint=187]="CuePoint",Di[Di.CueTime=179]="CueTime",Di[Di.CueTrackPositions=183]="CueTrackPositions",Di[Di.CueTrack=247]="CueTrack",Di[Di.CueClusterPosition=241]="CueClusterPosition",Di[Di.Colour=21936]="Colour",Di[Di.MatrixCoefficients=21937]="MatrixCoefficients",Di[Di.TransferCharacteristics=21946]="TransferCharacteristics",Di[Di.Primaries=21947]="Primaries",Di[Di.Range=21945]="Range",Di[Di.Projection=30320]="Projection",Di[Di.ProjectionType=30321]="ProjectionType",Di[Di.ProjectionPoseRoll=30325]="ProjectionPoseRoll",Di[Di.Attachments=423732329]="Attachments",Di[Di.AttachedFile=24999]="AttachedFile",Di[Di.FileDescription=18046]="FileDescription",Di[Di.FileName=18030]="FileName",Di[Di.FileMediaType=18016]="FileMediaType",Di[Di.FileData=18012]="FileData",Di[Di.FileUID=18094]="FileUID",Di[Di.Chapters=272869232]="Chapters",Di[Di.Tags=307544935]="Tags",Di[Di.Tag=29555]="Tag",Di[Di.Targets=25536]="Targets",Di[Di.TargetTypeValue=26826]="TargetTypeValue",Di[Di.TargetType=25546]="TargetType",Di[Di.TagTrackUID=25541]="TagTrackUID",Di[Di.TagEditionUID=25545]="TagEditionUID",Di[Di.TagChapterUID=25540]="TagChapterUID",Di[Di.TagAttachmentUID=25542]="TagAttachmentUID",Di[Di.SimpleTag=26568]="SimpleTag",Di[Di.TagName=17827]="TagName",Di[Di.TagLanguage=17530]="TagLanguage",Di[Di.TagString=17543]="TagString",Di[Di.TagBinary=17541]="TagBinary",Di[Di.ContentEncodings=28032]="ContentEncodings",Di[Di.ContentEncoding=25152]="ContentEncoding",Di[Di.ContentEncodingOrder=20529]="ContentEncodingOrder",Di[Di.ContentEncodingScope=20530]="ContentEncodingScope",Di[Di.ContentCompression=20532]="ContentCompression",Di[Di.ContentCompAlgo=16980]="ContentCompAlgo",Di[Di.ContentCompSettings=16981]="ContentCompSettings",Di[Di.ContentEncryption=20533]="ContentEncryption";const Mi=[Ri.EBML,Ri.Segment],Ni=[Ri.SeekHead,Ri.Info,Ri.Cluster,Ri.Tracks,Ri.Cues,Ri.Attachments,Ri.Chapters,Ri.Tags],Oi=[...Mi,...Ni],Li=16,zi=e=>{if(e.remainingLength<1)return null;const t=Ca(e);if(e.skip(-1),0===t)return null;let i=1,r=128;for(;0===(t&r);)i++,r>>=1;return e.remainingLength{if(e.remainingLength<1)return null;const t=Ca(e);if(0===t)return null;let i=1,r=128;for(;0===(t&r);)i++,r>>=1;if(e.remainingLength{if(t<1||t>8)throw new Error("Bad unsigned int size "+t);let i=0;for(let r=0;r{const t=zi(e);if(null===t)return null;if(e.remainingLength{if(e.remainingLength<1)return null;if(255===Ca(e))return;e.skip(-1);const t=Ui(e);return null===t?null:72057594037927940!==t?t:void 0},Hi=e=>{y(e.remainingLength>=2);const t=Wi(e);if(null===t)return null;const i=Vi(e);return null===i?null:{id:t,size:i}},Ki=(e,t)=>{const i=xa(e,t);let r=0;for(;r{const i=xa(e,t);let r=0;for(;r{if(0===t)return 0;if(4!==t&&8!==t)throw new Error("Bad float size "+t);return 4===t?Ua(e):qa(e)},$i=(e,t,i,r)=>d(null,null,function*(){const n=new Set(i);let s=t;for(;null===r||ss?r:s,found:!1}}),Qi=(e,t,i,r)=>d(null,null,function*(){const n=o(2,16),s=new Set(i);let a=t;for(;ae.tracks.map(e=>e.trackBacking))})}getMimeType(){return d(this,null,function*(){yield this.readMetadata();const e=yield this.getTrackBackings(),t=yield Promise.all(e.map(e=>e.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null})));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isWebM?"webm":"x-matroska");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings.filter(Boolean))].join(", ")}"`);return t})({isWebM:this.isWebM,hasVideo:this.segments.some(e=>e.tracks.some(e=>{var t;return"video"===(null==(t=e.info)?void 0:t.type)})),hasAudio:this.segments.some(e=>e.tracks.some(e=>{var t;return"audio"===(null==(t=e.info)?void 0:t.type)})),codecStrings:t.filter(Boolean)})})}getMetadataTags(){return d(this,null,function*(){yield this.readMetadata();for(const t of this.segments)t.metadataTagsCollected||(null!==this.reader.fileSize&&(yield this.loadSegmentMetadata(t)),t.metadataTagsCollected=!0);let e={};for(const t of this.segments)e=c(c({},e),t.metadataTags);return e})}readMetadata(){var e;return null!=(e=this.readMetadataPromise)?e:this.readMetadataPromise=(()=>d(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,2,Li);if(t instanceof Promise&&(t=yield t),!t)break;const i=Hi(t);if(!i)break;const r=i.id;let n=i.size;const s=t.filePos;if(r===Ri.EBML){lr(n);let e=this.reader.requestSlice(s,n);if(e instanceof Promise&&(e=yield e),!e)break;this.readContiguousElements(e)}else if(r===Ri.Segment){if(yield this.readSegment(s,n),void 0===n)break;if(null===this.reader.fileSize)break}else if(r===Ri.Cluster){if(null===this.reader.fileSize)break;if(void 0===n){n=(yield $i(this.reader,s,Oi,this.reader.fileSize)).pos-s}const e=T(this.segments);e&&(e.elementEndPos=s+n)}lr(n),e=s+n}}))()}readSegment(e,t){return d(this,null,function*(){var i;this.currentSegment={seekHeadSeen:!1,infoSeen:!1,tracksSeen:!1,cuesSeen:!1,tagsSeen:!1,attachmentsSeen:!1,timestampScale:-1,timestampFactor:-1,duration:-1,seekEntries:[],tracks:[],cuePoints:[],dataStartPos:e,elementEndPos:void 0===t?null:e+t,clusterSeekStartPos:e,lastReadCluster:null,metadataTags:{},metadataTagsCollected:!1},this.segments.push(this.currentSegment);let r=e;for(;null===this.currentSegment.elementEndPos||re.id===s);if(-1!==l){const e=pr[l].flag;this.currentSegment[e]=!0,lr(a);let t=this.reader.requestSlice(o,a);t instanceof Promise&&(t=yield t),t&&this.readContiguousElements(t)}else if(s===Ri.Tags||s===Ri.Attachments){s===Ri.Tags?this.currentSegment.tagsSeen=!0:this.currentSegment.attachmentsSeen=!0,lr(a);let e=this.reader.requestSlice(o,a);e instanceof Promise&&(e=yield e),e&&this.readContiguousElements(e)}else if(s===Ri.Cluster){this.currentSegment.clusterSeekStartPos=t;break}if(void 0===a)break;r=o+a}if(this.currentSegment.seekEntries.sort((e,t)=>e.segmentPosition-t.segmentPosition),null!==this.reader.fileSize)for(const t of this.currentSegment.seekEntries){const i=pr.find(e=>e.id===t.id);if(!i)continue;if(this.currentSegment[i.flag])continue;let r=this.reader.requestSliceRange(e+t.segmentPosition,2,Li);if(r instanceof Promise&&(r=yield r),!r)continue;const n=Hi(r);if(!n)continue;const{id:s,size:a}=n;if(s!==i.id)continue;lr(a),this.currentSegment[i.flag]=!0;let o=this.reader.requestSlice(r.filePos,a);o instanceof Promise&&(o=yield o),o&&this.readContiguousElements(o)}-1===this.currentSegment.timestampScale&&(this.currentSegment.timestampScale=1e6,this.currentSegment.timestampFactor=1e3);for(const e of this.currentSegment.tracks)null!==e.defaultDurationNs&&(e.defaultDuration=this.currentSegment.timestampFactor*e.defaultDurationNs/1e9);const n=new Map(this.currentSegment.tracks.map(e=>[e.id,e]));for(const e of this.currentSegment.cuePoints){const t=n.get(e.trackId);t&&t.cuePoints.push(e)}for(const e of this.currentSegment.tracks){e.cuePoints.sort((e,t)=>e.time-t.time);for(let t=0;ta&&(a=e.cuePoints.length,s=e);for(const e of this.currentSegment.tracks)0===e.cuePoints.length&&(e.cuePoints=s.cuePoints);this.currentSegment=null})}readCluster(e,t){return d(this,null,function*(){var i;if((null==(i=t.lastReadCluster)?void 0:i.elementStartPos)===e)return t.lastReadCluster;let r=this.reader.requestSliceRange(e,2,Li);r instanceof Promise&&(r=yield r),y(r);const n=e,s=Hi(r);y(s);y(s.id===Ri.Cluster);let a=s.size;const o=r.filePos;if(void 0===a){a=(yield $i(this.reader,o,Oi,t.elementEndPos)).pos-o}let l=this.reader.requestSlice(o,a);l instanceof Promise&&(l=yield l);const c={segment:t,elementStartPos:n,elementEndPos:o+a,dataStartPos:o,timestamp:-1,trackData:new Map};if(this.currentCluster=c,l){const e=this.readContiguousElements(l,Oi);c.elementEndPos=e}for(const[,e]of c.trackData){const t=e.track;y(e.blocks.length>0);let i=!1;for(let n=0;n({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp);for(let n=0;n({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp));const r=e.blocks[e.presentationTimestamps[0].blockIndex],s=e.blocks[T(e.presentationTimestamps).blockIndex];e.startTimestamp=r.timestamp,e.endTimestamp=s.timestamp+s.duration;const a=z(t.clusterPositionCache,e.startTimestamp,e=>e.startTimestamp);-1!==a&&t.clusterPositionCache[a].elementStartPos===n||t.clusterPositionCache.splice(a+1,0,{elementStartPos:c.elementStartPos,startTimestamp:e.startTimestamp})}return t.lastReadCluster=c,c})}getTrackDataInCluster(e,t){let i=e.trackData.get(t);if(!i){const r=e.segment.tracks.find(e=>e.id===t);if(!r)return null;i={track:r,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,blocks:[],presentationTimestamps:[]},e.trackData.set(t,i)}return i}expandLacedBlocks(e,t){var i;for(let r=0;r=2;){const i=e.filePos;if(!this.traverseElement(e,t))return i}return e.filePos}traverseElement(e,t){var i,r,n,s,a,o,l,d,h,f,m,p,g,k,T,S,v,w,P,I,x,C,E,A,R,D,M,N,O,L,z,U,q,W,V,H,K,j,X,$,G,Y,J,Z,te,ie,re,ne,se,ae,oe,le,ce,ue;const de=Hi(e);if(!de)return!1;if(t&&t.includes(de.id))return!1;const{id:he,size:fe}=de,me=e.filePos;switch(lr(fe),he){case Ri.DocType:this.isWebM="webm"===Ki(e,fe);break;case Ri.Seek:{if(!this.currentSegment)break;const t={id:-1,segmentPosition:-1};this.currentSegment.seekEntries.push(t),this.readContiguousElements(e.slice(me,fe)),-1!==t.id&&-1!==t.segmentPosition||this.currentSegment.seekEntries.pop()}break;case Ri.SeekID:{const t=null==(i=this.currentSegment)?void 0:i.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.id=qi(e,fe)}break;case Ri.SeekPosition:{const t=null==(r=this.currentSegment)?void 0:r.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.segmentPosition=qi(e,fe)}break;case Ri.TimestampScale:if(!this.currentSegment)break;this.currentSegment.timestampScale=qi(e,fe),this.currentSegment.timestampFactor=1e9/this.currentSegment.timestampScale;break;case Ri.Duration:if(!this.currentSegment)break;this.currentSegment.duration=Xi(e,fe);break;case Ri.TrackEntry:if(!this.currentSegment)break;if(this.currentTrack={id:-1,segment:this.currentSegment,demuxer:this,clusterPositionCache:[],cuePoints:[],disposition:u(c({},Be),{primary:!1}),trackBacking:null,codecId:null,codecPrivate:null,defaultDuration:null,defaultDurationNs:null,name:null,languageCode:"eng",hasLanguageBcp47:!1,decodingInstructions:[],info:null},this.readContiguousElements(e.slice(me,fe)),!this.currentTrack)break;if(this.currentTrack.decodingInstructions.some(e=>{var t;return"decompress"!==(null==(t=e.data)?void 0:t.type)||e.scope!==dr.Block||e.data.algorithm!==fr.HeaderStripping})&&(console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`),this.currentTrack=null),this.currentTrack&&-1!==this.currentTrack.id&&this.currentTrack.codecId&&this.currentTrack.info){const e=this.currentTrack.codecId.indexOf("/"),t=-1===e?this.currentTrack.codecId:this.currentTrack.codecId.slice(0,e);if("video"===this.currentTrack.info.type&&-1!==this.currentTrack.info.width&&-1!==this.currentTrack.info.height){if(this.currentTrack.info.squarePixelWidth=this.currentTrack.info.width,this.currentTrack.info.squarePixelHeight=this.currentTrack.info.height,null!==this.currentTrack.info.displayWidth&&null!==this.currentTrack.info.displayHeight){const e=this.currentTrack.info.displayWidth*this.currentTrack.info.height,t=this.currentTrack.info.displayHeight*this.currentTrack.info.width;e>0&&t>0&&(e>t?this.currentTrack.info.squarePixelWidth=Math.round(this.currentTrack.info.width*e/t):this.currentTrack.info.squarePixelHeight=Math.round(this.currentTrack.info.height*t/e))}this.currentTrack.codecId===Gi?(this.currentTrack.info.codec="avc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Yi?(this.currentTrack.info.codec="hevc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ji?this.currentTrack.info.codec="vp8":t===Zi?this.currentTrack.info.codec="vp9":t===er&&(this.currentTrack.info.codec="av1");const e=this.currentTrack;this.currentTrack.trackBacking=new br(e),this.currentSegment.tracks.push(this.currentTrack)}else if("audio"===this.currentTrack.info.type){t===tr?(this.currentTrack.info.codec="aac",this.currentTrack.info.aacCodecInfo={isMpeg2:this.currentTrack.codecId.includes("MPEG2"),objectType:null},this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===ir?this.currentTrack.info.codec="mp3":t===rr?(this.currentTrack.info.codec="opus",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate,this.currentTrack.info.sampleRate=We):t===nr?(this.currentTrack.info.codec="vorbis",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===sr?(this.currentTrack.info.codec="flac",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===ar?(this.currentTrack.info.codec="ac3",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===or?(this.currentTrack.info.codec="eac3",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):"A_PCM/INT/LIT"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32"):"A_PCM/INT/BIG"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16be":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24be":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32be"):"A_PCM/FLOAT/IEEE"===this.currentTrack.codecId&&(32===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-f32":64===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-f64"));const e=this.currentTrack;this.currentTrack.trackBacking=new Tr(e),this.currentSegment.tracks.push(this.currentTrack)}}this.currentTrack=null;break;case Ri.TrackNumber:if(!this.currentTrack)break;this.currentTrack.id=qi(e,fe);break;case Ri.TrackType:{if(!this.currentTrack)break;const t=qi(e,fe);1===t?this.currentTrack.info={type:"video",width:-1,height:-1,displayWidth:null,displayHeight:null,displayUnit:null,squarePixelWidth:-1,squarePixelHeight:-1,rotation:0,codec:null,codecDescription:null,colorSpace:null,alphaMode:!1}:2===t&&(this.currentTrack.info={type:"audio",numberOfChannels:1,sampleRate:8e3,bitDepth:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case Ri.FlagEnabled:if(!this.currentTrack)break;qi(e,fe)||(this.currentTrack=null);break;case Ri.FlagDefault:if(!this.currentTrack)break;this.currentTrack.disposition.default=!!qi(e,fe);break;case Ri.FlagForced:if(!this.currentTrack)break;this.currentTrack.disposition.forced=!!qi(e,fe);break;case Ri.FlagOriginal:if(!this.currentTrack)break;this.currentTrack.disposition.original=!!qi(e,fe);break;case Ri.FlagHearingImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.hearingImpaired=!!qi(e,fe);break;case Ri.FlagVisualImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.visuallyImpaired=!!qi(e,fe);break;case Ri.FlagCommentary:if(!this.currentTrack)break;this.currentTrack.disposition.commentary=!!qi(e,fe);break;case Ri.CodecID:if(!this.currentTrack)break;this.currentTrack.codecId=Ki(e,fe);break;case Ri.CodecPrivate:if(!this.currentTrack)break;this.currentTrack.codecPrivate=xa(e,fe);break;case Ri.DefaultDuration:if(!this.currentTrack)break;this.currentTrack.defaultDurationNs=qi(e,fe);break;case Ri.Name:if(!this.currentTrack)break;this.currentTrack.name=ji(e,fe);break;case Ri.Language:if(!this.currentTrack)break;if(this.currentTrack.hasLanguageBcp47)break;this.currentTrack.languageCode=Ki(e,fe),ee(this.currentTrack.languageCode)||(this.currentTrack.languageCode=Q);break;case Ri.LanguageBCP47:{if(!this.currentTrack)break;const t=Ki(e,fe).split("-")[0];this.currentTrack.languageCode=t||Q,this.currentTrack.hasLanguageBcp47=!0}break;case Ri.Video:if("video"!==(null==(s=null==(n=this.currentTrack)?void 0:n.info)?void 0:s.type))break;this.readContiguousElements(e.slice(me,fe));break;case Ri.PixelWidth:if("video"!==(null==(o=null==(a=this.currentTrack)?void 0:a.info)?void 0:o.type))break;this.currentTrack.info.width=qi(e,fe);break;case Ri.PixelHeight:if("video"!==(null==(d=null==(l=this.currentTrack)?void 0:l.info)?void 0:d.type))break;this.currentTrack.info.height=qi(e,fe);break;case Ri.DisplayWidth:if("video"!==(null==(f=null==(h=this.currentTrack)?void 0:h.info)?void 0:f.type))break;this.currentTrack.info.displayWidth=qi(e,fe);break;case Ri.DisplayHeight:if("video"!==(null==(p=null==(m=this.currentTrack)?void 0:m.info)?void 0:p.type))break;this.currentTrack.info.displayHeight=qi(e,fe);break;case Ri.DisplayUnit:if("video"!==(null==(k=null==(g=this.currentTrack)?void 0:g.info)?void 0:k.type))break;this.currentTrack.info.displayUnit=qi(e,fe);break;case Ri.AlphaMode:if("video"!==(null==(S=null==(T=this.currentTrack)?void 0:T.info)?void 0:S.type))break;this.currentTrack.info.alphaMode=1===qi(e,fe);break;case Ri.Colour:if("video"!==(null==(w=null==(v=this.currentTrack)?void 0:v.info)?void 0:w.type))break;this.currentTrack.info.colorSpace={},this.readContiguousElements(e.slice(me,fe));break;case Ri.MatrixCoefficients:{if("video"!==(null==(I=null==(P=this.currentTrack)?void 0:P.info)?void 0:I.type)||!this.currentTrack.info.colorSpace)break;const t=qi(e,fe),i=null!=(x=F[t])?x:null;this.currentTrack.info.colorSpace.matrix=i}break;case Ri.Range:if("video"!==(null==(E=null==(C=this.currentTrack)?void 0:C.info)?void 0:E.type)||!this.currentTrack.info.colorSpace)break;this.currentTrack.info.colorSpace.fullRange=2===qi(e,fe);break;case Ri.TransferCharacteristics:{if("video"!==(null==(R=null==(A=this.currentTrack)?void 0:A.info)?void 0:R.type)||!this.currentTrack.info.colorSpace)break;const t=qi(e,fe),i=null!=(D=_[t])?D:null;this.currentTrack.info.colorSpace.transfer=i}break;case Ri.Primaries:{if("video"!==(null==(N=null==(M=this.currentTrack)?void 0:M.info)?void 0:N.type)||!this.currentTrack.info.colorSpace)break;const t=qi(e,fe),i=null!=(O=B[t])?O:null;this.currentTrack.info.colorSpace.primaries=i}break;case Ri.Projection:if("video"!==(null==(z=null==(L=this.currentTrack)?void 0:L.info)?void 0:z.type))break;this.readContiguousElements(e.slice(me,fe));break;case Ri.ProjectionPoseRoll:{if("video"!==(null==(q=null==(U=this.currentTrack)?void 0:U.info)?void 0:q.type))break;const t=-Xi(e,fe);try{this.currentTrack.info.rotation=b(t)}catch(pe){}}break;case Ri.Audio:if("audio"!==(null==(V=null==(W=this.currentTrack)?void 0:W.info)?void 0:V.type))break;this.readContiguousElements(e.slice(me,fe));break;case Ri.SamplingFrequency:if("audio"!==(null==(K=null==(H=this.currentTrack)?void 0:H.info)?void 0:K.type))break;this.currentTrack.info.sampleRate=Xi(e,fe);break;case Ri.Channels:if("audio"!==(null==(X=null==(j=this.currentTrack)?void 0:j.info)?void 0:X.type))break;this.currentTrack.info.numberOfChannels=qi(e,fe);break;case Ri.BitDepth:if("audio"!==(null==(G=null==($=this.currentTrack)?void 0:$.info)?void 0:G.type))break;this.currentTrack.info.bitDepth=qi(e,fe);break;case Ri.CuePoint:if(!this.currentSegment)break;this.readContiguousElements(e.slice(me,fe)),this.currentCueTime=null;break;case Ri.CueTime:this.currentCueTime=qi(e,fe);break;case Ri.CueTrackPositions:{if(null===this.currentCueTime)break;y(this.currentSegment);const t={time:this.currentCueTime,trackId:-1,clusterPosition:-1};this.currentSegment.cuePoints.push(t),this.readContiguousElements(e.slice(me,fe)),-1!==t.trackId&&-1!==t.clusterPosition||this.currentSegment.cuePoints.pop()}break;case Ri.CueTrack:{const t=null==(Y=this.currentSegment)?void 0:Y.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;t.trackId=qi(e,fe)}break;case Ri.CueClusterPosition:{const t=null==(J=this.currentSegment)?void 0:J.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;y(this.currentSegment),t.clusterPosition=this.currentSegment.dataStartPos+qi(e,fe)}break;case Ri.Timestamp:if(!this.currentCluster)break;this.currentCluster.timestamp=qi(e,fe);break;case Ri.SimpleBlock:{if(!this.currentCluster)break;const t=Ui(e);if(null===t)break;const i=this.getTrackDataInCluster(this.currentCluster,t);if(!i)break;const r=Aa(e),n=Ca(e),s=n>>1&3;let a=!!(128&n);"audio"===(null==(Z=i.track.info)?void 0:Z.type)&&i.track.info.codec&&(a=!0);const o=xa(e,fe-(e.filePos-me)),l=i.track.decodingInstructions.length>0;i.blocks.push({timestamp:r,duration:0,isKeyFrame:a,data:o,lacing:s,decoded:!l,mainAdditional:null})}break;case Ri.BlockGroup:if(!this.currentCluster)break;this.readContiguousElements(e.slice(me,fe)),this.currentBlock=null;break;case Ri.Block:{if(!this.currentCluster)break;const t=Ui(e);if(null===t)break;const i=this.getTrackDataInCluster(this.currentCluster,t);if(!i)break;const r=Aa(e),n=Ca(e)>>1&3,s=xa(e,fe-(e.filePos-me)),a=i.track.decodingInstructions.length>0;this.currentBlock={timestamp:r,duration:0,isKeyFrame:!0,data:s,lacing:n,decoded:!a,mainAdditional:null},i.blocks.push(this.currentBlock)}break;case Ri.BlockAdditions:this.readContiguousElements(e.slice(me,fe));break;case Ri.BlockMore:if(!this.currentBlock)break;this.currentBlockAdditional={addId:1,data:null},this.readContiguousElements(e.slice(me,fe)),this.currentBlockAdditional.data&&1===this.currentBlockAdditional.addId&&(this.currentBlock.mainAdditional=this.currentBlockAdditional.data),this.currentBlockAdditional=null;break;case Ri.BlockAdditional:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.data=xa(e,fe);break;case Ri.BlockAddID:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.addId=qi(e,fe);break;case Ri.BlockDuration:if(!this.currentBlock)break;this.currentBlock.duration=qi(e,fe);break;case Ri.ReferenceBlock:if(!this.currentBlock)break;this.currentBlock.isKeyFrame=!1;break;case Ri.Tag:this.currentTagTargetIsMovie=!0,this.readContiguousElements(e.slice(me,fe));break;case Ri.Targets:this.readContiguousElements(e.slice(me,fe));break;case Ri.TargetTypeValue:50!==qi(e,fe)&&(this.currentTagTargetIsMovie=!1);break;case Ri.TagTrackUID:case Ri.TagEditionUID:case Ri.TagChapterUID:case Ri.TagAttachmentUID:this.currentTagTargetIsMovie=!1;break;case Ri.SimpleTag:if(!this.currentTagTargetIsMovie)break;this.currentSimpleTagName=null,this.readContiguousElements(e.slice(me,fe));break;case Ri.TagName:this.currentSimpleTagName=ji(e,fe);break;case Ri.TagString:{if(!this.currentSimpleTagName)break;const t=ji(e,fe);this.processTagValue(this.currentSimpleTagName,t)}break;case Ri.TagBinary:{if(!this.currentSimpleTagName)break;const t=xa(e,fe);this.processTagValue(this.currentSimpleTagName,t)}break;case Ri.AttachedFile:{if(!this.currentSegment)break;this.currentAttachedFile={fileUid:null,fileName:null,fileMediaType:null,fileData:null,fileDescription:null},this.readContiguousElements(e.slice(me,fe));const t=this.currentSegment.metadataTags;if(this.currentAttachedFile.fileUid&&this.currentAttachedFile.fileData&&(null!=t.raw||(t.raw={}),t.raw[this.currentAttachedFile.fileUid.toString()]=new Ce(this.currentAttachedFile.fileData,null!=(te=this.currentAttachedFile.fileMediaType)?te:void 0,null!=(ie=this.currentAttachedFile.fileName)?ie:void 0,null!=(re=this.currentAttachedFile.fileDescription)?re:void 0)),(null==(ne=this.currentAttachedFile.fileMediaType)?void 0:ne.startsWith("image/"))&&this.currentAttachedFile.fileData){const e=this.currentAttachedFile.fileName;let i="unknown";if(e){const t=e.toLowerCase();t.startsWith("cover.")?i="coverFront":t.startsWith("back.")&&(i="coverBack")}null!=t.images||(t.images=[]),t.images.push({data:this.currentAttachedFile.fileData,mimeType:this.currentAttachedFile.fileMediaType,kind:i,name:null!=(se=this.currentAttachedFile.fileName)?se:void 0,description:null!=(ae=this.currentAttachedFile.fileDescription)?ae:void 0})}this.currentAttachedFile=null}break;case Ri.FileUID:if(!this.currentAttachedFile)break;this.currentAttachedFile.fileUid=((e,t)=>{if(t<1)throw new Error("Bad unsigned int size "+t);let i=BigInt("0");for(let r=0;rt.order-e.order);break;case Ri.ContentEncoding:this.currentDecodingInstruction={order:0,scope:dr.Block,data:null},this.readContiguousElements(e.slice(me,fe)),this.currentDecodingInstruction.data&&this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction),this.currentDecodingInstruction=null;break;case Ri.ContentEncodingOrder:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.order=qi(e,fe);break;case Ri.ContentEncodingScope:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.scope=qi(e,fe);break;case Ri.ContentCompression:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decompress",algorithm:fr.Zlib,settings:null},this.readContiguousElements(e.slice(me,fe));break;case Ri.ContentCompAlgo:if("decompress"!==(null==(le=null==(oe=this.currentDecodingInstruction)?void 0:oe.data)?void 0:le.type))break;this.currentDecodingInstruction.data.algorithm=qi(e,fe);break;case Ri.ContentCompSettings:if("decompress"!==(null==(ue=null==(ce=this.currentDecodingInstruction)?void 0:ce.data)?void 0:ue.type))break;this.currentDecodingInstruction.data.settings=xa(e,fe);break;case Ri.ContentEncryption:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decrypt"}}return e.filePos=me+fe,!0}decodeBlockData(e,t){y(e.decodingInstructions.length>0);let i=t;for(const r of e.decodingInstructions)if(y(r.data),"decompress"===r.data.type)if(r.data.algorithm===fr.HeaderStripping)if(r.data.settings&&r.data.settings.length>0){const e=r.data.settings,t=new Uint8Array(e.length+i.length);t.set(e,0),t.set(i,e.length),i=t}return i}processTagValue(e,t){var i,r;if(!(null==(i=this.currentSegment)?void 0:i.metadataTags))return;const n=this.currentSegment.metadataTags;if(null!=n.raw||(n.raw={}),null!=(r=n.raw)[e]||(r[e]=t),"string"===typeof t)switch(e.toLowerCase()){case"title":null!=n.title||(n.title=t);break;case"description":null!=n.description||(n.description=t);break;case"artist":null!=n.artist||(n.artist=t);break;case"album":null!=n.album||(n.album=t);break;case"album_artist":null!=n.albumArtist||(n.albumArtist=t);break;case"genre":null!=n.genre||(n.genre=t);break;case"comment":null!=n.comment||(n.comment=t);break;case"lyrics":null!=n.lyrics||(n.lyrics=t);break;case"date":{const e=new Date(t);Number.isNaN(e.getTime())||null!=n.date||(n.date=e)}break;case"track_number":case"part_number":{const e=t.split("/"),i=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(null!=n.trackNumber||(n.trackNumber=i)),r&&Number.isInteger(r)&&r>0&&(null!=n.tracksTotal||(n.tracksTotal=r))}break;case"disc_number":case"disc":{const e=t.split("/"),i=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(null!=n.discNumber||(n.discNumber=i)),r&&Number.isInteger(r)&&r>0&&(null!=n.discsTotal||(n.discsTotal=r))}}}}class yr{constructor(e){this.internalTrack=e,this.packetToClusterLocation=new WeakMap}getId(){return this.internalTrack.id}getNumber(){const e=this.internalTrack.demuxer,t=this.internalTrack.trackBacking.getType();let i=0;for(const r of e.segments)for(const e of r.tracks)if(e.trackBacking.getType()===t&&i++,e===this.internalTrack)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.codecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.segment.timestampFactor}isRelativeToUnixEpoch(){return!1}getDisposition(){return this.internalTrack.disposition}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){var e;const t=this.internalTrack.segment;if(t.duration<=0)return null;let i=t.duration/t.timestampFactor;const r=yield this.getFirstPacket({metadataOnly:!0});return i+=null!=(e=null==r?void 0:r.timestamp)?e:0,i})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getFirstPacket(e){return d(this,null,function*(){return this.performClusterLookup(null,e=>e.trackData.get(this.internalTrack.id)?{blockIndex:0,correctBlockFound:!0}:{blockIndex:-1,correctBlockFound:!1},-1/0,1/0,e)})}intoTimescale(e){return G(e*this.internalTrack.segment.timestampFactor)}getPacket(e,t){return d(this,null,function*(){const i=this.intoTimescale(e);return this.performClusterLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const r=z(t.presentationTimestamps,i,e=>e.timestamp);return{blockIndex:-1!==r?t.presentationTimestamps[r].blockIndex:-1,correctBlockFound:-1!==r&&i{if(e===i.cluster){const t=e.trackData.get(this.internalTrack.id);if(i.blockIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const r=V(t.presentationTimestamps,e=>t.blocks[e.blockIndex].isKeyFrame&&e.timestamp<=i);return{blockIndex:-1!==r?t.presentationTimestamps[r].blockIndex:-1,correctBlockFound:-1!==r&&i{if(e===i.cluster){const t=e.trackData.get(this.internalTrack.id).blocks.findIndex((e,t)=>e.isKeyFrame&&t>i.blockIndex);if(-1!==t)return{blockIndex:t,correctBlockFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.blocks.findIndex(e=>e.isKeyFrame);return y(-1!==e),{blockIndex:e,correctBlockFound:!0}}}return{blockIndex:-1,correctBlockFound:!1}},-1/0,1/0,t)})}fetchPacketInCluster(e,t,i){return d(this,null,function*(){var r;if(-1===t)return null;const n=e.trackData.get(this.internalTrack.id).blocks[t];y(n),n.decoded||(n.data=this.internalTrack.demuxer.decodeBlockData(this.internalTrack,n.data),n.decoded=!0);const s=i.metadataOnly?Gt:n.data,a=n.timestamp/this.internalTrack.segment.timestampFactor,o=n.duration/this.internalTrack.segment.timestampFactor,l={};n.mainAdditional&&"video"===(null==(r=this.internalTrack.info)?void 0:r.type)&&this.internalTrack.info.alphaMode&&(l.alpha=i.metadataOnly?Gt:n.mainAdditional,l.alphaByteLength=n.mainAdditional.byteLength);const c=new Yt(s,n.isKeyFrame?"key":"delta",a,o,e.dataStartPos+t,n.data.byteLength,l);return this.packetToClusterLocation.set(c,{cluster:e,blockIndex:t}),c})}performClusterLookup(e,t,i,r,n){return d(this,null,function*(){var s,a,o,l;const{demuxer:c,segment:u}=this.internalTrack;let d=null,h=null,f=-1;if(e){const{blockIndex:i,correctBlockFound:r}=t(e);if(r)return this.fetchPacketInCluster(e,i,n);-1!==i&&(h=e,f=i)}const m=z(this.internalTrack.cuePoints,i,e=>e.time),p=-1!==m?this.internalTrack.cuePoints[m]:null,g=z(this.internalTrack.clusterPositionCache,i,e=>e.startTimestamp),k=-1!==g?this.internalTrack.clusterPositionCache[g]:null,b=Math.max(null!=(s=null==p?void 0:p.clusterPosition)?s:0,null!=(a=null==k?void 0:k.elementStartPos)?a:0)||null;let T;for(e?null===b||e.elementStartPos>=b?(T=e.elementEndPos,d=e):T=b:T=null!=b?b:u.clusterSeekStartPos;null===u.elementEndPos||T<=u.elementEndPos-2;){if(d){const e=d.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>r)break}let e=c.reader.requestSliceRange(T,2,Li);if(e instanceof Promise&&(e=yield e),!e)break;const i=T,s=Hi(e);if(!s||!Ni.includes(s.id)&&s.id!==Ri.Void){const e=yield Qi(c.reader,i,Ni,Math.min(null!=(o=u.elementEndPos)?o:1/0,i+gr));if(e){T=e;continue}break}const a=s.id;let l=s.size;const m=e.filePos;if(a===Ri.Cluster){d=yield c.readCluster(i,u),l=d.elementEndPos-m;const{blockIndex:e,correctBlockFound:r}=t(d);if(r)return this.fetchPacketInCluster(d,e,n);-1!==e&&(h=d,f=e)}if(void 0===l){y(a!==Ri.Cluster);l=(yield $i(c.reader,m,Oi,u.elementEndPos)).pos-m}const p=m+l;if(null===u.elementEndPos){let e=c.reader.requestSliceRange(p,2,Li);if(e instanceof Promise&&(e=yield e),!e)break;if(Wi(e)===Ri.Segment){u.elementEndPos=p;break}}T=p}if(p&&(!h||h.elementStartPosd(this,null,function*(){var e,t;let i=null;("vp9"===this.internalTrack.info.codec||"av1"===this.internalTrack.info.codec||"avc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription||"hevc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription)&&(i=yield this.getFirstPacket({}));const r={codec:Ue({width:this.internalTrack.info.width,height:this.internalTrack.info.height,codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,colorSpace:this.internalTrack.info.colorSpace,avcType:1,avcCodecInfo:"avc"===this.internalTrack.info.codec&&i?pt(i.data):null,hevcCodecInfo:"hevc"===this.internalTrack.info.codec&&i?vt(i.data):null,vp9CodecInfo:"vp9"===this.internalTrack.info.codec&&i?Rt(i.data):null,av1CodecInfo:"av1"===this.internalTrack.info.codec&&i?Mt(i.data):null}),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0,colorSpace:null!=(t=this.internalTrack.info.colorSpace)?t:void 0};return this.internalTrack.info.width===this.internalTrack.info.squarePixelWidth&&this.internalTrack.info.height===this.internalTrack.info.squarePixelHeight||(r.displayAspectWidth=this.internalTrack.info.squarePixelWidth,r.displayAspectHeight=this.internalTrack.info.squarePixelHeight),r}))():null})}}class Tr extends yr{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getType(){return"audio"}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}getDecoderConfig(){return d(this,null,function*(){var e,t;return this.internalTrack.info.codec?null!=(t=this.decoderConfig)?t:this.decoderConfig={codec:qe({codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,aacCodecInfo:this.internalTrack.info.aacCodecInfo}),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0}:null})}}const Sr=(e,t,i)=>d(null,null,function*(){const r=o(2,16);let n=t;for(;null===i||n=4;){const t=s.filePos,i=Ra(s),r=null!==e.fileSize?e.fileSize-n:null,a=Ye(i,r);if(a.header)return{header:a.header,startPos:n};s.filePos=t+a.bytesAdvanced,n=s.filePos}}return null});class vr extends Qt{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.firstFrameHeaderPos=null,this.loadedSamples=[],this.metadataTags=null,this.xingData=null,this.trackBackings=[],this.readingMutex=new D,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}readMetadata(){return d(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)yield this.advanceReader();if(!this.firstFrameHeader)throw new Error("No valid MP3 frame found.");this.trackBackings=[new wr(this)]}))()})}advanceReader(){return d(this,null,function*(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,Qa);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=Za(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}const e=yield Sr(this.reader,this.lastLoadedPos,this.reader.fileSize);if(!e)return void(this.lastSampleLoaded=!0);const t=e.header;this.lastLoadedPos=e.startPos+t.totalSize-1;const i=Ge(t.mpegVersionId,t.channel);let r=this.reader.requestSlice(e.startPos+i,4);if(r instanceof Promise&&(r=yield r),r){const t=Ra(r);if(t===$e||t===Qe){if(!this.xingData){let t=this.reader.requestSlice(e.startPos+i+4,12);if(t instanceof Promise&&(t=yield t),t){const e=xa(t,12),i=P(e),r=i.getUint32(0,!1);this.xingData={frameCount:r&Ze.FrameCount?i.getUint32(4,!1):null,fileSize:r&Ze.FileSize?i.getUint32(8,!1):null}}}return}}this.firstFrameHeader||(this.firstFrameHeader=t,this.firstFrameHeaderPos=e.startPos),t.sampleRate!==this.firstFrameHeader.sampleRate&&console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${t.sampleRate} Hz. Might be a bug, so please report this file.`);const n=t.audioSamplesInFrame/this.firstFrameHeader.sampleRate,s={timestamp:this.nextTimestampInSamples/this.firstFrameHeader.sampleRate,duration:n,dataStart:e.startPos,dataSize:t.totalSize};this.loadedSamples.push(s),this.nextTimestampInSamples+=t.audioSamplesInFrame})}getMimeType(){return d(this,null,function*(){return"audio/mpeg"})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackings})}getMetadataTags(){return d(this,null,function*(){const e=yield this.readingMutex.acquire();try{if(yield this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0,t=!1;for(;;){let i=this.reader.requestSlice(e,Qa);if(i instanceof Promise&&(i=yield i),!i)break;const r=Za(i);if(!r)break;t=!0;let n=this.reader.requestSlice(i.filePos,r.size);if(n instanceof Promise&&(n=yield n),!n)break;eo(n,r,this.metadataTags),e=i.filePos+r.size}if(!t&&null!==this.reader.fileSize&&this.reader.fileSize>=$a){let e=this.reader.requestSlice(this.reader.fileSize-$a,$a);e instanceof Promise&&(e=yield e),y(e);"TAG"===Wa(e,3)&&Ya(e,this.metadataTags)}return this.metadataTags}finally{e()}})}}class wr{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getTimeResolution(){return y(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.sampleRate/this.demuxer.firstFrameHeader.audioSamplesInFrame}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){const e=this.demuxer;if(y(null!==e.firstFrameHeader),y(null!==e.firstFrameHeaderPos),e.xingData){if(null!==e.xingData.frameCount)return e.xingData.frameCount*e.firstFrameHeader.audioSamplesInFrame/e.firstFrameHeader.sampleRate}else if(null!==e.reader.fileSize){const s=(t=e.firstFrameHeader.lowSamplingFrequency,i=e.firstFrameHeader.layer,r=e.firstFrameHeader.bitrate,n=e.firstFrameHeader.sampleRate,0===i?0:1===i?144*r/(n<e.timestamp);if(-1===i)throw new Error("Packet was not created from this track.");const r=i+1;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{i()}})}getPacket(e,t){return d(this,null,function*(){const i=yield this.demuxer.readingMutex.acquire();try{for(;;){const i=z(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===i&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(i,t);if(i>=0&&i+1>>0&4294967295}const xr=e=>{const t=P(e),i=t.getUint32(22,!0);t.setUint32(22,0,!0);let r=0;for(let n=0;n>>24^t])>>>0}return t.setUint32(22,i,!0),r},Cr=(e,t,i)=>{let r=0,n=null;if(e.length>0)if("vorbis"===t.codec){y(t.vorbisInfo);const s=(1<<(e=>{let t=0;for(;e;)t++,e>>=1;return t})(t.vorbisInfo.modeBlockflags.length-1))-1<<1,a=(e[0]&s)>>1;if(a>=t.vorbisInfo.modeBlockflags.length)throw new Error("Invalid mode number.");let o=i;const l=t.vorbisInfo.modeBlockflags[a];if(n=t.vorbisInfo.blocksizes[l],1===l){const i=1+(1|s),r=e[0]&i?1:0;o=t.vorbisInfo.blocksizes[r]}r=null!==o?o+n>>2:0}else if("opus"===t.codec){r=(e=>{const t=e[0]>>3;return{durationInSamples:Nt[t]}})(e).durationInSamples}return{durationInSamples:r,vorbisBlockSize:n}},Br=27,Er=282,_r=e=>{const t=e.filePos;if(Da(e)!==Pr)return null;e.skip(1);const i=Ca(e),r=za(e),n=Da(e),s=Da(e),a=Da(e),o=Ca(e),l=new Uint8Array(o);for(let d=0;de+t,0);return{headerStartPos:t,totalSize:c+u,dataStartPos:t+c,dataSize:u,headerType:i,granulePosition:r,serialNumber:n,sequenceNumber:s,checksum:a,lacingValues:l}},Ar=(e,t)=>{for(;e.filePos>>8&255)===i||(t>>>16&255)===i||(t>>>24&255)===i){if(e.skip(-4),t===Pr)return!0;e.skip(1)}}return!1};class Fr extends Qt{constructor(e){super(e),this.metadataPromise=null,this.bitstreams=[],this.trackBackings=[],this.metadataTags={},this.reader=e._reader}readMetadata(){return d(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,Br,Er);if(t instanceof Promise&&(t=yield t),!t)break;const i=_r(t);if(!i)break;if(!!!(2&i.headerType))break;this.bitstreams.push({serialNumber:i.serialNumber,bosPage:i,description:null,numberOfChannels:-1,sampleRate:-1,codecInfo:{codec:null,vorbisInfo:null,opusInfo:null},lastMetadataPacket:null}),e=i.headerStartPos+i.totalSize}for(const t of this.bitstreams){const e=yield this.readPacket(t.bosPage,0);e&&(e.data.byteLength>=7&&1===e.data[0]&&118===e.data[1]&&111===e.data[2]&&114===e.data[3]&&98===e.data[4]&&105===e.data[5]&&115===e.data[6]?yield this.readVorbisMetadata(e,t):e.data.byteLength>=8&&79===e.data[0]&&112===e.data[1]&&117===e.data[2]&&115===e.data[3]&&72===e.data[4]&&101===e.data[5]&&97===e.data[6]&&100===e.data[7]&&(yield this.readOpusMetadata(e,t)),null!==t.codecInfo.codec&&this.trackBackings.push(new Rr(t,this)))}}))()})}readVorbisMetadata(e,t){return d(this,null,function*(){let i=yield this.findNextPacketStart(e);if(!i)return;const r=yield this.readPacket(i.startPage,i.startSegmentIndex);if(!r)return;if(i=yield this.findNextPacketStart(r),!i)return;const n=yield this.readPacket(i.startPage,i.startSegmentIndex);if(!n)return;if(3!==r.data[0]||5!==n.data[0])return;const s=[],a=e=>{for(;s.push(Math.min(255,e)),!(e<255);)e-=255};a(e.data.length),a(r.data.length);const o=new Uint8Array(1+s.length+e.data.length+r.data.length+n.data.length);o[0]=2,o.set(s,1),o.set(e.data,1+s.length),o.set(r.data,1+s.length+e.data.length),o.set(n.data,1+s.length+e.data.length+r.data.length),t.codecInfo.codec="vorbis",t.description=o,t.lastMetadataPacket=n;const l=P(e.data);t.numberOfChannels=l.getUint8(11),t.sampleRate=l.getUint32(12,!0);const c=l.getUint8(28);t.codecInfo.vorbisInfo={blocksizes:[1<<(15&c),1<<(c>>4)],modeBlockflags:Ot(n.data).modeBlockflags},qt(r.data.subarray(7),this.metadataTags)})}readOpusMetadata(e,t){return d(this,null,function*(){const i=yield this.findNextPacketStart(e);if(!i)return;const r=yield this.readPacket(i.startPage,i.startSegmentIndex);if(!r)return;t.codecInfo.codec="opus",t.description=e.data,t.lastMetadataPacket=r;const n=(e=>{const t=P(e),i=t.getUint8(9),r=t.getUint16(10,!0),n=t.getUint32(12,!0),s=t.getInt16(16,!0),a=t.getUint8(18);let o=null;return a&&(o=e.subarray(19,21+i)),{outputChannelCount:i,preSkip:r,inputSampleRate:n,outputGain:s,channelMappingFamily:a,channelMappingTable:o}})(e.data);t.numberOfChannels=n.outputChannelCount,t.sampleRate=We,t.codecInfo.opusInfo={preSkip:n.preSkip},qt(r.data.subarray(8),this.metadataTags)})}readPacket(e,t){return d(this,null,function*(){y(te+t.length,0);if(0===o)return null;const l=new Uint8Array(o);let c=0;for(let e=0;e{let t="audio/ogg";e.codecStrings&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({codecStrings:(yield Promise.all(this.trackBackings.map(e=>e.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null})))).filter(Boolean)})})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackings})}getMetadataTags(){return d(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}}class Rr{constructor(e,t){this.bitstream=e,this.demuxer=t,this.encodedPacketToMetadata=new WeakMap,this.sequentialScanCache=[],this.sequentialScanMutex=new D,this.internalSampleRate="opus"===e.codecInfo.codec?We:e.sampleRate}getType(){return"audio"}getId(){return this.bitstream.serialNumber}getNumber(){const e=this.demuxer.trackBackings.findIndex(e=>e.bitstream===this.bitstream);return y(-1!==e),e+1}getNumberOfChannels(){return this.bitstream.numberOfChannels}getSampleRate(){return this.bitstream.sampleRate}getTimeResolution(){return this.bitstream.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return null})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getCodec(){return this.bitstream.codecInfo.codec}getInternalCodecId(){return null}getDecoderConfig(){return d(this,null,function*(){var e;return y(this.bitstream.codecInfo.codec),{codec:this.bitstream.codecInfo.codec,numberOfChannels:this.bitstream.numberOfChannels,sampleRate:this.bitstream.sampleRate,description:null!=(e=this.bitstream.description)?e:void 0}})}getName(){return null}getLanguageCode(){return Q}getDisposition(){return u(c({},Be),{primary:!1})}granulePositionToTimestampInSamples(e){return"opus"===this.bitstream.codecInfo.codec?(y(this.bitstream.codecInfo.opusInfo),e-this.bitstream.codecInfo.opusInfo.preSkip):e}createEncodedPacketFromOggPacket(e,t,i){if(!e)return null;const{durationInSamples:r,vorbisBlockSize:n}=Cr(e.data,this.bitstream.codecInfo,t.vorbisLastBlocksize),s=new Yt(i.metadataOnly?Gt:e.data,"key",Math.max(0,t.timestampInSamples)/this.internalSampleRate,r/this.internalSampleRate,e.endPage.headerStartPos+e.endSegmentIndex,e.data.byteLength);return this.encodedPacketToMetadata.set(s,{packet:e,timestampInSamples:t.timestampInSamples,durationInSamples:r,vorbisLastBlockSize:t.vorbisLastBlocksize,vorbisBlockSize:n}),s}getFirstPacket(e){return d(this,null,function*(){y(this.bitstream.lastMetadataPacket);const t=yield this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!t)return null;let i=0;"opus"===this.bitstream.codecInfo.codec&&(y(this.bitstream.codecInfo.opusInfo),i-=this.bitstream.codecInfo.opusInfo.preSkip);const r=yield this.demuxer.readPacket(t.startPage,t.startSegmentIndex);return this.createEncodedPacketFromOggPacket(r,{timestampInSamples:i,vorbisLastBlocksize:null},e)})}getNextPacket(e,t){return d(this,null,function*(){const i=this.encodedPacketToMetadata.get(e);if(!i)throw new Error("Packet was not created from this track.");const r=yield this.demuxer.findNextPacketStart(i.packet);if(!r)return null;const n=i.timestampInSamples+i.durationInSamples,s=yield this.demuxer.readPacket(r.startPage,r.startSegmentIndex);return this.createEncodedPacketFromOggPacket(s,{timestampInSamples:n,vorbisLastBlocksize:i.vorbisBlockSize},t)})}getPacket(e,t){return d(this,null,function*(){var i,r;if(null===this.demuxer.reader.fileSize)return this.getPacketSequential(e,t);const n=G(e*this.internalSampleRate);if(0===n)return this.getFirstPacket(t);if(n<0)return null;y(this.bitstream.lastMetadataPacket);const s=yield this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!s)return null;let a=s.startPage,o=this.demuxer.reader.fileSize;const l=[a];e:for(;a.headerStartPos+a.totalSizen?o=c.headerStartPos:(a=c,l.push(c));continue e}i=c.headerStartPos+c.totalSize}}let c=s.startPage;for(const e of l){if(e.granulePosition===a.granulePosition)break;(!c||e.headerStartPos>c.headerStartPos)&&(c=e)}let u=c;const d=[u];for(;u.serialNumber!==this.bitstream.serialNumber||u.granulePosition!==a.granulePosition;){const e=u.headerStartPos+u.totalSize;let t=this.demuxer.reader.requestSliceRange(e,Br,Er);t instanceof Promise&&(t=yield t),y(t);const i=_r(t);y(i),u=i,u.serialNumber===this.bitstream.serialNumber&&d.push(u)}y(-1!==u.granulePosition);let h,f,m=null,p=u,g=0;if(u.headerStartPos===s.startPage.headerStartPos)h=this.granulePositionToTimestampInSamples(0),f=!0,m=0;else{h=0,f=!1;for(let t=u.lacingValues.length-1;t>=0;t--){if(u.lacingValues[t]<255){m=t+1;break}}if(null===m)throw new Error("Invalid page with granule position: no packets end on this page.");g=m-1;const e={data:Gt,endPage:p,endSegmentIndex:g};if(yield this.demuxer.findNextPacketStart(e)){const e=Mr(d,u,m);y(e);const t=Dr(d,e.page,e.segmentIndex);t&&(u=t.page,m=t.segmentIndex)}else for(;;){const e=Mr(d,u,m);if(!e)break;const t=Dr(d,e.page,e.segmentIndex);if(!t)break;if(u=t.page,m=t.segmentIndex,e.page.headerStartPos!==p.headerStartPos){p=e.page,g=e.segmentIndex;break}}}let k=null,b=null;for(;null!==u;){y(null!==m);const e=yield this.demuxer.readPacket(u,m);if(!e)break;if(!(u.headerStartPos===s.startPage.headerStartPos&&mn||Math.max(a.timestampInSamples,0)===n))break}const a=yield this.demuxer.findNextPacketStart(e);if(!a)break;u=a.startPage,m=a.startSegmentIndex}return k})}getPacketSequential(e,t){return d(this,null,function*(){const i=yield this.sequentialScanMutex.acquire();try{const i=G(e*this.internalSampleRate);e=i/this.internalSampleRate;const r=z(this.sequentialScanCache,i,e=>e.timestampInSamples);let n;if(-1!==r){const e=this.sequentialScanCache[r];n=this.createEncodedPacketFromOggPacket(e.packet,{timestampInSamples:e.timestampInSamples,vorbisLastBlocksize:e.vorbisLastBlockSize},t)}else n=yield this.getFirstPacket(t);let s=0;for(;n&&n.timestampe)break;if(n=i,s++,100===s){s=0;const e=this.encodedPacketToMetadata.get(n);y(e),this.sequentialScanCache.length>0&&y(T(this.sequentialScanCache).timestampInSamples<=e.timestampInSamples),this.sequentialScanCache.push(e)}}return n}finally{i()}})}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Dr=(e,t,i)=>{let r=t,n=i;e:for(;;){for(n--;n>=0;n--){if(r.lacingValues[n]<255){n++;break e}}y(-1===n);if(!(1&r.headerType)){n=0;break}const t=W(e,e=>e.headerStartPos{if(i>0)return{page:t,segmentIndex:i-1};const r=W(e,e=>e.headerStartPosd(this,null,function*(){var e,t;let i=this.reader.requestSlice(0,12);i instanceof Promise&&(i=yield i),y(i);const r=Wa(i,4),n="RIFX"!==r,s="RF64"===r,a=Fa(i,n);let o=s?this.reader.fileSize:Math.min(a+8,null!=(e=this.reader.fileSize)?e:1/0);if("WAVE"!==Wa(i,4))throw new Error("Invalid WAVE file - wrong format");let l=0,c=null,u=i.filePos;for(;null===o||u=18&&357!==n){const e=Ba(r,i),s=t-18;if(Math.min(s,e)>=22&&n===Nr.EXTENSIBLE){r.skip(6);const e=xa(r,16);n=e[0]|e[1]<<8}}n!==Nr.MULAW&&n!==Nr.ALAW||(l=8),this.audioInfo={format:n,numberOfChannels:s,sampleRate:a,sampleSizeInBytes:Math.ceil(l/8),blockSizeInBytes:o}})}parseListChunk(e,t,i){return d(this,null,function*(){var r,n,s,a,o,l,c,u,d,h,f;let m=this.reader.requestSlice(e,t);if(m instanceof Promise&&(m=yield m),!m)return;const p=Wa(m,4);if("INFO"!==p&&"INF0"!==p)return;let g=m.filePos;for(;g<=e+t-8;){m.filePos=g;const e=Wa(m,4),t=Fa(m,i),p=xa(m,t);let k=0;for(let i=0;i0&&(null!=(l=this.metadataTags).trackNumber||(l.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&(null!=(c=this.metadataTags).tracksTotal||(c.tracksTotal=i))}break;case"ICRD":case"IDIT":{const e=new Date(y);Number.isNaN(e.getTime())||null!=(u=this.metadataTags).date||(u.date=e)}break;case"YEAR":{const e=Number.parseInt(y,10);Number.isInteger(e)&&e>0&&(null!=(d=this.metadataTags).date||(d.date=new Date(e,0,1)))}break;case"IGNR":case"GENR":null!=(h=this.metadataTags).genre||(h.genre=y);break;case"ICMT":case"CMNT":case"COMM":null!=(f=this.metadataTags).comment||(f.comment=y)}g+=8+t+(1&t)}})}parseId3Chunk(e,t){return d(this,null,function*(){let i=this.reader.requestSlice(e,t);if(i instanceof Promise&&(i=yield i),!i)return;const r=Za(i);if(r){const n=t-Qa;if(r.size=Math.min(r.size,n),r.size>0){const t=i.slice(e+Qa,r.size);eo(t,r,this.metadataTags)}}})}getCodec(){if(y(this.audioInfo),this.audioInfo.format===Nr.MULAW)return"ulaw";if(this.audioInfo.format===Nr.ALAW)return"alaw";if(this.audioInfo.format===Nr.PCM){if(1===this.audioInfo.sampleSizeInBytes)return"pcm-u8";if(2===this.audioInfo.sampleSizeInBytes)return"pcm-s16";if(3===this.audioInfo.sampleSizeInBytes)return"pcm-s24";if(4===this.audioInfo.sampleSizeInBytes)return"pcm-s32"}return this.audioInfo.format===Nr.IEEE_FLOAT&&4===this.audioInfo.sampleSizeInBytes?"pcm-f32":null}getMimeType(){return d(this,null,function*(){return"audio/wav"})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackings})}getMetadataTags(){return d(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}}const zr=2048;class Ur{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getCodec(){return this.demuxer.getCodec()}getInternalCodecId(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.format}getDecoderConfig(){return d(this,null,function*(){const e=this.demuxer.getCodec();return e?(y(this.demuxer.audioInfo),{codec:e,numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate}):null})}getNumberOfChannels(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getTimeResolution(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return y(-1!==this.demuxer.dataSize),this.demuxer.dataSize/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getName(){return null}getLanguageCode(){return Q}getDisposition(){return c({},Be)}getPacketAtIndex(e,t){return d(this,null,function*(){y(e>=0),y(this.demuxer.audioInfo);const i=e*zr*this.demuxer.audioInfo.blockSizeInBytes;if(i>=this.demuxer.dataSize)return null;const r=Math.min(zr*this.demuxer.audioInfo.blockSizeInBytes,this.demuxer.dataSize-i);if(null===this.demuxer.reader.fileSize){let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+i,r);if(e instanceof Promise&&(e=yield e),!e)return null}let n;if(t.metadataOnly)n=Gt;else{let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+i,r);e instanceof Promise&&(e=yield e),y(e),n=xa(e,r)}const s=e*zr/this.demuxer.audioInfo.sampleRate,a=r/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate;return this.demuxer.lastKnownPacketIndex=Math.max(e,this.demuxer.lastKnownPacketIndex),new Yt(n,"key",s,a,e,r)})}getFirstPacket(e){return this.getPacketAtIndex(0,e)}getPacket(e,t){return d(this,null,function*(){y(this.demuxer.audioInfo);const i=Math.floor(Math.min(e*this.demuxer.audioInfo.sampleRate/zr,(this.demuxer.dataSize-1)/(zr*this.demuxer.audioInfo.blockSizeInBytes)));if(i<0)return null;const r=yield this.getPacketAtIndex(i,t);if(r)return r;if(0===i)return null;y(null===this.demuxer.reader.fileSize);let n=yield this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex,t);for(;n;){const e=yield this.getNextPacket(n,t);if(!e)break;n=e}return n})}getNextPacket(e,t){y(this.demuxer.audioInfo);const i=Math.round(e.timestamp*this.demuxer.audioInfo.sampleRate/zr);return this.getPacketAtIndex(i+1,t)}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const qr=e=>{const t=e.filePos,i=xa(e,9),r=new Ee(i);if(4095!==r.readBits(12))return null;r.skipBits(1);if(0!==r.readBits(2))return null;const n=r.readBits(1),s=r.readBits(2)+1,a=r.readBits(4);if(15===a)return null;r.skipBits(1);const o=r.readBits(3);if(0===o)throw new Error("ADTS frames with channel configuration 0 are not supported.");r.skipBits(1),r.skipBits(1),r.skipBits(1),r.skipBits(1);const l=r.readBits(13);r.skipBits(11);const c=r.readBits(2)+1;if(1!==c)throw new Error("ADTS frames with more than one AAC frame are not supported.");let u=null;return 1===n?e.filePos-=2:u=r.readBits(16),{objectType:s,samplingFrequencyIndex:a,channelConfiguration:o,frameLength:l,numberOfAacFrames:c,crcCheck:u,startPos:t}},Wr=1024;class Vr extends Qt{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.loadedSamples=[],this.metadataTags=null,this.trackBackings=[],this.readingMutex=new D,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}readMetadata(){return d(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)yield this.advanceReader();y(this.firstFrameHeader),this.trackBackings=[new Hr(this)]}))()})}advanceReader(){return d(this,null,function*(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,Qa);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=Za(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}let e=this.reader.requestSliceRange(this.lastLoadedPos,7,9);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=qr(e);if(!t)return void(this.lastSampleLoaded=!0);if(null!==this.reader.fileSize&&t.startPos+t.frameLength>this.reader.fileSize)return void(this.lastSampleLoaded=!0);this.firstFrameHeader||(this.firstFrameHeader=t);const i=_e[t.samplingFrequencyIndex];y(void 0!==i);const r=Wr/i,n={timestamp:this.nextTimestampInSamples/i,duration:r,dataStart:t.startPos,dataSize:t.frameLength};this.loadedSamples.push(n),this.nextTimestampInSamples+=Wr,this.lastLoadedPos=t.startPos+t.frameLength})}getMimeType(){return d(this,null,function*(){return"audio/aac"})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackings})}getMetadataTags(){return d(this,null,function*(){const e=yield this.readingMutex.acquire();try{if(yield this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0;for(;;){let t=this.reader.requestSlice(e,Qa);if(t instanceof Promise&&(t=yield t),!t)break;const i=Za(t);if(!i)break;let r=this.reader.requestSlice(t.filePos,i.size);if(r instanceof Promise&&(r=yield r),!r)break;eo(r,i,this.metadataTags),e=t.filePos+i.size}return this.metadataTags}finally{e()}})}}class Hr{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getTimeResolution(){return this.getSampleRate()/Wr}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return null})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getName(){return null}getLanguageCode(){return Q}getCodec(){return"aac"}getInternalCodecId(){return y(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.objectType}getNumberOfChannels(){y(this.demuxer.firstFrameHeader);const e=Ae[this.demuxer.firstFrameHeader.channelConfiguration];return y(void 0!==e),e}getSampleRate(){y(this.demuxer.firstFrameHeader);const e=_e[this.demuxer.firstFrameHeader.samplingFrequencyIndex];return y(void 0!==e),e}getDisposition(){return c({},Be)}getDecoderConfig(){return d(this,null,function*(){return y(this.demuxer.firstFrameHeader),{codec:`mp4a.40.${this.demuxer.firstFrameHeader.objectType}`,numberOfChannels:this.getNumberOfChannels(),sampleRate:this.getSampleRate()}})}getPacketAtIndex(e,t){return d(this,null,function*(){if(-1===e)return null;const i=this.demuxer.loadedSamples[e];if(!i)return null;let r;if(t.metadataOnly)r=Gt;else{let e=this.demuxer.reader.requestSlice(i.dataStart,i.dataSize);if(e instanceof Promise&&(e=yield e),!e)return null;r=xa(e,i.dataSize)}return new Yt(r,"key",i.timestamp,i.duration,e,i.dataSize)})}getFirstPacket(e){return this.getPacketAtIndex(0,e)}getNextPacket(e,t){return d(this,null,function*(){const i=yield this.demuxer.readingMutex.acquire();try{const i=L(this.demuxer.loadedSamples,e.timestamp,e=>e.timestamp);if(-1===i)throw new Error("Packet was not created from this track.");const r=i+1;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{i()}})}getPacket(e,t){return d(this,null,function*(){const i=yield this.demuxer.readingMutex.acquire();try{for(;;){const i=z(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===i&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(i,t);if(i>=0&&i+1d(this,null,function*(){for(var e;null===this.reader.fileSize||ts.end-6)return{num:a.num,blockSize:a.blockSize,sampleRate:a.sampleRate,size:s.end-e,isLastFrame:!0};if(255===Ca(s)){const t=s.filePos;if(Ca(s)!==(1===this.blockingBit?249:248)){s.filePos=t;continue}s.skip(-2);const i=s.filePos-e,r=this.readFlacFrameHeader({slice:s,isFirstPacket:!1});if(!r){s.filePos=t;continue}if(0===this.blockingBit){if(r.num-a.num!==1){s.filePos=t;continue}}else if(r.num-a.num!==a.blockSize){s.filePos=t;continue}return{num:a.num,blockSize:a.blockSize,sampleRate:a.sampleRate,size:i,isLastFrame:!1}}}})}readFlacFrameHeader({slice:e,isFirstPacket:t}){const i=e.filePos,r=xa(e,4),n=new Ee(r);if(32764!==n.readBits(15))return null;if(null===this.blockingBit){y(t);const e=n.readBits(1);this.blockingBit=e}else if(1===this.blockingBit){y(!t);if(1!==n.readBits(1))return null}else{if(0!==this.blockingBit)throw new Error("Invalid blocking bit");y(!t);if(0!==n.readBits(1))return null}const s=(e=>0===e?null:1===e?192:e>=2&&e<=5?144*o(2,e):6===e?"uncommon-u8":7===e?"uncommon-u16":e>=8&&e<=15?o(2,e):null)(n.readBits(4));if(!s)return null;y(this.audioInfo);const a=((e,t)=>{switch(e){case 0:return t;case 1:return 88200;case 2:return 176400;case 3:return 192e3;case 4:return 8e3;case 5:return 16e3;case 6:return 22050;case 7:return 24e3;case 8:return 32e3;case 9:return 44100;case 10:return 48e3;case 11:return 96e3;case 12:return"uncommon-u8";case 13:return"uncommon-u16";case 14:return"uncommon-u16-10";default:return null}})(n.readBits(4),this.audioInfo.sampleRate);if(!a)return null;n.readBits(4),n.readBits(3);if(0!==n.readBits(1))return null;const l=(e=>{let t=0;const i=new Ee(xa(e,1));for(;1===i.readBits(1);)t++;if(0===t)return i.readBits(7);const r=[],n=t-1,s=new Ee(xa(e,n)),a=8-t-1;for(let o=0;oe|t<"uncommon-u16"===t?Ea(e)+1:"uncommon-u8"===t?Ca(e)+1:"number"===typeof t?t:(H(t),void y(!1)))(e,s),u=((e,t)=>"uncommon-u16"===t?Ea(e):"uncommon-u16-10"===t?10*Ea(e):"uncommon-u8"===t?Ca(e):"number"===typeof t?t:null)(e,a);if(null===u)return null;if(u!==this.audioInfo.sampleRate)return null;const d=e.filePos-i,h=Ca(e);e.skip(-d),e.skip(-1);const f=(e=>{let t=0;for(const i of e){t^=i;for(let e=0;e<8;e++)0!==(128&t)?t=t<<1^7:t<<=1,t&=255}return t})(xa(e,d));return h!==f?null:{num:l,blockSize:c,sampleRate:u}}advanceReader(){return d(this,null,function*(){yield this.readMetadata(),y(null!==this.lastLoadedPos),y(this.audioInfo);const e=this.lastLoadedPos,t=yield this.readNextFlacFrame({startPos:e,isFirstPacket:0===this.loadedSamples.length});if(!t)return void(this.lastSampleLoaded=!0);const i=this.loadedSamples[this.loadedSamples.length-1],r={blockOffset:i?i.blockOffset+i.blockSize:0,blockSize:t.blockSize,byteOffset:e,byteSize:t.size};this.lastLoadedPos=this.lastLoadedPos+t.size,this.loadedSamples.push(r),t.isLastFrame&&(this.lastSampleLoaded=!0)})}}class jr{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getCodec(){return"flac"}getInternalCodecId(){return null}getNumberOfChannels(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return Q}getTimeResolution(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return y(this.demuxer.audioInfo),0===this.demuxer.audioInfo.totalSamples?null:this.demuxer.audioInfo.totalSamples/this.demuxer.audioInfo.sampleRate})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getDisposition(){return c({},Be)}getDecoderConfig(){return d(this,null,function*(){return y(this.demuxer.audioInfo),{codec:"flac",numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate,description:this.demuxer.audioInfo.description}})}getPacket(e,t){return d(this,null,function*(){if(y(this.demuxer.audioInfo),e<0)throw new Error("Timestamp cannot be negative");const i=yield this.demuxer.readingMutex.acquire();try{for(;;){const i=z(this.demuxer.loadedSamples,e,e=>e.blockOffset/this.demuxer.audioInfo.sampleRate);if(-1===i){yield this.demuxer.advanceReader();continue}const r=this.demuxer.loadedSamples[i],n=r.blockOffset/this.demuxer.audioInfo.sampleRate;if(!(n+r.blockSize/this.demuxer.audioInfo.sampleRate<=e))return this.getPacketAtIndex(i,t);if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(this.demuxer.loadedSamples.length-1,t);yield this.demuxer.advanceReader()}}finally{i()}})}getNextPacket(e,t){return d(this,null,function*(){const i=yield this.demuxer.readingMutex.acquire();try{const i=e.sequenceNumber+1;if(this.demuxer.lastSampleLoaded&&i>=this.demuxer.loadedSamples.length)return null;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{i()}})}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}getPacketAtIndex(e,t){return d(this,null,function*(){const i=this.demuxer.loadedSamples[e];if(!i)return null;let r;if(t.metadataOnly)r=Gt;else{let e=this.demuxer.reader.requestSlice(i.byteOffset,i.byteSize);if(e instanceof Promise&&(e=yield e),!e)return null;r=xa(e,i.byteSize)}y(this.demuxer.audioInfo);const n=i.blockOffset/this.demuxer.audioInfo.sampleRate,s=i.blockSize/this.demuxer.audioInfo.sampleRate;return new Yt(r,"key",n,s,e,i.byteSize)})}getFirstPacket(e){return d(this,null,function*(){for(;0===this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(0,e)})}}const Xr=9e4,$r=188,Qr="PES packet is missing PTS where it was expected. PES packets without PTS are not currently supported. If you think this file should be supported, please report it.",Gr=new Set;class Yr extends Qt{constructor(e){super(e),this.metadataPromise=null,this.elementaryStreams=[],this.trackBackingEntries=[],this.packetOffset=0,this.packetStride=-1,this.sectionEndPositions=[],this.seekChunkSize=5242880,this.minReferencePointByteDistance=-1,this.reader=e._reader}readMetadata(){return d(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){let e=this.reader.requestSlice(0,205);e instanceof Promise&&(e=yield e),y(e);const t=xa(e,205);if(71===t[0]&&71===t[188])this.packetOffset=0,this.packetStride=$r;else if(71===t[0]&&71===t[204])this.packetOffset=0,this.packetStride=204;else{if(71!==t[4]||71!==t[196])throw new Error("Unreachable.");this.packetOffset=4,this.packetStride=192}this.minReferencePointByteDistance=256*this.packetStride;let i=this.packetOffset,r=null,n=!1,s=!1;for(;;){const e=yield this.readPacketHeader(i);if(!e)break;if(0===e.payloadUnitStartIndicator){i+=this.packetStride;continue}const t=yield this.readSection(i,!0,!s);if(!t)break;const a=3,o=32;let l=!1;if(!s&&0!==t.pid){if(!(0===t.payload[0]&&0===t.payload[1]&&1===t.payload[2])){const e=new Ee(t.payload),i=e.readAlignedByte();e.skipBits(8*i);l=2===e.readBits(8)}}if(0!==t.pid||n)if(t.pid!==r&&!l||s){const e=this.elementaryStreams.find(e=>e.pid===t.pid);e:if(e&&!e.initialized){const i=Zr(t,!0);if(!i)throw new Error(`Couldn't read first PES packet for Elementary Stream with PID ${e.pid}`);if(e.firstSection=t,e.canBeTrustedWithKeyPackets=1===t.randomAccessIndicator,this.input._initInput){const i=(yield this.input._initInput._getDemuxer()).elementaryStreams.find(i=>i.pid===t.pid&&i.info.codec===e.info.codec);if(i){e.info=i.info,e.initialized=!0;break e}}const r=new sn(e,i);if("video"===e.info.type){for(;;){if(r.suppliedPacket=null,yield r.markNextPacket(),"avc"===e.info.codec){if(!r.suppliedPacket)throw new Error("Invalid AVC video stream; could not extract AVCDecoderConfigurationRecord from any packet.");if(e.info.avcCodecInfo=pt(r.suppliedPacket.data),!e.info.avcCodecInfo)continue;const t=e.info.avcCodecInfo.sequenceParameterSets[0];y(t);const i=kt(t);e.info.width=i.displayWidth,e.info.height=i.displayHeight;const n=i.pixelAspectRatio.num,s=i.pixelAspectRatio.den;n>0&&s>0&&(n>s?(e.info.squarePixelWidth=Math.round(e.info.width*n/s),e.info.squarePixelHeight=e.info.height):(e.info.squarePixelWidth=e.info.width,e.info.squarePixelHeight=Math.round(e.info.height*s/n))),e.info.colorSpace={primaries:B[i.colourPrimaries],transfer:_[i.transferCharacteristics],matrix:F[i.matrixCoefficients],fullRange:!!i.fullRangeFlag},e.info.reorderSize=i.maxDecFrameBuffering;break}if("hevc"===e.info.codec){if(!r.suppliedPacket)throw new Error("Invalid HEVC video stream; could not extract HVCDecoderConfigurationRecord from first packet.");if(e.info.hevcCodecInfo=vt(r.suppliedPacket.data),!e.info.hevcCodecInfo)continue;const t=e.info.hevcCodecInfo.arrays.find(e=>e.nalUnitType===st.SPS_NUT).nalUnits[0];y(t);const i=St(t);e.info.width=i.displayWidth,e.info.height=i.displayHeight,i.pixelAspectRatio.num>i.pixelAspectRatio.den?(e.info.squarePixelWidth=Math.round(e.info.width*i.pixelAspectRatio.num/i.pixelAspectRatio.den),e.info.squarePixelHeight=e.info.height):(e.info.squarePixelWidth=e.info.width,e.info.squarePixelHeight=Math.round(e.info.height*i.pixelAspectRatio.den/i.pixelAspectRatio.num)),e.info.colorSpace={primaries:B[i.colourPrimaries],transfer:_[i.transferCharacteristics],matrix:F[i.matrixCoefficients],fullRange:!!i.fullRangeFlag},e.info.reorderSize=i.maxDecFrameBuffering;break}throw new Error("Unhandled.")}e.info.decoderConfig={codec:Ue({width:e.info.width,height:e.info.height,codec:e.info.codec,codecDescription:null,colorSpace:e.info.colorSpace,avcType:1,avcCodecInfo:e.info.avcCodecInfo,hevcCodecInfo:e.info.hevcCodecInfo,vp9CodecInfo:null,av1CodecInfo:null}),codedWidth:e.info.width,codedHeight:e.info.height,colorSpace:e.info.colorSpace},e.info.width===e.info.squarePixelWidth&&e.info.height===e.info.squarePixelHeight||(e.info.decoderConfig.displayAspectWidth=e.info.squarePixelWidth,e.info.decoderConfig.displayAspectHeight=e.info.squarePixelHeight),e.initialized=!0}else{if(yield r.markNextPacket(),!r.suppliedPacket)throw new Error(`Couldn't parse first media packet for Elementary Stream with PID ${e.pid}`);if("aac"===e.info.codec){const t=Pa.tempFromBytes(r.suppliedPacket.data),i=qr(t);if(!i)throw new Error("Invalid AAC audio stream; could not read ADTS frame header from first packet.");e.info.aacCodecInfo={isMpeg2:!1,objectType:i.objectType},e.info.numberOfChannels=Ae[i.channelConfiguration],e.info.sampleRate=_e[i.samplingFrequencyIndex]}else if("mp3"===e.info.codec){const t=Ra(Pa.tempFromBytes(r.suppliedPacket.data)),i=Ye(t,r.suppliedPacket.data.byteLength);if(!i.header)throw new Error("Invalid MP3 audio stream; could not read frame header from first packet.");e.info.numberOfChannels=3===i.header.channel?1:2,e.info.sampleRate=i.header.sampleRate}else if("ac3"===e.info.codec){const t=Vt(r.suppliedPacket.data);if(!t)throw new Error("Invalid AC-3 audio stream; could not read sync frame from first packet.");if(3===t.fscod)throw new Error("Invalid AC-3 audio stream; reserved sample rate code found in first packet.");e.info.numberOfChannels=Wt[t.acmod]+t.lfeon,e.info.sampleRate=tt[t.fscod]}else{if("eac3"!==e.info.codec)throw new Error("Unhandled.");{const t=jt(r.suppliedPacket.data);if(!t)throw new Error("Invalid E-AC-3 audio stream; could not read sync frame from first packet.");const i=Xt(t);if(null===i)throw new Error("Invalid E-AC-3 audio stream; reserved sample rate code found in first packet.");e.info.numberOfChannels=$t(t),e.info.sampleRate=i}}e.info.decoderConfig={codec:qe({codec:e.info.codec,codecDescription:null,aacCodecInfo:e.info.aacCodecInfo}),numberOfChannels:e.info.numberOfChannels,sampleRate:e.info.sampleRate},e.initialized=!0}}}else{const e=new Ee(t.payload),i=e.readAlignedByte();e.skipBits(8*i),e.skipBits(12);const r=e.readBits(12);e.skipBits(43),e.readBits(13),e.skipBits(6);const n=e.readBits(10);for(e.skipBits(8*n);8*(r+a)-e.pos>o;){const t=e.readBits(8);e.skipBits(3);const i=e.readBits(13);e.skipBits(6);const r=e.readBits(10),n=e.pos+8*r;let s=!1,a=!1;for(;e.poso;){const t=e.readBits(16);e.skipBits(3);const i=e.readBits(13);if(0!==t){if(null!==r)throw new Error("Only files with a single program are supported.");r=i}}if(null===r)throw new Error("Program Association Table must link to a Program Map Table.");n=!0}if(s&&this.elementaryStreams.every(e=>e.initialized))break;i+=this.packetStride}if(!s){if(!n)throw new Error("No Program Association Table found in the file.");throw new Error("No Program Map Table found in the file.")}for(const a of this.elementaryStreams)"video"===a.info.type?this.trackBackingEntries.push(new tn(a)):this.trackBackingEntries.push(new rn(a))}))()})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackingEntries})}getMetadataTags(){return d(this,null,function*(){return{}})}getMimeType(){return d(this,null,function*(){yield this.readMetadata();return(e=>{let t="video/MP2T";const i=[...new Set(e.filter(Boolean))];return i.length>0&&(t+=`; codecs="${i.join(", ")}"`),t})(yield Promise.all(this.trackBackingEntries.map(e=>e.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null}))))})}readSection(e,t,i=!1){return d(this,null,function*(){let r=e,n=e;const s=[];let a,o=0,l=null,c=!0,u=0;for(;;){const e=yield this.readPacket(n);if(n+=this.packetStride,!e)break;if(l){if(e.pid!==l.pid){if(i)break;continue}if(1===e.payloadUnitStartIndicator)break}else{if(0===e.payloadUnitStartIndicator)break;l=e}const a=!!(2&e.adaptationFieldControl),d=!!(1&e.adaptationFieldControl);let h=0;if(a&&(h=1+e.body[0],e===l&&h>1&&(u=e.body[1]>>6&1)),d&&(0===h?(s.push(e.body),o+=e.body.byteLength):(s.push(e.body.subarray(h)),o+=e.body.byteLength-h)),r=n,!t&&o>=64){c=!1;break}if(-1!==L(this.sectionEndPositions,r,e=>e)){c=!1;break}}if(c){const e=z(this.sectionEndPositions,r,e=>e);this.sectionEndPositions.splice(e+1,0,r)}if(!l)return null;if(1===s.length)a=s[0];else{const e=s.reduce((e,t)=>e+t.length,0);a=new Uint8Array(e);let t=0;for(const i of s)a.set(i,t),t+=i.length}return{startPos:e,endPos:t?r:null,pid:l.pid,payload:a,randomAccessIndicator:u}})}readPacketHeader(e){return d(this,null,function*(){let t=this.reader.requestSlice(e,4);if(t instanceof Promise&&(t=yield t),!t)return null;if(71!==Ca(t))throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file.");const i=Ea(t);return{payloadUnitStartIndicator:i>>14&1,pid:8191&i,adaptationFieldControl:Ca(t)>>4&3}})}readPacket(e){return d(this,null,function*(){let t=this.reader.requestSlice(e,$r);if(t instanceof Promise&&(t=yield t),!t)return null;const i=xa(t,$r);if(71!==i[0])throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file.");const r=(i[1]<<8)+i[2];return{payloadUnitStartIndicator:r>>14&1,pid:8191&r,adaptationFieldControl:i[3]>>4&3,body:i.subarray(4)}})}}const Jr=(e,t)=>{if(e.payload.byteLength<3)return null;const i=new Ee(e.payload);if(1!==i.readBits(24))return null;const r=i.readBits(8);if(i.skipBits(16),188===r||190===r||191===r||240===r||241===r||255===r||242===r||248===r)return null;i.skipBits(8);const n=i.readBits(2);i.skipBits(14);let s=null;if(2===n||3===n)s=0,i.skipBits(4),s+=i.readBits(3)*(1<<30),i.skipBits(1),s+=32768*i.readBits(15),i.skipBits(1),s+=i.readBits(15);else if(t)throw new Error(Qr);return{sectionStartPos:e.startPos,sectionEndPos:e.endPos,pts:s,randomAccessIndicator:e.randomAccessIndicator}},Zr=(e,t)=>{y(null!==e.endPos);const i=Jr(e,t);if(!i)return null;const r=new Ee(e.payload);r.skipBits(32);const n=r.readBits(16);r.skipBits(16);const s=r.readBits(8),a=r.pos+8*s;r.pos=a;const o=a/8;y(Number.isInteger(o));const l=e.payload.subarray(o,n>0?6+n:e.payload.byteLength);return u(c({},i),{data:l})};class en{constructor(e){this.elementaryStream=e,this.packetBuffers=new WeakMap,this.packetSectionStarts=new WeakMap}getId(){return this.elementaryStream.pid}getNumber(){const e=this.elementaryStream.demuxer,t=this.elementaryStream.info.type;let i=0;for(const r of e.trackBackingEntries)if(r.getType()===t&&i++,y(r instanceof en),r.elementaryStream===this.elementaryStream)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.elementaryStream.streamType}getName(){return null}getLanguageCode(){return Q}getDisposition(){return u(c({},Be),{primary:!1})}getTimeResolution(){return Xr}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return null})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}createEncodedPacket(e,t,i){let r;return r=this.allPacketsAreKeyPackets()||1===e.randomAccessIndicator?"key":"delta",new Yt(i.metadataOnly?Gt:e.data,r,e.pts/Xr,Math.max(t/Xr,0),e.sequenceNumber,e.data.byteLength)}getFirstPacket(e){return d(this,null,function*(){const t=this.elementaryStream.firstSection;y(t);const i=Zr(t,!0);y(i);const r=new sn(this.elementaryStream,i),n=new an(this,r),s=yield n.readNext();if(!s)return null;const a=this.createEncodedPacket(s.packet,s.duration,e);return this.packetBuffers.set(a,n),this.packetSectionStarts.set(a,s.packet.sectionStartPos),a})}getNextPacket(e,t){return d(this,null,function*(){let i=this.packetBuffers.get(e);if(i){const r=yield i.readNext();if(!r)return null;this.packetBuffers.delete(e);const n=this.createEncodedPacket(r.packet,r.duration,t);return this.packetBuffers.set(n,i),this.packetSectionStarts.set(n,r.packet.sectionStartPos),n}const r=this.packetSectionStarts.get(e);if(void 0===r)throw new Error("Packet was not created from this track.");const n=this.elementaryStream.demuxer,s=yield n.readSection(r,!0);y(s);const a=Zr(s,!0);y(a);const o=new sn(this.elementaryStream,a);i=new an(this,o);const l=e.sequenceNumber;for(;;){const e=yield i.readNext();if(!e)return null;if(e.packet.sequenceNumber>l){const r=this.createEncodedPacket(e.packet,e.duration,t);return this.packetBuffers.set(r,i),this.packetSectionStarts.set(r,e.packet.sectionStartPos),r}}})}getNextKeyPacket(e,t){return d(this,null,function*(){let i=e;for(;;){if(i=yield this.getNextPacket(i,t),!i)return null;if("key"===i.type)return i}})}getPacket(e,t){return this.doPacketLookup(e,!1,t)}getKeyPacket(e,t){return this.doPacketLookup(e,!0,t)}doPacketLookup(e,t,i){return d(this,null,function*(){var r,n,s,a,o,l;const c=G(e*Xr),u=this.elementaryStream.demuxer,{reader:h,seekChunkSize:f}=u,m=this.elementaryStream.pid,p=(e,t,i)=>d(this,null,function*(){let r=e;for(;re.pts),w=-1!==v?S[v]:null;if(w&&c-w.pts<45e3)b=w.sectionStartPos;else{let e=0;if(null!==h.fileSize){const t=Math.ceil(h.fileSize/f);if(t>1){let i=0,r=t-1;for(e=i;i<=r;){const t=Math.floor((i+r)/2),n=J(t*f,u.packetStride)+k.sectionStartPos,s=n+f,a=yield p(n,s,!1);a?a.pesPacketHeader.pts<=c?(e=t,i=t+1):r=t-1:r=t-1}}}b=J(e*f,u.packetStride)+k.sectionStartPos}const P=yield p(b,null!=(r=h.fileSize)?r:1/0,!1);let I=null!=(n=null==P?void 0:P.pesPacketHeader)?n:null;I||(I=k);const x=this.getReorderSize(),C=(e,t)=>d(this,null,function*(){var r,n;const s=yield u.readSection(e,!0);y(s);const a=Zr(s,!0);y(a);const o=new sn(this.elementaryStream,a),l=new an(this,o);for(;;){if((null!=(n=null==(r=T(l.presentationOrderPackets))?void 0:r.pts)?n:-1/0)>=c)break;if(!(yield l.readNextPacket()))break}const d=V(l.presentationOrderPackets,t);if(-1===d)return null;const h=l.presentationOrderPackets[d],f=0===d?0:h.pts-l.presentationOrderPackets[d-1].pts;for(;l.decodeOrderPackets[0]!==h;)l.decodeOrderPackets.shift();l.lastDuration=f;const m=yield l.readNext();y(m);const p=this.createEncodedPacket(m.packet,m.duration,i);return this.packetBuffers.set(p,l),this.packetSectionStarts.set(p,m.packet.sectionStartPos),p});if(!t||this.allPacketsAreKeyPackets()){e:for(;;){let e=I.sectionStartPos+u.packetStride;for(;;){const t=yield u.readPacketHeader(e);if(!t)break e;if(t.pid===m&&1===t.payloadUnitStartIndicator){const t=yield u.readSection(e,!1);if(t){const e=Jr(t,!1);if(e&&null!==e.pts){if(e.pts>c)break e;I=e,nn(this.elementaryStream,I);break}}}e+=u.packetStride}}e:for(let e=0;e=u.packetOffset;){const t=yield u.readPacketHeader(e);if(!t)break e;if(t.pid===m&&1===t.payloadUnitStartIndicator){const t=yield u.readSection(e,!1);if(t){const e=Jr(t,!1);if(e&&null!==e.pts){I=e;break}}}e-=u.packetStride}}return C(I.sectionStartPos,e=>e.pts<=c)}{let e=b,t=null;const i=!this.elementaryStream.canBeTrustedWithKeyPackets;for(;;){let r=null;const n=e<=k.sectionStartPos;let d,b=null;if(n)d=k,b=g;else{const t=yield p(e,null!=(s=h.fileSize)?s:1/0,i);d=null!=(a=null==t?void 0:t.pesPacketHeader)?a:null,b=null!=(o=null==t?void 0:t.section)?o:null}let T=!1,S=0;e:for(;d&&!(null!==t&&d.sectionStartPos>=t);){if(d.pts<=c){let e;if(this.elementaryStream.canBeTrustedWithKeyPackets)e=1===d.randomAccessIndicator;else{y(b);const t=Zr(b,!0);y(t);const i=new sn(this.elementaryStream,t);yield i.markNextPacket(),e=1===(null==(l=i.suppliedPacket)?void 0:l.randomAccessIndicator)}e&&(r=d)}if(d.pts>c&&(T=!0),T&&(S++,S>x))break;let e=d.sectionStartPos+u.packetStride;for(;;){const t=yield u.readPacketHeader(e);if(!t)break e;if(t.pid===m&&1===t.payloadUnitStartIndicator){const t=yield u.readSection(e,i);if(t){const e=Jr(t,!1);if(e&&null!==e.pts){d=e,b=t,nn(this.elementaryStream,d);break}}}e+=u.packetStride}}if(r){let e=r;if(0===S)e:for(let r=0;r=u.packetOffset;){const r=yield u.readPacketHeader(t);if(!r)break e;if(r.pid===m&&1===r.payloadUnitStartIndicator){const r=yield u.readSection(t,i);if(r){const t=Jr(r,!1);if(t&&null!==t.pts){e=t;break}}}t-=u.packetStride}}const t=yield C(e.sectionStartPos,e=>e.pts<=c&&1===e.randomAccessIndicator);return y(t),t}if(n)return null;t=e,e=Math.max(J(e-k.sectionStartPos-f,u.packetStride)+k.sectionStartPos,k.sectionStartPos)}}})}}class tn extends en{getType(){return"video"}getCodec(){return this.elementaryStream.info.codec}getCodedWidth(){return this.elementaryStream.info.width}getCodedHeight(){return this.elementaryStream.info.height}getSquarePixelWidth(){return this.elementaryStream.info.squarePixelWidth}getSquarePixelHeight(){return this.elementaryStream.info.squarePixelHeight}getRotation(){return 0}getColorSpace(){return d(this,null,function*(){return this.elementaryStream.info.colorSpace})}canBeTransparent(){return d(this,null,function*(){return!1})}getDecoderConfig(){return d(this,null,function*(){return y(this.elementaryStream.info.decoderConfig),this.elementaryStream.info.decoderConfig})}allPacketsAreKeyPackets(){return!1}getReorderSize(){return this.elementaryStream.info.reorderSize}}class rn extends en{getType(){return"audio"}getCodec(){return this.elementaryStream.info.codec}getNumberOfChannels(){return this.elementaryStream.info.numberOfChannels}getSampleRate(){return this.elementaryStream.info.sampleRate}getDecoderConfig(){return d(this,null,function*(){return y(this.elementaryStream.info.decoderConfig),this.elementaryStream.info.decoderConfig})}allPacketsAreKeyPackets(){return!0}getReorderSize(){return 0}}const nn=(e,t)=>{const i=e.referencePesPackets,r=z(i,t.sectionStartPos,e=>e.sectionStartPos);if(r>=0){const n=i[r];if(t.pts<=n.pts)return!1;const s=e.demuxer.minReferencePointByteDistance;if(t.sectionStartPos-n.sectionStartPos=e?e:this.bufferData(e-t).then(()=>Math.min(this.endPos-this.currentPos,e))}getCurrentPesPacket(){const e=this.pesPackets[this.currentPesPacketIndex];return y(e),e}bufferData(e){return d(this,null,function*(){const t=this.endPos+e;for(;this.endPos=a)break;o=e;const i=n+o;if(o+4>=a){this.seekTo(i);break}const l=s[o+1],c=s[o+2],u=s[o+3];let d=0,h=null;if(0===l&&0===c&&1===u?(d=4,h=s[o+4]):0===l&&1===c&&(d=3,h=u),0===d){o++;continue}const f=i;if(null!==r){if(null!==h){const e="avc"===t?ut(h):Tt(h);if("avc"===t?e===rt.AUD:e===st.AUD_NUT){const e=f-r;return this.seekTo(r),this.supplyPacket(e,0)}}o+=d}else r=f,o+=d}if(e>6,a=63&n[4];if(3===s||a>37){this.seekTo(t+1);continue}const o=Ht[3*a+s];y(void 0!==o),this.seekTo(t),r=this.ensureBuffered(o),r instanceof Promise&&(r=yield r);const l=Math.round(13824e4/e.info.sampleRate);return this.supplyPacket(r,l)}if("eac3"===t){if(11!==i)continue;this.skip(-1);const t=this.currentPos;let r=this.ensureBuffered(5);if(r instanceof Promise&&(r=yield r),r<5)return;const n=this.readBytes(5);if(11!==n[0]||119!==n[1]){this.seekTo(t+1);continue}const s=2*(((7&n[2])<<8|n[3])+1),a=3===n[4]>>6?3:n[4]>>4&3,o=Kt[a];this.seekTo(t),r=this.ensureBuffered(s),r instanceof Promise&&(r=yield r);const l=256*o,c=Math.round(l*Xr/e.info.sampleRate);return this.supplyPacket(r,c)}throw new Error("Unhandled.")}{if(255!==i)continue;this.skip(-1);const t=this.currentPos;let r=this.ensureBuffered(4);if(r instanceof Promise&&(r=yield r),r<4)return;const n=this.readBytes(4),s=P(n).getUint32(0),a=Ye(s,null);if(a.header){this.seekTo(t);let i=this.ensureBuffered(a.header.totalSize);i instanceof Promise&&(i=yield i);const r=a.header.audioSamplesInFrame*Xr/e.info.sampleRate;return this.supplyPacket(i,Math.round(r))}this.seekTo(t+1)}}}if(r=0)}readNext(){return d(this,null,function*(){if(0===this.decodeOrderPackets.length){if(!(yield this.readNextPacket()))return null}yield this.ensureCurrentPacketHasNext();const e=this.decodeOrderPackets[0],t=this.presentationOrderPackets.indexOf(e);let i;if(y(-1!==t),t===this.presentationOrderPackets.length-1)i=this.lastDuration;else{i=this.presentationOrderPackets[t+1].pts-e.pts,this.lastDuration=i}for(this.decodeOrderPackets.shift();this.presentationOrderPackets.length>0;){const e=this.presentationOrderPackets[0];if(this.decodeOrderPackets.includes(e))break;this.presentationOrderPackets.shift()}return{packet:e,duration:i}})}readNextPacket(){return d(this,null,function*(){if(this.reachedEnd)return!1;let e;return this.context.suppliedPacket||(yield this.context.markNextPacket()),e=this.context.suppliedPacket,this.context.suppliedPacket=null,e?(this.decodeOrderPackets.push(e),this.processPacketThroughReorderBuffer(e),!0):(this.reachedEnd=!0,this.flushReorderBuffer(),!1)})}ensureCurrentPacketHasNext(){return d(this,null,function*(){const e=this.decodeOrderPackets[0];for(y(e);;){const t=this.presentationOrderPackets.indexOf(e);if(-1!==t&&t<=this.presentationOrderPackets.length-2)break;if(!(yield this.readNextPacket()))break}})}processPacketThroughReorderBuffer(e){if(this.reorderBuffer.push(e),this.reorderBuffer.length>this.reorderSize){let e=0;for(let i=1;ie.pts-t.pts),this.presentationOrderPackets.push(...this.reorderBuffer),this.reorderBuffer.length=0}}const on="application/vnd.apple.mpegurl",ln="#EXT-X-STREAM-INF:",cn="#EXT-X-I-FRAME-STREAM-INF:",un="#EXT-X-MEDIA:",dn="#EXTINF:",hn="#EXT-X-MAP:",fn="#EXT-X-KEY:",mn="#EXT-X-MEDIA-SEQUENCE:",pn="#EXT-X-BYTERANGE:",gn="#EXT-X-PROGRAM-DATE-TIME:",kn="#EXT-X-TARGETDURATION:",yn="#EXT-X-PLAYLIST-TYPE:",bn=e=>0===e.length||e.startsWith("#")&&!e.startsWith("#EXT");class Tn{constructor(e){this._attributes={};let t="",i="",r=!1,n=!1;for(let s=0;sd(this,null,function*(){const e=[];if(this.trackDeclarations){for(const t of this.trackDeclarations)if("video"===t.type){const i=Te(e,e=>"video"===e.getType())+1;e.push(new wn(this,t,i))}else if("audio"===t.type){const i=Te(e,e=>"audio"===e.getType())+1;e.push(new Pn(this,t,i))}}else{if(this.firstSegment=yield this.getFirstSegment({}),!this.firstSegment)return[];const t=this.getInputForSegment(this.firstSegment),i=yield t.getTracks();for(const r of i)if("video"===r.type){const t=Te(e,e=>"video"===e.getType())+1;e.push(new wn(this,{id:e.length+1,type:"video"},t))}else if("audio"===r.type){const t=Te(e,e=>"audio"===e.getType())+1;e.push(new Pn(this,{id:e.length+1,type:"audio"},t))}}return e}))()})}getFirstTimestampForInput(e){return d(this,null,function*(){const t=this.firstTimestampCache.get(e);if(void 0!==t)return t;const i=yield e.getFirstTimestamp();return this.firstTimestampCache.set(e,i),i})}getMediaOffset(e,t){return d(this,null,function*(){var i;const r=null!=(i=e.firstSegment)?i:e;let n;if(this.firstSegmentFirstTimestamps.has(r))n=this.firstSegmentFirstTimestamps.get(r);else{const e=this.getInputForSegment(r);n=yield this.getFirstTimestampForInput(e),this.firstSegmentFirstTimestamps.set(r,n)}if(r===e)return r.timestamp-n;const s=yield this.getFirstTimestampForInput(t),a=e.timestamp-r.timestamp,o=s-n-a;return Math.abs(o)<=Math.min(.25,a)?r.timestamp-n:e.timestamp-s})}dispose(){for(const e of this.inputCache)e.input.dispose();this.inputCache.length=0}}class vn{constructor(e,t,i){this.packetInfos=new WeakMap,this.hydrationPromise=null,this.firstInputTrack=null,this.segmentedInput=e,this.decl=t,this.number=i}hydrate(){var e;return null!=(e=this.hydrationPromise)?e:this.hydrationPromise=(()=>d(this,null,function*(){var e;if(null!=(e=this.segmentedInput).firstSegment||(e.firstSegment=yield this.segmentedInput.getFirstSegment({})),!this.segmentedInput.firstSegment)throw new Error("Missing first segment, can't retrieve track.");const t=this.segmentedInput.getInputForSegment(this.segmentedInput.firstSegment),i=(yield t.getTracks()).find(e=>e.type===this.decl.type&&e.number===this.number);if(!i)throw new Error("No matching track found in underlying media data.");this.firstInputTrack=i}))()}getId(){return this.decl.id}getType(){return this.decl.type}getNumber(){return this.number}delegate(e){return this.firstInputTrack?e():this.hydrate().then(e)}getDecoderConfig(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())})}getHasOnlyKeyPackets(){return this.delegate(()=>{var e,t,i;return null!=(i=null==(t=(e=this.firstInputTrack._backing).getHasOnlyKeyPackets)?void 0:t.call(e))?i:null})}getPairingMask(){return BigInt("1")}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getInternalCodecId(){return this.delegate(()=>this.firstInputTrack._backing.getInternalCodecId())}getDisposition(){return this.delegate(()=>this.firstInputTrack._backing.getDisposition())}getLanguageCode(){return this.delegate(()=>this.firstInputTrack._backing.getLanguageCode())}getName(){return this.delegate(()=>this.firstInputTrack._backing.getName())}getTimeResolution(){return this.delegate(()=>this.firstInputTrack._backing.getTimeResolution())}isRelativeToUnixEpoch(){return d(this,null,function*(){return yield this.hydrate(),y(this.segmentedInput.firstSegment),this.segmentedInput.firstSegment.relativeToUnixEpoch})}getBitrate(){return this.delegate(()=>this.firstInputTrack._backing.getBitrate())}getAverageBitrate(){return this.delegate(()=>this.firstInputTrack._backing.getAverageBitrate())}getDurationFromMetadata(e){return this.segmentedInput.getDurationFromMetadata(e)}getLiveRefreshInterval(){return this.segmentedInput.getLiveRefreshInterval()}createAdjustedPacket(e,t,i){return d(this,null,function*(){y(e.sequenceNumber>=0),y(this.segmentedInput.firstSegment);const r=yield this.segmentedInput.getMediaOffset(t,i.input),n=t.timestamp-this.segmentedInput.firstSegment.timestamp,s=e.clone({timestamp:Y(e.timestamp+r,yield i.getTimeResolution()),sequenceNumber:Math.floor(1e8*n)+e.sequenceNumber});return this.packetInfos.set(s,{segment:t,track:i,sourcePacket:e}),s})}getFirstPacket(e){return d(this,null,function*(){yield this.hydrate(),y(this.segmentedInput.firstSegment),y(this.firstInputTrack);const t=yield this.firstInputTrack._backing.getFirstPacket(e);return t?this.createAdjustedPacket(t,this.segmentedInput.firstSegment,this.firstInputTrack):null})}getNextPacket(e,t){return this._getNextInternal(e,t,!1)}getNextKeyPacket(e,t){return this._getNextInternal(e,t,!0)}_getNextInternal(e,t,i){return d(this,null,function*(){const r=this.packetInfos.get(e);if(!r)throw new Error("Packet was not created from this track.");const n=i?yield r.track._backing.getNextKeyPacket(r.sourcePacket,t):yield r.track._backing.getNextPacket(r.sourcePacket,t);if(n)return this.createAdjustedPacket(n,r.segment,r.track);let s=r.segment;for(;;){const e=yield this.segmentedInput.getNextSegment(s,{skipLiveWait:t.skipLiveWait});if(!e)return null;const i=this.segmentedInput.getInputForSegment(e),n=(yield i.getTracks()).find(e=>e.type===r.track.type&&e.number===r.track.number);if(!n){s=e;continue}const a=yield n._backing.getFirstPacket(t);return a?this.createAdjustedPacket(a,e,n):null}})}getPacket(e,t){return this._getPacketInternal(e,t,!1)}getKeyPacket(e,t){return this._getPacketInternal(e,t,!0)}_getPacketInternal(e,t,i){return d(this,null,function*(){let r=yield this.segmentedInput.getSegmentAt(e,{skipLiveWait:t.skipLiveWait});if(!r)return null;for(yield this.hydrate();r;){const n=this.segmentedInput.getInputForSegment(r),s=(yield n.getTracks()).find(e=>e.type===this.firstInputTrack.type&&e.number===this.firstInputTrack.number);if(!s){r=yield this.segmentedInput.getPreviousSegment(r,{skipLiveWait:t.skipLiveWait});continue}const a=yield this.segmentedInput.getMediaOffset(r,n),o=e-a,l=i?yield s._backing.getKeyPacket(o,t):yield s._backing.getPacket(o,t);if(l)return this.createAdjustedPacket(l,r,s);r=yield this.segmentedInput.getPreviousSegment(r,{skipLiveWait:t.skipLiveWait})}return null})}}class wn extends vn{getType(){return"video"}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getCodedWidth(){return this.delegate(()=>this.firstInputTrack._backing.getCodedWidth())}getCodedHeight(){return this.delegate(()=>this.firstInputTrack._backing.getCodedHeight())}getSquarePixelWidth(){return this.delegate(()=>this.firstInputTrack._backing.getSquarePixelWidth())}getSquarePixelHeight(){return this.delegate(()=>this.firstInputTrack._backing.getSquarePixelHeight())}getRotation(){return this.delegate(()=>this.firstInputTrack._backing.getRotation())}getColorSpace(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.getColorSpace())})}canBeTransparent(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.canBeTransparent())})}getDecoderConfig(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())})}}class Pn extends vn{getType(){return"audio"}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getNumberOfChannels(){return this.delegate(()=>this.firstInputTrack._backing.getNumberOfChannels())}getSampleRate(){return this.delegate(()=>this.firstInputTrack._backing.getSampleRate())}getDecoderConfig(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())})}}ke();const In=1/0;class xn extends Ie{constructor(){super(...arguments),this._disposed=!1,this._refCount=0,this._usedForHls=!1,this._sizePromise=null,this.onread=null}getSizeOrNull(){return d(this,null,function*(){var e;if(this._disposed)throw new va;return null!=(e=this._sizePromise)?e:this._sizePromise=(()=>d(this,null,function*(){let e=this._getFileSize();return void 0!==e||(yield this._read(0,1,0,In),e=this._getFileSize(),y(void 0!==e)),e}))()})}getSize(){return d(this,null,function*(){if(this._disposed)throw new va;const e=yield this.getSizeOrNull();if(null===e)throw new Error("Cannot determine the size of an unsized source.");return e})}slice(e,t){if(!Number.isInteger(e)||e<0)throw new TypeError("offset must be a non-negative integer.");if(void 0!==t&&(!Number.isInteger(t)||t<0))throw new TypeError("length, when provided, must be a non-negative integer.");return new zn(this,e,t)}_dispatchRead(e,t){var i;null==(i=this.onread)||i.call(this,e,t),this._emit("read",{start:e,end:t})}ref(){return new Cn(this)}}class Cn{constructor(e){if(this._freed=!1,e._disposed)throw new Error("Cannot ref a disposed source.");e._refCount++,this._source=e}get source(){if(!this._source)throw new Error("Can't get source; ref has already been freed.");return this._source}get freed(){return this._freed}free(){if(this._freed)throw new Error("Illegal operation: double free on SourceRef.");const e=this.source;y(e._refCount>0),e._refCount--,0===e._refCount&&(e._dispose(),e._disposed=!0),this._freed=!0,this._source=null}[Symbol.dispose](){this.freed||this.free()}}class Bn extends xn{constructor(e,t){if("string"!==typeof e)throw new TypeError("rootPath must be a string.");if("function"!==typeof t)throw new TypeError("requestHandler must be a function.");super(),this.rootPath=e,this.requestHandler=t}_resolveRequest(e){const t=this.requestHandler(e),i=e=>{var t;if(!(e instanceof xn||e instanceof Cn))throw new TypeError("requestHandler must return or resolve to a Source or SourceRef.");const i=e instanceof xn?e.ref():e;return(t=i.source)._usedForHls||(t._usedForHls=this._usedForHls),i};return t instanceof Promise?t.then(i):i(t)}}const En=(e,t)=>e.path===t.path;class _n extends Bn{constructor(){super(...arguments),this._root=null,this._rootRequest=null}_read(e,t,i,r){if(!this._root){if(!this._rootRequest){const e=this._resolveRequest({path:this.rootPath,isRoot:!0}),t=e=>{const t=e instanceof xn?e.ref():e;return this._root=t,this._rootRequest=null,t};e instanceof Promise?this._rootRequest=e.then(t):(t(e),y(this._root))}if(this._rootRequest)return this._rootRequest.then(n=>n.source._read(e,t,i,r))}return this._root.source._read(e,t,i,r)}_getFileSize(){if(this._root)return this._root.source._getFileSize()}_dispose(){this._root?this._root.free():this._rootRequest&&this._rootRequest.then(e=>e.free())}}class An extends xn{constructor(e,t={}){var i;if(!(e instanceof Blob))throw new TypeError("blob must be a Blob.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!ye(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._readers=new WeakMap,this._blob=e,this._orchestrator=new Ln({maxCacheSize:null!=(i=t.maxCacheSize)?i:8*o(2,20),maxWorkerCount:4,runWorker:this._runWorker.bind(this),prefetchProfile:On.fileSystem}),this._orchestrator.fileSize=e.size}_getFileSize(){return this._orchestrator.fileSize}_read(e,t,i,r){return this._orchestrator.read(e,t,i,r)}_runWorker(e){return d(this,null,function*(){y(e.strictTarget);let t=this._readers.get(e);if(void 0===t){if("stream"in this._blob&&!oe()){t=this._blob.slice(e.currentPos).stream().getReader()}else t=null;this._readers.set(e,t)}for(;e.currentPos{if(t instanceof Error&&(t.message.includes("Failed to fetch")||t.message.includes("Load failed")||t.message.includes("NetworkError when attempting to fetch resource"))){let e=null;try{"undefined"!==typeof window&&"undefined"!==typeof window.location&&(e=new URL(i instanceof Request?i.url:i,window.location.href).origin)}catch(r){}if(("undefined"===typeof navigator||"boolean"!==typeof navigator.onLine||navigator.onLine)&&null!==e&&e!==window.location.origin)return console.warn("Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option."),null}return Math.min(o(2,e-2),16)},Dn=new Set;class Mn extends Bn{constructor(e,t={}){var i,r,n;if("string"!==typeof e&&!(e instanceof URL)&&!("undefined"!==typeof Request&&e instanceof Request))throw new TypeError("url must be a string, URL or Request.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.requestInit&&(!t.requestInit||"object"!==typeof t.requestInit))throw new TypeError("options.requestInit, when provided, must be an object.");if(void 0!==t.getRetryDelay&&"function"!==typeof t.getRetryDelay)throw new TypeError("options.getRetryDelay, when provided, must be a function.");if(void 0!==t.maxCacheSize&&(!ye(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");if(void 0!==t.parallelism&&(!Number.isInteger(t.parallelism)||t.parallelism<1))throw new TypeError("options.parallelism, when provided, must be a positive number.");if(void 0!==t.fetchFn&&"function"!==typeof t.fetchFn)throw new TypeError("options.fetchFn, when provided, must be a function.");super(e instanceof Request?e.url:e instanceof URL?e.href:e,e=>new Mn(e.path,this._options)),this._fileSizeDetermined=!1,this._url=e,this._options=t,this._getRetryDelay=null!=(i=t.getRetryDelay)?i:Rn;this._orchestrator=new Ln({maxCacheSize:null!=(r=t.maxCacheSize)?r:64*o(2,20),maxWorkerCount:null!=(n=t.parallelism)?n:2,runWorker:this._runWorker.bind(this),prefetchProfile:On.network})}_getFileSize(){return this._fileSizeDetermined?this._orchestrator.fileSize:void 0}_read(e,t,i,r){return this._orchestrator.read(e,t,i,r)}_runWorker(e){return d(this,null,function*(){for(var t,i;;){const n=new AbortController,s=yield ne(null!=(t=this._options.fetchFn)?t:fetch,this._url,ie(null!=(i=this._options.requestInit)?i:{},{headers:{Range:`bytes=${e.currentPos}-`},signal:n.signal}),this._getRetryDelay,()=>this._disposed);if(!s.ok)throw new Error(`Error fetching ${String(this._url)}: ${s.status} ${s.statusText}`);e:if(null===this._orchestrator.fileSize){const t=s.headers.get("Content-Range");if(t){const e=/\/(\d+)/.exec(t);if(e){this._orchestrator.supplyFileSize(Number(e[1]));break e}}const i=s.headers.get("Content-Length");i&&this._orchestrator.supplyFileSize(e.currentPos+Number(i))}if(this._fileSizeDetermined=!0,206!==s.status){if(!this._usedForHls){const e=new URL(this._url instanceof Request?this._url.url:this._url,"undefined"!==typeof window?window.location.href:void 0);"null"===e.origin||e.pathname.endsWith(".m3u8")||e.pathname.endsWith(".m3u")||Dn.has(e.origin)||(console.log(this._usedForHls,this._url,e.pathname),console.warn(`HTTP server (origin ${e.origin}) did not respond to a range request with 206 Partial Content, meaning the entire resource will now be downloaded. To enable efficient media file streaming across a network, please make sure your server supports range requests.`),Dn.add(e.origin))}e.currentPos=0,this._orchestrator.options.maxCacheSize=1/0,null!==this._orchestrator.fileSize?e.targetPos=this._orchestrator.fileSize:(e.targetPos=1/0,e.strictTarget=!1),this._orchestrator.consolidateEverythingIntoOneWorker(e)}if(!s.body)throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream.");const a=s.body.getReader();for(;;){if(e.currentPos>=e.targetPos||e.aborted)return n.abort(),void this._orchestrator.signalWorkerStoppedRunning(e);let t;try{t=yield a.read()}catch(r){if(this._disposed)throw r;const e=this._getRetryDelay(1,r,this._url);if(null!==e){console.error("Error while reading response stream. Attempting to resume.",r),yield Pe(1e3*e);break}throw r}if(e.aborted)continue;const{done:i,value:s}=t;if(i){if(e.currentPos>=e.targetPos)return void this._orchestrator.onWorkerFinished(e);if(e.strictTarget)break;return void this._orchestrator.onWorkerFinished(e)}this._dispatchRead(e.currentPos,e.currentPos+s.length),this._orchestrator.supplyWorkerData(e,s)}}})}_dispose(){this._orchestrator.dispose()}}class Nn extends xn{constructor(e,t={}){var i;if(!(e instanceof ReadableStream))throw new TypeError("stream must be a ReadableStream.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!ye(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._reader=null,this._cache=[],this._pendingSlices=[],this._currentIndex=0,this._targetIndex=0,this._maxRequestedIndex=0,this._endIndex=null,this._pulling=!1,this._stream=e,this._maxCacheSize=null!=(i=t.maxCacheSize)?i:16*o(2,20)}_getFileSize(){return this._endIndex}_read(e,t){if(null!==this._endIndex&&t>this._endIndex)return null;this._maxRequestedIndex=Math.max(this._maxRequestedIndex,t);const i=z(this._cache,e,e=>e.start),r=-1!==i?this._cache[i]:null;if(r&&r.start<=e&&t<=r.end)return{bytes:r.bytes,view:r.view,offset:r.start};let n=e;const s=new Uint8Array(t-e);if(-1!==i)for(let c=i;c=t)break;const r=Math.max(e,i.start);r>n&&this._throwDueToCacheMiss();const a=Math.min(t,i.end);rn&&this._throwDueToCacheMiss();const{promise:a,resolve:o,reject:l}=q();return this._pendingSlices.push({start:e,end:t,bytes:s,resolve:o,reject:l}),this._targetIndex=Math.max(this._targetIndex,t),this._pulling||(this._pulling=!0,this._pull().catch(e=>{if(this._pulling=!1,!(this._pendingSlices.length>0))throw e;this._pendingSlices.forEach(t=>t.reject(e)),this._pendingSlices.length=0})),a}_throwDueToCacheMiss(){throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache.")}_pull(){return d(this,null,function*(){for(null!=this._reader||(this._reader=this._stream.getReader());this._currentIndex0;){const e=this._cache[0];if(this._maxRequestedIndex-e.end<=this._maxCacheSize)break;this._cache.shift()}this._currentIndex+=t.byteLength}this._pulling=!1})}_dispose(){var e;this._pendingSlices.length=0,this._cache.length=0,null==(e=this._reader)||e.cancel()}}const On={fileSystem:(e,t)=>{const i=o(2,16);return{start:e=Math.floor((e-i)/i)*i,end:t=Math.ceil((t+i)/i)*i}},network:(e,t,i)=>{const r=o(2,16);e=Math.max(0,Math.floor((e-r)/r)*r);for(const n of i){const i=8*o(2,20),r=Math.max((n.startPos+n.targetPos)/2,n.targetPos-i);if(pe(e,t,r,n.targetPos)){const e=n.targetPos-n.startPos,r=Math.ceil((e+1)/i)*i,s=o(2,Math.ceil(Math.log2(e+1))),a=Math.min(s,r);t=Math.max(t,n.startPos+a)}}return{start:e,end:t=Math.max(t,e+Fn)}}};class Ln{constructor(e){this.options=e,this.fileSize=null,this.nextAge=0,this.workers=[],this.cache=[],this.currentCacheSize=0,this.disposed=!1,this.queuedReads=[]}read(e,t,i,r){var n;y(!this.disposed);const s=this.options.prefetchProfile(e,t,this.workers),a=Math.max(s.start,i),o=Math.min(s.end,null!=(n=this.fileSize)?n:1/0,r);y(a<=e&&t<=o);let l=null;const c=z(this.cache,e,e=>e.start),u=-1!==c?this.cache[c]:null;u&&u.start<=e&&t<=u.end&&(u.age=this.nextAge++,l={bytes:u.bytes,view:u.view,offset:u.start});const d=z(this.cache,a,e=>e.start),h=l?null:new Uint8Array(t-e);let f=0,m=a;const p=[];if(-1!==d){for(let i=d;i=o)break;if(r.end<=a)continue;const n=Math.max(a,r.start),s=Math.min(o,r.end);if(y(n<=s),m=h.length&&(l={bytes:h,view:P(h),offset:e}),0===p.length)return y(l),l;const{promise:g,resolve:k,reject:b}=q(),T=[];for(const y of p){const i=Math.max(e,y.start),r=Math.min(t,y.end);i===y.start&&r===y.end?T.push(y):ie.hole.start),i=-1!==t?this.queuedReads[t]:null;for(i&&y.start<=i.hole.end?(i.hole.end=Math.max(i.hole.end,y.end),i.strictTarget&&(i.strictTarget=e),S&&i.pendingSlices.push(S)):(t++,i={hole:{start:y.start,end:y.end},strictTarget:e,pendingSlices:S?[S]:[],age:this.nextAge++},this.queuedReads.splice(t,0,i));t+1i.hole.end)break;i.hole.end=Math.max(i.hole.end,e.hole.end),i.pendingSlices.push(...e.pendingSlices),i.strictTarget&&(i.strictTarget=e.strictTarget),i.age=Math.min(i.age,e.age),this.queuedReads.splice(t+1,1)}}}return l||(y(h),l=g.then(t=>t&&{bytes:t,view:P(t),offset:e})),l}checkHoleAgainstWorker(e,t,i){const r=o(2,17);if(pe(t.start-r,t.start,e.currentPos,e.targetPos)){e.targetPos=Math.max(e.targetPos,t.end);for(let t=0;t=this.options.maxWorkerCount){let e=null,t=null;for(let i=0;i{if(e.running=!1,!(e.pendingSlices.length>0))throw t;e.pendingSlices.forEach(e=>e.reject(t)),e.pendingSlices.length=0}).finally(()=>{if(!e.running&&this.queuedReads.length>0){let e=0;for(let r=1;re.targetPos&&(e.targetPos=e.currentPos,this.checkQueuedReadsAgainstWorker(e));for(let n=0;nt.start&&(t.start=r),t.end<=t.start&&(s.holes.splice(e,1),e--)}0===s.holes.length&&(s.resolve(s.bytes),e.pendingSlices.splice(n,1),n--)}for(let n=0;ne){r.resolve(null),t.pendingSlices.splice(i,1),i--;break}}}for(let t=0;t=e){for(const e of i.pendingSlices)e.resolve(null);this.queuedReads.splice(t,1),t--}else if(i.hole.end>e){i.hole.end=e,i.strictTarget=!0;for(let t=0;t=e&&(r.resolve(null),i.pendingSlices.splice(t,1),t--)}}}}signalWorkerStoppedRunning(e){e.running=!1,e.pendingSlices.length=0}onWorkerFinished(e){const t=this.workers.indexOf(e);y(-1!==t),e.running=!1,this.workers.splice(t,1),null===this.fileSize&&this.supplyFileSize(e.currentPos);for(const i of e.pendingSlices)i.resolve(null)}insertIntoCache(e){if(0===this.options.maxCacheSize)return;let t=z(this.cache,e.start,e=>e.start)+1;if(t>0){const i=this.cache[t-1];if(i.end>=e.end)return;if(i.end>e.start){const r=new Uint8Array(e.end-i.start);r.set(i.bytes,0),r.set(e.bytes,e.start-i.start),this.currentCacheSize+=e.end-i.end,i.bytes=r,i.view=P(r),i.end=e.end,t--,e=i}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length;for(let i=t+1;i=t.end){this.cache.splice(i,1),this.currentCacheSize-=t.bytes.length,i--;continue}const r=new Uint8Array(t.end-e.start);r.set(e.bytes,0),r.set(t.bytes,t.start-e.start),this.currentCacheSize-=e.end-t.start,e.bytes=r,e.view=P(r),e.end=t.end,this.cache.splice(i,1);break}for(;this.currentCacheSize>this.options.maxCacheSize;){let e=0,t=this.cache[0];for(let i=1;ithis._length)return null;const n=this._baseSource._read(this._offset+e,this._offset+t,this._offset+i,this._offset+r);return n instanceof Promise?n.then(e=>e?(e.offset-=this._offset,e):null):n?(n.offset-=this._offset,n):null}_dispose(){var e;null==(e=this._ref)||e.free()}ref(){return null!=this._ref||(this._ref=this._baseSource.ref()),super.ref()}}var Un=function(e,t,i){if(null!==t&&void 0!==t){if("object"!==typeof t&&"function"!==typeof t)throw new TypeError("Object expected.");var r,n;if(i){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");r=t[Symbol.asyncDispose]}if(void 0===r){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");r=t[Symbol.dispose],i&&(n=r)}if("function"!==typeof r)throw new TypeError("Object not disposable.");n&&(r=function(){try{n.call(this)}catch(e){return Promise.reject(e)}}),e.stack.push({value:t,dispose:r,async:i})}else i&&e.stack.push({async:!0});return t},qn=function(e){return function(t){function i(i){t.error=t.hasError?new e(i,t.error,"An error was suppressed during disposal."):i,t.hasError=!0}var r,n=0;return function e(){for(;r=t.stack.pop();)try{if(!r.async&&1===n)return n=0,t.stack.push(r),Promise.resolve().then(e);if(r.dispose){var s=r.dispose.call(r.value);if(r.async)return n|=2,Promise.resolve(s).then(e,function(t){return i(t),e()})}else n|=1}catch(a){i(a)}if(1===n)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}()}}("function"===typeof SuppressedError?SuppressedError:function(e,t,i){var r=new Error(i);return r.name="SuppressedError",r.error=e,r.suppressed=t,r});const Wn=/^0[xX][0-9a-fA-F]+$/,Vn=/^data:.*;base64,/i;class Hn extends Sn{constructor(e,t,i,r){super(e.input,t,i),this.segments=[],this.nextLines=null,this.currentUpdateSegmentsPromise=null,this.streamHasEnded=!1,this.lastSegmentUpdateTime=-1/0,this.refreshInterval=5,this.demuxer=e,this.nextLines=r}runUpdateSegments(){var e;return null!=(e=this.currentUpdateSegmentsPromise)?e:this.currentUpdateSegmentsPromise=(()=>d(this,null,function*(){try{const e=this.getRemainingWaitTimeMs();e>0&&(yield Pe(e)),this.lastSegmentUpdateTime=performance.now(),yield this.updateSegments()}finally{this.currentUpdateSegmentsPromise=null}}))()}getRemainingWaitTimeMs(){const e=performance.now()-this.lastSegmentUpdateTime,t=Math.max(0,1e3*this.refreshInterval-e);return t<=50?0:t}updateSegments(){return d(this,null,function*(){var e,t,i,r,n,s,a;let l=this.nextLines;if(this.nextLines=null,!l){const e={stack:[],error:void 0,hasError:!1};try{const t=Un(e,yield this.demuxer.input._getSourceUncached({path:this.path,isRoot:!1}),!1),i=new wa(t.source),r=yield i.requestEntireFile();y(r),l=Va(r,r.length,{ignore:bn})}catch(E){e.error=E,e.hasError=!0}finally{qn(e)}}let d=!1,h=0,f=null,m=null,p=0,g=null,k=null,b=null,S=null,v=null,w=null,I=!1,x=null!=(e=T(this.segments))?e:null;const C=e=>{const t=e.indexOf("@"),i=Number(-1===t?e:e.slice(0,t));if(!Number.isInteger(i)||i<0)throw new Error(`Invalid #EXT-X-BYTERANGE length '${e}'.`);let r=null;if(-1!==t&&(r=Number(e.slice(t+1)),!Number.isInteger(r)||r<0))throw new Error(`Invalid #EXT-X-BYTERANGE offset '${e}'.`);return{length:i,offset:r}},B=e=>{p=e,x&&(y(null!==x.sequenceNumber),x.sequenceNumber0&&null!==w&&(h=p*w),I=!0);const t=e.slice(8),i=t.indexOf(","),r=-1===i?t:t.slice(0,i),n=Number(r);if(!Number.isFinite(n)||n<0)throw new Error(`Invalid #EXTINF tag duration '${r}'.`);f=n}else if(e.startsWith(hn)){const t=new Tn(e.slice(11)),i=t.get("uri");if(!i)throw new Error("Invalid #EXT-X-MAP tag; missing URI attribute.");const s=t.get("byterange");let a=null;if(null!==s&&(a=C(s)),a&&null===a.offset)throw new Error("Invalid #EXT-X-MAP tag; BYTERANGE attribute must have a specified offset.");if(!x){const e={path:be(this.path,i),offset:null!=(r=null==a?void 0:a.offset)?r:0,length:null!=(n=null==a?void 0:a.length)?n:null};if("AES-128"===(null==m?void 0:m.method)&&!m.iv)throw new Error("IV attribute must be set on #EXT-X-KEY tag preceding the #EXT-X-MAP tag.");k={timestamp:h,relativeToUnixEpoch:null!==v,firstSegment:null,sequenceNumber:null,location:e,duration:0,encryption:m,initSegment:null,lastProgramDateTimeSeconds:v}}f=null,null===S?b=null:S=null}else if(e.startsWith(fn)){const t=new Tn(e.slice(11)),i=t.get("method");if("NONE"===i)m=null;else if("AES-128"===i){const e=t.get("uri");if(!e)throw new Error("Invalid #EXT-X-KEY: AES-128 requires a URI attribute.");let i=null;const r=t.get("iv");if(r){if(!Wn.test(r))throw new Error(`Unsupported IV format '${r}'.`);let e=r.slice(2);e=e.padStart(32,"0"),i=new Uint8Array(ai);for(let t=0;t=8&&112===i[4]&&115===i[5]&&115===i[6]&&104===i[7]){const e=P(i).getUint32(0);r=Jt(i.subarray(8,Math.min(e,i.length)))}}m={method:i,psshBox:r}}}}else if(e.startsWith(mn)){const t=e.slice(22),i=Number(t);if(!Number.isInteger(i)||i<0)throw new Error(`Invalid EXT-X-MEDIA-SEQUENCE value '${t}'.`);B(i)}else if(e.startsWith(pn)){const t=C(e.slice(17));if(null===t.offset){if(null===b)throw new Error("Invalid M3U8 file; #EXT-X-BYTERANGE without offset requires a previous byte range.");t.offset=b}S=t,b=t.offset+t.length}else if(e.startsWith(gn)){if(x)continue;const t=e.slice(25),i=Date.parse(t);if(!Number.isFinite(i))continue;const r=i/1e3;if(v===r)continue;if(null===v&&this.segments.length>0){const e=T(this.segments),t=r-(e.timestamp+e.duration);for(const i of this.segments)i.timestamp+=t,i.relativeToUnixEpoch=!0;h+=t}v=r,h=r}else if("#EXT-X-DISCONTINUITY"===e)g=null;else if(e.startsWith(kn)){const t=e.slice(22),i=Number(t);if(!Number.isFinite(i)||i<0)throw new Error(`Invalid EXT-X-TARGETDURATION value '${t}'.`);this.refreshInterval=i,w=i}else{if("#EXT-X-ENDLIST"===e){this.streamHasEnded=!0;break}if(e.startsWith(yn)){"vod"===e.slice(21).toLowerCase()&&(this.streamHasEnded=!0)}}}else{if("#EXTM3U"!==e)throw new Error("Invalid M3U8 file; expected first line to be #EXTM3U.");d=!0}}if(!d)throw new Error("Invalid M3U8 file; no #EXTM3U header.")})}getFirstSegment(){return d(this,null,function*(){var e;return 0===this.segments.length&&(yield this.runUpdateSegments()),null!=(e=this.segments[0])?e:null})}getSegmentAt(e,t){return d(this,null,function*(){0===this.segments.length&&(yield this.runUpdateSegments());let i=!!t.skipLiveWait&&this.getRemainingWaitTimeMs()>0;for(;;){const r=z(this.segments,e,e=>e.timestamp);if(-1===r)return null;if(r0;for(;;){if(re.segment===r);if(n)return n.age=this.nextInputCacheAge++,n.input;let s=null;(r.initSegment||r.firstSegment)&&(s=this.getInputForSegment(null!=(t=r.initSegment)?t:r.firstSegment));const a=u(c({},this.input._formatOptions),{isobmff:u(c({},this.input._formatOptions.isobmff),{resolveKeyId:(null==(i=this.input._formatOptions.isobmff)?void 0:i.resolveKeyId)&&(e=>{if(!r.encryption||"SAMPLE-AES"!==r.encryption.method&&"SAMPLE-AES-CTR"!==r.encryption.method||!r.encryption.psshBox)return this.input._formatOptions.isobmff.resolveKeyId(e);let t=e.psshBoxes;const{psshBox:i}=r.encryption;return null!==i.keyIds&&!i.keyIds.includes(e.keyId)||t.some(e=>Zt(e,i))||(t=[...t,i]),this.input._formatOptions.isobmff.resolveKeyId(u(c({},e),{psshBoxes:t}))})})}),l=new Ta({source:new _n(r.location.path,e=>d(this,null,function*(){var t,i;y(e.isRoot);const n=u(c({},e),{isRoot:!1});let s;const a=r.location.offset>0||null!==r.location.length;if(r.encryption&&"SAMPLE-AES"!==r.encryption.method&&"SAMPLE-AES-CTR"!==r.encryption.method)if("AES-128"===r.encryption.method){const e=r.encryption;y(e.iv);let t=yield this.input._getSourceCached(n);if(a){const e=t.source.slice(r.location.offset,null!=(i=r.location.length)?i:void 0).ref();t.free(),t=e}const l=((e,t,i)=>{let r=!1,n=0;const s=o(2,16),a=new pi;return new ReadableStream({pull:o=>d(null,null,function*(){r||(a.init(yield t()),r=!0);const l=s+16;let c=e.requestSliceRange(n,0,l);if(c instanceof Promise&&(c=yield c),!c||0===c.length)throw new Error("Invalid ciphertext.");const u=c.length;if(u%16!==0)throw new Error("Invalid ciphertext.");const d=u===l?u-16:u,h=xa(c,d),f=new Uint8Array(d);for(let e=0;e16)throw new Error("Invalid PKCS#7 padding. Incorrect key or corrupted data.");const t=f.subarray(0,d-e);o.enqueue(t),o.close(),i()}}),cancel:()=>{i()}})})(new wa(t.source),()=>d(this,null,function*(){const t={stack:[],error:void 0,hasError:!1};try{const i=Un(t,yield this.input._getSourceCached({path:e.keyUri,isRoot:!1},ya),!1),r=new wa(i.source),n=yield r.requestSlice(0,ai);if(!n)throw new Error("Invalid AES-128 key; expected at least 16 bytes of data.");return{key:xa(n,ai),iv:e.iv}}catch(i){t.error=i,t.hasError=!0}finally{qn(t)}}),()=>{t.free()});s=new Nn(l).ref()}else y(!1);else if(s=yield this.input._getSourceCached(n),a){const e=s.source.slice(r.location.offset,null!=(t=r.location.length)?t:void 0).ref();s.free(),s=e}return s})),formats:this.input._formats.filter(e=>!(e instanceof us)),initInput:null!=s?s:void 0,formatOptions:a});l._onFormatDetermined=e=>{var t,i;if(("SAMPLE-AES"===(null==(t=r.encryption)?void 0:t.method)||"SAMPLE-AES-CTR"===(null==(i=r.encryption)?void 0:i.method))&&!e._isIsobmff)throw new Error("The SAMPLE-AES and SAMPLE-AES-CTR encryption methods are currently only supported for ISOBMFF files.")},this.inputCache.push({segment:r,input:l,age:this.nextInputCacheAge++});if(this.inputCache.length>4){const e=Se(this.inputCache,e=>e.age);y(-1!==e),this.inputCache.splice(e,1)}return l}getLiveRefreshInterval(){return d(this,null,function*(){return 0===this.getRemainingWaitTimeMs()&&(yield this.runUpdateSegments()),this.streamHasEnded?null:this.refreshInterval})}}class Kn extends Qt{constructor(e){super(e),this.metadataPromise=null,this.trackBackings=null,this.internalTracks=null,this.segmentedInputs=[],this.hasMasterPlaylist=!0}readMetadata(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){y(this.input._rootSource instanceof Bn);const{rootPath:e}=this.input._rootSource,t=yield this.input._reader.requestEntireFile();y(t);const i=Va(t,t.length,{ignore:bn}),r=[],n=[];for(let u=1;u"video"===e.attributes.get("type").toLowerCase()).map(e=>e.attributes.get("group-id")))],a=[...new Set(n.filter(e=>"audio"===e.attributes.get("type").toLowerCase()).map(e=>e.attributes.get("group-id")))],o=yield Promise.all(r.map((t,i)=>d(this,null,function*(){var r,o,l,c;const u=[],h=t.attributes.get("codecs");let f;if(h)f=h.split(",").map(e=>e.trim());else{const e=this.getSegmentedInputForPath(t.fullPath),i=yield e.getTrackBackings(),r=yield Promise.all(i.map(e=>d(this,null,function*(){return{track:e,codec:yield e.getCodec()}})));f=yield Promise.all(r.filter(e=>null!==e.codec).map(e=>e.track.getDecoderConfig().then(e=>e.codec)))}const m=t.attributes.get("video"),p=t.attributes.get("audio"),g=f.some(e=>Re.includes(Ke(e))),k=f.some(e=>Me.includes(Ke(e)));if(null!==m&&!g){if(!s.includes(m))throw new Error(`Invalid M3U8 file; variant stream references video group "${m}" which is not defined in any #EXT-X-MEDIA tags.`);const t=n.find(e=>{const t=e.attributes.get("group-id"),i=e.attributes.get("type");return t===m&&"video"===i.toLowerCase()});e:if(t){const i=t.attributes.get("uri");if(null===i)break e;const r=be(e,i),n=this.getSegmentedInputForPath(r),s=(yield n.getTrackBackings()).find(e=>"video"===e.getType());if(!s||null===(yield s.getCodec()))break e;const a=yield s.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null});y(null!==a),f.push(a)}}if(null!==p&&!k){if(!a.includes(p))throw new Error(`Invalid M3U8 file; variant stream references audio group "${p}" which is not defined in any #EXT-X-MEDIA tags.`);const t=n.find(e=>{const t=e.attributes.get("group-id"),i=e.attributes.get("type");return t===p&&"audio"===i.toLowerCase()});e:if(t){const i=t.attributes.get("uri");if(null===i)break e;const r=be(e,i),n=this.getSegmentedInputForPath(r),s=(yield n.getTrackBackings()).find(e=>"audio"===e.getType());if(!s||null===(yield s.getCodec()))break e;const a=yield s.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null});y(null!==a),f.push(a)}}f=[...new Set(f)];let b=null,T=null;const S=t.attributes.getAsNumber("bandwidth");y(null!==S);const v=t.attributes.getAsNumber("average-bandwidth"),w=t.attributes.get("name");for(const e of f){const d=Ke(e);if(null!==d)if(Re.includes(d)){if(null!==b)throw new Error("Unsupported M3U8 file; multiple video codecs found in the CODECS attribute of a variant stream.");b=e;const a=t.attributes.get("video");if(null===a){const e=t.attributes.get("resolution");let r=null,n=null;if(e){const t=e.match(/^(\d+)x(\d+)$/);t&&(r=Number(t[1]),n=Number(t[2]))}u.push({id:-1,demuxer:this,backingTrack:null,default:!0,autoselect:!0,languageCode:Q,lineNumber:t.lineNumber,fullPath:t.fullPath,fullCodecString:b,pairingMask:BigInt("1")<0?r:null}})}else{if(!a.includes(r))throw new Error(`Invalid M3U8 file; variant stream references audio group "${r}" which is not defined in any #EXT-X-MEDIA tags.`);for(const e of n){const n=e.attributes.get("group-id"),s=e.attributes.get("type");if(n!==r||"audio"!==s.toLowerCase())continue;const a=null!=(l=e.attributes.get("channels"))?l:t.attributes.get("channels"),o=null!==a?Number(a.split("/")[0]):null;u.push({id:-1,demuxer:this,backingTrack:null,default:Qn(e.attributes),autoselect:Qn(e.attributes)||Gn(e.attributes),languageCode:Yn(e.attributes.get("language")),lineNumber:e.lineNumber,fullPath:null!=(c=e.fullPath)?c:t.fullPath,fullCodecString:T,pairingMask:BigInt("1")<0?o:null}})}}}}return u}))),l=[],c=e=>{var t,i;const r=l.find(t=>t.fullPath===e.fullPath&&t.info.type===e.info.type);r?(r.pairingMask|=e.pairingMask,r.default||(r.default=e.default),r.autoselect||(r.autoselect=e.autoselect),r.lineNumber=Math.min(r.lineNumber,e.lineNumber),null!==e.peakBitrate&&(r.peakBitrate=Math.max(null!=(t=r.peakBitrate)?t:-1/0,e.peakBitrate)),null!==e.averageBitrate&&(r.averageBitrate=Math.max(null!=(i=r.averageBitrate)?i:-1/0,e.averageBitrate)),r.languageCode===Q&&(r.languageCode=e.languageCode)):(e.id=l.length+1,l.push(e))};for(const u of o)for(const e of u)c(e);l.sort((e,t)=>e.lineNumber-t.lineNumber),this.trackBackings=[];for(const u of l)"video"===u.info.type?this.trackBackings.push(new Xn(u)):this.trackBackings.push(new $n(u));this.internalTracks=l}))()}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),y(this.trackBackings),this.trackBackings})}getSegmentedInputForPath(e){let t=this.segmentedInputs.find(t=>t.path===e);if(t)return t;let i=null;if(this.internalTracks){i=this.internalTracks.filter(t=>t.fullPath===e).map(e=>({id:e.id,type:e.info.type}))}return t=new Hn(this,e,i,null),this.segmentedInputs.push(t),t}getMetadataTags(){return d(this,null,function*(){return{}})}getMimeType(){return d(this,null,function*(){return on})}dispose(){if(this.segmentedInputs){for(const e of this.segmentedInputs)e.dispose();this.segmentedInputs.length=0}}}class jn{constructor(e){this.internalTrack=e,this.hydrationPromise=null}hydrate(){var e;return null!=(e=this.hydrationPromise)?e:this.hydrationPromise=(()=>d(this,null,function*(){const e=this.internalTrack.demuxer.getSegmentedInputForPath(this.internalTrack.fullPath);let t=null;const i=(yield e.getTrackBackings()).filter(e=>e.getType()===this.getType());if(1===i.length)t=i[0];else if(this instanceof Xn){for(const r of i)if((yield r.getCodec())===this.getCodec()){t=r;break}}else{y(this instanceof $n);for(const e of i)if((yield e.getCodec())===this.getCodec()){t=e;break}}if(!t)throw new Error("Could not find matching track in underlying media data.");this.internalTrack.backingTrack=t}))()}delegate(e){return this.internalTrack.backingTrack?e():this.hydrate().then(e)}getCodec(){throw new Error("Not implemented on base class.")}getDisposition(){return u(c({},Be),{default:this.internalTrack.autoselect,primary:this.internalTrack.default})}getId(){return this.internalTrack.id}getPairingMask(){return this.internalTrack.pairingMask}getInternalCodecId(){return null}getLanguageCode(){return this.internalTrack.languageCode}getName(){return this.internalTrack.name}getNumber(){y(this.internalTrack.demuxer.internalTracks);const e=this.internalTrack.info.type;let t=0;for(const i of this.internalTrack.demuxer.internalTracks)if(i.info.type===e&&t++,i===this.internalTrack)break;return t}getTimeResolution(){return this.delegate(()=>this.internalTrack.backingTrack.getTimeResolution())}isRelativeToUnixEpoch(){return this.delegate(()=>this.internalTrack.backingTrack.isRelativeToUnixEpoch())}getBitrate(){return this.internalTrack.peakBitrate}getAverageBitrate(){return this.internalTrack.averageBitrate}getDurationFromMetadata(e){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getDurationFromMetadata(e)})}getLiveRefreshInterval(){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getLiveRefreshInterval()})}getHasOnlyKeyPackets(){return this.internalTrack.hasOnlyKeyPackets||null}getFirstPacket(e){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getFirstPacket(e)})}getPacket(e,t){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getPacket(e,t)})}getKeyPacket(e,t){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getKeyPacket(e,t)})}getNextPacket(e,t){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getNextPacket(e,t)})}getNextKeyPacket(e,t){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getNextKeyPacket(e,t)})}}class Xn extends jn{constructor(e){super(e)}get backingVideoTrack(){return this.internalTrack.backingTrack}getType(){return"video"}getCodec(){return Ke(this.internalTrack.fullCodecString)}getCodedWidth(){return this.delegate(()=>this.backingVideoTrack.getCodedWidth())}getCodedHeight(){return this.delegate(()=>this.backingVideoTrack.getCodedHeight())}getSquarePixelWidth(){return this.delegate(()=>this.backingVideoTrack.getSquarePixelWidth())}getSquarePixelHeight(){return this.delegate(()=>this.backingVideoTrack.getSquarePixelHeight())}getMetadataDisplayWidth(){return this.backingVideoTrack?null:this.internalTrack.info.width}getMetadataDisplayHeight(){return this.backingVideoTrack?null:this.internalTrack.info.height}getRotation(){return this.delegate(()=>this.backingVideoTrack.getRotation())}getColorSpace(){return d(this,null,function*(){return yield this.hydrate(),this.backingVideoTrack.getColorSpace()})}canBeTransparent(){return d(this,null,function*(){return yield this.hydrate(),this.backingVideoTrack.canBeTransparent()})}getMetadataCodecParameterString(){return this.backingVideoTrack?null:this.internalTrack.fullCodecString}getDecoderConfig(){return d(this,null,function*(){return yield this.hydrate(),this.backingVideoTrack.getDecoderConfig()})}}class $n extends jn{constructor(e){super(e)}get backingAudioTrack(){return this.internalTrack.backingTrack}getType(){return"audio"}getCodec(){return Ke(this.internalTrack.fullCodecString)}getNumberOfChannels(){return null!==this.internalTrack.info.numberOfChannels?this.internalTrack.info.numberOfChannels:this.delegate(()=>this.backingAudioTrack.getNumberOfChannels())}getSampleRate(){return this.delegate(()=>this.backingAudioTrack.getSampleRate())}getMetadataCodecParameterString(){return this.backingAudioTrack?null:this.internalTrack.fullCodecString}getDecoderConfig(){return d(this,null,function*(){return yield this.hydrate(),this.backingAudioTrack.getDecoderConfig()})}}const Qn=e=>{const t=e.get("default");if(null===t)return!1;const i=t.toUpperCase();if("YES"===i)return!0;if("NO"===i)return!1;throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA DEFAULT attribute must be YES or NO, got "${t}".`)},Gn=e=>{const t=e.get("autoselect");if(null===t)return!1;const i=t.toUpperCase();if("YES"===i)return!0;if("NO"===i)return!1;throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA AUTOSELECT attribute must be YES or NO, got "${t}".`)},Yn=e=>{if(null===e)return Q;const t=e.split("-")[0];return t||Q};class Jn{constructor(){this._isIsobmff=!1}}class Zn extends Jn{constructor(){super(...arguments),this._isIsobmff=!0}_getMajorBrand(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=yield t),!t)return null;t.skip(4);const i=Wa(t,4);return"ftyp"!==i&&"styp"!==i?null:Wa(t,4)})}_createDemuxer(e){return new gi(e)}}class es extends Zn{_canReadInput(e){return d(this,null,function*(){const t=yield this._getMajorBrand(e);if(null!==t)return"qt "!==t;let i=e._reader.requestSlice(4,4);return i instanceof Promise&&(i=yield i),!!i&&"moof"===Wa(i,4)})}get name(){return"MP4"}get mimeType(){return"video/mp4"}}class ts extends Zn{_canReadInput(e){return d(this,null,function*(){return"qt "===(yield this._getMajorBrand(e))})}get name(){return"QuickTime File Format"}get mimeType(){return"video/quicktime"}}class is extends Jn{isSupportedEBMLOfDocType(e,t){return d(this,null,function*(){let i=e._reader.requestSlice(0,Li);if(i instanceof Promise&&(i=yield i),!i)return!1;const r=zi(i);if(null===r)return!1;if(r<1||r>8)return!1;if(qi(i,r)!==Ri.EBML)return!1;const n=Vi(i);if("number"!==typeof n)return!1;let s=e._reader.requestSlice(i.filePos,n);if(s instanceof Promise&&(s=yield s),!s)return!1;const a=i.filePos;for(;s.filePos<=a+n-2;){const e=Hi(s);if(!e)break;const{id:i,size:r}=e,n=s.filePos;if(void 0===r)return!1;switch(i){case Ri.EBMLVersion:if(1!==qi(s,r))return!1;break;case Ri.EBMLReadVersion:if(1!==qi(s,r))return!1;break;case Ri.DocType:if(Ki(s,r)!==t)return!1;break;case Ri.DocTypeVersion:if(qi(s,r)>4)return!1}s.filePos=n+r}return!0})}_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"matroska")}_createDemuxer(e){return new kr(e)}get name(){return"Matroska"}get mimeType(){return"video/x-matroska"}}class rs extends is{_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"webm")}get name(){return"WebM"}get mimeType(){return"video/webm"}}class ns extends Jn{_canReadInput(e){return d(this,null,function*(){let t=0;for(;;){let i=e._reader.requestSlice(t,Qa);if(i instanceof Promise&&(i=yield i),!i)break;const r=Za(i);if(!r)break;t=i.filePos+r.size}const i=yield Sr(e._reader,t,t+4096);if(!i)return!1;const r=i.header,n=Ge(r.mpegVersionId,r.channel);let s=e._reader.requestSlice(i.startPos+n,4);if(s instanceof Promise&&(s=yield s),!s)return!1;const a=Ra(s);if(a===$e||a===Qe)return!0;t=i.startPos+i.header.totalSize;const o=yield Sr(e._reader,t,t+4);if(!o)return!1;const l=o.header;return r.channel===l.channel&&r.sampleRate===l.sampleRate})}_createDemuxer(e){return new vr(e)}get name(){return"MP3"}get mimeType(){return"audio/mpeg"}}class ss extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=yield t),!t)return!1;const i=Wa(t,4);if("RIFF"!==i&&"RIFX"!==i&&"RF64"!==i)return!1;t.skip(4);return"WAVE"===Wa(t,4)})}_createDemuxer(e){return new Lr(e)}get name(){return"WAVE"}get mimeType(){return"audio/wav"}}class as extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=yield t),!!t&&"OggS"===Wa(t,4)})}_createDemuxer(e){return new Fr(e)}get name(){return"Ogg"}get mimeType(){return"application/ogg"}}class os extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=yield t),!!t&&"fLaC"===Wa(t,4)})}get name(){return"FLAC"}get mimeType(){return"audio/flac"}_createDemuxer(e){return new Kr(e)}}class ls extends Jn{_canReadInput(e){return d(this,null,function*(){let t=0;for(;;){let i=e._reader.requestSlice(t,Qa);if(i instanceof Promise&&(i=yield i),!i)break;const r=Za(i);if(!r)break;t=i.filePos+r.size}let i=e._reader.requestSliceRange(t,7,9);if(i instanceof Promise&&(i=yield i),!i)return!1;const r=qr(i);if(!r)return!1;if(t+=r.frameLength,i=e._reader.requestSliceRange(t,7,9),i instanceof Promise&&(i=yield i),!i)return!1;const n=qr(i);return!!n&&(r.objectType===n.objectType&&r.samplingFrequencyIndex===n.samplingFrequencyIndex&&r.channelConfiguration===n.channelConfiguration)})}_createDemuxer(e){return new Vr(e)}get name(){return"ADTS"}get mimeType(){return"audio/aac"}}class cs extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,205);if(t instanceof Promise&&(t=yield t),!t)return!1;const i=xa(t,205);return 71===i[0]&&71===i[188]||(71===i[0]&&71===i[204]||71===i[4]&&71===i[196])})}_createDemuxer(e){return new Yr(e)}get name(){return"MPEG Transport Stream"}get mimeType(){return"video/MP2T"}}class us extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,7);if(t instanceof Promise&&(t=yield t),!t)return!1;if(!("#EXTM3U"===Wa(t,7)))return!1;if(!(e._rootSource instanceof Bn))throw new TypeError("HLS inputs require `InputOptions.source` to be a PathedSource or a ref to one.");return e._rootSource._usedForHls=!0,!0})}_createDemuxer(e){return new Kn(e)}get name(){return"HTTP Live Streaming (HLS)"}get mimeType(){return on}}const ds=new es,hs=new ts,fs=new is,ms=new rs,ps=new ns,gs=new ss,ks=new as,ys=new ls,bs=new os,Ts=new cs,Ss=new us,vs=[Ss,ds,hs,fs,ms,gs,ks,bs,ps,ys,Ts],ws=[Ss,ds,hs,ps,ys,Ts];ke();let Ps=-1/0,Is=-1/0,xs=null;"undefined"!==typeof FinalizationRegistry&&(xs=new FinalizationRegistry(e=>{const t=performance.now();"video"===e.type?(t-Ps>=1e3&&(console.error("A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them."),Ps=t),"undefined"!==typeof VideoFrame&&e.data instanceof VideoFrame&&e.data.close()):(t-Is>=1e3&&(console.error("An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them."),Is=t),"undefined"!==typeof AudioData&&e.data instanceof AudioData&&e.data.close())}));const Cs=["I420","I420P10","I420P12","I420A","I420AP10","I420AP12","I422","I422P10","I422P12","I422A","I422AP10","I422AP12","I444","I444P10","I444P12","I444A","I444AP10","I444AP12","NV12","RGBA","RGBX","BGRA","BGRX"],Bs=new Set(Cs);class Es{get codedWidth(){return this.visibleRect.width}get codedHeight(){return this.visibleRect.height}get displayWidth(){return this.rotation%180===0?this.squarePixelWidth:this.squarePixelHeight}get displayHeight(){return this.rotation%180===0?this.squarePixelHeight:this.squarePixelWidth}get microsecondTimestamp(){return Math.trunc(te*this.timestamp)}get microsecondDuration(){return Math.trunc(te*this.duration)}get hasAlpha(){return this.format&&this.format.includes("A")}constructor(e,t){var i,r,n,s,a,o,l,c,u,d,h,f,m,p,g,k,b,T,S,v,P,I,x,C,B,E;if(this._closed=!1,e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e)){if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0===t.format||!Bs.has(t.format))throw new TypeError("init.format must be one of: "+Cs.join(", "));if(!Number.isInteger(t.codedWidth)||t.codedWidth<=0)throw new TypeError("init.codedWidth must be a positive integer.");if(!Number.isInteger(t.codedHeight)||t.codedHeight<=0)throw new TypeError("init.codedHeight must be a positive integer.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if(void 0!==t.layout){if(!Array.isArray(t.layout))throw new TypeError("init.layout, when provided, must be an array.");for(const e of t.layout){if(!e||"object"!==typeof e||Array.isArray(e))throw new TypeError("Each entry in init.layout must be an object.");if(!Number.isInteger(e.offset)||e.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(e.stride)||e.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==t.visibleRect&&we(t.visibleRect,"init.visibleRect"),void 0!==t.displayWidth&&(!Number.isInteger(t.displayWidth)||t.displayWidth<=0))throw new TypeError("init.displayWidth, when provided, must be a positive integer.");if(void 0!==t.displayHeight&&(!Number.isInteger(t.displayHeight)||t.displayHeight<=0))throw new TypeError("init.displayHeight, when provided, must be a positive integer.");if(void 0!==t.displayWidth!==(void 0!==t.displayHeight))throw new TypeError("init.displayWidth and init.displayHeight must be either both provided or both omitted.");this._data=w(e).slice(),this._layout=null!=(i=t.layout)?i:Ms(t.format,t.codedWidth,t.codedHeight),this.format=t.format,this.rotation=null!=(r=t.rotation)?r:0,this.timestamp=t.timestamp,this.duration=null!=(n=t.duration)?n:0,this.colorSpace=new _s(t.colorSpace),this.visibleRect={left:null!=(a=null==(s=t.visibleRect)?void 0:s.left)?a:0,top:null!=(l=null==(o=t.visibleRect)?void 0:o.top)?l:0,width:null!=(u=null==(c=t.visibleRect)?void 0:c.width)?u:t.codedWidth,height:null!=(h=null==(d=t.visibleRect)?void 0:d.height)?h:t.codedHeight},void 0!==t.displayWidth?(this.squarePixelWidth=this.rotation%180===0?t.displayWidth:t.displayHeight,this.squarePixelHeight=this.rotation%180===0?t.displayHeight:t.displayWidth):(this.squarePixelWidth=this.codedWidth,this.squarePixelHeight=this.codedHeight)}else if("undefined"!==typeof VideoFrame&&e instanceof VideoFrame){if(void 0!==(null==t?void 0:t.rotation)&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(void 0!==(null==t?void 0:t.timestamp)&&!Number.isFinite(null==t?void 0:t.timestamp))throw new TypeError("init.timestamp, when provided, must be a number.");if(void 0!==(null==t?void 0:t.duration)&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");void 0!==(null==t?void 0:t.visibleRect)&&we(t.visibleRect,"init.visibleRect"),this._data=e,this._layout=null,this.format=e.format,this.visibleRect={left:null!=(m=null==(f=e.visibleRect)?void 0:f.x)?m:0,top:null!=(g=null==(p=e.visibleRect)?void 0:p.y)?g:0,width:null!=(b=null==(k=e.visibleRect)?void 0:k.width)?b:e.codedWidth,height:null!=(S=null==(T=e.visibleRect)?void 0:T.height)?S:e.codedHeight},this.rotation=null!=(v=null==t?void 0:t.rotation)?v:0,this.squarePixelWidth=e.displayWidth,this.squarePixelHeight=e.displayHeight,this.timestamp=null!=(P=null==t?void 0:t.timestamp)?P:e.timestamp/1e6,this.duration=null!=(x=null==t?void 0:t.duration)?x:(null!=(I=e.duration)?I:0)/1e6,this.colorSpace=new _s(e.colorSpace)}else{if(!("undefined"!==typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!==typeof SVGImageElement&&e instanceof SVGImageElement||"undefined"!==typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!==typeof HTMLVideoElement&&e instanceof HTMLVideoElement||"undefined"!==typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!==typeof OffscreenCanvas&&e instanceof OffscreenCanvas))throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource.");{if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if("undefined"!==typeof VideoFrame)return new Es(new VideoFrame(e,{timestamp:Math.trunc(t.timestamp*te),duration:Math.trunc((null!=(C=t.duration)?C:0)*te)||void 0}),t);let i=0,r=0;if("naturalWidth"in e?(i=e.naturalWidth,r=e.naturalHeight):"videoWidth"in e?(i=e.videoWidth,r=e.videoHeight):"width"in e&&(i=Number(e.width),r=Number(e.height)),!i||!r)throw new TypeError("Could not determine dimensions.");const n=new OffscreenCanvas(i,r),s=n.getContext("2d",{alpha:ce(),willReadFrequently:!0});y(s),s.drawImage(e,0,0),this._data=n,this._layout=null,this.format="RGBX",this.visibleRect={left:0,top:0,width:i,height:r},this.squarePixelWidth=i,this.squarePixelHeight=r,this.rotation=null!=(B=t.rotation)?B:0,this.timestamp=t.timestamp,this.duration=null!=(E=t.duration)?E:0,this.colorSpace=new _s({matrix:"rgb",primaries:"bt709",transfer:"iec61966-2-1",fullRange:!0})}}this.pixelAspectRatio=ve({num:this.squarePixelWidth*this.codedHeight,den:this.squarePixelHeight*this.codedWidth}),null==xs||xs.register(this,{type:"video",data:this._data},this)}clone(){if(this._closed)throw new Error("VideoSample is closed.");return y(null!==this._data),As(this._data)?new Es(this._data.clone(),{timestamp:this.timestamp,duration:this.duration,rotation:this.rotation}):this._data instanceof Uint8Array?(y(this._layout),new Es(this._data,{format:this.format,layout:this._layout,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation,visibleRect:this.visibleRect,displayWidth:this.displayWidth,displayHeight:this.displayHeight})):new Es(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation,visibleRect:this.visibleRect,displayWidth:this.displayWidth,displayHeight:this.displayHeight})}close(){this._closed||(null==xs||xs.unregister(this),As(this._data)?this._data.close():this._data=null,this._closed=!0)}allocationSize(e={}){if(Ds(e),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot get allocation size when format is null. Sorry!");if(y(null!==this._data),!As(this._data)&&(e.colorSpace||e.format&&e.format!==this.format||e.layout||e.rect)){const t=this.toVideoFrame(),i=t.allocationSize(e);return t.close(),i}return As(this._data)?this._data.allocationSize(e):this._data instanceof Uint8Array?this._data.byteLength:this.codedWidth*this.codedHeight*4}copyTo(e){return d(this,arguments,function*(e,t={}){if(!R(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(Ds(t),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot copy video sample data when format is null. Sorry!");if(y(null!==this._data),!As(this._data)&&(t.colorSpace||t.format&&t.format!==this.format||t.layout||t.rect)){const i=this.toVideoFrame(),r=yield i.copyTo(e,t);return i.close(),r}if(As(this._data))return this._data.copyTo(e,t);if(this._data instanceof Uint8Array){y(this._layout);return w(e).set(this._data),this._layout}{const t=this._data.getContext("2d");y(t);const i=t.getImageData(0,0,this.codedWidth,this.codedHeight);return w(e).set(i.data),[{offset:0,stride:4*this.codedWidth}]}})}toVideoFrame(){if(this._closed)throw new Error("VideoSample is closed.");return y(null!==this._data),As(this._data)?new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0}):this._data instanceof Uint8Array?new VideoFrame(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0,colorSpace:this.colorSpace}):new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0})}draw(e,t,i,r,n,s,a,o,l){let c=0,u=0,d=this.displayWidth,h=this.displayHeight,f=0,m=0,p=this.displayWidth,g=this.displayHeight;if(void 0!==s?(c=t,u=i,d=r,h=n,f=s,m=a,void 0!==o?(p=o,g=l):(p=d,g=h)):(f=t,m=i,void 0!==r&&(p=r,g=n)),!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!Number.isFinite(c))throw new TypeError("sx must be a number.");if(!Number.isFinite(u))throw new TypeError("sy must be a number.");if(!Number.isFinite(d)||d<0)throw new TypeError("sWidth must be a non-negative number.");if(!Number.isFinite(h)||h<0)throw new TypeError("sHeight must be a non-negative number.");if(!Number.isFinite(f))throw new TypeError("dx must be a number.");if(!Number.isFinite(m))throw new TypeError("dy must be a number.");if(!Number.isFinite(p)||p<0)throw new TypeError("dWidth must be a non-negative number.");if(!Number.isFinite(g)||g<0)throw new TypeError("dHeight must be a non-negative number.");if(this._closed)throw new Error("VideoSample is closed.");({sx:c,sy:u,sWidth:d,sHeight:h}=this._rotateSourceRegion(c,u,d,h,this.rotation));const k=this.toCanvasImageSource();e.save();const y=f+p/2,b=m+g/2;e.translate(y,b),e.rotate(this.rotation*Math.PI/180);const T=this.rotation%180===0?1:p/g;e.scale(1/T,T),e.drawImage(k,c,u,d,h,-p/2,-g/2,p,g),e.restore()}drawWithFit(e,t){var i,r,n,s,a,o,l,c,u;if(!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!["fill","contain","cover"].includes(t.fit))throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270.");void 0!==t.crop&&Rs(t.crop,"options.");const d=e.canvas.width,h=e.canvas.height,f=null!=(i=t.rotation)?i:this.rotation,[m,p]=f%180===0?[this.squarePixelWidth,this.squarePixelHeight]:[this.squarePixelHeight,this.squarePixelWidth];let g,k,y,b;t.crop&&Fs(t.crop,m,p);const{sx:T,sy:S,sWidth:v,sHeight:w}=this._rotateSourceRegion(null!=(n=null==(r=t.crop)?void 0:r.left)?n:0,null!=(a=null==(s=t.crop)?void 0:s.top)?a:0,null!=(l=null==(o=t.crop)?void 0:o.width)?l:m,null!=(u=null==(c=t.crop)?void 0:c.height)?u:p,f);if("fill"===t.fit)g=0,k=0,y=d,b=h;else{const[e,i]=t.crop?[t.crop.width,t.crop.height]:[m,p],r="contain"===t.fit?Math.min(d/e,h/i):Math.max(d/e,h/i);y=e*r,b=i*r,g=(d-y)/2,k=(h-b)/2}e.save();const P=f%180===0?1:y/b;e.translate(d/2,h/2),e.rotate(f*Math.PI/180),e.scale(1/P,P),e.translate(-d/2,-h/2),e.drawImage(this.toCanvasImageSource(),T,S,v,w,g,k,y,b),e.restore()}_rotateSourceRegion(e,t,i,r,n){return 90===n?[e,t,i,r]=[t,this.squarePixelHeight-e-i,r,i]:180===n?[e,t]=[this.squarePixelWidth-e-i,this.squarePixelHeight-t-r]:270===n&&([e,t,i,r]=[this.squarePixelWidth-t-r,e,r,i]),{sx:e,sy:t,sWidth:i,sHeight:r}}toCanvasImageSource(){if(this._closed)throw new Error("VideoSample is closed.");if(y(null!==this._data),this._data instanceof Uint8Array){const e=this.toVideoFrame();return queueMicrotask(()=>e.close()),e}return this._data}setRotation(e){if(![0,90,180,270].includes(e))throw new TypeError("newRotation must be 0, 90, 180, or 270.");this.rotation=e}setTimestamp(e){if(!Number.isFinite(e))throw new TypeError("newTimestamp must be a number.");this.timestamp=e}setDuration(e){if(!Number.isFinite(e)||e<0)throw new TypeError("newDuration must be a non-negative number.");this.duration=e}[Symbol.dispose](){this.close()}}class _s{constructor(e){var t,i,r,n;if(void 0!==e){if(!e||"object"!==typeof e)throw new TypeError("init.colorSpace, when provided, must be an object.");const t=Object.keys(C);if(null!=e.primaries&&!t.includes(e.primaries))throw new TypeError(`init.colorSpace.primaries, when provided, must be one of ${t.join(", ")}.`);const i=Object.keys(E);if(null!=e.transfer&&!i.includes(e.transfer))throw new TypeError(`init.colorSpace.transfer, when provided, must be one of ${i.join(", ")}.`);const r=Object.keys(A);if(null!=e.matrix&&!r.includes(e.matrix))throw new TypeError(`init.colorSpace.matrix, when provided, must be one of ${r.join(", ")}.`);if(null!=e.fullRange&&"boolean"!==typeof e.fullRange)throw new TypeError("init.colorSpace.fullRange, when provided, must be a boolean.")}this.primaries=null!=(t=null==e?void 0:e.primaries)?t:null,this.transfer=null!=(i=null==e?void 0:e.transfer)?i:null,this.matrix=null!=(r=null==e?void 0:e.matrix)?r:null,this.fullRange=null!=(n=null==e?void 0:e.fullRange)?n:null}toJSON(){return{primaries:this.primaries,transfer:this.transfer,matrix:this.matrix,fullRange:this.fullRange}}}const As=e=>"undefined"!==typeof VideoFrame&&e instanceof VideoFrame,Fs=(e,t,i)=>{const r=Math.min(e.left,t),n=Math.min(e.top,i),s=Math.min(e.width,t-r),a=Math.min(e.height,i-n);return y(s>=0),y(a>=0),{left:r,top:n,width:s,height:a}},Rs=(e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(t+"crop, when provided, must be an object.");if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(t+"crop.left must be a non-negative integer.");if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(t+"crop.top must be a non-negative integer.");if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(t+"crop.width must be a non-negative integer.");if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(t+"crop.height must be a non-negative integer.")},Ds=e=>{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.colorSpace&&!["display-p3","srgb"].includes(e.colorSpace))throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");if(void 0!==e.format&&"string"!==typeof e.format)throw new TypeError("options.format, when provided, must be a string.");if(void 0!==e.layout){if(!Array.isArray(e.layout))throw new TypeError("options.layout, when provided, must be an array.");for(const t of e.layout){if(!t||"object"!==typeof t)throw new TypeError("Each entry in options.layout must be an object.");if(!Number.isInteger(t.offset)||t.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(t.stride)||t.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==e.rect){if(!e.rect||"object"!==typeof e.rect)throw new TypeError("options.rect, when provided, must be an object.");if(void 0!==e.rect.x&&(!Number.isInteger(e.rect.x)||e.rect.x<0))throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");if(void 0!==e.rect.y&&(!Number.isInteger(e.rect.y)||e.rect.y<0))throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");if(void 0!==e.rect.width&&(!Number.isInteger(e.rect.width)||e.rect.width<0))throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");if(void 0!==e.rect.height&&(!Number.isInteger(e.rect.height)||e.rect.height<0))throw new TypeError("options.rect.height, when provided, must be a non-negative integer.")}},Ms=(e,t,i)=>{const r=Ns(e),n=[];let s=0;for(const a of r){const e=Math.ceil(t/a.widthDivisor),r=Math.ceil(i/a.heightDivisor),o=e*a.sampleBytes,l=o*r;n.push({offset:s,stride:o}),s+=l}return n},Ns=e=>{const t=(e,t,i,r,n)=>{const s=[{sampleBytes:e,widthDivisor:1,heightDivisor:1},{sampleBytes:t,widthDivisor:i,heightDivisor:r},{sampleBytes:t,widthDivisor:i,heightDivisor:r}];return n&&s.push({sampleBytes:e,widthDivisor:1,heightDivisor:1}),s};switch(e){case"I420":return t(1,1,2,2,!1);case"I420P10":case"I420P12":return t(2,2,2,2,!1);case"I420A":return t(1,1,2,2,!0);case"I420AP10":case"I420AP12":return t(2,2,2,2,!0);case"I422":return t(1,1,2,1,!1);case"I422P10":case"I422P12":return t(2,2,2,1,!1);case"I422A":return t(1,1,2,1,!0);case"I422AP10":case"I422AP12":return t(2,2,2,1,!0);case"I444":return t(1,1,1,1,!1);case"I444P10":case"I444P12":return t(2,2,1,1,!1);case"I444A":return t(1,1,1,1,!0);case"I444AP10":case"I444AP12":return t(2,2,1,1,!0);case"NV12":return[{sampleBytes:1,widthDivisor:1,heightDivisor:1},{sampleBytes:2,widthDivisor:2,heightDivisor:2}];case"RGBA":case"RGBX":case"BGRA":case"BGRX":return[{sampleBytes:4,widthDivisor:1,heightDivisor:1}];default:H(e),y(!1)}},Os=new Set(["f32","f32-planar","s16","s16-planar","s32","s32-planar","u8","u8-planar"]);class Ls{get microsecondTimestamp(){return Math.trunc(te*this.timestamp)}get microsecondDuration(){return Math.trunc(te*this.duration)}constructor(e){if(this._closed=!1,Vs(e)){if(null===e.format)throw new TypeError("AudioData with null format is not supported.");this._data=e,this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=e.numberOfFrames,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp/1e6,this.duration=e.numberOfFrames/e.sampleRate}else{if(!e||"object"!==typeof e)throw new TypeError("Invalid AudioDataInit: must be an object.");if(!Os.has(e.format))throw new TypeError("Invalid AudioDataInit: invalid format.");if(!Number.isFinite(e.sampleRate)||e.sampleRate<=0)throw new TypeError("Invalid AudioDataInit: sampleRate must be > 0.");if(!Number.isInteger(e.numberOfChannels)||0===e.numberOfChannels)throw new TypeError("Invalid AudioDataInit: numberOfChannels must be an integer > 0.");if(!Number.isFinite(null==e?void 0:e.timestamp))throw new TypeError("init.timestamp must be a number.");const t=e.data.byteLength/(zs(e.format)*e.numberOfChannels);if(!Number.isInteger(t))throw new TypeError("Invalid AudioDataInit: data size is not a multiple of frame size.");let i;if(this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=t,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp,this.duration=t/e.sampleRate,e.data instanceof ArrayBuffer)i=new Uint8Array(e.data);else{if(!ArrayBuffer.isView(e.data))throw new TypeError("Invalid AudioDataInit: data is not a BufferSource.");i=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength)}const r=this.numberOfFrames*this.numberOfChannels*zs(this.format);if(i.byteLength=this.numberOfFrames)throw new RangeError("frameOffset out of range");const s=void 0!==e.frameCount?e.frameCount:this.numberOfFrames-n;if(s>this.numberOfFrames-n)throw new RangeError("frameCount out of range");const a=zs(r),o=Us(r);if(o&&e.planeIndex>=this.numberOfChannels)throw new RangeError("planeIndex out of range");if(!o&&0!==e.planeIndex)throw new RangeError("planeIndex out of range");return(o?s:s*this.numberOfChannels)*a}copyTo(e,t){if(!R(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!Number.isInteger(t.planeIndex)||t.planeIndex<0)throw new TypeError("planeIndex must be a non-negative integer.");if(void 0!==t.format&&!Os.has(t.format))throw new TypeError("Invalid format.");if(void 0!==t.frameOffset&&(!Number.isInteger(t.frameOffset)||t.frameOffset<0))throw new TypeError("frameOffset must be a non-negative integer.");if(void 0!==t.frameCount&&(!Number.isInteger(t.frameCount)||t.frameCount<0))throw new TypeError("frameCount must be a non-negative integer.");if(this._closed)throw new Error("AudioSample is closed.");const{planeIndex:i,format:r,frameCount:n,frameOffset:s}=t,a=this.format,o=null!=r?r:this.format;if(!o)throw new Error("Destination format not determined");const l=this.numberOfFrames,c=this.numberOfChannels,u=null!=s?s:0;if(u>=l)throw new RangeError("frameOffset out of range");const d=void 0!==n?n:l-u;if(d>l-u)throw new RangeError("frameCount out of range");const h=zs(o),f=Us(o);if(f&&i>=c)throw new RangeError("planeIndex out of range");if(!f&&0!==i)throw new RangeError("planeIndex out of range");const m=(f?d:d*c)*h;if(e.byteLength2&&o!==a?Hs(this._data,p,a,o,c,i,u,d):this._data.copyTo(e,{planeIndex:i,frameOffset:u,frameCount:d,format:o});else{const e=this._data,t=P(e),r=qs(a),n=zs(a),s=Us(a);for(let a=0;a0;){const n=Math.min(s,o),l=new Float32Array(i*n);for(let t=0;t0;){const n=Math.min(s,o),c=new Float32Array(i*n);for(let t=0;t{switch(e){case"u8":case"u8-planar":return 1;case"s16":case"s16-planar":return 2;case"s32":case"s32-planar":case"f32":case"f32-planar":return 4;default:throw new Error("Unknown AudioSampleFormat")}},Us=e=>{switch(e){case"u8-planar":case"s16-planar":case"s32-planar":case"f32-planar":return!0;default:return!1}},qs=e=>{switch(e){case"u8":case"u8-planar":return(e,t)=>(e.getUint8(t)-128)/128;case"s16":case"s16-planar":return(e,t)=>e.getInt16(t,!0)/32768;case"s32":case"s32-planar":return(e,t)=>e.getInt32(t,!0)/2147483648;case"f32":case"f32-planar":return(e,t)=>e.getFloat32(t,!0)}},Ws=e=>{switch(e){case"u8":case"u8-planar":return(e,t,i)=>e.setUint8(t,$(127.5*(i+1),0,255));case"s16":case"s16-planar":return(e,t,i)=>e.setInt16(t,$(Math.round(32767*i),-32768,32767),!0);case"s32":case"s32-planar":return(e,t,i)=>e.setInt32(t,$(Math.round(2147483647*i),-2147483648,2147483647),!0);case"f32":case"f32-planar":return(e,t,i)=>e.setFloat32(t,i,!0)}},Vs=e=>"undefined"!==typeof AudioData&&e instanceof AudioData,Hs=(e,t,i,r,n,s,a,o)=>{const l=qs(i),c=Ws(r),u=zs(i),d=zs(r),h=Us(i);if(Us(r))if(h){const r=new ArrayBuffer(o*u),n=P(r);e.copyTo(r,{planeIndex:s,frameOffset:a,frameCount:o,format:i});for(let e=0;e{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.metadataOnly&&"boolean"!==typeof e.metadataOnly)throw new TypeError("options.metadataOnly, when defined, must be a boolean.");if(void 0!==e.verifyKeyPackets&&"boolean"!==typeof e.verifyKeyPackets)throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");if(e.verifyKeyPackets&&e.metadataOnly)throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.");if(void 0!==e.skipLiveWait&&"boolean"!==typeof e.skipLiveWait)throw new TypeError("options.skipLiveWait, when defined, must be a boolean.")},$s=e=>{if(!ye(e))throw new TypeError("timestamp must be a number.")},Qs=(e,t,i)=>i.verifyKeyPackets?t.then(t=>d(null,null,function*(){if(!t||"delta"===t.type)return t;const i=yield e.determinePacketType(t);return i&&(t.type=i),t})):t;class Gs{constructor(e){if(!(e instanceof la))throw new TypeError("track must be an InputTrack.");this._track=e}getFirstPacket(){return d(this,arguments,function*(e={}){if(Xs(e),this._track.input._disposed)throw new va;return Qs(this._track,this._track._backing.getFirstPacket(e),e)})}getFirstKeyPacket(){return d(this,arguments,function*(e={}){Xs(e);const t=yield this.getFirstPacket(e);return t?"key"===t.type?t:this.getNextKeyPacket(t,e):null})}getPacket(e){return d(this,arguments,function*(e,t={}){if($s(e),Xs(t),this._track.input._disposed)throw new va;return Qs(this._track,this._track._backing.getPacket(e,t),t)})}getNextPacket(e){return d(this,arguments,function*(e,t={}){if(!(e instanceof Yt))throw new TypeError("packet must be an EncodedPacket.");if(Xs(t),this._track.input._disposed)throw new va;return Qs(this._track,this._track._backing.getNextPacket(e,t),t)})}getKeyPacket(e){return d(this,arguments,function*(e,t={}){if($s(e),Xs(t),this._track.input._disposed)throw new va;if(!t.verifyKeyPackets)return this._track._backing.getKeyPacket(e,t);const i=yield this._track._backing.getKeyPacket(e,t);if(!i)return i;y("key"===i.type);return"delta"===(yield this._track.determinePacketType(i))?this.getKeyPacket(i.timestamp-1/(yield this._track.getTimeResolution()),t):i})}getNextKeyPacket(e){return d(this,arguments,function*(e,t={}){if(!(e instanceof Yt))throw new TypeError("packet must be an EncodedPacket.");if(Xs(t),this._track.input._disposed)throw new va;if(!t.verifyKeyPackets)return this._track._backing.getNextKeyPacket(e,t);const i=yield this._track._backing.getNextKeyPacket(e,t);if(!i)return i;y("key"===i.type);return"delta"===(yield this._track.determinePacketType(i))?this.getNextKeyPacket(i,t):i})}packets(e,t,i={}){if(void 0!==e&&!(e instanceof Yt))throw new TypeError("startPacket must be an EncodedPacket.");if(void 0!==e&&e.isMetadataOnly&&!(null==i?void 0:i.metadataOnly))throw new TypeError("startPacket can only be metadata-only if options.metadataOnly is enabled.");if(void 0!==t&&!(t instanceof Yt))throw new TypeError("endPacket must be an EncodedPacket.");if(Xs(i),this._track.input._disposed)throw new va;const r=[];let{promise:n,resolve:s}=q(),{promise:a,resolve:o}=q(),l=!1,c=!1,u=null;const h=[],f=()=>Math.max(2,h.length);(()=>d(this,null,function*(){let u=null!=e?e:yield this.getFirstPacket(i);for(;u&&!c&&!this._track.input._disposed&&!(t&&u.sequenceNumber>=(null==t?void 0:t.sequenceNumber));)r.length>f()?(({promise:a,resolve:o}=q()),yield a):(r.push(u),s(),({promise:n,resolve:s}=q()),u=yield this.getNextPacket(u,i));l=!0,s()}))().catch(e=>{u||(u=e,s())});const m=this._track;return{next(){return d(this,null,function*(){for(;;){if(m.input._disposed)throw new va;if(c)return{value:void 0,done:!0};if(u)throw u;if(r.length>0){const e=r.shift(),t=performance.now();for(h.push(t);h.length>0&&t-h[0]>=1e3;)h.shift();return o(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};yield n}})},return(){return d(this,null,function*(){return c=!0,o(),s(),{value:void 0,done:!0}})},throw(e){return d(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}}class Ys{constructor(e,t){this.onSample=e,this.onError=t}}class Js{mediaSamplesInRange(e=0,t=1/0,i){$s(e),$s(t);const r=[];let n=!1,s=null,{promise:a,resolve:o}=q(),{promise:l,resolve:h}=q(),f=!1,m=!1,p=!1,g=null;const k=u(c({},i),{verifyKeyPackets:!0,metadataOnly:!1});(()=>d(this,null,function*(){var i;const c=yield this._createDecoder(i=>{h(),i.timestamp>=t&&(m=!0),m?i.close():(s&&(i.timestamp>e?(r.push(s),n=!0):s.close()),i.timestamp>=e&&(r.push(i),n=!0),s=n?null:i,r.length>0&&(o(),({promise:a,resolve:o}=q())))},e=>{g||(g=e,o())}),u=this._createPacketSink(),d=null!=(i=yield u.getKeyPacket(e,k))?i:yield u.getFirstKeyPacket(k);let y=d;const b=u.packets(null!=d?d:void 0,void 0,k);for(yield b.next();y&&!m&&!this._track.input._disposed;){const e=Zs(r.length);if(r.length+c.getDecodeQueueSize()>e){({promise:l,resolve:h}=q()),yield l;continue}c.decode(y);const t=yield b.next();if(t.done)break;y=t.value}yield b.return(),p||this._track.input._disposed||(yield c.flush()),c.close(),!n&&s&&r.push(s),f=!0,o()}))().catch(e=>{g||(g=e,o())});const y=this._track,b=()=>{null==s||s.close();for(const e of r)e.close()};return{next(){return d(this,null,function*(){for(;;){if(y.input._disposed)throw b(),new va;if(p)return{value:void 0,done:!0};if(g)throw b(),g;if(r.length>0){const e=r.shift();return h(),{value:e,done:!1}}if(f)return{value:void 0,done:!0};yield a}})},return(){return d(this,null,function*(){return p=!0,m=!0,h(),o(),b(),{value:void 0,done:!0}})},throw(e){return d(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}mediaSamplesAtTimestamps(e,t){(e=>{if(!(Symbol.iterator in e)&&!(Symbol.asyncIterator in e))throw new TypeError("Argument must be an iterable or async iterable.")})(e);const i=function(e){return f(this,null,function*(){Symbol.iterator in e?yield*m(e[Symbol.iterator]()):yield*m(e[Symbol.asyncIterator]())})}(e),r=[],n=[];let{promise:s,resolve:a}=q(),{promise:o,resolve:l}=q(),h=!1,g=!1,k=null;const b=e=>{n.push(e),a(),({promise:s,resolve:a}=q())},T=u(c({},t),{verifyKeyPackets:!0,metadataOnly:!1});(()=>d(this,null,function*(){const e=yield this._createDecoder(e=>{if(l(),g)return void e.close();let t=0;for(;r.length>0&&e.timestamp-r[0]>-1e-10;)t++,r.shift();if(t>0)for(let i=0;i{k||(k=e,a())}),t=this._createPacketSink();let s=null,c=null,u=-1;const f=()=>d(this,null,function*(){y(c);let i=c;for(e.decode(i);i.sequenceNumberr&&!g;)({promise:o,resolve:l}=q()),yield o;if(g)break;const s=yield t.getNextPacket(i,T);y(s),e.decode(s),i=s}u=-1}),m=()=>d(this,null,function*(){yield e.flush();for(let e=0;e{k||(k=e,a())});const S=this._track,v=()=>{for(const e of n)null==e||e.close()};return{next(){return d(this,null,function*(){for(;;){if(S.input._disposed)throw v(),new va;if(g)return{value:void 0,done:!0};if(k)throw v(),k;if(n.length>0){const e=n.shift();return y(void 0!==e),l(),{value:e,done:!1}}if(h)return{value:void 0,done:!0};yield s}})},return(){return d(this,null,function*(){return g=!0,l(),a(),v(),{value:void 0,done:!0}})},throw(e){return d(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}}const Zs=e=>0===e?40:8;class ea extends Ys{constructor(e,t,i,r,n,s){super(e,t),this.codec=i,this.decoderConfig=r,this.rotation=n,this.timeResolution=s,this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new se,this.customDecoderQueueSize=0,this.inputTimestamps=[],this.sampleQueue=[],this.currentPacketIndex=0,this.raslSkipped=!1,this.alphaDecoder=null,this.alphaHadKeyframe=!1,this.colorQueue=[],this.alphaQueue=[],this.merger=null,this.mergerCreationFailed=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue=[],this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1;const a=Ks.find(e=>e.supports(i,r));if(a)this.customDecoder=new a,this.customDecoder.codec=i,this.customDecoder.config=r,this.customDecoder.onSample=e=>{if(!(e instanceof Es))throw new TypeError("The argument passed to onSample must be a VideoSample.");this.finalizeAndEmitSample(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=e=>{if(this.alphaQueue.length>0){const t=this.alphaQueue.shift();y(void 0!==t),this.mergeAlpha(e,t)}else this.colorQueue.push(e)};if("avc"===i&&this.decoderConfig.description&&de()){const e=(e=>{try{const t=P(e);let i=0;const r=t.getUint8(i++),n=t.getUint8(i++),s=t.getUint8(i++),a=t.getUint8(i++),o=3&t.getUint8(i++),l=31&t.getUint8(i++),c=[];for(let f=0;f0){const t=kt(e.sequenceParameterSets[0]);t&&0===t.frameMbsOnlyFlag&&(this.decoderConfig=u(c({},this.decoderConfig),{hardwareAcceleration:"prefer-software"}))}}const t=new Error("Decoding error").stack;this.decoder=new VideoDecoder({output:t=>{try{e(t)}catch(i){this.onError(i)}},error:e=>{e.stack=t,this.onError(e)}}),this.decoder.configure(this.decoderConfig)}}getDecodeQueueSize(){var e,t;return this.customDecoder?this.customDecoderQueueSize:(y(this.decoder),Math.max(this.decoder.decodeQueueSize,null!=(t=null==(e=this.alphaDecoder)?void 0:e.decodeQueueSize)?t:0))}decode(e){if("hevc"===this.codec&&this.currentPacketIndex>0&&!this.raslSkipped){if(this.hasHevcRaslPicture(e.data))return;this.raslSkipped=!0}if(this.customDecoder)this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--);else{if(y(this.decoder),oe()||U(this.inputTimestamps,e.timestamp,e=>e),de()&&0===this.currentPacketIndex)if("avc"===this.codec){const t=[];for(const r of ct(e.data,this.decoderConfig)){const i=ut(e.data[r.offset]);i>=20&&i<=31||t.push(e.data.subarray(r.offset,r.offset+r.length))}const i=((e,t)=>{if(t.description){const i=3&w(t.description)[4];return mt(e,i+1)}return ft(e)})(t,this.decoderConfig);e=new Yt(i,e.type,e.timestamp,e.duration)}else if("hevc"===this.codec){const t=Ft(e.data,this.decoderConfig);t&&(e=new Yt(t,e.type,e.timestamp,e.duration))}this.decoder.decode(e.toEncodedVideoChunk()),this.decodeAlphaData(e)}this.currentPacketIndex++}decodeAlphaData(e){if(!e.sideData.alpha||this.mergerCreationFailed)return void this.pushNullAlphaFrame();if(!this.merger)try{this.merger=new ta}catch(i){return console.error("Due to an error, only color data will be decoded.",i),this.mergerCreationFailed=!0,void this.decodeAlphaData(e)}if(!this.alphaDecoder){const e=e=>{if(this.alphaDecoderQueueSize--,this.colorQueue.length>0){const t=this.colorQueue.shift();y(void 0!==t),this.mergeAlpha(t,e)}else this.alphaQueue.push(e);for(this.decodedAlphaChunkCount++;this.nullAlphaFrameQueue.length>0&&this.nullAlphaFrameQueue[0]===this.decodedAlphaChunkCount;)if(this.nullAlphaFrameQueue.shift(),this.colorQueue.length>0){const e=this.colorQueue.shift();y(void 0!==e),this.mergeAlpha(e,null)}else this.alphaQueue.push(null)},t=new Error("Decoding error").stack;this.alphaDecoder=new VideoDecoder({output:t=>{try{e(t)}catch(i){this.onError(i)}},error:e=>{e.stack=t,this.onError(e)}}),this.alphaDecoder.configure(this.decoderConfig)}const t=Lt(this.codec,this.decoderConfig,e.sideData.alpha);if(this.alphaHadKeyframe||(this.alphaHadKeyframe="key"===t),this.alphaHadKeyframe){if("hevc"===this.codec&&this.currentAlphaPacketIndex>0&&!this.alphaRaslSkipped){if(this.hasHevcRaslPicture(e.sideData.alpha))return void this.pushNullAlphaFrame();this.alphaRaslSkipped=!0}this.currentAlphaPacketIndex++,this.alphaDecoder.decode(e.alphaToEncodedVideoChunk(null!=t?t:e.type)),this.alphaDecoderQueueSize++}else this.pushNullAlphaFrame()}pushNullAlphaFrame(){0===this.alphaDecoderQueueSize?this.alphaQueue.push(null):this.nullAlphaFrameQueue.push(this.decodedAlphaChunkCount+this.alphaDecoderQueueSize)}hasHevcRaslPicture(e){for(const t of bt(e,this.decoderConfig)){const i=Tt(e[t.offset]);if(i===st.RASL_N||i===st.RASL_R)return!0}return!1}sampleHandler(e){if(oe()){if(this.sampleQueue.length>0&&e.timestamp>=T(this.sampleQueue).timestamp){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}U(this.sampleQueue,e,e=>e.timestamp)}else{const t=this.inputTimestamps.shift();y(void 0!==t),e.setTimestamp(t),this.finalizeAndEmitSample(e)}}finalizeAndEmitSample(e){e.setTimestamp(Math.round(e.timestamp*this.timeResolution)/this.timeResolution),e.setDuration(Math.round(e.duration*this.timeResolution)/this.timeResolution),e.setRotation(this.rotation),this.onSample(e)}mergeAlpha(e,t){var i;if(!t){const t=new Es(e);return void this.sampleHandler(t)}y(this.merger),this.merger.update(e,t),e.close(),t.close();const r=new VideoFrame(this.merger.canvas,{timestamp:e.timestamp,duration:null!=(i=e.duration)?i:void 0}),n=new Es(r);this.sampleHandler(n)}flush(){return d(this,null,function*(){var e;if(this.customDecoder?yield this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(y(this.decoder),yield Promise.all([this.decoder.flush(),null==(e=this.alphaDecoder)?void 0:e.flush()]),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>null==e?void 0:e.close()),this.alphaQueue.length=0,this.alphaHadKeyframe=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue.length=0,this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1),oe()){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}this.currentPacketIndex=0,this.raslSkipped=!1})}close(){var e,t;this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(y(this.decoder),this.decoder.close(),null==(e=this.alphaDecoder)||e.close(),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>null==e?void 0:e.close()),this.alphaQueue.length=0,null==(t=this.merger)||t.close());for(const i of this.sampleQueue)i.close();this.sampleQueue.length=0}}class ta{constructor(){"undefined"!==typeof OffscreenCanvas?this.canvas=new OffscreenCanvas(300,150):this.canvas=document.createElement("canvas");const e=this.canvas.getContext("webgl2",{premultipliedAlpha:!1});if(!e)throw new Error("Couldn't acquire WebGL 2 context.");this.gl=e,this.program=this.createProgram(),this.vao=this.createVAO(),this.colorTexture=this.createTexture(),this.alphaTexture=this.createTexture(),this.gl.useProgram(this.program),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_colorTexture"),0),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_alphaTexture"),1)}createProgram(){const e=this.createShader(this.gl.VERTEX_SHADER,"#version 300 es\n\t\t\tin vec2 a_position;\n\t\t\tin vec2 a_texCoord;\n\t\t\tout vec2 v_texCoord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = vec4(a_position, 0.0, 1.0);\n\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t}\n\t\t"),t=this.createShader(this.gl.FRAGMENT_SHADER,"#version 300 es\n\t\t\tprecision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_colorTexture;\n\t\t\tuniform sampler2D u_alphaTexture;\n\t\t\tin vec2 v_texCoord;\n\t\t\tout vec4 fragColor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture(u_colorTexture, v_texCoord).rgb;\n\t\t\t\tfloat alpha = texture(u_alphaTexture, v_texCoord).r;\n\t\t\t\tfragColor = vec4(color, alpha);\n\t\t\t}\n\t\t"),i=this.gl.createProgram();return this.gl.attachShader(i,e),this.gl.attachShader(i,t),this.gl.linkProgram(i),i}createShader(e,t){const i=this.gl.createShader(e);return this.gl.shaderSource(i,t),this.gl.compileShader(i),i}createVAO(){const e=this.gl.createVertexArray();this.gl.bindVertexArray(e);const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,i),this.gl.bufferData(this.gl.ARRAY_BUFFER,t,this.gl.STATIC_DRAW);const r=this.gl.getAttribLocation(this.program,"a_position"),n=this.gl.getAttribLocation(this.program,"a_texCoord");return this.gl.enableVertexAttribArray(r),this.gl.vertexAttribPointer(r,2,this.gl.FLOAT,!1,16,0),this.gl.enableVertexAttribArray(n),this.gl.vertexAttribPointer(n,2,this.gl.FLOAT,!1,16,8),e}createTexture(){const e=this.gl.createTexture();return this.gl.bindTexture(this.gl.TEXTURE_2D,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),e}update(e,t){e.displayWidth===this.canvas.width&&e.displayHeight===this.canvas.height||(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colorTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),this.gl.activeTexture(this.gl.TEXTURE1),this.gl.bindTexture(this.gl.TEXTURE_2D,this.alphaTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.bindVertexArray(this.vao),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)}close(){var e;null==(e=this.gl.getExtension("WEBGL_lose_context"))||e.loseContext(),this.gl=null}}class ia extends Js{constructor(e){if(!(e instanceof da))throw new TypeError("videoTrack must be an InputVideoTrack.");super(),this._track=e}_createDecoder(e,t){return d(this,null,function*(){if(!(yield this._track.canDecode()))throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track.");const i=yield this._track.getCodec(),r=yield this._track.getRotation(),n=yield this._track.getDecoderConfig(),s=yield this._track.getTimeResolution();return y(i&&n),new ea(e,t,i,n,r,s)})}_createPacketSink(){return new Gs(this._track)}getSample(e){return d(this,arguments,function*(e,t={}){$s(e);try{for(var i,r,n,s=p(this.mediaSamplesAtTimestamps([e],t));i=!(r=yield s.next()).done;i=!1){return r.value}}catch(r){n=[r]}finally{try{i&&(r=s.return)&&(yield r.call(s))}finally{if(n)throw n[0]}}throw new Error("Internal error: Iterator returned nothing.")})}samples(e=0,t=1/0,i={}){return this.mediaSamplesInRange(e,t,i)}samplesAtTimestamps(e,t={}){return this.mediaSamplesAtTimestamps(e,t)}}class ra{constructor(e,t={}){var i,r,n;if(this._rotation=0,this._initPromise=null,this._nextCanvasIndex=0,!(e instanceof da))throw new TypeError("videoTrack must be an InputVideoTrack.");if(t&&"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.alpha&&"boolean"!==typeof t.alpha)throw new TypeError("options.alpha, when provided, must be a boolean.");if(void 0!==t.width&&(!Number.isInteger(t.width)||t.width<=0))throw new TypeError("options.width, when defined, must be a positive integer.");if(void 0!==t.height&&(!Number.isInteger(t.height)||t.height<=0))throw new TypeError("options.height, when defined, must be a positive integer.");if(void 0!==t.fit&&!["fill","contain","cover"].includes(t.fit))throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".');if(void 0!==t.width&&void 0!==t.height&&void 0===t.fit)throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180 or 270.");if(void 0!==t.crop&&Rs(t.crop,"options."),void 0!==t.poolSize&&("number"!==typeof t.poolSize||!Number.isInteger(t.poolSize)||t.poolSize<0))throw new TypeError("poolSize must be a non-negative integer.");this._videoTrack=e,this._alpha=null!=(i=t.alpha)&&i,this._options=t,this._fit=null!=(r=t.fit)?r:"fill",this._videoSampleSink=new ia(e),this._canvasPool=Array.from({length:null!=(n=t.poolSize)?n:0},()=>null)}_ensureInit(){var e;return null!=(e=this._initPromise)?e:this._initPromise=(()=>d(this,null,function*(){var e;const t=this._options,i=this._videoTrack,r=null!=(e=t.rotation)?e:yield i.getRotation(),n=yield i.getSquarePixelWidth(),s=yield i.getSquarePixelHeight(),[a,o]=r%180===0?[n,s]:[s,n];let l=t.crop;l&&(l=Fs(l,a,o));let[c,u]=l?[l.width,l.height]:[a,o];const d=c/u;void 0!==t.width&&void 0===t.height?(c=t.width,u=Math.round(c/d)):void 0===t.width&&void 0!==t.height?(u=t.height,c=Math.round(u*d)):void 0!==t.width&&void 0!==t.height&&(c=t.width,u=t.height),this._width=c,this._height=u,this._rotation=r,this._crop=l}))()}_videoSampleToWrappedCanvas(e){const t=this._width,i=this._height;let r=this._canvasPool[this._nextCanvasIndex],n=!1;r||("undefined"!==typeof document?(r=document.createElement("canvas"),r.width=t,r.height=i):r=new OffscreenCanvas(t,i),this._canvasPool.length>0&&(this._canvasPool[this._nextCanvasIndex]=r),n=!0),this._canvasPool.length>0&&(this._nextCanvasIndex=(this._nextCanvasIndex+1)%this._canvasPool.length);const s=r.getContext("2d",{alpha:this._alpha||ce()});y(s),s.resetTransform(),n||(!this._alpha&&ce()?(s.fillStyle="black",s.fillRect(0,0,t,i)):s.clearRect(0,0,t,i)),e.drawWithFit(s,{fit:this._fit,rotation:this._rotation,crop:this._crop});const a={canvas:r,timestamp:e.timestamp,duration:e.duration};return e.close(),a}getCanvas(e,t){return d(this,null,function*(){$s(e),yield this._ensureInit();const i=yield this._videoSampleSink.getSample(e,t);return i&&this._videoSampleToWrappedCanvas(i)})}canvases(e=0,t=1/0,i){return f(this,null,function*(){yield new h(this._ensureInit()),yield*m(X(this._videoSampleSink.samples(e,t,i),e=>this._videoSampleToWrappedCanvas(e)))})}canvasesAtTimestamps(e,t){return f(this,null,function*(){yield new h(this._ensureInit()),yield*m(X(this._videoSampleSink.samplesAtTimestamps(e,t),e=>e&&this._videoSampleToWrappedCanvas(e)))})}}class na extends Ys{constructor(e,t,i,r){super(e,t),this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new se,this.customDecoderQueueSize=0,this.currentTimestamp=null;const n=t=>{(null===this.currentTimestamp||Math.abs(t.timestamp-this.currentTimestamp)>=t.duration)&&(this.currentTimestamp=t.timestamp);const i=this.currentTimestamp;if(this.currentTimestamp+=t.duration,0===t.numberOfFrames)return void t.close();const n=r.sampleRate;t.setTimestamp(Math.round(i*n)/n),e(t)},s=js.find(e=>e.supports(i,r));if(s)this.customDecoder=new s,this.customDecoder.codec=i,this.customDecoder.config=r,this.customDecoder.onSample=e=>{if(!(e instanceof Ls))throw new TypeError("The argument passed to onSample must be an AudioSample.");n(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=new Error("Decoding error").stack;this.decoder=new AudioDecoder({output:e=>{try{n(new Ls(e))}catch(t){this.onError(t)}},error:t=>{t.stack=e,this.onError(t)}}),this.decoder.configure(r)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(y(this.decoder),this.decoder.decodeQueueSize)}decode(e){this.customDecoder?(this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--)):(y(this.decoder),this.decoder.decode(e.toEncodedAudioChunk()))}flush(){return this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(y(this.decoder),this.decoder.flush())}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(y(this.decoder),this.decoder.close())}}class sa extends Ys{constructor(e,t,i){super(e,t),this.decoderConfig=i,this.currentTimestamp=null,y(De.includes(i.codec)),this.codec=i.codec;const{dataType:r,sampleSize:n,littleEndian:s}=He(this.codec);switch(this.inputSampleSize=n,n){case 1:"unsigned"===r?this.readInputValue=(e,t)=>e.getUint8(t)-o(2,7):"signed"===r?this.readInputValue=(e,t)=>e.getInt8(t):"ulaw"===r?this.readInputValue=(e,t)=>(e=>{let t=0,i=0,r=~e;128&r&&(r&=-129,t=-1),i=5+((240&r)>>4);const n=(1<(e=>{let t=0,i=0,r=85^e;128&r&&(r&=-129,t=-1),i=4+((240&r)>>4);let n=0;return n=4!==i?1<e.getUint16(t,s)-o(2,15):"signed"===r?this.readInputValue=(e,t)=>e.getInt16(t,s):y(!1);break;case 3:"unsigned"===r?this.readInputValue=(e,t)=>K(e,t,s)-o(2,23):"signed"===r?this.readInputValue=(e,t)=>((e,t,i)=>K(e,t,i)<<8>>8)(e,t,s):y(!1);break;case 4:"unsigned"===r?this.readInputValue=(e,t)=>e.getUint32(t,s)-o(2,31):"signed"===r?this.readInputValue=(e,t)=>e.getInt32(t,s):"float"===r?this.readInputValue=(e,t)=>e.getFloat32(t,s):y(!1);break;case 8:"float"===r?this.readInputValue=(e,t)=>e.getFloat64(t,s):y(!1);break;default:H(n),y(!1)}switch(n){case 1:"ulaw"===r||"alaw"===r?(this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,i)=>e.setInt16(t,i,!0)):(this.outputSampleSize=1,this.outputFormat="u8",this.writeOutputValue=(e,t,i)=>e.setUint8(t,i+o(2,7)));break;case 2:this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,i)=>e.setInt16(t,i,!0);break;case 3:this.outputSampleSize=4,this.outputFormat="s32",this.writeOutputValue=(e,t,i)=>e.setInt32(t,i<<8,!0);break;case 4:this.outputSampleSize=4,"float"===r?(this.outputFormat="f32",this.writeOutputValue=(e,t,i)=>e.setFloat32(t,i,!0)):(this.outputFormat="s32",this.writeOutputValue=(e,t,i)=>e.setInt32(t,i,!0));break;case 8:this.outputSampleSize=4,this.outputFormat="f32",this.writeOutputValue=(e,t,i)=>e.setFloat32(t,i,!0);break;default:H(n),y(!1)}}getDecodeQueueSize(){return 0}decode(e){const t=P(e.data),i=e.byteLength/this.decoderConfig.numberOfChannels/this.inputSampleSize,r=i*this.decoderConfig.numberOfChannels*this.outputSampleSize,n=new ArrayBuffer(r),s=new DataView(n);for(let c=0;c=a)&&(this.currentTimestamp=e.timestamp);const o=this.currentTimestamp;this.currentTimestamp+=a;const l=new Ls({format:this.outputFormat,data:n,numberOfChannels:this.decoderConfig.numberOfChannels,sampleRate:this.decoderConfig.sampleRate,numberOfFrames:i,timestamp:o});this.onSample(l)}flush(){return d(this,null,function*(){})}close(){}}class aa extends Js{constructor(e){if(!(e instanceof ha))throw new TypeError("audioTrack must be an InputAudioTrack.");super(),this._track=e}_createDecoder(e,t){return d(this,null,function*(){if(!(yield this._track.canDecode()))throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track.");const i=yield this._track.getCodec(),r=yield this._track.getDecoderConfig();return y(i&&r),De.includes(r.codec)?new sa(e,t,r):new na(e,t,i,r)})}_createPacketSink(){return new Gs(this._track)}getSample(e){return d(this,arguments,function*(e,t={}){$s(e);try{for(var i,r,n,s=p(this.mediaSamplesAtTimestamps([e],t));i=!(r=yield s.next()).done;i=!1){return r.value}}catch(r){n=[r]}finally{try{i&&(r=s.return)&&(yield r.call(s))}finally{if(n)throw n[0]}}throw new Error("Internal error: Iterator returned nothing.")})}samples(e=0,t=1/0,i={}){return this.mediaSamplesInRange(e,t,i)}samplesAtTimestamps(e,t={}){return this.mediaSamplesAtTimestamps(e,t)}}class oa{constructor(e){if(!(e instanceof ha))throw new TypeError("audioTrack must be an InputAudioTrack.");this._audioSampleSink=new aa(e)}_audioSampleToWrappedArrayBuffer(e){const t={buffer:e.toAudioBuffer(),timestamp:e.timestamp,duration:e.duration};return e.close(),t}getBuffer(e,t){return d(this,null,function*(){$s(e);const i=yield this._audioSampleSink.getSample(e,t);return i&&this._audioSampleToWrappedArrayBuffer(i)})}buffers(e=0,t=1/0,i){return X(this._audioSampleSink.samples(e,t,i),e=>this._audioSampleToWrappedArrayBuffer(e))}buffersAtTimestamps(e,t){return X(this._audioSampleSink.samplesAtTimestamps(e,t),e=>e&&this._audioSampleToWrappedArrayBuffer(e))}}class la{constructor(e,t){this.input=e,this._backing=t}isVideoTrack(){return this instanceof da}isAudioTrack(){return this instanceof ha}get id(){return this._backing.getId()}get number(){return this._backing.getNumber()}getInternalCodecId(){return d(this,null,function*(){return this._backing.getInternalCodecId()})}get internalCodecId(){return ca(this._backing.getInternalCodecId(),"internalCodecId","getInternalCodecId")}getLanguageCode(){return d(this,null,function*(){return this._backing.getLanguageCode()})}get languageCode(){return ca(this._backing.getLanguageCode(),"languageCode","getLanguageCode")}getName(){return d(this,null,function*(){return this._backing.getName()})}get name(){return ca(this._backing.getName(),"name","getName")}getTimeResolution(){return d(this,null,function*(){return this._backing.getTimeResolution()})}get timeResolution(){return ca(this._backing.getTimeResolution(),"timeResolution","getTimeResolution")}isRelativeToUnixEpoch(){return d(this,null,function*(){return this._backing.isRelativeToUnixEpoch()})}getDisposition(){return d(this,null,function*(){return this._backing.getDisposition()})}get disposition(){return ca(this._backing.getDisposition(),"disposition","getDisposition")}getBitrate(){return d(this,null,function*(){return this._backing.getBitrate()})}getAverageBitrate(){return d(this,null,function*(){return this._backing.getAverageBitrate()})}getFirstTimestamp(){return d(this,null,function*(){var e;const t=yield this._backing.getFirstPacket({metadataOnly:!0});return null!=(e=null==t?void 0:t.timestamp)?e:0})}computeDuration(e){return d(this,null,function*(){var t,i;const r=yield this._backing.getPacket(1/0,c({metadataOnly:!0},e)),n=(null!=(t=null==r?void 0:r.timestamp)?t:0)+(null!=(i=null==r?void 0:r.duration)?i:0);return Y(n,yield this.getTimeResolution())})}getDurationFromMetadata(){return d(this,arguments,function*(e={}){return this._backing.getDurationFromMetadata(e)})}computePacketStats(e=1/0,t){return d(this,null,function*(){const i=new Gs(this);let r=1/0,n=-1/0,s=0,a=0;try{for(var o,l,u,d=p(i.packets(void 0,void 0,c({metadataOnly:!0},t)));o=!(l=yield d.next()).done;o=!1){const t=l.value;if(s>=e&&t.timestamp>=n)break;r=Math.min(r,t.timestamp),n=Math.max(n,t.timestamp+t.duration),s++,a+=t.byteLength}}catch(l){u=[l]}finally{try{o&&(l=d.return)&&(yield l.call(d))}finally{if(u)throw u[0]}}return{packetCount:s,averagePacketRate:s?Number((s/(n-r)).toPrecision(16)):0,averageBitrate:s?Number((8*a/(n-r)).toPrecision(16)):0}})}isLive(){return d(this,null,function*(){return null!==(yield this._backing.getLiveRefreshInterval())})}getLiveRefreshInterval(){return d(this,null,function*(){return this._backing.getLiveRefreshInterval()})}canBePairedWith(e){if(!(e instanceof la))throw new TypeError("other must be an InputTrack.");return this.input===e.input&&this!==e&&(this._backing.getPairingMask()&e._backing.getPairingMask())!==BigInt("0")}getPairableTracks(e){return d(this,null,function*(){return this.input.getTracks(ga({filter:e=>e.canBePairedWith(this)},e))})}getPairableVideoTracks(e){return d(this,null,function*(){return this.input.getVideoTracks(ga({filter:e=>e.canBePairedWith(this)},e))})}getPairableAudioTracks(e){return d(this,null,function*(){return this.input.getAudioTracks(ga({filter:e=>e.canBePairedWith(this)},e))})}getPrimaryPairableVideoTrack(e){return d(this,null,function*(){return this.input.getPrimaryVideoTrack(ga({filter:e=>e.canBePairedWith(this)},e))})}getPrimaryPairableAudioTrack(e){return d(this,null,function*(){return this.input.getPrimaryAudioTrack(ga({filter:e=>e.canBePairedWith(this)},e))})}hasPairableTrack(e){return d(this,null,function*(){e&&(e=ua(e));const t=yield this.input.getTracks();for(const i of t)if(this.canBePairedWith(i)&&(!e||(yield e(i))))return!0;return!1})}hasPairableVideoTrack(e){return e&&(e=ua(e)),this.hasPairableTrack(t=>d(this,null,function*(){return t.isVideoTrack()&&(!e||(yield e(t)))}))}hasPairableAudioTrack(e){return e&&(e=ua(e)),this.hasPairableTrack(t=>d(this,null,function*(){return t.isAudioTrack()&&(!e||(yield e(t)))}))}}const ca=(e,t,i)=>{if(e instanceof Promise)throw new Error(`'${t}' is deprecated and not available synchronously for this track. Use the preferred '${i}()' instead.`);return e},ua=e=>{if(void 0!==e&&"function"!==typeof e)throw new TypeError("predicate, when provided, must be a function.");return e?t=>{const i=e=>{if("boolean"!==typeof e)throw new TypeError("predicate must return or resolve to a boolean value.");return e},r=e(t);return r instanceof Promise?r.then(i):i(r)}:void 0};class da extends la{constructor(e,t){super(e,t),this._pixelAspectRatioCache=null,this._backing=t}get type(){return"video"}getCodec(){return d(this,null,function*(){return this._backing.getCodec()})}get codec(){return ca(this._backing.getCodec(),"codec","getCodec")}hasOnlyKeyPackets(){return d(this,null,function*(){var e,t,i;return null!=(i=yield null==(t=(e=this._backing).getHasOnlyKeyPackets)?void 0:t.call(e))&&i})}getCodedWidth(){return d(this,null,function*(){return this._backing.getCodedWidth()})}get codedWidth(){return ca(this._backing.getCodedWidth(),"codedWidth","getCodedWidth")}getCodedHeight(){return d(this,null,function*(){return this._backing.getCodedHeight()})}get codedHeight(){return ca(this._backing.getCodedHeight(),"codedHeight","getCodedHeight")}getRotation(){return d(this,null,function*(){return this._backing.getRotation()})}get rotation(){return ca(this._backing.getRotation(),"rotation","getRotation")}getSquarePixelWidth(){return d(this,null,function*(){return this._backing.getSquarePixelWidth()})}get squarePixelWidth(){return ca(this._backing.getSquarePixelWidth(),"squarePixelWidth","getSquarePixelWidth")}getSquarePixelHeight(){return d(this,null,function*(){return this._backing.getSquarePixelHeight()})}get squarePixelHeight(){return ca(this._backing.getSquarePixelHeight(),"squarePixelHeight","getSquarePixelHeight")}getPixelAspectRatio(){return d(this,null,function*(){var e;return null!=(e=this._pixelAspectRatioCache)?e:this._pixelAspectRatioCache=ve({num:(yield this.getSquarePixelWidth())*(yield this.getCodedHeight()),den:(yield this.getSquarePixelHeight())*(yield this.getCodedWidth())})})}get pixelAspectRatio(){var e;return null!=(e=this._pixelAspectRatioCache)?e:this._pixelAspectRatioCache=ve({num:ca(this._backing.getSquarePixelWidth(),"pixelAspectRatio","getPixelAspectRatio")*ca(this._backing.getCodedHeight(),"pixelAspectRatio","getPixelAspectRatio"),den:ca(this._backing.getSquarePixelHeight(),"pixelAspectRatio","getPixelAspectRatio")*ca(this._backing.getCodedWidth(),"pixelAspectRatio","getPixelAspectRatio")})}getDisplayWidth(){return d(this,null,function*(){var e,t;const i=yield null==(t=(e=this._backing).getMetadataDisplayWidth)?void 0:t.call(e);if(null!=i)return i;return(yield this.getRotation())%180===0?this.getSquarePixelWidth():this.getSquarePixelHeight()})}get displayWidth(){var e,t;const i=null==(t=(e=this._backing).getMetadataDisplayWidth)?void 0:t.call(e);if(void 0!==i){const e=ca(i,"displayWidth","getDisplayWidth");if(null!==e)return e}const r=ca(this._backing.getRotation(),"displayWidth","getDisplayWidth")%180===0?this._backing.getSquarePixelWidth():this._backing.getSquarePixelHeight();return ca(r,"displayWidth","getDisplayWidth")}getDisplayHeight(){return d(this,null,function*(){var e,t;const i=yield null==(t=(e=this._backing).getMetadataDisplayHeight)?void 0:t.call(e);if(null!=i)return i;return(yield this.getRotation())%180===0?this.getSquarePixelHeight():this.getSquarePixelWidth()})}get displayHeight(){var e,t;const i=null==(t=(e=this._backing).getMetadataDisplayHeight)?void 0:t.call(e);if(void 0!==i){const e=ca(i,"displayHeight","getDisplayHeight");if(null!==e)return e}const r=ca(this._backing.getRotation(),"displayHeight","getDisplayHeight")%180===0?this._backing.getSquarePixelHeight():this._backing.getSquarePixelWidth();return ca(r,"displayHeight","getDisplayHeight")}getColorSpace(){return d(this,null,function*(){return this._backing.getColorSpace()})}hasHighDynamicRange(){return d(this,null,function*(){const e=yield this._backing.getColorSpace();return"bt2020"===e.primaries||"smpte432"===e.primaries||"pg"===e.transfer||"hlg"===e.transfer||"bt2020-ncl"===e.matrix})}canBeTransparent(){return d(this,null,function*(){return this._backing.canBeTransparent()})}getDecoderConfig(){return d(this,null,function*(){return this._backing.getDecoderConfig()})}getCodecParameterString(){return d(this,null,function*(){var e,t,i;const r=yield null==(t=(e=this._backing).getMetadataCodecParameterString)?void 0:t.call(e);if(null!=r)return r;const n=yield this._backing.getDecoderConfig();return null!=(i=null==n?void 0:n.codec)?i:null})}canDecode(){return d(this,null,function*(){try{const e=yield this._backing.getDecoderConfig();if(!e)return!1;const t=yield this._backing.getCodec();if(y(null!==t),Ks.some(i=>i.supports(t,e)))return!0;if("undefined"===typeof VideoDecoder)return!1;return!0===(yield VideoDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}})}determinePacketType(e){return d(this,null,function*(){if(!(e instanceof Yt))throw new TypeError("packet must be an EncodedPacket.");if(e.isMetadataOnly)throw new TypeError("packet must not be metadata-only to determine its type.");const t=yield this.getCodec();if(null===t)return null;const i=yield this.getDecoderConfig();return y(i),Lt(t,i,e.data)})}}class ha extends la{constructor(e,t){super(e,t),this._backing=t}get type(){return"audio"}getCodec(){return d(this,null,function*(){return this._backing.getCodec()})}get codec(){return ca(this._backing.getCodec(),"codec","getCodec")}hasOnlyKeyPackets(){return d(this,null,function*(){var e,t,i;return null==(i=yield null==(t=(e=this._backing).getHasOnlyKeyPackets)?void 0:t.call(e))||i})}getNumberOfChannels(){return d(this,null,function*(){return this._backing.getNumberOfChannels()})}get numberOfChannels(){return ca(this._backing.getNumberOfChannels(),"numberOfChannels","getNumberOfChannels")}getSampleRate(){return d(this,null,function*(){return this._backing.getSampleRate()})}get sampleRate(){return ca(this._backing.getSampleRate(),"sampleRate","getSampleRate")}getDecoderConfig(){return d(this,null,function*(){return this._backing.getDecoderConfig()})}getCodecParameterString(){return d(this,null,function*(){var e,t,i;const r=yield null==(t=(e=this._backing).getMetadataCodecParameterString)?void 0:t.call(e);if(null!=r)return r;const n=yield this._backing.getDecoderConfig();return null!=(i=null==n?void 0:n.codec)?i:null})}canDecode(){return d(this,null,function*(){try{const e=yield this._backing.getDecoderConfig();if(!e)return!1;const t=yield this._backing.getCodec();if(y(null!==t),js.some(i=>i.supports(t,e)))return!0;if(e.codec.startsWith("pcm-"))return!0;if("undefined"===typeof AudioDecoder)return!1;return!0===(yield AudioDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}})}determinePacketType(e){return d(this,null,function*(){if(!(e instanceof Yt))throw new TypeError("packet must be an EncodedPacket.");return null===(yield this.getCodec())?null:"key"})}}const fa=e=>-(null!=e?e:-1/0),ma=e=>-e,pa=e=>{if("object"!==typeof e||!e)throw new TypeError("query must be an object.");if(void 0!==e.filter&&"function"!==typeof e.filter)throw new TypeError("query.filter, when provided, must be a function.");if(void 0!==e.sortBy&&"function"!==typeof e.sortBy)throw new TypeError("query.sortBy, when provided, must be a function.");return{filter:e.filter?t=>{const i=e=>{if("boolean"!==typeof e)throw new TypeError("query.filter must return or resolve to a boolean.");return e},r=e.filter(t);return r instanceof Promise?r.then(i):i(r)}:void 0,sortBy:e.sortBy?t=>{const i=e=>{if("number"!==typeof e&&(!Array.isArray(e)||!e.every(e=>"number"===typeof e)))throw new TypeError("query.sortBy must return or resolve to a number or an array of numbers.");return e},r=e.sortBy(t);return r instanceof Promise?r.then(i):i(r)}:void 0}},ga=(e,t)=>({filter:(null==e?void 0:e.filter)||(null==t?void 0:t.filter)?i=>{var r,n;const s=null==(n=null==(r=null==e?void 0:e.filter)?void 0:r.call(e,i))||n,a=e=>{var r,n;return!1!==e&&(null==(n=null==(r=null==t?void 0:t.filter)?void 0:r.call(t,i))||n)};return s instanceof Promise?s.then(a):a(s)}:void 0,sortBy:(null==e?void 0:e.sortBy)||(null==t?void 0:t.sortBy)?i=>{var r,n,s,a;const o=null!=(n=null==(r=null==e?void 0:e.sortBy)?void 0:r.call(e,i))?n:[],l=null!=(a=null==(s=null==t?void 0:t.sortBy)?void 0:s.call(t,i))?a:[],c=(e,t)=>[...Array.isArray(e)?e:[e],...Array.isArray(t)?t:[t]];return o instanceof Promise||l instanceof Promise?Promise.all([o,l]).then(([e,t])=>c(e,t)):c(o,l)}:void 0}),ka=(e,t)=>d(null,null,function*(){let i=e;if(null==t?void 0:t.filter){const r=e.map(e=>t.filter(e));if(r.some(e=>e instanceof Promise)){const t=yield Promise.all(r);i=e.filter((e,i)=>t[i])}else i=e.filter((e,t)=>r[t])}if(!(null==t?void 0:t.sortBy))return i;const r=i.map(e=>t.sortBy(e)),n=r.some(e=>e instanceof Promise)?yield Promise.all(r):r;return i.map((e,t)=>({track:e,sortValue:n[t]})).sort((e,t)=>{var i,r;const n=Array.isArray(e.sortValue)?e.sortValue:[e.sortValue],s=Array.isArray(t.sortValue)?t.sortValue:[t.sortValue],a=Math.max(n.length,s.length);for(let o=0;oe.track)});ke();const ya=2;let ba=null;"undefined"!==typeof FinalizationRegistry&&(ba=new FinalizationRegistry(e=>{for(const t of e)t.freed||t.free()}));class Ta extends Ie{get disposed(){return this._disposed}constructor(e){var t,i;if(super(),this._demuxerPromise=null,this._format=null,this._trackBackingsCache=null,this._backingToTrack=new Map,this._disposed=!1,this._nextSourceCacheAge=0,this._sourceRefs=[],this._sourceCache=[],this._sourceCachePromises=[],this._onFormatDetermined=null,!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(!Array.isArray(e.formats)||e.formats.some(e=>!(e instanceof Jn)))throw new TypeError("options.formats must be an array of InputFormat.");if(!(e.source instanceof xn||e.source instanceof Cn))throw new TypeError("options.source must be a Source or SourceRef.");if(e.source instanceof xn&&e.source._disposed)throw new TypeError("options.source must not be a disposed Source.");if(void 0!==e.initInput&&!(e.initInput instanceof Ta))throw new TypeError("options.initInput, when provided, must be an Input.");void 0!==e.formatOptions&&((e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(`${t}, when provided, must be an object.`);if(void 0!==e.isobmff){if(!e.isobmff||"object"!==typeof e.isobmff)throw new TypeError(`${t}.isobmff, when provided, must be an object.`);if(void 0!==e.isobmff.resolveKeyId&&"function"!==typeof e.isobmff.resolveKeyId)throw new TypeError(`${t}.isobmff.resolveKeyId, when provided, must be a function.`)}})(e.formatOptions,"formatOptions"),this._formats=e.formats,this._initInput=null!=(t=e.initInput)?t:null,this._formatOptions=null!=(i=e.formatOptions)?i:{},e.source instanceof xn?this._rootRef=e.source.ref():this._rootRef=e.source,this._sourceRefs.push(this._rootRef),null==ba||ba.register(this,this._sourceRefs,this)}get _rootSource(){return this._rootRef.source}_getSourceUncached(e){return d(this,null,function*(){y(this._rootSource instanceof Bn);const t=yield this._rootSource._resolveRequest(e);return this._emit("source",{source:t.source,request:e,isRoot:e.isRoot}),t})}_getSourceCached(e,t=1){const i=this._sourceCache.find(i=>i.cacheGroup===t&&En(i.request,e));if(i)return i.age++,Promise.resolve(i.sourceRef.source.ref());const r=this._sourceCachePromises.find(i=>i.cacheGroup===t&&En(i.request,e));if(r)return r.promise.then(e=>e.sourceRef.source.ref());const n=(()=>d(this,null,function*(){const i=yield this._getSourceUncached(e);if(Te(this._sourceCache,e=>e.cacheGroup===t&&1===e.sourceRef.source._refCount)>=4){const e=Se(this._sourceCache,e=>e.cacheGroup===t&&1===e.sourceRef.source._refCount?e.age:1/0);y(-1!==e);const i=this._sourceCache[e];this._sourceCache.splice(e,1),i.sourceRef.free(),((e,t)=>{const i=e.indexOf(t);-1!==i&&e.splice(i,1)})(this._sourceRefs,i.sourceRef)}this._sourceRefs.push(i);const r=this._sourceCachePromises.findIndex(t=>t.request===e);y(-1!==r),this._sourceCachePromises.splice(r,1);return{request:e,sourceRef:i,age:this._nextSourceCacheAge++,cacheGroup:t}}))();return this._sourceCachePromises.push({request:e,cacheGroup:t,promise:n}),n.then(e=>{const t=e.sourceRef.source.ref();return this._sourceCache.push(e),t})}_getDemuxer(){var e;return null!=(e=this._demuxerPromise)?e:this._demuxerPromise=(()=>d(this,null,function*(){var e;this._reader=new wa(this._rootSource),this._emit("source",{source:this._rootSource,request:null,isRoot:!0});for(const t of this._formats){if(yield t._canReadInput(this))return this._format=t,null==(e=this._onFormatDetermined)||e.call(this,t),t._createDemuxer(this)}throw new Sa}))()}get source(){return this._rootSource}getFormat(){return d(this,null,function*(){return yield this._getDemuxer(),y(this._format),this._format})}canRead(){return d(this,null,function*(){try{return yield this._getDemuxer(),!0}catch(e){if(e instanceof Sa)return!1;throw e}})}getFirstTimestamp(e){return d(this,null,function*(){null!=e||(e=yield this.getTracks());const t=e.filter(e=>null!==e);if(0===t.length)return 0;const i=yield Promise.all(t.map(e=>e.getFirstTimestamp()));return Math.min(...i)})}computeDuration(e,t){return d(this,null,function*(){null!=e||(e=yield this.getTracks());const i=e.filter(e=>null!==e);if(0===i.length)return 0;const r=yield Promise.all(i.map(e=>e.computeDuration(t)));return Math.max(...r)})}getDurationFromMetadata(e,t){return d(this,null,function*(){null!=e||(e=yield this.getTracks());const i=e.filter(e=>null!==e),r=(yield Promise.all(i.map(e=>e.getDurationFromMetadata(t)))).filter(e=>null!==e);return 0===r.length?null:Math.max(...r)})}getTracks(e){return d(this,null,function*(){e&&(e=pa(e));const t=(yield this._getTrackBackings()).map(e=>this._wrapBackingAsTrack(e));return ka(t,e)})}getVideoTracks(e){return d(this,null,function*(){e&&(e=pa(e));const t=(yield this.getTracks()).filter(e=>e.isVideoTrack());return ka(t,e)})}getAudioTracks(e){return d(this,null,function*(){e&&(e=pa(e));const t=(yield this.getTracks()).filter(e=>e.isAudioTrack());return ka(t,e)})}getPrimaryVideoTrack(e){return d(this,null,function*(){var t;e&&(e=pa(e));const i=ga(e,{sortBy:e=>d(null,null,function*(){return[ma((yield e.getDisposition()).default),ma(yield e.hasPairableAudioTrack()),ma(!(yield e.hasOnlyKeyPackets())),fa(yield e.getBitrate())]})});return null!=(t=(yield this.getVideoTracks(i))[0])?t:null})}getPrimaryAudioTrack(e){return d(this,null,function*(){var t;e&&(e=pa(e));const i=yield this.getPrimaryVideoTrack(),r=ga(e,{sortBy:e=>d(this,null,function*(){return[ma(!i||e.canBePairedWith(i)),ma((yield e.getDisposition()).default),fa(yield e.getBitrate())]})});return null!=(t=(yield this.getAudioTracks(r))[0])?t:null})}_getTrackBackings(){return d(this,null,function*(){var e;const t=yield this._getDemuxer();return null!=(e=this._trackBackingsCache)?e:this._trackBackingsCache=yield t.getTrackBackings()})}_wrapBackingAsTrack(e){const t=this._backingToTrack.get(e);if(t)return t;const i="video"===e.getType()?new da(this,e):new ha(this,e);return this._backingToTrack.set(e,i),i}getMimeType(){return d(this,null,function*(){return(yield this._getDemuxer()).getMimeType()})}getMetadataTags(){return d(this,null,function*(){return(yield this._getDemuxer()).getMetadataTags()})}dispose(){var e;if(!this._disposed){this._disposed=!0;for(const e of this._sourceRefs)e.free();this._sourceRefs.length=0,null==ba||ba.unregister(this),null==(e=this._demuxerPromise)||e.then(e=>e.dispose())}}[Symbol.dispose](){this.dispose()}}class Sa extends Error{constructor(e="Input has an unsupported or unrecognizable format."){super(e),this.name="UnsupportedInputFormatError"}}class va extends Error{constructor(e="Input has been disposed."){super(e),this.name="InputDisposedError"}}class wa{constructor(e){this.source=e}get fileSize(){const e=this.source._getFileSize();if(void 0===e)throw new Error("Reading file size too early; read required first.");return e}get fileSizeNonStrict(){var e;return null!=(e=this.source._getFileSize())?e:null}requestSlice(e,t){if(this.source._disposed)throw new va;if(e<0)return null;if(null!==this.fileSizeNonStrict&&e+t>this.fileSizeNonStrict)return null;if(0===t){const t=new Uint8Array(0);return new Pa(t,P(t),0,e,e)}const i=e+t,r=this.source._read(e,i,0,In);return r instanceof Promise?r.then(t=>t?new Pa(t.bytes,t.view,t.offset,e,i):null):r?new Pa(r.bytes,r.view,r.offset,e,i):null}requestSliceRange(e,t,i){if(this.source._disposed)throw new va;if(e<0)return null;if(null!==this.fileSizeNonStrict)return this.requestSlice(e,$(this.fileSizeNonStrict-e,t,i));{const r=this.requestSlice(e,i),n=r=>r||(y(null!==this.fileSizeNonStrict),this.requestSlice(e,$(this.fileSizeNonStrict-e,t,i)));return r instanceof Promise?r.then(n):n(r)}}requestEntireFile(){if(null!==this.fileSizeNonStrict)return this.requestSlice(0,this.fileSizeNonStrict);return(()=>d(this,null,function*(){const e=[];let t=0;for(;;){if(1===e.length&&null!==this.fileSizeNonStrict)return this.requestSlice(0,this.fileSizeNonStrict);const i=1024*e.length;let r=this.requestSliceRange(i,0,1024);if(r instanceof Promise&&(r=yield r),!r)break;e.push(xa(r,r.length)),t+=r.length}const i=new Uint8Array(t);let r=0;for(const n of e)i.set(n,r),r+=n.length;return new Pa(i,P(i),0,0,t)}))()}}class Pa{constructor(e,t,i,r,n){this.bytes=e,this.view=t,this.offset=i,this.start=r,this.end=n,this.bufferPos=r-i}static tempFromBytes(e){return new Pa(e,P(e),0,0,e.length)}get length(){return this.end-this.start}get filePos(){return this.offset+this.bufferPos}set filePos(e){this.bufferPos=e-this.offset}get remainingLength(){return Math.max(this.end-this.filePos,0)}skip(e){this.bufferPos+=e}slice(e,t=this.end-e){if(ethis.end)throw new RangeError("Slicing outside of original slice.");return new Pa(this.bytes,this.view,this.offset,e,e+t)}}const Ia=(e,t)=>{if(e.filePose.end)throw new RangeError(`Tried reading [${e.filePos}, ${e.filePos+t}), but slice is [${e.start}, ${e.end}). This is likely an internal error, please report it alongside the file that caused it.`)},xa=(e,t)=>{Ia(e,t);const i=e.bytes.subarray(e.bufferPos,e.bufferPos+t);return e.bufferPos+=t,i},Ca=e=>(Ia(e,1),e.view.getUint8(e.bufferPos++)),Ba=(e,t)=>{Ia(e,2);const i=e.view.getUint16(e.bufferPos,t);return e.bufferPos+=2,i},Ea=e=>{Ia(e,2);const t=e.view.getUint16(e.bufferPos,!1);return e.bufferPos+=2,t},_a=e=>{Ia(e,3);const t=K(e.view,e.bufferPos,!1);return e.bufferPos+=3,t},Aa=e=>{Ia(e,2);const t=e.view.getInt16(e.bufferPos,!1);return e.bufferPos+=2,t},Fa=(e,t)=>{Ia(e,4);const i=e.view.getUint32(e.bufferPos,t);return e.bufferPos+=4,i},Ra=e=>{Ia(e,4);const t=e.view.getUint32(e.bufferPos,!1);return e.bufferPos+=4,t},Da=e=>{Ia(e,4);const t=e.view.getUint32(e.bufferPos,!0);return e.bufferPos+=4,t},Ma=e=>{Ia(e,4);const t=e.view.getInt32(e.bufferPos,!1);return e.bufferPos+=4,t},Na=(e,t)=>{let i,r;return t?(i=Fa(e,!0),r=Fa(e,!0)):(r=Fa(e,!1),i=Fa(e,!1)),4294967296*r+i},Oa=e=>4294967296*Ra(e)+Ra(e),La=e=>4294967296*Ma(e)+Ra(e),za=e=>{const t=Da(e),i=(e=>{Ia(e,4);const t=e.view.getInt32(e.bufferPos,!0);return e.bufferPos+=4,t})(e);return 4294967296*i+t},Ua=e=>{Ia(e,4);const t=e.view.getFloat32(e.bufferPos,!1);return e.bufferPos+=4,t},qa=e=>{Ia(e,8);const t=e.view.getFloat64(e.bufferPos,!1);return e.bufferPos+=8,t},Wa=(e,t)=>{Ia(e,t);let i="";for(let r=0;rI.decode(xa(e,t)).split("\n").map(e=>e.trim()).filter(e=>{var t;return e.length>0&&!(null==(t=null==i?void 0:i.ignore)?void 0:t.call(i,e))});var Ha,Ka,ja,Xa;(Ka=Ha||(Ha={}))[Ka.Unsynchronisation=128]="Unsynchronisation",Ka[Ka.ExtendedHeader=64]="ExtendedHeader",Ka[Ka.ExperimentalIndicator=32]="ExperimentalIndicator",Ka[Ka.Footer=16]="Footer",(Xa=ja||(ja={}))[Xa.ISO_8859_1=0]="ISO_8859_1",Xa[Xa.UTF_16_WITH_BOM=1]="UTF_16_WITH_BOM",Xa[Xa.UTF_16_BE_NO_BOM=2]="UTF_16_BE_NO_BOM",Xa[Xa.UTF_8=3]="UTF_8";const $a=128,Qa=10,Ga=["Blues","Classic rock","Country","Dance","Disco","Funk","Grunge","Hip-hop","Jazz","Metal","New age","Oldies","Other","Pop","Rhythm and blues","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death metal","Pranks","Soundtrack","Euro-techno","Ambient","Trip-hop","Vocal","Jazz & funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound clip","Gospel","Noise","Alternative rock","Bass","Soul","Punk","Space","Meditative","Instrumental pop","Instrumental rock","Ethnic","Gothic","Darkwave","Techno-industrial","Electronic","Pop-folk","Eurodance","Dream","Southern rock","Comedy","Cult","Gangsta","Top 40","Christian rap","Pop/funk","Jungle music","Native US","Cabaret","New wave","Psychedelic","Rave","Showtunes","Trailer","Lo-fi","Tribal","Acid punk","Acid jazz","Polka","Retro","Musical","Rock 'n' roll","Hard rock","Folk","Folk rock","National folk","Swing","Fast fusion","Bebop","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic rock","Progressive rock","Psychedelic rock","Symphonic rock","Slow rock","Big band","Chorus","Easy listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber music","Sonata","Symphony","Booty bass","Primus","Porn groove","Satire","Slow jam","Club","Tango","Samba","Folklore","Ballad","Power ballad","Rhythmic Soul","Freestyle","Duet","Punk rock","Drum solo","A cappella","Euro-house","Dance hall","Goa music","Drum & bass","Club-house","Hardcore techno","Terror","Indie","Britpop","Negerpunk","Polsk punk","Beat","Christian gangsta rap","Heavy metal","Black metal","Crossover","Contemporary Christian","Christian rock","Merengue","Salsa","Thrash metal","Anime","Jpop","Synthpop","Christmas","Art rock","Baroque","Bhangra","Big beat","Breakbeat","Chillout","Downtempo","Dub","EBM","Eclectic","Electro","Electroclash","Emo","Experimental","Garage","Global","IDM","Illbient","Industro-Goth","Jam Band","Krautrock","Leftfield","Lounge","Math rock","New romantic","Nu-breakz","Post-punk","Post-rock","Psytrance","Shoegaze","Space rock","Trop rock","World music","Neoclassical","Audiobook","Audio theatre","Neue Deutsche Welle","Podcast","Indie rock","G-Funk","Dubstep","Garage rock","Psybient"],Ya=(e,t)=>{var i;const r=e.filePos;null!=t.raw||(t.raw={}),null!=(i=t.raw).TAG||(i.TAG=xa(e,$a-3)),e.filePos=r;const n=Ja(e,30);n&&(null!=t.title||(t.title=n));const s=Ja(e,30);s&&(null!=t.artist||(t.artist=s));const a=Ja(e,30);a&&(null!=t.album||(t.album=a));const o=Ja(e,4),l=Number.parseInt(o,10);Number.isInteger(l)&&l>0&&(null!=t.date||(t.date=new Date(l,0,1)));const c=xa(e,30);let u;if(0===c[28]&&0!==c[29]){const i=c[29];i>0&&(null!=t.trackNumber||(t.trackNumber=i)),e.skip(-30),u=Ja(e,28),e.skip(2)}else e.skip(-30),u=Ja(e,30);u&&(null!=t.comment||(t.comment=u));const d=Ca(e);d{const i=xa(e,t),r=me(i.indexOf(0),i.length),n=i.subarray(0,r);let s="";for(let a=0;a{const t=e.filePos,i=Wa(e,3),r=Ca(e),n=Ca(e),s=Ca(e),a=Ra(e);if("ID3"!==i||255===r||255===n||0!==(2155905152&a))return e.filePos=t,null;return{majorVersion:r,revision:n,flags:s,size:Je(a)}},eo=(e,t,i)=>{var r,n,s,a,o,l;if(![2,3,4].includes(t.majorVersion))return void console.warn(`Unsupported ID3v2 major version: ${t.majorVersion}`);const c=xa(e,t.size),u=new to(t,c);if(t.flags&Ha.Footer&&u.removeFooter(),t.flags&Ha.Unsynchronisation&&3===t.majorVersion&&u.ununsynchronizeAll(),t.flags&Ha.ExtendedHeader){const e=u.readU32();3===t.majorVersion?u.pos+=e:u.pos+=e-4}for(;u.pos<=u.bytes.length-u.frameHeaderSize();){const e=u.readId3V2Frame();if(!e)break;const c=u.pos,d=u.pos+e.size;let h=!1,f=!1,m=!1;if(3===t.majorVersion?(h=!!(64&e.flags),f=!!(128&e.flags)):4===t.majorVersion&&(h=!!(4&e.flags),f=!!(8&e.flags),m=!!(2&e.flags)||!!(t.flags&Ha.Unsynchronisation)),h)console.warn(`Skipping encrypted ID3v2 frame ${e.id}`),u.pos=d;else if(f)console.warn(`Skipping compressed ID3v2 frame ${e.id}`),u.pos=d;else{if(m&&u.ununsynchronizeRegion(u.pos,d),null!=i.raw||(i.raw={}),"TXXX"===e.id){const e=null!=(n=(r=i.raw).TXXX)?n:r.TXXX={},t=u.readId3V2TextEncoding(),s=u.readId3V2Text(t,d),a=u.readId3V2Text(t,d);null!=e[s]||(e[s]=a)}else"T"===e.id[0]?null!=(s=i.raw)[a=e.id]||(s[a]=u.readId3V2EncodingAndText(d)):null!=(o=i.raw)[l=e.id]||(o[l]=u.readBytes(e.size));switch(u.pos=c,e.id){case"TIT2":case"TT2":null!=i.title||(i.title=u.readId3V2EncodingAndText(d));break;case"TIT3":case"TT3":null!=i.description||(i.description=u.readId3V2EncodingAndText(d));break;case"TPE1":case"TP1":null!=i.artist||(i.artist=u.readId3V2EncodingAndText(d));break;case"TALB":case"TAL":null!=i.album||(i.album=u.readId3V2EncodingAndText(d));break;case"TPE2":case"TP2":null!=i.albumArtist||(i.albumArtist=u.readId3V2EncodingAndText(d));break;case"TRCK":case"TRK":{const e=u.readId3V2EncodingAndText(d).split("/"),t=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(null!=i.trackNumber||(i.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&(null!=i.tracksTotal||(i.tracksTotal=r))}break;case"TPOS":case"TPA":{const e=u.readId3V2EncodingAndText(d).split("/"),t=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(null!=i.discNumber||(i.discNumber=t)),r&&Number.isInteger(r)&&r>0&&(null!=i.discsTotal||(i.discsTotal=r))}break;case"TCON":case"TCO":{const e=u.readId3V2EncodingAndText(d);let t=/^\((\d+)\)/.exec(e);if(t){const e=Number.parseInt(t[1]);if(void 0!==Ga[e]){null!=i.genre||(i.genre=Ga[e]);break}}if(t=/^\d+$/.exec(e),t){const e=Number.parseInt(t[0]);if(void 0!==Ga[e]){null!=i.genre||(i.genre=Ga[e]);break}}null!=i.genre||(i.genre=e)}break;case"TDRC":case"TDAT":{const e=u.readId3V2EncodingAndText(d),t=new Date(e);Number.isNaN(t.getTime())||null!=i.date||(i.date=t)}break;case"TYER":case"TYE":{const e=u.readId3V2EncodingAndText(d),t=Number.parseInt(e,10);Number.isInteger(t)&&(null!=i.date||(i.date=new Date(t,0,1)))}break;case"USLT":case"ULT":{const e=u.readU8();u.pos+=3,u.readId3V2Text(e,d),null!=i.lyrics||(i.lyrics=u.readId3V2Text(e,d))}break;case"COMM":case"COM":{const e=u.readU8();u.pos+=3,u.readId3V2Text(e,d),null!=i.comment||(i.comment=u.readId3V2Text(e,d))}break;case"APIC":case"PIC":{const e=u.readId3V2TextEncoding();let r;if(2===t.majorVersion){const e=u.readAscii(3);r="PNG"===e?"image/png":"JPG"===e?"image/jpeg":"image/*"}else r=u.readId3V2Text(e,d);const n=u.readU8(),s=u.readId3V2Text(e,d).trimEnd(),a=d-u.pos;if(a>=0){const e=u.readBytes(a);i.images||(i.images=[]),i.images.push({data:e,mimeType:r,kind:3===n?"coverFront":4===n?"coverBack":"unknown",description:s})}}break;default:u.pos+=e.size}u.pos=d}}};class to{constructor(e,t){this.header=e,this.bytes=t,this.pos=0,this.view=new DataView(t.buffer,t.byteOffset,t.byteLength)}frameHeaderSize(){return 2===this.header.majorVersion?6:10}ununsynchronizeAll(){const e=[];for(let t=0;t{const t=this.pos+e;if(t>this.bytes.length)return!1;if(t<=this.bytes.length-this.frameHeaderSize()){this.pos+=e;const t=this.readAscii(4);if("\0\0\0\0"!==t&&!/[0-9A-Z]{4}/.test(t))return!1}return!0};if(!s(i)){const e=4===this.header.majorVersion?t:Je(t);s(e)&&(i=e)}return this.pos=n,{id:e,size:i,flags:r}}}readId3V2TextEncoding(){const e=this.readU8();if(e>3)throw new Error(`Unsupported text encoding: ${e}`);return e}readId3V2Text(e,t){const i=this.pos,r=this.readBytes(t-this.pos);switch(e){case ja.ISO_8859_1:{let e="";for(let t=0;t0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(2,t))}if(254===r[0]&&255===r[1]){const e=new TextDecoder("utf-16be"),t=me(r.findIndex((e,t)=>0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(2,t))}{const e=me(r.findIndex(e=>0===e),r.length);return this.pos=i+Math.min(e+1,r.length),I.decode(r.subarray(0,e))}case ja.UTF_16_BE_NO_BOM:{const e=new TextDecoder("utf-16be"),t=me(r.findIndex((e,t)=>0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(0,t))}case ja.UTF_8:{const e=me(r.findIndex(e=>0===e),r.length);return this.pos=i+Math.min(e+1,r.length),I.decode(r.subarray(0,e))}}}readId3V2EncodingAndText(e){if(this.pos>=e)return"";const t=this.readId3V2TextEncoding();return this.readId3V2Text(t,e)}}class io{constructor(e){this.events=e,this.input=null,this.audioSink=null,this.audioIterator=null,this.audioContext=null,this.gainNode=null,this.audioContextStartTime=0,this.playbackTimeAtStart=0,this.latestScheduledEndTime=0,this.duration=Number.NaN,this.paused=!0,this.volume=.7,this.muted=!1,this.playbackRate=1,this.asyncId=0,this.queuedNodes=new Set}get currentTime(){return this.paused?this.playbackTimeAtStart:(this.audioContext.currentTime-this.audioContextStartTime)*this.playbackRate+this.playbackTimeAtStart}ensureAudioContext(e){if(this.audioContext)return;const t=window.AudioContext||window.webkitAudioContext;try{this.audioContext=new t({sampleRate:e})}catch(i){this.audioContext=new t}this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination),this.updateGain()}updateGain(){if(!this.gainNode)return;const e=this.muted?0:this.volume;this.gainNode.gain.value=e*e}stopQueuedNodes(){this.queuedNodes.forEach(e=>e.stop()),this.queuedNodes.clear()}stopIterator(){return d(this,null,function*(){var e;yield null==(e=this.audioIterator)?void 0:e.return(),this.audioIterator=null})}handleNoAudioTrack(){this.audioSink=null,this.ensureAudioContext()}load(e,t){return d(this,null,function*(){++this.asyncId,yield this.stopIterator(),this.stopQueuedNodes(),this.paused=!0,this.playbackTimeAtStart=0,this.audioContextStartTime=0;const{input:i,audioTrack:r,duration:n}=e;return this.input=i,this.duration=n,r?null!==r.codec&&(yield r.canDecode())?(this.ensureAudioContext(r.sampleRate),this.audioSink=new oa(r),void(null==t||t())):(this.audioSink=null,this.ensureAudioContext(),void(null==t||t())):(this.handleNoAudioTrack(),void(null==t||t()))})}runIterator(e){return d(this,null,function*(){if(this.audioSink)for(yield this.stopIterator(),this.audioIterator=this.audioSink.buffers(this.currentTime);;){if(e!==this.asyncId||this.paused)return;const i=this.audioIterator.next(),r=setInterval(()=>{e!==this.asyncId||this.paused?clearInterval(r):"running"===this.audioContext.state&&this.audioContext.currentTime>=this.latestScheduledEndTime-.2&&(this.audioContext.suspend(),this.events.emit("waiting"))},50);let n;try{n=yield i}catch(t){console.error("Audio iterator error:",t);break}finally{clearInterval(r)}if(e!==this.asyncId||this.paused)return;if("suspended"===this.audioContext.state&&(yield this.audioContext.resume(),this.events.emit("canplay"),this.events.emit("playing")),n.done)break;const{buffer:s,timestamp:a}=n.value,o=this.audioContext.createBufferSource();o.buffer=s,o.connect(this.gainNode),o.playbackRate.value=this.playbackRate;const l=this.audioContextStartTime+(a-this.playbackTimeAtStart)/this.playbackRate,c=l+s.duration/this.playbackRate;c>this.latestScheduledEndTime&&(this.latestScheduledEndTime=c),l>=this.audioContext.currentTime?o.start(l):o.start(this.audioContext.currentTime,(this.audioContext.currentTime-l)*this.playbackRate),this.queuedNodes.add(o),o.onended=()=>this.queuedNodes.delete(o)}})}play(){return d(this,null,function*(){if(!this.paused)return;this.audioContext||this.ensureAudioContext(),"suspended"===this.audioContext.state&&(yield this.audioContext.resume()),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime,this.paused=!1;const e=++this.asyncId;this.runIterator(e)})}pause(){this.paused||(this.playbackTimeAtStart=this.currentTime,this.paused=!0,this.stopIterator(),this.stopQueuedNodes())}seek(e){return d(this,null,function*(){this.playbackTimeAtStart=Math.max(0,e),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime;const t=++this.asyncId;this.paused||this.runIterator(t)})}setVolume(e,t){this.volume=e,this.muted=t,this.updateGain()}setPlaybackRate(e){if(e!==this.playbackRate&&(this.paused||(this.playbackTimeAtStart=this.currentTime,this.audioContextStartTime=this.audioContext.currentTime),this.playbackRate=e,!this.paused)){const e=++this.asyncId;this.runIterator(e)}}destroy(){var e;this.asyncId++,this.pause(),null==(e=this.audioContext)||e.close(),this.audioContext=null,this.input=null,this.audioSink=null}}const ro=/\.m3u8(?:$|[?#])/i;function no(e){return"string"===typeof e&&ro.test(e)}function so(e){const t=function(e){return"string"===typeof e?new Mn(e):e instanceof Blob?new An(e):"undefined"!==typeof ReadableStream&&e instanceof ReadableStream?new Nn(e):null!=e?e:null}(e);return t?new Ta({source:t,formats:no(e)?ws:vs}):null}function ao(e){return d(this,arguments,function*({input:e,videoTrack:t,audioTrack:i}){const r=[t,i].filter(Boolean),n=t||i,s=Boolean(n&&(yield n.isLive()));let a=Number.NaN;return r.length>0&&(a=yield e.getDurationFromMetadata(r,{skipLiveWait:!0}),null!==a||s||(a=yield e.computeDuration(r,{skipLiveWait:!0}))),s?Number.POSITIVE_INFINITY:null!=a?a:Number.NaN})}function oo(e){return d(this,null,function*(){var t,i;return null!=(i=null!=(t=yield e.getAverageBitrate())?t:yield e.getBitrate())?i:0})}class lo{constructor({canvas:e,ctx:t,events:i,timeupdateInterval:r=250,avSyncTolerance:n=.12,dropLateFrames:s=!1,poster:a="",preflightRange:o=!1}){this.canvas=e,this.ctx=t,this.events=i,this.timeupdateInterval=r,this.avSyncTolerance=n,this.dropLateFrames=s,this.poster=a,this.preflightRange=o,this.input=null,this.videoSink=null,this.videoIterator=null,this.nextFrame=null,this.rafId=0,this.asyncId=0,this.width=0,this.height=0,this.duration=Number.NaN,this.audioClock=null,this.lastTimeUpdate=0,this.stalled=!1,this.playbackRate=1,this.posterDrawn=!1,this.isFetching=!1}preflight(e){return d(this,null,function*(){if(!this.preflightRange||"string"!==typeof e||no(e))return!0;try{const t=(yield fetch(e,{method:"HEAD"})).headers.get("accept-ranges");return!(!t||"none"===t)||(this.events.emit("error",new Event("RangeNotSupported")),!1)}catch(t){return console.warn("Preflight check failed:",t),!0}})}drawPoster(){if(!this.poster||this.posterDrawn)return;const e=new Image;e.onload=()=>{this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width=e.naturalWidth||this.canvas.width,this.canvas.height=e.naturalHeight||this.canvas.height,this.ctx.drawImage(e,0,0,this.canvas.width,this.canvas.height),this.posterDrawn=!0},e.src=this.poster}stopIterator(){return d(this,null,function*(){var e;yield null==(e=this.videoIterator)?void 0:e.return(),this.videoIterator=null})}clear(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}load(e,t){return d(this,null,function*(){++this.asyncId,yield this.stopIterator(),this.clear(),this.posterDrawn=!1;const{input:i,videoTrack:r,duration:n}=e;if(this.input=i,this.duration=n,!r)return this.handleNoVideoTrack(),void(null==t||t());if(null===r.codec||!(yield r.canDecode()))return this.handleNoVideoTrack(),void(null==t||t());const s=yield r.canBeTransparent();this.videoSink=new ra(r,{poolSize:2,fit:"contain",alpha:s}),this.width=r.displayWidth,this.height=r.displayHeight,this.canvas.width=this.width,this.canvas.height=this.height,null==t||t(),yield this.resetIterator(0)})}handleNoVideoTrack(){this.videoSink=null,this.width=0,this.height=0,this.canvas.width=0,this.canvas.height=0,this.clear(),this.drawPoster()}resetIterator(e){return d(this,null,function*(){var t,i;if(yield this.stopIterator(),!this.videoSink)return;this.videoIterator=this.videoSink.canvases(e);const r=null!=(t=(yield this.videoIterator.next()).value)?t:null,n=null!=(i=(yield this.videoIterator.next()).value)?i:null;this.nextFrame=n,r?this.ctx.drawImage(r.canvas,0,0):this.drawPoster()})}updateNextFrame(e){return d(this,null,function*(){var t;if(this.videoIterator&&!this.isFetching){this.isFetching=!0;try{for(;;){const i=null!=(t=(yield this.videoIterator.next()).value)?t:null;if(!i||e!==this.asyncId)return;const r=this.audioClock.currentTime,n=this.dropLateFrames?Math.max(.06,this.avSyncTolerance/Math.max(1,this.playbackRate)):0;if(!(this.dropLateFrames&&i.timestampr)return void(this.nextFrame=null)}}}finally{this.isFetching=!1}}})}render(){if(!this.audioClock)return;const e=this.audioClock.currentTime,t=Date.now();if(t-this.lastTimeUpdate>=this.timeupdateInterval&&(this.events.emit("timeupdate"),this.lastTimeUpdate=t),Number.isFinite(this.duration)&&e>=this.duration)return this.stop(),this.stalled=!1,this.events.emit("ended"),this.events.emit("pause"),void this.events.emit("canplay");this.nextFrame&&this.nextFrame.timestamp<=e?(this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextFrame.canvas,0,0),this.nextFrame=null,this.updateNextFrame(this.asyncId),this.stalled&&(this.events.emit("canplay"),this.events.emit("playing"),this.stalled=!1)):this.nextFrame||(this.updateNextFrame(this.asyncId),!this.nextFrame&&Number.isFinite(this.duration)&&ethis.render())}start(e){this.audioClock=e,this.asyncId++,this.stalled=!1,this.updateNextFrame(this.asyncId),this.rafId=requestAnimationFrame(()=>this.render())}stop(){cancelAnimationFrame(this.rafId)}seek(e){return d(this,null,function*(){this.asyncId++,yield this.resetIterator(e)})}setPlaybackRate(e){this.playbackRate=Math.max(.1,Number(e)||1)}destroy(){this.asyncId++,this.stop(),this.stopIterator(),this.posterDrawn=!1,this.videoSink=null,this.input=null}}class co{constructor({canvas:e,ctx:t,events:i,option:r={}}){var n,s,a,o,l,c;this.events=i,this.option=r,this.audio=new io(i),this.video=new lo({canvas:e,ctx:t,events:i,timeupdateInterval:null!=(n=r.timeupdateInterval)?n:250,avSyncTolerance:null!=(s=r.avSyncTolerance)?s:.12,dropLateFrames:null!=(a=r.dropLateFrames)&&a,poster:null!=(o=r.poster)?o:"",preflightRange:null!=(l=r.preflightRange)&&l}),this.paused=!0,this.ended=!1,this.readyState=0,this.networkState=0,this.error=null,this.seeking=!1,this.loadSeq=0,this.input=null,this.media=null,null==(c=i.addEventListener)||c.call(i,"ended",()=>{this.ended=!0,this.paused=!0})}load(e){return d(this,null,function*(){const t=++this.loadSeq;this.pause(),this.disposeInput(),this.ended=!1,this.error=null,this.networkState=2,this.readyState=0,setTimeout(()=>this.events.emit("waiting"),0),setTimeout(()=>this.events.emit("loadstart"),0);const i=Number.isFinite(this.option.loadTimeout)?this.option.loadTimeout:0;try{yield Promise.race([this.performLoad(e,t),i>0?this.createTimeout(i):new Promise(()=>{})])}catch(r){if(t!==this.loadSeq)return;this.loadSeq++,this.error={code:4,message:r.message},this.networkState=3,this.events.emit("error")}})}performLoad(e,t){return d(this,null,function*(){if(!(yield this.video.preflight(e)))return;const i=so(e);if(!i)return this.video.handleNoVideoTrack(),void this.audio.handleNoAudioTrack();const r=yield function(e,t){return d(this,null,function*(){const i=yield e.getPrimaryVideoTrack(),r=i?yield i.getPrimaryPairableAudioTrack():yield e.getPrimaryAudioTrack(),n=yield ao({input:e,videoTrack:i,audioTrack:r});return{input:e,videoTrack:i,audioTrack:r,duration:n,isLive:!Number.isFinite(n)&&Boolean((i||r)&&(yield(i||r).isLive())),isHls:no(t),videoMode:no(t)?"auto":"manual",audioMode:no(t)?"auto":"manual"}})}(i,e);if(t!==this.loadSeq)return void i.dispose();this.disposeInput(),this.input=i,this.media=r;let n=!r.videoTrack,s=!r.audioTrack;const a=()=>{n&&s&&(this.readyState=1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"))};try{if(yield Promise.all([this.video.load(r,()=>{t===this.loadSeq&&(n=!0,a())}),this.audio.load(r,()=>{t===this.loadSeq&&(s=!0,a())})]),t!==this.loadSeq)return;this.readyState=4,this.networkState=1,this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("progress")}catch(o){if(t!==this.loadSeq)return;this.error={code:4,message:o.message},this.networkState=3,this.events.emit("error"),console.error("MediaBunny load error:",o)}})}createTimeout(e){return new Promise((t,i)=>{setTimeout(()=>i(new Error("Load timeout")),e)})}disposeInput(){var e;null==(e=this.input)||e.dispose(),this.input=null,this.media=null}replaceTracks(e){return d(this,arguments,function*({videoTrack:e,audioTrack:t,videoMode:i,audioMode:r}){if(!this.media)return;const n=u(c({},this.media),{videoTrack:e,audioTrack:t,videoMode:i,audioMode:r}),s=!this.paused,a=this.currentTime;this.pause(),this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),n.duration=yield ao(n),this.media=n,yield Promise.all([this.video.load(n),this.audio.load(n)]),yield Promise.all([this.video.seek(a),this.audio.seek(a)]),this.readyState=4,this.networkState=1,this.seeking=!1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"),this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("seeked"),s&&(yield this.play())})}selectHlsQuality(e){return d(this,null,function*(){var t,i;if(!(null==(t=this.media)?void 0:t.isHls)||!this.input)return;const r=yield this.input.getVideoTracks(),n="auto"===e?yield this.input.getPrimaryVideoTrack():null!=(i=r.find(t=>t.id===e))?i:this.media.videoTrack;if(!n)return;let s=this.media.audioTrack,a=this.media.audioMode;s&&n.canBePairedWith(s)||(s=yield n.getPrimaryPairableAudioTrack(),a="auto"),yield this.replaceTracks({videoTrack:n,audioTrack:s,videoMode:"auto"===e?"auto":"manual",audioMode:a})})}selectHlsAudio(e){return d(this,null,function*(){var t,i;if(!(null==(t=this.media)?void 0:t.isHls)||!this.input)return;const r=yield this.input.getAudioTracks(),n="auto"===e?this.media.videoTrack?yield this.media.videoTrack.getPrimaryPairableAudioTrack():yield this.input.getPrimaryAudioTrack():null!=(i=r.find(t=>t.id===e))?i:this.media.audioTrack;if(!n)return;let s=this.media.videoTrack,a=this.media.videoMode;s&&n.canBePairedWith(s)||(s=yield n.getPrimaryPairableVideoTrack(),a="auto"),yield this.replaceTracks({videoTrack:s,audioTrack:n,videoMode:a,audioMode:"auto"===e?"auto":"manual"})})}getHlsState(){return function(e){return d(this,null,function*(){var t,i,r,n;if(!(null==e?void 0:e.isHls)||!e.input)return null;const[s,a]=yield Promise.all([e.input.getVideoTracks(),e.videoTrack?e.videoTrack.getPairableAudioTracks():[]]),[o,l]=yield Promise.all([Promise.all(s.map((e,t)=>d(null,null,function*(){return{id:e.id,track:e,index:t,name:yield e.getName(),height:yield e.getDisplayHeight(),bitrate:yield oo(e)}}))),Promise.all(a.map((e,t)=>d(null,null,function*(){const i=yield e.getName(),r=yield e.getLanguageCode();return{id:e.id,track:e,index:t,name:i,lang:r,language:r,bitrate:yield oo(e)}})))]);return{levels:o,audios:l,currentLevel:e.videoTrack&&null!=(t=o.find(t=>t.id===e.videoTrack.id))?t:null,currentAudio:e.audioTrack&&null!=(i=l.find(t=>t.id===e.audioTrack.id))?i:null,videoMode:null!=(r=e.videoMode)?r:"auto",audioMode:null!=(n=e.audioMode)?n:"auto"}})}(this.media)}play(){return d(this,null,function*(){this.paused&&(this.ended&&(this.ended=!1,yield this.seek(0)),this.paused=!1,yield this.audio.play(),this.video.start(this.audio),this.events.emit("play"),this.events.emit("playing"))})}pause(){this.paused||(this.paused=!0,this.audio.pause(),this.video.stop(),this.events.emit("pause"))}seek(e){return d(this,null,function*(){const t=!this.paused;this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),this.pause(),yield Promise.all([this.audio.seek(e),this.video.seek(e)]),this.seeking=!1,this.events.emit("seeked"),t&&!this.ended&&(yield this.play())})}setVolume(e,t){this.audio.setVolume(e,t)}setPlaybackRate(e){this.audio.setPlaybackRate(e),this.video.setPlaybackRate(e)}destroy(){this.pause(),this.disposeInput(),this.audio.destroy(),this.video.destroy()}get currentTime(){return this.audio.currentTime}get duration(){var e,t,i;return null!=(i=null!=(t=null==(e=this.media)?void 0:e.duration)?t:this.audio.duration)?i:this.video.duration}get videoWidth(){return this.video.width}get videoHeight(){return this.video.height}}class uo{constructor({art:e,canvas:t,ctx:i,option:r}){var n,s;this.art=e,this.canvas=t,this.option=r,this.events=new k,this.engine=new co({canvas:t,ctx:i,events:this.events,option:r}),this._src=null,this._volume=null!=(n=r.volume)?n:.7,this._muted=!!r.muted,this._playbackRate=1,this.engine.setVolume(this._volume,this._muted),this.setupEventForwarding(),r.source?this.src=r.source:(null==(s=e.option)?void 0:s.url)&&(this.src=e.option.url)}setupEventForwarding(){const{events:e}=this.art.constructor.config;e.forEach(e=>{this.events.addEventListener(e,e=>{this.art.emit(`video:${e.type}`,e)})})}addEventListener(e,t){this.events.addEventListener(e,t)}removeEventListener(e,t){this.events.removeEventListener(e,t)}get src(){return this._src}set src(e){this._src=e,e&&this.engine.load(e)}get currentSrc(){return this._src}get currentTime(){return this.engine.currentTime}set currentTime(e){this.engine.seek(Number(e)||0)}get duration(){return this.engine.duration}get buffered(){return this.createTimeRanges(0,this.engine.duration)}get played(){return this.createTimeRanges(0,this.engine.currentTime)}get seekable(){return this.createTimeRanges(0,this.engine.duration)}createTimeRanges(e,t){const i=this.engine.duration;return!i||Number.isNaN(i)||t<=0?{length:0,start:()=>0,end:()=>0}:{length:1,start:()=>e,end:()=>t}}get paused(){return this.engine.paused}get playing(){return!this.engine.paused&&!this.engine.ended}get ended(){return this.engine.ended}get seeking(){return this.engine.seeking}get readyState(){return this.engine.readyState}get networkState(){return this.engine.networkState}get error(){return this.engine.error}get playbackRate(){return this._playbackRate}set playbackRate(e){const t=Number(e);Number.isNaN(t)||t<=0||(this._playbackRate=t,this.engine.setPlaybackRate(t),this.events.emit("ratechange"))}get volume(){return this._volume}set volume(e){this._volume=function(e,t,i){return Math.max(t,Math.min(i,Number(e)||0))}(e,0,1),this._muted=!1,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}get muted(){return this._muted}set muted(e){this._muted=!!e,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}play(){return this.engine.play()}pause(){this.engine.pause()}load(){this._src&&this.engine.load(this._src)}getM3u8State(){return this.engine.getHlsState()}switchM3u8Quality(e){return this.engine.selectHlsQuality(e)}switchM3u8Audio(e){return this.engine.selectHlsAudio(e)}get videoWidth(){return this.engine.videoWidth}get videoHeight(){return this.engine.videoHeight}get poster(){return this.option.poster||""}set poster(e){this.option.poster=e}get autoplay(){return this.option.autoplay||!1}set autoplay(e){}get loop(){return this.option.loop||!1}set loop(e){}get controls(){return!1}set controls(e){}get playsInline(){return!0}set playsInline(e){}get crossOrigin(){return this.option.crossOrigin||""}set crossOrigin(e){}get preload(){return"auto"}set preload(e){}get defaultMuted(){return!1}set defaultMuted(e){}get defaultPlaybackRate(){return 1}set defaultPlaybackRate(e){}canPlayType(e){return"maybe"}getBoundingClientRect(){return this.canvas.getBoundingClientRect()}requestVideoFrameCallback(e){return requestAnimationFrame(t=>{e(t,{presentationTime:this.engine.currentTime,expectedDisplayTime:t+16.6,width:this.engine.videoWidth,height:this.engine.videoHeight,mediaTime:this.engine.currentTime,presentedFrames:0,processingDuration:0,captureTime:t,receiveTime:t,rtpTimestamp:0})})}cancelVideoFrameCallback(e){cancelAnimationFrame(e)}setAttribute(e,t){"src"===e?this.src=t:"autoplay"===e?this.autoplay=t:"loop"===e?this.loop=t:"muted"===e?this.muted=!0:this.canvas.setAttribute(e,t)}destroy(){this.engine.destroy()}}return function(e={}){return t=>{const{constructor:i}=t,{createElement:r}=i.utils,n=r("canvas"),s=n.getContext("2d"),a=new uo({art:t,canvas:n,ctx:s,option:e});t.mediabunny=a;const o={};for(const e in n)"function"===typeof n[e]&&(o[e]=n[e].bind(n));const l=new Set([...Object.getOwnPropertyNames(a),...Object.getOwnPropertyNames(Object.getPrototypeOf(a))]);for(const e of l)"constructor"!==e&&(e in n||Object.defineProperty(n,e,{get(){const t=a[e];return"function"===typeof t?t.bind(a):t},set(t){a[e]=t},configurable:!0,enumerable:!0}));for(const e in o)n[e]=(...t)=>o[e](...t);function c(){var e;(null==(e=t.template)?void 0:e.$player)&&!t.option.autoSize&&Object.assign(n.style,{width:"100%",height:"100%",objectFit:"contain"})}return t.on("resize",c),t.on("video:loadedmetadata",c),function({art:e,shim:t,option:i}){if(i.m3u8)return e.on("video:loadedmetadata",u),e.on("restart",u),{update:u};function r(t){e.controls.cache.has(t)&&e.controls.remove(t)}function n(t){e.setting.find(t)&&e.setting.remove(t)}function s(){r("mediabunny-quality"),n("mediabunny-quality")}function a(){r("mediabunny-audio"),n("mediabunny-audio")}function o(e={}){return e.control||e.setting}function l(r){return d(this,null,function*(){var n;const a=(null==(n=i.m3u8)?void 0:n.quality)||{};if(!o(a)||!(null==r?void 0:r.levels.length))return void s();const l=a.auto||"Auto",c=a.title||"Quality",h=a.getName||(e=>e.name||`${e.height}P`),f=r.currentLevel?h(r.currentLevel):l,m=g(r.levels.map(e=>{var t;return{html:h(e),value:e.id,default:(null==(t=r.currentLevel)?void 0:t.id)===e.id}}),"html").sort((e,t)=>{const i=r.levels.find(t=>t.id===e.value),n=r.levels.find(e=>e.id===t.value);return((null==n?void 0:n.height)||0)-((null==i?void 0:i.height)||0)});m.push({html:l,value:"auto",default:!r.currentLevel});const p=i=>d(null,null,function*(){return yield t.switchM3u8Quality(i.value),e.notice.show=`${c}: ${i.html}`,yield u(),i.html});a.control&&e.controls.update({name:"mediabunny-quality",position:"right",html:f,style:{padding:"0 10px"},selector:m,onSelect:p}),a.setting&&e.setting.update({name:"mediabunny-quality",tooltip:f,html:c,icon:'',width:200,selector:m,onSelect:p})})}function c(r){return d(this,null,function*(){var n;const s=(null==(n=i.m3u8)?void 0:n.audio)||{};if(!o(s)||!(null==r?void 0:r.audios.length)||r.audios.length<2)return void a();const l=s.auto||"Auto",c=s.title||"Audio",h=s.getName||(e=>e.name||e.lang||e.language),f=r.currentAudio?h(r.currentAudio):l,m=g(r.audios.map(e=>{var t;return{html:h(e),value:e.id,default:(null==(t=r.currentAudio)?void 0:t.id)===e.id}}),"html");m.push({html:l,value:"auto",default:!r.currentAudio});const p=i=>d(null,null,function*(){return yield t.switchM3u8Audio(i.value),e.notice.show=`${c}: ${i.html}`,yield u(),i.html});s.control&&e.controls.update({name:"mediabunny-audio",position:"right",html:f,style:{padding:"0 10px"},selector:m,onSelect:p}),s.setting&&e.setting.update({name:"mediabunny-audio",tooltip:f,html:c,icon:'',width:200,selector:m,onSelect:p})})}function u(){return d(this,null,function*(){const e=yield t.getM3u8State();if(!e)return s(),void a();yield Promise.all([l(e),c(e)])})}}({art:t,shim:a,option:e}),t.on("destroy",()=>{delete t.mediabunny,a.destroy()}),n}}}); diff --git a/docs/compiled/artplayer-proxy-mediabunny.mjs b/docs/compiled/artplayer-proxy-mediabunny.mjs index 77d3f9981..2cb05293a 100644 --- a/docs/compiled/artplayer-proxy-mediabunny.mjs +++ b/docs/compiled/artplayer-proxy-mediabunny.mjs @@ -1,9 +1,171 @@ /*! - * artplayer-proxy-mediabunny.js v1.1.0 + * artplayer-proxy-mediabunny.js v1.2.0 * Github: https://github.com/zhw2590582/ArtPlayer * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ +const $audio = ''; +const $quality = ''; +function uniqBy(array, property) { + const seen = /* @__PURE__ */ new Map(); + return array.filter((item) => { + const key = item[property]; + if (key === void 0) { + return true; + } + return !seen.has(key) && seen.set(key, 1); + }); +} +function setupM3u8Controls({ art, shim, option }) { + if (!option.m3u8) + return; + function removeControl(name) { + if (art.controls.cache.has(name)) { + art.controls.remove(name); + } + } + function removeSetting(name) { + if (art.setting.find(name)) { + art.setting.remove(name); + } + } + function clearQuality() { + removeControl("mediabunny-quality"); + removeSetting("mediabunny-quality"); + } + function clearAudio() { + removeControl("mediabunny-audio"); + removeSetting("mediabunny-audio"); + } + function canRender(config = {}) { + return config.control || config.setting; + } + async function updateQuality(state) { + const config = option.m3u8?.quality || {}; + if (!canRender(config) || !state?.levels.length) { + clearQuality(); + return; + } + const auto = config.auto || "Auto"; + const title = config.title || "Quality"; + const getName = config.getName || ((level) => level.name || `${level.height}P`); + const defaultHtml = state.currentLevel ? getName(state.currentLevel) : auto; + const selector = uniqBy( + state.levels.map((item) => { + return { + html: getName(item), + value: item.id, + default: state.currentLevel?.id === item.id + }; + }), + "html" + ).sort((a, b) => { + const left = state.levels.find((item) => item.id === a.value); + const right = state.levels.find((item) => item.id === b.value); + return (right?.height || 0) - (left?.height || 0); + }); + selector.push({ + html: auto, + value: "auto", + default: !state.currentLevel + }); + const onSelect = async (item) => { + await shim.switchM3u8Quality(item.value); + art.notice.show = `${title}: ${item.html}`; + await update(); + return item.html; + }; + if (config.control) { + art.controls.update({ + name: "mediabunny-quality", + position: "right", + html: defaultHtml, + style: { padding: "0 10px" }, + selector, + onSelect + }); + } + if (config.setting) { + art.setting.update({ + name: "mediabunny-quality", + tooltip: defaultHtml, + html: title, + icon: $quality, + width: 200, + selector, + onSelect + }); + } + } + async function updateAudio(state) { + const config = option.m3u8?.audio || {}; + if (!canRender(config) || !state?.audios.length || state.audios.length < 2) { + clearAudio(); + return; + } + const auto = config.auto || "Auto"; + const title = config.title || "Audio"; + const getName = config.getName || ((track) => track.name || track.lang || track.language); + const defaultHtml = state.currentAudio ? getName(state.currentAudio) : auto; + const selector = uniqBy( + state.audios.map((item) => { + return { + html: getName(item), + value: item.id, + default: state.currentAudio?.id === item.id + }; + }), + "html" + ); + selector.push({ + html: auto, + value: "auto", + default: !state.currentAudio + }); + const onSelect = async (item) => { + await shim.switchM3u8Audio(item.value); + art.notice.show = `${title}: ${item.html}`; + await update(); + return item.html; + }; + if (config.control) { + art.controls.update({ + name: "mediabunny-audio", + position: "right", + html: defaultHtml, + style: { padding: "0 10px" }, + selector, + onSelect + }); + } + if (config.setting) { + art.setting.update({ + name: "mediabunny-audio", + tooltip: defaultHtml, + html: title, + icon: $audio, + width: 200, + selector, + onSelect + }); + } + } + async function update() { + const state = await shim.getM3u8State(); + if (!state) { + clearQuality(); + clearAudio(); + return; + } + await Promise.all([ + updateQuality(state), + updateAudio(state) + ]); + } + art.on("video:loadedmetadata", update); + art.on("restart", update); + return { update }; +} class EventTarget { constructor() { this.listeners = /* @__PURE__ */ new Map(); @@ -48,66 +210,6 @@ const normalizeRotation = (rotation) => { const last = (arr) => { return arr && arr[arr.length - 1]; }; -class Bitstream { - constructor(bytes) { - this.bytes = bytes; - this.pos = 0; - } - seekToByte(byteOffset) { - this.pos = 8 * byteOffset; - } - readBit() { - const byteIndex = Math.floor(this.pos / 8); - const byte = this.bytes[byteIndex] ?? 0; - const bitIndex = 7 - (this.pos & 7); - const bit = (byte & 1 << bitIndex) >> bitIndex; - this.pos++; - return bit; - } - readBits(n) { - if (n === 1) { - return this.readBit(); - } - let result = 0; - for (let i = 0; i < n; i++) { - result <<= 1; - result |= this.readBit(); - } - return result; - } - writeBits(n, value) { - const end = this.pos + n; - for (let i = this.pos; i < end; i++) { - const byteIndex = Math.floor(i / 8); - let byte = this.bytes[byteIndex]; - const bitIndex = 7 - (i & 7); - byte &= ~(1 << bitIndex); - byte |= (value & 1 << end - i - 1) >> end - i - 1 << bitIndex; - this.bytes[byteIndex] = byte; - } - this.pos = end; - } - readAlignedByte() { - if (this.pos % 8 !== 0) { - throw new Error("Bitstream is not byte-aligned."); - } - const byteIndex = this.pos / 8; - const byte = this.bytes[byteIndex] ?? 0; - this.pos += 8; - return byte; - } - skipBits(n) { - this.pos += n; - } - getBitsLeft() { - return this.bytes.length * 8 - this.pos; - } - clone() { - const clone = new Bitstream(this.bytes); - clone.pos = this.pos; - return clone; - } -} const readExpGolomb = (bitstream) => { let leadingZeroBits = 0; while (bitstream.readBits(1) === 0 && leadingZeroBits < 32) { @@ -192,21 +294,40 @@ const isAllowSharedBufferSource = (x) => { class AsyncMutex { constructor() { this.currentPromise = Promise.resolve(); + this.pending = 0; } async acquire() { let resolver; const nextPromise = new Promise((resolve) => { - resolver = resolve; + let resolved = false; + resolver = () => { + if (resolved) { + return; + } + resolve(); + this.pending--; + resolved = true; + }; }); const currentPromiseAlias = this.currentPromise; this.currentPromise = nextPromise; + this.pending++; await currentPromiseAlias; return resolver; } } +const HEX_STRING_REGEX = /^[0-9a-fA-F]+$/; const bytesToHexString = (bytes) => { return [...bytes].map((x) => x.toString(16).padStart(2, "0")).join(""); }; +const hexStringToBytes = (hexString) => { + assert(hexString.length % 2 === 0); + const bytes = new Uint8Array(hexString.length / 2); + for (let i = 0; i < hexString.length; i += 2) { + bytes[i / 2] = parseInt(hexString.slice(i, i + 2), 16); + } + return bytes; +}; const reverseBitsU32 = (x) => { x = x >> 1 & 1431655765 | (x & 1431655765) << 1; x = x >> 2 & 858993459 | (x & 858993459) << 2; @@ -262,6 +383,12 @@ const promiseWithResolvers = () => { }); return { promise, resolve, reject }; }; +const removeItem = (arr, item) => { + const index = arr.indexOf(item); + if (index !== -1) { + arr.splice(index, 1); + } +}; const findLast = (arr, predicate) => { for (let i = arr.length - 1; i >= 0; i--) { if (predicate(arr[i])) { @@ -351,6 +478,12 @@ const roundIfAlmostInteger = (value) => { const roundToMultiple = (value, multiple) => { return Math.round(value / multiple) * multiple; }; +const roundToDivisor = (value, multiple) => { + return Math.round(value * multiple) / multiple; +}; +const floorToMultiple = (value, multiple) => { + return Math.floor(value / multiple) * multiple; +}; const ilog = (x) => { let ret = 0; while (x) { @@ -417,7 +550,7 @@ const retriedFetch = async (fetchFn, url, requestInit, getRetryDelay, shouldStop throw new TypeError("Retry delay must be a non-negative finite number."); } if (retryDelayInSeconds > 0) { - await new Promise((resolve) => setTimeout(resolve, 1e3 * retryDelayInSeconds)); + await wait(1e3 * retryDelayInSeconds); } if (shouldStop()) { throw error; @@ -438,7 +571,8 @@ const isWebKit = () => { if (isWebKitCache !== null) { return isWebKitCache; } - return isWebKitCache = !!(typeof navigator !== "undefined" && (navigator.vendor?.match(/apple/i) || /AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) || /\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent))); + return isWebKitCache = !!(typeof navigator !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-deprecated + (navigator.vendor?.match(/apple/i) || /AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) || /\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent))); }; let isFirefoxCache = null; const isFirefox = () => { @@ -482,12 +616,166 @@ const base64ToBytes = (base64) => { } return bytes; }; +const uint8ArraysAreEqual = (a, b) => { + if (a.length !== b.length) { + return false; + } + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; +}; const polyfillSymbolDispose = () => { Symbol.dispose ?? (Symbol.dispose = /* @__PURE__ */ Symbol("Symbol.dispose")); }; const isNumber = (x) => { return typeof x === "number" && !Number.isNaN(x); }; +const joinPaths = (basePath, relativePath) => { + if (relativePath.includes("://")) { + return relativePath; + } + if (basePath.includes("://")) { + const queryIndex = basePath.indexOf("?"); + if (queryIndex !== -1) { + basePath = basePath.slice(0, queryIndex); + } + } + let result; + if (relativePath.startsWith("/")) { + const protocolIndex2 = basePath.indexOf("://"); + if (protocolIndex2 === -1) { + result = relativePath; + } else { + const pathStart = basePath.indexOf("/", protocolIndex2 + 3); + if (pathStart === -1) { + result = basePath + relativePath; + } else { + result = basePath.slice(0, pathStart) + relativePath; + } + } + } else { + const lastSlash = basePath.lastIndexOf("/"); + if (lastSlash === -1) { + result = relativePath; + } else { + result = basePath.slice(0, lastSlash + 1) + relativePath; + } + } + let prefix = ""; + const protocolIndex = result.indexOf("://"); + if (protocolIndex !== -1) { + const pathStart = result.indexOf("/", protocolIndex + 3); + if (pathStart !== -1) { + prefix = result.slice(0, pathStart); + result = result.slice(pathStart); + } + } + const segments = result.split("/"); + const normalized = []; + for (const segment of segments) { + if (segment === "..") { + normalized.pop(); + } else if (segment !== ".") { + normalized.push(segment); + } + } + return prefix + normalized.join("/"); +}; +const arrayCount = (array, predicate) => { + let count = 0; + for (let i = 0; i < array.length; i++) { + if (predicate(array[i])) { + count++; + } + } + return count; +}; +const arrayArgmin = (array, getValue) => { + let minIndex = -1; + let minValue = Infinity; + for (let i = 0; i < array.length; i++) { + const value = getValue(array[i]); + if (value < minValue) { + minValue = value; + minIndex = i; + } + } + return minIndex; +}; +const simplifyRational = (rational) => { + assert(Number.isInteger(rational.num)); + assert(Number.isInteger(rational.den)); + assert(rational.den !== 0); + let a = Math.abs(rational.num); + let b = Math.abs(rational.den); + while (b !== 0) { + const t = a % b; + a = b; + b = t; + } + const gcd = a || 1; + return { + num: rational.num / gcd, + den: rational.den / gcd + }; +}; +const validateRectangle = (rect, propertyPath) => { + if (typeof rect !== "object" || !rect) { + throw new TypeError(`${propertyPath} must be an object.`); + } + if (!Number.isInteger(rect.left) || rect.left < 0) { + throw new TypeError(`${propertyPath}.left must be a non-negative integer.`); + } + if (!Number.isInteger(rect.top) || rect.top < 0) { + throw new TypeError(`${propertyPath}.top must be a non-negative integer.`); + } + if (!Number.isInteger(rect.width) || rect.width < 0) { + throw new TypeError(`${propertyPath}.width must be a non-negative integer.`); + } + if (!Number.isInteger(rect.height) || rect.height < 0) { + throw new TypeError(`${propertyPath}.height must be a non-negative integer.`); + } +}; +const wait = (ms) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; +class EventEmitter { + constructor() { + this._listeners = /* @__PURE__ */ new Map(); + } + /** Registers a listener for the given event. */ + on(event, listener, options) { + if (!this._listeners.has(event)) { + this._listeners.set(event, /* @__PURE__ */ new Set()); + } + const entry = { fn: listener, once: options?.once ?? false }; + this._listeners.get(event).add(entry); + return () => { + this._listeners.get(event)?.delete(entry); + }; + } + /** @internal */ + _emit(...args) { + const [event, data] = args; + const listeners = this._listeners.get(event); + if (!listeners) { + return; + } + for (const entry of listeners) { + try { + entry.fn(data); + } catch (error) { + console.error(error); + } + if (entry.once) { + listeners.delete(entry); + } + } + } +} class RichImageData { /** Creates a new {@link RichImageData}. */ constructor(data, mimeType) { @@ -524,12 +812,127 @@ class AttachedFile { } const DEFAULT_TRACK_DISPOSITION = { default: true, + primary: true, forced: false, original: false, commentary: false, hearingImpaired: false, visuallyImpaired: false }; +class Bitstream { + constructor(bytes) { + this.bytes = bytes; + this.pos = 0; + } + seekToByte(byteOffset) { + this.pos = 8 * byteOffset; + } + readBit() { + const byteIndex = Math.floor(this.pos / 8); + const byte = this.bytes[byteIndex] ?? 0; + const bitIndex = 7 - (this.pos & 7); + const bit = (byte & 1 << bitIndex) >> bitIndex; + this.pos++; + return bit; + } + readBits(n) { + if (n === 1) { + return this.readBit(); + } + let result = 0; + for (let i = 0; i < n; i++) { + result <<= 1; + result |= this.readBit(); + } + return result; + } + writeBits(n, value) { + const end = this.pos + n; + for (let i = this.pos; i < end; i++) { + const byteIndex = Math.floor(i / 8); + let byte = this.bytes[byteIndex]; + const bitIndex = 7 - (i & 7); + byte &= ~(1 << bitIndex); + byte |= (value & 1 << end - i - 1) >> end - i - 1 << bitIndex; + this.bytes[byteIndex] = byte; + } + this.pos = end; + } + readAlignedByte() { + if (this.pos % 8 !== 0) { + throw new Error("Bitstream is not byte-aligned."); + } + const byteIndex = this.pos / 8; + const byte = this.bytes[byteIndex] ?? 0; + this.pos += 8; + return byte; + } + skipBits(n) { + this.pos += n; + } + getBitsLeft() { + return this.bytes.length * 8 - this.pos; + } + clone() { + const clone = new Bitstream(this.bytes); + clone.pos = this.pos; + return clone; + } +} +const aacFrequencyTable = [ + 96e3, + 88200, + 64e3, + 48e3, + 44100, + 32e3, + 24e3, + 22050, + 16e3, + 12e3, + 11025, + 8e3, + 7350 +]; +const aacChannelMap = [-1, 1, 2, 3, 4, 5, 6, 8]; +const parseAacAudioSpecificConfig = (bytes) => { + if (!bytes || bytes.byteLength < 2) { + throw new TypeError("AAC description must be at least 2 bytes long."); + } + const bitstream = new Bitstream(bytes); + let objectType = bitstream.readBits(5); + if (objectType === 31) { + objectType = 32 + bitstream.readBits(6); + } + const frequencyIndex = bitstream.readBits(4); + let sampleRate = null; + if (frequencyIndex === 15) { + sampleRate = bitstream.readBits(24); + } else { + if (frequencyIndex < aacFrequencyTable.length) { + sampleRate = aacFrequencyTable[frequencyIndex]; + } + } + const channelConfiguration = bitstream.readBits(4); + let numberOfChannels = null; + if (channelConfiguration >= 1 && channelConfiguration <= 7) { + numberOfChannels = aacChannelMap[channelConfiguration]; + } + return { + objectType, + frequencyIndex, + sampleRate, + channelConfiguration, + numberOfChannels + }; +}; +const VIDEO_CODECS = [ + "avc", + "hevc", + "vp9", + "av1", + "vp8" +]; const PCM_AUDIO_CODECS = [ "pcm-s16", // We don't prefix 'le' so we're compatible with the WebCodecs-registered PCM codec strings @@ -547,6 +950,59 @@ const PCM_AUDIO_CODECS = [ "ulaw", "alaw" ]; +const NON_PCM_AUDIO_CODECS = [ + "aac", + "opus", + "mp3", + "vorbis", + "flac", + "ac3", + "eac3" +]; +const AUDIO_CODECS = [ + ...NON_PCM_AUDIO_CODECS, + ...PCM_AUDIO_CODECS +]; +const AVC_LEVEL_TABLE = [ + { maxMacroblocks: 99, maxBitrate: 64e3, maxDpbMbs: 396, level: 10 }, + // Level 1 + { maxMacroblocks: 396, maxBitrate: 192e3, maxDpbMbs: 900, level: 11 }, + // Level 1.1 + { maxMacroblocks: 396, maxBitrate: 384e3, maxDpbMbs: 2376, level: 12 }, + // Level 1.2 + { maxMacroblocks: 396, maxBitrate: 768e3, maxDpbMbs: 2376, level: 13 }, + // Level 1.3 + { maxMacroblocks: 396, maxBitrate: 2e6, maxDpbMbs: 2376, level: 20 }, + // Level 2 + { maxMacroblocks: 792, maxBitrate: 4e6, maxDpbMbs: 4752, level: 21 }, + // Level 2.1 + { maxMacroblocks: 1620, maxBitrate: 4e6, maxDpbMbs: 8100, level: 22 }, + // Level 2.2 + { maxMacroblocks: 1620, maxBitrate: 1e7, maxDpbMbs: 8100, level: 30 }, + // Level 3 + { maxMacroblocks: 3600, maxBitrate: 14e6, maxDpbMbs: 18e3, level: 31 }, + // Level 3.1 + { maxMacroblocks: 5120, maxBitrate: 2e7, maxDpbMbs: 20480, level: 32 }, + // Level 3.2 + { maxMacroblocks: 8192, maxBitrate: 2e7, maxDpbMbs: 32768, level: 40 }, + // Level 4 + { maxMacroblocks: 8192, maxBitrate: 5e7, maxDpbMbs: 32768, level: 41 }, + // Level 4.1 + { maxMacroblocks: 8704, maxBitrate: 5e7, maxDpbMbs: 34816, level: 42 }, + // Level 4.2 + { maxMacroblocks: 22080, maxBitrate: 135e6, maxDpbMbs: 110400, level: 50 }, + // Level 5 + { maxMacroblocks: 36864, maxBitrate: 24e7, maxDpbMbs: 184320, level: 51 }, + // Level 5.1 + { maxMacroblocks: 36864, maxBitrate: 24e7, maxDpbMbs: 184320, level: 52 }, + // Level 5.2 + { maxMacroblocks: 139264, maxBitrate: 24e7, maxDpbMbs: 696320, level: 60 }, + // Level 6 + { maxMacroblocks: 139264, maxBitrate: 48e7, maxDpbMbs: 696320, level: 61 }, + // Level 6.1 + { maxMacroblocks: 139264, maxBitrate: 8e8, maxDpbMbs: 696320, level: 62 } + // Level 6.2 +]; const VP9_LEVEL_TABLE = [ { maxPictureSize: 36864, maxBitrate: 2e5, level: 10 }, // Level 1 @@ -712,8 +1168,14 @@ const extractAudioCodecString = (trackInfo) => { if (aacCodecInfo.isMpeg2) { return "mp4a.67"; } else { - const audioSpecificConfig = parseAacAudioSpecificConfig(codecDescription); - return `mp4a.40.${audioSpecificConfig.objectType}`; + let objectType; + if (aacCodecInfo.objectType !== null) { + objectType = aacCodecInfo.objectType; + } else { + const audioSpecificConfig = parseAacAudioSpecificConfig(codecDescription); + objectType = audioSpecificConfig.objectType; + } + return `mp4a.40.${objectType}`; } } else if (codec === "mp3") { return "mp3"; @@ -723,58 +1185,15 @@ const extractAudioCodecString = (trackInfo) => { return "vorbis"; } else if (codec === "flac") { return "flac"; + } else if (codec === "ac3") { + return "ac-3"; + } else if (codec === "eac3") { + return "ec-3"; } else if (codec && PCM_AUDIO_CODECS.includes(codec)) { return codec; } throw new TypeError(`Unhandled codec '${codec}'.`); }; -const aacFrequencyTable = [ - 96e3, - 88200, - 64e3, - 48e3, - 44100, - 32e3, - 24e3, - 22050, - 16e3, - 12e3, - 11025, - 8e3, - 7350 -]; -const aacChannelMap = [-1, 1, 2, 3, 4, 5, 6, 8]; -const parseAacAudioSpecificConfig = (bytes) => { - if (!bytes || bytes.byteLength < 2) { - throw new TypeError("AAC description must be at least 2 bytes long."); - } - const bitstream = new Bitstream(bytes); - let objectType = bitstream.readBits(5); - if (objectType === 31) { - objectType = 32 + bitstream.readBits(6); - } - const frequencyIndex = bitstream.readBits(4); - let sampleRate = null; - if (frequencyIndex === 15) { - sampleRate = bitstream.readBits(24); - } else { - if (frequencyIndex < aacFrequencyTable.length) { - sampleRate = aacFrequencyTable[frequencyIndex]; - } - } - const channelConfiguration = bitstream.readBits(4); - let numberOfChannels = null; - if (channelConfiguration >= 1 && channelConfiguration <= 7) { - numberOfChannels = aacChannelMap[channelConfiguration]; - } - return { - objectType, - frequencyIndex, - sampleRate, - channelConfiguration, - numberOfChannels - }; -}; const OPUS_SAMPLE_RATE = 48e3; const PCM_CODEC_REGEX = /^pcm-([usf])(\d+)+(be)?$/; const parsePcmCodec = (codec) => { @@ -799,12 +1218,318 @@ const parsePcmCodec = (codec) => { const silentValue = codec === "pcm-u8" ? 2 ** 7 : 0; return { dataType, sampleSize, littleEndian, silentValue }; }; +const inferCodecFromCodecString = (codecString) => { + if (codecString.startsWith("avc1") || codecString.startsWith("avc3")) { + return "avc"; + } else if (codecString.startsWith("hev1") || codecString.startsWith("hvc1")) { + return "hevc"; + } else if (codecString === "vp8") { + return "vp8"; + } else if (codecString.startsWith("vp09")) { + return "vp9"; + } else if (codecString.startsWith("av01")) { + return "av1"; + } + if (codecString === "mp3" || codecString === "mp4a.69" || codecString === "mp4a.6B" || codecString === "mp4a.6b" || codecString === "mp4a.40.34") { + return "mp3"; + } else if (codecString.startsWith("mp4a.40.") || codecString === "mp4a.67") { + return "aac"; + } else if (codecString === "opus") { + return "opus"; + } else if (codecString === "vorbis") { + return "vorbis"; + } else if (codecString === "flac") { + return "flac"; + } else if (codecString === "ac-3" || codecString === "ac3") { + return "ac3"; + } else if (codecString === "ec-3" || codecString === "eac3") { + return "eac3"; + } else if (codecString === "ulaw") { + return "ulaw"; + } else if (codecString === "alaw") { + return "alaw"; + } else if (PCM_CODEC_REGEX.test(codecString)) { + return codecString; + } + if (codecString === "webvtt") { + return "webvtt"; + } + return null; +}; +const FRAME_HEADER_SIZE = 4; +const SAMPLING_RATES = [44100, 48e3, 32e3]; +const KILOBIT_RATES = [ + // lowSamplingFrequency === 0 + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + // layer = 0 + -1, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + -1, + // layer 1 + -1, + 32, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + 384, + -1, + // layer = 2 + -1, + 32, + 64, + 96, + 128, + 160, + 192, + 224, + 256, + 288, + 320, + 352, + 384, + 416, + 448, + -1, + // layer = 3 + // lowSamplingFrequency === 1 + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + // layer = 0 + -1, + 8, + 16, + 24, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + -1, + // layer = 1 + -1, + 8, + 16, + 24, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + -1, + // layer = 2 + -1, + 32, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + 176, + 192, + 224, + 256, + -1 + // layer = 3 +]; +const XING = 1483304551; +const INFO = 1231971951; +const computeMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate, padding) => { + if (layer === 0) { + return 0; + } else if (layer === 1) { + return Math.floor(144 * bitrate / (sampleRate << lowSamplingFrequency)) + padding; + } else if (layer === 2) { + return Math.floor(144 * bitrate / sampleRate) + padding; + } else { + return (Math.floor(12 * bitrate / sampleRate) + padding) * 4; + } +}; +const computeAverageMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate) => { + if (layer === 0) { + return 0; + } else if (layer === 1) { + return 144 * bitrate / (sampleRate << lowSamplingFrequency); + } else if (layer === 2) { + return 144 * bitrate / sampleRate; + } else { + return 12 * bitrate / sampleRate * 4; + } +}; +const getXingOffset = (mpegVersionId, channel) => { + return mpegVersionId === 3 ? channel === 3 ? 21 : 36 : channel === 3 ? 13 : 21; +}; +const readMp3FrameHeader = (word, remainingBytes) => { + const firstByte = word >>> 24; + const secondByte = word >>> 16 & 255; + const thirdByte = word >>> 8 & 255; + const fourthByte = word & 255; + if (firstByte !== 255 && secondByte !== 255 && thirdByte !== 255 && fourthByte !== 255) { + return { + header: null, + bytesAdvanced: 4 + }; + } + if (firstByte !== 255) { + return { header: null, bytesAdvanced: 1 }; + } + if ((secondByte & 224) !== 224) { + return { header: null, bytesAdvanced: 1 }; + } + let lowSamplingFrequency = 0; + let mpeg25 = 0; + if (secondByte & 1 << 4) { + lowSamplingFrequency = secondByte & 1 << 3 ? 0 : 1; + } else { + lowSamplingFrequency = 1; + mpeg25 = 1; + } + const mpegVersionId = secondByte >> 3 & 3; + const layer = secondByte >> 1 & 3; + const bitrateIndex = thirdByte >> 4 & 15; + const frequencyIndex = (thirdByte >> 2 & 3) % 3; + const padding = thirdByte >> 1 & 1; + const channel = fourthByte >> 6 & 3; + const modeExtension = fourthByte >> 4 & 3; + const copyright = fourthByte >> 3 & 1; + const original = fourthByte >> 2 & 1; + const emphasis = fourthByte & 3; + const kilobitRate = KILOBIT_RATES[lowSamplingFrequency * 16 * 4 + layer * 16 + bitrateIndex]; + if (kilobitRate === -1) { + return { header: null, bytesAdvanced: 1 }; + } + const bitrate = kilobitRate * 1e3; + const sampleRate = SAMPLING_RATES[frequencyIndex] >> lowSamplingFrequency + mpeg25; + const frameLength = computeMp3FrameSize(lowSamplingFrequency, layer, bitrate, sampleRate, padding); + if (remainingBytes !== null && remainingBytes < frameLength) { + return { header: null, bytesAdvanced: 1 }; + } + let audioSamplesInFrame; + if (mpegVersionId === 3) { + audioSamplesInFrame = layer === 3 ? 384 : 1152; + } else { + if (layer === 3) { + audioSamplesInFrame = 384; + } else if (layer === 2) { + audioSamplesInFrame = 1152; + } else { + audioSamplesInFrame = 576; + } + } + return { + header: { + totalSize: frameLength, + mpegVersionId, + lowSamplingFrequency, + layer, + bitrate, + frequencyIndex, + sampleRate, + channel, + modeExtension, + copyright, + original, + emphasis, + audioSamplesInFrame + }, + bytesAdvanced: 1 + }; +}; +const decodeSynchsafe = (synchsafed) => { + let mask = 2130706432; + let unsynchsafed = 0; + while (mask !== 0) { + unsynchsafed >>= 1; + unsynchsafed |= synchsafed & mask; + mask >>= 8; + } + return unsynchsafed; +}; +var XingFlags; +(function(XingFlags2) { + XingFlags2[XingFlags2["FrameCount"] = 1] = "FrameCount"; + XingFlags2[XingFlags2["FileSize"] = 2] = "FileSize"; + XingFlags2[XingFlags2["Toc"] = 4] = "Toc"; +})(XingFlags || (XingFlags = {})); +const AC3_SAMPLE_RATES = [48e3, 44100, 32e3]; +const EAC3_REDUCED_SAMPLE_RATES = [24e3, 22050, 16e3]; var AvcNalUnitType; (function(AvcNalUnitType2) { + AvcNalUnitType2[AvcNalUnitType2["NON_IDR_SLICE"] = 1] = "NON_IDR_SLICE"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPA"] = 2] = "SLICE_DPA"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPB"] = 3] = "SLICE_DPB"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPC"] = 4] = "SLICE_DPC"; AvcNalUnitType2[AvcNalUnitType2["IDR"] = 5] = "IDR"; AvcNalUnitType2[AvcNalUnitType2["SEI"] = 6] = "SEI"; AvcNalUnitType2[AvcNalUnitType2["SPS"] = 7] = "SPS"; AvcNalUnitType2[AvcNalUnitType2["PPS"] = 8] = "PPS"; + AvcNalUnitType2[AvcNalUnitType2["AUD"] = 9] = "AUD"; AvcNalUnitType2[AvcNalUnitType2["SPS_EXT"] = 13] = "SPS_EXT"; })(AvcNalUnitType || (AvcNalUnitType = {})); var HevcNalUnitType; @@ -816,48 +1541,46 @@ var HevcNalUnitType; HevcNalUnitType2[HevcNalUnitType2["VPS_NUT"] = 32] = "VPS_NUT"; HevcNalUnitType2[HevcNalUnitType2["SPS_NUT"] = 33] = "SPS_NUT"; HevcNalUnitType2[HevcNalUnitType2["PPS_NUT"] = 34] = "PPS_NUT"; + HevcNalUnitType2[HevcNalUnitType2["AUD_NUT"] = 35] = "AUD_NUT"; HevcNalUnitType2[HevcNalUnitType2["PREFIX_SEI_NUT"] = 39] = "PREFIX_SEI_NUT"; HevcNalUnitType2[HevcNalUnitType2["SUFFIX_SEI_NUT"] = 40] = "SUFFIX_SEI_NUT"; })(HevcNalUnitType || (HevcNalUnitType = {})); -const findNalUnitsInAnnexB = (packetData) => { - const nalUnits = []; +const iterateNalUnitsInAnnexB = function* (packetData) { let i = 0; - while (i < packetData.length) { - let startCodePos = -1; - let startCodeLength = 0; - for (let j = i; j < packetData.length - 3; j++) { - if (packetData[j] === 0 && packetData[j + 1] === 0 && packetData[j + 2] === 1) { - startCodePos = j; - startCodeLength = 3; - break; - } - if (j < packetData.length - 4 && packetData[j] === 0 && packetData[j + 1] === 0 && packetData[j + 2] === 0 && packetData[j + 3] === 1) { - startCodePos = j; - startCodeLength = 4; - break; - } - } - if (startCodePos === -1) { + let nalStart = -1; + while (i < packetData.length - 2) { + const zeroIndex = packetData.indexOf(0, i); + if (zeroIndex === -1 || zeroIndex >= packetData.length - 2) { break; } - if (i > 0 && startCodePos > i) { - const nalData = packetData.subarray(i, startCodePos); - if (nalData.length > 0) { - nalUnits.push(nalData); - } + i = zeroIndex; + let startCodeLength = 0; + if (i + 3 < packetData.length && packetData[i + 1] === 0 && packetData[i + 2] === 0 && packetData[i + 3] === 1) { + startCodeLength = 4; + } else if (packetData[i + 1] === 0 && packetData[i + 2] === 1) { + startCodeLength = 3; } - i = startCodePos + startCodeLength; - } - if (i < packetData.length) { - const nalData = packetData.subarray(i); - if (nalData.length > 0) { - nalUnits.push(nalData); + if (startCodeLength === 0) { + i++; + continue; } + if (nalStart !== -1 && i > nalStart) { + yield { + offset: nalStart, + length: i - nalStart + }; + } + nalStart = i + startCodeLength; + i = nalStart; + } + if (nalStart !== -1 && nalStart < packetData.length) { + yield { + offset: nalStart, + length: packetData.length - nalStart + }; } - return nalUnits; }; -const findNalUnitsInLengthPrefixed = (packetData, lengthSize) => { - const nalUnits = []; +const iterateNalUnitsInLengthPrefixed = function* (packetData, lengthSize) { let offset = 0; const dataView = new DataView(packetData.buffer, packetData.byteOffset, packetData.byteLength); while (offset + lengthSize <= packetData.length) { @@ -868,18 +1591,30 @@ const findNalUnitsInLengthPrefixed = (packetData, lengthSize) => { nalUnitLength = dataView.getUint16(offset, false); } else if (lengthSize === 3) { nalUnitLength = getUint24(dataView, offset, false); - } else if (lengthSize === 4) { - nalUnitLength = dataView.getUint32(offset, false); } else { - assertNever(lengthSize); - assert(false); + assert(lengthSize === 4); + nalUnitLength = dataView.getUint32(offset, false); } offset += lengthSize; - const nalUnit = packetData.subarray(offset, offset + nalUnitLength); - nalUnits.push(nalUnit); + yield { + offset, + length: nalUnitLength + }; offset += nalUnitLength; } - return nalUnits; +}; +const iterateAvcNalUnits = (packetData, decoderConfig) => { + if (decoderConfig.description) { + const bytes = toUint8Array(decoderConfig.description); + const lengthSizeMinusOne = bytes[4] & 3; + const lengthSize = lengthSizeMinusOne + 1; + return iterateNalUnitsInLengthPrefixed(packetData, lengthSize); + } else { + return iterateNalUnitsInAnnexB(packetData); + } +}; +const extractNalUnitTypeForAvc = (byte) => { + return byte & 31; }; const removeEmulationPreventionBytes = (data) => { const result = []; @@ -933,16 +1668,6 @@ const concatNalUnitsInLengthPrefixed = (nalUnits, lengthSize) => { } return result; }; -const extractAvcNalUnits = (packetData, decoderConfig) => { - if (decoderConfig.description) { - const bytes = toUint8Array(decoderConfig.description); - const lengthSizeMinusOne = bytes[4] & 3; - const lengthSize = lengthSizeMinusOne + 1; - return findNalUnitsInLengthPrefixed(packetData, lengthSize); - } else { - return findNalUnitsInAnnexB(packetData); - } -}; const concatAvcNalUnits = (nalUnits, decoderConfig) => { if (decoderConfig.description) { const bytes = toUint8Array(decoderConfig.description); @@ -953,15 +1678,22 @@ const concatAvcNalUnits = (nalUnits, decoderConfig) => { return concatNalUnitsInAnnexB(nalUnits); } }; -const extractNalUnitTypeForAvc = (data) => { - return data[0] & 31; -}; const extractAvcDecoderConfigurationRecord = (packetData) => { try { - const nalUnits = findNalUnitsInAnnexB(packetData); - const spsUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.SPS); - const ppsUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.PPS); - const spsExtUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.SPS_EXT); + const spsUnits = []; + const ppsUnits = []; + const spsExtUnits = []; + for (const loc of iterateNalUnitsInAnnexB(packetData)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); + const type = extractNalUnitTypeForAvc(nalUnit[0]); + if (type === AvcNalUnitType.SPS) { + spsUnits.push(nalUnit); + } else if (type === AvcNalUnitType.PPS) { + ppsUnits.push(nalUnit); + } else if (type === AvcNalUnitType.SPS_EXT) { + spsExtUnits.push(nalUnit); + } + } if (spsUnits.length === 0) { return null; } @@ -1052,6 +1784,24 @@ const deserializeAvcDecoderConfigurationRecord = (data) => { return null; } }; +const AVC_HEVC_ASPECT_RATIO_IDC_TABLE = { + 1: { num: 1, den: 1 }, + 2: { num: 12, den: 11 }, + 3: { num: 10, den: 11 }, + 4: { num: 16, den: 11 }, + 5: { num: 40, den: 33 }, + 6: { num: 24, den: 11 }, + 7: { num: 20, den: 11 }, + 8: { num: 32, den: 11 }, + 9: { num: 80, den: 33 }, + 10: { num: 18, den: 11 }, + 11: { num: 15, den: 11 }, + 12: { num: 64, den: 33 }, + 13: { num: 160, den: 99 }, + 14: { num: 4, den: 3 }, + 15: { num: 3, den: 2 }, + 16: { num: 2, den: 1 } +}; const parseAvcSps = (sps) => { try { const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); @@ -1065,13 +1815,14 @@ const parseAvcSps = (sps) => { const constraintFlags = bitstream.readAlignedByte(); const levelIdc = bitstream.readAlignedByte(); readExpGolomb(bitstream); - let chromaFormatIdc = null; - let bitDepthLumaMinus8 = null; - let bitDepthChromaMinus8 = null; + let chromaFormatIdc = 1; + let bitDepthLumaMinus8 = 0; + let bitDepthChromaMinus8 = 0; + let separateColourPlaneFlag = 0; if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) { chromaFormatIdc = readExpGolomb(bitstream); if (chromaFormatIdc === 3) { - bitstream.skipBits(1); + separateColourPlaneFlag = bitstream.readBits(1); } bitDepthLumaMinus8 = readExpGolomb(bitstream); bitDepthChromaMinus8 = readExpGolomb(bitstream); @@ -1110,9 +1861,128 @@ const parseAvcSps = (sps) => { } readExpGolomb(bitstream); bitstream.skipBits(1); - readExpGolomb(bitstream); - readExpGolomb(bitstream); + const picWidthInMbsMinus1 = readExpGolomb(bitstream); + const picHeightInMapUnitsMinus1 = readExpGolomb(bitstream); + const codedWidth = 16 * (picWidthInMbsMinus1 + 1); + const codedHeight = 16 * (picHeightInMapUnitsMinus1 + 1); + let displayWidth = codedWidth; + let displayHeight = codedHeight; const frameMbsOnlyFlag = bitstream.readBits(1); + if (!frameMbsOnlyFlag) { + bitstream.skipBits(1); + } + bitstream.skipBits(1); + const frameCroppingFlag = bitstream.readBits(1); + if (frameCroppingFlag) { + const frameCropLeftOffset = readExpGolomb(bitstream); + const frameCropRightOffset = readExpGolomb(bitstream); + const frameCropTopOffset = readExpGolomb(bitstream); + const frameCropBottomOffset = readExpGolomb(bitstream); + let cropUnitX; + let cropUnitY; + const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0; + if (chromaArrayType === 0) { + cropUnitX = 1; + cropUnitY = 2 - frameMbsOnlyFlag; + } else { + const subWidthC = chromaFormatIdc === 3 ? 1 : 2; + const subHeightC = chromaFormatIdc === 1 ? 2 : 1; + cropUnitX = subWidthC; + cropUnitY = subHeightC * (2 - frameMbsOnlyFlag); + } + displayWidth -= cropUnitX * (frameCropLeftOffset + frameCropRightOffset); + displayHeight -= cropUnitY * (frameCropTopOffset + frameCropBottomOffset); + } + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let pixelAspectRatio = { num: 1, den: 1 }; + let numReorderFrames = null; + let maxDecFrameBuffering = null; + const vuiParametersPresentFlag = bitstream.readBits(1); + if (vuiParametersPresentFlag) { + const aspectRatioInfoPresentFlag = bitstream.readBits(1); + if (aspectRatioInfoPresentFlag) { + const aspectRatioIdc = bitstream.readBits(8); + if (aspectRatioIdc === 255) { + pixelAspectRatio = { + num: bitstream.readBits(16), + den: bitstream.readBits(16) + }; + } else { + const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspectRatioIdc]; + if (aspectRatio) { + pixelAspectRatio = aspectRatio; + } + } + } + const overscanInfoPresentFlag = bitstream.readBits(1); + if (overscanInfoPresentFlag) { + bitstream.skipBits(1); + } + const videoSignalTypePresentFlag = bitstream.readBits(1); + if (videoSignalTypePresentFlag) { + bitstream.skipBits(3); + fullRangeFlag = bitstream.readBits(1); + const colourDescriptionPresentFlag = bitstream.readBits(1); + if (colourDescriptionPresentFlag) { + colourPrimaries = bitstream.readBits(8); + transferCharacteristics = bitstream.readBits(8); + matrixCoefficients = bitstream.readBits(8); + } + } + const chromaLocInfoPresentFlag = bitstream.readBits(1); + if (chromaLocInfoPresentFlag) { + readExpGolomb(bitstream); + readExpGolomb(bitstream); + } + const timingInfoPresentFlag = bitstream.readBits(1); + if (timingInfoPresentFlag) { + bitstream.skipBits(32); + bitstream.skipBits(32); + bitstream.skipBits(1); + } + const nalHrdParametersPresentFlag = bitstream.readBits(1); + if (nalHrdParametersPresentFlag) { + skipAvcHrdParameters(bitstream); + } + const vclHrdParametersPresentFlag = bitstream.readBits(1); + if (vclHrdParametersPresentFlag) { + skipAvcHrdParameters(bitstream); + } + if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) { + bitstream.skipBits(1); + } + bitstream.skipBits(1); + const bitstreamRestrictionFlag = bitstream.readBits(1); + if (bitstreamRestrictionFlag) { + bitstream.skipBits(1); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + numReorderFrames = readExpGolomb(bitstream); + maxDecFrameBuffering = readExpGolomb(bitstream); + } + } + if (numReorderFrames === null) { + assert(maxDecFrameBuffering === null); + const constraintSet3Flag = constraintFlags & 16; + if ((profileIdc === 44 || profileIdc === 86 || profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244) && constraintSet3Flag) { + numReorderFrames = 0; + maxDecFrameBuffering = 0; + } else { + const picWidthInMbs = picWidthInMbsMinus1 + 1; + const picHeightInMapUnits = picHeightInMapUnitsMinus1 + 1; + const frameHeightInMbs = (2 - frameMbsOnlyFlag) * picHeightInMapUnits; + const levelInfo = AVC_LEVEL_TABLE.find((x) => x.level >= levelIdc) ?? last(AVC_LEVEL_TABLE); + const maxDpbFrames = Math.min(Math.floor(levelInfo.maxDpbMbs / (picWidthInMbs * frameHeightInMbs)), 16); + numReorderFrames = maxDpbFrames; + maxDecFrameBuffering = maxDpbFrames; + } + } + assert(maxDecFrameBuffering !== null); return { profileIdc, constraintFlags, @@ -1120,62 +1990,106 @@ const parseAvcSps = (sps) => { frameMbsOnlyFlag, chromaFormatIdc, bitDepthLumaMinus8, - bitDepthChromaMinus8 + bitDepthChromaMinus8, + codedWidth, + codedHeight, + displayWidth, + displayHeight, + pixelAspectRatio, + colourPrimaries, + matrixCoefficients, + transferCharacteristics, + fullRangeFlag, + numReorderFrames, + maxDecFrameBuffering }; } catch (error) { console.error("Error parsing AVC SPS:", error); return null; } }; -const extractHevcNalUnits = (packetData, decoderConfig) => { +const skipAvcHrdParameters = (bitstream) => { + const cpb_cnt_minus1 = readExpGolomb(bitstream); + bitstream.skipBits(4); + bitstream.skipBits(4); + for (let i = 0; i <= cpb_cnt_minus1; i++) { + readExpGolomb(bitstream); + readExpGolomb(bitstream); + bitstream.skipBits(1); + } + bitstream.skipBits(5); + bitstream.skipBits(5); + bitstream.skipBits(5); + bitstream.skipBits(5); +}; +const concatHevcNalUnits = (nalUnits, decoderConfig) => { if (decoderConfig.description) { const bytes = toUint8Array(decoderConfig.description); const lengthSizeMinusOne = bytes[21] & 3; const lengthSize = lengthSizeMinusOne + 1; - return findNalUnitsInLengthPrefixed(packetData, lengthSize); + return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize); } else { - return findNalUnitsInAnnexB(packetData); + return concatNalUnitsInAnnexB(nalUnits); } }; -const extractNalUnitTypeForHevc = (data) => { - return data[0] >> 1 & 63; +const iterateHevcNalUnits = (packetData, decoderConfig) => { + if (decoderConfig.description) { + const bytes = toUint8Array(decoderConfig.description); + const lengthSizeMinusOne = bytes[21] & 3; + const lengthSize = lengthSizeMinusOne + 1; + return iterateNalUnitsInLengthPrefixed(packetData, lengthSize); + } else { + return iterateNalUnitsInAnnexB(packetData); + } }; -const extractHevcDecoderConfigurationRecord = (packetData) => { +const extractNalUnitTypeForHevc = (byte) => { + return byte >> 1 & 63; +}; +const parseHevcSps = (sps) => { try { - const nalUnits = findNalUnitsInAnnexB(packetData); - const vpsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.VPS_NUT); - const spsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.SPS_NUT); - const ppsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.PPS_NUT); - const seiUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.PREFIX_SEI_NUT || extractNalUnitTypeForHevc(unit) === HevcNalUnitType.SUFFIX_SEI_NUT); - if (spsUnits.length === 0 || ppsUnits.length === 0) - return null; - const sps = spsUnits[0]; const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); bitstream.skipBits(16); bitstream.readBits(4); - const sps_max_sub_layers_minus1 = bitstream.readBits(3); - const sps_temporal_id_nesting_flag = bitstream.readBits(1); - const { general_profile_space, general_tier_flag, general_profile_idc, general_profile_compatibility_flags, general_constraint_indicator_flags, general_level_idc } = parseProfileTierLevel(bitstream, sps_max_sub_layers_minus1); + const spsMaxSubLayersMinus1 = bitstream.readBits(3); + const spsTemporalIdNestingFlag = bitstream.readBits(1); + const { general_profile_space, general_tier_flag, general_profile_idc, general_profile_compatibility_flags, general_constraint_indicator_flags, general_level_idc } = parseProfileTierLevel(bitstream, spsMaxSubLayersMinus1); readExpGolomb(bitstream); - const chroma_format_idc = readExpGolomb(bitstream); - if (chroma_format_idc === 3) - bitstream.skipBits(1); - readExpGolomb(bitstream); - readExpGolomb(bitstream); - if (bitstream.readBits(1)) { - readExpGolomb(bitstream); - readExpGolomb(bitstream); - readExpGolomb(bitstream); - readExpGolomb(bitstream); + const chromaFormatIdc = readExpGolomb(bitstream); + let separateColourPlaneFlag = 0; + if (chromaFormatIdc === 3) { + separateColourPlaneFlag = bitstream.readBits(1); } - const bit_depth_luma_minus8 = readExpGolomb(bitstream); - const bit_depth_chroma_minus8 = readExpGolomb(bitstream); + const picWidthInLumaSamples = readExpGolomb(bitstream); + const picHeightInLumaSamples = readExpGolomb(bitstream); + let displayWidth = picWidthInLumaSamples; + let displayHeight = picHeightInLumaSamples; + if (bitstream.readBits(1)) { + const confWinLeftOffset = readExpGolomb(bitstream); + const confWinRightOffset = readExpGolomb(bitstream); + const confWinTopOffset = readExpGolomb(bitstream); + const confWinBottomOffset = readExpGolomb(bitstream); + let subWidthC = 1; + let subHeightC = 1; + const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0; + if (chromaArrayType === 1) { + subWidthC = 2; + subHeightC = 2; + } else if (chromaArrayType === 2) { + subWidthC = 2; + subHeightC = 1; + } + displayWidth -= (confWinLeftOffset + confWinRightOffset) * subWidthC; + displayHeight -= (confWinTopOffset + confWinBottomOffset) * subHeightC; + } + const bitDepthLumaMinus8 = readExpGolomb(bitstream); + const bitDepthChromaMinus8 = readExpGolomb(bitstream); readExpGolomb(bitstream); - const sps_sub_layer_ordering_info_present_flag = bitstream.readBits(1); - const maxNum = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; - for (let i = maxNum; i <= sps_max_sub_layers_minus1; i++) { - readExpGolomb(bitstream); + const spsSubLayerOrderingInfoPresentFlag = bitstream.readBits(1); + const startI = spsSubLayerOrderingInfoPresentFlag ? 0 : spsMaxSubLayersMinus1; + let spsMaxNumReorderPics = 0; + for (let i = startI; i <= spsMaxSubLayersMinus1; i++) { readExpGolomb(bitstream); + spsMaxNumReorderPics = readExpGolomb(bitstream); readExpGolomb(bitstream); } readExpGolomb(bitstream); @@ -1198,21 +2112,83 @@ const extractHevcDecoderConfigurationRecord = (packetData) => { readExpGolomb(bitstream); bitstream.skipBits(1); } - const num_short_term_ref_pic_sets = readExpGolomb(bitstream); - skipAllStRefPicSets(bitstream, num_short_term_ref_pic_sets); + const numShortTermRefPicSets = readExpGolomb(bitstream); + skipAllStRefPicSets(bitstream, numShortTermRefPicSets); if (bitstream.readBits(1)) { - const num_long_term_ref_pics_sps = readExpGolomb(bitstream); - for (let i = 0; i < num_long_term_ref_pics_sps; i++) { + const numLongTermRefPicsSps = readExpGolomb(bitstream); + for (let i = 0; i < numLongTermRefPicsSps; i++) { readExpGolomb(bitstream); bitstream.skipBits(1); } } bitstream.skipBits(1); bitstream.skipBits(1); - let min_spatial_segmentation_idc = 0; + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let minSpatialSegmentationIdc = 0; + let pixelAspectRatio = { num: 1, den: 1 }; if (bitstream.readBits(1)) { - min_spatial_segmentation_idc = parseVuiForMinSpatialSegmentationIdc(bitstream, sps_max_sub_layers_minus1); + const vui = parseHevcVui(bitstream, spsMaxSubLayersMinus1); + pixelAspectRatio = vui.pixelAspectRatio; + colourPrimaries = vui.colourPrimaries; + transferCharacteristics = vui.transferCharacteristics; + matrixCoefficients = vui.matrixCoefficients; + fullRangeFlag = vui.fullRangeFlag; + minSpatialSegmentationIdc = vui.minSpatialSegmentationIdc; } + return { + displayWidth, + displayHeight, + pixelAspectRatio, + colourPrimaries, + transferCharacteristics, + matrixCoefficients, + fullRangeFlag, + maxDecFrameBuffering: spsMaxNumReorderPics + 1, + spsMaxSubLayersMinus1, + spsTemporalIdNestingFlag, + generalProfileSpace: general_profile_space, + generalTierFlag: general_tier_flag, + generalProfileIdc: general_profile_idc, + generalProfileCompatibilityFlags: general_profile_compatibility_flags, + generalConstraintIndicatorFlags: general_constraint_indicator_flags, + generalLevelIdc: general_level_idc, + chromaFormatIdc, + bitDepthLumaMinus8, + bitDepthChromaMinus8, + minSpatialSegmentationIdc + }; + } catch (error) { + console.error("Error parsing HEVC SPS:", error); + return null; + } +}; +const extractHevcDecoderConfigurationRecord = (packetData) => { + try { + const vpsUnits = []; + const spsUnits = []; + const ppsUnits = []; + const seiUnits = []; + for (const loc of iterateNalUnitsInAnnexB(packetData)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); + const type = extractNalUnitTypeForHevc(nalUnit[0]); + if (type === HevcNalUnitType.VPS_NUT) { + vpsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.SPS_NUT) { + spsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.PPS_NUT) { + ppsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.PREFIX_SEI_NUT || type === HevcNalUnitType.SUFFIX_SEI_NUT) { + seiUnits.push(nalUnit); + } + } + if (spsUnits.length === 0 || ppsUnits.length === 0) + return null; + const spsInfo = parseHevcSps(spsUnits[0]); + if (!spsInfo) + return null; let parallelismType = 0; if (ppsUnits.length > 0) { const pps = ppsUnits[0]; @@ -1275,28 +2251,28 @@ const extractHevcDecoderConfigurationRecord = (packetData) => { ...seiUnits.length ? [ { arrayCompleteness: 1, - nalUnitType: extractNalUnitTypeForHevc(seiUnits[0]), + nalUnitType: extractNalUnitTypeForHevc(seiUnits[0][0]), nalUnits: seiUnits } ] : [] ]; const record = { configurationVersion: 1, - generalProfileSpace: general_profile_space, - generalTierFlag: general_tier_flag, - generalProfileIdc: general_profile_idc, - generalProfileCompatibilityFlags: general_profile_compatibility_flags, - generalConstraintIndicatorFlags: general_constraint_indicator_flags, - generalLevelIdc: general_level_idc, - minSpatialSegmentationIdc: min_spatial_segmentation_idc, + generalProfileSpace: spsInfo.generalProfileSpace, + generalTierFlag: spsInfo.generalTierFlag, + generalProfileIdc: spsInfo.generalProfileIdc, + generalProfileCompatibilityFlags: spsInfo.generalProfileCompatibilityFlags, + generalConstraintIndicatorFlags: spsInfo.generalConstraintIndicatorFlags, + generalLevelIdc: spsInfo.generalLevelIdc, + minSpatialSegmentationIdc: spsInfo.minSpatialSegmentationIdc, parallelismType, - chromaFormatIdc: chroma_format_idc, - bitDepthLumaMinus8: bit_depth_luma_minus8, - bitDepthChromaMinus8: bit_depth_chroma_minus8, + chromaFormatIdc: spsInfo.chromaFormatIdc, + bitDepthLumaMinus8: spsInfo.bitDepthLumaMinus8, + bitDepthChromaMinus8: spsInfo.bitDepthChromaMinus8, avgFrameRate: 0, constantFrameRate: 0, - numTemporalLayers: sps_max_sub_layers_minus1 + 1, - temporalIdNested: sps_temporal_id_nesting_flag, + numTemporalLayers: spsInfo.spsMaxSubLayersMinus1 + 1, + temporalIdNested: spsInfo.spsTemporalIdNestingFlag, lengthSizeMinusOne: 3, arrays }; @@ -1408,12 +2384,25 @@ const skipStRefPicSet = (bitstream, stRpsIdx, num_short_term_ref_pic_sets, NumDe } return NumDeltaPocsThis; }; -const parseVuiForMinSpatialSegmentationIdc = (bitstream, sps_max_sub_layers_minus1) => { +const parseHevcVui = (bitstream, sps_max_sub_layers_minus1) => { + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let minSpatialSegmentationIdc = 0; + let pixelAspectRatio = { num: 1, den: 1 }; if (bitstream.readBits(1)) { const aspect_ratio_idc = bitstream.readBits(8); if (aspect_ratio_idc === 255) { - bitstream.readBits(16); - bitstream.readBits(16); + pixelAspectRatio = { + num: bitstream.readBits(16), + den: bitstream.readBits(16) + }; + } else { + const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspect_ratio_idc]; + if (aspectRatio) { + pixelAspectRatio = aspectRatio; + } } } if (bitstream.readBits(1)) { @@ -1421,11 +2410,11 @@ const parseVuiForMinSpatialSegmentationIdc = (bitstream, sps_max_sub_layers_minu } if (bitstream.readBits(1)) { bitstream.readBits(3); - bitstream.readBits(1); + fullRangeFlag = bitstream.readBits(1); if (bitstream.readBits(1)) { - bitstream.readBits(8); - bitstream.readBits(8); - bitstream.readBits(8); + colourPrimaries = bitstream.readBits(8); + transferCharacteristics = bitstream.readBits(8); + matrixCoefficients = bitstream.readBits(8); } } if (bitstream.readBits(1)) { @@ -1448,23 +2437,29 @@ const parseVuiForMinSpatialSegmentationIdc = (bitstream, sps_max_sub_layers_minu readExpGolomb(bitstream); } if (bitstream.readBits(1)) { - skipHrdParameters(bitstream, true, sps_max_sub_layers_minus1); + skipHevcHrdParameters(bitstream, true, sps_max_sub_layers_minus1); } } if (bitstream.readBits(1)) { bitstream.readBits(1); bitstream.readBits(1); bitstream.readBits(1); - const min_spatial_segmentation_idc = readExpGolomb(bitstream); + minSpatialSegmentationIdc = readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); - return min_spatial_segmentation_idc; } - return 0; + return { + pixelAspectRatio, + colourPrimaries, + transferCharacteristics, + matrixCoefficients, + fullRangeFlag, + minSpatialSegmentationIdc + }; }; -const skipHrdParameters = (bitstream, commonInfPresentFlag, maxNumSubLayersMinus1) => { +const skipHevcHrdParameters = (bitstream, commonInfPresentFlag, maxNumSubLayersMinus1) => { let nal_hrd_parameters_present_flag = false; let vcl_hrd_parameters_present_flag = false; let sub_pic_hrd_params_present_flag = false; @@ -1525,6 +2520,78 @@ const skipSubLayerHrdParameters = (bitstream, CpbCnt, sub_pic_hrd_params_present bitstream.readBits(1); } }; +var HevcNaluOrderState; +(function(HevcNaluOrderState2) { + HevcNaluOrderState2[HevcNaluOrderState2["audAllowed"] = 0] = "audAllowed"; + HevcNaluOrderState2[HevcNaluOrderState2["beforeFirstVcl"] = 1] = "beforeFirstVcl"; + HevcNaluOrderState2[HevcNaluOrderState2["afterFirstVcl"] = 2] = "afterFirstVcl"; + HevcNaluOrderState2[HevcNaluOrderState2["eoBitstreamAllowed"] = 3] = "eoBitstreamAllowed"; + HevcNaluOrderState2[HevcNaluOrderState2["noMoreDataAllowed"] = 4] = "noMoreDataAllowed"; +})(HevcNaluOrderState || (HevcNaluOrderState = {})); +const sanitizeHevcPacketForChromium = (packetData, decoderConfig) => { + const removedNalUnits = /* @__PURE__ */ new Set(); + let orderState = HevcNaluOrderState.audAllowed; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + if (orderState === HevcNaluOrderState.noMoreDataAllowed) { + removedNalUnits.add(loc.offset); + continue; + } + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (orderState === HevcNaluOrderState.eoBitstreamAllowed && type !== 37) { + removedNalUnits.add(loc.offset); + continue; + } + let remove = false; + if (type === 35) { + if (orderState > HevcNaluOrderState.audAllowed) { + remove = true; + } else { + orderState = HevcNaluOrderState.beforeFirstVcl; + } + } else if (type <= 31) { + if (orderState > HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.afterFirstVcl; + } + } else if (type === 36) { + if (orderState !== HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.eoBitstreamAllowed; + } + } else if (type === 37) { + if (orderState < HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.noMoreDataAllowed; + } + } else if (type === 32 || type === 33 || type === 34 || type === 39 || type >= 41 && type <= 44 || type >= 48 && type <= 55) { + if (orderState > HevcNaluOrderState.beforeFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.beforeFirstVcl; + } + } else if (type === 38 || type === 40 || type >= 45 && type <= 47 || type >= 56 && type <= 63) { + if (orderState < HevcNaluOrderState.afterFirstVcl) { + remove = true; + } + } + if (remove) { + removedNalUnits.add(loc.offset); + } + } + if (removedNalUnits.size === 0) { + return null; + } + const filteredNalUnits = []; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + if (!removedNalUnits.has(loc.offset)) { + filteredNalUnits.push(packetData.subarray(loc.offset, loc.offset + loc.length)); + } + } + return concatHevcNalUnits(filteredNalUnits, decoderConfig); +}; const extractVp9CodecInfoFromPacket = (packet) => { const bitstream = new Bitstream(packet); const frameMarker = bitstream.readBits(2); @@ -1929,14 +2996,17 @@ const parseModesFromVorbisSetupPacket = (setupHeader) => { const determineVideoPacketType = (codec, decoderConfig, packetData) => { switch (codec) { case "avc": { - const nalUnits = extractAvcNalUnits(packetData, decoderConfig); - let isKeyframe = nalUnits.some((x) => extractNalUnitTypeForAvc(x) === AvcNalUnitType.IDR); - if (!isKeyframe && (!isChromium() || getChromiumVersion() >= 144)) { - for (const nalUnit of nalUnits) { - const type = extractNalUnitTypeForAvc(nalUnit); - if (type !== AvcNalUnitType.SEI) { - continue; - } + for (const loc of iterateAvcNalUnits(packetData, decoderConfig)) { + const nalTypeByte = packetData[loc.offset]; + const type = extractNalUnitTypeForAvc(nalTypeByte); + if (type >= AvcNalUnitType.NON_IDR_SLICE && type <= AvcNalUnitType.SLICE_DPC) { + return "delta"; + } + if (type === AvcNalUnitType.IDR) { + return "key"; + } + if (type === AvcNalUnitType.SEI && (!isChromium() || getChromiumVersion() >= 144)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); const bytes = removeEmulationPreventionBytes(nalUnit); let pos = 1; do { @@ -1967,23 +3037,26 @@ const determineVideoPacketType = (codec, decoderConfig, packetData) => { const recoveryFrameCount = readExpGolomb(bitstream); const exactMatchFlag = bitstream.readBits(1); if (recoveryFrameCount === 0 && exactMatchFlag === 1) { - isKeyframe = true; - break; + return "key"; } } pos += payloadSize; } while (pos < bytes.length - 1); } } - return isKeyframe ? "key" : "delta"; + return "delta"; } case "hevc": { - const nalUnits = extractHevcNalUnits(packetData, decoderConfig); - const isKeyframe = nalUnits.some((x) => { - const type = extractNalUnitTypeForHevc(x); - return HevcNalUnitType.BLA_W_LP <= type && type <= HevcNalUnitType.RSV_IRAP_VCL23; - }); - return isKeyframe ? "key" : "delta"; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (type < HevcNalUnitType.BLA_W_LP) { + return "delta"; + } + if (type <= HevcNalUnitType.RSV_IRAP_VCL23) { + return "key"; + } + } + return "delta"; } case "vp8": { const frameType = packetData[0] & 1; @@ -2183,13 +3256,290 @@ const readVorbisComments = (bytes, metadataTags) => { } } }; +const AC3_ACMOD_CHANNEL_COUNTS = [2, 1, 2, 3, 3, 4, 4, 5]; +const parseAc3SyncFrame = (data) => { + if (data.length < 7) { + return null; + } + if (data[0] !== 11 || data[1] !== 119) { + return null; + } + const bitstream = new Bitstream(data); + bitstream.skipBits(16); + bitstream.skipBits(16); + const fscod = bitstream.readBits(2); + if (fscod === 3) { + return null; + } + const frmsizecod = bitstream.readBits(6); + const bsid = bitstream.readBits(5); + if (bsid > 8) { + return null; + } + const bsmod = bitstream.readBits(3); + const acmod = bitstream.readBits(3); + if ((acmod & 1) !== 0 && acmod !== 1) { + bitstream.skipBits(2); + } + if ((acmod & 4) !== 0) { + bitstream.skipBits(2); + } + if (acmod === 2) { + bitstream.skipBits(2); + } + const lfeon = bitstream.readBits(1); + const bitRateCode = Math.floor(frmsizecod / 2); + return { fscod, bsid, bsmod, acmod, lfeon, bitRateCode }; +}; +const AC3_FRAME_SIZES = [ + // frmsizecod, [48kHz, 44.1kHz, 32kHz] in bytes + 64 * 2, + 69 * 2, + 96 * 2, + 64 * 2, + 70 * 2, + 96 * 2, + 80 * 2, + 87 * 2, + 120 * 2, + 80 * 2, + 88 * 2, + 120 * 2, + 96 * 2, + 104 * 2, + 144 * 2, + 96 * 2, + 105 * 2, + 144 * 2, + 112 * 2, + 121 * 2, + 168 * 2, + 112 * 2, + 122 * 2, + 168 * 2, + 128 * 2, + 139 * 2, + 192 * 2, + 128 * 2, + 140 * 2, + 192 * 2, + 160 * 2, + 174 * 2, + 240 * 2, + 160 * 2, + 175 * 2, + 240 * 2, + 192 * 2, + 208 * 2, + 288 * 2, + 192 * 2, + 209 * 2, + 288 * 2, + 224 * 2, + 243 * 2, + 336 * 2, + 224 * 2, + 244 * 2, + 336 * 2, + 256 * 2, + 278 * 2, + 384 * 2, + 256 * 2, + 279 * 2, + 384 * 2, + 320 * 2, + 348 * 2, + 480 * 2, + 320 * 2, + 349 * 2, + 480 * 2, + 384 * 2, + 417 * 2, + 576 * 2, + 384 * 2, + 418 * 2, + 576 * 2, + 448 * 2, + 487 * 2, + 672 * 2, + 448 * 2, + 488 * 2, + 672 * 2, + 512 * 2, + 557 * 2, + 768 * 2, + 512 * 2, + 558 * 2, + 768 * 2, + 640 * 2, + 696 * 2, + 960 * 2, + 640 * 2, + 697 * 2, + 960 * 2, + 768 * 2, + 835 * 2, + 1152 * 2, + 768 * 2, + 836 * 2, + 1152 * 2, + 896 * 2, + 975 * 2, + 1344 * 2, + 896 * 2, + 976 * 2, + 1344 * 2, + 1024 * 2, + 1114 * 2, + 1536 * 2, + 1024 * 2, + 1115 * 2, + 1536 * 2, + 1152 * 2, + 1253 * 2, + 1728 * 2, + 1152 * 2, + 1254 * 2, + 1728 * 2, + 1280 * 2, + 1393 * 2, + 1920 * 2, + 1280 * 2, + 1394 * 2, + 1920 * 2 +]; +const AC3_SAMPLES_PER_FRAME = 1536; +const EAC3_NUMBLKS_TABLE = [1, 2, 3, 6]; +const parseEac3SyncFrame = (data) => { + if (data.length < 6) { + return null; + } + if (data[0] !== 11 || data[1] !== 119) { + return null; + } + const bitstream = new Bitstream(data); + bitstream.skipBits(16); + const strmtyp = bitstream.readBits(2); + bitstream.skipBits(3); + if (strmtyp !== 0 && strmtyp !== 2) { + return null; + } + const frmsiz = bitstream.readBits(11); + const fscod = bitstream.readBits(2); + let fscod2 = 0; + let numblkscod; + if (fscod === 3) { + fscod2 = bitstream.readBits(2); + numblkscod = 3; + } else { + numblkscod = bitstream.readBits(2); + } + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + const bsid = bitstream.readBits(5); + if (bsid < 11 || bsid > 16) { + return null; + } + const numblks = EAC3_NUMBLKS_TABLE[numblkscod]; + let fs; + if (fscod < 3) { + fs = AC3_SAMPLE_RATES[fscod] / 1e3; + } else { + fs = EAC3_REDUCED_SAMPLE_RATES[fscod2] / 1e3; + } + const dataRate = Math.round((frmsiz + 1) * fs / (numblks * 16)); + const bsmod = 0; + const numDepSub = 0; + const chanLoc = 0; + const substream = { + fscod, + fscod2, + bsid, + bsmod, + acmod, + lfeon, + numDepSub, + chanLoc + }; + return { + dataRate, + substreams: [substream] + }; +}; +const parseEac3Config = (data) => { + if (data.length < 2) { + return null; + } + const bitstream = new Bitstream(data); + const dataRate = bitstream.readBits(13); + const numIndSub = bitstream.readBits(3); + const substreams = []; + for (let i = 0; i <= numIndSub; i++) { + if (Math.ceil(bitstream.pos / 8) + 3 > data.length) { + break; + } + const fscod = bitstream.readBits(2); + const bsid = bitstream.readBits(5); + bitstream.skipBits(1); + bitstream.skipBits(1); + const bsmod = bitstream.readBits(3); + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + bitstream.skipBits(3); + const numDepSub = bitstream.readBits(4); + let chanLoc = 0; + if (numDepSub > 0) { + chanLoc = bitstream.readBits(9); + } else { + bitstream.skipBits(1); + } + substreams.push({ + fscod, + fscod2: null, + bsid, + bsmod, + acmod, + lfeon, + numDepSub, + chanLoc + }); + } + if (substreams.length === 0) { + return null; + } + return { dataRate, substreams }; +}; +const getEac3SampleRate = (config) => { + const sub = config.substreams[0]; + assert(sub); + if (sub.fscod < 3) { + return AC3_SAMPLE_RATES[sub.fscod]; + } else if (sub.fscod2 !== null && sub.fscod2 < 3) { + return EAC3_REDUCED_SAMPLE_RATES[sub.fscod2]; + } + return null; +}; +const getEac3ChannelCount = (config) => { + const sub = config.substreams[0]; + assert(sub); + let channels = AC3_ACMOD_CHANNEL_COUNTS[sub.acmod] + sub.lfeon; + if (sub.numDepSub > 0) { + const CHAN_LOC_COUNTS = [2, 2, 1, 1, 2, 2, 2, 1, 1]; + for (let bit = 0; bit < 9; bit++) { + if (sub.chanLoc & 1 << 8 - bit) { + channels += CHAN_LOC_COUNTS[bit]; + } + } + } + return channels; +}; class Demuxer { constructor(input) { this.input = input; } + dispose() { + } } -const customVideoDecoders = []; -const customAudioDecoders = []; const PLACEHOLDER_DATA = /* @__PURE__ */ new Uint8Array(0); class EncodedPacket { /** Creates a new {@link EncodedPacket} from raw bytes and timing information. */ @@ -2323,49 +3673,12569 @@ class EncodedPacket { chunk.copyTo(data); return new EncodedPacket(data, chunk.type, chunk.timestamp / 1e6, (chunk.duration ?? 0) / 1e6, void 0, void 0, sideData); } - /** Clones this packet while optionally updating timing information. */ + /** Clones this packet while optionally modifying the new packet's data. */ clone(options) { if (options !== void 0 && (typeof options !== "object" || options === null)) { throw new TypeError("options, when provided, must be an object."); } + if (options?.data !== void 0 && !(options.data instanceof Uint8Array)) { + throw new TypeError("options.data, when provided, must be a Uint8Array."); + } + if (options?.type !== void 0 && options.type !== "key" && options.type !== "delta") { + throw new TypeError('options.type, when provided, must be either "key" or "delta".'); + } if (options?.timestamp !== void 0 && !Number.isFinite(options.timestamp)) { throw new TypeError("options.timestamp, when provided, must be a number."); } if (options?.duration !== void 0 && !Number.isFinite(options.duration)) { throw new TypeError("options.duration, when provided, must be a number."); } - return new EncodedPacket(this.data, this.type, options?.timestamp ?? this.timestamp, options?.duration ?? this.duration, this.sequenceNumber, this.byteLength); + if (options?.sequenceNumber !== void 0 && !Number.isFinite(options.sequenceNumber)) { + throw new TypeError("options.sequenceNumber, when provided, must be a number."); + } + if (options?.sideData !== void 0 && (typeof options.sideData !== "object" || options.sideData === null)) { + throw new TypeError("options.sideData, when provided, must be an object."); + } + return new EncodedPacket(options?.data ?? this.data, options?.type ?? this.type, options?.timestamp ?? this.timestamp, options?.duration ?? this.duration, options?.sequenceNumber ?? this.sequenceNumber, this.byteLength, options?.sideData ?? this.sideData); } } -const fromUlaw = (u8) => { - const MULAW_BIAS = 33; - let sign = 0; - let position = 0; - let number = ~u8; - if (number & 128) { - number &= -129; - sign = -1; +const buildIsobmffMimeType = (info) => { + const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; + let string = base + (info.isQuickTime ? "quicktime" : "mp4"); + if (info.codecStrings.length > 0) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; } - position = ((number & 240) >> 4) + 5; - const decoded = (1 << position | (number & 15) << position - 4 | 1 << position - 5) - MULAW_BIAS; - return sign === 0 ? decoded : -decoded; + return string; }; -const fromAlaw = (u8) => { - let sign = 0; - let position = 0; - let number = u8 ^ 85; - if (number & 128) { - number &= -129; - sign = -1; +const parsePsshBoxContents = (contents) => { + const view = toDataView(contents); + let pos = 0; + const version = view.getUint8(pos); + pos += 1; + pos += 3; + const systemId = bytesToHexString(contents.subarray(pos, pos + 16)); + pos += 16; + let keyIds = null; + if (version > 0) { + const kidCount = view.getUint32(pos); + pos += 4; + if (kidCount > 0) { + keyIds = []; + for (let i = 0; i < kidCount; i++) { + keyIds.push(bytesToHexString(contents.subarray(pos, pos + 16))); + pos += 16; + } + } } - position = ((number & 240) >> 4) + 4; - let decoded = 0; - if (position !== 4) { - decoded = 1 << position | (number & 15) << position - 4 | 1 << position - 5; + const dataSize = view.getUint32(pos); + pos += 4; + return { + systemId, + keyIds, + data: contents.slice(pos, pos + dataSize) + }; +}; +const psshBoxesAreEqual = (a, b) => a.systemId === b.systemId && uint8ArraysAreEqual(a.data, b.data); +const MIN_BOX_HEADER_SIZE = 8; +const MAX_BOX_HEADER_SIZE = 16; +const readBoxHeader = (slice) => { + let totalSize = readU32Be(slice); + const name = readAscii(slice, 4); + let headerSize = 8; + const hasLargeSize = totalSize === 1; + if (hasLargeSize) { + totalSize = readU64Be(slice); + headerSize = 16; + } + const contentSize = totalSize - headerSize; + if (contentSize < 0) { + return null; + } + return { name, totalSize, headerSize, contentSize }; +}; +const readFixed_16_16 = (slice) => { + return readI32Be(slice) / 65536; +}; +const readFixed_2_30 = (slice) => { + return readI32Be(slice) / 1073741824; +}; +const readIsomVariableInteger = (slice) => { + let result = 0; + for (let i = 0; i < 4; i++) { + result <<= 7; + const nextByte = readU8(slice); + result |= nextByte & 127; + if ((nextByte & 128) === 0) { + break; + } + } + return result; +}; +const readMetadataStringShort = (slice) => { + let stringLength = readU16Be(slice); + slice.skip(2); + stringLength = Math.min(stringLength, slice.remainingLength); + return textDecoder.decode(readBytes(slice, stringLength)); +}; +const readDataBox = (slice) => { + const header = readBoxHeader(slice); + if (!header || header.name !== "data") { + return null; + } + if (slice.remainingLength < 8) { + return null; + } + const typeIndicator = readU32Be(slice); + slice.skip(4); + const data = readBytes(slice, header.contentSize - 8); + switch (typeIndicator) { + case 1: + return textDecoder.decode(data); + // UTF-8 + case 2: + return new TextDecoder("utf-16be").decode(data); + // UTF-16-BE + case 13: + return new RichImageData(data, "image/jpeg"); + case 14: + return new RichImageData(data, "image/png"); + case 27: + return new RichImageData(data, "image/bmp"); + default: + return data; + } +}; +const AES_128_BLOCK_SIZE = 16; +const Te4 = new Uint32Array(256); +const Td0 = new Uint32Array(256); +const Td1 = new Uint32Array(256); +const Td2 = new Uint32Array(256); +const Td3 = new Uint32Array(256); +const Td4 = new Uint32Array(256); +const rcon = new Uint32Array(10); +let tablesGenerated = false; +const generateAesTables = () => { + const sbox = new Uint8Array(256); + const log = new Uint8Array(256); + const pow = new Uint8Array(256); + for (let i = 0, p = 1; i < 256; i++) { + pow[i] = p; + log[p] = i; + p = p ^ p << 1 ^ (p & 128 ? 283 : 0); + } + const mul = (a, b) => a && b ? pow[(log[a] + log[b]) % 255] : 0; + sbox[0] = 99; + for (let i = 1; i < 256; i++) { + const x = pow[255 - log[i]]; + let s = x ^ x << 1 ^ x << 2 ^ x << 3 ^ x << 4; + s = s >>> 8 ^ s & 255 ^ 99; + sbox[i] = s; + } + for (let i = 0; i < 256; i++) { + const s = sbox[i]; + const is = sbox.indexOf(i); + Te4[i] = s << 24 | s << 16 | s << 8 | s; + Td4[i] = is << 24 | is << 16 | is << 8 | is; + const b0 = mul(is, 14); + const b1 = mul(is, 9); + const b2 = mul(is, 13); + const b3 = mul(is, 11); + const w = b0 << 24 | b1 << 16 | b2 << 8 | b3; + Td0[i] = w; + Td1[i] = w >>> 8 | w << 24; + Td2[i] = w >>> 16 | w << 16; + Td3[i] = w >>> 24 | w << 8; + } + let r = 1; + for (let i = 0; i < 10; i++) { + rcon[i] = r << 24; + r = r << 1 ^ (r & 128 ? 283 : 0); + } + tablesGenerated = true; +}; +class Aes128CbcContext { + constructor() { + this.roundkey = new Uint32Array(44); + this.iv = new Uint32Array(AES_128_BLOCK_SIZE / Uint32Array.BYTES_PER_ELEMENT); + this.in = new Uint8Array(AES_128_BLOCK_SIZE); + this.out = new Uint8Array(AES_128_BLOCK_SIZE); + this.inView = new DataView(this.in.buffer); + this.outView = new DataView(this.out.buffer); + } + init({ key, iv }) { + assert(key.byteLength === 16); + assert(iv.byteLength === 16); + if (!tablesGenerated) { + generateAesTables(); + } + const keyView = new DataView(key.buffer, key.byteOffset, key.byteLength); + const ivView = new DataView(iv.buffer, iv.byteOffset, iv.byteLength); + this.roundkey[0] = keyView.getUint32(0, false); + this.roundkey[1] = keyView.getUint32(4, false); + this.roundkey[2] = keyView.getUint32(8, false); + this.roundkey[3] = keyView.getUint32(12, false); + this.iv[0] = ivView.getUint32(0, false); + this.iv[1] = ivView.getUint32(4, false); + this.iv[2] = ivView.getUint32(8, false); + this.iv[3] = ivView.getUint32(12, false); + for (let index = 4; index < 44; index += 4) { + const temp = this.roundkey[index - 1]; + this.roundkey[index] = this.roundkey[index - 4] ^ Te4[temp >>> 16 & 255] & 4278190080 ^ Te4[temp >>> 8 & 255] & 16711680 ^ Te4[temp >>> 0 & 255] & 65280 ^ Te4[temp >>> 24 & 255] & 255 ^ rcon[index / 4 - 1]; + this.roundkey[index + 1] = this.roundkey[index - 3] ^ this.roundkey[index]; + this.roundkey[index + 2] = this.roundkey[index - 2] ^ this.roundkey[index + 1]; + this.roundkey[index + 3] = this.roundkey[index - 1] ^ this.roundkey[index + 2]; + } + for (let i = 0, j = 40; i < j; i += 4, j -= 4) { + for (let k = 0; k < 4; k++) { + const temp = this.roundkey[i + k]; + this.roundkey[i + k] = this.roundkey[j + k]; + this.roundkey[j + k] = temp; + } + } + for (let index = 4; index < 40; index += 4) { + for (let k = 0; k < 4; k++) { + const rk = this.roundkey[index + k]; + this.roundkey[index + k] = Td0[Te4[rk >>> 24 & 255] & 255] ^ Td1[Te4[rk >>> 16 & 255] & 255] ^ Td2[Te4[rk >>> 8 & 255] & 255] ^ Td3[Te4[rk >>> 0 & 255] & 255]; + } + } + } + decrypt() { + let s0 = this.inView.getUint32(0, false) ^ this.roundkey[0]; + let s1 = this.inView.getUint32(4, false) ^ this.roundkey[1]; + let s2 = this.inView.getUint32(8, false) ^ this.roundkey[2]; + let s3 = this.inView.getUint32(12, false) ^ this.roundkey[3]; + const temp0 = this.inView.getUint32(0, false); + const temp1 = this.inView.getUint32(4, false); + const temp2 = this.inView.getUint32(8, false); + const temp3 = this.inView.getUint32(12, false); + let t0, t1, t2, t3; + for (let round = 1; round < 10; round++) { + const offset = round * 4; + t0 = Td0[s0 >>> 24] ^ Td1[s3 >>> 16 & 255] ^ Td2[s2 >>> 8 & 255] ^ Td3[s1 & 255] ^ this.roundkey[offset]; + t1 = Td0[s1 >>> 24] ^ Td1[s0 >>> 16 & 255] ^ Td2[s3 >>> 8 & 255] ^ Td3[s2 & 255] ^ this.roundkey[offset + 1]; + t2 = Td0[s2 >>> 24] ^ Td1[s1 >>> 16 & 255] ^ Td2[s0 >>> 8 & 255] ^ Td3[s3 & 255] ^ this.roundkey[offset + 2]; + t3 = Td0[s3 >>> 24] ^ Td1[s2 >>> 16 & 255] ^ Td2[s1 >>> 8 & 255] ^ Td3[s0 & 255] ^ this.roundkey[offset + 3]; + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + const f0 = Td4[s0 >>> 24 & 255] & 4278190080 ^ Td4[s3 >>> 16 & 255] & 16711680 ^ Td4[s2 >>> 8 & 255] & 65280 ^ Td4[s1 >>> 0 & 255] & 255 ^ this.roundkey[40]; + const f1 = Td4[s1 >>> 24 & 255] & 4278190080 ^ Td4[s0 >>> 16 & 255] & 16711680 ^ Td4[s3 >>> 8 & 255] & 65280 ^ Td4[s2 >>> 0 & 255] & 255 ^ this.roundkey[41]; + const f2 = Td4[s2 >>> 24 & 255] & 4278190080 ^ Td4[s1 >>> 16 & 255] & 16711680 ^ Td4[s0 >>> 8 & 255] & 65280 ^ Td4[s3 >>> 0 & 255] & 255 ^ this.roundkey[42]; + const f3 = Td4[s3 >>> 24 & 255] & 4278190080 ^ Td4[s2 >>> 16 & 255] & 16711680 ^ Td4[s1 >>> 8 & 255] & 65280 ^ Td4[s0 >>> 0 & 255] & 255 ^ this.roundkey[43]; + this.outView.setUint32(0, f0 ^ this.iv[0], false); + this.outView.setUint32(4, f1 ^ this.iv[1], false); + this.outView.setUint32(8, f2 ^ this.iv[2], false); + this.outView.setUint32(12, f3 ^ this.iv[3], false); + this.iv[0] = temp0; + this.iv[1] = temp1; + this.iv[2] = temp2; + this.iv[3] = temp3; + } +} +const createAes128CbcDecryptStream = (reader, getInit, close) => { + let initted = false; + let pos = 0; + const CHUNK_SIZE = 2 ** 16; + const BLOCK_SIZE = 16; + const aesContext = new Aes128CbcContext(); + return new ReadableStream({ + pull: async (controller) => { + if (!initted) { + aesContext.init(await getInit()); + initted = true; + } + const requestedLength = CHUNK_SIZE + BLOCK_SIZE; + let nextSlice = reader.requestSliceRange(pos, 0, requestedLength); + if (nextSlice instanceof Promise) + nextSlice = await nextSlice; + if (!nextSlice || nextSlice.length === 0) { + throw new Error("Invalid ciphertext."); + } + const sliceLength = nextSlice.length; + if (sliceLength % 16 !== 0) { + throw new Error("Invalid ciphertext."); + } + const bytesToRead = sliceLength === requestedLength ? sliceLength - BLOCK_SIZE : sliceLength; + const input = readBytes(nextSlice, bytesToRead); + const output = new Uint8Array(bytesToRead); + for (let i = 0; i < bytesToRead; i += 16) { + aesContext.in.set(input.subarray(i, i + 16)); + aesContext.decrypt(); + output.set(aesContext.out, i); + } + if (bytesToRead < sliceLength) { + controller.enqueue(output); + pos += bytesToRead; + } else { + const paddingLength = output[bytesToRead - 1]; + if (paddingLength === 0 || paddingLength > 16) { + throw new Error("Invalid PKCS#7 padding. Incorrect key or corrupted data."); + } + const trimmedOutput = output.subarray(0, bytesToRead - paddingLength); + controller.enqueue(trimmedOutput); + controller.close(); + close(); + } + }, + cancel: () => { + close(); + } + }); +}; +class IsobmffDemuxer extends Demuxer { + constructor(input) { + super(input); + this.moovSlice = null; + this.currentTrack = null; + this.tracks = []; + this.metadataPromise = null; + this.movieTimescale = -1; + this.movieDurationInTimescale = -1; + this.isQuickTime = false; + this.metadataTags = {}; + this.currentMetadataKeys = null; + this.isFragmented = false; + this.fragmentTrackDefaults = []; + this.psshBoxes = []; + this.currentFragment = null; + this.lastReadFragment = null; + this.decryptionKeyCache = /* @__PURE__ */ new Map(); + this.reader = input._reader; + } + async getTrackBackings() { + await this.readMetadata(); + return this.tracks.map((track) => track.trackBacking); + } + async getMimeType() { + await this.readMetadata(); + const backings = await this.getTrackBackings(); + const codecStrings = await Promise.all(backings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildIsobmffMimeType({ + isQuickTime: this.isQuickTime, + hasVideo: this.tracks.some((x) => x.info?.type === "video"), + hasAudio: this.tracks.some((x) => x.info?.type === "audio"), + codecStrings: codecStrings.filter(Boolean) + }); + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } + readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let currentPos = 0; + let lookForMfraBox = false; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const startPos = currentPos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + if (boxInfo.name === "ftyp" || boxInfo.name === "styp") { + const majorBrand = readAscii(slice, 4); + this.isQuickTime = majorBrand === "qt "; + } else if (boxInfo.name === "moov") { + let moovSlice = this.reader.requestSlice(slice.filePos, boxInfo.contentSize); + if (moovSlice instanceof Promise) + moovSlice = await moovSlice; + if (!moovSlice) + break; + this.moovSlice = moovSlice; + this.readContiguousBoxes(this.moovSlice); + for (const track of this.tracks) { + const previousSegmentDurationsInSeconds = track.editListPreviousSegmentDurations / this.movieTimescale; + track.editListOffset -= Math.round(previousSegmentDurationsInSeconds * track.timescale); + } + lookForMfraBox = this.isFragmented && this.reader.fileSize !== null && this.reader.fileSize > startPos + boxInfo.totalSize; + break; + } else if (boxInfo.name === "moof") { + if (!this.input._initInput) { + throw new Error('"moof" box encountered with no "moov" box present; this file is likely a Segment as described in ISO/IEC 14496-12 Section 8.16. A separate init file that contains a "moov" box is required to read this file, please provide it using InputOptions.initInput.'); + } + const initDemuxer = await this.input._initInput._getDemuxer(); + if (initDemuxer.constructor !== IsobmffDemuxer) { + throw new Error("Init input must match the input's format."); + } + await initDemuxer.readMetadata(); + this.movieTimescale = initDemuxer.movieTimescale; + this.movieDurationInTimescale = initDemuxer.movieDurationInTimescale; + this.metadataTags = initDemuxer.metadataTags; + this.isFragmented = true; + this.fragmentTrackDefaults = initDemuxer.fragmentTrackDefaults; + this.psshBoxes = initDemuxer.psshBoxes; + for (const foreignTrack of initDemuxer.tracks) { + const track = { + id: foreignTrack.id, + demuxer: this, + trackBacking: null, + disposition: foreignTrack.disposition, + timescale: foreignTrack.timescale, + durationInMediaTimescale: foreignTrack.durationInMediaTimescale, + durationInMovieTimescale: foreignTrack.durationInMovieTimescale, + rotation: foreignTrack.rotation, + internalCodecId: foreignTrack.internalCodecId, + name: foreignTrack.name, + languageCode: foreignTrack.languageCode, + sampleTableByteOffset: null, + sampleTable: null, + fragmentLookupTable: [], + currentFragmentState: null, + fragmentPositionCache: [], + editListPreviousSegmentDurations: foreignTrack.editListPreviousSegmentDurations, + editListOffset: foreignTrack.editListOffset, + encryptionInfo: foreignTrack.encryptionInfo, + encryptionAuxInfo: null, + frmaCodecString: null, + info: foreignTrack.info + }; + if (foreignTrack.trackBacking) { + assert(track.info); + if (track.info.type === "video" && track.info.width !== -1) { + const videoTrack = track; + track.trackBacking = new IsobmffVideoTrackBacking(videoTrack); + this.tracks.push(track); + } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { + const audioTrack = track; + track.trackBacking = new IsobmffAudioTrackBacking(audioTrack); + this.tracks.push(track); + } + } + } + lookForMfraBox = false; + break; + } + currentPos = startPos + boxInfo.totalSize; + } + if (lookForMfraBox) { + assert(this.reader.fileSize !== null); + let lastWordSlice = this.reader.requestSlice(this.reader.fileSize - 4, 4); + if (lastWordSlice instanceof Promise) + lastWordSlice = await lastWordSlice; + assert(lastWordSlice); + const lastWord = readU32Be(lastWordSlice); + const potentialMfraPos = this.reader.fileSize - lastWord; + if (potentialMfraPos >= 0 && potentialMfraPos <= this.reader.fileSize - MAX_BOX_HEADER_SIZE) { + let mfraHeaderSlice = this.reader.requestSliceRange(potentialMfraPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (mfraHeaderSlice instanceof Promise) + mfraHeaderSlice = await mfraHeaderSlice; + if (mfraHeaderSlice) { + const boxInfo = readBoxHeader(mfraHeaderSlice); + if (boxInfo && boxInfo.name === "mfra") { + let mfraSlice = this.reader.requestSlice(mfraHeaderSlice.filePos, boxInfo.contentSize); + if (mfraSlice instanceof Promise) + mfraSlice = await mfraSlice; + if (mfraSlice) { + this.readContiguousBoxes(mfraSlice); + } + } + } + } + } + })()); + } + getSampleTableForTrack(internalTrack) { + if (internalTrack.sampleTable) { + return internalTrack.sampleTable; + } + const sampleTable = { + sampleTimingEntries: [], + sampleCompositionTimeOffsets: [], + sampleSizes: [], + keySampleIndices: null, + chunkOffsets: [], + sampleToChunk: [], + presentationTimestamps: null, + presentationTimestampIndexMap: null + }; + internalTrack.sampleTable = sampleTable; + if (internalTrack.sampleTableByteOffset === null) { + return sampleTable; + } + assert(this.moovSlice); + const stblContainerSlice = this.moovSlice.slice(internalTrack.sampleTableByteOffset); + this.currentTrack = internalTrack; + this.traverseBox(stblContainerSlice); + this.currentTrack = null; + const isPcmCodec = internalTrack.info?.type === "audio" && internalTrack.info.codec && PCM_AUDIO_CODECS.includes(internalTrack.info.codec); + if (isPcmCodec && sampleTable.sampleCompositionTimeOffsets.length === 0) { + assert(internalTrack.info?.type === "audio"); + const pcmInfo = parsePcmCodec(internalTrack.info.codec); + const newSampleTimingEntries = []; + const newSampleSizes = []; + for (let i = 0; i < sampleTable.sampleToChunk.length; i++) { + const chunkEntry = sampleTable.sampleToChunk[i]; + const nextEntry = sampleTable.sampleToChunk[i + 1]; + const chunkCount = (nextEntry ? nextEntry.startChunkIndex : sampleTable.chunkOffsets.length) - chunkEntry.startChunkIndex; + for (let j = 0; j < chunkCount; j++) { + const startSampleIndex = chunkEntry.startSampleIndex + j * chunkEntry.samplesPerChunk; + const endSampleIndex = startSampleIndex + chunkEntry.samplesPerChunk; + const startTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, startSampleIndex, (x) => x.startIndex); + const startTimingEntry = sampleTable.sampleTimingEntries[startTimingEntryIndex]; + const endTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, endSampleIndex, (x) => x.startIndex); + const endTimingEntry = sampleTable.sampleTimingEntries[endTimingEntryIndex]; + const firstSampleTimestamp = startTimingEntry.startDecodeTimestamp + (startSampleIndex - startTimingEntry.startIndex) * startTimingEntry.delta; + const lastSampleTimestamp = endTimingEntry.startDecodeTimestamp + (endSampleIndex - endTimingEntry.startIndex) * endTimingEntry.delta; + const delta = lastSampleTimestamp - firstSampleTimestamp; + const lastSampleTimingEntry = last(newSampleTimingEntries); + if (lastSampleTimingEntry && lastSampleTimingEntry.delta === delta) { + lastSampleTimingEntry.count++; + } else { + newSampleTimingEntries.push({ + startIndex: chunkEntry.startChunkIndex + j, + startDecodeTimestamp: firstSampleTimestamp, + count: 1, + delta + }); + } + const chunkSize = chunkEntry.samplesPerChunk * pcmInfo.sampleSize * internalTrack.info.numberOfChannels; + newSampleSizes.push(chunkSize); + } + chunkEntry.startSampleIndex = chunkEntry.startChunkIndex; + chunkEntry.samplesPerChunk = 1; + } + sampleTable.sampleTimingEntries = newSampleTimingEntries; + sampleTable.sampleSizes = newSampleSizes; + } + if (sampleTable.sampleCompositionTimeOffsets.length > 0) { + sampleTable.presentationTimestamps = []; + for (const entry of sampleTable.sampleTimingEntries) { + for (let i = 0; i < entry.count; i++) { + sampleTable.presentationTimestamps.push({ + presentationTimestamp: entry.startDecodeTimestamp + i * entry.delta, + sampleIndex: entry.startIndex + i + }); + } + } + for (const entry of sampleTable.sampleCompositionTimeOffsets) { + for (let i = 0; i < entry.count; i++) { + const sampleIndex = entry.startIndex + i; + const sample = sampleTable.presentationTimestamps[sampleIndex]; + if (!sample) { + continue; + } + sample.presentationTimestamp += entry.offset; + } + } + sampleTable.presentationTimestamps.sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); + sampleTable.presentationTimestampIndexMap = Array(sampleTable.presentationTimestamps.length).fill(-1); + for (let i = 0; i < sampleTable.presentationTimestamps.length; i++) { + sampleTable.presentationTimestampIndexMap[sampleTable.presentationTimestamps[i].sampleIndex] = i; + } + } + return sampleTable; + } + async readFragment(startPos) { + if (this.lastReadFragment?.moofOffset === startPos) { + return this.lastReadFragment; + } + let headerSlice = this.reader.requestSliceRange(startPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const moofBoxInfo = readBoxHeader(headerSlice); + assert(moofBoxInfo?.name === "moof"); + let entireSlice = this.reader.requestSlice(startPos, moofBoxInfo.totalSize); + if (entireSlice instanceof Promise) + entireSlice = await entireSlice; + assert(entireSlice); + this.traverseBox(entireSlice); + const fragment = this.lastReadFragment; + assert(fragment && fragment.moofOffset === startPos); + for (const [, trackData] of fragment.trackData) { + const track = trackData.track; + const { fragmentPositionCache } = track; + if (!trackData.startTimestampIsFinal) { + const lookupEntry = track.fragmentLookupTable.find((x) => x.moofOffset === fragment.moofOffset); + if (lookupEntry) { + offsetFragmentTrackDataByTimestamp(trackData, lookupEntry.timestamp); + } else { + const lastCacheIndex = binarySearchLessOrEqual(fragmentPositionCache, fragment.moofOffset - 1, (x) => x.moofOffset); + if (lastCacheIndex !== -1) { + const lastCache = fragmentPositionCache[lastCacheIndex]; + offsetFragmentTrackDataByTimestamp(trackData, lastCache.endTimestamp); + } + } + trackData.startTimestampIsFinal = true; + } + const insertionIndex = binarySearchLessOrEqual(fragmentPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); + if (insertionIndex === -1 || fragmentPositionCache[insertionIndex].moofOffset !== fragment.moofOffset) { + fragmentPositionCache.splice(insertionIndex + 1, 0, { + moofOffset: fragment.moofOffset, + startTimestamp: trackData.startTimestamp, + endTimestamp: trackData.endTimestamp + }); + } + if (trackData.encryptionAuxInfo && track.encryptionInfo) { + const entries = await resolveEncryptionAuxInfo(this.reader, track.encryptionInfo, trackData.encryptionAuxInfo); + for (let i = 0; i < Math.min(trackData.samples.length, entries.length); i++) { + const entry = entries[i]; + trackData.samples[i].encryption = entry; + } + } + } + return fragment; + } + readContiguousBoxes(slice) { + const startIndex = slice.filePos; + while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { + const foundBox = this.traverseBox(slice); + if (!foundBox) { + break; + } + } + } + // eslint-disable-next-line @stylistic/generator-star-spacing + *iterateContiguousBoxes(slice) { + const startIndex = slice.filePos; + while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { + const startPos = slice.filePos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + yield { boxInfo, slice }; + slice.filePos = startPos + boxInfo.totalSize; + } + } + traverseBox(slice) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G; + const startPos = slice.filePos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + return false; + } + const contentStartPos = slice.filePos; + const boxEndPos = startPos + boxInfo.totalSize; + switch (boxInfo.name) { + case "mdia": + case "minf": + case "dinf": + case "mfra": + case "edts": + case "sinf": + case "schi": + { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "mvhd": + { + const version = readU8(slice); + slice.skip(3); + if (version === 1) { + slice.skip(8 + 8); + this.movieTimescale = readU32Be(slice); + this.movieDurationInTimescale = readU64Be(slice); + } else { + slice.skip(4 + 4); + this.movieTimescale = readU32Be(slice); + this.movieDurationInTimescale = readU32Be(slice); + } + } + break; + case "trak": + { + const track = { + id: -1, + demuxer: this, + trackBacking: null, + disposition: { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }, + info: null, + timescale: -1, + durationInMovieTimescale: -1, + durationInMediaTimescale: -1, + rotation: 0, + internalCodecId: null, + name: null, + languageCode: UNDETERMINED_LANGUAGE, + sampleTableByteOffset: -1, + sampleTable: null, + fragmentLookupTable: [], + currentFragmentState: null, + fragmentPositionCache: [], + editListPreviousSegmentDurations: 0, + editListOffset: 0, + encryptionInfo: null, + encryptionAuxInfo: null, + frmaCodecString: null + }; + this.currentTrack = track; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + if (track.id !== -1 && track.timescale !== -1 && track.info !== null) { + if (track.info.type === "video" && track.info.width !== -1) { + const videoTrack = track; + track.trackBacking = new IsobmffVideoTrackBacking(videoTrack); + this.tracks.push(track); + } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { + const audioTrack = track; + track.trackBacking = new IsobmffAudioTrackBacking(audioTrack); + this.tracks.push(track); + } + } + this.currentTrack = null; + } + break; + case "tkhd": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + const flags = readU24Be(slice); + const trackEnabled = !!(flags & 1); + track.disposition.default = trackEnabled; + if (version === 0) { + slice.skip(8); + track.id = readU32Be(slice); + slice.skip(4); + track.durationInMovieTimescale = readU32Be(slice); + } else if (version === 1) { + slice.skip(16); + track.id = readU32Be(slice); + slice.skip(4); + track.durationInMovieTimescale = readU64Be(slice); + } else { + throw new Error(`Incorrect track header version ${version}.`); + } + slice.skip(2 * 4 + 2 + 2 + 2 + 2); + const matrix = [ + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice), + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice), + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice) + ]; + const rotation = normalizeRotation(roundToMultiple(extractRotationFromMatrix(matrix), 90)); + assert(rotation === 0 || rotation === 90 || rotation === 180 || rotation === 270); + track.rotation = rotation; + } + break; + case "elst": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + slice.skip(3); + let relevantEntryFound = false; + let previousSegmentDurations = 0; + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const segmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); + const mediaTime = version === 1 ? readI64Be(slice) : readI32Be(slice); + const mediaRate = readFixed_16_16(slice); + if (segmentDuration === 0) { + continue; + } + if (relevantEntryFound) { + console.warn("Unsupported edit list: multiple edits are not currently supported. Only using first edit."); + break; + } + if (mediaTime === -1) { + previousSegmentDurations += segmentDuration; + continue; + } + if (mediaRate !== 1) { + console.warn("Unsupported edit list entry: media rate must be 1."); + break; + } + track.editListPreviousSegmentDurations = previousSegmentDurations; + track.editListOffset = mediaTime; + relevantEntryFound = true; + } + } + break; + case "mdhd": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + slice.skip(3); + if (version === 0) { + slice.skip(8); + track.timescale = readU32Be(slice); + track.durationInMediaTimescale = readU32Be(slice); + } else if (version === 1) { + slice.skip(16); + track.timescale = readU32Be(slice); + track.durationInMediaTimescale = readU64Be(slice); + } + let language = readU16Be(slice); + if (language > 0) { + track.languageCode = ""; + for (let i = 0; i < 3; i++) { + track.languageCode = String.fromCharCode(96 + (language & 31)) + track.languageCode; + language >>= 5; + } + if (!isIso639Dash2LanguageCode(track.languageCode)) { + track.languageCode = UNDETERMINED_LANGUAGE; + } + } + } + break; + case "hdlr": + { + const track = this.currentTrack; + if (!track) { + break; + } + slice.skip(8); + const handlerType = readAscii(slice, 4); + if (handlerType === "vide") { + track.info = { + type: "video", + width: -1, + height: -1, + squarePixelWidth: -1, + squarePixelHeight: -1, + codec: null, + codecDescription: null, + colorSpace: null, + avcType: null, + avcCodecInfo: null, + hevcCodecInfo: null, + vp9CodecInfo: null, + av1CodecInfo: null + }; + } else if (handlerType === "soun") { + track.info = { + type: "audio", + numberOfChannels: -1, + sampleRate: -1, + codec: null, + codecDescription: null, + aacCodecInfo: null, + pcmLittleEndian: false, + pcmSampleSize: null + }; + } + } + break; + case "stbl": + { + const track = this.currentTrack; + if (!track) { + break; + } + track.sampleTableByteOffset = startPos; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "stsd": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (track.info === null || track.sampleTable) { + break; + } + const stsdVersion = readU8(slice); + slice.skip(3); + const entries = readU32Be(slice); + for (let i = 0; i < entries; i++) { + const sampleBoxStartPos = slice.filePos; + const sampleBoxInfo = readBoxHeader(slice); + if (!sampleBoxInfo) { + break; + } + track.internalCodecId = sampleBoxInfo.name; + const lowercaseBoxName = sampleBoxInfo.name.toLowerCase(); + if (track.info.type === "video") { + slice.skip(6 * 1 + 2 + 2 + 2 + 3 * 4); + track.info.width = readU16Be(slice); + track.info.height = readU16Be(slice); + track.info.squarePixelWidth = track.info.width; + track.info.squarePixelHeight = track.info.height; + slice.skip(4 + 4 + 4 + 2 + 32 + 2 + 2); + track.frmaCodecString = null; + this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); + const codecName = lowercaseBoxName === "encv" ? track.frmaCodecString : lowercaseBoxName; + track.frmaCodecString = null; + if (codecName === "avc1" || codecName === "avc3") { + track.info.codec = "avc"; + track.info.avcType = codecName === "avc1" ? 1 : 3; + } else if (codecName === "hvc1" || codecName === "hev1") { + track.info.codec = "hevc"; + } else if (codecName === "vp08") { + track.info.codec = "vp8"; + } else if (codecName === "vp09") { + track.info.codec = "vp9"; + } else if (codecName === "av01") { + track.info.codec = "av1"; + } else if (codecName === null) { + console.warn(`Unknown encrypted video codec due to missing frma box.`); + } else { + console.warn(`Unsupported video codec (sample entry type '${sampleBoxInfo.name}').`); + } + } else { + slice.skip(6 * 1 + 2); + const version = readU16Be(slice); + slice.skip(3 * 2); + let channelCount = readU16Be(slice); + let sampleSize = readU16Be(slice); + slice.skip(2 * 2); + let sampleRate = readU32Be(slice) / 65536; + let lpcmFlags = null; + if (stsdVersion === 0 && version > 0) { + if (version === 1) { + slice.skip(4); + sampleSize = 8 * readU32Be(slice); + slice.skip(2 * 4); + } else if (version === 2) { + slice.skip(4); + sampleRate = readF64Be(slice); + channelCount = readU32Be(slice); + slice.skip(4); + sampleSize = readU32Be(slice); + lpcmFlags = readU32Be(slice); + slice.skip(2 * 4); + } + } + track.info.numberOfChannels = channelCount; + track.info.sampleRate = sampleRate; + track.frmaCodecString = null; + this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); + const codecName = lowercaseBoxName === "enca" ? track.frmaCodecString : lowercaseBoxName; + track.frmaCodecString = null; + if (codecName === "mp4a") ; + else if (codecName === "opus") { + track.info.codec = "opus"; + track.info.sampleRate = OPUS_SAMPLE_RATE; + } else if (codecName === "flac") { + track.info.codec = "flac"; + } else if (codecName === "ulaw") { + track.info.codec = "ulaw"; + } else if (codecName === "alaw") { + track.info.codec = "alaw"; + } else if (codecName === "ac-3") { + track.info.codec = "ac3"; + } else if (codecName === "ec-3") { + track.info.codec = "eac3"; + } else if (codecName === "twos") { + if (sampleSize === 8) { + track.info.codec = "pcm-s8"; + } else if (sampleSize === 16) { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s16" : "pcm-s16be"; + } else { + console.warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`); + track.info.codec = null; + } + } else if (codecName === "sowt") { + if (sampleSize === 8) { + track.info.codec = "pcm-s8"; + } else if (sampleSize === 16) { + track.info.codec = "pcm-s16"; + } else { + console.warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`); + track.info.codec = null; + } + } else if (codecName === "raw ") { + track.info.codec = "pcm-u8"; + } else if (codecName === "in24") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s24" : "pcm-s24be"; + } else if (codecName === "in32") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s32" : "pcm-s32be"; + } else if (codecName === "fl32") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-f32" : "pcm-f32be"; + } else if (codecName === "fl64") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-f64" : "pcm-f64be"; + } else if (codecName === "ipcm") { + const pcmSampleSize = track.info.pcmSampleSize; + if (track.info.pcmLittleEndian) { + if (pcmSampleSize === 16) { + track.info.codec = "pcm-s16"; + } else if (pcmSampleSize === 24) { + track.info.codec = "pcm-s24"; + } else if (pcmSampleSize === 32) { + track.info.codec = "pcm-s32"; + } else { + console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } else { + if (pcmSampleSize === 16) { + track.info.codec = "pcm-s16be"; + } else if (pcmSampleSize === 24) { + track.info.codec = "pcm-s24be"; + } else if (pcmSampleSize === 32) { + track.info.codec = "pcm-s32be"; + } else { + console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } + } else if (codecName === "fpcm") { + const pcmSampleSize = track.info.pcmSampleSize; + if (track.info.pcmLittleEndian) { + if (pcmSampleSize === 32) { + track.info.codec = "pcm-f32"; + } else if (pcmSampleSize === 64) { + track.info.codec = "pcm-f64"; + } else { + console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } else { + if (pcmSampleSize === 32) { + track.info.codec = "pcm-f32be"; + } else if (pcmSampleSize === 64) { + track.info.codec = "pcm-f64be"; + } else { + console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } + } else if (codecName === "lpcm" && lpcmFlags !== null) { + const bytesPerSample = sampleSize + 7 >> 3; + const isFloat = Boolean(lpcmFlags & 1); + const isBigEndian = Boolean(lpcmFlags & 2); + const sFlags = lpcmFlags & 4 ? -1 : 0; + if (sampleSize > 0 && sampleSize <= 64) { + if (isFloat) { + if (sampleSize === 32) { + track.info.codec = isBigEndian ? "pcm-f32be" : "pcm-f32"; + } + } else { + if (sFlags & 1 << bytesPerSample - 1) { + if (bytesPerSample === 1) { + track.info.codec = "pcm-s8"; + } else if (bytesPerSample === 2) { + track.info.codec = isBigEndian ? "pcm-s16be" : "pcm-s16"; + } else if (bytesPerSample === 3) { + track.info.codec = isBigEndian ? "pcm-s24be" : "pcm-s24"; + } else if (bytesPerSample === 4) { + track.info.codec = isBigEndian ? "pcm-s32be" : "pcm-s32"; + } + } else { + if (bytesPerSample === 1) { + track.info.codec = "pcm-u8"; + } + } + } + } + if (track.info.codec === null) { + console.warn("Unsupported PCM format."); + } + } else if (codecName === null) { + console.warn(`Unknown encrypted audio codec due to missing frma box.`); + } else { + console.warn(`Unsupported audio codec (sample entry type '${sampleBoxInfo.name}').`); + } + } + slice.filePos = sampleBoxStartPos + sampleBoxInfo.totalSize; + } + } + break; + case "frma": + { + const track = this.currentTrack; + if (!track) { + break; + } + const format = readAscii(slice, 4); + const lowercase = format.toLowerCase(); + track.frmaCodecString = lowercase; + } + break; + case "schm": + { + const track = this.currentTrack; + if (!track) { + break; + } + slice.skip(4); + const schemeType = readAscii(slice, 4); + if (schemeType === "cenc" || schemeType === "cens" || schemeType === "cbcs") { + track.encryptionInfo = { + scheme: schemeType, + defaultKid: null, + defaultIsProtected: null, + defaultPerSampleIvSize: null, + defaultConstantIv: null, + defaultCryptByteBlock: null, + defaultSkipByteBlock: null + }; + } else { + console.warn(`Unsupported encryption scheme '${schemeType}'.`); + } + } + break; + case "tenc": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + const version = readU8(slice); + slice.skip(3); + slice.skip(1); + const patternByte = readU8(slice); + if (version > 0) { + track.encryptionInfo.defaultCryptByteBlock = patternByte >> 4; + track.encryptionInfo.defaultSkipByteBlock = patternByte & 15; + } else { + track.encryptionInfo.defaultCryptByteBlock = 0; + track.encryptionInfo.defaultSkipByteBlock = 0; + } + track.encryptionInfo.defaultIsProtected = readU8(slice) !== 0; + track.encryptionInfo.defaultPerSampleIvSize = readU8(slice); + track.encryptionInfo.defaultKid = bytesToHexString(readBytes(slice, 16)); + if (track.encryptionInfo.defaultIsProtected && track.encryptionInfo.defaultPerSampleIvSize === 0) { + const constantIvSize = readU8(slice); + const constantIv = new Uint8Array(16); + constantIv.set(readBytes(slice, constantIvSize), 0); + track.encryptionInfo.defaultConstantIv = constantIv; + } + } + break; + case "avcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info); + track.info.codecDescription = readBytes(slice, boxInfo.contentSize); + } + break; + case "hvcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info); + track.info.codecDescription = readBytes(slice, boxInfo.contentSize); + } + break; + case "vpcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + slice.skip(4); + const profile = readU8(slice); + const level = readU8(slice); + const thirdByte = readU8(slice); + const bitDepth = thirdByte >> 4; + const chromaSubsampling = thirdByte >> 1 & 7; + const videoFullRangeFlag = thirdByte & 1; + const colourPrimaries = readU8(slice); + const transferCharacteristics = readU8(slice); + const matrixCoefficients = readU8(slice); + track.info.vp9CodecInfo = { + profile, + level, + bitDepth, + chromaSubsampling, + videoFullRangeFlag, + colourPrimaries, + transferCharacteristics, + matrixCoefficients + }; + } + break; + case "av1C": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + slice.skip(1); + const secondByte = readU8(slice); + const profile = secondByte >> 5; + const level = secondByte & 31; + const thirdByte = readU8(slice); + const tier = thirdByte >> 7; + const highBitDepth = thirdByte >> 6 & 1; + const twelveBit = thirdByte >> 5 & 1; + const monochrome = thirdByte >> 4 & 1; + const chromaSubsamplingX = thirdByte >> 3 & 1; + const chromaSubsamplingY = thirdByte >> 2 & 1; + const chromaSamplePosition = thirdByte & 3; + const bitDepth = profile === 2 && highBitDepth ? twelveBit ? 12 : 10 : highBitDepth ? 10 : 8; + track.info.av1CodecInfo = { + profile, + level, + tier, + bitDepth, + monochrome, + chromaSubsamplingX, + chromaSubsamplingY, + chromaSamplePosition + }; + } + break; + case "colr": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + const colourType = readAscii(slice, 4); + if (colourType !== "nclx") { + break; + } + const colourPrimaries = readU16Be(slice); + const transferCharacteristics = readU16Be(slice); + const matrixCoefficients = readU16Be(slice); + const fullRangeFlag = Boolean(readU8(slice) & 128); + track.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients], + fullRange: fullRangeFlag + }; + } + break; + case "pasp": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + const num = readU32Be(slice); + const den = readU32Be(slice); + if (num > 0 && den > 0) { + if (num > den) { + track.info.squarePixelWidth = Math.round(track.info.width * num / den); + } else { + track.info.squarePixelHeight = Math.round(track.info.height * den / num); + } + } + } + break; + case "wave": + { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "esds": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(4); + const tag = readU8(slice); + assert(tag === 3); + readIsomVariableInteger(slice); + slice.skip(2); + const mixed = readU8(slice); + const streamDependenceFlag = (mixed & 128) !== 0; + const urlFlag = (mixed & 64) !== 0; + const ocrStreamFlag = (mixed & 32) !== 0; + if (streamDependenceFlag) { + slice.skip(2); + } + if (urlFlag) { + const urlLength = readU8(slice); + slice.skip(urlLength); + } + if (ocrStreamFlag) { + slice.skip(2); + } + const decoderConfigTag = readU8(slice); + assert(decoderConfigTag === 4); + const decoderConfigDescriptorLength = readIsomVariableInteger(slice); + const payloadStart = slice.filePos; + const objectTypeIndication = readU8(slice); + if (objectTypeIndication === 64 || objectTypeIndication === 103) { + track.info.codec = "aac"; + track.info.aacCodecInfo = { + isMpeg2: objectTypeIndication === 103, + objectType: null + }; + } else if (objectTypeIndication === 105 || objectTypeIndication === 107) { + track.info.codec = "mp3"; + } else if (objectTypeIndication === 221) { + track.info.codec = "vorbis"; + } else { + console.warn(`Unsupported audio codec (objectTypeIndication ${objectTypeIndication}) - discarding track.`); + } + slice.skip(1 + 3 + 4 + 4); + if (decoderConfigDescriptorLength > slice.filePos - payloadStart) { + const decoderSpecificInfoTag = readU8(slice); + assert(decoderSpecificInfoTag === 5); + const decoderSpecificInfoLength = readIsomVariableInteger(slice); + track.info.codecDescription = readBytes(slice, decoderSpecificInfoLength); + if (track.info.codec === "aac") { + const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); + if (audioSpecificConfig.numberOfChannels !== null) { + track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; + } + if (audioSpecificConfig.sampleRate !== null) { + track.info.sampleRate = audioSpecificConfig.sampleRate; + } + } + } + } + break; + case "enda": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + track.info.pcmLittleEndian = !!(readU16Be(slice) & 255); + } + break; + case "pcmC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(1 + 3); + const formatFlags = readU8(slice); + track.info.pcmLittleEndian = Boolean(formatFlags & 1); + track.info.pcmSampleSize = readU8(slice); + } + break; + case "dOps": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(1); + const outputChannelCount = readU8(slice); + const preSkip = readU16Be(slice); + const inputSampleRate = readU32Be(slice); + const outputGain = readI16Be(slice); + const channelMappingFamily = readU8(slice); + let channelMappingTable; + if (channelMappingFamily !== 0) { + channelMappingTable = readBytes(slice, 2 + outputChannelCount); + } else { + channelMappingTable = new Uint8Array(0); + } + const description = new Uint8Array(8 + 1 + 1 + 2 + 4 + 2 + 1 + channelMappingTable.byteLength); + const view = new DataView(description.buffer); + view.setUint32(0, 1332770163, false); + view.setUint32(4, 1214603620, false); + view.setUint8(8, 1); + view.setUint8(9, outputChannelCount); + view.setUint16(10, preSkip, true); + view.setUint32(12, inputSampleRate, true); + view.setInt16(16, outputGain, true); + view.setUint8(18, channelMappingFamily); + description.set(channelMappingTable, 19); + track.info.codecDescription = description; + track.info.numberOfChannels = outputChannelCount; + } + break; + case "dfLa": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(4); + const BLOCK_TYPE_MASK = 127; + const LAST_METADATA_BLOCK_FLAG_MASK = 128; + const startPos2 = slice.filePos; + while (slice.filePos < boxEndPos) { + const flagAndType = readU8(slice); + const metadataBlockLength = readU24Be(slice); + const type = flagAndType & BLOCK_TYPE_MASK; + if (type === FlacBlockType.STREAMINFO) { + slice.skip(10); + const word = readU32Be(slice); + const sampleRate = word >>> 12; + const numberOfChannels = (word >> 9 & 7) + 1; + track.info.sampleRate = sampleRate; + track.info.numberOfChannels = numberOfChannels; + slice.skip(20); + } else { + slice.skip(metadataBlockLength); + } + if (flagAndType & LAST_METADATA_BLOCK_FLAG_MASK) { + break; + } + } + const endPos = slice.filePos; + slice.filePos = startPos2; + const bytes = readBytes(slice, endPos - startPos2); + const description = new Uint8Array(4 + bytes.byteLength); + const view = new DataView(description.buffer); + view.setUint32(0, 1716281667, false); + description.set(bytes, 4); + track.info.codecDescription = description; + } + break; + case "dac3": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + const bytes = readBytes(slice, 3); + const bitstream = new Bitstream(bytes); + const fscod = bitstream.readBits(2); + bitstream.skipBits(5 + 3); + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + if (fscod < 3) { + track.info.sampleRate = AC3_SAMPLE_RATES[fscod]; + } + track.info.numberOfChannels = AC3_ACMOD_CHANNEL_COUNTS[acmod] + lfeon; + } + break; + case "dec3": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + const bytes = readBytes(slice, boxInfo.contentSize); + const config = parseEac3Config(bytes); + if (!config) { + console.warn("Invalid dec3 box contents, ignoring."); + break; + } + const sampleRate = getEac3SampleRate(config); + if (sampleRate !== null) { + track.info.sampleRate = sampleRate; + } + track.info.numberOfChannels = getEac3ChannelCount(config); + } + break; + case "stts": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + let currentIndex = 0; + let currentTimestamp = 0; + for (let i = 0; i < entryCount; i++) { + const sampleCount = readU32Be(slice); + const sampleDelta = readU32Be(slice); + track.sampleTable.sampleTimingEntries.push({ + startIndex: currentIndex, + startDecodeTimestamp: currentTimestamp, + count: sampleCount, + delta: sampleDelta + }); + currentIndex += sampleCount; + currentTimestamp += sampleCount * sampleDelta; + } + } + break; + case "ctts": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(1 + 3); + const entryCount = readU32Be(slice); + let sampleIndex = 0; + for (let i = 0; i < entryCount; i++) { + const sampleCount = readU32Be(slice); + const sampleOffset = readI32Be(slice); + track.sampleTable.sampleCompositionTimeOffsets.push({ + startIndex: sampleIndex, + count: sampleCount, + offset: sampleOffset + }); + sampleIndex += sampleCount; + } + } + break; + case "stsz": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const sampleSize = readU32Be(slice); + const sampleCount = readU32Be(slice); + if (sampleSize === 0) { + for (let i = 0; i < sampleCount; i++) { + const sampleSize2 = readU32Be(slice); + track.sampleTable.sampleSizes.push(sampleSize2); + } + } else { + track.sampleTable.sampleSizes.push(sampleSize); + } + } + break; + case "stz2": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + slice.skip(3); + const fieldSize = readU8(slice); + const sampleCount = readU32Be(slice); + const bytes = readBytes(slice, Math.ceil(sampleCount * fieldSize / 8)); + const bitstream = new Bitstream(bytes); + for (let i = 0; i < sampleCount; i++) { + const sampleSize = bitstream.readBits(fieldSize); + track.sampleTable.sampleSizes.push(sampleSize); + } + } + break; + case "stss": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + track.sampleTable.keySampleIndices = []; + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const sampleIndex = readU32Be(slice) - 1; + track.sampleTable.keySampleIndices.push(sampleIndex); + } + if (track.sampleTable.keySampleIndices[0] !== 0) { + track.sampleTable.keySampleIndices.unshift(0); + } + } + break; + case "stsc": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const startChunkIndex = readU32Be(slice) - 1; + const samplesPerChunk = readU32Be(slice); + const sampleDescriptionIndex = readU32Be(slice); + track.sampleTable.sampleToChunk.push({ + startSampleIndex: -1, + startChunkIndex, + samplesPerChunk, + sampleDescriptionIndex + }); + } + let startSampleIndex = 0; + for (let i = 0; i < track.sampleTable.sampleToChunk.length; i++) { + track.sampleTable.sampleToChunk[i].startSampleIndex = startSampleIndex; + if (i < track.sampleTable.sampleToChunk.length - 1) { + const nextChunk = track.sampleTable.sampleToChunk[i + 1]; + const chunkCount = nextChunk.startChunkIndex - track.sampleTable.sampleToChunk[i].startChunkIndex; + startSampleIndex += chunkCount * track.sampleTable.sampleToChunk[i].samplesPerChunk; + } + } + } + break; + case "stco": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const chunkOffset = readU32Be(slice); + track.sampleTable.chunkOffsets.push(chunkOffset); + } + } + break; + case "co64": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const chunkOffset = readU64Be(slice); + track.sampleTable.chunkOffsets.push(chunkOffset); + } + } + break; + case "mvex": + { + this.isFragmented = true; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "mehd": + { + const version = readU8(slice); + slice.skip(3); + const fragmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); + this.movieDurationInTimescale = fragmentDuration; + } + break; + case "trex": + { + slice.skip(4); + const trackId = readU32Be(slice); + const defaultSampleDescriptionIndex = readU32Be(slice); + const defaultSampleDuration = readU32Be(slice); + const defaultSampleSize = readU32Be(slice); + const defaultSampleFlags = readU32Be(slice); + this.fragmentTrackDefaults.push({ + trackId, + defaultSampleDescriptionIndex, + defaultSampleDuration, + defaultSampleSize, + defaultSampleFlags + }); + } + break; + case "tfra": + { + const version = readU8(slice); + slice.skip(3); + const trackId = readU32Be(slice); + const track = this.tracks.find((x) => x.id === trackId); + if (!track) { + break; + } + const word = readU32Be(slice); + const lengthSizeOfTrafNum = (word & 48) >> 4; + const lengthSizeOfTrunNum = (word & 12) >> 2; + const lengthSizeOfSampleNum = word & 3; + const functions = [readU8, readU16Be, readU24Be, readU32Be]; + const readTrafNum = functions[lengthSizeOfTrafNum]; + const readTrunNum = functions[lengthSizeOfTrunNum]; + const readSampleNum = functions[lengthSizeOfSampleNum]; + const numberOfEntries = readU32Be(slice); + for (let i = 0; i < numberOfEntries; i++) { + const time = version === 1 ? readU64Be(slice) : readU32Be(slice); + const moofOffset = version === 1 ? readU64Be(slice) : readU32Be(slice); + readTrafNum(slice); + readTrunNum(slice); + readSampleNum(slice); + track.fragmentLookupTable.push({ + timestamp: time, + moofOffset + }); + } + track.fragmentLookupTable.sort((a, b) => a.timestamp - b.timestamp); + for (let i = 0; i < track.fragmentLookupTable.length - 1; i++) { + const entry1 = track.fragmentLookupTable[i]; + const entry2 = track.fragmentLookupTable[i + 1]; + if (entry1.timestamp === entry2.timestamp) { + track.fragmentLookupTable.splice(i + 1, 1); + i--; + } + } + } + break; + case "moof": + { + this.currentFragment = { + moofOffset: startPos, + moofSize: boxInfo.totalSize, + implicitBaseDataOffset: startPos, + trackData: /* @__PURE__ */ new Map(), + psshBoxes: [] + }; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + this.lastReadFragment = this.currentFragment; + this.currentFragment = null; + } + break; + case "traf": + { + assert(this.currentFragment); + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + if (this.currentTrack) { + const trackData = this.currentFragment.trackData.get(this.currentTrack.id); + if (trackData) { + this.currentFragment.implicitBaseDataOffset = trackData.currentOffset; + trackData.presentationTimestamps = trackData.samples.map((x, i) => ({ presentationTimestamp: x.presentationTimestamp, sampleIndex: i })).sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); + for (let i = 0; i < trackData.presentationTimestamps.length; i++) { + const currentEntry = trackData.presentationTimestamps[i]; + const currentSample = trackData.samples[currentEntry.sampleIndex]; + if (trackData.firstKeyFrameTimestamp === null && currentSample.isKeyFrame) { + trackData.firstKeyFrameTimestamp = currentSample.presentationTimestamp; + } + if (i < trackData.presentationTimestamps.length - 1) { + const nextEntry = trackData.presentationTimestamps[i + 1]; + const duration = nextEntry.presentationTimestamp - currentEntry.presentationTimestamp; + currentSample.duration = duration; + } + } + const firstSample = trackData.samples[trackData.presentationTimestamps[0].sampleIndex]; + const lastSample = trackData.samples[last(trackData.presentationTimestamps).sampleIndex]; + trackData.startTimestamp = firstSample.presentationTimestamp; + trackData.endTimestamp = lastSample.presentationTimestamp + lastSample.duration; + const { currentFragmentState } = this.currentTrack; + assert(currentFragmentState); + if (currentFragmentState.startTimestamp !== null) { + offsetFragmentTrackDataByTimestamp(trackData, currentFragmentState.startTimestamp); + trackData.startTimestampIsFinal = true; + } + if (currentFragmentState.encryptionAuxInfo && !trackData.samples[0].encryption) { + trackData.encryptionAuxInfo = currentFragmentState.encryptionAuxInfo; + } + } + this.currentTrack.currentFragmentState = null; + this.currentTrack = null; + } + } + break; + case "pssh": + { + if (this.input._formatOptions.isobmff?._suppressPsshParsing) { + break; + } + const psshBox = parsePsshBoxContents(readBytes(slice, boxInfo.contentSize)); + if (this.currentFragment) { + this.currentFragment.psshBoxes.push(psshBox); + } else if (!this.currentTrack) { + this.psshBoxes.push(psshBox); + } + } + break; + case "tfhd": + { + assert(this.currentFragment); + slice.skip(1); + const flags = readU24Be(slice); + const baseDataOffsetPresent = Boolean(flags & 1); + const sampleDescriptionIndexPresent = Boolean(flags & 2); + const defaultSampleDurationPresent = Boolean(flags & 8); + const defaultSampleSizePresent = Boolean(flags & 16); + const defaultSampleFlagsPresent = Boolean(flags & 32); + const durationIsEmpty = Boolean(flags & 65536); + const defaultBaseIsMoof = Boolean(flags & 131072); + const trackId = readU32Be(slice); + const track = this.tracks.find((x) => x.id === trackId); + if (!track) { + break; + } + const defaults = this.fragmentTrackDefaults.find((x) => x.trackId === trackId); + this.currentTrack = track; + track.currentFragmentState = { + baseDataOffset: this.currentFragment.implicitBaseDataOffset, + sampleDescriptionIndex: defaults?.defaultSampleDescriptionIndex ?? null, + defaultSampleDuration: defaults?.defaultSampleDuration ?? null, + defaultSampleSize: defaults?.defaultSampleSize ?? null, + defaultSampleFlags: defaults?.defaultSampleFlags ?? null, + startTimestamp: null, + encryptionAuxInfo: null + }; + if (baseDataOffsetPresent) { + track.currentFragmentState.baseDataOffset = readU64Be(slice); + } else if (defaultBaseIsMoof) { + track.currentFragmentState.baseDataOffset = this.currentFragment.moofOffset; + } + if (sampleDescriptionIndexPresent) { + track.currentFragmentState.sampleDescriptionIndex = readU32Be(slice); + } + if (defaultSampleDurationPresent) { + track.currentFragmentState.defaultSampleDuration = readU32Be(slice); + } + if (defaultSampleSizePresent) { + track.currentFragmentState.defaultSampleSize = readU32Be(slice); + } + if (defaultSampleFlagsPresent) { + track.currentFragmentState.defaultSampleFlags = readU32Be(slice); + } + if (durationIsEmpty) { + track.currentFragmentState.defaultSampleDuration = 0; + } + } + break; + case "tfdt": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.currentFragmentState); + const version = readU8(slice); + slice.skip(3); + const baseMediaDecodeTime = version === 0 ? readU32Be(slice) : readU64Be(slice); + track.currentFragmentState.startTimestamp = baseMediaDecodeTime; + } + break; + case "trun": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(this.currentFragment); + assert(track.currentFragmentState); + const version = readU8(slice); + const flags = readU24Be(slice); + const dataOffsetPresent = Boolean(flags & 1); + const firstSampleFlagsPresent = Boolean(flags & 4); + const sampleDurationPresent = Boolean(flags & 256); + const sampleSizePresent = Boolean(flags & 512); + const sampleFlagsPresent = Boolean(flags & 1024); + const sampleCompositionTimeOffsetsPresent = Boolean(flags & 2048); + const sampleCount = readU32Be(slice); + let dataOffset = null; + if (dataOffsetPresent) { + dataOffset = readI32Be(slice); + } + let firstSampleFlags = null; + if (firstSampleFlagsPresent) { + firstSampleFlags = readU32Be(slice); + } + let trackData; + if (this.currentFragment.trackData.has(track.id)) { + trackData = this.currentFragment.trackData.get(track.id); + if (dataOffset !== null) { + trackData.currentOffset = track.currentFragmentState.baseDataOffset + dataOffset; + } + } else { + trackData = { + track, + currentTimestamp: 0, + currentOffset: track.currentFragmentState.baseDataOffset + (dataOffset ?? 0), + startTimestamp: 0, + endTimestamp: 0, + firstKeyFrameTimestamp: null, + samples: [], + presentationTimestamps: [], + startTimestampIsFinal: false, + encryptionAuxInfo: null + }; + this.currentFragment.trackData.set(track.id, trackData); + } + if (sampleCount === 0) { + this.currentFragment.implicitBaseDataOffset = trackData.currentOffset; + break; + } + for (let i = 0; i < sampleCount; i++) { + let sampleDuration; + if (sampleDurationPresent) { + sampleDuration = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleDuration !== null); + sampleDuration = track.currentFragmentState.defaultSampleDuration; + } + let sampleSize; + if (sampleSizePresent) { + sampleSize = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleSize !== null); + sampleSize = track.currentFragmentState.defaultSampleSize; + } + let sampleFlags; + if (sampleFlagsPresent) { + sampleFlags = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleFlags !== null); + sampleFlags = track.currentFragmentState.defaultSampleFlags; + } + if (i === 0 && firstSampleFlags !== null) { + sampleFlags = firstSampleFlags; + } + let sampleCompositionTimeOffset = 0; + if (sampleCompositionTimeOffsetsPresent) { + if (version === 0) { + sampleCompositionTimeOffset = readU32Be(slice); + } else { + sampleCompositionTimeOffset = readI32Be(slice); + } + } + const isKeyFrame = !(sampleFlags & 65536); + trackData.samples.push({ + presentationTimestamp: trackData.currentTimestamp + sampleCompositionTimeOffset, + duration: sampleDuration, + byteOffset: trackData.currentOffset, + byteSize: sampleSize, + isKeyFrame, + encryption: null + }); + trackData.currentOffset += sampleSize; + trackData.currentTimestamp += sampleDuration; + } + } + break; + case "saiz": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + slice.skip(1); + const flags = readU24Be(slice); + if (flags & 1) { + const auxInfoType = readAscii(slice, 4); + const auxInfoTypeParam = readU32Be(slice); + if (auxInfoType !== track.encryptionInfo.scheme || auxInfoTypeParam !== 0) { + break; + } + } + const defaultSampleInfoSize = readU8(slice); + const sampleCount = readU32Be(slice); + let sampleSizes = null; + if (defaultSampleInfoSize === 0 && sampleCount > 0) { + sampleSizes = readBytes(slice, sampleCount); + } + const aux = getOrCreateEncryptionAuxInfo(track); + aux.defaultSampleInfoSize = defaultSampleInfoSize; + aux.sampleSizes = sampleSizes; + aux.sampleCount = sampleCount; + } + break; + case "saio": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + const version = readU8(slice); + const flags = readU24Be(slice); + if (flags & 1) { + const auxInfoType = readAscii(slice, 4); + const auxInfoTypeParam = readU32Be(slice); + if (auxInfoType !== track.encryptionInfo.scheme || auxInfoTypeParam !== 0) { + break; + } + } + const entryCount = readU32Be(slice); + if (entryCount === 0) { + break; + } + if (entryCount > 1) { + console.warn("Multiple saio entries are not supported; using the first offset only."); + } + let offset = version === 0 ? readU32Be(slice) : Number(readU64Be(slice)); + if (this.currentFragment) { + offset += this.currentFragment.moofOffset; + } + const aux = getOrCreateEncryptionAuxInfo(track); + aux.offset = offset; + } + break; + case "senc": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + assert(this.currentFragment); + const trackData = this.currentFragment.trackData.get(track.id); + if (!trackData) { + break; + } + slice.skip(1); + const flags = readU24Be(slice); + const useSubsamples = Boolean(flags & 2); + const sampleCount = readU32Be(slice); + const ivSize = track.encryptionInfo.defaultPerSampleIvSize; + assert(ivSize !== null); + for (let i = 0; i < Math.min(sampleCount, trackData.samples.length); i++) { + const iv = new Uint8Array(16); + if (ivSize > 0) { + iv.set(readBytes(slice, ivSize), 0); + } else { + iv.set(track.encryptionInfo.defaultConstantIv, 0); + } + let subsamples = null; + if (useSubsamples) { + const subsampleCount = readU16Be(slice); + subsamples = []; + for (let j = 0; j < subsampleCount; j++) { + const clearLen = readU16Be(slice); + const protectedLen = readU32Be(slice); + subsamples.push({ clearLen, protectedLen }); + } + } + const sample = trackData.samples[i]; + sample.encryption = { iv, subsamples }; + } + } + break; + // Metadata section + // https://exiftool.org/TagNames/QuickTime.html + // https://mp4workshop.com/about + case "udta": + { + const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { + if (boxInfo2.name !== "meta" && !this.currentTrack) { + const startPos2 = slice2.filePos; + (_a = this.metadataTags).raw ?? (_a.raw = {}); + if (boxInfo2.name[0] === "©") { + (_b = this.metadataTags.raw)[_c = boxInfo2.name] ?? (_b[_c] = readMetadataStringShort(slice2)); + } else { + (_d = this.metadataTags.raw)[_e = boxInfo2.name] ?? (_d[_e] = readBytes(slice2, boxInfo2.contentSize)); + } + slice2.filePos = startPos2; + } + switch (boxInfo2.name) { + case "meta": + { + slice2.skip(-boxInfo2.headerSize); + this.traverseBox(slice2); + } + break; + case "©nam": + case "name": + { + if (this.currentTrack) { + this.currentTrack.name = textDecoder.decode(readBytes(slice2, boxInfo2.contentSize)); + } else { + (_f = this.metadataTags).title ?? (_f.title = readMetadataStringShort(slice2)); + } + } + break; + case "©des": + { + if (!this.currentTrack) { + (_g = this.metadataTags).description ?? (_g.description = readMetadataStringShort(slice2)); + } + } + break; + case "©ART": + { + if (!this.currentTrack) { + (_h = this.metadataTags).artist ?? (_h.artist = readMetadataStringShort(slice2)); + } + } + break; + case "©alb": + { + if (!this.currentTrack) { + (_i = this.metadataTags).album ?? (_i.album = readMetadataStringShort(slice2)); + } + } + break; + case "albr": + { + if (!this.currentTrack) { + (_j = this.metadataTags).albumArtist ?? (_j.albumArtist = readMetadataStringShort(slice2)); + } + } + break; + case "©gen": + { + if (!this.currentTrack) { + (_k = this.metadataTags).genre ?? (_k.genre = readMetadataStringShort(slice2)); + } + } + break; + case "©day": + { + if (!this.currentTrack) { + const date = new Date(readMetadataStringShort(slice2)); + if (!Number.isNaN(date.getTime())) { + (_l = this.metadataTags).date ?? (_l.date = date); + } + } + } + break; + case "©cmt": + { + if (!this.currentTrack) { + (_m = this.metadataTags).comment ?? (_m.comment = readMetadataStringShort(slice2)); + } + } + break; + case "©lyr": + { + if (!this.currentTrack) { + (_n = this.metadataTags).lyrics ?? (_n.lyrics = readMetadataStringShort(slice2)); + } + } + break; + } + } + } + break; + case "meta": + { + if (this.currentTrack) { + break; + } + const word = readU32Be(slice); + const isQuickTime = word !== 0; + this.currentMetadataKeys = /* @__PURE__ */ new Map(); + if (isQuickTime) { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } else { + this.readContiguousBoxes(slice.slice(contentStartPos + 4, boxInfo.contentSize - 4)); + } + this.currentMetadataKeys = null; + } + break; + case "keys": + { + if (!this.currentMetadataKeys) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const keySize = readU32Be(slice); + slice.skip(4); + const keyName = textDecoder.decode(readBytes(slice, keySize - 8)); + this.currentMetadataKeys.set(i + 1, keyName); + } + } + break; + case "ilst": + { + if (!this.currentMetadataKeys) { + break; + } + const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { + let metadataKey = boxInfo2.name; + const nameAsNumber = (metadataKey.charCodeAt(0) << 24) + (metadataKey.charCodeAt(1) << 16) + (metadataKey.charCodeAt(2) << 8) + metadataKey.charCodeAt(3); + if (this.currentMetadataKeys.has(nameAsNumber)) { + metadataKey = this.currentMetadataKeys.get(nameAsNumber); + } + const data = readDataBox(slice2); + (_o = this.metadataTags).raw ?? (_o.raw = {}); + (_p = this.metadataTags.raw)[metadataKey] ?? (_p[metadataKey] = data); + switch (metadataKey) { + case "©nam": + case "titl": + case "com.apple.quicktime.title": + case "title": + { + if (typeof data === "string") { + (_q = this.metadataTags).title ?? (_q.title = data); + } + } + break; + case "©des": + case "desc": + case "dscp": + case "com.apple.quicktime.description": + case "description": + { + if (typeof data === "string") { + (_r = this.metadataTags).description ?? (_r.description = data); + } + } + break; + case "©ART": + case "com.apple.quicktime.artist": + case "artist": + { + if (typeof data === "string") { + (_s = this.metadataTags).artist ?? (_s.artist = data); + } + } + break; + case "©alb": + case "albm": + case "com.apple.quicktime.album": + case "album": + { + if (typeof data === "string") { + (_t = this.metadataTags).album ?? (_t.album = data); + } + } + break; + case "aART": + case "album_artist": + { + if (typeof data === "string") { + (_u = this.metadataTags).albumArtist ?? (_u.albumArtist = data); + } + } + break; + case "©cmt": + case "com.apple.quicktime.comment": + case "comment": + { + if (typeof data === "string") { + (_v = this.metadataTags).comment ?? (_v.comment = data); + } + } + break; + case "©gen": + case "gnre": + case "com.apple.quicktime.genre": + case "genre": + { + if (typeof data === "string") { + (_w = this.metadataTags).genre ?? (_w.genre = data); + } + } + break; + case "©lyr": + case "lyrics": + { + if (typeof data === "string") { + (_x = this.metadataTags).lyrics ?? (_x.lyrics = data); + } + } + break; + case "©day": + case "rldt": + case "com.apple.quicktime.creationdate": + case "date": + { + if (typeof data === "string") { + const date = new Date(data); + if (!Number.isNaN(date.getTime())) { + (_y = this.metadataTags).date ?? (_y.date = date); + } + } + } + break; + case "covr": + case "com.apple.quicktime.artwork": + { + if (data instanceof RichImageData) { + (_z = this.metadataTags).images ?? (_z.images = []); + this.metadataTags.images.push({ + data: data.data, + kind: "coverFront", + mimeType: data.mimeType + }); + } else if (data instanceof Uint8Array) { + (_A = this.metadataTags).images ?? (_A.images = []); + this.metadataTags.images.push({ + data, + kind: "coverFront", + mimeType: "image/*" + }); + } + } + break; + case "track": + { + if (typeof data === "string") { + const parts = data.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + (_B = this.metadataTags).trackNumber ?? (_B.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + (_C = this.metadataTags).tracksTotal ?? (_C.tracksTotal = tracksTotal); + } + } + } + break; + case "trkn": + { + if (data instanceof Uint8Array && data.length >= 6) { + const view = toDataView(data); + const trackNumber = view.getUint16(2, false); + const tracksTotal = view.getUint16(4, false); + if (trackNumber > 0) { + (_D = this.metadataTags).trackNumber ?? (_D.trackNumber = trackNumber); + } + if (tracksTotal > 0) { + (_E = this.metadataTags).tracksTotal ?? (_E.tracksTotal = tracksTotal); + } + } + } + break; + case "disc": + case "disk": + { + if (data instanceof Uint8Array && data.length >= 6) { + const view = toDataView(data); + const discNumber = view.getUint16(2, false); + const discNumberMax = view.getUint16(4, false); + if (discNumber > 0) { + (_F = this.metadataTags).discNumber ?? (_F.discNumber = discNumber); + } + if (discNumberMax > 0) { + (_G = this.metadataTags).discsTotal ?? (_G.discsTotal = discNumberMax); + } + } + } + break; + } + } + } + break; + } + slice.filePos = boxEndPos; + return true; + } +} +class IsobmffTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.packetToSampleIndex = /* @__PURE__ */ new WeakMap(); + this.packetToFragmentLocation = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.internalTrack.id; + } + getNumber() { + const demuxer = this.internalTrack.demuxer; + const trackType = this.internalTrack.trackBacking.getType(); + let number = 0; + for (const track of demuxer.tracks) { + if (track.trackBacking.getType() === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.internalTrack.internalCodecId; + } + getName() { + return this.internalTrack.name; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getTimeResolution() { + return this.internalTrack.timescale; + } + isRelativeToUnixEpoch() { + return false; + } + getDisposition() { + return this.internalTrack.disposition; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const track = this.internalTrack; + if (track.durationInMediaTimescale <= 0) { + return null; + } + assert(track.trackBacking); + const firstPacket = await track.trackBacking.getFirstPacket({ metadataOnly: true }); + return (firstPacket?.timestamp ?? 0) + track.durationInMediaTimescale / track.timescale; + } + async getLiveRefreshInterval() { + return null; + } + async getFirstPacket(options) { + const regularPacket = await this.fetchPacketForSampleIndex(0, options); + if (regularPacket || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup( + null, + (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData) { + return { + sampleIndex: 0, + correctSampleFound: true + }; + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + mapTimestampIntoTimescale(timestamp) { + return roundIfAlmostInteger(timestamp * this.internalTrack.timescale) + this.internalTrack.editListOffset; + } + async getPacket(timestamp, options) { + const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); + const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); + if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup(null, (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (!trackData) { + return { sampleIndex: -1, correctSampleFound: false }; + } + const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.presentationTimestamp); + const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; + const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { sampleIndex: sampleIndex2, correctSampleFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextPacket(packet, options) { + const regularSampleIndex = this.packetToSampleIndex.get(packet); + if (regularSampleIndex !== void 0) { + return this.fetchPacketForSampleIndex(regularSampleIndex + 1, options); + } + const locationInFragment = this.packetToFragmentLocation.get(packet); + if (locationInFragment === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performFragmentedLookup( + locationInFragment.fragment, + (fragment) => { + if (fragment === locationInFragment.fragment) { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (locationInFragment.sampleIndex + 1 < trackData.samples.length) { + return { + sampleIndex: locationInFragment.sampleIndex + 1, + correctSampleFound: true + }; + } + } else { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData) { + return { + sampleIndex: 0, + correctSampleFound: true + }; + } + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + async getKeyPacket(timestamp, options) { + const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleIndex = getKeyframeSampleIndexForTimestamp(sampleTable, timestampInTimescale); + const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); + if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup(null, (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (!trackData) { + return { sampleIndex: -1, correctSampleFound: false }; + } + const index = findLastIndex(trackData.presentationTimestamps, (x) => { + const sample = trackData.samples[x.sampleIndex]; + return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; + }); + const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; + const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { sampleIndex: sampleIndex2, correctSampleFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextKeyPacket(packet, options) { + const regularSampleIndex = this.packetToSampleIndex.get(packet); + if (regularSampleIndex !== void 0) { + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, regularSampleIndex); + return this.fetchPacketForSampleIndex(nextKeyFrameSampleIndex, options); + } + const locationInFragment = this.packetToFragmentLocation.get(packet); + if (locationInFragment === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performFragmentedLookup( + locationInFragment.fragment, + (fragment) => { + if (fragment === locationInFragment.fragment) { + const trackData = fragment.trackData.get(this.internalTrack.id); + const nextKeyFrameIndex = trackData.samples.findIndex((x, i) => x.isKeyFrame && i > locationInFragment.sampleIndex); + if (nextKeyFrameIndex !== -1) { + return { + sampleIndex: nextKeyFrameIndex, + correctSampleFound: true + }; + } + } else { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData && trackData.firstKeyFrameTimestamp !== null) { + const keyFrameIndex = trackData.samples.findIndex((x) => x.isKeyFrame); + assert(keyFrameIndex !== -1); + return { + sampleIndex: keyFrameIndex, + correctSampleFound: true + }; + } + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + async fetchPacketForSampleIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleInfo = getSampleInfo(sampleTable, sampleIndex); + if (!sampleInfo) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.internalTrack.demuxer.reader.requestSlice(sampleInfo.sampleOffset, sampleInfo.sampleSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, sampleInfo.sampleSize); + if (this.internalTrack.encryptionAuxInfo) { + assert(this.internalTrack.encryptionInfo); + const entries = await resolveEncryptionAuxInfo(this.internalTrack.demuxer.reader, this.internalTrack.encryptionInfo, this.internalTrack.encryptionAuxInfo); + if (sampleIndex < entries.length) { + data = await decryptSample(this.internalTrack, entries[sampleIndex], data, null); + } + } + } + const timestamp = (sampleInfo.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; + const duration = sampleInfo.duration / this.internalTrack.timescale; + const packet = new EncodedPacket(data, sampleInfo.isKeyFrame ? "key" : "delta", timestamp, duration, sampleIndex, sampleInfo.sampleSize); + this.packetToSampleIndex.set(packet, sampleIndex); + return packet; + } + async fetchPacketInFragment(fragment, sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const trackData = fragment.trackData.get(this.internalTrack.id); + const fragmentSample = trackData.samples[sampleIndex]; + assert(fragmentSample); + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.internalTrack.demuxer.reader.requestSlice(fragmentSample.byteOffset, fragmentSample.byteSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, fragmentSample.byteSize); + if (fragmentSample.encryption) { + data = await decryptSample(this.internalTrack, fragmentSample.encryption, data, fragment); + } + } + const timestamp = (fragmentSample.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; + const duration = fragmentSample.duration / this.internalTrack.timescale; + const packet = new EncodedPacket(data, fragmentSample.isKeyFrame ? "key" : "delta", timestamp, duration, fragment.moofOffset + sampleIndex, fragmentSample.byteSize); + this.packetToFragmentLocation.set(packet, { fragment, sampleIndex }); + return packet; + } + /** Looks for a packet in the fragments while trying to load as few fragments as possible to retrieve it. */ + async performFragmentedLookup(startFragment, getMatchInFragment, searchTimestamp, latestTimestamp, options) { + const demuxer = this.internalTrack.demuxer; + let currentFragment = null; + let bestFragment = null; + let bestSampleIndex = -1; + if (startFragment) { + const { sampleIndex, correctSampleFound } = getMatchInFragment(startFragment); + if (correctSampleFound) { + return this.fetchPacketInFragment(startFragment, sampleIndex, options); + } + if (sampleIndex !== -1) { + bestFragment = startFragment; + bestSampleIndex = sampleIndex; + } + } + const lookupEntryIndex = binarySearchLessOrEqual(this.internalTrack.fragmentLookupTable, searchTimestamp, (x) => x.timestamp); + const lookupEntry = lookupEntryIndex !== -1 ? this.internalTrack.fragmentLookupTable[lookupEntryIndex] : null; + const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.fragmentPositionCache, searchTimestamp, (x) => x.startTimestamp); + const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.fragmentPositionCache[positionCacheIndex] : null; + const lookupEntryPosition = Math.max(lookupEntry?.moofOffset ?? 0, positionCacheEntry?.moofOffset ?? 0) || null; + let currentPos; + if (!startFragment) { + currentPos = lookupEntryPosition ?? 0; + } else { + if (lookupEntryPosition === null || startFragment.moofOffset >= lookupEntryPosition) { + currentPos = startFragment.moofOffset + startFragment.moofSize; + currentFragment = startFragment; + } else { + currentPos = lookupEntryPosition; + } + } + while (true) { + if (currentFragment) { + const trackData = currentFragment.trackData.get(this.internalTrack.id); + if (trackData && trackData.startTimestamp > latestTimestamp) { + break; + } + } + let slice = demuxer.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const boxStartPos = currentPos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + if (boxInfo.name === "moof") { + currentFragment = await demuxer.readFragment(boxStartPos); + const { sampleIndex, correctSampleFound } = getMatchInFragment(currentFragment); + if (correctSampleFound) { + return this.fetchPacketInFragment(currentFragment, sampleIndex, options); + } + if (sampleIndex !== -1) { + bestFragment = currentFragment; + bestSampleIndex = sampleIndex; + } + } + currentPos = boxStartPos + boxInfo.totalSize; + } + if (lookupEntry && (!bestFragment || bestFragment.moofOffset < lookupEntry.moofOffset)) { + const previousLookupEntry = this.internalTrack.fragmentLookupTable[lookupEntryIndex - 1]; + assert(!previousLookupEntry || previousLookupEntry.timestamp < lookupEntry.timestamp); + const newSearchTimestamp = previousLookupEntry?.timestamp ?? -Infinity; + return this.performFragmentedLookup(null, getMatchInFragment, newSearchTimestamp, latestTimestamp, options); + } + if (bestFragment) { + return this.fetchPacketInFragment(bestFragment, bestSampleIndex, options); + } + return null; + } +} +class IsobmffVideoTrackBacking extends IsobmffTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfigPromise = null; + this.internalTrack = internalTrack; + } + getType() { + return "video"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getCodedWidth() { + return this.internalTrack.info.width; + } + getCodedHeight() { + return this.internalTrack.info.height; + } + getSquarePixelWidth() { + return this.internalTrack.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.internalTrack.info.squarePixelHeight; + } + getRotation() { + return this.internalTrack.rotation; + } + async getColorSpace() { + return { + primaries: this.internalTrack.info.colorSpace?.primaries, + transfer: this.internalTrack.info.colorSpace?.transfer, + matrix: this.internalTrack.info.colorSpace?.matrix, + fullRange: this.internalTrack.info.colorSpace?.fullRange + }; + } + async canBeTransparent() { + return false; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { + if (this.internalTrack.info.codec === "vp9" && !this.internalTrack.info.vp9CodecInfo) { + const firstPacket = await this.getFirstPacket({}); + this.internalTrack.info.vp9CodecInfo = firstPacket && extractVp9CodecInfoFromPacket(firstPacket.data); + } else if (this.internalTrack.info.codec === "av1" && !this.internalTrack.info.av1CodecInfo) { + const firstPacket = await this.getFirstPacket({}); + this.internalTrack.info.av1CodecInfo = firstPacket && extractAv1CodecInfoFromPacket(firstPacket.data); + } + const config = { + codec: extractVideoCodecString(this.internalTrack.info), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? void 0, + colorSpace: this.internalTrack.info.colorSpace ?? void 0 + }; + if (this.internalTrack.info.width !== this.internalTrack.info.squarePixelWidth || this.internalTrack.info.height !== this.internalTrack.info.squarePixelHeight) { + config.displayAspectWidth = this.internalTrack.info.squarePixelWidth; + config.displayAspectHeight = this.internalTrack.info.squarePixelHeight; + } + return config; + })()); + } +} +class IsobmffAudioTrackBacking extends IsobmffTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfig = null; + this.internalTrack = internalTrack; + } + getType() { + return "audio"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getNumberOfChannels() { + return this.internalTrack.info.numberOfChannels; + } + getSampleRate() { + return this.internalTrack.info.sampleRate; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfig ?? (this.decoderConfig = { + codec: extractAudioCodecString(this.internalTrack.info), + numberOfChannels: this.internalTrack.info.numberOfChannels, + sampleRate: this.internalTrack.info.sampleRate, + description: this.internalTrack.info.codecDescription ?? void 0 + }); + } +} +const getSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { + if (sampleTable.presentationTimestamps) { + const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); + if (index === -1) { + return -1; + } + return sampleTable.presentationTimestamps[index].sampleIndex; } else { - decoded = number << 1 | 1; + const index = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, timescaleUnits, (x) => x.startDecodeTimestamp); + if (index === -1) { + return -1; + } + const entry = sampleTable.sampleTimingEntries[index]; + return entry.startIndex + Math.min(Math.floor((timescaleUnits - entry.startDecodeTimestamp) / entry.delta), entry.count - 1); + } +}; +const getKeyframeSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { + if (!sampleTable.keySampleIndices) { + return getSampleIndexForTimestamp(sampleTable, timescaleUnits); + } + if (sampleTable.presentationTimestamps) { + const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); + if (index === -1) { + return -1; + } + for (let i = index; i >= 0; i--) { + const sampleIndex = sampleTable.presentationTimestamps[i].sampleIndex; + const isKeyFrame = binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1; + if (isKeyFrame) { + return sampleIndex; + } + } + return -1; + } else { + const sampleIndex = getSampleIndexForTimestamp(sampleTable, timescaleUnits); + const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); + return sampleTable.keySampleIndices[index] ?? -1; + } +}; +const getSampleInfo = (sampleTable, sampleIndex) => { + const timingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, sampleIndex, (x) => x.startIndex); + const timingEntry = sampleTable.sampleTimingEntries[timingEntryIndex]; + if (!timingEntry || timingEntry.startIndex + timingEntry.count <= sampleIndex) { + return null; + } + const decodeTimestamp = timingEntry.startDecodeTimestamp + (sampleIndex - timingEntry.startIndex) * timingEntry.delta; + let presentationTimestamp = decodeTimestamp; + const offsetEntryIndex = binarySearchLessOrEqual(sampleTable.sampleCompositionTimeOffsets, sampleIndex, (x) => x.startIndex); + const offsetEntry = sampleTable.sampleCompositionTimeOffsets[offsetEntryIndex]; + if (offsetEntry && sampleIndex - offsetEntry.startIndex < offsetEntry.count) { + presentationTimestamp += offsetEntry.offset; + } + const sampleSize = sampleTable.sampleSizes[Math.min(sampleIndex, sampleTable.sampleSizes.length - 1)]; + const chunkEntryIndex = binarySearchLessOrEqual(sampleTable.sampleToChunk, sampleIndex, (x) => x.startSampleIndex); + const chunkEntry = sampleTable.sampleToChunk[chunkEntryIndex]; + assert(chunkEntry); + const chunkIndex = chunkEntry.startChunkIndex + Math.floor((sampleIndex - chunkEntry.startSampleIndex) / chunkEntry.samplesPerChunk); + const chunkOffset = sampleTable.chunkOffsets[chunkIndex]; + const startSampleIndexOfChunk = chunkEntry.startSampleIndex + (chunkIndex - chunkEntry.startChunkIndex) * chunkEntry.samplesPerChunk; + let chunkSize = 0; + let sampleOffset = chunkOffset; + if (sampleTable.sampleSizes.length === 1) { + sampleOffset += sampleSize * (sampleIndex - startSampleIndexOfChunk); + chunkSize += sampleSize * chunkEntry.samplesPerChunk; + } else { + for (let i = startSampleIndexOfChunk; i < startSampleIndexOfChunk + chunkEntry.samplesPerChunk; i++) { + const sampleSize2 = sampleTable.sampleSizes[i]; + if (i < sampleIndex) { + sampleOffset += sampleSize2; + } + chunkSize += sampleSize2; + } + } + let duration = timingEntry.delta; + if (sampleTable.presentationTimestamps) { + const presentationIndex = sampleTable.presentationTimestampIndexMap[sampleIndex]; + assert(presentationIndex !== void 0); + if (presentationIndex < sampleTable.presentationTimestamps.length - 1) { + const nextEntry = sampleTable.presentationTimestamps[presentationIndex + 1]; + const nextPresentationTimestamp = nextEntry.presentationTimestamp; + duration = nextPresentationTimestamp - presentationTimestamp; + } + } + return { + presentationTimestamp, + duration, + sampleOffset, + sampleSize, + chunkOffset, + chunkSize, + isKeyFrame: sampleTable.keySampleIndices ? binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1 : true + }; +}; +const getNextKeyframeIndexForSample = (sampleTable, sampleIndex) => { + if (!sampleTable.keySampleIndices) { + return sampleIndex + 1; + } + const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); + return sampleTable.keySampleIndices[index + 1] ?? -1; +}; +const offsetFragmentTrackDataByTimestamp = (trackData, timestamp) => { + trackData.startTimestamp += timestamp; + trackData.endTimestamp += timestamp; + for (const sample of trackData.samples) { + sample.presentationTimestamp += timestamp; + } + for (const entry of trackData.presentationTimestamps) { + entry.presentationTimestamp += timestamp; + } +}; +const extractRotationFromMatrix = (matrix) => { + const [a, b] = matrix; + const radians = Math.atan2(b, a); + if (!Number.isFinite(radians)) { + return 0; + } + return radians * (180 / Math.PI); +}; +const sampleTableIsEmpty = (sampleTable) => { + return sampleTable.sampleSizes.length === 0; +}; +const getOrCreateEncryptionAuxInfo = (track) => { + var _a; + if (track.currentFragmentState) { + return (_a = track.currentFragmentState).encryptionAuxInfo ?? (_a.encryptionAuxInfo = { + defaultSampleInfoSize: 0, + sampleSizes: null, + sampleCount: 0, + offset: null, + resolved: null + }); + } else { + return track.encryptionAuxInfo ?? (track.encryptionAuxInfo = { + defaultSampleInfoSize: 0, + sampleSizes: null, + sampleCount: 0, + offset: null, + resolved: null + }); + } +}; +const resolveEncryptionAuxInfo = async (reader, encryptionInfo, aux) => { + if (aux.resolved) { + return aux.resolved; + } + if (aux.offset === null || aux.sampleCount === 0) { + throw new Error("Incomplete saiz/saio info; cannot resolve encryption data."); + } + let totalSize = 0; + if (aux.defaultSampleInfoSize > 0) { + totalSize = aux.defaultSampleInfoSize * aux.sampleCount; + } else { + assert(aux.sampleSizes); + for (let i = 0; i < aux.sampleCount; i++) { + totalSize += aux.sampleSizes[i]; + } + } + let slice = reader.requestSlice(aux.offset, totalSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + throw new Error("Failed to read auxiliary encryption info."); + } + const ivSize = encryptionInfo.defaultPerSampleIvSize; + assert(ivSize !== null); + const entries = []; + for (let i = 0; i < aux.sampleCount; i++) { + const entrySize = aux.defaultSampleInfoSize > 0 ? aux.defaultSampleInfoSize : aux.sampleSizes[i]; + const iv = new Uint8Array(16); + if (ivSize > 0) { + iv.set(readBytes(slice, ivSize), 0); + } else { + iv.set(encryptionInfo.defaultConstantIv, 0); + } + let subsamples = null; + if (entrySize > ivSize) { + const subsampleCount = readU16Be(slice); + subsamples = []; + for (let j = 0; j < subsampleCount; j++) { + const clearLen = readU16Be(slice); + const protectedLen = readU32Be(slice); + subsamples.push({ clearLen, protectedLen }); + } + } + entries.push({ iv, subsamples }); + } + aux.resolved = entries; + return entries; +}; +const decryptSample = async (track, sampleEncryption, data, fragment) => { + assert(track.encryptionInfo); + const encryptionInfo = track.encryptionInfo; + assert(encryptionInfo.defaultKid !== null); + const keyId = encryptionInfo.defaultKid; + let keyBytes; + const cacheEntry = track.demuxer.decryptionKeyCache.get(keyId); + if (cacheEntry) { + keyBytes = await cacheEntry; + } else { + if (!track.demuxer.input._formatOptions.isobmff?.resolveKeyId) { + throw new Error("Encrypted media samples encountered. To decrypt them, please provide a callback for InputOptions.formatOptions.isobmff.resolveKeyId."); + } + const promise = (async () => { + let psshBoxes = track.demuxer.psshBoxes; + if (fragment) { + psshBoxes = [ + ...psshBoxes, + ...fragment.psshBoxes + ].filter((x) => x.keyIds === null || x.keyIds.includes(keyId)); + for (let i = 0; i < psshBoxes.length - 1; i++) { + for (let j = i + 1; j < psshBoxes.length; j++) { + if (psshBoxesAreEqual(psshBoxes[i], psshBoxes[j])) { + psshBoxes.splice(j, 1); + j--; + } + } + } + } + const keyResult = await track.demuxer.input._formatOptions.isobmff.resolveKeyId({ keyId, psshBoxes }); + if (!(typeof keyResult === "string" && keyResult.length === 32 && HEX_STRING_REGEX.test(keyResult) || keyResult instanceof Uint8Array && keyResult.byteLength === 16)) { + throw new TypeError("resolveKeyId must return a 32-character hex string or a 16-byte Uint8Array containing the decryption key."); + } + return keyResult instanceof Uint8Array ? keyResult : hexStringToBytes(keyResult); + })(); + track.demuxer.decryptionKeyCache.set(keyId, promise); + keyBytes = await promise; + } + if (encryptionInfo.scheme === "cenc" || encryptionInfo.scheme === "cens") { + return decryptCtr(keyBytes, encryptionInfo, sampleEncryption, data); + } else { + return decryptCbcs(keyBytes, encryptionInfo, sampleEncryption, data); + } +}; +const decryptCtr = async (key, encryptionInfo, sampleEncryption, data) => { + const counter = new Uint8Array(16); + counter.set(sampleEncryption.iv, 0); + const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "AES-CTR" }, false, ["decrypt"]); + const cryptApply = async (input) => { + const plaintext = await crypto.subtle.decrypt({ name: "AES-CTR", counter, length: 64 }, cryptoKey, input); + return new Uint8Array(plaintext); + }; + if (!sampleEncryption.subsamples) { + return cryptApply(data); + } + assert(encryptionInfo.defaultCryptByteBlock !== null && encryptionInfo.defaultSkipByteBlock !== null); + const cryptRanges = collectCryptRanges(sampleEncryption.subsamples, encryptionInfo.defaultCryptByteBlock, encryptionInfo.defaultSkipByteBlock); + let totalCryptLen = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + totalCryptLen += seg.length; + } + } + const cryptBuffer = new Uint8Array(totalCryptLen); + let writePos = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + cryptBuffer.set(data.subarray(seg.offset, seg.offset + seg.length), writePos); + writePos += seg.length; + } + } + const plain = await cryptApply(cryptBuffer); + const output = new Uint8Array(data); + let readPos = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + output.set(plain.subarray(readPos, readPos + seg.length), seg.offset); + readPos += seg.length; + } + } + return output; +}; +const decryptCbcs = (key, encryptionInfo, sampleEncryption, data) => { + const ctx = new Aes128CbcContext(); + ctx.init({ key, iv: sampleEncryption.iv }); + const cryptByteBlock = encryptionInfo.defaultCryptByteBlock; + const skipByteBlock = encryptionInfo.defaultSkipByteBlock; + assert(cryptByteBlock !== null && skipByteBlock !== null); + if (!sampleEncryption.subsamples) { + const output2 = new Uint8Array(data); + const numBlocks = Math.floor(data.length / 16); + for (let b = 0; b < numBlocks; b++) { + const off = b * 16; + ctx.in.set(data.subarray(off, off + 16)); + ctx.decrypt(); + output2.set(ctx.out, off); + } + return output2; + } + if (cryptByteBlock === 0 && skipByteBlock === 0) { + throw new Error("cbcs with subsamples requires pattern encryption."); + } + const output = new Uint8Array(data); + const cryptRanges = collectCryptRanges(sampleEncryption.subsamples, cryptByteBlock, skipByteBlock); + const ivView = new DataView(sampleEncryption.iv.buffer, sampleEncryption.iv.byteOffset, 16); + for (const range of cryptRanges) { + ctx.iv[0] = ivView.getUint32(0, false); + ctx.iv[1] = ivView.getUint32(4, false); + ctx.iv[2] = ivView.getUint32(8, false); + ctx.iv[3] = ivView.getUint32(12, false); + for (const seg of range.perSubsample) { + const numBlocks = seg.length / 16; + for (let b = 0; b < numBlocks; b++) { + const offset = seg.offset + b * 16; + ctx.in.set(data.subarray(offset, offset + 16)); + ctx.decrypt(); + output.set(ctx.out, offset); + } + } + } + return output; +}; +const collectCryptRanges = (subsamples, cryptByteBlock, skipByteBlock) => { + const ranges = []; + const hasPattern = cryptByteBlock !== 0 || skipByteBlock !== 0; + let cursor = 0; + for (const subsample of subsamples) { + cursor += subsample.clearLen; + const perSubsample = []; + if (!hasPattern) { + if (subsample.protectedLen > 0) { + perSubsample.push({ offset: cursor, length: subsample.protectedLen }); + } + cursor += subsample.protectedLen; + } else { + let remaining = subsample.protectedLen; + let pos = cursor; + while (remaining > 0) { + if (remaining < 16 * cryptByteBlock) { + break; + } + const cryptBytes = 16 * cryptByteBlock; + perSubsample.push({ offset: pos, length: cryptBytes }); + pos += cryptBytes; + remaining -= cryptBytes; + const skipBytes = Math.min(16 * skipByteBlock, remaining); + pos += skipBytes; + remaining -= skipBytes; + } + cursor += subsample.protectedLen; + } + ranges.push({ perSubsample }); + } + return ranges; +}; +var EBMLId; +(function(EBMLId2) { + EBMLId2[EBMLId2["EBML"] = 440786851] = "EBML"; + EBMLId2[EBMLId2["EBMLVersion"] = 17030] = "EBMLVersion"; + EBMLId2[EBMLId2["EBMLReadVersion"] = 17143] = "EBMLReadVersion"; + EBMLId2[EBMLId2["EBMLMaxIDLength"] = 17138] = "EBMLMaxIDLength"; + EBMLId2[EBMLId2["EBMLMaxSizeLength"] = 17139] = "EBMLMaxSizeLength"; + EBMLId2[EBMLId2["DocType"] = 17026] = "DocType"; + EBMLId2[EBMLId2["DocTypeVersion"] = 17031] = "DocTypeVersion"; + EBMLId2[EBMLId2["DocTypeReadVersion"] = 17029] = "DocTypeReadVersion"; + EBMLId2[EBMLId2["Void"] = 236] = "Void"; + EBMLId2[EBMLId2["Segment"] = 408125543] = "Segment"; + EBMLId2[EBMLId2["SeekHead"] = 290298740] = "SeekHead"; + EBMLId2[EBMLId2["Seek"] = 19899] = "Seek"; + EBMLId2[EBMLId2["SeekID"] = 21419] = "SeekID"; + EBMLId2[EBMLId2["SeekPosition"] = 21420] = "SeekPosition"; + EBMLId2[EBMLId2["Duration"] = 17545] = "Duration"; + EBMLId2[EBMLId2["Info"] = 357149030] = "Info"; + EBMLId2[EBMLId2["TimestampScale"] = 2807729] = "TimestampScale"; + EBMLId2[EBMLId2["MuxingApp"] = 19840] = "MuxingApp"; + EBMLId2[EBMLId2["WritingApp"] = 22337] = "WritingApp"; + EBMLId2[EBMLId2["Tracks"] = 374648427] = "Tracks"; + EBMLId2[EBMLId2["TrackEntry"] = 174] = "TrackEntry"; + EBMLId2[EBMLId2["TrackNumber"] = 215] = "TrackNumber"; + EBMLId2[EBMLId2["TrackUID"] = 29637] = "TrackUID"; + EBMLId2[EBMLId2["TrackType"] = 131] = "TrackType"; + EBMLId2[EBMLId2["FlagEnabled"] = 185] = "FlagEnabled"; + EBMLId2[EBMLId2["FlagDefault"] = 136] = "FlagDefault"; + EBMLId2[EBMLId2["FlagForced"] = 21930] = "FlagForced"; + EBMLId2[EBMLId2["FlagOriginal"] = 21934] = "FlagOriginal"; + EBMLId2[EBMLId2["FlagHearingImpaired"] = 21931] = "FlagHearingImpaired"; + EBMLId2[EBMLId2["FlagVisualImpaired"] = 21932] = "FlagVisualImpaired"; + EBMLId2[EBMLId2["FlagCommentary"] = 21935] = "FlagCommentary"; + EBMLId2[EBMLId2["FlagLacing"] = 156] = "FlagLacing"; + EBMLId2[EBMLId2["Name"] = 21358] = "Name"; + EBMLId2[EBMLId2["Language"] = 2274716] = "Language"; + EBMLId2[EBMLId2["LanguageBCP47"] = 2274717] = "LanguageBCP47"; + EBMLId2[EBMLId2["CodecID"] = 134] = "CodecID"; + EBMLId2[EBMLId2["CodecPrivate"] = 25506] = "CodecPrivate"; + EBMLId2[EBMLId2["CodecDelay"] = 22186] = "CodecDelay"; + EBMLId2[EBMLId2["SeekPreRoll"] = 22203] = "SeekPreRoll"; + EBMLId2[EBMLId2["DefaultDuration"] = 2352003] = "DefaultDuration"; + EBMLId2[EBMLId2["Video"] = 224] = "Video"; + EBMLId2[EBMLId2["PixelWidth"] = 176] = "PixelWidth"; + EBMLId2[EBMLId2["PixelHeight"] = 186] = "PixelHeight"; + EBMLId2[EBMLId2["DisplayWidth"] = 21680] = "DisplayWidth"; + EBMLId2[EBMLId2["DisplayHeight"] = 21690] = "DisplayHeight"; + EBMLId2[EBMLId2["DisplayUnit"] = 21682] = "DisplayUnit"; + EBMLId2[EBMLId2["AlphaMode"] = 21440] = "AlphaMode"; + EBMLId2[EBMLId2["Audio"] = 225] = "Audio"; + EBMLId2[EBMLId2["SamplingFrequency"] = 181] = "SamplingFrequency"; + EBMLId2[EBMLId2["Channels"] = 159] = "Channels"; + EBMLId2[EBMLId2["BitDepth"] = 25188] = "BitDepth"; + EBMLId2[EBMLId2["SimpleBlock"] = 163] = "SimpleBlock"; + EBMLId2[EBMLId2["BlockGroup"] = 160] = "BlockGroup"; + EBMLId2[EBMLId2["Block"] = 161] = "Block"; + EBMLId2[EBMLId2["BlockAdditions"] = 30113] = "BlockAdditions"; + EBMLId2[EBMLId2["BlockMore"] = 166] = "BlockMore"; + EBMLId2[EBMLId2["BlockAdditional"] = 165] = "BlockAdditional"; + EBMLId2[EBMLId2["BlockAddID"] = 238] = "BlockAddID"; + EBMLId2[EBMLId2["BlockDuration"] = 155] = "BlockDuration"; + EBMLId2[EBMLId2["ReferenceBlock"] = 251] = "ReferenceBlock"; + EBMLId2[EBMLId2["Cluster"] = 524531317] = "Cluster"; + EBMLId2[EBMLId2["Timestamp"] = 231] = "Timestamp"; + EBMLId2[EBMLId2["Cues"] = 475249515] = "Cues"; + EBMLId2[EBMLId2["CuePoint"] = 187] = "CuePoint"; + EBMLId2[EBMLId2["CueTime"] = 179] = "CueTime"; + EBMLId2[EBMLId2["CueTrackPositions"] = 183] = "CueTrackPositions"; + EBMLId2[EBMLId2["CueTrack"] = 247] = "CueTrack"; + EBMLId2[EBMLId2["CueClusterPosition"] = 241] = "CueClusterPosition"; + EBMLId2[EBMLId2["Colour"] = 21936] = "Colour"; + EBMLId2[EBMLId2["MatrixCoefficients"] = 21937] = "MatrixCoefficients"; + EBMLId2[EBMLId2["TransferCharacteristics"] = 21946] = "TransferCharacteristics"; + EBMLId2[EBMLId2["Primaries"] = 21947] = "Primaries"; + EBMLId2[EBMLId2["Range"] = 21945] = "Range"; + EBMLId2[EBMLId2["Projection"] = 30320] = "Projection"; + EBMLId2[EBMLId2["ProjectionType"] = 30321] = "ProjectionType"; + EBMLId2[EBMLId2["ProjectionPoseRoll"] = 30325] = "ProjectionPoseRoll"; + EBMLId2[EBMLId2["Attachments"] = 423732329] = "Attachments"; + EBMLId2[EBMLId2["AttachedFile"] = 24999] = "AttachedFile"; + EBMLId2[EBMLId2["FileDescription"] = 18046] = "FileDescription"; + EBMLId2[EBMLId2["FileName"] = 18030] = "FileName"; + EBMLId2[EBMLId2["FileMediaType"] = 18016] = "FileMediaType"; + EBMLId2[EBMLId2["FileData"] = 18012] = "FileData"; + EBMLId2[EBMLId2["FileUID"] = 18094] = "FileUID"; + EBMLId2[EBMLId2["Chapters"] = 272869232] = "Chapters"; + EBMLId2[EBMLId2["Tags"] = 307544935] = "Tags"; + EBMLId2[EBMLId2["Tag"] = 29555] = "Tag"; + EBMLId2[EBMLId2["Targets"] = 25536] = "Targets"; + EBMLId2[EBMLId2["TargetTypeValue"] = 26826] = "TargetTypeValue"; + EBMLId2[EBMLId2["TargetType"] = 25546] = "TargetType"; + EBMLId2[EBMLId2["TagTrackUID"] = 25541] = "TagTrackUID"; + EBMLId2[EBMLId2["TagEditionUID"] = 25545] = "TagEditionUID"; + EBMLId2[EBMLId2["TagChapterUID"] = 25540] = "TagChapterUID"; + EBMLId2[EBMLId2["TagAttachmentUID"] = 25542] = "TagAttachmentUID"; + EBMLId2[EBMLId2["SimpleTag"] = 26568] = "SimpleTag"; + EBMLId2[EBMLId2["TagName"] = 17827] = "TagName"; + EBMLId2[EBMLId2["TagLanguage"] = 17530] = "TagLanguage"; + EBMLId2[EBMLId2["TagString"] = 17543] = "TagString"; + EBMLId2[EBMLId2["TagBinary"] = 17541] = "TagBinary"; + EBMLId2[EBMLId2["ContentEncodings"] = 28032] = "ContentEncodings"; + EBMLId2[EBMLId2["ContentEncoding"] = 25152] = "ContentEncoding"; + EBMLId2[EBMLId2["ContentEncodingOrder"] = 20529] = "ContentEncodingOrder"; + EBMLId2[EBMLId2["ContentEncodingScope"] = 20530] = "ContentEncodingScope"; + EBMLId2[EBMLId2["ContentCompression"] = 20532] = "ContentCompression"; + EBMLId2[EBMLId2["ContentCompAlgo"] = 16980] = "ContentCompAlgo"; + EBMLId2[EBMLId2["ContentCompSettings"] = 16981] = "ContentCompSettings"; + EBMLId2[EBMLId2["ContentEncryption"] = 20533] = "ContentEncryption"; +})(EBMLId || (EBMLId = {})); +const LEVEL_0_EBML_IDS = [ + EBMLId.EBML, + EBMLId.Segment +]; +const LEVEL_1_EBML_IDS = [ + EBMLId.SeekHead, + EBMLId.Info, + EBMLId.Cluster, + EBMLId.Tracks, + EBMLId.Cues, + EBMLId.Attachments, + EBMLId.Chapters, + EBMLId.Tags +]; +const LEVEL_0_AND_1_EBML_IDS = [ + ...LEVEL_0_EBML_IDS, + ...LEVEL_1_EBML_IDS +]; +const MAX_VAR_INT_SIZE = 8; +const MIN_HEADER_SIZE = 2; +const MAX_HEADER_SIZE = 2 * MAX_VAR_INT_SIZE; +const readVarIntSize = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + slice.skip(-1); + if (firstByte === 0) { + return null; + } + let width = 1; + let mask = 128; + while ((firstByte & mask) === 0) { + width++; + mask >>= 1; + } + if (slice.remainingLength < width) { + return null; + } + return width; +}; +const readVarInt = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + if (firstByte === 0) { + return null; + } + let width = 1; + let mask = 1 << 7; + while ((firstByte & mask) === 0) { + width++; + mask >>= 1; + } + if (slice.remainingLength < width - 1) { + return null; + } + let value = firstByte & mask - 1; + for (let i = 1; i < width; i++) { + value *= 1 << 8; + value += readU8(slice); + } + return value; +}; +const readUnsignedInt = (slice, width) => { + if (width < 1 || width > 8) { + throw new Error("Bad unsigned int size " + width); + } + let value = 0; + for (let i = 0; i < width; i++) { + value *= 1 << 8; + value += readU8(slice); + } + return value; +}; +const readUnsignedBigInt = (slice, width) => { + if (width < 1) { + throw new Error("Bad unsigned int size " + width); + } + let value = 0n; + for (let i = 0; i < width; i++) { + value <<= 8n; + value += BigInt(readU8(slice)); + } + return value; +}; +const readElementId = (slice) => { + const size = readVarIntSize(slice); + if (size === null) { + return null; + } + if (slice.remainingLength < size) { + return null; + } + const id = readUnsignedInt(slice, size); + return id; +}; +const readElementSize = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + if (firstByte === 255) { + return void 0; + } + slice.skip(-1); + const size = readVarInt(slice); + if (size === null) { + return null; + } + if (size === 72057594037927940) { + return void 0; + } + return size; +}; +const readElementHeader = (slice) => { + assert(slice.remainingLength >= MIN_HEADER_SIZE); + const id = readElementId(slice); + if (id === null) { + return null; + } + const size = readElementSize(slice); + if (size === null) { + return null; + } + return { id, size }; +}; +const readAsciiString = (slice, length) => { + const bytes = readBytes(slice, length); + let strLength = 0; + while (strLength < length && bytes[strLength] !== 0) { + strLength += 1; + } + return String.fromCharCode(...bytes.subarray(0, strLength)); +}; +const readUnicodeString = (slice, length) => { + const bytes = readBytes(slice, length); + let strLength = 0; + while (strLength < length && bytes[strLength] !== 0) { + strLength += 1; + } + return textDecoder.decode(bytes.subarray(0, strLength)); +}; +const readFloat = (slice, width) => { + if (width === 0) { + return 0; + } + if (width !== 4 && width !== 8) { + throw new Error("Bad float size " + width); + } + return width === 4 ? readF32Be(slice) : readF64Be(slice); +}; +const searchForNextElementId = async (reader, startPos, ids, until) => { + const idsSet = new Set(ids); + let currentPos = startPos; + while (until === null || currentPos < until) { + let slice = reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementHeader = readElementHeader(slice); + if (!elementHeader) { + break; + } + if (idsSet.has(elementHeader.id)) { + return { pos: currentPos, found: true }; + } + assertDefinedSize(elementHeader.size); + currentPos = slice.filePos + elementHeader.size; + } + return { pos: until !== null && until > currentPos ? until : currentPos, found: false }; +}; +const resync = async (reader, startPos, ids, until) => { + const CHUNK_SIZE = 2 ** 16; + const idsSet = new Set(ids); + let currentPos = startPos; + while (currentPos < until) { + let slice = reader.requestSliceRange(currentPos, 0, Math.min(CHUNK_SIZE, until - currentPos)); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + if (slice.length < MAX_VAR_INT_SIZE) + break; + for (let i = 0; i < slice.length - MAX_VAR_INT_SIZE; i++) { + slice.filePos = currentPos; + const elementId = readElementId(slice); + if (elementId !== null && idsSet.has(elementId)) { + return currentPos; + } + currentPos++; + } + } + return null; +}; +const CODEC_STRING_MAP = { + "avc": "V_MPEG4/ISO/AVC", + "hevc": "V_MPEGH/ISO/HEVC", + "vp8": "V_VP8", + "vp9": "V_VP9", + "av1": "V_AV1", + "aac": "A_AAC", + "mp3": "A_MPEG/L3", + "opus": "A_OPUS", + "vorbis": "A_VORBIS", + "flac": "A_FLAC", + "ac3": "A_AC3", + "eac3": "A_EAC3" +}; +function assertDefinedSize(size) { + if (size === void 0) { + throw new Error("Undefined element size is used in a place where it is not supported."); + } +} +const buildMatroskaMimeType = (info) => { + const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; + let string = base + (info.isWebM ? "webm" : "x-matroska"); + if (info.codecStrings.length > 0) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings.filter(Boolean))]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; + } + return string; +}; +var BlockLacing; +(function(BlockLacing2) { + BlockLacing2[BlockLacing2["None"] = 0] = "None"; + BlockLacing2[BlockLacing2["Xiph"] = 1] = "Xiph"; + BlockLacing2[BlockLacing2["FixedSize"] = 2] = "FixedSize"; + BlockLacing2[BlockLacing2["Ebml"] = 3] = "Ebml"; +})(BlockLacing || (BlockLacing = {})); +var ContentEncodingScope; +(function(ContentEncodingScope2) { + ContentEncodingScope2[ContentEncodingScope2["Block"] = 1] = "Block"; + ContentEncodingScope2[ContentEncodingScope2["Private"] = 2] = "Private"; + ContentEncodingScope2[ContentEncodingScope2["Next"] = 4] = "Next"; +})(ContentEncodingScope || (ContentEncodingScope = {})); +var ContentCompAlgo; +(function(ContentCompAlgo2) { + ContentCompAlgo2[ContentCompAlgo2["Zlib"] = 0] = "Zlib"; + ContentCompAlgo2[ContentCompAlgo2["Bzlib"] = 1] = "Bzlib"; + ContentCompAlgo2[ContentCompAlgo2["lzo1x"] = 2] = "lzo1x"; + ContentCompAlgo2[ContentCompAlgo2["HeaderStripping"] = 3] = "HeaderStripping"; +})(ContentCompAlgo || (ContentCompAlgo = {})); +const METADATA_ELEMENTS = [ + { id: EBMLId.SeekHead, flag: "seekHeadSeen" }, + { id: EBMLId.Info, flag: "infoSeen" }, + { id: EBMLId.Tracks, flag: "tracksSeen" }, + { id: EBMLId.Cues, flag: "cuesSeen" } +]; +const MAX_RESYNC_LENGTH = 10 * 2 ** 20; +class MatroskaDemuxer extends Demuxer { + constructor(input) { + super(input); + this.readMetadataPromise = null; + this.segments = []; + this.currentSegment = null; + this.currentTrack = null; + this.currentCluster = null; + this.currentBlock = null; + this.currentBlockAdditional = null; + this.currentCueTime = null; + this.currentDecodingInstruction = null; + this.currentTagTargetIsMovie = true; + this.currentSimpleTagName = null; + this.currentAttachedFile = null; + this.isWebM = false; + this.reader = input._reader; + } + async getTrackBackings() { + await this.readMetadata(); + return this.segments.flatMap((segment) => segment.tracks.map((track) => track.trackBacking)); + } + async getMimeType() { + await this.readMetadata(); + const backings = await this.getTrackBackings(); + const codecStrings = await Promise.all(backings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildMatroskaMimeType({ + isWebM: this.isWebM, + hasVideo: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "video")), + hasAudio: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "audio")), + codecStrings: codecStrings.filter(Boolean) + }); + } + async getMetadataTags() { + await this.readMetadata(); + for (const segment of this.segments) { + if (!segment.metadataTagsCollected) { + if (this.reader.fileSize !== null) { + await this.loadSegmentMetadata(segment); + } + segment.metadataTagsCollected = true; + } + } + let metadataTags = {}; + for (const segment of this.segments) { + metadataTags = { ...metadataTags, ...segment.metadataTags }; + } + return metadataTags; + } + readMetadata() { + return this.readMetadataPromise ?? (this.readMetadataPromise = (async () => { + let currentPos = 0; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const header = readElementHeader(slice); + if (!header) { + break; + } + const id = header.id; + let size = header.size; + const dataStartPos = slice.filePos; + if (id === EBMLId.EBML) { + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + this.readContiguousElements(slice2); + } else if (id === EBMLId.Segment) { + await this.readSegment(dataStartPos, size); + if (size === void 0) { + break; + } + if (this.reader.fileSize === null) { + break; + } + } else if (id === EBMLId.Cluster) { + if (this.reader.fileSize === null) { + break; + } + if (size === void 0) { + const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, this.reader.fileSize); + size = nextElementPos.pos - dataStartPos; + } + const lastSegment = last(this.segments); + if (lastSegment) { + lastSegment.elementEndPos = dataStartPos + size; + } + } + assertDefinedSize(size); + currentPos = dataStartPos + size; + } + })()); + } + async readSegment(segmentDataStart, dataSize) { + this.currentSegment = { + seekHeadSeen: false, + infoSeen: false, + tracksSeen: false, + cuesSeen: false, + tagsSeen: false, + attachmentsSeen: false, + timestampScale: -1, + timestampFactor: -1, + duration: -1, + seekEntries: [], + tracks: [], + cuePoints: [], + dataStartPos: segmentDataStart, + elementEndPos: dataSize === void 0 ? null : segmentDataStart + dataSize, + clusterSeekStartPos: segmentDataStart, + lastReadCluster: null, + metadataTags: {}, + metadataTagsCollected: false + }; + this.segments.push(this.currentSegment); + let currentPos = segmentDataStart; + while (this.currentSegment.elementEndPos === null || currentPos < this.currentSegment.elementEndPos) { + let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementStartPos = currentPos; + const header = readElementHeader(slice); + if (!header || !LEVEL_1_EBML_IDS.includes(header.id) && header.id !== EBMLId.Void) { + const nextPos = await resync(this.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(this.currentSegment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); + if (nextPos) { + currentPos = nextPos; + continue; + } else { + break; + } + } + const { id, size } = header; + const dataStartPos = slice.filePos; + const metadataElementIndex = METADATA_ELEMENTS.findIndex((x) => x.id === id); + if (metadataElementIndex !== -1) { + const field = METADATA_ELEMENTS[metadataElementIndex].flag; + this.currentSegment[field] = true; + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (slice2) { + this.readContiguousElements(slice2); + } + } else if (id === EBMLId.Tags || id === EBMLId.Attachments) { + if (id === EBMLId.Tags) { + this.currentSegment.tagsSeen = true; + } else { + this.currentSegment.attachmentsSeen = true; + } + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (slice2) { + this.readContiguousElements(slice2); + } + } else if (id === EBMLId.Cluster) { + this.currentSegment.clusterSeekStartPos = elementStartPos; + break; + } + if (size === void 0) { + break; + } else { + currentPos = dataStartPos + size; + } + } + this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition); + if (this.reader.fileSize !== null) { + for (const seekEntry of this.currentSegment.seekEntries) { + const target = METADATA_ELEMENTS.find((x) => x.id === seekEntry.id); + if (!target) { + continue; + } + if (this.currentSegment[target.flag]) + continue; + let slice = this.reader.requestSliceRange(segmentDataStart + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + continue; + const header = readElementHeader(slice); + if (!header) + continue; + const { id, size } = header; + if (id !== target.id) + continue; + assertDefinedSize(size); + this.currentSegment[target.flag] = true; + let dataSlice = this.reader.requestSlice(slice.filePos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (!dataSlice) + continue; + this.readContiguousElements(dataSlice); + } + } + if (this.currentSegment.timestampScale === -1) { + this.currentSegment.timestampScale = 1e6; + this.currentSegment.timestampFactor = 1e9 / 1e6; + } + for (const track of this.currentSegment.tracks) { + if (track.defaultDurationNs !== null) { + track.defaultDuration = this.currentSegment.timestampFactor * track.defaultDurationNs / 1e9; + } + } + const idToTrack = new Map(this.currentSegment.tracks.map((x) => [x.id, x])); + for (const cuePoint of this.currentSegment.cuePoints) { + const track = idToTrack.get(cuePoint.trackId); + if (track) { + track.cuePoints.push(cuePoint); + } + } + for (const track of this.currentSegment.tracks) { + track.cuePoints.sort((a, b) => a.time - b.time); + for (let i = 0; i < track.cuePoints.length - 1; i++) { + const cuePoint1 = track.cuePoints[i]; + const cuePoint2 = track.cuePoints[i + 1]; + if (cuePoint1.time === cuePoint2.time) { + track.cuePoints.splice(i + 1, 1); + i--; + } + } + } + let trackWithMostCuePoints = null; + let maxCuePointCount = -Infinity; + for (const track of this.currentSegment.tracks) { + if (track.cuePoints.length > maxCuePointCount) { + maxCuePointCount = track.cuePoints.length; + trackWithMostCuePoints = track; + } + } + for (const track of this.currentSegment.tracks) { + if (track.cuePoints.length === 0) { + track.cuePoints = trackWithMostCuePoints.cuePoints; + } + } + this.currentSegment = null; + } + async readCluster(startPos, segment) { + if (segment.lastReadCluster?.elementStartPos === startPos) { + return segment.lastReadCluster; + } + let headerSlice = this.reader.requestSliceRange(startPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const elementStartPos = startPos; + const elementHeader = readElementHeader(headerSlice); + assert(elementHeader); + const id = elementHeader.id; + assert(id === EBMLId.Cluster); + let size = elementHeader.size; + const dataStartPos = headerSlice.filePos; + if (size === void 0) { + const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); + size = nextElementPos.pos - dataStartPos; + } + let dataSlice = this.reader.requestSlice(dataStartPos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + const cluster = { + segment, + elementStartPos, + elementEndPos: dataStartPos + size, + dataStartPos, + timestamp: -1, + trackData: /* @__PURE__ */ new Map() + }; + this.currentCluster = cluster; + if (dataSlice) { + const endPos = this.readContiguousElements(dataSlice, LEVEL_0_AND_1_EBML_IDS); + cluster.elementEndPos = endPos; + } + for (const [, trackData] of cluster.trackData) { + const track = trackData.track; + assert(trackData.blocks.length > 0); + let hasLacedBlocks = false; + for (let i = 0; i < trackData.blocks.length; i++) { + const block = trackData.blocks[i]; + block.timestamp += cluster.timestamp; + hasLacedBlocks || (hasLacedBlocks = block.lacing !== BlockLacing.None); + } + trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); + for (let i = 0; i < trackData.presentationTimestamps.length; i++) { + const currentEntry = trackData.presentationTimestamps[i]; + const currentBlock = trackData.blocks[currentEntry.blockIndex]; + if (trackData.firstKeyFrameTimestamp === null && currentBlock.isKeyFrame) { + trackData.firstKeyFrameTimestamp = currentBlock.timestamp; + } + if (i < trackData.presentationTimestamps.length - 1) { + const nextEntry = trackData.presentationTimestamps[i + 1]; + currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp; + } else if (currentBlock.duration === 0) { + if (track.defaultDuration != null) { + if (currentBlock.lacing === BlockLacing.None) { + currentBlock.duration = track.defaultDuration; + } + } + } + } + if (hasLacedBlocks) { + this.expandLacedBlocks(trackData.blocks, track); + trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); + } + const firstBlock = trackData.blocks[trackData.presentationTimestamps[0].blockIndex]; + const lastBlock = trackData.blocks[last(trackData.presentationTimestamps).blockIndex]; + trackData.startTimestamp = firstBlock.timestamp; + trackData.endTimestamp = lastBlock.timestamp + lastBlock.duration; + const insertionIndex = binarySearchLessOrEqual(track.clusterPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); + if (insertionIndex === -1 || track.clusterPositionCache[insertionIndex].elementStartPos !== elementStartPos) { + track.clusterPositionCache.splice(insertionIndex + 1, 0, { + elementStartPos: cluster.elementStartPos, + startTimestamp: trackData.startTimestamp + }); + } + } + segment.lastReadCluster = cluster; + return cluster; + } + getTrackDataInCluster(cluster, trackNumber) { + let trackData = cluster.trackData.get(trackNumber); + if (!trackData) { + const track = cluster.segment.tracks.find((x) => x.id === trackNumber); + if (!track) { + return null; + } + trackData = { + track, + startTimestamp: 0, + endTimestamp: 0, + firstKeyFrameTimestamp: null, + blocks: [], + presentationTimestamps: [] + }; + cluster.trackData.set(trackNumber, trackData); + } + return trackData; + } + expandLacedBlocks(blocks, track) { + for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) { + const originalBlock = blocks[blockIndex]; + if (originalBlock.lacing === BlockLacing.None) { + continue; + } + if (!originalBlock.decoded) { + originalBlock.data = this.decodeBlockData(track, originalBlock.data); + originalBlock.decoded = true; + } + const slice = FileSlice.tempFromBytes(originalBlock.data); + const frameSizes = []; + const frameCount = readU8(slice) + 1; + switch (originalBlock.lacing) { + case BlockLacing.Xiph: + { + let totalUsedSize = 0; + for (let i = 0; i < frameCount - 1; i++) { + let frameSize = 0; + while (slice.bufferPos < slice.length) { + const value = readU8(slice); + frameSize += value; + if (value < 255) { + frameSizes.push(frameSize); + totalUsedSize += frameSize; + break; + } + } + } + frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); + } + break; + case BlockLacing.FixedSize: + { + const totalDataSize = slice.length - 1; + const frameSize = Math.floor(totalDataSize / frameCount); + for (let i = 0; i < frameCount; i++) { + frameSizes.push(frameSize); + } + } + break; + case BlockLacing.Ebml: + { + const firstResult = readVarInt(slice); + assert(firstResult !== null); + let currentSize = firstResult; + frameSizes.push(currentSize); + let totalUsedSize = currentSize; + for (let i = 1; i < frameCount - 1; i++) { + const startPos = slice.bufferPos; + const diffResult = readVarInt(slice); + assert(diffResult !== null); + const unsignedDiff = diffResult; + const width = slice.bufferPos - startPos; + const bias = (1 << width * 7 - 1) - 1; + const diff = unsignedDiff - bias; + currentSize += diff; + frameSizes.push(currentSize); + totalUsedSize += currentSize; + } + frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); + } + break; + default: + assert(false); + } + assert(frameSizes.length === frameCount); + blocks.splice(blockIndex, 1); + const blockDuration = originalBlock.duration || frameCount * (track.defaultDuration ?? 0); + for (let i = 0; i < frameCount; i++) { + const frameSize = frameSizes[i]; + const frameData = readBytes(slice, frameSize); + const frameTimestamp = originalBlock.timestamp + blockDuration * i / frameCount; + const frameDuration = blockDuration / frameCount; + blocks.splice(blockIndex + i, 0, { + timestamp: frameTimestamp, + duration: frameDuration, + isKeyFrame: originalBlock.isKeyFrame, + data: frameData, + lacing: BlockLacing.None, + decoded: true, + mainAdditional: originalBlock.mainAdditional + }); + } + blockIndex += frameCount; + blockIndex--; + } + } + async loadSegmentMetadata(segment) { + for (const seekEntry of segment.seekEntries) { + if (seekEntry.id === EBMLId.Tags && !segment.tagsSeen) ; + else if (seekEntry.id === EBMLId.Attachments && !segment.attachmentsSeen) ; + else { + continue; + } + let slice = this.reader.requestSliceRange(segment.dataStartPos + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + continue; + const header = readElementHeader(slice); + if (!header || header.id !== seekEntry.id) + continue; + const { size } = header; + assertDefinedSize(size); + assert(!this.currentSegment); + this.currentSegment = segment; + let dataSlice = this.reader.requestSlice(slice.filePos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (dataSlice) { + this.readContiguousElements(dataSlice); + } + this.currentSegment = null; + if (seekEntry.id === EBMLId.Tags) { + segment.tagsSeen = true; + } else if (seekEntry.id === EBMLId.Attachments) { + segment.attachmentsSeen = true; + } + } + } + readContiguousElements(slice, stopIds) { + while (slice.remainingLength >= MIN_HEADER_SIZE) { + const startPos = slice.filePos; + const foundElement = this.traverseElement(slice, stopIds); + if (!foundElement) { + return startPos; + } + } + return slice.filePos; + } + traverseElement(slice, stopIds) { + const header = readElementHeader(slice); + if (!header) { + return false; + } + if (stopIds && stopIds.includes(header.id)) { + return false; + } + const { id, size } = header; + const dataStartPos = slice.filePos; + assertDefinedSize(size); + switch (id) { + case EBMLId.DocType: + { + this.isWebM = readAsciiString(slice, size) === "webm"; + } + break; + case EBMLId.Seek: + { + if (!this.currentSegment) + break; + const seekEntry = { id: -1, segmentPosition: -1 }; + this.currentSegment.seekEntries.push(seekEntry); + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (seekEntry.id === -1 || seekEntry.segmentPosition === -1) { + this.currentSegment.seekEntries.pop(); + } + } + break; + case EBMLId.SeekID: + { + const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; + if (!lastSeekEntry) + break; + lastSeekEntry.id = readUnsignedInt(slice, size); + } + break; + case EBMLId.SeekPosition: + { + const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; + if (!lastSeekEntry) + break; + lastSeekEntry.segmentPosition = readUnsignedInt(slice, size); + } + break; + case EBMLId.TimestampScale: + { + if (!this.currentSegment) + break; + this.currentSegment.timestampScale = readUnsignedInt(slice, size); + this.currentSegment.timestampFactor = 1e9 / this.currentSegment.timestampScale; + } + break; + case EBMLId.Duration: + { + if (!this.currentSegment) + break; + this.currentSegment.duration = readFloat(slice, size); + } + break; + case EBMLId.TrackEntry: + { + if (!this.currentSegment) + break; + this.currentTrack = { + id: -1, + segment: this.currentSegment, + demuxer: this, + clusterPositionCache: [], + cuePoints: [], + disposition: { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }, + trackBacking: null, + codecId: null, + codecPrivate: null, + defaultDuration: null, + defaultDurationNs: null, + name: null, + languageCode: "eng", + // The default in Matroska + hasLanguageBcp47: false, + decodingInstructions: [], + info: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (!this.currentTrack) { + break; + } + if (this.currentTrack.decodingInstructions.some((instruction) => { + return instruction.data?.type !== "decompress" || instruction.scope !== ContentEncodingScope.Block || instruction.data.algorithm !== ContentCompAlgo.HeaderStripping; + })) { + console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`); + this.currentTrack = null; + } + if (this.currentTrack && this.currentTrack.id !== -1 && this.currentTrack.codecId && this.currentTrack.info) { + const slashIndex = this.currentTrack.codecId.indexOf("/"); + const codecIdWithoutSuffix = slashIndex === -1 ? this.currentTrack.codecId : this.currentTrack.codecId.slice(0, slashIndex); + if (this.currentTrack.info.type === "video" && this.currentTrack.info.width !== -1 && this.currentTrack.info.height !== -1) { + this.currentTrack.info.squarePixelWidth = this.currentTrack.info.width; + this.currentTrack.info.squarePixelHeight = this.currentTrack.info.height; + if (this.currentTrack.info.displayWidth !== null && this.currentTrack.info.displayHeight !== null) { + const num = this.currentTrack.info.displayWidth * this.currentTrack.info.height; + const den = this.currentTrack.info.displayHeight * this.currentTrack.info.width; + if (num > 0 && den > 0) { + if (num > den) { + this.currentTrack.info.squarePixelWidth = Math.round(this.currentTrack.info.width * num / den); + } else { + this.currentTrack.info.squarePixelHeight = Math.round(this.currentTrack.info.height * den / num); + } + } + } + if (this.currentTrack.codecId === CODEC_STRING_MAP.avc) { + this.currentTrack.info.codec = "avc"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === CODEC_STRING_MAP.hevc) { + this.currentTrack.info.codec = "hevc"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp8) { + this.currentTrack.info.codec = "vp8"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp9) { + this.currentTrack.info.codec = "vp9"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.av1) { + this.currentTrack.info.codec = "av1"; + } + const videoTrack = this.currentTrack; + this.currentTrack.trackBacking = new MatroskaVideoTrackBacking(videoTrack); + this.currentSegment.tracks.push(this.currentTrack); + } else if (this.currentTrack.info.type === "audio") { + if (codecIdWithoutSuffix === CODEC_STRING_MAP.aac) { + this.currentTrack.info.codec = "aac"; + this.currentTrack.info.aacCodecInfo = { + isMpeg2: this.currentTrack.codecId.includes("MPEG2"), + objectType: null + }; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === CODEC_STRING_MAP.mp3) { + this.currentTrack.info.codec = "mp3"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.opus) { + this.currentTrack.info.codec = "opus"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + this.currentTrack.info.sampleRate = OPUS_SAMPLE_RATE; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vorbis) { + this.currentTrack.info.codec = "vorbis"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.flac) { + this.currentTrack.info.codec = "flac"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.ac3) { + this.currentTrack.info.codec = "ac3"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.eac3) { + this.currentTrack.info.codec = "eac3"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === "A_PCM/INT/LIT") { + if (this.currentTrack.info.bitDepth === 8) { + this.currentTrack.info.codec = "pcm-u8"; + } else if (this.currentTrack.info.bitDepth === 16) { + this.currentTrack.info.codec = "pcm-s16"; + } else if (this.currentTrack.info.bitDepth === 24) { + this.currentTrack.info.codec = "pcm-s24"; + } else if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-s32"; + } + } else if (this.currentTrack.codecId === "A_PCM/INT/BIG") { + if (this.currentTrack.info.bitDepth === 8) { + this.currentTrack.info.codec = "pcm-u8"; + } else if (this.currentTrack.info.bitDepth === 16) { + this.currentTrack.info.codec = "pcm-s16be"; + } else if (this.currentTrack.info.bitDepth === 24) { + this.currentTrack.info.codec = "pcm-s24be"; + } else if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-s32be"; + } + } else if (this.currentTrack.codecId === "A_PCM/FLOAT/IEEE") { + if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-f32"; + } else if (this.currentTrack.info.bitDepth === 64) { + this.currentTrack.info.codec = "pcm-f64"; + } + } + const audioTrack = this.currentTrack; + this.currentTrack.trackBacking = new MatroskaAudioTrackBacking(audioTrack); + this.currentSegment.tracks.push(this.currentTrack); + } + } + this.currentTrack = null; + } + break; + case EBMLId.TrackNumber: + { + if (!this.currentTrack) + break; + this.currentTrack.id = readUnsignedInt(slice, size); + } + break; + case EBMLId.TrackType: + { + if (!this.currentTrack) + break; + const type = readUnsignedInt(slice, size); + if (type === 1) { + this.currentTrack.info = { + type: "video", + width: -1, + height: -1, + displayWidth: null, + displayHeight: null, + displayUnit: null, + squarePixelWidth: -1, + squarePixelHeight: -1, + rotation: 0, + codec: null, + codecDescription: null, + colorSpace: null, + alphaMode: false + }; + } else if (type === 2) { + this.currentTrack.info = { + type: "audio", + numberOfChannels: 1, + // Default value + sampleRate: 8e3, + // Default value + bitDepth: -1, + codec: null, + codecDescription: null, + aacCodecInfo: null + }; + } + } + break; + case EBMLId.FlagEnabled: + { + if (!this.currentTrack) + break; + const enabled = readUnsignedInt(slice, size); + if (!enabled) { + this.currentTrack = null; + } + } + break; + case EBMLId.FlagDefault: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.default = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagForced: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.forced = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagOriginal: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.original = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagHearingImpaired: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.hearingImpaired = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagVisualImpaired: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.visuallyImpaired = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagCommentary: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.commentary = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.CodecID: + { + if (!this.currentTrack) + break; + this.currentTrack.codecId = readAsciiString(slice, size); + } + break; + case EBMLId.CodecPrivate: + { + if (!this.currentTrack) + break; + this.currentTrack.codecPrivate = readBytes(slice, size); + } + break; + case EBMLId.DefaultDuration: + { + if (!this.currentTrack) + break; + this.currentTrack.defaultDurationNs = readUnsignedInt(slice, size); + } + break; + case EBMLId.Name: + { + if (!this.currentTrack) + break; + this.currentTrack.name = readUnicodeString(slice, size); + } + break; + case EBMLId.Language: + { + if (!this.currentTrack) + break; + if (this.currentTrack.hasLanguageBcp47) { + break; + } + this.currentTrack.languageCode = readAsciiString(slice, size); + if (!isIso639Dash2LanguageCode(this.currentTrack.languageCode)) { + this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; + } + } + break; + case EBMLId.LanguageBCP47: + { + if (!this.currentTrack) + break; + const bcp47 = readAsciiString(slice, size); + const languageSubtag = bcp47.split("-")[0]; + if (languageSubtag) { + this.currentTrack.languageCode = languageSubtag; + } else { + this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; + } + this.currentTrack.hasLanguageBcp47 = true; + } + break; + case EBMLId.Video: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.PixelWidth: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.width = readUnsignedInt(slice, size); + } + break; + case EBMLId.PixelHeight: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.height = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayWidth: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayWidth = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayHeight: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayHeight = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayUnit: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayUnit = readUnsignedInt(slice, size); + } + break; + case EBMLId.AlphaMode: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.alphaMode = readUnsignedInt(slice, size) === 1; + } + break; + case EBMLId.Colour: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.colorSpace = {}; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.MatrixCoefficients: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const matrixCoefficients = readUnsignedInt(slice, size); + const mapped = MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients] ?? null; + this.currentTrack.info.colorSpace.matrix = mapped; + } + break; + case EBMLId.Range: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + this.currentTrack.info.colorSpace.fullRange = readUnsignedInt(slice, size) === 2; + } + break; + case EBMLId.TransferCharacteristics: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const transferCharacteristics = readUnsignedInt(slice, size); + const mapped = TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics] ?? null; + this.currentTrack.info.colorSpace.transfer = mapped; + } + break; + case EBMLId.Primaries: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const primaries = readUnsignedInt(slice, size); + const mapped = COLOR_PRIMARIES_MAP_INVERSE[primaries] ?? null; + this.currentTrack.info.colorSpace.primaries = mapped; + } + break; + case EBMLId.Projection: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.ProjectionPoseRoll: + { + if (this.currentTrack?.info?.type !== "video") + break; + const rotation = readFloat(slice, size); + const flippedRotation = -rotation; + try { + this.currentTrack.info.rotation = normalizeRotation(flippedRotation); + } catch { + } + } + break; + case EBMLId.Audio: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.SamplingFrequency: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.sampleRate = readFloat(slice, size); + } + break; + case EBMLId.Channels: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.numberOfChannels = readUnsignedInt(slice, size); + } + break; + case EBMLId.BitDepth: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.bitDepth = readUnsignedInt(slice, size); + } + break; + case EBMLId.CuePoint: + { + if (!this.currentSegment) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentCueTime = null; + } + break; + case EBMLId.CueTime: + { + this.currentCueTime = readUnsignedInt(slice, size); + } + break; + case EBMLId.CueTrackPositions: + { + if (this.currentCueTime === null) + break; + assert(this.currentSegment); + const cuePoint = { time: this.currentCueTime, trackId: -1, clusterPosition: -1 }; + this.currentSegment.cuePoints.push(cuePoint); + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (cuePoint.trackId === -1 || cuePoint.clusterPosition === -1) { + this.currentSegment.cuePoints.pop(); + } + } + break; + case EBMLId.CueTrack: + { + const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; + if (!lastCuePoint) + break; + lastCuePoint.trackId = readUnsignedInt(slice, size); + } + break; + case EBMLId.CueClusterPosition: + { + const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; + if (!lastCuePoint) + break; + assert(this.currentSegment); + lastCuePoint.clusterPosition = this.currentSegment.dataStartPos + readUnsignedInt(slice, size); + } + break; + case EBMLId.Timestamp: + { + if (!this.currentCluster) + break; + this.currentCluster.timestamp = readUnsignedInt(slice, size); + } + break; + case EBMLId.SimpleBlock: + { + if (!this.currentCluster) + break; + const trackNumber = readVarInt(slice); + if (trackNumber === null) + break; + const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); + if (!trackData) + break; + const relativeTimestamp = readI16Be(slice); + const flags = readU8(slice); + const lacing = flags >> 1 & 3; + let isKeyFrame = !!(flags & 128); + if (trackData.track.info?.type === "audio" && trackData.track.info.codec) { + isKeyFrame = true; + } + const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); + const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; + trackData.blocks.push({ + timestamp: relativeTimestamp, + // We'll add the cluster's timestamp to this later + duration: 0, + // Will set later + isKeyFrame, + data: blockData, + lacing, + decoded: !hasDecodingInstructions, + mainAdditional: null + }); + } + break; + case EBMLId.BlockGroup: + { + if (!this.currentCluster) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentBlock = null; + } + break; + case EBMLId.Block: + { + if (!this.currentCluster) + break; + const trackNumber = readVarInt(slice); + if (trackNumber === null) + break; + const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); + if (!trackData) + break; + const relativeTimestamp = readI16Be(slice); + const flags = readU8(slice); + const lacing = flags >> 1 & 3; + const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); + const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; + this.currentBlock = { + timestamp: relativeTimestamp, + // We'll add the cluster's timestamp to this later + duration: 0, + // Will set later + isKeyFrame: true, + data: blockData, + lacing, + decoded: !hasDecodingInstructions, + mainAdditional: null + }; + trackData.blocks.push(this.currentBlock); + } + break; + case EBMLId.BlockAdditions: + { + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.BlockMore: + { + if (!this.currentBlock) + break; + this.currentBlockAdditional = { + addId: 1, + data: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (this.currentBlockAdditional.data && this.currentBlockAdditional.addId === 1) { + this.currentBlock.mainAdditional = this.currentBlockAdditional.data; + } + this.currentBlockAdditional = null; + } + break; + case EBMLId.BlockAdditional: + { + if (!this.currentBlockAdditional) + break; + this.currentBlockAdditional.data = readBytes(slice, size); + } + break; + case EBMLId.BlockAddID: + { + if (!this.currentBlockAdditional) + break; + this.currentBlockAdditional.addId = readUnsignedInt(slice, size); + } + break; + case EBMLId.BlockDuration: + { + if (!this.currentBlock) + break; + this.currentBlock.duration = readUnsignedInt(slice, size); + } + break; + case EBMLId.ReferenceBlock: + { + if (!this.currentBlock) + break; + this.currentBlock.isKeyFrame = false; + } + break; + case EBMLId.Tag: + { + this.currentTagTargetIsMovie = true; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.Targets: + { + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.TargetTypeValue: + { + const targetTypeValue = readUnsignedInt(slice, size); + if (targetTypeValue !== 50) { + this.currentTagTargetIsMovie = false; + } + } + break; + case EBMLId.TagTrackUID: + case EBMLId.TagEditionUID: + case EBMLId.TagChapterUID: + case EBMLId.TagAttachmentUID: + { + this.currentTagTargetIsMovie = false; + } + break; + case EBMLId.SimpleTag: + { + if (!this.currentTagTargetIsMovie) + break; + this.currentSimpleTagName = null; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.TagName: + { + this.currentSimpleTagName = readUnicodeString(slice, size); + } + break; + case EBMLId.TagString: + { + if (!this.currentSimpleTagName) + break; + const value = readUnicodeString(slice, size); + this.processTagValue(this.currentSimpleTagName, value); + } + break; + case EBMLId.TagBinary: + { + if (!this.currentSimpleTagName) + break; + const value = readBytes(slice, size); + this.processTagValue(this.currentSimpleTagName, value); + } + break; + case EBMLId.AttachedFile: + { + if (!this.currentSegment) + break; + this.currentAttachedFile = { + fileUid: null, + fileName: null, + fileMediaType: null, + fileData: null, + fileDescription: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + const tags = this.currentSegment.metadataTags; + if (this.currentAttachedFile.fileUid && this.currentAttachedFile.fileData) { + tags.raw ?? (tags.raw = {}); + tags.raw[this.currentAttachedFile.fileUid.toString()] = new AttachedFile(this.currentAttachedFile.fileData, this.currentAttachedFile.fileMediaType ?? void 0, this.currentAttachedFile.fileName ?? void 0, this.currentAttachedFile.fileDescription ?? void 0); + } + if (this.currentAttachedFile.fileMediaType?.startsWith("image/") && this.currentAttachedFile.fileData) { + const fileName = this.currentAttachedFile.fileName; + let kind = "unknown"; + if (fileName) { + const lowerName = fileName.toLowerCase(); + if (lowerName.startsWith("cover.")) { + kind = "coverFront"; + } else if (lowerName.startsWith("back.")) { + kind = "coverBack"; + } + } + tags.images ?? (tags.images = []); + tags.images.push({ + data: this.currentAttachedFile.fileData, + mimeType: this.currentAttachedFile.fileMediaType, + kind, + name: this.currentAttachedFile.fileName ?? void 0, + description: this.currentAttachedFile.fileDescription ?? void 0 + }); + } + this.currentAttachedFile = null; + } + break; + case EBMLId.FileUID: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileUid = readUnsignedBigInt(slice, size); + } + break; + case EBMLId.FileName: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileName = readUnicodeString(slice, size); + } + break; + case EBMLId.FileMediaType: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileMediaType = readAsciiString(slice, size); + } + break; + case EBMLId.FileData: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileData = readBytes(slice, size); + } + break; + case EBMLId.FileDescription: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileDescription = readUnicodeString(slice, size); + } + break; + case EBMLId.ContentEncodings: + { + if (!this.currentTrack) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentTrack.decodingInstructions.sort((a, b) => b.order - a.order); + } + break; + case EBMLId.ContentEncoding: + { + this.currentDecodingInstruction = { + order: 0, + scope: ContentEncodingScope.Block, + data: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (this.currentDecodingInstruction.data) { + this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction); + } + this.currentDecodingInstruction = null; + } + break; + case EBMLId.ContentEncodingOrder: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.order = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentEncodingScope: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.scope = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentCompression: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.data = { + type: "decompress", + algorithm: ContentCompAlgo.Zlib, + settings: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.ContentCompAlgo: + { + if (this.currentDecodingInstruction?.data?.type !== "decompress") + break; + this.currentDecodingInstruction.data.algorithm = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentCompSettings: + { + if (this.currentDecodingInstruction?.data?.type !== "decompress") + break; + this.currentDecodingInstruction.data.settings = readBytes(slice, size); + } + break; + case EBMLId.ContentEncryption: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.data = { + type: "decrypt" + }; + } + break; + } + slice.filePos = dataStartPos + size; + return true; + } + decodeBlockData(track, rawData) { + assert(track.decodingInstructions.length > 0); + let currentData = rawData; + for (const instruction of track.decodingInstructions) { + assert(instruction.data); + switch (instruction.data.type) { + case "decompress": + { + switch (instruction.data.algorithm) { + case ContentCompAlgo.HeaderStripping: + { + if (instruction.data.settings && instruction.data.settings.length > 0) { + const prefix = instruction.data.settings; + const newData = new Uint8Array(prefix.length + currentData.length); + newData.set(prefix, 0); + newData.set(currentData, prefix.length); + currentData = newData; + } + } + break; + } + } + break; + } + } + return currentData; + } + processTagValue(name, value) { + var _a; + if (!this.currentSegment?.metadataTags) + return; + const metadataTags = this.currentSegment.metadataTags; + metadataTags.raw ?? (metadataTags.raw = {}); + (_a = metadataTags.raw)[name] ?? (_a[name] = value); + if (typeof value === "string") { + switch (name.toLowerCase()) { + case "title": + { + metadataTags.title ?? (metadataTags.title = value); + } + break; + case "description": + { + metadataTags.description ?? (metadataTags.description = value); + } + break; + case "artist": + { + metadataTags.artist ?? (metadataTags.artist = value); + } + break; + case "album": + { + metadataTags.album ?? (metadataTags.album = value); + } + break; + case "album_artist": + { + metadataTags.albumArtist ?? (metadataTags.albumArtist = value); + } + break; + case "genre": + { + metadataTags.genre ?? (metadataTags.genre = value); + } + break; + case "comment": + { + metadataTags.comment ?? (metadataTags.comment = value); + } + break; + case "lyrics": + { + metadataTags.lyrics ?? (metadataTags.lyrics = value); + } + break; + case "date": + { + const date = new Date(value); + if (!Number.isNaN(date.getTime())) { + metadataTags.date ?? (metadataTags.date = date); + } + } + break; + case "track_number": + case "part_number": + { + const parts = value.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + metadataTags.trackNumber ?? (metadataTags.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + metadataTags.tracksTotal ?? (metadataTags.tracksTotal = tracksTotal); + } + } + break; + case "disc_number": + case "disc": + { + const discParts = value.split("/"); + const discNum = Number.parseInt(discParts[0], 10); + const discsTotal = discParts[1] && Number.parseInt(discParts[1], 10); + if (Number.isInteger(discNum) && discNum > 0) { + metadataTags.discNumber ?? (metadataTags.discNumber = discNum); + } + if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) { + metadataTags.discsTotal ?? (metadataTags.discsTotal = discsTotal); + } + } + break; + } + } + } +} +class MatroskaTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.packetToClusterLocation = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.internalTrack.id; + } + getNumber() { + const demuxer = this.internalTrack.demuxer; + const trackType = this.internalTrack.trackBacking.getType(); + let number = 0; + for (const segment of demuxer.segments) { + for (const track of segment.tracks) { + if (track.trackBacking.getType() === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.internalTrack.codecId; + } + getName() { + return this.internalTrack.name; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getTimeResolution() { + return this.internalTrack.segment.timestampFactor; + } + isRelativeToUnixEpoch() { + return false; + } + getDisposition() { + return this.internalTrack.disposition; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const segment = this.internalTrack.segment; + if (segment.duration <= 0) { + return null; + } + let endTimestamp = segment.duration / segment.timestampFactor; + const firstPacket = await this.getFirstPacket({ metadataOnly: true }); + endTimestamp += firstPacket?.timestamp ?? 0; + return endTimestamp; + } + async getLiveRefreshInterval() { + return null; + } + async getFirstPacket(options) { + return this.performClusterLookup( + null, + (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData) { + return { + blockIndex: 0, + correctBlockFound: true + }; + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + intoTimescale(timestamp) { + return roundIfAlmostInteger(timestamp * this.internalTrack.segment.timestampFactor); + } + async getPacket(timestamp, options) { + const timestampInTimescale = this.intoTimescale(timestamp); + return this.performClusterLookup(null, (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (!trackData) { + return { blockIndex: -1, correctBlockFound: false }; + } + const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.timestamp); + const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; + const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { blockIndex, correctBlockFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextPacket(packet, options) { + const locationInCluster = this.packetToClusterLocation.get(packet); + if (locationInCluster === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performClusterLookup( + locationInCluster.cluster, + (cluster) => { + if (cluster === locationInCluster.cluster) { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (locationInCluster.blockIndex + 1 < trackData.blocks.length) { + return { + blockIndex: locationInCluster.blockIndex + 1, + correctBlockFound: true + }; + } + } else { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData) { + return { + blockIndex: 0, + correctBlockFound: true + }; + } + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + async getKeyPacket(timestamp, options) { + const timestampInTimescale = this.intoTimescale(timestamp); + return this.performClusterLookup(null, (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (!trackData) { + return { blockIndex: -1, correctBlockFound: false }; + } + const index = findLastIndex(trackData.presentationTimestamps, (x) => { + const block = trackData.blocks[x.blockIndex]; + return block.isKeyFrame && x.timestamp <= timestampInTimescale; + }); + const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; + const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { blockIndex, correctBlockFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextKeyPacket(packet, options) { + const locationInCluster = this.packetToClusterLocation.get(packet); + if (locationInCluster === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performClusterLookup( + locationInCluster.cluster, + (cluster) => { + if (cluster === locationInCluster.cluster) { + const trackData = cluster.trackData.get(this.internalTrack.id); + const nextKeyFrameIndex = trackData.blocks.findIndex((x, i) => x.isKeyFrame && i > locationInCluster.blockIndex); + if (nextKeyFrameIndex !== -1) { + return { + blockIndex: nextKeyFrameIndex, + correctBlockFound: true + }; + } + } else { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData && trackData.firstKeyFrameTimestamp !== null) { + const keyFrameIndex = trackData.blocks.findIndex((x) => x.isKeyFrame); + assert(keyFrameIndex !== -1); + return { + blockIndex: keyFrameIndex, + correctBlockFound: true + }; + } + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + async fetchPacketInCluster(cluster, blockIndex, options) { + if (blockIndex === -1) { + return null; + } + const trackData = cluster.trackData.get(this.internalTrack.id); + const block = trackData.blocks[blockIndex]; + assert(block); + if (!block.decoded) { + block.data = this.internalTrack.demuxer.decodeBlockData(this.internalTrack, block.data); + block.decoded = true; + } + const data = options.metadataOnly ? PLACEHOLDER_DATA : block.data; + const timestamp = block.timestamp / this.internalTrack.segment.timestampFactor; + const duration = block.duration / this.internalTrack.segment.timestampFactor; + const sideData = {}; + if (block.mainAdditional && this.internalTrack.info?.type === "video" && this.internalTrack.info.alphaMode) { + sideData.alpha = options.metadataOnly ? PLACEHOLDER_DATA : block.mainAdditional; + sideData.alphaByteLength = block.mainAdditional.byteLength; + } + const packet = new EncodedPacket(data, block.isKeyFrame ? "key" : "delta", timestamp, duration, cluster.dataStartPos + blockIndex, block.data.byteLength, sideData); + this.packetToClusterLocation.set(packet, { cluster, blockIndex }); + return packet; + } + /** Looks for a packet in the clusters while trying to load as few clusters as possible to retrieve it. */ + async performClusterLookup(startCluster, getMatchInCluster, searchTimestamp, latestTimestamp, options) { + const { demuxer, segment } = this.internalTrack; + let currentCluster = null; + let bestCluster = null; + let bestBlockIndex = -1; + if (startCluster) { + const { blockIndex, correctBlockFound } = getMatchInCluster(startCluster); + if (correctBlockFound) { + return this.fetchPacketInCluster(startCluster, blockIndex, options); + } + if (blockIndex !== -1) { + bestCluster = startCluster; + bestBlockIndex = blockIndex; + } + } + const cuePointIndex = binarySearchLessOrEqual(this.internalTrack.cuePoints, searchTimestamp, (x) => x.time); + const cuePoint = cuePointIndex !== -1 ? this.internalTrack.cuePoints[cuePointIndex] : null; + const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.clusterPositionCache, searchTimestamp, (x) => x.startTimestamp); + const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.clusterPositionCache[positionCacheIndex] : null; + const lookupEntryPosition = Math.max(cuePoint?.clusterPosition ?? 0, positionCacheEntry?.elementStartPos ?? 0) || null; + let currentPos; + if (!startCluster) { + currentPos = lookupEntryPosition ?? segment.clusterSeekStartPos; + } else { + if (lookupEntryPosition === null || startCluster.elementStartPos >= lookupEntryPosition) { + currentPos = startCluster.elementEndPos; + currentCluster = startCluster; + } else { + currentPos = lookupEntryPosition; + } + } + while (segment.elementEndPos === null || currentPos <= segment.elementEndPos - MIN_HEADER_SIZE) { + if (currentCluster) { + const trackData = currentCluster.trackData.get(this.internalTrack.id); + if (trackData && trackData.startTimestamp > latestTimestamp) { + break; + } + } + let slice = demuxer.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementStartPos = currentPos; + const elementHeader = readElementHeader(slice); + if (!elementHeader || !LEVEL_1_EBML_IDS.includes(elementHeader.id) && elementHeader.id !== EBMLId.Void) { + const nextPos = await resync(demuxer.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(segment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); + if (nextPos) { + currentPos = nextPos; + continue; + } else { + break; + } + } + const id = elementHeader.id; + let size = elementHeader.size; + const dataStartPos = slice.filePos; + if (id === EBMLId.Cluster) { + currentCluster = await demuxer.readCluster(elementStartPos, segment); + size = currentCluster.elementEndPos - dataStartPos; + const { blockIndex, correctBlockFound } = getMatchInCluster(currentCluster); + if (correctBlockFound) { + return this.fetchPacketInCluster(currentCluster, blockIndex, options); + } + if (blockIndex !== -1) { + bestCluster = currentCluster; + bestBlockIndex = blockIndex; + } + } + if (size === void 0) { + assert(id !== EBMLId.Cluster); + const nextElementPos = await searchForNextElementId(demuxer.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); + size = nextElementPos.pos - dataStartPos; + } + const endPos = dataStartPos + size; + if (segment.elementEndPos === null) { + let slice2 = demuxer.reader.requestSliceRange(endPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const elementId = readElementId(slice2); + if (elementId === EBMLId.Segment) { + segment.elementEndPos = endPos; + break; + } + } + currentPos = endPos; + } + if (cuePoint && (!bestCluster || bestCluster.elementStartPos < cuePoint.clusterPosition)) { + const previousCuePoint = this.internalTrack.cuePoints[cuePointIndex - 1]; + assert(!previousCuePoint || previousCuePoint.time < cuePoint.time); + const newSearchTimestamp = previousCuePoint?.time ?? -Infinity; + return this.performClusterLookup(null, getMatchInCluster, newSearchTimestamp, latestTimestamp, options); + } + if (bestCluster) { + return this.fetchPacketInCluster(bestCluster, bestBlockIndex, options); + } + return null; + } +} +class MatroskaVideoTrackBacking extends MatroskaTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfigPromise = null; + this.internalTrack = internalTrack; + } + getType() { + return "video"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getCodedWidth() { + return this.internalTrack.info.width; + } + getCodedHeight() { + return this.internalTrack.info.height; + } + getSquarePixelWidth() { + return this.internalTrack.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.internalTrack.info.squarePixelHeight; + } + getRotation() { + return this.internalTrack.info.rotation; + } + async getColorSpace() { + return { + primaries: this.internalTrack.info.colorSpace?.primaries, + transfer: this.internalTrack.info.colorSpace?.transfer, + matrix: this.internalTrack.info.colorSpace?.matrix, + fullRange: this.internalTrack.info.colorSpace?.fullRange + }; + } + async canBeTransparent() { + return this.internalTrack.info.alphaMode; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { + let firstPacket = null; + const needsPacketForAdditionalInfo = this.internalTrack.info.codec === "vp9" || this.internalTrack.info.codec === "av1" || this.internalTrack.info.codec === "avc" && !this.internalTrack.info.codecDescription || this.internalTrack.info.codec === "hevc" && !this.internalTrack.info.codecDescription; + if (needsPacketForAdditionalInfo) { + firstPacket = await this.getFirstPacket({}); + } + const config = { + codec: extractVideoCodecString({ + width: this.internalTrack.info.width, + height: this.internalTrack.info.height, + codec: this.internalTrack.info.codec, + codecDescription: this.internalTrack.info.codecDescription, + colorSpace: this.internalTrack.info.colorSpace, + avcType: 1, + // We don't know better (or do we?) so just assume 'avc1' + avcCodecInfo: this.internalTrack.info.codec === "avc" && firstPacket ? extractAvcDecoderConfigurationRecord(firstPacket.data) : null, + hevcCodecInfo: this.internalTrack.info.codec === "hevc" && firstPacket ? extractHevcDecoderConfigurationRecord(firstPacket.data) : null, + vp9CodecInfo: this.internalTrack.info.codec === "vp9" && firstPacket ? extractVp9CodecInfoFromPacket(firstPacket.data) : null, + av1CodecInfo: this.internalTrack.info.codec === "av1" && firstPacket ? extractAv1CodecInfoFromPacket(firstPacket.data) : null + }), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? void 0, + colorSpace: this.internalTrack.info.colorSpace ?? void 0 + }; + if (this.internalTrack.info.width !== this.internalTrack.info.squarePixelWidth || this.internalTrack.info.height !== this.internalTrack.info.squarePixelHeight) { + config.displayAspectWidth = this.internalTrack.info.squarePixelWidth; + config.displayAspectHeight = this.internalTrack.info.squarePixelHeight; + } + return config; + })()); + } +} +class MatroskaAudioTrackBacking extends MatroskaTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfig = null; + this.internalTrack = internalTrack; + } + getType() { + return "audio"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getNumberOfChannels() { + return this.internalTrack.info.numberOfChannels; + } + getSampleRate() { + return this.internalTrack.info.sampleRate; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfig ?? (this.decoderConfig = { + codec: extractAudioCodecString({ + codec: this.internalTrack.info.codec, + codecDescription: this.internalTrack.info.codecDescription, + aacCodecInfo: this.internalTrack.info.aacCodecInfo + }), + numberOfChannels: this.internalTrack.info.numberOfChannels, + sampleRate: this.internalTrack.info.sampleRate, + description: this.internalTrack.info.codecDescription ?? void 0 + }); + } +} +const readNextMp3FrameHeader = async (reader, startPos, until) => { + const CHUNK_SIZE = 2 ** 16; + let currentPos = startPos; + while (until === null || currentPos < until) { + const maxLength = until !== null ? Math.min(CHUNK_SIZE, until - currentPos) : CHUNK_SIZE; + let slice = reader.requestSliceRange(currentPos, FRAME_HEADER_SIZE, maxLength); + if (slice instanceof Promise) + slice = await slice; + if (!slice || slice.length < FRAME_HEADER_SIZE) + break; + while (slice.remainingLength >= FRAME_HEADER_SIZE) { + const posBeforeRead = slice.filePos; + const word = readU32Be(slice); + const remainingBytes = reader.fileSize !== null ? reader.fileSize - currentPos : null; + const result = readMp3FrameHeader(word, remainingBytes); + if (result.header) { + return { header: result.header, startPos: currentPos }; + } + slice.filePos = posBeforeRead + result.bytesAdvanced; + currentPos = slice.filePos; + } + } + return null; +}; +class Mp3Demuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.firstFrameHeader = null; + this.firstFrameHeaderPos = null; + this.loadedSamples = []; + this.metadataTags = null; + this.xingData = null; + this.trackBackings = []; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.lastLoadedPos = 0; + this.nextTimestampInSamples = 0; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + while (!this.firstFrameHeader && !this.lastSampleLoaded) { + await this.advanceReader(); + } + if (!this.firstFrameHeader) { + throw new Error("No valid MP3 frame found."); + } + this.trackBackings = [new Mp3AudioTrackBacking(this)]; + })()); + } + async advanceReader() { + if (this.lastLoadedPos === 0) { + while (true) { + let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) { + this.lastSampleLoaded = true; + return; + } + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + this.lastLoadedPos = slice2.filePos + id3V2Header.size; + } + } + const result = await readNextMp3FrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize); + if (!result) { + this.lastSampleLoaded = true; + return; + } + const header = result.header; + this.lastLoadedPos = result.startPos + header.totalSize - 1; + const xingOffset = getXingOffset(header.mpegVersionId, header.channel); + let slice = this.reader.requestSlice(result.startPos + xingOffset, 4); + if (slice instanceof Promise) + slice = await slice; + if (slice) { + const word = readU32Be(slice); + const isXing = word === XING || word === INFO; + if (isXing) { + if (!this.xingData) { + let xingDataSlice = this.reader.requestSlice(result.startPos + xingOffset + 4, 12); + if (xingDataSlice instanceof Promise) + xingDataSlice = await xingDataSlice; + if (xingDataSlice) { + const xingData = readBytes(xingDataSlice, 12); + const view = toDataView(xingData); + const flags = view.getUint32(0, false); + this.xingData = { + frameCount: flags & XingFlags.FrameCount ? view.getUint32(4, false) : null, + fileSize: flags & XingFlags.FileSize ? view.getUint32(8, false) : null + }; + } + } + return; + } + } + if (!this.firstFrameHeader) { + this.firstFrameHeader = header; + this.firstFrameHeaderPos = result.startPos; + } + if (header.sampleRate !== this.firstFrameHeader.sampleRate) { + console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${header.sampleRate} Hz. Might be a bug, so please report this file.`); + } + const sampleDuration = header.audioSamplesInFrame / this.firstFrameHeader.sampleRate; + const sample = { + timestamp: this.nextTimestampInSamples / this.firstFrameHeader.sampleRate, + duration: sampleDuration, + dataStart: result.startPos, + dataSize: header.totalSize + }; + this.loadedSamples.push(sample); + this.nextTimestampInSamples += header.audioSamplesInFrame; + return; + } + async getMimeType() { + return "audio/mpeg"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + const release = await this.readingMutex.acquire(); + try { + await this.readMetadata(); + if (this.metadataTags) { + return this.metadataTags; + } + this.metadataTags = {}; + let currentPos = 0; + let id3V2HeaderFound = false; + while (true) { + let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + break; + const id3V2Header = readId3V2Header(headerSlice); + if (!id3V2Header) { + break; + } + id3V2HeaderFound = true; + let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); + if (contentSlice instanceof Promise) + contentSlice = await contentSlice; + if (!contentSlice) + break; + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + currentPos = headerSlice.filePos + id3V2Header.size; + } + if (!id3V2HeaderFound && this.reader.fileSize !== null && this.reader.fileSize >= ID3_V1_TAG_SIZE) { + let slice = this.reader.requestSlice(this.reader.fileSize - ID3_V1_TAG_SIZE, ID3_V1_TAG_SIZE); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const tag = readAscii(slice, 3); + if (tag === "TAG") { + parseId3V1Tag(slice, this.metadataTags); + } + } + return this.metadataTags; + } finally { + release(); + } + } +} +class Mp3AudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getTimeResolution() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.sampleRate / this.demuxer.firstFrameHeader.audioSamplesInFrame; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const demuxer = this.demuxer; + assert(demuxer.firstFrameHeader !== null); + assert(demuxer.firstFrameHeaderPos !== null); + if (demuxer.xingData) { + if (demuxer.xingData.frameCount !== null) { + return demuxer.xingData.frameCount * demuxer.firstFrameHeader.audioSamplesInFrame / demuxer.firstFrameHeader.sampleRate; + } + } else { + if (demuxer.reader.fileSize !== null) { + const averageFrameSize = computeAverageMp3FrameSize(demuxer.firstFrameHeader.lowSamplingFrequency, demuxer.firstFrameHeader.layer, demuxer.firstFrameHeader.bitrate, demuxer.firstFrameHeader.sampleRate); + const frameCount = (demuxer.reader.fileSize - demuxer.firstFrameHeaderPos) / averageFrameSize; + return Math.round(frameCount) * demuxer.firstFrameHeader.audioSamplesInFrame / demuxer.firstFrameHeader.sampleRate; + } + } + return null; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getCodec() { + return "mp3"; + } + getInternalCodecId() { + return null; + } + getNumberOfChannels() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2; + } + getSampleRate() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.sampleRate; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.firstFrameHeader); + return { + codec: "mp3", + numberOfChannels: this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2, + sampleRate: this.demuxer.firstFrameHeader.sampleRate + }; + } + async getPacketAtIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.dataSize); + } + return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); + if (sampleIndex === -1) { + throw new Error("Packet was not created from this track."); + } + const nextIndex = sampleIndex + 1; + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + async getPacket(timestamp, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); + if (index === -1 && this.demuxer.loadedSamples.length > 0) { + return null; + } + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(index, options); + } + if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { + return this.getPacketAtIndex(index, options); + } + await this.demuxer.advanceReader(); + } + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } +} +const OGGS = 1399285583; +const OGG_CRC_POLYNOMIAL = 79764919; +const OGG_CRC_TABLE = new Uint32Array(256); +for (let n = 0; n < 256; n++) { + let crc = n << 24; + for (let k = 0; k < 8; k++) { + crc = crc & 2147483648 ? crc << 1 ^ OGG_CRC_POLYNOMIAL : crc << 1; + } + OGG_CRC_TABLE[n] = crc >>> 0 & 4294967295; +} +const computeOggPageCrc = (bytes) => { + const view = toDataView(bytes); + const originalChecksum = view.getUint32(22, true); + view.setUint32(22, 0, true); + let crc = 0; + for (let i = 0; i < bytes.length; i++) { + const byte = bytes[i]; + crc = (crc << 8 ^ OGG_CRC_TABLE[crc >>> 24 ^ byte]) >>> 0; + } + view.setUint32(22, originalChecksum, true); + return crc; +}; +const extractSampleMetadata = (data, codecInfo, vorbisLastBlocksize) => { + let durationInSamples = 0; + let currentBlocksize = null; + if (data.length > 0) { + if (codecInfo.codec === "vorbis") { + assert(codecInfo.vorbisInfo); + const vorbisModeCount = codecInfo.vorbisInfo.modeBlockflags.length; + const bitCount = ilog(vorbisModeCount - 1); + const modeMask = (1 << bitCount) - 1 << 1; + const modeNumber = (data[0] & modeMask) >> 1; + if (modeNumber >= codecInfo.vorbisInfo.modeBlockflags.length) { + throw new Error("Invalid mode number."); + } + let prevBlocksize = vorbisLastBlocksize; + const blockflag = codecInfo.vorbisInfo.modeBlockflags[modeNumber]; + currentBlocksize = codecInfo.vorbisInfo.blocksizes[blockflag]; + if (blockflag === 1) { + const prevMask = (modeMask | 1) + 1; + const flag = data[0] & prevMask ? 1 : 0; + prevBlocksize = codecInfo.vorbisInfo.blocksizes[flag]; + } + durationInSamples = prevBlocksize !== null ? prevBlocksize + currentBlocksize >> 2 : 0; + } else if (codecInfo.codec === "opus") { + const toc = parseOpusTocByte(data); + durationInSamples = toc.durationInSamples; + } + } + return { + durationInSamples, + vorbisBlockSize: currentBlocksize + }; +}; +const buildOggMimeType = (info) => { + let string = "audio/ogg"; + if (info.codecStrings) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; + } + return string; +}; +const MIN_PAGE_HEADER_SIZE = 27; +const MAX_PAGE_HEADER_SIZE = 27 + 255; +const MAX_PAGE_SIZE = MAX_PAGE_HEADER_SIZE + 255 * 255; +const readPageHeader = (slice) => { + const startPos = slice.filePos; + const capturePattern = readU32Le(slice); + if (capturePattern !== OGGS) { + return null; + } + slice.skip(1); + const headerType = readU8(slice); + const granulePosition = readI64Le(slice); + const serialNumber = readU32Le(slice); + const sequenceNumber = readU32Le(slice); + const checksum = readU32Le(slice); + const numberPageSegments = readU8(slice); + const lacingValues = new Uint8Array(numberPageSegments); + for (let i = 0; i < numberPageSegments; i++) { + lacingValues[i] = readU8(slice); + } + const headerSize = 27 + numberPageSegments; + const dataSize = lacingValues.reduce((a, b) => a + b, 0); + const totalSize = headerSize + dataSize; + return { + headerStartPos: startPos, + totalSize, + dataStartPos: startPos + headerSize, + dataSize, + headerType, + granulePosition, + serialNumber, + sequenceNumber, + checksum, + lacingValues + }; +}; +const findNextPageHeader = (slice, until) => { + while (slice.filePos < until - (4 - 1)) { + const word = readU32Le(slice); + const firstByte = word & 255; + const secondByte = word >>> 8 & 255; + const thirdByte = word >>> 16 & 255; + const fourthByte = word >>> 24 & 255; + const O = 79; + if (firstByte !== O && secondByte !== O && thirdByte !== O && fourthByte !== O) { + continue; + } + slice.skip(-4); + if (word === OGGS) { + return true; + } + slice.skip(1); + } + return false; +}; +class OggDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.bitstreams = []; + this.trackBackings = []; + this.metadataTags = {}; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let currentPos = 0; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const page = readPageHeader(slice); + if (!page) { + break; + } + const isBos = !!(page.headerType & 2); + if (!isBos) { + break; + } + this.bitstreams.push({ + serialNumber: page.serialNumber, + bosPage: page, + description: null, + numberOfChannels: -1, + sampleRate: -1, + codecInfo: { + codec: null, + vorbisInfo: null, + opusInfo: null + }, + lastMetadataPacket: null + }); + currentPos = page.headerStartPos + page.totalSize; + } + for (const bitstream of this.bitstreams) { + const firstPacket = await this.readPacket(bitstream.bosPage, 0); + if (!firstPacket) { + continue; + } + if ( + // Check for Vorbis + firstPacket.data.byteLength >= 7 && firstPacket.data[0] === 1 && firstPacket.data[1] === 118 && firstPacket.data[2] === 111 && firstPacket.data[3] === 114 && firstPacket.data[4] === 98 && firstPacket.data[5] === 105 && firstPacket.data[6] === 115 + ) { + await this.readVorbisMetadata(firstPacket, bitstream); + } else if ( + // Check for Opus + firstPacket.data.byteLength >= 8 && firstPacket.data[0] === 79 && firstPacket.data[1] === 112 && firstPacket.data[2] === 117 && firstPacket.data[3] === 115 && firstPacket.data[4] === 72 && firstPacket.data[5] === 101 && firstPacket.data[6] === 97 && firstPacket.data[7] === 100 + ) { + await this.readOpusMetadata(firstPacket, bitstream); + } + if (bitstream.codecInfo.codec !== null) { + this.trackBackings.push(new OggAudioTrackBacking(bitstream, this)); + } + } + })()); + } + async readVorbisMetadata(firstPacket, bitstream) { + let nextPacketPosition = await this.findNextPacketStart(firstPacket); + if (!nextPacketPosition) { + return; + } + const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!secondPacket) { + return; + } + nextPacketPosition = await this.findNextPacketStart(secondPacket); + if (!nextPacketPosition) { + return; + } + const thirdPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!thirdPacket) { + return; + } + if (secondPacket.data[0] !== 3 || thirdPacket.data[0] !== 5) { + return; + } + const lacingValues = []; + const addBytesToSegmentTable = (bytes) => { + while (true) { + lacingValues.push(Math.min(255, bytes)); + if (bytes < 255) { + break; + } + bytes -= 255; + } + }; + addBytesToSegmentTable(firstPacket.data.length); + addBytesToSegmentTable(secondPacket.data.length); + const description = new Uint8Array(1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length + thirdPacket.data.length); + description[0] = 2; + description.set(lacingValues, 1); + description.set(firstPacket.data, 1 + lacingValues.length); + description.set(secondPacket.data, 1 + lacingValues.length + firstPacket.data.length); + description.set(thirdPacket.data, 1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length); + bitstream.codecInfo.codec = "vorbis"; + bitstream.description = description; + bitstream.lastMetadataPacket = thirdPacket; + const view = toDataView(firstPacket.data); + bitstream.numberOfChannels = view.getUint8(11); + bitstream.sampleRate = view.getUint32(12, true); + const blockSizeByte = view.getUint8(28); + bitstream.codecInfo.vorbisInfo = { + blocksizes: [ + 1 << (blockSizeByte & 15), + 1 << (blockSizeByte >> 4) + ], + modeBlockflags: parseModesFromVorbisSetupPacket(thirdPacket.data).modeBlockflags + }; + readVorbisComments(secondPacket.data.subarray(7), this.metadataTags); + } + async readOpusMetadata(firstPacket, bitstream) { + const nextPacketPosition = await this.findNextPacketStart(firstPacket); + if (!nextPacketPosition) { + return; + } + const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!secondPacket) { + return; + } + bitstream.codecInfo.codec = "opus"; + bitstream.description = firstPacket.data; + bitstream.lastMetadataPacket = secondPacket; + const header = parseOpusIdentificationHeader(firstPacket.data); + bitstream.numberOfChannels = header.outputChannelCount; + bitstream.sampleRate = OPUS_SAMPLE_RATE; + bitstream.codecInfo.opusInfo = { + preSkip: header.preSkip + }; + readVorbisComments(secondPacket.data.subarray(8), this.metadataTags); + } + async readPacket(startPage, startSegmentIndex) { + assert(startSegmentIndex < startPage.lacingValues.length); + let startDataOffset = 0; + for (let i = 0; i < startSegmentIndex; i++) { + startDataOffset += startPage.lacingValues[i]; + } + let currentPage = startPage; + let currentDataOffset = startDataOffset; + let currentSegmentIndex = startSegmentIndex; + const chunks = []; + outer: while (true) { + let pageSlice = this.reader.requestSlice(currentPage.dataStartPos, currentPage.dataSize); + if (pageSlice instanceof Promise) + pageSlice = await pageSlice; + assert(pageSlice); + const pageData = readBytes(pageSlice, currentPage.dataSize); + while (true) { + if (currentSegmentIndex === currentPage.lacingValues.length) { + chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); + break; + } + const lacingValue = currentPage.lacingValues[currentSegmentIndex]; + currentDataOffset += lacingValue; + if (lacingValue < 255) { + chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); + break outer; + } + currentSegmentIndex++; + } + let currentPos = currentPage.headerStartPos + currentPage.totalSize; + while (true) { + let headerSlice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) { + return null; + } + const nextPage = readPageHeader(headerSlice); + if (!nextPage) { + return null; + } + currentPage = nextPage; + if (currentPage.serialNumber === startPage.serialNumber) { + break; + } + currentPos = currentPage.headerStartPos + currentPage.totalSize; + } + startDataOffset = 0; + currentDataOffset = 0; + currentSegmentIndex = 0; + } + const totalPacketSize = chunks.reduce((sum, chunk) => sum + chunk.length, 0); + if (totalPacketSize === 0) { + return null; + } + const packetData = new Uint8Array(totalPacketSize); + let offset = 0; + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + packetData.set(chunk, offset); + offset += chunk.length; + } + return { + data: packetData, + endPage: currentPage, + endSegmentIndex: currentSegmentIndex + }; + } + async findNextPacketStart(lastPacket) { + if (lastPacket.endSegmentIndex < lastPacket.endPage.lacingValues.length - 1) { + return { startPage: lastPacket.endPage, startSegmentIndex: lastPacket.endSegmentIndex + 1 }; + } + const isEos = !!(lastPacket.endPage.headerType & 4); + if (isEos) { + return null; + } + let currentPos = lastPacket.endPage.headerStartPos + lastPacket.endPage.totalSize; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const nextPage = readPageHeader(slice); + if (!nextPage) { + return null; + } + if (nextPage.serialNumber === lastPacket.endPage.serialNumber) { + return { startPage: nextPage, startSegmentIndex: 0 }; + } + currentPos = nextPage.headerStartPos + nextPage.totalSize; + } + } + async getMimeType() { + await this.readMetadata(); + const codecStrings = await Promise.all(this.trackBackings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildOggMimeType({ + codecStrings: codecStrings.filter(Boolean) + }); + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } +} +class OggAudioTrackBacking { + constructor(bitstream, demuxer) { + this.bitstream = bitstream; + this.demuxer = demuxer; + this.encodedPacketToMetadata = /* @__PURE__ */ new WeakMap(); + this.sequentialScanCache = []; + this.sequentialScanMutex = new AsyncMutex(); + this.internalSampleRate = bitstream.codecInfo.codec === "opus" ? OPUS_SAMPLE_RATE : bitstream.sampleRate; + } + getType() { + return "audio"; + } + getId() { + return this.bitstream.serialNumber; + } + getNumber() { + const index = this.demuxer.trackBackings.findIndex((x) => x.bitstream === this.bitstream); + assert(index !== -1); + return index + 1; + } + getNumberOfChannels() { + return this.bitstream.numberOfChannels; + } + getSampleRate() { + return this.bitstream.sampleRate; + } + getTimeResolution() { + return this.bitstream.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + getCodec() { + return this.bitstream.codecInfo.codec; + } + getInternalCodecId() { + return null; + } + async getDecoderConfig() { + assert(this.bitstream.codecInfo.codec); + return { + codec: this.bitstream.codecInfo.codec, + numberOfChannels: this.bitstream.numberOfChannels, + sampleRate: this.bitstream.sampleRate, + description: this.bitstream.description ?? void 0 + }; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }; + } + granulePositionToTimestampInSamples(granulePosition) { + if (this.bitstream.codecInfo.codec === "opus") { + assert(this.bitstream.codecInfo.opusInfo); + return granulePosition - this.bitstream.codecInfo.opusInfo.preSkip; + } + return granulePosition; + } + createEncodedPacketFromOggPacket(packet, additional, options) { + if (!packet) { + return null; + } + const { durationInSamples, vorbisBlockSize } = extractSampleMetadata(packet.data, this.bitstream.codecInfo, additional.vorbisLastBlocksize); + const encodedPacket = new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : packet.data, "key", Math.max(0, additional.timestampInSamples) / this.internalSampleRate, durationInSamples / this.internalSampleRate, packet.endPage.headerStartPos + packet.endSegmentIndex, packet.data.byteLength); + this.encodedPacketToMetadata.set(encodedPacket, { + packet, + timestampInSamples: additional.timestampInSamples, + durationInSamples, + vorbisLastBlockSize: additional.vorbisLastBlocksize, + vorbisBlockSize + }); + return encodedPacket; + } + async getFirstPacket(options) { + assert(this.bitstream.lastMetadataPacket); + const packetPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); + if (!packetPosition) { + return null; + } + let timestampInSamples = 0; + if (this.bitstream.codecInfo.codec === "opus") { + assert(this.bitstream.codecInfo.opusInfo); + timestampInSamples -= this.bitstream.codecInfo.opusInfo.preSkip; + } + const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); + return this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples, + vorbisLastBlocksize: null + }, options); + } + async getNextPacket(prevPacket, options) { + const prevMetadata = this.encodedPacketToMetadata.get(prevPacket); + if (!prevMetadata) { + throw new Error("Packet was not created from this track."); + } + const packetPosition = await this.demuxer.findNextPacketStart(prevMetadata.packet); + if (!packetPosition) { + return null; + } + const timestampInSamples = prevMetadata.timestampInSamples + prevMetadata.durationInSamples; + const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); + return this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples, + vorbisLastBlocksize: prevMetadata.vorbisBlockSize + }, options); + } + async getPacket(timestamp, options) { + if (this.demuxer.reader.fileSize === null) { + return this.getPacketSequential(timestamp, options); + } + const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); + if (timestampInSamples === 0) { + return this.getFirstPacket(options); + } + if (timestampInSamples < 0) { + return null; + } + assert(this.bitstream.lastMetadataPacket); + const startPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); + if (!startPosition) { + return null; + } + let lowPage = startPosition.startPage; + let high = this.demuxer.reader.fileSize; + const lowPages = [lowPage]; + outer: while (lowPage.headerStartPos + lowPage.totalSize < high) { + const low = lowPage.headerStartPos; + const mid = Math.floor((low + high) / 2); + let searchStartPos = mid; + while (true) { + const until = Math.min(searchStartPos + MAX_PAGE_SIZE, high - MIN_PAGE_HEADER_SIZE); + let searchSlice = this.demuxer.reader.requestSlice(searchStartPos, until - searchStartPos); + if (searchSlice instanceof Promise) + searchSlice = await searchSlice; + assert(searchSlice); + const found = findNextPageHeader(searchSlice, until); + if (!found) { + high = mid + MIN_PAGE_HEADER_SIZE; + continue outer; + } + let headerSlice = this.demuxer.reader.requestSliceRange(searchSlice.filePos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const page = readPageHeader(headerSlice); + assert(page); + let pageValid = false; + if (page.serialNumber === this.bitstream.serialNumber) { + pageValid = true; + } else { + let pageSlice = this.demuxer.reader.requestSlice(page.headerStartPos, page.totalSize); + if (pageSlice instanceof Promise) + pageSlice = await pageSlice; + assert(pageSlice); + const bytes = readBytes(pageSlice, page.totalSize); + const crc = computeOggPageCrc(bytes); + pageValid = crc === page.checksum; + } + if (!pageValid) { + searchStartPos = page.headerStartPos + 4; + continue; + } + if (pageValid && page.serialNumber !== this.bitstream.serialNumber) { + searchStartPos = page.headerStartPos + page.totalSize; + continue; + } + const isContinuationPage = page.granulePosition === -1; + if (isContinuationPage) { + searchStartPos = page.headerStartPos + page.totalSize; + continue; + } + if (this.granulePositionToTimestampInSamples(page.granulePosition) > timestampInSamples) { + high = page.headerStartPos; + } else { + lowPage = page; + lowPages.push(page); + } + continue outer; + } + } + let lowerPage = startPosition.startPage; + for (const otherLowPage of lowPages) { + if (otherLowPage.granulePosition === lowPage.granulePosition) { + break; + } + if (!lowerPage || otherLowPage.headerStartPos > lowerPage.headerStartPos) { + lowerPage = otherLowPage; + } + } + let currentPage = lowerPage; + const previousPages = [currentPage]; + while (true) { + if (currentPage.serialNumber === this.bitstream.serialNumber && currentPage.granulePosition === lowPage.granulePosition) { + break; + } + const nextPos = currentPage.headerStartPos + currentPage.totalSize; + let slice = this.demuxer.reader.requestSliceRange(nextPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const nextPage = readPageHeader(slice); + assert(nextPage); + currentPage = nextPage; + if (currentPage.serialNumber === this.bitstream.serialNumber) { + previousPages.push(currentPage); + } + } + assert(currentPage.granulePosition !== -1); + let currentSegmentIndex = null; + let currentTimestampInSamples; + let currentTimestampIsCorrect; + let endPage = currentPage; + let endSegmentIndex = 0; + if (currentPage.headerStartPos === startPosition.startPage.headerStartPos) { + currentTimestampInSamples = this.granulePositionToTimestampInSamples(0); + currentTimestampIsCorrect = true; + currentSegmentIndex = 0; + } else { + currentTimestampInSamples = 0; + currentTimestampIsCorrect = false; + for (let i = currentPage.lacingValues.length - 1; i >= 0; i--) { + const value = currentPage.lacingValues[i]; + if (value < 255) { + currentSegmentIndex = i + 1; + break; + } + } + if (currentSegmentIndex === null) { + throw new Error("Invalid page with granule position: no packets end on this page."); + } + endSegmentIndex = currentSegmentIndex - 1; + const pseudopacket = { + data: PLACEHOLDER_DATA, + endPage, + endSegmentIndex + }; + const nextPosition = await this.demuxer.findNextPacketStart(pseudopacket); + if (nextPosition) { + const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); + assert(endPosition); + const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); + if (startPosition2) { + currentPage = startPosition2.page; + currentSegmentIndex = startPosition2.segmentIndex; + } + } else { + while (true) { + const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); + if (!endPosition) { + break; + } + const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); + if (!startPosition2) { + break; + } + currentPage = startPosition2.page; + currentSegmentIndex = startPosition2.segmentIndex; + if (endPosition.page.headerStartPos !== endPage.headerStartPos) { + endPage = endPosition.page; + endSegmentIndex = endPosition.segmentIndex; + break; + } + } + } + } + let lastEncodedPacket = null; + let lastEncodedPacketMetadata = null; + while (currentPage !== null) { + assert(currentSegmentIndex !== null); + const packet = await this.demuxer.readPacket(currentPage, currentSegmentIndex); + if (!packet) { + break; + } + const skipPacket = currentPage.headerStartPos === startPosition.startPage.headerStartPos && currentSegmentIndex < startPosition.startSegmentIndex; + if (!skipPacket) { + let encodedPacket = this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples: currentTimestampInSamples, + vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null + }, options); + assert(encodedPacket); + let encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); + assert(encodedPacketMetadata); + if (!currentTimestampIsCorrect && packet.endPage.headerStartPos === endPage.headerStartPos && packet.endSegmentIndex === endSegmentIndex) { + currentTimestampInSamples = this.granulePositionToTimestampInSamples(currentPage.granulePosition); + currentTimestampIsCorrect = true; + encodedPacket = this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples: currentTimestampInSamples - encodedPacketMetadata.durationInSamples, + vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null + }, options); + assert(encodedPacket); + encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); + assert(encodedPacketMetadata); + } else { + currentTimestampInSamples += encodedPacketMetadata.durationInSamples; + } + lastEncodedPacket = encodedPacket; + lastEncodedPacketMetadata = encodedPacketMetadata; + if (currentTimestampIsCorrect && // Next timestamp will be too late + (Math.max(currentTimestampInSamples, 0) > timestampInSamples || Math.max(encodedPacketMetadata.timestampInSamples, 0) === timestampInSamples)) { + break; + } + } + const nextPosition = await this.demuxer.findNextPacketStart(packet); + if (!nextPosition) { + break; + } + currentPage = nextPosition.startPage; + currentSegmentIndex = nextPosition.startSegmentIndex; + } + return lastEncodedPacket; + } + // A slower but simpler and sequential algorithm for finding a packet in a file + async getPacketSequential(timestamp, options) { + const release = await this.sequentialScanMutex.acquire(); + try { + const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); + timestamp = timestampInSamples / this.internalSampleRate; + const index = binarySearchLessOrEqual(this.sequentialScanCache, timestampInSamples, (x) => x.timestampInSamples); + let currentPacket; + if (index !== -1) { + const cacheEntry = this.sequentialScanCache[index]; + currentPacket = this.createEncodedPacketFromOggPacket(cacheEntry.packet, { + timestampInSamples: cacheEntry.timestampInSamples, + vorbisLastBlocksize: cacheEntry.vorbisLastBlockSize + }, options); + } else { + currentPacket = await this.getFirstPacket(options); + } + let i = 0; + while (currentPacket && currentPacket.timestamp < timestamp) { + const nextPacket = await this.getNextPacket(currentPacket, options); + if (!nextPacket || nextPacket.timestamp > timestamp) { + break; + } + currentPacket = nextPacket; + i++; + if (i === 100) { + i = 0; + const metadata = this.encodedPacketToMetadata.get(currentPacket); + assert(metadata); + if (this.sequentialScanCache.length > 0) { + assert(last(this.sequentialScanCache).timestampInSamples <= metadata.timestampInSamples); + } + this.sequentialScanCache.push(metadata); + } + } + return currentPacket; + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } +} +const findPacketStartPosition = (pageList, endPage, endSegmentIndex) => { + let page = endPage; + let segmentIndex = endSegmentIndex; + outer: while (true) { + segmentIndex--; + for (segmentIndex; segmentIndex >= 0; segmentIndex--) { + const lacingValue = page.lacingValues[segmentIndex]; + if (lacingValue < 255) { + segmentIndex++; + break outer; + } + } + assert(segmentIndex === -1); + const pageStartsWithFreshPacket = !(page.headerType & 1); + if (pageStartsWithFreshPacket) { + segmentIndex = 0; + break; + } + const previousPage = findLast(pageList, (x) => x.headerStartPos < page.headerStartPos); + if (!previousPage) { + return null; + } + page = previousPage; + segmentIndex = page.lacingValues.length; + } + assert(segmentIndex !== -1); + if (segmentIndex === page.lacingValues.length) { + const nextPage = pageList[pageList.indexOf(page) + 1]; + assert(nextPage); + page = nextPage; + segmentIndex = 0; + } + return { page, segmentIndex }; +}; +const findPreviousPacketEndPosition = (pageList, startPage, startSegmentIndex) => { + if (startSegmentIndex > 0) { + return { page: startPage, segmentIndex: startSegmentIndex - 1 }; + } + const previousPage = findLast(pageList, (x) => x.headerStartPos < startPage.headerStartPos); + if (!previousPage) { + return null; + } + return { page: previousPage, segmentIndex: previousPage.lacingValues.length - 1 }; +}; +var WaveFormat; +(function(WaveFormat2) { + WaveFormat2[WaveFormat2["PCM"] = 1] = "PCM"; + WaveFormat2[WaveFormat2["IEEE_FLOAT"] = 3] = "IEEE_FLOAT"; + WaveFormat2[WaveFormat2["ALAW"] = 6] = "ALAW"; + WaveFormat2[WaveFormat2["MULAW"] = 7] = "MULAW"; + WaveFormat2[WaveFormat2["EXTENSIBLE"] = 65534] = "EXTENSIBLE"; +})(WaveFormat || (WaveFormat = {})); +class WaveDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.dataStart = -1; + this.dataSize = -1; + this.audioInfo = null; + this.trackBackings = []; + this.lastKnownPacketIndex = 0; + this.metadataTags = {}; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let slice = this.reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const riffType = readAscii(slice, 4); + const littleEndian = riffType !== "RIFX"; + const isRf64 = riffType === "RF64"; + const outerChunkSize = readU32(slice, littleEndian); + let totalFileSize = isRf64 ? this.reader.fileSize : Math.min(outerChunkSize + 8, this.reader.fileSize ?? Infinity); + const format = readAscii(slice, 4); + if (format !== "WAVE") { + throw new Error("Invalid WAVE file - wrong format"); + } + let chunksRead = 0; + let dataChunkSize = null; + let currentPos = slice.filePos; + while (totalFileSize === null || currentPos < totalFileSize) { + let slice2 = this.reader.requestSlice(currentPos, 8); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const chunkId = readAscii(slice2, 4); + const chunkSize = readU32(slice2, littleEndian); + const startPos = slice2.filePos; + if (isRf64 && chunksRead === 0 && chunkId !== "ds64") { + throw new Error('Invalid RF64 file: First chunk must be "ds64".'); + } + if (chunkId === "fmt ") { + await this.parseFmtChunk(startPos, chunkSize, littleEndian); + } else if (chunkId === "data") { + dataChunkSize ?? (dataChunkSize = chunkSize); + this.dataStart = slice2.filePos; + this.dataSize = Math.min(dataChunkSize, (totalFileSize ?? Infinity) - this.dataStart); + if (this.reader.fileSize === null) { + break; + } + } else if (chunkId === "ds64") { + let ds64Slice = this.reader.requestSlice(startPos, chunkSize); + if (ds64Slice instanceof Promise) + ds64Slice = await ds64Slice; + if (!ds64Slice) + break; + const riffChunkSize = readU64(ds64Slice, littleEndian); + dataChunkSize = readU64(ds64Slice, littleEndian); + totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity); + } else if (chunkId === "LIST") { + await this.parseListChunk(startPos, chunkSize, littleEndian); + } else if (chunkId === "ID3 " || chunkId === "id3 ") { + await this.parseId3Chunk(startPos, chunkSize); + } + currentPos = startPos + chunkSize + (chunkSize & 1); + chunksRead++; + } + if (!this.audioInfo) { + throw new Error('Invalid WAVE file - missing "fmt " chunk'); + } + if (this.dataStart === -1) { + throw new Error('Invalid WAVE file - missing "data" chunk'); + } + const blockSize = this.audioInfo.blockSizeInBytes; + this.dataSize = Math.floor(this.dataSize / blockSize) * blockSize; + this.trackBackings.push(new WaveAudioTrackBacking(this)); + })()); + } + async parseFmtChunk(startPos, size, littleEndian) { + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + let formatTag = readU16(slice, littleEndian); + const numChannels = readU16(slice, littleEndian); + const sampleRate = readU32(slice, littleEndian); + slice.skip(4); + const blockAlign = readU16(slice, littleEndian); + let bitsPerSample; + if (size === 14) { + bitsPerSample = 8; + } else { + bitsPerSample = readU16(slice, littleEndian); + } + if (size >= 18 && formatTag !== 357) { + const cbSize = readU16(slice, littleEndian); + const remainingSize = size - 18; + const extensionSize = Math.min(remainingSize, cbSize); + if (extensionSize >= 22 && formatTag === WaveFormat.EXTENSIBLE) { + slice.skip(2 + 4); + const subFormat = readBytes(slice, 16); + formatTag = subFormat[0] | subFormat[1] << 8; + } + } + if (formatTag === WaveFormat.MULAW || formatTag === WaveFormat.ALAW) { + bitsPerSample = 8; + } + this.audioInfo = { + format: formatTag, + numberOfChannels: numChannels, + sampleRate, + sampleSizeInBytes: Math.ceil(bitsPerSample / 8), + blockSizeInBytes: blockAlign + }; + } + async parseListChunk(startPos, size, littleEndian) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + const infoType = readAscii(slice, 4); + if (infoType !== "INFO" && infoType !== "INF0") { + return; + } + let currentPos = slice.filePos; + while (currentPos <= startPos + size - 8) { + slice.filePos = currentPos; + const chunkName = readAscii(slice, 4); + const chunkSize = readU32(slice, littleEndian); + const bytes = readBytes(slice, chunkSize); + let stringLength = 0; + for (let i = 0; i < bytes.length; i++) { + if (bytes[i] === 0) { + break; + } + stringLength++; + } + const value = String.fromCharCode(...bytes.subarray(0, stringLength)); + (_a = this.metadataTags).raw ?? (_a.raw = {}); + this.metadataTags.raw[chunkName] = value; + switch (chunkName) { + case "INAM": + case "TITL": + { + (_b = this.metadataTags).title ?? (_b.title = value); + } + break; + case "TIT3": + { + (_c = this.metadataTags).description ?? (_c.description = value); + } + break; + case "IART": + { + (_d = this.metadataTags).artist ?? (_d.artist = value); + } + break; + case "IPRD": + { + (_e = this.metadataTags).album ?? (_e.album = value); + } + break; + case "IPRT": + case "ITRK": + case "TRCK": + { + const parts = value.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + (_f = this.metadataTags).trackNumber ?? (_f.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + (_g = this.metadataTags).tracksTotal ?? (_g.tracksTotal = tracksTotal); + } + } + break; + case "ICRD": + case "IDIT": + { + const date = new Date(value); + if (!Number.isNaN(date.getTime())) { + (_h = this.metadataTags).date ?? (_h.date = date); + } + } + break; + case "YEAR": + { + const year = Number.parseInt(value, 10); + if (Number.isInteger(year) && year > 0) { + (_i = this.metadataTags).date ?? (_i.date = new Date(year, 0, 1)); + } + } + break; + case "IGNR": + case "GENR": + { + (_j = this.metadataTags).genre ?? (_j.genre = value); + } + break; + case "ICMT": + case "CMNT": + case "COMM": + { + (_k = this.metadataTags).comment ?? (_k.comment = value); + } + break; + } + currentPos += 8 + chunkSize + (chunkSize & 1); + } + } + async parseId3Chunk(startPos, size) { + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + const id3V2Header = readId3V2Header(slice); + if (id3V2Header) { + const availableSize = size - ID3_V2_HEADER_SIZE; + id3V2Header.size = Math.min(id3V2Header.size, availableSize); + if (id3V2Header.size > 0) { + const contentSlice = slice.slice(startPos + ID3_V2_HEADER_SIZE, id3V2Header.size); + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + } + } + } + getCodec() { + assert(this.audioInfo); + if (this.audioInfo.format === WaveFormat.MULAW) { + return "ulaw"; + } + if (this.audioInfo.format === WaveFormat.ALAW) { + return "alaw"; + } + if (this.audioInfo.format === WaveFormat.PCM) { + if (this.audioInfo.sampleSizeInBytes === 1) { + return "pcm-u8"; + } else if (this.audioInfo.sampleSizeInBytes === 2) { + return "pcm-s16"; + } else if (this.audioInfo.sampleSizeInBytes === 3) { + return "pcm-s24"; + } else if (this.audioInfo.sampleSizeInBytes === 4) { + return "pcm-s32"; + } + } + if (this.audioInfo.format === WaveFormat.IEEE_FLOAT) { + if (this.audioInfo.sampleSizeInBytes === 4) { + return "pcm-f32"; + } + } + return null; + } + async getMimeType() { + return "audio/wav"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } +} +const PACKET_SIZE_IN_FRAMES = 2048; +class WaveAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getCodec() { + return this.demuxer.getCodec(); + } + getInternalCodecId() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.format; + } + async getDecoderConfig() { + const codec = this.demuxer.getCodec(); + if (!codec) { + return null; + } + assert(this.demuxer.audioInfo); + return { + codec, + numberOfChannels: this.demuxer.audioInfo.numberOfChannels, + sampleRate: this.demuxer.audioInfo.sampleRate + }; + } + getNumberOfChannels() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + getTimeResolution() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + assert(this.demuxer.dataSize !== -1); + return this.demuxer.dataSize / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getPacketAtIndex(packetIndex, options) { + assert(packetIndex >= 0); + assert(this.demuxer.audioInfo); + const startOffset = packetIndex * PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes; + if (startOffset >= this.demuxer.dataSize) { + return null; + } + const sizeInBytes = Math.min(PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes, this.demuxer.dataSize - startOffset); + if (this.demuxer.reader.fileSize === null) { + let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + data = readBytes(slice, sizeInBytes); + } + const timestamp = packetIndex * PACKET_SIZE_IN_FRAMES / this.demuxer.audioInfo.sampleRate; + const duration = sizeInBytes / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; + this.demuxer.lastKnownPacketIndex = Math.max(packetIndex, this.demuxer.lastKnownPacketIndex); + return new EncodedPacket(data, "key", timestamp, duration, packetIndex, sizeInBytes); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getPacket(timestamp, options) { + assert(this.demuxer.audioInfo); + const packetIndex = Math.floor(Math.min(timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES, (this.demuxer.dataSize - 1) / (PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes))); + if (packetIndex < 0) { + return null; + } + const packet = await this.getPacketAtIndex(packetIndex, options); + if (packet) { + return packet; + } + if (packetIndex === 0) { + return null; + } + assert(this.demuxer.reader.fileSize === null); + let currentPacket = await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex, options); + while (currentPacket) { + const nextPacket = await this.getNextPacket(currentPacket, options); + if (!nextPacket) { + break; + } + currentPacket = nextPacket; + } + return currentPacket; + } + getNextPacket(packet, options) { + assert(this.demuxer.audioInfo); + const packetIndex = Math.round(packet.timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES); + return this.getPacketAtIndex(packetIndex + 1, options); + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } +} +const MIN_ADTS_FRAME_HEADER_SIZE = 7; +const MAX_ADTS_FRAME_HEADER_SIZE = 9; +const readAdtsFrameHeader = (slice) => { + const startPos = slice.filePos; + const bytes = readBytes(slice, 9); + const bitstream = new Bitstream(bytes); + const syncword = bitstream.readBits(12); + if (syncword !== 4095) { + return null; + } + bitstream.skipBits(1); + const layer = bitstream.readBits(2); + if (layer !== 0) { + return null; + } + const protectionAbsence = bitstream.readBits(1); + const objectType = bitstream.readBits(2) + 1; + const samplingFrequencyIndex = bitstream.readBits(4); + if (samplingFrequencyIndex === 15) { + return null; + } + bitstream.skipBits(1); + const channelConfiguration = bitstream.readBits(3); + if (channelConfiguration === 0) { + throw new Error("ADTS frames with channel configuration 0 are not supported."); + } + bitstream.skipBits(1); + bitstream.skipBits(1); + bitstream.skipBits(1); + bitstream.skipBits(1); + const frameLength = bitstream.readBits(13); + bitstream.skipBits(11); + const numberOfAacFrames = bitstream.readBits(2) + 1; + if (numberOfAacFrames !== 1) { + throw new Error("ADTS frames with more than one AAC frame are not supported."); + } + let crcCheck = null; + if (protectionAbsence === 1) { + slice.filePos -= 2; + } else { + crcCheck = bitstream.readBits(16); + } + return { + objectType, + samplingFrequencyIndex, + channelConfiguration, + frameLength, + numberOfAacFrames, + crcCheck, + startPos + }; +}; +const SAMPLES_PER_AAC_FRAME = 1024; +class AdtsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.firstFrameHeader = null; + this.loadedSamples = []; + this.metadataTags = null; + this.trackBackings = []; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.lastLoadedPos = 0; + this.nextTimestampInSamples = 0; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + while (!this.firstFrameHeader && !this.lastSampleLoaded) { + await this.advanceReader(); + } + assert(this.firstFrameHeader); + this.trackBackings = [new AdtsAudioTrackBacking(this)]; + })()); + } + async advanceReader() { + if (this.lastLoadedPos === 0) { + while (true) { + let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) { + this.lastSampleLoaded = true; + return; + } + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + this.lastLoadedPos = slice2.filePos + id3V2Header.size; + } + } + let slice = this.reader.requestSliceRange(this.lastLoadedPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + this.lastSampleLoaded = true; + return; + } + const header = readAdtsFrameHeader(slice); + if (!header) { + this.lastSampleLoaded = true; + return; + } + if (this.reader.fileSize !== null && header.startPos + header.frameLength > this.reader.fileSize) { + this.lastSampleLoaded = true; + return; + } + if (!this.firstFrameHeader) { + this.firstFrameHeader = header; + } + const sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; + assert(sampleRate !== void 0); + const sampleDuration = SAMPLES_PER_AAC_FRAME / sampleRate; + const sample = { + timestamp: this.nextTimestampInSamples / sampleRate, + duration: sampleDuration, + dataStart: header.startPos, + dataSize: header.frameLength + }; + this.loadedSamples.push(sample); + this.nextTimestampInSamples += SAMPLES_PER_AAC_FRAME; + this.lastLoadedPos = header.startPos + header.frameLength; + } + async getMimeType() { + return "audio/aac"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + const release = await this.readingMutex.acquire(); + try { + await this.readMetadata(); + if (this.metadataTags) { + return this.metadataTags; + } + this.metadataTags = {}; + let currentPos = 0; + while (true) { + let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + break; + const id3V2Header = readId3V2Header(headerSlice); + if (!id3V2Header) { + break; + } + let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); + if (contentSlice instanceof Promise) + contentSlice = await contentSlice; + if (!contentSlice) + break; + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + currentPos = headerSlice.filePos + id3V2Header.size; + } + return this.metadataTags; + } finally { + release(); + } + } +} +class AdtsAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getTimeResolution() { + const sampleRate = this.getSampleRate(); + return sampleRate / SAMPLES_PER_AAC_FRAME; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getCodec() { + return "aac"; + } + getInternalCodecId() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.objectType; + } + getNumberOfChannels() { + assert(this.demuxer.firstFrameHeader); + const numberOfChannels = aacChannelMap[this.demuxer.firstFrameHeader.channelConfiguration]; + assert(numberOfChannels !== void 0); + return numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.firstFrameHeader); + const sampleRate = aacFrequencyTable[this.demuxer.firstFrameHeader.samplingFrequencyIndex]; + assert(sampleRate !== void 0); + return sampleRate; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.firstFrameHeader); + return { + codec: `mp4a.40.${this.demuxer.firstFrameHeader.objectType}`, + numberOfChannels: this.getNumberOfChannels(), + sampleRate: this.getSampleRate() + }; + } + async getPacketAtIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.dataSize); + } + return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); + if (sampleIndex === -1) { + throw new Error("Packet was not created from this track."); + } + const nextIndex = sampleIndex + 1; + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + async getPacket(timestamp, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); + if (index === -1 && this.demuxer.loadedSamples.length > 0) { + return null; + } + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(index, options); + } + if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { + return this.getPacketAtIndex(index, options); + } + await this.demuxer.advanceReader(); + } + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } +} +const getBlockSizeOrUncommon = (bits) => { + if (bits === 0) { + return null; + } else if (bits === 1) { + return 192; + } else if (bits >= 2 && bits <= 5) { + return 144 * 2 ** bits; + } else if (bits === 6) { + return "uncommon-u8"; + } else if (bits === 7) { + return "uncommon-u16"; + } else if (bits >= 8 && bits <= 15) { + return 2 ** bits; + } else { + return null; + } +}; +const getSampleRateOrUncommon = (sampleRateBits, streamInfoSampleRate) => { + switch (sampleRateBits) { + case 0: + return streamInfoSampleRate; + case 1: + return 88200; + case 2: + return 176400; + case 3: + return 192e3; + case 4: + return 8e3; + case 5: + return 16e3; + case 6: + return 22050; + case 7: + return 24e3; + case 8: + return 32e3; + case 9: + return 44100; + case 10: + return 48e3; + case 11: + return 96e3; + case 12: + return "uncommon-u8"; + case 13: + return "uncommon-u16"; + case 14: + return "uncommon-u16-10"; + default: + return null; + } +}; +const readCodedNumber = (fileSlice) => { + let ones = 0; + const bitstream1 = new Bitstream(readBytes(fileSlice, 1)); + while (bitstream1.readBits(1) === 1) { + ones++; + } + if (ones === 0) { + return bitstream1.readBits(7); + } + const bitArray = []; + const extraBytes = ones - 1; + const bitstream2 = new Bitstream(readBytes(fileSlice, extraBytes)); + const firstByteBits = 8 - ones - 1; + for (let i = 0; i < firstByteBits; i++) { + bitArray.unshift(bitstream1.readBits(1)); + } + for (let i = 0; i < extraBytes; i++) { + for (let j = 0; j < 8; j++) { + const val = bitstream2.readBits(1); + if (j < 2) { + continue; + } + bitArray.unshift(val); + } + } + const encoded = bitArray.reduce((acc, bit, index) => { + return acc | bit << index; + }, 0); + return encoded; +}; +const readBlockSize = (slice, blockSizeBits) => { + if (blockSizeBits === "uncommon-u16") { + return readU16Be(slice) + 1; + } else if (blockSizeBits === "uncommon-u8") { + return readU8(slice) + 1; + } else if (typeof blockSizeBits === "number") { + return blockSizeBits; + } else { + assertNever(blockSizeBits); + assert(false); + } +}; +const readSampleRate = (slice, sampleRateOrUncommon) => { + if (sampleRateOrUncommon === "uncommon-u16") { + return readU16Be(slice); + } + if (sampleRateOrUncommon === "uncommon-u16-10") { + return readU16Be(slice) * 10; + } + if (sampleRateOrUncommon === "uncommon-u8") { + return readU8(slice); + } + if (typeof sampleRateOrUncommon === "number") { + return sampleRateOrUncommon; + } + return null; +}; +const calculateCrc8 = (data) => { + const polynomial = 7; + let crc = 0; + for (const byte of data) { + crc ^= byte; + for (let i = 0; i < 8; i++) { + if ((crc & 128) !== 0) { + crc = crc << 1 ^ polynomial; + } else { + crc <<= 1; + } + crc &= 255; + } + } + return crc; +}; +class FlacDemuxer extends Demuxer { + constructor(input) { + super(input); + this.loadedSamples = []; + this.metadataPromise = null; + this.trackBacking = null; + this.metadataTags = {}; + this.audioInfo = null; + this.lastLoadedPos = null; + this.blockingBit = null; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.reader = input._reader; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } + async getTrackBackings() { + await this.readMetadata(); + assert(this.trackBacking); + return [this.trackBacking]; + } + async getMimeType() { + return "audio/flac"; + } + async readMetadata() { + let currentPos = 4; + return this.metadataPromise ?? (this.metadataPromise = (async () => { + var _a; + while (this.reader.fileSize === null || currentPos < this.reader.fileSize) { + let sizeSlice = this.reader.requestSlice(currentPos, 4); + if (sizeSlice instanceof Promise) + sizeSlice = await sizeSlice; + currentPos += 4; + if (sizeSlice === null) { + throw new Error(`Metadata block at position ${currentPos} is too small! Corrupted file.`); + } + assert(sizeSlice); + const byte = readU8(sizeSlice); + const size = readU24Be(sizeSlice); + const isLastMetadata = (byte & 128) !== 0; + const metaBlockType = byte & 127; + switch (metaBlockType) { + case FlacBlockType.STREAMINFO: { + let streamInfoBlock = this.reader.requestSlice(currentPos, size); + if (streamInfoBlock instanceof Promise) + streamInfoBlock = await streamInfoBlock; + assert(streamInfoBlock); + if (streamInfoBlock === null) { + throw new Error(`StreamInfo block at position ${currentPos} is too small! Corrupted file.`); + } + const streamInfoBytes = readBytes(streamInfoBlock, 34); + const bitstream = new Bitstream(streamInfoBytes); + const minimumBlockSize = bitstream.readBits(16); + const maximumBlockSize = bitstream.readBits(16); + const minimumFrameSize = bitstream.readBits(24); + const maximumFrameSize = bitstream.readBits(24); + const sampleRate = bitstream.readBits(20); + const numberOfChannels = bitstream.readBits(3) + 1; + bitstream.readBits(5); + const totalSamples = bitstream.readBits(36); + bitstream.skipBits(16 * 8); + const description = new Uint8Array(42); + description.set(new Uint8Array([102, 76, 97, 67]), 0); + description.set(new Uint8Array([128, 0, 0, 34]), 4); + description.set(streamInfoBytes, 8); + this.audioInfo = { + numberOfChannels, + sampleRate, + totalSamples, + minimumBlockSize, + maximumBlockSize, + minimumFrameSize, + maximumFrameSize, + description + }; + this.trackBacking = new FlacAudioTrackBacking(this); + break; + } + case FlacBlockType.VORBIS_COMMENT: { + let vorbisCommentBlock = this.reader.requestSlice(currentPos, size); + if (vorbisCommentBlock instanceof Promise) + vorbisCommentBlock = await vorbisCommentBlock; + assert(vorbisCommentBlock); + readVorbisComments(readBytes(vorbisCommentBlock, size), this.metadataTags); + break; + } + case FlacBlockType.PICTURE: { + let pictureBlock = this.reader.requestSlice(currentPos, size); + if (pictureBlock instanceof Promise) + pictureBlock = await pictureBlock; + assert(pictureBlock); + const pictureType = readU32Be(pictureBlock); + const mediaTypeLength = readU32Be(pictureBlock); + const mediaType = textDecoder.decode(readBytes(pictureBlock, mediaTypeLength)); + const descriptionLength = readU32Be(pictureBlock); + const description = textDecoder.decode(readBytes(pictureBlock, descriptionLength)); + pictureBlock.skip(4 + 4 + 4 + 4); + const dataLength = readU32Be(pictureBlock); + const data = readBytes(pictureBlock, dataLength); + (_a = this.metadataTags).images ?? (_a.images = []); + this.metadataTags.images.push({ + data, + mimeType: mediaType, + // https://www.rfc-editor.org/rfc/rfc9639.html#table13 + kind: pictureType === 3 ? "coverFront" : pictureType === 4 ? "coverBack" : "unknown", + description + }); + break; + } + } + currentPos += size; + if (isLastMetadata) { + this.lastLoadedPos = currentPos; + break; + } + } + if (!this.audioInfo) { + throw new Error("Missing STREAMINFO metadata block! Corrupted FLAC file."); + } + })()); + } + async readNextFlacFrame({ startPos, isFirstPacket }) { + assert(this.audioInfo); + const minimumHeaderLength = 6; + const maximumHeaderLength = 16; + const minimumFrameLength = 10; + const maximumFrameLength = this.audioInfo.maximumBlockSize * this.audioInfo.numberOfChannels * 4 + maximumHeaderLength + 2; + const effectiveMinFrameSize = this.audioInfo.minimumFrameSize || minimumFrameLength; + const effectiveMaxFrameSize = this.audioInfo.maximumFrameSize || maximumFrameLength; + const maximumSliceLength = effectiveMaxFrameSize + maximumHeaderLength; + const slice = await this.reader.requestSliceRange(startPos, maximumHeaderLength, maximumSliceLength); + if (!slice) { + return null; + } + const frameHeader = this.readFlacFrameHeader({ + slice, + isFirstPacket + }); + if (!frameHeader) { + return null; + } + slice.filePos = startPos + effectiveMinFrameSize; + while (true) { + if (slice.filePos > slice.end - minimumHeaderLength) { + return { + num: frameHeader.num, + blockSize: frameHeader.blockSize, + sampleRate: frameHeader.sampleRate, + size: slice.end - startPos, + isLastFrame: true + }; + } + const nextByte = readU8(slice); + if (nextByte === 255) { + const positionBeforeReading = slice.filePos; + const byteAfterNextByte = readU8(slice); + const expected = this.blockingBit === 1 ? 249 : 248; + if (byteAfterNextByte !== expected) { + slice.filePos = positionBeforeReading; + continue; + } + slice.skip(-2); + const lengthIfNextFlacFrameHeaderIsLegit = slice.filePos - startPos; + const nextFrameHeader = this.readFlacFrameHeader({ + slice, + isFirstPacket: false + }); + if (!nextFrameHeader) { + slice.filePos = positionBeforeReading; + continue; + } + if (this.blockingBit === 0) { + if (nextFrameHeader.num - frameHeader.num !== 1) { + slice.filePos = positionBeforeReading; + continue; + } + } else { + if (nextFrameHeader.num - frameHeader.num !== frameHeader.blockSize) { + slice.filePos = positionBeforeReading; + continue; + } + } + return { + num: frameHeader.num, + blockSize: frameHeader.blockSize, + sampleRate: frameHeader.sampleRate, + size: lengthIfNextFlacFrameHeaderIsLegit, + isLastFrame: false + }; + } + } + } + readFlacFrameHeader({ slice, isFirstPacket }) { + const startOffset = slice.filePos; + const bytes = readBytes(slice, 4); + const bitstream = new Bitstream(bytes); + const bits = bitstream.readBits(15); + if (bits !== 32764) { + return null; + } + if (this.blockingBit === null) { + assert(isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + this.blockingBit = newBlockingBit; + } else if (this.blockingBit === 1) { + assert(!isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + if (newBlockingBit !== 1) { + return null; + } + } else if (this.blockingBit === 0) { + assert(!isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + if (newBlockingBit !== 0) { + return null; + } + } else { + throw new Error("Invalid blocking bit"); + } + const blockSizeOrUncommon = getBlockSizeOrUncommon(bitstream.readBits(4)); + if (!blockSizeOrUncommon) { + return null; + } + assert(this.audioInfo); + const sampleRateOrUncommon = getSampleRateOrUncommon(bitstream.readBits(4), this.audioInfo.sampleRate); + if (!sampleRateOrUncommon) { + return null; + } + bitstream.readBits(4); + bitstream.readBits(3); + const reservedZero = bitstream.readBits(1); + if (reservedZero !== 0) { + return null; + } + const num = readCodedNumber(slice); + const blockSize = readBlockSize(slice, blockSizeOrUncommon); + const sampleRate = readSampleRate(slice, sampleRateOrUncommon); + if (sampleRate === null) { + return null; + } + if (sampleRate !== this.audioInfo.sampleRate) { + return null; + } + const size = slice.filePos - startOffset; + const crc = readU8(slice); + slice.skip(-size); + slice.skip(-1); + const crcCalculated = calculateCrc8(readBytes(slice, size)); + if (crc !== crcCalculated) { + return null; + } + return { num, blockSize, sampleRate }; + } + async advanceReader() { + await this.readMetadata(); + assert(this.lastLoadedPos !== null); + assert(this.audioInfo); + const startPos = this.lastLoadedPos; + const frame = await this.readNextFlacFrame({ + startPos, + isFirstPacket: this.loadedSamples.length === 0 + }); + if (!frame) { + this.lastSampleLoaded = true; + return; + } + const lastSample = this.loadedSamples[this.loadedSamples.length - 1]; + const blockOffset = lastSample ? lastSample.blockOffset + lastSample.blockSize : 0; + const sample = { + blockOffset, + blockSize: frame.blockSize, + byteOffset: startPos, + byteSize: frame.size + }; + this.lastLoadedPos = this.lastLoadedPos + frame.size; + this.loadedSamples.push(sample); + if (frame.isLastFrame) { + this.lastSampleLoaded = true; + return; + } + } +} +class FlacAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getCodec() { + return "flac"; + } + getInternalCodecId() { + return null; + } + getNumberOfChannels() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getTimeResolution() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + assert(this.demuxer.audioInfo); + if (this.demuxer.audioInfo.totalSamples === 0) { + return null; + } + return this.demuxer.audioInfo.totalSamples / this.demuxer.audioInfo.sampleRate; + } + async getLiveRefreshInterval() { + return null; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.audioInfo); + return { + codec: "flac", + numberOfChannels: this.demuxer.audioInfo.numberOfChannels, + sampleRate: this.demuxer.audioInfo.sampleRate, + description: this.demuxer.audioInfo.description + }; + } + async getPacket(timestamp, options) { + assert(this.demuxer.audioInfo); + if (timestamp < 0) { + throw new Error("Timestamp cannot be negative"); + } + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const packetIndex = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.blockOffset / this.demuxer.audioInfo.sampleRate); + if (packetIndex === -1) { + await this.demuxer.advanceReader(); + continue; + } + const packet = this.demuxer.loadedSamples[packetIndex]; + const sampleTimestamp = packet.blockOffset / this.demuxer.audioInfo.sampleRate; + const sampleDuration = packet.blockSize / this.demuxer.audioInfo.sampleRate; + if (sampleTimestamp + sampleDuration <= timestamp) { + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(this.demuxer.loadedSamples.length - 1, options); + } + await this.demuxer.advanceReader(); + continue; + } + return this.getPacketAtIndex(packetIndex, options); + } + } finally { + release(); + } + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const nextIndex = packet.sequenceNumber + 1; + if (this.demuxer.lastSampleLoaded && nextIndex >= this.demuxer.loadedSamples.length) { + return null; + } + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } + async getPacketAtIndex(sampleIndex, options) { + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.byteOffset, rawSample.byteSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.byteSize); + } + assert(this.demuxer.audioInfo); + const timestamp = rawSample.blockOffset / this.demuxer.audioInfo.sampleRate; + const duration = rawSample.blockSize / this.demuxer.audioInfo.sampleRate; + return new EncodedPacket(data, "key", timestamp, duration, sampleIndex, rawSample.byteSize); + } + async getFirstPacket(options) { + while (this.demuxer.loadedSamples.length === 0 && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(0, options); + } +} +const TIMESCALE = 9e4; +const TS_PACKET_SIZE = 188; +const buildMpegTsMimeType = (codecStrings) => { + let string = "video/MP2T"; + const uniqueCodecStrings = [...new Set(codecStrings.filter(Boolean))]; + if (uniqueCodecStrings.length > 0) { + string += `; codecs="${uniqueCodecStrings.join(", ")}"`; + } + return string; +}; +const MISSING_PTS_ERROR_MESSAGE = "PES packet is missing PTS where it was expected. PES packets without PTS are not currently supported. If you think this file should be supported, please report it."; +const ignoredStreamTypes = /* @__PURE__ */ new Set(); +class MpegTsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.elementaryStreams = []; + this.trackBackingEntries = []; + this.packetOffset = 0; + this.packetStride = -1; + this.sectionEndPositions = []; + this.seekChunkSize = 5 * 1024 * 1024; + this.minReferencePointByteDistance = -1; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + const lengthToCheck = TS_PACKET_SIZE + 16 + 1; + let startingSlice = this.reader.requestSlice(0, lengthToCheck); + if (startingSlice instanceof Promise) + startingSlice = await startingSlice; + assert(startingSlice); + const startingBytes = readBytes(startingSlice, lengthToCheck); + if (startingBytes[0] === 71 && startingBytes[TS_PACKET_SIZE] === 71) { + this.packetOffset = 0; + this.packetStride = TS_PACKET_SIZE; + } else if (startingBytes[0] === 71 && startingBytes[TS_PACKET_SIZE + 16] === 71) { + this.packetOffset = 0; + this.packetStride = TS_PACKET_SIZE + 16; + } else if (startingBytes[4] === 71 && startingBytes[4 + TS_PACKET_SIZE + 4] === 71) { + this.packetOffset = 4; + this.packetStride = TS_PACKET_SIZE + 4; + } else { + throw new Error("Unreachable."); + } + const MIN_REFERENCE_POINT_PACKET_DISTANCE = 256; + this.minReferencePointByteDistance = MIN_REFERENCE_POINT_PACKET_DISTANCE * this.packetStride; + let currentPos = this.packetOffset; + let programMapPid = null; + let hasProgramAssociationTable = false; + let hasProgramMap = false; + while (true) { + const packetHeader = await this.readPacketHeader(currentPos); + if (!packetHeader) { + break; + } + if (packetHeader.payloadUnitStartIndicator === 0) { + currentPos += this.packetStride; + continue; + } + const section = await this.readSection(currentPos, true, !hasProgramMap); + if (!section) { + break; + } + const BYTES_BEFORE_SECTION_LENGTH = 3; + const BITS_IN_CRC_32 = 32; + let isProbablyProgramMap = false; + if (!hasProgramMap && section.pid !== 0) { + const isPesPacket = section.payload[0] === 0 && section.payload[1] === 0 && section.payload[2] === 1; + if (!isPesPacket) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + const tableId = bitstream.readBits(8); + isProbablyProgramMap = tableId === 2; + } + } + if (section.pid === 0 && !hasProgramAssociationTable) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + bitstream.skipBits(14); + const sectionLength = bitstream.readBits(10); + bitstream.skipBits(40); + while (8 * (sectionLength + BYTES_BEFORE_SECTION_LENGTH) - bitstream.pos > BITS_IN_CRC_32) { + const programNumber = bitstream.readBits(16); + bitstream.skipBits(3); + const id = bitstream.readBits(13); + if (programNumber !== 0) { + if (programMapPid !== null) { + throw new Error("Only files with a single program are supported."); + } else { + programMapPid = id; + } + } + } + if (programMapPid === null) { + throw new Error("Program Association Table must link to a Program Map Table."); + } + hasProgramAssociationTable = true; + } else if ((section.pid === programMapPid || isProbablyProgramMap) && !hasProgramMap) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + bitstream.skipBits(12); + const sectionLength = bitstream.readBits(12); + bitstream.skipBits(43); + bitstream.readBits(13); + bitstream.skipBits(6); + const programInfoLength = bitstream.readBits(10); + bitstream.skipBits(8 * programInfoLength); + while (8 * (sectionLength + BYTES_BEFORE_SECTION_LENGTH) - bitstream.pos > BITS_IN_CRC_32) { + const streamType = bitstream.readBits(8); + bitstream.skipBits(3); + const elementaryPid = bitstream.readBits(13); + bitstream.skipBits(6); + const esInfoLength = bitstream.readBits(10); + const esInfoEndPos = bitstream.pos + 8 * esInfoLength; + let hasAc3Descriptor = false; + let hasEac3Descriptor = false; + while (bitstream.pos < esInfoEndPos) { + const descriptorTag = bitstream.readBits(8); + const descriptorLength = bitstream.readBits(8); + if (descriptorTag === 106) { + hasAc3Descriptor = true; + } else if (descriptorTag === 122 || descriptorTag === 204) { + hasEac3Descriptor = true; + } + bitstream.skipBits(8 * descriptorLength); + } + let info = null; + switch (streamType) { + case 27: + case 36: + { + const codec = streamType === 27 ? "avc" : "hevc"; + info = { + type: "video", + codec, + decoderConfig: null, + avcCodecInfo: null, + hevcCodecInfo: null, + colorSpace: { + primaries: null, + transfer: null, + matrix: null, + fullRange: null + }, + width: -1, + height: -1, + squarePixelWidth: -1, + squarePixelHeight: -1, + reorderSize: -1 + }; + } + break; + case 3: + case 4: + case 15: + case 129: + case 135: + { + let codec; + if (streamType === 3 || streamType === 4) { + codec = "mp3"; + } else if (streamType === 15) { + codec = "aac"; + } else if (streamType === 129) { + codec = "ac3"; + } else if (streamType === 135) { + codec = "eac3"; + } else { + throw new Error("Unreachable."); + } + info = { + type: "audio", + codec, + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } + break; + case 6: + { + if (hasEac3Descriptor) { + info = { + type: "audio", + codec: "eac3", + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } else if (hasAc3Descriptor) { + info = { + type: "audio", + codec: "ac3", + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } + } + break; + default: { + if (!ignoredStreamTypes.has(streamType)) { + console.warn(`Note: MPEG-TS streams with stream_type 0x${streamType.toString(16)} are not currently supported.`); + ignoredStreamTypes.add(streamType); + } + } + } + if (info) { + this.elementaryStreams.push({ + demuxer: this, + pid: elementaryPid, + streamType, + initialized: false, + firstSection: null, + canBeTrustedWithKeyPackets: false, + info, + referencePesPackets: [] + }); + } + } + hasProgramMap = true; + } else { + const elementaryStream = this.elementaryStreams.find((x) => x.pid === section.pid); + outer: if (elementaryStream && !elementaryStream.initialized) { + const pesPacket = readPesPacket(section, true); + if (!pesPacket) { + throw new Error(`Couldn't read first PES packet for Elementary Stream with PID ${elementaryStream.pid}`); + } + elementaryStream.firstSection = section; + elementaryStream.canBeTrustedWithKeyPackets = section.randomAccessIndicator === 1; + if (this.input._initInput) { + const initDemuxer = await this.input._initInput._getDemuxer(); + const matchingStream = initDemuxer.elementaryStreams.find((x) => x.pid === section.pid && x.info.codec === elementaryStream.info.codec); + if (matchingStream) { + elementaryStream.info = matchingStream.info; + elementaryStream.initialized = true; + break outer; + } + } + const context = new PacketReadingContext(elementaryStream, pesPacket); + if (elementaryStream.info.type === "video") { + while (true) { + const contextAlias = context; + contextAlias.suppliedPacket = null; + await context.markNextPacket(); + if (elementaryStream.info.codec === "avc") { + if (!context.suppliedPacket) { + throw new Error("Invalid AVC video stream; could not extract AVCDecoderConfigurationRecord from any packet."); + } + elementaryStream.info.avcCodecInfo = extractAvcDecoderConfigurationRecord(context.suppliedPacket.data); + if (!elementaryStream.info.avcCodecInfo) { + continue; + } + const spsUnit = elementaryStream.info.avcCodecInfo.sequenceParameterSets[0]; + assert(spsUnit); + const spsInfo = parseAvcSps(spsUnit); + elementaryStream.info.width = spsInfo.displayWidth; + elementaryStream.info.height = spsInfo.displayHeight; + const num = spsInfo.pixelAspectRatio.num; + const den = spsInfo.pixelAspectRatio.den; + if (num > 0 && den > 0) { + if (num > den) { + elementaryStream.info.squarePixelWidth = Math.round(elementaryStream.info.width * num / den); + elementaryStream.info.squarePixelHeight = elementaryStream.info.height; + } else { + elementaryStream.info.squarePixelWidth = elementaryStream.info.width; + elementaryStream.info.squarePixelHeight = Math.round(elementaryStream.info.height * den / num); + } + } + elementaryStream.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[spsInfo.transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[spsInfo.matrixCoefficients], + fullRange: !!spsInfo.fullRangeFlag + }; + elementaryStream.info.reorderSize = spsInfo.maxDecFrameBuffering; + break; + } else if (elementaryStream.info.codec === "hevc") { + if (!context.suppliedPacket) { + throw new Error("Invalid HEVC video stream; could not extract HVCDecoderConfigurationRecord from first packet."); + } + elementaryStream.info.hevcCodecInfo = extractHevcDecoderConfigurationRecord(context.suppliedPacket.data); + if (!elementaryStream.info.hevcCodecInfo) { + continue; + } + const spsArray = elementaryStream.info.hevcCodecInfo.arrays.find((a) => a.nalUnitType === HevcNalUnitType.SPS_NUT); + const spsUnit = spsArray.nalUnits[0]; + assert(spsUnit); + const spsInfo = parseHevcSps(spsUnit); + elementaryStream.info.width = spsInfo.displayWidth; + elementaryStream.info.height = spsInfo.displayHeight; + if (spsInfo.pixelAspectRatio.num > spsInfo.pixelAspectRatio.den) { + elementaryStream.info.squarePixelWidth = Math.round(elementaryStream.info.width * spsInfo.pixelAspectRatio.num / spsInfo.pixelAspectRatio.den); + elementaryStream.info.squarePixelHeight = elementaryStream.info.height; + } else { + elementaryStream.info.squarePixelWidth = elementaryStream.info.width; + elementaryStream.info.squarePixelHeight = Math.round(elementaryStream.info.height * spsInfo.pixelAspectRatio.den / spsInfo.pixelAspectRatio.num); + } + elementaryStream.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[spsInfo.transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[spsInfo.matrixCoefficients], + fullRange: !!spsInfo.fullRangeFlag + }; + elementaryStream.info.reorderSize = spsInfo.maxDecFrameBuffering; + break; + } else { + throw new Error("Unhandled."); + } + } + elementaryStream.info.decoderConfig = { + codec: extractVideoCodecString({ + width: elementaryStream.info.width, + height: elementaryStream.info.height, + codec: elementaryStream.info.codec, + codecDescription: null, + colorSpace: elementaryStream.info.colorSpace, + avcType: 1, + avcCodecInfo: elementaryStream.info.avcCodecInfo, + hevcCodecInfo: elementaryStream.info.hevcCodecInfo, + vp9CodecInfo: null, + av1CodecInfo: null + }), + codedWidth: elementaryStream.info.width, + codedHeight: elementaryStream.info.height, + colorSpace: elementaryStream.info.colorSpace + }; + if (elementaryStream.info.width !== elementaryStream.info.squarePixelWidth || elementaryStream.info.height !== elementaryStream.info.squarePixelHeight) { + elementaryStream.info.decoderConfig.displayAspectWidth = elementaryStream.info.squarePixelWidth; + elementaryStream.info.decoderConfig.displayAspectHeight = elementaryStream.info.squarePixelHeight; + } + elementaryStream.initialized = true; + } else { + await context.markNextPacket(); + if (!context.suppliedPacket) { + throw new Error(`Couldn't parse first media packet for Elementary Stream with PID ${elementaryStream.pid}`); + } + if (elementaryStream.info.codec === "aac") { + const slice = FileSlice.tempFromBytes(context.suppliedPacket.data); + const header = readAdtsFrameHeader(slice); + if (!header) { + throw new Error("Invalid AAC audio stream; could not read ADTS frame header from first packet."); + } + elementaryStream.info.aacCodecInfo = { + isMpeg2: false, + objectType: header.objectType + }; + elementaryStream.info.numberOfChannels = aacChannelMap[header.channelConfiguration]; + elementaryStream.info.sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; + } else if (elementaryStream.info.codec === "mp3") { + const word = readU32Be(FileSlice.tempFromBytes(context.suppliedPacket.data)); + const result = readMp3FrameHeader(word, context.suppliedPacket.data.byteLength); + if (!result.header) { + throw new Error("Invalid MP3 audio stream; could not read frame header from first packet."); + } + elementaryStream.info.numberOfChannels = result.header.channel === 3 ? 1 : 2; + elementaryStream.info.sampleRate = result.header.sampleRate; + } else if (elementaryStream.info.codec === "ac3") { + const frameInfo = parseAc3SyncFrame(context.suppliedPacket.data); + if (!frameInfo) { + throw new Error("Invalid AC-3 audio stream; could not read sync frame from first packet."); + } + if (frameInfo.fscod === 3) { + throw new Error("Invalid AC-3 audio stream; reserved sample rate code found in first packet."); + } + elementaryStream.info.numberOfChannels = AC3_ACMOD_CHANNEL_COUNTS[frameInfo.acmod] + frameInfo.lfeon; + elementaryStream.info.sampleRate = AC3_SAMPLE_RATES[frameInfo.fscod]; + } else if (elementaryStream.info.codec === "eac3") { + const frameInfo = parseEac3SyncFrame(context.suppliedPacket.data); + if (!frameInfo) { + throw new Error("Invalid E-AC-3 audio stream; could not read sync frame from first packet."); + } + const sampleRate = getEac3SampleRate(frameInfo); + if (sampleRate === null) { + throw new Error("Invalid E-AC-3 audio stream; reserved sample rate code found in first packet."); + } + elementaryStream.info.numberOfChannels = getEac3ChannelCount(frameInfo); + elementaryStream.info.sampleRate = sampleRate; + } else { + throw new Error("Unhandled."); + } + elementaryStream.info.decoderConfig = { + codec: extractAudioCodecString({ + codec: elementaryStream.info.codec, + codecDescription: null, + aacCodecInfo: elementaryStream.info.aacCodecInfo + }), + numberOfChannels: elementaryStream.info.numberOfChannels, + sampleRate: elementaryStream.info.sampleRate + }; + elementaryStream.initialized = true; + } + } + } + const isDone = hasProgramMap && this.elementaryStreams.every((x) => x.initialized); + if (isDone) { + break; + } + currentPos += this.packetStride; + } + if (!hasProgramMap) { + if (!hasProgramAssociationTable) { + throw new Error("No Program Association Table found in the file."); + } + throw new Error("No Program Map Table found in the file."); + } + for (const stream of this.elementaryStreams) { + if (stream.info.type === "video") { + this.trackBackingEntries.push(new MpegTsVideoTrackBacking(stream)); + } else { + this.trackBackingEntries.push(new MpegTsAudioTrackBacking(stream)); + } + } + })()); + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackingEntries; + } + async getMetadataTags() { + return {}; + } + async getMimeType() { + await this.readMetadata(); + const codecStrings = await Promise.all(this.trackBackingEntries.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildMpegTsMimeType(codecStrings); + } + async readSection(startPos, full, contiguous = false) { + let endPos = startPos; + let currentPos = startPos; + const chunks = []; + let chunksByteLength = 0; + let firstPacket = null; + let mustAddSectionEnd = true; + let randomAccessIndicator = 0; + while (true) { + const packet = await this.readPacket(currentPos); + currentPos += this.packetStride; + if (!packet) { + break; + } + if (!firstPacket) { + if (packet.payloadUnitStartIndicator === 0) { + break; + } + firstPacket = packet; + } else { + if (packet.pid !== firstPacket.pid) { + if (contiguous) { + break; + } else { + continue; + } + } + if (packet.payloadUnitStartIndicator === 1) { + break; + } + } + const hasAdaptationField = !!(packet.adaptationFieldControl & 2); + const hasPayload = !!(packet.adaptationFieldControl & 1); + let adaptationFieldLength = 0; + if (hasAdaptationField) { + adaptationFieldLength = 1 + packet.body[0]; + if (packet === firstPacket && adaptationFieldLength > 1) { + randomAccessIndicator = packet.body[1] >> 6 & 1; + } + } + if (hasPayload) { + if (adaptationFieldLength === 0) { + chunks.push(packet.body); + chunksByteLength += packet.body.byteLength; + } else { + chunks.push(packet.body.subarray(adaptationFieldLength)); + chunksByteLength += packet.body.byteLength - adaptationFieldLength; + } + } + endPos = currentPos; + if (!full && chunksByteLength >= 64) { + mustAddSectionEnd = false; + break; + } + const isKnownSectionEnd = binarySearchExact(this.sectionEndPositions, endPos, (x) => x) !== -1; + if (isKnownSectionEnd) { + mustAddSectionEnd = false; + break; + } + } + if (mustAddSectionEnd) { + const index = binarySearchLessOrEqual(this.sectionEndPositions, endPos, (x) => x); + this.sectionEndPositions.splice(index + 1, 0, endPos); + } + if (!firstPacket) { + return null; + } + let merged; + if (chunks.length === 1) { + merged = chunks[0]; + } else { + const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0); + merged = new Uint8Array(totalLength); + let offset = 0; + for (const chunk of chunks) { + merged.set(chunk, offset); + offset += chunk.length; + } + } + return { + startPos, + endPos: full ? endPos : null, + pid: firstPacket.pid, + payload: merged, + randomAccessIndicator + }; + } + async readPacketHeader(pos) { + let slice = this.reader.requestSlice(pos, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const syncByte = readU8(slice); + if (syncByte !== 71) { + throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file."); + } + const nextTwoBytes = readU16Be(slice); + const payloadUnitStartIndicator = nextTwoBytes >> 14 & 1; + const pid = nextTwoBytes & 8191; + const nextByte = readU8(slice); + const adaptationFieldControl = nextByte >> 4 & 3; + return { + payloadUnitStartIndicator, + pid, + adaptationFieldControl + }; + } + async readPacket(pos) { + let slice = this.reader.requestSlice(pos, TS_PACKET_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const bytes = readBytes(slice, TS_PACKET_SIZE); + const syncByte = bytes[0]; + if (syncByte !== 71) { + throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file."); + } + const nextTwoBytes = (bytes[1] << 8) + bytes[2]; + const payloadUnitStartIndicator = nextTwoBytes >> 14 & 1; + const pid = nextTwoBytes & 8191; + const nextByte = bytes[3]; + const adaptationFieldControl = nextByte >> 4 & 3; + return { + payloadUnitStartIndicator, + pid, + adaptationFieldControl, + body: bytes.subarray(4) + }; + } +} +const readPesPacketHeader = (section, expectPts) => { + if (section.payload.byteLength < 3) { + return null; + } + const bitstream = new Bitstream(section.payload); + const startCodePrefix = bitstream.readBits(24); + if (startCodePrefix !== 1) { + return null; + } + const streamId = bitstream.readBits(8); + bitstream.skipBits(16); + if (streamId === 188 || streamId === 190 || streamId === 191 || streamId === 240 || streamId === 241 || streamId === 255 || streamId === 242 || streamId === 248) { + return null; + } + bitstream.skipBits(8); + const ptsDtsFlags = bitstream.readBits(2); + bitstream.skipBits(14); + let pts = null; + if (ptsDtsFlags === 2 || ptsDtsFlags === 3) { + pts = 0; + bitstream.skipBits(4); + pts += bitstream.readBits(3) * (1 << 30); + bitstream.skipBits(1); + pts += bitstream.readBits(15) * (1 << 15); + bitstream.skipBits(1); + pts += bitstream.readBits(15); + } else { + if (expectPts) { + throw new Error(MISSING_PTS_ERROR_MESSAGE); + } + } + return { + sectionStartPos: section.startPos, + sectionEndPos: section.endPos, + pts, + randomAccessIndicator: section.randomAccessIndicator + }; +}; +const readPesPacket = (section, expectPts) => { + assert(section.endPos !== null); + const header = readPesPacketHeader(section, expectPts); + if (!header) { + return null; + } + const bitstream = new Bitstream(section.payload); + bitstream.skipBits(32); + const pesPacketLength = bitstream.readBits(16); + const BYTES_UNTIL_END_OF_PES_PACKET_LENGTH = 6; + bitstream.skipBits(16); + const pesHeaderDataLength = bitstream.readBits(8); + const pesHeaderEndPos = bitstream.pos + 8 * pesHeaderDataLength; + bitstream.pos = pesHeaderEndPos; + const bytePos = pesHeaderEndPos / 8; + assert(Number.isInteger(bytePos)); + const data = section.payload.subarray( + bytePos, + // "A value of 0 indicates that the PES packet length is neither specified nor bounded and is allowed only in + // PES packets whose payload consists of bytes from a video elementary stream contained in + // transport stream packets." + pesPacketLength > 0 ? BYTES_UNTIL_END_OF_PES_PACKET_LENGTH + pesPacketLength : section.payload.byteLength + ); + return { + ...header, + data + }; +}; +class MpegTsTrackBacking { + constructor(elementaryStream) { + this.elementaryStream = elementaryStream; + this.packetBuffers = /* @__PURE__ */ new WeakMap(); + this.packetSectionStarts = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.elementaryStream.pid; + } + getNumber() { + const demuxer = this.elementaryStream.demuxer; + const trackType = this.elementaryStream.info.type; + let number = 0; + for (const backing of demuxer.trackBackingEntries) { + if (backing.getType() === trackType) { + number++; + } + assert(backing instanceof MpegTsTrackBacking); + if (backing.elementaryStream === this.elementaryStream) { + break; + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.elementaryStream.streamType; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }; + } + getTimeResolution() { + return TIMESCALE; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + createEncodedPacket(suppliedPacket, duration, options) { + let packetType; + if (this.allPacketsAreKeyPackets()) { + packetType = "key"; + } else { + packetType = suppliedPacket.randomAccessIndicator === 1 ? "key" : "delta"; + } + return new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : suppliedPacket.data, packetType, suppliedPacket.pts / TIMESCALE, Math.max(duration / TIMESCALE, 0), suppliedPacket.sequenceNumber, suppliedPacket.data.byteLength); + } + async getFirstPacket(options) { + const section = this.elementaryStream.firstSection; + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + const buffer = new PacketBuffer(this, context); + const result = await buffer.readNext(); + if (!result) { + return null; + } + const packet = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(packet, buffer); + this.packetSectionStarts.set(packet, result.packet.sectionStartPos); + return packet; + } + async getNextPacket(packet, options) { + let buffer = this.packetBuffers.get(packet); + if (buffer) { + const result = await buffer.readNext(); + if (!result) { + return null; + } + this.packetBuffers.delete(packet); + const newPacket = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(newPacket, buffer); + this.packetSectionStarts.set(newPacket, result.packet.sectionStartPos); + return newPacket; + } + const sectionStartPos = this.packetSectionStarts.get(packet); + if (sectionStartPos === void 0) { + throw new Error("Packet was not created from this track."); + } + const demuxer = this.elementaryStream.demuxer; + const section = await demuxer.readSection(sectionStartPos, true); + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + buffer = new PacketBuffer(this, context); + const targetSequenceNumber = packet.sequenceNumber; + while (true) { + const result = await buffer.readNext(); + if (!result) { + return null; + } + if (result.packet.sequenceNumber > targetSequenceNumber) { + const newPacket = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(newPacket, buffer); + this.packetSectionStarts.set(newPacket, result.packet.sectionStartPos); + return newPacket; + } + } + } + async getNextKeyPacket(packet, options) { + let currentPacket = packet; + while (true) { + currentPacket = await this.getNextPacket(currentPacket, options); + if (!currentPacket) { + return null; + } + if (currentPacket.type === "key") { + return currentPacket; + } + } + } + getPacket(timestamp, options) { + return this.doPacketLookup(timestamp, false, options); + } + getKeyPacket(timestamp, options) { + return this.doPacketLookup(timestamp, true, options); + } + /** + * Searches for the packet with the largest timestamp not larger than `timestamp` in the file, using a combination + * of chunk-based binary search and linear refinement. The reason the coarse search is done in large chunks is to + * make it more performant for small files and over high-latency readers such as the network. + */ + async doPacketLookup(timestamp, keyframesOnly, options) { + const searchPts = roundIfAlmostInteger(timestamp * TIMESCALE); + const demuxer = this.elementaryStream.demuxer; + const { reader, seekChunkSize } = demuxer; + const pid = this.elementaryStream.pid; + const findFirstPesPacketHeaderInChunk = async (startPos, endPos, readSectionInFull) => { + let currentPos = startPos; + while (currentPos < endPos) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + return null; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, readSectionInFull); + if (!section) { + return null; + } + const pesPacketHeader = readPesPacketHeader(section, false); + if (pesPacketHeader && pesPacketHeader.pts !== null) { + return { + pesPacketHeader, + section + }; + } + } + currentPos += demuxer.packetStride; + } + return null; + }; + const firstSection = this.elementaryStream.firstSection; + assert(firstSection); + const firstPesPacketHeader = readPesPacketHeader(firstSection, true); + assert(firstPesPacketHeader); + if (searchPts < firstPesPacketHeader.pts) { + return null; + } + let scanStartPos; + const referencePesPackets = this.elementaryStream.referencePesPackets; + const referencePointIndex = binarySearchLessOrEqual(referencePesPackets, searchPts, (x) => x.pts); + const referencePoint = referencePointIndex !== -1 ? referencePesPackets[referencePointIndex] : null; + if (referencePoint && searchPts - referencePoint.pts < TIMESCALE / 2) { + scanStartPos = referencePoint.sectionStartPos; + } else { + let startChunkIndex = 0; + if (reader.fileSize !== null) { + const numChunks = Math.ceil(reader.fileSize / seekChunkSize); + if (numChunks > 1) { + let low = 0; + let high = numChunks - 1; + startChunkIndex = low; + while (low <= high) { + const mid = Math.floor((low + high) / 2); + const chunkStartPos = floorToMultiple(mid * seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos; + const chunkEndPos = chunkStartPos + seekChunkSize; + const result2 = await findFirstPesPacketHeaderInChunk(chunkStartPos, chunkEndPos, false); + if (!result2) { + high = mid - 1; + continue; + } + if (result2.pesPacketHeader.pts <= searchPts) { + startChunkIndex = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + } + } + scanStartPos = floorToMultiple(startChunkIndex * seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos; + } + const result = await findFirstPesPacketHeaderInChunk(scanStartPos, reader.fileSize ?? Infinity, false); + let currentPesHeader = result?.pesPacketHeader ?? null; + if (!currentPesHeader) { + currentPesHeader = firstPesPacketHeader; + } + const reorderSize = this.getReorderSize(); + const retrieveEncodedPacket = async (sectionStartPos, predicate) => { + const section = await demuxer.readSection(sectionStartPos, true); + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + const buffer = new PacketBuffer(this, context); + while (true) { + const topPts = last(buffer.presentationOrderPackets)?.pts ?? -Infinity; + if (topPts >= searchPts) { + break; + } + const didRead = await buffer.readNextPacket(); + if (!didRead) { + break; + } + } + const targetIndex = findLastIndex(buffer.presentationOrderPackets, predicate); + if (targetIndex === -1) { + return null; + } + const targetPacket = buffer.presentationOrderPackets[targetIndex]; + const lastDuration = targetIndex === 0 ? 0 : targetPacket.pts - buffer.presentationOrderPackets[targetIndex - 1].pts; + while (buffer.decodeOrderPackets[0] !== targetPacket) { + buffer.decodeOrderPackets.shift(); + } + buffer.lastDuration = lastDuration; + const result2 = await buffer.readNext(); + assert(result2); + const packet = this.createEncodedPacket(result2.packet, result2.duration, options); + this.packetBuffers.set(packet, buffer); + this.packetSectionStarts.set(packet, result2.packet.sectionStartPos); + return packet; + }; + if (!keyframesOnly || this.allPacketsAreKeyPackets()) { + outer: while (true) { + let currentPos = currentPesHeader.sectionStartPos + demuxer.packetStride; + while (true) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, false); + if (section) { + const nextPesHeader = readPesPacketHeader(section, false); + if (nextPesHeader && nextPesHeader.pts !== null) { + if (nextPesHeader.pts > searchPts) { + break outer; + } + currentPesHeader = nextPesHeader; + maybeInsertReferencePacket(this.elementaryStream, currentPesHeader); + break; + } + } + } + currentPos += demuxer.packetStride; + } + } + outer: for (let i = 0; i < reorderSize + 1; i++) { + let pos = currentPesHeader.sectionStartPos - demuxer.packetStride; + while (pos >= demuxer.packetOffset) { + const packetHeader = await demuxer.readPacketHeader(pos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(pos, false); + if (section) { + const header = readPesPacketHeader(section, false); + if (header && header.pts !== null) { + currentPesHeader = header; + break; + } + } + } + pos -= demuxer.packetStride; + } + } + return retrieveEncodedPacket(currentPesHeader.sectionStartPos, (p) => p.pts <= searchPts); + } else { + let currentChunkStartPos = scanStartPos; + let nextChunkStartPos = null; + const readSectionsInFull = !this.elementaryStream.canBeTrustedWithKeyPackets; + while (true) { + let bestKeyPesHeader = null; + const isFirstChunk = currentChunkStartPos <= firstPesPacketHeader.sectionStartPos; + let pesHeader; + let pesHeaderSection = null; + if (isFirstChunk) { + pesHeader = firstPesPacketHeader; + pesHeaderSection = firstSection; + } else { + const result2 = await findFirstPesPacketHeaderInChunk(currentChunkStartPos, reader.fileSize ?? Infinity, readSectionsInFull); + pesHeader = result2?.pesPacketHeader ?? null; + pesHeaderSection = result2?.section ?? null; + } + let passedSearchPts = false; + let lookaheadCount = 0; + outer: while (pesHeader) { + if (nextChunkStartPos !== null && pesHeader.sectionStartPos >= nextChunkStartPos) { + break; + } + if (pesHeader.pts <= searchPts) { + let isKeyPacket; + if (this.elementaryStream.canBeTrustedWithKeyPackets) { + isKeyPacket = pesHeader.randomAccessIndicator === 1; + } else { + assert(pesHeaderSection); + const pesPacket = readPesPacket(pesHeaderSection, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + await context.markNextPacket(); + isKeyPacket = context.suppliedPacket?.randomAccessIndicator === 1; + } + if (isKeyPacket) { + bestKeyPesHeader = pesHeader; + } + } + if (pesHeader.pts > searchPts) { + passedSearchPts = true; + } + if (passedSearchPts) { + lookaheadCount++; + if (lookaheadCount > reorderSize) { + break; + } + } + let currentPos = pesHeader.sectionStartPos + demuxer.packetStride; + while (true) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, readSectionsInFull); + if (section) { + const nextPesHeader = readPesPacketHeader(section, false); + if (nextPesHeader && nextPesHeader.pts !== null) { + pesHeader = nextPesHeader; + pesHeaderSection = section; + maybeInsertReferencePacket(this.elementaryStream, pesHeader); + break; + } + } + } + currentPos += demuxer.packetStride; + } + } + if (bestKeyPesHeader) { + let startPesHeader = bestKeyPesHeader; + if (lookaheadCount === 0) { + outer: for (let i = 0; i < reorderSize; i++) { + let pos = startPesHeader.sectionStartPos - demuxer.packetStride; + while (pos >= demuxer.packetOffset) { + const packetHeader = await demuxer.readPacketHeader(pos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(pos, readSectionsInFull); + if (section) { + const header = readPesPacketHeader(section, false); + if (header && header.pts !== null) { + startPesHeader = header; + break; + } + } + } + pos -= demuxer.packetStride; + } + } + } + const encodedPacket = await retrieveEncodedPacket(startPesHeader.sectionStartPos, (p) => p.pts <= searchPts && p.randomAccessIndicator === 1); + assert(encodedPacket); + return encodedPacket; + } + if (isFirstChunk) { + return null; + } + nextChunkStartPos = currentChunkStartPos; + currentChunkStartPos = Math.max(floorToMultiple(currentChunkStartPos - firstPesPacketHeader.sectionStartPos - seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos, firstPesPacketHeader.sectionStartPos); + } + } + } +} +class MpegTsVideoTrackBacking extends MpegTsTrackBacking { + getType() { + return "video"; + } + getCodec() { + return this.elementaryStream.info.codec; + } + getCodedWidth() { + return this.elementaryStream.info.width; + } + getCodedHeight() { + return this.elementaryStream.info.height; + } + getSquarePixelWidth() { + return this.elementaryStream.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.elementaryStream.info.squarePixelHeight; + } + getRotation() { + return 0; + } + async getColorSpace() { + return this.elementaryStream.info.colorSpace; + } + async canBeTransparent() { + return false; + } + async getDecoderConfig() { + assert(this.elementaryStream.info.decoderConfig); + return this.elementaryStream.info.decoderConfig; + } + allPacketsAreKeyPackets() { + return false; + } + getReorderSize() { + return this.elementaryStream.info.reorderSize; + } +} +class MpegTsAudioTrackBacking extends MpegTsTrackBacking { + getType() { + return "audio"; + } + getCodec() { + return this.elementaryStream.info.codec; + } + getNumberOfChannels() { + return this.elementaryStream.info.numberOfChannels; + } + getSampleRate() { + return this.elementaryStream.info.sampleRate; + } + async getDecoderConfig() { + assert(this.elementaryStream.info.decoderConfig); + return this.elementaryStream.info.decoderConfig; + } + allPacketsAreKeyPackets() { + return true; + } + getReorderSize() { + return 0; + } +} +const maybeInsertReferencePacket = (elementaryStream, pesPacketHeader) => { + const referencePesPackets = elementaryStream.referencePesPackets; + const index = binarySearchLessOrEqual(referencePesPackets, pesPacketHeader.sectionStartPos, (x) => x.sectionStartPos); + if (index >= 0) { + const entry = referencePesPackets[index]; + if (pesPacketHeader.pts <= entry.pts) { + return false; + } + const minByteDistance = elementaryStream.demuxer.minReferencePointByteDistance; + if (pesPacketHeader.sectionStartPos - entry.sectionStartPos < minByteDistance) { + return false; + } + if (index < referencePesPackets.length - 1) { + const nextEntry = referencePesPackets[index + 1]; + if (nextEntry.pts < pesPacketHeader.pts) { + return false; + } + if (nextEntry.sectionStartPos - pesPacketHeader.sectionStartPos < minByteDistance) { + return false; + } + } + } + referencePesPackets.splice(index + 1, 0, pesPacketHeader); + return true; +}; +class PacketReadingContext { + constructor(elementaryStream, startingPesPacket) { + this.currentPos = 0; + this.pesPackets = []; + this.currentPesPacketIndex = 0; + this.currentPesPacketPos = 0; + this.endPos = 0; + this.lastSuppliedPesPacket = null; + this.nextPts = null; + this.suppliedPacket = null; + this.elementaryStream = elementaryStream; + this.pid = elementaryStream.pid; + this.demuxer = elementaryStream.demuxer; + this.startingPesPacket = startingPesPacket; + } + ensureBuffered(length) { + const remaining = this.endPos - this.currentPos; + if (remaining >= length) { + return length; + } + return this.bufferData(length - remaining).then(() => Math.min(this.endPos - this.currentPos, length)); + } + getCurrentPesPacket() { + const packet = this.pesPackets[this.currentPesPacketIndex]; + assert(packet); + return packet; + } + async bufferData(length) { + const targetEndPos = this.endPos + length; + while (this.endPos < targetEndPos) { + let pesPacket; + if (this.pesPackets.length === 0) { + pesPacket = this.startingPesPacket; + } else { + let currentPos = last(this.pesPackets).sectionEndPos; + assert(currentPos !== null); + while (true) { + const packetHeader = await this.demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + return; + } + if (packetHeader.pid === this.pid) { + const nextSection = await this.demuxer.readSection(currentPos, true); + if (!nextSection) { + return; + } + const nextPesPacket = readPesPacket(nextSection, false); + if (nextPesPacket) { + pesPacket = nextPesPacket; + break; + } + } + currentPos += this.demuxer.packetStride; + } + } + this.pesPackets.push(pesPacket); + this.endPos += pesPacket.data.byteLength; + } + } + readBytes(length) { + const currentPesPacket = this.getCurrentPesPacket(); + const relativeStartOffset = this.currentPos - this.currentPesPacketPos; + const relativeEndOffset = relativeStartOffset + length; + this.currentPos += length; + if (relativeEndOffset <= currentPesPacket.data.byteLength) { + return currentPesPacket.data.subarray(relativeStartOffset, relativeEndOffset); + } + const result = new Uint8Array(length); + result.set(currentPesPacket.data.subarray(relativeStartOffset)); + let offset = currentPesPacket.data.byteLength - relativeStartOffset; + while (true) { + this.advanceCurrentPacket(); + const currentPesPacket2 = this.getCurrentPesPacket(); + const relativeEndOffset2 = length - offset; + if (relativeEndOffset2 <= currentPesPacket2.data.byteLength) { + result.set(currentPesPacket2.data.subarray(0, relativeEndOffset2), offset); + break; + } + result.set(currentPesPacket2.data, offset); + offset += currentPesPacket2.data.byteLength; + } + return result; + } + readU8() { + let currentPesPacket = this.getCurrentPesPacket(); + const relativeOffset = this.currentPos - this.currentPesPacketPos; + this.currentPos++; + if (relativeOffset < currentPesPacket.data.byteLength) { + return currentPesPacket.data[relativeOffset]; + } + this.advanceCurrentPacket(); + currentPesPacket = this.getCurrentPesPacket(); + return currentPesPacket.data[0]; + } + seekTo(pos) { + if (pos === this.currentPos) { + return; + } + if (pos < this.currentPos) { + while (pos < this.currentPesPacketPos) { + this.currentPesPacketIndex--; + const currentPacket = this.getCurrentPesPacket(); + this.currentPesPacketPos -= currentPacket.data.byteLength; + } + } else { + while (true) { + const currentPesPacket = this.getCurrentPesPacket(); + const currentEndPos = this.currentPesPacketPos + currentPesPacket.data.byteLength; + if (pos < currentEndPos) { + break; + } + this.currentPesPacketPos += currentPesPacket.data.byteLength; + this.currentPesPacketIndex++; + } + } + this.currentPos = pos; + } + skip(n) { + this.seekTo(this.currentPos + n); + } + advanceCurrentPacket() { + this.currentPesPacketPos += this.getCurrentPesPacket().data.byteLength; + this.currentPesPacketIndex++; + } + async markNextPacket() { + assert(!this.suppliedPacket); + const elementaryStream = this.elementaryStream; + if (elementaryStream.info.type === "video") { + const codec = elementaryStream.info.codec; + const CHUNK_SIZE = 1024; + if (codec !== "avc" && codec !== "hevc") { + throw new Error("Unhandled."); + } + let packetStartPos = null; + while (true) { + let remaining = this.ensureBuffered(CHUNK_SIZE); + if (remaining instanceof Promise) + remaining = await remaining; + if (remaining === 0) { + break; + } + const chunkStartPos = this.currentPos; + const chunk = this.readBytes(remaining); + const length = chunk.byteLength; + let i = 0; + while (i < length) { + const zeroIndex = chunk.indexOf(0, i); + if (zeroIndex === -1 || zeroIndex >= length) { + break; + } + i = zeroIndex; + const posBeforeZero = chunkStartPos + i; + if (i + 4 >= length) { + this.seekTo(posBeforeZero); + break; + } + const b1 = chunk[i + 1]; + const b2 = chunk[i + 2]; + const b3 = chunk[i + 3]; + let startCodeLength = 0; + let nalUnitTypeByte = null; + if (b1 === 0 && b2 === 0 && b3 === 1) { + startCodeLength = 4; + nalUnitTypeByte = chunk[i + 4]; + } else if (b1 === 0 && b2 === 1) { + startCodeLength = 3; + nalUnitTypeByte = b3; + } + if (startCodeLength === 0) { + i++; + continue; + } + const startCodePos = posBeforeZero; + if (packetStartPos === null) { + packetStartPos = startCodePos; + i += startCodeLength; + continue; + } + if (nalUnitTypeByte !== null) { + const nalUnitType = codec === "avc" ? extractNalUnitTypeForAvc(nalUnitTypeByte) : extractNalUnitTypeForHevc(nalUnitTypeByte); + const isAud = codec === "avc" ? nalUnitType === AvcNalUnitType.AUD : nalUnitType === HevcNalUnitType.AUD_NUT; + if (isAud) { + const packetLength = startCodePos - packetStartPos; + this.seekTo(packetStartPos); + return this.supplyPacket(packetLength, 0); + } + } + i += startCodeLength; + } + if (remaining < CHUNK_SIZE) { + break; + } + } + if (packetStartPos !== null) { + const packetLength = this.endPos - packetStartPos; + this.seekTo(packetStartPos); + return this.supplyPacket(packetLength, 0); + } + } else { + const codec = elementaryStream.info.codec; + const CHUNK_SIZE = 128; + while (true) { + let remaining = this.ensureBuffered(CHUNK_SIZE); + if (remaining instanceof Promise) + remaining = await remaining; + const startPos = this.currentPos; + while (this.currentPos - startPos < remaining) { + const byte = this.readU8(); + if (codec === "aac") { + if (byte !== 255) { + continue; + } + this.skip(-1); + const possibleHeaderStartPos = this.currentPos; + let remaining2 = this.ensureBuffered(MAX_ADTS_FRAME_HEADER_SIZE); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < MAX_ADTS_FRAME_HEADER_SIZE) { + return; + } + const headerBytes = this.readBytes(MAX_ADTS_FRAME_HEADER_SIZE); + const header = readAdtsFrameHeader(FileSlice.tempFromBytes(headerBytes)); + if (header) { + this.seekTo(possibleHeaderStartPos); + let remaining3 = this.ensureBuffered(header.frameLength); + if (remaining3 instanceof Promise) + remaining3 = await remaining3; + return this.supplyPacket(remaining3, Math.round(SAMPLES_PER_AAC_FRAME * TIMESCALE / elementaryStream.info.sampleRate)); + } else { + this.seekTo(possibleHeaderStartPos + 1); + } + } else if (codec === "mp3") { + if (byte !== 255) { + continue; + } + this.skip(-1); + const possibleHeaderStartPos = this.currentPos; + let remaining2 = this.ensureBuffered(FRAME_HEADER_SIZE); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < FRAME_HEADER_SIZE) { + return; + } + const headerBytes = this.readBytes(FRAME_HEADER_SIZE); + const word = toDataView(headerBytes).getUint32(0); + const result = readMp3FrameHeader(word, null); + if (result.header) { + this.seekTo(possibleHeaderStartPos); + let remaining3 = this.ensureBuffered(result.header.totalSize); + if (remaining3 instanceof Promise) + remaining3 = await remaining3; + const duration = result.header.audioSamplesInFrame * TIMESCALE / elementaryStream.info.sampleRate; + return this.supplyPacket(remaining3, Math.round(duration)); + } else { + this.seekTo(possibleHeaderStartPos + 1); + } + } else if (codec === "ac3") { + if (byte !== 11) { + continue; + } + this.skip(-1); + const possibleSyncPos = this.currentPos; + let remaining2 = this.ensureBuffered(5); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < 5) { + return; + } + const headerBytes = this.readBytes(5); + if (headerBytes[0] !== 11 || headerBytes[1] !== 119) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const fscod = headerBytes[4] >> 6; + const frmsizecod = headerBytes[4] & 63; + if (fscod === 3 || frmsizecod > 37) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const frameSize = AC3_FRAME_SIZES[3 * frmsizecod + fscod]; + assert(frameSize !== void 0); + this.seekTo(possibleSyncPos); + remaining2 = this.ensureBuffered(frameSize); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + const duration = Math.round(AC3_SAMPLES_PER_FRAME * TIMESCALE / elementaryStream.info.sampleRate); + return this.supplyPacket(remaining2, duration); + } else if (codec === "eac3") { + if (byte !== 11) { + continue; + } + this.skip(-1); + const possibleSyncPos = this.currentPos; + let remaining2 = this.ensureBuffered(5); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < 5) { + return; + } + const headerBytes = this.readBytes(5); + if (headerBytes[0] !== 11 || headerBytes[1] !== 119) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const frmsiz = (headerBytes[2] & 7) << 8 | headerBytes[3]; + const frameSize = (frmsiz + 1) * 2; + const fscod = headerBytes[4] >> 6; + const numblkscod = fscod === 3 ? 3 : headerBytes[4] >> 4 & 3; + const numblks = EAC3_NUMBLKS_TABLE[numblkscod]; + this.seekTo(possibleSyncPos); + remaining2 = this.ensureBuffered(frameSize); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + const samplesPerFrame = numblks * 256; + const duration = Math.round(samplesPerFrame * TIMESCALE / elementaryStream.info.sampleRate); + return this.supplyPacket(remaining2, duration); + } else { + throw new Error("Unhandled."); + } + } + if (remaining < CHUNK_SIZE) { + break; + } + } + } + } + /** Supplies the context with a new encoded packet, beginning at the current position. */ + supplyPacket(packetLength, intrinsicDuration) { + const currentPesPacket = this.getCurrentPesPacket(); + let pts; + if (this.lastSuppliedPesPacket === currentPesPacket) { + assert(this.nextPts !== null); + pts = this.nextPts; + } else { + if (currentPesPacket.pts === null) { + throw new Error(MISSING_PTS_ERROR_MESSAGE); + } + pts = currentPesPacket.pts; + maybeInsertReferencePacket(this.elementaryStream, currentPesPacket); + } + this.lastSuppliedPesPacket = currentPesPacket; + this.nextPts = pts + intrinsicDuration; + const sectionStartPos = currentPesPacket.sectionStartPos; + const sequenceNumber = sectionStartPos + (this.currentPos - this.currentPesPacketPos); + const data = this.readBytes(packetLength); + let randomAccessIndicator = currentPesPacket.randomAccessIndicator; + if (randomAccessIndicator === 0 && !this.elementaryStream.canBeTrustedWithKeyPackets) { + if (this.elementaryStream.info.type === "audio") { + randomAccessIndicator = 1; + } else { + if (this.elementaryStream.info.decoderConfig) { + const isKey = determineVideoPacketType(this.elementaryStream.info.codec, this.elementaryStream.info.decoderConfig, data) === "key"; + randomAccessIndicator = Number(isKey); + } + } + } + this.suppliedPacket = { + pts, + data, + sequenceNumber, + sectionStartPos, + randomAccessIndicator + }; + this.pesPackets.splice(0, this.currentPesPacketIndex); + this.currentPesPacketIndex = 0; + } +} +class PacketBuffer { + constructor(backing, context) { + this.decodeOrderPackets = []; + this.reorderBuffer = []; + this.presentationOrderPackets = []; + this.reachedEnd = false; + this.lastDuration = 0; + this.backing = backing; + this.context = context; + this.reorderSize = backing.getReorderSize(); + assert(this.reorderSize >= 0); + } + async readNext() { + if (this.decodeOrderPackets.length === 0) { + const didRead = await this.readNextPacket(); + if (!didRead) { + return null; + } + } + await this.ensureCurrentPacketHasNext(); + const packet = this.decodeOrderPackets[0]; + const presentationIndex = this.presentationOrderPackets.indexOf(packet); + assert(presentationIndex !== -1); + let duration; + if (presentationIndex === this.presentationOrderPackets.length - 1) { + duration = this.lastDuration; + } else { + const nextPacket = this.presentationOrderPackets[presentationIndex + 1]; + duration = nextPacket.pts - packet.pts; + this.lastDuration = duration; + } + this.decodeOrderPackets.shift(); + while (this.presentationOrderPackets.length > 0) { + const first = this.presentationOrderPackets[0]; + if (this.decodeOrderPackets.includes(first)) { + break; + } + this.presentationOrderPackets.shift(); + } + return { packet, duration }; + } + async readNextPacket() { + if (this.reachedEnd) { + return false; + } + let suppliedPacket; + if (this.context.suppliedPacket) { + suppliedPacket = this.context.suppliedPacket; + } else { + await this.context.markNextPacket(); + suppliedPacket = this.context.suppliedPacket; + } + this.context.suppliedPacket = null; + if (!suppliedPacket) { + this.reachedEnd = true; + this.flushReorderBuffer(); + return false; + } + this.decodeOrderPackets.push(suppliedPacket); + this.processPacketThroughReorderBuffer(suppliedPacket); + return true; + } + async ensureCurrentPacketHasNext() { + const current = this.decodeOrderPackets[0]; + assert(current); + while (true) { + const presentationIndex = this.presentationOrderPackets.indexOf(current); + if (presentationIndex !== -1 && presentationIndex <= this.presentationOrderPackets.length - 2) { + break; + } + const didRead = await this.readNextPacket(); + if (!didRead) { + break; + } + } + } + processPacketThroughReorderBuffer(packet) { + this.reorderBuffer.push(packet); + if (this.reorderBuffer.length > this.reorderSize) { + let minIndex = 0; + for (let i = 1; i < this.reorderBuffer.length; i++) { + if (this.reorderBuffer[i].pts < this.reorderBuffer[minIndex].pts) { + minIndex = i; + } + } + const packet2 = this.reorderBuffer[minIndex]; + this.presentationOrderPackets.push(packet2); + this.reorderBuffer.splice(minIndex, 1); + } + } + flushReorderBuffer() { + this.reorderBuffer.sort((a, b) => a.pts - b.pts); + this.presentationOrderPackets.push(...this.reorderBuffer); + this.reorderBuffer.length = 0; + } +} +const HLS_MIME_TYPE = "application/vnd.apple.mpegurl"; +const TAG_STREAM_INF = "#EXT-X-STREAM-INF:"; +const TAG_I_FRAME_STREAM_INF = "#EXT-X-I-FRAME-STREAM-INF:"; +const TAG_MEDIA = "#EXT-X-MEDIA:"; +const TAG_EXTINF = "#EXTINF:"; +const TAG_MAP = "#EXT-X-MAP:"; +const TAG_KEY = "#EXT-X-KEY:"; +const TAG_MEDIA_SEQUENCE = "#EXT-X-MEDIA-SEQUENCE:"; +const TAG_BYTERANGE = "#EXT-X-BYTERANGE:"; +const TAG_PROGRAM_DATE_TIME = "#EXT-X-PROGRAM-DATE-TIME:"; +const TAG_DISCONTINUITY = "#EXT-X-DISCONTINUITY"; +const TAG_TARGETDURATION = "#EXT-X-TARGETDURATION:"; +const TAG_ENDLIST = "#EXT-X-ENDLIST"; +const TAG_PLAYLIST_TYPE = "#EXT-X-PLAYLIST-TYPE:"; +const TAG_I_FRAMES_ONLY = "#EXT-X-I-FRAMES-ONLY"; +const canIgnoreLine = (line) => line.length === 0 || line.startsWith("#") && !line.startsWith("#EXT"); +class AttributeList { + constructor(str) { + this._attributes = {}; + let key = ""; + let value = ""; + let inValue = false; + let inQuotes = false; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + if (char === '"') { + inQuotes = !inQuotes; + } else if (char === "=" && !inValue && !inQuotes) { + inValue = true; + } else if (char === "," && !inQuotes) { + if (key) { + this._attributes[key.trim().toLowerCase()] = value; + } + key = ""; + value = ""; + inValue = false; + } else if (inValue) { + value += char; + } else { + key += char; + } + } + if (key) { + this._attributes[key.trim().toLowerCase()] = value; + } + } + get(name) { + return this._attributes[name.toLowerCase()] ?? null; + } + getAsNumber(name) { + const value = this.get(name); + if (value === null) { + return null; + } + const num = Number(value); + return Number.isFinite(num) ? num : null; + } + merge(other) { + Object.assign(this._attributes, other._attributes); + } +} +class SegmentedInput { + constructor(input, path, trackDeclarations) { + this.nextInputCacheAge = 0; + this.inputCache = []; + this.trackBackingsPromise = null; + this.firstSegment = null; + this.firstSegmentFirstTimestamps = /* @__PURE__ */ new WeakMap(); + this.firstTimestampCache = /* @__PURE__ */ new WeakMap(); + this.input = input; + this.path = path; + this.trackDeclarations = trackDeclarations; + } + async getDurationFromMetadata(options) { + const lastSegment = await this.getSegmentAt(Infinity, { + skipLiveWait: options.skipLiveWait + }); + if (!lastSegment) { + return null; + } + return lastSegment.timestamp + lastSegment.duration; + } + async getTrackBackings() { + return this.trackBackingsPromise ?? (this.trackBackingsPromise = (async () => { + const backings = []; + if (this.trackDeclarations) { + for (const decl of this.trackDeclarations) { + if (decl.type === "video") { + const number = arrayCount(backings, (x) => x.getType() === "video") + 1; + backings.push(new SegmentedInputInputVideoTrackBacking(this, decl, number)); + } else if (decl.type === "audio") { + const number = arrayCount(backings, (x) => x.getType() === "audio") + 1; + backings.push(new SegmentedInputInputAudioTrackBacking(this, decl, number)); + } + } + } else { + this.firstSegment = await this.getFirstSegment({}); + if (!this.firstSegment) { + return []; + } + const input = this.getInputForSegment(this.firstSegment); + const inputTracks = await input.getTracks(); + for (const track of inputTracks) { + if (track.type === "video") { + const number = arrayCount(backings, (x) => x.getType() === "video") + 1; + backings.push(new SegmentedInputInputVideoTrackBacking(this, { + id: backings.length + 1, + type: "video" + }, number)); + } else if (track.type === "audio") { + const number = arrayCount(backings, (x) => x.getType() === "audio") + 1; + backings.push(new SegmentedInputInputAudioTrackBacking(this, { + id: backings.length + 1, + type: "audio" + }, number)); + } + } + } + return backings; + })()); + } + // This operation is done a lot and can be semi-expensive, so it's good to have a cache for it + async getFirstTimestampForInput(input) { + const existing = this.firstTimestampCache.get(input); + if (existing !== void 0) { + return existing; + } + const firstTimestamp = await input.getFirstTimestamp(); + this.firstTimestampCache.set(input, firstTimestamp); + return firstTimestamp; + } + async getMediaOffset(segment, input) { + const firstSegment = segment.firstSegment ?? segment; + let firstSegmentFirstTimestamp; + if (this.firstSegmentFirstTimestamps.has(firstSegment)) { + firstSegmentFirstTimestamp = this.firstSegmentFirstTimestamps.get(firstSegment); + } else { + const firstInput = this.getInputForSegment(firstSegment); + firstSegmentFirstTimestamp = await this.getFirstTimestampForInput(firstInput); + this.firstSegmentFirstTimestamps.set(firstSegment, firstSegmentFirstTimestamp); + } + if (firstSegment === segment) { + return firstSegment.timestamp - firstSegmentFirstTimestamp; + } + const segmentFirstTimestamp = await this.getFirstTimestampForInput(input); + const segmentElapsed = segment.timestamp - firstSegment.timestamp; + const inputElapsed = segmentFirstTimestamp - firstSegmentFirstTimestamp; + const difference = inputElapsed - segmentElapsed; + if (Math.abs(difference) <= Math.min(0.25, segmentElapsed)) { + return firstSegment.timestamp - firstSegmentFirstTimestamp; + } else { + return segment.timestamp - segmentFirstTimestamp; + } + } + dispose() { + for (const entry of this.inputCache) { + entry.input.dispose(); + } + this.inputCache.length = 0; + } +} +class SegmentedInputInputTrackBacking { + constructor(segmentedInput, decl, number) { + this.packetInfos = /* @__PURE__ */ new WeakMap(); + this.hydrationPromise = null; + this.firstInputTrack = null; + this.segmentedInput = segmentedInput; + this.decl = decl; + this.number = number; + } + hydrate() { + return this.hydrationPromise ?? (this.hydrationPromise = (async () => { + var _a; + (_a = this.segmentedInput).firstSegment ?? (_a.firstSegment = await this.segmentedInput.getFirstSegment({})); + if (!this.segmentedInput.firstSegment) { + throw new Error("Missing first segment, can't retrieve track."); + } + const input = this.segmentedInput.getInputForSegment(this.segmentedInput.firstSegment); + const inputTracks = await input.getTracks(); + const track = inputTracks.find((x) => x.type === this.decl.type && x.number === this.number); + if (!track) { + throw new Error("No matching track found in underlying media data."); + } + this.firstInputTrack = track; + })()); + } + getId() { + return this.decl.id; + } + getType() { + return this.decl.type; + } + getNumber() { + return this.number; + } + /** If the backing track is already present, delegate synchronously; otherwise, hydrate first. */ + delegate(fn) { + if (this.firstInputTrack) { + return fn(); + } + return this.hydrate().then(fn); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } + getHasOnlyKeyPackets() { + return this.delegate(() => this.firstInputTrack._backing.getHasOnlyKeyPackets?.() ?? null); + } + getPairingMask() { + return 1n; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getInternalCodecId() { + return this.delegate(() => this.firstInputTrack._backing.getInternalCodecId()); + } + getDisposition() { + return this.delegate(() => this.firstInputTrack._backing.getDisposition()); + } + getLanguageCode() { + return this.delegate(() => this.firstInputTrack._backing.getLanguageCode()); + } + getName() { + return this.delegate(() => this.firstInputTrack._backing.getName()); + } + getTimeResolution() { + return this.delegate(() => this.firstInputTrack._backing.getTimeResolution()); + } + async isRelativeToUnixEpoch() { + await this.hydrate(); + assert(this.segmentedInput.firstSegment); + return this.segmentedInput.firstSegment.relativeToUnixEpoch; + } + getBitrate() { + return this.delegate(() => this.firstInputTrack._backing.getBitrate()); + } + getAverageBitrate() { + return this.delegate(() => this.firstInputTrack._backing.getAverageBitrate()); + } + getDurationFromMetadata(options) { + return this.segmentedInput.getDurationFromMetadata(options); + } + getLiveRefreshInterval() { + return this.segmentedInput.getLiveRefreshInterval(); + } + async createAdjustedPacket(packet, segment, track) { + assert(packet.sequenceNumber >= 0); + assert(this.segmentedInput.firstSegment); + const mediaOffset = await this.segmentedInput.getMediaOffset(segment, track.input); + const segmentTimestampRelativeToFirst = segment.timestamp - this.segmentedInput.firstSegment.timestamp; + const modified = packet.clone({ + timestamp: roundToDivisor(packet.timestamp + mediaOffset, await track.getTimeResolution()), + // The 1e8 assumes a max of 100 MB per second, highly unlikely to be hit, so this should guarantee + // monotonically increasing sequence numbers across segments. + sequenceNumber: Math.floor(1e8 * segmentTimestampRelativeToFirst) + packet.sequenceNumber + }); + this.packetInfos.set(modified, { + segment, + track, + sourcePacket: packet + }); + return modified; + } + async getFirstPacket(options) { + await this.hydrate(); + assert(this.segmentedInput.firstSegment); + assert(this.firstInputTrack); + const packet = await this.firstInputTrack._backing.getFirstPacket(options); + if (!packet) { + return null; + } + return this.createAdjustedPacket(packet, this.segmentedInput.firstSegment, this.firstInputTrack); + } + getNextPacket(packet, options) { + return this._getNextInternal(packet, options, false); + } + getNextKeyPacket(packet, options) { + return this._getNextInternal(packet, options, true); + } + async _getNextInternal(packet, options, keyframesOnly) { + const info = this.packetInfos.get(packet); + if (!info) { + throw new Error("Packet was not created from this track."); + } + const nextPacket = keyframesOnly ? await info.track._backing.getNextKeyPacket(info.sourcePacket, options) : await info.track._backing.getNextPacket(info.sourcePacket, options); + if (nextPacket) { + return this.createAdjustedPacket(nextPacket, info.segment, info.track); + } + let currentSegment = info.segment; + while (true) { + const nextSegment = await this.segmentedInput.getNextSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + if (!nextSegment) { + return null; + } + const nextInput = this.segmentedInput.getInputForSegment(nextSegment); + const nextTracks = await nextInput.getTracks(); + const nextTrack = nextTracks.find((t) => t.type === info.track.type && t.number === info.track.number); + if (!nextTrack) { + currentSegment = nextSegment; + continue; + } + const firstPacket = await nextTrack._backing.getFirstPacket(options); + if (!firstPacket) { + return null; + } + return this.createAdjustedPacket(firstPacket, nextSegment, nextTrack); + } + } + getPacket(timestamp, options) { + return this._getPacketInternal(timestamp, options, false); + } + getKeyPacket(timestamp, options) { + return this._getPacketInternal(timestamp, options, true); + } + async _getPacketInternal(timestamp, options, keyframesOnly) { + let currentSegment = await this.segmentedInput.getSegmentAt(timestamp, { + skipLiveWait: options.skipLiveWait + }); + if (!currentSegment) { + return null; + } + await this.hydrate(); + while (currentSegment) { + const input = this.segmentedInput.getInputForSegment(currentSegment); + const tracks = await input.getTracks(); + const track = tracks.find((t) => t.type === this.firstInputTrack.type && t.number === this.firstInputTrack.number); + if (!track) { + currentSegment = await this.segmentedInput.getPreviousSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + continue; + } + const mediaOffset = await this.segmentedInput.getMediaOffset(currentSegment, input); + const offsetTimestamp = timestamp - mediaOffset; + const packet = keyframesOnly ? await track._backing.getKeyPacket(offsetTimestamp, options) : await track._backing.getPacket(offsetTimestamp, options); + if (!packet) { + currentSegment = await this.segmentedInput.getPreviousSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + continue; + } + return this.createAdjustedPacket(packet, currentSegment, track); + } + return null; + } +} +class SegmentedInputInputVideoTrackBacking extends SegmentedInputInputTrackBacking { + getType() { + return "video"; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getCodedWidth() { + return this.delegate(() => this.firstInputTrack._backing.getCodedWidth()); + } + getCodedHeight() { + return this.delegate(() => this.firstInputTrack._backing.getCodedHeight()); + } + getSquarePixelWidth() { + return this.delegate(() => this.firstInputTrack._backing.getSquarePixelWidth()); + } + getSquarePixelHeight() { + return this.delegate(() => this.firstInputTrack._backing.getSquarePixelHeight()); + } + getRotation() { + return this.delegate(() => this.firstInputTrack._backing.getRotation()); + } + async getColorSpace() { + return this.delegate(() => this.firstInputTrack._backing.getColorSpace()); + } + async canBeTransparent() { + return this.delegate(() => this.firstInputTrack._backing.canBeTransparent()); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } +} +class SegmentedInputInputAudioTrackBacking extends SegmentedInputInputTrackBacking { + getType() { + return "audio"; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getNumberOfChannels() { + return this.delegate(() => this.firstInputTrack._backing.getNumberOfChannels()); + } + getSampleRate() { + return this.delegate(() => this.firstInputTrack._backing.getSampleRate()); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } +} +polyfillSymbolDispose(); +const DEFAULT_MIN_READ_POSITION = 0; +const DEFAULT_MAX_READ_POSITION = Infinity; +class Source extends EventEmitter { + constructor() { + super(...arguments); + this._disposed = false; + this._refCount = 0; + this._usedForHls = false; + this._sizePromise = null; + this.onread = null; + } + /** + * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call + * will retrieve the size. + * + * Returns null if the source is unsized. + */ + async getSizeOrNull() { + if (this._disposed) { + throw new InputDisposedError(); + } + return this._sizePromise ?? (this._sizePromise = (async () => { + let size = this._getFileSize(); + if (size !== void 0) { + return size; + } + await this._read(0, 1, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION); + size = this._getFileSize(); + assert(size !== void 0); + return size; + })()); + } + /** + * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call + * will retrieve the size. + * + * Throws an error if the source is unsized. + */ + async getSize() { + if (this._disposed) { + throw new InputDisposedError(); + } + const result = await this.getSizeOrNull(); + if (result === null) { + throw new Error("Cannot determine the size of an unsized source."); + } + return result; + } + /** + * Returns a new {@link RangedSource} that maps data onto this source using the given offset and length. If a length + * is not provided, the ranged source spans until the end of this source's data. + * + * Useful for reading files that are embedded within larger files. + */ + slice(offset, length) { + if (!Number.isInteger(offset) || offset < 0) { + throw new TypeError("offset must be a non-negative integer."); + } + if (length !== void 0 && (!Number.isInteger(length) || length < 0)) { + throw new TypeError("length, when provided, must be a non-negative integer."); + } + return new RangedSource(this, offset, length); + } + /** @internal */ + _dispatchRead(start, end) { + this.onread?.(start, end); + this._emit("read", { start, end }); + } + /** + * Creates a new `SourceRef` pointing to this source. You are expected to call `.free()` on said `SourceRef` when + * you're done with it. + */ + ref() { + return new SourceRef(this); + } +} +class SourceRef { + /** @internal */ + constructor(source) { + this._freed = false; + if (source._disposed) { + throw new Error("Cannot ref a disposed source."); + } + source._refCount++; + this._source = source; + } + /** The {@link Source} this ref references. Accessing this field throws an error after having freed the ref. */ + get source() { + if (!this._source) { + throw new Error("Can't get source; ref has already been freed."); + } + return this._source; + } + /** Whether or not this reference has been freed via {@link SourceRef.free}. */ + get freed() { + return this._freed; + } + /** + * Frees the ref, decrementing the source's internal reference count. If the source's internal reference count + * reaches zero, it gets disposed. To catch bugs, this method throws if the ref is already freed. + */ + free() { + if (this._freed) { + throw new Error("Illegal operation: double free on SourceRef."); + } + const source = this.source; + assert(source._refCount > 0); + source._refCount--; + if (source._refCount === 0) { + source._dispose(); + source._disposed = true; + } + this._freed = true; + this._source = null; + } + /** + * Calls {@link SourceRef.free}. + */ + [Symbol.dispose]() { + if (!this.freed) { + this.free(); + } + } +} +class PathedSource extends Source { + constructor(rootPath, requestHandler) { + if (typeof rootPath !== "string") { + throw new TypeError("rootPath must be a string."); + } + if (typeof requestHandler !== "function") { + throw new TypeError("requestHandler must be a function."); + } + super(); + this.rootPath = rootPath; + this.requestHandler = requestHandler; + } + /** @internal */ + _resolveRequest(request) { + const result = this.requestHandler(request); + const handle = (result2) => { + var _a; + if (!(result2 instanceof Source || result2 instanceof SourceRef)) { + throw new TypeError("requestHandler must return or resolve to a Source or SourceRef."); + } + const ref = result2 instanceof Source ? result2.ref() : result2; + (_a = ref.source)._usedForHls || (_a._usedForHls = this._usedForHls); + return ref; + }; + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } +} +const sourceRequestsAreEqual = (a, b) => { + return a.path === b.path; +}; +class CustomPathedSource extends PathedSource { + constructor() { + super(...arguments); + this._root = null; + this._rootRequest = null; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + if (!this._root) { + if (!this._rootRequest) { + const result = this._resolveRequest({ path: this.rootPath, isRoot: true }); + const handle = (result2) => { + const ref = result2 instanceof Source ? result2.ref() : result2; + this._root = ref; + this._rootRequest = null; + return ref; + }; + if (result instanceof Promise) { + this._rootRequest = result.then(handle); + } else { + handle(result); + assert(this._root); + } + } + if (this._rootRequest) { + return this._rootRequest.then((ref) => ref.source._read(start, end, minReadPosition, maxReadPosition)); + } + } + return this._root.source._read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + _getFileSize() { + if (this._root) { + return this._root.source._getFileSize(); + } + return void 0; + } + /** @internal */ + _dispose() { + if (this._root) { + this._root.free(); + } else if (this._rootRequest) { + void this._rootRequest.then((ref) => ref.free()); + } + } +} +class BlobSource extends Source { + /** + * Creates a new {@link BlobSource} backed by the specified + * [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). + */ + constructor(blob, options = {}) { + if (!(blob instanceof Blob)) { + throw new TypeError("blob must be a Blob."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + super(); + this._readers = /* @__PURE__ */ new WeakMap(); + this._blob = blob; + this._orchestrator = new ReadOrchestrator({ + maxCacheSize: options.maxCacheSize ?? 8 * 2 ** 20, + maxWorkerCount: 4, + runWorker: this._runWorker.bind(this), + prefetchProfile: PREFETCH_PROFILES.fileSystem + }); + this._orchestrator.fileSize = blob.size; + } + /** @internal */ + _getFileSize() { + return this._orchestrator.fileSize; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + return this._orchestrator.read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + async _runWorker(worker) { + assert(worker.strictTarget); + let reader = this._readers.get(worker); + if (reader === void 0) { + if ("stream" in this._blob && !isWebKit()) { + const slice = this._blob.slice(worker.currentPos); + reader = slice.stream().getReader(); + } else { + reader = null; + } + this._readers.set(worker, reader); + } + while (worker.currentPos < worker.targetPos && !worker.aborted) { + if (reader) { + const { done, value } = await reader.read(); + if (done) { + this._orchestrator.onWorkerFinished(worker); + throw new Error("Blob reader stopped unexpectedly before all requested data was read."); + } + if (worker.aborted) { + break; + } + this._dispatchRead(worker.currentPos, worker.currentPos + value.length); + this._orchestrator.supplyWorkerData(worker, value); + } else { + const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer(); + if (worker.aborted) { + break; + } + this._dispatchRead(worker.currentPos, worker.currentPos + data.byteLength); + this._orchestrator.supplyWorkerData(worker, new Uint8Array(data)); + } + } + this._orchestrator.signalWorkerStoppedRunning(worker); + if (worker.aborted) { + await reader?.cancel(); + } + } + /** @internal */ + _dispose() { + this._orchestrator.dispose(); + } +} +const URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20; +const DEFAULT_RETRY_DELAY = ((previousAttempts, error, src) => { + const couldBeCorsError = error instanceof Error && (error.message.includes("Failed to fetch") || error.message.includes("Load failed") || error.message.includes("NetworkError when attempting to fetch resource")); + if (couldBeCorsError) { + let originOfSrc = null; + try { + if (typeof window !== "undefined" && typeof window.location !== "undefined") { + originOfSrc = new URL(src instanceof Request ? src.url : src, window.location.href).origin; + } + } catch { + } + const isOnline = typeof navigator !== "undefined" && typeof navigator.onLine === "boolean" ? navigator.onLine : true; + if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) { + console.warn(`Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option.`); + return null; + } + } + return Math.min(2 ** (previousAttempts - 2), 16); +}); +const warnedOrigins = /* @__PURE__ */ new Set(); +class UrlSource extends PathedSource { + /** + * Creates a new {@link UrlSource} backed by the resource at the specified URL. + * + * When passing a `Request` instance, note that the `signal` and `headers.Range` options will be overridden by + * Mediabunny. If you want to cancel ongoing requests, use {@link Input.dispose}. + */ + constructor(url, options = {}) { + if (typeof url !== "string" && !(url instanceof URL) && !(typeof Request !== "undefined" && url instanceof Request)) { + throw new TypeError("url must be a string, URL or Request."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.requestInit !== void 0 && (!options.requestInit || typeof options.requestInit !== "object")) { + throw new TypeError("options.requestInit, when provided, must be an object."); + } + if (options.getRetryDelay !== void 0 && typeof options.getRetryDelay !== "function") { + throw new TypeError("options.getRetryDelay, when provided, must be a function."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + if (options.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) { + throw new TypeError("options.parallelism, when provided, must be a positive number."); + } + if (options.fetchFn !== void 0 && typeof options.fetchFn !== "function") { + throw new TypeError("options.fetchFn, when provided, must be a function."); + } + const urlString = url instanceof Request ? url.url : url instanceof URL ? url.href : url; + super(urlString, (request) => new UrlSource(request.path, this._options)); + this._fileSizeDetermined = false; + this._url = url; + this._options = options; + this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY; + const DEFAULT_PARALLELISM = 2; + this._orchestrator = new ReadOrchestrator({ + maxCacheSize: options.maxCacheSize ?? 64 * 2 ** 20, + maxWorkerCount: options.parallelism ?? DEFAULT_PARALLELISM, + runWorker: this._runWorker.bind(this), + prefetchProfile: PREFETCH_PROFILES.network + }); + } + /** @internal */ + _getFileSize() { + return this._fileSizeDetermined ? this._orchestrator.fileSize : void 0; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + return this._orchestrator.read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + async _runWorker(worker) { + while (true) { + const abortController = new AbortController(); + const response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { + headers: { + // Always sending a range request is a good way to probe if the server supports them + Range: `bytes=${worker.currentPos}-` + }, + signal: abortController.signal + }), this._getRetryDelay, () => this._disposed); + if (!response.ok) { + throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); + } + outer: if (this._orchestrator.fileSize === null) { + const contentRange = response.headers.get("Content-Range"); + if (contentRange) { + const match = /\/(\d+)/.exec(contentRange); + if (match) { + this._orchestrator.supplyFileSize(Number(match[1])); + break outer; + } + } + const contentLength = response.headers.get("Content-Length"); + if (contentLength) { + this._orchestrator.supplyFileSize(worker.currentPos + Number(contentLength)); + } + } + this._fileSizeDetermined = true; + if (response.status !== 206) { + if (!this._usedForHls) { + const url = new URL(this._url instanceof Request ? this._url.url : this._url, typeof window !== "undefined" ? window.location.href : void 0); + if (url.origin !== "null" && !(url.pathname.endsWith(".m3u8") || url.pathname.endsWith(".m3u"))) { + if (!warnedOrigins.has(url.origin)) { + console.log(this._usedForHls, this._url, url.pathname); + console.warn(`HTTP server (origin ${url.origin}) did not respond to a range request with 206 Partial Content, meaning the entire resource will now be downloaded. To enable efficient media file streaming across a network, please make sure your server supports range requests.`); + warnedOrigins.add(url.origin); + } + } + } + worker.currentPos = 0; + this._orchestrator.options.maxCacheSize = Infinity; + if (this._orchestrator.fileSize !== null) { + worker.targetPos = this._orchestrator.fileSize; + } else { + worker.targetPos = Infinity; + worker.strictTarget = false; + } + this._orchestrator.consolidateEverythingIntoOneWorker(worker); + } + if (!response.body) { + throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream."); + } + const reader = response.body.getReader(); + while (true) { + if (worker.currentPos >= worker.targetPos || worker.aborted) { + abortController.abort(); + this._orchestrator.signalWorkerStoppedRunning(worker); + return; + } + let readResult; + try { + readResult = await reader.read(); + } catch (error) { + if (this._disposed) { + throw error; + } + const retryDelayInSeconds = this._getRetryDelay(1, error, this._url); + if (retryDelayInSeconds !== null) { + console.error("Error while reading response stream. Attempting to resume.", error); + await wait(1e3 * retryDelayInSeconds); + break; + } else { + throw error; + } + } + if (worker.aborted) { + continue; + } + const { done, value } = readResult; + if (done) { + if (worker.currentPos >= worker.targetPos) { + this._orchestrator.onWorkerFinished(worker); + return; + } + if (worker.strictTarget) { + break; + } else { + this._orchestrator.onWorkerFinished(worker); + return; + } + } + this._dispatchRead(worker.currentPos, worker.currentPos + value.length); + this._orchestrator.supplyWorkerData(worker, value); + } + } + } + /** @internal */ + _dispose() { + this._orchestrator.dispose(); + } +} +class ReadableStreamSource extends Source { + /** Creates a new {@link ReadableStreamSource} backed by the specified `ReadableStream`. */ + constructor(stream, options = {}) { + if (!(stream instanceof ReadableStream)) { + throw new TypeError("stream must be a ReadableStream."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + super(); + this._reader = null; + this._cache = []; + this._pendingSlices = []; + this._currentIndex = 0; + this._targetIndex = 0; + this._maxRequestedIndex = 0; + this._endIndex = null; + this._pulling = false; + this._stream = stream; + this._maxCacheSize = options.maxCacheSize ?? 16 * 2 ** 20; + } + /** @internal */ + _getFileSize() { + return this._endIndex; + } + /** @internal */ + _read(start, end) { + if (this._endIndex !== null && end > this._endIndex) { + return null; + } + this._maxRequestedIndex = Math.max(this._maxRequestedIndex, end); + const cacheStartIndex = binarySearchLessOrEqual(this._cache, start, (x) => x.start); + const cacheStartEntry = cacheStartIndex !== -1 ? this._cache[cacheStartIndex] : null; + if (cacheStartEntry && cacheStartEntry.start <= start && end <= cacheStartEntry.end) { + return { + bytes: cacheStartEntry.bytes, + view: cacheStartEntry.view, + offset: cacheStartEntry.start + }; + } + let lastEnd = start; + const bytes = new Uint8Array(end - start); + if (cacheStartIndex !== -1) { + for (let i = cacheStartIndex; i < this._cache.length; i++) { + const cacheEntry = this._cache[i]; + if (cacheEntry.start >= end) { + break; + } + const cappedStart = Math.max(start, cacheEntry.start); + if (cappedStart > lastEnd) { + this._throwDueToCacheMiss(); + } + const cappedEnd = Math.min(end, cacheEntry.end); + if (cappedStart < cappedEnd) { + bytes.set(cacheEntry.bytes.subarray(cappedStart - cacheEntry.start, cappedEnd - cacheEntry.start), cappedStart - start); + lastEnd = cappedEnd; + } + } + } + if (lastEnd === end) { + return { + bytes, + view: toDataView(bytes), + offset: start + }; + } + if (this._currentIndex > lastEnd) { + this._throwDueToCacheMiss(); + } + const { promise, resolve, reject } = promiseWithResolvers(); + this._pendingSlices.push({ + start, + end, + bytes, + resolve, + reject + }); + this._targetIndex = Math.max(this._targetIndex, end); + if (!this._pulling) { + this._pulling = true; + void this._pull().catch((error) => { + this._pulling = false; + if (this._pendingSlices.length > 0) { + this._pendingSlices.forEach((x) => x.reject(error)); + this._pendingSlices.length = 0; + } else { + throw error; + } + }); + } + return promise; + } + /** @internal */ + _throwDueToCacheMiss() { + throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache."); + } + /** @internal */ + async _pull() { + this._reader ?? (this._reader = this._stream.getReader()); + while (this._currentIndex < this._targetIndex && !this._disposed) { + const { done, value } = await this._reader.read(); + if (done) { + for (const pendingSlice of this._pendingSlices) { + pendingSlice.resolve(null); + } + this._pendingSlices.length = 0; + this._endIndex = this._currentIndex; + break; + } + const startIndex = this._currentIndex; + const endIndex = this._currentIndex + value.byteLength; + for (let i = 0; i < this._pendingSlices.length; i++) { + const pendingSlice = this._pendingSlices[i]; + const cappedStart = Math.max(startIndex, pendingSlice.start); + const cappedEnd = Math.min(endIndex, pendingSlice.end); + if (cappedStart < cappedEnd) { + pendingSlice.bytes.set(value.subarray(cappedStart - startIndex, cappedEnd - startIndex), cappedStart - pendingSlice.start); + if (cappedEnd === pendingSlice.end) { + pendingSlice.resolve({ + bytes: pendingSlice.bytes, + view: toDataView(pendingSlice.bytes), + offset: pendingSlice.start + }); + this._pendingSlices.splice(i, 1); + i--; + } + } + } + this._cache.push({ + start: startIndex, + end: endIndex, + bytes: value, + view: toDataView(value), + age: 0 + // Unused + }); + while (this._cache.length > 0) { + const firstEntry = this._cache[0]; + const distance = this._maxRequestedIndex - firstEntry.end; + if (distance <= this._maxCacheSize) { + break; + } + this._cache.shift(); + } + this._currentIndex += value.byteLength; + } + this._pulling = false; + } + /** @internal */ + _dispose() { + this._pendingSlices.length = 0; + this._cache.length = 0; + void this._reader?.cancel(); + } +} +const PREFETCH_PROFILES = { + fileSystem: (start, end) => { + const padding = 2 ** 16; + start = Math.floor((start - padding) / padding) * padding; + end = Math.ceil((end + padding) / padding) * padding; + return { start, end }; + }, + network: (start, end, workers) => { + const paddingStart = 2 ** 16; + start = Math.max(0, Math.floor((start - paddingStart) / paddingStart) * paddingStart); + for (const worker of workers) { + const maxExtensionAmount = 8 * 2 ** 20; + const thresholdPoint = Math.max((worker.startPos + worker.targetPos) / 2, worker.targetPos - maxExtensionAmount); + if (closedIntervalsOverlap(start, end, thresholdPoint, worker.targetPos)) { + const size = worker.targetPos - worker.startPos; + const a = Math.ceil((size + 1) / maxExtensionAmount) * maxExtensionAmount; + const b = 2 ** Math.ceil(Math.log2(size + 1)); + const extent = Math.min(b, a); + end = Math.max(end, worker.startPos + extent); + } + } + end = Math.max(end, start + URL_SOURCE_MIN_LOAD_AMOUNT); + return { + start, + end + }; + } +}; +class ReadOrchestrator { + constructor(options) { + this.options = options; + this.fileSize = null; + this.nextAge = 0; + this.workers = []; + this.cache = []; + this.currentCacheSize = 0; + this.disposed = false; + this.queuedReads = []; + } + read(innerStart, innerEnd, minReadPosition, maxReadPosition) { + assert(!this.disposed); + const prefetchRange = this.options.prefetchProfile(innerStart, innerEnd, this.workers); + const outerStart = Math.max(prefetchRange.start, minReadPosition); + const outerEnd = Math.min(prefetchRange.end, this.fileSize ?? Infinity, maxReadPosition); + assert(outerStart <= innerStart && innerEnd <= outerEnd); + let result = null; + const innerCacheStartIndex = binarySearchLessOrEqual(this.cache, innerStart, (x) => x.start); + const innerStartEntry = innerCacheStartIndex !== -1 ? this.cache[innerCacheStartIndex] : null; + if (innerStartEntry && innerStartEntry.start <= innerStart && innerEnd <= innerStartEntry.end) { + innerStartEntry.age = this.nextAge++; + result = { + bytes: innerStartEntry.bytes, + view: innerStartEntry.view, + offset: innerStartEntry.start + }; + } + const outerCacheStartIndex = binarySearchLessOrEqual(this.cache, outerStart, (x) => x.start); + const bytes = result ? null : new Uint8Array(innerEnd - innerStart); + let contiguousBytesWriteEnd = 0; + let lastEnd = outerStart; + const outerHoles = []; + if (outerCacheStartIndex !== -1) { + for (let i = outerCacheStartIndex; i < this.cache.length; i++) { + const entry = this.cache[i]; + if (entry.start >= outerEnd) { + break; + } + if (entry.end <= outerStart) { + continue; + } + const cappedOuterStart = Math.max(outerStart, entry.start); + const cappedOuterEnd = Math.min(outerEnd, entry.end); + assert(cappedOuterStart <= cappedOuterEnd); + if (lastEnd < cappedOuterStart) { + outerHoles.push({ start: lastEnd, end: cappedOuterStart }); + } + lastEnd = cappedOuterEnd; + if (bytes) { + const cappedInnerStart = Math.max(innerStart, entry.start); + const cappedInnerEnd = Math.min(innerEnd, entry.end); + if (cappedInnerStart < cappedInnerEnd) { + const relativeOffset = cappedInnerStart - innerStart; + bytes.set(entry.bytes.subarray(cappedInnerStart - entry.start, cappedInnerEnd - entry.start), relativeOffset); + if (relativeOffset === contiguousBytesWriteEnd) { + contiguousBytesWriteEnd = cappedInnerEnd - innerStart; + } + } + } + entry.age = this.nextAge++; + } + if (lastEnd < outerEnd) { + outerHoles.push({ start: lastEnd, end: outerEnd }); + } + } else { + outerHoles.push({ start: outerStart, end: outerEnd }); + } + if (bytes && contiguousBytesWriteEnd >= bytes.length) { + result = { + bytes, + view: toDataView(bytes), + offset: innerStart + }; + } + if (outerHoles.length === 0) { + assert(result); + return result; + } + const { promise, resolve, reject } = promiseWithResolvers(); + const innerHoles = []; + for (const outerHole of outerHoles) { + const cappedStart = Math.max(innerStart, outerHole.start); + const cappedEnd = Math.min(innerEnd, outerHole.end); + if (cappedStart === outerHole.start && cappedEnd === outerHole.end) { + innerHoles.push(outerHole); + } else if (cappedStart < cappedEnd) { + innerHoles.push({ start: cappedStart, end: cappedEnd }); + } + } + const pendingSlice = bytes && { + start: innerStart, + bytes, + holes: innerHoles, + resolve, + reject + }; + outer: for (const outerHole of outerHoles) { + for (const worker of this.workers) { + const addedToWorker = this.checkHoleAgainstWorker(worker, outerHole, pendingSlice ? [pendingSlice] : []); + if (addedToWorker) { + this.checkQueuedReadsAgainstWorker(worker); + continue outer; + } + } + const strictTarget = outerHole.end < outerEnd || this.fileSize !== null; + const newWorker = this.createWorker(outerHole.start, outerHole.end, strictTarget); + if (newWorker) { + if (pendingSlice) { + newWorker.pendingSlices = [pendingSlice]; + } + this.runWorker(newWorker); + } else { + let index = binarySearchLessOrEqual(this.queuedReads, outerHole.start, (x) => x.hole.start); + let entry = index !== -1 ? this.queuedReads[index] : null; + if (entry && outerHole.start <= entry.hole.end) { + entry.hole.end = Math.max(entry.hole.end, outerHole.end); + entry.strictTarget && (entry.strictTarget = strictTarget); + if (pendingSlice) { + entry.pendingSlices.push(pendingSlice); + } + } else { + index++; + entry = { + hole: { + // Clone the hole because it might be mutated later + start: outerHole.start, + end: outerHole.end + }, + strictTarget, + pendingSlices: pendingSlice ? [pendingSlice] : [], + age: this.nextAge++ + }; + this.queuedReads.splice(index, 0, entry); + } + while (index + 1 < this.queuedReads.length) { + const nextEntry = this.queuedReads[index + 1]; + if (nextEntry.hole.start > entry.hole.end) { + break; + } + entry.hole.end = Math.max(entry.hole.end, nextEntry.hole.end); + entry.pendingSlices.push(...nextEntry.pendingSlices); + entry.strictTarget && (entry.strictTarget = nextEntry.strictTarget); + entry.age = Math.min(entry.age, nextEntry.age); + this.queuedReads.splice(index + 1, 1); + } + } + } + if (!result) { + assert(bytes); + result = promise.then((bytes2) => bytes2 && { + bytes: bytes2, + view: toDataView(bytes2), + offset: innerStart + }); + } + return result; + } + checkHoleAgainstWorker(worker, hole, pendingSlices) { + const gapTolerance = 2 ** 17; + if (closedIntervalsOverlap(hole.start - gapTolerance, hole.start, worker.currentPos, worker.targetPos)) { + worker.targetPos = Math.max(worker.targetPos, hole.end); + for (let i = 0; i < pendingSlices.length; i++) { + const pendingSlice = pendingSlices[i]; + if (!worker.pendingSlices.includes(pendingSlice)) { + worker.pendingSlices.push(pendingSlice); + } + } + if (!worker.running) { + this.runWorker(worker); + } + return true; + } + return false; + } + checkQueuedReadsAgainstWorker(worker) { + let wasTrueOnce = false; + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + const result = this.checkHoleAgainstWorker(worker, queuedRead.hole, queuedRead.pendingSlices); + if (result) { + this.queuedReads.splice(i, 1); + i--; + wasTrueOnce = true; + } else if (wasTrueOnce) { + break; + } + } + } + createWorker(startPos, targetPos, strictTarget) { + if (this.workers.length >= this.options.maxWorkerCount) { + let oldestWorker = null; + let oldestIndex = null; + for (let i = 0; i < this.workers.length; i++) { + const worker2 = this.workers[i]; + if (!worker2.running && worker2.pendingSlices.length === 0 && (!oldestWorker || worker2.age < oldestWorker.age)) { + oldestIndex = i; + oldestWorker = worker2; + } + } + if (oldestWorker) { + assert(oldestIndex !== null); + assert(oldestWorker.pendingSlices.length === 0); + this.workers.splice(oldestIndex, 1); + } else { + return null; + } + } + const worker = { + startPos, + currentPos: startPos, + targetPos, + strictTarget, + running: false, + // Due to async shenanigans, it can happen that workers are started after disposal. In this case, instead of + // simply not creating the worker, we allow it to run but immediately label it as aborted, so it can then + // shut itself down. + aborted: this.disposed, + pendingSlices: [], + age: this.nextAge++ + }; + this.workers.push(worker); + return worker; + } + runWorker(worker) { + assert(!worker.running); + assert(worker.currentPos < worker.targetPos); + worker.running = true; + worker.age = this.nextAge++; + void this.options.runWorker(worker).catch((error) => { + worker.running = false; + if (worker.pendingSlices.length > 0) { + worker.pendingSlices.forEach((x) => x.reject(error)); + worker.pendingSlices.length = 0; + } else { + throw error; + } + }).finally(() => { + if (worker.running) { + return; + } + if (this.queuedReads.length > 0) { + let oldestIndex = 0; + for (let i = 1; i < this.queuedReads.length; i++) { + const queuedRead2 = this.queuedReads[i]; + if (queuedRead2.age < this.queuedReads[oldestIndex].age) { + oldestIndex = i; + } + } + const queuedRead = this.queuedReads[oldestIndex]; + this.queuedReads.splice(oldestIndex, 1); + const newWorker = this.createWorker(queuedRead.hole.start, queuedRead.hole.end, queuedRead.strictTarget); + assert(newWorker); + newWorker.pendingSlices = queuedRead.pendingSlices; + this.runWorker(newWorker); + } + }); + } + consolidateEverythingIntoOneWorker(worker) { + const uniqueSlices = new Set(worker.pendingSlices); + for (let i = 0; i < this.workers.length; i++) { + const otherWorker = this.workers[i]; + if (otherWorker === worker) { + continue; + } + for (const slice of otherWorker.pendingSlices) { + uniqueSlices.add(slice); + } + otherWorker.aborted = true; + otherWorker.pendingSlices.length = 0; + this.workers.splice(i, 1); + i--; + } + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + for (const slice of queuedRead.pendingSlices) { + uniqueSlices.add(slice); + } + } + worker.pendingSlices = [...uniqueSlices]; + this.queuedReads.length = 0; + } + /** Called by a worker when it has read some data. */ + supplyWorkerData(worker, bytes) { + assert(!worker.aborted); + const start = worker.currentPos; + const end = start + bytes.length; + this.insertIntoCache({ + start, + end, + bytes, + view: toDataView(bytes), + age: this.nextAge++ + }); + worker.currentPos += bytes.length; + if (worker.currentPos > worker.targetPos) { + worker.targetPos = worker.currentPos; + this.checkQueuedReadsAgainstWorker(worker); + } + for (let i = 0; i < worker.pendingSlices.length; i++) { + const pendingSlice = worker.pendingSlices[i]; + const clampedStart = Math.max(start, pendingSlice.start); + const clampedEnd = Math.min(end, pendingSlice.start + pendingSlice.bytes.length); + if (clampedStart < clampedEnd) { + pendingSlice.bytes.set(bytes.subarray(clampedStart - start, clampedEnd - start), clampedStart - pendingSlice.start); + } + for (let j = 0; j < pendingSlice.holes.length; j++) { + const hole = pendingSlice.holes[j]; + if (start <= hole.start && end > hole.start) { + hole.start = end; + } + if (hole.end <= hole.start) { + pendingSlice.holes.splice(j, 1); + j--; + } + } + if (pendingSlice.holes.length === 0) { + pendingSlice.resolve(pendingSlice.bytes); + worker.pendingSlices.splice(i, 1); + i--; + } + } + for (let i = 0; i < this.workers.length; i++) { + const otherWorker = this.workers[i]; + if (worker === otherWorker || otherWorker.running) { + continue; + } + if (closedIntervalsOverlap(start, end, otherWorker.currentPos, otherWorker.targetPos)) { + this.workers.splice(i, 1); + i--; + } + } + } + supplyFileSize(size) { + assert(this.fileSize === null); + this.fileSize = size; + for (const worker of this.workers) { + worker.targetPos = Math.min(worker.targetPos, size); + worker.strictTarget = true; + for (let i = 0; i < worker.pendingSlices.length; i++) { + const pendingSlice = worker.pendingSlices[i]; + for (const hole of pendingSlice.holes) { + if (hole.end > size) { + pendingSlice.resolve(null); + worker.pendingSlices.splice(i, 1); + i--; + break; + } + } + } + } + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + if (queuedRead.hole.start >= size) { + for (const slice of queuedRead.pendingSlices) + slice.resolve(null); + this.queuedReads.splice(i, 1); + i--; + } else if (queuedRead.hole.end > size) { + queuedRead.hole.end = size; + queuedRead.strictTarget = true; + for (let j = 0; j < queuedRead.pendingSlices.length; j++) { + const slice = queuedRead.pendingSlices[j]; + if (slice.start >= size) { + slice.resolve(null); + queuedRead.pendingSlices.splice(j, 1); + j--; + } + } + } + } + } + signalWorkerStoppedRunning(worker) { + worker.running = false; + worker.pendingSlices.length = 0; + } + /** Called when a worker reaches the end of the underlying data and must be cleaned up. */ + onWorkerFinished(worker) { + const index = this.workers.indexOf(worker); + assert(index !== -1); + worker.running = false; + this.workers.splice(index, 1); + if (this.fileSize === null) { + this.supplyFileSize(worker.currentPos); + } + for (const pendingSlice of worker.pendingSlices) { + pendingSlice.resolve(null); + } + } + insertIntoCache(entry) { + if (this.options.maxCacheSize === 0) { + return; + } + let insertionIndex = binarySearchLessOrEqual(this.cache, entry.start, (x) => x.start) + 1; + if (insertionIndex > 0) { + const previous = this.cache[insertionIndex - 1]; + if (previous.end >= entry.end) { + return; + } + if (previous.end > entry.start) { + const joined = new Uint8Array(entry.end - previous.start); + joined.set(previous.bytes, 0); + joined.set(entry.bytes, entry.start - previous.start); + this.currentCacheSize += entry.end - previous.end; + previous.bytes = joined; + previous.view = toDataView(joined); + previous.end = entry.end; + insertionIndex--; + entry = previous; + } else { + this.cache.splice(insertionIndex, 0, entry); + this.currentCacheSize += entry.bytes.length; + } + } else { + this.cache.splice(insertionIndex, 0, entry); + this.currentCacheSize += entry.bytes.length; + } + for (let i = insertionIndex + 1; i < this.cache.length; i++) { + const next = this.cache[i]; + if (entry.end <= next.start) { + break; + } + if (entry.end >= next.end) { + this.cache.splice(i, 1); + this.currentCacheSize -= next.bytes.length; + i--; + continue; + } + const joined = new Uint8Array(next.end - entry.start); + joined.set(entry.bytes, 0); + joined.set(next.bytes, next.start - entry.start); + this.currentCacheSize -= entry.end - next.start; + entry.bytes = joined; + entry.view = toDataView(joined); + entry.end = next.end; + this.cache.splice(i, 1); + break; + } + while (this.currentCacheSize > this.options.maxCacheSize) { + let oldestIndex = 0; + let oldestEntry = this.cache[0]; + for (let i = 1; i < this.cache.length; i++) { + const entry2 = this.cache[i]; + if (entry2.age < oldestEntry.age) { + oldestIndex = i; + oldestEntry = entry2; + } + } + if (this.currentCacheSize - oldestEntry.bytes.length <= this.options.maxCacheSize) { + break; + } + this.cache.splice(oldestIndex, 1); + this.currentCacheSize -= oldestEntry.bytes.length; + } + } + dispose() { + for (const worker of this.workers) { + worker.aborted = true; + } + this.workers.length = 0; + this.cache.length = 0; + this.disposed = true; + } +} +class RangedSource extends Source { + /** @internal */ + constructor(baseSource, offset, length) { + super(); + this._ref = null; + if (baseSource._disposed) { + throw new Error("Cannot create a slice of a disposed source."); + } + this._baseSource = baseSource; + this._offset = offset; + this._length = length ?? null; + } + /** @internal */ + _getFileSize() { + const baseSize = this._baseSource._getFileSize(); + if (baseSize === void 0) { + return this._length !== null ? this._length : void 0; + } + if (baseSize === null) { + if (this._length !== null) { + return this._length; + } else { + return null; + } + } + return clamp$1(baseSize - this._offset, 0, this._length ?? Infinity); + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + if (this._length !== null && end > this._length) { + return null; + } + const result = this._baseSource._read(this._offset + start, this._offset + end, this._offset + minReadPosition, this._offset + maxReadPosition); + if (result instanceof Promise) { + return result.then((result2) => { + if (!result2) { + return null; + } + result2.offset -= this._offset; + return result2; + }); + } else { + if (!result) { + return null; + } + result.offset -= this._offset; + return result; + } + } + /** @internal */ + _dispose() { + this._ref?.free(); + } + ref() { + this._ref ?? (this._ref = this._baseSource.ref()); + return super.ref(); + } +} +var __addDisposableResource = function(env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose, inner; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + if (async) inner = dispose; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + if (inner) dispose = function() { + try { + inner.call(this); + } catch (e) { + return Promise.reject(e); + } + }; + env.stack.push({ value, dispose, async }); + } else if (async) { + env.stack.push({ async: true }); + } + return value; +}; +var __disposeResources = /* @__PURE__ */ (function(SuppressedError2) { + return function(env) { + function fail(e) { + env.error = env.hasError ? new SuppressedError2(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + var r, s = 0; + function next() { + while (r = env.stack.pop()) { + try { + if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); + if (r.dispose) { + var result = r.dispose.call(r.value); + if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { + fail(e); + return next(); + }); + } else s |= 1; + } catch (e) { + fail(e); + } + } + if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); + if (env.hasError) throw env.error; + } + return next(); + }; +})(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}); +const IV_STRING_REGEX = /^0[xX][0-9a-fA-F]+$/; +const BASE64_DATA_URI_REGEX = /^data:.*;base64,/i; +class HlsSegmentedInput extends SegmentedInput { + constructor(demuxer, path, trackDeclarations, lines) { + super(demuxer.input, path, trackDeclarations); + this.segments = []; + this.nextLines = null; + this.currentUpdateSegmentsPromise = null; + this.streamHasEnded = false; + this.lastSegmentUpdateTime = -Infinity; + this.refreshInterval = 5; + this.demuxer = demuxer; + this.nextLines = lines; + } + runUpdateSegments() { + return this.currentUpdateSegmentsPromise ?? (this.currentUpdateSegmentsPromise = (async () => { + try { + const remainingWaitTimeMs = this.getRemainingWaitTimeMs(); + if (remainingWaitTimeMs > 0) { + await wait(remainingWaitTimeMs); + } + this.lastSegmentUpdateTime = performance.now(); + await this.updateSegments(); + } finally { + this.currentUpdateSegmentsPromise = null; + } + })()); + } + getRemainingWaitTimeMs() { + const elapsed = performance.now() - this.lastSegmentUpdateTime; + const result = Math.max(0, 1e3 * this.refreshInterval - elapsed); + if (result <= 50) { + return 0; + } + return result; + } + /** + * Reads and parses the segment info from the playlist file. When called more than one, it updates the existing + * segments by appending the new ones. Existing segments are never removed. + */ + async updateSegments() { + let lines = this.nextLines; + this.nextLines = null; + if (!lines) { + const env_1 = { stack: [], error: void 0, hasError: false }; + try { + const ref = __addDisposableResource(env_1, await this.demuxer.input._getSourceUncached({ path: this.path, isRoot: false }), false); + const reader = new Reader(ref.source); + const slice = await reader.requestEntireFile(); + assert(slice); + lines = readAllLines(slice, slice.length, { ignore: canIgnoreLine }); + } catch (e_1) { + env_1.error = e_1; + env_1.hasError = true; + } finally { + __disposeResources(env_1); + } + } + let headerRead = false; + let accumulatedTime = 0; + let nextSegmentDuration = null; + let currentKey = null; + let nextSequenceNumber = 0; + let currentFirstSegment = null; + let currentInitSegment = null; + let lastByteRangeEnd = null; + let nextByteRange = null; + let lastProgramDateTimeSeconds = null; + let targetDuration = null; + let segmentSeen = false; + let prevLastSegment = last(this.segments) ?? null; + const parseByteRange = (content) => { + const atIndex = content.indexOf("@"); + const length = Number(atIndex === -1 ? content : content.slice(0, atIndex)); + if (!Number.isInteger(length) || length < 0) { + throw new Error(`Invalid #EXT-X-BYTERANGE length '${content}'.`); + } + let offset = null; + if (atIndex !== -1) { + offset = Number(content.slice(atIndex + 1)); + if (!Number.isInteger(offset) || offset < 0) { + throw new Error(`Invalid #EXT-X-BYTERANGE offset '${content}'.`); + } + } + return { length, offset }; + }; + const setNextSequenceNumber = (number) => { + nextSequenceNumber = number; + if (prevLastSegment) { + assert(prevLastSegment.sequenceNumber !== null); + if (prevLastSegment.sequenceNumber < number) { + accumulatedTime = prevLastSegment.timestamp + prevLastSegment.duration; + currentFirstSegment = prevLastSegment.firstSegment; + currentInitSegment = prevLastSegment.initSegment; + lastProgramDateTimeSeconds = prevLastSegment.lastProgramDateTimeSeconds; + prevLastSegment = null; + } + } + }; + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!headerRead) { + if (line !== "#EXTM3U") { + throw new Error("Invalid M3U8 file; expected first line to be #EXTM3U."); + } + headerRead = true; + continue; + } + if (!line.startsWith("#")) { + if (!prevLastSegment) { + if (nextSegmentDuration === null) { + throw new Error("Invalid M3U8 file; a segment must be preceded by an #EXTINF tag."); + } + let key = currentKey; + if (key && key.method === "AES-128" && !key.iv) { + const iv = new Uint8Array(AES_128_BLOCK_SIZE); + const view = toDataView(iv); + view.setUint32(8, Math.floor(nextSequenceNumber / 2 ** 32)); + view.setUint32(12, nextSequenceNumber); + key = { ...key, iv }; + } + const fullPath = joinPaths(this.path, line); + const location = { + path: fullPath, + offset: nextByteRange?.offset ?? 0, + length: nextByteRange?.length ?? null + }; + const segment = { + timestamp: accumulatedTime, + relativeToUnixEpoch: lastProgramDateTimeSeconds !== null, + firstSegment: currentFirstSegment, + sequenceNumber: nextSequenceNumber, + location, + duration: nextSegmentDuration, + encryption: key, + initSegment: currentInitSegment, + lastProgramDateTimeSeconds + }; + currentFirstSegment ?? (currentFirstSegment = segment); + accumulatedTime += nextSegmentDuration; + this.segments.push(segment); + } + nextSegmentDuration = null; + if (nextByteRange === null) { + lastByteRangeEnd = null; + } else { + nextByteRange = null; + } + setNextSequenceNumber(nextSequenceNumber + 1); + } + if (line.startsWith(TAG_EXTINF)) { + if (prevLastSegment) { + segmentSeen = true; + continue; + } + if (!segmentSeen) { + if (lastProgramDateTimeSeconds === null && nextSequenceNumber > 0 && targetDuration !== null) { + accumulatedTime = nextSequenceNumber * targetDuration; + } + segmentSeen = true; + } + const extinfContent = line.slice(TAG_EXTINF.length); + const commaIndex = extinfContent.indexOf(","); + const durationStr = commaIndex === -1 ? extinfContent : extinfContent.slice(0, commaIndex); + const duration = Number(durationStr); + if (!Number.isFinite(duration) || duration < 0) { + throw new Error(`Invalid #EXTINF tag duration '${durationStr}'.`); + } + nextSegmentDuration = duration; + } else if (line.startsWith(TAG_MAP)) { + const attributes = new AttributeList(line.slice(TAG_MAP.length)); + const uri = attributes.get("uri"); + if (!uri) { + throw new Error("Invalid #EXT-X-MAP tag; missing URI attribute."); + } + const byteRange = attributes.get("byterange"); + let parsedByteRange = null; + if (byteRange !== null) { + parsedByteRange = parseByteRange(byteRange); + } + if (parsedByteRange && parsedByteRange.offset === null) { + throw new Error("Invalid #EXT-X-MAP tag; BYTERANGE attribute must have a specified offset."); + } + if (!prevLastSegment) { + const fullPath = joinPaths(this.path, uri); + const location = { + path: fullPath, + offset: parsedByteRange?.offset ?? 0, + length: parsedByteRange?.length ?? null + }; + if (currentKey?.method === "AES-128" && !currentKey.iv) { + throw new Error("IV attribute must be set on #EXT-X-KEY tag preceding the #EXT-X-MAP tag."); + } + const segment = { + timestamp: accumulatedTime, + relativeToUnixEpoch: lastProgramDateTimeSeconds !== null, + firstSegment: null, + sequenceNumber: null, + location, + duration: 0, + encryption: currentKey, + initSegment: null, + lastProgramDateTimeSeconds + }; + currentInitSegment = segment; + } + nextSegmentDuration = null; + if (nextByteRange === null) { + lastByteRangeEnd = null; + } else { + nextByteRange = null; + } + } else if (line.startsWith(TAG_KEY)) { + const attributes = new AttributeList(line.slice(TAG_KEY.length)); + const method = attributes.get("method"); + if (method === "NONE") { + currentKey = null; + } else if (method === "AES-128") { + const uri = attributes.get("uri"); + if (!uri) { + throw new Error("Invalid #EXT-X-KEY: AES-128 requires a URI attribute."); + } + let iv = null; + const ivString = attributes.get("iv"); + if (ivString) { + if (!IV_STRING_REGEX.test(ivString)) { + throw new Error(`Unsupported IV format '${ivString}'.`); + } + let hex = ivString.slice(2); + hex = hex.padStart(AES_128_BLOCK_SIZE * 2, "0"); + iv = new Uint8Array(AES_128_BLOCK_SIZE); + for (let i2 = 0; i2 < AES_128_BLOCK_SIZE; i2++) { + const startIndex = -AES_128_BLOCK_SIZE * 2 + i2; + iv[i2] = parseInt(hex.slice(startIndex, startIndex + 2), 16); + } + } + const keyFormat = attributes.get("keyformat") ?? "identity"; + if (keyFormat !== "identity") { + throw new Error("For AES-128 encryption, only the 'identity' KEYFORMAT is currently supported. If you think other formats should be supported, please raise an issue."); + } + currentKey = { + method: "AES-128", + keyUri: joinPaths(this.path, uri), + iv, + keyFormat + }; + } else if (method === "SAMPLE-AES" || method === "SAMPLE-AES-CTR") { + const uri = attributes.get("uri"); + if (!uri) { + throw new Error(`Invalid #EXT-X-KEY: ${method} requires a URI attribute.`); + } + const keyFormat = attributes.get("keyformat") ?? "identity"; + if (keyFormat === "identity") { + throw new Error("For SAMPLE-AES and SAMPLE-AES-CTR encryption, the 'identity' KEYFORMAT is not supported. If you think this format should be supported, please raise an issue."); + } + let psshBox = null; + if (BASE64_DATA_URI_REGEX.test(uri)) { + const commaIndex = uri.indexOf(","); + const bytes = base64ToBytes(uri.slice(commaIndex + 1)); + if (bytes.length >= 8 && bytes[4] === 112 && bytes[5] === 115 && bytes[6] === 115 && bytes[7] === 104) { + const size = toDataView(bytes).getUint32(0); + psshBox = parsePsshBoxContents(bytes.subarray(8, Math.min(size, bytes.length))); + } + } + currentKey = { + method, + psshBox + }; + } else { + throw new Error(`Unsupported encryption method '${method}'. If you think this method should be supported, please raise an issue.`); + } + } else if (line.startsWith(TAG_MEDIA_SEQUENCE)) { + const value = line.slice(TAG_MEDIA_SEQUENCE.length); + const number = Number(value); + if (!Number.isInteger(number) || number < 0) { + throw new Error(`Invalid EXT-X-MEDIA-SEQUENCE value '${value}'.`); + } + setNextSequenceNumber(number); + } else if (line.startsWith(TAG_BYTERANGE)) { + const parsed = parseByteRange(line.slice(TAG_BYTERANGE.length)); + if (parsed.offset === null) { + if (lastByteRangeEnd === null) { + throw new Error("Invalid M3U8 file; #EXT-X-BYTERANGE without offset requires a previous byte range."); + } + parsed.offset = lastByteRangeEnd; + } + nextByteRange = parsed; + lastByteRangeEnd = parsed.offset + parsed.length; + } else if (line.startsWith(TAG_PROGRAM_DATE_TIME)) { + if (prevLastSegment) { + continue; + } + const dateTime = line.slice(TAG_PROGRAM_DATE_TIME.length); + const dateTimeMs = Date.parse(dateTime); + if (!Number.isFinite(dateTimeMs)) { + continue; + } + const dateTimeSeconds = dateTimeMs / 1e3; + if (lastProgramDateTimeSeconds === dateTimeSeconds) { + continue; + } + if (lastProgramDateTimeSeconds === null && this.segments.length > 0) { + const lastSegment = last(this.segments); + const lastSegmentEnd = lastSegment.timestamp + lastSegment.duration; + const offset = dateTimeSeconds - lastSegmentEnd; + for (const segment of this.segments) { + segment.timestamp += offset; + segment.relativeToUnixEpoch = true; + } + accumulatedTime += offset; + } + lastProgramDateTimeSeconds = dateTimeSeconds; + accumulatedTime = dateTimeSeconds; + } else if (line === TAG_DISCONTINUITY) { + currentFirstSegment = null; + } else if (line.startsWith(TAG_TARGETDURATION)) { + const value = line.slice(TAG_TARGETDURATION.length); + const duration = Number(value); + if (!Number.isFinite(duration) || duration < 0) { + throw new Error(`Invalid EXT-X-TARGETDURATION value '${value}'.`); + } + this.refreshInterval = duration; + targetDuration = duration; + } else if (line === TAG_ENDLIST) { + this.streamHasEnded = true; + break; + } else if (line.startsWith(TAG_PLAYLIST_TYPE)) { + const type = line.slice(TAG_PLAYLIST_TYPE.length); + if (type.toLowerCase() === "vod") { + this.streamHasEnded = true; + } + } + } + if (!headerRead) { + throw new Error("Invalid M3U8 file; no #EXTM3U header."); + } + } + async getFirstSegment() { + if (this.segments.length === 0) { + await this.runUpdateSegments(); + } + return this.segments[0] ?? null; + } + async getSegmentAt(timestamp, options) { + if (this.segments.length === 0) { + await this.runUpdateSegments(); + } + let isLazy = !!options.skipLiveWait && this.getRemainingWaitTimeMs() > 0; + while (true) { + const index = binarySearchLessOrEqual(this.segments, timestamp, (x) => x.timestamp); + if (index === -1) { + return null; + } + if (index < this.segments.length - 1 || this.streamHasEnded || isLazy) { + return this.segments[index]; + } + const segment = this.segments[index]; + if (timestamp < segment.timestamp + segment.duration) { + return segment; + } + await this.runUpdateSegments(); + if (options.skipLiveWait) { + isLazy = true; + } + } + } + async getNextSegment(segment, options) { + const index = this.segments.indexOf(segment); + assert(index !== -1); + const nextIndex = index + 1; + let isLazy = !!options.skipLiveWait && this.getRemainingWaitTimeMs() > 0; + while (true) { + if (nextIndex < this.segments.length) { + return this.segments[nextIndex]; + } + if (this.streamHasEnded || isLazy) { + return null; + } + await this.runUpdateSegments(); + if (options.skipLiveWait) { + isLazy = true; + } + } + } + async getPreviousSegment(segment) { + const index = this.segments.indexOf(segment); + assert(index !== -1); + return this.segments[index - 1] ?? null; + } + getInputForSegment(segment) { + const hlsSegment = segment; + const cacheEntry = this.inputCache.find((x) => x.segment === hlsSegment); + if (cacheEntry) { + cacheEntry.age = this.nextInputCacheAge++; + return cacheEntry.input; + } + let initInput = null; + if (hlsSegment.initSegment || hlsSegment.firstSegment) { + initInput = this.getInputForSegment(hlsSegment.initSegment ?? hlsSegment.firstSegment); + } + const formatOptions = { + ...this.input._formatOptions, + isobmff: { + ...this.input._formatOptions.isobmff, + // Intercept calls to resolveKeyId to inject our psshBox knowledge into it + resolveKeyId: this.input._formatOptions.isobmff?.resolveKeyId && ((options) => { + if (!hlsSegment.encryption || !(hlsSegment.encryption.method === "SAMPLE-AES" || hlsSegment.encryption.method === "SAMPLE-AES-CTR") || !hlsSegment.encryption.psshBox) { + return this.input._formatOptions.isobmff.resolveKeyId(options); + } + let psshBoxes = options.psshBoxes; + const { psshBox } = hlsSegment.encryption; + if ((psshBox.keyIds === null || psshBox.keyIds.includes(options.keyId)) && !psshBoxes.some((x) => psshBoxesAreEqual(x, psshBox))) { + psshBoxes = [...psshBoxes, psshBox]; + } + return this.input._formatOptions.isobmff.resolveKeyId({ ...options, psshBoxes }); + }) + } + }; + const input = new Input({ + source: new CustomPathedSource(hlsSegment.location.path, async (request) => { + assert(request.isRoot); + const proxiedRequest = { + ...request, + isRoot: false + }; + let ref; + const needsSlice = hlsSegment.location.offset > 0 || hlsSegment.location.length !== null; + if (!hlsSegment.encryption || hlsSegment.encryption.method === "SAMPLE-AES" || hlsSegment.encryption.method === "SAMPLE-AES-CTR") { + ref = await this.input._getSourceCached(proxiedRequest); + if (needsSlice) { + const slice = ref.source.slice(hlsSegment.location.offset, hlsSegment.location.length ?? void 0); + const sliceRef = slice.ref(); + ref.free(); + ref = sliceRef; + } + } else if (hlsSegment.encryption.method === "AES-128") { + const encryption = hlsSegment.encryption; + assert(encryption.iv); + let ciphertextRef = await this.input._getSourceCached(proxiedRequest); + if (needsSlice) { + const slice = ciphertextRef.source.slice(hlsSegment.location.offset, hlsSegment.location.length ?? void 0); + const sliceRef = slice.ref(); + ciphertextRef.free(); + ciphertextRef = sliceRef; + } + const ciphertextReader = new Reader(ciphertextRef.source); + const stream = createAes128CbcDecryptStream(ciphertextReader, async () => { + const env_2 = { stack: [], error: void 0, hasError: false }; + try { + const keyRef = __addDisposableResource(env_2, await this.input._getSourceCached({ path: encryption.keyUri, isRoot: false }, ENCRYPTION_KEY_CACHE_GROUP), false); + const keyReader = new Reader(keyRef.source); + const keySlice = await keyReader.requestSlice(0, AES_128_BLOCK_SIZE); + if (!keySlice) { + throw new Error("Invalid AES-128 key; expected at least 16 bytes of data."); + } + const key = readBytes(keySlice, AES_128_BLOCK_SIZE); + return { key, iv: encryption.iv }; + } catch (e_2) { + env_2.error = e_2; + env_2.hasError = true; + } finally { + __disposeResources(env_2); + } + }, () => { + ciphertextRef.free(); + }); + ref = new ReadableStreamSource(stream).ref(); + } else { + assert(false); + } + return ref; + }), + // Do not allow recursive HLS. Cool on paper, but allows for nasty infinite-depth request trees. + formats: this.input._formats.filter((x) => !(x instanceof HlsInputFormat)), + initInput: initInput ?? void 0, + formatOptions + }); + input._onFormatDetermined = (format) => { + if ((hlsSegment.encryption?.method === "SAMPLE-AES" || hlsSegment.encryption?.method === "SAMPLE-AES-CTR") && !format._isIsobmff) { + throw new Error("The SAMPLE-AES and SAMPLE-AES-CTR encryption methods are currently only supported for ISOBMFF files."); + } + }; + this.inputCache.push({ + segment: hlsSegment, + input, + age: this.nextInputCacheAge++ + }); + const MAX_INPUT_CACHE_SIZE = 4; + if (this.inputCache.length > MAX_INPUT_CACHE_SIZE) { + const minAgeIndex = arrayArgmin(this.inputCache, (x) => x.age); + assert(minAgeIndex !== -1); + this.inputCache.splice(minAgeIndex, 1); + } + return input; + } + async getLiveRefreshInterval() { + if (this.getRemainingWaitTimeMs() === 0) { + await this.runUpdateSegments(); + } + return this.streamHasEnded ? null : this.refreshInterval; + } +} +class HlsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.trackBackings = null; + this.internalTracks = null; + this.segmentedInputs = []; + this.hasMasterPlaylist = true; + } + readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + assert(this.input._rootSource instanceof PathedSource); + const { rootPath } = this.input._rootSource; + const slice = await this.input._reader.requestEntireFile(); + assert(slice); + const lines = readAllLines(slice, slice.length, { ignore: canIgnoreLine }); + const variantStreams = []; + const mediaTags = []; + for (let i = 1; i < lines.length; i++) { + const line = lines[i]; + if (line.startsWith(TAG_STREAM_INF)) { + const streamInfLineNumber = i; + const playlistPath = lines[++i]; + if (playlistPath === void 0) { + throw new Error("Incorrect M3U8 file; a line must follow the #EXT-X-STREAM-INF tag."); + } + const fullPath = joinPaths(rootPath, playlistPath); + const attributes = new AttributeList(line.slice(TAG_STREAM_INF.length)); + const bandwidth = attributes.getAsNumber("bandwidth"); + if (bandwidth === null) { + throw new Error("Invalid M3U8 file; #EXT-X-STREAM-INF tag requires a BANDWIDTH attribute with a valid numerical value."); + } + variantStreams.push({ + fullPath, + attributes, + lineNumber: streamInfLineNumber, + hasOnlyKeyPackets: false + }); + } else if (line.startsWith(TAG_I_FRAME_STREAM_INF)) { + const attributes = new AttributeList(line.slice(TAG_I_FRAME_STREAM_INF.length)); + const playlistPath = attributes.get("uri"); + if (playlistPath === null) { + throw new Error("Invalid M3U8 file; #EXT-X-I-FRAME-STREAM-INF tag requires a URI attribute."); + } + const bandwidth = attributes.getAsNumber("bandwidth"); + if (bandwidth === null) { + throw new Error("Invalid M3U8 file; #EXT-X-I-FRAME-STREAM-INF tag requires a BANDWIDTH attribute with a valid numerical value."); + } + const fullPath = joinPaths(rootPath, playlistPath); + variantStreams.push({ + fullPath, + attributes, + lineNumber: i, + hasOnlyKeyPackets: true + }); + } else if (line.startsWith(TAG_MEDIA)) { + const attributes = new AttributeList(line.slice(TAG_MEDIA.length)); + const type = attributes.get("type"); + if (type === null) { + throw new Error("Invalid M3U8 file; #EXT-X-MEDIA tag requires a TYPE attribute."); + } + const groupId = attributes.get("group-id"); + if (groupId === null) { + throw new Error("Invalid M3U8 file; #EXT-X-MEDIA tag requires a GROUP-ID attribute."); + } + let fullPath = null; + const uri = attributes.get("uri"); + if (uri !== null) { + fullPath = joinPaths(rootPath, uri); + } + mediaTags.push({ fullPath, attributes, lineNumber: i }); + } else if (line === TAG_I_FRAMES_ONLY) ; + else if (line.startsWith(TAG_EXTINF)) { + const segmentedInput = new HlsSegmentedInput(this, rootPath, null, lines); + this.segmentedInputs = [segmentedInput]; + this.hasMasterPlaylist = false; + this.trackBackings = await segmentedInput.getTrackBackings(); + return; + } + } + const videoGroupIds = [ + ...new Set(mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "video").map((tag) => tag.attributes.get("group-id"))) + ]; + const audioGroupIds = [ + ...new Set(mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "audio").map((tag) => tag.attributes.get("group-id"))) + ]; + const internalTracksByVariant = await Promise.all(variantStreams.map(async (variantStream, i) => { + const result = []; + const codecsList = variantStream.attributes.get("codecs"); + let codecStrings; + if (codecsList) { + codecStrings = codecsList.split(",").map((x) => x.trim()); + } else { + const segmentedInput = this.getSegmentedInputForPath(variantStream.fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const tracksWithCodec = await Promise.all(trackBackings.map(async (t) => ({ track: t, codec: await t.getCodec() }))); + codecStrings = await Promise.all(tracksWithCodec.filter((x) => x.codec !== null).map((x) => x.track.getDecoderConfig().then((x2) => x2.codec))); + } + const videoGroupId = variantStream.attributes.get("video"); + const audioGroupId = variantStream.attributes.get("audio"); + const containsVideoCodecs = codecStrings.some((x) => VIDEO_CODECS.includes(inferCodecFromCodecString(x))); + const containsAudioCodecs = codecStrings.some((x) => AUDIO_CODECS.includes(inferCodecFromCodecString(x))); + if (videoGroupId !== null && !containsVideoCodecs) { + if (!videoGroupIds.includes(videoGroupId)) { + throw new Error(`Invalid M3U8 file; variant stream references video group "${videoGroupId}" which is not defined in any #EXT-X-MEDIA tags.`); + } + const matchingVideoMediaTag = mediaTags.find((mediaTag) => { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + return groupId === videoGroupId && type.toLowerCase() === "video"; + }); + outer: if (matchingVideoMediaTag) { + const uri = matchingVideoMediaTag.attributes.get("uri"); + if (uri === null) { + break outer; + } + const fullPath = joinPaths(rootPath, uri); + const segmentedInput = this.getSegmentedInputForPath(fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const videoTrack = trackBackings.find((x) => x.getType() === "video"); + if (!videoTrack || await videoTrack.getCodec() === null) { + break outer; + } + const additionalCodecString = await videoTrack.getDecoderConfig().then((x) => x?.codec ?? null); + assert(additionalCodecString !== null); + codecStrings.push(additionalCodecString); + } + } + if (audioGroupId !== null && !containsAudioCodecs) { + if (!audioGroupIds.includes(audioGroupId)) { + throw new Error(`Invalid M3U8 file; variant stream references audio group "${audioGroupId}" which is not defined in any #EXT-X-MEDIA tags.`); + } + const matchingAudioMediaTag = mediaTags.find((tag) => { + const groupId = tag.attributes.get("group-id"); + const type = tag.attributes.get("type"); + return groupId === audioGroupId && type.toLowerCase() === "audio"; + }); + outer: if (matchingAudioMediaTag) { + const uri = matchingAudioMediaTag.attributes.get("uri"); + if (uri === null) { + break outer; + } + const fullPath = joinPaths(rootPath, uri); + const segmentedInput = this.getSegmentedInputForPath(fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const audioTrack = trackBackings.find((x) => x.getType() === "audio"); + if (!audioTrack || await audioTrack.getCodec() === null) { + break outer; + } + const additionalCodecString = await audioTrack.getDecoderConfig().then((x) => x?.codec ?? null); + assert(additionalCodecString !== null); + codecStrings.push(additionalCodecString); + } + } + codecStrings = [...new Set(codecStrings)]; + let videoCodecString = null; + let audioCodecString = null; + const bandwidth = variantStream.attributes.getAsNumber("bandwidth"); + assert(bandwidth !== null); + const averageBandwidth = variantStream.attributes.getAsNumber("average-bandwidth"); + const name = variantStream.attributes.get("name"); + for (const codecString of codecStrings) { + const inferredCodec = inferCodecFromCodecString(codecString); + if (inferredCodec === null) { + continue; + } + if (VIDEO_CODECS.includes(inferredCodec)) { + if (videoCodecString !== null) { + throw new Error("Unsupported M3U8 file; multiple video codecs found in the CODECS attribute of a variant stream."); + } + videoCodecString = codecString; + const videoGroupId2 = variantStream.attributes.get("video"); + if (videoGroupId2 === null) { + const resolution = variantStream.attributes.get("resolution"); + let width = null; + let height = null; + if (resolution) { + const match = resolution.match(/^(\d+)x(\d+)$/); + if (match) { + width = Number(match[1]); + height = Number(match[2]); + } + } + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: true, + autoselect: true, + languageCode: UNDETERMINED_LANGUAGE, + lineNumber: variantStream.lineNumber, + fullPath: variantStream.fullPath, + fullCodecString: videoCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: bandwidth, + averageBitrate: averageBandwidth, + name, + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "video", + width, + height + } + }); + } else { + if (!videoGroupIds.includes(videoGroupId2)) { + throw new Error(`Invalid M3U8 file; variant stream references video group "${videoGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`); + } + for (const mediaTag of mediaTags) { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + if (groupId !== videoGroupId2 || type.toLowerCase() !== "video") { + continue; + } + const resolution = mediaTag.attributes.get("resolution") ?? variantStream.attributes.get("resolution"); + let width = null; + let height = null; + if (resolution) { + const match = resolution.match(/^(\d+)x(\d+)$/); + if (match) { + width = Number(match[1]); + height = Number(match[2]); + } + } + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: getMediaTagDefault(mediaTag.attributes), + // Autoselect is inferred to be true if the default is true + autoselect: getMediaTagDefault(mediaTag.attributes) || getMediaTagAutoselect(mediaTag.attributes), + languageCode: preprocessLanguageCode(mediaTag.attributes.get("language")), + lineNumber: mediaTag.lineNumber, + fullPath: mediaTag.fullPath ?? variantStream.fullPath, + fullCodecString: videoCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: null, + averageBitrate: null, + name: mediaTag.attributes.get("name"), + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "video", + width, + height + } + }); + } + } + } else if (AUDIO_CODECS.includes(inferredCodec)) { + if (audioCodecString !== null) { + throw new Error("Unsupported M3U8 file; multiple audio codecs found in the CODECS attribute of a variant stream."); + } + audioCodecString = codecString; + const audioGroupId2 = variantStream.attributes.get("audio"); + if (audioGroupId2 === null) { + const channels = variantStream.attributes.get("channels"); + const parsedChannels = channels !== null ? Number(channels.split("/")[0]) : null; + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: true, + autoselect: true, + languageCode: UNDETERMINED_LANGUAGE, + lineNumber: variantStream.lineNumber, + fullPath: variantStream.fullPath, + fullCodecString: audioCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: bandwidth, + averageBitrate: averageBandwidth, + name, + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "audio", + numberOfChannels: parsedChannels !== null && Number.isInteger(parsedChannels) && parsedChannels > 0 ? parsedChannels : null + } + }); + } else { + if (!audioGroupIds.includes(audioGroupId2)) { + throw new Error(`Invalid M3U8 file; variant stream references audio group "${audioGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`); + } + for (const mediaTag of mediaTags) { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + if (groupId !== audioGroupId2 || type.toLowerCase() !== "audio") { + continue; + } + const channels = mediaTag.attributes.get("channels") ?? variantStream.attributes.get("channels"); + const parsedChannels = channels !== null ? Number(channels.split("/")[0]) : null; + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: getMediaTagDefault(mediaTag.attributes), + // Autoselect is inferred to be true if the default is true + autoselect: getMediaTagDefault(mediaTag.attributes) || getMediaTagAutoselect(mediaTag.attributes), + languageCode: preprocessLanguageCode(mediaTag.attributes.get("language")), + lineNumber: mediaTag.lineNumber, + fullPath: mediaTag.fullPath ?? variantStream.fullPath, + fullCodecString: audioCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: null, + averageBitrate: null, + name: mediaTag.attributes.get("name"), + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "audio", + numberOfChannels: parsedChannels !== null && Number.isInteger(parsedChannels) && parsedChannels > 0 ? parsedChannels : null + } + }); + } + } + } + } + return result; + })); + const internalTracks = []; + const addInternalTrack = (track) => { + const existingTrack = internalTracks.find((x) => x.fullPath === track.fullPath && x.info.type === track.info.type); + if (existingTrack) { + existingTrack.pairingMask |= track.pairingMask; + existingTrack.default || (existingTrack.default = track.default); + existingTrack.autoselect || (existingTrack.autoselect = track.autoselect); + existingTrack.lineNumber = Math.min(existingTrack.lineNumber, track.lineNumber); + if (track.peakBitrate !== null) { + existingTrack.peakBitrate = Math.max(existingTrack.peakBitrate ?? -Infinity, track.peakBitrate); + } + if (track.averageBitrate !== null) { + existingTrack.averageBitrate = Math.max(existingTrack.averageBitrate ?? -Infinity, track.averageBitrate); + } + if (existingTrack.languageCode === UNDETERMINED_LANGUAGE) { + existingTrack.languageCode = track.languageCode; + } + } else { + track.id = internalTracks.length + 1; + internalTracks.push(track); + } + }; + for (const variantInternalTracks of internalTracksByVariant) { + for (const trackEntry of variantInternalTracks) { + addInternalTrack(trackEntry); + } + } + internalTracks.sort((a, b) => a.lineNumber - b.lineNumber); + this.trackBackings = []; + for (const internalTrack of internalTracks) { + if (internalTrack.info.type === "video") { + this.trackBackings.push(new HlsInputVideoTrackBacking(internalTrack)); + } else { + this.trackBackings.push(new HlsInputAudioTrackBacking(internalTrack)); + } + } + this.internalTracks = internalTracks; + })()); + } + async getTrackBackings() { + await this.readMetadata(); + assert(this.trackBackings); + return this.trackBackings; + } + getSegmentedInputForPath(path) { + let segmentedInput = this.segmentedInputs.find((x) => x.path === path); + if (segmentedInput) { + return segmentedInput; + } + let decls = null; + if (this.internalTracks) { + const tracks = this.internalTracks.filter((x) => x.fullPath === path); + decls = tracks.map((x) => ({ + id: x.id, + type: x.info.type + })); + } + segmentedInput = new HlsSegmentedInput(this, path, decls, null); + this.segmentedInputs.push(segmentedInput); + return segmentedInput; + } + async getMetadataTags() { + return {}; + } + async getMimeType() { + return HLS_MIME_TYPE; + } + dispose() { + if (this.segmentedInputs) { + for (const segInput of this.segmentedInputs) { + segInput.dispose(); + } + this.segmentedInputs.length = 0; + } + } +} +class HlsInputTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.hydrationPromise = null; + } + hydrate() { + return this.hydrationPromise ?? (this.hydrationPromise = (async () => { + const segmentedInput = this.internalTrack.demuxer.getSegmentedInputForPath(this.internalTrack.fullPath); + let trackBacking = null; + const trackBackings = await segmentedInput.getTrackBackings(); + const matchingType = trackBackings.filter((x) => x.getType() === this.getType()); + if (matchingType.length === 1) { + trackBacking = matchingType[0]; + } else { + if (this instanceof HlsInputVideoTrackBacking) { + for (const backing of matchingType) { + if (await backing.getCodec() === this.getCodec()) { + trackBacking = backing; + break; + } + } + } else { + assert(this instanceof HlsInputAudioTrackBacking); + for (const backing of matchingType) { + if (await backing.getCodec() === this.getCodec()) { + trackBacking = backing; + break; + } + } + } + } + if (!trackBacking) { + throw new Error("Could not find matching track in underlying media data."); + } + this.internalTrack.backingTrack = trackBacking; + })()); + } + /** If the backing track is already present, delegate synchronously; otherwise, hydrate first. */ + delegate(fn) { + if (this.internalTrack.backingTrack) { + return fn(); + } + return this.hydrate().then(fn); + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + // Meanings are swapped in HLS: "Default" means that a track is the primary track. + default: this.internalTrack.autoselect, + primary: this.internalTrack.default + }; + } + getId() { + return this.internalTrack.id; + } + getPairingMask() { + return this.internalTrack.pairingMask; + } + getInternalCodecId() { + return null; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getName() { + return this.internalTrack.name; + } + getNumber() { + assert(this.internalTrack.demuxer.internalTracks); + const trackType = this.internalTrack.info.type; + let number = 0; + for (const track of this.internalTrack.demuxer.internalTracks) { + if (track.info.type === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + return number; + } + getTimeResolution() { + return this.delegate(() => this.internalTrack.backingTrack.getTimeResolution()); + } + isRelativeToUnixEpoch() { + return this.delegate(() => this.internalTrack.backingTrack.isRelativeToUnixEpoch()); + } + getBitrate() { + return this.internalTrack.peakBitrate; + } + getAverageBitrate() { + return this.internalTrack.averageBitrate; + } + async getDurationFromMetadata(options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getDurationFromMetadata(options); + } + async getLiveRefreshInterval() { + await this.hydrate(); + return this.internalTrack.backingTrack.getLiveRefreshInterval(); + } + getHasOnlyKeyPackets() { + return this.internalTrack.hasOnlyKeyPackets || null; + } + async getFirstPacket(options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getFirstPacket(options); + } + async getPacket(timestamp, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getPacket(timestamp, options); + } + async getKeyPacket(timestamp, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getKeyPacket(timestamp, options); + } + async getNextPacket(packet, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getNextPacket(packet, options); + } + async getNextKeyPacket(packet, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getNextKeyPacket(packet, options); + } +} +class HlsInputVideoTrackBacking extends HlsInputTrackBacking { + constructor(internalTrack) { + super(internalTrack); + } + get backingVideoTrack() { + return this.internalTrack.backingTrack; + } + getType() { + return "video"; + } + getCodec() { + const inferredCodec = inferCodecFromCodecString(this.internalTrack.fullCodecString); + return inferredCodec; + } + getCodedWidth() { + return this.delegate(() => this.backingVideoTrack.getCodedWidth()); + } + getCodedHeight() { + return this.delegate(() => this.backingVideoTrack.getCodedHeight()); + } + getSquarePixelWidth() { + return this.delegate(() => this.backingVideoTrack.getSquarePixelWidth()); + } + getSquarePixelHeight() { + return this.delegate(() => this.backingVideoTrack.getSquarePixelHeight()); + } + getMetadataDisplayWidth() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.info.width; + } + getMetadataDisplayHeight() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.info.height; + } + getRotation() { + return this.delegate(() => this.backingVideoTrack.getRotation()); + } + async getColorSpace() { + await this.hydrate(); + return this.backingVideoTrack.getColorSpace(); + } + async canBeTransparent() { + await this.hydrate(); + return this.backingVideoTrack.canBeTransparent(); + } + getMetadataCodecParameterString() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.fullCodecString; + } + async getDecoderConfig() { + await this.hydrate(); + return this.backingVideoTrack.getDecoderConfig(); + } +} +class HlsInputAudioTrackBacking extends HlsInputTrackBacking { + constructor(internalTrack) { + super(internalTrack); + } + get backingAudioTrack() { + return this.internalTrack.backingTrack; + } + getType() { + return "audio"; + } + getCodec() { + const inferredCodec = inferCodecFromCodecString(this.internalTrack.fullCodecString); + return inferredCodec; + } + getNumberOfChannels() { + if (this.internalTrack.info.numberOfChannels !== null) { + return this.internalTrack.info.numberOfChannels; + } + return this.delegate(() => this.backingAudioTrack.getNumberOfChannels()); + } + getSampleRate() { + return this.delegate(() => this.backingAudioTrack.getSampleRate()); + } + getMetadataCodecParameterString() { + if (this.backingAudioTrack) { + return null; + } + return this.internalTrack.fullCodecString; + } + async getDecoderConfig() { + await this.hydrate(); + return this.backingAudioTrack.getDecoderConfig(); + } +} +const getMediaTagDefault = (attributes) => { + const value = attributes.get("default"); + if (value === null) { + return false; + } + const normalized = value.toUpperCase(); + if (normalized === "YES") { + return true; + } + if (normalized === "NO") { + return false; + } + throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA DEFAULT attribute must be YES or NO, got "${value}".`); +}; +const getMediaTagAutoselect = (attributes) => { + const value = attributes.get("autoselect"); + if (value === null) { + return false; + } + const normalized = value.toUpperCase(); + if (normalized === "YES") { + return true; + } + if (normalized === "NO") { + return false; + } + throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA AUTOSELECT attribute must be YES or NO, got "${value}".`); +}; +const preprocessLanguageCode = (code) => { + if (code === null) { + return UNDETERMINED_LANGUAGE; + } + const languageSubtag = code.split("-")[0]; + if (!languageSubtag) { + return UNDETERMINED_LANGUAGE; + } + return languageSubtag; +}; +class InputFormat { + constructor() { + this._isIsobmff = false; + } +} +class IsobmffInputFormat extends InputFormat { + constructor() { + super(...arguments); + this._isIsobmff = true; + } + /** @internal */ + async _getMajorBrand(input) { + let slice = input._reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return null; + slice.skip(4); + const fourCc = readAscii(slice, 4); + if (fourCc !== "ftyp" && fourCc !== "styp") { + return null; + } + return readAscii(slice, 4); + } + /** @internal */ + _createDemuxer(input) { + return new IsobmffDemuxer(input); + } +} +class Mp4InputFormat extends IsobmffInputFormat { + /** @internal */ + async _canReadInput(input) { + const majorBrand = await this._getMajorBrand(input); + if (majorBrand !== null) { + return majorBrand !== "qt "; + } + let slice = input._reader.requestSlice(4, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "moof"; + } + get name() { + return "MP4"; + } + get mimeType() { + return "video/mp4"; + } +} +class QuickTimeInputFormat extends IsobmffInputFormat { + /** @internal */ + async _canReadInput(input) { + const majorBrand = await this._getMajorBrand(input); + return majorBrand === "qt "; + } + get name() { + return "QuickTime File Format"; + } + get mimeType() { + return "video/quicktime"; + } +} +class MatroskaInputFormat extends InputFormat { + /** @internal */ + async isSupportedEBMLOfDocType(input, desiredDocType) { + let headerSlice = input._reader.requestSlice(0, MAX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + return false; + const varIntSize = readVarIntSize(headerSlice); + if (varIntSize === null) { + return false; + } + if (varIntSize < 1 || varIntSize > 8) { + return false; + } + const id = readUnsignedInt(headerSlice, varIntSize); + if (id !== EBMLId.EBML) { + return false; + } + const dataSize = readElementSize(headerSlice); + if (typeof dataSize !== "number") { + return false; + } + let dataSlice = input._reader.requestSlice(headerSlice.filePos, dataSize); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (!dataSlice) + return false; + const startPos = headerSlice.filePos; + while (dataSlice.filePos <= startPos + dataSize - MIN_HEADER_SIZE) { + const header = readElementHeader(dataSlice); + if (!header) + break; + const { id: id2, size } = header; + const dataStartPos = dataSlice.filePos; + if (size === void 0) + return false; + switch (id2) { + case EBMLId.EBMLVersion: + { + const ebmlVersion = readUnsignedInt(dataSlice, size); + if (ebmlVersion !== 1) { + return false; + } + } + break; + case EBMLId.EBMLReadVersion: + { + const ebmlReadVersion = readUnsignedInt(dataSlice, size); + if (ebmlReadVersion !== 1) { + return false; + } + } + break; + case EBMLId.DocType: + { + const docType = readAsciiString(dataSlice, size); + if (docType !== desiredDocType) { + return false; + } + } + break; + case EBMLId.DocTypeVersion: + { + const docTypeVersion = readUnsignedInt(dataSlice, size); + if (docTypeVersion > 4) { + return false; + } + } + break; + } + dataSlice.filePos = dataStartPos + size; + } + return true; + } + /** @internal */ + _canReadInput(input) { + return this.isSupportedEBMLOfDocType(input, "matroska"); + } + /** @internal */ + _createDemuxer(input) { + return new MatroskaDemuxer(input); + } + get name() { + return "Matroska"; + } + get mimeType() { + return "video/x-matroska"; + } +} +class WebMInputFormat extends MatroskaInputFormat { + /** @internal */ + _canReadInput(input) { + return this.isSupportedEBMLOfDocType(input, "webm"); + } + get name() { + return "WebM"; + } + get mimeType() { + return "video/webm"; + } +} +class Mp3InputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let currentPos = 0; + while (true) { + let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + currentPos = slice2.filePos + id3V2Header.size; + } + const firstResult = await readNextMp3FrameHeader(input._reader, currentPos, currentPos + 4096); + if (!firstResult) { + return false; + } + const firstHeader = firstResult.header; + const xingOffset = getXingOffset(firstHeader.mpegVersionId, firstHeader.channel); + let slice = input._reader.requestSlice(firstResult.startPos + xingOffset, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const word = readU32Be(slice); + const isXing = word === XING || word === INFO; + if (isXing) { + return true; + } + currentPos = firstResult.startPos + firstResult.header.totalSize; + const secondResult = await readNextMp3FrameHeader(input._reader, currentPos, currentPos + FRAME_HEADER_SIZE); + if (!secondResult) { + return false; + } + const secondHeader = secondResult.header; + if (firstHeader.channel !== secondHeader.channel || firstHeader.sampleRate !== secondHeader.sampleRate) { + return false; + } + return true; + } + /** @internal */ + _createDemuxer(input) { + return new Mp3Demuxer(input); + } + get name() { + return "MP3"; + } + get mimeType() { + return "audio/mpeg"; + } +} +class WaveInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const riffType = readAscii(slice, 4); + if (riffType !== "RIFF" && riffType !== "RIFX" && riffType !== "RF64") { + return false; + } + slice.skip(4); + const format = readAscii(slice, 4); + return format === "WAVE"; + } + /** @internal */ + _createDemuxer(input) { + return new WaveDemuxer(input); + } + get name() { + return "WAVE"; + } + get mimeType() { + return "audio/wav"; + } +} +class OggInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "OggS"; + } + /** @internal */ + _createDemuxer(input) { + return new OggDemuxer(input); + } + get name() { + return "Ogg"; + } + get mimeType() { + return "application/ogg"; + } +} +class FlacInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "fLaC"; + } + get name() { + return "FLAC"; + } + get mimeType() { + return "audio/flac"; + } + /** @internal */ + _createDemuxer(input) { + return new FlacDemuxer(input); + } +} +class AdtsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let currentPos = 0; + while (true) { + let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + currentPos = slice2.filePos + id3V2Header.size; + } + let slice = input._reader.requestSliceRange(currentPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const firstHeader = readAdtsFrameHeader(slice); + if (!firstHeader) { + return false; + } + currentPos += firstHeader.frameLength; + slice = input._reader.requestSliceRange(currentPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const secondHeader = readAdtsFrameHeader(slice); + if (!secondHeader) { + return false; + } + return firstHeader.objectType === secondHeader.objectType && firstHeader.samplingFrequencyIndex === secondHeader.samplingFrequencyIndex && firstHeader.channelConfiguration === secondHeader.channelConfiguration; + } + /** @internal */ + _createDemuxer(input) { + return new AdtsDemuxer(input); + } + get name() { + return "ADTS"; + } + get mimeType() { + return "audio/aac"; + } +} +class MpegTsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + const lengthToCheck = TS_PACKET_SIZE + 16 + 1; + let slice = input._reader.requestSlice(0, lengthToCheck); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const bytes = readBytes(slice, lengthToCheck); + if (bytes[0] === 71 && bytes[TS_PACKET_SIZE] === 71) { + return true; + } else if (bytes[0] === 71 && bytes[TS_PACKET_SIZE + 16] === 71) { + return true; + } else if (bytes[4] === 71 && bytes[4 + TS_PACKET_SIZE + 4] === 71) { + return true; + } + return false; + } + /** @internal */ + _createDemuxer(input) { + return new MpegTsDemuxer(input); + } + get name() { + return "MPEG Transport Stream"; + } + get mimeType() { + return "video/MP2T"; + } +} +class HlsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 7); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const isM3u8 = readAscii(slice, 7) === "#EXTM3U"; + if (!isM3u8) { + return false; + } + if (!(input._rootSource instanceof PathedSource)) { + throw new TypeError("HLS inputs require `InputOptions.source` to be a PathedSource or a ref to one."); + } + input._rootSource._usedForHls = true; + return true; + } + /** @internal */ + _createDemuxer(input) { + return new HlsDemuxer(input); + } + get name() { + return "HTTP Live Streaming (HLS)"; + } + get mimeType() { + return HLS_MIME_TYPE; + } +} +const MP4 = /* @__PURE__ */ new Mp4InputFormat(); +const QTFF = /* @__PURE__ */ new QuickTimeInputFormat(); +const MATROSKA = /* @__PURE__ */ new MatroskaInputFormat(); +const WEBM = /* @__PURE__ */ new WebMInputFormat(); +const MP3 = /* @__PURE__ */ new Mp3InputFormat(); +const WAVE = /* @__PURE__ */ new WaveInputFormat(); +const OGG = /* @__PURE__ */ new OggInputFormat(); +const ADTS = /* @__PURE__ */ new AdtsInputFormat(); +const FLAC = /* @__PURE__ */ new FlacInputFormat(); +const MPEG_TS = /* @__PURE__ */ new MpegTsInputFormat(); +const HLS = /* @__PURE__ */ new HlsInputFormat(); +const ALL_FORMATS = [HLS, MP4, QTFF, MATROSKA, WEBM, WAVE, OGG, FLAC, MP3, ADTS, MPEG_TS]; +const HLS_FORMATS = [HLS, MP4, QTFF, MP3, ADTS, MPEG_TS]; +const validateInputFormatOptions = (options, prefix) => { + if (!options || typeof options !== "object") { + throw new TypeError(`${prefix}, when provided, must be an object.`); + } + if (options.isobmff !== void 0) { + if (!options.isobmff || typeof options.isobmff !== "object") { + throw new TypeError(`${prefix}.isobmff, when provided, must be an object.`); + } + if (options.isobmff.resolveKeyId !== void 0 && typeof options.isobmff.resolveKeyId !== "function") { + throw new TypeError(`${prefix}.isobmff.resolveKeyId, when provided, must be a function.`); + } } - return sign === 0 ? decoded : -decoded; }; polyfillSymbolDispose(); let lastVideoGcErrorLog = -Infinity; @@ -2373,7 +16243,7 @@ let lastAudioGcErrorLog = -Infinity; let finalizationRegistry = null; if (typeof FinalizationRegistry !== "undefined") { finalizationRegistry = new FinalizationRegistry((value) => { - const now = Date.now(); + const now = performance.now(); if (value.type === "video") { if (now - lastVideoGcErrorLog >= 1e3) { console.error(`A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them.`); @@ -2431,13 +16301,21 @@ const VIDEO_SAMPLE_PIXEL_FORMATS = [ ]; const VIDEO_SAMPLE_PIXEL_FORMATS_SET = new Set(VIDEO_SAMPLE_PIXEL_FORMATS); class VideoSample { - /** The width of the frame in pixels after rotation. */ - get displayWidth() { - return this.rotation % 180 === 0 ? this.codedWidth : this.codedHeight; + /** The width of the frame in pixels. */ + get codedWidth() { + return this.visibleRect.width; } - /** The height of the frame in pixels after rotation. */ + /** The height of the frame in pixels. */ + get codedHeight() { + return this.visibleRect.height; + } + /** The display width of the frame in pixels, after aspect ratio adjustment and rotation. */ + get displayWidth() { + return this.rotation % 180 === 0 ? this.squarePixelWidth : this.squarePixelHeight; + } + /** The display height of the frame in pixels, after aspect ratio adjustment and rotation. */ get displayHeight() { - return this.rotation % 180 === 0 ? this.codedHeight : this.codedWidth; + return this.rotation % 180 === 0 ? this.squarePixelHeight : this.squarePixelWidth; } /** The presentation timestamp of the frame in microseconds. */ get microsecondTimestamp() { @@ -2478,15 +16356,54 @@ class VideoSample { if (init.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { throw new TypeError("init.duration, when provided, must be a non-negative number."); } + if (init.layout !== void 0) { + if (!Array.isArray(init.layout)) { + throw new TypeError("init.layout, when provided, must be an array."); + } + for (const plane of init.layout) { + if (!plane || typeof plane !== "object" || Array.isArray(plane)) { + throw new TypeError("Each entry in init.layout must be an object."); + } + if (!Number.isInteger(plane.offset) || plane.offset < 0) { + throw new TypeError("plane.offset must be a non-negative integer."); + } + if (!Number.isInteger(plane.stride) || plane.stride < 0) { + throw new TypeError("plane.stride must be a non-negative integer."); + } + } + } + if (init.visibleRect !== void 0) { + validateRectangle(init.visibleRect, "init.visibleRect"); + } + if (init.displayWidth !== void 0 && (!Number.isInteger(init.displayWidth) || init.displayWidth <= 0)) { + throw new TypeError("init.displayWidth, when provided, must be a positive integer."); + } + if (init.displayHeight !== void 0 && (!Number.isInteger(init.displayHeight) || init.displayHeight <= 0)) { + throw new TypeError("init.displayHeight, when provided, must be a positive integer."); + } + if (init.displayWidth !== void 0 !== (init.displayHeight !== void 0)) { + throw new TypeError("init.displayWidth and init.displayHeight must be either both provided or both omitted."); + } this._data = toUint8Array(data).slice(); this._layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight); this.format = init.format; - this.codedWidth = init.codedWidth; - this.codedHeight = init.codedHeight; this.rotation = init.rotation ?? 0; this.timestamp = init.timestamp; this.duration = init.duration ?? 0; this.colorSpace = new VideoSampleColorSpace(init.colorSpace); + this.visibleRect = { + left: init.visibleRect?.left ?? 0, + top: init.visibleRect?.top ?? 0, + width: init.visibleRect?.width ?? init.codedWidth, + height: init.visibleRect?.height ?? init.codedHeight + }; + if (init.displayWidth !== void 0) { + this.squarePixelWidth = this.rotation % 180 === 0 ? init.displayWidth : init.displayHeight; + this.squarePixelHeight = this.rotation % 180 === 0 ? init.displayHeight : init.displayWidth; + } else { + this.squarePixelWidth = this.codedWidth; + this.squarePixelHeight = this.codedHeight; + } } else if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) { if (init?.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) { throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270."); @@ -2497,12 +16414,21 @@ class VideoSample { if (init?.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { throw new TypeError("init.duration, when provided, must be a non-negative number."); } + if (init?.visibleRect !== void 0) { + validateRectangle(init.visibleRect, "init.visibleRect"); + } this._data = data; this._layout = null; this.format = data.format; - this.codedWidth = data.displayWidth; - this.codedHeight = data.displayHeight; + this.visibleRect = { + left: data.visibleRect?.x ?? 0, + top: data.visibleRect?.y ?? 0, + width: data.visibleRect?.width ?? data.codedWidth, + height: data.visibleRect?.height ?? data.codedHeight + }; this.rotation = init?.rotation ?? 0; + this.squarePixelWidth = data.displayWidth; + this.squarePixelHeight = data.displayHeight; this.timestamp = init?.timestamp ?? data.timestamp / 1e6; this.duration = init?.duration ?? (data.duration ?? 0) / 1e6; this.colorSpace = new VideoSampleColorSpace(data.colorSpace); @@ -2552,8 +16478,9 @@ class VideoSample { this._data = canvas; this._layout = null; this.format = "RGBX"; - this.codedWidth = width; - this.codedHeight = height; + this.visibleRect = { left: 0, top: 0, width, height }; + this.squarePixelWidth = width; + this.squarePixelHeight = height; this.rotation = init.rotation ?? 0; this.timestamp = init.timestamp; this.duration = init.duration ?? 0; @@ -2566,6 +16493,10 @@ class VideoSample { } else { throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource."); } + this.pixelAspectRatio = simplifyRational({ + num: this.squarePixelWidth * this.codedHeight, + den: this.squarePixelHeight * this.codedWidth + }); finalizationRegistry?.register(this, { type: "video", data: this._data }, this); } /** Clones this video sample. */ @@ -2590,7 +16521,10 @@ class VideoSample { timestamp: this.timestamp, duration: this.duration, colorSpace: this.colorSpace, - rotation: this.rotation + rotation: this.rotation, + visibleRect: this.visibleRect, + displayWidth: this.displayWidth, + displayHeight: this.displayHeight }); } else { return new VideoSample(this._data, { @@ -2600,7 +16534,10 @@ class VideoSample { timestamp: this.timestamp, duration: this.duration, colorSpace: this.colorSpace, - rotation: this.rotation + rotation: this.rotation, + visibleRect: this.visibleRect, + displayWidth: this.displayWidth, + displayHeight: this.displayHeight }); } } @@ -2818,7 +16755,7 @@ class VideoSample { const canvasWidth = context.canvas.width; const canvasHeight = context.canvas.height; const rotation = options.rotation ?? this.rotation; - const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [this.codedWidth, this.codedHeight] : [this.codedHeight, this.codedWidth]; + const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [this.squarePixelWidth, this.squarePixelHeight] : [this.squarePixelHeight, this.squarePixelWidth]; if (options.crop) { clampCropRectangle(options.crop, rotatedWidth, rotatedHeight); } @@ -2854,18 +16791,18 @@ class VideoSample { if (rotation === 90) { [sx, sy, sWidth, sHeight] = [ sy, - this.codedHeight - sx - sWidth, + this.squarePixelHeight - sx - sWidth, sHeight, sWidth ]; } else if (rotation === 180) { [sx, sy] = [ - this.codedWidth - sx - sWidth, - this.codedHeight - sy - sHeight + this.squarePixelWidth - sx - sWidth, + this.squarePixelHeight - sy - sHeight ]; } else if (rotation === 270) { [sx, sy, sWidth, sHeight] = [ - this.codedWidth - sy - sHeight, + this.squarePixelWidth - sy - sHeight, sx, sHeight, sWidth @@ -2922,6 +16859,26 @@ class VideoSample { class VideoSampleColorSpace { /** Creates a new VideoSampleColorSpace. */ constructor(init) { + if (init !== void 0) { + if (!init || typeof init !== "object") { + throw new TypeError("init.colorSpace, when provided, must be an object."); + } + const primariesValues = Object.keys(COLOR_PRIMARIES_MAP); + if (init.primaries != null && !primariesValues.includes(init.primaries)) { + throw new TypeError(`init.colorSpace.primaries, when provided, must be one of ${primariesValues.join(", ")}.`); + } + const transferValues = Object.keys(TRANSFER_CHARACTERISTICS_MAP); + if (init.transfer != null && !transferValues.includes(init.transfer)) { + throw new TypeError(`init.colorSpace.transfer, when provided, must be one of ${transferValues.join(", ")}.`); + } + const matrixValues = Object.keys(MATRIX_COEFFICIENTS_MAP); + if (init.matrix != null && !matrixValues.includes(init.matrix)) { + throw new TypeError(`init.colorSpace.matrix, when provided, must be one of ${matrixValues.join(", ")}.`); + } + if (init.fullRange != null && typeof init.fullRange !== "boolean") { + throw new TypeError("init.colorSpace.fullRange, when provided, must be a boolean."); + } + } this.primaries = init?.primaries ?? null; this.transfer = init?.transfer ?? null; this.matrix = init?.matrix ?? null; @@ -2941,12 +16898,13 @@ const isVideoFrame = (x) => { return typeof VideoFrame !== "undefined" && x instanceof VideoFrame; }; const clampCropRectangle = (crop, outerWidth, outerHeight) => { - crop.left = Math.min(crop.left, outerWidth); - crop.top = Math.min(crop.top, outerHeight); - crop.width = Math.min(crop.width, outerWidth - crop.left); - crop.height = Math.min(crop.height, outerHeight - crop.top); - assert(crop.width >= 0); - assert(crop.height >= 0); + const left = Math.min(crop.left, outerWidth); + const top = Math.min(crop.top, outerHeight); + const width = Math.min(crop.width, outerWidth - left); + const height = Math.min(crop.height, outerHeight - top); + assert(width >= 0); + assert(height >= 0); + return { left, top, width, height }; }; const validateCropRectangle = (crop, prefix) => { if (!crop || typeof crop !== "object") { @@ -3620,6 +17578,38 @@ const doAudioDataCopyToWebKitWorkaround = (audioData, destView, srcFormat, destF } } }; +const customVideoDecoders = []; +const customAudioDecoders = []; +const fromUlaw = (u8) => { + const MULAW_BIAS = 33; + let sign = 0; + let position = 0; + let number = ~u8; + if (number & 128) { + number &= -129; + sign = -1; + } + position = ((number & 240) >> 4) + 5; + const decoded = (1 << position | (number & 15) << position - 4 | 1 << position - 5) - MULAW_BIAS; + return sign === 0 ? decoded : -decoded; +}; +const fromAlaw = (u8) => { + let sign = 0; + let position = 0; + let number = u8 ^ 85; + if (number & 128) { + number &= -129; + sign = -1; + } + position = ((number & 240) >> 4) + 4; + let decoded = 0; + if (position !== 4) { + decoded = 1 << position | (number & 15) << position - 4 | 1 << position - 5; + } else { + decoded = number << 1 | 1; + } + return sign === 0 ? decoded : -decoded; +}; const validatePacketRetrievalOptions = (options) => { if (!options || typeof options !== "object") { throw new TypeError("options must be an object."); @@ -3633,6 +17623,9 @@ const validatePacketRetrievalOptions = (options) => { if (options.verifyKeyPackets && options.metadataOnly) { throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together."); } + if (options.skipLiveWait !== void 0 && typeof options.skipLiveWait !== "boolean") { + throw new TypeError("options.skipLiveWait, when defined, must be a boolean."); + } }; const validateTimestamp = (timestamp) => { if (!isNumber(timestamp)) { @@ -3665,15 +17658,27 @@ class EncodedPacketSink { } /** * Retrieves the track's first packet (in decode order), or null if it has no packets. The first packet is very - * likely to be a key packet. + * likely to be a key packet, but it doesn't have to be. */ - getFirstPacket(options = {}) { + async getFirstPacket(options = {}) { validatePacketRetrievalOptions(options); if (this._track.input._disposed) { throw new InputDisposedError(); } return maybeFixPacketType(this._track, this._track._backing.getFirstPacket(options), options); } + /** Retrieves the track's first key packet (in decode order), or null if it has no key packets. */ + async getFirstKeyPacket(options = {}) { + validatePacketRetrievalOptions(options); + const firstPacket = await this.getFirstPacket(options); + if (!firstPacket) { + return null; + } + if (firstPacket.type === "key") { + return firstPacket; + } + return this.getNextKeyPacket(firstPacket, options); + } /** * Retrieves the packet corresponding to the given timestamp, in seconds. More specifically, returns the last packet * (in presentation order) with a start timestamp less than or equal to the given timestamp. This method can be @@ -3682,7 +17687,7 @@ class EncodedPacketSink { * * @param timestamp - The timestamp used for retrieval, in seconds. */ - getPacket(timestamp, options = {}) { + async getPacket(timestamp, options = {}) { validateTimestamp(timestamp); validatePacketRetrievalOptions(options); if (this._track.input._disposed) { @@ -3694,7 +17699,7 @@ class EncodedPacketSink { * Retrieves the packet following the given packet (in decode order), or null if the given packet is the * last packet. */ - getNextPacket(packet, options = {}) { + async getNextPacket(packet, options = {}) { if (!(packet instanceof EncodedPacket)) { throw new TypeError("packet must be an EncodedPacket."); } @@ -3731,7 +17736,7 @@ class EncodedPacketSink { assert(packet.type === "key"); const determinedType = await this._track.determinePacketType(packet); if (determinedType === "delta") { - return this.getKeyPacket(packet.timestamp - 1 / this._track.timeResolution, options); + return this.getKeyPacket(packet.timestamp - 1 / await this._track.getTimeResolution(), options); } return packet; } @@ -3768,7 +17773,7 @@ class EncodedPacketSink { * method will intelligently preload packets based on the speed of the consumer. * * @param startPacket - (optional) The packet from which iteration should begin. This packet will also be yielded. - * @param endTimestamp - (optional) The timestamp at which iteration should end. This packet will _not_ be yielded. + * @param endPacket - (optional) The packet at which iteration should end. This packet will _not_ be yielded. */ packets(startPacket, endPacket, options = {}) { if (startPacket !== void 0 && !(startPacket instanceof EncodedPacket)) { @@ -3865,7 +17870,7 @@ class DecoderWrapper { } class BaseMediaSampleSink { /** @internal */ - mediaSamplesInRange(startTimestamp = 0, endTimestamp = Infinity) { + mediaSamplesInRange(startTimestamp = 0, endTimestamp = Infinity, options) { validateTimestamp(startTimestamp); validateTimestamp(endTimestamp); const sampleQueue = []; @@ -3877,6 +17882,11 @@ class BaseMediaSampleSink { let ended = false; let terminated = false; let outOfBandError = null; + const packetRetrievalOptions = { + ...options, + verifyKeyPackets: true, + metadataOnly: false + }; (async () => { const decoder = await this._createDecoder((sample) => { onQueueDequeue(); @@ -3911,10 +17921,10 @@ class BaseMediaSampleSink { } }); const packetSink = this._createPacketSink(); - const keyPacket = await packetSink.getKeyPacket(startTimestamp, { verifyKeyPackets: true }) ?? await packetSink.getFirstPacket(); + const keyPacket = await packetSink.getKeyPacket(startTimestamp, packetRetrievalOptions) ?? await packetSink.getFirstKeyPacket(packetRetrievalOptions); let currentPacket = keyPacket; const endPacket = void 0; - const packets = packetSink.packets(keyPacket ?? void 0, endPacket); + const packets = packetSink.packets(keyPacket ?? void 0, endPacket, packetRetrievalOptions); await packets.next(); while (currentPacket && !ended && !this._track.input._disposed) { const maxQueueSize = computeMaxQueueSize(sampleQueue.length); @@ -3992,7 +18002,7 @@ class BaseMediaSampleSink { }; } /** @internal */ - mediaSamplesAtTimestamps(timestamps) { + mediaSamplesAtTimestamps(timestamps, options) { validateAnyIterable(timestamps); const timestampIterator = toAsyncIterator(timestamps); const timestampsOfInterest = []; @@ -4007,6 +18017,11 @@ class BaseMediaSampleSink { onQueueNotEmpty(); ({ promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers()); }; + const retrievalOptions = { + ...options, + verifyKeyPackets: true, + metadataOnly: false + }; (async () => { const decoder = await this._createDecoder((sample) => { onQueueDequeue(); @@ -4049,7 +18064,7 @@ class BaseMediaSampleSink { if (terminated) { break; } - const nextPacket = await packetSink.getNextPacket(currentPacket); + const nextPacket = await packetSink.getNextPacket(currentPacket, retrievalOptions); assert(nextPacket); decoder.decode(nextPacket); currentPacket = nextPacket; @@ -4068,8 +18083,8 @@ class BaseMediaSampleSink { if (terminated || this._track.input._disposed) { break; } - const targetPacket = await packetSink.getPacket(timestamp); - const keyPacket = targetPacket && await packetSink.getKeyPacket(timestamp, { verifyKeyPackets: true }); + const targetPacket = await packetSink.getPacket(timestamp, retrievalOptions); + const keyPacket = targetPacket && await packetSink.getKeyPacket(timestamp, retrievalOptions); if (!keyPacket) { if (maxSequenceNumber !== -1) { await decodePackets(); @@ -4251,14 +18266,23 @@ class VideoDecoderWrapper extends DecoderWrapper { if (!isWebKit()) { insertSorted(this.inputTimestamps, packet.timestamp, (x) => x); } - if (isChromium() && this.currentPacketIndex === 0 && this.codec === "avc") { - const nalUnits = extractAvcNalUnits(packet.data, this.decoderConfig); - const filteredNalUnits = nalUnits.filter((x) => { - const type = extractNalUnitTypeForAvc(x); - return !(type >= 20 && type <= 31); - }); - const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig); - packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration); + if (isChromium() && this.currentPacketIndex === 0) { + if (this.codec === "avc") { + const filteredNalUnits = []; + for (const loc of iterateAvcNalUnits(packet.data, this.decoderConfig)) { + const type = extractNalUnitTypeForAvc(packet.data[loc.offset]); + if (!(type >= 20 && type <= 31)) { + filteredNalUnits.push(packet.data.subarray(loc.offset, loc.offset + loc.length)); + } + } + const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig); + packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration); + } else if (this.codec === "hevc") { + const sanitizedData = sanitizeHevcPacketForChromium(packet.data, this.decoderConfig); + if (sanitizedData) { + packet = new EncodedPacket(sanitizedData, packet.type, packet.timestamp, packet.duration); + } + } } this.decoder.decode(packet.toEncodedVideoChunk()); this.decodeAlphaData(packet); @@ -4351,11 +18375,13 @@ class VideoDecoderWrapper extends DecoderWrapper { * and causes bugs upstream. So, let's take the dropping into our own hands. */ hasHevcRaslPicture(packetData) { - const nalUnits = extractHevcNalUnits(packetData, this.decoderConfig); - return nalUnits.some((x) => { - const type = extractNalUnitTypeForHevc(x); - return type === HevcNalUnitType.RASL_N || type === HevcNalUnitType.RASL_R; - }); + for (const loc of iterateHevcNalUnits(packetData, this.decoderConfig)) { + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (type === HevcNalUnitType.RASL_N || type === HevcNalUnitType.RASL_R) { + return true; + } + } + return false; } /** Handler for the WebCodecs VideoDecoder for ironing out browser differences. */ sampleHandler(sample) { @@ -4580,10 +18606,10 @@ class VideoSampleSink extends BaseMediaSampleSink { if (!await this._track.canDecode()) { throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track."); } - const codec = this._track.codec; - const rotation = this._track.rotation; + const codec = await this._track.getCodec(); + const rotation = await this._track.getRotation(); const decoderConfig = await this._track.getDecoderConfig(); - const timeResolution = this._track.timeResolution; + const timeResolution = await this._track.getTimeResolution(); assert(codec && decoderConfig); return new VideoDecoderWrapper(onSample, onError, codec, decoderConfig, rotation, timeResolution); } @@ -4597,10 +18623,11 @@ class VideoSampleSink extends BaseMediaSampleSink { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getSample(timestamp) { + async getSample(timestamp, options = {}) { validateTimestamp(timestamp); - for await (const sample of this.mediaSamplesAtTimestamps([timestamp])) { + for await (const sample of this.mediaSamplesAtTimestamps([timestamp], options)) { return sample; } throw new Error("Internal error: Iterator returned nothing."); @@ -4611,9 +18638,10 @@ class VideoSampleSink extends BaseMediaSampleSink { * * @param startTimestamp - The timestamp in seconds at which to start yielding samples (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding samples (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - samples(startTimestamp = 0, endTimestamp = Infinity) { - return this.mediaSamplesInRange(startTimestamp, endTimestamp); + samples(startTimestamp = 0, endTimestamp = Infinity, options = {}) { + return this.mediaSamplesInRange(startTimestamp, endTimestamp, options); } /** * Creates an async iterator that yields a video sample (frame) for each timestamp in the argument. This method @@ -4622,14 +18650,17 @@ class VideoSampleSink extends BaseMediaSampleSink { * yield null if no frame is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - samplesAtTimestamps(timestamps) { - return this.mediaSamplesAtTimestamps(timestamps); + samplesAtTimestamps(timestamps, options = {}) { + return this.mediaSamplesAtTimestamps(timestamps, options); } } class CanvasSink { /** Creates a new {@link CanvasSink} for the given {@link InputVideoTrack}. */ constructor(videoTrack, options = {}) { + this._rotation = 0; + this._initPromise = null; this._nextCanvasIndex = 0; if (!(videoTrack instanceof InputVideoTrack)) { throw new TypeError("videoTrack must be an InputVideoTrack."); @@ -4661,45 +18692,57 @@ class CanvasSink { if (options.poolSize !== void 0 && (typeof options.poolSize !== "number" || !Number.isInteger(options.poolSize) || options.poolSize < 0)) { throw new TypeError("poolSize must be a non-negative integer."); } - const rotation = options.rotation ?? videoTrack.rotation; - const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [videoTrack.codedWidth, videoTrack.codedHeight] : [videoTrack.codedHeight, videoTrack.codedWidth]; - const crop = options.crop; - if (crop) { - clampCropRectangle(crop, rotatedWidth, rotatedHeight); - } - let [width, height] = crop ? [crop.width, crop.height] : [rotatedWidth, rotatedHeight]; - const originalAspectRatio = width / height; - if (options.width !== void 0 && options.height === void 0) { - width = options.width; - height = Math.round(width / originalAspectRatio); - } else if (options.width === void 0 && options.height !== void 0) { - height = options.height; - width = Math.round(height * originalAspectRatio); - } else if (options.width !== void 0 && options.height !== void 0) { - width = options.width; - height = options.height; - } this._videoTrack = videoTrack; this._alpha = options.alpha ?? false; - this._width = width; - this._height = height; - this._rotation = rotation; - this._crop = crop; + this._options = options; this._fit = options.fit ?? "fill"; this._videoSampleSink = new VideoSampleSink(videoTrack); this._canvasPool = Array.from({ length: options.poolSize ?? 0 }, () => null); } /** @internal */ + _ensureInit() { + return this._initPromise ?? (this._initPromise = (async () => { + const options = this._options; + const videoTrack = this._videoTrack; + const rotation = options.rotation ?? await videoTrack.getRotation(); + const squarePixelWidth = await videoTrack.getSquarePixelWidth(); + const squarePixelHeight = await videoTrack.getSquarePixelHeight(); + const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [squarePixelWidth, squarePixelHeight] : [squarePixelHeight, squarePixelWidth]; + let crop = options.crop; + if (crop) { + crop = clampCropRectangle(crop, rotatedWidth, rotatedHeight); + } + let [width, height] = crop ? [crop.width, crop.height] : [rotatedWidth, rotatedHeight]; + const originalAspectRatio = width / height; + if (options.width !== void 0 && options.height === void 0) { + width = options.width; + height = Math.round(width / originalAspectRatio); + } else if (options.width === void 0 && options.height !== void 0) { + height = options.height; + width = Math.round(height * originalAspectRatio); + } else if (options.width !== void 0 && options.height !== void 0) { + width = options.width; + height = options.height; + } + this._width = width; + this._height = height; + this._rotation = rotation; + this._crop = crop; + })()); + } + /** @internal */ _videoSampleToWrappedCanvas(sample) { + const width = this._width; + const height = this._height; let canvas = this._canvasPool[this._nextCanvasIndex]; let canvasIsNew = false; if (!canvas) { if (typeof document !== "undefined") { canvas = document.createElement("canvas"); - canvas.width = this._width; - canvas.height = this._height; + canvas.width = width; + canvas.height = height; } else { - canvas = new OffscreenCanvas(this._width, this._height); + canvas = new OffscreenCanvas(width, height); } if (this._canvasPool.length > 0) { this._canvasPool[this._nextCanvasIndex] = canvas; @@ -4718,9 +18761,9 @@ class CanvasSink { if (!canvasIsNew) { if (!this._alpha && isFirefox()) { context.fillStyle = "black"; - context.fillRect(0, 0, this._width, this._height); + context.fillRect(0, 0, width, height); } else { - context.clearRect(0, 0, this._width, this._height); + context.clearRect(0, 0, width, height); } } sample.drawWithFit(context, { @@ -4742,10 +18785,12 @@ class CanvasSink { * timestamp. Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getCanvas(timestamp) { + async getCanvas(timestamp, options) { validateTimestamp(timestamp); - const sample = await this._videoSampleSink.getSample(timestamp); + await this._ensureInit(); + const sample = await this._videoSampleSink.getSample(timestamp, options); return sample && this._videoSampleToWrappedCanvas(sample); } /** @@ -4754,9 +18799,11 @@ class CanvasSink { * * @param startTimestamp - The timestamp in seconds at which to start yielding canvases (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding canvases (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - canvases(startTimestamp = 0, endTimestamp = Infinity) { - return mapAsyncGenerator(this._videoSampleSink.samples(startTimestamp, endTimestamp), (sample) => this._videoSampleToWrappedCanvas(sample)); + async *canvases(startTimestamp = 0, endTimestamp = Infinity, options) { + await this._ensureInit(); + yield* mapAsyncGenerator(this._videoSampleSink.samples(startTimestamp, endTimestamp, options), (sample) => this._videoSampleToWrappedCanvas(sample)); } /** * Creates an async iterator that yields a canvas for each timestamp in the argument. This method uses an optimized @@ -4765,9 +18812,11 @@ class CanvasSink { * no frame is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - canvasesAtTimestamps(timestamps) { - return mapAsyncGenerator(this._videoSampleSink.samplesAtTimestamps(timestamps), (sample) => sample && this._videoSampleToWrappedCanvas(sample)); + async *canvasesAtTimestamps(timestamps, options) { + await this._ensureInit(); + yield* mapAsyncGenerator(this._videoSampleSink.samplesAtTimestamps(timestamps, options), (sample) => sample && this._videoSampleToWrappedCanvas(sample)); } } class AudioDecoderWrapper extends DecoderWrapper { @@ -5033,7 +19082,7 @@ class AudioSampleSink extends BaseMediaSampleSink { if (!await this._track.canDecode()) { throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track."); } - const codec = this._track.codec; + const codec = await this._track.getCodec(); const decoderConfig = await this._track.getDecoderConfig(); assert(codec && decoderConfig); if (PCM_AUDIO_CODECS.includes(decoderConfig.codec)) { @@ -5052,10 +19101,11 @@ class AudioSampleSink extends BaseMediaSampleSink { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getSample(timestamp) { + async getSample(timestamp, options = {}) { validateTimestamp(timestamp); - for await (const sample of this.mediaSamplesAtTimestamps([timestamp])) { + for await (const sample of this.mediaSamplesAtTimestamps([timestamp], options)) { return sample; } throw new Error("Internal error: Iterator returned nothing."); @@ -5066,9 +19116,10 @@ class AudioSampleSink extends BaseMediaSampleSink { * * @param startTimestamp - The timestamp in seconds at which to start yielding samples (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding samples (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - samples(startTimestamp = 0, endTimestamp = Infinity) { - return this.mediaSamplesInRange(startTimestamp, endTimestamp); + samples(startTimestamp = 0, endTimestamp = Infinity, options = {}) { + return this.mediaSamplesInRange(startTimestamp, endTimestamp, options); } /** * Creates an async iterator that yields an audio sample for each timestamp in the argument. This method @@ -5077,9 +19128,10 @@ class AudioSampleSink extends BaseMediaSampleSink { * yield null if no sample is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - samplesAtTimestamps(timestamps) { - return this.mediaSamplesAtTimestamps(timestamps); + samplesAtTimestamps(timestamps, options = {}) { + return this.mediaSamplesAtTimestamps(timestamps, options); } } class AudioBufferSink { @@ -5106,10 +19158,11 @@ class AudioBufferSink { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getBuffer(timestamp) { + async getBuffer(timestamp, options) { validateTimestamp(timestamp); - const data = await this._audioSampleSink.getSample(timestamp); + const data = await this._audioSampleSink.getSample(timestamp, options); return data && this._audioSampleToWrappedArrayBuffer(data); } /** @@ -5118,9 +19171,10 @@ class AudioBufferSink { * * @param startTimestamp - The timestamp in seconds at which to start yielding buffers (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding buffers (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - buffers(startTimestamp = 0, endTimestamp = Infinity) { - return mapAsyncGenerator(this._audioSampleSink.samples(startTimestamp, endTimestamp), (data) => this._audioSampleToWrappedArrayBuffer(data)); + buffers(startTimestamp = 0, endTimestamp = Infinity, options) { + return mapAsyncGenerator(this._audioSampleSink.samples(startTimestamp, endTimestamp, options), (data) => this._audioSampleToWrappedArrayBuffer(data)); } /** * Creates an async iterator that yields an audio buffer for each timestamp in the argument. This method @@ -5129,9 +19183,10 @@ class AudioBufferSink { * yield null if no buffer is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - buffersAtTimestamps(timestamps) { - return mapAsyncGenerator(this._audioSampleSink.samplesAtTimestamps(timestamps), (data) => data && this._audioSampleToWrappedArrayBuffer(data)); + buffersAtTimestamps(timestamps, options) { + return mapAsyncGenerator(this._audioSampleSink.samplesAtTimestamps(timestamps, options), (data) => data && this._audioSampleToWrappedArrayBuffer(data)); } } class InputTrack { @@ -5153,52 +19208,141 @@ class InputTrack { return this._backing.getId(); } /** - * The identifier of the codec used internally by the container. It is not homogenized by Mediabunny + * The 1-based index of this track among all tracks of the same type in the input file. For example, the first + * video track has number 1, the second video track has number 2, and so on. The index refers to the order in + * which the tracks are returned by {@link Input.getTracks}. + */ + get number() { + return this._backing.getNumber(); + } + /** + * Returns the identifier of the codec used internally by the container. It is not homogenized by Mediabunny * and depends entirely on the container format. * - * This field can be used to determine the codec of a track in case Mediabunny doesn't know that codec. + * This method can be used to determine the codec of a track in case Mediabunny doesn't know that codec. * - * - For ISOBMFF files, this field returns the name of the Sample Description Box (e.g. `'avc1'`). - * - For Matroska files, this field returns the value of the `CodecID` element. - * - For WAVE files, this field returns the value of the format tag in the `'fmt '` chunk. - * - For ADTS files, this field contains the `MPEG-4 Audio Object Type`. - * - In all other cases, this field is `null`. + * - For ISOBMFF files, this resolves to the name of the Sample Description Box (e.g. `'avc1'`). + * - For Matroska files, this resolves to the value of the `CodecID` element. + * - For WAVE files, this resolves to the value of the format tag in the `'fmt '` chunk. + * - For ADTS files, this resolves to the `MPEG-4 Audio Object Type`. + * - For MPEG-TS files, this resolves to the `streamType` value from the Program Map Table. + * - In all other cases, this resolves to `null`. */ - get internalCodecId() { + async getInternalCodecId() { return this._backing.getInternalCodecId(); } /** - * The ISO 639-2/T language code for this track. If the language is unknown, this field is `'und'` (undetermined). + * See {@link InputTrack.getInternalCodecId}. + * @deprecated Use {@link InputTrack.getInternalCodecId} instead. */ - get languageCode() { + get internalCodecId() { + return requireSync(this._backing.getInternalCodecId(), "internalCodecId", "getInternalCodecId"); + } + /** + * Returns the ISO 639-2/T language code for this track. If the language is unknown, this resolves to `'und'` + * (undetermined). + */ + async getLanguageCode() { return this._backing.getLanguageCode(); } - /** A user-defined name for this track. */ - get name() { + /** + * The ISO 639-2/T language code for this track. If the language is unknown, this field is `'und'` (undetermined). + * @deprecated Use {@link InputTrack.getLanguageCode} instead. + */ + get languageCode() { + return requireSync(this._backing.getLanguageCode(), "languageCode", "getLanguageCode"); + } + /** Returns the user-defined name for this track. */ + async getName() { return this._backing.getName(); } + /** + * A user-defined name for this track. + * @deprecated Use {@link InputTrack.getName} instead. + */ + get name() { + return requireSync(this._backing.getName(), "name", "getName"); + } + /** + * Returns a positive number x such that all timestamps and durations of all packets of this track are + * integer multiples of 1/x. + */ + async getTimeResolution() { + return this._backing.getTimeResolution(); + } /** * A positive number x such that all timestamps and durations of all packets of this track are * integer multiples of 1/x. + * @deprecated Use {@link InputTrack.getTimeResolution} instead. */ get timeResolution() { - return this._backing.getTimeResolution(); + return requireSync(this._backing.getTimeResolution(), "timeResolution", "getTimeResolution"); } - /** The track's disposition, i.e. information about its intended usage. */ - get disposition() { + /** + * Returns whether the timestamps of this track are relative to the Unix epoch (January 1, 1970 00:00:00 UTC). + * When `true`, each timestamp maps to a definitive point in time. + */ + async isRelativeToUnixEpoch() { + return this._backing.isRelativeToUnixEpoch(); + } + /** Returns the track's disposition, i.e. information about its intended usage. */ + async getDisposition() { return this._backing.getDisposition(); } + /** + * The track's disposition, i.e. information about its intended usage. + * @deprecated Use {@link InputTrack.getDisposition} instead. + */ + get disposition() { + return requireSync(this._backing.getDisposition(), "disposition", "getDisposition"); + } + /** + * Returns the peak bitrate of the track in bits per second, as specified in the track's metadata. This might not + * match the actual media data's bitrate. + */ + async getBitrate() { + return this._backing.getBitrate(); + } + /** + * Returns the average bitrate of the track in bits per second, as specified in the track's metadata. This might + * not match the actual media data's bitrate. + */ + async getAverageBitrate() { + return this._backing.getAverageBitrate(); + } /** * Returns the start timestamp of the first packet of this track, in seconds. While often near zero, this value * may be positive or even negative. A negative starting timestamp means the track's timing has been offset. Samples * with a negative timestamp should not be presented. */ - getFirstTimestamp() { - return this._backing.getFirstTimestamp(); + async getFirstTimestamp() { + const firstPacket = await this._backing.getFirstPacket({ metadataOnly: true }); + return firstPacket?.timestamp ?? 0; } - /** Returns the end timestamp of the last packet of this track, in seconds. */ - computeDuration() { - return this._backing.computeDuration(); + /** + * Returns the end timestamp of the last packet of this track, in seconds. + * + * By default, when the underlying media is live, this method will only resolve once the live stream ends. If you + * want to query the current end timestamp of the stream, set {@link PacketRetrievalOptions.skipLiveWait} to `true` + * in the options. + */ + async computeDuration(options) { + const lastPacket = await this._backing.getPacket(Infinity, { metadataOnly: true, ...options }); + const result = (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); + return roundToDivisor(result, await this.getTimeResolution()); + } + /** + * Gets the duration (end timestamp) in seconds of this track from metadata stored in the file. This value may be + * approximate or diverge from the actual, precise duration returned by `.computeDuration()`, but compared to that + * method, this method is cheaper. When the duration cannot be determined from the file metadata, `null` + * is returned. + * + * By default, when the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set + * {@link DurationMetadataRequestOptions.skipLiveWait} to `true` in the options. + */ + async getDurationFromMetadata(options = {}) { + return this._backing.getDurationFromMetadata(options); } /** * Computes aggregate packet statistics for this track, such as average packet rate or bitrate. @@ -5207,14 +19351,18 @@ class InputTrack { * looked at before it can return early; this means, you can use it to aggregate only a subset (prefix) of all * packets. This is very useful for getting a great estimate of video frame rate without having to scan through the * entire file. + * + * By default, when the underlying media is live and `targetPacketCount` is not set, this method will only resolve + * once the live stream ends. If you want to query the current packet statistics of the stream, set + * {@link PacketRetrievalOptions.skipLiveWait} to `true` in the options. */ - async computePacketStats(targetPacketCount = Infinity) { + async computePacketStats(targetPacketCount = Infinity, options) { const sink = new EncodedPacketSink(this); let startTimestamp = Infinity; let endTimestamp = -Infinity; let packetCount = 0; let totalPacketBytes = 0; - for await (const packet of sink.packets(void 0, void 0, { metadataOnly: true })) { + for await (const packet of sink.packets(void 0, void 0, { metadataOnly: true, ...options })) { if (packetCount >= targetPacketCount && packet.timestamp >= endTimestamp) { break; } @@ -5229,43 +19377,282 @@ class InputTrack { averageBitrate: packetCount ? Number((8 * totalPacketBytes / (endTimestamp - startTimestamp)).toPrecision(16)) : 0 }; } + /** + * Whether or not this track is currently live, meaning the media's end is still unknown. + * + * The value returned by this method may change over time as the track stops being live. To keep track of the + * track's live status, poll this method at the track's refresh interval + * via {@link InputTrack.getLiveRefreshInterval}. + */ + async isLive() { + return await this._backing.getLiveRefreshInterval() !== null; + } + /** + * Returns the track's live refresh interval in seconds, or `null` if the track is not live. This interval describes + * the time it takes, on average, for new live media data to become available. + */ + async getLiveRefreshInterval() { + return this._backing.getLiveRefreshInterval(); + } + /** + * Returns `true` if this track can be paired with the given track. Two tracks being pairable means they can be + * presented (displayed) together. + * + * Returns `false` if `other` equals `this`. + */ + canBePairedWith(other) { + if (!(other instanceof InputTrack)) { + throw new TypeError("other must be an InputTrack."); + } + if (this.input !== other.input || this === other) { + return false; + } + return (this._backing.getPairingMask() & other._backing.getPairingMask()) !== 0n; + } + /** + * Gets the list of other tracks that can be paired with this track. An optional query can be provided to narrow + * down the results. + */ + async getPairableTracks(query) { + return this.input.getTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** + * Gets the list of other video tracks that can be paired with this track. An optional query can be provided to + * narrow down the results. + */ + async getPairableVideoTracks(query) { + return this.input.getVideoTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** + * Gets the list of other audio tracks that can be paired with this track. An optional query can be provided to + * narrow down the results. + */ + async getPairableAudioTracks(query) { + return this.input.getAudioTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns the primary track that can be paired with this track, optionally steered by the provided query. */ + async getPrimaryPairableVideoTrack(query) { + return this.input.getPrimaryVideoTrack(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns the primary track that can be paired with this track, optionally steered by the provided query. */ + async getPrimaryPairableAudioTrack(query) { + return this.input.getPrimaryAudioTrack(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns `true` if there is another track that can be paired with this track. */ + async hasPairableTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + const tracks = await this.input.getTracks(); + for (const track of tracks) { + if (!this.canBePairedWith(track)) { + continue; + } + if (!predicate || await predicate(track)) { + return true; + } + } + return false; + } + /** Returns `true` if there is a video track that can be paired with this track. */ + hasPairableVideoTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + return this.hasPairableTrack(async (x) => x.isVideoTrack() && (!predicate || await predicate(x))); + } + /** Returns `true` if there is an audio track that can be paired with this track. */ + hasPairableAudioTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + return this.hasPairableTrack(async (x) => x.isAudioTrack() && (!predicate || await predicate(x))); + } } +const requireSync = (value, getterName, asyncName) => { + if (value instanceof Promise) { + throw new Error(`'${getterName}' is deprecated and not available synchronously for this track. Use the preferred '${asyncName}()' instead.`); + } + return value; +}; +const toValidatedPredicate = (predicate) => { + if (predicate !== void 0 && typeof predicate !== "function") { + throw new TypeError("predicate, when provided, must be a function."); + } + return predicate ? (track) => { + const handle = (result2) => { + if (typeof result2 !== "boolean") { + throw new TypeError("predicate must return or resolve to a boolean value."); + } + return result2; + }; + const result = predicate(track); + if (result instanceof Promise) { + return result.then(handle); + } + return handle(result); + } : void 0; +}; class InputVideoTrack extends InputTrack { /** @internal */ constructor(input, backing) { super(input, backing); + this._pixelAspectRatioCache = null; this._backing = backing; } get type() { return "video"; } - get codec() { + /** The codec of the track's packets. */ + async getCodec() { return this._backing.getCodec(); } - /** The width in pixels of the track's coded samples, before any transformations or rotations. */ - get codedWidth() { + /** + * The codec of the track's packets. + * @deprecated Use {@link InputVideoTrack.getCodec} instead. + */ + get codec() { + return requireSync(this._backing.getCodec(), "codec", "getCodec"); + } + async hasOnlyKeyPackets() { + return await this._backing.getHasOnlyKeyPackets?.() ?? false; + } + /** Returns the width in pixels of the track's coded samples, before any transformations or rotations. */ + async getCodedWidth() { return this._backing.getCodedWidth(); } - /** The height in pixels of the track's coded samples, before any transformations or rotations. */ - get codedHeight() { + /** + * The width in pixels of the track's coded samples, before any transformations or rotations. + * @deprecated Use {@link InputVideoTrack.getCodedWidth} instead. + */ + get codedWidth() { + return requireSync(this._backing.getCodedWidth(), "codedWidth", "getCodedWidth"); + } + /** Returns the height in pixels of the track's coded samples, before any transformations or rotations. */ + async getCodedHeight() { return this._backing.getCodedHeight(); } - /** The angle in degrees by which the track's frames should be rotated (clockwise). */ - get rotation() { + /** + * The height in pixels of the track's coded samples, before any transformations or rotations. + * @deprecated Use {@link InputVideoTrack.getCodedHeight} instead. + */ + get codedHeight() { + return requireSync(this._backing.getCodedHeight(), "codedHeight", "getCodedHeight"); + } + /** Returns the angle in degrees by which the track's frames should be rotated (clockwise). */ + async getRotation() { return this._backing.getRotation(); } - /** The width in pixels of the track's frames after rotation. */ - get displayWidth() { - const rotation = this._backing.getRotation(); - return rotation % 180 === 0 ? this._backing.getCodedWidth() : this._backing.getCodedHeight(); + /** + * The angle in degrees by which the track's frames should be rotated (clockwise). + * @deprecated Use {@link InputVideoTrack.getRotation} instead. + */ + get rotation() { + return requireSync(this._backing.getRotation(), "rotation", "getRotation"); } - /** The height in pixels of the track's frames after rotation. */ + /** + * Returns the width of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + */ + async getSquarePixelWidth() { + return this._backing.getSquarePixelWidth(); + } + /** + * The width of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + * @deprecated Use {@link InputVideoTrack.getSquarePixelWidth} instead. + */ + get squarePixelWidth() { + return requireSync(this._backing.getSquarePixelWidth(), "squarePixelWidth", "getSquarePixelWidth"); + } + /** + * Returns the height of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + */ + async getSquarePixelHeight() { + return this._backing.getSquarePixelHeight(); + } + /** + * The height of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + * @deprecated Use {@link InputVideoTrack.getSquarePixelHeight} instead. + */ + get squarePixelHeight() { + return requireSync(this._backing.getSquarePixelHeight(), "squarePixelHeight", "getSquarePixelHeight"); + } + /** + * Returns the pixel aspect ratio of the track's frames as a rational number in its reduced form. Most videos use + * square pixels (1:1). + */ + async getPixelAspectRatio() { + return this._pixelAspectRatioCache ?? (this._pixelAspectRatioCache = simplifyRational({ + num: await this.getSquarePixelWidth() * await this.getCodedHeight(), + den: await this.getSquarePixelHeight() * await this.getCodedWidth() + })); + } + /** + * The pixel aspect ratio of the track's frames, as a rational number in its reduced form. Most videos use + * square pixels (1:1). + * @deprecated Use {@link InputVideoTrack.getPixelAspectRatio} instead. + */ + get pixelAspectRatio() { + return this._pixelAspectRatioCache ?? (this._pixelAspectRatioCache = simplifyRational({ + num: requireSync(this._backing.getSquarePixelWidth(), "pixelAspectRatio", "getPixelAspectRatio") * requireSync(this._backing.getCodedHeight(), "pixelAspectRatio", "getPixelAspectRatio"), + den: requireSync(this._backing.getSquarePixelHeight(), "pixelAspectRatio", "getPixelAspectRatio") * requireSync(this._backing.getCodedWidth(), "pixelAspectRatio", "getPixelAspectRatio") + })); + } + /** Returns the display width of the track's frames in pixels, after aspect ratio adjustment and rotation. */ + async getDisplayWidth() { + const metadata = await this._backing.getMetadataDisplayWidth?.(); + if (metadata != null) { + return metadata; + } + const rotation = await this.getRotation(); + return rotation % 180 === 0 ? this.getSquarePixelWidth() : this.getSquarePixelHeight(); + } + /** + * The display width of the track's frames in pixels, after aspect ratio adjustment and rotation. + * @deprecated Use {@link InputVideoTrack.getDisplayWidth} instead. + */ + get displayWidth() { + const metadataRaw = this._backing.getMetadataDisplayWidth?.(); + if (metadataRaw !== void 0) { + const metadata = requireSync(metadataRaw, "displayWidth", "getDisplayWidth"); + if (metadata !== null) { + return metadata; + } + } + const rotation = requireSync(this._backing.getRotation(), "displayWidth", "getDisplayWidth"); + const value = rotation % 180 === 0 ? this._backing.getSquarePixelWidth() : this._backing.getSquarePixelHeight(); + return requireSync(value, "displayWidth", "getDisplayWidth"); + } + /** Returns the display height of the track's frames in pixels, after aspect ratio adjustment and rotation. */ + async getDisplayHeight() { + const metadata = await this._backing.getMetadataDisplayHeight?.(); + if (metadata != null) { + return metadata; + } + const rotation = await this.getRotation(); + return rotation % 180 === 0 ? this.getSquarePixelHeight() : this.getSquarePixelWidth(); + } + /** + * The display height of the track's frames in pixels, after aspect ratio adjustment and rotation. + * @deprecated Use {@link InputVideoTrack.getDisplayHeight} instead. + */ get displayHeight() { - const rotation = this._backing.getRotation(); - return rotation % 180 === 0 ? this._backing.getCodedHeight() : this._backing.getCodedWidth(); + const metadataRaw = this._backing.getMetadataDisplayHeight?.(); + if (metadataRaw !== void 0) { + const metadata = requireSync(metadataRaw, "displayHeight", "getDisplayHeight"); + if (metadata !== null) { + return metadata; + } + } + const rotation = requireSync(this._backing.getRotation(), "displayHeight", "getDisplayHeight"); + const value = rotation % 180 === 0 ? this._backing.getSquarePixelHeight() : this._backing.getSquarePixelWidth(); + return requireSync(value, "displayHeight", "getDisplayHeight"); } /** Returns the color space of the track's samples. */ - getColorSpace() { + async getColorSpace() { return this._backing.getColorSpace(); } /** If this method returns true, the track's samples use a high dynamic range (HDR). */ @@ -5274,7 +19661,7 @@ class InputVideoTrack extends InputTrack { return colorSpace.primaries === "bt2020" || colorSpace.primaries === "smpte432" || colorSpace.transfer === "pg" || colorSpace.transfer === "hlg" || colorSpace.matrix === "bt2020-ncl"; } /** Checks if this track may contain transparent samples with alpha data. */ - canBeTransparent() { + async canBeTransparent() { return this._backing.canBeTransparent(); } /** @@ -5282,10 +19669,14 @@ class InputVideoTrack extends InputTrack { * track's packets using a [`VideoDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder). Returns * null if the track's codec is unknown. */ - getDecoderConfig() { + async getDecoderConfig() { return this._backing.getDecoderConfig(); } async getCodecParameterString() { + const fromMetadata = await this._backing.getMetadataCodecParameterString?.(); + if (fromMetadata != null) { + return fromMetadata; + } const decoderConfig = await this._backing.getDecoderConfig(); return decoderConfig?.codec ?? null; } @@ -5295,7 +19686,7 @@ class InputVideoTrack extends InputTrack { if (!decoderConfig) { return false; } - const codec = this._backing.getCodec(); + const codec = await this._backing.getCodec(); assert(codec !== null); if (customVideoDecoders.some((x) => x.supports(codec, decoderConfig))) { return true; @@ -5317,12 +19708,13 @@ class InputVideoTrack extends InputTrack { if (packet.isMetadataOnly) { throw new TypeError("packet must not be metadata-only to determine its type."); } - if (this.codec === null) { + const codec = await this.getCodec(); + if (codec === null) { return null; } const decoderConfig = await this.getDecoderConfig(); assert(decoderConfig); - return determineVideoPacketType(this.codec, decoderConfig, packet.data); + return determineVideoPacketType(codec, decoderConfig, packet.data); } } class InputAudioTrack extends InputTrack { @@ -5334,26 +19726,55 @@ class InputAudioTrack extends InputTrack { get type() { return "audio"; } - get codec() { + /** The codec of the track's packets. */ + async getCodec() { return this._backing.getCodec(); } - /** The number of audio channels in the track. */ - get numberOfChannels() { + /** + * The codec of the track's packets. + * @deprecated Use {@link InputAudioTrack.getCodec} instead. + */ + get codec() { + return requireSync(this._backing.getCodec(), "codec", "getCodec"); + } + async hasOnlyKeyPackets() { + return await this._backing.getHasOnlyKeyPackets?.() ?? true; + } + /** Returns the number of audio channels in the track. */ + async getNumberOfChannels() { return this._backing.getNumberOfChannels(); } - /** The track's audio sample rate in hertz. */ - get sampleRate() { + /** + * The number of audio channels in the track. + * @deprecated Use {@link InputAudioTrack.getNumberOfChannels} instead. + */ + get numberOfChannels() { + return requireSync(this._backing.getNumberOfChannels(), "numberOfChannels", "getNumberOfChannels"); + } + /** Returns the track's audio sample rate in hertz. */ + async getSampleRate() { return this._backing.getSampleRate(); } + /** + * The track's audio sample rate in hertz. + * @deprecated Use {@link InputAudioTrack.getSampleRate} instead. + */ + get sampleRate() { + return requireSync(this._backing.getSampleRate(), "sampleRate", "getSampleRate"); + } /** * Returns the [decoder configuration](https://www.w3.org/TR/webcodecs/#audio-decoder-config) for decoding the * track's packets using an [`AudioDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder). Returns * null if the track's codec is unknown. */ - getDecoderConfig() { + async getDecoderConfig() { return this._backing.getDecoderConfig(); } async getCodecParameterString() { + const fromMetadata = await this._backing.getMetadataCodecParameterString?.(); + if (fromMetadata != null) { + return fromMetadata; + } const decoderConfig = await this._backing.getDecoderConfig(); return decoderConfig?.codec ?? null; } @@ -5363,7 +19784,7 @@ class InputAudioTrack extends InputTrack { if (!decoderConfig) { return false; } - const codec = this._backing.getCodec(); + const codec = await this._backing.getCodec(); assert(codec !== null); if (customAudioDecoders.some((x) => x.supports(codec, decoderConfig))) { return true; @@ -5386,4698 +19807,744 @@ class InputAudioTrack extends InputTrack { if (!(packet instanceof EncodedPacket)) { throw new TypeError("packet must be an EncodedPacket."); } - if (this.codec === null) { + if (await this.getCodec() === null) { return null; } return "key"; } } -const buildIsobmffMimeType = (info) => { - const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; - let string = base + (info.isQuickTime ? "quicktime" : "mp4"); - if (info.codecStrings.length > 0) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; - } - return string; +const desc = (value) => { + return -(value ?? -Infinity); }; -const MIN_BOX_HEADER_SIZE = 8; -const MAX_BOX_HEADER_SIZE = 16; -const readBoxHeader = (slice) => { - let totalSize = readU32Be(slice); - const name = readAscii(slice, 4); - let headerSize = 8; - const hasLargeSize = totalSize === 1; - if (hasLargeSize) { - totalSize = readU64Be(slice); - headerSize = 16; - } - const contentSize = totalSize - headerSize; - if (contentSize < 0) { - return null; - } - return { name, totalSize, headerSize, contentSize }; +const prefer = (value) => { + return -value; }; -const readFixed_16_16 = (slice) => { - return readI32Be(slice) / 65536; -}; -const readFixed_2_30 = (slice) => { - return readI32Be(slice) / 1073741824; -}; -const readIsomVariableInteger = (slice) => { - let result = 0; - for (let i = 0; i < 4; i++) { - result <<= 7; - const nextByte = readU8(slice); - result |= nextByte & 127; - if ((nextByte & 128) === 0) { - break; - } +const toValidatedInputTrackQuery = (query) => { + if (typeof query !== "object" || !query) { + throw new TypeError("query must be an object."); } - return result; -}; -const readMetadataStringShort = (slice) => { - let stringLength = readU16Be(slice); - slice.skip(2); - stringLength = Math.min(stringLength, slice.remainingLength); - return textDecoder.decode(readBytes(slice, stringLength)); -}; -const readDataBox = (slice) => { - const header = readBoxHeader(slice); - if (!header || header.name !== "data") { - return null; + if (query.filter !== void 0 && typeof query.filter !== "function") { + throw new TypeError("query.filter, when provided, must be a function."); } - if (slice.remainingLength < 8) { - return null; - } - const typeIndicator = readU32Be(slice); - slice.skip(4); - const data = readBytes(slice, header.contentSize - 8); - switch (typeIndicator) { - case 1: - return textDecoder.decode(data); - // UTF-8 - case 2: - return new TextDecoder("utf-16be").decode(data); - // UTF-16-BE - case 13: - return new RichImageData(data, "image/jpeg"); - case 14: - return new RichImageData(data, "image/png"); - case 27: - return new RichImageData(data, "image/bmp"); - default: - return data; - } -}; -class IsobmffDemuxer extends Demuxer { - constructor(input) { - super(input); - this.moovSlice = null; - this.currentTrack = null; - this.tracks = []; - this.metadataPromise = null; - this.movieTimescale = -1; - this.movieDurationInTimescale = -1; - this.isQuickTime = false; - this.metadataTags = {}; - this.currentMetadataKeys = null; - this.isFragmented = false; - this.fragmentTrackDefaults = []; - this.currentFragment = null; - this.lastReadFragment = null; - this.reader = input._reader; - } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); - } - async getTracks() { - await this.readMetadata(); - return this.tracks.map((track) => track.inputTrack); - } - async getMimeType() { - await this.readMetadata(); - const codecStrings = await Promise.all(this.tracks.map((x) => x.inputTrack.getCodecParameterString())); - return buildIsobmffMimeType({ - isQuickTime: this.isQuickTime, - hasVideo: this.tracks.some((x) => x.info?.type === "video"), - hasAudio: this.tracks.some((x) => x.info?.type === "audio"), - codecStrings: codecStrings.filter(Boolean) - }); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } - readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const startPos = currentPos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - if (boxInfo.name === "ftyp") { - const majorBrand = readAscii(slice, 4); - this.isQuickTime = majorBrand === "qt "; - } else if (boxInfo.name === "moov") { - let moovSlice = this.reader.requestSlice(slice.filePos, boxInfo.contentSize); - if (moovSlice instanceof Promise) - moovSlice = await moovSlice; - if (!moovSlice) - break; - this.moovSlice = moovSlice; - this.readContiguousBoxes(this.moovSlice); - this.tracks.sort((a, b) => Number(b.disposition.default) - Number(a.disposition.default)); - for (const track of this.tracks) { - const previousSegmentDurationsInSeconds = track.editListPreviousSegmentDurations / this.movieTimescale; - track.editListOffset -= Math.round(previousSegmentDurationsInSeconds * track.timescale); - } - break; - } - currentPos = startPos + boxInfo.totalSize; - } - if (this.isFragmented && this.reader.fileSize !== null) { - let lastWordSlice = this.reader.requestSlice(this.reader.fileSize - 4, 4); - if (lastWordSlice instanceof Promise) - lastWordSlice = await lastWordSlice; - assert(lastWordSlice); - const lastWord = readU32Be(lastWordSlice); - const potentialMfraPos = this.reader.fileSize - lastWord; - if (potentialMfraPos >= 0 && potentialMfraPos <= this.reader.fileSize - MAX_BOX_HEADER_SIZE) { - let mfraHeaderSlice = this.reader.requestSliceRange(potentialMfraPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (mfraHeaderSlice instanceof Promise) - mfraHeaderSlice = await mfraHeaderSlice; - if (mfraHeaderSlice) { - const boxInfo = readBoxHeader(mfraHeaderSlice); - if (boxInfo && boxInfo.name === "mfra") { - let mfraSlice = this.reader.requestSlice(mfraHeaderSlice.filePos, boxInfo.contentSize); - if (mfraSlice instanceof Promise) - mfraSlice = await mfraSlice; - if (mfraSlice) { - this.readContiguousBoxes(mfraSlice); - } - } - } - } - } - })()); - } - getSampleTableForTrack(internalTrack) { - if (internalTrack.sampleTable) { - return internalTrack.sampleTable; - } - const sampleTable = { - sampleTimingEntries: [], - sampleCompositionTimeOffsets: [], - sampleSizes: [], - keySampleIndices: null, - chunkOffsets: [], - sampleToChunk: [], - presentationTimestamps: null, - presentationTimestampIndexMap: null - }; - internalTrack.sampleTable = sampleTable; - assert(this.moovSlice); - const stblContainerSlice = this.moovSlice.slice(internalTrack.sampleTableByteOffset); - this.currentTrack = internalTrack; - this.traverseBox(stblContainerSlice); - this.currentTrack = null; - const isPcmCodec = internalTrack.info?.type === "audio" && internalTrack.info.codec && PCM_AUDIO_CODECS.includes(internalTrack.info.codec); - if (isPcmCodec && sampleTable.sampleCompositionTimeOffsets.length === 0) { - assert(internalTrack.info?.type === "audio"); - const pcmInfo = parsePcmCodec(internalTrack.info.codec); - const newSampleTimingEntries = []; - const newSampleSizes = []; - for (let i = 0; i < sampleTable.sampleToChunk.length; i++) { - const chunkEntry = sampleTable.sampleToChunk[i]; - const nextEntry = sampleTable.sampleToChunk[i + 1]; - const chunkCount = (nextEntry ? nextEntry.startChunkIndex : sampleTable.chunkOffsets.length) - chunkEntry.startChunkIndex; - for (let j = 0; j < chunkCount; j++) { - const startSampleIndex = chunkEntry.startSampleIndex + j * chunkEntry.samplesPerChunk; - const endSampleIndex = startSampleIndex + chunkEntry.samplesPerChunk; - const startTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, startSampleIndex, (x) => x.startIndex); - const startTimingEntry = sampleTable.sampleTimingEntries[startTimingEntryIndex]; - const endTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, endSampleIndex, (x) => x.startIndex); - const endTimingEntry = sampleTable.sampleTimingEntries[endTimingEntryIndex]; - const firstSampleTimestamp = startTimingEntry.startDecodeTimestamp + (startSampleIndex - startTimingEntry.startIndex) * startTimingEntry.delta; - const lastSampleTimestamp = endTimingEntry.startDecodeTimestamp + (endSampleIndex - endTimingEntry.startIndex) * endTimingEntry.delta; - const delta = lastSampleTimestamp - firstSampleTimestamp; - const lastSampleTimingEntry = last(newSampleTimingEntries); - if (lastSampleTimingEntry && lastSampleTimingEntry.delta === delta) { - lastSampleTimingEntry.count++; - } else { - newSampleTimingEntries.push({ - startIndex: chunkEntry.startChunkIndex + j, - startDecodeTimestamp: firstSampleTimestamp, - count: 1, - delta - }); - } - const chunkSize = chunkEntry.samplesPerChunk * pcmInfo.sampleSize * internalTrack.info.numberOfChannels; - newSampleSizes.push(chunkSize); - } - chunkEntry.startSampleIndex = chunkEntry.startChunkIndex; - chunkEntry.samplesPerChunk = 1; - } - sampleTable.sampleTimingEntries = newSampleTimingEntries; - sampleTable.sampleSizes = newSampleSizes; - } - if (sampleTable.sampleCompositionTimeOffsets.length > 0) { - sampleTable.presentationTimestamps = []; - for (const entry of sampleTable.sampleTimingEntries) { - for (let i = 0; i < entry.count; i++) { - sampleTable.presentationTimestamps.push({ - presentationTimestamp: entry.startDecodeTimestamp + i * entry.delta, - sampleIndex: entry.startIndex + i - }); - } - } - for (const entry of sampleTable.sampleCompositionTimeOffsets) { - for (let i = 0; i < entry.count; i++) { - const sampleIndex = entry.startIndex + i; - const sample = sampleTable.presentationTimestamps[sampleIndex]; - if (!sample) { - continue; - } - sample.presentationTimestamp += entry.offset; - } - } - sampleTable.presentationTimestamps.sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); - sampleTable.presentationTimestampIndexMap = Array(sampleTable.presentationTimestamps.length).fill(-1); - for (let i = 0; i < sampleTable.presentationTimestamps.length; i++) { - sampleTable.presentationTimestampIndexMap[sampleTable.presentationTimestamps[i].sampleIndex] = i; - } - } - return sampleTable; - } - async readFragment(startPos) { - if (this.lastReadFragment?.moofOffset === startPos) { - return this.lastReadFragment; - } - let headerSlice = this.reader.requestSliceRange(startPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const moofBoxInfo = readBoxHeader(headerSlice); - assert(moofBoxInfo?.name === "moof"); - let entireSlice = this.reader.requestSlice(startPos, moofBoxInfo.totalSize); - if (entireSlice instanceof Promise) - entireSlice = await entireSlice; - assert(entireSlice); - this.traverseBox(entireSlice); - const fragment = this.lastReadFragment; - assert(fragment && fragment.moofOffset === startPos); - for (const [, trackData] of fragment.trackData) { - const track = trackData.track; - const { fragmentPositionCache } = track; - if (!trackData.startTimestampIsFinal) { - const lookupEntry = track.fragmentLookupTable.find((x) => x.moofOffset === fragment.moofOffset); - if (lookupEntry) { - offsetFragmentTrackDataByTimestamp(trackData, lookupEntry.timestamp); - } else { - const lastCacheIndex = binarySearchLessOrEqual(fragmentPositionCache, fragment.moofOffset - 1, (x) => x.moofOffset); - if (lastCacheIndex !== -1) { - const lastCache = fragmentPositionCache[lastCacheIndex]; - offsetFragmentTrackDataByTimestamp(trackData, lastCache.endTimestamp); - } - } - trackData.startTimestampIsFinal = true; - } - const insertionIndex = binarySearchLessOrEqual(fragmentPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); - if (insertionIndex === -1 || fragmentPositionCache[insertionIndex].moofOffset !== fragment.moofOffset) { - fragmentPositionCache.splice(insertionIndex + 1, 0, { - moofOffset: fragment.moofOffset, - startTimestamp: trackData.startTimestamp, - endTimestamp: trackData.endTimestamp - }); - } - } - return fragment; - } - readContiguousBoxes(slice) { - const startIndex = slice.filePos; - while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { - const foundBox = this.traverseBox(slice); - if (!foundBox) { - break; - } - } - } - // eslint-disable-next-line @stylistic/generator-star-spacing - *iterateContiguousBoxes(slice) { - const startIndex = slice.filePos; - while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { - const startPos = slice.filePos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - yield { boxInfo, slice }; - slice.filePos = startPos + boxInfo.totalSize; - } - } - traverseBox(slice) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G; - const startPos = slice.filePos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - return false; - } - const contentStartPos = slice.filePos; - const boxEndPos = startPos + boxInfo.totalSize; - switch (boxInfo.name) { - case "mdia": - case "minf": - case "dinf": - case "mfra": - case "edts": - { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "mvhd": - { - const version = readU8(slice); - slice.skip(3); - if (version === 1) { - slice.skip(8 + 8); - this.movieTimescale = readU32Be(slice); - this.movieDurationInTimescale = readU64Be(slice); - } else { - slice.skip(4 + 4); - this.movieTimescale = readU32Be(slice); - this.movieDurationInTimescale = readU32Be(slice); - } - } - break; - case "trak": - { - const track = { - id: -1, - demuxer: this, - inputTrack: null, - disposition: { - ...DEFAULT_TRACK_DISPOSITION - }, - info: null, - timescale: -1, - durationInMovieTimescale: -1, - durationInMediaTimescale: -1, - rotation: 0, - internalCodecId: null, - name: null, - languageCode: UNDETERMINED_LANGUAGE, - sampleTableByteOffset: -1, - sampleTable: null, - fragmentLookupTable: [], - currentFragmentState: null, - fragmentPositionCache: [], - editListPreviousSegmentDurations: 0, - editListOffset: 0 - }; - this.currentTrack = track; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - if (track.id !== -1 && track.timescale !== -1 && track.info !== null) { - if (track.info.type === "video" && track.info.width !== -1) { - const videoTrack = track; - track.inputTrack = new InputVideoTrack(this.input, new IsobmffVideoTrackBacking(videoTrack)); - this.tracks.push(track); - } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { - const audioTrack = track; - track.inputTrack = new InputAudioTrack(this.input, new IsobmffAudioTrackBacking(audioTrack)); - this.tracks.push(track); - } - } - this.currentTrack = null; - } - break; - case "tkhd": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - const flags = readU24Be(slice); - const trackEnabled = !!(flags & 1); - track.disposition.default = trackEnabled; - if (version === 0) { - slice.skip(8); - track.id = readU32Be(slice); - slice.skip(4); - track.durationInMovieTimescale = readU32Be(slice); - } else if (version === 1) { - slice.skip(16); - track.id = readU32Be(slice); - slice.skip(4); - track.durationInMovieTimescale = readU64Be(slice); - } else { - throw new Error(`Incorrect track header version ${version}.`); - } - slice.skip(2 * 4 + 2 + 2 + 2 + 2); - const matrix = [ - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice), - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice), - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice) - ]; - const rotation = normalizeRotation(roundToMultiple(extractRotationFromMatrix(matrix), 90)); - assert(rotation === 0 || rotation === 90 || rotation === 180 || rotation === 270); - track.rotation = rotation; - } - break; - case "elst": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - slice.skip(3); - let relevantEntryFound = false; - let previousSegmentDurations = 0; - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const segmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); - const mediaTime = version === 1 ? readI64Be(slice) : readI32Be(slice); - const mediaRate = readFixed_16_16(slice); - if (segmentDuration === 0) { - continue; - } - if (relevantEntryFound) { - console.warn("Unsupported edit list: multiple edits are not currently supported. Only using first edit."); - break; - } - if (mediaTime === -1) { - previousSegmentDurations += segmentDuration; - continue; - } - if (mediaRate !== 1) { - console.warn("Unsupported edit list entry: media rate must be 1."); - break; - } - track.editListPreviousSegmentDurations = previousSegmentDurations; - track.editListOffset = mediaTime; - relevantEntryFound = true; - } - } - break; - case "mdhd": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - slice.skip(3); - if (version === 0) { - slice.skip(8); - track.timescale = readU32Be(slice); - track.durationInMediaTimescale = readU32Be(slice); - } else if (version === 1) { - slice.skip(16); - track.timescale = readU32Be(slice); - track.durationInMediaTimescale = readU64Be(slice); - } - let language = readU16Be(slice); - if (language > 0) { - track.languageCode = ""; - for (let i = 0; i < 3; i++) { - track.languageCode = String.fromCharCode(96 + (language & 31)) + track.languageCode; - language >>= 5; - } - if (!isIso639Dash2LanguageCode(track.languageCode)) { - track.languageCode = UNDETERMINED_LANGUAGE; - } - } - } - break; - case "hdlr": - { - const track = this.currentTrack; - if (!track) { - break; - } - slice.skip(8); - const handlerType = readAscii(slice, 4); - if (handlerType === "vide") { - track.info = { - type: "video", - width: -1, - height: -1, - codec: null, - codecDescription: null, - colorSpace: null, - avcType: null, - avcCodecInfo: null, - hevcCodecInfo: null, - vp9CodecInfo: null, - av1CodecInfo: null - }; - } else if (handlerType === "soun") { - track.info = { - type: "audio", - numberOfChannels: -1, - sampleRate: -1, - codec: null, - codecDescription: null, - aacCodecInfo: null - }; - } - } - break; - case "stbl": - { - const track = this.currentTrack; - if (!track) { - break; - } - track.sampleTableByteOffset = startPos; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "stsd": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (track.info === null || track.sampleTable) { - break; - } - const stsdVersion = readU8(slice); - slice.skip(3); - const entries = readU32Be(slice); - for (let i = 0; i < entries; i++) { - const sampleBoxStartPos = slice.filePos; - const sampleBoxInfo = readBoxHeader(slice); - if (!sampleBoxInfo) { - break; - } - track.internalCodecId = sampleBoxInfo.name; - const lowercaseBoxName = sampleBoxInfo.name.toLowerCase(); - if (track.info.type === "video") { - if (lowercaseBoxName === "avc1" || lowercaseBoxName === "avc3") { - track.info.codec = "avc"; - track.info.avcType = lowercaseBoxName === "avc1" ? 1 : 3; - } else if (lowercaseBoxName === "hvc1" || lowercaseBoxName === "hev1") { - track.info.codec = "hevc"; - } else if (lowercaseBoxName === "vp08") { - track.info.codec = "vp8"; - } else if (lowercaseBoxName === "vp09") { - track.info.codec = "vp9"; - } else if (lowercaseBoxName === "av01") { - track.info.codec = "av1"; - } else { - console.warn(`Unsupported video codec (sample entry type '${sampleBoxInfo.name}').`); - } - slice.skip(6 * 1 + 2 + 2 + 2 + 3 * 4); - track.info.width = readU16Be(slice); - track.info.height = readU16Be(slice); - slice.skip(4 + 4 + 4 + 2 + 32 + 2 + 2); - this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); - } else { - if (lowercaseBoxName === "mp4a") ; - else if (lowercaseBoxName === "opus") { - track.info.codec = "opus"; - } else if (lowercaseBoxName === "flac") { - track.info.codec = "flac"; - } else if (lowercaseBoxName === "twos" || lowercaseBoxName === "sowt" || lowercaseBoxName === "raw " || lowercaseBoxName === "in24" || lowercaseBoxName === "in32" || lowercaseBoxName === "fl32" || lowercaseBoxName === "fl64" || lowercaseBoxName === "lpcm" || lowercaseBoxName === "ipcm" || lowercaseBoxName === "fpcm") ; - else if (lowercaseBoxName === "ulaw") { - track.info.codec = "ulaw"; - } else if (lowercaseBoxName === "alaw") { - track.info.codec = "alaw"; - } else { - console.warn(`Unsupported audio codec (sample entry type '${sampleBoxInfo.name}').`); - } - slice.skip(6 * 1 + 2); - const version = readU16Be(slice); - slice.skip(3 * 2); - let channelCount = readU16Be(slice); - let sampleSize = readU16Be(slice); - slice.skip(2 * 2); - let sampleRate = readU32Be(slice) / 65536; - if (stsdVersion === 0 && version > 0) { - if (version === 1) { - slice.skip(4); - sampleSize = 8 * readU32Be(slice); - slice.skip(2 * 4); - } else if (version === 2) { - slice.skip(4); - sampleRate = readF64Be(slice); - channelCount = readU32Be(slice); - slice.skip(4); - sampleSize = readU32Be(slice); - const flags = readU32Be(slice); - slice.skip(2 * 4); - if (lowercaseBoxName === "lpcm") { - const bytesPerSample = sampleSize + 7 >> 3; - const isFloat = Boolean(flags & 1); - const isBigEndian = Boolean(flags & 2); - const sFlags = flags & 4 ? -1 : 0; - if (sampleSize > 0 && sampleSize <= 64) { - if (isFloat) { - if (sampleSize === 32) { - track.info.codec = isBigEndian ? "pcm-f32be" : "pcm-f32"; - } - } else { - if (sFlags & 1 << bytesPerSample - 1) { - if (bytesPerSample === 1) { - track.info.codec = "pcm-s8"; - } else if (bytesPerSample === 2) { - track.info.codec = isBigEndian ? "pcm-s16be" : "pcm-s16"; - } else if (bytesPerSample === 3) { - track.info.codec = isBigEndian ? "pcm-s24be" : "pcm-s24"; - } else if (bytesPerSample === 4) { - track.info.codec = isBigEndian ? "pcm-s32be" : "pcm-s32"; - } - } else { - if (bytesPerSample === 1) { - track.info.codec = "pcm-u8"; - } - } - } - } - if (track.info.codec === null) { - console.warn("Unsupported PCM format."); - } - } - } - } - if (track.info.codec === "opus") { - sampleRate = OPUS_SAMPLE_RATE; - } - track.info.numberOfChannels = channelCount; - track.info.sampleRate = sampleRate; - if (lowercaseBoxName === "twos") { - if (sampleSize === 8) { - track.info.codec = "pcm-s8"; - } else if (sampleSize === 16) { - track.info.codec = "pcm-s16be"; - } else { - console.warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`); - track.info.codec = null; - } - } else if (lowercaseBoxName === "sowt") { - if (sampleSize === 8) { - track.info.codec = "pcm-s8"; - } else if (sampleSize === 16) { - track.info.codec = "pcm-s16"; - } else { - console.warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`); - track.info.codec = null; - } - } else if (lowercaseBoxName === "raw ") { - track.info.codec = "pcm-u8"; - } else if (lowercaseBoxName === "in24") { - track.info.codec = "pcm-s24be"; - } else if (lowercaseBoxName === "in32") { - track.info.codec = "pcm-s32be"; - } else if (lowercaseBoxName === "fl32") { - track.info.codec = "pcm-f32be"; - } else if (lowercaseBoxName === "fl64") { - track.info.codec = "pcm-f64be"; - } else if (lowercaseBoxName === "ipcm") { - track.info.codec = "pcm-s16be"; - } else if (lowercaseBoxName === "fpcm") { - track.info.codec = "pcm-f32be"; - } - this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); - } - } - } - break; - case "avcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info); - track.info.codecDescription = readBytes(slice, boxInfo.contentSize); - } - break; - case "hvcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info); - track.info.codecDescription = readBytes(slice, boxInfo.contentSize); - } - break; - case "vpcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - slice.skip(4); - const profile = readU8(slice); - const level = readU8(slice); - const thirdByte = readU8(slice); - const bitDepth = thirdByte >> 4; - const chromaSubsampling = thirdByte >> 1 & 7; - const videoFullRangeFlag = thirdByte & 1; - const colourPrimaries = readU8(slice); - const transferCharacteristics = readU8(slice); - const matrixCoefficients = readU8(slice); - track.info.vp9CodecInfo = { - profile, - level, - bitDepth, - chromaSubsampling, - videoFullRangeFlag, - colourPrimaries, - transferCharacteristics, - matrixCoefficients - }; - } - break; - case "av1C": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - slice.skip(1); - const secondByte = readU8(slice); - const profile = secondByte >> 5; - const level = secondByte & 31; - const thirdByte = readU8(slice); - const tier = thirdByte >> 7; - const highBitDepth = thirdByte >> 6 & 1; - const twelveBit = thirdByte >> 5 & 1; - const monochrome = thirdByte >> 4 & 1; - const chromaSubsamplingX = thirdByte >> 3 & 1; - const chromaSubsamplingY = thirdByte >> 2 & 1; - const chromaSamplePosition = thirdByte & 3; - const bitDepth = profile === 2 && highBitDepth ? twelveBit ? 12 : 10 : highBitDepth ? 10 : 8; - track.info.av1CodecInfo = { - profile, - level, - tier, - bitDepth, - monochrome, - chromaSubsamplingX, - chromaSubsamplingY, - chromaSamplePosition - }; - } - break; - case "colr": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - const colourType = readAscii(slice, 4); - if (colourType !== "nclx") { - break; - } - const colourPrimaries = readU16Be(slice); - const transferCharacteristics = readU16Be(slice); - const matrixCoefficients = readU16Be(slice); - const fullRangeFlag = Boolean(readU8(slice) & 128); - track.info.colorSpace = { - primaries: COLOR_PRIMARIES_MAP_INVERSE[colourPrimaries], - transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics], - matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients], - fullRange: fullRangeFlag - }; - } - break; - case "wave": - { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "esds": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(4); - const tag = readU8(slice); - assert(tag === 3); - readIsomVariableInteger(slice); - slice.skip(2); - const mixed = readU8(slice); - const streamDependenceFlag = (mixed & 128) !== 0; - const urlFlag = (mixed & 64) !== 0; - const ocrStreamFlag = (mixed & 32) !== 0; - if (streamDependenceFlag) { - slice.skip(2); - } - if (urlFlag) { - const urlLength = readU8(slice); - slice.skip(urlLength); - } - if (ocrStreamFlag) { - slice.skip(2); - } - const decoderConfigTag = readU8(slice); - assert(decoderConfigTag === 4); - const decoderConfigDescriptorLength = readIsomVariableInteger(slice); - const payloadStart = slice.filePos; - const objectTypeIndication = readU8(slice); - if (objectTypeIndication === 64 || objectTypeIndication === 103) { - track.info.codec = "aac"; - track.info.aacCodecInfo = { isMpeg2: objectTypeIndication === 103 }; - } else if (objectTypeIndication === 105 || objectTypeIndication === 107) { - track.info.codec = "mp3"; - } else if (objectTypeIndication === 221) { - track.info.codec = "vorbis"; - } else { - console.warn(`Unsupported audio codec (objectTypeIndication ${objectTypeIndication}) - discarding track.`); - } - slice.skip(1 + 3 + 4 + 4); - if (decoderConfigDescriptorLength > slice.filePos - payloadStart) { - const decoderSpecificInfoTag = readU8(slice); - assert(decoderSpecificInfoTag === 5); - const decoderSpecificInfoLength = readIsomVariableInteger(slice); - track.info.codecDescription = readBytes(slice, decoderSpecificInfoLength); - if (track.info.codec === "aac") { - const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); - if (audioSpecificConfig.numberOfChannels !== null) { - track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; - } - if (audioSpecificConfig.sampleRate !== null) { - track.info.sampleRate = audioSpecificConfig.sampleRate; - } - } - } - } - break; - case "enda": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - const littleEndian = readU16Be(slice) & 255; - if (littleEndian) { - if (track.info.codec === "pcm-s16be") { - track.info.codec = "pcm-s16"; - } else if (track.info.codec === "pcm-s24be") { - track.info.codec = "pcm-s24"; - } else if (track.info.codec === "pcm-s32be") { - track.info.codec = "pcm-s32"; - } else if (track.info.codec === "pcm-f32be") { - track.info.codec = "pcm-f32"; - } else if (track.info.codec === "pcm-f64be") { - track.info.codec = "pcm-f64"; - } - } - } - break; - case "pcmC": { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(1 + 3); - const formatFlags = readU8(slice); - const isLittleEndian = Boolean(formatFlags & 1); - const pcmSampleSize = readU8(slice); - if (track.info.codec === "pcm-s16be") { - if (isLittleEndian) { - if (pcmSampleSize === 16) { - track.info.codec = "pcm-s16"; - } else if (pcmSampleSize === 24) { - track.info.codec = "pcm-s24"; - } else if (pcmSampleSize === 32) { - track.info.codec = "pcm-s32"; - } else { - console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } else { - if (pcmSampleSize === 16) { - track.info.codec = "pcm-s16be"; - } else if (pcmSampleSize === 24) { - track.info.codec = "pcm-s24be"; - } else if (pcmSampleSize === 32) { - track.info.codec = "pcm-s32be"; - } else { - console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } - } else if (track.info.codec === "pcm-f32be") { - if (isLittleEndian) { - if (pcmSampleSize === 32) { - track.info.codec = "pcm-f32"; - } else if (pcmSampleSize === 64) { - track.info.codec = "pcm-f64"; - } else { - console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } else { - if (pcmSampleSize === 32) { - track.info.codec = "pcm-f32be"; - } else if (pcmSampleSize === 64) { - track.info.codec = "pcm-f64be"; - } else { - console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } - } - break; - } - case "dOps": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(1); - const outputChannelCount = readU8(slice); - const preSkip = readU16Be(slice); - const inputSampleRate = readU32Be(slice); - const outputGain = readI16Be(slice); - const channelMappingFamily = readU8(slice); - let channelMappingTable; - if (channelMappingFamily !== 0) { - channelMappingTable = readBytes(slice, 2 + outputChannelCount); - } else { - channelMappingTable = new Uint8Array(0); - } - const description = new Uint8Array(8 + 1 + 1 + 2 + 4 + 2 + 1 + channelMappingTable.byteLength); - const view = new DataView(description.buffer); - view.setUint32(0, 1332770163, false); - view.setUint32(4, 1214603620, false); - view.setUint8(8, 1); - view.setUint8(9, outputChannelCount); - view.setUint16(10, preSkip, true); - view.setUint32(12, inputSampleRate, true); - view.setInt16(16, outputGain, true); - view.setUint8(18, channelMappingFamily); - description.set(channelMappingTable, 19); - track.info.codecDescription = description; - track.info.numberOfChannels = outputChannelCount; - } - break; - case "dfLa": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(4); - const BLOCK_TYPE_MASK = 127; - const LAST_METADATA_BLOCK_FLAG_MASK = 128; - const startPos2 = slice.filePos; - while (slice.filePos < boxEndPos) { - const flagAndType = readU8(slice); - const metadataBlockLength = readU24Be(slice); - const type = flagAndType & BLOCK_TYPE_MASK; - if (type === FlacBlockType.STREAMINFO) { - slice.skip(10); - const word = readU32Be(slice); - const sampleRate = word >>> 12; - const numberOfChannels = (word >> 9 & 7) + 1; - track.info.sampleRate = sampleRate; - track.info.numberOfChannels = numberOfChannels; - slice.skip(20); - } else { - slice.skip(metadataBlockLength); - } - if (flagAndType & LAST_METADATA_BLOCK_FLAG_MASK) { - break; - } - } - const endPos = slice.filePos; - slice.filePos = startPos2; - const bytes = readBytes(slice, endPos - startPos2); - const description = new Uint8Array(4 + bytes.byteLength); - const view = new DataView(description.buffer); - view.setUint32(0, 1716281667, false); - description.set(bytes, 4); - track.info.codecDescription = description; - } - break; - case "stts": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - let currentIndex = 0; - let currentTimestamp = 0; - for (let i = 0; i < entryCount; i++) { - const sampleCount = readU32Be(slice); - const sampleDelta = readU32Be(slice); - track.sampleTable.sampleTimingEntries.push({ - startIndex: currentIndex, - startDecodeTimestamp: currentTimestamp, - count: sampleCount, - delta: sampleDelta - }); - currentIndex += sampleCount; - currentTimestamp += sampleCount * sampleDelta; - } - } - break; - case "ctts": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(1 + 3); - const entryCount = readU32Be(slice); - let sampleIndex = 0; - for (let i = 0; i < entryCount; i++) { - const sampleCount = readU32Be(slice); - const sampleOffset = readI32Be(slice); - track.sampleTable.sampleCompositionTimeOffsets.push({ - startIndex: sampleIndex, - count: sampleCount, - offset: sampleOffset - }); - sampleIndex += sampleCount; - } - } - break; - case "stsz": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const sampleSize = readU32Be(slice); - const sampleCount = readU32Be(slice); - if (sampleSize === 0) { - for (let i = 0; i < sampleCount; i++) { - const sampleSize2 = readU32Be(slice); - track.sampleTable.sampleSizes.push(sampleSize2); - } - } else { - track.sampleTable.sampleSizes.push(sampleSize); - } - } - break; - case "stz2": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - slice.skip(3); - const fieldSize = readU8(slice); - const sampleCount = readU32Be(slice); - const bytes = readBytes(slice, Math.ceil(sampleCount * fieldSize / 8)); - const bitstream = new Bitstream(bytes); - for (let i = 0; i < sampleCount; i++) { - const sampleSize = bitstream.readBits(fieldSize); - track.sampleTable.sampleSizes.push(sampleSize); - } - } - break; - case "stss": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - track.sampleTable.keySampleIndices = []; - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const sampleIndex = readU32Be(slice) - 1; - track.sampleTable.keySampleIndices.push(sampleIndex); - } - if (track.sampleTable.keySampleIndices[0] !== 0) { - track.sampleTable.keySampleIndices.unshift(0); - } - } - break; - case "stsc": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const startChunkIndex = readU32Be(slice) - 1; - const samplesPerChunk = readU32Be(slice); - const sampleDescriptionIndex = readU32Be(slice); - track.sampleTable.sampleToChunk.push({ - startSampleIndex: -1, - startChunkIndex, - samplesPerChunk, - sampleDescriptionIndex - }); - } - let startSampleIndex = 0; - for (let i = 0; i < track.sampleTable.sampleToChunk.length; i++) { - track.sampleTable.sampleToChunk[i].startSampleIndex = startSampleIndex; - if (i < track.sampleTable.sampleToChunk.length - 1) { - const nextChunk = track.sampleTable.sampleToChunk[i + 1]; - const chunkCount = nextChunk.startChunkIndex - track.sampleTable.sampleToChunk[i].startChunkIndex; - startSampleIndex += chunkCount * track.sampleTable.sampleToChunk[i].samplesPerChunk; - } - } - } - break; - case "stco": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const chunkOffset = readU32Be(slice); - track.sampleTable.chunkOffsets.push(chunkOffset); - } - } - break; - case "co64": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const chunkOffset = readU64Be(slice); - track.sampleTable.chunkOffsets.push(chunkOffset); - } - } - break; - case "mvex": - { - this.isFragmented = true; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "mehd": - { - const version = readU8(slice); - slice.skip(3); - const fragmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); - this.movieDurationInTimescale = fragmentDuration; - } - break; - case "trex": - { - slice.skip(4); - const trackId = readU32Be(slice); - const defaultSampleDescriptionIndex = readU32Be(slice); - const defaultSampleDuration = readU32Be(slice); - const defaultSampleSize = readU32Be(slice); - const defaultSampleFlags = readU32Be(slice); - this.fragmentTrackDefaults.push({ - trackId, - defaultSampleDescriptionIndex, - defaultSampleDuration, - defaultSampleSize, - defaultSampleFlags - }); - } - break; - case "tfra": - { - const version = readU8(slice); - slice.skip(3); - const trackId = readU32Be(slice); - const track = this.tracks.find((x) => x.id === trackId); - if (!track) { - break; - } - const word = readU32Be(slice); - const lengthSizeOfTrafNum = (word & 48) >> 4; - const lengthSizeOfTrunNum = (word & 12) >> 2; - const lengthSizeOfSampleNum = word & 3; - const functions = [readU8, readU16Be, readU24Be, readU32Be]; - const readTrafNum = functions[lengthSizeOfTrafNum]; - const readTrunNum = functions[lengthSizeOfTrunNum]; - const readSampleNum = functions[lengthSizeOfSampleNum]; - const numberOfEntries = readU32Be(slice); - for (let i = 0; i < numberOfEntries; i++) { - const time = version === 1 ? readU64Be(slice) : readU32Be(slice); - const moofOffset = version === 1 ? readU64Be(slice) : readU32Be(slice); - readTrafNum(slice); - readTrunNum(slice); - readSampleNum(slice); - track.fragmentLookupTable.push({ - timestamp: time, - moofOffset - }); - } - track.fragmentLookupTable.sort((a, b) => a.timestamp - b.timestamp); - for (let i = 0; i < track.fragmentLookupTable.length - 1; i++) { - const entry1 = track.fragmentLookupTable[i]; - const entry2 = track.fragmentLookupTable[i + 1]; - if (entry1.timestamp === entry2.timestamp) { - track.fragmentLookupTable.splice(i + 1, 1); - i--; - } - } - } - break; - case "moof": - { - this.currentFragment = { - moofOffset: startPos, - moofSize: boxInfo.totalSize, - implicitBaseDataOffset: startPos, - trackData: /* @__PURE__ */ new Map() - }; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - this.lastReadFragment = this.currentFragment; - this.currentFragment = null; - } - break; - case "traf": - { - assert(this.currentFragment); - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - if (this.currentTrack) { - const trackData = this.currentFragment.trackData.get(this.currentTrack.id); - if (trackData) { - const { currentFragmentState } = this.currentTrack; - assert(currentFragmentState); - if (currentFragmentState.startTimestamp !== null) { - offsetFragmentTrackDataByTimestamp(trackData, currentFragmentState.startTimestamp); - trackData.startTimestampIsFinal = true; - } - } - this.currentTrack.currentFragmentState = null; - this.currentTrack = null; - } - } - break; - case "tfhd": - { - assert(this.currentFragment); - slice.skip(1); - const flags = readU24Be(slice); - const baseDataOffsetPresent = Boolean(flags & 1); - const sampleDescriptionIndexPresent = Boolean(flags & 2); - const defaultSampleDurationPresent = Boolean(flags & 8); - const defaultSampleSizePresent = Boolean(flags & 16); - const defaultSampleFlagsPresent = Boolean(flags & 32); - const durationIsEmpty = Boolean(flags & 65536); - const defaultBaseIsMoof = Boolean(flags & 131072); - const trackId = readU32Be(slice); - const track = this.tracks.find((x) => x.id === trackId); - if (!track) { - break; - } - const defaults = this.fragmentTrackDefaults.find((x) => x.trackId === trackId); - this.currentTrack = track; - track.currentFragmentState = { - baseDataOffset: this.currentFragment.implicitBaseDataOffset, - sampleDescriptionIndex: defaults?.defaultSampleDescriptionIndex ?? null, - defaultSampleDuration: defaults?.defaultSampleDuration ?? null, - defaultSampleSize: defaults?.defaultSampleSize ?? null, - defaultSampleFlags: defaults?.defaultSampleFlags ?? null, - startTimestamp: null - }; - if (baseDataOffsetPresent) { - track.currentFragmentState.baseDataOffset = readU64Be(slice); - } else if (defaultBaseIsMoof) { - track.currentFragmentState.baseDataOffset = this.currentFragment.moofOffset; - } - if (sampleDescriptionIndexPresent) { - track.currentFragmentState.sampleDescriptionIndex = readU32Be(slice); - } - if (defaultSampleDurationPresent) { - track.currentFragmentState.defaultSampleDuration = readU32Be(slice); - } - if (defaultSampleSizePresent) { - track.currentFragmentState.defaultSampleSize = readU32Be(slice); - } - if (defaultSampleFlagsPresent) { - track.currentFragmentState.defaultSampleFlags = readU32Be(slice); - } - if (durationIsEmpty) { - track.currentFragmentState.defaultSampleDuration = 0; - } - } - break; - case "tfdt": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.currentFragmentState); - const version = readU8(slice); - slice.skip(3); - const baseMediaDecodeTime = version === 0 ? readU32Be(slice) : readU64Be(slice); - track.currentFragmentState.startTimestamp = baseMediaDecodeTime; - } - break; - case "trun": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(this.currentFragment); - assert(track.currentFragmentState); - if (this.currentFragment.trackData.has(track.id)) { - console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring..."); - break; - } - const version = readU8(slice); - const flags = readU24Be(slice); - const dataOffsetPresent = Boolean(flags & 1); - const firstSampleFlagsPresent = Boolean(flags & 4); - const sampleDurationPresent = Boolean(flags & 256); - const sampleSizePresent = Boolean(flags & 512); - const sampleFlagsPresent = Boolean(flags & 1024); - const sampleCompositionTimeOffsetsPresent = Boolean(flags & 2048); - const sampleCount = readU32Be(slice); - let dataOffset = track.currentFragmentState.baseDataOffset; - if (dataOffsetPresent) { - dataOffset += readI32Be(slice); - } - let firstSampleFlags = null; - if (firstSampleFlagsPresent) { - firstSampleFlags = readU32Be(slice); - } - let currentOffset = dataOffset; - if (sampleCount === 0) { - this.currentFragment.implicitBaseDataOffset = currentOffset; - break; - } - let currentTimestamp = 0; - const trackData = { - track, - startTimestamp: 0, - endTimestamp: 0, - firstKeyFrameTimestamp: null, - samples: [], - presentationTimestamps: [], - startTimestampIsFinal: false - }; - this.currentFragment.trackData.set(track.id, trackData); - for (let i = 0; i < sampleCount; i++) { - let sampleDuration; - if (sampleDurationPresent) { - sampleDuration = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleDuration !== null); - sampleDuration = track.currentFragmentState.defaultSampleDuration; - } - let sampleSize; - if (sampleSizePresent) { - sampleSize = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleSize !== null); - sampleSize = track.currentFragmentState.defaultSampleSize; - } - let sampleFlags; - if (sampleFlagsPresent) { - sampleFlags = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleFlags !== null); - sampleFlags = track.currentFragmentState.defaultSampleFlags; - } - if (i === 0 && firstSampleFlags !== null) { - sampleFlags = firstSampleFlags; - } - let sampleCompositionTimeOffset = 0; - if (sampleCompositionTimeOffsetsPresent) { - if (version === 0) { - sampleCompositionTimeOffset = readU32Be(slice); - } else { - sampleCompositionTimeOffset = readI32Be(slice); - } - } - const isKeyFrame = !(sampleFlags & 65536); - trackData.samples.push({ - presentationTimestamp: currentTimestamp + sampleCompositionTimeOffset, - duration: sampleDuration, - byteOffset: currentOffset, - byteSize: sampleSize, - isKeyFrame - }); - currentOffset += sampleSize; - currentTimestamp += sampleDuration; - } - trackData.presentationTimestamps = trackData.samples.map((x, i) => ({ presentationTimestamp: x.presentationTimestamp, sampleIndex: i })).sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); - for (let i = 0; i < trackData.presentationTimestamps.length; i++) { - const currentEntry = trackData.presentationTimestamps[i]; - const currentSample = trackData.samples[currentEntry.sampleIndex]; - if (trackData.firstKeyFrameTimestamp === null && currentSample.isKeyFrame) { - trackData.firstKeyFrameTimestamp = currentSample.presentationTimestamp; - } - if (i < trackData.presentationTimestamps.length - 1) { - const nextEntry = trackData.presentationTimestamps[i + 1]; - currentSample.duration = nextEntry.presentationTimestamp - currentEntry.presentationTimestamp; - } - } - const firstSample = trackData.samples[trackData.presentationTimestamps[0].sampleIndex]; - const lastSample = trackData.samples[last(trackData.presentationTimestamps).sampleIndex]; - trackData.startTimestamp = firstSample.presentationTimestamp; - trackData.endTimestamp = lastSample.presentationTimestamp + lastSample.duration; - this.currentFragment.implicitBaseDataOffset = currentOffset; - } - break; - // Metadata section - // https://exiftool.org/TagNames/QuickTime.html - // https://mp4workshop.com/about - case "udta": - { - const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { - if (boxInfo2.name !== "meta" && !this.currentTrack) { - const startPos2 = slice2.filePos; - (_a = this.metadataTags).raw ?? (_a.raw = {}); - if (boxInfo2.name[0] === "©") { - (_b = this.metadataTags.raw)[_c = boxInfo2.name] ?? (_b[_c] = readMetadataStringShort(slice2)); - } else { - (_d = this.metadataTags.raw)[_e = boxInfo2.name] ?? (_d[_e] = readBytes(slice2, boxInfo2.contentSize)); - } - slice2.filePos = startPos2; - } - switch (boxInfo2.name) { - case "meta": - { - slice2.skip(-boxInfo2.headerSize); - this.traverseBox(slice2); - } - break; - case "©nam": - case "name": - { - if (this.currentTrack) { - this.currentTrack.name = textDecoder.decode(readBytes(slice2, boxInfo2.contentSize)); - } else { - (_f = this.metadataTags).title ?? (_f.title = readMetadataStringShort(slice2)); - } - } - break; - case "©des": - { - if (!this.currentTrack) { - (_g = this.metadataTags).description ?? (_g.description = readMetadataStringShort(slice2)); - } - } - break; - case "©ART": - { - if (!this.currentTrack) { - (_h = this.metadataTags).artist ?? (_h.artist = readMetadataStringShort(slice2)); - } - } - break; - case "©alb": - { - if (!this.currentTrack) { - (_i = this.metadataTags).album ?? (_i.album = readMetadataStringShort(slice2)); - } - } - break; - case "albr": - { - if (!this.currentTrack) { - (_j = this.metadataTags).albumArtist ?? (_j.albumArtist = readMetadataStringShort(slice2)); - } - } - break; - case "©gen": - { - if (!this.currentTrack) { - (_k = this.metadataTags).genre ?? (_k.genre = readMetadataStringShort(slice2)); - } - } - break; - case "©day": - { - if (!this.currentTrack) { - const date = new Date(readMetadataStringShort(slice2)); - if (!Number.isNaN(date.getTime())) { - (_l = this.metadataTags).date ?? (_l.date = date); - } - } - } - break; - case "©cmt": - { - if (!this.currentTrack) { - (_m = this.metadataTags).comment ?? (_m.comment = readMetadataStringShort(slice2)); - } - } - break; - case "©lyr": - { - if (!this.currentTrack) { - (_n = this.metadataTags).lyrics ?? (_n.lyrics = readMetadataStringShort(slice2)); - } - } - break; - } - } - } - break; - case "meta": - { - if (this.currentTrack) { - break; - } - const word = readU32Be(slice); - const isQuickTime = word !== 0; - this.currentMetadataKeys = /* @__PURE__ */ new Map(); - if (isQuickTime) { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } else { - this.readContiguousBoxes(slice.slice(contentStartPos + 4, boxInfo.contentSize - 4)); - } - this.currentMetadataKeys = null; - } - break; - case "keys": - { - if (!this.currentMetadataKeys) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const keySize = readU32Be(slice); - slice.skip(4); - const keyName = textDecoder.decode(readBytes(slice, keySize - 8)); - this.currentMetadataKeys.set(i + 1, keyName); - } - } - break; - case "ilst": - { - if (!this.currentMetadataKeys) { - break; - } - const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { - let metadataKey = boxInfo2.name; - const nameAsNumber = (metadataKey.charCodeAt(0) << 24) + (metadataKey.charCodeAt(1) << 16) + (metadataKey.charCodeAt(2) << 8) + metadataKey.charCodeAt(3); - if (this.currentMetadataKeys.has(nameAsNumber)) { - metadataKey = this.currentMetadataKeys.get(nameAsNumber); - } - const data = readDataBox(slice2); - (_o = this.metadataTags).raw ?? (_o.raw = {}); - (_p = this.metadataTags.raw)[metadataKey] ?? (_p[metadataKey] = data); - switch (metadataKey) { - case "©nam": - case "titl": - case "com.apple.quicktime.title": - case "title": - { - if (typeof data === "string") { - (_q = this.metadataTags).title ?? (_q.title = data); - } - } - break; - case "©des": - case "desc": - case "dscp": - case "com.apple.quicktime.description": - case "description": - { - if (typeof data === "string") { - (_r = this.metadataTags).description ?? (_r.description = data); - } - } - break; - case "©ART": - case "com.apple.quicktime.artist": - case "artist": - { - if (typeof data === "string") { - (_s = this.metadataTags).artist ?? (_s.artist = data); - } - } - break; - case "©alb": - case "albm": - case "com.apple.quicktime.album": - case "album": - { - if (typeof data === "string") { - (_t = this.metadataTags).album ?? (_t.album = data); - } - } - break; - case "aART": - case "album_artist": - { - if (typeof data === "string") { - (_u = this.metadataTags).albumArtist ?? (_u.albumArtist = data); - } - } - break; - case "©cmt": - case "com.apple.quicktime.comment": - case "comment": - { - if (typeof data === "string") { - (_v = this.metadataTags).comment ?? (_v.comment = data); - } - } - break; - case "©gen": - case "gnre": - case "com.apple.quicktime.genre": - case "genre": - { - if (typeof data === "string") { - (_w = this.metadataTags).genre ?? (_w.genre = data); - } - } - break; - case "©lyr": - case "lyrics": - { - if (typeof data === "string") { - (_x = this.metadataTags).lyrics ?? (_x.lyrics = data); - } - } - break; - case "©day": - case "rldt": - case "com.apple.quicktime.creationdate": - case "date": - { - if (typeof data === "string") { - const date = new Date(data); - if (!Number.isNaN(date.getTime())) { - (_y = this.metadataTags).date ?? (_y.date = date); - } - } - } - break; - case "covr": - case "com.apple.quicktime.artwork": - { - if (data instanceof RichImageData) { - (_z = this.metadataTags).images ?? (_z.images = []); - this.metadataTags.images.push({ - data: data.data, - kind: "coverFront", - mimeType: data.mimeType - }); - } else if (data instanceof Uint8Array) { - (_A = this.metadataTags).images ?? (_A.images = []); - this.metadataTags.images.push({ - data, - kind: "coverFront", - mimeType: "image/*" - }); - } - } - break; - case "track": - { - if (typeof data === "string") { - const parts = data.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - (_B = this.metadataTags).trackNumber ?? (_B.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - (_C = this.metadataTags).tracksTotal ?? (_C.tracksTotal = tracksTotal); - } - } - } - break; - case "trkn": - { - if (data instanceof Uint8Array && data.length >= 6) { - const view = toDataView(data); - const trackNumber = view.getUint16(2, false); - const tracksTotal = view.getUint16(4, false); - if (trackNumber > 0) { - (_D = this.metadataTags).trackNumber ?? (_D.trackNumber = trackNumber); - } - if (tracksTotal > 0) { - (_E = this.metadataTags).tracksTotal ?? (_E.tracksTotal = tracksTotal); - } - } - } - break; - case "disc": - case "disk": - { - if (data instanceof Uint8Array && data.length >= 6) { - const view = toDataView(data); - const discNumber = view.getUint16(2, false); - const discNumberMax = view.getUint16(4, false); - if (discNumber > 0) { - (_F = this.metadataTags).discNumber ?? (_F.discNumber = discNumber); - } - if (discNumberMax > 0) { - (_G = this.metadataTags).discsTotal ?? (_G.discsTotal = discNumberMax); - } - } - } - break; - } - } - } - break; - } - slice.filePos = boxEndPos; - return true; - } -} -class IsobmffTrackBacking { - constructor(internalTrack) { - this.internalTrack = internalTrack; - this.packetToSampleIndex = /* @__PURE__ */ new WeakMap(); - this.packetToFragmentLocation = /* @__PURE__ */ new WeakMap(); - } - getId() { - return this.internalTrack.id; - } - getCodec() { - throw new Error("Not implemented on base class."); - } - getInternalCodecId() { - return this.internalTrack.internalCodecId; - } - getName() { - return this.internalTrack.name; - } - getLanguageCode() { - return this.internalTrack.languageCode; - } - getTimeResolution() { - return this.internalTrack.timescale; - } - getDisposition() { - return this.internalTrack.disposition; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - async getFirstTimestamp() { - const firstPacket = await this.getFirstPacket({ metadataOnly: true }); - return firstPacket?.timestamp ?? 0; - } - async getFirstPacket(options) { - const regularPacket = await this.fetchPacketForSampleIndex(0, options); - if (regularPacket || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup( - null, - (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData) { - return { - sampleIndex: 0, - correctSampleFound: true - }; - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - mapTimestampIntoTimescale(timestamp) { - return roundIfAlmostInteger(timestamp * this.internalTrack.timescale) + this.internalTrack.editListOffset; - } - async getPacket(timestamp, options) { - const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); - const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); - if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup(null, (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (!trackData) { - return { sampleIndex: -1, correctSampleFound: false }; - } - const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.presentationTimestamp); - const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; - const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { sampleIndex: sampleIndex2, correctSampleFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextPacket(packet, options) { - const regularSampleIndex = this.packetToSampleIndex.get(packet); - if (regularSampleIndex !== void 0) { - return this.fetchPacketForSampleIndex(regularSampleIndex + 1, options); - } - const locationInFragment = this.packetToFragmentLocation.get(packet); - if (locationInFragment === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performFragmentedLookup( - locationInFragment.fragment, - (fragment) => { - if (fragment === locationInFragment.fragment) { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (locationInFragment.sampleIndex + 1 < trackData.samples.length) { - return { - sampleIndex: locationInFragment.sampleIndex + 1, - correctSampleFound: true - }; - } - } else { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData) { - return { - sampleIndex: 0, - correctSampleFound: true - }; - } - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - async getKeyPacket(timestamp, options) { - const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleIndex = getKeyframeSampleIndexForTimestamp(sampleTable, timestampInTimescale); - const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); - if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup(null, (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (!trackData) { - return { sampleIndex: -1, correctSampleFound: false }; - } - const index = findLastIndex(trackData.presentationTimestamps, (x) => { - const sample = trackData.samples[x.sampleIndex]; - return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; - }); - const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; - const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { sampleIndex: sampleIndex2, correctSampleFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextKeyPacket(packet, options) { - const regularSampleIndex = this.packetToSampleIndex.get(packet); - if (regularSampleIndex !== void 0) { - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, regularSampleIndex); - return this.fetchPacketForSampleIndex(nextKeyFrameSampleIndex, options); - } - const locationInFragment = this.packetToFragmentLocation.get(packet); - if (locationInFragment === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performFragmentedLookup( - locationInFragment.fragment, - (fragment) => { - if (fragment === locationInFragment.fragment) { - const trackData = fragment.trackData.get(this.internalTrack.id); - const nextKeyFrameIndex = trackData.samples.findIndex((x, i) => x.isKeyFrame && i > locationInFragment.sampleIndex); - if (nextKeyFrameIndex !== -1) { - return { - sampleIndex: nextKeyFrameIndex, - correctSampleFound: true - }; - } - } else { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData && trackData.firstKeyFrameTimestamp !== null) { - const keyFrameIndex = trackData.samples.findIndex((x) => x.isKeyFrame); - assert(keyFrameIndex !== -1); - return { - sampleIndex: keyFrameIndex, - correctSampleFound: true - }; - } - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - async fetchPacketForSampleIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleInfo = getSampleInfo(sampleTable, sampleIndex); - if (!sampleInfo) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.internalTrack.demuxer.reader.requestSlice(sampleInfo.sampleOffset, sampleInfo.sampleSize); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, sampleInfo.sampleSize); - } - const timestamp = (sampleInfo.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; - const duration = sampleInfo.duration / this.internalTrack.timescale; - const packet = new EncodedPacket(data, sampleInfo.isKeyFrame ? "key" : "delta", timestamp, duration, sampleIndex, sampleInfo.sampleSize); - this.packetToSampleIndex.set(packet, sampleIndex); - return packet; - } - async fetchPacketInFragment(fragment, sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const trackData = fragment.trackData.get(this.internalTrack.id); - const fragmentSample = trackData.samples[sampleIndex]; - assert(fragmentSample); - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.internalTrack.demuxer.reader.requestSlice(fragmentSample.byteOffset, fragmentSample.byteSize); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, fragmentSample.byteSize); - } - const timestamp = (fragmentSample.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; - const duration = fragmentSample.duration / this.internalTrack.timescale; - const packet = new EncodedPacket(data, fragmentSample.isKeyFrame ? "key" : "delta", timestamp, duration, fragment.moofOffset + sampleIndex, fragmentSample.byteSize); - this.packetToFragmentLocation.set(packet, { fragment, sampleIndex }); - return packet; - } - /** Looks for a packet in the fragments while trying to load as few fragments as possible to retrieve it. */ - async performFragmentedLookup(startFragment, getMatchInFragment, searchTimestamp, latestTimestamp, options) { - const demuxer = this.internalTrack.demuxer; - let currentFragment = null; - let bestFragment = null; - let bestSampleIndex = -1; - if (startFragment) { - const { sampleIndex, correctSampleFound } = getMatchInFragment(startFragment); - if (correctSampleFound) { - return this.fetchPacketInFragment(startFragment, sampleIndex, options); - } - if (sampleIndex !== -1) { - bestFragment = startFragment; - bestSampleIndex = sampleIndex; - } - } - const lookupEntryIndex = binarySearchLessOrEqual(this.internalTrack.fragmentLookupTable, searchTimestamp, (x) => x.timestamp); - const lookupEntry = lookupEntryIndex !== -1 ? this.internalTrack.fragmentLookupTable[lookupEntryIndex] : null; - const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.fragmentPositionCache, searchTimestamp, (x) => x.startTimestamp); - const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.fragmentPositionCache[positionCacheIndex] : null; - const lookupEntryPosition = Math.max(lookupEntry?.moofOffset ?? 0, positionCacheEntry?.moofOffset ?? 0) || null; - let currentPos; - if (!startFragment) { - currentPos = lookupEntryPosition ?? 0; - } else { - if (lookupEntryPosition === null || startFragment.moofOffset >= lookupEntryPosition) { - currentPos = startFragment.moofOffset + startFragment.moofSize; - currentFragment = startFragment; - } else { - currentPos = lookupEntryPosition; - } - } - while (true) { - if (currentFragment) { - const trackData = currentFragment.trackData.get(this.internalTrack.id); - if (trackData && trackData.startTimestamp > latestTimestamp) { - break; - } - } - let slice = demuxer.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const boxStartPos = currentPos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - if (boxInfo.name === "moof") { - currentFragment = await demuxer.readFragment(boxStartPos); - const { sampleIndex, correctSampleFound } = getMatchInFragment(currentFragment); - if (correctSampleFound) { - return this.fetchPacketInFragment(currentFragment, sampleIndex, options); - } - if (sampleIndex !== -1) { - bestFragment = currentFragment; - bestSampleIndex = sampleIndex; - } - } - currentPos = boxStartPos + boxInfo.totalSize; - } - if (lookupEntry && (!bestFragment || bestFragment.moofOffset < lookupEntry.moofOffset)) { - const previousLookupEntry = this.internalTrack.fragmentLookupTable[lookupEntryIndex - 1]; - assert(!previousLookupEntry || previousLookupEntry.timestamp < lookupEntry.timestamp); - const newSearchTimestamp = previousLookupEntry?.timestamp ?? -Infinity; - return this.performFragmentedLookup(null, getMatchInFragment, newSearchTimestamp, latestTimestamp, options); - } - if (bestFragment) { - return this.fetchPacketInFragment(bestFragment, bestSampleIndex, options); - } - return null; - } -} -class IsobmffVideoTrackBacking extends IsobmffTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfigPromise = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getCodedWidth() { - return this.internalTrack.info.width; - } - getCodedHeight() { - return this.internalTrack.info.height; - } - getRotation() { - return this.internalTrack.rotation; - } - async getColorSpace() { - return { - primaries: this.internalTrack.info.colorSpace?.primaries, - transfer: this.internalTrack.info.colorSpace?.transfer, - matrix: this.internalTrack.info.colorSpace?.matrix, - fullRange: this.internalTrack.info.colorSpace?.fullRange - }; - } - async canBeTransparent() { - return false; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { - if (this.internalTrack.info.codec === "vp9" && !this.internalTrack.info.vp9CodecInfo) { - const firstPacket = await this.getFirstPacket({}); - this.internalTrack.info.vp9CodecInfo = firstPacket && extractVp9CodecInfoFromPacket(firstPacket.data); - } else if (this.internalTrack.info.codec === "av1" && !this.internalTrack.info.av1CodecInfo) { - const firstPacket = await this.getFirstPacket({}); - this.internalTrack.info.av1CodecInfo = firstPacket && extractAv1CodecInfoFromPacket(firstPacket.data); - } - return { - codec: extractVideoCodecString(this.internalTrack.info), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? void 0, - colorSpace: this.internalTrack.info.colorSpace ?? void 0 - }; - })()); - } -} -class IsobmffAudioTrackBacking extends IsobmffTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfig = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getNumberOfChannels() { - return this.internalTrack.info.numberOfChannels; - } - getSampleRate() { - return this.internalTrack.info.sampleRate; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfig ?? (this.decoderConfig = { - codec: extractAudioCodecString(this.internalTrack.info), - numberOfChannels: this.internalTrack.info.numberOfChannels, - sampleRate: this.internalTrack.info.sampleRate, - description: this.internalTrack.info.codecDescription ?? void 0 - }); - } -} -const getSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { - if (sampleTable.presentationTimestamps) { - const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); - if (index === -1) { - return -1; - } - return sampleTable.presentationTimestamps[index].sampleIndex; - } else { - const index = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, timescaleUnits, (x) => x.startDecodeTimestamp); - if (index === -1) { - return -1; - } - const entry = sampleTable.sampleTimingEntries[index]; - return entry.startIndex + Math.min(Math.floor((timescaleUnits - entry.startDecodeTimestamp) / entry.delta), entry.count - 1); - } -}; -const getKeyframeSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { - if (!sampleTable.keySampleIndices) { - return getSampleIndexForTimestamp(sampleTable, timescaleUnits); - } - if (sampleTable.presentationTimestamps) { - const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); - if (index === -1) { - return -1; - } - for (let i = index; i >= 0; i--) { - const sampleIndex = sampleTable.presentationTimestamps[i].sampleIndex; - const isKeyFrame = binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1; - if (isKeyFrame) { - return sampleIndex; - } - } - return -1; - } else { - const sampleIndex = getSampleIndexForTimestamp(sampleTable, timescaleUnits); - const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); - return sampleTable.keySampleIndices[index] ?? -1; - } -}; -const getSampleInfo = (sampleTable, sampleIndex) => { - const timingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, sampleIndex, (x) => x.startIndex); - const timingEntry = sampleTable.sampleTimingEntries[timingEntryIndex]; - if (!timingEntry || timingEntry.startIndex + timingEntry.count <= sampleIndex) { - return null; - } - const decodeTimestamp = timingEntry.startDecodeTimestamp + (sampleIndex - timingEntry.startIndex) * timingEntry.delta; - let presentationTimestamp = decodeTimestamp; - const offsetEntryIndex = binarySearchLessOrEqual(sampleTable.sampleCompositionTimeOffsets, sampleIndex, (x) => x.startIndex); - const offsetEntry = sampleTable.sampleCompositionTimeOffsets[offsetEntryIndex]; - if (offsetEntry && sampleIndex - offsetEntry.startIndex < offsetEntry.count) { - presentationTimestamp += offsetEntry.offset; - } - const sampleSize = sampleTable.sampleSizes[Math.min(sampleIndex, sampleTable.sampleSizes.length - 1)]; - const chunkEntryIndex = binarySearchLessOrEqual(sampleTable.sampleToChunk, sampleIndex, (x) => x.startSampleIndex); - const chunkEntry = sampleTable.sampleToChunk[chunkEntryIndex]; - assert(chunkEntry); - const chunkIndex = chunkEntry.startChunkIndex + Math.floor((sampleIndex - chunkEntry.startSampleIndex) / chunkEntry.samplesPerChunk); - const chunkOffset = sampleTable.chunkOffsets[chunkIndex]; - const startSampleIndexOfChunk = chunkEntry.startSampleIndex + (chunkIndex - chunkEntry.startChunkIndex) * chunkEntry.samplesPerChunk; - let chunkSize = 0; - let sampleOffset = chunkOffset; - if (sampleTable.sampleSizes.length === 1) { - sampleOffset += sampleSize * (sampleIndex - startSampleIndexOfChunk); - chunkSize += sampleSize * chunkEntry.samplesPerChunk; - } else { - for (let i = startSampleIndexOfChunk; i < startSampleIndexOfChunk + chunkEntry.samplesPerChunk; i++) { - const sampleSize2 = sampleTable.sampleSizes[i]; - if (i < sampleIndex) { - sampleOffset += sampleSize2; - } - chunkSize += sampleSize2; - } - } - let duration = timingEntry.delta; - if (sampleTable.presentationTimestamps) { - const presentationIndex = sampleTable.presentationTimestampIndexMap[sampleIndex]; - assert(presentationIndex !== void 0); - if (presentationIndex < sampleTable.presentationTimestamps.length - 1) { - const nextEntry = sampleTable.presentationTimestamps[presentationIndex + 1]; - const nextPresentationTimestamp = nextEntry.presentationTimestamp; - duration = nextPresentationTimestamp - presentationTimestamp; - } + if (query.sortBy !== void 0 && typeof query.sortBy !== "function") { + throw new TypeError("query.sortBy, when provided, must be a function."); } return { - presentationTimestamp, - duration, - sampleOffset, - sampleSize, - chunkOffset, - chunkSize, - isKeyFrame: sampleTable.keySampleIndices ? binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1 : true + filter: query.filter ? (track) => { + const handle = (bool) => { + if (typeof bool !== "boolean") { + throw new TypeError("query.filter must return or resolve to a boolean."); + } + return bool; + }; + const result = query.filter(track); + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } : void 0, + sortBy: query.sortBy ? (track) => { + const handle = (value) => { + if (typeof value !== "number" && (!Array.isArray(value) || !value.every((x) => typeof x === "number"))) { + throw new TypeError("query.sortBy must return or resolve to a number or an array of numbers."); + } + return value; + }; + const result = query.sortBy(track); + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } : void 0 }; }; -const getNextKeyframeIndexForSample = (sampleTable, sampleIndex) => { - if (!sampleTable.keySampleIndices) { - return sampleIndex + 1; - } - const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); - return sampleTable.keySampleIndices[index + 1] ?? -1; -}; -const offsetFragmentTrackDataByTimestamp = (trackData, timestamp) => { - trackData.startTimestamp += timestamp; - trackData.endTimestamp += timestamp; - for (const sample of trackData.samples) { - sample.presentationTimestamp += timestamp; - } - for (const entry of trackData.presentationTimestamps) { - entry.presentationTimestamp += timestamp; - } -}; -const extractRotationFromMatrix = (matrix) => { - const [m11, , , m21] = matrix; - const scaleX = Math.hypot(m11, m21); - const cosTheta = m11 / scaleX; - const sinTheta = m21 / scaleX; - const result = -Math.atan2(sinTheta, cosTheta) * (180 / Math.PI); - if (!Number.isFinite(result)) { - return 0; - } - return result; -}; -const sampleTableIsEmpty = (sampleTable) => { - return sampleTable.sampleSizes.length === 0; -}; -var EBMLId; -(function(EBMLId2) { - EBMLId2[EBMLId2["EBML"] = 440786851] = "EBML"; - EBMLId2[EBMLId2["EBMLVersion"] = 17030] = "EBMLVersion"; - EBMLId2[EBMLId2["EBMLReadVersion"] = 17143] = "EBMLReadVersion"; - EBMLId2[EBMLId2["EBMLMaxIDLength"] = 17138] = "EBMLMaxIDLength"; - EBMLId2[EBMLId2["EBMLMaxSizeLength"] = 17139] = "EBMLMaxSizeLength"; - EBMLId2[EBMLId2["DocType"] = 17026] = "DocType"; - EBMLId2[EBMLId2["DocTypeVersion"] = 17031] = "DocTypeVersion"; - EBMLId2[EBMLId2["DocTypeReadVersion"] = 17029] = "DocTypeReadVersion"; - EBMLId2[EBMLId2["Void"] = 236] = "Void"; - EBMLId2[EBMLId2["Segment"] = 408125543] = "Segment"; - EBMLId2[EBMLId2["SeekHead"] = 290298740] = "SeekHead"; - EBMLId2[EBMLId2["Seek"] = 19899] = "Seek"; - EBMLId2[EBMLId2["SeekID"] = 21419] = "SeekID"; - EBMLId2[EBMLId2["SeekPosition"] = 21420] = "SeekPosition"; - EBMLId2[EBMLId2["Duration"] = 17545] = "Duration"; - EBMLId2[EBMLId2["Info"] = 357149030] = "Info"; - EBMLId2[EBMLId2["TimestampScale"] = 2807729] = "TimestampScale"; - EBMLId2[EBMLId2["MuxingApp"] = 19840] = "MuxingApp"; - EBMLId2[EBMLId2["WritingApp"] = 22337] = "WritingApp"; - EBMLId2[EBMLId2["Tracks"] = 374648427] = "Tracks"; - EBMLId2[EBMLId2["TrackEntry"] = 174] = "TrackEntry"; - EBMLId2[EBMLId2["TrackNumber"] = 215] = "TrackNumber"; - EBMLId2[EBMLId2["TrackUID"] = 29637] = "TrackUID"; - EBMLId2[EBMLId2["TrackType"] = 131] = "TrackType"; - EBMLId2[EBMLId2["FlagEnabled"] = 185] = "FlagEnabled"; - EBMLId2[EBMLId2["FlagDefault"] = 136] = "FlagDefault"; - EBMLId2[EBMLId2["FlagForced"] = 21930] = "FlagForced"; - EBMLId2[EBMLId2["FlagOriginal"] = 21934] = "FlagOriginal"; - EBMLId2[EBMLId2["FlagHearingImpaired"] = 21931] = "FlagHearingImpaired"; - EBMLId2[EBMLId2["FlagVisualImpaired"] = 21932] = "FlagVisualImpaired"; - EBMLId2[EBMLId2["FlagCommentary"] = 21935] = "FlagCommentary"; - EBMLId2[EBMLId2["FlagLacing"] = 156] = "FlagLacing"; - EBMLId2[EBMLId2["Name"] = 21358] = "Name"; - EBMLId2[EBMLId2["Language"] = 2274716] = "Language"; - EBMLId2[EBMLId2["LanguageBCP47"] = 2274717] = "LanguageBCP47"; - EBMLId2[EBMLId2["CodecID"] = 134] = "CodecID"; - EBMLId2[EBMLId2["CodecPrivate"] = 25506] = "CodecPrivate"; - EBMLId2[EBMLId2["CodecDelay"] = 22186] = "CodecDelay"; - EBMLId2[EBMLId2["SeekPreRoll"] = 22203] = "SeekPreRoll"; - EBMLId2[EBMLId2["DefaultDuration"] = 2352003] = "DefaultDuration"; - EBMLId2[EBMLId2["Video"] = 224] = "Video"; - EBMLId2[EBMLId2["PixelWidth"] = 176] = "PixelWidth"; - EBMLId2[EBMLId2["PixelHeight"] = 186] = "PixelHeight"; - EBMLId2[EBMLId2["AlphaMode"] = 21440] = "AlphaMode"; - EBMLId2[EBMLId2["Audio"] = 225] = "Audio"; - EBMLId2[EBMLId2["SamplingFrequency"] = 181] = "SamplingFrequency"; - EBMLId2[EBMLId2["Channels"] = 159] = "Channels"; - EBMLId2[EBMLId2["BitDepth"] = 25188] = "BitDepth"; - EBMLId2[EBMLId2["SimpleBlock"] = 163] = "SimpleBlock"; - EBMLId2[EBMLId2["BlockGroup"] = 160] = "BlockGroup"; - EBMLId2[EBMLId2["Block"] = 161] = "Block"; - EBMLId2[EBMLId2["BlockAdditions"] = 30113] = "BlockAdditions"; - EBMLId2[EBMLId2["BlockMore"] = 166] = "BlockMore"; - EBMLId2[EBMLId2["BlockAdditional"] = 165] = "BlockAdditional"; - EBMLId2[EBMLId2["BlockAddID"] = 238] = "BlockAddID"; - EBMLId2[EBMLId2["BlockDuration"] = 155] = "BlockDuration"; - EBMLId2[EBMLId2["ReferenceBlock"] = 251] = "ReferenceBlock"; - EBMLId2[EBMLId2["Cluster"] = 524531317] = "Cluster"; - EBMLId2[EBMLId2["Timestamp"] = 231] = "Timestamp"; - EBMLId2[EBMLId2["Cues"] = 475249515] = "Cues"; - EBMLId2[EBMLId2["CuePoint"] = 187] = "CuePoint"; - EBMLId2[EBMLId2["CueTime"] = 179] = "CueTime"; - EBMLId2[EBMLId2["CueTrackPositions"] = 183] = "CueTrackPositions"; - EBMLId2[EBMLId2["CueTrack"] = 247] = "CueTrack"; - EBMLId2[EBMLId2["CueClusterPosition"] = 241] = "CueClusterPosition"; - EBMLId2[EBMLId2["Colour"] = 21936] = "Colour"; - EBMLId2[EBMLId2["MatrixCoefficients"] = 21937] = "MatrixCoefficients"; - EBMLId2[EBMLId2["TransferCharacteristics"] = 21946] = "TransferCharacteristics"; - EBMLId2[EBMLId2["Primaries"] = 21947] = "Primaries"; - EBMLId2[EBMLId2["Range"] = 21945] = "Range"; - EBMLId2[EBMLId2["Projection"] = 30320] = "Projection"; - EBMLId2[EBMLId2["ProjectionType"] = 30321] = "ProjectionType"; - EBMLId2[EBMLId2["ProjectionPoseRoll"] = 30325] = "ProjectionPoseRoll"; - EBMLId2[EBMLId2["Attachments"] = 423732329] = "Attachments"; - EBMLId2[EBMLId2["AttachedFile"] = 24999] = "AttachedFile"; - EBMLId2[EBMLId2["FileDescription"] = 18046] = "FileDescription"; - EBMLId2[EBMLId2["FileName"] = 18030] = "FileName"; - EBMLId2[EBMLId2["FileMediaType"] = 18016] = "FileMediaType"; - EBMLId2[EBMLId2["FileData"] = 18012] = "FileData"; - EBMLId2[EBMLId2["FileUID"] = 18094] = "FileUID"; - EBMLId2[EBMLId2["Chapters"] = 272869232] = "Chapters"; - EBMLId2[EBMLId2["Tags"] = 307544935] = "Tags"; - EBMLId2[EBMLId2["Tag"] = 29555] = "Tag"; - EBMLId2[EBMLId2["Targets"] = 25536] = "Targets"; - EBMLId2[EBMLId2["TargetTypeValue"] = 26826] = "TargetTypeValue"; - EBMLId2[EBMLId2["TargetType"] = 25546] = "TargetType"; - EBMLId2[EBMLId2["TagTrackUID"] = 25541] = "TagTrackUID"; - EBMLId2[EBMLId2["TagEditionUID"] = 25545] = "TagEditionUID"; - EBMLId2[EBMLId2["TagChapterUID"] = 25540] = "TagChapterUID"; - EBMLId2[EBMLId2["TagAttachmentUID"] = 25542] = "TagAttachmentUID"; - EBMLId2[EBMLId2["SimpleTag"] = 26568] = "SimpleTag"; - EBMLId2[EBMLId2["TagName"] = 17827] = "TagName"; - EBMLId2[EBMLId2["TagLanguage"] = 17530] = "TagLanguage"; - EBMLId2[EBMLId2["TagString"] = 17543] = "TagString"; - EBMLId2[EBMLId2["TagBinary"] = 17541] = "TagBinary"; - EBMLId2[EBMLId2["ContentEncodings"] = 28032] = "ContentEncodings"; - EBMLId2[EBMLId2["ContentEncoding"] = 25152] = "ContentEncoding"; - EBMLId2[EBMLId2["ContentEncodingOrder"] = 20529] = "ContentEncodingOrder"; - EBMLId2[EBMLId2["ContentEncodingScope"] = 20530] = "ContentEncodingScope"; - EBMLId2[EBMLId2["ContentCompression"] = 20532] = "ContentCompression"; - EBMLId2[EBMLId2["ContentCompAlgo"] = 16980] = "ContentCompAlgo"; - EBMLId2[EBMLId2["ContentCompSettings"] = 16981] = "ContentCompSettings"; - EBMLId2[EBMLId2["ContentEncryption"] = 20533] = "ContentEncryption"; -})(EBMLId || (EBMLId = {})); -const LEVEL_0_EBML_IDS = [ - EBMLId.EBML, - EBMLId.Segment -]; -const LEVEL_1_EBML_IDS = [ - EBMLId.SeekHead, - EBMLId.Info, - EBMLId.Cluster, - EBMLId.Tracks, - EBMLId.Cues, - EBMLId.Attachments, - EBMLId.Chapters, - EBMLId.Tags -]; -const LEVEL_0_AND_1_EBML_IDS = [ - ...LEVEL_0_EBML_IDS, - ...LEVEL_1_EBML_IDS -]; -const MAX_VAR_INT_SIZE = 8; -const MIN_HEADER_SIZE = 2; -const MAX_HEADER_SIZE = 2 * MAX_VAR_INT_SIZE; -const readVarIntSize = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - slice.skip(-1); - if (firstByte === 0) { - return null; - } - let width = 1; - let mask = 128; - while ((firstByte & mask) === 0) { - width++; - mask >>= 1; - } - if (slice.remainingLength < width) { - return null; - } - return width; -}; -const readVarInt = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - if (firstByte === 0) { - return null; - } - let width = 1; - let mask = 1 << 7; - while ((firstByte & mask) === 0) { - width++; - mask >>= 1; - } - if (slice.remainingLength < width - 1) { - return null; - } - let value = firstByte & mask - 1; - for (let i = 1; i < width; i++) { - value *= 1 << 8; - value += readU8(slice); - } - return value; -}; -const readUnsignedInt = (slice, width) => { - if (width < 1 || width > 8) { - throw new Error("Bad unsigned int size " + width); - } - let value = 0; - for (let i = 0; i < width; i++) { - value *= 1 << 8; - value += readU8(slice); - } - return value; -}; -const readUnsignedBigInt = (slice, width) => { - if (width < 1) { - throw new Error("Bad unsigned int size " + width); - } - let value = 0n; - for (let i = 0; i < width; i++) { - value <<= 8n; - value += BigInt(readU8(slice)); - } - return value; -}; -const readElementId = (slice) => { - const size = readVarIntSize(slice); - if (size === null) { - return null; - } - if (slice.remainingLength < size) { - return null; - } - const id = readUnsignedInt(slice, size); - return id; -}; -const readElementSize = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - if (firstByte === 255) { - return void 0; - } - slice.skip(-1); - const size = readVarInt(slice); - if (size === null) { - return null; - } - if (size === 72057594037927940) { - return void 0; - } - return size; -}; -const readElementHeader = (slice) => { - assert(slice.remainingLength >= MIN_HEADER_SIZE); - const id = readElementId(slice); - if (id === null) { - return null; - } - const size = readElementSize(slice); - if (size === null) { - return null; - } - return { id, size }; -}; -const readAsciiString = (slice, length) => { - const bytes = readBytes(slice, length); - let strLength = 0; - while (strLength < length && bytes[strLength] !== 0) { - strLength += 1; - } - return String.fromCharCode(...bytes.subarray(0, strLength)); -}; -const readUnicodeString = (slice, length) => { - const bytes = readBytes(slice, length); - let strLength = 0; - while (strLength < length && bytes[strLength] !== 0) { - strLength += 1; - } - return textDecoder.decode(bytes.subarray(0, strLength)); -}; -const readFloat = (slice, width) => { - if (width === 0) { - return 0; - } - if (width !== 4 && width !== 8) { - throw new Error("Bad float size " + width); - } - return width === 4 ? readF32Be(slice) : readF64Be(slice); -}; -const searchForNextElementId = async (reader, startPos, ids, until) => { - const idsSet = new Set(ids); - let currentPos = startPos; - while (until === null || currentPos < until) { - let slice = reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementHeader = readElementHeader(slice); - if (!elementHeader) { - break; - } - if (idsSet.has(elementHeader.id)) { - return { pos: currentPos, found: true }; - } - assertDefinedSize(elementHeader.size); - currentPos = slice.filePos + elementHeader.size; - } - return { pos: until !== null && until > currentPos ? until : currentPos, found: false }; -}; -const resync = async (reader, startPos, ids, until) => { - const CHUNK_SIZE = 2 ** 16; - const idsSet = new Set(ids); - let currentPos = startPos; - while (currentPos < until) { - let slice = reader.requestSliceRange(currentPos, 0, Math.min(CHUNK_SIZE, until - currentPos)); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - if (slice.length < MAX_VAR_INT_SIZE) - break; - for (let i = 0; i < slice.length - MAX_VAR_INT_SIZE; i++) { - slice.filePos = currentPos; - const elementId = readElementId(slice); - if (elementId !== null && idsSet.has(elementId)) { - return currentPos; +const mergeInputTrackQueries = (queryA, queryB) => { + return { + filter: queryA?.filter || queryB?.filter ? (track) => { + const resultA = queryA?.filter?.(track) ?? true; + const handleResultA = (resultA2) => { + if (resultA2 === false) { + return false; + } + return queryB?.filter?.(track) ?? true; + }; + if (resultA instanceof Promise) { + return resultA.then(handleResultA); + } else { + return handleResultA(resultA); } - currentPos++; + } : void 0, + sortBy: queryA?.sortBy || queryB?.sortBy ? (track) => { + const resultA = queryA?.sortBy?.(track) ?? []; + const resultB = queryB?.sortBy?.(track) ?? []; + const join = (resultA2, resultB2) => { + return [ + ...Array.isArray(resultA2) ? resultA2 : [resultA2], + ...Array.isArray(resultB2) ? resultB2 : [resultB2] + ]; + }; + if (resultA instanceof Promise || resultB instanceof Promise) { + return Promise.all([resultA, resultB]).then(([resultA2, resultB2]) => { + return join(resultA2, resultB2); + }); + } else { + return join(resultA, resultB); + } + } : void 0 + }; +}; +const queryInputTracks = async (tracks, query) => { + let matched = tracks; + if (query?.filter) { + const filterMatches = tracks.map((t) => query.filter(t)); + const hasAsyncFilter = filterMatches.some((x) => x instanceof Promise); + if (hasAsyncFilter) { + const resolvedFilterMatches = await Promise.all(filterMatches); + matched = tracks.filter((_, i) => resolvedFilterMatches[i]); + } else { + matched = tracks.filter((_, i) => filterMatches[i]); } } - return null; -}; -const CODEC_STRING_MAP = { - "avc": "V_MPEG4/ISO/AVC", - "hevc": "V_MPEGH/ISO/HEVC", - "vp8": "V_VP8", - "vp9": "V_VP9", - "av1": "V_AV1", - "aac": "A_AAC", - "mp3": "A_MPEG/L3", - "opus": "A_OPUS", - "vorbis": "A_VORBIS", - "flac": "A_FLAC" -}; -function assertDefinedSize(size) { - if (size === void 0) { - throw new Error("Undefined element size is used in a place where it is not supported."); + if (!query?.sortBy) { + return matched; } + const sortValues = matched.map((t) => query.sortBy(t)); + const hasAsyncSort = sortValues.some((x) => x instanceof Promise); + const resolvedSortValues = hasAsyncSort ? await Promise.all(sortValues) : sortValues; + return matched.map((track, i) => ({ track, sortValue: resolvedSortValues[i] })).sort((a, b) => { + const aValues = Array.isArray(a.sortValue) ? a.sortValue : [a.sortValue]; + const bValues = Array.isArray(b.sortValue) ? b.sortValue : [b.sortValue]; + const maxLength = Math.max(aValues.length, bValues.length); + for (let i = 0; i < maxLength; i++) { + const aValue = aValues[i] ?? 0; + const bValue = bValues[i] ?? 0; + if (aValue === bValue) { + continue; + } + return aValue - bValue; + } + return 0; + }).map((x) => x.track); +}; +polyfillSymbolDispose(); +const DEFAULT_SOURCE_CACHE_GROUP = 1; +const ENCRYPTION_KEY_CACHE_GROUP = 2; +let inputFinalizationRegistry = null; +if (typeof FinalizationRegistry !== "undefined") { + inputFinalizationRegistry = new FinalizationRegistry((refs) => { + for (const ref of refs) { + if (!ref.freed) { + ref.free(); + } + } + }); } -const buildMatroskaMimeType = (info) => { - const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; - let string = base + (info.isWebM ? "webm" : "x-matroska"); - if (info.codecStrings.length > 0) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings.filter(Boolean))]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; +class Input extends EventEmitter { + /** True if the input has been disposed. */ + get disposed() { + return this._disposed; } - return string; -}; -var BlockLacing; -(function(BlockLacing2) { - BlockLacing2[BlockLacing2["None"] = 0] = "None"; - BlockLacing2[BlockLacing2["Xiph"] = 1] = "Xiph"; - BlockLacing2[BlockLacing2["FixedSize"] = 2] = "FixedSize"; - BlockLacing2[BlockLacing2["Ebml"] = 3] = "Ebml"; -})(BlockLacing || (BlockLacing = {})); -var ContentEncodingScope; -(function(ContentEncodingScope2) { - ContentEncodingScope2[ContentEncodingScope2["Block"] = 1] = "Block"; - ContentEncodingScope2[ContentEncodingScope2["Private"] = 2] = "Private"; - ContentEncodingScope2[ContentEncodingScope2["Next"] = 4] = "Next"; -})(ContentEncodingScope || (ContentEncodingScope = {})); -var ContentCompAlgo; -(function(ContentCompAlgo2) { - ContentCompAlgo2[ContentCompAlgo2["Zlib"] = 0] = "Zlib"; - ContentCompAlgo2[ContentCompAlgo2["Bzlib"] = 1] = "Bzlib"; - ContentCompAlgo2[ContentCompAlgo2["lzo1x"] = 2] = "lzo1x"; - ContentCompAlgo2[ContentCompAlgo2["HeaderStripping"] = 3] = "HeaderStripping"; -})(ContentCompAlgo || (ContentCompAlgo = {})); -const METADATA_ELEMENTS = [ - { id: EBMLId.SeekHead, flag: "seekHeadSeen" }, - { id: EBMLId.Info, flag: "infoSeen" }, - { id: EBMLId.Tracks, flag: "tracksSeen" }, - { id: EBMLId.Cues, flag: "cuesSeen" } -]; -const MAX_RESYNC_LENGTH = 10 * 2 ** 20; -class MatroskaDemuxer extends Demuxer { - constructor(input) { - super(input); - this.readMetadataPromise = null; - this.segments = []; - this.currentSegment = null; - this.currentTrack = null; - this.currentCluster = null; - this.currentBlock = null; - this.currentBlockAdditional = null; - this.currentCueTime = null; - this.currentDecodingInstruction = null; - this.currentTagTargetIsMovie = true; - this.currentSimpleTagName = null; - this.currentAttachedFile = null; - this.isWebM = false; - this.reader = input._reader; + /** + * Creates a new input file from the specified options. No reading operations will be performed until methods are + * called on this instance. + */ + constructor(options) { + super(); + this._demuxerPromise = null; + this._format = null; + this._trackBackingsCache = null; + this._backingToTrack = /* @__PURE__ */ new Map(); + this._disposed = false; + this._nextSourceCacheAge = 0; + this._sourceRefs = []; + this._sourceCache = []; + this._sourceCachePromises = []; + this._onFormatDetermined = null; + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (!Array.isArray(options.formats) || options.formats.some((x) => !(x instanceof InputFormat))) { + throw new TypeError("options.formats must be an array of InputFormat."); + } + if (!(options.source instanceof Source || options.source instanceof SourceRef)) { + throw new TypeError("options.source must be a Source or SourceRef."); + } + if (options.source instanceof Source && options.source._disposed) { + throw new TypeError("options.source must not be a disposed Source."); + } + if (options.initInput !== void 0 && !(options.initInput instanceof Input)) { + throw new TypeError("options.initInput, when provided, must be an Input."); + } + if (options.formatOptions !== void 0) { + validateInputFormatOptions(options.formatOptions, "formatOptions"); + } + this._formats = options.formats; + this._initInput = options.initInput ?? null; + this._formatOptions = options.formatOptions ?? {}; + if (options.source instanceof Source) { + this._rootRef = options.source.ref(); + } else { + this._rootRef = options.source; + } + this._sourceRefs.push(this._rootRef); + inputFinalizationRegistry?.register(this, this._sourceRefs, this); } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); + /** @internal */ + get _rootSource() { + return this._rootRef.source; } - async getTracks() { - await this.readMetadata(); - return this.segments.flatMap((segment) => segment.tracks.map((track) => track.inputTrack)); + /** @internal */ + async _getSourceUncached(request) { + assert(this._rootSource instanceof PathedSource); + const ref = await this._rootSource._resolveRequest(request); + this._emit("source", { source: ref.source, request, isRoot: request.isRoot }); + return ref; } - async getMimeType() { - await this.readMetadata(); - const tracks = await this.getTracks(); - const codecStrings = await Promise.all(tracks.map((x) => x.getCodecParameterString())); - return buildMatroskaMimeType({ - isWebM: this.isWebM, - hasVideo: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "video")), - hasAudio: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "audio")), - codecStrings: codecStrings.filter(Boolean) + /** @internal */ + _getSourceCached(request, cacheGroup = DEFAULT_SOURCE_CACHE_GROUP) { + const cachedEntry = this._sourceCache.find((x) => x.cacheGroup === cacheGroup && sourceRequestsAreEqual(x.request, request)); + if (cachedEntry) { + cachedEntry.age++; + return Promise.resolve(cachedEntry.sourceRef.source.ref()); + } + const cachedPromiseEntry = this._sourceCachePromises.find((x) => x.cacheGroup === cacheGroup && sourceRequestsAreEqual(x.request, request)); + if (cachedPromiseEntry) { + return cachedPromiseEntry.promise.then((x) => x.sourceRef.source.ref()); + } + const promise = (async () => { + const sourceRef = await this._getSourceUncached(request); + const MAX_SOURCE_CACHE_SIZE = 4; + const count = arrayCount(this._sourceCache, (x) => x.cacheGroup === cacheGroup && x.sourceRef.source._refCount === 1); + if (count >= MAX_SOURCE_CACHE_SIZE) { + const minAgeIndex = arrayArgmin(this._sourceCache, (x) => x.cacheGroup === cacheGroup && x.sourceRef.source._refCount === 1 ? x.age : Infinity); + assert(minAgeIndex !== -1); + const entry = this._sourceCache[minAgeIndex]; + this._sourceCache.splice(minAgeIndex, 1); + entry.sourceRef.free(); + removeItem(this._sourceRefs, entry.sourceRef); + } + this._sourceRefs.push(sourceRef); + const promiseIndex = this._sourceCachePromises.findIndex((x) => x.request === request); + assert(promiseIndex !== -1); + this._sourceCachePromises.splice(promiseIndex, 1); + const cacheEntry = { + request, + sourceRef, + age: this._nextSourceCacheAge++, + cacheGroup + }; + return cacheEntry; + })(); + this._sourceCachePromises.push({ + request, + cacheGroup, + promise + }); + return promise.then((entry) => { + const ref = entry.sourceRef.source.ref(); + this._sourceCache.push(entry); + return ref; }); } - async getMetadataTags() { - await this.readMetadata(); - for (const segment of this.segments) { - if (!segment.metadataTagsCollected) { - if (this.reader.fileSize !== null) { - await this.loadSegmentMetadata(segment); + /** @internal */ + _getDemuxer() { + return this._demuxerPromise ?? (this._demuxerPromise = (async () => { + this._reader = new Reader(this._rootSource); + this._emit("source", { source: this._rootSource, request: null, isRoot: true }); + for (const format of this._formats) { + const canRead = await format._canReadInput(this); + if (canRead) { + this._format = format; + this._onFormatDetermined?.(format); + return format._createDemuxer(this); } - segment.metadataTagsCollected = true; - } - } - let metadataTags = {}; - for (const segment of this.segments) { - metadataTags = { ...metadataTags, ...segment.metadataTags }; - } - return metadataTags; - } - readMetadata() { - return this.readMetadataPromise ?? (this.readMetadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const header = readElementHeader(slice); - if (!header) { - break; - } - const id = header.id; - let size = header.size; - const dataStartPos = slice.filePos; - if (id === EBMLId.EBML) { - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - this.readContiguousElements(slice2); - } else if (id === EBMLId.Segment) { - await this.readSegment(dataStartPos, size); - if (size === void 0) { - break; - } - if (this.reader.fileSize === null) { - break; - } - } else if (id === EBMLId.Cluster) { - if (this.reader.fileSize === null) { - break; - } - if (size === void 0) { - const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, this.reader.fileSize); - size = nextElementPos.pos - dataStartPos; - } - const lastSegment = last(this.segments); - if (lastSegment) { - lastSegment.elementEndPos = dataStartPos + size; - } - } - assertDefinedSize(size); - currentPos = dataStartPos + size; } + throw new UnsupportedInputFormatError(); })()); } - async readSegment(segmentDataStart, dataSize) { - this.currentSegment = { - seekHeadSeen: false, - infoSeen: false, - tracksSeen: false, - cuesSeen: false, - tagsSeen: false, - attachmentsSeen: false, - timestampScale: -1, - timestampFactor: -1, - duration: -1, - seekEntries: [], - tracks: [], - cuePoints: [], - dataStartPos: segmentDataStart, - elementEndPos: dataSize === void 0 ? null : segmentDataStart + dataSize, - clusterSeekStartPos: segmentDataStart, - lastReadCluster: null, - metadataTags: {}, - metadataTagsCollected: false - }; - this.segments.push(this.currentSegment); - let currentPos = segmentDataStart; - while (this.currentSegment.elementEndPos === null || currentPos < this.currentSegment.elementEndPos) { - let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementStartPos = currentPos; - const header = readElementHeader(slice); - if (!header || !LEVEL_1_EBML_IDS.includes(header.id) && header.id !== EBMLId.Void) { - const nextPos = await resync(this.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(this.currentSegment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); - if (nextPos) { - currentPos = nextPos; - continue; - } else { - break; - } - } - const { id, size } = header; - const dataStartPos = slice.filePos; - const metadataElementIndex = METADATA_ELEMENTS.findIndex((x) => x.id === id); - if (metadataElementIndex !== -1) { - const field = METADATA_ELEMENTS[metadataElementIndex].flag; - this.currentSegment[field] = true; - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (slice2) { - this.readContiguousElements(slice2); - } - } else if (id === EBMLId.Tags || id === EBMLId.Attachments) { - if (id === EBMLId.Tags) { - this.currentSegment.tagsSeen = true; - } else { - this.currentSegment.attachmentsSeen = true; - } - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (slice2) { - this.readContiguousElements(slice2); - } - } else if (id === EBMLId.Cluster) { - this.currentSegment.clusterSeekStartPos = elementStartPos; - break; - } - if (size === void 0) { - break; - } else { - currentPos = dataStartPos + size; - } - } - this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition); - if (this.reader.fileSize !== null) { - for (const seekEntry of this.currentSegment.seekEntries) { - const target = METADATA_ELEMENTS.find((x) => x.id === seekEntry.id); - if (!target) { - continue; - } - if (this.currentSegment[target.flag]) - continue; - let slice = this.reader.requestSliceRange(segmentDataStart + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - continue; - const header = readElementHeader(slice); - if (!header) - continue; - const { id, size } = header; - if (id !== target.id) - continue; - assertDefinedSize(size); - this.currentSegment[target.flag] = true; - let dataSlice = this.reader.requestSlice(slice.filePos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (!dataSlice) - continue; - this.readContiguousElements(dataSlice); - } - } - if (this.currentSegment.timestampScale === -1) { - this.currentSegment.timestampScale = 1e6; - this.currentSegment.timestampFactor = 1e9 / 1e6; - } - for (const track of this.currentSegment.tracks) { - if (track.defaultDurationNs !== null) { - track.defaultDuration = this.currentSegment.timestampFactor * track.defaultDurationNs / 1e9; - } - } - this.currentSegment.tracks.sort((a, b) => Number(b.disposition.default) - Number(a.disposition.default)); - const idToTrack = new Map(this.currentSegment.tracks.map((x) => [x.id, x])); - for (const cuePoint of this.currentSegment.cuePoints) { - const track = idToTrack.get(cuePoint.trackId); - if (track) { - track.cuePoints.push(cuePoint); - } - } - for (const track of this.currentSegment.tracks) { - track.cuePoints.sort((a, b) => a.time - b.time); - for (let i = 0; i < track.cuePoints.length - 1; i++) { - const cuePoint1 = track.cuePoints[i]; - const cuePoint2 = track.cuePoints[i + 1]; - if (cuePoint1.time === cuePoint2.time) { - track.cuePoints.splice(i + 1, 1); - i--; - } - } - } - let trackWithMostCuePoints = null; - let maxCuePointCount = -Infinity; - for (const track of this.currentSegment.tracks) { - if (track.cuePoints.length > maxCuePointCount) { - maxCuePointCount = track.cuePoints.length; - trackWithMostCuePoints = track; - } - } - for (const track of this.currentSegment.tracks) { - if (track.cuePoints.length === 0) { - track.cuePoints = trackWithMostCuePoints.cuePoints; - } - } - this.currentSegment = null; + /** + * Returns the source from which this input file reads data for the root path. + */ + get source() { + return this._rootSource; } - async readCluster(startPos, segment) { - if (segment.lastReadCluster?.elementStartPos === startPos) { - return segment.lastReadCluster; + /** + * Returns the format of the input file. You can compare this result directly to the {@link InputFormat} singletons + * or use `instanceof` checks for subset-aware logic (for example, `format instanceof MatroskaInputFormat` is true + * for both MKV and WebM). + */ + async getFormat() { + await this._getDemuxer(); + assert(this._format); + return this._format; + } + /** Returns `true` if the format of the input file is known and the file can be read, `false` otherwise. */ + async canRead() { + try { + await this._getDemuxer(); + return true; + } catch (error) { + if (error instanceof UnsupportedInputFormatError) { + return false; + } + throw error; } - let headerSlice = this.reader.requestSliceRange(startPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const elementStartPos = startPos; - const elementHeader = readElementHeader(headerSlice); - assert(elementHeader); - const id = elementHeader.id; - assert(id === EBMLId.Cluster); - let size = elementHeader.size; - const dataStartPos = headerSlice.filePos; + } + /** + * Returns the timestamp at which the input file starts. More precisely, returns the smallest starting timestamp + * among all tracks. + * + * Optionally, you can pass in the list of tracks for which you want to compute the starting timestamp. + * + * Note that this method is potentially expensive for inputs with many tracks (such as HLS manifests), since it + * probes every track. + */ + async getFirstTimestamp(tracks) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + if (filtered.length === 0) { + return 0; + } + const firstTimestamps = await Promise.all(filtered.map((x) => x.getFirstTimestamp())); + return Math.min(...firstTimestamps); + } + /** + * Computes the duration of the input file, in seconds. More precisely, returns the largest end timestamp among + * all tracks. + * + * Optionally, you can pass in the list of tracks for which you want to compute the duration. + * + * This method can be potentially expensive depending on the underlying file format, because it returns the most + * accurate duration possible and must check all tracks. Use {@link Input.getDurationFromMetadata} for a faster but + * less accurate estimate of duration. + * + * By default, when any track in the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set {@link PacketRetrievalOptions.skipLiveWait} + * to `true` in the options. + */ + async computeDuration(tracks, options) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + if (filtered.length === 0) { + return 0; + } + const tracksDurations = await Promise.all(filtered.map((x) => x.computeDuration(options))); + return Math.max(...tracksDurations); + } + /** + * Gets the duration (end timestamp) in seconds of the input file from metadata stored in the file. This value may + * be approximate or diverge from the actual, precise duration returned by `.computeDuration()`, but compared to + * that method, this method is cheaper. When the duration cannot be determined from the file metadata, `null` + * is returned. + * + * Optionally, you can pass in the list of tracks for which you want to get the duration from metadata. + * + * By default, when the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set + * {@link DurationMetadataRequestOptions.skipLiveWait} to `true` in the options. + */ + async getDurationFromMetadata(tracks, options) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + const tracksDurations = await Promise.all(filtered.map((x) => x.getDurationFromMetadata(options))); + const nonNullDurations = tracksDurations.filter((x) => x !== null); + if (nonNullDurations.length === 0) { + return null; + } + return Math.max(...nonNullDurations); + } + /** + * Returns the list of all tracks of this input file in the order in which they appear in the file. An optional + * query can be provided. + */ + async getTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const backings = await this._getTrackBackings(); + const tracks = backings.map((backing) => this._wrapBackingAsTrack(backing)); + return queryInputTracks(tracks, query); + } + /** Returns the list of all video tracks of this input file. An optional query can be provided. */ + async getVideoTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const tracks = await this.getTracks(); + const videoTracks = tracks.filter((x) => x.isVideoTrack()); + return queryInputTracks(videoTracks, query); + } + /** Returns the list of all audio tracks of this input file. An optional query can be provided. */ + async getAudioTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const tracks = await this.getTracks(); + const audioTracks = tracks.filter((x) => x.isAudioTrack()); + return queryInputTracks(audioTracks, query); + } + /** + * Returns the primary video track of this input file, or null if there are no video tracks. + * + * Multiple factors determine which track is considered primary, including its position in the file, disposition, + * bitrate (higher bitrate is preferred), and if it can be paired with an audio track. + */ + async getPrimaryVideoTrack(query) { + query && (query = toValidatedInputTrackQuery(query)); + const merged = mergeInputTrackQueries(query, { + sortBy: async (t) => [ + prefer((await t.getDisposition()).default), + prefer(await t.hasPairableAudioTrack()), + prefer(!await t.hasOnlyKeyPackets()), + desc(await t.getBitrate()) + ] + }); + const sorted = await this.getVideoTracks(merged); + return sorted[0] ?? null; + } + /** + * Returns the primary audio track of this input file, or null if there are no audio tracks. + * + * Multiple factors determine which track is considered primary, including its position in the file, disposition, + * bitrate (higher bitrate is preferred), and if it can be paired with the primary video track. + */ + async getPrimaryAudioTrack(query) { + query && (query = toValidatedInputTrackQuery(query)); + const primaryVideoTrack = await this.getPrimaryVideoTrack(); + const merged = mergeInputTrackQueries(query, { + sortBy: async (t) => [ + prefer(!primaryVideoTrack || t.canBePairedWith(primaryVideoTrack)), + prefer((await t.getDisposition()).default), + desc(await t.getBitrate()) + ] + }); + const sorted = await this.getAudioTracks(merged); + return sorted[0] ?? null; + } + /** @internal */ + async _getTrackBackings() { + const demuxer = await this._getDemuxer(); + return this._trackBackingsCache ?? (this._trackBackingsCache = await demuxer.getTrackBackings()); + } + /** @internal */ + _wrapBackingAsTrack(backing) { + const existing = this._backingToTrack.get(backing); + if (existing) { + return existing; + } + const type = backing.getType(); + const track = type === "video" ? new InputVideoTrack(this, backing) : new InputAudioTrack(this, backing); + this._backingToTrack.set(backing, track); + return track; + } + /** Returns the full MIME type of this input file, including track codecs. */ + async getMimeType() { + const demuxer = await this._getDemuxer(); + return demuxer.getMimeType(); + } + /** + * Returns descriptive metadata tags about the media file, such as title, author, date, cover art, or other + * attached files. + */ + async getMetadataTags() { + const demuxer = await this._getDemuxer(); + return demuxer.getMetadataTags(); + } + /** + * Disposes this input and frees connected resources. When an input is disposed, ongoing read operations will be + * canceled, all future read operations will fail, any open decoders will be closed, and all ongoing media sink + * operations will be canceled. Disallowed and canceled operations will throw an {@link InputDisposedError}. + * + * You are expected not to use an input after disposing it. While some operations may still work, it is not + * specified and may change in any future update. + */ + dispose() { + if (this._disposed) { + return; + } + this._disposed = true; + for (const ref of this._sourceRefs) { + ref.free(); + } + this._sourceRefs.length = 0; + inputFinalizationRegistry?.unregister(this); + void this._demuxerPromise?.then((demuxer) => demuxer.dispose()); + } + /** + * Calls `.dispose()` on the input, implementing the `Disposable` interface for use with + * JavaScript Explicit Resource Management features. + */ + [Symbol.dispose]() { + this.dispose(); + } +} +class UnsupportedInputFormatError extends Error { + /** Creates a new {@link UnsupportedInputFormatError}. */ + constructor(message = "Input has an unsupported or unrecognizable format.") { + super(message); + this.name = "UnsupportedInputFormatError"; + } +} +class InputDisposedError extends Error { + /** Creates a new {@link InputDisposedError}. */ + constructor(message = "Input has been disposed.") { + super(message); + this.name = "InputDisposedError"; + } +} +class Reader { + constructor(source) { + this.source = source; + } + get fileSize() { + const size = this.source._getFileSize(); if (size === void 0) { - const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); - size = nextElementPos.pos - dataStartPos; + throw new Error("Reading file size too early; read required first."); } - let dataSlice = this.reader.requestSlice(dataStartPos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - const cluster = { - segment, - elementStartPos, - elementEndPos: dataStartPos + size, - dataStartPos, - timestamp: -1, - trackData: /* @__PURE__ */ new Map() - }; - this.currentCluster = cluster; - if (dataSlice) { - const endPos = this.readContiguousElements(dataSlice, LEVEL_0_AND_1_EBML_IDS); - cluster.elementEndPos = endPos; - } - for (const [, trackData] of cluster.trackData) { - const track = trackData.track; - assert(trackData.blocks.length > 0); - let hasLacedBlocks = false; - for (let i = 0; i < trackData.blocks.length; i++) { - const block = trackData.blocks[i]; - block.timestamp += cluster.timestamp; - hasLacedBlocks || (hasLacedBlocks = block.lacing !== BlockLacing.None); - } - trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); - for (let i = 0; i < trackData.presentationTimestamps.length; i++) { - const currentEntry = trackData.presentationTimestamps[i]; - const currentBlock = trackData.blocks[currentEntry.blockIndex]; - if (trackData.firstKeyFrameTimestamp === null && currentBlock.isKeyFrame) { - trackData.firstKeyFrameTimestamp = currentBlock.timestamp; - } - if (i < trackData.presentationTimestamps.length - 1) { - const nextEntry = trackData.presentationTimestamps[i + 1]; - currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp; - } else if (currentBlock.duration === 0) { - if (track.defaultDuration != null) { - if (currentBlock.lacing === BlockLacing.None) { - currentBlock.duration = track.defaultDuration; - } - } - } - } - if (hasLacedBlocks) { - this.expandLacedBlocks(trackData.blocks, track); - trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); - } - const firstBlock = trackData.blocks[trackData.presentationTimestamps[0].blockIndex]; - const lastBlock = trackData.blocks[last(trackData.presentationTimestamps).blockIndex]; - trackData.startTimestamp = firstBlock.timestamp; - trackData.endTimestamp = lastBlock.timestamp + lastBlock.duration; - const insertionIndex = binarySearchLessOrEqual(track.clusterPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); - if (insertionIndex === -1 || track.clusterPositionCache[insertionIndex].elementStartPos !== elementStartPos) { - track.clusterPositionCache.splice(insertionIndex + 1, 0, { - elementStartPos: cluster.elementStartPos, - startTimestamp: trackData.startTimestamp - }); - } - } - segment.lastReadCluster = cluster; - return cluster; + return size; } - getTrackDataInCluster(cluster, trackNumber) { - let trackData = cluster.trackData.get(trackNumber); - if (!trackData) { - const track = cluster.segment.tracks.find((x) => x.id === trackNumber); - if (!track) { + get fileSizeNonStrict() { + return this.source._getFileSize() ?? null; + } + requestSlice(start, length) { + if (this.source._disposed) { + throw new InputDisposedError(); + } + if (start < 0) { + return null; + } + if (this.fileSizeNonStrict !== null && start + length > this.fileSizeNonStrict) { + return null; + } + if (length === 0) { + const buffer = new Uint8Array(0); + return new FileSlice(buffer, toDataView(buffer), 0, start, start); + } + const end = start + length; + const result = this.source._read(start, end, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION); + if (result instanceof Promise) { + return result.then((x) => { + if (!x) { + return null; + } + return new FileSlice(x.bytes, x.view, x.offset, start, end); + }); + } else { + if (!result) { return null; } - trackData = { - track, - startTimestamp: 0, - endTimestamp: 0, - firstKeyFrameTimestamp: null, - blocks: [], - presentationTimestamps: [] - }; - cluster.trackData.set(trackNumber, trackData); - } - return trackData; - } - expandLacedBlocks(blocks, track) { - for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) { - const originalBlock = blocks[blockIndex]; - if (originalBlock.lacing === BlockLacing.None) { - continue; - } - if (!originalBlock.decoded) { - originalBlock.data = this.decodeBlockData(track, originalBlock.data); - originalBlock.decoded = true; - } - const slice = FileSlice.tempFromBytes(originalBlock.data); - const frameSizes = []; - const frameCount = readU8(slice) + 1; - switch (originalBlock.lacing) { - case BlockLacing.Xiph: - { - let totalUsedSize = 0; - for (let i = 0; i < frameCount - 1; i++) { - let frameSize = 0; - while (slice.bufferPos < slice.length) { - const value = readU8(slice); - frameSize += value; - if (value < 255) { - frameSizes.push(frameSize); - totalUsedSize += frameSize; - break; - } - } - } - frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); - } - break; - case BlockLacing.FixedSize: - { - const totalDataSize = slice.length - 1; - const frameSize = Math.floor(totalDataSize / frameCount); - for (let i = 0; i < frameCount; i++) { - frameSizes.push(frameSize); - } - } - break; - case BlockLacing.Ebml: - { - const firstResult = readVarInt(slice); - assert(firstResult !== null); - let currentSize = firstResult; - frameSizes.push(currentSize); - let totalUsedSize = currentSize; - for (let i = 1; i < frameCount - 1; i++) { - const startPos = slice.bufferPos; - const diffResult = readVarInt(slice); - assert(diffResult !== null); - const unsignedDiff = diffResult; - const width = slice.bufferPos - startPos; - const bias = (1 << width * 7 - 1) - 1; - const diff = unsignedDiff - bias; - currentSize += diff; - frameSizes.push(currentSize); - totalUsedSize += currentSize; - } - frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); - } - break; - default: - assert(false); - } - assert(frameSizes.length === frameCount); - blocks.splice(blockIndex, 1); - const blockDuration = originalBlock.duration || frameCount * (track.defaultDuration ?? 0); - for (let i = 0; i < frameCount; i++) { - const frameSize = frameSizes[i]; - const frameData = readBytes(slice, frameSize); - const frameTimestamp = originalBlock.timestamp + blockDuration * i / frameCount; - const frameDuration = blockDuration / frameCount; - blocks.splice(blockIndex + i, 0, { - timestamp: frameTimestamp, - duration: frameDuration, - isKeyFrame: originalBlock.isKeyFrame, - data: frameData, - lacing: BlockLacing.None, - decoded: true, - mainAdditional: originalBlock.mainAdditional - }); - } - blockIndex += frameCount; - blockIndex--; + return new FileSlice(result.bytes, result.view, result.offset, start, end); } } - async loadSegmentMetadata(segment) { - for (const seekEntry of segment.seekEntries) { - if (seekEntry.id === EBMLId.Tags && !segment.tagsSeen) ; - else if (seekEntry.id === EBMLId.Attachments && !segment.attachmentsSeen) ; - else { - continue; - } - let slice = this.reader.requestSliceRange(segment.dataStartPos + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - continue; - const header = readElementHeader(slice); - if (!header || header.id !== seekEntry.id) - continue; - const { size } = header; - assertDefinedSize(size); - assert(!this.currentSegment); - this.currentSegment = segment; - let dataSlice = this.reader.requestSlice(slice.filePos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (dataSlice) { - this.readContiguousElements(dataSlice); - } - this.currentSegment = null; - if (seekEntry.id === EBMLId.Tags) { - segment.tagsSeen = true; - } else if (seekEntry.id === EBMLId.Attachments) { - segment.attachmentsSeen = true; - } + requestSliceRange(start, minLength, maxLength) { + if (this.source._disposed) { + throw new InputDisposedError(); } - } - readContiguousElements(slice, stopIds) { - while (slice.remainingLength >= MIN_HEADER_SIZE) { - const startPos = slice.filePos; - const foundElement = this.traverseElement(slice, stopIds); - if (!foundElement) { - return startPos; - } - } - return slice.filePos; - } - traverseElement(slice, stopIds) { - const header = readElementHeader(slice); - if (!header) { - return false; - } - if (stopIds && stopIds.includes(header.id)) { - return false; - } - const { id, size } = header; - const dataStartPos = slice.filePos; - assertDefinedSize(size); - switch (id) { - case EBMLId.DocType: - { - this.isWebM = readAsciiString(slice, size) === "webm"; - } - break; - case EBMLId.Seek: - { - if (!this.currentSegment) - break; - const seekEntry = { id: -1, segmentPosition: -1 }; - this.currentSegment.seekEntries.push(seekEntry); - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (seekEntry.id === -1 || seekEntry.segmentPosition === -1) { - this.currentSegment.seekEntries.pop(); - } - } - break; - case EBMLId.SeekID: - { - const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; - if (!lastSeekEntry) - break; - lastSeekEntry.id = readUnsignedInt(slice, size); - } - break; - case EBMLId.SeekPosition: - { - const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; - if (!lastSeekEntry) - break; - lastSeekEntry.segmentPosition = readUnsignedInt(slice, size); - } - break; - case EBMLId.TimestampScale: - { - if (!this.currentSegment) - break; - this.currentSegment.timestampScale = readUnsignedInt(slice, size); - this.currentSegment.timestampFactor = 1e9 / this.currentSegment.timestampScale; - } - break; - case EBMLId.Duration: - { - if (!this.currentSegment) - break; - this.currentSegment.duration = readFloat(slice, size); - } - break; - case EBMLId.TrackEntry: - { - if (!this.currentSegment) - break; - this.currentTrack = { - id: -1, - segment: this.currentSegment, - demuxer: this, - clusterPositionCache: [], - cuePoints: [], - disposition: { - ...DEFAULT_TRACK_DISPOSITION - }, - inputTrack: null, - codecId: null, - codecPrivate: null, - defaultDuration: null, - defaultDurationNs: null, - name: null, - languageCode: UNDETERMINED_LANGUAGE, - decodingInstructions: [], - info: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (!this.currentTrack) { - break; - } - if (this.currentTrack.decodingInstructions.some((instruction) => { - return instruction.data?.type !== "decompress" || instruction.scope !== ContentEncodingScope.Block || instruction.data.algorithm !== ContentCompAlgo.HeaderStripping; - })) { - console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`); - this.currentTrack = null; - } - if (this.currentTrack && this.currentTrack.id !== -1 && this.currentTrack.codecId && this.currentTrack.info) { - const slashIndex = this.currentTrack.codecId.indexOf("/"); - const codecIdWithoutSuffix = slashIndex === -1 ? this.currentTrack.codecId : this.currentTrack.codecId.slice(0, slashIndex); - if (this.currentTrack.info.type === "video" && this.currentTrack.info.width !== -1 && this.currentTrack.info.height !== -1) { - if (this.currentTrack.codecId === CODEC_STRING_MAP.avc) { - this.currentTrack.info.codec = "avc"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === CODEC_STRING_MAP.hevc) { - this.currentTrack.info.codec = "hevc"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp8) { - this.currentTrack.info.codec = "vp8"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp9) { - this.currentTrack.info.codec = "vp9"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.av1) { - this.currentTrack.info.codec = "av1"; - } - const videoTrack = this.currentTrack; - const inputTrack = new InputVideoTrack(this.input, new MatroskaVideoTrackBacking(videoTrack)); - this.currentTrack.inputTrack = inputTrack; - this.currentSegment.tracks.push(this.currentTrack); - } else if (this.currentTrack.info.type === "audio" && this.currentTrack.info.numberOfChannels !== -1 && this.currentTrack.info.sampleRate !== -1) { - if (codecIdWithoutSuffix === CODEC_STRING_MAP.aac) { - this.currentTrack.info.codec = "aac"; - this.currentTrack.info.aacCodecInfo = { - isMpeg2: this.currentTrack.codecId.includes("MPEG2") - }; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === CODEC_STRING_MAP.mp3) { - this.currentTrack.info.codec = "mp3"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.opus) { - this.currentTrack.info.codec = "opus"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - this.currentTrack.info.sampleRate = OPUS_SAMPLE_RATE; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vorbis) { - this.currentTrack.info.codec = "vorbis"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.flac) { - this.currentTrack.info.codec = "flac"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === "A_PCM/INT/LIT") { - if (this.currentTrack.info.bitDepth === 8) { - this.currentTrack.info.codec = "pcm-u8"; - } else if (this.currentTrack.info.bitDepth === 16) { - this.currentTrack.info.codec = "pcm-s16"; - } else if (this.currentTrack.info.bitDepth === 24) { - this.currentTrack.info.codec = "pcm-s24"; - } else if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-s32"; - } - } else if (this.currentTrack.codecId === "A_PCM/INT/BIG") { - if (this.currentTrack.info.bitDepth === 8) { - this.currentTrack.info.codec = "pcm-u8"; - } else if (this.currentTrack.info.bitDepth === 16) { - this.currentTrack.info.codec = "pcm-s16be"; - } else if (this.currentTrack.info.bitDepth === 24) { - this.currentTrack.info.codec = "pcm-s24be"; - } else if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-s32be"; - } - } else if (this.currentTrack.codecId === "A_PCM/FLOAT/IEEE") { - if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-f32"; - } else if (this.currentTrack.info.bitDepth === 64) { - this.currentTrack.info.codec = "pcm-f64"; - } - } - const audioTrack = this.currentTrack; - const inputTrack = new InputAudioTrack(this.input, new MatroskaAudioTrackBacking(audioTrack)); - this.currentTrack.inputTrack = inputTrack; - this.currentSegment.tracks.push(this.currentTrack); - } - } - this.currentTrack = null; - } - break; - case EBMLId.TrackNumber: - { - if (!this.currentTrack) - break; - this.currentTrack.id = readUnsignedInt(slice, size); - } - break; - case EBMLId.TrackType: - { - if (!this.currentTrack) - break; - const type = readUnsignedInt(slice, size); - if (type === 1) { - this.currentTrack.info = { - type: "video", - width: -1, - height: -1, - rotation: 0, - codec: null, - codecDescription: null, - colorSpace: null, - alphaMode: false - }; - } else if (type === 2) { - this.currentTrack.info = { - type: "audio", - numberOfChannels: -1, - sampleRate: -1, - bitDepth: -1, - codec: null, - codecDescription: null, - aacCodecInfo: null - }; - } - } - break; - case EBMLId.FlagEnabled: - { - if (!this.currentTrack) - break; - const enabled = readUnsignedInt(slice, size); - if (!enabled) { - this.currentTrack = null; - } - } - break; - case EBMLId.FlagDefault: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.default = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagForced: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.forced = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagOriginal: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.original = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagHearingImpaired: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.hearingImpaired = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagVisualImpaired: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.visuallyImpaired = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagCommentary: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.commentary = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.CodecID: - { - if (!this.currentTrack) - break; - this.currentTrack.codecId = readAsciiString(slice, size); - } - break; - case EBMLId.CodecPrivate: - { - if (!this.currentTrack) - break; - this.currentTrack.codecPrivate = readBytes(slice, size); - } - break; - case EBMLId.DefaultDuration: - { - if (!this.currentTrack) - break; - this.currentTrack.defaultDurationNs = readUnsignedInt(slice, size); - } - break; - case EBMLId.Name: - { - if (!this.currentTrack) - break; - this.currentTrack.name = readUnicodeString(slice, size); - } - break; - case EBMLId.Language: - { - if (!this.currentTrack) - break; - if (this.currentTrack.languageCode !== UNDETERMINED_LANGUAGE) { - break; - } - this.currentTrack.languageCode = readAsciiString(slice, size); - if (!isIso639Dash2LanguageCode(this.currentTrack.languageCode)) { - this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; - } - } - break; - case EBMLId.LanguageBCP47: - { - if (!this.currentTrack) - break; - const bcp47 = readAsciiString(slice, size); - const languageSubtag = bcp47.split("-")[0]; - if (languageSubtag) { - this.currentTrack.languageCode = languageSubtag; - } else { - this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; - } - } - break; - case EBMLId.Video: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.PixelWidth: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.width = readUnsignedInt(slice, size); - } - break; - case EBMLId.PixelHeight: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.height = readUnsignedInt(slice, size); - } - break; - case EBMLId.AlphaMode: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.alphaMode = readUnsignedInt(slice, size) === 1; - } - break; - case EBMLId.Colour: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.colorSpace = {}; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.MatrixCoefficients: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const matrixCoefficients = readUnsignedInt(slice, size); - const mapped = MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients] ?? null; - this.currentTrack.info.colorSpace.matrix = mapped; - } - break; - case EBMLId.Range: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - this.currentTrack.info.colorSpace.fullRange = readUnsignedInt(slice, size) === 2; - } - break; - case EBMLId.TransferCharacteristics: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const transferCharacteristics = readUnsignedInt(slice, size); - const mapped = TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics] ?? null; - this.currentTrack.info.colorSpace.transfer = mapped; - } - break; - case EBMLId.Primaries: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const primaries = readUnsignedInt(slice, size); - const mapped = COLOR_PRIMARIES_MAP_INVERSE[primaries] ?? null; - this.currentTrack.info.colorSpace.primaries = mapped; - } - break; - case EBMLId.Projection: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.ProjectionPoseRoll: - { - if (this.currentTrack?.info?.type !== "video") - break; - const rotation = readFloat(slice, size); - const flippedRotation = -rotation; - try { - this.currentTrack.info.rotation = normalizeRotation(flippedRotation); - } catch { - } - } - break; - case EBMLId.Audio: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.SamplingFrequency: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.sampleRate = readFloat(slice, size); - } - break; - case EBMLId.Channels: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.numberOfChannels = readUnsignedInt(slice, size); - } - break; - case EBMLId.BitDepth: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.bitDepth = readUnsignedInt(slice, size); - } - break; - case EBMLId.CuePoint: - { - if (!this.currentSegment) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentCueTime = null; - } - break; - case EBMLId.CueTime: - { - this.currentCueTime = readUnsignedInt(slice, size); - } - break; - case EBMLId.CueTrackPositions: - { - if (this.currentCueTime === null) - break; - assert(this.currentSegment); - const cuePoint = { time: this.currentCueTime, trackId: -1, clusterPosition: -1 }; - this.currentSegment.cuePoints.push(cuePoint); - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (cuePoint.trackId === -1 || cuePoint.clusterPosition === -1) { - this.currentSegment.cuePoints.pop(); - } - } - break; - case EBMLId.CueTrack: - { - const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; - if (!lastCuePoint) - break; - lastCuePoint.trackId = readUnsignedInt(slice, size); - } - break; - case EBMLId.CueClusterPosition: - { - const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; - if (!lastCuePoint) - break; - assert(this.currentSegment); - lastCuePoint.clusterPosition = this.currentSegment.dataStartPos + readUnsignedInt(slice, size); - } - break; - case EBMLId.Timestamp: - { - if (!this.currentCluster) - break; - this.currentCluster.timestamp = readUnsignedInt(slice, size); - } - break; - case EBMLId.SimpleBlock: - { - if (!this.currentCluster) - break; - const trackNumber = readVarInt(slice); - if (trackNumber === null) - break; - const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); - if (!trackData) - break; - const relativeTimestamp = readI16Be(slice); - const flags = readU8(slice); - const lacing = flags >> 1 & 3; - let isKeyFrame = !!(flags & 128); - if (trackData.track.info?.type === "audio" && trackData.track.info.codec) { - isKeyFrame = true; - } - const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); - const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; - trackData.blocks.push({ - timestamp: relativeTimestamp, - // We'll add the cluster's timestamp to this later - duration: 0, - // Will set later - isKeyFrame, - data: blockData, - lacing, - decoded: !hasDecodingInstructions, - mainAdditional: null - }); - } - break; - case EBMLId.BlockGroup: - { - if (!this.currentCluster) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentBlock = null; - } - break; - case EBMLId.Block: - { - if (!this.currentCluster) - break; - const trackNumber = readVarInt(slice); - if (trackNumber === null) - break; - const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); - if (!trackData) - break; - const relativeTimestamp = readI16Be(slice); - const flags = readU8(slice); - const lacing = flags >> 1 & 3; - const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); - const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; - this.currentBlock = { - timestamp: relativeTimestamp, - // We'll add the cluster's timestamp to this later - duration: 0, - // Will set later - isKeyFrame: true, - data: blockData, - lacing, - decoded: !hasDecodingInstructions, - mainAdditional: null - }; - trackData.blocks.push(this.currentBlock); - } - break; - case EBMLId.BlockAdditions: - { - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.BlockMore: - { - if (!this.currentBlock) - break; - this.currentBlockAdditional = { - addId: 1, - data: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (this.currentBlockAdditional.data && this.currentBlockAdditional.addId === 1) { - this.currentBlock.mainAdditional = this.currentBlockAdditional.data; - } - this.currentBlockAdditional = null; - } - break; - case EBMLId.BlockAdditional: - { - if (!this.currentBlockAdditional) - break; - this.currentBlockAdditional.data = readBytes(slice, size); - } - break; - case EBMLId.BlockAddID: - { - if (!this.currentBlockAdditional) - break; - this.currentBlockAdditional.addId = readUnsignedInt(slice, size); - } - break; - case EBMLId.BlockDuration: - { - if (!this.currentBlock) - break; - this.currentBlock.duration = readUnsignedInt(slice, size); - } - break; - case EBMLId.ReferenceBlock: - { - if (!this.currentBlock) - break; - this.currentBlock.isKeyFrame = false; - } - break; - case EBMLId.Tag: - { - this.currentTagTargetIsMovie = true; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.Targets: - { - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.TargetTypeValue: - { - const targetTypeValue = readUnsignedInt(slice, size); - if (targetTypeValue !== 50) { - this.currentTagTargetIsMovie = false; - } - } - break; - case EBMLId.TagTrackUID: - case EBMLId.TagEditionUID: - case EBMLId.TagChapterUID: - case EBMLId.TagAttachmentUID: - { - this.currentTagTargetIsMovie = false; - } - break; - case EBMLId.SimpleTag: - { - if (!this.currentTagTargetIsMovie) - break; - this.currentSimpleTagName = null; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.TagName: - { - this.currentSimpleTagName = readUnicodeString(slice, size); - } - break; - case EBMLId.TagString: - { - if (!this.currentSimpleTagName) - break; - const value = readUnicodeString(slice, size); - this.processTagValue(this.currentSimpleTagName, value); - } - break; - case EBMLId.TagBinary: - { - if (!this.currentSimpleTagName) - break; - const value = readBytes(slice, size); - this.processTagValue(this.currentSimpleTagName, value); - } - break; - case EBMLId.AttachedFile: - { - if (!this.currentSegment) - break; - this.currentAttachedFile = { - fileUid: null, - fileName: null, - fileMediaType: null, - fileData: null, - fileDescription: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - const tags = this.currentSegment.metadataTags; - if (this.currentAttachedFile.fileUid && this.currentAttachedFile.fileData) { - tags.raw ?? (tags.raw = {}); - tags.raw[this.currentAttachedFile.fileUid.toString()] = new AttachedFile(this.currentAttachedFile.fileData, this.currentAttachedFile.fileMediaType ?? void 0, this.currentAttachedFile.fileName ?? void 0, this.currentAttachedFile.fileDescription ?? void 0); - } - if (this.currentAttachedFile.fileMediaType?.startsWith("image/") && this.currentAttachedFile.fileData) { - const fileName = this.currentAttachedFile.fileName; - let kind = "unknown"; - if (fileName) { - const lowerName = fileName.toLowerCase(); - if (lowerName.startsWith("cover.")) { - kind = "coverFront"; - } else if (lowerName.startsWith("back.")) { - kind = "coverBack"; - } - } - tags.images ?? (tags.images = []); - tags.images.push({ - data: this.currentAttachedFile.fileData, - mimeType: this.currentAttachedFile.fileMediaType, - kind, - name: this.currentAttachedFile.fileName ?? void 0, - description: this.currentAttachedFile.fileDescription ?? void 0 - }); - } - this.currentAttachedFile = null; - } - break; - case EBMLId.FileUID: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileUid = readUnsignedBigInt(slice, size); - } - break; - case EBMLId.FileName: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileName = readUnicodeString(slice, size); - } - break; - case EBMLId.FileMediaType: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileMediaType = readAsciiString(slice, size); - } - break; - case EBMLId.FileData: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileData = readBytes(slice, size); - } - break; - case EBMLId.FileDescription: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileDescription = readUnicodeString(slice, size); - } - break; - case EBMLId.ContentEncodings: - { - if (!this.currentTrack) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentTrack.decodingInstructions.sort((a, b) => b.order - a.order); - } - break; - case EBMLId.ContentEncoding: - { - this.currentDecodingInstruction = { - order: 0, - scope: ContentEncodingScope.Block, - data: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (this.currentDecodingInstruction.data) { - this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction); - } - this.currentDecodingInstruction = null; - } - break; - case EBMLId.ContentEncodingOrder: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.order = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentEncodingScope: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.scope = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentCompression: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.data = { - type: "decompress", - algorithm: ContentCompAlgo.Zlib, - settings: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.ContentCompAlgo: - { - if (this.currentDecodingInstruction?.data?.type !== "decompress") - break; - this.currentDecodingInstruction.data.algorithm = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentCompSettings: - { - if (this.currentDecodingInstruction?.data?.type !== "decompress") - break; - this.currentDecodingInstruction.data.settings = readBytes(slice, size); - } - break; - case EBMLId.ContentEncryption: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.data = { - type: "decrypt" - }; - } - break; - } - slice.filePos = dataStartPos + size; - return true; - } - decodeBlockData(track, rawData) { - assert(track.decodingInstructions.length > 0); - let currentData = rawData; - for (const instruction of track.decodingInstructions) { - assert(instruction.data); - switch (instruction.data.type) { - case "decompress": - { - switch (instruction.data.algorithm) { - case ContentCompAlgo.HeaderStripping: - { - if (instruction.data.settings && instruction.data.settings.length > 0) { - const prefix = instruction.data.settings; - const newData = new Uint8Array(prefix.length + currentData.length); - newData.set(prefix, 0); - newData.set(currentData, prefix.length); - currentData = newData; - } - } - break; - } - } - break; - } - } - return currentData; - } - processTagValue(name, value) { - var _a; - if (!this.currentSegment?.metadataTags) - return; - const metadataTags = this.currentSegment.metadataTags; - metadataTags.raw ?? (metadataTags.raw = {}); - (_a = metadataTags.raw)[name] ?? (_a[name] = value); - if (typeof value === "string") { - switch (name.toLowerCase()) { - case "title": - { - metadataTags.title ?? (metadataTags.title = value); - } - break; - case "description": - { - metadataTags.description ?? (metadataTags.description = value); - } - break; - case "artist": - { - metadataTags.artist ?? (metadataTags.artist = value); - } - break; - case "album": - { - metadataTags.album ?? (metadataTags.album = value); - } - break; - case "album_artist": - { - metadataTags.albumArtist ?? (metadataTags.albumArtist = value); - } - break; - case "genre": - { - metadataTags.genre ?? (metadataTags.genre = value); - } - break; - case "comment": - { - metadataTags.comment ?? (metadataTags.comment = value); - } - break; - case "lyrics": - { - metadataTags.lyrics ?? (metadataTags.lyrics = value); - } - break; - case "date": - { - const date = new Date(value); - if (!Number.isNaN(date.getTime())) { - metadataTags.date ?? (metadataTags.date = date); - } - } - break; - case "track_number": - case "part_number": - { - const parts = value.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - metadataTags.trackNumber ?? (metadataTags.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - metadataTags.tracksTotal ?? (metadataTags.tracksTotal = tracksTotal); - } - } - break; - case "disc_number": - case "disc": - { - const discParts = value.split("/"); - const discNum = Number.parseInt(discParts[0], 10); - const discsTotal = discParts[1] && Number.parseInt(discParts[1], 10); - if (Number.isInteger(discNum) && discNum > 0) { - metadataTags.discNumber ?? (metadataTags.discNumber = discNum); - } - if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) { - metadataTags.discsTotal ?? (metadataTags.discsTotal = discsTotal); - } - } - break; - } - } - } -} -class MatroskaTrackBacking { - constructor(internalTrack) { - this.internalTrack = internalTrack; - this.packetToClusterLocation = /* @__PURE__ */ new WeakMap(); - } - getId() { - return this.internalTrack.id; - } - getCodec() { - throw new Error("Not implemented on base class."); - } - getInternalCodecId() { - return this.internalTrack.codecId; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return this.internalTrack.name; - } - getLanguageCode() { - return this.internalTrack.languageCode; - } - async getFirstTimestamp() { - const firstPacket = await this.getFirstPacket({ metadataOnly: true }); - return firstPacket?.timestamp ?? 0; - } - getTimeResolution() { - return this.internalTrack.segment.timestampFactor; - } - getDisposition() { - return this.internalTrack.disposition; - } - async getFirstPacket(options) { - return this.performClusterLookup( - null, - (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData) { - return { - blockIndex: 0, - correctBlockFound: true - }; - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - intoTimescale(timestamp) { - return roundIfAlmostInteger(timestamp * this.internalTrack.segment.timestampFactor); - } - async getPacket(timestamp, options) { - const timestampInTimescale = this.intoTimescale(timestamp); - return this.performClusterLookup(null, (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (!trackData) { - return { blockIndex: -1, correctBlockFound: false }; - } - const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.timestamp); - const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; - const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { blockIndex, correctBlockFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextPacket(packet, options) { - const locationInCluster = this.packetToClusterLocation.get(packet); - if (locationInCluster === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performClusterLookup( - locationInCluster.cluster, - (cluster) => { - if (cluster === locationInCluster.cluster) { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (locationInCluster.blockIndex + 1 < trackData.blocks.length) { - return { - blockIndex: locationInCluster.blockIndex + 1, - correctBlockFound: true - }; - } - } else { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData) { - return { - blockIndex: 0, - correctBlockFound: true - }; - } - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - async getKeyPacket(timestamp, options) { - const timestampInTimescale = this.intoTimescale(timestamp); - return this.performClusterLookup(null, (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (!trackData) { - return { blockIndex: -1, correctBlockFound: false }; - } - const index = findLastIndex(trackData.presentationTimestamps, (x) => { - const block = trackData.blocks[x.blockIndex]; - return block.isKeyFrame && x.timestamp <= timestampInTimescale; - }); - const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; - const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { blockIndex, correctBlockFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextKeyPacket(packet, options) { - const locationInCluster = this.packetToClusterLocation.get(packet); - if (locationInCluster === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performClusterLookup( - locationInCluster.cluster, - (cluster) => { - if (cluster === locationInCluster.cluster) { - const trackData = cluster.trackData.get(this.internalTrack.id); - const nextKeyFrameIndex = trackData.blocks.findIndex((x, i) => x.isKeyFrame && i > locationInCluster.blockIndex); - if (nextKeyFrameIndex !== -1) { - return { - blockIndex: nextKeyFrameIndex, - correctBlockFound: true - }; - } - } else { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData && trackData.firstKeyFrameTimestamp !== null) { - const keyFrameIndex = trackData.blocks.findIndex((x) => x.isKeyFrame); - assert(keyFrameIndex !== -1); - return { - blockIndex: keyFrameIndex, - correctBlockFound: true - }; - } - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - async fetchPacketInCluster(cluster, blockIndex, options) { - if (blockIndex === -1) { + if (start < 0) { return null; } - const trackData = cluster.trackData.get(this.internalTrack.id); - const block = trackData.blocks[blockIndex]; - assert(block); - if (!block.decoded) { - block.data = this.internalTrack.demuxer.decodeBlockData(this.internalTrack, block.data); - block.decoded = true; - } - const data = options.metadataOnly ? PLACEHOLDER_DATA : block.data; - const timestamp = block.timestamp / this.internalTrack.segment.timestampFactor; - const duration = block.duration / this.internalTrack.segment.timestampFactor; - const sideData = {}; - if (block.mainAdditional && this.internalTrack.info?.type === "video" && this.internalTrack.info.alphaMode) { - sideData.alpha = options.metadataOnly ? PLACEHOLDER_DATA : block.mainAdditional; - sideData.alphaByteLength = block.mainAdditional.byteLength; - } - const packet = new EncodedPacket(data, block.isKeyFrame ? "key" : "delta", timestamp, duration, cluster.dataStartPos + blockIndex, block.data.byteLength, sideData); - this.packetToClusterLocation.set(packet, { cluster, blockIndex }); - return packet; - } - /** Looks for a packet in the clusters while trying to load as few clusters as possible to retrieve it. */ - async performClusterLookup(startCluster, getMatchInCluster, searchTimestamp, latestTimestamp, options) { - const { demuxer, segment } = this.internalTrack; - let currentCluster = null; - let bestCluster = null; - let bestBlockIndex = -1; - if (startCluster) { - const { blockIndex, correctBlockFound } = getMatchInCluster(startCluster); - if (correctBlockFound) { - return this.fetchPacketInCluster(startCluster, blockIndex, options); - } - if (blockIndex !== -1) { - bestCluster = startCluster; - bestBlockIndex = blockIndex; - } - } - const cuePointIndex = binarySearchLessOrEqual(this.internalTrack.cuePoints, searchTimestamp, (x) => x.time); - const cuePoint = cuePointIndex !== -1 ? this.internalTrack.cuePoints[cuePointIndex] : null; - const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.clusterPositionCache, searchTimestamp, (x) => x.startTimestamp); - const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.clusterPositionCache[positionCacheIndex] : null; - const lookupEntryPosition = Math.max(cuePoint?.clusterPosition ?? 0, positionCacheEntry?.elementStartPos ?? 0) || null; - let currentPos; - if (!startCluster) { - currentPos = lookupEntryPosition ?? segment.clusterSeekStartPos; + if (this.fileSizeNonStrict !== null) { + return this.requestSlice(start, clamp$1(this.fileSizeNonStrict - start, minLength, maxLength)); } else { - if (lookupEntryPosition === null || startCluster.elementStartPos >= lookupEntryPosition) { - currentPos = startCluster.elementEndPos; - currentCluster = startCluster; + const promisedAttempt = this.requestSlice(start, maxLength); + const handleAttempt = (attempt) => { + if (attempt) { + return attempt; + } + assert(this.fileSizeNonStrict !== null); + return this.requestSlice(start, clamp$1(this.fileSizeNonStrict - start, minLength, maxLength)); + }; + if (promisedAttempt instanceof Promise) { + return promisedAttempt.then(handleAttempt); } else { - currentPos = lookupEntryPosition; + return handleAttempt(promisedAttempt); } } - while (segment.elementEndPos === null || currentPos <= segment.elementEndPos - MIN_HEADER_SIZE) { - if (currentCluster) { - const trackData = currentCluster.trackData.get(this.internalTrack.id); - if (trackData && trackData.startTimestamp > latestTimestamp) { - break; - } - } - let slice = demuxer.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementStartPos = currentPos; - const elementHeader = readElementHeader(slice); - if (!elementHeader || !LEVEL_1_EBML_IDS.includes(elementHeader.id) && elementHeader.id !== EBMLId.Void) { - const nextPos = await resync(demuxer.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(segment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); - if (nextPos) { - currentPos = nextPos; - continue; - } else { - break; - } - } - const id = elementHeader.id; - let size = elementHeader.size; - const dataStartPos = slice.filePos; - if (id === EBMLId.Cluster) { - currentCluster = await demuxer.readCluster(elementStartPos, segment); - size = currentCluster.elementEndPos - dataStartPos; - const { blockIndex, correctBlockFound } = getMatchInCluster(currentCluster); - if (correctBlockFound) { - return this.fetchPacketInCluster(currentCluster, blockIndex, options); - } - if (blockIndex !== -1) { - bestCluster = currentCluster; - bestBlockIndex = blockIndex; - } - } - if (size === void 0) { - assert(id !== EBMLId.Cluster); - const nextElementPos = await searchForNextElementId(demuxer.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); - size = nextElementPos.pos - dataStartPos; - } - const endPos = dataStartPos + size; - if (segment.elementEndPos === null) { - let slice2 = demuxer.reader.requestSliceRange(endPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const elementId = readElementId(slice2); - if (elementId === EBMLId.Segment) { - segment.elementEndPos = endPos; - break; - } - } - currentPos = endPos; + } + requestEntireFile() { + if (this.fileSizeNonStrict !== null) { + return this.requestSlice(0, this.fileSizeNonStrict); } - if (cuePoint && (!bestCluster || bestCluster.elementStartPos < cuePoint.clusterPosition)) { - const previousCuePoint = this.internalTrack.cuePoints[cuePointIndex - 1]; - assert(!previousCuePoint || previousCuePoint.time < cuePoint.time); - const newSearchTimestamp = previousCuePoint?.time ?? -Infinity; - return this.performClusterLookup(null, getMatchInCluster, newSearchTimestamp, latestTimestamp, options); - } - if (bestCluster) { - return this.fetchPacketInCluster(bestCluster, bestBlockIndex, options); - } - return null; + const CHUNK_SIZE = 1024; + return (async () => { + const chunks = []; + let currentSize = 0; + while (true) { + if (chunks.length === 1 && this.fileSizeNonStrict !== null) { + return this.requestSlice(0, this.fileSizeNonStrict); + } + const startOffset = chunks.length * CHUNK_SIZE; + let slice = this.requestSliceRange(startOffset, 0, CHUNK_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + break; + } + chunks.push(readBytes(slice, slice.length)); + currentSize += slice.length; + } + const joined = new Uint8Array(currentSize); + let offset = 0; + for (const chunk of chunks) { + joined.set(chunk, offset); + offset += chunk.length; + } + return new FileSlice(joined, toDataView(joined), 0, 0, currentSize); + })(); } } -class MatroskaVideoTrackBacking extends MatroskaTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfigPromise = null; - this.internalTrack = internalTrack; +class FileSlice { + constructor(bytes, view, offset, start, end) { + this.bytes = bytes; + this.view = view; + this.offset = offset; + this.start = start; + this.end = end; + this.bufferPos = start - offset; } - getCodec() { - return this.internalTrack.info.codec; + static tempFromBytes(bytes) { + return new FileSlice(bytes, toDataView(bytes), 0, 0, bytes.length); } - getCodedWidth() { - return this.internalTrack.info.width; + get length() { + return this.end - this.start; } - getCodedHeight() { - return this.internalTrack.info.height; + get filePos() { + return this.offset + this.bufferPos; } - getRotation() { - return this.internalTrack.info.rotation; + set filePos(value) { + this.bufferPos = value - this.offset; } - async getColorSpace() { - return { - primaries: this.internalTrack.info.colorSpace?.primaries, - transfer: this.internalTrack.info.colorSpace?.transfer, - matrix: this.internalTrack.info.colorSpace?.matrix, - fullRange: this.internalTrack.info.colorSpace?.fullRange - }; + /** The number of bytes left from the current pos to the end of the slice. */ + get remainingLength() { + return Math.max(this.end - this.filePos, 0); } - async canBeTransparent() { - return this.internalTrack.info.alphaMode; + skip(byteCount) { + this.bufferPos += byteCount; } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; + /** Creates a new subslice of this slice whose byte range must be contained within this slice. */ + slice(filePos, length = this.end - filePos) { + if (filePos < this.start || filePos + length > this.end) { + throw new RangeError("Slicing outside of original slice."); } - return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { - let firstPacket = null; - const needsPacketForAdditionalInfo = this.internalTrack.info.codec === "vp9" || this.internalTrack.info.codec === "av1" || this.internalTrack.info.codec === "avc" && !this.internalTrack.info.codecDescription || this.internalTrack.info.codec === "hevc" && !this.internalTrack.info.codecDescription; - if (needsPacketForAdditionalInfo) { - firstPacket = await this.getFirstPacket({}); - } - return { - codec: extractVideoCodecString({ - width: this.internalTrack.info.width, - height: this.internalTrack.info.height, - codec: this.internalTrack.info.codec, - codecDescription: this.internalTrack.info.codecDescription, - colorSpace: this.internalTrack.info.colorSpace, - avcType: 1, - // We don't know better (or do we?) so just assume 'avc1' - avcCodecInfo: this.internalTrack.info.codec === "avc" && firstPacket ? extractAvcDecoderConfigurationRecord(firstPacket.data) : null, - hevcCodecInfo: this.internalTrack.info.codec === "hevc" && firstPacket ? extractHevcDecoderConfigurationRecord(firstPacket.data) : null, - vp9CodecInfo: this.internalTrack.info.codec === "vp9" && firstPacket ? extractVp9CodecInfoFromPacket(firstPacket.data) : null, - av1CodecInfo: this.internalTrack.info.codec === "av1" && firstPacket ? extractAv1CodecInfoFromPacket(firstPacket.data) : null - }), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? void 0, - colorSpace: this.internalTrack.info.colorSpace ?? void 0 - }; - })()); + return new FileSlice(this.bytes, this.view, this.offset, filePos, filePos + length); } } -class MatroskaAudioTrackBacking extends MatroskaTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfig = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getNumberOfChannels() { - return this.internalTrack.info.numberOfChannels; - } - getSampleRate() { - return this.internalTrack.info.sampleRate; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfig ?? (this.decoderConfig = { - codec: extractAudioCodecString({ - codec: this.internalTrack.info.codec, - codecDescription: this.internalTrack.info.codecDescription, - aacCodecInfo: this.internalTrack.info.aacCodecInfo - }), - numberOfChannels: this.internalTrack.info.numberOfChannels, - sampleRate: this.internalTrack.info.sampleRate, - description: this.internalTrack.info.codecDescription ?? void 0 - }); - } -} -const FRAME_HEADER_SIZE = 4; -const SAMPLING_RATES = [44100, 48e3, 32e3]; -const KILOBIT_RATES = [ - // lowSamplingFrequency === 0 - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - // layer = 0 - -1, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224, - 256, - 320, - -1, - // layer 1 - -1, - 32, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224, - 256, - 320, - 384, - -1, - // layer = 2 - -1, - 32, - 64, - 96, - 128, - 160, - 192, - 224, - 256, - 288, - 320, - 352, - 384, - 416, - 448, - -1, - // layer = 3 - // lowSamplingFrequency === 1 - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - // layer = 0 - -1, - 8, - 16, - 24, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - -1, - // layer = 1 - -1, - 8, - 16, - 24, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - -1, - // layer = 2 - -1, - 32, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - 176, - 192, - 224, - 256, - -1 - // layer = 3 -]; -const XING = 1483304551; -const INFO = 1231971951; -const computeMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate, padding) => { - if (layer === 0) { - return 0; - } else if (layer === 1) { - return Math.floor(144 * bitrate / (sampleRate << lowSamplingFrequency)) + padding; - } else if (layer === 2) { - return Math.floor(144 * bitrate / sampleRate) + padding; - } else { - return (Math.floor(12 * bitrate / sampleRate) + padding) * 4; +const checkIsInRange = (slice, bytesToRead) => { + if (slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) { + throw new RangeError(`Tried reading [${slice.filePos}, ${slice.filePos + bytesToRead}), but slice is [${slice.start}, ${slice.end}). This is likely an internal error, please report it alongside the file that caused it.`); } }; -const getXingOffset = (mpegVersionId, channel) => { - return mpegVersionId === 3 ? channel === 3 ? 21 : 36 : channel === 3 ? 13 : 21; +const readBytes = (slice, length) => { + checkIsInRange(slice, length); + const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length); + slice.bufferPos += length; + return bytes; }; -const readFrameHeader$1 = (word, remainingBytes) => { - const firstByte = word >>> 24; - const secondByte = word >>> 16 & 255; - const thirdByte = word >>> 8 & 255; - const fourthByte = word & 255; - if (firstByte !== 255 && secondByte !== 255 && thirdByte !== 255 && fourthByte !== 255) { - return { - header: null, - bytesAdvanced: 4 - }; - } - if (firstByte !== 255) { - return { header: null, bytesAdvanced: 1 }; - } - if ((secondByte & 224) !== 224) { - return { header: null, bytesAdvanced: 1 }; - } - let lowSamplingFrequency = 0; - let mpeg25 = 0; - if (secondByte & 1 << 4) { - lowSamplingFrequency = secondByte & 1 << 3 ? 0 : 1; - } else { - lowSamplingFrequency = 1; - mpeg25 = 1; - } - const mpegVersionId = secondByte >> 3 & 3; - const layer = secondByte >> 1 & 3; - const bitrateIndex = thirdByte >> 4 & 15; - const frequencyIndex = (thirdByte >> 2 & 3) % 3; - const padding = thirdByte >> 1 & 1; - const channel = fourthByte >> 6 & 3; - const modeExtension = fourthByte >> 4 & 3; - const copyright = fourthByte >> 3 & 1; - const original = fourthByte >> 2 & 1; - const emphasis = fourthByte & 3; - const kilobitRate = KILOBIT_RATES[lowSamplingFrequency * 16 * 4 + layer * 16 + bitrateIndex]; - if (kilobitRate === -1) { - return { header: null, bytesAdvanced: 1 }; - } - const bitrate = kilobitRate * 1e3; - const sampleRate = SAMPLING_RATES[frequencyIndex] >> lowSamplingFrequency + mpeg25; - const frameLength = computeMp3FrameSize(lowSamplingFrequency, layer, bitrate, sampleRate, padding); - if (remainingBytes !== null && remainingBytes < frameLength) { - return { header: null, bytesAdvanced: 1 }; - } - let audioSamplesInFrame; - if (mpegVersionId === 3) { - audioSamplesInFrame = layer === 3 ? 384 : 1152; - } else { - if (layer === 3) { - audioSamplesInFrame = 384; - } else if (layer === 2) { - audioSamplesInFrame = 1152; - } else { - audioSamplesInFrame = 576; - } - } - return { - header: { - totalSize: frameLength, - mpegVersionId, - layer, - bitrate, - frequencyIndex, - sampleRate, - channel, - modeExtension, - copyright, - original, - emphasis, - audioSamplesInFrame - }, - bytesAdvanced: 1 - }; +const readU8 = (slice) => { + checkIsInRange(slice, 1); + return slice.view.getUint8(slice.bufferPos++); }; -const decodeSynchsafe = (synchsafed) => { - let mask = 2130706432; - let unsynchsafed = 0; - while (mask !== 0) { - unsynchsafed >>= 1; - unsynchsafed |= synchsafed & mask; - mask >>= 8; +const readU16 = (slice, littleEndian) => { + checkIsInRange(slice, 2); + const value = slice.view.getUint16(slice.bufferPos, littleEndian); + slice.bufferPos += 2; + return value; +}; +const readU16Be = (slice) => { + checkIsInRange(slice, 2); + const value = slice.view.getUint16(slice.bufferPos, false); + slice.bufferPos += 2; + return value; +}; +const readU24Be = (slice) => { + checkIsInRange(slice, 3); + const value = getUint24(slice.view, slice.bufferPos, false); + slice.bufferPos += 3; + return value; +}; +const readI16Be = (slice) => { + checkIsInRange(slice, 2); + const value = slice.view.getInt16(slice.bufferPos, false); + slice.bufferPos += 2; + return value; +}; +const readU32 = (slice, littleEndian) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, littleEndian); + slice.bufferPos += 4; + return value; +}; +const readU32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; +}; +const readU32Le = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, true); + slice.bufferPos += 4; + return value; +}; +const readI32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getInt32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; +}; +const readI32Le = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getInt32(slice.bufferPos, true); + slice.bufferPos += 4; + return value; +}; +const readU64 = (slice, littleEndian) => { + let low; + let high; + if (littleEndian) { + low = readU32(slice, true); + high = readU32(slice, true); + } else { + high = readU32(slice, false); + low = readU32(slice, false); } - return unsynchsafed; + return high * 4294967296 + low; +}; +const readU64Be = (slice) => { + const high = readU32Be(slice); + const low = readU32Be(slice); + return high * 4294967296 + low; +}; +const readI64Be = (slice) => { + const high = readI32Be(slice); + const low = readU32Be(slice); + return high * 4294967296 + low; +}; +const readI64Le = (slice) => { + const low = readU32Le(slice); + const high = readI32Le(slice); + return high * 4294967296 + low; +}; +const readF32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getFloat32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; +}; +const readF64Be = (slice) => { + checkIsInRange(slice, 8); + const value = slice.view.getFloat64(slice.bufferPos, false); + slice.bufferPos += 8; + return value; +}; +const readAscii = (slice, length) => { + checkIsInRange(slice, length); + let str = ""; + for (let i = 0; i < length; i++) { + str += String.fromCharCode(slice.bytes[slice.bufferPos++]); + } + return str; +}; +const readAllLines = (slice, length, options) => { + const text = textDecoder.decode(readBytes(slice, length)); + const lines = text.split("\n").map((x) => x.trim()).filter((x) => x.length > 0 && !options?.ignore?.(x)); + return lines; }; var Id3V2HeaderFlags; (function(Id3V2HeaderFlags2) { @@ -10355,7 +20822,7 @@ const readId3V2Header = (slice) => { return { majorVersion, revision, flags, size }; }; const parseId3V2Tag = (slice, header, tags) => { - var _a, _b, _c, _d; + var _a, _b, _c, _d, _e; if (![2, 3, 4].includes(header.majorVersion)) { console.warn(`Unsupported ID3v2 major version: ${header.majorVersion}`); return; @@ -10408,10 +20875,16 @@ const parseId3V2Tag = (slice, header, tags) => { reader.ununsynchronizeRegion(reader.pos, frameEndPos); } tags.raw ?? (tags.raw = {}); - if (frame.id[0] === "T") { - (_a = tags.raw)[_b = frame.id] ?? (_a[_b] = reader.readId3V2EncodingAndText(frameEndPos)); + if (frame.id === "TXXX") { + const txxx = (_a = tags.raw)["TXXX"] ?? (_a["TXXX"] = {}); + const encoding = reader.readId3V2TextEncoding(); + const description = reader.readId3V2Text(encoding, frameEndPos); + const value = reader.readId3V2Text(encoding, frameEndPos); + txxx[description] ?? (txxx[description] = value); + } else if (frame.id[0] === "T") { + (_b = tags.raw)[_c = frame.id] ?? (_b[_c] = reader.readId3V2EncodingAndText(frameEndPos)); } else { - (_c = tags.raw)[_d = frame.id] ?? (_c[_d] = reader.readBytes(frame.size)); + (_d = tags.raw)[_e = frame.id] ?? (_d[_e] = reader.readBytes(frame.size)); } reader.pos = frameStartPos; switch (frame.id) { @@ -10757,3701 +21230,6 @@ class Id3V2Reader { return this.readId3V2Text(encoding, until); } } -const readNextFrameHeader = async (reader, startPos, until) => { - let currentPos = startPos; - while (until === null || currentPos < until) { - let slice = reader.requestSlice(currentPos, FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const word = readU32Be(slice); - const result = readFrameHeader$1(word, reader.fileSize !== null ? reader.fileSize - currentPos : null); - if (result.header) { - return { header: result.header, startPos: currentPos }; - } - currentPos += result.bytesAdvanced; - } - return null; -}; -class Mp3Demuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.firstFrameHeader = null; - this.loadedSamples = []; - this.metadataTags = null; - this.tracks = []; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.lastLoadedPos = 0; - this.nextTimestampInSamples = 0; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - while (!this.firstFrameHeader && !this.lastSampleLoaded) { - await this.advanceReader(); - } - if (!this.firstFrameHeader) { - throw new Error("No valid MP3 frame found."); - } - this.tracks = [new InputAudioTrack(this.input, new Mp3AudioTrackBacking(this))]; - })()); - } - async advanceReader() { - if (this.lastLoadedPos === 0) { - while (true) { - let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) { - this.lastSampleLoaded = true; - return; - } - const id3V2Header = readId3V2Header(slice2); - if (!id3V2Header) { - break; - } - this.lastLoadedPos = slice2.filePos + id3V2Header.size; - } - } - const result = await readNextFrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize); - if (!result) { - this.lastSampleLoaded = true; - return; - } - const header = result.header; - this.lastLoadedPos = result.startPos + header.totalSize - 1; - const xingOffset = getXingOffset(header.mpegVersionId, header.channel); - let slice = this.reader.requestSlice(result.startPos + xingOffset, 4); - if (slice instanceof Promise) - slice = await slice; - if (slice) { - const word = readU32Be(slice); - const isXing = word === XING || word === INFO; - if (isXing) { - return; - } - } - if (!this.firstFrameHeader) { - this.firstFrameHeader = header; - } - if (header.sampleRate !== this.firstFrameHeader.sampleRate) { - console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${header.sampleRate} Hz. Might be a bug, so please report this file.`); - } - const sampleDuration = header.audioSamplesInFrame / this.firstFrameHeader.sampleRate; - const sample = { - timestamp: this.nextTimestampInSamples / this.firstFrameHeader.sampleRate, - duration: sampleDuration, - dataStart: result.startPos, - dataSize: header.totalSize - }; - this.loadedSamples.push(sample); - this.nextTimestampInSamples += header.audioSamplesInFrame; - return; - } - async getMimeType() { - return "audio/mpeg"; - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getMetadataTags() { - const release = await this.readingMutex.acquire(); - try { - await this.readMetadata(); - if (this.metadataTags) { - return this.metadataTags; - } - this.metadataTags = {}; - let currentPos = 0; - let id3V2HeaderFound = false; - while (true) { - let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) - break; - const id3V2Header = readId3V2Header(headerSlice); - if (!id3V2Header) { - break; - } - id3V2HeaderFound = true; - let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); - if (contentSlice instanceof Promise) - contentSlice = await contentSlice; - if (!contentSlice) - break; - parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); - currentPos = headerSlice.filePos + id3V2Header.size; - } - if (!id3V2HeaderFound && this.reader.fileSize !== null && this.reader.fileSize >= ID3_V1_TAG_SIZE) { - let slice = this.reader.requestSlice(this.reader.fileSize - ID3_V1_TAG_SIZE, ID3_V1_TAG_SIZE); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const tag = readAscii(slice, 3); - if (tag === "TAG") { - parseId3V1Tag(slice, this.metadataTags); - } - } - return this.metadataTags; - } finally { - release(); - } - } -} -class Mp3AudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - async getFirstTimestamp() { - return 0; - } - getTimeResolution() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.sampleRate / this.demuxer.firstFrameHeader.audioSamplesInFrame; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getCodec() { - return "mp3"; - } - getInternalCodecId() { - return null; - } - getNumberOfChannels() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2; - } - getSampleRate() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getDecoderConfig() { - assert(this.demuxer.firstFrameHeader); - return { - codec: "mp3", - numberOfChannels: this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2, - sampleRate: this.demuxer.firstFrameHeader.sampleRate - }; - } - async getPacketAtIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.dataSize); - } - return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); - if (sampleIndex === -1) { - throw new Error("Packet was not created from this track."); - } - const nextIndex = sampleIndex + 1; - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - async getPacket(timestamp, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); - if (index === -1 && this.demuxer.loadedSamples.length > 0) { - return null; - } - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(index, options); - } - if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { - return this.getPacketAtIndex(index, options); - } - await this.demuxer.advanceReader(); - } - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } -} -const OGGS = 1399285583; -const OGG_CRC_POLYNOMIAL = 79764919; -const OGG_CRC_TABLE = new Uint32Array(256); -for (let n = 0; n < 256; n++) { - let crc = n << 24; - for (let k = 0; k < 8; k++) { - crc = crc & 2147483648 ? crc << 1 ^ OGG_CRC_POLYNOMIAL : crc << 1; - } - OGG_CRC_TABLE[n] = crc >>> 0 & 4294967295; -} -const computeOggPageCrc = (bytes) => { - const view = toDataView(bytes); - const originalChecksum = view.getUint32(22, true); - view.setUint32(22, 0, true); - let crc = 0; - for (let i = 0; i < bytes.length; i++) { - const byte = bytes[i]; - crc = (crc << 8 ^ OGG_CRC_TABLE[crc >>> 24 ^ byte]) >>> 0; - } - view.setUint32(22, originalChecksum, true); - return crc; -}; -const extractSampleMetadata = (data, codecInfo, vorbisLastBlocksize) => { - let durationInSamples = 0; - let currentBlocksize = null; - if (data.length > 0) { - if (codecInfo.codec === "vorbis") { - assert(codecInfo.vorbisInfo); - const vorbisModeCount = codecInfo.vorbisInfo.modeBlockflags.length; - const bitCount = ilog(vorbisModeCount - 1); - const modeMask = (1 << bitCount) - 1 << 1; - const modeNumber = (data[0] & modeMask) >> 1; - if (modeNumber >= codecInfo.vorbisInfo.modeBlockflags.length) { - throw new Error("Invalid mode number."); - } - let prevBlocksize = vorbisLastBlocksize; - const blockflag = codecInfo.vorbisInfo.modeBlockflags[modeNumber]; - currentBlocksize = codecInfo.vorbisInfo.blocksizes[blockflag]; - if (blockflag === 1) { - const prevMask = (modeMask | 1) + 1; - const flag = data[0] & prevMask ? 1 : 0; - prevBlocksize = codecInfo.vorbisInfo.blocksizes[flag]; - } - durationInSamples = prevBlocksize !== null ? prevBlocksize + currentBlocksize >> 2 : 0; - } else if (codecInfo.codec === "opus") { - const toc = parseOpusTocByte(data); - durationInSamples = toc.durationInSamples; - } - } - return { - durationInSamples, - vorbisBlockSize: currentBlocksize - }; -}; -const buildOggMimeType = (info) => { - let string = "audio/ogg"; - if (info.codecStrings) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; - } - return string; -}; -const MIN_PAGE_HEADER_SIZE = 27; -const MAX_PAGE_HEADER_SIZE = 27 + 255; -const MAX_PAGE_SIZE = MAX_PAGE_HEADER_SIZE + 255 * 255; -const readPageHeader = (slice) => { - const startPos = slice.filePos; - const capturePattern = readU32Le(slice); - if (capturePattern !== OGGS) { - return null; - } - slice.skip(1); - const headerType = readU8(slice); - const granulePosition = readI64Le(slice); - const serialNumber = readU32Le(slice); - const sequenceNumber = readU32Le(slice); - const checksum = readU32Le(slice); - const numberPageSegments = readU8(slice); - const lacingValues = new Uint8Array(numberPageSegments); - for (let i = 0; i < numberPageSegments; i++) { - lacingValues[i] = readU8(slice); - } - const headerSize = 27 + numberPageSegments; - const dataSize = lacingValues.reduce((a, b) => a + b, 0); - const totalSize = headerSize + dataSize; - return { - headerStartPos: startPos, - totalSize, - dataStartPos: startPos + headerSize, - dataSize, - headerType, - granulePosition, - serialNumber, - sequenceNumber, - checksum, - lacingValues - }; -}; -const findNextPageHeader = (slice, until) => { - while (slice.filePos < until - (4 - 1)) { - const word = readU32Le(slice); - const firstByte = word & 255; - const secondByte = word >>> 8 & 255; - const thirdByte = word >>> 16 & 255; - const fourthByte = word >>> 24 & 255; - const O = 79; - if (firstByte !== O && secondByte !== O && thirdByte !== O && fourthByte !== O) { - continue; - } - slice.skip(-4); - if (word === OGGS) { - return true; - } - slice.skip(1); - } - return false; -}; -class OggDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.bitstreams = []; - this.tracks = []; - this.metadataTags = {}; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const page = readPageHeader(slice); - if (!page) { - break; - } - const isBos = !!(page.headerType & 2); - if (!isBos) { - break; - } - this.bitstreams.push({ - serialNumber: page.serialNumber, - bosPage: page, - description: null, - numberOfChannels: -1, - sampleRate: -1, - codecInfo: { - codec: null, - vorbisInfo: null, - opusInfo: null - }, - lastMetadataPacket: null - }); - currentPos = page.headerStartPos + page.totalSize; - } - for (const bitstream of this.bitstreams) { - const firstPacket = await this.readPacket(bitstream.bosPage, 0); - if (!firstPacket) { - continue; - } - if ( - // Check for Vorbis - firstPacket.data.byteLength >= 7 && firstPacket.data[0] === 1 && firstPacket.data[1] === 118 && firstPacket.data[2] === 111 && firstPacket.data[3] === 114 && firstPacket.data[4] === 98 && firstPacket.data[5] === 105 && firstPacket.data[6] === 115 - ) { - await this.readVorbisMetadata(firstPacket, bitstream); - } else if ( - // Check for Opus - firstPacket.data.byteLength >= 8 && firstPacket.data[0] === 79 && firstPacket.data[1] === 112 && firstPacket.data[2] === 117 && firstPacket.data[3] === 115 && firstPacket.data[4] === 72 && firstPacket.data[5] === 101 && firstPacket.data[6] === 97 && firstPacket.data[7] === 100 - ) { - await this.readOpusMetadata(firstPacket, bitstream); - } - if (bitstream.codecInfo.codec !== null) { - this.tracks.push(new InputAudioTrack(this.input, new OggAudioTrackBacking(bitstream, this))); - } - } - })()); - } - async readVorbisMetadata(firstPacket, bitstream) { - let nextPacketPosition = await this.findNextPacketStart(firstPacket); - if (!nextPacketPosition) { - return; - } - const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!secondPacket) { - return; - } - nextPacketPosition = await this.findNextPacketStart(secondPacket); - if (!nextPacketPosition) { - return; - } - const thirdPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!thirdPacket) { - return; - } - if (secondPacket.data[0] !== 3 || thirdPacket.data[0] !== 5) { - return; - } - const lacingValues = []; - const addBytesToSegmentTable = (bytes) => { - while (true) { - lacingValues.push(Math.min(255, bytes)); - if (bytes < 255) { - break; - } - bytes -= 255; - } - }; - addBytesToSegmentTable(firstPacket.data.length); - addBytesToSegmentTable(secondPacket.data.length); - const description = new Uint8Array(1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length + thirdPacket.data.length); - description[0] = 2; - description.set(lacingValues, 1); - description.set(firstPacket.data, 1 + lacingValues.length); - description.set(secondPacket.data, 1 + lacingValues.length + firstPacket.data.length); - description.set(thirdPacket.data, 1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length); - bitstream.codecInfo.codec = "vorbis"; - bitstream.description = description; - bitstream.lastMetadataPacket = thirdPacket; - const view = toDataView(firstPacket.data); - bitstream.numberOfChannels = view.getUint8(11); - bitstream.sampleRate = view.getUint32(12, true); - const blockSizeByte = view.getUint8(28); - bitstream.codecInfo.vorbisInfo = { - blocksizes: [ - 1 << (blockSizeByte & 15), - 1 << (blockSizeByte >> 4) - ], - modeBlockflags: parseModesFromVorbisSetupPacket(thirdPacket.data).modeBlockflags - }; - readVorbisComments(secondPacket.data.subarray(7), this.metadataTags); - } - async readOpusMetadata(firstPacket, bitstream) { - const nextPacketPosition = await this.findNextPacketStart(firstPacket); - if (!nextPacketPosition) { - return; - } - const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!secondPacket) { - return; - } - bitstream.codecInfo.codec = "opus"; - bitstream.description = firstPacket.data; - bitstream.lastMetadataPacket = secondPacket; - const header = parseOpusIdentificationHeader(firstPacket.data); - bitstream.numberOfChannels = header.outputChannelCount; - bitstream.sampleRate = OPUS_SAMPLE_RATE; - bitstream.codecInfo.opusInfo = { - preSkip: header.preSkip - }; - readVorbisComments(secondPacket.data.subarray(8), this.metadataTags); - } - async readPacket(startPage, startSegmentIndex) { - assert(startSegmentIndex < startPage.lacingValues.length); - let startDataOffset = 0; - for (let i = 0; i < startSegmentIndex; i++) { - startDataOffset += startPage.lacingValues[i]; - } - let currentPage = startPage; - let currentDataOffset = startDataOffset; - let currentSegmentIndex = startSegmentIndex; - const chunks = []; - outer: while (true) { - let pageSlice = this.reader.requestSlice(currentPage.dataStartPos, currentPage.dataSize); - if (pageSlice instanceof Promise) - pageSlice = await pageSlice; - assert(pageSlice); - const pageData = readBytes(pageSlice, currentPage.dataSize); - while (true) { - if (currentSegmentIndex === currentPage.lacingValues.length) { - chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); - break; - } - const lacingValue = currentPage.lacingValues[currentSegmentIndex]; - currentDataOffset += lacingValue; - if (lacingValue < 255) { - chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); - break outer; - } - currentSegmentIndex++; - } - let currentPos = currentPage.headerStartPos + currentPage.totalSize; - while (true) { - let headerSlice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) { - return null; - } - const nextPage = readPageHeader(headerSlice); - if (!nextPage) { - return null; - } - currentPage = nextPage; - if (currentPage.serialNumber === startPage.serialNumber) { - break; - } - currentPos = currentPage.headerStartPos + currentPage.totalSize; - } - startDataOffset = 0; - currentDataOffset = 0; - currentSegmentIndex = 0; - } - const totalPacketSize = chunks.reduce((sum, chunk) => sum + chunk.length, 0); - if (totalPacketSize === 0) { - return null; - } - const packetData = new Uint8Array(totalPacketSize); - let offset = 0; - for (let i = 0; i < chunks.length; i++) { - const chunk = chunks[i]; - packetData.set(chunk, offset); - offset += chunk.length; - } - return { - data: packetData, - endPage: currentPage, - endSegmentIndex: currentSegmentIndex - }; - } - async findNextPacketStart(lastPacket) { - if (lastPacket.endSegmentIndex < lastPacket.endPage.lacingValues.length - 1) { - return { startPage: lastPacket.endPage, startSegmentIndex: lastPacket.endSegmentIndex + 1 }; - } - const isEos = !!(lastPacket.endPage.headerType & 4); - if (isEos) { - return null; - } - let currentPos = lastPacket.endPage.headerStartPos + lastPacket.endPage.totalSize; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - const nextPage = readPageHeader(slice); - if (!nextPage) { - return null; - } - if (nextPage.serialNumber === lastPacket.endPage.serialNumber) { - return { startPage: nextPage, startSegmentIndex: 0 }; - } - currentPos = nextPage.headerStartPos + nextPage.totalSize; - } - } - async getMimeType() { - await this.readMetadata(); - const codecStrings = await Promise.all(this.tracks.map((x) => x.getCodecParameterString())); - return buildOggMimeType({ - codecStrings: codecStrings.filter(Boolean) - }); - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } -} -class OggAudioTrackBacking { - constructor(bitstream, demuxer) { - this.bitstream = bitstream; - this.demuxer = demuxer; - this.encodedPacketToMetadata = /* @__PURE__ */ new WeakMap(); - this.sequentialScanCache = []; - this.sequentialScanMutex = new AsyncMutex(); - this.internalSampleRate = bitstream.codecInfo.codec === "opus" ? OPUS_SAMPLE_RATE : bitstream.sampleRate; - } - getId() { - return this.bitstream.serialNumber; - } - getNumberOfChannels() { - return this.bitstream.numberOfChannels; - } - getSampleRate() { - return this.bitstream.sampleRate; - } - getTimeResolution() { - return this.bitstream.sampleRate; - } - getCodec() { - return this.bitstream.codecInfo.codec; - } - getInternalCodecId() { - return null; - } - async getDecoderConfig() { - assert(this.bitstream.codecInfo.codec); - return { - codec: this.bitstream.codecInfo.codec, - numberOfChannels: this.bitstream.numberOfChannels, - sampleRate: this.bitstream.sampleRate, - description: this.bitstream.description ?? void 0 - }; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - granulePositionToTimestampInSamples(granulePosition) { - if (this.bitstream.codecInfo.codec === "opus") { - assert(this.bitstream.codecInfo.opusInfo); - return granulePosition - this.bitstream.codecInfo.opusInfo.preSkip; - } - return granulePosition; - } - createEncodedPacketFromOggPacket(packet, additional, options) { - if (!packet) { - return null; - } - const { durationInSamples, vorbisBlockSize } = extractSampleMetadata(packet.data, this.bitstream.codecInfo, additional.vorbisLastBlocksize); - const encodedPacket = new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : packet.data, "key", Math.max(0, additional.timestampInSamples) / this.internalSampleRate, durationInSamples / this.internalSampleRate, packet.endPage.headerStartPos + packet.endSegmentIndex, packet.data.byteLength); - this.encodedPacketToMetadata.set(encodedPacket, { - packet, - timestampInSamples: additional.timestampInSamples, - durationInSamples, - vorbisLastBlockSize: additional.vorbisLastBlocksize, - vorbisBlockSize - }); - return encodedPacket; - } - async getFirstPacket(options) { - assert(this.bitstream.lastMetadataPacket); - const packetPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); - if (!packetPosition) { - return null; - } - let timestampInSamples = 0; - if (this.bitstream.codecInfo.codec === "opus") { - assert(this.bitstream.codecInfo.opusInfo); - timestampInSamples -= this.bitstream.codecInfo.opusInfo.preSkip; - } - const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); - return this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples, - vorbisLastBlocksize: null - }, options); - } - async getNextPacket(prevPacket, options) { - const prevMetadata = this.encodedPacketToMetadata.get(prevPacket); - if (!prevMetadata) { - throw new Error("Packet was not created from this track."); - } - const packetPosition = await this.demuxer.findNextPacketStart(prevMetadata.packet); - if (!packetPosition) { - return null; - } - const timestampInSamples = prevMetadata.timestampInSamples + prevMetadata.durationInSamples; - const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); - return this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples, - vorbisLastBlocksize: prevMetadata.vorbisBlockSize - }, options); - } - async getPacket(timestamp, options) { - if (this.demuxer.reader.fileSize === null) { - return this.getPacketSequential(timestamp, options); - } - const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); - if (timestampInSamples === 0) { - return this.getFirstPacket(options); - } - if (timestampInSamples < 0) { - return null; - } - assert(this.bitstream.lastMetadataPacket); - const startPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); - if (!startPosition) { - return null; - } - let lowPage = startPosition.startPage; - let high = this.demuxer.reader.fileSize; - const lowPages = [lowPage]; - outer: while (lowPage.headerStartPos + lowPage.totalSize < high) { - const low = lowPage.headerStartPos; - const mid = Math.floor((low + high) / 2); - let searchStartPos = mid; - while (true) { - const until = Math.min(searchStartPos + MAX_PAGE_SIZE, high - MIN_PAGE_HEADER_SIZE); - let searchSlice = this.demuxer.reader.requestSlice(searchStartPos, until - searchStartPos); - if (searchSlice instanceof Promise) - searchSlice = await searchSlice; - assert(searchSlice); - const found = findNextPageHeader(searchSlice, until); - if (!found) { - high = mid + MIN_PAGE_HEADER_SIZE; - continue outer; - } - let headerSlice = this.demuxer.reader.requestSliceRange(searchSlice.filePos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const page = readPageHeader(headerSlice); - assert(page); - let pageValid = false; - if (page.serialNumber === this.bitstream.serialNumber) { - pageValid = true; - } else { - let pageSlice = this.demuxer.reader.requestSlice(page.headerStartPos, page.totalSize); - if (pageSlice instanceof Promise) - pageSlice = await pageSlice; - assert(pageSlice); - const bytes = readBytes(pageSlice, page.totalSize); - const crc = computeOggPageCrc(bytes); - pageValid = crc === page.checksum; - } - if (!pageValid) { - searchStartPos = page.headerStartPos + 4; - continue; - } - if (pageValid && page.serialNumber !== this.bitstream.serialNumber) { - searchStartPos = page.headerStartPos + page.totalSize; - continue; - } - const isContinuationPage = page.granulePosition === -1; - if (isContinuationPage) { - searchStartPos = page.headerStartPos + page.totalSize; - continue; - } - if (this.granulePositionToTimestampInSamples(page.granulePosition) > timestampInSamples) { - high = page.headerStartPos; - } else { - lowPage = page; - lowPages.push(page); - } - continue outer; - } - } - let lowerPage = startPosition.startPage; - for (const otherLowPage of lowPages) { - if (otherLowPage.granulePosition === lowPage.granulePosition) { - break; - } - if (!lowerPage || otherLowPage.headerStartPos > lowerPage.headerStartPos) { - lowerPage = otherLowPage; - } - } - let currentPage = lowerPage; - const previousPages = [currentPage]; - while (true) { - if (currentPage.serialNumber === this.bitstream.serialNumber && currentPage.granulePosition === lowPage.granulePosition) { - break; - } - const nextPos = currentPage.headerStartPos + currentPage.totalSize; - let slice = this.demuxer.reader.requestSliceRange(nextPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const nextPage = readPageHeader(slice); - assert(nextPage); - currentPage = nextPage; - if (currentPage.serialNumber === this.bitstream.serialNumber) { - previousPages.push(currentPage); - } - } - assert(currentPage.granulePosition !== -1); - let currentSegmentIndex = null; - let currentTimestampInSamples; - let currentTimestampIsCorrect; - let endPage = currentPage; - let endSegmentIndex = 0; - if (currentPage.headerStartPos === startPosition.startPage.headerStartPos) { - currentTimestampInSamples = this.granulePositionToTimestampInSamples(0); - currentTimestampIsCorrect = true; - currentSegmentIndex = 0; - } else { - currentTimestampInSamples = 0; - currentTimestampIsCorrect = false; - for (let i = currentPage.lacingValues.length - 1; i >= 0; i--) { - const value = currentPage.lacingValues[i]; - if (value < 255) { - currentSegmentIndex = i + 1; - break; - } - } - if (currentSegmentIndex === null) { - throw new Error("Invalid page with granule position: no packets end on this page."); - } - endSegmentIndex = currentSegmentIndex - 1; - const pseudopacket = { - data: PLACEHOLDER_DATA, - endPage, - endSegmentIndex - }; - const nextPosition = await this.demuxer.findNextPacketStart(pseudopacket); - if (nextPosition) { - const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); - assert(endPosition); - const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); - if (startPosition2) { - currentPage = startPosition2.page; - currentSegmentIndex = startPosition2.segmentIndex; - } - } else { - while (true) { - const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); - if (!endPosition) { - break; - } - const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); - if (!startPosition2) { - break; - } - currentPage = startPosition2.page; - currentSegmentIndex = startPosition2.segmentIndex; - if (endPosition.page.headerStartPos !== endPage.headerStartPos) { - endPage = endPosition.page; - endSegmentIndex = endPosition.segmentIndex; - break; - } - } - } - } - let lastEncodedPacket = null; - let lastEncodedPacketMetadata = null; - while (currentPage !== null) { - assert(currentSegmentIndex !== null); - const packet = await this.demuxer.readPacket(currentPage, currentSegmentIndex); - if (!packet) { - break; - } - const skipPacket = currentPage.headerStartPos === startPosition.startPage.headerStartPos && currentSegmentIndex < startPosition.startSegmentIndex; - if (!skipPacket) { - let encodedPacket = this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples: currentTimestampInSamples, - vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null - }, options); - assert(encodedPacket); - let encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); - assert(encodedPacketMetadata); - if (!currentTimestampIsCorrect && packet.endPage.headerStartPos === endPage.headerStartPos && packet.endSegmentIndex === endSegmentIndex) { - currentTimestampInSamples = this.granulePositionToTimestampInSamples(currentPage.granulePosition); - currentTimestampIsCorrect = true; - encodedPacket = this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples: currentTimestampInSamples - encodedPacketMetadata.durationInSamples, - vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null - }, options); - assert(encodedPacket); - encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); - assert(encodedPacketMetadata); - } else { - currentTimestampInSamples += encodedPacketMetadata.durationInSamples; - } - lastEncodedPacket = encodedPacket; - lastEncodedPacketMetadata = encodedPacketMetadata; - if (currentTimestampIsCorrect && // Next timestamp will be too late - (Math.max(currentTimestampInSamples, 0) > timestampInSamples || Math.max(encodedPacketMetadata.timestampInSamples, 0) === timestampInSamples)) { - break; - } - } - const nextPosition = await this.demuxer.findNextPacketStart(packet); - if (!nextPosition) { - break; - } - currentPage = nextPosition.startPage; - currentSegmentIndex = nextPosition.startSegmentIndex; - } - return lastEncodedPacket; - } - // A slower but simpler and sequential algorithm for finding a packet in a file - async getPacketSequential(timestamp, options) { - const release = await this.sequentialScanMutex.acquire(); - try { - const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); - timestamp = timestampInSamples / this.internalSampleRate; - const index = binarySearchLessOrEqual(this.sequentialScanCache, timestampInSamples, (x) => x.timestampInSamples); - let currentPacket; - if (index !== -1) { - const cacheEntry = this.sequentialScanCache[index]; - currentPacket = this.createEncodedPacketFromOggPacket(cacheEntry.packet, { - timestampInSamples: cacheEntry.timestampInSamples, - vorbisLastBlocksize: cacheEntry.vorbisLastBlockSize - }, options); - } else { - currentPacket = await this.getFirstPacket(options); - } - let i = 0; - while (currentPacket && currentPacket.timestamp < timestamp) { - const nextPacket = await this.getNextPacket(currentPacket, options); - if (!nextPacket || nextPacket.timestamp > timestamp) { - break; - } - currentPacket = nextPacket; - i++; - if (i === 100) { - i = 0; - const metadata = this.encodedPacketToMetadata.get(currentPacket); - assert(metadata); - if (this.sequentialScanCache.length > 0) { - assert(last(this.sequentialScanCache).timestampInSamples <= metadata.timestampInSamples); - } - this.sequentialScanCache.push(metadata); - } - } - return currentPacket; - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } -} -const findPacketStartPosition = (pageList, endPage, endSegmentIndex) => { - let page = endPage; - let segmentIndex = endSegmentIndex; - outer: while (true) { - segmentIndex--; - for (segmentIndex; segmentIndex >= 0; segmentIndex--) { - const lacingValue = page.lacingValues[segmentIndex]; - if (lacingValue < 255) { - segmentIndex++; - break outer; - } - } - assert(segmentIndex === -1); - const pageStartsWithFreshPacket = !(page.headerType & 1); - if (pageStartsWithFreshPacket) { - segmentIndex = 0; - break; - } - const previousPage = findLast(pageList, (x) => x.headerStartPos < page.headerStartPos); - if (!previousPage) { - return null; - } - page = previousPage; - segmentIndex = page.lacingValues.length; - } - assert(segmentIndex !== -1); - if (segmentIndex === page.lacingValues.length) { - const nextPage = pageList[pageList.indexOf(page) + 1]; - assert(nextPage); - page = nextPage; - segmentIndex = 0; - } - return { page, segmentIndex }; -}; -const findPreviousPacketEndPosition = (pageList, startPage, startSegmentIndex) => { - if (startSegmentIndex > 0) { - return { page: startPage, segmentIndex: startSegmentIndex - 1 }; - } - const previousPage = findLast(pageList, (x) => x.headerStartPos < startPage.headerStartPos); - if (!previousPage) { - return null; - } - return { page: previousPage, segmentIndex: previousPage.lacingValues.length - 1 }; -}; -var WaveFormat; -(function(WaveFormat2) { - WaveFormat2[WaveFormat2["PCM"] = 1] = "PCM"; - WaveFormat2[WaveFormat2["IEEE_FLOAT"] = 3] = "IEEE_FLOAT"; - WaveFormat2[WaveFormat2["ALAW"] = 6] = "ALAW"; - WaveFormat2[WaveFormat2["MULAW"] = 7] = "MULAW"; - WaveFormat2[WaveFormat2["EXTENSIBLE"] = 65534] = "EXTENSIBLE"; -})(WaveFormat || (WaveFormat = {})); -class WaveDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.dataStart = -1; - this.dataSize = -1; - this.audioInfo = null; - this.tracks = []; - this.lastKnownPacketIndex = 0; - this.metadataTags = {}; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let slice = this.reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const riffType = readAscii(slice, 4); - const littleEndian = riffType !== "RIFX"; - const isRf64 = riffType === "RF64"; - const outerChunkSize = readU32(slice, littleEndian); - let totalFileSize = isRf64 ? this.reader.fileSize : Math.min(outerChunkSize + 8, this.reader.fileSize ?? Infinity); - const format = readAscii(slice, 4); - if (format !== "WAVE") { - throw new Error("Invalid WAVE file - wrong format"); - } - let chunksRead = 0; - let dataChunkSize = null; - let currentPos = slice.filePos; - while (totalFileSize === null || currentPos < totalFileSize) { - let slice2 = this.reader.requestSlice(currentPos, 8); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const chunkId = readAscii(slice2, 4); - const chunkSize = readU32(slice2, littleEndian); - const startPos = slice2.filePos; - if (isRf64 && chunksRead === 0 && chunkId !== "ds64") { - throw new Error('Invalid RF64 file: First chunk must be "ds64".'); - } - if (chunkId === "fmt ") { - await this.parseFmtChunk(startPos, chunkSize, littleEndian); - } else if (chunkId === "data") { - dataChunkSize ?? (dataChunkSize = chunkSize); - this.dataStart = slice2.filePos; - this.dataSize = Math.min(dataChunkSize, (totalFileSize ?? Infinity) - this.dataStart); - if (this.reader.fileSize === null) { - break; - } - } else if (chunkId === "ds64") { - let ds64Slice = this.reader.requestSlice(startPos, chunkSize); - if (ds64Slice instanceof Promise) - ds64Slice = await ds64Slice; - if (!ds64Slice) - break; - const riffChunkSize = readU64(ds64Slice, littleEndian); - dataChunkSize = readU64(ds64Slice, littleEndian); - totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity); - } else if (chunkId === "LIST") { - await this.parseListChunk(startPos, chunkSize, littleEndian); - } else if (chunkId === "ID3 " || chunkId === "id3 ") { - await this.parseId3Chunk(startPos, chunkSize); - } - currentPos = startPos + chunkSize + (chunkSize & 1); - chunksRead++; - } - if (!this.audioInfo) { - throw new Error('Invalid WAVE file - missing "fmt " chunk'); - } - if (this.dataStart === -1) { - throw new Error('Invalid WAVE file - missing "data" chunk'); - } - const blockSize = this.audioInfo.blockSizeInBytes; - this.dataSize = Math.floor(this.dataSize / blockSize) * blockSize; - this.tracks.push(new InputAudioTrack(this.input, new WaveAudioTrackBacking(this))); - })()); - } - async parseFmtChunk(startPos, size, littleEndian) { - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - let formatTag = readU16(slice, littleEndian); - const numChannels = readU16(slice, littleEndian); - const sampleRate = readU32(slice, littleEndian); - slice.skip(4); - const blockAlign = readU16(slice, littleEndian); - let bitsPerSample; - if (size === 14) { - bitsPerSample = 8; - } else { - bitsPerSample = readU16(slice, littleEndian); - } - if (size >= 18 && formatTag !== 357) { - const cbSize = readU16(slice, littleEndian); - const remainingSize = size - 18; - const extensionSize = Math.min(remainingSize, cbSize); - if (extensionSize >= 22 && formatTag === WaveFormat.EXTENSIBLE) { - slice.skip(2 + 4); - const subFormat = readBytes(slice, 16); - formatTag = subFormat[0] | subFormat[1] << 8; - } - } - if (formatTag === WaveFormat.MULAW || formatTag === WaveFormat.ALAW) { - bitsPerSample = 8; - } - this.audioInfo = { - format: formatTag, - numberOfChannels: numChannels, - sampleRate, - sampleSizeInBytes: Math.ceil(bitsPerSample / 8), - blockSizeInBytes: blockAlign - }; - } - async parseListChunk(startPos, size, littleEndian) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - const infoType = readAscii(slice, 4); - if (infoType !== "INFO" && infoType !== "INF0") { - return; - } - let currentPos = slice.filePos; - while (currentPos <= startPos + size - 8) { - slice.filePos = currentPos; - const chunkName = readAscii(slice, 4); - const chunkSize = readU32(slice, littleEndian); - const bytes = readBytes(slice, chunkSize); - let stringLength = 0; - for (let i = 0; i < bytes.length; i++) { - if (bytes[i] === 0) { - break; - } - stringLength++; - } - const value = String.fromCharCode(...bytes.subarray(0, stringLength)); - (_a = this.metadataTags).raw ?? (_a.raw = {}); - this.metadataTags.raw[chunkName] = value; - switch (chunkName) { - case "INAM": - case "TITL": - { - (_b = this.metadataTags).title ?? (_b.title = value); - } - break; - case "TIT3": - { - (_c = this.metadataTags).description ?? (_c.description = value); - } - break; - case "IART": - { - (_d = this.metadataTags).artist ?? (_d.artist = value); - } - break; - case "IPRD": - { - (_e = this.metadataTags).album ?? (_e.album = value); - } - break; - case "IPRT": - case "ITRK": - case "TRCK": - { - const parts = value.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - (_f = this.metadataTags).trackNumber ?? (_f.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - (_g = this.metadataTags).tracksTotal ?? (_g.tracksTotal = tracksTotal); - } - } - break; - case "ICRD": - case "IDIT": - { - const date = new Date(value); - if (!Number.isNaN(date.getTime())) { - (_h = this.metadataTags).date ?? (_h.date = date); - } - } - break; - case "YEAR": - { - const year = Number.parseInt(value, 10); - if (Number.isInteger(year) && year > 0) { - (_i = this.metadataTags).date ?? (_i.date = new Date(year, 0, 1)); - } - } - break; - case "IGNR": - case "GENR": - { - (_j = this.metadataTags).genre ?? (_j.genre = value); - } - break; - case "ICMT": - case "CMNT": - case "COMM": - { - (_k = this.metadataTags).comment ?? (_k.comment = value); - } - break; - } - currentPos += 8 + chunkSize + (chunkSize & 1); - } - } - async parseId3Chunk(startPos, size) { - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - const id3V2Header = readId3V2Header(slice); - if (id3V2Header) { - const contentSlice = slice.slice(startPos + 10, id3V2Header.size); - parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); - } - } - getCodec() { - assert(this.audioInfo); - if (this.audioInfo.format === WaveFormat.MULAW) { - return "ulaw"; - } - if (this.audioInfo.format === WaveFormat.ALAW) { - return "alaw"; - } - if (this.audioInfo.format === WaveFormat.PCM) { - if (this.audioInfo.sampleSizeInBytes === 1) { - return "pcm-u8"; - } else if (this.audioInfo.sampleSizeInBytes === 2) { - return "pcm-s16"; - } else if (this.audioInfo.sampleSizeInBytes === 3) { - return "pcm-s24"; - } else if (this.audioInfo.sampleSizeInBytes === 4) { - return "pcm-s32"; - } - } - if (this.audioInfo.format === WaveFormat.IEEE_FLOAT) { - if (this.audioInfo.sampleSizeInBytes === 4) { - return "pcm-f32"; - } - } - return null; - } - async getMimeType() { - return "audio/wav"; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } -} -const PACKET_SIZE_IN_FRAMES = 2048; -class WaveAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - getCodec() { - return this.demuxer.getCodec(); - } - getInternalCodecId() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.format; - } - async getDecoderConfig() { - const codec = this.demuxer.getCodec(); - if (!codec) { - return null; - } - assert(this.demuxer.audioInfo); - return { - codec, - numberOfChannels: this.demuxer.audioInfo.numberOfChannels, - sampleRate: this.demuxer.audioInfo.sampleRate - }; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getNumberOfChannels() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.numberOfChannels; - } - getSampleRate() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getTimeResolution() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async getPacketAtIndex(packetIndex, options) { - assert(this.demuxer.audioInfo); - const startOffset = packetIndex * PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes; - if (startOffset >= this.demuxer.dataSize) { - return null; - } - const sizeInBytes = Math.min(PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes, this.demuxer.dataSize - startOffset); - if (this.demuxer.reader.fileSize === null) { - let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, sizeInBytes); - } - const timestamp = packetIndex * PACKET_SIZE_IN_FRAMES / this.demuxer.audioInfo.sampleRate; - const duration = sizeInBytes / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; - this.demuxer.lastKnownPacketIndex = Math.max(packetIndex, timestamp); - return new EncodedPacket(data, "key", timestamp, duration, packetIndex, sizeInBytes); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getPacket(timestamp, options) { - assert(this.demuxer.audioInfo); - const packetIndex = Math.floor(Math.min(timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES, (this.demuxer.dataSize - 1) / (PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes))); - const packet = await this.getPacketAtIndex(packetIndex, options); - if (packet) { - return packet; - } - if (packetIndex === 0) { - return null; - } - assert(this.demuxer.reader.fileSize === null); - let currentPacket = await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex, options); - while (currentPacket) { - const nextPacket = await this.getNextPacket(currentPacket, options); - if (!nextPacket) { - break; - } - currentPacket = nextPacket; - } - return currentPacket; - } - getNextPacket(packet, options) { - assert(this.demuxer.audioInfo); - const packetIndex = Math.round(packet.timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES); - return this.getPacketAtIndex(packetIndex + 1, options); - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } -} -const MIN_FRAME_HEADER_SIZE = 7; -const MAX_FRAME_HEADER_SIZE = 9; -const readFrameHeader = (slice) => { - const startPos = slice.filePos; - const bytes = readBytes(slice, 9); - const bitstream = new Bitstream(bytes); - const syncword = bitstream.readBits(12); - if (syncword !== 4095) { - return null; - } - bitstream.skipBits(1); - const layer = bitstream.readBits(2); - if (layer !== 0) { - return null; - } - const protectionAbsence = bitstream.readBits(1); - const objectType = bitstream.readBits(2) + 1; - const samplingFrequencyIndex = bitstream.readBits(4); - if (samplingFrequencyIndex === 15) { - return null; - } - bitstream.skipBits(1); - const channelConfiguration = bitstream.readBits(3); - if (channelConfiguration === 0) { - throw new Error("ADTS frames with channel configuration 0 are not supported."); - } - bitstream.skipBits(1); - bitstream.skipBits(1); - bitstream.skipBits(1); - bitstream.skipBits(1); - const frameLength = bitstream.readBits(13); - bitstream.skipBits(11); - const numberOfAacFrames = bitstream.readBits(2) + 1; - if (numberOfAacFrames !== 1) { - throw new Error("ADTS frames with more than one AAC frame are not supported."); - } - let crcCheck = null; - if (protectionAbsence === 1) { - slice.filePos -= 2; - } else { - crcCheck = bitstream.readBits(16); - } - return { - objectType, - samplingFrequencyIndex, - channelConfiguration, - frameLength, - numberOfAacFrames, - crcCheck, - startPos - }; -}; -const SAMPLES_PER_AAC_FRAME = 1024; -class AdtsDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.firstFrameHeader = null; - this.loadedSamples = []; - this.tracks = []; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.lastLoadedPos = 0; - this.nextTimestampInSamples = 0; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - while (!this.firstFrameHeader && !this.lastSampleLoaded) { - await this.advanceReader(); - } - assert(this.firstFrameHeader); - this.tracks = [new InputAudioTrack(this.input, new AdtsAudioTrackBacking(this))]; - })()); - } - async advanceReader() { - let slice = this.reader.requestSliceRange(this.lastLoadedPos, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - this.lastSampleLoaded = true; - return; - } - const header = readFrameHeader(slice); - if (!header) { - this.lastSampleLoaded = true; - return; - } - if (this.reader.fileSize !== null && header.startPos + header.frameLength > this.reader.fileSize) { - this.lastSampleLoaded = true; - return; - } - if (!this.firstFrameHeader) { - this.firstFrameHeader = header; - } - const sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; - assert(sampleRate !== void 0); - const sampleDuration = SAMPLES_PER_AAC_FRAME / sampleRate; - const headerSize = header.crcCheck ? MAX_FRAME_HEADER_SIZE : MIN_FRAME_HEADER_SIZE; - const sample = { - timestamp: this.nextTimestampInSamples / sampleRate, - duration: sampleDuration, - dataStart: header.startPos + headerSize, - dataSize: header.frameLength - headerSize - }; - this.loadedSamples.push(sample); - this.nextTimestampInSamples += SAMPLES_PER_AAC_FRAME; - this.lastLoadedPos = header.startPos + header.frameLength; - } - async getMimeType() { - return "audio/aac"; - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getMetadataTags() { - return {}; - } -} -class AdtsAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - async getFirstTimestamp() { - return 0; - } - getTimeResolution() { - const sampleRate = this.getSampleRate(); - return sampleRate / SAMPLES_PER_AAC_FRAME; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getCodec() { - return "aac"; - } - getInternalCodecId() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.objectType; - } - getNumberOfChannels() { - assert(this.demuxer.firstFrameHeader); - const numberOfChannels = aacChannelMap[this.demuxer.firstFrameHeader.channelConfiguration]; - assert(numberOfChannels !== void 0); - return numberOfChannels; - } - getSampleRate() { - assert(this.demuxer.firstFrameHeader); - const sampleRate = aacFrequencyTable[this.demuxer.firstFrameHeader.samplingFrequencyIndex]; - assert(sampleRate !== void 0); - return sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getDecoderConfig() { - assert(this.demuxer.firstFrameHeader); - const bytes = new Uint8Array(3); - const bitstream = new Bitstream(bytes); - const { objectType, samplingFrequencyIndex, channelConfiguration } = this.demuxer.firstFrameHeader; - if (objectType > 31) { - bitstream.writeBits(5, 31); - bitstream.writeBits(6, objectType - 32); - } else { - bitstream.writeBits(5, objectType); - } - bitstream.writeBits(4, samplingFrequencyIndex); - bitstream.writeBits(4, channelConfiguration); - return { - codec: `mp4a.40.${this.demuxer.firstFrameHeader.objectType}`, - numberOfChannels: this.getNumberOfChannels(), - sampleRate: this.getSampleRate(), - description: bytes.subarray(0, Math.ceil((bitstream.pos - 1) / 8)) - }; - } - async getPacketAtIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.dataSize); - } - return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); - if (sampleIndex === -1) { - throw new Error("Packet was not created from this track."); - } - const nextIndex = sampleIndex + 1; - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - async getPacket(timestamp, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); - if (index === -1 && this.demuxer.loadedSamples.length > 0) { - return null; - } - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(index, options); - } - if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { - return this.getPacketAtIndex(index, options); - } - await this.demuxer.advanceReader(); - } - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } -} -const getBlockSizeOrUncommon = (bits) => { - if (bits === 0) { - return null; - } else if (bits === 1) { - return 192; - } else if (bits >= 2 && bits <= 5) { - return 144 * 2 ** bits; - } else if (bits === 6) { - return "uncommon-u8"; - } else if (bits === 7) { - return "uncommon-u16"; - } else if (bits >= 8 && bits <= 15) { - return 2 ** bits; - } else { - return null; - } -}; -const getSampleRateOrUncommon = (sampleRateBits, streamInfoSampleRate) => { - switch (sampleRateBits) { - case 0: - return streamInfoSampleRate; - case 1: - return 88200; - case 2: - return 176400; - case 3: - return 192e3; - case 4: - return 8e3; - case 5: - return 16e3; - case 6: - return 22050; - case 7: - return 24e3; - case 8: - return 32e3; - case 9: - return 44100; - case 10: - return 48e3; - case 11: - return 96e3; - case 12: - return "uncommon-u8"; - case 13: - return "uncommon-u16"; - case 14: - return "uncommon-u16-10"; - default: - return null; - } -}; -const readCodedNumber = (fileSlice) => { - let ones = 0; - const bitstream1 = new Bitstream(readBytes(fileSlice, 1)); - while (bitstream1.readBits(1) === 1) { - ones++; - } - if (ones === 0) { - return bitstream1.readBits(7); - } - const bitArray = []; - const extraBytes = ones - 1; - const bitstream2 = new Bitstream(readBytes(fileSlice, extraBytes)); - const firstByteBits = 8 - ones - 1; - for (let i = 0; i < firstByteBits; i++) { - bitArray.unshift(bitstream1.readBits(1)); - } - for (let i = 0; i < extraBytes; i++) { - for (let j = 0; j < 8; j++) { - const val = bitstream2.readBits(1); - if (j < 2) { - continue; - } - bitArray.unshift(val); - } - } - const encoded = bitArray.reduce((acc, bit, index) => { - return acc | bit << index; - }, 0); - return encoded; -}; -const readBlockSize = (slice, blockSizeBits) => { - if (blockSizeBits === "uncommon-u16") { - return readU16Be(slice) + 1; - } else if (blockSizeBits === "uncommon-u8") { - return readU8(slice) + 1; - } else if (typeof blockSizeBits === "number") { - return blockSizeBits; - } else { - assertNever(blockSizeBits); - assert(false); - } -}; -const readSampleRate = (slice, sampleRateOrUncommon) => { - if (sampleRateOrUncommon === "uncommon-u16") { - return readU16Be(slice); - } - if (sampleRateOrUncommon === "uncommon-u16-10") { - return readU16Be(slice) * 10; - } - if (sampleRateOrUncommon === "uncommon-u8") { - return readU8(slice); - } - if (typeof sampleRateOrUncommon === "number") { - return sampleRateOrUncommon; - } - return null; -}; -const calculateCrc8 = (data) => { - const polynomial = 7; - let crc = 0; - for (const byte of data) { - crc ^= byte; - for (let i = 0; i < 8; i++) { - if ((crc & 128) !== 0) { - crc = crc << 1 ^ polynomial; - } else { - crc <<= 1; - } - crc &= 255; - } - } - return crc; -}; -class FlacDemuxer extends Demuxer { - constructor(input) { - super(input); - this.loadedSamples = []; - this.metadataPromise = null; - this.track = null; - this.metadataTags = {}; - this.audioInfo = null; - this.lastLoadedPos = null; - this.blockingBit = null; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.reader = input._reader; - } - async computeDuration() { - await this.readMetadata(); - assert(this.track); - return this.track.computeDuration(); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } - async getTracks() { - await this.readMetadata(); - assert(this.track); - return [this.track]; - } - async getMimeType() { - return "audio/flac"; - } - async readMetadata() { - let currentPos = 4; - return this.metadataPromise ?? (this.metadataPromise = (async () => { - var _a; - while (this.reader.fileSize === null || currentPos < this.reader.fileSize) { - let sizeSlice = this.reader.requestSlice(currentPos, 4); - if (sizeSlice instanceof Promise) - sizeSlice = await sizeSlice; - currentPos += 4; - if (sizeSlice === null) { - throw new Error(`Metadata block at position ${currentPos} is too small! Corrupted file.`); - } - assert(sizeSlice); - const byte = readU8(sizeSlice); - const size = readU24Be(sizeSlice); - const isLastMetadata = (byte & 128) !== 0; - const metaBlockType = byte & 127; - switch (metaBlockType) { - case FlacBlockType.STREAMINFO: { - let streamInfoBlock = this.reader.requestSlice(currentPos, size); - if (streamInfoBlock instanceof Promise) - streamInfoBlock = await streamInfoBlock; - assert(streamInfoBlock); - if (streamInfoBlock === null) { - throw new Error(`StreamInfo block at position ${currentPos} is too small! Corrupted file.`); - } - const streamInfoBytes = readBytes(streamInfoBlock, 34); - const bitstream = new Bitstream(streamInfoBytes); - const minimumBlockSize = bitstream.readBits(16); - const maximumBlockSize = bitstream.readBits(16); - const minimumFrameSize = bitstream.readBits(24); - const maximumFrameSize = bitstream.readBits(24); - const sampleRate = bitstream.readBits(20); - const numberOfChannels = bitstream.readBits(3) + 1; - bitstream.readBits(5); - const totalSamples = bitstream.readBits(36); - bitstream.skipBits(16 * 8); - const description = new Uint8Array(42); - description.set(new Uint8Array([102, 76, 97, 67]), 0); - description.set(new Uint8Array([128, 0, 0, 34]), 4); - description.set(streamInfoBytes, 8); - this.audioInfo = { - numberOfChannels, - sampleRate, - totalSamples, - minimumBlockSize, - maximumBlockSize, - minimumFrameSize, - maximumFrameSize, - description - }; - this.track = new InputAudioTrack(this.input, new FlacAudioTrackBacking(this)); - break; - } - case FlacBlockType.VORBIS_COMMENT: { - let vorbisCommentBlock = this.reader.requestSlice(currentPos, size); - if (vorbisCommentBlock instanceof Promise) - vorbisCommentBlock = await vorbisCommentBlock; - assert(vorbisCommentBlock); - readVorbisComments(readBytes(vorbisCommentBlock, size), this.metadataTags); - break; - } - case FlacBlockType.PICTURE: { - let pictureBlock = this.reader.requestSlice(currentPos, size); - if (pictureBlock instanceof Promise) - pictureBlock = await pictureBlock; - assert(pictureBlock); - const pictureType = readU32Be(pictureBlock); - const mediaTypeLength = readU32Be(pictureBlock); - const mediaType = textDecoder.decode(readBytes(pictureBlock, mediaTypeLength)); - const descriptionLength = readU32Be(pictureBlock); - const description = textDecoder.decode(readBytes(pictureBlock, descriptionLength)); - pictureBlock.skip(4 + 4 + 4 + 4); - const dataLength = readU32Be(pictureBlock); - const data = readBytes(pictureBlock, dataLength); - (_a = this.metadataTags).images ?? (_a.images = []); - this.metadataTags.images.push({ - data, - mimeType: mediaType, - // https://www.rfc-editor.org/rfc/rfc9639.html#table13 - kind: pictureType === 3 ? "coverFront" : pictureType === 4 ? "coverBack" : "unknown", - description - }); - break; - } - } - currentPos += size; - if (isLastMetadata) { - this.lastLoadedPos = currentPos; - break; - } - } - })()); - } - async readNextFlacFrame({ startPos, isFirstPacket }) { - assert(this.audioInfo); - const minimumHeaderLength = 6; - const maximumHeaderSize = 16; - const maximumSliceLength = this.audioInfo.maximumFrameSize + maximumHeaderSize; - const slice = await this.reader.requestSliceRange(startPos, this.audioInfo.minimumFrameSize, maximumSliceLength); - if (!slice) { - return null; - } - const frameHeader = this.readFlacFrameHeader({ - slice, - isFirstPacket - }); - if (!frameHeader) { - return null; - } - slice.filePos = startPos + this.audioInfo.minimumFrameSize; - while (true) { - if (slice.filePos > slice.end - minimumHeaderLength) { - return { - num: frameHeader.num, - blockSize: frameHeader.blockSize, - sampleRate: frameHeader.sampleRate, - size: slice.end - startPos, - isLastFrame: true - }; - } - const nextByte = readU8(slice); - if (nextByte === 255) { - const positionBeforeReading = slice.filePos; - const byteAfterNextByte = readU8(slice); - const expected = this.blockingBit === 1 ? 249 : 248; - if (byteAfterNextByte !== expected) { - slice.filePos = positionBeforeReading; - continue; - } - slice.skip(-2); - const lengthIfNextFlacFrameHeaderIsLegit = slice.filePos - startPos; - const nextFrameHeader = this.readFlacFrameHeader({ - slice, - isFirstPacket: false - }); - if (!nextFrameHeader) { - slice.filePos = positionBeforeReading; - continue; - } - if (this.blockingBit === 0) { - if (nextFrameHeader.num - frameHeader.num !== 1) { - slice.filePos = positionBeforeReading; - continue; - } - } else { - if (nextFrameHeader.num - frameHeader.num !== frameHeader.blockSize) { - slice.filePos = positionBeforeReading; - continue; - } - } - return { - num: frameHeader.num, - blockSize: frameHeader.blockSize, - sampleRate: frameHeader.sampleRate, - size: lengthIfNextFlacFrameHeaderIsLegit, - isLastFrame: false - }; - } - } - } - readFlacFrameHeader({ slice, isFirstPacket }) { - const startOffset = slice.filePos; - const bytes = readBytes(slice, 4); - const bitstream = new Bitstream(bytes); - const bits = bitstream.readBits(15); - if (bits !== 32764) { - return null; - } - if (this.blockingBit === null) { - assert(isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - this.blockingBit = newBlockingBit; - } else if (this.blockingBit === 1) { - assert(!isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - if (newBlockingBit !== 1) { - return null; - } - } else if (this.blockingBit === 0) { - assert(!isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - if (newBlockingBit !== 0) { - return null; - } - } else { - throw new Error("Invalid blocking bit"); - } - const blockSizeOrUncommon = getBlockSizeOrUncommon(bitstream.readBits(4)); - if (!blockSizeOrUncommon) { - return null; - } - assert(this.audioInfo); - const sampleRateOrUncommon = getSampleRateOrUncommon(bitstream.readBits(4), this.audioInfo.sampleRate); - if (!sampleRateOrUncommon) { - return null; - } - bitstream.readBits(4); - bitstream.readBits(3); - const reservedZero = bitstream.readBits(1); - if (reservedZero !== 0) { - return null; - } - const num = readCodedNumber(slice); - const blockSize = readBlockSize(slice, blockSizeOrUncommon); - const sampleRate = readSampleRate(slice, sampleRateOrUncommon); - if (sampleRate === null) { - return null; - } - if (sampleRate !== this.audioInfo.sampleRate) { - return null; - } - const size = slice.filePos - startOffset; - const crc = readU8(slice); - slice.skip(-size); - slice.skip(-1); - const crcCalculated = calculateCrc8(readBytes(slice, size)); - if (crc !== crcCalculated) { - return null; - } - return { num, blockSize, sampleRate }; - } - async advanceReader() { - await this.readMetadata(); - assert(this.lastLoadedPos !== null); - assert(this.audioInfo); - const startPos = this.lastLoadedPos; - const frame = await this.readNextFlacFrame({ - startPos, - isFirstPacket: this.loadedSamples.length === 0 - }); - if (!frame) { - this.lastSampleLoaded = true; - return; - } - const lastSample = this.loadedSamples[this.loadedSamples.length - 1]; - const blockOffset = lastSample ? lastSample.blockOffset + lastSample.blockSize : 0; - const sample = { - blockOffset, - blockSize: frame.blockSize, - byteOffset: startPos, - byteSize: frame.size - }; - this.lastLoadedPos = this.lastLoadedPos + frame.size; - this.loadedSamples.push(sample); - if (frame.isLastFrame) { - this.lastSampleLoaded = true; - return; - } - } -} -class FlacAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - getCodec() { - return "flac"; - } - getInternalCodecId() { - return null; - } - getNumberOfChannels() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.numberOfChannels; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getSampleRate() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getTimeResolution() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async getDecoderConfig() { - assert(this.demuxer.audioInfo); - return { - codec: "flac", - numberOfChannels: this.demuxer.audioInfo.numberOfChannels, - sampleRate: this.demuxer.audioInfo.sampleRate, - description: this.demuxer.audioInfo.description - }; - } - async getPacket(timestamp, options) { - assert(this.demuxer.audioInfo); - if (timestamp < 0) { - throw new Error("Timestamp cannot be negative"); - } - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const packetIndex = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.blockOffset / this.demuxer.audioInfo.sampleRate); - if (packetIndex === -1) { - await this.demuxer.advanceReader(); - continue; - } - const packet = this.demuxer.loadedSamples[packetIndex]; - const sampleTimestamp = packet.blockOffset / this.demuxer.audioInfo.sampleRate; - const sampleDuration = packet.blockSize / this.demuxer.audioInfo.sampleRate; - if (sampleTimestamp + sampleDuration <= timestamp) { - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(this.demuxer.loadedSamples.length - 1, options); - } - await this.demuxer.advanceReader(); - continue; - } - return this.getPacketAtIndex(packetIndex, options); - } - } finally { - release(); - } - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const nextIndex = packet.sequenceNumber + 1; - if (this.demuxer.lastSampleLoaded && nextIndex >= this.demuxer.loadedSamples.length) { - return null; - } - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } - async getPacketAtIndex(sampleIndex, options) { - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.byteOffset, rawSample.byteSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.byteSize); - } - assert(this.demuxer.audioInfo); - const timestamp = rawSample.blockOffset / this.demuxer.audioInfo.sampleRate; - const duration = rawSample.blockSize / this.demuxer.audioInfo.sampleRate; - return new EncodedPacket(data, "key", timestamp, duration, sampleIndex, rawSample.byteSize); - } - async getFirstPacket(options) { - while (this.demuxer.loadedSamples.length === 0 && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(0, options); - } -} -class InputFormat { -} -class IsobmffInputFormat extends InputFormat { - /** @internal */ - async _getMajorBrand(input) { - let slice = input._reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return null; - slice.skip(4); - const fourCc = readAscii(slice, 4); - if (fourCc !== "ftyp") { - return null; - } - return readAscii(slice, 4); - } - /** @internal */ - _createDemuxer(input) { - return new IsobmffDemuxer(input); - } -} -class Mp4InputFormat extends IsobmffInputFormat { - /** @internal */ - async _canReadInput(input) { - const majorBrand = await this._getMajorBrand(input); - return !!majorBrand && majorBrand !== "qt "; - } - get name() { - return "MP4"; - } - get mimeType() { - return "video/mp4"; - } -} -class QuickTimeInputFormat extends IsobmffInputFormat { - /** @internal */ - async _canReadInput(input) { - const majorBrand = await this._getMajorBrand(input); - return majorBrand === "qt "; - } - get name() { - return "QuickTime File Format"; - } - get mimeType() { - return "video/quicktime"; - } -} -class MatroskaInputFormat extends InputFormat { - /** @internal */ - async isSupportedEBMLOfDocType(input, desiredDocType) { - let headerSlice = input._reader.requestSlice(0, MAX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) - return false; - const varIntSize = readVarIntSize(headerSlice); - if (varIntSize === null) { - return false; - } - if (varIntSize < 1 || varIntSize > 8) { - return false; - } - const id = readUnsignedInt(headerSlice, varIntSize); - if (id !== EBMLId.EBML) { - return false; - } - const dataSize = readElementSize(headerSlice); - if (typeof dataSize !== "number") { - return false; - } - let dataSlice = input._reader.requestSlice(headerSlice.filePos, dataSize); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (!dataSlice) - return false; - const startPos = headerSlice.filePos; - while (dataSlice.filePos <= startPos + dataSize - MIN_HEADER_SIZE) { - const header = readElementHeader(dataSlice); - if (!header) - break; - const { id: id2, size } = header; - const dataStartPos = dataSlice.filePos; - if (size === void 0) - return false; - switch (id2) { - case EBMLId.EBMLVersion: - { - const ebmlVersion = readUnsignedInt(dataSlice, size); - if (ebmlVersion !== 1) { - return false; - } - } - break; - case EBMLId.EBMLReadVersion: - { - const ebmlReadVersion = readUnsignedInt(dataSlice, size); - if (ebmlReadVersion !== 1) { - return false; - } - } - break; - case EBMLId.DocType: - { - const docType = readAsciiString(dataSlice, size); - if (docType !== desiredDocType) { - return false; - } - } - break; - case EBMLId.DocTypeVersion: - { - const docTypeVersion = readUnsignedInt(dataSlice, size); - if (docTypeVersion > 4) { - return false; - } - } - break; - } - dataSlice.filePos = dataStartPos + size; - } - return true; - } - /** @internal */ - _canReadInput(input) { - return this.isSupportedEBMLOfDocType(input, "matroska"); - } - /** @internal */ - _createDemuxer(input) { - return new MatroskaDemuxer(input); - } - get name() { - return "Matroska"; - } - get mimeType() { - return "video/x-matroska"; - } -} -class WebMInputFormat extends MatroskaInputFormat { - /** @internal */ - _canReadInput(input) { - return this.isSupportedEBMLOfDocType(input, "webm"); - } - get name() { - return "WebM"; - } - get mimeType() { - return "video/webm"; - } -} -class Mp3InputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 10); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - let currentPos = 0; - let id3V2HeaderFound = false; - while (true) { - let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const id3V2Header = readId3V2Header(slice2); - if (!id3V2Header) { - break; - } - id3V2HeaderFound = true; - currentPos = slice2.filePos + id3V2Header.size; - } - const firstResult = await readNextFrameHeader(input._reader, currentPos, currentPos + 4096); - if (!firstResult) { - return false; - } - if (id3V2HeaderFound) { - return true; - } - currentPos = firstResult.startPos + firstResult.header.totalSize; - const secondResult = await readNextFrameHeader(input._reader, currentPos, currentPos + FRAME_HEADER_SIZE); - if (!secondResult) { - return false; - } - const firstHeader = firstResult.header; - const secondHeader = secondResult.header; - if (firstHeader.channel !== secondHeader.channel || firstHeader.sampleRate !== secondHeader.sampleRate) { - return false; - } - return true; - } - /** @internal */ - _createDemuxer(input) { - return new Mp3Demuxer(input); - } - get name() { - return "MP3"; - } - get mimeType() { - return "audio/mpeg"; - } -} -class WaveInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const riffType = readAscii(slice, 4); - if (riffType !== "RIFF" && riffType !== "RIFX" && riffType !== "RF64") { - return false; - } - slice.skip(4); - const format = readAscii(slice, 4); - return format === "WAVE"; - } - /** @internal */ - _createDemuxer(input) { - return new WaveDemuxer(input); - } - get name() { - return "WAVE"; - } - get mimeType() { - return "audio/wav"; - } -} -class OggInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 4); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - return readAscii(slice, 4) === "OggS"; - } - /** @internal */ - _createDemuxer(input) { - return new OggDemuxer(input); - } - get name() { - return "Ogg"; - } - get mimeType() { - return "application/ogg"; - } -} -class FlacInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 4); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - return readAscii(slice, 4) === "fLaC"; - } - get name() { - return "FLAC"; - } - get mimeType() { - return "audio/flac"; - } - /** @internal */ - _createDemuxer(input) { - return new FlacDemuxer(input); - } -} -class AdtsInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSliceRange(0, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const firstHeader = readFrameHeader(slice); - if (!firstHeader) { - return false; - } - slice = input._reader.requestSliceRange(firstHeader.frameLength, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const secondHeader = readFrameHeader(slice); - if (!secondHeader) { - return false; - } - return firstHeader.objectType === secondHeader.objectType && firstHeader.samplingFrequencyIndex === secondHeader.samplingFrequencyIndex && firstHeader.channelConfiguration === secondHeader.channelConfiguration; - } - /** @internal */ - _createDemuxer(input) { - return new AdtsDemuxer(input); - } - get name() { - return "ADTS"; - } - get mimeType() { - return "audio/aac"; - } -} -const MP4 = /* @__PURE__ */ new Mp4InputFormat(); -const QTFF = /* @__PURE__ */ new QuickTimeInputFormat(); -const MATROSKA = /* @__PURE__ */ new MatroskaInputFormat(); -const WEBM = /* @__PURE__ */ new WebMInputFormat(); -const MP3 = /* @__PURE__ */ new Mp3InputFormat(); -const WAVE = /* @__PURE__ */ new WaveInputFormat(); -const OGG = /* @__PURE__ */ new OggInputFormat(); -const ADTS = /* @__PURE__ */ new AdtsInputFormat(); -const FLAC = /* @__PURE__ */ new FlacInputFormat(); -const ALL_FORMATS = [MP4, QTFF, MATROSKA, WEBM, WAVE, OGG, FLAC, MP3, ADTS]; -class Source { - constructor() { - this._disposed = false; - this._sizePromise = null; - this.onread = null; - } - /** - * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call - * will retrieve the size. - * - * Returns null if the source is unsized. - */ - async getSizeOrNull() { - if (this._disposed) { - throw new InputDisposedError(); - } - return this._sizePromise ?? (this._sizePromise = Promise.resolve(this._retrieveSize())); - } - /** - * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call - * will retrieve the size. - * - * Throws an error if the source is unsized. - */ - async getSize() { - if (this._disposed) { - throw new InputDisposedError(); - } - const result = await this.getSizeOrNull(); - if (result === null) { - throw new Error("Cannot determine the size of an unsized source."); - } - return result; - } -} -class BlobSource extends Source { - /** - * Creates a new {@link BlobSource} backed by the specified - * [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). - */ - constructor(blob, options = {}) { - if (!(blob instanceof Blob)) { - throw new TypeError("blob must be a Blob."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - super(); - this._readers = /* @__PURE__ */ new WeakMap(); - this._blob = blob; - this._orchestrator = new ReadOrchestrator({ - maxCacheSize: options.maxCacheSize ?? 8 * 2 ** 20, - maxWorkerCount: 4, - runWorker: this._runWorker.bind(this), - prefetchProfile: PREFETCH_PROFILES.fileSystem - }); - } - /** @internal */ - _retrieveSize() { - const size = this._blob.size; - this._orchestrator.fileSize = size; - return size; - } - /** @internal */ - _read(start, end) { - return this._orchestrator.read(start, end); - } - /** @internal */ - async _runWorker(worker) { - let reader = this._readers.get(worker); - if (reader === void 0) { - if ("stream" in this._blob && !isWebKit()) { - const slice = this._blob.slice(worker.currentPos); - reader = slice.stream().getReader(); - } else { - reader = null; - } - this._readers.set(worker, reader); - } - while (worker.currentPos < worker.targetPos && !worker.aborted) { - if (reader) { - const { done, value } = await reader.read(); - if (done) { - this._orchestrator.forgetWorker(worker); - throw new Error("Blob reader stopped unexpectedly before all requested data was read."); - } - if (worker.aborted) { - break; - } - this.onread?.(worker.currentPos, worker.currentPos + value.length); - this._orchestrator.supplyWorkerData(worker, value); - } else { - const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer(); - if (worker.aborted) { - break; - } - this.onread?.(worker.currentPos, worker.currentPos + data.byteLength); - this._orchestrator.supplyWorkerData(worker, new Uint8Array(data)); - } - } - worker.running = false; - if (worker.aborted) { - await reader?.cancel(); - } - } - /** @internal */ - _dispose() { - this._orchestrator.dispose(); - } -} -const URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20; -const DEFAULT_RETRY_DELAY = ((previousAttempts, error, src) => { - const couldBeCorsError = error instanceof Error && (error.message.includes("Failed to fetch") || error.message.includes("Load failed") || error.message.includes("NetworkError when attempting to fetch resource")); - if (couldBeCorsError) { - let originOfSrc = null; - try { - if (typeof window !== "undefined" && typeof window.location !== "undefined") { - originOfSrc = new URL(src instanceof Request ? src.url : src, window.location.href).origin; - } - } catch { - } - const isOnline = typeof navigator !== "undefined" && typeof navigator.onLine === "boolean" ? navigator.onLine : true; - if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) { - console.warn(`Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option.`); - return null; - } - } - return Math.min(2 ** (previousAttempts - 2), 16); -}); -class UrlSource extends Source { - /** Creates a new {@link UrlSource} backed by the resource at the specified URL. */ - constructor(url, options = {}) { - if (typeof url !== "string" && !(url instanceof URL) && !(typeof Request !== "undefined" && url instanceof Request)) { - throw new TypeError("url must be a string, URL or Request."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.requestInit !== void 0 && (!options.requestInit || typeof options.requestInit !== "object")) { - throw new TypeError("options.requestInit, when provided, must be an object."); - } - if (options.getRetryDelay !== void 0 && typeof options.getRetryDelay !== "function") { - throw new TypeError("options.getRetryDelay, when provided, must be a function."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - if (options.fetchFn !== void 0 && typeof options.fetchFn !== "function") { - throw new TypeError("options.fetchFn, when provided, must be a function."); - } - super(); - this._existingResponses = /* @__PURE__ */ new WeakMap(); - this._url = url; - this._options = options; - this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY; - this._orchestrator = new ReadOrchestrator({ - maxCacheSize: options.maxCacheSize ?? 64 * 2 ** 20, - // Most files in the real-world have a single sequential access pattern, but having two in parallel can - // also happen - maxWorkerCount: 2, - runWorker: this._runWorker.bind(this), - prefetchProfile: PREFETCH_PROFILES.network - }); - } - /** @internal */ - async _retrieveSize() { - const abortController = new AbortController(); - const response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { - headers: { - // We could also send a non-range request to request the same bytes (all of them), but doing it like - // this is an easy way to check if the server supports range requests in the first place - Range: "bytes=0-" - }, - signal: abortController.signal - }), this._getRetryDelay, () => this._disposed); - if (!response.ok) { - throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); - } - let worker; - let fileSize; - if (response.status === 206) { - fileSize = this._getTotalLengthFromRangeResponse(response); - worker = this._orchestrator.createWorker(0, Math.min(fileSize, URL_SOURCE_MIN_LOAD_AMOUNT)); - } else { - const contentLength = response.headers.get("Content-Length"); - if (contentLength) { - fileSize = Number(contentLength); - worker = this._orchestrator.createWorker(0, fileSize); - this._orchestrator.options.maxCacheSize = Infinity; - console.warn("HTTP server did not respond with 206 Partial Content, meaning the entire remote resource now has to be downloaded. For efficient media file streaming across a network, please make sure your server supports range requests."); - } else { - throw new Error(`HTTP response (status ${response.status}) must surface Content-Length header.`); - } - } - this._orchestrator.fileSize = fileSize; - this._existingResponses.set(worker, { response, abortController }); - this._orchestrator.runWorker(worker); - return fileSize; - } - /** @internal */ - _read(start, end) { - return this._orchestrator.read(start, end); - } - /** @internal */ - async _runWorker(worker) { - while (true) { - const existing = this._existingResponses.get(worker); - this._existingResponses.delete(worker); - let abortController = existing?.abortController; - let response = existing?.response; - if (!abortController) { - abortController = new AbortController(); - response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { - headers: { - Range: `bytes=${worker.currentPos}-` - }, - signal: abortController.signal - }), this._getRetryDelay, () => this._disposed); - } - assert(response); - if (!response.ok) { - throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); - } - if (worker.currentPos > 0 && response.status !== 206) { - throw new Error("HTTP server did not respond with 206 Partial Content to a range request. To enable efficient media file streaming across a network, please make sure your server supports range requests."); - } - if (!response.body) { - throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream."); - } - const reader = response.body.getReader(); - while (true) { - if (worker.currentPos >= worker.targetPos || worker.aborted) { - abortController.abort(); - worker.running = false; - return; - } - let readResult; - try { - readResult = await reader.read(); - } catch (error) { - if (this._disposed) { - throw error; - } - const retryDelayInSeconds = this._getRetryDelay(1, error, this._url); - if (retryDelayInSeconds !== null) { - console.error("Error while reading response stream. Attempting to resume.", error); - await new Promise((resolve) => setTimeout(resolve, 1e3 * retryDelayInSeconds)); - break; - } else { - throw error; - } - } - if (worker.aborted) { - continue; - } - const { done, value } = readResult; - if (done) { - if (worker.currentPos >= worker.targetPos) { - this._orchestrator.forgetWorker(worker); - worker.running = false; - return; - } - break; - } - this.onread?.(worker.currentPos, worker.currentPos + value.length); - this._orchestrator.supplyWorkerData(worker, value); - } - } - } - /** @internal */ - _getTotalLengthFromRangeResponse(response) { - const contentRange = response.headers.get("Content-Range"); - if (contentRange) { - const match = /\/(\d+)/.exec(contentRange); - if (match) { - return Number(match[1]); - } - } - const contentLength = response.headers.get("Content-Length"); - if (contentLength) { - return Number(contentLength); - } else { - throw new Error("Partial HTTP response (status 206) must surface either Content-Range or Content-Length header."); - } - } - /** @internal */ - _dispose() { - this._orchestrator.dispose(); - } -} -class ReadableStreamSource extends Source { - /** Creates a new {@link ReadableStreamSource} backed by the specified `ReadableStream`. */ - constructor(stream, options = {}) { - if (!(stream instanceof ReadableStream)) { - throw new TypeError("stream must be a ReadableStream."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - super(); - this._reader = null; - this._cache = []; - this._pendingSlices = []; - this._currentIndex = 0; - this._targetIndex = 0; - this._maxRequestedIndex = 0; - this._endIndex = null; - this._pulling = false; - this._stream = stream; - this._maxCacheSize = options.maxCacheSize ?? 16 * 2 ** 20; - } - /** @internal */ - _retrieveSize() { - return this._endIndex; - } - /** @internal */ - _read(start, end) { - if (this._endIndex !== null && end > this._endIndex) { - return null; - } - this._maxRequestedIndex = Math.max(this._maxRequestedIndex, end); - const cacheStartIndex = binarySearchLessOrEqual(this._cache, start, (x) => x.start); - const cacheStartEntry = cacheStartIndex !== -1 ? this._cache[cacheStartIndex] : null; - if (cacheStartEntry && cacheStartEntry.start <= start && end <= cacheStartEntry.end) { - return { - bytes: cacheStartEntry.bytes, - view: cacheStartEntry.view, - offset: cacheStartEntry.start - }; - } - let lastEnd = start; - const bytes = new Uint8Array(end - start); - if (cacheStartIndex !== -1) { - for (let i = cacheStartIndex; i < this._cache.length; i++) { - const cacheEntry = this._cache[i]; - if (cacheEntry.start >= end) { - break; - } - const cappedStart = Math.max(start, cacheEntry.start); - if (cappedStart > lastEnd) { - this._throwDueToCacheMiss(); - } - const cappedEnd = Math.min(end, cacheEntry.end); - if (cappedStart < cappedEnd) { - bytes.set(cacheEntry.bytes.subarray(cappedStart - cacheEntry.start, cappedEnd - cacheEntry.start), cappedStart - start); - lastEnd = cappedEnd; - } - } - } - if (lastEnd === end) { - return { - bytes, - view: toDataView(bytes), - offset: start - }; - } - if (this._currentIndex > lastEnd) { - this._throwDueToCacheMiss(); - } - const { promise, resolve, reject } = promiseWithResolvers(); - this._pendingSlices.push({ - start, - end, - bytes, - resolve, - reject - }); - this._targetIndex = Math.max(this._targetIndex, end); - if (!this._pulling) { - this._pulling = true; - void this._pull().catch((error) => { - this._pulling = false; - if (this._pendingSlices.length > 0) { - this._pendingSlices.forEach((x) => x.reject(error)); - this._pendingSlices.length = 0; - } else { - throw error; - } - }); - } - return promise; - } - /** @internal */ - _throwDueToCacheMiss() { - throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache."); - } - /** @internal */ - async _pull() { - this._reader ?? (this._reader = this._stream.getReader()); - while (this._currentIndex < this._targetIndex && !this._disposed) { - const { done, value } = await this._reader.read(); - if (done) { - for (const pendingSlice of this._pendingSlices) { - pendingSlice.resolve(null); - } - this._pendingSlices.length = 0; - this._endIndex = this._currentIndex; - break; - } - const startIndex = this._currentIndex; - const endIndex = this._currentIndex + value.byteLength; - for (let i = 0; i < this._pendingSlices.length; i++) { - const pendingSlice = this._pendingSlices[i]; - const cappedStart = Math.max(startIndex, pendingSlice.start); - const cappedEnd = Math.min(endIndex, pendingSlice.end); - if (cappedStart < cappedEnd) { - pendingSlice.bytes.set(value.subarray(cappedStart - startIndex, cappedEnd - startIndex), cappedStart - pendingSlice.start); - if (cappedEnd === pendingSlice.end) { - pendingSlice.resolve({ - bytes: pendingSlice.bytes, - view: toDataView(pendingSlice.bytes), - offset: pendingSlice.start - }); - this._pendingSlices.splice(i, 1); - i--; - } - } - } - this._cache.push({ - start: startIndex, - end: endIndex, - bytes: value, - view: toDataView(value), - age: 0 - // Unused - }); - while (this._cache.length > 0) { - const firstEntry = this._cache[0]; - const distance = this._maxRequestedIndex - firstEntry.end; - if (distance <= this._maxCacheSize) { - break; - } - this._cache.shift(); - } - this._currentIndex += value.byteLength; - } - this._pulling = false; - } - /** @internal */ - _dispose() { - this._pendingSlices.length = 0; - this._cache.length = 0; - } -} -const PREFETCH_PROFILES = { - fileSystem: (start, end) => { - const padding = 2 ** 16; - start = Math.floor((start - padding) / padding) * padding; - end = Math.ceil((end + padding) / padding) * padding; - return { start, end }; - }, - network: (start, end, workers) => { - const paddingStart = 2 ** 16; - start = Math.max(0, Math.floor((start - paddingStart) / paddingStart) * paddingStart); - for (const worker of workers) { - const maxExtensionAmount = 8 * 2 ** 20; - const thresholdPoint = Math.max((worker.startPos + worker.targetPos) / 2, worker.targetPos - maxExtensionAmount); - if (closedIntervalsOverlap(start, end, thresholdPoint, worker.targetPos)) { - const size = worker.targetPos - worker.startPos; - const a = Math.ceil((size + 1) / maxExtensionAmount) * maxExtensionAmount; - const b = 2 ** Math.ceil(Math.log2(size + 1)); - const extent = Math.min(b, a); - end = Math.max(end, worker.startPos + extent); - } - } - end = Math.max(end, start + URL_SOURCE_MIN_LOAD_AMOUNT); - return { - start, - end - }; - } -}; -class ReadOrchestrator { - constructor(options) { - this.options = options; - this.fileSize = null; - this.nextAge = 0; - this.workers = []; - this.cache = []; - this.currentCacheSize = 0; - this.disposed = false; - } - read(innerStart, innerEnd) { - assert(this.fileSize !== null); - const prefetchRange = this.options.prefetchProfile(innerStart, innerEnd, this.workers); - const outerStart = Math.max(prefetchRange.start, 0); - const outerEnd = Math.min(prefetchRange.end, this.fileSize); - assert(outerStart <= innerStart && innerEnd <= outerEnd); - let result = null; - const innerCacheStartIndex = binarySearchLessOrEqual(this.cache, innerStart, (x) => x.start); - const innerStartEntry = innerCacheStartIndex !== -1 ? this.cache[innerCacheStartIndex] : null; - if (innerStartEntry && innerStartEntry.start <= innerStart && innerEnd <= innerStartEntry.end) { - innerStartEntry.age = this.nextAge++; - result = { - bytes: innerStartEntry.bytes, - view: innerStartEntry.view, - offset: innerStartEntry.start - }; - } - const outerCacheStartIndex = binarySearchLessOrEqual(this.cache, outerStart, (x) => x.start); - const bytes = result ? null : new Uint8Array(innerEnd - innerStart); - let contiguousBytesWriteEnd = 0; - let lastEnd = outerStart; - const outerHoles = []; - if (outerCacheStartIndex !== -1) { - for (let i = outerCacheStartIndex; i < this.cache.length; i++) { - const entry = this.cache[i]; - if (entry.start >= outerEnd) { - break; - } - if (entry.end <= outerStart) { - continue; - } - const cappedOuterStart = Math.max(outerStart, entry.start); - const cappedOuterEnd = Math.min(outerEnd, entry.end); - assert(cappedOuterStart <= cappedOuterEnd); - if (lastEnd < cappedOuterStart) { - outerHoles.push({ start: lastEnd, end: cappedOuterStart }); - } - lastEnd = cappedOuterEnd; - if (bytes) { - const cappedInnerStart = Math.max(innerStart, entry.start); - const cappedInnerEnd = Math.min(innerEnd, entry.end); - if (cappedInnerStart < cappedInnerEnd) { - const relativeOffset = cappedInnerStart - innerStart; - bytes.set(entry.bytes.subarray(cappedInnerStart - entry.start, cappedInnerEnd - entry.start), relativeOffset); - if (relativeOffset === contiguousBytesWriteEnd) { - contiguousBytesWriteEnd = cappedInnerEnd - innerStart; - } - } - } - entry.age = this.nextAge++; - } - if (lastEnd < outerEnd) { - outerHoles.push({ start: lastEnd, end: outerEnd }); - } - } else { - outerHoles.push({ start: outerStart, end: outerEnd }); - } - if (bytes && contiguousBytesWriteEnd >= bytes.length) { - result = { - bytes, - view: toDataView(bytes), - offset: innerStart - }; - } - if (outerHoles.length === 0) { - assert(result); - return result; - } - const { promise, resolve, reject } = promiseWithResolvers(); - const innerHoles = []; - for (const outerHole of outerHoles) { - const cappedStart = Math.max(innerStart, outerHole.start); - const cappedEnd = Math.min(innerEnd, outerHole.end); - if (cappedStart === outerHole.start && cappedEnd === outerHole.end) { - innerHoles.push(outerHole); - } else if (cappedStart < cappedEnd) { - innerHoles.push({ start: cappedStart, end: cappedEnd }); - } - } - for (const outerHole of outerHoles) { - const pendingSlice = bytes && { - start: innerStart, - bytes, - holes: innerHoles, - resolve, - reject - }; - let workerFound = false; - for (const worker of this.workers) { - const gapTolerance = 2 ** 17; - if (closedIntervalsOverlap(outerHole.start - gapTolerance, outerHole.start, worker.currentPos, worker.targetPos)) { - worker.targetPos = Math.max(worker.targetPos, outerHole.end); - workerFound = true; - if (pendingSlice && !worker.pendingSlices.includes(pendingSlice)) { - worker.pendingSlices.push(pendingSlice); - } - if (!worker.running) { - this.runWorker(worker); - } - break; - } - } - if (!workerFound) { - const newWorker = this.createWorker(outerHole.start, outerHole.end); - if (pendingSlice) { - newWorker.pendingSlices = [pendingSlice]; - } - this.runWorker(newWorker); - } - } - if (!result) { - assert(bytes); - result = promise.then((bytes2) => ({ - bytes: bytes2, - view: toDataView(bytes2), - offset: innerStart - })); - } - return result; - } - createWorker(startPos, targetPos) { - const worker = { - startPos, - currentPos: startPos, - targetPos, - running: false, - // Due to async shenanigans, it can happen that workers are started after disposal. In this case, instead of - // simply not creating the worker, we allow it to run but immediately label it as aborted, so it can then - // shut itself down. - aborted: this.disposed, - pendingSlices: [], - age: this.nextAge++ - }; - this.workers.push(worker); - while (this.workers.length > this.options.maxWorkerCount) { - let oldestIndex = 0; - let oldestWorker = this.workers[0]; - for (let i = 1; i < this.workers.length; i++) { - const worker2 = this.workers[i]; - if (worker2.age < oldestWorker.age) { - oldestIndex = i; - oldestWorker = worker2; - } - } - if (oldestWorker.running && oldestWorker.pendingSlices.length > 0) { - break; - } - oldestWorker.aborted = true; - this.workers.splice(oldestIndex, 1); - } - return worker; - } - runWorker(worker) { - assert(!worker.running); - assert(worker.currentPos < worker.targetPos); - worker.running = true; - worker.age = this.nextAge++; - void this.options.runWorker(worker).catch((error) => { - worker.running = false; - if (worker.pendingSlices.length > 0) { - worker.pendingSlices.forEach((x) => x.reject(error)); - worker.pendingSlices.length = 0; - } else { - throw error; - } - }); - } - /** Called by a worker when it has read some data. */ - supplyWorkerData(worker, bytes) { - assert(!worker.aborted); - const start = worker.currentPos; - const end = start + bytes.length; - this.insertIntoCache({ - start, - end, - bytes, - view: toDataView(bytes), - age: this.nextAge++ - }); - worker.currentPos += bytes.length; - worker.targetPos = Math.max(worker.targetPos, worker.currentPos); - for (let i = 0; i < worker.pendingSlices.length; i++) { - const pendingSlice = worker.pendingSlices[i]; - const clampedStart = Math.max(start, pendingSlice.start); - const clampedEnd = Math.min(end, pendingSlice.start + pendingSlice.bytes.length); - if (clampedStart < clampedEnd) { - pendingSlice.bytes.set(bytes.subarray(clampedStart - start, clampedEnd - start), clampedStart - pendingSlice.start); - } - for (let j = 0; j < pendingSlice.holes.length; j++) { - const hole = pendingSlice.holes[j]; - if (start <= hole.start && end > hole.start) { - hole.start = end; - } - if (hole.end <= hole.start) { - pendingSlice.holes.splice(j, 1); - j--; - } - } - if (pendingSlice.holes.length === 0) { - pendingSlice.resolve(pendingSlice.bytes); - worker.pendingSlices.splice(i, 1); - i--; - } - } - for (let i = 0; i < this.workers.length; i++) { - const otherWorker = this.workers[i]; - if (worker === otherWorker || otherWorker.running) { - continue; - } - if (closedIntervalsOverlap(start, end, otherWorker.currentPos, otherWorker.targetPos)) { - this.workers.splice(i, 1); - i--; - } - } - } - forgetWorker(worker) { - const index = this.workers.indexOf(worker); - assert(index !== -1); - this.workers.splice(index, 1); - } - insertIntoCache(entry) { - if (this.options.maxCacheSize === 0) { - return; - } - let insertionIndex = binarySearchLessOrEqual(this.cache, entry.start, (x) => x.start) + 1; - if (insertionIndex > 0) { - const previous = this.cache[insertionIndex - 1]; - if (previous.end >= entry.end) { - return; - } - if (previous.end > entry.start) { - const joined = new Uint8Array(entry.end - previous.start); - joined.set(previous.bytes, 0); - joined.set(entry.bytes, entry.start - previous.start); - this.currentCacheSize += entry.end - previous.end; - previous.bytes = joined; - previous.view = toDataView(joined); - previous.end = entry.end; - insertionIndex--; - entry = previous; - } else { - this.cache.splice(insertionIndex, 0, entry); - this.currentCacheSize += entry.bytes.length; - } - } else { - this.cache.splice(insertionIndex, 0, entry); - this.currentCacheSize += entry.bytes.length; - } - for (let i = insertionIndex + 1; i < this.cache.length; i++) { - const next = this.cache[i]; - if (entry.end <= next.start) { - break; - } - if (entry.end >= next.end) { - this.cache.splice(i, 1); - this.currentCacheSize -= next.bytes.length; - i--; - continue; - } - const joined = new Uint8Array(next.end - entry.start); - joined.set(entry.bytes, 0); - joined.set(next.bytes, next.start - entry.start); - this.currentCacheSize -= entry.end - next.start; - entry.bytes = joined; - entry.view = toDataView(joined); - entry.end = next.end; - this.cache.splice(i, 1); - break; - } - while (this.currentCacheSize > this.options.maxCacheSize) { - let oldestIndex = 0; - let oldestEntry = this.cache[0]; - for (let i = 1; i < this.cache.length; i++) { - const entry2 = this.cache[i]; - if (entry2.age < oldestEntry.age) { - oldestIndex = i; - oldestEntry = entry2; - } - } - if (this.currentCacheSize - oldestEntry.bytes.length <= this.options.maxCacheSize) { - break; - } - this.cache.splice(oldestIndex, 1); - this.currentCacheSize -= oldestEntry.bytes.length; - } - } - dispose() { - for (const worker of this.workers) { - worker.aborted = true; - } - this.workers.length = 0; - this.cache.length = 0; - this.disposed = true; - } -} -polyfillSymbolDispose(); -class Input { - /** True if the input has been disposed. */ - get disposed() { - return this._disposed; - } - /** - * Creates a new input file from the specified options. No reading operations will be performed until methods are - * called on this instance. - */ - constructor(options) { - this._demuxerPromise = null; - this._format = null; - this._disposed = false; - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (!Array.isArray(options.formats) || options.formats.some((x) => !(x instanceof InputFormat))) { - throw new TypeError("options.formats must be an array of InputFormat."); - } - if (!(options.source instanceof Source)) { - throw new TypeError("options.source must be a Source."); - } - if (options.source._disposed) { - throw new Error("options.source must not be disposed."); - } - this._formats = options.formats; - this._source = options.source; - this._reader = new Reader(options.source); - } - /** @internal */ - _getDemuxer() { - return this._demuxerPromise ?? (this._demuxerPromise = (async () => { - this._reader.fileSize = await this._source.getSizeOrNull(); - for (const format of this._formats) { - const canRead = await format._canReadInput(this); - if (canRead) { - this._format = format; - return format._createDemuxer(this); - } - } - throw new Error("Input has an unsupported or unrecognizable format."); - })()); - } - /** - * Returns the source from which this input file reads its data. This is the same source that was passed to the - * constructor. - */ - get source() { - return this._source; - } - /** - * Returns the format of the input file. You can compare this result directly to the {@link InputFormat} singletons - * or use `instanceof` checks for subset-aware logic (for example, `format instanceof MatroskaInputFormat` is true - * for both MKV and WebM). - */ - async getFormat() { - await this._getDemuxer(); - assert(this._format); - return this._format; - } - /** - * Computes the duration of the input file, in seconds. More precisely, returns the largest end timestamp among - * all tracks. - */ - async computeDuration() { - const demuxer = await this._getDemuxer(); - return demuxer.computeDuration(); - } - /** Returns the list of all tracks of this input file. */ - async getTracks() { - const demuxer = await this._getDemuxer(); - return demuxer.getTracks(); - } - /** Returns the list of all video tracks of this input file. */ - async getVideoTracks() { - const tracks = await this.getTracks(); - return tracks.filter((x) => x.isVideoTrack()); - } - /** Returns the list of all audio tracks of this input file. */ - async getAudioTracks() { - const tracks = await this.getTracks(); - return tracks.filter((x) => x.isAudioTrack()); - } - /** Returns the primary video track of this input file, or null if there are no video tracks. */ - async getPrimaryVideoTrack() { - const tracks = await this.getTracks(); - return tracks.find((x) => x.isVideoTrack()) ?? null; - } - /** Returns the primary audio track of this input file, or null if there are no audio tracks. */ - async getPrimaryAudioTrack() { - const tracks = await this.getTracks(); - return tracks.find((x) => x.isAudioTrack()) ?? null; - } - /** Returns the full MIME type of this input file, including track codecs. */ - async getMimeType() { - const demuxer = await this._getDemuxer(); - return demuxer.getMimeType(); - } - /** - * Returns descriptive metadata tags about the media file, such as title, author, date, cover art, or other - * attached files. - */ - async getMetadataTags() { - const demuxer = await this._getDemuxer(); - return demuxer.getMetadataTags(); - } - /** - * Disposes this input and frees connected resources. When an input is disposed, ongoing read operations will be - * canceled, all future read operations will fail, any open decoders will be closed, and all ongoing media sink - * operations will be canceled. Disallowed and canceled operations will throw an {@link InputDisposedError}. - * - * You are expected not to use an input after disposing it. While some operations may still work, it is not - * specified and may change in any future update. - */ - dispose() { - if (this._disposed) { - return; - } - this._disposed = true; - this._source._disposed = true; - this._source._dispose(); - } - /** - * Calls `.dispose()` on the input, implementing the `Disposable` interface for use with - * JavaScript Explicit Resource Management features. - */ - [Symbol.dispose]() { - this.dispose(); - } -} -class InputDisposedError extends Error { - /** Creates a new {@link InputDisposedError}. */ - constructor(message = "Input has been disposed.") { - super(message); - this.name = "InputDisposedError"; - } -} -class Reader { - constructor(source) { - this.source = source; - } - requestSlice(start, length) { - if (this.source._disposed) { - throw new InputDisposedError(); - } - if (this.fileSize !== null && start + length > this.fileSize) { - return null; - } - const end = start + length; - const result = this.source._read(start, end); - if (result instanceof Promise) { - return result.then((x) => { - if (!x) { - return null; - } - return new FileSlice(x.bytes, x.view, x.offset, start, end); - }); - } else { - if (!result) { - return null; - } - return new FileSlice(result.bytes, result.view, result.offset, start, end); - } - } - requestSliceRange(start, minLength, maxLength) { - if (this.source._disposed) { - throw new InputDisposedError(); - } - if (this.fileSize !== null) { - return this.requestSlice(start, clamp$1(this.fileSize - start, minLength, maxLength)); - } else { - const promisedAttempt = this.requestSlice(start, maxLength); - const handleAttempt = (attempt) => { - if (attempt) { - return attempt; - } - const handleFileSize = (fileSize) => { - assert(fileSize !== null); - return this.requestSlice(start, clamp$1(fileSize - start, minLength, maxLength)); - }; - const promisedFileSize = this.source._retrieveSize(); - if (promisedFileSize instanceof Promise) { - return promisedFileSize.then(handleFileSize); - } else { - return handleFileSize(promisedFileSize); - } - }; - if (promisedAttempt instanceof Promise) { - return promisedAttempt.then(handleAttempt); - } else { - return handleAttempt(promisedAttempt); - } - } - } -} -class FileSlice { - constructor(bytes, view, offset, start, end) { - this.bytes = bytes; - this.view = view; - this.offset = offset; - this.start = start; - this.end = end; - this.bufferPos = start - offset; - } - static tempFromBytes(bytes) { - return new FileSlice(bytes, toDataView(bytes), 0, 0, bytes.length); - } - get length() { - return this.end - this.start; - } - get filePos() { - return this.offset + this.bufferPos; - } - set filePos(value) { - this.bufferPos = value - this.offset; - } - /** The number of bytes left from the current pos to the end of the slice. */ - get remainingLength() { - return Math.max(this.end - this.filePos, 0); - } - skip(byteCount) { - this.bufferPos += byteCount; - } - /** Creates a new subslice of this slice whose byte range must be contained within this slice. */ - slice(filePos, length = this.end - filePos) { - if (filePos < this.start || filePos + length > this.end) { - throw new RangeError("Slicing outside of original slice."); - } - return new FileSlice(this.bytes, this.view, this.offset, filePos, filePos + length); - } -} -const checkIsInRange = (slice, bytesToRead) => { - if (slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) { - throw new RangeError(`Tried reading [${slice.filePos}, ${slice.filePos + bytesToRead}), but slice is [${slice.start}, ${slice.end}). This is likely an internal error, please report it alongside the file that caused it.`); - } -}; -const readBytes = (slice, length) => { - checkIsInRange(slice, length); - const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length); - slice.bufferPos += length; - return bytes; -}; -const readU8 = (slice) => { - checkIsInRange(slice, 1); - return slice.view.getUint8(slice.bufferPos++); -}; -const readU16 = (slice, littleEndian) => { - checkIsInRange(slice, 2); - const value = slice.view.getUint16(slice.bufferPos, littleEndian); - slice.bufferPos += 2; - return value; -}; -const readU16Be = (slice) => { - checkIsInRange(slice, 2); - const value = slice.view.getUint16(slice.bufferPos, false); - slice.bufferPos += 2; - return value; -}; -const readU24Be = (slice) => { - checkIsInRange(slice, 3); - const value = getUint24(slice.view, slice.bufferPos, false); - slice.bufferPos += 3; - return value; -}; -const readI16Be = (slice) => { - checkIsInRange(slice, 2); - const value = slice.view.getInt16(slice.bufferPos, false); - slice.bufferPos += 2; - return value; -}; -const readU32 = (slice, littleEndian) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, littleEndian); - slice.bufferPos += 4; - return value; -}; -const readU32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; -}; -const readU32Le = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, true); - slice.bufferPos += 4; - return value; -}; -const readI32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getInt32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; -}; -const readI32Le = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getInt32(slice.bufferPos, true); - slice.bufferPos += 4; - return value; -}; -const readU64 = (slice, littleEndian) => { - let low; - let high; - if (littleEndian) { - low = readU32(slice, true); - high = readU32(slice, true); - } else { - high = readU32(slice, false); - low = readU32(slice, false); - } - return high * 4294967296 + low; -}; -const readU64Be = (slice) => { - const high = readU32Be(slice); - const low = readU32Be(slice); - return high * 4294967296 + low; -}; -const readI64Be = (slice) => { - const high = readI32Be(slice); - const low = readU32Be(slice); - return high * 4294967296 + low; -}; -const readI64Le = (slice) => { - const low = readU32Le(slice); - const high = readI32Le(slice); - return high * 4294967296 + low; -}; -const readF32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getFloat32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; -}; -const readF64Be = (slice) => { - checkIsInRange(slice, 8); - const value = slice.view.getFloat64(slice.bufferPos, false); - slice.bufferPos += 8; - return value; -}; -const readAscii = (slice, length) => { - checkIsInRange(slice, length); - let str = ""; - for (let i = 0; i < length; i++) { - str += String.fromCharCode(slice.bytes[slice.bufferPos++]); - } - return str; -}; class AudioEngine { constructor(events) { this.events = events; @@ -14476,16 +21254,6 @@ class AudioEngine { return this.playbackTimeAtStart; return (this.audioContext.currentTime - this.audioContextStartTime) * this.playbackRate + this.playbackTimeAtStart; } - normalizeSource(src) { - if (typeof src === "string") - return new UrlSource(src); - if (src instanceof Blob) - return new BlobSource(src); - if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { - return new ReadableStreamSource(src); - } - return src; - } ensureAudioContext(sampleRate) { if (this.audioContext) return; @@ -14513,27 +21281,22 @@ class AudioEngine { await this.audioIterator?.return(); this.audioIterator = null; } - async load(src, onMetadata) { - const id = ++this.asyncId; + handleNoAudioTrack() { + this.audioSink = null; + this.ensureAudioContext(); + } + async load(media, onMetadata) { + ++this.asyncId; await this.stopIterator(); this.stopQueuedNodes(); this.paused = true; this.playbackTimeAtStart = 0; this.audioContextStartTime = 0; - const source = this.normalizeSource(src); - if (!source) - return; - this.input = new Input({ - source, - formats: ALL_FORMATS - }); - this.duration = await this.input.computeDuration(); - if (id !== this.asyncId) - return; - const audioTrack = await this.input.getPrimaryAudioTrack(); + const { input, audioTrack, duration } = media; + this.input = input; + this.duration = duration; if (!audioTrack) { - this.audioSink = null; - this.ensureAudioContext(); + this.handleNoAudioTrack(); onMetadata?.(); return; } @@ -14666,6 +21429,99 @@ class AudioEngine { this.audioSink = null; } } +const M3U8_RE = /\.m3u8(?:$|[?#])/i; +function isHlsSource(src) { + return typeof src === "string" && M3U8_RE.test(src); +} +function normalizeSource(src) { + if (typeof src === "string") + return new UrlSource(src); + if (src instanceof Blob) + return new BlobSource(src); + if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { + return new ReadableStreamSource(src); + } + return src ?? null; +} +function createInput(src) { + const source = normalizeSource(src); + if (!source) + return null; + return new Input({ + source, + formats: isHlsSource(src) ? HLS_FORMATS : ALL_FORMATS + }); +} +async function resolveDuration({ input, videoTrack, audioTrack }) { + const tracks = [videoTrack, audioTrack].filter(Boolean); + const referenceTrack = videoTrack || audioTrack; + const isLive = Boolean(referenceTrack && await referenceTrack.isLive()); + let duration = Number.NaN; + if (tracks.length > 0) { + duration = await input.getDurationFromMetadata(tracks, { skipLiveWait: true }); + if (duration === null && !isLive) { + duration = await input.computeDuration(tracks, { skipLiveWait: true }); + } + } + return isLive ? Number.POSITIVE_INFINITY : duration ?? Number.NaN; +} +async function selectPlaybackTracks(input, src) { + const videoTrack = await input.getPrimaryVideoTrack(); + const audioTrack = videoTrack ? await videoTrack.getPrimaryPairableAudioTrack() : await input.getPrimaryAudioTrack(); + const duration = await resolveDuration({ input, videoTrack, audioTrack }); + return { + input, + videoTrack, + audioTrack, + duration, + isLive: Number.isFinite(duration) ? false : Boolean((videoTrack || audioTrack) && await (videoTrack || audioTrack).isLive()), + isHls: isHlsSource(src), + videoMode: isHlsSource(src) ? "auto" : "manual", + audioMode: isHlsSource(src) ? "auto" : "manual" + }; +} +async function getTrackBitrate(track) { + return await track.getAverageBitrate() ?? await track.getBitrate() ?? 0; +} +async function getHlsState(media) { + if (!media?.isHls || !media.input) + return null; + const [videoTracks, pairableAudioTracks] = await Promise.all([ + media.input.getVideoTracks(), + media.videoTrack ? media.videoTrack.getPairableAudioTracks() : [] + ]); + const [levels, audios] = await Promise.all([ + Promise.all(videoTracks.map(async (track, index) => ({ + id: track.id, + track, + index, + name: await track.getName(), + height: await track.getDisplayHeight(), + bitrate: await getTrackBitrate(track) + }))), + Promise.all(pairableAudioTracks.map(async (track, index) => { + const name = await track.getName(); + const language = await track.getLanguageCode(); + return { + id: track.id, + track, + index, + name, + lang: language, + language, + bitrate: await getTrackBitrate(track) + }; + })) + ]); + return { + levels, + audios, + currentLevel: media.videoTrack ? levels.find((item) => item.id === media.videoTrack.id) ?? null : null, + currentAudio: media.audioTrack ? audios.find((item) => item.id === media.audioTrack.id) ?? null : null, + videoMode: media.videoMode ?? "auto", + audioMode: media.audioMode ?? "auto" + }; +} class VideoEngine { constructor({ canvas, @@ -14701,18 +21557,8 @@ class VideoEngine { this.posterDrawn = false; this.isFetching = false; } - normalizeSource(src) { - if (typeof src === "string") - return new UrlSource(src); - if (src instanceof Blob) - return new BlobSource(src); - if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { - return new ReadableStreamSource(src); - } - return src; - } async preflight(url) { - if (!this.preflightRange || typeof url !== "string") + if (!this.preflightRange || typeof url !== "string" || isHlsSource(url)) return true; try { const res = await fetch(url, { method: "HEAD" }); @@ -14747,26 +21593,14 @@ class VideoEngine { clear() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); } - async load(src, onMetadata) { - const id = ++this.asyncId; + async load(media, onMetadata) { + ++this.asyncId; await this.stopIterator(); this.clear(); this.posterDrawn = false; - if (!await this.preflight(src)) - return; - const source = this.normalizeSource(src); - if (!source) { - this.drawPoster(); - return; - } - this.input = new Input({ - source, - formats: ALL_FORMATS - }); - this.duration = await this.input.computeDuration(); - if (id !== this.asyncId) - return; - const videoTrack = await this.input.getPrimaryVideoTrack(); + const { input, videoTrack, duration } = media; + this.input = input; + this.duration = duration; if (!videoTrack) { this.handleNoVideoTrack(); onMetadata?.(); @@ -14809,7 +21643,6 @@ class VideoEngine { this.nextFrame = second; if (first) { this.ctx.drawImage(first.canvas, 0, 0); - this.events.emit("loadeddata"); } else { this.drawPoster(); } @@ -14902,8 +21735,8 @@ class VideoEngine { this.stop(); this.stopIterator(); this.posterDrawn = false; - this.input = null; this.videoSink = null; + this.input = null; } } class MediaBunnyEngine { @@ -14928,6 +21761,8 @@ class MediaBunnyEngine { this.error = null; this.seeking = false; this.loadSeq = 0; + this.input = null; + this.media = null; events.addEventListener?.("ended", () => { this.ended = true; this.paused = true; @@ -14936,6 +21771,7 @@ class MediaBunnyEngine { async load(src) { const id = ++this.loadSeq; this.pause(); + this.disposeInput(); this.ended = false; this.error = null; this.networkState = 2; @@ -14959,8 +21795,24 @@ class MediaBunnyEngine { } } async performLoad(src, id) { - let videoMetadataLoaded = false; - let audioMetadataLoaded = false; + if (!await this.video.preflight(src)) + return; + const input = createInput(src); + if (!input) { + this.video.handleNoVideoTrack(); + this.audio.handleNoAudioTrack(); + return; + } + const media = await selectPlaybackTracks(input, src); + if (id !== this.loadSeq) { + input.dispose(); + return; + } + this.disposeInput(); + this.input = input; + this.media = media; + let videoMetadataLoaded = !media.videoTrack; + let audioMetadataLoaded = !media.audioTrack; const checkMetadata = () => { if (videoMetadataLoaded && audioMetadataLoaded) { this.readyState = 1; @@ -14971,13 +21823,13 @@ class MediaBunnyEngine { }; try { await Promise.all([ - this.video.load(src, () => { + this.video.load(media, () => { if (id !== this.loadSeq) return; videoMetadataLoaded = true; checkMetadata(); }), - this.audio.load(src, () => { + this.audio.load(media, () => { if (id !== this.loadSeq) return; audioMetadataLoaded = true; @@ -15006,6 +21858,95 @@ class MediaBunnyEngine { setTimeout(() => reject(new Error("Load timeout")), ms); }); } + disposeInput() { + this.input?.dispose(); + this.input = null; + this.media = null; + } + async replaceTracks({ videoTrack, audioTrack, videoMode, audioMode }) { + if (!this.media) + return; + const nextMedia = { + ...this.media, + videoTrack, + audioTrack, + videoMode, + audioMode + }; + const shouldResume = !this.paused; + const currentTime = this.currentTime; + this.pause(); + this.ended = false; + this.seeking = true; + this.events.emit("seeking"); + this.events.emit("waiting"); + nextMedia.duration = await resolveDuration(nextMedia); + this.media = nextMedia; + await Promise.all([ + this.video.load(nextMedia), + this.audio.load(nextMedia) + ]); + await Promise.all([ + this.video.seek(currentTime), + this.audio.seek(currentTime) + ]); + this.readyState = 4; + this.networkState = 1; + this.seeking = false; + this.events.emit("loadedmetadata"); + this.events.emit("durationchange"); + this.events.emit("progress"); + this.events.emit("loadeddata"); + this.events.emit("canplay"); + this.events.emit("canplaythrough"); + this.events.emit("seeked"); + if (shouldResume) { + await this.play(); + } + } + async selectHlsQuality(value) { + if (!this.media?.isHls || !this.input) + return; + const videoTracks = await this.input.getVideoTracks(); + const videoTrack = value === "auto" ? await this.input.getPrimaryVideoTrack() : videoTracks.find((track) => track.id === value) ?? this.media.videoTrack; + if (!videoTrack) + return; + let audioTrack = this.media.audioTrack; + let audioMode = this.media.audioMode; + if (!audioTrack || !videoTrack.canBePairedWith(audioTrack)) { + audioTrack = await videoTrack.getPrimaryPairableAudioTrack(); + audioMode = "auto"; + } + await this.replaceTracks({ + videoTrack, + audioTrack, + videoMode: value === "auto" ? "auto" : "manual", + audioMode + }); + } + async selectHlsAudio(value) { + if (!this.media?.isHls || !this.input) + return; + const audioTracks = await this.input.getAudioTracks(); + const audioTrack = value === "auto" ? this.media.videoTrack ? await this.media.videoTrack.getPrimaryPairableAudioTrack() : await this.input.getPrimaryAudioTrack() : audioTracks.find((track) => track.id === value) ?? this.media.audioTrack; + if (!audioTrack) + return; + let videoTrack = this.media.videoTrack; + let videoMode = this.media.videoMode; + if (!videoTrack || !audioTrack.canBePairedWith(videoTrack)) { + videoTrack = await audioTrack.getPrimaryPairableVideoTrack(); + videoMode = "auto"; + } + await this.replaceTracks({ + videoTrack, + audioTrack, + videoMode, + audioMode: value === "auto" ? "auto" : "manual" + }); + } + getHlsState() { + return getHlsState(this.media); + } async play() { if (!this.paused) return; @@ -15053,6 +21994,7 @@ class MediaBunnyEngine { } destroy() { this.pause(); + this.disposeInput(); this.audio.destroy(); this.video.destroy(); } @@ -15061,7 +22003,7 @@ class MediaBunnyEngine { return this.audio.currentTime; } get duration() { - return this.audio.duration || this.video.duration; + return this.media?.duration ?? this.audio.duration ?? this.video.duration; } get videoWidth() { return this.video.width; @@ -15214,6 +22156,15 @@ class VideoShim { if (this._src) this.engine.load(this._src); } + getM3u8State() { + return this.engine.getHlsState(); + } + switchM3u8Quality(value) { + return this.engine.selectHlsQuality(value); + } + switchM3u8Audio(value) { + return this.engine.selectHlsAudio(value); + } // Video dimensions get videoWidth() { return this.engine.videoWidth; @@ -15324,6 +22275,7 @@ function artplayerProxyMediabunny(option = {}) { ctx, option }); + art.mediabunny = shim; const originalCanvasMethods = {}; for (const prop in canvas) { if (typeof canvas[prop] === "function") { @@ -15366,7 +22318,9 @@ function artplayerProxyMediabunny(option = {}) { } art.on("resize", resize); art.on("video:loadedmetadata", resize); + setupM3u8Controls({ art, shim, option }); art.on("destroy", () => { + delete art.mediabunny; shim.destroy(); }); return canvas; diff --git a/docs/compiled/artplayer.js b/docs/compiled/artplayer.js index 858619e16..cc6d0d1c0 100644 --- a/docs/compiled/artplayer.js +++ b/docs/compiled/artplayer.js @@ -4,4 +4,4 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";function t(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var e,r={exports:{}};var a=(e||(e=1,r.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var o=t(r);if("boolean"===o)return"boolean";if("string"===o)return"string";if("number"===o)return"number";if("symbol"===o)return"symbol";if("function"===o)return"GeneratorFunction"===a(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(a(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(o=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return o.slice(8,-1).toLowerCase().replace(/\s/g,"")};function a(t){return t.constructor?t.constructor.name:null}function o(t,e){var a=2=1,p=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(s)||d,h="undefined"!==typeof window&&"undefined"!==typeof document;function u(t,e=document){return e.querySelector(t)}function m(t,e=document){return Array.from(e.querySelectorAll(t))}function f(t,e){return t.classList.add(e)}function g(t,e){return t.classList.remove(e)}function v(t,e){return t.classList.contains(e)}function y(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function b(t){return t.parentNode.removeChild(t)}function w(t,e,r){return t.style[e]=r,t}function x(t,e){for(const r in e)w(t,r,e[r]);return t}function k(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function $(t,e){k(t).forEach(t=>g(t,e)),f(t,e)}function T(t,e,r="top"){p||(t.setAttribute("aria-label",e),f(t,"hint--rounded"),f(t,`hint--${r}`))}function E(t,e=0){const r=t.getBoundingClientRect(),a=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=a&&r.top+r.height+e>=0,i=r.left-e<=o+e&&r.left+r.width+e>=0;return n&&i}function C(t,e){return R(t).includes(e)}function z(t,e){return e.parentNode.replaceChild(t,e),t}function L(t){return document.createElement(t)}function S(t="",e=""){const r=L("i");return f(r,"art-icon"),f(r,`art-icon-${t}`),y(r,e),r}function M(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function I(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function A(t){return t.getBoundingClientRect()}function P(t,e){return new Promise((r,a)=>{const o=new Image;o.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=o.width*e,n.height=o.height*e,i.drawImage(o,0,0,n.width,n.height),n.toBlob(e=>{const o=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(o),a(new Error(`Image load failed: ${t}`))},n.src=o})}else r(o)},o.onerror=function(){a(new Error(`Image load failed: ${t}`))},o.src=t})}function R(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function O(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class _ extends Error{constructor(t,e){super(t),"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function V(t,e){if(!t)throw new _(e);return t}function Y(t){return t.includes("?")?Y(t.split("?")[0]):t.includes("#")?Y(t.split("#")[0]):t.trim().toLowerCase().split(".").pop()}function N(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r)}function D(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function F(t){return t.charAt(0).toUpperCase()+t.slice(1)}function B(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),a=Math.floor(t-3600*e-60*r);return(e>0?[e,r,a]:[r,a]).map(t=>t<10?`0${t}`:String(t)).join(":")}function H(t){return t.replace(/[&<>'"]/g,t=>({"&":"&","<":"<",">":">","'":"'",'"':"""}[t]||t))}const W=Object.defineProperty,{hasOwnProperty:j}=Object.prototype;function U(t,e){return j.call(t,e)}function q(t,e){return Object.getOwnPropertyDescriptor(t,e)}function X(...t){const e=t=>t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(a=>{const o=t[a],n=r[a];Array.isArray(o)&&Array.isArray(n)?t[a]=o.concat(...n):e(o)&&e(n)?t[a]=X(o,n):t[a]=n}),t),{})}function G(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let a=r.slice(0,3);return 1===r.length&&(a=`${r}00`),2===r.length&&(a=`${r}0`),`${e},${a}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function K(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function Z(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const a=t.match(e);return a?{start:r(a[1].trim()),end:r(a[2].trim()),text:a[5].replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}:null}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function J(t=0){return new Promise(e=>setTimeout(e,t))}function Q(t,e){let r;return function(...a){clearTimeout(r),r=setTimeout(()=>(r=null,t.apply(this,a)),e)}}function tt(t,e){let r=!1;return function(...a){r||(t.apply(this,a),r=!0,setTimeout(()=>{r=!1},e))}}const et=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:_,addClass:f,append:y,assToVtt:Z,capitalize:F,clamp:D,createElement:L,debounce:Q,def:W,download:N,errorHandle:V,escape:H,get:q,getComposedPath:R,getExt:Y,getIcon:S,getRect:A,getSafeAreaInsets:O,getStyle:function(t,e,r=!0){const a=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(a):a},has:U,hasClass:v,includeFromEvent:C,inverseClass:$,isBrowser:h,isIOS:c,isIOS13:d,isInViewport:E,isMobile:p,isSafari:l,loadImg:P,mergeDeep:X,query:u,queryAll:m,remove:b,removeClass:g,replaceElement:z,secondToTime:B,setStyle:w,setStyleText:M,setStyles:x,siblings:k,sleep:J,srtToVtt:G,supportsFlex:I,throttle:tt,tooltip:T,unescape:function(t){const e={"&":"&","<":"<",">":">","'":"'",""":'"'},r=new RegExp(`(${Object.keys(e).join("|")})`,"g");return t.replace(r,t=>e[t]||t)},userAgent:s,vttToBlob:K},Symbol.toStringTag,{value:"Module"})),rt="array",at="boolean",ot="string",nt="number",it="object",st="function";function lt(t,e,r){return V(e===ot||e===nt||t instanceof Element,`${r.join(".")} require '${ot}' or 'Element' type`)}const ct={html:lt,disable:`?${at}`,name:`?${ot}`,index:`?${nt}`,style:`?${it}`,click:`?${st}`,mounted:`?${st}`,tooltip:`?${ot}|${nt}`,width:`?${nt}`,selector:`?${rt}`,onSelect:`?${st}`,switch:`?${at}`,onSwitch:`?${st}`,range:`?${rt}`,onRange:`?${st}`,onChange:`?${st}`},dt={id:ot,container:lt,url:ot,poster:ot,type:ot,theme:ot,lang:ot,volume:nt,isLive:at,muted:at,autoplay:at,autoSize:at,autoMini:at,loop:at,flip:at,playbackRate:at,aspectRatio:at,screenshot:at,setting:at,hotkey:at,pip:at,mutex:at,backdrop:at,fullscreen:at,fullscreenWeb:at,subtitleOffset:at,miniProgressBar:at,useSSR:at,playsInline:at,lock:at,gesture:at,fastForward:at,autoPlayback:at,autoOrientation:at,airplay:at,proxy:`?${st}`,plugins:[st],layers:[ct],contextmenu:[ct],settings:[ct],controls:[{...ct,position:(t,e,r)=>{const a=["top","left","right"];return V(a.includes(t),`${r.join(".")} only accept ${a.toString()} as parameters`)}}],quality:[{default:`?${at}`,html:ot,url:ot}],highlight:[{time:nt,text:ot}],thumbnails:{url:ot,number:nt,column:nt,width:nt,height:nt,scale:nt},subtitle:{url:ot,name:ot,type:ot,style:it,escape:at,encoding:ot,onVttLoad:st},moreVideoAttr:it,i18n:it,icons:it,cssVar:it,customType:it};class pt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return v(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?f(e,r):g(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",o(e,ct),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;V(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const a=L("div");f(a,`art-${this.name}`),f(a,`art-${this.name}-${r}`);const n=Array.from(this.$parent.children);a.dataset.index=e.index||this.id;const i=n.find(t=>Number(t.dataset.index)>=Number(a.dataset.index));i?i.insertAdjacentElement("beforebegin",a):y(this.$parent,a),e.html&&y(a,e.html),e.style&&x(a,e.style),e.tooltip&&T(a,e.tooltip);const s=[];if(e.click){const t=this.art.events.proxy(a,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});s.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,a,s),this[r]=a,this.cache.set(r,{$ref:a,events:s,option:e}),e.mounted&&e.mounted.call(this.art,a),a}remove(t){V(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],b(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class ht extends pt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,p||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:a}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:a}}=e,o=a.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return{...t,html:`${r.get("Play Speed")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.playbackRate=Number(a),t.show=!1)},mounted:t=>{const r=u('[data-value="1"]',t);r&&$(r,"art-current"),e.on("video:ratechange",()=>{const r=m("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&$(r,"art-current")})}}}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:a}}=e,o=a.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return{...t,html:`${r.get("Aspect Ratio")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.aspectRatio=a,t.show=!1)},mounted:t=>{const r=u('[data-value="default"]',t);r&&$(r,"art-current"),e.on("aspectRatio",e=>{const r=m("span",t).find(t=>t.dataset.value===e);r&&$(r,"art-current")})}}}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:a}}=e,o=a.map(t=>`${r.get(F(t))}`).join("");return{...t,html:`${r.get("Video Flip")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.flip=a.toLowerCase(),t.show=!1)},mounted:t=>{const r=u('[data-value="normal"]',t);r&&$(r,"art-current"),e.on("flip",e=>{const r=m("span",t).find(t=>t.dataset.value===e);r&&$(r,"art-current")})}}}}({name:"flip",index:30})),this.add(function(t){return e=>({...t,html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){const e=h?location.href:"";return{...t,html:`ArtPlayer ${n}`}}({name:"version",index:50})),this.add(function(t){return e=>({...t,html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let o=0;o{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,o=t.clientY,{height:n,width:i,left:s,top:l}=A(r),{height:c,width:d}=A(a);let p=e-s,h=o-l;e+d>s+i&&(p=i-d),o+c>l+n&&(h=n-c),x(a,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{C(t,a)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}function ut(t,e){const{$progress:r}=t.template,{left:a}=A(r),o=D((p?e.touches[0].clientX:e.clientX)-a,0,r.clientWidth),n=o/r.clientWidth*t.duration;return{second:n,time:B(n),width:o,percentage:D(o/r.clientWidth,0,1)}}function mt(t,e){if(t.isRotate){const r=e.touches[0].clientY/t.height,a=r*t.duration;t.emit("setBar","played",r,e),t.seek=a}else{const{second:r,percentage:a}=ut(t,e);t.emit("setBar","played",a,e),t.seek=r}}function ft(t){return e=>{const{icons:r,option:a,proxy:o}=e,{$player:n,$progress:i}=e.template;return{...t,html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=u(".art-progress-hover",t),d=u(".art-progress-loaded",t),h=u(".art-progress-played",t),m=u(".art-progress-highlight",t),v=u(".art-progress-indicator",t),b=u(".art-progress-tip",t);function x(r,a){const{width:o,time:n}=a||ut(e,r);b.textContent=n||"00:00";const i=b.clientWidth;o<=i/2?w(b,"left",0):o>t.clientWidth-i/2?w(b,"left",t.clientWidth-i+"px"):w(b,"left",o-i/2+"px")}r.indicator?y(v,r.indicator):w(v,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,a,o){const i="played"===r&&o&&p;if("loaded"===r&&w(d,"width",100*a+"%"),"hover"===r&&(w(c,"width",100*a+"%"),C(o,m)?function(r){const{width:a}=ut(e,r),{text:o}=r.target.dataset;b.textContent=o;const n=b.clientWidth;a<=n/2?w(b,"left",0):a>t.clientWidth-n/2?w(b,"left",t.clientWidth-n+"px"):w(b,"left",a-n/2+"px")}(o):x(o),0===a?g(n,"art-progress-hover"):f(n,"art-progress-hover")),"played"===r&&(w(h,"width",100*a+"%"),w(v,"left",100*a+"%")),i){f(n,"art-progress-hover");x(o,{width:t.clientWidth*a,time:B(a*e.duration)}),clearTimeout(s),s=setTimeout(()=>{g(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){m.textContent="";for(let t=0;t`;y(m,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),p||(o(i,"click",t=>{t.target!==v&&mt(e,t)}),o(i,"mousemove",t=>{const{percentage:r}=ut(e,t);e.emit("setBar","hover",r,t)}),o(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),o(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:a}=ut(e,t);e.emit("setBar","played",a,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}}}}class gt extends pt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:a}=this.art.template;t.on("mousemove",()=>{p||(this.show=!0)}),t.on("click",()=>{p?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=C(t,a)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(g(r,"art-hide-cursor"),f(r,"art-hover"),this.timer=Date.now()):(f(r,"art-hide-cursor"),g(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(ft({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.play),i=y(t,a.pause);function s(){w(n,"display","flex"),w(i,"display","none")}function l(){w(n,"display","none"),w(i,"display","flex")}T(n,o.get("Play")),T(i,o.get("Pause")),r(n,"click",()=>{e.play()}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:a}=e,o=y(t,a.volume),n=y(t,a.volumeClose),i=y(t,'
'),s=y(i,'
'),l=y(s,'
'),c=y(s,'
'),d=y(c,'
'),h=y(d,'
'),u=y(c,'
');function m(t){const{top:e,height:r}=A(c);return 1-(t.clientY-e)/r}function f(){if(e.muted||0===e.volume)w(o,"display","none"),w(n,"display","flex"),w(u,"top","100%"),w(h,"top","100%"),l.textContent=0;else{const t=100*e.volume;w(o,"display","flex"),w(n,"display","none"),w(u,"top",100-t+"%"),w(h,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(f(),e.on("video:volumechange",f),r(o,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),p)w(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=m(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=m(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>({...t,style:p?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${B(e.currentTime)} / ${B(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const a=["video:loadedmetadata","video:timeupdate","video:progress"];for(let o=0;o{this.art.quality=t.quality}),t.screenshot&&!p&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:a}=e;y(t,a.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e;y(t,a.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{T(t,o.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e;y(t,a.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{T(t,o.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:a}=e;y(t,a.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.fullscreenWebOn),i=y(t,a.fullscreenWebOff);w(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(T(t,o.get("Exit Web Fullscreen")),w(n,"display","none"),w(i,"display","inline-flex")):(T(t,o.get("Web Fullscreen")),w(n,"display","inline-flex"),w(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.fullscreenOn),i=y(t,a.fullscreenOff);w(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(T(t,o.get("Exit Fullscreen")),w(n,"display","none"),w(i,"display","inline-flex")):(T(t,o.get("Fullscreen")),w(n,"display","inline-flex"),w(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),W(e,"$control_item",{get:()=>r}),W(e,"$control_value",{get:()=>o})}const i=a(n,"click",async e=>{const r=R(e),a=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(a),t.onSelect&&(o.innerHTML=await t.onSelect.call(this.art,a,a.$control_item,e))});r.push(i)}}function vt(t,e,r,a){const o=e-a,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(o)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,o);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}class yt{constructor(t){this.destroyEvents=new Set,this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:a,$video:o}}=t;function n(e){C(e,a)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(o,"click",e=>{const a=Date.now();i.push(a);const{MOBILE_CLICK_PLAY:o,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>a-t<=n);switch(c.length){case 1:t.emit("click",e),p?!t.isLock&&o&&t.toggle():t.toggle(),i=c;break;case 2:t.emit("dblclick",e),p?!t.isLock&&s&&t.toggle():l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{f(r,"art-hover"),t.emit("hover",!0,e)},e=>{g(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:a}=t;t.on("resize",()=>{const{aspectRatio:e,notice:a}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,a.show=""});const o=Q(()=>t.emit("resize"),a.RESIZE_TIME);t.on("window:orientationchange",()=>o()),t.on("window:resize",()=>o()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>o())}(t,this),function(t,e){if(p&&!t.option.isLive){const{$video:r,$progress:a}=t.template;let o=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){o===a&&mt(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:a,pageY:n}=e.touches[0],c=vt(i,s,a,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=D((a-i)/t.width,-1,1),d=D((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=o===r?t.constructor.TOUCH_MOVE_RATIO:1,u=D(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",D(u/t.duration,0,1),e),t.notice.show=`${B(u)} / ${B(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,o=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{o=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(a,"touchstart",t=>{o=a,c(t)}),e.proxy(a,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:a}}=t,o=tt(()=>{t.emit("view",E(a,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>o()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],a=["resize","scroll","orientationchange"],o=[];function n(n={}){for(let t=0;t{const a=n.document||i.ownerDocument||document,s=e.proxy(a,r,e=>{t.emit(`document:${r}`,e)});o.push(s)}),a.forEach(r=>{const a=n.window||i.ownerDocument?.defaultView||window,s=e.proxy(a,r,e=>{t.emit(`window:${r}`,e)});o.push(s)})}n(),e.bindGlobalEvents=n}(t,this),function(t){if(t.constructor.USE_RAF){let e=null;!function r(){t.playing&&t.emit("raf"),t.isDestroy||(e=requestAnimationFrame(r))}(),t.on("destroy",()=>{cancelAnimationFrame(e)})}}(t)}proxy(t,e,r,a={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,a));t.addEventListener(e,r,a);const o=()=>t.removeEventListener(e,r,a);return this.destroyEvents.add(o),o}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class bt{constructor(t){this.art=t,this.keys={},p||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{this.art.toggle()}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',state:'\n\n\n',play:'\n \n',pause:'\n \n',check:'\n\n',volume:'\n \n \n',volumeClose:'\n \n \n',screenshot:'\n\t\n\n',setting:'\n \n \n',pip:'\n\n',arrowLeft:'\n \n',arrowRight:'\n \n',playbackRate:'',aspectRatio:'',config:'',lock:'\n\n\n\n\n',flip:'\n\n\n\n\n\n',unlock:'\n\n\n',fullscreenOff:'\n\n\n\n\n',fullscreenOn:'\n\n\n\n\n',fullscreenWebOff:'\n\n\n\n\n',fullscreenWebOn:'\n\n\n\n\n',switchOn:'\n\n\n \n',switchOff:'\n\n\n \n\n',error:'\n\n\n\n\n',close:'\n\n\n\n\n',airplay:'\n \n \n \n \n\n',...t.option.icons};for(const r in e)W(this,r,{get:()=>S(r,e[r])})}}class $t extends pt{constructor(t){super(t),this.name="info",p||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:a,$video:o}}=this.art;t(a,"click",()=>{this.show=!1});let n=null;const i=m("[data-video]",r)||[];this.art.on("destroy",()=>clearTimeout(n)),function t(){for(let e=0;e{w(o,"display","none"),w(n,"display",null)}),a.proxy(e.$state,"click",()=>t.play())}}class zt{constructor(t){this.art=t,this.timer=null,t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){const{constructor:e,template:{$player:r,$noticeInner:a}}=this.art;t?(a.textContent=t instanceof Error?t.message.trim():t,f(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{a.textContent="",g(r,"art-notice-show")},e.NOTICE_TIME)):g(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}const Lt=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],St=(()=>{if("undefined"===typeof document)return!1;const t=Lt[0],e={};for(const r of Lt){if(r[1]in document){for(const[a,o]of r.entries())e[t[a]]=o;return e}}return!1})(),Mt={change:St.fullscreenchange,error:St.fullscreenerror},It={request:(t=document.documentElement,e)=>new Promise((r,a)=>{const o=()=>{It.off("change",o),r()};It.on("change",o);const n=t[St.requestFullscreen](e);n instanceof Promise&&n.then(o).catch(a)}),exit:()=>new Promise((t,e)=>{if(!It.isFullscreen)return void t();const r=()=>{It.off("change",r),t()};It.on("change",r);const a=document[St.exitFullscreen]();a instanceof Promise&&a.then(r).catch(e)}),toggle:(t,e)=>It.isFullscreen?It.exit():It.request(t,e),onchange(t){It.on("change",t)},onerror(t){It.on("error",t)},on(t,e){const r=Mt[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Mt[t];r&&document.removeEventListener(r,e,!1)},raw:St};function At(t){const{i18n:e,notice:r,template:{$video:a,$player:o}}=t;t.once("video:loadedmetadata",()=>{var n;It.isEnabled?(n=t,It.on("change",()=>{n.emit("fullscreen",It.isFullscreen),It.isFullscreen?(n.state="fullscreen",f(o,"art-fullscreen")):g(o,"art-fullscreen"),n.emit("resize")}),It.on("error",t=>{n.emit("fullscreenError",t)}),W(n,"fullscreen",{get:()=>It.isFullscreen,async set(t){t?await It.request(o):await It.exit()}})):a.webkitSupportsFullscreen?(t=>{t.on("document:webkitfullscreenchange",()=>{t.emit("fullscreen",t.fullscreen),t.emit("resize")}),W(t,"fullscreen",{get:()=>document.fullscreenElement===a,set(e){e?(t.state="fullscreen",a.webkitEnterFullscreen()):a.webkitExitFullscreen()}})})(t):W(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),W(t,"fullscreen",q(t,"fullscreen"))})}function Pt(t){const{icons:e,proxy:r,storage:a,template:{$player:o,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(g(o,"art-mini"),w(e,"display","none"),o.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(w(e,"display","none"),w(r,"display","flex")):(w(e,"display","flex"),w(r,"display","none"))}function p(){const{$mini:e}=t.template,r=A(e),o=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;a.set("top",o),a.set("left",n),w(e,"top",`${o}px`),w(e,"left",`${n}px`)}W(t,"mini",{get:()=>v(o,"art-mini"),set(h){if(h){t.state="mini",f(o,"art-mini");const h=function(){const{$mini:o}=t.template;if(o)return y(o,n),w(o,"display","flex");{const o=L("div");f(o,"art-mini-popup"),y(document.body,o),t.template.$mini=o,y(o,n);const p=y(o,'
');y(p,e.close),r(p,"click",c);const h=y(o,'
'),u=y(h,e.play),m=y(h,e.pause);return r(u,"click",()=>t.play()),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(o,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){f(o,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;w(o,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,g(o,"art-mini-dragging");const t=A(o);a.set("left",t.left),a.set("top",t.top),w(o,"left",`${t.left}px`),w(o,"top",`${t.top}px`),w(o,"transform",null)}}),o}}(),u=a.get("top"),m=a.get("left");"number"===typeof u&&"number"===typeof m?(w(h,"top",`${u}px`),w(h,"left",`${m}px`),E(h)||p()):p(),t.emit("mini",!0)}else c()}})}function Rt(t){const{i18n:e,notice:r,template:{$video:a}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:a}=t;e.disablePictureInPicture=!1,W(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw a.show=t,t})):document.exitPictureInPicture().catch(t=>{throw a.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):a.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),W(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):W(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ot(t){const{option:e,template:{$progress:r,$video:a}}=t;let o=null,n=!1,i=null;t.on("setBar",async(o,s,l)=>{const c=t.controls?.thumbnails,{url:d,scale:h}=e.thumbnails;if(!c||!d)return;if("hover"===o||"played"===o&&l&&p){if(i||n||(n=!0,i=await P(d,h),n=!1),!i)return;const o=r.clientWidth*s;o>0&&or.clientWidth-h/2?w(n,"left",r.clientWidth-h+"px"):w(n,"left",o-h/2+"px")}(o)}}),W(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(o),o=null,n=!1,i=null)}})}Object.defineProperties(It,{isFullscreen:{get:()=>Boolean(document[St.fullscreenElement])},element:{enumerable:!0,get:()=>document[St.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[St.fullscreenEnabled])}});class _t{constructor(t){!function(t){const{option:e,template:{$video:r}}=t;W(t,"url",{get:()=>r.src,async set(a){if(a){const o=t.url,n=e.type||Y(a),i=e.customType[n];n&&i?(await J(),t.loading.show=!0,i.call(t,r,a,t)):(URL.revokeObjectURL(o),r.src=a),o!==t.url&&(t.option.url=a,t.isReady&&o&&t.once("video:canplay",()=>{t.emit("restart",a)}))}else await J(),t.loading.show=!0}})}(t),function(t){const{template:{$video:e}}=t;W(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:a,constructor:{instances:o},template:{$video:n}}=t;W(t,"play",{async value(){const i=await n.play();if(r.show=e.get("Play"),t.emit("play"),a.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;W(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${B(t.currentTime)} / ${B(t.duration)}`),t.emit("seek",t.currentTime,r)}}),W(t,"forward",{set(e){t.seek=t.currentTime+e}}),W(t,"backward",{set(e){t.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:a,storage:o}=t;W(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=D(t,0,1),a.show=`${r.get("Volume")}: ${Number.parseInt(100*e.volume,10)}`,0!==e.volume&&o.set("volume",e.volume)}}),W(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;W(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{r=Number.parseFloat(r),Number.isNaN(r)||(e.currentTime=D(r,0,t.duration))}})}(t),function(t){W(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){function e(e,r){return new Promise((a,o)=>{if(e===t.url)return void a();const{playing:n,aspectRatio:i,playbackRate:s}=t;t.pause(),t.url=e,t.notice.show="";const l={error:e=>{t.off("video:canplay",l.canplay),t.off("video:loadedmetadata",l.metadata),o(e)},metadata:()=>{t.currentTime=r},canplay:async()=>{t.off("video:error",l.error),t.playbackRate=s,t.aspectRatio=i,n&&await t.play(),t.notice.show="",a()}};t.once("video:error",l.error),t.once("video:loadedmetadata",l.metadata),t.once("video:canplay",l.canplay)})}W(t,"switchQuality",{value:r=>e(r,t.currentTime)}),W(t,"switchUrl",{value:t=>e(t,0)}),W(t,"switch",{set:t.switchUrl})}(t),function(t){const{template:{$video:e},i18n:r,notice:a}=t;W(t,"playbackRate",{get:()=>e.playbackRate,set(o){if(o){if(o===e.playbackRate)return;e.playbackRate=o,a.show=`${r.get("Rate")}: ${1===o?r.get("Normal"):`${o}x`}`}else t.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:a,$player:o}}=t;W(t,"aspectRatio",{get:()=>o.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)w(a,"width",null),w(a,"height",null),w(a,"margin",null),delete o.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=o,i=e/r,s=t[0]/t[1];i>s?(w(a,"width",s*r+"px"),w(a,"height","100%"),w(a,"margin","0 auto")):(w(a,"width","100%"),w(a,"height",e/s+"px"),w(a,"margin","auto 0")),o.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,a=L("canvas");W(t,"getDataURL",{value:()=>new Promise((t,o)=>{try{a.width=r.videoWidth,a.height=r.videoHeight,a.getContext("2d").drawImage(r,0,0),t(a.toDataURL("image/png"))}catch(n){e.show=n,o(n)}})}),W(t,"getBlobUrl",{value:()=>new Promise((t,o)=>{try{a.width=r.videoWidth,a.height=r.videoHeight,a.getContext("2d").drawImage(r,0,0),a.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,o(n)}})}),W(t,"screenshot",{value:async e=>{const a=await t.getDataURL();return N(a,`${e||`artplayer_${B(r.currentTime)}`}.png`),t.emit("screenshot",a),a}})}(t),At(t),function(t){const{constructor:e,template:{$container:r,$player:a}}=t;let o="";W(t,"fullscreenWeb",{get:()=>v(a,"art-fullscreen-web"),set(n){n?(o=a.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&y(document.body,a),t.state="fullscreenWeb",w(a,"width","100%"),w(a,"height","100%"),f(a,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&y(r,a),o&&(a.style.cssText=o,o=""),g(a,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),Rt(t),function(t){const{$video:e}=t.template;W(t,"loaded",{get:()=>t.loadedTime/e.duration}),W(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){W(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;W(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:a}=t.template;W(t,"autoSize",{value(){const{videoWidth:o,videoHeight:n}=a,{width:i,height:s}=A(e),l=o/n;if(i/s>l)w(r,"width",s*l/i*100+"%"),w(r,"height","100%");else{const t=i/l/s*100;w(r,"width","100%"),w(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){W(t,"rect",{get:()=>A(t.template.$player)});const e=["bottom","height","left","right","top","width"];for(let r=0;rt.rect[a]})}W(t,"x",{get:()=>t.left+window.pageXOffset}),W(t,"y",{get:()=>t.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:a}=t;W(t,"flip",{get:()=>e.dataset.flip||"normal",set(o){o||(o="normal"),"normal"===o?delete e.dataset.flip:e.dataset.flip=o,a.show=`${r.get("Video Flip")}: ${r.get(F(o))}`,t.emit("flip",o)}})}(t),Pt(t),function(t){const{template:{$poster:e}}=t;W(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch{return""}},set(t){w(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;W(t,"autoHeight",{value(){const{clientWidth:a}=e,{videoHeight:o,videoWidth:n}=r,i=o*(a/n);w(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;W(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){W(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){W(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];W(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let a=0;aa.$track?.offset||0,set(o){const{cues:n}=t.subtitle;if(!a.$track||0===n.length)return;const i=D(o,-10,10);a.$track.offset=i;for(let e=0;e{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,W(t,"airplay",{value(){n?(o.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){W(t,"quality",{set(e){const{controls:r,notice:a,i18n:o}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:n?.html||"",selector:e,onSelect:async e=>(await t.switchQuality(e.url),a.show=`${o.get("Switch Video")}: ${e.html}`,e.html)})}})}(t),Ot(t),function(t){const{i18n:e,notice:r,option:a,constructor:o,proxy:n,template:{$player:s,$video:l,$poster:c}}=t;let d=0;for(let p=0;p{t.emit(`video:${e.type}`,e)});t.on("video:canplay",()=>{d=0,t.loading.show=!1}),t.once("video:canplay",()=>{t.loading.show=!1,t.controls.show=!0,t.mask.show=!0,t.isReady=!0,t.emit("ready")}),t.on("video:ended",()=>{a.loop?(t.seek=0,t.play(),t.controls.show=!1,t.mask.show=!1):(t.controls.show=!0,t.mask.show=!0)}),t.on("video:error",async n=>{d{t.emit("resize"),p&&(t.loading.show=!1,t.controls.show=!0,t.mask.show=!0)}),t.on("video:loadstart",()=>{t.loading.show=!0,t.mask.show=!1,t.controls.show=!0}),t.on("video:pause",()=>{t.controls.show=!0,t.mask.show=!0}),t.on("video:play",()=>{t.mask.show=!1,w(c,"display","none")}),t.on("video:playing",()=>{t.mask.show=!1}),t.on("video:progress",()=>{t.playing&&(t.loading.show=!1)}),t.on("video:seeked",()=>{t.loading.show=!1,t.mask.show=!0}),t.on("video:seeking",()=>{t.loading.show=!0,t.mask.show=!1}),t.on("video:timeupdate",()=>{t.mask.show=!1}),t.on("video:waiting",()=>{t.loading.show=!0,t.mask.show=!1})}(t),function(t){const{option:e,storage:r,template:{$video:a,$poster:o}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(a.volume=D(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(a.volume=D(n,0,1)),e.poster&&w(o,"backgroundImage",`url(${e.poster})`),e.autoplay&&(a.autoplay=e.autoplay),e.playsInline&&(a.playsInline=!0,a["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Vt(t){const{notice:e,constructor:r,template:{$player:a,$video:o}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=o,r=document.documentElement.clientWidth,a=document.documentElement.clientHeight;return t>e&&ra}return t.on("fullscreenWeb",e=>{if(e){if(l()){const e=Number(r.AUTO_ORIENTATION_TIME??0);setTimeout(()=>{t.fullscreenWeb&&!v(a,n)&&function(){const e=O(),r=document.documentElement.clientWidth,o=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;w(a,"width",`${o}px`),w(a,"height",`${i}px`),w(a,"transform-origin","0 0"),w(a,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),f(a,n),t.isRotate=!0,t.emit("resize")}()},e)}}else v(a,n)&&(w(a,"width",""),w(a,"height",""),w(a,"transform-origin",""),w(a,"transform",""),g(a,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",async t=>{const r=!!screen?.orientation?.lock;if(t){if(r&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";await screen.orientation.lock(t),s=!0,f(a,i)}catch(o){s=!1,e.show=o}}else if(v(a,i)&&g(a,i),r&&s){try{screen.orientation.unlock()}catch{}s=!1}}),{name:"autoOrientation",get state(){return v(a,n)}}}function Yt(t){const{i18n:e,icons:r,storage:a,constructor:o,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=u(".art-auto-playback-last",s),c=u(".art-auto-playback-jump",s),d=u(".art-auto-playback-close",s);y(d,r.close);let p=null;function h(){const r=(a.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),w(s,"display","none"),r&&r>=o.AUTO_PLAYBACK_MIN&&(w(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${B(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{w(s,"display","none")}),n(c,"click",()=>{t.seek=r,t.play(),w(i,"display","none"),w(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{w(s,"display","none")},o.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=a.get("times")||{},r=Object.keys(e);r.length>o.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,a.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return a.get("times")||{}},clear:()=>a.del("times"),delete(t){const e=a.get("times")||{};return delete e[t],a.set("times",e),e}}}function Nt(t){const{constructor:e,proxy:r,template:{$player:a,$video:o}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,g(a,"art-fast-forward"))};return r(o,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,f(a,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return v(a,"art-fast-forward")}}}function Dt(t){const{layers:e,icons:r,template:{$player:a}}=t;function o(){return v(a,"art-lock")}function n(){f(a,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){g(a,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const a=y(e,r.lock),o=y(e,r.unlock);w(a,"display","none"),t.on("lock",t=>{t?(w(a,"display","inline-flex"),w(o,"display","none")):(w(a,"display","none"),w(o,"display","inline-flex"))})},click(){o()?i():n()}}),{name:"lock",get state(){return o()},set state(t){t?n():i()}}}function Ft(t){return t.on("control",e=>{e?g(t.template.$player,"art-mini-progress-bar"):f(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Bt{constructor(t){this.art=t,this.id=0;const{option:e}=t;e.miniProgressBar&&!e.isLive&&this.add(Ft),e.lock&&p&&this.add(Dt),e.autoPlayback&&!e.isLive&&this.add(Yt),e.autoOrientation&&p&&this.add(Vt),e.fastForward&&p&&!e.isLive&&this.add(Nt);for(let r=0;rthis.next(t,e)):this.next(t,e)}next(t,e){const r=e&&e.name||t.name||`plugin${this.id}`;return V(!U(this,r),`Cannot add a plugin that already has the same name: ${r}`),W(this,r,{value:e}),this}}class Ht extends pt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:a}}=t;this.name="setting",this.$parent=a,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=C(t,r.setting),a=C(t,this.$parent);!this.show||e||a||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,PLAYBACK_RATE:o}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:a,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:o.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,ASPECT_RATIO:o}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:a,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:o.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,FLIP:o}}=t;function n(t){return e.get(F(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:a,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:o.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:a}=t;return{width:a.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){for(let r=0;r{e.default=e===t,e.default&&e.$item&&$(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,a=[]){for(let o=0;oe}),W(n,"$parents",{get:()=>r}),W(n,"$option",{get:()=>t});const a=[];W(n,"$events",{get:()=>a}),W(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,a)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){const{controls:t,constructor:{SETTING_WIDTH:e,SETTING_ITEM_HEIGHT:r},template:{$player:a,$setting:o}}=this.art;if(t.setting&&this.show){const n=this.active[0]?.$parent?.width||e,{left:i,width:s}=A(t.setting),{left:l,width:c}=A(a),d=i-l+s/2-n/2;if(w(o,"height",`${this.active===this.option?this.active.length*r:(this.active.length+1)*r}px`),w(o,"width",`${n}px`),this.art.isRotate||p)return;d+n>c?(w(o,"left",null),w(o,"right",null)):(w(o,"left",`${d}px`),w(o,"right","auto"))}}inactivate(t){for(let e=0;e'),s=L("div");f(s,"art-setting-item-left-icon"),y(s,a),y(i,s),y(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),y(e,n)}createItem(t,e=!1){if(!this.cache.has(t.$option))return;const r=this.cache.get(t.$option),a=t.$item;let o="selector";U(t,"switch")&&(o="switch"),U(t,"range")&&(o="range"),U(t,"onClick")&&(o="button");const{icons:n,proxy:i,constructor:s}=this.art,l=L("div");f(l,"art-setting-item"),w(l,"height",`${s.SETTING_ITEM_HEIGHT}px`),l.dataset.name=t.name||"",l.dataset.value=t.value||"";const c=y(l,'
'),d=y(l,'
'),p=L("div");switch(f(p,"art-setting-item-left-icon"),o){case"button":case"switch":case"range":y(p,t.icon||n.config);break;case"selector":t.selector?.length?y(p,t.icon||n.config):y(p,n.check)}y(c,p),W(t,"$icon",{configurable:!0,get:()=>p}),W(t,"icon",{configurable:!0,get:()=>p.innerHTML,set(t){p.innerHTML="",y(p,t)}});const h=L("div");f(h,"art-setting-item-left-text"),y(h,t.html||""),y(c,h),W(t,"$html",{configurable:!0,get:()=>h}),W(t,"html",{configurable:!0,get:()=>h.innerHTML,set(t){h.innerHTML="",y(h,t)}});const u=L("div");switch(f(u,"art-setting-item-right-tooltip"),y(u,t.tooltip||""),y(d,u),W(t,"$tooltip",{configurable:!0,get:()=>u}),W(t,"tooltip",{configurable:!0,get:()=>u.innerHTML,set(t){u.innerHTML="",y(u,t)}}),o){case"switch":{const e=L("div");f(e,"art-setting-item-right-icon");const r=y(e,n.switchOn),a=y(e,n.switchOff);w(t.switch?a:r,"display","none"),y(d,e),W(t,"$switch",{configurable:!0,get:()=>e});let o=t.switch;W(t,"switch",{configurable:!0,get:()=>o,set(t){o=t,t?(w(a,"display","none"),w(r,"display",null)):(w(a,"display",null),w(r,"display","none"))}});break}case"range":{const e=L("div");f(e,"art-setting-item-right-icon");const r=y(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],f(r,"art-setting-range"),y(d,e),W(t,"$range",{configurable:!0,get:()=>r});let a=[...t.range];W(t,"range",{configurable:!0,get:()=>a,set(t){a=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(t.selector?.length){const t=L("div");f(t,"art-setting-item-right-icon"),y(t,n.arrowRight),y(d,t)}}switch(o){case"switch":if(t.onSwitch){const e=i(l,"click",async e=>{t.switch=await t.onSwitch.call(this.art,t,l,e)});t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=i(t.$range,"change",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onRange.call(this.art,t,l,e)});t.$events.push(e)}if(t.onChange){const e=i(t.$range,"input",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onChange.call(this.art,t,l,e)});t.$events.push(e)}}break;case"selector":{const e=i(l,"click",async e=>{t.selector?.length?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=await t.$parent.onSelect.call(this.art,t,l,e)))});t.$events.push(e),t.default&&f(l,"art-current")}break;case"button":if(t.onClick){const e=i(l,"click",async e=>{t.tooltip=await t.onClick.call(this.art,t,l,e)});t.$events.push(e)}}W(t,"$item",{configurable:!0,get:()=>l}),e?z(l,a):y(r,l),t.mounted&&setTimeout(()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){if(this.active=t,this.cache.has(t)){$(this.cache.get(t),"art-current")}else{const e=L("div");this.cache.set(t,e),f(e,"art-setting-panel"),y(this.$parent,e),$(e,"art-current"),t[0]?.$parent&&this.createHeader(t[0]);for(let r=0;rnull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){return this.art.template.$video?.textTracks?.[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?x(r,t):w(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?H(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(t,e={}){const{i18n:r,notice:a,option:o}=this.art,n={...o.subtitle,...e,url:t},i=await this.init(n);return e.name&&(a.show=`${r.get("Switch Subtitle")}: ${e.name}`),i}createTrack(t,e){const{template:r,proxy:a,option:o}=this.art,{$video:n,$track:i}=r,s=L("track");s.default=!0,s.kind=t,s.src=e,s.label=o.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,b(i),y(n,s),r.$track=s,this.destroyEvent=a(this.textTrack,"cuechange",()=>this.update())}async init(t){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(o(t,dt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||Y(t.url)){case"srt":{const e=G(r);return K(t.onVttLoad(e))}case"ass":{const e=Z(r);return K(t.onVttLoad(e))}case"vtt":return K(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null}}class qt{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=u(e.container),V(this.$container,`No container element found by ${e.container}`)),V(I(),"The current browser does not support flex layout");const a=this.$container.tagName.toLowerCase();V("div"===a,`Unsupported container element type, only support 'div' but got '${a}'`),V(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=t.id,this.init()}static get html(){return`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${n}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `}query(t){return u(t,this.$container)}init(){const{option:t}=this.art;if(t.useSSR||(this.$container.innerHTML=qt.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);V(e instanceof HTMLVideoElement||e instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),z(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&f(this.$player,"art-backdrop"),p&&f(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":f(this.$player,"art-destroy")}}class Xt{on(t,e,r){const a=this.e||(this.e={});return(a[t]||(a[t]=[])).push({fn:e,ctx:r}),this}once(t,e,r){const a=this;function o(...n){a.off(t,o),e.apply(r,n)}return o._=e,this.on(t,o,r)}emit(t,...e){const r=((this.e||(this.e={}))[t]||[]).slice();for(let a=0;ae.call(this,this)),Zt.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${Zt.version}`);for(let e=0;et(`Event@${e.type}`))}Kt.push(this)}static get instances(){return Kt}static get version(){return n}static get config(){return i}static get utils(){return et}static get scheme(){return dt}static get Emitter(){return Xt}static get validator(){return o}static get kindOf(){return o.kindOf}static get html(){return qt.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:l?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:navigator?.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){Zt.REMOVE_SRC_WHEN_DESTROY&&this.reset(),this.events.destroy(),this.template.destroy(t),Kt.splice(Kt.indexOf(this),1),this.isDestroy=!0,this.emit("destroy")}}return Zt.STYLE=jt,Zt.DEBUG=!1,Zt.CONTEXTMENU=!0,Zt.NOTICE_TIME=2e3,Zt.SETTING_WIDTH=250,Zt.SETTING_ITEM_WIDTH=200,Zt.SETTING_ITEM_HEIGHT=35,Zt.RESIZE_TIME=200,Zt.SCROLL_TIME=200,Zt.SCROLL_GAP=50,Zt.AUTO_PLAYBACK_MAX=10,Zt.AUTO_PLAYBACK_MIN=5,Zt.AUTO_PLAYBACK_TIMEOUT=3e3,Zt.RECONNECT_TIME_MAX=5,Zt.RECONNECT_SLEEP_TIME=1e3,Zt.CONTROL_HIDE_TIME=3e3,Zt.DBCLICK_TIME=300,Zt.DBCLICK_FULLSCREEN=!0,Zt.MOBILE_DBCLICK_PLAY=!0,Zt.MOBILE_CLICK_PLAY=!1,Zt.AUTO_ORIENTATION_TIME=200,Zt.INFO_LOOP_TIME=1e3,Zt.FAST_FORWARD_VALUE=3,Zt.FAST_FORWARD_TIME=1e3,Zt.TOUCH_MOVE_RATIO=.5,Zt.VOLUME_STEP=.1,Zt.SEEK_STEP=5,Zt.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],Zt.ASPECT_RATIO=["default","4:3","16:9"],Zt.FLIP=["normal","horizontal","vertical"],Zt.FULLSCREEN_WEB_IN_BODY=!0,Zt.LOG_VERSION=!0,Zt.USE_RAF=!1,Zt.REMOVE_SRC_WHEN_DESTROY=!0,h&&(M("artplayer-style",jt),setTimeout(()=>{Zt.LOG_VERSION&&console.log(`%c ArtPlayer %c ${Zt.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),Zt}); +!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";function t(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var e,r={exports:{}};var a=(e||(e=1,r.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var o=t(r);if("boolean"===o)return"boolean";if("string"===o)return"string";if("number"===o)return"number";if("symbol"===o)return"symbol";if("function"===o)return"GeneratorFunction"===a(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(a(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(o=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return o.slice(8,-1).toLowerCase().replace(/\s/g,"")};function a(t){return t.constructor?t.constructor.name:null}function o(t,e){var a=2=1,p=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(s)||d,h="undefined"!==typeof window&&"undefined"!==typeof document;function u(t,e=document){return e.querySelector(t)}function m(t,e=document){return Array.from(e.querySelectorAll(t))}function f(t,e){return t.classList.add(e)}function g(t,e){return t.classList.remove(e)}function v(t,e){return t.classList.contains(e)}function y(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function b(t){return t.parentNode.removeChild(t)}function w(t,e,r){return t.style[e]=r,t}function x(t,e){for(const r in e)w(t,r,e[r]);return t}function k(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function $(t,e){k(t).forEach(t=>g(t,e)),f(t,e)}function T(t,e,r="top"){p||(t.setAttribute("aria-label",e),f(t,"hint--rounded"),f(t,`hint--${r}`))}function E(t,e=0){const r=t.getBoundingClientRect(),a=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=a&&r.top+r.height+e>=0,i=r.left-e<=o+e&&r.left+r.width+e>=0;return n&&i}function C(t,e){return R(t).includes(e)}function z(t,e){return e.parentNode.replaceChild(t,e),t}function L(t){return document.createElement(t)}function S(t="",e=""){const r=L("i");return f(r,"art-icon"),f(r,`art-icon-${t}`),y(r,e),r}function M(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function I(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function A(t){return t.getBoundingClientRect()}function P(t,e){return new Promise((r,a)=>{const o=new Image;o.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=o.width*e,n.height=o.height*e,i.drawImage(o,0,0,n.width,n.height),n.toBlob(e=>{const o=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(o),a(new Error(`Image load failed: ${t}`))},n.src=o})}else r(o)},o.onerror=function(){a(new Error(`Image load failed: ${t}`))},o.src=t})}function R(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function O(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class _ extends Error{constructor(t,e){super(t),"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function V(t,e){if(!t)throw new _(e);return t}function Y(t){return t.includes("?")?Y(t.split("?")[0]):t.includes("#")?Y(t.split("#")[0]):t.trim().toLowerCase().split(".").pop()}function N(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r)}function D(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function F(t){return t.charAt(0).toUpperCase()+t.slice(1)}function B(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),a=Math.floor(t-3600*e-60*r);return(e>0?[e,r,a]:[r,a]).map(t=>t<10?`0${t}`:String(t)).join(":")}function H(t){return t.replace(/[&<>'"]/g,t=>({"&":"&","<":"<",">":">","'":"'",'"':"""}[t]||t))}const W=Object.defineProperty,{hasOwnProperty:j}=Object.prototype;function U(t,e){return j.call(t,e)}function q(t,e){return Object.getOwnPropertyDescriptor(t,e)}function X(...t){const e=t=>t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(a=>{const o=t[a],n=r[a];Array.isArray(o)&&Array.isArray(n)?t[a]=o.concat(...n):e(o)&&e(n)?t[a]=X(o,n):t[a]=n}),t),{})}function G(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let a=r.slice(0,3);return 1===r.length&&(a=`${r}00`),2===r.length&&(a=`${r}0`),`${e},${a}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function K(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function Z(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const a=t.match(e);return a?{start:r(a[1].trim()),end:r(a[2].trim()),text:a[5].replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}:null}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function J(t=0){return new Promise(e=>setTimeout(e,t))}function Q(t,e){let r;return function(...a){clearTimeout(r),r=setTimeout(()=>(r=null,t.apply(this,a)),e)}}function tt(t,e){let r=!1;return function(...a){r||(t.apply(this,a),r=!0,setTimeout(()=>{r=!1},e))}}const et=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:_,addClass:f,append:y,assToVtt:Z,capitalize:F,clamp:D,createElement:L,debounce:Q,def:W,download:N,errorHandle:V,escape:H,get:q,getComposedPath:R,getExt:Y,getIcon:S,getRect:A,getSafeAreaInsets:O,getStyle:function(t,e,r=!0){const a=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(a):a},has:U,hasClass:v,includeFromEvent:C,inverseClass:$,isBrowser:h,isIOS:c,isIOS13:d,isInViewport:E,isMobile:p,isSafari:l,loadImg:P,mergeDeep:X,query:u,queryAll:m,remove:b,removeClass:g,replaceElement:z,secondToTime:B,setStyle:w,setStyleText:M,setStyles:x,siblings:k,sleep:J,srtToVtt:G,supportsFlex:I,throttle:tt,tooltip:T,unescape:function(t){const e={"&":"&","<":"<",">":">","'":"'",""":'"'},r=new RegExp(`(${Object.keys(e).join("|")})`,"g");return t.replace(r,t=>e[t]||t)},userAgent:s,vttToBlob:K},Symbol.toStringTag,{value:"Module"})),rt="array",at="boolean",ot="string",nt="number",it="object",st="function";function lt(t,e,r){return V(e===ot||e===nt||t instanceof Element,`${r.join(".")} require '${ot}' or 'Element' type`)}const ct={html:lt,disable:`?${at}`,name:`?${ot}`,index:`?${nt}`,style:`?${it}`,click:`?${st}`,mounted:`?${st}`,tooltip:`?${ot}|${nt}`,width:`?${nt}`,selector:`?${rt}`,onSelect:`?${st}`,switch:`?${at}`,onSwitch:`?${st}`,range:`?${rt}`,onRange:`?${st}`,onChange:`?${st}`},dt={id:ot,container:lt,url:ot,poster:ot,type:ot,theme:ot,lang:ot,volume:nt,isLive:at,muted:at,autoplay:at,autoSize:at,autoMini:at,loop:at,flip:at,playbackRate:at,aspectRatio:at,screenshot:at,setting:at,hotkey:at,pip:at,mutex:at,backdrop:at,fullscreen:at,fullscreenWeb:at,subtitleOffset:at,miniProgressBar:at,useSSR:at,playsInline:at,lock:at,gesture:at,fastForward:at,autoPlayback:at,autoOrientation:at,airplay:at,proxy:`?${st}`,plugins:[st],layers:[ct],contextmenu:[ct],settings:[ct],controls:[{...ct,position:(t,e,r)=>{const a=["top","left","right"];return V(a.includes(t),`${r.join(".")} only accept ${a.toString()} as parameters`)}}],quality:[{default:`?${at}`,html:ot,url:ot}],highlight:[{time:nt,text:ot}],thumbnails:{url:ot,number:nt,column:nt,width:nt,height:nt,scale:nt},subtitle:{url:ot,name:ot,type:ot,style:it,escape:at,encoding:ot,onVttLoad:st},moreVideoAttr:it,i18n:it,icons:it,cssVar:it,customType:it};class pt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return v(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?f(e,r):g(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",o(e,ct),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;V(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const a=L("div");f(a,`art-${this.name}`),f(a,`art-${this.name}-${r}`);const n=Array.from(this.$parent.children);a.dataset.index=e.index||this.id;const i=n.find(t=>Number(t.dataset.index)>=Number(a.dataset.index));i?i.insertAdjacentElement("beforebegin",a):y(this.$parent,a),e.html&&y(a,e.html),e.style&&x(a,e.style),e.tooltip&&T(a,e.tooltip);const s=[];if(e.click){const t=this.art.events.proxy(a,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});s.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,a,s),this[r]=a,this.cache.set(r,{$ref:a,events:s,option:e}),e.mounted&&e.mounted.call(this.art,a),a}remove(t){V(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],b(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class ht extends pt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,p||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:a}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:a}}=e,o=a.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return{...t,html:`${r.get("Play Speed")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.playbackRate=Number(a),t.show=!1)},mounted:t=>{const r=u('[data-value="1"]',t);r&&$(r,"art-current"),e.on("video:ratechange",()=>{const r=m("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&$(r,"art-current")})}}}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:a}}=e,o=a.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return{...t,html:`${r.get("Aspect Ratio")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.aspectRatio=a,t.show=!1)},mounted:t=>{const r=u('[data-value="default"]',t);r&&$(r,"art-current"),e.on("aspectRatio",e=>{const r=m("span",t).find(t=>t.dataset.value===e);r&&$(r,"art-current")})}}}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:a}}=e,o=a.map(t=>`${r.get(F(t))}`).join("");return{...t,html:`${r.get("Video Flip")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.flip=a.toLowerCase(),t.show=!1)},mounted:t=>{const r=u('[data-value="normal"]',t);r&&$(r,"art-current"),e.on("flip",e=>{const r=m("span",t).find(t=>t.dataset.value===e);r&&$(r,"art-current")})}}}}({name:"flip",index:30})),this.add(function(t){return e=>({...t,html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){const e=h?location.href:"";return{...t,html:`ArtPlayer ${n}`}}({name:"version",index:50})),this.add(function(t){return e=>({...t,html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let o=0;o{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,o=t.clientY,{height:n,width:i,left:s,top:l}=A(r),{height:c,width:d}=A(a);let p=e-s,h=o-l;e+d>s+i&&(p=i-d),o+c>l+n&&(h=n-c),x(a,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{C(t,a)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}function ut(t,e){const{$progress:r}=t.template,{left:a}=A(r),o=D((p?e.touches[0].clientX:e.clientX)-a,0,r.clientWidth),n=o/r.clientWidth*t.duration;return{second:n,time:B(n),width:o,percentage:D(o/r.clientWidth,0,1)}}function mt(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,a=r*t.duration;t.emit("setBar","played",r,e),t.seek=a}else{const{second:r,percentage:a}=ut(t,e);t.emit("setBar","played",a,e),t.seek=r}}function ft(t){return e=>{const{icons:r,option:a,proxy:o}=e,{$player:n,$progress:i}=e.template;return{...t,html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=u(".art-progress-hover",t),d=u(".art-progress-loaded",t),h=u(".art-progress-played",t),m=u(".art-progress-highlight",t),v=u(".art-progress-indicator",t),b=u(".art-progress-tip",t);function x(r,a){const{width:o,time:n}=a||ut(e,r);b.textContent=n||"00:00";const i=b.clientWidth;o<=i/2?w(b,"left",0):o>t.clientWidth-i/2?w(b,"left",t.clientWidth-i+"px"):w(b,"left",o-i/2+"px")}r.indicator?y(v,r.indicator):w(v,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,a,o){const i="played"===r&&o&&p;if("loaded"===r&&w(d,"width",100*a+"%"),"hover"===r&&(w(c,"width",100*a+"%"),C(o,m)?function(r){const{width:a}=ut(e,r),{text:o}=r.target.dataset;b.textContent=o;const n=b.clientWidth;a<=n/2?w(b,"left",0):a>t.clientWidth-n/2?w(b,"left",t.clientWidth-n+"px"):w(b,"left",a-n/2+"px")}(o):x(o),0===a?g(n,"art-progress-hover"):f(n,"art-progress-hover")),"played"===r&&(w(h,"width",100*a+"%"),w(v,"left",100*a+"%")),i){f(n,"art-progress-hover");x(o,{width:t.clientWidth*a,time:B(a*e.duration)}),clearTimeout(s),s=setTimeout(()=>{g(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){m.textContent="";for(let t=0;t`;y(m,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),p||(o(i,"click",t=>{t.target!==v&&mt(e,t)}),o(i,"mousemove",t=>{const{percentage:r}=ut(e,t);e.emit("setBar","hover",r,t)}),o(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),o(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:a}=ut(e,t);e.emit("setBar","played",a,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}}}}class gt extends pt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:a}=this.art.template;t.on("mousemove",()=>{p||(this.show=!0)}),t.on("click",()=>{p?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=C(t,a)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(g(r,"art-hide-cursor"),f(r,"art-hover"),this.timer=Date.now()):(f(r,"art-hide-cursor"),g(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(ft({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.play),i=y(t,a.pause);function s(){w(n,"display","flex"),w(i,"display","none")}function l(){w(n,"display","none"),w(i,"display","flex")}T(n,o.get("Play")),T(i,o.get("Pause")),r(n,"click",()=>{e.play()}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:a}=e,o=y(t,a.volume),n=y(t,a.volumeClose),i=y(t,'
'),s=y(i,'
'),l=y(s,'
'),c=y(s,'
'),d=y(c,'
'),h=y(d,'
'),u=y(c,'
');function m(t){const{top:e,height:r}=A(c);return 1-(t.clientY-e)/r}function f(){if(e.muted||0===e.volume)w(o,"display","none"),w(n,"display","flex"),w(u,"top","100%"),w(h,"top","100%"),l.textContent=0;else{const t=100*e.volume;w(o,"display","flex"),w(n,"display","none"),w(u,"top",100-t+"%"),w(h,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(f(),e.on("video:volumechange",f),r(o,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),p)w(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=m(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=m(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>({...t,style:p?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${B(e.currentTime)} / ${B(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const a=["video:loadedmetadata","video:timeupdate","video:progress"];for(let o=0;o{this.art.quality=t.quality}),t.screenshot&&!p&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:a}=e;y(t,a.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e;y(t,a.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{T(t,o.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e;y(t,a.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{T(t,o.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:a}=e;y(t,a.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.fullscreenWebOn),i=y(t,a.fullscreenWebOff);w(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(T(t,o.get("Exit Web Fullscreen")),w(n,"display","none"),w(i,"display","inline-flex")):(T(t,o.get("Web Fullscreen")),w(n,"display","inline-flex"),w(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.fullscreenOn),i=y(t,a.fullscreenOff);w(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(T(t,o.get("Exit Fullscreen")),w(n,"display","none"),w(i,"display","inline-flex")):(T(t,o.get("Fullscreen")),w(n,"display","inline-flex"),w(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),W(e,"$control_item",{get:()=>r}),W(e,"$control_value",{get:()=>o})}const i=a(n,"click",async e=>{const r=R(e),a=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(a),t.onSelect&&(o.innerHTML=await t.onSelect.call(this.art,a,a.$control_item,e))});r.push(i)}}function vt(t,e,r,a){const o=e-a,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(o)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,o);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}class yt{constructor(t){this.destroyEvents=new Set,this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:a,$video:o}}=t;function n(e){C(e,a)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(o,"click",e=>{const a=Date.now();i.push(a);const{MOBILE_CLICK_PLAY:o,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>a-t<=n);switch(c.length){case 1:t.emit("click",e),p?!t.isLock&&o&&t.toggle():t.toggle(),i=c;break;case 2:t.emit("dblclick",e),p?!t.isLock&&s&&t.toggle():l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{f(r,"art-hover"),t.emit("hover",!0,e)},e=>{g(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:a}=t;t.on("resize",()=>{const{aspectRatio:e,notice:a}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,a.show=""});const o=Q(()=>t.emit("resize"),a.RESIZE_TIME);t.on("window:orientationchange",()=>o()),t.on("window:resize",()=>o()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>o())}(t,this),function(t,e){if(p&&!t.option.isLive){const{$video:r,$progress:a}=t.template;let o=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){o===a&&mt(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:a,pageY:n}=e.touches[0],c=vt(i,s,a,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=D((a-i)/t.width,-1,1),d=D((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=o===r?t.constructor.TOUCH_MOVE_RATIO:1,u=D(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",D(u/t.duration,0,1),e),t.notice.show=`${B(u)} / ${B(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,o=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{o=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(a,"touchstart",t=>{o=a,c(t)}),e.proxy(a,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:a}}=t,o=tt(()=>{t.emit("view",E(a,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>o()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],a=["resize","scroll","orientationchange"],o=[];function n(n={}){for(let t=0;t{const a=n.document||i.ownerDocument||document,s=e.proxy(a,r,e=>{t.emit(`document:${r}`,e)});o.push(s)}),a.forEach(r=>{const a=n.window||i.ownerDocument?.defaultView||window,s=e.proxy(a,r,e=>{t.emit(`window:${r}`,e)});o.push(s)})}n(),e.bindGlobalEvents=n}(t,this),function(t){if(t.constructor.USE_RAF){let e=null;!function r(){t.playing&&t.emit("raf"),t.isDestroy||(e=requestAnimationFrame(r))}(),t.on("destroy",()=>{cancelAnimationFrame(e)})}}(t)}proxy(t,e,r,a={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,a));t.addEventListener(e,r,a);const o=()=>t.removeEventListener(e,r,a);return this.destroyEvents.add(o),o}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class bt{constructor(t){this.art=t,this.keys={},p||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{this.art.toggle()}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',state:'\n\n\n',play:'\n \n',pause:'\n \n',check:'\n\n',volume:'\n \n \n',volumeClose:'\n \n \n',screenshot:'\n\t\n\n',setting:'\n \n \n',pip:'\n\n',arrowLeft:'\n \n',arrowRight:'\n \n',playbackRate:'',aspectRatio:'',config:'',lock:'\n\n\n\n\n',flip:'\n\n\n\n\n\n',unlock:'\n\n\n',fullscreenOff:'\n\n\n\n\n',fullscreenOn:'\n\n\n\n\n',fullscreenWebOff:'\n\n\n\n\n',fullscreenWebOn:'\n\n\n\n\n',switchOn:'\n\n\n \n',switchOff:'\n\n\n \n\n',error:'\n\n\n\n\n',close:'\n\n\n\n\n',airplay:'\n \n \n \n \n\n',...t.option.icons};for(const r in e)W(this,r,{get:()=>S(r,e[r])})}}class $t extends pt{constructor(t){super(t),this.name="info",p||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:a,$video:o}}=this.art;t(a,"click",()=>{this.show=!1});let n=null;const i=m("[data-video]",r)||[];this.art.on("destroy",()=>clearTimeout(n)),function t(){for(let e=0;e{w(o,"display","none"),w(n,"display",null)}),a.proxy(e.$state,"click",()=>t.play())}}class zt{constructor(t){this.art=t,this.timer=null,t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){const{constructor:e,template:{$player:r,$noticeInner:a}}=this.art;t?(a.textContent=t instanceof Error?t.message.trim():t,f(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{a.textContent="",g(r,"art-notice-show")},e.NOTICE_TIME)):g(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}const Lt=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],St=(()=>{if("undefined"===typeof document)return!1;const t=Lt[0],e={};for(const r of Lt){if(r[1]in document){for(const[a,o]of r.entries())e[t[a]]=o;return e}}return!1})(),Mt={change:St.fullscreenchange,error:St.fullscreenerror},It={request:(t=document.documentElement,e)=>new Promise((r,a)=>{const o=()=>{It.off("change",o),r()};It.on("change",o);const n=t[St.requestFullscreen](e);n instanceof Promise&&n.then(o).catch(a)}),exit:()=>new Promise((t,e)=>{if(!It.isFullscreen)return void t();const r=()=>{It.off("change",r),t()};It.on("change",r);const a=document[St.exitFullscreen]();a instanceof Promise&&a.then(r).catch(e)}),toggle:(t,e)=>It.isFullscreen?It.exit():It.request(t,e),onchange(t){It.on("change",t)},onerror(t){It.on("error",t)},on(t,e){const r=Mt[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Mt[t];r&&document.removeEventListener(r,e,!1)},raw:St};function At(t){const{i18n:e,notice:r,template:{$video:a,$player:o}}=t;t.once("video:loadedmetadata",()=>{var n;It.isEnabled?(n=t,It.on("change",()=>{n.emit("fullscreen",It.isFullscreen),It.isFullscreen?(n.state="fullscreen",f(o,"art-fullscreen")):g(o,"art-fullscreen"),n.emit("resize")}),It.on("error",t=>{n.emit("fullscreenError",t)}),W(n,"fullscreen",{get:()=>It.isFullscreen,async set(t){t?await It.request(o):await It.exit()}})):a.webkitSupportsFullscreen?(t=>{t.on("document:webkitfullscreenchange",()=>{t.emit("fullscreen",t.fullscreen),t.emit("resize")}),W(t,"fullscreen",{get:()=>document.fullscreenElement===a,set(e){e?(t.state="fullscreen",a.webkitEnterFullscreen()):a.webkitExitFullscreen()}})})(t):W(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),W(t,"fullscreen",q(t,"fullscreen"))})}function Pt(t){const{icons:e,proxy:r,storage:a,template:{$player:o,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(g(o,"art-mini"),w(e,"display","none"),o.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(w(e,"display","none"),w(r,"display","flex")):(w(e,"display","flex"),w(r,"display","none"))}function p(){const{$mini:e}=t.template,r=A(e),o=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;a.set("top",o),a.set("left",n),w(e,"top",`${o}px`),w(e,"left",`${n}px`)}W(t,"mini",{get:()=>v(o,"art-mini"),set(h){if(h){t.state="mini",f(o,"art-mini");const h=function(){const{$mini:o}=t.template;if(o)return y(o,n),w(o,"display","flex");{const o=L("div");f(o,"art-mini-popup"),y(document.body,o),t.template.$mini=o,y(o,n);const p=y(o,'
');y(p,e.close),r(p,"click",c);const h=y(o,'
'),u=y(h,e.play),m=y(h,e.pause);return r(u,"click",()=>t.play()),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(o,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){f(o,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;w(o,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,g(o,"art-mini-dragging");const t=A(o);a.set("left",t.left),a.set("top",t.top),w(o,"left",`${t.left}px`),w(o,"top",`${t.top}px`),w(o,"transform",null)}}),o}}(),u=a.get("top"),m=a.get("left");"number"===typeof u&&"number"===typeof m?(w(h,"top",`${u}px`),w(h,"left",`${m}px`),E(h)||p()):p(),t.emit("mini",!0)}else c()}})}function Rt(t){const{i18n:e,notice:r,template:{$video:a}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:a}=t;e.disablePictureInPicture=!1,W(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw a.show=t,t})):document.exitPictureInPicture().catch(t=>{throw a.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):a.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),W(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):W(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ot(t){const{option:e,template:{$progress:r,$video:a}}=t;let o=null,n=!1,i=null;t.on("setBar",async(o,s,l)=>{const c=t.controls?.thumbnails,{url:d,scale:h}=e.thumbnails;if(!c||!d)return;if("hover"===o||"played"===o&&l&&p){if(i||n||(n=!0,i=await P(d,h),n=!1),!i)return;const o=r.clientWidth*s;o>0&&or.clientWidth-h/2?w(n,"left",r.clientWidth-h+"px"):w(n,"left",o-h/2+"px")}(o)}}),W(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(o),o=null,n=!1,i=null)}})}Object.defineProperties(It,{isFullscreen:{get:()=>Boolean(document[St.fullscreenElement])},element:{enumerable:!0,get:()=>document[St.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[St.fullscreenEnabled])}});class _t{constructor(t){!function(t){const{option:e,template:{$video:r}}=t;W(t,"url",{get:()=>r.src,async set(a){if(a){const o=t.url,n=e.type||Y(a),i=e.customType[n];n&&i?(await J(),t.loading.show=!0,i.call(t,r,a,t)):(URL.revokeObjectURL(o),r.src=a),o!==t.url&&(t.option.url=a,t.isReady&&o&&t.once("video:canplay",()=>{t.emit("restart",a)}))}else await J(),t.loading.show=!0}})}(t),function(t){const{template:{$video:e}}=t;W(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:a,constructor:{instances:o},template:{$video:n}}=t;W(t,"play",{async value(){const i=await n.play();if(r.show=e.get("Play"),t.emit("play"),a.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;W(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${B(t.currentTime)} / ${B(t.duration)}`),t.emit("seek",t.currentTime,r)}}),W(t,"forward",{set(e){t.seek=t.currentTime+e}}),W(t,"backward",{set(e){t.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:a,storage:o}=t;W(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=D(t,0,1),a.show=`${r.get("Volume")}: ${Number.parseInt(100*e.volume,10)}`,0!==e.volume&&o.set("volume",e.volume)}}),W(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;W(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{r=Number.parseFloat(r),Number.isNaN(r)||(e.currentTime=D(r,0,t.duration))}})}(t),function(t){W(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){function e(e,r){return new Promise((a,o)=>{if(e===t.url)return void a();const{playing:n,aspectRatio:i,playbackRate:s}=t;t.pause(),t.url=e,t.notice.show="";const l={error:e=>{t.off("video:canplay",l.canplay),t.off("video:loadedmetadata",l.metadata),o(e)},metadata:()=>{t.currentTime=r},canplay:async()=>{t.off("video:error",l.error),t.playbackRate=s,t.aspectRatio=i,n&&await t.play(),t.notice.show="",a()}};t.once("video:error",l.error),t.once("video:loadedmetadata",l.metadata),t.once("video:canplay",l.canplay)})}W(t,"switchQuality",{value:r=>e(r,t.currentTime)}),W(t,"switchUrl",{value:t=>e(t,0)}),W(t,"switch",{set:t.switchUrl})}(t),function(t){const{template:{$video:e},i18n:r,notice:a}=t;W(t,"playbackRate",{get:()=>e.playbackRate,set(o){if(o){if(o===e.playbackRate)return;e.playbackRate=o,a.show=`${r.get("Rate")}: ${1===o?r.get("Normal"):`${o}x`}`}else t.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:a,$player:o}}=t;W(t,"aspectRatio",{get:()=>o.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)w(a,"width",null),w(a,"height",null),w(a,"margin",null),delete o.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=o,i=e/r,s=t[0]/t[1];i>s?(w(a,"width",s*r+"px"),w(a,"height","100%"),w(a,"margin","0 auto")):(w(a,"width","100%"),w(a,"height",e/s+"px"),w(a,"margin","auto 0")),o.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,a=L("canvas");W(t,"getDataURL",{value:()=>new Promise((t,o)=>{try{a.width=r.videoWidth,a.height=r.videoHeight,a.getContext("2d").drawImage(r,0,0),t(a.toDataURL("image/png"))}catch(n){e.show=n,o(n)}})}),W(t,"getBlobUrl",{value:()=>new Promise((t,o)=>{try{a.width=r.videoWidth,a.height=r.videoHeight,a.getContext("2d").drawImage(r,0,0),a.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,o(n)}})}),W(t,"screenshot",{value:async e=>{const a=await t.getDataURL();return N(a,`${e||`artplayer_${B(r.currentTime)}`}.png`),t.emit("screenshot",a),a}})}(t),At(t),function(t){const{constructor:e,template:{$container:r,$player:a}}=t;let o="";W(t,"fullscreenWeb",{get:()=>v(a,"art-fullscreen-web"),set(n){n?(o=a.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&y(document.body,a),t.state="fullscreenWeb",w(a,"width","100%"),w(a,"height","100%"),f(a,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&y(r,a),o&&(a.style.cssText=o,o=""),g(a,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),Rt(t),function(t){const{$video:e}=t.template;W(t,"loaded",{get:()=>t.loadedTime/e.duration}),W(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){W(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;W(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:a}=t.template;W(t,"autoSize",{value(){const{videoWidth:o,videoHeight:n}=a,{width:i,height:s}=A(e),l=o/n;if(i/s>l)w(r,"width",s*l/i*100+"%"),w(r,"height","100%");else{const t=i/l/s*100;w(r,"width","100%"),w(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){W(t,"rect",{get:()=>A(t.template.$player)});const e=["bottom","height","left","right","top","width"];for(let r=0;rt.rect[a]})}W(t,"x",{get:()=>t.left+window.pageXOffset}),W(t,"y",{get:()=>t.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:a}=t;W(t,"flip",{get:()=>e.dataset.flip||"normal",set(o){o||(o="normal"),"normal"===o?delete e.dataset.flip:e.dataset.flip=o,a.show=`${r.get("Video Flip")}: ${r.get(F(o))}`,t.emit("flip",o)}})}(t),Pt(t),function(t){const{template:{$poster:e}}=t;W(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch{return""}},set(t){w(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;W(t,"autoHeight",{value(){const{clientWidth:a}=e,{videoHeight:o,videoWidth:n}=r,i=o*(a/n);w(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;W(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){W(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){W(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];W(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let a=0;aa.$track?.offset||0,set(o){const{cues:n}=t.subtitle;if(!a.$track||0===n.length)return;const i=D(o,-10,10);a.$track.offset=i;for(let e=0;e{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,W(t,"airplay",{value(){n?(o.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){W(t,"quality",{set(e){const{controls:r,notice:a,i18n:o}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:n?.html||"",selector:e,onSelect:async e=>(await t.switchQuality(e.url),a.show=`${o.get("Switch Video")}: ${e.html}`,e.html)})}})}(t),Ot(t),function(t){const{i18n:e,notice:r,option:a,constructor:o,proxy:n,template:{$player:s,$video:l,$poster:c}}=t;let d=0;for(let p=0;p{t.emit(`video:${e.type}`,e)});t.on("video:canplay",()=>{d=0,t.loading.show=!1}),t.once("video:canplay",()=>{t.loading.show=!1,t.controls.show=!0,t.mask.show=!0,t.isReady=!0,t.emit("ready")}),t.on("video:ended",()=>{a.loop?(t.seek=0,t.play(),t.controls.show=!1,t.mask.show=!1):(t.controls.show=!0,t.mask.show=!0)}),t.on("video:error",async n=>{d{t.emit("resize"),p&&(t.loading.show=!1,t.controls.show=!0,t.mask.show=!0)}),t.on("video:loadstart",()=>{t.loading.show=!0,t.mask.show=!1,t.controls.show=!0}),t.on("video:pause",()=>{t.controls.show=!0,t.mask.show=!0}),t.on("video:play",()=>{t.mask.show=!1,w(c,"display","none")}),t.on("video:playing",()=>{t.mask.show=!1}),t.on("video:progress",()=>{t.playing&&(t.loading.show=!1)}),t.on("video:seeked",()=>{t.loading.show=!1,t.mask.show=!0}),t.on("video:seeking",()=>{t.loading.show=!0,t.mask.show=!1}),t.on("video:timeupdate",()=>{t.mask.show=!1}),t.on("video:waiting",()=>{t.loading.show=!0,t.mask.show=!1})}(t),function(t){const{option:e,storage:r,template:{$video:a,$poster:o}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(a.volume=D(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(a.volume=D(n,0,1)),e.poster&&w(o,"backgroundImage",`url(${e.poster})`),e.autoplay&&(a.autoplay=e.autoplay),e.playsInline&&(a.playsInline=!0,a["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Vt(t){const{notice:e,constructor:r,template:{$player:a,$video:o}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=o,r=document.documentElement.clientWidth,a=document.documentElement.clientHeight;return t>e&&ra}return t.on("fullscreenWeb",e=>{if(e){if(l()){const e=Number(r.AUTO_ORIENTATION_TIME??0);setTimeout(()=>{t.fullscreenWeb&&!v(a,n)&&function(){const e=O(),r=document.documentElement.clientWidth,o=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;w(a,"width",`${o}px`),w(a,"height",`${i}px`),w(a,"transform-origin","0 0"),w(a,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),f(a,n),t.isRotate=!0,t.emit("resize")}()},e)}}else v(a,n)&&(w(a,"width",""),w(a,"height",""),w(a,"transform-origin",""),w(a,"transform",""),g(a,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",async t=>{const r=!!screen?.orientation?.lock;if(t){if(r&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";await screen.orientation.lock(t),s=!0,f(a,i)}catch(o){s=!1,e.show=o}}else if(v(a,i)&&g(a,i),r&&s){try{screen.orientation.unlock()}catch{}s=!1}}),{name:"autoOrientation",get state(){return v(a,n)}}}function Yt(t){const{i18n:e,icons:r,storage:a,constructor:o,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=u(".art-auto-playback-last",s),c=u(".art-auto-playback-jump",s),d=u(".art-auto-playback-close",s);y(d,r.close);let p=null;function h(){const r=(a.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),w(s,"display","none"),r&&r>=o.AUTO_PLAYBACK_MIN&&(w(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${B(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{w(s,"display","none")}),n(c,"click",()=>{t.seek=r,t.play(),w(i,"display","none"),w(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{w(s,"display","none")},o.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=a.get("times")||{},r=Object.keys(e);r.length>o.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,a.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return a.get("times")||{}},clear:()=>a.del("times"),delete(t){const e=a.get("times")||{};return delete e[t],a.set("times",e),e}}}function Nt(t){const{constructor:e,proxy:r,template:{$player:a,$video:o}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,g(a,"art-fast-forward"))};return r(o,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,f(a,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return v(a,"art-fast-forward")}}}function Dt(t){const{layers:e,icons:r,template:{$player:a}}=t;function o(){return v(a,"art-lock")}function n(){f(a,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){g(a,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const a=y(e,r.lock),o=y(e,r.unlock);w(a,"display","none"),t.on("lock",t=>{t?(w(a,"display","inline-flex"),w(o,"display","none")):(w(a,"display","none"),w(o,"display","inline-flex"))})},click(){o()?i():n()}}),{name:"lock",get state(){return o()},set state(t){t?n():i()}}}function Ft(t){return t.on("control",e=>{e?g(t.template.$player,"art-mini-progress-bar"):f(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Bt{constructor(t){this.art=t,this.id=0;const{option:e}=t;e.miniProgressBar&&!e.isLive&&this.add(Ft),e.lock&&p&&this.add(Dt),e.autoPlayback&&!e.isLive&&this.add(Yt),e.autoOrientation&&p&&this.add(Vt),e.fastForward&&p&&!e.isLive&&this.add(Nt);for(let r=0;rthis.next(t,e)):this.next(t,e)}next(t,e){const r=e&&e.name||t.name||`plugin${this.id}`;return V(!U(this,r),`Cannot add a plugin that already has the same name: ${r}`),W(this,r,{value:e}),this}}class Ht extends pt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:a}}=t;this.name="setting",this.$parent=a,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=C(t,r.setting),a=C(t,this.$parent);!this.show||e||a||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,PLAYBACK_RATE:o}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:a,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:o.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,ASPECT_RATIO:o}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:a,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:o.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,FLIP:o}}=t;function n(t){return e.get(F(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:a,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:o.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:a}=t;return{width:a.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){for(let r=0;r{e.default=e===t,e.default&&e.$item&&$(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,a=[]){for(let o=0;oe}),W(n,"$parents",{get:()=>r}),W(n,"$option",{get:()=>t});const a=[];W(n,"$events",{get:()=>a}),W(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,a)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){const{controls:t,constructor:{SETTING_WIDTH:e,SETTING_ITEM_HEIGHT:r},template:{$player:a,$setting:o}}=this.art;if(t.setting&&this.show){const n=this.active[0]?.$parent?.width||e,{left:i,width:s}=A(t.setting),{left:l,width:c}=A(a),d=i-l+s/2-n/2;if(w(o,"height",`${this.active===this.option?this.active.length*r:(this.active.length+1)*r}px`),w(o,"width",`${n}px`),this.art.isRotate||p)return;d+n>c?(w(o,"left",null),w(o,"right",null)):(w(o,"left",`${d}px`),w(o,"right","auto"))}}inactivate(t){for(let e=0;e'),s=L("div");f(s,"art-setting-item-left-icon"),y(s,a),y(i,s),y(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),y(e,n)}createItem(t,e=!1){if(!this.cache.has(t.$option))return;const r=this.cache.get(t.$option),a=t.$item;let o="selector";U(t,"switch")&&(o="switch"),U(t,"range")&&(o="range"),U(t,"onClick")&&(o="button");const{icons:n,proxy:i,constructor:s}=this.art,l=L("div");f(l,"art-setting-item"),w(l,"height",`${s.SETTING_ITEM_HEIGHT}px`),l.dataset.name=t.name||"",l.dataset.value=t.value||"";const c=y(l,'
'),d=y(l,'
'),p=L("div");switch(f(p,"art-setting-item-left-icon"),o){case"button":case"switch":case"range":y(p,t.icon||n.config);break;case"selector":t.selector?.length?y(p,t.icon||n.config):y(p,n.check)}y(c,p),W(t,"$icon",{configurable:!0,get:()=>p}),W(t,"icon",{configurable:!0,get:()=>p.innerHTML,set(t){p.innerHTML="",y(p,t)}});const h=L("div");f(h,"art-setting-item-left-text"),y(h,t.html||""),y(c,h),W(t,"$html",{configurable:!0,get:()=>h}),W(t,"html",{configurable:!0,get:()=>h.innerHTML,set(t){h.innerHTML="",y(h,t)}});const u=L("div");switch(f(u,"art-setting-item-right-tooltip"),y(u,t.tooltip||""),y(d,u),W(t,"$tooltip",{configurable:!0,get:()=>u}),W(t,"tooltip",{configurable:!0,get:()=>u.innerHTML,set(t){u.innerHTML="",y(u,t)}}),o){case"switch":{const e=L("div");f(e,"art-setting-item-right-icon");const r=y(e,n.switchOn),a=y(e,n.switchOff);w(t.switch?a:r,"display","none"),y(d,e),W(t,"$switch",{configurable:!0,get:()=>e});let o=t.switch;W(t,"switch",{configurable:!0,get:()=>o,set(t){o=t,t?(w(a,"display","none"),w(r,"display",null)):(w(a,"display",null),w(r,"display","none"))}});break}case"range":{const e=L("div");f(e,"art-setting-item-right-icon");const r=y(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],f(r,"art-setting-range"),y(d,e),W(t,"$range",{configurable:!0,get:()=>r});let a=[...t.range];W(t,"range",{configurable:!0,get:()=>a,set(t){a=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(t.selector?.length){const t=L("div");f(t,"art-setting-item-right-icon"),y(t,n.arrowRight),y(d,t)}}switch(o){case"switch":if(t.onSwitch){const e=i(l,"click",async e=>{t.switch=await t.onSwitch.call(this.art,t,l,e)});t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=i(t.$range,"change",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onRange.call(this.art,t,l,e)});t.$events.push(e)}if(t.onChange){const e=i(t.$range,"input",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onChange.call(this.art,t,l,e)});t.$events.push(e)}}break;case"selector":{const e=i(l,"click",async e=>{t.selector?.length?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=await t.$parent.onSelect.call(this.art,t,l,e)))});t.$events.push(e),t.default&&f(l,"art-current")}break;case"button":if(t.onClick){const e=i(l,"click",async e=>{t.tooltip=await t.onClick.call(this.art,t,l,e)});t.$events.push(e)}}W(t,"$item",{configurable:!0,get:()=>l}),e?z(l,a):y(r,l),t.mounted&&setTimeout(()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){if(this.active=t,this.cache.has(t)){$(this.cache.get(t),"art-current")}else{const e=L("div");this.cache.set(t,e),f(e,"art-setting-panel"),y(this.$parent,e),$(e,"art-current"),t[0]?.$parent&&this.createHeader(t[0]);for(let r=0;rnull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){return this.art.template.$video?.textTracks?.[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?x(r,t):w(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?H(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(t,e={}){const{i18n:r,notice:a,option:o}=this.art,n={...o.subtitle,...e,url:t},i=await this.init(n);return e.name&&(a.show=`${r.get("Switch Subtitle")}: ${e.name}`),i}createTrack(t,e){const{template:r,proxy:a,option:o}=this.art,{$video:n,$track:i}=r,s=L("track");s.default=!0,s.kind=t,s.src=e,s.label=o.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,b(i),y(n,s),r.$track=s,this.destroyEvent=a(this.textTrack,"cuechange",()=>this.update())}async init(t){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(o(t,dt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||Y(t.url)){case"srt":{const e=G(r);return K(t.onVttLoad(e))}case"ass":{const e=Z(r);return K(t.onVttLoad(e))}case"vtt":return K(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null}}class qt{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=u(e.container),V(this.$container,`No container element found by ${e.container}`)),V(I(),"The current browser does not support flex layout");const a=this.$container.tagName.toLowerCase();V("div"===a,`Unsupported container element type, only support 'div' but got '${a}'`),V(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=t.id,this.init()}static get html(){return`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${n}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `}query(t){return u(t,this.$container)}init(){const{option:t}=this.art;if(t.useSSR||(this.$container.innerHTML=qt.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);V(e instanceof HTMLVideoElement||e instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),z(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&f(this.$player,"art-backdrop"),p&&f(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":f(this.$player,"art-destroy")}}class Xt{on(t,e,r){const a=this.e||(this.e={});return(a[t]||(a[t]=[])).push({fn:e,ctx:r}),this}once(t,e,r){const a=this;function o(...n){a.off(t,o),e.apply(r,n)}return o._=e,this.on(t,o,r)}emit(t,...e){const r=((this.e||(this.e={}))[t]||[]).slice();for(let a=0;ae.call(this,this)),Zt.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${Zt.version}`);for(let e=0;et(`Event@${e.type}`))}Kt.push(this)}static get instances(){return Kt}static get version(){return n}static get config(){return i}static get utils(){return et}static get scheme(){return dt}static get Emitter(){return Xt}static get validator(){return o}static get kindOf(){return o.kindOf}static get html(){return qt.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:l?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:navigator?.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){Zt.REMOVE_SRC_WHEN_DESTROY&&this.reset(),this.events.destroy(),this.template.destroy(t),Kt.splice(Kt.indexOf(this),1),this.isDestroy=!0,this.emit("destroy")}}return Zt.STYLE=jt,Zt.DEBUG=!1,Zt.CONTEXTMENU=!0,Zt.NOTICE_TIME=2e3,Zt.SETTING_WIDTH=250,Zt.SETTING_ITEM_WIDTH=200,Zt.SETTING_ITEM_HEIGHT=35,Zt.RESIZE_TIME=200,Zt.SCROLL_TIME=200,Zt.SCROLL_GAP=50,Zt.AUTO_PLAYBACK_MAX=10,Zt.AUTO_PLAYBACK_MIN=5,Zt.AUTO_PLAYBACK_TIMEOUT=3e3,Zt.RECONNECT_TIME_MAX=5,Zt.RECONNECT_SLEEP_TIME=1e3,Zt.CONTROL_HIDE_TIME=3e3,Zt.DBCLICK_TIME=300,Zt.DBCLICK_FULLSCREEN=!0,Zt.MOBILE_DBCLICK_PLAY=!0,Zt.MOBILE_CLICK_PLAY=!1,Zt.AUTO_ORIENTATION_TIME=200,Zt.INFO_LOOP_TIME=1e3,Zt.FAST_FORWARD_VALUE=3,Zt.FAST_FORWARD_TIME=1e3,Zt.TOUCH_MOVE_RATIO=.5,Zt.VOLUME_STEP=.1,Zt.SEEK_STEP=5,Zt.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],Zt.ASPECT_RATIO=["default","4:3","16:9"],Zt.FLIP=["normal","horizontal","vertical"],Zt.FULLSCREEN_WEB_IN_BODY=!0,Zt.LOG_VERSION=!0,Zt.USE_RAF=!1,Zt.REMOVE_SRC_WHEN_DESTROY=!0,h&&(M("artplayer-style",jt),setTimeout(()=>{Zt.LOG_VERSION&&console.log(`%c ArtPlayer %c ${Zt.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),Zt}); diff --git a/docs/compiled/artplayer.legacy.js b/docs/compiled/artplayer.legacy.js index deb358eb6..85e7d8eca 100644 --- a/docs/compiled/artplayer.legacy.js +++ b/docs/compiled/artplayer.legacy.js @@ -4,4 +4,4 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";var t,e=Object.defineProperty,r=Object.defineProperties,o=Object.getOwnPropertyDescriptors,a=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(t,r,o)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[r]=o,l=(t,e)=>{for(var r in e||(e={}))n.call(e,r)&&s(t,r,e[r]);if(a)for(var r of a(e))i.call(e,r)&&s(t,r,e[r]);return t},c=(t,e)=>r(t,o(e)),d=(t,e,r)=>new Promise((o,a)=>{var n=t=>{try{s(r.next(t))}catch(e){a(e)}},i=t=>{try{s(r.throw(t))}catch(e){a(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(n,i);s((r=r.apply(t,e)).next())});function p(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var h,u={exports:{}};var m=(h||(h=1,u.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var a=t(r);if("boolean"===a)return"boolean";if("string"===a)return"string";if("number"===a)return"number";if("symbol"===a)return"symbol";if("function"===a)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(a=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return a.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function a(t,e){var o=2=1,k=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(y)||x,$="undefined"!==typeof window&&"undefined"!==typeof document;function T(t,e=document){return e.querySelector(t)}function E(t,e=document){return Array.from(e.querySelectorAll(t))}function C(t,e){return t.classList.add(e)}function z(t,e){return t.classList.remove(e)}function L(t,e){return t.classList.contains(e)}function S(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function M(t){return t.parentNode.removeChild(t)}function I(t,e,r){return t.style[e]=r,t}function P(t,e){for(const r in e)I(t,r,e[r]);return t}function A(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function O(t,e){A(t).forEach(t=>z(t,e)),C(t,e)}function R(t,e,r="top"){k||(t.setAttribute("aria-label",e),C(t,"hint--rounded"),C(t,`hint--${r}`))}function _(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,a=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=a+e&&r.left+r.width+e>=0;return n&&i}function V(t,e){return j(t).includes(e)}function Y(t,e){return e.parentNode.replaceChild(t,e),t}function N(t){return document.createElement(t)}function D(t="",e=""){const r=N("i");return C(r,"art-icon"),C(r,`art-icon-${t}`),S(r,e),r}function F(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function B(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function H(t){return t.getBoundingClientRect()}function W(t,e){return new Promise((r,o)=>{const a=new Image;a.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=a.width*e,n.height=a.height*e,i.drawImage(a,0,0,n.width,n.height),n.toBlob(e=>{const a=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(a),o(new Error(`Image load failed: ${t}`))},n.src=a})}else r(a)},a.onerror=function(){o(new Error(`Image load failed: ${t}`))},a.src=t})}function j(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function U(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class q extends Error{constructor(t,e){super(t),"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function X(t,e){if(!t)throw new q(e);return t}function G(t){return t.includes("?")?G(t.split("?")[0]):t.includes("#")?G(t.split("#")[0]):t.trim().toLowerCase().split(".").pop()}function K(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r)}function Z(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function J(t){return t.charAt(0).toUpperCase()+t.slice(1)}function Q(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}function tt(t){return t.replace(/[&<>'"]/g,t=>({"&":"&","<":"<",">":">","'":"'",'"':"""}[t]||t))}const et=Object.defineProperty,{hasOwnProperty:rt}=Object.prototype;function ot(t,e){return rt.call(t,e)}function at(t,e){return Object.getOwnPropertyDescriptor(t,e)}function nt(...t){const e=t=>t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const a=t[o],n=r[o];Array.isArray(a)&&Array.isArray(n)?t[o]=a.concat(...n):e(a)&&e(n)?t[o]=nt(a,n):t[o]=n}),t),{})}function it(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function st(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function lt(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);return o?{start:r(o[1].trim()),end:r(o[2].trim()),text:o[5].replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}:null}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function ct(t=0){return new Promise(e=>setTimeout(e,t))}function dt(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=null,t.apply(this,o)),e)}}function pt(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const ht=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:q,addClass:C,append:S,assToVtt:lt,capitalize:J,clamp:Z,createElement:N,debounce:dt,def:et,download:K,errorHandle:X,escape:tt,get:at,getComposedPath:j,getExt:G,getIcon:D,getRect:H,getSafeAreaInsets:U,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:ot,hasClass:L,includeFromEvent:V,inverseClass:O,isBrowser:$,isIOS:w,isIOS13:x,isInViewport:_,isMobile:k,isSafari:b,loadImg:W,mergeDeep:nt,query:T,queryAll:E,remove:M,removeClass:z,replaceElement:Y,secondToTime:Q,setStyle:I,setStyleText:F,setStyles:P,siblings:A,sleep:ct,srtToVtt:it,supportsFlex:B,throttle:pt,tooltip:R,unescape:function(t){const e={"&":"&","<":"<",">":">","'":"'",""":'"'},r=new RegExp(`(${Object.keys(e).join("|")})`,"g");return t.replace(r,t=>e[t]||t)},userAgent:y,vttToBlob:st},Symbol.toStringTag,{value:"Module"})),ut="array",mt="boolean",ft="string",gt="number",vt="object",yt="function";function bt(t,e,r){return X(e===ft||e===gt||t instanceof Element,`${r.join(".")} require '${ft}' or 'Element' type`)}const wt={html:bt,disable:`?${mt}`,name:`?${ft}`,index:`?${gt}`,style:`?${vt}`,click:`?${yt}`,mounted:`?${yt}`,tooltip:`?${ft}|${gt}`,width:`?${gt}`,selector:`?${ut}`,onSelect:`?${yt}`,switch:`?${mt}`,onSwitch:`?${yt}`,range:`?${ut}`,onRange:`?${yt}`,onChange:`?${yt}`},xt={id:ft,container:bt,url:ft,poster:ft,type:ft,theme:ft,lang:ft,volume:gt,isLive:mt,muted:mt,autoplay:mt,autoSize:mt,autoMini:mt,loop:mt,flip:mt,playbackRate:mt,aspectRatio:mt,screenshot:mt,setting:mt,hotkey:mt,pip:mt,mutex:mt,backdrop:mt,fullscreen:mt,fullscreenWeb:mt,subtitleOffset:mt,miniProgressBar:mt,useSSR:mt,playsInline:mt,lock:mt,gesture:mt,fastForward:mt,autoPlayback:mt,autoOrientation:mt,airplay:mt,proxy:`?${yt}`,plugins:[yt],layers:[wt],contextmenu:[wt],settings:[wt],controls:[c(l({},wt),{position:(t,e,r)=>{const o=["top","left","right"];return X(o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}})],quality:[{default:`?${mt}`,html:ft,url:ft}],highlight:[{time:gt,text:ft}],thumbnails:{url:ft,number:gt,column:gt,width:gt,height:gt,scale:gt},subtitle:{url:ft,name:ft,type:ft,style:vt,escape:mt,encoding:ft,onVttLoad:yt},moreVideoAttr:vt,i18n:vt,icons:vt,cssVar:vt,customType:vt};class kt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return L(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?C(e,r):z(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",f(e,wt),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;X(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const o=N("div");C(o,`art-${this.name}`),C(o,`art-${this.name}-${r}`);const a=Array.from(this.$parent.children);o.dataset.index=e.index||this.id;const n=a.find(t=>Number(t.dataset.index)>=Number(o.dataset.index));n?n.insertAdjacentElement("beforebegin",o):S(this.$parent,o),e.html&&S(o,e.html),e.style&&P(o,e.style),e.tooltip&&R(o,e.tooltip);const i=[];if(e.click){const t=this.art.events.proxy(o,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});i.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,o,i),this[r]=o,this.cache.set(r,{$ref:o,events:i,option:e}),e.mounted&&e.mounted.call(this.art,o),o}remove(t){X(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],M(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class $t extends kt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,k||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:o}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,a=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return c(l({},t),{html:`${r.get("Play Speed")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const r=T('[data-value="1"]',t);r&&O(r,"art-current"),e.on("video:ratechange",()=>{const r=E("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&O(r,"art-current")})}})}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,a=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return c(l({},t),{html:`${r.get("Aspect Ratio")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const r=T('[data-value="default"]',t);r&&O(r,"art-current"),e.on("aspectRatio",e=>{const r=E("span",t).find(t=>t.dataset.value===e);r&&O(r,"art-current")})}})}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,a=o.map(t=>`${r.get(J(t))}`).join("");return c(l({},t),{html:`${r.get("Video Flip")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const r=T('[data-value="normal"]',t);r&&O(r,"art-current"),e.on("flip",e=>{const r=E("span",t).find(t=>t.dataset.value===e);r&&O(r,"art-current")})}})}}({name:"flip",index:30})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){const e=$?location.href:"";return c(l({},t),{html:`ArtPlayer ${g}`})}({name:"version",index:50})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,a=t.clientY,{height:n,width:i,left:s,top:l}=H(r),{height:c,width:d}=H(o);let p=e-s,h=a-l;e+d>s+i&&(p=i-d),a+c>l+n&&(h=n-c),P(o,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{V(t,o)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}function Tt(t,e){const{$progress:r}=t.template,{left:o}=H(r),a=Z((k?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),n=a/r.clientWidth*t.duration;return{second:n,time:Q(n),width:a,percentage:Z(a/r.clientWidth,0,1)}}function Et(t,e){if(t.isRotate){const r=e.touches[0].clientY/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=Tt(t,e);t.emit("setBar","played",o,e),t.seek=r}}function Ct(t){return e=>{const{icons:r,option:o,proxy:a}=e,{$player:n,$progress:i}=e.template;return c(l({},t),{html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=T(".art-progress-hover",t),d=T(".art-progress-loaded",t),p=T(".art-progress-played",t),h=T(".art-progress-highlight",t),u=T(".art-progress-indicator",t),m=T(".art-progress-tip",t);function f(r,o){const{width:a,time:n}=o||Tt(e,r);m.textContent=n||"00:00";const i=m.clientWidth;a<=i/2?I(m,"left",0):a>t.clientWidth-i/2?I(m,"left",t.clientWidth-i+"px"):I(m,"left",a-i/2+"px")}r.indicator?S(u,r.indicator):I(u,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,o,a){const i="played"===r&&a&&k;if("loaded"===r&&I(d,"width",100*o+"%"),"hover"===r&&(I(c,"width",100*o+"%"),V(a,h)?function(r){const{width:o}=Tt(e,r),{text:a}=r.target.dataset;m.textContent=a;const n=m.clientWidth;o<=n/2?I(m,"left",0):o>t.clientWidth-n/2?I(m,"left",t.clientWidth-n+"px"):I(m,"left",o-n/2+"px")}(a):f(a),0===o?z(n,"art-progress-hover"):C(n,"art-progress-hover")),"played"===r&&(I(p,"width",100*o+"%"),I(u,"left",100*o+"%")),i){C(n,"art-progress-hover");f(a,{width:t.clientWidth*o,time:Q(o*e.duration)}),clearTimeout(s),s=setTimeout(()=>{z(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){h.textContent="";for(let t=0;t`;S(h,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),k||(a(i,"click",t=>{t.target!==u&&Et(e,t)}),a(i,"mousemove",t=>{const{percentage:r}=Tt(e,t);e.emit("setBar","hover",r,t)}),a(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),a(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:o}=Tt(e,t);e.emit("setBar","played",o,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}})}}class zt extends kt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;t.on("mousemove",()=>{k||(this.show=!0)}),t.on("click",()=>{k?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=V(t,o)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(z(r,"art-hide-cursor"),C(r,"art-hover"),this.timer=Date.now()):(C(r,"art-hide-cursor"),z(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(Ct({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.play),i=S(t,o.pause);function s(){I(n,"display","flex"),I(i,"display","none")}function l(){I(n,"display","none"),I(i,"display","flex")}R(n,a.get("Play")),R(i,a.get("Pause")),r(n,"click",()=>{e.play()}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o}=e,a=S(t,o.volume),n=S(t,o.volumeClose),i=S(t,'
'),s=S(i,'
'),l=S(s,'
'),c=S(s,'
'),d=S(c,'
'),p=S(d,'
'),h=S(c,'
');function u(t){const{top:e,height:r}=H(c);return 1-(t.clientY-e)/r}function m(){if(e.muted||0===e.volume)I(a,"display","none"),I(n,"display","flex"),I(h,"top","100%"),I(p,"top","100%"),l.textContent=0;else{const t=100*e.volume;I(a,"display","flex"),I(n,"display","none"),I(h,"top",100-t+"%"),I(p,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(m(),e.on("video:volumechange",m),r(a,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),k)I(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=u(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=u(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>c(l({},t),{style:k?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${Q(e.currentTime)} / ${Q(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const o=["video:loadedmetadata","video:timeupdate","video:progress"];for(let a=0;a{this.art.quality=t.quality}),t.screenshot&&!k&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:o}=e;S(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;S(t,o.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{R(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;S(t,o.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{R(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:o}=e;S(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.fullscreenWebOn),i=S(t,o.fullscreenWebOff);I(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(R(t,a.get("Exit Web Fullscreen")),I(n,"display","none"),I(i,"display","inline-flex")):(R(t,a.get("Web Fullscreen")),I(n,"display","inline-flex"),I(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.fullscreenOn),i=S(t,o.fullscreenOff);I(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(R(t,a.get("Exit Fullscreen")),I(n,"display","none"),I(i,"display","inline-flex")):(R(t,a.get("Fullscreen")),I(n,"display","inline-flex"),I(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),et(e,"$control_item",{get:()=>r}),et(e,"$control_value",{get:()=>a})}const i=o(n,"click",e=>d(this,null,function*(){const r=j(e),o=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(o),t.onSelect&&(a.innerHTML=yield t.onSelect.call(this.art,o,o.$control_item,e))}));r.push(i)}}function Lt(t,e,r,o){const a=e-o,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(a)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,a);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}class St{constructor(t){this.destroyEvents=new Set,this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:a}}=t;function n(e){V(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(a,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:a,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=n);switch(c.length){case 1:t.emit("click",e),k?!t.isLock&&a&&t.toggle():t.toggle(),i=c;break;case 2:t.emit("dblclick",e),k?!t.isLock&&s&&t.toggle():l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{C(r,"art-hover"),t.emit("hover",!0,e)},e=>{z(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const a=dt(()=>t.emit("resize"),o.RESIZE_TIME);t.on("window:orientationchange",()=>a()),t.on("window:resize",()=>a()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>a())}(t,this),function(t,e){if(k&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let a=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){a===o&&Et(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:o,pageY:n}=e.touches[0],c=Lt(i,s,o,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=Z((o-i)/t.width,-1,1),d=Z((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=a===r?t.constructor.TOUCH_MOVE_RATIO:1,u=Z(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",Z(u/t.duration,0,1),e),t.notice.show=`${Q(u)} / ${Q(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,a=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{a=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{a=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,a=pt(()=>{t.emit("view",_(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>a()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],a=[];function n(n={}){for(let t=0;t{const o=n.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});a.push(s)}),o.forEach(r=>{var o;const s=n.window||(null==(o=i.ownerDocument)?void 0:o.defaultView)||window,l=e.proxy(s,r,e=>{t.emit(`window:${r}`,e)});a.push(l)})}n(),e.bindGlobalEvents=n}(t,this),function(t){if(t.constructor.USE_RAF){let e=null;!function r(){t.playing&&t.emit("raf"),t.isDestroy||(e=requestAnimationFrame(r))}(),t.on("destroy",()=>{cancelAnimationFrame(e)})}}(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));t.addEventListener(e,r,o);const a=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(a),a}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class Mt{constructor(t){this.art=t,this.keys={},k||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{this.art.toggle()}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',state:'\n\n\n',play:'\n \n',pause:'\n \n',check:'\n\n',volume:'\n \n \n',volumeClose:'\n \n \n',screenshot:'\n\t\n\n',setting:'\n \n \n',pip:'\n\n',arrowLeft:'\n \n',arrowRight:'\n \n',playbackRate:'',aspectRatio:'',config:'',lock:'\n\n\n\n\n',flip:'\n\n\n\n\n\n',unlock:'\n\n\n',fullscreenOff:'\n\n\n\n\n',fullscreenOn:'\n\n\n\n\n',fullscreenWebOff:'\n\n\n\n\n',fullscreenWebOn:'\n\n\n\n\n',switchOn:'\n\n\n \n',switchOff:'\n\n\n \n\n',error:'\n\n\n\n\n',close:'\n\n\n\n\n',airplay:'\n \n \n \n \n\n'},t.option.icons);for(const r in e)et(this,r,{get:()=>D(r,e[r])})}}class Ot extends kt{constructor(t){super(t),this.name="info",k||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:a}}=this.art;t(o,"click",()=>{this.show=!1});let n=null;const i=E("[data-video]",r)||[];this.art.on("destroy",()=>clearTimeout(n)),function t(){for(let e=0;e{I(a,"display","none"),I(n,"display",null)}),o.proxy(e.$state,"click",()=>t.play())}}class Yt{constructor(t){this.art=t,this.timer=null,t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,C(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",z(r,"art-notice-show")},e.NOTICE_TIME)):z(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}const Nt=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],Dt=(()=>{if("undefined"===typeof document)return!1;const t=Nt[0],e={};for(const r of Nt){if(r[1]in document){for(const[o,a]of r.entries())e[t[o]]=a;return e}}return!1})(),Ft={change:Dt.fullscreenchange,error:Dt.fullscreenerror},Bt={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const a=()=>{Bt.off("change",a),r()};Bt.on("change",a);const n=t[Dt.requestFullscreen](e);n instanceof Promise&&n.then(a).catch(o)}),exit:()=>new Promise((t,e)=>{if(!Bt.isFullscreen)return void t();const r=()=>{Bt.off("change",r),t()};Bt.on("change",r);const o=document[Dt.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>Bt.isFullscreen?Bt.exit():Bt.request(t,e),onchange(t){Bt.on("change",t)},onerror(t){Bt.on("error",t)},on(t,e){const r=Ft[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Ft[t];r&&document.removeEventListener(r,e,!1)},raw:Dt};function Ht(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t,n=t=>{Bt.on("change",()=>{t.emit("fullscreen",Bt.isFullscreen),Bt.isFullscreen?(t.state="fullscreen",C(a,"art-fullscreen")):z(a,"art-fullscreen"),t.emit("resize")}),Bt.on("error",e=>{t.emit("fullscreenError",e)}),et(t,"fullscreen",{get:()=>Bt.isFullscreen,set(t){return d(this,null,function*(){t?yield Bt.request(a):yield Bt.exit()})}})};t.once("video:loadedmetadata",()=>{var a;Bt.isEnabled?n(t):o.webkitSupportsFullscreen?((a=t).on("document:webkitfullscreenchange",()=>{a.emit("fullscreen",a.fullscreen),a.emit("resize")}),et(a,"fullscreen",{get:()=>document.fullscreenElement===o,set(t){t?(a.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})):et(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),et(t,"fullscreen",at(t,"fullscreen"))})}function Wt(t){const{icons:e,proxy:r,storage:o,template:{$player:a,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(z(a,"art-mini"),I(e,"display","none"),a.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(I(e,"display","none"),I(r,"display","flex")):(I(e,"display","flex"),I(r,"display","none"))}function p(){const{$mini:e}=t.template,r=H(e),a=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;o.set("top",a),o.set("left",n),I(e,"top",`${a}px`),I(e,"left",`${n}px`)}et(t,"mini",{get:()=>L(a,"art-mini"),set(h){if(h){t.state="mini",C(a,"art-mini");const h=function(){const{$mini:a}=t.template;if(a)return S(a,n),I(a,"display","flex");{const a=N("div");C(a,"art-mini-popup"),S(document.body,a),t.template.$mini=a,S(a,n);const p=S(a,'
');S(p,e.close),r(p,"click",c);const h=S(a,'
'),u=S(h,e.play),m=S(h,e.pause);return r(u,"click",()=>t.play()),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(a,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){C(a,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;I(a,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,z(a,"art-mini-dragging");const t=H(a);o.set("left",t.left),o.set("top",t.top),I(a,"left",`${t.left}px`),I(a,"top",`${t.top}px`),I(a,"transform",null)}}),a}}(),u=o.get("top"),m=o.get("left");"number"===typeof u&&"number"===typeof m?(I(h,"top",`${u}px`),I(h,"left",`${m}px`),_(h)||p()):p(),t.emit("mini",!0)}else c()}})}function jt(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,et(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),et(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):et(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ut(t){const{option:e,template:{$progress:r,$video:o}}=t;let a=null,n=!1,i=null;t.on("setBar",(a,s,l)=>d(null,null,function*(){var c;const d=null==(c=t.controls)?void 0:c.thumbnails,{url:p,scale:h}=e.thumbnails;if(!d||!p)return;if("hover"===a||"played"===a&&l&&k){if(i||n||(n=!0,i=yield W(p,h),n=!1),!i)return;const a=r.clientWidth*s;a>0&&ar.clientWidth-u/2?I(s,"left",r.clientWidth-u+"px"):I(s,"left",a-u/2+"px")}(a)}})),et(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(a),a=null,n=!1,i=null)}})}Object.defineProperties(Bt,{isFullscreen:{get:()=>Boolean(document[Dt.fullscreenElement])},element:{enumerable:!0,get:()=>document[Dt.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[Dt.fullscreenEnabled])}});class qt{constructor(t){!function(t){const{option:e,template:{$video:r}}=t;et(t,"url",{get:()=>r.src,set(o){return d(this,null,function*(){if(o){const a=t.url,n=e.type||G(o),i=e.customType[n];n&&i?(yield ct(),t.loading.show=!0,i.call(t,r,o,t)):(URL.revokeObjectURL(a),r.src=o),a!==t.url&&(t.option.url=o,t.isReady&&a&&t.once("video:canplay",()=>{t.emit("restart",o)}))}else yield ct(),t.loading.show=!0})}})}(t),function(t){const{template:{$video:e}}=t;et(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:a},template:{$video:n}}=t;et(t,"play",{value(){return d(this,null,function*(){const i=yield n.play();if(r.show=e.get("Play"),t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;et(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${Q(t.currentTime)} / ${Q(t.duration)}`),t.emit("seek",t.currentTime,r)}}),et(t,"forward",{set(e){t.seek=t.currentTime+e}}),et(t,"backward",{set(e){t.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:a}=t;et(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=Z(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(100*e.volume,10)}`,0!==e.volume&&a.set("volume",e.volume)}}),et(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;et(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{r=Number.parseFloat(r),Number.isNaN(r)||(e.currentTime=Z(r,0,t.duration))}})}(t),function(t){et(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){function e(e,r){return new Promise((o,a)=>{if(e===t.url)return void o();const{playing:n,aspectRatio:i,playbackRate:s}=t;t.pause(),t.url=e,t.notice.show="";const l={error:e=>{t.off("video:canplay",l.canplay),t.off("video:loadedmetadata",l.metadata),a(e)},metadata:()=>{t.currentTime=r},canplay:()=>d(null,null,function*(){t.off("video:error",l.error),t.playbackRate=s,t.aspectRatio=i,n&&(yield t.play()),t.notice.show="",o()})};t.once("video:error",l.error),t.once("video:loadedmetadata",l.metadata),t.once("video:canplay",l.canplay)})}et(t,"switchQuality",{value:r=>e(r,t.currentTime)}),et(t,"switchUrl",{value:t=>e(t,0)}),et(t,"switch",{set:t.switchUrl})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t;et(t,"playbackRate",{get:()=>e.playbackRate,set(a){if(a){if(a===e.playbackRate)return;e.playbackRate=a,o.show=`${r.get("Rate")}: ${1===a?r.get("Normal"):`${a}x`}`}else t.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t;et(t,"aspectRatio",{get:()=>a.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)I(o,"width",null),I(o,"height",null),I(o,"margin",null),delete a.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=a,i=e/r,s=t[0]/t[1];i>s?(I(o,"width",s*r+"px"),I(o,"height","100%"),I(o,"margin","0 auto")):(I(o,"width","100%"),I(o,"height",e/s+"px"),I(o,"margin","auto 0")),a.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=N("canvas");et(t,"getDataURL",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(n){e.show=n,a(n)}})}),et(t,"getBlobUrl",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,a(n)}})}),et(t,"screenshot",{value:e=>d(null,null,function*(){const o=yield t.getDataURL();return K(o,`${e||`artplayer_${Q(r.currentTime)}`}.png`),t.emit("screenshot",o),o})})}(t),Ht(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let a="";et(t,"fullscreenWeb",{get:()=>L(o,"art-fullscreen-web"),set(n){n?(a=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&S(document.body,o),t.state="fullscreenWeb",I(o,"width","100%"),I(o,"height","100%"),C(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&S(r,o),a&&(o.style.cssText=a,a=""),z(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),jt(t),function(t){const{$video:e}=t.template;et(t,"loaded",{get:()=>t.loadedTime/e.duration}),et(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){et(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;et(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;et(t,"autoSize",{value(){const{videoWidth:a,videoHeight:n}=o,{width:i,height:s}=H(e),l=a/n;if(i/s>l)I(r,"width",s*l/i*100+"%"),I(r,"height","100%");else{const t=i/l/s*100;I(r,"width","100%"),I(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){et(t,"rect",{get:()=>H(t.template.$player)});const e=["bottom","height","left","right","top","width"];for(let r=0;rt.rect[o]})}et(t,"x",{get:()=>t.left+window.pageXOffset}),et(t,"y",{get:()=>t.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;et(t,"flip",{get:()=>e.dataset.flip||"normal",set(a){a||(a="normal"),"normal"===a?delete e.dataset.flip:e.dataset.flip=a,o.show=`${r.get("Video Flip")}: ${r.get(J(a))}`,t.emit("flip",a)}})}(t),Wt(t),function(t){const{template:{$poster:e}}=t;et(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch(t){return""}},set(t){I(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;et(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:a,videoWidth:n}=r,i=a*(o/n);I(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;et(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){et(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){et(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];et(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;o{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,et(t,"airplay",{value(){n?(a.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){et(t,"quality",{set(e){const{controls:r,notice:o,i18n:a}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:(null==n?void 0:n.html)||"",selector:e,onSelect(e){return d(this,null,function*(){return yield t.switchQuality(e.url),o.show=`${a.get("Switch Video")}: ${e.html}`,e.html})}})}})}(t),Ut(t),function(t){const{i18n:e,notice:r,option:o,constructor:a,proxy:n,template:{$player:i,$video:s,$poster:l}}=t;let c=0;for(let d=0;d{t.emit(`video:${e.type}`,e)});t.on("video:canplay",()=>{c=0,t.loading.show=!1}),t.once("video:canplay",()=>{t.loading.show=!1,t.controls.show=!0,t.mask.show=!0,t.isReady=!0,t.emit("ready")}),t.on("video:ended",()=>{o.loop?(t.seek=0,t.play(),t.controls.show=!1,t.mask.show=!1):(t.controls.show=!0,t.mask.show=!0)}),t.on("video:error",n=>d(null,null,function*(){c{t.emit("resize"),k&&(t.loading.show=!1,t.controls.show=!0,t.mask.show=!0)}),t.on("video:loadstart",()=>{t.loading.show=!0,t.mask.show=!1,t.controls.show=!0}),t.on("video:pause",()=>{t.controls.show=!0,t.mask.show=!0}),t.on("video:play",()=>{t.mask.show=!1,I(l,"display","none")}),t.on("video:playing",()=>{t.mask.show=!1}),t.on("video:progress",()=>{t.playing&&(t.loading.show=!1)}),t.on("video:seeked",()=>{t.loading.show=!1,t.mask.show=!0}),t.on("video:seeking",()=>{t.loading.show=!0,t.mask.show=!1}),t.on("video:timeupdate",()=>{t.mask.show=!1}),t.on("video:waiting",()=>{t.loading.show=!0,t.mask.show=!1})}(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:a}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=Z(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(o.volume=Z(n,0,1)),e.poster&&I(a,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Xt(t){const{notice:e,constructor:r,template:{$player:o,$video:a}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=a,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{var a;if(e){if(l()){const e=Number(null!=(a=r.AUTO_ORIENTATION_TIME)?a:0);setTimeout(()=>{t.fullscreenWeb&&!L(o,n)&&function(){const e=U(),r=document.documentElement.clientWidth,a=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;I(o,"width",`${a}px`),I(o,"height",`${i}px`),I(o,"transform-origin","0 0"),I(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),C(o,n),t.isRotate=!0,t.emit("resize")}()},e)}}else L(o,n)&&(I(o,"width",""),I(o,"height",""),I(o,"transform-origin",""),I(o,"transform",""),z(o,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",t=>d(null,null,function*(){var r;const a=!!(null==(r=null==screen?void 0:screen.orientation)?void 0:r.lock);if(t){if(a&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";yield screen.orientation.lock(t),s=!0,C(o,i)}catch(n){s=!1,e.show=n}}else if(L(o,i)&&z(o,i),a&&s){try{screen.orientation.unlock()}catch(c){}s=!1}})),{name:"autoOrientation",get state(){return L(o,n)}}}function Gt(t){const{i18n:e,icons:r,storage:o,constructor:a,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=T(".art-auto-playback-last",s),c=T(".art-auto-playback-jump",s),d=T(".art-auto-playback-close",s);S(d,r.close);let p=null;function h(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),I(s,"display","none"),r&&r>=a.AUTO_PLAYBACK_MIN&&(I(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${Q(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{I(s,"display","none")}),n(c,"click",()=>{t.seek=r,t.play(),I(i,"display","none"),I(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{I(s,"display","none")},a.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>a.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function Kt(t){const{constructor:e,proxy:r,template:{$player:o,$video:a}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,z(o,"art-fast-forward"))};return r(a,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,C(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return L(o,"art-fast-forward")}}}function Zt(t){const{layers:e,icons:r,template:{$player:o}}=t;function a(){return L(o,"art-lock")}function n(){C(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){z(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=S(e,r.lock),a=S(e,r.unlock);I(o,"display","none"),t.on("lock",t=>{t?(I(o,"display","inline-flex"),I(a,"display","none")):(I(o,"display","none"),I(a,"display","inline-flex"))})},click(){a()?i():n()}}),{name:"lock",get state(){return a()},set state(t){t?n():i()}}}function Jt(t){return t.on("control",e=>{e?z(t.template.$player,"art-mini-progress-bar"):C(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Qt{constructor(t){this.art=t,this.id=0;const{option:e}=t;e.miniProgressBar&&!e.isLive&&this.add(Jt),e.lock&&k&&this.add(Zt),e.autoPlayback&&!e.isLive&&this.add(Gt),e.autoOrientation&&k&&this.add(Xt),e.fastForward&&k&&!e.isLive&&this.add(Kt);for(let r=0;rthis.next(t,e)):this.next(t,e)}next(t,e){const r=e&&e.name||t.name||`plugin${this.id}`;return X(!ot(this,r),`Cannot add a plugin that already has the same name: ${r}`),et(this,r,{value:e}),this}}class te extends kt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=V(t,r.setting),o=V(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:a}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:a.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:a}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:a.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:a}}=t;function n(t){return e.get(J(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:a.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){var r;for(let o=0;o{e.default=e===t,e.default&&e.$item&&O(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let a=0;ae}),et(n,"$parents",{get:()=>r}),et(n,"$option",{get:()=>t});const o=[];et(n,"$events",{get:()=>o}),et(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){var t,e;const{controls:r,constructor:{SETTING_WIDTH:o,SETTING_ITEM_HEIGHT:a},template:{$player:n,$setting:i}}=this.art;if(r.setting&&this.show){const s=(null==(e=null==(t=this.active[0])?void 0:t.$parent)?void 0:e.width)||o,{left:l,width:c}=H(r.setting),{left:d,width:p}=H(n),h=l-d+c/2-s/2;if(I(i,"height",`${this.active===this.option?this.active.length*a:(this.active.length+1)*a}px`),I(i,"width",`${s}px`),this.art.isRotate||k)return;h+s>p?(I(i,"left",null),I(i,"right",null)):(I(i,"left",`${h}px`),I(i,"right","auto"))}}inactivate(t){for(let e=0;e'),s=N("div");C(s,"art-setting-item-left-icon"),S(s,o),S(i,s),S(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),S(e,n)}createItem(t,e=!1){var r,o;if(!this.cache.has(t.$option))return;const a=this.cache.get(t.$option),n=t.$item;let i="selector";ot(t,"switch")&&(i="switch"),ot(t,"range")&&(i="range"),ot(t,"onClick")&&(i="button");const{icons:s,proxy:l,constructor:c}=this.art,p=N("div");C(p,"art-setting-item"),I(p,"height",`${c.SETTING_ITEM_HEIGHT}px`),p.dataset.name=t.name||"",p.dataset.value=t.value||"";const h=S(p,'
'),u=S(p,'
'),m=N("div");switch(C(m,"art-setting-item-left-icon"),i){case"button":case"switch":case"range":S(m,t.icon||s.config);break;case"selector":(null==(r=t.selector)?void 0:r.length)?S(m,t.icon||s.config):S(m,s.check)}S(h,m),et(t,"$icon",{configurable:!0,get:()=>m}),et(t,"icon",{configurable:!0,get:()=>m.innerHTML,set(t){m.innerHTML="",S(m,t)}});const f=N("div");C(f,"art-setting-item-left-text"),S(f,t.html||""),S(h,f),et(t,"$html",{configurable:!0,get:()=>f}),et(t,"html",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",S(f,t)}});const g=N("div");switch(C(g,"art-setting-item-right-tooltip"),S(g,t.tooltip||""),S(u,g),et(t,"$tooltip",{configurable:!0,get:()=>g}),et(t,"tooltip",{configurable:!0,get:()=>g.innerHTML,set(t){g.innerHTML="",S(g,t)}}),i){case"switch":{const e=N("div");C(e,"art-setting-item-right-icon");const r=S(e,s.switchOn),o=S(e,s.switchOff);I(t.switch?o:r,"display","none"),S(u,e),et(t,"$switch",{configurable:!0,get:()=>e});let a=t.switch;et(t,"switch",{configurable:!0,get:()=>a,set(t){a=t,t?(I(o,"display","none"),I(r,"display",null)):(I(o,"display",null),I(r,"display","none"))}});break}case"range":{const e=N("div");C(e,"art-setting-item-right-icon");const r=S(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],C(r,"art-setting-range"),S(u,e),et(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];et(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(null==(o=t.selector)?void 0:o.length){const t=N("div");C(t,"art-setting-item-right-icon"),S(t,s.arrowRight),S(u,t)}}switch(i){case"switch":if(t.onSwitch){const e=l(p,"click",e=>d(this,null,function*(){t.switch=yield t.onSwitch.call(this.art,t,p,e)}));t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=l(t.$range,"change",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onRange.call(this.art,t,p,e)}));t.$events.push(e)}if(t.onChange){const e=l(t.$range,"input",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onChange.call(this.art,t,p,e)}));t.$events.push(e)}}break;case"selector":{const e=l(p,"click",e=>d(this,null,function*(){var r;(null==(r=t.selector)?void 0:r.length)?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=yield t.$parent.onSelect.call(this.art,t,p,e)))}));t.$events.push(e),t.default&&C(p,"art-current")}break;case"button":if(t.onClick){const e=l(p,"click",e=>d(this,null,function*(){t.tooltip=yield t.onClick.call(this.art,t,p,e)}));t.$events.push(e)}}et(t,"$item",{configurable:!0,get:()=>p}),e?Y(p,n):S(a,p),t.mounted&&setTimeout(()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){var e;if(this.active=t,this.cache.has(t)){O(this.cache.get(t),"art-current")}else{const r=N("div");this.cache.set(t,r),C(r,"art-setting-panel"),S(this.$parent,r),O(r,"art-current"),(null==(e=t[0])?void 0:e.$parent)&&this.createHeader(t[0]);for(let e=0;enull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){var t,e;return null==(e=null==(t=this.art.template.$video)?void 0:t.textTracks)?void 0:e[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?P(r,t):I(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?tt(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}switch(t){return d(this,arguments,function*(t,e={}){const{i18n:r,notice:o,option:a}=this.art,n=c(l(l({},a.subtitle),e),{url:t}),i=yield this.init(n);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i})}createTrack(t,e){const{template:r,proxy:o,option:a}=this.art,{$video:n,$track:i}=r,s=N("track");s.default=!0,s.kind=t,s.src=e,s.label=a.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,M(i),S(n,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}init(t){return d(this,null,function*(){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(f(t,xt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||G(t.url)){case"srt":{const e=it(r);return st(t.onVttLoad(e))}case"ass":{const e=lt(r);return st(t.onVttLoad(e))}case"vtt":return st(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null})}}class ae{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=T(e.container),X(this.$container,`No container element found by ${e.container}`)),X(B(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();X("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),X(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=t.id,this.init()}static get html(){return`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${g}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `}query(t){return T(t,this.$container)}init(){const{option:t}=this.art;if(t.useSSR||(this.$container.innerHTML=ae.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);X(e instanceof HTMLVideoElement||e instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),Y(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&C(this.$player,"art-backdrop"),k&&C(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":C(this.$player,"art-destroy")}}class ne{on(t,e,r){const o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:r}),this}once(t,e,r){const o=this;function a(...n){o.off(t,a),e.apply(r,n)}return a._=e,this.on(t,a,r)}emit(t,...e){const r=((this.e||(this.e={}))[t]||[]).slice();for(let o=0;oe.call(this,this)),le.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${le.version}`);for(let e=0;et(`Event@${e.type}`))}se.push(this)}static get instances(){return se}static get version(){return g}static get config(){return v}static get utils(){return ht}static get scheme(){return xt}static get Emitter(){return ne}static get validator(){return f}static get kindOf(){return f.kindOf}static get html(){return ae.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:b?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:null==navigator?void 0:navigator.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){le.REMOVE_SRC_WHEN_DESTROY&&this.reset(),this.events.destroy(),this.template.destroy(t),se.splice(se.indexOf(this),1),this.isDestroy=!0,this.emit("destroy")}}return le.STYLE=re,le.DEBUG=!1,le.CONTEXTMENU=!0,le.NOTICE_TIME=2e3,le.SETTING_WIDTH=250,le.SETTING_ITEM_WIDTH=200,le.SETTING_ITEM_HEIGHT=35,le.RESIZE_TIME=200,le.SCROLL_TIME=200,le.SCROLL_GAP=50,le.AUTO_PLAYBACK_MAX=10,le.AUTO_PLAYBACK_MIN=5,le.AUTO_PLAYBACK_TIMEOUT=3e3,le.RECONNECT_TIME_MAX=5,le.RECONNECT_SLEEP_TIME=1e3,le.CONTROL_HIDE_TIME=3e3,le.DBCLICK_TIME=300,le.DBCLICK_FULLSCREEN=!0,le.MOBILE_DBCLICK_PLAY=!0,le.MOBILE_CLICK_PLAY=!1,le.AUTO_ORIENTATION_TIME=200,le.INFO_LOOP_TIME=1e3,le.FAST_FORWARD_VALUE=3,le.FAST_FORWARD_TIME=1e3,le.TOUCH_MOVE_RATIO=.5,le.VOLUME_STEP=.1,le.SEEK_STEP=5,le.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],le.ASPECT_RATIO=["default","4:3","16:9"],le.FLIP=["normal","horizontal","vertical"],le.FULLSCREEN_WEB_IN_BODY=!0,le.LOG_VERSION=!0,le.USE_RAF=!1,le.REMOVE_SRC_WHEN_DESTROY=!0,$&&(F("artplayer-style",re),setTimeout(()=>{le.LOG_VERSION&&console.log(`%c ArtPlayer %c ${le.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),le}); +!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";var t,e=Object.defineProperty,r=Object.defineProperties,o=Object.getOwnPropertyDescriptors,a=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(t,r,o)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[r]=o,l=(t,e)=>{for(var r in e||(e={}))n.call(e,r)&&s(t,r,e[r]);if(a)for(var r of a(e))i.call(e,r)&&s(t,r,e[r]);return t},c=(t,e)=>r(t,o(e)),d=(t,e,r)=>new Promise((o,a)=>{var n=t=>{try{s(r.next(t))}catch(e){a(e)}},i=t=>{try{s(r.throw(t))}catch(e){a(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(n,i);s((r=r.apply(t,e)).next())});function p(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var h,u={exports:{}};var m=(h||(h=1,u.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var a=t(r);if("boolean"===a)return"boolean";if("string"===a)return"string";if("number"===a)return"number";if("symbol"===a)return"symbol";if("function"===a)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(a=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return a.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function a(t,e){var o=2=1,k=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(y)||x,$="undefined"!==typeof window&&"undefined"!==typeof document;function T(t,e=document){return e.querySelector(t)}function E(t,e=document){return Array.from(e.querySelectorAll(t))}function C(t,e){return t.classList.add(e)}function z(t,e){return t.classList.remove(e)}function L(t,e){return t.classList.contains(e)}function S(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function M(t){return t.parentNode.removeChild(t)}function I(t,e,r){return t.style[e]=r,t}function P(t,e){for(const r in e)I(t,r,e[r]);return t}function A(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function O(t,e){A(t).forEach(t=>z(t,e)),C(t,e)}function R(t,e,r="top"){k||(t.setAttribute("aria-label",e),C(t,"hint--rounded"),C(t,`hint--${r}`))}function _(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,a=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=a+e&&r.left+r.width+e>=0;return n&&i}function V(t,e){return j(t).includes(e)}function Y(t,e){return e.parentNode.replaceChild(t,e),t}function N(t){return document.createElement(t)}function D(t="",e=""){const r=N("i");return C(r,"art-icon"),C(r,`art-icon-${t}`),S(r,e),r}function F(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function B(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function H(t){return t.getBoundingClientRect()}function W(t,e){return new Promise((r,o)=>{const a=new Image;a.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=a.width*e,n.height=a.height*e,i.drawImage(a,0,0,n.width,n.height),n.toBlob(e=>{const a=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(a),o(new Error(`Image load failed: ${t}`))},n.src=a})}else r(a)},a.onerror=function(){o(new Error(`Image load failed: ${t}`))},a.src=t})}function j(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function U(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class q extends Error{constructor(t,e){super(t),"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function X(t,e){if(!t)throw new q(e);return t}function G(t){return t.includes("?")?G(t.split("?")[0]):t.includes("#")?G(t.split("#")[0]):t.trim().toLowerCase().split(".").pop()}function K(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r)}function Z(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function J(t){return t.charAt(0).toUpperCase()+t.slice(1)}function Q(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}function tt(t){return t.replace(/[&<>'"]/g,t=>({"&":"&","<":"<",">":">","'":"'",'"':"""}[t]||t))}const et=Object.defineProperty,{hasOwnProperty:rt}=Object.prototype;function ot(t,e){return rt.call(t,e)}function at(t,e){return Object.getOwnPropertyDescriptor(t,e)}function nt(...t){const e=t=>t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const a=t[o],n=r[o];Array.isArray(a)&&Array.isArray(n)?t[o]=a.concat(...n):e(a)&&e(n)?t[o]=nt(a,n):t[o]=n}),t),{})}function it(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function st(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function lt(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);return o?{start:r(o[1].trim()),end:r(o[2].trim()),text:o[5].replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}:null}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function ct(t=0){return new Promise(e=>setTimeout(e,t))}function dt(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=null,t.apply(this,o)),e)}}function pt(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const ht=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:q,addClass:C,append:S,assToVtt:lt,capitalize:J,clamp:Z,createElement:N,debounce:dt,def:et,download:K,errorHandle:X,escape:tt,get:at,getComposedPath:j,getExt:G,getIcon:D,getRect:H,getSafeAreaInsets:U,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:ot,hasClass:L,includeFromEvent:V,inverseClass:O,isBrowser:$,isIOS:w,isIOS13:x,isInViewport:_,isMobile:k,isSafari:b,loadImg:W,mergeDeep:nt,query:T,queryAll:E,remove:M,removeClass:z,replaceElement:Y,secondToTime:Q,setStyle:I,setStyleText:F,setStyles:P,siblings:A,sleep:ct,srtToVtt:it,supportsFlex:B,throttle:pt,tooltip:R,unescape:function(t){const e={"&":"&","<":"<",">":">","'":"'",""":'"'},r=new RegExp(`(${Object.keys(e).join("|")})`,"g");return t.replace(r,t=>e[t]||t)},userAgent:y,vttToBlob:st},Symbol.toStringTag,{value:"Module"})),ut="array",mt="boolean",ft="string",gt="number",vt="object",yt="function";function bt(t,e,r){return X(e===ft||e===gt||t instanceof Element,`${r.join(".")} require '${ft}' or 'Element' type`)}const wt={html:bt,disable:`?${mt}`,name:`?${ft}`,index:`?${gt}`,style:`?${vt}`,click:`?${yt}`,mounted:`?${yt}`,tooltip:`?${ft}|${gt}`,width:`?${gt}`,selector:`?${ut}`,onSelect:`?${yt}`,switch:`?${mt}`,onSwitch:`?${yt}`,range:`?${ut}`,onRange:`?${yt}`,onChange:`?${yt}`},xt={id:ft,container:bt,url:ft,poster:ft,type:ft,theme:ft,lang:ft,volume:gt,isLive:mt,muted:mt,autoplay:mt,autoSize:mt,autoMini:mt,loop:mt,flip:mt,playbackRate:mt,aspectRatio:mt,screenshot:mt,setting:mt,hotkey:mt,pip:mt,mutex:mt,backdrop:mt,fullscreen:mt,fullscreenWeb:mt,subtitleOffset:mt,miniProgressBar:mt,useSSR:mt,playsInline:mt,lock:mt,gesture:mt,fastForward:mt,autoPlayback:mt,autoOrientation:mt,airplay:mt,proxy:`?${yt}`,plugins:[yt],layers:[wt],contextmenu:[wt],settings:[wt],controls:[c(l({},wt),{position:(t,e,r)=>{const o=["top","left","right"];return X(o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}})],quality:[{default:`?${mt}`,html:ft,url:ft}],highlight:[{time:gt,text:ft}],thumbnails:{url:ft,number:gt,column:gt,width:gt,height:gt,scale:gt},subtitle:{url:ft,name:ft,type:ft,style:vt,escape:mt,encoding:ft,onVttLoad:yt},moreVideoAttr:vt,i18n:vt,icons:vt,cssVar:vt,customType:vt};class kt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return L(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?C(e,r):z(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",f(e,wt),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;X(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const o=N("div");C(o,`art-${this.name}`),C(o,`art-${this.name}-${r}`);const a=Array.from(this.$parent.children);o.dataset.index=e.index||this.id;const n=a.find(t=>Number(t.dataset.index)>=Number(o.dataset.index));n?n.insertAdjacentElement("beforebegin",o):S(this.$parent,o),e.html&&S(o,e.html),e.style&&P(o,e.style),e.tooltip&&R(o,e.tooltip);const i=[];if(e.click){const t=this.art.events.proxy(o,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});i.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,o,i),this[r]=o,this.cache.set(r,{$ref:o,events:i,option:e}),e.mounted&&e.mounted.call(this.art,o),o}remove(t){X(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],M(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class $t extends kt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,k||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:o}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,a=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return c(l({},t),{html:`${r.get("Play Speed")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const r=T('[data-value="1"]',t);r&&O(r,"art-current"),e.on("video:ratechange",()=>{const r=E("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&O(r,"art-current")})}})}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,a=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return c(l({},t),{html:`${r.get("Aspect Ratio")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const r=T('[data-value="default"]',t);r&&O(r,"art-current"),e.on("aspectRatio",e=>{const r=E("span",t).find(t=>t.dataset.value===e);r&&O(r,"art-current")})}})}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,a=o.map(t=>`${r.get(J(t))}`).join("");return c(l({},t),{html:`${r.get("Video Flip")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const r=T('[data-value="normal"]',t);r&&O(r,"art-current"),e.on("flip",e=>{const r=E("span",t).find(t=>t.dataset.value===e);r&&O(r,"art-current")})}})}}({name:"flip",index:30})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){const e=$?location.href:"";return c(l({},t),{html:`ArtPlayer ${g}`})}({name:"version",index:50})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,a=t.clientY,{height:n,width:i,left:s,top:l}=H(r),{height:c,width:d}=H(o);let p=e-s,h=a-l;e+d>s+i&&(p=i-d),a+c>l+n&&(h=n-c),P(o,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{V(t,o)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}function Tt(t,e){const{$progress:r}=t.template,{left:o}=H(r),a=Z((k?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),n=a/r.clientWidth*t.duration;return{second:n,time:Q(n),width:a,percentage:Z(a/r.clientWidth,0,1)}}function Et(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=Tt(t,e);t.emit("setBar","played",o,e),t.seek=r}}function Ct(t){return e=>{const{icons:r,option:o,proxy:a}=e,{$player:n,$progress:i}=e.template;return c(l({},t),{html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=T(".art-progress-hover",t),d=T(".art-progress-loaded",t),p=T(".art-progress-played",t),h=T(".art-progress-highlight",t),u=T(".art-progress-indicator",t),m=T(".art-progress-tip",t);function f(r,o){const{width:a,time:n}=o||Tt(e,r);m.textContent=n||"00:00";const i=m.clientWidth;a<=i/2?I(m,"left",0):a>t.clientWidth-i/2?I(m,"left",t.clientWidth-i+"px"):I(m,"left",a-i/2+"px")}r.indicator?S(u,r.indicator):I(u,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,o,a){const i="played"===r&&a&&k;if("loaded"===r&&I(d,"width",100*o+"%"),"hover"===r&&(I(c,"width",100*o+"%"),V(a,h)?function(r){const{width:o}=Tt(e,r),{text:a}=r.target.dataset;m.textContent=a;const n=m.clientWidth;o<=n/2?I(m,"left",0):o>t.clientWidth-n/2?I(m,"left",t.clientWidth-n+"px"):I(m,"left",o-n/2+"px")}(a):f(a),0===o?z(n,"art-progress-hover"):C(n,"art-progress-hover")),"played"===r&&(I(p,"width",100*o+"%"),I(u,"left",100*o+"%")),i){C(n,"art-progress-hover");f(a,{width:t.clientWidth*o,time:Q(o*e.duration)}),clearTimeout(s),s=setTimeout(()=>{z(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){h.textContent="";for(let t=0;t`;S(h,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),k||(a(i,"click",t=>{t.target!==u&&Et(e,t)}),a(i,"mousemove",t=>{const{percentage:r}=Tt(e,t);e.emit("setBar","hover",r,t)}),a(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),a(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:o}=Tt(e,t);e.emit("setBar","played",o,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}})}}class zt extends kt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;t.on("mousemove",()=>{k||(this.show=!0)}),t.on("click",()=>{k?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=V(t,o)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(z(r,"art-hide-cursor"),C(r,"art-hover"),this.timer=Date.now()):(C(r,"art-hide-cursor"),z(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(Ct({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.play),i=S(t,o.pause);function s(){I(n,"display","flex"),I(i,"display","none")}function l(){I(n,"display","none"),I(i,"display","flex")}R(n,a.get("Play")),R(i,a.get("Pause")),r(n,"click",()=>{e.play()}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o}=e,a=S(t,o.volume),n=S(t,o.volumeClose),i=S(t,'
'),s=S(i,'
'),l=S(s,'
'),c=S(s,'
'),d=S(c,'
'),p=S(d,'
'),h=S(c,'
');function u(t){const{top:e,height:r}=H(c);return 1-(t.clientY-e)/r}function m(){if(e.muted||0===e.volume)I(a,"display","none"),I(n,"display","flex"),I(h,"top","100%"),I(p,"top","100%"),l.textContent=0;else{const t=100*e.volume;I(a,"display","flex"),I(n,"display","none"),I(h,"top",100-t+"%"),I(p,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(m(),e.on("video:volumechange",m),r(a,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),k)I(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=u(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=u(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>c(l({},t),{style:k?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${Q(e.currentTime)} / ${Q(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const o=["video:loadedmetadata","video:timeupdate","video:progress"];for(let a=0;a{this.art.quality=t.quality}),t.screenshot&&!k&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:o}=e;S(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;S(t,o.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{R(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;S(t,o.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{R(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:o}=e;S(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.fullscreenWebOn),i=S(t,o.fullscreenWebOff);I(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(R(t,a.get("Exit Web Fullscreen")),I(n,"display","none"),I(i,"display","inline-flex")):(R(t,a.get("Web Fullscreen")),I(n,"display","inline-flex"),I(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.fullscreenOn),i=S(t,o.fullscreenOff);I(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(R(t,a.get("Exit Fullscreen")),I(n,"display","none"),I(i,"display","inline-flex")):(R(t,a.get("Fullscreen")),I(n,"display","inline-flex"),I(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),et(e,"$control_item",{get:()=>r}),et(e,"$control_value",{get:()=>a})}const i=o(n,"click",e=>d(this,null,function*(){const r=j(e),o=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(o),t.onSelect&&(a.innerHTML=yield t.onSelect.call(this.art,o,o.$control_item,e))}));r.push(i)}}function Lt(t,e,r,o){const a=e-o,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(a)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,a);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}class St{constructor(t){this.destroyEvents=new Set,this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:a}}=t;function n(e){V(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(a,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:a,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=n);switch(c.length){case 1:t.emit("click",e),k?!t.isLock&&a&&t.toggle():t.toggle(),i=c;break;case 2:t.emit("dblclick",e),k?!t.isLock&&s&&t.toggle():l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{C(r,"art-hover"),t.emit("hover",!0,e)},e=>{z(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const a=dt(()=>t.emit("resize"),o.RESIZE_TIME);t.on("window:orientationchange",()=>a()),t.on("window:resize",()=>a()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>a())}(t,this),function(t,e){if(k&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let a=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){a===o&&Et(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:o,pageY:n}=e.touches[0],c=Lt(i,s,o,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=Z((o-i)/t.width,-1,1),d=Z((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=a===r?t.constructor.TOUCH_MOVE_RATIO:1,u=Z(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",Z(u/t.duration,0,1),e),t.notice.show=`${Q(u)} / ${Q(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,a=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{a=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{a=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,a=pt(()=>{t.emit("view",_(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>a()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],a=[];function n(n={}){for(let t=0;t{const o=n.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});a.push(s)}),o.forEach(r=>{var o;const s=n.window||(null==(o=i.ownerDocument)?void 0:o.defaultView)||window,l=e.proxy(s,r,e=>{t.emit(`window:${r}`,e)});a.push(l)})}n(),e.bindGlobalEvents=n}(t,this),function(t){if(t.constructor.USE_RAF){let e=null;!function r(){t.playing&&t.emit("raf"),t.isDestroy||(e=requestAnimationFrame(r))}(),t.on("destroy",()=>{cancelAnimationFrame(e)})}}(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));t.addEventListener(e,r,o);const a=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(a),a}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class Mt{constructor(t){this.art=t,this.keys={},k||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{this.art.toggle()}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',state:'\n\n\n',play:'\n \n',pause:'\n \n',check:'\n\n',volume:'\n \n \n',volumeClose:'\n \n \n',screenshot:'\n\t\n\n',setting:'\n \n \n',pip:'\n\n',arrowLeft:'\n \n',arrowRight:'\n \n',playbackRate:'',aspectRatio:'',config:'',lock:'\n\n\n\n\n',flip:'\n\n\n\n\n\n',unlock:'\n\n\n',fullscreenOff:'\n\n\n\n\n',fullscreenOn:'\n\n\n\n\n',fullscreenWebOff:'\n\n\n\n\n',fullscreenWebOn:'\n\n\n\n\n',switchOn:'\n\n\n \n',switchOff:'\n\n\n \n\n',error:'\n\n\n\n\n',close:'\n\n\n\n\n',airplay:'\n \n \n \n \n\n'},t.option.icons);for(const r in e)et(this,r,{get:()=>D(r,e[r])})}}class Ot extends kt{constructor(t){super(t),this.name="info",k||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:a}}=this.art;t(o,"click",()=>{this.show=!1});let n=null;const i=E("[data-video]",r)||[];this.art.on("destroy",()=>clearTimeout(n)),function t(){for(let e=0;e{I(a,"display","none"),I(n,"display",null)}),o.proxy(e.$state,"click",()=>t.play())}}class Yt{constructor(t){this.art=t,this.timer=null,t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,C(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",z(r,"art-notice-show")},e.NOTICE_TIME)):z(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}const Nt=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],Dt=(()=>{if("undefined"===typeof document)return!1;const t=Nt[0],e={};for(const r of Nt){if(r[1]in document){for(const[o,a]of r.entries())e[t[o]]=a;return e}}return!1})(),Ft={change:Dt.fullscreenchange,error:Dt.fullscreenerror},Bt={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const a=()=>{Bt.off("change",a),r()};Bt.on("change",a);const n=t[Dt.requestFullscreen](e);n instanceof Promise&&n.then(a).catch(o)}),exit:()=>new Promise((t,e)=>{if(!Bt.isFullscreen)return void t();const r=()=>{Bt.off("change",r),t()};Bt.on("change",r);const o=document[Dt.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>Bt.isFullscreen?Bt.exit():Bt.request(t,e),onchange(t){Bt.on("change",t)},onerror(t){Bt.on("error",t)},on(t,e){const r=Ft[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Ft[t];r&&document.removeEventListener(r,e,!1)},raw:Dt};function Ht(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t,n=t=>{Bt.on("change",()=>{t.emit("fullscreen",Bt.isFullscreen),Bt.isFullscreen?(t.state="fullscreen",C(a,"art-fullscreen")):z(a,"art-fullscreen"),t.emit("resize")}),Bt.on("error",e=>{t.emit("fullscreenError",e)}),et(t,"fullscreen",{get:()=>Bt.isFullscreen,set(t){return d(this,null,function*(){t?yield Bt.request(a):yield Bt.exit()})}})};t.once("video:loadedmetadata",()=>{var a;Bt.isEnabled?n(t):o.webkitSupportsFullscreen?((a=t).on("document:webkitfullscreenchange",()=>{a.emit("fullscreen",a.fullscreen),a.emit("resize")}),et(a,"fullscreen",{get:()=>document.fullscreenElement===o,set(t){t?(a.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})):et(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),et(t,"fullscreen",at(t,"fullscreen"))})}function Wt(t){const{icons:e,proxy:r,storage:o,template:{$player:a,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(z(a,"art-mini"),I(e,"display","none"),a.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(I(e,"display","none"),I(r,"display","flex")):(I(e,"display","flex"),I(r,"display","none"))}function p(){const{$mini:e}=t.template,r=H(e),a=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;o.set("top",a),o.set("left",n),I(e,"top",`${a}px`),I(e,"left",`${n}px`)}et(t,"mini",{get:()=>L(a,"art-mini"),set(h){if(h){t.state="mini",C(a,"art-mini");const h=function(){const{$mini:a}=t.template;if(a)return S(a,n),I(a,"display","flex");{const a=N("div");C(a,"art-mini-popup"),S(document.body,a),t.template.$mini=a,S(a,n);const p=S(a,'
');S(p,e.close),r(p,"click",c);const h=S(a,'
'),u=S(h,e.play),m=S(h,e.pause);return r(u,"click",()=>t.play()),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(a,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){C(a,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;I(a,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,z(a,"art-mini-dragging");const t=H(a);o.set("left",t.left),o.set("top",t.top),I(a,"left",`${t.left}px`),I(a,"top",`${t.top}px`),I(a,"transform",null)}}),a}}(),u=o.get("top"),m=o.get("left");"number"===typeof u&&"number"===typeof m?(I(h,"top",`${u}px`),I(h,"left",`${m}px`),_(h)||p()):p(),t.emit("mini",!0)}else c()}})}function jt(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,et(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),et(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):et(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ut(t){const{option:e,template:{$progress:r,$video:o}}=t;let a=null,n=!1,i=null;t.on("setBar",(a,s,l)=>d(null,null,function*(){var c;const d=null==(c=t.controls)?void 0:c.thumbnails,{url:p,scale:h}=e.thumbnails;if(!d||!p)return;if("hover"===a||"played"===a&&l&&k){if(i||n||(n=!0,i=yield W(p,h),n=!1),!i)return;const a=r.clientWidth*s;a>0&&ar.clientWidth-u/2?I(s,"left",r.clientWidth-u+"px"):I(s,"left",a-u/2+"px")}(a)}})),et(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(a),a=null,n=!1,i=null)}})}Object.defineProperties(Bt,{isFullscreen:{get:()=>Boolean(document[Dt.fullscreenElement])},element:{enumerable:!0,get:()=>document[Dt.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[Dt.fullscreenEnabled])}});class qt{constructor(t){!function(t){const{option:e,template:{$video:r}}=t;et(t,"url",{get:()=>r.src,set(o){return d(this,null,function*(){if(o){const a=t.url,n=e.type||G(o),i=e.customType[n];n&&i?(yield ct(),t.loading.show=!0,i.call(t,r,o,t)):(URL.revokeObjectURL(a),r.src=o),a!==t.url&&(t.option.url=o,t.isReady&&a&&t.once("video:canplay",()=>{t.emit("restart",o)}))}else yield ct(),t.loading.show=!0})}})}(t),function(t){const{template:{$video:e}}=t;et(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:a},template:{$video:n}}=t;et(t,"play",{value(){return d(this,null,function*(){const i=yield n.play();if(r.show=e.get("Play"),t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;et(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${Q(t.currentTime)} / ${Q(t.duration)}`),t.emit("seek",t.currentTime,r)}}),et(t,"forward",{set(e){t.seek=t.currentTime+e}}),et(t,"backward",{set(e){t.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:a}=t;et(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=Z(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(100*e.volume,10)}`,0!==e.volume&&a.set("volume",e.volume)}}),et(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;et(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{r=Number.parseFloat(r),Number.isNaN(r)||(e.currentTime=Z(r,0,t.duration))}})}(t),function(t){et(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){function e(e,r){return new Promise((o,a)=>{if(e===t.url)return void o();const{playing:n,aspectRatio:i,playbackRate:s}=t;t.pause(),t.url=e,t.notice.show="";const l={error:e=>{t.off("video:canplay",l.canplay),t.off("video:loadedmetadata",l.metadata),a(e)},metadata:()=>{t.currentTime=r},canplay:()=>d(null,null,function*(){t.off("video:error",l.error),t.playbackRate=s,t.aspectRatio=i,n&&(yield t.play()),t.notice.show="",o()})};t.once("video:error",l.error),t.once("video:loadedmetadata",l.metadata),t.once("video:canplay",l.canplay)})}et(t,"switchQuality",{value:r=>e(r,t.currentTime)}),et(t,"switchUrl",{value:t=>e(t,0)}),et(t,"switch",{set:t.switchUrl})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t;et(t,"playbackRate",{get:()=>e.playbackRate,set(a){if(a){if(a===e.playbackRate)return;e.playbackRate=a,o.show=`${r.get("Rate")}: ${1===a?r.get("Normal"):`${a}x`}`}else t.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t;et(t,"aspectRatio",{get:()=>a.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)I(o,"width",null),I(o,"height",null),I(o,"margin",null),delete a.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=a,i=e/r,s=t[0]/t[1];i>s?(I(o,"width",s*r+"px"),I(o,"height","100%"),I(o,"margin","0 auto")):(I(o,"width","100%"),I(o,"height",e/s+"px"),I(o,"margin","auto 0")),a.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=N("canvas");et(t,"getDataURL",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(n){e.show=n,a(n)}})}),et(t,"getBlobUrl",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,a(n)}})}),et(t,"screenshot",{value:e=>d(null,null,function*(){const o=yield t.getDataURL();return K(o,`${e||`artplayer_${Q(r.currentTime)}`}.png`),t.emit("screenshot",o),o})})}(t),Ht(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let a="";et(t,"fullscreenWeb",{get:()=>L(o,"art-fullscreen-web"),set(n){n?(a=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&S(document.body,o),t.state="fullscreenWeb",I(o,"width","100%"),I(o,"height","100%"),C(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&S(r,o),a&&(o.style.cssText=a,a=""),z(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),jt(t),function(t){const{$video:e}=t.template;et(t,"loaded",{get:()=>t.loadedTime/e.duration}),et(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){et(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;et(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;et(t,"autoSize",{value(){const{videoWidth:a,videoHeight:n}=o,{width:i,height:s}=H(e),l=a/n;if(i/s>l)I(r,"width",s*l/i*100+"%"),I(r,"height","100%");else{const t=i/l/s*100;I(r,"width","100%"),I(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){et(t,"rect",{get:()=>H(t.template.$player)});const e=["bottom","height","left","right","top","width"];for(let r=0;rt.rect[o]})}et(t,"x",{get:()=>t.left+window.pageXOffset}),et(t,"y",{get:()=>t.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;et(t,"flip",{get:()=>e.dataset.flip||"normal",set(a){a||(a="normal"),"normal"===a?delete e.dataset.flip:e.dataset.flip=a,o.show=`${r.get("Video Flip")}: ${r.get(J(a))}`,t.emit("flip",a)}})}(t),Wt(t),function(t){const{template:{$poster:e}}=t;et(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch(t){return""}},set(t){I(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;et(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:a,videoWidth:n}=r,i=a*(o/n);I(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;et(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){et(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){et(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];et(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;o{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,et(t,"airplay",{value(){n?(a.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){et(t,"quality",{set(e){const{controls:r,notice:o,i18n:a}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:(null==n?void 0:n.html)||"",selector:e,onSelect(e){return d(this,null,function*(){return yield t.switchQuality(e.url),o.show=`${a.get("Switch Video")}: ${e.html}`,e.html})}})}})}(t),Ut(t),function(t){const{i18n:e,notice:r,option:o,constructor:a,proxy:n,template:{$player:i,$video:s,$poster:l}}=t;let c=0;for(let d=0;d{t.emit(`video:${e.type}`,e)});t.on("video:canplay",()=>{c=0,t.loading.show=!1}),t.once("video:canplay",()=>{t.loading.show=!1,t.controls.show=!0,t.mask.show=!0,t.isReady=!0,t.emit("ready")}),t.on("video:ended",()=>{o.loop?(t.seek=0,t.play(),t.controls.show=!1,t.mask.show=!1):(t.controls.show=!0,t.mask.show=!0)}),t.on("video:error",n=>d(null,null,function*(){c{t.emit("resize"),k&&(t.loading.show=!1,t.controls.show=!0,t.mask.show=!0)}),t.on("video:loadstart",()=>{t.loading.show=!0,t.mask.show=!1,t.controls.show=!0}),t.on("video:pause",()=>{t.controls.show=!0,t.mask.show=!0}),t.on("video:play",()=>{t.mask.show=!1,I(l,"display","none")}),t.on("video:playing",()=>{t.mask.show=!1}),t.on("video:progress",()=>{t.playing&&(t.loading.show=!1)}),t.on("video:seeked",()=>{t.loading.show=!1,t.mask.show=!0}),t.on("video:seeking",()=>{t.loading.show=!0,t.mask.show=!1}),t.on("video:timeupdate",()=>{t.mask.show=!1}),t.on("video:waiting",()=>{t.loading.show=!0,t.mask.show=!1})}(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:a}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=Z(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(o.volume=Z(n,0,1)),e.poster&&I(a,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Xt(t){const{notice:e,constructor:r,template:{$player:o,$video:a}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=a,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{var a;if(e){if(l()){const e=Number(null!=(a=r.AUTO_ORIENTATION_TIME)?a:0);setTimeout(()=>{t.fullscreenWeb&&!L(o,n)&&function(){const e=U(),r=document.documentElement.clientWidth,a=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;I(o,"width",`${a}px`),I(o,"height",`${i}px`),I(o,"transform-origin","0 0"),I(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),C(o,n),t.isRotate=!0,t.emit("resize")}()},e)}}else L(o,n)&&(I(o,"width",""),I(o,"height",""),I(o,"transform-origin",""),I(o,"transform",""),z(o,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",t=>d(null,null,function*(){var r;const a=!!(null==(r=null==screen?void 0:screen.orientation)?void 0:r.lock);if(t){if(a&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";yield screen.orientation.lock(t),s=!0,C(o,i)}catch(n){s=!1,e.show=n}}else if(L(o,i)&&z(o,i),a&&s){try{screen.orientation.unlock()}catch(c){}s=!1}})),{name:"autoOrientation",get state(){return L(o,n)}}}function Gt(t){const{i18n:e,icons:r,storage:o,constructor:a,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=T(".art-auto-playback-last",s),c=T(".art-auto-playback-jump",s),d=T(".art-auto-playback-close",s);S(d,r.close);let p=null;function h(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),I(s,"display","none"),r&&r>=a.AUTO_PLAYBACK_MIN&&(I(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${Q(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{I(s,"display","none")}),n(c,"click",()=>{t.seek=r,t.play(),I(i,"display","none"),I(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{I(s,"display","none")},a.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>a.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function Kt(t){const{constructor:e,proxy:r,template:{$player:o,$video:a}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,z(o,"art-fast-forward"))};return r(a,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,C(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return L(o,"art-fast-forward")}}}function Zt(t){const{layers:e,icons:r,template:{$player:o}}=t;function a(){return L(o,"art-lock")}function n(){C(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){z(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=S(e,r.lock),a=S(e,r.unlock);I(o,"display","none"),t.on("lock",t=>{t?(I(o,"display","inline-flex"),I(a,"display","none")):(I(o,"display","none"),I(a,"display","inline-flex"))})},click(){a()?i():n()}}),{name:"lock",get state(){return a()},set state(t){t?n():i()}}}function Jt(t){return t.on("control",e=>{e?z(t.template.$player,"art-mini-progress-bar"):C(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Qt{constructor(t){this.art=t,this.id=0;const{option:e}=t;e.miniProgressBar&&!e.isLive&&this.add(Jt),e.lock&&k&&this.add(Zt),e.autoPlayback&&!e.isLive&&this.add(Gt),e.autoOrientation&&k&&this.add(Xt),e.fastForward&&k&&!e.isLive&&this.add(Kt);for(let r=0;rthis.next(t,e)):this.next(t,e)}next(t,e){const r=e&&e.name||t.name||`plugin${this.id}`;return X(!ot(this,r),`Cannot add a plugin that already has the same name: ${r}`),et(this,r,{value:e}),this}}class te extends kt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=V(t,r.setting),o=V(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:a}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:a.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:a}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:a.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:a}}=t;function n(t){return e.get(J(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:a.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){var r;for(let o=0;o{e.default=e===t,e.default&&e.$item&&O(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let a=0;ae}),et(n,"$parents",{get:()=>r}),et(n,"$option",{get:()=>t});const o=[];et(n,"$events",{get:()=>o}),et(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){var t,e;const{controls:r,constructor:{SETTING_WIDTH:o,SETTING_ITEM_HEIGHT:a},template:{$player:n,$setting:i}}=this.art;if(r.setting&&this.show){const s=(null==(e=null==(t=this.active[0])?void 0:t.$parent)?void 0:e.width)||o,{left:l,width:c}=H(r.setting),{left:d,width:p}=H(n),h=l-d+c/2-s/2;if(I(i,"height",`${this.active===this.option?this.active.length*a:(this.active.length+1)*a}px`),I(i,"width",`${s}px`),this.art.isRotate||k)return;h+s>p?(I(i,"left",null),I(i,"right",null)):(I(i,"left",`${h}px`),I(i,"right","auto"))}}inactivate(t){for(let e=0;e'),s=N("div");C(s,"art-setting-item-left-icon"),S(s,o),S(i,s),S(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),S(e,n)}createItem(t,e=!1){var r,o;if(!this.cache.has(t.$option))return;const a=this.cache.get(t.$option),n=t.$item;let i="selector";ot(t,"switch")&&(i="switch"),ot(t,"range")&&(i="range"),ot(t,"onClick")&&(i="button");const{icons:s,proxy:l,constructor:c}=this.art,p=N("div");C(p,"art-setting-item"),I(p,"height",`${c.SETTING_ITEM_HEIGHT}px`),p.dataset.name=t.name||"",p.dataset.value=t.value||"";const h=S(p,'
'),u=S(p,'
'),m=N("div");switch(C(m,"art-setting-item-left-icon"),i){case"button":case"switch":case"range":S(m,t.icon||s.config);break;case"selector":(null==(r=t.selector)?void 0:r.length)?S(m,t.icon||s.config):S(m,s.check)}S(h,m),et(t,"$icon",{configurable:!0,get:()=>m}),et(t,"icon",{configurable:!0,get:()=>m.innerHTML,set(t){m.innerHTML="",S(m,t)}});const f=N("div");C(f,"art-setting-item-left-text"),S(f,t.html||""),S(h,f),et(t,"$html",{configurable:!0,get:()=>f}),et(t,"html",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",S(f,t)}});const g=N("div");switch(C(g,"art-setting-item-right-tooltip"),S(g,t.tooltip||""),S(u,g),et(t,"$tooltip",{configurable:!0,get:()=>g}),et(t,"tooltip",{configurable:!0,get:()=>g.innerHTML,set(t){g.innerHTML="",S(g,t)}}),i){case"switch":{const e=N("div");C(e,"art-setting-item-right-icon");const r=S(e,s.switchOn),o=S(e,s.switchOff);I(t.switch?o:r,"display","none"),S(u,e),et(t,"$switch",{configurable:!0,get:()=>e});let a=t.switch;et(t,"switch",{configurable:!0,get:()=>a,set(t){a=t,t?(I(o,"display","none"),I(r,"display",null)):(I(o,"display",null),I(r,"display","none"))}});break}case"range":{const e=N("div");C(e,"art-setting-item-right-icon");const r=S(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],C(r,"art-setting-range"),S(u,e),et(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];et(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(null==(o=t.selector)?void 0:o.length){const t=N("div");C(t,"art-setting-item-right-icon"),S(t,s.arrowRight),S(u,t)}}switch(i){case"switch":if(t.onSwitch){const e=l(p,"click",e=>d(this,null,function*(){t.switch=yield t.onSwitch.call(this.art,t,p,e)}));t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=l(t.$range,"change",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onRange.call(this.art,t,p,e)}));t.$events.push(e)}if(t.onChange){const e=l(t.$range,"input",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onChange.call(this.art,t,p,e)}));t.$events.push(e)}}break;case"selector":{const e=l(p,"click",e=>d(this,null,function*(){var r;(null==(r=t.selector)?void 0:r.length)?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=yield t.$parent.onSelect.call(this.art,t,p,e)))}));t.$events.push(e),t.default&&C(p,"art-current")}break;case"button":if(t.onClick){const e=l(p,"click",e=>d(this,null,function*(){t.tooltip=yield t.onClick.call(this.art,t,p,e)}));t.$events.push(e)}}et(t,"$item",{configurable:!0,get:()=>p}),e?Y(p,n):S(a,p),t.mounted&&setTimeout(()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){var e;if(this.active=t,this.cache.has(t)){O(this.cache.get(t),"art-current")}else{const r=N("div");this.cache.set(t,r),C(r,"art-setting-panel"),S(this.$parent,r),O(r,"art-current"),(null==(e=t[0])?void 0:e.$parent)&&this.createHeader(t[0]);for(let e=0;enull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){var t,e;return null==(e=null==(t=this.art.template.$video)?void 0:t.textTracks)?void 0:e[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?P(r,t):I(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?tt(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}switch(t){return d(this,arguments,function*(t,e={}){const{i18n:r,notice:o,option:a}=this.art,n=c(l(l({},a.subtitle),e),{url:t}),i=yield this.init(n);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i})}createTrack(t,e){const{template:r,proxy:o,option:a}=this.art,{$video:n,$track:i}=r,s=N("track");s.default=!0,s.kind=t,s.src=e,s.label=a.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,M(i),S(n,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}init(t){return d(this,null,function*(){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(f(t,xt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||G(t.url)){case"srt":{const e=it(r);return st(t.onVttLoad(e))}case"ass":{const e=lt(r);return st(t.onVttLoad(e))}case"vtt":return st(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null})}}class ae{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=T(e.container),X(this.$container,`No container element found by ${e.container}`)),X(B(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();X("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),X(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=t.id,this.init()}static get html(){return`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${g}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `}query(t){return T(t,this.$container)}init(){const{option:t}=this.art;if(t.useSSR||(this.$container.innerHTML=ae.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);X(e instanceof HTMLVideoElement||e instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),Y(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&C(this.$player,"art-backdrop"),k&&C(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":C(this.$player,"art-destroy")}}class ne{on(t,e,r){const o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:r}),this}once(t,e,r){const o=this;function a(...n){o.off(t,a),e.apply(r,n)}return a._=e,this.on(t,a,r)}emit(t,...e){const r=((this.e||(this.e={}))[t]||[]).slice();for(let o=0;oe.call(this,this)),le.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${le.version}`);for(let e=0;et(`Event@${e.type}`))}se.push(this)}static get instances(){return se}static get version(){return g}static get config(){return v}static get utils(){return ht}static get scheme(){return xt}static get Emitter(){return ne}static get validator(){return f}static get kindOf(){return f.kindOf}static get html(){return ae.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:b?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:null==navigator?void 0:navigator.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){le.REMOVE_SRC_WHEN_DESTROY&&this.reset(),this.events.destroy(),this.template.destroy(t),se.splice(se.indexOf(this),1),this.isDestroy=!0,this.emit("destroy")}}return le.STYLE=re,le.DEBUG=!1,le.CONTEXTMENU=!0,le.NOTICE_TIME=2e3,le.SETTING_WIDTH=250,le.SETTING_ITEM_WIDTH=200,le.SETTING_ITEM_HEIGHT=35,le.RESIZE_TIME=200,le.SCROLL_TIME=200,le.SCROLL_GAP=50,le.AUTO_PLAYBACK_MAX=10,le.AUTO_PLAYBACK_MIN=5,le.AUTO_PLAYBACK_TIMEOUT=3e3,le.RECONNECT_TIME_MAX=5,le.RECONNECT_SLEEP_TIME=1e3,le.CONTROL_HIDE_TIME=3e3,le.DBCLICK_TIME=300,le.DBCLICK_FULLSCREEN=!0,le.MOBILE_DBCLICK_PLAY=!0,le.MOBILE_CLICK_PLAY=!1,le.AUTO_ORIENTATION_TIME=200,le.INFO_LOOP_TIME=1e3,le.FAST_FORWARD_VALUE=3,le.FAST_FORWARD_TIME=1e3,le.TOUCH_MOVE_RATIO=.5,le.VOLUME_STEP=.1,le.SEEK_STEP=5,le.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],le.ASPECT_RATIO=["default","4:3","16:9"],le.FLIP=["normal","horizontal","vertical"],le.FULLSCREEN_WEB_IN_BODY=!0,le.LOG_VERSION=!0,le.USE_RAF=!1,le.REMOVE_SRC_WHEN_DESTROY=!0,$&&(F("artplayer-style",re),setTimeout(()=>{le.LOG_VERSION&&console.log(`%c ArtPlayer %c ${le.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),le}); diff --git a/docs/compiled/artplayer.mjs b/docs/compiled/artplayer.mjs index 49f7546c5..a9c2bac69 100644 --- a/docs/compiled/artplayer.mjs +++ b/docs/compiled/artplayer.mjs @@ -1205,7 +1205,7 @@ function getPosFromEvent(art, event) { } function setCurrentTime(art, event) { if (art.isRotate) { - const percentage = event.touches[0].clientY / art.height; + const percentage = (event.touches[0].clientY - art.top) / art.height; const second = percentage * art.duration; art.emit("setBar", "played", percentage, event); art.seek = second; diff --git a/docs/document/404.html b/docs/document/404.html index e8a9e14bf..a1ae92c1e 100644 --- a/docs/document/404.html +++ b/docs/document/404.html @@ -9,7 +9,7 @@ - + @@ -21,7 +21,7 @@
- + \ No newline at end of file diff --git a/docs/document/advanced/built-in.html b/docs/document/advanced/built-in.html index e54608964..8ed46d3b9 100644 --- a/docs/document/advanced/built-in.html +++ b/docs/document/advanced/built-in.html @@ -9,9 +9,9 @@ - + - + @@ -217,7 +217,7 @@ art.on('ready', () => { art.plugins.add(myPlugin); }); - + \ No newline at end of file diff --git a/docs/document/advanced/class.html b/docs/document/advanced/class.html index f85ad135b..431c20666 100644 --- a/docs/document/advanced/class.html +++ b/docs/document/advanced/class.html @@ -9,9 +9,9 @@ - + - + @@ -31,7 +31,7 @@ }); console.info([...Artplayer.instances]);

version ​

返回播放器的版本信息

▶ Run Code
js
console.info(Artplayer.version);

env ​

返回播放器的环境变量

▶ Run Code
js
console.info(Artplayer.env);

build ​

返回播放器的打包时间

▶ Run Code
js
console.info(Artplayer.build);

config ​

返回视频的默认配置

▶ Run Code
js
console.info(Artplayer.config);

utils ​

返回播放器的工具函数集合

▶ Run Code
js
console.info(Artplayer.utils);

全部工具函数请参考以下地址:

artplayer/types/utils.d.ts

scheme ​

返回播放器选项的校验方案

▶ Run Code
js
console.info(Artplayer.scheme);

Emitter ​

返回事件分发器的构造函数

▶ Run Code
js
console.info(Artplayer.Emitter);

validator ​

返回选项的校验函数

▶ Run Code
js
console.info(Artplayer.validator);

kindOf ​

返回类型检测的函数工具

▶ Run Code
js
console.info(Artplayer.kindOf);

html ​

返回播放器所需的 html 字符串

▶ Run Code
js
console.info(Artplayer.html);

option ​

返回播放器的默认选项

▶ Run Code
js
console.info(Artplayer.option);
- + \ No newline at end of file diff --git a/docs/document/advanced/event.html b/docs/document/advanced/event.html index 702530cca..a38d0656d 100644 --- a/docs/document/advanced/event.html +++ b/docs/document/advanced/event.html @@ -9,9 +9,9 @@ - + - + @@ -385,7 +385,7 @@ art.on('keydown', (event) => { console.log(event.code); });

video:canplay ​

浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容

video:canplaythrough ​

浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束

video:complete ​

OfflineAudioContext 渲染完成

video:durationchange ​

duration 属性的值改变时触发

video:emptied ​

媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载它

video:ended ​

视频停止播放,因为 media 已经到达结束点

video:error ​

获取媒体数据时出错,或者资源类型不是受支持的媒体格式

video:loadeddata ​

media 中的首帧已经完成加载

video:loadedmetadata ​

已加载元数据

video:pause ​

播放已暂停

video:play ​

播放已开始

video:playing ​

由于缺乏数据而暂停或延迟后,播放准备开始

video:progress ​

在浏览器加载资源时周期性触发

video:ratechange ​

播放速率发生变化

video:seeked ​

跳帧(seek)操作完成

video:seeking ​

跳帧(seek)操作开始

video:stalled ​

用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现

video:suspend ​

媒体数据加载已暂停

video:timeupdate ​

currentTime 属性指定的时间发生变化

video:volumechange ​

音量发生变化

video:waiting ​

由于暂时缺少数据,播放已停止

- + \ No newline at end of file diff --git a/docs/document/advanced/global.html b/docs/document/advanced/global.html index 1428dc1ac..f4c28c148 100644 --- a/docs/document/advanced/global.html +++ b/docs/document/advanced/global.html @@ -9,9 +9,9 @@ - + - + @@ -248,7 +248,7 @@ // 只销毁界面,不主动清空 src art.destroy(); - + \ No newline at end of file diff --git a/docs/document/advanced/plugin.html b/docs/document/advanced/plugin.html index 693e54253..9cd9dc79b 100644 --- a/docs/document/advanced/plugin.html +++ b/docs/document/advanced/plugin.html @@ -9,9 +9,9 @@ - + - + @@ -122,7 +122,7 @@ }) ], }); - + \ No newline at end of file diff --git a/docs/document/advanced/property.html b/docs/document/advanced/property.html index 44cbbe023..c7ef2a66c 100644 --- a/docs/document/advanced/property.html +++ b/docs/document/advanced/property.html @@ -9,9 +9,9 @@ - + - + @@ -457,7 +457,7 @@ art.on('ready', () => { art.subtitleOffset = 1; }); - + \ No newline at end of file diff --git a/docs/document/assets/app.CDNxlRra.js b/docs/document/assets/app.CkD0mcCX.js similarity index 95% rename from docs/document/assets/app.CDNxlRra.js rename to docs/document/assets/app.CkD0mcCX.js index cb20c6c86..a707bf37a 100644 --- a/docs/document/assets/app.CDNxlRra.js +++ b/docs/document/assets/app.CkD0mcCX.js @@ -1 +1 @@ -import{t as p}from"./chunks/theme.DA2WZC55.js";import{R as s,a6 as i,a7 as u,a8 as c,a9 as l,aa as f,ab as d,ac as m,ad as h,ae as g,af as A,d as v,u as y,v as C,s as P,ag as b,ah as w,ai as R,aj as E}from"./chunks/framework.xxfEszSJ.js";function r(e){if(e.extends){const a=r(e.extends);return{...a,...e,async enhanceApp(t){a.enhanceApp&&await a.enhanceApp(t),e.enhanceApp&&await e.enhanceApp(t)}}}return e}const n=r(p),S=v({name:"VitePressApp",setup(){const{site:e,lang:a,dir:t}=y();return C(()=>{P(()=>{document.documentElement.lang=a.value,document.documentElement.dir=t.value})}),e.value.router.prefetchLinks&&b(),w(),R(),n.setup&&n.setup(),()=>E(n.Layout)}});async function T(){globalThis.__VITEPRESS__=!0;const e=D(),a=j();a.provide(u,e);const t=c(e.route);return a.provide(l,t),a.component("Content",f),a.component("ClientOnly",d),Object.defineProperties(a.config.globalProperties,{$frontmatter:{get(){return t.frontmatter.value}},$params:{get(){return t.page.value.params}}}),n.enhanceApp&&await n.enhanceApp({app:a,router:e,siteData:m}),{app:a,router:e,data:t}}function j(){return A(S)}function D(){let e=s;return h(a=>{let t=g(a),o=null;return t&&(e&&(t=t.replace(/\.js$/,".lean.js")),o=import(t)),s&&(e=!1),o},n.NotFound)}s&&T().then(({app:e,router:a,data:t})=>{a.go().then(()=>{i(a.route,t.site),e.mount("#app")})});export{T as createApp}; +import{t as p}from"./chunks/theme.DqsiyDQE.js";import{R as s,a6 as i,a7 as u,a8 as c,a9 as l,aa as f,ab as d,ac as m,ad as h,ae as g,af as A,d as v,u as y,v as C,s as P,ag as b,ah as w,ai as R,aj as E}from"./chunks/framework.xxfEszSJ.js";function r(e){if(e.extends){const a=r(e.extends);return{...a,...e,async enhanceApp(t){a.enhanceApp&&await a.enhanceApp(t),e.enhanceApp&&await e.enhanceApp(t)}}}return e}const n=r(p),S=v({name:"VitePressApp",setup(){const{site:e,lang:a,dir:t}=y();return C(()=>{P(()=>{document.documentElement.lang=a.value,document.documentElement.dir=t.value})}),e.value.router.prefetchLinks&&b(),w(),R(),n.setup&&n.setup(),()=>E(n.Layout)}});async function T(){globalThis.__VITEPRESS__=!0;const e=D(),a=j();a.provide(u,e);const t=c(e.route);return a.provide(l,t),a.component("Content",f),a.component("ClientOnly",d),Object.defineProperties(a.config.globalProperties,{$frontmatter:{get(){return t.frontmatter.value}},$params:{get(){return t.page.value.params}}}),n.enhanceApp&&await n.enhanceApp({app:a,router:e,siteData:m}),{app:a,router:e,data:t}}function j(){return A(S)}function D(){let e=s;return h(a=>{let t=g(a),o=null;return t&&(e&&(t=t.replace(/\.js$/,".lean.js")),o=import(t)),s&&(e=!1),o},n.NotFound)}s&&T().then(({app:e,router:a,data:t})=>{a.go().then(()=>{i(a.route,t.site),e.mount("#app")})});export{T as createApp}; diff --git a/docs/document/assets/chunks/theme.DA2WZC55.js b/docs/document/assets/chunks/theme.DqsiyDQE.js similarity index 99% rename from docs/document/assets/chunks/theme.DA2WZC55.js rename to docs/document/assets/chunks/theme.DqsiyDQE.js index d1ecaf8ba..475e634bc 100644 --- a/docs/document/assets/chunks/theme.DA2WZC55.js +++ b/docs/document/assets/chunks/theme.DqsiyDQE.js @@ -1 +1 @@ -import{d as k,c as h,r as p,n as A,o as i,a as ee,t as C,b as P,w as f,T as we,e as g,_ as V,u as Re,i as it,f as lt,g as he,h as S,j as d,k as c,l as te,m as Pe,p as T,q as J,s as fe,v as Q,x as Me,y as Ne,z as ct,A as ut,F as H,B as z,C as Z,D as We,E as ve,G as y,H as W,I as Ke,J as me,K as Y,L as _e,M as dt,N as Je,O as pt,P as Ie,Q as xe,R as ge,S as ht,U as ft,V as vt,W as Fe,X as mt,Y as Xe,Z as _t,$ as gt,a0 as Ye,a1 as Qe,a2 as kt,a3 as bt,a4 as $t,a5 as yt}from"./framework.xxfEszSJ.js";const Pt=k({__name:"VPBadge",props:{text:{},type:{default:"tip"}},setup(n){return(e,t)=>(i(),h("span",{class:A(["VPBadge",e.type])},[p(e.$slots,"default",{},()=>[ee(C(e.text),1)])],2))}}),Lt={key:0,class:"VPBackdrop"},Vt=k({__name:"VPBackdrop",props:{show:{type:Boolean}},setup(n){return(e,t)=>(i(),P(we,{name:"fade"},{default:f(()=>[e.show?(i(),h("div",Lt)):g("",!0)]),_:1}))}}),St=V(Vt,[["__scopeId","data-v-b2600058"]]),M=Re;function Tt(n,e){let t,s=!1;return()=>{t&&clearTimeout(t),s?t=setTimeout(n,e):(n(),(s=!0)&&setTimeout(()=>s=!1,e))}}function Le(n){return n.startsWith("/")?n:`/${n}`}function Ce(n){const{pathname:e,search:t,hash:s,protocol:o}=new URL(n,"http://a.com");if(it(n)||n.startsWith("#")||!o.startsWith("http")||!lt(e))return n;const{site:a}=M(),r=e.endsWith("/")||e.endsWith(".html")?n:n.replace(/(?:(^\.+)\/)?.*$/,`$1${e.replace(/(\.md)?$/,a.value.cleanUrls?"":".html")}${t}${s}`);return he(r)}function ae({correspondingLink:n=!1}={}){const{site:e,localeIndex:t,page:s,theme:o,hash:a}=M(),r=S(()=>{var u,v;return{label:(u=e.value.locales[t.value])==null?void 0:u.label,link:((v=e.value.locales[t.value])==null?void 0:v.link)||(t.value==="root"?"/":`/${t.value}/`)}});return{localeLinks:S(()=>Object.entries(e.value.locales).flatMap(([u,v])=>r.value.label===v.label?[]:{text:v.label,link:wt(v.link||(u==="root"?"/":`/${u}/`),o.value.i18nRouting!==!1&&n,s.value.relativePath.slice(r.value.link.length-1),!e.value.cleanUrls)+a.value})),currentLang:r}}function wt(n,e,t,s){return e?n.replace(/\/$/,"")+Le(t.replace(/(^|\/)index\.md$/,"$1").replace(/\.md$/,s?".html":"")):n}const Mt={class:"NotFound"},Nt={class:"code"},It={class:"title"},Ct={class:"quote"},At={class:"action"},Ht=["href","aria-label"],Bt=k({__name:"NotFound",setup(n){const{theme:e}=M(),{currentLang:t}=ae();return(s,o)=>{var a,r,l,u,v;return i(),h("div",Mt,[d("p",Nt,C(((a=c(e).notFound)==null?void 0:a.code)??"404"),1),d("h1",It,C(((r=c(e).notFound)==null?void 0:r.title)??"PAGE NOT FOUND"),1),o[0]||(o[0]=d("div",{class:"divider"},null,-1)),d("blockquote",Ct,C(((l=c(e).notFound)==null?void 0:l.quote)??"But if you don't change your direction, and if you keep looking, you may end up where you are heading."),1),d("div",At,[d("a",{class:"link",href:c(he)(c(t).link),"aria-label":((u=c(e).notFound)==null?void 0:u.linkLabel)??"go to home"},C(((v=c(e).notFound)==null?void 0:v.linkText)??"Take me home"),9,Ht)])])}}}),Et=V(Bt,[["__scopeId","data-v-93fd8736"]]);function Ze(n,e){if(Array.isArray(n))return le(n);if(n==null)return[];e=Le(e);const t=Object.keys(n).sort((o,a)=>a.split("/").length-o.split("/").length).find(o=>e.startsWith(Le(o))),s=t?n[t]:[];return Array.isArray(s)?le(s):le(s.items,s.base)}function Ot(n){const e=[];let t=0;for(const s in n){const o=n[s];if(o.items){t=e.push(o);continue}e[t]||e.push({items:[]}),e[t].items.push(o)}return e}function Dt(n){const e=[];function t(s){for(const o of s)o.text&&o.link&&e.push({text:o.text,link:o.link,docFooterText:o.docFooterText}),o.items&&t(o.items)}return t(n),e}function Ve(n,e){return Array.isArray(e)?e.some(t=>Ve(n,t)):te(n,e.link)?!0:e.items?Ve(n,e.items):!1}function le(n,e){return[...n].map(t=>{const s={...t},o=s.base||e;return o&&s.link&&(s.link=o+s.link),s.items&&(s.items=le(s.items,o)),s})}function x(){const{frontmatter:n,page:e,theme:t}=M(),s=Pe("(min-width: 960px)"),o=T(!1),a=S(()=>{const N=t.value.sidebar,w=e.value.relativePath;return N?Ze(N,w):[]}),r=T(a.value);J(a,(N,w)=>{JSON.stringify(N)!==JSON.stringify(w)&&(r.value=a.value)});const l=S(()=>n.value.sidebar!==!1&&r.value.length>0&&n.value.layout!=="home"),u=S(()=>v?n.value.aside==null?t.value.aside==="left":n.value.aside==="left":!1),v=S(()=>n.value.layout==="home"?!1:n.value.aside!=null?!!n.value.aside:t.value.aside!==!1),_=S(()=>l.value&&s.value),m=S(()=>l.value?Ot(r.value):[]);function L(){o.value=!0}function b(){o.value=!1}function $(){o.value?b():L()}return{isOpen:o,sidebar:r,sidebarGroups:m,hasSidebar:l,hasAside:v,leftAside:u,isSidebarEnabled:_,open:L,close:b,toggle:$}}function Ft(n,e){let t;fe(()=>{t=n.value?document.activeElement:void 0}),Q(()=>{window.addEventListener("keyup",s)}),Me(()=>{window.removeEventListener("keyup",s)});function s(o){o.key==="Escape"&&n.value&&(e(),t==null||t.focus())}}function zt(n){const{page:e,hash:t}=M(),s=T(!1),o=S(()=>n.value.collapsed!=null),a=S(()=>!!n.value.link),r=T(!1),l=()=>{r.value=te(e.value.relativePath,n.value.link)};J([e,n,t],l),Q(l);const u=S(()=>r.value?!0:n.value.items?Ve(e.value.relativePath,n.value.items):!1),v=S(()=>!!(n.value.items&&n.value.items.length));fe(()=>{s.value=!!(o.value&&n.value.collapsed)}),Ne(()=>{(r.value||u.value)&&(s.value=!1)});function _(){o.value&&(s.value=!s.value)}return{collapsed:s,collapsible:o,isLink:a,isActiveLink:r,hasActiveLink:u,hasChildren:v,toggle:_}}function jt(){const{hasSidebar:n}=x(),e=Pe("(min-width: 960px)"),t=Pe("(min-width: 1280px)");return{isAsideEnabled:S(()=>!t.value&&!e.value?!1:n.value?t.value:e.value)}}const Ut=/\b(?:VPBadge|header-anchor|footnote-ref|ignore-header)\b/,Se=[];function et(n){return typeof n.outline=="object"&&!Array.isArray(n.outline)&&n.outline.label||n.outlineTitle||"On this page"}function Ae(n){const e=[...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")].filter(t=>t.id&&t.hasChildNodes()).map(t=>{const s=Number(t.tagName[1]);return{element:t,title:qt(t),link:"#"+t.id,level:s}});return Gt(e,n)}function qt(n){let e="";for(const t of n.childNodes)if(t.nodeType===1){if(Ut.test(t.className))continue;e+=t.textContent}else t.nodeType===3&&(e+=t.textContent);return e.trim()}function Gt(n,e){if(e===!1)return[];const t=(typeof e=="object"&&!Array.isArray(e)?e.level:e)||2,[s,o]=typeof t=="number"?[t,t]:t==="deep"?[2,6]:t;return Kt(n,s,o)}function Rt(n,e){const{isAsideEnabled:t}=jt(),s=Tt(a,100);let o=null;Q(()=>{requestAnimationFrame(a),window.addEventListener("scroll",s)}),ct(()=>{r(location.hash)}),Me(()=>{window.removeEventListener("scroll",s)});function a(){if(!t.value)return;const l=window.scrollY,u=window.innerHeight,v=document.body.offsetHeight,_=Math.abs(l+u-v)<1,m=Se.map(({element:b,link:$})=>({link:$,top:Wt(b)})).filter(({top:b})=>!Number.isNaN(b)).sort((b,$)=>b.top-$.top);if(!m.length){r(null);return}if(l<1){r(null);return}if(_){r(m[m.length-1].link);return}let L=null;for(const{link:b,top:$}of m){if($>l+ut()+4)break;L=b}r(L)}function r(l){o&&o.classList.remove("active"),l==null?o=null:o=n.value.querySelector(`a[href="${decodeURIComponent(l)}"]`);const u=o;u?(u.classList.add("active"),e.value.style.top=u.offsetTop+39+"px",e.value.style.opacity="1"):(e.value.style.top="33px",e.value.style.opacity="0")}}function Wt(n){let e=0;for(;n!==document.body;){if(n===null)return NaN;e+=n.offsetTop,n=n.offsetParent}return e}function Kt(n,e,t){Se.length=0;const s=[],o=[];return n.forEach(a=>{const r={...a,children:[]};let l=o[o.length-1];for(;l&&l.level>=r.level;)o.pop(),l=o[o.length-1];if(r.element.classList.contains("ignore-header")||l&&"shouldIgnore"in l){o.push({level:r.level,shouldIgnore:!0});return}r.level>t||r.level{const o=Z("VPDocOutlineItem",!0);return i(),h("ul",{class:A(["VPDocOutlineItem",t.root?"root":"nested"])},[(i(!0),h(H,null,z(t.headers,({children:a,link:r,title:l})=>(i(),h("li",null,[d("a",{class:"outline-link",href:r,onClick:e,title:l},C(l),9,Jt),a!=null&&a.length?(i(),P(o,{key:0,headers:a},null,8,["headers"])):g("",!0)]))),256))],2)}}}),tt=V(xt,[["__scopeId","data-v-da421f78"]]),Xt={class:"content"},Yt={"aria-level":"2",class:"outline-title",id:"doc-outline-aria-label",role:"heading"},Qt=k({__name:"VPDocAsideOutline",setup(n){const{frontmatter:e,theme:t}=M(),s=We([]);ve(()=>{s.value=Ae(e.value.outline??t.value.outline)});const o=T(),a=T();return Rt(o,a),(r,l)=>(i(),h("nav",{"aria-labelledby":"doc-outline-aria-label",class:A(["VPDocAsideOutline",{"has-outline":s.value.length>0}]),ref_key:"container",ref:o},[d("div",Xt,[d("div",{class:"outline-marker",ref_key:"marker",ref:a},null,512),d("div",Yt,C(c(et)(c(t))),1),y(tt,{headers:s.value,root:!0},null,8,["headers"])])],2))}}),Zt=V(Qt,[["__scopeId","data-v-dfbd9fb8"]]),en={class:"VPDocAsideCarbonAds"},tn=k({__name:"VPDocAsideCarbonAds",props:{carbonAds:{}},setup(n){const e=()=>null;return(t,s)=>(i(),h("div",en,[y(c(e),{"carbon-ads":t.carbonAds},null,8,["carbon-ads"])]))}}),nn={class:"VPDocAside"},sn=k({__name:"VPDocAside",setup(n){const{theme:e}=M();return(t,s)=>(i(),h("div",nn,[p(t.$slots,"aside-top",{},void 0,!0),p(t.$slots,"aside-outline-before",{},void 0,!0),y(Zt),p(t.$slots,"aside-outline-after",{},void 0,!0),s[0]||(s[0]=d("div",{class:"spacer"},null,-1)),p(t.$slots,"aside-ads-before",{},void 0,!0),c(e).carbonAds?(i(),P(tn,{key:0,"carbon-ads":c(e).carbonAds},null,8,["carbon-ads"])):g("",!0),p(t.$slots,"aside-ads-after",{},void 0,!0),p(t.$slots,"aside-bottom",{},void 0,!0)]))}}),on=V(sn,[["__scopeId","data-v-79cae1a0"]]);function an(){const{theme:n,page:e}=M();return S(()=>{const{text:t="Edit this page",pattern:s=""}=n.value.editLink||{};let o;return typeof s=="function"?o=s(e.value):o=s.replace(/:path/g,e.value.filePath),{url:o,text:t}})}function rn(){const{page:n,theme:e,frontmatter:t}=M();return S(()=>{var v,_,m,L,b,$,N,w;const s=Ze(e.value.sidebar,n.value.relativePath),o=Dt(s),a=ln(o,O=>O.link.replace(/[?#].*$/,"")),r=a.findIndex(O=>te(n.value.relativePath,O.link)),l=((v=e.value.docFooter)==null?void 0:v.prev)===!1&&!t.value.prev||t.value.prev===!1,u=((_=e.value.docFooter)==null?void 0:_.next)===!1&&!t.value.next||t.value.next===!1;return{prev:l?void 0:{text:(typeof t.value.prev=="string"?t.value.prev:typeof t.value.prev=="object"?t.value.prev.text:void 0)??((m=a[r-1])==null?void 0:m.docFooterText)??((L=a[r-1])==null?void 0:L.text),link:(typeof t.value.prev=="object"?t.value.prev.link:void 0)??((b=a[r-1])==null?void 0:b.link)},next:u?void 0:{text:(typeof t.value.next=="string"?t.value.next:typeof t.value.next=="object"?t.value.next.text:void 0)??(($=a[r+1])==null?void 0:$.docFooterText)??((N=a[r+1])==null?void 0:N.text),link:(typeof t.value.next=="object"?t.value.next.link:void 0)??((w=a[r+1])==null?void 0:w.link)}}})}function ln(n,e){const t=new Set;return n.filter(s=>{const o=e(s);return t.has(o)?!1:t.add(o)})}const K=k({__name:"VPLink",props:{tag:{},href:{},noIcon:{type:Boolean},target:{},rel:{}},setup(n){const e=n,t=S(()=>e.tag??(e.href?"a":"span")),s=S(()=>e.href&&Ke.test(e.href)||e.target==="_blank");return(o,a)=>(i(),P(W(t.value),{class:A(["VPLink",{link:o.href,"vp-external-link-icon":s.value,"no-icon":o.noIcon}]),href:o.href?c(Ce)(o.href):void 0,target:o.target??(s.value?"_blank":void 0),rel:o.rel??(s.value?"noreferrer":void 0)},{default:f(()=>[p(o.$slots,"default")]),_:3},8,["class","href","target","rel"]))}}),cn={class:"VPLastUpdated"},un=["datetime"],dn=k({__name:"VPDocFooterLastUpdated",setup(n){const{theme:e,page:t,lang:s}=M(),o=S(()=>new Date(t.value.lastUpdated)),a=S(()=>o.value.toISOString()),r=T("");return Q(()=>{fe(()=>{var l,u,v;r.value=new Intl.DateTimeFormat((u=(l=e.value.lastUpdated)==null?void 0:l.formatOptions)!=null&&u.forceLocale?s.value:void 0,((v=e.value.lastUpdated)==null?void 0:v.formatOptions)??{dateStyle:"short",timeStyle:"short"}).format(o.value)})}),(l,u)=>{var v;return i(),h("p",cn,[ee(C(((v=c(e).lastUpdated)==null?void 0:v.text)||c(e).lastUpdatedText||"Last updated")+": ",1),d("time",{datetime:a.value},C(r.value),9,un)])}}}),pn=V(dn,[["__scopeId","data-v-e95db471"]]),hn={key:0,class:"VPDocFooter"},fn={key:0,class:"edit-info"},vn={key:0,class:"edit-link"},mn={key:1,class:"last-updated"},_n={key:1,class:"prev-next","aria-labelledby":"doc-footer-aria-label"},gn={class:"pager"},kn=["innerHTML"],bn=["innerHTML"],$n={class:"pager"},yn=["innerHTML"],Pn=["innerHTML"],Ln=k({__name:"VPDocFooter",setup(n){const{theme:e,page:t,frontmatter:s}=M(),o=an(),a=rn(),r=S(()=>e.value.editLink&&s.value.editLink!==!1),l=S(()=>t.value.lastUpdated),u=S(()=>r.value||l.value||a.value.prev||a.value.next);return(v,_)=>{var m,L,b,$;return u.value?(i(),h("footer",hn,[p(v.$slots,"doc-footer-before",{},void 0,!0),r.value||l.value?(i(),h("div",fn,[r.value?(i(),h("div",vn,[y(K,{class:"edit-link-button",href:c(o).url,"no-icon":!0},{default:f(()=>[_[0]||(_[0]=d("span",{class:"vpi-square-pen edit-link-icon"},null,-1)),ee(" "+C(c(o).text),1)]),_:1},8,["href"])])):g("",!0),l.value?(i(),h("div",mn,[y(pn)])):g("",!0)])):g("",!0),(m=c(a).prev)!=null&&m.link||(L=c(a).next)!=null&&L.link?(i(),h("nav",_n,[_[1]||(_[1]=d("span",{class:"visually-hidden",id:"doc-footer-aria-label"},"Pager",-1)),d("div",gn,[(b=c(a).prev)!=null&&b.link?(i(),P(K,{key:0,class:"pager-link prev",href:c(a).prev.link},{default:f(()=>{var N;return[d("span",{class:"desc",innerHTML:((N=c(e).docFooter)==null?void 0:N.prev)||"Previous page"},null,8,kn),d("span",{class:"title",innerHTML:c(a).prev.text},null,8,bn)]}),_:1},8,["href"])):g("",!0)]),d("div",$n,[($=c(a).next)!=null&&$.link?(i(),P(K,{key:0,class:"pager-link next",href:c(a).next.link},{default:f(()=>{var N;return[d("span",{class:"desc",innerHTML:((N=c(e).docFooter)==null?void 0:N.next)||"Next page"},null,8,yn),d("span",{class:"title",innerHTML:c(a).next.text},null,8,Pn)]}),_:1},8,["href"])):g("",!0)])])):g("",!0)])):g("",!0)}}}),Vn=V(Ln,[["__scopeId","data-v-07d71ff1"]]),Sn={class:"container"},Tn={class:"aside-container"},wn={class:"aside-content"},Mn={class:"content"},Nn={class:"content-container"},In={class:"main"},Cn=k({__name:"VPDoc",setup(n){const{theme:e}=M(),t=me(),{hasSidebar:s,hasAside:o,leftAside:a}=x(),r=S(()=>t.path.replace(/[./]+/g,"_").replace(/_html$/,""));return(l,u)=>{const v=Z("Content");return i(),h("div",{class:A(["VPDoc",{"has-sidebar":c(s),"has-aside":c(o)}])},[p(l.$slots,"doc-top",{},void 0,!0),d("div",Sn,[c(o)?(i(),h("div",{key:0,class:A(["aside",{"left-aside":c(a)}])},[u[0]||(u[0]=d("div",{class:"aside-curtain"},null,-1)),d("div",Tn,[d("div",wn,[y(on,null,{"aside-top":f(()=>[p(l.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":f(()=>[p(l.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":f(()=>[p(l.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[p(l.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[p(l.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[p(l.$slots,"aside-ads-after",{},void 0,!0)]),_:3})])])],2)):g("",!0),d("div",Mn,[d("div",Nn,[p(l.$slots,"doc-before",{},void 0,!0),d("main",In,[y(v,{class:A(["vp-doc",[r.value,c(e).externalLinkIcon&&"external-link-icon-enabled"]])},null,8,["class"])]),y(Vn,null,{"doc-footer-before":f(()=>[p(l.$slots,"doc-footer-before",{},void 0,!0)]),_:3}),p(l.$slots,"doc-after",{},void 0,!0)])])]),p(l.$slots,"doc-bottom",{},void 0,!0)],2)}}}),An=V(Cn,[["__scopeId","data-v-ef3a4dda"]]),Hn=k({__name:"VPButton",props:{tag:{},size:{default:"medium"},theme:{default:"brand"},text:{},href:{},target:{},rel:{}},setup(n){const e=n,t=S(()=>e.href&&Ke.test(e.href)),s=S(()=>e.tag||(e.href?"a":"button"));return(o,a)=>(i(),P(W(s.value),{class:A(["VPButton",[o.size,o.theme]]),href:o.href?c(Ce)(o.href):void 0,target:e.target??(t.value?"_blank":void 0),rel:e.rel??(t.value?"noreferrer":void 0)},{default:f(()=>[ee(C(o.text),1)]),_:1},8,["class","href","target","rel"]))}}),Bn=V(Hn,[["__scopeId","data-v-b20c43c2"]]),En=["src","alt"],On=k({inheritAttrs:!1,__name:"VPImage",props:{image:{},alt:{}},setup(n){return(e,t)=>{const s=Z("VPImage",!0);return e.image?(i(),h(H,{key:0},[typeof e.image=="string"||"src"in e.image?(i(),h("img",Y({key:0,class:"VPImage"},typeof e.image=="string"?e.$attrs:{...e.image,...e.$attrs},{src:c(he)(typeof e.image=="string"?e.image:e.image.src),alt:e.alt??(typeof e.image=="string"?"":e.image.alt||"")}),null,16,En)):(i(),h(H,{key:1},[y(s,Y({class:"dark",image:e.image.dark,alt:e.image.alt},e.$attrs),null,16,["image","alt"]),y(s,Y({class:"light",image:e.image.light,alt:e.image.alt},e.$attrs),null,16,["image","alt"])],64))],64)):g("",!0)}}}),ue=V(On,[["__scopeId","data-v-4d414b82"]]),Dn={class:"container"},Fn={class:"main"},zn={class:"heading"},jn=["innerHTML"],Un=["innerHTML"],qn=["innerHTML"],Gn={key:0,class:"actions"},Rn={key:0,class:"image"},Wn={class:"image-container"},Kn=k({__name:"VPHero",props:{name:{},text:{},tagline:{},image:{},actions:{}},setup(n){const e=_e("hero-image-slot-exists");return(t,s)=>(i(),h("div",{class:A(["VPHero",{"has-image":t.image||c(e)}])},[d("div",Dn,[d("div",Fn,[p(t.$slots,"home-hero-info-before",{},void 0,!0),p(t.$slots,"home-hero-info",{},()=>[d("h1",zn,[t.name?(i(),h("span",{key:0,innerHTML:t.name,class:"name clip"},null,8,jn)):g("",!0),t.text?(i(),h("span",{key:1,innerHTML:t.text,class:"text"},null,8,Un)):g("",!0)]),t.tagline?(i(),h("p",{key:0,innerHTML:t.tagline,class:"tagline"},null,8,qn)):g("",!0)],!0),p(t.$slots,"home-hero-info-after",{},void 0,!0),t.actions?(i(),h("div",Gn,[(i(!0),h(H,null,z(t.actions,o=>(i(),h("div",{key:o.link,class:"action"},[y(Bn,{tag:"a",size:"medium",theme:o.theme,text:o.text,href:o.link,target:o.target,rel:o.rel},null,8,["theme","text","href","target","rel"])]))),128))])):g("",!0),p(t.$slots,"home-hero-actions-after",{},void 0,!0)]),t.image||c(e)?(i(),h("div",Rn,[d("div",Wn,[s[0]||(s[0]=d("div",{class:"image-bg"},null,-1)),p(t.$slots,"home-hero-image",{},()=>[t.image?(i(),P(ue,{key:0,class:"image-src",image:t.image},null,8,["image"])):g("",!0)],!0)])])):g("",!0)])],2))}}),Jn=V(Kn,[["__scopeId","data-v-d266baba"]]),xn=k({__name:"VPHomeHero",setup(n){const{frontmatter:e}=M();return(t,s)=>c(e).hero?(i(),P(Jn,{key:0,class:"VPHomeHero",name:c(e).hero.name,text:c(e).hero.text,tagline:c(e).hero.tagline,image:c(e).hero.image,actions:c(e).hero.actions},{"home-hero-info-before":f(()=>[p(t.$slots,"home-hero-info-before")]),"home-hero-info":f(()=>[p(t.$slots,"home-hero-info")]),"home-hero-info-after":f(()=>[p(t.$slots,"home-hero-info-after")]),"home-hero-actions-after":f(()=>[p(t.$slots,"home-hero-actions-after")]),"home-hero-image":f(()=>[p(t.$slots,"home-hero-image")]),_:3},8,["name","text","tagline","image","actions"])):g("",!0)}}),Xn={class:"box"},Yn={key:0,class:"icon"},Qn=["innerHTML"],Zn=["innerHTML"],es=["innerHTML"],ts={key:4,class:"link-text"},ns={class:"link-text-value"},ss=k({__name:"VPFeature",props:{icon:{},title:{},details:{},link:{},linkText:{},rel:{},target:{}},setup(n){return(e,t)=>(i(),P(K,{class:"VPFeature",href:e.link,rel:e.rel,target:e.target,"no-icon":!0,tag:e.link?"a":"div"},{default:f(()=>[d("article",Xn,[typeof e.icon=="object"&&e.icon.wrap?(i(),h("div",Yn,[y(ue,{image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])])):typeof e.icon=="object"?(i(),P(ue,{key:1,image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])):e.icon?(i(),h("div",{key:2,class:"icon",innerHTML:e.icon},null,8,Qn)):g("",!0),d("h2",{class:"title",innerHTML:e.title},null,8,Zn),e.details?(i(),h("p",{key:3,class:"details",innerHTML:e.details},null,8,es)):g("",!0),e.linkText?(i(),h("div",ts,[d("p",ns,[ee(C(e.linkText)+" ",1),t[0]||(t[0]=d("span",{class:"vpi-arrow-right link-text-icon"},null,-1))])])):g("",!0)])]),_:1},8,["href","rel","target","tag"]))}}),os=V(ss,[["__scopeId","data-v-95001937"]]),as={key:0,class:"VPFeatures"},rs={class:"container"},is={class:"items"},ls=k({__name:"VPFeatures",props:{features:{}},setup(n){const e=n,t=S(()=>{const s=e.features.length;if(s){if(s===2)return"grid-2";if(s===3)return"grid-3";if(s%3===0)return"grid-6";if(s>3)return"grid-4"}else return});return(s,o)=>s.features?(i(),h("div",as,[d("div",rs,[d("div",is,[(i(!0),h(H,null,z(s.features,a=>(i(),h("div",{key:a.title,class:A(["item",[t.value]])},[y(os,{icon:a.icon,title:a.title,details:a.details,link:a.link,"link-text":a.linkText,rel:a.rel,target:a.target},null,8,["icon","title","details","link","link-text","rel","target"])],2))),128))])])])):g("",!0)}}),cs=V(ls,[["__scopeId","data-v-1da4ff3d"]]),us=k({__name:"VPHomeFeatures",setup(n){const{frontmatter:e}=M();return(t,s)=>c(e).features?(i(),P(cs,{key:0,class:"VPHomeFeatures",features:c(e).features},null,8,["features"])):g("",!0)}}),ds=k({__name:"VPHomeContent",setup(n){const{width:e}=dt({initialWidth:0,includeScrollbar:!1});return(t,s)=>(i(),h("div",{class:"vp-doc container",style:Je(c(e)?{"--vp-offset":`calc(50% - ${c(e)/2}px)`}:{})},[p(t.$slots,"default",{},void 0,!0)],4))}}),ps=V(ds,[["__scopeId","data-v-2498cc33"]]),hs=k({__name:"VPHome",setup(n){const{frontmatter:e,theme:t}=M();return(s,o)=>{const a=Z("Content");return i(),h("div",{class:A(["VPHome",{"external-link-icon-enabled":c(t).externalLinkIcon}])},[p(s.$slots,"home-hero-before",{},void 0,!0),y(xn,null,{"home-hero-info-before":f(()=>[p(s.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[p(s.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[p(s.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[p(s.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[p(s.$slots,"home-hero-image",{},void 0,!0)]),_:3}),p(s.$slots,"home-hero-after",{},void 0,!0),p(s.$slots,"home-features-before",{},void 0,!0),y(us),p(s.$slots,"home-features-after",{},void 0,!0),c(e).markdownStyles!==!1?(i(),P(ps,{key:0},{default:f(()=>[y(a)]),_:1})):(i(),P(a,{key:1}))],2)}}}),fs=V(hs,[["__scopeId","data-v-8b59c434"]]),vs={},ms={class:"VPPage"};function _s(n,e){const t=Z("Content");return i(),h("div",ms,[p(n.$slots,"page-top"),y(t),p(n.$slots,"page-bottom")])}const gs=V(vs,[["render",_s]]),ks=k({__name:"VPContent",setup(n){const{page:e,frontmatter:t}=M(),{hasSidebar:s}=x();return(o,a)=>(i(),h("div",{class:A(["VPContent",{"has-sidebar":c(s),"is-home":c(t).layout==="home"}]),id:"VPContent"},[c(e).isNotFound?p(o.$slots,"not-found",{key:0},()=>[y(Et)],!0):c(t).layout==="page"?(i(),P(gs,{key:1},{"page-top":f(()=>[p(o.$slots,"page-top",{},void 0,!0)]),"page-bottom":f(()=>[p(o.$slots,"page-bottom",{},void 0,!0)]),_:3})):c(t).layout==="home"?(i(),P(fs,{key:2},{"home-hero-before":f(()=>[p(o.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":f(()=>[p(o.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[p(o.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[p(o.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[p(o.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[p(o.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":f(()=>[p(o.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":f(()=>[p(o.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":f(()=>[p(o.$slots,"home-features-after",{},void 0,!0)]),_:3})):c(t).layout&&c(t).layout!=="doc"?(i(),P(W(c(t).layout),{key:3})):(i(),P(An,{key:4},{"doc-top":f(()=>[p(o.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":f(()=>[p(o.$slots,"doc-bottom",{},void 0,!0)]),"doc-footer-before":f(()=>[p(o.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":f(()=>[p(o.$slots,"doc-before",{},void 0,!0)]),"doc-after":f(()=>[p(o.$slots,"doc-after",{},void 0,!0)]),"aside-top":f(()=>[p(o.$slots,"aside-top",{},void 0,!0)]),"aside-outline-before":f(()=>[p(o.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[p(o.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[p(o.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[p(o.$slots,"aside-ads-after",{},void 0,!0)]),"aside-bottom":f(()=>[p(o.$slots,"aside-bottom",{},void 0,!0)]),_:3}))],2))}}),bs=V(ks,[["__scopeId","data-v-d2aef184"]]),$s={class:"container"},ys=["innerHTML"],Ps=["innerHTML"],Ls=k({__name:"VPFooter",setup(n){const{theme:e,frontmatter:t}=M(),{hasSidebar:s}=x();return(o,a)=>c(e).footer&&c(t).footer!==!1?(i(),h("footer",{key:0,class:A(["VPFooter",{"has-sidebar":c(s)}])},[d("div",$s,[c(e).footer.message?(i(),h("p",{key:0,class:"message",innerHTML:c(e).footer.message},null,8,ys)):g("",!0),c(e).footer.copyright?(i(),h("p",{key:1,class:"copyright",innerHTML:c(e).footer.copyright},null,8,Ps)):g("",!0)])],2)):g("",!0)}}),Vs=V(Ls,[["__scopeId","data-v-e3157d6d"]]);function Ss(){const{theme:n,frontmatter:e}=M(),t=We([]),s=S(()=>t.value.length>0);return ve(()=>{t.value=Ae(e.value.outline??n.value.outline)}),{headers:t,hasLocalNav:s}}const Ts={class:"menu-text"},ws={class:"header"},Ms={class:"outline"},Ns=k({__name:"VPLocalNavOutlineDropdown",props:{headers:{},navHeight:{}},setup(n){const e=n,{theme:t}=M(),s=T(!1),o=T(0),a=T(),r=T();function l(m){var L;(L=a.value)!=null&&L.contains(m.target)||(s.value=!1)}J(s,m=>{if(m){document.addEventListener("click",l);return}document.removeEventListener("click",l)}),pt("Escape",()=>{s.value=!1}),ve(()=>{s.value=!1});function u(){s.value=!s.value,o.value=window.innerHeight+Math.min(window.scrollY-e.navHeight,0)}function v(m){m.target.classList.contains("outline-link")&&(r.value&&(r.value.style.transition="none"),Ie(()=>{s.value=!1}))}function _(){s.value=!1,window.scrollTo({top:0,left:0,behavior:"smooth"})}return(m,L)=>(i(),h("div",{class:"VPLocalNavOutlineDropdown",style:Je({"--vp-vh":o.value+"px"}),ref_key:"main",ref:a},[m.headers.length>0?(i(),h("button",{key:0,onClick:u,class:A({open:s.value})},[d("span",Ts,C(c(et)(c(t))),1),L[0]||(L[0]=d("span",{class:"vpi-chevron-right icon"},null,-1))],2)):(i(),h("button",{key:1,onClick:_},C(c(t).returnToTopLabel||"Return to top"),1)),y(we,{name:"flyout"},{default:f(()=>[s.value?(i(),h("div",{key:0,ref_key:"items",ref:r,class:"items",onClick:v},[d("div",ws,[d("a",{class:"top-link",href:"#",onClick:_},C(c(t).returnToTopLabel||"Return to top"),1)]),d("div",Ms,[y(tt,{headers:m.headers},null,8,["headers"])])],512)):g("",!0)]),_:1})],4))}}),Is=V(Ns,[["__scopeId","data-v-d61422fe"]]),Cs={class:"container"},As=["aria-expanded"],Hs={class:"menu-text"},Bs=k({__name:"VPLocalNav",props:{open:{type:Boolean}},emits:["open-menu"],setup(n){const{theme:e,frontmatter:t}=M(),{hasSidebar:s}=x(),{headers:o}=Ss(),{y:a}=xe(),r=T(0);Q(()=>{r.value=parseInt(getComputedStyle(document.documentElement).getPropertyValue("--vp-nav-height"))}),ve(()=>{o.value=Ae(t.value.outline??e.value.outline)});const l=S(()=>o.value.length===0),u=S(()=>l.value&&!s.value),v=S(()=>({VPLocalNav:!0,"has-sidebar":s.value,empty:l.value,fixed:u.value}));return(_,m)=>c(t).layout!=="home"&&(!u.value||c(a)>=r.value)?(i(),h("div",{key:0,class:A(v.value)},[d("div",Cs,[c(s)?(i(),h("button",{key:0,class:"menu","aria-expanded":_.open,"aria-controls":"VPSidebarNav",onClick:m[0]||(m[0]=L=>_.$emit("open-menu"))},[m[1]||(m[1]=d("span",{class:"vpi-align-left menu-icon"},null,-1)),d("span",Hs,C(c(e).sidebarMenuLabel||"Menu"),1)],8,As)):g("",!0),y(Is,{headers:c(o),navHeight:r.value},null,8,["headers","navHeight"])])],2)):g("",!0)}}),Es=V(Bs,[["__scopeId","data-v-9d8129cc"]]);function Os(){const n=T(!1);function e(){n.value=!0,window.addEventListener("resize",o)}function t(){n.value=!1,window.removeEventListener("resize",o)}function s(){n.value?t():e()}function o(){window.outerWidth>=768&&t()}const a=me();return J(()=>a.path,t),{isScreenOpen:n,openScreen:e,closeScreen:t,toggleScreen:s}}const Ds={},Fs={class:"VPSwitch",type:"button",role:"switch"},zs={class:"check"},js={key:0,class:"icon"};function Us(n,e){return i(),h("button",Fs,[d("span",zs,[n.$slots.default?(i(),h("span",js,[p(n.$slots,"default",{},void 0,!0)])):g("",!0)])])}const qs=V(Ds,[["render",Us],["__scopeId","data-v-7012e5dd"]]),Gs=k({__name:"VPSwitchAppearance",setup(n){const{isDark:e,theme:t}=M(),s=_e("toggle-appearance",()=>{e.value=!e.value}),o=T("");return Ne(()=>{o.value=e.value?t.value.lightModeSwitchTitle||"Switch to light theme":t.value.darkModeSwitchTitle||"Switch to dark theme"}),(a,r)=>(i(),P(qs,{title:o.value,class:"VPSwitchAppearance","aria-checked":c(e),onClick:c(s)},{default:f(()=>r[0]||(r[0]=[d("span",{class:"vpi-sun sun"},null,-1),d("span",{class:"vpi-moon moon"},null,-1)])),_:1},8,["title","aria-checked","onClick"]))}}),He=V(Gs,[["__scopeId","data-v-fa1daf57"]]),Rs={key:0,class:"VPNavBarAppearance"},Ws=k({__name:"VPNavBarAppearance",setup(n){const{site:e}=M();return(t,s)=>c(e).appearance&&c(e).appearance!=="force-dark"&&c(e).appearance!=="force-auto"?(i(),h("div",Rs,[y(He)])):g("",!0)}}),Ks=V(Ws,[["__scopeId","data-v-123fcb2f"]]),Be=T();let nt=!1,be=0;function Js(n){const e=T(!1);if(ge){!nt&&xs(),be++;const t=J(Be,s=>{var o,a,r;s===n.el.value||(o=n.el.value)!=null&&o.contains(s)?(e.value=!0,(a=n.onFocus)==null||a.call(n)):(e.value=!1,(r=n.onBlur)==null||r.call(n))});Me(()=>{t(),be--,be||Xs()})}return ht(e)}function xs(){document.addEventListener("focusin",st),nt=!0,Be.value=document.activeElement}function Xs(){document.removeEventListener("focusin",st)}function st(){Be.value=document.activeElement}const Ys={class:"VPMenuLink"},Qs=["innerHTML"],Zs=k({__name:"VPMenuLink",props:{item:{}},setup(n){const{page:e}=M();return(t,s)=>(i(),h("div",Ys,[y(K,{class:A({active:c(te)(c(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon},{default:f(()=>[d("span",{innerHTML:t.item.text},null,8,Qs)]),_:1},8,["class","href","target","rel","no-icon"])]))}}),ke=V(Zs,[["__scopeId","data-v-65e4a6b1"]]),eo={class:"VPMenuGroup"},to={key:0,class:"title"},no=k({__name:"VPMenuGroup",props:{text:{},items:{}},setup(n){return(e,t)=>(i(),h("div",eo,[e.text?(i(),h("p",to,C(e.text),1)):g("",!0),(i(!0),h(H,null,z(e.items,s=>(i(),h(H,null,["link"in s?(i(),P(ke,{key:0,item:s},null,8,["item"])):g("",!0)],64))),256))]))}}),so=V(no,[["__scopeId","data-v-2bec9359"]]),oo={class:"VPMenu"},ao={key:0,class:"items"},ro=k({__name:"VPMenu",props:{items:{}},setup(n){return(e,t)=>(i(),h("div",oo,[e.items?(i(),h("div",ao,[(i(!0),h(H,null,z(e.items,s=>(i(),h(H,{key:JSON.stringify(s)},["link"in s?(i(),P(ke,{key:0,item:s},null,8,["item"])):"component"in s?(i(),P(W(s.component),Y({key:1,ref_for:!0},s.props),null,16)):(i(),P(so,{key:2,text:s.text,items:s.items},null,8,["text","items"]))],64))),128))])):g("",!0),p(e.$slots,"default",{},void 0,!0)]))}}),io=V(ro,[["__scopeId","data-v-39eca401"]]),lo=["aria-expanded","aria-label"],co={key:0,class:"text"},uo=["innerHTML"],po={key:1,class:"vpi-more-horizontal icon"},ho={class:"menu"},fo=k({__name:"VPFlyout",props:{icon:{},button:{},label:{},items:{}},setup(n){const e=T(!1),t=T();Js({el:t,onBlur:s});function s(){e.value=!1}return(o,a)=>(i(),h("div",{class:"VPFlyout",ref_key:"el",ref:t,onMouseenter:a[1]||(a[1]=r=>e.value=!0),onMouseleave:a[2]||(a[2]=r=>e.value=!1)},[d("button",{type:"button",class:"button","aria-haspopup":"true","aria-expanded":e.value,"aria-label":o.label,onClick:a[0]||(a[0]=r=>e.value=!e.value)},[o.button||o.icon?(i(),h("span",co,[o.icon?(i(),h("span",{key:0,class:A([o.icon,"option-icon"])},null,2)):g("",!0),o.button?(i(),h("span",{key:1,innerHTML:o.button},null,8,uo)):g("",!0),a[3]||(a[3]=d("span",{class:"vpi-chevron-down text-icon"},null,-1))])):(i(),h("span",po))],8,lo),d("div",ho,[y(io,{items:o.items},{default:f(()=>[p(o.$slots,"default",{},void 0,!0)]),_:3},8,["items"])])],544))}}),Ee=V(fo,[["__scopeId","data-v-40e55da0"]]),vo=["href","aria-label","innerHTML"],mo=k({__name:"VPSocialLink",props:{icon:{},link:{},ariaLabel:{}},setup(n){const e=n,t=T();Q(async()=>{var a;await Ie();const o=(a=t.value)==null?void 0:a.children[0];o instanceof HTMLElement&&o.className.startsWith("vpi-social-")&&(getComputedStyle(o).maskImage||getComputedStyle(o).webkitMaskImage)==="none"&&o.style.setProperty("--icon",`url('https://api.iconify.design/simple-icons/${e.icon}.svg')`)});const s=S(()=>typeof e.icon=="object"?e.icon.svg:``);return(o,a)=>(i(),h("a",{ref_key:"el",ref:t,class:"VPSocialLink no-icon",href:o.link,"aria-label":o.ariaLabel??(typeof o.icon=="string"?o.icon:""),target:"_blank",rel:"noopener",innerHTML:s.value},null,8,vo))}}),_o=V(mo,[["__scopeId","data-v-fbf39218"]]),go={class:"VPSocialLinks"},ko=k({__name:"VPSocialLinks",props:{links:{}},setup(n){return(e,t)=>(i(),h("div",go,[(i(!0),h(H,null,z(e.links,({link:s,icon:o,ariaLabel:a})=>(i(),P(_o,{key:s,icon:o,link:s,ariaLabel:a},null,8,["icon","link","ariaLabel"]))),128))]))}}),Oe=V(ko,[["__scopeId","data-v-f2234a39"]]),bo={key:0,class:"group translations"},$o={class:"trans-title"},yo={key:1,class:"group"},Po={class:"item appearance"},Lo={class:"label"},Vo={class:"appearance-action"},So={key:2,class:"group"},To={class:"item social-links"},wo=k({__name:"VPNavBarExtra",setup(n){const{site:e,theme:t}=M(),{localeLinks:s,currentLang:o}=ae({correspondingLink:!0}),a=S(()=>s.value.length&&o.value.label||e.value.appearance||t.value.socialLinks);return(r,l)=>a.value?(i(),P(Ee,{key:0,class:"VPNavBarExtra",label:"extra navigation"},{default:f(()=>[c(s).length&&c(o).label?(i(),h("div",bo,[d("p",$o,C(c(o).label),1),(i(!0),h(H,null,z(c(s),u=>(i(),P(ke,{key:u.link,item:u},null,8,["item"]))),128))])):g("",!0),c(e).appearance&&c(e).appearance!=="force-dark"&&c(e).appearance!=="force-auto"?(i(),h("div",yo,[d("div",Po,[d("p",Lo,C(c(t).darkModeSwitchLabel||"Appearance"),1),d("div",Vo,[y(He)])])])):g("",!0),c(t).socialLinks?(i(),h("div",So,[d("div",To,[y(Oe,{class:"social-links-list",links:c(t).socialLinks},null,8,["links"])])])):g("",!0)]),_:1})):g("",!0)}}),Mo=V(wo,[["__scopeId","data-v-0c845e5d"]]),No=["aria-expanded"],Io=k({__name:"VPNavBarHamburger",props:{active:{type:Boolean}},emits:["click"],setup(n){return(e,t)=>(i(),h("button",{type:"button",class:A(["VPNavBarHamburger",{active:e.active}]),"aria-label":"mobile navigation","aria-expanded":e.active,"aria-controls":"VPNavScreen",onClick:t[0]||(t[0]=s=>e.$emit("click"))},t[1]||(t[1]=[d("span",{class:"container"},[d("span",{class:"top"}),d("span",{class:"middle"}),d("span",{class:"bottom"})],-1)]),10,No))}}),Co=V(Io,[["__scopeId","data-v-670493dd"]]),Ao=["innerHTML"],Ho=k({__name:"VPNavBarMenuLink",props:{item:{}},setup(n){const{page:e}=M();return(t,s)=>(i(),P(K,{class:A({VPNavBarMenuLink:!0,active:c(te)(c(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,tabindex:"0"},{default:f(()=>[d("span",{innerHTML:t.item.text},null,8,Ao)]),_:1},8,["class","href","target","rel","no-icon"]))}}),Bo=V(Ho,[["__scopeId","data-v-8dbce4d0"]]),Eo=k({__name:"VPNavBarMenuGroup",props:{item:{}},setup(n){const e=n,{page:t}=M(),s=a=>"component"in a?!1:"link"in a?te(t.value.relativePath,a.link,!!e.item.activeMatch):a.items.some(s),o=S(()=>s(e.item));return(a,r)=>(i(),P(Ee,{class:A({VPNavBarMenuGroup:!0,active:c(te)(c(t).relativePath,a.item.activeMatch,!!a.item.activeMatch)||o.value}),button:a.item.text,items:a.item.items},null,8,["class","button","items"]))}}),Oo={key:0,"aria-labelledby":"main-nav-aria-label",class:"VPNavBarMenu"},Do=k({__name:"VPNavBarMenu",setup(n){const{theme:e}=M();return(t,s)=>c(e).nav?(i(),h("nav",Oo,[s[0]||(s[0]=d("span",{id:"main-nav-aria-label",class:"visually-hidden"}," Main Navigation ",-1)),(i(!0),h(H,null,z(c(e).nav,o=>(i(),h(H,{key:JSON.stringify(o)},["link"in o?(i(),P(Bo,{key:0,item:o},null,8,["item"])):"component"in o?(i(),P(W(o.component),Y({key:1,ref_for:!0},o.props),null,16)):(i(),P(Eo,{key:2,item:o},null,8,["item"]))],64))),128))])):g("",!0)}}),Fo=V(Do,[["__scopeId","data-v-5bacfe89"]]),zo="/document/assets/flex-logo.BJA2J7hW.svg";function $e(n,e){return typeof n>"u"?e:n}function ze(n){const e=Array(n);for(let t=0;t=this.minlength&&(l||!r[_])){let L=ie(u,o,v),b="";switch(this.tokenize){case"full":if(3$;N--)if(N-$>=this.minlength){const w=ie(u,o,v,m,$);b=_.substring($,N),this.push_index(r,b,w,n,t)}break}case"reverse":if(2=this.minlength){const N=ie(u,o,v,m,$);this.push_index(r,b,N,n,t)}b=""}case"forward":if(1=this.minlength&&this.push_index(r,b,L,n,t);break}default:if(this.boost&&(L=Math.min(0|L/this.boost(e,_,v),u-1)),this.push_index(r,_,L,n,t),l&&1=this.minlength&&!$[_]){$[_]=1;const R=ie(N+(o/2>N?0:1),o,v,O-1,F-1),X=this.bidirectional&&_>w;this.push_index(a,X?w:_,R,n,t,X?_:w)}}}}}this.fastupdate||(this.register[n]=1)}}return this};function ie(n,e,t,s,o){return t&&1=this.minlength&&!m[b]){if(!this.optimize&&!a&&!this.map[b])return r;L[N++]=b,m[b]=1}n=L,s=n.length}if(!s)return r;e||(e=100);let u,v=this.depth&&1=t)))));b++);if(v)return o?qe(l,t,0):void(n[n.length]=l)}return!e&&l};function qe(n,e,t){return n=n.length===1?n[0]:Uo(n),t||n.length>e?n.slice(t,t+e):n}function Ge(n,e,t,s){if(t){const o=s&&e>t;n=n[o?e:t],n=n&&n[o?t:e]}else n=n[e];return n}q.prototype.contain=function(n){return!!this.register[n]},q.prototype.update=function(n,e){return this.remove(n).add(n,e)},q.prototype.remove=function(n,e){const t=this.register[n];if(t){if(this.fastupdate)for(let s,o=0;o{if(a.value){for(var B=m.value.search(a.value,{enrich:!0}),I=[],j=0;j!B||!B.length?[]:B.reduce((j,E)=>(j[I(E)]||(j[I(E)]=[]),j[I(E)].push(E),j),{}),R=()=>{setTimeout(()=>{l.value&&l.value.focus()},100),De(),o.value=!0};Q(async()=>{var E,D;const B=await vt(()=>import("./virtual_search-data.B1Wl_n0C.js"),[]);u.value=B.default.INDEX_DATA,v.value=B.default.PREVIEW_LOOKUP,_.value=B.default.Options,r.value=window.location.origin+he(t.value==="root"?"/":t.value),L.value=((E=_.value)==null?void 0:E.buttonLabel)||L.value,b.value=((D=_.value)==null?void 0:D.placeholder)||b.value;var I=new q(_.value);I.import("reg",u.value.reg),I.import("cfg",u.value.cfg),I.import("map",u.value.map),I.import("ctx",u.value.ctx),m.value=I,s.value.innerHTML=/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?"⌘":"Ctrl";const j=U=>{var se;U.key==="k"&&(U.ctrlKey||U.metaKey)&&(U.preventDefault(),R()),U.key==="Escape"&&((se=a.value)==null?void 0:se.length)==0&&o.value&&(o.value=!1)};window.addEventListener("keydown",j)});const X=S(()=>F(O.value,B=>B.link.split("/").slice(0,-1).join("-"))),ne=S(()=>Object.values(X.value).flat().map(B=>B.id));function De(){o.value=!1,a.value=""}const at=B=>{var I,j;if(document.getElementsByClassName("search-group")[0]){if(B.key=="ArrowUp"||B.key=="ArrowDown"){const E=ne.value.indexOf($.value);if(B.key=="ArrowUp"){const D=E==0?ne.value.length-1:E-1;$.value=ne.value[D]}if(B.key=="ArrowDown"){const D=E>ne.value.length-2?0:E+1;$.value=ne.value[D]}if(E<5){const D=N.value.getElementsByClassName("VPPluginSearch-search-group")[0];D==null||D.scrollIntoView(!0)}else(I=document.getElementById(ne.value[$.value]))==null||I.scrollIntoView(!0);Ie()}B.key=="Enter"&&w.go(e.site.value.base+((j=N.value.getElementsByClassName("link-focused")[0].getAttribute("href"))==null?void 0:j.replace(r.value,"")))}};return(B,I)=>{const j=Z("ClientOnly");return i(),h("div",la,[y(j,null,{default:f(()=>[(i(),P(gt,{to:"body"},[Fe(d("div",{class:"VPPluginSearch-modal-back",onClick:I[2]||(I[2]=E=>o.value=!1),onKeydown:at},[d("div",{class:"VPPluginSearch-modal",onClick:I[1]||(I[1]=Xe(()=>{},["stop"])),ref_key:"modal",ref:N},[d("form",ca,[I[4]||(I[4]=d("label",{class:"DocSearch-MagnifierLabel",for:"docsearch-input",id:"docsearch-label"},[d("svg",{width:"20",height:"20",class:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},[d("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none","fill-rule":"evenodd","stroke-linecap":"round","stroke-linejoin":"round"})])],-1)),Fe(d("input",{class:"DocSearch-Input","aria-autocomplete":"both","aria-labelledby":"docsearch-label",id:"docsearch-input",autocomplete:"off",autocorrect:"off",autocapitalize:"off",enterkeyhint:"search",spellcheck:"false",autofocus:"true","onUpdate:modelValue":I[0]||(I[0]=E=>a.value=E),placeholder:b.value,maxlength:"64",type:"search",ref_key:"input",ref:l},null,8,ua),[[_t,a.value]])]),d("div",da,[(i(!0),h(H,null,z(X.value,(E,D)=>(i(),h("div",{class:"search-group",key:D},[d("span",pa,C(D?D.toString()[0].toUpperCase()+D.toString().slice(1):"Home"),1),(i(!0),h(H,null,z(E,(U,se)=>(i(),h("a",{href:r.value+U.link,key:U.id,onClick:De,onMouseenter:re=>$.value=U.id,class:A({"link-focused":$.value==U.id}),id:se.toString()},[d("div",fa,[d("span",va,C(U.link.includes("#")?"#":"▤"),1),d("div",ma,[d("h3",null,C(U.title),1),d("p",null,[d("div",{innerHTML:U.preview},null,8,_a)])]),I[5]||(I[5]=d("span",{class:"VPPluginSearch-search-item-icon"},"↪",-1))])],42,ha))),128))]))),128))]),I[6]||(I[6]=d("img",{class:"VPPluginSearch-flex-logo",src:zo,alt:"flex logo"},null,-1))],512)],544),[[mt,o.value]])]))]),_:1}),d("div",{id:"docsearch",onClick:I[3]||(I[3]=E=>R())},[d("button",ga,[d("span",ka,[I[7]||(I[7]=d("svg",{width:"20",height:"20",class:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},[d("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none","fill-rule":"evenodd","stroke-linecap":"round","stroke-linejoin":"round"})],-1)),d("span",ba,C(L.value),1)]),d("span",$a,[d("span",{class:"DocSearch-Button-Key",ref_key:"metaKey",ref:s},"Meta",512),I[8]||(I[8]=d("span",{class:"DocSearch-Button-Key"},"K",-1))])])])])}}}),Pa=k({__name:"VPNavBarSocialLinks",setup(n){const{theme:e}=M();return(t,s)=>c(e).socialLinks?(i(),P(Oe,{key:0,class:"VPNavBarSocialLinks",links:c(e).socialLinks},null,8,["links"])):g("",!0)}}),La=V(Pa,[["__scopeId","data-v-08b35e6f"]]),Va=["href","rel","target"],Sa=["innerHTML"],Ta={key:2},wa=k({__name:"VPNavBarTitle",setup(n){const{site:e,theme:t}=M(),{hasSidebar:s}=x(),{currentLang:o}=ae(),a=S(()=>{var u;return typeof t.value.logoLink=="string"?t.value.logoLink:(u=t.value.logoLink)==null?void 0:u.link}),r=S(()=>{var u;return typeof t.value.logoLink=="string"||(u=t.value.logoLink)==null?void 0:u.rel}),l=S(()=>{var u;return typeof t.value.logoLink=="string"||(u=t.value.logoLink)==null?void 0:u.target});return(u,v)=>(i(),h("div",{class:A(["VPNavBarTitle",{"has-sidebar":c(s)}])},[d("a",{class:"title",href:a.value??c(Ce)(c(o).link),rel:r.value,target:l.value},[p(u.$slots,"nav-bar-title-before",{},void 0,!0),c(t).logo?(i(),P(ue,{key:0,class:"logo",image:c(t).logo},null,8,["image"])):g("",!0),c(t).siteTitle?(i(),h("span",{key:1,innerHTML:c(t).siteTitle},null,8,Sa)):c(t).siteTitle===void 0?(i(),h("span",Ta,C(c(e).title),1)):g("",!0),p(u.$slots,"nav-bar-title-after",{},void 0,!0)],8,Va)],2))}}),Ma=V(wa,[["__scopeId","data-v-5622a072"]]),Na={class:"items"},Ia={class:"title"},Ca=k({__name:"VPNavBarTranslations",setup(n){const{theme:e}=M(),{localeLinks:t,currentLang:s}=ae({correspondingLink:!0});return(o,a)=>c(t).length&&c(s).label?(i(),P(Ee,{key:0,class:"VPNavBarTranslations",icon:"vpi-languages",label:c(e).langMenuLabel||"Change language"},{default:f(()=>[d("div",Na,[d("p",Ia,C(c(s).label),1),(i(!0),h(H,null,z(c(t),r=>(i(),P(ke,{key:r.link,item:r},null,8,["item"]))),128))])]),_:1},8,["label"])):g("",!0)}}),Aa=V(Ca,[["__scopeId","data-v-dac637f3"]]),Ha={class:"wrapper"},Ba={class:"container"},Ea={class:"title"},Oa={class:"content"},Da={class:"content-body"},Fa=k({__name:"VPNavBar",props:{isScreenOpen:{type:Boolean}},emits:["toggle-screen"],setup(n){const e=n,{y:t}=xe(),{hasSidebar:s}=x(),{frontmatter:o}=M(),a=T({});return Ne(()=>{a.value={"has-sidebar":s.value,home:o.value.layout==="home",top:t.value===0,"screen-open":e.isScreenOpen}}),(r,l)=>(i(),h("div",{class:A(["VPNavBar",a.value])},[d("div",Ha,[d("div",Ba,[d("div",Ea,[y(Ma,null,{"nav-bar-title-before":f(()=>[p(r.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[p(r.$slots,"nav-bar-title-after",{},void 0,!0)]),_:3})]),d("div",Oa,[d("div",Da,[p(r.$slots,"nav-bar-content-before",{},void 0,!0),y(ya,{class:"search"}),y(Fo,{class:"menu"}),y(Aa,{class:"translations"}),y(Ks,{class:"appearance"}),y(La,{class:"social-links"}),y(Mo,{class:"extra"}),p(r.$slots,"nav-bar-content-after",{},void 0,!0),y(Co,{class:"hamburger",active:r.isScreenOpen,onClick:l[0]||(l[0]=u=>r.$emit("toggle-screen"))},null,8,["active"])])])])]),l[1]||(l[1]=d("div",{class:"divider"},[d("div",{class:"divider-line"})],-1))],2))}}),za=V(Fa,[["__scopeId","data-v-bb7529ee"]]),ja={key:0,class:"VPNavScreenAppearance"},Ua={class:"text"},qa=k({__name:"VPNavScreenAppearance",setup(n){const{site:e,theme:t}=M();return(s,o)=>c(e).appearance&&c(e).appearance!=="force-dark"&&c(e).appearance!=="force-auto"?(i(),h("div",ja,[d("p",Ua,C(c(t).darkModeSwitchLabel||"Appearance"),1),y(He)])):g("",!0)}}),Ga=V(qa,[["__scopeId","data-v-774971f8"]]),Ra=["innerHTML"],Wa=k({__name:"VPNavScreenMenuLink",props:{item:{}},setup(n){const e=_e("close-screen");return(t,s)=>(i(),P(K,{class:"VPNavScreenMenuLink",href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,onClick:c(e)},{default:f(()=>[d("span",{innerHTML:t.item.text},null,8,Ra)]),_:1},8,["href","target","rel","no-icon","onClick"]))}}),Ka=V(Wa,[["__scopeId","data-v-29871565"]]),Ja=["innerHTML"],xa=k({__name:"VPNavScreenMenuGroupLink",props:{item:{}},setup(n){const e=_e("close-screen");return(t,s)=>(i(),P(K,{class:"VPNavScreenMenuGroupLink",href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,onClick:c(e)},{default:f(()=>[d("span",{innerHTML:t.item.text},null,8,Ja)]),_:1},8,["href","target","rel","no-icon","onClick"]))}}),ot=V(xa,[["__scopeId","data-v-581896e9"]]),Xa={class:"VPNavScreenMenuGroupSection"},Ya={key:0,class:"title"},Qa=k({__name:"VPNavScreenMenuGroupSection",props:{text:{},items:{}},setup(n){return(e,t)=>(i(),h("div",Xa,[e.text?(i(),h("p",Ya,C(e.text),1)):g("",!0),(i(!0),h(H,null,z(e.items,s=>(i(),P(ot,{key:s.text,item:s},null,8,["item"]))),128))]))}}),Za=V(Qa,[["__scopeId","data-v-836cddb8"]]),er=["aria-controls","aria-expanded"],tr=["innerHTML"],nr=["id"],sr={key:0,class:"item"},or={key:1,class:"item"},ar={key:2,class:"group"},rr=k({__name:"VPNavScreenMenuGroup",props:{text:{},items:{}},setup(n){const e=n,t=T(!1),s=S(()=>`NavScreenGroup-${e.text.replace(" ","-").toLowerCase()}`);function o(){t.value=!t.value}return(a,r)=>(i(),h("div",{class:A(["VPNavScreenMenuGroup",{open:t.value}])},[d("button",{class:"button","aria-controls":s.value,"aria-expanded":t.value,onClick:o},[d("span",{class:"button-text",innerHTML:a.text},null,8,tr),r[0]||(r[0]=d("span",{class:"vpi-plus button-icon"},null,-1))],8,er),d("div",{id:s.value,class:"items"},[(i(!0),h(H,null,z(a.items,l=>(i(),h(H,{key:JSON.stringify(l)},["link"in l?(i(),h("div",sr,[y(ot,{item:l},null,8,["item"])])):"component"in l?(i(),h("div",or,[(i(),P(W(l.component),Y({ref_for:!0},l.props,{"screen-menu":""}),null,16))])):(i(),h("div",ar,[y(Za,{text:l.text,items:l.items},null,8,["text","items"])]))],64))),128))],8,nr)],2))}}),ir=V(rr,[["__scopeId","data-v-a8d3502a"]]),lr={key:0,class:"VPNavScreenMenu"},cr=k({__name:"VPNavScreenMenu",setup(n){const{theme:e}=M();return(t,s)=>c(e).nav?(i(),h("nav",lr,[(i(!0),h(H,null,z(c(e).nav,o=>(i(),h(H,{key:JSON.stringify(o)},["link"in o?(i(),P(Ka,{key:0,item:o},null,8,["item"])):"component"in o?(i(),P(W(o.component),Y({key:1,ref_for:!0},o.props,{"screen-menu":""}),null,16)):(i(),P(ir,{key:2,text:o.text||"",items:o.items},null,8,["text","items"]))],64))),128))])):g("",!0)}}),ur=k({__name:"VPNavScreenSocialLinks",setup(n){const{theme:e}=M();return(t,s)=>c(e).socialLinks?(i(),P(Oe,{key:0,class:"VPNavScreenSocialLinks",links:c(e).socialLinks},null,8,["links"])):g("",!0)}}),dr={class:"list"},pr=k({__name:"VPNavScreenTranslations",setup(n){const{localeLinks:e,currentLang:t}=ae({correspondingLink:!0}),s=T(!1);function o(){s.value=!s.value}return(a,r)=>c(e).length&&c(t).label?(i(),h("div",{key:0,class:A(["VPNavScreenTranslations",{open:s.value}])},[d("button",{class:"title",onClick:o},[r[0]||(r[0]=d("span",{class:"vpi-languages icon lang"},null,-1)),ee(" "+C(c(t).label)+" ",1),r[1]||(r[1]=d("span",{class:"vpi-chevron-down icon chevron"},null,-1))]),d("ul",dr,[(i(!0),h(H,null,z(c(e),l=>(i(),h("li",{key:l.link,class:"item"},[y(K,{class:"link",href:l.link},{default:f(()=>[ee(C(l.text),1)]),_:2},1032,["href"])]))),128))])],2)):g("",!0)}}),hr=V(pr,[["__scopeId","data-v-0d43316b"]]),fr={class:"container"},vr=k({__name:"VPNavScreen",props:{open:{type:Boolean}},setup(n){const e=T(null),t=Ye(ge?document.body:null);return(s,o)=>(i(),P(we,{name:"fade",onEnter:o[0]||(o[0]=a=>t.value=!0),onAfterLeave:o[1]||(o[1]=a=>t.value=!1)},{default:f(()=>[s.open?(i(),h("div",{key:0,class:"VPNavScreen",ref_key:"screen",ref:e,id:"VPNavScreen"},[d("div",fr,[p(s.$slots,"nav-screen-content-before",{},void 0,!0),y(cr,{class:"menu"}),y(hr,{class:"translations"}),y(Ga,{class:"appearance"}),y(ur,{class:"social-links"}),p(s.$slots,"nav-screen-content-after",{},void 0,!0)])],512)):g("",!0)]),_:3}))}}),mr=V(vr,[["__scopeId","data-v-34fa79a7"]]),_r={key:0,class:"VPNav"},gr=k({__name:"VPNav",setup(n){const{isScreenOpen:e,closeScreen:t,toggleScreen:s}=Os(),{frontmatter:o}=M(),a=S(()=>o.value.navbar!==!1);return Qe("close-screen",t),fe(()=>{ge&&document.documentElement.classList.toggle("hide-nav",!a.value)}),(r,l)=>a.value?(i(),h("header",_r,[y(za,{"is-screen-open":c(e),onToggleScreen:c(s)},{"nav-bar-title-before":f(()=>[p(r.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[p(r.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":f(()=>[p(r.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":f(()=>[p(r.$slots,"nav-bar-content-after",{},void 0,!0)]),_:3},8,["is-screen-open","onToggleScreen"]),y(mr,{open:c(e)},{"nav-screen-content-before":f(()=>[p(r.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":f(()=>[p(r.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3},8,["open"])])):g("",!0)}}),kr=V(gr,[["__scopeId","data-v-a46e73f0"]]),br=["role","tabindex"],$r={key:1,class:"items"},yr=k({__name:"VPSidebarItem",props:{item:{},depth:{}},setup(n){const e=n,{collapsed:t,collapsible:s,isLink:o,isActiveLink:a,hasActiveLink:r,hasChildren:l,toggle:u}=zt(S(()=>e.item)),v=S(()=>l.value?"section":"div"),_=S(()=>o.value?"a":"div"),m=S(()=>l.value?e.depth+2===7?"p":`h${e.depth+2}`:"p"),L=S(()=>o.value?void 0:"button"),b=S(()=>[[`level-${e.depth}`],{collapsible:s.value},{collapsed:t.value},{"is-link":o.value},{"is-active":a.value},{"has-active":r.value}]);function $(w){"key"in w&&w.key!=="Enter"||!e.item.link&&u()}function N(){e.item.link&&u()}return(w,O)=>{const F=Z("VPSidebarItem",!0);return i(),P(W(v.value),{class:A(["VPSidebarItem",b.value])},{default:f(()=>[w.item.text?(i(),h("div",Y({key:0,class:"item",role:L.value},kt(w.item.items?{click:$,keydown:$}:{},!0),{tabindex:w.item.items&&0}),[O[1]||(O[1]=d("div",{class:"indicator"},null,-1)),w.item.link?(i(),P(K,{key:0,tag:_.value,class:"link",href:w.item.link,rel:w.item.rel,target:w.item.target},{default:f(()=>[(i(),P(W(m.value),{class:"text",innerHTML:w.item.text},null,8,["innerHTML"]))]),_:1},8,["tag","href","rel","target"])):(i(),P(W(m.value),{key:1,class:"text",innerHTML:w.item.text},null,8,["innerHTML"])),w.item.collapsed!=null&&w.item.items&&w.item.items.length?(i(),h("div",{key:2,class:"caret",role:"button","aria-label":"toggle section",onClick:N,onKeydown:bt(N,["enter"]),tabindex:"0"},O[0]||(O[0]=[d("span",{class:"vpi-chevron-right caret-icon"},null,-1)]),32)):g("",!0)],16,br)):g("",!0),w.item.items&&w.item.items.length?(i(),h("div",$r,[w.depth<5?(i(!0),h(H,{key:0},z(w.item.items,R=>(i(),P(F,{key:R.text,item:R,depth:w.depth+1},null,8,["item","depth"]))),128)):g("",!0)])):g("",!0)]),_:1},8,["class"])}}}),Pr=V(yr,[["__scopeId","data-v-2e0476bc"]]),Lr=k({__name:"VPSidebarGroup",props:{items:{}},setup(n){const e=T(!0);let t=null;return Q(()=>{t=setTimeout(()=>{t=null,e.value=!1},300)}),$t(()=>{t!=null&&(clearTimeout(t),t=null)}),(s,o)=>(i(!0),h(H,null,z(s.items,a=>(i(),h("div",{key:a.text,class:A(["group",{"no-transition":e.value}])},[y(Pr,{item:a,depth:0},null,8,["item"])],2))),128))}}),Vr=V(Lr,[["__scopeId","data-v-ec086cd5"]]),Sr={class:"nav",id:"VPSidebarNav","aria-labelledby":"sidebar-aria-label",tabindex:"-1"},Tr=k({__name:"VPSidebar",props:{open:{type:Boolean}},setup(n){const{sidebarGroups:e,hasSidebar:t}=x(),s=n,o=T(null),a=Ye(ge?document.body:null);J([s,o],()=>{var l;s.open?(a.value=!0,(l=o.value)==null||l.focus()):a.value=!1},{immediate:!0,flush:"post"});const r=T(0);return J(e,()=>{r.value+=1},{deep:!0}),(l,u)=>c(t)?(i(),h("aside",{key:0,class:A(["VPSidebar",{open:l.open}]),ref_key:"navEl",ref:o,onClick:u[0]||(u[0]=Xe(()=>{},["stop"]))},[u[2]||(u[2]=d("div",{class:"curtain"},null,-1)),d("nav",Sr,[u[1]||(u[1]=d("span",{class:"visually-hidden",id:"sidebar-aria-label"}," Sidebar Navigation ",-1)),p(l.$slots,"sidebar-nav-before",{},void 0,!0),(i(),P(Vr,{items:c(e),key:r.value},null,8,["items"])),p(l.$slots,"sidebar-nav-after",{},void 0,!0)])],2)):g("",!0)}}),wr=V(Tr,[["__scopeId","data-v-12a40e3d"]]),Mr=k({__name:"VPSkipLink",setup(n){const{theme:e}=M(),t=me(),s=T();J(()=>t.path,()=>s.value.focus());function o({target:a}){const r=document.getElementById(decodeURIComponent(a.hash).slice(1));if(r){const l=()=>{r.removeAttribute("tabindex"),r.removeEventListener("blur",l)};r.setAttribute("tabindex","-1"),r.addEventListener("blur",l),r.focus(),window.scrollTo(0,0)}}return(a,r)=>(i(),h(H,null,[d("span",{ref_key:"backToTop",ref:s,tabindex:"-1"},null,512),d("a",{href:"#VPContent",class:"VPSkipLink visually-hidden",onClick:o},C(c(e).skipToContentLabel||"Skip to content"),1)],64))}}),Nr=V(Mr,[["__scopeId","data-v-17ad389b"]]),Ir=k({__name:"Layout",setup(n){const{isOpen:e,open:t,close:s}=x(),o=me();J(()=>o.path,s),Ft(e,s);const{frontmatter:a}=M(),r=yt(),l=S(()=>!!r["home-hero-image"]);return Qe("hero-image-slot-exists",l),(u,v)=>{const _=Z("Content");return c(a).layout!==!1?(i(),h("div",{key:0,class:A(["Layout",c(a).pageClass])},[p(u.$slots,"layout-top",{},void 0,!0),y(Nr),y(St,{class:"backdrop",show:c(e),onClick:c(s)},null,8,["show","onClick"]),y(kr,null,{"nav-bar-title-before":f(()=>[p(u.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[p(u.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":f(()=>[p(u.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":f(()=>[p(u.$slots,"nav-bar-content-after",{},void 0,!0)]),"nav-screen-content-before":f(()=>[p(u.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":f(()=>[p(u.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3}),y(Es,{open:c(e),onOpenMenu:c(t)},null,8,["open","onOpenMenu"]),y(wr,{open:c(e)},{"sidebar-nav-before":f(()=>[p(u.$slots,"sidebar-nav-before",{},void 0,!0)]),"sidebar-nav-after":f(()=>[p(u.$slots,"sidebar-nav-after",{},void 0,!0)]),_:3},8,["open"]),y(bs,null,{"page-top":f(()=>[p(u.$slots,"page-top",{},void 0,!0)]),"page-bottom":f(()=>[p(u.$slots,"page-bottom",{},void 0,!0)]),"not-found":f(()=>[p(u.$slots,"not-found",{},void 0,!0)]),"home-hero-before":f(()=>[p(u.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":f(()=>[p(u.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[p(u.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[p(u.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[p(u.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[p(u.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":f(()=>[p(u.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":f(()=>[p(u.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":f(()=>[p(u.$slots,"home-features-after",{},void 0,!0)]),"doc-footer-before":f(()=>[p(u.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":f(()=>[p(u.$slots,"doc-before",{},void 0,!0)]),"doc-after":f(()=>[p(u.$slots,"doc-after",{},void 0,!0)]),"doc-top":f(()=>[p(u.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":f(()=>[p(u.$slots,"doc-bottom",{},void 0,!0)]),"aside-top":f(()=>[p(u.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":f(()=>[p(u.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":f(()=>[p(u.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[p(u.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[p(u.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[p(u.$slots,"aside-ads-after",{},void 0,!0)]),_:3}),y(Vs),p(u.$slots,"layout-bottom",{},void 0,!0)],2)):(i(),P(_,{key:1}))}}}),Cr=V(Ir,[["__scopeId","data-v-c4daae71"]]),Hr={Layout:Cr,enhanceApp:({app:n})=>{n.component("Badge",Pt)}};export{Hr as t}; +import{d as k,c as h,r as p,n as A,o as i,a as ee,t as C,b as P,w as f,T as we,e as g,_ as V,u as Re,i as it,f as lt,g as he,h as S,j as d,k as c,l as te,m as Pe,p as T,q as J,s as fe,v as Q,x as Me,y as Ne,z as ct,A as ut,F as H,B as z,C as Z,D as We,E as ve,G as y,H as W,I as Ke,J as me,K as Y,L as _e,M as dt,N as Je,O as pt,P as Ie,Q as xe,R as ge,S as ht,U as ft,V as vt,W as Fe,X as mt,Y as Xe,Z as _t,$ as gt,a0 as Ye,a1 as Qe,a2 as kt,a3 as bt,a4 as $t,a5 as yt}from"./framework.xxfEszSJ.js";const Pt=k({__name:"VPBadge",props:{text:{},type:{default:"tip"}},setup(n){return(e,t)=>(i(),h("span",{class:A(["VPBadge",e.type])},[p(e.$slots,"default",{},()=>[ee(C(e.text),1)])],2))}}),Lt={key:0,class:"VPBackdrop"},Vt=k({__name:"VPBackdrop",props:{show:{type:Boolean}},setup(n){return(e,t)=>(i(),P(we,{name:"fade"},{default:f(()=>[e.show?(i(),h("div",Lt)):g("",!0)]),_:1}))}}),St=V(Vt,[["__scopeId","data-v-b2600058"]]),M=Re;function Tt(n,e){let t,s=!1;return()=>{t&&clearTimeout(t),s?t=setTimeout(n,e):(n(),(s=!0)&&setTimeout(()=>s=!1,e))}}function Le(n){return n.startsWith("/")?n:`/${n}`}function Ce(n){const{pathname:e,search:t,hash:s,protocol:o}=new URL(n,"http://a.com");if(it(n)||n.startsWith("#")||!o.startsWith("http")||!lt(e))return n;const{site:a}=M(),r=e.endsWith("/")||e.endsWith(".html")?n:n.replace(/(?:(^\.+)\/)?.*$/,`$1${e.replace(/(\.md)?$/,a.value.cleanUrls?"":".html")}${t}${s}`);return he(r)}function ae({correspondingLink:n=!1}={}){const{site:e,localeIndex:t,page:s,theme:o,hash:a}=M(),r=S(()=>{var u,v;return{label:(u=e.value.locales[t.value])==null?void 0:u.label,link:((v=e.value.locales[t.value])==null?void 0:v.link)||(t.value==="root"?"/":`/${t.value}/`)}});return{localeLinks:S(()=>Object.entries(e.value.locales).flatMap(([u,v])=>r.value.label===v.label?[]:{text:v.label,link:wt(v.link||(u==="root"?"/":`/${u}/`),o.value.i18nRouting!==!1&&n,s.value.relativePath.slice(r.value.link.length-1),!e.value.cleanUrls)+a.value})),currentLang:r}}function wt(n,e,t,s){return e?n.replace(/\/$/,"")+Le(t.replace(/(^|\/)index\.md$/,"$1").replace(/\.md$/,s?".html":"")):n}const Mt={class:"NotFound"},Nt={class:"code"},It={class:"title"},Ct={class:"quote"},At={class:"action"},Ht=["href","aria-label"],Bt=k({__name:"NotFound",setup(n){const{theme:e}=M(),{currentLang:t}=ae();return(s,o)=>{var a,r,l,u,v;return i(),h("div",Mt,[d("p",Nt,C(((a=c(e).notFound)==null?void 0:a.code)??"404"),1),d("h1",It,C(((r=c(e).notFound)==null?void 0:r.title)??"PAGE NOT FOUND"),1),o[0]||(o[0]=d("div",{class:"divider"},null,-1)),d("blockquote",Ct,C(((l=c(e).notFound)==null?void 0:l.quote)??"But if you don't change your direction, and if you keep looking, you may end up where you are heading."),1),d("div",At,[d("a",{class:"link",href:c(he)(c(t).link),"aria-label":((u=c(e).notFound)==null?void 0:u.linkLabel)??"go to home"},C(((v=c(e).notFound)==null?void 0:v.linkText)??"Take me home"),9,Ht)])])}}}),Et=V(Bt,[["__scopeId","data-v-93fd8736"]]);function Ze(n,e){if(Array.isArray(n))return le(n);if(n==null)return[];e=Le(e);const t=Object.keys(n).sort((o,a)=>a.split("/").length-o.split("/").length).find(o=>e.startsWith(Le(o))),s=t?n[t]:[];return Array.isArray(s)?le(s):le(s.items,s.base)}function Ot(n){const e=[];let t=0;for(const s in n){const o=n[s];if(o.items){t=e.push(o);continue}e[t]||e.push({items:[]}),e[t].items.push(o)}return e}function Dt(n){const e=[];function t(s){for(const o of s)o.text&&o.link&&e.push({text:o.text,link:o.link,docFooterText:o.docFooterText}),o.items&&t(o.items)}return t(n),e}function Ve(n,e){return Array.isArray(e)?e.some(t=>Ve(n,t)):te(n,e.link)?!0:e.items?Ve(n,e.items):!1}function le(n,e){return[...n].map(t=>{const s={...t},o=s.base||e;return o&&s.link&&(s.link=o+s.link),s.items&&(s.items=le(s.items,o)),s})}function x(){const{frontmatter:n,page:e,theme:t}=M(),s=Pe("(min-width: 960px)"),o=T(!1),a=S(()=>{const N=t.value.sidebar,w=e.value.relativePath;return N?Ze(N,w):[]}),r=T(a.value);J(a,(N,w)=>{JSON.stringify(N)!==JSON.stringify(w)&&(r.value=a.value)});const l=S(()=>n.value.sidebar!==!1&&r.value.length>0&&n.value.layout!=="home"),u=S(()=>v?n.value.aside==null?t.value.aside==="left":n.value.aside==="left":!1),v=S(()=>n.value.layout==="home"?!1:n.value.aside!=null?!!n.value.aside:t.value.aside!==!1),_=S(()=>l.value&&s.value),m=S(()=>l.value?Ot(r.value):[]);function L(){o.value=!0}function b(){o.value=!1}function $(){o.value?b():L()}return{isOpen:o,sidebar:r,sidebarGroups:m,hasSidebar:l,hasAside:v,leftAside:u,isSidebarEnabled:_,open:L,close:b,toggle:$}}function Ft(n,e){let t;fe(()=>{t=n.value?document.activeElement:void 0}),Q(()=>{window.addEventListener("keyup",s)}),Me(()=>{window.removeEventListener("keyup",s)});function s(o){o.key==="Escape"&&n.value&&(e(),t==null||t.focus())}}function zt(n){const{page:e,hash:t}=M(),s=T(!1),o=S(()=>n.value.collapsed!=null),a=S(()=>!!n.value.link),r=T(!1),l=()=>{r.value=te(e.value.relativePath,n.value.link)};J([e,n,t],l),Q(l);const u=S(()=>r.value?!0:n.value.items?Ve(e.value.relativePath,n.value.items):!1),v=S(()=>!!(n.value.items&&n.value.items.length));fe(()=>{s.value=!!(o.value&&n.value.collapsed)}),Ne(()=>{(r.value||u.value)&&(s.value=!1)});function _(){o.value&&(s.value=!s.value)}return{collapsed:s,collapsible:o,isLink:a,isActiveLink:r,hasActiveLink:u,hasChildren:v,toggle:_}}function jt(){const{hasSidebar:n}=x(),e=Pe("(min-width: 960px)"),t=Pe("(min-width: 1280px)");return{isAsideEnabled:S(()=>!t.value&&!e.value?!1:n.value?t.value:e.value)}}const Ut=/\b(?:VPBadge|header-anchor|footnote-ref|ignore-header)\b/,Se=[];function et(n){return typeof n.outline=="object"&&!Array.isArray(n.outline)&&n.outline.label||n.outlineTitle||"On this page"}function Ae(n){const e=[...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")].filter(t=>t.id&&t.hasChildNodes()).map(t=>{const s=Number(t.tagName[1]);return{element:t,title:qt(t),link:"#"+t.id,level:s}});return Gt(e,n)}function qt(n){let e="";for(const t of n.childNodes)if(t.nodeType===1){if(Ut.test(t.className))continue;e+=t.textContent}else t.nodeType===3&&(e+=t.textContent);return e.trim()}function Gt(n,e){if(e===!1)return[];const t=(typeof e=="object"&&!Array.isArray(e)?e.level:e)||2,[s,o]=typeof t=="number"?[t,t]:t==="deep"?[2,6]:t;return Kt(n,s,o)}function Rt(n,e){const{isAsideEnabled:t}=jt(),s=Tt(a,100);let o=null;Q(()=>{requestAnimationFrame(a),window.addEventListener("scroll",s)}),ct(()=>{r(location.hash)}),Me(()=>{window.removeEventListener("scroll",s)});function a(){if(!t.value)return;const l=window.scrollY,u=window.innerHeight,v=document.body.offsetHeight,_=Math.abs(l+u-v)<1,m=Se.map(({element:b,link:$})=>({link:$,top:Wt(b)})).filter(({top:b})=>!Number.isNaN(b)).sort((b,$)=>b.top-$.top);if(!m.length){r(null);return}if(l<1){r(null);return}if(_){r(m[m.length-1].link);return}let L=null;for(const{link:b,top:$}of m){if($>l+ut()+4)break;L=b}r(L)}function r(l){o&&o.classList.remove("active"),l==null?o=null:o=n.value.querySelector(`a[href="${decodeURIComponent(l)}"]`);const u=o;u?(u.classList.add("active"),e.value.style.top=u.offsetTop+39+"px",e.value.style.opacity="1"):(e.value.style.top="33px",e.value.style.opacity="0")}}function Wt(n){let e=0;for(;n!==document.body;){if(n===null)return NaN;e+=n.offsetTop,n=n.offsetParent}return e}function Kt(n,e,t){Se.length=0;const s=[],o=[];return n.forEach(a=>{const r={...a,children:[]};let l=o[o.length-1];for(;l&&l.level>=r.level;)o.pop(),l=o[o.length-1];if(r.element.classList.contains("ignore-header")||l&&"shouldIgnore"in l){o.push({level:r.level,shouldIgnore:!0});return}r.level>t||r.level{const o=Z("VPDocOutlineItem",!0);return i(),h("ul",{class:A(["VPDocOutlineItem",t.root?"root":"nested"])},[(i(!0),h(H,null,z(t.headers,({children:a,link:r,title:l})=>(i(),h("li",null,[d("a",{class:"outline-link",href:r,onClick:e,title:l},C(l),9,Jt),a!=null&&a.length?(i(),P(o,{key:0,headers:a},null,8,["headers"])):g("",!0)]))),256))],2)}}}),tt=V(xt,[["__scopeId","data-v-da421f78"]]),Xt={class:"content"},Yt={"aria-level":"2",class:"outline-title",id:"doc-outline-aria-label",role:"heading"},Qt=k({__name:"VPDocAsideOutline",setup(n){const{frontmatter:e,theme:t}=M(),s=We([]);ve(()=>{s.value=Ae(e.value.outline??t.value.outline)});const o=T(),a=T();return Rt(o,a),(r,l)=>(i(),h("nav",{"aria-labelledby":"doc-outline-aria-label",class:A(["VPDocAsideOutline",{"has-outline":s.value.length>0}]),ref_key:"container",ref:o},[d("div",Xt,[d("div",{class:"outline-marker",ref_key:"marker",ref:a},null,512),d("div",Yt,C(c(et)(c(t))),1),y(tt,{headers:s.value,root:!0},null,8,["headers"])])],2))}}),Zt=V(Qt,[["__scopeId","data-v-dfbd9fb8"]]),en={class:"VPDocAsideCarbonAds"},tn=k({__name:"VPDocAsideCarbonAds",props:{carbonAds:{}},setup(n){const e=()=>null;return(t,s)=>(i(),h("div",en,[y(c(e),{"carbon-ads":t.carbonAds},null,8,["carbon-ads"])]))}}),nn={class:"VPDocAside"},sn=k({__name:"VPDocAside",setup(n){const{theme:e}=M();return(t,s)=>(i(),h("div",nn,[p(t.$slots,"aside-top",{},void 0,!0),p(t.$slots,"aside-outline-before",{},void 0,!0),y(Zt),p(t.$slots,"aside-outline-after",{},void 0,!0),s[0]||(s[0]=d("div",{class:"spacer"},null,-1)),p(t.$slots,"aside-ads-before",{},void 0,!0),c(e).carbonAds?(i(),P(tn,{key:0,"carbon-ads":c(e).carbonAds},null,8,["carbon-ads"])):g("",!0),p(t.$slots,"aside-ads-after",{},void 0,!0),p(t.$slots,"aside-bottom",{},void 0,!0)]))}}),on=V(sn,[["__scopeId","data-v-79cae1a0"]]);function an(){const{theme:n,page:e}=M();return S(()=>{const{text:t="Edit this page",pattern:s=""}=n.value.editLink||{};let o;return typeof s=="function"?o=s(e.value):o=s.replace(/:path/g,e.value.filePath),{url:o,text:t}})}function rn(){const{page:n,theme:e,frontmatter:t}=M();return S(()=>{var v,_,m,L,b,$,N,w;const s=Ze(e.value.sidebar,n.value.relativePath),o=Dt(s),a=ln(o,O=>O.link.replace(/[?#].*$/,"")),r=a.findIndex(O=>te(n.value.relativePath,O.link)),l=((v=e.value.docFooter)==null?void 0:v.prev)===!1&&!t.value.prev||t.value.prev===!1,u=((_=e.value.docFooter)==null?void 0:_.next)===!1&&!t.value.next||t.value.next===!1;return{prev:l?void 0:{text:(typeof t.value.prev=="string"?t.value.prev:typeof t.value.prev=="object"?t.value.prev.text:void 0)??((m=a[r-1])==null?void 0:m.docFooterText)??((L=a[r-1])==null?void 0:L.text),link:(typeof t.value.prev=="object"?t.value.prev.link:void 0)??((b=a[r-1])==null?void 0:b.link)},next:u?void 0:{text:(typeof t.value.next=="string"?t.value.next:typeof t.value.next=="object"?t.value.next.text:void 0)??(($=a[r+1])==null?void 0:$.docFooterText)??((N=a[r+1])==null?void 0:N.text),link:(typeof t.value.next=="object"?t.value.next.link:void 0)??((w=a[r+1])==null?void 0:w.link)}}})}function ln(n,e){const t=new Set;return n.filter(s=>{const o=e(s);return t.has(o)?!1:t.add(o)})}const K=k({__name:"VPLink",props:{tag:{},href:{},noIcon:{type:Boolean},target:{},rel:{}},setup(n){const e=n,t=S(()=>e.tag??(e.href?"a":"span")),s=S(()=>e.href&&Ke.test(e.href)||e.target==="_blank");return(o,a)=>(i(),P(W(t.value),{class:A(["VPLink",{link:o.href,"vp-external-link-icon":s.value,"no-icon":o.noIcon}]),href:o.href?c(Ce)(o.href):void 0,target:o.target??(s.value?"_blank":void 0),rel:o.rel??(s.value?"noreferrer":void 0)},{default:f(()=>[p(o.$slots,"default")]),_:3},8,["class","href","target","rel"]))}}),cn={class:"VPLastUpdated"},un=["datetime"],dn=k({__name:"VPDocFooterLastUpdated",setup(n){const{theme:e,page:t,lang:s}=M(),o=S(()=>new Date(t.value.lastUpdated)),a=S(()=>o.value.toISOString()),r=T("");return Q(()=>{fe(()=>{var l,u,v;r.value=new Intl.DateTimeFormat((u=(l=e.value.lastUpdated)==null?void 0:l.formatOptions)!=null&&u.forceLocale?s.value:void 0,((v=e.value.lastUpdated)==null?void 0:v.formatOptions)??{dateStyle:"short",timeStyle:"short"}).format(o.value)})}),(l,u)=>{var v;return i(),h("p",cn,[ee(C(((v=c(e).lastUpdated)==null?void 0:v.text)||c(e).lastUpdatedText||"Last updated")+": ",1),d("time",{datetime:a.value},C(r.value),9,un)])}}}),pn=V(dn,[["__scopeId","data-v-e95db471"]]),hn={key:0,class:"VPDocFooter"},fn={key:0,class:"edit-info"},vn={key:0,class:"edit-link"},mn={key:1,class:"last-updated"},_n={key:1,class:"prev-next","aria-labelledby":"doc-footer-aria-label"},gn={class:"pager"},kn=["innerHTML"],bn=["innerHTML"],$n={class:"pager"},yn=["innerHTML"],Pn=["innerHTML"],Ln=k({__name:"VPDocFooter",setup(n){const{theme:e,page:t,frontmatter:s}=M(),o=an(),a=rn(),r=S(()=>e.value.editLink&&s.value.editLink!==!1),l=S(()=>t.value.lastUpdated),u=S(()=>r.value||l.value||a.value.prev||a.value.next);return(v,_)=>{var m,L,b,$;return u.value?(i(),h("footer",hn,[p(v.$slots,"doc-footer-before",{},void 0,!0),r.value||l.value?(i(),h("div",fn,[r.value?(i(),h("div",vn,[y(K,{class:"edit-link-button",href:c(o).url,"no-icon":!0},{default:f(()=>[_[0]||(_[0]=d("span",{class:"vpi-square-pen edit-link-icon"},null,-1)),ee(" "+C(c(o).text),1)]),_:1},8,["href"])])):g("",!0),l.value?(i(),h("div",mn,[y(pn)])):g("",!0)])):g("",!0),(m=c(a).prev)!=null&&m.link||(L=c(a).next)!=null&&L.link?(i(),h("nav",_n,[_[1]||(_[1]=d("span",{class:"visually-hidden",id:"doc-footer-aria-label"},"Pager",-1)),d("div",gn,[(b=c(a).prev)!=null&&b.link?(i(),P(K,{key:0,class:"pager-link prev",href:c(a).prev.link},{default:f(()=>{var N;return[d("span",{class:"desc",innerHTML:((N=c(e).docFooter)==null?void 0:N.prev)||"Previous page"},null,8,kn),d("span",{class:"title",innerHTML:c(a).prev.text},null,8,bn)]}),_:1},8,["href"])):g("",!0)]),d("div",$n,[($=c(a).next)!=null&&$.link?(i(),P(K,{key:0,class:"pager-link next",href:c(a).next.link},{default:f(()=>{var N;return[d("span",{class:"desc",innerHTML:((N=c(e).docFooter)==null?void 0:N.next)||"Next page"},null,8,yn),d("span",{class:"title",innerHTML:c(a).next.text},null,8,Pn)]}),_:1},8,["href"])):g("",!0)])])):g("",!0)])):g("",!0)}}}),Vn=V(Ln,[["__scopeId","data-v-07d71ff1"]]),Sn={class:"container"},Tn={class:"aside-container"},wn={class:"aside-content"},Mn={class:"content"},Nn={class:"content-container"},In={class:"main"},Cn=k({__name:"VPDoc",setup(n){const{theme:e}=M(),t=me(),{hasSidebar:s,hasAside:o,leftAside:a}=x(),r=S(()=>t.path.replace(/[./]+/g,"_").replace(/_html$/,""));return(l,u)=>{const v=Z("Content");return i(),h("div",{class:A(["VPDoc",{"has-sidebar":c(s),"has-aside":c(o)}])},[p(l.$slots,"doc-top",{},void 0,!0),d("div",Sn,[c(o)?(i(),h("div",{key:0,class:A(["aside",{"left-aside":c(a)}])},[u[0]||(u[0]=d("div",{class:"aside-curtain"},null,-1)),d("div",Tn,[d("div",wn,[y(on,null,{"aside-top":f(()=>[p(l.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":f(()=>[p(l.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":f(()=>[p(l.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[p(l.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[p(l.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[p(l.$slots,"aside-ads-after",{},void 0,!0)]),_:3})])])],2)):g("",!0),d("div",Mn,[d("div",Nn,[p(l.$slots,"doc-before",{},void 0,!0),d("main",In,[y(v,{class:A(["vp-doc",[r.value,c(e).externalLinkIcon&&"external-link-icon-enabled"]])},null,8,["class"])]),y(Vn,null,{"doc-footer-before":f(()=>[p(l.$slots,"doc-footer-before",{},void 0,!0)]),_:3}),p(l.$slots,"doc-after",{},void 0,!0)])])]),p(l.$slots,"doc-bottom",{},void 0,!0)],2)}}}),An=V(Cn,[["__scopeId","data-v-ef3a4dda"]]),Hn=k({__name:"VPButton",props:{tag:{},size:{default:"medium"},theme:{default:"brand"},text:{},href:{},target:{},rel:{}},setup(n){const e=n,t=S(()=>e.href&&Ke.test(e.href)),s=S(()=>e.tag||(e.href?"a":"button"));return(o,a)=>(i(),P(W(s.value),{class:A(["VPButton",[o.size,o.theme]]),href:o.href?c(Ce)(o.href):void 0,target:e.target??(t.value?"_blank":void 0),rel:e.rel??(t.value?"noreferrer":void 0)},{default:f(()=>[ee(C(o.text),1)]),_:1},8,["class","href","target","rel"]))}}),Bn=V(Hn,[["__scopeId","data-v-b20c43c2"]]),En=["src","alt"],On=k({inheritAttrs:!1,__name:"VPImage",props:{image:{},alt:{}},setup(n){return(e,t)=>{const s=Z("VPImage",!0);return e.image?(i(),h(H,{key:0},[typeof e.image=="string"||"src"in e.image?(i(),h("img",Y({key:0,class:"VPImage"},typeof e.image=="string"?e.$attrs:{...e.image,...e.$attrs},{src:c(he)(typeof e.image=="string"?e.image:e.image.src),alt:e.alt??(typeof e.image=="string"?"":e.image.alt||"")}),null,16,En)):(i(),h(H,{key:1},[y(s,Y({class:"dark",image:e.image.dark,alt:e.image.alt},e.$attrs),null,16,["image","alt"]),y(s,Y({class:"light",image:e.image.light,alt:e.image.alt},e.$attrs),null,16,["image","alt"])],64))],64)):g("",!0)}}}),ue=V(On,[["__scopeId","data-v-4d414b82"]]),Dn={class:"container"},Fn={class:"main"},zn={class:"heading"},jn=["innerHTML"],Un=["innerHTML"],qn=["innerHTML"],Gn={key:0,class:"actions"},Rn={key:0,class:"image"},Wn={class:"image-container"},Kn=k({__name:"VPHero",props:{name:{},text:{},tagline:{},image:{},actions:{}},setup(n){const e=_e("hero-image-slot-exists");return(t,s)=>(i(),h("div",{class:A(["VPHero",{"has-image":t.image||c(e)}])},[d("div",Dn,[d("div",Fn,[p(t.$slots,"home-hero-info-before",{},void 0,!0),p(t.$slots,"home-hero-info",{},()=>[d("h1",zn,[t.name?(i(),h("span",{key:0,innerHTML:t.name,class:"name clip"},null,8,jn)):g("",!0),t.text?(i(),h("span",{key:1,innerHTML:t.text,class:"text"},null,8,Un)):g("",!0)]),t.tagline?(i(),h("p",{key:0,innerHTML:t.tagline,class:"tagline"},null,8,qn)):g("",!0)],!0),p(t.$slots,"home-hero-info-after",{},void 0,!0),t.actions?(i(),h("div",Gn,[(i(!0),h(H,null,z(t.actions,o=>(i(),h("div",{key:o.link,class:"action"},[y(Bn,{tag:"a",size:"medium",theme:o.theme,text:o.text,href:o.link,target:o.target,rel:o.rel},null,8,["theme","text","href","target","rel"])]))),128))])):g("",!0),p(t.$slots,"home-hero-actions-after",{},void 0,!0)]),t.image||c(e)?(i(),h("div",Rn,[d("div",Wn,[s[0]||(s[0]=d("div",{class:"image-bg"},null,-1)),p(t.$slots,"home-hero-image",{},()=>[t.image?(i(),P(ue,{key:0,class:"image-src",image:t.image},null,8,["image"])):g("",!0)],!0)])])):g("",!0)])],2))}}),Jn=V(Kn,[["__scopeId","data-v-d266baba"]]),xn=k({__name:"VPHomeHero",setup(n){const{frontmatter:e}=M();return(t,s)=>c(e).hero?(i(),P(Jn,{key:0,class:"VPHomeHero",name:c(e).hero.name,text:c(e).hero.text,tagline:c(e).hero.tagline,image:c(e).hero.image,actions:c(e).hero.actions},{"home-hero-info-before":f(()=>[p(t.$slots,"home-hero-info-before")]),"home-hero-info":f(()=>[p(t.$slots,"home-hero-info")]),"home-hero-info-after":f(()=>[p(t.$slots,"home-hero-info-after")]),"home-hero-actions-after":f(()=>[p(t.$slots,"home-hero-actions-after")]),"home-hero-image":f(()=>[p(t.$slots,"home-hero-image")]),_:3},8,["name","text","tagline","image","actions"])):g("",!0)}}),Xn={class:"box"},Yn={key:0,class:"icon"},Qn=["innerHTML"],Zn=["innerHTML"],es=["innerHTML"],ts={key:4,class:"link-text"},ns={class:"link-text-value"},ss=k({__name:"VPFeature",props:{icon:{},title:{},details:{},link:{},linkText:{},rel:{},target:{}},setup(n){return(e,t)=>(i(),P(K,{class:"VPFeature",href:e.link,rel:e.rel,target:e.target,"no-icon":!0,tag:e.link?"a":"div"},{default:f(()=>[d("article",Xn,[typeof e.icon=="object"&&e.icon.wrap?(i(),h("div",Yn,[y(ue,{image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])])):typeof e.icon=="object"?(i(),P(ue,{key:1,image:e.icon,alt:e.icon.alt,height:e.icon.height||48,width:e.icon.width||48},null,8,["image","alt","height","width"])):e.icon?(i(),h("div",{key:2,class:"icon",innerHTML:e.icon},null,8,Qn)):g("",!0),d("h2",{class:"title",innerHTML:e.title},null,8,Zn),e.details?(i(),h("p",{key:3,class:"details",innerHTML:e.details},null,8,es)):g("",!0),e.linkText?(i(),h("div",ts,[d("p",ns,[ee(C(e.linkText)+" ",1),t[0]||(t[0]=d("span",{class:"vpi-arrow-right link-text-icon"},null,-1))])])):g("",!0)])]),_:1},8,["href","rel","target","tag"]))}}),os=V(ss,[["__scopeId","data-v-95001937"]]),as={key:0,class:"VPFeatures"},rs={class:"container"},is={class:"items"},ls=k({__name:"VPFeatures",props:{features:{}},setup(n){const e=n,t=S(()=>{const s=e.features.length;if(s){if(s===2)return"grid-2";if(s===3)return"grid-3";if(s%3===0)return"grid-6";if(s>3)return"grid-4"}else return});return(s,o)=>s.features?(i(),h("div",as,[d("div",rs,[d("div",is,[(i(!0),h(H,null,z(s.features,a=>(i(),h("div",{key:a.title,class:A(["item",[t.value]])},[y(os,{icon:a.icon,title:a.title,details:a.details,link:a.link,"link-text":a.linkText,rel:a.rel,target:a.target},null,8,["icon","title","details","link","link-text","rel","target"])],2))),128))])])])):g("",!0)}}),cs=V(ls,[["__scopeId","data-v-1da4ff3d"]]),us=k({__name:"VPHomeFeatures",setup(n){const{frontmatter:e}=M();return(t,s)=>c(e).features?(i(),P(cs,{key:0,class:"VPHomeFeatures",features:c(e).features},null,8,["features"])):g("",!0)}}),ds=k({__name:"VPHomeContent",setup(n){const{width:e}=dt({initialWidth:0,includeScrollbar:!1});return(t,s)=>(i(),h("div",{class:"vp-doc container",style:Je(c(e)?{"--vp-offset":`calc(50% - ${c(e)/2}px)`}:{})},[p(t.$slots,"default",{},void 0,!0)],4))}}),ps=V(ds,[["__scopeId","data-v-2498cc33"]]),hs=k({__name:"VPHome",setup(n){const{frontmatter:e,theme:t}=M();return(s,o)=>{const a=Z("Content");return i(),h("div",{class:A(["VPHome",{"external-link-icon-enabled":c(t).externalLinkIcon}])},[p(s.$slots,"home-hero-before",{},void 0,!0),y(xn,null,{"home-hero-info-before":f(()=>[p(s.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[p(s.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[p(s.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[p(s.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[p(s.$slots,"home-hero-image",{},void 0,!0)]),_:3}),p(s.$slots,"home-hero-after",{},void 0,!0),p(s.$slots,"home-features-before",{},void 0,!0),y(us),p(s.$slots,"home-features-after",{},void 0,!0),c(e).markdownStyles!==!1?(i(),P(ps,{key:0},{default:f(()=>[y(a)]),_:1})):(i(),P(a,{key:1}))],2)}}}),fs=V(hs,[["__scopeId","data-v-8b59c434"]]),vs={},ms={class:"VPPage"};function _s(n,e){const t=Z("Content");return i(),h("div",ms,[p(n.$slots,"page-top"),y(t),p(n.$slots,"page-bottom")])}const gs=V(vs,[["render",_s]]),ks=k({__name:"VPContent",setup(n){const{page:e,frontmatter:t}=M(),{hasSidebar:s}=x();return(o,a)=>(i(),h("div",{class:A(["VPContent",{"has-sidebar":c(s),"is-home":c(t).layout==="home"}]),id:"VPContent"},[c(e).isNotFound?p(o.$slots,"not-found",{key:0},()=>[y(Et)],!0):c(t).layout==="page"?(i(),P(gs,{key:1},{"page-top":f(()=>[p(o.$slots,"page-top",{},void 0,!0)]),"page-bottom":f(()=>[p(o.$slots,"page-bottom",{},void 0,!0)]),_:3})):c(t).layout==="home"?(i(),P(fs,{key:2},{"home-hero-before":f(()=>[p(o.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":f(()=>[p(o.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[p(o.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[p(o.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[p(o.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[p(o.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":f(()=>[p(o.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":f(()=>[p(o.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":f(()=>[p(o.$slots,"home-features-after",{},void 0,!0)]),_:3})):c(t).layout&&c(t).layout!=="doc"?(i(),P(W(c(t).layout),{key:3})):(i(),P(An,{key:4},{"doc-top":f(()=>[p(o.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":f(()=>[p(o.$slots,"doc-bottom",{},void 0,!0)]),"doc-footer-before":f(()=>[p(o.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":f(()=>[p(o.$slots,"doc-before",{},void 0,!0)]),"doc-after":f(()=>[p(o.$slots,"doc-after",{},void 0,!0)]),"aside-top":f(()=>[p(o.$slots,"aside-top",{},void 0,!0)]),"aside-outline-before":f(()=>[p(o.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[p(o.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[p(o.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[p(o.$slots,"aside-ads-after",{},void 0,!0)]),"aside-bottom":f(()=>[p(o.$slots,"aside-bottom",{},void 0,!0)]),_:3}))],2))}}),bs=V(ks,[["__scopeId","data-v-d2aef184"]]),$s={class:"container"},ys=["innerHTML"],Ps=["innerHTML"],Ls=k({__name:"VPFooter",setup(n){const{theme:e,frontmatter:t}=M(),{hasSidebar:s}=x();return(o,a)=>c(e).footer&&c(t).footer!==!1?(i(),h("footer",{key:0,class:A(["VPFooter",{"has-sidebar":c(s)}])},[d("div",$s,[c(e).footer.message?(i(),h("p",{key:0,class:"message",innerHTML:c(e).footer.message},null,8,ys)):g("",!0),c(e).footer.copyright?(i(),h("p",{key:1,class:"copyright",innerHTML:c(e).footer.copyright},null,8,Ps)):g("",!0)])],2)):g("",!0)}}),Vs=V(Ls,[["__scopeId","data-v-e3157d6d"]]);function Ss(){const{theme:n,frontmatter:e}=M(),t=We([]),s=S(()=>t.value.length>0);return ve(()=>{t.value=Ae(e.value.outline??n.value.outline)}),{headers:t,hasLocalNav:s}}const Ts={class:"menu-text"},ws={class:"header"},Ms={class:"outline"},Ns=k({__name:"VPLocalNavOutlineDropdown",props:{headers:{},navHeight:{}},setup(n){const e=n,{theme:t}=M(),s=T(!1),o=T(0),a=T(),r=T();function l(m){var L;(L=a.value)!=null&&L.contains(m.target)||(s.value=!1)}J(s,m=>{if(m){document.addEventListener("click",l);return}document.removeEventListener("click",l)}),pt("Escape",()=>{s.value=!1}),ve(()=>{s.value=!1});function u(){s.value=!s.value,o.value=window.innerHeight+Math.min(window.scrollY-e.navHeight,0)}function v(m){m.target.classList.contains("outline-link")&&(r.value&&(r.value.style.transition="none"),Ie(()=>{s.value=!1}))}function _(){s.value=!1,window.scrollTo({top:0,left:0,behavior:"smooth"})}return(m,L)=>(i(),h("div",{class:"VPLocalNavOutlineDropdown",style:Je({"--vp-vh":o.value+"px"}),ref_key:"main",ref:a},[m.headers.length>0?(i(),h("button",{key:0,onClick:u,class:A({open:s.value})},[d("span",Ts,C(c(et)(c(t))),1),L[0]||(L[0]=d("span",{class:"vpi-chevron-right icon"},null,-1))],2)):(i(),h("button",{key:1,onClick:_},C(c(t).returnToTopLabel||"Return to top"),1)),y(we,{name:"flyout"},{default:f(()=>[s.value?(i(),h("div",{key:0,ref_key:"items",ref:r,class:"items",onClick:v},[d("div",ws,[d("a",{class:"top-link",href:"#",onClick:_},C(c(t).returnToTopLabel||"Return to top"),1)]),d("div",Ms,[y(tt,{headers:m.headers},null,8,["headers"])])],512)):g("",!0)]),_:1})],4))}}),Is=V(Ns,[["__scopeId","data-v-d61422fe"]]),Cs={class:"container"},As=["aria-expanded"],Hs={class:"menu-text"},Bs=k({__name:"VPLocalNav",props:{open:{type:Boolean}},emits:["open-menu"],setup(n){const{theme:e,frontmatter:t}=M(),{hasSidebar:s}=x(),{headers:o}=Ss(),{y:a}=xe(),r=T(0);Q(()=>{r.value=parseInt(getComputedStyle(document.documentElement).getPropertyValue("--vp-nav-height"))}),ve(()=>{o.value=Ae(t.value.outline??e.value.outline)});const l=S(()=>o.value.length===0),u=S(()=>l.value&&!s.value),v=S(()=>({VPLocalNav:!0,"has-sidebar":s.value,empty:l.value,fixed:u.value}));return(_,m)=>c(t).layout!=="home"&&(!u.value||c(a)>=r.value)?(i(),h("div",{key:0,class:A(v.value)},[d("div",Cs,[c(s)?(i(),h("button",{key:0,class:"menu","aria-expanded":_.open,"aria-controls":"VPSidebarNav",onClick:m[0]||(m[0]=L=>_.$emit("open-menu"))},[m[1]||(m[1]=d("span",{class:"vpi-align-left menu-icon"},null,-1)),d("span",Hs,C(c(e).sidebarMenuLabel||"Menu"),1)],8,As)):g("",!0),y(Is,{headers:c(o),navHeight:r.value},null,8,["headers","navHeight"])])],2)):g("",!0)}}),Es=V(Bs,[["__scopeId","data-v-9d8129cc"]]);function Os(){const n=T(!1);function e(){n.value=!0,window.addEventListener("resize",o)}function t(){n.value=!1,window.removeEventListener("resize",o)}function s(){n.value?t():e()}function o(){window.outerWidth>=768&&t()}const a=me();return J(()=>a.path,t),{isScreenOpen:n,openScreen:e,closeScreen:t,toggleScreen:s}}const Ds={},Fs={class:"VPSwitch",type:"button",role:"switch"},zs={class:"check"},js={key:0,class:"icon"};function Us(n,e){return i(),h("button",Fs,[d("span",zs,[n.$slots.default?(i(),h("span",js,[p(n.$slots,"default",{},void 0,!0)])):g("",!0)])])}const qs=V(Ds,[["render",Us],["__scopeId","data-v-7012e5dd"]]),Gs=k({__name:"VPSwitchAppearance",setup(n){const{isDark:e,theme:t}=M(),s=_e("toggle-appearance",()=>{e.value=!e.value}),o=T("");return Ne(()=>{o.value=e.value?t.value.lightModeSwitchTitle||"Switch to light theme":t.value.darkModeSwitchTitle||"Switch to dark theme"}),(a,r)=>(i(),P(qs,{title:o.value,class:"VPSwitchAppearance","aria-checked":c(e),onClick:c(s)},{default:f(()=>r[0]||(r[0]=[d("span",{class:"vpi-sun sun"},null,-1),d("span",{class:"vpi-moon moon"},null,-1)])),_:1},8,["title","aria-checked","onClick"]))}}),He=V(Gs,[["__scopeId","data-v-fa1daf57"]]),Rs={key:0,class:"VPNavBarAppearance"},Ws=k({__name:"VPNavBarAppearance",setup(n){const{site:e}=M();return(t,s)=>c(e).appearance&&c(e).appearance!=="force-dark"&&c(e).appearance!=="force-auto"?(i(),h("div",Rs,[y(He)])):g("",!0)}}),Ks=V(Ws,[["__scopeId","data-v-123fcb2f"]]),Be=T();let nt=!1,be=0;function Js(n){const e=T(!1);if(ge){!nt&&xs(),be++;const t=J(Be,s=>{var o,a,r;s===n.el.value||(o=n.el.value)!=null&&o.contains(s)?(e.value=!0,(a=n.onFocus)==null||a.call(n)):(e.value=!1,(r=n.onBlur)==null||r.call(n))});Me(()=>{t(),be--,be||Xs()})}return ht(e)}function xs(){document.addEventListener("focusin",st),nt=!0,Be.value=document.activeElement}function Xs(){document.removeEventListener("focusin",st)}function st(){Be.value=document.activeElement}const Ys={class:"VPMenuLink"},Qs=["innerHTML"],Zs=k({__name:"VPMenuLink",props:{item:{}},setup(n){const{page:e}=M();return(t,s)=>(i(),h("div",Ys,[y(K,{class:A({active:c(te)(c(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon},{default:f(()=>[d("span",{innerHTML:t.item.text},null,8,Qs)]),_:1},8,["class","href","target","rel","no-icon"])]))}}),ke=V(Zs,[["__scopeId","data-v-65e4a6b1"]]),eo={class:"VPMenuGroup"},to={key:0,class:"title"},no=k({__name:"VPMenuGroup",props:{text:{},items:{}},setup(n){return(e,t)=>(i(),h("div",eo,[e.text?(i(),h("p",to,C(e.text),1)):g("",!0),(i(!0),h(H,null,z(e.items,s=>(i(),h(H,null,["link"in s?(i(),P(ke,{key:0,item:s},null,8,["item"])):g("",!0)],64))),256))]))}}),so=V(no,[["__scopeId","data-v-2bec9359"]]),oo={class:"VPMenu"},ao={key:0,class:"items"},ro=k({__name:"VPMenu",props:{items:{}},setup(n){return(e,t)=>(i(),h("div",oo,[e.items?(i(),h("div",ao,[(i(!0),h(H,null,z(e.items,s=>(i(),h(H,{key:JSON.stringify(s)},["link"in s?(i(),P(ke,{key:0,item:s},null,8,["item"])):"component"in s?(i(),P(W(s.component),Y({key:1,ref_for:!0},s.props),null,16)):(i(),P(so,{key:2,text:s.text,items:s.items},null,8,["text","items"]))],64))),128))])):g("",!0),p(e.$slots,"default",{},void 0,!0)]))}}),io=V(ro,[["__scopeId","data-v-39eca401"]]),lo=["aria-expanded","aria-label"],co={key:0,class:"text"},uo=["innerHTML"],po={key:1,class:"vpi-more-horizontal icon"},ho={class:"menu"},fo=k({__name:"VPFlyout",props:{icon:{},button:{},label:{},items:{}},setup(n){const e=T(!1),t=T();Js({el:t,onBlur:s});function s(){e.value=!1}return(o,a)=>(i(),h("div",{class:"VPFlyout",ref_key:"el",ref:t,onMouseenter:a[1]||(a[1]=r=>e.value=!0),onMouseleave:a[2]||(a[2]=r=>e.value=!1)},[d("button",{type:"button",class:"button","aria-haspopup":"true","aria-expanded":e.value,"aria-label":o.label,onClick:a[0]||(a[0]=r=>e.value=!e.value)},[o.button||o.icon?(i(),h("span",co,[o.icon?(i(),h("span",{key:0,class:A([o.icon,"option-icon"])},null,2)):g("",!0),o.button?(i(),h("span",{key:1,innerHTML:o.button},null,8,uo)):g("",!0),a[3]||(a[3]=d("span",{class:"vpi-chevron-down text-icon"},null,-1))])):(i(),h("span",po))],8,lo),d("div",ho,[y(io,{items:o.items},{default:f(()=>[p(o.$slots,"default",{},void 0,!0)]),_:3},8,["items"])])],544))}}),Ee=V(fo,[["__scopeId","data-v-40e55da0"]]),vo=["href","aria-label","innerHTML"],mo=k({__name:"VPSocialLink",props:{icon:{},link:{},ariaLabel:{}},setup(n){const e=n,t=T();Q(async()=>{var a;await Ie();const o=(a=t.value)==null?void 0:a.children[0];o instanceof HTMLElement&&o.className.startsWith("vpi-social-")&&(getComputedStyle(o).maskImage||getComputedStyle(o).webkitMaskImage)==="none"&&o.style.setProperty("--icon",`url('https://api.iconify.design/simple-icons/${e.icon}.svg')`)});const s=S(()=>typeof e.icon=="object"?e.icon.svg:``);return(o,a)=>(i(),h("a",{ref_key:"el",ref:t,class:"VPSocialLink no-icon",href:o.link,"aria-label":o.ariaLabel??(typeof o.icon=="string"?o.icon:""),target:"_blank",rel:"noopener",innerHTML:s.value},null,8,vo))}}),_o=V(mo,[["__scopeId","data-v-fbf39218"]]),go={class:"VPSocialLinks"},ko=k({__name:"VPSocialLinks",props:{links:{}},setup(n){return(e,t)=>(i(),h("div",go,[(i(!0),h(H,null,z(e.links,({link:s,icon:o,ariaLabel:a})=>(i(),P(_o,{key:s,icon:o,link:s,ariaLabel:a},null,8,["icon","link","ariaLabel"]))),128))]))}}),Oe=V(ko,[["__scopeId","data-v-f2234a39"]]),bo={key:0,class:"group translations"},$o={class:"trans-title"},yo={key:1,class:"group"},Po={class:"item appearance"},Lo={class:"label"},Vo={class:"appearance-action"},So={key:2,class:"group"},To={class:"item social-links"},wo=k({__name:"VPNavBarExtra",setup(n){const{site:e,theme:t}=M(),{localeLinks:s,currentLang:o}=ae({correspondingLink:!0}),a=S(()=>s.value.length&&o.value.label||e.value.appearance||t.value.socialLinks);return(r,l)=>a.value?(i(),P(Ee,{key:0,class:"VPNavBarExtra",label:"extra navigation"},{default:f(()=>[c(s).length&&c(o).label?(i(),h("div",bo,[d("p",$o,C(c(o).label),1),(i(!0),h(H,null,z(c(s),u=>(i(),P(ke,{key:u.link,item:u},null,8,["item"]))),128))])):g("",!0),c(e).appearance&&c(e).appearance!=="force-dark"&&c(e).appearance!=="force-auto"?(i(),h("div",yo,[d("div",Po,[d("p",Lo,C(c(t).darkModeSwitchLabel||"Appearance"),1),d("div",Vo,[y(He)])])])):g("",!0),c(t).socialLinks?(i(),h("div",So,[d("div",To,[y(Oe,{class:"social-links-list",links:c(t).socialLinks},null,8,["links"])])])):g("",!0)]),_:1})):g("",!0)}}),Mo=V(wo,[["__scopeId","data-v-0c845e5d"]]),No=["aria-expanded"],Io=k({__name:"VPNavBarHamburger",props:{active:{type:Boolean}},emits:["click"],setup(n){return(e,t)=>(i(),h("button",{type:"button",class:A(["VPNavBarHamburger",{active:e.active}]),"aria-label":"mobile navigation","aria-expanded":e.active,"aria-controls":"VPNavScreen",onClick:t[0]||(t[0]=s=>e.$emit("click"))},t[1]||(t[1]=[d("span",{class:"container"},[d("span",{class:"top"}),d("span",{class:"middle"}),d("span",{class:"bottom"})],-1)]),10,No))}}),Co=V(Io,[["__scopeId","data-v-670493dd"]]),Ao=["innerHTML"],Ho=k({__name:"VPNavBarMenuLink",props:{item:{}},setup(n){const{page:e}=M();return(t,s)=>(i(),P(K,{class:A({VPNavBarMenuLink:!0,active:c(te)(c(e).relativePath,t.item.activeMatch||t.item.link,!!t.item.activeMatch)}),href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,tabindex:"0"},{default:f(()=>[d("span",{innerHTML:t.item.text},null,8,Ao)]),_:1},8,["class","href","target","rel","no-icon"]))}}),Bo=V(Ho,[["__scopeId","data-v-8dbce4d0"]]),Eo=k({__name:"VPNavBarMenuGroup",props:{item:{}},setup(n){const e=n,{page:t}=M(),s=a=>"component"in a?!1:"link"in a?te(t.value.relativePath,a.link,!!e.item.activeMatch):a.items.some(s),o=S(()=>s(e.item));return(a,r)=>(i(),P(Ee,{class:A({VPNavBarMenuGroup:!0,active:c(te)(c(t).relativePath,a.item.activeMatch,!!a.item.activeMatch)||o.value}),button:a.item.text,items:a.item.items},null,8,["class","button","items"]))}}),Oo={key:0,"aria-labelledby":"main-nav-aria-label",class:"VPNavBarMenu"},Do=k({__name:"VPNavBarMenu",setup(n){const{theme:e}=M();return(t,s)=>c(e).nav?(i(),h("nav",Oo,[s[0]||(s[0]=d("span",{id:"main-nav-aria-label",class:"visually-hidden"}," Main Navigation ",-1)),(i(!0),h(H,null,z(c(e).nav,o=>(i(),h(H,{key:JSON.stringify(o)},["link"in o?(i(),P(Bo,{key:0,item:o},null,8,["item"])):"component"in o?(i(),P(W(o.component),Y({key:1,ref_for:!0},o.props),null,16)):(i(),P(Eo,{key:2,item:o},null,8,["item"]))],64))),128))])):g("",!0)}}),Fo=V(Do,[["__scopeId","data-v-5bacfe89"]]),zo="/document/assets/flex-logo.BJA2J7hW.svg";function $e(n,e){return typeof n>"u"?e:n}function ze(n){const e=Array(n);for(let t=0;t=this.minlength&&(l||!r[_])){let L=ie(u,o,v),b="";switch(this.tokenize){case"full":if(3$;N--)if(N-$>=this.minlength){const w=ie(u,o,v,m,$);b=_.substring($,N),this.push_index(r,b,w,n,t)}break}case"reverse":if(2=this.minlength){const N=ie(u,o,v,m,$);this.push_index(r,b,N,n,t)}b=""}case"forward":if(1=this.minlength&&this.push_index(r,b,L,n,t);break}default:if(this.boost&&(L=Math.min(0|L/this.boost(e,_,v),u-1)),this.push_index(r,_,L,n,t),l&&1=this.minlength&&!$[_]){$[_]=1;const R=ie(N+(o/2>N?0:1),o,v,O-1,F-1),X=this.bidirectional&&_>w;this.push_index(a,X?w:_,R,n,t,X?_:w)}}}}}this.fastupdate||(this.register[n]=1)}}return this};function ie(n,e,t,s,o){return t&&1=this.minlength&&!m[b]){if(!this.optimize&&!a&&!this.map[b])return r;L[N++]=b,m[b]=1}n=L,s=n.length}if(!s)return r;e||(e=100);let u,v=this.depth&&1=t)))));b++);if(v)return o?qe(l,t,0):void(n[n.length]=l)}return!e&&l};function qe(n,e,t){return n=n.length===1?n[0]:Uo(n),t||n.length>e?n.slice(t,t+e):n}function Ge(n,e,t,s){if(t){const o=s&&e>t;n=n[o?e:t],n=n&&n[o?t:e]}else n=n[e];return n}q.prototype.contain=function(n){return!!this.register[n]},q.prototype.update=function(n,e){return this.remove(n).add(n,e)},q.prototype.remove=function(n,e){const t=this.register[n];if(t){if(this.fastupdate)for(let s,o=0;o{if(a.value){for(var B=m.value.search(a.value,{enrich:!0}),I=[],j=0;j!B||!B.length?[]:B.reduce((j,E)=>(j[I(E)]||(j[I(E)]=[]),j[I(E)].push(E),j),{}),R=()=>{setTimeout(()=>{l.value&&l.value.focus()},100),De(),o.value=!0};Q(async()=>{var E,D;const B=await vt(()=>import("./virtual_search-data.CYnorm-S.js"),[]);u.value=B.default.INDEX_DATA,v.value=B.default.PREVIEW_LOOKUP,_.value=B.default.Options,r.value=window.location.origin+he(t.value==="root"?"/":t.value),L.value=((E=_.value)==null?void 0:E.buttonLabel)||L.value,b.value=((D=_.value)==null?void 0:D.placeholder)||b.value;var I=new q(_.value);I.import("reg",u.value.reg),I.import("cfg",u.value.cfg),I.import("map",u.value.map),I.import("ctx",u.value.ctx),m.value=I,s.value.innerHTML=/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?"⌘":"Ctrl";const j=U=>{var se;U.key==="k"&&(U.ctrlKey||U.metaKey)&&(U.preventDefault(),R()),U.key==="Escape"&&((se=a.value)==null?void 0:se.length)==0&&o.value&&(o.value=!1)};window.addEventListener("keydown",j)});const X=S(()=>F(O.value,B=>B.link.split("/").slice(0,-1).join("-"))),ne=S(()=>Object.values(X.value).flat().map(B=>B.id));function De(){o.value=!1,a.value=""}const at=B=>{var I,j;if(document.getElementsByClassName("search-group")[0]){if(B.key=="ArrowUp"||B.key=="ArrowDown"){const E=ne.value.indexOf($.value);if(B.key=="ArrowUp"){const D=E==0?ne.value.length-1:E-1;$.value=ne.value[D]}if(B.key=="ArrowDown"){const D=E>ne.value.length-2?0:E+1;$.value=ne.value[D]}if(E<5){const D=N.value.getElementsByClassName("VPPluginSearch-search-group")[0];D==null||D.scrollIntoView(!0)}else(I=document.getElementById(ne.value[$.value]))==null||I.scrollIntoView(!0);Ie()}B.key=="Enter"&&w.go(e.site.value.base+((j=N.value.getElementsByClassName("link-focused")[0].getAttribute("href"))==null?void 0:j.replace(r.value,"")))}};return(B,I)=>{const j=Z("ClientOnly");return i(),h("div",la,[y(j,null,{default:f(()=>[(i(),P(gt,{to:"body"},[Fe(d("div",{class:"VPPluginSearch-modal-back",onClick:I[2]||(I[2]=E=>o.value=!1),onKeydown:at},[d("div",{class:"VPPluginSearch-modal",onClick:I[1]||(I[1]=Xe(()=>{},["stop"])),ref_key:"modal",ref:N},[d("form",ca,[I[4]||(I[4]=d("label",{class:"DocSearch-MagnifierLabel",for:"docsearch-input",id:"docsearch-label"},[d("svg",{width:"20",height:"20",class:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},[d("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none","fill-rule":"evenodd","stroke-linecap":"round","stroke-linejoin":"round"})])],-1)),Fe(d("input",{class:"DocSearch-Input","aria-autocomplete":"both","aria-labelledby":"docsearch-label",id:"docsearch-input",autocomplete:"off",autocorrect:"off",autocapitalize:"off",enterkeyhint:"search",spellcheck:"false",autofocus:"true","onUpdate:modelValue":I[0]||(I[0]=E=>a.value=E),placeholder:b.value,maxlength:"64",type:"search",ref_key:"input",ref:l},null,8,ua),[[_t,a.value]])]),d("div",da,[(i(!0),h(H,null,z(X.value,(E,D)=>(i(),h("div",{class:"search-group",key:D},[d("span",pa,C(D?D.toString()[0].toUpperCase()+D.toString().slice(1):"Home"),1),(i(!0),h(H,null,z(E,(U,se)=>(i(),h("a",{href:r.value+U.link,key:U.id,onClick:De,onMouseenter:re=>$.value=U.id,class:A({"link-focused":$.value==U.id}),id:se.toString()},[d("div",fa,[d("span",va,C(U.link.includes("#")?"#":"▤"),1),d("div",ma,[d("h3",null,C(U.title),1),d("p",null,[d("div",{innerHTML:U.preview},null,8,_a)])]),I[5]||(I[5]=d("span",{class:"VPPluginSearch-search-item-icon"},"↪",-1))])],42,ha))),128))]))),128))]),I[6]||(I[6]=d("img",{class:"VPPluginSearch-flex-logo",src:zo,alt:"flex logo"},null,-1))],512)],544),[[mt,o.value]])]))]),_:1}),d("div",{id:"docsearch",onClick:I[3]||(I[3]=E=>R())},[d("button",ga,[d("span",ka,[I[7]||(I[7]=d("svg",{width:"20",height:"20",class:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},[d("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none","fill-rule":"evenodd","stroke-linecap":"round","stroke-linejoin":"round"})],-1)),d("span",ba,C(L.value),1)]),d("span",$a,[d("span",{class:"DocSearch-Button-Key",ref_key:"metaKey",ref:s},"Meta",512),I[8]||(I[8]=d("span",{class:"DocSearch-Button-Key"},"K",-1))])])])])}}}),Pa=k({__name:"VPNavBarSocialLinks",setup(n){const{theme:e}=M();return(t,s)=>c(e).socialLinks?(i(),P(Oe,{key:0,class:"VPNavBarSocialLinks",links:c(e).socialLinks},null,8,["links"])):g("",!0)}}),La=V(Pa,[["__scopeId","data-v-08b35e6f"]]),Va=["href","rel","target"],Sa=["innerHTML"],Ta={key:2},wa=k({__name:"VPNavBarTitle",setup(n){const{site:e,theme:t}=M(),{hasSidebar:s}=x(),{currentLang:o}=ae(),a=S(()=>{var u;return typeof t.value.logoLink=="string"?t.value.logoLink:(u=t.value.logoLink)==null?void 0:u.link}),r=S(()=>{var u;return typeof t.value.logoLink=="string"||(u=t.value.logoLink)==null?void 0:u.rel}),l=S(()=>{var u;return typeof t.value.logoLink=="string"||(u=t.value.logoLink)==null?void 0:u.target});return(u,v)=>(i(),h("div",{class:A(["VPNavBarTitle",{"has-sidebar":c(s)}])},[d("a",{class:"title",href:a.value??c(Ce)(c(o).link),rel:r.value,target:l.value},[p(u.$slots,"nav-bar-title-before",{},void 0,!0),c(t).logo?(i(),P(ue,{key:0,class:"logo",image:c(t).logo},null,8,["image"])):g("",!0),c(t).siteTitle?(i(),h("span",{key:1,innerHTML:c(t).siteTitle},null,8,Sa)):c(t).siteTitle===void 0?(i(),h("span",Ta,C(c(e).title),1)):g("",!0),p(u.$slots,"nav-bar-title-after",{},void 0,!0)],8,Va)],2))}}),Ma=V(wa,[["__scopeId","data-v-5622a072"]]),Na={class:"items"},Ia={class:"title"},Ca=k({__name:"VPNavBarTranslations",setup(n){const{theme:e}=M(),{localeLinks:t,currentLang:s}=ae({correspondingLink:!0});return(o,a)=>c(t).length&&c(s).label?(i(),P(Ee,{key:0,class:"VPNavBarTranslations",icon:"vpi-languages",label:c(e).langMenuLabel||"Change language"},{default:f(()=>[d("div",Na,[d("p",Ia,C(c(s).label),1),(i(!0),h(H,null,z(c(t),r=>(i(),P(ke,{key:r.link,item:r},null,8,["item"]))),128))])]),_:1},8,["label"])):g("",!0)}}),Aa=V(Ca,[["__scopeId","data-v-dac637f3"]]),Ha={class:"wrapper"},Ba={class:"container"},Ea={class:"title"},Oa={class:"content"},Da={class:"content-body"},Fa=k({__name:"VPNavBar",props:{isScreenOpen:{type:Boolean}},emits:["toggle-screen"],setup(n){const e=n,{y:t}=xe(),{hasSidebar:s}=x(),{frontmatter:o}=M(),a=T({});return Ne(()=>{a.value={"has-sidebar":s.value,home:o.value.layout==="home",top:t.value===0,"screen-open":e.isScreenOpen}}),(r,l)=>(i(),h("div",{class:A(["VPNavBar",a.value])},[d("div",Ha,[d("div",Ba,[d("div",Ea,[y(Ma,null,{"nav-bar-title-before":f(()=>[p(r.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[p(r.$slots,"nav-bar-title-after",{},void 0,!0)]),_:3})]),d("div",Oa,[d("div",Da,[p(r.$slots,"nav-bar-content-before",{},void 0,!0),y(ya,{class:"search"}),y(Fo,{class:"menu"}),y(Aa,{class:"translations"}),y(Ks,{class:"appearance"}),y(La,{class:"social-links"}),y(Mo,{class:"extra"}),p(r.$slots,"nav-bar-content-after",{},void 0,!0),y(Co,{class:"hamburger",active:r.isScreenOpen,onClick:l[0]||(l[0]=u=>r.$emit("toggle-screen"))},null,8,["active"])])])])]),l[1]||(l[1]=d("div",{class:"divider"},[d("div",{class:"divider-line"})],-1))],2))}}),za=V(Fa,[["__scopeId","data-v-bb7529ee"]]),ja={key:0,class:"VPNavScreenAppearance"},Ua={class:"text"},qa=k({__name:"VPNavScreenAppearance",setup(n){const{site:e,theme:t}=M();return(s,o)=>c(e).appearance&&c(e).appearance!=="force-dark"&&c(e).appearance!=="force-auto"?(i(),h("div",ja,[d("p",Ua,C(c(t).darkModeSwitchLabel||"Appearance"),1),y(He)])):g("",!0)}}),Ga=V(qa,[["__scopeId","data-v-774971f8"]]),Ra=["innerHTML"],Wa=k({__name:"VPNavScreenMenuLink",props:{item:{}},setup(n){const e=_e("close-screen");return(t,s)=>(i(),P(K,{class:"VPNavScreenMenuLink",href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,onClick:c(e)},{default:f(()=>[d("span",{innerHTML:t.item.text},null,8,Ra)]),_:1},8,["href","target","rel","no-icon","onClick"]))}}),Ka=V(Wa,[["__scopeId","data-v-29871565"]]),Ja=["innerHTML"],xa=k({__name:"VPNavScreenMenuGroupLink",props:{item:{}},setup(n){const e=_e("close-screen");return(t,s)=>(i(),P(K,{class:"VPNavScreenMenuGroupLink",href:t.item.link,target:t.item.target,rel:t.item.rel,"no-icon":t.item.noIcon,onClick:c(e)},{default:f(()=>[d("span",{innerHTML:t.item.text},null,8,Ja)]),_:1},8,["href","target","rel","no-icon","onClick"]))}}),ot=V(xa,[["__scopeId","data-v-581896e9"]]),Xa={class:"VPNavScreenMenuGroupSection"},Ya={key:0,class:"title"},Qa=k({__name:"VPNavScreenMenuGroupSection",props:{text:{},items:{}},setup(n){return(e,t)=>(i(),h("div",Xa,[e.text?(i(),h("p",Ya,C(e.text),1)):g("",!0),(i(!0),h(H,null,z(e.items,s=>(i(),P(ot,{key:s.text,item:s},null,8,["item"]))),128))]))}}),Za=V(Qa,[["__scopeId","data-v-836cddb8"]]),er=["aria-controls","aria-expanded"],tr=["innerHTML"],nr=["id"],sr={key:0,class:"item"},or={key:1,class:"item"},ar={key:2,class:"group"},rr=k({__name:"VPNavScreenMenuGroup",props:{text:{},items:{}},setup(n){const e=n,t=T(!1),s=S(()=>`NavScreenGroup-${e.text.replace(" ","-").toLowerCase()}`);function o(){t.value=!t.value}return(a,r)=>(i(),h("div",{class:A(["VPNavScreenMenuGroup",{open:t.value}])},[d("button",{class:"button","aria-controls":s.value,"aria-expanded":t.value,onClick:o},[d("span",{class:"button-text",innerHTML:a.text},null,8,tr),r[0]||(r[0]=d("span",{class:"vpi-plus button-icon"},null,-1))],8,er),d("div",{id:s.value,class:"items"},[(i(!0),h(H,null,z(a.items,l=>(i(),h(H,{key:JSON.stringify(l)},["link"in l?(i(),h("div",sr,[y(ot,{item:l},null,8,["item"])])):"component"in l?(i(),h("div",or,[(i(),P(W(l.component),Y({ref_for:!0},l.props,{"screen-menu":""}),null,16))])):(i(),h("div",ar,[y(Za,{text:l.text,items:l.items},null,8,["text","items"])]))],64))),128))],8,nr)],2))}}),ir=V(rr,[["__scopeId","data-v-a8d3502a"]]),lr={key:0,class:"VPNavScreenMenu"},cr=k({__name:"VPNavScreenMenu",setup(n){const{theme:e}=M();return(t,s)=>c(e).nav?(i(),h("nav",lr,[(i(!0),h(H,null,z(c(e).nav,o=>(i(),h(H,{key:JSON.stringify(o)},["link"in o?(i(),P(Ka,{key:0,item:o},null,8,["item"])):"component"in o?(i(),P(W(o.component),Y({key:1,ref_for:!0},o.props,{"screen-menu":""}),null,16)):(i(),P(ir,{key:2,text:o.text||"",items:o.items},null,8,["text","items"]))],64))),128))])):g("",!0)}}),ur=k({__name:"VPNavScreenSocialLinks",setup(n){const{theme:e}=M();return(t,s)=>c(e).socialLinks?(i(),P(Oe,{key:0,class:"VPNavScreenSocialLinks",links:c(e).socialLinks},null,8,["links"])):g("",!0)}}),dr={class:"list"},pr=k({__name:"VPNavScreenTranslations",setup(n){const{localeLinks:e,currentLang:t}=ae({correspondingLink:!0}),s=T(!1);function o(){s.value=!s.value}return(a,r)=>c(e).length&&c(t).label?(i(),h("div",{key:0,class:A(["VPNavScreenTranslations",{open:s.value}])},[d("button",{class:"title",onClick:o},[r[0]||(r[0]=d("span",{class:"vpi-languages icon lang"},null,-1)),ee(" "+C(c(t).label)+" ",1),r[1]||(r[1]=d("span",{class:"vpi-chevron-down icon chevron"},null,-1))]),d("ul",dr,[(i(!0),h(H,null,z(c(e),l=>(i(),h("li",{key:l.link,class:"item"},[y(K,{class:"link",href:l.link},{default:f(()=>[ee(C(l.text),1)]),_:2},1032,["href"])]))),128))])],2)):g("",!0)}}),hr=V(pr,[["__scopeId","data-v-0d43316b"]]),fr={class:"container"},vr=k({__name:"VPNavScreen",props:{open:{type:Boolean}},setup(n){const e=T(null),t=Ye(ge?document.body:null);return(s,o)=>(i(),P(we,{name:"fade",onEnter:o[0]||(o[0]=a=>t.value=!0),onAfterLeave:o[1]||(o[1]=a=>t.value=!1)},{default:f(()=>[s.open?(i(),h("div",{key:0,class:"VPNavScreen",ref_key:"screen",ref:e,id:"VPNavScreen"},[d("div",fr,[p(s.$slots,"nav-screen-content-before",{},void 0,!0),y(cr,{class:"menu"}),y(hr,{class:"translations"}),y(Ga,{class:"appearance"}),y(ur,{class:"social-links"}),p(s.$slots,"nav-screen-content-after",{},void 0,!0)])],512)):g("",!0)]),_:3}))}}),mr=V(vr,[["__scopeId","data-v-34fa79a7"]]),_r={key:0,class:"VPNav"},gr=k({__name:"VPNav",setup(n){const{isScreenOpen:e,closeScreen:t,toggleScreen:s}=Os(),{frontmatter:o}=M(),a=S(()=>o.value.navbar!==!1);return Qe("close-screen",t),fe(()=>{ge&&document.documentElement.classList.toggle("hide-nav",!a.value)}),(r,l)=>a.value?(i(),h("header",_r,[y(za,{"is-screen-open":c(e),onToggleScreen:c(s)},{"nav-bar-title-before":f(()=>[p(r.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[p(r.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":f(()=>[p(r.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":f(()=>[p(r.$slots,"nav-bar-content-after",{},void 0,!0)]),_:3},8,["is-screen-open","onToggleScreen"]),y(mr,{open:c(e)},{"nav-screen-content-before":f(()=>[p(r.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":f(()=>[p(r.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3},8,["open"])])):g("",!0)}}),kr=V(gr,[["__scopeId","data-v-a46e73f0"]]),br=["role","tabindex"],$r={key:1,class:"items"},yr=k({__name:"VPSidebarItem",props:{item:{},depth:{}},setup(n){const e=n,{collapsed:t,collapsible:s,isLink:o,isActiveLink:a,hasActiveLink:r,hasChildren:l,toggle:u}=zt(S(()=>e.item)),v=S(()=>l.value?"section":"div"),_=S(()=>o.value?"a":"div"),m=S(()=>l.value?e.depth+2===7?"p":`h${e.depth+2}`:"p"),L=S(()=>o.value?void 0:"button"),b=S(()=>[[`level-${e.depth}`],{collapsible:s.value},{collapsed:t.value},{"is-link":o.value},{"is-active":a.value},{"has-active":r.value}]);function $(w){"key"in w&&w.key!=="Enter"||!e.item.link&&u()}function N(){e.item.link&&u()}return(w,O)=>{const F=Z("VPSidebarItem",!0);return i(),P(W(v.value),{class:A(["VPSidebarItem",b.value])},{default:f(()=>[w.item.text?(i(),h("div",Y({key:0,class:"item",role:L.value},kt(w.item.items?{click:$,keydown:$}:{},!0),{tabindex:w.item.items&&0}),[O[1]||(O[1]=d("div",{class:"indicator"},null,-1)),w.item.link?(i(),P(K,{key:0,tag:_.value,class:"link",href:w.item.link,rel:w.item.rel,target:w.item.target},{default:f(()=>[(i(),P(W(m.value),{class:"text",innerHTML:w.item.text},null,8,["innerHTML"]))]),_:1},8,["tag","href","rel","target"])):(i(),P(W(m.value),{key:1,class:"text",innerHTML:w.item.text},null,8,["innerHTML"])),w.item.collapsed!=null&&w.item.items&&w.item.items.length?(i(),h("div",{key:2,class:"caret",role:"button","aria-label":"toggle section",onClick:N,onKeydown:bt(N,["enter"]),tabindex:"0"},O[0]||(O[0]=[d("span",{class:"vpi-chevron-right caret-icon"},null,-1)]),32)):g("",!0)],16,br)):g("",!0),w.item.items&&w.item.items.length?(i(),h("div",$r,[w.depth<5?(i(!0),h(H,{key:0},z(w.item.items,R=>(i(),P(F,{key:R.text,item:R,depth:w.depth+1},null,8,["item","depth"]))),128)):g("",!0)])):g("",!0)]),_:1},8,["class"])}}}),Pr=V(yr,[["__scopeId","data-v-2e0476bc"]]),Lr=k({__name:"VPSidebarGroup",props:{items:{}},setup(n){const e=T(!0);let t=null;return Q(()=>{t=setTimeout(()=>{t=null,e.value=!1},300)}),$t(()=>{t!=null&&(clearTimeout(t),t=null)}),(s,o)=>(i(!0),h(H,null,z(s.items,a=>(i(),h("div",{key:a.text,class:A(["group",{"no-transition":e.value}])},[y(Pr,{item:a,depth:0},null,8,["item"])],2))),128))}}),Vr=V(Lr,[["__scopeId","data-v-ec086cd5"]]),Sr={class:"nav",id:"VPSidebarNav","aria-labelledby":"sidebar-aria-label",tabindex:"-1"},Tr=k({__name:"VPSidebar",props:{open:{type:Boolean}},setup(n){const{sidebarGroups:e,hasSidebar:t}=x(),s=n,o=T(null),a=Ye(ge?document.body:null);J([s,o],()=>{var l;s.open?(a.value=!0,(l=o.value)==null||l.focus()):a.value=!1},{immediate:!0,flush:"post"});const r=T(0);return J(e,()=>{r.value+=1},{deep:!0}),(l,u)=>c(t)?(i(),h("aside",{key:0,class:A(["VPSidebar",{open:l.open}]),ref_key:"navEl",ref:o,onClick:u[0]||(u[0]=Xe(()=>{},["stop"]))},[u[2]||(u[2]=d("div",{class:"curtain"},null,-1)),d("nav",Sr,[u[1]||(u[1]=d("span",{class:"visually-hidden",id:"sidebar-aria-label"}," Sidebar Navigation ",-1)),p(l.$slots,"sidebar-nav-before",{},void 0,!0),(i(),P(Vr,{items:c(e),key:r.value},null,8,["items"])),p(l.$slots,"sidebar-nav-after",{},void 0,!0)])],2)):g("",!0)}}),wr=V(Tr,[["__scopeId","data-v-12a40e3d"]]),Mr=k({__name:"VPSkipLink",setup(n){const{theme:e}=M(),t=me(),s=T();J(()=>t.path,()=>s.value.focus());function o({target:a}){const r=document.getElementById(decodeURIComponent(a.hash).slice(1));if(r){const l=()=>{r.removeAttribute("tabindex"),r.removeEventListener("blur",l)};r.setAttribute("tabindex","-1"),r.addEventListener("blur",l),r.focus(),window.scrollTo(0,0)}}return(a,r)=>(i(),h(H,null,[d("span",{ref_key:"backToTop",ref:s,tabindex:"-1"},null,512),d("a",{href:"#VPContent",class:"VPSkipLink visually-hidden",onClick:o},C(c(e).skipToContentLabel||"Skip to content"),1)],64))}}),Nr=V(Mr,[["__scopeId","data-v-17ad389b"]]),Ir=k({__name:"Layout",setup(n){const{isOpen:e,open:t,close:s}=x(),o=me();J(()=>o.path,s),Ft(e,s);const{frontmatter:a}=M(),r=yt(),l=S(()=>!!r["home-hero-image"]);return Qe("hero-image-slot-exists",l),(u,v)=>{const _=Z("Content");return c(a).layout!==!1?(i(),h("div",{key:0,class:A(["Layout",c(a).pageClass])},[p(u.$slots,"layout-top",{},void 0,!0),y(Nr),y(St,{class:"backdrop",show:c(e),onClick:c(s)},null,8,["show","onClick"]),y(kr,null,{"nav-bar-title-before":f(()=>[p(u.$slots,"nav-bar-title-before",{},void 0,!0)]),"nav-bar-title-after":f(()=>[p(u.$slots,"nav-bar-title-after",{},void 0,!0)]),"nav-bar-content-before":f(()=>[p(u.$slots,"nav-bar-content-before",{},void 0,!0)]),"nav-bar-content-after":f(()=>[p(u.$slots,"nav-bar-content-after",{},void 0,!0)]),"nav-screen-content-before":f(()=>[p(u.$slots,"nav-screen-content-before",{},void 0,!0)]),"nav-screen-content-after":f(()=>[p(u.$slots,"nav-screen-content-after",{},void 0,!0)]),_:3}),y(Es,{open:c(e),onOpenMenu:c(t)},null,8,["open","onOpenMenu"]),y(wr,{open:c(e)},{"sidebar-nav-before":f(()=>[p(u.$slots,"sidebar-nav-before",{},void 0,!0)]),"sidebar-nav-after":f(()=>[p(u.$slots,"sidebar-nav-after",{},void 0,!0)]),_:3},8,["open"]),y(bs,null,{"page-top":f(()=>[p(u.$slots,"page-top",{},void 0,!0)]),"page-bottom":f(()=>[p(u.$slots,"page-bottom",{},void 0,!0)]),"not-found":f(()=>[p(u.$slots,"not-found",{},void 0,!0)]),"home-hero-before":f(()=>[p(u.$slots,"home-hero-before",{},void 0,!0)]),"home-hero-info-before":f(()=>[p(u.$slots,"home-hero-info-before",{},void 0,!0)]),"home-hero-info":f(()=>[p(u.$slots,"home-hero-info",{},void 0,!0)]),"home-hero-info-after":f(()=>[p(u.$slots,"home-hero-info-after",{},void 0,!0)]),"home-hero-actions-after":f(()=>[p(u.$slots,"home-hero-actions-after",{},void 0,!0)]),"home-hero-image":f(()=>[p(u.$slots,"home-hero-image",{},void 0,!0)]),"home-hero-after":f(()=>[p(u.$slots,"home-hero-after",{},void 0,!0)]),"home-features-before":f(()=>[p(u.$slots,"home-features-before",{},void 0,!0)]),"home-features-after":f(()=>[p(u.$slots,"home-features-after",{},void 0,!0)]),"doc-footer-before":f(()=>[p(u.$slots,"doc-footer-before",{},void 0,!0)]),"doc-before":f(()=>[p(u.$slots,"doc-before",{},void 0,!0)]),"doc-after":f(()=>[p(u.$slots,"doc-after",{},void 0,!0)]),"doc-top":f(()=>[p(u.$slots,"doc-top",{},void 0,!0)]),"doc-bottom":f(()=>[p(u.$slots,"doc-bottom",{},void 0,!0)]),"aside-top":f(()=>[p(u.$slots,"aside-top",{},void 0,!0)]),"aside-bottom":f(()=>[p(u.$slots,"aside-bottom",{},void 0,!0)]),"aside-outline-before":f(()=>[p(u.$slots,"aside-outline-before",{},void 0,!0)]),"aside-outline-after":f(()=>[p(u.$slots,"aside-outline-after",{},void 0,!0)]),"aside-ads-before":f(()=>[p(u.$slots,"aside-ads-before",{},void 0,!0)]),"aside-ads-after":f(()=>[p(u.$slots,"aside-ads-after",{},void 0,!0)]),_:3}),y(Vs),p(u.$slots,"layout-bottom",{},void 0,!0)],2)):(i(),P(_,{key:1}))}}}),Cr=V(Ir,[["__scopeId","data-v-c4daae71"]]),Hr={Layout:Cr,enhanceApp:({app:n})=>{n.component("Badge",Pt)}};export{Hr as t}; diff --git a/docs/document/assets/chunks/virtual_search-data.B1Wl_n0C.js b/docs/document/assets/chunks/virtual_search-data.B1Wl_n0C.js deleted file mode 100644 index 0f944ca2c..000000000 --- a/docs/document/assets/chunks/virtual_search-data.B1Wl_n0C.js +++ /dev/null @@ -1,1404 +0,0 @@ -const e={map:'[{"高级属性":["0.0"],"option":["0.1","1.12","10.1","11.12","20.9","23.9","24.17"],"template":["0.2","10.2"],"events":["0.3","10.3"],"storage":["0.4","10.4"],"icons":["0.5","10.5","22.39","26.39"],"i18n":["0.6","10.6","22.43","26.43"],"notice":["0.7","3.4","10.7","13.4"],"layers":["0.8","10.8","18.0","22.29","26.29"],"controls":["0.9","10.9","17.0","22.32","26.32"],"contextmenu":["0.10","2.37","3.3","10.10","12.37","13.3","22.31","26.31"],"subtitle":["0.11","2.36","10.11","12.36","22.37","26.37"],"info":["0.12","2.32","3.22","10.12","12.32","13.22"],"loading":["0.13","2.34","10.13","12.34"],"hotkey":["0.14","2.5","10.14","12.5","22.19","26.19"],"mask":["0.15","2.35","10.15","12.35"],"setting":["0.16","2.39","3.5","3.6","3.7","10.16","12.39","13.5","13.6","13.7","22.18","26.18"],"plugins":["0.17","10.17","22.35","26.35"],"静态属性":["1.0"],"instances":["1.1","11.1"],"version":["1.2","11.2"],"env":["1.3","11.3"],"build":["1.4","11.4"],"config":["1.5","11.5","24.13"],"utils":["1.6","11.6"],"scheme":["1.7","11.7"],"emitter":["1.8","11.8"],"validator":["1.9","11.9"],"kindof":["1.10","11.10"],"html":["1.11","11.11"],"实例事件":["2.0"],"ready":["2.1","12.1"],"restart":["2.2","12.2"],"pause":["2.3","5.2","12.3","15.2"],"play":["2.4","5.1","12.4","15.1"],"destroy":["2.6","5.4","12.6","15.4"],"focus":["2.7","12.7"],"blur":["2.8","12.8"],"dblclick":["2.9","12.9"],"click":["2.10","12.10"],"error":["2.11","12.11"],"hover":["2.12","12.12"],"mousemove":["2.13","12.13"],"resize":["2.14","3.8","12.14","13.8"],"view":["2.15","12.15"],"lock":["2.16","12.16","22.44","26.44"],"aspectratio":["2.17","5.32","12.17","15.32","22.16","26.16"],"autoheight":["2.18","5.33","12.18","15.33"],"autosize":["2.19","5.27","12.19","15.27","22.11","26.11"],"flip":["2.20","3.30","5.30","12.20","13.30","15.30","22.14","26.14"],"fullscreen":["2.21","3.31","5.20","12.21","13.31","15.20","22.23","26.23"],"fullscreenerror":["2.22","12.22"],"fullscreenweb":["2.23","5.21","12.23","15.21","22.24","26.24"],"mini":["2.24","5.24","12.24","15.24"],"pip":["2.25","5.22","12.25","15.22","22.20","26.20"],"screenshot":["2.26","5.17","12.26","15.17","22.17","26.17"],"seek":["2.27","3.27","5.6","12.27","13.27","15.6"],"subtitleoffset":["2.28","5.47","12.28","15.47","22.25","26.25"],"subtitlebeforeupdate":["2.29","12.29"],"subtitleafterupdate":["2.30","12.30"],"subtitleload":["2.31","12.31"],"layer":["2.33","12.33"],"control":["2.38","3.16","12.38","13.16"],"muted":["2.40","5.14","12.40","15.14","22.9","26.9"],"keydown":["2.41","12.41"],"video":["2.42","2.43","2.44","2.45","2.46","2.47","2.48","2.49","2.50","2.51","2.52","2.53","2.54","2.55","2.56","2.57","2.58","2.59","2.60","2.61","2.62","5.43","12.42","12.43","12.44","12.45","12.46","12.47","12.48","12.49","12.50","12.51","12.52","12.53","12.54","12.55","12.56","12.57","12.58","12.59","12.60","12.61","12.62","15.43"],"全局属性":["3.0"],"debug":["3.1","13.1"],"style":["3.2","13.2"],"scroll":["3.9","3.10","13.9","13.10"],"auto":["3.11","3.12","3.13","3.21","13.11","13.12","13.13","13.21"],"reconnect":["3.14","3.15","13.14","13.15"],"dbclick":["3.17","3.18","13.17","13.18"],"mobile":["3.19","3.20","13.19","13.20"],"fast":["3.23","3.24","13.23","13.24"],"touch":["3.25","13.25"],"volume":["3.26","5.9","13.26","15.9","22.7","26.7"],"playback":["3.28","13.28"],"aspect":["3.29","13.29"],"log":["3.32","13.32"],"use":["3.33","13.33"],"remove":["3.34","13.34","19.8"],"编写插件":["4.0"],"实例属性":["5.0"],"toggle":["5.3","15.3"],"reset":["5.5","15.5","24.15"],"forward":["5.7","15.7"],"backward":["5.8","15.8"],"url":["5.10","15.10","22.2","26.2"],"switch":["5.11","15.11"],"switchurl":["5.12","15.12"],"switchquality":["5.13","15.13"],"currenttime":["5.15","15.15"],"duration":["5.16","15.16"],"getdataurl":["5.18","15.18"],"getbloburl":["5.19","15.19"],"poster":["5.23","15.23","22.5","26.5"],"playing":["5.25","15.25"],"state":["5.26","15.26"],"rect":["5.28","15.28"],"bottom":["5.29","15.29"],"playbackrate":["5.31","15.31","22.15","26.15"],"attr":["5.34","15.34"],"type":["5.35","15.35","22.40","26.40"],"theme":["5.36","15.36","22.6","26.6"],"airplay":["5.37","15.37","22.49","26.49"],"loaded":["5.38","15.38"],"loadedtime":["5.39","15.39"],"played":["5.40","15.40"],"proxy":["5.41","15.41","22.51","26.51"],"query":["5.42","15.42"],"cssvar":["5.44","15.44","22.50","26.50"],"quality":["5.45","15.45","22.33","26.33"],"thumbnails":["5.46","15.46","22.36","26.36"],"右键菜单":["6.0"],"配置":["6.1","7.1","8.1"],"创建":["6.2","7.2","8.2","9.2","9.3","9.4","9.5","9.6"],"添加":["6.3","7.3","8.3","9.7"],"删除":["6.4","7.4","8.4","9.8"],"更新":["6.5","7.5","8.5","9.9"],"控制器":["7.0"],"业务层":["8.0"],"设置面板":["9.0"],"内置":["9.1"],"advanced":["10.0"],"static":["11.0"],"instance":["12.0","15.0"],"global":["13.0"],"writing":["14.0"],"context":["16.0"],"configuration":["16.1","17.1","18.1"],"creation":["16.2","17.2","18.2"],"addition":["16.3","18.3"],"deletion":["16.4"],"update":["16.5","18.5","19.9"],"adding":["17.3","21.3"],"removal":["17.4","18.4"],"updating":["17.5"],"settings":["19.0","22.30","26.30"],"built":["19.1"],"create":["19.2","19.3","19.4","19.5","19.6"],"add":["19.7"],"installation":["20.0","20.1"],"cdn":["20.2","23.2","24.3"],"usage":["20.3"],"vue":["20.4","20.7","23.4","23.7"],"react":["20.5","20.8","23.5","23.8"],"typescript":["20.6","23.6"],"javascript":["20.10","23.10"],"legacy":["20.11"],"ecmascript":["20.12","23.12"],"custom":["20.13"],"language":["21.0"],"default":["21.1"],"importing":["21.2"],"modifying":["21.4"],"basic":["22.0"],"container":["22.1","26.1"],"id":["22.3","26.3"],"onready":["22.4","26.4"],"islive":["22.8","26.8"],"autoplay":["22.10","26.10"],"automini":["22.12","26.12"],"loop":["22.13","26.13"],"mutex":["22.21","26.21"],"backdrop":["22.22","26.22"],"miniprogressbar":["22.26","26.26"],"usessr":["22.27","26.27"],"playsinline":["22.28","26.28"],"highlight":["22.34","26.34"],"morevideoattr":["22.38","26.38"],"customtype":["22.41","26.41"],"lang":["22.42","26.42"],"gesture":["22.45","26.45"],"fastforward":["22.46","26.46"],"autoplayback":["22.47","26.47"],"autoorientation":["22.48","26.48"],"安装使用":["23.0"],"安装":["23.1","24.2"],"使用":["23.3"],"古老的浏览器":["23.11"],"自定义":["23.13"],"弹幕库":["24.0"],"演示":["24.1"],"弹幕结构":["24.4"],"全部选项":["24.5"],"生命周期":["24.6"],"使用弹幕数组":["24.7"],"使用弹幕":["24.8"],"使用异步返回":["24.9"],"hide":["24.10"],"ishide":["24.11"],"emit":["24.12"],"load":["24.14"],"mount":["24.16"],"事件":["24.18"],"语言设置":["25.0"],"默认语言":["25.1"],"导入语言":["25.2"],"新增语言":["25.3"],"修改语言":["25.4"],"基础选项":["26.0"]},{"0":["3.28","5.38","5.40","22.7","26.7"],"1":["23.11","24.5"],"3":["3.29","23.9"],"4":["3.29","25.3"],"5":["3.28","8.2","18.2","24.5"],"7":["8.3","18.3","22.7"],"9":["25.3"],"10":["24.5"],"15":["4.0"],"21":["8.5","9.9","18.5","19.9"],"26":["7.5","17.5"],"27":["9.9","19.9"],"75":["3.28"],"250":["3.5"],"这里的":["0.0","1.0","3.0","5.0"],"播放器的选项":["0.1"],"div":["0.1","0.2","0.4","0.5","0.7","0.14","0.17","1.1","1.6","2.0","2.1","2.2","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.28","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","3.3","4.0","5.1","5.2","5.3","5.16","5.28","5.33","5.37","5.45","6.2","6.3","6.4","6.5","7.2","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.4","9.7","9.8","9.9","10.1","10.2","14.0","16.2","16.3","16.4","16.5","17.2","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","22.2","22.29","22.30","24.6","24.7","24.9","24.10","24.11","24.12","24.13","24.14","24.15","24.17","24.18","26.2","26.29","26.30","26.31","26.32"],"classname":["0.1","0.2","0.17","2.0","2.1","2.2","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.28","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","4.0","5.45","6.2","6.3","6.4","6.5","7.2","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.4","9.7","9.8","9.9","10.2","14.0","16.2","16.3","16.4","16.5","17.2","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","22.2","22.29","22.30","24.6","24.7","24.9","24.11","24.12","24.13","24.14","24.15","24.17","24.18","26.2","26.29","26.30"],"run":["0.1","0.2","2.0","2.2","2.6","2.11","2.12","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.28","2.29","2.30","2.31","2.39","4.0","5.45","6.2","6.3","6.4","6.5","7.2","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.4","9.7","9.8","9.9","14.0","16.2","16.3","16.4","16.5","17.2","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","22.2","22.29","24.6","24.7","24.9","24.11","24.12","24.13","24.14","24.15","24.17","24.18","26.2","26.29","26.30"],"管理播放器所有的":["0.2","0.3","0.5"],"dom":["0.2","0.3","5.41","5.42","9.2","9.3","9.5","9.6","10.2","10.3","15.41","15.42","19.2","19.3","19.5","19.6","22.1","26.1"],"元素":["0.2","9.5","9.6"],"事件":["0.3","4.0"],"实质上是代理了":["0.3"],"addeventlistener":["0.3","5.41","10.3","15.41"],"和":["0.3","4.0","5.13","24.8","24.10","26.4"],"removeeventlistener":["0.3","10.3"],"当使用以下方法来处理事件":["0.3"],"播放器销毁时也会自动销毁该事件":["0.3"],"管理播放器的本地存储":["0.4"],"name":["0.4","4.0","10.4","17.1"],"属性用于设置缓存的":["0.4"],"key":["0.4","10.4"],"set":["0.4","10.4","15.9","15.11","15.12","15.44","15.45","22.36","22.37"],"方法用于设置缓存":["0.4"],"get":["0.4","0.6","10.6","15.34","15.44"],"方法用于获取缓存":["0.4"],"del":["0.4"],"方法用于删除缓存":["0.4"],"clear":["0.4"],"方法用于清空缓存":["0.4"],"svg":["0.5","10.5"],"图标":["0.5"],"管理播放器的":["0.6"],"方法用于获取":["0.6"],"的值":["0.6"],"update":["0.6","0.8","0.9","0.10","0.16"],"管理播放器的提示语":["0.7"],"只有一个":["0.7"],"show":["0.7","0.13","0.15","10.13","10.15","24.10"],"属性用于显示提示语":["0.7"],"管理播放器的层":["0.8"],"add":["0.8","0.9","0.10","0.14","0.16","0.17","10.8","10.9","10.10","10.14","10.16"],"方法用于动态添加层":["0.8"],"remove":["0.8","0.9","0.10","0.14","0.16"],"方法用于动态删除层":["0.8"],"管理播放器的控制器":["0.9"],"方法用于动态添加控制器":["0.9"],"方法用于动态删除控制器":["0.9"],"管理播放器的右键菜单":["0.10"],"方法用于动态添加菜单":["0.10"],"方法用于动态删除菜单":["0.10"],"方法用于动态更新菜单":["0.10"],"管理播放器的字幕功能":["0.11"],"url":["0.11","5.12","10.11","15.12","15.18","15.19"],"属性设置和返回当前字幕地址":["0.11"],"style":["0.11"],"方法设置当前字幕的样式":["0.11"],"switch":["0.11"],"管理播放器的信息面板":["0.12"],"常用于查看当前播放器和视频的运行状态":["0.12"],"例如版本号":["0.12"],"分辨率":["0.12"],"时长等":["0.12"],"管理播放器的加载层":["0.13"],"属性用于设置是否显示加载层":["0.13"],"toggle":["0.13","0.15","19.5"],"管理播放器的快捷键功能":["0.14"],"方法用于添加快捷键":["0.14"],"方法用于删除快捷键":["0.14"],"管理播放器的遮罩层":["0.15"],"属性用于设置是否显示遮罩层":["0.15"],"管理播放器的设置面板":["0.16"],"方法用于动态添加设置项":["0.16"],"方法用于动态删除设置项":["0.16"],"方法用于动态更新设置项":["0.16"],"管理播放器的插件功能":["0.17"],"只有一个方法":["0.17"],"用于动态添加插件":["0.17"],"返回全部播放器实例的数组":["1.1"],"假如你想同时管理多个播放器的时候":["1.1"],"可以用到该属性":["1.1"],"返回播放器的版本信息":["1.2"],"返回播放器的环境变量":["1.3"],"返回播放器的打包时间":["1.4"],"返回视频的默认配置":["1.5"],"返回播放器的工具函数集合":["1.6"],"返回播放器选项的校验方案":["1.7"],"返回事件分发器的构造函数":["1.8"],"返回选项的校验函数":["1.9"],"返回类型检测的函数工具":["1.10"],"返回播放器所需的":["1.11"],"返回播放器的默认选项":["1.12"],"播放器的事件分为两种":["2.0"],"一种视频的":["2.0"],"原生事件":["2.0"],"前缀":["2.0"],"video":["2.0","12.0","13.29","13.30","13.34","15.3","15.5","15.11","15.12","15.13","15.16","15.38","15.40","22.2","22.5","22.37","22.40","22.41"],"另外一种是":["2.0"],"自定义事件":["2.0"],"监听事件":["2.0"],"code":["2.0","2.2","2.28","4.0","6.2","6.3","6.4","6.5","7.2","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.4","9.7","9.8","9.9","14.0","16.2","16.3","16.4","16.5","17.2","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","20.1","20.2","20.3","20.4","20.5","22.2","22.29","23.1","23.2","23.3","23.4","23.5","24.2","24.3","24.6","24.7","24.9","24.11","24.12","24.13","24.14","24.15","24.17","24.18","26.2","26.29"],"js":["2.0","4.0","6.5","7.2","7.3","7.5","8.2","8.3","8.5","9.4","9.8","9.9","16.5","17.2","17.3","17.5","18.2","18.3","18.5","19.4","19.8","19.9","20.4","20.5","20.7","20.8","20.10","20.11","21.2","21.4","23.4","23.5","23.7","23.8","23.10","23.11","24.5","24.18","25.2","25.3","25.4"],"当播放器首次可以播放器时触发":["2.1"],"当播放器切换地址后并可以播放时触发":["2.2"],"当播放器暂停时触发":["2.3"],"当播放器播放时触发":["2.4"],"当播放器热键被按下时触发":["2.5"],"当播放器销毁时触发":["2.6"],"当播放器获得焦点时触发":["2.7"],"当播放器失去焦点时触发":["2.8"],"当播放器被双击时触发":["2.9"],"当播放器被单击时触发":["2.10"],"当播放器加载视频发生错误时触发":["2.11"],"当播放器被鼠标移出或者移入时触发":["2.12"],"当播放器被鼠标经过时触发":["2.13"],"当播放器尺寸变化时触发":["2.14"],"当播放器出现在视口时触发":["2.15"],"在移动端":["2.16","3.19","3.20","3.21","3.23","3.24","3.25"],"当锁定的状态发生变化时触发":["2.16"],"当播放器长宽比变化时触发":["2.17"],"当播放器自动设置高度时触发":["2.18"],"当播放器自动设置尺寸时触发":["2.19"],"当播放器发生翻转时触发":["2.20"],"当播放器发生窗口全屏时触发":["2.21"],"当播放器发生窗口全屏错误时触发":["2.22"],"当播放器发生网页全屏时触发":["2.23"],"当播放器进入迷你模式时触发":["2.24"],"当播放器进入画中画时触发":["2.25"],"当播放器被截图时触发":["2.26"],"当播放器发生时间跳转时触发":["2.27"],"当播放器发生字幕偏移时触发":["2.28"],"当字幕更新前触发":["2.29"],"当字幕更新后触发":["2.30"],"当字幕加载时触发":["2.31"],"当信息面板显示或隐藏时触发":["2.32"],"当自定义层显示或隐藏时触发":["2.33"],"当加载器显示或隐藏时触发":["2.34"],"当遮罩层显示或隐藏时触发":["2.35"],"当字幕层显示或隐藏时触发":["2.36"],"当右键菜单显示或隐藏时触发":["2.37"],"当控制器显示或隐藏时触发":["2.38"],"当设置面板显示或隐藏时触发":["2.39"],"当静音的状态变化时触发":["2.40"],"监听来自":["2.41"],"document":["2.41"],"的":["2.41"],"canplay":["2.42","12.42"],"canplaythrough":["2.43","12.43"],"complete":["2.44","12.44"],"durationchange":["2.45","12.45"],"emptied":["2.46","12.46"],"ended":["2.47","12.47"],"error":["2.48","12.48"],"loadeddata":["2.49","12.49"],"loadedmetadata":["2.50","12.50"],"pause":["2.51","12.51"],"play":["2.52","3.19","3.20","12.52","13.19","13.20","15.3"],"playing":["2.53","12.53"],"progress":["2.54","12.54","22.36"],"ratechange":["2.55","12.55"],"seeked":["2.56","12.56"],"seeking":["2.57","12.57"],"stalled":["2.58","12.58"],"suspend":["2.59","12.59"],"timeupdate":["2.60","12.60"],"volumechange":["2.61","12.61"],"waiting":["2.62","12.62"],"是否开始":["3.1"],"模式":["3.1"],"返回播放器样式文本":["3.2"],"是否开启右键菜单":["3.3"],"默认开启":["3.3"],"time":["3.4","3.8","3.9","3.14","3.15","3.16","3.17","3.21","3.22","3.24","13.4","13.8","13.9","13.14","13.15","13.16","13.17","13.21","13.22","13.24","22.25"],"提示信息的显示时长":["3.4"],"单位为毫秒":["3.4","3.8","3.9","3.13","3.16","3.17","3.22"],"width":["3.5","3.6","5.29","9.3","13.5","13.6","15.29","15.33"],"设置面板的默认宽度":["3.5"],"单位为像素":["3.5","3.6","3.7","3.10"],"默认为":["3.5","3.6","3.7","3.11","3.17","3.26","3.28","3.29","3.30","3.32","3.33"],"item":["3.6","3.7","13.6","13.7","19.6"],"设置面板的设置项的默认宽度":["3.6"],"height":["3.7","5.29","13.7","15.29"],"设置面板的设置项的默认高度":["3.7"],"事件的节流时间":["3.8","3.9"],"gap":["3.10","13.10"],"view":["3.10","10.12"],"事件的边界容差距离":["3.10"],"playback":["3.11","3.12","3.13","12.53","13.11","13.12","13.13","22.47"],"max":["3.11","3.14","13.11","13.14"],"自动回放功能的最大记录数":["3.11"],"min":["3.12","13.12"],"自动回放功能的最小记录时长":["3.12"],"单位为秒":["3.12","3.27","5.39"],"timeout":["3.13","13.13"],"自动回放功能的隐藏延迟时长":["3.13"],"发生连接错误时":["3.14","3.15"],"自动连接的最大次数":["3.14"],"sleep":["3.15","13.15"],"自动连接的延迟时间":["3.15"],"hide":["3.16","13.13","13.16"],"底部控制栏的自动隐藏的延迟时间":["3.16"],"双击事件的延迟事件":["3.17"],"fullscreen":["3.18","12.22","13.18"],"在桌面端":["3.18"],"是否双击切换全屏":["3.18"],"dbclick":["3.19","13.19"],"是否双击切换播放暂停":["3.19"],"click":["3.20","13.20"],"是否单击切换播放暂停":["3.20"],"orientation":["3.21","13.21"],"自动旋屏的延迟时间":["3.21"],"loop":["3.22","13.22"],"信息面板的刷新时间":["3.22"],"forward":["3.23","3.24","13.23","13.24"],"value":["3.23","13.23"],"长按加速的速率倍数":["3.23"],"长按加速的延迟时间":["3.24"],"move":["3.25","13.25"],"ratio":["3.25","3.29","13.25","13.29"],"左右滑动进度的速率倍数":["3.25"],"step":["3.26","3.27","13.26","13.27"],"快捷键调节音量的幅度比例":["3.26"],"快捷键调节播放进度的幅度":["3.27"],"rate":["3.28","13.28"],"内置播放速率的列表":["3.28"],"内置视频长宽比的列表":["3.29"],"default":["3.29","13.5","13.6","13.7","22.1","22.2","22.3","22.4","22.5","22.6","22.7","22.8","22.9","22.10","22.11","22.12","22.13","22.14","22.15","22.16","22.17","22.18","22.19","22.20","22.21","22.22","22.23","22.24","22.25","22.26","22.27","22.28","22.29","22.30","22.31","22.32","22.33","22.34","22.35","22.36","22.37","22.38","22.39","22.40","22.41","22.42","22.43","22.44","22.45","22.46","22.47","22.48","22.49","22.50","22.51","26.1","26.2","26.3","26.4","26.5","26.6","26.7","26.8","26.9","26.10","26.11","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.19","26.20","26.21","26.22","26.23","26.24","26.25","26.26","26.27","26.28","26.29","26.30","26.31","26.32","26.33","26.34","26.35","26.36","26.37","26.38","26.39","26.40","26.41","26.42","26.43","26.44","26.45","26.46","26.47","26.48","26.49","26.50","26.51"],"内置视频翻转的列表":["3.30"],"normal":["3.30"],"horizontal":["3.30"],"vertical":["3.30"],"web":["3.31","13.31"],"in":["3.31","13.28","13.29","13.30","13.31","19.1","20.10"],"body":["3.31","13.31"],"网页全屏时":["3.31"],"version":["3.32","13.32"],"设置是否打印播放器版本":["3.32"],"raf":["3.33","13.33"],"设置是否使用":["3.33"],"requestanimationframe":["3.33"],"src":["3.34","5.5","13.34","21.2","25.2"],"when":["3.34","10.3","12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.31","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","13.34","15.33"],"destroy":["3.34","13.34"],"在销毁播放器时":["3.34"],"是否同时移除视频的":["3.34"],"但你已经知道播放器的":["4.0"],"属性":["4.0","6.1","7.1","8.1","9.2","9.3","9.5","9.6","26.33","26.34","26.36","26.37"],"方法":["4.0"],"后":["4.0"],"再编写插件是非常简单的事":["4.0"],"可以在实例化的时候加载插件的函数":["4.0"],"function":["4.0","5.1","5.2","5.3","5.4","5.5","5.12","5.13","5.17","5.18","5.19","5.27","5.33","5.34","5.37","5.41","5.42","5.44","9.3","14.0","15.1","15.2","15.3","15.4","15.5","15.12","15.13","15.17","15.18","15.19","15.27","15.33","15.34","15.37","15.41","15.42","15.44","22.4","22.51","26.4","26.51"],"myplugin":["4.0"],"art":["4.0","5.12","7.2","15.12","17.2"],"console":["4.0"],"info":["4.0"],"return":["4.0"],"something":["4.0"],"type":["5.1","5.2","5.3","5.4","5.5","5.6","5.7","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.15","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.24","5.25","5.26","5.27","5.28","5.30","5.31","5.32","5.33","5.34","5.36","5.37","5.38","5.39","5.40","5.41","5.42","5.43","5.44","5.45","5.46","5.47","15.1","15.2","15.3","15.4","15.5","15.6","15.7","15.8","15.9","15.10","15.11","15.12","15.13","15.14","15.15","15.16","15.17","15.18","15.19","15.20","15.21","15.22","15.23","15.24","15.25","15.26","15.27","15.28","15.29","15.30","15.31","15.32","15.33","15.34","15.36","15.37","15.38","15.39","15.40","15.41","15.42","15.43","15.44","15.45","15.46","15.47","16.1","17.1","18.1","19.2","19.3","19.5","19.6","20.10","22.1","22.2","22.3","22.4","22.5","22.6","22.7","22.8","22.9","22.10","22.11","22.12","22.13","22.14","22.15","22.16","22.17","22.18","22.19","22.20","22.21","22.22","22.23","22.24","22.25","22.26","22.27","22.28","22.29","22.30","22.31","22.32","22.33","22.34","22.35","22.36","22.37","22.38","22.39","22.41","22.42","22.43","22.44","22.45","22.46","22.47","22.48","22.49","22.50","22.51","26.1","26.2","26.3","26.4","26.5","26.6","26.7","26.8","26.9","26.10","26.11","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.19","26.20","26.21","26.22","26.23","26.24","26.25","26.26","26.27","26.28","26.29","26.30","26.31","26.32","26.33","26.34","26.35","26.36","26.37","26.38","26.39","26.41","26.42","26.43","26.44","26.45","26.46","26.47","26.48","26.49","26.50","26.51"],"播放视频":["5.1"],"暂停视频":["5.2"],"切换视频的播放和暂停":["5.3"],"parameter":["5.4","5.6","5.7","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.15","5.20","5.21","5.22","5.23","5.24","5.25","5.26","5.30","5.31","5.32","5.34","5.35","5.36","5.45","5.46","5.47","15.4","15.6","15.7","15.8","15.9","15.10","15.11","15.12","15.13","15.14","15.15","15.20","15.21","15.22","15.23","15.24","15.25","15.26","15.30","15.31","15.32","15.34","15.35","15.36","15.45","15.46","15.47","22.4"],"boolean":["5.4","5.14","5.20","5.21","5.22","5.25","7.1","15.4","15.14","15.20","15.21","15.22","15.24","15.25","16.1","17.1","18.1","22.8","22.9","22.10","22.11","22.12","22.13","22.14","22.15","22.16","22.17","22.18","22.19","22.20","22.21","22.22","22.23","22.24","22.25","22.26","22.27","22.28","22.44","22.45","22.46","22.47","22.48","22.49","26.8","26.9","26.10","26.11","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.19","26.20","26.21","26.22","26.23","26.24","26.25","26.26","26.27","26.28","26.44","26.45","26.46","26.47","26.48","26.49"],"重置播放器的视频元素":["5.5"],"会移除当前":["5.5"],"并调用一次":["5.5"],"setter":["5.6","5.7","5.8","5.9","5.10","5.11","5.14","5.15","5.20","5.21","5.22","5.23","5.24","5.26","5.30","5.31","5.32","5.35","5.36","5.45","5.46","5.47","15.6","15.7","15.8","15.9","15.10","15.11","15.14","15.15","15.20","15.21","15.22","15.23","15.24","15.26","15.30","15.31","15.32","15.35","15.36","15.45","15.46","15.47"],"number":["5.6","5.7","5.8","5.9","5.15","5.31","13.14","15.6","15.7","15.8","15.9","15.15","15.31","15.47","21.0","22.7","26.7"],"getter":["5.9","5.10","5.14","5.15","5.16","5.20","5.21","5.22","5.23","5.24","5.25","5.26","5.28","5.30","5.31","5.32","5.35","5.36","5.38","5.39","5.40","5.46","5.47","15.9","15.10","15.14","15.15","15.16","15.20","15.21","15.22","15.23","15.24","15.25","15.26","15.28","15.29","15.30","15.31","15.32","15.35","15.36","15.38","15.39","15.40","15.46","15.47"],"string":["5.11","5.12","5.13","5.23","5.26","5.30","5.32","5.34","5.35","5.36","9.2","9.3","9.5","9.6","15.10","15.11","15.12","15.13","15.23","15.26","15.30","15.32","15.34","15.35","15.36","17.1","19.2","19.3","19.5","19.6","22.1","22.2","22.3","22.5","22.6","22.40","22.42","26.1","26.2","26.3","26.5","26.6","26.40","26.42"],"设置视频地址":["5.11","5.12"],"设置时和":["5.11","5.12"],"设置视频画质地址":["5.13"],"获取视频时长":["5.16"],"下载当前视频帧的截图":["5.17"],"可选参数为截图名字":["5.17"],"获取当前视频帧的截图的":["5.18","5.19"],"base64":["5.18","15.18"],"地址":["5.18","5.19"],"blob":["5.19","15.19"],"设置和获取视频海报":["5.23"],"获取或设置播放器当前状态":["5.26"],"设置视频是否自适应尺寸":["5.27"],"获取播放器的尺寸和坐标信息":["5.28"],"top":["5.29","15.29"],"left":["5.29","15.29"],"right":["5.29","15.29"],"x":["5.29","15.29"],"y":["5.29","15.29"],"当容器只有宽度":["5.33"],"该属性可以自动计算出并设置视频的高度":["5.33"],"动态获取和设置":["5.34"],"开启隔空播放":["5.37"],"视频缓存的比例":["5.38"],"范围是":["5.38","5.40"],"已缓存的媒体时长":["5.39"],"视频播放的比例":["5.40"],"事件的代理函数":["5.41"],"实质上代理了":["5.41"],"的查询函数":["5.42"],"element":["5.43","9.2","9.3","9.5","9.6","15.5","15.43","19.2","19.3","19.5","19.6","22.1","26.1"],"快捷返回播放器的":["5.43"],"动态获取或设置":["5.44"],"css":["5.44"],"变量":["5.44","23.10"],"array":["5.45","9.3","11.1","15.45","19.3","22.29","22.30","22.31","22.32","22.33","22.34","22.35","26.29","26.30","26.31","26.32","26.33","26.34","26.35"],"动态设置画质列表":["5.45"],"object":["5.46","15.46","22.36","22.37","22.38","22.39","22.41","22.43","22.50","26.36","26.37","26.38","26.39","26.41","26.43","26.50"],"类型":["6.1","7.1","8.1","9.2","9.3","9.5","9.6","26.34","26.36","26.37"],"描述":["6.1","7.1","8.1","9.2","9.3","9.5","9.6","26.36"],"disable":["6.1","7.1","8.1","16.1","17.1","18.1"],"var":["7.2","9.4","17.2"],"new":["7.2","17.2","21.3"],"artplayer":["7.2","17.2","20.4","20.5","20.11","20.12","21.2","22.1","23.5","23.11","23.12","24.18","25.2","25.4","26.1"],"container":["7.2","15.33","17.2"],"须先打开设置面板":["9.1"],"然后自带四个内置项":["9.1"],"flip":["9.1"],"playbackrate":["9.1"],"按钮":["9.2"],"html":["9.2","9.3","9.5","9.6","19.2","19.3","19.5","19.6","20.3","23.3","26.39"],"元素的":["9.2","9.3","9.5","9.6"],"选择列表":["9.3"],"icon":["9.3","9.5","9.6","19.3","19.6"],"元素的图标":["9.3"],"selector":["9.3","19.3"],"元素列表":["9.3"],"onselect":["9.3"],"元素点击事件":["9.3"],"列表嵌套":["9.4"],"切换按钮":["9.5"],"范围滑块":["9.6"],"properties":["10.0","11.0","13.0","14.0","15.0"],"the":["10.0","10.1","10.2","10.3","10.4","10.6","10.7","10.8","10.9","10.10","10.11","10.12","10.13","10.14","10.15","10.16","10.17","11.2","11.3","11.4","11.5","11.6","11.7","11.8","11.9","11.10","11.11","11.12","12.0","12.1","12.2","12.3","12.4","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.23","12.24","12.25","12.26","12.27","12.28","12.32","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","12.42","12.43","12.46","12.58","13.0","13.2","13.3","13.4","13.5","13.6","13.7","13.8","13.9","13.10","13.11","13.12","13.13","13.14","13.15","13.16","13.17","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.28","13.29","13.30","13.34","14.0","15.1","15.2","15.4","15.5","15.11","15.12","15.13","15.16","15.18","15.19","15.22","15.28","15.33","15.38","15.39","15.40","15.45","17.1","19.2","19.3","19.5","19.6","20.6","20.9","20.11","20.13","21.0","21.1","22.1","22.2","22.3","22.4","22.5","22.6","22.7","22.11","22.22","22.33","22.34","22.36","22.40","22.41","22.47","22.51"],"player":["10.1","10.2","10.3","10.4","10.6","10.7","10.8","10.9","10.10","10.11","10.12","10.13","10.14","10.15","10.16","10.17","11.1","12.0","12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.14","12.15","12.17","12.18","12.19","12.20","12.21","12.23","12.24","12.25","12.26","12.27","14.0","15.5","15.28","22.7"],"s":["10.1","10.4","10.6","10.7","10.8","10.9","10.10","10.11","10.12","10.13","10.14","10.15","10.16","10.17","12.17","12.18","13.34","14.0","15.5","15.28"],"options":["10.1","22.0"],"manages":["10.2","10.3","10.4","10.5","10.6","10.7","10.8","10.9","10.10","10.11","10.12","10.13","10.14","10.15","10.16","10.17"],"all":["10.2","10.3","10.5","11.1"],"elements":["10.2"],"of":["10.2","11.1","11.6","12.0","13.5","13.6","13.7","13.28","13.29","13.30","15.16","15.38","15.40","20.13","21.0"],"for":["10.3","10.5","12.41","13.8","13.9","13.17","13.26","15.41","19.5","19.6"],"it":["10.3","10.7","22.40"],"essentially":["10.3","15.41"],"proxies":["10.3"],"and":["10.3","10.11","12.0","13.34","14.0","15.23","20.0"],"using":["10.3"],"local":["10.4"],"property":["10.4","10.11","16.1","17.1","18.1","19.2","19.3","19.5","19.6"],"is":["10.4","10.6","10.8","10.9","10.10","10.14","10.16","12.20","20.13"],"used":["10.4","10.6","10.8","10.9","10.10","10.12","10.16","22.39","22.40","22.50"],"to":["10.4","10.6","10.8","10.9","10.10","10.12","10.16","13.1","13.3","13.31","13.32","13.33","13.34","15.12","16.1","17.1","19.1","21.0","22.10","22.15","22.16","22.17","22.19","22.22","22.27","22.33","22.39","22.40","22.47","22.50"],"cache":["10.4"],"method":["10.4","10.6","10.8","10.9","10.10","10.14","10.16"],"notifications":["10.7"],"only":["10.7","15.33","20.11"],"dynamically":["10.8","10.9","10.10","10.16","15.34","15.35","15.36","15.44","15.45"],"context":["10.10","12.37","22.31"],"menu":["10.10","16.0"],"functionality":["10.11","10.14","10.17"],"sets":["10.11","13.32","13.33","15.13","15.14","15.15","15.20","15.21","15.22","15.23","15.26","15.27","15.30","15.31","15.32"],"information":["10.12","22.34"],"panel":["10.12","10.16","12.39","19.0"],"commonly":["10.12"],"layer":["10.13","10.15"],"settings":["10.16","12.39","21.0"],"plugin":["10.17","14.0","24.18"],"with":["10.17","12.0","14.0"],"here":["11.0","15.0"],"returns":["11.1","11.2","11.3","11.4","11.5","11.6","11.7","11.8","11.9","11.10","11.11","11.12","13.2","15.43"],"an":["11.1","12.11","12.48"],"collection":["11.6"],"events":["12.0","14.0","15.41"],"are":["12.0","12.29","12.30","12.31","14.0","21.2"],"divided":["12.0"],"into":["12.0"],"two":["12.0"],"types":["12.0"],"native":["12.0"],"prefixed":["12.0"],"custom":["12.0","12.33","22.29","22.30","22.31","22.32","22.35","22.43"],"listening":["12.0"],"triggered":["12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.29","12.30","12.31","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40"],"switches":["12.2"],"urls":["12.2"],"a":["12.5","12.22","12.33","14.0","15.17","15.33","15.41","15.42","20.13","21.3","21.4","22.4","22.26"],"occurs":["12.11"],"mouse":["12.12","12.13"],"enters":["12.12","12.21","12.23","12.24","12.25"],"state":["12.16"],"windowed":["12.22"],"subtitle":["12.28","22.25"],"offset":["12.28"],"changes":["12.28"],"before":["12.29","21.2"],"subtitles":["12.29","12.30","12.31","22.37"],"updated":["12.29","12.30"],"after":["12.30"],"loaded":["12.31"],"loader":["12.34"],"listens":["12.41"],"browser":["12.42"],"media":["12.46","15.39"],"has":["12.46","15.33"],"whether":["13.1","13.3","13.18","13.31","13.32","13.33","13.34","15.27","16.1","17.1","18.1","20.13","22.10","22.14","22.15","22.16","22.17","22.18","22.19","22.20","22.22","22.23","22.24","22.27","22.33","22.44","22.45","22.46","22.47","22.48","22.49"],"enable":["13.1","13.3","22.8","22.22"],"mode":["13.1"],"display":["13.4","22.17","22.33","22.34"],"duration":["13.4"],"throttle":["13.8","13.9"],"boundary":["13.10"],"tolerance":["13.10"],"distance":["13.10"],"maximum":["13.11","13.14"],"record":["13.11","13.12"],"minimum":["13.12"],"delay":["13.13","13.15","13.17"],"auto":["13.16"],"on":["13.18","13.19","13.20","13.21","13.23","13.24","13.25","22.34","22.36","22.41"],"desktop":["13.18"],"mobile":["13.21","13.23","13.24","13.25","20.13"],"refresh":["13.22"],"interval":["13.22"],"size":["13.26","13.27"],"built":["13.28","13.29","13.30"],"list":["13.28","13.29","13.30","15.45","19.3","19.4"],"mount":["13.31"],"attribute":["13.34"],"call":["13.34"],"plugins":["14.0"],"once":["14.0"],"you":["14.0","19.1","20.9"],"familiar":["14.0"],"methods":["14.0"],"becomes":["14.0"],"very":["14.0"],"straightforward":["14.0"],"task":["14.0"],"can":["14.0","20.9"],"load":["14.0"],"during":["14.0"],"instantiation":["14.0"],"removes":["15.5"],"rewind":["15.8"],"similar":["15.12"],"or":["15.15","15.20","15.22","15.26","15.44"],"gets":["15.15","15.16","15.18","15.19","15.20","15.22","15.23","15.25","15.26","15.28"],"downloads":["15.17"],"defined":["15.33"],"this":["15.33","22.4","22.43"],"initiate":["15.37"],"proportion":["15.38","15.40"],"buffered":["15.39"],"proxying":["15.41"],"quickly":["15.43"],"description":["16.1","17.1","18.1","19.2","19.3","19.5","19.6"],"control":["17.1","22.32"],"first":["19.1"],"need":["19.1"],"open":["19.1"],"button":["19.2","19.5"],"selection":["19.3","22.33"],"nested":["19.4"],"range":["19.6"],"slider":["19.6"],"group":["20.1","20.2","20.3","20.4","20.5","23.1","23.2","23.3","23.4","23.5","24.2","24.3"],"bash":["20.2","23.2","24.2","24.3"],"index":["20.3","23.3","24.18"],"jsx":["20.5","20.8","23.5","23.8"],"import":["20.5","21.4","23.5","23.9","25.4"],"from":["20.5","23.5","25.4"],"useeffect":["20.5","23.5"],"useref":["20.5"],"also":["20.9"],"use":["20.9","22.19","22.27","22.47"],"sometimes":["20.10"],"your":["20.10"],"files":["20.10","21.2"],"may":["20.10"],"lose":["20.10"],"typescript":["20.10","23.10"],"hints":["20.10"],"browsers":["20.11"],"production":["20.11"],"build":["20.11"],"supports":["20.11"],"latest":["20.11"],"major":["20.11"],"module":["20.12","23.12"],"tip":["20.12","23.12"],"esm":["20.12","23.12"],"demo":["20.12","23.12"],"https":["20.12","23.12"],"org":["20.12","23.12"],"useragent":["20.13","23.13"],"currently":["20.13"],"detection":["20.13"],"device":["20.13"],"danger":["21.0","25.0"],"due":["21.0"],"increasing":["21.0"],"languages":["21.1","21.2"],"language":["21.2","21.3","21.4","22.42","26.42"],"bundling":["21.2"],"located":["21.2"],"at":["21.2"],"i18n":["21.2","25.2"],"zhtw":["21.4","25.4"],"where":["22.1"],"source":["22.2"],"unique":["22.3"],"undefined":["22.4","22.51","26.4","26.51"],"constructor":["22.4"],"accepts":["22.4"],"as":["22.4"],"second":["22.4"],"f00":["22.6","26.6"],"false":["22.8","22.9","22.10","22.11","22.12","22.13","22.14","22.15","22.16","22.17","22.18","22.20","22.23","22.24","22.25","22.26","22.27","22.38","22.44","22.46","22.47","22.48","22.49","26.10","26.11","26.12","26.14","26.15","26.16","26.17","26.25","26.27","26.38","26.44","26.47","26.49"],"by":["22.11"],"automatically":["22.12"],"true":["22.19","22.21","22.22","22.28","22.45","26.19","26.22"],"hotkeys":["22.19"],"if":["22.21"],"blur":["22.22"],"ssr":["22.27","26.27"],"server":["22.27"],"initialize":["22.29","22.30","22.31","22.32","22.35"],"panels":["22.30"],"bottom":["22.32"],"preview":["22.36"],"bar":["22.36"],"supported":["22.37"],"formats":["22.37"],"vtt":["22.37","26.37"],"srt":["22.37","26.37"],"ass":["22.37","26.37"],"controls":["22.38","26.38"],"preload":["22.38"],"metadata":["22.38"],"replace":["22.39"],"specify":["22.40"],"format":["22.40"],"needs":["22.40"],"be":["22.40","22.43"],"matches":["22.41"],"based":["22.41"],"navigator":["22.42","26.42"],"configuration":["22.43"],"will":["22.43"],"deeply":["22.43"],"merged":["22.43"],"automatic":["22.47"],"导入":["23.6"],"你也可以使用选项的类型":["23.9"],"ts":["23.9"],"有时你的":["23.10"],"文件会丢失":["23.10"],"的类型提示":["23.10"],"这时候你可以手动导入类型":["23.10"],"生产构建的":["23.11"],"只兼容最新一个主版本的":["23.11"],"chrome":["23.11"],"last":["23.11"],"目前对于是否移动设备的判断并不准确":["23.13"],"有时候希望通过改变":["23.13"],"来调整播放器的ui":["23.13"],"查看完整演示":["24.1"],"jsdelivr":["24.3"],"每一个弹幕是一个对象":["24.4"],"多个弹幕组成的数组就是弹幕库":["24.4"],"通常只需要":["24.4"],"text":["24.4"],"只有":["24.5"],"danmuku":["24.5","24.18"],"是必须的参数":["24.5"],"其余都是非必填":["24.5"],"弹幕数据":["24.5"],"speed":["24.5"],"弹幕持续时间":["24.5"],"范围在":["24.5"],"margin":["24.5"],"来自用户输入的弹幕":["24.6"],"beforeemit":["24.6"],"filter":["24.6"],"beforevisible":["24.6"],"artplayerplugindanmuku":["24.6"],"visible":["24.6"],"来自服务器的弹幕":["24.6"],"xml":["24.8"],"弹幕":["24.8"],"文件":["24.8"],"data":["24.9","24.11","24.12","24.13","24.14","24.18"],"通过方法":["24.10","24.12","24.13"],"进行隐藏或者显示弹幕":["24.10"],"通过属性":["24.11"],"判断当前弹幕是隐藏或者显示":["24.11"],"发送一条实时弹幕":["24.12"],"libs":["24.12","24.13","24.14","24.18"],"实时改变弹幕配置":["24.13"],"uncompiled":["24.13","24.14","24.18"],"通过":["24.14"],"方法可以重载弹幕库":["24.14"],"或者切换新弹幕库":["24.14"],"或者追加新的弹幕库":["24.14"],"用于清空当前显示的弹幕":["24.15"],"在初始化弹幕插件的时候":["24.16"],"是可以指定弹幕发射器的挂载位置的":["24.16"],"默认是挂载在控制栏的中部":["24.16"],"你也可以把它挂载在播放器以外的地方":["24.16"],"当播放器全屏的时候":["24.16"],"发射器会自动回到控制栏的中部":["24.16"],"假如你挂载的地方是亮色的话":["24.16"],"建议把":["24.16"],"用于获取当前弹幕配置":["24.17"],"鉴于捆绑的多国语言越来越多":["25.0"],"从":["25.0"],"默认语言有":["25.1"],"en":["25.1"],"zh":["25.1"],"打包前的语言文件存放于":["25.2"],"欢迎来添加你的语言":["25.2"],"打包后的语言文件存放于":["25.2"],"dist":["25.2"],"播放器挂载的":["26.1"],"视频源地址":["26.2"],"播放器的唯一标识":["26.3"],"构造函数接受一个函数作为第二个参数":["26.4"],"播放器初始化成功且视频可以播放时触发":["26.4"],"ready":["26.4"],"视频的海报":["26.5"],"是否自动播放":["26.10"],"是否使用快捷键":["26.19"],"是否开启播放器":["26.22"],"字幕时间偏移":["26.25"],"是否使用":["26.27"],"初始化自定义的":["26.29","26.30","26.31","26.35"],"层":["26.29"],"设置面板":["26.30"],"右键菜单":["26.31"],"初始化自定义的底部":["26.32"],"控制栏":["26.32"],"是否在底部控制栏里显示":["26.33"],"画质选择":["26.33"],"列表":["26.33"],"在进度条上显示":["26.34"],"高亮信息":["26.34"],"插件":["26.35"],"在进度条上设置":["26.36"],"预览图":["26.36"],"设置视频的字幕":["26.37"],"支持字幕格式":["26.37"],"用于替换默认图标":["26.39"],"支持":["26.39"],"用于指明视频的格式":["26.40"],"需要配合":["26.40"],"customtype":["26.40"],"通过视频的":["26.41"],"自定义":["26.43"],"配置":["26.43"],"该配置会和自带的":["26.43"],"进行深度合并":["26.43"],"新增你的语言":["26.43"],"是否使用自动":["26.47"],"回放功能":["26.47"],"用于改变内置的css变量":["26.50"]},{"0":["3.25","3.26","5.9","13.28","15.38","15.40","21.0","24.5","25.0"],"1":["3.26","3.28","5.9","5.38","5.40","13.28","15.38","15.40","20.11","21.0","23.10","25.0"],"2":["3.28","20.8","20.12","23.8","23.12","23.13"],"3":["3.23","13.29","20.9","22.2","23.10","26.2"],"4":["6.2","13.29","16.2","21.3","22.47","23.13","26.43"],"5":["3.12","3.14","3.25","3.27","13.28","20.12","21.0","22.29","22.30","23.12","23.13","25.0","26.29","26.30"],"6":["2.0","6.3","7.3","12.0","16.3","17.3","20.12","23.12"],"7":["26.7"],"9":["3.29","9.7","19.7","21.3","26.43"],"10":["2.2","3.11","7.2","17.2"],"11":["2.28"],"13":["6.2","6.3","16.2","16.3"],"14":["9.7","19.7"],"15":["14.0"],"16":["3.29","13.29"],"19":["5.45","15.45"],"21":["6.4","6.5","7.3","7.4","8.4","16.4","16.5","17.3","17.4","18.4"],"22":["8.2","8.3","9.8","18.2","18.3","19.8"],"23":["22.29","26.29"],"24":["6.5","16.5"],"25":["3.28","24.5"],"29":["5.45","8.5","18.5"],"34":["22.30","26.30"],"35":["3.7"],"40":["7.5","17.5"],"50":["3.10"],"75":["13.28"],"200":["3.6","3.8","3.9","3.21"],"300":["3.17"],"1000":["3.15","3.22","3.24"],"2000":["3.4"],"3000":["3.13","3.16"],"code":["0.1","0.2","0.4","0.5","0.6","0.7","0.13","0.14","0.15","0.16","0.17","1.1","1.6","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","3.3","3.5","3.6","3.7","3.17","3.29","3.30","5.1","5.2","5.3","5.12","5.14","5.16","5.17","5.20","5.21","5.22","5.23","5.25","5.27","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.44","5.45","5.46","9.3","10.1","10.2","10.5","12.0","12.20","12.29","12.30","12.31","15.2","15.12","15.16","15.37","15.44","15.45","19.3","22.1","22.7","22.10","22.19","22.30","22.31","22.32","22.35","22.43","22.47","24.10","24.16","25.2","26.1","26.4","26.10","26.19","26.30","26.31","26.32","26.35","26.39","26.43","26.47","26.50"],"js":["0.2","0.4","0.14","0.17","2.2","2.18","2.22","2.24","2.28","2.29","2.30","2.31","5.45","6.2","6.3","6.4","7.4","8.4","9.3","9.6","9.7","10.2","12.0","14.0","15.16","15.45","16.2","16.3","16.4","17.4","18.4","19.7","21.3","22.2","22.10","22.19","22.29","22.30","22.47","24.4","24.6","24.11","24.12","24.13","24.14","25.1","26.2","26.4","26.29","26.30","26.32","26.43"],"var":["0.2","0.4","2.0","4.0","5.45","6.2","6.3","6.4","6.5","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.3","9.7","9.8","9.9","10.2","12.0","14.0","16.2","16.3","16.4","16.5","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","21.3","22.2","22.29","22.30","24.13","24.14","24.18","25.3","25.4","26.2","26.29","26.30"],"proxy":["0.3"],"方法用于代理":["0.3"],"hover":["0.3"],"方法用于代理自定义的":["0.3"],"div":["0.3","0.6","0.8","0.9","0.10","0.13","0.15","0.16","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.11","1.12","2.41","3.1","3.2","3.4","3.5","3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.15","3.16","3.17","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.29","3.30","3.32","3.33","5.6","5.7","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.15","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.24","5.25","5.27","5.30","5.31","5.32","5.34","5.35","5.36","5.39","5.41","5.43","5.44","5.46","5.47","9.1","9.3","10.5","12.0","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.20","12.22","12.24","12.26","12.27","12.28","12.29","12.30","12.31","12.34","12.39","12.40","12.41","15.1","15.2","15.3","15.12","15.16","15.20","15.22","15.28","15.33","15.37","15.44","15.45","15.46","15.47","19.3","20.4","22.1","22.7","22.10","22.19","22.31","22.32","22.35","22.39","22.43","22.47","23.4","24.8","24.16","26.1","26.3","26.4","26.5","26.7","26.8","26.9","26.10","26.13","26.17","26.19","26.21","26.26","26.35","26.39","26.43","26.45","26.46","26.47","26.50"],"classname":["0.4","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.14","0.15","0.16","1.1","1.2","1.3","1.4","1.5","1.6","1.7","1.8","1.9","1.10","1.12","2.41","3.1","3.2","3.3","3.4","3.5","3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.16","3.17","3.18","3.19","3.20","3.22","3.23","3.26","3.27","3.29","3.30","3.32","3.33","5.1","5.2","5.3","5.6","5.7","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.24","5.25","5.27","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.43","5.44","5.46","5.47","9.1","9.3","10.1","10.5","12.0","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.15","12.17","12.18","12.20","12.22","12.24","12.26","12.28","12.29","12.30","12.31","12.40","15.1","15.2","15.3","15.12","15.16","15.20","15.22","15.28","15.37","15.44","15.45","15.46","19.3","22.1","22.7","22.10","22.19","22.31","22.32","22.35","22.39","22.43","22.47","24.8","24.10","24.16","26.1","26.3","26.4","26.5","26.7","26.9","26.10","26.13","26.17","26.19","26.31","26.32","26.35","26.39","26.43","26.45","26.46","26.47","26.50"],"run":["0.4","0.5","0.6","0.7","0.10","0.13","0.14","0.15","0.16","0.17","1.1","1.6","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.16","2.19","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.40","2.41","3.3","3.5","3.6","3.7","3.8","3.9","3.10","3.11","3.17","3.22","3.29","3.30","3.32","5.1","5.2","5.3","5.8","5.10","5.12","5.14","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.25","5.27","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.44","5.46","5.47","9.1","9.3","10.1","10.2","10.5","12.0","12.6","12.7","12.8","12.10","12.20","12.22","12.28","12.29","12.30","12.31","15.1","15.2","15.3","15.12","15.16","15.20","15.28","15.37","15.44","15.45","19.3","22.1","22.7","22.10","22.19","22.30","22.31","22.32","22.35","22.43","22.47","24.8","24.10","24.16","26.1","26.4","26.5","26.7","26.10","26.19","26.31","26.32","26.35","26.39","26.43","26.47","26.50"],"art":["0.4","0.12","2.0","5.11","5.13","5.45","6.2","6.3","6.4","6.5","7.3","7.4","7.5","8.2","8.3","8.5","9.3","9.4","9.7","9.8","9.9","10.2","12.0","14.0","15.11","15.13","16.2","16.3","16.4","16.5","17.3","17.4","17.5","18.2","18.3","18.5","19.4","19.7","19.8","19.9","22.2","23.10","24.14","24.18","25.3","25.4","26.2"],"new":["0.4","2.0","4.0","6.2","6.3","6.4","6.5","7.3","7.4","7.5","8.3","9.3","9.4","9.7","9.8","9.9","10.2","12.0","14.0","16.2","16.3","16.4","16.5","17.3","17.4","17.5","18.3","19.4","19.7","19.8","19.9","21.2","22.2","24.14","24.18","25.3","26.2"],"artplayer":["0.4","2.0","4.0","5.5","6.2","6.3","6.4","6.5","7.3","7.4","7.5","9.3","9.4","9.8","9.9","12.0","14.0","16.2","16.3","16.4","16.5","17.3","17.4","17.5","19.4","19.8","19.9","20.3","20.6","21.4","22.2","23.3","23.4","23.6","23.9","23.10","24.6","24.7","24.9","24.10","24.11","24.12","24.13","24.14","24.15","24.17","26.2"],"container":["0.4","2.0","4.0","6.4","6.5","7.3","7.5","9.3","9.4","9.8","9.9","12.0","14.0","16.4","16.5","17.3","17.5","19.4","19.8","19.9","20.4","20.5","22.2","22.11","23.5","24.18","26.11"],"方法用于更新":["0.6"],"对象":["0.6"],"方法用于动态更新层":["0.8"],"show":["0.8","0.9","0.10","0.12","0.16","10.7"],"属性用于设置是否显示全部层":["0.8"],"toggle":["0.8","0.9","0.10","0.16","22.18"],"方法用于切换是否显示全部层":["0.8"],"方法用于动态更新控制器":["0.9"],"属性用于设置是否显示全部控制器":["0.9"],"方法用于切换是否显示全部控制器":["0.9"],"属性用于设置是否显示全部菜单":["0.10"],"方法用于切换是否显示全部菜单":["0.10"],"方法设置当前字幕地址和选项":["0.11"],"texttrack":["0.11"],"获取当前字幕轨":["0.11"],"activecues":["0.11"],"获取当前活跃的字幕列表":["0.11"],"cues":["0.11"],"通过":["0.12"],"控制面板的显示与隐藏":["0.12"],"触发的事件名为":["0.12"],"属性用于切换是否显示加载层":["0.13"],"属性用于切换是否显示遮罩层":["0.15"],"属性用于设置是否显示全部设置项":["0.16"],"方法用于切换是否显示全部设置项":["0.16"],"字符串":["1.11"],"app":["2.0","4.0","7.2","7.5","9.3","9.4","9.8","9.9","12.0","14.0","17.2","17.5","19.4","19.8","19.9","22.2","24.18"],"url":["2.0","4.0","5.11","7.2","7.5","9.4","9.9","12.0","14.0","15.11","15.13","17.2","17.5","19.4","19.9","22.36","22.37","24.18","26.36","26.37"],"assets":["2.0","4.0","7.2","8.2","8.3","8.4","8.5","9.4","9.9","12.0","14.0","17.2","18.2","18.3","18.4","18.5","19.4","19.9","22.2","22.29","24.18","26.29"],"sample":["2.0","4.0","7.2","8.2","8.3","8.4","8.5","9.4","9.9","12.0","14.0","17.2","18.2","18.3","18.4","18.5","19.4","19.9","22.29","24.18","26.29"],"mp4":["2.0","4.0","7.2","14.0","17.2","24.18"],"on":["2.0","4.0","12.16","19.6","22.21","22.45"],"canplay":["2.0"],"事件":["2.41"],"浏览器可以播放媒体文件了":["2.42"],"浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束":["2.43"],"offlineaudiocontext":["2.44"],"duration":["2.45","13.12","13.13","15.39"],"媒体内容变为空":["2.46"],"例如":["2.46"],"视频停止播放":["2.47"],"获取媒体数据时出错":["2.48"],"media":["2.49","12.59","13.34"],"已加载元数据":["2.50"],"播放已暂停":["2.51"],"播放已开始":["2.52"],"由于缺乏数据而暂停或延迟后":["2.53"],"在浏览器加载资源时周期性触发":["2.54"],"播放速率发生变化":["2.55"],"跳帧":["2.56","2.57"],"用户代理":["2.58"],"媒体数据加载已暂停":["2.59"],"currenttime":["2.60"],"音量发生变化":["2.61"],"由于暂时缺少数据":["2.62"],"可以打印出视频全部的内置事件":["3.1"],"默认关闭":["3.1"],"默认为":["3.4","3.8","3.9","3.10","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.27","3.31","3.34","5.4"],"单位为毫秒":["3.15","3.21","3.24"],"true":["3.18","3.19","3.31","3.32","3.34","5.4","13.34","26.21","26.28","26.45"],"false":["3.20","3.33","13.33","26.8","26.9","26.13","26.18","26.20","26.23","26.24","26.26","26.46","26.48"],"是否把播放器挂在在":["3.31"],"元素下":["3.31"],"目前主要用于进度条的平滑效果":["3.33"],"属性并调用":["3.34"],"load":["3.34","5.5","13.34","15.5"],"以主动释放媒体资源":["3.34"],"开启后可以在单页应用或频繁创建":["3.34"],"销毁播放器的场景下":["3.34"],"dosomething":["4.0","14.0"],"video":["4.0","5.34","5.38","5.40","7.2","9.4","9.9","10.12","14.0","15.1","15.2","15.7","15.8","15.9","15.10","15.14","15.15","15.17","15.23","15.25","15.27","15.33","15.34","15.35","17.2","19.4","19.9","22.4","22.14","22.15","22.16","24.18","26.41"],"plugins":["4.0"],"ready":["4.0","12.2","12.53","22.4"],"可以在实例化之后再加载插件的函数":["4.0"],"销毁播放器":["5.4"],"接受一个参数表示是否销毁后同时移除播放器的":["5.4"],"html":["5.4","20.12","22.39","23.12","26.27","26.33"],"常用于在单页应用中手动释放媒体资源或重新初始化视频标签":["5.5"],"注意":["5.5"],"全局配置":["5.5"],"remove":["5.5","10.8","10.9","10.10","10.14","10.16"],"视频时间跳转":["5.6"],"单位秒":["5.6","5.7","5.8","26.34"],"视频时间快进":["5.7"],"视频时间快退":["5.8"],"设置和获取视频音量":["5.9"],"范围在":["5.9","26.25"],"string":["5.10","6.1","7.1","8.1","11.11","16.1","18.1","22.36","22.37","26.33","26.34","26.36","26.37"],"设置和获取视频地址":["5.10"],"类似":["5.11","5.12","5.13","5.15","5.42"],"但会执行一些优化操作":["5.11","5.12"],"switchurl":["5.13","15.13"],"但会带上之前的播放进度":["5.13"],"设置和获取视频是否静音":["5.14"],"设置和获取视频当前时间":["5.15"],"设置时间时和":["5.15"],"seek":["5.15"],"但它不会触发额外的事件":["5.15"],"返回的是一个":["5.18","5.19"],"promise":["5.18","5.19"],"设置和获取播放器窗口全屏":["5.20"],"设置和获取播放器网页全屏":["5.21"],"设置和获取播放器画中画模式":["5.22"],"只有在视频播放前才能看到海报效果":["5.23"],"boolean":["5.24","6.1","8.1","9.5","19.5","26.33"],"设置和获取播放器迷你模式":["5.24"],"获取视频是否正在播放中":["5.25"],"支持":["5.26","5.30"],"standard":["5.26","15.26"],"正常":["5.26"],"mini":["5.26","22.12","22.26"],"迷你窗":["5.26"],"pip":["5.26"],"type":["5.29","11.10","20.9","23.9","23.10"],"getter":["5.29"],"这些属性是对":["5.29"],"rect":["5.29","15.29"],"的快捷访问":["5.29"],"设置和获取播放器翻转":["5.30"],"normal":["5.30","13.30"],"horizontal":["5.30","13.30"],"vertical":["5.30"],"设置和获取播放器播放速度":["5.31"],"设置和获取播放器长宽比":["5.32"],"元素的属性":["5.34"],"动态获取和设置视频类型":["5.35"],"动态获取和设置播放器主题颜色":["5.36"],"常配合":["5.38","5.40"],"timeupdate":["5.38","5.40"],"事件使用":["5.38","5.40"],"通常与":["5.39"],"loaded":["5.39"],"一起使用":["5.39","26.40"],"用于展示缓冲进度细节":["5.39"],"和":["5.41","26.6","26.14","26.15","26.16"],"removeeventlistener":["5.41","15.41"],"当使用":["5.41"],"来处理事件":["5.41"],"播放器销毁时也会自动销毁该事件":["5.41"],"document":["5.42","12.41","15.42"],"queryselector":["5.42","15.42"],"但被查询的对象局限于当前播放器内":["5.42"],"可以避免同类名的错误":["5.42"],"元素":["5.43"],"动态设置缩略图":["5.46"],"number":["5.47","9.2","9.3","17.1","19.3","22.34","22.36","26.34","26.36"],"动态设置字幕偏移":["5.47"],"是否禁用组件":["6.1","7.1","8.1"],"name":["6.1","7.1","7.2","8.1","14.0","16.1","17.2","18.1","22.37","26.37"],"组件唯一名称":["7.1"],"用于标记类名":["7.1"],"index":["7.1","7.2","17.1","17.2","24.6","24.9","24.11","24.12","24.13","24.14"],"controls":["7.2","17.2"],"your":["7.2","17.2","22.43"],"button":["7.2","17.2","22.18","22.44","22.49"],"img":["8.2","8.3","8.4","8.5","18.2","18.3","18.4","18.5","22.29","26.29"],"layer":["8.2","8.3","8.4","8.5","10.8","12.35","12.36","18.2","18.3","18.4","18.5"],"png":["8.2","8.3","8.5","18.2","18.3","18.5"],"aspectratio":["9.1"],"subtitleoffset":["9.1"],"icon":["9.2","19.2","19.5"],"元素的图标":["9.2","9.5","9.6"],"onclick":["9.2","19.2"],"function":["9.2","9.5","9.6","11.9","19.2","19.3","19.6","20.5","22.14","22.15","22.16","22.17","23.5","24.6"],"元素点击事件":["9.2"],"width":["9.2","19.3"],"列表宽度":["9.3"],"tooltip":["9.3","9.5","9.6","19.3"],"提示文本":["9.3","9.6"],"switch":["9.5","19.5"],"按钮默认状态":["9.5"],"onswitch":["9.5"],"按钮切换事件":["9.5"],"range":["9.6","15.9"],"array":["9.6","19.6"],"默认状态数组":["9.6"],"onrange":["9.6","19.6"],"完成时触发的事件":["9.6"],"onchange":["9.6"],"变化时触发的事件":["9.6"],"here":["10.0","13.0"],"following":["10.3"],"methods":["10.3"],"to":["10.3","10.13","10.14","10.15","12.0","12.2","13.0","15.5","15.6","15.11","15.13","15.29","15.41","15.42","18.1","20.13","22.4","22.9","22.13","22.14","22.18","22.20","22.23","22.24","22.28","22.38","22.41","22.44","22.45","22.46","22.48","22.49"],"handle":["10.3","15.41"],"will":["10.3","22.8","22.38"],"also":["10.3"],"be":["10.3","11.1"],"automatically":["10.3","12.18","12.19","15.33","15.41","22.38"],"destroyed":["10.3","12.6"],"is":["10.3","10.13","10.15","12.1","12.3","12.5","12.6","12.9","12.10","12.11","12.18","12.19","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.53","13.3","13.5","13.28","13.29","13.30","13.33","13.34","15.14","15.23","15.25","15.41","22.1","22.4","22.40"],"a":["10.4","10.7","10.8","10.9","12.26","12.27","12.56","12.57","13.6","13.7","13.15","15.4","15.6","15.18","15.19","22.44","22.46","22.51"],"get":["10.4","15.9","15.10","15.35","15.36"],"retrieve":["10.4","10.6"],"del":["10.4"],"the":["10.5","12.11","12.44","12.49","12.55","12.60","12.61","13.31","13.32","15.7","15.8","15.9","15.10","15.14","15.15","15.17","15.20","15.21","15.23","15.24","15.25","15.26","15.27","15.30","15.31","15.32","15.34","15.35","15.36","15.41","15.42","15.43","16.1","18.1","19.1","20.10","22.14","22.15","22.16","22.17","22.18","22.20","22.21","22.23","22.24","22.42","22.43","22.48","22.49","22.50"],"player":["10.5","11.6","12.11","12.12","12.13","12.28","13.2","13.31","13.32","13.34","15.4","15.20","15.21","15.22","15.24","15.26","15.30","15.31","15.32","15.36","15.43","20.5","22.1","22.3","22.4","22.6","22.11","22.12","22.22","22.23","22.24","22.48","23.5"],"an":["10.6","15.17"],"value":["10.6"],"update":["10.6","10.10","10.16"],"has":["10.7","12.47","12.62"],"property":["10.7","10.13","10.15","11.1","15.33","22.33","22.34","22.36","22.37"],"for":["10.7","10.17","11.6","11.7","12.1","12.46","13.10","13.11","13.12","13.13","13.15","13.16","13.21","13.22","13.23","13.24","13.25","13.27","17.1","20.9","20.11","21.2","22.3","22.22"],"displaying":["10.7"],"control":["10.9","22.17","22.33"],"items":["10.10","10.16"],"returns":["10.11"],"current":["10.11","10.12","15.5","15.15","15.17","15.18","15.19","15.26"],"style":["10.11"],"method":["10.11","10.17"],"of":["10.11","10.12","11.2","11.3","11.4","11.8","11.12","13.4","13.14","15.15","15.17","15.18","15.19","15.34","17.1","19.3","19.5","20.11","22.40"],"status":["10.12"],"and":["10.12","12.2","15.3","15.5","15.9","15.10","15.24","15.28","15.30","15.31","15.32","15.33","15.34","15.35","15.36","15.41","20.12","22.4","22.39","22.41"],"such":["10.12","20.10","22.22"],"as":["10.12","22.22"],"used":["10.13","10.14","10.15","15.5","15.39","17.1"],"set":["10.13","10.15","12.18","12.19","15.10","15.33","15.34","15.35","15.36","15.46","15.47"],"whether":["10.13","10.15","13.19","13.20","15.4","15.14","15.25","22.9","22.13","22.28"],"display":["10.13","10.15","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.42","22.44","22.49"],"hotkeys":["10.14"],"only":["10.17","15.23","22.5","22.26"],"one":["10.17"],"add":["10.17","22.43","22.46"],"dynamically":["10.17","15.46","15.47"],"adding":["10.17"],"this":["11.1","22.8"],"can":["11.1","12.42","13.1","15.33","20.10","20.11","22.51"],"useful":["11.1","22.27"],"information":["11.2","15.28"],"environment":["11.3"],"variables":["11.3","15.44","22.50"],"timestamp":["11.4"],"default":["11.5","11.12","13.3","13.8","13.9","13.18","13.28","13.29","13.30","13.32","13.33","13.34","19.5","19.6","20.5","23.5"],"configuration":["11.5"],"utility":["11.6"],"functions":["11.6"],"validation":["11.7","11.9"],"schema":["11.7"],"constructor":["11.8"],"detection":["11.10"],"required":["11.11"],"options":["11.12","13.30","20.9"],"first":["12.1"],"becomes":["12.2"],"play":["12.2"],"paused":["12.3"],"starts":["12.4"],"playing":["12.4","12.42"],"pressed":["12.5"],"gains":["12.7"],"loses":["12.8"],"focus":["12.8"],"double":["12.9","13.17","13.18","13.19"],"clicked":["12.9","12.10"],"while":["12.11","12.48"],"loading":["12.11"],"or":["12.12","12.21","12.23","12.24","12.25","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","15.14","15.21"],"leaves":["12.12"],"moves":["12.13"],"over":["12.13"],"s":["12.14","12.19","15.20","15.21","15.22","15.26","15.30","15.31","15.32","15.33","15.36","15.43","22.6","22.7","22.11","22.41"],"dimensions":["12.14","15.28","22.11"],"change":["12.14"],"enters":["12.15","22.12"],"viewport":["12.15"],"changes":["12.16","12.17","12.40"],"mobile":["12.16"],"devices":["12.16"],"aspect":["12.17","15.32","22.16"],"ratio":["12.17","22.16"],"height":["12.18","15.33"],"size":["12.19","15.27"],"flipped":["12.20"],"exits":["12.21","12.23","12.24","12.25"],"windowed":["12.21"],"mode":["12.21","12.23","12.24","15.22","22.8","22.12","22.27","22.28","24.5"],"error":["12.22"],"occurs":["12.22"],"web":["12.23","15.21","22.24"],"fullscreen":["12.23","22.48"],"picture":["12.25","15.22","22.20"],"in":["12.25","12.28","13.4","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.22","15.6","15.8","15.22","15.39","22.17","22.20","22.33","22.38","22.43","22.48","22.50"],"takes":["12.26"],"performs":["12.27","15.12"],"time":["12.27","15.6","15.7","15.8","15.15","22.34","26.34"],"panel":["12.32","13.5","13.6","13.7","13.22","19.1"],"shown":["12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39"],"hidden":["12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39"],"menu":["12.37","13.3"],"bar":["12.38","22.17","22.26","22.32","22.33","22.34"],"state":["12.40","15.20","15.30","19.5","19.6"],"event":["12.41","13.8","13.9","13.10","13.17","15.41","19.3","19.6"],"from":["12.41","15.38","15.40","20.12","21.0","21.4","22.25","23.9","25.2"],"start":["12.42","22.9"],"browser":["12.43"],"estimates":["12.43"],"triggered":["12.45","19.6","22.4"],"become":["12.46"],"empty":["12.46"],"example":["12.46"],"playback":["12.47","12.51","12.52","12.62","15.15","15.31","22.13","22.15"],"occurred":["12.48"],"metadata":["12.50","26.38"],"fired":["12.54"],"user":["12.58"],"agent":["12.58"],"refer":["13.0"],"which":["13.1","22.5"],"print":["13.1","13.32"],"all":["13.1"],"built":["13.1","22.43","22.50"],"context":["13.3"],"notification":["13.4"],"messages":["13.4"],"milliseconds":["13.4","13.8","13.9","13.17","13.22"],"settings":["13.5","13.6","13.7","19.1"],"pixels":["13.5","13.10"],"view":["13.10"],"count":["13.11"],"feature":["13.12","13.13","22.47"],"automatic":["13.14","13.15"],"reconnection":["13.14","13.15"],"attempts":["13.14"],"when":["13.14","13.15","15.11","15.12","15.41","22.4","22.5","22.12","22.22"],"connection":["13.15"],"delay":["13.16","13.21","13.24"],"bottom":["13.16","22.17","22.33"],"click":["13.17","13.18","13.19","19.2","19.3"],"toggles":["13.18","13.19","13.20"],"single":["13.20"],"rotation":["13.21"],"speed":["13.23","13.25","22.15"],"multiplier":["13.23","13.25"],"long":["13.23","13.24","22.46"],"press":["13.23","13.24","22.46"],"left":["13.25"],"right":["13.25"],"adjustment":["13.26"],"via":["13.26","13.27"],"keyboard":["13.26","13.27"],"shortcuts":["13.26","13.27"],"seeking":["13.27"],"rates":["13.28"],"ratios":["13.29"],"under":["13.31"],"element":["13.31","15.34"],"requestanimationframe":["13.33"],"currently":["13.33","15.25","22.3","22.6","22.42"],"it":["13.33","19.1","22.38"],"actively":["13.34"],"release":["13.34","15.5"],"resources":["13.34","21.0"],"destroying":["13.34"],"myplugin":["14.0"],"console":["14.0"],"info":["14.0"],"return":["14.0","22.51"],"something":["14.0"],"pause":["15.3"],"accepts":["15.4"],"indicating":["15.4"],"src":["15.5"],"calls":["15.5"],"once":["15.5"],"commonly":["15.5"],"manually":["15.5","20.10"],"specific":["15.6"],"fast":["15.7"],"seconds":["15.8","15.39"],"similar":["15.11","15.13","15.42"],"setting":["15.11","15.12","15.15"],"but":["15.12","15.13","15.42"],"some":["15.12"],"optimization":["15.12"],"operations":["15.12"],"quality":["15.13"],"gets":["15.14","15.21","15.24","15.30","15.31","15.32"],"frame":["15.17"],"screenshot":["15.18","15.19"],"window":["15.20","22.23"],"effect":["15.23","22.22"],"visible":["15.23"],"sets":["15.24"],"supported":["15.26"],"values":["15.26"],"adapts":["15.27"],"its":["15.27"],"coordinate":["15.28"],"these":["15.29"],"properties":["15.29"],"provide":["15.29"],"quick":["15.29"],"access":["15.29"],"calculate":["15.33"],"attributes":["15.34"],"buffered":["15.38"],"ranging":["15.38","15.40","22.25"],"often":["15.38","15.40","22.11"],"typically":["15.39"],"alongside":["15.39"],"using":["15.41"],"search":["15.42"],"css":["15.44","22.50"],"subtitle":["15.47"],"offset":["15.47","22.25"],"component":["16.1","18.1"],"unique":["16.1","17.1","18.1"],"class":["17.1"],"marking":["17.1"],"comes":["19.1"],"with":["19.1","22.40","22.43"],"four":["19.1"],"elements":["19.3"],"onselect":["19.3"],"text":["19.3","26.34"],"item":["19.5"],"usage":["20.0"],"bash":["20.1","23.1"],"npm":["20.1","23.1","24.2"],"jsdelivr":["20.2","23.2"],"net":["20.2","23.2","24.3"],"https":["20.2","23.2","24.3"],"head":["20.3","23.3"],"title":["20.3","23.3"],"demo":["20.3"],"meta":["20.3"],"charset":["20.3"],"template":["20.4","23.4"],"ref":["20.4"],"export":["20.5","23.5"],"option":["20.5","23.5"],"getinstance":["20.5","23.5"],"rest":["20.5","23.5"],"const":["20.5","23.5"],"d":["20.6"],"import":["20.8","20.10","23.8","23.10","25.2"],"ts":["20.9","26.40"],"cases":["20.10"],"you":["20.10","20.11","20.13","22.27"],"types":["20.10"],"variable":["20.10"],"version":["20.11","20.12","21.0","23.11"],"chrome":["20.11"],"last":["20.11"],"starting":["20.12","21.0"],"not":["20.13"],"always":["20.13"],"accurate":["20.13"],"sometimes":["20.13"],"may":["20.13"],"want":["20.13","22.27"],"adjust":["20.13","22.38"],"bundled":["21.0","21.2"],"multilingual":["21.0"],"are":["21.1"],"en":["21.1","26.42"],"zh":["21.1","21.4","25.4","26.42"],"cn":["21.1","25.1"],"contributions":["21.2"],"welcome":["21.2"],"i18n":["21.4","25.4"],"tw":["21.4","25.4"],"mounted":["22.1"],"identifier":["22.3"],"successfully":["22.4"],"initialized":["22.4"],"image":["22.5","22.36"],"appears":["22.5","22.25"],"color":["22.6","24.5"],"live":["22.8"],"streaming":["22.8"],"fill":["22.11"],"entire":["22.11"],"multiple":["22.21"],"players":["22.21"],"exist":["22.21"],"page":["22.21"],"ui":["22.22","26.22"],"enabled":["22.22"],"overlays":["22.22"],"5s":["22.25","26.25"],"progress":["22.26","22.34"],"that":["22.26"],"side":["22.27"],"rendering":["22.27"],"mount":["22.27"],"if":["22.27"],"use":["22.28"],"menus":["22.31"],"list":["22.33"],"description":["22.33","22.34","22.36","22.37"],"thumbnail":["22.36"],"safari":["22.38","26.38"],"supports":["22.39"],"strings":["22.39"],"htmlelement":["22.39","26.39"],"together":["22.40"],"customtype":["22.40"],"by":["22.40"],"determined":["22.40"],"suffix":["22.40"],"delegates":["22.41"],"decoding":["22.41"],"third":["22.41","22.51"],"party":["22.41","22.51"],"tolowercase":["22.42","26.42"],"language":["22.43"],"enable":["22.45"],"events":["22.45"],"rotate":["22.48"],"modify":["22.50"],"htmlcanvaselement":["22.51","26.51"],"useref":["23.5"],"let":["23.10"],"null":["23.10"],"参数":["23.10"],"对于古老的浏览器":["23.11"],"可以使用":["23.11"],"legacy":["23.11"],"文件":["23.11"],"从":["23.12"],"开始":["23.12"],"所以在":["23.13"],"开始新增了一个":["23.13"],"install":["24.2"],"就可以发送一个弹幕":["24.4"],"其余都是非必要参数":["24.4"],"弹幕文本":["24.4"],"弹幕上下边距":["24.5"],"支持像素数字和百分比":["24.5"],"opacity":["24.5"],"弹幕透明度":["24.5"],"ffffff":["24.5"],"默认弹幕颜色":["24.5"],"可以被单独弹幕项覆盖":["24.5"],"data":["24.6","24.7","24.10","24.15","24.17"],"libs":["24.6","24.7","24.9","24.10","24.11","24.15","24.17"],"uncompiled":["24.6","24.7","24.9","24.10","24.11","24.12","24.15","24.17"],"plugin":["24.6","24.7","24.9","24.10","24.11","24.12","24.13","24.14","24.15","24.17"],"danmuku":["24.6","24.9","24.11","24.12","24.13","24.14","24.15","24.17"],"保存到数据库":["24.6"],"savedanmu":["24.6"],"bilibili":["24.8"],"网站的弹幕格式一致":["24.8"],"theme":["24.16"],"设置成":["24.16"],"light":["24.16"],"否则会看不清":["24.16"],"无需手动导入":["25.1"],"group":["25.2"],"id":["25.2"],"容器":["26.1"],"目前只用于记忆播放":["26.3"],"autoplayback":["26.3"],"事件一样":["26.4"],"只会出现在播放器初始化且未播放的状态下":["26.5"],"播放器主题颜色":["26.6"],"目前用于":["26.6"],"进度条":["26.6"],"播放器的默认音量":["26.7"],"使用直播模式":["26.8"],"会隐藏进度条和播放时间":["26.8"],"是否默认静音":["26.9"],"播放器的尺寸默认会填充整个":["26.11"],"容器尺寸":["26.11"],"所以经常出现黑边":["26.11"],"该值能自动调整播放器尺寸以隐藏黑边":["26.11"],"当播放器滚动到浏览器视口以外时":["26.12"],"自动进入":["26.12"],"迷你播放":["26.12"],"模式":["26.12","26.28"],"是否循环播放":["26.13"],"是否显示视频翻转功能":["26.14"],"目前只出现在":["26.14"],"设置面板":["26.14","26.15","26.16","26.18","26.22","26.25"],"右键菜单":["26.14","26.15","26.16","26.22"],"是否显示视频播放速度功能":["26.15"],"会出现在":["26.15","26.16"],"是否显示视频长宽比功能":["26.16"],"是否在底部控制栏里显示":["26.17","26.18","26.20"],"视频截图":["26.17"],"功能":["26.17"],"的开关按钮":["26.18","26.20"],"画中画":["26.20"],"假如页面里同时存在多个播放器":["26.21"],"是否只能让一个播放器播放":["26.21"],"的背景虚化效果":["26.22"],"开启后":["26.22"],"是否在底部控制栏里显示播放器":["26.23","26.24"],"窗口全屏":["26.23"],"按钮":["26.23","26.24","26.49"],"网页全屏":["26.24"],"出现在":["26.25"],"迷你进度条":["26.26"],"只在播放器失去焦点后且正在播放时出现":["26.26"],"挂载模式":["26.27"],"假如你希望在播放器挂载前":["26.27"],"就提前渲染好播放器所需的":["26.27"],"时有用":["26.27"],"你可以通过":["26.27"],"在移动端是否使用":["26.28"],"类型":["26.33"],"描述":["26.33","26.34","26.37"],"默认画质":["26.33"],"画质名字":["26.33"],"高亮时间":["26.34"],"高亮文本":["26.34"],"预览图地址":["26.36"],"预览图数量":["26.36"],"column":["26.36"],"字幕名字":["26.37"],"字幕地址":["26.37"],"字幕类型":["26.37"],"可选":["26.37"],"preload":["26.38"],"中会自动调整为":["26.38"],"字符串和":["26.39"],"默认视频的格式就是视频地址的后缀":["26.40"],"如":["26.40"],"m3u8":["26.40"],"mkv":["26.40"],"但有时候视频地地址没有正确的后缀":["26.40"],"进行匹配":["26.41"],"把视频解码权交给第三方程序进行处理":["26.41"],"处理的函数能接收三个参数":["26.41"],"视频":["26.41"],"dom":["26.41"],"默认显示语言":["26.42"],"目前支持":["26.42"],"是否在移动端显示一个":["26.44"],"锁定按钮":["26.44"],"用于隐藏底部":["26.44"],"控制栏":["26.44"],"是否在移动端启用视频元素上的手势事件":["26.45"],"是否在移动端添加长按视频快进功能":["26.46"],"是否在移动端的网页全屏时":["26.48"],"根据视频尺寸和视口尺寸":["26.48"],"旋转播放器":["26.48"],"是否显示":["26.49"],"当前只有部分浏览器支持该功能":["26.49"],"函数可以返回一个第三方的":["26.51"],"或者":["26.51"],"htmlvideoelement":["26.51"],"例如可以代理一个已经存在的":["26.51"]},{"0":["9.6","13.25","13.26","15.9"],"1":["9.6","13.26","15.9","19.6","20.10"],"2":["13.28","22.1","24.5","26.1"],"3":["13.23","20.7","20.10","23.7"],"4":["22.7","22.10","22.19","22.31","22.32","22.39","22.43","25.1","26.10","26.19","26.31","26.32","26.39","26.47","26.50"],"5":["9.6","13.12","13.27","19.6","22.47","26.47"],"6":["2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40"],"7":["2.19","2.21","2.23","2.25","2.26","5.16","5.28","5.33","15.16","15.28","15.33","22.4","26.4","26.39"],"8":["2.17","2.20","5.1","5.14","5.21","5.31","5.32","5.34","5.35","5.36","5.44","12.20","15.44","20.3"],"9":["2.29","2.30","2.31","5.12","5.20","5.22","5.23","5.37","12.29","12.30","12.31","13.29","15.12","15.20","15.22","15.37","22.43","26.4"],"10":["2.6","2.18","2.24","7.5","9.6","13.11","17.5","24.4"],"11":["5.2","5.3","5.21","5.33","12.28","15.2","15.33","23.11"],"12":["22.31","26.31"],"15":["22.35","26.35"],"16":["22.32","26.32"],"17":["4.0","14.0"],"25":["13.28"],"29":["15.45"],"35":["13.7"],"50":["13.10"],"200":["13.6","13.8","13.9","13.21"],"250":["9.3","13.5","19.3"],"300":["13.17"],"1000":["13.22","13.24","24.6"],"2000":["13.4"],"3000":["13.13"],"是指挂载在":["0.0","1.0","5.0"],"js":["0.1","0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.15","0.16","1.1","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.19","2.20","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.3","3.5","3.6","3.7","3.8","3.9","3.10","3.17","3.28","3.29","3.30","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.25","5.27","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.41","5.44","5.46","5.47","9.1","9.5","10.1","10.4","10.5","10.6","10.14","12.2","12.6","12.17","12.20","12.22","12.24","12.28","12.29","12.30","12.31","15.1","15.2","15.3","15.12","15.20","15.22","15.28","15.33","15.37","15.44","15.46","19.3","19.6","21.0","22.1","22.4","22.7","22.31","22.32","22.35","22.39","22.43","24.7","24.9","24.10","24.15","24.16","24.17","25.0","26.1","26.7","26.10","26.19","26.31","26.34","26.35","26.39","26.47","26.50"],"var":["0.1","0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.14","0.15","0.16","0.17","2.1","2.2","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.28","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","5.2","5.3","5.12","5.14","5.16","5.20","5.22","5.23","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.44","5.46","9.5","10.1","10.5","10.14","12.22","12.29","12.30","12.31","15.12","15.16","15.20","15.22","15.33","15.44","15.45","19.3","21.4","22.1","22.7","22.10","22.19","22.31","22.32","22.43","22.47","24.6","24.9","24.10","24.11","24.12","25.1","25.2","26.1","26.4","26.10","26.19","26.31","26.32","26.39","26.43","26.47"],"art":["0.1","0.2","0.5","0.6","0.7","0.10","0.14","0.16","0.17","2.2","2.6","2.11","2.12","2.16","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.28","2.29","2.30","2.31","2.39","5.16","5.20","5.22","5.23","5.28","5.33","5.44","8.4","9.5","10.1","10.5","12.31","15.16","15.20","15.22","15.33","15.44","15.45","18.4","19.3","20.5","20.10","21.3","21.4","22.1","22.7","22.10","22.19","22.29","22.30","22.31","22.32","22.43","22.47","23.5","24.6","24.11","24.12","24.13","25.1","25.2","26.1","26.4","26.19","26.29","26.30","26.31","26.32","26.35","26.39","26.41","26.43","26.47"],"new":["0.1","0.2","0.6","0.7","0.14","0.16","0.17","2.2","2.6","2.17","2.18","2.20","2.22","2.24","2.28","2.29","2.30","2.31","5.12","5.23","5.44","5.45","8.2","8.4","8.5","10.1","15.12","15.16","15.20","15.33","15.45","18.2","18.4","18.5","19.3","20.5","21.4","22.1","22.7","22.10","22.19","22.29","22.30","22.31","22.32","22.43","22.47","23.5","24.6","24.11","24.12","24.13","25.4","26.1","26.4","26.29","26.30","26.31","26.32","26.43"],"artplayer":["0.2","0.7","0.14","0.16","0.17","2.2","2.22","2.24","2.28","2.29","2.30","2.31","3.5","3.6","3.7","3.29","3.30","5.12","5.23","5.45","8.2","8.3","8.4","8.5","9.7","10.1","10.2","15.12","15.16","15.45","18.2","18.3","18.4","18.5","19.3","19.7","20.1","20.8","20.9","20.10","21.0","21.3","22.10","22.19","22.29","22.30","22.32","22.43","22.47","23.1","23.8","24.2","24.3","24.8","24.16","25.0","25.3","26.4","26.27","26.29","26.30","26.32","26.43"],"container":["0.2","0.3","0.14","0.17","2.2","2.28","5.12","5.45","6.2","6.3","7.4","8.2","8.3","8.4","8.5","9.7","10.2","15.12","15.16","15.45","16.2","16.3","17.4","18.2","18.3","18.4","18.5","19.3","19.7","21.4","22.10","22.19","22.29","22.30","22.32","22.43","22.47","23.4","23.9","24.6","24.11","24.12","24.13","24.14","25.3","25.4","26.2","26.4","26.29","26.30","26.32","26.43"],"app":["0.2","0.4","0.14","5.45","6.2","6.3","6.4","6.5","7.3","7.4","8.2","8.3","8.4","8.5","9.7","10.2","15.12","15.16","15.45","16.2","16.3","16.4","16.5","17.3","17.4","18.2","18.3","18.4","18.5","19.3","19.7","20.4","22.1","22.19","22.29","22.30","22.47","23.4","24.11","24.12","24.13","24.14","25.4","26.2","26.4","26.29","26.30","26.43"],"url":["0.2","0.4","5.45","6.2","6.3","6.4","6.5","7.3","7.4","8.2","8.3","8.5","9.3","9.7","9.8","10.2","15.16","15.45","16.2","16.3","16.4","16.5","17.3","17.4","18.2","18.3","18.5","19.3","19.7","19.8","22.29","22.30","22.33","22.40","22.47","24.12","24.13","24.14","26.29","26.30","26.33","26.41","26.43"],"classname":["0.3","0.11","0.12","1.11","3.15","3.21","3.24","3.25","3.28","3.31","5.4","5.15","5.26","5.30","5.38","5.39","5.40","5.41","5.42","9.2","9.5","10.4","10.6","10.7","10.14","10.17","11.6","12.1","12.2","12.11","12.12","12.13","12.14","12.16","12.19","12.21","12.23","12.25","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.41","13.2","13.3","13.4","13.5","13.6","13.7","13.8","13.9","13.10","13.11","13.17","13.18","13.22","13.28","13.29","13.30","13.32","15.6","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.24","15.25","15.27","15.30","15.31","15.32","15.33","15.34","15.35","15.36","15.41","15.43","15.47","19.5","22.4","22.9","22.13","22.17","22.25","22.34","22.42","22.50","26.6","26.8","26.12","26.14","26.15","26.16","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.27","26.28","26.33","26.34","26.38","26.40","26.42","26.44","26.48","26.49","26.51"],"run":["0.3","0.8","0.9","0.11","0.12","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.11","1.12","3.1","3.2","3.4","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.23","3.24","3.25","3.26","3.27","3.28","3.31","3.33","5.4","5.6","5.7","5.9","5.11","5.13","5.15","5.24","5.30","5.38","5.39","5.40","5.41","5.42","5.43","9.2","9.5","10.4","10.6","10.7","10.14","10.17","11.6","12.1","12.2","12.3","12.4","12.5","12.9","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.21","12.23","12.24","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.3","13.5","13.8","13.9","13.10","13.17","13.28","13.29","13.30","15.7","15.8","15.9","15.10","15.14","15.21","15.22","15.23","15.25","15.27","15.31","15.32","15.33","15.34","15.35","15.36","15.41","15.43","15.46","15.47","22.4","22.9","22.13","22.17","22.34","22.39","22.50","26.3","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.28","26.33","26.34","26.40","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"code":["0.3","0.8","0.9","0.10","0.11","0.12","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.12","2.41","3.1","3.2","3.4","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.31","3.32","3.33","5.4","5.6","5.7","5.8","5.9","5.10","5.11","5.13","5.15","5.18","5.19","5.24","5.30","5.38","5.39","5.40","5.41","5.42","5.43","5.47","9.1","9.2","9.5","10.4","10.6","10.7","10.14","10.17","11.6","12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.29","13.30","15.1","15.3","15.8","15.9","15.10","15.14","15.20","15.21","15.22","15.25","15.27","15.28","15.31","15.32","15.33","15.34","15.35","15.36","15.41","15.43","15.46","15.47","21.0","21.2","22.4","22.13","22.17","22.39","22.50","24.8","26.3","26.5","26.7","26.8","26.9","26.12","26.13","26.17","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.28","26.33","26.34","26.40","26.42","26.44","26.45","26.46","26.48","26.49"],"document":["0.3","22.1"],"assets":["0.4","5.45","6.2","6.3","6.4","6.5","7.3","7.4","7.5","9.3","9.7","9.8","10.2","15.45","16.2","16.3","16.4","16.5","17.3","17.4","17.5","19.3","19.7","19.8","22.30","22.47","24.12","24.13","24.14","26.2","26.30","26.43"],"sample":["0.4","5.45","6.2","6.3","6.4","6.5","7.3","7.4","7.5","9.3","9.8","10.2","16.2","16.3","16.4","16.5","17.3","17.4","17.5","19.3","19.8","22.2","22.30","24.13","24.14","26.2","26.30","26.43"],"video":["0.4","3.34","5.45","6.2","6.3","6.4","6.5","7.3","7.5","8.2","8.3","8.5","9.3","9.8","10.2","12.11","13.1","15.6","15.18","15.19","16.2","16.3","16.4","16.5","17.3","17.5","18.2","18.3","18.5","19.3","19.8","22.38","22.45","22.46","24.13","24.14","26.2","26.51"],"mp4":["0.4","6.3","6.4","6.5","7.3","7.5","8.2","8.3","8.5","9.3","9.4","9.8","9.9","10.2","12.0","16.3","16.4","16.5","17.3","17.5","18.2","18.3","18.5","19.3","19.4","19.8","19.9","22.2","24.14","26.2"],"test":["0.4"],"foo":["0.4"],"bar":["0.4","13.16","22.6","22.8","22.22"],"const":["0.4","9.6","19.6","23.9"],"获取整体的字幕列表":["0.11"],"div":["0.11","0.12","3.31","5.4","5.26","5.38","5.40","5.42","9.2","9.5","10.4","10.6","10.7","10.14","10.17","11.5","11.6","11.9","11.10","12.1","12.11","12.19","12.21","12.23","12.25","12.32","12.33","12.35","12.36","12.37","12.38","13.2","13.3","13.4","13.5","13.6","13.7","13.8","13.9","13.10","13.11","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.26","13.28","13.29","13.30","13.32","15.6","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.24","15.25","15.27","15.30","15.31","15.32","15.34","15.35","15.36","15.41","15.43","19.5","20.3","22.4","22.9","22.13","22.17","22.25","22.28","22.34","22.42","22.50","26.6","26.12","26.14","26.15","26.16","26.18","26.20","26.23","26.24","26.25","26.27","26.28","26.33","26.34","26.38","26.40","26.41","26.42","26.44","26.48","26.49","26.51"],"详见事件文档":["0.12"],"console":["1.1","2.0","12.0","24.18"],"info":["2.0","12.0","24.18"],"只监听一次事件":["2.0"],"但估计没有足够的数据来支撑播放到结束":["2.42"],"渲染完成":["2.44"],"属性的值改变时触发":["2.45"],"当这个":["2.46"],"因为":["2.47"],"或者资源类型不是受支持的媒体格式":["2.48"],"中的首帧已经完成加载":["2.49"],"播放准备开始":["2.53"],"seek":["2.56","2.57","12.56","12.57","13.25","15.15"],"user":["2.58","23.13"],"属性指定的时间发生变化":["2.60"],"播放已停止":["2.62"],"也是指挂载在":["3.0"],"构造函数":["3.0"],"减少视频资源占用":["3.34"],"如果你希望保留":["3.34"],"元素的状态":["3.34"],"仅移除界面":["3.34"],"可将其设置为":["3.34"],"when":["5.5","11.1","12.45","22.26"],"destroy":["5.5"],"也会在调用":["5.5"],"时自动执行类似逻辑":["5.5"],"画中画":["5.26"],"fullscreen":["5.26","15.21","22.24"],"窗口全屏":["5.26"],"fullscreenweb":["5.26"],"网页全屏":["5.26"],"对应":["5.29"],"domrect":["5.29"],"的同名字段":["5.29"],"组件唯一名称":["6.1","8.1"],"用于标记类名":["6.1","8.1"],"index":["6.1","7.5","8.1","16.1","17.5","18.1","24.7","24.10","24.15","24.16","24.17"],"number":["6.1","7.1","8.1","10.12","16.1","18.1","19.2"],"contextmenu":["6.4","6.5","16.4","16.5"],"name":["6.5","7.5","9.9","16.5","17.5","19.9","22.33"],"组件索引":["7.1"],"用于显示的优先级":["7.1"],"html":["7.1","7.2","9.4","9.9","15.4","17.1","17.2","19.4","19.9","22.27","22.33"],"element":["7.1","17.1","22.45"],"position":["7.2","7.5","17.2","17.5"],"left":["7.2","17.2"],"tooltip":["7.2","9.2","9.9","17.2","19.2","19.5","19.6","19.9"],"style":["7.2","9.3","17.1","17.2","22.37","26.37"],"color":["7.2","15.36","17.2"],"red":["7.2","17.2"],"click":["7.2","17.2"],"function":["7.2","11.10","17.2","19.5","22.35","22.41","23.10","26.35"],"args":["7.2","17.2"],"controls":["7.3","7.5","17.3","17.5"],"add":["7.3","17.3"],"button1":["7.5","17.5"],"png":["8.4","18.4","22.29","26.29"],"列表宽度":["9.2"],"提示文本":["9.2","9.5"],"setting":["9.3","9.4","9.8","9.9","19.3","19.4","19.8","19.9"],"true":["9.3","9.4","9.8","9.9","13.18","13.19","13.32","19.3","19.4","19.8","19.9","24.6"],"settings":["9.3","9.4","9.9","19.3","19.4","19.9","22.14","22.15","22.16","22.18","22.22","22.25"],"subtitle":["9.3","19.3"],"01":["9.3","9.4"],"default":["9.3","13.1","13.4","13.10","13.11","13.12","13.13","13.14","13.15","13.16","13.17","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31"],"span":["9.3"],"multi":["9.4","19.4"],"level":["9.4","13.0","19.4"],"selector":["9.4","19.4"],"value":["9.6"],"min":["9.6"],"flip":["9.8","19.1","19.8"],"slider":["9.9","19.9"],"5x":["9.9","19.9"],"icon":["9.9","19.9"],"refer":["10.0","11.0","15.0"],"to":["10.0","11.0","11.1","12.53","13.25","15.0","15.4","15.15","15.39","20.11"],"proxy":["10.3"],"method":["10.3"],"used":["10.3","13.33","15.38","15.40","22.3","22.6"],"hover":["10.3"],"delete":["10.4"],"clear":["10.4"],"all":["10.4","20.12"],"caches":["10.4"],"object":["10.6","26.11"],"update":["10.8","10.9"],"show":["10.8","10.9","10.10","10.16"],"property":["10.8","10.9","10.10","10.16"],"switch":["10.11"],"version":["10.12"],"resolution":["10.12"],"duration":["10.12"],"etc":["10.12"],"control":["10.12"],"visibility":["10.12"],"toggle":["10.13","10.15","22.20"],"set":["10.16"],"the":["11.0","12.45","12.48","15.0","15.6","15.29","22.8","22.12","22.25","22.26","22.27","22.44","22.45"],"you":["11.1"],"need":["11.1"],"manage":["11.1"],"multiple":["11.1"],"player":["11.2","11.3","11.4","11.7","11.11","11.12","15.41","15.42","20.13","22.5","22.21","22.26","22.27"],"for":["11.5","11.9","13.33","16.1","18.1","22.6","22.18","22.38","22.41","22.51"],"videos":["11.5"],"options":["11.7","11.9","22.37"],"event":["11.8","12.0","12.46","15.38","15.40","19.2","19.5","22.4"],"utility":["11.10"],"by":["11.11","20.13","22.9"],"on":["12.0","13.0","13.3","14.0","22.28","22.44","22.46","22.48","24.18"],"canplay":["12.0"],"an":["12.0","20.12"],"only":["12.0","22.3","22.14","22.21","22.49"],"once":["12.0"],"time":["12.1","12.60","24.4"],"a":["12.11","13.14","22.22"],"mode":["12.25","13.31","15.24","22.48"],"media":["12.42","15.5"],"but":["12.42","15.11","15.15"],"estimates":["12.42"],"it":["12.43","15.15","22.15","22.16","22.51"],"can":["12.43","13.34","22.41"],"play":["12.43","22.4"],"offlineaudiocontext":["12.44"],"this":["12.46","13.34","22.11"],"is":["12.46","12.58","13.1","13.4","13.6","13.7","13.8","13.9","13.10","13.11","13.12","13.13","13.14","13.16","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","15.15","15.42","20.11","21.1","22.2","22.5","22.21"],"sent":["12.46"],"stopped":["12.47","12.62"],"fetching":["12.48"],"first":["12.49"],"frame":["12.49","15.18","15.19"],"has":["12.50","12.51","12.52"],"start":["12.53"],"after":["12.53","14.0"],"periodically":["12.54"],"as":["12.54"],"playback":["12.55","15.13","22.3"],"trying":["12.58"],"data":["12.59","24.8","24.16"],"indicated":["12.60"],"volume":["12.61","22.22"],"top":["13.0"],"mounted":["13.0"],"in":["13.1","13.12","13.13","13.15","13.16","13.21","13.24","13.27","13.34","15.5","15.7","15.26","20.12","22.2","22.11","22.14","22.15","22.16","22.18","22.23","22.24","22.25","22.34"],"events":["13.1"],"text":["13.2","19.2","19.5","19.6","22.34"],"pixels":["13.6","13.7"],"feature":["13.11","22.46"],"seconds":["13.12","13.27","15.6","15.7","22.34"],"milliseconds":["13.13","13.15","13.16","13.21","13.24"],"connection":["13.14"],"error":["13.14","13.15"],"occurs":["13.14","13.15"],"pause":["13.19","13.20"],"false":["13.20"],"swipe":["13.25"],"vertical":["13.30","15.30"],"during":["13.31"],"primarily":["13.33"],"smooth":["13.33"],"progress":["13.33","15.13","15.39","22.6","22.8"],"enabling":["13.34"],"reduce":["13.34"],"resource":["13.34"],"usage":["13.34"],"single":["13.34","15.5"],"page":["13.34","15.5","15.21"],"applications":["13.34","15.5"],"or":["13.34","15.5","22.51"],"scenarios":["13.34"],"where":["13.34"],"ready":["14.0"],"also":["14.0","15.4","20.12"],"remove":["15.4"],"s":["15.4","15.24","20.13","22.27"],"resources":["15.5"],"reinitialize":["15.5"],"tag":["15.5"],"performs":["15.11"],"some":["15.11","22.49"],"optimization":["15.11"],"operations":["15.11"],"retains":["15.13"],"previous":["15.13"],"similar":["15.15","22.4"],"optional":["15.17"],"parameter":["15.17","20.10"],"specifies":["15.17"],"filename":["15.17"],"returns":["15.18","15.19"],"promise":["15.18","15.19","24.6"],"state":["15.21"],"before":["15.23","22.27"],"starts":["15.23"],"playing":["15.23"],"normal":["15.26","15.30"],"mini":["15.26"],"window":["15.26"],"pip":["15.26"],"picture":["15.26"],"automatically":["15.27","22.11"],"correspond":["15.29"],"fields":["15.29"],"of":["15.29","22.12","22.36"],"same":["15.29"],"supported":["15.30","22.42"],"values":["15.30"],"horizontal":["15.30"],"speed":["15.31"],"ratio":["15.32"],"with":["15.38","15.40"],"timeupdate":["15.38","15.40"],"loaded":["15.39"],"display":["15.39","17.1"],"detailed":["15.39"],"buffering":["15.39"],"cleaned":["15.41"],"up":["15.41"],"destroyed":["15.41"],"scoped":["15.42"],"current":["15.42","20.5","23.5"],"preventing":["15.42"],"css":["16.1","18.1","26.11"],"class":["16.1","18.1","20.3"],"determines":["17.1"],"priority":["17.1"],"dom":["17.1"],"items":["19.1"],"playbackrate":["19.1"],"aspectratio":["19.1"],"width":["19.2","22.36","26.36"],"list":["19.2"],"onswitch":["19.5"],"completion":["19.6"],"onchange":["19.6"],"change":["19.6"],"install":["20.1","23.1"],"utf":["20.3","26.37"],"body":["20.3"],"if":["20.5","23.5"],"typeof":["20.5","23.5"],"ts":["20.6","22.40"],"file":["20.6","20.11"],"from":["20.8","20.9","20.13","21.2","23.8","23.11"],"import":["20.9","21.1","21.2","23.11"],"let":["20.10"],"null":["20.10"],"use":["20.11"],"which":["20.11"],"compatible":["20.11"],"down":["20.11"],"ie":["20.11","23.11"],"plugins":["20.12","24.14","24.18"],"provide":["20.12"],"ui":["20.13"],"changing":["20.13"],"therefore":["20.13"],"starting":["20.13"],"core":["21.0"],"will":["21.0","22.15","22.16","22.22"],"no":["21.0","21.1"],"longer":["21.0"],"bundle":["21.0"],"manual":["21.1"],"dist":["21.2","23.12"],"group":["21.2"],"id":["21.2"],"sometimes":["22.2","22.40"],"not":["22.2","22.5","22.40"],"known":["22.2"],"immediately":["22.2"],"such":["22.2"],"cases":["22.2"],"memory":["22.3"],"autoplayback":["22.3"],"initialized":["22.5"],"and":["22.5","22.6","22.8","22.22"],"hide":["22.8","22.44"],"resulting":["22.11"],"black":["22.11"],"bars":["22.11"],"option":["22.11"],"adjusts":["22.11"],"scrolls":["22.12"],"out":["22.12"],"currently":["22.14","22.49"],"appears":["22.14","22.26"],"appear":["22.15","22.16"],"panel":["22.18","22.22","22.25"],"button":["22.20","22.23","22.24"],"bottom":["22.20","22.23","22.24"],"simultaneously":["22.21"],"whether":["22.21"],"one":["22.21"],"context":["22.22"],"menu":["22.22"],"apply":["22.22"],"loses":["22.26"],"focus":["22.26"],"pre":["22.27"],"render":["22.27"],"required":["22.27"],"mobile":["22.28","22.44","22.45","22.48"],"devices":["22.28","22.44"],"layer":["22.29","26.29"],"boolean":["22.33"],"string":["22.33","22.34"],"myplugin":["22.35","26.35"],"column":["22.36"],"columns":["22.36"],"encoding":["22.37","26.37"],"auto":["22.38","26.38"],"better":["22.38"],"loading":["22.38"],"experience":["22.38"],"more":["22.38"],"attributes":["22.38"],"e":["22.40"],"g":["22.40"],"m3u8":["22.40"],"mkv":["22.40"],"however":["22.40"],"may":["22.40"],"have":["22.40"],"programs":["22.41"],"processing":["22.41"],"receive":["22.41"],"three":["22.41"],"en":["22.42"],"zh":["22.42","25.2"],"cn":["22.42","26.42"],"fast":["22.46"],"forward":["22.46"],"web":["22.48"],"based":["22.48"],"browsers":["22.49"],"support":["22.49"],"htmlvideoelement":["22.51"],"example":["22.51"],"demo":["23.3"],"meta":["23.3"],"charset":["23.3"],"ref":["23.4"],"时会自动导入的":["23.6"],"param":["23.10"],"getinstance":["23.10"],"可以兼容到":["23.11"],"和所有插件还会提供一个":["23.12"],"版本的":["23.12"],"mjs":["23.12"],"如":["23.12"],"globalthis":["23.13"],"custom":["23.13"],"agent":["23.13"],"全局变量":["23.13"],"plugin":["24.2","24.3","24.8","24.16"],"danmuku":["24.2","24.7","24.10","24.16"],"npm":["24.3"],"弹幕时间":["24.4"],"默认为当前播放器时间":["24.4"],"默认弹幕模式":["24.5"],"滚动":["24.5"],"顶部":["24.5"],"底部":["24.5"],"modes":["24.5"],"弹幕可见的模式":["24.5"],"fontsize":["24.5"],"danmu":["24.6","24.18"],"return":["24.6"],"resolve":["24.6"],"settimeout":["24.6"],"libs":["24.8","24.16"],"uncompiled":["24.8","24.16"],"artplayerplugindanmuku":["24.14","24.18"],"xml":["24.18"],"visible":["24.18"],"显示弹幕":["24.18"],"版本开始":["25.0"],"核心代码除了包含":["25.0"],"zhtw":["25.2"],"tw":["25.2"],"高亮元素":["26.6"],"上":["26.6"],"类似":["26.11"],"的":["26.11"],"fit":["26.11"],"里":["26.14","26.15","26.16","26.25"],"音量条等浮层会应用":["26.22"],"filter":["26.22"],"毛玻璃效果":["26.22"],"看起来更通透":["26.22"],"访问到播放器所需的":["26.27"],"画质地址":["26.33"],"预览图列数":["26.36"],"预览图宽度":["26.36"],"height":["26.36"],"预览图高度":["26.36"],"scale":["26.36"],"字幕样式":["26.37"],"字幕编码":["26.37"],"默认":["26.37"],"以提升加载体验":["26.38"],"更多视频属性":["26.38"],"这些属性将直接写入视频元素里":["26.38"],"所以需要特别指明":["26.40"],"元素":["26.41"],"视频地址":["26.41"],"当前实例":["26.41"],"dom元素":["26.51"]},{"0":["19.6","24.4"],"1":["3.29","9.3","13.29","19.3"],"2":["3.29","9.6","19.6","20.13","26.3"],"3":["9.6"],"4":["9.1","20.13","21.1","22.17","22.34","22.50","23.10","26.5","26.7","26.8","26.9","26.13","26.17","26.21","26.25","26.26","26.33","26.34","26.40","26.42","26.45","26.46"],"5":["13.14","13.25","20.13"],"6":["2.41","5.42","5.43","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","23.10"],"7":["5.4","5.6","5.7","5.10","5.17","5.18","5.19","5.24","5.38","5.39","5.40","12.19","12.21","12.23","12.25","12.26","15.10","22.39"],"8":["5.9","5.15","5.25","5.27","5.30","5.41","12.17","15.1","15.9","15.14","15.21","15.25","15.30","15.31","15.32","15.34","15.35","15.36","15.41","22.37","23.3","26.37"],"9":["5.11","5.13","15.11","15.13","15.23","22.4"],"10":["5.8","5.41","7.3","7.4","12.2","12.6","12.18","12.24","15.8","15.12","15.41","17.3","17.4","19.6"],"11":["15.3","15.21","20.11"],"14":["26.33"],"22":["9.9","19.9"],"25":["22.34","26.34"],"40":["3.7"],"100":["3.10"],"150":["9.4","19.4"],"300":["3.5","3.6"],"500":["3.8","3.9","3.17"],"1000":["13.15"],"3000":["13.16"],"实例":["0.0","5.0"],"artplayer":["0.1","0.3","0.5","0.6","0.8","0.9","0.10","0.13","0.15","1.1","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","3.1","3.3","3.4","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.15","3.16","3.17","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.31","3.32","3.33","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.20","5.21","5.22","5.25","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.41","5.44","5.46","5.47","9.1","9.2","9.5","10.3","10.4","10.5","10.6","10.7","10.14","10.17","12.2","12.6","12.17","12.18","12.20","12.22","12.24","12.28","12.29","12.30","12.31","13.5","13.6","13.7","13.8","13.9","13.28","13.29","13.30","15.2","15.3","15.5","15.20","15.22","15.28","15.33","15.34","15.37","15.41","15.44","15.46","15.47","19.5","20.2","22.4","22.7","22.17","22.31","22.39","23.2","23.13","25.1","26.10","26.19","26.31","26.34","26.39","26.40","26.47","26.50"],"container":["0.1","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.15","0.16","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","5.2","5.3","5.9","5.11","5.13","5.14","5.16","5.20","5.21","5.22","5.23","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.41","5.44","5.46","5.47","9.2","9.5","10.1","10.3","10.4","10.5","10.6","10.7","10.14","10.17","12.2","12.20","12.22","12.28","12.29","12.30","12.31","15.2","15.20","15.22","15.28","15.41","15.44","15.46","19.5","20.9","21.3","22.4","22.7","22.17","22.31","22.39","24.9","24.10","24.15","24.17","25.1","25.2","26.10","26.19","26.31","26.34","26.39","26.47"],"app":["0.1","0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.16","0.17","2.2","2.6","2.17","2.18","2.20","2.22","2.24","2.28","2.29","2.30","2.31","5.12","5.16","5.20","5.22","5.23","5.28","5.33","5.34","5.44","9.5","10.1","10.4","10.5","10.6","10.14","12.31","15.20","15.22","15.28","15.33","15.41","15.44","19.5","20.3","20.5","21.3","21.4","22.4","22.7","22.10","22.31","22.32","22.39","22.43","23.9","24.6","24.10","25.2","25.3","26.1","26.19","26.31","26.32","26.39","26.47"],"assets":["0.2","0.6","0.7","0.10","0.14","0.16","0.17","2.2","2.22","2.28","2.31","5.12","5.23","5.44","9.5","10.1","10.4","10.6","10.14","15.12","15.16","15.20","15.22","15.33","21.4","22.1","22.4","22.7","22.10","22.19","22.31","22.32","22.43","23.9","24.6","24.10","24.11","25.2","25.3","25.4","26.1","26.4","26.31","26.32"],"sample":["0.2","0.6","0.14","0.16","0.17","2.2","2.28","5.12","5.23","9.5","9.7","10.1","10.4","10.6","10.14","15.12","15.16","15.20","15.22","15.33","15.45","19.7","21.4","22.1","22.4","22.7","22.10","22.19","22.31","22.32","22.43","22.47","23.9","24.6","24.11","24.12","25.2","25.4","26.4","26.32"],"video":["0.2","0.14","0.16","0.17","5.12","7.4","8.4","9.5","9.7","10.4","10.6","10.14","15.20","15.22","15.45","17.4","18.4","19.7","21.4","22.1","22.10","22.19","22.29","22.30","22.32","22.43","22.47","22.48","22.51","24.6","24.11","24.12","25.2","25.4","26.4","26.29","26.30","26.32","26.43"],"mp4":["0.2","0.14","0.17","5.12","5.45","6.2","7.4","8.4","9.5","9.7","10.4","10.14","15.12","15.16","15.20","15.33","15.45","16.2","17.4","18.4","19.7","22.1","22.4","22.10","22.19","22.29","22.30","22.32","22.43","22.47","24.6","24.11","24.12","24.13","25.2","25.4","26.4","26.29","26.30","26.43"],"console":["0.2","0.4","1.6","7.2","10.2","11.6","15.16","17.2","22.35","26.35"],"info":["0.2","0.4","1.1","7.2","10.2","11.6","17.2","22.35","26.35"],"queryselector":["0.3","5.41","10.3","15.41","22.1","24.16","26.1"],"art":["0.3","0.8","0.9","0.11","0.13","0.15","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.19","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.40","2.41","3.5","3.6","3.7","3.30","5.1","5.2","5.3","5.6","5.7","5.8","5.9","5.10","5.14","5.15","5.17","5.18","5.19","5.21","5.24","5.25","5.27","5.30","5.31","5.32","5.34","5.35","5.36","5.37","5.39","5.46","5.47","9.1","9.2","10.4","10.6","10.7","10.12","10.14","10.17","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.16","12.17","12.18","12.20","12.21","12.22","12.23","12.24","12.26","12.27","12.28","12.29","12.30","12.39","12.40","12.41","15.1","15.2","15.3","15.8","15.9","15.10","15.14","15.23","15.28","15.31","15.32","15.34","15.35","15.36","15.37","15.46","15.47","19.2","19.5","21.2","22.4","22.17","22.35","22.39","22.50","24.7","24.9","24.10","24.15","24.17","26.5","26.7","26.10","26.17","26.33","26.34","26.40","26.50"],"new":["0.3","0.5","0.8","0.9","0.10","0.11","0.13","0.15","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.19","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.30","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.25","5.27","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.46","5.47","9.1","9.2","9.5","10.4","10.5","10.6","10.7","10.14","10.17","12.2","12.6","12.7","12.8","12.10","12.17","12.18","12.20","12.22","12.24","12.26","12.28","12.29","12.30","12.31","15.1","15.2","15.3","15.22","15.23","15.28","15.32","15.34","15.35","15.37","15.44","15.46","15.47","19.5","22.4","22.17","22.39","24.9","24.10","24.15","24.17","25.1","25.2","26.7","26.10","26.19","26.34","26.39","26.40","26.47","26.50"],"url":["0.6","0.7","0.9","0.10","0.14","0.16","0.17","2.2","2.18","2.22","2.24","2.28","2.29","2.30","2.31","5.20","5.23","5.33","5.44","8.4","9.5","10.1","10.4","10.5","10.6","10.14","15.20","15.22","15.33","15.44","18.4","21.3","21.4","22.1","22.4","22.7","22.10","22.19","22.31","22.32","22.41","22.43","23.9","24.6","24.10","24.11","25.2","25.3","25.4","26.1","26.4","26.31","26.32","26.39","26.47"],"js":["0.11","0.12","1.6","3.1","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.33","5.4","5.6","5.7","5.15","5.24","5.26","5.30","5.38","5.39","5.40","5.42","5.43","9.2","10.3","10.7","10.17","11.6","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.18","12.19","12.21","12.23","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.22","13.28","13.29","13.30","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.25","15.27","15.30","15.31","15.32","15.34","15.35","15.36","15.41","15.43","15.47","19.2","19.5","21.1","22.13","22.17","22.25","22.34","22.42","22.50","24.8","26.3","26.5","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.27","26.28","26.33","26.40","26.42","26.44","26.45","26.46","26.48","26.49"],"var":["0.11","0.12","1.1","2.41","3.5","3.6","3.7","3.17","3.30","5.1","5.6","5.7","5.8","5.9","5.10","5.11","5.13","5.15","5.17","5.18","5.19","5.21","5.24","5.25","5.27","5.30","5.38","5.39","5.40","5.41","5.43","5.47","9.1","9.2","10.3","10.4","10.6","10.7","10.17","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.23","12.24","12.25","12.26","12.27","12.28","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","15.1","15.2","15.3","15.8","15.9","15.10","15.14","15.23","15.25","15.28","15.31","15.32","15.34","15.35","15.36","15.37","15.41","15.46","15.47","19.2","19.5","21.1","21.2","22.4","22.17","22.34","22.39","22.50","24.7","24.15","24.16","24.17","26.3","26.5","26.7","26.17","26.25","26.33","26.34","26.40","26.50"],"function":["0.14","6.5","16.5","17.1","20.10","26.37"],"构造函数":["1.0"],"code":["1.11","3.34","5.5","5.26","5.29","9.6","10.3","11.1","13.1","13.2","13.3","13.4","13.6","13.7","13.8","13.9","13.10","13.11","13.12","13.13","13.14","13.15","13.16","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.28","13.31","13.32","13.33","15.6","15.7","15.11","15.13","15.17","15.18","15.19","15.23","15.24","15.30","15.38","15.39","15.40","19.1","19.2","19.5","20.11","22.3","22.5","22.9","22.25","22.28","22.33","22.34","22.40","22.42","22.45","23.11","26.6","26.11","26.14","26.15","26.16","26.22","26.27","26.36","26.38","26.41","26.51"],"once":["2.0"],"不必停下来进一步缓冲内容":["2.42"],"media":["2.46","2.47","12.43","12.48"],"已经加载完成":["2.46"],"操作完成":["2.56"],"操作开始":["2.57"],"agent":["2.58"],"的":["3.0"],"false":["3.3","3.34","20.5","23.5","24.5","24.14"],"div":["3.34","5.5","5.29","9.6","10.3","10.13","10.15","11.1","11.2","11.3","11.4","11.7","11.8","11.11","11.12","13.1","13.12","13.13","13.14","13.15","13.16","13.24","13.25","13.27","13.31","13.33","15.4","15.15","15.17","15.26","15.38","15.39","15.40","15.42","19.1","19.2","20.5","22.3","22.5","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.33","22.40","22.44","22.45","22.46","22.49","22.51","23.3","23.5","26.11","26.22","26.36"],"classname":["3.34","5.5","5.29","9.6","10.3","11.1","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","13.1","13.12","13.13","13.14","13.15","13.16","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.33","15.15","15.17","15.26","15.38","15.39","15.40","19.1","19.2","22.3","22.5","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.28","22.33","22.40","22.44","22.45","22.46","22.49","26.11","26.22","26.36","26.41"],"run":["3.34","5.5","5.26","5.29","9.6","10.3","11.1","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.12","13.1","13.2","13.4","13.6","13.7","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","15.6","15.11","15.13","15.15","15.17","15.18","15.19","15.24","15.30","15.38","15.39","15.40","19.1","19.2","19.5","22.3","22.5","22.6","22.8","22.12","22.20","22.23","22.24","22.25","22.28","22.33","22.40","22.42","22.45","22.46","22.49","26.11","26.22","26.27","26.36","26.38","26.41"],"add":["4.0","6.3","8.3","14.0","16.3","18.3","24.2"],"例如我想写一个在视频暂停后":["4.0"],"显示一个图片广告的插件":["4.0"],"on":["5.12","15.12","15.16","15.33"],"播放器当前可见宽高":["5.29"],"document":["5.41","10.3","15.41","24.16","26.1"],"default":["5.45","7.5","15.45","17.5","19.3","23.10"],"true":["5.45","7.5","9.7","13.31","15.4","15.45","17.5","19.7","22.4","22.10","22.30","22.47","24.5","26.4","26.30","26.37"],"html":["5.45","6.1","6.2","6.3","6.4","6.5","7.3","7.5","8.1","8.2","8.3","8.5","9.8","15.45","16.1","16.2","16.3","16.4","16.5","17.3","17.5","18.1","18.2","18.3","18.5","19.8","22.29","22.30","22.37","23.13","24.14","26.29","26.30","26.37"],"sd":["5.45","15.45"],"480p":["5.45","15.45"],"组件索引":["6.1","8.1"],"用于显示的优先级":["6.1","8.1"],"contextmenu":["6.2","6.3","16.2","16.3"],"name":["6.2","6.3","6.4","7.3","7.4","8.2","8.3","8.4","8.5","9.8","15.29","16.2","16.3","16.4","17.3","17.4","18.2","18.3","18.4","18.5","19.8","22.29","22.35","26.29","26.35"],"your":["6.2","6.3","6.4","6.5","7.3","16.2","16.3","16.4","16.5","17.3","22.47","26.43"],"menu":["6.2","6.3","6.4","6.5","16.2","16.3","16.4","16.5","22.14","22.15","22.16"],"click":["6.4","6.5","16.4","16.5","17.1","24.14"],"args":["6.5","16.5"],"组件的":["7.1"],"dom":["7.1","22.41","22.51"],"元素":["7.1"],"style":["7.1","8.2","8.3","8.5","18.2","18.3","18.5","19.3","20.4","22.29"],"object":["7.1","17.1"],"mounted":["7.2","17.2","22.27"],"subtitle":["7.2","7.5","17.2","17.5"],"button1":["7.3","7.4","17.3","17.4"],"index":["7.3","7.4","17.3","17.4","24.8"],"position":["7.3","17.3","24.13","24.14"],"left":["7.3","17.3"],"controls":["7.4","17.4","24.13","24.14"],"right":["7.5","17.5","24.14"],"selector":["7.5","17.5","22.30","26.30"],"01":["7.5","17.5","19.3","19.4"],"layers":["8.2","8.3","8.4","8.5","18.2","18.3","18.4","18.5"],"potser":["8.2","8.3","8.5","18.2","18.3","18.5","22.29","26.29"],"width":["8.2","8.3","8.5","9.4","9.9","18.2","18.3","18.5","19.4","19.9","22.29"],"100px":["8.2","8.3","8.5","18.2","18.3","18.5"],"src":["8.2","8.5","9.9","18.2","18.5","19.9"],"color":["9.3","19.3"],"red":["9.3","19.3"],"srt":["9.3","19.3"],"id":["9.3","19.3","22.47"],"yellow":["9.3"],"02":["9.3"],"setting":["9.5","9.7","19.7","22.30","26.30"],"max":["9.6","19.6"],"step":["9.6"],"settings":["9.8","19.8"],"slider":["9.8","19.8"],"tooltip":["9.8","19.8"],"5x":["9.8","19.8"],"icon":["9.8","19.8"],"img":["9.9","19.9"],"height":["9.9","19.9","22.36"],"state":["9.9","13.34","19.9"],"svg":["9.9","19.9"],"secondary":["10.0"],"custom":["10.3"],"test":["10.4"],"foo":["10.4"],"bar":["10.4","13.33","22.18","22.20","22.23","22.24","22.44"],"const":["10.4","20.8","20.9","23.8"],"set":["10.8","10.9","10.10","22.2"],"whether":["10.8","10.9","10.10","10.16","22.37"],"all":["10.8","10.9","10.10","10.16","13.0"],"are":["10.8","13.34"],"displayed":["10.8"],"toggle":["10.8","10.9","10.10","10.16"],"display":["10.9","10.10","10.16","16.1","18.1"],"options":["10.11"],"texttrack":["10.11"],"gets":["10.11"],"text":["10.11"],"track":["10.11"],"activecues":["10.11"],"list":["10.11"],"via":["10.12"],"show":["10.12"],"triggered":["10.12"],"event":["10.12","17.1"],"is":["10.12","12.42","13.15","20.6","22.26","22.27"],"named":["10.12"],"of":["10.13","10.15","12.49","12.62","13.34"],"first":["11.0","15.0"],"level":["11.0","15.0"],"players":["11.1","13.34"],"simultaneously":["11.1"],"there":["12.42"],"not":["12.42","15.15"],"rendering":["12.44"],"value":["12.45","19.6"],"when":["12.46","15.5"],"because":["12.47","12.62"],"the":["12.47","12.54","20.3","22.38"],"data":["12.48","23.10"],"or":["12.48"],"been":["12.50","12.51","12.53"],"begun":["12.52"],"having":["12.53"],"rate":["12.55"],"operation":["12.56","12.57"],"to":["12.58","22.11","22.21","22.37"],"fetch":["12.58"],"loading":["12.59"],"by":["12.60"],"has":["12.61"],"constructor":["13.0"],"property":["13.0","20.10"],"off":["13.1"],"effects":["13.33"],"frequently":["13.34"],"created":["13.34"],"destroyed":["13.34"],"if":["13.34"],"you":["13.34","22.1","22.2"],"wish":["13.34"],"preserve":["13.34"],"for":["14.0"],"example":["14.0"],"let":["14.0"],"after":["15.4"],"destruction":["15.4"],"defaults":["15.4"],"note":["15.5","20.3"],"global":["15.5","20.13"],"configuration":["15.5"],"remove":["15.5"],"destroy":["15.5","20.5","23.5"],"will":["15.5"],"also":["15.5"],"ready":["15.12","15.16"],"seek":["15.12"],"settimeout":["15.12"],"does":["15.15"],"trigger":["15.15"],"additional":["15.15"],"events":["15.15"],"fullscreen":["15.26"],"fullscreenweb":["15.26"],"webpage":["15.26"],"in":["15.29"],"domrect":["15.29"],"player":["15.29"],"s":["15.29"],"current":["15.29"],"errors":["15.42"],"with":["15.42"],"duplicate":["15.42"],"class":["15.42"],"names":["15.42"],"priority":["16.1","18.1"],"element":["16.1","22.41","22.51"],"handler":["17.1"],"subtitleoffset":["19.1"],"span":["19.3"],"min":["19.6"],"yarn":["20.1","23.1","24.2"],"npm":["20.2","23.2"],"dist":["20.2","20.12","23.2","24.3"],"warning":["20.3","22.47"],"option":["20.4","23.4"],"get":["20.4"],"return":["20.5","22.35","23.5","23.10","26.35"],"ref":["20.5","23.5"],"param":["20.10"],"getinstance":["20.10"],"import":["20.11"],"from":["20.11"],"group":["20.11","23.11"],"bash":["20.11","23.11"],"jsdelivr":["20.11","23.11"],"net":["20.11","23.11"],"mjs":["20.12"],"format":["20.12"],"such":["20.12"],"as":["20.12"],"version":["20.13"],"variable":["20.13"],"globalthis":["20.13"],"user":["20.13"],"any":["21.0"],"languages":["21.0"],"other":["21.0"],"than":["21.0"],"simplified":["21.0"],"chinese":["21.0"],"and":["21.0","22.14","22.15","22.16","22.26","22.48"],"english":["21.0"],"required":["21.1"],"zhtw":["21.2"],"zh":["21.2"],"tw":["21.2"],"may":["22.1"],"can":["22.2","22.27"],"asynchronously":["22.2"],"muted":["22.4","26.4"],"yet":["22.5"],"playing":["22.5","22.26"],"highlighted":["22.6"],"elements":["22.6"],"playback":["22.8"],"time":["22.8","22.21"],"size":["22.11"],"hide":["22.11"],"browser":["22.12"],"viewport":["22.12","22.48"],"panel":["22.14","22.15","22.16"],"context":["22.14","22.15","22.16"],"bottom":["22.18","22.44"],"control":["22.18","22.20","22.23","22.24","22.44"],"allowed":["22.21"],"play":["22.21","26.43"],"at":["22.21"],"a":["22.21"],"filter":["22.22"],"frosted":["22.22"],"glass":["22.22"],"more":["22.22"],"transparent":["22.22"],"look":["22.22"],"however":["22.22"],"access":["22.27"],"setting01":["22.30","26.30"],"scale":["22.36"],"utf":["22.37","23.3"],"escape":["22.37","26.37"],"boolean":["22.37","26.37"],"tags":["22.37"],"these":["22.38"],"be":["22.38"],"written":["22.38"],"directly":["22.38"],"into":["22.38"],"correct":["22.40"],"so":["22.40"],"explicitly":["22.40"],"specified":["22.40"],"parameters":["22.41"],"lang":["22.43","26.43"],"devices":["22.45","22.46"],"mobile":["22.46"],"dimensions":["22.48"],"this":["22.49"],"feature":["22.49"],"an":["22.51"],"existing":["22.51"],"body":["23.3"],"属性":["23.10"],"export":["23.10"],"https":["23.11"],"plugin":["23.12"],"danmuku":["23.12","24.3","24.8"],"head":["23.13"],"title":["23.13"],"mode":["24.4"],"弹幕模式":["24.4"],"滚动":["24.4"],"弹幕字体大小":["24.5"],"antioverlap":["24.5"],"弹幕是否防重叠":["24.5"],"synchronousplayback":["24.5"],"是否同步播放速度":["24.5"],"mount":["24.5"],"undefined":["24.5"],"弹幕发射器挂载点":["24.5"],"默认为播放器控制栏中部":["24.5"],"heatmap":["24.5"],"plugins":["24.6","24.11","24.12","24.13"],"xml":["24.6","24.13","24.14"],"这是用户在输入框输入弹幕文本":["24.6"],"然后点击发送按钮后触发的函数":["24.6"],"artplayerplugindanmuku":["24.11","24.12","24.13"],"emitter":["24.14"],"重载":["24.14"],"danmu":["24.16"],"loaded":["24.18"],"danmus":["24.18"],"加载弹幕":["24.18"],"length":["24.18"],"简体中文":["25.0"],"和":["25.0"],"英文":["25.0"],"有时候":["26.2"],"地址没那么快知道":["26.2"],"这时候你可以异步设置":["26.2"],"cover":["26.11"],"但在部分低性能设备或老旧浏览器上可能会有性能或兼容性问题":["26.22"],"预览图缩放":["26.36"],"是否转义":["26.37"],"标签":["26.37"],"默认为":["26.37"],"onvttload":["26.37"],"用于修改":["26.37"]},{"0":["15.12","23.9"],"1":["3.25","9.9","19.9","24.4"],"2":["3.26","9.3","13.29","19.3","22.3","24.4"],"3":["3.28","13.28","19.6","26.1"],"4":["3.28","13.28","19.1","20.10","22.5","22.8","22.9","22.13","22.23","22.24","22.25","22.28","22.33","22.36","22.40","22.42","22.45","22.46","22.49","26.6","26.11","26.12","26.14","26.15","26.16","26.18","26.20","26.22","26.23","26.24","26.28","26.36","26.37","26.38","26.41","26.44","26.48","26.49","26.51"],"5":["3.23","3.29","9.9","13.29","19.9","22.7"],"6":["3.29","13.29","15.43","20.10","22.2","26.2"],"7":["5.29","15.6","15.7","15.17","15.18","15.19","15.24","15.38","15.39","15.40","26.27","26.38"],"8":["5.26","15.15","15.26","15.27","22.36","23.13","26.36","26.41"],"9":["5.5"],"10":["3.12","3.14","3.27","5.12","9.9","19.9"],"12":["24.13"],"14":["22.33"],"20":["3.11"],"22":["9.5"],"40":["13.7"],"50":["24.13"],"100":["13.10"],"300":["13.5","13.6"],"500":["3.21","13.8","13.9","13.17"],"512":["24.5"],"2000":["3.22","3.24","13.22"],"3000":["3.15","15.12"],"5000":["3.4","3.13","3.16"],"的":["0.0","0.4","1.0","5.0"],"url":["0.1","0.3","0.5","0.8","0.12","0.13","0.15","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.19","2.20","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.30","5.1","5.2","5.3","5.8","5.9","5.13","5.14","5.15","5.16","5.17","5.18","5.19","5.21","5.22","5.25","5.28","5.30","5.31","5.32","5.34","5.35","5.36","5.37","5.46","5.47","9.1","9.2","9.6","10.3","10.7","10.17","12.2","12.6","12.7","12.8","12.10","12.12","12.16","12.17","12.18","12.20","12.22","12.24","12.26","12.28","12.29","12.30","12.31","15.2","15.3","15.8","15.9","15.14","15.23","15.28","15.31","15.32","15.34","15.35","15.36","15.37","15.41","15.46","15.47","19.2","19.5","20.5","20.9","21.2","22.17","22.34","22.39","22.50","24.9","24.15","24.17","25.1","26.7","26.10","26.19","26.34","26.40","26.50"],"assets":["0.1","0.3","0.5","0.8","0.9","0.11","0.13","0.15","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.23","2.24","2.25","2.26","2.27","2.29","2.30","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","3.30","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.20","5.21","5.22","5.25","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.46","5.47","9.1","9.2","9.6","10.3","10.5","10.7","10.17","12.2","12.6","12.17","12.18","12.20","12.22","12.24","12.28","12.29","12.30","12.31","15.2","15.3","15.9","15.14","15.23","15.28","15.31","15.32","15.34","15.35","15.37","15.41","15.44","15.46","15.47","19.2","19.5","20.9","21.2","21.3","22.17","22.34","22.39","22.40","24.9","24.15","24.17","25.1","26.10","26.19","26.33","26.34","26.39","26.40","26.47","26.50"],"sample":["0.1","0.3","0.5","0.7","0.8","0.9","0.10","0.11","0.13","0.15","2.6","2.11","2.12","2.16","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.29","2.30","2.31","2.39","5.2","5.3","5.9","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.20","5.21","5.22","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.44","5.46","5.47","9.2","9.6","10.3","10.5","10.7","10.17","12.2","12.18","12.20","12.22","12.24","12.28","12.29","12.30","12.31","15.2","15.23","15.28","15.34","15.41","15.44","15.46","19.2","19.5","20.9","21.2","21.3","22.17","22.34","22.39","22.40","24.9","24.10","24.15","24.17","25.3","26.1","26.10","26.19","26.31","26.33","26.34","26.39","26.40","26.47"],"video":["0.1","0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.15","2.2","2.6","2.12","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.28","2.29","2.30","2.31","5.2","5.3","5.9","5.11","5.13","5.14","5.16","5.20","5.22","5.23","5.28","5.31","5.32","5.33","5.35","5.36","5.44","5.46","9.2","9.6","10.1","10.3","10.5","10.7","10.17","12.2","12.22","12.28","12.29","12.30","12.31","15.28","15.41","15.44","15.46","19.2","19.5","20.9","21.2","21.3","22.7","22.17","22.31","22.39","23.9","24.9","24.10","24.15","24.17","25.3","26.1","26.10","26.19","26.31","26.34","26.39","26.40","26.47"],"mp4":["0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.16","2.2","2.17","2.18","2.20","2.22","2.24","2.28","2.29","2.30","2.31","5.16","5.20","5.22","5.23","5.28","5.32","5.33","5.34","5.44","5.46","9.2","10.1","10.3","10.5","10.6","10.7","10.17","12.28","12.29","12.30","12.31","15.22","15.23","15.28","15.41","15.44","19.2","19.5","20.9","21.2","21.3","21.4","22.7","22.17","22.31","22.39","23.9","24.9","24.10","24.17","25.3","26.1","26.10","26.19","26.31","26.32","26.34","26.39","26.47"],"warning":["0.4","10.2","10.4","11.6","15.12","15.16","15.33","20.4","22.7","22.10","25.0"],"提示":["0.4"],"默认所有播放器实例都是共享同一个":["0.4"],"localstorage":["0.4"],"而且默认的":["0.4"],"是":["0.4"],"settings":["0.4","9.2","9.5","19.5"],"如果你想不同的播放器使用不同的":["0.4"],"console":["0.6","0.14","0.17","6.2","6.3","6.4","6.5","9.3","9.4","10.1","10.4","10.5","10.6","10.14","11.1","16.2","16.3","16.4","16.5","19.3","19.4","22.30"],"info":["0.6","0.14","0.17","1.6","6.2","6.3","6.4","6.5","9.3","9.4","10.1","10.4","10.5","10.6","10.14","11.1","15.16","16.2","16.3","16.4","16.5","19.3","19.4","22.30"],"play":["0.6","10.6","12.42","22.43","26.4"],"on":["0.7","0.8","0.9","0.10","2.2","2.22","5.33","5.44","7.5","8.5","9.9","10.7","10.14","15.0","15.28","15.44","17.5","18.5","19.9","20.3","22.22"],"ready":["0.9","0.10","2.2","5.12","5.44","7.5","10.14","15.33","17.5"],"artplayer":["0.11","0.12","1.6","2.41","3.34","5.4","5.6","5.7","5.17","5.24","5.26","5.27","5.29","5.38","5.39","5.40","5.42","5.43","9.6","11.1","11.6","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.19","12.21","12.23","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.1","13.3","13.4","13.10","13.11","13.12","13.13","13.14","13.15","13.16","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","15.1","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.24","15.25","15.27","15.30","15.31","15.32","15.35","15.36","15.43","19.1","19.2","19.6","20.13","21.1","22.25","22.27","22.33","22.34","22.40","22.42","22.50","26.3","26.5","26.7","26.8","26.9","26.13","26.14","26.15","26.16","26.17","26.21","26.25","26.26","26.33","26.36","26.42","26.45","26.46"],"container":["0.11","0.12","1.1","2.1","2.3","2.4","2.14","2.41","3.5","3.6","3.7","3.8","3.9","3.10","3.17","3.29","3.30","5.1","5.4","5.6","5.7","5.8","5.10","5.15","5.17","5.18","5.19","5.24","5.25","5.26","5.27","5.30","5.38","5.39","5.40","5.42","5.43","9.1","9.6","12.1","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.21","12.23","12.24","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.30","15.1","15.3","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.25","15.30","15.31","15.32","15.34","15.35","15.36","15.37","15.47","19.2","19.6","21.1","21.2","22.25","22.33","22.34","22.40","22.42","22.50","24.7","24.16","26.5","26.7","26.17","26.25","26.27","26.33","26.40","26.42","26.50"],"app":["0.11","0.12","0.13","0.15","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.19","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.6","3.7","3.30","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.17","5.18","5.19","5.21","5.25","5.27","5.30","5.31","5.32","5.35","5.36","5.37","5.39","5.41","5.46","5.47","9.1","9.2","9.6","10.3","10.7","10.17","12.2","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.16","12.17","12.18","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.29","12.30","12.39","12.40","12.41","15.1","15.2","15.3","15.8","15.9","15.10","15.11","15.13","15.14","15.21","15.23","15.30","15.31","15.32","15.34","15.35","15.36","15.37","15.46","15.47","19.2","20.9","21.2","22.17","22.34","22.40","22.50","23.3","23.5","24.7","24.9","24.15","24.16","24.17","25.1","26.7","26.10","26.17","26.25","26.27","26.33","26.34","26.40","26.50"],"new":["0.12","1.1","3.3","3.6","3.7","3.8","3.9","3.10","3.11","3.17","3.22","3.28","3.29","3.33","5.4","5.5","5.6","5.7","5.24","5.26","5.29","5.38","5.39","5.40","5.41","5.42","5.43","9.6","10.3","10.16","12.1","12.3","12.4","12.5","12.9","12.11","12.12","12.13","12.14","12.15","12.16","12.19","12.21","12.23","12.25","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.8","13.9","13.30","15.6","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.15","15.17","15.18","15.19","15.21","15.24","15.25","15.27","15.30","15.31","15.36","15.38","15.39","15.40","15.41","15.43","19.1","19.2","19.6","21.1","22.13","22.25","22.33","22.34","22.40","22.42","22.50","24.7","24.8","24.16","26.3","26.5","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.28","26.33","26.36","26.38","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"hotkeyevent":["0.14","10.14"],"event":["0.14","9.3","9.4","10.14","19.4"],"click":["0.14","6.2","6.3","7.1","7.3","10.14","15.20","15.22","16.2","16.3","17.3","22.31","24.12"],"true":["0.16","2.28","3.1","3.20","3.33","7.2","9.2","9.5","17.2","19.5","22.17","22.37"],"flip":["0.16"],"playbackrate":["0.16"],"aspectratio":["0.16"],"function":["0.17","6.2","6.3","6.4","7.1","7.3","9.4","10.14","10.17","15.20","15.22","16.2","16.3","16.4","17.3","19.4","22.30","22.37","24.12","24.14","26.30"],"myplugin":["0.17","10.17"],"art":["1.1","3.1","3.3","3.4","3.8","3.9","3.10","3.11","3.12","3.13","3.17","3.18","3.21","3.22","3.23","3.24","3.27","3.28","3.29","3.32","3.33","5.4","5.5","5.26","5.29","5.38","5.40","5.41","5.42","5.43","9.6","10.3","10.16","12.1","12.11","12.14","12.19","12.25","12.32","12.33","12.34","12.35","12.36","12.37","12.38","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.29","13.30","15.6","15.7","15.15","15.17","15.18","15.19","15.21","15.24","15.25","15.26","15.27","15.30","15.38","15.39","15.40","15.41","15.43","19.1","19.6","20.8","21.1","22.9","22.13","22.25","22.28","22.33","22.34","22.40","22.41","22.42","23.8","24.8","24.16","26.3","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.28","26.36","26.38","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"js":["1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.12","3.2","3.34","5.5","5.29","10.9","10.10","10.13","10.15","10.16","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","15.4","15.6","15.15","15.17","15.24","15.26","15.38","15.39","15.40","15.42","19.1","20.2","22.3","22.5","22.6","22.8","22.9","22.12","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.28","22.33","22.36","22.40","22.44","22.45","22.46","22.49","23.2","24.3","26.6","26.11","26.22","26.36","26.37","26.38","26.41","26.51"],"手动触发事件":["2.0"],"subtitle":["2.28","2.29","2.30","2.31","12.31"],"或者部分加载完成":["2.46"],"则发送此事件":["2.46"],"已经到达结束点":["2.47"],"正在尝试获取媒体数据":["2.58"],"一级属性":["3.0"],"var":["3.1","3.3","3.4","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.29","3.31","3.32","3.33","5.4","5.5","5.26","5.29","5.42","9.6","10.13","10.15","10.16","12.1","12.11","13.3","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.22","13.28","13.29","13.30","15.6","15.7","15.11","15.13","15.15","15.17","15.18","15.19","15.21","15.24","15.26","15.27","15.30","15.38","15.39","15.40","15.43","19.1","19.6","22.3","22.5","22.9","22.13","22.25","22.28","22.33","22.40","22.42","24.8","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.27","26.28","26.36","26.38","26.41","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"false":["3.18","3.19","3.31","3.32","6.5","13.3","13.18","13.32","16.5"],"adsplugin":["4.0","14.0"],"option":["4.0","14.0","24.18"],"layers":["4.0","14.0"],"ads":["4.0"],"html":["4.0","7.4","8.4","9.7","15.20","15.22","17.4","18.4","19.7","20.13","22.31","22.32","24.11","24.12","24.13","26.31","26.32"],"img":["4.0","9.5","9.8","19.8","22.39","26.39"],"style":["4.0","6.1","7.3","8.1","8.4","16.1","17.3","18.1","18.4","23.4","26.29"],"width":["4.0","8.4","9.5","9.8","18.4","19.8","24.5","26.29"],"100px":["4.0","8.4","18.4","22.29","26.29"],"src":["4.0","8.3","8.4","9.8","18.3","18.4","19.8","22.29","26.29"],"display":["4.0","10.8"],"none":["4.0"],"position":["4.0","5.20","7.4","8.2","8.3","8.5","15.20","15.22","17.4","18.2","18.3","18.5","22.29","22.32","24.11","24.12","26.29","26.32"],"absolute":["4.0","8.2","8.3","8.5","18.2","18.3","18.5","22.29","26.29"],"top":["4.0","8.2","8.3","8.5","18.2","18.3","18.5","22.29","26.29"],"20px":["4.0","22.29","26.29"],"right":["4.0","7.2","7.4","8.2","8.5","15.20","15.22","17.2","17.4","18.2","18.5","22.29","24.11","24.12","24.13"],"seek":["5.12","22.19"],"settimeout":["5.12","7.5","17.5","22.2"],"controls":["5.20","5.22","15.20","15.22","24.11","24.12"],"jpg":["5.23"],"hd":["5.45","15.45"],"720p":["5.45","15.45"],"element":["6.1","8.1","13.34","18.1","22.38"],"组件的":["6.1","8.1"],"dom":["6.1","8.1","9.4","16.1","18.1","19.4"],"元素":["6.1","8.1"],"args":["6.2","6.3","6.4","16.2","16.3","16.4","22.30","26.30"],"show":["6.5","9.7","9.9","16.5","19.7","19.9"],"组件样式对象":["7.1"],"组件点击事件":["7.1"],"mounted":["7.1","15.0","17.1"],"selector":["7.2","17.2"],"default":["7.2","10.4","17.2","20.10","21.4","25.4"],"span":["7.2","17.2"],"01":["7.2","17.2","22.30","26.30"],"button":["7.3","7.4","17.3","17.4"],"tooltip":["7.3","7.4","8.2","8.3","17.1","17.3","17.4","18.2","18.3","22.32"],"color":["7.3","17.3"],"red":["7.3","17.3"],"your":["7.4","17.4","22.31","22.32","26.31","26.32","26.47"],"02":["7.5","9.4","17.5","19.3","19.4","22.30","26.30"],"update":["7.5","17.5"],"the":["7.5","17.5","21.4","22.10","25.4"],"tip":["8.2","8.3","18.2","18.3"],"50px":["8.2","8.3","8.5","18.2","18.3","18.5"],"potser":["8.4","18.4"],"setting":["9.2","19.5"],"item":["9.3","9.4","19.3","19.4"],"onselect":["9.4","19.4","22.30","26.30"],"pip":["9.5","19.5"],"mode":["9.5","19.5"],"close":["9.5","19.5"],"height":["9.5","9.8","19.8"],"add":["9.7","20.1","23.1"],"slider":["9.7","19.7"],"state":["9.8","19.8"],"range":["9.9","19.9","24.13"],"attached":["10.0","11.0"],"note":["10.2","10.4","15.12","15.16","15.33","22.7","22.10","22.47"],"to":["10.2","12.42","12.43","14.0","22.1"],"easily":["10.2"],"distinguish":["10.2"],"between":["10.2"],"and":["10.2","15.29"],"by":["10.4"],"zh":["10.6"],"cn":["10.6"],"of":["10.8","10.9","10.10","10.16","12.45","16.1","22.1"],"div":["10.8","10.9","10.10","10.11","10.12","10.16","15.5","15.29","19.6","22.11","22.21","22.27","22.36","22.37","22.38","22.41","22.48","26.37"],"classname":["10.8","10.9","10.10","10.12","10.13","10.15","10.16","15.4","15.5","15.29","15.42","19.6","22.21","22.27","22.36","22.37","22.38","22.41","22.48","22.51","26.37"],"run":["10.8","10.9","10.10","10.12","10.13","10.15","10.16","11.11","15.4","15.5","15.26","15.29","15.42","19.6","22.14","22.15","22.16","22.18","22.21","22.26","22.27","22.36","22.37","22.38","22.41","22.44","22.48","22.51","26.37"],"code":["10.8","10.9","10.10","10.12","10.13","10.15","10.16","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","15.4","15.15","15.26","15.29","15.42","19.6","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.23","22.24","22.26","22.27","22.36","22.37","22.38","22.44","22.46","22.48","22.49","22.51","26.37"],"currently":["10.11"],"active":["10.11"],"cues":["10.11"],"overall":["10.11"],"see":["10.12"],"documentation":["10.12"],"for":["10.12","22.1","22.37"],"details":["10.12"],"all":["11.6"],"manually":["12.0","21.0"],"triggering":["12.0"],"enough":["12.42"],"data":["12.42","12.58","20.10"],"through":["12.43"],"is":["12.44","14.0","15.5","17.1"],"already":["12.46"],"been":["12.46","20.13"],"loaded":["12.46","12.50"],"or":["12.46","12.53","22.22"],"media":["12.47","12.49","12.58"],"resource":["12.48"],"type":["12.48","24.13"],"paused":["12.51","12.53","14.0"],"browser":["12.54"],"has":["12.55","12.56","12.57","12.59","20.13"],"but":["12.58"],"currenttime":["12.60"],"changed":["12.61"],"a":["12.62"],"temporary":["12.62"],"names":["13.0"],"are":["13.0"],"in":["13.0"],"uppercase":["13.0"],"only":["13.34"],"ui":["13.34"],"set":["13.34","22.1"],"say":["14.0"],"i":["14.0","24.6"],"want":["14.0","22.10"],"write":["14.0"],"that":["14.0"],"displays":["14.0"],"an":["14.0","22.43"],"image":["14.0"],"ad":["14.0"],"when":["14.0"],"automatically":["15.5","20.6"],"execute":["15.5"],"similar":["15.5","22.11"],"logic":["15.5"],"called":["15.5"],"t":["15.12"],"some":["15.16","22.22"],"videos":["15.16"],"may":["15.16","22.22"],"not":["15.16"],"switch":["15.20"],"visible":["15.29"],"resize":["15.33"],"object":["16.1","18.1","22.11"],"triggered":["17.1"],"after":["17.1"],"yellow":["19.3"],"step":["19.6","24.13"],"unpkg":["20.2","20.11","23.2","24.3"],"player":["20.3","22.47"],"s":["20.3"],"dimensions":["20.3"],"depend":["20.3"],"instance":["20.4","22.41"],"getinstance":["20.4"],"path":["20.5"],"imported":["20.6"],"useref":["20.8","23.8"],"export":["20.10"],"return":["20.10"],"https":["20.11"],"cdn":["20.11","23.11"],"npm":["20.11","23.11"],"dist":["20.11","23.11"],"plugin":["20.12"],"danmuku":["20.12"],"doctype":["20.12","23.12"],"agent":["20.13"],"added":["20.13"],"head":["20.13"],"title":["20.13"],"demo":["20.13","23.13"],"you":["21.0","22.10"],"need":["21.0","22.1"],"import":["21.0"],"change":["21.4","25.4"],"size":["22.1"],"example":["22.1"],"equivalent":["22.4"],"muted":["22.10"],"if":["22.10","24.6"],"css":["22.11","26.1"],"fit":["22.11"],"cover":["22.11"],"description":["22.19"],"increase":["22.19"],"volume":["22.19","23.9"],"decrease":["22.19"],"forward":["22.19"],"backward":["22.19"],"this":["22.22","26.4"],"cause":["22.22"],"performance":["22.22"],"compatibility":["22.22"],"issues":["22.22"],"low":["22.22"],"via":["22.27"],"menu":["22.31","26.31"],"left":["22.32","26.32"],"something":["22.35","26.35"],"dosomething":["22.35","26.35"],"onvttload":["22.37"],"modifying":["22.37"],"text":["22.37","24.6","24.12"],"loading":["22.39","26.39"],"current":["22.41"],"modify":["22.43"],"existing":["22.43"],"because":["22.47"],"uses":["22.47"],"as":["22.47"],"key":["22.47"],"class":["23.3"],"get":["23.4"],"d":["23.6"],"选项":["23.10"],"lang":["23.12","25.2","25.3"],"meta":["23.13"],"charset":["23.13"],"utf":["23.13"],"com":["24.3"],"默认":["24.4"],"顶部":["24.4"],"底部":["24.4"],"是否开启热力图":["24.5"],"当播放器宽度小于此值时":["24.5"],"弹幕发射器置于播放器底部":["24.5"],"points":["24.5"],"热力图数据":["24.5"],"filter":["24.5"],"弹幕载入前的过滤器":["24.5"],"只支持返回布尔值":["24.5"],"beforeemit":["24.5"],"弹幕发送前的过滤器":["24.5"],"支持返回":["24.5"],"你可以对弹幕做合法校验":["24.6"],"或者做存库处理":["24.6"],"当返回true后才表示把弹幕加入到弹幕队列":["24.6"],"async":["24.6"],"const":["24.6"],"isdirty":["24.6"],"fuck":["24.6"],"test":["24.6"],"plugins":["24.10"],"artplayerplugindanmuku":["24.10"],"xml":["24.11","24.12"],"隐藏弹幕":["24.11"],"发送弹幕":["24.12"],"弹幕大小":["24.13"],"input":["24.13"],"min":["24.13"],"max":["24.13"],"重新加载当前弹幕库":["24.14"],"切换":["24.14"],"error":["24.18"],"加载错误":["24.18"],"config":["24.18"],"配置变化":["24.18"],"外":["25.0"],"不再捆绑其它多国语言":["25.0"],"需要自行导入需要的语言":["25.0"],"language":["25.4"],"您可能需要初始化容器元素的大小":["26.1"],"如":["26.1"],"等同于":["26.4"],"document":["26.27"],"queryselector":["26.27"],"control":["26.32"],"文本的函数":["26.37"],"修改现有的语言":["26.43"],"id":["26.47"]},{"0":["5.12","20.5","20.9"],"1":["9.8","13.25","19.8","24.13"],"2":["13.26"],"3":["22.1"],"4":["22.6","22.11","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.26","22.37","22.38","22.41","22.44","22.48","22.51"],"5":["9.8","13.23","19.8","20.9","23.9"],"6":["15.42"],"7":["15.4","15.29","22.27","22.38"],"8":["20.13","22.41","23.12"],"9":["15.5","22.29","26.29"],"10":["9.8","13.12","13.14","13.27","19.8"],"11":["22.43","26.43"],"12":["22.37","26.37"],"20":["13.11"],"22":["9.2","9.6","9.7","19.2","19.5","19.7"],"25":["24.13"],"32":["0.14","10.14"],"60":["22.34","26.34"],"120":["26.34"],"150":["9.3","19.3"],"200":["24.5"],"404":["2.11","12.11"],"500":["13.21"],"1000":["22.2"],"2000":["13.24"],"3000":["5.12","13.15"],"5000":["13.4","13.13","13.16"],"二级属性":["0.0"],"mp4":["0.1","0.11","0.12","0.13","0.15","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.19","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.6","3.7","3.29","3.30","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.17","5.18","5.19","5.21","5.25","5.26","5.30","5.31","5.35","5.36","5.37","5.39","5.41","5.47","9.1","9.6","10.8","10.9","10.10","10.16","12.2","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.16","12.17","12.18","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.39","12.41","13.30","15.1","15.2","15.3","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.25","15.30","15.31","15.32","15.34","15.35","15.36","15.37","15.46","15.47","19.6","20.5","22.33","22.34","22.50","23.5","24.15","24.16","25.1","26.7","26.25","26.33","26.36","26.50"],"console":["0.1","0.3","0.5","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.11","1.12","3.2","5.9","5.14","5.15","5.16","5.23","5.28","5.30","5.31","5.32","5.34","5.35","5.36","5.44","7.3","8.2","8.3","10.3","10.17","13.2","15.28","15.32","15.34","15.41","15.44","17.3","18.2","18.3","22.29","22.31","22.32","26.29","26.30","26.31"],"info":["0.1","0.3","0.5","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.12","5.9","5.14","5.16","5.23","5.28","5.31","5.32","5.34","5.35","5.36","7.3","8.2","8.3","10.3","10.17","15.28","15.34","15.41","17.3","18.2","18.3","22.29","22.31","22.32","26.29","26.30","26.31"],"warning":["0.2","1.6","5.12","10.1","10.5","10.6","15.20","15.22","15.41","21.0","22.2","22.4","22.17","22.19","22.40","23.3","23.4","26.10","26.40","26.47"],"提示":["0.2","5.12","23.3","26.47"],"为了方便区别":["0.2"],"元素和普通对象":["0.2"],"播放器里的所有":["0.2"],"click":["0.3","5.20","5.22","6.1","8.1","8.2","8.3","10.3","15.41","16.1","18.1","18.2","18.3","22.29","22.32","24.10","24.11","26.29","26.31","26.32"],"event":["0.3","10.3","16.1","24.11"],"你可以修改":["0.4"],"即可":["0.4"],"zh":["0.6"],"cn":["0.6","21.4","25.4"],"your":["0.6","10.6","15.33","20.3","21.3","21.4","22.3","25.3","25.4","26.3"],"ready":["0.7","0.8","0.11","0.13","0.14","0.15","0.16","2.6","2.18","2.22","2.24","5.9","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.23","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.45","5.46","6.5","8.5","9.9","10.7","12.18","12.22","12.24","15.9","15.11","15.13","15.14","15.23","15.28","15.31","15.32","15.34","15.35","15.36","15.44","15.45","15.46","16.5","18.5","19.9"],"html":["0.8","0.9","0.10","5.20","5.22","14.0","24.10"],"some":["0.8","0.9","0.10"],"text":["0.8","0.9","0.10","17.1"],"position":["0.9","5.22","5.37","7.1","8.4","14.0","17.1","18.4","24.10"],"video":["0.11","0.12","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.16","2.19","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.6","3.7","3.28","3.29","3.30","5.1","5.6","5.7","5.8","5.10","5.15","5.17","5.18","5.19","5.21","5.24","5.25","5.26","5.27","5.29","5.30","5.37","5.39","5.41","5.47","9.1","10.8","10.9","10.10","10.16","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.23","12.24","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","15.21","15.30","15.31","15.32","15.36","15.37","15.47","19.6","20.5","22.25","22.33","22.34","22.42","22.50","23.5","24.7","24.16","25.1","26.7","26.17","26.25","26.33","26.36","26.50"],"on":["0.11","0.12","0.13","0.14","0.15","0.16","2.6","2.11","2.12","2.18","2.24","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.21","5.23","5.28","5.30","5.31","5.32","5.34","5.35","5.36","5.45","5.46","6.4","6.5","7.4","10.9","10.10","12.2","12.6","12.18","12.22","12.24","15.9","15.11","15.13","15.14","15.23","15.30","15.31","15.32","15.34","15.35","15.36","15.45","15.46","16.4","16.5","17.4","22.4"],"assets":["0.12","1.1","2.1","2.3","2.4","2.14","2.41","3.5","3.6","3.7","3.8","3.9","3.10","3.17","3.28","3.29","5.1","5.4","5.5","5.6","5.7","5.17","5.24","5.26","5.27","5.29","5.38","5.39","5.40","5.41","5.42","5.43","10.8","10.9","10.10","10.13","10.15","10.16","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.19","12.21","12.23","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.28","13.29","13.30","15.1","15.6","15.7","15.8","15.10","15.11","15.13","15.15","15.17","15.18","15.19","15.21","15.24","15.25","15.26","15.27","15.30","15.36","15.38","15.39","15.40","19.1","19.6","21.1","22.25","22.33","22.36","22.42","22.50","24.7","24.8","24.16","26.5","26.7","26.17","26.25","26.36","26.37","26.42"],"sample":["0.12","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.19","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.40","2.41","3.5","3.6","3.7","3.8","3.9","3.10","3.17","3.28","3.29","3.30","5.1","5.6","5.7","5.8","5.10","5.17","5.24","5.25","5.26","5.27","5.29","5.37","5.38","5.39","5.40","5.41","5.42","9.1","10.8","10.9","10.10","10.13","10.15","10.16","12.1","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.19","12.21","12.23","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.29","13.30","15.1","15.3","15.8","15.9","15.10","15.11","15.13","15.14","15.15","15.18","15.19","15.21","15.25","15.26","15.30","15.31","15.32","15.35","15.36","15.37","15.47","19.1","19.6","21.1","22.25","22.33","22.36","22.42","22.50","24.7","24.16","25.1","26.5","26.7","26.17","26.25","26.36","26.37","26.42","26.50"],"subtitleoffset":["0.16"],"return":["0.17","9.3","9.4","10.17","19.3","19.4","24.9","24.12"],"name":["0.17","10.17"],"something":["0.17"],"dosomething":["0.17"],"一级属性":["1.0","5.0"],"app":["1.1","3.3","3.8","3.9","3.10","3.11","3.12","3.13","3.17","3.22","3.23","3.28","3.29","3.33","5.4","5.5","5.6","5.7","5.24","5.26","5.29","5.38","5.40","5.42","5.43","10.8","10.9","10.10","10.13","10.15","10.16","12.1","12.3","12.4","12.11","12.14","12.19","12.32","12.33","12.34","12.35","12.36","12.37","12.38","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.28","13.29","13.30","15.6","15.7","15.15","15.17","15.18","15.19","15.24","15.25","15.26","15.27","15.29","15.38","15.39","15.40","15.43","19.1","19.6","20.13","21.1","22.5","22.9","22.13","22.25","22.27","22.33","22.36","22.37","22.42","24.8","26.5","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.23","26.24","26.26","26.28","26.36","26.37","26.38","26.41","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"url":["1.1","3.6","3.7","3.8","3.9","3.10","3.17","3.22","3.28","3.29","5.4","5.5","5.6","5.7","5.24","5.26","5.27","5.29","5.38","5.39","5.40","5.41","5.42","5.43","10.8","10.9","10.10","10.13","10.15","10.16","12.1","12.3","12.4","12.5","12.9","12.11","12.13","12.14","12.15","12.19","12.21","12.23","12.25","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.28","13.29","13.30","15.1","15.6","15.7","15.15","15.17","15.21","15.24","15.25","15.26","15.27","15.30","15.38","15.39","15.40","15.43","19.1","19.6","21.1","22.3","22.25","22.42","23.5","24.7","24.8","24.16","26.3","26.5","26.8","26.9","26.13","26.14","26.15","26.16","26.17","26.21","26.25","26.26","26.38","26.42","26.45","26.46","26.51"],"全部工具函数请参考以下地址":["1.6"],"js":["1.11","10.8","10.11","10.12","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","13.2","13.34","15.5","15.29","22.11","22.21","22.27","22.37","22.38","22.41","22.48","22.51"],"emit":["2.0","12.0"],"focus":["2.0","12.0"],"移除事件":["2.0"],"true":["2.16","2.17","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.39","3.30","5.2","5.3","5.21","6.2","6.4","6.5","9.1","9.6","10.16","12.17","12.20","12.28","13.1","13.20","13.33","15.2","15.3","16.2","16.4","16.5","19.2","19.6","24.16","26.10","26.33","26.47"],"setting":["2.17","2.20","2.28","3.30","9.1","9.6","12.17","12.20","13.30","19.2","19.6","22.7"],"fullscreen":["2.22"],"srt":["2.28","2.29","2.30","2.31","12.31"],"并调用":["2.46"],"但数据意外未出现":["2.58"],"属性名字全部都是大写的形式":["3.0"],"未来容易发生变动":["3.0"],"new":["3.1","3.4","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.34","10.8","10.9","10.10","10.11","10.12","10.13","10.15","11.1","13.1","13.3","13.4","13.10","13.11","13.12","13.13","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.26","13.27","13.28","13.29","13.31","13.32","13.33","15.4","15.5","15.26","15.29","15.42","22.3","22.5","22.6","22.8","22.9","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.23","22.24","22.26","22.28","22.35","22.36","22.37","22.38","22.44","22.45","22.46","22.48","22.49","22.51","23.9","26.6","26.11","26.22","26.35","26.37","26.41"],"container":["3.1","3.3","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.31","3.32","3.33","3.34","5.5","5.29","10.8","10.9","10.10","10.11","10.12","10.13","10.15","10.16","11.1","13.3","13.6","13.7","13.8","13.9","13.10","13.11","13.17","13.22","13.28","13.29","15.4","15.5","15.6","15.7","15.15","15.17","15.24","15.26","15.27","15.29","15.38","15.39","15.40","15.42","15.43","19.1","20.3","22.5","22.6","22.8","22.9","22.12","22.13","22.14","22.15","22.16","22.20","22.23","22.24","22.27","22.28","22.36","22.37","22.45","22.46","22.49","22.51","23.10","24.8","26.3","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.28","26.36","26.37","26.38","26.41","26.44","26.45","26.46","26.48","26.49","26.51"],"log":["3.2","5.44","15.44"],"art":["3.14","3.15","3.16","3.19","3.20","3.25","3.26","3.31","3.34","10.8","10.9","10.10","10.11","10.13","10.15","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.28","13.31","13.32","13.33","15.4","15.5","15.29","15.42","20.9","22.3","22.5","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.23","22.24","22.26","22.36","22.37","22.38","22.44","22.45","22.46","22.48","22.49","22.51","23.9","26.11","26.22","26.27","26.37"],"var":["3.34","10.8","10.9","10.10","10.11","10.12","11.1","13.1","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","15.4","15.5","15.29","15.42","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.23","22.24","22.26","22.27","22.35","22.36","22.37","22.38","22.41","22.44","22.45","22.46","22.48","22.49","22.51","26.11","26.35","26.37"],"show":["4.0","6.2","6.3","6.4","14.0","16.2","16.3","16.4"],"block":["4.0","14.0"],"hide":["4.0","14.0"],"controls":["4.0","5.37","15.37","17.1","24.10"],"tooltip":["4.0","7.1","9.7","19.7","26.32"],"muted":["5.2","5.3","5.25","15.2","15.3","26.10"],"seek":["5.11","5.13"],"t":["5.12"],"right":["5.20","5.22","8.3","8.4","14.0","17.1","18.3","18.4","24.10","26.29"],"switch":["5.20","15.12"],"function":["5.20","5.22","6.1","8.1","8.2","8.3","16.1","18.1","18.2","18.3","22.29","22.31","22.32","24.9","24.11","24.13","26.29","26.31"],"theme":["5.44","15.44"],"settimeout":["5.45","6.5","8.5","9.9","10.14","15.45","16.5","18.5","19.9","26.2"],"subtitle":["5.47","12.29","12.30"],"object":["6.1","8.1"],"组件样式对象":["6.1","8.1"],"false":["6.2","6.3","6.4","9.5","13.19","13.31","13.34","16.2","16.3","16.4","19.5","24.6"],"update":["6.5","8.5","9.9"],"组件挂载后触发":["7.1"],"组件的提示文本":["7.1"],"yellow":["7.2","17.2"],"02":["7.2","17.2"],"onselect":["7.2","17.2"],"item":["7.2","9.5","17.2"],"dom":["7.2","17.2"],"args":["7.3","8.2","8.3","17.3","18.2","18.3","22.29","22.31","22.32","26.29","26.31"],"mounted":["7.3","8.2","8.3","17.3","18.2","18.3","24.13"],"style":["7.4","14.0","17.4","20.5","22.32","23.5","24.13","26.32"],"color":["7.4","17.4","22.32","24.4","26.32"],"red":["7.4","17.4"],"control":["7.5","17.5"],"by":["7.5","8.5","9.9","17.5","18.5","19.9","22.2","22.47"],"absolute":["8.4","14.0","18.4"],"top":["8.4","14.0","18.4"],"50px":["8.4","18.4"],"the":["8.5","9.9","18.5","19.9","20.4"],"button":["9.2"],"img":["9.2","9.6","9.7","14.0","19.2","19.5","19.7"],"height":["9.2","9.6","19.2","19.5","20.5","22.1","23.5","26.1"],"src":["9.2","9.5","14.0","19.5","22.39","26.39"],"quality":["9.3","19.3"],"1080p":["9.3","19.3"],"state":["9.5","22.39","24.6","26.39"],"svg":["9.5","9.8","19.5","19.8"],"settings":["9.6","10.4","19.2","19.6"],"slider":["9.6"],"5x":["9.6","9.7","19.6","19.7"],"width":["9.6","9.7","14.0","19.5","19.7","20.5","22.1","23.5","26.1"],"icon":["9.7","19.7"],"range":["9.8","19.8"],"instance":["10.0","23.4"],"which":["10.0","17.1"],"note":["10.1","15.20","15.22","15.41","22.2","22.17","22.19"],"if":["10.1","10.4","15.41","20.11","22.47","24.11","24.12"],"you":["10.1","10.4","15.41","20.6"],"directly":["10.1","20.4"],"regular":["10.2"],"objects":["10.2"],"within":["10.2"],"are":["10.2"],"mouseenter":["10.3"],"instances":["10.4"],"share":["10.4"],"same":["10.4","15.12"],"localstorage":["10.4"],"and":["10.4","12.46","15.12"],"want":["10.4"],"different":["10.4"],"players":["10.4"],"use":["10.4"],"loading":["10.5"],"this":["10.5","22.40"],"is":["10.5","12.48","15.33","20.4"],"using":["10.6"],"can":["10.6","22.40"],"only":["10.6","22.40"],"to":["10.7","11.6","15.20","15.22","20.5","23.5"],"artplayer":["10.8","10.9","10.10","10.11","10.12","10.13","10.15","10.16","13.34","15.4","15.6","15.15","15.17","15.26","15.29","15.38","15.39","15.40","15.42","22.3","22.5","22.6","22.8","22.9","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.28","22.35","22.36","22.37","22.38","22.44","22.45","22.46","22.49","22.51","26.6","26.11","26.12","26.18","26.20","26.22","26.23","26.24","26.28","26.35","26.37","26.38","26.41","26.44","26.48","26.49","26.51"],"classname":["10.11","13.34","22.11","22.22"],"run":["10.11","13.34","22.11","22.22"],"code":["10.11","13.34","15.5","22.11","22.22","22.41"],"flip":["10.16"],"playbackrate":["10.16"],"constructor":["11.0"],"please":["11.6"],"refer":["11.6"],"removing":["12.0"],"through":["12.42"],"end":["12.43"],"without":["12.43"],"duration":["12.45"],"partially":["12.46"],"reached":["12.47"],"not":["12.48","20.4"],"has":["12.49"],"delayed":["12.53"],"due":["12.53","15.20","15.22","22.17"],"loads":["12.54"],"changed":["12.55"],"completed":["12.56"],"begun":["12.57"],"been":["12.59"],"property":["12.60"],"lack":["12.62"],"these":["13.0","22.19"],"subject":["13.0"],"change":["13.0"],"div":["13.34","20.13","22.22","23.13"],"ads":["14.0"],"100px":["14.0"],"display":["14.0","24.13"],"none":["14.0"],"20px":["14.0"],"have":["15.12","15.16"],"functionality":["15.12"],"a":["15.16","21.0"],"such":["15.16"],"as":["15.16"],"live":["15.16"],"streams":["15.16"],"or":["15.16","17.1","22.1"],"browser":["15.20","15.22","22.17"],"security":["15.20","15.22","22.17"],"mechanisms":["15.22","22.17"],"jpg":["15.23"],"json":["15.28"],"stringify":["15.28"],"useful":["15.33"],"but":["15.33"],"need":["15.41"],"certain":["15.41"],"left":["17.1"],"side":["17.1"],"pnpm":["20.1","23.1","24.2"],"com":["20.2","20.11","23.2","23.11"],"of":["20.3"],"its":["20.3"],"therefore":["20.3"],"must":["20.3"],"reactive":["20.4"],"modifying":["20.4"],"600px":["20.5","23.5"],"400px":["20.5","22.1","26.1"],"margin":["20.5"],"60px":["20.5"],"auto":["20.5"],"when":["20.6","21.0"],"null":["20.8","23.8"],"volume":["20.9"],"option":["20.10","23.10"],"tip":["20.11"],"lang":["20.12","21.2","21.3"],"en":["20.12","23.12"],"head":["20.12","23.12"],"meta":["20.12","20.13","23.12"],"charset":["20.12","20.13","23.12"],"utf":["20.12","20.13","23.12"],"body":["20.13","23.13"],"class":["20.13","23.13"],"require":["21.0"],"cannot":["21.0"],"be":["21.0"],"matched":["21.0"],"script":["21.2","25.2"],"play":["21.4","22.19","25.4"],"css":["22.1"],"300px":["22.1","26.1"],"three":["22.2"],"file":["22.2"],"formats":["22.2"],"caches":["22.7"],"last":["22.7"],"upon":["22.7","22.10"],"immediately":["22.10"],"page":["22.10"],"load":["22.10"],"space":["22.19"],"toggle":["22.19"],"pause":["22.19"],"devices":["22.22"],"older":["22.22"],"browsers":["22.22"],"document":["22.27"],"queryselector":["22.27"],"opacity":["22.29","26.29"],"setting02":["22.30","26.30"],"green":["22.32","26.32"],"one":["22.34","26.34"],"more":["22.34","26.34"],"chance":["22.34","26.34"],"ploading":["22.39","26.39"],"gif":["22.39","26.39"],"recognition":["22.40"],"player":["22.40"],"parse":["22.40"],"suffixes":["22.40"],"like":["22.40"],"cache":["22.47"],"progress":["22.47"],"however":["22.47"],"for":["22.47"],"播放器的尺寸依赖于容器":["23.3"],"getinstance":["23.4"],"path":["23.5"],"ts":["23.6"],"types":["23.10"],"const":["23.10"],"unpkg":["23.11"],"title":["23.12"],"ffffff":["24.4"],"弹幕颜色":["24.4"],"默认为白色":["24.4"],"promise":["24.5"],"beforevisible":["24.5"],"弹幕显示前的过滤器":["24.5"],"visible":["24.5"],"弹幕层是否可见":["24.5"],"emitter":["24.5"],"是否开启弹幕发射器":["24.5"],"maxlength":["24.5"],"弹幕输入框最大长度":["24.5"],"await":["24.6"],"这里是所有弹幕的过滤器":["24.6"],"包含来自服务端的和来自用户输入的":["24.6"],"plugins":["24.9","24.15","24.16","24.17"],"artplayerplugindanmuku":["24.9","24.15","24.16","24.17"],"xml":["24.10"],"隐藏弹幕":["24.10"],"prompt":["24.12"],"请输入弹幕文本":["24.12"],"弹幕测试文本":["24.12"],"trim":["24.12"],"value":["24.13"],"flex":["24.13"],"alignitems":["24.13"],"center":["24.13"],"切换到新的弹幕库":["24.14"],"config":["24.14"],"v2":["24.14"],"fullscreenweb":["24.16"],"stop":["24.18"],"弹幕停止":["24.18"],"start":["24.18"],"弹幕开始":["24.18"],"当无法匹配到语言时":["25.0"],"会默认显示英文":["25.0"],"i18n":["25.0","25.3"],"或者使用":["26.1"],"aspect":["26.1"],"热键":["26.19"],"描述":["26.19"],"增加音量":["26.19"],"降低音量":["26.19"],"innerhtml":["26.27"],"sd":["26.33"],"后缀的识别":["26.40"],"播放器只能解析这种后缀":["26.40"],"因为播放器默认使用":["26.47"]},{"0":["23.5"],"2":["5.31"],"4":["22.22"],"5":["5.8","5.9","5.15","15.8","26.7"],"8":["2.0","12.0","20.12"],"9":["5.32","22.1"],"10":["5.11","5.13","15.11","15.13"],"16":["5.32","15.32","22.1","24.12","26.1"],"22":["19.6"],"60":["22.36","24.5","26.36"],"120":["22.34"],"180":["22.34","26.34"],"200":["24.6"],"240":["26.34"],"360":["9.3"],"720":["9.3","19.3"],"1000":["0.8","0.9","0.10","0.16","24.5","26.2"],"1080":["9.3","19.3"],"5000":["0.14","10.14"],"比较少用":["0.0"],"warning":["0.1","0.5","0.6","0.7","0.8","5.16","5.20","5.22","5.28","5.33","5.41","10.3","10.7","10.14","15.28","20.5","20.13","22.29","22.30","22.31","22.32","22.39","22.42","22.50","23.13","26.2","26.4","26.7","26.17","26.19","26.31","26.32","26.39","26.42","26.50"],"提示":["0.1","5.16","5.20","5.22","5.33","26.2","26.7","26.10","26.17"],"假如直接修改这个":["0.1"],"元素都是以":["0.2"],"开头命名的":["0.2"],"这是所有":["0.2"],"元素的定义":["0.2"],"mouseenter":["0.3"],"mouseleave":["0.3","10.3"],"loading":["0.5","12.49"],"这是所有图标的定义":["0.5"],"types":["0.5","1.6","11.6","25.0","26.50"],"使用":["0.6","24.9"],"只能更新实例化之后的":["0.6"],"to":["0.7","22.2"],"play":["0.7","4.0","5.2","10.7","15.2","21.3","22.2","25.3"],"如果想马上隐藏":["0.7"],"settimeout":["0.8","0.9","0.10","0.12","0.13","0.14","0.15","0.16","5.2","5.3","5.8","5.11","5.13","5.21","6.4","7.4","8.4","9.8","10.8","10.9","10.10","10.16","15.2","15.8","15.11","15.13","16.4","17.4","18.4","19.8"],"false":["0.8","0.9","0.10","0.15","0.16","22.29","22.31","24.4","26.29","26.31"],"left":["0.9","7.1","10.9"],"true":["0.10","0.12","0.13","2.19","3.5","3.6","3.7","3.28","3.29","5.1","5.14","5.25","5.34","6.3","10.10","12.16","12.19","12.21","12.22","12.23","12.24","12.25","12.26","12.39","13.5","13.6","13.7","13.28","13.29","13.30","15.1","15.21","15.25","15.34","16.3","19.1","22.25","22.33","26.17","26.25"],"srt":["0.11","5.47","12.28","12.29","12.30","15.47"],"ready":["0.12","5.2","5.3","5.5","5.6","5.7","5.8","5.10","5.17","5.21","5.24","5.25","5.26","5.27","5.29","6.4","7.4","8.4","9.8","10.8","10.9","10.10","10.11","10.12","10.13","10.15","10.16","12.0","12.6","15.2","15.3","15.5","15.8","15.10","15.15","15.17","15.18","15.19","15.21","15.25","15.26","15.29","15.30","16.4","17.4","18.4","19.8","24.17"],"on":["0.17","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.16","2.17","2.19","2.20","2.21","2.23","2.25","2.26","2.27","2.28","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.8","3.9","3.10","3.17","5.1","5.2","5.3","5.4","5.5","5.6","5.7","5.17","5.24","5.25","5.26","5.27","5.29","5.38","5.39","5.40","5.47","8.4","9.8","10.8","10.11","10.12","10.13","10.15","10.16","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.17","12.19","12.20","12.21","12.23","12.25","12.26","12.27","12.28","12.29","12.30","12.31","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.8","13.9","13.10","13.17","15.1","15.2","15.3","15.5","15.6","15.7","15.8","15.10","15.15","15.17","15.18","15.19","15.20","15.21","15.22","15.24","15.25","15.26","15.27","15.29","15.38","15.39","15.40","15.47","17.1","18.4","19.8","24.15","24.17","26.4"],"非常少使用":["1.0"],"sample":["1.1","3.1","3.3","3.4","3.11","3.12","3.13","3.18","3.21","3.22","3.23","3.24","3.27","3.31","3.32","3.33","3.34","5.4","5.5","5.43","10.11","10.12","11.1","13.8","13.9","13.10","13.11","13.12","13.13","13.17","13.21","13.22","13.23","13.24","13.28","13.33","13.34","15.4","15.5","15.6","15.7","15.17","15.24","15.27","15.29","15.38","15.39","15.40","15.42","15.43","20.10","22.5","22.6","22.8","22.9","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.28","22.35","22.37","22.38","22.41","22.44","22.45","22.46","22.49","22.51","23.10","24.8","26.6","26.8","26.9","26.11","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.28","26.35","26.38","26.41","26.44","26.45","26.46","26.48","26.49","26.51"],"video":["1.1","3.8","3.9","3.10","3.11","3.12","3.13","3.17","3.21","3.22","3.23","3.24","3.31","3.33","5.4","5.5","5.42","10.11","10.13","10.15","11.1","12.1","12.14","13.6","13.7","13.8","13.9","13.10","13.17","13.22","13.28","15.4","15.24","15.26","15.29","15.39","15.42","19.1","20.10","21.1","22.9","22.13","22.28","22.36","23.10","24.8","26.5","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.28","26.37","26.38","26.42","26.44","26.45","26.46","26.48","26.49"],"mp4":["1.1","3.8","3.9","3.10","3.17","3.22","3.28","3.34","5.4","5.5","5.6","5.7","5.24","5.27","5.29","5.38","5.40","5.42","5.43","10.11","10.12","10.13","10.15","12.1","12.3","12.4","12.11","12.14","12.19","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.40","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.22","13.28","13.29","13.34","15.4","15.5","15.6","15.7","15.15","15.17","15.24","15.26","15.27","15.29","15.38","15.39","15.40","15.42","15.43","19.1","20.10","21.1","22.5","22.25","22.36","22.37","22.38","22.42","23.10","24.7","24.8","26.5","26.8","26.9","26.13","26.14","26.15","26.16","26.17","26.21","26.26","26.37","26.38","26.42","26.45","26.46","26.51"],"artplayer":["1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.11","1.12","3.2","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","13.2","22.11","22.21","22.22","22.41","22.48"],"d":["1.6"],"info":["1.11","2.12","5.15","5.26","5.29","5.30","5.41","5.42","9.5","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","15.9","15.14","15.15","15.23","15.26","15.29","15.30","15.31","15.32","15.35","15.36","19.5","24.17","26.32"],"const":["2.0","5.18","5.19","9.5","12.0","15.18","15.19","19.5","20.10","24.13"],"onready":["2.0","12.0"],"console":["2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.40","2.41","5.25","5.26","5.29","5.39","5.41","5.42","5.43","9.5","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","12.5","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.27","12.31","12.41","15.9","15.14","15.15","15.23","15.26","15.29","15.30","15.31","15.35","15.36","15.42","15.43","19.5","20.5","23.5","24.17","26.32"],"event":["2.5","2.7","2.8","2.9","2.10","2.12","2.13","2.22","2.41","5.41","9.2","9.5","12.5","12.7","12.8","12.9","12.10","12.12","12.13","12.22","18.1"],"reconnecttime":["2.11","12.11"],"state":["2.12","2.15","2.16","2.21","2.23","2.24","2.25","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","9.2","9.6","9.7","12.12","12.15","12.21","12.23","12.24","12.25","12.32","12.33","12.34","12.35","12.36","12.37","12.38","19.2","19.7"],"height":["2.18","9.7","19.6","19.7"],"datauri":["2.26","12.26"],"currenttime":["2.27","12.27"],"offset":["2.28"],"cues":["2.29","2.30","2.31","12.29","12.30","12.31"],"option":["2.31","12.31"],"load":["2.46","12.46"],"方法重新加载它":["2.46"],"基本上用不到":["3.0"],"app":["3.1","3.4","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.24","3.25","3.26","3.27","3.31","3.32","3.34","10.11","10.12","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","13.34","15.4","15.5","15.42","20.10","22.3","22.6","22.8","22.11","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.28","22.35","22.38","22.41","22.44","22.45","22.46","22.48","22.49","22.51","23.10","23.13","26.3","26.11","26.22","26.35"],"url":["3.1","3.3","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.33","3.34","10.12","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","13.34","15.4","15.5","15.29","15.42","20.10","22.5","22.6","22.8","22.9","22.11","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.28","22.35","22.38","22.44","22.45","22.46","22.48","22.49","22.51","23.10","26.6","26.11","26.12","26.18","26.20","26.22","26.23","26.24","26.27","26.28","26.35","26.44","26.48","26.49"],"assets":["3.1","3.3","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.33","3.34","10.11","10.12","11.1","13.3","13.4","13.8","13.9","13.10","13.11","13.12","13.13","13.17","13.18","13.21","13.22","13.23","13.24","13.31","13.32","13.33","13.34","15.4","15.5","15.29","15.42","15.43","20.10","22.5","22.6","22.8","22.9","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.28","22.35","22.37","22.38","22.41","22.44","22.45","22.46","22.48","22.49","22.51","23.10","26.3","26.6","26.8","26.9","26.11","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.27","26.28","26.35","26.38","26.41","26.44","26.45","26.46","26.48","26.49","26.51"],"loop":["3.5","3.6","3.7","13.5","13.6","13.7"],"flip":["3.5","3.6","3.7","13.5","13.6","13.7"],"dblclick":["3.17"],"setting":["3.28","3.29","12.28","13.28","13.29","19.1","24.13"],"playbackrate":["3.28","13.28"],"contextmenu":["3.28","3.29","3.30","13.29","13.30"],"aspectratio":["3.29","10.16","13.29"],"show":["3.29","3.30","9.8","13.30","19.8","22.29","22.31","24.11","24.18","26.29","26.31"],"click":["4.0","5.37","5.41","14.0","15.37"],"marginright":["4.0","14.0"],"比较常用":["5.0"],"muted":["5.1","15.1","15.25"],"seek":["5.8","15.8","15.11","15.13"],"switch":["5.12"],"和":["5.12","7.1","24.5"],"的功能是一样的":["5.12"],"只是":["5.12"],"有的视频是没有时长的":["5.16"],"async":["5.18","5.19","15.18","15.19"],"await":["5.18","5.19","15.18","15.19"],"t":["5.23"],"json":["5.28"],"stringify":["5.28"],"resize":["5.33","24.15"],"当你的容器只有宽度":["5.33"],"playsinline":["5.34","15.34"],"m3u8":["5.35","22.2","26.41"],"000":["5.36"],"right":["5.37","7.1","15.37"],"html":["5.37","10.8","10.9","10.10","15.37","20.1","23.1"],"timeupdate":["5.39"],"green":["5.44","15.44"],"1080p":["5.45","15.45"],"png":["5.46","15.46","22.36","22.39","26.36","26.39"],"组件点击事件":["6.1","8.1"],"mounted":["6.1","8.1","16.1","18.1","22.29","26.29"],"组件挂载后触发":["6.1","8.1"],"get":["6.2","6.3","7.2","7.3","8.2","8.3","16.2","16.3","17.2","17.3","18.2","18.3"],"the":["6.2","6.3","6.4","6.5","7.2","7.3","7.4","8.2","8.3","8.4","9.8","16.2","16.3","16.4","16.5","17.2","17.3","17.4","18.2","18.3","18.4","19.8","22.19"],"element":["6.2","6.3","7.2","7.3","8.2","8.3","16.2","16.3","17.2","17.3","18.2","18.3"],"of":["6.2","6.3","7.2","7.3","8.2","8.3","10.5","12.53","16.2","16.3","17.2","17.3","18.2","18.3"],"by":["6.2","6.3","6.4","6.5","7.2","7.4","8.4","16.2","16.3","16.4","16.5","17.2","17.4","18.4","21.0"],"delete":["6.4","7.4","8.4","9.8","16.4","17.4","18.4","19.8"],"控制控制器出现的左右位置":["7.1"],"selector":["7.1","17.1"],"array":["7.1","17.1"],"return":["7.2","17.2"],"control":["7.2","7.3","7.4","17.2","17.3","17.4"],"200px":["8.5","18.5"],"svg":["9.2","9.6","9.7","19.2","19.6","19.7"],"item":["9.2","9.6","19.2"],"720p":["9.3","19.3"],"360p":["9.3","19.3"],"nextstate":["9.5","19.5"],"src":["9.6","9.7","19.2","19.6","19.7"],"pip":["9.9","19.9"],"mode":["9.9","19.9"],"close":["9.9","19.9"],"are":["10.0","11.0","15.0","22.2"],"less":["10.0"],"commonly":["10.0","15.0"],"modify":["10.1","10.4","20.11","20.13"],"this":["10.1","10.2"],"object":["10.1"],"named":["10.2"],"with":["10.2","20.12","23.12"],"a":["10.2","12.48","15.12","15.20","15.22"],"prefix":["10.2"],"is":["10.2","15.12","20.5","22.47"],"definition":["10.2","10.5"],"note":["10.3","10.14","15.28","20.13","22.4"],"if":["10.3","10.6","10.7","22.4","22.17"],"you":["10.3","10.6","10.7","22.47"],"need":["10.3","20.11","20.13","22.47"],"that":["10.3","15.16"],"should":["10.3"],"only":["10.3","10.14","15.5","15.41","22.19"],"exist":["10.3","15.41"],"during":["10.3"],"can":["10.4"],"after":["10.6","10.14","16.1","18.1","22.19"],"instantiation":["10.6"],"want":["10.6","10.7"],"before":["10.6","20.13"],"hide":["10.7","24.18"],"some":["10.8","10.9","10.10"],"text":["10.8","10.9","10.10","24.7","24.9"],"position":["10.9","15.37"],"these":["10.14"],"take":["10.14","22.19"],"effect":["10.14","22.19"],"subtitleoffset":["10.16"],"something":["10.17"],"dosomething":["10.17"],"which":["11.0","15.0"],"rarely":["11.0"],"following":["11.6","20.11"],"address":["11.6"],"off":["12.0"],"end":["12.42","12.47"],"without":["12.42"],"stopping":["12.42","12.43"],"for":["12.42","12.43","21.0","22.10","22.30","22.31","22.32","22.50"],"property":["12.45"],"changes":["12.45"],"method":["12.46","15.12"],"called":["12.46"],"its":["12.47"],"supported":["12.48","22.2"],"finished":["12.49"],"lack":["12.53"],"resource":["12.54"],"unexpectedly":["12.58"],"not":["12.58","20.5"],"suspended":["12.59"],"has":["12.60"],"changed":["12.60"],"data":["12.62"],"future":["13.0"],"and":["13.0","20.11"],"container":["13.1","13.4","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","13.34","20.10","22.3","22.18","22.21","22.22","22.26","22.35","22.38","22.41","22.44","22.48","23.3","26.35"],"log":["13.2","20.5","23.5"],"new":["13.14","13.15","13.16","13.25","13.34","20.8","20.9","22.11","22.22","22.27","22.41","23.8","26.27"],"var":["13.34","22.11","22.22"],"art":["13.34","22.11","22.22","22.27"],"controls":["14.0"],"tooltip":["14.0","16.1"],"returns":["15.12"],"promise":["15.12","24.9"],"it":["15.12","15.33","15.41","20.13"],"resolve":["15.12"],"s":["15.12","15.41"],"been":["15.16"],"fully":["15.16"],"decoded":["15.16"],"in":["15.16","20.4"],"mechanisms":["15.20"],"user":["15.20","15.22"],"interaction":["15.20","15.22"],"e":["15.20","15.22","22.7"],"g":["15.20","15.22","22.7"],"dimension":["15.28"],"exact":["15.33"],"unknown":["15.33"],"lifecycle":["15.41"],"triggered":["16.1","18.1"],"mount":["16.1","18.1"],"appears":["17.1"],"objects":["17.1"],"selection":["17.1"],"list":["17.1"],"img":["19.6"],"width":["19.6"],"have":["20.3"],"defined":["20.3"],"tip":["20.3","20.9","23.9","23.11"],"see":["20.3"],"more":["20.3","22.10","22.42"],"will":["20.4"],"reactive":["20.5"],"import":["20.6","20.12","23.12"],"current":["20.8","23.8"],"full":["20.9"],"typescript":["20.9","23.9"],"support":["20.11"],"even":["20.11"],"older":["20.11"],"configuration":["20.11","22.31","22.32"],"title":["20.12"],"map":["20.12","23.12"],"displayed":["21.0"],"default":["21.0"],"i18n":["21.0","21.3"],"syntax":["21.0","22.50"],"lang":["21.1","25.1"],"window":["21.2","25.2"],"imported":["21.4","25.4"],"use":["22.1"],"aspect":["22.1"],"ratio":["22.1","26.1"],"ogg":["22.2","26.2"],"webm":["22.2","26.2"],"other":["22.2"],"like":["22.2"],"or":["22.2"],"flv":["22.2"],"inside":["22.4"],"callback":["22.4"],"refers":["22.4"],"instance":["22.4"],"however":["22.4"],"an":["22.4"],"arrow":["22.4"],"next":["22.7"],"initialization":["22.7"],"page":["22.7"],"refresh":["22.7"],"must":["22.10"],"be":["22.10"],"set":["22.10"],"screenshotting":["22.17"],"may":["22.17"],"fail":["22.17"],"source":["22.17"],"player":["22.19"],"gains":["22.19"],"focus":["22.19"],"js":["22.22"],"innerhtml":["22.27"],"component":["22.31","22.32"],"please":["22.32"],"refer":["22.32"],"sd":["22.33"],"480p":["22.33","26.33"],"谁でもいいはずなのに":["22.34","26.34"],"夏の想い出がまわる":["22.34","26.34"],"all":["22.39"],"icon":["22.39"],"but":["22.40"],"cannot":["22.40"],"zh":["22.43","26.43"],"cn":["22.43","26.43"],"same":["22.47"],"different":["22.47"],"then":["22.47"],"reference":["22.50"],"的尺寸":["23.3"],"所以你的容器":["23.3"],"必须是有尺寸的":["23.3"],"非响应式":["23.4"],"在":["23.4"],"400px":["23.5"],"margin":["23.5"],"60px":["23.5"],"auto":["23.5"],"全部":["23.9"],"定义":["23.9"],"volume":["23.10"],"假如你要兼容更古老的浏览器时":["23.11"],"请修改以下配置然后自行构建":["23.11"],"body":["23.12"],"border":["24.4"],"弹幕是否有描边":["24.4"],"默认为":["24.4"],"locktime":["24.5"],"输入框锁定时间":["24.5"],"theme":["24.5"],"dark":["24.5","24.16"],"弹幕主题":["24.5"],"支持":["24.5"],"length":["24.6"],"这是弹幕即将显示的时触发的函数":["24.6"],"当返回true后才表示可以马上发送到播放器里":["24.6"],"弹幕已经出现在播放器里":["24.6"],"你可以访问到弹幕的dom元素里":["24.6"],"plugins":["24.7","24.8"],"artplayerplugindanmuku":["24.7","24.8"],"resovle":["24.9"],"function":["24.10","26.32"],"target":["24.11"],"innertext":["24.11"],"else":["24.11"],"color":["24.12"],"math":["24.12"],"floor":["24.12"],"random":["24.12"],"0xffffff":["24.12"],"tostring":["24.12"],"queryselector":["24.13"],"addeventlistener":["24.13"],"追加":["24.14"],"追加新的弹幕库":["24.14"],"参数类型和option":["24.14"],"danmuku相同":["24.14"],"xml":["24.15","24.17"],"弹幕隐藏":["24.18"],"弹幕显示":["24.18"],"写法参考":["25.0","26.50"],"默认支持三种视频文件格式":["26.2"],"播放器会缓存最后一次音量的大小":["26.7"],"假如希望默认进入页面就能自动播放视频":["26.10"],"必需为":["26.10"],"视频快进":["26.19"],"视频快退":["26.19"],"space":["26.19"],"切换播放":["26.19"],"暂停":["26.19"],"subtitle":["26.25"],"args":["26.32"],"hd":["26.33"],"webkit":["26.38"],"全部图标的定义":["26.39"],"但无法解析这种后缀":["26.40"],"作为":["26.47"],"key":["26.47"],"来缓存播放进度的":["26.47"],"但假如你的同一个视频的":["26.47"]},{"0":["5.10","5.11","5.13","5.16","5.23","15.10","15.11","15.13","15.16","15.23","20.10","23.10"],"1":["5.47","9.7","15.47","19.7","24.7","24.9"],"2":["5.8","15.8","15.31"],"5":["5.6","5.7","9.7","15.6","15.7","15.9","15.15","19.7","20.10","23.10"],"9":["15.32","26.1"],"10":["5.46","9.7","15.46","19.7","22.36","26.36"],"60":["5.46","15.46"],"240":["22.34"],"300":["22.34","26.34"],"360":["19.3"],"404":["3.14","3.15","13.14","13.15"],"1000":["0.13","0.15","10.8","10.9","10.10","10.13","10.15","10.16"],"3000":["0.12","5.2","5.3","5.8","5.11","5.13","5.21","5.45","6.4","6.5","7.4","7.5","8.4","8.5","9.8","9.9","10.12","15.2","15.3","15.8","15.11","15.13","15.21","15.45","16.4","16.5","17.4","17.5","18.4","18.5","19.8","19.9"],"对象":["0.1"],"播放器不会马上做出响应":["0.1"],"types":["0.2","2.0","10.2","10.5","20.9","21.0","22.39","22.50","23.9","26.39"],"d":["0.2","0.5","2.0","10.2","10.5","11.6","12.0","21.0","22.39","22.50","25.0","26.39","26.50"],"ts":["0.2","0.5","1.6","2.0","10.2","10.5","11.6","12.0","21.0","22.39","22.50","25.0","26.39","26.50"],"warning":["0.3","0.9","0.10","0.14","0.16","2.0","10.8","10.9","10.10","10.16","12.0","22.1","22.36","22.43","23.5","26.1","26.29","26.30","26.36","26.43"],"提示":["0.3","0.14","5.28","5.41","23.13","26.1","26.4","26.19"],"假如你需要一些":["0.3","5.41"],"事件只存在于播放器的生命周期上时":["0.3","5.41"],"强烈建议使用这些函数":["0.3"],"以避免造成内存泄漏":["0.3","5.41"],"your":["0.4","5.17","10.4","15.17"],"假如想在实例化之前更新":["0.6"],"请使用基础选项的":["0.6"],"来更新":["0.6"],"的显示":["0.7"],"组件配置":["0.8","0.9","0.10","26.29","26.31","26.32"],"请参考以下地址":["0.8","0.9","0.10","0.16","26.29","26.30","26.31","26.32"],"component":["0.8","0.9","0.10","0.16","10.8","10.9","10.10","10.16","22.29","22.30","26.29","26.30","26.31","26.32"],"color":["0.11","10.11","22.37","26.37"],"red":["0.11","10.11"],"false":["0.12","0.13","5.21","9.9","10.8","10.9","10.10","10.12","10.13","10.15","10.16","15.21","19.9","22.22","22.45","26.22","26.45"],"只在播放器获得焦点后":["0.14","26.19"],"如点击了播放器后":["0.14","26.19"],"这些快捷键才会生效":["0.14","26.19"],"true":["0.15","3.11","3.12","3.13","3.21","3.22","3.23","3.24","5.24","10.12","10.13","10.15","13.11","13.12","13.13","13.21","13.22","13.23","13.24","15.14","15.24","22.8","22.9","22.11","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.27","22.38","22.44","22.46","22.48","22.49","24.12","26.8","26.9","26.11","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.23","26.24","26.26","26.27","26.38","26.44","26.46","26.48","26.49"],"设置面板":["0.16"],"html":["0.16","10.16","22.42","22.43","24.2","26.42","26.43"],"ready":["0.17","2.0","5.1","5.4","5.47","10.17","15.1","15.4","15.6","15.7","15.24","15.27","15.47"],"off":["2.0"],"全部事件请参考以下地址":["2.0"],"events":["2.0"],"info":["2.1","2.2","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.28","2.29","2.30","2.31","5.18","5.19","5.25","5.38","5.39","5.40","5.43","9.2","9.6","12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.29","12.30","12.31","15.18","15.19","15.25","15.38","15.39","15.40","15.42","15.43","19.2","19.6"],"console":["2.2","2.6","2.19","2.28","2.39","3.8","3.9","3.10","3.17","5.18","5.19","5.38","5.40","9.2","9.6","12.1","12.2","12.3","12.4","12.6","12.11","12.14","12.16","12.17","12.18","12.19","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.28","12.29","12.30","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","13.8","13.9","13.10","13.17","15.18","15.19","15.25","15.38","15.39","15.40","19.2","19.6"],"log":["2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.8","3.9","3.10","3.17","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.8","13.9","13.10","13.17"],"video":["3.1","3.3","3.4","3.16","3.18","3.19","3.20","3.25","3.26","3.27","3.32","13.3","13.4","13.11","13.12","13.13","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","22.3","22.6","22.8","22.11","22.12","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.27","22.35","22.44","22.49","26.3","26.11","26.27","26.35"],"mp4":["3.1","3.3","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.33","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","22.3","22.6","22.8","22.9","22.11","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.27","22.28","22.35","22.44","22.45","22.46","22.48","22.49","22.51","26.3","26.6","26.11","26.12","26.18","26.20","26.22","26.23","26.24","26.27","26.28","26.35","26.44","26.48","26.49"],"playbackrate":["3.5","3.6","3.7","13.5","13.6","13.7"],"aspectratio":["3.5","3.6","3.7","13.5","13.6","13.7"],"autoplayback":["3.11","3.12","3.13","13.11","13.12","13.13"],"sample":["3.14","3.15","3.16","3.19","3.20","3.25","3.26","13.1","13.3","13.4","13.14","13.15","13.16","13.18","13.19","13.20","13.25","13.26","13.27","13.31","13.32","22.3","22.11","22.21","22.22","22.27","22.48","26.3","26.27"],"autoorientation":["3.21","13.21"],"show":["3.22","3.28","13.22","13.28","13.29"],"fastforward":["3.23","3.24","13.23","13.24"],"fullscreenweb":["3.31","13.31"],"miniprogressbar":["3.33","13.33"],"只销毁界面":["3.34"],"不主动清空":["3.34"],"pause":["4.0","14.0"],"layer":["4.0","14.0"],"png":["4.0","14.0"],"仅重置":["5.5"],"不移除界面":["5.5"],"t":["5.10","5.11","5.13","15.10","15.11","15.13","15.23"],"方法会返回":["5.12"],"promise":["5.12"],"当":["5.12"],"resolve":["5.12"],"时表示新地址是可以播放":["5.12"],"reject":["5.12","15.12"],"时表示新地址加载错误":["5.12"],"例如直播中的视频或者没被解码完成的视频":["5.16"],"这个时候获取的时长会是":["5.16"],"name":["5.17","15.17"],"由于浏览器安全机制":["5.20","5.22","26.17"],"触发窗口全屏前":["5.20"],"页面必须先存在交互":["5.20","5.22"],"例如用户点击过页面":["5.20","5.22"],"触发画中画前":["5.22"],"默认":["5.26"],"尺寸和坐标信息是通过":["5.28"],"getboundingclientrect":["5.28","15.28"],"获取的":["5.28"],"但不知道具体高度时":["5.33"],"这个属性很有用":["5.33"],"它能自动计算出视频的高度":["5.33"],"但你需要确定设置这个属性的时机":["5.33"],"强烈建议使用该函数":["5.41"],"4k":["5.45","15.45"],"number":["5.46","15.46","24.13"],"column":["5.46","15.46"],"tooltip":["6.1","8.1","18.1"],"组件的提示文本":["6.1","8.1"],"remove":["6.4","7.4","8.4","9.8","16.4","17.4","18.4"],"选择列表的对象数组":["7.1"],"onselect":["7.1","17.1"],"选择列表的元素被点击时触发的函数":["7.1"],"by":["7.3","8.2","8.3","9.8","17.3","18.2","18.3","19.8"],"left":["8.5","18.5","22.2"],"return":["9.2","9.5","9.6","19.2","19.5","19.6"],"switchquality":["9.3","19.3"],"open":["9.5","19.5"],"event":["9.6"],"x":["9.6","19.6"],"range":["9.7","19.7"],"switch":["9.9","19.9"],"used":["10.0","11.0","13.0","15.0","22.4"],"will":["10.1","15.16","20.5","22.4","22.7"],"not":["10.1","13.34","15.5","22.4"],"respond":["10.1"],"immediately":["10.1","10.7"],"s":["10.3","22.40"],"lifecycle":["10.3"],"strongly":["10.3","15.41"],"recommended":["10.3","15.41"],"use":["10.3","10.6","15.41","22.40"],"these":["10.3"],"functions":["10.3"],"avoid":["10.3","15.41"],"memory":["10.3","15.41"],"leaks":["10.3","15.41"],"please":["10.6","10.8","10.9","10.10","10.16","12.0","22.2","22.10","22.29","22.30","22.31"],"option":["10.6"],"in":["10.6","20.5"],"basic":["10.6"],"settings":["10.6","22.42","22.43"],"for":["10.8","10.9","10.10","10.16","12.0","15.33","20.13","22.4","22.29"],"configuration":["10.8","10.9","10.10","22.29"],"refer":["10.8","10.9","10.10","10.16","12.0","22.2","22.29","22.30","22.31"],"srt":["10.11","22.25","26.25"],"settimeout":["10.12","10.13","10.15","15.3","15.21"],"gains":["10.14"],"focus":["10.14"],"e":["10.14","22.19"],"g":["10.14","22.19"],"clicking":["10.14","22.19"],"on":["10.17","15.4","22.2","22.19","24.6"],"a":["12.0","17.1"],"complete":["12.0"],"list":["12.0"],"state":["12.39"],"further":["12.42"],"buffering":["12.42","12.43"],"to":["12.46","15.33","22.29","22.30","22.31","22.32"],"reload":["12.46"],"it":["12.46","20.11"],"format":["12.48"],"data":["12.53"],"forthcoming":["12.58"],"rarely":["13.0"],"assets":["13.1","13.14","13.15","13.16","13.19","13.20","13.25","13.26","13.27","22.3","22.11","22.27"],"dblclick":["13.17"],"contextmenu":["13.28"],"do":["13.34","15.5"],"clear":["13.34"],"play":["14.0"],"interface":["15.5"],"playable":["15.12"],"fails":["15.12"],"load":["15.12"],"cases":["15.16"],"obtained":["15.16","15.28"],"be":["15.16"],"page":["15.20","15.22"],"must":["15.20","15.22"],"occur":["15.20","15.22"],"before":["15.20","15.22"],"triggering":["15.20","15.22"],"default":["15.26"],"is":["15.26","15.28","22.17"],"via":["15.28"],"you":["15.33","22.40"],"need":["15.33"],"determine":["15.33"],"timing":["15.33"],"setting":["15.33","22.14","22.15","22.16","22.25","26.14","26.15","26.16","26.25"],"m3u8":["15.35","22.41","26.2"],"000":["15.36"],"timeupdate":["15.39"],"this":["15.41","22.7"],"text":["16.1","18.1"],"when":["17.1"],"item":["17.1"],"clicked":["17.1"],"script":["20.1","23.1","24.2"],"examples":["20.3"],"at":["20.3"],"following":["20.3","22.32"],"link":["20.3"],"example":["20.3","23.3"],"update":["20.4","20.5"],"player":["20.4","20.12","23.12"],"directly":["20.5"],"modifying":["20.5"],"the":["20.5","22.32"],"definitions":["20.9","22.39"],"packages":["20.9","23.9"],"volume":["20.10"],"art8":["20.10","23.10"],"new":["20.10","23.10"],"yourself":["20.11"],"scripts":["20.11","23.11"],"reference":["20.11","21.0"],"documentation":["20.11"],"browserslist":["20.11","23.11"],"body":["20.12"],"div":["20.12","23.12"],"id":["20.12","23.12"],"importing":["20.13"],"dependency":["20.13"],"take":["20.13"],"effect":["20.13"],"see":["21.0"],"or":["21.1","25.1"],"note":["22.1"],"among":["22.1"],"all":["22.1"],"options":["22.1"],"only":["22.1"],"required":["22.1"],"third":["22.2"],"party":["22.2"],"libraries":["22.2"],"section":["22.2"],"point":["22.4"],"jpg":["22.5","26.5"],"ffad00":["22.6","26.6"],"read":["22.7","22.10"],"cached":["22.7"],"value":["22.7"],"information":["22.10"],"policy":["22.10","26.10"],"changes":["22.10","26.10"],"cross":["22.17"],"origin":["22.17"],"with":["22.17"],"website":["22.17"],"disable":["22.22"],"url":["22.27"],"panel":["22.30"],"address":["22.32"],"hd":["22.33"],"720p":["22.33","26.33"],"こんなとこにあるはずもないのに":["22.34","26.34"],"终わり":["22.34","26.34"],"generate":["22.36"],"online":["22.36"],"tool":["22.36","26.36"],"03a9f4":["22.37","26.37"],"font":["22.37","24.5","26.37"],"size":["22.37","24.5","26.37"],"30px":["22.37","26.37"],"webkit":["22.38"],"playsinline":["22.38","26.38"],"therefore":["22.40"],"if":["22.40"],"best":["22.40"],"also":["22.40"],"start":["22.42","22.43","26.42","26.43"],"i18n":["22.42","26.42"],"tw":["22.43","26.43"],"more":["22.43"],"identify":["22.47"],"unique":["22.47"],"document":["22.51","26.51"],"createelement":["22.51","26.51"],"tip":["23.3"],"以下链接可以看到更多的使用例子":["23.3"],"里直接修改":["23.4","23.5"],"是不会改变播放器的":["23.4","23.5"],"非响应式":["23.5"],"在":["23.5"],"构建配置":["23.11"],"build":["23.11"],"参考文档":["23.11"],"你需要在引入":["23.13"],"依赖前来修改它才会生效":["23.13"],"style":["24.4"],"弹幕自定义样式":["24.4"],"默认为空对象":["24.4"],"light":["24.5"],"只在自定义挂载时生效":["24.5"],"不透明度配置项":["24.5"],"弹幕字号配置项":["24.5"],"显示区域配置项":["24.5"],"弹幕速度配置项":["24.5"],"颜色列表配置项":["24.5"],"ref":["24.6"],"innerhtml":["24.6"],"ଘ":["24.6"],"੭ˊᵕˋ":["24.6"],"੭":["24.6"],"使用数组":["24.7"],"time":["24.7","24.9"],"异步返回":["24.9"],"显示弹幕":["24.10","24.11"],"hide":["24.11"],"border":["24.12"],"change":["24.13"],"fontsize":["24.13"],"const":["24.14"],"target":["24.14"],"xml":["24.16"],"也可以手动挂载":["24.16"],"reset":["24.18"],"弹幕重置":["24.18"],"destroy":["24.18"],"弹幕销毁":["24.18"],"全部选项里":["26.1"],"只有":["26.1"],"是必填的":["26.1"],"如需要播放":["26.2"],"或者":["26.2"],"flv":["26.2"],"等其它格式":["26.2"],"请参考左侧的":["26.2"],"第三方库":["26.2"],"回调函数里的":["26.4"],"就是播放器实例":["26.4"],"但回调函数假如使用了箭头函数":["26.4"],"则不会指向播放器实例":["26.4"],"下次初始化时":["26.7"],"如刷新页面":["26.7"],"播放器会读取该缓存值":["26.7"],"更多信息请阅读":["26.10"],"假如视频源地址和网站是跨域的":["26.17"],"可能会出现截图失败":["26.17"],"关闭毛玻璃效果":["26.22"],"在线生成预览图":["26.36"],"thumbnail":["26.36"],"所以假如你使用了":["26.40"],"最好同时要指明":["26.40"],"function":["26.41"],"更多的语言设置":["26.42","26.43"],"是不同的话":["26.47"],"那么你需要使用":["26.47"],"来标识视频的唯一":["26.47"]}]'},t={"0.0":{t:"# 高级属性",p:`这里的 高级属性 是指挂载在 实例 的 二级属性,比较少用 -`,l:"advanced/built-in.html",a:"高级属性"},"0.1":{t:"`option`",p:`播放器的选项 -<div className="run-code">▶ Run Code< ...`,l:"advanced/built-in.html#option",a:"option"},"0.2":{t:"`template`",p:`管理播放器所有的 DOM 元素 -<div className="run-code">▶ Ru ...`,l:"advanced/built-in.html#template",a:"template"},"0.3":{t:"`events`",p:"管理播放器所有的 DOM 事件,实质上是代理了 addEventListener 和 removeEventListener ...",l:"advanced/built-in.html#events",a:"events"},"0.4":{t:"`storage`",p:`管理播放器的本地存储 - -name 属性用于设置缓存的 key -set 方法用于设置缓存 -get 方法用于获取缓存 -del 方 ...`,l:"advanced/built-in.html#storage",a:"storage"},"0.5":{t:"`icons`",p:`管理播放器所有的 svg 图标 -<div className="run-code">▶ Ru ...`,l:"advanced/built-in.html#icons",a:"icons"},"0.6":{t:"`i18n`",p:`管理播放器的 i18n - -get 方法用于获取 i18n 的值 -update 方法用于更新 i18n 对象 - -<div ...`,l:"advanced/built-in.html#i18n",a:"i18n"},"0.7":{t:"`notice`",p:`管理播放器的提示语,只有一个 show 属性用于显示提示语 -<div className="run-code ...`,l:"advanced/built-in.html#notice",a:"notice"},"0.8":{t:"`layers`",p:`管理播放器的层 - -add 方法用于动态添加层 -remove 方法用于动态删除层 -update 方法用于动态更新层 -show ...`,l:"advanced/built-in.html#layers",a:"layers"},"0.9":{t:"`controls`",p:`管理播放器的控制器 - -add 方法用于动态添加控制器 -remove 方法用于动态删除控制器 -update 方法用于动态更新控 ...`,l:"advanced/built-in.html#controls",a:"controls"},"0.10":{t:"`contextmenu`",p:`管理播放器的右键菜单 - -add 方法用于动态添加菜单 -remove 方法用于动态删除菜单 -update 方法用于动态更新菜单 ...`,l:"advanced/built-in.html#contextmenu",a:"contextmenu"},"0.11":{t:"`subtitle`",p:`管理播放器的字幕功能 - -url 属性设置和返回当前字幕地址 -style 方法设置当前字幕的样式 -switch 方法设置当前字 ...`,l:"advanced/built-in.html#subtitle",a:"subtitle"},"0.12":{t:"`info`",p:`管理播放器的信息面板,常用于查看当前播放器和视频的运行状态,例如版本号、分辨率、时长等。 - -通过 art.info.show ...`,l:"advanced/built-in.html#info",a:"info"},"0.13":{t:"`loading`",p:`管理播放器的加载层 - -show 属性用于设置是否显示加载层 -toggle 属性用于切换是否显示加载层 - -<div cl ...`,l:"advanced/built-in.html#loading",a:"loading"},"0.14":{t:"`hotkey`",p:`管理播放器的快捷键功能 - -add 方法用于添加快捷键 -remove 方法用于删除快捷键 - -<div className ...`,l:"advanced/built-in.html#hotkey",a:"hotkey"},"0.15":{t:"`mask`",p:`管理播放器的遮罩层 - -show 属性用于设置是否显示遮罩层 -toggle 属性用于切换是否显示遮罩层 - -<div cl ...`,l:"advanced/built-in.html#mask",a:"mask"},"0.16":{t:"`setting`",p:`管理播放器的设置面板 - -add 方法用于动态添加设置项 -remove 方法用于动态删除设置项 -update 方法用于动态更新 ...`,l:"advanced/built-in.html#setting",a:"setting"},"0.17":{t:"`plugins`",p:`管理播放器的插件功能,只有一个方法 add 用于动态添加插件 -<div className="run-cod ...`,l:"advanced/built-in.html#plugins",a:"plugins"},"1.0":{t:"# 静态属性",p:`这里的 静态属性 是指挂载在 构造函数 的 一级属性,非常少使用 -`,l:"advanced/class.html",a:"静态属性"},"1.1":{t:"`instances`",p:`返回全部播放器实例的数组,假如你想同时管理多个播放器的时候,可以用到该属性 -<div className=" ...`,l:"advanced/class.html#instances",a:"instances"},"1.2":{t:"`version`",p:`返回播放器的版本信息 -<div className="run-code">▶ Run Cod ...`,l:"advanced/class.html#version",a:"version"},"1.3":{t:"`env`",p:`返回播放器的环境变量 -<div className="run-code">▶ Run Cod ...`,l:"advanced/class.html#env",a:"env"},"1.4":{t:"`build`",p:`返回播放器的打包时间 -<div className="run-code">▶ Run Cod ...`,l:"advanced/class.html#build",a:"build"},"1.5":{t:"`config`",p:`返回视频的默认配置 -<div className="run-code">▶ Run Code ...`,l:"advanced/class.html#config",a:"config"},"1.6":{t:"`utils`",p:`返回播放器的工具函数集合 -<div className="run-code">▶ Run C ...`,l:"advanced/class.html#utils",a:"utils"},"1.7":{t:"`scheme`",p:`返回播放器选项的校验方案 -<div className="run-code">▶ Run C ...`,l:"advanced/class.html#scheme",a:"scheme"},"1.8":{t:"`Emitter`",p:`返回事件分发器的构造函数 -<div className="run-code">▶ Run C ...`,l:"advanced/class.html#emitter",a:"emitter"},"1.9":{t:"`validator`",p:`返回选项的校验函数 -<div className="run-code">▶ Run Code ...`,l:"advanced/class.html#validator",a:"validator"},"1.10":{t:"`kindOf`",p:`返回类型检测的函数工具 -<div className="run-code">▶ Run Co ...`,l:"advanced/class.html#kindof",a:"kindof"},"1.11":{t:"`html`",p:`返回播放器所需的 html 字符串 -<div className="run-code">▶ ...`,l:"advanced/class.html#html",a:"html"},"1.12":{t:"`option`",p:`返回播放器的默认选项 -<div className="run-code">▶ Run Cod ...`,l:"advanced/class.html#option",a:"option"},"2.0":{t:"# 实例事件",p:`播放器的事件分为两种,一种视频的 原生事件 (前缀 video:),另外一种是 自定义事件 -监听事件: -<div cl ...`,l:"advanced/event.html",a:"实例事件"},"2.1":{t:"`ready`",p:`当播放器首次可以播放器时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#ready",a:"ready"},"2.2":{t:"`restart`",p:`当播放器切换地址后并可以播放时触发 -<div className="run-code">▶ ...`,l:"advanced/event.html#restart",a:"restart"},"2.3":{t:"`pause`",p:`当播放器暂停时触发 -<div className="run-code">▶ Run Code ...`,l:"advanced/event.html#pause",a:"pause"},"2.4":{t:"`play`",p:`当播放器播放时触发 -<div className="run-code">▶ Run Code ...`,l:"advanced/event.html#play",a:"play"},"2.5":{t:"`hotkey`",p:`当播放器热键被按下时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#hotkey",a:"hotkey"},"2.6":{t:"`destroy`",p:`当播放器销毁时触发 -<div className="run-code">▶ Run Code ...`,l:"advanced/event.html#destroy",a:"destroy"},"2.7":{t:"`focus`",p:`当播放器获得焦点时触发 -<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#focus",a:"focus"},"2.8":{t:"`blur`",p:`当播放器失去焦点时触发 -<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#blur",a:"blur"},"2.9":{t:"`dblclick`",p:`当播放器被双击时触发 -<div className="run-code">▶ Run Cod ...`,l:"advanced/event.html#dblclick",a:"dblclick"},"2.10":{t:"`click`",p:`当播放器被单击时触发 -<div className="run-code">▶ Run Cod ...`,l:"advanced/event.html#click",a:"click"},"2.11":{t:"`error`",p:`当播放器加载视频发生错误时触发 -<div className="run-code">▶ Ru ...`,l:"advanced/event.html#error",a:"error"},"2.12":{t:"`hover`",p:`当播放器被鼠标移出或者移入时触发 -<div className="run-code">▶ R ...`,l:"advanced/event.html#hover",a:"hover"},"2.13":{t:"`mousemove`",p:`当播放器被鼠标经过时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#mousemove",a:"mousemove"},"2.14":{t:"`resize`",p:`当播放器尺寸变化时触发 -<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#resize",a:"resize"},"2.15":{t:"`view`",p:`当播放器出现在视口时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#view",a:"view"},"2.16":{t:"`lock`",p:`在移动端,当锁定的状态发生变化时触发 -<div className="run-code">▶ ...`,l:"advanced/event.html#lock",a:"lock"},"2.17":{t:"`aspectRatio`",p:`当播放器长宽比变化时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#aspectratio",a:"aspectratio"},"2.18":{t:"`autoHeight`",p:`当播放器自动设置高度时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#autoheight",a:"autoheight"},"2.19":{t:"`autoSize`",p:`当播放器自动设置尺寸时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#autosize",a:"autosize"},"2.20":{t:"`flip`",p:`当播放器发生翻转时触发 -<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#flip",a:"flip"},"2.21":{t:"`fullscreen`",p:`当播放器发生窗口全屏时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#fullscreen",a:"fullscreen"},"2.22":{t:"`fullscreenError`",p:`当播放器发生窗口全屏错误时触发 -<div className="run-code">▶ Ru ...`,l:"advanced/event.html#fullscreenerror",a:"fullscreenerror"},"2.23":{t:"`fullscreenWeb`",p:`当播放器发生网页全屏时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#fullscreenweb",a:"fullscreenweb"},"2.24":{t:"`mini`",p:`当播放器进入迷你模式时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#mini",a:"mini"},"2.25":{t:"`pip`",p:`当播放器进入画中画时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#pip",a:"pip"},"2.26":{t:"`screenshot`",p:`当播放器被截图时触发 -<div className="run-code">▶ Run Cod ...`,l:"advanced/event.html#screenshot",a:"screenshot"},"2.27":{t:"`seek`",p:`当播放器发生时间跳转时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#seek",a:"seek"},"2.28":{t:"`subtitleOffset`",p:`当播放器发生字幕偏移时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#subtitleoffset",a:"subtitleoffset"},"2.29":{t:"`subtitleBeforeUpdate`",p:`当字幕更新前触发 -<div className="run-code">▶ Run Code& ...`,l:"advanced/event.html#subtitlebeforeupdate",a:"subtitlebeforeupdate"},"2.30":{t:"`subtitleAfterUpdate`",p:`当字幕更新后触发 -<div className="run-code">▶ Run Code& ...`,l:"advanced/event.html#subtitleafterupdate",a:"subtitleafterupdate"},"2.31":{t:"`subtitleLoad`",p:`当字幕加载时触发 -<div className="run-code">▶ Run Code& ...`,l:"advanced/event.html#subtitleload",a:"subtitleload"},"2.32":{t:"`info`",p:`当信息面板显示或隐藏时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#info",a:"info"},"2.33":{t:"`layer`",p:`当自定义层显示或隐藏时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#layer",a:"layer"},"2.34":{t:"`loading`",p:`当加载器显示或隐藏时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#loading",a:"loading"},"2.35":{t:"`mask`",p:`当遮罩层显示或隐藏时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#mask",a:"mask"},"2.36":{t:"`subtitle`",p:`当字幕层显示或隐藏时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#subtitle",a:"subtitle"},"2.37":{t:"`contextmenu`",p:`当右键菜单显示或隐藏时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#contextmenu",a:"contextmenu"},"2.38":{t:"`control`",p:`当控制器显示或隐藏时触发 -<div className="run-code">▶ Run C ...`,l:"advanced/event.html#control",a:"control"},"2.39":{t:"`setting`",p:`当设置面板显示或隐藏时触发 -<div className="run-code">▶ Run ...`,l:"advanced/event.html#setting",a:"setting"},"2.40":{t:"`muted`",p:`当静音的状态变化时触发 -<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#muted",a:"muted"},"2.41":{t:"`keydown`",p:`监听来自 document 的 keydown 事件 -<div className="run-code&qu ...`,l:"advanced/event.html#keydown",a:"keydown"},"2.42":{t:"`video:canplay`",p:`浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容 -`,l:"advanced/event.html#video-canplay",a:"video-canplay"},"2.43":{t:"`video:canplaythrough`",p:`浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束 -`,l:"advanced/event.html#video-canplaythrough",a:"video-canplaythrough"},"2.44":{t:"`video:complete`",p:`OfflineAudioContext 渲染完成 -`,l:"advanced/event.html#video-complete",a:"video-complete"},"2.45":{t:"`video:durationchange`",p:`duration 属性的值改变时触发 -`,l:"advanced/event.html#video-durationchange",a:"video-durationchange"},"2.46":{t:"`video:emptied`",p:"媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载 ...",l:"advanced/event.html#video-emptied",a:"video-emptied"},"2.47":{t:"`video:ended`",p:`视频停止播放,因为 media 已经到达结束点 -`,l:"advanced/event.html#video-ended",a:"video-ended"},"2.48":{t:"`video:error`",p:`获取媒体数据时出错,或者资源类型不是受支持的媒体格式 -`,l:"advanced/event.html#video-error",a:"video-error"},"2.49":{t:"`video:loadeddata`",p:`media 中的首帧已经完成加载 -`,l:"advanced/event.html#video-loadeddata",a:"video-loadeddata"},"2.50":{t:"`video:loadedmetadata`",p:`已加载元数据 -`,l:"advanced/event.html#video-loadedmetadata",a:"video-loadedmetadata"},"2.51":{t:"`video:pause`",p:`播放已暂停 -`,l:"advanced/event.html#video-pause",a:"video-pause"},"2.52":{t:"`video:play`",p:`播放已开始 -`,l:"advanced/event.html#video-play",a:"video-play"},"2.53":{t:"`video:playing`",p:`由于缺乏数据而暂停或延迟后,播放准备开始 -`,l:"advanced/event.html#video-playing",a:"video-playing"},"2.54":{t:"`video:progress`",p:`在浏览器加载资源时周期性触发 -`,l:"advanced/event.html#video-progress",a:"video-progress"},"2.55":{t:"`video:ratechange`",p:`播放速率发生变化 -`,l:"advanced/event.html#video-ratechange",a:"video-ratechange"},"2.56":{t:"`video:seeked`",p:`跳帧(seek)操作完成 -`,l:"advanced/event.html#video-seeked",a:"video-seeked"},"2.57":{t:"`video:seeking`",p:`跳帧(seek)操作开始 -`,l:"advanced/event.html#video-seeking",a:"video-seeking"},"2.58":{t:"`video:stalled`",p:`用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现 -`,l:"advanced/event.html#video-stalled",a:"video-stalled"},"2.59":{t:"`video:suspend`",p:`媒体数据加载已暂停 -`,l:"advanced/event.html#video-suspend",a:"video-suspend"},"2.60":{t:"`video:timeupdate`",p:`currentTime 属性指定的时间发生变化 -`,l:"advanced/event.html#video-timeupdate",a:"video-timeupdate"},"2.61":{t:"`video:volumechange`",p:`音量发生变化 -`,l:"advanced/event.html#video-volumechange",a:"video-volumechange"},"2.62":{t:"`video:waiting`",p:`由于暂时缺少数据,播放已停止 -`,l:"advanced/event.html#video-waiting",a:"video-waiting"},"3.0":{t:"# 全局属性",p:`这里的 全局属性 也是指挂载在 构造函数 的 一级属性,属性名字全部都是大写的形式,未来容易发生变动,基本上用不到 -`,l:"advanced/global.html",a:"全局属性"},"3.1":{t:"DEBUG",p:`是否开始 debug 模式,可以打印出视频全部的内置事件,默认关闭 -<div className="run- ...`,l:"advanced/global.html#debug",a:"debug"},"3.2":{t:"STYLE",p:`返回播放器样式文本 -<div className="run-code">▶ Run Code ...`,l:"advanced/global.html#style",a:"style"},"3.3":{t:"CONTEXTMENU",p:`是否开启右键菜单,默认开启 -<div className="run-code">▶ Run ...`,l:"advanced/global.html#contextmenu",a:"contextmenu"},"3.4":{t:"NOTICE_TIME",p:`提示信息的显示时长,单位为毫秒,默认为 2000 -<div className="run-code" ...`,l:"advanced/global.html#notice-time",a:"notice-time"},"3.5":{t:"SETTING_WIDTH",p:`设置面板的默认宽度,单位为像素,默认为 250 -<div className="run-code" ...`,l:"advanced/global.html#setting-width",a:"setting-width"},"3.6":{t:"SETTING_ITEM_WIDTH",p:`设置面板的设置项的默认宽度,单位为像素,默认为 200 -<div className="run-code&q ...`,l:"advanced/global.html#setting-item-width",a:"setting-item-width"},"3.7":{t:"SETTING_ITEM_HEIGHT",p:`设置面板的设置项的默认高度,单位为像素,默认为 35 -<div className="run-code&qu ...`,l:"advanced/global.html#setting-item-height",a:"setting-item-height"},"3.8":{t:"RESIZE_TIME",p:`resize 事件的节流时间,单位为毫秒,默认为 200 -<div className="run-code& ...`,l:"advanced/global.html#resize-time",a:"resize-time"},"3.9":{t:"SCROLL_TIME",p:`scroll 事件的节流时间,单位为毫秒,默认为 200 -<div className="run-code& ...`,l:"advanced/global.html#scroll-time",a:"scroll-time"},"3.10":{t:"SCROLL_GAP",p:`view 事件的边界容差距离,单位为像素,默认为 50 -<div className="run-code&q ...`,l:"advanced/global.html#scroll-gap",a:"scroll-gap"},"3.11":{t:"AUTO_PLAYBACK_MAX",p:`自动回放功能的最大记录数,默认为 10 -<div className="run-code"> ...`,l:"advanced/global.html#auto-playback-max",a:"auto-playback-max"},"3.12":{t:"AUTO_PLAYBACK_MIN",p:`自动回放功能的最小记录时长,单位为秒,默认为 5 -<div className="run-code" ...`,l:"advanced/global.html#auto-playback-min",a:"auto-playback-min"},"3.13":{t:"AUTO_PLAYBACK_TIMEOUT",p:`自动回放功能的隐藏延迟时长,单位为毫秒,默认为 3000 -<div className="run-code& ...`,l:"advanced/global.html#auto-playback-timeout",a:"auto-playback-timeout"},"3.14":{t:"RECONNECT_TIME_MAX",p:`发生连接错误时,自动连接的最大次数,默认为 5 -<div className="run-code" ...`,l:"advanced/global.html#reconnect-time-max",a:"reconnect-time-max"},"3.15":{t:"RECONNECT_SLEEP_TIME",p:`发生连接错误时,自动连接的延迟时间,单位为毫秒,默认为 1000 -<div className="run-c ...`,l:"advanced/global.html#reconnect-sleep-time",a:"reconnect-sleep-time"},"3.16":{t:"CONTROL_HIDE_TIME",p:`底部控制栏的自动隐藏的延迟时间,单位为毫秒,默认为 3000 -<div className="run-cod ...`,l:"advanced/global.html#control-hide-time",a:"control-hide-time"},"3.17":{t:"DBCLICK_TIME",p:`双击事件的延迟事件,单位为毫秒,默认为 300 -<div className="run-code" ...`,l:"advanced/global.html#dbclick-time",a:"dbclick-time"},"3.18":{t:"DBCLICK_FULLSCREEN",p:`在桌面端,是否双击切换全屏,默认为 true -<div className="run-code"& ...`,l:"advanced/global.html#dbclick-fullscreen",a:"dbclick-fullscreen"},"3.19":{t:"MOBILE_DBCLICK_PLAY",p:`在移动端,是否双击切换播放暂停,默认为 true -<div className="run-code" ...`,l:"advanced/global.html#mobile-dbclick-play",a:"mobile-dbclick-play"},"3.20":{t:"MOBILE_CLICK_PLAY",p:`在移动端,是否单击切换播放暂停,默认为 false -<div className="run-code&quo ...`,l:"advanced/global.html#mobile-click-play",a:"mobile-click-play"},"3.21":{t:"AUTO_ORIENTATION_TIME",p:`在移动端,自动旋屏的延迟时间,单位为毫秒,默认为 200 -<div className="run-code& ...`,l:"advanced/global.html#auto-orientation-time",a:"auto-orientation-time"},"3.22":{t:"INFO_LOOP_TIME",p:`信息面板的刷新时间,单位为毫秒,默认为 1000 -<div className="run-code" ...`,l:"advanced/global.html#info-loop-time",a:"info-loop-time"},"3.23":{t:"FAST_FORWARD_VALUE",p:`在移动端,长按加速的速率倍数,默认为 3 -<div className="run-code"> ...`,l:"advanced/global.html#fast-forward-value",a:"fast-forward-value"},"3.24":{t:"FAST_FORWARD_TIME",p:`在移动端,长按加速的延迟时间,单位为毫秒,默认为 1000 -<div className="run-code ...`,l:"advanced/global.html#fast-forward-time",a:"fast-forward-time"},"3.25":{t:"TOUCH_MOVE_RATIO",p:`在移动端,左右滑动进度的速率倍数,默认为 0.5 -<div className="run-code" ...`,l:"advanced/global.html#touch-move-ratio",a:"touch-move-ratio"},"3.26":{t:"VOLUME_STEP",p:`快捷键调节音量的幅度比例,默认为 0.1 -<div className="run-code"> ...`,l:"advanced/global.html#volume-step",a:"volume-step"},"3.27":{t:"SEEK_STEP",p:`快捷键调节播放进度的幅度,单位为秒,默认为 5 -<div className="run-code" ...`,l:"advanced/global.html#seek-step",a:"seek-step"},"3.28":{t:"PLAYBACK_RATE",p:`内置播放速率的列表,默认为 [0.5, 0.75, 1, 1.25, 1.5, 2] -<div className=& ...`,l:"advanced/global.html#playback-rate",a:"playback-rate"},"3.29":{t:"ASPECT_RATIO",p:`内置视频长宽比的列表,默认为 ['default', '4:3', '16:9'] -<div className=&q ...`,l:"advanced/global.html#aspect-ratio",a:"aspect-ratio"},"3.30":{t:"FLIP",p:`内置视频翻转的列表,默认为 ['normal', 'horizontal', 'vertical'] -<div cla ...`,l:"advanced/global.html#flip",a:"flip"},"3.31":{t:"FULLSCREEN_WEB_IN_BODY",p:`网页全屏时,是否把播放器挂在在 body 元素下,默认为 true -<div className="run- ...`,l:"advanced/global.html#fullscreen-web-in-body",a:"fullscreen-web-in-body"},"3.32":{t:"LOG_VERSION",p:`设置是否打印播放器版本,默认为 true -<div className="run-code"> ...`,l:"advanced/global.html#log-version",a:"log-version"},"3.33":{t:"USE_RAF",p:`设置是否使用 requestAnimationFrame ,默认为 false,目前主要用于进度条的平滑效果 -<div ...`,l:"advanced/global.html#use-raf",a:"use-raf"},"3.34":{t:"REMOVE_SRC_WHEN_DESTROY",p:`在销毁播放器时,是否同时移除视频的 src 属性并调用 load() 以主动释放媒体资源,默认为 true。 -开启后可以在单 ...`,l:"advanced/global.html#remove-src-when-destroy",a:"remove-src-when-destroy"},"4.0":{t:"# 编写插件",p:`但你已经知道播放器的属性, 方法和事件后,再编写插件是非常简单的事 -可以在实例化的时候加载插件的函数 -<div cla ...`,l:"advanced/plugin.html",a:"编写插件"},"5.0":{t:"# 实例属性",p:`这里的 实例属性 是指挂载在 实例 的 一级属性,比较常用 -`,l:"advanced/property.html",a:"实例属性"},"5.1":{t:"`play`",p:` -Type: Function - -播放视频 -<div className="run-code"&g ...`,l:"advanced/property.html#play",a:"play"},"5.2":{t:"`pause`",p:` -Type: Function - -暂停视频 -<div className="run-code"&g ...`,l:"advanced/property.html#pause",a:"pause"},"5.3":{t:"`toggle`",p:` -Type: Function - -切换视频的播放和暂停 -<div className="run-code&q ...`,l:"advanced/property.html#toggle",a:"toggle"},"5.4":{t:"`destroy`",p:` -Type: Function -Parameter: Boolean - -销毁播放器,接受一个参数表示是否销毁后同时移除播放器 ...`,l:"advanced/property.html#destroy",a:"destroy"},"5.5":{t:"`reset`",p:` -Type: Function - -重置播放器的视频元素:会移除当前 src 并调用一次 load(),常用于在单页应用中手动 ...`,l:"advanced/property.html#reset",a:"reset"},"5.6":{t:"`seek`",p:` -Type: Setter -Parameter: Number - -视频时间跳转,单位秒 -<div className= ...`,l:"advanced/property.html#seek",a:"seek"},"5.7":{t:"`forward`",p:` -Type: Setter -Parameter: Number - -视频时间快进,单位秒 -<div className= ...`,l:"advanced/property.html#forward",a:"forward"},"5.8":{t:"`backward`",p:` -Type: Setter -Parameter: Number - -视频时间快退,单位秒 -<div className= ...`,l:"advanced/property.html#backward",a:"backward"},"5.9":{t:"`volume`",p:` -Type: Setter/Getter -Parameter: Number - -设置和获取视频音量,范围在:[0, 1] -& ...`,l:"advanced/property.html#volume",a:"volume"},"5.10":{t:"`url`",p:` -Type: Setter/Getter -Parameter: String - -设置和获取视频地址 -<div clas ...`,l:"advanced/property.html#url",a:"url"},"5.11":{t:"`switch`",p:` -Type: Setter -Parameter: String - -设置视频地址,设置时和 art.url 类似,但会执行一些 ...`,l:"advanced/property.html#switch",a:"switch"},"5.12":{t:"`switchUrl`",p:` -Type: Function -Parameter: String - -设置视频地址,设置时和 art.url 类似,但会执行 ...`,l:"advanced/property.html#switchurl",a:"switchurl"},"5.13":{t:"`switchQuality`",p:` -Type: Function -Parameter: String - -设置视频画质地址,和 art.switchUrl 类似 ...`,l:"advanced/property.html#switchquality",a:"switchquality"},"5.14":{t:"`muted`",p:` -Type: Setter/Getter -Parameter: Boolean - -设置和获取视频是否静音 -<div c ...`,l:"advanced/property.html#muted",a:"muted"},"5.15":{t:"`currentTime`",p:` -Type: Setter/Getter -Parameter: Number - -设置和获取视频当前时间,设置时间时和 see ...`,l:"advanced/property.html#currenttime",a:"currenttime"},"5.16":{t:"`duration`",p:` -Type: Getter - -获取视频时长 -<div className="run-code"&g ...`,l:"advanced/property.html#duration",a:"duration"},"5.17":{t:"`screenshot`",p:` -Type: Function - -下载当前视频帧的截图, 可选参数为截图名字 -<div className=" ...`,l:"advanced/property.html#screenshot",a:"screenshot"},"5.18":{t:"`getDataURL`",p:` -Type: Function - -获取当前视频帧的截图的base64地址,返回的是一个 Promise -<div cl ...`,l:"advanced/property.html#getdataurl",a:"getdataurl"},"5.19":{t:"`getBlobUrl`",p:` -Type: Function - -获取当前视频帧的截图的blob地址,返回的是一个 Promise -<div clas ...`,l:"advanced/property.html#getbloburl",a:"getbloburl"},"5.20":{t:"`fullscreen`",p:` -Type: Setter/Getter -Parameter: Boolean - -设置和获取播放器窗口全屏 -<div ...`,l:"advanced/property.html#fullscreen",a:"fullscreen"},"5.21":{t:"`fullscreenWeb`",p:` -Type: Setter/Getter -Parameter: Boolean - -设置和获取播放器网页全屏 -<div ...`,l:"advanced/property.html#fullscreenweb",a:"fullscreenweb"},"5.22":{t:"`pip`",p:` -Type: Setter/Getter -Parameter: Boolean - -设置和获取播放器画中画模式 -<div ...`,l:"advanced/property.html#pip",a:"pip"},"5.23":{t:"`poster`",p:` -Type: Setter/Getter -Parameter: String - -设置和获取视频海报,只有在视频播放前才能看到 ...`,l:"advanced/property.html#poster",a:"poster"},"5.24":{t:"`mini`",p:` -Type: Setter/Getter -Parameter: Boolean - -设置和获取播放器迷你模式 -<div ...`,l:"advanced/property.html#mini",a:"mini"},"5.25":{t:"`playing`",p:` -Type: Getter -Parameter: Boolean - -获取视频是否正在播放中 -<div classNam ...`,l:"advanced/property.html#playing",a:"playing"},"5.26":{t:"`state`",p:` -Type: Setter/Getter -Parameter: String - -获取或设置播放器当前状态,支持:standa ...`,l:"advanced/property.html#state",a:"state"},"5.27":{t:"`autoSize`",p:` -Type: Function - -设置视频是否自适应尺寸 -<div className="run-code& ...`,l:"advanced/property.html#autosize",a:"autosize"},"5.28":{t:"`rect`",p:` -Type: Getter - -获取播放器的尺寸和坐标信息 -<div className="run-code& ...`,l:"advanced/property.html#rect",a:"rect"},"5.29":{t:"`bottom` / `top` / `left` / `right` / `x` / `y` / `width` / `height`",p:` -Type: Getter - -这些属性是对 rect 的快捷访问: - -bottom, top, left, right, x ...`,l:"advanced/property.html#bottom-top-left-right-x-y-width-height",a:"bottom-top-left-right-x-y-width-height"},"5.30":{t:"`flip`",p:` -Type: Setter/Getter -Parameter: String - -设置和获取播放器翻转,支持normal, ...`,l:"advanced/property.html#flip",a:"flip"},"5.31":{t:"`playbackRate`",p:` -Type: Setter/Getter -Parameter: Number - -设置和获取播放器播放速度 -<div c ...`,l:"advanced/property.html#playbackrate",a:"playbackrate"},"5.32":{t:"`aspectRatio`",p:` -Type: Setter/Getter -Parameter: String - -设置和获取播放器长宽比 -<div cl ...`,l:"advanced/property.html#aspectratio",a:"aspectratio"},"5.33":{t:"`autoHeight`",p:` -Type: Function - -当容器只有宽度,该属性可以自动计算出并设置视频的高度 -<div className= ...`,l:"advanced/property.html#autoheight",a:"autoheight"},"5.34":{t:"`attr`",p:` -Type: Function -Parameter: String - -动态获取和设置 video 元素的属性 -<div ...`,l:"advanced/property.html#attr",a:"attr"},"5.35":{t:"`type`",p:` -Type: Setter/Getter -Parameter: String - -动态获取和设置视频类型 -<div cl ...`,l:"advanced/property.html#type",a:"type"},"5.36":{t:"`theme`",p:` -Type: Setter/Getter -Parameter: String - -动态获取和设置播放器主题颜色 -<div ...`,l:"advanced/property.html#theme",a:"theme"},"5.37":{t:"`airplay`",p:` -Type: Function - -开启隔空播放 -<div className="run-code" ...`,l:"advanced/property.html#airplay",a:"airplay"},"5.38":{t:"`loaded`",p:` -Type: Getter - -视频缓存的比例,范围是 [0, 1],常配合 video:timeupdate 事件使用 -&l ...`,l:"advanced/property.html#loaded",a:"loaded"},"5.39":{t:"`loadedTime`",p:` -Type: Getter - -已缓存的媒体时长,单位为秒。通常与 loaded 一起使用,用于展示缓冲进度细节。 -<d ...`,l:"advanced/property.html#loadedtime",a:"loadedtime"},"5.40":{t:"`played`",p:` -Type: Getter - -视频播放的比例,范围是 [0, 1],常配合 video:timeupdate 事件使用 -&l ...`,l:"advanced/property.html#played",a:"played"},"5.41":{t:"`proxy`",p:` -Type: Function - -DOM 事件的代理函数,实质上代理了 addEventListener 和 removeE ...`,l:"advanced/property.html#proxy",a:"proxy"},"5.42":{t:"`query`",p:` -Type: Function - -DOM 的查询函数,类似 document.querySelector,但被查询的对象局限 ...`,l:"advanced/property.html#query",a:"query"},"5.43":{t:"`video`",p:` -Type: Element - -快捷返回播放器的 video 元素 -<div className="run- ...`,l:"advanced/property.html#video",a:"video"},"5.44":{t:"`cssVar`",p:` -Type: Function - -动态获取或设置 css 变量 -<div className="run-co ...`,l:"advanced/property.html#cssvar",a:"cssvar"},"5.45":{t:"`quality`",p:` -Type: Setter -Parameter: Array - -动态设置画质列表 -<div className=&qu ...`,l:"advanced/property.html#quality",a:"quality"},"5.46":{t:"`thumbnails`",p:` -Type: Setter/Getter -Parameter: Object - -动态设置缩略图 -<div classN ...`,l:"advanced/property.html#thumbnails",a:"thumbnails"},"5.47":{t:"`subtitleOffset`",p:` -Type: Setter/Getter -Parameter: Number - -动态设置字幕偏移 -<div class ...`,l:"advanced/property.html#subtitleoffset",a:"subtitleoffset"},"6.0":{t:"# 右键菜单",p:"",l:"component/contextmenu.html",a:"右键菜单"},"6.1":{t:"配置",p:` - - -属性 -类型 -描述 - - - - -disable -Boolean -是否禁用组件 - - -name -String -组件唯一名称,用于 ...`,l:"component/contextmenu.html#配置",a:"配置"},"6.2":{t:"创建",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/contextmenu.html#创建",a:"创建"},"6.3":{t:"添加",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/contextmenu.html#添加",a:"添加"},"6.4":{t:"删除",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/contextmenu.html#删除",a:"删除"},"6.5":{t:"更新",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/contextmenu.html#更新",a:"更新"},"7.0":{t:"# 控制器",p:"",l:"component/controls.html",a:"控制器"},"7.1":{t:"配置",p:` - - -属性 -类型 -描述 - - - - -disable -Boolean -是否禁用组件 - - -name -String -组件唯一名称,用于 ...`,l:"component/controls.html#配置",a:"配置"},"7.2":{t:"创建",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/controls.html#创建",a:"创建"},"7.3":{t:"添加",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/controls.html#添加",a:"添加"},"7.4":{t:"删除",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/controls.html#删除",a:"删除"},"7.5":{t:"更新",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/controls.html#更新",a:"更新"},"8.0":{t:"# 业务层",p:"",l:"component/layers.html",a:"业务层"},"8.1":{t:"配置",p:` - - -属性 -类型 -描述 - - - - -disable -Boolean -是否禁用组件 - - -name -String -组件唯一名称,用于 ...`,l:"component/layers.html#配置",a:"配置"},"8.2":{t:"创建",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/layers.html#创建",a:"创建"},"8.3":{t:"添加",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/layers.html#添加",a:"添加"},"8.4":{t:"删除",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/layers.html#删除",a:"删除"},"8.5":{t:"更新",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/layers.html#更新",a:"更新"},"9.0":{t:"# 设置面板",p:"",l:"component/setting.html",a:"设置面板"},"9.1":{t:"内置",p:"须先打开设置面板,然后自带四个内置项:flip, playbackRate, aspectRatio, subtitleOf ...",l:"component/setting.html#内置",a:"内置"},"9.2":{t:"创建 - 按钮",p:` - - -属性 -类型 -描述 - - - - -html -String, Element -元素的 DOM - - -icon -String, El ...`,l:"component/setting.html#创建-按钮",a:"创建-按钮"},"9.3":{t:"创建 - 选择列表",p:` - - -属性 -类型 -描述 - - - - -html -String, Element -元素的 DOM - - -icon -String, El ...`,l:"component/setting.html#创建-选择列表",a:"创建-选择列表"},"9.4":{t:"创建 - 列表嵌套",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/setting.html#创建-列表嵌套",a:"创建-列表嵌套"},"9.5":{t:"创建 - 切换按钮",p:` - - -属性 -类型 -描述 - - - - -html -String, Element -元素的 DOM 元素 - - -icon -String, ...`,l:"component/setting.html#创建-切换按钮",a:"创建-切换按钮"},"9.6":{t:"创建 - 范围滑块",p:` - - -属性 -类型 -描述 - - - - -html -String, Element -元素的 DOM 元素 - - -icon -String, ...`,l:"component/setting.html#创建-范围滑块",a:"创建-范围滑块"},"9.7":{t:"添加",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/setting.html#添加",a:"添加"},"9.8":{t:"删除",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/setting.html#删除",a:"删除"},"9.9":{t:"更新",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/setting.html#更新",a:"更新"},"10.0":{t:"# Advanced Properties",p:"The Advanced Properties here refer to the secondary properties ...",l:"en/advanced/built-in.html",a:"advanced-properties"},"10.1":{t:"`option`",p:`The player's options. -<div className="run-code"&g ...`,l:"en/advanced/built-in.html#option",a:"option"},"10.2":{t:"`template`",p:`Manages all DOM elements of the player. -<div className=&quo ...`,l:"en/advanced/built-in.html#template",a:"template"},"10.3":{t:"`events`",p:"Manages all DOM events for the player. It essentially proxies ...",l:"en/advanced/built-in.html#events",a:"events"},"10.4":{t:"`storage`",p:`Manages the player's local storage. - -The name property is used ...`,l:"en/advanced/built-in.html#storage",a:"storage"},"10.5":{t:"`icons`",p:`Manages all svg icons for the player. -<div className=" ...`,l:"en/advanced/built-in.html#icons",a:"icons"},"10.6":{t:"`i18n`",p:`Manages the player's i18n. - -The get method is used to retrieve ...`,l:"en/advanced/built-in.html#i18n",a:"i18n"},"10.7":{t:"`notice`",p:"Manages the player's notifications. It only has a show propert ...",l:"en/advanced/built-in.html#notice",a:"notice"},"10.8":{t:"`layers`",p:`Manages the player's layers. - -The add method is used to dynami ...`,l:"en/advanced/built-in.html#layers",a:"layers"},"10.9":{t:"`controls`",p:`Manages the player's controls. - - -The add method is used to dyn ...`,l:"en/advanced/built-in.html#controls",a:"controls"},"10.10":{t:"`contextmenu`",p:`Manages the player's context menu - -The add method is used to d ...`,l:"en/advanced/built-in.html#contextmenu",a:"contextmenu"},"10.11":{t:"`subtitle`",p:`Manages the player's subtitle functionality - -The url property ...`,l:"en/advanced/built-in.html#subtitle",a:"subtitle"},"10.12":{t:"`info`",p:"Manages the player's information panel, commonly used to view ...",l:"en/advanced/built-in.html#info",a:"info"},"10.13":{t:"`loading`",p:`Manages the player's loading layer - -The show property is used ...`,l:"en/advanced/built-in.html#loading",a:"loading"},"10.14":{t:"`hotkey`",p:`Manages the player's hotkey functionality - -The add method is u ...`,l:"en/advanced/built-in.html#hotkey",a:"hotkey"},"10.15":{t:"`mask`",p:`Manages the player's mask layer - -The show property is used to ...`,l:"en/advanced/built-in.html#mask",a:"mask"},"10.16":{t:"`setting`",p:`Manages the player's settings panel - -The add method is used to ...`,l:"en/advanced/built-in.html#setting",a:"setting"},"10.17":{t:"`plugins`",p:"Manages the player's plugin functionality, with only one metho ...",l:"en/advanced/built-in.html#plugins",a:"plugins"},"11.0":{t:"# Static Properties",p:"Here, static properties refer to the first-level properties at ...",l:"en/advanced/class.html",a:"static-properties"},"11.1":{t:"`instances`",p:"Returns an array of all player instances. This property can be ...",l:"en/advanced/class.html#instances",a:"instances"},"11.2":{t:"`version`",p:`Returns the version information of the player. -<div classNa ...`,l:"en/advanced/class.html#version",a:"version"},"11.3":{t:"`env`",p:`Returns the environment variables of the player. -<div class ...`,l:"en/advanced/class.html#env",a:"env"},"11.4":{t:"`build`",p:`Returns the build timestamp of the player. -<div className=& ...`,l:"en/advanced/class.html#build",a:"build"},"11.5":{t:"`config`",p:`Returns the default configuration for videos. -<div classNam ...`,l:"en/advanced/class.html#config",a:"config"},"11.6":{t:"`utils`",p:`Returns the collection of utility functions for the player. -&l ...`,l:"en/advanced/class.html#utils",a:"utils"},"11.7":{t:"`scheme`",p:`Returns the validation schema for player options. -<div clas ...`,l:"en/advanced/class.html#scheme",a:"scheme"},"11.8":{t:"`Emitter`",p:`Returns the constructor of the event emitter. -<div classNam ...`,l:"en/advanced/class.html#emitter",a:"emitter"},"11.9":{t:"`validator`",p:`Returns the validation function for options. -<div className ...`,l:"en/advanced/class.html#validator",a:"validator"},"11.10":{t:"`kindOf`",p:`Returns the type detection utility function. -<div className ...`,l:"en/advanced/class.html#kindof",a:"kindof"},"11.11":{t:"`html`",p:`Returns the html string required by the player. -<div classN ...`,l:"en/advanced/class.html#html",a:"html"},"11.12":{t:"`option`",p:`Returns the default options of the player. -<div className=& ...`,l:"en/advanced/class.html#option",a:"option"},"12.0":{t:"# Instance Events",p:"Player events are divided into two types: native events of the ...",l:"en/advanced/event.html",a:"instance-events"},"12.1":{t:"`ready`",p:`Triggered when the player is ready for the first time. -<div ...`,l:"en/advanced/event.html#ready",a:"ready"},"12.2":{t:"`restart`",p:"Triggered when the player switches URLs and becomes ready to p ...",l:"en/advanced/event.html#restart",a:"restart"},"12.3":{t:"`pause`",p:`Triggered when the player is paused. -<div className="r ...`,l:"en/advanced/event.html#pause",a:"pause"},"12.4":{t:"`play`",p:`Triggered when the player starts playing. -<div className=&q ...`,l:"en/advanced/event.html#play",a:"play"},"12.5":{t:"`hotkey`",p:`Triggered when a player hotkey is pressed. -<div className=& ...`,l:"en/advanced/event.html#hotkey",a:"hotkey"},"12.6":{t:"`destroy`",p:`Triggered when the player is destroyed. -<div className=&quo ...`,l:"en/advanced/event.html#destroy",a:"destroy"},"12.7":{t:"`focus`",p:`Triggered when the player gains focus. -<div className=" ...`,l:"en/advanced/event.html#focus",a:"focus"},"12.8":{t:"`blur`",p:`Triggered when the player loses focus. -<div className=" ...`,l:"en/advanced/event.html#blur",a:"blur"},"12.9":{t:"`dblclick`",p:`Triggered when the player is double-clicked. -<div className ...`,l:"en/advanced/event.html#dblclick",a:"dblclick"},"12.10":{t:"`click`",p:`Triggered when the player is clicked. -<div className=" ...`,l:"en/advanced/event.html#click",a:"click"},"12.11":{t:"`error`",p:"Triggered when an error occurs while the player is loading a v ...",l:"en/advanced/event.html#error",a:"error"},"12.12":{t:"`hover`",p:`Triggered when the mouse enters or leaves the player. -<div ...`,l:"en/advanced/event.html#hover",a:"hover"},"12.13":{t:"`mousemove`",p:`Triggered when the mouse moves over the player. -<div classN ...`,l:"en/advanced/event.html#mousemove",a:"mousemove"},"12.14":{t:"`resize`",p:`Triggered when the player's dimensions change. -<div classNa ...`,l:"en/advanced/event.html#resize",a:"resize"},"12.15":{t:"`view`",p:`Triggered when the player enters the viewport. -<div classNa ...`,l:"en/advanced/event.html#view",a:"view"},"12.16":{t:"`lock`",p:`Triggered when the lock state changes on mobile devices. -<d ...`,l:"en/advanced/event.html#lock",a:"lock"},"12.17":{t:"`aspectRatio`",p:`Triggered when the player's aspect ratio changes. -<div clas ...`,l:"en/advanced/event.html#aspectratio",a:"aspectratio"},"12.18":{t:"`autoHeight`",p:`Triggered when the player's height is automatically set. -<d ...`,l:"en/advanced/event.html#autoheight",a:"autoheight"},"12.19":{t:"`autoSize`",p:`Triggered when the player's size is automatically set. -<div ...`,l:"en/advanced/event.html#autosize",a:"autosize"},"12.20":{t:"`flip`",p:`Triggered when the player is flipped. -<div className=" ...`,l:"en/advanced/event.html#flip",a:"flip"},"12.21":{t:"`fullscreen`",p:"Triggered when the player enters or exits windowed fullscreen ...",l:"en/advanced/event.html#fullscreen",a:"fullscreen"},"12.22":{t:"`fullscreenError`",p:`Triggered when a windowed fullscreen error occurs. -<div cla ...`,l:"en/advanced/event.html#fullscreenerror",a:"fullscreenerror"},"12.23":{t:"`fullscreenWeb`",p:"Triggered when the player enters or exits web fullscreen mode. ...",l:"en/advanced/event.html#fullscreenweb",a:"fullscreenweb"},"12.24":{t:"`mini`",p:`Triggered when the player enters or exits mini mode. -<div c ...`,l:"en/advanced/event.html#mini",a:"mini"},"12.25":{t:"`pip`",p:"Triggered when the player enters or exits Picture-in-Picture m ...",l:"en/advanced/event.html#pip",a:"pip"},"12.26":{t:"`screenshot`",p:`Triggered when the player takes a screenshot. -<div classNam ...`,l:"en/advanced/event.html#screenshot",a:"screenshot"},"12.27":{t:"`seek`",p:`Triggered when the player performs a time seek. -<div classN ...`,l:"en/advanced/event.html#seek",a:"seek"},"12.28":{t:"`subtitleOffset`",p:`Triggered when the subtitle offset changes in the player. -< ...`,l:"en/advanced/event.html#subtitleoffset",a:"subtitleoffset"},"12.29":{t:"`subtitleBeforeUpdate`",p:`Triggered before subtitles are updated. -<div className=&quo ...`,l:"en/advanced/event.html#subtitlebeforeupdate",a:"subtitlebeforeupdate"},"12.30":{t:"`subtitleAfterUpdate`",p:`Triggered after subtitles are updated. -<div className=" ...`,l:"en/advanced/event.html#subtitleafterupdate",a:"subtitleafterupdate"},"12.31":{t:"`subtitleLoad`",p:`Triggered when subtitles are loaded. -<div className="r ...`,l:"en/advanced/event.html#subtitleload",a:"subtitleload"},"12.32":{t:"`info`",p:`Triggered when the info panel is shown or hidden. -<div clas ...`,l:"en/advanced/event.html#info",a:"info"},"12.33":{t:"`layer`",p:`Triggered when a custom layer is shown or hidden. -<div clas ...`,l:"en/advanced/event.html#layer",a:"layer"},"12.34":{t:"`loading`",p:`Triggered when the loader is shown or hidden. -<div classNam ...`,l:"en/advanced/event.html#loading",a:"loading"},"12.35":{t:"`mask`",p:`Triggered when the mask layer is shown or hidden. -<div clas ...`,l:"en/advanced/event.html#mask",a:"mask"},"12.36":{t:"`subtitle`",p:`Triggered when the subtitle layer is shown or hidden. -<div ...`,l:"en/advanced/event.html#subtitle",a:"subtitle"},"12.37":{t:"`contextmenu`",p:`Triggered when the context menu is shown or hidden. -<div cl ...`,l:"en/advanced/event.html#contextmenu",a:"contextmenu"},"12.38":{t:"`control`",p:`Triggered when the control bar is shown or hidden. -<div cla ...`,l:"en/advanced/event.html#control",a:"control"},"12.39":{t:"`setting`",p:`Triggered when the settings panel is shown or hidden. -<div ...`,l:"en/advanced/event.html#setting",a:"setting"},"12.40":{t:"`muted`",p:`Triggered when the muted state changes. -<div className=&quo ...`,l:"en/advanced/event.html#muted",a:"muted"},"12.41":{t:"`keydown`",p:`Listens for the keydown event from the document. -<div class ...`,l:"en/advanced/event.html#keydown",a:"keydown"},"12.42":{t:"`video:canplay`",p:"The browser can start playing the media, but estimates there i ...",l:"en/advanced/event.html#video-canplay",a:"video-canplay"},"12.43":{t:"`video:canplaythrough`",p:"The browser estimates it can play the media through to the end ...",l:"en/advanced/event.html#video-canplaythrough",a:"video-canplaythrough"},"12.44":{t:"`video:complete`",p:`The OfflineAudioContext rendering is complete. -`,l:"en/advanced/event.html#video-complete",a:"video-complete"},"12.45":{t:"`video:durationchange`",p:`Triggered when the value of the duration property changes. -`,l:"en/advanced/event.html#video-durationchange",a:"video-durationchange"},"12.46":{t:"`video:emptied`",p:"The media has become empty; for example, this event is sent wh ...",l:"en/advanced/event.html#video-emptied",a:"video-emptied"},"12.47":{t:"`video:ended`",p:`Playback has stopped because the media has reached its end. -`,l:"en/advanced/event.html#video-ended",a:"video-ended"},"12.48":{t:"`video:error`",p:"An error occurred while fetching the media data, or the resour ...",l:"en/advanced/event.html#video-error",a:"video-error"},"12.49":{t:"`video:loadeddata`",p:`The first frame of the media has finished loading. -`,l:"en/advanced/event.html#video-loadeddata",a:"video-loadeddata"},"12.50":{t:"`video:loadedmetadata`",p:`Metadata has been loaded. -`,l:"en/advanced/event.html#video-loadedmetadata",a:"video-loadedmetadata"},"12.51":{t:"`video:pause`",p:`Playback has been paused. -`,l:"en/advanced/event.html#video-pause",a:"video-pause"},"12.52":{t:"`video:play`",p:`Playback has begun. -`,l:"en/advanced/event.html#video-play",a:"video-play"},"12.53":{t:"`video:playing`",p:"Playback is ready to start after having been paused or delayed ...",l:"en/advanced/event.html#video-playing",a:"video-playing"},"12.54":{t:"`video:progress`",p:`Fired periodically as the browser loads the resource. -`,l:"en/advanced/event.html#video-progress",a:"video-progress"},"12.55":{t:"`video:ratechange`",p:`The playback rate has changed. -`,l:"en/advanced/event.html#video-ratechange",a:"video-ratechange"},"12.56":{t:"`video:seeked`",p:`A seek operation has completed. -`,l:"en/advanced/event.html#video-seeked",a:"video-seeked"},"12.57":{t:"`video:seeking`",p:`A seek operation has begun. -`,l:"en/advanced/event.html#video-seeking",a:"video-seeking"},"12.58":{t:"`video:stalled`",p:"The user agent is trying to fetch media data, but data is unex ...",l:"en/advanced/event.html#video-stalled",a:"video-stalled"},"12.59":{t:"`video:suspend`",p:`Media data loading has been suspended. -`,l:"en/advanced/event.html#video-suspend",a:"video-suspend"},"12.60":{t:"`video:timeupdate`",p:`The time indicated by the currentTime property has changed. -`,l:"en/advanced/event.html#video-timeupdate",a:"video-timeupdate"},"12.61":{t:"`video:volumechange`",p:`The volume has changed. -`,l:"en/advanced/event.html#video-volumechange",a:"video-volumechange"},"12.62":{t:"`video:waiting`",p:`Playback has stopped because of a temporary lack of data. -`,l:"en/advanced/event.html#video-waiting",a:"video-waiting"},"13.0":{t:"# Global Properties",p:"The global properties here refer to the top-level properties m ...",l:"en/advanced/global.html",a:"global-properties"},"13.1":{t:"DEBUG",p:"Whether to enable debug mode, which can print all built-in vid ...",l:"en/advanced/global.html#debug",a:"debug"},"13.2":{t:"STYLE",p:`Returns the player style text. -<div className="run-cod ...`,l:"en/advanced/global.html#style",a:"style"},"13.3":{t:"CONTEXTMENU",p:`Whether to enable the context menu. Default is on. -<div cla ...`,l:"en/advanced/global.html#contextmenu",a:"contextmenu"},"13.4":{t:"NOTICE_TIME",p:"The display duration of notification messages, in milliseconds ...",l:"en/advanced/global.html#notice-time",a:"notice-time"},"13.5":{t:"SETTING_WIDTH",p:"The default width of the settings panel, in pixels. Default is ...",l:"en/advanced/global.html#setting-width",a:"setting-width"},"13.6":{t:"SETTING_ITEM_WIDTH",p:"The default width of a setting item in the settings panel, in ...",l:"en/advanced/global.html#setting-item-width",a:"setting-item-width"},"13.7":{t:"SETTING_ITEM_HEIGHT",p:"The default height of a setting item in the settings panel, in ...",l:"en/advanced/global.html#setting-item-height",a:"setting-item-height"},"13.8":{t:"RESIZE_TIME",p:"The throttle time for the resize event, in milliseconds. Defau ...",l:"en/advanced/global.html#resize-time",a:"resize-time"},"13.9":{t:"SCROLL_TIME",p:"The throttle time for the scroll event, in milliseconds. Defau ...",l:"en/advanced/global.html#scroll-time",a:"scroll-time"},"13.10":{t:"SCROLL_GAP",p:"The boundary tolerance distance for the view event, in pixels. ...",l:"en/advanced/global.html#scroll-gap",a:"scroll-gap"},"13.11":{t:"AUTO_PLAYBACK_MAX",p:"The maximum record count for the auto-playback feature. Defaul ...",l:"en/advanced/global.html#auto-playback-max",a:"auto-playback-max"},"13.12":{t:"AUTO_PLAYBACK_MIN",p:"The minimum record duration for the auto-playback feature, in ...",l:"en/advanced/global.html#auto-playback-min",a:"auto-playback-min"},"13.13":{t:"AUTO_PLAYBACK_TIMEOUT",p:"The hide delay duration for the auto-playback feature, in mill ...",l:"en/advanced/global.html#auto-playback-timeout",a:"auto-playback-timeout"},"13.14":{t:"RECONNECT_TIME_MAX",p:"The maximum number of automatic reconnection attempts when a c ...",l:"en/advanced/global.html#reconnect-time-max",a:"reconnect-time-max"},"13.15":{t:"RECONNECT_SLEEP_TIME",p:"The delay time for automatic reconnection when a connection er ...",l:"en/advanced/global.html#reconnect-sleep-time",a:"reconnect-sleep-time"},"13.16":{t:"CONTROL_HIDE_TIME",p:"The auto-hide delay time for the bottom control bar, in millis ...",l:"en/advanced/global.html#control-hide-time",a:"control-hide-time"},"13.17":{t:"DBCLICK_TIME",p:"The delay time for the double-click event, in milliseconds. De ...",l:"en/advanced/global.html#dbclick-time",a:"dbclick-time"},"13.18":{t:"DBCLICK_FULLSCREEN",p:"On desktop, whether double-click toggles fullscreen. Default i ...",l:"en/advanced/global.html#dbclick-fullscreen",a:"dbclick-fullscreen"},"13.19":{t:"MOBILE_DBCLICK_PLAY",p:"On mobile, whether double-click toggles play/pause. Default is ...",l:"en/advanced/global.html#mobile-dbclick-play",a:"mobile-dbclick-play"},"13.20":{t:"MOBILE_CLICK_PLAY",p:"On mobile, whether single-click toggles play/pause. Default is ...",l:"en/advanced/global.html#mobile-click-play",a:"mobile-click-play"},"13.21":{t:"AUTO_ORIENTATION_TIME",p:"On mobile, the delay time for auto-rotation, in milliseconds. ...",l:"en/advanced/global.html#auto-orientation-time",a:"auto-orientation-time"},"13.22":{t:"INFO_LOOP_TIME",p:"The refresh interval for the info panel, in milliseconds. Defa ...",l:"en/advanced/global.html#info-loop-time",a:"info-loop-time"},"13.23":{t:"FAST_FORWARD_VALUE",p:"On mobile, the speed multiplier for long-press fast-forward. D ...",l:"en/advanced/global.html#fast-forward-value",a:"fast-forward-value"},"13.24":{t:"FAST_FORWARD_TIME",p:"On mobile, the delay time for long-press fast-forward, in mill ...",l:"en/advanced/global.html#fast-forward-time",a:"fast-forward-time"},"13.25":{t:"TOUCH_MOVE_RATIO",p:"On mobile, the speed multiplier for left/right swipe to seek. ...",l:"en/advanced/global.html#touch-move-ratio",a:"touch-move-ratio"},"13.26":{t:"VOLUME_STEP",p:"The step size for volume adjustment via keyboard shortcuts. De ...",l:"en/advanced/global.html#volume-step",a:"volume-step"},"13.27":{t:"SEEK_STEP",p:"The step size for seeking via keyboard shortcuts, in seconds. ...",l:"en/advanced/global.html#seek-step",a:"seek-step"},"13.28":{t:"PLAYBACK_RATE",p:"The built-in list of playback rates. Default is [0.5, 0.75, 1, ...",l:"en/advanced/global.html#playback-rate",a:"playback-rate"},"13.29":{t:"ASPECT_RATIO",p:"The built-in list of video aspect ratios. Default is ['default ...",l:"en/advanced/global.html#aspect-ratio",a:"aspect-ratio"},"13.30":{t:"FLIP",p:"The built-in list of video flip options. Default is ['normal', ...",l:"en/advanced/global.html#flip",a:"flip"},"13.31":{t:"FULLSCREEN_WEB_IN_BODY",p:"Whether to mount the player under the body element during web ...",l:"en/advanced/global.html#fullscreen-web-in-body",a:"fullscreen-web-in-body"},"13.32":{t:"LOG_VERSION",p:`Sets whether to print the player version. Default is true. -< ...`,l:"en/advanced/global.html#log-version",a:"log-version"},"13.33":{t:"USE_RAF",p:"Sets whether to use requestAnimationFrame. Default is false. C ...",l:"en/advanced/global.html#use-raf",a:"use-raf"},"13.34":{t:"REMOVE_SRC_WHEN_DESTROY",p:"Whether to remove the video's src attribute and call load() to ...",l:"en/advanced/global.html#remove-src-when-destroy",a:"remove-src-when-destroy"},"14.0":{t:"# Writing Plugins",p:"Once you are familiar with the player's properties, methods, a ...",l:"en/advanced/plugin.html",a:"writing-plugins"},"15.0":{t:"# Instance Properties",p:"Here, Instance Properties refer to the first-level properties ...",l:"en/advanced/property.html",a:"instance-properties"},"15.1":{t:"`play`",p:` -Type: Function - -Play the video. -<div className="run-c ...`,l:"en/advanced/property.html#play",a:"play"},"15.2":{t:"`pause`",p:` -Type: Function - -Pause the video. -<div className="run- ...`,l:"en/advanced/property.html#pause",a:"pause"},"15.3":{t:"`toggle`",p:` -Type: Function - -Toggle video play and pause. -<div classNam ...`,l:"en/advanced/property.html#toggle",a:"toggle"},"15.4":{t:"`destroy`",p:` -Type: Function -Parameter: Boolean - -Destroy the player. Accept ...`,l:"en/advanced/property.html#destroy",a:"destroy"},"15.5":{t:"`reset`",p:` -Type: Function - -Reset the player's video element: removes the ...`,l:"en/advanced/property.html#reset",a:"reset"},"15.6":{t:"`seek`",p:` -Type: Setter -Parameter: Number - -Seek to a specific time in th ...`,l:"en/advanced/property.html#seek",a:"seek"},"15.7":{t:"`forward`",p:` -Type: Setter -Parameter: Number - -Fast-forward the video time, ...`,l:"en/advanced/property.html#forward",a:"forward"},"15.8":{t:"`backward`",p:` -Type: Setter -Parameter: Number - -Rewind the video time, in sec ...`,l:"en/advanced/property.html#backward",a:"backward"},"15.9":{t:"`volume`",p:` -Type: Setter/Getter -Parameter: Number - -Set and get the video ...`,l:"en/advanced/property.html#volume",a:"volume"},"15.10":{t:"`url`",p:` -Type: Setter/Getter -Parameter: String - -Set and get the video ...`,l:"en/advanced/property.html#url",a:"url"},"15.11":{t:"`switch`",p:` -Type: Setter -Parameter: String - -Set the video URL. Similar to ...`,l:"en/advanced/property.html#switch",a:"switch"},"15.12":{t:"`switchUrl`",p:` -Type: Function -Parameter: String - -Set the video URL. Similar ...`,l:"en/advanced/property.html#switchurl",a:"switchurl"},"15.13":{t:"`switchQuality`",p:` -Type: Function -Parameter: String - -Sets the video quality URL. ...`,l:"en/advanced/property.html#switchquality",a:"switchquality"},"15.14":{t:"`muted`",p:` -Type: Setter/Getter -Parameter: Boolean - -Sets or gets whether ...`,l:"en/advanced/property.html#muted",a:"muted"},"15.15":{t:"`currentTime`",p:` -Type: Setter/Getter -Parameter: Number - -Sets or gets the curre ...`,l:"en/advanced/property.html#currenttime",a:"currenttime"},"15.16":{t:"`duration`",p:` -Type: Getter - -Gets the duration of the video. -<div classNa ...`,l:"en/advanced/property.html#duration",a:"duration"},"15.17":{t:"`screenshot`",p:` -Type: Function - -Downloads a screenshot of the current video f ...`,l:"en/advanced/property.html#screenshot",a:"screenshot"},"15.18":{t:"`getDataURL`",p:` -Type: Function - -Gets the base64 URL of a screenshot of the cu ...`,l:"en/advanced/property.html#getdataurl",a:"getdataurl"},"15.19":{t:"`getBlobUrl`",p:` -Type: Function - -Gets the blob URL of a screenshot of the curr ...`,l:"en/advanced/property.html#getbloburl",a:"getbloburl"},"15.20":{t:"`fullscreen`",p:` -Type: Setter/Getter -Parameter: Boolean - -Sets or gets the play ...`,l:"en/advanced/property.html#fullscreen",a:"fullscreen"},"15.21":{t:"`fullscreenWeb`",p:` -Type: Setter/Getter -Parameter: Boolean - -Sets or gets the play ...`,l:"en/advanced/property.html#fullscreenweb",a:"fullscreenweb"},"15.22":{t:"`pip`",p:` -Type: Setter/Getter -Parameter: Boolean - -Sets or gets the play ...`,l:"en/advanced/property.html#pip",a:"pip"},"15.23":{t:"`poster`",p:` -Type: Setter/Getter -Parameter: String - -Sets and gets the vide ...`,l:"en/advanced/property.html#poster",a:"poster"},"15.24":{t:"`mini`",p:` -Type: Setter/Getter -Parameter: Boolean - -Sets and gets the pla ...`,l:"en/advanced/property.html#mini",a:"mini"},"15.25":{t:"`playing`",p:` -Type: Getter -Parameter: Boolean - -Gets whether the video is cu ...`,l:"en/advanced/property.html#playing",a:"playing"},"15.26":{t:"`state`",p:` -Type: Setter/Getter -Parameter: String - -Gets or sets the playe ...`,l:"en/advanced/property.html#state",a:"state"},"15.27":{t:"`autoSize`",p:` -Type: Function - -Sets whether the video adapts its size automa ...`,l:"en/advanced/property.html#autosize",a:"autosize"},"15.28":{t:"`rect`",p:` -Type: Getter - -Gets the player's dimensions and coordinate inf ...`,l:"en/advanced/property.html#rect",a:"rect"},"15.29":{t:"`bottom` / `top` / `left` / `right` / `x` / `y` / `width` / `height`",p:` -Type: Getter - -These properties provide quick access to rect: - ...`,l:"en/advanced/property.html#bottom-top-left-right-x-y-width-height",a:"bottom-top-left-right-x-y-width-height"},"15.30":{t:"`flip`",p:` -Type: Setter/Getter -Parameter: String - -Sets and gets the play ...`,l:"en/advanced/property.html#flip",a:"flip"},"15.31":{t:"`playbackRate`",p:` -Type: Setter/Getter -Parameter: Number - -Sets and gets the play ...`,l:"en/advanced/property.html#playbackrate",a:"playbackrate"},"15.32":{t:"`aspectRatio`",p:` -Type: Setter/Getter -Parameter: String - -Sets and gets the play ...`,l:"en/advanced/property.html#aspectratio",a:"aspectratio"},"15.33":{t:"`autoHeight`",p:` -Type: Function - -When the container only has a defined width, ...`,l:"en/advanced/property.html#autoheight",a:"autoheight"},"15.34":{t:"`attr`",p:` -Type: Function -Parameter: String - -Dynamically get and set att ...`,l:"en/advanced/property.html#attr",a:"attr"},"15.35":{t:"`type`",p:` -Type: Setter/Getter -Parameter: String - -Dynamically get and se ...`,l:"en/advanced/property.html#type",a:"type"},"15.36":{t:"`theme`",p:` -Type: Setter/Getter -Parameter: String - -Dynamically get and se ...`,l:"en/advanced/property.html#theme",a:"theme"},"15.37":{t:"`airplay`",p:` -Type: Function - -Initiate AirPlay. -<div className="run ...`,l:"en/advanced/property.html#airplay",a:"airplay"},"15.38":{t:"`loaded`",p:` -Type: Getter - -The proportion of video buffered, ranging from ...`,l:"en/advanced/property.html#loaded",a:"loaded"},"15.39":{t:"`loadedTime`",p:` -Type: Getter - -The buffered media duration in seconds. Typical ...`,l:"en/advanced/property.html#loadedtime",a:"loadedtime"},"15.40":{t:"`played`",p:` -Type: Getter - -The proportion of video played, ranging from [0 ...`,l:"en/advanced/property.html#played",a:"played"},"15.41":{t:"`proxy`",p:` -Type: Function - -A proxy function for DOM events, essentially ...`,l:"en/advanced/property.html#proxy",a:"proxy"},"15.42":{t:"`query`",p:` -Type: Function - -A DOM query function, similar to document.que ...`,l:"en/advanced/property.html#query",a:"query"},"15.43":{t:"`video`",p:` -Type: Element - -Quickly returns the player's video element. -&l ...`,l:"en/advanced/property.html#video",a:"video"},"15.44":{t:"`cssVar`",p:` -Type: Function - -Dynamically get or set CSS variables. -<div ...`,l:"en/advanced/property.html#cssvar",a:"cssvar"},"15.45":{t:"`quality`",p:` -Type: Setter -Parameter: Array - -Dynamically set the quality li ...`,l:"en/advanced/property.html#quality",a:"quality"},"15.46":{t:"`thumbnails`",p:` -Type: Setter/Getter -Parameter: Object - -Dynamically set thumbn ...`,l:"en/advanced/property.html#thumbnails",a:"thumbnails"},"15.47":{t:"`subtitleOffset`",p:` -Type: Setter/Getter -Parameter: Number - -Dynamically set subtit ...`,l:"en/advanced/property.html#subtitleoffset",a:"subtitleoffset"},"16.0":{t:"# Context Menu",p:"",l:"en/component/contextmenu.html",a:"context-menu"},"16.1":{t:"Configuration",p:` - - -Property -Type -Description - - - - -disable -Boolean -Whether to di ...`,l:"en/component/contextmenu.html#configuration",a:"configuration"},"16.2":{t:"Creation",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/contextmenu.html#creation",a:"creation"},"16.3":{t:"Addition",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/contextmenu.html#addition",a:"addition"},"16.4":{t:"Deletion",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/contextmenu.html#deletion",a:"deletion"},"16.5":{t:"Update",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/contextmenu.html#update",a:"update"},"17.0":{t:"# Controls",p:"",l:"en/component/controls.html",a:"controls"},"17.1":{t:"Configuration",p:` - - -Property -Type -Description - - - - -disable -Boolean -Whether to di ...`,l:"en/component/controls.html#configuration",a:"configuration"},"17.2":{t:"Creation",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/controls.html#creation",a:"creation"},"17.3":{t:"Adding",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/controls.html#adding",a:"adding"},"17.4":{t:"Removal",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/controls.html#removal",a:"removal"},"17.5":{t:"Updating",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/controls.html#updating",a:"updating"},"18.0":{t:"# Layers",p:"",l:"en/component/layers.html",a:"layers"},"18.1":{t:"Configuration",p:` - - -Property -Type -Description - - - - -disable -Boolean -Whether to di ...`,l:"en/component/layers.html#configuration",a:"configuration"},"18.2":{t:"Creation",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/layers.html#creation",a:"creation"},"18.3":{t:"Addition",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/layers.html#addition",a:"addition"},"18.4":{t:"Removal",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/layers.html#removal",a:"removal"},"18.5":{t:"Update",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/layers.html#update",a:"update"},"19.0":{t:"# Settings Panel",p:"",l:"en/component/setting.html",a:"settings-panel"},"19.1":{t:"Built-in",p:"First, you need to open the settings panel. It comes with four ...",l:"en/component/setting.html#built-in",a:"built-in"},"19.2":{t:"Create - Button",p:` - - -Property -Type -Description - - - - -html -String, Element -The DOM ...`,l:"en/component/setting.html#create-button",a:"create-button"},"19.3":{t:"Create - Selection List",p:` - - -Property -Type -Description - - - - -html -String, Element -The DOM ...`,l:"en/component/setting.html#create-selection-list",a:"create-selection-list"},"19.4":{t:"Create - Nested List",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/setting.html#create-nested-list",a:"create-nested-list"},"19.5":{t:"Create - Toggle Button",p:` - - -Property -Type -Description - - - - -html -String, Element -DOM elem ...`,l:"en/component/setting.html#create-toggle-button",a:"create-toggle-button"},"19.6":{t:"Create - Range Slider",p:` - - -Property -Type -Description - - - - -html -String, Element -DOM elem ...`,l:"en/component/setting.html#create-range-slider",a:"create-range-slider"},"19.7":{t:"Add",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/setting.html#add",a:"add"},"19.8":{t:"Remove",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/setting.html#remove",a:"remove"},"19.9":{t:"Update",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/setting.html#update",a:"update"},"20.0":{t:"# Installation and Usage",p:"",l:"en/index.html",a:"installation-and-usage"},"20.1":{t:"Installation",p:`::: code-group -npm install artplayer - -yarn add artplayer - -pnpm ...`,l:"en/index.html#installation",a:"installation"},"20.2":{t:"`CDN`",p:`::: code-group -https://cdn.jsdelivr.net/npm/artplayer/dist/art ...`,l:"en/index.html#cdn",a:"cdn"},"20.3":{t:"Usage",p:`::: code-group -<html> - <head> - <title ...`,l:"en/index.html#usage",a:"usage"},"20.4":{t:"`Vue.js`",p:`::: code-group -<template> - <div ref="$container ...`,l:"en/index.html#vue-js",a:"vue-js"},"20.5":{t:"`React.js`",p:`::: code-group -import Artplayer from 'artplayer' -import { useE ...`,l:"en/index.html#react-js",a:"react-js"},"20.6":{t:"TypeScript",p:"The artplayer.d.ts file is automatically imported when you imp ...",l:"en/index.html#typescript",a:"typescript"},"20.7":{t:"Vue.js",p:` - -`,l:"en/index.html#vue-js",a:"vue-js"},"20.8":{t:"React.js",p:`import Artplayer from 'artplayer'; -const art = useRef<Artpl ...`,l:"en/index.html#react-js",a:"react-js"},"20.9":{t:"Option",p:`You can also use the type for the options. -import Artplayer, { ...`,l:"en/index.html#option",a:"option"},"20.10":{t:"JavaScript",p:"Sometimes your js files may lose TypeScript type hints. In suc ...",l:"en/index.html#javascript",a:"javascript"},"20.11":{t:"Legacy Browsers",p:"The production build artplayer.js only supports the latest maj ...",l:"en/index.html#legacy-browsers",a:"legacy-browsers"},"20.12":{t:"ECMAScript Module",p:`::: tip ESM Demo: -https://artplayer.org/esm.html -::: -Starting ...`,l:"en/index.html#ecmascript-module",a:"ecmascript-module"},"20.13":{t:"Custom userAgent",p:"Currently, the detection of whether a device is mobile is not ...",l:"en/index.html#custom-useragent",a:"custom-useragent"},"21.0":{t:"# Language Settings",p:`::: danger -Due to the increasing number of bundled multilingua ...`,l:"en/start/i18n.html",a:"language-settings"},"21.1":{t:"Default Languages",p:"The default languages are: en, zh-cn. No manual import is requ ...",l:"en/start/i18n.html#default-languages",a:"default-languages"},"21.2":{t:"Importing Languages",p:"Language files before bundling are located at: artplayer/src/i ...",l:"en/start/i18n.html#importing-languages",a:"importing-languages"},"21.3":{t:"Adding a New Language",p:`var art = new Artplayer({ - container: '.artplayer-app', - ...`,l:"en/start/i18n.html#adding-a-new-language",a:"adding-a-new-language"},"21.4":{t:"Modifying a Language",p:`import zhTw from 'artplayer/i18n/zh-tw'; - -var art = new Artpla ...`,l:"en/start/i18n.html#modifying-a-language",a:"modifying-a-language"},"22.0":{t:"# Basic Options",p:"",l:"en/start/option.html",a:"basic-options"},"22.1":{t:"`container`",p:` -Type: String, Element -Default: #artplayer - -The DOM container ...`,l:"en/start/option.html#container",a:"container"},"22.2":{t:"`url`",p:` -Type: String -Default: '' - -The video source URL. -<div class ...`,l:"en/start/option.html#url",a:"url"},"22.3":{t:"`id`",p:` -Type: String -Default: '' - -The unique identifier for the playe ...`,l:"en/start/option.html#id",a:"id"},"22.4":{t:"`onReady`",p:` -Type: Function -Default: undefined - -The constructor accepts a ...`,l:"en/start/option.html#onready",a:"onready"},"22.5":{t:"`poster`",p:` -Type: String -Default: '' - -The video poster image, which only ...`,l:"en/start/option.html#poster",a:"poster"},"22.6":{t:"`theme`",p:` -Type: String -Default: #f00 - -The player's theme color, current ...`,l:"en/start/option.html#theme",a:"theme"},"22.7":{t:"`volume`",p:` -Type: Number -Default: 0.7 - -The player's default volume. -<d ...`,l:"en/start/option.html#volume",a:"volume"},"22.8":{t:"`isLive`",p:` -Type: Boolean -Default: false - -Enable live streaming mode. Thi ...`,l:"en/start/option.html#islive",a:"islive"},"22.9":{t:"`muted`",p:` -Type: Boolean -Default: false - -Whether to start muted by defau ...`,l:"en/start/option.html#muted",a:"muted"},"22.10":{t:"`autoplay`",p:` -Type: Boolean -Default: false - -Whether to autoplay. -<div cl ...`,l:"en/start/option.html#autoplay",a:"autoplay"},"22.11":{t:"`autoSize`",p:` -Type: Boolean -Default: false - -By default, the player's dimens ...`,l:"en/start/option.html#autosize",a:"autosize"},"22.12":{t:"`autoMini`",p:` -Type: Boolean -Default: false - -Automatically enters Mini Playe ...`,l:"en/start/option.html#automini",a:"automini"},"22.13":{t:"`loop`",p:` -Type: Boolean -Default: false - -Whether to loop playback. -<d ...`,l:"en/start/option.html#loop",a:"loop"},"22.14":{t:"`flip`",p:` -Type: Boolean -Default: false - -Whether to display the video fl ...`,l:"en/start/option.html#flip",a:"flip"},"22.15":{t:"`playbackRate`",p:` -Type: Boolean -Default: false - -Whether to display the video pl ...`,l:"en/start/option.html#playbackrate",a:"playbackrate"},"22.16":{t:"`aspectRatio`",p:` -Type: Boolean -Default: false - -Whether to display the video as ...`,l:"en/start/option.html#aspectratio",a:"aspectratio"},"22.17":{t:"`screenshot`",p:` -Type: Boolean -Default: false - -Whether to display the Screensh ...`,l:"en/start/option.html#screenshot",a:"screenshot"},"22.18":{t:"`setting`",p:` -Type: Boolean -Default: false - -Whether to display the toggle b ...`,l:"en/start/option.html#setting",a:"setting"},"22.19":{t:"`hotkey`",p:` -Type: Boolean -Default: true - -Whether to use hotkeys. -<div ...`,l:"en/start/option.html#hotkey",a:"hotkey"},"22.20":{t:"`pip`",p:` -Type: Boolean -Default: false - -Whether to display the Picture- ...`,l:"en/start/option.html#pip",a:"pip"},"22.21":{t:"`mutex`",p:` -Type: Boolean -Default: true - -If multiple players exist on the ...`,l:"en/start/option.html#mutex",a:"mutex"},"22.22":{t:"`backdrop`",p:` -Type: Boolean -Default: true - -Whether to enable the backdrop b ...`,l:"en/start/option.html#backdrop",a:"backdrop"},"22.23":{t:"`fullscreen`",p:` -Type: Boolean -Default: false - -Whether to display the player W ...`,l:"en/start/option.html#fullscreen",a:"fullscreen"},"22.24":{t:"`fullscreenWeb`",p:` -Type: Boolean -Default: false - -Whether to display the player W ...`,l:"en/start/option.html#fullscreenweb",a:"fullscreenweb"},"22.25":{t:"`subtitleOffset`",p:` -Type: Boolean -Default: false - -Subtitle time offset, ranging f ...`,l:"en/start/option.html#subtitleoffset",a:"subtitleoffset"},"22.26":{t:"`miniProgressBar`",p:` -Type: Boolean -Default: false - -A mini progress bar that only a ...`,l:"en/start/option.html#miniprogressbar",a:"miniprogressbar"},"22.27":{t:"`useSSR`",p:` -Type: Boolean -Default: false - -Whether to use SSR (Server-Side ...`,l:"en/start/option.html#usessr",a:"usessr"},"22.28":{t:"`playsInline`",p:` -Type: Boolean -Default: true - -Whether to use playsInline mode ...`,l:"en/start/option.html#playsinline",a:"playsinline"},"22.29":{t:"`layers`",p:` -Type: Array -Default: [] - -Initialize custom layers. -<div cl ...`,l:"en/start/option.html#layers",a:"layers"},"22.30":{t:"`settings`",p:` -Type: Array -Default: [] - -Initialize custom settings panels. -& ...`,l:"en/start/option.html#settings",a:"settings"},"22.31":{t:"`contextmenu`",p:` -Type: Array -Default: [] - -Initialize custom context menus. -< ...`,l:"en/start/option.html#contextmenu",a:"contextmenu"},"22.32":{t:"`controls`",p:` -Type: Array -Default: [] - -Initialize custom bottom control bar ...`,l:"en/start/option.html#controls",a:"controls"},"22.33":{t:"`quality`",p:` -Type: Array -Default: [] - -Whether to display the Quality Selec ...`,l:"en/start/option.html#quality",a:"quality"},"22.34":{t:"`highlight`",p:` -Type: Array -Default: [] - -Display Highlight Information on the ...`,l:"en/start/option.html#highlight",a:"highlight"},"22.35":{t:"`plugins`",p:` -Type: Array -Default: [] - -Initialize custom plugins. -<div c ...`,l:"en/start/option.html#plugins",a:"plugins"},"22.36":{t:"`thumbnails`",p:` -Type: Object -Default: {} - -Set Preview Thumbnails on the progr ...`,l:"en/start/option.html#thumbnails",a:"thumbnails"},"22.37":{t:"`subtitle`",p:` -Type: Object -Default: {} - -Set video subtitles. Supported subt ...`,l:"en/start/option.html#subtitle",a:"subtitle"},"22.38":{t:"`moreVideoAttr`",p:` -Type: Object -Default: {'controls': false, 'preload': 'metadat ...`,l:"en/start/option.html#morevideoattr",a:"morevideoattr"},"22.39":{t:"`icons`",p:` -Type: Object -Default: {} - -Used to replace default icons. Supp ...`,l:"en/start/option.html#icons",a:"icons"},"22.40":{t:"`type`",p:` -Type: String -Default: '' - -Used to specify the video format. I ...`,l:"en/start/option.html#type",a:"type"},"22.41":{t:"`customType`",p:` -Type: Object -Default: {} - -Matches based on the video's type a ...`,l:"en/start/option.html#customtype",a:"customtype"},"22.42":{t:"`lang`",p:` -Type: String -Default: navigator.language.toLowerCase() - -The d ...`,l:"en/start/option.html#lang",a:"lang"},"22.43":{t:"`i18n`",p:` -Type: Object -Default: {} - -Custom i18n configuration. This con ...`,l:"en/start/option.html#i18n",a:"i18n"},"22.44":{t:"`lock`",p:` -Type: Boolean -Default: false - -Whether to display a lock butto ...`,l:"en/start/option.html#lock",a:"lock"},"22.45":{t:"`gesture`",p:` -Type: Boolean -Default: true - -Whether to enable gesture events ...`,l:"en/start/option.html#gesture",a:"gesture"},"22.46":{t:"`fastForward`",p:` -Type: Boolean -Default: false - -Whether to add a long-press vid ...`,l:"en/start/option.html#fastforward",a:"fastforward"},"22.47":{t:"`autoPlayback`",p:` -Type: Boolean -Default: false - -Whether to use the automatic pl ...`,l:"en/start/option.html#autoplayback",a:"autoplayback"},"22.48":{t:"`autoOrientation`",p:` -Type: Boolean -Default: false - -Whether to rotate the player in ...`,l:"en/start/option.html#autoorientation",a:"autoorientation"},"22.49":{t:"`airplay`",p:` -Type: Boolean -Default: false - -Whether to display the airplay ...`,l:"en/start/option.html#airplay",a:"airplay"},"22.50":{t:"`cssVar`",p:` -Type: Object -Default: {} - -Used to modify the built-in CSS var ...`,l:"en/start/option.html#cssvar",a:"cssvar"},"22.51":{t:"`proxy`",p:` -Type: function -Default: undefined - -The function can return a ...`,l:"en/start/option.html#proxy",a:"proxy"},"23.0":{t:"# 安装使用",p:"",l:"index.html",a:"安装使用"},"23.1":{t:"安装",p:`::: code-group -npm install artplayer - -yarn add artplayer - -pnpm ...`,l:"index.html#安装",a:"安装"},"23.2":{t:"`CDN`",p:`::: code-group -https://cdn.jsdelivr.net/npm/artplayer/dist/art ...`,l:"index.html#cdn",a:"cdn"},"23.3":{t:"使用",p:`::: code-group -<html> - <head> - <title ...`,l:"index.html#使用",a:"使用"},"23.4":{t:"`Vue.js`",p:`::: code-group -<template> - <div ref="$container ...`,l:"index.html#vue-js",a:"vue-js"},"23.5":{t:"`React.js`",p:`::: code-group -import Artplayer from 'artplayer' -import { useE ...`,l:"index.html#react-js",a:"react-js"},"23.6":{t:"TypeScript",p:`导入 Artplayer 时会自动导入的 artplayer.d.ts -`,l:"index.html#typescript",a:"typescript"},"23.7":{t:"Vue.js",p:` - -`,l:"index.html#vue-js",a:"vue-js"},"23.8":{t:"React.js",p:`import Artplayer from 'artplayer'; -const art = useRef<Artpl ...`,l:"index.html#react-js",a:"react-js"},"23.9":{t:"Option",p:`你也可以使用选项的类型 -import Artplayer, { type Option } from 'artplayer' ...`,l:"index.html#option",a:"option"},"23.10":{t:"JavaScript",p:`有时你的 js 文件会丢失 TypeScript 的类型提示,这时候你可以手动导入类型 -变量: -/** - * @type { ...`,l:"index.html#javascript",a:"javascript"},"23.11":{t:"古老的浏览器",p:`生产构建的 artplayer.js 只兼容最新一个主版本的 Chrome:last 1 Chrome version -对于 ...`,l:"index.html#古老的浏览器",a:"古老的浏览器"},"23.12":{t:"ECMAScript Module",p:`::: tip ESM Demo: -https://artplayer.org/esm.html -::: -从 5.2.6 开 ...`,l:"index.html#ecmascript-module",a:"ecmascript-module"},"23.13":{t:"自定义 userAgent",p:"目前对于是否移动设备的判断并不准确,有时候希望通过改变 userAgent 来调整播放器的UI, 所以在 5.2.4 开始新 ...",l:"index.html#自定义-useragent",a:"自定义-useragent"},"24.0":{t:"# 弹幕库",p:"",l:"plugin/danmuku.html",a:"弹幕库"},"24.1":{t:"演示",p:`👉 查看完整演示 -`,l:"plugin/danmuku.html#演示",a:"演示"},"24.2":{t:"安装",p:`::: code-group -npm install artplayer-plugin-danmuku - -yarn add ...`,l:"plugin/danmuku.html#安装",a:"安装"},"24.3":{t:"CDN",p:`::: code-group -https://cdn.jsdelivr.net/npm/artplayer-plugin-d ...`,l:"plugin/danmuku.html#cdn",a:"cdn"},"24.4":{t:"弹幕结构",p:`每一个弹幕是一个对象,多个弹幕组成的数组就是弹幕库,通常只需要text就可以发送一个弹幕,其余都是非必要参数 -{ - t ...`,l:"plugin/danmuku.html#弹幕结构",a:"弹幕结构"},"24.5":{t:"全部选项",p:`只有danmuku是必须的参数,其余都是非必填 -{ - danmuku: [], // 弹幕数据 - speed: ...`,l:"plugin/danmuku.html#全部选项",a:"全部选项"},"24.6":{t:"生命周期",p:`来自用户输入的弹幕: -beforeEmit -> filter -> beforeVisible -> a ...`,l:"plugin/danmuku.html#生命周期",a:"生命周期"},"24.7":{t:"使用弹幕数组",p:"<div className="run-code" data-libs="./uncom ...",l:"plugin/danmuku.html#使用弹幕数组",a:"使用弹幕数组"},"24.8":{t:"使用弹幕 XML",p:`弹幕 XML 文件,和 Bilibili 网站的弹幕格式一致 -<div className="run-cod ...`,l:"plugin/danmuku.html#使用弹幕-xml",a:"使用弹幕-xml"},"24.9":{t:"使用异步返回",p:"<div className="run-code" data-libs="./uncom ...",l:"plugin/danmuku.html#使用异步返回",a:"使用异步返回"},"24.10":{t:"`hide/show`",p:`通过方法 hide 和 show 进行隐藏或者显示弹幕 -<div className="run-code&q ...`,l:"plugin/danmuku.html#hide-show",a:"hide-show"},"24.11":{t:"`isHide`",p:`通过属性 isHide 判断当前弹幕是隐藏或者显示 -<div className="run-code&quo ...`,l:"plugin/danmuku.html#ishide",a:"ishide"},"24.12":{t:"`emit`",p:`通过方法 emit 发送一条实时弹幕 -<div className="run-code" data ...`,l:"plugin/danmuku.html#emit",a:"emit"},"24.13":{t:"`config`",p:`通过方法 config 实时改变弹幕配置 -<div className="run-code" da ...`,l:"plugin/danmuku.html#config",a:"config"},"24.14":{t:"`load`",p:`通过 load 方法可以重载弹幕库,或者切换新弹幕库,或者追加新的弹幕库 -<div className="r ...`,l:"plugin/danmuku.html#load",a:"load"},"24.15":{t:"`reset`",p:`用于清空当前显示的弹幕 -<div className="run-code" data-libs=& ...`,l:"plugin/danmuku.html#reset",a:"reset"},"24.16":{t:"`mount`",p:`在初始化弹幕插件的时候,是可以指定弹幕发射器的挂载位置的,默认是挂载在控制栏的中部,你也可以把它挂载在播放器以外的地方。 -当 ...`,l:"plugin/danmuku.html#mount",a:"mount"},"24.17":{t:"`option`",p:`用于获取当前弹幕配置 -<div className="run-code" data-libs=&q ...`,l:"plugin/danmuku.html#option",a:"option"},"24.18":{t:"事件",p:"<div className="run-code" data-libs="./uncom ...",l:"plugin/danmuku.html#事件",a:"事件"},"25.0":{t:"# 语言设置",p:`::: danger -鉴于捆绑的多国语言越来越多, 从 5.1.0 版本开始, artplayer.js 核心代码除了包含 ...`,l:"start/i18n.html",a:"语言设置"},"25.1":{t:"默认语言",p:`默认语言有: en, zh-cn, 无需手动导入 -var art = new Artplayer({ - contain ...`,l:"start/i18n.html#默认语言",a:"默认语言"},"25.2":{t:"导入语言",p:`打包前的语言文件存放于: artplayer/src/i18n/*.js, 欢迎来添加你的语言 -打包后的语言文件存放于: a ...`,l:"start/i18n.html#导入语言",a:"导入语言"},"25.3":{t:"新增语言",p:`var art = new Artplayer({ - container: '.artplayer-app', - ...`,l:"start/i18n.html#新增语言",a:"新增语言"},"25.4":{t:"修改语言",p:`import zhTw from 'artplayer/i18n/zh-tw'; - -var art = new Artpla ...`,l:"start/i18n.html#修改语言",a:"修改语言"},"26.0":{t:"# 基础选项",p:"",l:"start/option.html",a:"基础选项"},"26.1":{t:"`container`",p:` -Type: String, Element -Default: #artplayer - -播放器挂载的 DOM 容器 -< ...`,l:"start/option.html#container",a:"container"},"26.2":{t:"`url`",p:` -Type: String -Default: '' - -视频源地址 -<div className="run-c ...`,l:"start/option.html#url",a:"url"},"26.3":{t:"`id`",p:` -Type: String -Default: '' - -播放器的唯一标识,目前只用于记忆播放 autoplayback -< ...`,l:"start/option.html#id",a:"id"},"26.4":{t:"`onReady`",p:` -Type: Function -Default: undefined - -构造函数接受一个函数作为第二个参数,播放器初始化成功 ...`,l:"start/option.html#onready",a:"onready"},"26.5":{t:"`poster`",p:` -Type: String -Default: '' - -视频的海报,只会出现在播放器初始化且未播放的状态下 -<div c ...`,l:"start/option.html#poster",a:"poster"},"26.6":{t:"`theme`",p:` -Type: String -Default: #f00 - -播放器主题颜色,目前用于 进度条 和 高亮元素 上 -<div ...`,l:"start/option.html#theme",a:"theme"},"26.7":{t:"`volume`",p:` -Type: Number -Default: 0.7 - -播放器的默认音量 -<div className="r ...`,l:"start/option.html#volume",a:"volume"},"26.8":{t:"`isLive`",p:` -Type: Boolean -Default: false - -使用直播模式,会隐藏进度条和播放时间 -<div clas ...`,l:"start/option.html#islive",a:"islive"},"26.9":{t:"`muted`",p:` -Type: Boolean -Default: false - -是否默认静音 -<div className=" ...`,l:"start/option.html#muted",a:"muted"},"26.10":{t:"`autoplay`",p:` -Type: Boolean -Default: false - -是否自动播放 -<div className=" ...`,l:"start/option.html#autoplay",a:"autoplay"},"26.11":{t:"`autoSize`",p:` -Type: Boolean -Default: false - -播放器的尺寸默认会填充整个 container 容器尺寸,所以 ...`,l:"start/option.html#autosize",a:"autosize"},"26.12":{t:"`autoMini`",p:` -Type: Boolean -Default: false - -当播放器滚动到浏览器视口以外时,自动进入 迷你播放 模式 -&l ...`,l:"start/option.html#automini",a:"automini"},"26.13":{t:"`loop`",p:` -Type: Boolean -Default: false - -是否循环播放 -<div className=" ...`,l:"start/option.html#loop",a:"loop"},"26.14":{t:"`flip`",p:` -Type: Boolean -Default: false - -是否显示视频翻转功能,目前只出现在 设置面板 和 右键菜单 里 ...`,l:"start/option.html#flip",a:"flip"},"26.15":{t:"`playbackRate`",p:` -Type: Boolean -Default: false - -是否显示视频播放速度功能,会出现在 设置面板 和 右键菜单 里 ...`,l:"start/option.html#playbackrate",a:"playbackrate"},"26.16":{t:"`aspectRatio`",p:` -Type: Boolean -Default: false - -是否显示视频长宽比功能,会出现在 设置面板 和 右键菜单 里 - ...`,l:"start/option.html#aspectratio",a:"aspectratio"},"26.17":{t:"`screenshot`",p:` -Type: Boolean -Default: false - -是否在底部控制栏里显示 视频截图 功能 -<div cla ...`,l:"start/option.html#screenshot",a:"screenshot"},"26.18":{t:"`setting`",p:` -Type: Boolean -Default: false - -是否在底部控制栏里显示 设置面板 的开关按钮 -<div ...`,l:"start/option.html#setting",a:"setting"},"26.19":{t:"`hotkey`",p:` -Type: Boolean -Default: true - -是否使用快捷键 -<div className=" ...`,l:"start/option.html#hotkey",a:"hotkey"},"26.20":{t:"`pip`",p:` -Type: Boolean -Default: false - -是否在底部控制栏里显示 画中画 的开关按钮 -<div c ...`,l:"start/option.html#pip",a:"pip"},"26.21":{t:"`mutex`",p:` -Type: Boolean -Default: true - -假如页面里同时存在多个播放器,是否只能让一个播放器播放 -< ...`,l:"start/option.html#mutex",a:"mutex"},"26.22":{t:"`backdrop`",p:` -Type: Boolean -Default: true - -是否开启播放器 UI 的背景虚化效果。开启后,设置面板、右键菜单 ...`,l:"start/option.html#backdrop",a:"backdrop"},"26.23":{t:"`fullscreen`",p:` -Type: Boolean -Default: false - -是否在底部控制栏里显示播放器 窗口全屏 按钮 -<div ...`,l:"start/option.html#fullscreen",a:"fullscreen"},"26.24":{t:"`fullscreenWeb`",p:` -Type: Boolean -Default: false - -是否在底部控制栏里显示播放器 网页全屏 按钮 -<div ...`,l:"start/option.html#fullscreenweb",a:"fullscreenweb"},"26.25":{t:"`subtitleOffset`",p:` -Type: Boolean -Default: false - -字幕时间偏移,范围在 [-5s, 5s],出现在 设置面板 里 ...`,l:"start/option.html#subtitleoffset",a:"subtitleoffset"},"26.26":{t:"`miniProgressBar`",p:` -Type: Boolean -Default: false - -迷你进度条,只在播放器失去焦点后且正在播放时出现 -<di ...`,l:"start/option.html#miniprogressbar",a:"miniprogressbar"},"26.27":{t:"`useSSR`",p:` -Type: Boolean -Default: false - -是否使用 SSR 挂载模式,假如你希望在播放器挂载前,就提前渲 ...`,l:"start/option.html#usessr",a:"usessr"},"26.28":{t:"`playsInline`",p:` -Type: Boolean -Default: true - -在移动端是否使用 playsInline 模式 -<div ...`,l:"start/option.html#playsinline",a:"playsinline"},"26.29":{t:"`layers`",p:` -Type: Array -Default: [] - -初始化自定义的 层 -<div className="ru ...`,l:"start/option.html#layers",a:"layers"},"26.30":{t:"`settings`",p:` -Type: Array -Default: [] - -初始化自定义的 设置面板 -<div className=" ...`,l:"start/option.html#settings",a:"settings"},"26.31":{t:"`contextmenu`",p:` -Type: Array -Default: [] - -初始化自定义的 右键菜单 -<div className=" ...`,l:"start/option.html#contextmenu",a:"contextmenu"},"26.32":{t:"`controls`",p:` -Type: Array -Default: [] - -初始化自定义的底部 控制栏 -<div className=&quo ...`,l:"start/option.html#controls",a:"controls"},"26.33":{t:"`quality`",p:` -Type: Array -Default: [] - -是否在底部控制栏里显示 画质选择 列表 - - - -属性 -类型 -描述 - - - - - ...`,l:"start/option.html#quality",a:"quality"},"26.34":{t:"`highlight`",p:` -Type: Array -Default: [] - -在进度条上显示 高亮信息 - - - -属性 -类型 -描述 - - - - -time -Nu ...`,l:"start/option.html#highlight",a:"highlight"},"26.35":{t:"`plugins`",p:` -Type: Array -Default: [] - -初始化自定义的 插件 -<div className="r ...`,l:"start/option.html#plugins",a:"plugins"},"26.36":{t:"`thumbnails`",p:` -Type: Object -Default: {} - -在进度条上设置 预览图 - - - -属性 -类型 -描述 - - - - -url -Str ...`,l:"start/option.html#thumbnails",a:"thumbnails"},"26.37":{t:"`subtitle`",p:` -Type: Object -Default: {} - -设置视频的字幕,支持字幕格式:vtt, srt, ass - - - -属性 - ...`,l:"start/option.html#subtitle",a:"subtitle"},"26.38":{t:"`moreVideoAttr`",p:` -Type: Object -Default: {'controls': false, 'preload': 'metadat ...`,l:"start/option.html#morevideoattr",a:"morevideoattr"},"26.39":{t:"`icons`",p:` -Type: Object -Default: {} - -用于替换默认图标,支持 Html 字符串和 HTMLElement -& ...`,l:"start/option.html#icons",a:"icons"},"26.40":{t:"`type`",p:` -Type: String -Default: '' - -用于指明视频的格式,需要配合 customType 一起使用,默认视频 ...`,l:"start/option.html#type",a:"type"},"26.41":{t:"`customType`",p:` -Type: Object -Default: {} - -通过视频的 type 进行匹配,把视频解码权交给第三方程序进行处理,处 ...`,l:"start/option.html#customtype",a:"customtype"},"26.42":{t:"`lang`",p:` -Type: String -Default: navigator.language.toLowerCase() - -默认显示语 ...`,l:"start/option.html#lang",a:"lang"},"26.43":{t:"`i18n`",p:` -Type: Object -Default: {} - -自定义 i18n 配置,该配置会和自带的 i18n 进行深度合并 -新增 ...`,l:"start/option.html#i18n",a:"i18n"},"26.44":{t:"`lock`",p:` -Type: Boolean -Default: false - -是否在移动端显示一个 锁定按钮 ,用于隐藏底部 控制栏 -< ...`,l:"start/option.html#lock",a:"lock"},"26.45":{t:"`gesture`",p:` -Type: Boolean -Default: true - -是否在移动端启用视频元素上的手势事件 -<div class ...`,l:"start/option.html#gesture",a:"gesture"},"26.46":{t:"`fastForward`",p:` -Type: Boolean -Default: false - -是否在移动端添加长按视频快进功能 -<div classN ...`,l:"start/option.html#fastforward",a:"fastforward"},"26.47":{t:"`autoPlayback`",p:` -Type: Boolean -Default: false - -是否使用自动 回放功能 -<div className=& ...`,l:"start/option.html#autoplayback",a:"autoplayback"},"26.48":{t:"`autoOrientation`",p:` -Type: Boolean -Default: false - -是否在移动端的网页全屏时,根据视频尺寸和视口尺寸,旋转播放器 - ...`,l:"start/option.html#autoorientation",a:"autoorientation"},"26.49":{t:"`airplay`",p:` -Type: Boolean -Default: false - -是否显示 airplay 按钮,当前只有部分浏览器支持该功能 - ...`,l:"start/option.html#airplay",a:"airplay"},"26.50":{t:"`cssVar`",p:` -Type: Object -Default: {} - -用于改变内置的css变量 -<div className=&quo ...`,l:"start/option.html#cssvar",a:"cssvar"},"26.51":{t:"`proxy`",p:` -Type: function -Default: undefined - -函数可以返回一个第三方的 HTMLCanvasEle ...`,l:"start/option.html#proxy",a:"proxy"}},n={previewLength:62,buttonLabel:"Search",placeholder:"Search docs",allow:[],ignore:[]},a={INDEX_DATA:e,PREVIEW_LOOKUP:t,Options:n};export{a as default}; diff --git a/docs/document/assets/chunks/virtual_search-data.CYnorm-S.js b/docs/document/assets/chunks/virtual_search-data.CYnorm-S.js new file mode 100644 index 000000000..3c9defee6 --- /dev/null +++ b/docs/document/assets/chunks/virtual_search-data.CYnorm-S.js @@ -0,0 +1,1404 @@ +const e={map:'[{"高级属性":["0.0"],"option":["0.1","1.12","10.1","11.12","20.9","23.9","24.17"],"template":["0.2","10.2"],"events":["0.3","10.3"],"storage":["0.4","10.4"],"icons":["0.5","10.5","22.39","26.39"],"i18n":["0.6","10.6","22.43","26.43"],"notice":["0.7","3.4","10.7","13.4"],"layers":["0.8","10.8","18.0","22.29","26.29"],"controls":["0.9","10.9","17.0","22.32","26.32"],"contextmenu":["0.10","2.37","3.3","10.10","12.37","13.3","22.31","26.31"],"subtitle":["0.11","2.36","10.11","12.36","22.37","26.37"],"info":["0.12","2.32","3.22","10.12","12.32","13.22"],"loading":["0.13","2.34","10.13","12.34"],"hotkey":["0.14","2.5","10.14","12.5","22.19","26.19"],"mask":["0.15","2.35","10.15","12.35"],"setting":["0.16","2.39","3.5","3.6","3.7","10.16","12.39","13.5","13.6","13.7","22.18","26.18"],"plugins":["0.17","10.17","22.35","26.35"],"静态属性":["1.0"],"instances":["1.1","11.1"],"version":["1.2","11.2"],"env":["1.3","11.3"],"build":["1.4","11.4"],"config":["1.5","11.5","24.13"],"utils":["1.6","11.6"],"scheme":["1.7","11.7"],"emitter":["1.8","11.8"],"validator":["1.9","11.9"],"kindof":["1.10","11.10"],"html":["1.11","11.11"],"实例事件":["2.0"],"ready":["2.1","12.1"],"restart":["2.2","12.2"],"pause":["2.3","5.2","12.3","15.2"],"play":["2.4","5.1","12.4","15.1"],"destroy":["2.6","5.4","12.6","15.4"],"focus":["2.7","12.7"],"blur":["2.8","12.8"],"dblclick":["2.9","12.9"],"click":["2.10","12.10"],"error":["2.11","12.11"],"hover":["2.12","12.12"],"mousemove":["2.13","12.13"],"resize":["2.14","3.8","12.14","13.8"],"view":["2.15","12.15"],"lock":["2.16","12.16","22.44","26.44"],"aspectratio":["2.17","5.32","12.17","15.32","22.16","26.16"],"autoheight":["2.18","5.33","12.18","15.33"],"autosize":["2.19","5.27","12.19","15.27","22.11","26.11"],"flip":["2.20","3.30","5.30","12.20","13.30","15.30","22.14","26.14"],"fullscreen":["2.21","3.31","5.20","12.21","13.31","15.20","22.23","26.23"],"fullscreenerror":["2.22","12.22"],"fullscreenweb":["2.23","5.21","12.23","15.21","22.24","26.24"],"mini":["2.24","5.24","12.24","15.24"],"pip":["2.25","5.22","12.25","15.22","22.20","26.20"],"screenshot":["2.26","5.17","12.26","15.17","22.17","26.17"],"seek":["2.27","3.27","5.6","12.27","13.27","15.6"],"subtitleoffset":["2.28","5.47","12.28","15.47","22.25","26.25"],"subtitlebeforeupdate":["2.29","12.29"],"subtitleafterupdate":["2.30","12.30"],"subtitleload":["2.31","12.31"],"layer":["2.33","12.33"],"control":["2.38","3.16","12.38","13.16"],"muted":["2.40","5.14","12.40","15.14","22.9","26.9"],"keydown":["2.41","12.41"],"video":["2.42","2.43","2.44","2.45","2.46","2.47","2.48","2.49","2.50","2.51","2.52","2.53","2.54","2.55","2.56","2.57","2.58","2.59","2.60","2.61","2.62","5.43","12.42","12.43","12.44","12.45","12.46","12.47","12.48","12.49","12.50","12.51","12.52","12.53","12.54","12.55","12.56","12.57","12.58","12.59","12.60","12.61","12.62","15.43"],"全局属性":["3.0"],"debug":["3.1","13.1"],"style":["3.2","13.2"],"scroll":["3.9","3.10","13.9","13.10"],"auto":["3.11","3.12","3.13","3.21","13.11","13.12","13.13","13.21"],"reconnect":["3.14","3.15","13.14","13.15"],"dbclick":["3.17","3.18","13.17","13.18"],"mobile":["3.19","3.20","13.19","13.20"],"fast":["3.23","3.24","13.23","13.24"],"touch":["3.25","13.25"],"volume":["3.26","5.9","13.26","15.9","22.7","26.7"],"playback":["3.28","13.28"],"aspect":["3.29","13.29"],"log":["3.32","13.32"],"use":["3.33","13.33"],"remove":["3.34","13.34","19.8"],"编写插件":["4.0"],"实例属性":["5.0"],"toggle":["5.3","15.3"],"reset":["5.5","15.5","24.15"],"forward":["5.7","15.7"],"backward":["5.8","15.8"],"url":["5.10","15.10","22.2","26.2"],"switch":["5.11","15.11"],"switchurl":["5.12","15.12"],"switchquality":["5.13","15.13"],"currenttime":["5.15","15.15"],"duration":["5.16","15.16"],"getdataurl":["5.18","15.18"],"getbloburl":["5.19","15.19"],"poster":["5.23","15.23","22.5","26.5"],"playing":["5.25","15.25"],"state":["5.26","15.26"],"rect":["5.28","15.28"],"bottom":["5.29","15.29"],"playbackrate":["5.31","15.31","22.15","26.15"],"attr":["5.34","15.34"],"type":["5.35","15.35","22.40","26.40"],"theme":["5.36","15.36","22.6","26.6"],"airplay":["5.37","15.37","22.49","26.49"],"loaded":["5.38","15.38"],"loadedtime":["5.39","15.39"],"played":["5.40","15.40"],"proxy":["5.41","15.41","22.51","26.51"],"query":["5.42","15.42"],"cssvar":["5.44","15.44","22.50","26.50"],"quality":["5.45","15.45","22.33","26.33"],"thumbnails":["5.46","15.46","22.36","26.36"],"右键菜单":["6.0"],"配置":["6.1","7.1","8.1"],"创建":["6.2","7.2","8.2","9.2","9.3","9.4","9.5","9.6"],"添加":["6.3","7.3","8.3","9.7"],"删除":["6.4","7.4","8.4","9.8"],"更新":["6.5","7.5","8.5","9.9"],"控制器":["7.0"],"业务层":["8.0"],"设置面板":["9.0"],"内置":["9.1"],"advanced":["10.0"],"static":["11.0"],"instance":["12.0","15.0"],"global":["13.0"],"writing":["14.0"],"context":["16.0"],"configuration":["16.1","17.1","18.1"],"creation":["16.2","17.2","18.2"],"addition":["16.3","18.3"],"deletion":["16.4"],"update":["16.5","18.5","19.9"],"adding":["17.3","21.3"],"removal":["17.4","18.4"],"updating":["17.5"],"settings":["19.0","22.30","26.30"],"built":["19.1"],"create":["19.2","19.3","19.4","19.5","19.6"],"add":["19.7"],"installation":["20.0","20.1"],"cdn":["20.2","23.2","24.3"],"usage":["20.3"],"vue":["20.4","20.7","23.4","23.7"],"react":["20.5","20.8","23.5","23.8"],"typescript":["20.6","23.6"],"javascript":["20.10","23.10"],"legacy":["20.11"],"ecmascript":["20.12","23.12"],"custom":["20.13"],"language":["21.0"],"default":["21.1"],"importing":["21.2"],"modifying":["21.4"],"basic":["22.0"],"container":["22.1","26.1"],"id":["22.3","26.3"],"onready":["22.4","26.4"],"islive":["22.8","26.8"],"autoplay":["22.10","26.10"],"automini":["22.12","26.12"],"loop":["22.13","26.13"],"mutex":["22.21","26.21"],"backdrop":["22.22","26.22"],"miniprogressbar":["22.26","26.26"],"usessr":["22.27","26.27"],"playsinline":["22.28","26.28"],"highlight":["22.34","26.34"],"morevideoattr":["22.38","26.38"],"customtype":["22.41","26.41"],"lang":["22.42","26.42"],"gesture":["22.45","26.45"],"fastforward":["22.46","26.46"],"autoplayback":["22.47","26.47"],"autoorientation":["22.48","26.48"],"安装使用":["23.0"],"安装":["23.1","24.2"],"使用":["23.3"],"古老的浏览器":["23.11"],"自定义":["23.13"],"弹幕库":["24.0"],"演示":["24.1"],"弹幕结构":["24.4"],"全部选项":["24.5"],"生命周期":["24.6"],"使用弹幕数组":["24.7"],"使用弹幕":["24.8"],"使用异步返回":["24.9"],"hide":["24.10"],"ishide":["24.11"],"emit":["24.12"],"load":["24.14"],"mount":["24.16"],"事件":["24.18"],"语言设置":["25.0"],"默认语言":["25.1"],"导入语言":["25.2"],"新增语言":["25.3"],"修改语言":["25.4"],"基础选项":["26.0"]},{"0":["3.28","5.38","5.40","22.7","26.7"],"1":["23.11","24.5"],"3":["3.29","23.9"],"4":["3.29","25.3"],"5":["3.28","8.2","18.2","24.5"],"7":["8.3","18.3","22.7"],"9":["25.3"],"10":["24.5"],"15":["4.0"],"21":["8.5","9.9","18.5","19.9"],"26":["7.5","17.5"],"27":["9.9","19.9"],"75":["3.28"],"250":["3.5"],"这里的":["0.0","1.0","3.0","5.0"],"播放器的选项":["0.1"],"div":["0.1","0.2","0.4","0.5","0.7","0.14","0.17","1.1","1.6","2.0","2.1","2.2","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.28","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","3.3","4.0","5.1","5.2","5.3","5.16","5.28","5.33","5.37","5.45","6.2","6.3","6.4","6.5","7.2","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.4","9.7","9.8","9.9","10.1","10.2","14.0","16.2","16.3","16.4","16.5","17.2","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","22.2","22.29","22.30","24.6","24.7","24.9","24.10","24.11","24.12","24.13","24.14","24.15","24.17","24.18","26.2","26.29","26.30","26.31","26.32"],"classname":["0.1","0.2","0.17","2.0","2.1","2.2","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.28","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","4.0","5.45","6.2","6.3","6.4","6.5","7.2","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.4","9.7","9.8","9.9","10.2","14.0","16.2","16.3","16.4","16.5","17.2","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","22.2","22.29","22.30","24.6","24.7","24.9","24.11","24.12","24.13","24.14","24.15","24.17","24.18","26.2","26.29","26.30"],"run":["0.1","0.2","2.0","2.2","2.6","2.11","2.12","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.28","2.29","2.30","2.31","2.39","4.0","5.45","6.2","6.3","6.4","6.5","7.2","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.4","9.7","9.8","9.9","14.0","16.2","16.3","16.4","16.5","17.2","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","22.2","22.29","24.6","24.7","24.9","24.11","24.12","24.13","24.14","24.15","24.17","24.18","26.2","26.29","26.30"],"管理播放器所有的":["0.2","0.3","0.5"],"dom":["0.2","0.3","5.41","5.42","9.2","9.3","9.5","9.6","10.2","10.3","15.41","15.42","19.2","19.3","19.5","19.6","22.1","26.1"],"元素":["0.2","9.5","9.6"],"事件":["0.3","4.0"],"实质上是代理了":["0.3"],"addeventlistener":["0.3","5.41","10.3","15.41"],"和":["0.3","4.0","5.13","24.8","24.10","26.4"],"removeeventlistener":["0.3","10.3"],"当使用以下方法来处理事件":["0.3"],"播放器销毁时也会自动销毁该事件":["0.3"],"管理播放器的本地存储":["0.4"],"name":["0.4","4.0","10.4","17.1"],"属性用于设置缓存的":["0.4"],"key":["0.4","10.4"],"set":["0.4","10.4","15.9","15.11","15.12","15.44","15.45","22.36","22.37"],"方法用于设置缓存":["0.4"],"get":["0.4","0.6","10.6","15.34","15.44"],"方法用于获取缓存":["0.4"],"del":["0.4"],"方法用于删除缓存":["0.4"],"clear":["0.4"],"方法用于清空缓存":["0.4"],"svg":["0.5","10.5"],"图标":["0.5"],"管理播放器的":["0.6"],"方法用于获取":["0.6"],"的值":["0.6"],"update":["0.6","0.8","0.9","0.10","0.16"],"管理播放器的提示语":["0.7"],"只有一个":["0.7"],"show":["0.7","0.13","0.15","10.13","10.15","24.10"],"属性用于显示提示语":["0.7"],"管理播放器的层":["0.8"],"add":["0.8","0.9","0.10","0.14","0.16","0.17","10.8","10.9","10.10","10.14","10.16"],"方法用于动态添加层":["0.8"],"remove":["0.8","0.9","0.10","0.14","0.16"],"方法用于动态删除层":["0.8"],"管理播放器的控制器":["0.9"],"方法用于动态添加控制器":["0.9"],"方法用于动态删除控制器":["0.9"],"管理播放器的右键菜单":["0.10"],"方法用于动态添加菜单":["0.10"],"方法用于动态删除菜单":["0.10"],"方法用于动态更新菜单":["0.10"],"管理播放器的字幕功能":["0.11"],"url":["0.11","5.12","10.11","15.12","15.18","15.19"],"属性设置和返回当前字幕地址":["0.11"],"style":["0.11"],"方法设置当前字幕的样式":["0.11"],"switch":["0.11"],"管理播放器的信息面板":["0.12"],"常用于查看当前播放器和视频的运行状态":["0.12"],"例如版本号":["0.12"],"分辨率":["0.12"],"时长等":["0.12"],"管理播放器的加载层":["0.13"],"属性用于设置是否显示加载层":["0.13"],"toggle":["0.13","0.15","19.5"],"管理播放器的快捷键功能":["0.14"],"方法用于添加快捷键":["0.14"],"方法用于删除快捷键":["0.14"],"管理播放器的遮罩层":["0.15"],"属性用于设置是否显示遮罩层":["0.15"],"管理播放器的设置面板":["0.16"],"方法用于动态添加设置项":["0.16"],"方法用于动态删除设置项":["0.16"],"方法用于动态更新设置项":["0.16"],"管理播放器的插件功能":["0.17"],"只有一个方法":["0.17"],"用于动态添加插件":["0.17"],"返回全部播放器实例的数组":["1.1"],"假如你想同时管理多个播放器的时候":["1.1"],"可以用到该属性":["1.1"],"返回播放器的版本信息":["1.2"],"返回播放器的环境变量":["1.3"],"返回播放器的打包时间":["1.4"],"返回视频的默认配置":["1.5"],"返回播放器的工具函数集合":["1.6"],"返回播放器选项的校验方案":["1.7"],"返回事件分发器的构造函数":["1.8"],"返回选项的校验函数":["1.9"],"返回类型检测的函数工具":["1.10"],"返回播放器所需的":["1.11"],"返回播放器的默认选项":["1.12"],"播放器的事件分为两种":["2.0"],"一种视频的":["2.0"],"原生事件":["2.0"],"前缀":["2.0"],"video":["2.0","12.0","13.29","13.30","13.34","15.3","15.5","15.11","15.12","15.13","15.16","15.38","15.40","22.2","22.5","22.37","22.40","22.41"],"另外一种是":["2.0"],"自定义事件":["2.0"],"监听事件":["2.0"],"code":["2.0","2.2","2.28","4.0","6.2","6.3","6.4","6.5","7.2","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.4","9.7","9.8","9.9","14.0","16.2","16.3","16.4","16.5","17.2","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","20.1","20.2","20.3","20.4","20.5","22.2","22.29","23.1","23.2","23.3","23.4","23.5","24.2","24.3","24.6","24.7","24.9","24.11","24.12","24.13","24.14","24.15","24.17","24.18","26.2","26.29"],"js":["2.0","4.0","6.5","7.2","7.3","7.5","8.2","8.3","8.5","9.4","9.8","9.9","16.5","17.2","17.3","17.5","18.2","18.3","18.5","19.4","19.8","19.9","20.4","20.5","20.7","20.8","20.10","20.11","21.2","21.4","23.4","23.5","23.7","23.8","23.10","23.11","24.5","24.18","25.2","25.3","25.4"],"当播放器首次可以播放器时触发":["2.1"],"当播放器切换地址后并可以播放时触发":["2.2"],"当播放器暂停时触发":["2.3"],"当播放器播放时触发":["2.4"],"当播放器热键被按下时触发":["2.5"],"当播放器销毁时触发":["2.6"],"当播放器获得焦点时触发":["2.7"],"当播放器失去焦点时触发":["2.8"],"当播放器被双击时触发":["2.9"],"当播放器被单击时触发":["2.10"],"当播放器加载视频发生错误时触发":["2.11"],"当播放器被鼠标移出或者移入时触发":["2.12"],"当播放器被鼠标经过时触发":["2.13"],"当播放器尺寸变化时触发":["2.14"],"当播放器出现在视口时触发":["2.15"],"在移动端":["2.16","3.19","3.20","3.21","3.23","3.24","3.25"],"当锁定的状态发生变化时触发":["2.16"],"当播放器长宽比变化时触发":["2.17"],"当播放器自动设置高度时触发":["2.18"],"当播放器自动设置尺寸时触发":["2.19"],"当播放器发生翻转时触发":["2.20"],"当播放器发生窗口全屏时触发":["2.21"],"当播放器发生窗口全屏错误时触发":["2.22"],"当播放器发生网页全屏时触发":["2.23"],"当播放器进入迷你模式时触发":["2.24"],"当播放器进入画中画时触发":["2.25"],"当播放器被截图时触发":["2.26"],"当播放器发生时间跳转时触发":["2.27"],"当播放器发生字幕偏移时触发":["2.28"],"当字幕更新前触发":["2.29"],"当字幕更新后触发":["2.30"],"当字幕加载时触发":["2.31"],"当信息面板显示或隐藏时触发":["2.32"],"当自定义层显示或隐藏时触发":["2.33"],"当加载器显示或隐藏时触发":["2.34"],"当遮罩层显示或隐藏时触发":["2.35"],"当字幕层显示或隐藏时触发":["2.36"],"当右键菜单显示或隐藏时触发":["2.37"],"当控制器显示或隐藏时触发":["2.38"],"当设置面板显示或隐藏时触发":["2.39"],"当静音的状态变化时触发":["2.40"],"监听来自":["2.41"],"document":["2.41"],"的":["2.41"],"canplay":["2.42","12.42"],"canplaythrough":["2.43","12.43"],"complete":["2.44","12.44"],"durationchange":["2.45","12.45"],"emptied":["2.46","12.46"],"ended":["2.47","12.47"],"error":["2.48","12.48"],"loadeddata":["2.49","12.49"],"loadedmetadata":["2.50","12.50"],"pause":["2.51","12.51"],"play":["2.52","3.19","3.20","12.52","13.19","13.20","15.3"],"playing":["2.53","12.53"],"progress":["2.54","12.54","22.36"],"ratechange":["2.55","12.55"],"seeked":["2.56","12.56"],"seeking":["2.57","12.57"],"stalled":["2.58","12.58"],"suspend":["2.59","12.59"],"timeupdate":["2.60","12.60"],"volumechange":["2.61","12.61"],"waiting":["2.62","12.62"],"是否开始":["3.1"],"模式":["3.1"],"返回播放器样式文本":["3.2"],"是否开启右键菜单":["3.3"],"默认开启":["3.3"],"time":["3.4","3.8","3.9","3.14","3.15","3.16","3.17","3.21","3.22","3.24","13.4","13.8","13.9","13.14","13.15","13.16","13.17","13.21","13.22","13.24","22.25"],"提示信息的显示时长":["3.4"],"单位为毫秒":["3.4","3.8","3.9","3.13","3.16","3.17","3.22"],"width":["3.5","3.6","5.29","9.3","13.5","13.6","15.29","15.33"],"设置面板的默认宽度":["3.5"],"单位为像素":["3.5","3.6","3.7","3.10"],"默认为":["3.5","3.6","3.7","3.11","3.17","3.26","3.28","3.29","3.30","3.32","3.33"],"item":["3.6","3.7","13.6","13.7","19.6"],"设置面板的设置项的默认宽度":["3.6"],"height":["3.7","5.29","13.7","15.29"],"设置面板的设置项的默认高度":["3.7"],"事件的节流时间":["3.8","3.9"],"gap":["3.10","13.10"],"view":["3.10","10.12"],"事件的边界容差距离":["3.10"],"playback":["3.11","3.12","3.13","12.53","13.11","13.12","13.13","22.47"],"max":["3.11","3.14","13.11","13.14"],"自动回放功能的最大记录数":["3.11"],"min":["3.12","13.12"],"自动回放功能的最小记录时长":["3.12"],"单位为秒":["3.12","3.27","5.39"],"timeout":["3.13","13.13"],"自动回放功能的隐藏延迟时长":["3.13"],"发生连接错误时":["3.14","3.15"],"自动连接的最大次数":["3.14"],"sleep":["3.15","13.15"],"自动连接的延迟时间":["3.15"],"hide":["3.16","13.13","13.16"],"底部控制栏的自动隐藏的延迟时间":["3.16"],"双击事件的延迟事件":["3.17"],"fullscreen":["3.18","12.22","13.18"],"在桌面端":["3.18"],"是否双击切换全屏":["3.18"],"dbclick":["3.19","13.19"],"是否双击切换播放暂停":["3.19"],"click":["3.20","13.20"],"是否单击切换播放暂停":["3.20"],"orientation":["3.21","13.21"],"自动旋屏的延迟时间":["3.21"],"loop":["3.22","13.22"],"信息面板的刷新时间":["3.22"],"forward":["3.23","3.24","13.23","13.24"],"value":["3.23","13.23"],"长按加速的速率倍数":["3.23"],"长按加速的延迟时间":["3.24"],"move":["3.25","13.25"],"ratio":["3.25","3.29","13.25","13.29"],"左右滑动进度的速率倍数":["3.25"],"step":["3.26","3.27","13.26","13.27"],"快捷键调节音量的幅度比例":["3.26"],"快捷键调节播放进度的幅度":["3.27"],"rate":["3.28","13.28"],"内置播放速率的列表":["3.28"],"内置视频长宽比的列表":["3.29"],"default":["3.29","13.5","13.6","13.7","22.1","22.2","22.3","22.4","22.5","22.6","22.7","22.8","22.9","22.10","22.11","22.12","22.13","22.14","22.15","22.16","22.17","22.18","22.19","22.20","22.21","22.22","22.23","22.24","22.25","22.26","22.27","22.28","22.29","22.30","22.31","22.32","22.33","22.34","22.35","22.36","22.37","22.38","22.39","22.40","22.41","22.42","22.43","22.44","22.45","22.46","22.47","22.48","22.49","22.50","22.51","26.1","26.2","26.3","26.4","26.5","26.6","26.7","26.8","26.9","26.10","26.11","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.19","26.20","26.21","26.22","26.23","26.24","26.25","26.26","26.27","26.28","26.29","26.30","26.31","26.32","26.33","26.34","26.35","26.36","26.37","26.38","26.39","26.40","26.41","26.42","26.43","26.44","26.45","26.46","26.47","26.48","26.49","26.50","26.51"],"内置视频翻转的列表":["3.30"],"normal":["3.30"],"horizontal":["3.30"],"vertical":["3.30"],"web":["3.31","13.31"],"in":["3.31","13.28","13.29","13.30","13.31","19.1","20.10"],"body":["3.31","13.31"],"网页全屏时":["3.31"],"version":["3.32","13.32"],"设置是否打印播放器版本":["3.32"],"raf":["3.33","13.33"],"设置是否使用":["3.33"],"requestanimationframe":["3.33"],"src":["3.34","5.5","13.34","21.2","25.2"],"when":["3.34","10.3","12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.31","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","13.34","15.33"],"destroy":["3.34","13.34"],"在销毁播放器时":["3.34"],"是否同时移除视频的":["3.34"],"但你已经知道播放器的":["4.0"],"属性":["4.0","6.1","7.1","8.1","9.2","9.3","9.5","9.6","26.33","26.34","26.36","26.37"],"方法":["4.0"],"后":["4.0"],"再编写插件是非常简单的事":["4.0"],"可以在实例化的时候加载插件的函数":["4.0"],"function":["4.0","5.1","5.2","5.3","5.4","5.5","5.12","5.13","5.17","5.18","5.19","5.27","5.33","5.34","5.37","5.41","5.42","5.44","9.3","14.0","15.1","15.2","15.3","15.4","15.5","15.12","15.13","15.17","15.18","15.19","15.27","15.33","15.34","15.37","15.41","15.42","15.44","22.4","22.51","26.4","26.51"],"myplugin":["4.0"],"art":["4.0","5.12","7.2","15.12","17.2"],"console":["4.0"],"info":["4.0"],"return":["4.0"],"something":["4.0"],"type":["5.1","5.2","5.3","5.4","5.5","5.6","5.7","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.15","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.24","5.25","5.26","5.27","5.28","5.30","5.31","5.32","5.33","5.34","5.36","5.37","5.38","5.39","5.40","5.41","5.42","5.43","5.44","5.45","5.46","5.47","15.1","15.2","15.3","15.4","15.5","15.6","15.7","15.8","15.9","15.10","15.11","15.12","15.13","15.14","15.15","15.16","15.17","15.18","15.19","15.20","15.21","15.22","15.23","15.24","15.25","15.26","15.27","15.28","15.29","15.30","15.31","15.32","15.33","15.34","15.36","15.37","15.38","15.39","15.40","15.41","15.42","15.43","15.44","15.45","15.46","15.47","16.1","17.1","18.1","19.2","19.3","19.5","19.6","20.10","22.1","22.2","22.3","22.4","22.5","22.6","22.7","22.8","22.9","22.10","22.11","22.12","22.13","22.14","22.15","22.16","22.17","22.18","22.19","22.20","22.21","22.22","22.23","22.24","22.25","22.26","22.27","22.28","22.29","22.30","22.31","22.32","22.33","22.34","22.35","22.36","22.37","22.38","22.39","22.41","22.42","22.43","22.44","22.45","22.46","22.47","22.48","22.49","22.50","22.51","26.1","26.2","26.3","26.4","26.5","26.6","26.7","26.8","26.9","26.10","26.11","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.19","26.20","26.21","26.22","26.23","26.24","26.25","26.26","26.27","26.28","26.29","26.30","26.31","26.32","26.33","26.34","26.35","26.36","26.37","26.38","26.39","26.41","26.42","26.43","26.44","26.45","26.46","26.47","26.48","26.49","26.50","26.51"],"播放视频":["5.1"],"暂停视频":["5.2"],"切换视频的播放和暂停":["5.3"],"parameter":["5.4","5.6","5.7","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.15","5.20","5.21","5.22","5.23","5.24","5.25","5.26","5.30","5.31","5.32","5.34","5.35","5.36","5.45","5.46","5.47","15.4","15.6","15.7","15.8","15.9","15.10","15.11","15.12","15.13","15.14","15.15","15.20","15.21","15.22","15.23","15.24","15.25","15.26","15.30","15.31","15.32","15.34","15.35","15.36","15.45","15.46","15.47","22.4"],"boolean":["5.4","5.14","5.20","5.21","5.22","5.25","7.1","15.4","15.14","15.20","15.21","15.22","15.24","15.25","16.1","17.1","18.1","22.8","22.9","22.10","22.11","22.12","22.13","22.14","22.15","22.16","22.17","22.18","22.19","22.20","22.21","22.22","22.23","22.24","22.25","22.26","22.27","22.28","22.44","22.45","22.46","22.47","22.48","22.49","26.8","26.9","26.10","26.11","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.19","26.20","26.21","26.22","26.23","26.24","26.25","26.26","26.27","26.28","26.44","26.45","26.46","26.47","26.48","26.49"],"重置播放器的视频元素":["5.5"],"会移除当前":["5.5"],"并调用一次":["5.5"],"setter":["5.6","5.7","5.8","5.9","5.10","5.11","5.14","5.15","5.20","5.21","5.22","5.23","5.24","5.26","5.30","5.31","5.32","5.35","5.36","5.45","5.46","5.47","15.6","15.7","15.8","15.9","15.10","15.11","15.14","15.15","15.20","15.21","15.22","15.23","15.24","15.26","15.30","15.31","15.32","15.35","15.36","15.45","15.46","15.47"],"number":["5.6","5.7","5.8","5.9","5.15","5.31","13.14","15.6","15.7","15.8","15.9","15.15","15.31","15.47","21.0","22.7","26.7"],"getter":["5.9","5.10","5.14","5.15","5.16","5.20","5.21","5.22","5.23","5.24","5.25","5.26","5.28","5.30","5.31","5.32","5.35","5.36","5.38","5.39","5.40","5.46","5.47","15.9","15.10","15.14","15.15","15.16","15.20","15.21","15.22","15.23","15.24","15.25","15.26","15.28","15.29","15.30","15.31","15.32","15.35","15.36","15.38","15.39","15.40","15.46","15.47"],"string":["5.11","5.12","5.13","5.23","5.26","5.30","5.32","5.34","5.35","5.36","9.2","9.3","9.5","9.6","15.10","15.11","15.12","15.13","15.23","15.26","15.30","15.32","15.34","15.35","15.36","17.1","19.2","19.3","19.5","19.6","22.1","22.2","22.3","22.5","22.6","22.40","22.42","26.1","26.2","26.3","26.5","26.6","26.40","26.42"],"设置视频地址":["5.11","5.12"],"设置时和":["5.11","5.12"],"设置视频画质地址":["5.13"],"获取视频时长":["5.16"],"下载当前视频帧的截图":["5.17"],"可选参数为截图名字":["5.17"],"获取当前视频帧的截图的":["5.18","5.19"],"base64":["5.18","15.18"],"地址":["5.18","5.19"],"blob":["5.19","15.19"],"设置和获取视频海报":["5.23"],"获取或设置播放器当前状态":["5.26"],"设置视频是否自适应尺寸":["5.27"],"获取播放器的尺寸和坐标信息":["5.28"],"top":["5.29","15.29"],"left":["5.29","15.29"],"right":["5.29","15.29"],"x":["5.29","15.29"],"y":["5.29","15.29"],"当容器只有宽度":["5.33"],"该属性可以自动计算出并设置视频的高度":["5.33"],"动态获取和设置":["5.34"],"开启隔空播放":["5.37"],"视频缓存的比例":["5.38"],"范围是":["5.38","5.40"],"已缓存的媒体时长":["5.39"],"视频播放的比例":["5.40"],"事件的代理函数":["5.41"],"实质上代理了":["5.41"],"的查询函数":["5.42"],"element":["5.43","9.2","9.3","9.5","9.6","15.5","15.43","19.2","19.3","19.5","19.6","22.1","26.1"],"快捷返回播放器的":["5.43"],"动态获取或设置":["5.44"],"css":["5.44"],"变量":["5.44","23.10"],"array":["5.45","9.3","11.1","15.45","19.3","22.29","22.30","22.31","22.32","22.33","22.34","22.35","26.29","26.30","26.31","26.32","26.33","26.34","26.35"],"动态设置画质列表":["5.45"],"object":["5.46","15.46","22.36","22.37","22.38","22.39","22.41","22.43","22.50","26.36","26.37","26.38","26.39","26.41","26.43","26.50"],"类型":["6.1","7.1","8.1","9.2","9.3","9.5","9.6","26.34","26.36","26.37"],"描述":["6.1","7.1","8.1","9.2","9.3","9.5","9.6","26.36"],"disable":["6.1","7.1","8.1","16.1","17.1","18.1"],"var":["7.2","9.4","17.2"],"new":["7.2","17.2","21.3"],"artplayer":["7.2","17.2","20.4","20.5","20.11","20.12","21.2","22.1","23.5","23.11","23.12","24.18","25.2","25.4","26.1"],"container":["7.2","15.33","17.2"],"须先打开设置面板":["9.1"],"然后自带四个内置项":["9.1"],"flip":["9.1"],"playbackrate":["9.1"],"按钮":["9.2"],"html":["9.2","9.3","9.5","9.6","19.2","19.3","19.5","19.6","20.3","23.3","26.39"],"元素的":["9.2","9.3","9.5","9.6"],"选择列表":["9.3"],"icon":["9.3","9.5","9.6","19.3","19.6"],"元素的图标":["9.3"],"selector":["9.3","19.3"],"元素列表":["9.3"],"onselect":["9.3"],"元素点击事件":["9.3"],"列表嵌套":["9.4"],"切换按钮":["9.5"],"范围滑块":["9.6"],"properties":["10.0","11.0","13.0","14.0","15.0"],"the":["10.0","10.1","10.2","10.3","10.4","10.6","10.7","10.8","10.9","10.10","10.11","10.12","10.13","10.14","10.15","10.16","10.17","11.2","11.3","11.4","11.5","11.6","11.7","11.8","11.9","11.10","11.11","11.12","12.0","12.1","12.2","12.3","12.4","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.23","12.24","12.25","12.26","12.27","12.28","12.32","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","12.42","12.43","12.46","12.58","13.0","13.2","13.3","13.4","13.5","13.6","13.7","13.8","13.9","13.10","13.11","13.12","13.13","13.14","13.15","13.16","13.17","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.28","13.29","13.30","13.34","14.0","15.1","15.2","15.4","15.5","15.11","15.12","15.13","15.16","15.18","15.19","15.22","15.28","15.33","15.38","15.39","15.40","15.45","17.1","19.2","19.3","19.5","19.6","20.6","20.9","20.11","20.13","21.0","21.1","22.1","22.2","22.3","22.4","22.5","22.6","22.7","22.11","22.22","22.33","22.34","22.36","22.40","22.41","22.47","22.51"],"player":["10.1","10.2","10.3","10.4","10.6","10.7","10.8","10.9","10.10","10.11","10.12","10.13","10.14","10.15","10.16","10.17","11.1","12.0","12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.14","12.15","12.17","12.18","12.19","12.20","12.21","12.23","12.24","12.25","12.26","12.27","14.0","15.5","15.28","22.7"],"s":["10.1","10.4","10.6","10.7","10.8","10.9","10.10","10.11","10.12","10.13","10.14","10.15","10.16","10.17","12.17","12.18","13.34","14.0","15.5","15.28"],"options":["10.1","22.0"],"manages":["10.2","10.3","10.4","10.5","10.6","10.7","10.8","10.9","10.10","10.11","10.12","10.13","10.14","10.15","10.16","10.17"],"all":["10.2","10.3","10.5","11.1"],"elements":["10.2"],"of":["10.2","11.1","11.6","12.0","13.5","13.6","13.7","13.28","13.29","13.30","15.16","15.38","15.40","20.13","21.0"],"for":["10.3","10.5","12.41","13.8","13.9","13.17","13.26","15.41","19.5","19.6"],"it":["10.3","10.7","22.40"],"essentially":["10.3","15.41"],"proxies":["10.3"],"and":["10.3","10.11","12.0","13.34","14.0","15.23","20.0"],"using":["10.3"],"local":["10.4"],"property":["10.4","10.11","16.1","17.1","18.1","19.2","19.3","19.5","19.6"],"is":["10.4","10.6","10.8","10.9","10.10","10.14","10.16","12.20","20.13"],"used":["10.4","10.6","10.8","10.9","10.10","10.12","10.16","22.39","22.40","22.50"],"to":["10.4","10.6","10.8","10.9","10.10","10.12","10.16","13.1","13.3","13.31","13.32","13.33","13.34","15.12","16.1","17.1","19.1","21.0","22.10","22.15","22.16","22.17","22.19","22.22","22.27","22.33","22.39","22.40","22.47","22.50"],"cache":["10.4"],"method":["10.4","10.6","10.8","10.9","10.10","10.14","10.16"],"notifications":["10.7"],"only":["10.7","15.33","20.11"],"dynamically":["10.8","10.9","10.10","10.16","15.34","15.35","15.36","15.44","15.45"],"context":["10.10","12.37","22.31"],"menu":["10.10","16.0"],"functionality":["10.11","10.14","10.17"],"sets":["10.11","13.32","13.33","15.13","15.14","15.15","15.20","15.21","15.22","15.23","15.26","15.27","15.30","15.31","15.32"],"information":["10.12","22.34"],"panel":["10.12","10.16","12.39","19.0"],"commonly":["10.12"],"layer":["10.13","10.15"],"settings":["10.16","12.39","21.0"],"plugin":["10.17","14.0","24.18"],"with":["10.17","12.0","14.0"],"here":["11.0","15.0"],"returns":["11.1","11.2","11.3","11.4","11.5","11.6","11.7","11.8","11.9","11.10","11.11","11.12","13.2","15.43"],"an":["11.1","12.11","12.48"],"collection":["11.6"],"events":["12.0","14.0","15.41"],"are":["12.0","12.29","12.30","12.31","14.0","21.2"],"divided":["12.0"],"into":["12.0"],"two":["12.0"],"types":["12.0"],"native":["12.0"],"prefixed":["12.0"],"custom":["12.0","12.33","22.29","22.30","22.31","22.32","22.35","22.43"],"listening":["12.0"],"triggered":["12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.29","12.30","12.31","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40"],"switches":["12.2"],"urls":["12.2"],"a":["12.5","12.22","12.33","14.0","15.17","15.33","15.41","15.42","20.13","21.3","21.4","22.4","22.26"],"occurs":["12.11"],"mouse":["12.12","12.13"],"enters":["12.12","12.21","12.23","12.24","12.25"],"state":["12.16"],"windowed":["12.22"],"subtitle":["12.28","22.25"],"offset":["12.28"],"changes":["12.28"],"before":["12.29","21.2"],"subtitles":["12.29","12.30","12.31","22.37"],"updated":["12.29","12.30"],"after":["12.30"],"loaded":["12.31"],"loader":["12.34"],"listens":["12.41"],"browser":["12.42"],"media":["12.46","15.39"],"has":["12.46","15.33"],"whether":["13.1","13.3","13.18","13.31","13.32","13.33","13.34","15.27","16.1","17.1","18.1","20.13","22.10","22.14","22.15","22.16","22.17","22.18","22.19","22.20","22.22","22.23","22.24","22.27","22.33","22.44","22.45","22.46","22.47","22.48","22.49"],"enable":["13.1","13.3","22.8","22.22"],"mode":["13.1"],"display":["13.4","22.17","22.33","22.34"],"duration":["13.4"],"throttle":["13.8","13.9"],"boundary":["13.10"],"tolerance":["13.10"],"distance":["13.10"],"maximum":["13.11","13.14"],"record":["13.11","13.12"],"minimum":["13.12"],"delay":["13.13","13.15","13.17"],"auto":["13.16"],"on":["13.18","13.19","13.20","13.21","13.23","13.24","13.25","22.34","22.36","22.41"],"desktop":["13.18"],"mobile":["13.21","13.23","13.24","13.25","20.13"],"refresh":["13.22"],"interval":["13.22"],"size":["13.26","13.27"],"built":["13.28","13.29","13.30"],"list":["13.28","13.29","13.30","15.45","19.3","19.4"],"mount":["13.31"],"attribute":["13.34"],"call":["13.34"],"plugins":["14.0"],"once":["14.0"],"you":["14.0","19.1","20.9"],"familiar":["14.0"],"methods":["14.0"],"becomes":["14.0"],"very":["14.0"],"straightforward":["14.0"],"task":["14.0"],"can":["14.0","20.9"],"load":["14.0"],"during":["14.0"],"instantiation":["14.0"],"removes":["15.5"],"rewind":["15.8"],"similar":["15.12"],"or":["15.15","15.20","15.22","15.26","15.44"],"gets":["15.15","15.16","15.18","15.19","15.20","15.22","15.23","15.25","15.26","15.28"],"downloads":["15.17"],"defined":["15.33"],"this":["15.33","22.4","22.43"],"initiate":["15.37"],"proportion":["15.38","15.40"],"buffered":["15.39"],"proxying":["15.41"],"quickly":["15.43"],"description":["16.1","17.1","18.1","19.2","19.3","19.5","19.6"],"control":["17.1","22.32"],"first":["19.1"],"need":["19.1"],"open":["19.1"],"button":["19.2","19.5"],"selection":["19.3","22.33"],"nested":["19.4"],"range":["19.6"],"slider":["19.6"],"group":["20.1","20.2","20.3","20.4","20.5","23.1","23.2","23.3","23.4","23.5","24.2","24.3"],"bash":["20.1","20.2","23.1","23.2","24.2","24.3"],"index":["20.3","23.3","24.18"],"jsx":["20.5","20.8","23.5","23.8"],"import":["20.5","21.4","23.5","23.9","25.4"],"from":["20.5","23.5","25.4"],"useeffect":["20.5","23.5"],"useref":["20.5"],"also":["20.9"],"use":["20.9","22.19","22.27","22.47"],"sometimes":["20.10"],"your":["20.10"],"files":["20.10","21.2"],"may":["20.10"],"lose":["20.10"],"typescript":["20.10","23.10"],"hints":["20.10"],"browsers":["20.11"],"production":["20.11"],"build":["20.11"],"supports":["20.11"],"latest":["20.11"],"major":["20.11"],"module":["20.12","23.12"],"tip":["20.12","23.12"],"esm":["20.12","23.12"],"demo":["20.12","23.12"],"https":["20.12","23.12"],"org":["20.12","23.12"],"useragent":["20.13","23.13"],"currently":["20.13"],"detection":["20.13"],"device":["20.13"],"danger":["21.0","25.0"],"due":["21.0"],"increasing":["21.0"],"languages":["21.1","21.2"],"language":["21.2","21.3","21.4","22.42","26.42"],"bundling":["21.2"],"located":["21.2"],"at":["21.2"],"i18n":["21.2","25.2"],"zhtw":["21.4","25.4"],"where":["22.1"],"source":["22.2"],"unique":["22.3"],"undefined":["22.4","22.51","26.4","26.51"],"constructor":["22.4"],"accepts":["22.4"],"as":["22.4"],"second":["22.4"],"f00":["22.6","26.6"],"false":["22.8","22.9","22.10","22.11","22.12","22.13","22.14","22.15","22.16","22.17","22.18","22.20","22.23","22.24","22.25","22.26","22.27","22.38","22.44","22.46","22.47","22.48","22.49","26.10","26.11","26.12","26.14","26.15","26.16","26.17","26.25","26.27","26.38","26.44","26.47","26.49"],"by":["22.11"],"automatically":["22.12"],"true":["22.19","22.21","22.22","22.28","22.45","26.19","26.22"],"hotkeys":["22.19"],"if":["22.21"],"blur":["22.22"],"ssr":["22.27","26.27"],"server":["22.27"],"initialize":["22.29","22.30","22.31","22.32","22.35"],"panels":["22.30"],"bottom":["22.32"],"preview":["22.36"],"bar":["22.36"],"supported":["22.37"],"formats":["22.37"],"vtt":["22.37","26.37"],"srt":["22.37","26.37"],"ass":["22.37","26.37"],"controls":["22.38","26.38"],"preload":["22.38"],"metadata":["22.38"],"replace":["22.39"],"specify":["22.40"],"format":["22.40"],"needs":["22.40"],"be":["22.40","22.43"],"matches":["22.41"],"based":["22.41"],"navigator":["22.42","26.42"],"configuration":["22.43"],"will":["22.43"],"deeply":["22.43"],"merged":["22.43"],"automatic":["22.47"],"导入":["23.6"],"你也可以使用选项的类型":["23.9"],"ts":["23.9"],"有时你的":["23.10"],"文件会丢失":["23.10"],"的类型提示":["23.10"],"这时候你可以手动导入类型":["23.10"],"生产构建的":["23.11"],"只兼容最新一个主版本的":["23.11"],"chrome":["23.11"],"last":["23.11"],"目前对于是否移动设备的判断并不准确":["23.13"],"有时候希望通过改变":["23.13"],"来调整播放器的ui":["23.13"],"查看完整演示":["24.1"],"jsdelivr":["24.3"],"每一个弹幕是一个对象":["24.4"],"多个弹幕组成的数组就是弹幕库":["24.4"],"通常只需要":["24.4"],"text":["24.4"],"只有":["24.5"],"danmuku":["24.5","24.18"],"是必须的参数":["24.5"],"其余都是非必填":["24.5"],"弹幕数据":["24.5"],"speed":["24.5"],"弹幕持续时间":["24.5"],"范围在":["24.5"],"margin":["24.5"],"来自用户输入的弹幕":["24.6"],"beforeemit":["24.6"],"filter":["24.6"],"beforevisible":["24.6"],"artplayerplugindanmuku":["24.6"],"visible":["24.6"],"来自服务器的弹幕":["24.6"],"xml":["24.8"],"弹幕":["24.8"],"文件":["24.8"],"data":["24.9","24.11","24.12","24.13","24.14","24.18"],"通过方法":["24.10","24.12","24.13"],"进行隐藏或者显示弹幕":["24.10"],"通过属性":["24.11"],"判断当前弹幕是隐藏或者显示":["24.11"],"发送一条实时弹幕":["24.12"],"libs":["24.12","24.13","24.14","24.18"],"实时改变弹幕配置":["24.13"],"uncompiled":["24.13","24.14","24.18"],"通过":["24.14"],"方法可以重载弹幕库":["24.14"],"或者切换新弹幕库":["24.14"],"或者追加新的弹幕库":["24.14"],"用于清空当前显示的弹幕":["24.15"],"在初始化弹幕插件的时候":["24.16"],"是可以指定弹幕发射器的挂载位置的":["24.16"],"默认是挂载在控制栏的中部":["24.16"],"你也可以把它挂载在播放器以外的地方":["24.16"],"当播放器全屏的时候":["24.16"],"发射器会自动回到控制栏的中部":["24.16"],"假如你挂载的地方是亮色的话":["24.16"],"建议把":["24.16"],"用于获取当前弹幕配置":["24.17"],"鉴于捆绑的多国语言越来越多":["25.0"],"从":["25.0"],"默认语言有":["25.1"],"en":["25.1"],"zh":["25.1"],"打包前的语言文件存放于":["25.2"],"欢迎来添加你的语言":["25.2"],"打包后的语言文件存放于":["25.2"],"dist":["25.2"],"播放器挂载的":["26.1"],"视频源地址":["26.2"],"播放器的唯一标识":["26.3"],"构造函数接受一个函数作为第二个参数":["26.4"],"播放器初始化成功且视频可以播放时触发":["26.4"],"ready":["26.4"],"视频的海报":["26.5"],"是否自动播放":["26.10"],"是否使用快捷键":["26.19"],"是否开启播放器":["26.22"],"字幕时间偏移":["26.25"],"是否使用":["26.27"],"初始化自定义的":["26.29","26.30","26.31","26.35"],"层":["26.29"],"设置面板":["26.30"],"右键菜单":["26.31"],"初始化自定义的底部":["26.32"],"控制栏":["26.32"],"是否在底部控制栏里显示":["26.33"],"画质选择":["26.33"],"列表":["26.33"],"在进度条上显示":["26.34"],"高亮信息":["26.34"],"插件":["26.35"],"在进度条上设置":["26.36"],"预览图":["26.36"],"设置视频的字幕":["26.37"],"支持字幕格式":["26.37"],"用于替换默认图标":["26.39"],"支持":["26.39"],"用于指明视频的格式":["26.40"],"需要配合":["26.40"],"customtype":["26.40"],"通过视频的":["26.41"],"自定义":["26.43"],"配置":["26.43"],"该配置会和自带的":["26.43"],"进行深度合并":["26.43"],"新增你的语言":["26.43"],"是否使用自动":["26.47"],"回放功能":["26.47"],"用于改变内置的css变量":["26.50"]},{"0":["3.25","3.26","5.9","13.28","15.38","15.40","21.0","24.5","25.0"],"1":["3.26","3.28","5.9","5.38","5.40","13.28","15.38","15.40","20.11","21.0","23.10","25.0"],"2":["3.28","20.8","20.12","23.8","23.12","23.13"],"3":["3.23","13.29","20.9","22.2","23.10","26.2"],"4":["6.2","13.29","16.2","21.3","22.47","23.13","26.43"],"5":["3.12","3.14","3.25","3.27","13.28","20.12","21.0","22.29","22.30","23.12","23.13","25.0","26.29","26.30"],"6":["2.0","6.3","7.3","12.0","16.3","17.3","20.12","23.12"],"7":["26.7"],"9":["3.29","9.7","19.7","21.3","26.43"],"10":["2.2","3.11","7.2","17.2"],"11":["2.28"],"13":["6.2","6.3","16.2","16.3"],"14":["9.7","19.7"],"15":["14.0"],"16":["3.29","13.29"],"19":["5.45","15.45"],"21":["6.4","6.5","7.3","7.4","8.4","16.4","16.5","17.3","17.4","18.4"],"22":["8.2","8.3","9.8","18.2","18.3","19.8"],"23":["22.29","26.29"],"24":["6.5","16.5"],"25":["3.28","24.5"],"29":["5.45","8.5","18.5"],"34":["22.30","26.30"],"35":["3.7"],"40":["7.5","17.5"],"50":["3.10"],"75":["13.28"],"200":["3.6","3.8","3.9","3.21"],"300":["3.17"],"1000":["3.15","3.22","3.24"],"2000":["3.4"],"3000":["3.13","3.16"],"code":["0.1","0.2","0.4","0.5","0.6","0.7","0.13","0.14","0.15","0.16","0.17","1.1","1.6","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","3.3","3.5","3.6","3.7","3.17","3.29","3.30","5.1","5.2","5.3","5.12","5.14","5.16","5.17","5.20","5.21","5.22","5.23","5.25","5.27","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.44","5.45","5.46","9.3","10.1","10.2","10.5","12.0","12.20","12.29","12.30","12.31","15.2","15.12","15.16","15.37","15.44","15.45","19.3","22.1","22.7","22.10","22.19","22.30","22.31","22.32","22.35","22.43","22.47","24.10","24.16","25.2","26.1","26.4","26.10","26.19","26.30","26.31","26.32","26.35","26.39","26.43","26.47","26.50"],"js":["0.2","0.4","0.14","0.17","2.2","2.18","2.22","2.24","2.28","2.29","2.30","2.31","5.45","6.2","6.3","6.4","7.4","8.4","9.3","9.6","9.7","10.2","12.0","14.0","15.16","15.45","16.2","16.3","16.4","17.4","18.4","19.7","21.3","22.2","22.10","22.19","22.29","22.30","22.47","24.4","24.6","24.11","24.12","24.13","24.14","25.1","26.2","26.4","26.29","26.30","26.32","26.43"],"var":["0.2","0.4","2.0","4.0","5.45","6.2","6.3","6.4","6.5","7.3","7.4","7.5","8.2","8.3","8.4","8.5","9.3","9.7","9.8","9.9","10.2","12.0","14.0","16.2","16.3","16.4","16.5","17.3","17.4","17.5","18.2","18.3","18.4","18.5","19.4","19.7","19.8","19.9","21.3","22.2","22.29","22.30","24.13","24.14","24.18","25.3","25.4","26.2","26.29","26.30"],"proxy":["0.3"],"方法用于代理":["0.3"],"hover":["0.3"],"方法用于代理自定义的":["0.3"],"div":["0.3","0.6","0.8","0.9","0.10","0.13","0.15","0.16","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.11","1.12","2.41","3.1","3.2","3.4","3.5","3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.15","3.16","3.17","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.29","3.30","3.32","3.33","5.6","5.7","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.15","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.24","5.25","5.27","5.30","5.31","5.32","5.34","5.35","5.36","5.39","5.41","5.43","5.44","5.46","5.47","9.1","9.3","10.5","12.0","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.20","12.22","12.24","12.26","12.27","12.28","12.29","12.30","12.31","12.34","12.39","12.40","12.41","15.1","15.2","15.3","15.12","15.16","15.20","15.22","15.28","15.33","15.37","15.44","15.45","15.46","15.47","19.3","20.4","22.1","22.7","22.10","22.19","22.31","22.32","22.35","22.39","22.43","22.47","23.4","24.8","24.16","26.1","26.3","26.4","26.5","26.7","26.8","26.9","26.10","26.13","26.17","26.19","26.21","26.26","26.35","26.39","26.43","26.45","26.46","26.47","26.50"],"classname":["0.4","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.14","0.15","0.16","1.1","1.2","1.3","1.4","1.5","1.6","1.7","1.8","1.9","1.10","1.12","2.41","3.1","3.2","3.3","3.4","3.5","3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.16","3.17","3.18","3.19","3.20","3.22","3.23","3.26","3.27","3.29","3.30","3.32","3.33","5.1","5.2","5.3","5.6","5.7","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.24","5.25","5.27","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.43","5.44","5.46","5.47","9.1","9.3","10.1","10.5","12.0","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.15","12.17","12.18","12.20","12.22","12.24","12.26","12.28","12.29","12.30","12.31","12.40","15.1","15.2","15.3","15.12","15.16","15.20","15.22","15.28","15.37","15.44","15.45","15.46","19.3","22.1","22.7","22.10","22.19","22.31","22.32","22.35","22.39","22.43","22.47","24.8","24.10","24.16","26.1","26.3","26.4","26.5","26.7","26.9","26.10","26.13","26.17","26.19","26.31","26.32","26.35","26.39","26.43","26.45","26.46","26.47","26.50"],"run":["0.4","0.5","0.6","0.7","0.10","0.13","0.14","0.15","0.16","0.17","1.1","1.6","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.16","2.19","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.40","2.41","3.3","3.5","3.6","3.7","3.8","3.9","3.10","3.11","3.17","3.22","3.29","3.30","3.32","5.1","5.2","5.3","5.8","5.10","5.12","5.14","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.25","5.27","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.44","5.46","5.47","9.1","9.3","10.1","10.2","10.5","12.0","12.6","12.7","12.8","12.10","12.20","12.22","12.28","12.29","12.30","12.31","15.1","15.2","15.3","15.12","15.16","15.20","15.28","15.37","15.44","15.45","19.3","22.1","22.7","22.10","22.19","22.30","22.31","22.32","22.35","22.43","22.47","24.8","24.10","24.16","26.1","26.4","26.5","26.7","26.10","26.19","26.31","26.32","26.35","26.39","26.43","26.47","26.50"],"art":["0.4","0.12","2.0","5.11","5.13","5.45","6.2","6.3","6.4","6.5","7.3","7.4","7.5","8.2","8.3","8.5","9.3","9.4","9.7","9.8","9.9","10.2","12.0","14.0","15.11","15.13","16.2","16.3","16.4","16.5","17.3","17.4","17.5","18.2","18.3","18.5","19.4","19.7","19.8","19.9","22.2","23.10","24.14","24.18","25.3","25.4","26.2"],"new":["0.4","2.0","4.0","6.2","6.3","6.4","6.5","7.3","7.4","7.5","8.3","9.3","9.4","9.7","9.8","9.9","10.2","12.0","14.0","16.2","16.3","16.4","16.5","17.3","17.4","17.5","18.3","19.4","19.7","19.8","19.9","21.2","22.2","24.14","24.18","25.3","26.2"],"artplayer":["0.4","2.0","4.0","5.5","6.2","6.3","6.4","6.5","7.3","7.4","7.5","9.3","9.4","9.8","9.9","12.0","14.0","16.2","16.3","16.4","16.5","17.3","17.4","17.5","19.4","19.8","19.9","20.3","20.6","21.4","22.2","23.3","23.4","23.6","23.9","23.10","24.6","24.7","24.9","24.10","24.11","24.12","24.13","24.14","24.15","24.17","26.2"],"container":["0.4","2.0","4.0","6.4","6.5","7.3","7.5","9.3","9.4","9.8","9.9","12.0","14.0","16.4","16.5","17.3","17.5","19.4","19.8","19.9","20.4","20.5","22.2","22.11","23.5","24.18","26.11"],"方法用于更新":["0.6"],"对象":["0.6"],"方法用于动态更新层":["0.8"],"show":["0.8","0.9","0.10","0.12","0.16","10.7"],"属性用于设置是否显示全部层":["0.8"],"toggle":["0.8","0.9","0.10","0.16","22.18"],"方法用于切换是否显示全部层":["0.8"],"方法用于动态更新控制器":["0.9"],"属性用于设置是否显示全部控制器":["0.9"],"方法用于切换是否显示全部控制器":["0.9"],"属性用于设置是否显示全部菜单":["0.10"],"方法用于切换是否显示全部菜单":["0.10"],"方法设置当前字幕地址和选项":["0.11"],"texttrack":["0.11"],"获取当前字幕轨":["0.11"],"activecues":["0.11"],"获取当前活跃的字幕列表":["0.11"],"cues":["0.11"],"通过":["0.12"],"控制面板的显示与隐藏":["0.12"],"触发的事件名为":["0.12"],"属性用于切换是否显示加载层":["0.13"],"属性用于切换是否显示遮罩层":["0.15"],"属性用于设置是否显示全部设置项":["0.16"],"方法用于切换是否显示全部设置项":["0.16"],"字符串":["1.11"],"app":["2.0","4.0","7.2","7.5","9.3","9.4","9.8","9.9","12.0","14.0","17.2","17.5","19.4","19.8","19.9","22.2","24.18"],"url":["2.0","4.0","5.11","7.2","7.5","9.4","9.9","12.0","14.0","15.11","15.13","17.2","17.5","19.4","19.9","22.36","22.37","24.18","26.36","26.37"],"assets":["2.0","4.0","7.2","8.2","8.3","8.4","8.5","9.4","9.9","12.0","14.0","17.2","18.2","18.3","18.4","18.5","19.4","19.9","22.2","22.29","24.18","26.29"],"sample":["2.0","4.0","7.2","8.2","8.3","8.4","8.5","9.4","9.9","12.0","14.0","17.2","18.2","18.3","18.4","18.5","19.4","19.9","22.29","24.18","26.29"],"mp4":["2.0","4.0","7.2","14.0","17.2","24.18"],"on":["2.0","4.0","12.16","19.6","22.21","22.45"],"canplay":["2.0"],"事件":["2.41"],"浏览器可以播放媒体文件了":["2.42"],"浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束":["2.43"],"offlineaudiocontext":["2.44"],"duration":["2.45","13.12","13.13","15.39"],"媒体内容变为空":["2.46"],"例如":["2.46"],"视频停止播放":["2.47"],"获取媒体数据时出错":["2.48"],"media":["2.49","12.59","13.34"],"已加载元数据":["2.50"],"播放已暂停":["2.51"],"播放已开始":["2.52"],"由于缺乏数据而暂停或延迟后":["2.53"],"在浏览器加载资源时周期性触发":["2.54"],"播放速率发生变化":["2.55"],"跳帧":["2.56","2.57"],"用户代理":["2.58"],"媒体数据加载已暂停":["2.59"],"currenttime":["2.60"],"音量发生变化":["2.61"],"由于暂时缺少数据":["2.62"],"可以打印出视频全部的内置事件":["3.1"],"默认关闭":["3.1"],"默认为":["3.4","3.8","3.9","3.10","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.27","3.31","3.34","5.4"],"单位为毫秒":["3.15","3.21","3.24"],"true":["3.18","3.19","3.31","3.32","3.34","5.4","13.34","26.21","26.28","26.45"],"false":["3.20","3.33","13.33","26.8","26.9","26.13","26.18","26.20","26.23","26.24","26.26","26.46","26.48"],"是否把播放器挂在在":["3.31"],"元素下":["3.31"],"目前主要用于进度条的平滑效果":["3.33"],"属性并调用":["3.34"],"load":["3.34","5.5","13.34","15.5"],"以主动释放媒体资源":["3.34"],"开启后可以在单页应用或频繁创建":["3.34"],"销毁播放器的场景下":["3.34"],"dosomething":["4.0","14.0"],"video":["4.0","5.34","5.38","5.40","7.2","9.4","9.9","10.12","14.0","15.1","15.2","15.7","15.8","15.9","15.10","15.14","15.15","15.17","15.23","15.25","15.27","15.33","15.34","15.35","17.2","19.4","19.9","22.4","22.14","22.15","22.16","24.18","26.41"],"plugins":["4.0"],"ready":["4.0","12.2","12.53","22.4"],"可以在实例化之后再加载插件的函数":["4.0"],"销毁播放器":["5.4"],"接受一个参数表示是否销毁后同时移除播放器的":["5.4"],"html":["5.4","20.12","22.39","23.12","26.27","26.33"],"常用于在单页应用中手动释放媒体资源或重新初始化视频标签":["5.5"],"注意":["5.5"],"全局配置":["5.5"],"remove":["5.5","10.8","10.9","10.10","10.14","10.16"],"视频时间跳转":["5.6"],"单位秒":["5.6","5.7","5.8","26.34"],"视频时间快进":["5.7"],"视频时间快退":["5.8"],"设置和获取视频音量":["5.9"],"范围在":["5.9","26.25"],"string":["5.10","6.1","7.1","8.1","11.11","16.1","18.1","22.36","22.37","26.33","26.34","26.36","26.37"],"设置和获取视频地址":["5.10"],"类似":["5.11","5.12","5.13","5.15","5.42"],"但会执行一些优化操作":["5.11","5.12"],"switchurl":["5.13","15.13"],"但会带上之前的播放进度":["5.13"],"设置和获取视频是否静音":["5.14"],"设置和获取视频当前时间":["5.15"],"设置时间时和":["5.15"],"seek":["5.15"],"但它不会触发额外的事件":["5.15"],"返回的是一个":["5.18","5.19"],"promise":["5.18","5.19"],"设置和获取播放器窗口全屏":["5.20"],"设置和获取播放器网页全屏":["5.21"],"设置和获取播放器画中画模式":["5.22"],"只有在视频播放前才能看到海报效果":["5.23"],"boolean":["5.24","6.1","8.1","9.5","19.5","26.33"],"设置和获取播放器迷你模式":["5.24"],"获取视频是否正在播放中":["5.25"],"支持":["5.26","5.30"],"standard":["5.26","15.26"],"正常":["5.26"],"mini":["5.26","22.12","22.26"],"迷你窗":["5.26"],"pip":["5.26"],"type":["5.29","11.10","20.9","23.9","23.10"],"getter":["5.29"],"这些属性是对":["5.29"],"rect":["5.29","15.29"],"的快捷访问":["5.29"],"设置和获取播放器翻转":["5.30"],"normal":["5.30","13.30"],"horizontal":["5.30","13.30"],"vertical":["5.30"],"设置和获取播放器播放速度":["5.31"],"设置和获取播放器长宽比":["5.32"],"元素的属性":["5.34"],"动态获取和设置视频类型":["5.35"],"动态获取和设置播放器主题颜色":["5.36"],"常配合":["5.38","5.40"],"timeupdate":["5.38","5.40"],"事件使用":["5.38","5.40"],"通常与":["5.39"],"loaded":["5.39"],"一起使用":["5.39","26.40"],"用于展示缓冲进度细节":["5.39"],"和":["5.41","26.6","26.14","26.15","26.16"],"removeeventlistener":["5.41","15.41"],"当使用":["5.41"],"来处理事件":["5.41"],"播放器销毁时也会自动销毁该事件":["5.41"],"document":["5.42","12.41","15.42"],"queryselector":["5.42","15.42"],"但被查询的对象局限于当前播放器内":["5.42"],"可以避免同类名的错误":["5.42"],"元素":["5.43"],"动态设置缩略图":["5.46"],"number":["5.47","9.2","9.3","17.1","19.3","22.34","22.36","26.34","26.36"],"动态设置字幕偏移":["5.47"],"是否禁用组件":["6.1","7.1","8.1"],"name":["6.1","7.1","7.2","8.1","14.0","16.1","17.2","18.1","22.37","26.37"],"组件唯一名称":["7.1"],"用于标记类名":["7.1"],"index":["7.1","7.2","17.1","17.2","24.6","24.9","24.11","24.12","24.13","24.14"],"controls":["7.2","17.2"],"your":["7.2","17.2","22.43"],"button":["7.2","17.2","22.18","22.44","22.49"],"img":["8.2","8.3","8.4","8.5","18.2","18.3","18.4","18.5","22.29","26.29"],"layer":["8.2","8.3","8.4","8.5","10.8","12.35","12.36","18.2","18.3","18.4","18.5"],"png":["8.2","8.3","8.5","18.2","18.3","18.5"],"aspectratio":["9.1"],"subtitleoffset":["9.1"],"icon":["9.2","19.2","19.5"],"元素的图标":["9.2","9.5","9.6"],"onclick":["9.2","19.2"],"function":["9.2","9.5","9.6","11.9","19.2","19.3","19.6","20.5","22.14","22.15","22.16","22.17","23.5","24.6"],"元素点击事件":["9.2"],"width":["9.2","19.3"],"列表宽度":["9.3"],"tooltip":["9.3","9.5","9.6","19.3"],"提示文本":["9.3","9.6"],"switch":["9.5","19.5"],"按钮默认状态":["9.5"],"onswitch":["9.5"],"按钮切换事件":["9.5"],"range":["9.6","15.9"],"array":["9.6","19.6"],"默认状态数组":["9.6"],"onrange":["9.6","19.6"],"完成时触发的事件":["9.6"],"onchange":["9.6"],"变化时触发的事件":["9.6"],"here":["10.0","13.0"],"following":["10.3"],"methods":["10.3"],"to":["10.3","10.13","10.14","10.15","12.0","12.2","13.0","15.5","15.6","15.11","15.13","15.29","15.41","15.42","18.1","20.13","22.4","22.9","22.13","22.14","22.18","22.20","22.23","22.24","22.28","22.38","22.41","22.44","22.45","22.46","22.48","22.49"],"handle":["10.3","15.41"],"will":["10.3","22.8","22.38"],"also":["10.3"],"be":["10.3","11.1"],"automatically":["10.3","12.18","12.19","15.33","15.41","22.38"],"destroyed":["10.3","12.6"],"is":["10.3","10.13","10.15","12.1","12.3","12.5","12.6","12.9","12.10","12.11","12.18","12.19","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.53","13.3","13.5","13.28","13.29","13.30","13.33","13.34","15.14","15.23","15.25","15.41","22.1","22.4","22.40"],"a":["10.4","10.7","10.8","10.9","12.26","12.27","12.56","12.57","13.6","13.7","13.15","15.4","15.6","15.18","15.19","22.44","22.46","22.51"],"get":["10.4","15.9","15.10","15.35","15.36"],"retrieve":["10.4","10.6"],"del":["10.4"],"the":["10.5","12.11","12.44","12.49","12.55","12.60","12.61","13.31","13.32","15.7","15.8","15.9","15.10","15.14","15.15","15.17","15.20","15.21","15.23","15.24","15.25","15.26","15.27","15.30","15.31","15.32","15.34","15.35","15.36","15.41","15.42","15.43","16.1","18.1","19.1","20.10","22.14","22.15","22.16","22.17","22.18","22.20","22.21","22.23","22.24","22.42","22.43","22.48","22.49","22.50"],"player":["10.5","11.6","12.11","12.12","12.13","12.28","13.2","13.31","13.32","13.34","15.4","15.20","15.21","15.22","15.24","15.26","15.30","15.31","15.32","15.36","15.43","20.5","22.1","22.3","22.4","22.6","22.11","22.12","22.22","22.23","22.24","22.48","23.5"],"an":["10.6","15.17"],"value":["10.6"],"update":["10.6","10.10","10.16"],"has":["10.7","12.47","12.62"],"property":["10.7","10.13","10.15","11.1","15.33","22.33","22.34","22.36","22.37"],"for":["10.7","10.17","11.6","11.7","12.1","12.46","13.10","13.11","13.12","13.13","13.15","13.16","13.21","13.22","13.23","13.24","13.25","13.27","17.1","20.9","20.11","21.2","22.3","22.22"],"displaying":["10.7"],"control":["10.9","22.17","22.33"],"items":["10.10","10.16"],"returns":["10.11"],"current":["10.11","10.12","15.5","15.15","15.17","15.18","15.19","15.26"],"style":["10.11"],"method":["10.11","10.17"],"of":["10.11","10.12","11.2","11.3","11.4","11.8","11.12","13.4","13.14","15.15","15.17","15.18","15.19","15.34","17.1","19.3","19.5","20.11","22.40"],"status":["10.12"],"and":["10.12","12.2","15.3","15.5","15.9","15.10","15.24","15.28","15.30","15.31","15.32","15.33","15.34","15.35","15.36","15.41","20.12","22.4","22.39","22.41"],"such":["10.12","20.10","22.22"],"as":["10.12","22.22"],"used":["10.13","10.14","10.15","15.5","15.39","17.1"],"set":["10.13","10.15","12.18","12.19","15.10","15.33","15.34","15.35","15.36","15.46","15.47"],"whether":["10.13","10.15","13.19","13.20","15.4","15.14","15.25","22.9","22.13","22.28"],"display":["10.13","10.15","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.42","22.44","22.49"],"hotkeys":["10.14"],"only":["10.17","15.23","22.5","22.26"],"one":["10.17"],"add":["10.17","22.43","22.46"],"dynamically":["10.17","15.46","15.47"],"adding":["10.17"],"this":["11.1","22.8"],"can":["11.1","12.42","13.1","15.33","20.10","20.11","22.51"],"useful":["11.1","22.27"],"information":["11.2","15.28"],"environment":["11.3"],"variables":["11.3","15.44","22.50"],"timestamp":["11.4"],"default":["11.5","11.12","13.3","13.8","13.9","13.18","13.28","13.29","13.30","13.32","13.33","13.34","19.5","19.6","20.5","23.5"],"configuration":["11.5"],"utility":["11.6"],"functions":["11.6"],"validation":["11.7","11.9"],"schema":["11.7"],"constructor":["11.8"],"detection":["11.10"],"required":["11.11"],"options":["11.12","13.30","20.9"],"first":["12.1"],"becomes":["12.2"],"play":["12.2"],"paused":["12.3"],"starts":["12.4"],"playing":["12.4","12.42"],"pressed":["12.5"],"gains":["12.7"],"loses":["12.8"],"focus":["12.8"],"double":["12.9","13.17","13.18","13.19"],"clicked":["12.9","12.10"],"while":["12.11","12.48"],"loading":["12.11"],"or":["12.12","12.21","12.23","12.24","12.25","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","15.14","15.21"],"leaves":["12.12"],"moves":["12.13"],"over":["12.13"],"s":["12.14","12.19","15.20","15.21","15.22","15.26","15.30","15.31","15.32","15.33","15.36","15.43","22.6","22.7","22.11","22.41"],"dimensions":["12.14","15.28","22.11"],"change":["12.14"],"enters":["12.15","22.12"],"viewport":["12.15"],"changes":["12.16","12.17","12.40"],"mobile":["12.16"],"devices":["12.16"],"aspect":["12.17","15.32","22.16"],"ratio":["12.17","22.16"],"height":["12.18","15.33"],"size":["12.19","15.27"],"flipped":["12.20"],"exits":["12.21","12.23","12.24","12.25"],"windowed":["12.21"],"mode":["12.21","12.23","12.24","15.22","22.8","22.12","22.27","22.28","24.5"],"error":["12.22"],"occurs":["12.22"],"web":["12.23","15.21","22.24"],"fullscreen":["12.23","22.48"],"picture":["12.25","15.22","22.20"],"in":["12.25","12.28","13.4","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.22","15.6","15.8","15.22","15.39","22.17","22.20","22.33","22.38","22.43","22.48","22.50"],"takes":["12.26"],"performs":["12.27","15.12"],"time":["12.27","15.6","15.7","15.8","15.15","22.34","26.34"],"panel":["12.32","13.5","13.6","13.7","13.22","19.1"],"shown":["12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39"],"hidden":["12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39"],"menu":["12.37","13.3"],"bar":["12.38","22.17","22.26","22.32","22.33","22.34"],"state":["12.40","15.20","15.30","19.5","19.6"],"event":["12.41","13.8","13.9","13.10","13.17","15.41","19.3","19.6"],"from":["12.41","15.38","15.40","20.12","21.0","21.4","22.25","23.9","25.2"],"start":["12.42","22.9"],"browser":["12.43"],"estimates":["12.43"],"triggered":["12.45","19.6","22.4"],"become":["12.46"],"empty":["12.46"],"example":["12.46"],"playback":["12.47","12.51","12.52","12.62","15.15","15.31","22.13","22.15"],"occurred":["12.48"],"metadata":["12.50","26.38"],"fired":["12.54"],"user":["12.58"],"agent":["12.58"],"refer":["13.0"],"which":["13.1","22.5"],"print":["13.1","13.32"],"all":["13.1"],"built":["13.1","22.43","22.50"],"context":["13.3"],"notification":["13.4"],"messages":["13.4"],"milliseconds":["13.4","13.8","13.9","13.17","13.22"],"settings":["13.5","13.6","13.7","19.1"],"pixels":["13.5","13.10"],"view":["13.10"],"count":["13.11"],"feature":["13.12","13.13","22.47"],"automatic":["13.14","13.15"],"reconnection":["13.14","13.15"],"attempts":["13.14"],"when":["13.14","13.15","15.11","15.12","15.41","22.4","22.5","22.12","22.22"],"connection":["13.15"],"delay":["13.16","13.21","13.24"],"bottom":["13.16","22.17","22.33"],"click":["13.17","13.18","13.19","19.2","19.3"],"toggles":["13.18","13.19","13.20"],"single":["13.20"],"rotation":["13.21"],"speed":["13.23","13.25","22.15"],"multiplier":["13.23","13.25"],"long":["13.23","13.24","22.46"],"press":["13.23","13.24","22.46"],"left":["13.25"],"right":["13.25"],"adjustment":["13.26"],"via":["13.26","13.27"],"keyboard":["13.26","13.27"],"shortcuts":["13.26","13.27"],"seeking":["13.27"],"rates":["13.28"],"ratios":["13.29"],"under":["13.31"],"element":["13.31","15.34"],"requestanimationframe":["13.33"],"currently":["13.33","15.25","22.3","22.6","22.42"],"it":["13.33","19.1","22.38"],"actively":["13.34"],"release":["13.34","15.5"],"resources":["13.34","21.0"],"destroying":["13.34"],"myplugin":["14.0"],"console":["14.0"],"info":["14.0"],"return":["14.0","22.51"],"something":["14.0"],"pause":["15.3"],"accepts":["15.4"],"indicating":["15.4"],"src":["15.5"],"calls":["15.5"],"once":["15.5"],"commonly":["15.5"],"manually":["15.5","20.10"],"specific":["15.6"],"fast":["15.7"],"seconds":["15.8","15.39"],"similar":["15.11","15.13","15.42"],"setting":["15.11","15.12","15.15"],"but":["15.12","15.13","15.42"],"some":["15.12"],"optimization":["15.12"],"operations":["15.12"],"quality":["15.13"],"gets":["15.14","15.21","15.24","15.30","15.31","15.32"],"frame":["15.17"],"screenshot":["15.18","15.19"],"window":["15.20","22.23"],"effect":["15.23","22.22"],"visible":["15.23"],"sets":["15.24"],"supported":["15.26"],"values":["15.26"],"adapts":["15.27"],"its":["15.27"],"coordinate":["15.28"],"these":["15.29"],"properties":["15.29"],"provide":["15.29"],"quick":["15.29"],"access":["15.29"],"calculate":["15.33"],"attributes":["15.34"],"buffered":["15.38"],"ranging":["15.38","15.40","22.25"],"often":["15.38","15.40","22.11"],"typically":["15.39"],"alongside":["15.39"],"using":["15.41"],"search":["15.42"],"css":["15.44","22.50"],"subtitle":["15.47"],"offset":["15.47","22.25"],"component":["16.1","18.1"],"unique":["16.1","17.1","18.1"],"class":["17.1"],"marking":["17.1"],"comes":["19.1"],"with":["19.1","22.40","22.43"],"four":["19.1"],"elements":["19.3"],"onselect":["19.3"],"text":["19.3","26.34"],"item":["19.5"],"usage":["20.0"],"npm":["20.1","23.1","24.2"],"install":["20.1","23.1","24.2"],"jsdelivr":["20.2","23.2"],"net":["20.2","23.2","24.3"],"https":["20.2","23.2","24.3"],"head":["20.3","23.3"],"title":["20.3","23.3"],"demo":["20.3"],"meta":["20.3"],"charset":["20.3"],"template":["20.4","23.4"],"ref":["20.4"],"export":["20.5","23.5"],"option":["20.5","23.5"],"getinstance":["20.5","23.5"],"rest":["20.5","23.5"],"const":["20.5","23.5"],"d":["20.6"],"import":["20.8","20.10","23.8","23.10","25.2"],"ts":["20.9","26.40"],"cases":["20.10"],"you":["20.10","20.11","20.13","22.27"],"types":["20.10"],"variable":["20.10"],"version":["20.11","20.12","21.0","23.11"],"chrome":["20.11"],"last":["20.11"],"starting":["20.12","21.0"],"not":["20.13"],"always":["20.13"],"accurate":["20.13"],"sometimes":["20.13"],"may":["20.13"],"want":["20.13","22.27"],"adjust":["20.13","22.38"],"bundled":["21.0","21.2"],"multilingual":["21.0"],"are":["21.1"],"en":["21.1","26.42"],"zh":["21.1","21.4","25.4","26.42"],"cn":["21.1","25.1"],"contributions":["21.2"],"welcome":["21.2"],"i18n":["21.4","25.4"],"tw":["21.4","25.4"],"mounted":["22.1"],"identifier":["22.3"],"successfully":["22.4"],"initialized":["22.4"],"image":["22.5","22.36"],"appears":["22.5","22.25"],"color":["22.6","24.5"],"live":["22.8"],"streaming":["22.8"],"fill":["22.11"],"entire":["22.11"],"multiple":["22.21"],"players":["22.21"],"exist":["22.21"],"page":["22.21"],"ui":["22.22","26.22"],"enabled":["22.22"],"overlays":["22.22"],"5s":["22.25","26.25"],"progress":["22.26","22.34"],"that":["22.26"],"side":["22.27"],"rendering":["22.27"],"mount":["22.27"],"if":["22.27"],"use":["22.28"],"menus":["22.31"],"list":["22.33"],"description":["22.33","22.34","22.36","22.37"],"thumbnail":["22.36"],"safari":["22.38","26.38"],"supports":["22.39"],"strings":["22.39"],"htmlelement":["22.39","26.39"],"together":["22.40"],"customtype":["22.40"],"by":["22.40"],"determined":["22.40"],"suffix":["22.40"],"delegates":["22.41"],"decoding":["22.41"],"third":["22.41","22.51"],"party":["22.41","22.51"],"tolowercase":["22.42","26.42"],"language":["22.43"],"enable":["22.45"],"events":["22.45"],"rotate":["22.48"],"modify":["22.50"],"htmlcanvaselement":["22.51","26.51"],"useref":["23.5"],"let":["23.10"],"null":["23.10"],"参数":["23.10"],"对于古老的浏览器":["23.11"],"可以使用":["23.11"],"legacy":["23.11"],"文件":["23.11"],"从":["23.12"],"开始":["23.12"],"所以在":["23.13"],"开始新增了一个":["23.13"],"就可以发送一个弹幕":["24.4"],"其余都是非必要参数":["24.4"],"弹幕文本":["24.4"],"弹幕上下边距":["24.5"],"支持像素数字和百分比":["24.5"],"opacity":["24.5"],"弹幕透明度":["24.5"],"ffffff":["24.5"],"默认弹幕颜色":["24.5"],"可以被单独弹幕项覆盖":["24.5"],"data":["24.6","24.7","24.10","24.15","24.17"],"libs":["24.6","24.7","24.9","24.10","24.11","24.15","24.17"],"uncompiled":["24.6","24.7","24.9","24.10","24.11","24.12","24.15","24.17"],"plugin":["24.6","24.7","24.9","24.10","24.11","24.12","24.13","24.14","24.15","24.17"],"danmuku":["24.6","24.9","24.11","24.12","24.13","24.14","24.15","24.17"],"保存到数据库":["24.6"],"savedanmu":["24.6"],"bilibili":["24.8"],"网站的弹幕格式一致":["24.8"],"theme":["24.16"],"设置成":["24.16"],"light":["24.16"],"否则会看不清":["24.16"],"无需手动导入":["25.1"],"group":["25.2"],"id":["25.2"],"容器":["26.1"],"目前只用于记忆播放":["26.3"],"autoplayback":["26.3"],"事件一样":["26.4"],"只会出现在播放器初始化且未播放的状态下":["26.5"],"播放器主题颜色":["26.6"],"目前用于":["26.6"],"进度条":["26.6"],"播放器的默认音量":["26.7"],"使用直播模式":["26.8"],"会隐藏进度条和播放时间":["26.8"],"是否默认静音":["26.9"],"播放器的尺寸默认会填充整个":["26.11"],"容器尺寸":["26.11"],"所以经常出现黑边":["26.11"],"该值能自动调整播放器尺寸以隐藏黑边":["26.11"],"当播放器滚动到浏览器视口以外时":["26.12"],"自动进入":["26.12"],"迷你播放":["26.12"],"模式":["26.12","26.28"],"是否循环播放":["26.13"],"是否显示视频翻转功能":["26.14"],"目前只出现在":["26.14"],"设置面板":["26.14","26.15","26.16","26.18","26.22","26.25"],"右键菜单":["26.14","26.15","26.16","26.22"],"是否显示视频播放速度功能":["26.15"],"会出现在":["26.15","26.16"],"是否显示视频长宽比功能":["26.16"],"是否在底部控制栏里显示":["26.17","26.18","26.20"],"视频截图":["26.17"],"功能":["26.17"],"的开关按钮":["26.18","26.20"],"画中画":["26.20"],"假如页面里同时存在多个播放器":["26.21"],"是否只能让一个播放器播放":["26.21"],"的背景虚化效果":["26.22"],"开启后":["26.22"],"是否在底部控制栏里显示播放器":["26.23","26.24"],"窗口全屏":["26.23"],"按钮":["26.23","26.24","26.49"],"网页全屏":["26.24"],"出现在":["26.25"],"迷你进度条":["26.26"],"只在播放器失去焦点后且正在播放时出现":["26.26"],"挂载模式":["26.27"],"假如你希望在播放器挂载前":["26.27"],"就提前渲染好播放器所需的":["26.27"],"时有用":["26.27"],"你可以通过":["26.27"],"在移动端是否使用":["26.28"],"类型":["26.33"],"描述":["26.33","26.34","26.37"],"默认画质":["26.33"],"画质名字":["26.33"],"高亮时间":["26.34"],"高亮文本":["26.34"],"预览图地址":["26.36"],"预览图数量":["26.36"],"column":["26.36"],"字幕名字":["26.37"],"字幕地址":["26.37"],"字幕类型":["26.37"],"可选":["26.37"],"preload":["26.38"],"中会自动调整为":["26.38"],"字符串和":["26.39"],"默认视频的格式就是视频地址的后缀":["26.40"],"如":["26.40"],"m3u8":["26.40"],"mkv":["26.40"],"但有时候视频地地址没有正确的后缀":["26.40"],"进行匹配":["26.41"],"把视频解码权交给第三方程序进行处理":["26.41"],"处理的函数能接收三个参数":["26.41"],"视频":["26.41"],"dom":["26.41"],"默认显示语言":["26.42"],"目前支持":["26.42"],"是否在移动端显示一个":["26.44"],"锁定按钮":["26.44"],"用于隐藏底部":["26.44"],"控制栏":["26.44"],"是否在移动端启用视频元素上的手势事件":["26.45"],"是否在移动端添加长按视频快进功能":["26.46"],"是否在移动端的网页全屏时":["26.48"],"根据视频尺寸和视口尺寸":["26.48"],"旋转播放器":["26.48"],"是否显示":["26.49"],"当前只有部分浏览器支持该功能":["26.49"],"函数可以返回一个第三方的":["26.51"],"或者":["26.51"],"htmlvideoelement":["26.51"],"例如可以代理一个已经存在的":["26.51"]},{"0":["9.6","13.25","13.26","15.9"],"1":["9.6","13.26","15.9","19.6","20.10"],"2":["13.28","22.1","24.5","26.1"],"3":["13.23","20.7","20.10","23.7"],"4":["22.7","22.10","22.19","22.31","22.32","22.39","22.43","25.1","26.10","26.19","26.31","26.32","26.39","26.47","26.50"],"5":["9.6","13.12","13.27","19.6","22.47","26.47"],"6":["2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40"],"7":["2.19","2.21","2.23","2.25","2.26","5.16","5.28","5.33","15.16","15.28","15.33","22.4","26.4","26.39"],"8":["2.17","2.20","5.1","5.14","5.21","5.31","5.32","5.34","5.35","5.36","5.44","12.20","15.44","20.3"],"9":["2.29","2.30","2.31","5.12","5.20","5.22","5.23","5.37","12.29","12.30","12.31","13.29","15.12","15.20","15.22","15.37","22.43","26.4"],"10":["2.6","2.18","2.24","7.5","9.6","13.11","17.5","24.4"],"11":["5.2","5.3","5.21","5.33","12.28","15.2","15.33","23.11"],"12":["22.31","26.31"],"15":["22.35","26.35"],"16":["22.32","26.32"],"17":["4.0","14.0"],"25":["13.28"],"29":["15.45"],"35":["13.7"],"50":["13.10"],"200":["13.6","13.8","13.9","13.21"],"250":["9.3","13.5","19.3"],"300":["13.17"],"1000":["13.22","13.24","24.6"],"2000":["13.4"],"3000":["13.13"],"是指挂载在":["0.0","1.0","5.0"],"js":["0.1","0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.15","0.16","1.1","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.19","2.20","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.3","3.5","3.6","3.7","3.8","3.9","3.10","3.17","3.28","3.29","3.30","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.12","5.13","5.14","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.23","5.25","5.27","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.41","5.44","5.46","5.47","9.1","9.5","10.1","10.4","10.5","10.6","10.14","12.2","12.6","12.17","12.20","12.22","12.24","12.28","12.29","12.30","12.31","15.1","15.2","15.3","15.12","15.20","15.22","15.28","15.33","15.37","15.44","15.46","19.3","19.6","21.0","22.1","22.4","22.7","22.31","22.32","22.35","22.39","22.43","24.7","24.9","24.10","24.15","24.16","24.17","25.0","26.1","26.7","26.10","26.19","26.31","26.34","26.35","26.39","26.47","26.50"],"var":["0.1","0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.14","0.15","0.16","0.17","2.1","2.2","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.28","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","5.2","5.3","5.12","5.14","5.16","5.20","5.22","5.23","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.44","5.46","9.5","10.1","10.5","10.14","12.22","12.29","12.30","12.31","15.12","15.16","15.20","15.22","15.33","15.44","15.45","19.3","21.4","22.1","22.7","22.10","22.19","22.31","22.32","22.43","22.47","24.6","24.9","24.10","24.11","24.12","25.1","25.2","26.1","26.4","26.10","26.19","26.31","26.32","26.39","26.43","26.47"],"art":["0.1","0.2","0.5","0.6","0.7","0.10","0.14","0.16","0.17","2.2","2.6","2.11","2.12","2.16","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.28","2.29","2.30","2.31","2.39","5.16","5.20","5.22","5.23","5.28","5.33","5.44","8.4","9.5","10.1","10.5","12.31","15.16","15.20","15.22","15.33","15.44","15.45","18.4","19.3","20.5","20.10","21.3","21.4","22.1","22.7","22.10","22.19","22.29","22.30","22.31","22.32","22.43","22.47","23.5","24.6","24.11","24.12","24.13","25.1","25.2","26.1","26.4","26.19","26.29","26.30","26.31","26.32","26.35","26.39","26.41","26.43","26.47"],"new":["0.1","0.2","0.6","0.7","0.14","0.16","0.17","2.2","2.6","2.17","2.18","2.20","2.22","2.24","2.28","2.29","2.30","2.31","5.12","5.23","5.44","5.45","8.2","8.4","8.5","10.1","15.12","15.16","15.20","15.33","15.45","18.2","18.4","18.5","19.3","20.5","21.4","22.1","22.7","22.10","22.19","22.29","22.30","22.31","22.32","22.43","22.47","23.5","24.6","24.11","24.12","24.13","25.4","26.1","26.4","26.29","26.30","26.31","26.32","26.43"],"artplayer":["0.2","0.7","0.14","0.16","0.17","2.2","2.22","2.24","2.28","2.29","2.30","2.31","3.5","3.6","3.7","3.29","3.30","5.12","5.23","5.45","8.2","8.3","8.4","8.5","9.7","10.1","10.2","15.12","15.16","15.45","18.2","18.3","18.4","18.5","19.3","19.7","20.1","20.8","20.9","20.10","21.0","21.3","22.10","22.19","22.29","22.30","22.32","22.43","22.47","23.1","23.8","24.2","24.3","24.8","24.16","25.0","25.3","26.4","26.27","26.29","26.30","26.32","26.43"],"container":["0.2","0.3","0.14","0.17","2.2","2.28","5.12","5.45","6.2","6.3","7.4","8.2","8.3","8.4","8.5","9.7","10.2","15.12","15.16","15.45","16.2","16.3","17.4","18.2","18.3","18.4","18.5","19.3","19.7","21.4","22.10","22.19","22.29","22.30","22.32","22.43","22.47","23.4","23.9","24.6","24.11","24.12","24.13","24.14","25.3","25.4","26.2","26.4","26.29","26.30","26.32","26.43"],"app":["0.2","0.4","0.14","5.45","6.2","6.3","6.4","6.5","7.3","7.4","8.2","8.3","8.4","8.5","9.7","10.2","15.12","15.16","15.45","16.2","16.3","16.4","16.5","17.3","17.4","18.2","18.3","18.4","18.5","19.3","19.7","20.4","22.1","22.19","22.29","22.30","22.47","23.4","24.11","24.12","24.13","24.14","25.4","26.2","26.4","26.29","26.30","26.43"],"url":["0.2","0.4","5.45","6.2","6.3","6.4","6.5","7.3","7.4","8.2","8.3","8.5","9.3","9.7","9.8","10.2","15.16","15.45","16.2","16.3","16.4","16.5","17.3","17.4","18.2","18.3","18.5","19.3","19.7","19.8","22.29","22.30","22.33","22.40","22.47","24.12","24.13","24.14","26.29","26.30","26.33","26.41","26.43"],"classname":["0.3","0.11","0.12","1.11","3.15","3.21","3.24","3.25","3.28","3.31","5.4","5.15","5.26","5.30","5.38","5.39","5.40","5.41","5.42","9.2","9.5","10.4","10.6","10.7","10.14","10.17","11.6","12.1","12.2","12.11","12.12","12.13","12.14","12.16","12.19","12.21","12.23","12.25","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.41","13.2","13.3","13.4","13.5","13.6","13.7","13.8","13.9","13.10","13.11","13.17","13.18","13.22","13.28","13.29","13.30","13.32","15.6","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.24","15.25","15.27","15.30","15.31","15.32","15.33","15.34","15.35","15.36","15.41","15.43","15.47","19.5","22.4","22.9","22.13","22.17","22.25","22.34","22.42","22.50","26.6","26.8","26.12","26.14","26.15","26.16","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.27","26.28","26.33","26.34","26.38","26.40","26.42","26.44","26.48","26.49","26.51"],"run":["0.3","0.8","0.9","0.11","0.12","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.11","1.12","3.1","3.2","3.4","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.23","3.24","3.25","3.26","3.27","3.28","3.31","3.33","5.4","5.6","5.7","5.9","5.11","5.13","5.15","5.24","5.30","5.38","5.39","5.40","5.41","5.42","5.43","9.2","9.5","10.4","10.6","10.7","10.14","10.17","11.6","12.1","12.2","12.3","12.4","12.5","12.9","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.21","12.23","12.24","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.3","13.5","13.8","13.9","13.10","13.17","13.28","13.29","13.30","15.7","15.8","15.9","15.10","15.14","15.21","15.22","15.23","15.25","15.27","15.31","15.32","15.33","15.34","15.35","15.36","15.41","15.43","15.46","15.47","22.4","22.9","22.13","22.17","22.34","22.39","22.50","26.3","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.28","26.33","26.34","26.40","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"code":["0.3","0.8","0.9","0.10","0.11","0.12","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.12","2.41","3.1","3.2","3.4","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.31","3.32","3.33","5.4","5.6","5.7","5.8","5.9","5.10","5.11","5.13","5.15","5.18","5.19","5.24","5.30","5.38","5.39","5.40","5.41","5.42","5.43","5.47","9.1","9.2","9.5","10.4","10.6","10.7","10.14","10.17","11.6","12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.29","13.30","15.1","15.3","15.8","15.9","15.10","15.14","15.20","15.21","15.22","15.25","15.27","15.28","15.31","15.32","15.33","15.34","15.35","15.36","15.41","15.43","15.46","15.47","21.0","21.2","22.4","22.13","22.17","22.39","22.50","24.8","26.3","26.5","26.7","26.8","26.9","26.12","26.13","26.17","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.28","26.33","26.34","26.40","26.42","26.44","26.45","26.46","26.48","26.49"],"document":["0.3","22.1"],"assets":["0.4","5.45","6.2","6.3","6.4","6.5","7.3","7.4","7.5","9.3","9.7","9.8","10.2","15.45","16.2","16.3","16.4","16.5","17.3","17.4","17.5","19.3","19.7","19.8","22.30","22.47","24.12","24.13","24.14","26.2","26.30","26.43"],"sample":["0.4","5.45","6.2","6.3","6.4","6.5","7.3","7.4","7.5","9.3","9.8","10.2","16.2","16.3","16.4","16.5","17.3","17.4","17.5","19.3","19.8","22.2","22.30","24.13","24.14","26.2","26.30","26.43"],"video":["0.4","3.34","5.45","6.2","6.3","6.4","6.5","7.3","7.5","8.2","8.3","8.5","9.3","9.8","10.2","12.11","13.1","15.6","15.18","15.19","16.2","16.3","16.4","16.5","17.3","17.5","18.2","18.3","18.5","19.3","19.8","22.38","22.45","22.46","24.13","24.14","26.2","26.51"],"mp4":["0.4","6.3","6.4","6.5","7.3","7.5","8.2","8.3","8.5","9.3","9.4","9.8","9.9","10.2","12.0","16.3","16.4","16.5","17.3","17.5","18.2","18.3","18.5","19.3","19.4","19.8","19.9","22.2","24.14","26.2"],"test":["0.4"],"foo":["0.4"],"bar":["0.4","13.16","22.6","22.8","22.22"],"const":["0.4","9.6","19.6","23.9"],"获取整体的字幕列表":["0.11"],"div":["0.11","0.12","3.31","5.4","5.26","5.38","5.40","5.42","9.2","9.5","10.4","10.6","10.7","10.14","10.17","11.5","11.6","11.9","11.10","12.1","12.11","12.19","12.21","12.23","12.25","12.32","12.33","12.35","12.36","12.37","12.38","13.2","13.3","13.4","13.5","13.6","13.7","13.8","13.9","13.10","13.11","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.26","13.28","13.29","13.30","13.32","15.6","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.24","15.25","15.27","15.30","15.31","15.32","15.34","15.35","15.36","15.41","15.43","19.5","20.3","22.4","22.9","22.13","22.17","22.25","22.28","22.34","22.42","22.50","26.6","26.12","26.14","26.15","26.16","26.18","26.20","26.23","26.24","26.25","26.27","26.28","26.33","26.34","26.38","26.40","26.41","26.42","26.44","26.48","26.49","26.51"],"详见事件文档":["0.12"],"console":["1.1","2.0","12.0","24.18"],"info":["2.0","12.0","24.18"],"只监听一次事件":["2.0"],"但估计没有足够的数据来支撑播放到结束":["2.42"],"渲染完成":["2.44"],"属性的值改变时触发":["2.45"],"当这个":["2.46"],"因为":["2.47"],"或者资源类型不是受支持的媒体格式":["2.48"],"中的首帧已经完成加载":["2.49"],"播放准备开始":["2.53"],"seek":["2.56","2.57","12.56","12.57","13.25","15.15"],"user":["2.58","23.13"],"属性指定的时间发生变化":["2.60"],"播放已停止":["2.62"],"也是指挂载在":["3.0"],"构造函数":["3.0"],"减少视频资源占用":["3.34"],"如果你希望保留":["3.34"],"元素的状态":["3.34"],"仅移除界面":["3.34"],"可将其设置为":["3.34"],"when":["5.5","11.1","12.45","22.26"],"destroy":["5.5"],"也会在调用":["5.5"],"时自动执行类似逻辑":["5.5"],"画中画":["5.26"],"fullscreen":["5.26","15.21","22.24"],"窗口全屏":["5.26"],"fullscreenweb":["5.26"],"网页全屏":["5.26"],"对应":["5.29"],"domrect":["5.29"],"的同名字段":["5.29"],"组件唯一名称":["6.1","8.1"],"用于标记类名":["6.1","8.1"],"index":["6.1","7.5","8.1","16.1","17.5","18.1","24.7","24.10","24.15","24.16","24.17"],"number":["6.1","7.1","8.1","10.12","16.1","18.1","19.2"],"contextmenu":["6.4","6.5","16.4","16.5"],"name":["6.5","7.5","9.9","16.5","17.5","19.9","22.33"],"组件索引":["7.1"],"用于显示的优先级":["7.1"],"html":["7.1","7.2","9.4","9.9","15.4","17.1","17.2","19.4","19.9","22.27","22.33"],"element":["7.1","17.1","22.45"],"position":["7.2","7.5","17.2","17.5"],"left":["7.2","17.2"],"tooltip":["7.2","9.2","9.9","17.2","19.2","19.5","19.6","19.9"],"style":["7.2","9.3","17.1","17.2","22.37","26.37"],"color":["7.2","15.36","17.2"],"red":["7.2","17.2"],"click":["7.2","17.2"],"function":["7.2","11.10","17.2","19.5","22.35","22.41","23.10","26.35"],"args":["7.2","17.2"],"controls":["7.3","7.5","17.3","17.5"],"add":["7.3","17.3"],"button1":["7.5","17.5"],"png":["8.4","18.4","22.29","26.29"],"列表宽度":["9.2"],"提示文本":["9.2","9.5"],"setting":["9.3","9.4","9.8","9.9","19.3","19.4","19.8","19.9"],"true":["9.3","9.4","9.8","9.9","13.18","13.19","13.32","19.3","19.4","19.8","19.9","24.6"],"settings":["9.3","9.4","9.9","19.3","19.4","19.9","22.14","22.15","22.16","22.18","22.22","22.25"],"subtitle":["9.3","19.3"],"01":["9.3","9.4"],"default":["9.3","13.1","13.4","13.10","13.11","13.12","13.13","13.14","13.15","13.16","13.17","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31"],"span":["9.3"],"multi":["9.4","19.4"],"level":["9.4","13.0","19.4"],"selector":["9.4","19.4"],"value":["9.6"],"min":["9.6"],"flip":["9.8","19.1","19.8"],"slider":["9.9","19.9"],"5x":["9.9","19.9"],"icon":["9.9","19.9"],"refer":["10.0","11.0","15.0"],"to":["10.0","11.0","11.1","12.53","13.25","15.0","15.4","15.15","15.39","20.11"],"proxy":["10.3"],"method":["10.3"],"used":["10.3","13.33","15.38","15.40","22.3","22.6"],"hover":["10.3"],"delete":["10.4"],"clear":["10.4"],"all":["10.4","20.12"],"caches":["10.4"],"object":["10.6","26.11"],"update":["10.8","10.9"],"show":["10.8","10.9","10.10","10.16"],"property":["10.8","10.9","10.10","10.16"],"switch":["10.11"],"version":["10.12"],"resolution":["10.12"],"duration":["10.12"],"etc":["10.12"],"control":["10.12"],"visibility":["10.12"],"toggle":["10.13","10.15","22.20"],"set":["10.16"],"the":["11.0","12.45","12.48","15.0","15.6","15.29","22.8","22.12","22.25","22.26","22.27","22.44","22.45"],"you":["11.1"],"need":["11.1"],"manage":["11.1"],"multiple":["11.1"],"player":["11.2","11.3","11.4","11.7","11.11","11.12","15.41","15.42","20.13","22.5","22.21","22.26","22.27"],"for":["11.5","11.9","13.33","16.1","18.1","22.6","22.18","22.38","22.41","22.51"],"videos":["11.5"],"options":["11.7","11.9","22.37"],"event":["11.8","12.0","12.46","15.38","15.40","19.2","19.5","22.4"],"utility":["11.10"],"by":["11.11","20.13","22.9"],"on":["12.0","13.0","13.3","14.0","22.28","22.44","22.46","22.48","24.18"],"canplay":["12.0"],"an":["12.0","20.12"],"only":["12.0","22.3","22.14","22.21","22.49"],"once":["12.0"],"time":["12.1","12.60","24.4"],"a":["12.11","13.14","22.22"],"mode":["12.25","13.31","15.24","22.48"],"media":["12.42","15.5"],"but":["12.42","15.11","15.15"],"estimates":["12.42"],"it":["12.43","15.15","22.15","22.16","22.51"],"can":["12.43","13.34","22.41"],"play":["12.43","22.4"],"offlineaudiocontext":["12.44"],"this":["12.46","13.34","22.11"],"is":["12.46","12.58","13.1","13.4","13.6","13.7","13.8","13.9","13.10","13.11","13.12","13.13","13.14","13.16","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","15.15","15.42","20.11","21.1","22.2","22.5","22.21"],"sent":["12.46"],"stopped":["12.47","12.62"],"fetching":["12.48"],"first":["12.49"],"frame":["12.49","15.18","15.19"],"has":["12.50","12.51","12.52"],"start":["12.53"],"after":["12.53","14.0"],"periodically":["12.54"],"as":["12.54"],"playback":["12.55","15.13","22.3"],"trying":["12.58"],"data":["12.59","24.8","24.16"],"indicated":["12.60"],"volume":["12.61","22.22"],"top":["13.0"],"mounted":["13.0"],"in":["13.1","13.12","13.13","13.15","13.16","13.21","13.24","13.27","13.34","15.5","15.7","15.26","20.12","22.2","22.11","22.14","22.15","22.16","22.18","22.23","22.24","22.25","22.34"],"events":["13.1"],"text":["13.2","19.2","19.5","19.6","22.34"],"pixels":["13.6","13.7"],"feature":["13.11","22.46"],"seconds":["13.12","13.27","15.6","15.7","22.34"],"milliseconds":["13.13","13.15","13.16","13.21","13.24"],"connection":["13.14"],"error":["13.14","13.15"],"occurs":["13.14","13.15"],"pause":["13.19","13.20"],"false":["13.20"],"swipe":["13.25"],"vertical":["13.30","15.30"],"during":["13.31"],"primarily":["13.33"],"smooth":["13.33"],"progress":["13.33","15.13","15.39","22.6","22.8"],"enabling":["13.34"],"reduce":["13.34"],"resource":["13.34"],"usage":["13.34"],"single":["13.34","15.5"],"page":["13.34","15.5","15.21"],"applications":["13.34","15.5"],"or":["13.34","15.5","22.51"],"scenarios":["13.34"],"where":["13.34"],"ready":["14.0"],"also":["14.0","15.4","20.12"],"remove":["15.4"],"s":["15.4","15.24","20.13","22.27"],"resources":["15.5"],"reinitialize":["15.5"],"tag":["15.5"],"performs":["15.11"],"some":["15.11","22.49"],"optimization":["15.11"],"operations":["15.11"],"retains":["15.13"],"previous":["15.13"],"similar":["15.15","22.4"],"optional":["15.17"],"parameter":["15.17","20.10"],"specifies":["15.17"],"filename":["15.17"],"returns":["15.18","15.19"],"promise":["15.18","15.19","24.6"],"state":["15.21"],"before":["15.23","22.27"],"starts":["15.23"],"playing":["15.23"],"normal":["15.26","15.30"],"mini":["15.26"],"window":["15.26"],"pip":["15.26"],"picture":["15.26"],"automatically":["15.27","22.11"],"correspond":["15.29"],"fields":["15.29"],"of":["15.29","22.12","22.36"],"same":["15.29"],"supported":["15.30","22.42"],"values":["15.30"],"horizontal":["15.30"],"speed":["15.31"],"ratio":["15.32"],"with":["15.38","15.40"],"timeupdate":["15.38","15.40"],"loaded":["15.39"],"display":["15.39","17.1"],"detailed":["15.39"],"buffering":["15.39"],"cleaned":["15.41"],"up":["15.41"],"destroyed":["15.41"],"scoped":["15.42"],"current":["15.42","20.5","23.5"],"preventing":["15.42"],"css":["16.1","18.1","26.11"],"class":["16.1","18.1","20.3"],"determines":["17.1"],"priority":["17.1"],"dom":["17.1"],"items":["19.1"],"playbackrate":["19.1"],"aspectratio":["19.1"],"width":["19.2","22.36","26.36"],"list":["19.2"],"onswitch":["19.5"],"completion":["19.6"],"onchange":["19.6"],"change":["19.6"],"yarn":["20.1","23.1"],"utf":["20.3","26.37"],"body":["20.3"],"if":["20.5","23.5"],"typeof":["20.5","23.5"],"ts":["20.6","22.40"],"file":["20.6","20.11"],"from":["20.8","20.9","20.13","21.2","23.8","23.11"],"import":["20.9","21.1","21.2","23.11"],"let":["20.10"],"null":["20.10"],"use":["20.11"],"which":["20.11"],"compatible":["20.11"],"down":["20.11"],"ie":["20.11","23.11"],"plugins":["20.12","24.14","24.18"],"provide":["20.12"],"ui":["20.13"],"changing":["20.13"],"therefore":["20.13"],"starting":["20.13"],"core":["21.0"],"will":["21.0","22.15","22.16","22.22"],"no":["21.0","21.1"],"longer":["21.0"],"bundle":["21.0"],"manual":["21.1"],"dist":["21.2","23.12"],"group":["21.2"],"id":["21.2"],"sometimes":["22.2","22.40"],"not":["22.2","22.5","22.40"],"known":["22.2"],"immediately":["22.2"],"such":["22.2"],"cases":["22.2"],"memory":["22.3"],"autoplayback":["22.3"],"initialized":["22.5"],"and":["22.5","22.6","22.8","22.22"],"hide":["22.8","22.44"],"resulting":["22.11"],"black":["22.11"],"bars":["22.11"],"option":["22.11"],"adjusts":["22.11"],"scrolls":["22.12"],"out":["22.12"],"currently":["22.14","22.49"],"appears":["22.14","22.26"],"appear":["22.15","22.16"],"panel":["22.18","22.22","22.25"],"button":["22.20","22.23","22.24"],"bottom":["22.20","22.23","22.24"],"simultaneously":["22.21"],"whether":["22.21"],"one":["22.21"],"context":["22.22"],"menu":["22.22"],"apply":["22.22"],"loses":["22.26"],"focus":["22.26"],"pre":["22.27"],"render":["22.27"],"required":["22.27"],"mobile":["22.28","22.44","22.45","22.48"],"devices":["22.28","22.44"],"layer":["22.29","26.29"],"boolean":["22.33"],"string":["22.33","22.34"],"myplugin":["22.35","26.35"],"column":["22.36"],"columns":["22.36"],"encoding":["22.37","26.37"],"auto":["22.38","26.38"],"better":["22.38"],"loading":["22.38"],"experience":["22.38"],"more":["22.38"],"attributes":["22.38"],"e":["22.40"],"g":["22.40"],"m3u8":["22.40"],"mkv":["22.40"],"however":["22.40"],"may":["22.40"],"have":["22.40"],"programs":["22.41"],"processing":["22.41"],"receive":["22.41"],"three":["22.41"],"en":["22.42"],"zh":["22.42","25.2"],"cn":["22.42","26.42"],"fast":["22.46"],"forward":["22.46"],"web":["22.48"],"based":["22.48"],"browsers":["22.49"],"support":["22.49"],"htmlvideoelement":["22.51"],"example":["22.51"],"demo":["23.3"],"meta":["23.3"],"charset":["23.3"],"ref":["23.4"],"时会自动导入的":["23.6"],"param":["23.10"],"getinstance":["23.10"],"可以兼容到":["23.11"],"和所有插件还会提供一个":["23.12"],"版本的":["23.12"],"mjs":["23.12"],"如":["23.12"],"globalthis":["23.13"],"custom":["23.13"],"agent":["23.13"],"全局变量":["23.13"],"plugin":["24.2","24.3","24.8","24.16"],"danmuku":["24.2","24.7","24.10","24.16"],"npm":["24.3"],"弹幕时间":["24.4"],"默认为当前播放器时间":["24.4"],"默认弹幕模式":["24.5"],"滚动":["24.5"],"顶部":["24.5"],"底部":["24.5"],"modes":["24.5"],"弹幕可见的模式":["24.5"],"fontsize":["24.5"],"danmu":["24.6","24.18"],"return":["24.6"],"resolve":["24.6"],"settimeout":["24.6"],"libs":["24.8","24.16"],"uncompiled":["24.8","24.16"],"artplayerplugindanmuku":["24.14","24.18"],"xml":["24.18"],"visible":["24.18"],"显示弹幕":["24.18"],"版本开始":["25.0"],"核心代码除了包含":["25.0"],"zhtw":["25.2"],"tw":["25.2"],"高亮元素":["26.6"],"上":["26.6"],"类似":["26.11"],"的":["26.11"],"fit":["26.11"],"里":["26.14","26.15","26.16","26.25"],"音量条等浮层会应用":["26.22"],"filter":["26.22"],"毛玻璃效果":["26.22"],"看起来更通透":["26.22"],"访问到播放器所需的":["26.27"],"画质地址":["26.33"],"预览图列数":["26.36"],"预览图宽度":["26.36"],"height":["26.36"],"预览图高度":["26.36"],"scale":["26.36"],"字幕样式":["26.37"],"字幕编码":["26.37"],"默认":["26.37"],"以提升加载体验":["26.38"],"更多视频属性":["26.38"],"这些属性将直接写入视频元素里":["26.38"],"所以需要特别指明":["26.40"],"元素":["26.41"],"视频地址":["26.41"],"当前实例":["26.41"],"dom元素":["26.51"]},{"0":["19.6","24.4"],"1":["3.29","9.3","13.29","19.3"],"2":["3.29","9.6","19.6","20.13","26.3"],"3":["9.6"],"4":["9.1","20.13","21.1","22.17","22.34","22.50","23.10","26.5","26.7","26.8","26.9","26.13","26.17","26.21","26.25","26.26","26.33","26.34","26.40","26.42","26.45","26.46"],"5":["13.14","13.25","20.13"],"6":["2.41","5.42","5.43","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","23.10"],"7":["5.4","5.6","5.7","5.10","5.17","5.18","5.19","5.24","5.38","5.39","5.40","12.19","12.21","12.23","12.25","12.26","15.10","22.39"],"8":["5.9","5.15","5.25","5.27","5.30","5.41","12.17","15.1","15.9","15.14","15.21","15.25","15.30","15.31","15.32","15.34","15.35","15.36","15.41","22.37","23.3","26.37"],"9":["5.11","5.13","15.11","15.13","15.23","22.4"],"10":["5.8","5.41","7.3","7.4","12.2","12.6","12.18","12.24","15.8","15.12","15.41","17.3","17.4","19.6"],"11":["15.3","15.21","20.11"],"14":["26.33"],"22":["9.9","19.9"],"25":["22.34","26.34"],"40":["3.7"],"100":["3.10"],"150":["9.4","19.4"],"300":["3.5","3.6"],"500":["3.8","3.9","3.17"],"1000":["13.15"],"3000":["13.16"],"实例":["0.0","5.0"],"artplayer":["0.1","0.3","0.5","0.6","0.8","0.9","0.10","0.13","0.15","1.1","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","3.1","3.3","3.4","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.15","3.16","3.17","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.31","3.32","3.33","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.20","5.21","5.22","5.25","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.41","5.44","5.46","5.47","9.1","9.2","9.5","10.3","10.4","10.5","10.6","10.7","10.14","10.17","12.2","12.6","12.17","12.18","12.20","12.22","12.24","12.28","12.29","12.30","12.31","13.5","13.6","13.7","13.8","13.9","13.28","13.29","13.30","15.2","15.3","15.5","15.20","15.22","15.28","15.33","15.34","15.37","15.41","15.44","15.46","15.47","19.5","20.2","22.4","22.7","22.17","22.31","22.39","23.2","23.13","25.1","26.10","26.19","26.31","26.34","26.39","26.40","26.47","26.50"],"container":["0.1","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.15","0.16","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","5.2","5.3","5.9","5.11","5.13","5.14","5.16","5.20","5.21","5.22","5.23","5.28","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.41","5.44","5.46","5.47","9.2","9.5","10.1","10.3","10.4","10.5","10.6","10.7","10.14","10.17","12.2","12.20","12.22","12.28","12.29","12.30","12.31","15.2","15.20","15.22","15.28","15.41","15.44","15.46","19.5","20.9","21.3","22.4","22.7","22.17","22.31","22.39","24.9","24.10","24.15","24.17","25.1","25.2","26.10","26.19","26.31","26.34","26.39","26.47"],"app":["0.1","0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.16","0.17","2.2","2.6","2.17","2.18","2.20","2.22","2.24","2.28","2.29","2.30","2.31","5.12","5.16","5.20","5.22","5.23","5.28","5.33","5.34","5.44","9.5","10.1","10.4","10.5","10.6","10.14","12.31","15.20","15.22","15.28","15.33","15.41","15.44","19.5","20.3","20.5","21.3","21.4","22.4","22.7","22.10","22.31","22.32","22.39","22.43","23.9","24.6","24.10","25.2","25.3","26.1","26.19","26.31","26.32","26.39","26.47"],"assets":["0.2","0.6","0.7","0.10","0.14","0.16","0.17","2.2","2.22","2.28","2.31","5.12","5.23","5.44","9.5","10.1","10.4","10.6","10.14","15.12","15.16","15.20","15.22","15.33","21.4","22.1","22.4","22.7","22.10","22.19","22.31","22.32","22.43","23.9","24.6","24.10","24.11","25.2","25.3","25.4","26.1","26.4","26.31","26.32"],"sample":["0.2","0.6","0.14","0.16","0.17","2.2","2.28","5.12","5.23","9.5","9.7","10.1","10.4","10.6","10.14","15.12","15.16","15.20","15.22","15.33","15.45","19.7","21.4","22.1","22.4","22.7","22.10","22.19","22.31","22.32","22.43","22.47","23.9","24.6","24.11","24.12","25.2","25.4","26.4","26.32"],"video":["0.2","0.14","0.16","0.17","5.12","7.4","8.4","9.5","9.7","10.4","10.6","10.14","15.20","15.22","15.45","17.4","18.4","19.7","21.4","22.1","22.10","22.19","22.29","22.30","22.32","22.43","22.47","22.48","22.51","24.6","24.11","24.12","25.2","25.4","26.4","26.29","26.30","26.32","26.43"],"mp4":["0.2","0.14","0.17","5.12","5.45","6.2","7.4","8.4","9.5","9.7","10.4","10.14","15.12","15.16","15.20","15.33","15.45","16.2","17.4","18.4","19.7","22.1","22.4","22.10","22.19","22.29","22.30","22.32","22.43","22.47","24.6","24.11","24.12","24.13","25.2","25.4","26.4","26.29","26.30","26.43"],"console":["0.2","0.4","1.6","7.2","10.2","11.6","15.16","17.2","22.35","26.35"],"info":["0.2","0.4","1.1","7.2","10.2","11.6","17.2","22.35","26.35"],"queryselector":["0.3","5.41","10.3","15.41","22.1","24.16","26.1"],"art":["0.3","0.8","0.9","0.11","0.13","0.15","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.19","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.40","2.41","3.5","3.6","3.7","3.30","5.1","5.2","5.3","5.6","5.7","5.8","5.9","5.10","5.14","5.15","5.17","5.18","5.19","5.21","5.24","5.25","5.27","5.30","5.31","5.32","5.34","5.35","5.36","5.37","5.39","5.46","5.47","9.1","9.2","10.4","10.6","10.7","10.12","10.14","10.17","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.16","12.17","12.18","12.20","12.21","12.22","12.23","12.24","12.26","12.27","12.28","12.29","12.30","12.39","12.40","12.41","15.1","15.2","15.3","15.8","15.9","15.10","15.14","15.23","15.28","15.31","15.32","15.34","15.35","15.36","15.37","15.46","15.47","19.2","19.5","21.2","22.4","22.17","22.35","22.39","22.50","24.7","24.9","24.10","24.15","24.17","26.5","26.7","26.10","26.17","26.33","26.34","26.40","26.50"],"new":["0.3","0.5","0.8","0.9","0.10","0.11","0.13","0.15","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.19","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.30","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.16","5.17","5.18","5.19","5.20","5.21","5.22","5.25","5.27","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.46","5.47","9.1","9.2","9.5","10.4","10.5","10.6","10.7","10.14","10.17","12.2","12.6","12.7","12.8","12.10","12.17","12.18","12.20","12.22","12.24","12.26","12.28","12.29","12.30","12.31","15.1","15.2","15.3","15.22","15.23","15.28","15.32","15.34","15.35","15.37","15.44","15.46","15.47","19.5","22.4","22.17","22.39","24.9","24.10","24.15","24.17","25.1","25.2","26.7","26.10","26.19","26.34","26.39","26.40","26.47","26.50"],"url":["0.6","0.7","0.9","0.10","0.14","0.16","0.17","2.2","2.18","2.22","2.24","2.28","2.29","2.30","2.31","5.20","5.23","5.33","5.44","8.4","9.5","10.1","10.4","10.5","10.6","10.14","15.20","15.22","15.33","15.44","18.4","21.3","21.4","22.1","22.4","22.7","22.10","22.19","22.31","22.32","22.41","22.43","23.9","24.6","24.10","24.11","25.2","25.3","25.4","26.1","26.4","26.31","26.32","26.39","26.47"],"js":["0.11","0.12","1.6","3.1","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.33","5.4","5.6","5.7","5.15","5.24","5.26","5.30","5.38","5.39","5.40","5.42","5.43","9.2","10.3","10.7","10.17","11.6","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.18","12.19","12.21","12.23","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.22","13.28","13.29","13.30","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.25","15.27","15.30","15.31","15.32","15.34","15.35","15.36","15.41","15.43","15.47","19.2","19.5","21.1","22.13","22.17","22.25","22.34","22.42","22.50","24.8","26.3","26.5","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.27","26.28","26.33","26.40","26.42","26.44","26.45","26.46","26.48","26.49"],"var":["0.11","0.12","1.1","2.41","3.5","3.6","3.7","3.17","3.30","5.1","5.6","5.7","5.8","5.9","5.10","5.11","5.13","5.15","5.17","5.18","5.19","5.21","5.24","5.25","5.27","5.30","5.38","5.39","5.40","5.41","5.43","5.47","9.1","9.2","10.3","10.4","10.6","10.7","10.17","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.23","12.24","12.25","12.26","12.27","12.28","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","15.1","15.2","15.3","15.8","15.9","15.10","15.14","15.23","15.25","15.28","15.31","15.32","15.34","15.35","15.36","15.37","15.41","15.46","15.47","19.2","19.5","21.1","21.2","22.4","22.17","22.34","22.39","22.50","24.7","24.15","24.16","24.17","26.3","26.5","26.7","26.17","26.25","26.33","26.34","26.40","26.50"],"function":["0.14","6.5","16.5","17.1","20.10","26.37"],"构造函数":["1.0"],"code":["1.11","3.34","5.5","5.26","5.29","9.6","10.3","11.1","13.1","13.2","13.3","13.4","13.6","13.7","13.8","13.9","13.10","13.11","13.12","13.13","13.14","13.15","13.16","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.28","13.31","13.32","13.33","15.6","15.7","15.11","15.13","15.17","15.18","15.19","15.23","15.24","15.30","15.38","15.39","15.40","19.1","19.2","19.5","20.11","22.3","22.5","22.9","22.25","22.28","22.33","22.34","22.40","22.42","22.45","23.11","26.6","26.11","26.14","26.15","26.16","26.22","26.27","26.36","26.38","26.41","26.51"],"once":["2.0"],"不必停下来进一步缓冲内容":["2.42"],"media":["2.46","2.47","12.43","12.48"],"已经加载完成":["2.46"],"操作完成":["2.56"],"操作开始":["2.57"],"agent":["2.58"],"的":["3.0"],"false":["3.3","3.34","20.5","23.5","24.5","24.14"],"div":["3.34","5.5","5.29","9.6","10.3","10.13","10.15","11.1","11.2","11.3","11.4","11.7","11.8","11.11","11.12","13.1","13.12","13.13","13.14","13.15","13.16","13.24","13.25","13.27","13.31","13.33","15.4","15.15","15.17","15.26","15.38","15.39","15.40","15.42","19.1","19.2","20.5","22.3","22.5","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.33","22.40","22.44","22.45","22.46","22.49","22.51","23.3","23.5","26.11","26.22","26.36"],"classname":["3.34","5.5","5.29","9.6","10.3","11.1","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","13.1","13.12","13.13","13.14","13.15","13.16","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.33","15.15","15.17","15.26","15.38","15.39","15.40","19.1","19.2","22.3","22.5","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.28","22.33","22.40","22.44","22.45","22.46","22.49","26.11","26.22","26.36","26.41"],"run":["3.34","5.5","5.26","5.29","9.6","10.3","11.1","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.12","13.1","13.2","13.4","13.6","13.7","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","15.6","15.11","15.13","15.15","15.17","15.18","15.19","15.24","15.30","15.38","15.39","15.40","19.1","19.2","19.5","22.3","22.5","22.6","22.8","22.12","22.20","22.23","22.24","22.25","22.28","22.33","22.40","22.42","22.45","22.46","22.49","26.11","26.22","26.27","26.36","26.38","26.41"],"add":["4.0","6.3","8.3","14.0","16.3","18.3","20.1","23.1","24.2"],"例如我想写一个在视频暂停后":["4.0"],"显示一个图片广告的插件":["4.0"],"on":["5.12","15.12","15.16","15.33"],"播放器当前可见宽高":["5.29"],"document":["5.41","10.3","15.41","24.16","26.1"],"default":["5.45","7.5","15.45","17.5","19.3","23.10"],"true":["5.45","7.5","9.7","13.31","15.4","15.45","17.5","19.7","22.4","22.10","22.30","22.47","24.5","26.4","26.30","26.37"],"html":["5.45","6.1","6.2","6.3","6.4","6.5","7.3","7.5","8.1","8.2","8.3","8.5","9.8","15.45","16.1","16.2","16.3","16.4","16.5","17.3","17.5","18.1","18.2","18.3","18.5","19.8","22.29","22.30","22.37","23.13","24.14","26.29","26.30","26.37"],"sd":["5.45","15.45"],"480p":["5.45","15.45"],"组件索引":["6.1","8.1"],"用于显示的优先级":["6.1","8.1"],"contextmenu":["6.2","6.3","16.2","16.3"],"name":["6.2","6.3","6.4","7.3","7.4","8.2","8.3","8.4","8.5","9.8","15.29","16.2","16.3","16.4","17.3","17.4","18.2","18.3","18.4","18.5","19.8","22.29","22.35","26.29","26.35"],"your":["6.2","6.3","6.4","6.5","7.3","16.2","16.3","16.4","16.5","17.3","22.47","26.43"],"menu":["6.2","6.3","6.4","6.5","16.2","16.3","16.4","16.5","22.14","22.15","22.16"],"click":["6.4","6.5","16.4","16.5","17.1","24.14"],"args":["6.5","16.5"],"组件的":["7.1"],"dom":["7.1","22.41","22.51"],"元素":["7.1"],"style":["7.1","8.2","8.3","8.5","18.2","18.3","18.5","19.3","20.4","22.29"],"object":["7.1","17.1"],"mounted":["7.2","17.2","22.27"],"subtitle":["7.2","7.5","17.2","17.5"],"button1":["7.3","7.4","17.3","17.4"],"index":["7.3","7.4","17.3","17.4","24.8"],"position":["7.3","17.3","24.13","24.14"],"left":["7.3","17.3"],"controls":["7.4","17.4","24.13","24.14"],"right":["7.5","17.5","24.14"],"selector":["7.5","17.5","22.30","26.30"],"01":["7.5","17.5","19.3","19.4"],"layers":["8.2","8.3","8.4","8.5","18.2","18.3","18.4","18.5"],"potser":["8.2","8.3","8.5","18.2","18.3","18.5","22.29","26.29"],"width":["8.2","8.3","8.5","9.4","9.9","18.2","18.3","18.5","19.4","19.9","22.29"],"100px":["8.2","8.3","8.5","18.2","18.3","18.5"],"src":["8.2","8.5","9.9","18.2","18.5","19.9"],"color":["9.3","19.3"],"red":["9.3","19.3"],"srt":["9.3","19.3"],"id":["9.3","19.3","22.47"],"yellow":["9.3"],"02":["9.3"],"setting":["9.5","9.7","19.7","22.30","26.30"],"max":["9.6","19.6"],"step":["9.6"],"settings":["9.8","19.8"],"slider":["9.8","19.8"],"tooltip":["9.8","19.8"],"5x":["9.8","19.8"],"icon":["9.8","19.8"],"img":["9.9","19.9"],"height":["9.9","19.9","22.36"],"state":["9.9","13.34","19.9"],"svg":["9.9","19.9"],"secondary":["10.0"],"custom":["10.3"],"test":["10.4"],"foo":["10.4"],"bar":["10.4","13.33","22.18","22.20","22.23","22.24","22.44"],"const":["10.4","20.8","20.9","23.8"],"set":["10.8","10.9","10.10","22.2"],"whether":["10.8","10.9","10.10","10.16","22.37"],"all":["10.8","10.9","10.10","10.16","13.0"],"are":["10.8","13.34"],"displayed":["10.8"],"toggle":["10.8","10.9","10.10","10.16"],"display":["10.9","10.10","10.16","16.1","18.1"],"options":["10.11"],"texttrack":["10.11"],"gets":["10.11"],"text":["10.11"],"track":["10.11"],"activecues":["10.11"],"list":["10.11"],"via":["10.12"],"show":["10.12"],"triggered":["10.12"],"event":["10.12","17.1"],"is":["10.12","12.42","13.15","20.6","22.26","22.27"],"named":["10.12"],"of":["10.13","10.15","12.49","12.62","13.34"],"first":["11.0","15.0"],"level":["11.0","15.0"],"players":["11.1","13.34"],"simultaneously":["11.1"],"there":["12.42"],"not":["12.42","15.15"],"rendering":["12.44"],"value":["12.45","19.6"],"when":["12.46","15.5"],"because":["12.47","12.62"],"the":["12.47","12.54","20.3","22.38"],"data":["12.48","23.10"],"or":["12.48"],"been":["12.50","12.51","12.53"],"begun":["12.52"],"having":["12.53"],"rate":["12.55"],"operation":["12.56","12.57"],"to":["12.58","22.11","22.21","22.37"],"fetch":["12.58"],"loading":["12.59"],"by":["12.60"],"has":["12.61"],"constructor":["13.0"],"property":["13.0","20.10"],"off":["13.1"],"effects":["13.33"],"frequently":["13.34"],"created":["13.34"],"destroyed":["13.34"],"if":["13.34"],"you":["13.34","22.1","22.2"],"wish":["13.34"],"preserve":["13.34"],"for":["14.0"],"example":["14.0"],"let":["14.0"],"after":["15.4"],"destruction":["15.4"],"defaults":["15.4"],"note":["15.5","20.3"],"global":["15.5","20.13"],"configuration":["15.5"],"remove":["15.5"],"destroy":["15.5","20.5","23.5"],"will":["15.5"],"also":["15.5"],"ready":["15.12","15.16"],"seek":["15.12"],"settimeout":["15.12"],"does":["15.15"],"trigger":["15.15"],"additional":["15.15"],"events":["15.15"],"fullscreen":["15.26"],"fullscreenweb":["15.26"],"webpage":["15.26"],"in":["15.29"],"domrect":["15.29"],"player":["15.29"],"s":["15.29"],"current":["15.29"],"errors":["15.42"],"with":["15.42"],"duplicate":["15.42"],"class":["15.42"],"names":["15.42"],"priority":["16.1","18.1"],"element":["16.1","22.41","22.51"],"handler":["17.1"],"subtitleoffset":["19.1"],"span":["19.3"],"min":["19.6"],"npm":["20.2","23.2"],"dist":["20.2","20.12","23.2","24.3"],"warning":["20.3","22.47"],"option":["20.4","23.4"],"get":["20.4"],"return":["20.5","22.35","23.5","23.10","26.35"],"ref":["20.5","23.5"],"param":["20.10"],"getinstance":["20.10"],"import":["20.11"],"from":["20.11"],"group":["20.11","23.11"],"bash":["20.11","23.11"],"jsdelivr":["20.11","23.11"],"net":["20.11","23.11"],"mjs":["20.12"],"format":["20.12"],"such":["20.12"],"as":["20.12"],"version":["20.13"],"variable":["20.13"],"globalthis":["20.13"],"user":["20.13"],"any":["21.0"],"languages":["21.0"],"other":["21.0"],"than":["21.0"],"simplified":["21.0"],"chinese":["21.0"],"and":["21.0","22.14","22.15","22.16","22.26","22.48"],"english":["21.0"],"required":["21.1"],"zhtw":["21.2"],"zh":["21.2"],"tw":["21.2"],"may":["22.1"],"can":["22.2","22.27"],"asynchronously":["22.2"],"muted":["22.4","26.4"],"yet":["22.5"],"playing":["22.5","22.26"],"highlighted":["22.6"],"elements":["22.6"],"playback":["22.8"],"time":["22.8","22.21"],"size":["22.11"],"hide":["22.11"],"browser":["22.12"],"viewport":["22.12","22.48"],"panel":["22.14","22.15","22.16"],"context":["22.14","22.15","22.16"],"bottom":["22.18","22.44"],"control":["22.18","22.20","22.23","22.24","22.44"],"allowed":["22.21"],"play":["22.21","26.43"],"at":["22.21"],"a":["22.21"],"filter":["22.22"],"frosted":["22.22"],"glass":["22.22"],"more":["22.22"],"transparent":["22.22"],"look":["22.22"],"however":["22.22"],"access":["22.27"],"setting01":["22.30","26.30"],"scale":["22.36"],"utf":["22.37","23.3"],"escape":["22.37","26.37"],"boolean":["22.37","26.37"],"tags":["22.37"],"these":["22.38"],"be":["22.38"],"written":["22.38"],"directly":["22.38"],"into":["22.38"],"correct":["22.40"],"so":["22.40"],"explicitly":["22.40"],"specified":["22.40"],"parameters":["22.41"],"lang":["22.43","26.43"],"devices":["22.45","22.46"],"mobile":["22.46"],"dimensions":["22.48"],"this":["22.49"],"feature":["22.49"],"an":["22.51"],"existing":["22.51"],"body":["23.3"],"属性":["23.10"],"export":["23.10"],"https":["23.11"],"plugin":["23.12"],"danmuku":["23.12","24.3","24.8"],"head":["23.13"],"title":["23.13"],"yarn":["24.2"],"mode":["24.4"],"弹幕模式":["24.4"],"滚动":["24.4"],"弹幕字体大小":["24.5"],"antioverlap":["24.5"],"弹幕是否防重叠":["24.5"],"synchronousplayback":["24.5"],"是否同步播放速度":["24.5"],"mount":["24.5"],"undefined":["24.5"],"弹幕发射器挂载点":["24.5"],"默认为播放器控制栏中部":["24.5"],"heatmap":["24.5"],"plugins":["24.6","24.11","24.12","24.13"],"xml":["24.6","24.13","24.14"],"这是用户在输入框输入弹幕文本":["24.6"],"然后点击发送按钮后触发的函数":["24.6"],"artplayerplugindanmuku":["24.11","24.12","24.13"],"emitter":["24.14"],"重载":["24.14"],"danmu":["24.16"],"loaded":["24.18"],"danmus":["24.18"],"加载弹幕":["24.18"],"length":["24.18"],"简体中文":["25.0"],"和":["25.0"],"英文":["25.0"],"有时候":["26.2"],"地址没那么快知道":["26.2"],"这时候你可以异步设置":["26.2"],"cover":["26.11"],"但在部分低性能设备或老旧浏览器上可能会有性能或兼容性问题":["26.22"],"预览图缩放":["26.36"],"是否转义":["26.37"],"标签":["26.37"],"默认为":["26.37"],"onvttload":["26.37"],"用于修改":["26.37"]},{"0":["15.12","23.9"],"1":["3.25","9.9","19.9","24.4"],"2":["3.26","9.3","13.29","19.3","22.3","24.4"],"3":["3.28","13.28","19.6","26.1"],"4":["3.28","13.28","19.1","20.10","22.5","22.8","22.9","22.13","22.23","22.24","22.25","22.28","22.33","22.36","22.40","22.42","22.45","22.46","22.49","26.6","26.11","26.12","26.14","26.15","26.16","26.18","26.20","26.22","26.23","26.24","26.28","26.36","26.37","26.38","26.41","26.44","26.48","26.49","26.51"],"5":["3.23","3.29","9.9","13.29","19.9","22.7"],"6":["3.29","13.29","15.43","20.10","22.2","26.2"],"7":["5.29","15.6","15.7","15.17","15.18","15.19","15.24","15.38","15.39","15.40","26.27","26.38"],"8":["5.26","15.15","15.26","15.27","22.36","23.13","26.36","26.41"],"9":["5.5"],"10":["3.12","3.14","3.27","5.12","9.9","19.9"],"12":["24.13"],"14":["22.33"],"20":["3.11"],"22":["9.5"],"40":["13.7"],"50":["24.13"],"100":["13.10"],"300":["13.5","13.6"],"500":["3.21","13.8","13.9","13.17"],"512":["24.5"],"2000":["3.22","3.24","13.22"],"3000":["3.15","15.12"],"5000":["3.4","3.13","3.16"],"的":["0.0","0.4","1.0","5.0"],"url":["0.1","0.3","0.5","0.8","0.12","0.13","0.15","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.19","2.20","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.30","5.1","5.2","5.3","5.8","5.9","5.13","5.14","5.15","5.16","5.17","5.18","5.19","5.21","5.22","5.25","5.28","5.30","5.31","5.32","5.34","5.35","5.36","5.37","5.46","5.47","9.1","9.2","9.6","10.3","10.7","10.17","12.2","12.6","12.7","12.8","12.10","12.12","12.16","12.17","12.18","12.20","12.22","12.24","12.26","12.28","12.29","12.30","12.31","15.2","15.3","15.8","15.9","15.14","15.23","15.28","15.31","15.32","15.34","15.35","15.36","15.37","15.41","15.46","15.47","19.2","19.5","20.5","20.9","21.2","22.17","22.34","22.39","22.50","24.9","24.15","24.17","25.1","26.7","26.10","26.19","26.34","26.40","26.50"],"assets":["0.1","0.3","0.5","0.8","0.9","0.11","0.13","0.15","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.23","2.24","2.25","2.26","2.27","2.29","2.30","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","3.30","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.20","5.21","5.22","5.25","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.37","5.46","5.47","9.1","9.2","9.6","10.3","10.5","10.7","10.17","12.2","12.6","12.17","12.18","12.20","12.22","12.24","12.28","12.29","12.30","12.31","15.2","15.3","15.9","15.14","15.23","15.28","15.31","15.32","15.34","15.35","15.37","15.41","15.44","15.46","15.47","19.2","19.5","20.9","21.2","21.3","22.17","22.34","22.39","22.40","24.9","24.15","24.17","25.1","26.10","26.19","26.33","26.34","26.39","26.40","26.47","26.50"],"sample":["0.1","0.3","0.5","0.7","0.8","0.9","0.10","0.11","0.13","0.15","2.6","2.11","2.12","2.16","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.29","2.30","2.31","2.39","5.2","5.3","5.9","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.20","5.21","5.22","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.44","5.46","5.47","9.2","9.6","10.3","10.5","10.7","10.17","12.2","12.18","12.20","12.22","12.24","12.28","12.29","12.30","12.31","15.2","15.23","15.28","15.34","15.41","15.44","15.46","19.2","19.5","20.9","21.2","21.3","22.17","22.34","22.39","22.40","24.9","24.10","24.15","24.17","25.3","26.1","26.10","26.19","26.31","26.33","26.34","26.39","26.40","26.47"],"video":["0.1","0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.13","0.15","2.2","2.6","2.12","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.28","2.29","2.30","2.31","5.2","5.3","5.9","5.11","5.13","5.14","5.16","5.20","5.22","5.23","5.28","5.31","5.32","5.33","5.35","5.36","5.44","5.46","9.2","9.6","10.1","10.3","10.5","10.7","10.17","12.2","12.22","12.28","12.29","12.30","12.31","15.28","15.41","15.44","15.46","19.2","19.5","20.9","21.2","21.3","22.7","22.17","22.31","22.39","23.9","24.9","24.10","24.15","24.17","25.3","26.1","26.10","26.19","26.31","26.34","26.39","26.40","26.47"],"mp4":["0.3","0.5","0.6","0.7","0.8","0.9","0.10","0.16","2.2","2.17","2.18","2.20","2.22","2.24","2.28","2.29","2.30","2.31","5.16","5.20","5.22","5.23","5.28","5.32","5.33","5.34","5.44","5.46","9.2","10.1","10.3","10.5","10.6","10.7","10.17","12.28","12.29","12.30","12.31","15.22","15.23","15.28","15.41","15.44","19.2","19.5","20.9","21.2","21.3","21.4","22.7","22.17","22.31","22.39","23.9","24.9","24.10","24.17","25.3","26.1","26.10","26.19","26.31","26.32","26.34","26.39","26.47"],"warning":["0.4","10.2","10.4","11.6","15.12","15.16","15.33","20.4","22.7","22.10","25.0"],"提示":["0.4"],"默认所有播放器实例都是共享同一个":["0.4"],"localstorage":["0.4"],"而且默认的":["0.4"],"是":["0.4"],"settings":["0.4","9.2","9.5","19.5"],"如果你想不同的播放器使用不同的":["0.4"],"console":["0.6","0.14","0.17","6.2","6.3","6.4","6.5","9.3","9.4","10.1","10.4","10.5","10.6","10.14","11.1","16.2","16.3","16.4","16.5","19.3","19.4","22.30"],"info":["0.6","0.14","0.17","1.6","6.2","6.3","6.4","6.5","9.3","9.4","10.1","10.4","10.5","10.6","10.14","11.1","15.16","16.2","16.3","16.4","16.5","19.3","19.4","22.30"],"play":["0.6","10.6","12.42","22.43","26.4"],"on":["0.7","0.8","0.9","0.10","2.2","2.22","5.33","5.44","7.5","8.5","9.9","10.7","10.14","15.0","15.28","15.44","17.5","18.5","19.9","20.3","22.22"],"ready":["0.9","0.10","2.2","5.12","5.44","7.5","10.14","15.33","17.5"],"artplayer":["0.11","0.12","1.6","2.41","3.34","5.4","5.6","5.7","5.17","5.24","5.26","5.27","5.29","5.38","5.39","5.40","5.42","5.43","9.6","11.1","11.6","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.19","12.21","12.23","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.1","13.3","13.4","13.10","13.11","13.12","13.13","13.14","13.15","13.16","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","15.1","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.24","15.25","15.27","15.30","15.31","15.32","15.35","15.36","15.43","19.1","19.2","19.6","20.13","21.1","22.25","22.27","22.33","22.34","22.40","22.42","22.50","26.3","26.5","26.7","26.8","26.9","26.13","26.14","26.15","26.16","26.17","26.21","26.25","26.26","26.33","26.36","26.42","26.45","26.46"],"container":["0.11","0.12","1.1","2.1","2.3","2.4","2.14","2.41","3.5","3.6","3.7","3.8","3.9","3.10","3.17","3.29","3.30","5.1","5.4","5.6","5.7","5.8","5.10","5.15","5.17","5.18","5.19","5.24","5.25","5.26","5.27","5.30","5.38","5.39","5.40","5.42","5.43","9.1","9.6","12.1","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.21","12.23","12.24","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.30","15.1","15.3","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.23","15.25","15.30","15.31","15.32","15.34","15.35","15.36","15.37","15.47","19.2","19.6","21.1","21.2","22.25","22.33","22.34","22.40","22.42","22.50","24.7","24.16","26.5","26.7","26.17","26.25","26.27","26.33","26.40","26.42","26.50"],"app":["0.11","0.12","0.13","0.15","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.19","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.6","3.7","3.30","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.17","5.18","5.19","5.21","5.25","5.27","5.30","5.31","5.32","5.35","5.36","5.37","5.39","5.41","5.46","5.47","9.1","9.2","9.6","10.3","10.7","10.17","12.2","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.16","12.17","12.18","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.29","12.30","12.39","12.40","12.41","15.1","15.2","15.3","15.8","15.9","15.10","15.11","15.13","15.14","15.21","15.23","15.30","15.31","15.32","15.34","15.35","15.36","15.37","15.46","15.47","19.2","20.9","21.2","22.17","22.34","22.40","22.50","23.3","23.5","24.7","24.9","24.15","24.16","24.17","25.1","26.7","26.10","26.17","26.25","26.27","26.33","26.34","26.40","26.50"],"new":["0.12","1.1","3.3","3.6","3.7","3.8","3.9","3.10","3.11","3.17","3.22","3.28","3.29","3.33","5.4","5.5","5.6","5.7","5.24","5.26","5.29","5.38","5.39","5.40","5.41","5.42","5.43","9.6","10.3","10.16","12.1","12.3","12.4","12.5","12.9","12.11","12.12","12.13","12.14","12.15","12.16","12.19","12.21","12.23","12.25","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.8","13.9","13.30","15.6","15.7","15.8","15.9","15.10","15.11","15.13","15.14","15.15","15.17","15.18","15.19","15.21","15.24","15.25","15.27","15.30","15.31","15.36","15.38","15.39","15.40","15.41","15.43","19.1","19.2","19.6","21.1","22.13","22.25","22.33","22.34","22.40","22.42","22.50","24.7","24.8","24.16","26.3","26.5","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.17","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.28","26.33","26.36","26.38","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"hotkeyevent":["0.14","10.14"],"event":["0.14","9.3","9.4","10.14","19.4"],"click":["0.14","6.2","6.3","7.1","7.3","10.14","15.20","15.22","16.2","16.3","17.3","22.31","24.12"],"true":["0.16","2.28","3.1","3.20","3.33","7.2","9.2","9.5","17.2","19.5","22.17","22.37"],"flip":["0.16"],"playbackrate":["0.16"],"aspectratio":["0.16"],"function":["0.17","6.2","6.3","6.4","7.1","7.3","9.4","10.14","10.17","15.20","15.22","16.2","16.3","16.4","17.3","19.4","22.30","22.37","24.12","24.14","26.30"],"myplugin":["0.17","10.17"],"art":["1.1","3.1","3.3","3.4","3.8","3.9","3.10","3.11","3.12","3.13","3.17","3.18","3.21","3.22","3.23","3.24","3.27","3.28","3.29","3.32","3.33","5.4","5.5","5.26","5.29","5.38","5.40","5.41","5.42","5.43","9.6","10.3","10.16","12.1","12.11","12.14","12.19","12.25","12.32","12.33","12.34","12.35","12.36","12.37","12.38","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.29","13.30","15.6","15.7","15.15","15.17","15.18","15.19","15.21","15.24","15.25","15.26","15.27","15.30","15.38","15.39","15.40","15.41","15.43","19.1","19.6","20.8","21.1","22.9","22.13","22.25","22.28","22.33","22.34","22.40","22.41","22.42","23.8","24.8","24.16","26.3","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.23","26.24","26.25","26.26","26.28","26.36","26.38","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"js":["1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.12","3.2","3.34","5.5","5.29","10.9","10.10","10.13","10.15","10.16","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","15.4","15.6","15.15","15.17","15.24","15.26","15.38","15.39","15.40","15.42","19.1","20.2","22.3","22.5","22.6","22.8","22.9","22.12","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.28","22.33","22.36","22.40","22.44","22.45","22.46","22.49","23.2","24.3","26.6","26.11","26.22","26.36","26.37","26.38","26.41","26.51"],"手动触发事件":["2.0"],"subtitle":["2.28","2.29","2.30","2.31","12.31"],"或者部分加载完成":["2.46"],"则发送此事件":["2.46"],"已经到达结束点":["2.47"],"正在尝试获取媒体数据":["2.58"],"一级属性":["3.0"],"var":["3.1","3.3","3.4","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.29","3.31","3.32","3.33","5.4","5.5","5.26","5.29","5.42","9.6","10.13","10.15","10.16","12.1","12.11","13.3","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.22","13.28","13.29","13.30","15.6","15.7","15.11","15.13","15.15","15.17","15.18","15.19","15.21","15.24","15.26","15.27","15.30","15.38","15.39","15.40","15.43","19.1","19.6","22.3","22.5","22.9","22.13","22.25","22.28","22.33","22.40","22.42","24.8","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.27","26.28","26.36","26.38","26.41","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"false":["3.18","3.19","3.31","3.32","6.5","13.3","13.18","13.32","16.5"],"adsplugin":["4.0","14.0"],"option":["4.0","14.0","24.18"],"layers":["4.0","14.0"],"ads":["4.0"],"html":["4.0","7.4","8.4","9.7","15.20","15.22","17.4","18.4","19.7","20.13","22.31","22.32","24.11","24.12","24.13","26.31","26.32"],"img":["4.0","9.5","9.8","19.8","22.39","26.39"],"style":["4.0","6.1","7.3","8.1","8.4","16.1","17.3","18.1","18.4","23.4","26.29"],"width":["4.0","8.4","9.5","9.8","18.4","19.8","24.5","26.29"],"100px":["4.0","8.4","18.4","22.29","26.29"],"src":["4.0","8.3","8.4","9.8","18.3","18.4","19.8","22.29","26.29"],"display":["4.0","10.8"],"none":["4.0"],"position":["4.0","5.20","7.4","8.2","8.3","8.5","15.20","15.22","17.4","18.2","18.3","18.5","22.29","22.32","24.11","24.12","26.29","26.32"],"absolute":["4.0","8.2","8.3","8.5","18.2","18.3","18.5","22.29","26.29"],"top":["4.0","8.2","8.3","8.5","18.2","18.3","18.5","22.29","26.29"],"20px":["4.0","22.29","26.29"],"right":["4.0","7.2","7.4","8.2","8.5","15.20","15.22","17.2","17.4","18.2","18.5","22.29","24.11","24.12","24.13"],"seek":["5.12","22.19"],"settimeout":["5.12","7.5","17.5","22.2"],"controls":["5.20","5.22","15.20","15.22","24.11","24.12"],"jpg":["5.23"],"hd":["5.45","15.45"],"720p":["5.45","15.45"],"element":["6.1","8.1","13.34","18.1","22.38"],"组件的":["6.1","8.1"],"dom":["6.1","8.1","9.4","16.1","18.1","19.4"],"元素":["6.1","8.1"],"args":["6.2","6.3","6.4","16.2","16.3","16.4","22.30","26.30"],"show":["6.5","9.7","9.9","16.5","19.7","19.9"],"组件样式对象":["7.1"],"组件点击事件":["7.1"],"mounted":["7.1","15.0","17.1"],"selector":["7.2","17.2"],"default":["7.2","10.4","17.2","20.10","21.4","25.4"],"span":["7.2","17.2"],"01":["7.2","17.2","22.30","26.30"],"button":["7.3","7.4","17.3","17.4"],"tooltip":["7.3","7.4","8.2","8.3","17.1","17.3","17.4","18.2","18.3","22.32"],"color":["7.3","17.3"],"red":["7.3","17.3"],"your":["7.4","17.4","22.31","22.32","26.31","26.32","26.47"],"02":["7.5","9.4","17.5","19.3","19.4","22.30","26.30"],"update":["7.5","17.5"],"the":["7.5","17.5","21.4","22.10","25.4"],"tip":["8.2","8.3","18.2","18.3"],"50px":["8.2","8.3","8.5","18.2","18.3","18.5"],"potser":["8.4","18.4"],"setting":["9.2","19.5"],"item":["9.3","9.4","19.3","19.4"],"onselect":["9.4","19.4","22.30","26.30"],"pip":["9.5","19.5"],"mode":["9.5","19.5"],"close":["9.5","19.5"],"height":["9.5","9.8","19.8"],"add":["9.7"],"slider":["9.7","19.7"],"state":["9.8","19.8"],"range":["9.9","19.9","24.13"],"attached":["10.0","11.0"],"note":["10.2","10.4","15.12","15.16","15.33","22.7","22.10","22.47"],"to":["10.2","12.42","12.43","14.0","22.1"],"easily":["10.2"],"distinguish":["10.2"],"between":["10.2"],"and":["10.2","15.29"],"by":["10.4"],"zh":["10.6"],"cn":["10.6"],"of":["10.8","10.9","10.10","10.16","12.45","16.1","22.1"],"div":["10.8","10.9","10.10","10.11","10.12","10.16","15.5","15.29","19.6","22.11","22.21","22.27","22.36","22.37","22.38","22.41","22.48","26.37"],"classname":["10.8","10.9","10.10","10.12","10.13","10.15","10.16","15.4","15.5","15.29","15.42","19.6","22.21","22.27","22.36","22.37","22.38","22.41","22.48","22.51","26.37"],"run":["10.8","10.9","10.10","10.12","10.13","10.15","10.16","11.11","15.4","15.5","15.26","15.29","15.42","19.6","22.14","22.15","22.16","22.18","22.21","22.26","22.27","22.36","22.37","22.38","22.41","22.44","22.48","22.51","26.37"],"code":["10.8","10.9","10.10","10.12","10.13","10.15","10.16","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","15.4","15.15","15.26","15.29","15.42","19.6","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.23","22.24","22.26","22.27","22.36","22.37","22.38","22.44","22.46","22.48","22.49","22.51","26.37"],"currently":["10.11"],"active":["10.11"],"cues":["10.11"],"overall":["10.11"],"see":["10.12"],"documentation":["10.12"],"for":["10.12","22.1","22.37"],"details":["10.12"],"all":["11.6"],"manually":["12.0","21.0"],"triggering":["12.0"],"enough":["12.42"],"data":["12.42","12.58","20.10"],"through":["12.43"],"is":["12.44","14.0","15.5","17.1"],"already":["12.46"],"been":["12.46","20.13"],"loaded":["12.46","12.50"],"or":["12.46","12.53","22.22"],"media":["12.47","12.49","12.58"],"resource":["12.48"],"type":["12.48","24.13"],"paused":["12.51","12.53","14.0"],"browser":["12.54"],"has":["12.55","12.56","12.57","12.59","20.13"],"but":["12.58"],"currenttime":["12.60"],"changed":["12.61"],"a":["12.62"],"temporary":["12.62"],"names":["13.0"],"are":["13.0"],"in":["13.0"],"uppercase":["13.0"],"only":["13.34"],"ui":["13.34"],"set":["13.34","22.1"],"say":["14.0"],"i":["14.0","24.6"],"want":["14.0","22.10"],"write":["14.0"],"that":["14.0"],"displays":["14.0"],"an":["14.0","22.43"],"image":["14.0"],"ad":["14.0"],"when":["14.0"],"automatically":["15.5","20.6"],"execute":["15.5"],"similar":["15.5","22.11"],"logic":["15.5"],"called":["15.5"],"t":["15.12"],"some":["15.16","22.22"],"videos":["15.16"],"may":["15.16","22.22"],"not":["15.16"],"switch":["15.20"],"visible":["15.29"],"resize":["15.33"],"object":["16.1","18.1","22.11"],"triggered":["17.1"],"after":["17.1"],"yellow":["19.3"],"step":["19.6","24.13"],"pnpm":["20.1","23.1"],"unpkg":["20.2","20.11","23.2","24.3"],"player":["20.3","22.47"],"s":["20.3"],"dimensions":["20.3"],"depend":["20.3"],"instance":["20.4","22.41"],"getinstance":["20.4"],"path":["20.5"],"imported":["20.6"],"useref":["20.8","23.8"],"export":["20.10"],"return":["20.10"],"https":["20.11"],"cdn":["20.11","23.11"],"npm":["20.11","23.11"],"dist":["20.11","23.11"],"plugin":["20.12"],"danmuku":["20.12"],"doctype":["20.12","23.12"],"agent":["20.13"],"added":["20.13"],"head":["20.13"],"title":["20.13"],"demo":["20.13","23.13"],"you":["21.0","22.10"],"need":["21.0","22.1"],"import":["21.0"],"change":["21.4","25.4"],"size":["22.1"],"example":["22.1"],"equivalent":["22.4"],"muted":["22.10"],"if":["22.10","24.6"],"css":["22.11","26.1"],"fit":["22.11"],"cover":["22.11"],"description":["22.19"],"increase":["22.19"],"volume":["22.19","23.9"],"decrease":["22.19"],"forward":["22.19"],"backward":["22.19"],"this":["22.22","26.4"],"cause":["22.22"],"performance":["22.22"],"compatibility":["22.22"],"issues":["22.22"],"low":["22.22"],"via":["22.27"],"menu":["22.31","26.31"],"left":["22.32","26.32"],"something":["22.35","26.35"],"dosomething":["22.35","26.35"],"onvttload":["22.37"],"modifying":["22.37"],"text":["22.37","24.6","24.12"],"loading":["22.39","26.39"],"current":["22.41"],"modify":["22.43"],"existing":["22.43"],"because":["22.47"],"uses":["22.47"],"as":["22.47"],"key":["22.47"],"class":["23.3"],"get":["23.4"],"d":["23.6"],"选项":["23.10"],"lang":["23.12","25.2","25.3"],"meta":["23.13"],"charset":["23.13"],"utf":["23.13"],"com":["24.3"],"默认":["24.4"],"顶部":["24.4"],"底部":["24.4"],"是否开启热力图":["24.5"],"当播放器宽度小于此值时":["24.5"],"弹幕发射器置于播放器底部":["24.5"],"points":["24.5"],"热力图数据":["24.5"],"filter":["24.5"],"弹幕载入前的过滤器":["24.5"],"只支持返回布尔值":["24.5"],"beforeemit":["24.5"],"弹幕发送前的过滤器":["24.5"],"支持返回":["24.5"],"你可以对弹幕做合法校验":["24.6"],"或者做存库处理":["24.6"],"当返回true后才表示把弹幕加入到弹幕队列":["24.6"],"async":["24.6"],"const":["24.6"],"isdirty":["24.6"],"fuck":["24.6"],"test":["24.6"],"plugins":["24.10"],"artplayerplugindanmuku":["24.10"],"xml":["24.11","24.12"],"隐藏弹幕":["24.11"],"发送弹幕":["24.12"],"弹幕大小":["24.13"],"input":["24.13"],"min":["24.13"],"max":["24.13"],"重新加载当前弹幕库":["24.14"],"切换":["24.14"],"error":["24.18"],"加载错误":["24.18"],"config":["24.18"],"配置变化":["24.18"],"外":["25.0"],"不再捆绑其它多国语言":["25.0"],"需要自行导入需要的语言":["25.0"],"language":["25.4"],"您可能需要初始化容器元素的大小":["26.1"],"如":["26.1"],"等同于":["26.4"],"document":["26.27"],"queryselector":["26.27"],"control":["26.32"],"文本的函数":["26.37"],"修改现有的语言":["26.43"],"id":["26.47"]},{"0":["5.12","20.5","20.9"],"1":["9.8","13.25","19.8","24.13"],"2":["13.26"],"3":["22.1"],"4":["22.6","22.11","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.26","22.37","22.38","22.41","22.44","22.48","22.51"],"5":["9.8","13.23","19.8","20.9","23.9"],"6":["15.42"],"7":["15.4","15.29","22.27","22.38"],"8":["20.13","22.41","23.12"],"9":["15.5","22.29","26.29"],"10":["9.8","13.12","13.14","13.27","19.8"],"11":["22.43","26.43"],"12":["22.37","26.37"],"20":["13.11"],"22":["9.2","9.6","9.7","19.2","19.5","19.7"],"25":["24.13"],"32":["0.14","10.14"],"60":["22.34","26.34"],"120":["26.34"],"150":["9.3","19.3"],"200":["24.5"],"404":["2.11","12.11"],"500":["13.21"],"1000":["22.2"],"2000":["13.24"],"3000":["5.12","13.15"],"5000":["13.4","13.13","13.16"],"二级属性":["0.0"],"mp4":["0.1","0.11","0.12","0.13","0.15","2.1","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.19","2.21","2.23","2.25","2.26","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.6","3.7","3.29","3.30","5.1","5.2","5.3","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.17","5.18","5.19","5.21","5.25","5.26","5.30","5.31","5.35","5.36","5.37","5.39","5.41","5.47","9.1","9.6","10.8","10.9","10.10","10.16","12.2","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.16","12.17","12.18","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.39","12.41","13.30","15.1","15.2","15.3","15.8","15.9","15.10","15.11","15.13","15.14","15.18","15.19","15.21","15.25","15.30","15.31","15.32","15.34","15.35","15.36","15.37","15.46","15.47","19.6","20.5","22.33","22.34","22.50","23.5","24.15","24.16","25.1","26.7","26.25","26.33","26.36","26.50"],"console":["0.1","0.3","0.5","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.11","1.12","3.2","5.9","5.14","5.15","5.16","5.23","5.28","5.30","5.31","5.32","5.34","5.35","5.36","5.44","7.3","8.2","8.3","10.3","10.17","13.2","15.28","15.32","15.34","15.41","15.44","17.3","18.2","18.3","22.29","22.31","22.32","26.29","26.30","26.31"],"info":["0.1","0.3","0.5","1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.12","5.9","5.14","5.16","5.23","5.28","5.31","5.32","5.34","5.35","5.36","7.3","8.2","8.3","10.3","10.17","15.28","15.34","15.41","17.3","18.2","18.3","22.29","22.31","22.32","26.29","26.30","26.31"],"warning":["0.2","1.6","5.12","10.1","10.5","10.6","15.20","15.22","15.41","21.0","22.2","22.4","22.17","22.19","22.40","23.3","23.4","26.10","26.40","26.47"],"提示":["0.2","5.12","23.3","26.47"],"为了方便区别":["0.2"],"元素和普通对象":["0.2"],"播放器里的所有":["0.2"],"click":["0.3","5.20","5.22","6.1","8.1","8.2","8.3","10.3","15.41","16.1","18.1","18.2","18.3","22.29","22.32","24.10","24.11","26.29","26.31","26.32"],"event":["0.3","10.3","16.1","24.11"],"你可以修改":["0.4"],"即可":["0.4"],"zh":["0.6"],"cn":["0.6","21.4","25.4"],"your":["0.6","10.6","15.33","20.3","21.3","21.4","22.3","25.3","25.4","26.3"],"ready":["0.7","0.8","0.11","0.13","0.14","0.15","0.16","2.6","2.18","2.22","2.24","5.9","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.23","5.28","5.30","5.31","5.32","5.33","5.34","5.35","5.36","5.45","5.46","6.5","8.5","9.9","10.7","12.18","12.22","12.24","15.9","15.11","15.13","15.14","15.23","15.28","15.31","15.32","15.34","15.35","15.36","15.44","15.45","15.46","16.5","18.5","19.9"],"html":["0.8","0.9","0.10","5.20","5.22","14.0","24.10"],"some":["0.8","0.9","0.10"],"text":["0.8","0.9","0.10","17.1"],"position":["0.9","5.22","5.37","7.1","8.4","14.0","17.1","18.4","24.10"],"video":["0.11","0.12","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.16","2.19","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.5","3.6","3.7","3.28","3.29","3.30","5.1","5.6","5.7","5.8","5.10","5.15","5.17","5.18","5.19","5.21","5.24","5.25","5.26","5.27","5.29","5.30","5.37","5.39","5.41","5.47","9.1","10.8","10.9","10.10","10.16","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.23","12.24","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","15.21","15.30","15.31","15.32","15.36","15.37","15.47","19.6","20.5","22.25","22.33","22.34","22.42","22.50","23.5","24.7","24.16","25.1","26.7","26.17","26.25","26.33","26.36","26.50"],"on":["0.11","0.12","0.13","0.14","0.15","0.16","2.6","2.11","2.12","2.18","2.24","5.8","5.9","5.10","5.11","5.13","5.14","5.15","5.16","5.18","5.19","5.21","5.23","5.28","5.30","5.31","5.32","5.34","5.35","5.36","5.45","5.46","6.4","6.5","7.4","10.9","10.10","12.2","12.6","12.18","12.22","12.24","15.9","15.11","15.13","15.14","15.23","15.30","15.31","15.32","15.34","15.35","15.36","15.45","15.46","16.4","16.5","17.4","22.4"],"assets":["0.12","1.1","2.1","2.3","2.4","2.14","2.41","3.5","3.6","3.7","3.8","3.9","3.10","3.17","3.28","3.29","5.1","5.4","5.5","5.6","5.7","5.17","5.24","5.26","5.27","5.29","5.38","5.39","5.40","5.41","5.42","5.43","10.8","10.9","10.10","10.13","10.15","10.16","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.19","12.21","12.23","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.28","13.29","13.30","15.1","15.6","15.7","15.8","15.10","15.11","15.13","15.15","15.17","15.18","15.19","15.21","15.24","15.25","15.26","15.27","15.30","15.36","15.38","15.39","15.40","19.1","19.6","21.1","22.25","22.33","22.36","22.42","22.50","24.7","24.8","24.16","26.5","26.7","26.17","26.25","26.36","26.37","26.42"],"sample":["0.12","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.19","2.27","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.40","2.41","3.5","3.6","3.7","3.8","3.9","3.10","3.17","3.28","3.29","3.30","5.1","5.6","5.7","5.8","5.10","5.17","5.24","5.25","5.26","5.27","5.29","5.37","5.38","5.39","5.40","5.41","5.42","9.1","10.8","10.9","10.10","10.13","10.15","10.16","12.1","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.19","12.21","12.23","12.25","12.26","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.29","13.30","15.1","15.3","15.8","15.9","15.10","15.11","15.13","15.14","15.15","15.18","15.19","15.21","15.25","15.26","15.30","15.31","15.32","15.35","15.36","15.37","15.47","19.1","19.6","21.1","22.25","22.33","22.36","22.42","22.50","24.7","24.16","25.1","26.5","26.7","26.17","26.25","26.36","26.37","26.42","26.50"],"subtitleoffset":["0.16"],"return":["0.17","9.3","9.4","10.17","19.3","19.4","24.9","24.12"],"name":["0.17","10.17"],"something":["0.17"],"dosomething":["0.17"],"一级属性":["1.0","5.0"],"app":["1.1","3.3","3.8","3.9","3.10","3.11","3.12","3.13","3.17","3.22","3.23","3.28","3.29","3.33","5.4","5.5","5.6","5.7","5.24","5.26","5.29","5.38","5.40","5.42","5.43","10.8","10.9","10.10","10.13","10.15","10.16","12.1","12.3","12.4","12.11","12.14","12.19","12.32","12.33","12.34","12.35","12.36","12.37","12.38","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.28","13.29","13.30","15.6","15.7","15.15","15.17","15.18","15.19","15.24","15.25","15.26","15.27","15.29","15.38","15.39","15.40","15.43","19.1","19.6","20.13","21.1","22.5","22.9","22.13","22.25","22.27","22.33","22.36","22.37","22.42","24.8","26.5","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.23","26.24","26.26","26.28","26.36","26.37","26.38","26.41","26.42","26.44","26.45","26.46","26.48","26.49","26.51"],"url":["1.1","3.6","3.7","3.8","3.9","3.10","3.17","3.22","3.28","3.29","5.4","5.5","5.6","5.7","5.24","5.26","5.27","5.29","5.38","5.39","5.40","5.41","5.42","5.43","10.8","10.9","10.10","10.13","10.15","10.16","12.1","12.3","12.4","12.5","12.9","12.11","12.13","12.14","12.15","12.19","12.21","12.23","12.25","12.27","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.28","13.29","13.30","15.1","15.6","15.7","15.15","15.17","15.21","15.24","15.25","15.26","15.27","15.30","15.38","15.39","15.40","15.43","19.1","19.6","21.1","22.3","22.25","22.42","23.5","24.7","24.8","24.16","26.3","26.5","26.8","26.9","26.13","26.14","26.15","26.16","26.17","26.21","26.25","26.26","26.38","26.42","26.45","26.46","26.51"],"全部工具函数请参考以下地址":["1.6"],"js":["1.11","10.8","10.11","10.12","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","13.2","13.34","15.5","15.29","22.11","22.21","22.27","22.37","22.38","22.41","22.48","22.51"],"emit":["2.0","12.0"],"focus":["2.0","12.0"],"移除事件":["2.0"],"true":["2.16","2.17","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.39","3.30","5.2","5.3","5.21","6.2","6.4","6.5","9.1","9.6","10.16","12.17","12.20","12.28","13.1","13.20","13.33","15.2","15.3","16.2","16.4","16.5","19.2","19.6","24.16","26.10","26.33","26.47"],"setting":["2.17","2.20","2.28","3.30","9.1","9.6","12.17","12.20","13.30","19.2","19.6","22.7"],"fullscreen":["2.22"],"srt":["2.28","2.29","2.30","2.31","12.31"],"并调用":["2.46"],"但数据意外未出现":["2.58"],"属性名字全部都是大写的形式":["3.0"],"未来容易发生变动":["3.0"],"new":["3.1","3.4","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.34","10.8","10.9","10.10","10.11","10.12","10.13","10.15","11.1","13.1","13.3","13.4","13.10","13.11","13.12","13.13","13.17","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.26","13.27","13.28","13.29","13.31","13.32","13.33","15.4","15.5","15.26","15.29","15.42","22.3","22.5","22.6","22.8","22.9","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.23","22.24","22.26","22.28","22.35","22.36","22.37","22.38","22.44","22.45","22.46","22.48","22.49","22.51","23.9","26.6","26.11","26.22","26.35","26.37","26.41"],"container":["3.1","3.3","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.28","3.31","3.32","3.33","3.34","5.5","5.29","10.8","10.9","10.10","10.11","10.12","10.13","10.15","10.16","11.1","13.3","13.6","13.7","13.8","13.9","13.10","13.11","13.17","13.22","13.28","13.29","15.4","15.5","15.6","15.7","15.15","15.17","15.24","15.26","15.27","15.29","15.38","15.39","15.40","15.42","15.43","19.1","20.3","22.5","22.6","22.8","22.9","22.12","22.13","22.14","22.15","22.16","22.20","22.23","22.24","22.27","22.28","22.36","22.37","22.45","22.46","22.49","22.51","23.10","24.8","26.3","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.28","26.36","26.37","26.38","26.41","26.44","26.45","26.46","26.48","26.49","26.51"],"log":["3.2","5.44","15.44"],"art":["3.14","3.15","3.16","3.19","3.20","3.25","3.26","3.31","3.34","10.8","10.9","10.10","10.11","10.13","10.15","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.28","13.31","13.32","13.33","15.4","15.5","15.29","15.42","20.9","22.3","22.5","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.23","22.24","22.26","22.36","22.37","22.38","22.44","22.45","22.46","22.48","22.49","22.51","23.9","26.11","26.22","26.27","26.37"],"var":["3.34","10.8","10.9","10.10","10.11","10.12","11.1","13.1","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","15.4","15.5","15.29","15.42","22.6","22.8","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.23","22.24","22.26","22.27","22.35","22.36","22.37","22.38","22.41","22.44","22.45","22.46","22.48","22.49","22.51","26.11","26.35","26.37"],"show":["4.0","6.2","6.3","6.4","14.0","16.2","16.3","16.4"],"block":["4.0","14.0"],"hide":["4.0","14.0"],"controls":["4.0","5.37","15.37","17.1","24.10"],"tooltip":["4.0","7.1","9.7","19.7","26.32"],"muted":["5.2","5.3","5.25","15.2","15.3","26.10"],"seek":["5.11","5.13"],"t":["5.12"],"right":["5.20","5.22","8.3","8.4","14.0","17.1","18.3","18.4","24.10","26.29"],"switch":["5.20","15.12"],"function":["5.20","5.22","6.1","8.1","8.2","8.3","16.1","18.1","18.2","18.3","22.29","22.31","22.32","24.9","24.11","24.13","26.29","26.31"],"theme":["5.44","15.44"],"settimeout":["5.45","6.5","8.5","9.9","10.14","15.45","16.5","18.5","19.9","26.2"],"subtitle":["5.47","12.29","12.30"],"object":["6.1","8.1"],"组件样式对象":["6.1","8.1"],"false":["6.2","6.3","6.4","9.5","13.19","13.31","13.34","16.2","16.3","16.4","19.5","24.6"],"update":["6.5","8.5","9.9"],"组件挂载后触发":["7.1"],"组件的提示文本":["7.1"],"yellow":["7.2","17.2"],"02":["7.2","17.2"],"onselect":["7.2","17.2"],"item":["7.2","9.5","17.2"],"dom":["7.2","17.2"],"args":["7.3","8.2","8.3","17.3","18.2","18.3","22.29","22.31","22.32","26.29","26.31"],"mounted":["7.3","8.2","8.3","17.3","18.2","18.3","24.13"],"style":["7.4","14.0","17.4","20.5","22.32","23.5","24.13","26.32"],"color":["7.4","17.4","22.32","24.4","26.32"],"red":["7.4","17.4"],"control":["7.5","17.5"],"by":["7.5","8.5","9.9","17.5","18.5","19.9","22.2","22.47"],"absolute":["8.4","14.0","18.4"],"top":["8.4","14.0","18.4"],"50px":["8.4","18.4"],"the":["8.5","9.9","18.5","19.9","20.4"],"button":["9.2"],"img":["9.2","9.6","9.7","14.0","19.2","19.5","19.7"],"height":["9.2","9.6","19.2","19.5","20.5","22.1","23.5","26.1"],"src":["9.2","9.5","14.0","19.5","22.39","26.39"],"quality":["9.3","19.3"],"1080p":["9.3","19.3"],"state":["9.5","22.39","24.6","26.39"],"svg":["9.5","9.8","19.5","19.8"],"settings":["9.6","10.4","19.2","19.6"],"slider":["9.6"],"5x":["9.6","9.7","19.6","19.7"],"width":["9.6","9.7","14.0","19.5","19.7","20.5","22.1","23.5","26.1"],"icon":["9.7","19.7"],"range":["9.8","19.8"],"instance":["10.0","23.4"],"which":["10.0","17.1"],"note":["10.1","15.20","15.22","15.41","22.2","22.17","22.19"],"if":["10.1","10.4","15.41","20.11","22.47","24.11","24.12"],"you":["10.1","10.4","15.41","20.6"],"directly":["10.1","20.4"],"regular":["10.2"],"objects":["10.2"],"within":["10.2"],"are":["10.2"],"mouseenter":["10.3"],"instances":["10.4"],"share":["10.4"],"same":["10.4","15.12"],"localstorage":["10.4"],"and":["10.4","12.46","15.12"],"want":["10.4"],"different":["10.4"],"players":["10.4"],"use":["10.4"],"loading":["10.5"],"this":["10.5","22.40"],"is":["10.5","12.48","15.33","20.4"],"using":["10.6"],"can":["10.6","22.40"],"only":["10.6","22.40"],"to":["10.7","11.6","15.20","15.22","20.5","23.5"],"artplayer":["10.8","10.9","10.10","10.11","10.12","10.13","10.15","10.16","13.34","15.4","15.6","15.15","15.17","15.26","15.29","15.38","15.39","15.40","15.42","22.3","22.5","22.6","22.8","22.9","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.28","22.35","22.36","22.37","22.38","22.44","22.45","22.46","22.49","22.51","26.6","26.11","26.12","26.18","26.20","26.22","26.23","26.24","26.28","26.35","26.37","26.38","26.41","26.44","26.48","26.49","26.51"],"classname":["10.11","13.34","22.11","22.22"],"run":["10.11","13.34","22.11","22.22"],"code":["10.11","13.34","15.5","22.11","22.22","22.41"],"flip":["10.16"],"playbackrate":["10.16"],"constructor":["11.0"],"please":["11.6"],"refer":["11.6"],"removing":["12.0"],"through":["12.42"],"end":["12.43"],"without":["12.43"],"duration":["12.45"],"partially":["12.46"],"reached":["12.47"],"not":["12.48","20.4"],"has":["12.49"],"delayed":["12.53"],"due":["12.53","15.20","15.22","22.17"],"loads":["12.54"],"changed":["12.55"],"completed":["12.56"],"begun":["12.57"],"been":["12.59"],"property":["12.60"],"lack":["12.62"],"these":["13.0","22.19"],"subject":["13.0"],"change":["13.0"],"div":["13.34","20.13","22.22","23.13"],"ads":["14.0"],"100px":["14.0"],"display":["14.0","24.13"],"none":["14.0"],"20px":["14.0"],"have":["15.12","15.16"],"functionality":["15.12"],"a":["15.16","21.0"],"such":["15.16"],"as":["15.16"],"live":["15.16"],"streams":["15.16"],"or":["15.16","17.1","22.1"],"browser":["15.20","15.22","22.17"],"security":["15.20","15.22","22.17"],"mechanisms":["15.22","22.17"],"jpg":["15.23"],"json":["15.28"],"stringify":["15.28"],"useful":["15.33"],"but":["15.33"],"need":["15.41"],"certain":["15.41"],"left":["17.1"],"side":["17.1"],"bun":["20.1","23.1"],"com":["20.2","20.11","23.2","23.11"],"of":["20.3"],"its":["20.3"],"therefore":["20.3"],"must":["20.3"],"reactive":["20.4"],"modifying":["20.4"],"600px":["20.5","23.5"],"400px":["20.5","22.1","26.1"],"margin":["20.5"],"60px":["20.5"],"auto":["20.5"],"when":["20.6","21.0"],"null":["20.8","23.8"],"volume":["20.9"],"option":["20.10","23.10"],"tip":["20.11"],"lang":["20.12","21.2","21.3"],"en":["20.12","23.12"],"head":["20.12","23.12"],"meta":["20.12","20.13","23.12"],"charset":["20.12","20.13","23.12"],"utf":["20.12","20.13","23.12"],"body":["20.13","23.13"],"class":["20.13","23.13"],"require":["21.0"],"cannot":["21.0"],"be":["21.0"],"matched":["21.0"],"script":["21.2","25.2"],"play":["21.4","22.19","25.4"],"css":["22.1"],"300px":["22.1","26.1"],"three":["22.2"],"file":["22.2"],"formats":["22.2"],"caches":["22.7"],"last":["22.7"],"upon":["22.7","22.10"],"immediately":["22.10"],"page":["22.10"],"load":["22.10"],"space":["22.19"],"toggle":["22.19"],"pause":["22.19"],"devices":["22.22"],"older":["22.22"],"browsers":["22.22"],"document":["22.27"],"queryselector":["22.27"],"opacity":["22.29","26.29"],"setting02":["22.30","26.30"],"green":["22.32","26.32"],"one":["22.34","26.34"],"more":["22.34","26.34"],"chance":["22.34","26.34"],"ploading":["22.39","26.39"],"gif":["22.39","26.39"],"recognition":["22.40"],"player":["22.40"],"parse":["22.40"],"suffixes":["22.40"],"like":["22.40"],"cache":["22.47"],"progress":["22.47"],"however":["22.47"],"for":["22.47"],"播放器的尺寸依赖于容器":["23.3"],"getinstance":["23.4"],"path":["23.5"],"ts":["23.6"],"types":["23.10"],"const":["23.10"],"unpkg":["23.11"],"title":["23.12"],"pnpm":["24.2"],"ffffff":["24.4"],"弹幕颜色":["24.4"],"默认为白色":["24.4"],"promise":["24.5"],"beforevisible":["24.5"],"弹幕显示前的过滤器":["24.5"],"visible":["24.5"],"弹幕层是否可见":["24.5"],"emitter":["24.5"],"是否开启弹幕发射器":["24.5"],"maxlength":["24.5"],"弹幕输入框最大长度":["24.5"],"await":["24.6"],"这里是所有弹幕的过滤器":["24.6"],"包含来自服务端的和来自用户输入的":["24.6"],"plugins":["24.9","24.15","24.16","24.17"],"artplayerplugindanmuku":["24.9","24.15","24.16","24.17"],"xml":["24.10"],"隐藏弹幕":["24.10"],"prompt":["24.12"],"请输入弹幕文本":["24.12"],"弹幕测试文本":["24.12"],"trim":["24.12"],"value":["24.13"],"flex":["24.13"],"alignitems":["24.13"],"center":["24.13"],"切换到新的弹幕库":["24.14"],"config":["24.14"],"v2":["24.14"],"fullscreenweb":["24.16"],"stop":["24.18"],"弹幕停止":["24.18"],"start":["24.18"],"弹幕开始":["24.18"],"当无法匹配到语言时":["25.0"],"会默认显示英文":["25.0"],"i18n":["25.0","25.3"],"或者使用":["26.1"],"aspect":["26.1"],"热键":["26.19"],"描述":["26.19"],"增加音量":["26.19"],"降低音量":["26.19"],"innerhtml":["26.27"],"sd":["26.33"],"后缀的识别":["26.40"],"播放器只能解析这种后缀":["26.40"],"因为播放器默认使用":["26.47"]},{"0":["23.5"],"2":["5.31"],"4":["22.22"],"5":["5.8","5.9","5.15","15.8","26.7"],"8":["2.0","12.0","20.12"],"9":["5.32","22.1"],"10":["5.11","5.13","15.11","15.13"],"16":["5.32","15.32","22.1","24.12","26.1"],"22":["19.6"],"60":["22.36","24.5","26.36"],"120":["22.34"],"180":["22.34","26.34"],"200":["24.6"],"240":["26.34"],"360":["9.3"],"720":["9.3","19.3"],"1000":["0.8","0.9","0.10","0.16","24.5","26.2"],"1080":["9.3","19.3"],"5000":["0.14","10.14"],"比较少用":["0.0"],"warning":["0.1","0.5","0.6","0.7","0.8","5.16","5.20","5.22","5.28","5.33","5.41","10.3","10.7","10.14","15.28","20.5","20.13","22.29","22.30","22.31","22.32","22.39","22.42","22.50","23.13","26.2","26.4","26.7","26.17","26.19","26.31","26.32","26.39","26.42","26.50"],"提示":["0.1","5.16","5.20","5.22","5.33","26.2","26.7","26.10","26.17"],"假如直接修改这个":["0.1"],"元素都是以":["0.2"],"开头命名的":["0.2"],"这是所有":["0.2"],"元素的定义":["0.2"],"mouseenter":["0.3"],"mouseleave":["0.3","10.3"],"loading":["0.5","12.49"],"这是所有图标的定义":["0.5"],"types":["0.5","1.6","11.6","25.0","26.50"],"使用":["0.6","24.9"],"只能更新实例化之后的":["0.6"],"to":["0.7","22.2"],"play":["0.7","4.0","5.2","10.7","15.2","21.3","22.2","25.3"],"如果想马上隐藏":["0.7"],"settimeout":["0.8","0.9","0.10","0.12","0.13","0.14","0.15","0.16","5.2","5.3","5.8","5.11","5.13","5.21","6.4","7.4","8.4","9.8","10.8","10.9","10.10","10.16","15.2","15.8","15.11","15.13","16.4","17.4","18.4","19.8"],"false":["0.8","0.9","0.10","0.15","0.16","22.29","22.31","24.4","26.29","26.31"],"left":["0.9","7.1","10.9"],"true":["0.10","0.12","0.13","2.19","3.5","3.6","3.7","3.28","3.29","5.1","5.14","5.25","5.34","6.3","10.10","12.16","12.19","12.21","12.22","12.23","12.24","12.25","12.26","12.39","13.5","13.6","13.7","13.28","13.29","13.30","15.1","15.21","15.25","15.34","16.3","19.1","22.25","22.33","26.17","26.25"],"srt":["0.11","5.47","12.28","12.29","12.30","15.47"],"ready":["0.12","5.2","5.3","5.5","5.6","5.7","5.8","5.10","5.17","5.21","5.24","5.25","5.26","5.27","5.29","6.4","7.4","8.4","9.8","10.8","10.9","10.10","10.11","10.12","10.13","10.15","10.16","12.0","12.6","15.2","15.3","15.5","15.8","15.10","15.15","15.17","15.18","15.19","15.21","15.25","15.26","15.29","15.30","16.4","17.4","18.4","19.8","24.17"],"on":["0.17","2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.13","2.14","2.15","2.16","2.17","2.19","2.20","2.21","2.23","2.25","2.26","2.27","2.28","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.8","3.9","3.10","3.17","5.1","5.2","5.3","5.4","5.5","5.6","5.7","5.17","5.24","5.25","5.26","5.27","5.29","5.38","5.39","5.40","5.47","8.4","9.8","10.8","10.11","10.12","10.13","10.15","10.16","12.1","12.3","12.4","12.5","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.17","12.19","12.20","12.21","12.23","12.25","12.26","12.27","12.28","12.29","12.30","12.31","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.8","13.9","13.10","13.17","15.1","15.2","15.3","15.5","15.6","15.7","15.8","15.10","15.15","15.17","15.18","15.19","15.20","15.21","15.22","15.24","15.25","15.26","15.27","15.29","15.38","15.39","15.40","15.47","17.1","18.4","19.8","24.15","24.17","26.4"],"非常少使用":["1.0"],"sample":["1.1","3.1","3.3","3.4","3.11","3.12","3.13","3.18","3.21","3.22","3.23","3.24","3.27","3.31","3.32","3.33","3.34","5.4","5.5","5.43","10.11","10.12","11.1","13.8","13.9","13.10","13.11","13.12","13.13","13.17","13.21","13.22","13.23","13.24","13.28","13.33","13.34","15.4","15.5","15.6","15.7","15.17","15.24","15.27","15.29","15.38","15.39","15.40","15.42","15.43","20.10","22.5","22.6","22.8","22.9","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.28","22.35","22.37","22.38","22.41","22.44","22.45","22.46","22.49","22.51","23.10","24.8","26.6","26.8","26.9","26.11","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.28","26.35","26.38","26.41","26.44","26.45","26.46","26.48","26.49","26.51"],"video":["1.1","3.8","3.9","3.10","3.11","3.12","3.13","3.17","3.21","3.22","3.23","3.24","3.31","3.33","5.4","5.5","5.42","10.11","10.13","10.15","11.1","12.1","12.14","13.6","13.7","13.8","13.9","13.10","13.17","13.22","13.28","15.4","15.24","15.26","15.29","15.39","15.42","19.1","20.10","21.1","22.9","22.13","22.28","22.36","23.10","24.8","26.5","26.6","26.8","26.9","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.28","26.37","26.38","26.42","26.44","26.45","26.46","26.48","26.49"],"mp4":["1.1","3.8","3.9","3.10","3.17","3.22","3.28","3.34","5.4","5.5","5.6","5.7","5.24","5.27","5.29","5.38","5.40","5.42","5.43","10.11","10.12","10.13","10.15","12.1","12.3","12.4","12.11","12.14","12.19","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.40","13.5","13.6","13.7","13.8","13.9","13.10","13.17","13.22","13.28","13.29","13.34","15.4","15.5","15.6","15.7","15.15","15.17","15.24","15.26","15.27","15.29","15.38","15.39","15.40","15.42","15.43","19.1","20.10","21.1","22.5","22.25","22.36","22.37","22.38","22.42","23.10","24.7","24.8","26.5","26.8","26.9","26.13","26.14","26.15","26.16","26.17","26.21","26.26","26.37","26.38","26.42","26.45","26.46","26.51"],"artplayer":["1.2","1.3","1.4","1.5","1.7","1.8","1.9","1.10","1.11","1.12","3.2","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","13.2","22.11","22.21","22.22","22.41","22.48"],"d":["1.6"],"info":["1.11","2.12","5.15","5.26","5.29","5.30","5.41","5.42","9.5","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","15.9","15.14","15.15","15.23","15.26","15.29","15.30","15.31","15.32","15.35","15.36","19.5","24.17","26.32"],"const":["2.0","5.18","5.19","9.5","12.0","15.18","15.19","19.5","20.10","24.13"],"onready":["2.0","12.0"],"console":["2.1","2.3","2.4","2.5","2.7","2.8","2.9","2.10","2.11","2.12","2.13","2.14","2.15","2.16","2.17","2.18","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.29","2.30","2.31","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.40","2.41","5.25","5.26","5.29","5.39","5.41","5.42","5.43","9.5","11.2","11.3","11.4","11.5","11.7","11.8","11.9","11.10","11.11","11.12","12.5","12.7","12.8","12.9","12.10","12.12","12.13","12.15","12.27","12.31","12.41","15.9","15.14","15.15","15.23","15.26","15.29","15.30","15.31","15.35","15.36","15.42","15.43","19.5","20.5","23.5","24.17","26.32"],"event":["2.5","2.7","2.8","2.9","2.10","2.12","2.13","2.22","2.41","5.41","9.2","9.5","12.5","12.7","12.8","12.9","12.10","12.12","12.13","12.22","18.1"],"reconnecttime":["2.11","12.11"],"state":["2.12","2.15","2.16","2.21","2.23","2.24","2.25","2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","9.2","9.6","9.7","12.12","12.15","12.21","12.23","12.24","12.25","12.32","12.33","12.34","12.35","12.36","12.37","12.38","19.2","19.7"],"height":["2.18","9.7","19.6","19.7"],"datauri":["2.26","12.26"],"currenttime":["2.27","12.27"],"offset":["2.28"],"cues":["2.29","2.30","2.31","12.29","12.30","12.31"],"option":["2.31","12.31"],"load":["2.46","12.46"],"方法重新加载它":["2.46"],"基本上用不到":["3.0"],"app":["3.1","3.4","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.24","3.25","3.26","3.27","3.31","3.32","3.34","10.11","10.12","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","13.34","15.4","15.5","15.42","20.10","22.3","22.6","22.8","22.11","22.12","22.14","22.15","22.16","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.28","22.35","22.38","22.41","22.44","22.45","22.46","22.48","22.49","22.51","23.10","23.13","26.3","26.11","26.22","26.35"],"url":["3.1","3.3","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.33","3.34","10.12","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.22","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","13.34","15.4","15.5","15.29","15.42","20.10","22.5","22.6","22.8","22.9","22.11","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.28","22.35","22.38","22.44","22.45","22.46","22.48","22.49","22.51","23.10","26.6","26.11","26.12","26.18","26.20","26.22","26.23","26.24","26.27","26.28","26.35","26.44","26.48","26.49"],"assets":["3.1","3.3","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.22","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.33","3.34","10.11","10.12","11.1","13.3","13.4","13.8","13.9","13.10","13.11","13.12","13.13","13.17","13.18","13.21","13.22","13.23","13.24","13.31","13.32","13.33","13.34","15.4","15.5","15.29","15.42","15.43","20.10","22.5","22.6","22.8","22.9","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.28","22.35","22.37","22.38","22.41","22.44","22.45","22.46","22.48","22.49","22.51","23.10","26.3","26.6","26.8","26.9","26.11","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.21","26.22","26.23","26.24","26.26","26.27","26.28","26.35","26.38","26.41","26.44","26.45","26.46","26.48","26.49","26.51"],"loop":["3.5","3.6","3.7","13.5","13.6","13.7"],"flip":["3.5","3.6","3.7","13.5","13.6","13.7"],"dblclick":["3.17"],"setting":["3.28","3.29","12.28","13.28","13.29","19.1","24.13"],"playbackrate":["3.28","13.28"],"contextmenu":["3.28","3.29","3.30","13.29","13.30"],"aspectratio":["3.29","10.16","13.29"],"show":["3.29","3.30","9.8","13.30","19.8","22.29","22.31","24.11","24.18","26.29","26.31"],"click":["4.0","5.37","5.41","14.0","15.37"],"marginright":["4.0","14.0"],"比较常用":["5.0"],"muted":["5.1","15.1","15.25"],"seek":["5.8","15.8","15.11","15.13"],"switch":["5.12"],"和":["5.12","7.1","24.5"],"的功能是一样的":["5.12"],"只是":["5.12"],"有的视频是没有时长的":["5.16"],"async":["5.18","5.19","15.18","15.19"],"await":["5.18","5.19","15.18","15.19"],"t":["5.23"],"json":["5.28"],"stringify":["5.28"],"resize":["5.33","24.15"],"当你的容器只有宽度":["5.33"],"playsinline":["5.34","15.34"],"m3u8":["5.35","22.2","26.41"],"000":["5.36"],"right":["5.37","7.1","15.37"],"html":["5.37","10.8","10.9","10.10","15.37"],"timeupdate":["5.39"],"green":["5.44","15.44"],"1080p":["5.45","15.45"],"png":["5.46","15.46","22.36","22.39","26.36","26.39"],"组件点击事件":["6.1","8.1"],"mounted":["6.1","8.1","16.1","18.1","22.29","26.29"],"组件挂载后触发":["6.1","8.1"],"get":["6.2","6.3","7.2","7.3","8.2","8.3","16.2","16.3","17.2","17.3","18.2","18.3"],"the":["6.2","6.3","6.4","6.5","7.2","7.3","7.4","8.2","8.3","8.4","9.8","16.2","16.3","16.4","16.5","17.2","17.3","17.4","18.2","18.3","18.4","19.8","22.19"],"element":["6.2","6.3","7.2","7.3","8.2","8.3","16.2","16.3","17.2","17.3","18.2","18.3"],"of":["6.2","6.3","7.2","7.3","8.2","8.3","10.5","12.53","16.2","16.3","17.2","17.3","18.2","18.3"],"by":["6.2","6.3","6.4","6.5","7.2","7.4","8.4","16.2","16.3","16.4","16.5","17.2","17.4","18.4","21.0"],"delete":["6.4","7.4","8.4","9.8","16.4","17.4","18.4","19.8"],"控制控制器出现的左右位置":["7.1"],"selector":["7.1","17.1"],"array":["7.1","17.1"],"return":["7.2","17.2"],"control":["7.2","7.3","7.4","17.2","17.3","17.4"],"200px":["8.5","18.5"],"svg":["9.2","9.6","9.7","19.2","19.6","19.7"],"item":["9.2","9.6","19.2"],"720p":["9.3","19.3"],"360p":["9.3","19.3"],"nextstate":["9.5","19.5"],"src":["9.6","9.7","19.2","19.6","19.7"],"pip":["9.9","19.9"],"mode":["9.9","19.9"],"close":["9.9","19.9"],"are":["10.0","11.0","15.0","22.2"],"less":["10.0"],"commonly":["10.0","15.0"],"modify":["10.1","10.4","20.11","20.13"],"this":["10.1","10.2"],"object":["10.1"],"named":["10.2"],"with":["10.2","20.12","23.12"],"a":["10.2","12.48","15.12","15.20","15.22"],"prefix":["10.2"],"is":["10.2","15.12","20.5","22.47"],"definition":["10.2","10.5"],"note":["10.3","10.14","15.28","20.13","22.4"],"if":["10.3","10.6","10.7","22.4","22.17"],"you":["10.3","10.6","10.7","22.47"],"need":["10.3","20.11","20.13","22.47"],"that":["10.3","15.16"],"should":["10.3"],"only":["10.3","10.14","15.5","15.41","22.19"],"exist":["10.3","15.41"],"during":["10.3"],"can":["10.4"],"after":["10.6","10.14","16.1","18.1","22.19"],"instantiation":["10.6"],"want":["10.6","10.7"],"before":["10.6","20.13"],"hide":["10.7","24.18"],"some":["10.8","10.9","10.10"],"text":["10.8","10.9","10.10","24.7","24.9"],"position":["10.9","15.37"],"these":["10.14"],"take":["10.14","22.19"],"effect":["10.14","22.19"],"subtitleoffset":["10.16"],"something":["10.17"],"dosomething":["10.17"],"which":["11.0","15.0"],"rarely":["11.0"],"following":["11.6","20.11"],"address":["11.6"],"off":["12.0"],"end":["12.42","12.47"],"without":["12.42"],"stopping":["12.42","12.43"],"for":["12.42","12.43","21.0","22.10","22.30","22.31","22.32","22.50"],"property":["12.45"],"changes":["12.45"],"method":["12.46","15.12"],"called":["12.46"],"its":["12.47"],"supported":["12.48","22.2"],"finished":["12.49"],"lack":["12.53"],"resource":["12.54"],"unexpectedly":["12.58"],"not":["12.58","20.5"],"suspended":["12.59"],"has":["12.60"],"changed":["12.60"],"data":["12.62"],"future":["13.0"],"and":["13.0","20.11"],"container":["13.1","13.4","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","13.34","20.10","22.3","22.18","22.21","22.22","22.26","22.35","22.38","22.41","22.44","22.48","23.3","26.35"],"log":["13.2","20.5","23.5"],"new":["13.14","13.15","13.16","13.25","13.34","20.8","20.9","22.11","22.22","22.27","22.41","23.8","26.27"],"var":["13.34","22.11","22.22"],"art":["13.34","22.11","22.22","22.27"],"controls":["14.0"],"tooltip":["14.0","16.1"],"returns":["15.12"],"promise":["15.12","24.9"],"it":["15.12","15.33","15.41","20.13"],"resolve":["15.12"],"s":["15.12","15.41"],"been":["15.16"],"fully":["15.16"],"decoded":["15.16"],"in":["15.16","20.4"],"mechanisms":["15.20"],"user":["15.20","15.22"],"interaction":["15.20","15.22"],"e":["15.20","15.22","22.7"],"g":["15.20","15.22","22.7"],"dimension":["15.28"],"exact":["15.33"],"unknown":["15.33"],"lifecycle":["15.41"],"triggered":["16.1","18.1"],"mount":["16.1","18.1"],"appears":["17.1"],"objects":["17.1"],"selection":["17.1"],"list":["17.1"],"img":["19.6"],"width":["19.6"],"have":["20.3"],"defined":["20.3"],"tip":["20.3","20.9","23.9","23.11"],"see":["20.3"],"more":["20.3","22.10","22.42"],"will":["20.4"],"reactive":["20.5"],"import":["20.6","20.12","23.12"],"current":["20.8","23.8"],"full":["20.9"],"typescript":["20.9","23.9"],"support":["20.11"],"even":["20.11"],"older":["20.11"],"configuration":["20.11","22.31","22.32"],"title":["20.12"],"map":["20.12","23.12"],"displayed":["21.0"],"default":["21.0"],"i18n":["21.0","21.3"],"syntax":["21.0","22.50"],"lang":["21.1","25.1"],"window":["21.2","25.2"],"imported":["21.4","25.4"],"use":["22.1"],"aspect":["22.1"],"ratio":["22.1","26.1"],"ogg":["22.2","26.2"],"webm":["22.2","26.2"],"other":["22.2"],"like":["22.2"],"or":["22.2"],"flv":["22.2"],"inside":["22.4"],"callback":["22.4"],"refers":["22.4"],"instance":["22.4"],"however":["22.4"],"an":["22.4"],"arrow":["22.4"],"next":["22.7"],"initialization":["22.7"],"page":["22.7"],"refresh":["22.7"],"must":["22.10"],"be":["22.10"],"set":["22.10"],"screenshotting":["22.17"],"may":["22.17"],"fail":["22.17"],"source":["22.17"],"player":["22.19"],"gains":["22.19"],"focus":["22.19"],"js":["22.22"],"innerhtml":["22.27"],"component":["22.31","22.32"],"please":["22.32"],"refer":["22.32"],"sd":["22.33"],"480p":["22.33","26.33"],"谁でもいいはずなのに":["22.34","26.34"],"夏の想い出がまわる":["22.34","26.34"],"all":["22.39"],"icon":["22.39"],"but":["22.40"],"cannot":["22.40"],"zh":["22.43","26.43"],"cn":["22.43","26.43"],"same":["22.47"],"different":["22.47"],"then":["22.47"],"reference":["22.50"],"的尺寸":["23.3"],"所以你的容器":["23.3"],"必须是有尺寸的":["23.3"],"非响应式":["23.4"],"在":["23.4"],"400px":["23.5"],"margin":["23.5"],"60px":["23.5"],"auto":["23.5"],"全部":["23.9"],"定义":["23.9"],"volume":["23.10"],"假如你要兼容更古老的浏览器时":["23.11"],"请修改以下配置然后自行构建":["23.11"],"body":["23.12"],"border":["24.4"],"弹幕是否有描边":["24.4"],"默认为":["24.4"],"locktime":["24.5"],"输入框锁定时间":["24.5"],"theme":["24.5"],"dark":["24.5","24.16"],"弹幕主题":["24.5"],"支持":["24.5"],"length":["24.6"],"这是弹幕即将显示的时触发的函数":["24.6"],"当返回true后才表示可以马上发送到播放器里":["24.6"],"弹幕已经出现在播放器里":["24.6"],"你可以访问到弹幕的dom元素里":["24.6"],"plugins":["24.7","24.8"],"artplayerplugindanmuku":["24.7","24.8"],"resovle":["24.9"],"function":["24.10","26.32"],"target":["24.11"],"innertext":["24.11"],"else":["24.11"],"color":["24.12"],"math":["24.12"],"floor":["24.12"],"random":["24.12"],"0xffffff":["24.12"],"tostring":["24.12"],"queryselector":["24.13"],"addeventlistener":["24.13"],"追加":["24.14"],"追加新的弹幕库":["24.14"],"参数类型和option":["24.14"],"danmuku相同":["24.14"],"xml":["24.15","24.17"],"弹幕隐藏":["24.18"],"弹幕显示":["24.18"],"写法参考":["25.0","26.50"],"默认支持三种视频文件格式":["26.2"],"播放器会缓存最后一次音量的大小":["26.7"],"假如希望默认进入页面就能自动播放视频":["26.10"],"必需为":["26.10"],"视频快进":["26.19"],"视频快退":["26.19"],"space":["26.19"],"切换播放":["26.19"],"暂停":["26.19"],"subtitle":["26.25"],"args":["26.32"],"hd":["26.33"],"webkit":["26.38"],"全部图标的定义":["26.39"],"但无法解析这种后缀":["26.40"],"作为":["26.47"],"key":["26.47"],"来缓存播放进度的":["26.47"],"但假如你的同一个视频的":["26.47"]},{"0":["5.10","5.11","5.13","5.16","5.23","15.10","15.11","15.13","15.16","15.23","20.10","23.10"],"1":["5.47","9.7","15.47","19.7","24.7","24.9"],"2":["5.8","15.8","15.31"],"5":["5.6","5.7","9.7","15.6","15.7","15.9","15.15","19.7","20.10","23.10"],"9":["15.32","26.1"],"10":["5.46","9.7","15.46","19.7","22.36","26.36"],"60":["5.46","15.46"],"240":["22.34"],"300":["22.34","26.34"],"360":["19.3"],"404":["3.14","3.15","13.14","13.15"],"1000":["0.13","0.15","10.8","10.9","10.10","10.13","10.15","10.16"],"3000":["0.12","5.2","5.3","5.8","5.11","5.13","5.21","5.45","6.4","6.5","7.4","7.5","8.4","8.5","9.8","9.9","10.12","15.2","15.3","15.8","15.11","15.13","15.21","15.45","16.4","16.5","17.4","17.5","18.4","18.5","19.8","19.9"],"对象":["0.1"],"播放器不会马上做出响应":["0.1"],"types":["0.2","2.0","10.2","10.5","20.9","21.0","22.39","22.50","23.9","26.39"],"d":["0.2","0.5","2.0","10.2","10.5","11.6","12.0","21.0","22.39","22.50","25.0","26.39","26.50"],"ts":["0.2","0.5","1.6","2.0","10.2","10.5","11.6","12.0","21.0","22.39","22.50","25.0","26.39","26.50"],"warning":["0.3","0.9","0.10","0.14","0.16","2.0","10.8","10.9","10.10","10.16","12.0","22.1","22.36","22.43","23.5","26.1","26.29","26.30","26.36","26.43"],"提示":["0.3","0.14","5.28","5.41","23.13","26.1","26.4","26.19"],"假如你需要一些":["0.3","5.41"],"事件只存在于播放器的生命周期上时":["0.3","5.41"],"强烈建议使用这些函数":["0.3"],"以避免造成内存泄漏":["0.3","5.41"],"your":["0.4","5.17","10.4","15.17"],"假如想在实例化之前更新":["0.6"],"请使用基础选项的":["0.6"],"来更新":["0.6"],"的显示":["0.7"],"组件配置":["0.8","0.9","0.10","26.29","26.31","26.32"],"请参考以下地址":["0.8","0.9","0.10","0.16","26.29","26.30","26.31","26.32"],"component":["0.8","0.9","0.10","0.16","10.8","10.9","10.10","10.16","22.29","22.30","26.29","26.30","26.31","26.32"],"color":["0.11","10.11","22.37","26.37"],"red":["0.11","10.11"],"false":["0.12","0.13","5.21","9.9","10.8","10.9","10.10","10.12","10.13","10.15","10.16","15.21","19.9","22.22","22.45","26.22","26.45"],"只在播放器获得焦点后":["0.14","26.19"],"如点击了播放器后":["0.14","26.19"],"这些快捷键才会生效":["0.14","26.19"],"true":["0.15","3.11","3.12","3.13","3.21","3.22","3.23","3.24","5.24","10.12","10.13","10.15","13.11","13.12","13.13","13.21","13.22","13.23","13.24","15.14","15.24","22.8","22.9","22.11","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.23","22.24","22.26","22.27","22.38","22.44","22.46","22.48","22.49","24.12","26.8","26.9","26.11","26.12","26.13","26.14","26.15","26.16","26.18","26.20","26.23","26.24","26.26","26.27","26.38","26.44","26.46","26.48","26.49"],"设置面板":["0.16"],"html":["0.16","10.16","20.1","22.42","22.43","23.1","24.2","26.42","26.43"],"ready":["0.17","2.0","5.1","5.4","5.47","10.17","15.1","15.4","15.6","15.7","15.24","15.27","15.47"],"off":["2.0"],"全部事件请参考以下地址":["2.0"],"events":["2.0"],"info":["2.1","2.2","2.3","2.4","2.5","2.6","2.7","2.8","2.9","2.10","2.11","2.13","2.14","2.15","2.16","2.17","2.18","2.19","2.20","2.21","2.22","2.23","2.24","2.25","2.26","2.27","2.28","2.29","2.30","2.31","5.18","5.19","5.25","5.38","5.39","5.40","5.43","9.2","9.6","12.1","12.2","12.3","12.4","12.5","12.6","12.7","12.8","12.9","12.10","12.11","12.12","12.13","12.14","12.15","12.16","12.17","12.18","12.19","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.27","12.28","12.29","12.30","12.31","15.18","15.19","15.25","15.38","15.39","15.40","15.42","15.43","19.2","19.6"],"console":["2.2","2.6","2.19","2.28","2.39","3.8","3.9","3.10","3.17","5.18","5.19","5.38","5.40","9.2","9.6","12.1","12.2","12.3","12.4","12.6","12.11","12.14","12.16","12.17","12.18","12.19","12.20","12.21","12.22","12.23","12.24","12.25","12.26","12.28","12.29","12.30","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","13.8","13.9","13.10","13.17","15.18","15.19","15.25","15.38","15.39","15.40","19.2","19.6"],"log":["2.32","2.33","2.34","2.35","2.36","2.37","2.38","2.39","2.40","2.41","3.8","3.9","3.10","3.17","12.32","12.33","12.34","12.35","12.36","12.37","12.38","12.39","12.40","12.41","13.8","13.9","13.10","13.17"],"video":["3.1","3.3","3.4","3.16","3.18","3.19","3.20","3.25","3.26","3.27","3.32","13.3","13.4","13.11","13.12","13.13","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","22.3","22.6","22.8","22.11","22.12","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.27","22.35","22.44","22.49","26.3","26.11","26.27","26.35"],"mp4":["3.1","3.3","3.4","3.11","3.12","3.13","3.14","3.15","3.16","3.18","3.19","3.20","3.21","3.23","3.24","3.25","3.26","3.27","3.31","3.32","3.33","11.1","13.1","13.3","13.4","13.11","13.12","13.13","13.14","13.15","13.16","13.18","13.19","13.20","13.21","13.23","13.24","13.25","13.26","13.27","13.31","13.32","13.33","22.3","22.6","22.8","22.9","22.11","22.12","22.13","22.14","22.15","22.16","22.18","22.20","22.21","22.22","22.23","22.24","22.26","22.27","22.28","22.35","22.44","22.45","22.46","22.48","22.49","22.51","26.3","26.6","26.11","26.12","26.18","26.20","26.22","26.23","26.24","26.27","26.28","26.35","26.44","26.48","26.49"],"playbackrate":["3.5","3.6","3.7","13.5","13.6","13.7"],"aspectratio":["3.5","3.6","3.7","13.5","13.6","13.7"],"autoplayback":["3.11","3.12","3.13","13.11","13.12","13.13"],"sample":["3.14","3.15","3.16","3.19","3.20","3.25","3.26","13.1","13.3","13.4","13.14","13.15","13.16","13.18","13.19","13.20","13.25","13.26","13.27","13.31","13.32","22.3","22.11","22.21","22.22","22.27","22.48","26.3","26.27"],"autoorientation":["3.21","13.21"],"show":["3.22","3.28","13.22","13.28","13.29"],"fastforward":["3.23","3.24","13.23","13.24"],"fullscreenweb":["3.31","13.31"],"miniprogressbar":["3.33","13.33"],"只销毁界面":["3.34"],"不主动清空":["3.34"],"pause":["4.0","14.0"],"layer":["4.0","14.0"],"png":["4.0","14.0"],"仅重置":["5.5"],"不移除界面":["5.5"],"t":["5.10","5.11","5.13","15.10","15.11","15.13","15.23"],"方法会返回":["5.12"],"promise":["5.12"],"当":["5.12"],"resolve":["5.12"],"时表示新地址是可以播放":["5.12"],"reject":["5.12","15.12"],"时表示新地址加载错误":["5.12"],"例如直播中的视频或者没被解码完成的视频":["5.16"],"这个时候获取的时长会是":["5.16"],"name":["5.17","15.17"],"由于浏览器安全机制":["5.20","5.22","26.17"],"触发窗口全屏前":["5.20"],"页面必须先存在交互":["5.20","5.22"],"例如用户点击过页面":["5.20","5.22"],"触发画中画前":["5.22"],"默认":["5.26"],"尺寸和坐标信息是通过":["5.28"],"getboundingclientrect":["5.28","15.28"],"获取的":["5.28"],"但不知道具体高度时":["5.33"],"这个属性很有用":["5.33"],"它能自动计算出视频的高度":["5.33"],"但你需要确定设置这个属性的时机":["5.33"],"强烈建议使用该函数":["5.41"],"4k":["5.45","15.45"],"number":["5.46","15.46","24.13"],"column":["5.46","15.46"],"tooltip":["6.1","8.1","18.1"],"组件的提示文本":["6.1","8.1"],"remove":["6.4","7.4","8.4","9.8","16.4","17.4","18.4"],"选择列表的对象数组":["7.1"],"onselect":["7.1","17.1"],"选择列表的元素被点击时触发的函数":["7.1"],"by":["7.3","8.2","8.3","9.8","17.3","18.2","18.3","19.8"],"left":["8.5","18.5","22.2"],"return":["9.2","9.5","9.6","19.2","19.5","19.6"],"switchquality":["9.3","19.3"],"open":["9.5","19.5"],"event":["9.6"],"x":["9.6","19.6"],"range":["9.7","19.7"],"switch":["9.9","19.9"],"used":["10.0","11.0","13.0","15.0","22.4"],"will":["10.1","15.16","20.5","22.4","22.7"],"not":["10.1","13.34","15.5","22.4"],"respond":["10.1"],"immediately":["10.1","10.7"],"s":["10.3","22.40"],"lifecycle":["10.3"],"strongly":["10.3","15.41"],"recommended":["10.3","15.41"],"use":["10.3","10.6","15.41","22.40"],"these":["10.3"],"functions":["10.3"],"avoid":["10.3","15.41"],"memory":["10.3","15.41"],"leaks":["10.3","15.41"],"please":["10.6","10.8","10.9","10.10","10.16","12.0","22.2","22.10","22.29","22.30","22.31"],"option":["10.6"],"in":["10.6","20.5"],"basic":["10.6"],"settings":["10.6","22.42","22.43"],"for":["10.8","10.9","10.10","10.16","12.0","15.33","20.13","22.4","22.29"],"configuration":["10.8","10.9","10.10","22.29"],"refer":["10.8","10.9","10.10","10.16","12.0","22.2","22.29","22.30","22.31"],"srt":["10.11","22.25","26.25"],"settimeout":["10.12","10.13","10.15","15.3","15.21"],"gains":["10.14"],"focus":["10.14"],"e":["10.14","22.19"],"g":["10.14","22.19"],"clicking":["10.14","22.19"],"on":["10.17","15.4","22.2","22.19","24.6"],"a":["12.0","17.1"],"complete":["12.0"],"list":["12.0"],"state":["12.39"],"further":["12.42"],"buffering":["12.42","12.43"],"to":["12.46","15.33","22.29","22.30","22.31","22.32"],"reload":["12.46"],"it":["12.46","20.11"],"format":["12.48"],"data":["12.53"],"forthcoming":["12.58"],"rarely":["13.0"],"assets":["13.1","13.14","13.15","13.16","13.19","13.20","13.25","13.26","13.27","22.3","22.11","22.27"],"dblclick":["13.17"],"contextmenu":["13.28"],"do":["13.34","15.5"],"clear":["13.34"],"play":["14.0"],"interface":["15.5"],"playable":["15.12"],"fails":["15.12"],"load":["15.12"],"cases":["15.16"],"obtained":["15.16","15.28"],"be":["15.16"],"page":["15.20","15.22"],"must":["15.20","15.22"],"occur":["15.20","15.22"],"before":["15.20","15.22"],"triggering":["15.20","15.22"],"default":["15.26"],"is":["15.26","15.28","22.17"],"via":["15.28"],"you":["15.33","22.40"],"need":["15.33"],"determine":["15.33"],"timing":["15.33"],"setting":["15.33","22.14","22.15","22.16","22.25","26.14","26.15","26.16","26.25"],"m3u8":["15.35","22.41","26.2"],"000":["15.36"],"timeupdate":["15.39"],"this":["15.41","22.7"],"text":["16.1","18.1"],"when":["17.1"],"item":["17.1"],"clicked":["17.1"],"script":["20.1","23.1","24.2"],"examples":["20.3"],"at":["20.3"],"following":["20.3","22.32"],"link":["20.3"],"example":["20.3","23.3"],"update":["20.4","20.5"],"player":["20.4","20.12","23.12"],"directly":["20.5"],"modifying":["20.5"],"the":["20.5","22.32"],"definitions":["20.9","22.39"],"packages":["20.9","23.9"],"volume":["20.10"],"art8":["20.10","23.10"],"new":["20.10","23.10"],"yourself":["20.11"],"scripts":["20.11","23.11"],"reference":["20.11","21.0"],"documentation":["20.11"],"browserslist":["20.11","23.11"],"body":["20.12"],"div":["20.12","23.12"],"id":["20.12","23.12"],"importing":["20.13"],"dependency":["20.13"],"take":["20.13"],"effect":["20.13"],"see":["21.0"],"or":["21.1","25.1"],"note":["22.1"],"among":["22.1"],"all":["22.1"],"options":["22.1"],"only":["22.1"],"required":["22.1"],"third":["22.2"],"party":["22.2"],"libraries":["22.2"],"section":["22.2"],"point":["22.4"],"jpg":["22.5","26.5"],"ffad00":["22.6","26.6"],"read":["22.7","22.10"],"cached":["22.7"],"value":["22.7"],"information":["22.10"],"policy":["22.10","26.10"],"changes":["22.10","26.10"],"cross":["22.17"],"origin":["22.17"],"with":["22.17"],"website":["22.17"],"disable":["22.22"],"url":["22.27"],"panel":["22.30"],"address":["22.32"],"hd":["22.33"],"720p":["22.33","26.33"],"こんなとこにあるはずもないのに":["22.34","26.34"],"终わり":["22.34","26.34"],"generate":["22.36"],"online":["22.36"],"tool":["22.36","26.36"],"03a9f4":["22.37","26.37"],"font":["22.37","24.5","26.37"],"size":["22.37","24.5","26.37"],"30px":["22.37","26.37"],"webkit":["22.38"],"playsinline":["22.38","26.38"],"therefore":["22.40"],"if":["22.40"],"best":["22.40"],"also":["22.40"],"start":["22.42","22.43","26.42","26.43"],"i18n":["22.42","26.42"],"tw":["22.43","26.43"],"more":["22.43"],"identify":["22.47"],"unique":["22.47"],"document":["22.51","26.51"],"createelement":["22.51","26.51"],"tip":["23.3"],"以下链接可以看到更多的使用例子":["23.3"],"里直接修改":["23.4","23.5"],"是不会改变播放器的":["23.4","23.5"],"非响应式":["23.5"],"在":["23.5"],"构建配置":["23.11"],"build":["23.11"],"参考文档":["23.11"],"你需要在引入":["23.13"],"依赖前来修改它才会生效":["23.13"],"style":["24.4"],"弹幕自定义样式":["24.4"],"默认为空对象":["24.4"],"light":["24.5"],"只在自定义挂载时生效":["24.5"],"不透明度配置项":["24.5"],"弹幕字号配置项":["24.5"],"显示区域配置项":["24.5"],"弹幕速度配置项":["24.5"],"颜色列表配置项":["24.5"],"ref":["24.6"],"innerhtml":["24.6"],"ଘ":["24.6"],"੭ˊᵕˋ":["24.6"],"੭":["24.6"],"使用数组":["24.7"],"time":["24.7","24.9"],"异步返回":["24.9"],"显示弹幕":["24.10","24.11"],"hide":["24.11"],"border":["24.12"],"change":["24.13"],"fontsize":["24.13"],"const":["24.14"],"target":["24.14"],"xml":["24.16"],"也可以手动挂载":["24.16"],"reset":["24.18"],"弹幕重置":["24.18"],"destroy":["24.18"],"弹幕销毁":["24.18"],"全部选项里":["26.1"],"只有":["26.1"],"是必填的":["26.1"],"如需要播放":["26.2"],"或者":["26.2"],"flv":["26.2"],"等其它格式":["26.2"],"请参考左侧的":["26.2"],"第三方库":["26.2"],"回调函数里的":["26.4"],"就是播放器实例":["26.4"],"但回调函数假如使用了箭头函数":["26.4"],"则不会指向播放器实例":["26.4"],"下次初始化时":["26.7"],"如刷新页面":["26.7"],"播放器会读取该缓存值":["26.7"],"更多信息请阅读":["26.10"],"假如视频源地址和网站是跨域的":["26.17"],"可能会出现截图失败":["26.17"],"关闭毛玻璃效果":["26.22"],"在线生成预览图":["26.36"],"thumbnail":["26.36"],"所以假如你使用了":["26.40"],"最好同时要指明":["26.40"],"function":["26.41"],"更多的语言设置":["26.42","26.43"],"是不同的话":["26.47"],"那么你需要使用":["26.47"],"来标识视频的唯一":["26.47"]}]'},t={"0.0":{t:"# 高级属性",p:`这里的 高级属性 是指挂载在 实例 的 二级属性,比较少用 +`,l:"advanced/built-in.html",a:"高级属性"},"0.1":{t:"`option`",p:`播放器的选项 +<div className="run-code">▶ Run Code< ...`,l:"advanced/built-in.html#option",a:"option"},"0.2":{t:"`template`",p:`管理播放器所有的 DOM 元素 +<div className="run-code">▶ Ru ...`,l:"advanced/built-in.html#template",a:"template"},"0.3":{t:"`events`",p:"管理播放器所有的 DOM 事件,实质上是代理了 addEventListener 和 removeEventListener ...",l:"advanced/built-in.html#events",a:"events"},"0.4":{t:"`storage`",p:`管理播放器的本地存储 + +name 属性用于设置缓存的 key +set 方法用于设置缓存 +get 方法用于获取缓存 +del 方 ...`,l:"advanced/built-in.html#storage",a:"storage"},"0.5":{t:"`icons`",p:`管理播放器所有的 svg 图标 +<div className="run-code">▶ Ru ...`,l:"advanced/built-in.html#icons",a:"icons"},"0.6":{t:"`i18n`",p:`管理播放器的 i18n + +get 方法用于获取 i18n 的值 +update 方法用于更新 i18n 对象 + +<div ...`,l:"advanced/built-in.html#i18n",a:"i18n"},"0.7":{t:"`notice`",p:`管理播放器的提示语,只有一个 show 属性用于显示提示语 +<div className="run-code ...`,l:"advanced/built-in.html#notice",a:"notice"},"0.8":{t:"`layers`",p:`管理播放器的层 + +add 方法用于动态添加层 +remove 方法用于动态删除层 +update 方法用于动态更新层 +show ...`,l:"advanced/built-in.html#layers",a:"layers"},"0.9":{t:"`controls`",p:`管理播放器的控制器 + +add 方法用于动态添加控制器 +remove 方法用于动态删除控制器 +update 方法用于动态更新控 ...`,l:"advanced/built-in.html#controls",a:"controls"},"0.10":{t:"`contextmenu`",p:`管理播放器的右键菜单 + +add 方法用于动态添加菜单 +remove 方法用于动态删除菜单 +update 方法用于动态更新菜单 ...`,l:"advanced/built-in.html#contextmenu",a:"contextmenu"},"0.11":{t:"`subtitle`",p:`管理播放器的字幕功能 + +url 属性设置和返回当前字幕地址 +style 方法设置当前字幕的样式 +switch 方法设置当前字 ...`,l:"advanced/built-in.html#subtitle",a:"subtitle"},"0.12":{t:"`info`",p:`管理播放器的信息面板,常用于查看当前播放器和视频的运行状态,例如版本号、分辨率、时长等。 + +通过 art.info.show ...`,l:"advanced/built-in.html#info",a:"info"},"0.13":{t:"`loading`",p:`管理播放器的加载层 + +show 属性用于设置是否显示加载层 +toggle 属性用于切换是否显示加载层 + +<div cl ...`,l:"advanced/built-in.html#loading",a:"loading"},"0.14":{t:"`hotkey`",p:`管理播放器的快捷键功能 + +add 方法用于添加快捷键 +remove 方法用于删除快捷键 + +<div className ...`,l:"advanced/built-in.html#hotkey",a:"hotkey"},"0.15":{t:"`mask`",p:`管理播放器的遮罩层 + +show 属性用于设置是否显示遮罩层 +toggle 属性用于切换是否显示遮罩层 + +<div cl ...`,l:"advanced/built-in.html#mask",a:"mask"},"0.16":{t:"`setting`",p:`管理播放器的设置面板 + +add 方法用于动态添加设置项 +remove 方法用于动态删除设置项 +update 方法用于动态更新 ...`,l:"advanced/built-in.html#setting",a:"setting"},"0.17":{t:"`plugins`",p:`管理播放器的插件功能,只有一个方法 add 用于动态添加插件 +<div className="run-cod ...`,l:"advanced/built-in.html#plugins",a:"plugins"},"1.0":{t:"# 静态属性",p:`这里的 静态属性 是指挂载在 构造函数 的 一级属性,非常少使用 +`,l:"advanced/class.html",a:"静态属性"},"1.1":{t:"`instances`",p:`返回全部播放器实例的数组,假如你想同时管理多个播放器的时候,可以用到该属性 +<div className=" ...`,l:"advanced/class.html#instances",a:"instances"},"1.2":{t:"`version`",p:`返回播放器的版本信息 +<div className="run-code">▶ Run Cod ...`,l:"advanced/class.html#version",a:"version"},"1.3":{t:"`env`",p:`返回播放器的环境变量 +<div className="run-code">▶ Run Cod ...`,l:"advanced/class.html#env",a:"env"},"1.4":{t:"`build`",p:`返回播放器的打包时间 +<div className="run-code">▶ Run Cod ...`,l:"advanced/class.html#build",a:"build"},"1.5":{t:"`config`",p:`返回视频的默认配置 +<div className="run-code">▶ Run Code ...`,l:"advanced/class.html#config",a:"config"},"1.6":{t:"`utils`",p:`返回播放器的工具函数集合 +<div className="run-code">▶ Run C ...`,l:"advanced/class.html#utils",a:"utils"},"1.7":{t:"`scheme`",p:`返回播放器选项的校验方案 +<div className="run-code">▶ Run C ...`,l:"advanced/class.html#scheme",a:"scheme"},"1.8":{t:"`Emitter`",p:`返回事件分发器的构造函数 +<div className="run-code">▶ Run C ...`,l:"advanced/class.html#emitter",a:"emitter"},"1.9":{t:"`validator`",p:`返回选项的校验函数 +<div className="run-code">▶ Run Code ...`,l:"advanced/class.html#validator",a:"validator"},"1.10":{t:"`kindOf`",p:`返回类型检测的函数工具 +<div className="run-code">▶ Run Co ...`,l:"advanced/class.html#kindof",a:"kindof"},"1.11":{t:"`html`",p:`返回播放器所需的 html 字符串 +<div className="run-code">▶ ...`,l:"advanced/class.html#html",a:"html"},"1.12":{t:"`option`",p:`返回播放器的默认选项 +<div className="run-code">▶ Run Cod ...`,l:"advanced/class.html#option",a:"option"},"2.0":{t:"# 实例事件",p:`播放器的事件分为两种,一种视频的 原生事件 (前缀 video:),另外一种是 自定义事件 +监听事件: +<div cl ...`,l:"advanced/event.html",a:"实例事件"},"2.1":{t:"`ready`",p:`当播放器首次可以播放器时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#ready",a:"ready"},"2.2":{t:"`restart`",p:`当播放器切换地址后并可以播放时触发 +<div className="run-code">▶ ...`,l:"advanced/event.html#restart",a:"restart"},"2.3":{t:"`pause`",p:`当播放器暂停时触发 +<div className="run-code">▶ Run Code ...`,l:"advanced/event.html#pause",a:"pause"},"2.4":{t:"`play`",p:`当播放器播放时触发 +<div className="run-code">▶ Run Code ...`,l:"advanced/event.html#play",a:"play"},"2.5":{t:"`hotkey`",p:`当播放器热键被按下时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#hotkey",a:"hotkey"},"2.6":{t:"`destroy`",p:`当播放器销毁时触发 +<div className="run-code">▶ Run Code ...`,l:"advanced/event.html#destroy",a:"destroy"},"2.7":{t:"`focus`",p:`当播放器获得焦点时触发 +<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#focus",a:"focus"},"2.8":{t:"`blur`",p:`当播放器失去焦点时触发 +<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#blur",a:"blur"},"2.9":{t:"`dblclick`",p:`当播放器被双击时触发 +<div className="run-code">▶ Run Cod ...`,l:"advanced/event.html#dblclick",a:"dblclick"},"2.10":{t:"`click`",p:`当播放器被单击时触发 +<div className="run-code">▶ Run Cod ...`,l:"advanced/event.html#click",a:"click"},"2.11":{t:"`error`",p:`当播放器加载视频发生错误时触发 +<div className="run-code">▶ Ru ...`,l:"advanced/event.html#error",a:"error"},"2.12":{t:"`hover`",p:`当播放器被鼠标移出或者移入时触发 +<div className="run-code">▶ R ...`,l:"advanced/event.html#hover",a:"hover"},"2.13":{t:"`mousemove`",p:`当播放器被鼠标经过时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#mousemove",a:"mousemove"},"2.14":{t:"`resize`",p:`当播放器尺寸变化时触发 +<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#resize",a:"resize"},"2.15":{t:"`view`",p:`当播放器出现在视口时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#view",a:"view"},"2.16":{t:"`lock`",p:`在移动端,当锁定的状态发生变化时触发 +<div className="run-code">▶ ...`,l:"advanced/event.html#lock",a:"lock"},"2.17":{t:"`aspectRatio`",p:`当播放器长宽比变化时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#aspectratio",a:"aspectratio"},"2.18":{t:"`autoHeight`",p:`当播放器自动设置高度时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#autoheight",a:"autoheight"},"2.19":{t:"`autoSize`",p:`当播放器自动设置尺寸时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#autosize",a:"autosize"},"2.20":{t:"`flip`",p:`当播放器发生翻转时触发 +<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#flip",a:"flip"},"2.21":{t:"`fullscreen`",p:`当播放器发生窗口全屏时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#fullscreen",a:"fullscreen"},"2.22":{t:"`fullscreenError`",p:`当播放器发生窗口全屏错误时触发 +<div className="run-code">▶ Ru ...`,l:"advanced/event.html#fullscreenerror",a:"fullscreenerror"},"2.23":{t:"`fullscreenWeb`",p:`当播放器发生网页全屏时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#fullscreenweb",a:"fullscreenweb"},"2.24":{t:"`mini`",p:`当播放器进入迷你模式时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#mini",a:"mini"},"2.25":{t:"`pip`",p:`当播放器进入画中画时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#pip",a:"pip"},"2.26":{t:"`screenshot`",p:`当播放器被截图时触发 +<div className="run-code">▶ Run Cod ...`,l:"advanced/event.html#screenshot",a:"screenshot"},"2.27":{t:"`seek`",p:`当播放器发生时间跳转时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#seek",a:"seek"},"2.28":{t:"`subtitleOffset`",p:`当播放器发生字幕偏移时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#subtitleoffset",a:"subtitleoffset"},"2.29":{t:"`subtitleBeforeUpdate`",p:`当字幕更新前触发 +<div className="run-code">▶ Run Code& ...`,l:"advanced/event.html#subtitlebeforeupdate",a:"subtitlebeforeupdate"},"2.30":{t:"`subtitleAfterUpdate`",p:`当字幕更新后触发 +<div className="run-code">▶ Run Code& ...`,l:"advanced/event.html#subtitleafterupdate",a:"subtitleafterupdate"},"2.31":{t:"`subtitleLoad`",p:`当字幕加载时触发 +<div className="run-code">▶ Run Code& ...`,l:"advanced/event.html#subtitleload",a:"subtitleload"},"2.32":{t:"`info`",p:`当信息面板显示或隐藏时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#info",a:"info"},"2.33":{t:"`layer`",p:`当自定义层显示或隐藏时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#layer",a:"layer"},"2.34":{t:"`loading`",p:`当加载器显示或隐藏时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#loading",a:"loading"},"2.35":{t:"`mask`",p:`当遮罩层显示或隐藏时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#mask",a:"mask"},"2.36":{t:"`subtitle`",p:`当字幕层显示或隐藏时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#subtitle",a:"subtitle"},"2.37":{t:"`contextmenu`",p:`当右键菜单显示或隐藏时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#contextmenu",a:"contextmenu"},"2.38":{t:"`control`",p:`当控制器显示或隐藏时触发 +<div className="run-code">▶ Run C ...`,l:"advanced/event.html#control",a:"control"},"2.39":{t:"`setting`",p:`当设置面板显示或隐藏时触发 +<div className="run-code">▶ Run ...`,l:"advanced/event.html#setting",a:"setting"},"2.40":{t:"`muted`",p:`当静音的状态变化时触发 +<div className="run-code">▶ Run Co ...`,l:"advanced/event.html#muted",a:"muted"},"2.41":{t:"`keydown`",p:`监听来自 document 的 keydown 事件 +<div className="run-code&qu ...`,l:"advanced/event.html#keydown",a:"keydown"},"2.42":{t:"`video:canplay`",p:`浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容 +`,l:"advanced/event.html#video-canplay",a:"video-canplay"},"2.43":{t:"`video:canplaythrough`",p:`浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束 +`,l:"advanced/event.html#video-canplaythrough",a:"video-canplaythrough"},"2.44":{t:"`video:complete`",p:`OfflineAudioContext 渲染完成 +`,l:"advanced/event.html#video-complete",a:"video-complete"},"2.45":{t:"`video:durationchange`",p:`duration 属性的值改变时触发 +`,l:"advanced/event.html#video-durationchange",a:"video-durationchange"},"2.46":{t:"`video:emptied`",p:"媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载 ...",l:"advanced/event.html#video-emptied",a:"video-emptied"},"2.47":{t:"`video:ended`",p:`视频停止播放,因为 media 已经到达结束点 +`,l:"advanced/event.html#video-ended",a:"video-ended"},"2.48":{t:"`video:error`",p:`获取媒体数据时出错,或者资源类型不是受支持的媒体格式 +`,l:"advanced/event.html#video-error",a:"video-error"},"2.49":{t:"`video:loadeddata`",p:`media 中的首帧已经完成加载 +`,l:"advanced/event.html#video-loadeddata",a:"video-loadeddata"},"2.50":{t:"`video:loadedmetadata`",p:`已加载元数据 +`,l:"advanced/event.html#video-loadedmetadata",a:"video-loadedmetadata"},"2.51":{t:"`video:pause`",p:`播放已暂停 +`,l:"advanced/event.html#video-pause",a:"video-pause"},"2.52":{t:"`video:play`",p:`播放已开始 +`,l:"advanced/event.html#video-play",a:"video-play"},"2.53":{t:"`video:playing`",p:`由于缺乏数据而暂停或延迟后,播放准备开始 +`,l:"advanced/event.html#video-playing",a:"video-playing"},"2.54":{t:"`video:progress`",p:`在浏览器加载资源时周期性触发 +`,l:"advanced/event.html#video-progress",a:"video-progress"},"2.55":{t:"`video:ratechange`",p:`播放速率发生变化 +`,l:"advanced/event.html#video-ratechange",a:"video-ratechange"},"2.56":{t:"`video:seeked`",p:`跳帧(seek)操作完成 +`,l:"advanced/event.html#video-seeked",a:"video-seeked"},"2.57":{t:"`video:seeking`",p:`跳帧(seek)操作开始 +`,l:"advanced/event.html#video-seeking",a:"video-seeking"},"2.58":{t:"`video:stalled`",p:`用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现 +`,l:"advanced/event.html#video-stalled",a:"video-stalled"},"2.59":{t:"`video:suspend`",p:`媒体数据加载已暂停 +`,l:"advanced/event.html#video-suspend",a:"video-suspend"},"2.60":{t:"`video:timeupdate`",p:`currentTime 属性指定的时间发生变化 +`,l:"advanced/event.html#video-timeupdate",a:"video-timeupdate"},"2.61":{t:"`video:volumechange`",p:`音量发生变化 +`,l:"advanced/event.html#video-volumechange",a:"video-volumechange"},"2.62":{t:"`video:waiting`",p:`由于暂时缺少数据,播放已停止 +`,l:"advanced/event.html#video-waiting",a:"video-waiting"},"3.0":{t:"# 全局属性",p:`这里的 全局属性 也是指挂载在 构造函数 的 一级属性,属性名字全部都是大写的形式,未来容易发生变动,基本上用不到 +`,l:"advanced/global.html",a:"全局属性"},"3.1":{t:"DEBUG",p:`是否开始 debug 模式,可以打印出视频全部的内置事件,默认关闭 +<div className="run- ...`,l:"advanced/global.html#debug",a:"debug"},"3.2":{t:"STYLE",p:`返回播放器样式文本 +<div className="run-code">▶ Run Code ...`,l:"advanced/global.html#style",a:"style"},"3.3":{t:"CONTEXTMENU",p:`是否开启右键菜单,默认开启 +<div className="run-code">▶ Run ...`,l:"advanced/global.html#contextmenu",a:"contextmenu"},"3.4":{t:"NOTICE_TIME",p:`提示信息的显示时长,单位为毫秒,默认为 2000 +<div className="run-code" ...`,l:"advanced/global.html#notice-time",a:"notice-time"},"3.5":{t:"SETTING_WIDTH",p:`设置面板的默认宽度,单位为像素,默认为 250 +<div className="run-code" ...`,l:"advanced/global.html#setting-width",a:"setting-width"},"3.6":{t:"SETTING_ITEM_WIDTH",p:`设置面板的设置项的默认宽度,单位为像素,默认为 200 +<div className="run-code&q ...`,l:"advanced/global.html#setting-item-width",a:"setting-item-width"},"3.7":{t:"SETTING_ITEM_HEIGHT",p:`设置面板的设置项的默认高度,单位为像素,默认为 35 +<div className="run-code&qu ...`,l:"advanced/global.html#setting-item-height",a:"setting-item-height"},"3.8":{t:"RESIZE_TIME",p:`resize 事件的节流时间,单位为毫秒,默认为 200 +<div className="run-code& ...`,l:"advanced/global.html#resize-time",a:"resize-time"},"3.9":{t:"SCROLL_TIME",p:`scroll 事件的节流时间,单位为毫秒,默认为 200 +<div className="run-code& ...`,l:"advanced/global.html#scroll-time",a:"scroll-time"},"3.10":{t:"SCROLL_GAP",p:`view 事件的边界容差距离,单位为像素,默认为 50 +<div className="run-code&q ...`,l:"advanced/global.html#scroll-gap",a:"scroll-gap"},"3.11":{t:"AUTO_PLAYBACK_MAX",p:`自动回放功能的最大记录数,默认为 10 +<div className="run-code"> ...`,l:"advanced/global.html#auto-playback-max",a:"auto-playback-max"},"3.12":{t:"AUTO_PLAYBACK_MIN",p:`自动回放功能的最小记录时长,单位为秒,默认为 5 +<div className="run-code" ...`,l:"advanced/global.html#auto-playback-min",a:"auto-playback-min"},"3.13":{t:"AUTO_PLAYBACK_TIMEOUT",p:`自动回放功能的隐藏延迟时长,单位为毫秒,默认为 3000 +<div className="run-code& ...`,l:"advanced/global.html#auto-playback-timeout",a:"auto-playback-timeout"},"3.14":{t:"RECONNECT_TIME_MAX",p:`发生连接错误时,自动连接的最大次数,默认为 5 +<div className="run-code" ...`,l:"advanced/global.html#reconnect-time-max",a:"reconnect-time-max"},"3.15":{t:"RECONNECT_SLEEP_TIME",p:`发生连接错误时,自动连接的延迟时间,单位为毫秒,默认为 1000 +<div className="run-c ...`,l:"advanced/global.html#reconnect-sleep-time",a:"reconnect-sleep-time"},"3.16":{t:"CONTROL_HIDE_TIME",p:`底部控制栏的自动隐藏的延迟时间,单位为毫秒,默认为 3000 +<div className="run-cod ...`,l:"advanced/global.html#control-hide-time",a:"control-hide-time"},"3.17":{t:"DBCLICK_TIME",p:`双击事件的延迟事件,单位为毫秒,默认为 300 +<div className="run-code" ...`,l:"advanced/global.html#dbclick-time",a:"dbclick-time"},"3.18":{t:"DBCLICK_FULLSCREEN",p:`在桌面端,是否双击切换全屏,默认为 true +<div className="run-code"& ...`,l:"advanced/global.html#dbclick-fullscreen",a:"dbclick-fullscreen"},"3.19":{t:"MOBILE_DBCLICK_PLAY",p:`在移动端,是否双击切换播放暂停,默认为 true +<div className="run-code" ...`,l:"advanced/global.html#mobile-dbclick-play",a:"mobile-dbclick-play"},"3.20":{t:"MOBILE_CLICK_PLAY",p:`在移动端,是否单击切换播放暂停,默认为 false +<div className="run-code&quo ...`,l:"advanced/global.html#mobile-click-play",a:"mobile-click-play"},"3.21":{t:"AUTO_ORIENTATION_TIME",p:`在移动端,自动旋屏的延迟时间,单位为毫秒,默认为 200 +<div className="run-code& ...`,l:"advanced/global.html#auto-orientation-time",a:"auto-orientation-time"},"3.22":{t:"INFO_LOOP_TIME",p:`信息面板的刷新时间,单位为毫秒,默认为 1000 +<div className="run-code" ...`,l:"advanced/global.html#info-loop-time",a:"info-loop-time"},"3.23":{t:"FAST_FORWARD_VALUE",p:`在移动端,长按加速的速率倍数,默认为 3 +<div className="run-code"> ...`,l:"advanced/global.html#fast-forward-value",a:"fast-forward-value"},"3.24":{t:"FAST_FORWARD_TIME",p:`在移动端,长按加速的延迟时间,单位为毫秒,默认为 1000 +<div className="run-code ...`,l:"advanced/global.html#fast-forward-time",a:"fast-forward-time"},"3.25":{t:"TOUCH_MOVE_RATIO",p:`在移动端,左右滑动进度的速率倍数,默认为 0.5 +<div className="run-code" ...`,l:"advanced/global.html#touch-move-ratio",a:"touch-move-ratio"},"3.26":{t:"VOLUME_STEP",p:`快捷键调节音量的幅度比例,默认为 0.1 +<div className="run-code"> ...`,l:"advanced/global.html#volume-step",a:"volume-step"},"3.27":{t:"SEEK_STEP",p:`快捷键调节播放进度的幅度,单位为秒,默认为 5 +<div className="run-code" ...`,l:"advanced/global.html#seek-step",a:"seek-step"},"3.28":{t:"PLAYBACK_RATE",p:`内置播放速率的列表,默认为 [0.5, 0.75, 1, 1.25, 1.5, 2] +<div className=& ...`,l:"advanced/global.html#playback-rate",a:"playback-rate"},"3.29":{t:"ASPECT_RATIO",p:`内置视频长宽比的列表,默认为 ['default', '4:3', '16:9'] +<div className=&q ...`,l:"advanced/global.html#aspect-ratio",a:"aspect-ratio"},"3.30":{t:"FLIP",p:`内置视频翻转的列表,默认为 ['normal', 'horizontal', 'vertical'] +<div cla ...`,l:"advanced/global.html#flip",a:"flip"},"3.31":{t:"FULLSCREEN_WEB_IN_BODY",p:`网页全屏时,是否把播放器挂在在 body 元素下,默认为 true +<div className="run- ...`,l:"advanced/global.html#fullscreen-web-in-body",a:"fullscreen-web-in-body"},"3.32":{t:"LOG_VERSION",p:`设置是否打印播放器版本,默认为 true +<div className="run-code"> ...`,l:"advanced/global.html#log-version",a:"log-version"},"3.33":{t:"USE_RAF",p:`设置是否使用 requestAnimationFrame ,默认为 false,目前主要用于进度条的平滑效果 +<div ...`,l:"advanced/global.html#use-raf",a:"use-raf"},"3.34":{t:"REMOVE_SRC_WHEN_DESTROY",p:`在销毁播放器时,是否同时移除视频的 src 属性并调用 load() 以主动释放媒体资源,默认为 true。 +开启后可以在单 ...`,l:"advanced/global.html#remove-src-when-destroy",a:"remove-src-when-destroy"},"4.0":{t:"# 编写插件",p:`但你已经知道播放器的属性, 方法和事件后,再编写插件是非常简单的事 +可以在实例化的时候加载插件的函数 +<div cla ...`,l:"advanced/plugin.html",a:"编写插件"},"5.0":{t:"# 实例属性",p:`这里的 实例属性 是指挂载在 实例 的 一级属性,比较常用 +`,l:"advanced/property.html",a:"实例属性"},"5.1":{t:"`play`",p:` +Type: Function + +播放视频 +<div className="run-code"&g ...`,l:"advanced/property.html#play",a:"play"},"5.2":{t:"`pause`",p:` +Type: Function + +暂停视频 +<div className="run-code"&g ...`,l:"advanced/property.html#pause",a:"pause"},"5.3":{t:"`toggle`",p:` +Type: Function + +切换视频的播放和暂停 +<div className="run-code&q ...`,l:"advanced/property.html#toggle",a:"toggle"},"5.4":{t:"`destroy`",p:` +Type: Function +Parameter: Boolean + +销毁播放器,接受一个参数表示是否销毁后同时移除播放器 ...`,l:"advanced/property.html#destroy",a:"destroy"},"5.5":{t:"`reset`",p:` +Type: Function + +重置播放器的视频元素:会移除当前 src 并调用一次 load(),常用于在单页应用中手动 ...`,l:"advanced/property.html#reset",a:"reset"},"5.6":{t:"`seek`",p:` +Type: Setter +Parameter: Number + +视频时间跳转,单位秒 +<div className= ...`,l:"advanced/property.html#seek",a:"seek"},"5.7":{t:"`forward`",p:` +Type: Setter +Parameter: Number + +视频时间快进,单位秒 +<div className= ...`,l:"advanced/property.html#forward",a:"forward"},"5.8":{t:"`backward`",p:` +Type: Setter +Parameter: Number + +视频时间快退,单位秒 +<div className= ...`,l:"advanced/property.html#backward",a:"backward"},"5.9":{t:"`volume`",p:` +Type: Setter/Getter +Parameter: Number + +设置和获取视频音量,范围在:[0, 1] +& ...`,l:"advanced/property.html#volume",a:"volume"},"5.10":{t:"`url`",p:` +Type: Setter/Getter +Parameter: String + +设置和获取视频地址 +<div clas ...`,l:"advanced/property.html#url",a:"url"},"5.11":{t:"`switch`",p:` +Type: Setter +Parameter: String + +设置视频地址,设置时和 art.url 类似,但会执行一些 ...`,l:"advanced/property.html#switch",a:"switch"},"5.12":{t:"`switchUrl`",p:` +Type: Function +Parameter: String + +设置视频地址,设置时和 art.url 类似,但会执行 ...`,l:"advanced/property.html#switchurl",a:"switchurl"},"5.13":{t:"`switchQuality`",p:` +Type: Function +Parameter: String + +设置视频画质地址,和 art.switchUrl 类似 ...`,l:"advanced/property.html#switchquality",a:"switchquality"},"5.14":{t:"`muted`",p:` +Type: Setter/Getter +Parameter: Boolean + +设置和获取视频是否静音 +<div c ...`,l:"advanced/property.html#muted",a:"muted"},"5.15":{t:"`currentTime`",p:` +Type: Setter/Getter +Parameter: Number + +设置和获取视频当前时间,设置时间时和 see ...`,l:"advanced/property.html#currenttime",a:"currenttime"},"5.16":{t:"`duration`",p:` +Type: Getter + +获取视频时长 +<div className="run-code"&g ...`,l:"advanced/property.html#duration",a:"duration"},"5.17":{t:"`screenshot`",p:` +Type: Function + +下载当前视频帧的截图, 可选参数为截图名字 +<div className=" ...`,l:"advanced/property.html#screenshot",a:"screenshot"},"5.18":{t:"`getDataURL`",p:` +Type: Function + +获取当前视频帧的截图的base64地址,返回的是一个 Promise +<div cl ...`,l:"advanced/property.html#getdataurl",a:"getdataurl"},"5.19":{t:"`getBlobUrl`",p:` +Type: Function + +获取当前视频帧的截图的blob地址,返回的是一个 Promise +<div clas ...`,l:"advanced/property.html#getbloburl",a:"getbloburl"},"5.20":{t:"`fullscreen`",p:` +Type: Setter/Getter +Parameter: Boolean + +设置和获取播放器窗口全屏 +<div ...`,l:"advanced/property.html#fullscreen",a:"fullscreen"},"5.21":{t:"`fullscreenWeb`",p:` +Type: Setter/Getter +Parameter: Boolean + +设置和获取播放器网页全屏 +<div ...`,l:"advanced/property.html#fullscreenweb",a:"fullscreenweb"},"5.22":{t:"`pip`",p:` +Type: Setter/Getter +Parameter: Boolean + +设置和获取播放器画中画模式 +<div ...`,l:"advanced/property.html#pip",a:"pip"},"5.23":{t:"`poster`",p:` +Type: Setter/Getter +Parameter: String + +设置和获取视频海报,只有在视频播放前才能看到 ...`,l:"advanced/property.html#poster",a:"poster"},"5.24":{t:"`mini`",p:` +Type: Setter/Getter +Parameter: Boolean + +设置和获取播放器迷你模式 +<div ...`,l:"advanced/property.html#mini",a:"mini"},"5.25":{t:"`playing`",p:` +Type: Getter +Parameter: Boolean + +获取视频是否正在播放中 +<div classNam ...`,l:"advanced/property.html#playing",a:"playing"},"5.26":{t:"`state`",p:` +Type: Setter/Getter +Parameter: String + +获取或设置播放器当前状态,支持:standa ...`,l:"advanced/property.html#state",a:"state"},"5.27":{t:"`autoSize`",p:` +Type: Function + +设置视频是否自适应尺寸 +<div className="run-code& ...`,l:"advanced/property.html#autosize",a:"autosize"},"5.28":{t:"`rect`",p:` +Type: Getter + +获取播放器的尺寸和坐标信息 +<div className="run-code& ...`,l:"advanced/property.html#rect",a:"rect"},"5.29":{t:"`bottom` / `top` / `left` / `right` / `x` / `y` / `width` / `height`",p:` +Type: Getter + +这些属性是对 rect 的快捷访问: + +bottom, top, left, right, x ...`,l:"advanced/property.html#bottom-top-left-right-x-y-width-height",a:"bottom-top-left-right-x-y-width-height"},"5.30":{t:"`flip`",p:` +Type: Setter/Getter +Parameter: String + +设置和获取播放器翻转,支持normal, ...`,l:"advanced/property.html#flip",a:"flip"},"5.31":{t:"`playbackRate`",p:` +Type: Setter/Getter +Parameter: Number + +设置和获取播放器播放速度 +<div c ...`,l:"advanced/property.html#playbackrate",a:"playbackrate"},"5.32":{t:"`aspectRatio`",p:` +Type: Setter/Getter +Parameter: String + +设置和获取播放器长宽比 +<div cl ...`,l:"advanced/property.html#aspectratio",a:"aspectratio"},"5.33":{t:"`autoHeight`",p:` +Type: Function + +当容器只有宽度,该属性可以自动计算出并设置视频的高度 +<div className= ...`,l:"advanced/property.html#autoheight",a:"autoheight"},"5.34":{t:"`attr`",p:` +Type: Function +Parameter: String + +动态获取和设置 video 元素的属性 +<div ...`,l:"advanced/property.html#attr",a:"attr"},"5.35":{t:"`type`",p:` +Type: Setter/Getter +Parameter: String + +动态获取和设置视频类型 +<div cl ...`,l:"advanced/property.html#type",a:"type"},"5.36":{t:"`theme`",p:` +Type: Setter/Getter +Parameter: String + +动态获取和设置播放器主题颜色 +<div ...`,l:"advanced/property.html#theme",a:"theme"},"5.37":{t:"`airplay`",p:` +Type: Function + +开启隔空播放 +<div className="run-code" ...`,l:"advanced/property.html#airplay",a:"airplay"},"5.38":{t:"`loaded`",p:` +Type: Getter + +视频缓存的比例,范围是 [0, 1],常配合 video:timeupdate 事件使用 +&l ...`,l:"advanced/property.html#loaded",a:"loaded"},"5.39":{t:"`loadedTime`",p:` +Type: Getter + +已缓存的媒体时长,单位为秒。通常与 loaded 一起使用,用于展示缓冲进度细节。 +<d ...`,l:"advanced/property.html#loadedtime",a:"loadedtime"},"5.40":{t:"`played`",p:` +Type: Getter + +视频播放的比例,范围是 [0, 1],常配合 video:timeupdate 事件使用 +&l ...`,l:"advanced/property.html#played",a:"played"},"5.41":{t:"`proxy`",p:` +Type: Function + +DOM 事件的代理函数,实质上代理了 addEventListener 和 removeE ...`,l:"advanced/property.html#proxy",a:"proxy"},"5.42":{t:"`query`",p:` +Type: Function + +DOM 的查询函数,类似 document.querySelector,但被查询的对象局限 ...`,l:"advanced/property.html#query",a:"query"},"5.43":{t:"`video`",p:` +Type: Element + +快捷返回播放器的 video 元素 +<div className="run- ...`,l:"advanced/property.html#video",a:"video"},"5.44":{t:"`cssVar`",p:` +Type: Function + +动态获取或设置 css 变量 +<div className="run-co ...`,l:"advanced/property.html#cssvar",a:"cssvar"},"5.45":{t:"`quality`",p:` +Type: Setter +Parameter: Array + +动态设置画质列表 +<div className=&qu ...`,l:"advanced/property.html#quality",a:"quality"},"5.46":{t:"`thumbnails`",p:` +Type: Setter/Getter +Parameter: Object + +动态设置缩略图 +<div classN ...`,l:"advanced/property.html#thumbnails",a:"thumbnails"},"5.47":{t:"`subtitleOffset`",p:` +Type: Setter/Getter +Parameter: Number + +动态设置字幕偏移 +<div class ...`,l:"advanced/property.html#subtitleoffset",a:"subtitleoffset"},"6.0":{t:"# 右键菜单",p:"",l:"component/contextmenu.html",a:"右键菜单"},"6.1":{t:"配置",p:` + + +属性 +类型 +描述 + + + + +disable +Boolean +是否禁用组件 + + +name +String +组件唯一名称,用于 ...`,l:"component/contextmenu.html#配置",a:"配置"},"6.2":{t:"创建",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/contextmenu.html#创建",a:"创建"},"6.3":{t:"添加",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/contextmenu.html#添加",a:"添加"},"6.4":{t:"删除",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/contextmenu.html#删除",a:"删除"},"6.5":{t:"更新",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/contextmenu.html#更新",a:"更新"},"7.0":{t:"# 控制器",p:"",l:"component/controls.html",a:"控制器"},"7.1":{t:"配置",p:` + + +属性 +类型 +描述 + + + + +disable +Boolean +是否禁用组件 + + +name +String +组件唯一名称,用于 ...`,l:"component/controls.html#配置",a:"配置"},"7.2":{t:"创建",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/controls.html#创建",a:"创建"},"7.3":{t:"添加",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/controls.html#添加",a:"添加"},"7.4":{t:"删除",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/controls.html#删除",a:"删除"},"7.5":{t:"更新",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/controls.html#更新",a:"更新"},"8.0":{t:"# 业务层",p:"",l:"component/layers.html",a:"业务层"},"8.1":{t:"配置",p:` + + +属性 +类型 +描述 + + + + +disable +Boolean +是否禁用组件 + + +name +String +组件唯一名称,用于 ...`,l:"component/layers.html#配置",a:"配置"},"8.2":{t:"创建",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/layers.html#创建",a:"创建"},"8.3":{t:"添加",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/layers.html#添加",a:"添加"},"8.4":{t:"删除",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/layers.html#删除",a:"删除"},"8.5":{t:"更新",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/layers.html#更新",a:"更新"},"9.0":{t:"# 设置面板",p:"",l:"component/setting.html",a:"设置面板"},"9.1":{t:"内置",p:"须先打开设置面板,然后自带四个内置项:flip, playbackRate, aspectRatio, subtitleOf ...",l:"component/setting.html#内置",a:"内置"},"9.2":{t:"创建 - 按钮",p:` + + +属性 +类型 +描述 + + + + +html +String, Element +元素的 DOM + + +icon +String, El ...`,l:"component/setting.html#创建-按钮",a:"创建-按钮"},"9.3":{t:"创建 - 选择列表",p:` + + +属性 +类型 +描述 + + + + +html +String, Element +元素的 DOM + + +icon +String, El ...`,l:"component/setting.html#创建-选择列表",a:"创建-选择列表"},"9.4":{t:"创建 - 列表嵌套",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/setting.html#创建-列表嵌套",a:"创建-列表嵌套"},"9.5":{t:"创建 - 切换按钮",p:` + + +属性 +类型 +描述 + + + + +html +String, Element +元素的 DOM 元素 + + +icon +String, ...`,l:"component/setting.html#创建-切换按钮",a:"创建-切换按钮"},"9.6":{t:"创建 - 范围滑块",p:` + + +属性 +类型 +描述 + + + + +html +String, Element +元素的 DOM 元素 + + +icon +String, ...`,l:"component/setting.html#创建-范围滑块",a:"创建-范围滑块"},"9.7":{t:"添加",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/setting.html#添加",a:"添加"},"9.8":{t:"删除",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/setting.html#删除",a:"删除"},"9.9":{t:"更新",p:"<div className="run-code">▶ Run Code</div&g ...",l:"component/setting.html#更新",a:"更新"},"10.0":{t:"# Advanced Properties",p:"The Advanced Properties here refer to the secondary properties ...",l:"en/advanced/built-in.html",a:"advanced-properties"},"10.1":{t:"`option`",p:`The player's options. +<div className="run-code"&g ...`,l:"en/advanced/built-in.html#option",a:"option"},"10.2":{t:"`template`",p:`Manages all DOM elements of the player. +<div className=&quo ...`,l:"en/advanced/built-in.html#template",a:"template"},"10.3":{t:"`events`",p:"Manages all DOM events for the player. It essentially proxies ...",l:"en/advanced/built-in.html#events",a:"events"},"10.4":{t:"`storage`",p:`Manages the player's local storage. + +The name property is used ...`,l:"en/advanced/built-in.html#storage",a:"storage"},"10.5":{t:"`icons`",p:`Manages all svg icons for the player. +<div className=" ...`,l:"en/advanced/built-in.html#icons",a:"icons"},"10.6":{t:"`i18n`",p:`Manages the player's i18n. + +The get method is used to retrieve ...`,l:"en/advanced/built-in.html#i18n",a:"i18n"},"10.7":{t:"`notice`",p:"Manages the player's notifications. It only has a show propert ...",l:"en/advanced/built-in.html#notice",a:"notice"},"10.8":{t:"`layers`",p:`Manages the player's layers. + +The add method is used to dynami ...`,l:"en/advanced/built-in.html#layers",a:"layers"},"10.9":{t:"`controls`",p:`Manages the player's controls. + + +The add method is used to dyn ...`,l:"en/advanced/built-in.html#controls",a:"controls"},"10.10":{t:"`contextmenu`",p:`Manages the player's context menu + +The add method is used to d ...`,l:"en/advanced/built-in.html#contextmenu",a:"contextmenu"},"10.11":{t:"`subtitle`",p:`Manages the player's subtitle functionality + +The url property ...`,l:"en/advanced/built-in.html#subtitle",a:"subtitle"},"10.12":{t:"`info`",p:"Manages the player's information panel, commonly used to view ...",l:"en/advanced/built-in.html#info",a:"info"},"10.13":{t:"`loading`",p:`Manages the player's loading layer + +The show property is used ...`,l:"en/advanced/built-in.html#loading",a:"loading"},"10.14":{t:"`hotkey`",p:`Manages the player's hotkey functionality + +The add method is u ...`,l:"en/advanced/built-in.html#hotkey",a:"hotkey"},"10.15":{t:"`mask`",p:`Manages the player's mask layer + +The show property is used to ...`,l:"en/advanced/built-in.html#mask",a:"mask"},"10.16":{t:"`setting`",p:`Manages the player's settings panel + +The add method is used to ...`,l:"en/advanced/built-in.html#setting",a:"setting"},"10.17":{t:"`plugins`",p:"Manages the player's plugin functionality, with only one metho ...",l:"en/advanced/built-in.html#plugins",a:"plugins"},"11.0":{t:"# Static Properties",p:"Here, static properties refer to the first-level properties at ...",l:"en/advanced/class.html",a:"static-properties"},"11.1":{t:"`instances`",p:"Returns an array of all player instances. This property can be ...",l:"en/advanced/class.html#instances",a:"instances"},"11.2":{t:"`version`",p:`Returns the version information of the player. +<div classNa ...`,l:"en/advanced/class.html#version",a:"version"},"11.3":{t:"`env`",p:`Returns the environment variables of the player. +<div class ...`,l:"en/advanced/class.html#env",a:"env"},"11.4":{t:"`build`",p:`Returns the build timestamp of the player. +<div className=& ...`,l:"en/advanced/class.html#build",a:"build"},"11.5":{t:"`config`",p:`Returns the default configuration for videos. +<div classNam ...`,l:"en/advanced/class.html#config",a:"config"},"11.6":{t:"`utils`",p:`Returns the collection of utility functions for the player. +&l ...`,l:"en/advanced/class.html#utils",a:"utils"},"11.7":{t:"`scheme`",p:`Returns the validation schema for player options. +<div clas ...`,l:"en/advanced/class.html#scheme",a:"scheme"},"11.8":{t:"`Emitter`",p:`Returns the constructor of the event emitter. +<div classNam ...`,l:"en/advanced/class.html#emitter",a:"emitter"},"11.9":{t:"`validator`",p:`Returns the validation function for options. +<div className ...`,l:"en/advanced/class.html#validator",a:"validator"},"11.10":{t:"`kindOf`",p:`Returns the type detection utility function. +<div className ...`,l:"en/advanced/class.html#kindof",a:"kindof"},"11.11":{t:"`html`",p:`Returns the html string required by the player. +<div classN ...`,l:"en/advanced/class.html#html",a:"html"},"11.12":{t:"`option`",p:`Returns the default options of the player. +<div className=& ...`,l:"en/advanced/class.html#option",a:"option"},"12.0":{t:"# Instance Events",p:"Player events are divided into two types: native events of the ...",l:"en/advanced/event.html",a:"instance-events"},"12.1":{t:"`ready`",p:`Triggered when the player is ready for the first time. +<div ...`,l:"en/advanced/event.html#ready",a:"ready"},"12.2":{t:"`restart`",p:"Triggered when the player switches URLs and becomes ready to p ...",l:"en/advanced/event.html#restart",a:"restart"},"12.3":{t:"`pause`",p:`Triggered when the player is paused. +<div className="r ...`,l:"en/advanced/event.html#pause",a:"pause"},"12.4":{t:"`play`",p:`Triggered when the player starts playing. +<div className=&q ...`,l:"en/advanced/event.html#play",a:"play"},"12.5":{t:"`hotkey`",p:`Triggered when a player hotkey is pressed. +<div className=& ...`,l:"en/advanced/event.html#hotkey",a:"hotkey"},"12.6":{t:"`destroy`",p:`Triggered when the player is destroyed. +<div className=&quo ...`,l:"en/advanced/event.html#destroy",a:"destroy"},"12.7":{t:"`focus`",p:`Triggered when the player gains focus. +<div className=" ...`,l:"en/advanced/event.html#focus",a:"focus"},"12.8":{t:"`blur`",p:`Triggered when the player loses focus. +<div className=" ...`,l:"en/advanced/event.html#blur",a:"blur"},"12.9":{t:"`dblclick`",p:`Triggered when the player is double-clicked. +<div className ...`,l:"en/advanced/event.html#dblclick",a:"dblclick"},"12.10":{t:"`click`",p:`Triggered when the player is clicked. +<div className=" ...`,l:"en/advanced/event.html#click",a:"click"},"12.11":{t:"`error`",p:"Triggered when an error occurs while the player is loading a v ...",l:"en/advanced/event.html#error",a:"error"},"12.12":{t:"`hover`",p:`Triggered when the mouse enters or leaves the player. +<div ...`,l:"en/advanced/event.html#hover",a:"hover"},"12.13":{t:"`mousemove`",p:`Triggered when the mouse moves over the player. +<div classN ...`,l:"en/advanced/event.html#mousemove",a:"mousemove"},"12.14":{t:"`resize`",p:`Triggered when the player's dimensions change. +<div classNa ...`,l:"en/advanced/event.html#resize",a:"resize"},"12.15":{t:"`view`",p:`Triggered when the player enters the viewport. +<div classNa ...`,l:"en/advanced/event.html#view",a:"view"},"12.16":{t:"`lock`",p:`Triggered when the lock state changes on mobile devices. +<d ...`,l:"en/advanced/event.html#lock",a:"lock"},"12.17":{t:"`aspectRatio`",p:`Triggered when the player's aspect ratio changes. +<div clas ...`,l:"en/advanced/event.html#aspectratio",a:"aspectratio"},"12.18":{t:"`autoHeight`",p:`Triggered when the player's height is automatically set. +<d ...`,l:"en/advanced/event.html#autoheight",a:"autoheight"},"12.19":{t:"`autoSize`",p:`Triggered when the player's size is automatically set. +<div ...`,l:"en/advanced/event.html#autosize",a:"autosize"},"12.20":{t:"`flip`",p:`Triggered when the player is flipped. +<div className=" ...`,l:"en/advanced/event.html#flip",a:"flip"},"12.21":{t:"`fullscreen`",p:"Triggered when the player enters or exits windowed fullscreen ...",l:"en/advanced/event.html#fullscreen",a:"fullscreen"},"12.22":{t:"`fullscreenError`",p:`Triggered when a windowed fullscreen error occurs. +<div cla ...`,l:"en/advanced/event.html#fullscreenerror",a:"fullscreenerror"},"12.23":{t:"`fullscreenWeb`",p:"Triggered when the player enters or exits web fullscreen mode. ...",l:"en/advanced/event.html#fullscreenweb",a:"fullscreenweb"},"12.24":{t:"`mini`",p:`Triggered when the player enters or exits mini mode. +<div c ...`,l:"en/advanced/event.html#mini",a:"mini"},"12.25":{t:"`pip`",p:"Triggered when the player enters or exits Picture-in-Picture m ...",l:"en/advanced/event.html#pip",a:"pip"},"12.26":{t:"`screenshot`",p:`Triggered when the player takes a screenshot. +<div classNam ...`,l:"en/advanced/event.html#screenshot",a:"screenshot"},"12.27":{t:"`seek`",p:`Triggered when the player performs a time seek. +<div classN ...`,l:"en/advanced/event.html#seek",a:"seek"},"12.28":{t:"`subtitleOffset`",p:`Triggered when the subtitle offset changes in the player. +< ...`,l:"en/advanced/event.html#subtitleoffset",a:"subtitleoffset"},"12.29":{t:"`subtitleBeforeUpdate`",p:`Triggered before subtitles are updated. +<div className=&quo ...`,l:"en/advanced/event.html#subtitlebeforeupdate",a:"subtitlebeforeupdate"},"12.30":{t:"`subtitleAfterUpdate`",p:`Triggered after subtitles are updated. +<div className=" ...`,l:"en/advanced/event.html#subtitleafterupdate",a:"subtitleafterupdate"},"12.31":{t:"`subtitleLoad`",p:`Triggered when subtitles are loaded. +<div className="r ...`,l:"en/advanced/event.html#subtitleload",a:"subtitleload"},"12.32":{t:"`info`",p:`Triggered when the info panel is shown or hidden. +<div clas ...`,l:"en/advanced/event.html#info",a:"info"},"12.33":{t:"`layer`",p:`Triggered when a custom layer is shown or hidden. +<div clas ...`,l:"en/advanced/event.html#layer",a:"layer"},"12.34":{t:"`loading`",p:`Triggered when the loader is shown or hidden. +<div classNam ...`,l:"en/advanced/event.html#loading",a:"loading"},"12.35":{t:"`mask`",p:`Triggered when the mask layer is shown or hidden. +<div clas ...`,l:"en/advanced/event.html#mask",a:"mask"},"12.36":{t:"`subtitle`",p:`Triggered when the subtitle layer is shown or hidden. +<div ...`,l:"en/advanced/event.html#subtitle",a:"subtitle"},"12.37":{t:"`contextmenu`",p:`Triggered when the context menu is shown or hidden. +<div cl ...`,l:"en/advanced/event.html#contextmenu",a:"contextmenu"},"12.38":{t:"`control`",p:`Triggered when the control bar is shown or hidden. +<div cla ...`,l:"en/advanced/event.html#control",a:"control"},"12.39":{t:"`setting`",p:`Triggered when the settings panel is shown or hidden. +<div ...`,l:"en/advanced/event.html#setting",a:"setting"},"12.40":{t:"`muted`",p:`Triggered when the muted state changes. +<div className=&quo ...`,l:"en/advanced/event.html#muted",a:"muted"},"12.41":{t:"`keydown`",p:`Listens for the keydown event from the document. +<div class ...`,l:"en/advanced/event.html#keydown",a:"keydown"},"12.42":{t:"`video:canplay`",p:"The browser can start playing the media, but estimates there i ...",l:"en/advanced/event.html#video-canplay",a:"video-canplay"},"12.43":{t:"`video:canplaythrough`",p:"The browser estimates it can play the media through to the end ...",l:"en/advanced/event.html#video-canplaythrough",a:"video-canplaythrough"},"12.44":{t:"`video:complete`",p:`The OfflineAudioContext rendering is complete. +`,l:"en/advanced/event.html#video-complete",a:"video-complete"},"12.45":{t:"`video:durationchange`",p:`Triggered when the value of the duration property changes. +`,l:"en/advanced/event.html#video-durationchange",a:"video-durationchange"},"12.46":{t:"`video:emptied`",p:"The media has become empty; for example, this event is sent wh ...",l:"en/advanced/event.html#video-emptied",a:"video-emptied"},"12.47":{t:"`video:ended`",p:`Playback has stopped because the media has reached its end. +`,l:"en/advanced/event.html#video-ended",a:"video-ended"},"12.48":{t:"`video:error`",p:"An error occurred while fetching the media data, or the resour ...",l:"en/advanced/event.html#video-error",a:"video-error"},"12.49":{t:"`video:loadeddata`",p:`The first frame of the media has finished loading. +`,l:"en/advanced/event.html#video-loadeddata",a:"video-loadeddata"},"12.50":{t:"`video:loadedmetadata`",p:`Metadata has been loaded. +`,l:"en/advanced/event.html#video-loadedmetadata",a:"video-loadedmetadata"},"12.51":{t:"`video:pause`",p:`Playback has been paused. +`,l:"en/advanced/event.html#video-pause",a:"video-pause"},"12.52":{t:"`video:play`",p:`Playback has begun. +`,l:"en/advanced/event.html#video-play",a:"video-play"},"12.53":{t:"`video:playing`",p:"Playback is ready to start after having been paused or delayed ...",l:"en/advanced/event.html#video-playing",a:"video-playing"},"12.54":{t:"`video:progress`",p:`Fired periodically as the browser loads the resource. +`,l:"en/advanced/event.html#video-progress",a:"video-progress"},"12.55":{t:"`video:ratechange`",p:`The playback rate has changed. +`,l:"en/advanced/event.html#video-ratechange",a:"video-ratechange"},"12.56":{t:"`video:seeked`",p:`A seek operation has completed. +`,l:"en/advanced/event.html#video-seeked",a:"video-seeked"},"12.57":{t:"`video:seeking`",p:`A seek operation has begun. +`,l:"en/advanced/event.html#video-seeking",a:"video-seeking"},"12.58":{t:"`video:stalled`",p:"The user agent is trying to fetch media data, but data is unex ...",l:"en/advanced/event.html#video-stalled",a:"video-stalled"},"12.59":{t:"`video:suspend`",p:`Media data loading has been suspended. +`,l:"en/advanced/event.html#video-suspend",a:"video-suspend"},"12.60":{t:"`video:timeupdate`",p:`The time indicated by the currentTime property has changed. +`,l:"en/advanced/event.html#video-timeupdate",a:"video-timeupdate"},"12.61":{t:"`video:volumechange`",p:`The volume has changed. +`,l:"en/advanced/event.html#video-volumechange",a:"video-volumechange"},"12.62":{t:"`video:waiting`",p:`Playback has stopped because of a temporary lack of data. +`,l:"en/advanced/event.html#video-waiting",a:"video-waiting"},"13.0":{t:"# Global Properties",p:"The global properties here refer to the top-level properties m ...",l:"en/advanced/global.html",a:"global-properties"},"13.1":{t:"DEBUG",p:"Whether to enable debug mode, which can print all built-in vid ...",l:"en/advanced/global.html#debug",a:"debug"},"13.2":{t:"STYLE",p:`Returns the player style text. +<div className="run-cod ...`,l:"en/advanced/global.html#style",a:"style"},"13.3":{t:"CONTEXTMENU",p:`Whether to enable the context menu. Default is on. +<div cla ...`,l:"en/advanced/global.html#contextmenu",a:"contextmenu"},"13.4":{t:"NOTICE_TIME",p:"The display duration of notification messages, in milliseconds ...",l:"en/advanced/global.html#notice-time",a:"notice-time"},"13.5":{t:"SETTING_WIDTH",p:"The default width of the settings panel, in pixels. Default is ...",l:"en/advanced/global.html#setting-width",a:"setting-width"},"13.6":{t:"SETTING_ITEM_WIDTH",p:"The default width of a setting item in the settings panel, in ...",l:"en/advanced/global.html#setting-item-width",a:"setting-item-width"},"13.7":{t:"SETTING_ITEM_HEIGHT",p:"The default height of a setting item in the settings panel, in ...",l:"en/advanced/global.html#setting-item-height",a:"setting-item-height"},"13.8":{t:"RESIZE_TIME",p:"The throttle time for the resize event, in milliseconds. Defau ...",l:"en/advanced/global.html#resize-time",a:"resize-time"},"13.9":{t:"SCROLL_TIME",p:"The throttle time for the scroll event, in milliseconds. Defau ...",l:"en/advanced/global.html#scroll-time",a:"scroll-time"},"13.10":{t:"SCROLL_GAP",p:"The boundary tolerance distance for the view event, in pixels. ...",l:"en/advanced/global.html#scroll-gap",a:"scroll-gap"},"13.11":{t:"AUTO_PLAYBACK_MAX",p:"The maximum record count for the auto-playback feature. Defaul ...",l:"en/advanced/global.html#auto-playback-max",a:"auto-playback-max"},"13.12":{t:"AUTO_PLAYBACK_MIN",p:"The minimum record duration for the auto-playback feature, in ...",l:"en/advanced/global.html#auto-playback-min",a:"auto-playback-min"},"13.13":{t:"AUTO_PLAYBACK_TIMEOUT",p:"The hide delay duration for the auto-playback feature, in mill ...",l:"en/advanced/global.html#auto-playback-timeout",a:"auto-playback-timeout"},"13.14":{t:"RECONNECT_TIME_MAX",p:"The maximum number of automatic reconnection attempts when a c ...",l:"en/advanced/global.html#reconnect-time-max",a:"reconnect-time-max"},"13.15":{t:"RECONNECT_SLEEP_TIME",p:"The delay time for automatic reconnection when a connection er ...",l:"en/advanced/global.html#reconnect-sleep-time",a:"reconnect-sleep-time"},"13.16":{t:"CONTROL_HIDE_TIME",p:"The auto-hide delay time for the bottom control bar, in millis ...",l:"en/advanced/global.html#control-hide-time",a:"control-hide-time"},"13.17":{t:"DBCLICK_TIME",p:"The delay time for the double-click event, in milliseconds. De ...",l:"en/advanced/global.html#dbclick-time",a:"dbclick-time"},"13.18":{t:"DBCLICK_FULLSCREEN",p:"On desktop, whether double-click toggles fullscreen. Default i ...",l:"en/advanced/global.html#dbclick-fullscreen",a:"dbclick-fullscreen"},"13.19":{t:"MOBILE_DBCLICK_PLAY",p:"On mobile, whether double-click toggles play/pause. Default is ...",l:"en/advanced/global.html#mobile-dbclick-play",a:"mobile-dbclick-play"},"13.20":{t:"MOBILE_CLICK_PLAY",p:"On mobile, whether single-click toggles play/pause. Default is ...",l:"en/advanced/global.html#mobile-click-play",a:"mobile-click-play"},"13.21":{t:"AUTO_ORIENTATION_TIME",p:"On mobile, the delay time for auto-rotation, in milliseconds. ...",l:"en/advanced/global.html#auto-orientation-time",a:"auto-orientation-time"},"13.22":{t:"INFO_LOOP_TIME",p:"The refresh interval for the info panel, in milliseconds. Defa ...",l:"en/advanced/global.html#info-loop-time",a:"info-loop-time"},"13.23":{t:"FAST_FORWARD_VALUE",p:"On mobile, the speed multiplier for long-press fast-forward. D ...",l:"en/advanced/global.html#fast-forward-value",a:"fast-forward-value"},"13.24":{t:"FAST_FORWARD_TIME",p:"On mobile, the delay time for long-press fast-forward, in mill ...",l:"en/advanced/global.html#fast-forward-time",a:"fast-forward-time"},"13.25":{t:"TOUCH_MOVE_RATIO",p:"On mobile, the speed multiplier for left/right swipe to seek. ...",l:"en/advanced/global.html#touch-move-ratio",a:"touch-move-ratio"},"13.26":{t:"VOLUME_STEP",p:"The step size for volume adjustment via keyboard shortcuts. De ...",l:"en/advanced/global.html#volume-step",a:"volume-step"},"13.27":{t:"SEEK_STEP",p:"The step size for seeking via keyboard shortcuts, in seconds. ...",l:"en/advanced/global.html#seek-step",a:"seek-step"},"13.28":{t:"PLAYBACK_RATE",p:"The built-in list of playback rates. Default is [0.5, 0.75, 1, ...",l:"en/advanced/global.html#playback-rate",a:"playback-rate"},"13.29":{t:"ASPECT_RATIO",p:"The built-in list of video aspect ratios. Default is ['default ...",l:"en/advanced/global.html#aspect-ratio",a:"aspect-ratio"},"13.30":{t:"FLIP",p:"The built-in list of video flip options. Default is ['normal', ...",l:"en/advanced/global.html#flip",a:"flip"},"13.31":{t:"FULLSCREEN_WEB_IN_BODY",p:"Whether to mount the player under the body element during web ...",l:"en/advanced/global.html#fullscreen-web-in-body",a:"fullscreen-web-in-body"},"13.32":{t:"LOG_VERSION",p:`Sets whether to print the player version. Default is true. +< ...`,l:"en/advanced/global.html#log-version",a:"log-version"},"13.33":{t:"USE_RAF",p:"Sets whether to use requestAnimationFrame. Default is false. C ...",l:"en/advanced/global.html#use-raf",a:"use-raf"},"13.34":{t:"REMOVE_SRC_WHEN_DESTROY",p:"Whether to remove the video's src attribute and call load() to ...",l:"en/advanced/global.html#remove-src-when-destroy",a:"remove-src-when-destroy"},"14.0":{t:"# Writing Plugins",p:"Once you are familiar with the player's properties, methods, a ...",l:"en/advanced/plugin.html",a:"writing-plugins"},"15.0":{t:"# Instance Properties",p:"Here, Instance Properties refer to the first-level properties ...",l:"en/advanced/property.html",a:"instance-properties"},"15.1":{t:"`play`",p:` +Type: Function + +Play the video. +<div className="run-c ...`,l:"en/advanced/property.html#play",a:"play"},"15.2":{t:"`pause`",p:` +Type: Function + +Pause the video. +<div className="run- ...`,l:"en/advanced/property.html#pause",a:"pause"},"15.3":{t:"`toggle`",p:` +Type: Function + +Toggle video play and pause. +<div classNam ...`,l:"en/advanced/property.html#toggle",a:"toggle"},"15.4":{t:"`destroy`",p:` +Type: Function +Parameter: Boolean + +Destroy the player. Accept ...`,l:"en/advanced/property.html#destroy",a:"destroy"},"15.5":{t:"`reset`",p:` +Type: Function + +Reset the player's video element: removes the ...`,l:"en/advanced/property.html#reset",a:"reset"},"15.6":{t:"`seek`",p:` +Type: Setter +Parameter: Number + +Seek to a specific time in th ...`,l:"en/advanced/property.html#seek",a:"seek"},"15.7":{t:"`forward`",p:` +Type: Setter +Parameter: Number + +Fast-forward the video time, ...`,l:"en/advanced/property.html#forward",a:"forward"},"15.8":{t:"`backward`",p:` +Type: Setter +Parameter: Number + +Rewind the video time, in sec ...`,l:"en/advanced/property.html#backward",a:"backward"},"15.9":{t:"`volume`",p:` +Type: Setter/Getter +Parameter: Number + +Set and get the video ...`,l:"en/advanced/property.html#volume",a:"volume"},"15.10":{t:"`url`",p:` +Type: Setter/Getter +Parameter: String + +Set and get the video ...`,l:"en/advanced/property.html#url",a:"url"},"15.11":{t:"`switch`",p:` +Type: Setter +Parameter: String + +Set the video URL. Similar to ...`,l:"en/advanced/property.html#switch",a:"switch"},"15.12":{t:"`switchUrl`",p:` +Type: Function +Parameter: String + +Set the video URL. Similar ...`,l:"en/advanced/property.html#switchurl",a:"switchurl"},"15.13":{t:"`switchQuality`",p:` +Type: Function +Parameter: String + +Sets the video quality URL. ...`,l:"en/advanced/property.html#switchquality",a:"switchquality"},"15.14":{t:"`muted`",p:` +Type: Setter/Getter +Parameter: Boolean + +Sets or gets whether ...`,l:"en/advanced/property.html#muted",a:"muted"},"15.15":{t:"`currentTime`",p:` +Type: Setter/Getter +Parameter: Number + +Sets or gets the curre ...`,l:"en/advanced/property.html#currenttime",a:"currenttime"},"15.16":{t:"`duration`",p:` +Type: Getter + +Gets the duration of the video. +<div classNa ...`,l:"en/advanced/property.html#duration",a:"duration"},"15.17":{t:"`screenshot`",p:` +Type: Function + +Downloads a screenshot of the current video f ...`,l:"en/advanced/property.html#screenshot",a:"screenshot"},"15.18":{t:"`getDataURL`",p:` +Type: Function + +Gets the base64 URL of a screenshot of the cu ...`,l:"en/advanced/property.html#getdataurl",a:"getdataurl"},"15.19":{t:"`getBlobUrl`",p:` +Type: Function + +Gets the blob URL of a screenshot of the curr ...`,l:"en/advanced/property.html#getbloburl",a:"getbloburl"},"15.20":{t:"`fullscreen`",p:` +Type: Setter/Getter +Parameter: Boolean + +Sets or gets the play ...`,l:"en/advanced/property.html#fullscreen",a:"fullscreen"},"15.21":{t:"`fullscreenWeb`",p:` +Type: Setter/Getter +Parameter: Boolean + +Sets or gets the play ...`,l:"en/advanced/property.html#fullscreenweb",a:"fullscreenweb"},"15.22":{t:"`pip`",p:` +Type: Setter/Getter +Parameter: Boolean + +Sets or gets the play ...`,l:"en/advanced/property.html#pip",a:"pip"},"15.23":{t:"`poster`",p:` +Type: Setter/Getter +Parameter: String + +Sets and gets the vide ...`,l:"en/advanced/property.html#poster",a:"poster"},"15.24":{t:"`mini`",p:` +Type: Setter/Getter +Parameter: Boolean + +Sets and gets the pla ...`,l:"en/advanced/property.html#mini",a:"mini"},"15.25":{t:"`playing`",p:` +Type: Getter +Parameter: Boolean + +Gets whether the video is cu ...`,l:"en/advanced/property.html#playing",a:"playing"},"15.26":{t:"`state`",p:` +Type: Setter/Getter +Parameter: String + +Gets or sets the playe ...`,l:"en/advanced/property.html#state",a:"state"},"15.27":{t:"`autoSize`",p:` +Type: Function + +Sets whether the video adapts its size automa ...`,l:"en/advanced/property.html#autosize",a:"autosize"},"15.28":{t:"`rect`",p:` +Type: Getter + +Gets the player's dimensions and coordinate inf ...`,l:"en/advanced/property.html#rect",a:"rect"},"15.29":{t:"`bottom` / `top` / `left` / `right` / `x` / `y` / `width` / `height`",p:` +Type: Getter + +These properties provide quick access to rect: + ...`,l:"en/advanced/property.html#bottom-top-left-right-x-y-width-height",a:"bottom-top-left-right-x-y-width-height"},"15.30":{t:"`flip`",p:` +Type: Setter/Getter +Parameter: String + +Sets and gets the play ...`,l:"en/advanced/property.html#flip",a:"flip"},"15.31":{t:"`playbackRate`",p:` +Type: Setter/Getter +Parameter: Number + +Sets and gets the play ...`,l:"en/advanced/property.html#playbackrate",a:"playbackrate"},"15.32":{t:"`aspectRatio`",p:` +Type: Setter/Getter +Parameter: String + +Sets and gets the play ...`,l:"en/advanced/property.html#aspectratio",a:"aspectratio"},"15.33":{t:"`autoHeight`",p:` +Type: Function + +When the container only has a defined width, ...`,l:"en/advanced/property.html#autoheight",a:"autoheight"},"15.34":{t:"`attr`",p:` +Type: Function +Parameter: String + +Dynamically get and set att ...`,l:"en/advanced/property.html#attr",a:"attr"},"15.35":{t:"`type`",p:` +Type: Setter/Getter +Parameter: String + +Dynamically get and se ...`,l:"en/advanced/property.html#type",a:"type"},"15.36":{t:"`theme`",p:` +Type: Setter/Getter +Parameter: String + +Dynamically get and se ...`,l:"en/advanced/property.html#theme",a:"theme"},"15.37":{t:"`airplay`",p:` +Type: Function + +Initiate AirPlay. +<div className="run ...`,l:"en/advanced/property.html#airplay",a:"airplay"},"15.38":{t:"`loaded`",p:` +Type: Getter + +The proportion of video buffered, ranging from ...`,l:"en/advanced/property.html#loaded",a:"loaded"},"15.39":{t:"`loadedTime`",p:` +Type: Getter + +The buffered media duration in seconds. Typical ...`,l:"en/advanced/property.html#loadedtime",a:"loadedtime"},"15.40":{t:"`played`",p:` +Type: Getter + +The proportion of video played, ranging from [0 ...`,l:"en/advanced/property.html#played",a:"played"},"15.41":{t:"`proxy`",p:` +Type: Function + +A proxy function for DOM events, essentially ...`,l:"en/advanced/property.html#proxy",a:"proxy"},"15.42":{t:"`query`",p:` +Type: Function + +A DOM query function, similar to document.que ...`,l:"en/advanced/property.html#query",a:"query"},"15.43":{t:"`video`",p:` +Type: Element + +Quickly returns the player's video element. +&l ...`,l:"en/advanced/property.html#video",a:"video"},"15.44":{t:"`cssVar`",p:` +Type: Function + +Dynamically get or set CSS variables. +<div ...`,l:"en/advanced/property.html#cssvar",a:"cssvar"},"15.45":{t:"`quality`",p:` +Type: Setter +Parameter: Array + +Dynamically set the quality li ...`,l:"en/advanced/property.html#quality",a:"quality"},"15.46":{t:"`thumbnails`",p:` +Type: Setter/Getter +Parameter: Object + +Dynamically set thumbn ...`,l:"en/advanced/property.html#thumbnails",a:"thumbnails"},"15.47":{t:"`subtitleOffset`",p:` +Type: Setter/Getter +Parameter: Number + +Dynamically set subtit ...`,l:"en/advanced/property.html#subtitleoffset",a:"subtitleoffset"},"16.0":{t:"# Context Menu",p:"",l:"en/component/contextmenu.html",a:"context-menu"},"16.1":{t:"Configuration",p:` + + +Property +Type +Description + + + + +disable +Boolean +Whether to di ...`,l:"en/component/contextmenu.html#configuration",a:"configuration"},"16.2":{t:"Creation",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/contextmenu.html#creation",a:"creation"},"16.3":{t:"Addition",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/contextmenu.html#addition",a:"addition"},"16.4":{t:"Deletion",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/contextmenu.html#deletion",a:"deletion"},"16.5":{t:"Update",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/contextmenu.html#update",a:"update"},"17.0":{t:"# Controls",p:"",l:"en/component/controls.html",a:"controls"},"17.1":{t:"Configuration",p:` + + +Property +Type +Description + + + + +disable +Boolean +Whether to di ...`,l:"en/component/controls.html#configuration",a:"configuration"},"17.2":{t:"Creation",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/controls.html#creation",a:"creation"},"17.3":{t:"Adding",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/controls.html#adding",a:"adding"},"17.4":{t:"Removal",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/controls.html#removal",a:"removal"},"17.5":{t:"Updating",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/controls.html#updating",a:"updating"},"18.0":{t:"# Layers",p:"",l:"en/component/layers.html",a:"layers"},"18.1":{t:"Configuration",p:` + + +Property +Type +Description + + + + +disable +Boolean +Whether to di ...`,l:"en/component/layers.html#configuration",a:"configuration"},"18.2":{t:"Creation",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/layers.html#creation",a:"creation"},"18.3":{t:"Addition",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/layers.html#addition",a:"addition"},"18.4":{t:"Removal",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/layers.html#removal",a:"removal"},"18.5":{t:"Update",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/layers.html#update",a:"update"},"19.0":{t:"# Settings Panel",p:"",l:"en/component/setting.html",a:"settings-panel"},"19.1":{t:"Built-in",p:"First, you need to open the settings panel. It comes with four ...",l:"en/component/setting.html#built-in",a:"built-in"},"19.2":{t:"Create - Button",p:` + + +Property +Type +Description + + + + +html +String, Element +The DOM ...`,l:"en/component/setting.html#create-button",a:"create-button"},"19.3":{t:"Create - Selection List",p:` + + +Property +Type +Description + + + + +html +String, Element +The DOM ...`,l:"en/component/setting.html#create-selection-list",a:"create-selection-list"},"19.4":{t:"Create - Nested List",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/setting.html#create-nested-list",a:"create-nested-list"},"19.5":{t:"Create - Toggle Button",p:` + + +Property +Type +Description + + + + +html +String, Element +DOM elem ...`,l:"en/component/setting.html#create-toggle-button",a:"create-toggle-button"},"19.6":{t:"Create - Range Slider",p:` + + +Property +Type +Description + + + + +html +String, Element +DOM elem ...`,l:"en/component/setting.html#create-range-slider",a:"create-range-slider"},"19.7":{t:"Add",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/setting.html#add",a:"add"},"19.8":{t:"Remove",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/setting.html#remove",a:"remove"},"19.9":{t:"Update",p:"<div className="run-code">▶ Run Code</div&g ...",l:"en/component/setting.html#update",a:"update"},"20.0":{t:"# Installation and Usage",p:"",l:"en/index.html",a:"installation-and-usage"},"20.1":{t:"Installation",p:`::: code-group +npm install artplayer + +yarn add artplayer + +pnpm ...`,l:"en/index.html#installation",a:"installation"},"20.2":{t:"`CDN`",p:`::: code-group +https://cdn.jsdelivr.net/npm/artplayer/dist/art ...`,l:"en/index.html#cdn",a:"cdn"},"20.3":{t:"Usage",p:`::: code-group +<html> + <head> + <title ...`,l:"en/index.html#usage",a:"usage"},"20.4":{t:"`Vue.js`",p:`::: code-group +<template> + <div ref="$container ...`,l:"en/index.html#vue-js",a:"vue-js"},"20.5":{t:"`React.js`",p:`::: code-group +import Artplayer from 'artplayer' +import { useE ...`,l:"en/index.html#react-js",a:"react-js"},"20.6":{t:"TypeScript",p:"The artplayer.d.ts file is automatically imported when you imp ...",l:"en/index.html#typescript",a:"typescript"},"20.7":{t:"Vue.js",p:` + +`,l:"en/index.html#vue-js",a:"vue-js"},"20.8":{t:"React.js",p:`import Artplayer from 'artplayer'; +const art = useRef<Artpl ...`,l:"en/index.html#react-js",a:"react-js"},"20.9":{t:"Option",p:`You can also use the type for the options. +import Artplayer, { ...`,l:"en/index.html#option",a:"option"},"20.10":{t:"JavaScript",p:"Sometimes your js files may lose TypeScript type hints. In suc ...",l:"en/index.html#javascript",a:"javascript"},"20.11":{t:"Legacy Browsers",p:"The production build artplayer.js only supports the latest maj ...",l:"en/index.html#legacy-browsers",a:"legacy-browsers"},"20.12":{t:"ECMAScript Module",p:`::: tip ESM Demo: +https://artplayer.org/esm.html +::: +Starting ...`,l:"en/index.html#ecmascript-module",a:"ecmascript-module"},"20.13":{t:"Custom userAgent",p:"Currently, the detection of whether a device is mobile is not ...",l:"en/index.html#custom-useragent",a:"custom-useragent"},"21.0":{t:"# Language Settings",p:`::: danger +Due to the increasing number of bundled multilingua ...`,l:"en/start/i18n.html",a:"language-settings"},"21.1":{t:"Default Languages",p:"The default languages are: en, zh-cn. No manual import is requ ...",l:"en/start/i18n.html#default-languages",a:"default-languages"},"21.2":{t:"Importing Languages",p:"Language files before bundling are located at: artplayer/src/i ...",l:"en/start/i18n.html#importing-languages",a:"importing-languages"},"21.3":{t:"Adding a New Language",p:`var art = new Artplayer({ + container: '.artplayer-app', + ...`,l:"en/start/i18n.html#adding-a-new-language",a:"adding-a-new-language"},"21.4":{t:"Modifying a Language",p:`import zhTw from 'artplayer/i18n/zh-tw'; + +var art = new Artpla ...`,l:"en/start/i18n.html#modifying-a-language",a:"modifying-a-language"},"22.0":{t:"# Basic Options",p:"",l:"en/start/option.html",a:"basic-options"},"22.1":{t:"`container`",p:` +Type: String, Element +Default: #artplayer + +The DOM container ...`,l:"en/start/option.html#container",a:"container"},"22.2":{t:"`url`",p:` +Type: String +Default: '' + +The video source URL. +<div class ...`,l:"en/start/option.html#url",a:"url"},"22.3":{t:"`id`",p:` +Type: String +Default: '' + +The unique identifier for the playe ...`,l:"en/start/option.html#id",a:"id"},"22.4":{t:"`onReady`",p:` +Type: Function +Default: undefined + +The constructor accepts a ...`,l:"en/start/option.html#onready",a:"onready"},"22.5":{t:"`poster`",p:` +Type: String +Default: '' + +The video poster image, which only ...`,l:"en/start/option.html#poster",a:"poster"},"22.6":{t:"`theme`",p:` +Type: String +Default: #f00 + +The player's theme color, current ...`,l:"en/start/option.html#theme",a:"theme"},"22.7":{t:"`volume`",p:` +Type: Number +Default: 0.7 + +The player's default volume. +<d ...`,l:"en/start/option.html#volume",a:"volume"},"22.8":{t:"`isLive`",p:` +Type: Boolean +Default: false + +Enable live streaming mode. Thi ...`,l:"en/start/option.html#islive",a:"islive"},"22.9":{t:"`muted`",p:` +Type: Boolean +Default: false + +Whether to start muted by defau ...`,l:"en/start/option.html#muted",a:"muted"},"22.10":{t:"`autoplay`",p:` +Type: Boolean +Default: false + +Whether to autoplay. +<div cl ...`,l:"en/start/option.html#autoplay",a:"autoplay"},"22.11":{t:"`autoSize`",p:` +Type: Boolean +Default: false + +By default, the player's dimens ...`,l:"en/start/option.html#autosize",a:"autosize"},"22.12":{t:"`autoMini`",p:` +Type: Boolean +Default: false + +Automatically enters Mini Playe ...`,l:"en/start/option.html#automini",a:"automini"},"22.13":{t:"`loop`",p:` +Type: Boolean +Default: false + +Whether to loop playback. +<d ...`,l:"en/start/option.html#loop",a:"loop"},"22.14":{t:"`flip`",p:` +Type: Boolean +Default: false + +Whether to display the video fl ...`,l:"en/start/option.html#flip",a:"flip"},"22.15":{t:"`playbackRate`",p:` +Type: Boolean +Default: false + +Whether to display the video pl ...`,l:"en/start/option.html#playbackrate",a:"playbackrate"},"22.16":{t:"`aspectRatio`",p:` +Type: Boolean +Default: false + +Whether to display the video as ...`,l:"en/start/option.html#aspectratio",a:"aspectratio"},"22.17":{t:"`screenshot`",p:` +Type: Boolean +Default: false + +Whether to display the Screensh ...`,l:"en/start/option.html#screenshot",a:"screenshot"},"22.18":{t:"`setting`",p:` +Type: Boolean +Default: false + +Whether to display the toggle b ...`,l:"en/start/option.html#setting",a:"setting"},"22.19":{t:"`hotkey`",p:` +Type: Boolean +Default: true + +Whether to use hotkeys. +<div ...`,l:"en/start/option.html#hotkey",a:"hotkey"},"22.20":{t:"`pip`",p:` +Type: Boolean +Default: false + +Whether to display the Picture- ...`,l:"en/start/option.html#pip",a:"pip"},"22.21":{t:"`mutex`",p:` +Type: Boolean +Default: true + +If multiple players exist on the ...`,l:"en/start/option.html#mutex",a:"mutex"},"22.22":{t:"`backdrop`",p:` +Type: Boolean +Default: true + +Whether to enable the backdrop b ...`,l:"en/start/option.html#backdrop",a:"backdrop"},"22.23":{t:"`fullscreen`",p:` +Type: Boolean +Default: false + +Whether to display the player W ...`,l:"en/start/option.html#fullscreen",a:"fullscreen"},"22.24":{t:"`fullscreenWeb`",p:` +Type: Boolean +Default: false + +Whether to display the player W ...`,l:"en/start/option.html#fullscreenweb",a:"fullscreenweb"},"22.25":{t:"`subtitleOffset`",p:` +Type: Boolean +Default: false + +Subtitle time offset, ranging f ...`,l:"en/start/option.html#subtitleoffset",a:"subtitleoffset"},"22.26":{t:"`miniProgressBar`",p:` +Type: Boolean +Default: false + +A mini progress bar that only a ...`,l:"en/start/option.html#miniprogressbar",a:"miniprogressbar"},"22.27":{t:"`useSSR`",p:` +Type: Boolean +Default: false + +Whether to use SSR (Server-Side ...`,l:"en/start/option.html#usessr",a:"usessr"},"22.28":{t:"`playsInline`",p:` +Type: Boolean +Default: true + +Whether to use playsInline mode ...`,l:"en/start/option.html#playsinline",a:"playsinline"},"22.29":{t:"`layers`",p:` +Type: Array +Default: [] + +Initialize custom layers. +<div cl ...`,l:"en/start/option.html#layers",a:"layers"},"22.30":{t:"`settings`",p:` +Type: Array +Default: [] + +Initialize custom settings panels. +& ...`,l:"en/start/option.html#settings",a:"settings"},"22.31":{t:"`contextmenu`",p:` +Type: Array +Default: [] + +Initialize custom context menus. +< ...`,l:"en/start/option.html#contextmenu",a:"contextmenu"},"22.32":{t:"`controls`",p:` +Type: Array +Default: [] + +Initialize custom bottom control bar ...`,l:"en/start/option.html#controls",a:"controls"},"22.33":{t:"`quality`",p:` +Type: Array +Default: [] + +Whether to display the Quality Selec ...`,l:"en/start/option.html#quality",a:"quality"},"22.34":{t:"`highlight`",p:` +Type: Array +Default: [] + +Display Highlight Information on the ...`,l:"en/start/option.html#highlight",a:"highlight"},"22.35":{t:"`plugins`",p:` +Type: Array +Default: [] + +Initialize custom plugins. +<div c ...`,l:"en/start/option.html#plugins",a:"plugins"},"22.36":{t:"`thumbnails`",p:` +Type: Object +Default: {} + +Set Preview Thumbnails on the progr ...`,l:"en/start/option.html#thumbnails",a:"thumbnails"},"22.37":{t:"`subtitle`",p:` +Type: Object +Default: {} + +Set video subtitles. Supported subt ...`,l:"en/start/option.html#subtitle",a:"subtitle"},"22.38":{t:"`moreVideoAttr`",p:` +Type: Object +Default: {'controls': false, 'preload': 'metadat ...`,l:"en/start/option.html#morevideoattr",a:"morevideoattr"},"22.39":{t:"`icons`",p:` +Type: Object +Default: {} + +Used to replace default icons. Supp ...`,l:"en/start/option.html#icons",a:"icons"},"22.40":{t:"`type`",p:` +Type: String +Default: '' + +Used to specify the video format. I ...`,l:"en/start/option.html#type",a:"type"},"22.41":{t:"`customType`",p:` +Type: Object +Default: {} + +Matches based on the video's type a ...`,l:"en/start/option.html#customtype",a:"customtype"},"22.42":{t:"`lang`",p:` +Type: String +Default: navigator.language.toLowerCase() + +The d ...`,l:"en/start/option.html#lang",a:"lang"},"22.43":{t:"`i18n`",p:` +Type: Object +Default: {} + +Custom i18n configuration. This con ...`,l:"en/start/option.html#i18n",a:"i18n"},"22.44":{t:"`lock`",p:` +Type: Boolean +Default: false + +Whether to display a lock butto ...`,l:"en/start/option.html#lock",a:"lock"},"22.45":{t:"`gesture`",p:` +Type: Boolean +Default: true + +Whether to enable gesture events ...`,l:"en/start/option.html#gesture",a:"gesture"},"22.46":{t:"`fastForward`",p:` +Type: Boolean +Default: false + +Whether to add a long-press vid ...`,l:"en/start/option.html#fastforward",a:"fastforward"},"22.47":{t:"`autoPlayback`",p:` +Type: Boolean +Default: false + +Whether to use the automatic pl ...`,l:"en/start/option.html#autoplayback",a:"autoplayback"},"22.48":{t:"`autoOrientation`",p:` +Type: Boolean +Default: false + +Whether to rotate the player in ...`,l:"en/start/option.html#autoorientation",a:"autoorientation"},"22.49":{t:"`airplay`",p:` +Type: Boolean +Default: false + +Whether to display the airplay ...`,l:"en/start/option.html#airplay",a:"airplay"},"22.50":{t:"`cssVar`",p:` +Type: Object +Default: {} + +Used to modify the built-in CSS var ...`,l:"en/start/option.html#cssvar",a:"cssvar"},"22.51":{t:"`proxy`",p:` +Type: function +Default: undefined + +The function can return a ...`,l:"en/start/option.html#proxy",a:"proxy"},"23.0":{t:"# 安装使用",p:"",l:"index.html",a:"安装使用"},"23.1":{t:"安装",p:`::: code-group +npm install artplayer + +yarn add artplayer + +pnpm ...`,l:"index.html#安装",a:"安装"},"23.2":{t:"`CDN`",p:`::: code-group +https://cdn.jsdelivr.net/npm/artplayer/dist/art ...`,l:"index.html#cdn",a:"cdn"},"23.3":{t:"使用",p:`::: code-group +<html> + <head> + <title ...`,l:"index.html#使用",a:"使用"},"23.4":{t:"`Vue.js`",p:`::: code-group +<template> + <div ref="$container ...`,l:"index.html#vue-js",a:"vue-js"},"23.5":{t:"`React.js`",p:`::: code-group +import Artplayer from 'artplayer' +import { useE ...`,l:"index.html#react-js",a:"react-js"},"23.6":{t:"TypeScript",p:`导入 Artplayer 时会自动导入的 artplayer.d.ts +`,l:"index.html#typescript",a:"typescript"},"23.7":{t:"Vue.js",p:` + +`,l:"index.html#vue-js",a:"vue-js"},"23.8":{t:"React.js",p:`import Artplayer from 'artplayer'; +const art = useRef<Artpl ...`,l:"index.html#react-js",a:"react-js"},"23.9":{t:"Option",p:`你也可以使用选项的类型 +import Artplayer, { type Option } from 'artplayer' ...`,l:"index.html#option",a:"option"},"23.10":{t:"JavaScript",p:`有时你的 js 文件会丢失 TypeScript 的类型提示,这时候你可以手动导入类型 +变量: +/** + * @type { ...`,l:"index.html#javascript",a:"javascript"},"23.11":{t:"古老的浏览器",p:`生产构建的 artplayer.js 只兼容最新一个主版本的 Chrome:last 1 Chrome version +对于 ...`,l:"index.html#古老的浏览器",a:"古老的浏览器"},"23.12":{t:"ECMAScript Module",p:`::: tip ESM Demo: +https://artplayer.org/esm.html +::: +从 5.2.6 开 ...`,l:"index.html#ecmascript-module",a:"ecmascript-module"},"23.13":{t:"自定义 userAgent",p:"目前对于是否移动设备的判断并不准确,有时候希望通过改变 userAgent 来调整播放器的UI, 所以在 5.2.4 开始新 ...",l:"index.html#自定义-useragent",a:"自定义-useragent"},"24.0":{t:"# 弹幕库",p:"",l:"plugin/danmuku.html",a:"弹幕库"},"24.1":{t:"演示",p:`👉 查看完整演示 +`,l:"plugin/danmuku.html#演示",a:"演示"},"24.2":{t:"安装",p:`::: code-group +npm install artplayer-plugin-danmuku + +yarn add ...`,l:"plugin/danmuku.html#安装",a:"安装"},"24.3":{t:"CDN",p:`::: code-group +https://cdn.jsdelivr.net/npm/artplayer-plugin-d ...`,l:"plugin/danmuku.html#cdn",a:"cdn"},"24.4":{t:"弹幕结构",p:`每一个弹幕是一个对象,多个弹幕组成的数组就是弹幕库,通常只需要text就可以发送一个弹幕,其余都是非必要参数 +{ + t ...`,l:"plugin/danmuku.html#弹幕结构",a:"弹幕结构"},"24.5":{t:"全部选项",p:`只有danmuku是必须的参数,其余都是非必填 +{ + danmuku: [], // 弹幕数据 + speed: ...`,l:"plugin/danmuku.html#全部选项",a:"全部选项"},"24.6":{t:"生命周期",p:`来自用户输入的弹幕: +beforeEmit -> filter -> beforeVisible -> a ...`,l:"plugin/danmuku.html#生命周期",a:"生命周期"},"24.7":{t:"使用弹幕数组",p:"<div className="run-code" data-libs="./uncom ...",l:"plugin/danmuku.html#使用弹幕数组",a:"使用弹幕数组"},"24.8":{t:"使用弹幕 XML",p:`弹幕 XML 文件,和 Bilibili 网站的弹幕格式一致 +<div className="run-cod ...`,l:"plugin/danmuku.html#使用弹幕-xml",a:"使用弹幕-xml"},"24.9":{t:"使用异步返回",p:"<div className="run-code" data-libs="./uncom ...",l:"plugin/danmuku.html#使用异步返回",a:"使用异步返回"},"24.10":{t:"`hide/show`",p:`通过方法 hide 和 show 进行隐藏或者显示弹幕 +<div className="run-code&q ...`,l:"plugin/danmuku.html#hide-show",a:"hide-show"},"24.11":{t:"`isHide`",p:`通过属性 isHide 判断当前弹幕是隐藏或者显示 +<div className="run-code&quo ...`,l:"plugin/danmuku.html#ishide",a:"ishide"},"24.12":{t:"`emit`",p:`通过方法 emit 发送一条实时弹幕 +<div className="run-code" data ...`,l:"plugin/danmuku.html#emit",a:"emit"},"24.13":{t:"`config`",p:`通过方法 config 实时改变弹幕配置 +<div className="run-code" da ...`,l:"plugin/danmuku.html#config",a:"config"},"24.14":{t:"`load`",p:`通过 load 方法可以重载弹幕库,或者切换新弹幕库,或者追加新的弹幕库 +<div className="r ...`,l:"plugin/danmuku.html#load",a:"load"},"24.15":{t:"`reset`",p:`用于清空当前显示的弹幕 +<div className="run-code" data-libs=& ...`,l:"plugin/danmuku.html#reset",a:"reset"},"24.16":{t:"`mount`",p:`在初始化弹幕插件的时候,是可以指定弹幕发射器的挂载位置的,默认是挂载在控制栏的中部,你也可以把它挂载在播放器以外的地方。 +当 ...`,l:"plugin/danmuku.html#mount",a:"mount"},"24.17":{t:"`option`",p:`用于获取当前弹幕配置 +<div className="run-code" data-libs=&q ...`,l:"plugin/danmuku.html#option",a:"option"},"24.18":{t:"事件",p:"<div className="run-code" data-libs="./uncom ...",l:"plugin/danmuku.html#事件",a:"事件"},"25.0":{t:"# 语言设置",p:`::: danger +鉴于捆绑的多国语言越来越多, 从 5.1.0 版本开始, artplayer.js 核心代码除了包含 ...`,l:"start/i18n.html",a:"语言设置"},"25.1":{t:"默认语言",p:`默认语言有: en, zh-cn, 无需手动导入 +var art = new Artplayer({ + contain ...`,l:"start/i18n.html#默认语言",a:"默认语言"},"25.2":{t:"导入语言",p:`打包前的语言文件存放于: artplayer/src/i18n/*.js, 欢迎来添加你的语言 +打包后的语言文件存放于: a ...`,l:"start/i18n.html#导入语言",a:"导入语言"},"25.3":{t:"新增语言",p:`var art = new Artplayer({ + container: '.artplayer-app', + ...`,l:"start/i18n.html#新增语言",a:"新增语言"},"25.4":{t:"修改语言",p:`import zhTw from 'artplayer/i18n/zh-tw'; + +var art = new Artpla ...`,l:"start/i18n.html#修改语言",a:"修改语言"},"26.0":{t:"# 基础选项",p:"",l:"start/option.html",a:"基础选项"},"26.1":{t:"`container`",p:` +Type: String, Element +Default: #artplayer + +播放器挂载的 DOM 容器 +< ...`,l:"start/option.html#container",a:"container"},"26.2":{t:"`url`",p:` +Type: String +Default: '' + +视频源地址 +<div className="run-c ...`,l:"start/option.html#url",a:"url"},"26.3":{t:"`id`",p:` +Type: String +Default: '' + +播放器的唯一标识,目前只用于记忆播放 autoplayback +< ...`,l:"start/option.html#id",a:"id"},"26.4":{t:"`onReady`",p:` +Type: Function +Default: undefined + +构造函数接受一个函数作为第二个参数,播放器初始化成功 ...`,l:"start/option.html#onready",a:"onready"},"26.5":{t:"`poster`",p:` +Type: String +Default: '' + +视频的海报,只会出现在播放器初始化且未播放的状态下 +<div c ...`,l:"start/option.html#poster",a:"poster"},"26.6":{t:"`theme`",p:` +Type: String +Default: #f00 + +播放器主题颜色,目前用于 进度条 和 高亮元素 上 +<div ...`,l:"start/option.html#theme",a:"theme"},"26.7":{t:"`volume`",p:` +Type: Number +Default: 0.7 + +播放器的默认音量 +<div className="r ...`,l:"start/option.html#volume",a:"volume"},"26.8":{t:"`isLive`",p:` +Type: Boolean +Default: false + +使用直播模式,会隐藏进度条和播放时间 +<div clas ...`,l:"start/option.html#islive",a:"islive"},"26.9":{t:"`muted`",p:` +Type: Boolean +Default: false + +是否默认静音 +<div className=" ...`,l:"start/option.html#muted",a:"muted"},"26.10":{t:"`autoplay`",p:` +Type: Boolean +Default: false + +是否自动播放 +<div className=" ...`,l:"start/option.html#autoplay",a:"autoplay"},"26.11":{t:"`autoSize`",p:` +Type: Boolean +Default: false + +播放器的尺寸默认会填充整个 container 容器尺寸,所以 ...`,l:"start/option.html#autosize",a:"autosize"},"26.12":{t:"`autoMini`",p:` +Type: Boolean +Default: false + +当播放器滚动到浏览器视口以外时,自动进入 迷你播放 模式 +&l ...`,l:"start/option.html#automini",a:"automini"},"26.13":{t:"`loop`",p:` +Type: Boolean +Default: false + +是否循环播放 +<div className=" ...`,l:"start/option.html#loop",a:"loop"},"26.14":{t:"`flip`",p:` +Type: Boolean +Default: false + +是否显示视频翻转功能,目前只出现在 设置面板 和 右键菜单 里 ...`,l:"start/option.html#flip",a:"flip"},"26.15":{t:"`playbackRate`",p:` +Type: Boolean +Default: false + +是否显示视频播放速度功能,会出现在 设置面板 和 右键菜单 里 ...`,l:"start/option.html#playbackrate",a:"playbackrate"},"26.16":{t:"`aspectRatio`",p:` +Type: Boolean +Default: false + +是否显示视频长宽比功能,会出现在 设置面板 和 右键菜单 里 + ...`,l:"start/option.html#aspectratio",a:"aspectratio"},"26.17":{t:"`screenshot`",p:` +Type: Boolean +Default: false + +是否在底部控制栏里显示 视频截图 功能 +<div cla ...`,l:"start/option.html#screenshot",a:"screenshot"},"26.18":{t:"`setting`",p:` +Type: Boolean +Default: false + +是否在底部控制栏里显示 设置面板 的开关按钮 +<div ...`,l:"start/option.html#setting",a:"setting"},"26.19":{t:"`hotkey`",p:` +Type: Boolean +Default: true + +是否使用快捷键 +<div className=" ...`,l:"start/option.html#hotkey",a:"hotkey"},"26.20":{t:"`pip`",p:` +Type: Boolean +Default: false + +是否在底部控制栏里显示 画中画 的开关按钮 +<div c ...`,l:"start/option.html#pip",a:"pip"},"26.21":{t:"`mutex`",p:` +Type: Boolean +Default: true + +假如页面里同时存在多个播放器,是否只能让一个播放器播放 +< ...`,l:"start/option.html#mutex",a:"mutex"},"26.22":{t:"`backdrop`",p:` +Type: Boolean +Default: true + +是否开启播放器 UI 的背景虚化效果。开启后,设置面板、右键菜单 ...`,l:"start/option.html#backdrop",a:"backdrop"},"26.23":{t:"`fullscreen`",p:` +Type: Boolean +Default: false + +是否在底部控制栏里显示播放器 窗口全屏 按钮 +<div ...`,l:"start/option.html#fullscreen",a:"fullscreen"},"26.24":{t:"`fullscreenWeb`",p:` +Type: Boolean +Default: false + +是否在底部控制栏里显示播放器 网页全屏 按钮 +<div ...`,l:"start/option.html#fullscreenweb",a:"fullscreenweb"},"26.25":{t:"`subtitleOffset`",p:` +Type: Boolean +Default: false + +字幕时间偏移,范围在 [-5s, 5s],出现在 设置面板 里 ...`,l:"start/option.html#subtitleoffset",a:"subtitleoffset"},"26.26":{t:"`miniProgressBar`",p:` +Type: Boolean +Default: false + +迷你进度条,只在播放器失去焦点后且正在播放时出现 +<di ...`,l:"start/option.html#miniprogressbar",a:"miniprogressbar"},"26.27":{t:"`useSSR`",p:` +Type: Boolean +Default: false + +是否使用 SSR 挂载模式,假如你希望在播放器挂载前,就提前渲 ...`,l:"start/option.html#usessr",a:"usessr"},"26.28":{t:"`playsInline`",p:` +Type: Boolean +Default: true + +在移动端是否使用 playsInline 模式 +<div ...`,l:"start/option.html#playsinline",a:"playsinline"},"26.29":{t:"`layers`",p:` +Type: Array +Default: [] + +初始化自定义的 层 +<div className="ru ...`,l:"start/option.html#layers",a:"layers"},"26.30":{t:"`settings`",p:` +Type: Array +Default: [] + +初始化自定义的 设置面板 +<div className=" ...`,l:"start/option.html#settings",a:"settings"},"26.31":{t:"`contextmenu`",p:` +Type: Array +Default: [] + +初始化自定义的 右键菜单 +<div className=" ...`,l:"start/option.html#contextmenu",a:"contextmenu"},"26.32":{t:"`controls`",p:` +Type: Array +Default: [] + +初始化自定义的底部 控制栏 +<div className=&quo ...`,l:"start/option.html#controls",a:"controls"},"26.33":{t:"`quality`",p:` +Type: Array +Default: [] + +是否在底部控制栏里显示 画质选择 列表 + + + +属性 +类型 +描述 + + + + + ...`,l:"start/option.html#quality",a:"quality"},"26.34":{t:"`highlight`",p:` +Type: Array +Default: [] + +在进度条上显示 高亮信息 + + + +属性 +类型 +描述 + + + + +time +Nu ...`,l:"start/option.html#highlight",a:"highlight"},"26.35":{t:"`plugins`",p:` +Type: Array +Default: [] + +初始化自定义的 插件 +<div className="r ...`,l:"start/option.html#plugins",a:"plugins"},"26.36":{t:"`thumbnails`",p:` +Type: Object +Default: {} + +在进度条上设置 预览图 + + + +属性 +类型 +描述 + + + + +url +Str ...`,l:"start/option.html#thumbnails",a:"thumbnails"},"26.37":{t:"`subtitle`",p:` +Type: Object +Default: {} + +设置视频的字幕,支持字幕格式:vtt, srt, ass + + + +属性 + ...`,l:"start/option.html#subtitle",a:"subtitle"},"26.38":{t:"`moreVideoAttr`",p:` +Type: Object +Default: {'controls': false, 'preload': 'metadat ...`,l:"start/option.html#morevideoattr",a:"morevideoattr"},"26.39":{t:"`icons`",p:` +Type: Object +Default: {} + +用于替换默认图标,支持 Html 字符串和 HTMLElement +& ...`,l:"start/option.html#icons",a:"icons"},"26.40":{t:"`type`",p:` +Type: String +Default: '' + +用于指明视频的格式,需要配合 customType 一起使用,默认视频 ...`,l:"start/option.html#type",a:"type"},"26.41":{t:"`customType`",p:` +Type: Object +Default: {} + +通过视频的 type 进行匹配,把视频解码权交给第三方程序进行处理,处 ...`,l:"start/option.html#customtype",a:"customtype"},"26.42":{t:"`lang`",p:` +Type: String +Default: navigator.language.toLowerCase() + +默认显示语 ...`,l:"start/option.html#lang",a:"lang"},"26.43":{t:"`i18n`",p:` +Type: Object +Default: {} + +自定义 i18n 配置,该配置会和自带的 i18n 进行深度合并 +新增 ...`,l:"start/option.html#i18n",a:"i18n"},"26.44":{t:"`lock`",p:` +Type: Boolean +Default: false + +是否在移动端显示一个 锁定按钮 ,用于隐藏底部 控制栏 +< ...`,l:"start/option.html#lock",a:"lock"},"26.45":{t:"`gesture`",p:` +Type: Boolean +Default: true + +是否在移动端启用视频元素上的手势事件 +<div class ...`,l:"start/option.html#gesture",a:"gesture"},"26.46":{t:"`fastForward`",p:` +Type: Boolean +Default: false + +是否在移动端添加长按视频快进功能 +<div classN ...`,l:"start/option.html#fastforward",a:"fastforward"},"26.47":{t:"`autoPlayback`",p:` +Type: Boolean +Default: false + +是否使用自动 回放功能 +<div className=& ...`,l:"start/option.html#autoplayback",a:"autoplayback"},"26.48":{t:"`autoOrientation`",p:` +Type: Boolean +Default: false + +是否在移动端的网页全屏时,根据视频尺寸和视口尺寸,旋转播放器 + ...`,l:"start/option.html#autoorientation",a:"autoorientation"},"26.49":{t:"`airplay`",p:` +Type: Boolean +Default: false + +是否显示 airplay 按钮,当前只有部分浏览器支持该功能 + ...`,l:"start/option.html#airplay",a:"airplay"},"26.50":{t:"`cssVar`",p:` +Type: Object +Default: {} + +用于改变内置的css变量 +<div className=&quo ...`,l:"start/option.html#cssvar",a:"cssvar"},"26.51":{t:"`proxy`",p:` +Type: function +Default: undefined + +函数可以返回一个第三方的 HTMLCanvasEle ...`,l:"start/option.html#proxy",a:"proxy"}},n={previewLength:62,buttonLabel:"Search",placeholder:"Search docs",allow:[],ignore:[]},a={INDEX_DATA:e,PREVIEW_LOOKUP:t,Options:n};export{a as default}; diff --git a/docs/document/assets/en_index.md.DFeypQS9.js b/docs/document/assets/en_index.md.Clwh28HI.js similarity index 91% rename from docs/document/assets/en_index.md.DFeypQS9.js rename to docs/document/assets/en_index.md.Clwh28HI.js index 61c00e6d4..d23937d5f 100644 --- a/docs/document/assets/en_index.md.DFeypQS9.js +++ b/docs/document/assets/en_index.md.Clwh28HI.js @@ -1,4 +1,4 @@ -import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g=JSON.parse('{"title":"Installation and Usage","description":"","frontmatter":{},"headers":[],"relativePath":"en/index.md","filePath":"en/index.md","lastUpdated":1772946913000}'),p={name:"en/index.md"};function t(e,s,h,k,r,E){return n(),a("div",null,s[0]||(s[0]=[l(`

Installation and Usage ​

Installation ​

bash
npm install artplayer
bash
yarn add artplayer
bash
pnpm add artplayer
html
<script src="path/to/artplayer.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
bash
https://unpkg.com/artplayer/dist/artplayer.js

Usage ​

html
<html>
+import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g=JSON.parse('{"title":"Installation and Usage","description":"","frontmatter":{},"headers":[],"relativePath":"en/index.md","filePath":"en/index.md","lastUpdated":1775270107000}'),p={name:"en/index.md"};function t(e,s,h,k,r,E){return n(),a("div",null,s[0]||(s[0]=[l(`

Installation and Usage ​

Installation ​

bash
npm install artplayer
bash
yarn add artplayer
bash
pnpm add artplayer
bash
bun add artplayer
html
<script src="path/to/artplayer.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
bash
https://unpkg.com/artplayer/dist/artplayer.js

Usage ​

html
<html>
     <head>
         <title>ArtPlayer Demo</title>
         <meta charset="UTF-8" />
@@ -19,7 +19,7 @@ import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g
           });
         </script>
     </body>
-</html>

Note

The player's dimensions depend on the dimensions of its container. Therefore, your container must have defined dimensions.

See more usage examples at the following link

/example

Vue.js ​

vue
<template>
+</html>

Note

The player's dimensions depend on the dimensions of its container. Therefore, your container must have defined dimensions.

See more usage examples at the following link

/example

Vue.js ​

vue
<template>
   <div ref="$container" />
 </template>
 
@@ -71,7 +71,7 @@ import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g
 function getInstance(art) {
   console.log(art)
 }
-</script>

Artplayer is not reactive:

Directly modifying the option in Vue.js will not update the player.

React.js ​

jsx
import Artplayer from 'artplayer'
+</script>

Artplayer is not reactive:

Directly modifying the option in Vue.js will not update the player.

React.js ​

jsx
import Artplayer from 'artplayer'
 import { useEffect, useRef } from 'react'
 
 export default function Player({ option, getInstance, ...rest }) {
@@ -154,7 +154,7 @@ import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g
 
 option.volume = 0.5;
 
-const art8 = new Artplayer(option);

Legacy Browsers ​

The production build artplayer.js only supports the latest major version of Chrome: last 1 Chrome version.

For legacy browsers, you can use the artplayer.legacy.js file, which is compatible down to: IE 11.

js
import Artplayer from 'artplayer/legacy'
bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
bash
https://unpkg.com/artplayer/dist/artplayer.legacy.js

If you need to support even older browsers, modify the following configuration and build it yourself:

Build configuration: scripts/build.js

Reference documentation: browserslist

ECMAScript Module ​

Starting from version 5.2.6, artplayer and all plugins also provide an ESM version in mjs format, such as:

  • artplayer/dist/artplayer.mjs
  • artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs
html
<!DOCTYPE html>
+const art8 = new Artplayer(option);

Legacy Browsers ​

The production build artplayer.js only supports the latest major version of Chrome: last 1 Chrome version.

For legacy browsers, you can use the artplayer.legacy.js file, which is compatible down to: IE 11.

js
import Artplayer from 'artplayer/legacy'
bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
bash
https://unpkg.com/artplayer/dist/artplayer.legacy.js

If you need to support even older browsers, modify the following configuration and build it yourself:

Build configuration: scripts/build.js

Reference documentation: browserslist

ECMAScript Module ​

Starting from version 5.2.6, artplayer and all plugins also provide an ESM version in mjs format, such as:

  • artplayer/dist/artplayer.mjs
  • artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs
html
<!DOCTYPE html>
 <html lang="en">
 
 <head>
diff --git a/docs/document/assets/en_index.md.DFeypQS9.lean.js b/docs/document/assets/en_index.md.Clwh28HI.lean.js
similarity index 84%
rename from docs/document/assets/en_index.md.DFeypQS9.lean.js
rename to docs/document/assets/en_index.md.Clwh28HI.lean.js
index 2c46cdd73..bd28e4607 100644
--- a/docs/document/assets/en_index.md.DFeypQS9.lean.js
+++ b/docs/document/assets/en_index.md.Clwh28HI.lean.js
@@ -1 +1 @@
-import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g=JSON.parse('{"title":"Installation and Usage","description":"","frontmatter":{},"headers":[],"relativePath":"en/index.md","filePath":"en/index.md","lastUpdated":1772946913000}'),p={name:"en/index.md"};function t(e,s,h,k,r,E){return n(),a("div",null,s[0]||(s[0]=[l("",50)]))}const c=i(p,[["render",t]]);export{g as __pageData,c as default};
+import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g=JSON.parse('{"title":"Installation and Usage","description":"","frontmatter":{},"headers":[],"relativePath":"en/index.md","filePath":"en/index.md","lastUpdated":1775270107000}'),p={name:"en/index.md"};function t(e,s,h,k,r,E){return n(),a("div",null,s[0]||(s[0]=[l("",50)]))}const c=i(p,[["render",t]]);export{g as __pageData,c as default};
diff --git a/docs/document/assets/en_start_i18n.md.Cg_MHRXn.js b/docs/document/assets/en_start_i18n.md.BLwUSSfJ.js
similarity index 98%
rename from docs/document/assets/en_start_i18n.md.Cg_MHRXn.js
rename to docs/document/assets/en_start_i18n.md.BLwUSSfJ.js
index 720a91acf..beeaeecdf 100644
--- a/docs/document/assets/en_start_i18n.md.Cg_MHRXn.js
+++ b/docs/document/assets/en_start_i18n.md.BLwUSSfJ.js
@@ -2,7 +2,7 @@ import{_ as a,c as i,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g
     container: '.artplayer-app',
     url: '/assets/sample/video.mp4',
     lang: 'zh-cn', // or 'en'
-});

Importing Languages ​

Language files before bundling are located at: artplayer/src/i18n/*.js. Contributions for new languages are welcome.

Bundled language files are located at: artplayer/dist/i18n/*.js

js
import id from 'artplayer/i18n/id';
+});

Importing Languages ​

Language files before bundling are located at: artplayer/src/i18n/*.js. Contributions for new languages are welcome.

Bundled language files are located at: artplayer/dist/i18n/*.js

js
import id from 'artplayer/i18n/id';
 import zhTw from 'artplayer/i18n/zh-tw';
 
 var art = new Artplayer({
diff --git a/docs/document/assets/en_start_i18n.md.Cg_MHRXn.lean.js b/docs/document/assets/en_start_i18n.md.BLwUSSfJ.lean.js
similarity index 100%
rename from docs/document/assets/en_start_i18n.md.Cg_MHRXn.lean.js
rename to docs/document/assets/en_start_i18n.md.BLwUSSfJ.lean.js
diff --git a/docs/document/assets/index.md.DhvU8bFi.js b/docs/document/assets/index.md.CZIHn4-e.js
similarity index 91%
rename from docs/document/assets/index.md.DhvU8bFi.js
rename to docs/document/assets/index.md.CZIHn4-e.js
index 898bd1c4b..23fe0dc65 100644
--- a/docs/document/assets/index.md.DhvU8bFi.js
+++ b/docs/document/assets/index.md.CZIHn4-e.js
@@ -1,4 +1,4 @@
-import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g=JSON.parse('{"title":"安装使用","description":"","frontmatter":{},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1767420511000}'),p={name:"index.md"};function t(e,s,h,k,r,E){return n(),a("div",null,s[0]||(s[0]=[l(`

安装使用 ​

安装 ​

bash
npm install artplayer
bash
yarn add artplayer
bash
pnpm add artplayer
html
<script src="path/to/artplayer.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
bash
https://unpkg.com/artplayer/dist/artplayer.js

使用 ​

html
<html>
+import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g=JSON.parse('{"title":"安装使用","description":"","frontmatter":{},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1775270107000}'),p={name:"index.md"};function t(e,s,h,k,r,E){return n(),a("div",null,s[0]||(s[0]=[l(`

安装使用 ​

安装 ​

bash
npm install artplayer
bash
yarn add artplayer
bash
pnpm add artplayer
bash
bun add artplayer
html
<script src="path/to/artplayer.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
bash
https://unpkg.com/artplayer/dist/artplayer.js

使用 ​

html
<html>
     <head>
         <title>ArtPlayer Demo</title>
         <meta charset="UTF-8" />
@@ -19,7 +19,7 @@ import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g
           });
         </script>
     </body>
-</html>

提示

播放器的尺寸依赖于容器 container 的尺寸,所以你的容器 container 必须是有尺寸的

以下链接可以看到更多的使用例子

/example

Vue.js ​

vue
<template>
+</html>

提示

播放器的尺寸依赖于容器 container 的尺寸,所以你的容器 container 必须是有尺寸的

以下链接可以看到更多的使用例子

/example

Vue.js ​

vue
<template>
   <div ref="$container" />
 </template>
 
@@ -71,7 +71,7 @@ import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g
 function getInstance(art) {
   console.log(art)
 }
-</script>

Artplayer 非响应式:

在 Vue.js 里直接修改 option 是不会改变播放器的

React.js ​

jsx
import Artplayer from 'artplayer'
+</script>

Artplayer 非响应式:

在 Vue.js 里直接修改 option 是不会改变播放器的

React.js ​

jsx
import Artplayer from 'artplayer'
 import { useEffect, useRef } from 'react'
 
 export default function Player({ option, getInstance, ...rest }) {
@@ -154,7 +154,7 @@ import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g
 
 option.volume = 0.5;
 
-const art8 = new Artplayer(option);

古老的浏览器 ​

生产构建的 artplayer.js 只兼容最新一个主版本的 Chrome:last 1 Chrome version

对于古老的浏览器,可以使用 artplayer.legacy.js 文件,可以兼容到:IE 11

js
import Artplayer from 'artplayer/legacy'
bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
bash
https://unpkg.com/artplayer/dist/artplayer.legacy.js

假如你要兼容更古老的浏览器时,请修改以下配置然后自行构建:

构建配置:scripts/build.js

参考文档:browserslist

ECMAScript Module ​

从 5.2.6 开始,artplayer 和所有插件还会提供一个 ESM 版本的 mjs,如:

  • artplayer/dist/artplayer.mjs
  • artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs
html
<!DOCTYPE html>
+const art8 = new Artplayer(option);

古老的浏览器 ​

生产构建的 artplayer.js 只兼容最新一个主版本的 Chrome:last 1 Chrome version

对于古老的浏览器,可以使用 artplayer.legacy.js 文件,可以兼容到:IE 11

js
import Artplayer from 'artplayer/legacy'
bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
bash
https://unpkg.com/artplayer/dist/artplayer.legacy.js

假如你要兼容更古老的浏览器时,请修改以下配置然后自行构建:

构建配置:scripts/build.js

参考文档:browserslist

ECMAScript Module ​

从 5.2.6 开始,artplayer 和所有插件还会提供一个 ESM 版本的 mjs,如:

  • artplayer/dist/artplayer.mjs
  • artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs
html
<!DOCTYPE html>
 <html lang="en">
 
 <head>
diff --git a/docs/document/assets/index.md.DhvU8bFi.lean.js b/docs/document/assets/index.md.CZIHn4-e.lean.js
similarity index 84%
rename from docs/document/assets/index.md.DhvU8bFi.lean.js
rename to docs/document/assets/index.md.CZIHn4-e.lean.js
index 59beeb14b..f32b7f437 100644
--- a/docs/document/assets/index.md.DhvU8bFi.lean.js
+++ b/docs/document/assets/index.md.CZIHn4-e.lean.js
@@ -1 +1 @@
-import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g=JSON.parse('{"title":"安装使用","description":"","frontmatter":{},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1767420511000}'),p={name:"index.md"};function t(e,s,h,k,r,E){return n(),a("div",null,s[0]||(s[0]=[l("",50)]))}const c=i(p,[["render",t]]);export{g as __pageData,c as default};
+import{_ as i,c as a,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const g=JSON.parse('{"title":"安装使用","description":"","frontmatter":{},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1775270107000}'),p={name:"index.md"};function t(e,s,h,k,r,E){return n(),a("div",null,s[0]||(s[0]=[l("",50)]))}const c=i(p,[["render",t]]);export{g as __pageData,c as default};
diff --git a/docs/document/assets/plugin_danmuku.md.BVV3kpeJ.js b/docs/document/assets/plugin_danmuku.md.FiBSjkUz.js
similarity index 99%
rename from docs/document/assets/plugin_danmuku.md.BVV3kpeJ.js
rename to docs/document/assets/plugin_danmuku.md.FiBSjkUz.js
index e87fede44..3a0466f6e 100644
--- a/docs/document/assets/plugin_danmuku.md.BVV3kpeJ.js
+++ b/docs/document/assets/plugin_danmuku.md.FiBSjkUz.js
@@ -1,4 +1,4 @@
-import{_ as n,c as l,o as p,ak as s,j as i}from"./chunks/framework.xxfEszSJ.js";const y=JSON.parse('{"title":"弹幕库","description":"","frontmatter":{},"headers":[],"relativePath":"plugin/danmuku.md","filePath":"plugin/danmuku.md","lastUpdated":1734270991000}'),h={name:"plugin/danmuku.md"};function e(k,a,t,r,E,d){return p(),l("div",null,a[0]||(a[0]=[s(`

弹幕库 ​

演示 ​

👉 查看完整演示

安装 ​

bash
npm install artplayer-plugin-danmuku
bash
yarn add artplayer-plugin-danmuku
bash
pnpm add artplayer-plugin-danmuku
html
<script src="path/to/artplayer-plugin-danmuku.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
bash
https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js

弹幕结构 ​

每一个弹幕是一个对象,多个弹幕组成的数组就是弹幕库,通常只需要text就可以发送一个弹幕,其余都是非必要参数

js
{
+import{_ as n,c as l,o as p,ak as s,j as i}from"./chunks/framework.xxfEszSJ.js";const y=JSON.parse('{"title":"弹幕库","description":"","frontmatter":{},"headers":[],"relativePath":"plugin/danmuku.md","filePath":"plugin/danmuku.md","lastUpdated":1734270991000}'),h={name:"plugin/danmuku.md"};function e(k,a,t,r,E,d){return p(),l("div",null,a[0]||(a[0]=[s(`

弹幕库 ​

演示 ​

👉 查看完整演示

安装 ​

bash
npm install artplayer-plugin-danmuku
bash
yarn add artplayer-plugin-danmuku
bash
pnpm add artplayer-plugin-danmuku
html
<script src="path/to/artplayer-plugin-danmuku.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
bash
https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js

弹幕结构 ​

每一个弹幕是一个对象,多个弹幕组成的数组就是弹幕库,通常只需要text就可以发送一个弹幕,其余都是非必要参数

js
{
     text: '', // 弹幕文本
     time: 10, // 弹幕时间, 默认为当前播放器时间
     mode: 0, // 弹幕模式: 0: 滚动(默认),1: 顶部,2: 底部
diff --git a/docs/document/assets/plugin_danmuku.md.BVV3kpeJ.lean.js b/docs/document/assets/plugin_danmuku.md.FiBSjkUz.lean.js
similarity index 100%
rename from docs/document/assets/plugin_danmuku.md.BVV3kpeJ.lean.js
rename to docs/document/assets/plugin_danmuku.md.FiBSjkUz.lean.js
diff --git a/docs/document/assets/start_i18n.md.CWsZb7Vr.js b/docs/document/assets/start_i18n.md.CDm9a8pv.js
similarity index 98%
rename from docs/document/assets/start_i18n.md.CWsZb7Vr.js
rename to docs/document/assets/start_i18n.md.CDm9a8pv.js
index df1cabece..a7435c513 100644
--- a/docs/document/assets/start_i18n.md.CWsZb7Vr.js
+++ b/docs/document/assets/start_i18n.md.CDm9a8pv.js
@@ -2,7 +2,7 @@ import{_ as a,c as i,o as n,ak as l}from"./chunks/framework.xxfEszSJ.js";const c
     container: '.artplayer-app',
     url: '/assets/sample/video.mp4',
     lang: 'zh-cn', // or 'en'
-});

导入语言 ​

打包前的语言文件存放于: artplayer/src/i18n/*.js, 欢迎来添加你的语言

打包后的语言文件存放于: artplayer/dist/i18n/*.js

js
import id from 'artplayer/i18n/id';
+});

导入语言 ​

打包前的语言文件存放于: artplayer/src/i18n/*.js, 欢迎来添加你的语言

打包后的语言文件存放于: artplayer/dist/i18n/*.js

js
import id from 'artplayer/i18n/id';
 import zhTw from 'artplayer/i18n/zh-tw';
 
 var art = new Artplayer({
diff --git a/docs/document/assets/start_i18n.md.CWsZb7Vr.lean.js b/docs/document/assets/start_i18n.md.CDm9a8pv.lean.js
similarity index 100%
rename from docs/document/assets/start_i18n.md.CWsZb7Vr.lean.js
rename to docs/document/assets/start_i18n.md.CDm9a8pv.lean.js
diff --git a/docs/document/component/contextmenu.html b/docs/document/component/contextmenu.html
index 0c8d3aec7..f75399365 100644
--- a/docs/document/component/contextmenu.html
+++ b/docs/document/component/contextmenu.html
@@ -9,9 +9,9 @@
     
     
     
-    
+    
     
-    
+    
     
     
     
@@ -106,7 +106,7 @@
         })
     }, 3000);
 });
- + \ No newline at end of file diff --git a/docs/document/component/controls.html b/docs/document/component/controls.html index 043f7018d..0d88d2f05 100644 --- a/docs/document/component/controls.html +++ b/docs/document/component/controls.html @@ -9,9 +9,9 @@ - + - + @@ -153,7 +153,7 @@ }); }, 3000); });
- + \ No newline at end of file diff --git a/docs/document/component/layers.html b/docs/document/component/layers.html index 34dd8d1a7..f5b03f4b5 100644 --- a/docs/document/component/layers.html +++ b/docs/document/component/layers.html @@ -9,9 +9,9 @@ - + - + @@ -125,7 +125,7 @@ }); }, 3000); }); - + \ No newline at end of file diff --git a/docs/document/component/setting.html b/docs/document/component/setting.html index 4a0b9c7fb..2e8cfa666 100644 --- a/docs/document/component/setting.html +++ b/docs/document/component/setting.html @@ -9,9 +9,9 @@ - + - + @@ -245,7 +245,7 @@ }); }, 3000); }); - + \ No newline at end of file diff --git a/docs/document/en/advanced/built-in.html b/docs/document/en/advanced/built-in.html index c36a7c1f1..b8dffd90b 100644 --- a/docs/document/en/advanced/built-in.html +++ b/docs/document/en/advanced/built-in.html @@ -9,9 +9,9 @@ - + - + @@ -217,7 +217,7 @@ art.on('ready', () => { art.plugins.add(myPlugin); }); - + \ No newline at end of file diff --git a/docs/document/en/advanced/class.html b/docs/document/en/advanced/class.html index d54330dbb..417b6d0de 100644 --- a/docs/document/en/advanced/class.html +++ b/docs/document/en/advanced/class.html @@ -9,9 +9,9 @@ - + - + @@ -31,7 +31,7 @@ }); console.info([...Artplayer.instances]);

version ​

Returns the version information of the player.

▶ Run Code
js
console.info(Artplayer.version);

env ​

Returns the environment variables of the player.

▶ Run Code
js
console.info(Artplayer.env);

build ​

Returns the build timestamp of the player.

▶ Run Code
js
console.info(Artplayer.build);

config ​

Returns the default configuration for videos.

▶ Run Code
js
console.info(Artplayer.config);

utils ​

Returns the collection of utility functions for the player.

▶ Run Code
js
console.info(Artplayer.utils);

For all utility functions, please refer to the following address:

artplayer/types/utils.d.ts

scheme ​

Returns the validation schema for player options.

▶ Run Code
js
console.info(Artplayer.scheme);

Emitter ​

Returns the constructor of the event emitter.

▶ Run Code
js
console.info(Artplayer.Emitter);

validator ​

Returns the validation function for options.

▶ Run Code
js
console.info(Artplayer.validator);

kindOf ​

Returns the type detection utility function.

▶ Run Code
js
console.info(Artplayer.kindOf);

html ​

Returns the html string required by the player.

▶ Run Code
js
console.info(Artplayer.html);

option ​

Returns the default options of the player.

▶ Run Code
js
console.info(Artplayer.option);
- + \ No newline at end of file diff --git a/docs/document/en/advanced/event.html b/docs/document/en/advanced/event.html index 52d7ea933..c93a0a2c5 100644 --- a/docs/document/en/advanced/event.html +++ b/docs/document/en/advanced/event.html @@ -9,9 +9,9 @@ - + - + @@ -385,7 +385,7 @@ art.on('keydown', (event) => { console.log(event.code); });

video:canplay ​

The browser can start playing the media, but estimates there is not enough data to play through to the end without stopping for further buffering.

video:canplaythrough ​

The browser estimates it can play the media through to the end without stopping for buffering.

video:complete ​

The OfflineAudioContext rendering is complete.

video:durationchange ​

Triggered when the value of the duration property changes.

video:emptied ​

The media has become empty; for example, this event is sent when the media has already been loaded (or partially loaded), and the load() method is called to reload it.

video:ended ​

Playback has stopped because the media has reached its end.

video:error ​

An error occurred while fetching the media data, or the resource type is not a supported media format.

video:loadeddata ​

The first frame of the media has finished loading.

video:loadedmetadata ​

Metadata has been loaded.

video:pause ​

Playback has been paused.

video:play ​

Playback has begun.

video:playing ​

Playback is ready to start after having been paused or delayed due to lack of data.

video:progress ​

Fired periodically as the browser loads the resource.

video:ratechange ​

The playback rate has changed.

video:seeked ​

A seek operation has completed.

video:seeking ​

A seek operation has begun.

video:stalled ​

The user agent is trying to fetch media data, but data is unexpectedly not forthcoming.

video:suspend ​

Media data loading has been suspended.

video:timeupdate ​

The time indicated by the currentTime property has changed.

video:volumechange ​

The volume has changed.

video:waiting ​

Playback has stopped because of a temporary lack of data.

- + \ No newline at end of file diff --git a/docs/document/en/advanced/global.html b/docs/document/en/advanced/global.html index a7265b076..2b903e5de 100644 --- a/docs/document/en/advanced/global.html +++ b/docs/document/en/advanced/global.html @@ -9,9 +9,9 @@ - + - + @@ -248,7 +248,7 @@ // Only destroy the UI, do not actively clear the src art.destroy(); - + \ No newline at end of file diff --git a/docs/document/en/advanced/plugin.html b/docs/document/en/advanced/plugin.html index 1b0f22989..fee21b907 100644 --- a/docs/document/en/advanced/plugin.html +++ b/docs/document/en/advanced/plugin.html @@ -9,9 +9,9 @@ - + - + @@ -122,7 +122,7 @@ }) ], }); - + \ No newline at end of file diff --git a/docs/document/en/advanced/property.html b/docs/document/en/advanced/property.html index 3ec5b3cf0..1d07f8037 100644 --- a/docs/document/en/advanced/property.html +++ b/docs/document/en/advanced/property.html @@ -9,9 +9,9 @@ - + - + @@ -457,7 +457,7 @@ art.on('ready', () => { art.subtitleOffset = 1; }); - + \ No newline at end of file diff --git a/docs/document/en/component/contextmenu.html b/docs/document/en/component/contextmenu.html index f080586fa..3fe48f0e3 100644 --- a/docs/document/en/component/contextmenu.html +++ b/docs/document/en/component/contextmenu.html @@ -9,9 +9,9 @@ - + - + @@ -106,7 +106,7 @@ }) }, 3000); }); - + \ No newline at end of file diff --git a/docs/document/en/component/controls.html b/docs/document/en/component/controls.html index 7200c62ac..2d45f7dd0 100644 --- a/docs/document/en/component/controls.html +++ b/docs/document/en/component/controls.html @@ -9,9 +9,9 @@ - + - + @@ -153,7 +153,7 @@ }); }, 3000); }); - + \ No newline at end of file diff --git a/docs/document/en/component/layers.html b/docs/document/en/component/layers.html index cf57b2e07..d3ea79938 100644 --- a/docs/document/en/component/layers.html +++ b/docs/document/en/component/layers.html @@ -9,9 +9,9 @@ - + - + @@ -125,7 +125,7 @@ }); }, 3000); }); - + \ No newline at end of file diff --git a/docs/document/en/component/setting.html b/docs/document/en/component/setting.html index 46264e150..fea6bb8e6 100644 --- a/docs/document/en/component/setting.html +++ b/docs/document/en/component/setting.html @@ -9,9 +9,9 @@ - + - + @@ -245,7 +245,7 @@ }); }, 3000); }); - + \ No newline at end of file diff --git a/docs/document/en/index.html b/docs/document/en/index.html index 0f5a2a0a4..0f3d2b93a 100644 --- a/docs/document/en/index.html +++ b/docs/document/en/index.html @@ -9,11 +9,11 @@ - + - + - + @@ -23,7 +23,7 @@ -
Skip to content

Installation and Usage ​

Installation ​

bash
npm install artplayer
bash
yarn add artplayer
bash
pnpm add artplayer
html
<script src="path/to/artplayer.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
bash
https://unpkg.com/artplayer/dist/artplayer.js

Usage ​

html
<html>
+    
Skip to content

Installation and Usage ​

Installation ​

bash
npm install artplayer
bash
yarn add artplayer
bash
pnpm add artplayer
bash
bun add artplayer
html
<script src="path/to/artplayer.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
bash
https://unpkg.com/artplayer/dist/artplayer.js

Usage ​

html
<html>
     <head>
         <title>ArtPlayer Demo</title>
         <meta charset="UTF-8" />
@@ -44,7 +44,7 @@
           });
         </script>
     </body>
-</html>

Note

The player's dimensions depend on the dimensions of its container. Therefore, your container must have defined dimensions.

See more usage examples at the following link

/example

Vue.js ​

vue
<template>
+</html>

Note

The player's dimensions depend on the dimensions of its container. Therefore, your container must have defined dimensions.

See more usage examples at the following link

/example

Vue.js ​

vue
<template>
   <div ref="$container" />
 </template>
 
@@ -96,7 +96,7 @@
 function getInstance(art) {
   console.log(art)
 }
-</script>

Artplayer is not reactive:

Directly modifying the option in Vue.js will not update the player.

React.js ​

jsx
import Artplayer from 'artplayer'
+</script>

Artplayer is not reactive:

Directly modifying the option in Vue.js will not update the player.

React.js ​

jsx
import Artplayer from 'artplayer'
 import { useEffect, useRef } from 'react'
 
 export default function Player({ option, getInstance, ...rest }) {
@@ -179,7 +179,7 @@
 
 option.volume = 0.5;
 
-const art8 = new Artplayer(option);

Legacy Browsers ​

The production build artplayer.js only supports the latest major version of Chrome: last 1 Chrome version.

For legacy browsers, you can use the artplayer.legacy.js file, which is compatible down to: IE 11.

js
import Artplayer from 'artplayer/legacy'
bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
bash
https://unpkg.com/artplayer/dist/artplayer.legacy.js

If you need to support even older browsers, modify the following configuration and build it yourself:

Build configuration: scripts/build.js

Reference documentation: browserslist

ECMAScript Module ​

Starting from version 5.2.6, artplayer and all plugins also provide an ESM version in mjs format, such as:

  • artplayer/dist/artplayer.mjs
  • artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs
html
<!DOCTYPE html>
+const art8 = new Artplayer(option);

Legacy Browsers ​

The production build artplayer.js only supports the latest major version of Chrome: last 1 Chrome version.

For legacy browsers, you can use the artplayer.legacy.js file, which is compatible down to: IE 11.

js
import Artplayer from 'artplayer/legacy'
bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
bash
https://unpkg.com/artplayer/dist/artplayer.legacy.js

If you need to support even older browsers, modify the following configuration and build it yourself:

Build configuration: scripts/build.js

Reference documentation: browserslist

ECMAScript Module ​

Starting from version 5.2.6, artplayer and all plugins also provide an ESM version in mjs format, such as:

  • artplayer/dist/artplayer.mjs
  • artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs
html
<!DOCTYPE html>
 <html lang="en">
 
 <head>
@@ -236,8 +236,8 @@
           });
         </script>
     </body>
-</html>

Note

You need to modify it before importing the Artplayer dependency for it to take effect.

- +</html>

Note

You need to modify it before importing the Artplayer dependency for it to take effect.

+ \ No newline at end of file diff --git a/docs/document/en/start/i18n.html b/docs/document/en/start/i18n.html index 72ca7f33a..67e6a3f8e 100644 --- a/docs/document/en/start/i18n.html +++ b/docs/document/en/start/i18n.html @@ -9,11 +9,11 @@ - + - + - + @@ -27,7 +27,7 @@ container: '.artplayer-app', url: '/assets/sample/video.mp4', lang: 'zh-cn', // or 'en' -});

Importing Languages ​

Language files before bundling are located at: artplayer/src/i18n/*.js. Contributions for new languages are welcome.

Bundled language files are located at: artplayer/dist/i18n/*.js

js
import id from 'artplayer/i18n/id';
+});

Importing Languages ​

Language files before bundling are located at: artplayer/src/i18n/*.js. Contributions for new languages are welcome.

Bundled language files are located at: artplayer/dist/i18n/*.js

js
import id from 'artplayer/i18n/id';
 import zhTw from 'artplayer/i18n/zh-tw';
 
 var art = new Artplayer({
@@ -75,7 +75,7 @@
         },
     },
 });
- + \ No newline at end of file diff --git a/docs/document/en/start/option.html b/docs/document/en/start/option.html index 3b1b17486..f9c0acc8e 100644 --- a/docs/document/en/start/option.html +++ b/docs/document/en/start/option.html @@ -9,9 +9,9 @@ - + - + @@ -415,7 +415,7 @@ url: '/assets/sample/video.mp4', proxy: () => document.createElement('video') }); - + \ No newline at end of file diff --git a/docs/document/hashmap.json b/docs/document/hashmap.json index 3007f4e6c..afff85c46 100644 --- a/docs/document/hashmap.json +++ b/docs/document/hashmap.json @@ -1 +1 @@ -{"advanced_built-in.md":"DiyRIcIA","advanced_class.md":"Da3aE0pP","advanced_event.md":"mrsB0MsK","advanced_global.md":"Bdw3azKs","advanced_plugin.md":"B3Pobmcq","advanced_property.md":"CA7GaeI3","component_contextmenu.md":"ClKmcIKr","component_controls.md":"Cl62yW1F","component_layers.md":"Cys52VMi","component_setting.md":"BP5674ir","en_advanced_built-in.md":"CCHa0pnS","en_advanced_class.md":"SSD-Ahrs","en_advanced_event.md":"DEsqIUNQ","en_advanced_global.md":"3hwkL6RS","en_advanced_plugin.md":"C8AgK5Nt","en_advanced_property.md":"CaOAGGTk","en_component_contextmenu.md":"CsJAr6Ey","en_component_controls.md":"t1Ub-agE","en_component_layers.md":"Yo2RXBZy","en_component_setting.md":"Be0gsY-X","en_index.md":"DFeypQS9","en_start_i18n.md":"Cg_MHRXn","en_start_option.md":"C2vGTVOZ","index.md":"DhvU8bFi","plugin_danmuku.md":"BVV3kpeJ","start_i18n.md":"CWsZb7Vr","start_option.md":"D52S8Ynf"} +{"advanced_built-in.md":"DiyRIcIA","advanced_class.md":"Da3aE0pP","advanced_event.md":"mrsB0MsK","advanced_global.md":"Bdw3azKs","advanced_plugin.md":"B3Pobmcq","advanced_property.md":"CA7GaeI3","component_contextmenu.md":"ClKmcIKr","component_controls.md":"Cl62yW1F","component_layers.md":"Cys52VMi","component_setting.md":"BP5674ir","en_advanced_built-in.md":"CCHa0pnS","en_advanced_class.md":"SSD-Ahrs","en_advanced_event.md":"DEsqIUNQ","en_advanced_global.md":"3hwkL6RS","en_advanced_plugin.md":"C8AgK5Nt","en_advanced_property.md":"CaOAGGTk","en_component_contextmenu.md":"CsJAr6Ey","en_component_controls.md":"t1Ub-agE","en_component_layers.md":"Yo2RXBZy","en_component_setting.md":"Be0gsY-X","en_index.md":"Clwh28HI","en_start_i18n.md":"BLwUSSfJ","en_start_option.md":"C2vGTVOZ","index.md":"CZIHn4-e","plugin_danmuku.md":"FiBSjkUz","start_i18n.md":"CDm9a8pv","start_option.md":"D52S8Ynf"} diff --git a/docs/document/index.html b/docs/document/index.html index 21daed561..3f52b433c 100644 --- a/docs/document/index.html +++ b/docs/document/index.html @@ -9,11 +9,11 @@ - + - + - + @@ -23,7 +23,7 @@ -
Skip to content

安装使用 ​

安装 ​

bash
npm install artplayer
bash
yarn add artplayer
bash
pnpm add artplayer
html
<script src="path/to/artplayer.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
bash
https://unpkg.com/artplayer/dist/artplayer.js

使用 ​

html
<html>
+    
Skip to content

安装使用 ​

安装 ​

bash
npm install artplayer
bash
yarn add artplayer
bash
pnpm add artplayer
bash
bun add artplayer
html
<script src="path/to/artplayer.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
bash
https://unpkg.com/artplayer/dist/artplayer.js

使用 ​

html
<html>
     <head>
         <title>ArtPlayer Demo</title>
         <meta charset="UTF-8" />
@@ -44,7 +44,7 @@
           });
         </script>
     </body>
-</html>

提示

播放器的尺寸依赖于容器 container 的尺寸,所以你的容器 container 必须是有尺寸的

以下链接可以看到更多的使用例子

/example

Vue.js ​

vue
<template>
+</html>

提示

播放器的尺寸依赖于容器 container 的尺寸,所以你的容器 container 必须是有尺寸的

以下链接可以看到更多的使用例子

/example

Vue.js ​

vue
<template>
   <div ref="$container" />
 </template>
 
@@ -96,7 +96,7 @@
 function getInstance(art) {
   console.log(art)
 }
-</script>

Artplayer 非响应式:

在 Vue.js 里直接修改 option 是不会改变播放器的

React.js ​

jsx
import Artplayer from 'artplayer'
+</script>

Artplayer 非响应式:

在 Vue.js 里直接修改 option 是不会改变播放器的

React.js ​

jsx
import Artplayer from 'artplayer'
 import { useEffect, useRef } from 'react'
 
 export default function Player({ option, getInstance, ...rest }) {
@@ -179,7 +179,7 @@
 
 option.volume = 0.5;
 
-const art8 = new Artplayer(option);

古老的浏览器 ​

生产构建的 artplayer.js 只兼容最新一个主版本的 Chrome:last 1 Chrome version

对于古老的浏览器,可以使用 artplayer.legacy.js 文件,可以兼容到:IE 11

js
import Artplayer from 'artplayer/legacy'
bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
bash
https://unpkg.com/artplayer/dist/artplayer.legacy.js

假如你要兼容更古老的浏览器时,请修改以下配置然后自行构建:

构建配置:scripts/build.js

参考文档:browserslist

ECMAScript Module ​

从 5.2.6 开始,artplayer 和所有插件还会提供一个 ESM 版本的 mjs,如:

  • artplayer/dist/artplayer.mjs
  • artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs
html
<!DOCTYPE html>
+const art8 = new Artplayer(option);

古老的浏览器 ​

生产构建的 artplayer.js 只兼容最新一个主版本的 Chrome:last 1 Chrome version

对于古老的浏览器,可以使用 artplayer.legacy.js 文件,可以兼容到:IE 11

js
import Artplayer from 'artplayer/legacy'
bash
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
bash
https://unpkg.com/artplayer/dist/artplayer.legacy.js

假如你要兼容更古老的浏览器时,请修改以下配置然后自行构建:

构建配置:scripts/build.js

参考文档:browserslist

ECMAScript Module ​

从 5.2.6 开始,artplayer 和所有插件还会提供一个 ESM 版本的 mjs,如:

  • artplayer/dist/artplayer.mjs
  • artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs
html
<!DOCTYPE html>
 <html lang="en">
 
 <head>
@@ -236,8 +236,8 @@
           });
         </script>
     </body>
-</html>

提示

你需要在引入 Artplayer 依赖前来修改它才会生效

- +</html>

提示

你需要在引入 Artplayer 依赖前来修改它才会生效

+ \ No newline at end of file diff --git a/docs/document/plugin/danmuku.html b/docs/document/plugin/danmuku.html index 3cfa95eb3..f714908c6 100644 --- a/docs/document/plugin/danmuku.html +++ b/docs/document/plugin/danmuku.html @@ -9,11 +9,11 @@ - + - + - + @@ -23,7 +23,7 @@ -
Skip to content

弹幕库 ​

演示 ​

👉 查看完整演示

安装 ​

bash
npm install artplayer-plugin-danmuku
bash
yarn add artplayer-plugin-danmuku
bash
pnpm add artplayer-plugin-danmuku
html
<script src="path/to/artplayer-plugin-danmuku.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
bash
https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js

弹幕结构 ​

每一个弹幕是一个对象,多个弹幕组成的数组就是弹幕库,通常只需要text就可以发送一个弹幕,其余都是非必要参数

js
{
+    
Skip to content

弹幕库 ​

演示 ​

👉 查看完整演示

安装 ​

bash
npm install artplayer-plugin-danmuku
bash
yarn add artplayer-plugin-danmuku
bash
pnpm add artplayer-plugin-danmuku
html
<script src="path/to/artplayer-plugin-danmuku.js"></script>

CDN ​

bash
https://cdn.jsdelivr.net/npm/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
bash
https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js

弹幕结构 ​

每一个弹幕是一个对象,多个弹幕组成的数组就是弹幕库,通常只需要text就可以发送一个弹幕,其余都是非必要参数

js
{
     text: '', // 弹幕文本
     time: 10, // 弹幕时间, 默认为当前播放器时间
     mode: 0, // 弹幕模式: 0: 滚动(默认),1: 顶部,2: 底部
@@ -367,7 +367,7 @@
 art.on('artplayerPluginDanmuku:destroy', () => {
     console.info('弹幕销毁');
 });
- + \ No newline at end of file diff --git a/docs/document/start/i18n.html b/docs/document/start/i18n.html index 01f629381..843ee634f 100644 --- a/docs/document/start/i18n.html +++ b/docs/document/start/i18n.html @@ -9,11 +9,11 @@ - + - + - + @@ -27,7 +27,7 @@ container: '.artplayer-app', url: '/assets/sample/video.mp4', lang: 'zh-cn', // or 'en' -});

导入语言 ​

打包前的语言文件存放于: artplayer/src/i18n/*.js, 欢迎来添加你的语言

打包后的语言文件存放于: artplayer/dist/i18n/*.js

js
import id from 'artplayer/i18n/id';
+});

导入语言 ​

打包前的语言文件存放于: artplayer/src/i18n/*.js, 欢迎来添加你的语言

打包后的语言文件存放于: artplayer/dist/i18n/*.js

js
import id from 'artplayer/i18n/id';
 import zhTw from 'artplayer/i18n/zh-tw';
 
 var art = new Artplayer({
@@ -75,7 +75,7 @@
         },
     },
 });
- + \ No newline at end of file diff --git a/docs/document/start/option.html b/docs/document/start/option.html index 3e2f4e211..e647a0e64 100644 --- a/docs/document/start/option.html +++ b/docs/document/start/option.html @@ -9,9 +9,9 @@ - + - + @@ -415,7 +415,7 @@ url: '/assets/sample/video.mp4', proxy: () => document.createElement('video') }); - + \ No newline at end of file diff --git a/docs/uncompiled/artplayer-proxy-mediabunny/index.js b/docs/uncompiled/artplayer-proxy-mediabunny/index.js index 8d291d480..353664813 100644 --- a/docs/uncompiled/artplayer-proxy-mediabunny/index.js +++ b/docs/uncompiled/artplayer-proxy-mediabunny/index.js @@ -1,5 +1,167 @@ var artplayerProxyMediabunny = (function() { "use strict"; + const $audio = ''; + const $quality = ''; + function uniqBy(array, property) { + const seen = /* @__PURE__ */ new Map(); + return array.filter((item) => { + const key = item[property]; + if (key === void 0) { + return true; + } + return !seen.has(key) && seen.set(key, 1); + }); + } + function setupM3u8Controls({ art, shim, option }) { + if (!option.m3u8) + return; + function removeControl(name) { + if (art.controls.cache.has(name)) { + art.controls.remove(name); + } + } + function removeSetting(name) { + if (art.setting.find(name)) { + art.setting.remove(name); + } + } + function clearQuality() { + removeControl("mediabunny-quality"); + removeSetting("mediabunny-quality"); + } + function clearAudio() { + removeControl("mediabunny-audio"); + removeSetting("mediabunny-audio"); + } + function canRender(config = {}) { + return config.control || config.setting; + } + async function updateQuality(state) { + const config = option.m3u8?.quality || {}; + if (!canRender(config) || !state?.levels.length) { + clearQuality(); + return; + } + const auto = config.auto || "Auto"; + const title = config.title || "Quality"; + const getName = config.getName || ((level) => level.name || `${level.height}P`); + const defaultHtml = state.currentLevel ? getName(state.currentLevel) : auto; + const selector = uniqBy( + state.levels.map((item) => { + return { + html: getName(item), + value: item.id, + default: state.currentLevel?.id === item.id + }; + }), + "html" + ).sort((a, b) => { + const left = state.levels.find((item) => item.id === a.value); + const right = state.levels.find((item) => item.id === b.value); + return (right?.height || 0) - (left?.height || 0); + }); + selector.push({ + html: auto, + value: "auto", + default: !state.currentLevel + }); + const onSelect = async (item) => { + await shim.switchM3u8Quality(item.value); + art.notice.show = `${title}: ${item.html}`; + await update(); + return item.html; + }; + if (config.control) { + art.controls.update({ + name: "mediabunny-quality", + position: "right", + html: defaultHtml, + style: { padding: "0 10px" }, + selector, + onSelect + }); + } + if (config.setting) { + art.setting.update({ + name: "mediabunny-quality", + tooltip: defaultHtml, + html: title, + icon: $quality, + width: 200, + selector, + onSelect + }); + } + } + async function updateAudio(state) { + const config = option.m3u8?.audio || {}; + if (!canRender(config) || !state?.audios.length || state.audios.length < 2) { + clearAudio(); + return; + } + const auto = config.auto || "Auto"; + const title = config.title || "Audio"; + const getName = config.getName || ((track) => track.name || track.lang || track.language); + const defaultHtml = state.currentAudio ? getName(state.currentAudio) : auto; + const selector = uniqBy( + state.audios.map((item) => { + return { + html: getName(item), + value: item.id, + default: state.currentAudio?.id === item.id + }; + }), + "html" + ); + selector.push({ + html: auto, + value: "auto", + default: !state.currentAudio + }); + const onSelect = async (item) => { + await shim.switchM3u8Audio(item.value); + art.notice.show = `${title}: ${item.html}`; + await update(); + return item.html; + }; + if (config.control) { + art.controls.update({ + name: "mediabunny-audio", + position: "right", + html: defaultHtml, + style: { padding: "0 10px" }, + selector, + onSelect + }); + } + if (config.setting) { + art.setting.update({ + name: "mediabunny-audio", + tooltip: defaultHtml, + html: title, + icon: $audio, + width: 200, + selector, + onSelect + }); + } + } + async function update() { + const state = await shim.getM3u8State(); + if (!state) { + clearQuality(); + clearAudio(); + return; + } + await Promise.all([ + updateQuality(state), + updateAudio(state) + ]); + } + art.on("video:loadedmetadata", update); + art.on("restart", update); + return { update }; + } class EventTarget { constructor() { this.listeners = /* @__PURE__ */ new Map(); @@ -44,66 +206,6 @@ var artplayerProxyMediabunny = (function() { const last = (arr) => { return arr && arr[arr.length - 1]; }; - class Bitstream { - constructor(bytes) { - this.bytes = bytes; - this.pos = 0; - } - seekToByte(byteOffset) { - this.pos = 8 * byteOffset; - } - readBit() { - const byteIndex = Math.floor(this.pos / 8); - const byte = this.bytes[byteIndex] ?? 0; - const bitIndex = 7 - (this.pos & 7); - const bit = (byte & 1 << bitIndex) >> bitIndex; - this.pos++; - return bit; - } - readBits(n) { - if (n === 1) { - return this.readBit(); - } - let result = 0; - for (let i = 0; i < n; i++) { - result <<= 1; - result |= this.readBit(); - } - return result; - } - writeBits(n, value) { - const end = this.pos + n; - for (let i = this.pos; i < end; i++) { - const byteIndex = Math.floor(i / 8); - let byte = this.bytes[byteIndex]; - const bitIndex = 7 - (i & 7); - byte &= ~(1 << bitIndex); - byte |= (value & 1 << end - i - 1) >> end - i - 1 << bitIndex; - this.bytes[byteIndex] = byte; - } - this.pos = end; - } - readAlignedByte() { - if (this.pos % 8 !== 0) { - throw new Error("Bitstream is not byte-aligned."); - } - const byteIndex = this.pos / 8; - const byte = this.bytes[byteIndex] ?? 0; - this.pos += 8; - return byte; - } - skipBits(n) { - this.pos += n; - } - getBitsLeft() { - return this.bytes.length * 8 - this.pos; - } - clone() { - const clone = new Bitstream(this.bytes); - clone.pos = this.pos; - return clone; - } - } const readExpGolomb = (bitstream) => { let leadingZeroBits = 0; while (bitstream.readBits(1) === 0 && leadingZeroBits < 32) { @@ -188,21 +290,40 @@ var artplayerProxyMediabunny = (function() { class AsyncMutex { constructor() { this.currentPromise = Promise.resolve(); + this.pending = 0; } async acquire() { let resolver; const nextPromise = new Promise((resolve) => { - resolver = resolve; + let resolved = false; + resolver = () => { + if (resolved) { + return; + } + resolve(); + this.pending--; + resolved = true; + }; }); const currentPromiseAlias = this.currentPromise; this.currentPromise = nextPromise; + this.pending++; await currentPromiseAlias; return resolver; } } + const HEX_STRING_REGEX = /^[0-9a-fA-F]+$/; const bytesToHexString = (bytes) => { return [...bytes].map((x) => x.toString(16).padStart(2, "0")).join(""); }; + const hexStringToBytes = (hexString) => { + assert(hexString.length % 2 === 0); + const bytes = new Uint8Array(hexString.length / 2); + for (let i = 0; i < hexString.length; i += 2) { + bytes[i / 2] = parseInt(hexString.slice(i, i + 2), 16); + } + return bytes; + }; const reverseBitsU32 = (x) => { x = x >> 1 & 1431655765 | (x & 1431655765) << 1; x = x >> 2 & 858993459 | (x & 858993459) << 2; @@ -258,6 +379,12 @@ var artplayerProxyMediabunny = (function() { }); return { promise, resolve, reject }; }; + const removeItem = (arr, item) => { + const index = arr.indexOf(item); + if (index !== -1) { + arr.splice(index, 1); + } + }; const findLast = (arr, predicate) => { for (let i = arr.length - 1; i >= 0; i--) { if (predicate(arr[i])) { @@ -347,6 +474,12 @@ var artplayerProxyMediabunny = (function() { const roundToMultiple = (value, multiple) => { return Math.round(value / multiple) * multiple; }; + const roundToDivisor = (value, multiple) => { + return Math.round(value * multiple) / multiple; + }; + const floorToMultiple = (value, multiple) => { + return Math.floor(value / multiple) * multiple; + }; const ilog = (x) => { let ret = 0; while (x) { @@ -413,7 +546,7 @@ var artplayerProxyMediabunny = (function() { throw new TypeError("Retry delay must be a non-negative finite number."); } if (retryDelayInSeconds > 0) { - await new Promise((resolve) => setTimeout(resolve, 1e3 * retryDelayInSeconds)); + await wait(1e3 * retryDelayInSeconds); } if (shouldStop()) { throw error; @@ -434,7 +567,8 @@ var artplayerProxyMediabunny = (function() { if (isWebKitCache !== null) { return isWebKitCache; } - return isWebKitCache = !!(typeof navigator !== "undefined" && (navigator.vendor?.match(/apple/i) || /AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) || /\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent))); + return isWebKitCache = !!(typeof navigator !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-deprecated + (navigator.vendor?.match(/apple/i) || /AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) || /\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent))); }; let isFirefoxCache = null; const isFirefox = () => { @@ -478,12 +612,166 @@ var artplayerProxyMediabunny = (function() { } return bytes; }; + const uint8ArraysAreEqual = (a, b) => { + if (a.length !== b.length) { + return false; + } + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; + }; const polyfillSymbolDispose = () => { Symbol.dispose ?? (Symbol.dispose = /* @__PURE__ */ Symbol("Symbol.dispose")); }; const isNumber = (x) => { return typeof x === "number" && !Number.isNaN(x); }; + const joinPaths = (basePath, relativePath) => { + if (relativePath.includes("://")) { + return relativePath; + } + if (basePath.includes("://")) { + const queryIndex = basePath.indexOf("?"); + if (queryIndex !== -1) { + basePath = basePath.slice(0, queryIndex); + } + } + let result; + if (relativePath.startsWith("/")) { + const protocolIndex2 = basePath.indexOf("://"); + if (protocolIndex2 === -1) { + result = relativePath; + } else { + const pathStart = basePath.indexOf("/", protocolIndex2 + 3); + if (pathStart === -1) { + result = basePath + relativePath; + } else { + result = basePath.slice(0, pathStart) + relativePath; + } + } + } else { + const lastSlash = basePath.lastIndexOf("/"); + if (lastSlash === -1) { + result = relativePath; + } else { + result = basePath.slice(0, lastSlash + 1) + relativePath; + } + } + let prefix = ""; + const protocolIndex = result.indexOf("://"); + if (protocolIndex !== -1) { + const pathStart = result.indexOf("/", protocolIndex + 3); + if (pathStart !== -1) { + prefix = result.slice(0, pathStart); + result = result.slice(pathStart); + } + } + const segments = result.split("/"); + const normalized = []; + for (const segment of segments) { + if (segment === "..") { + normalized.pop(); + } else if (segment !== ".") { + normalized.push(segment); + } + } + return prefix + normalized.join("/"); + }; + const arrayCount = (array, predicate) => { + let count = 0; + for (let i = 0; i < array.length; i++) { + if (predicate(array[i])) { + count++; + } + } + return count; + }; + const arrayArgmin = (array, getValue) => { + let minIndex = -1; + let minValue = Infinity; + for (let i = 0; i < array.length; i++) { + const value = getValue(array[i]); + if (value < minValue) { + minValue = value; + minIndex = i; + } + } + return minIndex; + }; + const simplifyRational = (rational) => { + assert(Number.isInteger(rational.num)); + assert(Number.isInteger(rational.den)); + assert(rational.den !== 0); + let a = Math.abs(rational.num); + let b = Math.abs(rational.den); + while (b !== 0) { + const t = a % b; + a = b; + b = t; + } + const gcd = a || 1; + return { + num: rational.num / gcd, + den: rational.den / gcd + }; + }; + const validateRectangle = (rect, propertyPath) => { + if (typeof rect !== "object" || !rect) { + throw new TypeError(`${propertyPath} must be an object.`); + } + if (!Number.isInteger(rect.left) || rect.left < 0) { + throw new TypeError(`${propertyPath}.left must be a non-negative integer.`); + } + if (!Number.isInteger(rect.top) || rect.top < 0) { + throw new TypeError(`${propertyPath}.top must be a non-negative integer.`); + } + if (!Number.isInteger(rect.width) || rect.width < 0) { + throw new TypeError(`${propertyPath}.width must be a non-negative integer.`); + } + if (!Number.isInteger(rect.height) || rect.height < 0) { + throw new TypeError(`${propertyPath}.height must be a non-negative integer.`); + } + }; + const wait = (ms) => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }; + class EventEmitter { + constructor() { + this._listeners = /* @__PURE__ */ new Map(); + } + /** Registers a listener for the given event. */ + on(event, listener, options) { + if (!this._listeners.has(event)) { + this._listeners.set(event, /* @__PURE__ */ new Set()); + } + const entry = { fn: listener, once: options?.once ?? false }; + this._listeners.get(event).add(entry); + return () => { + this._listeners.get(event)?.delete(entry); + }; + } + /** @internal */ + _emit(...args) { + const [event, data] = args; + const listeners = this._listeners.get(event); + if (!listeners) { + return; + } + for (const entry of listeners) { + try { + entry.fn(data); + } catch (error) { + console.error(error); + } + if (entry.once) { + listeners.delete(entry); + } + } + } + } class RichImageData { /** Creates a new {@link RichImageData}. */ constructor(data, mimeType) { @@ -520,12 +808,127 @@ var artplayerProxyMediabunny = (function() { } const DEFAULT_TRACK_DISPOSITION = { default: true, + primary: true, forced: false, original: false, commentary: false, hearingImpaired: false, visuallyImpaired: false }; + class Bitstream { + constructor(bytes) { + this.bytes = bytes; + this.pos = 0; + } + seekToByte(byteOffset) { + this.pos = 8 * byteOffset; + } + readBit() { + const byteIndex = Math.floor(this.pos / 8); + const byte = this.bytes[byteIndex] ?? 0; + const bitIndex = 7 - (this.pos & 7); + const bit = (byte & 1 << bitIndex) >> bitIndex; + this.pos++; + return bit; + } + readBits(n) { + if (n === 1) { + return this.readBit(); + } + let result = 0; + for (let i = 0; i < n; i++) { + result <<= 1; + result |= this.readBit(); + } + return result; + } + writeBits(n, value) { + const end = this.pos + n; + for (let i = this.pos; i < end; i++) { + const byteIndex = Math.floor(i / 8); + let byte = this.bytes[byteIndex]; + const bitIndex = 7 - (i & 7); + byte &= ~(1 << bitIndex); + byte |= (value & 1 << end - i - 1) >> end - i - 1 << bitIndex; + this.bytes[byteIndex] = byte; + } + this.pos = end; + } + readAlignedByte() { + if (this.pos % 8 !== 0) { + throw new Error("Bitstream is not byte-aligned."); + } + const byteIndex = this.pos / 8; + const byte = this.bytes[byteIndex] ?? 0; + this.pos += 8; + return byte; + } + skipBits(n) { + this.pos += n; + } + getBitsLeft() { + return this.bytes.length * 8 - this.pos; + } + clone() { + const clone = new Bitstream(this.bytes); + clone.pos = this.pos; + return clone; + } + } + const aacFrequencyTable = [ + 96e3, + 88200, + 64e3, + 48e3, + 44100, + 32e3, + 24e3, + 22050, + 16e3, + 12e3, + 11025, + 8e3, + 7350 + ]; + const aacChannelMap = [-1, 1, 2, 3, 4, 5, 6, 8]; + const parseAacAudioSpecificConfig = (bytes) => { + if (!bytes || bytes.byteLength < 2) { + throw new TypeError("AAC description must be at least 2 bytes long."); + } + const bitstream = new Bitstream(bytes); + let objectType = bitstream.readBits(5); + if (objectType === 31) { + objectType = 32 + bitstream.readBits(6); + } + const frequencyIndex = bitstream.readBits(4); + let sampleRate = null; + if (frequencyIndex === 15) { + sampleRate = bitstream.readBits(24); + } else { + if (frequencyIndex < aacFrequencyTable.length) { + sampleRate = aacFrequencyTable[frequencyIndex]; + } + } + const channelConfiguration = bitstream.readBits(4); + let numberOfChannels = null; + if (channelConfiguration >= 1 && channelConfiguration <= 7) { + numberOfChannels = aacChannelMap[channelConfiguration]; + } + return { + objectType, + frequencyIndex, + sampleRate, + channelConfiguration, + numberOfChannels + }; + }; + const VIDEO_CODECS = [ + "avc", + "hevc", + "vp9", + "av1", + "vp8" + ]; const PCM_AUDIO_CODECS = [ "pcm-s16", // We don't prefix 'le' so we're compatible with the WebCodecs-registered PCM codec strings @@ -543,6 +946,59 @@ var artplayerProxyMediabunny = (function() { "ulaw", "alaw" ]; + const NON_PCM_AUDIO_CODECS = [ + "aac", + "opus", + "mp3", + "vorbis", + "flac", + "ac3", + "eac3" + ]; + const AUDIO_CODECS = [ + ...NON_PCM_AUDIO_CODECS, + ...PCM_AUDIO_CODECS + ]; + const AVC_LEVEL_TABLE = [ + { maxMacroblocks: 99, maxBitrate: 64e3, maxDpbMbs: 396, level: 10 }, + // Level 1 + { maxMacroblocks: 396, maxBitrate: 192e3, maxDpbMbs: 900, level: 11 }, + // Level 1.1 + { maxMacroblocks: 396, maxBitrate: 384e3, maxDpbMbs: 2376, level: 12 }, + // Level 1.2 + { maxMacroblocks: 396, maxBitrate: 768e3, maxDpbMbs: 2376, level: 13 }, + // Level 1.3 + { maxMacroblocks: 396, maxBitrate: 2e6, maxDpbMbs: 2376, level: 20 }, + // Level 2 + { maxMacroblocks: 792, maxBitrate: 4e6, maxDpbMbs: 4752, level: 21 }, + // Level 2.1 + { maxMacroblocks: 1620, maxBitrate: 4e6, maxDpbMbs: 8100, level: 22 }, + // Level 2.2 + { maxMacroblocks: 1620, maxBitrate: 1e7, maxDpbMbs: 8100, level: 30 }, + // Level 3 + { maxMacroblocks: 3600, maxBitrate: 14e6, maxDpbMbs: 18e3, level: 31 }, + // Level 3.1 + { maxMacroblocks: 5120, maxBitrate: 2e7, maxDpbMbs: 20480, level: 32 }, + // Level 3.2 + { maxMacroblocks: 8192, maxBitrate: 2e7, maxDpbMbs: 32768, level: 40 }, + // Level 4 + { maxMacroblocks: 8192, maxBitrate: 5e7, maxDpbMbs: 32768, level: 41 }, + // Level 4.1 + { maxMacroblocks: 8704, maxBitrate: 5e7, maxDpbMbs: 34816, level: 42 }, + // Level 4.2 + { maxMacroblocks: 22080, maxBitrate: 135e6, maxDpbMbs: 110400, level: 50 }, + // Level 5 + { maxMacroblocks: 36864, maxBitrate: 24e7, maxDpbMbs: 184320, level: 51 }, + // Level 5.1 + { maxMacroblocks: 36864, maxBitrate: 24e7, maxDpbMbs: 184320, level: 52 }, + // Level 5.2 + { maxMacroblocks: 139264, maxBitrate: 24e7, maxDpbMbs: 696320, level: 60 }, + // Level 6 + { maxMacroblocks: 139264, maxBitrate: 48e7, maxDpbMbs: 696320, level: 61 }, + // Level 6.1 + { maxMacroblocks: 139264, maxBitrate: 8e8, maxDpbMbs: 696320, level: 62 } + // Level 6.2 + ]; const VP9_LEVEL_TABLE = [ { maxPictureSize: 36864, maxBitrate: 2e5, level: 10 }, // Level 1 @@ -708,8 +1164,14 @@ var artplayerProxyMediabunny = (function() { if (aacCodecInfo.isMpeg2) { return "mp4a.67"; } else { - const audioSpecificConfig = parseAacAudioSpecificConfig(codecDescription); - return `mp4a.40.${audioSpecificConfig.objectType}`; + let objectType; + if (aacCodecInfo.objectType !== null) { + objectType = aacCodecInfo.objectType; + } else { + const audioSpecificConfig = parseAacAudioSpecificConfig(codecDescription); + objectType = audioSpecificConfig.objectType; + } + return `mp4a.40.${objectType}`; } } else if (codec === "mp3") { return "mp3"; @@ -719,58 +1181,15 @@ var artplayerProxyMediabunny = (function() { return "vorbis"; } else if (codec === "flac") { return "flac"; + } else if (codec === "ac3") { + return "ac-3"; + } else if (codec === "eac3") { + return "ec-3"; } else if (codec && PCM_AUDIO_CODECS.includes(codec)) { return codec; } throw new TypeError(`Unhandled codec '${codec}'.`); }; - const aacFrequencyTable = [ - 96e3, - 88200, - 64e3, - 48e3, - 44100, - 32e3, - 24e3, - 22050, - 16e3, - 12e3, - 11025, - 8e3, - 7350 - ]; - const aacChannelMap = [-1, 1, 2, 3, 4, 5, 6, 8]; - const parseAacAudioSpecificConfig = (bytes) => { - if (!bytes || bytes.byteLength < 2) { - throw new TypeError("AAC description must be at least 2 bytes long."); - } - const bitstream = new Bitstream(bytes); - let objectType = bitstream.readBits(5); - if (objectType === 31) { - objectType = 32 + bitstream.readBits(6); - } - const frequencyIndex = bitstream.readBits(4); - let sampleRate = null; - if (frequencyIndex === 15) { - sampleRate = bitstream.readBits(24); - } else { - if (frequencyIndex < aacFrequencyTable.length) { - sampleRate = aacFrequencyTable[frequencyIndex]; - } - } - const channelConfiguration = bitstream.readBits(4); - let numberOfChannels = null; - if (channelConfiguration >= 1 && channelConfiguration <= 7) { - numberOfChannels = aacChannelMap[channelConfiguration]; - } - return { - objectType, - frequencyIndex, - sampleRate, - channelConfiguration, - numberOfChannels - }; - }; const OPUS_SAMPLE_RATE = 48e3; const PCM_CODEC_REGEX = /^pcm-([usf])(\d+)+(be)?$/; const parsePcmCodec = (codec) => { @@ -795,12 +1214,318 @@ var artplayerProxyMediabunny = (function() { const silentValue = codec === "pcm-u8" ? 2 ** 7 : 0; return { dataType, sampleSize, littleEndian, silentValue }; }; + const inferCodecFromCodecString = (codecString) => { + if (codecString.startsWith("avc1") || codecString.startsWith("avc3")) { + return "avc"; + } else if (codecString.startsWith("hev1") || codecString.startsWith("hvc1")) { + return "hevc"; + } else if (codecString === "vp8") { + return "vp8"; + } else if (codecString.startsWith("vp09")) { + return "vp9"; + } else if (codecString.startsWith("av01")) { + return "av1"; + } + if (codecString === "mp3" || codecString === "mp4a.69" || codecString === "mp4a.6B" || codecString === "mp4a.6b" || codecString === "mp4a.40.34") { + return "mp3"; + } else if (codecString.startsWith("mp4a.40.") || codecString === "mp4a.67") { + return "aac"; + } else if (codecString === "opus") { + return "opus"; + } else if (codecString === "vorbis") { + return "vorbis"; + } else if (codecString === "flac") { + return "flac"; + } else if (codecString === "ac-3" || codecString === "ac3") { + return "ac3"; + } else if (codecString === "ec-3" || codecString === "eac3") { + return "eac3"; + } else if (codecString === "ulaw") { + return "ulaw"; + } else if (codecString === "alaw") { + return "alaw"; + } else if (PCM_CODEC_REGEX.test(codecString)) { + return codecString; + } + if (codecString === "webvtt") { + return "webvtt"; + } + return null; + }; + const FRAME_HEADER_SIZE = 4; + const SAMPLING_RATES = [44100, 48e3, 32e3]; + const KILOBIT_RATES = [ + // lowSamplingFrequency === 0 + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + // layer = 0 + -1, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + -1, + // layer 1 + -1, + 32, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + 384, + -1, + // layer = 2 + -1, + 32, + 64, + 96, + 128, + 160, + 192, + 224, + 256, + 288, + 320, + 352, + 384, + 416, + 448, + -1, + // layer = 3 + // lowSamplingFrequency === 1 + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + // layer = 0 + -1, + 8, + 16, + 24, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + -1, + // layer = 1 + -1, + 8, + 16, + 24, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + -1, + // layer = 2 + -1, + 32, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + 176, + 192, + 224, + 256, + -1 + // layer = 3 + ]; + const XING = 1483304551; + const INFO = 1231971951; + const computeMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate, padding) => { + if (layer === 0) { + return 0; + } else if (layer === 1) { + return Math.floor(144 * bitrate / (sampleRate << lowSamplingFrequency)) + padding; + } else if (layer === 2) { + return Math.floor(144 * bitrate / sampleRate) + padding; + } else { + return (Math.floor(12 * bitrate / sampleRate) + padding) * 4; + } + }; + const computeAverageMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate) => { + if (layer === 0) { + return 0; + } else if (layer === 1) { + return 144 * bitrate / (sampleRate << lowSamplingFrequency); + } else if (layer === 2) { + return 144 * bitrate / sampleRate; + } else { + return 12 * bitrate / sampleRate * 4; + } + }; + const getXingOffset = (mpegVersionId, channel) => { + return mpegVersionId === 3 ? channel === 3 ? 21 : 36 : channel === 3 ? 13 : 21; + }; + const readMp3FrameHeader = (word, remainingBytes) => { + const firstByte = word >>> 24; + const secondByte = word >>> 16 & 255; + const thirdByte = word >>> 8 & 255; + const fourthByte = word & 255; + if (firstByte !== 255 && secondByte !== 255 && thirdByte !== 255 && fourthByte !== 255) { + return { + header: null, + bytesAdvanced: 4 + }; + } + if (firstByte !== 255) { + return { header: null, bytesAdvanced: 1 }; + } + if ((secondByte & 224) !== 224) { + return { header: null, bytesAdvanced: 1 }; + } + let lowSamplingFrequency = 0; + let mpeg25 = 0; + if (secondByte & 1 << 4) { + lowSamplingFrequency = secondByte & 1 << 3 ? 0 : 1; + } else { + lowSamplingFrequency = 1; + mpeg25 = 1; + } + const mpegVersionId = secondByte >> 3 & 3; + const layer = secondByte >> 1 & 3; + const bitrateIndex = thirdByte >> 4 & 15; + const frequencyIndex = (thirdByte >> 2 & 3) % 3; + const padding = thirdByte >> 1 & 1; + const channel = fourthByte >> 6 & 3; + const modeExtension = fourthByte >> 4 & 3; + const copyright = fourthByte >> 3 & 1; + const original = fourthByte >> 2 & 1; + const emphasis = fourthByte & 3; + const kilobitRate = KILOBIT_RATES[lowSamplingFrequency * 16 * 4 + layer * 16 + bitrateIndex]; + if (kilobitRate === -1) { + return { header: null, bytesAdvanced: 1 }; + } + const bitrate = kilobitRate * 1e3; + const sampleRate = SAMPLING_RATES[frequencyIndex] >> lowSamplingFrequency + mpeg25; + const frameLength = computeMp3FrameSize(lowSamplingFrequency, layer, bitrate, sampleRate, padding); + if (remainingBytes !== null && remainingBytes < frameLength) { + return { header: null, bytesAdvanced: 1 }; + } + let audioSamplesInFrame; + if (mpegVersionId === 3) { + audioSamplesInFrame = layer === 3 ? 384 : 1152; + } else { + if (layer === 3) { + audioSamplesInFrame = 384; + } else if (layer === 2) { + audioSamplesInFrame = 1152; + } else { + audioSamplesInFrame = 576; + } + } + return { + header: { + totalSize: frameLength, + mpegVersionId, + lowSamplingFrequency, + layer, + bitrate, + frequencyIndex, + sampleRate, + channel, + modeExtension, + copyright, + original, + emphasis, + audioSamplesInFrame + }, + bytesAdvanced: 1 + }; + }; + const decodeSynchsafe = (synchsafed) => { + let mask = 2130706432; + let unsynchsafed = 0; + while (mask !== 0) { + unsynchsafed >>= 1; + unsynchsafed |= synchsafed & mask; + mask >>= 8; + } + return unsynchsafed; + }; + var XingFlags; + (function(XingFlags2) { + XingFlags2[XingFlags2["FrameCount"] = 1] = "FrameCount"; + XingFlags2[XingFlags2["FileSize"] = 2] = "FileSize"; + XingFlags2[XingFlags2["Toc"] = 4] = "Toc"; + })(XingFlags || (XingFlags = {})); + const AC3_SAMPLE_RATES = [48e3, 44100, 32e3]; + const EAC3_REDUCED_SAMPLE_RATES = [24e3, 22050, 16e3]; var AvcNalUnitType; (function(AvcNalUnitType2) { + AvcNalUnitType2[AvcNalUnitType2["NON_IDR_SLICE"] = 1] = "NON_IDR_SLICE"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPA"] = 2] = "SLICE_DPA"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPB"] = 3] = "SLICE_DPB"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPC"] = 4] = "SLICE_DPC"; AvcNalUnitType2[AvcNalUnitType2["IDR"] = 5] = "IDR"; AvcNalUnitType2[AvcNalUnitType2["SEI"] = 6] = "SEI"; AvcNalUnitType2[AvcNalUnitType2["SPS"] = 7] = "SPS"; AvcNalUnitType2[AvcNalUnitType2["PPS"] = 8] = "PPS"; + AvcNalUnitType2[AvcNalUnitType2["AUD"] = 9] = "AUD"; AvcNalUnitType2[AvcNalUnitType2["SPS_EXT"] = 13] = "SPS_EXT"; })(AvcNalUnitType || (AvcNalUnitType = {})); var HevcNalUnitType; @@ -812,48 +1537,46 @@ var artplayerProxyMediabunny = (function() { HevcNalUnitType2[HevcNalUnitType2["VPS_NUT"] = 32] = "VPS_NUT"; HevcNalUnitType2[HevcNalUnitType2["SPS_NUT"] = 33] = "SPS_NUT"; HevcNalUnitType2[HevcNalUnitType2["PPS_NUT"] = 34] = "PPS_NUT"; + HevcNalUnitType2[HevcNalUnitType2["AUD_NUT"] = 35] = "AUD_NUT"; HevcNalUnitType2[HevcNalUnitType2["PREFIX_SEI_NUT"] = 39] = "PREFIX_SEI_NUT"; HevcNalUnitType2[HevcNalUnitType2["SUFFIX_SEI_NUT"] = 40] = "SUFFIX_SEI_NUT"; })(HevcNalUnitType || (HevcNalUnitType = {})); - const findNalUnitsInAnnexB = (packetData) => { - const nalUnits = []; + const iterateNalUnitsInAnnexB = function* (packetData) { let i = 0; - while (i < packetData.length) { - let startCodePos = -1; - let startCodeLength = 0; - for (let j = i; j < packetData.length - 3; j++) { - if (packetData[j] === 0 && packetData[j + 1] === 0 && packetData[j + 2] === 1) { - startCodePos = j; - startCodeLength = 3; - break; - } - if (j < packetData.length - 4 && packetData[j] === 0 && packetData[j + 1] === 0 && packetData[j + 2] === 0 && packetData[j + 3] === 1) { - startCodePos = j; - startCodeLength = 4; - break; - } - } - if (startCodePos === -1) { + let nalStart = -1; + while (i < packetData.length - 2) { + const zeroIndex = packetData.indexOf(0, i); + if (zeroIndex === -1 || zeroIndex >= packetData.length - 2) { break; } - if (i > 0 && startCodePos > i) { - const nalData = packetData.subarray(i, startCodePos); - if (nalData.length > 0) { - nalUnits.push(nalData); - } + i = zeroIndex; + let startCodeLength = 0; + if (i + 3 < packetData.length && packetData[i + 1] === 0 && packetData[i + 2] === 0 && packetData[i + 3] === 1) { + startCodeLength = 4; + } else if (packetData[i + 1] === 0 && packetData[i + 2] === 1) { + startCodeLength = 3; } - i = startCodePos + startCodeLength; - } - if (i < packetData.length) { - const nalData = packetData.subarray(i); - if (nalData.length > 0) { - nalUnits.push(nalData); + if (startCodeLength === 0) { + i++; + continue; } + if (nalStart !== -1 && i > nalStart) { + yield { + offset: nalStart, + length: i - nalStart + }; + } + nalStart = i + startCodeLength; + i = nalStart; + } + if (nalStart !== -1 && nalStart < packetData.length) { + yield { + offset: nalStart, + length: packetData.length - nalStart + }; } - return nalUnits; }; - const findNalUnitsInLengthPrefixed = (packetData, lengthSize) => { - const nalUnits = []; + const iterateNalUnitsInLengthPrefixed = function* (packetData, lengthSize) { let offset = 0; const dataView = new DataView(packetData.buffer, packetData.byteOffset, packetData.byteLength); while (offset + lengthSize <= packetData.length) { @@ -864,18 +1587,30 @@ var artplayerProxyMediabunny = (function() { nalUnitLength = dataView.getUint16(offset, false); } else if (lengthSize === 3) { nalUnitLength = getUint24(dataView, offset, false); - } else if (lengthSize === 4) { - nalUnitLength = dataView.getUint32(offset, false); } else { - assertNever(lengthSize); - assert(false); + assert(lengthSize === 4); + nalUnitLength = dataView.getUint32(offset, false); } offset += lengthSize; - const nalUnit = packetData.subarray(offset, offset + nalUnitLength); - nalUnits.push(nalUnit); + yield { + offset, + length: nalUnitLength + }; offset += nalUnitLength; } - return nalUnits; + }; + const iterateAvcNalUnits = (packetData, decoderConfig) => { + if (decoderConfig.description) { + const bytes = toUint8Array(decoderConfig.description); + const lengthSizeMinusOne = bytes[4] & 3; + const lengthSize = lengthSizeMinusOne + 1; + return iterateNalUnitsInLengthPrefixed(packetData, lengthSize); + } else { + return iterateNalUnitsInAnnexB(packetData); + } + }; + const extractNalUnitTypeForAvc = (byte) => { + return byte & 31; }; const removeEmulationPreventionBytes = (data) => { const result = []; @@ -929,16 +1664,6 @@ var artplayerProxyMediabunny = (function() { } return result; }; - const extractAvcNalUnits = (packetData, decoderConfig) => { - if (decoderConfig.description) { - const bytes = toUint8Array(decoderConfig.description); - const lengthSizeMinusOne = bytes[4] & 3; - const lengthSize = lengthSizeMinusOne + 1; - return findNalUnitsInLengthPrefixed(packetData, lengthSize); - } else { - return findNalUnitsInAnnexB(packetData); - } - }; const concatAvcNalUnits = (nalUnits, decoderConfig) => { if (decoderConfig.description) { const bytes = toUint8Array(decoderConfig.description); @@ -949,15 +1674,22 @@ var artplayerProxyMediabunny = (function() { return concatNalUnitsInAnnexB(nalUnits); } }; - const extractNalUnitTypeForAvc = (data) => { - return data[0] & 31; - }; const extractAvcDecoderConfigurationRecord = (packetData) => { try { - const nalUnits = findNalUnitsInAnnexB(packetData); - const spsUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.SPS); - const ppsUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.PPS); - const spsExtUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.SPS_EXT); + const spsUnits = []; + const ppsUnits = []; + const spsExtUnits = []; + for (const loc of iterateNalUnitsInAnnexB(packetData)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); + const type = extractNalUnitTypeForAvc(nalUnit[0]); + if (type === AvcNalUnitType.SPS) { + spsUnits.push(nalUnit); + } else if (type === AvcNalUnitType.PPS) { + ppsUnits.push(nalUnit); + } else if (type === AvcNalUnitType.SPS_EXT) { + spsExtUnits.push(nalUnit); + } + } if (spsUnits.length === 0) { return null; } @@ -1048,6 +1780,24 @@ var artplayerProxyMediabunny = (function() { return null; } }; + const AVC_HEVC_ASPECT_RATIO_IDC_TABLE = { + 1: { num: 1, den: 1 }, + 2: { num: 12, den: 11 }, + 3: { num: 10, den: 11 }, + 4: { num: 16, den: 11 }, + 5: { num: 40, den: 33 }, + 6: { num: 24, den: 11 }, + 7: { num: 20, den: 11 }, + 8: { num: 32, den: 11 }, + 9: { num: 80, den: 33 }, + 10: { num: 18, den: 11 }, + 11: { num: 15, den: 11 }, + 12: { num: 64, den: 33 }, + 13: { num: 160, den: 99 }, + 14: { num: 4, den: 3 }, + 15: { num: 3, den: 2 }, + 16: { num: 2, den: 1 } + }; const parseAvcSps = (sps) => { try { const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); @@ -1061,13 +1811,14 @@ var artplayerProxyMediabunny = (function() { const constraintFlags = bitstream.readAlignedByte(); const levelIdc = bitstream.readAlignedByte(); readExpGolomb(bitstream); - let chromaFormatIdc = null; - let bitDepthLumaMinus8 = null; - let bitDepthChromaMinus8 = null; + let chromaFormatIdc = 1; + let bitDepthLumaMinus8 = 0; + let bitDepthChromaMinus8 = 0; + let separateColourPlaneFlag = 0; if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) { chromaFormatIdc = readExpGolomb(bitstream); if (chromaFormatIdc === 3) { - bitstream.skipBits(1); + separateColourPlaneFlag = bitstream.readBits(1); } bitDepthLumaMinus8 = readExpGolomb(bitstream); bitDepthChromaMinus8 = readExpGolomb(bitstream); @@ -1106,9 +1857,128 @@ var artplayerProxyMediabunny = (function() { } readExpGolomb(bitstream); bitstream.skipBits(1); - readExpGolomb(bitstream); - readExpGolomb(bitstream); + const picWidthInMbsMinus1 = readExpGolomb(bitstream); + const picHeightInMapUnitsMinus1 = readExpGolomb(bitstream); + const codedWidth = 16 * (picWidthInMbsMinus1 + 1); + const codedHeight = 16 * (picHeightInMapUnitsMinus1 + 1); + let displayWidth = codedWidth; + let displayHeight = codedHeight; const frameMbsOnlyFlag = bitstream.readBits(1); + if (!frameMbsOnlyFlag) { + bitstream.skipBits(1); + } + bitstream.skipBits(1); + const frameCroppingFlag = bitstream.readBits(1); + if (frameCroppingFlag) { + const frameCropLeftOffset = readExpGolomb(bitstream); + const frameCropRightOffset = readExpGolomb(bitstream); + const frameCropTopOffset = readExpGolomb(bitstream); + const frameCropBottomOffset = readExpGolomb(bitstream); + let cropUnitX; + let cropUnitY; + const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0; + if (chromaArrayType === 0) { + cropUnitX = 1; + cropUnitY = 2 - frameMbsOnlyFlag; + } else { + const subWidthC = chromaFormatIdc === 3 ? 1 : 2; + const subHeightC = chromaFormatIdc === 1 ? 2 : 1; + cropUnitX = subWidthC; + cropUnitY = subHeightC * (2 - frameMbsOnlyFlag); + } + displayWidth -= cropUnitX * (frameCropLeftOffset + frameCropRightOffset); + displayHeight -= cropUnitY * (frameCropTopOffset + frameCropBottomOffset); + } + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let pixelAspectRatio = { num: 1, den: 1 }; + let numReorderFrames = null; + let maxDecFrameBuffering = null; + const vuiParametersPresentFlag = bitstream.readBits(1); + if (vuiParametersPresentFlag) { + const aspectRatioInfoPresentFlag = bitstream.readBits(1); + if (aspectRatioInfoPresentFlag) { + const aspectRatioIdc = bitstream.readBits(8); + if (aspectRatioIdc === 255) { + pixelAspectRatio = { + num: bitstream.readBits(16), + den: bitstream.readBits(16) + }; + } else { + const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspectRatioIdc]; + if (aspectRatio) { + pixelAspectRatio = aspectRatio; + } + } + } + const overscanInfoPresentFlag = bitstream.readBits(1); + if (overscanInfoPresentFlag) { + bitstream.skipBits(1); + } + const videoSignalTypePresentFlag = bitstream.readBits(1); + if (videoSignalTypePresentFlag) { + bitstream.skipBits(3); + fullRangeFlag = bitstream.readBits(1); + const colourDescriptionPresentFlag = bitstream.readBits(1); + if (colourDescriptionPresentFlag) { + colourPrimaries = bitstream.readBits(8); + transferCharacteristics = bitstream.readBits(8); + matrixCoefficients = bitstream.readBits(8); + } + } + const chromaLocInfoPresentFlag = bitstream.readBits(1); + if (chromaLocInfoPresentFlag) { + readExpGolomb(bitstream); + readExpGolomb(bitstream); + } + const timingInfoPresentFlag = bitstream.readBits(1); + if (timingInfoPresentFlag) { + bitstream.skipBits(32); + bitstream.skipBits(32); + bitstream.skipBits(1); + } + const nalHrdParametersPresentFlag = bitstream.readBits(1); + if (nalHrdParametersPresentFlag) { + skipAvcHrdParameters(bitstream); + } + const vclHrdParametersPresentFlag = bitstream.readBits(1); + if (vclHrdParametersPresentFlag) { + skipAvcHrdParameters(bitstream); + } + if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) { + bitstream.skipBits(1); + } + bitstream.skipBits(1); + const bitstreamRestrictionFlag = bitstream.readBits(1); + if (bitstreamRestrictionFlag) { + bitstream.skipBits(1); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + numReorderFrames = readExpGolomb(bitstream); + maxDecFrameBuffering = readExpGolomb(bitstream); + } + } + if (numReorderFrames === null) { + assert(maxDecFrameBuffering === null); + const constraintSet3Flag = constraintFlags & 16; + if ((profileIdc === 44 || profileIdc === 86 || profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244) && constraintSet3Flag) { + numReorderFrames = 0; + maxDecFrameBuffering = 0; + } else { + const picWidthInMbs = picWidthInMbsMinus1 + 1; + const picHeightInMapUnits = picHeightInMapUnitsMinus1 + 1; + const frameHeightInMbs = (2 - frameMbsOnlyFlag) * picHeightInMapUnits; + const levelInfo = AVC_LEVEL_TABLE.find((x) => x.level >= levelIdc) ?? last(AVC_LEVEL_TABLE); + const maxDpbFrames = Math.min(Math.floor(levelInfo.maxDpbMbs / (picWidthInMbs * frameHeightInMbs)), 16); + numReorderFrames = maxDpbFrames; + maxDecFrameBuffering = maxDpbFrames; + } + } + assert(maxDecFrameBuffering !== null); return { profileIdc, constraintFlags, @@ -1116,62 +1986,106 @@ var artplayerProxyMediabunny = (function() { frameMbsOnlyFlag, chromaFormatIdc, bitDepthLumaMinus8, - bitDepthChromaMinus8 + bitDepthChromaMinus8, + codedWidth, + codedHeight, + displayWidth, + displayHeight, + pixelAspectRatio, + colourPrimaries, + matrixCoefficients, + transferCharacteristics, + fullRangeFlag, + numReorderFrames, + maxDecFrameBuffering }; } catch (error) { console.error("Error parsing AVC SPS:", error); return null; } }; - const extractHevcNalUnits = (packetData, decoderConfig) => { + const skipAvcHrdParameters = (bitstream) => { + const cpb_cnt_minus1 = readExpGolomb(bitstream); + bitstream.skipBits(4); + bitstream.skipBits(4); + for (let i = 0; i <= cpb_cnt_minus1; i++) { + readExpGolomb(bitstream); + readExpGolomb(bitstream); + bitstream.skipBits(1); + } + bitstream.skipBits(5); + bitstream.skipBits(5); + bitstream.skipBits(5); + bitstream.skipBits(5); + }; + const concatHevcNalUnits = (nalUnits, decoderConfig) => { if (decoderConfig.description) { const bytes = toUint8Array(decoderConfig.description); const lengthSizeMinusOne = bytes[21] & 3; const lengthSize = lengthSizeMinusOne + 1; - return findNalUnitsInLengthPrefixed(packetData, lengthSize); + return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize); } else { - return findNalUnitsInAnnexB(packetData); + return concatNalUnitsInAnnexB(nalUnits); } }; - const extractNalUnitTypeForHevc = (data) => { - return data[0] >> 1 & 63; + const iterateHevcNalUnits = (packetData, decoderConfig) => { + if (decoderConfig.description) { + const bytes = toUint8Array(decoderConfig.description); + const lengthSizeMinusOne = bytes[21] & 3; + const lengthSize = lengthSizeMinusOne + 1; + return iterateNalUnitsInLengthPrefixed(packetData, lengthSize); + } else { + return iterateNalUnitsInAnnexB(packetData); + } }; - const extractHevcDecoderConfigurationRecord = (packetData) => { + const extractNalUnitTypeForHevc = (byte) => { + return byte >> 1 & 63; + }; + const parseHevcSps = (sps) => { try { - const nalUnits = findNalUnitsInAnnexB(packetData); - const vpsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.VPS_NUT); - const spsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.SPS_NUT); - const ppsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.PPS_NUT); - const seiUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.PREFIX_SEI_NUT || extractNalUnitTypeForHevc(unit) === HevcNalUnitType.SUFFIX_SEI_NUT); - if (spsUnits.length === 0 || ppsUnits.length === 0) - return null; - const sps = spsUnits[0]; const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); bitstream.skipBits(16); bitstream.readBits(4); - const sps_max_sub_layers_minus1 = bitstream.readBits(3); - const sps_temporal_id_nesting_flag = bitstream.readBits(1); - const { general_profile_space, general_tier_flag, general_profile_idc, general_profile_compatibility_flags, general_constraint_indicator_flags, general_level_idc } = parseProfileTierLevel(bitstream, sps_max_sub_layers_minus1); + const spsMaxSubLayersMinus1 = bitstream.readBits(3); + const spsTemporalIdNestingFlag = bitstream.readBits(1); + const { general_profile_space, general_tier_flag, general_profile_idc, general_profile_compatibility_flags, general_constraint_indicator_flags, general_level_idc } = parseProfileTierLevel(bitstream, spsMaxSubLayersMinus1); readExpGolomb(bitstream); - const chroma_format_idc = readExpGolomb(bitstream); - if (chroma_format_idc === 3) - bitstream.skipBits(1); - readExpGolomb(bitstream); - readExpGolomb(bitstream); - if (bitstream.readBits(1)) { - readExpGolomb(bitstream); - readExpGolomb(bitstream); - readExpGolomb(bitstream); - readExpGolomb(bitstream); + const chromaFormatIdc = readExpGolomb(bitstream); + let separateColourPlaneFlag = 0; + if (chromaFormatIdc === 3) { + separateColourPlaneFlag = bitstream.readBits(1); } - const bit_depth_luma_minus8 = readExpGolomb(bitstream); - const bit_depth_chroma_minus8 = readExpGolomb(bitstream); + const picWidthInLumaSamples = readExpGolomb(bitstream); + const picHeightInLumaSamples = readExpGolomb(bitstream); + let displayWidth = picWidthInLumaSamples; + let displayHeight = picHeightInLumaSamples; + if (bitstream.readBits(1)) { + const confWinLeftOffset = readExpGolomb(bitstream); + const confWinRightOffset = readExpGolomb(bitstream); + const confWinTopOffset = readExpGolomb(bitstream); + const confWinBottomOffset = readExpGolomb(bitstream); + let subWidthC = 1; + let subHeightC = 1; + const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0; + if (chromaArrayType === 1) { + subWidthC = 2; + subHeightC = 2; + } else if (chromaArrayType === 2) { + subWidthC = 2; + subHeightC = 1; + } + displayWidth -= (confWinLeftOffset + confWinRightOffset) * subWidthC; + displayHeight -= (confWinTopOffset + confWinBottomOffset) * subHeightC; + } + const bitDepthLumaMinus8 = readExpGolomb(bitstream); + const bitDepthChromaMinus8 = readExpGolomb(bitstream); readExpGolomb(bitstream); - const sps_sub_layer_ordering_info_present_flag = bitstream.readBits(1); - const maxNum = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; - for (let i = maxNum; i <= sps_max_sub_layers_minus1; i++) { - readExpGolomb(bitstream); + const spsSubLayerOrderingInfoPresentFlag = bitstream.readBits(1); + const startI = spsSubLayerOrderingInfoPresentFlag ? 0 : spsMaxSubLayersMinus1; + let spsMaxNumReorderPics = 0; + for (let i = startI; i <= spsMaxSubLayersMinus1; i++) { readExpGolomb(bitstream); + spsMaxNumReorderPics = readExpGolomb(bitstream); readExpGolomb(bitstream); } readExpGolomb(bitstream); @@ -1194,21 +2108,83 @@ var artplayerProxyMediabunny = (function() { readExpGolomb(bitstream); bitstream.skipBits(1); } - const num_short_term_ref_pic_sets = readExpGolomb(bitstream); - skipAllStRefPicSets(bitstream, num_short_term_ref_pic_sets); + const numShortTermRefPicSets = readExpGolomb(bitstream); + skipAllStRefPicSets(bitstream, numShortTermRefPicSets); if (bitstream.readBits(1)) { - const num_long_term_ref_pics_sps = readExpGolomb(bitstream); - for (let i = 0; i < num_long_term_ref_pics_sps; i++) { + const numLongTermRefPicsSps = readExpGolomb(bitstream); + for (let i = 0; i < numLongTermRefPicsSps; i++) { readExpGolomb(bitstream); bitstream.skipBits(1); } } bitstream.skipBits(1); bitstream.skipBits(1); - let min_spatial_segmentation_idc = 0; + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let minSpatialSegmentationIdc = 0; + let pixelAspectRatio = { num: 1, den: 1 }; if (bitstream.readBits(1)) { - min_spatial_segmentation_idc = parseVuiForMinSpatialSegmentationIdc(bitstream, sps_max_sub_layers_minus1); + const vui = parseHevcVui(bitstream, spsMaxSubLayersMinus1); + pixelAspectRatio = vui.pixelAspectRatio; + colourPrimaries = vui.colourPrimaries; + transferCharacteristics = vui.transferCharacteristics; + matrixCoefficients = vui.matrixCoefficients; + fullRangeFlag = vui.fullRangeFlag; + minSpatialSegmentationIdc = vui.minSpatialSegmentationIdc; } + return { + displayWidth, + displayHeight, + pixelAspectRatio, + colourPrimaries, + transferCharacteristics, + matrixCoefficients, + fullRangeFlag, + maxDecFrameBuffering: spsMaxNumReorderPics + 1, + spsMaxSubLayersMinus1, + spsTemporalIdNestingFlag, + generalProfileSpace: general_profile_space, + generalTierFlag: general_tier_flag, + generalProfileIdc: general_profile_idc, + generalProfileCompatibilityFlags: general_profile_compatibility_flags, + generalConstraintIndicatorFlags: general_constraint_indicator_flags, + generalLevelIdc: general_level_idc, + chromaFormatIdc, + bitDepthLumaMinus8, + bitDepthChromaMinus8, + minSpatialSegmentationIdc + }; + } catch (error) { + console.error("Error parsing HEVC SPS:", error); + return null; + } + }; + const extractHevcDecoderConfigurationRecord = (packetData) => { + try { + const vpsUnits = []; + const spsUnits = []; + const ppsUnits = []; + const seiUnits = []; + for (const loc of iterateNalUnitsInAnnexB(packetData)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); + const type = extractNalUnitTypeForHevc(nalUnit[0]); + if (type === HevcNalUnitType.VPS_NUT) { + vpsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.SPS_NUT) { + spsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.PPS_NUT) { + ppsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.PREFIX_SEI_NUT || type === HevcNalUnitType.SUFFIX_SEI_NUT) { + seiUnits.push(nalUnit); + } + } + if (spsUnits.length === 0 || ppsUnits.length === 0) + return null; + const spsInfo = parseHevcSps(spsUnits[0]); + if (!spsInfo) + return null; let parallelismType = 0; if (ppsUnits.length > 0) { const pps = ppsUnits[0]; @@ -1271,28 +2247,28 @@ var artplayerProxyMediabunny = (function() { ...seiUnits.length ? [ { arrayCompleteness: 1, - nalUnitType: extractNalUnitTypeForHevc(seiUnits[0]), + nalUnitType: extractNalUnitTypeForHevc(seiUnits[0][0]), nalUnits: seiUnits } ] : [] ]; const record = { configurationVersion: 1, - generalProfileSpace: general_profile_space, - generalTierFlag: general_tier_flag, - generalProfileIdc: general_profile_idc, - generalProfileCompatibilityFlags: general_profile_compatibility_flags, - generalConstraintIndicatorFlags: general_constraint_indicator_flags, - generalLevelIdc: general_level_idc, - minSpatialSegmentationIdc: min_spatial_segmentation_idc, + generalProfileSpace: spsInfo.generalProfileSpace, + generalTierFlag: spsInfo.generalTierFlag, + generalProfileIdc: spsInfo.generalProfileIdc, + generalProfileCompatibilityFlags: spsInfo.generalProfileCompatibilityFlags, + generalConstraintIndicatorFlags: spsInfo.generalConstraintIndicatorFlags, + generalLevelIdc: spsInfo.generalLevelIdc, + minSpatialSegmentationIdc: spsInfo.minSpatialSegmentationIdc, parallelismType, - chromaFormatIdc: chroma_format_idc, - bitDepthLumaMinus8: bit_depth_luma_minus8, - bitDepthChromaMinus8: bit_depth_chroma_minus8, + chromaFormatIdc: spsInfo.chromaFormatIdc, + bitDepthLumaMinus8: spsInfo.bitDepthLumaMinus8, + bitDepthChromaMinus8: spsInfo.bitDepthChromaMinus8, avgFrameRate: 0, constantFrameRate: 0, - numTemporalLayers: sps_max_sub_layers_minus1 + 1, - temporalIdNested: sps_temporal_id_nesting_flag, + numTemporalLayers: spsInfo.spsMaxSubLayersMinus1 + 1, + temporalIdNested: spsInfo.spsTemporalIdNestingFlag, lengthSizeMinusOne: 3, arrays }; @@ -1404,12 +2380,25 @@ var artplayerProxyMediabunny = (function() { } return NumDeltaPocsThis; }; - const parseVuiForMinSpatialSegmentationIdc = (bitstream, sps_max_sub_layers_minus1) => { + const parseHevcVui = (bitstream, sps_max_sub_layers_minus1) => { + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let minSpatialSegmentationIdc = 0; + let pixelAspectRatio = { num: 1, den: 1 }; if (bitstream.readBits(1)) { const aspect_ratio_idc = bitstream.readBits(8); if (aspect_ratio_idc === 255) { - bitstream.readBits(16); - bitstream.readBits(16); + pixelAspectRatio = { + num: bitstream.readBits(16), + den: bitstream.readBits(16) + }; + } else { + const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspect_ratio_idc]; + if (aspectRatio) { + pixelAspectRatio = aspectRatio; + } } } if (bitstream.readBits(1)) { @@ -1417,11 +2406,11 @@ var artplayerProxyMediabunny = (function() { } if (bitstream.readBits(1)) { bitstream.readBits(3); - bitstream.readBits(1); + fullRangeFlag = bitstream.readBits(1); if (bitstream.readBits(1)) { - bitstream.readBits(8); - bitstream.readBits(8); - bitstream.readBits(8); + colourPrimaries = bitstream.readBits(8); + transferCharacteristics = bitstream.readBits(8); + matrixCoefficients = bitstream.readBits(8); } } if (bitstream.readBits(1)) { @@ -1444,23 +2433,29 @@ var artplayerProxyMediabunny = (function() { readExpGolomb(bitstream); } if (bitstream.readBits(1)) { - skipHrdParameters(bitstream, true, sps_max_sub_layers_minus1); + skipHevcHrdParameters(bitstream, true, sps_max_sub_layers_minus1); } } if (bitstream.readBits(1)) { bitstream.readBits(1); bitstream.readBits(1); bitstream.readBits(1); - const min_spatial_segmentation_idc = readExpGolomb(bitstream); + minSpatialSegmentationIdc = readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); - return min_spatial_segmentation_idc; } - return 0; + return { + pixelAspectRatio, + colourPrimaries, + transferCharacteristics, + matrixCoefficients, + fullRangeFlag, + minSpatialSegmentationIdc + }; }; - const skipHrdParameters = (bitstream, commonInfPresentFlag, maxNumSubLayersMinus1) => { + const skipHevcHrdParameters = (bitstream, commonInfPresentFlag, maxNumSubLayersMinus1) => { let nal_hrd_parameters_present_flag = false; let vcl_hrd_parameters_present_flag = false; let sub_pic_hrd_params_present_flag = false; @@ -1521,6 +2516,78 @@ var artplayerProxyMediabunny = (function() { bitstream.readBits(1); } }; + var HevcNaluOrderState; + (function(HevcNaluOrderState2) { + HevcNaluOrderState2[HevcNaluOrderState2["audAllowed"] = 0] = "audAllowed"; + HevcNaluOrderState2[HevcNaluOrderState2["beforeFirstVcl"] = 1] = "beforeFirstVcl"; + HevcNaluOrderState2[HevcNaluOrderState2["afterFirstVcl"] = 2] = "afterFirstVcl"; + HevcNaluOrderState2[HevcNaluOrderState2["eoBitstreamAllowed"] = 3] = "eoBitstreamAllowed"; + HevcNaluOrderState2[HevcNaluOrderState2["noMoreDataAllowed"] = 4] = "noMoreDataAllowed"; + })(HevcNaluOrderState || (HevcNaluOrderState = {})); + const sanitizeHevcPacketForChromium = (packetData, decoderConfig) => { + const removedNalUnits = /* @__PURE__ */ new Set(); + let orderState = HevcNaluOrderState.audAllowed; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + if (orderState === HevcNaluOrderState.noMoreDataAllowed) { + removedNalUnits.add(loc.offset); + continue; + } + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (orderState === HevcNaluOrderState.eoBitstreamAllowed && type !== 37) { + removedNalUnits.add(loc.offset); + continue; + } + let remove = false; + if (type === 35) { + if (orderState > HevcNaluOrderState.audAllowed) { + remove = true; + } else { + orderState = HevcNaluOrderState.beforeFirstVcl; + } + } else if (type <= 31) { + if (orderState > HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.afterFirstVcl; + } + } else if (type === 36) { + if (orderState !== HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.eoBitstreamAllowed; + } + } else if (type === 37) { + if (orderState < HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.noMoreDataAllowed; + } + } else if (type === 32 || type === 33 || type === 34 || type === 39 || type >= 41 && type <= 44 || type >= 48 && type <= 55) { + if (orderState > HevcNaluOrderState.beforeFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.beforeFirstVcl; + } + } else if (type === 38 || type === 40 || type >= 45 && type <= 47 || type >= 56 && type <= 63) { + if (orderState < HevcNaluOrderState.afterFirstVcl) { + remove = true; + } + } + if (remove) { + removedNalUnits.add(loc.offset); + } + } + if (removedNalUnits.size === 0) { + return null; + } + const filteredNalUnits = []; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + if (!removedNalUnits.has(loc.offset)) { + filteredNalUnits.push(packetData.subarray(loc.offset, loc.offset + loc.length)); + } + } + return concatHevcNalUnits(filteredNalUnits, decoderConfig); + }; const extractVp9CodecInfoFromPacket = (packet) => { const bitstream = new Bitstream(packet); const frameMarker = bitstream.readBits(2); @@ -1925,14 +2992,17 @@ var artplayerProxyMediabunny = (function() { const determineVideoPacketType = (codec, decoderConfig, packetData) => { switch (codec) { case "avc": { - const nalUnits = extractAvcNalUnits(packetData, decoderConfig); - let isKeyframe = nalUnits.some((x) => extractNalUnitTypeForAvc(x) === AvcNalUnitType.IDR); - if (!isKeyframe && (!isChromium() || getChromiumVersion() >= 144)) { - for (const nalUnit of nalUnits) { - const type = extractNalUnitTypeForAvc(nalUnit); - if (type !== AvcNalUnitType.SEI) { - continue; - } + for (const loc of iterateAvcNalUnits(packetData, decoderConfig)) { + const nalTypeByte = packetData[loc.offset]; + const type = extractNalUnitTypeForAvc(nalTypeByte); + if (type >= AvcNalUnitType.NON_IDR_SLICE && type <= AvcNalUnitType.SLICE_DPC) { + return "delta"; + } + if (type === AvcNalUnitType.IDR) { + return "key"; + } + if (type === AvcNalUnitType.SEI && (!isChromium() || getChromiumVersion() >= 144)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); const bytes = removeEmulationPreventionBytes(nalUnit); let pos = 1; do { @@ -1963,23 +3033,26 @@ var artplayerProxyMediabunny = (function() { const recoveryFrameCount = readExpGolomb(bitstream); const exactMatchFlag = bitstream.readBits(1); if (recoveryFrameCount === 0 && exactMatchFlag === 1) { - isKeyframe = true; - break; + return "key"; } } pos += payloadSize; } while (pos < bytes.length - 1); } } - return isKeyframe ? "key" : "delta"; + return "delta"; } case "hevc": { - const nalUnits = extractHevcNalUnits(packetData, decoderConfig); - const isKeyframe = nalUnits.some((x) => { - const type = extractNalUnitTypeForHevc(x); - return HevcNalUnitType.BLA_W_LP <= type && type <= HevcNalUnitType.RSV_IRAP_VCL23; - }); - return isKeyframe ? "key" : "delta"; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (type < HevcNalUnitType.BLA_W_LP) { + return "delta"; + } + if (type <= HevcNalUnitType.RSV_IRAP_VCL23) { + return "key"; + } + } + return "delta"; } case "vp8": { const frameType = packetData[0] & 1; @@ -2179,13 +3252,290 @@ var artplayerProxyMediabunny = (function() { } } }; + const AC3_ACMOD_CHANNEL_COUNTS = [2, 1, 2, 3, 3, 4, 4, 5]; + const parseAc3SyncFrame = (data) => { + if (data.length < 7) { + return null; + } + if (data[0] !== 11 || data[1] !== 119) { + return null; + } + const bitstream = new Bitstream(data); + bitstream.skipBits(16); + bitstream.skipBits(16); + const fscod = bitstream.readBits(2); + if (fscod === 3) { + return null; + } + const frmsizecod = bitstream.readBits(6); + const bsid = bitstream.readBits(5); + if (bsid > 8) { + return null; + } + const bsmod = bitstream.readBits(3); + const acmod = bitstream.readBits(3); + if ((acmod & 1) !== 0 && acmod !== 1) { + bitstream.skipBits(2); + } + if ((acmod & 4) !== 0) { + bitstream.skipBits(2); + } + if (acmod === 2) { + bitstream.skipBits(2); + } + const lfeon = bitstream.readBits(1); + const bitRateCode = Math.floor(frmsizecod / 2); + return { fscod, bsid, bsmod, acmod, lfeon, bitRateCode }; + }; + const AC3_FRAME_SIZES = [ + // frmsizecod, [48kHz, 44.1kHz, 32kHz] in bytes + 64 * 2, + 69 * 2, + 96 * 2, + 64 * 2, + 70 * 2, + 96 * 2, + 80 * 2, + 87 * 2, + 120 * 2, + 80 * 2, + 88 * 2, + 120 * 2, + 96 * 2, + 104 * 2, + 144 * 2, + 96 * 2, + 105 * 2, + 144 * 2, + 112 * 2, + 121 * 2, + 168 * 2, + 112 * 2, + 122 * 2, + 168 * 2, + 128 * 2, + 139 * 2, + 192 * 2, + 128 * 2, + 140 * 2, + 192 * 2, + 160 * 2, + 174 * 2, + 240 * 2, + 160 * 2, + 175 * 2, + 240 * 2, + 192 * 2, + 208 * 2, + 288 * 2, + 192 * 2, + 209 * 2, + 288 * 2, + 224 * 2, + 243 * 2, + 336 * 2, + 224 * 2, + 244 * 2, + 336 * 2, + 256 * 2, + 278 * 2, + 384 * 2, + 256 * 2, + 279 * 2, + 384 * 2, + 320 * 2, + 348 * 2, + 480 * 2, + 320 * 2, + 349 * 2, + 480 * 2, + 384 * 2, + 417 * 2, + 576 * 2, + 384 * 2, + 418 * 2, + 576 * 2, + 448 * 2, + 487 * 2, + 672 * 2, + 448 * 2, + 488 * 2, + 672 * 2, + 512 * 2, + 557 * 2, + 768 * 2, + 512 * 2, + 558 * 2, + 768 * 2, + 640 * 2, + 696 * 2, + 960 * 2, + 640 * 2, + 697 * 2, + 960 * 2, + 768 * 2, + 835 * 2, + 1152 * 2, + 768 * 2, + 836 * 2, + 1152 * 2, + 896 * 2, + 975 * 2, + 1344 * 2, + 896 * 2, + 976 * 2, + 1344 * 2, + 1024 * 2, + 1114 * 2, + 1536 * 2, + 1024 * 2, + 1115 * 2, + 1536 * 2, + 1152 * 2, + 1253 * 2, + 1728 * 2, + 1152 * 2, + 1254 * 2, + 1728 * 2, + 1280 * 2, + 1393 * 2, + 1920 * 2, + 1280 * 2, + 1394 * 2, + 1920 * 2 + ]; + const AC3_SAMPLES_PER_FRAME = 1536; + const EAC3_NUMBLKS_TABLE = [1, 2, 3, 6]; + const parseEac3SyncFrame = (data) => { + if (data.length < 6) { + return null; + } + if (data[0] !== 11 || data[1] !== 119) { + return null; + } + const bitstream = new Bitstream(data); + bitstream.skipBits(16); + const strmtyp = bitstream.readBits(2); + bitstream.skipBits(3); + if (strmtyp !== 0 && strmtyp !== 2) { + return null; + } + const frmsiz = bitstream.readBits(11); + const fscod = bitstream.readBits(2); + let fscod2 = 0; + let numblkscod; + if (fscod === 3) { + fscod2 = bitstream.readBits(2); + numblkscod = 3; + } else { + numblkscod = bitstream.readBits(2); + } + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + const bsid = bitstream.readBits(5); + if (bsid < 11 || bsid > 16) { + return null; + } + const numblks = EAC3_NUMBLKS_TABLE[numblkscod]; + let fs; + if (fscod < 3) { + fs = AC3_SAMPLE_RATES[fscod] / 1e3; + } else { + fs = EAC3_REDUCED_SAMPLE_RATES[fscod2] / 1e3; + } + const dataRate = Math.round((frmsiz + 1) * fs / (numblks * 16)); + const bsmod = 0; + const numDepSub = 0; + const chanLoc = 0; + const substream = { + fscod, + fscod2, + bsid, + bsmod, + acmod, + lfeon, + numDepSub, + chanLoc + }; + return { + dataRate, + substreams: [substream] + }; + }; + const parseEac3Config = (data) => { + if (data.length < 2) { + return null; + } + const bitstream = new Bitstream(data); + const dataRate = bitstream.readBits(13); + const numIndSub = bitstream.readBits(3); + const substreams = []; + for (let i = 0; i <= numIndSub; i++) { + if (Math.ceil(bitstream.pos / 8) + 3 > data.length) { + break; + } + const fscod = bitstream.readBits(2); + const bsid = bitstream.readBits(5); + bitstream.skipBits(1); + bitstream.skipBits(1); + const bsmod = bitstream.readBits(3); + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + bitstream.skipBits(3); + const numDepSub = bitstream.readBits(4); + let chanLoc = 0; + if (numDepSub > 0) { + chanLoc = bitstream.readBits(9); + } else { + bitstream.skipBits(1); + } + substreams.push({ + fscod, + fscod2: null, + bsid, + bsmod, + acmod, + lfeon, + numDepSub, + chanLoc + }); + } + if (substreams.length === 0) { + return null; + } + return { dataRate, substreams }; + }; + const getEac3SampleRate = (config) => { + const sub = config.substreams[0]; + assert(sub); + if (sub.fscod < 3) { + return AC3_SAMPLE_RATES[sub.fscod]; + } else if (sub.fscod2 !== null && sub.fscod2 < 3) { + return EAC3_REDUCED_SAMPLE_RATES[sub.fscod2]; + } + return null; + }; + const getEac3ChannelCount = (config) => { + const sub = config.substreams[0]; + assert(sub); + let channels = AC3_ACMOD_CHANNEL_COUNTS[sub.acmod] + sub.lfeon; + if (sub.numDepSub > 0) { + const CHAN_LOC_COUNTS = [2, 2, 1, 1, 2, 2, 2, 1, 1]; + for (let bit = 0; bit < 9; bit++) { + if (sub.chanLoc & 1 << 8 - bit) { + channels += CHAN_LOC_COUNTS[bit]; + } + } + } + return channels; + }; class Demuxer { constructor(input) { this.input = input; } + dispose() { + } } - const customVideoDecoders = []; - const customAudioDecoders = []; const PLACEHOLDER_DATA = /* @__PURE__ */ new Uint8Array(0); class EncodedPacket { /** Creates a new {@link EncodedPacket} from raw bytes and timing information. */ @@ -2319,49 +3669,12574 @@ var artplayerProxyMediabunny = (function() { chunk.copyTo(data); return new EncodedPacket(data, chunk.type, chunk.timestamp / 1e6, (chunk.duration ?? 0) / 1e6, void 0, void 0, sideData); } - /** Clones this packet while optionally updating timing information. */ + /** Clones this packet while optionally modifying the new packet's data. */ clone(options) { if (options !== void 0 && (typeof options !== "object" || options === null)) { throw new TypeError("options, when provided, must be an object."); } + if (options?.data !== void 0 && !(options.data instanceof Uint8Array)) { + throw new TypeError("options.data, when provided, must be a Uint8Array."); + } + if (options?.type !== void 0 && options.type !== "key" && options.type !== "delta") { + throw new TypeError('options.type, when provided, must be either "key" or "delta".'); + } if (options?.timestamp !== void 0 && !Number.isFinite(options.timestamp)) { throw new TypeError("options.timestamp, when provided, must be a number."); } if (options?.duration !== void 0 && !Number.isFinite(options.duration)) { throw new TypeError("options.duration, when provided, must be a number."); } - return new EncodedPacket(this.data, this.type, options?.timestamp ?? this.timestamp, options?.duration ?? this.duration, this.sequenceNumber, this.byteLength); + if (options?.sequenceNumber !== void 0 && !Number.isFinite(options.sequenceNumber)) { + throw new TypeError("options.sequenceNumber, when provided, must be a number."); + } + if (options?.sideData !== void 0 && (typeof options.sideData !== "object" || options.sideData === null)) { + throw new TypeError("options.sideData, when provided, must be an object."); + } + return new EncodedPacket(options?.data ?? this.data, options?.type ?? this.type, options?.timestamp ?? this.timestamp, options?.duration ?? this.duration, options?.sequenceNumber ?? this.sequenceNumber, this.byteLength, options?.sideData ?? this.sideData); } } - const fromUlaw = (u8) => { - const MULAW_BIAS = 33; - let sign = 0; - let position = 0; - let number = ~u8; - if (number & 128) { - number &= -129; - sign = -1; + const buildIsobmffMimeType = (info) => { + const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; + let string = base + (info.isQuickTime ? "quicktime" : "mp4"); + if (info.codecStrings.length > 0) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; } - position = ((number & 240) >> 4) + 5; - const decoded = (1 << position | (number & 15) << position - 4 | 1 << position - 5) - MULAW_BIAS; - return sign === 0 ? decoded : -decoded; + return string; }; - const fromAlaw = (u8) => { - let sign = 0; - let position = 0; - let number = u8 ^ 85; - if (number & 128) { - number &= -129; - sign = -1; + const parsePsshBoxContents = (contents) => { + const view = toDataView(contents); + let pos = 0; + const version = view.getUint8(pos); + pos += 1; + pos += 3; + const systemId = bytesToHexString(contents.subarray(pos, pos + 16)); + pos += 16; + let keyIds = null; + if (version > 0) { + const kidCount = view.getUint32(pos); + pos += 4; + if (kidCount > 0) { + keyIds = []; + for (let i = 0; i < kidCount; i++) { + keyIds.push(bytesToHexString(contents.subarray(pos, pos + 16))); + pos += 16; + } + } } - position = ((number & 240) >> 4) + 4; - let decoded = 0; - if (position !== 4) { - decoded = 1 << position | (number & 15) << position - 4 | 1 << position - 5; + const dataSize = view.getUint32(pos); + pos += 4; + return { + systemId, + keyIds, + data: contents.slice(pos, pos + dataSize) + }; + }; + const psshBoxesAreEqual = (a, b) => a.systemId === b.systemId && uint8ArraysAreEqual(a.data, b.data); + const MIN_BOX_HEADER_SIZE = 8; + const MAX_BOX_HEADER_SIZE = 16; + const readBoxHeader = (slice) => { + let totalSize = readU32Be(slice); + const name = readAscii(slice, 4); + let headerSize = 8; + const hasLargeSize = totalSize === 1; + if (hasLargeSize) { + totalSize = readU64Be(slice); + headerSize = 16; + } + const contentSize = totalSize - headerSize; + if (contentSize < 0) { + return null; + } + return { name, totalSize, headerSize, contentSize }; + }; + const readFixed_16_16 = (slice) => { + return readI32Be(slice) / 65536; + }; + const readFixed_2_30 = (slice) => { + return readI32Be(slice) / 1073741824; + }; + const readIsomVariableInteger = (slice) => { + let result = 0; + for (let i = 0; i < 4; i++) { + result <<= 7; + const nextByte = readU8(slice); + result |= nextByte & 127; + if ((nextByte & 128) === 0) { + break; + } + } + return result; + }; + const readMetadataStringShort = (slice) => { + let stringLength = readU16Be(slice); + slice.skip(2); + stringLength = Math.min(stringLength, slice.remainingLength); + return textDecoder.decode(readBytes(slice, stringLength)); + }; + const readDataBox = (slice) => { + const header = readBoxHeader(slice); + if (!header || header.name !== "data") { + return null; + } + if (slice.remainingLength < 8) { + return null; + } + const typeIndicator = readU32Be(slice); + slice.skip(4); + const data = readBytes(slice, header.contentSize - 8); + switch (typeIndicator) { + case 1: + return textDecoder.decode(data); + // UTF-8 + case 2: + return new TextDecoder("utf-16be").decode(data); + // UTF-16-BE + case 13: + return new RichImageData(data, "image/jpeg"); + case 14: + return new RichImageData(data, "image/png"); + case 27: + return new RichImageData(data, "image/bmp"); + default: + return data; + } + }; + const AES_128_BLOCK_SIZE = 16; + const Te4 = new Uint32Array(256); + const Td0 = new Uint32Array(256); + const Td1 = new Uint32Array(256); + const Td2 = new Uint32Array(256); + const Td3 = new Uint32Array(256); + const Td4 = new Uint32Array(256); + const rcon = new Uint32Array(10); + let tablesGenerated = false; + const generateAesTables = () => { + const sbox = new Uint8Array(256); + const log = new Uint8Array(256); + const pow = new Uint8Array(256); + for (let i = 0, p = 1; i < 256; i++) { + pow[i] = p; + log[p] = i; + p = p ^ p << 1 ^ (p & 128 ? 283 : 0); + } + const mul = (a, b) => a && b ? pow[(log[a] + log[b]) % 255] : 0; + sbox[0] = 99; + for (let i = 1; i < 256; i++) { + const x = pow[255 - log[i]]; + let s = x ^ x << 1 ^ x << 2 ^ x << 3 ^ x << 4; + s = s >>> 8 ^ s & 255 ^ 99; + sbox[i] = s; + } + for (let i = 0; i < 256; i++) { + const s = sbox[i]; + const is = sbox.indexOf(i); + Te4[i] = s << 24 | s << 16 | s << 8 | s; + Td4[i] = is << 24 | is << 16 | is << 8 | is; + const b0 = mul(is, 14); + const b1 = mul(is, 9); + const b2 = mul(is, 13); + const b3 = mul(is, 11); + const w = b0 << 24 | b1 << 16 | b2 << 8 | b3; + Td0[i] = w; + Td1[i] = w >>> 8 | w << 24; + Td2[i] = w >>> 16 | w << 16; + Td3[i] = w >>> 24 | w << 8; + } + let r = 1; + for (let i = 0; i < 10; i++) { + rcon[i] = r << 24; + r = r << 1 ^ (r & 128 ? 283 : 0); + } + tablesGenerated = true; + }; + class Aes128CbcContext { + constructor() { + this.roundkey = new Uint32Array(44); + this.iv = new Uint32Array(AES_128_BLOCK_SIZE / Uint32Array.BYTES_PER_ELEMENT); + this.in = new Uint8Array(AES_128_BLOCK_SIZE); + this.out = new Uint8Array(AES_128_BLOCK_SIZE); + this.inView = new DataView(this.in.buffer); + this.outView = new DataView(this.out.buffer); + } + init({ key, iv }) { + assert(key.byteLength === 16); + assert(iv.byteLength === 16); + if (!tablesGenerated) { + generateAesTables(); + } + const keyView = new DataView(key.buffer, key.byteOffset, key.byteLength); + const ivView = new DataView(iv.buffer, iv.byteOffset, iv.byteLength); + this.roundkey[0] = keyView.getUint32(0, false); + this.roundkey[1] = keyView.getUint32(4, false); + this.roundkey[2] = keyView.getUint32(8, false); + this.roundkey[3] = keyView.getUint32(12, false); + this.iv[0] = ivView.getUint32(0, false); + this.iv[1] = ivView.getUint32(4, false); + this.iv[2] = ivView.getUint32(8, false); + this.iv[3] = ivView.getUint32(12, false); + for (let index = 4; index < 44; index += 4) { + const temp = this.roundkey[index - 1]; + this.roundkey[index] = this.roundkey[index - 4] ^ Te4[temp >>> 16 & 255] & 4278190080 ^ Te4[temp >>> 8 & 255] & 16711680 ^ Te4[temp >>> 0 & 255] & 65280 ^ Te4[temp >>> 24 & 255] & 255 ^ rcon[index / 4 - 1]; + this.roundkey[index + 1] = this.roundkey[index - 3] ^ this.roundkey[index]; + this.roundkey[index + 2] = this.roundkey[index - 2] ^ this.roundkey[index + 1]; + this.roundkey[index + 3] = this.roundkey[index - 1] ^ this.roundkey[index + 2]; + } + for (let i = 0, j = 40; i < j; i += 4, j -= 4) { + for (let k = 0; k < 4; k++) { + const temp = this.roundkey[i + k]; + this.roundkey[i + k] = this.roundkey[j + k]; + this.roundkey[j + k] = temp; + } + } + for (let index = 4; index < 40; index += 4) { + for (let k = 0; k < 4; k++) { + const rk = this.roundkey[index + k]; + this.roundkey[index + k] = Td0[Te4[rk >>> 24 & 255] & 255] ^ Td1[Te4[rk >>> 16 & 255] & 255] ^ Td2[Te4[rk >>> 8 & 255] & 255] ^ Td3[Te4[rk >>> 0 & 255] & 255]; + } + } + } + decrypt() { + let s0 = this.inView.getUint32(0, false) ^ this.roundkey[0]; + let s1 = this.inView.getUint32(4, false) ^ this.roundkey[1]; + let s2 = this.inView.getUint32(8, false) ^ this.roundkey[2]; + let s3 = this.inView.getUint32(12, false) ^ this.roundkey[3]; + const temp0 = this.inView.getUint32(0, false); + const temp1 = this.inView.getUint32(4, false); + const temp2 = this.inView.getUint32(8, false); + const temp3 = this.inView.getUint32(12, false); + let t0, t1, t2, t3; + for (let round = 1; round < 10; round++) { + const offset = round * 4; + t0 = Td0[s0 >>> 24] ^ Td1[s3 >>> 16 & 255] ^ Td2[s2 >>> 8 & 255] ^ Td3[s1 & 255] ^ this.roundkey[offset]; + t1 = Td0[s1 >>> 24] ^ Td1[s0 >>> 16 & 255] ^ Td2[s3 >>> 8 & 255] ^ Td3[s2 & 255] ^ this.roundkey[offset + 1]; + t2 = Td0[s2 >>> 24] ^ Td1[s1 >>> 16 & 255] ^ Td2[s0 >>> 8 & 255] ^ Td3[s3 & 255] ^ this.roundkey[offset + 2]; + t3 = Td0[s3 >>> 24] ^ Td1[s2 >>> 16 & 255] ^ Td2[s1 >>> 8 & 255] ^ Td3[s0 & 255] ^ this.roundkey[offset + 3]; + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + const f0 = Td4[s0 >>> 24 & 255] & 4278190080 ^ Td4[s3 >>> 16 & 255] & 16711680 ^ Td4[s2 >>> 8 & 255] & 65280 ^ Td4[s1 >>> 0 & 255] & 255 ^ this.roundkey[40]; + const f1 = Td4[s1 >>> 24 & 255] & 4278190080 ^ Td4[s0 >>> 16 & 255] & 16711680 ^ Td4[s3 >>> 8 & 255] & 65280 ^ Td4[s2 >>> 0 & 255] & 255 ^ this.roundkey[41]; + const f2 = Td4[s2 >>> 24 & 255] & 4278190080 ^ Td4[s1 >>> 16 & 255] & 16711680 ^ Td4[s0 >>> 8 & 255] & 65280 ^ Td4[s3 >>> 0 & 255] & 255 ^ this.roundkey[42]; + const f3 = Td4[s3 >>> 24 & 255] & 4278190080 ^ Td4[s2 >>> 16 & 255] & 16711680 ^ Td4[s1 >>> 8 & 255] & 65280 ^ Td4[s0 >>> 0 & 255] & 255 ^ this.roundkey[43]; + this.outView.setUint32(0, f0 ^ this.iv[0], false); + this.outView.setUint32(4, f1 ^ this.iv[1], false); + this.outView.setUint32(8, f2 ^ this.iv[2], false); + this.outView.setUint32(12, f3 ^ this.iv[3], false); + this.iv[0] = temp0; + this.iv[1] = temp1; + this.iv[2] = temp2; + this.iv[3] = temp3; + } + } + const createAes128CbcDecryptStream = (reader, getInit, close) => { + let initted = false; + let pos = 0; + const CHUNK_SIZE = 2 ** 16; + const BLOCK_SIZE = 16; + const aesContext = new Aes128CbcContext(); + return new ReadableStream({ + pull: async (controller) => { + if (!initted) { + aesContext.init(await getInit()); + initted = true; + } + const requestedLength = CHUNK_SIZE + BLOCK_SIZE; + let nextSlice = reader.requestSliceRange(pos, 0, requestedLength); + if (nextSlice instanceof Promise) + nextSlice = await nextSlice; + if (!nextSlice || nextSlice.length === 0) { + throw new Error("Invalid ciphertext."); + } + const sliceLength = nextSlice.length; + if (sliceLength % 16 !== 0) { + throw new Error("Invalid ciphertext."); + } + const bytesToRead = sliceLength === requestedLength ? sliceLength - BLOCK_SIZE : sliceLength; + const input = readBytes(nextSlice, bytesToRead); + const output = new Uint8Array(bytesToRead); + for (let i = 0; i < bytesToRead; i += 16) { + aesContext.in.set(input.subarray(i, i + 16)); + aesContext.decrypt(); + output.set(aesContext.out, i); + } + if (bytesToRead < sliceLength) { + controller.enqueue(output); + pos += bytesToRead; + } else { + const paddingLength = output[bytesToRead - 1]; + if (paddingLength === 0 || paddingLength > 16) { + throw new Error("Invalid PKCS#7 padding. Incorrect key or corrupted data."); + } + const trimmedOutput = output.subarray(0, bytesToRead - paddingLength); + controller.enqueue(trimmedOutput); + controller.close(); + close(); + } + }, + cancel: () => { + close(); + } + }); + }; + class IsobmffDemuxer extends Demuxer { + constructor(input) { + super(input); + this.moovSlice = null; + this.currentTrack = null; + this.tracks = []; + this.metadataPromise = null; + this.movieTimescale = -1; + this.movieDurationInTimescale = -1; + this.isQuickTime = false; + this.metadataTags = {}; + this.currentMetadataKeys = null; + this.isFragmented = false; + this.fragmentTrackDefaults = []; + this.psshBoxes = []; + this.currentFragment = null; + this.lastReadFragment = null; + this.decryptionKeyCache = /* @__PURE__ */ new Map(); + this.reader = input._reader; + } + async getTrackBackings() { + await this.readMetadata(); + return this.tracks.map((track) => track.trackBacking); + } + async getMimeType() { + await this.readMetadata(); + const backings = await this.getTrackBackings(); + const codecStrings = await Promise.all(backings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildIsobmffMimeType({ + isQuickTime: this.isQuickTime, + hasVideo: this.tracks.some((x) => x.info?.type === "video"), + hasAudio: this.tracks.some((x) => x.info?.type === "audio"), + codecStrings: codecStrings.filter(Boolean) + }); + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } + readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let currentPos = 0; + let lookForMfraBox = false; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const startPos = currentPos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + if (boxInfo.name === "ftyp" || boxInfo.name === "styp") { + const majorBrand = readAscii(slice, 4); + this.isQuickTime = majorBrand === "qt "; + } else if (boxInfo.name === "moov") { + let moovSlice = this.reader.requestSlice(slice.filePos, boxInfo.contentSize); + if (moovSlice instanceof Promise) + moovSlice = await moovSlice; + if (!moovSlice) + break; + this.moovSlice = moovSlice; + this.readContiguousBoxes(this.moovSlice); + for (const track of this.tracks) { + const previousSegmentDurationsInSeconds = track.editListPreviousSegmentDurations / this.movieTimescale; + track.editListOffset -= Math.round(previousSegmentDurationsInSeconds * track.timescale); + } + lookForMfraBox = this.isFragmented && this.reader.fileSize !== null && this.reader.fileSize > startPos + boxInfo.totalSize; + break; + } else if (boxInfo.name === "moof") { + if (!this.input._initInput) { + throw new Error('"moof" box encountered with no "moov" box present; this file is likely a Segment as described in ISO/IEC 14496-12 Section 8.16. A separate init file that contains a "moov" box is required to read this file, please provide it using InputOptions.initInput.'); + } + const initDemuxer = await this.input._initInput._getDemuxer(); + if (initDemuxer.constructor !== IsobmffDemuxer) { + throw new Error("Init input must match the input's format."); + } + await initDemuxer.readMetadata(); + this.movieTimescale = initDemuxer.movieTimescale; + this.movieDurationInTimescale = initDemuxer.movieDurationInTimescale; + this.metadataTags = initDemuxer.metadataTags; + this.isFragmented = true; + this.fragmentTrackDefaults = initDemuxer.fragmentTrackDefaults; + this.psshBoxes = initDemuxer.psshBoxes; + for (const foreignTrack of initDemuxer.tracks) { + const track = { + id: foreignTrack.id, + demuxer: this, + trackBacking: null, + disposition: foreignTrack.disposition, + timescale: foreignTrack.timescale, + durationInMediaTimescale: foreignTrack.durationInMediaTimescale, + durationInMovieTimescale: foreignTrack.durationInMovieTimescale, + rotation: foreignTrack.rotation, + internalCodecId: foreignTrack.internalCodecId, + name: foreignTrack.name, + languageCode: foreignTrack.languageCode, + sampleTableByteOffset: null, + sampleTable: null, + fragmentLookupTable: [], + currentFragmentState: null, + fragmentPositionCache: [], + editListPreviousSegmentDurations: foreignTrack.editListPreviousSegmentDurations, + editListOffset: foreignTrack.editListOffset, + encryptionInfo: foreignTrack.encryptionInfo, + encryptionAuxInfo: null, + frmaCodecString: null, + info: foreignTrack.info + }; + if (foreignTrack.trackBacking) { + assert(track.info); + if (track.info.type === "video" && track.info.width !== -1) { + const videoTrack = track; + track.trackBacking = new IsobmffVideoTrackBacking(videoTrack); + this.tracks.push(track); + } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { + const audioTrack = track; + track.trackBacking = new IsobmffAudioTrackBacking(audioTrack); + this.tracks.push(track); + } + } + } + lookForMfraBox = false; + break; + } + currentPos = startPos + boxInfo.totalSize; + } + if (lookForMfraBox) { + assert(this.reader.fileSize !== null); + let lastWordSlice = this.reader.requestSlice(this.reader.fileSize - 4, 4); + if (lastWordSlice instanceof Promise) + lastWordSlice = await lastWordSlice; + assert(lastWordSlice); + const lastWord = readU32Be(lastWordSlice); + const potentialMfraPos = this.reader.fileSize - lastWord; + if (potentialMfraPos >= 0 && potentialMfraPos <= this.reader.fileSize - MAX_BOX_HEADER_SIZE) { + let mfraHeaderSlice = this.reader.requestSliceRange(potentialMfraPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (mfraHeaderSlice instanceof Promise) + mfraHeaderSlice = await mfraHeaderSlice; + if (mfraHeaderSlice) { + const boxInfo = readBoxHeader(mfraHeaderSlice); + if (boxInfo && boxInfo.name === "mfra") { + let mfraSlice = this.reader.requestSlice(mfraHeaderSlice.filePos, boxInfo.contentSize); + if (mfraSlice instanceof Promise) + mfraSlice = await mfraSlice; + if (mfraSlice) { + this.readContiguousBoxes(mfraSlice); + } + } + } + } + } + })()); + } + getSampleTableForTrack(internalTrack) { + if (internalTrack.sampleTable) { + return internalTrack.sampleTable; + } + const sampleTable = { + sampleTimingEntries: [], + sampleCompositionTimeOffsets: [], + sampleSizes: [], + keySampleIndices: null, + chunkOffsets: [], + sampleToChunk: [], + presentationTimestamps: null, + presentationTimestampIndexMap: null + }; + internalTrack.sampleTable = sampleTable; + if (internalTrack.sampleTableByteOffset === null) { + return sampleTable; + } + assert(this.moovSlice); + const stblContainerSlice = this.moovSlice.slice(internalTrack.sampleTableByteOffset); + this.currentTrack = internalTrack; + this.traverseBox(stblContainerSlice); + this.currentTrack = null; + const isPcmCodec = internalTrack.info?.type === "audio" && internalTrack.info.codec && PCM_AUDIO_CODECS.includes(internalTrack.info.codec); + if (isPcmCodec && sampleTable.sampleCompositionTimeOffsets.length === 0) { + assert(internalTrack.info?.type === "audio"); + const pcmInfo = parsePcmCodec(internalTrack.info.codec); + const newSampleTimingEntries = []; + const newSampleSizes = []; + for (let i = 0; i < sampleTable.sampleToChunk.length; i++) { + const chunkEntry = sampleTable.sampleToChunk[i]; + const nextEntry = sampleTable.sampleToChunk[i + 1]; + const chunkCount = (nextEntry ? nextEntry.startChunkIndex : sampleTable.chunkOffsets.length) - chunkEntry.startChunkIndex; + for (let j = 0; j < chunkCount; j++) { + const startSampleIndex = chunkEntry.startSampleIndex + j * chunkEntry.samplesPerChunk; + const endSampleIndex = startSampleIndex + chunkEntry.samplesPerChunk; + const startTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, startSampleIndex, (x) => x.startIndex); + const startTimingEntry = sampleTable.sampleTimingEntries[startTimingEntryIndex]; + const endTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, endSampleIndex, (x) => x.startIndex); + const endTimingEntry = sampleTable.sampleTimingEntries[endTimingEntryIndex]; + const firstSampleTimestamp = startTimingEntry.startDecodeTimestamp + (startSampleIndex - startTimingEntry.startIndex) * startTimingEntry.delta; + const lastSampleTimestamp = endTimingEntry.startDecodeTimestamp + (endSampleIndex - endTimingEntry.startIndex) * endTimingEntry.delta; + const delta = lastSampleTimestamp - firstSampleTimestamp; + const lastSampleTimingEntry = last(newSampleTimingEntries); + if (lastSampleTimingEntry && lastSampleTimingEntry.delta === delta) { + lastSampleTimingEntry.count++; + } else { + newSampleTimingEntries.push({ + startIndex: chunkEntry.startChunkIndex + j, + startDecodeTimestamp: firstSampleTimestamp, + count: 1, + delta + }); + } + const chunkSize = chunkEntry.samplesPerChunk * pcmInfo.sampleSize * internalTrack.info.numberOfChannels; + newSampleSizes.push(chunkSize); + } + chunkEntry.startSampleIndex = chunkEntry.startChunkIndex; + chunkEntry.samplesPerChunk = 1; + } + sampleTable.sampleTimingEntries = newSampleTimingEntries; + sampleTable.sampleSizes = newSampleSizes; + } + if (sampleTable.sampleCompositionTimeOffsets.length > 0) { + sampleTable.presentationTimestamps = []; + for (const entry of sampleTable.sampleTimingEntries) { + for (let i = 0; i < entry.count; i++) { + sampleTable.presentationTimestamps.push({ + presentationTimestamp: entry.startDecodeTimestamp + i * entry.delta, + sampleIndex: entry.startIndex + i + }); + } + } + for (const entry of sampleTable.sampleCompositionTimeOffsets) { + for (let i = 0; i < entry.count; i++) { + const sampleIndex = entry.startIndex + i; + const sample = sampleTable.presentationTimestamps[sampleIndex]; + if (!sample) { + continue; + } + sample.presentationTimestamp += entry.offset; + } + } + sampleTable.presentationTimestamps.sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); + sampleTable.presentationTimestampIndexMap = Array(sampleTable.presentationTimestamps.length).fill(-1); + for (let i = 0; i < sampleTable.presentationTimestamps.length; i++) { + sampleTable.presentationTimestampIndexMap[sampleTable.presentationTimestamps[i].sampleIndex] = i; + } + } + return sampleTable; + } + async readFragment(startPos) { + if (this.lastReadFragment?.moofOffset === startPos) { + return this.lastReadFragment; + } + let headerSlice = this.reader.requestSliceRange(startPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const moofBoxInfo = readBoxHeader(headerSlice); + assert(moofBoxInfo?.name === "moof"); + let entireSlice = this.reader.requestSlice(startPos, moofBoxInfo.totalSize); + if (entireSlice instanceof Promise) + entireSlice = await entireSlice; + assert(entireSlice); + this.traverseBox(entireSlice); + const fragment = this.lastReadFragment; + assert(fragment && fragment.moofOffset === startPos); + for (const [, trackData] of fragment.trackData) { + const track = trackData.track; + const { fragmentPositionCache } = track; + if (!trackData.startTimestampIsFinal) { + const lookupEntry = track.fragmentLookupTable.find((x) => x.moofOffset === fragment.moofOffset); + if (lookupEntry) { + offsetFragmentTrackDataByTimestamp(trackData, lookupEntry.timestamp); + } else { + const lastCacheIndex = binarySearchLessOrEqual(fragmentPositionCache, fragment.moofOffset - 1, (x) => x.moofOffset); + if (lastCacheIndex !== -1) { + const lastCache = fragmentPositionCache[lastCacheIndex]; + offsetFragmentTrackDataByTimestamp(trackData, lastCache.endTimestamp); + } + } + trackData.startTimestampIsFinal = true; + } + const insertionIndex = binarySearchLessOrEqual(fragmentPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); + if (insertionIndex === -1 || fragmentPositionCache[insertionIndex].moofOffset !== fragment.moofOffset) { + fragmentPositionCache.splice(insertionIndex + 1, 0, { + moofOffset: fragment.moofOffset, + startTimestamp: trackData.startTimestamp, + endTimestamp: trackData.endTimestamp + }); + } + if (trackData.encryptionAuxInfo && track.encryptionInfo) { + const entries = await resolveEncryptionAuxInfo(this.reader, track.encryptionInfo, trackData.encryptionAuxInfo); + for (let i = 0; i < Math.min(trackData.samples.length, entries.length); i++) { + const entry = entries[i]; + trackData.samples[i].encryption = entry; + } + } + } + return fragment; + } + readContiguousBoxes(slice) { + const startIndex = slice.filePos; + while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { + const foundBox = this.traverseBox(slice); + if (!foundBox) { + break; + } + } + } + // eslint-disable-next-line @stylistic/generator-star-spacing + *iterateContiguousBoxes(slice) { + const startIndex = slice.filePos; + while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { + const startPos = slice.filePos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + yield { boxInfo, slice }; + slice.filePos = startPos + boxInfo.totalSize; + } + } + traverseBox(slice) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G; + const startPos = slice.filePos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + return false; + } + const contentStartPos = slice.filePos; + const boxEndPos = startPos + boxInfo.totalSize; + switch (boxInfo.name) { + case "mdia": + case "minf": + case "dinf": + case "mfra": + case "edts": + case "sinf": + case "schi": + { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "mvhd": + { + const version = readU8(slice); + slice.skip(3); + if (version === 1) { + slice.skip(8 + 8); + this.movieTimescale = readU32Be(slice); + this.movieDurationInTimescale = readU64Be(slice); + } else { + slice.skip(4 + 4); + this.movieTimescale = readU32Be(slice); + this.movieDurationInTimescale = readU32Be(slice); + } + } + break; + case "trak": + { + const track = { + id: -1, + demuxer: this, + trackBacking: null, + disposition: { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }, + info: null, + timescale: -1, + durationInMovieTimescale: -1, + durationInMediaTimescale: -1, + rotation: 0, + internalCodecId: null, + name: null, + languageCode: UNDETERMINED_LANGUAGE, + sampleTableByteOffset: -1, + sampleTable: null, + fragmentLookupTable: [], + currentFragmentState: null, + fragmentPositionCache: [], + editListPreviousSegmentDurations: 0, + editListOffset: 0, + encryptionInfo: null, + encryptionAuxInfo: null, + frmaCodecString: null + }; + this.currentTrack = track; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + if (track.id !== -1 && track.timescale !== -1 && track.info !== null) { + if (track.info.type === "video" && track.info.width !== -1) { + const videoTrack = track; + track.trackBacking = new IsobmffVideoTrackBacking(videoTrack); + this.tracks.push(track); + } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { + const audioTrack = track; + track.trackBacking = new IsobmffAudioTrackBacking(audioTrack); + this.tracks.push(track); + } + } + this.currentTrack = null; + } + break; + case "tkhd": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + const flags = readU24Be(slice); + const trackEnabled = !!(flags & 1); + track.disposition.default = trackEnabled; + if (version === 0) { + slice.skip(8); + track.id = readU32Be(slice); + slice.skip(4); + track.durationInMovieTimescale = readU32Be(slice); + } else if (version === 1) { + slice.skip(16); + track.id = readU32Be(slice); + slice.skip(4); + track.durationInMovieTimescale = readU64Be(slice); + } else { + throw new Error(`Incorrect track header version ${version}.`); + } + slice.skip(2 * 4 + 2 + 2 + 2 + 2); + const matrix = [ + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice), + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice), + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice) + ]; + const rotation = normalizeRotation(roundToMultiple(extractRotationFromMatrix(matrix), 90)); + assert(rotation === 0 || rotation === 90 || rotation === 180 || rotation === 270); + track.rotation = rotation; + } + break; + case "elst": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + slice.skip(3); + let relevantEntryFound = false; + let previousSegmentDurations = 0; + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const segmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); + const mediaTime = version === 1 ? readI64Be(slice) : readI32Be(slice); + const mediaRate = readFixed_16_16(slice); + if (segmentDuration === 0) { + continue; + } + if (relevantEntryFound) { + console.warn("Unsupported edit list: multiple edits are not currently supported. Only using first edit."); + break; + } + if (mediaTime === -1) { + previousSegmentDurations += segmentDuration; + continue; + } + if (mediaRate !== 1) { + console.warn("Unsupported edit list entry: media rate must be 1."); + break; + } + track.editListPreviousSegmentDurations = previousSegmentDurations; + track.editListOffset = mediaTime; + relevantEntryFound = true; + } + } + break; + case "mdhd": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + slice.skip(3); + if (version === 0) { + slice.skip(8); + track.timescale = readU32Be(slice); + track.durationInMediaTimescale = readU32Be(slice); + } else if (version === 1) { + slice.skip(16); + track.timescale = readU32Be(slice); + track.durationInMediaTimescale = readU64Be(slice); + } + let language = readU16Be(slice); + if (language > 0) { + track.languageCode = ""; + for (let i = 0; i < 3; i++) { + track.languageCode = String.fromCharCode(96 + (language & 31)) + track.languageCode; + language >>= 5; + } + if (!isIso639Dash2LanguageCode(track.languageCode)) { + track.languageCode = UNDETERMINED_LANGUAGE; + } + } + } + break; + case "hdlr": + { + const track = this.currentTrack; + if (!track) { + break; + } + slice.skip(8); + const handlerType = readAscii(slice, 4); + if (handlerType === "vide") { + track.info = { + type: "video", + width: -1, + height: -1, + squarePixelWidth: -1, + squarePixelHeight: -1, + codec: null, + codecDescription: null, + colorSpace: null, + avcType: null, + avcCodecInfo: null, + hevcCodecInfo: null, + vp9CodecInfo: null, + av1CodecInfo: null + }; + } else if (handlerType === "soun") { + track.info = { + type: "audio", + numberOfChannels: -1, + sampleRate: -1, + codec: null, + codecDescription: null, + aacCodecInfo: null, + pcmLittleEndian: false, + pcmSampleSize: null + }; + } + } + break; + case "stbl": + { + const track = this.currentTrack; + if (!track) { + break; + } + track.sampleTableByteOffset = startPos; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "stsd": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (track.info === null || track.sampleTable) { + break; + } + const stsdVersion = readU8(slice); + slice.skip(3); + const entries = readU32Be(slice); + for (let i = 0; i < entries; i++) { + const sampleBoxStartPos = slice.filePos; + const sampleBoxInfo = readBoxHeader(slice); + if (!sampleBoxInfo) { + break; + } + track.internalCodecId = sampleBoxInfo.name; + const lowercaseBoxName = sampleBoxInfo.name.toLowerCase(); + if (track.info.type === "video") { + slice.skip(6 * 1 + 2 + 2 + 2 + 3 * 4); + track.info.width = readU16Be(slice); + track.info.height = readU16Be(slice); + track.info.squarePixelWidth = track.info.width; + track.info.squarePixelHeight = track.info.height; + slice.skip(4 + 4 + 4 + 2 + 32 + 2 + 2); + track.frmaCodecString = null; + this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); + const codecName = lowercaseBoxName === "encv" ? track.frmaCodecString : lowercaseBoxName; + track.frmaCodecString = null; + if (codecName === "avc1" || codecName === "avc3") { + track.info.codec = "avc"; + track.info.avcType = codecName === "avc1" ? 1 : 3; + } else if (codecName === "hvc1" || codecName === "hev1") { + track.info.codec = "hevc"; + } else if (codecName === "vp08") { + track.info.codec = "vp8"; + } else if (codecName === "vp09") { + track.info.codec = "vp9"; + } else if (codecName === "av01") { + track.info.codec = "av1"; + } else if (codecName === null) { + console.warn(`Unknown encrypted video codec due to missing frma box.`); + } else { + console.warn(`Unsupported video codec (sample entry type '${sampleBoxInfo.name}').`); + } + } else { + slice.skip(6 * 1 + 2); + const version = readU16Be(slice); + slice.skip(3 * 2); + let channelCount = readU16Be(slice); + let sampleSize = readU16Be(slice); + slice.skip(2 * 2); + let sampleRate = readU32Be(slice) / 65536; + let lpcmFlags = null; + if (stsdVersion === 0 && version > 0) { + if (version === 1) { + slice.skip(4); + sampleSize = 8 * readU32Be(slice); + slice.skip(2 * 4); + } else if (version === 2) { + slice.skip(4); + sampleRate = readF64Be(slice); + channelCount = readU32Be(slice); + slice.skip(4); + sampleSize = readU32Be(slice); + lpcmFlags = readU32Be(slice); + slice.skip(2 * 4); + } + } + track.info.numberOfChannels = channelCount; + track.info.sampleRate = sampleRate; + track.frmaCodecString = null; + this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); + const codecName = lowercaseBoxName === "enca" ? track.frmaCodecString : lowercaseBoxName; + track.frmaCodecString = null; + if (codecName === "mp4a") ; + else if (codecName === "opus") { + track.info.codec = "opus"; + track.info.sampleRate = OPUS_SAMPLE_RATE; + } else if (codecName === "flac") { + track.info.codec = "flac"; + } else if (codecName === "ulaw") { + track.info.codec = "ulaw"; + } else if (codecName === "alaw") { + track.info.codec = "alaw"; + } else if (codecName === "ac-3") { + track.info.codec = "ac3"; + } else if (codecName === "ec-3") { + track.info.codec = "eac3"; + } else if (codecName === "twos") { + if (sampleSize === 8) { + track.info.codec = "pcm-s8"; + } else if (sampleSize === 16) { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s16" : "pcm-s16be"; + } else { + console.warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`); + track.info.codec = null; + } + } else if (codecName === "sowt") { + if (sampleSize === 8) { + track.info.codec = "pcm-s8"; + } else if (sampleSize === 16) { + track.info.codec = "pcm-s16"; + } else { + console.warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`); + track.info.codec = null; + } + } else if (codecName === "raw ") { + track.info.codec = "pcm-u8"; + } else if (codecName === "in24") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s24" : "pcm-s24be"; + } else if (codecName === "in32") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s32" : "pcm-s32be"; + } else if (codecName === "fl32") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-f32" : "pcm-f32be"; + } else if (codecName === "fl64") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-f64" : "pcm-f64be"; + } else if (codecName === "ipcm") { + const pcmSampleSize = track.info.pcmSampleSize; + if (track.info.pcmLittleEndian) { + if (pcmSampleSize === 16) { + track.info.codec = "pcm-s16"; + } else if (pcmSampleSize === 24) { + track.info.codec = "pcm-s24"; + } else if (pcmSampleSize === 32) { + track.info.codec = "pcm-s32"; + } else { + console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } else { + if (pcmSampleSize === 16) { + track.info.codec = "pcm-s16be"; + } else if (pcmSampleSize === 24) { + track.info.codec = "pcm-s24be"; + } else if (pcmSampleSize === 32) { + track.info.codec = "pcm-s32be"; + } else { + console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } + } else if (codecName === "fpcm") { + const pcmSampleSize = track.info.pcmSampleSize; + if (track.info.pcmLittleEndian) { + if (pcmSampleSize === 32) { + track.info.codec = "pcm-f32"; + } else if (pcmSampleSize === 64) { + track.info.codec = "pcm-f64"; + } else { + console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } else { + if (pcmSampleSize === 32) { + track.info.codec = "pcm-f32be"; + } else if (pcmSampleSize === 64) { + track.info.codec = "pcm-f64be"; + } else { + console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } + } else if (codecName === "lpcm" && lpcmFlags !== null) { + const bytesPerSample = sampleSize + 7 >> 3; + const isFloat = Boolean(lpcmFlags & 1); + const isBigEndian = Boolean(lpcmFlags & 2); + const sFlags = lpcmFlags & 4 ? -1 : 0; + if (sampleSize > 0 && sampleSize <= 64) { + if (isFloat) { + if (sampleSize === 32) { + track.info.codec = isBigEndian ? "pcm-f32be" : "pcm-f32"; + } + } else { + if (sFlags & 1 << bytesPerSample - 1) { + if (bytesPerSample === 1) { + track.info.codec = "pcm-s8"; + } else if (bytesPerSample === 2) { + track.info.codec = isBigEndian ? "pcm-s16be" : "pcm-s16"; + } else if (bytesPerSample === 3) { + track.info.codec = isBigEndian ? "pcm-s24be" : "pcm-s24"; + } else if (bytesPerSample === 4) { + track.info.codec = isBigEndian ? "pcm-s32be" : "pcm-s32"; + } + } else { + if (bytesPerSample === 1) { + track.info.codec = "pcm-u8"; + } + } + } + } + if (track.info.codec === null) { + console.warn("Unsupported PCM format."); + } + } else if (codecName === null) { + console.warn(`Unknown encrypted audio codec due to missing frma box.`); + } else { + console.warn(`Unsupported audio codec (sample entry type '${sampleBoxInfo.name}').`); + } + } + slice.filePos = sampleBoxStartPos + sampleBoxInfo.totalSize; + } + } + break; + case "frma": + { + const track = this.currentTrack; + if (!track) { + break; + } + const format = readAscii(slice, 4); + const lowercase = format.toLowerCase(); + track.frmaCodecString = lowercase; + } + break; + case "schm": + { + const track = this.currentTrack; + if (!track) { + break; + } + slice.skip(4); + const schemeType = readAscii(slice, 4); + if (schemeType === "cenc" || schemeType === "cens" || schemeType === "cbcs") { + track.encryptionInfo = { + scheme: schemeType, + defaultKid: null, + defaultIsProtected: null, + defaultPerSampleIvSize: null, + defaultConstantIv: null, + defaultCryptByteBlock: null, + defaultSkipByteBlock: null + }; + } else { + console.warn(`Unsupported encryption scheme '${schemeType}'.`); + } + } + break; + case "tenc": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + const version = readU8(slice); + slice.skip(3); + slice.skip(1); + const patternByte = readU8(slice); + if (version > 0) { + track.encryptionInfo.defaultCryptByteBlock = patternByte >> 4; + track.encryptionInfo.defaultSkipByteBlock = patternByte & 15; + } else { + track.encryptionInfo.defaultCryptByteBlock = 0; + track.encryptionInfo.defaultSkipByteBlock = 0; + } + track.encryptionInfo.defaultIsProtected = readU8(slice) !== 0; + track.encryptionInfo.defaultPerSampleIvSize = readU8(slice); + track.encryptionInfo.defaultKid = bytesToHexString(readBytes(slice, 16)); + if (track.encryptionInfo.defaultIsProtected && track.encryptionInfo.defaultPerSampleIvSize === 0) { + const constantIvSize = readU8(slice); + const constantIv = new Uint8Array(16); + constantIv.set(readBytes(slice, constantIvSize), 0); + track.encryptionInfo.defaultConstantIv = constantIv; + } + } + break; + case "avcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info); + track.info.codecDescription = readBytes(slice, boxInfo.contentSize); + } + break; + case "hvcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info); + track.info.codecDescription = readBytes(slice, boxInfo.contentSize); + } + break; + case "vpcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + slice.skip(4); + const profile = readU8(slice); + const level = readU8(slice); + const thirdByte = readU8(slice); + const bitDepth = thirdByte >> 4; + const chromaSubsampling = thirdByte >> 1 & 7; + const videoFullRangeFlag = thirdByte & 1; + const colourPrimaries = readU8(slice); + const transferCharacteristics = readU8(slice); + const matrixCoefficients = readU8(slice); + track.info.vp9CodecInfo = { + profile, + level, + bitDepth, + chromaSubsampling, + videoFullRangeFlag, + colourPrimaries, + transferCharacteristics, + matrixCoefficients + }; + } + break; + case "av1C": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + slice.skip(1); + const secondByte = readU8(slice); + const profile = secondByte >> 5; + const level = secondByte & 31; + const thirdByte = readU8(slice); + const tier = thirdByte >> 7; + const highBitDepth = thirdByte >> 6 & 1; + const twelveBit = thirdByte >> 5 & 1; + const monochrome = thirdByte >> 4 & 1; + const chromaSubsamplingX = thirdByte >> 3 & 1; + const chromaSubsamplingY = thirdByte >> 2 & 1; + const chromaSamplePosition = thirdByte & 3; + const bitDepth = profile === 2 && highBitDepth ? twelveBit ? 12 : 10 : highBitDepth ? 10 : 8; + track.info.av1CodecInfo = { + profile, + level, + tier, + bitDepth, + monochrome, + chromaSubsamplingX, + chromaSubsamplingY, + chromaSamplePosition + }; + } + break; + case "colr": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + const colourType = readAscii(slice, 4); + if (colourType !== "nclx") { + break; + } + const colourPrimaries = readU16Be(slice); + const transferCharacteristics = readU16Be(slice); + const matrixCoefficients = readU16Be(slice); + const fullRangeFlag = Boolean(readU8(slice) & 128); + track.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients], + fullRange: fullRangeFlag + }; + } + break; + case "pasp": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + const num = readU32Be(slice); + const den = readU32Be(slice); + if (num > 0 && den > 0) { + if (num > den) { + track.info.squarePixelWidth = Math.round(track.info.width * num / den); + } else { + track.info.squarePixelHeight = Math.round(track.info.height * den / num); + } + } + } + break; + case "wave": + { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "esds": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(4); + const tag = readU8(slice); + assert(tag === 3); + readIsomVariableInteger(slice); + slice.skip(2); + const mixed = readU8(slice); + const streamDependenceFlag = (mixed & 128) !== 0; + const urlFlag = (mixed & 64) !== 0; + const ocrStreamFlag = (mixed & 32) !== 0; + if (streamDependenceFlag) { + slice.skip(2); + } + if (urlFlag) { + const urlLength = readU8(slice); + slice.skip(urlLength); + } + if (ocrStreamFlag) { + slice.skip(2); + } + const decoderConfigTag = readU8(slice); + assert(decoderConfigTag === 4); + const decoderConfigDescriptorLength = readIsomVariableInteger(slice); + const payloadStart = slice.filePos; + const objectTypeIndication = readU8(slice); + if (objectTypeIndication === 64 || objectTypeIndication === 103) { + track.info.codec = "aac"; + track.info.aacCodecInfo = { + isMpeg2: objectTypeIndication === 103, + objectType: null + }; + } else if (objectTypeIndication === 105 || objectTypeIndication === 107) { + track.info.codec = "mp3"; + } else if (objectTypeIndication === 221) { + track.info.codec = "vorbis"; + } else { + console.warn(`Unsupported audio codec (objectTypeIndication ${objectTypeIndication}) - discarding track.`); + } + slice.skip(1 + 3 + 4 + 4); + if (decoderConfigDescriptorLength > slice.filePos - payloadStart) { + const decoderSpecificInfoTag = readU8(slice); + assert(decoderSpecificInfoTag === 5); + const decoderSpecificInfoLength = readIsomVariableInteger(slice); + track.info.codecDescription = readBytes(slice, decoderSpecificInfoLength); + if (track.info.codec === "aac") { + const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); + if (audioSpecificConfig.numberOfChannels !== null) { + track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; + } + if (audioSpecificConfig.sampleRate !== null) { + track.info.sampleRate = audioSpecificConfig.sampleRate; + } + } + } + } + break; + case "enda": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + track.info.pcmLittleEndian = !!(readU16Be(slice) & 255); + } + break; + case "pcmC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(1 + 3); + const formatFlags = readU8(slice); + track.info.pcmLittleEndian = Boolean(formatFlags & 1); + track.info.pcmSampleSize = readU8(slice); + } + break; + case "dOps": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(1); + const outputChannelCount = readU8(slice); + const preSkip = readU16Be(slice); + const inputSampleRate = readU32Be(slice); + const outputGain = readI16Be(slice); + const channelMappingFamily = readU8(slice); + let channelMappingTable; + if (channelMappingFamily !== 0) { + channelMappingTable = readBytes(slice, 2 + outputChannelCount); + } else { + channelMappingTable = new Uint8Array(0); + } + const description = new Uint8Array(8 + 1 + 1 + 2 + 4 + 2 + 1 + channelMappingTable.byteLength); + const view = new DataView(description.buffer); + view.setUint32(0, 1332770163, false); + view.setUint32(4, 1214603620, false); + view.setUint8(8, 1); + view.setUint8(9, outputChannelCount); + view.setUint16(10, preSkip, true); + view.setUint32(12, inputSampleRate, true); + view.setInt16(16, outputGain, true); + view.setUint8(18, channelMappingFamily); + description.set(channelMappingTable, 19); + track.info.codecDescription = description; + track.info.numberOfChannels = outputChannelCount; + } + break; + case "dfLa": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(4); + const BLOCK_TYPE_MASK = 127; + const LAST_METADATA_BLOCK_FLAG_MASK = 128; + const startPos2 = slice.filePos; + while (slice.filePos < boxEndPos) { + const flagAndType = readU8(slice); + const metadataBlockLength = readU24Be(slice); + const type = flagAndType & BLOCK_TYPE_MASK; + if (type === FlacBlockType.STREAMINFO) { + slice.skip(10); + const word = readU32Be(slice); + const sampleRate = word >>> 12; + const numberOfChannels = (word >> 9 & 7) + 1; + track.info.sampleRate = sampleRate; + track.info.numberOfChannels = numberOfChannels; + slice.skip(20); + } else { + slice.skip(metadataBlockLength); + } + if (flagAndType & LAST_METADATA_BLOCK_FLAG_MASK) { + break; + } + } + const endPos = slice.filePos; + slice.filePos = startPos2; + const bytes = readBytes(slice, endPos - startPos2); + const description = new Uint8Array(4 + bytes.byteLength); + const view = new DataView(description.buffer); + view.setUint32(0, 1716281667, false); + description.set(bytes, 4); + track.info.codecDescription = description; + } + break; + case "dac3": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + const bytes = readBytes(slice, 3); + const bitstream = new Bitstream(bytes); + const fscod = bitstream.readBits(2); + bitstream.skipBits(5 + 3); + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + if (fscod < 3) { + track.info.sampleRate = AC3_SAMPLE_RATES[fscod]; + } + track.info.numberOfChannels = AC3_ACMOD_CHANNEL_COUNTS[acmod] + lfeon; + } + break; + case "dec3": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + const bytes = readBytes(slice, boxInfo.contentSize); + const config = parseEac3Config(bytes); + if (!config) { + console.warn("Invalid dec3 box contents, ignoring."); + break; + } + const sampleRate = getEac3SampleRate(config); + if (sampleRate !== null) { + track.info.sampleRate = sampleRate; + } + track.info.numberOfChannels = getEac3ChannelCount(config); + } + break; + case "stts": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + let currentIndex = 0; + let currentTimestamp = 0; + for (let i = 0; i < entryCount; i++) { + const sampleCount = readU32Be(slice); + const sampleDelta = readU32Be(slice); + track.sampleTable.sampleTimingEntries.push({ + startIndex: currentIndex, + startDecodeTimestamp: currentTimestamp, + count: sampleCount, + delta: sampleDelta + }); + currentIndex += sampleCount; + currentTimestamp += sampleCount * sampleDelta; + } + } + break; + case "ctts": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(1 + 3); + const entryCount = readU32Be(slice); + let sampleIndex = 0; + for (let i = 0; i < entryCount; i++) { + const sampleCount = readU32Be(slice); + const sampleOffset = readI32Be(slice); + track.sampleTable.sampleCompositionTimeOffsets.push({ + startIndex: sampleIndex, + count: sampleCount, + offset: sampleOffset + }); + sampleIndex += sampleCount; + } + } + break; + case "stsz": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const sampleSize = readU32Be(slice); + const sampleCount = readU32Be(slice); + if (sampleSize === 0) { + for (let i = 0; i < sampleCount; i++) { + const sampleSize2 = readU32Be(slice); + track.sampleTable.sampleSizes.push(sampleSize2); + } + } else { + track.sampleTable.sampleSizes.push(sampleSize); + } + } + break; + case "stz2": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + slice.skip(3); + const fieldSize = readU8(slice); + const sampleCount = readU32Be(slice); + const bytes = readBytes(slice, Math.ceil(sampleCount * fieldSize / 8)); + const bitstream = new Bitstream(bytes); + for (let i = 0; i < sampleCount; i++) { + const sampleSize = bitstream.readBits(fieldSize); + track.sampleTable.sampleSizes.push(sampleSize); + } + } + break; + case "stss": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + track.sampleTable.keySampleIndices = []; + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const sampleIndex = readU32Be(slice) - 1; + track.sampleTable.keySampleIndices.push(sampleIndex); + } + if (track.sampleTable.keySampleIndices[0] !== 0) { + track.sampleTable.keySampleIndices.unshift(0); + } + } + break; + case "stsc": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const startChunkIndex = readU32Be(slice) - 1; + const samplesPerChunk = readU32Be(slice); + const sampleDescriptionIndex = readU32Be(slice); + track.sampleTable.sampleToChunk.push({ + startSampleIndex: -1, + startChunkIndex, + samplesPerChunk, + sampleDescriptionIndex + }); + } + let startSampleIndex = 0; + for (let i = 0; i < track.sampleTable.sampleToChunk.length; i++) { + track.sampleTable.sampleToChunk[i].startSampleIndex = startSampleIndex; + if (i < track.sampleTable.sampleToChunk.length - 1) { + const nextChunk = track.sampleTable.sampleToChunk[i + 1]; + const chunkCount = nextChunk.startChunkIndex - track.sampleTable.sampleToChunk[i].startChunkIndex; + startSampleIndex += chunkCount * track.sampleTable.sampleToChunk[i].samplesPerChunk; + } + } + } + break; + case "stco": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const chunkOffset = readU32Be(slice); + track.sampleTable.chunkOffsets.push(chunkOffset); + } + } + break; + case "co64": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const chunkOffset = readU64Be(slice); + track.sampleTable.chunkOffsets.push(chunkOffset); + } + } + break; + case "mvex": + { + this.isFragmented = true; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "mehd": + { + const version = readU8(slice); + slice.skip(3); + const fragmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); + this.movieDurationInTimescale = fragmentDuration; + } + break; + case "trex": + { + slice.skip(4); + const trackId = readU32Be(slice); + const defaultSampleDescriptionIndex = readU32Be(slice); + const defaultSampleDuration = readU32Be(slice); + const defaultSampleSize = readU32Be(slice); + const defaultSampleFlags = readU32Be(slice); + this.fragmentTrackDefaults.push({ + trackId, + defaultSampleDescriptionIndex, + defaultSampleDuration, + defaultSampleSize, + defaultSampleFlags + }); + } + break; + case "tfra": + { + const version = readU8(slice); + slice.skip(3); + const trackId = readU32Be(slice); + const track = this.tracks.find((x) => x.id === trackId); + if (!track) { + break; + } + const word = readU32Be(slice); + const lengthSizeOfTrafNum = (word & 48) >> 4; + const lengthSizeOfTrunNum = (word & 12) >> 2; + const lengthSizeOfSampleNum = word & 3; + const functions = [readU8, readU16Be, readU24Be, readU32Be]; + const readTrafNum = functions[lengthSizeOfTrafNum]; + const readTrunNum = functions[lengthSizeOfTrunNum]; + const readSampleNum = functions[lengthSizeOfSampleNum]; + const numberOfEntries = readU32Be(slice); + for (let i = 0; i < numberOfEntries; i++) { + const time = version === 1 ? readU64Be(slice) : readU32Be(slice); + const moofOffset = version === 1 ? readU64Be(slice) : readU32Be(slice); + readTrafNum(slice); + readTrunNum(slice); + readSampleNum(slice); + track.fragmentLookupTable.push({ + timestamp: time, + moofOffset + }); + } + track.fragmentLookupTable.sort((a, b) => a.timestamp - b.timestamp); + for (let i = 0; i < track.fragmentLookupTable.length - 1; i++) { + const entry1 = track.fragmentLookupTable[i]; + const entry2 = track.fragmentLookupTable[i + 1]; + if (entry1.timestamp === entry2.timestamp) { + track.fragmentLookupTable.splice(i + 1, 1); + i--; + } + } + } + break; + case "moof": + { + this.currentFragment = { + moofOffset: startPos, + moofSize: boxInfo.totalSize, + implicitBaseDataOffset: startPos, + trackData: /* @__PURE__ */ new Map(), + psshBoxes: [] + }; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + this.lastReadFragment = this.currentFragment; + this.currentFragment = null; + } + break; + case "traf": + { + assert(this.currentFragment); + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + if (this.currentTrack) { + const trackData = this.currentFragment.trackData.get(this.currentTrack.id); + if (trackData) { + this.currentFragment.implicitBaseDataOffset = trackData.currentOffset; + trackData.presentationTimestamps = trackData.samples.map((x, i) => ({ presentationTimestamp: x.presentationTimestamp, sampleIndex: i })).sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); + for (let i = 0; i < trackData.presentationTimestamps.length; i++) { + const currentEntry = trackData.presentationTimestamps[i]; + const currentSample = trackData.samples[currentEntry.sampleIndex]; + if (trackData.firstKeyFrameTimestamp === null && currentSample.isKeyFrame) { + trackData.firstKeyFrameTimestamp = currentSample.presentationTimestamp; + } + if (i < trackData.presentationTimestamps.length - 1) { + const nextEntry = trackData.presentationTimestamps[i + 1]; + const duration = nextEntry.presentationTimestamp - currentEntry.presentationTimestamp; + currentSample.duration = duration; + } + } + const firstSample = trackData.samples[trackData.presentationTimestamps[0].sampleIndex]; + const lastSample = trackData.samples[last(trackData.presentationTimestamps).sampleIndex]; + trackData.startTimestamp = firstSample.presentationTimestamp; + trackData.endTimestamp = lastSample.presentationTimestamp + lastSample.duration; + const { currentFragmentState } = this.currentTrack; + assert(currentFragmentState); + if (currentFragmentState.startTimestamp !== null) { + offsetFragmentTrackDataByTimestamp(trackData, currentFragmentState.startTimestamp); + trackData.startTimestampIsFinal = true; + } + if (currentFragmentState.encryptionAuxInfo && !trackData.samples[0].encryption) { + trackData.encryptionAuxInfo = currentFragmentState.encryptionAuxInfo; + } + } + this.currentTrack.currentFragmentState = null; + this.currentTrack = null; + } + } + break; + case "pssh": + { + if (this.input._formatOptions.isobmff?._suppressPsshParsing) { + break; + } + const psshBox = parsePsshBoxContents(readBytes(slice, boxInfo.contentSize)); + if (this.currentFragment) { + this.currentFragment.psshBoxes.push(psshBox); + } else if (!this.currentTrack) { + this.psshBoxes.push(psshBox); + } + } + break; + case "tfhd": + { + assert(this.currentFragment); + slice.skip(1); + const flags = readU24Be(slice); + const baseDataOffsetPresent = Boolean(flags & 1); + const sampleDescriptionIndexPresent = Boolean(flags & 2); + const defaultSampleDurationPresent = Boolean(flags & 8); + const defaultSampleSizePresent = Boolean(flags & 16); + const defaultSampleFlagsPresent = Boolean(flags & 32); + const durationIsEmpty = Boolean(flags & 65536); + const defaultBaseIsMoof = Boolean(flags & 131072); + const trackId = readU32Be(slice); + const track = this.tracks.find((x) => x.id === trackId); + if (!track) { + break; + } + const defaults = this.fragmentTrackDefaults.find((x) => x.trackId === trackId); + this.currentTrack = track; + track.currentFragmentState = { + baseDataOffset: this.currentFragment.implicitBaseDataOffset, + sampleDescriptionIndex: defaults?.defaultSampleDescriptionIndex ?? null, + defaultSampleDuration: defaults?.defaultSampleDuration ?? null, + defaultSampleSize: defaults?.defaultSampleSize ?? null, + defaultSampleFlags: defaults?.defaultSampleFlags ?? null, + startTimestamp: null, + encryptionAuxInfo: null + }; + if (baseDataOffsetPresent) { + track.currentFragmentState.baseDataOffset = readU64Be(slice); + } else if (defaultBaseIsMoof) { + track.currentFragmentState.baseDataOffset = this.currentFragment.moofOffset; + } + if (sampleDescriptionIndexPresent) { + track.currentFragmentState.sampleDescriptionIndex = readU32Be(slice); + } + if (defaultSampleDurationPresent) { + track.currentFragmentState.defaultSampleDuration = readU32Be(slice); + } + if (defaultSampleSizePresent) { + track.currentFragmentState.defaultSampleSize = readU32Be(slice); + } + if (defaultSampleFlagsPresent) { + track.currentFragmentState.defaultSampleFlags = readU32Be(slice); + } + if (durationIsEmpty) { + track.currentFragmentState.defaultSampleDuration = 0; + } + } + break; + case "tfdt": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.currentFragmentState); + const version = readU8(slice); + slice.skip(3); + const baseMediaDecodeTime = version === 0 ? readU32Be(slice) : readU64Be(slice); + track.currentFragmentState.startTimestamp = baseMediaDecodeTime; + } + break; + case "trun": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(this.currentFragment); + assert(track.currentFragmentState); + const version = readU8(slice); + const flags = readU24Be(slice); + const dataOffsetPresent = Boolean(flags & 1); + const firstSampleFlagsPresent = Boolean(flags & 4); + const sampleDurationPresent = Boolean(flags & 256); + const sampleSizePresent = Boolean(flags & 512); + const sampleFlagsPresent = Boolean(flags & 1024); + const sampleCompositionTimeOffsetsPresent = Boolean(flags & 2048); + const sampleCount = readU32Be(slice); + let dataOffset = null; + if (dataOffsetPresent) { + dataOffset = readI32Be(slice); + } + let firstSampleFlags = null; + if (firstSampleFlagsPresent) { + firstSampleFlags = readU32Be(slice); + } + let trackData; + if (this.currentFragment.trackData.has(track.id)) { + trackData = this.currentFragment.trackData.get(track.id); + if (dataOffset !== null) { + trackData.currentOffset = track.currentFragmentState.baseDataOffset + dataOffset; + } + } else { + trackData = { + track, + currentTimestamp: 0, + currentOffset: track.currentFragmentState.baseDataOffset + (dataOffset ?? 0), + startTimestamp: 0, + endTimestamp: 0, + firstKeyFrameTimestamp: null, + samples: [], + presentationTimestamps: [], + startTimestampIsFinal: false, + encryptionAuxInfo: null + }; + this.currentFragment.trackData.set(track.id, trackData); + } + if (sampleCount === 0) { + this.currentFragment.implicitBaseDataOffset = trackData.currentOffset; + break; + } + for (let i = 0; i < sampleCount; i++) { + let sampleDuration; + if (sampleDurationPresent) { + sampleDuration = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleDuration !== null); + sampleDuration = track.currentFragmentState.defaultSampleDuration; + } + let sampleSize; + if (sampleSizePresent) { + sampleSize = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleSize !== null); + sampleSize = track.currentFragmentState.defaultSampleSize; + } + let sampleFlags; + if (sampleFlagsPresent) { + sampleFlags = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleFlags !== null); + sampleFlags = track.currentFragmentState.defaultSampleFlags; + } + if (i === 0 && firstSampleFlags !== null) { + sampleFlags = firstSampleFlags; + } + let sampleCompositionTimeOffset = 0; + if (sampleCompositionTimeOffsetsPresent) { + if (version === 0) { + sampleCompositionTimeOffset = readU32Be(slice); + } else { + sampleCompositionTimeOffset = readI32Be(slice); + } + } + const isKeyFrame = !(sampleFlags & 65536); + trackData.samples.push({ + presentationTimestamp: trackData.currentTimestamp + sampleCompositionTimeOffset, + duration: sampleDuration, + byteOffset: trackData.currentOffset, + byteSize: sampleSize, + isKeyFrame, + encryption: null + }); + trackData.currentOffset += sampleSize; + trackData.currentTimestamp += sampleDuration; + } + } + break; + case "saiz": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + slice.skip(1); + const flags = readU24Be(slice); + if (flags & 1) { + const auxInfoType = readAscii(slice, 4); + const auxInfoTypeParam = readU32Be(slice); + if (auxInfoType !== track.encryptionInfo.scheme || auxInfoTypeParam !== 0) { + break; + } + } + const defaultSampleInfoSize = readU8(slice); + const sampleCount = readU32Be(slice); + let sampleSizes = null; + if (defaultSampleInfoSize === 0 && sampleCount > 0) { + sampleSizes = readBytes(slice, sampleCount); + } + const aux = getOrCreateEncryptionAuxInfo(track); + aux.defaultSampleInfoSize = defaultSampleInfoSize; + aux.sampleSizes = sampleSizes; + aux.sampleCount = sampleCount; + } + break; + case "saio": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + const version = readU8(slice); + const flags = readU24Be(slice); + if (flags & 1) { + const auxInfoType = readAscii(slice, 4); + const auxInfoTypeParam = readU32Be(slice); + if (auxInfoType !== track.encryptionInfo.scheme || auxInfoTypeParam !== 0) { + break; + } + } + const entryCount = readU32Be(slice); + if (entryCount === 0) { + break; + } + if (entryCount > 1) { + console.warn("Multiple saio entries are not supported; using the first offset only."); + } + let offset = version === 0 ? readU32Be(slice) : Number(readU64Be(slice)); + if (this.currentFragment) { + offset += this.currentFragment.moofOffset; + } + const aux = getOrCreateEncryptionAuxInfo(track); + aux.offset = offset; + } + break; + case "senc": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + assert(this.currentFragment); + const trackData = this.currentFragment.trackData.get(track.id); + if (!trackData) { + break; + } + slice.skip(1); + const flags = readU24Be(slice); + const useSubsamples = Boolean(flags & 2); + const sampleCount = readU32Be(slice); + const ivSize = track.encryptionInfo.defaultPerSampleIvSize; + assert(ivSize !== null); + for (let i = 0; i < Math.min(sampleCount, trackData.samples.length); i++) { + const iv = new Uint8Array(16); + if (ivSize > 0) { + iv.set(readBytes(slice, ivSize), 0); + } else { + iv.set(track.encryptionInfo.defaultConstantIv, 0); + } + let subsamples = null; + if (useSubsamples) { + const subsampleCount = readU16Be(slice); + subsamples = []; + for (let j = 0; j < subsampleCount; j++) { + const clearLen = readU16Be(slice); + const protectedLen = readU32Be(slice); + subsamples.push({ clearLen, protectedLen }); + } + } + const sample = trackData.samples[i]; + sample.encryption = { iv, subsamples }; + } + } + break; + // Metadata section + // https://exiftool.org/TagNames/QuickTime.html + // https://mp4workshop.com/about + case "udta": + { + const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { + if (boxInfo2.name !== "meta" && !this.currentTrack) { + const startPos2 = slice2.filePos; + (_a = this.metadataTags).raw ?? (_a.raw = {}); + if (boxInfo2.name[0] === "©") { + (_b = this.metadataTags.raw)[_c = boxInfo2.name] ?? (_b[_c] = readMetadataStringShort(slice2)); + } else { + (_d = this.metadataTags.raw)[_e = boxInfo2.name] ?? (_d[_e] = readBytes(slice2, boxInfo2.contentSize)); + } + slice2.filePos = startPos2; + } + switch (boxInfo2.name) { + case "meta": + { + slice2.skip(-boxInfo2.headerSize); + this.traverseBox(slice2); + } + break; + case "©nam": + case "name": + { + if (this.currentTrack) { + this.currentTrack.name = textDecoder.decode(readBytes(slice2, boxInfo2.contentSize)); + } else { + (_f = this.metadataTags).title ?? (_f.title = readMetadataStringShort(slice2)); + } + } + break; + case "©des": + { + if (!this.currentTrack) { + (_g = this.metadataTags).description ?? (_g.description = readMetadataStringShort(slice2)); + } + } + break; + case "©ART": + { + if (!this.currentTrack) { + (_h = this.metadataTags).artist ?? (_h.artist = readMetadataStringShort(slice2)); + } + } + break; + case "©alb": + { + if (!this.currentTrack) { + (_i = this.metadataTags).album ?? (_i.album = readMetadataStringShort(slice2)); + } + } + break; + case "albr": + { + if (!this.currentTrack) { + (_j = this.metadataTags).albumArtist ?? (_j.albumArtist = readMetadataStringShort(slice2)); + } + } + break; + case "©gen": + { + if (!this.currentTrack) { + (_k = this.metadataTags).genre ?? (_k.genre = readMetadataStringShort(slice2)); + } + } + break; + case "©day": + { + if (!this.currentTrack) { + const date = new Date(readMetadataStringShort(slice2)); + if (!Number.isNaN(date.getTime())) { + (_l = this.metadataTags).date ?? (_l.date = date); + } + } + } + break; + case "©cmt": + { + if (!this.currentTrack) { + (_m = this.metadataTags).comment ?? (_m.comment = readMetadataStringShort(slice2)); + } + } + break; + case "©lyr": + { + if (!this.currentTrack) { + (_n = this.metadataTags).lyrics ?? (_n.lyrics = readMetadataStringShort(slice2)); + } + } + break; + } + } + } + break; + case "meta": + { + if (this.currentTrack) { + break; + } + const word = readU32Be(slice); + const isQuickTime = word !== 0; + this.currentMetadataKeys = /* @__PURE__ */ new Map(); + if (isQuickTime) { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } else { + this.readContiguousBoxes(slice.slice(contentStartPos + 4, boxInfo.contentSize - 4)); + } + this.currentMetadataKeys = null; + } + break; + case "keys": + { + if (!this.currentMetadataKeys) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const keySize = readU32Be(slice); + slice.skip(4); + const keyName = textDecoder.decode(readBytes(slice, keySize - 8)); + this.currentMetadataKeys.set(i + 1, keyName); + } + } + break; + case "ilst": + { + if (!this.currentMetadataKeys) { + break; + } + const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { + let metadataKey = boxInfo2.name; + const nameAsNumber = (metadataKey.charCodeAt(0) << 24) + (metadataKey.charCodeAt(1) << 16) + (metadataKey.charCodeAt(2) << 8) + metadataKey.charCodeAt(3); + if (this.currentMetadataKeys.has(nameAsNumber)) { + metadataKey = this.currentMetadataKeys.get(nameAsNumber); + } + const data = readDataBox(slice2); + (_o = this.metadataTags).raw ?? (_o.raw = {}); + (_p = this.metadataTags.raw)[metadataKey] ?? (_p[metadataKey] = data); + switch (metadataKey) { + case "©nam": + case "titl": + case "com.apple.quicktime.title": + case "title": + { + if (typeof data === "string") { + (_q = this.metadataTags).title ?? (_q.title = data); + } + } + break; + case "©des": + case "desc": + case "dscp": + case "com.apple.quicktime.description": + case "description": + { + if (typeof data === "string") { + (_r = this.metadataTags).description ?? (_r.description = data); + } + } + break; + case "©ART": + case "com.apple.quicktime.artist": + case "artist": + { + if (typeof data === "string") { + (_s = this.metadataTags).artist ?? (_s.artist = data); + } + } + break; + case "©alb": + case "albm": + case "com.apple.quicktime.album": + case "album": + { + if (typeof data === "string") { + (_t = this.metadataTags).album ?? (_t.album = data); + } + } + break; + case "aART": + case "album_artist": + { + if (typeof data === "string") { + (_u = this.metadataTags).albumArtist ?? (_u.albumArtist = data); + } + } + break; + case "©cmt": + case "com.apple.quicktime.comment": + case "comment": + { + if (typeof data === "string") { + (_v = this.metadataTags).comment ?? (_v.comment = data); + } + } + break; + case "©gen": + case "gnre": + case "com.apple.quicktime.genre": + case "genre": + { + if (typeof data === "string") { + (_w = this.metadataTags).genre ?? (_w.genre = data); + } + } + break; + case "©lyr": + case "lyrics": + { + if (typeof data === "string") { + (_x = this.metadataTags).lyrics ?? (_x.lyrics = data); + } + } + break; + case "©day": + case "rldt": + case "com.apple.quicktime.creationdate": + case "date": + { + if (typeof data === "string") { + const date = new Date(data); + if (!Number.isNaN(date.getTime())) { + (_y = this.metadataTags).date ?? (_y.date = date); + } + } + } + break; + case "covr": + case "com.apple.quicktime.artwork": + { + if (data instanceof RichImageData) { + (_z = this.metadataTags).images ?? (_z.images = []); + this.metadataTags.images.push({ + data: data.data, + kind: "coverFront", + mimeType: data.mimeType + }); + } else if (data instanceof Uint8Array) { + (_A = this.metadataTags).images ?? (_A.images = []); + this.metadataTags.images.push({ + data, + kind: "coverFront", + mimeType: "image/*" + }); + } + } + break; + case "track": + { + if (typeof data === "string") { + const parts = data.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + (_B = this.metadataTags).trackNumber ?? (_B.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + (_C = this.metadataTags).tracksTotal ?? (_C.tracksTotal = tracksTotal); + } + } + } + break; + case "trkn": + { + if (data instanceof Uint8Array && data.length >= 6) { + const view = toDataView(data); + const trackNumber = view.getUint16(2, false); + const tracksTotal = view.getUint16(4, false); + if (trackNumber > 0) { + (_D = this.metadataTags).trackNumber ?? (_D.trackNumber = trackNumber); + } + if (tracksTotal > 0) { + (_E = this.metadataTags).tracksTotal ?? (_E.tracksTotal = tracksTotal); + } + } + } + break; + case "disc": + case "disk": + { + if (data instanceof Uint8Array && data.length >= 6) { + const view = toDataView(data); + const discNumber = view.getUint16(2, false); + const discNumberMax = view.getUint16(4, false); + if (discNumber > 0) { + (_F = this.metadataTags).discNumber ?? (_F.discNumber = discNumber); + } + if (discNumberMax > 0) { + (_G = this.metadataTags).discsTotal ?? (_G.discsTotal = discNumberMax); + } + } + } + break; + } + } + } + break; + } + slice.filePos = boxEndPos; + return true; + } + } + class IsobmffTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.packetToSampleIndex = /* @__PURE__ */ new WeakMap(); + this.packetToFragmentLocation = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.internalTrack.id; + } + getNumber() { + const demuxer = this.internalTrack.demuxer; + const trackType = this.internalTrack.trackBacking.getType(); + let number = 0; + for (const track of demuxer.tracks) { + if (track.trackBacking.getType() === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.internalTrack.internalCodecId; + } + getName() { + return this.internalTrack.name; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getTimeResolution() { + return this.internalTrack.timescale; + } + isRelativeToUnixEpoch() { + return false; + } + getDisposition() { + return this.internalTrack.disposition; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const track = this.internalTrack; + if (track.durationInMediaTimescale <= 0) { + return null; + } + assert(track.trackBacking); + const firstPacket = await track.trackBacking.getFirstPacket({ metadataOnly: true }); + return (firstPacket?.timestamp ?? 0) + track.durationInMediaTimescale / track.timescale; + } + async getLiveRefreshInterval() { + return null; + } + async getFirstPacket(options) { + const regularPacket = await this.fetchPacketForSampleIndex(0, options); + if (regularPacket || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup( + null, + (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData) { + return { + sampleIndex: 0, + correctSampleFound: true + }; + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + mapTimestampIntoTimescale(timestamp) { + return roundIfAlmostInteger(timestamp * this.internalTrack.timescale) + this.internalTrack.editListOffset; + } + async getPacket(timestamp, options) { + const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); + const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); + if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup(null, (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (!trackData) { + return { sampleIndex: -1, correctSampleFound: false }; + } + const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.presentationTimestamp); + const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; + const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { sampleIndex: sampleIndex2, correctSampleFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextPacket(packet, options) { + const regularSampleIndex = this.packetToSampleIndex.get(packet); + if (regularSampleIndex !== void 0) { + return this.fetchPacketForSampleIndex(regularSampleIndex + 1, options); + } + const locationInFragment = this.packetToFragmentLocation.get(packet); + if (locationInFragment === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performFragmentedLookup( + locationInFragment.fragment, + (fragment) => { + if (fragment === locationInFragment.fragment) { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (locationInFragment.sampleIndex + 1 < trackData.samples.length) { + return { + sampleIndex: locationInFragment.sampleIndex + 1, + correctSampleFound: true + }; + } + } else { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData) { + return { + sampleIndex: 0, + correctSampleFound: true + }; + } + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + async getKeyPacket(timestamp, options) { + const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleIndex = getKeyframeSampleIndexForTimestamp(sampleTable, timestampInTimescale); + const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); + if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup(null, (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (!trackData) { + return { sampleIndex: -1, correctSampleFound: false }; + } + const index = findLastIndex(trackData.presentationTimestamps, (x) => { + const sample = trackData.samples[x.sampleIndex]; + return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; + }); + const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; + const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { sampleIndex: sampleIndex2, correctSampleFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextKeyPacket(packet, options) { + const regularSampleIndex = this.packetToSampleIndex.get(packet); + if (regularSampleIndex !== void 0) { + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, regularSampleIndex); + return this.fetchPacketForSampleIndex(nextKeyFrameSampleIndex, options); + } + const locationInFragment = this.packetToFragmentLocation.get(packet); + if (locationInFragment === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performFragmentedLookup( + locationInFragment.fragment, + (fragment) => { + if (fragment === locationInFragment.fragment) { + const trackData = fragment.trackData.get(this.internalTrack.id); + const nextKeyFrameIndex = trackData.samples.findIndex((x, i) => x.isKeyFrame && i > locationInFragment.sampleIndex); + if (nextKeyFrameIndex !== -1) { + return { + sampleIndex: nextKeyFrameIndex, + correctSampleFound: true + }; + } + } else { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData && trackData.firstKeyFrameTimestamp !== null) { + const keyFrameIndex = trackData.samples.findIndex((x) => x.isKeyFrame); + assert(keyFrameIndex !== -1); + return { + sampleIndex: keyFrameIndex, + correctSampleFound: true + }; + } + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + async fetchPacketForSampleIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleInfo = getSampleInfo(sampleTable, sampleIndex); + if (!sampleInfo) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.internalTrack.demuxer.reader.requestSlice(sampleInfo.sampleOffset, sampleInfo.sampleSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, sampleInfo.sampleSize); + if (this.internalTrack.encryptionAuxInfo) { + assert(this.internalTrack.encryptionInfo); + const entries = await resolveEncryptionAuxInfo(this.internalTrack.demuxer.reader, this.internalTrack.encryptionInfo, this.internalTrack.encryptionAuxInfo); + if (sampleIndex < entries.length) { + data = await decryptSample(this.internalTrack, entries[sampleIndex], data, null); + } + } + } + const timestamp = (sampleInfo.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; + const duration = sampleInfo.duration / this.internalTrack.timescale; + const packet = new EncodedPacket(data, sampleInfo.isKeyFrame ? "key" : "delta", timestamp, duration, sampleIndex, sampleInfo.sampleSize); + this.packetToSampleIndex.set(packet, sampleIndex); + return packet; + } + async fetchPacketInFragment(fragment, sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const trackData = fragment.trackData.get(this.internalTrack.id); + const fragmentSample = trackData.samples[sampleIndex]; + assert(fragmentSample); + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.internalTrack.demuxer.reader.requestSlice(fragmentSample.byteOffset, fragmentSample.byteSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, fragmentSample.byteSize); + if (fragmentSample.encryption) { + data = await decryptSample(this.internalTrack, fragmentSample.encryption, data, fragment); + } + } + const timestamp = (fragmentSample.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; + const duration = fragmentSample.duration / this.internalTrack.timescale; + const packet = new EncodedPacket(data, fragmentSample.isKeyFrame ? "key" : "delta", timestamp, duration, fragment.moofOffset + sampleIndex, fragmentSample.byteSize); + this.packetToFragmentLocation.set(packet, { fragment, sampleIndex }); + return packet; + } + /** Looks for a packet in the fragments while trying to load as few fragments as possible to retrieve it. */ + async performFragmentedLookup(startFragment, getMatchInFragment, searchTimestamp, latestTimestamp, options) { + const demuxer = this.internalTrack.demuxer; + let currentFragment = null; + let bestFragment = null; + let bestSampleIndex = -1; + if (startFragment) { + const { sampleIndex, correctSampleFound } = getMatchInFragment(startFragment); + if (correctSampleFound) { + return this.fetchPacketInFragment(startFragment, sampleIndex, options); + } + if (sampleIndex !== -1) { + bestFragment = startFragment; + bestSampleIndex = sampleIndex; + } + } + const lookupEntryIndex = binarySearchLessOrEqual(this.internalTrack.fragmentLookupTable, searchTimestamp, (x) => x.timestamp); + const lookupEntry = lookupEntryIndex !== -1 ? this.internalTrack.fragmentLookupTable[lookupEntryIndex] : null; + const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.fragmentPositionCache, searchTimestamp, (x) => x.startTimestamp); + const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.fragmentPositionCache[positionCacheIndex] : null; + const lookupEntryPosition = Math.max(lookupEntry?.moofOffset ?? 0, positionCacheEntry?.moofOffset ?? 0) || null; + let currentPos; + if (!startFragment) { + currentPos = lookupEntryPosition ?? 0; + } else { + if (lookupEntryPosition === null || startFragment.moofOffset >= lookupEntryPosition) { + currentPos = startFragment.moofOffset + startFragment.moofSize; + currentFragment = startFragment; + } else { + currentPos = lookupEntryPosition; + } + } + while (true) { + if (currentFragment) { + const trackData = currentFragment.trackData.get(this.internalTrack.id); + if (trackData && trackData.startTimestamp > latestTimestamp) { + break; + } + } + let slice = demuxer.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const boxStartPos = currentPos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + if (boxInfo.name === "moof") { + currentFragment = await demuxer.readFragment(boxStartPos); + const { sampleIndex, correctSampleFound } = getMatchInFragment(currentFragment); + if (correctSampleFound) { + return this.fetchPacketInFragment(currentFragment, sampleIndex, options); + } + if (sampleIndex !== -1) { + bestFragment = currentFragment; + bestSampleIndex = sampleIndex; + } + } + currentPos = boxStartPos + boxInfo.totalSize; + } + if (lookupEntry && (!bestFragment || bestFragment.moofOffset < lookupEntry.moofOffset)) { + const previousLookupEntry = this.internalTrack.fragmentLookupTable[lookupEntryIndex - 1]; + assert(!previousLookupEntry || previousLookupEntry.timestamp < lookupEntry.timestamp); + const newSearchTimestamp = previousLookupEntry?.timestamp ?? -Infinity; + return this.performFragmentedLookup(null, getMatchInFragment, newSearchTimestamp, latestTimestamp, options); + } + if (bestFragment) { + return this.fetchPacketInFragment(bestFragment, bestSampleIndex, options); + } + return null; + } + } + class IsobmffVideoTrackBacking extends IsobmffTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfigPromise = null; + this.internalTrack = internalTrack; + } + getType() { + return "video"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getCodedWidth() { + return this.internalTrack.info.width; + } + getCodedHeight() { + return this.internalTrack.info.height; + } + getSquarePixelWidth() { + return this.internalTrack.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.internalTrack.info.squarePixelHeight; + } + getRotation() { + return this.internalTrack.rotation; + } + async getColorSpace() { + return { + primaries: this.internalTrack.info.colorSpace?.primaries, + transfer: this.internalTrack.info.colorSpace?.transfer, + matrix: this.internalTrack.info.colorSpace?.matrix, + fullRange: this.internalTrack.info.colorSpace?.fullRange + }; + } + async canBeTransparent() { + return false; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { + if (this.internalTrack.info.codec === "vp9" && !this.internalTrack.info.vp9CodecInfo) { + const firstPacket = await this.getFirstPacket({}); + this.internalTrack.info.vp9CodecInfo = firstPacket && extractVp9CodecInfoFromPacket(firstPacket.data); + } else if (this.internalTrack.info.codec === "av1" && !this.internalTrack.info.av1CodecInfo) { + const firstPacket = await this.getFirstPacket({}); + this.internalTrack.info.av1CodecInfo = firstPacket && extractAv1CodecInfoFromPacket(firstPacket.data); + } + const config = { + codec: extractVideoCodecString(this.internalTrack.info), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? void 0, + colorSpace: this.internalTrack.info.colorSpace ?? void 0 + }; + if (this.internalTrack.info.width !== this.internalTrack.info.squarePixelWidth || this.internalTrack.info.height !== this.internalTrack.info.squarePixelHeight) { + config.displayAspectWidth = this.internalTrack.info.squarePixelWidth; + config.displayAspectHeight = this.internalTrack.info.squarePixelHeight; + } + return config; + })()); + } + } + class IsobmffAudioTrackBacking extends IsobmffTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfig = null; + this.internalTrack = internalTrack; + } + getType() { + return "audio"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getNumberOfChannels() { + return this.internalTrack.info.numberOfChannels; + } + getSampleRate() { + return this.internalTrack.info.sampleRate; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfig ?? (this.decoderConfig = { + codec: extractAudioCodecString(this.internalTrack.info), + numberOfChannels: this.internalTrack.info.numberOfChannels, + sampleRate: this.internalTrack.info.sampleRate, + description: this.internalTrack.info.codecDescription ?? void 0 + }); + } + } + const getSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { + if (sampleTable.presentationTimestamps) { + const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); + if (index === -1) { + return -1; + } + return sampleTable.presentationTimestamps[index].sampleIndex; } else { - decoded = number << 1 | 1; + const index = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, timescaleUnits, (x) => x.startDecodeTimestamp); + if (index === -1) { + return -1; + } + const entry = sampleTable.sampleTimingEntries[index]; + return entry.startIndex + Math.min(Math.floor((timescaleUnits - entry.startDecodeTimestamp) / entry.delta), entry.count - 1); + } + }; + const getKeyframeSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { + if (!sampleTable.keySampleIndices) { + return getSampleIndexForTimestamp(sampleTable, timescaleUnits); + } + if (sampleTable.presentationTimestamps) { + const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); + if (index === -1) { + return -1; + } + for (let i = index; i >= 0; i--) { + const sampleIndex = sampleTable.presentationTimestamps[i].sampleIndex; + const isKeyFrame = binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1; + if (isKeyFrame) { + return sampleIndex; + } + } + return -1; + } else { + const sampleIndex = getSampleIndexForTimestamp(sampleTable, timescaleUnits); + const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); + return sampleTable.keySampleIndices[index] ?? -1; + } + }; + const getSampleInfo = (sampleTable, sampleIndex) => { + const timingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, sampleIndex, (x) => x.startIndex); + const timingEntry = sampleTable.sampleTimingEntries[timingEntryIndex]; + if (!timingEntry || timingEntry.startIndex + timingEntry.count <= sampleIndex) { + return null; + } + const decodeTimestamp = timingEntry.startDecodeTimestamp + (sampleIndex - timingEntry.startIndex) * timingEntry.delta; + let presentationTimestamp = decodeTimestamp; + const offsetEntryIndex = binarySearchLessOrEqual(sampleTable.sampleCompositionTimeOffsets, sampleIndex, (x) => x.startIndex); + const offsetEntry = sampleTable.sampleCompositionTimeOffsets[offsetEntryIndex]; + if (offsetEntry && sampleIndex - offsetEntry.startIndex < offsetEntry.count) { + presentationTimestamp += offsetEntry.offset; + } + const sampleSize = sampleTable.sampleSizes[Math.min(sampleIndex, sampleTable.sampleSizes.length - 1)]; + const chunkEntryIndex = binarySearchLessOrEqual(sampleTable.sampleToChunk, sampleIndex, (x) => x.startSampleIndex); + const chunkEntry = sampleTable.sampleToChunk[chunkEntryIndex]; + assert(chunkEntry); + const chunkIndex = chunkEntry.startChunkIndex + Math.floor((sampleIndex - chunkEntry.startSampleIndex) / chunkEntry.samplesPerChunk); + const chunkOffset = sampleTable.chunkOffsets[chunkIndex]; + const startSampleIndexOfChunk = chunkEntry.startSampleIndex + (chunkIndex - chunkEntry.startChunkIndex) * chunkEntry.samplesPerChunk; + let chunkSize = 0; + let sampleOffset = chunkOffset; + if (sampleTable.sampleSizes.length === 1) { + sampleOffset += sampleSize * (sampleIndex - startSampleIndexOfChunk); + chunkSize += sampleSize * chunkEntry.samplesPerChunk; + } else { + for (let i = startSampleIndexOfChunk; i < startSampleIndexOfChunk + chunkEntry.samplesPerChunk; i++) { + const sampleSize2 = sampleTable.sampleSizes[i]; + if (i < sampleIndex) { + sampleOffset += sampleSize2; + } + chunkSize += sampleSize2; + } + } + let duration = timingEntry.delta; + if (sampleTable.presentationTimestamps) { + const presentationIndex = sampleTable.presentationTimestampIndexMap[sampleIndex]; + assert(presentationIndex !== void 0); + if (presentationIndex < sampleTable.presentationTimestamps.length - 1) { + const nextEntry = sampleTable.presentationTimestamps[presentationIndex + 1]; + const nextPresentationTimestamp = nextEntry.presentationTimestamp; + duration = nextPresentationTimestamp - presentationTimestamp; + } + } + return { + presentationTimestamp, + duration, + sampleOffset, + sampleSize, + chunkOffset, + chunkSize, + isKeyFrame: sampleTable.keySampleIndices ? binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1 : true + }; + }; + const getNextKeyframeIndexForSample = (sampleTable, sampleIndex) => { + if (!sampleTable.keySampleIndices) { + return sampleIndex + 1; + } + const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); + return sampleTable.keySampleIndices[index + 1] ?? -1; + }; + const offsetFragmentTrackDataByTimestamp = (trackData, timestamp) => { + trackData.startTimestamp += timestamp; + trackData.endTimestamp += timestamp; + for (const sample of trackData.samples) { + sample.presentationTimestamp += timestamp; + } + for (const entry of trackData.presentationTimestamps) { + entry.presentationTimestamp += timestamp; + } + }; + const extractRotationFromMatrix = (matrix) => { + const [a, b] = matrix; + const radians = Math.atan2(b, a); + if (!Number.isFinite(radians)) { + return 0; + } + return radians * (180 / Math.PI); + }; + const sampleTableIsEmpty = (sampleTable) => { + return sampleTable.sampleSizes.length === 0; + }; + const getOrCreateEncryptionAuxInfo = (track) => { + var _a; + if (track.currentFragmentState) { + return (_a = track.currentFragmentState).encryptionAuxInfo ?? (_a.encryptionAuxInfo = { + defaultSampleInfoSize: 0, + sampleSizes: null, + sampleCount: 0, + offset: null, + resolved: null + }); + } else { + return track.encryptionAuxInfo ?? (track.encryptionAuxInfo = { + defaultSampleInfoSize: 0, + sampleSizes: null, + sampleCount: 0, + offset: null, + resolved: null + }); + } + }; + const resolveEncryptionAuxInfo = async (reader, encryptionInfo, aux) => { + if (aux.resolved) { + return aux.resolved; + } + if (aux.offset === null || aux.sampleCount === 0) { + throw new Error("Incomplete saiz/saio info; cannot resolve encryption data."); + } + let totalSize = 0; + if (aux.defaultSampleInfoSize > 0) { + totalSize = aux.defaultSampleInfoSize * aux.sampleCount; + } else { + assert(aux.sampleSizes); + for (let i = 0; i < aux.sampleCount; i++) { + totalSize += aux.sampleSizes[i]; + } + } + let slice = reader.requestSlice(aux.offset, totalSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + throw new Error("Failed to read auxiliary encryption info."); + } + const ivSize = encryptionInfo.defaultPerSampleIvSize; + assert(ivSize !== null); + const entries = []; + for (let i = 0; i < aux.sampleCount; i++) { + const entrySize = aux.defaultSampleInfoSize > 0 ? aux.defaultSampleInfoSize : aux.sampleSizes[i]; + const iv = new Uint8Array(16); + if (ivSize > 0) { + iv.set(readBytes(slice, ivSize), 0); + } else { + iv.set(encryptionInfo.defaultConstantIv, 0); + } + let subsamples = null; + if (entrySize > ivSize) { + const subsampleCount = readU16Be(slice); + subsamples = []; + for (let j = 0; j < subsampleCount; j++) { + const clearLen = readU16Be(slice); + const protectedLen = readU32Be(slice); + subsamples.push({ clearLen, protectedLen }); + } + } + entries.push({ iv, subsamples }); + } + aux.resolved = entries; + return entries; + }; + const decryptSample = async (track, sampleEncryption, data, fragment) => { + assert(track.encryptionInfo); + const encryptionInfo = track.encryptionInfo; + assert(encryptionInfo.defaultKid !== null); + const keyId = encryptionInfo.defaultKid; + let keyBytes; + const cacheEntry = track.demuxer.decryptionKeyCache.get(keyId); + if (cacheEntry) { + keyBytes = await cacheEntry; + } else { + if (!track.demuxer.input._formatOptions.isobmff?.resolveKeyId) { + throw new Error("Encrypted media samples encountered. To decrypt them, please provide a callback for InputOptions.formatOptions.isobmff.resolveKeyId."); + } + const promise = (async () => { + let psshBoxes = track.demuxer.psshBoxes; + if (fragment) { + psshBoxes = [ + ...psshBoxes, + ...fragment.psshBoxes + ].filter((x) => x.keyIds === null || x.keyIds.includes(keyId)); + for (let i = 0; i < psshBoxes.length - 1; i++) { + for (let j = i + 1; j < psshBoxes.length; j++) { + if (psshBoxesAreEqual(psshBoxes[i], psshBoxes[j])) { + psshBoxes.splice(j, 1); + j--; + } + } + } + } + const keyResult = await track.demuxer.input._formatOptions.isobmff.resolveKeyId({ keyId, psshBoxes }); + if (!(typeof keyResult === "string" && keyResult.length === 32 && HEX_STRING_REGEX.test(keyResult) || keyResult instanceof Uint8Array && keyResult.byteLength === 16)) { + throw new TypeError("resolveKeyId must return a 32-character hex string or a 16-byte Uint8Array containing the decryption key."); + } + return keyResult instanceof Uint8Array ? keyResult : hexStringToBytes(keyResult); + })(); + track.demuxer.decryptionKeyCache.set(keyId, promise); + keyBytes = await promise; + } + if (encryptionInfo.scheme === "cenc" || encryptionInfo.scheme === "cens") { + return decryptCtr(keyBytes, encryptionInfo, sampleEncryption, data); + } else { + return decryptCbcs(keyBytes, encryptionInfo, sampleEncryption, data); + } + }; + const decryptCtr = async (key, encryptionInfo, sampleEncryption, data) => { + const counter = new Uint8Array(16); + counter.set(sampleEncryption.iv, 0); + const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "AES-CTR" }, false, ["decrypt"]); + const cryptApply = async (input) => { + const plaintext = await crypto.subtle.decrypt({ name: "AES-CTR", counter, length: 64 }, cryptoKey, input); + return new Uint8Array(plaintext); + }; + if (!sampleEncryption.subsamples) { + return cryptApply(data); + } + assert(encryptionInfo.defaultCryptByteBlock !== null && encryptionInfo.defaultSkipByteBlock !== null); + const cryptRanges = collectCryptRanges(sampleEncryption.subsamples, encryptionInfo.defaultCryptByteBlock, encryptionInfo.defaultSkipByteBlock); + let totalCryptLen = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + totalCryptLen += seg.length; + } + } + const cryptBuffer = new Uint8Array(totalCryptLen); + let writePos = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + cryptBuffer.set(data.subarray(seg.offset, seg.offset + seg.length), writePos); + writePos += seg.length; + } + } + const plain = await cryptApply(cryptBuffer); + const output = new Uint8Array(data); + let readPos = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + output.set(plain.subarray(readPos, readPos + seg.length), seg.offset); + readPos += seg.length; + } + } + return output; + }; + const decryptCbcs = (key, encryptionInfo, sampleEncryption, data) => { + const ctx = new Aes128CbcContext(); + ctx.init({ key, iv: sampleEncryption.iv }); + const cryptByteBlock = encryptionInfo.defaultCryptByteBlock; + const skipByteBlock = encryptionInfo.defaultSkipByteBlock; + assert(cryptByteBlock !== null && skipByteBlock !== null); + if (!sampleEncryption.subsamples) { + const output2 = new Uint8Array(data); + const numBlocks = Math.floor(data.length / 16); + for (let b = 0; b < numBlocks; b++) { + const off = b * 16; + ctx.in.set(data.subarray(off, off + 16)); + ctx.decrypt(); + output2.set(ctx.out, off); + } + return output2; + } + if (cryptByteBlock === 0 && skipByteBlock === 0) { + throw new Error("cbcs with subsamples requires pattern encryption."); + } + const output = new Uint8Array(data); + const cryptRanges = collectCryptRanges(sampleEncryption.subsamples, cryptByteBlock, skipByteBlock); + const ivView = new DataView(sampleEncryption.iv.buffer, sampleEncryption.iv.byteOffset, 16); + for (const range of cryptRanges) { + ctx.iv[0] = ivView.getUint32(0, false); + ctx.iv[1] = ivView.getUint32(4, false); + ctx.iv[2] = ivView.getUint32(8, false); + ctx.iv[3] = ivView.getUint32(12, false); + for (const seg of range.perSubsample) { + const numBlocks = seg.length / 16; + for (let b = 0; b < numBlocks; b++) { + const offset = seg.offset + b * 16; + ctx.in.set(data.subarray(offset, offset + 16)); + ctx.decrypt(); + output.set(ctx.out, offset); + } + } + } + return output; + }; + const collectCryptRanges = (subsamples, cryptByteBlock, skipByteBlock) => { + const ranges = []; + const hasPattern = cryptByteBlock !== 0 || skipByteBlock !== 0; + let cursor = 0; + for (const subsample of subsamples) { + cursor += subsample.clearLen; + const perSubsample = []; + if (!hasPattern) { + if (subsample.protectedLen > 0) { + perSubsample.push({ offset: cursor, length: subsample.protectedLen }); + } + cursor += subsample.protectedLen; + } else { + let remaining = subsample.protectedLen; + let pos = cursor; + while (remaining > 0) { + if (remaining < 16 * cryptByteBlock) { + break; + } + const cryptBytes = 16 * cryptByteBlock; + perSubsample.push({ offset: pos, length: cryptBytes }); + pos += cryptBytes; + remaining -= cryptBytes; + const skipBytes = Math.min(16 * skipByteBlock, remaining); + pos += skipBytes; + remaining -= skipBytes; + } + cursor += subsample.protectedLen; + } + ranges.push({ perSubsample }); + } + return ranges; + }; + var EBMLId; + (function(EBMLId2) { + EBMLId2[EBMLId2["EBML"] = 440786851] = "EBML"; + EBMLId2[EBMLId2["EBMLVersion"] = 17030] = "EBMLVersion"; + EBMLId2[EBMLId2["EBMLReadVersion"] = 17143] = "EBMLReadVersion"; + EBMLId2[EBMLId2["EBMLMaxIDLength"] = 17138] = "EBMLMaxIDLength"; + EBMLId2[EBMLId2["EBMLMaxSizeLength"] = 17139] = "EBMLMaxSizeLength"; + EBMLId2[EBMLId2["DocType"] = 17026] = "DocType"; + EBMLId2[EBMLId2["DocTypeVersion"] = 17031] = "DocTypeVersion"; + EBMLId2[EBMLId2["DocTypeReadVersion"] = 17029] = "DocTypeReadVersion"; + EBMLId2[EBMLId2["Void"] = 236] = "Void"; + EBMLId2[EBMLId2["Segment"] = 408125543] = "Segment"; + EBMLId2[EBMLId2["SeekHead"] = 290298740] = "SeekHead"; + EBMLId2[EBMLId2["Seek"] = 19899] = "Seek"; + EBMLId2[EBMLId2["SeekID"] = 21419] = "SeekID"; + EBMLId2[EBMLId2["SeekPosition"] = 21420] = "SeekPosition"; + EBMLId2[EBMLId2["Duration"] = 17545] = "Duration"; + EBMLId2[EBMLId2["Info"] = 357149030] = "Info"; + EBMLId2[EBMLId2["TimestampScale"] = 2807729] = "TimestampScale"; + EBMLId2[EBMLId2["MuxingApp"] = 19840] = "MuxingApp"; + EBMLId2[EBMLId2["WritingApp"] = 22337] = "WritingApp"; + EBMLId2[EBMLId2["Tracks"] = 374648427] = "Tracks"; + EBMLId2[EBMLId2["TrackEntry"] = 174] = "TrackEntry"; + EBMLId2[EBMLId2["TrackNumber"] = 215] = "TrackNumber"; + EBMLId2[EBMLId2["TrackUID"] = 29637] = "TrackUID"; + EBMLId2[EBMLId2["TrackType"] = 131] = "TrackType"; + EBMLId2[EBMLId2["FlagEnabled"] = 185] = "FlagEnabled"; + EBMLId2[EBMLId2["FlagDefault"] = 136] = "FlagDefault"; + EBMLId2[EBMLId2["FlagForced"] = 21930] = "FlagForced"; + EBMLId2[EBMLId2["FlagOriginal"] = 21934] = "FlagOriginal"; + EBMLId2[EBMLId2["FlagHearingImpaired"] = 21931] = "FlagHearingImpaired"; + EBMLId2[EBMLId2["FlagVisualImpaired"] = 21932] = "FlagVisualImpaired"; + EBMLId2[EBMLId2["FlagCommentary"] = 21935] = "FlagCommentary"; + EBMLId2[EBMLId2["FlagLacing"] = 156] = "FlagLacing"; + EBMLId2[EBMLId2["Name"] = 21358] = "Name"; + EBMLId2[EBMLId2["Language"] = 2274716] = "Language"; + EBMLId2[EBMLId2["LanguageBCP47"] = 2274717] = "LanguageBCP47"; + EBMLId2[EBMLId2["CodecID"] = 134] = "CodecID"; + EBMLId2[EBMLId2["CodecPrivate"] = 25506] = "CodecPrivate"; + EBMLId2[EBMLId2["CodecDelay"] = 22186] = "CodecDelay"; + EBMLId2[EBMLId2["SeekPreRoll"] = 22203] = "SeekPreRoll"; + EBMLId2[EBMLId2["DefaultDuration"] = 2352003] = "DefaultDuration"; + EBMLId2[EBMLId2["Video"] = 224] = "Video"; + EBMLId2[EBMLId2["PixelWidth"] = 176] = "PixelWidth"; + EBMLId2[EBMLId2["PixelHeight"] = 186] = "PixelHeight"; + EBMLId2[EBMLId2["DisplayWidth"] = 21680] = "DisplayWidth"; + EBMLId2[EBMLId2["DisplayHeight"] = 21690] = "DisplayHeight"; + EBMLId2[EBMLId2["DisplayUnit"] = 21682] = "DisplayUnit"; + EBMLId2[EBMLId2["AlphaMode"] = 21440] = "AlphaMode"; + EBMLId2[EBMLId2["Audio"] = 225] = "Audio"; + EBMLId2[EBMLId2["SamplingFrequency"] = 181] = "SamplingFrequency"; + EBMLId2[EBMLId2["Channels"] = 159] = "Channels"; + EBMLId2[EBMLId2["BitDepth"] = 25188] = "BitDepth"; + EBMLId2[EBMLId2["SimpleBlock"] = 163] = "SimpleBlock"; + EBMLId2[EBMLId2["BlockGroup"] = 160] = "BlockGroup"; + EBMLId2[EBMLId2["Block"] = 161] = "Block"; + EBMLId2[EBMLId2["BlockAdditions"] = 30113] = "BlockAdditions"; + EBMLId2[EBMLId2["BlockMore"] = 166] = "BlockMore"; + EBMLId2[EBMLId2["BlockAdditional"] = 165] = "BlockAdditional"; + EBMLId2[EBMLId2["BlockAddID"] = 238] = "BlockAddID"; + EBMLId2[EBMLId2["BlockDuration"] = 155] = "BlockDuration"; + EBMLId2[EBMLId2["ReferenceBlock"] = 251] = "ReferenceBlock"; + EBMLId2[EBMLId2["Cluster"] = 524531317] = "Cluster"; + EBMLId2[EBMLId2["Timestamp"] = 231] = "Timestamp"; + EBMLId2[EBMLId2["Cues"] = 475249515] = "Cues"; + EBMLId2[EBMLId2["CuePoint"] = 187] = "CuePoint"; + EBMLId2[EBMLId2["CueTime"] = 179] = "CueTime"; + EBMLId2[EBMLId2["CueTrackPositions"] = 183] = "CueTrackPositions"; + EBMLId2[EBMLId2["CueTrack"] = 247] = "CueTrack"; + EBMLId2[EBMLId2["CueClusterPosition"] = 241] = "CueClusterPosition"; + EBMLId2[EBMLId2["Colour"] = 21936] = "Colour"; + EBMLId2[EBMLId2["MatrixCoefficients"] = 21937] = "MatrixCoefficients"; + EBMLId2[EBMLId2["TransferCharacteristics"] = 21946] = "TransferCharacteristics"; + EBMLId2[EBMLId2["Primaries"] = 21947] = "Primaries"; + EBMLId2[EBMLId2["Range"] = 21945] = "Range"; + EBMLId2[EBMLId2["Projection"] = 30320] = "Projection"; + EBMLId2[EBMLId2["ProjectionType"] = 30321] = "ProjectionType"; + EBMLId2[EBMLId2["ProjectionPoseRoll"] = 30325] = "ProjectionPoseRoll"; + EBMLId2[EBMLId2["Attachments"] = 423732329] = "Attachments"; + EBMLId2[EBMLId2["AttachedFile"] = 24999] = "AttachedFile"; + EBMLId2[EBMLId2["FileDescription"] = 18046] = "FileDescription"; + EBMLId2[EBMLId2["FileName"] = 18030] = "FileName"; + EBMLId2[EBMLId2["FileMediaType"] = 18016] = "FileMediaType"; + EBMLId2[EBMLId2["FileData"] = 18012] = "FileData"; + EBMLId2[EBMLId2["FileUID"] = 18094] = "FileUID"; + EBMLId2[EBMLId2["Chapters"] = 272869232] = "Chapters"; + EBMLId2[EBMLId2["Tags"] = 307544935] = "Tags"; + EBMLId2[EBMLId2["Tag"] = 29555] = "Tag"; + EBMLId2[EBMLId2["Targets"] = 25536] = "Targets"; + EBMLId2[EBMLId2["TargetTypeValue"] = 26826] = "TargetTypeValue"; + EBMLId2[EBMLId2["TargetType"] = 25546] = "TargetType"; + EBMLId2[EBMLId2["TagTrackUID"] = 25541] = "TagTrackUID"; + EBMLId2[EBMLId2["TagEditionUID"] = 25545] = "TagEditionUID"; + EBMLId2[EBMLId2["TagChapterUID"] = 25540] = "TagChapterUID"; + EBMLId2[EBMLId2["TagAttachmentUID"] = 25542] = "TagAttachmentUID"; + EBMLId2[EBMLId2["SimpleTag"] = 26568] = "SimpleTag"; + EBMLId2[EBMLId2["TagName"] = 17827] = "TagName"; + EBMLId2[EBMLId2["TagLanguage"] = 17530] = "TagLanguage"; + EBMLId2[EBMLId2["TagString"] = 17543] = "TagString"; + EBMLId2[EBMLId2["TagBinary"] = 17541] = "TagBinary"; + EBMLId2[EBMLId2["ContentEncodings"] = 28032] = "ContentEncodings"; + EBMLId2[EBMLId2["ContentEncoding"] = 25152] = "ContentEncoding"; + EBMLId2[EBMLId2["ContentEncodingOrder"] = 20529] = "ContentEncodingOrder"; + EBMLId2[EBMLId2["ContentEncodingScope"] = 20530] = "ContentEncodingScope"; + EBMLId2[EBMLId2["ContentCompression"] = 20532] = "ContentCompression"; + EBMLId2[EBMLId2["ContentCompAlgo"] = 16980] = "ContentCompAlgo"; + EBMLId2[EBMLId2["ContentCompSettings"] = 16981] = "ContentCompSettings"; + EBMLId2[EBMLId2["ContentEncryption"] = 20533] = "ContentEncryption"; + })(EBMLId || (EBMLId = {})); + const LEVEL_0_EBML_IDS = [ + EBMLId.EBML, + EBMLId.Segment + ]; + const LEVEL_1_EBML_IDS = [ + EBMLId.SeekHead, + EBMLId.Info, + EBMLId.Cluster, + EBMLId.Tracks, + EBMLId.Cues, + EBMLId.Attachments, + EBMLId.Chapters, + EBMLId.Tags + ]; + const LEVEL_0_AND_1_EBML_IDS = [ + ...LEVEL_0_EBML_IDS, + ...LEVEL_1_EBML_IDS + ]; + const MAX_VAR_INT_SIZE = 8; + const MIN_HEADER_SIZE = 2; + const MAX_HEADER_SIZE = 2 * MAX_VAR_INT_SIZE; + const readVarIntSize = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + slice.skip(-1); + if (firstByte === 0) { + return null; + } + let width = 1; + let mask = 128; + while ((firstByte & mask) === 0) { + width++; + mask >>= 1; + } + if (slice.remainingLength < width) { + return null; + } + return width; + }; + const readVarInt = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + if (firstByte === 0) { + return null; + } + let width = 1; + let mask = 1 << 7; + while ((firstByte & mask) === 0) { + width++; + mask >>= 1; + } + if (slice.remainingLength < width - 1) { + return null; + } + let value = firstByte & mask - 1; + for (let i = 1; i < width; i++) { + value *= 1 << 8; + value += readU8(slice); + } + return value; + }; + const readUnsignedInt = (slice, width) => { + if (width < 1 || width > 8) { + throw new Error("Bad unsigned int size " + width); + } + let value = 0; + for (let i = 0; i < width; i++) { + value *= 1 << 8; + value += readU8(slice); + } + return value; + }; + const readUnsignedBigInt = (slice, width) => { + if (width < 1) { + throw new Error("Bad unsigned int size " + width); + } + let value = 0n; + for (let i = 0; i < width; i++) { + value <<= 8n; + value += BigInt(readU8(slice)); + } + return value; + }; + const readElementId = (slice) => { + const size = readVarIntSize(slice); + if (size === null) { + return null; + } + if (slice.remainingLength < size) { + return null; + } + const id = readUnsignedInt(slice, size); + return id; + }; + const readElementSize = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + if (firstByte === 255) { + return void 0; + } + slice.skip(-1); + const size = readVarInt(slice); + if (size === null) { + return null; + } + if (size === 72057594037927940) { + return void 0; + } + return size; + }; + const readElementHeader = (slice) => { + assert(slice.remainingLength >= MIN_HEADER_SIZE); + const id = readElementId(slice); + if (id === null) { + return null; + } + const size = readElementSize(slice); + if (size === null) { + return null; + } + return { id, size }; + }; + const readAsciiString = (slice, length) => { + const bytes = readBytes(slice, length); + let strLength = 0; + while (strLength < length && bytes[strLength] !== 0) { + strLength += 1; + } + return String.fromCharCode(...bytes.subarray(0, strLength)); + }; + const readUnicodeString = (slice, length) => { + const bytes = readBytes(slice, length); + let strLength = 0; + while (strLength < length && bytes[strLength] !== 0) { + strLength += 1; + } + return textDecoder.decode(bytes.subarray(0, strLength)); + }; + const readFloat = (slice, width) => { + if (width === 0) { + return 0; + } + if (width !== 4 && width !== 8) { + throw new Error("Bad float size " + width); + } + return width === 4 ? readF32Be(slice) : readF64Be(slice); + }; + const searchForNextElementId = async (reader, startPos, ids, until) => { + const idsSet = new Set(ids); + let currentPos = startPos; + while (until === null || currentPos < until) { + let slice = reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementHeader = readElementHeader(slice); + if (!elementHeader) { + break; + } + if (idsSet.has(elementHeader.id)) { + return { pos: currentPos, found: true }; + } + assertDefinedSize(elementHeader.size); + currentPos = slice.filePos + elementHeader.size; + } + return { pos: until !== null && until > currentPos ? until : currentPos, found: false }; + }; + const resync = async (reader, startPos, ids, until) => { + const CHUNK_SIZE = 2 ** 16; + const idsSet = new Set(ids); + let currentPos = startPos; + while (currentPos < until) { + let slice = reader.requestSliceRange(currentPos, 0, Math.min(CHUNK_SIZE, until - currentPos)); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + if (slice.length < MAX_VAR_INT_SIZE) + break; + for (let i = 0; i < slice.length - MAX_VAR_INT_SIZE; i++) { + slice.filePos = currentPos; + const elementId = readElementId(slice); + if (elementId !== null && idsSet.has(elementId)) { + return currentPos; + } + currentPos++; + } + } + return null; + }; + const CODEC_STRING_MAP = { + "avc": "V_MPEG4/ISO/AVC", + "hevc": "V_MPEGH/ISO/HEVC", + "vp8": "V_VP8", + "vp9": "V_VP9", + "av1": "V_AV1", + "aac": "A_AAC", + "mp3": "A_MPEG/L3", + "opus": "A_OPUS", + "vorbis": "A_VORBIS", + "flac": "A_FLAC", + "ac3": "A_AC3", + "eac3": "A_EAC3" + }; + function assertDefinedSize(size) { + if (size === void 0) { + throw new Error("Undefined element size is used in a place where it is not supported."); + } + } + const buildMatroskaMimeType = (info) => { + const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; + let string = base + (info.isWebM ? "webm" : "x-matroska"); + if (info.codecStrings.length > 0) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings.filter(Boolean))]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; + } + return string; + }; + var BlockLacing; + (function(BlockLacing2) { + BlockLacing2[BlockLacing2["None"] = 0] = "None"; + BlockLacing2[BlockLacing2["Xiph"] = 1] = "Xiph"; + BlockLacing2[BlockLacing2["FixedSize"] = 2] = "FixedSize"; + BlockLacing2[BlockLacing2["Ebml"] = 3] = "Ebml"; + })(BlockLacing || (BlockLacing = {})); + var ContentEncodingScope; + (function(ContentEncodingScope2) { + ContentEncodingScope2[ContentEncodingScope2["Block"] = 1] = "Block"; + ContentEncodingScope2[ContentEncodingScope2["Private"] = 2] = "Private"; + ContentEncodingScope2[ContentEncodingScope2["Next"] = 4] = "Next"; + })(ContentEncodingScope || (ContentEncodingScope = {})); + var ContentCompAlgo; + (function(ContentCompAlgo2) { + ContentCompAlgo2[ContentCompAlgo2["Zlib"] = 0] = "Zlib"; + ContentCompAlgo2[ContentCompAlgo2["Bzlib"] = 1] = "Bzlib"; + ContentCompAlgo2[ContentCompAlgo2["lzo1x"] = 2] = "lzo1x"; + ContentCompAlgo2[ContentCompAlgo2["HeaderStripping"] = 3] = "HeaderStripping"; + })(ContentCompAlgo || (ContentCompAlgo = {})); + const METADATA_ELEMENTS = [ + { id: EBMLId.SeekHead, flag: "seekHeadSeen" }, + { id: EBMLId.Info, flag: "infoSeen" }, + { id: EBMLId.Tracks, flag: "tracksSeen" }, + { id: EBMLId.Cues, flag: "cuesSeen" } + ]; + const MAX_RESYNC_LENGTH = 10 * 2 ** 20; + class MatroskaDemuxer extends Demuxer { + constructor(input) { + super(input); + this.readMetadataPromise = null; + this.segments = []; + this.currentSegment = null; + this.currentTrack = null; + this.currentCluster = null; + this.currentBlock = null; + this.currentBlockAdditional = null; + this.currentCueTime = null; + this.currentDecodingInstruction = null; + this.currentTagTargetIsMovie = true; + this.currentSimpleTagName = null; + this.currentAttachedFile = null; + this.isWebM = false; + this.reader = input._reader; + } + async getTrackBackings() { + await this.readMetadata(); + return this.segments.flatMap((segment) => segment.tracks.map((track) => track.trackBacking)); + } + async getMimeType() { + await this.readMetadata(); + const backings = await this.getTrackBackings(); + const codecStrings = await Promise.all(backings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildMatroskaMimeType({ + isWebM: this.isWebM, + hasVideo: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "video")), + hasAudio: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "audio")), + codecStrings: codecStrings.filter(Boolean) + }); + } + async getMetadataTags() { + await this.readMetadata(); + for (const segment of this.segments) { + if (!segment.metadataTagsCollected) { + if (this.reader.fileSize !== null) { + await this.loadSegmentMetadata(segment); + } + segment.metadataTagsCollected = true; + } + } + let metadataTags = {}; + for (const segment of this.segments) { + metadataTags = { ...metadataTags, ...segment.metadataTags }; + } + return metadataTags; + } + readMetadata() { + return this.readMetadataPromise ?? (this.readMetadataPromise = (async () => { + let currentPos = 0; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const header = readElementHeader(slice); + if (!header) { + break; + } + const id = header.id; + let size = header.size; + const dataStartPos = slice.filePos; + if (id === EBMLId.EBML) { + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + this.readContiguousElements(slice2); + } else if (id === EBMLId.Segment) { + await this.readSegment(dataStartPos, size); + if (size === void 0) { + break; + } + if (this.reader.fileSize === null) { + break; + } + } else if (id === EBMLId.Cluster) { + if (this.reader.fileSize === null) { + break; + } + if (size === void 0) { + const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, this.reader.fileSize); + size = nextElementPos.pos - dataStartPos; + } + const lastSegment = last(this.segments); + if (lastSegment) { + lastSegment.elementEndPos = dataStartPos + size; + } + } + assertDefinedSize(size); + currentPos = dataStartPos + size; + } + })()); + } + async readSegment(segmentDataStart, dataSize) { + this.currentSegment = { + seekHeadSeen: false, + infoSeen: false, + tracksSeen: false, + cuesSeen: false, + tagsSeen: false, + attachmentsSeen: false, + timestampScale: -1, + timestampFactor: -1, + duration: -1, + seekEntries: [], + tracks: [], + cuePoints: [], + dataStartPos: segmentDataStart, + elementEndPos: dataSize === void 0 ? null : segmentDataStart + dataSize, + clusterSeekStartPos: segmentDataStart, + lastReadCluster: null, + metadataTags: {}, + metadataTagsCollected: false + }; + this.segments.push(this.currentSegment); + let currentPos = segmentDataStart; + while (this.currentSegment.elementEndPos === null || currentPos < this.currentSegment.elementEndPos) { + let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementStartPos = currentPos; + const header = readElementHeader(slice); + if (!header || !LEVEL_1_EBML_IDS.includes(header.id) && header.id !== EBMLId.Void) { + const nextPos = await resync(this.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(this.currentSegment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); + if (nextPos) { + currentPos = nextPos; + continue; + } else { + break; + } + } + const { id, size } = header; + const dataStartPos = slice.filePos; + const metadataElementIndex = METADATA_ELEMENTS.findIndex((x) => x.id === id); + if (metadataElementIndex !== -1) { + const field = METADATA_ELEMENTS[metadataElementIndex].flag; + this.currentSegment[field] = true; + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (slice2) { + this.readContiguousElements(slice2); + } + } else if (id === EBMLId.Tags || id === EBMLId.Attachments) { + if (id === EBMLId.Tags) { + this.currentSegment.tagsSeen = true; + } else { + this.currentSegment.attachmentsSeen = true; + } + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (slice2) { + this.readContiguousElements(slice2); + } + } else if (id === EBMLId.Cluster) { + this.currentSegment.clusterSeekStartPos = elementStartPos; + break; + } + if (size === void 0) { + break; + } else { + currentPos = dataStartPos + size; + } + } + this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition); + if (this.reader.fileSize !== null) { + for (const seekEntry of this.currentSegment.seekEntries) { + const target = METADATA_ELEMENTS.find((x) => x.id === seekEntry.id); + if (!target) { + continue; + } + if (this.currentSegment[target.flag]) + continue; + let slice = this.reader.requestSliceRange(segmentDataStart + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + continue; + const header = readElementHeader(slice); + if (!header) + continue; + const { id, size } = header; + if (id !== target.id) + continue; + assertDefinedSize(size); + this.currentSegment[target.flag] = true; + let dataSlice = this.reader.requestSlice(slice.filePos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (!dataSlice) + continue; + this.readContiguousElements(dataSlice); + } + } + if (this.currentSegment.timestampScale === -1) { + this.currentSegment.timestampScale = 1e6; + this.currentSegment.timestampFactor = 1e9 / 1e6; + } + for (const track of this.currentSegment.tracks) { + if (track.defaultDurationNs !== null) { + track.defaultDuration = this.currentSegment.timestampFactor * track.defaultDurationNs / 1e9; + } + } + const idToTrack = new Map(this.currentSegment.tracks.map((x) => [x.id, x])); + for (const cuePoint of this.currentSegment.cuePoints) { + const track = idToTrack.get(cuePoint.trackId); + if (track) { + track.cuePoints.push(cuePoint); + } + } + for (const track of this.currentSegment.tracks) { + track.cuePoints.sort((a, b) => a.time - b.time); + for (let i = 0; i < track.cuePoints.length - 1; i++) { + const cuePoint1 = track.cuePoints[i]; + const cuePoint2 = track.cuePoints[i + 1]; + if (cuePoint1.time === cuePoint2.time) { + track.cuePoints.splice(i + 1, 1); + i--; + } + } + } + let trackWithMostCuePoints = null; + let maxCuePointCount = -Infinity; + for (const track of this.currentSegment.tracks) { + if (track.cuePoints.length > maxCuePointCount) { + maxCuePointCount = track.cuePoints.length; + trackWithMostCuePoints = track; + } + } + for (const track of this.currentSegment.tracks) { + if (track.cuePoints.length === 0) { + track.cuePoints = trackWithMostCuePoints.cuePoints; + } + } + this.currentSegment = null; + } + async readCluster(startPos, segment) { + if (segment.lastReadCluster?.elementStartPos === startPos) { + return segment.lastReadCluster; + } + let headerSlice = this.reader.requestSliceRange(startPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const elementStartPos = startPos; + const elementHeader = readElementHeader(headerSlice); + assert(elementHeader); + const id = elementHeader.id; + assert(id === EBMLId.Cluster); + let size = elementHeader.size; + const dataStartPos = headerSlice.filePos; + if (size === void 0) { + const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); + size = nextElementPos.pos - dataStartPos; + } + let dataSlice = this.reader.requestSlice(dataStartPos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + const cluster = { + segment, + elementStartPos, + elementEndPos: dataStartPos + size, + dataStartPos, + timestamp: -1, + trackData: /* @__PURE__ */ new Map() + }; + this.currentCluster = cluster; + if (dataSlice) { + const endPos = this.readContiguousElements(dataSlice, LEVEL_0_AND_1_EBML_IDS); + cluster.elementEndPos = endPos; + } + for (const [, trackData] of cluster.trackData) { + const track = trackData.track; + assert(trackData.blocks.length > 0); + let hasLacedBlocks = false; + for (let i = 0; i < trackData.blocks.length; i++) { + const block = trackData.blocks[i]; + block.timestamp += cluster.timestamp; + hasLacedBlocks || (hasLacedBlocks = block.lacing !== BlockLacing.None); + } + trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); + for (let i = 0; i < trackData.presentationTimestamps.length; i++) { + const currentEntry = trackData.presentationTimestamps[i]; + const currentBlock = trackData.blocks[currentEntry.blockIndex]; + if (trackData.firstKeyFrameTimestamp === null && currentBlock.isKeyFrame) { + trackData.firstKeyFrameTimestamp = currentBlock.timestamp; + } + if (i < trackData.presentationTimestamps.length - 1) { + const nextEntry = trackData.presentationTimestamps[i + 1]; + currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp; + } else if (currentBlock.duration === 0) { + if (track.defaultDuration != null) { + if (currentBlock.lacing === BlockLacing.None) { + currentBlock.duration = track.defaultDuration; + } + } + } + } + if (hasLacedBlocks) { + this.expandLacedBlocks(trackData.blocks, track); + trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); + } + const firstBlock = trackData.blocks[trackData.presentationTimestamps[0].blockIndex]; + const lastBlock = trackData.blocks[last(trackData.presentationTimestamps).blockIndex]; + trackData.startTimestamp = firstBlock.timestamp; + trackData.endTimestamp = lastBlock.timestamp + lastBlock.duration; + const insertionIndex = binarySearchLessOrEqual(track.clusterPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); + if (insertionIndex === -1 || track.clusterPositionCache[insertionIndex].elementStartPos !== elementStartPos) { + track.clusterPositionCache.splice(insertionIndex + 1, 0, { + elementStartPos: cluster.elementStartPos, + startTimestamp: trackData.startTimestamp + }); + } + } + segment.lastReadCluster = cluster; + return cluster; + } + getTrackDataInCluster(cluster, trackNumber) { + let trackData = cluster.trackData.get(trackNumber); + if (!trackData) { + const track = cluster.segment.tracks.find((x) => x.id === trackNumber); + if (!track) { + return null; + } + trackData = { + track, + startTimestamp: 0, + endTimestamp: 0, + firstKeyFrameTimestamp: null, + blocks: [], + presentationTimestamps: [] + }; + cluster.trackData.set(trackNumber, trackData); + } + return trackData; + } + expandLacedBlocks(blocks, track) { + for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) { + const originalBlock = blocks[blockIndex]; + if (originalBlock.lacing === BlockLacing.None) { + continue; + } + if (!originalBlock.decoded) { + originalBlock.data = this.decodeBlockData(track, originalBlock.data); + originalBlock.decoded = true; + } + const slice = FileSlice.tempFromBytes(originalBlock.data); + const frameSizes = []; + const frameCount = readU8(slice) + 1; + switch (originalBlock.lacing) { + case BlockLacing.Xiph: + { + let totalUsedSize = 0; + for (let i = 0; i < frameCount - 1; i++) { + let frameSize = 0; + while (slice.bufferPos < slice.length) { + const value = readU8(slice); + frameSize += value; + if (value < 255) { + frameSizes.push(frameSize); + totalUsedSize += frameSize; + break; + } + } + } + frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); + } + break; + case BlockLacing.FixedSize: + { + const totalDataSize = slice.length - 1; + const frameSize = Math.floor(totalDataSize / frameCount); + for (let i = 0; i < frameCount; i++) { + frameSizes.push(frameSize); + } + } + break; + case BlockLacing.Ebml: + { + const firstResult = readVarInt(slice); + assert(firstResult !== null); + let currentSize = firstResult; + frameSizes.push(currentSize); + let totalUsedSize = currentSize; + for (let i = 1; i < frameCount - 1; i++) { + const startPos = slice.bufferPos; + const diffResult = readVarInt(slice); + assert(diffResult !== null); + const unsignedDiff = diffResult; + const width = slice.bufferPos - startPos; + const bias = (1 << width * 7 - 1) - 1; + const diff = unsignedDiff - bias; + currentSize += diff; + frameSizes.push(currentSize); + totalUsedSize += currentSize; + } + frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); + } + break; + default: + assert(false); + } + assert(frameSizes.length === frameCount); + blocks.splice(blockIndex, 1); + const blockDuration = originalBlock.duration || frameCount * (track.defaultDuration ?? 0); + for (let i = 0; i < frameCount; i++) { + const frameSize = frameSizes[i]; + const frameData = readBytes(slice, frameSize); + const frameTimestamp = originalBlock.timestamp + blockDuration * i / frameCount; + const frameDuration = blockDuration / frameCount; + blocks.splice(blockIndex + i, 0, { + timestamp: frameTimestamp, + duration: frameDuration, + isKeyFrame: originalBlock.isKeyFrame, + data: frameData, + lacing: BlockLacing.None, + decoded: true, + mainAdditional: originalBlock.mainAdditional + }); + } + blockIndex += frameCount; + blockIndex--; + } + } + async loadSegmentMetadata(segment) { + for (const seekEntry of segment.seekEntries) { + if (seekEntry.id === EBMLId.Tags && !segment.tagsSeen) ; + else if (seekEntry.id === EBMLId.Attachments && !segment.attachmentsSeen) ; + else { + continue; + } + let slice = this.reader.requestSliceRange(segment.dataStartPos + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + continue; + const header = readElementHeader(slice); + if (!header || header.id !== seekEntry.id) + continue; + const { size } = header; + assertDefinedSize(size); + assert(!this.currentSegment); + this.currentSegment = segment; + let dataSlice = this.reader.requestSlice(slice.filePos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (dataSlice) { + this.readContiguousElements(dataSlice); + } + this.currentSegment = null; + if (seekEntry.id === EBMLId.Tags) { + segment.tagsSeen = true; + } else if (seekEntry.id === EBMLId.Attachments) { + segment.attachmentsSeen = true; + } + } + } + readContiguousElements(slice, stopIds) { + while (slice.remainingLength >= MIN_HEADER_SIZE) { + const startPos = slice.filePos; + const foundElement = this.traverseElement(slice, stopIds); + if (!foundElement) { + return startPos; + } + } + return slice.filePos; + } + traverseElement(slice, stopIds) { + const header = readElementHeader(slice); + if (!header) { + return false; + } + if (stopIds && stopIds.includes(header.id)) { + return false; + } + const { id, size } = header; + const dataStartPos = slice.filePos; + assertDefinedSize(size); + switch (id) { + case EBMLId.DocType: + { + this.isWebM = readAsciiString(slice, size) === "webm"; + } + break; + case EBMLId.Seek: + { + if (!this.currentSegment) + break; + const seekEntry = { id: -1, segmentPosition: -1 }; + this.currentSegment.seekEntries.push(seekEntry); + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (seekEntry.id === -1 || seekEntry.segmentPosition === -1) { + this.currentSegment.seekEntries.pop(); + } + } + break; + case EBMLId.SeekID: + { + const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; + if (!lastSeekEntry) + break; + lastSeekEntry.id = readUnsignedInt(slice, size); + } + break; + case EBMLId.SeekPosition: + { + const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; + if (!lastSeekEntry) + break; + lastSeekEntry.segmentPosition = readUnsignedInt(slice, size); + } + break; + case EBMLId.TimestampScale: + { + if (!this.currentSegment) + break; + this.currentSegment.timestampScale = readUnsignedInt(slice, size); + this.currentSegment.timestampFactor = 1e9 / this.currentSegment.timestampScale; + } + break; + case EBMLId.Duration: + { + if (!this.currentSegment) + break; + this.currentSegment.duration = readFloat(slice, size); + } + break; + case EBMLId.TrackEntry: + { + if (!this.currentSegment) + break; + this.currentTrack = { + id: -1, + segment: this.currentSegment, + demuxer: this, + clusterPositionCache: [], + cuePoints: [], + disposition: { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }, + trackBacking: null, + codecId: null, + codecPrivate: null, + defaultDuration: null, + defaultDurationNs: null, + name: null, + languageCode: "eng", + // The default in Matroska + hasLanguageBcp47: false, + decodingInstructions: [], + info: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (!this.currentTrack) { + break; + } + if (this.currentTrack.decodingInstructions.some((instruction) => { + return instruction.data?.type !== "decompress" || instruction.scope !== ContentEncodingScope.Block || instruction.data.algorithm !== ContentCompAlgo.HeaderStripping; + })) { + console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`); + this.currentTrack = null; + } + if (this.currentTrack && this.currentTrack.id !== -1 && this.currentTrack.codecId && this.currentTrack.info) { + const slashIndex = this.currentTrack.codecId.indexOf("/"); + const codecIdWithoutSuffix = slashIndex === -1 ? this.currentTrack.codecId : this.currentTrack.codecId.slice(0, slashIndex); + if (this.currentTrack.info.type === "video" && this.currentTrack.info.width !== -1 && this.currentTrack.info.height !== -1) { + this.currentTrack.info.squarePixelWidth = this.currentTrack.info.width; + this.currentTrack.info.squarePixelHeight = this.currentTrack.info.height; + if (this.currentTrack.info.displayWidth !== null && this.currentTrack.info.displayHeight !== null) { + const num = this.currentTrack.info.displayWidth * this.currentTrack.info.height; + const den = this.currentTrack.info.displayHeight * this.currentTrack.info.width; + if (num > 0 && den > 0) { + if (num > den) { + this.currentTrack.info.squarePixelWidth = Math.round(this.currentTrack.info.width * num / den); + } else { + this.currentTrack.info.squarePixelHeight = Math.round(this.currentTrack.info.height * den / num); + } + } + } + if (this.currentTrack.codecId === CODEC_STRING_MAP.avc) { + this.currentTrack.info.codec = "avc"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === CODEC_STRING_MAP.hevc) { + this.currentTrack.info.codec = "hevc"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp8) { + this.currentTrack.info.codec = "vp8"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp9) { + this.currentTrack.info.codec = "vp9"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.av1) { + this.currentTrack.info.codec = "av1"; + } + const videoTrack = this.currentTrack; + this.currentTrack.trackBacking = new MatroskaVideoTrackBacking(videoTrack); + this.currentSegment.tracks.push(this.currentTrack); + } else if (this.currentTrack.info.type === "audio") { + if (codecIdWithoutSuffix === CODEC_STRING_MAP.aac) { + this.currentTrack.info.codec = "aac"; + this.currentTrack.info.aacCodecInfo = { + isMpeg2: this.currentTrack.codecId.includes("MPEG2"), + objectType: null + }; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === CODEC_STRING_MAP.mp3) { + this.currentTrack.info.codec = "mp3"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.opus) { + this.currentTrack.info.codec = "opus"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + this.currentTrack.info.sampleRate = OPUS_SAMPLE_RATE; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vorbis) { + this.currentTrack.info.codec = "vorbis"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.flac) { + this.currentTrack.info.codec = "flac"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.ac3) { + this.currentTrack.info.codec = "ac3"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.eac3) { + this.currentTrack.info.codec = "eac3"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === "A_PCM/INT/LIT") { + if (this.currentTrack.info.bitDepth === 8) { + this.currentTrack.info.codec = "pcm-u8"; + } else if (this.currentTrack.info.bitDepth === 16) { + this.currentTrack.info.codec = "pcm-s16"; + } else if (this.currentTrack.info.bitDepth === 24) { + this.currentTrack.info.codec = "pcm-s24"; + } else if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-s32"; + } + } else if (this.currentTrack.codecId === "A_PCM/INT/BIG") { + if (this.currentTrack.info.bitDepth === 8) { + this.currentTrack.info.codec = "pcm-u8"; + } else if (this.currentTrack.info.bitDepth === 16) { + this.currentTrack.info.codec = "pcm-s16be"; + } else if (this.currentTrack.info.bitDepth === 24) { + this.currentTrack.info.codec = "pcm-s24be"; + } else if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-s32be"; + } + } else if (this.currentTrack.codecId === "A_PCM/FLOAT/IEEE") { + if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-f32"; + } else if (this.currentTrack.info.bitDepth === 64) { + this.currentTrack.info.codec = "pcm-f64"; + } + } + const audioTrack = this.currentTrack; + this.currentTrack.trackBacking = new MatroskaAudioTrackBacking(audioTrack); + this.currentSegment.tracks.push(this.currentTrack); + } + } + this.currentTrack = null; + } + break; + case EBMLId.TrackNumber: + { + if (!this.currentTrack) + break; + this.currentTrack.id = readUnsignedInt(slice, size); + } + break; + case EBMLId.TrackType: + { + if (!this.currentTrack) + break; + const type = readUnsignedInt(slice, size); + if (type === 1) { + this.currentTrack.info = { + type: "video", + width: -1, + height: -1, + displayWidth: null, + displayHeight: null, + displayUnit: null, + squarePixelWidth: -1, + squarePixelHeight: -1, + rotation: 0, + codec: null, + codecDescription: null, + colorSpace: null, + alphaMode: false + }; + } else if (type === 2) { + this.currentTrack.info = { + type: "audio", + numberOfChannels: 1, + // Default value + sampleRate: 8e3, + // Default value + bitDepth: -1, + codec: null, + codecDescription: null, + aacCodecInfo: null + }; + } + } + break; + case EBMLId.FlagEnabled: + { + if (!this.currentTrack) + break; + const enabled = readUnsignedInt(slice, size); + if (!enabled) { + this.currentTrack = null; + } + } + break; + case EBMLId.FlagDefault: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.default = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagForced: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.forced = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagOriginal: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.original = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagHearingImpaired: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.hearingImpaired = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagVisualImpaired: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.visuallyImpaired = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagCommentary: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.commentary = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.CodecID: + { + if (!this.currentTrack) + break; + this.currentTrack.codecId = readAsciiString(slice, size); + } + break; + case EBMLId.CodecPrivate: + { + if (!this.currentTrack) + break; + this.currentTrack.codecPrivate = readBytes(slice, size); + } + break; + case EBMLId.DefaultDuration: + { + if (!this.currentTrack) + break; + this.currentTrack.defaultDurationNs = readUnsignedInt(slice, size); + } + break; + case EBMLId.Name: + { + if (!this.currentTrack) + break; + this.currentTrack.name = readUnicodeString(slice, size); + } + break; + case EBMLId.Language: + { + if (!this.currentTrack) + break; + if (this.currentTrack.hasLanguageBcp47) { + break; + } + this.currentTrack.languageCode = readAsciiString(slice, size); + if (!isIso639Dash2LanguageCode(this.currentTrack.languageCode)) { + this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; + } + } + break; + case EBMLId.LanguageBCP47: + { + if (!this.currentTrack) + break; + const bcp47 = readAsciiString(slice, size); + const languageSubtag = bcp47.split("-")[0]; + if (languageSubtag) { + this.currentTrack.languageCode = languageSubtag; + } else { + this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; + } + this.currentTrack.hasLanguageBcp47 = true; + } + break; + case EBMLId.Video: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.PixelWidth: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.width = readUnsignedInt(slice, size); + } + break; + case EBMLId.PixelHeight: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.height = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayWidth: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayWidth = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayHeight: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayHeight = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayUnit: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayUnit = readUnsignedInt(slice, size); + } + break; + case EBMLId.AlphaMode: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.alphaMode = readUnsignedInt(slice, size) === 1; + } + break; + case EBMLId.Colour: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.colorSpace = {}; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.MatrixCoefficients: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const matrixCoefficients = readUnsignedInt(slice, size); + const mapped = MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients] ?? null; + this.currentTrack.info.colorSpace.matrix = mapped; + } + break; + case EBMLId.Range: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + this.currentTrack.info.colorSpace.fullRange = readUnsignedInt(slice, size) === 2; + } + break; + case EBMLId.TransferCharacteristics: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const transferCharacteristics = readUnsignedInt(slice, size); + const mapped = TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics] ?? null; + this.currentTrack.info.colorSpace.transfer = mapped; + } + break; + case EBMLId.Primaries: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const primaries = readUnsignedInt(slice, size); + const mapped = COLOR_PRIMARIES_MAP_INVERSE[primaries] ?? null; + this.currentTrack.info.colorSpace.primaries = mapped; + } + break; + case EBMLId.Projection: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.ProjectionPoseRoll: + { + if (this.currentTrack?.info?.type !== "video") + break; + const rotation = readFloat(slice, size); + const flippedRotation = -rotation; + try { + this.currentTrack.info.rotation = normalizeRotation(flippedRotation); + } catch { + } + } + break; + case EBMLId.Audio: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.SamplingFrequency: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.sampleRate = readFloat(slice, size); + } + break; + case EBMLId.Channels: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.numberOfChannels = readUnsignedInt(slice, size); + } + break; + case EBMLId.BitDepth: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.bitDepth = readUnsignedInt(slice, size); + } + break; + case EBMLId.CuePoint: + { + if (!this.currentSegment) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentCueTime = null; + } + break; + case EBMLId.CueTime: + { + this.currentCueTime = readUnsignedInt(slice, size); + } + break; + case EBMLId.CueTrackPositions: + { + if (this.currentCueTime === null) + break; + assert(this.currentSegment); + const cuePoint = { time: this.currentCueTime, trackId: -1, clusterPosition: -1 }; + this.currentSegment.cuePoints.push(cuePoint); + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (cuePoint.trackId === -1 || cuePoint.clusterPosition === -1) { + this.currentSegment.cuePoints.pop(); + } + } + break; + case EBMLId.CueTrack: + { + const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; + if (!lastCuePoint) + break; + lastCuePoint.trackId = readUnsignedInt(slice, size); + } + break; + case EBMLId.CueClusterPosition: + { + const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; + if (!lastCuePoint) + break; + assert(this.currentSegment); + lastCuePoint.clusterPosition = this.currentSegment.dataStartPos + readUnsignedInt(slice, size); + } + break; + case EBMLId.Timestamp: + { + if (!this.currentCluster) + break; + this.currentCluster.timestamp = readUnsignedInt(slice, size); + } + break; + case EBMLId.SimpleBlock: + { + if (!this.currentCluster) + break; + const trackNumber = readVarInt(slice); + if (trackNumber === null) + break; + const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); + if (!trackData) + break; + const relativeTimestamp = readI16Be(slice); + const flags = readU8(slice); + const lacing = flags >> 1 & 3; + let isKeyFrame = !!(flags & 128); + if (trackData.track.info?.type === "audio" && trackData.track.info.codec) { + isKeyFrame = true; + } + const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); + const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; + trackData.blocks.push({ + timestamp: relativeTimestamp, + // We'll add the cluster's timestamp to this later + duration: 0, + // Will set later + isKeyFrame, + data: blockData, + lacing, + decoded: !hasDecodingInstructions, + mainAdditional: null + }); + } + break; + case EBMLId.BlockGroup: + { + if (!this.currentCluster) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentBlock = null; + } + break; + case EBMLId.Block: + { + if (!this.currentCluster) + break; + const trackNumber = readVarInt(slice); + if (trackNumber === null) + break; + const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); + if (!trackData) + break; + const relativeTimestamp = readI16Be(slice); + const flags = readU8(slice); + const lacing = flags >> 1 & 3; + const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); + const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; + this.currentBlock = { + timestamp: relativeTimestamp, + // We'll add the cluster's timestamp to this later + duration: 0, + // Will set later + isKeyFrame: true, + data: blockData, + lacing, + decoded: !hasDecodingInstructions, + mainAdditional: null + }; + trackData.blocks.push(this.currentBlock); + } + break; + case EBMLId.BlockAdditions: + { + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.BlockMore: + { + if (!this.currentBlock) + break; + this.currentBlockAdditional = { + addId: 1, + data: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (this.currentBlockAdditional.data && this.currentBlockAdditional.addId === 1) { + this.currentBlock.mainAdditional = this.currentBlockAdditional.data; + } + this.currentBlockAdditional = null; + } + break; + case EBMLId.BlockAdditional: + { + if (!this.currentBlockAdditional) + break; + this.currentBlockAdditional.data = readBytes(slice, size); + } + break; + case EBMLId.BlockAddID: + { + if (!this.currentBlockAdditional) + break; + this.currentBlockAdditional.addId = readUnsignedInt(slice, size); + } + break; + case EBMLId.BlockDuration: + { + if (!this.currentBlock) + break; + this.currentBlock.duration = readUnsignedInt(slice, size); + } + break; + case EBMLId.ReferenceBlock: + { + if (!this.currentBlock) + break; + this.currentBlock.isKeyFrame = false; + } + break; + case EBMLId.Tag: + { + this.currentTagTargetIsMovie = true; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.Targets: + { + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.TargetTypeValue: + { + const targetTypeValue = readUnsignedInt(slice, size); + if (targetTypeValue !== 50) { + this.currentTagTargetIsMovie = false; + } + } + break; + case EBMLId.TagTrackUID: + case EBMLId.TagEditionUID: + case EBMLId.TagChapterUID: + case EBMLId.TagAttachmentUID: + { + this.currentTagTargetIsMovie = false; + } + break; + case EBMLId.SimpleTag: + { + if (!this.currentTagTargetIsMovie) + break; + this.currentSimpleTagName = null; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.TagName: + { + this.currentSimpleTagName = readUnicodeString(slice, size); + } + break; + case EBMLId.TagString: + { + if (!this.currentSimpleTagName) + break; + const value = readUnicodeString(slice, size); + this.processTagValue(this.currentSimpleTagName, value); + } + break; + case EBMLId.TagBinary: + { + if (!this.currentSimpleTagName) + break; + const value = readBytes(slice, size); + this.processTagValue(this.currentSimpleTagName, value); + } + break; + case EBMLId.AttachedFile: + { + if (!this.currentSegment) + break; + this.currentAttachedFile = { + fileUid: null, + fileName: null, + fileMediaType: null, + fileData: null, + fileDescription: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + const tags = this.currentSegment.metadataTags; + if (this.currentAttachedFile.fileUid && this.currentAttachedFile.fileData) { + tags.raw ?? (tags.raw = {}); + tags.raw[this.currentAttachedFile.fileUid.toString()] = new AttachedFile(this.currentAttachedFile.fileData, this.currentAttachedFile.fileMediaType ?? void 0, this.currentAttachedFile.fileName ?? void 0, this.currentAttachedFile.fileDescription ?? void 0); + } + if (this.currentAttachedFile.fileMediaType?.startsWith("image/") && this.currentAttachedFile.fileData) { + const fileName = this.currentAttachedFile.fileName; + let kind = "unknown"; + if (fileName) { + const lowerName = fileName.toLowerCase(); + if (lowerName.startsWith("cover.")) { + kind = "coverFront"; + } else if (lowerName.startsWith("back.")) { + kind = "coverBack"; + } + } + tags.images ?? (tags.images = []); + tags.images.push({ + data: this.currentAttachedFile.fileData, + mimeType: this.currentAttachedFile.fileMediaType, + kind, + name: this.currentAttachedFile.fileName ?? void 0, + description: this.currentAttachedFile.fileDescription ?? void 0 + }); + } + this.currentAttachedFile = null; + } + break; + case EBMLId.FileUID: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileUid = readUnsignedBigInt(slice, size); + } + break; + case EBMLId.FileName: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileName = readUnicodeString(slice, size); + } + break; + case EBMLId.FileMediaType: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileMediaType = readAsciiString(slice, size); + } + break; + case EBMLId.FileData: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileData = readBytes(slice, size); + } + break; + case EBMLId.FileDescription: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileDescription = readUnicodeString(slice, size); + } + break; + case EBMLId.ContentEncodings: + { + if (!this.currentTrack) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentTrack.decodingInstructions.sort((a, b) => b.order - a.order); + } + break; + case EBMLId.ContentEncoding: + { + this.currentDecodingInstruction = { + order: 0, + scope: ContentEncodingScope.Block, + data: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (this.currentDecodingInstruction.data) { + this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction); + } + this.currentDecodingInstruction = null; + } + break; + case EBMLId.ContentEncodingOrder: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.order = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentEncodingScope: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.scope = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentCompression: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.data = { + type: "decompress", + algorithm: ContentCompAlgo.Zlib, + settings: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.ContentCompAlgo: + { + if (this.currentDecodingInstruction?.data?.type !== "decompress") + break; + this.currentDecodingInstruction.data.algorithm = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentCompSettings: + { + if (this.currentDecodingInstruction?.data?.type !== "decompress") + break; + this.currentDecodingInstruction.data.settings = readBytes(slice, size); + } + break; + case EBMLId.ContentEncryption: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.data = { + type: "decrypt" + }; + } + break; + } + slice.filePos = dataStartPos + size; + return true; + } + decodeBlockData(track, rawData) { + assert(track.decodingInstructions.length > 0); + let currentData = rawData; + for (const instruction of track.decodingInstructions) { + assert(instruction.data); + switch (instruction.data.type) { + case "decompress": + { + switch (instruction.data.algorithm) { + case ContentCompAlgo.HeaderStripping: + { + if (instruction.data.settings && instruction.data.settings.length > 0) { + const prefix = instruction.data.settings; + const newData = new Uint8Array(prefix.length + currentData.length); + newData.set(prefix, 0); + newData.set(currentData, prefix.length); + currentData = newData; + } + } + break; + } + } + break; + } + } + return currentData; + } + processTagValue(name, value) { + var _a; + if (!this.currentSegment?.metadataTags) + return; + const metadataTags = this.currentSegment.metadataTags; + metadataTags.raw ?? (metadataTags.raw = {}); + (_a = metadataTags.raw)[name] ?? (_a[name] = value); + if (typeof value === "string") { + switch (name.toLowerCase()) { + case "title": + { + metadataTags.title ?? (metadataTags.title = value); + } + break; + case "description": + { + metadataTags.description ?? (metadataTags.description = value); + } + break; + case "artist": + { + metadataTags.artist ?? (metadataTags.artist = value); + } + break; + case "album": + { + metadataTags.album ?? (metadataTags.album = value); + } + break; + case "album_artist": + { + metadataTags.albumArtist ?? (metadataTags.albumArtist = value); + } + break; + case "genre": + { + metadataTags.genre ?? (metadataTags.genre = value); + } + break; + case "comment": + { + metadataTags.comment ?? (metadataTags.comment = value); + } + break; + case "lyrics": + { + metadataTags.lyrics ?? (metadataTags.lyrics = value); + } + break; + case "date": + { + const date = new Date(value); + if (!Number.isNaN(date.getTime())) { + metadataTags.date ?? (metadataTags.date = date); + } + } + break; + case "track_number": + case "part_number": + { + const parts = value.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + metadataTags.trackNumber ?? (metadataTags.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + metadataTags.tracksTotal ?? (metadataTags.tracksTotal = tracksTotal); + } + } + break; + case "disc_number": + case "disc": + { + const discParts = value.split("/"); + const discNum = Number.parseInt(discParts[0], 10); + const discsTotal = discParts[1] && Number.parseInt(discParts[1], 10); + if (Number.isInteger(discNum) && discNum > 0) { + metadataTags.discNumber ?? (metadataTags.discNumber = discNum); + } + if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) { + metadataTags.discsTotal ?? (metadataTags.discsTotal = discsTotal); + } + } + break; + } + } + } + } + class MatroskaTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.packetToClusterLocation = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.internalTrack.id; + } + getNumber() { + const demuxer = this.internalTrack.demuxer; + const trackType = this.internalTrack.trackBacking.getType(); + let number = 0; + for (const segment of demuxer.segments) { + for (const track of segment.tracks) { + if (track.trackBacking.getType() === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.internalTrack.codecId; + } + getName() { + return this.internalTrack.name; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getTimeResolution() { + return this.internalTrack.segment.timestampFactor; + } + isRelativeToUnixEpoch() { + return false; + } + getDisposition() { + return this.internalTrack.disposition; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const segment = this.internalTrack.segment; + if (segment.duration <= 0) { + return null; + } + let endTimestamp = segment.duration / segment.timestampFactor; + const firstPacket = await this.getFirstPacket({ metadataOnly: true }); + endTimestamp += firstPacket?.timestamp ?? 0; + return endTimestamp; + } + async getLiveRefreshInterval() { + return null; + } + async getFirstPacket(options) { + return this.performClusterLookup( + null, + (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData) { + return { + blockIndex: 0, + correctBlockFound: true + }; + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + intoTimescale(timestamp) { + return roundIfAlmostInteger(timestamp * this.internalTrack.segment.timestampFactor); + } + async getPacket(timestamp, options) { + const timestampInTimescale = this.intoTimescale(timestamp); + return this.performClusterLookup(null, (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (!trackData) { + return { blockIndex: -1, correctBlockFound: false }; + } + const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.timestamp); + const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; + const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { blockIndex, correctBlockFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextPacket(packet, options) { + const locationInCluster = this.packetToClusterLocation.get(packet); + if (locationInCluster === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performClusterLookup( + locationInCluster.cluster, + (cluster) => { + if (cluster === locationInCluster.cluster) { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (locationInCluster.blockIndex + 1 < trackData.blocks.length) { + return { + blockIndex: locationInCluster.blockIndex + 1, + correctBlockFound: true + }; + } + } else { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData) { + return { + blockIndex: 0, + correctBlockFound: true + }; + } + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + async getKeyPacket(timestamp, options) { + const timestampInTimescale = this.intoTimescale(timestamp); + return this.performClusterLookup(null, (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (!trackData) { + return { blockIndex: -1, correctBlockFound: false }; + } + const index = findLastIndex(trackData.presentationTimestamps, (x) => { + const block = trackData.blocks[x.blockIndex]; + return block.isKeyFrame && x.timestamp <= timestampInTimescale; + }); + const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; + const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { blockIndex, correctBlockFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextKeyPacket(packet, options) { + const locationInCluster = this.packetToClusterLocation.get(packet); + if (locationInCluster === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performClusterLookup( + locationInCluster.cluster, + (cluster) => { + if (cluster === locationInCluster.cluster) { + const trackData = cluster.trackData.get(this.internalTrack.id); + const nextKeyFrameIndex = trackData.blocks.findIndex((x, i) => x.isKeyFrame && i > locationInCluster.blockIndex); + if (nextKeyFrameIndex !== -1) { + return { + blockIndex: nextKeyFrameIndex, + correctBlockFound: true + }; + } + } else { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData && trackData.firstKeyFrameTimestamp !== null) { + const keyFrameIndex = trackData.blocks.findIndex((x) => x.isKeyFrame); + assert(keyFrameIndex !== -1); + return { + blockIndex: keyFrameIndex, + correctBlockFound: true + }; + } + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + async fetchPacketInCluster(cluster, blockIndex, options) { + if (blockIndex === -1) { + return null; + } + const trackData = cluster.trackData.get(this.internalTrack.id); + const block = trackData.blocks[blockIndex]; + assert(block); + if (!block.decoded) { + block.data = this.internalTrack.demuxer.decodeBlockData(this.internalTrack, block.data); + block.decoded = true; + } + const data = options.metadataOnly ? PLACEHOLDER_DATA : block.data; + const timestamp = block.timestamp / this.internalTrack.segment.timestampFactor; + const duration = block.duration / this.internalTrack.segment.timestampFactor; + const sideData = {}; + if (block.mainAdditional && this.internalTrack.info?.type === "video" && this.internalTrack.info.alphaMode) { + sideData.alpha = options.metadataOnly ? PLACEHOLDER_DATA : block.mainAdditional; + sideData.alphaByteLength = block.mainAdditional.byteLength; + } + const packet = new EncodedPacket(data, block.isKeyFrame ? "key" : "delta", timestamp, duration, cluster.dataStartPos + blockIndex, block.data.byteLength, sideData); + this.packetToClusterLocation.set(packet, { cluster, blockIndex }); + return packet; + } + /** Looks for a packet in the clusters while trying to load as few clusters as possible to retrieve it. */ + async performClusterLookup(startCluster, getMatchInCluster, searchTimestamp, latestTimestamp, options) { + const { demuxer, segment } = this.internalTrack; + let currentCluster = null; + let bestCluster = null; + let bestBlockIndex = -1; + if (startCluster) { + const { blockIndex, correctBlockFound } = getMatchInCluster(startCluster); + if (correctBlockFound) { + return this.fetchPacketInCluster(startCluster, blockIndex, options); + } + if (blockIndex !== -1) { + bestCluster = startCluster; + bestBlockIndex = blockIndex; + } + } + const cuePointIndex = binarySearchLessOrEqual(this.internalTrack.cuePoints, searchTimestamp, (x) => x.time); + const cuePoint = cuePointIndex !== -1 ? this.internalTrack.cuePoints[cuePointIndex] : null; + const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.clusterPositionCache, searchTimestamp, (x) => x.startTimestamp); + const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.clusterPositionCache[positionCacheIndex] : null; + const lookupEntryPosition = Math.max(cuePoint?.clusterPosition ?? 0, positionCacheEntry?.elementStartPos ?? 0) || null; + let currentPos; + if (!startCluster) { + currentPos = lookupEntryPosition ?? segment.clusterSeekStartPos; + } else { + if (lookupEntryPosition === null || startCluster.elementStartPos >= lookupEntryPosition) { + currentPos = startCluster.elementEndPos; + currentCluster = startCluster; + } else { + currentPos = lookupEntryPosition; + } + } + while (segment.elementEndPos === null || currentPos <= segment.elementEndPos - MIN_HEADER_SIZE) { + if (currentCluster) { + const trackData = currentCluster.trackData.get(this.internalTrack.id); + if (trackData && trackData.startTimestamp > latestTimestamp) { + break; + } + } + let slice = demuxer.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementStartPos = currentPos; + const elementHeader = readElementHeader(slice); + if (!elementHeader || !LEVEL_1_EBML_IDS.includes(elementHeader.id) && elementHeader.id !== EBMLId.Void) { + const nextPos = await resync(demuxer.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(segment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); + if (nextPos) { + currentPos = nextPos; + continue; + } else { + break; + } + } + const id = elementHeader.id; + let size = elementHeader.size; + const dataStartPos = slice.filePos; + if (id === EBMLId.Cluster) { + currentCluster = await demuxer.readCluster(elementStartPos, segment); + size = currentCluster.elementEndPos - dataStartPos; + const { blockIndex, correctBlockFound } = getMatchInCluster(currentCluster); + if (correctBlockFound) { + return this.fetchPacketInCluster(currentCluster, blockIndex, options); + } + if (blockIndex !== -1) { + bestCluster = currentCluster; + bestBlockIndex = blockIndex; + } + } + if (size === void 0) { + assert(id !== EBMLId.Cluster); + const nextElementPos = await searchForNextElementId(demuxer.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); + size = nextElementPos.pos - dataStartPos; + } + const endPos = dataStartPos + size; + if (segment.elementEndPos === null) { + let slice2 = demuxer.reader.requestSliceRange(endPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const elementId = readElementId(slice2); + if (elementId === EBMLId.Segment) { + segment.elementEndPos = endPos; + break; + } + } + currentPos = endPos; + } + if (cuePoint && (!bestCluster || bestCluster.elementStartPos < cuePoint.clusterPosition)) { + const previousCuePoint = this.internalTrack.cuePoints[cuePointIndex - 1]; + assert(!previousCuePoint || previousCuePoint.time < cuePoint.time); + const newSearchTimestamp = previousCuePoint?.time ?? -Infinity; + return this.performClusterLookup(null, getMatchInCluster, newSearchTimestamp, latestTimestamp, options); + } + if (bestCluster) { + return this.fetchPacketInCluster(bestCluster, bestBlockIndex, options); + } + return null; + } + } + class MatroskaVideoTrackBacking extends MatroskaTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfigPromise = null; + this.internalTrack = internalTrack; + } + getType() { + return "video"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getCodedWidth() { + return this.internalTrack.info.width; + } + getCodedHeight() { + return this.internalTrack.info.height; + } + getSquarePixelWidth() { + return this.internalTrack.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.internalTrack.info.squarePixelHeight; + } + getRotation() { + return this.internalTrack.info.rotation; + } + async getColorSpace() { + return { + primaries: this.internalTrack.info.colorSpace?.primaries, + transfer: this.internalTrack.info.colorSpace?.transfer, + matrix: this.internalTrack.info.colorSpace?.matrix, + fullRange: this.internalTrack.info.colorSpace?.fullRange + }; + } + async canBeTransparent() { + return this.internalTrack.info.alphaMode; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { + let firstPacket = null; + const needsPacketForAdditionalInfo = this.internalTrack.info.codec === "vp9" || this.internalTrack.info.codec === "av1" || this.internalTrack.info.codec === "avc" && !this.internalTrack.info.codecDescription || this.internalTrack.info.codec === "hevc" && !this.internalTrack.info.codecDescription; + if (needsPacketForAdditionalInfo) { + firstPacket = await this.getFirstPacket({}); + } + const config = { + codec: extractVideoCodecString({ + width: this.internalTrack.info.width, + height: this.internalTrack.info.height, + codec: this.internalTrack.info.codec, + codecDescription: this.internalTrack.info.codecDescription, + colorSpace: this.internalTrack.info.colorSpace, + avcType: 1, + // We don't know better (or do we?) so just assume 'avc1' + avcCodecInfo: this.internalTrack.info.codec === "avc" && firstPacket ? extractAvcDecoderConfigurationRecord(firstPacket.data) : null, + hevcCodecInfo: this.internalTrack.info.codec === "hevc" && firstPacket ? extractHevcDecoderConfigurationRecord(firstPacket.data) : null, + vp9CodecInfo: this.internalTrack.info.codec === "vp9" && firstPacket ? extractVp9CodecInfoFromPacket(firstPacket.data) : null, + av1CodecInfo: this.internalTrack.info.codec === "av1" && firstPacket ? extractAv1CodecInfoFromPacket(firstPacket.data) : null + }), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? void 0, + colorSpace: this.internalTrack.info.colorSpace ?? void 0 + }; + if (this.internalTrack.info.width !== this.internalTrack.info.squarePixelWidth || this.internalTrack.info.height !== this.internalTrack.info.squarePixelHeight) { + config.displayAspectWidth = this.internalTrack.info.squarePixelWidth; + config.displayAspectHeight = this.internalTrack.info.squarePixelHeight; + } + return config; + })()); + } + } + class MatroskaAudioTrackBacking extends MatroskaTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfig = null; + this.internalTrack = internalTrack; + } + getType() { + return "audio"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getNumberOfChannels() { + return this.internalTrack.info.numberOfChannels; + } + getSampleRate() { + return this.internalTrack.info.sampleRate; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfig ?? (this.decoderConfig = { + codec: extractAudioCodecString({ + codec: this.internalTrack.info.codec, + codecDescription: this.internalTrack.info.codecDescription, + aacCodecInfo: this.internalTrack.info.aacCodecInfo + }), + numberOfChannels: this.internalTrack.info.numberOfChannels, + sampleRate: this.internalTrack.info.sampleRate, + description: this.internalTrack.info.codecDescription ?? void 0 + }); + } + } + const readNextMp3FrameHeader = async (reader, startPos, until) => { + const CHUNK_SIZE = 2 ** 16; + let currentPos = startPos; + while (until === null || currentPos < until) { + const maxLength = until !== null ? Math.min(CHUNK_SIZE, until - currentPos) : CHUNK_SIZE; + let slice = reader.requestSliceRange(currentPos, FRAME_HEADER_SIZE, maxLength); + if (slice instanceof Promise) + slice = await slice; + if (!slice || slice.length < FRAME_HEADER_SIZE) + break; + while (slice.remainingLength >= FRAME_HEADER_SIZE) { + const posBeforeRead = slice.filePos; + const word = readU32Be(slice); + const remainingBytes = reader.fileSize !== null ? reader.fileSize - currentPos : null; + const result = readMp3FrameHeader(word, remainingBytes); + if (result.header) { + return { header: result.header, startPos: currentPos }; + } + slice.filePos = posBeforeRead + result.bytesAdvanced; + currentPos = slice.filePos; + } + } + return null; + }; + class Mp3Demuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.firstFrameHeader = null; + this.firstFrameHeaderPos = null; + this.loadedSamples = []; + this.metadataTags = null; + this.xingData = null; + this.trackBackings = []; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.lastLoadedPos = 0; + this.nextTimestampInSamples = 0; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + while (!this.firstFrameHeader && !this.lastSampleLoaded) { + await this.advanceReader(); + } + if (!this.firstFrameHeader) { + throw new Error("No valid MP3 frame found."); + } + this.trackBackings = [new Mp3AudioTrackBacking(this)]; + })()); + } + async advanceReader() { + if (this.lastLoadedPos === 0) { + while (true) { + let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) { + this.lastSampleLoaded = true; + return; + } + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + this.lastLoadedPos = slice2.filePos + id3V2Header.size; + } + } + const result = await readNextMp3FrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize); + if (!result) { + this.lastSampleLoaded = true; + return; + } + const header = result.header; + this.lastLoadedPos = result.startPos + header.totalSize - 1; + const xingOffset = getXingOffset(header.mpegVersionId, header.channel); + let slice = this.reader.requestSlice(result.startPos + xingOffset, 4); + if (slice instanceof Promise) + slice = await slice; + if (slice) { + const word = readU32Be(slice); + const isXing = word === XING || word === INFO; + if (isXing) { + if (!this.xingData) { + let xingDataSlice = this.reader.requestSlice(result.startPos + xingOffset + 4, 12); + if (xingDataSlice instanceof Promise) + xingDataSlice = await xingDataSlice; + if (xingDataSlice) { + const xingData = readBytes(xingDataSlice, 12); + const view = toDataView(xingData); + const flags = view.getUint32(0, false); + this.xingData = { + frameCount: flags & XingFlags.FrameCount ? view.getUint32(4, false) : null, + fileSize: flags & XingFlags.FileSize ? view.getUint32(8, false) : null + }; + } + } + return; + } + } + if (!this.firstFrameHeader) { + this.firstFrameHeader = header; + this.firstFrameHeaderPos = result.startPos; + } + if (header.sampleRate !== this.firstFrameHeader.sampleRate) { + console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${header.sampleRate} Hz. Might be a bug, so please report this file.`); + } + const sampleDuration = header.audioSamplesInFrame / this.firstFrameHeader.sampleRate; + const sample = { + timestamp: this.nextTimestampInSamples / this.firstFrameHeader.sampleRate, + duration: sampleDuration, + dataStart: result.startPos, + dataSize: header.totalSize + }; + this.loadedSamples.push(sample); + this.nextTimestampInSamples += header.audioSamplesInFrame; + return; + } + async getMimeType() { + return "audio/mpeg"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + const release = await this.readingMutex.acquire(); + try { + await this.readMetadata(); + if (this.metadataTags) { + return this.metadataTags; + } + this.metadataTags = {}; + let currentPos = 0; + let id3V2HeaderFound = false; + while (true) { + let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + break; + const id3V2Header = readId3V2Header(headerSlice); + if (!id3V2Header) { + break; + } + id3V2HeaderFound = true; + let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); + if (contentSlice instanceof Promise) + contentSlice = await contentSlice; + if (!contentSlice) + break; + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + currentPos = headerSlice.filePos + id3V2Header.size; + } + if (!id3V2HeaderFound && this.reader.fileSize !== null && this.reader.fileSize >= ID3_V1_TAG_SIZE) { + let slice = this.reader.requestSlice(this.reader.fileSize - ID3_V1_TAG_SIZE, ID3_V1_TAG_SIZE); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const tag = readAscii(slice, 3); + if (tag === "TAG") { + parseId3V1Tag(slice, this.metadataTags); + } + } + return this.metadataTags; + } finally { + release(); + } + } + } + class Mp3AudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getTimeResolution() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.sampleRate / this.demuxer.firstFrameHeader.audioSamplesInFrame; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const demuxer = this.demuxer; + assert(demuxer.firstFrameHeader !== null); + assert(demuxer.firstFrameHeaderPos !== null); + if (demuxer.xingData) { + if (demuxer.xingData.frameCount !== null) { + return demuxer.xingData.frameCount * demuxer.firstFrameHeader.audioSamplesInFrame / demuxer.firstFrameHeader.sampleRate; + } + } else { + if (demuxer.reader.fileSize !== null) { + const averageFrameSize = computeAverageMp3FrameSize(demuxer.firstFrameHeader.lowSamplingFrequency, demuxer.firstFrameHeader.layer, demuxer.firstFrameHeader.bitrate, demuxer.firstFrameHeader.sampleRate); + const frameCount = (demuxer.reader.fileSize - demuxer.firstFrameHeaderPos) / averageFrameSize; + return Math.round(frameCount) * demuxer.firstFrameHeader.audioSamplesInFrame / demuxer.firstFrameHeader.sampleRate; + } + } + return null; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getCodec() { + return "mp3"; + } + getInternalCodecId() { + return null; + } + getNumberOfChannels() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2; + } + getSampleRate() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.sampleRate; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.firstFrameHeader); + return { + codec: "mp3", + numberOfChannels: this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2, + sampleRate: this.demuxer.firstFrameHeader.sampleRate + }; + } + async getPacketAtIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.dataSize); + } + return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); + if (sampleIndex === -1) { + throw new Error("Packet was not created from this track."); + } + const nextIndex = sampleIndex + 1; + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + async getPacket(timestamp, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); + if (index === -1 && this.demuxer.loadedSamples.length > 0) { + return null; + } + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(index, options); + } + if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { + return this.getPacketAtIndex(index, options); + } + await this.demuxer.advanceReader(); + } + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } + } + const OGGS = 1399285583; + const OGG_CRC_POLYNOMIAL = 79764919; + const OGG_CRC_TABLE = new Uint32Array(256); + for (let n = 0; n < 256; n++) { + let crc = n << 24; + for (let k = 0; k < 8; k++) { + crc = crc & 2147483648 ? crc << 1 ^ OGG_CRC_POLYNOMIAL : crc << 1; + } + OGG_CRC_TABLE[n] = crc >>> 0 & 4294967295; + } + const computeOggPageCrc = (bytes) => { + const view = toDataView(bytes); + const originalChecksum = view.getUint32(22, true); + view.setUint32(22, 0, true); + let crc = 0; + for (let i = 0; i < bytes.length; i++) { + const byte = bytes[i]; + crc = (crc << 8 ^ OGG_CRC_TABLE[crc >>> 24 ^ byte]) >>> 0; + } + view.setUint32(22, originalChecksum, true); + return crc; + }; + const extractSampleMetadata = (data, codecInfo, vorbisLastBlocksize) => { + let durationInSamples = 0; + let currentBlocksize = null; + if (data.length > 0) { + if (codecInfo.codec === "vorbis") { + assert(codecInfo.vorbisInfo); + const vorbisModeCount = codecInfo.vorbisInfo.modeBlockflags.length; + const bitCount = ilog(vorbisModeCount - 1); + const modeMask = (1 << bitCount) - 1 << 1; + const modeNumber = (data[0] & modeMask) >> 1; + if (modeNumber >= codecInfo.vorbisInfo.modeBlockflags.length) { + throw new Error("Invalid mode number."); + } + let prevBlocksize = vorbisLastBlocksize; + const blockflag = codecInfo.vorbisInfo.modeBlockflags[modeNumber]; + currentBlocksize = codecInfo.vorbisInfo.blocksizes[blockflag]; + if (blockflag === 1) { + const prevMask = (modeMask | 1) + 1; + const flag = data[0] & prevMask ? 1 : 0; + prevBlocksize = codecInfo.vorbisInfo.blocksizes[flag]; + } + durationInSamples = prevBlocksize !== null ? prevBlocksize + currentBlocksize >> 2 : 0; + } else if (codecInfo.codec === "opus") { + const toc = parseOpusTocByte(data); + durationInSamples = toc.durationInSamples; + } + } + return { + durationInSamples, + vorbisBlockSize: currentBlocksize + }; + }; + const buildOggMimeType = (info) => { + let string = "audio/ogg"; + if (info.codecStrings) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; + } + return string; + }; + const MIN_PAGE_HEADER_SIZE = 27; + const MAX_PAGE_HEADER_SIZE = 27 + 255; + const MAX_PAGE_SIZE = MAX_PAGE_HEADER_SIZE + 255 * 255; + const readPageHeader = (slice) => { + const startPos = slice.filePos; + const capturePattern = readU32Le(slice); + if (capturePattern !== OGGS) { + return null; + } + slice.skip(1); + const headerType = readU8(slice); + const granulePosition = readI64Le(slice); + const serialNumber = readU32Le(slice); + const sequenceNumber = readU32Le(slice); + const checksum = readU32Le(slice); + const numberPageSegments = readU8(slice); + const lacingValues = new Uint8Array(numberPageSegments); + for (let i = 0; i < numberPageSegments; i++) { + lacingValues[i] = readU8(slice); + } + const headerSize = 27 + numberPageSegments; + const dataSize = lacingValues.reduce((a, b) => a + b, 0); + const totalSize = headerSize + dataSize; + return { + headerStartPos: startPos, + totalSize, + dataStartPos: startPos + headerSize, + dataSize, + headerType, + granulePosition, + serialNumber, + sequenceNumber, + checksum, + lacingValues + }; + }; + const findNextPageHeader = (slice, until) => { + while (slice.filePos < until - (4 - 1)) { + const word = readU32Le(slice); + const firstByte = word & 255; + const secondByte = word >>> 8 & 255; + const thirdByte = word >>> 16 & 255; + const fourthByte = word >>> 24 & 255; + const O = 79; + if (firstByte !== O && secondByte !== O && thirdByte !== O && fourthByte !== O) { + continue; + } + slice.skip(-4); + if (word === OGGS) { + return true; + } + slice.skip(1); + } + return false; + }; + class OggDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.bitstreams = []; + this.trackBackings = []; + this.metadataTags = {}; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let currentPos = 0; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const page = readPageHeader(slice); + if (!page) { + break; + } + const isBos = !!(page.headerType & 2); + if (!isBos) { + break; + } + this.bitstreams.push({ + serialNumber: page.serialNumber, + bosPage: page, + description: null, + numberOfChannels: -1, + sampleRate: -1, + codecInfo: { + codec: null, + vorbisInfo: null, + opusInfo: null + }, + lastMetadataPacket: null + }); + currentPos = page.headerStartPos + page.totalSize; + } + for (const bitstream of this.bitstreams) { + const firstPacket = await this.readPacket(bitstream.bosPage, 0); + if (!firstPacket) { + continue; + } + if ( + // Check for Vorbis + firstPacket.data.byteLength >= 7 && firstPacket.data[0] === 1 && firstPacket.data[1] === 118 && firstPacket.data[2] === 111 && firstPacket.data[3] === 114 && firstPacket.data[4] === 98 && firstPacket.data[5] === 105 && firstPacket.data[6] === 115 + ) { + await this.readVorbisMetadata(firstPacket, bitstream); + } else if ( + // Check for Opus + firstPacket.data.byteLength >= 8 && firstPacket.data[0] === 79 && firstPacket.data[1] === 112 && firstPacket.data[2] === 117 && firstPacket.data[3] === 115 && firstPacket.data[4] === 72 && firstPacket.data[5] === 101 && firstPacket.data[6] === 97 && firstPacket.data[7] === 100 + ) { + await this.readOpusMetadata(firstPacket, bitstream); + } + if (bitstream.codecInfo.codec !== null) { + this.trackBackings.push(new OggAudioTrackBacking(bitstream, this)); + } + } + })()); + } + async readVorbisMetadata(firstPacket, bitstream) { + let nextPacketPosition = await this.findNextPacketStart(firstPacket); + if (!nextPacketPosition) { + return; + } + const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!secondPacket) { + return; + } + nextPacketPosition = await this.findNextPacketStart(secondPacket); + if (!nextPacketPosition) { + return; + } + const thirdPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!thirdPacket) { + return; + } + if (secondPacket.data[0] !== 3 || thirdPacket.data[0] !== 5) { + return; + } + const lacingValues = []; + const addBytesToSegmentTable = (bytes) => { + while (true) { + lacingValues.push(Math.min(255, bytes)); + if (bytes < 255) { + break; + } + bytes -= 255; + } + }; + addBytesToSegmentTable(firstPacket.data.length); + addBytesToSegmentTable(secondPacket.data.length); + const description = new Uint8Array(1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length + thirdPacket.data.length); + description[0] = 2; + description.set(lacingValues, 1); + description.set(firstPacket.data, 1 + lacingValues.length); + description.set(secondPacket.data, 1 + lacingValues.length + firstPacket.data.length); + description.set(thirdPacket.data, 1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length); + bitstream.codecInfo.codec = "vorbis"; + bitstream.description = description; + bitstream.lastMetadataPacket = thirdPacket; + const view = toDataView(firstPacket.data); + bitstream.numberOfChannels = view.getUint8(11); + bitstream.sampleRate = view.getUint32(12, true); + const blockSizeByte = view.getUint8(28); + bitstream.codecInfo.vorbisInfo = { + blocksizes: [ + 1 << (blockSizeByte & 15), + 1 << (blockSizeByte >> 4) + ], + modeBlockflags: parseModesFromVorbisSetupPacket(thirdPacket.data).modeBlockflags + }; + readVorbisComments(secondPacket.data.subarray(7), this.metadataTags); + } + async readOpusMetadata(firstPacket, bitstream) { + const nextPacketPosition = await this.findNextPacketStart(firstPacket); + if (!nextPacketPosition) { + return; + } + const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!secondPacket) { + return; + } + bitstream.codecInfo.codec = "opus"; + bitstream.description = firstPacket.data; + bitstream.lastMetadataPacket = secondPacket; + const header = parseOpusIdentificationHeader(firstPacket.data); + bitstream.numberOfChannels = header.outputChannelCount; + bitstream.sampleRate = OPUS_SAMPLE_RATE; + bitstream.codecInfo.opusInfo = { + preSkip: header.preSkip + }; + readVorbisComments(secondPacket.data.subarray(8), this.metadataTags); + } + async readPacket(startPage, startSegmentIndex) { + assert(startSegmentIndex < startPage.lacingValues.length); + let startDataOffset = 0; + for (let i = 0; i < startSegmentIndex; i++) { + startDataOffset += startPage.lacingValues[i]; + } + let currentPage = startPage; + let currentDataOffset = startDataOffset; + let currentSegmentIndex = startSegmentIndex; + const chunks = []; + outer: while (true) { + let pageSlice = this.reader.requestSlice(currentPage.dataStartPos, currentPage.dataSize); + if (pageSlice instanceof Promise) + pageSlice = await pageSlice; + assert(pageSlice); + const pageData = readBytes(pageSlice, currentPage.dataSize); + while (true) { + if (currentSegmentIndex === currentPage.lacingValues.length) { + chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); + break; + } + const lacingValue = currentPage.lacingValues[currentSegmentIndex]; + currentDataOffset += lacingValue; + if (lacingValue < 255) { + chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); + break outer; + } + currentSegmentIndex++; + } + let currentPos = currentPage.headerStartPos + currentPage.totalSize; + while (true) { + let headerSlice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) { + return null; + } + const nextPage = readPageHeader(headerSlice); + if (!nextPage) { + return null; + } + currentPage = nextPage; + if (currentPage.serialNumber === startPage.serialNumber) { + break; + } + currentPos = currentPage.headerStartPos + currentPage.totalSize; + } + startDataOffset = 0; + currentDataOffset = 0; + currentSegmentIndex = 0; + } + const totalPacketSize = chunks.reduce((sum, chunk) => sum + chunk.length, 0); + if (totalPacketSize === 0) { + return null; + } + const packetData = new Uint8Array(totalPacketSize); + let offset = 0; + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + packetData.set(chunk, offset); + offset += chunk.length; + } + return { + data: packetData, + endPage: currentPage, + endSegmentIndex: currentSegmentIndex + }; + } + async findNextPacketStart(lastPacket) { + if (lastPacket.endSegmentIndex < lastPacket.endPage.lacingValues.length - 1) { + return { startPage: lastPacket.endPage, startSegmentIndex: lastPacket.endSegmentIndex + 1 }; + } + const isEos = !!(lastPacket.endPage.headerType & 4); + if (isEos) { + return null; + } + let currentPos = lastPacket.endPage.headerStartPos + lastPacket.endPage.totalSize; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const nextPage = readPageHeader(slice); + if (!nextPage) { + return null; + } + if (nextPage.serialNumber === lastPacket.endPage.serialNumber) { + return { startPage: nextPage, startSegmentIndex: 0 }; + } + currentPos = nextPage.headerStartPos + nextPage.totalSize; + } + } + async getMimeType() { + await this.readMetadata(); + const codecStrings = await Promise.all(this.trackBackings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildOggMimeType({ + codecStrings: codecStrings.filter(Boolean) + }); + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } + } + class OggAudioTrackBacking { + constructor(bitstream, demuxer) { + this.bitstream = bitstream; + this.demuxer = demuxer; + this.encodedPacketToMetadata = /* @__PURE__ */ new WeakMap(); + this.sequentialScanCache = []; + this.sequentialScanMutex = new AsyncMutex(); + this.internalSampleRate = bitstream.codecInfo.codec === "opus" ? OPUS_SAMPLE_RATE : bitstream.sampleRate; + } + getType() { + return "audio"; + } + getId() { + return this.bitstream.serialNumber; + } + getNumber() { + const index = this.demuxer.trackBackings.findIndex((x) => x.bitstream === this.bitstream); + assert(index !== -1); + return index + 1; + } + getNumberOfChannels() { + return this.bitstream.numberOfChannels; + } + getSampleRate() { + return this.bitstream.sampleRate; + } + getTimeResolution() { + return this.bitstream.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + getCodec() { + return this.bitstream.codecInfo.codec; + } + getInternalCodecId() { + return null; + } + async getDecoderConfig() { + assert(this.bitstream.codecInfo.codec); + return { + codec: this.bitstream.codecInfo.codec, + numberOfChannels: this.bitstream.numberOfChannels, + sampleRate: this.bitstream.sampleRate, + description: this.bitstream.description ?? void 0 + }; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }; + } + granulePositionToTimestampInSamples(granulePosition) { + if (this.bitstream.codecInfo.codec === "opus") { + assert(this.bitstream.codecInfo.opusInfo); + return granulePosition - this.bitstream.codecInfo.opusInfo.preSkip; + } + return granulePosition; + } + createEncodedPacketFromOggPacket(packet, additional, options) { + if (!packet) { + return null; + } + const { durationInSamples, vorbisBlockSize } = extractSampleMetadata(packet.data, this.bitstream.codecInfo, additional.vorbisLastBlocksize); + const encodedPacket = new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : packet.data, "key", Math.max(0, additional.timestampInSamples) / this.internalSampleRate, durationInSamples / this.internalSampleRate, packet.endPage.headerStartPos + packet.endSegmentIndex, packet.data.byteLength); + this.encodedPacketToMetadata.set(encodedPacket, { + packet, + timestampInSamples: additional.timestampInSamples, + durationInSamples, + vorbisLastBlockSize: additional.vorbisLastBlocksize, + vorbisBlockSize + }); + return encodedPacket; + } + async getFirstPacket(options) { + assert(this.bitstream.lastMetadataPacket); + const packetPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); + if (!packetPosition) { + return null; + } + let timestampInSamples = 0; + if (this.bitstream.codecInfo.codec === "opus") { + assert(this.bitstream.codecInfo.opusInfo); + timestampInSamples -= this.bitstream.codecInfo.opusInfo.preSkip; + } + const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); + return this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples, + vorbisLastBlocksize: null + }, options); + } + async getNextPacket(prevPacket, options) { + const prevMetadata = this.encodedPacketToMetadata.get(prevPacket); + if (!prevMetadata) { + throw new Error("Packet was not created from this track."); + } + const packetPosition = await this.demuxer.findNextPacketStart(prevMetadata.packet); + if (!packetPosition) { + return null; + } + const timestampInSamples = prevMetadata.timestampInSamples + prevMetadata.durationInSamples; + const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); + return this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples, + vorbisLastBlocksize: prevMetadata.vorbisBlockSize + }, options); + } + async getPacket(timestamp, options) { + if (this.demuxer.reader.fileSize === null) { + return this.getPacketSequential(timestamp, options); + } + const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); + if (timestampInSamples === 0) { + return this.getFirstPacket(options); + } + if (timestampInSamples < 0) { + return null; + } + assert(this.bitstream.lastMetadataPacket); + const startPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); + if (!startPosition) { + return null; + } + let lowPage = startPosition.startPage; + let high = this.demuxer.reader.fileSize; + const lowPages = [lowPage]; + outer: while (lowPage.headerStartPos + lowPage.totalSize < high) { + const low = lowPage.headerStartPos; + const mid = Math.floor((low + high) / 2); + let searchStartPos = mid; + while (true) { + const until = Math.min(searchStartPos + MAX_PAGE_SIZE, high - MIN_PAGE_HEADER_SIZE); + let searchSlice = this.demuxer.reader.requestSlice(searchStartPos, until - searchStartPos); + if (searchSlice instanceof Promise) + searchSlice = await searchSlice; + assert(searchSlice); + const found = findNextPageHeader(searchSlice, until); + if (!found) { + high = mid + MIN_PAGE_HEADER_SIZE; + continue outer; + } + let headerSlice = this.demuxer.reader.requestSliceRange(searchSlice.filePos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const page = readPageHeader(headerSlice); + assert(page); + let pageValid = false; + if (page.serialNumber === this.bitstream.serialNumber) { + pageValid = true; + } else { + let pageSlice = this.demuxer.reader.requestSlice(page.headerStartPos, page.totalSize); + if (pageSlice instanceof Promise) + pageSlice = await pageSlice; + assert(pageSlice); + const bytes = readBytes(pageSlice, page.totalSize); + const crc = computeOggPageCrc(bytes); + pageValid = crc === page.checksum; + } + if (!pageValid) { + searchStartPos = page.headerStartPos + 4; + continue; + } + if (pageValid && page.serialNumber !== this.bitstream.serialNumber) { + searchStartPos = page.headerStartPos + page.totalSize; + continue; + } + const isContinuationPage = page.granulePosition === -1; + if (isContinuationPage) { + searchStartPos = page.headerStartPos + page.totalSize; + continue; + } + if (this.granulePositionToTimestampInSamples(page.granulePosition) > timestampInSamples) { + high = page.headerStartPos; + } else { + lowPage = page; + lowPages.push(page); + } + continue outer; + } + } + let lowerPage = startPosition.startPage; + for (const otherLowPage of lowPages) { + if (otherLowPage.granulePosition === lowPage.granulePosition) { + break; + } + if (!lowerPage || otherLowPage.headerStartPos > lowerPage.headerStartPos) { + lowerPage = otherLowPage; + } + } + let currentPage = lowerPage; + const previousPages = [currentPage]; + while (true) { + if (currentPage.serialNumber === this.bitstream.serialNumber && currentPage.granulePosition === lowPage.granulePosition) { + break; + } + const nextPos = currentPage.headerStartPos + currentPage.totalSize; + let slice = this.demuxer.reader.requestSliceRange(nextPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const nextPage = readPageHeader(slice); + assert(nextPage); + currentPage = nextPage; + if (currentPage.serialNumber === this.bitstream.serialNumber) { + previousPages.push(currentPage); + } + } + assert(currentPage.granulePosition !== -1); + let currentSegmentIndex = null; + let currentTimestampInSamples; + let currentTimestampIsCorrect; + let endPage = currentPage; + let endSegmentIndex = 0; + if (currentPage.headerStartPos === startPosition.startPage.headerStartPos) { + currentTimestampInSamples = this.granulePositionToTimestampInSamples(0); + currentTimestampIsCorrect = true; + currentSegmentIndex = 0; + } else { + currentTimestampInSamples = 0; + currentTimestampIsCorrect = false; + for (let i = currentPage.lacingValues.length - 1; i >= 0; i--) { + const value = currentPage.lacingValues[i]; + if (value < 255) { + currentSegmentIndex = i + 1; + break; + } + } + if (currentSegmentIndex === null) { + throw new Error("Invalid page with granule position: no packets end on this page."); + } + endSegmentIndex = currentSegmentIndex - 1; + const pseudopacket = { + data: PLACEHOLDER_DATA, + endPage, + endSegmentIndex + }; + const nextPosition = await this.demuxer.findNextPacketStart(pseudopacket); + if (nextPosition) { + const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); + assert(endPosition); + const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); + if (startPosition2) { + currentPage = startPosition2.page; + currentSegmentIndex = startPosition2.segmentIndex; + } + } else { + while (true) { + const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); + if (!endPosition) { + break; + } + const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); + if (!startPosition2) { + break; + } + currentPage = startPosition2.page; + currentSegmentIndex = startPosition2.segmentIndex; + if (endPosition.page.headerStartPos !== endPage.headerStartPos) { + endPage = endPosition.page; + endSegmentIndex = endPosition.segmentIndex; + break; + } + } + } + } + let lastEncodedPacket = null; + let lastEncodedPacketMetadata = null; + while (currentPage !== null) { + assert(currentSegmentIndex !== null); + const packet = await this.demuxer.readPacket(currentPage, currentSegmentIndex); + if (!packet) { + break; + } + const skipPacket = currentPage.headerStartPos === startPosition.startPage.headerStartPos && currentSegmentIndex < startPosition.startSegmentIndex; + if (!skipPacket) { + let encodedPacket = this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples: currentTimestampInSamples, + vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null + }, options); + assert(encodedPacket); + let encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); + assert(encodedPacketMetadata); + if (!currentTimestampIsCorrect && packet.endPage.headerStartPos === endPage.headerStartPos && packet.endSegmentIndex === endSegmentIndex) { + currentTimestampInSamples = this.granulePositionToTimestampInSamples(currentPage.granulePosition); + currentTimestampIsCorrect = true; + encodedPacket = this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples: currentTimestampInSamples - encodedPacketMetadata.durationInSamples, + vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null + }, options); + assert(encodedPacket); + encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); + assert(encodedPacketMetadata); + } else { + currentTimestampInSamples += encodedPacketMetadata.durationInSamples; + } + lastEncodedPacket = encodedPacket; + lastEncodedPacketMetadata = encodedPacketMetadata; + if (currentTimestampIsCorrect && // Next timestamp will be too late + (Math.max(currentTimestampInSamples, 0) > timestampInSamples || Math.max(encodedPacketMetadata.timestampInSamples, 0) === timestampInSamples)) { + break; + } + } + const nextPosition = await this.demuxer.findNextPacketStart(packet); + if (!nextPosition) { + break; + } + currentPage = nextPosition.startPage; + currentSegmentIndex = nextPosition.startSegmentIndex; + } + return lastEncodedPacket; + } + // A slower but simpler and sequential algorithm for finding a packet in a file + async getPacketSequential(timestamp, options) { + const release = await this.sequentialScanMutex.acquire(); + try { + const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); + timestamp = timestampInSamples / this.internalSampleRate; + const index = binarySearchLessOrEqual(this.sequentialScanCache, timestampInSamples, (x) => x.timestampInSamples); + let currentPacket; + if (index !== -1) { + const cacheEntry = this.sequentialScanCache[index]; + currentPacket = this.createEncodedPacketFromOggPacket(cacheEntry.packet, { + timestampInSamples: cacheEntry.timestampInSamples, + vorbisLastBlocksize: cacheEntry.vorbisLastBlockSize + }, options); + } else { + currentPacket = await this.getFirstPacket(options); + } + let i = 0; + while (currentPacket && currentPacket.timestamp < timestamp) { + const nextPacket = await this.getNextPacket(currentPacket, options); + if (!nextPacket || nextPacket.timestamp > timestamp) { + break; + } + currentPacket = nextPacket; + i++; + if (i === 100) { + i = 0; + const metadata = this.encodedPacketToMetadata.get(currentPacket); + assert(metadata); + if (this.sequentialScanCache.length > 0) { + assert(last(this.sequentialScanCache).timestampInSamples <= metadata.timestampInSamples); + } + this.sequentialScanCache.push(metadata); + } + } + return currentPacket; + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } + } + const findPacketStartPosition = (pageList, endPage, endSegmentIndex) => { + let page = endPage; + let segmentIndex = endSegmentIndex; + outer: while (true) { + segmentIndex--; + for (segmentIndex; segmentIndex >= 0; segmentIndex--) { + const lacingValue = page.lacingValues[segmentIndex]; + if (lacingValue < 255) { + segmentIndex++; + break outer; + } + } + assert(segmentIndex === -1); + const pageStartsWithFreshPacket = !(page.headerType & 1); + if (pageStartsWithFreshPacket) { + segmentIndex = 0; + break; + } + const previousPage = findLast(pageList, (x) => x.headerStartPos < page.headerStartPos); + if (!previousPage) { + return null; + } + page = previousPage; + segmentIndex = page.lacingValues.length; + } + assert(segmentIndex !== -1); + if (segmentIndex === page.lacingValues.length) { + const nextPage = pageList[pageList.indexOf(page) + 1]; + assert(nextPage); + page = nextPage; + segmentIndex = 0; + } + return { page, segmentIndex }; + }; + const findPreviousPacketEndPosition = (pageList, startPage, startSegmentIndex) => { + if (startSegmentIndex > 0) { + return { page: startPage, segmentIndex: startSegmentIndex - 1 }; + } + const previousPage = findLast(pageList, (x) => x.headerStartPos < startPage.headerStartPos); + if (!previousPage) { + return null; + } + return { page: previousPage, segmentIndex: previousPage.lacingValues.length - 1 }; + }; + var WaveFormat; + (function(WaveFormat2) { + WaveFormat2[WaveFormat2["PCM"] = 1] = "PCM"; + WaveFormat2[WaveFormat2["IEEE_FLOAT"] = 3] = "IEEE_FLOAT"; + WaveFormat2[WaveFormat2["ALAW"] = 6] = "ALAW"; + WaveFormat2[WaveFormat2["MULAW"] = 7] = "MULAW"; + WaveFormat2[WaveFormat2["EXTENSIBLE"] = 65534] = "EXTENSIBLE"; + })(WaveFormat || (WaveFormat = {})); + class WaveDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.dataStart = -1; + this.dataSize = -1; + this.audioInfo = null; + this.trackBackings = []; + this.lastKnownPacketIndex = 0; + this.metadataTags = {}; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let slice = this.reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const riffType = readAscii(slice, 4); + const littleEndian = riffType !== "RIFX"; + const isRf64 = riffType === "RF64"; + const outerChunkSize = readU32(slice, littleEndian); + let totalFileSize = isRf64 ? this.reader.fileSize : Math.min(outerChunkSize + 8, this.reader.fileSize ?? Infinity); + const format = readAscii(slice, 4); + if (format !== "WAVE") { + throw new Error("Invalid WAVE file - wrong format"); + } + let chunksRead = 0; + let dataChunkSize = null; + let currentPos = slice.filePos; + while (totalFileSize === null || currentPos < totalFileSize) { + let slice2 = this.reader.requestSlice(currentPos, 8); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const chunkId = readAscii(slice2, 4); + const chunkSize = readU32(slice2, littleEndian); + const startPos = slice2.filePos; + if (isRf64 && chunksRead === 0 && chunkId !== "ds64") { + throw new Error('Invalid RF64 file: First chunk must be "ds64".'); + } + if (chunkId === "fmt ") { + await this.parseFmtChunk(startPos, chunkSize, littleEndian); + } else if (chunkId === "data") { + dataChunkSize ?? (dataChunkSize = chunkSize); + this.dataStart = slice2.filePos; + this.dataSize = Math.min(dataChunkSize, (totalFileSize ?? Infinity) - this.dataStart); + if (this.reader.fileSize === null) { + break; + } + } else if (chunkId === "ds64") { + let ds64Slice = this.reader.requestSlice(startPos, chunkSize); + if (ds64Slice instanceof Promise) + ds64Slice = await ds64Slice; + if (!ds64Slice) + break; + const riffChunkSize = readU64(ds64Slice, littleEndian); + dataChunkSize = readU64(ds64Slice, littleEndian); + totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity); + } else if (chunkId === "LIST") { + await this.parseListChunk(startPos, chunkSize, littleEndian); + } else if (chunkId === "ID3 " || chunkId === "id3 ") { + await this.parseId3Chunk(startPos, chunkSize); + } + currentPos = startPos + chunkSize + (chunkSize & 1); + chunksRead++; + } + if (!this.audioInfo) { + throw new Error('Invalid WAVE file - missing "fmt " chunk'); + } + if (this.dataStart === -1) { + throw new Error('Invalid WAVE file - missing "data" chunk'); + } + const blockSize = this.audioInfo.blockSizeInBytes; + this.dataSize = Math.floor(this.dataSize / blockSize) * blockSize; + this.trackBackings.push(new WaveAudioTrackBacking(this)); + })()); + } + async parseFmtChunk(startPos, size, littleEndian) { + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + let formatTag = readU16(slice, littleEndian); + const numChannels = readU16(slice, littleEndian); + const sampleRate = readU32(slice, littleEndian); + slice.skip(4); + const blockAlign = readU16(slice, littleEndian); + let bitsPerSample; + if (size === 14) { + bitsPerSample = 8; + } else { + bitsPerSample = readU16(slice, littleEndian); + } + if (size >= 18 && formatTag !== 357) { + const cbSize = readU16(slice, littleEndian); + const remainingSize = size - 18; + const extensionSize = Math.min(remainingSize, cbSize); + if (extensionSize >= 22 && formatTag === WaveFormat.EXTENSIBLE) { + slice.skip(2 + 4); + const subFormat = readBytes(slice, 16); + formatTag = subFormat[0] | subFormat[1] << 8; + } + } + if (formatTag === WaveFormat.MULAW || formatTag === WaveFormat.ALAW) { + bitsPerSample = 8; + } + this.audioInfo = { + format: formatTag, + numberOfChannels: numChannels, + sampleRate, + sampleSizeInBytes: Math.ceil(bitsPerSample / 8), + blockSizeInBytes: blockAlign + }; + } + async parseListChunk(startPos, size, littleEndian) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + const infoType = readAscii(slice, 4); + if (infoType !== "INFO" && infoType !== "INF0") { + return; + } + let currentPos = slice.filePos; + while (currentPos <= startPos + size - 8) { + slice.filePos = currentPos; + const chunkName = readAscii(slice, 4); + const chunkSize = readU32(slice, littleEndian); + const bytes = readBytes(slice, chunkSize); + let stringLength = 0; + for (let i = 0; i < bytes.length; i++) { + if (bytes[i] === 0) { + break; + } + stringLength++; + } + const value = String.fromCharCode(...bytes.subarray(0, stringLength)); + (_a = this.metadataTags).raw ?? (_a.raw = {}); + this.metadataTags.raw[chunkName] = value; + switch (chunkName) { + case "INAM": + case "TITL": + { + (_b = this.metadataTags).title ?? (_b.title = value); + } + break; + case "TIT3": + { + (_c = this.metadataTags).description ?? (_c.description = value); + } + break; + case "IART": + { + (_d = this.metadataTags).artist ?? (_d.artist = value); + } + break; + case "IPRD": + { + (_e = this.metadataTags).album ?? (_e.album = value); + } + break; + case "IPRT": + case "ITRK": + case "TRCK": + { + const parts = value.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + (_f = this.metadataTags).trackNumber ?? (_f.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + (_g = this.metadataTags).tracksTotal ?? (_g.tracksTotal = tracksTotal); + } + } + break; + case "ICRD": + case "IDIT": + { + const date = new Date(value); + if (!Number.isNaN(date.getTime())) { + (_h = this.metadataTags).date ?? (_h.date = date); + } + } + break; + case "YEAR": + { + const year = Number.parseInt(value, 10); + if (Number.isInteger(year) && year > 0) { + (_i = this.metadataTags).date ?? (_i.date = new Date(year, 0, 1)); + } + } + break; + case "IGNR": + case "GENR": + { + (_j = this.metadataTags).genre ?? (_j.genre = value); + } + break; + case "ICMT": + case "CMNT": + case "COMM": + { + (_k = this.metadataTags).comment ?? (_k.comment = value); + } + break; + } + currentPos += 8 + chunkSize + (chunkSize & 1); + } + } + async parseId3Chunk(startPos, size) { + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + const id3V2Header = readId3V2Header(slice); + if (id3V2Header) { + const availableSize = size - ID3_V2_HEADER_SIZE; + id3V2Header.size = Math.min(id3V2Header.size, availableSize); + if (id3V2Header.size > 0) { + const contentSlice = slice.slice(startPos + ID3_V2_HEADER_SIZE, id3V2Header.size); + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + } + } + } + getCodec() { + assert(this.audioInfo); + if (this.audioInfo.format === WaveFormat.MULAW) { + return "ulaw"; + } + if (this.audioInfo.format === WaveFormat.ALAW) { + return "alaw"; + } + if (this.audioInfo.format === WaveFormat.PCM) { + if (this.audioInfo.sampleSizeInBytes === 1) { + return "pcm-u8"; + } else if (this.audioInfo.sampleSizeInBytes === 2) { + return "pcm-s16"; + } else if (this.audioInfo.sampleSizeInBytes === 3) { + return "pcm-s24"; + } else if (this.audioInfo.sampleSizeInBytes === 4) { + return "pcm-s32"; + } + } + if (this.audioInfo.format === WaveFormat.IEEE_FLOAT) { + if (this.audioInfo.sampleSizeInBytes === 4) { + return "pcm-f32"; + } + } + return null; + } + async getMimeType() { + return "audio/wav"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } + } + const PACKET_SIZE_IN_FRAMES = 2048; + class WaveAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getCodec() { + return this.demuxer.getCodec(); + } + getInternalCodecId() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.format; + } + async getDecoderConfig() { + const codec = this.demuxer.getCodec(); + if (!codec) { + return null; + } + assert(this.demuxer.audioInfo); + return { + codec, + numberOfChannels: this.demuxer.audioInfo.numberOfChannels, + sampleRate: this.demuxer.audioInfo.sampleRate + }; + } + getNumberOfChannels() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + getTimeResolution() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + assert(this.demuxer.dataSize !== -1); + return this.demuxer.dataSize / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getPacketAtIndex(packetIndex, options) { + assert(packetIndex >= 0); + assert(this.demuxer.audioInfo); + const startOffset = packetIndex * PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes; + if (startOffset >= this.demuxer.dataSize) { + return null; + } + const sizeInBytes = Math.min(PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes, this.demuxer.dataSize - startOffset); + if (this.demuxer.reader.fileSize === null) { + let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + data = readBytes(slice, sizeInBytes); + } + const timestamp = packetIndex * PACKET_SIZE_IN_FRAMES / this.demuxer.audioInfo.sampleRate; + const duration = sizeInBytes / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; + this.demuxer.lastKnownPacketIndex = Math.max(packetIndex, this.demuxer.lastKnownPacketIndex); + return new EncodedPacket(data, "key", timestamp, duration, packetIndex, sizeInBytes); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getPacket(timestamp, options) { + assert(this.demuxer.audioInfo); + const packetIndex = Math.floor(Math.min(timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES, (this.demuxer.dataSize - 1) / (PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes))); + if (packetIndex < 0) { + return null; + } + const packet = await this.getPacketAtIndex(packetIndex, options); + if (packet) { + return packet; + } + if (packetIndex === 0) { + return null; + } + assert(this.demuxer.reader.fileSize === null); + let currentPacket = await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex, options); + while (currentPacket) { + const nextPacket = await this.getNextPacket(currentPacket, options); + if (!nextPacket) { + break; + } + currentPacket = nextPacket; + } + return currentPacket; + } + getNextPacket(packet, options) { + assert(this.demuxer.audioInfo); + const packetIndex = Math.round(packet.timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES); + return this.getPacketAtIndex(packetIndex + 1, options); + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } + } + const MIN_ADTS_FRAME_HEADER_SIZE = 7; + const MAX_ADTS_FRAME_HEADER_SIZE = 9; + const readAdtsFrameHeader = (slice) => { + const startPos = slice.filePos; + const bytes = readBytes(slice, 9); + const bitstream = new Bitstream(bytes); + const syncword = bitstream.readBits(12); + if (syncword !== 4095) { + return null; + } + bitstream.skipBits(1); + const layer = bitstream.readBits(2); + if (layer !== 0) { + return null; + } + const protectionAbsence = bitstream.readBits(1); + const objectType = bitstream.readBits(2) + 1; + const samplingFrequencyIndex = bitstream.readBits(4); + if (samplingFrequencyIndex === 15) { + return null; + } + bitstream.skipBits(1); + const channelConfiguration = bitstream.readBits(3); + if (channelConfiguration === 0) { + throw new Error("ADTS frames with channel configuration 0 are not supported."); + } + bitstream.skipBits(1); + bitstream.skipBits(1); + bitstream.skipBits(1); + bitstream.skipBits(1); + const frameLength = bitstream.readBits(13); + bitstream.skipBits(11); + const numberOfAacFrames = bitstream.readBits(2) + 1; + if (numberOfAacFrames !== 1) { + throw new Error("ADTS frames with more than one AAC frame are not supported."); + } + let crcCheck = null; + if (protectionAbsence === 1) { + slice.filePos -= 2; + } else { + crcCheck = bitstream.readBits(16); + } + return { + objectType, + samplingFrequencyIndex, + channelConfiguration, + frameLength, + numberOfAacFrames, + crcCheck, + startPos + }; + }; + const SAMPLES_PER_AAC_FRAME = 1024; + class AdtsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.firstFrameHeader = null; + this.loadedSamples = []; + this.metadataTags = null; + this.trackBackings = []; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.lastLoadedPos = 0; + this.nextTimestampInSamples = 0; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + while (!this.firstFrameHeader && !this.lastSampleLoaded) { + await this.advanceReader(); + } + assert(this.firstFrameHeader); + this.trackBackings = [new AdtsAudioTrackBacking(this)]; + })()); + } + async advanceReader() { + if (this.lastLoadedPos === 0) { + while (true) { + let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) { + this.lastSampleLoaded = true; + return; + } + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + this.lastLoadedPos = slice2.filePos + id3V2Header.size; + } + } + let slice = this.reader.requestSliceRange(this.lastLoadedPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + this.lastSampleLoaded = true; + return; + } + const header = readAdtsFrameHeader(slice); + if (!header) { + this.lastSampleLoaded = true; + return; + } + if (this.reader.fileSize !== null && header.startPos + header.frameLength > this.reader.fileSize) { + this.lastSampleLoaded = true; + return; + } + if (!this.firstFrameHeader) { + this.firstFrameHeader = header; + } + const sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; + assert(sampleRate !== void 0); + const sampleDuration = SAMPLES_PER_AAC_FRAME / sampleRate; + const sample = { + timestamp: this.nextTimestampInSamples / sampleRate, + duration: sampleDuration, + dataStart: header.startPos, + dataSize: header.frameLength + }; + this.loadedSamples.push(sample); + this.nextTimestampInSamples += SAMPLES_PER_AAC_FRAME; + this.lastLoadedPos = header.startPos + header.frameLength; + } + async getMimeType() { + return "audio/aac"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + const release = await this.readingMutex.acquire(); + try { + await this.readMetadata(); + if (this.metadataTags) { + return this.metadataTags; + } + this.metadataTags = {}; + let currentPos = 0; + while (true) { + let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + break; + const id3V2Header = readId3V2Header(headerSlice); + if (!id3V2Header) { + break; + } + let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); + if (contentSlice instanceof Promise) + contentSlice = await contentSlice; + if (!contentSlice) + break; + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + currentPos = headerSlice.filePos + id3V2Header.size; + } + return this.metadataTags; + } finally { + release(); + } + } + } + class AdtsAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getTimeResolution() { + const sampleRate = this.getSampleRate(); + return sampleRate / SAMPLES_PER_AAC_FRAME; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getCodec() { + return "aac"; + } + getInternalCodecId() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.objectType; + } + getNumberOfChannels() { + assert(this.demuxer.firstFrameHeader); + const numberOfChannels = aacChannelMap[this.demuxer.firstFrameHeader.channelConfiguration]; + assert(numberOfChannels !== void 0); + return numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.firstFrameHeader); + const sampleRate = aacFrequencyTable[this.demuxer.firstFrameHeader.samplingFrequencyIndex]; + assert(sampleRate !== void 0); + return sampleRate; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.firstFrameHeader); + return { + codec: `mp4a.40.${this.demuxer.firstFrameHeader.objectType}`, + numberOfChannels: this.getNumberOfChannels(), + sampleRate: this.getSampleRate() + }; + } + async getPacketAtIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.dataSize); + } + return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); + if (sampleIndex === -1) { + throw new Error("Packet was not created from this track."); + } + const nextIndex = sampleIndex + 1; + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + async getPacket(timestamp, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); + if (index === -1 && this.demuxer.loadedSamples.length > 0) { + return null; + } + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(index, options); + } + if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { + return this.getPacketAtIndex(index, options); + } + await this.demuxer.advanceReader(); + } + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } + } + const getBlockSizeOrUncommon = (bits) => { + if (bits === 0) { + return null; + } else if (bits === 1) { + return 192; + } else if (bits >= 2 && bits <= 5) { + return 144 * 2 ** bits; + } else if (bits === 6) { + return "uncommon-u8"; + } else if (bits === 7) { + return "uncommon-u16"; + } else if (bits >= 8 && bits <= 15) { + return 2 ** bits; + } else { + return null; + } + }; + const getSampleRateOrUncommon = (sampleRateBits, streamInfoSampleRate) => { + switch (sampleRateBits) { + case 0: + return streamInfoSampleRate; + case 1: + return 88200; + case 2: + return 176400; + case 3: + return 192e3; + case 4: + return 8e3; + case 5: + return 16e3; + case 6: + return 22050; + case 7: + return 24e3; + case 8: + return 32e3; + case 9: + return 44100; + case 10: + return 48e3; + case 11: + return 96e3; + case 12: + return "uncommon-u8"; + case 13: + return "uncommon-u16"; + case 14: + return "uncommon-u16-10"; + default: + return null; + } + }; + const readCodedNumber = (fileSlice) => { + let ones = 0; + const bitstream1 = new Bitstream(readBytes(fileSlice, 1)); + while (bitstream1.readBits(1) === 1) { + ones++; + } + if (ones === 0) { + return bitstream1.readBits(7); + } + const bitArray = []; + const extraBytes = ones - 1; + const bitstream2 = new Bitstream(readBytes(fileSlice, extraBytes)); + const firstByteBits = 8 - ones - 1; + for (let i = 0; i < firstByteBits; i++) { + bitArray.unshift(bitstream1.readBits(1)); + } + for (let i = 0; i < extraBytes; i++) { + for (let j = 0; j < 8; j++) { + const val = bitstream2.readBits(1); + if (j < 2) { + continue; + } + bitArray.unshift(val); + } + } + const encoded = bitArray.reduce((acc, bit, index) => { + return acc | bit << index; + }, 0); + return encoded; + }; + const readBlockSize = (slice, blockSizeBits) => { + if (blockSizeBits === "uncommon-u16") { + return readU16Be(slice) + 1; + } else if (blockSizeBits === "uncommon-u8") { + return readU8(slice) + 1; + } else if (typeof blockSizeBits === "number") { + return blockSizeBits; + } else { + assertNever(blockSizeBits); + assert(false); + } + }; + const readSampleRate = (slice, sampleRateOrUncommon) => { + if (sampleRateOrUncommon === "uncommon-u16") { + return readU16Be(slice); + } + if (sampleRateOrUncommon === "uncommon-u16-10") { + return readU16Be(slice) * 10; + } + if (sampleRateOrUncommon === "uncommon-u8") { + return readU8(slice); + } + if (typeof sampleRateOrUncommon === "number") { + return sampleRateOrUncommon; + } + return null; + }; + const calculateCrc8 = (data) => { + const polynomial = 7; + let crc = 0; + for (const byte of data) { + crc ^= byte; + for (let i = 0; i < 8; i++) { + if ((crc & 128) !== 0) { + crc = crc << 1 ^ polynomial; + } else { + crc <<= 1; + } + crc &= 255; + } + } + return crc; + }; + class FlacDemuxer extends Demuxer { + constructor(input) { + super(input); + this.loadedSamples = []; + this.metadataPromise = null; + this.trackBacking = null; + this.metadataTags = {}; + this.audioInfo = null; + this.lastLoadedPos = null; + this.blockingBit = null; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.reader = input._reader; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } + async getTrackBackings() { + await this.readMetadata(); + assert(this.trackBacking); + return [this.trackBacking]; + } + async getMimeType() { + return "audio/flac"; + } + async readMetadata() { + let currentPos = 4; + return this.metadataPromise ?? (this.metadataPromise = (async () => { + var _a; + while (this.reader.fileSize === null || currentPos < this.reader.fileSize) { + let sizeSlice = this.reader.requestSlice(currentPos, 4); + if (sizeSlice instanceof Promise) + sizeSlice = await sizeSlice; + currentPos += 4; + if (sizeSlice === null) { + throw new Error(`Metadata block at position ${currentPos} is too small! Corrupted file.`); + } + assert(sizeSlice); + const byte = readU8(sizeSlice); + const size = readU24Be(sizeSlice); + const isLastMetadata = (byte & 128) !== 0; + const metaBlockType = byte & 127; + switch (metaBlockType) { + case FlacBlockType.STREAMINFO: { + let streamInfoBlock = this.reader.requestSlice(currentPos, size); + if (streamInfoBlock instanceof Promise) + streamInfoBlock = await streamInfoBlock; + assert(streamInfoBlock); + if (streamInfoBlock === null) { + throw new Error(`StreamInfo block at position ${currentPos} is too small! Corrupted file.`); + } + const streamInfoBytes = readBytes(streamInfoBlock, 34); + const bitstream = new Bitstream(streamInfoBytes); + const minimumBlockSize = bitstream.readBits(16); + const maximumBlockSize = bitstream.readBits(16); + const minimumFrameSize = bitstream.readBits(24); + const maximumFrameSize = bitstream.readBits(24); + const sampleRate = bitstream.readBits(20); + const numberOfChannels = bitstream.readBits(3) + 1; + bitstream.readBits(5); + const totalSamples = bitstream.readBits(36); + bitstream.skipBits(16 * 8); + const description = new Uint8Array(42); + description.set(new Uint8Array([102, 76, 97, 67]), 0); + description.set(new Uint8Array([128, 0, 0, 34]), 4); + description.set(streamInfoBytes, 8); + this.audioInfo = { + numberOfChannels, + sampleRate, + totalSamples, + minimumBlockSize, + maximumBlockSize, + minimumFrameSize, + maximumFrameSize, + description + }; + this.trackBacking = new FlacAudioTrackBacking(this); + break; + } + case FlacBlockType.VORBIS_COMMENT: { + let vorbisCommentBlock = this.reader.requestSlice(currentPos, size); + if (vorbisCommentBlock instanceof Promise) + vorbisCommentBlock = await vorbisCommentBlock; + assert(vorbisCommentBlock); + readVorbisComments(readBytes(vorbisCommentBlock, size), this.metadataTags); + break; + } + case FlacBlockType.PICTURE: { + let pictureBlock = this.reader.requestSlice(currentPos, size); + if (pictureBlock instanceof Promise) + pictureBlock = await pictureBlock; + assert(pictureBlock); + const pictureType = readU32Be(pictureBlock); + const mediaTypeLength = readU32Be(pictureBlock); + const mediaType = textDecoder.decode(readBytes(pictureBlock, mediaTypeLength)); + const descriptionLength = readU32Be(pictureBlock); + const description = textDecoder.decode(readBytes(pictureBlock, descriptionLength)); + pictureBlock.skip(4 + 4 + 4 + 4); + const dataLength = readU32Be(pictureBlock); + const data = readBytes(pictureBlock, dataLength); + (_a = this.metadataTags).images ?? (_a.images = []); + this.metadataTags.images.push({ + data, + mimeType: mediaType, + // https://www.rfc-editor.org/rfc/rfc9639.html#table13 + kind: pictureType === 3 ? "coverFront" : pictureType === 4 ? "coverBack" : "unknown", + description + }); + break; + } + } + currentPos += size; + if (isLastMetadata) { + this.lastLoadedPos = currentPos; + break; + } + } + if (!this.audioInfo) { + throw new Error("Missing STREAMINFO metadata block! Corrupted FLAC file."); + } + })()); + } + async readNextFlacFrame({ startPos, isFirstPacket }) { + assert(this.audioInfo); + const minimumHeaderLength = 6; + const maximumHeaderLength = 16; + const minimumFrameLength = 10; + const maximumFrameLength = this.audioInfo.maximumBlockSize * this.audioInfo.numberOfChannels * 4 + maximumHeaderLength + 2; + const effectiveMinFrameSize = this.audioInfo.minimumFrameSize || minimumFrameLength; + const effectiveMaxFrameSize = this.audioInfo.maximumFrameSize || maximumFrameLength; + const maximumSliceLength = effectiveMaxFrameSize + maximumHeaderLength; + const slice = await this.reader.requestSliceRange(startPos, maximumHeaderLength, maximumSliceLength); + if (!slice) { + return null; + } + const frameHeader = this.readFlacFrameHeader({ + slice, + isFirstPacket + }); + if (!frameHeader) { + return null; + } + slice.filePos = startPos + effectiveMinFrameSize; + while (true) { + if (slice.filePos > slice.end - minimumHeaderLength) { + return { + num: frameHeader.num, + blockSize: frameHeader.blockSize, + sampleRate: frameHeader.sampleRate, + size: slice.end - startPos, + isLastFrame: true + }; + } + const nextByte = readU8(slice); + if (nextByte === 255) { + const positionBeforeReading = slice.filePos; + const byteAfterNextByte = readU8(slice); + const expected = this.blockingBit === 1 ? 249 : 248; + if (byteAfterNextByte !== expected) { + slice.filePos = positionBeforeReading; + continue; + } + slice.skip(-2); + const lengthIfNextFlacFrameHeaderIsLegit = slice.filePos - startPos; + const nextFrameHeader = this.readFlacFrameHeader({ + slice, + isFirstPacket: false + }); + if (!nextFrameHeader) { + slice.filePos = positionBeforeReading; + continue; + } + if (this.blockingBit === 0) { + if (nextFrameHeader.num - frameHeader.num !== 1) { + slice.filePos = positionBeforeReading; + continue; + } + } else { + if (nextFrameHeader.num - frameHeader.num !== frameHeader.blockSize) { + slice.filePos = positionBeforeReading; + continue; + } + } + return { + num: frameHeader.num, + blockSize: frameHeader.blockSize, + sampleRate: frameHeader.sampleRate, + size: lengthIfNextFlacFrameHeaderIsLegit, + isLastFrame: false + }; + } + } + } + readFlacFrameHeader({ slice, isFirstPacket }) { + const startOffset = slice.filePos; + const bytes = readBytes(slice, 4); + const bitstream = new Bitstream(bytes); + const bits = bitstream.readBits(15); + if (bits !== 32764) { + return null; + } + if (this.blockingBit === null) { + assert(isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + this.blockingBit = newBlockingBit; + } else if (this.blockingBit === 1) { + assert(!isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + if (newBlockingBit !== 1) { + return null; + } + } else if (this.blockingBit === 0) { + assert(!isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + if (newBlockingBit !== 0) { + return null; + } + } else { + throw new Error("Invalid blocking bit"); + } + const blockSizeOrUncommon = getBlockSizeOrUncommon(bitstream.readBits(4)); + if (!blockSizeOrUncommon) { + return null; + } + assert(this.audioInfo); + const sampleRateOrUncommon = getSampleRateOrUncommon(bitstream.readBits(4), this.audioInfo.sampleRate); + if (!sampleRateOrUncommon) { + return null; + } + bitstream.readBits(4); + bitstream.readBits(3); + const reservedZero = bitstream.readBits(1); + if (reservedZero !== 0) { + return null; + } + const num = readCodedNumber(slice); + const blockSize = readBlockSize(slice, blockSizeOrUncommon); + const sampleRate = readSampleRate(slice, sampleRateOrUncommon); + if (sampleRate === null) { + return null; + } + if (sampleRate !== this.audioInfo.sampleRate) { + return null; + } + const size = slice.filePos - startOffset; + const crc = readU8(slice); + slice.skip(-size); + slice.skip(-1); + const crcCalculated = calculateCrc8(readBytes(slice, size)); + if (crc !== crcCalculated) { + return null; + } + return { num, blockSize, sampleRate }; + } + async advanceReader() { + await this.readMetadata(); + assert(this.lastLoadedPos !== null); + assert(this.audioInfo); + const startPos = this.lastLoadedPos; + const frame = await this.readNextFlacFrame({ + startPos, + isFirstPacket: this.loadedSamples.length === 0 + }); + if (!frame) { + this.lastSampleLoaded = true; + return; + } + const lastSample = this.loadedSamples[this.loadedSamples.length - 1]; + const blockOffset = lastSample ? lastSample.blockOffset + lastSample.blockSize : 0; + const sample = { + blockOffset, + blockSize: frame.blockSize, + byteOffset: startPos, + byteSize: frame.size + }; + this.lastLoadedPos = this.lastLoadedPos + frame.size; + this.loadedSamples.push(sample); + if (frame.isLastFrame) { + this.lastSampleLoaded = true; + return; + } + } + } + class FlacAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getCodec() { + return "flac"; + } + getInternalCodecId() { + return null; + } + getNumberOfChannels() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getTimeResolution() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + assert(this.demuxer.audioInfo); + if (this.demuxer.audioInfo.totalSamples === 0) { + return null; + } + return this.demuxer.audioInfo.totalSamples / this.demuxer.audioInfo.sampleRate; + } + async getLiveRefreshInterval() { + return null; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.audioInfo); + return { + codec: "flac", + numberOfChannels: this.demuxer.audioInfo.numberOfChannels, + sampleRate: this.demuxer.audioInfo.sampleRate, + description: this.demuxer.audioInfo.description + }; + } + async getPacket(timestamp, options) { + assert(this.demuxer.audioInfo); + if (timestamp < 0) { + throw new Error("Timestamp cannot be negative"); + } + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const packetIndex = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.blockOffset / this.demuxer.audioInfo.sampleRate); + if (packetIndex === -1) { + await this.demuxer.advanceReader(); + continue; + } + const packet = this.demuxer.loadedSamples[packetIndex]; + const sampleTimestamp = packet.blockOffset / this.demuxer.audioInfo.sampleRate; + const sampleDuration = packet.blockSize / this.demuxer.audioInfo.sampleRate; + if (sampleTimestamp + sampleDuration <= timestamp) { + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(this.demuxer.loadedSamples.length - 1, options); + } + await this.demuxer.advanceReader(); + continue; + } + return this.getPacketAtIndex(packetIndex, options); + } + } finally { + release(); + } + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const nextIndex = packet.sequenceNumber + 1; + if (this.demuxer.lastSampleLoaded && nextIndex >= this.demuxer.loadedSamples.length) { + return null; + } + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } + async getPacketAtIndex(sampleIndex, options) { + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.byteOffset, rawSample.byteSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.byteSize); + } + assert(this.demuxer.audioInfo); + const timestamp = rawSample.blockOffset / this.demuxer.audioInfo.sampleRate; + const duration = rawSample.blockSize / this.demuxer.audioInfo.sampleRate; + return new EncodedPacket(data, "key", timestamp, duration, sampleIndex, rawSample.byteSize); + } + async getFirstPacket(options) { + while (this.demuxer.loadedSamples.length === 0 && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(0, options); + } + } + const TIMESCALE = 9e4; + const TS_PACKET_SIZE = 188; + const buildMpegTsMimeType = (codecStrings) => { + let string = "video/MP2T"; + const uniqueCodecStrings = [...new Set(codecStrings.filter(Boolean))]; + if (uniqueCodecStrings.length > 0) { + string += `; codecs="${uniqueCodecStrings.join(", ")}"`; + } + return string; + }; + const MISSING_PTS_ERROR_MESSAGE = "PES packet is missing PTS where it was expected. PES packets without PTS are not currently supported. If you think this file should be supported, please report it."; + const ignoredStreamTypes = /* @__PURE__ */ new Set(); + class MpegTsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.elementaryStreams = []; + this.trackBackingEntries = []; + this.packetOffset = 0; + this.packetStride = -1; + this.sectionEndPositions = []; + this.seekChunkSize = 5 * 1024 * 1024; + this.minReferencePointByteDistance = -1; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + const lengthToCheck = TS_PACKET_SIZE + 16 + 1; + let startingSlice = this.reader.requestSlice(0, lengthToCheck); + if (startingSlice instanceof Promise) + startingSlice = await startingSlice; + assert(startingSlice); + const startingBytes = readBytes(startingSlice, lengthToCheck); + if (startingBytes[0] === 71 && startingBytes[TS_PACKET_SIZE] === 71) { + this.packetOffset = 0; + this.packetStride = TS_PACKET_SIZE; + } else if (startingBytes[0] === 71 && startingBytes[TS_PACKET_SIZE + 16] === 71) { + this.packetOffset = 0; + this.packetStride = TS_PACKET_SIZE + 16; + } else if (startingBytes[4] === 71 && startingBytes[4 + TS_PACKET_SIZE + 4] === 71) { + this.packetOffset = 4; + this.packetStride = TS_PACKET_SIZE + 4; + } else { + throw new Error("Unreachable."); + } + const MIN_REFERENCE_POINT_PACKET_DISTANCE = 256; + this.minReferencePointByteDistance = MIN_REFERENCE_POINT_PACKET_DISTANCE * this.packetStride; + let currentPos = this.packetOffset; + let programMapPid = null; + let hasProgramAssociationTable = false; + let hasProgramMap = false; + while (true) { + const packetHeader = await this.readPacketHeader(currentPos); + if (!packetHeader) { + break; + } + if (packetHeader.payloadUnitStartIndicator === 0) { + currentPos += this.packetStride; + continue; + } + const section = await this.readSection(currentPos, true, !hasProgramMap); + if (!section) { + break; + } + const BYTES_BEFORE_SECTION_LENGTH = 3; + const BITS_IN_CRC_32 = 32; + let isProbablyProgramMap = false; + if (!hasProgramMap && section.pid !== 0) { + const isPesPacket = section.payload[0] === 0 && section.payload[1] === 0 && section.payload[2] === 1; + if (!isPesPacket) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + const tableId = bitstream.readBits(8); + isProbablyProgramMap = tableId === 2; + } + } + if (section.pid === 0 && !hasProgramAssociationTable) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + bitstream.skipBits(14); + const sectionLength = bitstream.readBits(10); + bitstream.skipBits(40); + while (8 * (sectionLength + BYTES_BEFORE_SECTION_LENGTH) - bitstream.pos > BITS_IN_CRC_32) { + const programNumber = bitstream.readBits(16); + bitstream.skipBits(3); + const id = bitstream.readBits(13); + if (programNumber !== 0) { + if (programMapPid !== null) { + throw new Error("Only files with a single program are supported."); + } else { + programMapPid = id; + } + } + } + if (programMapPid === null) { + throw new Error("Program Association Table must link to a Program Map Table."); + } + hasProgramAssociationTable = true; + } else if ((section.pid === programMapPid || isProbablyProgramMap) && !hasProgramMap) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + bitstream.skipBits(12); + const sectionLength = bitstream.readBits(12); + bitstream.skipBits(43); + bitstream.readBits(13); + bitstream.skipBits(6); + const programInfoLength = bitstream.readBits(10); + bitstream.skipBits(8 * programInfoLength); + while (8 * (sectionLength + BYTES_BEFORE_SECTION_LENGTH) - bitstream.pos > BITS_IN_CRC_32) { + const streamType = bitstream.readBits(8); + bitstream.skipBits(3); + const elementaryPid = bitstream.readBits(13); + bitstream.skipBits(6); + const esInfoLength = bitstream.readBits(10); + const esInfoEndPos = bitstream.pos + 8 * esInfoLength; + let hasAc3Descriptor = false; + let hasEac3Descriptor = false; + while (bitstream.pos < esInfoEndPos) { + const descriptorTag = bitstream.readBits(8); + const descriptorLength = bitstream.readBits(8); + if (descriptorTag === 106) { + hasAc3Descriptor = true; + } else if (descriptorTag === 122 || descriptorTag === 204) { + hasEac3Descriptor = true; + } + bitstream.skipBits(8 * descriptorLength); + } + let info = null; + switch (streamType) { + case 27: + case 36: + { + const codec = streamType === 27 ? "avc" : "hevc"; + info = { + type: "video", + codec, + decoderConfig: null, + avcCodecInfo: null, + hevcCodecInfo: null, + colorSpace: { + primaries: null, + transfer: null, + matrix: null, + fullRange: null + }, + width: -1, + height: -1, + squarePixelWidth: -1, + squarePixelHeight: -1, + reorderSize: -1 + }; + } + break; + case 3: + case 4: + case 15: + case 129: + case 135: + { + let codec; + if (streamType === 3 || streamType === 4) { + codec = "mp3"; + } else if (streamType === 15) { + codec = "aac"; + } else if (streamType === 129) { + codec = "ac3"; + } else if (streamType === 135) { + codec = "eac3"; + } else { + throw new Error("Unreachable."); + } + info = { + type: "audio", + codec, + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } + break; + case 6: + { + if (hasEac3Descriptor) { + info = { + type: "audio", + codec: "eac3", + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } else if (hasAc3Descriptor) { + info = { + type: "audio", + codec: "ac3", + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } + } + break; + default: { + if (!ignoredStreamTypes.has(streamType)) { + console.warn(`Note: MPEG-TS streams with stream_type 0x${streamType.toString(16)} are not currently supported.`); + ignoredStreamTypes.add(streamType); + } + } + } + if (info) { + this.elementaryStreams.push({ + demuxer: this, + pid: elementaryPid, + streamType, + initialized: false, + firstSection: null, + canBeTrustedWithKeyPackets: false, + info, + referencePesPackets: [] + }); + } + } + hasProgramMap = true; + } else { + const elementaryStream = this.elementaryStreams.find((x) => x.pid === section.pid); + outer: if (elementaryStream && !elementaryStream.initialized) { + const pesPacket = readPesPacket(section, true); + if (!pesPacket) { + throw new Error(`Couldn't read first PES packet for Elementary Stream with PID ${elementaryStream.pid}`); + } + elementaryStream.firstSection = section; + elementaryStream.canBeTrustedWithKeyPackets = section.randomAccessIndicator === 1; + if (this.input._initInput) { + const initDemuxer = await this.input._initInput._getDemuxer(); + const matchingStream = initDemuxer.elementaryStreams.find((x) => x.pid === section.pid && x.info.codec === elementaryStream.info.codec); + if (matchingStream) { + elementaryStream.info = matchingStream.info; + elementaryStream.initialized = true; + break outer; + } + } + const context = new PacketReadingContext(elementaryStream, pesPacket); + if (elementaryStream.info.type === "video") { + while (true) { + const contextAlias = context; + contextAlias.suppliedPacket = null; + await context.markNextPacket(); + if (elementaryStream.info.codec === "avc") { + if (!context.suppliedPacket) { + throw new Error("Invalid AVC video stream; could not extract AVCDecoderConfigurationRecord from any packet."); + } + elementaryStream.info.avcCodecInfo = extractAvcDecoderConfigurationRecord(context.suppliedPacket.data); + if (!elementaryStream.info.avcCodecInfo) { + continue; + } + const spsUnit = elementaryStream.info.avcCodecInfo.sequenceParameterSets[0]; + assert(spsUnit); + const spsInfo = parseAvcSps(spsUnit); + elementaryStream.info.width = spsInfo.displayWidth; + elementaryStream.info.height = spsInfo.displayHeight; + const num = spsInfo.pixelAspectRatio.num; + const den = spsInfo.pixelAspectRatio.den; + if (num > 0 && den > 0) { + if (num > den) { + elementaryStream.info.squarePixelWidth = Math.round(elementaryStream.info.width * num / den); + elementaryStream.info.squarePixelHeight = elementaryStream.info.height; + } else { + elementaryStream.info.squarePixelWidth = elementaryStream.info.width; + elementaryStream.info.squarePixelHeight = Math.round(elementaryStream.info.height * den / num); + } + } + elementaryStream.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[spsInfo.transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[spsInfo.matrixCoefficients], + fullRange: !!spsInfo.fullRangeFlag + }; + elementaryStream.info.reorderSize = spsInfo.maxDecFrameBuffering; + break; + } else if (elementaryStream.info.codec === "hevc") { + if (!context.suppliedPacket) { + throw new Error("Invalid HEVC video stream; could not extract HVCDecoderConfigurationRecord from first packet."); + } + elementaryStream.info.hevcCodecInfo = extractHevcDecoderConfigurationRecord(context.suppliedPacket.data); + if (!elementaryStream.info.hevcCodecInfo) { + continue; + } + const spsArray = elementaryStream.info.hevcCodecInfo.arrays.find((a) => a.nalUnitType === HevcNalUnitType.SPS_NUT); + const spsUnit = spsArray.nalUnits[0]; + assert(spsUnit); + const spsInfo = parseHevcSps(spsUnit); + elementaryStream.info.width = spsInfo.displayWidth; + elementaryStream.info.height = spsInfo.displayHeight; + if (spsInfo.pixelAspectRatio.num > spsInfo.pixelAspectRatio.den) { + elementaryStream.info.squarePixelWidth = Math.round(elementaryStream.info.width * spsInfo.pixelAspectRatio.num / spsInfo.pixelAspectRatio.den); + elementaryStream.info.squarePixelHeight = elementaryStream.info.height; + } else { + elementaryStream.info.squarePixelWidth = elementaryStream.info.width; + elementaryStream.info.squarePixelHeight = Math.round(elementaryStream.info.height * spsInfo.pixelAspectRatio.den / spsInfo.pixelAspectRatio.num); + } + elementaryStream.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[spsInfo.transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[spsInfo.matrixCoefficients], + fullRange: !!spsInfo.fullRangeFlag + }; + elementaryStream.info.reorderSize = spsInfo.maxDecFrameBuffering; + break; + } else { + throw new Error("Unhandled."); + } + } + elementaryStream.info.decoderConfig = { + codec: extractVideoCodecString({ + width: elementaryStream.info.width, + height: elementaryStream.info.height, + codec: elementaryStream.info.codec, + codecDescription: null, + colorSpace: elementaryStream.info.colorSpace, + avcType: 1, + avcCodecInfo: elementaryStream.info.avcCodecInfo, + hevcCodecInfo: elementaryStream.info.hevcCodecInfo, + vp9CodecInfo: null, + av1CodecInfo: null + }), + codedWidth: elementaryStream.info.width, + codedHeight: elementaryStream.info.height, + colorSpace: elementaryStream.info.colorSpace + }; + if (elementaryStream.info.width !== elementaryStream.info.squarePixelWidth || elementaryStream.info.height !== elementaryStream.info.squarePixelHeight) { + elementaryStream.info.decoderConfig.displayAspectWidth = elementaryStream.info.squarePixelWidth; + elementaryStream.info.decoderConfig.displayAspectHeight = elementaryStream.info.squarePixelHeight; + } + elementaryStream.initialized = true; + } else { + await context.markNextPacket(); + if (!context.suppliedPacket) { + throw new Error(`Couldn't parse first media packet for Elementary Stream with PID ${elementaryStream.pid}`); + } + if (elementaryStream.info.codec === "aac") { + const slice = FileSlice.tempFromBytes(context.suppliedPacket.data); + const header = readAdtsFrameHeader(slice); + if (!header) { + throw new Error("Invalid AAC audio stream; could not read ADTS frame header from first packet."); + } + elementaryStream.info.aacCodecInfo = { + isMpeg2: false, + objectType: header.objectType + }; + elementaryStream.info.numberOfChannels = aacChannelMap[header.channelConfiguration]; + elementaryStream.info.sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; + } else if (elementaryStream.info.codec === "mp3") { + const word = readU32Be(FileSlice.tempFromBytes(context.suppliedPacket.data)); + const result = readMp3FrameHeader(word, context.suppliedPacket.data.byteLength); + if (!result.header) { + throw new Error("Invalid MP3 audio stream; could not read frame header from first packet."); + } + elementaryStream.info.numberOfChannels = result.header.channel === 3 ? 1 : 2; + elementaryStream.info.sampleRate = result.header.sampleRate; + } else if (elementaryStream.info.codec === "ac3") { + const frameInfo = parseAc3SyncFrame(context.suppliedPacket.data); + if (!frameInfo) { + throw new Error("Invalid AC-3 audio stream; could not read sync frame from first packet."); + } + if (frameInfo.fscod === 3) { + throw new Error("Invalid AC-3 audio stream; reserved sample rate code found in first packet."); + } + elementaryStream.info.numberOfChannels = AC3_ACMOD_CHANNEL_COUNTS[frameInfo.acmod] + frameInfo.lfeon; + elementaryStream.info.sampleRate = AC3_SAMPLE_RATES[frameInfo.fscod]; + } else if (elementaryStream.info.codec === "eac3") { + const frameInfo = parseEac3SyncFrame(context.suppliedPacket.data); + if (!frameInfo) { + throw new Error("Invalid E-AC-3 audio stream; could not read sync frame from first packet."); + } + const sampleRate = getEac3SampleRate(frameInfo); + if (sampleRate === null) { + throw new Error("Invalid E-AC-3 audio stream; reserved sample rate code found in first packet."); + } + elementaryStream.info.numberOfChannels = getEac3ChannelCount(frameInfo); + elementaryStream.info.sampleRate = sampleRate; + } else { + throw new Error("Unhandled."); + } + elementaryStream.info.decoderConfig = { + codec: extractAudioCodecString({ + codec: elementaryStream.info.codec, + codecDescription: null, + aacCodecInfo: elementaryStream.info.aacCodecInfo + }), + numberOfChannels: elementaryStream.info.numberOfChannels, + sampleRate: elementaryStream.info.sampleRate + }; + elementaryStream.initialized = true; + } + } + } + const isDone = hasProgramMap && this.elementaryStreams.every((x) => x.initialized); + if (isDone) { + break; + } + currentPos += this.packetStride; + } + if (!hasProgramMap) { + if (!hasProgramAssociationTable) { + throw new Error("No Program Association Table found in the file."); + } + throw new Error("No Program Map Table found in the file."); + } + for (const stream of this.elementaryStreams) { + if (stream.info.type === "video") { + this.trackBackingEntries.push(new MpegTsVideoTrackBacking(stream)); + } else { + this.trackBackingEntries.push(new MpegTsAudioTrackBacking(stream)); + } + } + })()); + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackingEntries; + } + async getMetadataTags() { + return {}; + } + async getMimeType() { + await this.readMetadata(); + const codecStrings = await Promise.all(this.trackBackingEntries.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildMpegTsMimeType(codecStrings); + } + async readSection(startPos, full, contiguous = false) { + let endPos = startPos; + let currentPos = startPos; + const chunks = []; + let chunksByteLength = 0; + let firstPacket = null; + let mustAddSectionEnd = true; + let randomAccessIndicator = 0; + while (true) { + const packet = await this.readPacket(currentPos); + currentPos += this.packetStride; + if (!packet) { + break; + } + if (!firstPacket) { + if (packet.payloadUnitStartIndicator === 0) { + break; + } + firstPacket = packet; + } else { + if (packet.pid !== firstPacket.pid) { + if (contiguous) { + break; + } else { + continue; + } + } + if (packet.payloadUnitStartIndicator === 1) { + break; + } + } + const hasAdaptationField = !!(packet.adaptationFieldControl & 2); + const hasPayload = !!(packet.adaptationFieldControl & 1); + let adaptationFieldLength = 0; + if (hasAdaptationField) { + adaptationFieldLength = 1 + packet.body[0]; + if (packet === firstPacket && adaptationFieldLength > 1) { + randomAccessIndicator = packet.body[1] >> 6 & 1; + } + } + if (hasPayload) { + if (adaptationFieldLength === 0) { + chunks.push(packet.body); + chunksByteLength += packet.body.byteLength; + } else { + chunks.push(packet.body.subarray(adaptationFieldLength)); + chunksByteLength += packet.body.byteLength - adaptationFieldLength; + } + } + endPos = currentPos; + if (!full && chunksByteLength >= 64) { + mustAddSectionEnd = false; + break; + } + const isKnownSectionEnd = binarySearchExact(this.sectionEndPositions, endPos, (x) => x) !== -1; + if (isKnownSectionEnd) { + mustAddSectionEnd = false; + break; + } + } + if (mustAddSectionEnd) { + const index = binarySearchLessOrEqual(this.sectionEndPositions, endPos, (x) => x); + this.sectionEndPositions.splice(index + 1, 0, endPos); + } + if (!firstPacket) { + return null; + } + let merged; + if (chunks.length === 1) { + merged = chunks[0]; + } else { + const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0); + merged = new Uint8Array(totalLength); + let offset = 0; + for (const chunk of chunks) { + merged.set(chunk, offset); + offset += chunk.length; + } + } + return { + startPos, + endPos: full ? endPos : null, + pid: firstPacket.pid, + payload: merged, + randomAccessIndicator + }; + } + async readPacketHeader(pos) { + let slice = this.reader.requestSlice(pos, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const syncByte = readU8(slice); + if (syncByte !== 71) { + throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file."); + } + const nextTwoBytes = readU16Be(slice); + const payloadUnitStartIndicator = nextTwoBytes >> 14 & 1; + const pid = nextTwoBytes & 8191; + const nextByte = readU8(slice); + const adaptationFieldControl = nextByte >> 4 & 3; + return { + payloadUnitStartIndicator, + pid, + adaptationFieldControl + }; + } + async readPacket(pos) { + let slice = this.reader.requestSlice(pos, TS_PACKET_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const bytes = readBytes(slice, TS_PACKET_SIZE); + const syncByte = bytes[0]; + if (syncByte !== 71) { + throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file."); + } + const nextTwoBytes = (bytes[1] << 8) + bytes[2]; + const payloadUnitStartIndicator = nextTwoBytes >> 14 & 1; + const pid = nextTwoBytes & 8191; + const nextByte = bytes[3]; + const adaptationFieldControl = nextByte >> 4 & 3; + return { + payloadUnitStartIndicator, + pid, + adaptationFieldControl, + body: bytes.subarray(4) + }; + } + } + const readPesPacketHeader = (section, expectPts) => { + if (section.payload.byteLength < 3) { + return null; + } + const bitstream = new Bitstream(section.payload); + const startCodePrefix = bitstream.readBits(24); + if (startCodePrefix !== 1) { + return null; + } + const streamId = bitstream.readBits(8); + bitstream.skipBits(16); + if (streamId === 188 || streamId === 190 || streamId === 191 || streamId === 240 || streamId === 241 || streamId === 255 || streamId === 242 || streamId === 248) { + return null; + } + bitstream.skipBits(8); + const ptsDtsFlags = bitstream.readBits(2); + bitstream.skipBits(14); + let pts = null; + if (ptsDtsFlags === 2 || ptsDtsFlags === 3) { + pts = 0; + bitstream.skipBits(4); + pts += bitstream.readBits(3) * (1 << 30); + bitstream.skipBits(1); + pts += bitstream.readBits(15) * (1 << 15); + bitstream.skipBits(1); + pts += bitstream.readBits(15); + } else { + if (expectPts) { + throw new Error(MISSING_PTS_ERROR_MESSAGE); + } + } + return { + sectionStartPos: section.startPos, + sectionEndPos: section.endPos, + pts, + randomAccessIndicator: section.randomAccessIndicator + }; + }; + const readPesPacket = (section, expectPts) => { + assert(section.endPos !== null); + const header = readPesPacketHeader(section, expectPts); + if (!header) { + return null; + } + const bitstream = new Bitstream(section.payload); + bitstream.skipBits(32); + const pesPacketLength = bitstream.readBits(16); + const BYTES_UNTIL_END_OF_PES_PACKET_LENGTH = 6; + bitstream.skipBits(16); + const pesHeaderDataLength = bitstream.readBits(8); + const pesHeaderEndPos = bitstream.pos + 8 * pesHeaderDataLength; + bitstream.pos = pesHeaderEndPos; + const bytePos = pesHeaderEndPos / 8; + assert(Number.isInteger(bytePos)); + const data = section.payload.subarray( + bytePos, + // "A value of 0 indicates that the PES packet length is neither specified nor bounded and is allowed only in + // PES packets whose payload consists of bytes from a video elementary stream contained in + // transport stream packets." + pesPacketLength > 0 ? BYTES_UNTIL_END_OF_PES_PACKET_LENGTH + pesPacketLength : section.payload.byteLength + ); + return { + ...header, + data + }; + }; + class MpegTsTrackBacking { + constructor(elementaryStream) { + this.elementaryStream = elementaryStream; + this.packetBuffers = /* @__PURE__ */ new WeakMap(); + this.packetSectionStarts = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.elementaryStream.pid; + } + getNumber() { + const demuxer = this.elementaryStream.demuxer; + const trackType = this.elementaryStream.info.type; + let number = 0; + for (const backing of demuxer.trackBackingEntries) { + if (backing.getType() === trackType) { + number++; + } + assert(backing instanceof MpegTsTrackBacking); + if (backing.elementaryStream === this.elementaryStream) { + break; + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.elementaryStream.streamType; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }; + } + getTimeResolution() { + return TIMESCALE; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + createEncodedPacket(suppliedPacket, duration, options) { + let packetType; + if (this.allPacketsAreKeyPackets()) { + packetType = "key"; + } else { + packetType = suppliedPacket.randomAccessIndicator === 1 ? "key" : "delta"; + } + return new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : suppliedPacket.data, packetType, suppliedPacket.pts / TIMESCALE, Math.max(duration / TIMESCALE, 0), suppliedPacket.sequenceNumber, suppliedPacket.data.byteLength); + } + async getFirstPacket(options) { + const section = this.elementaryStream.firstSection; + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + const buffer = new PacketBuffer(this, context); + const result = await buffer.readNext(); + if (!result) { + return null; + } + const packet = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(packet, buffer); + this.packetSectionStarts.set(packet, result.packet.sectionStartPos); + return packet; + } + async getNextPacket(packet, options) { + let buffer = this.packetBuffers.get(packet); + if (buffer) { + const result = await buffer.readNext(); + if (!result) { + return null; + } + this.packetBuffers.delete(packet); + const newPacket = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(newPacket, buffer); + this.packetSectionStarts.set(newPacket, result.packet.sectionStartPos); + return newPacket; + } + const sectionStartPos = this.packetSectionStarts.get(packet); + if (sectionStartPos === void 0) { + throw new Error("Packet was not created from this track."); + } + const demuxer = this.elementaryStream.demuxer; + const section = await demuxer.readSection(sectionStartPos, true); + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + buffer = new PacketBuffer(this, context); + const targetSequenceNumber = packet.sequenceNumber; + while (true) { + const result = await buffer.readNext(); + if (!result) { + return null; + } + if (result.packet.sequenceNumber > targetSequenceNumber) { + const newPacket = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(newPacket, buffer); + this.packetSectionStarts.set(newPacket, result.packet.sectionStartPos); + return newPacket; + } + } + } + async getNextKeyPacket(packet, options) { + let currentPacket = packet; + while (true) { + currentPacket = await this.getNextPacket(currentPacket, options); + if (!currentPacket) { + return null; + } + if (currentPacket.type === "key") { + return currentPacket; + } + } + } + getPacket(timestamp, options) { + return this.doPacketLookup(timestamp, false, options); + } + getKeyPacket(timestamp, options) { + return this.doPacketLookup(timestamp, true, options); + } + /** + * Searches for the packet with the largest timestamp not larger than `timestamp` in the file, using a combination + * of chunk-based binary search and linear refinement. The reason the coarse search is done in large chunks is to + * make it more performant for small files and over high-latency readers such as the network. + */ + async doPacketLookup(timestamp, keyframesOnly, options) { + const searchPts = roundIfAlmostInteger(timestamp * TIMESCALE); + const demuxer = this.elementaryStream.demuxer; + const { reader, seekChunkSize } = demuxer; + const pid = this.elementaryStream.pid; + const findFirstPesPacketHeaderInChunk = async (startPos, endPos, readSectionInFull) => { + let currentPos = startPos; + while (currentPos < endPos) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + return null; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, readSectionInFull); + if (!section) { + return null; + } + const pesPacketHeader = readPesPacketHeader(section, false); + if (pesPacketHeader && pesPacketHeader.pts !== null) { + return { + pesPacketHeader, + section + }; + } + } + currentPos += demuxer.packetStride; + } + return null; + }; + const firstSection = this.elementaryStream.firstSection; + assert(firstSection); + const firstPesPacketHeader = readPesPacketHeader(firstSection, true); + assert(firstPesPacketHeader); + if (searchPts < firstPesPacketHeader.pts) { + return null; + } + let scanStartPos; + const referencePesPackets = this.elementaryStream.referencePesPackets; + const referencePointIndex = binarySearchLessOrEqual(referencePesPackets, searchPts, (x) => x.pts); + const referencePoint = referencePointIndex !== -1 ? referencePesPackets[referencePointIndex] : null; + if (referencePoint && searchPts - referencePoint.pts < TIMESCALE / 2) { + scanStartPos = referencePoint.sectionStartPos; + } else { + let startChunkIndex = 0; + if (reader.fileSize !== null) { + const numChunks = Math.ceil(reader.fileSize / seekChunkSize); + if (numChunks > 1) { + let low = 0; + let high = numChunks - 1; + startChunkIndex = low; + while (low <= high) { + const mid = Math.floor((low + high) / 2); + const chunkStartPos = floorToMultiple(mid * seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos; + const chunkEndPos = chunkStartPos + seekChunkSize; + const result2 = await findFirstPesPacketHeaderInChunk(chunkStartPos, chunkEndPos, false); + if (!result2) { + high = mid - 1; + continue; + } + if (result2.pesPacketHeader.pts <= searchPts) { + startChunkIndex = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + } + } + scanStartPos = floorToMultiple(startChunkIndex * seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos; + } + const result = await findFirstPesPacketHeaderInChunk(scanStartPos, reader.fileSize ?? Infinity, false); + let currentPesHeader = result?.pesPacketHeader ?? null; + if (!currentPesHeader) { + currentPesHeader = firstPesPacketHeader; + } + const reorderSize = this.getReorderSize(); + const retrieveEncodedPacket = async (sectionStartPos, predicate) => { + const section = await demuxer.readSection(sectionStartPos, true); + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + const buffer = new PacketBuffer(this, context); + while (true) { + const topPts = last(buffer.presentationOrderPackets)?.pts ?? -Infinity; + if (topPts >= searchPts) { + break; + } + const didRead = await buffer.readNextPacket(); + if (!didRead) { + break; + } + } + const targetIndex = findLastIndex(buffer.presentationOrderPackets, predicate); + if (targetIndex === -1) { + return null; + } + const targetPacket = buffer.presentationOrderPackets[targetIndex]; + const lastDuration = targetIndex === 0 ? 0 : targetPacket.pts - buffer.presentationOrderPackets[targetIndex - 1].pts; + while (buffer.decodeOrderPackets[0] !== targetPacket) { + buffer.decodeOrderPackets.shift(); + } + buffer.lastDuration = lastDuration; + const result2 = await buffer.readNext(); + assert(result2); + const packet = this.createEncodedPacket(result2.packet, result2.duration, options); + this.packetBuffers.set(packet, buffer); + this.packetSectionStarts.set(packet, result2.packet.sectionStartPos); + return packet; + }; + if (!keyframesOnly || this.allPacketsAreKeyPackets()) { + outer: while (true) { + let currentPos = currentPesHeader.sectionStartPos + demuxer.packetStride; + while (true) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, false); + if (section) { + const nextPesHeader = readPesPacketHeader(section, false); + if (nextPesHeader && nextPesHeader.pts !== null) { + if (nextPesHeader.pts > searchPts) { + break outer; + } + currentPesHeader = nextPesHeader; + maybeInsertReferencePacket(this.elementaryStream, currentPesHeader); + break; + } + } + } + currentPos += demuxer.packetStride; + } + } + outer: for (let i = 0; i < reorderSize + 1; i++) { + let pos = currentPesHeader.sectionStartPos - demuxer.packetStride; + while (pos >= demuxer.packetOffset) { + const packetHeader = await demuxer.readPacketHeader(pos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(pos, false); + if (section) { + const header = readPesPacketHeader(section, false); + if (header && header.pts !== null) { + currentPesHeader = header; + break; + } + } + } + pos -= demuxer.packetStride; + } + } + return retrieveEncodedPacket(currentPesHeader.sectionStartPos, (p) => p.pts <= searchPts); + } else { + let currentChunkStartPos = scanStartPos; + let nextChunkStartPos = null; + const readSectionsInFull = !this.elementaryStream.canBeTrustedWithKeyPackets; + while (true) { + let bestKeyPesHeader = null; + const isFirstChunk = currentChunkStartPos <= firstPesPacketHeader.sectionStartPos; + let pesHeader; + let pesHeaderSection = null; + if (isFirstChunk) { + pesHeader = firstPesPacketHeader; + pesHeaderSection = firstSection; + } else { + const result2 = await findFirstPesPacketHeaderInChunk(currentChunkStartPos, reader.fileSize ?? Infinity, readSectionsInFull); + pesHeader = result2?.pesPacketHeader ?? null; + pesHeaderSection = result2?.section ?? null; + } + let passedSearchPts = false; + let lookaheadCount = 0; + outer: while (pesHeader) { + if (nextChunkStartPos !== null && pesHeader.sectionStartPos >= nextChunkStartPos) { + break; + } + if (pesHeader.pts <= searchPts) { + let isKeyPacket; + if (this.elementaryStream.canBeTrustedWithKeyPackets) { + isKeyPacket = pesHeader.randomAccessIndicator === 1; + } else { + assert(pesHeaderSection); + const pesPacket = readPesPacket(pesHeaderSection, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + await context.markNextPacket(); + isKeyPacket = context.suppliedPacket?.randomAccessIndicator === 1; + } + if (isKeyPacket) { + bestKeyPesHeader = pesHeader; + } + } + if (pesHeader.pts > searchPts) { + passedSearchPts = true; + } + if (passedSearchPts) { + lookaheadCount++; + if (lookaheadCount > reorderSize) { + break; + } + } + let currentPos = pesHeader.sectionStartPos + demuxer.packetStride; + while (true) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, readSectionsInFull); + if (section) { + const nextPesHeader = readPesPacketHeader(section, false); + if (nextPesHeader && nextPesHeader.pts !== null) { + pesHeader = nextPesHeader; + pesHeaderSection = section; + maybeInsertReferencePacket(this.elementaryStream, pesHeader); + break; + } + } + } + currentPos += demuxer.packetStride; + } + } + if (bestKeyPesHeader) { + let startPesHeader = bestKeyPesHeader; + if (lookaheadCount === 0) { + outer: for (let i = 0; i < reorderSize; i++) { + let pos = startPesHeader.sectionStartPos - demuxer.packetStride; + while (pos >= demuxer.packetOffset) { + const packetHeader = await demuxer.readPacketHeader(pos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(pos, readSectionsInFull); + if (section) { + const header = readPesPacketHeader(section, false); + if (header && header.pts !== null) { + startPesHeader = header; + break; + } + } + } + pos -= demuxer.packetStride; + } + } + } + const encodedPacket = await retrieveEncodedPacket(startPesHeader.sectionStartPos, (p) => p.pts <= searchPts && p.randomAccessIndicator === 1); + assert(encodedPacket); + return encodedPacket; + } + if (isFirstChunk) { + return null; + } + nextChunkStartPos = currentChunkStartPos; + currentChunkStartPos = Math.max(floorToMultiple(currentChunkStartPos - firstPesPacketHeader.sectionStartPos - seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos, firstPesPacketHeader.sectionStartPos); + } + } + } + } + class MpegTsVideoTrackBacking extends MpegTsTrackBacking { + getType() { + return "video"; + } + getCodec() { + return this.elementaryStream.info.codec; + } + getCodedWidth() { + return this.elementaryStream.info.width; + } + getCodedHeight() { + return this.elementaryStream.info.height; + } + getSquarePixelWidth() { + return this.elementaryStream.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.elementaryStream.info.squarePixelHeight; + } + getRotation() { + return 0; + } + async getColorSpace() { + return this.elementaryStream.info.colorSpace; + } + async canBeTransparent() { + return false; + } + async getDecoderConfig() { + assert(this.elementaryStream.info.decoderConfig); + return this.elementaryStream.info.decoderConfig; + } + allPacketsAreKeyPackets() { + return false; + } + getReorderSize() { + return this.elementaryStream.info.reorderSize; + } + } + class MpegTsAudioTrackBacking extends MpegTsTrackBacking { + getType() { + return "audio"; + } + getCodec() { + return this.elementaryStream.info.codec; + } + getNumberOfChannels() { + return this.elementaryStream.info.numberOfChannels; + } + getSampleRate() { + return this.elementaryStream.info.sampleRate; + } + async getDecoderConfig() { + assert(this.elementaryStream.info.decoderConfig); + return this.elementaryStream.info.decoderConfig; + } + allPacketsAreKeyPackets() { + return true; + } + getReorderSize() { + return 0; + } + } + const maybeInsertReferencePacket = (elementaryStream, pesPacketHeader) => { + const referencePesPackets = elementaryStream.referencePesPackets; + const index = binarySearchLessOrEqual(referencePesPackets, pesPacketHeader.sectionStartPos, (x) => x.sectionStartPos); + if (index >= 0) { + const entry = referencePesPackets[index]; + if (pesPacketHeader.pts <= entry.pts) { + return false; + } + const minByteDistance = elementaryStream.demuxer.minReferencePointByteDistance; + if (pesPacketHeader.sectionStartPos - entry.sectionStartPos < minByteDistance) { + return false; + } + if (index < referencePesPackets.length - 1) { + const nextEntry = referencePesPackets[index + 1]; + if (nextEntry.pts < pesPacketHeader.pts) { + return false; + } + if (nextEntry.sectionStartPos - pesPacketHeader.sectionStartPos < minByteDistance) { + return false; + } + } + } + referencePesPackets.splice(index + 1, 0, pesPacketHeader); + return true; + }; + class PacketReadingContext { + constructor(elementaryStream, startingPesPacket) { + this.currentPos = 0; + this.pesPackets = []; + this.currentPesPacketIndex = 0; + this.currentPesPacketPos = 0; + this.endPos = 0; + this.lastSuppliedPesPacket = null; + this.nextPts = null; + this.suppliedPacket = null; + this.elementaryStream = elementaryStream; + this.pid = elementaryStream.pid; + this.demuxer = elementaryStream.demuxer; + this.startingPesPacket = startingPesPacket; + } + ensureBuffered(length) { + const remaining = this.endPos - this.currentPos; + if (remaining >= length) { + return length; + } + return this.bufferData(length - remaining).then(() => Math.min(this.endPos - this.currentPos, length)); + } + getCurrentPesPacket() { + const packet = this.pesPackets[this.currentPesPacketIndex]; + assert(packet); + return packet; + } + async bufferData(length) { + const targetEndPos = this.endPos + length; + while (this.endPos < targetEndPos) { + let pesPacket; + if (this.pesPackets.length === 0) { + pesPacket = this.startingPesPacket; + } else { + let currentPos = last(this.pesPackets).sectionEndPos; + assert(currentPos !== null); + while (true) { + const packetHeader = await this.demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + return; + } + if (packetHeader.pid === this.pid) { + const nextSection = await this.demuxer.readSection(currentPos, true); + if (!nextSection) { + return; + } + const nextPesPacket = readPesPacket(nextSection, false); + if (nextPesPacket) { + pesPacket = nextPesPacket; + break; + } + } + currentPos += this.demuxer.packetStride; + } + } + this.pesPackets.push(pesPacket); + this.endPos += pesPacket.data.byteLength; + } + } + readBytes(length) { + const currentPesPacket = this.getCurrentPesPacket(); + const relativeStartOffset = this.currentPos - this.currentPesPacketPos; + const relativeEndOffset = relativeStartOffset + length; + this.currentPos += length; + if (relativeEndOffset <= currentPesPacket.data.byteLength) { + return currentPesPacket.data.subarray(relativeStartOffset, relativeEndOffset); + } + const result = new Uint8Array(length); + result.set(currentPesPacket.data.subarray(relativeStartOffset)); + let offset = currentPesPacket.data.byteLength - relativeStartOffset; + while (true) { + this.advanceCurrentPacket(); + const currentPesPacket2 = this.getCurrentPesPacket(); + const relativeEndOffset2 = length - offset; + if (relativeEndOffset2 <= currentPesPacket2.data.byteLength) { + result.set(currentPesPacket2.data.subarray(0, relativeEndOffset2), offset); + break; + } + result.set(currentPesPacket2.data, offset); + offset += currentPesPacket2.data.byteLength; + } + return result; + } + readU8() { + let currentPesPacket = this.getCurrentPesPacket(); + const relativeOffset = this.currentPos - this.currentPesPacketPos; + this.currentPos++; + if (relativeOffset < currentPesPacket.data.byteLength) { + return currentPesPacket.data[relativeOffset]; + } + this.advanceCurrentPacket(); + currentPesPacket = this.getCurrentPesPacket(); + return currentPesPacket.data[0]; + } + seekTo(pos) { + if (pos === this.currentPos) { + return; + } + if (pos < this.currentPos) { + while (pos < this.currentPesPacketPos) { + this.currentPesPacketIndex--; + const currentPacket = this.getCurrentPesPacket(); + this.currentPesPacketPos -= currentPacket.data.byteLength; + } + } else { + while (true) { + const currentPesPacket = this.getCurrentPesPacket(); + const currentEndPos = this.currentPesPacketPos + currentPesPacket.data.byteLength; + if (pos < currentEndPos) { + break; + } + this.currentPesPacketPos += currentPesPacket.data.byteLength; + this.currentPesPacketIndex++; + } + } + this.currentPos = pos; + } + skip(n) { + this.seekTo(this.currentPos + n); + } + advanceCurrentPacket() { + this.currentPesPacketPos += this.getCurrentPesPacket().data.byteLength; + this.currentPesPacketIndex++; + } + async markNextPacket() { + assert(!this.suppliedPacket); + const elementaryStream = this.elementaryStream; + if (elementaryStream.info.type === "video") { + const codec = elementaryStream.info.codec; + const CHUNK_SIZE = 1024; + if (codec !== "avc" && codec !== "hevc") { + throw new Error("Unhandled."); + } + let packetStartPos = null; + while (true) { + let remaining = this.ensureBuffered(CHUNK_SIZE); + if (remaining instanceof Promise) + remaining = await remaining; + if (remaining === 0) { + break; + } + const chunkStartPos = this.currentPos; + const chunk = this.readBytes(remaining); + const length = chunk.byteLength; + let i = 0; + while (i < length) { + const zeroIndex = chunk.indexOf(0, i); + if (zeroIndex === -1 || zeroIndex >= length) { + break; + } + i = zeroIndex; + const posBeforeZero = chunkStartPos + i; + if (i + 4 >= length) { + this.seekTo(posBeforeZero); + break; + } + const b1 = chunk[i + 1]; + const b2 = chunk[i + 2]; + const b3 = chunk[i + 3]; + let startCodeLength = 0; + let nalUnitTypeByte = null; + if (b1 === 0 && b2 === 0 && b3 === 1) { + startCodeLength = 4; + nalUnitTypeByte = chunk[i + 4]; + } else if (b1 === 0 && b2 === 1) { + startCodeLength = 3; + nalUnitTypeByte = b3; + } + if (startCodeLength === 0) { + i++; + continue; + } + const startCodePos = posBeforeZero; + if (packetStartPos === null) { + packetStartPos = startCodePos; + i += startCodeLength; + continue; + } + if (nalUnitTypeByte !== null) { + const nalUnitType = codec === "avc" ? extractNalUnitTypeForAvc(nalUnitTypeByte) : extractNalUnitTypeForHevc(nalUnitTypeByte); + const isAud = codec === "avc" ? nalUnitType === AvcNalUnitType.AUD : nalUnitType === HevcNalUnitType.AUD_NUT; + if (isAud) { + const packetLength = startCodePos - packetStartPos; + this.seekTo(packetStartPos); + return this.supplyPacket(packetLength, 0); + } + } + i += startCodeLength; + } + if (remaining < CHUNK_SIZE) { + break; + } + } + if (packetStartPos !== null) { + const packetLength = this.endPos - packetStartPos; + this.seekTo(packetStartPos); + return this.supplyPacket(packetLength, 0); + } + } else { + const codec = elementaryStream.info.codec; + const CHUNK_SIZE = 128; + while (true) { + let remaining = this.ensureBuffered(CHUNK_SIZE); + if (remaining instanceof Promise) + remaining = await remaining; + const startPos = this.currentPos; + while (this.currentPos - startPos < remaining) { + const byte = this.readU8(); + if (codec === "aac") { + if (byte !== 255) { + continue; + } + this.skip(-1); + const possibleHeaderStartPos = this.currentPos; + let remaining2 = this.ensureBuffered(MAX_ADTS_FRAME_HEADER_SIZE); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < MAX_ADTS_FRAME_HEADER_SIZE) { + return; + } + const headerBytes = this.readBytes(MAX_ADTS_FRAME_HEADER_SIZE); + const header = readAdtsFrameHeader(FileSlice.tempFromBytes(headerBytes)); + if (header) { + this.seekTo(possibleHeaderStartPos); + let remaining3 = this.ensureBuffered(header.frameLength); + if (remaining3 instanceof Promise) + remaining3 = await remaining3; + return this.supplyPacket(remaining3, Math.round(SAMPLES_PER_AAC_FRAME * TIMESCALE / elementaryStream.info.sampleRate)); + } else { + this.seekTo(possibleHeaderStartPos + 1); + } + } else if (codec === "mp3") { + if (byte !== 255) { + continue; + } + this.skip(-1); + const possibleHeaderStartPos = this.currentPos; + let remaining2 = this.ensureBuffered(FRAME_HEADER_SIZE); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < FRAME_HEADER_SIZE) { + return; + } + const headerBytes = this.readBytes(FRAME_HEADER_SIZE); + const word = toDataView(headerBytes).getUint32(0); + const result = readMp3FrameHeader(word, null); + if (result.header) { + this.seekTo(possibleHeaderStartPos); + let remaining3 = this.ensureBuffered(result.header.totalSize); + if (remaining3 instanceof Promise) + remaining3 = await remaining3; + const duration = result.header.audioSamplesInFrame * TIMESCALE / elementaryStream.info.sampleRate; + return this.supplyPacket(remaining3, Math.round(duration)); + } else { + this.seekTo(possibleHeaderStartPos + 1); + } + } else if (codec === "ac3") { + if (byte !== 11) { + continue; + } + this.skip(-1); + const possibleSyncPos = this.currentPos; + let remaining2 = this.ensureBuffered(5); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < 5) { + return; + } + const headerBytes = this.readBytes(5); + if (headerBytes[0] !== 11 || headerBytes[1] !== 119) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const fscod = headerBytes[4] >> 6; + const frmsizecod = headerBytes[4] & 63; + if (fscod === 3 || frmsizecod > 37) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const frameSize = AC3_FRAME_SIZES[3 * frmsizecod + fscod]; + assert(frameSize !== void 0); + this.seekTo(possibleSyncPos); + remaining2 = this.ensureBuffered(frameSize); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + const duration = Math.round(AC3_SAMPLES_PER_FRAME * TIMESCALE / elementaryStream.info.sampleRate); + return this.supplyPacket(remaining2, duration); + } else if (codec === "eac3") { + if (byte !== 11) { + continue; + } + this.skip(-1); + const possibleSyncPos = this.currentPos; + let remaining2 = this.ensureBuffered(5); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < 5) { + return; + } + const headerBytes = this.readBytes(5); + if (headerBytes[0] !== 11 || headerBytes[1] !== 119) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const frmsiz = (headerBytes[2] & 7) << 8 | headerBytes[3]; + const frameSize = (frmsiz + 1) * 2; + const fscod = headerBytes[4] >> 6; + const numblkscod = fscod === 3 ? 3 : headerBytes[4] >> 4 & 3; + const numblks = EAC3_NUMBLKS_TABLE[numblkscod]; + this.seekTo(possibleSyncPos); + remaining2 = this.ensureBuffered(frameSize); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + const samplesPerFrame = numblks * 256; + const duration = Math.round(samplesPerFrame * TIMESCALE / elementaryStream.info.sampleRate); + return this.supplyPacket(remaining2, duration); + } else { + throw new Error("Unhandled."); + } + } + if (remaining < CHUNK_SIZE) { + break; + } + } + } + } + /** Supplies the context with a new encoded packet, beginning at the current position. */ + supplyPacket(packetLength, intrinsicDuration) { + const currentPesPacket = this.getCurrentPesPacket(); + let pts; + if (this.lastSuppliedPesPacket === currentPesPacket) { + assert(this.nextPts !== null); + pts = this.nextPts; + } else { + if (currentPesPacket.pts === null) { + throw new Error(MISSING_PTS_ERROR_MESSAGE); + } + pts = currentPesPacket.pts; + maybeInsertReferencePacket(this.elementaryStream, currentPesPacket); + } + this.lastSuppliedPesPacket = currentPesPacket; + this.nextPts = pts + intrinsicDuration; + const sectionStartPos = currentPesPacket.sectionStartPos; + const sequenceNumber = sectionStartPos + (this.currentPos - this.currentPesPacketPos); + const data = this.readBytes(packetLength); + let randomAccessIndicator = currentPesPacket.randomAccessIndicator; + if (randomAccessIndicator === 0 && !this.elementaryStream.canBeTrustedWithKeyPackets) { + if (this.elementaryStream.info.type === "audio") { + randomAccessIndicator = 1; + } else { + if (this.elementaryStream.info.decoderConfig) { + const isKey = determineVideoPacketType(this.elementaryStream.info.codec, this.elementaryStream.info.decoderConfig, data) === "key"; + randomAccessIndicator = Number(isKey); + } + } + } + this.suppliedPacket = { + pts, + data, + sequenceNumber, + sectionStartPos, + randomAccessIndicator + }; + this.pesPackets.splice(0, this.currentPesPacketIndex); + this.currentPesPacketIndex = 0; + } + } + class PacketBuffer { + constructor(backing, context) { + this.decodeOrderPackets = []; + this.reorderBuffer = []; + this.presentationOrderPackets = []; + this.reachedEnd = false; + this.lastDuration = 0; + this.backing = backing; + this.context = context; + this.reorderSize = backing.getReorderSize(); + assert(this.reorderSize >= 0); + } + async readNext() { + if (this.decodeOrderPackets.length === 0) { + const didRead = await this.readNextPacket(); + if (!didRead) { + return null; + } + } + await this.ensureCurrentPacketHasNext(); + const packet = this.decodeOrderPackets[0]; + const presentationIndex = this.presentationOrderPackets.indexOf(packet); + assert(presentationIndex !== -1); + let duration; + if (presentationIndex === this.presentationOrderPackets.length - 1) { + duration = this.lastDuration; + } else { + const nextPacket = this.presentationOrderPackets[presentationIndex + 1]; + duration = nextPacket.pts - packet.pts; + this.lastDuration = duration; + } + this.decodeOrderPackets.shift(); + while (this.presentationOrderPackets.length > 0) { + const first = this.presentationOrderPackets[0]; + if (this.decodeOrderPackets.includes(first)) { + break; + } + this.presentationOrderPackets.shift(); + } + return { packet, duration }; + } + async readNextPacket() { + if (this.reachedEnd) { + return false; + } + let suppliedPacket; + if (this.context.suppliedPacket) { + suppliedPacket = this.context.suppliedPacket; + } else { + await this.context.markNextPacket(); + suppliedPacket = this.context.suppliedPacket; + } + this.context.suppliedPacket = null; + if (!suppliedPacket) { + this.reachedEnd = true; + this.flushReorderBuffer(); + return false; + } + this.decodeOrderPackets.push(suppliedPacket); + this.processPacketThroughReorderBuffer(suppliedPacket); + return true; + } + async ensureCurrentPacketHasNext() { + const current = this.decodeOrderPackets[0]; + assert(current); + while (true) { + const presentationIndex = this.presentationOrderPackets.indexOf(current); + if (presentationIndex !== -1 && presentationIndex <= this.presentationOrderPackets.length - 2) { + break; + } + const didRead = await this.readNextPacket(); + if (!didRead) { + break; + } + } + } + processPacketThroughReorderBuffer(packet) { + this.reorderBuffer.push(packet); + if (this.reorderBuffer.length > this.reorderSize) { + let minIndex = 0; + for (let i = 1; i < this.reorderBuffer.length; i++) { + if (this.reorderBuffer[i].pts < this.reorderBuffer[minIndex].pts) { + minIndex = i; + } + } + const packet2 = this.reorderBuffer[minIndex]; + this.presentationOrderPackets.push(packet2); + this.reorderBuffer.splice(minIndex, 1); + } + } + flushReorderBuffer() { + this.reorderBuffer.sort((a, b) => a.pts - b.pts); + this.presentationOrderPackets.push(...this.reorderBuffer); + this.reorderBuffer.length = 0; + } + } + const HLS_MIME_TYPE = "application/vnd.apple.mpegurl"; + const TAG_STREAM_INF = "#EXT-X-STREAM-INF:"; + const TAG_I_FRAME_STREAM_INF = "#EXT-X-I-FRAME-STREAM-INF:"; + const TAG_MEDIA = "#EXT-X-MEDIA:"; + const TAG_EXTINF = "#EXTINF:"; + const TAG_MAP = "#EXT-X-MAP:"; + const TAG_KEY = "#EXT-X-KEY:"; + const TAG_MEDIA_SEQUENCE = "#EXT-X-MEDIA-SEQUENCE:"; + const TAG_BYTERANGE = "#EXT-X-BYTERANGE:"; + const TAG_PROGRAM_DATE_TIME = "#EXT-X-PROGRAM-DATE-TIME:"; + const TAG_DISCONTINUITY = "#EXT-X-DISCONTINUITY"; + const TAG_TARGETDURATION = "#EXT-X-TARGETDURATION:"; + const TAG_ENDLIST = "#EXT-X-ENDLIST"; + const TAG_PLAYLIST_TYPE = "#EXT-X-PLAYLIST-TYPE:"; + const TAG_I_FRAMES_ONLY = "#EXT-X-I-FRAMES-ONLY"; + const canIgnoreLine = (line) => line.length === 0 || line.startsWith("#") && !line.startsWith("#EXT"); + class AttributeList { + constructor(str) { + this._attributes = {}; + let key = ""; + let value = ""; + let inValue = false; + let inQuotes = false; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + if (char === '"') { + inQuotes = !inQuotes; + } else if (char === "=" && !inValue && !inQuotes) { + inValue = true; + } else if (char === "," && !inQuotes) { + if (key) { + this._attributes[key.trim().toLowerCase()] = value; + } + key = ""; + value = ""; + inValue = false; + } else if (inValue) { + value += char; + } else { + key += char; + } + } + if (key) { + this._attributes[key.trim().toLowerCase()] = value; + } + } + get(name) { + return this._attributes[name.toLowerCase()] ?? null; + } + getAsNumber(name) { + const value = this.get(name); + if (value === null) { + return null; + } + const num = Number(value); + return Number.isFinite(num) ? num : null; + } + merge(other) { + Object.assign(this._attributes, other._attributes); + } + } + class SegmentedInput { + constructor(input, path, trackDeclarations) { + this.nextInputCacheAge = 0; + this.inputCache = []; + this.trackBackingsPromise = null; + this.firstSegment = null; + this.firstSegmentFirstTimestamps = /* @__PURE__ */ new WeakMap(); + this.firstTimestampCache = /* @__PURE__ */ new WeakMap(); + this.input = input; + this.path = path; + this.trackDeclarations = trackDeclarations; + } + async getDurationFromMetadata(options) { + const lastSegment = await this.getSegmentAt(Infinity, { + skipLiveWait: options.skipLiveWait + }); + if (!lastSegment) { + return null; + } + return lastSegment.timestamp + lastSegment.duration; + } + async getTrackBackings() { + return this.trackBackingsPromise ?? (this.trackBackingsPromise = (async () => { + const backings = []; + if (this.trackDeclarations) { + for (const decl of this.trackDeclarations) { + if (decl.type === "video") { + const number = arrayCount(backings, (x) => x.getType() === "video") + 1; + backings.push(new SegmentedInputInputVideoTrackBacking(this, decl, number)); + } else if (decl.type === "audio") { + const number = arrayCount(backings, (x) => x.getType() === "audio") + 1; + backings.push(new SegmentedInputInputAudioTrackBacking(this, decl, number)); + } + } + } else { + this.firstSegment = await this.getFirstSegment({}); + if (!this.firstSegment) { + return []; + } + const input = this.getInputForSegment(this.firstSegment); + const inputTracks = await input.getTracks(); + for (const track of inputTracks) { + if (track.type === "video") { + const number = arrayCount(backings, (x) => x.getType() === "video") + 1; + backings.push(new SegmentedInputInputVideoTrackBacking(this, { + id: backings.length + 1, + type: "video" + }, number)); + } else if (track.type === "audio") { + const number = arrayCount(backings, (x) => x.getType() === "audio") + 1; + backings.push(new SegmentedInputInputAudioTrackBacking(this, { + id: backings.length + 1, + type: "audio" + }, number)); + } + } + } + return backings; + })()); + } + // This operation is done a lot and can be semi-expensive, so it's good to have a cache for it + async getFirstTimestampForInput(input) { + const existing = this.firstTimestampCache.get(input); + if (existing !== void 0) { + return existing; + } + const firstTimestamp = await input.getFirstTimestamp(); + this.firstTimestampCache.set(input, firstTimestamp); + return firstTimestamp; + } + async getMediaOffset(segment, input) { + const firstSegment = segment.firstSegment ?? segment; + let firstSegmentFirstTimestamp; + if (this.firstSegmentFirstTimestamps.has(firstSegment)) { + firstSegmentFirstTimestamp = this.firstSegmentFirstTimestamps.get(firstSegment); + } else { + const firstInput = this.getInputForSegment(firstSegment); + firstSegmentFirstTimestamp = await this.getFirstTimestampForInput(firstInput); + this.firstSegmentFirstTimestamps.set(firstSegment, firstSegmentFirstTimestamp); + } + if (firstSegment === segment) { + return firstSegment.timestamp - firstSegmentFirstTimestamp; + } + const segmentFirstTimestamp = await this.getFirstTimestampForInput(input); + const segmentElapsed = segment.timestamp - firstSegment.timestamp; + const inputElapsed = segmentFirstTimestamp - firstSegmentFirstTimestamp; + const difference = inputElapsed - segmentElapsed; + if (Math.abs(difference) <= Math.min(0.25, segmentElapsed)) { + return firstSegment.timestamp - firstSegmentFirstTimestamp; + } else { + return segment.timestamp - segmentFirstTimestamp; + } + } + dispose() { + for (const entry of this.inputCache) { + entry.input.dispose(); + } + this.inputCache.length = 0; + } + } + class SegmentedInputInputTrackBacking { + constructor(segmentedInput, decl, number) { + this.packetInfos = /* @__PURE__ */ new WeakMap(); + this.hydrationPromise = null; + this.firstInputTrack = null; + this.segmentedInput = segmentedInput; + this.decl = decl; + this.number = number; + } + hydrate() { + return this.hydrationPromise ?? (this.hydrationPromise = (async () => { + var _a; + (_a = this.segmentedInput).firstSegment ?? (_a.firstSegment = await this.segmentedInput.getFirstSegment({})); + if (!this.segmentedInput.firstSegment) { + throw new Error("Missing first segment, can't retrieve track."); + } + const input = this.segmentedInput.getInputForSegment(this.segmentedInput.firstSegment); + const inputTracks = await input.getTracks(); + const track = inputTracks.find((x) => x.type === this.decl.type && x.number === this.number); + if (!track) { + throw new Error("No matching track found in underlying media data."); + } + this.firstInputTrack = track; + })()); + } + getId() { + return this.decl.id; + } + getType() { + return this.decl.type; + } + getNumber() { + return this.number; + } + /** If the backing track is already present, delegate synchronously; otherwise, hydrate first. */ + delegate(fn) { + if (this.firstInputTrack) { + return fn(); + } + return this.hydrate().then(fn); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } + getHasOnlyKeyPackets() { + return this.delegate(() => this.firstInputTrack._backing.getHasOnlyKeyPackets?.() ?? null); + } + getPairingMask() { + return 1n; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getInternalCodecId() { + return this.delegate(() => this.firstInputTrack._backing.getInternalCodecId()); + } + getDisposition() { + return this.delegate(() => this.firstInputTrack._backing.getDisposition()); + } + getLanguageCode() { + return this.delegate(() => this.firstInputTrack._backing.getLanguageCode()); + } + getName() { + return this.delegate(() => this.firstInputTrack._backing.getName()); + } + getTimeResolution() { + return this.delegate(() => this.firstInputTrack._backing.getTimeResolution()); + } + async isRelativeToUnixEpoch() { + await this.hydrate(); + assert(this.segmentedInput.firstSegment); + return this.segmentedInput.firstSegment.relativeToUnixEpoch; + } + getBitrate() { + return this.delegate(() => this.firstInputTrack._backing.getBitrate()); + } + getAverageBitrate() { + return this.delegate(() => this.firstInputTrack._backing.getAverageBitrate()); + } + getDurationFromMetadata(options) { + return this.segmentedInput.getDurationFromMetadata(options); + } + getLiveRefreshInterval() { + return this.segmentedInput.getLiveRefreshInterval(); + } + async createAdjustedPacket(packet, segment, track) { + assert(packet.sequenceNumber >= 0); + assert(this.segmentedInput.firstSegment); + const mediaOffset = await this.segmentedInput.getMediaOffset(segment, track.input); + const segmentTimestampRelativeToFirst = segment.timestamp - this.segmentedInput.firstSegment.timestamp; + const modified = packet.clone({ + timestamp: roundToDivisor(packet.timestamp + mediaOffset, await track.getTimeResolution()), + // The 1e8 assumes a max of 100 MB per second, highly unlikely to be hit, so this should guarantee + // monotonically increasing sequence numbers across segments. + sequenceNumber: Math.floor(1e8 * segmentTimestampRelativeToFirst) + packet.sequenceNumber + }); + this.packetInfos.set(modified, { + segment, + track, + sourcePacket: packet + }); + return modified; + } + async getFirstPacket(options) { + await this.hydrate(); + assert(this.segmentedInput.firstSegment); + assert(this.firstInputTrack); + const packet = await this.firstInputTrack._backing.getFirstPacket(options); + if (!packet) { + return null; + } + return this.createAdjustedPacket(packet, this.segmentedInput.firstSegment, this.firstInputTrack); + } + getNextPacket(packet, options) { + return this._getNextInternal(packet, options, false); + } + getNextKeyPacket(packet, options) { + return this._getNextInternal(packet, options, true); + } + async _getNextInternal(packet, options, keyframesOnly) { + const info = this.packetInfos.get(packet); + if (!info) { + throw new Error("Packet was not created from this track."); + } + const nextPacket = keyframesOnly ? await info.track._backing.getNextKeyPacket(info.sourcePacket, options) : await info.track._backing.getNextPacket(info.sourcePacket, options); + if (nextPacket) { + return this.createAdjustedPacket(nextPacket, info.segment, info.track); + } + let currentSegment = info.segment; + while (true) { + const nextSegment = await this.segmentedInput.getNextSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + if (!nextSegment) { + return null; + } + const nextInput = this.segmentedInput.getInputForSegment(nextSegment); + const nextTracks = await nextInput.getTracks(); + const nextTrack = nextTracks.find((t) => t.type === info.track.type && t.number === info.track.number); + if (!nextTrack) { + currentSegment = nextSegment; + continue; + } + const firstPacket = await nextTrack._backing.getFirstPacket(options); + if (!firstPacket) { + return null; + } + return this.createAdjustedPacket(firstPacket, nextSegment, nextTrack); + } + } + getPacket(timestamp, options) { + return this._getPacketInternal(timestamp, options, false); + } + getKeyPacket(timestamp, options) { + return this._getPacketInternal(timestamp, options, true); + } + async _getPacketInternal(timestamp, options, keyframesOnly) { + let currentSegment = await this.segmentedInput.getSegmentAt(timestamp, { + skipLiveWait: options.skipLiveWait + }); + if (!currentSegment) { + return null; + } + await this.hydrate(); + while (currentSegment) { + const input = this.segmentedInput.getInputForSegment(currentSegment); + const tracks = await input.getTracks(); + const track = tracks.find((t) => t.type === this.firstInputTrack.type && t.number === this.firstInputTrack.number); + if (!track) { + currentSegment = await this.segmentedInput.getPreviousSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + continue; + } + const mediaOffset = await this.segmentedInput.getMediaOffset(currentSegment, input); + const offsetTimestamp = timestamp - mediaOffset; + const packet = keyframesOnly ? await track._backing.getKeyPacket(offsetTimestamp, options) : await track._backing.getPacket(offsetTimestamp, options); + if (!packet) { + currentSegment = await this.segmentedInput.getPreviousSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + continue; + } + return this.createAdjustedPacket(packet, currentSegment, track); + } + return null; + } + } + class SegmentedInputInputVideoTrackBacking extends SegmentedInputInputTrackBacking { + getType() { + return "video"; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getCodedWidth() { + return this.delegate(() => this.firstInputTrack._backing.getCodedWidth()); + } + getCodedHeight() { + return this.delegate(() => this.firstInputTrack._backing.getCodedHeight()); + } + getSquarePixelWidth() { + return this.delegate(() => this.firstInputTrack._backing.getSquarePixelWidth()); + } + getSquarePixelHeight() { + return this.delegate(() => this.firstInputTrack._backing.getSquarePixelHeight()); + } + getRotation() { + return this.delegate(() => this.firstInputTrack._backing.getRotation()); + } + async getColorSpace() { + return this.delegate(() => this.firstInputTrack._backing.getColorSpace()); + } + async canBeTransparent() { + return this.delegate(() => this.firstInputTrack._backing.canBeTransparent()); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } + } + class SegmentedInputInputAudioTrackBacking extends SegmentedInputInputTrackBacking { + getType() { + return "audio"; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getNumberOfChannels() { + return this.delegate(() => this.firstInputTrack._backing.getNumberOfChannels()); + } + getSampleRate() { + return this.delegate(() => this.firstInputTrack._backing.getSampleRate()); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } + } + new Proxy({}, { + get(_, key) { + throw new Error(`Module "" has been externalized for browser compatibility. Cannot access ".${key}" in client code. See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.`); + } + }); + polyfillSymbolDispose(); + const DEFAULT_MIN_READ_POSITION = 0; + const DEFAULT_MAX_READ_POSITION = Infinity; + class Source extends EventEmitter { + constructor() { + super(...arguments); + this._disposed = false; + this._refCount = 0; + this._usedForHls = false; + this._sizePromise = null; + this.onread = null; + } + /** + * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call + * will retrieve the size. + * + * Returns null if the source is unsized. + */ + async getSizeOrNull() { + if (this._disposed) { + throw new InputDisposedError(); + } + return this._sizePromise ?? (this._sizePromise = (async () => { + let size = this._getFileSize(); + if (size !== void 0) { + return size; + } + await this._read(0, 1, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION); + size = this._getFileSize(); + assert(size !== void 0); + return size; + })()); + } + /** + * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call + * will retrieve the size. + * + * Throws an error if the source is unsized. + */ + async getSize() { + if (this._disposed) { + throw new InputDisposedError(); + } + const result = await this.getSizeOrNull(); + if (result === null) { + throw new Error("Cannot determine the size of an unsized source."); + } + return result; + } + /** + * Returns a new {@link RangedSource} that maps data onto this source using the given offset and length. If a length + * is not provided, the ranged source spans until the end of this source's data. + * + * Useful for reading files that are embedded within larger files. + */ + slice(offset, length) { + if (!Number.isInteger(offset) || offset < 0) { + throw new TypeError("offset must be a non-negative integer."); + } + if (length !== void 0 && (!Number.isInteger(length) || length < 0)) { + throw new TypeError("length, when provided, must be a non-negative integer."); + } + return new RangedSource(this, offset, length); + } + /** @internal */ + _dispatchRead(start, end) { + this.onread?.(start, end); + this._emit("read", { start, end }); + } + /** + * Creates a new `SourceRef` pointing to this source. You are expected to call `.free()` on said `SourceRef` when + * you're done with it. + */ + ref() { + return new SourceRef(this); + } + } + class SourceRef { + /** @internal */ + constructor(source) { + this._freed = false; + if (source._disposed) { + throw new Error("Cannot ref a disposed source."); + } + source._refCount++; + this._source = source; + } + /** The {@link Source} this ref references. Accessing this field throws an error after having freed the ref. */ + get source() { + if (!this._source) { + throw new Error("Can't get source; ref has already been freed."); + } + return this._source; + } + /** Whether or not this reference has been freed via {@link SourceRef.free}. */ + get freed() { + return this._freed; + } + /** + * Frees the ref, decrementing the source's internal reference count. If the source's internal reference count + * reaches zero, it gets disposed. To catch bugs, this method throws if the ref is already freed. + */ + free() { + if (this._freed) { + throw new Error("Illegal operation: double free on SourceRef."); + } + const source = this.source; + assert(source._refCount > 0); + source._refCount--; + if (source._refCount === 0) { + source._dispose(); + source._disposed = true; + } + this._freed = true; + this._source = null; + } + /** + * Calls {@link SourceRef.free}. + */ + [Symbol.dispose]() { + if (!this.freed) { + this.free(); + } + } + } + class PathedSource extends Source { + constructor(rootPath, requestHandler) { + if (typeof rootPath !== "string") { + throw new TypeError("rootPath must be a string."); + } + if (typeof requestHandler !== "function") { + throw new TypeError("requestHandler must be a function."); + } + super(); + this.rootPath = rootPath; + this.requestHandler = requestHandler; + } + /** @internal */ + _resolveRequest(request) { + const result = this.requestHandler(request); + const handle = (result2) => { + var _a; + if (!(result2 instanceof Source || result2 instanceof SourceRef)) { + throw new TypeError("requestHandler must return or resolve to a Source or SourceRef."); + } + const ref = result2 instanceof Source ? result2.ref() : result2; + (_a = ref.source)._usedForHls || (_a._usedForHls = this._usedForHls); + return ref; + }; + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } + } + const sourceRequestsAreEqual = (a, b) => { + return a.path === b.path; + }; + class CustomPathedSource extends PathedSource { + constructor() { + super(...arguments); + this._root = null; + this._rootRequest = null; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + if (!this._root) { + if (!this._rootRequest) { + const result = this._resolveRequest({ path: this.rootPath, isRoot: true }); + const handle = (result2) => { + const ref = result2 instanceof Source ? result2.ref() : result2; + this._root = ref; + this._rootRequest = null; + return ref; + }; + if (result instanceof Promise) { + this._rootRequest = result.then(handle); + } else { + handle(result); + assert(this._root); + } + } + if (this._rootRequest) { + return this._rootRequest.then((ref) => ref.source._read(start, end, minReadPosition, maxReadPosition)); + } + } + return this._root.source._read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + _getFileSize() { + if (this._root) { + return this._root.source._getFileSize(); + } + return void 0; + } + /** @internal */ + _dispose() { + if (this._root) { + this._root.free(); + } else if (this._rootRequest) { + void this._rootRequest.then((ref) => ref.free()); + } + } + } + class BlobSource extends Source { + /** + * Creates a new {@link BlobSource} backed by the specified + * [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). + */ + constructor(blob, options = {}) { + if (!(blob instanceof Blob)) { + throw new TypeError("blob must be a Blob."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + super(); + this._readers = /* @__PURE__ */ new WeakMap(); + this._blob = blob; + this._orchestrator = new ReadOrchestrator({ + maxCacheSize: options.maxCacheSize ?? 8 * 2 ** 20, + maxWorkerCount: 4, + runWorker: this._runWorker.bind(this), + prefetchProfile: PREFETCH_PROFILES.fileSystem + }); + this._orchestrator.fileSize = blob.size; + } + /** @internal */ + _getFileSize() { + return this._orchestrator.fileSize; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + return this._orchestrator.read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + async _runWorker(worker) { + assert(worker.strictTarget); + let reader = this._readers.get(worker); + if (reader === void 0) { + if ("stream" in this._blob && !isWebKit()) { + const slice = this._blob.slice(worker.currentPos); + reader = slice.stream().getReader(); + } else { + reader = null; + } + this._readers.set(worker, reader); + } + while (worker.currentPos < worker.targetPos && !worker.aborted) { + if (reader) { + const { done, value } = await reader.read(); + if (done) { + this._orchestrator.onWorkerFinished(worker); + throw new Error("Blob reader stopped unexpectedly before all requested data was read."); + } + if (worker.aborted) { + break; + } + this._dispatchRead(worker.currentPos, worker.currentPos + value.length); + this._orchestrator.supplyWorkerData(worker, value); + } else { + const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer(); + if (worker.aborted) { + break; + } + this._dispatchRead(worker.currentPos, worker.currentPos + data.byteLength); + this._orchestrator.supplyWorkerData(worker, new Uint8Array(data)); + } + } + this._orchestrator.signalWorkerStoppedRunning(worker); + if (worker.aborted) { + await reader?.cancel(); + } + } + /** @internal */ + _dispose() { + this._orchestrator.dispose(); + } + } + const URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20; + const DEFAULT_RETRY_DELAY = ((previousAttempts, error, src) => { + const couldBeCorsError = error instanceof Error && (error.message.includes("Failed to fetch") || error.message.includes("Load failed") || error.message.includes("NetworkError when attempting to fetch resource")); + if (couldBeCorsError) { + let originOfSrc = null; + try { + if (typeof window !== "undefined" && typeof window.location !== "undefined") { + originOfSrc = new URL(src instanceof Request ? src.url : src, window.location.href).origin; + } + } catch { + } + const isOnline = typeof navigator !== "undefined" && typeof navigator.onLine === "boolean" ? navigator.onLine : true; + if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) { + console.warn(`Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option.`); + return null; + } + } + return Math.min(2 ** (previousAttempts - 2), 16); + }); + const warnedOrigins = /* @__PURE__ */ new Set(); + class UrlSource extends PathedSource { + /** + * Creates a new {@link UrlSource} backed by the resource at the specified URL. + * + * When passing a `Request` instance, note that the `signal` and `headers.Range` options will be overridden by + * Mediabunny. If you want to cancel ongoing requests, use {@link Input.dispose}. + */ + constructor(url, options = {}) { + if (typeof url !== "string" && !(url instanceof URL) && !(typeof Request !== "undefined" && url instanceof Request)) { + throw new TypeError("url must be a string, URL or Request."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.requestInit !== void 0 && (!options.requestInit || typeof options.requestInit !== "object")) { + throw new TypeError("options.requestInit, when provided, must be an object."); + } + if (options.getRetryDelay !== void 0 && typeof options.getRetryDelay !== "function") { + throw new TypeError("options.getRetryDelay, when provided, must be a function."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + if (options.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) { + throw new TypeError("options.parallelism, when provided, must be a positive number."); + } + if (options.fetchFn !== void 0 && typeof options.fetchFn !== "function") { + throw new TypeError("options.fetchFn, when provided, must be a function."); + } + const urlString = url instanceof Request ? url.url : url instanceof URL ? url.href : url; + super(urlString, (request) => new UrlSource(request.path, this._options)); + this._fileSizeDetermined = false; + this._url = url; + this._options = options; + this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY; + const DEFAULT_PARALLELISM = 2; + this._orchestrator = new ReadOrchestrator({ + maxCacheSize: options.maxCacheSize ?? 64 * 2 ** 20, + maxWorkerCount: options.parallelism ?? DEFAULT_PARALLELISM, + runWorker: this._runWorker.bind(this), + prefetchProfile: PREFETCH_PROFILES.network + }); + } + /** @internal */ + _getFileSize() { + return this._fileSizeDetermined ? this._orchestrator.fileSize : void 0; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + return this._orchestrator.read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + async _runWorker(worker) { + while (true) { + const abortController = new AbortController(); + const response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { + headers: { + // Always sending a range request is a good way to probe if the server supports them + Range: `bytes=${worker.currentPos}-` + }, + signal: abortController.signal + }), this._getRetryDelay, () => this._disposed); + if (!response.ok) { + throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); + } + outer: if (this._orchestrator.fileSize === null) { + const contentRange = response.headers.get("Content-Range"); + if (contentRange) { + const match = /\/(\d+)/.exec(contentRange); + if (match) { + this._orchestrator.supplyFileSize(Number(match[1])); + break outer; + } + } + const contentLength = response.headers.get("Content-Length"); + if (contentLength) { + this._orchestrator.supplyFileSize(worker.currentPos + Number(contentLength)); + } + } + this._fileSizeDetermined = true; + if (response.status !== 206) { + if (!this._usedForHls) { + const url = new URL(this._url instanceof Request ? this._url.url : this._url, typeof window !== "undefined" ? window.location.href : void 0); + if (url.origin !== "null" && !(url.pathname.endsWith(".m3u8") || url.pathname.endsWith(".m3u"))) { + if (!warnedOrigins.has(url.origin)) { + console.log(this._usedForHls, this._url, url.pathname); + console.warn(`HTTP server (origin ${url.origin}) did not respond to a range request with 206 Partial Content, meaning the entire resource will now be downloaded. To enable efficient media file streaming across a network, please make sure your server supports range requests.`); + warnedOrigins.add(url.origin); + } + } + } + worker.currentPos = 0; + this._orchestrator.options.maxCacheSize = Infinity; + if (this._orchestrator.fileSize !== null) { + worker.targetPos = this._orchestrator.fileSize; + } else { + worker.targetPos = Infinity; + worker.strictTarget = false; + } + this._orchestrator.consolidateEverythingIntoOneWorker(worker); + } + if (!response.body) { + throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream."); + } + const reader = response.body.getReader(); + while (true) { + if (worker.currentPos >= worker.targetPos || worker.aborted) { + abortController.abort(); + this._orchestrator.signalWorkerStoppedRunning(worker); + return; + } + let readResult; + try { + readResult = await reader.read(); + } catch (error) { + if (this._disposed) { + throw error; + } + const retryDelayInSeconds = this._getRetryDelay(1, error, this._url); + if (retryDelayInSeconds !== null) { + console.error("Error while reading response stream. Attempting to resume.", error); + await wait(1e3 * retryDelayInSeconds); + break; + } else { + throw error; + } + } + if (worker.aborted) { + continue; + } + const { done, value } = readResult; + if (done) { + if (worker.currentPos >= worker.targetPos) { + this._orchestrator.onWorkerFinished(worker); + return; + } + if (worker.strictTarget) { + break; + } else { + this._orchestrator.onWorkerFinished(worker); + return; + } + } + this._dispatchRead(worker.currentPos, worker.currentPos + value.length); + this._orchestrator.supplyWorkerData(worker, value); + } + } + } + /** @internal */ + _dispose() { + this._orchestrator.dispose(); + } + } + class ReadableStreamSource extends Source { + /** Creates a new {@link ReadableStreamSource} backed by the specified `ReadableStream`. */ + constructor(stream, options = {}) { + if (!(stream instanceof ReadableStream)) { + throw new TypeError("stream must be a ReadableStream."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + super(); + this._reader = null; + this._cache = []; + this._pendingSlices = []; + this._currentIndex = 0; + this._targetIndex = 0; + this._maxRequestedIndex = 0; + this._endIndex = null; + this._pulling = false; + this._stream = stream; + this._maxCacheSize = options.maxCacheSize ?? 16 * 2 ** 20; + } + /** @internal */ + _getFileSize() { + return this._endIndex; + } + /** @internal */ + _read(start, end) { + if (this._endIndex !== null && end > this._endIndex) { + return null; + } + this._maxRequestedIndex = Math.max(this._maxRequestedIndex, end); + const cacheStartIndex = binarySearchLessOrEqual(this._cache, start, (x) => x.start); + const cacheStartEntry = cacheStartIndex !== -1 ? this._cache[cacheStartIndex] : null; + if (cacheStartEntry && cacheStartEntry.start <= start && end <= cacheStartEntry.end) { + return { + bytes: cacheStartEntry.bytes, + view: cacheStartEntry.view, + offset: cacheStartEntry.start + }; + } + let lastEnd = start; + const bytes = new Uint8Array(end - start); + if (cacheStartIndex !== -1) { + for (let i = cacheStartIndex; i < this._cache.length; i++) { + const cacheEntry = this._cache[i]; + if (cacheEntry.start >= end) { + break; + } + const cappedStart = Math.max(start, cacheEntry.start); + if (cappedStart > lastEnd) { + this._throwDueToCacheMiss(); + } + const cappedEnd = Math.min(end, cacheEntry.end); + if (cappedStart < cappedEnd) { + bytes.set(cacheEntry.bytes.subarray(cappedStart - cacheEntry.start, cappedEnd - cacheEntry.start), cappedStart - start); + lastEnd = cappedEnd; + } + } + } + if (lastEnd === end) { + return { + bytes, + view: toDataView(bytes), + offset: start + }; + } + if (this._currentIndex > lastEnd) { + this._throwDueToCacheMiss(); + } + const { promise, resolve, reject } = promiseWithResolvers(); + this._pendingSlices.push({ + start, + end, + bytes, + resolve, + reject + }); + this._targetIndex = Math.max(this._targetIndex, end); + if (!this._pulling) { + this._pulling = true; + void this._pull().catch((error) => { + this._pulling = false; + if (this._pendingSlices.length > 0) { + this._pendingSlices.forEach((x) => x.reject(error)); + this._pendingSlices.length = 0; + } else { + throw error; + } + }); + } + return promise; + } + /** @internal */ + _throwDueToCacheMiss() { + throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache."); + } + /** @internal */ + async _pull() { + this._reader ?? (this._reader = this._stream.getReader()); + while (this._currentIndex < this._targetIndex && !this._disposed) { + const { done, value } = await this._reader.read(); + if (done) { + for (const pendingSlice of this._pendingSlices) { + pendingSlice.resolve(null); + } + this._pendingSlices.length = 0; + this._endIndex = this._currentIndex; + break; + } + const startIndex = this._currentIndex; + const endIndex = this._currentIndex + value.byteLength; + for (let i = 0; i < this._pendingSlices.length; i++) { + const pendingSlice = this._pendingSlices[i]; + const cappedStart = Math.max(startIndex, pendingSlice.start); + const cappedEnd = Math.min(endIndex, pendingSlice.end); + if (cappedStart < cappedEnd) { + pendingSlice.bytes.set(value.subarray(cappedStart - startIndex, cappedEnd - startIndex), cappedStart - pendingSlice.start); + if (cappedEnd === pendingSlice.end) { + pendingSlice.resolve({ + bytes: pendingSlice.bytes, + view: toDataView(pendingSlice.bytes), + offset: pendingSlice.start + }); + this._pendingSlices.splice(i, 1); + i--; + } + } + } + this._cache.push({ + start: startIndex, + end: endIndex, + bytes: value, + view: toDataView(value), + age: 0 + // Unused + }); + while (this._cache.length > 0) { + const firstEntry = this._cache[0]; + const distance = this._maxRequestedIndex - firstEntry.end; + if (distance <= this._maxCacheSize) { + break; + } + this._cache.shift(); + } + this._currentIndex += value.byteLength; + } + this._pulling = false; + } + /** @internal */ + _dispose() { + this._pendingSlices.length = 0; + this._cache.length = 0; + void this._reader?.cancel(); + } + } + const PREFETCH_PROFILES = { + fileSystem: (start, end) => { + const padding = 2 ** 16; + start = Math.floor((start - padding) / padding) * padding; + end = Math.ceil((end + padding) / padding) * padding; + return { start, end }; + }, + network: (start, end, workers) => { + const paddingStart = 2 ** 16; + start = Math.max(0, Math.floor((start - paddingStart) / paddingStart) * paddingStart); + for (const worker of workers) { + const maxExtensionAmount = 8 * 2 ** 20; + const thresholdPoint = Math.max((worker.startPos + worker.targetPos) / 2, worker.targetPos - maxExtensionAmount); + if (closedIntervalsOverlap(start, end, thresholdPoint, worker.targetPos)) { + const size = worker.targetPos - worker.startPos; + const a = Math.ceil((size + 1) / maxExtensionAmount) * maxExtensionAmount; + const b = 2 ** Math.ceil(Math.log2(size + 1)); + const extent = Math.min(b, a); + end = Math.max(end, worker.startPos + extent); + } + } + end = Math.max(end, start + URL_SOURCE_MIN_LOAD_AMOUNT); + return { + start, + end + }; + } + }; + class ReadOrchestrator { + constructor(options) { + this.options = options; + this.fileSize = null; + this.nextAge = 0; + this.workers = []; + this.cache = []; + this.currentCacheSize = 0; + this.disposed = false; + this.queuedReads = []; + } + read(innerStart, innerEnd, minReadPosition, maxReadPosition) { + assert(!this.disposed); + const prefetchRange = this.options.prefetchProfile(innerStart, innerEnd, this.workers); + const outerStart = Math.max(prefetchRange.start, minReadPosition); + const outerEnd = Math.min(prefetchRange.end, this.fileSize ?? Infinity, maxReadPosition); + assert(outerStart <= innerStart && innerEnd <= outerEnd); + let result = null; + const innerCacheStartIndex = binarySearchLessOrEqual(this.cache, innerStart, (x) => x.start); + const innerStartEntry = innerCacheStartIndex !== -1 ? this.cache[innerCacheStartIndex] : null; + if (innerStartEntry && innerStartEntry.start <= innerStart && innerEnd <= innerStartEntry.end) { + innerStartEntry.age = this.nextAge++; + result = { + bytes: innerStartEntry.bytes, + view: innerStartEntry.view, + offset: innerStartEntry.start + }; + } + const outerCacheStartIndex = binarySearchLessOrEqual(this.cache, outerStart, (x) => x.start); + const bytes = result ? null : new Uint8Array(innerEnd - innerStart); + let contiguousBytesWriteEnd = 0; + let lastEnd = outerStart; + const outerHoles = []; + if (outerCacheStartIndex !== -1) { + for (let i = outerCacheStartIndex; i < this.cache.length; i++) { + const entry = this.cache[i]; + if (entry.start >= outerEnd) { + break; + } + if (entry.end <= outerStart) { + continue; + } + const cappedOuterStart = Math.max(outerStart, entry.start); + const cappedOuterEnd = Math.min(outerEnd, entry.end); + assert(cappedOuterStart <= cappedOuterEnd); + if (lastEnd < cappedOuterStart) { + outerHoles.push({ start: lastEnd, end: cappedOuterStart }); + } + lastEnd = cappedOuterEnd; + if (bytes) { + const cappedInnerStart = Math.max(innerStart, entry.start); + const cappedInnerEnd = Math.min(innerEnd, entry.end); + if (cappedInnerStart < cappedInnerEnd) { + const relativeOffset = cappedInnerStart - innerStart; + bytes.set(entry.bytes.subarray(cappedInnerStart - entry.start, cappedInnerEnd - entry.start), relativeOffset); + if (relativeOffset === contiguousBytesWriteEnd) { + contiguousBytesWriteEnd = cappedInnerEnd - innerStart; + } + } + } + entry.age = this.nextAge++; + } + if (lastEnd < outerEnd) { + outerHoles.push({ start: lastEnd, end: outerEnd }); + } + } else { + outerHoles.push({ start: outerStart, end: outerEnd }); + } + if (bytes && contiguousBytesWriteEnd >= bytes.length) { + result = { + bytes, + view: toDataView(bytes), + offset: innerStart + }; + } + if (outerHoles.length === 0) { + assert(result); + return result; + } + const { promise, resolve, reject } = promiseWithResolvers(); + const innerHoles = []; + for (const outerHole of outerHoles) { + const cappedStart = Math.max(innerStart, outerHole.start); + const cappedEnd = Math.min(innerEnd, outerHole.end); + if (cappedStart === outerHole.start && cappedEnd === outerHole.end) { + innerHoles.push(outerHole); + } else if (cappedStart < cappedEnd) { + innerHoles.push({ start: cappedStart, end: cappedEnd }); + } + } + const pendingSlice = bytes && { + start: innerStart, + bytes, + holes: innerHoles, + resolve, + reject + }; + outer: for (const outerHole of outerHoles) { + for (const worker of this.workers) { + const addedToWorker = this.checkHoleAgainstWorker(worker, outerHole, pendingSlice ? [pendingSlice] : []); + if (addedToWorker) { + this.checkQueuedReadsAgainstWorker(worker); + continue outer; + } + } + const strictTarget = outerHole.end < outerEnd || this.fileSize !== null; + const newWorker = this.createWorker(outerHole.start, outerHole.end, strictTarget); + if (newWorker) { + if (pendingSlice) { + newWorker.pendingSlices = [pendingSlice]; + } + this.runWorker(newWorker); + } else { + let index = binarySearchLessOrEqual(this.queuedReads, outerHole.start, (x) => x.hole.start); + let entry = index !== -1 ? this.queuedReads[index] : null; + if (entry && outerHole.start <= entry.hole.end) { + entry.hole.end = Math.max(entry.hole.end, outerHole.end); + entry.strictTarget && (entry.strictTarget = strictTarget); + if (pendingSlice) { + entry.pendingSlices.push(pendingSlice); + } + } else { + index++; + entry = { + hole: { + // Clone the hole because it might be mutated later + start: outerHole.start, + end: outerHole.end + }, + strictTarget, + pendingSlices: pendingSlice ? [pendingSlice] : [], + age: this.nextAge++ + }; + this.queuedReads.splice(index, 0, entry); + } + while (index + 1 < this.queuedReads.length) { + const nextEntry = this.queuedReads[index + 1]; + if (nextEntry.hole.start > entry.hole.end) { + break; + } + entry.hole.end = Math.max(entry.hole.end, nextEntry.hole.end); + entry.pendingSlices.push(...nextEntry.pendingSlices); + entry.strictTarget && (entry.strictTarget = nextEntry.strictTarget); + entry.age = Math.min(entry.age, nextEntry.age); + this.queuedReads.splice(index + 1, 1); + } + } + } + if (!result) { + assert(bytes); + result = promise.then((bytes2) => bytes2 && { + bytes: bytes2, + view: toDataView(bytes2), + offset: innerStart + }); + } + return result; + } + checkHoleAgainstWorker(worker, hole, pendingSlices) { + const gapTolerance = 2 ** 17; + if (closedIntervalsOverlap(hole.start - gapTolerance, hole.start, worker.currentPos, worker.targetPos)) { + worker.targetPos = Math.max(worker.targetPos, hole.end); + for (let i = 0; i < pendingSlices.length; i++) { + const pendingSlice = pendingSlices[i]; + if (!worker.pendingSlices.includes(pendingSlice)) { + worker.pendingSlices.push(pendingSlice); + } + } + if (!worker.running) { + this.runWorker(worker); + } + return true; + } + return false; + } + checkQueuedReadsAgainstWorker(worker) { + let wasTrueOnce = false; + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + const result = this.checkHoleAgainstWorker(worker, queuedRead.hole, queuedRead.pendingSlices); + if (result) { + this.queuedReads.splice(i, 1); + i--; + wasTrueOnce = true; + } else if (wasTrueOnce) { + break; + } + } + } + createWorker(startPos, targetPos, strictTarget) { + if (this.workers.length >= this.options.maxWorkerCount) { + let oldestWorker = null; + let oldestIndex = null; + for (let i = 0; i < this.workers.length; i++) { + const worker2 = this.workers[i]; + if (!worker2.running && worker2.pendingSlices.length === 0 && (!oldestWorker || worker2.age < oldestWorker.age)) { + oldestIndex = i; + oldestWorker = worker2; + } + } + if (oldestWorker) { + assert(oldestIndex !== null); + assert(oldestWorker.pendingSlices.length === 0); + this.workers.splice(oldestIndex, 1); + } else { + return null; + } + } + const worker = { + startPos, + currentPos: startPos, + targetPos, + strictTarget, + running: false, + // Due to async shenanigans, it can happen that workers are started after disposal. In this case, instead of + // simply not creating the worker, we allow it to run but immediately label it as aborted, so it can then + // shut itself down. + aborted: this.disposed, + pendingSlices: [], + age: this.nextAge++ + }; + this.workers.push(worker); + return worker; + } + runWorker(worker) { + assert(!worker.running); + assert(worker.currentPos < worker.targetPos); + worker.running = true; + worker.age = this.nextAge++; + void this.options.runWorker(worker).catch((error) => { + worker.running = false; + if (worker.pendingSlices.length > 0) { + worker.pendingSlices.forEach((x) => x.reject(error)); + worker.pendingSlices.length = 0; + } else { + throw error; + } + }).finally(() => { + if (worker.running) { + return; + } + if (this.queuedReads.length > 0) { + let oldestIndex = 0; + for (let i = 1; i < this.queuedReads.length; i++) { + const queuedRead2 = this.queuedReads[i]; + if (queuedRead2.age < this.queuedReads[oldestIndex].age) { + oldestIndex = i; + } + } + const queuedRead = this.queuedReads[oldestIndex]; + this.queuedReads.splice(oldestIndex, 1); + const newWorker = this.createWorker(queuedRead.hole.start, queuedRead.hole.end, queuedRead.strictTarget); + assert(newWorker); + newWorker.pendingSlices = queuedRead.pendingSlices; + this.runWorker(newWorker); + } + }); + } + consolidateEverythingIntoOneWorker(worker) { + const uniqueSlices = new Set(worker.pendingSlices); + for (let i = 0; i < this.workers.length; i++) { + const otherWorker = this.workers[i]; + if (otherWorker === worker) { + continue; + } + for (const slice of otherWorker.pendingSlices) { + uniqueSlices.add(slice); + } + otherWorker.aborted = true; + otherWorker.pendingSlices.length = 0; + this.workers.splice(i, 1); + i--; + } + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + for (const slice of queuedRead.pendingSlices) { + uniqueSlices.add(slice); + } + } + worker.pendingSlices = [...uniqueSlices]; + this.queuedReads.length = 0; + } + /** Called by a worker when it has read some data. */ + supplyWorkerData(worker, bytes) { + assert(!worker.aborted); + const start = worker.currentPos; + const end = start + bytes.length; + this.insertIntoCache({ + start, + end, + bytes, + view: toDataView(bytes), + age: this.nextAge++ + }); + worker.currentPos += bytes.length; + if (worker.currentPos > worker.targetPos) { + worker.targetPos = worker.currentPos; + this.checkQueuedReadsAgainstWorker(worker); + } + for (let i = 0; i < worker.pendingSlices.length; i++) { + const pendingSlice = worker.pendingSlices[i]; + const clampedStart = Math.max(start, pendingSlice.start); + const clampedEnd = Math.min(end, pendingSlice.start + pendingSlice.bytes.length); + if (clampedStart < clampedEnd) { + pendingSlice.bytes.set(bytes.subarray(clampedStart - start, clampedEnd - start), clampedStart - pendingSlice.start); + } + for (let j = 0; j < pendingSlice.holes.length; j++) { + const hole = pendingSlice.holes[j]; + if (start <= hole.start && end > hole.start) { + hole.start = end; + } + if (hole.end <= hole.start) { + pendingSlice.holes.splice(j, 1); + j--; + } + } + if (pendingSlice.holes.length === 0) { + pendingSlice.resolve(pendingSlice.bytes); + worker.pendingSlices.splice(i, 1); + i--; + } + } + for (let i = 0; i < this.workers.length; i++) { + const otherWorker = this.workers[i]; + if (worker === otherWorker || otherWorker.running) { + continue; + } + if (closedIntervalsOverlap(start, end, otherWorker.currentPos, otherWorker.targetPos)) { + this.workers.splice(i, 1); + i--; + } + } + } + supplyFileSize(size) { + assert(this.fileSize === null); + this.fileSize = size; + for (const worker of this.workers) { + worker.targetPos = Math.min(worker.targetPos, size); + worker.strictTarget = true; + for (let i = 0; i < worker.pendingSlices.length; i++) { + const pendingSlice = worker.pendingSlices[i]; + for (const hole of pendingSlice.holes) { + if (hole.end > size) { + pendingSlice.resolve(null); + worker.pendingSlices.splice(i, 1); + i--; + break; + } + } + } + } + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + if (queuedRead.hole.start >= size) { + for (const slice of queuedRead.pendingSlices) + slice.resolve(null); + this.queuedReads.splice(i, 1); + i--; + } else if (queuedRead.hole.end > size) { + queuedRead.hole.end = size; + queuedRead.strictTarget = true; + for (let j = 0; j < queuedRead.pendingSlices.length; j++) { + const slice = queuedRead.pendingSlices[j]; + if (slice.start >= size) { + slice.resolve(null); + queuedRead.pendingSlices.splice(j, 1); + j--; + } + } + } + } + } + signalWorkerStoppedRunning(worker) { + worker.running = false; + worker.pendingSlices.length = 0; + } + /** Called when a worker reaches the end of the underlying data and must be cleaned up. */ + onWorkerFinished(worker) { + const index = this.workers.indexOf(worker); + assert(index !== -1); + worker.running = false; + this.workers.splice(index, 1); + if (this.fileSize === null) { + this.supplyFileSize(worker.currentPos); + } + for (const pendingSlice of worker.pendingSlices) { + pendingSlice.resolve(null); + } + } + insertIntoCache(entry) { + if (this.options.maxCacheSize === 0) { + return; + } + let insertionIndex = binarySearchLessOrEqual(this.cache, entry.start, (x) => x.start) + 1; + if (insertionIndex > 0) { + const previous = this.cache[insertionIndex - 1]; + if (previous.end >= entry.end) { + return; + } + if (previous.end > entry.start) { + const joined = new Uint8Array(entry.end - previous.start); + joined.set(previous.bytes, 0); + joined.set(entry.bytes, entry.start - previous.start); + this.currentCacheSize += entry.end - previous.end; + previous.bytes = joined; + previous.view = toDataView(joined); + previous.end = entry.end; + insertionIndex--; + entry = previous; + } else { + this.cache.splice(insertionIndex, 0, entry); + this.currentCacheSize += entry.bytes.length; + } + } else { + this.cache.splice(insertionIndex, 0, entry); + this.currentCacheSize += entry.bytes.length; + } + for (let i = insertionIndex + 1; i < this.cache.length; i++) { + const next = this.cache[i]; + if (entry.end <= next.start) { + break; + } + if (entry.end >= next.end) { + this.cache.splice(i, 1); + this.currentCacheSize -= next.bytes.length; + i--; + continue; + } + const joined = new Uint8Array(next.end - entry.start); + joined.set(entry.bytes, 0); + joined.set(next.bytes, next.start - entry.start); + this.currentCacheSize -= entry.end - next.start; + entry.bytes = joined; + entry.view = toDataView(joined); + entry.end = next.end; + this.cache.splice(i, 1); + break; + } + while (this.currentCacheSize > this.options.maxCacheSize) { + let oldestIndex = 0; + let oldestEntry = this.cache[0]; + for (let i = 1; i < this.cache.length; i++) { + const entry2 = this.cache[i]; + if (entry2.age < oldestEntry.age) { + oldestIndex = i; + oldestEntry = entry2; + } + } + if (this.currentCacheSize - oldestEntry.bytes.length <= this.options.maxCacheSize) { + break; + } + this.cache.splice(oldestIndex, 1); + this.currentCacheSize -= oldestEntry.bytes.length; + } + } + dispose() { + for (const worker of this.workers) { + worker.aborted = true; + } + this.workers.length = 0; + this.cache.length = 0; + this.disposed = true; + } + } + class RangedSource extends Source { + /** @internal */ + constructor(baseSource, offset, length) { + super(); + this._ref = null; + if (baseSource._disposed) { + throw new Error("Cannot create a slice of a disposed source."); + } + this._baseSource = baseSource; + this._offset = offset; + this._length = length ?? null; + } + /** @internal */ + _getFileSize() { + const baseSize = this._baseSource._getFileSize(); + if (baseSize === void 0) { + return this._length !== null ? this._length : void 0; + } + if (baseSize === null) { + if (this._length !== null) { + return this._length; + } else { + return null; + } + } + return clamp$1(baseSize - this._offset, 0, this._length ?? Infinity); + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + if (this._length !== null && end > this._length) { + return null; + } + const result = this._baseSource._read(this._offset + start, this._offset + end, this._offset + minReadPosition, this._offset + maxReadPosition); + if (result instanceof Promise) { + return result.then((result2) => { + if (!result2) { + return null; + } + result2.offset -= this._offset; + return result2; + }); + } else { + if (!result) { + return null; + } + result.offset -= this._offset; + return result; + } + } + /** @internal */ + _dispose() { + this._ref?.free(); + } + ref() { + this._ref ?? (this._ref = this._baseSource.ref()); + return super.ref(); + } + } + var __addDisposableResource = function(env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose, inner; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + if (async) inner = dispose; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + if (inner) dispose = function() { + try { + inner.call(this); + } catch (e) { + return Promise.reject(e); + } + }; + env.stack.push({ value, dispose, async }); + } else if (async) { + env.stack.push({ async: true }); + } + return value; + }; + var __disposeResources = /* @__PURE__ */ (function(SuppressedError2) { + return function(env) { + function fail(e) { + env.error = env.hasError ? new SuppressedError2(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + var r, s = 0; + function next() { + while (r = env.stack.pop()) { + try { + if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); + if (r.dispose) { + var result = r.dispose.call(r.value); + if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { + fail(e); + return next(); + }); + } else s |= 1; + } catch (e) { + fail(e); + } + } + if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); + if (env.hasError) throw env.error; + } + return next(); + }; + })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; + }); + const IV_STRING_REGEX = /^0[xX][0-9a-fA-F]+$/; + const BASE64_DATA_URI_REGEX = /^data:.*;base64,/i; + class HlsSegmentedInput extends SegmentedInput { + constructor(demuxer, path, trackDeclarations, lines) { + super(demuxer.input, path, trackDeclarations); + this.segments = []; + this.nextLines = null; + this.currentUpdateSegmentsPromise = null; + this.streamHasEnded = false; + this.lastSegmentUpdateTime = -Infinity; + this.refreshInterval = 5; + this.demuxer = demuxer; + this.nextLines = lines; + } + runUpdateSegments() { + return this.currentUpdateSegmentsPromise ?? (this.currentUpdateSegmentsPromise = (async () => { + try { + const remainingWaitTimeMs = this.getRemainingWaitTimeMs(); + if (remainingWaitTimeMs > 0) { + await wait(remainingWaitTimeMs); + } + this.lastSegmentUpdateTime = performance.now(); + await this.updateSegments(); + } finally { + this.currentUpdateSegmentsPromise = null; + } + })()); + } + getRemainingWaitTimeMs() { + const elapsed = performance.now() - this.lastSegmentUpdateTime; + const result = Math.max(0, 1e3 * this.refreshInterval - elapsed); + if (result <= 50) { + return 0; + } + return result; + } + /** + * Reads and parses the segment info from the playlist file. When called more than one, it updates the existing + * segments by appending the new ones. Existing segments are never removed. + */ + async updateSegments() { + let lines = this.nextLines; + this.nextLines = null; + if (!lines) { + const env_1 = { stack: [], error: void 0, hasError: false }; + try { + const ref = __addDisposableResource(env_1, await this.demuxer.input._getSourceUncached({ path: this.path, isRoot: false }), false); + const reader = new Reader(ref.source); + const slice = await reader.requestEntireFile(); + assert(slice); + lines = readAllLines(slice, slice.length, { ignore: canIgnoreLine }); + } catch (e_1) { + env_1.error = e_1; + env_1.hasError = true; + } finally { + __disposeResources(env_1); + } + } + let headerRead = false; + let accumulatedTime = 0; + let nextSegmentDuration = null; + let currentKey = null; + let nextSequenceNumber = 0; + let currentFirstSegment = null; + let currentInitSegment = null; + let lastByteRangeEnd = null; + let nextByteRange = null; + let lastProgramDateTimeSeconds = null; + let targetDuration = null; + let segmentSeen = false; + let prevLastSegment = last(this.segments) ?? null; + const parseByteRange = (content) => { + const atIndex = content.indexOf("@"); + const length = Number(atIndex === -1 ? content : content.slice(0, atIndex)); + if (!Number.isInteger(length) || length < 0) { + throw new Error(`Invalid #EXT-X-BYTERANGE length '${content}'.`); + } + let offset = null; + if (atIndex !== -1) { + offset = Number(content.slice(atIndex + 1)); + if (!Number.isInteger(offset) || offset < 0) { + throw new Error(`Invalid #EXT-X-BYTERANGE offset '${content}'.`); + } + } + return { length, offset }; + }; + const setNextSequenceNumber = (number) => { + nextSequenceNumber = number; + if (prevLastSegment) { + assert(prevLastSegment.sequenceNumber !== null); + if (prevLastSegment.sequenceNumber < number) { + accumulatedTime = prevLastSegment.timestamp + prevLastSegment.duration; + currentFirstSegment = prevLastSegment.firstSegment; + currentInitSegment = prevLastSegment.initSegment; + lastProgramDateTimeSeconds = prevLastSegment.lastProgramDateTimeSeconds; + prevLastSegment = null; + } + } + }; + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!headerRead) { + if (line !== "#EXTM3U") { + throw new Error("Invalid M3U8 file; expected first line to be #EXTM3U."); + } + headerRead = true; + continue; + } + if (!line.startsWith("#")) { + if (!prevLastSegment) { + if (nextSegmentDuration === null) { + throw new Error("Invalid M3U8 file; a segment must be preceded by an #EXTINF tag."); + } + let key = currentKey; + if (key && key.method === "AES-128" && !key.iv) { + const iv = new Uint8Array(AES_128_BLOCK_SIZE); + const view = toDataView(iv); + view.setUint32(8, Math.floor(nextSequenceNumber / 2 ** 32)); + view.setUint32(12, nextSequenceNumber); + key = { ...key, iv }; + } + const fullPath = joinPaths(this.path, line); + const location = { + path: fullPath, + offset: nextByteRange?.offset ?? 0, + length: nextByteRange?.length ?? null + }; + const segment = { + timestamp: accumulatedTime, + relativeToUnixEpoch: lastProgramDateTimeSeconds !== null, + firstSegment: currentFirstSegment, + sequenceNumber: nextSequenceNumber, + location, + duration: nextSegmentDuration, + encryption: key, + initSegment: currentInitSegment, + lastProgramDateTimeSeconds + }; + currentFirstSegment ?? (currentFirstSegment = segment); + accumulatedTime += nextSegmentDuration; + this.segments.push(segment); + } + nextSegmentDuration = null; + if (nextByteRange === null) { + lastByteRangeEnd = null; + } else { + nextByteRange = null; + } + setNextSequenceNumber(nextSequenceNumber + 1); + } + if (line.startsWith(TAG_EXTINF)) { + if (prevLastSegment) { + segmentSeen = true; + continue; + } + if (!segmentSeen) { + if (lastProgramDateTimeSeconds === null && nextSequenceNumber > 0 && targetDuration !== null) { + accumulatedTime = nextSequenceNumber * targetDuration; + } + segmentSeen = true; + } + const extinfContent = line.slice(TAG_EXTINF.length); + const commaIndex = extinfContent.indexOf(","); + const durationStr = commaIndex === -1 ? extinfContent : extinfContent.slice(0, commaIndex); + const duration = Number(durationStr); + if (!Number.isFinite(duration) || duration < 0) { + throw new Error(`Invalid #EXTINF tag duration '${durationStr}'.`); + } + nextSegmentDuration = duration; + } else if (line.startsWith(TAG_MAP)) { + const attributes = new AttributeList(line.slice(TAG_MAP.length)); + const uri = attributes.get("uri"); + if (!uri) { + throw new Error("Invalid #EXT-X-MAP tag; missing URI attribute."); + } + const byteRange = attributes.get("byterange"); + let parsedByteRange = null; + if (byteRange !== null) { + parsedByteRange = parseByteRange(byteRange); + } + if (parsedByteRange && parsedByteRange.offset === null) { + throw new Error("Invalid #EXT-X-MAP tag; BYTERANGE attribute must have a specified offset."); + } + if (!prevLastSegment) { + const fullPath = joinPaths(this.path, uri); + const location = { + path: fullPath, + offset: parsedByteRange?.offset ?? 0, + length: parsedByteRange?.length ?? null + }; + if (currentKey?.method === "AES-128" && !currentKey.iv) { + throw new Error("IV attribute must be set on #EXT-X-KEY tag preceding the #EXT-X-MAP tag."); + } + const segment = { + timestamp: accumulatedTime, + relativeToUnixEpoch: lastProgramDateTimeSeconds !== null, + firstSegment: null, + sequenceNumber: null, + location, + duration: 0, + encryption: currentKey, + initSegment: null, + lastProgramDateTimeSeconds + }; + currentInitSegment = segment; + } + nextSegmentDuration = null; + if (nextByteRange === null) { + lastByteRangeEnd = null; + } else { + nextByteRange = null; + } + } else if (line.startsWith(TAG_KEY)) { + const attributes = new AttributeList(line.slice(TAG_KEY.length)); + const method = attributes.get("method"); + if (method === "NONE") { + currentKey = null; + } else if (method === "AES-128") { + const uri = attributes.get("uri"); + if (!uri) { + throw new Error("Invalid #EXT-X-KEY: AES-128 requires a URI attribute."); + } + let iv = null; + const ivString = attributes.get("iv"); + if (ivString) { + if (!IV_STRING_REGEX.test(ivString)) { + throw new Error(`Unsupported IV format '${ivString}'.`); + } + let hex = ivString.slice(2); + hex = hex.padStart(AES_128_BLOCK_SIZE * 2, "0"); + iv = new Uint8Array(AES_128_BLOCK_SIZE); + for (let i2 = 0; i2 < AES_128_BLOCK_SIZE; i2++) { + const startIndex = -AES_128_BLOCK_SIZE * 2 + i2; + iv[i2] = parseInt(hex.slice(startIndex, startIndex + 2), 16); + } + } + const keyFormat = attributes.get("keyformat") ?? "identity"; + if (keyFormat !== "identity") { + throw new Error("For AES-128 encryption, only the 'identity' KEYFORMAT is currently supported. If you think other formats should be supported, please raise an issue."); + } + currentKey = { + method: "AES-128", + keyUri: joinPaths(this.path, uri), + iv, + keyFormat + }; + } else if (method === "SAMPLE-AES" || method === "SAMPLE-AES-CTR") { + const uri = attributes.get("uri"); + if (!uri) { + throw new Error(`Invalid #EXT-X-KEY: ${method} requires a URI attribute.`); + } + const keyFormat = attributes.get("keyformat") ?? "identity"; + if (keyFormat === "identity") { + throw new Error("For SAMPLE-AES and SAMPLE-AES-CTR encryption, the 'identity' KEYFORMAT is not supported. If you think this format should be supported, please raise an issue."); + } + let psshBox = null; + if (BASE64_DATA_URI_REGEX.test(uri)) { + const commaIndex = uri.indexOf(","); + const bytes = base64ToBytes(uri.slice(commaIndex + 1)); + if (bytes.length >= 8 && bytes[4] === 112 && bytes[5] === 115 && bytes[6] === 115 && bytes[7] === 104) { + const size = toDataView(bytes).getUint32(0); + psshBox = parsePsshBoxContents(bytes.subarray(8, Math.min(size, bytes.length))); + } + } + currentKey = { + method, + psshBox + }; + } else { + throw new Error(`Unsupported encryption method '${method}'. If you think this method should be supported, please raise an issue.`); + } + } else if (line.startsWith(TAG_MEDIA_SEQUENCE)) { + const value = line.slice(TAG_MEDIA_SEQUENCE.length); + const number = Number(value); + if (!Number.isInteger(number) || number < 0) { + throw new Error(`Invalid EXT-X-MEDIA-SEQUENCE value '${value}'.`); + } + setNextSequenceNumber(number); + } else if (line.startsWith(TAG_BYTERANGE)) { + const parsed = parseByteRange(line.slice(TAG_BYTERANGE.length)); + if (parsed.offset === null) { + if (lastByteRangeEnd === null) { + throw new Error("Invalid M3U8 file; #EXT-X-BYTERANGE without offset requires a previous byte range."); + } + parsed.offset = lastByteRangeEnd; + } + nextByteRange = parsed; + lastByteRangeEnd = parsed.offset + parsed.length; + } else if (line.startsWith(TAG_PROGRAM_DATE_TIME)) { + if (prevLastSegment) { + continue; + } + const dateTime = line.slice(TAG_PROGRAM_DATE_TIME.length); + const dateTimeMs = Date.parse(dateTime); + if (!Number.isFinite(dateTimeMs)) { + continue; + } + const dateTimeSeconds = dateTimeMs / 1e3; + if (lastProgramDateTimeSeconds === dateTimeSeconds) { + continue; + } + if (lastProgramDateTimeSeconds === null && this.segments.length > 0) { + const lastSegment = last(this.segments); + const lastSegmentEnd = lastSegment.timestamp + lastSegment.duration; + const offset = dateTimeSeconds - lastSegmentEnd; + for (const segment of this.segments) { + segment.timestamp += offset; + segment.relativeToUnixEpoch = true; + } + accumulatedTime += offset; + } + lastProgramDateTimeSeconds = dateTimeSeconds; + accumulatedTime = dateTimeSeconds; + } else if (line === TAG_DISCONTINUITY) { + currentFirstSegment = null; + } else if (line.startsWith(TAG_TARGETDURATION)) { + const value = line.slice(TAG_TARGETDURATION.length); + const duration = Number(value); + if (!Number.isFinite(duration) || duration < 0) { + throw new Error(`Invalid EXT-X-TARGETDURATION value '${value}'.`); + } + this.refreshInterval = duration; + targetDuration = duration; + } else if (line === TAG_ENDLIST) { + this.streamHasEnded = true; + break; + } else if (line.startsWith(TAG_PLAYLIST_TYPE)) { + const type = line.slice(TAG_PLAYLIST_TYPE.length); + if (type.toLowerCase() === "vod") { + this.streamHasEnded = true; + } + } + } + if (!headerRead) { + throw new Error("Invalid M3U8 file; no #EXTM3U header."); + } + } + async getFirstSegment() { + if (this.segments.length === 0) { + await this.runUpdateSegments(); + } + return this.segments[0] ?? null; + } + async getSegmentAt(timestamp, options) { + if (this.segments.length === 0) { + await this.runUpdateSegments(); + } + let isLazy = !!options.skipLiveWait && this.getRemainingWaitTimeMs() > 0; + while (true) { + const index = binarySearchLessOrEqual(this.segments, timestamp, (x) => x.timestamp); + if (index === -1) { + return null; + } + if (index < this.segments.length - 1 || this.streamHasEnded || isLazy) { + return this.segments[index]; + } + const segment = this.segments[index]; + if (timestamp < segment.timestamp + segment.duration) { + return segment; + } + await this.runUpdateSegments(); + if (options.skipLiveWait) { + isLazy = true; + } + } + } + async getNextSegment(segment, options) { + const index = this.segments.indexOf(segment); + assert(index !== -1); + const nextIndex = index + 1; + let isLazy = !!options.skipLiveWait && this.getRemainingWaitTimeMs() > 0; + while (true) { + if (nextIndex < this.segments.length) { + return this.segments[nextIndex]; + } + if (this.streamHasEnded || isLazy) { + return null; + } + await this.runUpdateSegments(); + if (options.skipLiveWait) { + isLazy = true; + } + } + } + async getPreviousSegment(segment) { + const index = this.segments.indexOf(segment); + assert(index !== -1); + return this.segments[index - 1] ?? null; + } + getInputForSegment(segment) { + const hlsSegment = segment; + const cacheEntry = this.inputCache.find((x) => x.segment === hlsSegment); + if (cacheEntry) { + cacheEntry.age = this.nextInputCacheAge++; + return cacheEntry.input; + } + let initInput = null; + if (hlsSegment.initSegment || hlsSegment.firstSegment) { + initInput = this.getInputForSegment(hlsSegment.initSegment ?? hlsSegment.firstSegment); + } + const formatOptions = { + ...this.input._formatOptions, + isobmff: { + ...this.input._formatOptions.isobmff, + // Intercept calls to resolveKeyId to inject our psshBox knowledge into it + resolveKeyId: this.input._formatOptions.isobmff?.resolveKeyId && ((options) => { + if (!hlsSegment.encryption || !(hlsSegment.encryption.method === "SAMPLE-AES" || hlsSegment.encryption.method === "SAMPLE-AES-CTR") || !hlsSegment.encryption.psshBox) { + return this.input._formatOptions.isobmff.resolveKeyId(options); + } + let psshBoxes = options.psshBoxes; + const { psshBox } = hlsSegment.encryption; + if ((psshBox.keyIds === null || psshBox.keyIds.includes(options.keyId)) && !psshBoxes.some((x) => psshBoxesAreEqual(x, psshBox))) { + psshBoxes = [...psshBoxes, psshBox]; + } + return this.input._formatOptions.isobmff.resolveKeyId({ ...options, psshBoxes }); + }) + } + }; + const input = new Input({ + source: new CustomPathedSource(hlsSegment.location.path, async (request) => { + assert(request.isRoot); + const proxiedRequest = { + ...request, + isRoot: false + }; + let ref; + const needsSlice = hlsSegment.location.offset > 0 || hlsSegment.location.length !== null; + if (!hlsSegment.encryption || hlsSegment.encryption.method === "SAMPLE-AES" || hlsSegment.encryption.method === "SAMPLE-AES-CTR") { + ref = await this.input._getSourceCached(proxiedRequest); + if (needsSlice) { + const slice = ref.source.slice(hlsSegment.location.offset, hlsSegment.location.length ?? void 0); + const sliceRef = slice.ref(); + ref.free(); + ref = sliceRef; + } + } else if (hlsSegment.encryption.method === "AES-128") { + const encryption = hlsSegment.encryption; + assert(encryption.iv); + let ciphertextRef = await this.input._getSourceCached(proxiedRequest); + if (needsSlice) { + const slice = ciphertextRef.source.slice(hlsSegment.location.offset, hlsSegment.location.length ?? void 0); + const sliceRef = slice.ref(); + ciphertextRef.free(); + ciphertextRef = sliceRef; + } + const ciphertextReader = new Reader(ciphertextRef.source); + const stream = createAes128CbcDecryptStream(ciphertextReader, async () => { + const env_2 = { stack: [], error: void 0, hasError: false }; + try { + const keyRef = __addDisposableResource(env_2, await this.input._getSourceCached({ path: encryption.keyUri, isRoot: false }, ENCRYPTION_KEY_CACHE_GROUP), false); + const keyReader = new Reader(keyRef.source); + const keySlice = await keyReader.requestSlice(0, AES_128_BLOCK_SIZE); + if (!keySlice) { + throw new Error("Invalid AES-128 key; expected at least 16 bytes of data."); + } + const key = readBytes(keySlice, AES_128_BLOCK_SIZE); + return { key, iv: encryption.iv }; + } catch (e_2) { + env_2.error = e_2; + env_2.hasError = true; + } finally { + __disposeResources(env_2); + } + }, () => { + ciphertextRef.free(); + }); + ref = new ReadableStreamSource(stream).ref(); + } else { + assert(false); + } + return ref; + }), + // Do not allow recursive HLS. Cool on paper, but allows for nasty infinite-depth request trees. + formats: this.input._formats.filter((x) => !(x instanceof HlsInputFormat)), + initInput: initInput ?? void 0, + formatOptions + }); + input._onFormatDetermined = (format) => { + if ((hlsSegment.encryption?.method === "SAMPLE-AES" || hlsSegment.encryption?.method === "SAMPLE-AES-CTR") && !format._isIsobmff) { + throw new Error("The SAMPLE-AES and SAMPLE-AES-CTR encryption methods are currently only supported for ISOBMFF files."); + } + }; + this.inputCache.push({ + segment: hlsSegment, + input, + age: this.nextInputCacheAge++ + }); + const MAX_INPUT_CACHE_SIZE = 4; + if (this.inputCache.length > MAX_INPUT_CACHE_SIZE) { + const minAgeIndex = arrayArgmin(this.inputCache, (x) => x.age); + assert(minAgeIndex !== -1); + this.inputCache.splice(minAgeIndex, 1); + } + return input; + } + async getLiveRefreshInterval() { + if (this.getRemainingWaitTimeMs() === 0) { + await this.runUpdateSegments(); + } + return this.streamHasEnded ? null : this.refreshInterval; + } + } + class HlsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.trackBackings = null; + this.internalTracks = null; + this.segmentedInputs = []; + this.hasMasterPlaylist = true; + } + readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + assert(this.input._rootSource instanceof PathedSource); + const { rootPath } = this.input._rootSource; + const slice = await this.input._reader.requestEntireFile(); + assert(slice); + const lines = readAllLines(slice, slice.length, { ignore: canIgnoreLine }); + const variantStreams = []; + const mediaTags = []; + for (let i = 1; i < lines.length; i++) { + const line = lines[i]; + if (line.startsWith(TAG_STREAM_INF)) { + const streamInfLineNumber = i; + const playlistPath = lines[++i]; + if (playlistPath === void 0) { + throw new Error("Incorrect M3U8 file; a line must follow the #EXT-X-STREAM-INF tag."); + } + const fullPath = joinPaths(rootPath, playlistPath); + const attributes = new AttributeList(line.slice(TAG_STREAM_INF.length)); + const bandwidth = attributes.getAsNumber("bandwidth"); + if (bandwidth === null) { + throw new Error("Invalid M3U8 file; #EXT-X-STREAM-INF tag requires a BANDWIDTH attribute with a valid numerical value."); + } + variantStreams.push({ + fullPath, + attributes, + lineNumber: streamInfLineNumber, + hasOnlyKeyPackets: false + }); + } else if (line.startsWith(TAG_I_FRAME_STREAM_INF)) { + const attributes = new AttributeList(line.slice(TAG_I_FRAME_STREAM_INF.length)); + const playlistPath = attributes.get("uri"); + if (playlistPath === null) { + throw new Error("Invalid M3U8 file; #EXT-X-I-FRAME-STREAM-INF tag requires a URI attribute."); + } + const bandwidth = attributes.getAsNumber("bandwidth"); + if (bandwidth === null) { + throw new Error("Invalid M3U8 file; #EXT-X-I-FRAME-STREAM-INF tag requires a BANDWIDTH attribute with a valid numerical value."); + } + const fullPath = joinPaths(rootPath, playlistPath); + variantStreams.push({ + fullPath, + attributes, + lineNumber: i, + hasOnlyKeyPackets: true + }); + } else if (line.startsWith(TAG_MEDIA)) { + const attributes = new AttributeList(line.slice(TAG_MEDIA.length)); + const type = attributes.get("type"); + if (type === null) { + throw new Error("Invalid M3U8 file; #EXT-X-MEDIA tag requires a TYPE attribute."); + } + const groupId = attributes.get("group-id"); + if (groupId === null) { + throw new Error("Invalid M3U8 file; #EXT-X-MEDIA tag requires a GROUP-ID attribute."); + } + let fullPath = null; + const uri = attributes.get("uri"); + if (uri !== null) { + fullPath = joinPaths(rootPath, uri); + } + mediaTags.push({ fullPath, attributes, lineNumber: i }); + } else if (line === TAG_I_FRAMES_ONLY) ; + else if (line.startsWith(TAG_EXTINF)) { + const segmentedInput = new HlsSegmentedInput(this, rootPath, null, lines); + this.segmentedInputs = [segmentedInput]; + this.hasMasterPlaylist = false; + this.trackBackings = await segmentedInput.getTrackBackings(); + return; + } + } + const videoGroupIds = [ + ...new Set(mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "video").map((tag) => tag.attributes.get("group-id"))) + ]; + const audioGroupIds = [ + ...new Set(mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "audio").map((tag) => tag.attributes.get("group-id"))) + ]; + const internalTracksByVariant = await Promise.all(variantStreams.map(async (variantStream, i) => { + const result = []; + const codecsList = variantStream.attributes.get("codecs"); + let codecStrings; + if (codecsList) { + codecStrings = codecsList.split(",").map((x) => x.trim()); + } else { + const segmentedInput = this.getSegmentedInputForPath(variantStream.fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const tracksWithCodec = await Promise.all(trackBackings.map(async (t) => ({ track: t, codec: await t.getCodec() }))); + codecStrings = await Promise.all(tracksWithCodec.filter((x) => x.codec !== null).map((x) => x.track.getDecoderConfig().then((x2) => x2.codec))); + } + const videoGroupId = variantStream.attributes.get("video"); + const audioGroupId = variantStream.attributes.get("audio"); + const containsVideoCodecs = codecStrings.some((x) => VIDEO_CODECS.includes(inferCodecFromCodecString(x))); + const containsAudioCodecs = codecStrings.some((x) => AUDIO_CODECS.includes(inferCodecFromCodecString(x))); + if (videoGroupId !== null && !containsVideoCodecs) { + if (!videoGroupIds.includes(videoGroupId)) { + throw new Error(`Invalid M3U8 file; variant stream references video group "${videoGroupId}" which is not defined in any #EXT-X-MEDIA tags.`); + } + const matchingVideoMediaTag = mediaTags.find((mediaTag) => { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + return groupId === videoGroupId && type.toLowerCase() === "video"; + }); + outer: if (matchingVideoMediaTag) { + const uri = matchingVideoMediaTag.attributes.get("uri"); + if (uri === null) { + break outer; + } + const fullPath = joinPaths(rootPath, uri); + const segmentedInput = this.getSegmentedInputForPath(fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const videoTrack = trackBackings.find((x) => x.getType() === "video"); + if (!videoTrack || await videoTrack.getCodec() === null) { + break outer; + } + const additionalCodecString = await videoTrack.getDecoderConfig().then((x) => x?.codec ?? null); + assert(additionalCodecString !== null); + codecStrings.push(additionalCodecString); + } + } + if (audioGroupId !== null && !containsAudioCodecs) { + if (!audioGroupIds.includes(audioGroupId)) { + throw new Error(`Invalid M3U8 file; variant stream references audio group "${audioGroupId}" which is not defined in any #EXT-X-MEDIA tags.`); + } + const matchingAudioMediaTag = mediaTags.find((tag) => { + const groupId = tag.attributes.get("group-id"); + const type = tag.attributes.get("type"); + return groupId === audioGroupId && type.toLowerCase() === "audio"; + }); + outer: if (matchingAudioMediaTag) { + const uri = matchingAudioMediaTag.attributes.get("uri"); + if (uri === null) { + break outer; + } + const fullPath = joinPaths(rootPath, uri); + const segmentedInput = this.getSegmentedInputForPath(fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const audioTrack = trackBackings.find((x) => x.getType() === "audio"); + if (!audioTrack || await audioTrack.getCodec() === null) { + break outer; + } + const additionalCodecString = await audioTrack.getDecoderConfig().then((x) => x?.codec ?? null); + assert(additionalCodecString !== null); + codecStrings.push(additionalCodecString); + } + } + codecStrings = [...new Set(codecStrings)]; + let videoCodecString = null; + let audioCodecString = null; + const bandwidth = variantStream.attributes.getAsNumber("bandwidth"); + assert(bandwidth !== null); + const averageBandwidth = variantStream.attributes.getAsNumber("average-bandwidth"); + const name = variantStream.attributes.get("name"); + for (const codecString of codecStrings) { + const inferredCodec = inferCodecFromCodecString(codecString); + if (inferredCodec === null) { + continue; + } + if (VIDEO_CODECS.includes(inferredCodec)) { + if (videoCodecString !== null) { + throw new Error("Unsupported M3U8 file; multiple video codecs found in the CODECS attribute of a variant stream."); + } + videoCodecString = codecString; + const videoGroupId2 = variantStream.attributes.get("video"); + if (videoGroupId2 === null) { + const resolution = variantStream.attributes.get("resolution"); + let width = null; + let height = null; + if (resolution) { + const match = resolution.match(/^(\d+)x(\d+)$/); + if (match) { + width = Number(match[1]); + height = Number(match[2]); + } + } + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: true, + autoselect: true, + languageCode: UNDETERMINED_LANGUAGE, + lineNumber: variantStream.lineNumber, + fullPath: variantStream.fullPath, + fullCodecString: videoCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: bandwidth, + averageBitrate: averageBandwidth, + name, + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "video", + width, + height + } + }); + } else { + if (!videoGroupIds.includes(videoGroupId2)) { + throw new Error(`Invalid M3U8 file; variant stream references video group "${videoGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`); + } + for (const mediaTag of mediaTags) { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + if (groupId !== videoGroupId2 || type.toLowerCase() !== "video") { + continue; + } + const resolution = mediaTag.attributes.get("resolution") ?? variantStream.attributes.get("resolution"); + let width = null; + let height = null; + if (resolution) { + const match = resolution.match(/^(\d+)x(\d+)$/); + if (match) { + width = Number(match[1]); + height = Number(match[2]); + } + } + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: getMediaTagDefault(mediaTag.attributes), + // Autoselect is inferred to be true if the default is true + autoselect: getMediaTagDefault(mediaTag.attributes) || getMediaTagAutoselect(mediaTag.attributes), + languageCode: preprocessLanguageCode(mediaTag.attributes.get("language")), + lineNumber: mediaTag.lineNumber, + fullPath: mediaTag.fullPath ?? variantStream.fullPath, + fullCodecString: videoCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: null, + averageBitrate: null, + name: mediaTag.attributes.get("name"), + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "video", + width, + height + } + }); + } + } + } else if (AUDIO_CODECS.includes(inferredCodec)) { + if (audioCodecString !== null) { + throw new Error("Unsupported M3U8 file; multiple audio codecs found in the CODECS attribute of a variant stream."); + } + audioCodecString = codecString; + const audioGroupId2 = variantStream.attributes.get("audio"); + if (audioGroupId2 === null) { + const channels = variantStream.attributes.get("channels"); + const parsedChannels = channels !== null ? Number(channels.split("/")[0]) : null; + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: true, + autoselect: true, + languageCode: UNDETERMINED_LANGUAGE, + lineNumber: variantStream.lineNumber, + fullPath: variantStream.fullPath, + fullCodecString: audioCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: bandwidth, + averageBitrate: averageBandwidth, + name, + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "audio", + numberOfChannels: parsedChannels !== null && Number.isInteger(parsedChannels) && parsedChannels > 0 ? parsedChannels : null + } + }); + } else { + if (!audioGroupIds.includes(audioGroupId2)) { + throw new Error(`Invalid M3U8 file; variant stream references audio group "${audioGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`); + } + for (const mediaTag of mediaTags) { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + if (groupId !== audioGroupId2 || type.toLowerCase() !== "audio") { + continue; + } + const channels = mediaTag.attributes.get("channels") ?? variantStream.attributes.get("channels"); + const parsedChannels = channels !== null ? Number(channels.split("/")[0]) : null; + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: getMediaTagDefault(mediaTag.attributes), + // Autoselect is inferred to be true if the default is true + autoselect: getMediaTagDefault(mediaTag.attributes) || getMediaTagAutoselect(mediaTag.attributes), + languageCode: preprocessLanguageCode(mediaTag.attributes.get("language")), + lineNumber: mediaTag.lineNumber, + fullPath: mediaTag.fullPath ?? variantStream.fullPath, + fullCodecString: audioCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: null, + averageBitrate: null, + name: mediaTag.attributes.get("name"), + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "audio", + numberOfChannels: parsedChannels !== null && Number.isInteger(parsedChannels) && parsedChannels > 0 ? parsedChannels : null + } + }); + } + } + } + } + return result; + })); + const internalTracks = []; + const addInternalTrack = (track) => { + const existingTrack = internalTracks.find((x) => x.fullPath === track.fullPath && x.info.type === track.info.type); + if (existingTrack) { + existingTrack.pairingMask |= track.pairingMask; + existingTrack.default || (existingTrack.default = track.default); + existingTrack.autoselect || (existingTrack.autoselect = track.autoselect); + existingTrack.lineNumber = Math.min(existingTrack.lineNumber, track.lineNumber); + if (track.peakBitrate !== null) { + existingTrack.peakBitrate = Math.max(existingTrack.peakBitrate ?? -Infinity, track.peakBitrate); + } + if (track.averageBitrate !== null) { + existingTrack.averageBitrate = Math.max(existingTrack.averageBitrate ?? -Infinity, track.averageBitrate); + } + if (existingTrack.languageCode === UNDETERMINED_LANGUAGE) { + existingTrack.languageCode = track.languageCode; + } + } else { + track.id = internalTracks.length + 1; + internalTracks.push(track); + } + }; + for (const variantInternalTracks of internalTracksByVariant) { + for (const trackEntry of variantInternalTracks) { + addInternalTrack(trackEntry); + } + } + internalTracks.sort((a, b) => a.lineNumber - b.lineNumber); + this.trackBackings = []; + for (const internalTrack of internalTracks) { + if (internalTrack.info.type === "video") { + this.trackBackings.push(new HlsInputVideoTrackBacking(internalTrack)); + } else { + this.trackBackings.push(new HlsInputAudioTrackBacking(internalTrack)); + } + } + this.internalTracks = internalTracks; + })()); + } + async getTrackBackings() { + await this.readMetadata(); + assert(this.trackBackings); + return this.trackBackings; + } + getSegmentedInputForPath(path) { + let segmentedInput = this.segmentedInputs.find((x) => x.path === path); + if (segmentedInput) { + return segmentedInput; + } + let decls = null; + if (this.internalTracks) { + const tracks = this.internalTracks.filter((x) => x.fullPath === path); + decls = tracks.map((x) => ({ + id: x.id, + type: x.info.type + })); + } + segmentedInput = new HlsSegmentedInput(this, path, decls, null); + this.segmentedInputs.push(segmentedInput); + return segmentedInput; + } + async getMetadataTags() { + return {}; + } + async getMimeType() { + return HLS_MIME_TYPE; + } + dispose() { + if (this.segmentedInputs) { + for (const segInput of this.segmentedInputs) { + segInput.dispose(); + } + this.segmentedInputs.length = 0; + } + } + } + class HlsInputTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.hydrationPromise = null; + } + hydrate() { + return this.hydrationPromise ?? (this.hydrationPromise = (async () => { + const segmentedInput = this.internalTrack.demuxer.getSegmentedInputForPath(this.internalTrack.fullPath); + let trackBacking = null; + const trackBackings = await segmentedInput.getTrackBackings(); + const matchingType = trackBackings.filter((x) => x.getType() === this.getType()); + if (matchingType.length === 1) { + trackBacking = matchingType[0]; + } else { + if (this instanceof HlsInputVideoTrackBacking) { + for (const backing of matchingType) { + if (await backing.getCodec() === this.getCodec()) { + trackBacking = backing; + break; + } + } + } else { + assert(this instanceof HlsInputAudioTrackBacking); + for (const backing of matchingType) { + if (await backing.getCodec() === this.getCodec()) { + trackBacking = backing; + break; + } + } + } + } + if (!trackBacking) { + throw new Error("Could not find matching track in underlying media data."); + } + this.internalTrack.backingTrack = trackBacking; + })()); + } + /** If the backing track is already present, delegate synchronously; otherwise, hydrate first. */ + delegate(fn) { + if (this.internalTrack.backingTrack) { + return fn(); + } + return this.hydrate().then(fn); + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + // Meanings are swapped in HLS: "Default" means that a track is the primary track. + default: this.internalTrack.autoselect, + primary: this.internalTrack.default + }; + } + getId() { + return this.internalTrack.id; + } + getPairingMask() { + return this.internalTrack.pairingMask; + } + getInternalCodecId() { + return null; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getName() { + return this.internalTrack.name; + } + getNumber() { + assert(this.internalTrack.demuxer.internalTracks); + const trackType = this.internalTrack.info.type; + let number = 0; + for (const track of this.internalTrack.demuxer.internalTracks) { + if (track.info.type === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + return number; + } + getTimeResolution() { + return this.delegate(() => this.internalTrack.backingTrack.getTimeResolution()); + } + isRelativeToUnixEpoch() { + return this.delegate(() => this.internalTrack.backingTrack.isRelativeToUnixEpoch()); + } + getBitrate() { + return this.internalTrack.peakBitrate; + } + getAverageBitrate() { + return this.internalTrack.averageBitrate; + } + async getDurationFromMetadata(options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getDurationFromMetadata(options); + } + async getLiveRefreshInterval() { + await this.hydrate(); + return this.internalTrack.backingTrack.getLiveRefreshInterval(); + } + getHasOnlyKeyPackets() { + return this.internalTrack.hasOnlyKeyPackets || null; + } + async getFirstPacket(options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getFirstPacket(options); + } + async getPacket(timestamp, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getPacket(timestamp, options); + } + async getKeyPacket(timestamp, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getKeyPacket(timestamp, options); + } + async getNextPacket(packet, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getNextPacket(packet, options); + } + async getNextKeyPacket(packet, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getNextKeyPacket(packet, options); + } + } + class HlsInputVideoTrackBacking extends HlsInputTrackBacking { + constructor(internalTrack) { + super(internalTrack); + } + get backingVideoTrack() { + return this.internalTrack.backingTrack; + } + getType() { + return "video"; + } + getCodec() { + const inferredCodec = inferCodecFromCodecString(this.internalTrack.fullCodecString); + return inferredCodec; + } + getCodedWidth() { + return this.delegate(() => this.backingVideoTrack.getCodedWidth()); + } + getCodedHeight() { + return this.delegate(() => this.backingVideoTrack.getCodedHeight()); + } + getSquarePixelWidth() { + return this.delegate(() => this.backingVideoTrack.getSquarePixelWidth()); + } + getSquarePixelHeight() { + return this.delegate(() => this.backingVideoTrack.getSquarePixelHeight()); + } + getMetadataDisplayWidth() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.info.width; + } + getMetadataDisplayHeight() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.info.height; + } + getRotation() { + return this.delegate(() => this.backingVideoTrack.getRotation()); + } + async getColorSpace() { + await this.hydrate(); + return this.backingVideoTrack.getColorSpace(); + } + async canBeTransparent() { + await this.hydrate(); + return this.backingVideoTrack.canBeTransparent(); + } + getMetadataCodecParameterString() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.fullCodecString; + } + async getDecoderConfig() { + await this.hydrate(); + return this.backingVideoTrack.getDecoderConfig(); + } + } + class HlsInputAudioTrackBacking extends HlsInputTrackBacking { + constructor(internalTrack) { + super(internalTrack); + } + get backingAudioTrack() { + return this.internalTrack.backingTrack; + } + getType() { + return "audio"; + } + getCodec() { + const inferredCodec = inferCodecFromCodecString(this.internalTrack.fullCodecString); + return inferredCodec; + } + getNumberOfChannels() { + if (this.internalTrack.info.numberOfChannels !== null) { + return this.internalTrack.info.numberOfChannels; + } + return this.delegate(() => this.backingAudioTrack.getNumberOfChannels()); + } + getSampleRate() { + return this.delegate(() => this.backingAudioTrack.getSampleRate()); + } + getMetadataCodecParameterString() { + if (this.backingAudioTrack) { + return null; + } + return this.internalTrack.fullCodecString; + } + async getDecoderConfig() { + await this.hydrate(); + return this.backingAudioTrack.getDecoderConfig(); + } + } + const getMediaTagDefault = (attributes) => { + const value = attributes.get("default"); + if (value === null) { + return false; + } + const normalized = value.toUpperCase(); + if (normalized === "YES") { + return true; + } + if (normalized === "NO") { + return false; + } + throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA DEFAULT attribute must be YES or NO, got "${value}".`); + }; + const getMediaTagAutoselect = (attributes) => { + const value = attributes.get("autoselect"); + if (value === null) { + return false; + } + const normalized = value.toUpperCase(); + if (normalized === "YES") { + return true; + } + if (normalized === "NO") { + return false; + } + throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA AUTOSELECT attribute must be YES or NO, got "${value}".`); + }; + const preprocessLanguageCode = (code) => { + if (code === null) { + return UNDETERMINED_LANGUAGE; + } + const languageSubtag = code.split("-")[0]; + if (!languageSubtag) { + return UNDETERMINED_LANGUAGE; + } + return languageSubtag; + }; + class InputFormat { + constructor() { + this._isIsobmff = false; + } + } + class IsobmffInputFormat extends InputFormat { + constructor() { + super(...arguments); + this._isIsobmff = true; + } + /** @internal */ + async _getMajorBrand(input) { + let slice = input._reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return null; + slice.skip(4); + const fourCc = readAscii(slice, 4); + if (fourCc !== "ftyp" && fourCc !== "styp") { + return null; + } + return readAscii(slice, 4); + } + /** @internal */ + _createDemuxer(input) { + return new IsobmffDemuxer(input); + } + } + class Mp4InputFormat extends IsobmffInputFormat { + /** @internal */ + async _canReadInput(input) { + const majorBrand = await this._getMajorBrand(input); + if (majorBrand !== null) { + return majorBrand !== "qt "; + } + let slice = input._reader.requestSlice(4, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "moof"; + } + get name() { + return "MP4"; + } + get mimeType() { + return "video/mp4"; + } + } + class QuickTimeInputFormat extends IsobmffInputFormat { + /** @internal */ + async _canReadInput(input) { + const majorBrand = await this._getMajorBrand(input); + return majorBrand === "qt "; + } + get name() { + return "QuickTime File Format"; + } + get mimeType() { + return "video/quicktime"; + } + } + class MatroskaInputFormat extends InputFormat { + /** @internal */ + async isSupportedEBMLOfDocType(input, desiredDocType) { + let headerSlice = input._reader.requestSlice(0, MAX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + return false; + const varIntSize = readVarIntSize(headerSlice); + if (varIntSize === null) { + return false; + } + if (varIntSize < 1 || varIntSize > 8) { + return false; + } + const id = readUnsignedInt(headerSlice, varIntSize); + if (id !== EBMLId.EBML) { + return false; + } + const dataSize = readElementSize(headerSlice); + if (typeof dataSize !== "number") { + return false; + } + let dataSlice = input._reader.requestSlice(headerSlice.filePos, dataSize); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (!dataSlice) + return false; + const startPos = headerSlice.filePos; + while (dataSlice.filePos <= startPos + dataSize - MIN_HEADER_SIZE) { + const header = readElementHeader(dataSlice); + if (!header) + break; + const { id: id2, size } = header; + const dataStartPos = dataSlice.filePos; + if (size === void 0) + return false; + switch (id2) { + case EBMLId.EBMLVersion: + { + const ebmlVersion = readUnsignedInt(dataSlice, size); + if (ebmlVersion !== 1) { + return false; + } + } + break; + case EBMLId.EBMLReadVersion: + { + const ebmlReadVersion = readUnsignedInt(dataSlice, size); + if (ebmlReadVersion !== 1) { + return false; + } + } + break; + case EBMLId.DocType: + { + const docType = readAsciiString(dataSlice, size); + if (docType !== desiredDocType) { + return false; + } + } + break; + case EBMLId.DocTypeVersion: + { + const docTypeVersion = readUnsignedInt(dataSlice, size); + if (docTypeVersion > 4) { + return false; + } + } + break; + } + dataSlice.filePos = dataStartPos + size; + } + return true; + } + /** @internal */ + _canReadInput(input) { + return this.isSupportedEBMLOfDocType(input, "matroska"); + } + /** @internal */ + _createDemuxer(input) { + return new MatroskaDemuxer(input); + } + get name() { + return "Matroska"; + } + get mimeType() { + return "video/x-matroska"; + } + } + class WebMInputFormat extends MatroskaInputFormat { + /** @internal */ + _canReadInput(input) { + return this.isSupportedEBMLOfDocType(input, "webm"); + } + get name() { + return "WebM"; + } + get mimeType() { + return "video/webm"; + } + } + class Mp3InputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let currentPos = 0; + while (true) { + let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + currentPos = slice2.filePos + id3V2Header.size; + } + const firstResult = await readNextMp3FrameHeader(input._reader, currentPos, currentPos + 4096); + if (!firstResult) { + return false; + } + const firstHeader = firstResult.header; + const xingOffset = getXingOffset(firstHeader.mpegVersionId, firstHeader.channel); + let slice = input._reader.requestSlice(firstResult.startPos + xingOffset, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const word = readU32Be(slice); + const isXing = word === XING || word === INFO; + if (isXing) { + return true; + } + currentPos = firstResult.startPos + firstResult.header.totalSize; + const secondResult = await readNextMp3FrameHeader(input._reader, currentPos, currentPos + FRAME_HEADER_SIZE); + if (!secondResult) { + return false; + } + const secondHeader = secondResult.header; + if (firstHeader.channel !== secondHeader.channel || firstHeader.sampleRate !== secondHeader.sampleRate) { + return false; + } + return true; + } + /** @internal */ + _createDemuxer(input) { + return new Mp3Demuxer(input); + } + get name() { + return "MP3"; + } + get mimeType() { + return "audio/mpeg"; + } + } + class WaveInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const riffType = readAscii(slice, 4); + if (riffType !== "RIFF" && riffType !== "RIFX" && riffType !== "RF64") { + return false; + } + slice.skip(4); + const format = readAscii(slice, 4); + return format === "WAVE"; + } + /** @internal */ + _createDemuxer(input) { + return new WaveDemuxer(input); + } + get name() { + return "WAVE"; + } + get mimeType() { + return "audio/wav"; + } + } + class OggInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "OggS"; + } + /** @internal */ + _createDemuxer(input) { + return new OggDemuxer(input); + } + get name() { + return "Ogg"; + } + get mimeType() { + return "application/ogg"; + } + } + class FlacInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "fLaC"; + } + get name() { + return "FLAC"; + } + get mimeType() { + return "audio/flac"; + } + /** @internal */ + _createDemuxer(input) { + return new FlacDemuxer(input); + } + } + class AdtsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let currentPos = 0; + while (true) { + let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + currentPos = slice2.filePos + id3V2Header.size; + } + let slice = input._reader.requestSliceRange(currentPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const firstHeader = readAdtsFrameHeader(slice); + if (!firstHeader) { + return false; + } + currentPos += firstHeader.frameLength; + slice = input._reader.requestSliceRange(currentPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const secondHeader = readAdtsFrameHeader(slice); + if (!secondHeader) { + return false; + } + return firstHeader.objectType === secondHeader.objectType && firstHeader.samplingFrequencyIndex === secondHeader.samplingFrequencyIndex && firstHeader.channelConfiguration === secondHeader.channelConfiguration; + } + /** @internal */ + _createDemuxer(input) { + return new AdtsDemuxer(input); + } + get name() { + return "ADTS"; + } + get mimeType() { + return "audio/aac"; + } + } + class MpegTsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + const lengthToCheck = TS_PACKET_SIZE + 16 + 1; + let slice = input._reader.requestSlice(0, lengthToCheck); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const bytes = readBytes(slice, lengthToCheck); + if (bytes[0] === 71 && bytes[TS_PACKET_SIZE] === 71) { + return true; + } else if (bytes[0] === 71 && bytes[TS_PACKET_SIZE + 16] === 71) { + return true; + } else if (bytes[4] === 71 && bytes[4 + TS_PACKET_SIZE + 4] === 71) { + return true; + } + return false; + } + /** @internal */ + _createDemuxer(input) { + return new MpegTsDemuxer(input); + } + get name() { + return "MPEG Transport Stream"; + } + get mimeType() { + return "video/MP2T"; + } + } + class HlsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 7); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const isM3u8 = readAscii(slice, 7) === "#EXTM3U"; + if (!isM3u8) { + return false; + } + if (!(input._rootSource instanceof PathedSource)) { + throw new TypeError("HLS inputs require `InputOptions.source` to be a PathedSource or a ref to one."); + } + input._rootSource._usedForHls = true; + return true; + } + /** @internal */ + _createDemuxer(input) { + return new HlsDemuxer(input); + } + get name() { + return "HTTP Live Streaming (HLS)"; + } + get mimeType() { + return HLS_MIME_TYPE; + } + } + const MP4 = /* @__PURE__ */ new Mp4InputFormat(); + const QTFF = /* @__PURE__ */ new QuickTimeInputFormat(); + const MATROSKA = /* @__PURE__ */ new MatroskaInputFormat(); + const WEBM = /* @__PURE__ */ new WebMInputFormat(); + const MP3 = /* @__PURE__ */ new Mp3InputFormat(); + const WAVE = /* @__PURE__ */ new WaveInputFormat(); + const OGG = /* @__PURE__ */ new OggInputFormat(); + const ADTS = /* @__PURE__ */ new AdtsInputFormat(); + const FLAC = /* @__PURE__ */ new FlacInputFormat(); + const MPEG_TS = /* @__PURE__ */ new MpegTsInputFormat(); + const HLS = /* @__PURE__ */ new HlsInputFormat(); + const ALL_FORMATS = [HLS, MP4, QTFF, MATROSKA, WEBM, WAVE, OGG, FLAC, MP3, ADTS, MPEG_TS]; + const HLS_FORMATS = [HLS, MP4, QTFF, MP3, ADTS, MPEG_TS]; + const validateInputFormatOptions = (options, prefix) => { + if (!options || typeof options !== "object") { + throw new TypeError(`${prefix}, when provided, must be an object.`); + } + if (options.isobmff !== void 0) { + if (!options.isobmff || typeof options.isobmff !== "object") { + throw new TypeError(`${prefix}.isobmff, when provided, must be an object.`); + } + if (options.isobmff.resolveKeyId !== void 0 && typeof options.isobmff.resolveKeyId !== "function") { + throw new TypeError(`${prefix}.isobmff.resolveKeyId, when provided, must be a function.`); + } } - return sign === 0 ? decoded : -decoded; }; polyfillSymbolDispose(); let lastVideoGcErrorLog = -Infinity; @@ -2369,7 +16244,7 @@ var artplayerProxyMediabunny = (function() { let finalizationRegistry = null; if (typeof FinalizationRegistry !== "undefined") { finalizationRegistry = new FinalizationRegistry((value) => { - const now = Date.now(); + const now = performance.now(); if (value.type === "video") { if (now - lastVideoGcErrorLog >= 1e3) { console.error(`A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them.`); @@ -2427,13 +16302,21 @@ var artplayerProxyMediabunny = (function() { ]; const VIDEO_SAMPLE_PIXEL_FORMATS_SET = new Set(VIDEO_SAMPLE_PIXEL_FORMATS); class VideoSample { - /** The width of the frame in pixels after rotation. */ - get displayWidth() { - return this.rotation % 180 === 0 ? this.codedWidth : this.codedHeight; + /** The width of the frame in pixels. */ + get codedWidth() { + return this.visibleRect.width; } - /** The height of the frame in pixels after rotation. */ + /** The height of the frame in pixels. */ + get codedHeight() { + return this.visibleRect.height; + } + /** The display width of the frame in pixels, after aspect ratio adjustment and rotation. */ + get displayWidth() { + return this.rotation % 180 === 0 ? this.squarePixelWidth : this.squarePixelHeight; + } + /** The display height of the frame in pixels, after aspect ratio adjustment and rotation. */ get displayHeight() { - return this.rotation % 180 === 0 ? this.codedHeight : this.codedWidth; + return this.rotation % 180 === 0 ? this.squarePixelHeight : this.squarePixelWidth; } /** The presentation timestamp of the frame in microseconds. */ get microsecondTimestamp() { @@ -2474,15 +16357,54 @@ var artplayerProxyMediabunny = (function() { if (init.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { throw new TypeError("init.duration, when provided, must be a non-negative number."); } + if (init.layout !== void 0) { + if (!Array.isArray(init.layout)) { + throw new TypeError("init.layout, when provided, must be an array."); + } + for (const plane of init.layout) { + if (!plane || typeof plane !== "object" || Array.isArray(plane)) { + throw new TypeError("Each entry in init.layout must be an object."); + } + if (!Number.isInteger(plane.offset) || plane.offset < 0) { + throw new TypeError("plane.offset must be a non-negative integer."); + } + if (!Number.isInteger(plane.stride) || plane.stride < 0) { + throw new TypeError("plane.stride must be a non-negative integer."); + } + } + } + if (init.visibleRect !== void 0) { + validateRectangle(init.visibleRect, "init.visibleRect"); + } + if (init.displayWidth !== void 0 && (!Number.isInteger(init.displayWidth) || init.displayWidth <= 0)) { + throw new TypeError("init.displayWidth, when provided, must be a positive integer."); + } + if (init.displayHeight !== void 0 && (!Number.isInteger(init.displayHeight) || init.displayHeight <= 0)) { + throw new TypeError("init.displayHeight, when provided, must be a positive integer."); + } + if (init.displayWidth !== void 0 !== (init.displayHeight !== void 0)) { + throw new TypeError("init.displayWidth and init.displayHeight must be either both provided or both omitted."); + } this._data = toUint8Array(data).slice(); this._layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight); this.format = init.format; - this.codedWidth = init.codedWidth; - this.codedHeight = init.codedHeight; this.rotation = init.rotation ?? 0; this.timestamp = init.timestamp; this.duration = init.duration ?? 0; this.colorSpace = new VideoSampleColorSpace(init.colorSpace); + this.visibleRect = { + left: init.visibleRect?.left ?? 0, + top: init.visibleRect?.top ?? 0, + width: init.visibleRect?.width ?? init.codedWidth, + height: init.visibleRect?.height ?? init.codedHeight + }; + if (init.displayWidth !== void 0) { + this.squarePixelWidth = this.rotation % 180 === 0 ? init.displayWidth : init.displayHeight; + this.squarePixelHeight = this.rotation % 180 === 0 ? init.displayHeight : init.displayWidth; + } else { + this.squarePixelWidth = this.codedWidth; + this.squarePixelHeight = this.codedHeight; + } } else if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) { if (init?.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) { throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270."); @@ -2493,12 +16415,21 @@ var artplayerProxyMediabunny = (function() { if (init?.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { throw new TypeError("init.duration, when provided, must be a non-negative number."); } + if (init?.visibleRect !== void 0) { + validateRectangle(init.visibleRect, "init.visibleRect"); + } this._data = data; this._layout = null; this.format = data.format; - this.codedWidth = data.displayWidth; - this.codedHeight = data.displayHeight; + this.visibleRect = { + left: data.visibleRect?.x ?? 0, + top: data.visibleRect?.y ?? 0, + width: data.visibleRect?.width ?? data.codedWidth, + height: data.visibleRect?.height ?? data.codedHeight + }; this.rotation = init?.rotation ?? 0; + this.squarePixelWidth = data.displayWidth; + this.squarePixelHeight = data.displayHeight; this.timestamp = init?.timestamp ?? data.timestamp / 1e6; this.duration = init?.duration ?? (data.duration ?? 0) / 1e6; this.colorSpace = new VideoSampleColorSpace(data.colorSpace); @@ -2548,8 +16479,9 @@ var artplayerProxyMediabunny = (function() { this._data = canvas; this._layout = null; this.format = "RGBX"; - this.codedWidth = width; - this.codedHeight = height; + this.visibleRect = { left: 0, top: 0, width, height }; + this.squarePixelWidth = width; + this.squarePixelHeight = height; this.rotation = init.rotation ?? 0; this.timestamp = init.timestamp; this.duration = init.duration ?? 0; @@ -2562,6 +16494,10 @@ var artplayerProxyMediabunny = (function() { } else { throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource."); } + this.pixelAspectRatio = simplifyRational({ + num: this.squarePixelWidth * this.codedHeight, + den: this.squarePixelHeight * this.codedWidth + }); finalizationRegistry?.register(this, { type: "video", data: this._data }, this); } /** Clones this video sample. */ @@ -2586,7 +16522,10 @@ var artplayerProxyMediabunny = (function() { timestamp: this.timestamp, duration: this.duration, colorSpace: this.colorSpace, - rotation: this.rotation + rotation: this.rotation, + visibleRect: this.visibleRect, + displayWidth: this.displayWidth, + displayHeight: this.displayHeight }); } else { return new VideoSample(this._data, { @@ -2596,7 +16535,10 @@ var artplayerProxyMediabunny = (function() { timestamp: this.timestamp, duration: this.duration, colorSpace: this.colorSpace, - rotation: this.rotation + rotation: this.rotation, + visibleRect: this.visibleRect, + displayWidth: this.displayWidth, + displayHeight: this.displayHeight }); } } @@ -2814,7 +16756,7 @@ var artplayerProxyMediabunny = (function() { const canvasWidth = context.canvas.width; const canvasHeight = context.canvas.height; const rotation = options.rotation ?? this.rotation; - const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [this.codedWidth, this.codedHeight] : [this.codedHeight, this.codedWidth]; + const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [this.squarePixelWidth, this.squarePixelHeight] : [this.squarePixelHeight, this.squarePixelWidth]; if (options.crop) { clampCropRectangle(options.crop, rotatedWidth, rotatedHeight); } @@ -2850,18 +16792,18 @@ var artplayerProxyMediabunny = (function() { if (rotation === 90) { [sx, sy, sWidth, sHeight] = [ sy, - this.codedHeight - sx - sWidth, + this.squarePixelHeight - sx - sWidth, sHeight, sWidth ]; } else if (rotation === 180) { [sx, sy] = [ - this.codedWidth - sx - sWidth, - this.codedHeight - sy - sHeight + this.squarePixelWidth - sx - sWidth, + this.squarePixelHeight - sy - sHeight ]; } else if (rotation === 270) { [sx, sy, sWidth, sHeight] = [ - this.codedWidth - sy - sHeight, + this.squarePixelWidth - sy - sHeight, sx, sHeight, sWidth @@ -2918,6 +16860,26 @@ var artplayerProxyMediabunny = (function() { class VideoSampleColorSpace { /** Creates a new VideoSampleColorSpace. */ constructor(init) { + if (init !== void 0) { + if (!init || typeof init !== "object") { + throw new TypeError("init.colorSpace, when provided, must be an object."); + } + const primariesValues = Object.keys(COLOR_PRIMARIES_MAP); + if (init.primaries != null && !primariesValues.includes(init.primaries)) { + throw new TypeError(`init.colorSpace.primaries, when provided, must be one of ${primariesValues.join(", ")}.`); + } + const transferValues = Object.keys(TRANSFER_CHARACTERISTICS_MAP); + if (init.transfer != null && !transferValues.includes(init.transfer)) { + throw new TypeError(`init.colorSpace.transfer, when provided, must be one of ${transferValues.join(", ")}.`); + } + const matrixValues = Object.keys(MATRIX_COEFFICIENTS_MAP); + if (init.matrix != null && !matrixValues.includes(init.matrix)) { + throw new TypeError(`init.colorSpace.matrix, when provided, must be one of ${matrixValues.join(", ")}.`); + } + if (init.fullRange != null && typeof init.fullRange !== "boolean") { + throw new TypeError("init.colorSpace.fullRange, when provided, must be a boolean."); + } + } this.primaries = init?.primaries ?? null; this.transfer = init?.transfer ?? null; this.matrix = init?.matrix ?? null; @@ -2937,12 +16899,13 @@ var artplayerProxyMediabunny = (function() { return typeof VideoFrame !== "undefined" && x instanceof VideoFrame; }; const clampCropRectangle = (crop, outerWidth, outerHeight) => { - crop.left = Math.min(crop.left, outerWidth); - crop.top = Math.min(crop.top, outerHeight); - crop.width = Math.min(crop.width, outerWidth - crop.left); - crop.height = Math.min(crop.height, outerHeight - crop.top); - assert(crop.width >= 0); - assert(crop.height >= 0); + const left = Math.min(crop.left, outerWidth); + const top = Math.min(crop.top, outerHeight); + const width = Math.min(crop.width, outerWidth - left); + const height = Math.min(crop.height, outerHeight - top); + assert(width >= 0); + assert(height >= 0); + return { left, top, width, height }; }; const validateCropRectangle = (crop, prefix) => { if (!crop || typeof crop !== "object") { @@ -3616,6 +17579,38 @@ var artplayerProxyMediabunny = (function() { } } }; + const customVideoDecoders = []; + const customAudioDecoders = []; + const fromUlaw = (u8) => { + const MULAW_BIAS = 33; + let sign = 0; + let position = 0; + let number = ~u8; + if (number & 128) { + number &= -129; + sign = -1; + } + position = ((number & 240) >> 4) + 5; + const decoded = (1 << position | (number & 15) << position - 4 | 1 << position - 5) - MULAW_BIAS; + return sign === 0 ? decoded : -decoded; + }; + const fromAlaw = (u8) => { + let sign = 0; + let position = 0; + let number = u8 ^ 85; + if (number & 128) { + number &= -129; + sign = -1; + } + position = ((number & 240) >> 4) + 4; + let decoded = 0; + if (position !== 4) { + decoded = 1 << position | (number & 15) << position - 4 | 1 << position - 5; + } else { + decoded = number << 1 | 1; + } + return sign === 0 ? decoded : -decoded; + }; const validatePacketRetrievalOptions = (options) => { if (!options || typeof options !== "object") { throw new TypeError("options must be an object."); @@ -3629,6 +17624,9 @@ var artplayerProxyMediabunny = (function() { if (options.verifyKeyPackets && options.metadataOnly) { throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together."); } + if (options.skipLiveWait !== void 0 && typeof options.skipLiveWait !== "boolean") { + throw new TypeError("options.skipLiveWait, when defined, must be a boolean."); + } }; const validateTimestamp = (timestamp) => { if (!isNumber(timestamp)) { @@ -3661,15 +17659,27 @@ var artplayerProxyMediabunny = (function() { } /** * Retrieves the track's first packet (in decode order), or null if it has no packets. The first packet is very - * likely to be a key packet. + * likely to be a key packet, but it doesn't have to be. */ - getFirstPacket(options = {}) { + async getFirstPacket(options = {}) { validatePacketRetrievalOptions(options); if (this._track.input._disposed) { throw new InputDisposedError(); } return maybeFixPacketType(this._track, this._track._backing.getFirstPacket(options), options); } + /** Retrieves the track's first key packet (in decode order), or null if it has no key packets. */ + async getFirstKeyPacket(options = {}) { + validatePacketRetrievalOptions(options); + const firstPacket = await this.getFirstPacket(options); + if (!firstPacket) { + return null; + } + if (firstPacket.type === "key") { + return firstPacket; + } + return this.getNextKeyPacket(firstPacket, options); + } /** * Retrieves the packet corresponding to the given timestamp, in seconds. More specifically, returns the last packet * (in presentation order) with a start timestamp less than or equal to the given timestamp. This method can be @@ -3678,7 +17688,7 @@ var artplayerProxyMediabunny = (function() { * * @param timestamp - The timestamp used for retrieval, in seconds. */ - getPacket(timestamp, options = {}) { + async getPacket(timestamp, options = {}) { validateTimestamp(timestamp); validatePacketRetrievalOptions(options); if (this._track.input._disposed) { @@ -3690,7 +17700,7 @@ var artplayerProxyMediabunny = (function() { * Retrieves the packet following the given packet (in decode order), or null if the given packet is the * last packet. */ - getNextPacket(packet, options = {}) { + async getNextPacket(packet, options = {}) { if (!(packet instanceof EncodedPacket)) { throw new TypeError("packet must be an EncodedPacket."); } @@ -3727,7 +17737,7 @@ var artplayerProxyMediabunny = (function() { assert(packet.type === "key"); const determinedType = await this._track.determinePacketType(packet); if (determinedType === "delta") { - return this.getKeyPacket(packet.timestamp - 1 / this._track.timeResolution, options); + return this.getKeyPacket(packet.timestamp - 1 / await this._track.getTimeResolution(), options); } return packet; } @@ -3764,7 +17774,7 @@ var artplayerProxyMediabunny = (function() { * method will intelligently preload packets based on the speed of the consumer. * * @param startPacket - (optional) The packet from which iteration should begin. This packet will also be yielded. - * @param endTimestamp - (optional) The timestamp at which iteration should end. This packet will _not_ be yielded. + * @param endPacket - (optional) The packet at which iteration should end. This packet will _not_ be yielded. */ packets(startPacket, endPacket, options = {}) { if (startPacket !== void 0 && !(startPacket instanceof EncodedPacket)) { @@ -3861,7 +17871,7 @@ var artplayerProxyMediabunny = (function() { } class BaseMediaSampleSink { /** @internal */ - mediaSamplesInRange(startTimestamp = 0, endTimestamp = Infinity) { + mediaSamplesInRange(startTimestamp = 0, endTimestamp = Infinity, options) { validateTimestamp(startTimestamp); validateTimestamp(endTimestamp); const sampleQueue = []; @@ -3873,6 +17883,11 @@ var artplayerProxyMediabunny = (function() { let ended = false; let terminated = false; let outOfBandError = null; + const packetRetrievalOptions = { + ...options, + verifyKeyPackets: true, + metadataOnly: false + }; (async () => { const decoder = await this._createDecoder((sample) => { onQueueDequeue(); @@ -3907,10 +17922,10 @@ var artplayerProxyMediabunny = (function() { } }); const packetSink = this._createPacketSink(); - const keyPacket = await packetSink.getKeyPacket(startTimestamp, { verifyKeyPackets: true }) ?? await packetSink.getFirstPacket(); + const keyPacket = await packetSink.getKeyPacket(startTimestamp, packetRetrievalOptions) ?? await packetSink.getFirstKeyPacket(packetRetrievalOptions); let currentPacket = keyPacket; const endPacket = void 0; - const packets = packetSink.packets(keyPacket ?? void 0, endPacket); + const packets = packetSink.packets(keyPacket ?? void 0, endPacket, packetRetrievalOptions); await packets.next(); while (currentPacket && !ended && !this._track.input._disposed) { const maxQueueSize = computeMaxQueueSize(sampleQueue.length); @@ -3988,7 +18003,7 @@ var artplayerProxyMediabunny = (function() { }; } /** @internal */ - mediaSamplesAtTimestamps(timestamps) { + mediaSamplesAtTimestamps(timestamps, options) { validateAnyIterable(timestamps); const timestampIterator = toAsyncIterator(timestamps); const timestampsOfInterest = []; @@ -4003,6 +18018,11 @@ var artplayerProxyMediabunny = (function() { onQueueNotEmpty(); ({ promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers()); }; + const retrievalOptions = { + ...options, + verifyKeyPackets: true, + metadataOnly: false + }; (async () => { const decoder = await this._createDecoder((sample) => { onQueueDequeue(); @@ -4045,7 +18065,7 @@ var artplayerProxyMediabunny = (function() { if (terminated) { break; } - const nextPacket = await packetSink.getNextPacket(currentPacket); + const nextPacket = await packetSink.getNextPacket(currentPacket, retrievalOptions); assert(nextPacket); decoder.decode(nextPacket); currentPacket = nextPacket; @@ -4064,8 +18084,8 @@ var artplayerProxyMediabunny = (function() { if (terminated || this._track.input._disposed) { break; } - const targetPacket = await packetSink.getPacket(timestamp); - const keyPacket = targetPacket && await packetSink.getKeyPacket(timestamp, { verifyKeyPackets: true }); + const targetPacket = await packetSink.getPacket(timestamp, retrievalOptions); + const keyPacket = targetPacket && await packetSink.getKeyPacket(timestamp, retrievalOptions); if (!keyPacket) { if (maxSequenceNumber !== -1) { await decodePackets(); @@ -4247,14 +18267,23 @@ var artplayerProxyMediabunny = (function() { if (!isWebKit()) { insertSorted(this.inputTimestamps, packet.timestamp, (x) => x); } - if (isChromium() && this.currentPacketIndex === 0 && this.codec === "avc") { - const nalUnits = extractAvcNalUnits(packet.data, this.decoderConfig); - const filteredNalUnits = nalUnits.filter((x) => { - const type = extractNalUnitTypeForAvc(x); - return !(type >= 20 && type <= 31); - }); - const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig); - packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration); + if (isChromium() && this.currentPacketIndex === 0) { + if (this.codec === "avc") { + const filteredNalUnits = []; + for (const loc of iterateAvcNalUnits(packet.data, this.decoderConfig)) { + const type = extractNalUnitTypeForAvc(packet.data[loc.offset]); + if (!(type >= 20 && type <= 31)) { + filteredNalUnits.push(packet.data.subarray(loc.offset, loc.offset + loc.length)); + } + } + const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig); + packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration); + } else if (this.codec === "hevc") { + const sanitizedData = sanitizeHevcPacketForChromium(packet.data, this.decoderConfig); + if (sanitizedData) { + packet = new EncodedPacket(sanitizedData, packet.type, packet.timestamp, packet.duration); + } + } } this.decoder.decode(packet.toEncodedVideoChunk()); this.decodeAlphaData(packet); @@ -4347,11 +18376,13 @@ var artplayerProxyMediabunny = (function() { * and causes bugs upstream. So, let's take the dropping into our own hands. */ hasHevcRaslPicture(packetData) { - const nalUnits = extractHevcNalUnits(packetData, this.decoderConfig); - return nalUnits.some((x) => { - const type = extractNalUnitTypeForHevc(x); - return type === HevcNalUnitType.RASL_N || type === HevcNalUnitType.RASL_R; - }); + for (const loc of iterateHevcNalUnits(packetData, this.decoderConfig)) { + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (type === HevcNalUnitType.RASL_N || type === HevcNalUnitType.RASL_R) { + return true; + } + } + return false; } /** Handler for the WebCodecs VideoDecoder for ironing out browser differences. */ sampleHandler(sample) { @@ -4576,10 +18607,10 @@ var artplayerProxyMediabunny = (function() { if (!await this._track.canDecode()) { throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track."); } - const codec = this._track.codec; - const rotation = this._track.rotation; + const codec = await this._track.getCodec(); + const rotation = await this._track.getRotation(); const decoderConfig = await this._track.getDecoderConfig(); - const timeResolution = this._track.timeResolution; + const timeResolution = await this._track.getTimeResolution(); assert(codec && decoderConfig); return new VideoDecoderWrapper(onSample, onError, codec, decoderConfig, rotation, timeResolution); } @@ -4593,10 +18624,11 @@ var artplayerProxyMediabunny = (function() { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getSample(timestamp) { + async getSample(timestamp, options = {}) { validateTimestamp(timestamp); - for await (const sample of this.mediaSamplesAtTimestamps([timestamp])) { + for await (const sample of this.mediaSamplesAtTimestamps([timestamp], options)) { return sample; } throw new Error("Internal error: Iterator returned nothing."); @@ -4607,9 +18639,10 @@ var artplayerProxyMediabunny = (function() { * * @param startTimestamp - The timestamp in seconds at which to start yielding samples (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding samples (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - samples(startTimestamp = 0, endTimestamp = Infinity) { - return this.mediaSamplesInRange(startTimestamp, endTimestamp); + samples(startTimestamp = 0, endTimestamp = Infinity, options = {}) { + return this.mediaSamplesInRange(startTimestamp, endTimestamp, options); } /** * Creates an async iterator that yields a video sample (frame) for each timestamp in the argument. This method @@ -4618,14 +18651,17 @@ var artplayerProxyMediabunny = (function() { * yield null if no frame is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - samplesAtTimestamps(timestamps) { - return this.mediaSamplesAtTimestamps(timestamps); + samplesAtTimestamps(timestamps, options = {}) { + return this.mediaSamplesAtTimestamps(timestamps, options); } } class CanvasSink { /** Creates a new {@link CanvasSink} for the given {@link InputVideoTrack}. */ constructor(videoTrack, options = {}) { + this._rotation = 0; + this._initPromise = null; this._nextCanvasIndex = 0; if (!(videoTrack instanceof InputVideoTrack)) { throw new TypeError("videoTrack must be an InputVideoTrack."); @@ -4657,45 +18693,57 @@ var artplayerProxyMediabunny = (function() { if (options.poolSize !== void 0 && (typeof options.poolSize !== "number" || !Number.isInteger(options.poolSize) || options.poolSize < 0)) { throw new TypeError("poolSize must be a non-negative integer."); } - const rotation = options.rotation ?? videoTrack.rotation; - const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [videoTrack.codedWidth, videoTrack.codedHeight] : [videoTrack.codedHeight, videoTrack.codedWidth]; - const crop = options.crop; - if (crop) { - clampCropRectangle(crop, rotatedWidth, rotatedHeight); - } - let [width, height] = crop ? [crop.width, crop.height] : [rotatedWidth, rotatedHeight]; - const originalAspectRatio = width / height; - if (options.width !== void 0 && options.height === void 0) { - width = options.width; - height = Math.round(width / originalAspectRatio); - } else if (options.width === void 0 && options.height !== void 0) { - height = options.height; - width = Math.round(height * originalAspectRatio); - } else if (options.width !== void 0 && options.height !== void 0) { - width = options.width; - height = options.height; - } this._videoTrack = videoTrack; this._alpha = options.alpha ?? false; - this._width = width; - this._height = height; - this._rotation = rotation; - this._crop = crop; + this._options = options; this._fit = options.fit ?? "fill"; this._videoSampleSink = new VideoSampleSink(videoTrack); this._canvasPool = Array.from({ length: options.poolSize ?? 0 }, () => null); } /** @internal */ + _ensureInit() { + return this._initPromise ?? (this._initPromise = (async () => { + const options = this._options; + const videoTrack = this._videoTrack; + const rotation = options.rotation ?? await videoTrack.getRotation(); + const squarePixelWidth = await videoTrack.getSquarePixelWidth(); + const squarePixelHeight = await videoTrack.getSquarePixelHeight(); + const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [squarePixelWidth, squarePixelHeight] : [squarePixelHeight, squarePixelWidth]; + let crop = options.crop; + if (crop) { + crop = clampCropRectangle(crop, rotatedWidth, rotatedHeight); + } + let [width, height] = crop ? [crop.width, crop.height] : [rotatedWidth, rotatedHeight]; + const originalAspectRatio = width / height; + if (options.width !== void 0 && options.height === void 0) { + width = options.width; + height = Math.round(width / originalAspectRatio); + } else if (options.width === void 0 && options.height !== void 0) { + height = options.height; + width = Math.round(height * originalAspectRatio); + } else if (options.width !== void 0 && options.height !== void 0) { + width = options.width; + height = options.height; + } + this._width = width; + this._height = height; + this._rotation = rotation; + this._crop = crop; + })()); + } + /** @internal */ _videoSampleToWrappedCanvas(sample) { + const width = this._width; + const height = this._height; let canvas = this._canvasPool[this._nextCanvasIndex]; let canvasIsNew = false; if (!canvas) { if (typeof document !== "undefined") { canvas = document.createElement("canvas"); - canvas.width = this._width; - canvas.height = this._height; + canvas.width = width; + canvas.height = height; } else { - canvas = new OffscreenCanvas(this._width, this._height); + canvas = new OffscreenCanvas(width, height); } if (this._canvasPool.length > 0) { this._canvasPool[this._nextCanvasIndex] = canvas; @@ -4714,9 +18762,9 @@ var artplayerProxyMediabunny = (function() { if (!canvasIsNew) { if (!this._alpha && isFirefox()) { context.fillStyle = "black"; - context.fillRect(0, 0, this._width, this._height); + context.fillRect(0, 0, width, height); } else { - context.clearRect(0, 0, this._width, this._height); + context.clearRect(0, 0, width, height); } } sample.drawWithFit(context, { @@ -4738,10 +18786,12 @@ var artplayerProxyMediabunny = (function() { * timestamp. Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getCanvas(timestamp) { + async getCanvas(timestamp, options) { validateTimestamp(timestamp); - const sample = await this._videoSampleSink.getSample(timestamp); + await this._ensureInit(); + const sample = await this._videoSampleSink.getSample(timestamp, options); return sample && this._videoSampleToWrappedCanvas(sample); } /** @@ -4750,9 +18800,11 @@ var artplayerProxyMediabunny = (function() { * * @param startTimestamp - The timestamp in seconds at which to start yielding canvases (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding canvases (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - canvases(startTimestamp = 0, endTimestamp = Infinity) { - return mapAsyncGenerator(this._videoSampleSink.samples(startTimestamp, endTimestamp), (sample) => this._videoSampleToWrappedCanvas(sample)); + async *canvases(startTimestamp = 0, endTimestamp = Infinity, options) { + await this._ensureInit(); + yield* mapAsyncGenerator(this._videoSampleSink.samples(startTimestamp, endTimestamp, options), (sample) => this._videoSampleToWrappedCanvas(sample)); } /** * Creates an async iterator that yields a canvas for each timestamp in the argument. This method uses an optimized @@ -4761,9 +18813,11 @@ var artplayerProxyMediabunny = (function() { * no frame is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - canvasesAtTimestamps(timestamps) { - return mapAsyncGenerator(this._videoSampleSink.samplesAtTimestamps(timestamps), (sample) => sample && this._videoSampleToWrappedCanvas(sample)); + async *canvasesAtTimestamps(timestamps, options) { + await this._ensureInit(); + yield* mapAsyncGenerator(this._videoSampleSink.samplesAtTimestamps(timestamps, options), (sample) => sample && this._videoSampleToWrappedCanvas(sample)); } } class AudioDecoderWrapper extends DecoderWrapper { @@ -5029,7 +19083,7 @@ var artplayerProxyMediabunny = (function() { if (!await this._track.canDecode()) { throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track."); } - const codec = this._track.codec; + const codec = await this._track.getCodec(); const decoderConfig = await this._track.getDecoderConfig(); assert(codec && decoderConfig); if (PCM_AUDIO_CODECS.includes(decoderConfig.codec)) { @@ -5048,10 +19102,11 @@ var artplayerProxyMediabunny = (function() { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getSample(timestamp) { + async getSample(timestamp, options = {}) { validateTimestamp(timestamp); - for await (const sample of this.mediaSamplesAtTimestamps([timestamp])) { + for await (const sample of this.mediaSamplesAtTimestamps([timestamp], options)) { return sample; } throw new Error("Internal error: Iterator returned nothing."); @@ -5062,9 +19117,10 @@ var artplayerProxyMediabunny = (function() { * * @param startTimestamp - The timestamp in seconds at which to start yielding samples (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding samples (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - samples(startTimestamp = 0, endTimestamp = Infinity) { - return this.mediaSamplesInRange(startTimestamp, endTimestamp); + samples(startTimestamp = 0, endTimestamp = Infinity, options = {}) { + return this.mediaSamplesInRange(startTimestamp, endTimestamp, options); } /** * Creates an async iterator that yields an audio sample for each timestamp in the argument. This method @@ -5073,9 +19129,10 @@ var artplayerProxyMediabunny = (function() { * yield null if no sample is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - samplesAtTimestamps(timestamps) { - return this.mediaSamplesAtTimestamps(timestamps); + samplesAtTimestamps(timestamps, options = {}) { + return this.mediaSamplesAtTimestamps(timestamps, options); } } class AudioBufferSink { @@ -5102,10 +19159,11 @@ var artplayerProxyMediabunny = (function() { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getBuffer(timestamp) { + async getBuffer(timestamp, options) { validateTimestamp(timestamp); - const data = await this._audioSampleSink.getSample(timestamp); + const data = await this._audioSampleSink.getSample(timestamp, options); return data && this._audioSampleToWrappedArrayBuffer(data); } /** @@ -5114,9 +19172,10 @@ var artplayerProxyMediabunny = (function() { * * @param startTimestamp - The timestamp in seconds at which to start yielding buffers (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding buffers (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - buffers(startTimestamp = 0, endTimestamp = Infinity) { - return mapAsyncGenerator(this._audioSampleSink.samples(startTimestamp, endTimestamp), (data) => this._audioSampleToWrappedArrayBuffer(data)); + buffers(startTimestamp = 0, endTimestamp = Infinity, options) { + return mapAsyncGenerator(this._audioSampleSink.samples(startTimestamp, endTimestamp, options), (data) => this._audioSampleToWrappedArrayBuffer(data)); } /** * Creates an async iterator that yields an audio buffer for each timestamp in the argument. This method @@ -5125,9 +19184,10 @@ var artplayerProxyMediabunny = (function() { * yield null if no buffer is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - buffersAtTimestamps(timestamps) { - return mapAsyncGenerator(this._audioSampleSink.samplesAtTimestamps(timestamps), (data) => data && this._audioSampleToWrappedArrayBuffer(data)); + buffersAtTimestamps(timestamps, options) { + return mapAsyncGenerator(this._audioSampleSink.samplesAtTimestamps(timestamps, options), (data) => data && this._audioSampleToWrappedArrayBuffer(data)); } } class InputTrack { @@ -5149,52 +19209,141 @@ var artplayerProxyMediabunny = (function() { return this._backing.getId(); } /** - * The identifier of the codec used internally by the container. It is not homogenized by Mediabunny + * The 1-based index of this track among all tracks of the same type in the input file. For example, the first + * video track has number 1, the second video track has number 2, and so on. The index refers to the order in + * which the tracks are returned by {@link Input.getTracks}. + */ + get number() { + return this._backing.getNumber(); + } + /** + * Returns the identifier of the codec used internally by the container. It is not homogenized by Mediabunny * and depends entirely on the container format. * - * This field can be used to determine the codec of a track in case Mediabunny doesn't know that codec. + * This method can be used to determine the codec of a track in case Mediabunny doesn't know that codec. * - * - For ISOBMFF files, this field returns the name of the Sample Description Box (e.g. `'avc1'`). - * - For Matroska files, this field returns the value of the `CodecID` element. - * - For WAVE files, this field returns the value of the format tag in the `'fmt '` chunk. - * - For ADTS files, this field contains the `MPEG-4 Audio Object Type`. - * - In all other cases, this field is `null`. + * - For ISOBMFF files, this resolves to the name of the Sample Description Box (e.g. `'avc1'`). + * - For Matroska files, this resolves to the value of the `CodecID` element. + * - For WAVE files, this resolves to the value of the format tag in the `'fmt '` chunk. + * - For ADTS files, this resolves to the `MPEG-4 Audio Object Type`. + * - For MPEG-TS files, this resolves to the `streamType` value from the Program Map Table. + * - In all other cases, this resolves to `null`. */ - get internalCodecId() { + async getInternalCodecId() { return this._backing.getInternalCodecId(); } /** - * The ISO 639-2/T language code for this track. If the language is unknown, this field is `'und'` (undetermined). + * See {@link InputTrack.getInternalCodecId}. + * @deprecated Use {@link InputTrack.getInternalCodecId} instead. */ - get languageCode() { + get internalCodecId() { + return requireSync(this._backing.getInternalCodecId(), "internalCodecId", "getInternalCodecId"); + } + /** + * Returns the ISO 639-2/T language code for this track. If the language is unknown, this resolves to `'und'` + * (undetermined). + */ + async getLanguageCode() { return this._backing.getLanguageCode(); } - /** A user-defined name for this track. */ - get name() { + /** + * The ISO 639-2/T language code for this track. If the language is unknown, this field is `'und'` (undetermined). + * @deprecated Use {@link InputTrack.getLanguageCode} instead. + */ + get languageCode() { + return requireSync(this._backing.getLanguageCode(), "languageCode", "getLanguageCode"); + } + /** Returns the user-defined name for this track. */ + async getName() { return this._backing.getName(); } + /** + * A user-defined name for this track. + * @deprecated Use {@link InputTrack.getName} instead. + */ + get name() { + return requireSync(this._backing.getName(), "name", "getName"); + } + /** + * Returns a positive number x such that all timestamps and durations of all packets of this track are + * integer multiples of 1/x. + */ + async getTimeResolution() { + return this._backing.getTimeResolution(); + } /** * A positive number x such that all timestamps and durations of all packets of this track are * integer multiples of 1/x. + * @deprecated Use {@link InputTrack.getTimeResolution} instead. */ get timeResolution() { - return this._backing.getTimeResolution(); + return requireSync(this._backing.getTimeResolution(), "timeResolution", "getTimeResolution"); } - /** The track's disposition, i.e. information about its intended usage. */ - get disposition() { + /** + * Returns whether the timestamps of this track are relative to the Unix epoch (January 1, 1970 00:00:00 UTC). + * When `true`, each timestamp maps to a definitive point in time. + */ + async isRelativeToUnixEpoch() { + return this._backing.isRelativeToUnixEpoch(); + } + /** Returns the track's disposition, i.e. information about its intended usage. */ + async getDisposition() { return this._backing.getDisposition(); } + /** + * The track's disposition, i.e. information about its intended usage. + * @deprecated Use {@link InputTrack.getDisposition} instead. + */ + get disposition() { + return requireSync(this._backing.getDisposition(), "disposition", "getDisposition"); + } + /** + * Returns the peak bitrate of the track in bits per second, as specified in the track's metadata. This might not + * match the actual media data's bitrate. + */ + async getBitrate() { + return this._backing.getBitrate(); + } + /** + * Returns the average bitrate of the track in bits per second, as specified in the track's metadata. This might + * not match the actual media data's bitrate. + */ + async getAverageBitrate() { + return this._backing.getAverageBitrate(); + } /** * Returns the start timestamp of the first packet of this track, in seconds. While often near zero, this value * may be positive or even negative. A negative starting timestamp means the track's timing has been offset. Samples * with a negative timestamp should not be presented. */ - getFirstTimestamp() { - return this._backing.getFirstTimestamp(); + async getFirstTimestamp() { + const firstPacket = await this._backing.getFirstPacket({ metadataOnly: true }); + return firstPacket?.timestamp ?? 0; } - /** Returns the end timestamp of the last packet of this track, in seconds. */ - computeDuration() { - return this._backing.computeDuration(); + /** + * Returns the end timestamp of the last packet of this track, in seconds. + * + * By default, when the underlying media is live, this method will only resolve once the live stream ends. If you + * want to query the current end timestamp of the stream, set {@link PacketRetrievalOptions.skipLiveWait} to `true` + * in the options. + */ + async computeDuration(options) { + const lastPacket = await this._backing.getPacket(Infinity, { metadataOnly: true, ...options }); + const result = (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); + return roundToDivisor(result, await this.getTimeResolution()); + } + /** + * Gets the duration (end timestamp) in seconds of this track from metadata stored in the file. This value may be + * approximate or diverge from the actual, precise duration returned by `.computeDuration()`, but compared to that + * method, this method is cheaper. When the duration cannot be determined from the file metadata, `null` + * is returned. + * + * By default, when the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set + * {@link DurationMetadataRequestOptions.skipLiveWait} to `true` in the options. + */ + async getDurationFromMetadata(options = {}) { + return this._backing.getDurationFromMetadata(options); } /** * Computes aggregate packet statistics for this track, such as average packet rate or bitrate. @@ -5203,14 +19352,18 @@ var artplayerProxyMediabunny = (function() { * looked at before it can return early; this means, you can use it to aggregate only a subset (prefix) of all * packets. This is very useful for getting a great estimate of video frame rate without having to scan through the * entire file. + * + * By default, when the underlying media is live and `targetPacketCount` is not set, this method will only resolve + * once the live stream ends. If you want to query the current packet statistics of the stream, set + * {@link PacketRetrievalOptions.skipLiveWait} to `true` in the options. */ - async computePacketStats(targetPacketCount = Infinity) { + async computePacketStats(targetPacketCount = Infinity, options) { const sink = new EncodedPacketSink(this); let startTimestamp = Infinity; let endTimestamp = -Infinity; let packetCount = 0; let totalPacketBytes = 0; - for await (const packet of sink.packets(void 0, void 0, { metadataOnly: true })) { + for await (const packet of sink.packets(void 0, void 0, { metadataOnly: true, ...options })) { if (packetCount >= targetPacketCount && packet.timestamp >= endTimestamp) { break; } @@ -5225,43 +19378,282 @@ var artplayerProxyMediabunny = (function() { averageBitrate: packetCount ? Number((8 * totalPacketBytes / (endTimestamp - startTimestamp)).toPrecision(16)) : 0 }; } + /** + * Whether or not this track is currently live, meaning the media's end is still unknown. + * + * The value returned by this method may change over time as the track stops being live. To keep track of the + * track's live status, poll this method at the track's refresh interval + * via {@link InputTrack.getLiveRefreshInterval}. + */ + async isLive() { + return await this._backing.getLiveRefreshInterval() !== null; + } + /** + * Returns the track's live refresh interval in seconds, or `null` if the track is not live. This interval describes + * the time it takes, on average, for new live media data to become available. + */ + async getLiveRefreshInterval() { + return this._backing.getLiveRefreshInterval(); + } + /** + * Returns `true` if this track can be paired with the given track. Two tracks being pairable means they can be + * presented (displayed) together. + * + * Returns `false` if `other` equals `this`. + */ + canBePairedWith(other) { + if (!(other instanceof InputTrack)) { + throw new TypeError("other must be an InputTrack."); + } + if (this.input !== other.input || this === other) { + return false; + } + return (this._backing.getPairingMask() & other._backing.getPairingMask()) !== 0n; + } + /** + * Gets the list of other tracks that can be paired with this track. An optional query can be provided to narrow + * down the results. + */ + async getPairableTracks(query) { + return this.input.getTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** + * Gets the list of other video tracks that can be paired with this track. An optional query can be provided to + * narrow down the results. + */ + async getPairableVideoTracks(query) { + return this.input.getVideoTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** + * Gets the list of other audio tracks that can be paired with this track. An optional query can be provided to + * narrow down the results. + */ + async getPairableAudioTracks(query) { + return this.input.getAudioTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns the primary track that can be paired with this track, optionally steered by the provided query. */ + async getPrimaryPairableVideoTrack(query) { + return this.input.getPrimaryVideoTrack(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns the primary track that can be paired with this track, optionally steered by the provided query. */ + async getPrimaryPairableAudioTrack(query) { + return this.input.getPrimaryAudioTrack(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns `true` if there is another track that can be paired with this track. */ + async hasPairableTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + const tracks = await this.input.getTracks(); + for (const track of tracks) { + if (!this.canBePairedWith(track)) { + continue; + } + if (!predicate || await predicate(track)) { + return true; + } + } + return false; + } + /** Returns `true` if there is a video track that can be paired with this track. */ + hasPairableVideoTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + return this.hasPairableTrack(async (x) => x.isVideoTrack() && (!predicate || await predicate(x))); + } + /** Returns `true` if there is an audio track that can be paired with this track. */ + hasPairableAudioTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + return this.hasPairableTrack(async (x) => x.isAudioTrack() && (!predicate || await predicate(x))); + } } + const requireSync = (value, getterName, asyncName) => { + if (value instanceof Promise) { + throw new Error(`'${getterName}' is deprecated and not available synchronously for this track. Use the preferred '${asyncName}()' instead.`); + } + return value; + }; + const toValidatedPredicate = (predicate) => { + if (predicate !== void 0 && typeof predicate !== "function") { + throw new TypeError("predicate, when provided, must be a function."); + } + return predicate ? (track) => { + const handle = (result2) => { + if (typeof result2 !== "boolean") { + throw new TypeError("predicate must return or resolve to a boolean value."); + } + return result2; + }; + const result = predicate(track); + if (result instanceof Promise) { + return result.then(handle); + } + return handle(result); + } : void 0; + }; class InputVideoTrack extends InputTrack { /** @internal */ constructor(input, backing) { super(input, backing); + this._pixelAspectRatioCache = null; this._backing = backing; } get type() { return "video"; } - get codec() { + /** The codec of the track's packets. */ + async getCodec() { return this._backing.getCodec(); } - /** The width in pixels of the track's coded samples, before any transformations or rotations. */ - get codedWidth() { + /** + * The codec of the track's packets. + * @deprecated Use {@link InputVideoTrack.getCodec} instead. + */ + get codec() { + return requireSync(this._backing.getCodec(), "codec", "getCodec"); + } + async hasOnlyKeyPackets() { + return await this._backing.getHasOnlyKeyPackets?.() ?? false; + } + /** Returns the width in pixels of the track's coded samples, before any transformations or rotations. */ + async getCodedWidth() { return this._backing.getCodedWidth(); } - /** The height in pixels of the track's coded samples, before any transformations or rotations. */ - get codedHeight() { + /** + * The width in pixels of the track's coded samples, before any transformations or rotations. + * @deprecated Use {@link InputVideoTrack.getCodedWidth} instead. + */ + get codedWidth() { + return requireSync(this._backing.getCodedWidth(), "codedWidth", "getCodedWidth"); + } + /** Returns the height in pixels of the track's coded samples, before any transformations or rotations. */ + async getCodedHeight() { return this._backing.getCodedHeight(); } - /** The angle in degrees by which the track's frames should be rotated (clockwise). */ - get rotation() { + /** + * The height in pixels of the track's coded samples, before any transformations or rotations. + * @deprecated Use {@link InputVideoTrack.getCodedHeight} instead. + */ + get codedHeight() { + return requireSync(this._backing.getCodedHeight(), "codedHeight", "getCodedHeight"); + } + /** Returns the angle in degrees by which the track's frames should be rotated (clockwise). */ + async getRotation() { return this._backing.getRotation(); } - /** The width in pixels of the track's frames after rotation. */ - get displayWidth() { - const rotation = this._backing.getRotation(); - return rotation % 180 === 0 ? this._backing.getCodedWidth() : this._backing.getCodedHeight(); + /** + * The angle in degrees by which the track's frames should be rotated (clockwise). + * @deprecated Use {@link InputVideoTrack.getRotation} instead. + */ + get rotation() { + return requireSync(this._backing.getRotation(), "rotation", "getRotation"); } - /** The height in pixels of the track's frames after rotation. */ + /** + * Returns the width of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + */ + async getSquarePixelWidth() { + return this._backing.getSquarePixelWidth(); + } + /** + * The width of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + * @deprecated Use {@link InputVideoTrack.getSquarePixelWidth} instead. + */ + get squarePixelWidth() { + return requireSync(this._backing.getSquarePixelWidth(), "squarePixelWidth", "getSquarePixelWidth"); + } + /** + * Returns the height of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + */ + async getSquarePixelHeight() { + return this._backing.getSquarePixelHeight(); + } + /** + * The height of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + * @deprecated Use {@link InputVideoTrack.getSquarePixelHeight} instead. + */ + get squarePixelHeight() { + return requireSync(this._backing.getSquarePixelHeight(), "squarePixelHeight", "getSquarePixelHeight"); + } + /** + * Returns the pixel aspect ratio of the track's frames as a rational number in its reduced form. Most videos use + * square pixels (1:1). + */ + async getPixelAspectRatio() { + return this._pixelAspectRatioCache ?? (this._pixelAspectRatioCache = simplifyRational({ + num: await this.getSquarePixelWidth() * await this.getCodedHeight(), + den: await this.getSquarePixelHeight() * await this.getCodedWidth() + })); + } + /** + * The pixel aspect ratio of the track's frames, as a rational number in its reduced form. Most videos use + * square pixels (1:1). + * @deprecated Use {@link InputVideoTrack.getPixelAspectRatio} instead. + */ + get pixelAspectRatio() { + return this._pixelAspectRatioCache ?? (this._pixelAspectRatioCache = simplifyRational({ + num: requireSync(this._backing.getSquarePixelWidth(), "pixelAspectRatio", "getPixelAspectRatio") * requireSync(this._backing.getCodedHeight(), "pixelAspectRatio", "getPixelAspectRatio"), + den: requireSync(this._backing.getSquarePixelHeight(), "pixelAspectRatio", "getPixelAspectRatio") * requireSync(this._backing.getCodedWidth(), "pixelAspectRatio", "getPixelAspectRatio") + })); + } + /** Returns the display width of the track's frames in pixels, after aspect ratio adjustment and rotation. */ + async getDisplayWidth() { + const metadata = await this._backing.getMetadataDisplayWidth?.(); + if (metadata != null) { + return metadata; + } + const rotation = await this.getRotation(); + return rotation % 180 === 0 ? this.getSquarePixelWidth() : this.getSquarePixelHeight(); + } + /** + * The display width of the track's frames in pixels, after aspect ratio adjustment and rotation. + * @deprecated Use {@link InputVideoTrack.getDisplayWidth} instead. + */ + get displayWidth() { + const metadataRaw = this._backing.getMetadataDisplayWidth?.(); + if (metadataRaw !== void 0) { + const metadata = requireSync(metadataRaw, "displayWidth", "getDisplayWidth"); + if (metadata !== null) { + return metadata; + } + } + const rotation = requireSync(this._backing.getRotation(), "displayWidth", "getDisplayWidth"); + const value = rotation % 180 === 0 ? this._backing.getSquarePixelWidth() : this._backing.getSquarePixelHeight(); + return requireSync(value, "displayWidth", "getDisplayWidth"); + } + /** Returns the display height of the track's frames in pixels, after aspect ratio adjustment and rotation. */ + async getDisplayHeight() { + const metadata = await this._backing.getMetadataDisplayHeight?.(); + if (metadata != null) { + return metadata; + } + const rotation = await this.getRotation(); + return rotation % 180 === 0 ? this.getSquarePixelHeight() : this.getSquarePixelWidth(); + } + /** + * The display height of the track's frames in pixels, after aspect ratio adjustment and rotation. + * @deprecated Use {@link InputVideoTrack.getDisplayHeight} instead. + */ get displayHeight() { - const rotation = this._backing.getRotation(); - return rotation % 180 === 0 ? this._backing.getCodedHeight() : this._backing.getCodedWidth(); + const metadataRaw = this._backing.getMetadataDisplayHeight?.(); + if (metadataRaw !== void 0) { + const metadata = requireSync(metadataRaw, "displayHeight", "getDisplayHeight"); + if (metadata !== null) { + return metadata; + } + } + const rotation = requireSync(this._backing.getRotation(), "displayHeight", "getDisplayHeight"); + const value = rotation % 180 === 0 ? this._backing.getSquarePixelHeight() : this._backing.getSquarePixelWidth(); + return requireSync(value, "displayHeight", "getDisplayHeight"); } /** Returns the color space of the track's samples. */ - getColorSpace() { + async getColorSpace() { return this._backing.getColorSpace(); } /** If this method returns true, the track's samples use a high dynamic range (HDR). */ @@ -5270,7 +19662,7 @@ var artplayerProxyMediabunny = (function() { return colorSpace.primaries === "bt2020" || colorSpace.primaries === "smpte432" || colorSpace.transfer === "pg" || colorSpace.transfer === "hlg" || colorSpace.matrix === "bt2020-ncl"; } /** Checks if this track may contain transparent samples with alpha data. */ - canBeTransparent() { + async canBeTransparent() { return this._backing.canBeTransparent(); } /** @@ -5278,10 +19670,14 @@ var artplayerProxyMediabunny = (function() { * track's packets using a [`VideoDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder). Returns * null if the track's codec is unknown. */ - getDecoderConfig() { + async getDecoderConfig() { return this._backing.getDecoderConfig(); } async getCodecParameterString() { + const fromMetadata = await this._backing.getMetadataCodecParameterString?.(); + if (fromMetadata != null) { + return fromMetadata; + } const decoderConfig = await this._backing.getDecoderConfig(); return decoderConfig?.codec ?? null; } @@ -5291,7 +19687,7 @@ var artplayerProxyMediabunny = (function() { if (!decoderConfig) { return false; } - const codec = this._backing.getCodec(); + const codec = await this._backing.getCodec(); assert(codec !== null); if (customVideoDecoders.some((x) => x.supports(codec, decoderConfig))) { return true; @@ -5313,12 +19709,13 @@ var artplayerProxyMediabunny = (function() { if (packet.isMetadataOnly) { throw new TypeError("packet must not be metadata-only to determine its type."); } - if (this.codec === null) { + const codec = await this.getCodec(); + if (codec === null) { return null; } const decoderConfig = await this.getDecoderConfig(); assert(decoderConfig); - return determineVideoPacketType(this.codec, decoderConfig, packet.data); + return determineVideoPacketType(codec, decoderConfig, packet.data); } } class InputAudioTrack extends InputTrack { @@ -5330,26 +19727,55 @@ var artplayerProxyMediabunny = (function() { get type() { return "audio"; } - get codec() { + /** The codec of the track's packets. */ + async getCodec() { return this._backing.getCodec(); } - /** The number of audio channels in the track. */ - get numberOfChannels() { + /** + * The codec of the track's packets. + * @deprecated Use {@link InputAudioTrack.getCodec} instead. + */ + get codec() { + return requireSync(this._backing.getCodec(), "codec", "getCodec"); + } + async hasOnlyKeyPackets() { + return await this._backing.getHasOnlyKeyPackets?.() ?? true; + } + /** Returns the number of audio channels in the track. */ + async getNumberOfChannels() { return this._backing.getNumberOfChannels(); } - /** The track's audio sample rate in hertz. */ - get sampleRate() { + /** + * The number of audio channels in the track. + * @deprecated Use {@link InputAudioTrack.getNumberOfChannels} instead. + */ + get numberOfChannels() { + return requireSync(this._backing.getNumberOfChannels(), "numberOfChannels", "getNumberOfChannels"); + } + /** Returns the track's audio sample rate in hertz. */ + async getSampleRate() { return this._backing.getSampleRate(); } + /** + * The track's audio sample rate in hertz. + * @deprecated Use {@link InputAudioTrack.getSampleRate} instead. + */ + get sampleRate() { + return requireSync(this._backing.getSampleRate(), "sampleRate", "getSampleRate"); + } /** * Returns the [decoder configuration](https://www.w3.org/TR/webcodecs/#audio-decoder-config) for decoding the * track's packets using an [`AudioDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder). Returns * null if the track's codec is unknown. */ - getDecoderConfig() { + async getDecoderConfig() { return this._backing.getDecoderConfig(); } async getCodecParameterString() { + const fromMetadata = await this._backing.getMetadataCodecParameterString?.(); + if (fromMetadata != null) { + return fromMetadata; + } const decoderConfig = await this._backing.getDecoderConfig(); return decoderConfig?.codec ?? null; } @@ -5359,7 +19785,7 @@ var artplayerProxyMediabunny = (function() { if (!decoderConfig) { return false; } - const codec = this._backing.getCodec(); + const codec = await this._backing.getCodec(); assert(codec !== null); if (customAudioDecoders.some((x) => x.supports(codec, decoderConfig))) { return true; @@ -5382,4698 +19808,744 @@ var artplayerProxyMediabunny = (function() { if (!(packet instanceof EncodedPacket)) { throw new TypeError("packet must be an EncodedPacket."); } - if (this.codec === null) { + if (await this.getCodec() === null) { return null; } return "key"; } } - const buildIsobmffMimeType = (info) => { - const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; - let string = base + (info.isQuickTime ? "quicktime" : "mp4"); - if (info.codecStrings.length > 0) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; - } - return string; + const desc = (value) => { + return -(value ?? -Infinity); }; - const MIN_BOX_HEADER_SIZE = 8; - const MAX_BOX_HEADER_SIZE = 16; - const readBoxHeader = (slice) => { - let totalSize = readU32Be(slice); - const name = readAscii(slice, 4); - let headerSize = 8; - const hasLargeSize = totalSize === 1; - if (hasLargeSize) { - totalSize = readU64Be(slice); - headerSize = 16; - } - const contentSize = totalSize - headerSize; - if (contentSize < 0) { - return null; - } - return { name, totalSize, headerSize, contentSize }; + const prefer = (value) => { + return -value; }; - const readFixed_16_16 = (slice) => { - return readI32Be(slice) / 65536; - }; - const readFixed_2_30 = (slice) => { - return readI32Be(slice) / 1073741824; - }; - const readIsomVariableInteger = (slice) => { - let result = 0; - for (let i = 0; i < 4; i++) { - result <<= 7; - const nextByte = readU8(slice); - result |= nextByte & 127; - if ((nextByte & 128) === 0) { - break; - } + const toValidatedInputTrackQuery = (query) => { + if (typeof query !== "object" || !query) { + throw new TypeError("query must be an object."); } - return result; - }; - const readMetadataStringShort = (slice) => { - let stringLength = readU16Be(slice); - slice.skip(2); - stringLength = Math.min(stringLength, slice.remainingLength); - return textDecoder.decode(readBytes(slice, stringLength)); - }; - const readDataBox = (slice) => { - const header = readBoxHeader(slice); - if (!header || header.name !== "data") { - return null; + if (query.filter !== void 0 && typeof query.filter !== "function") { + throw new TypeError("query.filter, when provided, must be a function."); } - if (slice.remainingLength < 8) { - return null; - } - const typeIndicator = readU32Be(slice); - slice.skip(4); - const data = readBytes(slice, header.contentSize - 8); - switch (typeIndicator) { - case 1: - return textDecoder.decode(data); - // UTF-8 - case 2: - return new TextDecoder("utf-16be").decode(data); - // UTF-16-BE - case 13: - return new RichImageData(data, "image/jpeg"); - case 14: - return new RichImageData(data, "image/png"); - case 27: - return new RichImageData(data, "image/bmp"); - default: - return data; - } - }; - class IsobmffDemuxer extends Demuxer { - constructor(input) { - super(input); - this.moovSlice = null; - this.currentTrack = null; - this.tracks = []; - this.metadataPromise = null; - this.movieTimescale = -1; - this.movieDurationInTimescale = -1; - this.isQuickTime = false; - this.metadataTags = {}; - this.currentMetadataKeys = null; - this.isFragmented = false; - this.fragmentTrackDefaults = []; - this.currentFragment = null; - this.lastReadFragment = null; - this.reader = input._reader; - } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); - } - async getTracks() { - await this.readMetadata(); - return this.tracks.map((track) => track.inputTrack); - } - async getMimeType() { - await this.readMetadata(); - const codecStrings = await Promise.all(this.tracks.map((x) => x.inputTrack.getCodecParameterString())); - return buildIsobmffMimeType({ - isQuickTime: this.isQuickTime, - hasVideo: this.tracks.some((x) => x.info?.type === "video"), - hasAudio: this.tracks.some((x) => x.info?.type === "audio"), - codecStrings: codecStrings.filter(Boolean) - }); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } - readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const startPos = currentPos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - if (boxInfo.name === "ftyp") { - const majorBrand = readAscii(slice, 4); - this.isQuickTime = majorBrand === "qt "; - } else if (boxInfo.name === "moov") { - let moovSlice = this.reader.requestSlice(slice.filePos, boxInfo.contentSize); - if (moovSlice instanceof Promise) - moovSlice = await moovSlice; - if (!moovSlice) - break; - this.moovSlice = moovSlice; - this.readContiguousBoxes(this.moovSlice); - this.tracks.sort((a, b) => Number(b.disposition.default) - Number(a.disposition.default)); - for (const track of this.tracks) { - const previousSegmentDurationsInSeconds = track.editListPreviousSegmentDurations / this.movieTimescale; - track.editListOffset -= Math.round(previousSegmentDurationsInSeconds * track.timescale); - } - break; - } - currentPos = startPos + boxInfo.totalSize; - } - if (this.isFragmented && this.reader.fileSize !== null) { - let lastWordSlice = this.reader.requestSlice(this.reader.fileSize - 4, 4); - if (lastWordSlice instanceof Promise) - lastWordSlice = await lastWordSlice; - assert(lastWordSlice); - const lastWord = readU32Be(lastWordSlice); - const potentialMfraPos = this.reader.fileSize - lastWord; - if (potentialMfraPos >= 0 && potentialMfraPos <= this.reader.fileSize - MAX_BOX_HEADER_SIZE) { - let mfraHeaderSlice = this.reader.requestSliceRange(potentialMfraPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (mfraHeaderSlice instanceof Promise) - mfraHeaderSlice = await mfraHeaderSlice; - if (mfraHeaderSlice) { - const boxInfo = readBoxHeader(mfraHeaderSlice); - if (boxInfo && boxInfo.name === "mfra") { - let mfraSlice = this.reader.requestSlice(mfraHeaderSlice.filePos, boxInfo.contentSize); - if (mfraSlice instanceof Promise) - mfraSlice = await mfraSlice; - if (mfraSlice) { - this.readContiguousBoxes(mfraSlice); - } - } - } - } - } - })()); - } - getSampleTableForTrack(internalTrack) { - if (internalTrack.sampleTable) { - return internalTrack.sampleTable; - } - const sampleTable = { - sampleTimingEntries: [], - sampleCompositionTimeOffsets: [], - sampleSizes: [], - keySampleIndices: null, - chunkOffsets: [], - sampleToChunk: [], - presentationTimestamps: null, - presentationTimestampIndexMap: null - }; - internalTrack.sampleTable = sampleTable; - assert(this.moovSlice); - const stblContainerSlice = this.moovSlice.slice(internalTrack.sampleTableByteOffset); - this.currentTrack = internalTrack; - this.traverseBox(stblContainerSlice); - this.currentTrack = null; - const isPcmCodec = internalTrack.info?.type === "audio" && internalTrack.info.codec && PCM_AUDIO_CODECS.includes(internalTrack.info.codec); - if (isPcmCodec && sampleTable.sampleCompositionTimeOffsets.length === 0) { - assert(internalTrack.info?.type === "audio"); - const pcmInfo = parsePcmCodec(internalTrack.info.codec); - const newSampleTimingEntries = []; - const newSampleSizes = []; - for (let i = 0; i < sampleTable.sampleToChunk.length; i++) { - const chunkEntry = sampleTable.sampleToChunk[i]; - const nextEntry = sampleTable.sampleToChunk[i + 1]; - const chunkCount = (nextEntry ? nextEntry.startChunkIndex : sampleTable.chunkOffsets.length) - chunkEntry.startChunkIndex; - for (let j = 0; j < chunkCount; j++) { - const startSampleIndex = chunkEntry.startSampleIndex + j * chunkEntry.samplesPerChunk; - const endSampleIndex = startSampleIndex + chunkEntry.samplesPerChunk; - const startTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, startSampleIndex, (x) => x.startIndex); - const startTimingEntry = sampleTable.sampleTimingEntries[startTimingEntryIndex]; - const endTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, endSampleIndex, (x) => x.startIndex); - const endTimingEntry = sampleTable.sampleTimingEntries[endTimingEntryIndex]; - const firstSampleTimestamp = startTimingEntry.startDecodeTimestamp + (startSampleIndex - startTimingEntry.startIndex) * startTimingEntry.delta; - const lastSampleTimestamp = endTimingEntry.startDecodeTimestamp + (endSampleIndex - endTimingEntry.startIndex) * endTimingEntry.delta; - const delta = lastSampleTimestamp - firstSampleTimestamp; - const lastSampleTimingEntry = last(newSampleTimingEntries); - if (lastSampleTimingEntry && lastSampleTimingEntry.delta === delta) { - lastSampleTimingEntry.count++; - } else { - newSampleTimingEntries.push({ - startIndex: chunkEntry.startChunkIndex + j, - startDecodeTimestamp: firstSampleTimestamp, - count: 1, - delta - }); - } - const chunkSize = chunkEntry.samplesPerChunk * pcmInfo.sampleSize * internalTrack.info.numberOfChannels; - newSampleSizes.push(chunkSize); - } - chunkEntry.startSampleIndex = chunkEntry.startChunkIndex; - chunkEntry.samplesPerChunk = 1; - } - sampleTable.sampleTimingEntries = newSampleTimingEntries; - sampleTable.sampleSizes = newSampleSizes; - } - if (sampleTable.sampleCompositionTimeOffsets.length > 0) { - sampleTable.presentationTimestamps = []; - for (const entry of sampleTable.sampleTimingEntries) { - for (let i = 0; i < entry.count; i++) { - sampleTable.presentationTimestamps.push({ - presentationTimestamp: entry.startDecodeTimestamp + i * entry.delta, - sampleIndex: entry.startIndex + i - }); - } - } - for (const entry of sampleTable.sampleCompositionTimeOffsets) { - for (let i = 0; i < entry.count; i++) { - const sampleIndex = entry.startIndex + i; - const sample = sampleTable.presentationTimestamps[sampleIndex]; - if (!sample) { - continue; - } - sample.presentationTimestamp += entry.offset; - } - } - sampleTable.presentationTimestamps.sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); - sampleTable.presentationTimestampIndexMap = Array(sampleTable.presentationTimestamps.length).fill(-1); - for (let i = 0; i < sampleTable.presentationTimestamps.length; i++) { - sampleTable.presentationTimestampIndexMap[sampleTable.presentationTimestamps[i].sampleIndex] = i; - } - } - return sampleTable; - } - async readFragment(startPos) { - if (this.lastReadFragment?.moofOffset === startPos) { - return this.lastReadFragment; - } - let headerSlice = this.reader.requestSliceRange(startPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const moofBoxInfo = readBoxHeader(headerSlice); - assert(moofBoxInfo?.name === "moof"); - let entireSlice = this.reader.requestSlice(startPos, moofBoxInfo.totalSize); - if (entireSlice instanceof Promise) - entireSlice = await entireSlice; - assert(entireSlice); - this.traverseBox(entireSlice); - const fragment = this.lastReadFragment; - assert(fragment && fragment.moofOffset === startPos); - for (const [, trackData] of fragment.trackData) { - const track = trackData.track; - const { fragmentPositionCache } = track; - if (!trackData.startTimestampIsFinal) { - const lookupEntry = track.fragmentLookupTable.find((x) => x.moofOffset === fragment.moofOffset); - if (lookupEntry) { - offsetFragmentTrackDataByTimestamp(trackData, lookupEntry.timestamp); - } else { - const lastCacheIndex = binarySearchLessOrEqual(fragmentPositionCache, fragment.moofOffset - 1, (x) => x.moofOffset); - if (lastCacheIndex !== -1) { - const lastCache = fragmentPositionCache[lastCacheIndex]; - offsetFragmentTrackDataByTimestamp(trackData, lastCache.endTimestamp); - } - } - trackData.startTimestampIsFinal = true; - } - const insertionIndex = binarySearchLessOrEqual(fragmentPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); - if (insertionIndex === -1 || fragmentPositionCache[insertionIndex].moofOffset !== fragment.moofOffset) { - fragmentPositionCache.splice(insertionIndex + 1, 0, { - moofOffset: fragment.moofOffset, - startTimestamp: trackData.startTimestamp, - endTimestamp: trackData.endTimestamp - }); - } - } - return fragment; - } - readContiguousBoxes(slice) { - const startIndex = slice.filePos; - while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { - const foundBox = this.traverseBox(slice); - if (!foundBox) { - break; - } - } - } - // eslint-disable-next-line @stylistic/generator-star-spacing - *iterateContiguousBoxes(slice) { - const startIndex = slice.filePos; - while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { - const startPos = slice.filePos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - yield { boxInfo, slice }; - slice.filePos = startPos + boxInfo.totalSize; - } - } - traverseBox(slice) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G; - const startPos = slice.filePos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - return false; - } - const contentStartPos = slice.filePos; - const boxEndPos = startPos + boxInfo.totalSize; - switch (boxInfo.name) { - case "mdia": - case "minf": - case "dinf": - case "mfra": - case "edts": - { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "mvhd": - { - const version = readU8(slice); - slice.skip(3); - if (version === 1) { - slice.skip(8 + 8); - this.movieTimescale = readU32Be(slice); - this.movieDurationInTimescale = readU64Be(slice); - } else { - slice.skip(4 + 4); - this.movieTimescale = readU32Be(slice); - this.movieDurationInTimescale = readU32Be(slice); - } - } - break; - case "trak": - { - const track = { - id: -1, - demuxer: this, - inputTrack: null, - disposition: { - ...DEFAULT_TRACK_DISPOSITION - }, - info: null, - timescale: -1, - durationInMovieTimescale: -1, - durationInMediaTimescale: -1, - rotation: 0, - internalCodecId: null, - name: null, - languageCode: UNDETERMINED_LANGUAGE, - sampleTableByteOffset: -1, - sampleTable: null, - fragmentLookupTable: [], - currentFragmentState: null, - fragmentPositionCache: [], - editListPreviousSegmentDurations: 0, - editListOffset: 0 - }; - this.currentTrack = track; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - if (track.id !== -1 && track.timescale !== -1 && track.info !== null) { - if (track.info.type === "video" && track.info.width !== -1) { - const videoTrack = track; - track.inputTrack = new InputVideoTrack(this.input, new IsobmffVideoTrackBacking(videoTrack)); - this.tracks.push(track); - } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { - const audioTrack = track; - track.inputTrack = new InputAudioTrack(this.input, new IsobmffAudioTrackBacking(audioTrack)); - this.tracks.push(track); - } - } - this.currentTrack = null; - } - break; - case "tkhd": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - const flags = readU24Be(slice); - const trackEnabled = !!(flags & 1); - track.disposition.default = trackEnabled; - if (version === 0) { - slice.skip(8); - track.id = readU32Be(slice); - slice.skip(4); - track.durationInMovieTimescale = readU32Be(slice); - } else if (version === 1) { - slice.skip(16); - track.id = readU32Be(slice); - slice.skip(4); - track.durationInMovieTimescale = readU64Be(slice); - } else { - throw new Error(`Incorrect track header version ${version}.`); - } - slice.skip(2 * 4 + 2 + 2 + 2 + 2); - const matrix = [ - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice), - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice), - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice) - ]; - const rotation = normalizeRotation(roundToMultiple(extractRotationFromMatrix(matrix), 90)); - assert(rotation === 0 || rotation === 90 || rotation === 180 || rotation === 270); - track.rotation = rotation; - } - break; - case "elst": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - slice.skip(3); - let relevantEntryFound = false; - let previousSegmentDurations = 0; - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const segmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); - const mediaTime = version === 1 ? readI64Be(slice) : readI32Be(slice); - const mediaRate = readFixed_16_16(slice); - if (segmentDuration === 0) { - continue; - } - if (relevantEntryFound) { - console.warn("Unsupported edit list: multiple edits are not currently supported. Only using first edit."); - break; - } - if (mediaTime === -1) { - previousSegmentDurations += segmentDuration; - continue; - } - if (mediaRate !== 1) { - console.warn("Unsupported edit list entry: media rate must be 1."); - break; - } - track.editListPreviousSegmentDurations = previousSegmentDurations; - track.editListOffset = mediaTime; - relevantEntryFound = true; - } - } - break; - case "mdhd": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - slice.skip(3); - if (version === 0) { - slice.skip(8); - track.timescale = readU32Be(slice); - track.durationInMediaTimescale = readU32Be(slice); - } else if (version === 1) { - slice.skip(16); - track.timescale = readU32Be(slice); - track.durationInMediaTimescale = readU64Be(slice); - } - let language = readU16Be(slice); - if (language > 0) { - track.languageCode = ""; - for (let i = 0; i < 3; i++) { - track.languageCode = String.fromCharCode(96 + (language & 31)) + track.languageCode; - language >>= 5; - } - if (!isIso639Dash2LanguageCode(track.languageCode)) { - track.languageCode = UNDETERMINED_LANGUAGE; - } - } - } - break; - case "hdlr": - { - const track = this.currentTrack; - if (!track) { - break; - } - slice.skip(8); - const handlerType = readAscii(slice, 4); - if (handlerType === "vide") { - track.info = { - type: "video", - width: -1, - height: -1, - codec: null, - codecDescription: null, - colorSpace: null, - avcType: null, - avcCodecInfo: null, - hevcCodecInfo: null, - vp9CodecInfo: null, - av1CodecInfo: null - }; - } else if (handlerType === "soun") { - track.info = { - type: "audio", - numberOfChannels: -1, - sampleRate: -1, - codec: null, - codecDescription: null, - aacCodecInfo: null - }; - } - } - break; - case "stbl": - { - const track = this.currentTrack; - if (!track) { - break; - } - track.sampleTableByteOffset = startPos; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "stsd": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (track.info === null || track.sampleTable) { - break; - } - const stsdVersion = readU8(slice); - slice.skip(3); - const entries = readU32Be(slice); - for (let i = 0; i < entries; i++) { - const sampleBoxStartPos = slice.filePos; - const sampleBoxInfo = readBoxHeader(slice); - if (!sampleBoxInfo) { - break; - } - track.internalCodecId = sampleBoxInfo.name; - const lowercaseBoxName = sampleBoxInfo.name.toLowerCase(); - if (track.info.type === "video") { - if (lowercaseBoxName === "avc1" || lowercaseBoxName === "avc3") { - track.info.codec = "avc"; - track.info.avcType = lowercaseBoxName === "avc1" ? 1 : 3; - } else if (lowercaseBoxName === "hvc1" || lowercaseBoxName === "hev1") { - track.info.codec = "hevc"; - } else if (lowercaseBoxName === "vp08") { - track.info.codec = "vp8"; - } else if (lowercaseBoxName === "vp09") { - track.info.codec = "vp9"; - } else if (lowercaseBoxName === "av01") { - track.info.codec = "av1"; - } else { - console.warn(`Unsupported video codec (sample entry type '${sampleBoxInfo.name}').`); - } - slice.skip(6 * 1 + 2 + 2 + 2 + 3 * 4); - track.info.width = readU16Be(slice); - track.info.height = readU16Be(slice); - slice.skip(4 + 4 + 4 + 2 + 32 + 2 + 2); - this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); - } else { - if (lowercaseBoxName === "mp4a") ; - else if (lowercaseBoxName === "opus") { - track.info.codec = "opus"; - } else if (lowercaseBoxName === "flac") { - track.info.codec = "flac"; - } else if (lowercaseBoxName === "twos" || lowercaseBoxName === "sowt" || lowercaseBoxName === "raw " || lowercaseBoxName === "in24" || lowercaseBoxName === "in32" || lowercaseBoxName === "fl32" || lowercaseBoxName === "fl64" || lowercaseBoxName === "lpcm" || lowercaseBoxName === "ipcm" || lowercaseBoxName === "fpcm") ; - else if (lowercaseBoxName === "ulaw") { - track.info.codec = "ulaw"; - } else if (lowercaseBoxName === "alaw") { - track.info.codec = "alaw"; - } else { - console.warn(`Unsupported audio codec (sample entry type '${sampleBoxInfo.name}').`); - } - slice.skip(6 * 1 + 2); - const version = readU16Be(slice); - slice.skip(3 * 2); - let channelCount = readU16Be(slice); - let sampleSize = readU16Be(slice); - slice.skip(2 * 2); - let sampleRate = readU32Be(slice) / 65536; - if (stsdVersion === 0 && version > 0) { - if (version === 1) { - slice.skip(4); - sampleSize = 8 * readU32Be(slice); - slice.skip(2 * 4); - } else if (version === 2) { - slice.skip(4); - sampleRate = readF64Be(slice); - channelCount = readU32Be(slice); - slice.skip(4); - sampleSize = readU32Be(slice); - const flags = readU32Be(slice); - slice.skip(2 * 4); - if (lowercaseBoxName === "lpcm") { - const bytesPerSample = sampleSize + 7 >> 3; - const isFloat = Boolean(flags & 1); - const isBigEndian = Boolean(flags & 2); - const sFlags = flags & 4 ? -1 : 0; - if (sampleSize > 0 && sampleSize <= 64) { - if (isFloat) { - if (sampleSize === 32) { - track.info.codec = isBigEndian ? "pcm-f32be" : "pcm-f32"; - } - } else { - if (sFlags & 1 << bytesPerSample - 1) { - if (bytesPerSample === 1) { - track.info.codec = "pcm-s8"; - } else if (bytesPerSample === 2) { - track.info.codec = isBigEndian ? "pcm-s16be" : "pcm-s16"; - } else if (bytesPerSample === 3) { - track.info.codec = isBigEndian ? "pcm-s24be" : "pcm-s24"; - } else if (bytesPerSample === 4) { - track.info.codec = isBigEndian ? "pcm-s32be" : "pcm-s32"; - } - } else { - if (bytesPerSample === 1) { - track.info.codec = "pcm-u8"; - } - } - } - } - if (track.info.codec === null) { - console.warn("Unsupported PCM format."); - } - } - } - } - if (track.info.codec === "opus") { - sampleRate = OPUS_SAMPLE_RATE; - } - track.info.numberOfChannels = channelCount; - track.info.sampleRate = sampleRate; - if (lowercaseBoxName === "twos") { - if (sampleSize === 8) { - track.info.codec = "pcm-s8"; - } else if (sampleSize === 16) { - track.info.codec = "pcm-s16be"; - } else { - console.warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`); - track.info.codec = null; - } - } else if (lowercaseBoxName === "sowt") { - if (sampleSize === 8) { - track.info.codec = "pcm-s8"; - } else if (sampleSize === 16) { - track.info.codec = "pcm-s16"; - } else { - console.warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`); - track.info.codec = null; - } - } else if (lowercaseBoxName === "raw ") { - track.info.codec = "pcm-u8"; - } else if (lowercaseBoxName === "in24") { - track.info.codec = "pcm-s24be"; - } else if (lowercaseBoxName === "in32") { - track.info.codec = "pcm-s32be"; - } else if (lowercaseBoxName === "fl32") { - track.info.codec = "pcm-f32be"; - } else if (lowercaseBoxName === "fl64") { - track.info.codec = "pcm-f64be"; - } else if (lowercaseBoxName === "ipcm") { - track.info.codec = "pcm-s16be"; - } else if (lowercaseBoxName === "fpcm") { - track.info.codec = "pcm-f32be"; - } - this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); - } - } - } - break; - case "avcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info); - track.info.codecDescription = readBytes(slice, boxInfo.contentSize); - } - break; - case "hvcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info); - track.info.codecDescription = readBytes(slice, boxInfo.contentSize); - } - break; - case "vpcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - slice.skip(4); - const profile = readU8(slice); - const level = readU8(slice); - const thirdByte = readU8(slice); - const bitDepth = thirdByte >> 4; - const chromaSubsampling = thirdByte >> 1 & 7; - const videoFullRangeFlag = thirdByte & 1; - const colourPrimaries = readU8(slice); - const transferCharacteristics = readU8(slice); - const matrixCoefficients = readU8(slice); - track.info.vp9CodecInfo = { - profile, - level, - bitDepth, - chromaSubsampling, - videoFullRangeFlag, - colourPrimaries, - transferCharacteristics, - matrixCoefficients - }; - } - break; - case "av1C": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - slice.skip(1); - const secondByte = readU8(slice); - const profile = secondByte >> 5; - const level = secondByte & 31; - const thirdByte = readU8(slice); - const tier = thirdByte >> 7; - const highBitDepth = thirdByte >> 6 & 1; - const twelveBit = thirdByte >> 5 & 1; - const monochrome = thirdByte >> 4 & 1; - const chromaSubsamplingX = thirdByte >> 3 & 1; - const chromaSubsamplingY = thirdByte >> 2 & 1; - const chromaSamplePosition = thirdByte & 3; - const bitDepth = profile === 2 && highBitDepth ? twelveBit ? 12 : 10 : highBitDepth ? 10 : 8; - track.info.av1CodecInfo = { - profile, - level, - tier, - bitDepth, - monochrome, - chromaSubsamplingX, - chromaSubsamplingY, - chromaSamplePosition - }; - } - break; - case "colr": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - const colourType = readAscii(slice, 4); - if (colourType !== "nclx") { - break; - } - const colourPrimaries = readU16Be(slice); - const transferCharacteristics = readU16Be(slice); - const matrixCoefficients = readU16Be(slice); - const fullRangeFlag = Boolean(readU8(slice) & 128); - track.info.colorSpace = { - primaries: COLOR_PRIMARIES_MAP_INVERSE[colourPrimaries], - transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics], - matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients], - fullRange: fullRangeFlag - }; - } - break; - case "wave": - { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "esds": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(4); - const tag = readU8(slice); - assert(tag === 3); - readIsomVariableInteger(slice); - slice.skip(2); - const mixed = readU8(slice); - const streamDependenceFlag = (mixed & 128) !== 0; - const urlFlag = (mixed & 64) !== 0; - const ocrStreamFlag = (mixed & 32) !== 0; - if (streamDependenceFlag) { - slice.skip(2); - } - if (urlFlag) { - const urlLength = readU8(slice); - slice.skip(urlLength); - } - if (ocrStreamFlag) { - slice.skip(2); - } - const decoderConfigTag = readU8(slice); - assert(decoderConfigTag === 4); - const decoderConfigDescriptorLength = readIsomVariableInteger(slice); - const payloadStart = slice.filePos; - const objectTypeIndication = readU8(slice); - if (objectTypeIndication === 64 || objectTypeIndication === 103) { - track.info.codec = "aac"; - track.info.aacCodecInfo = { isMpeg2: objectTypeIndication === 103 }; - } else if (objectTypeIndication === 105 || objectTypeIndication === 107) { - track.info.codec = "mp3"; - } else if (objectTypeIndication === 221) { - track.info.codec = "vorbis"; - } else { - console.warn(`Unsupported audio codec (objectTypeIndication ${objectTypeIndication}) - discarding track.`); - } - slice.skip(1 + 3 + 4 + 4); - if (decoderConfigDescriptorLength > slice.filePos - payloadStart) { - const decoderSpecificInfoTag = readU8(slice); - assert(decoderSpecificInfoTag === 5); - const decoderSpecificInfoLength = readIsomVariableInteger(slice); - track.info.codecDescription = readBytes(slice, decoderSpecificInfoLength); - if (track.info.codec === "aac") { - const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); - if (audioSpecificConfig.numberOfChannels !== null) { - track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; - } - if (audioSpecificConfig.sampleRate !== null) { - track.info.sampleRate = audioSpecificConfig.sampleRate; - } - } - } - } - break; - case "enda": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - const littleEndian = readU16Be(slice) & 255; - if (littleEndian) { - if (track.info.codec === "pcm-s16be") { - track.info.codec = "pcm-s16"; - } else if (track.info.codec === "pcm-s24be") { - track.info.codec = "pcm-s24"; - } else if (track.info.codec === "pcm-s32be") { - track.info.codec = "pcm-s32"; - } else if (track.info.codec === "pcm-f32be") { - track.info.codec = "pcm-f32"; - } else if (track.info.codec === "pcm-f64be") { - track.info.codec = "pcm-f64"; - } - } - } - break; - case "pcmC": { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(1 + 3); - const formatFlags = readU8(slice); - const isLittleEndian = Boolean(formatFlags & 1); - const pcmSampleSize = readU8(slice); - if (track.info.codec === "pcm-s16be") { - if (isLittleEndian) { - if (pcmSampleSize === 16) { - track.info.codec = "pcm-s16"; - } else if (pcmSampleSize === 24) { - track.info.codec = "pcm-s24"; - } else if (pcmSampleSize === 32) { - track.info.codec = "pcm-s32"; - } else { - console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } else { - if (pcmSampleSize === 16) { - track.info.codec = "pcm-s16be"; - } else if (pcmSampleSize === 24) { - track.info.codec = "pcm-s24be"; - } else if (pcmSampleSize === 32) { - track.info.codec = "pcm-s32be"; - } else { - console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } - } else if (track.info.codec === "pcm-f32be") { - if (isLittleEndian) { - if (pcmSampleSize === 32) { - track.info.codec = "pcm-f32"; - } else if (pcmSampleSize === 64) { - track.info.codec = "pcm-f64"; - } else { - console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } else { - if (pcmSampleSize === 32) { - track.info.codec = "pcm-f32be"; - } else if (pcmSampleSize === 64) { - track.info.codec = "pcm-f64be"; - } else { - console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } - } - break; - } - case "dOps": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(1); - const outputChannelCount = readU8(slice); - const preSkip = readU16Be(slice); - const inputSampleRate = readU32Be(slice); - const outputGain = readI16Be(slice); - const channelMappingFamily = readU8(slice); - let channelMappingTable; - if (channelMappingFamily !== 0) { - channelMappingTable = readBytes(slice, 2 + outputChannelCount); - } else { - channelMappingTable = new Uint8Array(0); - } - const description = new Uint8Array(8 + 1 + 1 + 2 + 4 + 2 + 1 + channelMappingTable.byteLength); - const view = new DataView(description.buffer); - view.setUint32(0, 1332770163, false); - view.setUint32(4, 1214603620, false); - view.setUint8(8, 1); - view.setUint8(9, outputChannelCount); - view.setUint16(10, preSkip, true); - view.setUint32(12, inputSampleRate, true); - view.setInt16(16, outputGain, true); - view.setUint8(18, channelMappingFamily); - description.set(channelMappingTable, 19); - track.info.codecDescription = description; - track.info.numberOfChannels = outputChannelCount; - } - break; - case "dfLa": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(4); - const BLOCK_TYPE_MASK = 127; - const LAST_METADATA_BLOCK_FLAG_MASK = 128; - const startPos2 = slice.filePos; - while (slice.filePos < boxEndPos) { - const flagAndType = readU8(slice); - const metadataBlockLength = readU24Be(slice); - const type = flagAndType & BLOCK_TYPE_MASK; - if (type === FlacBlockType.STREAMINFO) { - slice.skip(10); - const word = readU32Be(slice); - const sampleRate = word >>> 12; - const numberOfChannels = (word >> 9 & 7) + 1; - track.info.sampleRate = sampleRate; - track.info.numberOfChannels = numberOfChannels; - slice.skip(20); - } else { - slice.skip(metadataBlockLength); - } - if (flagAndType & LAST_METADATA_BLOCK_FLAG_MASK) { - break; - } - } - const endPos = slice.filePos; - slice.filePos = startPos2; - const bytes = readBytes(slice, endPos - startPos2); - const description = new Uint8Array(4 + bytes.byteLength); - const view = new DataView(description.buffer); - view.setUint32(0, 1716281667, false); - description.set(bytes, 4); - track.info.codecDescription = description; - } - break; - case "stts": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - let currentIndex = 0; - let currentTimestamp = 0; - for (let i = 0; i < entryCount; i++) { - const sampleCount = readU32Be(slice); - const sampleDelta = readU32Be(slice); - track.sampleTable.sampleTimingEntries.push({ - startIndex: currentIndex, - startDecodeTimestamp: currentTimestamp, - count: sampleCount, - delta: sampleDelta - }); - currentIndex += sampleCount; - currentTimestamp += sampleCount * sampleDelta; - } - } - break; - case "ctts": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(1 + 3); - const entryCount = readU32Be(slice); - let sampleIndex = 0; - for (let i = 0; i < entryCount; i++) { - const sampleCount = readU32Be(slice); - const sampleOffset = readI32Be(slice); - track.sampleTable.sampleCompositionTimeOffsets.push({ - startIndex: sampleIndex, - count: sampleCount, - offset: sampleOffset - }); - sampleIndex += sampleCount; - } - } - break; - case "stsz": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const sampleSize = readU32Be(slice); - const sampleCount = readU32Be(slice); - if (sampleSize === 0) { - for (let i = 0; i < sampleCount; i++) { - const sampleSize2 = readU32Be(slice); - track.sampleTable.sampleSizes.push(sampleSize2); - } - } else { - track.sampleTable.sampleSizes.push(sampleSize); - } - } - break; - case "stz2": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - slice.skip(3); - const fieldSize = readU8(slice); - const sampleCount = readU32Be(slice); - const bytes = readBytes(slice, Math.ceil(sampleCount * fieldSize / 8)); - const bitstream = new Bitstream(bytes); - for (let i = 0; i < sampleCount; i++) { - const sampleSize = bitstream.readBits(fieldSize); - track.sampleTable.sampleSizes.push(sampleSize); - } - } - break; - case "stss": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - track.sampleTable.keySampleIndices = []; - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const sampleIndex = readU32Be(slice) - 1; - track.sampleTable.keySampleIndices.push(sampleIndex); - } - if (track.sampleTable.keySampleIndices[0] !== 0) { - track.sampleTable.keySampleIndices.unshift(0); - } - } - break; - case "stsc": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const startChunkIndex = readU32Be(slice) - 1; - const samplesPerChunk = readU32Be(slice); - const sampleDescriptionIndex = readU32Be(slice); - track.sampleTable.sampleToChunk.push({ - startSampleIndex: -1, - startChunkIndex, - samplesPerChunk, - sampleDescriptionIndex - }); - } - let startSampleIndex = 0; - for (let i = 0; i < track.sampleTable.sampleToChunk.length; i++) { - track.sampleTable.sampleToChunk[i].startSampleIndex = startSampleIndex; - if (i < track.sampleTable.sampleToChunk.length - 1) { - const nextChunk = track.sampleTable.sampleToChunk[i + 1]; - const chunkCount = nextChunk.startChunkIndex - track.sampleTable.sampleToChunk[i].startChunkIndex; - startSampleIndex += chunkCount * track.sampleTable.sampleToChunk[i].samplesPerChunk; - } - } - } - break; - case "stco": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const chunkOffset = readU32Be(slice); - track.sampleTable.chunkOffsets.push(chunkOffset); - } - } - break; - case "co64": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const chunkOffset = readU64Be(slice); - track.sampleTable.chunkOffsets.push(chunkOffset); - } - } - break; - case "mvex": - { - this.isFragmented = true; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "mehd": - { - const version = readU8(slice); - slice.skip(3); - const fragmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); - this.movieDurationInTimescale = fragmentDuration; - } - break; - case "trex": - { - slice.skip(4); - const trackId = readU32Be(slice); - const defaultSampleDescriptionIndex = readU32Be(slice); - const defaultSampleDuration = readU32Be(slice); - const defaultSampleSize = readU32Be(slice); - const defaultSampleFlags = readU32Be(slice); - this.fragmentTrackDefaults.push({ - trackId, - defaultSampleDescriptionIndex, - defaultSampleDuration, - defaultSampleSize, - defaultSampleFlags - }); - } - break; - case "tfra": - { - const version = readU8(slice); - slice.skip(3); - const trackId = readU32Be(slice); - const track = this.tracks.find((x) => x.id === trackId); - if (!track) { - break; - } - const word = readU32Be(slice); - const lengthSizeOfTrafNum = (word & 48) >> 4; - const lengthSizeOfTrunNum = (word & 12) >> 2; - const lengthSizeOfSampleNum = word & 3; - const functions = [readU8, readU16Be, readU24Be, readU32Be]; - const readTrafNum = functions[lengthSizeOfTrafNum]; - const readTrunNum = functions[lengthSizeOfTrunNum]; - const readSampleNum = functions[lengthSizeOfSampleNum]; - const numberOfEntries = readU32Be(slice); - for (let i = 0; i < numberOfEntries; i++) { - const time = version === 1 ? readU64Be(slice) : readU32Be(slice); - const moofOffset = version === 1 ? readU64Be(slice) : readU32Be(slice); - readTrafNum(slice); - readTrunNum(slice); - readSampleNum(slice); - track.fragmentLookupTable.push({ - timestamp: time, - moofOffset - }); - } - track.fragmentLookupTable.sort((a, b) => a.timestamp - b.timestamp); - for (let i = 0; i < track.fragmentLookupTable.length - 1; i++) { - const entry1 = track.fragmentLookupTable[i]; - const entry2 = track.fragmentLookupTable[i + 1]; - if (entry1.timestamp === entry2.timestamp) { - track.fragmentLookupTable.splice(i + 1, 1); - i--; - } - } - } - break; - case "moof": - { - this.currentFragment = { - moofOffset: startPos, - moofSize: boxInfo.totalSize, - implicitBaseDataOffset: startPos, - trackData: /* @__PURE__ */ new Map() - }; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - this.lastReadFragment = this.currentFragment; - this.currentFragment = null; - } - break; - case "traf": - { - assert(this.currentFragment); - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - if (this.currentTrack) { - const trackData = this.currentFragment.trackData.get(this.currentTrack.id); - if (trackData) { - const { currentFragmentState } = this.currentTrack; - assert(currentFragmentState); - if (currentFragmentState.startTimestamp !== null) { - offsetFragmentTrackDataByTimestamp(trackData, currentFragmentState.startTimestamp); - trackData.startTimestampIsFinal = true; - } - } - this.currentTrack.currentFragmentState = null; - this.currentTrack = null; - } - } - break; - case "tfhd": - { - assert(this.currentFragment); - slice.skip(1); - const flags = readU24Be(slice); - const baseDataOffsetPresent = Boolean(flags & 1); - const sampleDescriptionIndexPresent = Boolean(flags & 2); - const defaultSampleDurationPresent = Boolean(flags & 8); - const defaultSampleSizePresent = Boolean(flags & 16); - const defaultSampleFlagsPresent = Boolean(flags & 32); - const durationIsEmpty = Boolean(flags & 65536); - const defaultBaseIsMoof = Boolean(flags & 131072); - const trackId = readU32Be(slice); - const track = this.tracks.find((x) => x.id === trackId); - if (!track) { - break; - } - const defaults = this.fragmentTrackDefaults.find((x) => x.trackId === trackId); - this.currentTrack = track; - track.currentFragmentState = { - baseDataOffset: this.currentFragment.implicitBaseDataOffset, - sampleDescriptionIndex: defaults?.defaultSampleDescriptionIndex ?? null, - defaultSampleDuration: defaults?.defaultSampleDuration ?? null, - defaultSampleSize: defaults?.defaultSampleSize ?? null, - defaultSampleFlags: defaults?.defaultSampleFlags ?? null, - startTimestamp: null - }; - if (baseDataOffsetPresent) { - track.currentFragmentState.baseDataOffset = readU64Be(slice); - } else if (defaultBaseIsMoof) { - track.currentFragmentState.baseDataOffset = this.currentFragment.moofOffset; - } - if (sampleDescriptionIndexPresent) { - track.currentFragmentState.sampleDescriptionIndex = readU32Be(slice); - } - if (defaultSampleDurationPresent) { - track.currentFragmentState.defaultSampleDuration = readU32Be(slice); - } - if (defaultSampleSizePresent) { - track.currentFragmentState.defaultSampleSize = readU32Be(slice); - } - if (defaultSampleFlagsPresent) { - track.currentFragmentState.defaultSampleFlags = readU32Be(slice); - } - if (durationIsEmpty) { - track.currentFragmentState.defaultSampleDuration = 0; - } - } - break; - case "tfdt": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.currentFragmentState); - const version = readU8(slice); - slice.skip(3); - const baseMediaDecodeTime = version === 0 ? readU32Be(slice) : readU64Be(slice); - track.currentFragmentState.startTimestamp = baseMediaDecodeTime; - } - break; - case "trun": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(this.currentFragment); - assert(track.currentFragmentState); - if (this.currentFragment.trackData.has(track.id)) { - console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring..."); - break; - } - const version = readU8(slice); - const flags = readU24Be(slice); - const dataOffsetPresent = Boolean(flags & 1); - const firstSampleFlagsPresent = Boolean(flags & 4); - const sampleDurationPresent = Boolean(flags & 256); - const sampleSizePresent = Boolean(flags & 512); - const sampleFlagsPresent = Boolean(flags & 1024); - const sampleCompositionTimeOffsetsPresent = Boolean(flags & 2048); - const sampleCount = readU32Be(slice); - let dataOffset = track.currentFragmentState.baseDataOffset; - if (dataOffsetPresent) { - dataOffset += readI32Be(slice); - } - let firstSampleFlags = null; - if (firstSampleFlagsPresent) { - firstSampleFlags = readU32Be(slice); - } - let currentOffset = dataOffset; - if (sampleCount === 0) { - this.currentFragment.implicitBaseDataOffset = currentOffset; - break; - } - let currentTimestamp = 0; - const trackData = { - track, - startTimestamp: 0, - endTimestamp: 0, - firstKeyFrameTimestamp: null, - samples: [], - presentationTimestamps: [], - startTimestampIsFinal: false - }; - this.currentFragment.trackData.set(track.id, trackData); - for (let i = 0; i < sampleCount; i++) { - let sampleDuration; - if (sampleDurationPresent) { - sampleDuration = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleDuration !== null); - sampleDuration = track.currentFragmentState.defaultSampleDuration; - } - let sampleSize; - if (sampleSizePresent) { - sampleSize = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleSize !== null); - sampleSize = track.currentFragmentState.defaultSampleSize; - } - let sampleFlags; - if (sampleFlagsPresent) { - sampleFlags = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleFlags !== null); - sampleFlags = track.currentFragmentState.defaultSampleFlags; - } - if (i === 0 && firstSampleFlags !== null) { - sampleFlags = firstSampleFlags; - } - let sampleCompositionTimeOffset = 0; - if (sampleCompositionTimeOffsetsPresent) { - if (version === 0) { - sampleCompositionTimeOffset = readU32Be(slice); - } else { - sampleCompositionTimeOffset = readI32Be(slice); - } - } - const isKeyFrame = !(sampleFlags & 65536); - trackData.samples.push({ - presentationTimestamp: currentTimestamp + sampleCompositionTimeOffset, - duration: sampleDuration, - byteOffset: currentOffset, - byteSize: sampleSize, - isKeyFrame - }); - currentOffset += sampleSize; - currentTimestamp += sampleDuration; - } - trackData.presentationTimestamps = trackData.samples.map((x, i) => ({ presentationTimestamp: x.presentationTimestamp, sampleIndex: i })).sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); - for (let i = 0; i < trackData.presentationTimestamps.length; i++) { - const currentEntry = trackData.presentationTimestamps[i]; - const currentSample = trackData.samples[currentEntry.sampleIndex]; - if (trackData.firstKeyFrameTimestamp === null && currentSample.isKeyFrame) { - trackData.firstKeyFrameTimestamp = currentSample.presentationTimestamp; - } - if (i < trackData.presentationTimestamps.length - 1) { - const nextEntry = trackData.presentationTimestamps[i + 1]; - currentSample.duration = nextEntry.presentationTimestamp - currentEntry.presentationTimestamp; - } - } - const firstSample = trackData.samples[trackData.presentationTimestamps[0].sampleIndex]; - const lastSample = trackData.samples[last(trackData.presentationTimestamps).sampleIndex]; - trackData.startTimestamp = firstSample.presentationTimestamp; - trackData.endTimestamp = lastSample.presentationTimestamp + lastSample.duration; - this.currentFragment.implicitBaseDataOffset = currentOffset; - } - break; - // Metadata section - // https://exiftool.org/TagNames/QuickTime.html - // https://mp4workshop.com/about - case "udta": - { - const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { - if (boxInfo2.name !== "meta" && !this.currentTrack) { - const startPos2 = slice2.filePos; - (_a = this.metadataTags).raw ?? (_a.raw = {}); - if (boxInfo2.name[0] === "©") { - (_b = this.metadataTags.raw)[_c = boxInfo2.name] ?? (_b[_c] = readMetadataStringShort(slice2)); - } else { - (_d = this.metadataTags.raw)[_e = boxInfo2.name] ?? (_d[_e] = readBytes(slice2, boxInfo2.contentSize)); - } - slice2.filePos = startPos2; - } - switch (boxInfo2.name) { - case "meta": - { - slice2.skip(-boxInfo2.headerSize); - this.traverseBox(slice2); - } - break; - case "©nam": - case "name": - { - if (this.currentTrack) { - this.currentTrack.name = textDecoder.decode(readBytes(slice2, boxInfo2.contentSize)); - } else { - (_f = this.metadataTags).title ?? (_f.title = readMetadataStringShort(slice2)); - } - } - break; - case "©des": - { - if (!this.currentTrack) { - (_g = this.metadataTags).description ?? (_g.description = readMetadataStringShort(slice2)); - } - } - break; - case "©ART": - { - if (!this.currentTrack) { - (_h = this.metadataTags).artist ?? (_h.artist = readMetadataStringShort(slice2)); - } - } - break; - case "©alb": - { - if (!this.currentTrack) { - (_i = this.metadataTags).album ?? (_i.album = readMetadataStringShort(slice2)); - } - } - break; - case "albr": - { - if (!this.currentTrack) { - (_j = this.metadataTags).albumArtist ?? (_j.albumArtist = readMetadataStringShort(slice2)); - } - } - break; - case "©gen": - { - if (!this.currentTrack) { - (_k = this.metadataTags).genre ?? (_k.genre = readMetadataStringShort(slice2)); - } - } - break; - case "©day": - { - if (!this.currentTrack) { - const date = new Date(readMetadataStringShort(slice2)); - if (!Number.isNaN(date.getTime())) { - (_l = this.metadataTags).date ?? (_l.date = date); - } - } - } - break; - case "©cmt": - { - if (!this.currentTrack) { - (_m = this.metadataTags).comment ?? (_m.comment = readMetadataStringShort(slice2)); - } - } - break; - case "©lyr": - { - if (!this.currentTrack) { - (_n = this.metadataTags).lyrics ?? (_n.lyrics = readMetadataStringShort(slice2)); - } - } - break; - } - } - } - break; - case "meta": - { - if (this.currentTrack) { - break; - } - const word = readU32Be(slice); - const isQuickTime = word !== 0; - this.currentMetadataKeys = /* @__PURE__ */ new Map(); - if (isQuickTime) { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } else { - this.readContiguousBoxes(slice.slice(contentStartPos + 4, boxInfo.contentSize - 4)); - } - this.currentMetadataKeys = null; - } - break; - case "keys": - { - if (!this.currentMetadataKeys) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const keySize = readU32Be(slice); - slice.skip(4); - const keyName = textDecoder.decode(readBytes(slice, keySize - 8)); - this.currentMetadataKeys.set(i + 1, keyName); - } - } - break; - case "ilst": - { - if (!this.currentMetadataKeys) { - break; - } - const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { - let metadataKey = boxInfo2.name; - const nameAsNumber = (metadataKey.charCodeAt(0) << 24) + (metadataKey.charCodeAt(1) << 16) + (metadataKey.charCodeAt(2) << 8) + metadataKey.charCodeAt(3); - if (this.currentMetadataKeys.has(nameAsNumber)) { - metadataKey = this.currentMetadataKeys.get(nameAsNumber); - } - const data = readDataBox(slice2); - (_o = this.metadataTags).raw ?? (_o.raw = {}); - (_p = this.metadataTags.raw)[metadataKey] ?? (_p[metadataKey] = data); - switch (metadataKey) { - case "©nam": - case "titl": - case "com.apple.quicktime.title": - case "title": - { - if (typeof data === "string") { - (_q = this.metadataTags).title ?? (_q.title = data); - } - } - break; - case "©des": - case "desc": - case "dscp": - case "com.apple.quicktime.description": - case "description": - { - if (typeof data === "string") { - (_r = this.metadataTags).description ?? (_r.description = data); - } - } - break; - case "©ART": - case "com.apple.quicktime.artist": - case "artist": - { - if (typeof data === "string") { - (_s = this.metadataTags).artist ?? (_s.artist = data); - } - } - break; - case "©alb": - case "albm": - case "com.apple.quicktime.album": - case "album": - { - if (typeof data === "string") { - (_t = this.metadataTags).album ?? (_t.album = data); - } - } - break; - case "aART": - case "album_artist": - { - if (typeof data === "string") { - (_u = this.metadataTags).albumArtist ?? (_u.albumArtist = data); - } - } - break; - case "©cmt": - case "com.apple.quicktime.comment": - case "comment": - { - if (typeof data === "string") { - (_v = this.metadataTags).comment ?? (_v.comment = data); - } - } - break; - case "©gen": - case "gnre": - case "com.apple.quicktime.genre": - case "genre": - { - if (typeof data === "string") { - (_w = this.metadataTags).genre ?? (_w.genre = data); - } - } - break; - case "©lyr": - case "lyrics": - { - if (typeof data === "string") { - (_x = this.metadataTags).lyrics ?? (_x.lyrics = data); - } - } - break; - case "©day": - case "rldt": - case "com.apple.quicktime.creationdate": - case "date": - { - if (typeof data === "string") { - const date = new Date(data); - if (!Number.isNaN(date.getTime())) { - (_y = this.metadataTags).date ?? (_y.date = date); - } - } - } - break; - case "covr": - case "com.apple.quicktime.artwork": - { - if (data instanceof RichImageData) { - (_z = this.metadataTags).images ?? (_z.images = []); - this.metadataTags.images.push({ - data: data.data, - kind: "coverFront", - mimeType: data.mimeType - }); - } else if (data instanceof Uint8Array) { - (_A = this.metadataTags).images ?? (_A.images = []); - this.metadataTags.images.push({ - data, - kind: "coverFront", - mimeType: "image/*" - }); - } - } - break; - case "track": - { - if (typeof data === "string") { - const parts = data.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - (_B = this.metadataTags).trackNumber ?? (_B.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - (_C = this.metadataTags).tracksTotal ?? (_C.tracksTotal = tracksTotal); - } - } - } - break; - case "trkn": - { - if (data instanceof Uint8Array && data.length >= 6) { - const view = toDataView(data); - const trackNumber = view.getUint16(2, false); - const tracksTotal = view.getUint16(4, false); - if (trackNumber > 0) { - (_D = this.metadataTags).trackNumber ?? (_D.trackNumber = trackNumber); - } - if (tracksTotal > 0) { - (_E = this.metadataTags).tracksTotal ?? (_E.tracksTotal = tracksTotal); - } - } - } - break; - case "disc": - case "disk": - { - if (data instanceof Uint8Array && data.length >= 6) { - const view = toDataView(data); - const discNumber = view.getUint16(2, false); - const discNumberMax = view.getUint16(4, false); - if (discNumber > 0) { - (_F = this.metadataTags).discNumber ?? (_F.discNumber = discNumber); - } - if (discNumberMax > 0) { - (_G = this.metadataTags).discsTotal ?? (_G.discsTotal = discNumberMax); - } - } - } - break; - } - } - } - break; - } - slice.filePos = boxEndPos; - return true; - } - } - class IsobmffTrackBacking { - constructor(internalTrack) { - this.internalTrack = internalTrack; - this.packetToSampleIndex = /* @__PURE__ */ new WeakMap(); - this.packetToFragmentLocation = /* @__PURE__ */ new WeakMap(); - } - getId() { - return this.internalTrack.id; - } - getCodec() { - throw new Error("Not implemented on base class."); - } - getInternalCodecId() { - return this.internalTrack.internalCodecId; - } - getName() { - return this.internalTrack.name; - } - getLanguageCode() { - return this.internalTrack.languageCode; - } - getTimeResolution() { - return this.internalTrack.timescale; - } - getDisposition() { - return this.internalTrack.disposition; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - async getFirstTimestamp() { - const firstPacket = await this.getFirstPacket({ metadataOnly: true }); - return firstPacket?.timestamp ?? 0; - } - async getFirstPacket(options) { - const regularPacket = await this.fetchPacketForSampleIndex(0, options); - if (regularPacket || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup( - null, - (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData) { - return { - sampleIndex: 0, - correctSampleFound: true - }; - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - mapTimestampIntoTimescale(timestamp) { - return roundIfAlmostInteger(timestamp * this.internalTrack.timescale) + this.internalTrack.editListOffset; - } - async getPacket(timestamp, options) { - const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); - const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); - if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup(null, (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (!trackData) { - return { sampleIndex: -1, correctSampleFound: false }; - } - const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.presentationTimestamp); - const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; - const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { sampleIndex: sampleIndex2, correctSampleFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextPacket(packet, options) { - const regularSampleIndex = this.packetToSampleIndex.get(packet); - if (regularSampleIndex !== void 0) { - return this.fetchPacketForSampleIndex(regularSampleIndex + 1, options); - } - const locationInFragment = this.packetToFragmentLocation.get(packet); - if (locationInFragment === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performFragmentedLookup( - locationInFragment.fragment, - (fragment) => { - if (fragment === locationInFragment.fragment) { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (locationInFragment.sampleIndex + 1 < trackData.samples.length) { - return { - sampleIndex: locationInFragment.sampleIndex + 1, - correctSampleFound: true - }; - } - } else { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData) { - return { - sampleIndex: 0, - correctSampleFound: true - }; - } - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - async getKeyPacket(timestamp, options) { - const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleIndex = getKeyframeSampleIndexForTimestamp(sampleTable, timestampInTimescale); - const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); - if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup(null, (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (!trackData) { - return { sampleIndex: -1, correctSampleFound: false }; - } - const index = findLastIndex(trackData.presentationTimestamps, (x) => { - const sample = trackData.samples[x.sampleIndex]; - return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; - }); - const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; - const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { sampleIndex: sampleIndex2, correctSampleFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextKeyPacket(packet, options) { - const regularSampleIndex = this.packetToSampleIndex.get(packet); - if (regularSampleIndex !== void 0) { - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, regularSampleIndex); - return this.fetchPacketForSampleIndex(nextKeyFrameSampleIndex, options); - } - const locationInFragment = this.packetToFragmentLocation.get(packet); - if (locationInFragment === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performFragmentedLookup( - locationInFragment.fragment, - (fragment) => { - if (fragment === locationInFragment.fragment) { - const trackData = fragment.trackData.get(this.internalTrack.id); - const nextKeyFrameIndex = trackData.samples.findIndex((x, i) => x.isKeyFrame && i > locationInFragment.sampleIndex); - if (nextKeyFrameIndex !== -1) { - return { - sampleIndex: nextKeyFrameIndex, - correctSampleFound: true - }; - } - } else { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData && trackData.firstKeyFrameTimestamp !== null) { - const keyFrameIndex = trackData.samples.findIndex((x) => x.isKeyFrame); - assert(keyFrameIndex !== -1); - return { - sampleIndex: keyFrameIndex, - correctSampleFound: true - }; - } - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - async fetchPacketForSampleIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleInfo = getSampleInfo(sampleTable, sampleIndex); - if (!sampleInfo) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.internalTrack.demuxer.reader.requestSlice(sampleInfo.sampleOffset, sampleInfo.sampleSize); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, sampleInfo.sampleSize); - } - const timestamp = (sampleInfo.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; - const duration = sampleInfo.duration / this.internalTrack.timescale; - const packet = new EncodedPacket(data, sampleInfo.isKeyFrame ? "key" : "delta", timestamp, duration, sampleIndex, sampleInfo.sampleSize); - this.packetToSampleIndex.set(packet, sampleIndex); - return packet; - } - async fetchPacketInFragment(fragment, sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const trackData = fragment.trackData.get(this.internalTrack.id); - const fragmentSample = trackData.samples[sampleIndex]; - assert(fragmentSample); - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.internalTrack.demuxer.reader.requestSlice(fragmentSample.byteOffset, fragmentSample.byteSize); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, fragmentSample.byteSize); - } - const timestamp = (fragmentSample.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; - const duration = fragmentSample.duration / this.internalTrack.timescale; - const packet = new EncodedPacket(data, fragmentSample.isKeyFrame ? "key" : "delta", timestamp, duration, fragment.moofOffset + sampleIndex, fragmentSample.byteSize); - this.packetToFragmentLocation.set(packet, { fragment, sampleIndex }); - return packet; - } - /** Looks for a packet in the fragments while trying to load as few fragments as possible to retrieve it. */ - async performFragmentedLookup(startFragment, getMatchInFragment, searchTimestamp, latestTimestamp, options) { - const demuxer = this.internalTrack.demuxer; - let currentFragment = null; - let bestFragment = null; - let bestSampleIndex = -1; - if (startFragment) { - const { sampleIndex, correctSampleFound } = getMatchInFragment(startFragment); - if (correctSampleFound) { - return this.fetchPacketInFragment(startFragment, sampleIndex, options); - } - if (sampleIndex !== -1) { - bestFragment = startFragment; - bestSampleIndex = sampleIndex; - } - } - const lookupEntryIndex = binarySearchLessOrEqual(this.internalTrack.fragmentLookupTable, searchTimestamp, (x) => x.timestamp); - const lookupEntry = lookupEntryIndex !== -1 ? this.internalTrack.fragmentLookupTable[lookupEntryIndex] : null; - const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.fragmentPositionCache, searchTimestamp, (x) => x.startTimestamp); - const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.fragmentPositionCache[positionCacheIndex] : null; - const lookupEntryPosition = Math.max(lookupEntry?.moofOffset ?? 0, positionCacheEntry?.moofOffset ?? 0) || null; - let currentPos; - if (!startFragment) { - currentPos = lookupEntryPosition ?? 0; - } else { - if (lookupEntryPosition === null || startFragment.moofOffset >= lookupEntryPosition) { - currentPos = startFragment.moofOffset + startFragment.moofSize; - currentFragment = startFragment; - } else { - currentPos = lookupEntryPosition; - } - } - while (true) { - if (currentFragment) { - const trackData = currentFragment.trackData.get(this.internalTrack.id); - if (trackData && trackData.startTimestamp > latestTimestamp) { - break; - } - } - let slice = demuxer.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const boxStartPos = currentPos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - if (boxInfo.name === "moof") { - currentFragment = await demuxer.readFragment(boxStartPos); - const { sampleIndex, correctSampleFound } = getMatchInFragment(currentFragment); - if (correctSampleFound) { - return this.fetchPacketInFragment(currentFragment, sampleIndex, options); - } - if (sampleIndex !== -1) { - bestFragment = currentFragment; - bestSampleIndex = sampleIndex; - } - } - currentPos = boxStartPos + boxInfo.totalSize; - } - if (lookupEntry && (!bestFragment || bestFragment.moofOffset < lookupEntry.moofOffset)) { - const previousLookupEntry = this.internalTrack.fragmentLookupTable[lookupEntryIndex - 1]; - assert(!previousLookupEntry || previousLookupEntry.timestamp < lookupEntry.timestamp); - const newSearchTimestamp = previousLookupEntry?.timestamp ?? -Infinity; - return this.performFragmentedLookup(null, getMatchInFragment, newSearchTimestamp, latestTimestamp, options); - } - if (bestFragment) { - return this.fetchPacketInFragment(bestFragment, bestSampleIndex, options); - } - return null; - } - } - class IsobmffVideoTrackBacking extends IsobmffTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfigPromise = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getCodedWidth() { - return this.internalTrack.info.width; - } - getCodedHeight() { - return this.internalTrack.info.height; - } - getRotation() { - return this.internalTrack.rotation; - } - async getColorSpace() { - return { - primaries: this.internalTrack.info.colorSpace?.primaries, - transfer: this.internalTrack.info.colorSpace?.transfer, - matrix: this.internalTrack.info.colorSpace?.matrix, - fullRange: this.internalTrack.info.colorSpace?.fullRange - }; - } - async canBeTransparent() { - return false; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { - if (this.internalTrack.info.codec === "vp9" && !this.internalTrack.info.vp9CodecInfo) { - const firstPacket = await this.getFirstPacket({}); - this.internalTrack.info.vp9CodecInfo = firstPacket && extractVp9CodecInfoFromPacket(firstPacket.data); - } else if (this.internalTrack.info.codec === "av1" && !this.internalTrack.info.av1CodecInfo) { - const firstPacket = await this.getFirstPacket({}); - this.internalTrack.info.av1CodecInfo = firstPacket && extractAv1CodecInfoFromPacket(firstPacket.data); - } - return { - codec: extractVideoCodecString(this.internalTrack.info), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? void 0, - colorSpace: this.internalTrack.info.colorSpace ?? void 0 - }; - })()); - } - } - class IsobmffAudioTrackBacking extends IsobmffTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfig = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getNumberOfChannels() { - return this.internalTrack.info.numberOfChannels; - } - getSampleRate() { - return this.internalTrack.info.sampleRate; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfig ?? (this.decoderConfig = { - codec: extractAudioCodecString(this.internalTrack.info), - numberOfChannels: this.internalTrack.info.numberOfChannels, - sampleRate: this.internalTrack.info.sampleRate, - description: this.internalTrack.info.codecDescription ?? void 0 - }); - } - } - const getSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { - if (sampleTable.presentationTimestamps) { - const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); - if (index === -1) { - return -1; - } - return sampleTable.presentationTimestamps[index].sampleIndex; - } else { - const index = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, timescaleUnits, (x) => x.startDecodeTimestamp); - if (index === -1) { - return -1; - } - const entry = sampleTable.sampleTimingEntries[index]; - return entry.startIndex + Math.min(Math.floor((timescaleUnits - entry.startDecodeTimestamp) / entry.delta), entry.count - 1); - } - }; - const getKeyframeSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { - if (!sampleTable.keySampleIndices) { - return getSampleIndexForTimestamp(sampleTable, timescaleUnits); - } - if (sampleTable.presentationTimestamps) { - const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); - if (index === -1) { - return -1; - } - for (let i = index; i >= 0; i--) { - const sampleIndex = sampleTable.presentationTimestamps[i].sampleIndex; - const isKeyFrame = binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1; - if (isKeyFrame) { - return sampleIndex; - } - } - return -1; - } else { - const sampleIndex = getSampleIndexForTimestamp(sampleTable, timescaleUnits); - const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); - return sampleTable.keySampleIndices[index] ?? -1; - } - }; - const getSampleInfo = (sampleTable, sampleIndex) => { - const timingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, sampleIndex, (x) => x.startIndex); - const timingEntry = sampleTable.sampleTimingEntries[timingEntryIndex]; - if (!timingEntry || timingEntry.startIndex + timingEntry.count <= sampleIndex) { - return null; - } - const decodeTimestamp = timingEntry.startDecodeTimestamp + (sampleIndex - timingEntry.startIndex) * timingEntry.delta; - let presentationTimestamp = decodeTimestamp; - const offsetEntryIndex = binarySearchLessOrEqual(sampleTable.sampleCompositionTimeOffsets, sampleIndex, (x) => x.startIndex); - const offsetEntry = sampleTable.sampleCompositionTimeOffsets[offsetEntryIndex]; - if (offsetEntry && sampleIndex - offsetEntry.startIndex < offsetEntry.count) { - presentationTimestamp += offsetEntry.offset; - } - const sampleSize = sampleTable.sampleSizes[Math.min(sampleIndex, sampleTable.sampleSizes.length - 1)]; - const chunkEntryIndex = binarySearchLessOrEqual(sampleTable.sampleToChunk, sampleIndex, (x) => x.startSampleIndex); - const chunkEntry = sampleTable.sampleToChunk[chunkEntryIndex]; - assert(chunkEntry); - const chunkIndex = chunkEntry.startChunkIndex + Math.floor((sampleIndex - chunkEntry.startSampleIndex) / chunkEntry.samplesPerChunk); - const chunkOffset = sampleTable.chunkOffsets[chunkIndex]; - const startSampleIndexOfChunk = chunkEntry.startSampleIndex + (chunkIndex - chunkEntry.startChunkIndex) * chunkEntry.samplesPerChunk; - let chunkSize = 0; - let sampleOffset = chunkOffset; - if (sampleTable.sampleSizes.length === 1) { - sampleOffset += sampleSize * (sampleIndex - startSampleIndexOfChunk); - chunkSize += sampleSize * chunkEntry.samplesPerChunk; - } else { - for (let i = startSampleIndexOfChunk; i < startSampleIndexOfChunk + chunkEntry.samplesPerChunk; i++) { - const sampleSize2 = sampleTable.sampleSizes[i]; - if (i < sampleIndex) { - sampleOffset += sampleSize2; - } - chunkSize += sampleSize2; - } - } - let duration = timingEntry.delta; - if (sampleTable.presentationTimestamps) { - const presentationIndex = sampleTable.presentationTimestampIndexMap[sampleIndex]; - assert(presentationIndex !== void 0); - if (presentationIndex < sampleTable.presentationTimestamps.length - 1) { - const nextEntry = sampleTable.presentationTimestamps[presentationIndex + 1]; - const nextPresentationTimestamp = nextEntry.presentationTimestamp; - duration = nextPresentationTimestamp - presentationTimestamp; - } + if (query.sortBy !== void 0 && typeof query.sortBy !== "function") { + throw new TypeError("query.sortBy, when provided, must be a function."); } return { - presentationTimestamp, - duration, - sampleOffset, - sampleSize, - chunkOffset, - chunkSize, - isKeyFrame: sampleTable.keySampleIndices ? binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1 : true + filter: query.filter ? (track) => { + const handle = (bool) => { + if (typeof bool !== "boolean") { + throw new TypeError("query.filter must return or resolve to a boolean."); + } + return bool; + }; + const result = query.filter(track); + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } : void 0, + sortBy: query.sortBy ? (track) => { + const handle = (value) => { + if (typeof value !== "number" && (!Array.isArray(value) || !value.every((x) => typeof x === "number"))) { + throw new TypeError("query.sortBy must return or resolve to a number or an array of numbers."); + } + return value; + }; + const result = query.sortBy(track); + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } : void 0 }; }; - const getNextKeyframeIndexForSample = (sampleTable, sampleIndex) => { - if (!sampleTable.keySampleIndices) { - return sampleIndex + 1; - } - const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); - return sampleTable.keySampleIndices[index + 1] ?? -1; - }; - const offsetFragmentTrackDataByTimestamp = (trackData, timestamp) => { - trackData.startTimestamp += timestamp; - trackData.endTimestamp += timestamp; - for (const sample of trackData.samples) { - sample.presentationTimestamp += timestamp; - } - for (const entry of trackData.presentationTimestamps) { - entry.presentationTimestamp += timestamp; - } - }; - const extractRotationFromMatrix = (matrix) => { - const [m11, , , m21] = matrix; - const scaleX = Math.hypot(m11, m21); - const cosTheta = m11 / scaleX; - const sinTheta = m21 / scaleX; - const result = -Math.atan2(sinTheta, cosTheta) * (180 / Math.PI); - if (!Number.isFinite(result)) { - return 0; - } - return result; - }; - const sampleTableIsEmpty = (sampleTable) => { - return sampleTable.sampleSizes.length === 0; - }; - var EBMLId; - (function(EBMLId2) { - EBMLId2[EBMLId2["EBML"] = 440786851] = "EBML"; - EBMLId2[EBMLId2["EBMLVersion"] = 17030] = "EBMLVersion"; - EBMLId2[EBMLId2["EBMLReadVersion"] = 17143] = "EBMLReadVersion"; - EBMLId2[EBMLId2["EBMLMaxIDLength"] = 17138] = "EBMLMaxIDLength"; - EBMLId2[EBMLId2["EBMLMaxSizeLength"] = 17139] = "EBMLMaxSizeLength"; - EBMLId2[EBMLId2["DocType"] = 17026] = "DocType"; - EBMLId2[EBMLId2["DocTypeVersion"] = 17031] = "DocTypeVersion"; - EBMLId2[EBMLId2["DocTypeReadVersion"] = 17029] = "DocTypeReadVersion"; - EBMLId2[EBMLId2["Void"] = 236] = "Void"; - EBMLId2[EBMLId2["Segment"] = 408125543] = "Segment"; - EBMLId2[EBMLId2["SeekHead"] = 290298740] = "SeekHead"; - EBMLId2[EBMLId2["Seek"] = 19899] = "Seek"; - EBMLId2[EBMLId2["SeekID"] = 21419] = "SeekID"; - EBMLId2[EBMLId2["SeekPosition"] = 21420] = "SeekPosition"; - EBMLId2[EBMLId2["Duration"] = 17545] = "Duration"; - EBMLId2[EBMLId2["Info"] = 357149030] = "Info"; - EBMLId2[EBMLId2["TimestampScale"] = 2807729] = "TimestampScale"; - EBMLId2[EBMLId2["MuxingApp"] = 19840] = "MuxingApp"; - EBMLId2[EBMLId2["WritingApp"] = 22337] = "WritingApp"; - EBMLId2[EBMLId2["Tracks"] = 374648427] = "Tracks"; - EBMLId2[EBMLId2["TrackEntry"] = 174] = "TrackEntry"; - EBMLId2[EBMLId2["TrackNumber"] = 215] = "TrackNumber"; - EBMLId2[EBMLId2["TrackUID"] = 29637] = "TrackUID"; - EBMLId2[EBMLId2["TrackType"] = 131] = "TrackType"; - EBMLId2[EBMLId2["FlagEnabled"] = 185] = "FlagEnabled"; - EBMLId2[EBMLId2["FlagDefault"] = 136] = "FlagDefault"; - EBMLId2[EBMLId2["FlagForced"] = 21930] = "FlagForced"; - EBMLId2[EBMLId2["FlagOriginal"] = 21934] = "FlagOriginal"; - EBMLId2[EBMLId2["FlagHearingImpaired"] = 21931] = "FlagHearingImpaired"; - EBMLId2[EBMLId2["FlagVisualImpaired"] = 21932] = "FlagVisualImpaired"; - EBMLId2[EBMLId2["FlagCommentary"] = 21935] = "FlagCommentary"; - EBMLId2[EBMLId2["FlagLacing"] = 156] = "FlagLacing"; - EBMLId2[EBMLId2["Name"] = 21358] = "Name"; - EBMLId2[EBMLId2["Language"] = 2274716] = "Language"; - EBMLId2[EBMLId2["LanguageBCP47"] = 2274717] = "LanguageBCP47"; - EBMLId2[EBMLId2["CodecID"] = 134] = "CodecID"; - EBMLId2[EBMLId2["CodecPrivate"] = 25506] = "CodecPrivate"; - EBMLId2[EBMLId2["CodecDelay"] = 22186] = "CodecDelay"; - EBMLId2[EBMLId2["SeekPreRoll"] = 22203] = "SeekPreRoll"; - EBMLId2[EBMLId2["DefaultDuration"] = 2352003] = "DefaultDuration"; - EBMLId2[EBMLId2["Video"] = 224] = "Video"; - EBMLId2[EBMLId2["PixelWidth"] = 176] = "PixelWidth"; - EBMLId2[EBMLId2["PixelHeight"] = 186] = "PixelHeight"; - EBMLId2[EBMLId2["AlphaMode"] = 21440] = "AlphaMode"; - EBMLId2[EBMLId2["Audio"] = 225] = "Audio"; - EBMLId2[EBMLId2["SamplingFrequency"] = 181] = "SamplingFrequency"; - EBMLId2[EBMLId2["Channels"] = 159] = "Channels"; - EBMLId2[EBMLId2["BitDepth"] = 25188] = "BitDepth"; - EBMLId2[EBMLId2["SimpleBlock"] = 163] = "SimpleBlock"; - EBMLId2[EBMLId2["BlockGroup"] = 160] = "BlockGroup"; - EBMLId2[EBMLId2["Block"] = 161] = "Block"; - EBMLId2[EBMLId2["BlockAdditions"] = 30113] = "BlockAdditions"; - EBMLId2[EBMLId2["BlockMore"] = 166] = "BlockMore"; - EBMLId2[EBMLId2["BlockAdditional"] = 165] = "BlockAdditional"; - EBMLId2[EBMLId2["BlockAddID"] = 238] = "BlockAddID"; - EBMLId2[EBMLId2["BlockDuration"] = 155] = "BlockDuration"; - EBMLId2[EBMLId2["ReferenceBlock"] = 251] = "ReferenceBlock"; - EBMLId2[EBMLId2["Cluster"] = 524531317] = "Cluster"; - EBMLId2[EBMLId2["Timestamp"] = 231] = "Timestamp"; - EBMLId2[EBMLId2["Cues"] = 475249515] = "Cues"; - EBMLId2[EBMLId2["CuePoint"] = 187] = "CuePoint"; - EBMLId2[EBMLId2["CueTime"] = 179] = "CueTime"; - EBMLId2[EBMLId2["CueTrackPositions"] = 183] = "CueTrackPositions"; - EBMLId2[EBMLId2["CueTrack"] = 247] = "CueTrack"; - EBMLId2[EBMLId2["CueClusterPosition"] = 241] = "CueClusterPosition"; - EBMLId2[EBMLId2["Colour"] = 21936] = "Colour"; - EBMLId2[EBMLId2["MatrixCoefficients"] = 21937] = "MatrixCoefficients"; - EBMLId2[EBMLId2["TransferCharacteristics"] = 21946] = "TransferCharacteristics"; - EBMLId2[EBMLId2["Primaries"] = 21947] = "Primaries"; - EBMLId2[EBMLId2["Range"] = 21945] = "Range"; - EBMLId2[EBMLId2["Projection"] = 30320] = "Projection"; - EBMLId2[EBMLId2["ProjectionType"] = 30321] = "ProjectionType"; - EBMLId2[EBMLId2["ProjectionPoseRoll"] = 30325] = "ProjectionPoseRoll"; - EBMLId2[EBMLId2["Attachments"] = 423732329] = "Attachments"; - EBMLId2[EBMLId2["AttachedFile"] = 24999] = "AttachedFile"; - EBMLId2[EBMLId2["FileDescription"] = 18046] = "FileDescription"; - EBMLId2[EBMLId2["FileName"] = 18030] = "FileName"; - EBMLId2[EBMLId2["FileMediaType"] = 18016] = "FileMediaType"; - EBMLId2[EBMLId2["FileData"] = 18012] = "FileData"; - EBMLId2[EBMLId2["FileUID"] = 18094] = "FileUID"; - EBMLId2[EBMLId2["Chapters"] = 272869232] = "Chapters"; - EBMLId2[EBMLId2["Tags"] = 307544935] = "Tags"; - EBMLId2[EBMLId2["Tag"] = 29555] = "Tag"; - EBMLId2[EBMLId2["Targets"] = 25536] = "Targets"; - EBMLId2[EBMLId2["TargetTypeValue"] = 26826] = "TargetTypeValue"; - EBMLId2[EBMLId2["TargetType"] = 25546] = "TargetType"; - EBMLId2[EBMLId2["TagTrackUID"] = 25541] = "TagTrackUID"; - EBMLId2[EBMLId2["TagEditionUID"] = 25545] = "TagEditionUID"; - EBMLId2[EBMLId2["TagChapterUID"] = 25540] = "TagChapterUID"; - EBMLId2[EBMLId2["TagAttachmentUID"] = 25542] = "TagAttachmentUID"; - EBMLId2[EBMLId2["SimpleTag"] = 26568] = "SimpleTag"; - EBMLId2[EBMLId2["TagName"] = 17827] = "TagName"; - EBMLId2[EBMLId2["TagLanguage"] = 17530] = "TagLanguage"; - EBMLId2[EBMLId2["TagString"] = 17543] = "TagString"; - EBMLId2[EBMLId2["TagBinary"] = 17541] = "TagBinary"; - EBMLId2[EBMLId2["ContentEncodings"] = 28032] = "ContentEncodings"; - EBMLId2[EBMLId2["ContentEncoding"] = 25152] = "ContentEncoding"; - EBMLId2[EBMLId2["ContentEncodingOrder"] = 20529] = "ContentEncodingOrder"; - EBMLId2[EBMLId2["ContentEncodingScope"] = 20530] = "ContentEncodingScope"; - EBMLId2[EBMLId2["ContentCompression"] = 20532] = "ContentCompression"; - EBMLId2[EBMLId2["ContentCompAlgo"] = 16980] = "ContentCompAlgo"; - EBMLId2[EBMLId2["ContentCompSettings"] = 16981] = "ContentCompSettings"; - EBMLId2[EBMLId2["ContentEncryption"] = 20533] = "ContentEncryption"; - })(EBMLId || (EBMLId = {})); - const LEVEL_0_EBML_IDS = [ - EBMLId.EBML, - EBMLId.Segment - ]; - const LEVEL_1_EBML_IDS = [ - EBMLId.SeekHead, - EBMLId.Info, - EBMLId.Cluster, - EBMLId.Tracks, - EBMLId.Cues, - EBMLId.Attachments, - EBMLId.Chapters, - EBMLId.Tags - ]; - const LEVEL_0_AND_1_EBML_IDS = [ - ...LEVEL_0_EBML_IDS, - ...LEVEL_1_EBML_IDS - ]; - const MAX_VAR_INT_SIZE = 8; - const MIN_HEADER_SIZE = 2; - const MAX_HEADER_SIZE = 2 * MAX_VAR_INT_SIZE; - const readVarIntSize = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - slice.skip(-1); - if (firstByte === 0) { - return null; - } - let width = 1; - let mask = 128; - while ((firstByte & mask) === 0) { - width++; - mask >>= 1; - } - if (slice.remainingLength < width) { - return null; - } - return width; - }; - const readVarInt = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - if (firstByte === 0) { - return null; - } - let width = 1; - let mask = 1 << 7; - while ((firstByte & mask) === 0) { - width++; - mask >>= 1; - } - if (slice.remainingLength < width - 1) { - return null; - } - let value = firstByte & mask - 1; - for (let i = 1; i < width; i++) { - value *= 1 << 8; - value += readU8(slice); - } - return value; - }; - const readUnsignedInt = (slice, width) => { - if (width < 1 || width > 8) { - throw new Error("Bad unsigned int size " + width); - } - let value = 0; - for (let i = 0; i < width; i++) { - value *= 1 << 8; - value += readU8(slice); - } - return value; - }; - const readUnsignedBigInt = (slice, width) => { - if (width < 1) { - throw new Error("Bad unsigned int size " + width); - } - let value = 0n; - for (let i = 0; i < width; i++) { - value <<= 8n; - value += BigInt(readU8(slice)); - } - return value; - }; - const readElementId = (slice) => { - const size = readVarIntSize(slice); - if (size === null) { - return null; - } - if (slice.remainingLength < size) { - return null; - } - const id = readUnsignedInt(slice, size); - return id; - }; - const readElementSize = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - if (firstByte === 255) { - return void 0; - } - slice.skip(-1); - const size = readVarInt(slice); - if (size === null) { - return null; - } - if (size === 72057594037927940) { - return void 0; - } - return size; - }; - const readElementHeader = (slice) => { - assert(slice.remainingLength >= MIN_HEADER_SIZE); - const id = readElementId(slice); - if (id === null) { - return null; - } - const size = readElementSize(slice); - if (size === null) { - return null; - } - return { id, size }; - }; - const readAsciiString = (slice, length) => { - const bytes = readBytes(slice, length); - let strLength = 0; - while (strLength < length && bytes[strLength] !== 0) { - strLength += 1; - } - return String.fromCharCode(...bytes.subarray(0, strLength)); - }; - const readUnicodeString = (slice, length) => { - const bytes = readBytes(slice, length); - let strLength = 0; - while (strLength < length && bytes[strLength] !== 0) { - strLength += 1; - } - return textDecoder.decode(bytes.subarray(0, strLength)); - }; - const readFloat = (slice, width) => { - if (width === 0) { - return 0; - } - if (width !== 4 && width !== 8) { - throw new Error("Bad float size " + width); - } - return width === 4 ? readF32Be(slice) : readF64Be(slice); - }; - const searchForNextElementId = async (reader, startPos, ids, until) => { - const idsSet = new Set(ids); - let currentPos = startPos; - while (until === null || currentPos < until) { - let slice = reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementHeader = readElementHeader(slice); - if (!elementHeader) { - break; - } - if (idsSet.has(elementHeader.id)) { - return { pos: currentPos, found: true }; - } - assertDefinedSize(elementHeader.size); - currentPos = slice.filePos + elementHeader.size; - } - return { pos: until !== null && until > currentPos ? until : currentPos, found: false }; - }; - const resync = async (reader, startPos, ids, until) => { - const CHUNK_SIZE = 2 ** 16; - const idsSet = new Set(ids); - let currentPos = startPos; - while (currentPos < until) { - let slice = reader.requestSliceRange(currentPos, 0, Math.min(CHUNK_SIZE, until - currentPos)); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - if (slice.length < MAX_VAR_INT_SIZE) - break; - for (let i = 0; i < slice.length - MAX_VAR_INT_SIZE; i++) { - slice.filePos = currentPos; - const elementId = readElementId(slice); - if (elementId !== null && idsSet.has(elementId)) { - return currentPos; + const mergeInputTrackQueries = (queryA, queryB) => { + return { + filter: queryA?.filter || queryB?.filter ? (track) => { + const resultA = queryA?.filter?.(track) ?? true; + const handleResultA = (resultA2) => { + if (resultA2 === false) { + return false; + } + return queryB?.filter?.(track) ?? true; + }; + if (resultA instanceof Promise) { + return resultA.then(handleResultA); + } else { + return handleResultA(resultA); } - currentPos++; + } : void 0, + sortBy: queryA?.sortBy || queryB?.sortBy ? (track) => { + const resultA = queryA?.sortBy?.(track) ?? []; + const resultB = queryB?.sortBy?.(track) ?? []; + const join = (resultA2, resultB2) => { + return [ + ...Array.isArray(resultA2) ? resultA2 : [resultA2], + ...Array.isArray(resultB2) ? resultB2 : [resultB2] + ]; + }; + if (resultA instanceof Promise || resultB instanceof Promise) { + return Promise.all([resultA, resultB]).then(([resultA2, resultB2]) => { + return join(resultA2, resultB2); + }); + } else { + return join(resultA, resultB); + } + } : void 0 + }; + }; + const queryInputTracks = async (tracks, query) => { + let matched = tracks; + if (query?.filter) { + const filterMatches = tracks.map((t) => query.filter(t)); + const hasAsyncFilter = filterMatches.some((x) => x instanceof Promise); + if (hasAsyncFilter) { + const resolvedFilterMatches = await Promise.all(filterMatches); + matched = tracks.filter((_, i) => resolvedFilterMatches[i]); + } else { + matched = tracks.filter((_, i) => filterMatches[i]); } } - return null; - }; - const CODEC_STRING_MAP = { - "avc": "V_MPEG4/ISO/AVC", - "hevc": "V_MPEGH/ISO/HEVC", - "vp8": "V_VP8", - "vp9": "V_VP9", - "av1": "V_AV1", - "aac": "A_AAC", - "mp3": "A_MPEG/L3", - "opus": "A_OPUS", - "vorbis": "A_VORBIS", - "flac": "A_FLAC" - }; - function assertDefinedSize(size) { - if (size === void 0) { - throw new Error("Undefined element size is used in a place where it is not supported."); + if (!query?.sortBy) { + return matched; } + const sortValues = matched.map((t) => query.sortBy(t)); + const hasAsyncSort = sortValues.some((x) => x instanceof Promise); + const resolvedSortValues = hasAsyncSort ? await Promise.all(sortValues) : sortValues; + return matched.map((track, i) => ({ track, sortValue: resolvedSortValues[i] })).sort((a, b) => { + const aValues = Array.isArray(a.sortValue) ? a.sortValue : [a.sortValue]; + const bValues = Array.isArray(b.sortValue) ? b.sortValue : [b.sortValue]; + const maxLength = Math.max(aValues.length, bValues.length); + for (let i = 0; i < maxLength; i++) { + const aValue = aValues[i] ?? 0; + const bValue = bValues[i] ?? 0; + if (aValue === bValue) { + continue; + } + return aValue - bValue; + } + return 0; + }).map((x) => x.track); + }; + polyfillSymbolDispose(); + const DEFAULT_SOURCE_CACHE_GROUP = 1; + const ENCRYPTION_KEY_CACHE_GROUP = 2; + let inputFinalizationRegistry = null; + if (typeof FinalizationRegistry !== "undefined") { + inputFinalizationRegistry = new FinalizationRegistry((refs) => { + for (const ref of refs) { + if (!ref.freed) { + ref.free(); + } + } + }); } - const buildMatroskaMimeType = (info) => { - const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; - let string = base + (info.isWebM ? "webm" : "x-matroska"); - if (info.codecStrings.length > 0) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings.filter(Boolean))]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; + class Input extends EventEmitter { + /** True if the input has been disposed. */ + get disposed() { + return this._disposed; } - return string; - }; - var BlockLacing; - (function(BlockLacing2) { - BlockLacing2[BlockLacing2["None"] = 0] = "None"; - BlockLacing2[BlockLacing2["Xiph"] = 1] = "Xiph"; - BlockLacing2[BlockLacing2["FixedSize"] = 2] = "FixedSize"; - BlockLacing2[BlockLacing2["Ebml"] = 3] = "Ebml"; - })(BlockLacing || (BlockLacing = {})); - var ContentEncodingScope; - (function(ContentEncodingScope2) { - ContentEncodingScope2[ContentEncodingScope2["Block"] = 1] = "Block"; - ContentEncodingScope2[ContentEncodingScope2["Private"] = 2] = "Private"; - ContentEncodingScope2[ContentEncodingScope2["Next"] = 4] = "Next"; - })(ContentEncodingScope || (ContentEncodingScope = {})); - var ContentCompAlgo; - (function(ContentCompAlgo2) { - ContentCompAlgo2[ContentCompAlgo2["Zlib"] = 0] = "Zlib"; - ContentCompAlgo2[ContentCompAlgo2["Bzlib"] = 1] = "Bzlib"; - ContentCompAlgo2[ContentCompAlgo2["lzo1x"] = 2] = "lzo1x"; - ContentCompAlgo2[ContentCompAlgo2["HeaderStripping"] = 3] = "HeaderStripping"; - })(ContentCompAlgo || (ContentCompAlgo = {})); - const METADATA_ELEMENTS = [ - { id: EBMLId.SeekHead, flag: "seekHeadSeen" }, - { id: EBMLId.Info, flag: "infoSeen" }, - { id: EBMLId.Tracks, flag: "tracksSeen" }, - { id: EBMLId.Cues, flag: "cuesSeen" } - ]; - const MAX_RESYNC_LENGTH = 10 * 2 ** 20; - class MatroskaDemuxer extends Demuxer { - constructor(input) { - super(input); - this.readMetadataPromise = null; - this.segments = []; - this.currentSegment = null; - this.currentTrack = null; - this.currentCluster = null; - this.currentBlock = null; - this.currentBlockAdditional = null; - this.currentCueTime = null; - this.currentDecodingInstruction = null; - this.currentTagTargetIsMovie = true; - this.currentSimpleTagName = null; - this.currentAttachedFile = null; - this.isWebM = false; - this.reader = input._reader; + /** + * Creates a new input file from the specified options. No reading operations will be performed until methods are + * called on this instance. + */ + constructor(options) { + super(); + this._demuxerPromise = null; + this._format = null; + this._trackBackingsCache = null; + this._backingToTrack = /* @__PURE__ */ new Map(); + this._disposed = false; + this._nextSourceCacheAge = 0; + this._sourceRefs = []; + this._sourceCache = []; + this._sourceCachePromises = []; + this._onFormatDetermined = null; + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (!Array.isArray(options.formats) || options.formats.some((x) => !(x instanceof InputFormat))) { + throw new TypeError("options.formats must be an array of InputFormat."); + } + if (!(options.source instanceof Source || options.source instanceof SourceRef)) { + throw new TypeError("options.source must be a Source or SourceRef."); + } + if (options.source instanceof Source && options.source._disposed) { + throw new TypeError("options.source must not be a disposed Source."); + } + if (options.initInput !== void 0 && !(options.initInput instanceof Input)) { + throw new TypeError("options.initInput, when provided, must be an Input."); + } + if (options.formatOptions !== void 0) { + validateInputFormatOptions(options.formatOptions, "formatOptions"); + } + this._formats = options.formats; + this._initInput = options.initInput ?? null; + this._formatOptions = options.formatOptions ?? {}; + if (options.source instanceof Source) { + this._rootRef = options.source.ref(); + } else { + this._rootRef = options.source; + } + this._sourceRefs.push(this._rootRef); + inputFinalizationRegistry?.register(this, this._sourceRefs, this); } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); + /** @internal */ + get _rootSource() { + return this._rootRef.source; } - async getTracks() { - await this.readMetadata(); - return this.segments.flatMap((segment) => segment.tracks.map((track) => track.inputTrack)); + /** @internal */ + async _getSourceUncached(request) { + assert(this._rootSource instanceof PathedSource); + const ref = await this._rootSource._resolveRequest(request); + this._emit("source", { source: ref.source, request, isRoot: request.isRoot }); + return ref; } - async getMimeType() { - await this.readMetadata(); - const tracks = await this.getTracks(); - const codecStrings = await Promise.all(tracks.map((x) => x.getCodecParameterString())); - return buildMatroskaMimeType({ - isWebM: this.isWebM, - hasVideo: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "video")), - hasAudio: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "audio")), - codecStrings: codecStrings.filter(Boolean) + /** @internal */ + _getSourceCached(request, cacheGroup = DEFAULT_SOURCE_CACHE_GROUP) { + const cachedEntry = this._sourceCache.find((x) => x.cacheGroup === cacheGroup && sourceRequestsAreEqual(x.request, request)); + if (cachedEntry) { + cachedEntry.age++; + return Promise.resolve(cachedEntry.sourceRef.source.ref()); + } + const cachedPromiseEntry = this._sourceCachePromises.find((x) => x.cacheGroup === cacheGroup && sourceRequestsAreEqual(x.request, request)); + if (cachedPromiseEntry) { + return cachedPromiseEntry.promise.then((x) => x.sourceRef.source.ref()); + } + const promise = (async () => { + const sourceRef = await this._getSourceUncached(request); + const MAX_SOURCE_CACHE_SIZE = 4; + const count = arrayCount(this._sourceCache, (x) => x.cacheGroup === cacheGroup && x.sourceRef.source._refCount === 1); + if (count >= MAX_SOURCE_CACHE_SIZE) { + const minAgeIndex = arrayArgmin(this._sourceCache, (x) => x.cacheGroup === cacheGroup && x.sourceRef.source._refCount === 1 ? x.age : Infinity); + assert(minAgeIndex !== -1); + const entry = this._sourceCache[minAgeIndex]; + this._sourceCache.splice(minAgeIndex, 1); + entry.sourceRef.free(); + removeItem(this._sourceRefs, entry.sourceRef); + } + this._sourceRefs.push(sourceRef); + const promiseIndex = this._sourceCachePromises.findIndex((x) => x.request === request); + assert(promiseIndex !== -1); + this._sourceCachePromises.splice(promiseIndex, 1); + const cacheEntry = { + request, + sourceRef, + age: this._nextSourceCacheAge++, + cacheGroup + }; + return cacheEntry; + })(); + this._sourceCachePromises.push({ + request, + cacheGroup, + promise + }); + return promise.then((entry) => { + const ref = entry.sourceRef.source.ref(); + this._sourceCache.push(entry); + return ref; }); } - async getMetadataTags() { - await this.readMetadata(); - for (const segment of this.segments) { - if (!segment.metadataTagsCollected) { - if (this.reader.fileSize !== null) { - await this.loadSegmentMetadata(segment); + /** @internal */ + _getDemuxer() { + return this._demuxerPromise ?? (this._demuxerPromise = (async () => { + this._reader = new Reader(this._rootSource); + this._emit("source", { source: this._rootSource, request: null, isRoot: true }); + for (const format of this._formats) { + const canRead = await format._canReadInput(this); + if (canRead) { + this._format = format; + this._onFormatDetermined?.(format); + return format._createDemuxer(this); } - segment.metadataTagsCollected = true; - } - } - let metadataTags = {}; - for (const segment of this.segments) { - metadataTags = { ...metadataTags, ...segment.metadataTags }; - } - return metadataTags; - } - readMetadata() { - return this.readMetadataPromise ?? (this.readMetadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const header = readElementHeader(slice); - if (!header) { - break; - } - const id = header.id; - let size = header.size; - const dataStartPos = slice.filePos; - if (id === EBMLId.EBML) { - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - this.readContiguousElements(slice2); - } else if (id === EBMLId.Segment) { - await this.readSegment(dataStartPos, size); - if (size === void 0) { - break; - } - if (this.reader.fileSize === null) { - break; - } - } else if (id === EBMLId.Cluster) { - if (this.reader.fileSize === null) { - break; - } - if (size === void 0) { - const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, this.reader.fileSize); - size = nextElementPos.pos - dataStartPos; - } - const lastSegment = last(this.segments); - if (lastSegment) { - lastSegment.elementEndPos = dataStartPos + size; - } - } - assertDefinedSize(size); - currentPos = dataStartPos + size; } + throw new UnsupportedInputFormatError(); })()); } - async readSegment(segmentDataStart, dataSize) { - this.currentSegment = { - seekHeadSeen: false, - infoSeen: false, - tracksSeen: false, - cuesSeen: false, - tagsSeen: false, - attachmentsSeen: false, - timestampScale: -1, - timestampFactor: -1, - duration: -1, - seekEntries: [], - tracks: [], - cuePoints: [], - dataStartPos: segmentDataStart, - elementEndPos: dataSize === void 0 ? null : segmentDataStart + dataSize, - clusterSeekStartPos: segmentDataStart, - lastReadCluster: null, - metadataTags: {}, - metadataTagsCollected: false - }; - this.segments.push(this.currentSegment); - let currentPos = segmentDataStart; - while (this.currentSegment.elementEndPos === null || currentPos < this.currentSegment.elementEndPos) { - let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementStartPos = currentPos; - const header = readElementHeader(slice); - if (!header || !LEVEL_1_EBML_IDS.includes(header.id) && header.id !== EBMLId.Void) { - const nextPos = await resync(this.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(this.currentSegment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); - if (nextPos) { - currentPos = nextPos; - continue; - } else { - break; - } - } - const { id, size } = header; - const dataStartPos = slice.filePos; - const metadataElementIndex = METADATA_ELEMENTS.findIndex((x) => x.id === id); - if (metadataElementIndex !== -1) { - const field = METADATA_ELEMENTS[metadataElementIndex].flag; - this.currentSegment[field] = true; - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (slice2) { - this.readContiguousElements(slice2); - } - } else if (id === EBMLId.Tags || id === EBMLId.Attachments) { - if (id === EBMLId.Tags) { - this.currentSegment.tagsSeen = true; - } else { - this.currentSegment.attachmentsSeen = true; - } - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (slice2) { - this.readContiguousElements(slice2); - } - } else if (id === EBMLId.Cluster) { - this.currentSegment.clusterSeekStartPos = elementStartPos; - break; - } - if (size === void 0) { - break; - } else { - currentPos = dataStartPos + size; - } - } - this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition); - if (this.reader.fileSize !== null) { - for (const seekEntry of this.currentSegment.seekEntries) { - const target = METADATA_ELEMENTS.find((x) => x.id === seekEntry.id); - if (!target) { - continue; - } - if (this.currentSegment[target.flag]) - continue; - let slice = this.reader.requestSliceRange(segmentDataStart + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - continue; - const header = readElementHeader(slice); - if (!header) - continue; - const { id, size } = header; - if (id !== target.id) - continue; - assertDefinedSize(size); - this.currentSegment[target.flag] = true; - let dataSlice = this.reader.requestSlice(slice.filePos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (!dataSlice) - continue; - this.readContiguousElements(dataSlice); - } - } - if (this.currentSegment.timestampScale === -1) { - this.currentSegment.timestampScale = 1e6; - this.currentSegment.timestampFactor = 1e9 / 1e6; - } - for (const track of this.currentSegment.tracks) { - if (track.defaultDurationNs !== null) { - track.defaultDuration = this.currentSegment.timestampFactor * track.defaultDurationNs / 1e9; - } - } - this.currentSegment.tracks.sort((a, b) => Number(b.disposition.default) - Number(a.disposition.default)); - const idToTrack = new Map(this.currentSegment.tracks.map((x) => [x.id, x])); - for (const cuePoint of this.currentSegment.cuePoints) { - const track = idToTrack.get(cuePoint.trackId); - if (track) { - track.cuePoints.push(cuePoint); - } - } - for (const track of this.currentSegment.tracks) { - track.cuePoints.sort((a, b) => a.time - b.time); - for (let i = 0; i < track.cuePoints.length - 1; i++) { - const cuePoint1 = track.cuePoints[i]; - const cuePoint2 = track.cuePoints[i + 1]; - if (cuePoint1.time === cuePoint2.time) { - track.cuePoints.splice(i + 1, 1); - i--; - } - } - } - let trackWithMostCuePoints = null; - let maxCuePointCount = -Infinity; - for (const track of this.currentSegment.tracks) { - if (track.cuePoints.length > maxCuePointCount) { - maxCuePointCount = track.cuePoints.length; - trackWithMostCuePoints = track; - } - } - for (const track of this.currentSegment.tracks) { - if (track.cuePoints.length === 0) { - track.cuePoints = trackWithMostCuePoints.cuePoints; - } - } - this.currentSegment = null; + /** + * Returns the source from which this input file reads data for the root path. + */ + get source() { + return this._rootSource; } - async readCluster(startPos, segment) { - if (segment.lastReadCluster?.elementStartPos === startPos) { - return segment.lastReadCluster; + /** + * Returns the format of the input file. You can compare this result directly to the {@link InputFormat} singletons + * or use `instanceof` checks for subset-aware logic (for example, `format instanceof MatroskaInputFormat` is true + * for both MKV and WebM). + */ + async getFormat() { + await this._getDemuxer(); + assert(this._format); + return this._format; + } + /** Returns `true` if the format of the input file is known and the file can be read, `false` otherwise. */ + async canRead() { + try { + await this._getDemuxer(); + return true; + } catch (error) { + if (error instanceof UnsupportedInputFormatError) { + return false; + } + throw error; } - let headerSlice = this.reader.requestSliceRange(startPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const elementStartPos = startPos; - const elementHeader = readElementHeader(headerSlice); - assert(elementHeader); - const id = elementHeader.id; - assert(id === EBMLId.Cluster); - let size = elementHeader.size; - const dataStartPos = headerSlice.filePos; + } + /** + * Returns the timestamp at which the input file starts. More precisely, returns the smallest starting timestamp + * among all tracks. + * + * Optionally, you can pass in the list of tracks for which you want to compute the starting timestamp. + * + * Note that this method is potentially expensive for inputs with many tracks (such as HLS manifests), since it + * probes every track. + */ + async getFirstTimestamp(tracks) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + if (filtered.length === 0) { + return 0; + } + const firstTimestamps = await Promise.all(filtered.map((x) => x.getFirstTimestamp())); + return Math.min(...firstTimestamps); + } + /** + * Computes the duration of the input file, in seconds. More precisely, returns the largest end timestamp among + * all tracks. + * + * Optionally, you can pass in the list of tracks for which you want to compute the duration. + * + * This method can be potentially expensive depending on the underlying file format, because it returns the most + * accurate duration possible and must check all tracks. Use {@link Input.getDurationFromMetadata} for a faster but + * less accurate estimate of duration. + * + * By default, when any track in the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set {@link PacketRetrievalOptions.skipLiveWait} + * to `true` in the options. + */ + async computeDuration(tracks, options) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + if (filtered.length === 0) { + return 0; + } + const tracksDurations = await Promise.all(filtered.map((x) => x.computeDuration(options))); + return Math.max(...tracksDurations); + } + /** + * Gets the duration (end timestamp) in seconds of the input file from metadata stored in the file. This value may + * be approximate or diverge from the actual, precise duration returned by `.computeDuration()`, but compared to + * that method, this method is cheaper. When the duration cannot be determined from the file metadata, `null` + * is returned. + * + * Optionally, you can pass in the list of tracks for which you want to get the duration from metadata. + * + * By default, when the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set + * {@link DurationMetadataRequestOptions.skipLiveWait} to `true` in the options. + */ + async getDurationFromMetadata(tracks, options) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + const tracksDurations = await Promise.all(filtered.map((x) => x.getDurationFromMetadata(options))); + const nonNullDurations = tracksDurations.filter((x) => x !== null); + if (nonNullDurations.length === 0) { + return null; + } + return Math.max(...nonNullDurations); + } + /** + * Returns the list of all tracks of this input file in the order in which they appear in the file. An optional + * query can be provided. + */ + async getTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const backings = await this._getTrackBackings(); + const tracks = backings.map((backing) => this._wrapBackingAsTrack(backing)); + return queryInputTracks(tracks, query); + } + /** Returns the list of all video tracks of this input file. An optional query can be provided. */ + async getVideoTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const tracks = await this.getTracks(); + const videoTracks = tracks.filter((x) => x.isVideoTrack()); + return queryInputTracks(videoTracks, query); + } + /** Returns the list of all audio tracks of this input file. An optional query can be provided. */ + async getAudioTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const tracks = await this.getTracks(); + const audioTracks = tracks.filter((x) => x.isAudioTrack()); + return queryInputTracks(audioTracks, query); + } + /** + * Returns the primary video track of this input file, or null if there are no video tracks. + * + * Multiple factors determine which track is considered primary, including its position in the file, disposition, + * bitrate (higher bitrate is preferred), and if it can be paired with an audio track. + */ + async getPrimaryVideoTrack(query) { + query && (query = toValidatedInputTrackQuery(query)); + const merged = mergeInputTrackQueries(query, { + sortBy: async (t) => [ + prefer((await t.getDisposition()).default), + prefer(await t.hasPairableAudioTrack()), + prefer(!await t.hasOnlyKeyPackets()), + desc(await t.getBitrate()) + ] + }); + const sorted = await this.getVideoTracks(merged); + return sorted[0] ?? null; + } + /** + * Returns the primary audio track of this input file, or null if there are no audio tracks. + * + * Multiple factors determine which track is considered primary, including its position in the file, disposition, + * bitrate (higher bitrate is preferred), and if it can be paired with the primary video track. + */ + async getPrimaryAudioTrack(query) { + query && (query = toValidatedInputTrackQuery(query)); + const primaryVideoTrack = await this.getPrimaryVideoTrack(); + const merged = mergeInputTrackQueries(query, { + sortBy: async (t) => [ + prefer(!primaryVideoTrack || t.canBePairedWith(primaryVideoTrack)), + prefer((await t.getDisposition()).default), + desc(await t.getBitrate()) + ] + }); + const sorted = await this.getAudioTracks(merged); + return sorted[0] ?? null; + } + /** @internal */ + async _getTrackBackings() { + const demuxer = await this._getDemuxer(); + return this._trackBackingsCache ?? (this._trackBackingsCache = await demuxer.getTrackBackings()); + } + /** @internal */ + _wrapBackingAsTrack(backing) { + const existing = this._backingToTrack.get(backing); + if (existing) { + return existing; + } + const type = backing.getType(); + const track = type === "video" ? new InputVideoTrack(this, backing) : new InputAudioTrack(this, backing); + this._backingToTrack.set(backing, track); + return track; + } + /** Returns the full MIME type of this input file, including track codecs. */ + async getMimeType() { + const demuxer = await this._getDemuxer(); + return demuxer.getMimeType(); + } + /** + * Returns descriptive metadata tags about the media file, such as title, author, date, cover art, or other + * attached files. + */ + async getMetadataTags() { + const demuxer = await this._getDemuxer(); + return demuxer.getMetadataTags(); + } + /** + * Disposes this input and frees connected resources. When an input is disposed, ongoing read operations will be + * canceled, all future read operations will fail, any open decoders will be closed, and all ongoing media sink + * operations will be canceled. Disallowed and canceled operations will throw an {@link InputDisposedError}. + * + * You are expected not to use an input after disposing it. While some operations may still work, it is not + * specified and may change in any future update. + */ + dispose() { + if (this._disposed) { + return; + } + this._disposed = true; + for (const ref of this._sourceRefs) { + ref.free(); + } + this._sourceRefs.length = 0; + inputFinalizationRegistry?.unregister(this); + void this._demuxerPromise?.then((demuxer) => demuxer.dispose()); + } + /** + * Calls `.dispose()` on the input, implementing the `Disposable` interface for use with + * JavaScript Explicit Resource Management features. + */ + [Symbol.dispose]() { + this.dispose(); + } + } + class UnsupportedInputFormatError extends Error { + /** Creates a new {@link UnsupportedInputFormatError}. */ + constructor(message = "Input has an unsupported or unrecognizable format.") { + super(message); + this.name = "UnsupportedInputFormatError"; + } + } + class InputDisposedError extends Error { + /** Creates a new {@link InputDisposedError}. */ + constructor(message = "Input has been disposed.") { + super(message); + this.name = "InputDisposedError"; + } + } + class Reader { + constructor(source) { + this.source = source; + } + get fileSize() { + const size = this.source._getFileSize(); if (size === void 0) { - const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); - size = nextElementPos.pos - dataStartPos; + throw new Error("Reading file size too early; read required first."); } - let dataSlice = this.reader.requestSlice(dataStartPos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - const cluster = { - segment, - elementStartPos, - elementEndPos: dataStartPos + size, - dataStartPos, - timestamp: -1, - trackData: /* @__PURE__ */ new Map() - }; - this.currentCluster = cluster; - if (dataSlice) { - const endPos = this.readContiguousElements(dataSlice, LEVEL_0_AND_1_EBML_IDS); - cluster.elementEndPos = endPos; - } - for (const [, trackData] of cluster.trackData) { - const track = trackData.track; - assert(trackData.blocks.length > 0); - let hasLacedBlocks = false; - for (let i = 0; i < trackData.blocks.length; i++) { - const block = trackData.blocks[i]; - block.timestamp += cluster.timestamp; - hasLacedBlocks || (hasLacedBlocks = block.lacing !== BlockLacing.None); - } - trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); - for (let i = 0; i < trackData.presentationTimestamps.length; i++) { - const currentEntry = trackData.presentationTimestamps[i]; - const currentBlock = trackData.blocks[currentEntry.blockIndex]; - if (trackData.firstKeyFrameTimestamp === null && currentBlock.isKeyFrame) { - trackData.firstKeyFrameTimestamp = currentBlock.timestamp; - } - if (i < trackData.presentationTimestamps.length - 1) { - const nextEntry = trackData.presentationTimestamps[i + 1]; - currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp; - } else if (currentBlock.duration === 0) { - if (track.defaultDuration != null) { - if (currentBlock.lacing === BlockLacing.None) { - currentBlock.duration = track.defaultDuration; - } - } - } - } - if (hasLacedBlocks) { - this.expandLacedBlocks(trackData.blocks, track); - trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); - } - const firstBlock = trackData.blocks[trackData.presentationTimestamps[0].blockIndex]; - const lastBlock = trackData.blocks[last(trackData.presentationTimestamps).blockIndex]; - trackData.startTimestamp = firstBlock.timestamp; - trackData.endTimestamp = lastBlock.timestamp + lastBlock.duration; - const insertionIndex = binarySearchLessOrEqual(track.clusterPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); - if (insertionIndex === -1 || track.clusterPositionCache[insertionIndex].elementStartPos !== elementStartPos) { - track.clusterPositionCache.splice(insertionIndex + 1, 0, { - elementStartPos: cluster.elementStartPos, - startTimestamp: trackData.startTimestamp - }); - } - } - segment.lastReadCluster = cluster; - return cluster; + return size; } - getTrackDataInCluster(cluster, trackNumber) { - let trackData = cluster.trackData.get(trackNumber); - if (!trackData) { - const track = cluster.segment.tracks.find((x) => x.id === trackNumber); - if (!track) { + get fileSizeNonStrict() { + return this.source._getFileSize() ?? null; + } + requestSlice(start, length) { + if (this.source._disposed) { + throw new InputDisposedError(); + } + if (start < 0) { + return null; + } + if (this.fileSizeNonStrict !== null && start + length > this.fileSizeNonStrict) { + return null; + } + if (length === 0) { + const buffer = new Uint8Array(0); + return new FileSlice(buffer, toDataView(buffer), 0, start, start); + } + const end = start + length; + const result = this.source._read(start, end, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION); + if (result instanceof Promise) { + return result.then((x) => { + if (!x) { + return null; + } + return new FileSlice(x.bytes, x.view, x.offset, start, end); + }); + } else { + if (!result) { return null; } - trackData = { - track, - startTimestamp: 0, - endTimestamp: 0, - firstKeyFrameTimestamp: null, - blocks: [], - presentationTimestamps: [] - }; - cluster.trackData.set(trackNumber, trackData); - } - return trackData; - } - expandLacedBlocks(blocks, track) { - for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) { - const originalBlock = blocks[blockIndex]; - if (originalBlock.lacing === BlockLacing.None) { - continue; - } - if (!originalBlock.decoded) { - originalBlock.data = this.decodeBlockData(track, originalBlock.data); - originalBlock.decoded = true; - } - const slice = FileSlice.tempFromBytes(originalBlock.data); - const frameSizes = []; - const frameCount = readU8(slice) + 1; - switch (originalBlock.lacing) { - case BlockLacing.Xiph: - { - let totalUsedSize = 0; - for (let i = 0; i < frameCount - 1; i++) { - let frameSize = 0; - while (slice.bufferPos < slice.length) { - const value = readU8(slice); - frameSize += value; - if (value < 255) { - frameSizes.push(frameSize); - totalUsedSize += frameSize; - break; - } - } - } - frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); - } - break; - case BlockLacing.FixedSize: - { - const totalDataSize = slice.length - 1; - const frameSize = Math.floor(totalDataSize / frameCount); - for (let i = 0; i < frameCount; i++) { - frameSizes.push(frameSize); - } - } - break; - case BlockLacing.Ebml: - { - const firstResult = readVarInt(slice); - assert(firstResult !== null); - let currentSize = firstResult; - frameSizes.push(currentSize); - let totalUsedSize = currentSize; - for (let i = 1; i < frameCount - 1; i++) { - const startPos = slice.bufferPos; - const diffResult = readVarInt(slice); - assert(diffResult !== null); - const unsignedDiff = diffResult; - const width = slice.bufferPos - startPos; - const bias = (1 << width * 7 - 1) - 1; - const diff = unsignedDiff - bias; - currentSize += diff; - frameSizes.push(currentSize); - totalUsedSize += currentSize; - } - frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); - } - break; - default: - assert(false); - } - assert(frameSizes.length === frameCount); - blocks.splice(blockIndex, 1); - const blockDuration = originalBlock.duration || frameCount * (track.defaultDuration ?? 0); - for (let i = 0; i < frameCount; i++) { - const frameSize = frameSizes[i]; - const frameData = readBytes(slice, frameSize); - const frameTimestamp = originalBlock.timestamp + blockDuration * i / frameCount; - const frameDuration = blockDuration / frameCount; - blocks.splice(blockIndex + i, 0, { - timestamp: frameTimestamp, - duration: frameDuration, - isKeyFrame: originalBlock.isKeyFrame, - data: frameData, - lacing: BlockLacing.None, - decoded: true, - mainAdditional: originalBlock.mainAdditional - }); - } - blockIndex += frameCount; - blockIndex--; + return new FileSlice(result.bytes, result.view, result.offset, start, end); } } - async loadSegmentMetadata(segment) { - for (const seekEntry of segment.seekEntries) { - if (seekEntry.id === EBMLId.Tags && !segment.tagsSeen) ; - else if (seekEntry.id === EBMLId.Attachments && !segment.attachmentsSeen) ; - else { - continue; - } - let slice = this.reader.requestSliceRange(segment.dataStartPos + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - continue; - const header = readElementHeader(slice); - if (!header || header.id !== seekEntry.id) - continue; - const { size } = header; - assertDefinedSize(size); - assert(!this.currentSegment); - this.currentSegment = segment; - let dataSlice = this.reader.requestSlice(slice.filePos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (dataSlice) { - this.readContiguousElements(dataSlice); - } - this.currentSegment = null; - if (seekEntry.id === EBMLId.Tags) { - segment.tagsSeen = true; - } else if (seekEntry.id === EBMLId.Attachments) { - segment.attachmentsSeen = true; - } + requestSliceRange(start, minLength, maxLength) { + if (this.source._disposed) { + throw new InputDisposedError(); } - } - readContiguousElements(slice, stopIds) { - while (slice.remainingLength >= MIN_HEADER_SIZE) { - const startPos = slice.filePos; - const foundElement = this.traverseElement(slice, stopIds); - if (!foundElement) { - return startPos; - } - } - return slice.filePos; - } - traverseElement(slice, stopIds) { - const header = readElementHeader(slice); - if (!header) { - return false; - } - if (stopIds && stopIds.includes(header.id)) { - return false; - } - const { id, size } = header; - const dataStartPos = slice.filePos; - assertDefinedSize(size); - switch (id) { - case EBMLId.DocType: - { - this.isWebM = readAsciiString(slice, size) === "webm"; - } - break; - case EBMLId.Seek: - { - if (!this.currentSegment) - break; - const seekEntry = { id: -1, segmentPosition: -1 }; - this.currentSegment.seekEntries.push(seekEntry); - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (seekEntry.id === -1 || seekEntry.segmentPosition === -1) { - this.currentSegment.seekEntries.pop(); - } - } - break; - case EBMLId.SeekID: - { - const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; - if (!lastSeekEntry) - break; - lastSeekEntry.id = readUnsignedInt(slice, size); - } - break; - case EBMLId.SeekPosition: - { - const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; - if (!lastSeekEntry) - break; - lastSeekEntry.segmentPosition = readUnsignedInt(slice, size); - } - break; - case EBMLId.TimestampScale: - { - if (!this.currentSegment) - break; - this.currentSegment.timestampScale = readUnsignedInt(slice, size); - this.currentSegment.timestampFactor = 1e9 / this.currentSegment.timestampScale; - } - break; - case EBMLId.Duration: - { - if (!this.currentSegment) - break; - this.currentSegment.duration = readFloat(slice, size); - } - break; - case EBMLId.TrackEntry: - { - if (!this.currentSegment) - break; - this.currentTrack = { - id: -1, - segment: this.currentSegment, - demuxer: this, - clusterPositionCache: [], - cuePoints: [], - disposition: { - ...DEFAULT_TRACK_DISPOSITION - }, - inputTrack: null, - codecId: null, - codecPrivate: null, - defaultDuration: null, - defaultDurationNs: null, - name: null, - languageCode: UNDETERMINED_LANGUAGE, - decodingInstructions: [], - info: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (!this.currentTrack) { - break; - } - if (this.currentTrack.decodingInstructions.some((instruction) => { - return instruction.data?.type !== "decompress" || instruction.scope !== ContentEncodingScope.Block || instruction.data.algorithm !== ContentCompAlgo.HeaderStripping; - })) { - console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`); - this.currentTrack = null; - } - if (this.currentTrack && this.currentTrack.id !== -1 && this.currentTrack.codecId && this.currentTrack.info) { - const slashIndex = this.currentTrack.codecId.indexOf("/"); - const codecIdWithoutSuffix = slashIndex === -1 ? this.currentTrack.codecId : this.currentTrack.codecId.slice(0, slashIndex); - if (this.currentTrack.info.type === "video" && this.currentTrack.info.width !== -1 && this.currentTrack.info.height !== -1) { - if (this.currentTrack.codecId === CODEC_STRING_MAP.avc) { - this.currentTrack.info.codec = "avc"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === CODEC_STRING_MAP.hevc) { - this.currentTrack.info.codec = "hevc"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp8) { - this.currentTrack.info.codec = "vp8"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp9) { - this.currentTrack.info.codec = "vp9"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.av1) { - this.currentTrack.info.codec = "av1"; - } - const videoTrack = this.currentTrack; - const inputTrack = new InputVideoTrack(this.input, new MatroskaVideoTrackBacking(videoTrack)); - this.currentTrack.inputTrack = inputTrack; - this.currentSegment.tracks.push(this.currentTrack); - } else if (this.currentTrack.info.type === "audio" && this.currentTrack.info.numberOfChannels !== -1 && this.currentTrack.info.sampleRate !== -1) { - if (codecIdWithoutSuffix === CODEC_STRING_MAP.aac) { - this.currentTrack.info.codec = "aac"; - this.currentTrack.info.aacCodecInfo = { - isMpeg2: this.currentTrack.codecId.includes("MPEG2") - }; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === CODEC_STRING_MAP.mp3) { - this.currentTrack.info.codec = "mp3"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.opus) { - this.currentTrack.info.codec = "opus"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - this.currentTrack.info.sampleRate = OPUS_SAMPLE_RATE; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vorbis) { - this.currentTrack.info.codec = "vorbis"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.flac) { - this.currentTrack.info.codec = "flac"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === "A_PCM/INT/LIT") { - if (this.currentTrack.info.bitDepth === 8) { - this.currentTrack.info.codec = "pcm-u8"; - } else if (this.currentTrack.info.bitDepth === 16) { - this.currentTrack.info.codec = "pcm-s16"; - } else if (this.currentTrack.info.bitDepth === 24) { - this.currentTrack.info.codec = "pcm-s24"; - } else if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-s32"; - } - } else if (this.currentTrack.codecId === "A_PCM/INT/BIG") { - if (this.currentTrack.info.bitDepth === 8) { - this.currentTrack.info.codec = "pcm-u8"; - } else if (this.currentTrack.info.bitDepth === 16) { - this.currentTrack.info.codec = "pcm-s16be"; - } else if (this.currentTrack.info.bitDepth === 24) { - this.currentTrack.info.codec = "pcm-s24be"; - } else if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-s32be"; - } - } else if (this.currentTrack.codecId === "A_PCM/FLOAT/IEEE") { - if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-f32"; - } else if (this.currentTrack.info.bitDepth === 64) { - this.currentTrack.info.codec = "pcm-f64"; - } - } - const audioTrack = this.currentTrack; - const inputTrack = new InputAudioTrack(this.input, new MatroskaAudioTrackBacking(audioTrack)); - this.currentTrack.inputTrack = inputTrack; - this.currentSegment.tracks.push(this.currentTrack); - } - } - this.currentTrack = null; - } - break; - case EBMLId.TrackNumber: - { - if (!this.currentTrack) - break; - this.currentTrack.id = readUnsignedInt(slice, size); - } - break; - case EBMLId.TrackType: - { - if (!this.currentTrack) - break; - const type = readUnsignedInt(slice, size); - if (type === 1) { - this.currentTrack.info = { - type: "video", - width: -1, - height: -1, - rotation: 0, - codec: null, - codecDescription: null, - colorSpace: null, - alphaMode: false - }; - } else if (type === 2) { - this.currentTrack.info = { - type: "audio", - numberOfChannels: -1, - sampleRate: -1, - bitDepth: -1, - codec: null, - codecDescription: null, - aacCodecInfo: null - }; - } - } - break; - case EBMLId.FlagEnabled: - { - if (!this.currentTrack) - break; - const enabled = readUnsignedInt(slice, size); - if (!enabled) { - this.currentTrack = null; - } - } - break; - case EBMLId.FlagDefault: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.default = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagForced: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.forced = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagOriginal: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.original = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagHearingImpaired: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.hearingImpaired = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagVisualImpaired: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.visuallyImpaired = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagCommentary: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.commentary = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.CodecID: - { - if (!this.currentTrack) - break; - this.currentTrack.codecId = readAsciiString(slice, size); - } - break; - case EBMLId.CodecPrivate: - { - if (!this.currentTrack) - break; - this.currentTrack.codecPrivate = readBytes(slice, size); - } - break; - case EBMLId.DefaultDuration: - { - if (!this.currentTrack) - break; - this.currentTrack.defaultDurationNs = readUnsignedInt(slice, size); - } - break; - case EBMLId.Name: - { - if (!this.currentTrack) - break; - this.currentTrack.name = readUnicodeString(slice, size); - } - break; - case EBMLId.Language: - { - if (!this.currentTrack) - break; - if (this.currentTrack.languageCode !== UNDETERMINED_LANGUAGE) { - break; - } - this.currentTrack.languageCode = readAsciiString(slice, size); - if (!isIso639Dash2LanguageCode(this.currentTrack.languageCode)) { - this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; - } - } - break; - case EBMLId.LanguageBCP47: - { - if (!this.currentTrack) - break; - const bcp47 = readAsciiString(slice, size); - const languageSubtag = bcp47.split("-")[0]; - if (languageSubtag) { - this.currentTrack.languageCode = languageSubtag; - } else { - this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; - } - } - break; - case EBMLId.Video: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.PixelWidth: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.width = readUnsignedInt(slice, size); - } - break; - case EBMLId.PixelHeight: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.height = readUnsignedInt(slice, size); - } - break; - case EBMLId.AlphaMode: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.alphaMode = readUnsignedInt(slice, size) === 1; - } - break; - case EBMLId.Colour: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.colorSpace = {}; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.MatrixCoefficients: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const matrixCoefficients = readUnsignedInt(slice, size); - const mapped = MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients] ?? null; - this.currentTrack.info.colorSpace.matrix = mapped; - } - break; - case EBMLId.Range: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - this.currentTrack.info.colorSpace.fullRange = readUnsignedInt(slice, size) === 2; - } - break; - case EBMLId.TransferCharacteristics: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const transferCharacteristics = readUnsignedInt(slice, size); - const mapped = TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics] ?? null; - this.currentTrack.info.colorSpace.transfer = mapped; - } - break; - case EBMLId.Primaries: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const primaries = readUnsignedInt(slice, size); - const mapped = COLOR_PRIMARIES_MAP_INVERSE[primaries] ?? null; - this.currentTrack.info.colorSpace.primaries = mapped; - } - break; - case EBMLId.Projection: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.ProjectionPoseRoll: - { - if (this.currentTrack?.info?.type !== "video") - break; - const rotation = readFloat(slice, size); - const flippedRotation = -rotation; - try { - this.currentTrack.info.rotation = normalizeRotation(flippedRotation); - } catch { - } - } - break; - case EBMLId.Audio: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.SamplingFrequency: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.sampleRate = readFloat(slice, size); - } - break; - case EBMLId.Channels: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.numberOfChannels = readUnsignedInt(slice, size); - } - break; - case EBMLId.BitDepth: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.bitDepth = readUnsignedInt(slice, size); - } - break; - case EBMLId.CuePoint: - { - if (!this.currentSegment) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentCueTime = null; - } - break; - case EBMLId.CueTime: - { - this.currentCueTime = readUnsignedInt(slice, size); - } - break; - case EBMLId.CueTrackPositions: - { - if (this.currentCueTime === null) - break; - assert(this.currentSegment); - const cuePoint = { time: this.currentCueTime, trackId: -1, clusterPosition: -1 }; - this.currentSegment.cuePoints.push(cuePoint); - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (cuePoint.trackId === -1 || cuePoint.clusterPosition === -1) { - this.currentSegment.cuePoints.pop(); - } - } - break; - case EBMLId.CueTrack: - { - const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; - if (!lastCuePoint) - break; - lastCuePoint.trackId = readUnsignedInt(slice, size); - } - break; - case EBMLId.CueClusterPosition: - { - const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; - if (!lastCuePoint) - break; - assert(this.currentSegment); - lastCuePoint.clusterPosition = this.currentSegment.dataStartPos + readUnsignedInt(slice, size); - } - break; - case EBMLId.Timestamp: - { - if (!this.currentCluster) - break; - this.currentCluster.timestamp = readUnsignedInt(slice, size); - } - break; - case EBMLId.SimpleBlock: - { - if (!this.currentCluster) - break; - const trackNumber = readVarInt(slice); - if (trackNumber === null) - break; - const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); - if (!trackData) - break; - const relativeTimestamp = readI16Be(slice); - const flags = readU8(slice); - const lacing = flags >> 1 & 3; - let isKeyFrame = !!(flags & 128); - if (trackData.track.info?.type === "audio" && trackData.track.info.codec) { - isKeyFrame = true; - } - const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); - const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; - trackData.blocks.push({ - timestamp: relativeTimestamp, - // We'll add the cluster's timestamp to this later - duration: 0, - // Will set later - isKeyFrame, - data: blockData, - lacing, - decoded: !hasDecodingInstructions, - mainAdditional: null - }); - } - break; - case EBMLId.BlockGroup: - { - if (!this.currentCluster) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentBlock = null; - } - break; - case EBMLId.Block: - { - if (!this.currentCluster) - break; - const trackNumber = readVarInt(slice); - if (trackNumber === null) - break; - const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); - if (!trackData) - break; - const relativeTimestamp = readI16Be(slice); - const flags = readU8(slice); - const lacing = flags >> 1 & 3; - const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); - const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; - this.currentBlock = { - timestamp: relativeTimestamp, - // We'll add the cluster's timestamp to this later - duration: 0, - // Will set later - isKeyFrame: true, - data: blockData, - lacing, - decoded: !hasDecodingInstructions, - mainAdditional: null - }; - trackData.blocks.push(this.currentBlock); - } - break; - case EBMLId.BlockAdditions: - { - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.BlockMore: - { - if (!this.currentBlock) - break; - this.currentBlockAdditional = { - addId: 1, - data: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (this.currentBlockAdditional.data && this.currentBlockAdditional.addId === 1) { - this.currentBlock.mainAdditional = this.currentBlockAdditional.data; - } - this.currentBlockAdditional = null; - } - break; - case EBMLId.BlockAdditional: - { - if (!this.currentBlockAdditional) - break; - this.currentBlockAdditional.data = readBytes(slice, size); - } - break; - case EBMLId.BlockAddID: - { - if (!this.currentBlockAdditional) - break; - this.currentBlockAdditional.addId = readUnsignedInt(slice, size); - } - break; - case EBMLId.BlockDuration: - { - if (!this.currentBlock) - break; - this.currentBlock.duration = readUnsignedInt(slice, size); - } - break; - case EBMLId.ReferenceBlock: - { - if (!this.currentBlock) - break; - this.currentBlock.isKeyFrame = false; - } - break; - case EBMLId.Tag: - { - this.currentTagTargetIsMovie = true; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.Targets: - { - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.TargetTypeValue: - { - const targetTypeValue = readUnsignedInt(slice, size); - if (targetTypeValue !== 50) { - this.currentTagTargetIsMovie = false; - } - } - break; - case EBMLId.TagTrackUID: - case EBMLId.TagEditionUID: - case EBMLId.TagChapterUID: - case EBMLId.TagAttachmentUID: - { - this.currentTagTargetIsMovie = false; - } - break; - case EBMLId.SimpleTag: - { - if (!this.currentTagTargetIsMovie) - break; - this.currentSimpleTagName = null; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.TagName: - { - this.currentSimpleTagName = readUnicodeString(slice, size); - } - break; - case EBMLId.TagString: - { - if (!this.currentSimpleTagName) - break; - const value = readUnicodeString(slice, size); - this.processTagValue(this.currentSimpleTagName, value); - } - break; - case EBMLId.TagBinary: - { - if (!this.currentSimpleTagName) - break; - const value = readBytes(slice, size); - this.processTagValue(this.currentSimpleTagName, value); - } - break; - case EBMLId.AttachedFile: - { - if (!this.currentSegment) - break; - this.currentAttachedFile = { - fileUid: null, - fileName: null, - fileMediaType: null, - fileData: null, - fileDescription: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - const tags = this.currentSegment.metadataTags; - if (this.currentAttachedFile.fileUid && this.currentAttachedFile.fileData) { - tags.raw ?? (tags.raw = {}); - tags.raw[this.currentAttachedFile.fileUid.toString()] = new AttachedFile(this.currentAttachedFile.fileData, this.currentAttachedFile.fileMediaType ?? void 0, this.currentAttachedFile.fileName ?? void 0, this.currentAttachedFile.fileDescription ?? void 0); - } - if (this.currentAttachedFile.fileMediaType?.startsWith("image/") && this.currentAttachedFile.fileData) { - const fileName = this.currentAttachedFile.fileName; - let kind = "unknown"; - if (fileName) { - const lowerName = fileName.toLowerCase(); - if (lowerName.startsWith("cover.")) { - kind = "coverFront"; - } else if (lowerName.startsWith("back.")) { - kind = "coverBack"; - } - } - tags.images ?? (tags.images = []); - tags.images.push({ - data: this.currentAttachedFile.fileData, - mimeType: this.currentAttachedFile.fileMediaType, - kind, - name: this.currentAttachedFile.fileName ?? void 0, - description: this.currentAttachedFile.fileDescription ?? void 0 - }); - } - this.currentAttachedFile = null; - } - break; - case EBMLId.FileUID: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileUid = readUnsignedBigInt(slice, size); - } - break; - case EBMLId.FileName: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileName = readUnicodeString(slice, size); - } - break; - case EBMLId.FileMediaType: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileMediaType = readAsciiString(slice, size); - } - break; - case EBMLId.FileData: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileData = readBytes(slice, size); - } - break; - case EBMLId.FileDescription: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileDescription = readUnicodeString(slice, size); - } - break; - case EBMLId.ContentEncodings: - { - if (!this.currentTrack) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentTrack.decodingInstructions.sort((a, b) => b.order - a.order); - } - break; - case EBMLId.ContentEncoding: - { - this.currentDecodingInstruction = { - order: 0, - scope: ContentEncodingScope.Block, - data: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (this.currentDecodingInstruction.data) { - this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction); - } - this.currentDecodingInstruction = null; - } - break; - case EBMLId.ContentEncodingOrder: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.order = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentEncodingScope: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.scope = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentCompression: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.data = { - type: "decompress", - algorithm: ContentCompAlgo.Zlib, - settings: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.ContentCompAlgo: - { - if (this.currentDecodingInstruction?.data?.type !== "decompress") - break; - this.currentDecodingInstruction.data.algorithm = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentCompSettings: - { - if (this.currentDecodingInstruction?.data?.type !== "decompress") - break; - this.currentDecodingInstruction.data.settings = readBytes(slice, size); - } - break; - case EBMLId.ContentEncryption: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.data = { - type: "decrypt" - }; - } - break; - } - slice.filePos = dataStartPos + size; - return true; - } - decodeBlockData(track, rawData) { - assert(track.decodingInstructions.length > 0); - let currentData = rawData; - for (const instruction of track.decodingInstructions) { - assert(instruction.data); - switch (instruction.data.type) { - case "decompress": - { - switch (instruction.data.algorithm) { - case ContentCompAlgo.HeaderStripping: - { - if (instruction.data.settings && instruction.data.settings.length > 0) { - const prefix = instruction.data.settings; - const newData = new Uint8Array(prefix.length + currentData.length); - newData.set(prefix, 0); - newData.set(currentData, prefix.length); - currentData = newData; - } - } - break; - } - } - break; - } - } - return currentData; - } - processTagValue(name, value) { - var _a; - if (!this.currentSegment?.metadataTags) - return; - const metadataTags = this.currentSegment.metadataTags; - metadataTags.raw ?? (metadataTags.raw = {}); - (_a = metadataTags.raw)[name] ?? (_a[name] = value); - if (typeof value === "string") { - switch (name.toLowerCase()) { - case "title": - { - metadataTags.title ?? (metadataTags.title = value); - } - break; - case "description": - { - metadataTags.description ?? (metadataTags.description = value); - } - break; - case "artist": - { - metadataTags.artist ?? (metadataTags.artist = value); - } - break; - case "album": - { - metadataTags.album ?? (metadataTags.album = value); - } - break; - case "album_artist": - { - metadataTags.albumArtist ?? (metadataTags.albumArtist = value); - } - break; - case "genre": - { - metadataTags.genre ?? (metadataTags.genre = value); - } - break; - case "comment": - { - metadataTags.comment ?? (metadataTags.comment = value); - } - break; - case "lyrics": - { - metadataTags.lyrics ?? (metadataTags.lyrics = value); - } - break; - case "date": - { - const date = new Date(value); - if (!Number.isNaN(date.getTime())) { - metadataTags.date ?? (metadataTags.date = date); - } - } - break; - case "track_number": - case "part_number": - { - const parts = value.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - metadataTags.trackNumber ?? (metadataTags.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - metadataTags.tracksTotal ?? (metadataTags.tracksTotal = tracksTotal); - } - } - break; - case "disc_number": - case "disc": - { - const discParts = value.split("/"); - const discNum = Number.parseInt(discParts[0], 10); - const discsTotal = discParts[1] && Number.parseInt(discParts[1], 10); - if (Number.isInteger(discNum) && discNum > 0) { - metadataTags.discNumber ?? (metadataTags.discNumber = discNum); - } - if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) { - metadataTags.discsTotal ?? (metadataTags.discsTotal = discsTotal); - } - } - break; - } - } - } - } - class MatroskaTrackBacking { - constructor(internalTrack) { - this.internalTrack = internalTrack; - this.packetToClusterLocation = /* @__PURE__ */ new WeakMap(); - } - getId() { - return this.internalTrack.id; - } - getCodec() { - throw new Error("Not implemented on base class."); - } - getInternalCodecId() { - return this.internalTrack.codecId; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return this.internalTrack.name; - } - getLanguageCode() { - return this.internalTrack.languageCode; - } - async getFirstTimestamp() { - const firstPacket = await this.getFirstPacket({ metadataOnly: true }); - return firstPacket?.timestamp ?? 0; - } - getTimeResolution() { - return this.internalTrack.segment.timestampFactor; - } - getDisposition() { - return this.internalTrack.disposition; - } - async getFirstPacket(options) { - return this.performClusterLookup( - null, - (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData) { - return { - blockIndex: 0, - correctBlockFound: true - }; - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - intoTimescale(timestamp) { - return roundIfAlmostInteger(timestamp * this.internalTrack.segment.timestampFactor); - } - async getPacket(timestamp, options) { - const timestampInTimescale = this.intoTimescale(timestamp); - return this.performClusterLookup(null, (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (!trackData) { - return { blockIndex: -1, correctBlockFound: false }; - } - const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.timestamp); - const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; - const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { blockIndex, correctBlockFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextPacket(packet, options) { - const locationInCluster = this.packetToClusterLocation.get(packet); - if (locationInCluster === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performClusterLookup( - locationInCluster.cluster, - (cluster) => { - if (cluster === locationInCluster.cluster) { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (locationInCluster.blockIndex + 1 < trackData.blocks.length) { - return { - blockIndex: locationInCluster.blockIndex + 1, - correctBlockFound: true - }; - } - } else { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData) { - return { - blockIndex: 0, - correctBlockFound: true - }; - } - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - async getKeyPacket(timestamp, options) { - const timestampInTimescale = this.intoTimescale(timestamp); - return this.performClusterLookup(null, (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (!trackData) { - return { blockIndex: -1, correctBlockFound: false }; - } - const index = findLastIndex(trackData.presentationTimestamps, (x) => { - const block = trackData.blocks[x.blockIndex]; - return block.isKeyFrame && x.timestamp <= timestampInTimescale; - }); - const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; - const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { blockIndex, correctBlockFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextKeyPacket(packet, options) { - const locationInCluster = this.packetToClusterLocation.get(packet); - if (locationInCluster === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performClusterLookup( - locationInCluster.cluster, - (cluster) => { - if (cluster === locationInCluster.cluster) { - const trackData = cluster.trackData.get(this.internalTrack.id); - const nextKeyFrameIndex = trackData.blocks.findIndex((x, i) => x.isKeyFrame && i > locationInCluster.blockIndex); - if (nextKeyFrameIndex !== -1) { - return { - blockIndex: nextKeyFrameIndex, - correctBlockFound: true - }; - } - } else { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData && trackData.firstKeyFrameTimestamp !== null) { - const keyFrameIndex = trackData.blocks.findIndex((x) => x.isKeyFrame); - assert(keyFrameIndex !== -1); - return { - blockIndex: keyFrameIndex, - correctBlockFound: true - }; - } - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - async fetchPacketInCluster(cluster, blockIndex, options) { - if (blockIndex === -1) { + if (start < 0) { return null; } - const trackData = cluster.trackData.get(this.internalTrack.id); - const block = trackData.blocks[blockIndex]; - assert(block); - if (!block.decoded) { - block.data = this.internalTrack.demuxer.decodeBlockData(this.internalTrack, block.data); - block.decoded = true; - } - const data = options.metadataOnly ? PLACEHOLDER_DATA : block.data; - const timestamp = block.timestamp / this.internalTrack.segment.timestampFactor; - const duration = block.duration / this.internalTrack.segment.timestampFactor; - const sideData = {}; - if (block.mainAdditional && this.internalTrack.info?.type === "video" && this.internalTrack.info.alphaMode) { - sideData.alpha = options.metadataOnly ? PLACEHOLDER_DATA : block.mainAdditional; - sideData.alphaByteLength = block.mainAdditional.byteLength; - } - const packet = new EncodedPacket(data, block.isKeyFrame ? "key" : "delta", timestamp, duration, cluster.dataStartPos + blockIndex, block.data.byteLength, sideData); - this.packetToClusterLocation.set(packet, { cluster, blockIndex }); - return packet; - } - /** Looks for a packet in the clusters while trying to load as few clusters as possible to retrieve it. */ - async performClusterLookup(startCluster, getMatchInCluster, searchTimestamp, latestTimestamp, options) { - const { demuxer, segment } = this.internalTrack; - let currentCluster = null; - let bestCluster = null; - let bestBlockIndex = -1; - if (startCluster) { - const { blockIndex, correctBlockFound } = getMatchInCluster(startCluster); - if (correctBlockFound) { - return this.fetchPacketInCluster(startCluster, blockIndex, options); - } - if (blockIndex !== -1) { - bestCluster = startCluster; - bestBlockIndex = blockIndex; - } - } - const cuePointIndex = binarySearchLessOrEqual(this.internalTrack.cuePoints, searchTimestamp, (x) => x.time); - const cuePoint = cuePointIndex !== -1 ? this.internalTrack.cuePoints[cuePointIndex] : null; - const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.clusterPositionCache, searchTimestamp, (x) => x.startTimestamp); - const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.clusterPositionCache[positionCacheIndex] : null; - const lookupEntryPosition = Math.max(cuePoint?.clusterPosition ?? 0, positionCacheEntry?.elementStartPos ?? 0) || null; - let currentPos; - if (!startCluster) { - currentPos = lookupEntryPosition ?? segment.clusterSeekStartPos; + if (this.fileSizeNonStrict !== null) { + return this.requestSlice(start, clamp$1(this.fileSizeNonStrict - start, minLength, maxLength)); } else { - if (lookupEntryPosition === null || startCluster.elementStartPos >= lookupEntryPosition) { - currentPos = startCluster.elementEndPos; - currentCluster = startCluster; + const promisedAttempt = this.requestSlice(start, maxLength); + const handleAttempt = (attempt) => { + if (attempt) { + return attempt; + } + assert(this.fileSizeNonStrict !== null); + return this.requestSlice(start, clamp$1(this.fileSizeNonStrict - start, minLength, maxLength)); + }; + if (promisedAttempt instanceof Promise) { + return promisedAttempt.then(handleAttempt); } else { - currentPos = lookupEntryPosition; + return handleAttempt(promisedAttempt); } } - while (segment.elementEndPos === null || currentPos <= segment.elementEndPos - MIN_HEADER_SIZE) { - if (currentCluster) { - const trackData = currentCluster.trackData.get(this.internalTrack.id); - if (trackData && trackData.startTimestamp > latestTimestamp) { - break; - } - } - let slice = demuxer.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementStartPos = currentPos; - const elementHeader = readElementHeader(slice); - if (!elementHeader || !LEVEL_1_EBML_IDS.includes(elementHeader.id) && elementHeader.id !== EBMLId.Void) { - const nextPos = await resync(demuxer.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(segment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); - if (nextPos) { - currentPos = nextPos; - continue; - } else { - break; - } - } - const id = elementHeader.id; - let size = elementHeader.size; - const dataStartPos = slice.filePos; - if (id === EBMLId.Cluster) { - currentCluster = await demuxer.readCluster(elementStartPos, segment); - size = currentCluster.elementEndPos - dataStartPos; - const { blockIndex, correctBlockFound } = getMatchInCluster(currentCluster); - if (correctBlockFound) { - return this.fetchPacketInCluster(currentCluster, blockIndex, options); - } - if (blockIndex !== -1) { - bestCluster = currentCluster; - bestBlockIndex = blockIndex; - } - } - if (size === void 0) { - assert(id !== EBMLId.Cluster); - const nextElementPos = await searchForNextElementId(demuxer.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); - size = nextElementPos.pos - dataStartPos; - } - const endPos = dataStartPos + size; - if (segment.elementEndPos === null) { - let slice2 = demuxer.reader.requestSliceRange(endPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const elementId = readElementId(slice2); - if (elementId === EBMLId.Segment) { - segment.elementEndPos = endPos; - break; - } - } - currentPos = endPos; + } + requestEntireFile() { + if (this.fileSizeNonStrict !== null) { + return this.requestSlice(0, this.fileSizeNonStrict); } - if (cuePoint && (!bestCluster || bestCluster.elementStartPos < cuePoint.clusterPosition)) { - const previousCuePoint = this.internalTrack.cuePoints[cuePointIndex - 1]; - assert(!previousCuePoint || previousCuePoint.time < cuePoint.time); - const newSearchTimestamp = previousCuePoint?.time ?? -Infinity; - return this.performClusterLookup(null, getMatchInCluster, newSearchTimestamp, latestTimestamp, options); - } - if (bestCluster) { - return this.fetchPacketInCluster(bestCluster, bestBlockIndex, options); - } - return null; + const CHUNK_SIZE = 1024; + return (async () => { + const chunks = []; + let currentSize = 0; + while (true) { + if (chunks.length === 1 && this.fileSizeNonStrict !== null) { + return this.requestSlice(0, this.fileSizeNonStrict); + } + const startOffset = chunks.length * CHUNK_SIZE; + let slice = this.requestSliceRange(startOffset, 0, CHUNK_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + break; + } + chunks.push(readBytes(slice, slice.length)); + currentSize += slice.length; + } + const joined = new Uint8Array(currentSize); + let offset = 0; + for (const chunk of chunks) { + joined.set(chunk, offset); + offset += chunk.length; + } + return new FileSlice(joined, toDataView(joined), 0, 0, currentSize); + })(); } } - class MatroskaVideoTrackBacking extends MatroskaTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfigPromise = null; - this.internalTrack = internalTrack; + class FileSlice { + constructor(bytes, view, offset, start, end) { + this.bytes = bytes; + this.view = view; + this.offset = offset; + this.start = start; + this.end = end; + this.bufferPos = start - offset; } - getCodec() { - return this.internalTrack.info.codec; + static tempFromBytes(bytes) { + return new FileSlice(bytes, toDataView(bytes), 0, 0, bytes.length); } - getCodedWidth() { - return this.internalTrack.info.width; + get length() { + return this.end - this.start; } - getCodedHeight() { - return this.internalTrack.info.height; + get filePos() { + return this.offset + this.bufferPos; } - getRotation() { - return this.internalTrack.info.rotation; + set filePos(value) { + this.bufferPos = value - this.offset; } - async getColorSpace() { - return { - primaries: this.internalTrack.info.colorSpace?.primaries, - transfer: this.internalTrack.info.colorSpace?.transfer, - matrix: this.internalTrack.info.colorSpace?.matrix, - fullRange: this.internalTrack.info.colorSpace?.fullRange - }; + /** The number of bytes left from the current pos to the end of the slice. */ + get remainingLength() { + return Math.max(this.end - this.filePos, 0); } - async canBeTransparent() { - return this.internalTrack.info.alphaMode; + skip(byteCount) { + this.bufferPos += byteCount; } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; + /** Creates a new subslice of this slice whose byte range must be contained within this slice. */ + slice(filePos, length = this.end - filePos) { + if (filePos < this.start || filePos + length > this.end) { + throw new RangeError("Slicing outside of original slice."); } - return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { - let firstPacket = null; - const needsPacketForAdditionalInfo = this.internalTrack.info.codec === "vp9" || this.internalTrack.info.codec === "av1" || this.internalTrack.info.codec === "avc" && !this.internalTrack.info.codecDescription || this.internalTrack.info.codec === "hevc" && !this.internalTrack.info.codecDescription; - if (needsPacketForAdditionalInfo) { - firstPacket = await this.getFirstPacket({}); - } - return { - codec: extractVideoCodecString({ - width: this.internalTrack.info.width, - height: this.internalTrack.info.height, - codec: this.internalTrack.info.codec, - codecDescription: this.internalTrack.info.codecDescription, - colorSpace: this.internalTrack.info.colorSpace, - avcType: 1, - // We don't know better (or do we?) so just assume 'avc1' - avcCodecInfo: this.internalTrack.info.codec === "avc" && firstPacket ? extractAvcDecoderConfigurationRecord(firstPacket.data) : null, - hevcCodecInfo: this.internalTrack.info.codec === "hevc" && firstPacket ? extractHevcDecoderConfigurationRecord(firstPacket.data) : null, - vp9CodecInfo: this.internalTrack.info.codec === "vp9" && firstPacket ? extractVp9CodecInfoFromPacket(firstPacket.data) : null, - av1CodecInfo: this.internalTrack.info.codec === "av1" && firstPacket ? extractAv1CodecInfoFromPacket(firstPacket.data) : null - }), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? void 0, - colorSpace: this.internalTrack.info.colorSpace ?? void 0 - }; - })()); + return new FileSlice(this.bytes, this.view, this.offset, filePos, filePos + length); } } - class MatroskaAudioTrackBacking extends MatroskaTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfig = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getNumberOfChannels() { - return this.internalTrack.info.numberOfChannels; - } - getSampleRate() { - return this.internalTrack.info.sampleRate; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfig ?? (this.decoderConfig = { - codec: extractAudioCodecString({ - codec: this.internalTrack.info.codec, - codecDescription: this.internalTrack.info.codecDescription, - aacCodecInfo: this.internalTrack.info.aacCodecInfo - }), - numberOfChannels: this.internalTrack.info.numberOfChannels, - sampleRate: this.internalTrack.info.sampleRate, - description: this.internalTrack.info.codecDescription ?? void 0 - }); - } - } - const FRAME_HEADER_SIZE = 4; - const SAMPLING_RATES = [44100, 48e3, 32e3]; - const KILOBIT_RATES = [ - // lowSamplingFrequency === 0 - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - // layer = 0 - -1, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224, - 256, - 320, - -1, - // layer 1 - -1, - 32, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224, - 256, - 320, - 384, - -1, - // layer = 2 - -1, - 32, - 64, - 96, - 128, - 160, - 192, - 224, - 256, - 288, - 320, - 352, - 384, - 416, - 448, - -1, - // layer = 3 - // lowSamplingFrequency === 1 - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - // layer = 0 - -1, - 8, - 16, - 24, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - -1, - // layer = 1 - -1, - 8, - 16, - 24, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - -1, - // layer = 2 - -1, - 32, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - 176, - 192, - 224, - 256, - -1 - // layer = 3 - ]; - const XING = 1483304551; - const INFO = 1231971951; - const computeMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate, padding) => { - if (layer === 0) { - return 0; - } else if (layer === 1) { - return Math.floor(144 * bitrate / (sampleRate << lowSamplingFrequency)) + padding; - } else if (layer === 2) { - return Math.floor(144 * bitrate / sampleRate) + padding; - } else { - return (Math.floor(12 * bitrate / sampleRate) + padding) * 4; + const checkIsInRange = (slice, bytesToRead) => { + if (slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) { + throw new RangeError(`Tried reading [${slice.filePos}, ${slice.filePos + bytesToRead}), but slice is [${slice.start}, ${slice.end}). This is likely an internal error, please report it alongside the file that caused it.`); } }; - const getXingOffset = (mpegVersionId, channel) => { - return mpegVersionId === 3 ? channel === 3 ? 21 : 36 : channel === 3 ? 13 : 21; + const readBytes = (slice, length) => { + checkIsInRange(slice, length); + const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length); + slice.bufferPos += length; + return bytes; }; - const readFrameHeader$1 = (word, remainingBytes) => { - const firstByte = word >>> 24; - const secondByte = word >>> 16 & 255; - const thirdByte = word >>> 8 & 255; - const fourthByte = word & 255; - if (firstByte !== 255 && secondByte !== 255 && thirdByte !== 255 && fourthByte !== 255) { - return { - header: null, - bytesAdvanced: 4 - }; - } - if (firstByte !== 255) { - return { header: null, bytesAdvanced: 1 }; - } - if ((secondByte & 224) !== 224) { - return { header: null, bytesAdvanced: 1 }; - } - let lowSamplingFrequency = 0; - let mpeg25 = 0; - if (secondByte & 1 << 4) { - lowSamplingFrequency = secondByte & 1 << 3 ? 0 : 1; - } else { - lowSamplingFrequency = 1; - mpeg25 = 1; - } - const mpegVersionId = secondByte >> 3 & 3; - const layer = secondByte >> 1 & 3; - const bitrateIndex = thirdByte >> 4 & 15; - const frequencyIndex = (thirdByte >> 2 & 3) % 3; - const padding = thirdByte >> 1 & 1; - const channel = fourthByte >> 6 & 3; - const modeExtension = fourthByte >> 4 & 3; - const copyright = fourthByte >> 3 & 1; - const original = fourthByte >> 2 & 1; - const emphasis = fourthByte & 3; - const kilobitRate = KILOBIT_RATES[lowSamplingFrequency * 16 * 4 + layer * 16 + bitrateIndex]; - if (kilobitRate === -1) { - return { header: null, bytesAdvanced: 1 }; - } - const bitrate = kilobitRate * 1e3; - const sampleRate = SAMPLING_RATES[frequencyIndex] >> lowSamplingFrequency + mpeg25; - const frameLength = computeMp3FrameSize(lowSamplingFrequency, layer, bitrate, sampleRate, padding); - if (remainingBytes !== null && remainingBytes < frameLength) { - return { header: null, bytesAdvanced: 1 }; - } - let audioSamplesInFrame; - if (mpegVersionId === 3) { - audioSamplesInFrame = layer === 3 ? 384 : 1152; - } else { - if (layer === 3) { - audioSamplesInFrame = 384; - } else if (layer === 2) { - audioSamplesInFrame = 1152; - } else { - audioSamplesInFrame = 576; - } - } - return { - header: { - totalSize: frameLength, - mpegVersionId, - layer, - bitrate, - frequencyIndex, - sampleRate, - channel, - modeExtension, - copyright, - original, - emphasis, - audioSamplesInFrame - }, - bytesAdvanced: 1 - }; + const readU8 = (slice) => { + checkIsInRange(slice, 1); + return slice.view.getUint8(slice.bufferPos++); }; - const decodeSynchsafe = (synchsafed) => { - let mask = 2130706432; - let unsynchsafed = 0; - while (mask !== 0) { - unsynchsafed >>= 1; - unsynchsafed |= synchsafed & mask; - mask >>= 8; + const readU16 = (slice, littleEndian) => { + checkIsInRange(slice, 2); + const value = slice.view.getUint16(slice.bufferPos, littleEndian); + slice.bufferPos += 2; + return value; + }; + const readU16Be = (slice) => { + checkIsInRange(slice, 2); + const value = slice.view.getUint16(slice.bufferPos, false); + slice.bufferPos += 2; + return value; + }; + const readU24Be = (slice) => { + checkIsInRange(slice, 3); + const value = getUint24(slice.view, slice.bufferPos, false); + slice.bufferPos += 3; + return value; + }; + const readI16Be = (slice) => { + checkIsInRange(slice, 2); + const value = slice.view.getInt16(slice.bufferPos, false); + slice.bufferPos += 2; + return value; + }; + const readU32 = (slice, littleEndian) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, littleEndian); + slice.bufferPos += 4; + return value; + }; + const readU32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; + }; + const readU32Le = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, true); + slice.bufferPos += 4; + return value; + }; + const readI32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getInt32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; + }; + const readI32Le = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getInt32(slice.bufferPos, true); + slice.bufferPos += 4; + return value; + }; + const readU64 = (slice, littleEndian) => { + let low; + let high; + if (littleEndian) { + low = readU32(slice, true); + high = readU32(slice, true); + } else { + high = readU32(slice, false); + low = readU32(slice, false); } - return unsynchsafed; + return high * 4294967296 + low; + }; + const readU64Be = (slice) => { + const high = readU32Be(slice); + const low = readU32Be(slice); + return high * 4294967296 + low; + }; + const readI64Be = (slice) => { + const high = readI32Be(slice); + const low = readU32Be(slice); + return high * 4294967296 + low; + }; + const readI64Le = (slice) => { + const low = readU32Le(slice); + const high = readI32Le(slice); + return high * 4294967296 + low; + }; + const readF32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getFloat32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; + }; + const readF64Be = (slice) => { + checkIsInRange(slice, 8); + const value = slice.view.getFloat64(slice.bufferPos, false); + slice.bufferPos += 8; + return value; + }; + const readAscii = (slice, length) => { + checkIsInRange(slice, length); + let str = ""; + for (let i = 0; i < length; i++) { + str += String.fromCharCode(slice.bytes[slice.bufferPos++]); + } + return str; + }; + const readAllLines = (slice, length, options) => { + const text = textDecoder.decode(readBytes(slice, length)); + const lines = text.split("\n").map((x) => x.trim()).filter((x) => x.length > 0 && !options?.ignore?.(x)); + return lines; }; var Id3V2HeaderFlags; (function(Id3V2HeaderFlags2) { @@ -10351,7 +20823,7 @@ var artplayerProxyMediabunny = (function() { return { majorVersion, revision, flags, size }; }; const parseId3V2Tag = (slice, header, tags) => { - var _a, _b, _c, _d; + var _a, _b, _c, _d, _e; if (![2, 3, 4].includes(header.majorVersion)) { console.warn(`Unsupported ID3v2 major version: ${header.majorVersion}`); return; @@ -10404,10 +20876,16 @@ var artplayerProxyMediabunny = (function() { reader.ununsynchronizeRegion(reader.pos, frameEndPos); } tags.raw ?? (tags.raw = {}); - if (frame.id[0] === "T") { - (_a = tags.raw)[_b = frame.id] ?? (_a[_b] = reader.readId3V2EncodingAndText(frameEndPos)); + if (frame.id === "TXXX") { + const txxx = (_a = tags.raw)["TXXX"] ?? (_a["TXXX"] = {}); + const encoding = reader.readId3V2TextEncoding(); + const description = reader.readId3V2Text(encoding, frameEndPos); + const value = reader.readId3V2Text(encoding, frameEndPos); + txxx[description] ?? (txxx[description] = value); + } else if (frame.id[0] === "T") { + (_b = tags.raw)[_c = frame.id] ?? (_b[_c] = reader.readId3V2EncodingAndText(frameEndPos)); } else { - (_c = tags.raw)[_d = frame.id] ?? (_c[_d] = reader.readBytes(frame.size)); + (_d = tags.raw)[_e = frame.id] ?? (_d[_e] = reader.readBytes(frame.size)); } reader.pos = frameStartPos; switch (frame.id) { @@ -10753,3706 +21231,6 @@ var artplayerProxyMediabunny = (function() { return this.readId3V2Text(encoding, until); } } - const readNextFrameHeader = async (reader, startPos, until) => { - let currentPos = startPos; - while (until === null || currentPos < until) { - let slice = reader.requestSlice(currentPos, FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const word = readU32Be(slice); - const result = readFrameHeader$1(word, reader.fileSize !== null ? reader.fileSize - currentPos : null); - if (result.header) { - return { header: result.header, startPos: currentPos }; - } - currentPos += result.bytesAdvanced; - } - return null; - }; - class Mp3Demuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.firstFrameHeader = null; - this.loadedSamples = []; - this.metadataTags = null; - this.tracks = []; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.lastLoadedPos = 0; - this.nextTimestampInSamples = 0; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - while (!this.firstFrameHeader && !this.lastSampleLoaded) { - await this.advanceReader(); - } - if (!this.firstFrameHeader) { - throw new Error("No valid MP3 frame found."); - } - this.tracks = [new InputAudioTrack(this.input, new Mp3AudioTrackBacking(this))]; - })()); - } - async advanceReader() { - if (this.lastLoadedPos === 0) { - while (true) { - let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) { - this.lastSampleLoaded = true; - return; - } - const id3V2Header = readId3V2Header(slice2); - if (!id3V2Header) { - break; - } - this.lastLoadedPos = slice2.filePos + id3V2Header.size; - } - } - const result = await readNextFrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize); - if (!result) { - this.lastSampleLoaded = true; - return; - } - const header = result.header; - this.lastLoadedPos = result.startPos + header.totalSize - 1; - const xingOffset = getXingOffset(header.mpegVersionId, header.channel); - let slice = this.reader.requestSlice(result.startPos + xingOffset, 4); - if (slice instanceof Promise) - slice = await slice; - if (slice) { - const word = readU32Be(slice); - const isXing = word === XING || word === INFO; - if (isXing) { - return; - } - } - if (!this.firstFrameHeader) { - this.firstFrameHeader = header; - } - if (header.sampleRate !== this.firstFrameHeader.sampleRate) { - console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${header.sampleRate} Hz. Might be a bug, so please report this file.`); - } - const sampleDuration = header.audioSamplesInFrame / this.firstFrameHeader.sampleRate; - const sample = { - timestamp: this.nextTimestampInSamples / this.firstFrameHeader.sampleRate, - duration: sampleDuration, - dataStart: result.startPos, - dataSize: header.totalSize - }; - this.loadedSamples.push(sample); - this.nextTimestampInSamples += header.audioSamplesInFrame; - return; - } - async getMimeType() { - return "audio/mpeg"; - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getMetadataTags() { - const release = await this.readingMutex.acquire(); - try { - await this.readMetadata(); - if (this.metadataTags) { - return this.metadataTags; - } - this.metadataTags = {}; - let currentPos = 0; - let id3V2HeaderFound = false; - while (true) { - let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) - break; - const id3V2Header = readId3V2Header(headerSlice); - if (!id3V2Header) { - break; - } - id3V2HeaderFound = true; - let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); - if (contentSlice instanceof Promise) - contentSlice = await contentSlice; - if (!contentSlice) - break; - parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); - currentPos = headerSlice.filePos + id3V2Header.size; - } - if (!id3V2HeaderFound && this.reader.fileSize !== null && this.reader.fileSize >= ID3_V1_TAG_SIZE) { - let slice = this.reader.requestSlice(this.reader.fileSize - ID3_V1_TAG_SIZE, ID3_V1_TAG_SIZE); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const tag = readAscii(slice, 3); - if (tag === "TAG") { - parseId3V1Tag(slice, this.metadataTags); - } - } - return this.metadataTags; - } finally { - release(); - } - } - } - class Mp3AudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - async getFirstTimestamp() { - return 0; - } - getTimeResolution() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.sampleRate / this.demuxer.firstFrameHeader.audioSamplesInFrame; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getCodec() { - return "mp3"; - } - getInternalCodecId() { - return null; - } - getNumberOfChannels() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2; - } - getSampleRate() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getDecoderConfig() { - assert(this.demuxer.firstFrameHeader); - return { - codec: "mp3", - numberOfChannels: this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2, - sampleRate: this.demuxer.firstFrameHeader.sampleRate - }; - } - async getPacketAtIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.dataSize); - } - return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); - if (sampleIndex === -1) { - throw new Error("Packet was not created from this track."); - } - const nextIndex = sampleIndex + 1; - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - async getPacket(timestamp, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); - if (index === -1 && this.demuxer.loadedSamples.length > 0) { - return null; - } - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(index, options); - } - if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { - return this.getPacketAtIndex(index, options); - } - await this.demuxer.advanceReader(); - } - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } - } - const OGGS = 1399285583; - const OGG_CRC_POLYNOMIAL = 79764919; - const OGG_CRC_TABLE = new Uint32Array(256); - for (let n = 0; n < 256; n++) { - let crc = n << 24; - for (let k = 0; k < 8; k++) { - crc = crc & 2147483648 ? crc << 1 ^ OGG_CRC_POLYNOMIAL : crc << 1; - } - OGG_CRC_TABLE[n] = crc >>> 0 & 4294967295; - } - const computeOggPageCrc = (bytes) => { - const view = toDataView(bytes); - const originalChecksum = view.getUint32(22, true); - view.setUint32(22, 0, true); - let crc = 0; - for (let i = 0; i < bytes.length; i++) { - const byte = bytes[i]; - crc = (crc << 8 ^ OGG_CRC_TABLE[crc >>> 24 ^ byte]) >>> 0; - } - view.setUint32(22, originalChecksum, true); - return crc; - }; - const extractSampleMetadata = (data, codecInfo, vorbisLastBlocksize) => { - let durationInSamples = 0; - let currentBlocksize = null; - if (data.length > 0) { - if (codecInfo.codec === "vorbis") { - assert(codecInfo.vorbisInfo); - const vorbisModeCount = codecInfo.vorbisInfo.modeBlockflags.length; - const bitCount = ilog(vorbisModeCount - 1); - const modeMask = (1 << bitCount) - 1 << 1; - const modeNumber = (data[0] & modeMask) >> 1; - if (modeNumber >= codecInfo.vorbisInfo.modeBlockflags.length) { - throw new Error("Invalid mode number."); - } - let prevBlocksize = vorbisLastBlocksize; - const blockflag = codecInfo.vorbisInfo.modeBlockflags[modeNumber]; - currentBlocksize = codecInfo.vorbisInfo.blocksizes[blockflag]; - if (blockflag === 1) { - const prevMask = (modeMask | 1) + 1; - const flag = data[0] & prevMask ? 1 : 0; - prevBlocksize = codecInfo.vorbisInfo.blocksizes[flag]; - } - durationInSamples = prevBlocksize !== null ? prevBlocksize + currentBlocksize >> 2 : 0; - } else if (codecInfo.codec === "opus") { - const toc = parseOpusTocByte(data); - durationInSamples = toc.durationInSamples; - } - } - return { - durationInSamples, - vorbisBlockSize: currentBlocksize - }; - }; - const buildOggMimeType = (info) => { - let string = "audio/ogg"; - if (info.codecStrings) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; - } - return string; - }; - const MIN_PAGE_HEADER_SIZE = 27; - const MAX_PAGE_HEADER_SIZE = 27 + 255; - const MAX_PAGE_SIZE = MAX_PAGE_HEADER_SIZE + 255 * 255; - const readPageHeader = (slice) => { - const startPos = slice.filePos; - const capturePattern = readU32Le(slice); - if (capturePattern !== OGGS) { - return null; - } - slice.skip(1); - const headerType = readU8(slice); - const granulePosition = readI64Le(slice); - const serialNumber = readU32Le(slice); - const sequenceNumber = readU32Le(slice); - const checksum = readU32Le(slice); - const numberPageSegments = readU8(slice); - const lacingValues = new Uint8Array(numberPageSegments); - for (let i = 0; i < numberPageSegments; i++) { - lacingValues[i] = readU8(slice); - } - const headerSize = 27 + numberPageSegments; - const dataSize = lacingValues.reduce((a, b) => a + b, 0); - const totalSize = headerSize + dataSize; - return { - headerStartPos: startPos, - totalSize, - dataStartPos: startPos + headerSize, - dataSize, - headerType, - granulePosition, - serialNumber, - sequenceNumber, - checksum, - lacingValues - }; - }; - const findNextPageHeader = (slice, until) => { - while (slice.filePos < until - (4 - 1)) { - const word = readU32Le(slice); - const firstByte = word & 255; - const secondByte = word >>> 8 & 255; - const thirdByte = word >>> 16 & 255; - const fourthByte = word >>> 24 & 255; - const O = 79; - if (firstByte !== O && secondByte !== O && thirdByte !== O && fourthByte !== O) { - continue; - } - slice.skip(-4); - if (word === OGGS) { - return true; - } - slice.skip(1); - } - return false; - }; - class OggDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.bitstreams = []; - this.tracks = []; - this.metadataTags = {}; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const page = readPageHeader(slice); - if (!page) { - break; - } - const isBos = !!(page.headerType & 2); - if (!isBos) { - break; - } - this.bitstreams.push({ - serialNumber: page.serialNumber, - bosPage: page, - description: null, - numberOfChannels: -1, - sampleRate: -1, - codecInfo: { - codec: null, - vorbisInfo: null, - opusInfo: null - }, - lastMetadataPacket: null - }); - currentPos = page.headerStartPos + page.totalSize; - } - for (const bitstream of this.bitstreams) { - const firstPacket = await this.readPacket(bitstream.bosPage, 0); - if (!firstPacket) { - continue; - } - if ( - // Check for Vorbis - firstPacket.data.byteLength >= 7 && firstPacket.data[0] === 1 && firstPacket.data[1] === 118 && firstPacket.data[2] === 111 && firstPacket.data[3] === 114 && firstPacket.data[4] === 98 && firstPacket.data[5] === 105 && firstPacket.data[6] === 115 - ) { - await this.readVorbisMetadata(firstPacket, bitstream); - } else if ( - // Check for Opus - firstPacket.data.byteLength >= 8 && firstPacket.data[0] === 79 && firstPacket.data[1] === 112 && firstPacket.data[2] === 117 && firstPacket.data[3] === 115 && firstPacket.data[4] === 72 && firstPacket.data[5] === 101 && firstPacket.data[6] === 97 && firstPacket.data[7] === 100 - ) { - await this.readOpusMetadata(firstPacket, bitstream); - } - if (bitstream.codecInfo.codec !== null) { - this.tracks.push(new InputAudioTrack(this.input, new OggAudioTrackBacking(bitstream, this))); - } - } - })()); - } - async readVorbisMetadata(firstPacket, bitstream) { - let nextPacketPosition = await this.findNextPacketStart(firstPacket); - if (!nextPacketPosition) { - return; - } - const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!secondPacket) { - return; - } - nextPacketPosition = await this.findNextPacketStart(secondPacket); - if (!nextPacketPosition) { - return; - } - const thirdPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!thirdPacket) { - return; - } - if (secondPacket.data[0] !== 3 || thirdPacket.data[0] !== 5) { - return; - } - const lacingValues = []; - const addBytesToSegmentTable = (bytes) => { - while (true) { - lacingValues.push(Math.min(255, bytes)); - if (bytes < 255) { - break; - } - bytes -= 255; - } - }; - addBytesToSegmentTable(firstPacket.data.length); - addBytesToSegmentTable(secondPacket.data.length); - const description = new Uint8Array(1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length + thirdPacket.data.length); - description[0] = 2; - description.set(lacingValues, 1); - description.set(firstPacket.data, 1 + lacingValues.length); - description.set(secondPacket.data, 1 + lacingValues.length + firstPacket.data.length); - description.set(thirdPacket.data, 1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length); - bitstream.codecInfo.codec = "vorbis"; - bitstream.description = description; - bitstream.lastMetadataPacket = thirdPacket; - const view = toDataView(firstPacket.data); - bitstream.numberOfChannels = view.getUint8(11); - bitstream.sampleRate = view.getUint32(12, true); - const blockSizeByte = view.getUint8(28); - bitstream.codecInfo.vorbisInfo = { - blocksizes: [ - 1 << (blockSizeByte & 15), - 1 << (blockSizeByte >> 4) - ], - modeBlockflags: parseModesFromVorbisSetupPacket(thirdPacket.data).modeBlockflags - }; - readVorbisComments(secondPacket.data.subarray(7), this.metadataTags); - } - async readOpusMetadata(firstPacket, bitstream) { - const nextPacketPosition = await this.findNextPacketStart(firstPacket); - if (!nextPacketPosition) { - return; - } - const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!secondPacket) { - return; - } - bitstream.codecInfo.codec = "opus"; - bitstream.description = firstPacket.data; - bitstream.lastMetadataPacket = secondPacket; - const header = parseOpusIdentificationHeader(firstPacket.data); - bitstream.numberOfChannels = header.outputChannelCount; - bitstream.sampleRate = OPUS_SAMPLE_RATE; - bitstream.codecInfo.opusInfo = { - preSkip: header.preSkip - }; - readVorbisComments(secondPacket.data.subarray(8), this.metadataTags); - } - async readPacket(startPage, startSegmentIndex) { - assert(startSegmentIndex < startPage.lacingValues.length); - let startDataOffset = 0; - for (let i = 0; i < startSegmentIndex; i++) { - startDataOffset += startPage.lacingValues[i]; - } - let currentPage = startPage; - let currentDataOffset = startDataOffset; - let currentSegmentIndex = startSegmentIndex; - const chunks = []; - outer: while (true) { - let pageSlice = this.reader.requestSlice(currentPage.dataStartPos, currentPage.dataSize); - if (pageSlice instanceof Promise) - pageSlice = await pageSlice; - assert(pageSlice); - const pageData = readBytes(pageSlice, currentPage.dataSize); - while (true) { - if (currentSegmentIndex === currentPage.lacingValues.length) { - chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); - break; - } - const lacingValue = currentPage.lacingValues[currentSegmentIndex]; - currentDataOffset += lacingValue; - if (lacingValue < 255) { - chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); - break outer; - } - currentSegmentIndex++; - } - let currentPos = currentPage.headerStartPos + currentPage.totalSize; - while (true) { - let headerSlice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) { - return null; - } - const nextPage = readPageHeader(headerSlice); - if (!nextPage) { - return null; - } - currentPage = nextPage; - if (currentPage.serialNumber === startPage.serialNumber) { - break; - } - currentPos = currentPage.headerStartPos + currentPage.totalSize; - } - startDataOffset = 0; - currentDataOffset = 0; - currentSegmentIndex = 0; - } - const totalPacketSize = chunks.reduce((sum, chunk) => sum + chunk.length, 0); - if (totalPacketSize === 0) { - return null; - } - const packetData = new Uint8Array(totalPacketSize); - let offset = 0; - for (let i = 0; i < chunks.length; i++) { - const chunk = chunks[i]; - packetData.set(chunk, offset); - offset += chunk.length; - } - return { - data: packetData, - endPage: currentPage, - endSegmentIndex: currentSegmentIndex - }; - } - async findNextPacketStart(lastPacket) { - if (lastPacket.endSegmentIndex < lastPacket.endPage.lacingValues.length - 1) { - return { startPage: lastPacket.endPage, startSegmentIndex: lastPacket.endSegmentIndex + 1 }; - } - const isEos = !!(lastPacket.endPage.headerType & 4); - if (isEos) { - return null; - } - let currentPos = lastPacket.endPage.headerStartPos + lastPacket.endPage.totalSize; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - const nextPage = readPageHeader(slice); - if (!nextPage) { - return null; - } - if (nextPage.serialNumber === lastPacket.endPage.serialNumber) { - return { startPage: nextPage, startSegmentIndex: 0 }; - } - currentPos = nextPage.headerStartPos + nextPage.totalSize; - } - } - async getMimeType() { - await this.readMetadata(); - const codecStrings = await Promise.all(this.tracks.map((x) => x.getCodecParameterString())); - return buildOggMimeType({ - codecStrings: codecStrings.filter(Boolean) - }); - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } - } - class OggAudioTrackBacking { - constructor(bitstream, demuxer) { - this.bitstream = bitstream; - this.demuxer = demuxer; - this.encodedPacketToMetadata = /* @__PURE__ */ new WeakMap(); - this.sequentialScanCache = []; - this.sequentialScanMutex = new AsyncMutex(); - this.internalSampleRate = bitstream.codecInfo.codec === "opus" ? OPUS_SAMPLE_RATE : bitstream.sampleRate; - } - getId() { - return this.bitstream.serialNumber; - } - getNumberOfChannels() { - return this.bitstream.numberOfChannels; - } - getSampleRate() { - return this.bitstream.sampleRate; - } - getTimeResolution() { - return this.bitstream.sampleRate; - } - getCodec() { - return this.bitstream.codecInfo.codec; - } - getInternalCodecId() { - return null; - } - async getDecoderConfig() { - assert(this.bitstream.codecInfo.codec); - return { - codec: this.bitstream.codecInfo.codec, - numberOfChannels: this.bitstream.numberOfChannels, - sampleRate: this.bitstream.sampleRate, - description: this.bitstream.description ?? void 0 - }; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - granulePositionToTimestampInSamples(granulePosition) { - if (this.bitstream.codecInfo.codec === "opus") { - assert(this.bitstream.codecInfo.opusInfo); - return granulePosition - this.bitstream.codecInfo.opusInfo.preSkip; - } - return granulePosition; - } - createEncodedPacketFromOggPacket(packet, additional, options) { - if (!packet) { - return null; - } - const { durationInSamples, vorbisBlockSize } = extractSampleMetadata(packet.data, this.bitstream.codecInfo, additional.vorbisLastBlocksize); - const encodedPacket = new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : packet.data, "key", Math.max(0, additional.timestampInSamples) / this.internalSampleRate, durationInSamples / this.internalSampleRate, packet.endPage.headerStartPos + packet.endSegmentIndex, packet.data.byteLength); - this.encodedPacketToMetadata.set(encodedPacket, { - packet, - timestampInSamples: additional.timestampInSamples, - durationInSamples, - vorbisLastBlockSize: additional.vorbisLastBlocksize, - vorbisBlockSize - }); - return encodedPacket; - } - async getFirstPacket(options) { - assert(this.bitstream.lastMetadataPacket); - const packetPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); - if (!packetPosition) { - return null; - } - let timestampInSamples = 0; - if (this.bitstream.codecInfo.codec === "opus") { - assert(this.bitstream.codecInfo.opusInfo); - timestampInSamples -= this.bitstream.codecInfo.opusInfo.preSkip; - } - const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); - return this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples, - vorbisLastBlocksize: null - }, options); - } - async getNextPacket(prevPacket, options) { - const prevMetadata = this.encodedPacketToMetadata.get(prevPacket); - if (!prevMetadata) { - throw new Error("Packet was not created from this track."); - } - const packetPosition = await this.demuxer.findNextPacketStart(prevMetadata.packet); - if (!packetPosition) { - return null; - } - const timestampInSamples = prevMetadata.timestampInSamples + prevMetadata.durationInSamples; - const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); - return this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples, - vorbisLastBlocksize: prevMetadata.vorbisBlockSize - }, options); - } - async getPacket(timestamp, options) { - if (this.demuxer.reader.fileSize === null) { - return this.getPacketSequential(timestamp, options); - } - const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); - if (timestampInSamples === 0) { - return this.getFirstPacket(options); - } - if (timestampInSamples < 0) { - return null; - } - assert(this.bitstream.lastMetadataPacket); - const startPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); - if (!startPosition) { - return null; - } - let lowPage = startPosition.startPage; - let high = this.demuxer.reader.fileSize; - const lowPages = [lowPage]; - outer: while (lowPage.headerStartPos + lowPage.totalSize < high) { - const low = lowPage.headerStartPos; - const mid = Math.floor((low + high) / 2); - let searchStartPos = mid; - while (true) { - const until = Math.min(searchStartPos + MAX_PAGE_SIZE, high - MIN_PAGE_HEADER_SIZE); - let searchSlice = this.demuxer.reader.requestSlice(searchStartPos, until - searchStartPos); - if (searchSlice instanceof Promise) - searchSlice = await searchSlice; - assert(searchSlice); - const found = findNextPageHeader(searchSlice, until); - if (!found) { - high = mid + MIN_PAGE_HEADER_SIZE; - continue outer; - } - let headerSlice = this.demuxer.reader.requestSliceRange(searchSlice.filePos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const page = readPageHeader(headerSlice); - assert(page); - let pageValid = false; - if (page.serialNumber === this.bitstream.serialNumber) { - pageValid = true; - } else { - let pageSlice = this.demuxer.reader.requestSlice(page.headerStartPos, page.totalSize); - if (pageSlice instanceof Promise) - pageSlice = await pageSlice; - assert(pageSlice); - const bytes = readBytes(pageSlice, page.totalSize); - const crc = computeOggPageCrc(bytes); - pageValid = crc === page.checksum; - } - if (!pageValid) { - searchStartPos = page.headerStartPos + 4; - continue; - } - if (pageValid && page.serialNumber !== this.bitstream.serialNumber) { - searchStartPos = page.headerStartPos + page.totalSize; - continue; - } - const isContinuationPage = page.granulePosition === -1; - if (isContinuationPage) { - searchStartPos = page.headerStartPos + page.totalSize; - continue; - } - if (this.granulePositionToTimestampInSamples(page.granulePosition) > timestampInSamples) { - high = page.headerStartPos; - } else { - lowPage = page; - lowPages.push(page); - } - continue outer; - } - } - let lowerPage = startPosition.startPage; - for (const otherLowPage of lowPages) { - if (otherLowPage.granulePosition === lowPage.granulePosition) { - break; - } - if (!lowerPage || otherLowPage.headerStartPos > lowerPage.headerStartPos) { - lowerPage = otherLowPage; - } - } - let currentPage = lowerPage; - const previousPages = [currentPage]; - while (true) { - if (currentPage.serialNumber === this.bitstream.serialNumber && currentPage.granulePosition === lowPage.granulePosition) { - break; - } - const nextPos = currentPage.headerStartPos + currentPage.totalSize; - let slice = this.demuxer.reader.requestSliceRange(nextPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const nextPage = readPageHeader(slice); - assert(nextPage); - currentPage = nextPage; - if (currentPage.serialNumber === this.bitstream.serialNumber) { - previousPages.push(currentPage); - } - } - assert(currentPage.granulePosition !== -1); - let currentSegmentIndex = null; - let currentTimestampInSamples; - let currentTimestampIsCorrect; - let endPage = currentPage; - let endSegmentIndex = 0; - if (currentPage.headerStartPos === startPosition.startPage.headerStartPos) { - currentTimestampInSamples = this.granulePositionToTimestampInSamples(0); - currentTimestampIsCorrect = true; - currentSegmentIndex = 0; - } else { - currentTimestampInSamples = 0; - currentTimestampIsCorrect = false; - for (let i = currentPage.lacingValues.length - 1; i >= 0; i--) { - const value = currentPage.lacingValues[i]; - if (value < 255) { - currentSegmentIndex = i + 1; - break; - } - } - if (currentSegmentIndex === null) { - throw new Error("Invalid page with granule position: no packets end on this page."); - } - endSegmentIndex = currentSegmentIndex - 1; - const pseudopacket = { - data: PLACEHOLDER_DATA, - endPage, - endSegmentIndex - }; - const nextPosition = await this.demuxer.findNextPacketStart(pseudopacket); - if (nextPosition) { - const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); - assert(endPosition); - const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); - if (startPosition2) { - currentPage = startPosition2.page; - currentSegmentIndex = startPosition2.segmentIndex; - } - } else { - while (true) { - const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); - if (!endPosition) { - break; - } - const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); - if (!startPosition2) { - break; - } - currentPage = startPosition2.page; - currentSegmentIndex = startPosition2.segmentIndex; - if (endPosition.page.headerStartPos !== endPage.headerStartPos) { - endPage = endPosition.page; - endSegmentIndex = endPosition.segmentIndex; - break; - } - } - } - } - let lastEncodedPacket = null; - let lastEncodedPacketMetadata = null; - while (currentPage !== null) { - assert(currentSegmentIndex !== null); - const packet = await this.demuxer.readPacket(currentPage, currentSegmentIndex); - if (!packet) { - break; - } - const skipPacket = currentPage.headerStartPos === startPosition.startPage.headerStartPos && currentSegmentIndex < startPosition.startSegmentIndex; - if (!skipPacket) { - let encodedPacket = this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples: currentTimestampInSamples, - vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null - }, options); - assert(encodedPacket); - let encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); - assert(encodedPacketMetadata); - if (!currentTimestampIsCorrect && packet.endPage.headerStartPos === endPage.headerStartPos && packet.endSegmentIndex === endSegmentIndex) { - currentTimestampInSamples = this.granulePositionToTimestampInSamples(currentPage.granulePosition); - currentTimestampIsCorrect = true; - encodedPacket = this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples: currentTimestampInSamples - encodedPacketMetadata.durationInSamples, - vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null - }, options); - assert(encodedPacket); - encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); - assert(encodedPacketMetadata); - } else { - currentTimestampInSamples += encodedPacketMetadata.durationInSamples; - } - lastEncodedPacket = encodedPacket; - lastEncodedPacketMetadata = encodedPacketMetadata; - if (currentTimestampIsCorrect && // Next timestamp will be too late - (Math.max(currentTimestampInSamples, 0) > timestampInSamples || Math.max(encodedPacketMetadata.timestampInSamples, 0) === timestampInSamples)) { - break; - } - } - const nextPosition = await this.demuxer.findNextPacketStart(packet); - if (!nextPosition) { - break; - } - currentPage = nextPosition.startPage; - currentSegmentIndex = nextPosition.startSegmentIndex; - } - return lastEncodedPacket; - } - // A slower but simpler and sequential algorithm for finding a packet in a file - async getPacketSequential(timestamp, options) { - const release = await this.sequentialScanMutex.acquire(); - try { - const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); - timestamp = timestampInSamples / this.internalSampleRate; - const index = binarySearchLessOrEqual(this.sequentialScanCache, timestampInSamples, (x) => x.timestampInSamples); - let currentPacket; - if (index !== -1) { - const cacheEntry = this.sequentialScanCache[index]; - currentPacket = this.createEncodedPacketFromOggPacket(cacheEntry.packet, { - timestampInSamples: cacheEntry.timestampInSamples, - vorbisLastBlocksize: cacheEntry.vorbisLastBlockSize - }, options); - } else { - currentPacket = await this.getFirstPacket(options); - } - let i = 0; - while (currentPacket && currentPacket.timestamp < timestamp) { - const nextPacket = await this.getNextPacket(currentPacket, options); - if (!nextPacket || nextPacket.timestamp > timestamp) { - break; - } - currentPacket = nextPacket; - i++; - if (i === 100) { - i = 0; - const metadata = this.encodedPacketToMetadata.get(currentPacket); - assert(metadata); - if (this.sequentialScanCache.length > 0) { - assert(last(this.sequentialScanCache).timestampInSamples <= metadata.timestampInSamples); - } - this.sequentialScanCache.push(metadata); - } - } - return currentPacket; - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } - } - const findPacketStartPosition = (pageList, endPage, endSegmentIndex) => { - let page = endPage; - let segmentIndex = endSegmentIndex; - outer: while (true) { - segmentIndex--; - for (segmentIndex; segmentIndex >= 0; segmentIndex--) { - const lacingValue = page.lacingValues[segmentIndex]; - if (lacingValue < 255) { - segmentIndex++; - break outer; - } - } - assert(segmentIndex === -1); - const pageStartsWithFreshPacket = !(page.headerType & 1); - if (pageStartsWithFreshPacket) { - segmentIndex = 0; - break; - } - const previousPage = findLast(pageList, (x) => x.headerStartPos < page.headerStartPos); - if (!previousPage) { - return null; - } - page = previousPage; - segmentIndex = page.lacingValues.length; - } - assert(segmentIndex !== -1); - if (segmentIndex === page.lacingValues.length) { - const nextPage = pageList[pageList.indexOf(page) + 1]; - assert(nextPage); - page = nextPage; - segmentIndex = 0; - } - return { page, segmentIndex }; - }; - const findPreviousPacketEndPosition = (pageList, startPage, startSegmentIndex) => { - if (startSegmentIndex > 0) { - return { page: startPage, segmentIndex: startSegmentIndex - 1 }; - } - const previousPage = findLast(pageList, (x) => x.headerStartPos < startPage.headerStartPos); - if (!previousPage) { - return null; - } - return { page: previousPage, segmentIndex: previousPage.lacingValues.length - 1 }; - }; - var WaveFormat; - (function(WaveFormat2) { - WaveFormat2[WaveFormat2["PCM"] = 1] = "PCM"; - WaveFormat2[WaveFormat2["IEEE_FLOAT"] = 3] = "IEEE_FLOAT"; - WaveFormat2[WaveFormat2["ALAW"] = 6] = "ALAW"; - WaveFormat2[WaveFormat2["MULAW"] = 7] = "MULAW"; - WaveFormat2[WaveFormat2["EXTENSIBLE"] = 65534] = "EXTENSIBLE"; - })(WaveFormat || (WaveFormat = {})); - class WaveDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.dataStart = -1; - this.dataSize = -1; - this.audioInfo = null; - this.tracks = []; - this.lastKnownPacketIndex = 0; - this.metadataTags = {}; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let slice = this.reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const riffType = readAscii(slice, 4); - const littleEndian = riffType !== "RIFX"; - const isRf64 = riffType === "RF64"; - const outerChunkSize = readU32(slice, littleEndian); - let totalFileSize = isRf64 ? this.reader.fileSize : Math.min(outerChunkSize + 8, this.reader.fileSize ?? Infinity); - const format = readAscii(slice, 4); - if (format !== "WAVE") { - throw new Error("Invalid WAVE file - wrong format"); - } - let chunksRead = 0; - let dataChunkSize = null; - let currentPos = slice.filePos; - while (totalFileSize === null || currentPos < totalFileSize) { - let slice2 = this.reader.requestSlice(currentPos, 8); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const chunkId = readAscii(slice2, 4); - const chunkSize = readU32(slice2, littleEndian); - const startPos = slice2.filePos; - if (isRf64 && chunksRead === 0 && chunkId !== "ds64") { - throw new Error('Invalid RF64 file: First chunk must be "ds64".'); - } - if (chunkId === "fmt ") { - await this.parseFmtChunk(startPos, chunkSize, littleEndian); - } else if (chunkId === "data") { - dataChunkSize ?? (dataChunkSize = chunkSize); - this.dataStart = slice2.filePos; - this.dataSize = Math.min(dataChunkSize, (totalFileSize ?? Infinity) - this.dataStart); - if (this.reader.fileSize === null) { - break; - } - } else if (chunkId === "ds64") { - let ds64Slice = this.reader.requestSlice(startPos, chunkSize); - if (ds64Slice instanceof Promise) - ds64Slice = await ds64Slice; - if (!ds64Slice) - break; - const riffChunkSize = readU64(ds64Slice, littleEndian); - dataChunkSize = readU64(ds64Slice, littleEndian); - totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity); - } else if (chunkId === "LIST") { - await this.parseListChunk(startPos, chunkSize, littleEndian); - } else if (chunkId === "ID3 " || chunkId === "id3 ") { - await this.parseId3Chunk(startPos, chunkSize); - } - currentPos = startPos + chunkSize + (chunkSize & 1); - chunksRead++; - } - if (!this.audioInfo) { - throw new Error('Invalid WAVE file - missing "fmt " chunk'); - } - if (this.dataStart === -1) { - throw new Error('Invalid WAVE file - missing "data" chunk'); - } - const blockSize = this.audioInfo.blockSizeInBytes; - this.dataSize = Math.floor(this.dataSize / blockSize) * blockSize; - this.tracks.push(new InputAudioTrack(this.input, new WaveAudioTrackBacking(this))); - })()); - } - async parseFmtChunk(startPos, size, littleEndian) { - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - let formatTag = readU16(slice, littleEndian); - const numChannels = readU16(slice, littleEndian); - const sampleRate = readU32(slice, littleEndian); - slice.skip(4); - const blockAlign = readU16(slice, littleEndian); - let bitsPerSample; - if (size === 14) { - bitsPerSample = 8; - } else { - bitsPerSample = readU16(slice, littleEndian); - } - if (size >= 18 && formatTag !== 357) { - const cbSize = readU16(slice, littleEndian); - const remainingSize = size - 18; - const extensionSize = Math.min(remainingSize, cbSize); - if (extensionSize >= 22 && formatTag === WaveFormat.EXTENSIBLE) { - slice.skip(2 + 4); - const subFormat = readBytes(slice, 16); - formatTag = subFormat[0] | subFormat[1] << 8; - } - } - if (formatTag === WaveFormat.MULAW || formatTag === WaveFormat.ALAW) { - bitsPerSample = 8; - } - this.audioInfo = { - format: formatTag, - numberOfChannels: numChannels, - sampleRate, - sampleSizeInBytes: Math.ceil(bitsPerSample / 8), - blockSizeInBytes: blockAlign - }; - } - async parseListChunk(startPos, size, littleEndian) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - const infoType = readAscii(slice, 4); - if (infoType !== "INFO" && infoType !== "INF0") { - return; - } - let currentPos = slice.filePos; - while (currentPos <= startPos + size - 8) { - slice.filePos = currentPos; - const chunkName = readAscii(slice, 4); - const chunkSize = readU32(slice, littleEndian); - const bytes = readBytes(slice, chunkSize); - let stringLength = 0; - for (let i = 0; i < bytes.length; i++) { - if (bytes[i] === 0) { - break; - } - stringLength++; - } - const value = String.fromCharCode(...bytes.subarray(0, stringLength)); - (_a = this.metadataTags).raw ?? (_a.raw = {}); - this.metadataTags.raw[chunkName] = value; - switch (chunkName) { - case "INAM": - case "TITL": - { - (_b = this.metadataTags).title ?? (_b.title = value); - } - break; - case "TIT3": - { - (_c = this.metadataTags).description ?? (_c.description = value); - } - break; - case "IART": - { - (_d = this.metadataTags).artist ?? (_d.artist = value); - } - break; - case "IPRD": - { - (_e = this.metadataTags).album ?? (_e.album = value); - } - break; - case "IPRT": - case "ITRK": - case "TRCK": - { - const parts = value.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - (_f = this.metadataTags).trackNumber ?? (_f.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - (_g = this.metadataTags).tracksTotal ?? (_g.tracksTotal = tracksTotal); - } - } - break; - case "ICRD": - case "IDIT": - { - const date = new Date(value); - if (!Number.isNaN(date.getTime())) { - (_h = this.metadataTags).date ?? (_h.date = date); - } - } - break; - case "YEAR": - { - const year = Number.parseInt(value, 10); - if (Number.isInteger(year) && year > 0) { - (_i = this.metadataTags).date ?? (_i.date = new Date(year, 0, 1)); - } - } - break; - case "IGNR": - case "GENR": - { - (_j = this.metadataTags).genre ?? (_j.genre = value); - } - break; - case "ICMT": - case "CMNT": - case "COMM": - { - (_k = this.metadataTags).comment ?? (_k.comment = value); - } - break; - } - currentPos += 8 + chunkSize + (chunkSize & 1); - } - } - async parseId3Chunk(startPos, size) { - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - const id3V2Header = readId3V2Header(slice); - if (id3V2Header) { - const contentSlice = slice.slice(startPos + 10, id3V2Header.size); - parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); - } - } - getCodec() { - assert(this.audioInfo); - if (this.audioInfo.format === WaveFormat.MULAW) { - return "ulaw"; - } - if (this.audioInfo.format === WaveFormat.ALAW) { - return "alaw"; - } - if (this.audioInfo.format === WaveFormat.PCM) { - if (this.audioInfo.sampleSizeInBytes === 1) { - return "pcm-u8"; - } else if (this.audioInfo.sampleSizeInBytes === 2) { - return "pcm-s16"; - } else if (this.audioInfo.sampleSizeInBytes === 3) { - return "pcm-s24"; - } else if (this.audioInfo.sampleSizeInBytes === 4) { - return "pcm-s32"; - } - } - if (this.audioInfo.format === WaveFormat.IEEE_FLOAT) { - if (this.audioInfo.sampleSizeInBytes === 4) { - return "pcm-f32"; - } - } - return null; - } - async getMimeType() { - return "audio/wav"; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } - } - const PACKET_SIZE_IN_FRAMES = 2048; - class WaveAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - getCodec() { - return this.demuxer.getCodec(); - } - getInternalCodecId() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.format; - } - async getDecoderConfig() { - const codec = this.demuxer.getCodec(); - if (!codec) { - return null; - } - assert(this.demuxer.audioInfo); - return { - codec, - numberOfChannels: this.demuxer.audioInfo.numberOfChannels, - sampleRate: this.demuxer.audioInfo.sampleRate - }; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getNumberOfChannels() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.numberOfChannels; - } - getSampleRate() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getTimeResolution() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async getPacketAtIndex(packetIndex, options) { - assert(this.demuxer.audioInfo); - const startOffset = packetIndex * PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes; - if (startOffset >= this.demuxer.dataSize) { - return null; - } - const sizeInBytes = Math.min(PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes, this.demuxer.dataSize - startOffset); - if (this.demuxer.reader.fileSize === null) { - let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, sizeInBytes); - } - const timestamp = packetIndex * PACKET_SIZE_IN_FRAMES / this.demuxer.audioInfo.sampleRate; - const duration = sizeInBytes / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; - this.demuxer.lastKnownPacketIndex = Math.max(packetIndex, timestamp); - return new EncodedPacket(data, "key", timestamp, duration, packetIndex, sizeInBytes); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getPacket(timestamp, options) { - assert(this.demuxer.audioInfo); - const packetIndex = Math.floor(Math.min(timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES, (this.demuxer.dataSize - 1) / (PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes))); - const packet = await this.getPacketAtIndex(packetIndex, options); - if (packet) { - return packet; - } - if (packetIndex === 0) { - return null; - } - assert(this.demuxer.reader.fileSize === null); - let currentPacket = await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex, options); - while (currentPacket) { - const nextPacket = await this.getNextPacket(currentPacket, options); - if (!nextPacket) { - break; - } - currentPacket = nextPacket; - } - return currentPacket; - } - getNextPacket(packet, options) { - assert(this.demuxer.audioInfo); - const packetIndex = Math.round(packet.timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES); - return this.getPacketAtIndex(packetIndex + 1, options); - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } - } - const MIN_FRAME_HEADER_SIZE = 7; - const MAX_FRAME_HEADER_SIZE = 9; - const readFrameHeader = (slice) => { - const startPos = slice.filePos; - const bytes = readBytes(slice, 9); - const bitstream = new Bitstream(bytes); - const syncword = bitstream.readBits(12); - if (syncword !== 4095) { - return null; - } - bitstream.skipBits(1); - const layer = bitstream.readBits(2); - if (layer !== 0) { - return null; - } - const protectionAbsence = bitstream.readBits(1); - const objectType = bitstream.readBits(2) + 1; - const samplingFrequencyIndex = bitstream.readBits(4); - if (samplingFrequencyIndex === 15) { - return null; - } - bitstream.skipBits(1); - const channelConfiguration = bitstream.readBits(3); - if (channelConfiguration === 0) { - throw new Error("ADTS frames with channel configuration 0 are not supported."); - } - bitstream.skipBits(1); - bitstream.skipBits(1); - bitstream.skipBits(1); - bitstream.skipBits(1); - const frameLength = bitstream.readBits(13); - bitstream.skipBits(11); - const numberOfAacFrames = bitstream.readBits(2) + 1; - if (numberOfAacFrames !== 1) { - throw new Error("ADTS frames with more than one AAC frame are not supported."); - } - let crcCheck = null; - if (protectionAbsence === 1) { - slice.filePos -= 2; - } else { - crcCheck = bitstream.readBits(16); - } - return { - objectType, - samplingFrequencyIndex, - channelConfiguration, - frameLength, - numberOfAacFrames, - crcCheck, - startPos - }; - }; - const SAMPLES_PER_AAC_FRAME = 1024; - class AdtsDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.firstFrameHeader = null; - this.loadedSamples = []; - this.tracks = []; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.lastLoadedPos = 0; - this.nextTimestampInSamples = 0; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - while (!this.firstFrameHeader && !this.lastSampleLoaded) { - await this.advanceReader(); - } - assert(this.firstFrameHeader); - this.tracks = [new InputAudioTrack(this.input, new AdtsAudioTrackBacking(this))]; - })()); - } - async advanceReader() { - let slice = this.reader.requestSliceRange(this.lastLoadedPos, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - this.lastSampleLoaded = true; - return; - } - const header = readFrameHeader(slice); - if (!header) { - this.lastSampleLoaded = true; - return; - } - if (this.reader.fileSize !== null && header.startPos + header.frameLength > this.reader.fileSize) { - this.lastSampleLoaded = true; - return; - } - if (!this.firstFrameHeader) { - this.firstFrameHeader = header; - } - const sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; - assert(sampleRate !== void 0); - const sampleDuration = SAMPLES_PER_AAC_FRAME / sampleRate; - const headerSize = header.crcCheck ? MAX_FRAME_HEADER_SIZE : MIN_FRAME_HEADER_SIZE; - const sample = { - timestamp: this.nextTimestampInSamples / sampleRate, - duration: sampleDuration, - dataStart: header.startPos + headerSize, - dataSize: header.frameLength - headerSize - }; - this.loadedSamples.push(sample); - this.nextTimestampInSamples += SAMPLES_PER_AAC_FRAME; - this.lastLoadedPos = header.startPos + header.frameLength; - } - async getMimeType() { - return "audio/aac"; - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getMetadataTags() { - return {}; - } - } - class AdtsAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - async getFirstTimestamp() { - return 0; - } - getTimeResolution() { - const sampleRate = this.getSampleRate(); - return sampleRate / SAMPLES_PER_AAC_FRAME; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getCodec() { - return "aac"; - } - getInternalCodecId() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.objectType; - } - getNumberOfChannels() { - assert(this.demuxer.firstFrameHeader); - const numberOfChannels = aacChannelMap[this.demuxer.firstFrameHeader.channelConfiguration]; - assert(numberOfChannels !== void 0); - return numberOfChannels; - } - getSampleRate() { - assert(this.demuxer.firstFrameHeader); - const sampleRate = aacFrequencyTable[this.demuxer.firstFrameHeader.samplingFrequencyIndex]; - assert(sampleRate !== void 0); - return sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getDecoderConfig() { - assert(this.demuxer.firstFrameHeader); - const bytes = new Uint8Array(3); - const bitstream = new Bitstream(bytes); - const { objectType, samplingFrequencyIndex, channelConfiguration } = this.demuxer.firstFrameHeader; - if (objectType > 31) { - bitstream.writeBits(5, 31); - bitstream.writeBits(6, objectType - 32); - } else { - bitstream.writeBits(5, objectType); - } - bitstream.writeBits(4, samplingFrequencyIndex); - bitstream.writeBits(4, channelConfiguration); - return { - codec: `mp4a.40.${this.demuxer.firstFrameHeader.objectType}`, - numberOfChannels: this.getNumberOfChannels(), - sampleRate: this.getSampleRate(), - description: bytes.subarray(0, Math.ceil((bitstream.pos - 1) / 8)) - }; - } - async getPacketAtIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.dataSize); - } - return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); - if (sampleIndex === -1) { - throw new Error("Packet was not created from this track."); - } - const nextIndex = sampleIndex + 1; - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - async getPacket(timestamp, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); - if (index === -1 && this.demuxer.loadedSamples.length > 0) { - return null; - } - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(index, options); - } - if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { - return this.getPacketAtIndex(index, options); - } - await this.demuxer.advanceReader(); - } - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } - } - const getBlockSizeOrUncommon = (bits) => { - if (bits === 0) { - return null; - } else if (bits === 1) { - return 192; - } else if (bits >= 2 && bits <= 5) { - return 144 * 2 ** bits; - } else if (bits === 6) { - return "uncommon-u8"; - } else if (bits === 7) { - return "uncommon-u16"; - } else if (bits >= 8 && bits <= 15) { - return 2 ** bits; - } else { - return null; - } - }; - const getSampleRateOrUncommon = (sampleRateBits, streamInfoSampleRate) => { - switch (sampleRateBits) { - case 0: - return streamInfoSampleRate; - case 1: - return 88200; - case 2: - return 176400; - case 3: - return 192e3; - case 4: - return 8e3; - case 5: - return 16e3; - case 6: - return 22050; - case 7: - return 24e3; - case 8: - return 32e3; - case 9: - return 44100; - case 10: - return 48e3; - case 11: - return 96e3; - case 12: - return "uncommon-u8"; - case 13: - return "uncommon-u16"; - case 14: - return "uncommon-u16-10"; - default: - return null; - } - }; - const readCodedNumber = (fileSlice) => { - let ones = 0; - const bitstream1 = new Bitstream(readBytes(fileSlice, 1)); - while (bitstream1.readBits(1) === 1) { - ones++; - } - if (ones === 0) { - return bitstream1.readBits(7); - } - const bitArray = []; - const extraBytes = ones - 1; - const bitstream2 = new Bitstream(readBytes(fileSlice, extraBytes)); - const firstByteBits = 8 - ones - 1; - for (let i = 0; i < firstByteBits; i++) { - bitArray.unshift(bitstream1.readBits(1)); - } - for (let i = 0; i < extraBytes; i++) { - for (let j = 0; j < 8; j++) { - const val = bitstream2.readBits(1); - if (j < 2) { - continue; - } - bitArray.unshift(val); - } - } - const encoded = bitArray.reduce((acc, bit, index) => { - return acc | bit << index; - }, 0); - return encoded; - }; - const readBlockSize = (slice, blockSizeBits) => { - if (blockSizeBits === "uncommon-u16") { - return readU16Be(slice) + 1; - } else if (blockSizeBits === "uncommon-u8") { - return readU8(slice) + 1; - } else if (typeof blockSizeBits === "number") { - return blockSizeBits; - } else { - assertNever(blockSizeBits); - assert(false); - } - }; - const readSampleRate = (slice, sampleRateOrUncommon) => { - if (sampleRateOrUncommon === "uncommon-u16") { - return readU16Be(slice); - } - if (sampleRateOrUncommon === "uncommon-u16-10") { - return readU16Be(slice) * 10; - } - if (sampleRateOrUncommon === "uncommon-u8") { - return readU8(slice); - } - if (typeof sampleRateOrUncommon === "number") { - return sampleRateOrUncommon; - } - return null; - }; - const calculateCrc8 = (data) => { - const polynomial = 7; - let crc = 0; - for (const byte of data) { - crc ^= byte; - for (let i = 0; i < 8; i++) { - if ((crc & 128) !== 0) { - crc = crc << 1 ^ polynomial; - } else { - crc <<= 1; - } - crc &= 255; - } - } - return crc; - }; - class FlacDemuxer extends Demuxer { - constructor(input) { - super(input); - this.loadedSamples = []; - this.metadataPromise = null; - this.track = null; - this.metadataTags = {}; - this.audioInfo = null; - this.lastLoadedPos = null; - this.blockingBit = null; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.reader = input._reader; - } - async computeDuration() { - await this.readMetadata(); - assert(this.track); - return this.track.computeDuration(); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } - async getTracks() { - await this.readMetadata(); - assert(this.track); - return [this.track]; - } - async getMimeType() { - return "audio/flac"; - } - async readMetadata() { - let currentPos = 4; - return this.metadataPromise ?? (this.metadataPromise = (async () => { - var _a; - while (this.reader.fileSize === null || currentPos < this.reader.fileSize) { - let sizeSlice = this.reader.requestSlice(currentPos, 4); - if (sizeSlice instanceof Promise) - sizeSlice = await sizeSlice; - currentPos += 4; - if (sizeSlice === null) { - throw new Error(`Metadata block at position ${currentPos} is too small! Corrupted file.`); - } - assert(sizeSlice); - const byte = readU8(sizeSlice); - const size = readU24Be(sizeSlice); - const isLastMetadata = (byte & 128) !== 0; - const metaBlockType = byte & 127; - switch (metaBlockType) { - case FlacBlockType.STREAMINFO: { - let streamInfoBlock = this.reader.requestSlice(currentPos, size); - if (streamInfoBlock instanceof Promise) - streamInfoBlock = await streamInfoBlock; - assert(streamInfoBlock); - if (streamInfoBlock === null) { - throw new Error(`StreamInfo block at position ${currentPos} is too small! Corrupted file.`); - } - const streamInfoBytes = readBytes(streamInfoBlock, 34); - const bitstream = new Bitstream(streamInfoBytes); - const minimumBlockSize = bitstream.readBits(16); - const maximumBlockSize = bitstream.readBits(16); - const minimumFrameSize = bitstream.readBits(24); - const maximumFrameSize = bitstream.readBits(24); - const sampleRate = bitstream.readBits(20); - const numberOfChannels = bitstream.readBits(3) + 1; - bitstream.readBits(5); - const totalSamples = bitstream.readBits(36); - bitstream.skipBits(16 * 8); - const description = new Uint8Array(42); - description.set(new Uint8Array([102, 76, 97, 67]), 0); - description.set(new Uint8Array([128, 0, 0, 34]), 4); - description.set(streamInfoBytes, 8); - this.audioInfo = { - numberOfChannels, - sampleRate, - totalSamples, - minimumBlockSize, - maximumBlockSize, - minimumFrameSize, - maximumFrameSize, - description - }; - this.track = new InputAudioTrack(this.input, new FlacAudioTrackBacking(this)); - break; - } - case FlacBlockType.VORBIS_COMMENT: { - let vorbisCommentBlock = this.reader.requestSlice(currentPos, size); - if (vorbisCommentBlock instanceof Promise) - vorbisCommentBlock = await vorbisCommentBlock; - assert(vorbisCommentBlock); - readVorbisComments(readBytes(vorbisCommentBlock, size), this.metadataTags); - break; - } - case FlacBlockType.PICTURE: { - let pictureBlock = this.reader.requestSlice(currentPos, size); - if (pictureBlock instanceof Promise) - pictureBlock = await pictureBlock; - assert(pictureBlock); - const pictureType = readU32Be(pictureBlock); - const mediaTypeLength = readU32Be(pictureBlock); - const mediaType = textDecoder.decode(readBytes(pictureBlock, mediaTypeLength)); - const descriptionLength = readU32Be(pictureBlock); - const description = textDecoder.decode(readBytes(pictureBlock, descriptionLength)); - pictureBlock.skip(4 + 4 + 4 + 4); - const dataLength = readU32Be(pictureBlock); - const data = readBytes(pictureBlock, dataLength); - (_a = this.metadataTags).images ?? (_a.images = []); - this.metadataTags.images.push({ - data, - mimeType: mediaType, - // https://www.rfc-editor.org/rfc/rfc9639.html#table13 - kind: pictureType === 3 ? "coverFront" : pictureType === 4 ? "coverBack" : "unknown", - description - }); - break; - } - } - currentPos += size; - if (isLastMetadata) { - this.lastLoadedPos = currentPos; - break; - } - } - })()); - } - async readNextFlacFrame({ startPos, isFirstPacket }) { - assert(this.audioInfo); - const minimumHeaderLength = 6; - const maximumHeaderSize = 16; - const maximumSliceLength = this.audioInfo.maximumFrameSize + maximumHeaderSize; - const slice = await this.reader.requestSliceRange(startPos, this.audioInfo.minimumFrameSize, maximumSliceLength); - if (!slice) { - return null; - } - const frameHeader = this.readFlacFrameHeader({ - slice, - isFirstPacket - }); - if (!frameHeader) { - return null; - } - slice.filePos = startPos + this.audioInfo.minimumFrameSize; - while (true) { - if (slice.filePos > slice.end - minimumHeaderLength) { - return { - num: frameHeader.num, - blockSize: frameHeader.blockSize, - sampleRate: frameHeader.sampleRate, - size: slice.end - startPos, - isLastFrame: true - }; - } - const nextByte = readU8(slice); - if (nextByte === 255) { - const positionBeforeReading = slice.filePos; - const byteAfterNextByte = readU8(slice); - const expected = this.blockingBit === 1 ? 249 : 248; - if (byteAfterNextByte !== expected) { - slice.filePos = positionBeforeReading; - continue; - } - slice.skip(-2); - const lengthIfNextFlacFrameHeaderIsLegit = slice.filePos - startPos; - const nextFrameHeader = this.readFlacFrameHeader({ - slice, - isFirstPacket: false - }); - if (!nextFrameHeader) { - slice.filePos = positionBeforeReading; - continue; - } - if (this.blockingBit === 0) { - if (nextFrameHeader.num - frameHeader.num !== 1) { - slice.filePos = positionBeforeReading; - continue; - } - } else { - if (nextFrameHeader.num - frameHeader.num !== frameHeader.blockSize) { - slice.filePos = positionBeforeReading; - continue; - } - } - return { - num: frameHeader.num, - blockSize: frameHeader.blockSize, - sampleRate: frameHeader.sampleRate, - size: lengthIfNextFlacFrameHeaderIsLegit, - isLastFrame: false - }; - } - } - } - readFlacFrameHeader({ slice, isFirstPacket }) { - const startOffset = slice.filePos; - const bytes = readBytes(slice, 4); - const bitstream = new Bitstream(bytes); - const bits = bitstream.readBits(15); - if (bits !== 32764) { - return null; - } - if (this.blockingBit === null) { - assert(isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - this.blockingBit = newBlockingBit; - } else if (this.blockingBit === 1) { - assert(!isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - if (newBlockingBit !== 1) { - return null; - } - } else if (this.blockingBit === 0) { - assert(!isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - if (newBlockingBit !== 0) { - return null; - } - } else { - throw new Error("Invalid blocking bit"); - } - const blockSizeOrUncommon = getBlockSizeOrUncommon(bitstream.readBits(4)); - if (!blockSizeOrUncommon) { - return null; - } - assert(this.audioInfo); - const sampleRateOrUncommon = getSampleRateOrUncommon(bitstream.readBits(4), this.audioInfo.sampleRate); - if (!sampleRateOrUncommon) { - return null; - } - bitstream.readBits(4); - bitstream.readBits(3); - const reservedZero = bitstream.readBits(1); - if (reservedZero !== 0) { - return null; - } - const num = readCodedNumber(slice); - const blockSize = readBlockSize(slice, blockSizeOrUncommon); - const sampleRate = readSampleRate(slice, sampleRateOrUncommon); - if (sampleRate === null) { - return null; - } - if (sampleRate !== this.audioInfo.sampleRate) { - return null; - } - const size = slice.filePos - startOffset; - const crc = readU8(slice); - slice.skip(-size); - slice.skip(-1); - const crcCalculated = calculateCrc8(readBytes(slice, size)); - if (crc !== crcCalculated) { - return null; - } - return { num, blockSize, sampleRate }; - } - async advanceReader() { - await this.readMetadata(); - assert(this.lastLoadedPos !== null); - assert(this.audioInfo); - const startPos = this.lastLoadedPos; - const frame = await this.readNextFlacFrame({ - startPos, - isFirstPacket: this.loadedSamples.length === 0 - }); - if (!frame) { - this.lastSampleLoaded = true; - return; - } - const lastSample = this.loadedSamples[this.loadedSamples.length - 1]; - const blockOffset = lastSample ? lastSample.blockOffset + lastSample.blockSize : 0; - const sample = { - blockOffset, - blockSize: frame.blockSize, - byteOffset: startPos, - byteSize: frame.size - }; - this.lastLoadedPos = this.lastLoadedPos + frame.size; - this.loadedSamples.push(sample); - if (frame.isLastFrame) { - this.lastSampleLoaded = true; - return; - } - } - } - class FlacAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - getCodec() { - return "flac"; - } - getInternalCodecId() { - return null; - } - getNumberOfChannels() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.numberOfChannels; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getSampleRate() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getTimeResolution() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async getDecoderConfig() { - assert(this.demuxer.audioInfo); - return { - codec: "flac", - numberOfChannels: this.demuxer.audioInfo.numberOfChannels, - sampleRate: this.demuxer.audioInfo.sampleRate, - description: this.demuxer.audioInfo.description - }; - } - async getPacket(timestamp, options) { - assert(this.demuxer.audioInfo); - if (timestamp < 0) { - throw new Error("Timestamp cannot be negative"); - } - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const packetIndex = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.blockOffset / this.demuxer.audioInfo.sampleRate); - if (packetIndex === -1) { - await this.demuxer.advanceReader(); - continue; - } - const packet = this.demuxer.loadedSamples[packetIndex]; - const sampleTimestamp = packet.blockOffset / this.demuxer.audioInfo.sampleRate; - const sampleDuration = packet.blockSize / this.demuxer.audioInfo.sampleRate; - if (sampleTimestamp + sampleDuration <= timestamp) { - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(this.demuxer.loadedSamples.length - 1, options); - } - await this.demuxer.advanceReader(); - continue; - } - return this.getPacketAtIndex(packetIndex, options); - } - } finally { - release(); - } - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const nextIndex = packet.sequenceNumber + 1; - if (this.demuxer.lastSampleLoaded && nextIndex >= this.demuxer.loadedSamples.length) { - return null; - } - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } - async getPacketAtIndex(sampleIndex, options) { - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.byteOffset, rawSample.byteSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.byteSize); - } - assert(this.demuxer.audioInfo); - const timestamp = rawSample.blockOffset / this.demuxer.audioInfo.sampleRate; - const duration = rawSample.blockSize / this.demuxer.audioInfo.sampleRate; - return new EncodedPacket(data, "key", timestamp, duration, sampleIndex, rawSample.byteSize); - } - async getFirstPacket(options) { - while (this.demuxer.loadedSamples.length === 0 && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(0, options); - } - } - class InputFormat { - } - class IsobmffInputFormat extends InputFormat { - /** @internal */ - async _getMajorBrand(input) { - let slice = input._reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return null; - slice.skip(4); - const fourCc = readAscii(slice, 4); - if (fourCc !== "ftyp") { - return null; - } - return readAscii(slice, 4); - } - /** @internal */ - _createDemuxer(input) { - return new IsobmffDemuxer(input); - } - } - class Mp4InputFormat extends IsobmffInputFormat { - /** @internal */ - async _canReadInput(input) { - const majorBrand = await this._getMajorBrand(input); - return !!majorBrand && majorBrand !== "qt "; - } - get name() { - return "MP4"; - } - get mimeType() { - return "video/mp4"; - } - } - class QuickTimeInputFormat extends IsobmffInputFormat { - /** @internal */ - async _canReadInput(input) { - const majorBrand = await this._getMajorBrand(input); - return majorBrand === "qt "; - } - get name() { - return "QuickTime File Format"; - } - get mimeType() { - return "video/quicktime"; - } - } - class MatroskaInputFormat extends InputFormat { - /** @internal */ - async isSupportedEBMLOfDocType(input, desiredDocType) { - let headerSlice = input._reader.requestSlice(0, MAX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) - return false; - const varIntSize = readVarIntSize(headerSlice); - if (varIntSize === null) { - return false; - } - if (varIntSize < 1 || varIntSize > 8) { - return false; - } - const id = readUnsignedInt(headerSlice, varIntSize); - if (id !== EBMLId.EBML) { - return false; - } - const dataSize = readElementSize(headerSlice); - if (typeof dataSize !== "number") { - return false; - } - let dataSlice = input._reader.requestSlice(headerSlice.filePos, dataSize); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (!dataSlice) - return false; - const startPos = headerSlice.filePos; - while (dataSlice.filePos <= startPos + dataSize - MIN_HEADER_SIZE) { - const header = readElementHeader(dataSlice); - if (!header) - break; - const { id: id2, size } = header; - const dataStartPos = dataSlice.filePos; - if (size === void 0) - return false; - switch (id2) { - case EBMLId.EBMLVersion: - { - const ebmlVersion = readUnsignedInt(dataSlice, size); - if (ebmlVersion !== 1) { - return false; - } - } - break; - case EBMLId.EBMLReadVersion: - { - const ebmlReadVersion = readUnsignedInt(dataSlice, size); - if (ebmlReadVersion !== 1) { - return false; - } - } - break; - case EBMLId.DocType: - { - const docType = readAsciiString(dataSlice, size); - if (docType !== desiredDocType) { - return false; - } - } - break; - case EBMLId.DocTypeVersion: - { - const docTypeVersion = readUnsignedInt(dataSlice, size); - if (docTypeVersion > 4) { - return false; - } - } - break; - } - dataSlice.filePos = dataStartPos + size; - } - return true; - } - /** @internal */ - _canReadInput(input) { - return this.isSupportedEBMLOfDocType(input, "matroska"); - } - /** @internal */ - _createDemuxer(input) { - return new MatroskaDemuxer(input); - } - get name() { - return "Matroska"; - } - get mimeType() { - return "video/x-matroska"; - } - } - class WebMInputFormat extends MatroskaInputFormat { - /** @internal */ - _canReadInput(input) { - return this.isSupportedEBMLOfDocType(input, "webm"); - } - get name() { - return "WebM"; - } - get mimeType() { - return "video/webm"; - } - } - class Mp3InputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 10); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - let currentPos = 0; - let id3V2HeaderFound = false; - while (true) { - let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const id3V2Header = readId3V2Header(slice2); - if (!id3V2Header) { - break; - } - id3V2HeaderFound = true; - currentPos = slice2.filePos + id3V2Header.size; - } - const firstResult = await readNextFrameHeader(input._reader, currentPos, currentPos + 4096); - if (!firstResult) { - return false; - } - if (id3V2HeaderFound) { - return true; - } - currentPos = firstResult.startPos + firstResult.header.totalSize; - const secondResult = await readNextFrameHeader(input._reader, currentPos, currentPos + FRAME_HEADER_SIZE); - if (!secondResult) { - return false; - } - const firstHeader = firstResult.header; - const secondHeader = secondResult.header; - if (firstHeader.channel !== secondHeader.channel || firstHeader.sampleRate !== secondHeader.sampleRate) { - return false; - } - return true; - } - /** @internal */ - _createDemuxer(input) { - return new Mp3Demuxer(input); - } - get name() { - return "MP3"; - } - get mimeType() { - return "audio/mpeg"; - } - } - class WaveInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const riffType = readAscii(slice, 4); - if (riffType !== "RIFF" && riffType !== "RIFX" && riffType !== "RF64") { - return false; - } - slice.skip(4); - const format = readAscii(slice, 4); - return format === "WAVE"; - } - /** @internal */ - _createDemuxer(input) { - return new WaveDemuxer(input); - } - get name() { - return "WAVE"; - } - get mimeType() { - return "audio/wav"; - } - } - class OggInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 4); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - return readAscii(slice, 4) === "OggS"; - } - /** @internal */ - _createDemuxer(input) { - return new OggDemuxer(input); - } - get name() { - return "Ogg"; - } - get mimeType() { - return "application/ogg"; - } - } - class FlacInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 4); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - return readAscii(slice, 4) === "fLaC"; - } - get name() { - return "FLAC"; - } - get mimeType() { - return "audio/flac"; - } - /** @internal */ - _createDemuxer(input) { - return new FlacDemuxer(input); - } - } - class AdtsInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSliceRange(0, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const firstHeader = readFrameHeader(slice); - if (!firstHeader) { - return false; - } - slice = input._reader.requestSliceRange(firstHeader.frameLength, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const secondHeader = readFrameHeader(slice); - if (!secondHeader) { - return false; - } - return firstHeader.objectType === secondHeader.objectType && firstHeader.samplingFrequencyIndex === secondHeader.samplingFrequencyIndex && firstHeader.channelConfiguration === secondHeader.channelConfiguration; - } - /** @internal */ - _createDemuxer(input) { - return new AdtsDemuxer(input); - } - get name() { - return "ADTS"; - } - get mimeType() { - return "audio/aac"; - } - } - const MP4 = /* @__PURE__ */ new Mp4InputFormat(); - const QTFF = /* @__PURE__ */ new QuickTimeInputFormat(); - const MATROSKA = /* @__PURE__ */ new MatroskaInputFormat(); - const WEBM = /* @__PURE__ */ new WebMInputFormat(); - const MP3 = /* @__PURE__ */ new Mp3InputFormat(); - const WAVE = /* @__PURE__ */ new WaveInputFormat(); - const OGG = /* @__PURE__ */ new OggInputFormat(); - const ADTS = /* @__PURE__ */ new AdtsInputFormat(); - const FLAC = /* @__PURE__ */ new FlacInputFormat(); - const ALL_FORMATS = [MP4, QTFF, MATROSKA, WEBM, WAVE, OGG, FLAC, MP3, ADTS]; - new Proxy({}, { - get(_, key) { - throw new Error(`Module "" has been externalized for browser compatibility. Cannot access ".${key}" in client code. See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.`); - } - }); - class Source { - constructor() { - this._disposed = false; - this._sizePromise = null; - this.onread = null; - } - /** - * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call - * will retrieve the size. - * - * Returns null if the source is unsized. - */ - async getSizeOrNull() { - if (this._disposed) { - throw new InputDisposedError(); - } - return this._sizePromise ?? (this._sizePromise = Promise.resolve(this._retrieveSize())); - } - /** - * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call - * will retrieve the size. - * - * Throws an error if the source is unsized. - */ - async getSize() { - if (this._disposed) { - throw new InputDisposedError(); - } - const result = await this.getSizeOrNull(); - if (result === null) { - throw new Error("Cannot determine the size of an unsized source."); - } - return result; - } - } - class BlobSource extends Source { - /** - * Creates a new {@link BlobSource} backed by the specified - * [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). - */ - constructor(blob, options = {}) { - if (!(blob instanceof Blob)) { - throw new TypeError("blob must be a Blob."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - super(); - this._readers = /* @__PURE__ */ new WeakMap(); - this._blob = blob; - this._orchestrator = new ReadOrchestrator({ - maxCacheSize: options.maxCacheSize ?? 8 * 2 ** 20, - maxWorkerCount: 4, - runWorker: this._runWorker.bind(this), - prefetchProfile: PREFETCH_PROFILES.fileSystem - }); - } - /** @internal */ - _retrieveSize() { - const size = this._blob.size; - this._orchestrator.fileSize = size; - return size; - } - /** @internal */ - _read(start, end) { - return this._orchestrator.read(start, end); - } - /** @internal */ - async _runWorker(worker) { - let reader = this._readers.get(worker); - if (reader === void 0) { - if ("stream" in this._blob && !isWebKit()) { - const slice = this._blob.slice(worker.currentPos); - reader = slice.stream().getReader(); - } else { - reader = null; - } - this._readers.set(worker, reader); - } - while (worker.currentPos < worker.targetPos && !worker.aborted) { - if (reader) { - const { done, value } = await reader.read(); - if (done) { - this._orchestrator.forgetWorker(worker); - throw new Error("Blob reader stopped unexpectedly before all requested data was read."); - } - if (worker.aborted) { - break; - } - this.onread?.(worker.currentPos, worker.currentPos + value.length); - this._orchestrator.supplyWorkerData(worker, value); - } else { - const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer(); - if (worker.aborted) { - break; - } - this.onread?.(worker.currentPos, worker.currentPos + data.byteLength); - this._orchestrator.supplyWorkerData(worker, new Uint8Array(data)); - } - } - worker.running = false; - if (worker.aborted) { - await reader?.cancel(); - } - } - /** @internal */ - _dispose() { - this._orchestrator.dispose(); - } - } - const URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20; - const DEFAULT_RETRY_DELAY = ((previousAttempts, error, src) => { - const couldBeCorsError = error instanceof Error && (error.message.includes("Failed to fetch") || error.message.includes("Load failed") || error.message.includes("NetworkError when attempting to fetch resource")); - if (couldBeCorsError) { - let originOfSrc = null; - try { - if (typeof window !== "undefined" && typeof window.location !== "undefined") { - originOfSrc = new URL(src instanceof Request ? src.url : src, window.location.href).origin; - } - } catch { - } - const isOnline = typeof navigator !== "undefined" && typeof navigator.onLine === "boolean" ? navigator.onLine : true; - if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) { - console.warn(`Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option.`); - return null; - } - } - return Math.min(2 ** (previousAttempts - 2), 16); - }); - class UrlSource extends Source { - /** Creates a new {@link UrlSource} backed by the resource at the specified URL. */ - constructor(url, options = {}) { - if (typeof url !== "string" && !(url instanceof URL) && !(typeof Request !== "undefined" && url instanceof Request)) { - throw new TypeError("url must be a string, URL or Request."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.requestInit !== void 0 && (!options.requestInit || typeof options.requestInit !== "object")) { - throw new TypeError("options.requestInit, when provided, must be an object."); - } - if (options.getRetryDelay !== void 0 && typeof options.getRetryDelay !== "function") { - throw new TypeError("options.getRetryDelay, when provided, must be a function."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - if (options.fetchFn !== void 0 && typeof options.fetchFn !== "function") { - throw new TypeError("options.fetchFn, when provided, must be a function."); - } - super(); - this._existingResponses = /* @__PURE__ */ new WeakMap(); - this._url = url; - this._options = options; - this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY; - this._orchestrator = new ReadOrchestrator({ - maxCacheSize: options.maxCacheSize ?? 64 * 2 ** 20, - // Most files in the real-world have a single sequential access pattern, but having two in parallel can - // also happen - maxWorkerCount: 2, - runWorker: this._runWorker.bind(this), - prefetchProfile: PREFETCH_PROFILES.network - }); - } - /** @internal */ - async _retrieveSize() { - const abortController = new AbortController(); - const response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { - headers: { - // We could also send a non-range request to request the same bytes (all of them), but doing it like - // this is an easy way to check if the server supports range requests in the first place - Range: "bytes=0-" - }, - signal: abortController.signal - }), this._getRetryDelay, () => this._disposed); - if (!response.ok) { - throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); - } - let worker; - let fileSize; - if (response.status === 206) { - fileSize = this._getTotalLengthFromRangeResponse(response); - worker = this._orchestrator.createWorker(0, Math.min(fileSize, URL_SOURCE_MIN_LOAD_AMOUNT)); - } else { - const contentLength = response.headers.get("Content-Length"); - if (contentLength) { - fileSize = Number(contentLength); - worker = this._orchestrator.createWorker(0, fileSize); - this._orchestrator.options.maxCacheSize = Infinity; - console.warn("HTTP server did not respond with 206 Partial Content, meaning the entire remote resource now has to be downloaded. For efficient media file streaming across a network, please make sure your server supports range requests."); - } else { - throw new Error(`HTTP response (status ${response.status}) must surface Content-Length header.`); - } - } - this._orchestrator.fileSize = fileSize; - this._existingResponses.set(worker, { response, abortController }); - this._orchestrator.runWorker(worker); - return fileSize; - } - /** @internal */ - _read(start, end) { - return this._orchestrator.read(start, end); - } - /** @internal */ - async _runWorker(worker) { - while (true) { - const existing = this._existingResponses.get(worker); - this._existingResponses.delete(worker); - let abortController = existing?.abortController; - let response = existing?.response; - if (!abortController) { - abortController = new AbortController(); - response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { - headers: { - Range: `bytes=${worker.currentPos}-` - }, - signal: abortController.signal - }), this._getRetryDelay, () => this._disposed); - } - assert(response); - if (!response.ok) { - throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); - } - if (worker.currentPos > 0 && response.status !== 206) { - throw new Error("HTTP server did not respond with 206 Partial Content to a range request. To enable efficient media file streaming across a network, please make sure your server supports range requests."); - } - if (!response.body) { - throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream."); - } - const reader = response.body.getReader(); - while (true) { - if (worker.currentPos >= worker.targetPos || worker.aborted) { - abortController.abort(); - worker.running = false; - return; - } - let readResult; - try { - readResult = await reader.read(); - } catch (error) { - if (this._disposed) { - throw error; - } - const retryDelayInSeconds = this._getRetryDelay(1, error, this._url); - if (retryDelayInSeconds !== null) { - console.error("Error while reading response stream. Attempting to resume.", error); - await new Promise((resolve) => setTimeout(resolve, 1e3 * retryDelayInSeconds)); - break; - } else { - throw error; - } - } - if (worker.aborted) { - continue; - } - const { done, value } = readResult; - if (done) { - if (worker.currentPos >= worker.targetPos) { - this._orchestrator.forgetWorker(worker); - worker.running = false; - return; - } - break; - } - this.onread?.(worker.currentPos, worker.currentPos + value.length); - this._orchestrator.supplyWorkerData(worker, value); - } - } - } - /** @internal */ - _getTotalLengthFromRangeResponse(response) { - const contentRange = response.headers.get("Content-Range"); - if (contentRange) { - const match = /\/(\d+)/.exec(contentRange); - if (match) { - return Number(match[1]); - } - } - const contentLength = response.headers.get("Content-Length"); - if (contentLength) { - return Number(contentLength); - } else { - throw new Error("Partial HTTP response (status 206) must surface either Content-Range or Content-Length header."); - } - } - /** @internal */ - _dispose() { - this._orchestrator.dispose(); - } - } - class ReadableStreamSource extends Source { - /** Creates a new {@link ReadableStreamSource} backed by the specified `ReadableStream`. */ - constructor(stream, options = {}) { - if (!(stream instanceof ReadableStream)) { - throw new TypeError("stream must be a ReadableStream."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - super(); - this._reader = null; - this._cache = []; - this._pendingSlices = []; - this._currentIndex = 0; - this._targetIndex = 0; - this._maxRequestedIndex = 0; - this._endIndex = null; - this._pulling = false; - this._stream = stream; - this._maxCacheSize = options.maxCacheSize ?? 16 * 2 ** 20; - } - /** @internal */ - _retrieveSize() { - return this._endIndex; - } - /** @internal */ - _read(start, end) { - if (this._endIndex !== null && end > this._endIndex) { - return null; - } - this._maxRequestedIndex = Math.max(this._maxRequestedIndex, end); - const cacheStartIndex = binarySearchLessOrEqual(this._cache, start, (x) => x.start); - const cacheStartEntry = cacheStartIndex !== -1 ? this._cache[cacheStartIndex] : null; - if (cacheStartEntry && cacheStartEntry.start <= start && end <= cacheStartEntry.end) { - return { - bytes: cacheStartEntry.bytes, - view: cacheStartEntry.view, - offset: cacheStartEntry.start - }; - } - let lastEnd = start; - const bytes = new Uint8Array(end - start); - if (cacheStartIndex !== -1) { - for (let i = cacheStartIndex; i < this._cache.length; i++) { - const cacheEntry = this._cache[i]; - if (cacheEntry.start >= end) { - break; - } - const cappedStart = Math.max(start, cacheEntry.start); - if (cappedStart > lastEnd) { - this._throwDueToCacheMiss(); - } - const cappedEnd = Math.min(end, cacheEntry.end); - if (cappedStart < cappedEnd) { - bytes.set(cacheEntry.bytes.subarray(cappedStart - cacheEntry.start, cappedEnd - cacheEntry.start), cappedStart - start); - lastEnd = cappedEnd; - } - } - } - if (lastEnd === end) { - return { - bytes, - view: toDataView(bytes), - offset: start - }; - } - if (this._currentIndex > lastEnd) { - this._throwDueToCacheMiss(); - } - const { promise, resolve, reject } = promiseWithResolvers(); - this._pendingSlices.push({ - start, - end, - bytes, - resolve, - reject - }); - this._targetIndex = Math.max(this._targetIndex, end); - if (!this._pulling) { - this._pulling = true; - void this._pull().catch((error) => { - this._pulling = false; - if (this._pendingSlices.length > 0) { - this._pendingSlices.forEach((x) => x.reject(error)); - this._pendingSlices.length = 0; - } else { - throw error; - } - }); - } - return promise; - } - /** @internal */ - _throwDueToCacheMiss() { - throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache."); - } - /** @internal */ - async _pull() { - this._reader ?? (this._reader = this._stream.getReader()); - while (this._currentIndex < this._targetIndex && !this._disposed) { - const { done, value } = await this._reader.read(); - if (done) { - for (const pendingSlice of this._pendingSlices) { - pendingSlice.resolve(null); - } - this._pendingSlices.length = 0; - this._endIndex = this._currentIndex; - break; - } - const startIndex = this._currentIndex; - const endIndex = this._currentIndex + value.byteLength; - for (let i = 0; i < this._pendingSlices.length; i++) { - const pendingSlice = this._pendingSlices[i]; - const cappedStart = Math.max(startIndex, pendingSlice.start); - const cappedEnd = Math.min(endIndex, pendingSlice.end); - if (cappedStart < cappedEnd) { - pendingSlice.bytes.set(value.subarray(cappedStart - startIndex, cappedEnd - startIndex), cappedStart - pendingSlice.start); - if (cappedEnd === pendingSlice.end) { - pendingSlice.resolve({ - bytes: pendingSlice.bytes, - view: toDataView(pendingSlice.bytes), - offset: pendingSlice.start - }); - this._pendingSlices.splice(i, 1); - i--; - } - } - } - this._cache.push({ - start: startIndex, - end: endIndex, - bytes: value, - view: toDataView(value), - age: 0 - // Unused - }); - while (this._cache.length > 0) { - const firstEntry = this._cache[0]; - const distance = this._maxRequestedIndex - firstEntry.end; - if (distance <= this._maxCacheSize) { - break; - } - this._cache.shift(); - } - this._currentIndex += value.byteLength; - } - this._pulling = false; - } - /** @internal */ - _dispose() { - this._pendingSlices.length = 0; - this._cache.length = 0; - } - } - const PREFETCH_PROFILES = { - fileSystem: (start, end) => { - const padding = 2 ** 16; - start = Math.floor((start - padding) / padding) * padding; - end = Math.ceil((end + padding) / padding) * padding; - return { start, end }; - }, - network: (start, end, workers) => { - const paddingStart = 2 ** 16; - start = Math.max(0, Math.floor((start - paddingStart) / paddingStart) * paddingStart); - for (const worker of workers) { - const maxExtensionAmount = 8 * 2 ** 20; - const thresholdPoint = Math.max((worker.startPos + worker.targetPos) / 2, worker.targetPos - maxExtensionAmount); - if (closedIntervalsOverlap(start, end, thresholdPoint, worker.targetPos)) { - const size = worker.targetPos - worker.startPos; - const a = Math.ceil((size + 1) / maxExtensionAmount) * maxExtensionAmount; - const b = 2 ** Math.ceil(Math.log2(size + 1)); - const extent = Math.min(b, a); - end = Math.max(end, worker.startPos + extent); - } - } - end = Math.max(end, start + URL_SOURCE_MIN_LOAD_AMOUNT); - return { - start, - end - }; - } - }; - class ReadOrchestrator { - constructor(options) { - this.options = options; - this.fileSize = null; - this.nextAge = 0; - this.workers = []; - this.cache = []; - this.currentCacheSize = 0; - this.disposed = false; - } - read(innerStart, innerEnd) { - assert(this.fileSize !== null); - const prefetchRange = this.options.prefetchProfile(innerStart, innerEnd, this.workers); - const outerStart = Math.max(prefetchRange.start, 0); - const outerEnd = Math.min(prefetchRange.end, this.fileSize); - assert(outerStart <= innerStart && innerEnd <= outerEnd); - let result = null; - const innerCacheStartIndex = binarySearchLessOrEqual(this.cache, innerStart, (x) => x.start); - const innerStartEntry = innerCacheStartIndex !== -1 ? this.cache[innerCacheStartIndex] : null; - if (innerStartEntry && innerStartEntry.start <= innerStart && innerEnd <= innerStartEntry.end) { - innerStartEntry.age = this.nextAge++; - result = { - bytes: innerStartEntry.bytes, - view: innerStartEntry.view, - offset: innerStartEntry.start - }; - } - const outerCacheStartIndex = binarySearchLessOrEqual(this.cache, outerStart, (x) => x.start); - const bytes = result ? null : new Uint8Array(innerEnd - innerStart); - let contiguousBytesWriteEnd = 0; - let lastEnd = outerStart; - const outerHoles = []; - if (outerCacheStartIndex !== -1) { - for (let i = outerCacheStartIndex; i < this.cache.length; i++) { - const entry = this.cache[i]; - if (entry.start >= outerEnd) { - break; - } - if (entry.end <= outerStart) { - continue; - } - const cappedOuterStart = Math.max(outerStart, entry.start); - const cappedOuterEnd = Math.min(outerEnd, entry.end); - assert(cappedOuterStart <= cappedOuterEnd); - if (lastEnd < cappedOuterStart) { - outerHoles.push({ start: lastEnd, end: cappedOuterStart }); - } - lastEnd = cappedOuterEnd; - if (bytes) { - const cappedInnerStart = Math.max(innerStart, entry.start); - const cappedInnerEnd = Math.min(innerEnd, entry.end); - if (cappedInnerStart < cappedInnerEnd) { - const relativeOffset = cappedInnerStart - innerStart; - bytes.set(entry.bytes.subarray(cappedInnerStart - entry.start, cappedInnerEnd - entry.start), relativeOffset); - if (relativeOffset === contiguousBytesWriteEnd) { - contiguousBytesWriteEnd = cappedInnerEnd - innerStart; - } - } - } - entry.age = this.nextAge++; - } - if (lastEnd < outerEnd) { - outerHoles.push({ start: lastEnd, end: outerEnd }); - } - } else { - outerHoles.push({ start: outerStart, end: outerEnd }); - } - if (bytes && contiguousBytesWriteEnd >= bytes.length) { - result = { - bytes, - view: toDataView(bytes), - offset: innerStart - }; - } - if (outerHoles.length === 0) { - assert(result); - return result; - } - const { promise, resolve, reject } = promiseWithResolvers(); - const innerHoles = []; - for (const outerHole of outerHoles) { - const cappedStart = Math.max(innerStart, outerHole.start); - const cappedEnd = Math.min(innerEnd, outerHole.end); - if (cappedStart === outerHole.start && cappedEnd === outerHole.end) { - innerHoles.push(outerHole); - } else if (cappedStart < cappedEnd) { - innerHoles.push({ start: cappedStart, end: cappedEnd }); - } - } - for (const outerHole of outerHoles) { - const pendingSlice = bytes && { - start: innerStart, - bytes, - holes: innerHoles, - resolve, - reject - }; - let workerFound = false; - for (const worker of this.workers) { - const gapTolerance = 2 ** 17; - if (closedIntervalsOverlap(outerHole.start - gapTolerance, outerHole.start, worker.currentPos, worker.targetPos)) { - worker.targetPos = Math.max(worker.targetPos, outerHole.end); - workerFound = true; - if (pendingSlice && !worker.pendingSlices.includes(pendingSlice)) { - worker.pendingSlices.push(pendingSlice); - } - if (!worker.running) { - this.runWorker(worker); - } - break; - } - } - if (!workerFound) { - const newWorker = this.createWorker(outerHole.start, outerHole.end); - if (pendingSlice) { - newWorker.pendingSlices = [pendingSlice]; - } - this.runWorker(newWorker); - } - } - if (!result) { - assert(bytes); - result = promise.then((bytes2) => ({ - bytes: bytes2, - view: toDataView(bytes2), - offset: innerStart - })); - } - return result; - } - createWorker(startPos, targetPos) { - const worker = { - startPos, - currentPos: startPos, - targetPos, - running: false, - // Due to async shenanigans, it can happen that workers are started after disposal. In this case, instead of - // simply not creating the worker, we allow it to run but immediately label it as aborted, so it can then - // shut itself down. - aborted: this.disposed, - pendingSlices: [], - age: this.nextAge++ - }; - this.workers.push(worker); - while (this.workers.length > this.options.maxWorkerCount) { - let oldestIndex = 0; - let oldestWorker = this.workers[0]; - for (let i = 1; i < this.workers.length; i++) { - const worker2 = this.workers[i]; - if (worker2.age < oldestWorker.age) { - oldestIndex = i; - oldestWorker = worker2; - } - } - if (oldestWorker.running && oldestWorker.pendingSlices.length > 0) { - break; - } - oldestWorker.aborted = true; - this.workers.splice(oldestIndex, 1); - } - return worker; - } - runWorker(worker) { - assert(!worker.running); - assert(worker.currentPos < worker.targetPos); - worker.running = true; - worker.age = this.nextAge++; - void this.options.runWorker(worker).catch((error) => { - worker.running = false; - if (worker.pendingSlices.length > 0) { - worker.pendingSlices.forEach((x) => x.reject(error)); - worker.pendingSlices.length = 0; - } else { - throw error; - } - }); - } - /** Called by a worker when it has read some data. */ - supplyWorkerData(worker, bytes) { - assert(!worker.aborted); - const start = worker.currentPos; - const end = start + bytes.length; - this.insertIntoCache({ - start, - end, - bytes, - view: toDataView(bytes), - age: this.nextAge++ - }); - worker.currentPos += bytes.length; - worker.targetPos = Math.max(worker.targetPos, worker.currentPos); - for (let i = 0; i < worker.pendingSlices.length; i++) { - const pendingSlice = worker.pendingSlices[i]; - const clampedStart = Math.max(start, pendingSlice.start); - const clampedEnd = Math.min(end, pendingSlice.start + pendingSlice.bytes.length); - if (clampedStart < clampedEnd) { - pendingSlice.bytes.set(bytes.subarray(clampedStart - start, clampedEnd - start), clampedStart - pendingSlice.start); - } - for (let j = 0; j < pendingSlice.holes.length; j++) { - const hole = pendingSlice.holes[j]; - if (start <= hole.start && end > hole.start) { - hole.start = end; - } - if (hole.end <= hole.start) { - pendingSlice.holes.splice(j, 1); - j--; - } - } - if (pendingSlice.holes.length === 0) { - pendingSlice.resolve(pendingSlice.bytes); - worker.pendingSlices.splice(i, 1); - i--; - } - } - for (let i = 0; i < this.workers.length; i++) { - const otherWorker = this.workers[i]; - if (worker === otherWorker || otherWorker.running) { - continue; - } - if (closedIntervalsOverlap(start, end, otherWorker.currentPos, otherWorker.targetPos)) { - this.workers.splice(i, 1); - i--; - } - } - } - forgetWorker(worker) { - const index = this.workers.indexOf(worker); - assert(index !== -1); - this.workers.splice(index, 1); - } - insertIntoCache(entry) { - if (this.options.maxCacheSize === 0) { - return; - } - let insertionIndex = binarySearchLessOrEqual(this.cache, entry.start, (x) => x.start) + 1; - if (insertionIndex > 0) { - const previous = this.cache[insertionIndex - 1]; - if (previous.end >= entry.end) { - return; - } - if (previous.end > entry.start) { - const joined = new Uint8Array(entry.end - previous.start); - joined.set(previous.bytes, 0); - joined.set(entry.bytes, entry.start - previous.start); - this.currentCacheSize += entry.end - previous.end; - previous.bytes = joined; - previous.view = toDataView(joined); - previous.end = entry.end; - insertionIndex--; - entry = previous; - } else { - this.cache.splice(insertionIndex, 0, entry); - this.currentCacheSize += entry.bytes.length; - } - } else { - this.cache.splice(insertionIndex, 0, entry); - this.currentCacheSize += entry.bytes.length; - } - for (let i = insertionIndex + 1; i < this.cache.length; i++) { - const next = this.cache[i]; - if (entry.end <= next.start) { - break; - } - if (entry.end >= next.end) { - this.cache.splice(i, 1); - this.currentCacheSize -= next.bytes.length; - i--; - continue; - } - const joined = new Uint8Array(next.end - entry.start); - joined.set(entry.bytes, 0); - joined.set(next.bytes, next.start - entry.start); - this.currentCacheSize -= entry.end - next.start; - entry.bytes = joined; - entry.view = toDataView(joined); - entry.end = next.end; - this.cache.splice(i, 1); - break; - } - while (this.currentCacheSize > this.options.maxCacheSize) { - let oldestIndex = 0; - let oldestEntry = this.cache[0]; - for (let i = 1; i < this.cache.length; i++) { - const entry2 = this.cache[i]; - if (entry2.age < oldestEntry.age) { - oldestIndex = i; - oldestEntry = entry2; - } - } - if (this.currentCacheSize - oldestEntry.bytes.length <= this.options.maxCacheSize) { - break; - } - this.cache.splice(oldestIndex, 1); - this.currentCacheSize -= oldestEntry.bytes.length; - } - } - dispose() { - for (const worker of this.workers) { - worker.aborted = true; - } - this.workers.length = 0; - this.cache.length = 0; - this.disposed = true; - } - } - polyfillSymbolDispose(); - class Input { - /** True if the input has been disposed. */ - get disposed() { - return this._disposed; - } - /** - * Creates a new input file from the specified options. No reading operations will be performed until methods are - * called on this instance. - */ - constructor(options) { - this._demuxerPromise = null; - this._format = null; - this._disposed = false; - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (!Array.isArray(options.formats) || options.formats.some((x) => !(x instanceof InputFormat))) { - throw new TypeError("options.formats must be an array of InputFormat."); - } - if (!(options.source instanceof Source)) { - throw new TypeError("options.source must be a Source."); - } - if (options.source._disposed) { - throw new Error("options.source must not be disposed."); - } - this._formats = options.formats; - this._source = options.source; - this._reader = new Reader(options.source); - } - /** @internal */ - _getDemuxer() { - return this._demuxerPromise ?? (this._demuxerPromise = (async () => { - this._reader.fileSize = await this._source.getSizeOrNull(); - for (const format of this._formats) { - const canRead = await format._canReadInput(this); - if (canRead) { - this._format = format; - return format._createDemuxer(this); - } - } - throw new Error("Input has an unsupported or unrecognizable format."); - })()); - } - /** - * Returns the source from which this input file reads its data. This is the same source that was passed to the - * constructor. - */ - get source() { - return this._source; - } - /** - * Returns the format of the input file. You can compare this result directly to the {@link InputFormat} singletons - * or use `instanceof` checks for subset-aware logic (for example, `format instanceof MatroskaInputFormat` is true - * for both MKV and WebM). - */ - async getFormat() { - await this._getDemuxer(); - assert(this._format); - return this._format; - } - /** - * Computes the duration of the input file, in seconds. More precisely, returns the largest end timestamp among - * all tracks. - */ - async computeDuration() { - const demuxer = await this._getDemuxer(); - return demuxer.computeDuration(); - } - /** Returns the list of all tracks of this input file. */ - async getTracks() { - const demuxer = await this._getDemuxer(); - return demuxer.getTracks(); - } - /** Returns the list of all video tracks of this input file. */ - async getVideoTracks() { - const tracks = await this.getTracks(); - return tracks.filter((x) => x.isVideoTrack()); - } - /** Returns the list of all audio tracks of this input file. */ - async getAudioTracks() { - const tracks = await this.getTracks(); - return tracks.filter((x) => x.isAudioTrack()); - } - /** Returns the primary video track of this input file, or null if there are no video tracks. */ - async getPrimaryVideoTrack() { - const tracks = await this.getTracks(); - return tracks.find((x) => x.isVideoTrack()) ?? null; - } - /** Returns the primary audio track of this input file, or null if there are no audio tracks. */ - async getPrimaryAudioTrack() { - const tracks = await this.getTracks(); - return tracks.find((x) => x.isAudioTrack()) ?? null; - } - /** Returns the full MIME type of this input file, including track codecs. */ - async getMimeType() { - const demuxer = await this._getDemuxer(); - return demuxer.getMimeType(); - } - /** - * Returns descriptive metadata tags about the media file, such as title, author, date, cover art, or other - * attached files. - */ - async getMetadataTags() { - const demuxer = await this._getDemuxer(); - return demuxer.getMetadataTags(); - } - /** - * Disposes this input and frees connected resources. When an input is disposed, ongoing read operations will be - * canceled, all future read operations will fail, any open decoders will be closed, and all ongoing media sink - * operations will be canceled. Disallowed and canceled operations will throw an {@link InputDisposedError}. - * - * You are expected not to use an input after disposing it. While some operations may still work, it is not - * specified and may change in any future update. - */ - dispose() { - if (this._disposed) { - return; - } - this._disposed = true; - this._source._disposed = true; - this._source._dispose(); - } - /** - * Calls `.dispose()` on the input, implementing the `Disposable` interface for use with - * JavaScript Explicit Resource Management features. - */ - [Symbol.dispose]() { - this.dispose(); - } - } - class InputDisposedError extends Error { - /** Creates a new {@link InputDisposedError}. */ - constructor(message = "Input has been disposed.") { - super(message); - this.name = "InputDisposedError"; - } - } - class Reader { - constructor(source) { - this.source = source; - } - requestSlice(start, length) { - if (this.source._disposed) { - throw new InputDisposedError(); - } - if (this.fileSize !== null && start + length > this.fileSize) { - return null; - } - const end = start + length; - const result = this.source._read(start, end); - if (result instanceof Promise) { - return result.then((x) => { - if (!x) { - return null; - } - return new FileSlice(x.bytes, x.view, x.offset, start, end); - }); - } else { - if (!result) { - return null; - } - return new FileSlice(result.bytes, result.view, result.offset, start, end); - } - } - requestSliceRange(start, minLength, maxLength) { - if (this.source._disposed) { - throw new InputDisposedError(); - } - if (this.fileSize !== null) { - return this.requestSlice(start, clamp$1(this.fileSize - start, minLength, maxLength)); - } else { - const promisedAttempt = this.requestSlice(start, maxLength); - const handleAttempt = (attempt) => { - if (attempt) { - return attempt; - } - const handleFileSize = (fileSize) => { - assert(fileSize !== null); - return this.requestSlice(start, clamp$1(fileSize - start, minLength, maxLength)); - }; - const promisedFileSize = this.source._retrieveSize(); - if (promisedFileSize instanceof Promise) { - return promisedFileSize.then(handleFileSize); - } else { - return handleFileSize(promisedFileSize); - } - }; - if (promisedAttempt instanceof Promise) { - return promisedAttempt.then(handleAttempt); - } else { - return handleAttempt(promisedAttempt); - } - } - } - } - class FileSlice { - constructor(bytes, view, offset, start, end) { - this.bytes = bytes; - this.view = view; - this.offset = offset; - this.start = start; - this.end = end; - this.bufferPos = start - offset; - } - static tempFromBytes(bytes) { - return new FileSlice(bytes, toDataView(bytes), 0, 0, bytes.length); - } - get length() { - return this.end - this.start; - } - get filePos() { - return this.offset + this.bufferPos; - } - set filePos(value) { - this.bufferPos = value - this.offset; - } - /** The number of bytes left from the current pos to the end of the slice. */ - get remainingLength() { - return Math.max(this.end - this.filePos, 0); - } - skip(byteCount) { - this.bufferPos += byteCount; - } - /** Creates a new subslice of this slice whose byte range must be contained within this slice. */ - slice(filePos, length = this.end - filePos) { - if (filePos < this.start || filePos + length > this.end) { - throw new RangeError("Slicing outside of original slice."); - } - return new FileSlice(this.bytes, this.view, this.offset, filePos, filePos + length); - } - } - const checkIsInRange = (slice, bytesToRead) => { - if (slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) { - throw new RangeError(`Tried reading [${slice.filePos}, ${slice.filePos + bytesToRead}), but slice is [${slice.start}, ${slice.end}). This is likely an internal error, please report it alongside the file that caused it.`); - } - }; - const readBytes = (slice, length) => { - checkIsInRange(slice, length); - const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length); - slice.bufferPos += length; - return bytes; - }; - const readU8 = (slice) => { - checkIsInRange(slice, 1); - return slice.view.getUint8(slice.bufferPos++); - }; - const readU16 = (slice, littleEndian) => { - checkIsInRange(slice, 2); - const value = slice.view.getUint16(slice.bufferPos, littleEndian); - slice.bufferPos += 2; - return value; - }; - const readU16Be = (slice) => { - checkIsInRange(slice, 2); - const value = slice.view.getUint16(slice.bufferPos, false); - slice.bufferPos += 2; - return value; - }; - const readU24Be = (slice) => { - checkIsInRange(slice, 3); - const value = getUint24(slice.view, slice.bufferPos, false); - slice.bufferPos += 3; - return value; - }; - const readI16Be = (slice) => { - checkIsInRange(slice, 2); - const value = slice.view.getInt16(slice.bufferPos, false); - slice.bufferPos += 2; - return value; - }; - const readU32 = (slice, littleEndian) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, littleEndian); - slice.bufferPos += 4; - return value; - }; - const readU32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; - }; - const readU32Le = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, true); - slice.bufferPos += 4; - return value; - }; - const readI32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getInt32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; - }; - const readI32Le = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getInt32(slice.bufferPos, true); - slice.bufferPos += 4; - return value; - }; - const readU64 = (slice, littleEndian) => { - let low; - let high; - if (littleEndian) { - low = readU32(slice, true); - high = readU32(slice, true); - } else { - high = readU32(slice, false); - low = readU32(slice, false); - } - return high * 4294967296 + low; - }; - const readU64Be = (slice) => { - const high = readU32Be(slice); - const low = readU32Be(slice); - return high * 4294967296 + low; - }; - const readI64Be = (slice) => { - const high = readI32Be(slice); - const low = readU32Be(slice); - return high * 4294967296 + low; - }; - const readI64Le = (slice) => { - const low = readU32Le(slice); - const high = readI32Le(slice); - return high * 4294967296 + low; - }; - const readF32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getFloat32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; - }; - const readF64Be = (slice) => { - checkIsInRange(slice, 8); - const value = slice.view.getFloat64(slice.bufferPos, false); - slice.bufferPos += 8; - return value; - }; - const readAscii = (slice, length) => { - checkIsInRange(slice, length); - let str = ""; - for (let i = 0; i < length; i++) { - str += String.fromCharCode(slice.bytes[slice.bufferPos++]); - } - return str; - }; class AudioEngine { constructor(events) { this.events = events; @@ -14477,16 +21255,6 @@ var artplayerProxyMediabunny = (function() { return this.playbackTimeAtStart; return (this.audioContext.currentTime - this.audioContextStartTime) * this.playbackRate + this.playbackTimeAtStart; } - normalizeSource(src) { - if (typeof src === "string") - return new UrlSource(src); - if (src instanceof Blob) - return new BlobSource(src); - if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { - return new ReadableStreamSource(src); - } - return src; - } ensureAudioContext(sampleRate) { if (this.audioContext) return; @@ -14514,27 +21282,22 @@ var artplayerProxyMediabunny = (function() { await this.audioIterator?.return(); this.audioIterator = null; } - async load(src, onMetadata) { - const id = ++this.asyncId; + handleNoAudioTrack() { + this.audioSink = null; + this.ensureAudioContext(); + } + async load(media, onMetadata) { + ++this.asyncId; await this.stopIterator(); this.stopQueuedNodes(); this.paused = true; this.playbackTimeAtStart = 0; this.audioContextStartTime = 0; - const source = this.normalizeSource(src); - if (!source) - return; - this.input = new Input({ - source, - formats: ALL_FORMATS - }); - this.duration = await this.input.computeDuration(); - if (id !== this.asyncId) - return; - const audioTrack = await this.input.getPrimaryAudioTrack(); + const { input, audioTrack, duration } = media; + this.input = input; + this.duration = duration; if (!audioTrack) { - this.audioSink = null; - this.ensureAudioContext(); + this.handleNoAudioTrack(); onMetadata?.(); return; } @@ -14667,6 +21430,99 @@ var artplayerProxyMediabunny = (function() { this.audioSink = null; } } + const M3U8_RE = /\.m3u8(?:$|[?#])/i; + function isHlsSource(src) { + return typeof src === "string" && M3U8_RE.test(src); + } + function normalizeSource(src) { + if (typeof src === "string") + return new UrlSource(src); + if (src instanceof Blob) + return new BlobSource(src); + if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { + return new ReadableStreamSource(src); + } + return src ?? null; + } + function createInput(src) { + const source = normalizeSource(src); + if (!source) + return null; + return new Input({ + source, + formats: isHlsSource(src) ? HLS_FORMATS : ALL_FORMATS + }); + } + async function resolveDuration({ input, videoTrack, audioTrack }) { + const tracks = [videoTrack, audioTrack].filter(Boolean); + const referenceTrack = videoTrack || audioTrack; + const isLive = Boolean(referenceTrack && await referenceTrack.isLive()); + let duration = Number.NaN; + if (tracks.length > 0) { + duration = await input.getDurationFromMetadata(tracks, { skipLiveWait: true }); + if (duration === null && !isLive) { + duration = await input.computeDuration(tracks, { skipLiveWait: true }); + } + } + return isLive ? Number.POSITIVE_INFINITY : duration ?? Number.NaN; + } + async function selectPlaybackTracks(input, src) { + const videoTrack = await input.getPrimaryVideoTrack(); + const audioTrack = videoTrack ? await videoTrack.getPrimaryPairableAudioTrack() : await input.getPrimaryAudioTrack(); + const duration = await resolveDuration({ input, videoTrack, audioTrack }); + return { + input, + videoTrack, + audioTrack, + duration, + isLive: Number.isFinite(duration) ? false : Boolean((videoTrack || audioTrack) && await (videoTrack || audioTrack).isLive()), + isHls: isHlsSource(src), + videoMode: isHlsSource(src) ? "auto" : "manual", + audioMode: isHlsSource(src) ? "auto" : "manual" + }; + } + async function getTrackBitrate(track) { + return await track.getAverageBitrate() ?? await track.getBitrate() ?? 0; + } + async function getHlsState(media) { + if (!media?.isHls || !media.input) + return null; + const [videoTracks, pairableAudioTracks] = await Promise.all([ + media.input.getVideoTracks(), + media.videoTrack ? media.videoTrack.getPairableAudioTracks() : [] + ]); + const [levels, audios] = await Promise.all([ + Promise.all(videoTracks.map(async (track, index) => ({ + id: track.id, + track, + index, + name: await track.getName(), + height: await track.getDisplayHeight(), + bitrate: await getTrackBitrate(track) + }))), + Promise.all(pairableAudioTracks.map(async (track, index) => { + const name = await track.getName(); + const language = await track.getLanguageCode(); + return { + id: track.id, + track, + index, + name, + lang: language, + language, + bitrate: await getTrackBitrate(track) + }; + })) + ]); + return { + levels, + audios, + currentLevel: media.videoTrack ? levels.find((item) => item.id === media.videoTrack.id) ?? null : null, + currentAudio: media.audioTrack ? audios.find((item) => item.id === media.audioTrack.id) ?? null : null, + videoMode: media.videoMode ?? "auto", + audioMode: media.audioMode ?? "auto" + }; + } class VideoEngine { constructor({ canvas, @@ -14702,18 +21558,8 @@ var artplayerProxyMediabunny = (function() { this.posterDrawn = false; this.isFetching = false; } - normalizeSource(src) { - if (typeof src === "string") - return new UrlSource(src); - if (src instanceof Blob) - return new BlobSource(src); - if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { - return new ReadableStreamSource(src); - } - return src; - } async preflight(url) { - if (!this.preflightRange || typeof url !== "string") + if (!this.preflightRange || typeof url !== "string" || isHlsSource(url)) return true; try { const res = await fetch(url, { method: "HEAD" }); @@ -14748,26 +21594,14 @@ var artplayerProxyMediabunny = (function() { clear() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); } - async load(src, onMetadata) { - const id = ++this.asyncId; + async load(media, onMetadata) { + ++this.asyncId; await this.stopIterator(); this.clear(); this.posterDrawn = false; - if (!await this.preflight(src)) - return; - const source = this.normalizeSource(src); - if (!source) { - this.drawPoster(); - return; - } - this.input = new Input({ - source, - formats: ALL_FORMATS - }); - this.duration = await this.input.computeDuration(); - if (id !== this.asyncId) - return; - const videoTrack = await this.input.getPrimaryVideoTrack(); + const { input, videoTrack, duration } = media; + this.input = input; + this.duration = duration; if (!videoTrack) { this.handleNoVideoTrack(); onMetadata?.(); @@ -14810,7 +21644,6 @@ var artplayerProxyMediabunny = (function() { this.nextFrame = second; if (first) { this.ctx.drawImage(first.canvas, 0, 0); - this.events.emit("loadeddata"); } else { this.drawPoster(); } @@ -14903,8 +21736,8 @@ var artplayerProxyMediabunny = (function() { this.stop(); this.stopIterator(); this.posterDrawn = false; - this.input = null; this.videoSink = null; + this.input = null; } } class MediaBunnyEngine { @@ -14929,6 +21762,8 @@ var artplayerProxyMediabunny = (function() { this.error = null; this.seeking = false; this.loadSeq = 0; + this.input = null; + this.media = null; events.addEventListener?.("ended", () => { this.ended = true; this.paused = true; @@ -14937,6 +21772,7 @@ var artplayerProxyMediabunny = (function() { async load(src) { const id = ++this.loadSeq; this.pause(); + this.disposeInput(); this.ended = false; this.error = null; this.networkState = 2; @@ -14960,8 +21796,24 @@ var artplayerProxyMediabunny = (function() { } } async performLoad(src, id) { - let videoMetadataLoaded = false; - let audioMetadataLoaded = false; + if (!await this.video.preflight(src)) + return; + const input = createInput(src); + if (!input) { + this.video.handleNoVideoTrack(); + this.audio.handleNoAudioTrack(); + return; + } + const media = await selectPlaybackTracks(input, src); + if (id !== this.loadSeq) { + input.dispose(); + return; + } + this.disposeInput(); + this.input = input; + this.media = media; + let videoMetadataLoaded = !media.videoTrack; + let audioMetadataLoaded = !media.audioTrack; const checkMetadata = () => { if (videoMetadataLoaded && audioMetadataLoaded) { this.readyState = 1; @@ -14972,13 +21824,13 @@ var artplayerProxyMediabunny = (function() { }; try { await Promise.all([ - this.video.load(src, () => { + this.video.load(media, () => { if (id !== this.loadSeq) return; videoMetadataLoaded = true; checkMetadata(); }), - this.audio.load(src, () => { + this.audio.load(media, () => { if (id !== this.loadSeq) return; audioMetadataLoaded = true; @@ -15007,6 +21859,95 @@ var artplayerProxyMediabunny = (function() { setTimeout(() => reject(new Error("Load timeout")), ms); }); } + disposeInput() { + this.input?.dispose(); + this.input = null; + this.media = null; + } + async replaceTracks({ videoTrack, audioTrack, videoMode, audioMode }) { + if (!this.media) + return; + const nextMedia = { + ...this.media, + videoTrack, + audioTrack, + videoMode, + audioMode + }; + const shouldResume = !this.paused; + const currentTime = this.currentTime; + this.pause(); + this.ended = false; + this.seeking = true; + this.events.emit("seeking"); + this.events.emit("waiting"); + nextMedia.duration = await resolveDuration(nextMedia); + this.media = nextMedia; + await Promise.all([ + this.video.load(nextMedia), + this.audio.load(nextMedia) + ]); + await Promise.all([ + this.video.seek(currentTime), + this.audio.seek(currentTime) + ]); + this.readyState = 4; + this.networkState = 1; + this.seeking = false; + this.events.emit("loadedmetadata"); + this.events.emit("durationchange"); + this.events.emit("progress"); + this.events.emit("loadeddata"); + this.events.emit("canplay"); + this.events.emit("canplaythrough"); + this.events.emit("seeked"); + if (shouldResume) { + await this.play(); + } + } + async selectHlsQuality(value) { + if (!this.media?.isHls || !this.input) + return; + const videoTracks = await this.input.getVideoTracks(); + const videoTrack = value === "auto" ? await this.input.getPrimaryVideoTrack() : videoTracks.find((track) => track.id === value) ?? this.media.videoTrack; + if (!videoTrack) + return; + let audioTrack = this.media.audioTrack; + let audioMode = this.media.audioMode; + if (!audioTrack || !videoTrack.canBePairedWith(audioTrack)) { + audioTrack = await videoTrack.getPrimaryPairableAudioTrack(); + audioMode = "auto"; + } + await this.replaceTracks({ + videoTrack, + audioTrack, + videoMode: value === "auto" ? "auto" : "manual", + audioMode + }); + } + async selectHlsAudio(value) { + if (!this.media?.isHls || !this.input) + return; + const audioTracks = await this.input.getAudioTracks(); + const audioTrack = value === "auto" ? this.media.videoTrack ? await this.media.videoTrack.getPrimaryPairableAudioTrack() : await this.input.getPrimaryAudioTrack() : audioTracks.find((track) => track.id === value) ?? this.media.audioTrack; + if (!audioTrack) + return; + let videoTrack = this.media.videoTrack; + let videoMode = this.media.videoMode; + if (!videoTrack || !audioTrack.canBePairedWith(videoTrack)) { + videoTrack = await audioTrack.getPrimaryPairableVideoTrack(); + videoMode = "auto"; + } + await this.replaceTracks({ + videoTrack, + audioTrack, + videoMode, + audioMode: value === "auto" ? "auto" : "manual" + }); + } + getHlsState() { + return getHlsState(this.media); + } async play() { if (!this.paused) return; @@ -15054,6 +21995,7 @@ var artplayerProxyMediabunny = (function() { } destroy() { this.pause(); + this.disposeInput(); this.audio.destroy(); this.video.destroy(); } @@ -15062,7 +22004,7 @@ var artplayerProxyMediabunny = (function() { return this.audio.currentTime; } get duration() { - return this.audio.duration || this.video.duration; + return this.media?.duration ?? this.audio.duration ?? this.video.duration; } get videoWidth() { return this.video.width; @@ -15215,6 +22157,15 @@ var artplayerProxyMediabunny = (function() { if (this._src) this.engine.load(this._src); } + getM3u8State() { + return this.engine.getHlsState(); + } + switchM3u8Quality(value) { + return this.engine.selectHlsQuality(value); + } + switchM3u8Audio(value) { + return this.engine.selectHlsAudio(value); + } // Video dimensions get videoWidth() { return this.engine.videoWidth; @@ -15325,6 +22276,7 @@ var artplayerProxyMediabunny = (function() { ctx, option }); + art.mediabunny = shim; const originalCanvasMethods = {}; for (const prop in canvas) { if (typeof canvas[prop] === "function") { @@ -15367,7 +22319,9 @@ var artplayerProxyMediabunny = (function() { } art.on("resize", resize); art.on("video:loadedmetadata", resize); + setupM3u8Controls({ art, shim, option }); art.on("destroy", () => { + delete art.mediabunny; shim.destroy(); }); return canvas; diff --git a/packages/artplayer-proxy-mediabunny/README.md b/packages/artplayer-proxy-mediabunny/README.md index 8b83aa4ed..be1fd5ee1 100644 --- a/packages/artplayer-proxy-mediabunny/README.md +++ b/packages/artplayer-proxy-mediabunny/README.md @@ -1,6 +1,6 @@ # artplayer-proxy-mediabunny -mediabunny proxy for ArtPlayer +mediabunny proxy for ArtPlayer, including `m3u8` playback through Mediabunny's HLS input support. ## Demo diff --git a/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.js b/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.js index d783a9953..d2213fb12 100644 --- a/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.js +++ b/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.js @@ -1,7 +1,7 @@ /*! - * artplayer-proxy-mediabunny.js v1.1.0 + * artplayer-proxy-mediabunny.js v1.2.0 * Github: https://github.com/zhw2590582/ArtPlayer * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";class e{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const r=this.listeners.get(e);if(!r)return;const i=r.indexOf(t);i>=0&&r.splice(i,1)}emit(e,t){const r=new Event(e);r.detail=t;const i=this.listeners.get(e);i&&i.forEach(e=>e(r))}}function t(e){if(!e)throw new Error("Assertion failed.")}const r=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},i=e=>e&&e[e.length-1];class a{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){const e=Math.floor(this.pos/8),t=this.bytes[e]??0,r=7-(7&this.pos),i=(t&1<>r;return this.pos++,i}readBits(e){if(1===e)return this.readBit();let t=0;for(let r=0;r>r-i-1<{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<{const t=s(e);return 0===(1&t)?-(t>>1):t+1>>1},o=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),c=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),l=new TextDecoder,d=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),u={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},h=d(u),m={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},f=d(m),p={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},g=d(p),k=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class b{constructor(){this.currentPromise=Promise.resolve()}async acquire(){let e;const t=new Promise(t=>{e=t}),r=this.currentPromise;return this.currentPromise=t,await r,e}}const T=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),y=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,w=(e,t,r)=>{let i=0,a=e.length-1,s=-1;for(;i<=a;){const n=i+a>>1,o=r(e[n]);o===t?(s=n,a=n-1):o{let i=0,a=e.length-1,s=-1;for(;i<=a;){const n=i+(a-i+1)/2|0;r(e[n])<=t?(s=n,i=n+1):a=n-1}return s},I=(e,t,r)=>{const i=S(e,r(t),r);e.splice(i+1,0,t)},v=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},P=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return e[r]},x=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return r;return-1},C=e=>{throw new Error(`Unexpected value: ${e}`)},_=(e,t,r)=>{const i=e.getUint8(t),a=e.getUint8(t+1),s=e.getUint8(t+2);return r?i|a<<8|s<<16:i<<16|a<<8|s},B=(e,t,r,i)=>{r>>>=0,r&=16777215,e.setUint8(t,r>>>16&255),e.setUint8(t+1,r>>>8&255),e.setUint8(t+2,255&r)},E=(e,t)=>({async next(){const r=await e.next();return r.done?{value:void 0,done:!0}:{value:t(r.value),done:!1}},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),F=(e,t,r)=>Math.max(t,Math.min(r,e)),D="und",A=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},R=/^[a-z]{3}$/,M=e=>R.test(e),N=1e6*(1+Number.EPSILON),z=(e,t)=>{const r={...e,...t};if(e.headers||t.headers){const i=e.headers?O(e.headers):{},a=t.headers?O(t.headers):{},s={...i};Object.entries(a).forEach(([e,t])=>{const r=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());r&&delete s[r],s[e]=t}),r.headers=s}return r},O=e=>{if(e instanceof Headers){const t={};return e.forEach((e,r)=>{t[r]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,r])=>{t[e]=r}),t}return e},L=async(e,t,r,i,a)=>{let s=0;for(;;)try{return await e(t,r)}catch(n){if(a())throw n;s++;const e=i(s,n,t);if(null===e)throw n;if(console.error("Retrying failed fetch. Error:",n),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&await new Promise(t=>setTimeout(t,1e3*e)),a())throw n}};class U{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let V=null;const q=()=>null!==V?V:V=!("undefined"===typeof navigator||!(navigator.vendor?.match(/apple/i)||/AppleWebKit/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)||/\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent)));let H=null;const W=()=>null!==H?H:H="undefined"!==typeof navigator&&navigator.userAgent?.includes("Firefox");let j=null;const K=()=>null!==j?j:j=!("undefined"===typeof navigator||!navigator.vendor?.includes("Google Inc")&&!/Chrome/.test(navigator.userAgent));let $=null;const Q=(e,t)=>-1!==e?e:t,G=(e,t,r,i)=>e<=i&&r<=t,X=e=>{const t=atob(e),r=new Uint8Array(t.length);for(let i=0;i{Symbol.dispose??(Symbol.dispose=Symbol("Symbol.dispose"))},J=e=>"number"===typeof e&&!Number.isNaN(e);class Z{constructor(e,t){if(this.data=e,this.mimeType=t,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("string"!==typeof t)throw new TypeError("mimeType must be a string.")}}class ee{constructor(e,t,r,i){if(this.data=e,this.mimeType=t,this.name=r,this.description=i,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if(void 0!==t&&"string"!==typeof t)throw new TypeError("mimeType, when provided, must be a string.");if(void 0!==r&&"string"!==typeof r)throw new TypeError("name, when provided, must be a string.");if(void 0!==i&&"string"!==typeof i)throw new TypeError("description, when provided, must be a string.")}}const te={default:!0,forced:!1,original:!1,commentary:!1,hearingImpaired:!1,visuallyImpaired:!1},re=["pcm-s16","pcm-s16be","pcm-s24","pcm-s24be","pcm-s32","pcm-s32be","pcm-f32","pcm-f32be","pcm-f64","pcm-f64be","pcm-u8","pcm-s8","ulaw","alaw"],ie=[{maxPictureSize:36864,maxBitrate:2e5,level:10},{maxPictureSize:73728,maxBitrate:8e5,level:11},{maxPictureSize:122880,maxBitrate:18e5,level:20},{maxPictureSize:245760,maxBitrate:36e5,level:21},{maxPictureSize:552960,maxBitrate:72e5,level:30},{maxPictureSize:983040,maxBitrate:12e6,level:31},{maxPictureSize:2228224,maxBitrate:18e6,level:40},{maxPictureSize:2228224,maxBitrate:3e7,level:41},{maxPictureSize:8912896,maxBitrate:6e7,level:50},{maxPictureSize:8912896,maxBitrate:12e7,level:51},{maxPictureSize:8912896,maxBitrate:18e7,level:52},{maxPictureSize:35651584,maxBitrate:18e7,level:60},{maxPictureSize:35651584,maxBitrate:24e7,level:61},{maxPictureSize:35651584,maxBitrate:48e7,level:62}],ae=".01.01.01.01.00",se=".0.110.01.01.01.0",ne=e=>{const{codec:r,codecDescription:a,colorSpace:s,avcCodecInfo:n,hevcCodecInfo:o,vp9CodecInfo:l,av1CodecInfo:d}=e;if("avc"===r){if(t(null!==e.avcType),n){const t=new Uint8Array([n.avcProfileIndication,n.profileCompatibility,n.avcLevelIndication]);return`avc${e.avcType}.${T(t)}`}if(!a||a.byteLength<4)throw new TypeError("AVC decoder description is not provided or is not at least 4 bytes long.");return`avc${e.avcType}.${T(a.subarray(1,4))}`}if("hevc"===r){let e,t,r,i,s,n;if(o)e=o.generalProfileSpace,t=o.generalProfileIdc,r=y(o.generalProfileCompatibilityFlags),i=o.generalTierFlag,s=o.generalLevelIdc,n=[...o.generalConstraintIndicatorFlags];else{if(!a||a.byteLength<23)throw new TypeError("HEVC decoder description is not provided or is not at least 23 bytes long.");const o=c(a),l=o.getUint8(1);e=l>>6&3,t=31&l,r=y(o.getUint32(2)),i=l>>5&1,s=o.getUint8(12),n=[];for(let e=0;e<6;e++)n.push(o.getUint8(6+e))}let l="hev1.";for(l+=["","A","B","C"][e]+t,l+=".",l+=r.toString(16).toUpperCase(),l+=".",l+=0===i?"L":"H",l+=s;n.length>0&&0===n[n.length-1];)n.pop();return n.length>0&&(l+=".",l+=n.map(e=>e.toString(16).toUpperCase()).join(".")),l}if("vp8"===r)return"vp8";if("vp9"===r){if(!l){const t=e.width*e.height;let r=i(ie).level;for(const e of ie)if(t<=e.maxPictureSize){r=e.level;break}return`vp09.00.${r.toString().padStart(2,"0")}.08`}let t=`vp09.${l.profile.toString().padStart(2,"0")}.${l.level.toString().padStart(2,"0")}.${l.bitDepth.toString().padStart(2,"0")}.${l.chromaSubsampling.toString().padStart(2,"0")}`;return t+=`.${l.colourPrimaries.toString().padStart(2,"0")}.${l.transferCharacteristics.toString().padStart(2,"0")}.${l.matrixCoefficients.toString().padStart(2,"0")}.${l.videoFullRangeFlag.toString().padStart(2,"0")}`,t.endsWith(ae)&&(t=t.slice(0,-15)),t}if("av1"===r){if(!d){const t=e.width*e.height;let r=i(ie).level;for(const e of ie)if(t<=e.maxPictureSize){r=e.level;break}return`av01.0.${r.toString().padStart(2,"0")}M.08`}const t=d.profile,r=d.level.toString().padStart(2,"0"),a=d.tier?"H":"M",n=d.bitDepth.toString().padStart(2,"0"),o=d.monochrome?"1":"0",c=100*d.chromaSubsamplingX+10*d.chromaSubsamplingY+1*(d.chromaSubsamplingX&&d.chromaSubsamplingY?d.chromaSamplePosition:0),l=s?.primaries?u[s.primaries]:1,h=s?.transfer?m[s.transfer]:1,f=s?.matrix?p[s.matrix]:1,g=s?.fullRange?1:0;let k=`av01.${t}.${r}${a}.${n}`;return k+=`.${o}.${c.toString().padStart(3,"0")}`,k+=`.${l.toString().padStart(2,"0")}`,k+=`.${h.toString().padStart(2,"0")}`,k+=`.${f.toString().padStart(2,"0")}`,k+=`.${g}`,k.endsWith(se)&&(k=k.slice(0,-17)),k}throw new TypeError(`Unhandled codec '${r}'.`)},oe=e=>{const{codec:t,codecDescription:r,aacCodecInfo:i}=e;if("aac"===t){if(!i)throw new TypeError("AAC codec info must be provided.");if(i.isMpeg2)return"mp4a.67";return`mp4a.40.${de(r).objectType}`}if("mp3"===t)return"mp3";if("opus"===t)return"opus";if("vorbis"===t)return"vorbis";if("flac"===t)return"flac";if(t&&re.includes(t))return t;throw new TypeError(`Unhandled codec '${t}'.`)},ce=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350],le=[-1,1,2,3,4,5,6,8],de=e=>{if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");const t=new a(e);let r=t.readBits(5);31===r&&(r=32+t.readBits(6));const i=t.readBits(4);let s=null;15===i?s=t.readBits(24):i=1&&n<=7&&(o=le[n]),{objectType:r,frequencyIndex:i,sampleRate:s,channelConfiguration:n,numberOfChannels:o}},ue=48e3,he=/^pcm-([usf])(\d+)+(be)?$/,me=e=>{if(t(re.includes(e)),"ulaw"===e)return{dataType:"ulaw",sampleSize:1,littleEndian:!0,silentValue:255};if("alaw"===e)return{dataType:"alaw",sampleSize:1,littleEndian:!0,silentValue:213};const r=he.exec(e);let i;t(r),i="u"===r[1]?"unsigned":"s"===r[1]?"signed":"float";return{dataType:i,sampleSize:Number(r[2])/8,littleEndian:"be"!==r[3],silentValue:"pcm-u8"===e?128:0}};var fe,pe,ge,ke;(pe=fe||(fe={}))[pe.IDR=5]="IDR",pe[pe.SEI=6]="SEI",pe[pe.SPS=7]="SPS",pe[pe.PPS=8]="PPS",pe[pe.SPS_EXT=13]="SPS_EXT",(ke=ge||(ge={}))[ke.RASL_N=8]="RASL_N",ke[ke.RASL_R=9]="RASL_R",ke[ke.BLA_W_LP=16]="BLA_W_LP",ke[ke.RSV_IRAP_VCL23=23]="RSV_IRAP_VCL23",ke[ke.VPS_NUT=32]="VPS_NUT",ke[ke.SPS_NUT=33]="SPS_NUT",ke[ke.PPS_NUT=34]="PPS_NUT",ke[ke.PREFIX_SEI_NUT=39]="PREFIX_SEI_NUT",ke[ke.SUFFIX_SEI_NUT=40]="SUFFIX_SEI_NUT";const be=e=>{const t=[];let r=0;for(;r0&&i>r){const a=e.subarray(r,i);a.length>0&&t.push(a)}r=i+a}if(r0&&t.push(i)}return t},Te=(e,r)=>{const i=[];let a=0;const s=new DataView(e.buffer,e.byteOffset,e.byteLength);for(;a+r<=e.length;){let n;1===r?n=s.getUint8(a):2===r?n=s.getUint16(a,!1):3===r?n=_(s,a,!1):4===r?n=s.getUint32(a,!1):(C(r),t(!1)),a+=r;const o=e.subarray(a,a+n);i.push(o),a+=n}return i},ye=e=>{const t=[],r=e.length;for(let i=0;i{if(t.description){const r=3&o(t.description)[4];return Te(e,r+1)}return be(e)},Ie=(e,t)=>{if(t.description){return((e,t)=>{const r=e.reduce((e,r)=>e+t+r.byteLength,0),i=new Uint8Array(r);let a=0;for(const s of e){const e=new DataView(i.buffer,i.byteOffset,i.byteLength);switch(t){case 1:e.setUint8(a,s.byteLength);break;case 2:e.setUint16(a,s.byteLength,!1);break;case 3:B(e,a,s.byteLength);break;case 4:e.setUint32(a,s.byteLength,!1)}a+=t,i.set(s,a),a+=s.byteLength}return i})(e,(3&o(t.description)[4])+1)}return(e=>{const t=e.reduce((e,t)=>e+we.byteLength+t.byteLength,0),r=new Uint8Array(t);let i=0;for(const a of e)r.set(we,i),i+=we.byteLength,r.set(a,i),i+=a.byteLength;return r})(e)},ve=e=>31&e[0],Pe=e=>{try{const r=be(e),i=r.filter(e=>ve(e)===fe.SPS),a=r.filter(e=>ve(e)===fe.PPS),s=r.filter(e=>ve(e)===fe.SPS_EXT);if(0===i.length)return null;if(0===a.length)return null;const n=i[0],o=xe(n);t(null!==o);const c=100===o.profileIdc||110===o.profileIdc||122===o.profileIdc||144===o.profileIdc;return{configurationVersion:1,avcProfileIndication:o.profileIdc,profileCompatibility:o.constraintFlags,avcLevelIndication:o.levelIdc,lengthSizeMinusOne:3,sequenceParameterSets:i,pictureParameterSets:a,chromaFormat:c?o.chromaFormatIdc:null,bitDepthLumaMinus8:c?o.bitDepthLumaMinus8:null,bitDepthChromaMinus8:c?o.bitDepthChromaMinus8:null,sequenceParameterSetExt:c?s:null}}catch(r){return console.error("Error building AVC Decoder Configuration Record:",r),null}},xe=e=>{try{const t=new a(ye(e));t.skipBits(1),t.skipBits(2);if(7!==t.readBits(5))return null;const r=t.readAlignedByte(),i=t.readAlignedByte(),o=t.readAlignedByte();s(t);let c=null,l=null,d=null;if(100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r){c=s(t),3===c&&t.skipBits(1),l=s(t),d=s(t),t.skipBits(1);if(t.readBits(1))for(let e=0;e<(3!==c?8:12);e++){if(t.readBits(1)){const r=e<6?16:64;let i=8,a=8;for(let e=0;e{if(t.description){const r=3&o(t.description)[21];return Te(e,r+1)}return be(e)},_e=e=>e[0]>>1&63,Be=e=>{try{const t=be(e),r=t.filter(e=>_e(e)===ge.VPS_NUT),i=t.filter(e=>_e(e)===ge.SPS_NUT),o=t.filter(e=>_e(e)===ge.PPS_NUT),c=t.filter(e=>_e(e)===ge.PREFIX_SEI_NUT||_e(e)===ge.SUFFIX_SEI_NUT);if(0===i.length||0===o.length)return null;const l=i[0],d=new a(ye(l));d.skipBits(16),d.readBits(4);const u=d.readBits(3),h=d.readBits(1),{general_profile_space:m,general_tier_flag:f,general_profile_idc:p,general_profile_compatibility_flags:g,general_constraint_indicator_flags:k,general_level_idc:b}=Ee(d,u);s(d);const T=s(d);3===T&&d.skipBits(1),s(d),s(d),d.readBits(1)&&(s(d),s(d),s(d),s(d));const y=s(d),w=s(d);s(d);const S=d.readBits(1);for(let e=S?0:u;e<=u;e++)s(d),s(d),s(d);s(d),s(d),s(d),s(d),s(d),s(d),d.readBits(1)&&d.readBits(1)&&Fe(d),d.skipBits(1),d.skipBits(1),d.readBits(1)&&(d.skipBits(4),d.skipBits(4),s(d),s(d),d.skipBits(1));const I=s(d);if(De(d,I),d.readBits(1)){const e=s(d);for(let t=0;t0){const e=o[0],t=new a(ye(e));t.skipBits(16),s(t),s(t),t.skipBits(1),t.skipBits(1),t.skipBits(3),t.skipBits(1),t.skipBits(1),s(t),s(t),n(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&s(t),n(t),n(t),t.skipBits(1),t.skipBits(1),t.skipBits(1),t.skipBits(1);const r=t.readBits(1),i=t.readBits(1);P=r||i?r&&!i?2:!r&&i?3:0:0}const x=[...r.length?[{arrayCompleteness:1,nalUnitType:ge.VPS_NUT,nalUnits:r}]:[],...i.length?[{arrayCompleteness:1,nalUnitType:ge.SPS_NUT,nalUnits:i}]:[],...o.length?[{arrayCompleteness:1,nalUnitType:ge.PPS_NUT,nalUnits:o}]:[],...c.length?[{arrayCompleteness:1,nalUnitType:_e(c[0]),nalUnits:c}]:[]];return{configurationVersion:1,generalProfileSpace:m,generalTierFlag:f,generalProfileIdc:p,generalProfileCompatibilityFlags:g,generalConstraintIndicatorFlags:k,generalLevelIdc:b,minSpatialSegmentationIdc:v,parallelismType:P,chromaFormatIdc:T,bitDepthLumaMinus8:y,bitDepthChromaMinus8:w,avgFrameRate:0,constantFrameRate:0,numTemporalLayers:u+1,temporalIdNested:h,lengthSizeMinusOne:3,arrays:x}}catch(t){return console.error("Error building HEVC Decoder Configuration Record:",t),null}},Ee=(e,t)=>{const r=e.readBits(2),i=e.readBits(1),a=e.readBits(5);let s=0;for(let d=0;d<32;d++)s=s<<1|e.readBits(1);const n=new Uint8Array(6);for(let d=0;d<6;d++)n[d]=e.readBits(8);const o=e.readBits(8),c=[],l=[];for(let d=0;d0)for(let d=t;d<8;d++)e.skipBits(2);for(let d=0;d{for(let t=0;t<4;t++)for(let r=0;r<(3===t?2:6);r++){if(e.readBits(1)){const r=Math.min(64,1<<4+(t<<1));t>1&&n(e);for(let t=0;t{const r=[];for(let i=0;i{let a=0,n=0,o=0;if(0!==t&&(n=e.readBits(1)),n){if(t===r){o=t-(s(e)+1)}else o=t-1;e.readBits(1),s(e);const n=i[o]??0;for(let t=0;t<=n;t++){e.readBits(1)||e.readBits(1)}a=i[o]}else{const t=s(e),r=s(e);for(let i=0;i{if(e.readBits(1)){255===e.readBits(8)&&(e.readBits(16),e.readBits(16))}if(e.readBits(1)&&e.readBits(1),e.readBits(1)&&(e.readBits(3),e.readBits(1),e.readBits(1)&&(e.readBits(8),e.readBits(8),e.readBits(8))),e.readBits(1)&&(s(e),s(e)),e.readBits(1),e.readBits(1),e.readBits(1),e.readBits(1)&&(s(e),s(e),s(e),s(e)),e.readBits(1)&&(e.readBits(32),e.readBits(32),e.readBits(1)&&s(e),e.readBits(1)&&Me(e,!0,t)),e.readBits(1)){e.readBits(1),e.readBits(1),e.readBits(1);const t=s(e);return s(e),s(e),s(e),s(e),t}return 0},Me=(e,t,r)=>{let i=!1,a=!1,n=!1;i=1===e.readBits(1),a=1===e.readBits(1),(i||a)&&(n=1===e.readBits(1),n&&(e.readBits(8),e.readBits(5),e.readBits(1),e.readBits(5)),e.readBits(4),e.readBits(4),n&&e.readBits(4),e.readBits(5),e.readBits(5),e.readBits(5));for(let o=0;o<=r;o++){let t=!0;1===e.readBits(1)||(t=1===e.readBits(1));let r=!1;t?s(e):r=1===e.readBits(1);let o=1;if(!r){o=s(e)+1}i&&Ne(e,o,n),a&&Ne(e,o,n)}},Ne=(e,t,r)=>{for(let i=0;i{const t=new a(e);if(2!==t.readBits(2))return null;const r=t.readBits(1),s=(t.readBits(1)<<1)+r;3===s&&t.skipBits(1);if(1===t.readBits(1))return null;if(0!==t.readBits(1))return null;t.skipBits(2);if(4817730!==t.readBits(24))return null;let n=8;if(s>=2){n=t.readBits(1)?12:10}const o=t.readBits(3);let c=0,l=0;if(7!==o){if(l=t.readBits(1),1===s||3===s){const e=t.readBits(1),r=t.readBits(1);c=e||r?e&&!r?2:1:3,t.skipBits(1)}else c=1}else c=3,l=1;const d=(t.readBits(16)+1)*(t.readBits(16)+1);let u=i(ie).level;for(const i of ie)if(d<=i.maxPictureSize){u=i.level;break}return{profile:s,level:u,bitDepth:n,chromaSubsampling:c,videoFullRangeFlag:l,colourPrimaries:2===o?1:1===o?6:2,transferCharacteristics:2===o?1:1===o?6:2,matrixCoefficients:7===o?0:2===o?1:1===o?6:2}},Oe=function*(e){const r=new a(e),i=()=>{let e=0;for(let t=0;t<8;t++){const i=r.readAlignedByte();if(e|=(127&i)<<7*t,!(128&i))break;if(7===t&&128&i)return null}return e>=2**32-1?null:e};for(;r.getBitsLeft()>=8;){r.skipBits(1);const a=r.readBits(4),s=r.readBits(1),n=r.readBits(1);let o;if(r.skipBits(1),s&&r.skipBits(8),n){const e=i();if(null===e)return;o=e}else o=Math.floor(r.getBitsLeft()/8);t(r.pos%8===0),yield{type:a,data:e.subarray(r.pos/8,r.pos/8+o)},r.skipBits(8*o)}},Le=e=>{for(const{type:t,data:r}of Oe(e)){if(1!==t)continue;const e=new a(r),i=e.readBits(3);e.readBits(1);const s=e.readBits(1);let n=0,o=0,c=0;if(s)n=e.readBits(5);else{if(e.readBits(1)){e.skipBits(32),e.skipBits(32);if(e.readBits(1))return null}const t=e.readBits(1);t&&(c=e.readBits(5),e.skipBits(32),e.skipBits(5),e.skipBits(5));const r=e.readBits(5);for(let i=0;i<=r;i++){e.skipBits(12);const r=e.readBits(5);if(0===i&&(n=r),r>7){const t=e.readBits(1);0===i&&(o=t)}if(t){if(e.readBits(1)){const t=c+1;e.skipBits(t),e.skipBits(t),e.skipBits(1)}}e.readBits(1)&&e.skipBits(4)}}const l=e.readBits(4),d=e.readBits(4),u=l+1;e.skipBits(u);const h=d+1;e.skipBits(h);let m=0;if(m=s?0:e.readBits(1),m&&(e.skipBits(4),e.skipBits(3)),e.skipBits(1),e.skipBits(1),e.skipBits(1),!s){e.skipBits(1),e.skipBits(1),e.skipBits(1),e.skipBits(1);const t=e.readBits(1);t&&(e.skipBits(1),e.skipBits(1));let r=0;if(r=e.readBits(1)?2:e.readBits(1),r>0){e.readBits(1)||e.skipBits(1)}t&&e.skipBits(3)}e.skipBits(1),e.skipBits(1),e.skipBits(1);const f=e.readBits(1);let p=8;if(2===i&&f){p=e.readBits(1)?12:10}else i<=2&&(p=f?10:8);let g=0;1!==i&&(g=e.readBits(1));let k=1,b=1,T=0;return g||(0===i?(k=1,b=1):1===i?(k=0,b=0):12===p&&(k=e.readBits(1),k&&(b=e.readBits(1))),k&&b&&(T=e.readBits(2))),{profile:i,level:n,tier:o,bitDepth:p,monochrome:g,chromaSubsamplingX:k,chromaSubsamplingY:b,chromaSamplePosition:T}}return null},Ue=[480,960,1920,2880,480,960,1920,2880,480,960,1920,2880,480,960,480,960,120,240,480,960,120,240,480,960,120,240,480,960,120,240,480,960],Ve=e=>{if(e.length<7)throw new Error("Setup header is too short.");if(5!==e[0])throw new Error("Wrong packet type in Setup header.");if("vorbis"!==String.fromCharCode(...e.slice(1,7)))throw new Error("Invalid packet signature in Setup header.");const t=e.length,r=new Uint8Array(t);for(let a=0;a97;)if(1===i.readBits(1)){s=i.pos;break}if(0===s)throw new Error("Invalid Setup header: framing bit not found.");let n=0,o=!1,c=0;for(;i.getBitsLeft()>=97;){const e=i.pos,t=i.readBits(8),r=i.readBits(16),a=i.readBits(16);if(t>63||0!==r||0!==a){i.pos=e;break}if(i.skipBits(1),n++,n>64)break;i.clone().readBits(6)+1===n&&(o=!0,c=n)}if(!o)throw new Error("Invalid Setup header: mode header not found.");if(c>63)throw new Error(`Unsupported mode count: ${c}.`);const l=c;i.pos=0,i.skipBits(s);const d=Array(l).fill(0);for(let a=l-1;a>=0;a--)i.skipBits(40),d[a]=i.readBits(1);return{modeBlockflags:d}},qe=(e,r,i)=>{switch(e){case"avc":{const e=Se(i,r);let t=e.some(e=>ve(e)===fe.IDR);if(!t&&(!K()||(()=>{if(null!==$)return $;if("undefined"===typeof navigator)return null;const e=/\bChrome\/(\d+)/.exec(navigator.userAgent);return e?$=Number(e[1]):null})()>=144))for(const r of e){if(ve(r)!==fe.SEI)continue;const e=ye(r);let i=1;do{let r=0;for(;;){const t=e[i++];if(void 0===t)break;if(r+=t,t<255)break}let n=0;for(;;){const t=e[i++];if(void 0===t)break;if(n+=t,t<255)break}if(r===6){const r=new a(e);r.pos=8*i;const n=s(r),o=r.readBits(1);if(0===n&&1===o){t=!0;break}}i+=n}while(i{const t=_e(e);return ge.BLA_W_LP<=t&&t<=ge.RSV_IRAP_VCL23})?"key":"delta";case"vp8":return 0===(1&i[0])?"key":"delta";case"vp9":{const e=new a(i);if(2!==e.readBits(2))return null;const t=e.readBits(1);3===(e.readBits(1)<<1)+t&&e.skipBits(1);if(e.readBits(1))return null;return 0===e.readBits(1)?"key":"delta"}case"av1":{let e=!1;for(const{type:t,data:r}of Oe(i))if(1===t){const t=new a(r);t.skipBits(4),e=!!t.readBits(1)}else if(3===t||6===t||7===t){if(e)return"key";const t=new a(r);if(t.readBits(1))return null;return 0===t.readBits(2)?"key":"delta"}return null}default:C(e),t(!1)}};var He,We;(We=He||(He={}))[We.STREAMINFO=0]="STREAMINFO",We[We.VORBIS_COMMENT=4]="VORBIS_COMMENT",We[We.PICTURE=6]="PICTURE";const je=(e,t)=>{var r,i;const a=c(e);let s=0;const n=a.getUint32(s,!0);s+=4;const o=l.decode(e.subarray(s,s+n));s+=n,n>0&&(t.raw??(t.raw={}),(r=t.raw).vendor??(r.vendor=o));const d=a.getUint32(s,!0);s+=4;for(let u=0;u0&&(t.trackNumber??(t.trackNumber=r)),i&&Number.isInteger(i)&&i>0&&(t.tracksTotal??(t.tracksTotal=i))}break;case"TRACKTOTAL":{const e=Number.parseInt(u,10);Number.isInteger(e)&&e>0&&(t.tracksTotal??(t.tracksTotal=e))}break;case"DISCNUMBER":{const e=u.split("/"),r=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(t.discNumber??(t.discNumber=r)),i&&Number.isInteger(i)&&i>0&&(t.discsTotal??(t.discsTotal=i))}break;case"DISCTOTAL":{const e=Number.parseInt(u,10);Number.isInteger(e)&&e>0&&(t.discsTotal??(t.discsTotal=e))}break;case"DATE":{const e=new Date(u);Number.isNaN(e.getTime())||(t.date??(t.date=e))}break;case"GENRE":t.genre??(t.genre=u);break;case"METADATA_BLOCK_PICTURE":{const e=X(u),r=c(e),i=r.getUint32(0,!1),a=r.getUint32(4,!1),s=String.fromCharCode(...e.subarray(8,8+a)),n=r.getUint32(8+a,!1),o=l.decode(e.subarray(12+a,12+a+n)),d=r.getUint32(a+n+28),h=e.subarray(a+n+32,a+n+32+d);t.images??(t.images=[]),t.images.push({data:h,mimeType:s,kind:3===i?"coverFront":4===i?"coverBack":"unknown",name:void 0,description:o||void 0})}}}};class Ke{constructor(e){this.input=e}}const $e=[],Qe=[],Ge=new Uint8Array(0);class Xe{constructor(e,t,r,i,a=-1,s,n){if(this.data=e,this.type=t,this.timestamp=r,this.duration=i,this.sequenceNumber=a,e===Ge&&void 0===s)throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets.");if(void 0===s&&(s=e.byteLength),!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("key"!==t&&"delta"!==t)throw new TypeError('type must be either "key" or "delta".');if(!Number.isFinite(r))throw new TypeError("timestamp must be a number.");if(!Number.isFinite(i)||i<0)throw new TypeError("duration must be a non-negative number.");if(!Number.isFinite(a))throw new TypeError("sequenceNumber must be a number.");if(!Number.isInteger(s)||s<0)throw new TypeError("byteLength must be a non-negative integer.");if(void 0!==n&&("object"!==typeof n||!n))throw new TypeError("sideData, when provided, must be an object.");if(void 0!==n?.alpha&&!(n.alpha instanceof Uint8Array))throw new TypeError("sideData.alpha, when provided, must be a Uint8Array.");if(void 0!==n?.alphaByteLength&&(!Number.isInteger(n.alphaByteLength)||n.alphaByteLength<0))throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer.");this.byteLength=s,this.sideData=n??{},this.sideData.alpha&&void 0===this.sideData.alphaByteLength&&(this.sideData.alphaByteLength=this.sideData.alpha.byteLength)}get isMetadataOnly(){return this.data===Ge}get microsecondTimestamp(){return Math.trunc(N*this.timestamp)}get microsecondDuration(){return Math.trunc(N*this.duration)}toEncodedVideoChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}alphaToEncodedVideoChunk(e=this.type){if(!this.sideData.alpha)throw new TypeError("This packet does not contain alpha side data.");if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.sideData.alpha,type:e,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}toEncodedAudioChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to an audio chunk.");if("undefined"===typeof EncodedAudioChunk)throw new Error("Your browser does not support EncodedAudioChunk.");return new EncodedAudioChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}static fromEncodedChunk(e,t){if(!(e instanceof EncodedVideoChunk||e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk.");const r=new Uint8Array(e.byteLength);return e.copyTo(r),new Xe(r,e.type,e.timestamp/1e6,(e.duration??0)/1e6,void 0,void 0,t)}clone(e){if(void 0!==e&&("object"!==typeof e||null===e))throw new TypeError("options, when provided, must be an object.");if(void 0!==e?.timestamp&&!Number.isFinite(e.timestamp))throw new TypeError("options.timestamp, when provided, must be a number.");if(void 0!==e?.duration&&!Number.isFinite(e.duration))throw new TypeError("options.duration, when provided, must be a number.");return new Xe(this.data,this.type,e?.timestamp??this.timestamp,e?.duration??this.duration,this.sequenceNumber,this.byteLength)}}Y();let Ye=-1/0,Je=-1/0,Ze=null;"undefined"!==typeof FinalizationRegistry&&(Ze=new FinalizationRegistry(e=>{const t=Date.now();"video"===e.type?(t-Ye>=1e3&&(console.error("A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them."),Ye=t),"undefined"!==typeof VideoFrame&&e.data instanceof VideoFrame&&e.data.close()):(t-Je>=1e3&&(console.error("An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them."),Je=t),"undefined"!==typeof AudioData&&e.data instanceof AudioData&&e.data.close())}));const et=["I420","I420P10","I420P12","I420A","I420AP10","I420AP12","I422","I422P10","I422P12","I422A","I422AP10","I422AP12","I444","I444P10","I444P12","I444A","I444AP10","I444AP12","NV12","RGBA","RGBX","BGRA","BGRX"],tt=new Set(et);class rt{get displayWidth(){return this.rotation%180===0?this.codedWidth:this.codedHeight}get displayHeight(){return this.rotation%180===0?this.codedHeight:this.codedWidth}get microsecondTimestamp(){return Math.trunc(N*this.timestamp)}get microsecondDuration(){return Math.trunc(N*this.duration)}get hasAlpha(){return this.format&&this.format.includes("A")}constructor(e,r){if(this._closed=!1,e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e)){if(!r||"object"!==typeof r)throw new TypeError("init must be an object.");if(void 0===r.format||!tt.has(r.format))throw new TypeError("init.format must be one of: "+et.join(", "));if(!Number.isInteger(r.codedWidth)||r.codedWidth<=0)throw new TypeError("init.codedWidth must be a positive integer.");if(!Number.isInteger(r.codedHeight)||r.codedHeight<=0)throw new TypeError("init.codedHeight must be a positive integer.");if(void 0!==r.rotation&&![0,90,180,270].includes(r.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(r.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==r.duration&&(!Number.isFinite(r.duration)||r.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");this._data=o(e).slice(),this._layout=r.layout??ct(r.format,r.codedWidth,r.codedHeight),this.format=r.format,this.codedWidth=r.codedWidth,this.codedHeight=r.codedHeight,this.rotation=r.rotation??0,this.timestamp=r.timestamp,this.duration=r.duration??0,this.colorSpace=new it(r.colorSpace)}else if("undefined"!==typeof VideoFrame&&e instanceof VideoFrame){if(void 0!==r?.rotation&&![0,90,180,270].includes(r.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(void 0!==r?.timestamp&&!Number.isFinite(r?.timestamp))throw new TypeError("init.timestamp, when provided, must be a number.");if(void 0!==r?.duration&&(!Number.isFinite(r.duration)||r.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");this._data=e,this._layout=null,this.format=e.format,this.codedWidth=e.displayWidth,this.codedHeight=e.displayHeight,this.rotation=r?.rotation??0,this.timestamp=r?.timestamp??e.timestamp/1e6,this.duration=r?.duration??(e.duration??0)/1e6,this.colorSpace=new it(e.colorSpace)}else{if(!("undefined"!==typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!==typeof SVGImageElement&&e instanceof SVGImageElement||"undefined"!==typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!==typeof HTMLVideoElement&&e instanceof HTMLVideoElement||"undefined"!==typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!==typeof OffscreenCanvas&&e instanceof OffscreenCanvas))throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource.");{if(!r||"object"!==typeof r)throw new TypeError("init must be an object.");if(void 0!==r.rotation&&![0,90,180,270].includes(r.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(r.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==r.duration&&(!Number.isFinite(r.duration)||r.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if("undefined"!==typeof VideoFrame)return new rt(new VideoFrame(e,{timestamp:Math.trunc(r.timestamp*N),duration:Math.trunc((r.duration??0)*N)||void 0}),r);let i=0,a=0;if("naturalWidth"in e?(i=e.naturalWidth,a=e.naturalHeight):"videoWidth"in e?(i=e.videoWidth,a=e.videoHeight):"width"in e&&(i=Number(e.width),a=Number(e.height)),!i||!a)throw new TypeError("Could not determine dimensions.");const s=new OffscreenCanvas(i,a),n=s.getContext("2d",{alpha:W(),willReadFrequently:!0});t(n),n.drawImage(e,0,0),this._data=s,this._layout=null,this.format="RGBX",this.codedWidth=i,this.codedHeight=a,this.rotation=r.rotation??0,this.timestamp=r.timestamp,this.duration=r.duration??0,this.colorSpace=new it({matrix:"rgb",primaries:"bt709",transfer:"iec61966-2-1",fullRange:!0})}}Ze?.register(this,{type:"video",data:this._data},this)}clone(){if(this._closed)throw new Error("VideoSample is closed.");return t(null!==this._data),at(this._data)?new rt(this._data.clone(),{timestamp:this.timestamp,duration:this.duration,rotation:this.rotation}):this._data instanceof Uint8Array?(t(this._layout),new rt(this._data,{format:this.format,layout:this._layout,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation})):new rt(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation})}close(){this._closed||(Ze?.unregister(this),at(this._data)?this._data.close():this._data=null,this._closed=!0)}allocationSize(e={}){if(ot(e),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot get allocation size when format is null. Sorry!");if(t(null!==this._data),!at(this._data)&&(e.colorSpace||e.format&&e.format!==this.format||e.layout||e.rect)){const t=this.toVideoFrame(),r=t.allocationSize(e);return t.close(),r}return at(this._data)?this._data.allocationSize(e):this._data instanceof Uint8Array?this._data.byteLength:this.codedWidth*this.codedHeight*4}async copyTo(e,r={}){if(!k(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(ot(r),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot copy video sample data when format is null. Sorry!");if(t(null!==this._data),!at(this._data)&&(r.colorSpace||r.format&&r.format!==this.format||r.layout||r.rect)){const t=this.toVideoFrame(),i=await t.copyTo(e,r);return t.close(),i}if(at(this._data))return this._data.copyTo(e,r);if(this._data instanceof Uint8Array){t(this._layout);return o(e).set(this._data),this._layout}{const r=this._data.getContext("2d");t(r);const i=r.getImageData(0,0,this.codedWidth,this.codedHeight);return o(e).set(i.data),[{offset:0,stride:4*this.codedWidth}]}}toVideoFrame(){if(this._closed)throw new Error("VideoSample is closed.");return t(null!==this._data),at(this._data)?new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0}):this._data instanceof Uint8Array?new VideoFrame(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0,colorSpace:this.colorSpace}):new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0})}draw(e,t,r,i,a,s,n,o,c){let l=0,d=0,u=this.displayWidth,h=this.displayHeight,m=0,f=0,p=this.displayWidth,g=this.displayHeight;if(void 0!==s?(l=t,d=r,u=i,h=a,m=s,f=n,void 0!==o?(p=o,g=c):(p=u,g=h)):(m=t,f=r,void 0!==i&&(p=i,g=a)),!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!Number.isFinite(l))throw new TypeError("sx must be a number.");if(!Number.isFinite(d))throw new TypeError("sy must be a number.");if(!Number.isFinite(u)||u<0)throw new TypeError("sWidth must be a non-negative number.");if(!Number.isFinite(h)||h<0)throw new TypeError("sHeight must be a non-negative number.");if(!Number.isFinite(m))throw new TypeError("dx must be a number.");if(!Number.isFinite(f))throw new TypeError("dy must be a number.");if(!Number.isFinite(p)||p<0)throw new TypeError("dWidth must be a non-negative number.");if(!Number.isFinite(g)||g<0)throw new TypeError("dHeight must be a non-negative number.");if(this._closed)throw new Error("VideoSample is closed.");({sx:l,sy:d,sWidth:u,sHeight:h}=this._rotateSourceRegion(l,d,u,h,this.rotation));const k=this.toCanvasImageSource();e.save();const b=m+p/2,T=f+g/2;e.translate(b,T),e.rotate(this.rotation*Math.PI/180);const y=this.rotation%180===0?1:p/g;e.scale(1/y,y),e.drawImage(k,l,d,u,h,-p/2,-g/2,p,g),e.restore()}drawWithFit(e,t){if(!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!["fill","contain","cover"].includes(t.fit))throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270.");void 0!==t.crop&&nt(t.crop,"options.");const r=e.canvas.width,i=e.canvas.height,a=t.rotation??this.rotation,[s,n]=a%180===0?[this.codedWidth,this.codedHeight]:[this.codedHeight,this.codedWidth];let o,c,l,d;t.crop&&st(t.crop,s,n);const{sx:u,sy:h,sWidth:m,sHeight:f}=this._rotateSourceRegion(t.crop?.left??0,t.crop?.top??0,t.crop?.width??s,t.crop?.height??n,a);if("fill"===t.fit)o=0,c=0,l=r,d=i;else{const[e,a]=t.crop?[t.crop.width,t.crop.height]:[s,n],u="contain"===t.fit?Math.min(r/e,i/a):Math.max(r/e,i/a);l=e*u,d=a*u,o=(r-l)/2,c=(i-d)/2}e.save();const p=a%180===0?1:l/d;e.translate(r/2,i/2),e.rotate(a*Math.PI/180),e.scale(1/p,p),e.translate(-r/2,-i/2),e.drawImage(this.toCanvasImageSource(),u,h,m,f,o,c,l,d),e.restore()}_rotateSourceRegion(e,t,r,i,a){return 90===a?[e,t,r,i]=[t,this.codedHeight-e-r,i,r]:180===a?[e,t]=[this.codedWidth-e-r,this.codedHeight-t-i]:270===a&&([e,t,r,i]=[this.codedWidth-t-i,e,i,r]),{sx:e,sy:t,sWidth:r,sHeight:i}}toCanvasImageSource(){if(this._closed)throw new Error("VideoSample is closed.");if(t(null!==this._data),this._data instanceof Uint8Array){const e=this.toVideoFrame();return queueMicrotask(()=>e.close()),e}return this._data}setRotation(e){if(![0,90,180,270].includes(e))throw new TypeError("newRotation must be 0, 90, 180, or 270.");this.rotation=e}setTimestamp(e){if(!Number.isFinite(e))throw new TypeError("newTimestamp must be a number.");this.timestamp=e}setDuration(e){if(!Number.isFinite(e)||e<0)throw new TypeError("newDuration must be a non-negative number.");this.duration=e}[Symbol.dispose](){this.close()}}class it{constructor(e){this.primaries=e?.primaries??null,this.transfer=e?.transfer??null,this.matrix=e?.matrix??null,this.fullRange=e?.fullRange??null}toJSON(){return{primaries:this.primaries,transfer:this.transfer,matrix:this.matrix,fullRange:this.fullRange}}}const at=e=>"undefined"!==typeof VideoFrame&&e instanceof VideoFrame,st=(e,r,i)=>{e.left=Math.min(e.left,r),e.top=Math.min(e.top,i),e.width=Math.min(e.width,r-e.left),e.height=Math.min(e.height,i-e.top),t(e.width>=0),t(e.height>=0)},nt=(e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(t+"crop, when provided, must be an object.");if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(t+"crop.left must be a non-negative integer.");if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(t+"crop.top must be a non-negative integer.");if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(t+"crop.width must be a non-negative integer.");if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(t+"crop.height must be a non-negative integer.")},ot=e=>{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.colorSpace&&!["display-p3","srgb"].includes(e.colorSpace))throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");if(void 0!==e.format&&"string"!==typeof e.format)throw new TypeError("options.format, when provided, must be a string.");if(void 0!==e.layout){if(!Array.isArray(e.layout))throw new TypeError("options.layout, when provided, must be an array.");for(const t of e.layout){if(!t||"object"!==typeof t)throw new TypeError("Each entry in options.layout must be an object.");if(!Number.isInteger(t.offset)||t.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(t.stride)||t.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==e.rect){if(!e.rect||"object"!==typeof e.rect)throw new TypeError("options.rect, when provided, must be an object.");if(void 0!==e.rect.x&&(!Number.isInteger(e.rect.x)||e.rect.x<0))throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");if(void 0!==e.rect.y&&(!Number.isInteger(e.rect.y)||e.rect.y<0))throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");if(void 0!==e.rect.width&&(!Number.isInteger(e.rect.width)||e.rect.width<0))throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");if(void 0!==e.rect.height&&(!Number.isInteger(e.rect.height)||e.rect.height<0))throw new TypeError("options.rect.height, when provided, must be a non-negative integer.")}},ct=(e,t,r)=>{const i=lt(e),a=[];let s=0;for(const n of i){const e=Math.ceil(t/n.widthDivisor),i=Math.ceil(r/n.heightDivisor),o=e*n.sampleBytes,c=o*i;a.push({offset:s,stride:o}),s+=c}return a},lt=e=>{const r=(e,t,r,i,a)=>{const s=[{sampleBytes:e,widthDivisor:1,heightDivisor:1},{sampleBytes:t,widthDivisor:r,heightDivisor:i},{sampleBytes:t,widthDivisor:r,heightDivisor:i}];return a&&s.push({sampleBytes:e,widthDivisor:1,heightDivisor:1}),s};switch(e){case"I420":return r(1,1,2,2,!1);case"I420P10":case"I420P12":return r(2,2,2,2,!1);case"I420A":return r(1,1,2,2,!0);case"I420AP10":case"I420AP12":return r(2,2,2,2,!0);case"I422":return r(1,1,2,1,!1);case"I422P10":case"I422P12":return r(2,2,2,1,!1);case"I422A":return r(1,1,2,1,!0);case"I422AP10":case"I422AP12":return r(2,2,2,1,!0);case"I444":return r(1,1,1,1,!1);case"I444P10":case"I444P12":return r(2,2,1,1,!1);case"I444A":return r(1,1,1,1,!0);case"I444AP10":case"I444AP12":return r(2,2,1,1,!0);case"NV12":return[{sampleBytes:1,widthDivisor:1,heightDivisor:1},{sampleBytes:2,widthDivisor:2,heightDivisor:2}];case"RGBA":case"RGBX":case"BGRA":case"BGRX":return[{sampleBytes:4,widthDivisor:1,heightDivisor:1}];default:C(e),t(!1)}},dt=new Set(["f32","f32-planar","s16","s16-planar","s32","s32-planar","u8","u8-planar"]);class ut{get microsecondTimestamp(){return Math.trunc(N*this.timestamp)}get microsecondDuration(){return Math.trunc(N*this.duration)}constructor(e){if(this._closed=!1,gt(e)){if(null===e.format)throw new TypeError("AudioData with null format is not supported.");this._data=e,this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=e.numberOfFrames,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp/1e6,this.duration=e.numberOfFrames/e.sampleRate}else{if(!e||"object"!==typeof e)throw new TypeError("Invalid AudioDataInit: must be an object.");if(!dt.has(e.format))throw new TypeError("Invalid AudioDataInit: invalid format.");if(!Number.isFinite(e.sampleRate)||e.sampleRate<=0)throw new TypeError("Invalid AudioDataInit: sampleRate must be > 0.");if(!Number.isInteger(e.numberOfChannels)||0===e.numberOfChannels)throw new TypeError("Invalid AudioDataInit: numberOfChannels must be an integer > 0.");if(!Number.isFinite(e?.timestamp))throw new TypeError("init.timestamp must be a number.");const t=e.data.byteLength/(ht(e.format)*e.numberOfChannels);if(!Number.isInteger(t))throw new TypeError("Invalid AudioDataInit: data size is not a multiple of frame size.");let r;if(this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=t,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp,this.duration=t/e.sampleRate,e.data instanceof ArrayBuffer)r=new Uint8Array(e.data);else{if(!ArrayBuffer.isView(e.data))throw new TypeError("Invalid AudioDataInit: data is not a BufferSource.");r=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength)}const i=this.numberOfFrames*this.numberOfChannels*ht(this.format);if(r.byteLength=this.numberOfFrames)throw new RangeError("frameOffset out of range");const i=void 0!==e.frameCount?e.frameCount:this.numberOfFrames-r;if(i>this.numberOfFrames-r)throw new RangeError("frameCount out of range");const a=ht(t),s=mt(t);if(s&&e.planeIndex>=this.numberOfChannels)throw new RangeError("planeIndex out of range");if(!s&&0!==e.planeIndex)throw new RangeError("planeIndex out of range");return(s?i:i*this.numberOfChannels)*a}copyTo(e,t){if(!k(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!Number.isInteger(t.planeIndex)||t.planeIndex<0)throw new TypeError("planeIndex must be a non-negative integer.");if(void 0!==t.format&&!dt.has(t.format))throw new TypeError("Invalid format.");if(void 0!==t.frameOffset&&(!Number.isInteger(t.frameOffset)||t.frameOffset<0))throw new TypeError("frameOffset must be a non-negative integer.");if(void 0!==t.frameCount&&(!Number.isInteger(t.frameCount)||t.frameCount<0))throw new TypeError("frameCount must be a non-negative integer.");if(this._closed)throw new Error("AudioSample is closed.");const{planeIndex:r,format:i,frameCount:a,frameOffset:s}=t,n=this.format,o=i??this.format;if(!o)throw new Error("Destination format not determined");const l=this.numberOfFrames,d=this.numberOfChannels,u=s??0;if(u>=l)throw new RangeError("frameOffset out of range");const h=void 0!==a?a:l-u;if(h>l-u)throw new RangeError("frameCount out of range");const m=ht(o),f=mt(o);if(f&&r>=d)throw new RangeError("planeIndex out of range");if(!f&&0!==r)throw new RangeError("planeIndex out of range");const p=(f?h:h*d)*m;if(e.byteLength2&&o!==n?kt(this._data,g,n,o,d,r,u,h):this._data.copyTo(e,{planeIndex:r,frameOffset:u,frameCount:h,format:o});else{const e=this._data,t=c(e),i=ft(n),a=ht(n),s=mt(n);for(let n=0;n0;){const a=Math.min(s,o),c=new Float32Array(r*a);for(let t=0;t0;){const a=Math.min(s,o),l=new Float32Array(r*a);for(let t=0;t{switch(e){case"u8":case"u8-planar":return 1;case"s16":case"s16-planar":return 2;case"s32":case"s32-planar":case"f32":case"f32-planar":return 4;default:throw new Error("Unknown AudioSampleFormat")}},mt=e=>{switch(e){case"u8-planar":case"s16-planar":case"s32-planar":case"f32-planar":return!0;default:return!1}},ft=e=>{switch(e){case"u8":case"u8-planar":return(e,t)=>(e.getUint8(t)-128)/128;case"s16":case"s16-planar":return(e,t)=>e.getInt16(t,!0)/32768;case"s32":case"s32-planar":return(e,t)=>e.getInt32(t,!0)/2147483648;case"f32":case"f32-planar":return(e,t)=>e.getFloat32(t,!0)}},pt=e=>{switch(e){case"u8":case"u8-planar":return(e,t,r)=>e.setUint8(t,F(127.5*(r+1),0,255));case"s16":case"s16-planar":return(e,t,r)=>e.setInt16(t,F(Math.round(32767*r),-32768,32767),!0);case"s32":case"s32-planar":return(e,t,r)=>e.setInt32(t,F(Math.round(2147483647*r),-2147483648,2147483647),!0);case"f32":case"f32-planar":return(e,t,r)=>e.setFloat32(t,r,!0)}},gt=e=>"undefined"!==typeof AudioData&&e instanceof AudioData,kt=(e,t,r,i,a,s,n,o)=>{const l=ft(r),d=pt(i),u=ht(r),h=ht(i),m=mt(r);if(mt(i))if(m){const i=new ArrayBuffer(o*u),a=c(i);e.copyTo(i,{planeIndex:s,frameOffset:n,frameCount:o,format:r});for(let e=0;e{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.metadataOnly&&"boolean"!==typeof e.metadataOnly)throw new TypeError("options.metadataOnly, when defined, must be a boolean.");if(void 0!==e.verifyKeyPackets&&"boolean"!==typeof e.verifyKeyPackets)throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");if(e.verifyKeyPackets&&e.metadataOnly)throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.")},Tt=e=>{if(!J(e))throw new TypeError("timestamp must be a number.")},yt=(e,t,r)=>r.verifyKeyPackets?t.then(async t=>{if(!t||"delta"===t.type)return t;const r=await e.determinePacketType(t);return r&&(t.type=r),t}):t;class wt{constructor(e){if(!(e instanceof At))throw new TypeError("track must be an InputTrack.");this._track=e}getFirstPacket(e={}){if(bt(e),this._track.input._disposed)throw new ea;return yt(this._track,this._track._backing.getFirstPacket(e),e)}getPacket(e,t={}){if(Tt(e),bt(t),this._track.input._disposed)throw new ea;return yt(this._track,this._track._backing.getPacket(e,t),t)}getNextPacket(e,t={}){if(!(e instanceof Xe))throw new TypeError("packet must be an EncodedPacket.");if(bt(t),this._track.input._disposed)throw new ea;return yt(this._track,this._track._backing.getNextPacket(e,t),t)}async getKeyPacket(e,r={}){if(Tt(e),bt(r),this._track.input._disposed)throw new ea;if(!r.verifyKeyPackets)return this._track._backing.getKeyPacket(e,r);const i=await this._track._backing.getKeyPacket(e,r);if(!i)return i;t("key"===i.type);return"delta"===await this._track.determinePacketType(i)?this.getKeyPacket(i.timestamp-1/this._track.timeResolution,r):i}async getNextKeyPacket(e,r={}){if(!(e instanceof Xe))throw new TypeError("packet must be an EncodedPacket.");if(bt(r),this._track.input._disposed)throw new ea;if(!r.verifyKeyPackets)return this._track._backing.getNextKeyPacket(e,r);const i=await this._track._backing.getNextKeyPacket(e,r);if(!i)return i;t("key"===i.type);return"delta"===await this._track.determinePacketType(i)?this.getNextKeyPacket(i,r):i}packets(e,t,r={}){if(void 0!==e&&!(e instanceof Xe))throw new TypeError("startPacket must be an EncodedPacket.");if(void 0!==e&&e.isMetadataOnly&&!r?.metadataOnly)throw new TypeError("startPacket can only be metadata-only if options.metadataOnly is enabled.");if(void 0!==t&&!(t instanceof Xe))throw new TypeError("endPacket must be an EncodedPacket.");if(bt(r),this._track.input._disposed)throw new ea;const i=[];let{promise:a,resolve:s}=v(),{promise:n,resolve:o}=v(),c=!1,l=!1,d=null;const u=[],h=()=>Math.max(2,u.length);(async()=>{let d=e??await this.getFirstPacket(r);for(;d&&!l&&!this._track.input._disposed&&!(t&&d.sequenceNumber>=t?.sequenceNumber);)i.length>h()?(({promise:n,resolve:o}=v()),await n):(i.push(d),s(),({promise:a,resolve:s}=v()),d=await this.getNextPacket(d,r));c=!0,s()})().catch(e=>{d||(d=e,s())});const m=this._track;return{async next(){for(;;){if(m.input._disposed)throw new ea;if(l)return{value:void 0,done:!0};if(d)throw d;if(i.length>0){const e=i.shift(),t=performance.now();for(u.push(t);u.length>0&&t-u[0]>=1e3;)u.shift();return o(),{value:e,done:!1}}if(c)return{value:void 0,done:!0};await a}},return:async()=>(l=!0,o(),s(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}}class St{constructor(e,t){this.onSample=e,this.onError=t}}class It{mediaSamplesInRange(e=0,t=1/0){Tt(e),Tt(t);const r=[];let i=!1,a=null,{promise:s,resolve:n}=v(),{promise:o,resolve:c}=v(),l=!1,d=!1,u=!1,h=null;(async()=>{const m=await this._createDecoder(o=>{c(),o.timestamp>=t&&(d=!0),d?o.close():(a&&(o.timestamp>e?(r.push(a),i=!0):a.close()),o.timestamp>=e&&(r.push(o),i=!0),a=i?null:o,r.length>0&&(n(),({promise:s,resolve:n}=v())))},e=>{h||(h=e,n())}),f=this._createPacketSink(),p=await f.getKeyPacket(e,{verifyKeyPackets:!0})??await f.getFirstPacket();let g=p;const k=f.packets(p??void 0,void 0);for(await k.next();g&&!d&&!this._track.input._disposed;){const e=vt(r.length);if(r.length+m.getDecodeQueueSize()>e){({promise:o,resolve:c}=v()),await o;continue}m.decode(g);const t=await k.next();if(t.done)break;g=t.value}await k.return(),u||this._track.input._disposed||await m.flush(),m.close(),!i&&a&&r.push(a),l=!0,n()})().catch(e=>{h||(h=e,n())});const m=this._track,f=()=>{a?.close();for(const e of r)e.close()};return{async next(){for(;;){if(m.input._disposed)throw f(),new ea;if(u)return{value:void 0,done:!0};if(h)throw f(),h;if(r.length>0){const e=r.shift();return c(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};await s}},return:async()=>(u=!0,d=!0,c(),n(),f(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}mediaSamplesAtTimestamps(e){(e=>{if(!(Symbol.iterator in e)&&!(Symbol.asyncIterator in e))throw new TypeError("Argument must be an iterable or async iterable.")})(e);const r=async function*(e){Symbol.iterator in e?yield*e[Symbol.iterator]():yield*e[Symbol.asyncIterator]()}(e),i=[],a=[];let{promise:s,resolve:n}=v(),{promise:o,resolve:c}=v(),l=!1,d=!1,u=null;const h=e=>{a.push(e),n(),({promise:s,resolve:n}=v())};(async()=>{const e=await this._createDecoder(e=>{if(c(),d)return void e.close();let t=0;for(;i.length>0&&e.timestamp-i[0]>-1e-10;)t++,i.shift();if(t>0)for(let r=0;r{u||(u=e,n())}),s=this._createPacketSink();let m=null,f=null,p=-1;const g=async()=>{t(f);let r=f;for(e.decode(r);r.sequenceNumberi&&!d;)({promise:o,resolve:c}=v()),await o;if(d)break;const n=await s.getNextPacket(r);t(n),e.decode(n),r=n}p=-1},k=async()=>{await e.flush();for(let e=0;e{u||(u=e,n())});const m=this._track,f=()=>{for(const e of a)e?.close()};return{async next(){for(;;){if(m.input._disposed)throw f(),new ea;if(d)return{value:void 0,done:!0};if(u)throw f(),u;if(a.length>0){const e=a.shift();return t(void 0!==e),c(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};await s}},return:async()=>(d=!0,c(),n(),f(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}}const vt=e=>0===e?40:8;class Pt extends St{constructor(e,r,i,a,s,n){super(e,r),this.codec=i,this.decoderConfig=a,this.rotation=s,this.timeResolution=n,this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new U,this.customDecoderQueueSize=0,this.inputTimestamps=[],this.sampleQueue=[],this.currentPacketIndex=0,this.raslSkipped=!1,this.alphaDecoder=null,this.alphaHadKeyframe=!1,this.colorQueue=[],this.alphaQueue=[],this.merger=null,this.mergerCreationFailed=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue=[],this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1;const l=$e.find(e=>e.supports(i,a));if(l)this.customDecoder=new l,this.customDecoder.codec=i,this.customDecoder.config=a,this.customDecoder.onSample=e=>{if(!(e instanceof rt))throw new TypeError("The argument passed to onSample must be a VideoSample.");this.finalizeAndEmitSample(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=e=>{if(this.alphaQueue.length>0){const r=this.alphaQueue.shift();t(void 0!==r),this.mergeAlpha(e,r)}else this.colorQueue.push(e)};if("avc"===i&&this.decoderConfig.description&&K()){const e=(e=>{try{const t=c(e);let r=0;const i=t.getUint8(r++),a=t.getUint8(r++),s=t.getUint8(r++),n=t.getUint8(r++),o=3&t.getUint8(r++),l=31&t.getUint8(r++),d=[];for(let c=0;c0){const t=xe(e.sequenceParameterSets[0]);t&&0===t.frameMbsOnlyFlag&&(this.decoderConfig={...this.decoderConfig,hardwareAcceleration:"prefer-software"})}}const r=new Error("Decoding error").stack;this.decoder=new VideoDecoder({output:t=>{try{e(t)}catch(r){this.onError(r)}},error:e=>{e.stack=r,this.onError(e)}}),this.decoder.configure(this.decoderConfig)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(t(this.decoder),Math.max(this.decoder.decodeQueueSize,this.alphaDecoder?.decodeQueueSize??0))}decode(e){if("hevc"===this.codec&&this.currentPacketIndex>0&&!this.raslSkipped){if(this.hasHevcRaslPicture(e.data))return;this.raslSkipped=!0}if(this.customDecoder)this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--);else{if(t(this.decoder),q()||I(this.inputTimestamps,e.timestamp,e=>e),K()&&0===this.currentPacketIndex&&"avc"===this.codec){const t=Se(e.data,this.decoderConfig).filter(e=>{const t=ve(e);return!(t>=20&&t<=31)}),r=Ie(t,this.decoderConfig);e=new Xe(r,e.type,e.timestamp,e.duration)}this.decoder.decode(e.toEncodedVideoChunk()),this.decodeAlphaData(e)}this.currentPacketIndex++}decodeAlphaData(e){if(!e.sideData.alpha||this.mergerCreationFailed)return void this.pushNullAlphaFrame();if(!this.merger)try{this.merger=new xt}catch(i){return console.error("Due to an error, only color data will be decoded.",i),this.mergerCreationFailed=!0,void this.decodeAlphaData(e)}if(!this.alphaDecoder){const e=e=>{if(this.alphaDecoderQueueSize--,this.colorQueue.length>0){const r=this.colorQueue.shift();t(void 0!==r),this.mergeAlpha(r,e)}else this.alphaQueue.push(e);for(this.decodedAlphaChunkCount++;this.nullAlphaFrameQueue.length>0&&this.nullAlphaFrameQueue[0]===this.decodedAlphaChunkCount;)if(this.nullAlphaFrameQueue.shift(),this.colorQueue.length>0){const e=this.colorQueue.shift();t(void 0!==e),this.mergeAlpha(e,null)}else this.alphaQueue.push(null)},r=new Error("Decoding error").stack;this.alphaDecoder=new VideoDecoder({output:t=>{try{e(t)}catch(i){this.onError(i)}},error:e=>{e.stack=r,this.onError(e)}}),this.alphaDecoder.configure(this.decoderConfig)}const r=qe(this.codec,this.decoderConfig,e.sideData.alpha);if(this.alphaHadKeyframe||(this.alphaHadKeyframe="key"===r),this.alphaHadKeyframe){if("hevc"===this.codec&&this.currentAlphaPacketIndex>0&&!this.alphaRaslSkipped){if(this.hasHevcRaslPicture(e.sideData.alpha))return void this.pushNullAlphaFrame();this.alphaRaslSkipped=!0}this.currentAlphaPacketIndex++,this.alphaDecoder.decode(e.alphaToEncodedVideoChunk(r??e.type)),this.alphaDecoderQueueSize++}else this.pushNullAlphaFrame()}pushNullAlphaFrame(){0===this.alphaDecoderQueueSize?this.alphaQueue.push(null):this.nullAlphaFrameQueue.push(this.decodedAlphaChunkCount+this.alphaDecoderQueueSize)}hasHevcRaslPicture(e){return Ce(e,this.decoderConfig).some(e=>{const t=_e(e);return t===ge.RASL_N||t===ge.RASL_R})}sampleHandler(e){if(q()){if(this.sampleQueue.length>0&&e.timestamp>=i(this.sampleQueue).timestamp){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}I(this.sampleQueue,e,e=>e.timestamp)}else{const r=this.inputTimestamps.shift();t(void 0!==r),e.setTimestamp(r),this.finalizeAndEmitSample(e)}}finalizeAndEmitSample(e){e.setTimestamp(Math.round(e.timestamp*this.timeResolution)/this.timeResolution),e.setDuration(Math.round(e.duration*this.timeResolution)/this.timeResolution),e.setRotation(this.rotation),this.onSample(e)}mergeAlpha(e,r){if(!r){const t=new rt(e);return void this.sampleHandler(t)}t(this.merger),this.merger.update(e,r),e.close(),r.close();const i=new VideoFrame(this.merger.canvas,{timestamp:e.timestamp,duration:e.duration??void 0}),a=new rt(i);this.sampleHandler(a)}async flush(){if(this.customDecoder?await this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(t(this.decoder),await Promise.all([this.decoder.flush(),this.alphaDecoder?.flush()]),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>e?.close()),this.alphaQueue.length=0,this.alphaHadKeyframe=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue.length=0,this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1),q()){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}this.currentPacketIndex=0,this.raslSkipped=!1}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(t(this.decoder),this.decoder.close(),this.alphaDecoder?.close(),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>e?.close()),this.alphaQueue.length=0,this.merger?.close());for(const e of this.sampleQueue)e.close();this.sampleQueue.length=0}}class xt{constructor(){"undefined"!==typeof OffscreenCanvas?this.canvas=new OffscreenCanvas(300,150):this.canvas=document.createElement("canvas");const e=this.canvas.getContext("webgl2",{premultipliedAlpha:!1});if(!e)throw new Error("Couldn't acquire WebGL 2 context.");this.gl=e,this.program=this.createProgram(),this.vao=this.createVAO(),this.colorTexture=this.createTexture(),this.alphaTexture=this.createTexture(),this.gl.useProgram(this.program),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_colorTexture"),0),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_alphaTexture"),1)}createProgram(){const e=this.createShader(this.gl.VERTEX_SHADER,"#version 300 es\n\t\t\tin vec2 a_position;\n\t\t\tin vec2 a_texCoord;\n\t\t\tout vec2 v_texCoord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = vec4(a_position, 0.0, 1.0);\n\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t}\n\t\t"),t=this.createShader(this.gl.FRAGMENT_SHADER,"#version 300 es\n\t\t\tprecision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_colorTexture;\n\t\t\tuniform sampler2D u_alphaTexture;\n\t\t\tin vec2 v_texCoord;\n\t\t\tout vec4 fragColor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture(u_colorTexture, v_texCoord).rgb;\n\t\t\t\tfloat alpha = texture(u_alphaTexture, v_texCoord).r;\n\t\t\t\tfragColor = vec4(color, alpha);\n\t\t\t}\n\t\t"),r=this.gl.createProgram();return this.gl.attachShader(r,e),this.gl.attachShader(r,t),this.gl.linkProgram(r),r}createShader(e,t){const r=this.gl.createShader(e);return this.gl.shaderSource(r,t),this.gl.compileShader(r),r}createVAO(){const e=this.gl.createVertexArray();this.gl.bindVertexArray(e);const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),r=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,r),this.gl.bufferData(this.gl.ARRAY_BUFFER,t,this.gl.STATIC_DRAW);const i=this.gl.getAttribLocation(this.program,"a_position"),a=this.gl.getAttribLocation(this.program,"a_texCoord");return this.gl.enableVertexAttribArray(i),this.gl.vertexAttribPointer(i,2,this.gl.FLOAT,!1,16,0),this.gl.enableVertexAttribArray(a),this.gl.vertexAttribPointer(a,2,this.gl.FLOAT,!1,16,8),e}createTexture(){const e=this.gl.createTexture();return this.gl.bindTexture(this.gl.TEXTURE_2D,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),e}update(e,t){e.displayWidth===this.canvas.width&&e.displayHeight===this.canvas.height||(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colorTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),this.gl.activeTexture(this.gl.TEXTURE1),this.gl.bindTexture(this.gl.TEXTURE_2D,this.alphaTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.bindVertexArray(this.vao),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)}close(){this.gl.getExtension("WEBGL_lose_context")?.loseContext(),this.gl=null}}class Ct extends It{constructor(e){if(!(e instanceof Rt))throw new TypeError("videoTrack must be an InputVideoTrack.");super(),this._track=e}async _createDecoder(e,r){if(!(await this._track.canDecode()))throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track.");const i=this._track.codec,a=this._track.rotation,s=await this._track.getDecoderConfig(),n=this._track.timeResolution;return t(i&&s),new Pt(e,r,i,s,a,n)}_createPacketSink(){return new wt(this._track)}async getSample(e){Tt(e);for await(const t of this.mediaSamplesAtTimestamps([e]))return t;throw new Error("Internal error: Iterator returned nothing.")}samples(e=0,t=1/0){return this.mediaSamplesInRange(e,t)}samplesAtTimestamps(e){return this.mediaSamplesAtTimestamps(e)}}class _t{constructor(e,t={}){if(this._nextCanvasIndex=0,!(e instanceof Rt))throw new TypeError("videoTrack must be an InputVideoTrack.");if(t&&"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.alpha&&"boolean"!==typeof t.alpha)throw new TypeError("options.alpha, when provided, must be a boolean.");if(void 0!==t.width&&(!Number.isInteger(t.width)||t.width<=0))throw new TypeError("options.width, when defined, must be a positive integer.");if(void 0!==t.height&&(!Number.isInteger(t.height)||t.height<=0))throw new TypeError("options.height, when defined, must be a positive integer.");if(void 0!==t.fit&&!["fill","contain","cover"].includes(t.fit))throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".');if(void 0!==t.width&&void 0!==t.height&&void 0===t.fit)throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180 or 270.");if(void 0!==t.crop&&nt(t.crop,"options."),void 0!==t.poolSize&&("number"!==typeof t.poolSize||!Number.isInteger(t.poolSize)||t.poolSize<0))throw new TypeError("poolSize must be a non-negative integer.");const r=t.rotation??e.rotation,[i,a]=r%180===0?[e.codedWidth,e.codedHeight]:[e.codedHeight,e.codedWidth],s=t.crop;s&&st(s,i,a);let[n,o]=s?[s.width,s.height]:[i,a];const c=n/o;void 0!==t.width&&void 0===t.height?(n=t.width,o=Math.round(n/c)):void 0===t.width&&void 0!==t.height?(o=t.height,n=Math.round(o*c)):void 0!==t.width&&void 0!==t.height&&(n=t.width,o=t.height),this._videoTrack=e,this._alpha=t.alpha??!1,this._width=n,this._height=o,this._rotation=r,this._crop=s,this._fit=t.fit??"fill",this._videoSampleSink=new Ct(e),this._canvasPool=Array.from({length:t.poolSize??0},()=>null)}_videoSampleToWrappedCanvas(e){let r=this._canvasPool[this._nextCanvasIndex],i=!1;r||("undefined"!==typeof document?(r=document.createElement("canvas"),r.width=this._width,r.height=this._height):r=new OffscreenCanvas(this._width,this._height),this._canvasPool.length>0&&(this._canvasPool[this._nextCanvasIndex]=r),i=!0),this._canvasPool.length>0&&(this._nextCanvasIndex=(this._nextCanvasIndex+1)%this._canvasPool.length);const a=r.getContext("2d",{alpha:this._alpha||W()});t(a),a.resetTransform(),i||(!this._alpha&&W()?(a.fillStyle="black",a.fillRect(0,0,this._width,this._height)):a.clearRect(0,0,this._width,this._height)),e.drawWithFit(a,{fit:this._fit,rotation:this._rotation,crop:this._crop});const s={canvas:r,timestamp:e.timestamp,duration:e.duration};return e.close(),s}async getCanvas(e){Tt(e);const t=await this._videoSampleSink.getSample(e);return t&&this._videoSampleToWrappedCanvas(t)}canvases(e=0,t=1/0){return E(this._videoSampleSink.samples(e,t),e=>this._videoSampleToWrappedCanvas(e))}canvasesAtTimestamps(e){return E(this._videoSampleSink.samplesAtTimestamps(e),e=>e&&this._videoSampleToWrappedCanvas(e))}}class Bt extends St{constructor(e,t,r,i){super(e,t),this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new U,this.customDecoderQueueSize=0,this.currentTimestamp=null;const a=t=>{(null===this.currentTimestamp||Math.abs(t.timestamp-this.currentTimestamp)>=t.duration)&&(this.currentTimestamp=t.timestamp);const r=this.currentTimestamp;if(this.currentTimestamp+=t.duration,0===t.numberOfFrames)return void t.close();const a=i.sampleRate;t.setTimestamp(Math.round(r*a)/a),e(t)},s=Qe.find(e=>e.supports(r,i));if(s)this.customDecoder=new s,this.customDecoder.codec=r,this.customDecoder.config=i,this.customDecoder.onSample=e=>{if(!(e instanceof ut))throw new TypeError("The argument passed to onSample must be an AudioSample.");a(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=new Error("Decoding error").stack;this.decoder=new AudioDecoder({output:e=>{try{a(new ut(e))}catch(t){this.onError(t)}},error:t=>{t.stack=e,this.onError(t)}}),this.decoder.configure(i)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(t(this.decoder),this.decoder.decodeQueueSize)}decode(e){this.customDecoder?(this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--)):(t(this.decoder),this.decoder.decode(e.toEncodedAudioChunk()))}flush(){return this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(t(this.decoder),this.decoder.flush())}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(t(this.decoder),this.decoder.close())}}class Et extends St{constructor(e,r,i){super(e,r),this.decoderConfig=i,this.currentTimestamp=null,t(re.includes(i.codec)),this.codec=i.codec;const{dataType:a,sampleSize:s,littleEndian:n}=me(this.codec);switch(this.inputSampleSize=s,s){case 1:"unsigned"===a?this.readInputValue=(e,t)=>e.getUint8(t)-128:"signed"===a?this.readInputValue=(e,t)=>e.getInt8(t):"ulaw"===a?this.readInputValue=(e,t)=>(e=>{let t=0,r=0,i=~e;128&i&&(i&=-129,t=-1),r=5+((240&i)>>4);const a=(1<(e=>{let t=0,r=0,i=85^e;128&i&&(i&=-129,t=-1),r=4+((240&i)>>4);let a=0;return a=4!==r?1<e.getUint16(t,n)-32768:"signed"===a?this.readInputValue=(e,t)=>e.getInt16(t,n):t(!1);break;case 3:"unsigned"===a?this.readInputValue=(e,t)=>_(e,t,n)-2**23:"signed"===a?this.readInputValue=(e,t)=>((e,t,r)=>_(e,t,r)<<8>>8)(e,t,n):t(!1);break;case 4:"unsigned"===a?this.readInputValue=(e,t)=>e.getUint32(t,n)-2**31:"signed"===a?this.readInputValue=(e,t)=>e.getInt32(t,n):"float"===a?this.readInputValue=(e,t)=>e.getFloat32(t,n):t(!1);break;case 8:"float"===a?this.readInputValue=(e,t)=>e.getFloat64(t,n):t(!1);break;default:C(s),t(!1)}switch(s){case 1:"ulaw"===a||"alaw"===a?(this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,r)=>e.setInt16(t,r,!0)):(this.outputSampleSize=1,this.outputFormat="u8",this.writeOutputValue=(e,t,r)=>e.setUint8(t,r+128));break;case 2:this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,r)=>e.setInt16(t,r,!0);break;case 3:this.outputSampleSize=4,this.outputFormat="s32",this.writeOutputValue=(e,t,r)=>e.setInt32(t,r<<8,!0);break;case 4:this.outputSampleSize=4,"float"===a?(this.outputFormat="f32",this.writeOutputValue=(e,t,r)=>e.setFloat32(t,r,!0)):(this.outputFormat="s32",this.writeOutputValue=(e,t,r)=>e.setInt32(t,r,!0));break;case 8:this.outputSampleSize=4,this.outputFormat="f32",this.writeOutputValue=(e,t,r)=>e.setFloat32(t,r,!0);break;default:C(s),t(!1)}}getDecodeQueueSize(){return 0}decode(e){const t=c(e.data),r=e.byteLength/this.decoderConfig.numberOfChannels/this.inputSampleSize,i=r*this.decoderConfig.numberOfChannels*this.outputSampleSize,a=new ArrayBuffer(i),s=new DataView(a);for(let c=0;c=n)&&(this.currentTimestamp=e.timestamp);const o=this.currentTimestamp;this.currentTimestamp+=n;const l=new ut({format:this.outputFormat,data:a,numberOfChannels:this.decoderConfig.numberOfChannels,sampleRate:this.decoderConfig.sampleRate,numberOfFrames:r,timestamp:o});this.onSample(l)}async flush(){}close(){}}class Ft extends It{constructor(e){if(!(e instanceof Mt))throw new TypeError("audioTrack must be an InputAudioTrack.");super(),this._track=e}async _createDecoder(e,r){if(!(await this._track.canDecode()))throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track.");const i=this._track.codec,a=await this._track.getDecoderConfig();return t(i&&a),re.includes(a.codec)?new Et(e,r,a):new Bt(e,r,i,a)}_createPacketSink(){return new wt(this._track)}async getSample(e){Tt(e);for await(const t of this.mediaSamplesAtTimestamps([e]))return t;throw new Error("Internal error: Iterator returned nothing.")}samples(e=0,t=1/0){return this.mediaSamplesInRange(e,t)}samplesAtTimestamps(e){return this.mediaSamplesAtTimestamps(e)}}class Dt{constructor(e){if(!(e instanceof Mt))throw new TypeError("audioTrack must be an InputAudioTrack.");this._audioSampleSink=new Ft(e)}_audioSampleToWrappedArrayBuffer(e){const t={buffer:e.toAudioBuffer(),timestamp:e.timestamp,duration:e.duration};return e.close(),t}async getBuffer(e){Tt(e);const t=await this._audioSampleSink.getSample(e);return t&&this._audioSampleToWrappedArrayBuffer(t)}buffers(e=0,t=1/0){return E(this._audioSampleSink.samples(e,t),e=>this._audioSampleToWrappedArrayBuffer(e))}buffersAtTimestamps(e){return E(this._audioSampleSink.samplesAtTimestamps(e),e=>e&&this._audioSampleToWrappedArrayBuffer(e))}}class At{constructor(e,t){this.input=e,this._backing=t}isVideoTrack(){return this instanceof Rt}isAudioTrack(){return this instanceof Mt}get id(){return this._backing.getId()}get internalCodecId(){return this._backing.getInternalCodecId()}get languageCode(){return this._backing.getLanguageCode()}get name(){return this._backing.getName()}get timeResolution(){return this._backing.getTimeResolution()}get disposition(){return this._backing.getDisposition()}getFirstTimestamp(){return this._backing.getFirstTimestamp()}computeDuration(){return this._backing.computeDuration()}async computePacketStats(e=1/0){const t=new wt(this);let r=1/0,i=-1/0,a=0,s=0;for await(const n of t.packets(void 0,void 0,{metadataOnly:!0})){if(a>=e&&n.timestamp>=i)break;r=Math.min(r,n.timestamp),i=Math.max(i,n.timestamp+n.duration),a++,s+=n.byteLength}return{packetCount:a,averagePacketRate:a?Number((a/(i-r)).toPrecision(16)):0,averageBitrate:a?Number((8*s/(i-r)).toPrecision(16)):0}}}class Rt extends At{constructor(e,t){super(e,t),this._backing=t}get type(){return"video"}get codec(){return this._backing.getCodec()}get codedWidth(){return this._backing.getCodedWidth()}get codedHeight(){return this._backing.getCodedHeight()}get rotation(){return this._backing.getRotation()}get displayWidth(){return this._backing.getRotation()%180===0?this._backing.getCodedWidth():this._backing.getCodedHeight()}get displayHeight(){return this._backing.getRotation()%180===0?this._backing.getCodedHeight():this._backing.getCodedWidth()}getColorSpace(){return this._backing.getColorSpace()}async hasHighDynamicRange(){const e=await this._backing.getColorSpace();return"bt2020"===e.primaries||"smpte432"===e.primaries||"pg"===e.transfer||"hlg"===e.transfer||"bt2020-ncl"===e.matrix}canBeTransparent(){return this._backing.canBeTransparent()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecParameterString(){const e=await this._backing.getDecoderConfig();return e?.codec??null}async canDecode(){try{const e=await this._backing.getDecoderConfig();if(!e)return!1;const r=this._backing.getCodec();if(t(null!==r),$e.some(t=>t.supports(r,e)))return!0;if("undefined"===typeof VideoDecoder)return!1;return!0===(await VideoDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}}async determinePacketType(e){if(!(e instanceof Xe))throw new TypeError("packet must be an EncodedPacket.");if(e.isMetadataOnly)throw new TypeError("packet must not be metadata-only to determine its type.");if(null===this.codec)return null;const r=await this.getDecoderConfig();return t(r),qe(this.codec,r,e.data)}}class Mt extends At{constructor(e,t){super(e,t),this._backing=t}get type(){return"audio"}get codec(){return this._backing.getCodec()}get numberOfChannels(){return this._backing.getNumberOfChannels()}get sampleRate(){return this._backing.getSampleRate()}getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecParameterString(){const e=await this._backing.getDecoderConfig();return e?.codec??null}async canDecode(){try{const e=await this._backing.getDecoderConfig();if(!e)return!1;const r=this._backing.getCodec();if(t(null!==r),Qe.some(t=>t.supports(r,e)))return!0;if(e.codec.startsWith("pcm-"))return!0;if("undefined"===typeof AudioDecoder)return!1;return!0===(await AudioDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}}async determinePacketType(e){if(!(e instanceof Xe))throw new TypeError("packet must be an EncodedPacket.");return null===this.codec?null:"key"}}const Nt=e=>{let t=ua(e);const r=ya(e,4);let i=8;1===t&&(t=pa(e),i=16);const a=t-i;return a<0?null:{name:r,totalSize:t,headerSize:i,contentSize:a}},zt=e=>ma(e)/65536,Ot=e=>ma(e)/1073741824,Lt=e=>{let t=0;for(let r=0;r<4;r++){t<<=7;const r=sa(e);if(t|=127&r,0===(128&r))break}return t},Ut=e=>{let t=oa(e);return e.skip(2),t=Math.min(t,e.remainingLength),l.decode(aa(e,t))},Vt=e=>{const t=Nt(e);if(!t||"data"!==t.name)return null;if(e.remainingLength<8)return null;const r=ua(e);e.skip(4);const i=aa(e,t.contentSize-8);switch(r){case 1:return l.decode(i);case 2:return new TextDecoder("utf-16be").decode(i);case 13:return new Z(i,"image/jpeg");case 14:return new Z(i,"image/png");case 27:return new Z(i,"image/bmp");default:return i}};class qt extends Ke{constructor(e){super(e),this.moovSlice=null,this.currentTrack=null,this.tracks=[],this.metadataPromise=null,this.movieTimescale=-1,this.movieDurationInTimescale=-1,this.isQuickTime=!1,this.metadataTags={},this.currentMetadataKeys=null,this.isFragmented=!1,this.fragmentTrackDefaults=[],this.currentFragment=null,this.lastReadFragment=null,this.reader=e._reader}async computeDuration(){const e=await this.getTracks(),t=await Promise.all(e.map(e=>e.computeDuration()));return Math.max(0,...t)}async getTracks(){return await this.readMetadata(),this.tracks.map(e=>e.inputTrack)}async getMimeType(){await this.readMetadata();const e=await Promise.all(this.tracks.map(e=>e.inputTrack.getCodecParameterString()));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isQuickTime?"quicktime":"mp4");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({isQuickTime:this.isQuickTime,hasVideo:this.tracks.some(e=>"video"===e.info?.type),hasAudio:this.tracks.some(e=>"audio"===e.info?.type),codecStrings:e.filter(Boolean)})}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,8,16);if(t instanceof Promise&&(t=await t),!t)break;const r=e,i=Nt(t);if(!i)break;if("ftyp"===i.name){const e=ya(t,4);this.isQuickTime="qt "===e}else if("moov"===i.name){let e=this.reader.requestSlice(t.filePos,i.contentSize);if(e instanceof Promise&&(e=await e),!e)break;this.moovSlice=e,this.readContiguousBoxes(this.moovSlice),this.tracks.sort((e,t)=>Number(t.disposition.default)-Number(e.disposition.default));for(const t of this.tracks){const e=t.editListPreviousSegmentDurations/this.movieTimescale;t.editListOffset-=Math.round(e*t.timescale)}break}e=r+i.totalSize}if(this.isFragmented&&null!==this.reader.fileSize){let e=this.reader.requestSlice(this.reader.fileSize-4,4);e instanceof Promise&&(e=await e),t(e);const r=ua(e),i=this.reader.fileSize-r;if(i>=0&&i<=this.reader.fileSize-16){let e=this.reader.requestSliceRange(i,8,16);if(e instanceof Promise&&(e=await e),e){const t=Nt(e);if(t&&"mfra"===t.name){let r=this.reader.requestSlice(e.filePos,t.contentSize);r instanceof Promise&&(r=await r),r&&this.readContiguousBoxes(r)}}}}})())}getSampleTableForTrack(e){if(e.sampleTable)return e.sampleTable;const r={sampleTimingEntries:[],sampleCompositionTimeOffsets:[],sampleSizes:[],keySampleIndices:null,chunkOffsets:[],sampleToChunk:[],presentationTimestamps:null,presentationTimestampIndexMap:null};e.sampleTable=r,t(this.moovSlice);const a=this.moovSlice.slice(e.sampleTableByteOffset);this.currentTrack=e,this.traverseBox(a),this.currentTrack=null;if("audio"===e.info?.type&&e.info.codec&&re.includes(e.info.codec)&&0===r.sampleCompositionTimeOffsets.length){t("audio"===e.info?.type);const a=me(e.info.codec),s=[],n=[];for(let t=0;te.startIndex),u=r.sampleTimingEntries[d],h=S(r.sampleTimingEntries,l,e=>e.startIndex),m=r.sampleTimingEntries[h],f=u.startDecodeTimestamp+(c-u.startIndex)*u.delta,p=m.startDecodeTimestamp+(l-m.startIndex)*m.delta-f,g=i(s);g&&g.delta===p?g.count++:s.push({startIndex:o.startChunkIndex+t,startDecodeTimestamp:f,count:1,delta:p});const k=o.samplesPerChunk*a.sampleSize*e.info.numberOfChannels;n.push(k)}o.startSampleIndex=o.startChunkIndex,o.samplesPerChunk=1}r.sampleTimingEntries=s,r.sampleSizes=n}if(r.sampleCompositionTimeOffsets.length>0){r.presentationTimestamps=[];for(const e of r.sampleTimingEntries)for(let t=0;te.presentationTimestamp-t.presentationTimestamp),r.presentationTimestampIndexMap=Array(r.presentationTimestamps.length).fill(-1);for(let e=0;ee.moofOffset===s.moofOffset);if(i)Xt(t,i.timestamp);else{const e=S(r,s.moofOffset-1,e=>e.moofOffset);if(-1!==e){const i=r[e];Xt(t,i.endTimestamp)}}t.startTimestampIsFinal=!0}const i=S(r,t.startTimestamp,e=>e.startTimestamp);-1!==i&&r[i].moofOffset===s.moofOffset||r.splice(i+1,0,{moofOffset:s.moofOffset,startTimestamp:t.startTimestamp,endTimestamp:t.endTimestamp})}return s}readContiguousBoxes(e){const t=e.filePos;for(;e.filePos-t<=e.length-8;){if(!this.traverseBox(e))break}}*iterateContiguousBoxes(e){const t=e.filePos;for(;e.filePos-t<=e.length-8;){const t=e.filePos,r=Nt(e);if(!r)break;yield{boxInfo:r,slice:e},e.filePos=t+r.totalSize}}traverseBox(e){var s,n,o,d,u,m,p,k,b,T,y,w,S,I,v,P,x,C,_,B,E,F,A,R,N,z,O,L,U,V,q,H,W;const j=e.filePos,K=Nt(e);if(!K)return!1;const $=e.filePos,Q=j+K.totalSize;switch(K.name){case"mdia":case"minf":case"dinf":case"mfra":case"edts":case"wave":this.readContiguousBoxes(e.slice($,K.contentSize));break;case"mvhd":{const t=sa(e);e.skip(3),1===t?(e.skip(16),this.movieTimescale=ua(e),this.movieDurationInTimescale=pa(e)):(e.skip(8),this.movieTimescale=ua(e),this.movieDurationInTimescale=ua(e))}break;case"trak":{const t={id:-1,demuxer:this,inputTrack:null,disposition:{...te},info:null,timescale:-1,durationInMovieTimescale:-1,durationInMediaTimescale:-1,rotation:0,internalCodecId:null,name:null,languageCode:D,sampleTableByteOffset:-1,sampleTable:null,fragmentLookupTable:[],currentFragmentState:null,fragmentPositionCache:[],editListPreviousSegmentDurations:0,editListOffset:0};if(this.currentTrack=t,this.readContiguousBoxes(e.slice($,K.contentSize)),-1!==t.id&&-1!==t.timescale&&null!==t.info)if("video"===t.info.type&&-1!==t.info.width){const e=t;t.inputTrack=new Rt(this.input,new Wt(e)),this.tracks.push(t)}else if("audio"===t.info.type&&-1!==t.info.numberOfChannels){const e=t;t.inputTrack=new Mt(this.input,new jt(e)),this.tracks.push(t)}this.currentTrack=null}break;case"tkhd":{const i=this.currentTrack;if(!i)break;const a=sa(e),s=!!(1&ca(e));if(i.disposition.default=s,0===a)e.skip(8),i.id=ua(e),e.skip(4),i.durationInMovieTimescale=ua(e);else{if(1!==a)throw new Error(`Incorrect track header version ${a}.`);e.skip(16),i.id=ua(e),e.skip(4),i.durationInMovieTimescale=pa(e)}e.skip(16);const n=[zt(e),zt(e),Ot(e),zt(e),zt(e),Ot(e),zt(e),zt(e),Ot(e)],o=r((G=Yt(n),X=90,Math.round(G/X)*X));t(0===o||90===o||180===o||270===o),i.rotation=o}break;case"elst":{const t=this.currentTrack;if(!t)break;const r=sa(e);e.skip(3);let i=!1,a=0;const s=ua(e);for(let n=0;n0){t.languageCode="";for(let e=0;e<3;e++)t.languageCode=String.fromCharCode(96+(31&i))+t.languageCode,i>>=5;M(t.languageCode)||(t.languageCode=D)}}break;case"hdlr":{const t=this.currentTrack;if(!t)break;e.skip(8);const r=ya(e,4);"vide"===r?t.info={type:"video",width:-1,height:-1,codec:null,codecDescription:null,colorSpace:null,avcType:null,avcCodecInfo:null,hevcCodecInfo:null,vp9CodecInfo:null,av1CodecInfo:null}:"soun"===r&&(t.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case"stbl":{const t=this.currentTrack;if(!t)break;t.sampleTableByteOffset=j,this.readContiguousBoxes(e.slice($,K.contentSize))}break;case"stsd":{const t=this.currentTrack;if(!t)break;if(null===t.info||t.sampleTable)break;const r=sa(e);e.skip(3);const i=ua(e);for(let a=0;a0)if(1===n)e.skip(4),c=8*ua(e),e.skip(8);else if(2===n){e.skip(4),l=Ta(e),o=ua(e),e.skip(4),c=ua(e);const r=ua(e);if(e.skip(8),"lpcm"===s){const e=c+7>>3,i=Boolean(1&r),a=Boolean(2&r),s=4&r?-1:0;c>0&&c<=64&&(i?32===c&&(t.info.codec=a?"pcm-f32be":"pcm-f32"):s&1<>4,o=s>>1&7,c=1&s,l=sa(e),d=sa(e),u=sa(e);r.info.vp9CodecInfo={profile:i,level:a,bitDepth:n,chromaSubsampling:o,videoFullRangeFlag:c,colourPrimaries:l,transferCharacteristics:d,matrixCoefficients:u}}break;case"av1C":{const r=this.currentTrack;if(!r)break;t("video"===r.info?.type),e.skip(1);const i=sa(e),a=i>>5,s=31&i,n=sa(e),o=n>>7,c=n>>6&1,l=n>>4&1,d=n>>3&1,u=n>>2&1,h=3&n,m=2===a&&c?n>>5&1?12:10:c?10:8;r.info.av1CodecInfo={profile:a,level:s,tier:o,bitDepth:m,monochrome:l,chromaSubsamplingX:d,chromaSubsamplingY:u,chromaSamplePosition:h}}break;case"colr":{const r=this.currentTrack;if(!r)break;t("video"===r.info?.type);if("nclx"!==ya(e,4))break;const i=oa(e),a=oa(e),s=oa(e),n=Boolean(128&sa(e));r.info.colorSpace={primaries:h[i],transfer:f[a],matrix:g[s],fullRange:n}}break;case"esds":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type),e.skip(4);t(3===sa(e)),Lt(e),e.skip(2);const i=sa(e),a=0!==(64&i),s=0!==(32&i);if(0!==(128&i)&&e.skip(2),a){const t=sa(e);e.skip(t)}s&&e.skip(2);t(4===sa(e));const n=Lt(e),o=e.filePos,c=sa(e);if(64===c||103===c?(r.info.codec="aac",r.info.aacCodecInfo={isMpeg2:103===c}):105===c||107===c?r.info.codec="mp3":221===c?r.info.codec="vorbis":console.warn(`Unsupported audio codec (objectTypeIndication ${c}) - discarding track.`),e.skip(12),n>e.filePos-o){t(5===sa(e));const i=Lt(e);if(r.info.codecDescription=aa(e,i),"aac"===r.info.codec){const e=de(r.info.codecDescription);null!==e.numberOfChannels&&(r.info.numberOfChannels=e.numberOfChannels),null!==e.sampleRate&&(r.info.sampleRate=e.sampleRate)}}}break;case"enda":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type);255&oa(e)&&("pcm-s16be"===r.info.codec?r.info.codec="pcm-s16":"pcm-s24be"===r.info.codec?r.info.codec="pcm-s24":"pcm-s32be"===r.info.codec?r.info.codec="pcm-s32":"pcm-f32be"===r.info.codec?r.info.codec="pcm-f32":"pcm-f64be"===r.info.codec&&(r.info.codec="pcm-f64"))}break;case"pcmC":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type),e.skip(4);const i=sa(e),a=Boolean(1&i),s=sa(e);"pcm-s16be"===r.info.codec?a?16===s?r.info.codec="pcm-s16":24===s?r.info.codec="pcm-s24":32===s?r.info.codec="pcm-s32":(console.warn(`Invalid ipcm sample size ${s}.`),r.info.codec=null):16===s?r.info.codec="pcm-s16be":24===s?r.info.codec="pcm-s24be":32===s?r.info.codec="pcm-s32be":(console.warn(`Invalid ipcm sample size ${s}.`),r.info.codec=null):"pcm-f32be"===r.info.codec&&(a?32===s?r.info.codec="pcm-f32":64===s?r.info.codec="pcm-f64":(console.warn(`Invalid fpcm sample size ${s}.`),r.info.codec=null):32===s?r.info.codec="pcm-f32be":64===s?r.info.codec="pcm-f64be":(console.warn(`Invalid fpcm sample size ${s}.`),r.info.codec=null));break}case"dOps":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type),e.skip(1);const i=sa(e),a=oa(e),s=ua(e),n=la(e),o=sa(e);let c;c=0!==o?aa(e,2+i):new Uint8Array(0);const l=new Uint8Array(19+c.byteLength),d=new DataView(l.buffer);d.setUint32(0,1332770163,!1),d.setUint32(4,1214603620,!1),d.setUint8(8,1),d.setUint8(9,i),d.setUint16(10,a,!0),d.setUint32(12,s,!0),d.setInt16(16,n,!0),d.setUint8(18,o),l.set(c,19),r.info.codecDescription=l,r.info.numberOfChannels=i}break;case"dfLa":{const r=this.currentTrack;if(!r)break;t("audio"===r.info?.type),e.skip(4);const i=127,a=128,s=e.filePos;for(;e.filePos>>12,a=1+(t>>9&7);r.info.sampleRate=i,r.info.numberOfChannels=a,e.skip(20)}else e.skip(s);if(t&a)break}const n=e.filePos;e.filePos=s;const o=aa(e,n-s),c=new Uint8Array(4+o.byteLength);new DataView(c.buffer).setUint32(0,1716281667,!1),c.set(o,4),r.info.codecDescription=c}break;case"stts":{const t=this.currentTrack;if(!t)break;if(!t.sampleTable)break;e.skip(4);const r=ua(e);let i=0,a=0;for(let s=0;se.id===r);if(!i)break;const a=ua(e),s=(12&a)>>2,n=3&a,o=[sa,oa,ca,ua],c=o[(48&a)>>4],l=o[s],d=o[n],u=ua(e);for(let h=0;he.timestamp-t.timestamp);for(let e=0;ee.id===d);if(!u)break;const h=this.fragmentTrackDefaults.find(e=>e.trackId===d);this.currentTrack=u,u.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:h?.defaultSampleDescriptionIndex??null,defaultSampleDuration:h?.defaultSampleDuration??null,defaultSampleSize:h?.defaultSampleSize??null,defaultSampleFlags:h?.defaultSampleFlags??null,startTimestamp:null},i?u.currentFragmentState.baseDataOffset=pa(e):l&&(u.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),a&&(u.currentFragmentState.sampleDescriptionIndex=ua(e)),s&&(u.currentFragmentState.defaultSampleDuration=ua(e)),n&&(u.currentFragmentState.defaultSampleSize=ua(e)),o&&(u.currentFragmentState.defaultSampleFlags=ua(e)),c&&(u.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{const r=this.currentTrack;if(!r)break;t(r.currentFragmentState);const i=sa(e);e.skip(3);const a=0===i?ua(e):pa(e);r.currentFragmentState.startTimestamp=a}break;case"trun":{const r=this.currentTrack;if(!r)break;if(t(this.currentFragment),t(r.currentFragmentState),this.currentFragment.trackData.has(r.id)){console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring...");break}const a=sa(e),s=ca(e),n=Boolean(1&s),o=Boolean(4&s),c=Boolean(256&s),l=Boolean(512&s),d=Boolean(1024&s),u=Boolean(2048&s),h=ua(e);let m=r.currentFragmentState.baseDataOffset;n&&(m+=ma(e));let f=null;o&&(f=ua(e));let p=m;if(0===h){this.currentFragment.implicitBaseDataOffset=p;break}let g=0;const k={track:r,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(r.id,k);for(let i=0;i({presentationTimestamp:e.presentationTimestamp,sampleIndex:t})).sort((e,t)=>e.presentationTimestamp-t.presentationTimestamp);for(let e=0;e0&&((L=this.metadataTags).trackNumber??(L.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&((U=this.metadataTags).tracksTotal??(U.tracksTotal=r))}break;case"trkn":if(a instanceof Uint8Array&&a.length>=6){const e=c(a),t=e.getUint16(2,!1),r=e.getUint16(4,!1);t>0&&((V=this.metadataTags).trackNumber??(V.trackNumber=t)),r>0&&((q=this.metadataTags).tracksTotal??(q.tracksTotal=r))}break;case"disc":case"disk":if(a instanceof Uint8Array&&a.length>=6){const e=c(a),t=e.getUint16(2,!1),r=e.getUint16(4,!1);t>0&&((H=this.metadataTags).discNumber??(H.discNumber=t)),r>0&&((W=this.metadataTags).discsTotal??(W.discsTotal=r))}}}}}var G,X;return e.filePos=Q,!0}}class Ht{constructor(e){this.internalTrack=e,this.packetToSampleIndex=new WeakMap,this.packetToFragmentLocation=new WeakMap}getId(){return this.internalTrack.id}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.internalCodecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.timescale}getDisposition(){return this.internalTrack.disposition}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}async getFirstTimestamp(){const e=await this.getFirstPacket({metadataOnly:!0});return e?.timestamp??0}async getFirstPacket(e){const t=await this.fetchPacketForSampleIndex(0,e);return t||!this.internalTrack.demuxer.isFragmented?t:this.performFragmentedLookup(null,e=>e.trackData.get(this.internalTrack.id)?{sampleIndex:0,correctSampleFound:!0}:{sampleIndex:-1,correctSampleFound:!1},-1/0,1/0,e)}mapTimestampIntoTimescale(e){return A(e*this.internalTrack.timescale)+this.internalTrack.editListOffset}async getPacket(e,t){const r=this.mapTimestampIntoTimescale(e),i=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),a=Kt(i,r),s=await this.fetchPacketForSampleIndex(a,t);return Jt(i)&&this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const i=S(t.presentationTimestamps,r,e=>e.presentationTimestamp);return{sampleIndex:-1!==i?t.presentationTimestamps[i].sampleIndex:-1,correctSampleFound:-1!==i&&r{if(e===i.fragment){const t=e.trackData.get(this.internalTrack.id);if(i.sampleIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const i=x(t.presentationTimestamps,e=>t.samples[e.sampleIndex].isKeyFrame&&e.presentationTimestamp<=r);return{sampleIndex:-1!==i?t.presentationTimestamps[i].sampleIndex:-1,correctSampleFound:-1!==i&&r{if(e===a.fragment){const t=e.trackData.get(this.internalTrack.id).samples.findIndex((e,t)=>e.isKeyFrame&&t>a.sampleIndex);if(-1!==t)return{sampleIndex:t,correctSampleFound:!0}}else{const r=e.trackData.get(this.internalTrack.id);if(r&&null!==r.firstKeyFrameTimestamp){const e=r.samples.findIndex(e=>e.isKeyFrame);return t(-1!==e),{sampleIndex:e,correctSampleFound:!0}}}return{sampleIndex:-1,correctSampleFound:!1}},-1/0,1/0,r)}async fetchPacketForSampleIndex(e,r){if(-1===e)return null;const i=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),a=Qt(i,e);if(!a)return null;let s;if(r.metadataOnly)s=Ge;else{let e=this.internalTrack.demuxer.reader.requestSlice(a.sampleOffset,a.sampleSize);e instanceof Promise&&(e=await e),t(e),s=aa(e,a.sampleSize)}const n=(a.presentationTimestamp-this.internalTrack.editListOffset)/this.internalTrack.timescale,o=a.duration/this.internalTrack.timescale,c=new Xe(s,a.isKeyFrame?"key":"delta",n,o,e,a.sampleSize);return this.packetToSampleIndex.set(c,e),c}async fetchPacketInFragment(e,r,i){if(-1===r)return null;const a=e.trackData.get(this.internalTrack.id).samples[r];let s;if(t(a),i.metadataOnly)s=Ge;else{let e=this.internalTrack.demuxer.reader.requestSlice(a.byteOffset,a.byteSize);e instanceof Promise&&(e=await e),t(e),s=aa(e,a.byteSize)}const n=(a.presentationTimestamp-this.internalTrack.editListOffset)/this.internalTrack.timescale,o=a.duration/this.internalTrack.timescale,c=new Xe(s,a.isKeyFrame?"key":"delta",n,o,e.moofOffset+r,a.byteSize);return this.packetToFragmentLocation.set(c,{fragment:e,sampleIndex:r}),c}async performFragmentedLookup(e,r,i,a,s){const n=this.internalTrack.demuxer;let o=null,c=null,l=-1;if(e){const{sampleIndex:t,correctSampleFound:i}=r(e);if(i)return this.fetchPacketInFragment(e,t,s);-1!==t&&(c=e,l=t)}const d=S(this.internalTrack.fragmentLookupTable,i,e=>e.timestamp),u=-1!==d?this.internalTrack.fragmentLookupTable[d]:null,h=S(this.internalTrack.fragmentPositionCache,i,e=>e.startTimestamp),m=-1!==h?this.internalTrack.fragmentPositionCache[h]:null,f=Math.max(u?.moofOffset??0,m?.moofOffset??0)||null;let p;for(e?null===f||e.moofOffset>=f?(p=e.moofOffset+e.moofSize,o=e):p=f:p=f??0;;){if(o){const e=o.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>a)break}let e=n.reader.requestSliceRange(p,8,16);if(e instanceof Promise&&(e=await e),!e)break;const t=p,i=Nt(e);if(!i)break;if("moof"===i.name){o=await n.readFragment(t);const{sampleIndex:e,correctSampleFound:i}=r(o);if(i)return this.fetchPacketInFragment(o,e,s);-1!==e&&(c=o,l=e)}p=t+i.totalSize}if(u&&(!c||c.moofOffset{if("vp9"!==this.internalTrack.info.codec||this.internalTrack.info.vp9CodecInfo){if("av1"===this.internalTrack.info.codec&&!this.internalTrack.info.av1CodecInfo){const e=await this.getFirstPacket({});this.internalTrack.info.av1CodecInfo=e&&Le(e.data)}}else{const e=await this.getFirstPacket({});this.internalTrack.info.vp9CodecInfo=e&&ze(e.data)}return{codec:ne(this.internalTrack.info),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0}})()):null}}class jt extends Ht{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return this.internalTrack.info.codec?this.decoderConfig??(this.decoderConfig={codec:oe(this.internalTrack.info),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}):null}}const Kt=(e,t)=>{if(e.presentationTimestamps){const r=S(e.presentationTimestamps,t,e=>e.presentationTimestamp);return-1===r?-1:e.presentationTimestamps[r].sampleIndex}{const r=S(e.sampleTimingEntries,t,e=>e.startDecodeTimestamp);if(-1===r)return-1;const i=e.sampleTimingEntries[r];return i.startIndex+Math.min(Math.floor((t-i.startDecodeTimestamp)/i.delta),i.count-1)}},$t=(e,t)=>{if(!e.keySampleIndices)return Kt(e,t);if(e.presentationTimestamps){const r=S(e.presentationTimestamps,t,e=>e.presentationTimestamp);if(-1===r)return-1;for(let t=r;t>=0;t--){const r=e.presentationTimestamps[t].sampleIndex;if(-1!==w(e.keySampleIndices,r,e=>e))return r}return-1}{const r=Kt(e,t),i=S(e.keySampleIndices,r,e=>e);return e.keySampleIndices[i]??-1}},Qt=(e,r)=>{const i=S(e.sampleTimingEntries,r,e=>e.startIndex),a=e.sampleTimingEntries[i];if(!a||a.startIndex+a.count<=r)return null;let s=a.startDecodeTimestamp+(r-a.startIndex)*a.delta;const n=S(e.sampleCompositionTimeOffsets,r,e=>e.startIndex),o=e.sampleCompositionTimeOffsets[n];o&&r-o.startIndexe.startSampleIndex),d=e.sampleToChunk[l];t(d);const u=d.startChunkIndex+Math.floor((r-d.startSampleIndex)/d.samplesPerChunk),h=e.chunkOffsets[u],m=d.startSampleIndex+(u-d.startChunkIndex)*d.samplesPerChunk;let f=0,p=h;if(1===e.sampleSizes.length)p+=c*(r-m),f+=c*d.samplesPerChunk;else for(let t=m;te)}},Gt=(e,t)=>{if(!e.keySampleIndices)return t+1;const r=S(e.keySampleIndices,t,e=>e);return e.keySampleIndices[r+1]??-1},Xt=(e,t)=>{e.startTimestamp+=t,e.endTimestamp+=t;for(const r of e.samples)r.presentationTimestamp+=t;for(const r of e.presentationTimestamps)r.presentationTimestamp+=t},Yt=e=>{const[t,,,r]=e,i=Math.hypot(t,r),a=t/i,s=r/i,n=-Math.atan2(s,a)*(180/Math.PI);return Number.isFinite(n)?n:0},Jt=e=>0===e.sampleSizes.length;var Zt,er;(er=Zt||(Zt={}))[er.EBML=440786851]="EBML",er[er.EBMLVersion=17030]="EBMLVersion",er[er.EBMLReadVersion=17143]="EBMLReadVersion",er[er.EBMLMaxIDLength=17138]="EBMLMaxIDLength",er[er.EBMLMaxSizeLength=17139]="EBMLMaxSizeLength",er[er.DocType=17026]="DocType",er[er.DocTypeVersion=17031]="DocTypeVersion",er[er.DocTypeReadVersion=17029]="DocTypeReadVersion",er[er.Void=236]="Void",er[er.Segment=408125543]="Segment",er[er.SeekHead=290298740]="SeekHead",er[er.Seek=19899]="Seek",er[er.SeekID=21419]="SeekID",er[er.SeekPosition=21420]="SeekPosition",er[er.Duration=17545]="Duration",er[er.Info=357149030]="Info",er[er.TimestampScale=2807729]="TimestampScale",er[er.MuxingApp=19840]="MuxingApp",er[er.WritingApp=22337]="WritingApp",er[er.Tracks=374648427]="Tracks",er[er.TrackEntry=174]="TrackEntry",er[er.TrackNumber=215]="TrackNumber",er[er.TrackUID=29637]="TrackUID",er[er.TrackType=131]="TrackType",er[er.FlagEnabled=185]="FlagEnabled",er[er.FlagDefault=136]="FlagDefault",er[er.FlagForced=21930]="FlagForced",er[er.FlagOriginal=21934]="FlagOriginal",er[er.FlagHearingImpaired=21931]="FlagHearingImpaired",er[er.FlagVisualImpaired=21932]="FlagVisualImpaired",er[er.FlagCommentary=21935]="FlagCommentary",er[er.FlagLacing=156]="FlagLacing",er[er.Name=21358]="Name",er[er.Language=2274716]="Language",er[er.LanguageBCP47=2274717]="LanguageBCP47",er[er.CodecID=134]="CodecID",er[er.CodecPrivate=25506]="CodecPrivate",er[er.CodecDelay=22186]="CodecDelay",er[er.SeekPreRoll=22203]="SeekPreRoll",er[er.DefaultDuration=2352003]="DefaultDuration",er[er.Video=224]="Video",er[er.PixelWidth=176]="PixelWidth",er[er.PixelHeight=186]="PixelHeight",er[er.AlphaMode=21440]="AlphaMode",er[er.Audio=225]="Audio",er[er.SamplingFrequency=181]="SamplingFrequency",er[er.Channels=159]="Channels",er[er.BitDepth=25188]="BitDepth",er[er.SimpleBlock=163]="SimpleBlock",er[er.BlockGroup=160]="BlockGroup",er[er.Block=161]="Block",er[er.BlockAdditions=30113]="BlockAdditions",er[er.BlockMore=166]="BlockMore",er[er.BlockAdditional=165]="BlockAdditional",er[er.BlockAddID=238]="BlockAddID",er[er.BlockDuration=155]="BlockDuration",er[er.ReferenceBlock=251]="ReferenceBlock",er[er.Cluster=524531317]="Cluster",er[er.Timestamp=231]="Timestamp",er[er.Cues=475249515]="Cues",er[er.CuePoint=187]="CuePoint",er[er.CueTime=179]="CueTime",er[er.CueTrackPositions=183]="CueTrackPositions",er[er.CueTrack=247]="CueTrack",er[er.CueClusterPosition=241]="CueClusterPosition",er[er.Colour=21936]="Colour",er[er.MatrixCoefficients=21937]="MatrixCoefficients",er[er.TransferCharacteristics=21946]="TransferCharacteristics",er[er.Primaries=21947]="Primaries",er[er.Range=21945]="Range",er[er.Projection=30320]="Projection",er[er.ProjectionType=30321]="ProjectionType",er[er.ProjectionPoseRoll=30325]="ProjectionPoseRoll",er[er.Attachments=423732329]="Attachments",er[er.AttachedFile=24999]="AttachedFile",er[er.FileDescription=18046]="FileDescription",er[er.FileName=18030]="FileName",er[er.FileMediaType=18016]="FileMediaType",er[er.FileData=18012]="FileData",er[er.FileUID=18094]="FileUID",er[er.Chapters=272869232]="Chapters",er[er.Tags=307544935]="Tags",er[er.Tag=29555]="Tag",er[er.Targets=25536]="Targets",er[er.TargetTypeValue=26826]="TargetTypeValue",er[er.TargetType=25546]="TargetType",er[er.TagTrackUID=25541]="TagTrackUID",er[er.TagEditionUID=25545]="TagEditionUID",er[er.TagChapterUID=25540]="TagChapterUID",er[er.TagAttachmentUID=25542]="TagAttachmentUID",er[er.SimpleTag=26568]="SimpleTag",er[er.TagName=17827]="TagName",er[er.TagLanguage=17530]="TagLanguage",er[er.TagString=17543]="TagString",er[er.TagBinary=17541]="TagBinary",er[er.ContentEncodings=28032]="ContentEncodings",er[er.ContentEncoding=25152]="ContentEncoding",er[er.ContentEncodingOrder=20529]="ContentEncodingOrder",er[er.ContentEncodingScope=20530]="ContentEncodingScope",er[er.ContentCompression=20532]="ContentCompression",er[er.ContentCompAlgo=16980]="ContentCompAlgo",er[er.ContentCompSettings=16981]="ContentCompSettings",er[er.ContentEncryption=20533]="ContentEncryption";const tr=[Zt.EBML,Zt.Segment],rr=[Zt.SeekHead,Zt.Info,Zt.Cluster,Zt.Tracks,Zt.Cues,Zt.Attachments,Zt.Chapters,Zt.Tags],ir=[...tr,...rr],ar=16,sr=e=>{if(e.remainingLength<1)return null;const t=sa(e);if(e.skip(-1),0===t)return null;let r=1,i=128;for(;0===(t&i);)r++,i>>=1;return e.remainingLength{if(e.remainingLength<1)return null;const t=sa(e);if(0===t)return null;let r=1,i=128;for(;0===(t&i);)r++,i>>=1;if(e.remainingLength{if(t<1||t>8)throw new Error("Bad unsigned int size "+t);let r=0;for(let i=0;i{const t=sr(e);if(null===t)return null;if(e.remainingLength{if(e.remainingLength<1)return null;if(255===sa(e))return;e.skip(-1);const t=nr(e);return null===t?null:72057594037927940!==t?t:void 0},dr=e=>{t(e.remainingLength>=2);const r=cr(e);if(null===r)return null;const i=lr(e);return null===i?null:{id:r,size:i}},ur=(e,t)=>{const r=aa(e,t);let i=0;for(;i{const r=aa(e,t);let i=0;for(;i{if(0===t)return 0;if(4!==t&&8!==t)throw new Error("Bad float size "+t);return 4===t?ba(e):Ta(e)},fr=async(e,t,r,i)=>{const a=new Set(r);let s=t;for(;null===i||ss?i:s,found:!1}},pr=async(e,t,r,i)=>{const a=new Set(r);let s=t;for(;se.computeDuration()));return Math.max(0,...t)}async getTracks(){return await this.readMetadata(),this.segments.flatMap(e=>e.tracks.map(e=>e.inputTrack))}async getMimeType(){await this.readMetadata();const e=await this.getTracks(),t=await Promise.all(e.map(e=>e.getCodecParameterString()));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isWebM?"webm":"x-matroska");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings.filter(Boolean))].join(", ")}"`);return t})({isWebM:this.isWebM,hasVideo:this.segments.some(e=>e.tracks.some(e=>"video"===e.info?.type)),hasAudio:this.segments.some(e=>e.tracks.some(e=>"audio"===e.info?.type)),codecStrings:t.filter(Boolean)})}async getMetadataTags(){await this.readMetadata();for(const t of this.segments)t.metadataTagsCollected||(null!==this.reader.fileSize&&await this.loadSegmentMetadata(t),t.metadataTagsCollected=!0);let e={};for(const t of this.segments)e={...e,...t.metadataTags};return e}readMetadata(){return this.readMetadataPromise??(this.readMetadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,2,ar);if(t instanceof Promise&&(t=await t),!t)break;const r=dr(t);if(!r)break;const a=r.id;let s=r.size;const n=t.filePos;if(a===Zt.EBML){xr(s);let e=this.reader.requestSlice(n,s);if(e instanceof Promise&&(e=await e),!e)break;this.readContiguousElements(e)}else if(a===Zt.Segment){if(await this.readSegment(n,s),void 0===s)break;if(null===this.reader.fileSize)break}else if(a===Zt.Cluster){if(null===this.reader.fileSize)break;if(void 0===s){s=(await fr(this.reader,n,ir,this.reader.fileSize)).pos-n}const e=i(this.segments);e&&(e.elementEndPos=n+s)}xr(s),e=n+s}})())}async readSegment(e,t){this.currentSegment={seekHeadSeen:!1,infoSeen:!1,tracksSeen:!1,cuesSeen:!1,tagsSeen:!1,attachmentsSeen:!1,timestampScale:-1,timestampFactor:-1,duration:-1,seekEntries:[],tracks:[],cuePoints:[],dataStartPos:e,elementEndPos:void 0===t?null:e+t,clusterSeekStartPos:e,lastReadCluster:null,metadataTags:{},metadataTagsCollected:!1},this.segments.push(this.currentSegment);let r=e;for(;null===this.currentSegment.elementEndPos||re.id===a);if(-1!==o){const e=Ar[o].flag;this.currentSegment[e]=!0,xr(s);let t=this.reader.requestSlice(n,s);t instanceof Promise&&(t=await t),t&&this.readContiguousElements(t)}else if(a===Zt.Tags||a===Zt.Attachments){a===Zt.Tags?this.currentSegment.tagsSeen=!0:this.currentSegment.attachmentsSeen=!0,xr(s);let e=this.reader.requestSlice(n,s);e instanceof Promise&&(e=await e),e&&this.readContiguousElements(e)}else if(a===Zt.Cluster){this.currentSegment.clusterSeekStartPos=t;break}if(void 0===s)break;r=n+s}if(this.currentSegment.seekEntries.sort((e,t)=>e.segmentPosition-t.segmentPosition),null!==this.reader.fileSize)for(const n of this.currentSegment.seekEntries){const t=Ar.find(e=>e.id===n.id);if(!t)continue;if(this.currentSegment[t.flag])continue;let r=this.reader.requestSliceRange(e+n.segmentPosition,2,ar);if(r instanceof Promise&&(r=await r),!r)continue;const i=dr(r);if(!i)continue;const{id:a,size:s}=i;if(a!==t.id)continue;xr(s),this.currentSegment[t.flag]=!0;let o=this.reader.requestSlice(r.filePos,s);o instanceof Promise&&(o=await o),o&&this.readContiguousElements(o)}-1===this.currentSegment.timestampScale&&(this.currentSegment.timestampScale=1e6,this.currentSegment.timestampFactor=1e3);for(const n of this.currentSegment.tracks)null!==n.defaultDurationNs&&(n.defaultDuration=this.currentSegment.timestampFactor*n.defaultDurationNs/1e9);this.currentSegment.tracks.sort((e,t)=>Number(t.disposition.default)-Number(e.disposition.default));const i=new Map(this.currentSegment.tracks.map(e=>[e.id,e]));for(const n of this.currentSegment.cuePoints){const e=i.get(n.trackId);e&&e.cuePoints.push(n)}for(const n of this.currentSegment.tracks){n.cuePoints.sort((e,t)=>e.time-t.time);for(let e=0;es&&(s=n.cuePoints.length,a=n);for(const n of this.currentSegment.tracks)0===n.cuePoints.length&&(n.cuePoints=a.cuePoints);this.currentSegment=null}async readCluster(e,r){if(r.lastReadCluster?.elementStartPos===e)return r.lastReadCluster;let a=this.reader.requestSliceRange(e,2,ar);a instanceof Promise&&(a=await a),t(a);const s=e,n=dr(a);t(n);t(n.id===Zt.Cluster);let o=n.size;const c=a.filePos;if(void 0===o){o=(await fr(this.reader,c,ir,r.elementEndPos)).pos-c}let l=this.reader.requestSlice(c,o);l instanceof Promise&&(l=await l);const d={segment:r,elementStartPos:s,elementEndPos:c+o,dataStartPos:c,timestamp:-1,trackData:new Map};if(this.currentCluster=d,l){const e=this.readContiguousElements(l,ir);d.elementEndPos=e}for(const[,u]of d.trackData){const e=u.track;t(u.blocks.length>0);let r=!1;for(let t=0;t({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp);for(let t=0;t({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp));const a=u.blocks[u.presentationTimestamps[0].blockIndex],n=u.blocks[i(u.presentationTimestamps).blockIndex];u.startTimestamp=a.timestamp,u.endTimestamp=n.timestamp+n.duration;const o=S(e.clusterPositionCache,u.startTimestamp,e=>e.startTimestamp);-1!==o&&e.clusterPositionCache[o].elementStartPos===s||e.clusterPositionCache.splice(o+1,0,{elementStartPos:d.elementStartPos,startTimestamp:u.startTimestamp})}return r.lastReadCluster=d,d}getTrackDataInCluster(e,t){let r=e.trackData.get(t);if(!r){const i=e.segment.tracks.find(e=>e.id===t);if(!i)return null;r={track:i,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,blocks:[],presentationTimestamps:[]},e.trackData.set(t,r)}return r}expandLacedBlocks(e,r){for(let i=0;i=2;){const r=e.filePos;if(!this.traverseElement(e,t))return r}return e.filePos}traverseElement(e,i){const a=dr(e);if(!a)return!1;if(i&&i.includes(a.id))return!1;const{id:s,size:n}=a,o=e.filePos;switch(xr(n),s){case Zt.DocType:this.isWebM="webm"===ur(e,n);break;case Zt.Seek:{if(!this.currentSegment)break;const t={id:-1,segmentPosition:-1};this.currentSegment.seekEntries.push(t),this.readContiguousElements(e.slice(o,n)),-1!==t.id&&-1!==t.segmentPosition||this.currentSegment.seekEntries.pop()}break;case Zt.SeekID:{const t=this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.id=or(e,n)}break;case Zt.SeekPosition:{const t=this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.segmentPosition=or(e,n)}break;case Zt.TimestampScale:if(!this.currentSegment)break;this.currentSegment.timestampScale=or(e,n),this.currentSegment.timestampFactor=1e9/this.currentSegment.timestampScale;break;case Zt.Duration:if(!this.currentSegment)break;this.currentSegment.duration=mr(e,n);break;case Zt.TrackEntry:if(!this.currentSegment)break;if(this.currentTrack={id:-1,segment:this.currentSegment,demuxer:this,clusterPositionCache:[],cuePoints:[],disposition:{...te},inputTrack:null,codecId:null,codecPrivate:null,defaultDuration:null,defaultDurationNs:null,name:null,languageCode:D,decodingInstructions:[],info:null},this.readContiguousElements(e.slice(o,n)),!this.currentTrack)break;if(this.currentTrack.decodingInstructions.some(e=>"decompress"!==e.data?.type||e.scope!==Br.Block||e.data.algorithm!==Fr.HeaderStripping)&&(console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`),this.currentTrack=null),this.currentTrack&&-1!==this.currentTrack.id&&this.currentTrack.codecId&&this.currentTrack.info){const e=this.currentTrack.codecId.indexOf("/"),t=-1===e?this.currentTrack.codecId:this.currentTrack.codecId.slice(0,e);if("video"===this.currentTrack.info.type&&-1!==this.currentTrack.info.width&&-1!==this.currentTrack.info.height){this.currentTrack.codecId===gr?(this.currentTrack.info.codec="avc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===kr?(this.currentTrack.info.codec="hevc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===br?this.currentTrack.info.codec="vp8":t===Tr?this.currentTrack.info.codec="vp9":t===yr&&(this.currentTrack.info.codec="av1");const e=this.currentTrack,r=new Rt(this.input,new zr(e));this.currentTrack.inputTrack=r,this.currentSegment.tracks.push(this.currentTrack)}else if("audio"===this.currentTrack.info.type&&-1!==this.currentTrack.info.numberOfChannels&&-1!==this.currentTrack.info.sampleRate){t===wr?(this.currentTrack.info.codec="aac",this.currentTrack.info.aacCodecInfo={isMpeg2:this.currentTrack.codecId.includes("MPEG2")},this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Sr?this.currentTrack.info.codec="mp3":t===Ir?(this.currentTrack.info.codec="opus",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate,this.currentTrack.info.sampleRate=ue):t===vr?(this.currentTrack.info.codec="vorbis",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Pr?(this.currentTrack.info.codec="flac",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):"A_PCM/INT/LIT"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32"):"A_PCM/INT/BIG"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16be":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24be":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32be"):"A_PCM/FLOAT/IEEE"===this.currentTrack.codecId&&(32===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-f32":64===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-f64"));const e=this.currentTrack,r=new Mt(this.input,new Or(e));this.currentTrack.inputTrack=r,this.currentSegment.tracks.push(this.currentTrack)}}this.currentTrack=null;break;case Zt.TrackNumber:if(!this.currentTrack)break;this.currentTrack.id=or(e,n);break;case Zt.TrackType:{if(!this.currentTrack)break;const t=or(e,n);1===t?this.currentTrack.info={type:"video",width:-1,height:-1,rotation:0,codec:null,codecDescription:null,colorSpace:null,alphaMode:!1}:2===t&&(this.currentTrack.info={type:"audio",numberOfChannels:-1,sampleRate:-1,bitDepth:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case Zt.FlagEnabled:if(!this.currentTrack)break;or(e,n)||(this.currentTrack=null);break;case Zt.FlagDefault:if(!this.currentTrack)break;this.currentTrack.disposition.default=!!or(e,n);break;case Zt.FlagForced:if(!this.currentTrack)break;this.currentTrack.disposition.forced=!!or(e,n);break;case Zt.FlagOriginal:if(!this.currentTrack)break;this.currentTrack.disposition.original=!!or(e,n);break;case Zt.FlagHearingImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.hearingImpaired=!!or(e,n);break;case Zt.FlagVisualImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.visuallyImpaired=!!or(e,n);break;case Zt.FlagCommentary:if(!this.currentTrack)break;this.currentTrack.disposition.commentary=!!or(e,n);break;case Zt.CodecID:if(!this.currentTrack)break;this.currentTrack.codecId=ur(e,n);break;case Zt.CodecPrivate:if(!this.currentTrack)break;this.currentTrack.codecPrivate=aa(e,n);break;case Zt.DefaultDuration:if(!this.currentTrack)break;this.currentTrack.defaultDurationNs=or(e,n);break;case Zt.Name:if(!this.currentTrack)break;this.currentTrack.name=hr(e,n);break;case Zt.Language:if(!this.currentTrack)break;if(this.currentTrack.languageCode!==D)break;this.currentTrack.languageCode=ur(e,n),M(this.currentTrack.languageCode)||(this.currentTrack.languageCode=D);break;case Zt.LanguageBCP47:{if(!this.currentTrack)break;const t=ur(e,n).split("-")[0];this.currentTrack.languageCode=t||D}break;case Zt.Video:if("video"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case Zt.PixelWidth:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.width=or(e,n);break;case Zt.PixelHeight:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.height=or(e,n);break;case Zt.AlphaMode:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.alphaMode=1===or(e,n);break;case Zt.Colour:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.colorSpace={},this.readContiguousElements(e.slice(o,n));break;case Zt.MatrixCoefficients:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=or(e,n),r=g[t]??null;this.currentTrack.info.colorSpace.matrix=r}break;case Zt.Range:if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;this.currentTrack.info.colorSpace.fullRange=2===or(e,n);break;case Zt.TransferCharacteristics:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=or(e,n),r=f[t]??null;this.currentTrack.info.colorSpace.transfer=r}break;case Zt.Primaries:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=or(e,n),r=h[t]??null;this.currentTrack.info.colorSpace.primaries=r}break;case Zt.Projection:if("video"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case Zt.ProjectionPoseRoll:{if("video"!==this.currentTrack?.info?.type)break;const t=-mr(e,n);try{this.currentTrack.info.rotation=r(t)}catch{}}break;case Zt.Audio:if("audio"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case Zt.SamplingFrequency:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.sampleRate=mr(e,n);break;case Zt.Channels:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.numberOfChannels=or(e,n);break;case Zt.BitDepth:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.bitDepth=or(e,n);break;case Zt.CuePoint:if(!this.currentSegment)break;this.readContiguousElements(e.slice(o,n)),this.currentCueTime=null;break;case Zt.CueTime:this.currentCueTime=or(e,n);break;case Zt.CueTrackPositions:{if(null===this.currentCueTime)break;t(this.currentSegment);const r={time:this.currentCueTime,trackId:-1,clusterPosition:-1};this.currentSegment.cuePoints.push(r),this.readContiguousElements(e.slice(o,n)),-1!==r.trackId&&-1!==r.clusterPosition||this.currentSegment.cuePoints.pop()}break;case Zt.CueTrack:{const t=this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;t.trackId=or(e,n)}break;case Zt.CueClusterPosition:{const r=this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length-1];if(!r)break;t(this.currentSegment),r.clusterPosition=this.currentSegment.dataStartPos+or(e,n)}break;case Zt.Timestamp:if(!this.currentCluster)break;this.currentCluster.timestamp=or(e,n);break;case Zt.SimpleBlock:{if(!this.currentCluster)break;const t=nr(e);if(null===t)break;const r=this.getTrackDataInCluster(this.currentCluster,t);if(!r)break;const i=la(e),a=sa(e),s=a>>1&3;let c=!!(128&a);"audio"===r.track.info?.type&&r.track.info.codec&&(c=!0);const l=aa(e,n-(e.filePos-o)),d=r.track.decodingInstructions.length>0;r.blocks.push({timestamp:i,duration:0,isKeyFrame:c,data:l,lacing:s,decoded:!d,mainAdditional:null})}break;case Zt.BlockGroup:if(!this.currentCluster)break;this.readContiguousElements(e.slice(o,n)),this.currentBlock=null;break;case Zt.Block:{if(!this.currentCluster)break;const t=nr(e);if(null===t)break;const r=this.getTrackDataInCluster(this.currentCluster,t);if(!r)break;const i=la(e),a=sa(e)>>1&3,s=aa(e,n-(e.filePos-o)),c=r.track.decodingInstructions.length>0;this.currentBlock={timestamp:i,duration:0,isKeyFrame:!0,data:s,lacing:a,decoded:!c,mainAdditional:null},r.blocks.push(this.currentBlock)}break;case Zt.BlockAdditions:this.readContiguousElements(e.slice(o,n));break;case Zt.BlockMore:if(!this.currentBlock)break;this.currentBlockAdditional={addId:1,data:null},this.readContiguousElements(e.slice(o,n)),this.currentBlockAdditional.data&&1===this.currentBlockAdditional.addId&&(this.currentBlock.mainAdditional=this.currentBlockAdditional.data),this.currentBlockAdditional=null;break;case Zt.BlockAdditional:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.data=aa(e,n);break;case Zt.BlockAddID:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.addId=or(e,n);break;case Zt.BlockDuration:if(!this.currentBlock)break;this.currentBlock.duration=or(e,n);break;case Zt.ReferenceBlock:if(!this.currentBlock)break;this.currentBlock.isKeyFrame=!1;break;case Zt.Tag:this.currentTagTargetIsMovie=!0,this.readContiguousElements(e.slice(o,n));break;case Zt.Targets:this.readContiguousElements(e.slice(o,n));break;case Zt.TargetTypeValue:50!==or(e,n)&&(this.currentTagTargetIsMovie=!1);break;case Zt.TagTrackUID:case Zt.TagEditionUID:case Zt.TagChapterUID:case Zt.TagAttachmentUID:this.currentTagTargetIsMovie=!1;break;case Zt.SimpleTag:if(!this.currentTagTargetIsMovie)break;this.currentSimpleTagName=null,this.readContiguousElements(e.slice(o,n));break;case Zt.TagName:this.currentSimpleTagName=hr(e,n);break;case Zt.TagString:{if(!this.currentSimpleTagName)break;const t=hr(e,n);this.processTagValue(this.currentSimpleTagName,t)}break;case Zt.TagBinary:{if(!this.currentSimpleTagName)break;const t=aa(e,n);this.processTagValue(this.currentSimpleTagName,t)}break;case Zt.AttachedFile:{if(!this.currentSegment)break;this.currentAttachedFile={fileUid:null,fileName:null,fileMediaType:null,fileData:null,fileDescription:null},this.readContiguousElements(e.slice(o,n));const t=this.currentSegment.metadataTags;if(this.currentAttachedFile.fileUid&&this.currentAttachedFile.fileData&&(t.raw??(t.raw={}),t.raw[this.currentAttachedFile.fileUid.toString()]=new ee(this.currentAttachedFile.fileData,this.currentAttachedFile.fileMediaType??void 0,this.currentAttachedFile.fileName??void 0,this.currentAttachedFile.fileDescription??void 0)),this.currentAttachedFile.fileMediaType?.startsWith("image/")&&this.currentAttachedFile.fileData){const e=this.currentAttachedFile.fileName;let r="unknown";if(e){const t=e.toLowerCase();t.startsWith("cover.")?r="coverFront":t.startsWith("back.")&&(r="coverBack")}t.images??(t.images=[]),t.images.push({data:this.currentAttachedFile.fileData,mimeType:this.currentAttachedFile.fileMediaType,kind:r,name:this.currentAttachedFile.fileName??void 0,description:this.currentAttachedFile.fileDescription??void 0})}this.currentAttachedFile=null}break;case Zt.FileUID:if(!this.currentAttachedFile)break;this.currentAttachedFile.fileUid=((e,t)=>{if(t<1)throw new Error("Bad unsigned int size "+t);let r=0n;for(let i=0;it.order-e.order);break;case Zt.ContentEncoding:this.currentDecodingInstruction={order:0,scope:Br.Block,data:null},this.readContiguousElements(e.slice(o,n)),this.currentDecodingInstruction.data&&this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction),this.currentDecodingInstruction=null;break;case Zt.ContentEncodingOrder:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.order=or(e,n);break;case Zt.ContentEncodingScope:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.scope=or(e,n);break;case Zt.ContentCompression:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decompress",algorithm:Fr.Zlib,settings:null},this.readContiguousElements(e.slice(o,n));break;case Zt.ContentCompAlgo:if("decompress"!==this.currentDecodingInstruction?.data?.type)break;this.currentDecodingInstruction.data.algorithm=or(e,n);break;case Zt.ContentCompSettings:if("decompress"!==this.currentDecodingInstruction?.data?.type)break;this.currentDecodingInstruction.data.settings=aa(e,n);break;case Zt.ContentEncryption:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decrypt"}}return e.filePos=o+n,!0}decodeBlockData(e,r){t(e.decodingInstructions.length>0);let i=r;for(const a of e.decodingInstructions)if(t(a.data),"decompress"===a.data.type)if(a.data.algorithm===Fr.HeaderStripping)if(a.data.settings&&a.data.settings.length>0){const e=a.data.settings,t=new Uint8Array(e.length+i.length);t.set(e,0),t.set(i,e.length),i=t}return i}processTagValue(e,t){var r;if(!this.currentSegment?.metadataTags)return;const i=this.currentSegment.metadataTags;if(i.raw??(i.raw={}),(r=i.raw)[e]??(r[e]=t),"string"===typeof t)switch(e.toLowerCase()){case"title":i.title??(i.title=t);break;case"description":i.description??(i.description=t);break;case"artist":i.artist??(i.artist=t);break;case"album":i.album??(i.album=t);break;case"album_artist":i.albumArtist??(i.albumArtist=t);break;case"genre":i.genre??(i.genre=t);break;case"comment":i.comment??(i.comment=t);break;case"lyrics":i.lyrics??(i.lyrics=t);break;case"date":{const e=new Date(t);Number.isNaN(e.getTime())||(i.date??(i.date=e))}break;case"track_number":case"part_number":{const e=t.split("/"),r=Number.parseInt(e[0],10),a=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(i.trackNumber??(i.trackNumber=r)),a&&Number.isInteger(a)&&a>0&&(i.tracksTotal??(i.tracksTotal=a))}break;case"disc_number":case"disc":{const e=t.split("/"),r=Number.parseInt(e[0],10),a=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(i.discNumber??(i.discNumber=r)),a&&Number.isInteger(a)&&a>0&&(i.discsTotal??(i.discsTotal=a))}}}}class Nr{constructor(e){this.internalTrack=e,this.packetToClusterLocation=new WeakMap}getId(){return this.internalTrack.id}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.codecId}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}async getFirstTimestamp(){const e=await this.getFirstPacket({metadataOnly:!0});return e?.timestamp??0}getTimeResolution(){return this.internalTrack.segment.timestampFactor}getDisposition(){return this.internalTrack.disposition}async getFirstPacket(e){return this.performClusterLookup(null,e=>e.trackData.get(this.internalTrack.id)?{blockIndex:0,correctBlockFound:!0}:{blockIndex:-1,correctBlockFound:!1},-1/0,1/0,e)}intoTimescale(e){return A(e*this.internalTrack.segment.timestampFactor)}async getPacket(e,t){const r=this.intoTimescale(e);return this.performClusterLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const i=S(t.presentationTimestamps,r,e=>e.timestamp);return{blockIndex:-1!==i?t.presentationTimestamps[i].blockIndex:-1,correctBlockFound:-1!==i&&r{if(e===r.cluster){const t=e.trackData.get(this.internalTrack.id);if(r.blockIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const i=x(t.presentationTimestamps,e=>t.blocks[e.blockIndex].isKeyFrame&&e.timestamp<=r);return{blockIndex:-1!==i?t.presentationTimestamps[i].blockIndex:-1,correctBlockFound:-1!==i&&r{if(e===i.cluster){const t=e.trackData.get(this.internalTrack.id).blocks.findIndex((e,t)=>e.isKeyFrame&&t>i.blockIndex);if(-1!==t)return{blockIndex:t,correctBlockFound:!0}}else{const r=e.trackData.get(this.internalTrack.id);if(r&&null!==r.firstKeyFrameTimestamp){const e=r.blocks.findIndex(e=>e.isKeyFrame);return t(-1!==e),{blockIndex:e,correctBlockFound:!0}}}return{blockIndex:-1,correctBlockFound:!1}},-1/0,1/0,r)}async fetchPacketInCluster(e,r,i){if(-1===r)return null;const a=e.trackData.get(this.internalTrack.id).blocks[r];t(a),a.decoded||(a.data=this.internalTrack.demuxer.decodeBlockData(this.internalTrack,a.data),a.decoded=!0);const s=i.metadataOnly?Ge:a.data,n=a.timestamp/this.internalTrack.segment.timestampFactor,o=a.duration/this.internalTrack.segment.timestampFactor,c={};a.mainAdditional&&"video"===this.internalTrack.info?.type&&this.internalTrack.info.alphaMode&&(c.alpha=i.metadataOnly?Ge:a.mainAdditional,c.alphaByteLength=a.mainAdditional.byteLength);const l=new Xe(s,a.isKeyFrame?"key":"delta",n,o,e.dataStartPos+r,a.data.byteLength,c);return this.packetToClusterLocation.set(l,{cluster:e,blockIndex:r}),l}async performClusterLookup(e,r,i,a,s){const{demuxer:n,segment:o}=this.internalTrack;let c=null,l=null,d=-1;if(e){const{blockIndex:t,correctBlockFound:i}=r(e);if(i)return this.fetchPacketInCluster(e,t,s);-1!==t&&(l=e,d=t)}const u=S(this.internalTrack.cuePoints,i,e=>e.time),h=-1!==u?this.internalTrack.cuePoints[u]:null,m=S(this.internalTrack.clusterPositionCache,i,e=>e.startTimestamp),f=-1!==m?this.internalTrack.clusterPositionCache[m]:null,p=Math.max(h?.clusterPosition??0,f?.elementStartPos??0)||null;let g;for(e?null===p||e.elementStartPos>=p?(g=e.elementEndPos,c=e):g=p:g=p??o.clusterSeekStartPos;null===o.elementEndPos||g<=o.elementEndPos-2;){if(c){const e=c.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>a)break}let e=n.reader.requestSliceRange(g,2,ar);if(e instanceof Promise&&(e=await e),!e)break;const i=g,u=dr(e);if(!u||!rr.includes(u.id)&&u.id!==Zt.Void){const e=await pr(n.reader,i,rr,Math.min(o.elementEndPos??1/0,i+Rr));if(e){g=e;continue}break}const h=u.id;let m=u.size;const f=e.filePos;if(h===Zt.Cluster){c=await n.readCluster(i,o),m=c.elementEndPos-f;const{blockIndex:e,correctBlockFound:t}=r(c);if(t)return this.fetchPacketInCluster(c,e,s);-1!==e&&(l=c,d=e)}if(void 0===m){t(h!==Zt.Cluster);m=(await fr(n.reader,f,ir,o.elementEndPos)).pos-f}const p=f+m;if(null===o.elementEndPos){let e=n.reader.requestSliceRange(p,2,ar);if(e instanceof Promise&&(e=await e),!e)break;if(cr(e)===Zt.Segment){o.elementEndPos=p;break}}g=p}if(h&&(!l||l.elementStartPos{let e=null;return("vp9"===this.internalTrack.info.codec||"av1"===this.internalTrack.info.codec||"avc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription||"hevc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription)&&(e=await this.getFirstPacket({})),{codec:ne({width:this.internalTrack.info.width,height:this.internalTrack.info.height,codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,colorSpace:this.internalTrack.info.colorSpace,avcType:1,avcCodecInfo:"avc"===this.internalTrack.info.codec&&e?Pe(e.data):null,hevcCodecInfo:"hevc"===this.internalTrack.info.codec&&e?Be(e.data):null,vp9CodecInfo:"vp9"===this.internalTrack.info.codec&&e?ze(e.data):null,av1CodecInfo:"av1"===this.internalTrack.info.codec&&e?Le(e.data):null}),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0}})()):null}}class Or extends Nr{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return this.internalTrack.info.codec?this.decoderConfig??(this.decoderConfig={codec:oe({codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,aacCodecInfo:this.internalTrack.info.aacCodecInfo}),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}):null}}const Lr=[44100,48e3,32e3],Ur=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1,-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1,-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1],Vr=(e,t)=>{const r=e>>>24,i=e>>>16&255,a=e>>>8&255,s=255&e;if(255!==r&&255!==i&&255!==a&&255!==s)return{header:null,bytesAdvanced:4};if(255!==r)return{header:null,bytesAdvanced:1};if(224!==(224&i))return{header:null,bytesAdvanced:1};let n=0,o=0;16&i?n=8&i?0:1:(n=1,o=1);const c=i>>3&3,l=i>>1&3,d=(a>>2&3)%3,u=s>>6&3,h=s>>4&3,m=s>>3&1,f=s>>2&1,p=3&s,g=Ur[16*n*4+16*l+(a>>4&15)];if(-1===g)return{header:null,bytesAdvanced:1};const k=1e3*g,b=Lr[d]>>n+o,T=((e,t,r,i,a)=>0===t?0:1===t?Math.floor(144*r/(i<>1&1);if(null!==t&&t{let t=2130706432,r=0;for(;0!==t;)r>>=1,r|=e&t,t>>=8;return r};var Hr,Wr,jr,Kr;(Wr=Hr||(Hr={}))[Wr.Unsynchronisation=128]="Unsynchronisation",Wr[Wr.ExtendedHeader=64]="ExtendedHeader",Wr[Wr.ExperimentalIndicator=32]="ExperimentalIndicator",Wr[Wr.Footer=16]="Footer",(Kr=jr||(jr={}))[Kr.ISO_8859_1=0]="ISO_8859_1",Kr[Kr.UTF_16_WITH_BOM=1]="UTF_16_WITH_BOM",Kr[Kr.UTF_16_BE_NO_BOM=2]="UTF_16_BE_NO_BOM",Kr[Kr.UTF_8=3]="UTF_8";const $r=128,Qr=["Blues","Classic rock","Country","Dance","Disco","Funk","Grunge","Hip-hop","Jazz","Metal","New age","Oldies","Other","Pop","Rhythm and blues","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death metal","Pranks","Soundtrack","Euro-techno","Ambient","Trip-hop","Vocal","Jazz & funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound clip","Gospel","Noise","Alternative rock","Bass","Soul","Punk","Space","Meditative","Instrumental pop","Instrumental rock","Ethnic","Gothic","Darkwave","Techno-industrial","Electronic","Pop-folk","Eurodance","Dream","Southern rock","Comedy","Cult","Gangsta","Top 40","Christian rap","Pop/funk","Jungle music","Native US","Cabaret","New wave","Psychedelic","Rave","Showtunes","Trailer","Lo-fi","Tribal","Acid punk","Acid jazz","Polka","Retro","Musical","Rock 'n' roll","Hard rock","Folk","Folk rock","National folk","Swing","Fast fusion","Bebop","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic rock","Progressive rock","Psychedelic rock","Symphonic rock","Slow rock","Big band","Chorus","Easy listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber music","Sonata","Symphony","Booty bass","Primus","Porn groove","Satire","Slow jam","Club","Tango","Samba","Folklore","Ballad","Power ballad","Rhythmic Soul","Freestyle","Duet","Punk rock","Drum solo","A cappella","Euro-house","Dance hall","Goa music","Drum & bass","Club-house","Hardcore techno","Terror","Indie","Britpop","Negerpunk","Polsk punk","Beat","Christian gangsta rap","Heavy metal","Black metal","Crossover","Contemporary Christian","Christian rock","Merengue","Salsa","Thrash metal","Anime","Jpop","Synthpop","Christmas","Art rock","Baroque","Bhangra","Big beat","Breakbeat","Chillout","Downtempo","Dub","EBM","Eclectic","Electro","Electroclash","Emo","Experimental","Garage","Global","IDM","Illbient","Industro-Goth","Jam Band","Krautrock","Leftfield","Lounge","Math rock","New romantic","Nu-breakz","Post-punk","Post-rock","Psytrance","Shoegaze","Space rock","Trop rock","World music","Neoclassical","Audiobook","Audio theatre","Neue Deutsche Welle","Podcast","Indie rock","G-Funk","Dubstep","Garage rock","Psybient"],Gr=(e,t)=>{const r=aa(e,t),i=Q(r.indexOf(0),r.length),a=r.subarray(0,i);let s="";for(let n=0;n{const t=e.filePos,r=ya(e,3),i=sa(e),a=sa(e),s=sa(e),n=ua(e);if("ID3"!==r||255===i||255===a||0!==(2155905152&n))return e.filePos=t,null;return{majorVersion:i,revision:a,flags:s,size:qr(n)}},Yr=(e,t,r)=>{var i,a,s,n;if(![2,3,4].includes(t.majorVersion))return void console.warn(`Unsupported ID3v2 major version: ${t.majorVersion}`);const o=aa(e,t.size),c=new Jr(t,o);if(t.flags&Hr.Footer&&c.removeFooter(),t.flags&Hr.Unsynchronisation&&3===t.majorVersion&&c.ununsynchronizeAll(),t.flags&Hr.ExtendedHeader){const e=c.readU32();3===t.majorVersion?c.pos+=e:c.pos+=e-4}for(;c.pos<=c.bytes.length-c.frameHeaderSize();){const e=c.readId3V2Frame();if(!e)break;const o=c.pos,l=c.pos+e.size;let d=!1,u=!1,h=!1;if(3===t.majorVersion?(d=!!(64&e.flags),u=!!(128&e.flags)):4===t.majorVersion&&(d=!!(4&e.flags),u=!!(8&e.flags),h=!!(2&e.flags)||!!(t.flags&Hr.Unsynchronisation)),d)console.warn(`Skipping encrypted ID3v2 frame ${e.id}`),c.pos=l;else if(u)console.warn(`Skipping compressed ID3v2 frame ${e.id}`),c.pos=l;else{switch(h&&c.ununsynchronizeRegion(c.pos,l),r.raw??(r.raw={}),"T"===e.id[0]?(i=r.raw)[a=e.id]??(i[a]=c.readId3V2EncodingAndText(l)):(s=r.raw)[n=e.id]??(s[n]=c.readBytes(e.size)),c.pos=o,e.id){case"TIT2":case"TT2":r.title??(r.title=c.readId3V2EncodingAndText(l));break;case"TIT3":case"TT3":r.description??(r.description=c.readId3V2EncodingAndText(l));break;case"TPE1":case"TP1":r.artist??(r.artist=c.readId3V2EncodingAndText(l));break;case"TALB":case"TAL":r.album??(r.album=c.readId3V2EncodingAndText(l));break;case"TPE2":case"TP2":r.albumArtist??(r.albumArtist=c.readId3V2EncodingAndText(l));break;case"TRCK":case"TRK":{const e=c.readId3V2EncodingAndText(l).split("/"),t=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(r.trackNumber??(r.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&(r.tracksTotal??(r.tracksTotal=i))}break;case"TPOS":case"TPA":{const e=c.readId3V2EncodingAndText(l).split("/"),t=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(r.discNumber??(r.discNumber=t)),i&&Number.isInteger(i)&&i>0&&(r.discsTotal??(r.discsTotal=i))}break;case"TCON":case"TCO":{const e=c.readId3V2EncodingAndText(l);let t=/^\((\d+)\)/.exec(e);if(t){const e=Number.parseInt(t[1]);if(void 0!==Qr[e]){r.genre??(r.genre=Qr[e]);break}}if(t=/^\d+$/.exec(e),t){const e=Number.parseInt(t[0]);if(void 0!==Qr[e]){r.genre??(r.genre=Qr[e]);break}}r.genre??(r.genre=e)}break;case"TDRC":case"TDAT":{const e=c.readId3V2EncodingAndText(l),t=new Date(e);Number.isNaN(t.getTime())||(r.date??(r.date=t))}break;case"TYER":case"TYE":{const e=c.readId3V2EncodingAndText(l),t=Number.parseInt(e,10);Number.isInteger(t)&&(r.date??(r.date=new Date(t,0,1)))}break;case"USLT":case"ULT":{const e=c.readU8();c.pos+=3,c.readId3V2Text(e,l),r.lyrics??(r.lyrics=c.readId3V2Text(e,l))}break;case"COMM":case"COM":{const e=c.readU8();c.pos+=3,c.readId3V2Text(e,l),r.comment??(r.comment=c.readId3V2Text(e,l))}break;case"APIC":case"PIC":{const e=c.readId3V2TextEncoding();let i;if(2===t.majorVersion){const e=c.readAscii(3);i="PNG"===e?"image/png":"JPG"===e?"image/jpeg":"image/*"}else i=c.readId3V2Text(e,l);const a=c.readU8(),s=c.readId3V2Text(e,l).trimEnd(),n=l-c.pos;if(n>=0){const e=c.readBytes(n);r.images||(r.images=[]),r.images.push({data:e,mimeType:i,kind:3===a?"coverFront":4===a?"coverBack":"unknown",description:s})}}break;default:c.pos+=e.size}c.pos=l}}};class Jr{constructor(e,t){this.header=e,this.bytes=t,this.pos=0,this.view=new DataView(t.buffer,t.byteOffset,t.byteLength)}frameHeaderSize(){return 2===this.header.majorVersion?6:10}ununsynchronizeAll(){const e=[];for(let t=0;t{const t=this.pos+e;if(t>this.bytes.length)return!1;if(t<=this.bytes.length-this.frameHeaderSize()){this.pos+=e;const t=this.readAscii(4);if("\0\0\0\0"!==t&&!/[0-9A-Z]{4}/.test(t))return!1}return!0};if(!s(r)){const e=4===this.header.majorVersion?t:qr(t);s(e)&&(r=e)}return this.pos=a,{id:e,size:r,flags:i}}}readId3V2TextEncoding(){const e=this.readU8();if(e>3)throw new Error(`Unsupported text encoding: ${e}`);return e}readId3V2Text(e,t){const r=this.pos,i=this.readBytes(t-this.pos);switch(e){case jr.ISO_8859_1:{let e="";for(let t=0;t0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(2,t))}if(254===i[0]&&255===i[1]){const e=new TextDecoder("utf-16be"),t=Q(i.findIndex((e,t)=>0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(2,t))}{const e=Q(i.findIndex(e=>0===e),i.length);return this.pos=r+Math.min(e+1,i.length),l.decode(i.subarray(0,e))}case jr.UTF_16_BE_NO_BOM:{const e=new TextDecoder("utf-16be"),t=Q(i.findIndex((e,t)=>0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(0,t))}case jr.UTF_8:{const e=Q(i.findIndex(e=>0===e),i.length);return this.pos=r+Math.min(e+1,i.length),l.decode(i.subarray(0,e))}}}readId3V2EncodingAndText(e){if(this.pos>=e)return"";const t=this.readId3V2TextEncoding();return this.readId3V2Text(t,e)}}const Zr=async(e,t,r)=>{let i=t;for(;null===r||i{for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)await this.advanceReader();if(!this.firstFrameHeader)throw new Error("No valid MP3 frame found.");this.tracks=[new Mt(this.input,new ti(this))]})())}async advanceReader(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,10);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const t=Xr(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}const e=await Zr(this.reader,this.lastLoadedPos,this.reader.fileSize);if(!e)return void(this.lastSampleLoaded=!0);const t=e.header;this.lastLoadedPos=e.startPos+t.totalSize-1;const r=(i=t.mpegVersionId,a=t.channel,3===i?3===a?21:36:3===a?13:21);var i,a;let s=this.reader.requestSlice(e.startPos+r,4);if(s instanceof Promise&&(s=await s),s){const e=ua(s);if(1483304551===e||1231971951===e)return}this.firstFrameHeader||(this.firstFrameHeader=t),t.sampleRate!==this.firstFrameHeader.sampleRate&&console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${t.sampleRate} Hz. Might be a bug, so please report this file.`);const n=t.audioSamplesInFrame/this.firstFrameHeader.sampleRate,o={timestamp:this.nextTimestampInSamples/this.firstFrameHeader.sampleRate,duration:n,dataStart:e.startPos,dataSize:t.totalSize};this.loadedSamples.push(o),this.nextTimestampInSamples+=t.audioSamplesInFrame}async getMimeType(){return"audio/mpeg"}async getTracks(){return await this.readMetadata(),this.tracks}async computeDuration(){await this.readMetadata();const e=this.tracks[0];return t(e),e.computeDuration()}async getMetadataTags(){const e=await this.readingMutex.acquire();try{if(await this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0,r=!1;for(;;){let t=this.reader.requestSlice(e,10);if(t instanceof Promise&&(t=await t),!t)break;const i=Xr(t);if(!i)break;r=!0;let a=this.reader.requestSlice(t.filePos,i.size);if(a instanceof Promise&&(a=await a),!a)break;Yr(a,i,this.metadataTags),e=t.filePos+i.size}if(!r&&null!==this.reader.fileSize&&this.reader.fileSize>=$r){let e=this.reader.requestSlice(this.reader.fileSize-$r,$r);e instanceof Promise&&(e=await e),t(e);"TAG"===ya(e,3)&&((e,t)=>{var r;const i=e.filePos;t.raw??(t.raw={}),(r=t.raw).TAG??(r.TAG=aa(e,125)),e.filePos=i;const a=Gr(e,30);a&&(t.title??(t.title=a));const s=Gr(e,30);s&&(t.artist??(t.artist=s));const n=Gr(e,30);n&&(t.album??(t.album=n));const o=Gr(e,4),c=Number.parseInt(o,10);Number.isInteger(c)&&c>0&&(t.date??(t.date=new Date(c,0,1)));const l=aa(e,30);let d;if(0===l[28]&&0!==l[29]){const r=l[29];r>0&&(t.trackNumber??(t.trackNumber=r)),e.skip(-30),d=Gr(e,28),e.skip(2)}else e.skip(-30),d=Gr(e,30);d&&(t.comment??(t.comment=d));const u=sa(e);ue.timestamp);if(-1===r)throw new Error("Packet was not created from this track.");const i=r+1;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{r()}}async getPacket(e,t){const r=await this.demuxer.readingMutex.acquire();try{for(;;){const r=S(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===r&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(r,t);if(r>=0&&r+1>>0&4294967295}const ai=e=>{const t=c(e),r=t.getUint32(22,!0);t.setUint32(22,0,!0);let i=0;for(let a=0;a>>24^t])>>>0}return t.setUint32(22,r,!0),i},si=(e,r,i)=>{let a=0,s=null;if(e.length>0)if("vorbis"===r.codec){t(r.vorbisInfo);const n=(1<<(e=>{let t=0;for(;e;)t++,e>>=1;return t})(r.vorbisInfo.modeBlockflags.length-1))-1<<1,o=(e[0]&n)>>1;if(o>=r.vorbisInfo.modeBlockflags.length)throw new Error("Invalid mode number.");let c=i;const l=r.vorbisInfo.modeBlockflags[o];if(s=r.vorbisInfo.blocksizes[l],1===l){const t=1+(1|n),i=e[0]&t?1:0;c=r.vorbisInfo.blocksizes[i]}a=null!==c?c+s>>2:0}else if("opus"===r.codec){a=(e=>{const t=e[0]>>3;return{durationInSamples:Ue[t]}})(e).durationInSamples}return{durationInSamples:a,vorbisBlockSize:s}},ni=27,oi=282,ci=e=>{const t=e.filePos;if(ha(e)!==ri)return null;e.skip(1);const r=sa(e),i=ka(e),a=ha(e),s=ha(e),n=ha(e),o=sa(e),c=new Uint8Array(o);for(let u=0;ue+t,0);return{headerStartPos:t,totalSize:l+d,dataStartPos:t+l,dataSize:d,headerType:r,granulePosition:i,serialNumber:a,sequenceNumber:s,checksum:n,lacingValues:c}},li=(e,t)=>{for(;e.filePos>>8&255)===r||(t>>>16&255)===r||(t>>>24&255)===r){if(e.skip(-4),t===ri)return!0;e.skip(1)}}return!1};class di extends Ke{constructor(e){super(e),this.metadataPromise=null,this.bitstreams=[],this.tracks=[],this.metadataTags={},this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,ni,oi);if(t instanceof Promise&&(t=await t),!t)break;const r=ci(t);if(!r)break;if(!!!(2&r.headerType))break;this.bitstreams.push({serialNumber:r.serialNumber,bosPage:r,description:null,numberOfChannels:-1,sampleRate:-1,codecInfo:{codec:null,vorbisInfo:null,opusInfo:null},lastMetadataPacket:null}),e=r.headerStartPos+r.totalSize}for(const t of this.bitstreams){const e=await this.readPacket(t.bosPage,0);e&&(e.data.byteLength>=7&&1===e.data[0]&&118===e.data[1]&&111===e.data[2]&&114===e.data[3]&&98===e.data[4]&&105===e.data[5]&&115===e.data[6]?await this.readVorbisMetadata(e,t):e.data.byteLength>=8&&79===e.data[0]&&112===e.data[1]&&117===e.data[2]&&115===e.data[3]&&72===e.data[4]&&101===e.data[5]&&97===e.data[6]&&100===e.data[7]&&await this.readOpusMetadata(e,t),null!==t.codecInfo.codec&&this.tracks.push(new Mt(this.input,new ui(t,this))))}})())}async readVorbisMetadata(e,t){let r=await this.findNextPacketStart(e);if(!r)return;const i=await this.readPacket(r.startPage,r.startSegmentIndex);if(!i)return;if(r=await this.findNextPacketStart(i),!r)return;const a=await this.readPacket(r.startPage,r.startSegmentIndex);if(!a)return;if(3!==i.data[0]||5!==a.data[0])return;const s=[],n=e=>{for(;s.push(Math.min(255,e)),!(e<255);)e-=255};n(e.data.length),n(i.data.length);const o=new Uint8Array(1+s.length+e.data.length+i.data.length+a.data.length);o[0]=2,o.set(s,1),o.set(e.data,1+s.length),o.set(i.data,1+s.length+e.data.length),o.set(a.data,1+s.length+e.data.length+i.data.length),t.codecInfo.codec="vorbis",t.description=o,t.lastMetadataPacket=a;const l=c(e.data);t.numberOfChannels=l.getUint8(11),t.sampleRate=l.getUint32(12,!0);const d=l.getUint8(28);t.codecInfo.vorbisInfo={blocksizes:[1<<(15&d),1<<(d>>4)],modeBlockflags:Ve(a.data).modeBlockflags},je(i.data.subarray(7),this.metadataTags)}async readOpusMetadata(e,t){const r=await this.findNextPacketStart(e);if(!r)return;const i=await this.readPacket(r.startPage,r.startSegmentIndex);if(!i)return;t.codecInfo.codec="opus",t.description=e.data,t.lastMetadataPacket=i;const a=(e=>{const t=c(e),r=t.getUint8(9),i=t.getUint16(10,!0),a=t.getUint32(12,!0),s=t.getInt16(16,!0),n=t.getUint8(18);let o=null;return n&&(o=e.subarray(19,21+r)),{outputChannelCount:r,preSkip:i,inputSampleRate:a,outputGain:s,channelMappingFamily:n,channelMappingTable:o}})(e.data);t.numberOfChannels=a.outputChannelCount,t.sampleRate=ue,t.codecInfo.opusInfo={preSkip:a.preSkip},je(i.data.subarray(8),this.metadataTags)}async readPacket(e,r){t(re+t.length,0);if(0===c)return null;const l=new Uint8Array(c);let d=0;for(let t=0;t{let t="audio/ogg";e.codecStrings&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({codecStrings:(await Promise.all(this.tracks.map(e=>e.getCodecParameterString()))).filter(Boolean)})}async getTracks(){return await this.readMetadata(),this.tracks}async computeDuration(){const e=await this.getTracks(),t=await Promise.all(e.map(e=>e.computeDuration()));return Math.max(0,...t)}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}}class ui{constructor(e,t){this.bitstream=e,this.demuxer=t,this.encodedPacketToMetadata=new WeakMap,this.sequentialScanCache=[],this.sequentialScanMutex=new b,this.internalSampleRate="opus"===e.codecInfo.codec?ue:e.sampleRate}getId(){return this.bitstream.serialNumber}getNumberOfChannels(){return this.bitstream.numberOfChannels}getSampleRate(){return this.bitstream.sampleRate}getTimeResolution(){return this.bitstream.sampleRate}getCodec(){return this.bitstream.codecInfo.codec}getInternalCodecId(){return null}async getDecoderConfig(){return t(this.bitstream.codecInfo.codec),{codec:this.bitstream.codecInfo.codec,numberOfChannels:this.bitstream.numberOfChannels,sampleRate:this.bitstream.sampleRate,description:this.bitstream.description??void 0}}getName(){return null}getLanguageCode(){return D}getDisposition(){return{...te}}async getFirstTimestamp(){return 0}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}granulePositionToTimestampInSamples(e){return"opus"===this.bitstream.codecInfo.codec?(t(this.bitstream.codecInfo.opusInfo),e-this.bitstream.codecInfo.opusInfo.preSkip):e}createEncodedPacketFromOggPacket(e,t,r){if(!e)return null;const{durationInSamples:i,vorbisBlockSize:a}=si(e.data,this.bitstream.codecInfo,t.vorbisLastBlocksize),s=new Xe(r.metadataOnly?Ge:e.data,"key",Math.max(0,t.timestampInSamples)/this.internalSampleRate,i/this.internalSampleRate,e.endPage.headerStartPos+e.endSegmentIndex,e.data.byteLength);return this.encodedPacketToMetadata.set(s,{packet:e,timestampInSamples:t.timestampInSamples,durationInSamples:i,vorbisLastBlockSize:t.vorbisLastBlocksize,vorbisBlockSize:a}),s}async getFirstPacket(e){t(this.bitstream.lastMetadataPacket);const r=await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!r)return null;let i=0;"opus"===this.bitstream.codecInfo.codec&&(t(this.bitstream.codecInfo.opusInfo),i-=this.bitstream.codecInfo.opusInfo.preSkip);const a=await this.demuxer.readPacket(r.startPage,r.startSegmentIndex);return this.createEncodedPacketFromOggPacket(a,{timestampInSamples:i,vorbisLastBlocksize:null},e)}async getNextPacket(e,t){const r=this.encodedPacketToMetadata.get(e);if(!r)throw new Error("Packet was not created from this track.");const i=await this.demuxer.findNextPacketStart(r.packet);if(!i)return null;const a=r.timestampInSamples+r.durationInSamples,s=await this.demuxer.readPacket(i.startPage,i.startSegmentIndex);return this.createEncodedPacketFromOggPacket(s,{timestampInSamples:a,vorbisLastBlocksize:r.vorbisBlockSize},t)}async getPacket(e,r){if(null===this.demuxer.reader.fileSize)return this.getPacketSequential(e,r);const i=A(e*this.internalSampleRate);if(0===i)return this.getFirstPacket(r);if(i<0)return null;t(this.bitstream.lastMetadataPacket);const a=await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!a)return null;let s=a.startPage,n=this.demuxer.reader.fileSize;const o=[s];e:for(;s.headerStartPos+s.totalSizei?n=d.headerStartPos:(s=d,o.push(d));continue e}a=d.headerStartPos+d.totalSize}}let c=a.startPage;for(const t of o){if(t.granulePosition===s.granulePosition)break;(!c||t.headerStartPos>c.headerStartPos)&&(c=t)}let l=c;const d=[l];for(;l.serialNumber!==this.bitstream.serialNumber||l.granulePosition!==s.granulePosition;){const e=l.headerStartPos+l.totalSize;let r=this.demuxer.reader.requestSliceRange(e,ni,oi);r instanceof Promise&&(r=await r),t(r);const i=ci(r);t(i),l=i,l.serialNumber===this.bitstream.serialNumber&&d.push(l)}t(-1!==l.granulePosition);let u,h,m=null,f=l,p=0;if(l.headerStartPos===a.startPage.headerStartPos)u=this.granulePositionToTimestampInSamples(0),h=!0,m=0;else{u=0,h=!1;for(let t=l.lacingValues.length-1;t>=0;t--){if(l.lacingValues[t]<255){m=t+1;break}}if(null===m)throw new Error("Invalid page with granule position: no packets end on this page.");p=m-1;const e={data:Ge,endPage:f,endSegmentIndex:p};if(await this.demuxer.findNextPacketStart(e)){const e=mi(d,l,m);t(e);const r=hi(d,e.page,e.segmentIndex);r&&(l=r.page,m=r.segmentIndex)}else for(;;){const e=mi(d,l,m);if(!e)break;const t=hi(d,e.page,e.segmentIndex);if(!t)break;if(l=t.page,m=t.segmentIndex,e.page.headerStartPos!==f.headerStartPos){f=e.page,p=e.segmentIndex;break}}}let g=null,k=null;for(;null!==l;){t(null!==m);const e=await this.demuxer.readPacket(l,m);if(!e)break;if(!(l.headerStartPos===a.startPage.headerStartPos&&mi||Math.max(s.timestampInSamples,0)===i))break}const s=await this.demuxer.findNextPacketStart(e);if(!s)break;l=s.startPage,m=s.startSegmentIndex}return g}async getPacketSequential(e,r){const a=await this.sequentialScanMutex.acquire();try{const a=A(e*this.internalSampleRate);e=a/this.internalSampleRate;const s=S(this.sequentialScanCache,a,e=>e.timestampInSamples);let n;if(-1!==s){const e=this.sequentialScanCache[s];n=this.createEncodedPacketFromOggPacket(e.packet,{timestampInSamples:e.timestampInSamples,vorbisLastBlocksize:e.vorbisLastBlockSize},r)}else n=await this.getFirstPacket(r);let o=0;for(;n&&n.timestampe)break;if(n=a,o++,100===o){o=0;const e=this.encodedPacketToMetadata.get(n);t(e),this.sequentialScanCache.length>0&&t(i(this.sequentialScanCache).timestampInSamples<=e.timestampInSamples),this.sequentialScanCache.push(e)}}return n}finally{a()}}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const hi=(e,r,i)=>{let a=r,s=i;e:for(;;){for(s--;s>=0;s--){if(a.lacingValues[s]<255){s++;break e}}t(-1===s);if(!(1&a.headerType)){s=0;break}const r=P(e,e=>e.headerStartPos{if(r>0)return{page:t,segmentIndex:r-1};const i=P(e,e=>e.headerStartPos{let e=this.reader.requestSlice(0,12);e instanceof Promise&&(e=await e),t(e);const r=ya(e,4),i="RIFX"!==r,a="RF64"===r,s=da(e,i);let n=a?this.reader.fileSize:Math.min(s+8,this.reader.fileSize??1/0);if("WAVE"!==ya(e,4))throw new Error("Invalid WAVE file - wrong format");let o=0,c=null,l=e.filePos;for(;null===n||l=18&&357!==a){const e=na(i,r),s=t-18;if(Math.min(s,e)>=22&&a===fi.EXTENSIBLE){i.skip(6);const e=aa(i,16);a=e[0]|e[1]<<8}}a!==fi.MULAW&&a!==fi.ALAW||(c=8),this.audioInfo={format:a,numberOfChannels:s,sampleRate:n,sampleSizeInBytes:Math.ceil(c/8),blockSizeInBytes:o}}async parseListChunk(e,t,r){var i,a,s,n,o,c,l,d,u,h,m;let f=this.reader.requestSlice(e,t);if(f instanceof Promise&&(f=await f),!f)return;const p=ya(f,4);if("INFO"!==p&&"INF0"!==p)return;let g=f.filePos;for(;g<=e+t-8;){f.filePos=g;const e=ya(f,4),t=da(f,r),p=aa(f,t);let k=0;for(let r=0;r0&&((c=this.metadataTags).trackNumber??(c.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&((l=this.metadataTags).tracksTotal??(l.tracksTotal=r))}break;case"ICRD":case"IDIT":{const e=new Date(b);Number.isNaN(e.getTime())||((d=this.metadataTags).date??(d.date=e))}break;case"YEAR":{const e=Number.parseInt(b,10);Number.isInteger(e)&&e>0&&((u=this.metadataTags).date??(u.date=new Date(e,0,1)))}break;case"IGNR":case"GENR":(h=this.metadataTags).genre??(h.genre=b);break;case"ICMT":case"CMNT":case"COMM":(m=this.metadataTags).comment??(m.comment=b)}g+=8+t+(1&t)}}async parseId3Chunk(e,t){let r=this.reader.requestSlice(e,t);if(r instanceof Promise&&(r=await r),!r)return;const i=Xr(r);if(i){const t=r.slice(e+10,i.size);Yr(t,i,this.metadataTags)}}getCodec(){if(t(this.audioInfo),this.audioInfo.format===fi.MULAW)return"ulaw";if(this.audioInfo.format===fi.ALAW)return"alaw";if(this.audioInfo.format===fi.PCM){if(1===this.audioInfo.sampleSizeInBytes)return"pcm-u8";if(2===this.audioInfo.sampleSizeInBytes)return"pcm-s16";if(3===this.audioInfo.sampleSizeInBytes)return"pcm-s24";if(4===this.audioInfo.sampleSizeInBytes)return"pcm-s32"}return this.audioInfo.format===fi.IEEE_FLOAT&&4===this.audioInfo.sampleSizeInBytes?"pcm-f32":null}async getMimeType(){return"audio/wav"}async computeDuration(){await this.readMetadata();const e=this.tracks[0];return t(e),e.computeDuration()}async getTracks(){return await this.readMetadata(),this.tracks}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}}const ki=2048;class bi{constructor(e){this.demuxer=e}getId(){return 1}getCodec(){return this.demuxer.getCodec()}getInternalCodecId(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.format}async getDecoderConfig(){const e=this.demuxer.getCodec();return e?(t(this.demuxer.audioInfo),{codec:e,numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate}):null}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}getNumberOfChannels(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getTimeResolution(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return D}getDisposition(){return{...te}}async getFirstTimestamp(){return 0}async getPacketAtIndex(e,r){t(this.demuxer.audioInfo);const i=e*ki*this.demuxer.audioInfo.blockSizeInBytes;if(i>=this.demuxer.dataSize)return null;const a=Math.min(ki*this.demuxer.audioInfo.blockSizeInBytes,this.demuxer.dataSize-i);if(null===this.demuxer.reader.fileSize){let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+i,a);if(e instanceof Promise&&(e=await e),!e)return null}let s;if(r.metadataOnly)s=Ge;else{let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+i,a);e instanceof Promise&&(e=await e),t(e),s=aa(e,a)}const n=e*ki/this.demuxer.audioInfo.sampleRate,o=a/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate;return this.demuxer.lastKnownPacketIndex=Math.max(e,n),new Xe(s,"key",n,o,e,a)}getFirstPacket(e){return this.getPacketAtIndex(0,e)}async getPacket(e,r){t(this.demuxer.audioInfo);const i=Math.floor(Math.min(e*this.demuxer.audioInfo.sampleRate/ki,(this.demuxer.dataSize-1)/(ki*this.demuxer.audioInfo.blockSizeInBytes))),a=await this.getPacketAtIndex(i,r);if(a)return a;if(0===i)return null;t(null===this.demuxer.reader.fileSize);let s=await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex,r);for(;s;){const e=await this.getNextPacket(s,r);if(!e)break;s=e}return s}getNextPacket(e,r){t(this.demuxer.audioInfo);const i=Math.round(e.timestamp*this.demuxer.audioInfo.sampleRate/ki);return this.getPacketAtIndex(i+1,r)}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Ti=e=>{const t=e.filePos,r=aa(e,9),i=new a(r);if(4095!==i.readBits(12))return null;i.skipBits(1);if(0!==i.readBits(2))return null;const s=i.readBits(1),n=i.readBits(2)+1,o=i.readBits(4);if(15===o)return null;i.skipBits(1);const c=i.readBits(3);if(0===c)throw new Error("ADTS frames with channel configuration 0 are not supported.");i.skipBits(1),i.skipBits(1),i.skipBits(1),i.skipBits(1);const l=i.readBits(13);i.skipBits(11);const d=i.readBits(2)+1;if(1!==d)throw new Error("ADTS frames with more than one AAC frame are not supported.");let u=null;return 1===s?e.filePos-=2:u=i.readBits(16),{objectType:n,samplingFrequencyIndex:o,channelConfiguration:c,frameLength:l,numberOfAacFrames:d,crcCheck:u,startPos:t}},yi=1024;class wi extends Ke{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.loadedSamples=[],this.tracks=[],this.readingMutex=new b,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)await this.advanceReader();t(this.firstFrameHeader),this.tracks=[new Mt(this.input,new Si(this))]})())}async advanceReader(){let e=this.reader.requestSliceRange(this.lastLoadedPos,7,9);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const r=Ti(e);if(!r)return void(this.lastSampleLoaded=!0);if(null!==this.reader.fileSize&&r.startPos+r.frameLength>this.reader.fileSize)return void(this.lastSampleLoaded=!0);this.firstFrameHeader||(this.firstFrameHeader=r);const i=ce[r.samplingFrequencyIndex];t(void 0!==i);const a=yi/i,s=r.crcCheck?9:7,n={timestamp:this.nextTimestampInSamples/i,duration:a,dataStart:r.startPos+s,dataSize:r.frameLength-s};this.loadedSamples.push(n),this.nextTimestampInSamples+=yi,this.lastLoadedPos=r.startPos+r.frameLength}async getMimeType(){return"audio/aac"}async getTracks(){return await this.readMetadata(),this.tracks}async computeDuration(){await this.readMetadata();const e=this.tracks[0];return t(e),e.computeDuration()}async getMetadataTags(){return{}}}class Si{constructor(e){this.demuxer=e}getId(){return 1}async getFirstTimestamp(){return 0}getTimeResolution(){return this.getSampleRate()/yi}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}getName(){return null}getLanguageCode(){return D}getCodec(){return"aac"}getInternalCodecId(){return t(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.objectType}getNumberOfChannels(){t(this.demuxer.firstFrameHeader);const e=le[this.demuxer.firstFrameHeader.channelConfiguration];return t(void 0!==e),e}getSampleRate(){t(this.demuxer.firstFrameHeader);const e=ce[this.demuxer.firstFrameHeader.samplingFrequencyIndex];return t(void 0!==e),e}getDisposition(){return{...te}}async getDecoderConfig(){t(this.demuxer.firstFrameHeader);const e=new Uint8Array(3),r=new a(e),{objectType:i,samplingFrequencyIndex:s,channelConfiguration:n}=this.demuxer.firstFrameHeader;return i>31?(r.writeBits(5,31),r.writeBits(6,i-32)):r.writeBits(5,i),r.writeBits(4,s),r.writeBits(4,n),{codec:`mp4a.40.${this.demuxer.firstFrameHeader.objectType}`,numberOfChannels:this.getNumberOfChannels(),sampleRate:this.getSampleRate(),description:e.subarray(0,Math.ceil((r.pos-1)/8))}}async getPacketAtIndex(e,t){if(-1===e)return null;const r=this.demuxer.loadedSamples[e];if(!r)return null;let i;if(t.metadataOnly)i=Ge;else{let e=this.demuxer.reader.requestSlice(r.dataStart,r.dataSize);if(e instanceof Promise&&(e=await e),!e)return null;i=aa(e,r.dataSize)}return new Xe(i,"key",r.timestamp,r.duration,e,r.dataSize)}getFirstPacket(e){return this.getPacketAtIndex(0,e)}async getNextPacket(e,t){const r=await this.demuxer.readingMutex.acquire();try{const r=w(this.demuxer.loadedSamples,e.timestamp,e=>e.timestamp);if(-1===r)throw new Error("Packet was not created from this track.");const i=r+1;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{r()}}async getPacket(e,t){const r=await this.demuxer.readingMutex.acquire();try{for(;;){const r=S(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===r&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(r,t);if(r>=0&&r+1{for(var r;null===this.reader.fileSize||ea.end-6)return{num:s.num,blockSize:s.blockSize,sampleRate:s.sampleRate,size:a.end-e,isLastFrame:!0};if(255===sa(a)){const t=a.filePos;if(sa(a)!==(1===this.blockingBit?249:248)){a.filePos=t;continue}a.skip(-2);const r=a.filePos-e,i=this.readFlacFrameHeader({slice:a,isFirstPacket:!1});if(!i){a.filePos=t;continue}if(0===this.blockingBit){if(i.num-s.num!==1){a.filePos=t;continue}}else if(i.num-s.num!==s.blockSize){a.filePos=t;continue}return{num:s.num,blockSize:s.blockSize,sampleRate:s.sampleRate,size:r,isLastFrame:!1}}}}readFlacFrameHeader({slice:e,isFirstPacket:r}){const i=e.filePos,s=aa(e,4),n=new a(s);if(32764!==n.readBits(15))return null;if(null===this.blockingBit){t(r);const e=n.readBits(1);this.blockingBit=e}else if(1===this.blockingBit){t(!r);if(1!==n.readBits(1))return null}else{if(0!==this.blockingBit)throw new Error("Invalid blocking bit");t(!r);if(0!==n.readBits(1))return null}const o=(e=>0===e?null:1===e?192:e>=2&&e<=5?144*2**e:6===e?"uncommon-u8":7===e?"uncommon-u16":e>=8&&e<=15?2**e:null)(n.readBits(4));if(!o)return null;t(this.audioInfo);const c=((e,t)=>{switch(e){case 0:return t;case 1:return 88200;case 2:return 176400;case 3:return 192e3;case 4:return 8e3;case 5:return 16e3;case 6:return 22050;case 7:return 24e3;case 8:return 32e3;case 9:return 44100;case 10:return 48e3;case 11:return 96e3;case 12:return"uncommon-u8";case 13:return"uncommon-u16";case 14:return"uncommon-u16-10";default:return null}})(n.readBits(4),this.audioInfo.sampleRate);if(!c)return null;n.readBits(4),n.readBits(3);if(0!==n.readBits(1))return null;const l=(e=>{let t=0;const r=new a(aa(e,1));for(;1===r.readBits(1);)t++;if(0===t)return r.readBits(7);const i=[],s=t-1,n=new a(aa(e,s)),o=8-t-1;for(let a=0;ae|t<"uncommon-u16"===r?oa(e)+1:"uncommon-u8"===r?sa(e)+1:"number"===typeof r?r:(C(r),void t(!1)))(e,o),u=((e,t)=>"uncommon-u16"===t?oa(e):"uncommon-u16-10"===t?10*oa(e):"uncommon-u8"===t?sa(e):"number"===typeof t?t:null)(e,c);if(null===u)return null;if(u!==this.audioInfo.sampleRate)return null;const h=e.filePos-i,m=sa(e);e.skip(-h),e.skip(-1);const f=(e=>{let t=0;for(const r of e){t^=r;for(let e=0;e<8;e++)0!==(128&t)?t=t<<1^7:t<<=1,t&=255}return t})(aa(e,h));return m!==f?null:{num:l,blockSize:d,sampleRate:u}}async advanceReader(){await this.readMetadata(),t(null!==this.lastLoadedPos),t(this.audioInfo);const e=this.lastLoadedPos,r=await this.readNextFlacFrame({startPos:e,isFirstPacket:0===this.loadedSamples.length});if(!r)return void(this.lastSampleLoaded=!0);const i=this.loadedSamples[this.loadedSamples.length-1],a={blockOffset:i?i.blockOffset+i.blockSize:0,blockSize:r.blockSize,byteOffset:e,byteSize:r.size};this.lastLoadedPos=this.lastLoadedPos+r.size,this.loadedSamples.push(a),r.isLastFrame&&(this.lastSampleLoaded=!0)}}class vi{constructor(e){this.demuxer=e}getId(){return 1}getCodec(){return"flac"}getInternalCodecId(){return null}getNumberOfChannels(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}async computeDuration(){const e=await this.getPacket(1/0,{metadataOnly:!0});return(e?.timestamp??0)+(e?.duration??0)}getSampleRate(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return D}getTimeResolution(){return t(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getDisposition(){return{...te}}async getFirstTimestamp(){return 0}async getDecoderConfig(){return t(this.demuxer.audioInfo),{codec:"flac",numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate,description:this.demuxer.audioInfo.description}}async getPacket(e,r){if(t(this.demuxer.audioInfo),e<0)throw new Error("Timestamp cannot be negative");const i=await this.demuxer.readingMutex.acquire();try{for(;;){const t=S(this.demuxer.loadedSamples,e,e=>e.blockOffset/this.demuxer.audioInfo.sampleRate);if(-1===t){await this.demuxer.advanceReader();continue}const i=this.demuxer.loadedSamples[t],a=i.blockOffset/this.demuxer.audioInfo.sampleRate;if(!(a+i.blockSize/this.demuxer.audioInfo.sampleRate<=e))return this.getPacketAtIndex(t,r);if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(this.demuxer.loadedSamples.length-1,r);await this.demuxer.advanceReader()}}finally{i()}}async getNextPacket(e,t){const r=await this.demuxer.readingMutex.acquire();try{const r=e.sequenceNumber+1;if(this.demuxer.lastSampleLoaded&&r>=this.demuxer.loadedSamples.length)return null;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{r()}}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}async getPacketAtIndex(e,r){const i=this.demuxer.loadedSamples[e];if(!i)return null;let a;if(r.metadataOnly)a=Ge;else{let e=this.demuxer.reader.requestSlice(i.byteOffset,i.byteSize);if(e instanceof Promise&&(e=await e),!e)return null;a=aa(e,i.byteSize)}t(this.demuxer.audioInfo);const s=i.blockOffset/this.demuxer.audioInfo.sampleRate,n=i.blockSize/this.demuxer.audioInfo.sampleRate;return new Xe(a,"key",s,n,e,i.byteSize)}async getFirstPacket(e){for(;0===this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(0,e)}}class Pi{}class xi extends Pi{async _getMajorBrand(e){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=await t),!t)return null;t.skip(4);return"ftyp"!==ya(t,4)?null:ya(t,4)}_createDemuxer(e){return new qt(e)}}class Ci extends xi{async _canReadInput(e){const t=await this._getMajorBrand(e);return!!t&&"qt "!==t}get name(){return"MP4"}get mimeType(){return"video/mp4"}}class _i extends xi{async _canReadInput(e){return"qt "===await this._getMajorBrand(e)}get name(){return"QuickTime File Format"}get mimeType(){return"video/quicktime"}}class Bi extends Pi{async isSupportedEBMLOfDocType(e,t){let r=e._reader.requestSlice(0,ar);if(r instanceof Promise&&(r=await r),!r)return!1;const i=sr(r);if(null===i)return!1;if(i<1||i>8)return!1;if(or(r,i)!==Zt.EBML)return!1;const a=lr(r);if("number"!==typeof a)return!1;let s=e._reader.requestSlice(r.filePos,a);if(s instanceof Promise&&(s=await s),!s)return!1;const n=r.filePos;for(;s.filePos<=n+a-2;){const e=dr(s);if(!e)break;const{id:r,size:i}=e,a=s.filePos;if(void 0===i)return!1;switch(r){case Zt.EBMLVersion:if(1!==or(s,i))return!1;break;case Zt.EBMLReadVersion:if(1!==or(s,i))return!1;break;case Zt.DocType:if(ur(s,i)!==t)return!1;break;case Zt.DocTypeVersion:if(or(s,i)>4)return!1}s.filePos=a+i}return!0}_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"matroska")}_createDemuxer(e){return new Mr(e)}get name(){return"Matroska"}get mimeType(){return"video/x-matroska"}}class Ei extends Bi{_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"webm")}get name(){return"WebM"}get mimeType(){return"video/webm"}}class Fi extends Pi{async _canReadInput(e){let t=e._reader.requestSlice(0,10);if(t instanceof Promise&&(t=await t),!t)return!1;let r=0,i=!1;for(;;){let t=e._reader.requestSlice(r,10);if(t instanceof Promise&&(t=await t),!t)break;const a=Xr(t);if(!a)break;i=!0,r=t.filePos+a.size}const a=await Zr(e._reader,r,r+4096);if(!a)return!1;if(i)return!0;r=a.startPos+a.header.totalSize;const s=await Zr(e._reader,r,r+4);if(!s)return!1;const n=a.header,o=s.header;return n.channel===o.channel&&n.sampleRate===o.sampleRate}_createDemuxer(e){return new ei(e)}get name(){return"MP3"}get mimeType(){return"audio/mpeg"}}class Di extends Pi{async _canReadInput(e){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=await t),!t)return!1;const r=ya(t,4);if("RIFF"!==r&&"RIFX"!==r&&"RF64"!==r)return!1;t.skip(4);return"WAVE"===ya(t,4)}_createDemuxer(e){return new gi(e)}get name(){return"WAVE"}get mimeType(){return"audio/wav"}}class Ai extends Pi{async _canReadInput(e){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=await t),!!t&&"OggS"===ya(t,4)}_createDemuxer(e){return new di(e)}get name(){return"Ogg"}get mimeType(){return"application/ogg"}}class Ri extends Pi{async _canReadInput(e){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=await t),!!t&&"fLaC"===ya(t,4)}get name(){return"FLAC"}get mimeType(){return"audio/flac"}_createDemuxer(e){return new Ii(e)}}class Mi extends Pi{async _canReadInput(e){let t=e._reader.requestSliceRange(0,7,9);if(t instanceof Promise&&(t=await t),!t)return!1;const r=Ti(t);if(!r)return!1;if(t=e._reader.requestSliceRange(r.frameLength,7,9),t instanceof Promise&&(t=await t),!t)return!1;const i=Ti(t);return!!i&&(r.objectType===i.objectType&&r.samplingFrequencyIndex===i.samplingFrequencyIndex&&r.channelConfiguration===i.channelConfiguration)}_createDemuxer(e){return new wi(e)}get name(){return"ADTS"}get mimeType(){return"audio/aac"}}const Ni=new Ci,zi=new _i,Oi=new Bi,Li=new Ei,Ui=new Fi,Vi=new Di,qi=new Ai,Hi=new Mi,Wi=[Ni,zi,Oi,Li,Vi,qi,new Ri,Ui,Hi];class ji{constructor(){this._disposed=!1,this._sizePromise=null,this.onread=null}async getSizeOrNull(){if(this._disposed)throw new ea;return this._sizePromise??(this._sizePromise=Promise.resolve(this._retrieveSize()))}async getSize(){if(this._disposed)throw new ea;const e=await this.getSizeOrNull();if(null===e)throw new Error("Cannot determine the size of an unsized source.");return e}}class Ki extends ji{constructor(e,t={}){if(!(e instanceof Blob))throw new TypeError("blob must be a Blob.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!J(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._readers=new WeakMap,this._blob=e,this._orchestrator=new Ji({maxCacheSize:t.maxCacheSize??8388608,maxWorkerCount:4,runWorker:this._runWorker.bind(this),prefetchProfile:Yi.fileSystem})}_retrieveSize(){const e=this._blob.size;return this._orchestrator.fileSize=e,e}_read(e,t){return this._orchestrator.read(e,t)}async _runWorker(e){let t=this._readers.get(e);if(void 0===t){if("stream"in this._blob&&!q()){t=this._blob.slice(e.currentPos).stream().getReader()}else t=null;this._readers.set(e,t)}for(;e.currentPos{if(t instanceof Error&&(t.message.includes("Failed to fetch")||t.message.includes("Load failed")||t.message.includes("NetworkError when attempting to fetch resource"))){let e=null;try{"undefined"!==typeof window&&"undefined"!==typeof window.location&&(e=new URL(r instanceof Request?r.url:r,window.location.href).origin)}catch{}if(("undefined"===typeof navigator||"boolean"!==typeof navigator.onLine||navigator.onLine)&&null!==e&&e!==window.location.origin)return console.warn("Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option."),null}return Math.min(2**(e-2),16)};class Gi extends ji{constructor(e,t={}){if("string"!==typeof e&&!(e instanceof URL)&&!("undefined"!==typeof Request&&e instanceof Request))throw new TypeError("url must be a string, URL or Request.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.requestInit&&(!t.requestInit||"object"!==typeof t.requestInit))throw new TypeError("options.requestInit, when provided, must be an object.");if(void 0!==t.getRetryDelay&&"function"!==typeof t.getRetryDelay)throw new TypeError("options.getRetryDelay, when provided, must be a function.");if(void 0!==t.maxCacheSize&&(!J(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");if(void 0!==t.fetchFn&&"function"!==typeof t.fetchFn)throw new TypeError("options.fetchFn, when provided, must be a function.");super(),this._existingResponses=new WeakMap,this._url=e,this._options=t,this._getRetryDelay=t.getRetryDelay??Qi,this._orchestrator=new Ji({maxCacheSize:t.maxCacheSize??67108864,maxWorkerCount:2,runWorker:this._runWorker.bind(this),prefetchProfile:Yi.network})}async _retrieveSize(){const e=new AbortController,t=await L(this._options.fetchFn??fetch,this._url,z(this._options.requestInit??{},{headers:{Range:"bytes=0-"},signal:e.signal}),this._getRetryDelay,()=>this._disposed);if(!t.ok)throw new Error(`Error fetching ${String(this._url)}: ${t.status} ${t.statusText}`);let r,i;if(206===t.status)i=this._getTotalLengthFromRangeResponse(t),r=this._orchestrator.createWorker(0,Math.min(i,$i));else{const e=t.headers.get("Content-Length");if(!e)throw new Error(`HTTP response (status ${t.status}) must surface Content-Length header.`);i=Number(e),r=this._orchestrator.createWorker(0,i),this._orchestrator.options.maxCacheSize=1/0,console.warn("HTTP server did not respond with 206 Partial Content, meaning the entire remote resource now has to be downloaded. For efficient media file streaming across a network, please make sure your server supports range requests.")}return this._orchestrator.fileSize=i,this._existingResponses.set(r,{response:t,abortController:e}),this._orchestrator.runWorker(r),i}_read(e,t){return this._orchestrator.read(e,t)}async _runWorker(e){for(;;){const i=this._existingResponses.get(e);this._existingResponses.delete(e);let a=i?.abortController,s=i?.response;if(a||(a=new AbortController,s=await L(this._options.fetchFn??fetch,this._url,z(this._options.requestInit??{},{headers:{Range:`bytes=${e.currentPos}-`},signal:a.signal}),this._getRetryDelay,()=>this._disposed)),t(s),!s.ok)throw new Error(`Error fetching ${String(this._url)}: ${s.status} ${s.statusText}`);if(e.currentPos>0&&206!==s.status)throw new Error("HTTP server did not respond with 206 Partial Content to a range request. To enable efficient media file streaming across a network, please make sure your server supports range requests.");if(!s.body)throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream.");const n=s.body.getReader();for(;;){if(e.currentPos>=e.targetPos||e.aborted)return a.abort(),void(e.running=!1);let t;try{t=await n.read()}catch(r){if(this._disposed)throw r;const e=this._getRetryDelay(1,r,this._url);if(null!==e){console.error("Error while reading response stream. Attempting to resume.",r),await new Promise(t=>setTimeout(t,1e3*e));break}throw r}if(e.aborted)continue;const{done:i,value:s}=t;if(i){if(e.currentPos>=e.targetPos)return this._orchestrator.forgetWorker(e),void(e.running=!1);break}this.onread?.(e.currentPos,e.currentPos+s.length),this._orchestrator.supplyWorkerData(e,s)}}}_getTotalLengthFromRangeResponse(e){const t=e.headers.get("Content-Range");if(t){const e=/\/(\d+)/.exec(t);if(e)return Number(e[1])}const r=e.headers.get("Content-Length");if(r)return Number(r);throw new Error("Partial HTTP response (status 206) must surface either Content-Range or Content-Length header.")}_dispose(){this._orchestrator.dispose()}}class Xi extends ji{constructor(e,t={}){if(!(e instanceof ReadableStream))throw new TypeError("stream must be a ReadableStream.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!J(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._reader=null,this._cache=[],this._pendingSlices=[],this._currentIndex=0,this._targetIndex=0,this._maxRequestedIndex=0,this._endIndex=null,this._pulling=!1,this._stream=e,this._maxCacheSize=t.maxCacheSize??16777216}_retrieveSize(){return this._endIndex}_read(e,t){if(null!==this._endIndex&&t>this._endIndex)return null;this._maxRequestedIndex=Math.max(this._maxRequestedIndex,t);const r=S(this._cache,e,e=>e.start),i=-1!==r?this._cache[r]:null;if(i&&i.start<=e&&t<=i.end)return{bytes:i.bytes,view:i.view,offset:i.start};let a=e;const s=new Uint8Array(t-e);if(-1!==r)for(let c=r;c=t)break;const i=Math.max(e,r.start);i>a&&this._throwDueToCacheMiss();const n=Math.min(t,r.end);ia&&this._throwDueToCacheMiss();const{promise:n,resolve:o,reject:l}=v();return this._pendingSlices.push({start:e,end:t,bytes:s,resolve:o,reject:l}),this._targetIndex=Math.max(this._targetIndex,t),this._pulling||(this._pulling=!0,this._pull().catch(e=>{if(this._pulling=!1,!(this._pendingSlices.length>0))throw e;this._pendingSlices.forEach(t=>t.reject(e)),this._pendingSlices.length=0})),n}_throwDueToCacheMiss(){throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache.")}async _pull(){for(this._reader??(this._reader=this._stream.getReader());this._currentIndex0;){const e=this._cache[0];if(this._maxRequestedIndex-e.end<=this._maxCacheSize)break;this._cache.shift()}this._currentIndex+=t.byteLength}this._pulling=!1}_dispose(){this._pendingSlices.length=0,this._cache.length=0}}const Yi={fileSystem:(e,t)=>{const r=65536;return{start:e=Math.floor((e-r)/r)*r,end:t=Math.ceil((t+r)/r)*r}},network:(e,t,r)=>{const i=65536;e=Math.max(0,Math.floor((e-i)/i)*i);for(const a of r){const r=8388608,i=Math.max((a.startPos+a.targetPos)/2,a.targetPos-r);if(G(e,t,i,a.targetPos)){const e=a.targetPos-a.startPos,i=Math.ceil((e+1)/r)*r,s=2**Math.ceil(Math.log2(e+1)),n=Math.min(s,i);t=Math.max(t,a.startPos+n)}}return{start:e,end:t=Math.max(t,e+$i)}}};class Ji{constructor(e){this.options=e,this.fileSize=null,this.nextAge=0,this.workers=[],this.cache=[],this.currentCacheSize=0,this.disposed=!1}read(e,r){t(null!==this.fileSize);const i=this.options.prefetchProfile(e,r,this.workers),a=Math.max(i.start,0),s=Math.min(i.end,this.fileSize);t(a<=e&&r<=s);let n=null;const o=S(this.cache,e,e=>e.start),l=-1!==o?this.cache[o]:null;l&&l.start<=e&&r<=l.end&&(l.age=this.nextAge++,n={bytes:l.bytes,view:l.view,offset:l.start});const d=S(this.cache,a,e=>e.start),u=n?null:new Uint8Array(r-e);let h=0,m=a;const f=[];if(-1!==d){for(let i=d;i=s)break;if(n.end<=a)continue;const o=Math.max(a,n.start),c=Math.min(s,n.end);if(t(o<=c),m=u.length&&(n={bytes:u,view:c(u),offset:e}),0===f.length)return t(n),n;const{promise:p,resolve:g,reject:k}=v(),b=[];for(const t of f){const i=Math.max(e,t.start),a=Math.min(r,t.end);i===t.start&&a===t.end?b.push(t):i({bytes:t,view:c(t),offset:e}))),n}createWorker(e,t){const r={startPos:e,currentPos:e,targetPos:t,running:!1,aborted:this.disposed,pendingSlices:[],age:this.nextAge++};for(this.workers.push(r);this.workers.length>this.options.maxWorkerCount;){let e=0,t=this.workers[0];for(let r=1;r0)break;t.aborted=!0,this.workers.splice(e,1)}return r}runWorker(e){t(!e.running),t(e.currentPos{if(e.running=!1,!(e.pendingSlices.length>0))throw t;e.pendingSlices.forEach(e=>e.reject(t)),e.pendingSlices.length=0})}supplyWorkerData(e,r){t(!e.aborted);const i=e.currentPos,a=i+r.length;this.insertIntoCache({start:i,end:a,bytes:r,view:c(r),age:this.nextAge++}),e.currentPos+=r.length,e.targetPos=Math.max(e.targetPos,e.currentPos);for(let t=0;tt.start&&(t.start=a),t.end<=t.start&&(s.holes.splice(e,1),e--)}0===s.holes.length&&(s.resolve(s.bytes),e.pendingSlices.splice(t,1),t--)}for(let t=0;te.start)+1;if(t>0){const r=this.cache[t-1];if(r.end>=e.end)return;if(r.end>e.start){const i=new Uint8Array(e.end-r.start);i.set(r.bytes,0),i.set(e.bytes,e.start-r.start),this.currentCacheSize+=e.end-r.end,r.bytes=i,r.view=c(i),r.end=e.end,t--,e=r}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length;for(let r=t+1;r=t.end){this.cache.splice(r,1),this.currentCacheSize-=t.bytes.length,r--;continue}const i=new Uint8Array(t.end-e.start);i.set(e.bytes,0),i.set(t.bytes,t.start-e.start),this.currentCacheSize-=e.end-t.start,e.bytes=i,e.view=c(i),e.end=t.end,this.cache.splice(r,1);break}for(;this.currentCacheSize>this.options.maxCacheSize;){let e=0,t=this.cache[0];for(let r=1;r!(e instanceof Pi)))throw new TypeError("options.formats must be an array of InputFormat.");if(!(e.source instanceof ji))throw new TypeError("options.source must be a Source.");if(e.source._disposed)throw new Error("options.source must not be disposed.");this._formats=e.formats,this._source=e.source,this._reader=new ta(e.source)}_getDemuxer(){return this._demuxerPromise??(this._demuxerPromise=(async()=>{this._reader.fileSize=await this._source.getSizeOrNull();for(const e of this._formats){if(await e._canReadInput(this))return this._format=e,e._createDemuxer(this)}throw new Error("Input has an unsupported or unrecognizable format.")})())}get source(){return this._source}async getFormat(){return await this._getDemuxer(),t(this._format),this._format}async computeDuration(){return(await this._getDemuxer()).computeDuration()}async getTracks(){return(await this._getDemuxer()).getTracks()}async getVideoTracks(){return(await this.getTracks()).filter(e=>e.isVideoTrack())}async getAudioTracks(){return(await this.getTracks()).filter(e=>e.isAudioTrack())}async getPrimaryVideoTrack(){return(await this.getTracks()).find(e=>e.isVideoTrack())??null}async getPrimaryAudioTrack(){return(await this.getTracks()).find(e=>e.isAudioTrack())??null}async getMimeType(){return(await this._getDemuxer()).getMimeType()}async getMetadataTags(){return(await this._getDemuxer()).getMetadataTags()}dispose(){this._disposed||(this._disposed=!0,this._source._disposed=!0,this._source._dispose())}[Symbol.dispose](){this.dispose()}}class ea extends Error{constructor(e="Input has been disposed."){super(e),this.name="InputDisposedError"}}class ta{constructor(e){this.source=e}requestSlice(e,t){if(this.source._disposed)throw new ea;if(null!==this.fileSize&&e+t>this.fileSize)return null;const r=e+t,i=this.source._read(e,r);return i instanceof Promise?i.then(t=>t?new ra(t.bytes,t.view,t.offset,e,r):null):i?new ra(i.bytes,i.view,i.offset,e,r):null}requestSliceRange(e,r,i){if(this.source._disposed)throw new ea;if(null!==this.fileSize)return this.requestSlice(e,F(this.fileSize-e,r,i));{const a=this.requestSlice(e,i),s=a=>{if(a)return a;const s=a=>(t(null!==a),this.requestSlice(e,F(a-e,r,i))),n=this.source._retrieveSize();return n instanceof Promise?n.then(s):s(n)};return a instanceof Promise?a.then(s):s(a)}}}class ra{constructor(e,t,r,i,a){this.bytes=e,this.view=t,this.offset=r,this.start=i,this.end=a,this.bufferPos=i-r}static tempFromBytes(e){return new ra(e,c(e),0,0,e.length)}get length(){return this.end-this.start}get filePos(){return this.offset+this.bufferPos}set filePos(e){this.bufferPos=e-this.offset}get remainingLength(){return Math.max(this.end-this.filePos,0)}skip(e){this.bufferPos+=e}slice(e,t=this.end-e){if(ethis.end)throw new RangeError("Slicing outside of original slice.");return new ra(this.bytes,this.view,this.offset,e,e+t)}}const ia=(e,t)=>{if(e.filePose.end)throw new RangeError(`Tried reading [${e.filePos}, ${e.filePos+t}), but slice is [${e.start}, ${e.end}). This is likely an internal error, please report it alongside the file that caused it.`)},aa=(e,t)=>{ia(e,t);const r=e.bytes.subarray(e.bufferPos,e.bufferPos+t);return e.bufferPos+=t,r},sa=e=>(ia(e,1),e.view.getUint8(e.bufferPos++)),na=(e,t)=>{ia(e,2);const r=e.view.getUint16(e.bufferPos,t);return e.bufferPos+=2,r},oa=e=>{ia(e,2);const t=e.view.getUint16(e.bufferPos,!1);return e.bufferPos+=2,t},ca=e=>{ia(e,3);const t=_(e.view,e.bufferPos,!1);return e.bufferPos+=3,t},la=e=>{ia(e,2);const t=e.view.getInt16(e.bufferPos,!1);return e.bufferPos+=2,t},da=(e,t)=>{ia(e,4);const r=e.view.getUint32(e.bufferPos,t);return e.bufferPos+=4,r},ua=e=>{ia(e,4);const t=e.view.getUint32(e.bufferPos,!1);return e.bufferPos+=4,t},ha=e=>{ia(e,4);const t=e.view.getUint32(e.bufferPos,!0);return e.bufferPos+=4,t},ma=e=>{ia(e,4);const t=e.view.getInt32(e.bufferPos,!1);return e.bufferPos+=4,t},fa=(e,t)=>{let r,i;return t?(r=da(e,!0),i=da(e,!0)):(i=da(e,!1),r=da(e,!1)),4294967296*i+r},pa=e=>4294967296*ua(e)+ua(e),ga=e=>4294967296*ma(e)+ua(e),ka=e=>{const t=ha(e),r=(e=>{ia(e,4);const t=e.view.getInt32(e.bufferPos,!0);return e.bufferPos+=4,t})(e);return 4294967296*r+t},ba=e=>{ia(e,4);const t=e.view.getFloat32(e.bufferPos,!1);return e.bufferPos+=4,t},Ta=e=>{ia(e,8);const t=e.view.getFloat64(e.bufferPos,!1);return e.bufferPos+=8,t},ya=(e,t)=>{ia(e,t);let r="";for(let i=0;ie.stop()),this.queuedNodes.clear()}async stopIterator(){await(this.audioIterator?.return()),this.audioIterator=null}async load(e,t){const r=++this.asyncId;await this.stopIterator(),this.stopQueuedNodes(),this.paused=!0,this.playbackTimeAtStart=0,this.audioContextStartTime=0;const i=this.normalizeSource(e);if(!i)return;if(this.input=new Zi({source:i,formats:Wi}),this.duration=await this.input.computeDuration(),r!==this.asyncId)return;const a=await this.input.getPrimaryAudioTrack();return a&&null!==a.codec&&await a.canDecode()?(this.ensureAudioContext(a.sampleRate),this.audioSink=new Dt(a),void t?.()):(this.audioSink=null,this.ensureAudioContext(),void t?.())}async runIterator(e){if(this.audioSink)for(await this.stopIterator(),this.audioIterator=this.audioSink.buffers(this.currentTime);;){if(e!==this.asyncId||this.paused)return;const r=this.audioIterator.next(),i=setInterval(()=>{e!==this.asyncId||this.paused?clearInterval(i):"running"===this.audioContext.state&&this.audioContext.currentTime>=this.latestScheduledEndTime-.2&&(this.audioContext.suspend(),this.events.emit("waiting"))},50);let a;try{a=await r}catch(t){console.error("Audio iterator error:",t);break}finally{clearInterval(i)}if(e!==this.asyncId||this.paused)return;if("suspended"===this.audioContext.state&&(await this.audioContext.resume(),this.events.emit("canplay"),this.events.emit("playing")),a.done)break;const{buffer:s,timestamp:n}=a.value,o=this.audioContext.createBufferSource();o.buffer=s,o.connect(this.gainNode),o.playbackRate.value=this.playbackRate;const c=this.audioContextStartTime+(n-this.playbackTimeAtStart)/this.playbackRate,l=c+s.duration/this.playbackRate;l>this.latestScheduledEndTime&&(this.latestScheduledEndTime=l),c>=this.audioContext.currentTime?o.start(c):o.start(this.audioContext.currentTime,(this.audioContext.currentTime-c)*this.playbackRate),this.queuedNodes.add(o),o.onended=()=>this.queuedNodes.delete(o)}}async play(){if(!this.paused)return;this.audioContext||this.ensureAudioContext(),"suspended"===this.audioContext.state&&await this.audioContext.resume(),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime,this.paused=!1;const e=++this.asyncId;this.runIterator(e)}pause(){this.paused||(this.playbackTimeAtStart=this.currentTime,this.paused=!0,this.stopIterator(),this.stopQueuedNodes())}async seek(e){this.playbackTimeAtStart=Math.max(0,e),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime;const t=++this.asyncId;this.paused||this.runIterator(t)}setVolume(e,t){this.volume=e,this.muted=t,this.updateGain()}setPlaybackRate(e){if(e!==this.playbackRate&&(this.paused||(this.playbackTimeAtStart=this.currentTime,this.audioContextStartTime=this.audioContext.currentTime),this.playbackRate=e,!this.paused)){const e=++this.asyncId;this.runIterator(e)}}destroy(){this.asyncId++,this.pause(),this.audioContext?.close(),this.audioContext=null,this.input=null,this.audioSink=null}}class Sa{constructor({canvas:e,ctx:t,events:r,timeupdateInterval:i=250,avSyncTolerance:a=.12,dropLateFrames:s=!1,poster:n="",preflightRange:o=!1}){this.canvas=e,this.ctx=t,this.events=r,this.timeupdateInterval=i,this.avSyncTolerance=a,this.dropLateFrames=s,this.poster=n,this.preflightRange=o,this.input=null,this.videoSink=null,this.videoIterator=null,this.nextFrame=null,this.rafId=0,this.asyncId=0,this.width=0,this.height=0,this.duration=Number.NaN,this.audioClock=null,this.lastTimeUpdate=0,this.stalled=!1,this.playbackRate=1,this.posterDrawn=!1,this.isFetching=!1}normalizeSource(e){return"string"===typeof e?new Gi(e):e instanceof Blob?new Ki(e):"undefined"!==typeof ReadableStream&&e instanceof ReadableStream?new Xi(e):e}async preflight(e){if(!this.preflightRange||"string"!==typeof e)return!0;try{const t=(await fetch(e,{method:"HEAD"})).headers.get("accept-ranges");return!(!t||"none"===t)||(this.events.emit("error",new Event("RangeNotSupported")),!1)}catch(t){return console.warn("Preflight check failed:",t),!0}}drawPoster(){if(!this.poster||this.posterDrawn)return;const e=new Image;e.onload=()=>{this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width=e.naturalWidth||this.canvas.width,this.canvas.height=e.naturalHeight||this.canvas.height,this.ctx.drawImage(e,0,0,this.canvas.width,this.canvas.height),this.posterDrawn=!0},e.src=this.poster}async stopIterator(){await(this.videoIterator?.return()),this.videoIterator=null}clear(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}async load(e,t){const r=++this.asyncId;if(await this.stopIterator(),this.clear(),this.posterDrawn=!1,!(await this.preflight(e)))return;const i=this.normalizeSource(e);if(!i)return void this.drawPoster();if(this.input=new Zi({source:i,formats:Wi}),this.duration=await this.input.computeDuration(),r!==this.asyncId)return;const a=await this.input.getPrimaryVideoTrack();if(!a)return this.handleNoVideoTrack(),void t?.();if(null===a.codec||!(await a.canDecode()))return this.handleNoVideoTrack(),void t?.();const s=await a.canBeTransparent();this.videoSink=new _t(a,{poolSize:2,fit:"contain",alpha:s}),this.width=a.displayWidth,this.height=a.displayHeight,this.canvas.width=this.width,this.canvas.height=this.height,t?.(),await this.resetIterator(0)}handleNoVideoTrack(){this.videoSink=null,this.width=0,this.height=0,this.canvas.width=0,this.canvas.height=0,this.clear(),this.drawPoster()}async resetIterator(e){if(await this.stopIterator(),!this.videoSink)return;this.videoIterator=this.videoSink.canvases(e);const t=(await this.videoIterator.next()).value??null,r=(await this.videoIterator.next()).value??null;this.nextFrame=r,t?(this.ctx.drawImage(t.canvas,0,0),this.events.emit("loadeddata")):this.drawPoster()}async updateNextFrame(e){if(this.videoIterator&&!this.isFetching){this.isFetching=!0;try{for(;;){const t=(await this.videoIterator.next()).value??null;if(!t||e!==this.asyncId)return;const r=this.audioClock.currentTime,i=this.dropLateFrames?Math.max(.06,this.avSyncTolerance/Math.max(1,this.playbackRate)):0;if(!(this.dropLateFrames&&t.timestampr)return void(this.nextFrame=null)}}}finally{this.isFetching=!1}}}render(){if(!this.audioClock)return;const e=this.audioClock.currentTime,t=Date.now();if(t-this.lastTimeUpdate>=this.timeupdateInterval&&(this.events.emit("timeupdate"),this.lastTimeUpdate=t),Number.isFinite(this.duration)&&e>=this.duration)return this.stop(),this.stalled=!1,this.events.emit("ended"),this.events.emit("pause"),void this.events.emit("canplay");this.nextFrame&&this.nextFrame.timestamp<=e?(this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextFrame.canvas,0,0),this.nextFrame=null,this.updateNextFrame(this.asyncId),this.stalled&&(this.events.emit("canplay"),this.events.emit("playing"),this.stalled=!1)):this.nextFrame||(this.updateNextFrame(this.asyncId),!this.nextFrame&&Number.isFinite(this.duration)&&ethis.render())}start(e){this.audioClock=e,this.asyncId++,this.stalled=!1,this.updateNextFrame(this.asyncId),this.rafId=requestAnimationFrame(()=>this.render())}stop(){cancelAnimationFrame(this.rafId)}async seek(e){this.asyncId++,await this.resetIterator(e)}setPlaybackRate(e){this.playbackRate=Math.max(.1,Number(e)||1)}destroy(){this.asyncId++,this.stop(),this.stopIterator(),this.posterDrawn=!1,this.input=null,this.videoSink=null}}class Ia{constructor({canvas:e,ctx:t,events:r,option:i={}}){this.events=r,this.option=i,this.audio=new wa(r),this.video=new Sa({canvas:e,ctx:t,events:r,timeupdateInterval:i.timeupdateInterval??250,avSyncTolerance:i.avSyncTolerance??.12,dropLateFrames:i.dropLateFrames??!1,poster:i.poster??"",preflightRange:i.preflightRange??!1}),this.paused=!0,this.ended=!1,this.readyState=0,this.networkState=0,this.error=null,this.seeking=!1,this.loadSeq=0,r.addEventListener?.("ended",()=>{this.ended=!0,this.paused=!0})}async load(e){const t=++this.loadSeq;this.pause(),this.ended=!1,this.error=null,this.networkState=2,this.readyState=0,setTimeout(()=>this.events.emit("waiting"),0),setTimeout(()=>this.events.emit("loadstart"),0);const r=Number.isFinite(this.option.loadTimeout)?this.option.loadTimeout:0;try{await Promise.race([this.performLoad(e,t),r>0?this.createTimeout(r):new Promise(()=>{})])}catch(i){if(t!==this.loadSeq)return;this.loadSeq++,this.error={code:4,message:i.message},this.networkState=3,this.events.emit("error")}}async performLoad(e,t){let r=!1,i=!1;const a=()=>{r&&i&&(this.readyState=1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"))};try{if(await Promise.all([this.video.load(e,()=>{t===this.loadSeq&&(r=!0,a())}),this.audio.load(e,()=>{t===this.loadSeq&&(i=!0,a())})]),t!==this.loadSeq)return;this.readyState=4,this.networkState=1,this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("progress")}catch(s){if(t!==this.loadSeq)return;this.error={code:4,message:s.message},this.networkState=3,this.events.emit("error"),console.error("MediaBunny load error:",s)}}createTimeout(e){return new Promise((t,r)=>{setTimeout(()=>r(new Error("Load timeout")),e)})}async play(){this.paused&&(this.ended&&(this.ended=!1,await this.seek(0)),this.paused=!1,await this.audio.play(),this.video.start(this.audio),this.events.emit("play"),this.events.emit("playing"))}pause(){this.paused||(this.paused=!0,this.audio.pause(),this.video.stop(),this.events.emit("pause"))}async seek(e){const t=!this.paused;this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),this.pause(),await Promise.all([this.audio.seek(e),this.video.seek(e)]),this.seeking=!1,this.events.emit("seeked"),t&&!this.ended&&await this.play()}setVolume(e,t){this.audio.setVolume(e,t)}setPlaybackRate(e){this.audio.setPlaybackRate(e),this.video.setPlaybackRate(e)}destroy(){this.pause(),this.audio.destroy(),this.video.destroy()}get currentTime(){return this.audio.currentTime}get duration(){return this.audio.duration||this.video.duration}get videoWidth(){return this.video.width}get videoHeight(){return this.video.height}}class va{constructor({art:t,canvas:r,ctx:i,option:a}){this.art=t,this.canvas=r,this.option=a,this.events=new e,this.engine=new Ia({canvas:r,ctx:i,events:this.events,option:a}),this._src=null,this._volume=a.volume??.7,this._muted=!!a.muted,this._playbackRate=1,this.engine.setVolume(this._volume,this._muted),this.setupEventForwarding(),a.source?this.src=a.source:t.option?.url&&(this.src=t.option.url)}setupEventForwarding(){const{events:e}=this.art.constructor.config;e.forEach(e=>{this.events.addEventListener(e,e=>{this.art.emit(`video:${e.type}`,e)})})}addEventListener(e,t){this.events.addEventListener(e,t)}removeEventListener(e,t){this.events.removeEventListener(e,t)}get src(){return this._src}set src(e){this._src=e,e&&this.engine.load(e)}get currentSrc(){return this._src}get currentTime(){return this.engine.currentTime}set currentTime(e){this.engine.seek(Number(e)||0)}get duration(){return this.engine.duration}get buffered(){return this.createTimeRanges(0,this.engine.duration)}get played(){return this.createTimeRanges(0,this.engine.currentTime)}get seekable(){return this.createTimeRanges(0,this.engine.duration)}createTimeRanges(e,t){const r=this.engine.duration;return!r||Number.isNaN(r)||t<=0?{length:0,start:()=>0,end:()=>0}:{length:1,start:()=>e,end:()=>t}}get paused(){return this.engine.paused}get playing(){return!this.engine.paused&&!this.engine.ended}get ended(){return this.engine.ended}get seeking(){return this.engine.seeking}get readyState(){return this.engine.readyState}get networkState(){return this.engine.networkState}get error(){return this.engine.error}get playbackRate(){return this._playbackRate}set playbackRate(e){const t=Number(e);Number.isNaN(t)||t<=0||(this._playbackRate=t,this.engine.setPlaybackRate(t),this.events.emit("ratechange"))}get volume(){return this._volume}set volume(e){this._volume=function(e,t,r){return Math.max(t,Math.min(r,Number(e)||0))}(e,0,1),this._muted=!1,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}get muted(){return this._muted}set muted(e){this._muted=!!e,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}play(){return this.engine.play()}pause(){this.engine.pause()}load(){this._src&&this.engine.load(this._src)}get videoWidth(){return this.engine.videoWidth}get videoHeight(){return this.engine.videoHeight}get poster(){return this.option.poster||""}set poster(e){this.option.poster=e}get autoplay(){return this.option.autoplay||!1}set autoplay(e){}get loop(){return this.option.loop||!1}set loop(e){}get controls(){return!1}set controls(e){}get playsInline(){return!0}set playsInline(e){}get crossOrigin(){return this.option.crossOrigin||""}set crossOrigin(e){}get preload(){return"auto"}set preload(e){}get defaultMuted(){return!1}set defaultMuted(e){}get defaultPlaybackRate(){return 1}set defaultPlaybackRate(e){}canPlayType(e){return"maybe"}getBoundingClientRect(){return this.canvas.getBoundingClientRect()}requestVideoFrameCallback(e){return requestAnimationFrame(t=>{e(t,{presentationTime:this.engine.currentTime,expectedDisplayTime:t+16.6,width:this.engine.videoWidth,height:this.engine.videoHeight,mediaTime:this.engine.currentTime,presentedFrames:0,processingDuration:0,captureTime:t,receiveTime:t,rtpTimestamp:0})})}cancelVideoFrameCallback(e){cancelAnimationFrame(e)}setAttribute(e,t){"src"===e?this.src=t:"autoplay"===e?this.autoplay=t:"loop"===e?this.loop=t:"muted"===e?this.muted=!0:this.canvas.setAttribute(e,t)}destroy(){this.engine.destroy()}}return function(e={}){return t=>{const{constructor:r}=t,{createElement:i}=r.utils,a=i("canvas"),s=a.getContext("2d"),n=new va({art:t,canvas:a,ctx:s,option:e}),o={};for(const e in a)"function"===typeof a[e]&&(o[e]=a[e].bind(a));const c=new Set([...Object.getOwnPropertyNames(n),...Object.getOwnPropertyNames(Object.getPrototypeOf(n))]);for(const e of c)"constructor"!==e&&(e in a||Object.defineProperty(a,e,{get(){const t=n[e];return"function"===typeof t?t.bind(n):t},set(t){n[e]=t},configurable:!0,enumerable:!0}));for(const e in o)a[e]=(...t)=>o[e](...t);function l(){const e=t.template?.$player;e&&!t.option.autoSize&&Object.assign(a.style,{width:"100%",height:"100%",objectFit:"contain"})}return t.on("resize",l),t.on("video:loadedmetadata",l),t.on("destroy",()=>{n.destroy()}),a}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";function e(e,t){const i=new Map;return e.filter(e=>{const r=e[t];return void 0===r||!i.has(r)&&i.set(r,1)})}class t{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const i=this.listeners.get(e);if(!i)return;const r=i.indexOf(t);r>=0&&i.splice(r,1)}emit(e,t){const i=new Event(e);i.detail=t;const r=this.listeners.get(e);r&&r.forEach(e=>e(i))}}function i(e){if(!e)throw new Error("Assertion failed.")}const r=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},a=e=>e&&e[e.length-1],s=e=>{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<{const t=s(e);return 0===(1&t)?-(t>>1):t+1>>1},o=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),c=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),l=new TextDecoder,u=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),d={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},h=u(d),f={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},m=u(f),p={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},g=u(p),k=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class b{constructor(){this.currentPromise=Promise.resolve(),this.pending=0}async acquire(){let e;const t=new Promise(t=>{let i=!1;e=()=>{i||(t(),this.pending--,i=!0)}}),i=this.currentPromise;return this.currentPromise=t,this.pending++,await i,e}}const y=/^[0-9a-fA-F]+$/,w=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),T=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,S=(e,t,i)=>{let r=0,a=e.length-1,s=-1;for(;r<=a;){const n=r+a>>1,o=i(e[n]);o===t?(s=n,a=n-1):o{let r=0,a=e.length-1,s=-1;for(;r<=a;){const n=r+(a-r+1)/2|0;i(e[n])<=t?(s=n,r=n+1):a=n-1}return s},v=(e,t,i)=>{const r=P(e,i(t),i);e.splice(r+1,0,t)},I=()=>{let e,t;return{promise:new Promise((i,r)=>{e=i,t=r}),resolve:e,reject:t}},x=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return e[i]},C=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return i;return-1},B=e=>{throw new Error(`Unexpected value: ${e}`)},E=(e,t,i)=>{const r=e.getUint8(t),a=e.getUint8(t+1),s=e.getUint8(t+2);return i?r|a<<8|s<<16:r<<16|a<<8|s},_=(e,t,i,r)=>{i>>>=0,i&=16777215,e.setUint8(t,i>>>16&255),e.setUint8(t+1,i>>>8&255),e.setUint8(t+2,255&i)},A=(e,t)=>({async next(){const i=await e.next();return i.done?{value:void 0,done:!0}:{value:t(i.value),done:!1}},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),F=(e,t,i)=>Math.max(t,Math.min(i,e)),R="und",D=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},M=(e,t)=>Math.round(e*t)/t,N=(e,t)=>Math.floor(e/t)*t,O=/^[a-z]{3}$/,L=e=>O.test(e),z=1e6*(1+Number.EPSILON),U=(e,t)=>{const i={...e,...t};if(e.headers||t.headers){const r=e.headers?q(e.headers):{},a=t.headers?q(t.headers):{},s={...r};Object.entries(a).forEach(([e,t])=>{const i=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());i&&delete s[i],s[e]=t}),i.headers=s}return i},q=e=>{if(e instanceof Headers){const t={};return e.forEach((e,i)=>{t[i]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,i])=>{t[e]=i}),t}return e},W=async(e,t,i,r,a)=>{let s=0;for(;;)try{return await e(t,i)}catch(n){if(a())throw n;s++;const e=r(s,n,t);if(null===e)throw n;if(console.error("Retrying failed fetch. Error:",n),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&await ce(1e3*e),a())throw n}};class V{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let H=null;const K=()=>null!==H?H:H=!("undefined"===typeof navigator||!(navigator.vendor?.match(/apple/i)||/AppleWebKit/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)||/\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent)));let j=null;const X=()=>null!==j?j:j="undefined"!==typeof navigator&&navigator.userAgent?.includes("Firefox");let $=null;const Q=()=>null!==$?$:$=!("undefined"===typeof navigator||!navigator.vendor?.includes("Google Inc")&&!/Chrome/.test(navigator.userAgent));let G=null;const Y=()=>{if(null!==G)return G;if("undefined"===typeof navigator)return null;const e=/\bChrome\/(\d+)/.exec(navigator.userAgent);return e?G=Number(e[1]):null},J=(e,t)=>-1!==e?e:t,Z=(e,t,i,r)=>e<=r&&i<=t,ee=e=>{const t=atob(e),i=new Uint8Array(t.length);for(let r=0;r{Symbol.dispose??(Symbol.dispose=Symbol("Symbol.dispose"))},ie=e=>"number"===typeof e&&!Number.isNaN(e),re=(e,t)=>{if(t.includes("://"))return t;if(e.includes("://")){const t=e.indexOf("?");-1!==t&&(e=e.slice(0,t))}let i;if(t.startsWith("/")){const r=e.indexOf("://");if(-1===r)i=t;else{const a=e.indexOf("/",r+3);i=-1===a?e+t:e.slice(0,a)+t}}else{const r=e.lastIndexOf("/");i=-1===r?t:e.slice(0,r+1)+t}let r="";const a=i.indexOf("://");if(-1!==a){const e=i.indexOf("/",a+3);-1!==e&&(r=i.slice(0,e),i=i.slice(e))}const s=i.split("/"),n=[];for(const o of s)".."===o?n.pop():"."!==o&&n.push(o);return r+n.join("/")},ae=(e,t)=>{let i=0;for(let r=0;r{let i=-1,r=1/0;for(let a=0;a{i(Number.isInteger(e.num)),i(Number.isInteger(e.den)),i(0!==e.den);let t=Math.abs(e.num),r=Math.abs(e.den);for(;0!==r;){const e=t%r;t=r,r=e}const a=t||1;return{num:e.num/a,den:e.den/a}},oe=(e,t)=>{if("object"!==typeof e||!e)throw new TypeError(`${t} must be an object.`);if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(`${t}.left must be a non-negative integer.`);if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(`${t}.top must be a non-negative integer.`);if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(`${t}.width must be a non-negative integer.`);if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(`${t}.height must be a non-negative integer.`)},ce=e=>new Promise(t=>setTimeout(t,e));class le{constructor(){this._listeners=new Map}on(e,t,i){this._listeners.has(e)||this._listeners.set(e,new Set);const r={fn:t,once:i?.once??!1};return this._listeners.get(e).add(r),()=>{this._listeners.get(e)?.delete(r)}}_emit(...e){const[t,i]=e,r=this._listeners.get(t);if(r)for(const s of r){try{s.fn(i)}catch(a){console.error(a)}s.once&&r.delete(s)}}}class ue{constructor(e,t){if(this.data=e,this.mimeType=t,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("string"!==typeof t)throw new TypeError("mimeType must be a string.")}}class de{constructor(e,t,i,r){if(this.data=e,this.mimeType=t,this.name=i,this.description=r,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if(void 0!==t&&"string"!==typeof t)throw new TypeError("mimeType, when provided, must be a string.");if(void 0!==i&&"string"!==typeof i)throw new TypeError("name, when provided, must be a string.");if(void 0!==r&&"string"!==typeof r)throw new TypeError("description, when provided, must be a string.")}}const he={default:!0,primary:!0,forced:!1,original:!1,commentary:!1,hearingImpaired:!1,visuallyImpaired:!1};class fe{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){const e=Math.floor(this.pos/8),t=this.bytes[e]??0,i=7-(7&this.pos),r=(t&1<>i;return this.pos++,r}readBits(e){if(1===e)return this.readBit();let t=0;for(let i=0;i>i-r-1<{if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");const t=new fe(e);let i=t.readBits(5);31===i&&(i=32+t.readBits(6));const r=t.readBits(4);let a=null;15===r?a=t.readBits(24):r=1&&s<=7&&(n=pe[s]),{objectType:i,frequencyIndex:r,sampleRate:a,channelConfiguration:s,numberOfChannels:n}},ke=["avc","hevc","vp9","av1","vp8"],be=["pcm-s16","pcm-s16be","pcm-s24","pcm-s24be","pcm-s32","pcm-s32be","pcm-f32","pcm-f32be","pcm-f64","pcm-f64be","pcm-u8","pcm-s8","ulaw","alaw"],ye=["aac","opus","mp3","vorbis","flac","ac3","eac3",...be],we=[{maxMacroblocks:99,maxBitrate:64e3,maxDpbMbs:396,level:10},{maxMacroblocks:396,maxBitrate:192e3,maxDpbMbs:900,level:11},{maxMacroblocks:396,maxBitrate:384e3,maxDpbMbs:2376,level:12},{maxMacroblocks:396,maxBitrate:768e3,maxDpbMbs:2376,level:13},{maxMacroblocks:396,maxBitrate:2e6,maxDpbMbs:2376,level:20},{maxMacroblocks:792,maxBitrate:4e6,maxDpbMbs:4752,level:21},{maxMacroblocks:1620,maxBitrate:4e6,maxDpbMbs:8100,level:22},{maxMacroblocks:1620,maxBitrate:1e7,maxDpbMbs:8100,level:30},{maxMacroblocks:3600,maxBitrate:14e6,maxDpbMbs:18e3,level:31},{maxMacroblocks:5120,maxBitrate:2e7,maxDpbMbs:20480,level:32},{maxMacroblocks:8192,maxBitrate:2e7,maxDpbMbs:32768,level:40},{maxMacroblocks:8192,maxBitrate:5e7,maxDpbMbs:32768,level:41},{maxMacroblocks:8704,maxBitrate:5e7,maxDpbMbs:34816,level:42},{maxMacroblocks:22080,maxBitrate:135e6,maxDpbMbs:110400,level:50},{maxMacroblocks:36864,maxBitrate:24e7,maxDpbMbs:184320,level:51},{maxMacroblocks:36864,maxBitrate:24e7,maxDpbMbs:184320,level:52},{maxMacroblocks:139264,maxBitrate:24e7,maxDpbMbs:696320,level:60},{maxMacroblocks:139264,maxBitrate:48e7,maxDpbMbs:696320,level:61},{maxMacroblocks:139264,maxBitrate:8e8,maxDpbMbs:696320,level:62}],Te=[{maxPictureSize:36864,maxBitrate:2e5,level:10},{maxPictureSize:73728,maxBitrate:8e5,level:11},{maxPictureSize:122880,maxBitrate:18e5,level:20},{maxPictureSize:245760,maxBitrate:36e5,level:21},{maxPictureSize:552960,maxBitrate:72e5,level:30},{maxPictureSize:983040,maxBitrate:12e6,level:31},{maxPictureSize:2228224,maxBitrate:18e6,level:40},{maxPictureSize:2228224,maxBitrate:3e7,level:41},{maxPictureSize:8912896,maxBitrate:6e7,level:50},{maxPictureSize:8912896,maxBitrate:12e7,level:51},{maxPictureSize:8912896,maxBitrate:18e7,level:52},{maxPictureSize:35651584,maxBitrate:18e7,level:60},{maxPictureSize:35651584,maxBitrate:24e7,level:61},{maxPictureSize:35651584,maxBitrate:48e7,level:62}],Se=".01.01.01.01.00",Pe=".0.110.01.01.01.0",ve=e=>{const{codec:t,codecDescription:r,colorSpace:s,avcCodecInfo:n,hevcCodecInfo:o,vp9CodecInfo:l,av1CodecInfo:u}=e;if("avc"===t){if(i(null!==e.avcType),n){const t=new Uint8Array([n.avcProfileIndication,n.profileCompatibility,n.avcLevelIndication]);return`avc${e.avcType}.${w(t)}`}if(!r||r.byteLength<4)throw new TypeError("AVC decoder description is not provided or is not at least 4 bytes long.");return`avc${e.avcType}.${w(r.subarray(1,4))}`}if("hevc"===t){let e,t,i,a,s,n;if(o)e=o.generalProfileSpace,t=o.generalProfileIdc,i=T(o.generalProfileCompatibilityFlags),a=o.generalTierFlag,s=o.generalLevelIdc,n=[...o.generalConstraintIndicatorFlags];else{if(!r||r.byteLength<23)throw new TypeError("HEVC decoder description is not provided or is not at least 23 bytes long.");const o=c(r),l=o.getUint8(1);e=l>>6&3,t=31&l,i=T(o.getUint32(2)),a=l>>5&1,s=o.getUint8(12),n=[];for(let e=0;e<6;e++)n.push(o.getUint8(6+e))}let l="hev1.";for(l+=["","A","B","C"][e]+t,l+=".",l+=i.toString(16).toUpperCase(),l+=".",l+=0===a?"L":"H",l+=s;n.length>0&&0===n[n.length-1];)n.pop();return n.length>0&&(l+=".",l+=n.map(e=>e.toString(16).toUpperCase()).join(".")),l}if("vp8"===t)return"vp8";if("vp9"===t){if(!l){const t=e.width*e.height;let i=a(Te).level;for(const e of Te)if(t<=e.maxPictureSize){i=e.level;break}return`vp09.00.${i.toString().padStart(2,"0")}.08`}let t=`vp09.${l.profile.toString().padStart(2,"0")}.${l.level.toString().padStart(2,"0")}.${l.bitDepth.toString().padStart(2,"0")}.${l.chromaSubsampling.toString().padStart(2,"0")}`;return t+=`.${l.colourPrimaries.toString().padStart(2,"0")}.${l.transferCharacteristics.toString().padStart(2,"0")}.${l.matrixCoefficients.toString().padStart(2,"0")}.${l.videoFullRangeFlag.toString().padStart(2,"0")}`,t.endsWith(Se)&&(t=t.slice(0,-15)),t}if("av1"===t){if(!u){const t=e.width*e.height;let i=a(Te).level;for(const e of Te)if(t<=e.maxPictureSize){i=e.level;break}return`av01.0.${i.toString().padStart(2,"0")}M.08`}const t=u.profile,i=u.level.toString().padStart(2,"0"),r=u.tier?"H":"M",n=u.bitDepth.toString().padStart(2,"0"),o=u.monochrome?"1":"0",c=100*u.chromaSubsamplingX+10*u.chromaSubsamplingY+1*(u.chromaSubsamplingX&&u.chromaSubsamplingY?u.chromaSamplePosition:0),l=s?.primaries?d[s.primaries]:1,h=s?.transfer?f[s.transfer]:1,m=s?.matrix?p[s.matrix]:1,g=s?.fullRange?1:0;let k=`av01.${t}.${i}${r}.${n}`;return k+=`.${o}.${c.toString().padStart(3,"0")}`,k+=`.${l.toString().padStart(2,"0")}`,k+=`.${h.toString().padStart(2,"0")}`,k+=`.${m.toString().padStart(2,"0")}`,k+=`.${g}`,k.endsWith(Pe)&&(k=k.slice(0,-17)),k}throw new TypeError(`Unhandled codec '${t}'.`)},Ie=e=>{const{codec:t,codecDescription:i,aacCodecInfo:r}=e;if("aac"===t){if(!r)throw new TypeError("AAC codec info must be provided.");if(r.isMpeg2)return"mp4a.67";{let e;if(null!==r.objectType)e=r.objectType;else{e=ge(i).objectType}return`mp4a.40.${e}`}}if("mp3"===t)return"mp3";if("opus"===t)return"opus";if("vorbis"===t)return"vorbis";if("flac"===t)return"flac";if("ac3"===t)return"ac-3";if("eac3"===t)return"ec-3";if(t&&be.includes(t))return t;throw new TypeError(`Unhandled codec '${t}'.`)},xe=48e3,Ce=/^pcm-([usf])(\d+)+(be)?$/,Be=e=>{if(i(be.includes(e)),"ulaw"===e)return{dataType:"ulaw",sampleSize:1,littleEndian:!0,silentValue:255};if("alaw"===e)return{dataType:"alaw",sampleSize:1,littleEndian:!0,silentValue:213};const t=Ce.exec(e);let r;i(t),r="u"===t[1]?"unsigned":"s"===t[1]?"signed":"float";return{dataType:r,sampleSize:Number(t[2])/8,littleEndian:"be"!==t[3],silentValue:"pcm-u8"===e?128:0}},Ee=e=>e.startsWith("avc1")||e.startsWith("avc3")?"avc":e.startsWith("hev1")||e.startsWith("hvc1")?"hevc":"vp8"===e?"vp8":e.startsWith("vp09")?"vp9":e.startsWith("av01")?"av1":"mp3"===e||"mp4a.69"===e||"mp4a.6B"===e||"mp4a.6b"===e||"mp4a.40.34"===e?"mp3":e.startsWith("mp4a.40.")||"mp4a.67"===e?"aac":"opus"===e?"opus":"vorbis"===e?"vorbis":"flac"===e?"flac":"ac-3"===e||"ac3"===e?"ac3":"ec-3"===e||"eac3"===e?"eac3":"ulaw"===e?"ulaw":"alaw"===e?"alaw":Ce.test(e)?e:"webvtt"===e?"webvtt":null,_e=[44100,48e3,32e3],Ae=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1,-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1,-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1],Fe=1483304551,Re=1231971951,De=(e,t)=>3===e?3===t?21:36:3===t?13:21,Me=(e,t)=>{const i=e>>>24,r=e>>>16&255,a=e>>>8&255,s=255&e;if(255!==i&&255!==r&&255!==a&&255!==s)return{header:null,bytesAdvanced:4};if(255!==i)return{header:null,bytesAdvanced:1};if(224!==(224&r))return{header:null,bytesAdvanced:1};let n=0,o=0;16&r?n=8&r?0:1:(n=1,o=1);const c=r>>3&3,l=r>>1&3,u=(a>>2&3)%3,d=s>>6&3,h=s>>4&3,f=s>>3&1,m=s>>2&1,p=3&s,g=Ae[16*n*4+16*l+(a>>4&15)];if(-1===g)return{header:null,bytesAdvanced:1};const k=1e3*g,b=_e[u]>>n+o,y=((e,t,i,r,a)=>0===t?0:1===t?Math.floor(144*i/(r<>1&1);if(null!==t&&t{let t=2130706432,i=0;for(;0!==t;)i>>=1,i|=e&t,t>>=8;return i};var Oe,Le;(Le=Oe||(Oe={}))[Le.FrameCount=1]="FrameCount",Le[Le.FileSize=2]="FileSize",Le[Le.Toc=4]="Toc";const ze=[48e3,44100,32e3],Ue=[24e3,22050,16e3];var qe,We,Ve,He;(We=qe||(qe={}))[We.NON_IDR_SLICE=1]="NON_IDR_SLICE",We[We.SLICE_DPA=2]="SLICE_DPA",We[We.SLICE_DPB=3]="SLICE_DPB",We[We.SLICE_DPC=4]="SLICE_DPC",We[We.IDR=5]="IDR",We[We.SEI=6]="SEI",We[We.SPS=7]="SPS",We[We.PPS=8]="PPS",We[We.AUD=9]="AUD",We[We.SPS_EXT=13]="SPS_EXT",(He=Ve||(Ve={}))[He.RASL_N=8]="RASL_N",He[He.RASL_R=9]="RASL_R",He[He.BLA_W_LP=16]="BLA_W_LP",He[He.RSV_IRAP_VCL23=23]="RSV_IRAP_VCL23",He[He.VPS_NUT=32]="VPS_NUT",He[He.SPS_NUT=33]="SPS_NUT",He[He.PPS_NUT=34]="PPS_NUT",He[He.AUD_NUT=35]="AUD_NUT",He[He.PREFIX_SEI_NUT=39]="PREFIX_SEI_NUT",He[He.SUFFIX_SEI_NUT=40]="SUFFIX_SEI_NUT";const Ke=function*(e){let t=0,i=-1;for(;t=e.length-2)break;t=r;let a=0;t+3i&&(yield{offset:i,length:t-i}),i=t+a,t=i):t++}-1!==i&&i{if(t.description){const i=3&o(t.description)[4];return je(e,i+1)}return Ke(e)},$e=e=>31&e,Qe=e=>{const t=[],i=e.length;for(let r=0;r{const t=e.reduce((e,t)=>e+Ge.byteLength+t.byteLength,0),i=new Uint8Array(t);let r=0;for(const a of e)i.set(Ge,r),r+=Ge.byteLength,i.set(a,r),r+=a.byteLength;return i},Je=(e,t)=>{const i=e.reduce((e,i)=>e+t+i.byteLength,0),r=new Uint8Array(i);let a=0;for(const s of e){const e=new DataView(r.buffer,r.byteOffset,r.byteLength);switch(t){case 1:e.setUint8(a,s.byteLength);break;case 2:e.setUint16(a,s.byteLength,!1);break;case 3:_(e,a,s.byteLength);break;case 4:e.setUint32(a,s.byteLength,!1)}a+=t,r.set(s,a),a+=s.byteLength}return r},Ze=e=>{try{const t=[],r=[],a=[];for(const i of Ke(e)){const s=e.subarray(i.offset,i.offset+i.length),n=$e(s[0]);n===qe.SPS?t.push(s):n===qe.PPS?r.push(s):n===qe.SPS_EXT&&a.push(s)}if(0===t.length)return null;if(0===r.length)return null;const s=t[0],n=tt(s);i(null!==n);const o=100===n.profileIdc||110===n.profileIdc||122===n.profileIdc||144===n.profileIdc;return{configurationVersion:1,avcProfileIndication:n.profileIdc,profileCompatibility:n.constraintFlags,avcLevelIndication:n.levelIdc,lengthSizeMinusOne:3,sequenceParameterSets:t,pictureParameterSets:r,chromaFormat:o?n.chromaFormatIdc:null,bitDepthLumaMinus8:o?n.bitDepthLumaMinus8:null,bitDepthChromaMinus8:o?n.bitDepthChromaMinus8:null,sequenceParameterSetExt:o?a:null}}catch(t){return console.error("Error building AVC Decoder Configuration Record:",t),null}},et={1:{num:1,den:1},2:{num:12,den:11},3:{num:10,den:11},4:{num:16,den:11},5:{num:40,den:33},6:{num:24,den:11},7:{num:20,den:11},8:{num:32,den:11},9:{num:80,den:33},10:{num:18,den:11},11:{num:15,den:11},12:{num:64,den:33},13:{num:160,den:99},14:{num:4,den:3},15:{num:3,den:2},16:{num:2,den:1}},tt=e=>{try{const t=new fe(Qe(e));t.skipBits(1),t.skipBits(2);if(7!==t.readBits(5))return null;const r=t.readAlignedByte(),o=t.readAlignedByte(),c=t.readAlignedByte();s(t);let l=1,u=0,d=0,h=0;if(100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r){l=s(t),3===l&&(h=t.readBits(1)),u=s(t),d=s(t),t.skipBits(1);if(t.readBits(1))for(let e=0;e<(3!==l?8:12);e++){if(t.readBits(1)){const i=e<6?16:64;let r=8,a=8;for(let e=0;ee.level>=c)??a(we),r=Math.min(Math.floor(i.maxDpbMbs/(e*t)),16);x=r,C=r}else x=0,C=0}return i(null!==C),{profileIdc:r,constraintFlags:o,levelIdc:c,frameMbsOnlyFlag:w,chromaFormatIdc:l,bitDepthLumaMinus8:u,bitDepthChromaMinus8:d,codedWidth:g,codedHeight:k,displayWidth:b,displayHeight:y,pixelAspectRatio:I,colourPrimaries:T,matrixCoefficients:P,transferCharacteristics:S,fullRangeFlag:v,numReorderFrames:x,maxDecFrameBuffering:C}}catch(t){return console.error("Error parsing AVC SPS:",t),null}},it=e=>{const t=s(e);e.skipBits(4),e.skipBits(4);for(let i=0;i<=t;i++)s(e),s(e),e.skipBits(1);e.skipBits(5),e.skipBits(5),e.skipBits(5),e.skipBits(5)},rt=(e,t)=>{if(t.description){const i=3&o(t.description)[21];return je(e,i+1)}return Ke(e)},at=e=>e>>1&63,st=e=>{try{const t=new fe(Qe(e));t.skipBits(16),t.readBits(4);const i=t.readBits(3),r=t.readBits(1),{general_profile_space:a,general_tier_flag:n,general_profile_idc:o,general_profile_compatibility_flags:c,general_constraint_indicator_flags:l,general_level_idc:u}=ot(t,i);s(t);const d=s(t);let h=0;3===d&&(h=t.readBits(1));const f=s(t),m=s(t);let p=f,g=m;if(t.readBits(1)){const e=s(t),i=s(t),r=s(t),a=s(t);let n=1,o=1;const c=0===h?d:0;1===c?(n=2,o=2):2===c&&(n=2,o=1),p-=(e+i)*n,g-=(r+a)*o}const k=s(t),b=s(t);s(t);const y=t.readBits(1);let w=0;for(let e=y?0:i;e<=i;e++)s(t),w=s(t),s(t);s(t),s(t),s(t),s(t),s(t),s(t),t.readBits(1)&&t.readBits(1)&&ct(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&(t.skipBits(4),t.skipBits(4),s(t),s(t),t.skipBits(1));const T=s(t);if(lt(t,T),t.readBits(1)){const e=s(t);for(let i=0;i{try{const t=[],i=[],r=[],a=[];for(const s of Ke(e)){const n=e.subarray(s.offset,s.offset+s.length),o=at(n[0]);o===Ve.VPS_NUT?t.push(n):o===Ve.SPS_NUT?i.push(n):o===Ve.PPS_NUT?r.push(n):o!==Ve.PREFIX_SEI_NUT&&o!==Ve.SUFFIX_SEI_NUT||a.push(n)}if(0===i.length||0===r.length)return null;const o=st(i[0]);if(!o)return null;let c=0;if(r.length>0){const e=r[0],t=new fe(Qe(e));t.skipBits(16),s(t),s(t),t.skipBits(1),t.skipBits(1),t.skipBits(3),t.skipBits(1),t.skipBits(1),s(t),s(t),n(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&s(t),n(t),n(t),t.skipBits(1),t.skipBits(1),t.skipBits(1),t.skipBits(1);const i=t.readBits(1),a=t.readBits(1);c=i||a?i&&!a?2:!i&&a?3:0:0}const l=[...t.length?[{arrayCompleteness:1,nalUnitType:Ve.VPS_NUT,nalUnits:t}]:[],...i.length?[{arrayCompleteness:1,nalUnitType:Ve.SPS_NUT,nalUnits:i}]:[],...r.length?[{arrayCompleteness:1,nalUnitType:Ve.PPS_NUT,nalUnits:r}]:[],...a.length?[{arrayCompleteness:1,nalUnitType:at(a[0][0]),nalUnits:a}]:[]];return{configurationVersion:1,generalProfileSpace:o.generalProfileSpace,generalTierFlag:o.generalTierFlag,generalProfileIdc:o.generalProfileIdc,generalProfileCompatibilityFlags:o.generalProfileCompatibilityFlags,generalConstraintIndicatorFlags:o.generalConstraintIndicatorFlags,generalLevelIdc:o.generalLevelIdc,minSpatialSegmentationIdc:o.minSpatialSegmentationIdc,parallelismType:c,chromaFormatIdc:o.chromaFormatIdc,bitDepthLumaMinus8:o.bitDepthLumaMinus8,bitDepthChromaMinus8:o.bitDepthChromaMinus8,avgFrameRate:0,constantFrameRate:0,numTemporalLayers:o.spsMaxSubLayersMinus1+1,temporalIdNested:o.spsTemporalIdNestingFlag,lengthSizeMinusOne:3,arrays:l}}catch(t){return console.error("Error building HEVC Decoder Configuration Record:",t),null}},ot=(e,t)=>{const i=e.readBits(2),r=e.readBits(1),a=e.readBits(5);let s=0;for(let u=0;u<32;u++)s=s<<1|e.readBits(1);const n=new Uint8Array(6);for(let u=0;u<6;u++)n[u]=e.readBits(8);const o=e.readBits(8),c=[],l=[];for(let u=0;u0)for(let u=t;u<8;u++)e.skipBits(2);for(let u=0;u{for(let t=0;t<4;t++)for(let i=0;i<(3===t?2:6);i++){if(e.readBits(1)){const i=Math.min(64,1<<4+(t<<1));t>1&&n(e);for(let t=0;t{const i=[];for(let r=0;r{let a=0,n=0,o=0;if(0!==t&&(n=e.readBits(1)),n){if(t===i){o=t-(s(e)+1)}else o=t-1;e.readBits(1),s(e);const n=r[o]??0;for(let t=0;t<=n;t++){e.readBits(1)||e.readBits(1)}a=r[o]}else{const t=s(e),i=s(e);for(let r=0;r{let i=2,r=2,a=2,n=0,o=0,c={num:1,den:1};if(e.readBits(1)){const t=e.readBits(8);if(255===t)c={num:e.readBits(16),den:e.readBits(16)};else{const e=et[t];e&&(c=e)}}return e.readBits(1)&&e.readBits(1),e.readBits(1)&&(e.readBits(3),n=e.readBits(1),e.readBits(1)&&(i=e.readBits(8),r=e.readBits(8),a=e.readBits(8))),e.readBits(1)&&(s(e),s(e)),e.readBits(1),e.readBits(1),e.readBits(1),e.readBits(1)&&(s(e),s(e),s(e),s(e)),e.readBits(1)&&(e.readBits(32),e.readBits(32),e.readBits(1)&&s(e),e.readBits(1)&&ht(e,!0,t)),e.readBits(1)&&(e.readBits(1),e.readBits(1),e.readBits(1),o=s(e),s(e),s(e),s(e),s(e)),{pixelAspectRatio:c,colourPrimaries:i,transferCharacteristics:r,matrixCoefficients:a,fullRangeFlag:n,minSpatialSegmentationIdc:o}},ht=(e,t,i)=>{let r=!1,a=!1,n=!1;r=1===e.readBits(1),a=1===e.readBits(1),(r||a)&&(n=1===e.readBits(1),n&&(e.readBits(8),e.readBits(5),e.readBits(1),e.readBits(5)),e.readBits(4),e.readBits(4),n&&e.readBits(4),e.readBits(5),e.readBits(5),e.readBits(5));for(let o=0;o<=i;o++){let t=!0;1===e.readBits(1)||(t=1===e.readBits(1));let i=!1;t?s(e):i=1===e.readBits(1);let o=1;if(!i){o=s(e)+1}r&&ft(e,o,n),a&&ft(e,o,n)}},ft=(e,t,i)=>{for(let r=0;r{const i=new Set;let r=mt.audAllowed;for(const s of rt(e,t)){if(r===mt.noMoreDataAllowed){i.add(s.offset);continue}const t=at(e[s.offset]);if(r===mt.eoBitstreamAllowed&&37!==t){i.add(s.offset);continue}let a=!1;35===t?r>mt.audAllowed?a=!0:r=mt.beforeFirstVcl:t<=31?r>mt.afterFirstVcl?a=!0:r=mt.afterFirstVcl:36===t?r!==mt.afterFirstVcl?a=!0:r=mt.eoBitstreamAllowed:37===t?r=41&&t<=44||t>=48&&t<=55?r>mt.beforeFirstVcl?a=!0:r=mt.beforeFirstVcl:(38===t||40===t||t>=45&&t<=47||t>=56&&t<=63)&&r{if(t.description){const i=3&o(t.description)[21];return Je(e,i+1)}return Ye(e)})(a,t)},kt=e=>{const t=new fe(e);if(2!==t.readBits(2))return null;const i=t.readBits(1),r=(t.readBits(1)<<1)+i;3===r&&t.skipBits(1);if(1===t.readBits(1))return null;if(0!==t.readBits(1))return null;t.skipBits(2);if(4817730!==t.readBits(24))return null;let s=8;if(r>=2){s=t.readBits(1)?12:10}const n=t.readBits(3);let o=0,c=0;if(7!==n){if(c=t.readBits(1),1===r||3===r){const e=t.readBits(1),i=t.readBits(1);o=e||i?e&&!i?2:1:3,t.skipBits(1)}else o=1}else o=3,c=1;const l=(t.readBits(16)+1)*(t.readBits(16)+1);let u=a(Te).level;for(const a of Te)if(l<=a.maxPictureSize){u=a.level;break}return{profile:r,level:u,bitDepth:s,chromaSubsampling:o,videoFullRangeFlag:c,colourPrimaries:2===n?1:1===n?6:2,transferCharacteristics:2===n?1:1===n?6:2,matrixCoefficients:7===n?0:2===n?1:1===n?6:2}},bt=function*(e){const t=new fe(e),r=()=>{let e=0;for(let i=0;i<8;i++){const r=t.readAlignedByte();if(e|=(127&r)<<7*i,!(128&r))break;if(7===i&&128&r)return null}return e>=2**32-1?null:e};for(;t.getBitsLeft()>=8;){t.skipBits(1);const a=t.readBits(4),s=t.readBits(1),n=t.readBits(1);let o;if(t.skipBits(1),s&&t.skipBits(8),n){const e=r();if(null===e)return;o=e}else o=Math.floor(t.getBitsLeft()/8);i(t.pos%8===0),yield{type:a,data:e.subarray(t.pos/8,t.pos/8+o)},t.skipBits(8*o)}},yt=e=>{for(const{type:t,data:i}of bt(e)){if(1!==t)continue;const e=new fe(i),r=e.readBits(3);e.readBits(1);const a=e.readBits(1);let s=0,n=0,o=0;if(a)s=e.readBits(5);else{if(e.readBits(1)){e.skipBits(32),e.skipBits(32);if(e.readBits(1))return null}const t=e.readBits(1);t&&(o=e.readBits(5),e.skipBits(32),e.skipBits(5),e.skipBits(5));const i=e.readBits(5);for(let r=0;r<=i;r++){e.skipBits(12);const i=e.readBits(5);if(0===r&&(s=i),i>7){const t=e.readBits(1);0===r&&(n=t)}if(t){if(e.readBits(1)){const t=o+1;e.skipBits(t),e.skipBits(t),e.skipBits(1)}}e.readBits(1)&&e.skipBits(4)}}const c=e.readBits(4),l=e.readBits(4),u=c+1;e.skipBits(u);const d=l+1;e.skipBits(d);let h=0;if(h=a?0:e.readBits(1),h&&(e.skipBits(4),e.skipBits(3)),e.skipBits(1),e.skipBits(1),e.skipBits(1),!a){e.skipBits(1),e.skipBits(1),e.skipBits(1),e.skipBits(1);const t=e.readBits(1);t&&(e.skipBits(1),e.skipBits(1));let i=0;if(i=e.readBits(1)?2:e.readBits(1),i>0){e.readBits(1)||e.skipBits(1)}t&&e.skipBits(3)}e.skipBits(1),e.skipBits(1),e.skipBits(1);const f=e.readBits(1);let m=8;if(2===r&&f){m=e.readBits(1)?12:10}else r<=2&&(m=f?10:8);let p=0;1!==r&&(p=e.readBits(1));let g=1,k=1,b=0;return p||(0===r?(g=1,k=1):1===r?(g=0,k=0):12===m&&(g=e.readBits(1),g&&(k=e.readBits(1))),g&&k&&(b=e.readBits(2))),{profile:r,level:s,tier:n,bitDepth:m,monochrome:p,chromaSubsamplingX:g,chromaSubsamplingY:k,chromaSamplePosition:b}}return null},wt=[480,960,1920,2880,480,960,1920,2880,480,960,1920,2880,480,960,480,960,120,240,480,960,120,240,480,960,120,240,480,960,120,240,480,960],Tt=e=>{if(e.length<7)throw new Error("Setup header is too short.");if(5!==e[0])throw new Error("Wrong packet type in Setup header.");if("vorbis"!==String.fromCharCode(...e.slice(1,7)))throw new Error("Invalid packet signature in Setup header.");const t=e.length,i=new Uint8Array(t);for(let u=0;u97;)if(1===r.readBits(1)){a=r.pos;break}if(0===a)throw new Error("Invalid Setup header: framing bit not found.");let s=0,n=!1,o=0;for(;r.getBitsLeft()>=97;){const e=r.pos,t=r.readBits(8),i=r.readBits(16),a=r.readBits(16);if(t>63||0!==i||0!==a){r.pos=e;break}if(r.skipBits(1),s++,s>64)break;r.clone().readBits(6)+1===s&&(n=!0,o=s)}if(!n)throw new Error("Invalid Setup header: mode header not found.");if(o>63)throw new Error(`Unsupported mode count: ${o}.`);const c=o;r.pos=0,r.skipBits(a);const l=Array(c).fill(0);for(let u=c-1;u>=0;u--)r.skipBits(40),l[u]=r.readBits(1);return{modeBlockflags:l}},St=(e,t,r)=>{switch(e){case"avc":for(const e of Xe(r,t)){const t=r[e.offset],i=$e(t);if(i>=qe.NON_IDR_SLICE&&i<=qe.SLICE_DPC)return"delta";if(i===qe.IDR)return"key";if(i===qe.SEI&&(!Q()||Y()>=144)){const t=r.subarray(e.offset,e.offset+e.length),i=Qe(t);let a=1;do{let e=0;for(;;){const t=i[a++];if(void 0===t)break;if(e+=t,t<255)break}let t=0;for(;;){const e=i[a++];if(void 0===e)break;if(t+=e,e<255)break}if(e===6){const e=new fe(i);e.pos=8*a;const t=s(e),r=e.readBits(1);if(0===t&&1===r)return"key"}a+=t}while(a{var i,r;const a=c(e);let s=0;const n=a.getUint32(s,!0);s+=4;const o=l.decode(e.subarray(s,s+n));s+=n,n>0&&(t.raw??(t.raw={}),(i=t.raw).vendor??(i.vendor=o));const u=a.getUint32(s,!0);s+=4;for(let d=0;d0&&(t.trackNumber??(t.trackNumber=i)),r&&Number.isInteger(r)&&r>0&&(t.tracksTotal??(t.tracksTotal=r))}break;case"TRACKTOTAL":{const e=Number.parseInt(d,10);Number.isInteger(e)&&e>0&&(t.tracksTotal??(t.tracksTotal=e))}break;case"DISCNUMBER":{const e=d.split("/"),i=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(t.discNumber??(t.discNumber=i)),r&&Number.isInteger(r)&&r>0&&(t.discsTotal??(t.discsTotal=r))}break;case"DISCTOTAL":{const e=Number.parseInt(d,10);Number.isInteger(e)&&e>0&&(t.discsTotal??(t.discsTotal=e))}break;case"DATE":{const e=new Date(d);Number.isNaN(e.getTime())||(t.date??(t.date=e))}break;case"GENRE":t.genre??(t.genre=d);break;case"METADATA_BLOCK_PICTURE":{const e=ee(d),i=c(e),r=i.getUint32(0,!1),a=i.getUint32(4,!1),s=String.fromCharCode(...e.subarray(8,8+a)),n=i.getUint32(8+a,!1),o=l.decode(e.subarray(12+a,12+a+n)),u=i.getUint32(a+n+28),h=e.subarray(a+n+32,a+n+32+u);t.images??(t.images=[]),t.images.push({data:h,mimeType:s,kind:3===r?"coverFront":4===r?"coverBack":"unknown",name:void 0,description:o||void 0})}}}},xt=[2,1,2,3,3,4,4,5],Ct=e=>{if(e.length<7)return null;if(11!==e[0]||119!==e[1])return null;const t=new fe(e);t.skipBits(16),t.skipBits(16);const i=t.readBits(2);if(3===i)return null;const r=t.readBits(6),a=t.readBits(5);if(a>8)return null;const s=t.readBits(3),n=t.readBits(3);0!==(1&n)&&1!==n&&t.skipBits(2),0!==(4&n)&&t.skipBits(2),2===n&&t.skipBits(2);return{fscod:i,bsid:a,bsmod:s,acmod:n,lfeon:t.readBits(1),bitRateCode:Math.floor(r/2)}},Bt=[128,138,192,128,140,192,160,174,240,160,176,240,192,208,288,192,210,288,224,242,336,224,244,336,256,278,384,256,280,384,320,348,480,320,350,480,384,416,576,384,418,576,448,486,672,448,488,672,512,556,768,512,558,768,640,696,960,640,698,960,768,834,1152,768,836,1152,896,974,1344,896,976,1344,1024,1114,1536,1024,1116,1536,1280,1392,1920,1280,1394,1920,1536,1670,2304,1536,1672,2304,1792,1950,2688,1792,1952,2688,2048,2228,3072,2048,2230,3072,2304,2506,3456,2304,2508,3456,2560,2786,3840,2560,2788,3840],Et=[1,2,3,6],_t=e=>{if(e.length<6)return null;if(11!==e[0]||119!==e[1])return null;const t=new fe(e);t.skipBits(16);const i=t.readBits(2);if(t.skipBits(3),0!==i&&2!==i)return null;const r=t.readBits(11),a=t.readBits(2);let s,n=0;3===a?(n=t.readBits(2),s=3):s=t.readBits(2);const o=t.readBits(3),c=t.readBits(1),l=t.readBits(5);if(l<11||l>16)return null;const u=Et[s];let d;d=a<3?ze[a]/1e3:Ue[n]/1e3;return{dataRate:Math.round((r+1)*d/(16*u)),substreams:[{fscod:a,fscod2:n,bsid:l,bsmod:0,acmod:o,lfeon:c,numDepSub:0,chanLoc:0}]}},At=e=>{const t=e.substreams[0];return i(t),t.fscod<3?ze[t.fscod]:null!==t.fscod2&&t.fscod2<3?Ue[t.fscod2]:null},Ft=e=>{const t=e.substreams[0];i(t);let r=xt[t.acmod]+t.lfeon;if(t.numDepSub>0){const e=[2,2,1,1,2,2,2,1,1];for(let i=0;i<9;i++)t.chanLoc&1<<8-i&&(r+=e[i])}return r};class Rt{constructor(e){this.input=e}dispose(){}}const Dt=new Uint8Array(0);class Mt{constructor(e,t,i,r,a=-1,s,n){if(this.data=e,this.type=t,this.timestamp=i,this.duration=r,this.sequenceNumber=a,e===Dt&&void 0===s)throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets.");if(void 0===s&&(s=e.byteLength),!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("key"!==t&&"delta"!==t)throw new TypeError('type must be either "key" or "delta".');if(!Number.isFinite(i))throw new TypeError("timestamp must be a number.");if(!Number.isFinite(r)||r<0)throw new TypeError("duration must be a non-negative number.");if(!Number.isFinite(a))throw new TypeError("sequenceNumber must be a number.");if(!Number.isInteger(s)||s<0)throw new TypeError("byteLength must be a non-negative integer.");if(void 0!==n&&("object"!==typeof n||!n))throw new TypeError("sideData, when provided, must be an object.");if(void 0!==n?.alpha&&!(n.alpha instanceof Uint8Array))throw new TypeError("sideData.alpha, when provided, must be a Uint8Array.");if(void 0!==n?.alphaByteLength&&(!Number.isInteger(n.alphaByteLength)||n.alphaByteLength<0))throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer.");this.byteLength=s,this.sideData=n??{},this.sideData.alpha&&void 0===this.sideData.alphaByteLength&&(this.sideData.alphaByteLength=this.sideData.alpha.byteLength)}get isMetadataOnly(){return this.data===Dt}get microsecondTimestamp(){return Math.trunc(z*this.timestamp)}get microsecondDuration(){return Math.trunc(z*this.duration)}toEncodedVideoChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}alphaToEncodedVideoChunk(e=this.type){if(!this.sideData.alpha)throw new TypeError("This packet does not contain alpha side data.");if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.sideData.alpha,type:e,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}toEncodedAudioChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to an audio chunk.");if("undefined"===typeof EncodedAudioChunk)throw new Error("Your browser does not support EncodedAudioChunk.");return new EncodedAudioChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}static fromEncodedChunk(e,t){if(!(e instanceof EncodedVideoChunk||e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk.");const i=new Uint8Array(e.byteLength);return e.copyTo(i),new Mt(i,e.type,e.timestamp/1e6,(e.duration??0)/1e6,void 0,void 0,t)}clone(e){if(void 0!==e&&("object"!==typeof e||null===e))throw new TypeError("options, when provided, must be an object.");if(void 0!==e?.data&&!(e.data instanceof Uint8Array))throw new TypeError("options.data, when provided, must be a Uint8Array.");if(void 0!==e?.type&&"key"!==e.type&&"delta"!==e.type)throw new TypeError('options.type, when provided, must be either "key" or "delta".');if(void 0!==e?.timestamp&&!Number.isFinite(e.timestamp))throw new TypeError("options.timestamp, when provided, must be a number.");if(void 0!==e?.duration&&!Number.isFinite(e.duration))throw new TypeError("options.duration, when provided, must be a number.");if(void 0!==e?.sequenceNumber&&!Number.isFinite(e.sequenceNumber))throw new TypeError("options.sequenceNumber, when provided, must be a number.");if(void 0!==e?.sideData&&("object"!==typeof e.sideData||null===e.sideData))throw new TypeError("options.sideData, when provided, must be an object.");return new Mt(e?.data??this.data,e?.type??this.type,e?.timestamp??this.timestamp,e?.duration??this.duration,e?.sequenceNumber??this.sequenceNumber,this.byteLength,e?.sideData??this.sideData)}}const Nt=e=>{const t=c(e);let i=0;const r=t.getUint8(i);i+=1,i+=3;const a=w(e.subarray(i,i+16));i+=16;let s=null;if(r>0){const r=t.getUint32(i);if(i+=4,r>0){s=[];for(let t=0;te.systemId===t.systemId&&((e,t)=>{if(e.length!==t.length)return!1;for(let i=0;i{let t=gn(e);const i=In(e,4);let r=8;1===t&&(t=wn(e),r=16);const a=t-r;return a<0?null:{name:i,totalSize:t,headerSize:r,contentSize:a}},zt=e=>bn(e)/65536,Ut=e=>bn(e)/1073741824,qt=e=>{let t=0;for(let i=0;i<4;i++){t<<=7;const i=un(e);if(t|=127&i,0===(128&i))break}return t},Wt=e=>{let t=hn(e);return e.skip(2),t=Math.min(t,e.remainingLength),l.decode(ln(e,t))},Vt=e=>{const t=Lt(e);if(!t||"data"!==t.name)return null;if(e.remainingLength<8)return null;const i=gn(e);e.skip(4);const r=ln(e,t.contentSize-8);switch(i){case 1:return l.decode(r);case 2:return new TextDecoder("utf-16be").decode(r);case 13:return new ue(r,"image/jpeg");case 14:return new ue(r,"image/png");case 27:return new ue(r,"image/bmp");default:return r}},Ht=16,Kt=new Uint32Array(256),jt=new Uint32Array(256),Xt=new Uint32Array(256),$t=new Uint32Array(256),Qt=new Uint32Array(256),Gt=new Uint32Array(256),Yt=new Uint32Array(10);let Jt=!1;class Zt{constructor(){this.roundkey=new Uint32Array(44),this.iv=new Uint32Array(Ht/Uint32Array.BYTES_PER_ELEMENT),this.in=new Uint8Array(Ht),this.out=new Uint8Array(Ht),this.inView=new DataView(this.in.buffer),this.outView=new DataView(this.out.buffer)}init({key:e,iv:t}){i(16===e.byteLength),i(16===t.byteLength),Jt||(()=>{const e=new Uint8Array(256),t=new Uint8Array(256),i=new Uint8Array(256);for(let s=0,n=1;s<256;s++)i[s]=n,t[n]=s,n=n^n<<1^(128&n?283:0);const r=(e,r)=>e&&r?i[(t[e]+t[r])%255]:0;e[0]=99;for(let s=1;s<256;s++){const r=i[255-t[s]];let a=r^r<<1^r<<2^r<<3^r<<4;a=a>>>8^255&a^99,e[s]=a}for(let s=0;s<256;s++){const t=e[s],i=e.indexOf(s);Kt[s]=t<<24|t<<16|t<<8|t,Gt[s]=i<<24|i<<16|i<<8|i;const a=r(i,14)<<24|r(i,9)<<16|r(i,13)<<8|r(i,11);jt[s]=a,Xt[s]=a>>>8|a<<24,$t[s]=a>>>16|a<<16,Qt[s]=a>>>24|a<<8}let a=1;for(let s=0;s<10;s++)Yt[s]=a<<24,a=a<<1^(128&a?283:0);Jt=!0})();const r=new DataView(e.buffer,e.byteOffset,e.byteLength),a=new DataView(t.buffer,t.byteOffset,t.byteLength);this.roundkey[0]=r.getUint32(0,!1),this.roundkey[1]=r.getUint32(4,!1),this.roundkey[2]=r.getUint32(8,!1),this.roundkey[3]=r.getUint32(12,!1),this.iv[0]=a.getUint32(0,!1),this.iv[1]=a.getUint32(4,!1),this.iv[2]=a.getUint32(8,!1),this.iv[3]=a.getUint32(12,!1);for(let i=4;i<44;i+=4){const e=this.roundkey[i-1];this.roundkey[i]=this.roundkey[i-4]^4278190080&Kt[e>>>16&255]^16711680&Kt[e>>>8&255]^65280&Kt[e>>>0&255]^255&Kt[e>>>24&255]^Yt[i/4-1],this.roundkey[i+1]=this.roundkey[i-3]^this.roundkey[i],this.roundkey[i+2]=this.roundkey[i-2]^this.roundkey[i+1],this.roundkey[i+3]=this.roundkey[i-1]^this.roundkey[i+2]}for(let i=0,s=40;i>>24&255]]^Xt[255&Kt[t>>>16&255]]^$t[255&Kt[t>>>8&255]]^Qt[255&Kt[t>>>0&255]]}}decrypt(){let e=this.inView.getUint32(0,!1)^this.roundkey[0],t=this.inView.getUint32(4,!1)^this.roundkey[1],i=this.inView.getUint32(8,!1)^this.roundkey[2],r=this.inView.getUint32(12,!1)^this.roundkey[3];const a=this.inView.getUint32(0,!1),s=this.inView.getUint32(4,!1),n=this.inView.getUint32(8,!1),o=this.inView.getUint32(12,!1);let c,l,u,d;for(let g=1;g<10;g++){const a=4*g;c=jt[e>>>24]^Xt[r>>>16&255]^$t[i>>>8&255]^Qt[255&t]^this.roundkey[a],l=jt[t>>>24]^Xt[e>>>16&255]^$t[r>>>8&255]^Qt[255&i]^this.roundkey[a+1],u=jt[i>>>24]^Xt[t>>>16&255]^$t[e>>>8&255]^Qt[255&r]^this.roundkey[a+2],d=jt[r>>>24]^Xt[i>>>16&255]^$t[t>>>8&255]^Qt[255&e]^this.roundkey[a+3],e=c,t=l,i=u,r=d}const h=4278190080&Gt[e>>>24&255]^16711680&Gt[r>>>16&255]^65280&Gt[i>>>8&255]^255&Gt[t>>>0&255]^this.roundkey[40],f=4278190080&Gt[t>>>24&255]^16711680&Gt[e>>>16&255]^65280&Gt[r>>>8&255]^255&Gt[i>>>0&255]^this.roundkey[41],m=4278190080&Gt[i>>>24&255]^16711680&Gt[t>>>16&255]^65280&Gt[e>>>8&255]^255&Gt[r>>>0&255]^this.roundkey[42],p=4278190080&Gt[r>>>24&255]^16711680&Gt[i>>>16&255]^65280&Gt[t>>>8&255]^255&Gt[e>>>0&255]^this.roundkey[43];this.outView.setUint32(0,h^this.iv[0],!1),this.outView.setUint32(4,f^this.iv[1],!1),this.outView.setUint32(8,m^this.iv[2],!1),this.outView.setUint32(12,p^this.iv[3],!1),this.iv[0]=a,this.iv[1]=s,this.iv[2]=n,this.iv[3]=o}}class ei extends Rt{constructor(e){super(e),this.moovSlice=null,this.currentTrack=null,this.tracks=[],this.metadataPromise=null,this.movieTimescale=-1,this.movieDurationInTimescale=-1,this.isQuickTime=!1,this.metadataTags={},this.currentMetadataKeys=null,this.isFragmented=!1,this.fragmentTrackDefaults=[],this.psshBoxes=[],this.currentFragment=null,this.lastReadFragment=null,this.decryptionKeyCache=new Map,this.reader=e._reader}async getTrackBackings(){return await this.readMetadata(),this.tracks.map(e=>e.trackBacking)}async getMimeType(){await this.readMetadata();const e=await this.getTrackBackings(),t=await Promise.all(e.map(e=>e.getDecoderConfig().then(e=>e?.codec??null)));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isQuickTime?"quicktime":"mp4");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({isQuickTime:this.isQuickTime,hasVideo:this.tracks.some(e=>"video"===e.info?.type),hasAudio:this.tracks.some(e=>"audio"===e.info?.type),codecStrings:t.filter(Boolean)})}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=0,t=!1;for(;;){let r=this.reader.requestSliceRange(e,8,16);if(r instanceof Promise&&(r=await r),!r)break;const a=e,s=Lt(r);if(!s)break;if("ftyp"===s.name||"styp"===s.name){const e=In(r,4);this.isQuickTime="qt "===e}else{if("moov"===s.name){let e=this.reader.requestSlice(r.filePos,s.contentSize);if(e instanceof Promise&&(e=await e),!e)break;this.moovSlice=e,this.readContiguousBoxes(this.moovSlice);for(const t of this.tracks){const e=t.editListPreviousSegmentDurations/this.movieTimescale;t.editListOffset-=Math.round(e*t.timescale)}t=this.isFragmented&&null!==this.reader.fileSize&&this.reader.fileSize>a+s.totalSize;break}if("moof"===s.name){if(!this.input._initInput)throw new Error('"moof" box encountered with no "moov" box present; this file is likely a Segment as described in ISO/IEC 14496-12 Section 8.16. A separate init file that contains a "moov" box is required to read this file, please provide it using InputOptions.initInput.');const e=await this.input._initInput._getDemuxer();if(e.constructor!==ei)throw new Error("Init input must match the input's format.");await e.readMetadata(),this.movieTimescale=e.movieTimescale,this.movieDurationInTimescale=e.movieDurationInTimescale,this.metadataTags=e.metadataTags,this.isFragmented=!0,this.fragmentTrackDefaults=e.fragmentTrackDefaults,this.psshBoxes=e.psshBoxes;for(const t of e.tracks){const e={id:t.id,demuxer:this,trackBacking:null,disposition:t.disposition,timescale:t.timescale,durationInMediaTimescale:t.durationInMediaTimescale,durationInMovieTimescale:t.durationInMovieTimescale,rotation:t.rotation,internalCodecId:t.internalCodecId,name:t.name,languageCode:t.languageCode,sampleTableByteOffset:null,sampleTable:null,fragmentLookupTable:[],currentFragmentState:null,fragmentPositionCache:[],editListPreviousSegmentDurations:t.editListPreviousSegmentDurations,editListOffset:t.editListOffset,encryptionInfo:t.encryptionInfo,encryptionAuxInfo:null,frmaCodecString:null,info:t.info};if(t.trackBacking)if(i(e.info),"video"===e.info.type&&-1!==e.info.width){const t=e;e.trackBacking=new ii(t),this.tracks.push(e)}else if("audio"===e.info.type&&-1!==e.info.numberOfChannels){const t=e;e.trackBacking=new ri(t),this.tracks.push(e)}}t=!1;break}}e=a+s.totalSize}if(t){i(null!==this.reader.fileSize);let e=this.reader.requestSlice(this.reader.fileSize-4,4);e instanceof Promise&&(e=await e),i(e);const t=gn(e),r=this.reader.fileSize-t;if(r>=0&&r<=this.reader.fileSize-16){let e=this.reader.requestSliceRange(r,8,16);if(e instanceof Promise&&(e=await e),e){const t=Lt(e);if(t&&"mfra"===t.name){let i=this.reader.requestSlice(e.filePos,t.contentSize);i instanceof Promise&&(i=await i),i&&this.readContiguousBoxes(i)}}}}})())}getSampleTableForTrack(e){if(e.sampleTable)return e.sampleTable;const t={sampleTimingEntries:[],sampleCompositionTimeOffsets:[],sampleSizes:[],keySampleIndices:null,chunkOffsets:[],sampleToChunk:[],presentationTimestamps:null,presentationTimestampIndexMap:null};if(e.sampleTable=t,null===e.sampleTableByteOffset)return t;i(this.moovSlice);const r=this.moovSlice.slice(e.sampleTableByteOffset);this.currentTrack=e,this.traverseBox(r),this.currentTrack=null;if("audio"===e.info?.type&&e.info.codec&&be.includes(e.info.codec)&&0===t.sampleCompositionTimeOffsets.length){i("audio"===e.info?.type);const r=Be(e.info.codec),s=[],n=[];for(let i=0;ie.startIndex),d=t.sampleTimingEntries[u],h=P(t.sampleTimingEntries,l,e=>e.startIndex),f=t.sampleTimingEntries[h],m=d.startDecodeTimestamp+(c-d.startIndex)*d.delta,p=f.startDecodeTimestamp+(l-f.startIndex)*f.delta-m,g=a(s);g&&g.delta===p?g.count++:s.push({startIndex:o.startChunkIndex+i,startDecodeTimestamp:m,count:1,delta:p});const k=o.samplesPerChunk*r.sampleSize*e.info.numberOfChannels;n.push(k)}o.startSampleIndex=o.startChunkIndex,o.samplesPerChunk=1}t.sampleTimingEntries=s,t.sampleSizes=n}if(t.sampleCompositionTimeOffsets.length>0){t.presentationTimestamps=[];for(const e of t.sampleTimingEntries)for(let i=0;ie.presentationTimestamp-t.presentationTimestamp),t.presentationTimestampIndexMap=Array(t.presentationTimestamps.length).fill(-1);for(let e=0;ee.moofOffset===s.moofOffset);if(r)ci(i,r.timestamp);else{const e=P(t,s.moofOffset-1,e=>e.moofOffset);if(-1!==e){const r=t[e];ci(i,r.endTimestamp)}}i.startTimestampIsFinal=!0}const r=P(t,i.startTimestamp,e=>e.startTimestamp);if(-1!==r&&t[r].moofOffset===s.moofOffset||t.splice(r+1,0,{moofOffset:s.moofOffset,startTimestamp:i.startTimestamp,endTimestamp:i.endTimestamp}),i.encryptionAuxInfo&&e.encryptionInfo){const t=await hi(this.reader,e.encryptionInfo,i.encryptionAuxInfo);for(let e=0;e0){t.languageCode="";for(let e=0;e<3;e++)t.languageCode=String.fromCharCode(96+(31&r))+t.languageCode,r>>=5;L(t.languageCode)||(t.languageCode=R)}}break;case"hdlr":{const t=this.currentTrack;if(!t)break;e.skip(8);const i=In(e,4);"vide"===i?t.info={type:"video",width:-1,height:-1,squarePixelWidth:-1,squarePixelHeight:-1,codec:null,codecDescription:null,colorSpace:null,avcType:null,avcCodecInfo:null,hevcCodecInfo:null,vp9CodecInfo:null,av1CodecInfo:null}:"soun"===i&&(t.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null,aacCodecInfo:null,pcmLittleEndian:!1,pcmSampleSize:null})}break;case"stbl":{const t=this.currentTrack;if(!t)break;t.sampleTableByteOffset=K,this.readContiguousBoxes(e.slice(X,j.contentSize))}break;case"stsd":{const t=this.currentTrack;if(!t)break;if(null===t.info||t.sampleTable)break;const i=un(e);e.skip(3);const r=gn(e);for(let a=0;a0&&(1===n?(e.skip(4),c=8*gn(e),e.skip(8)):2===n&&(e.skip(4),l=vn(e),o=gn(e),e.skip(4),c=gn(e),u=gn(e),e.skip(8))),t.info.numberOfChannels=o,t.info.sampleRate=l,t.frmaCodecString=null,this.readContiguousBoxes(e.slice(e.filePos,r+a.totalSize-e.filePos));const d="enca"===s?t.frmaCodecString:s;if(t.frmaCodecString=null,"mp4a"===d);else if("opus"===d)t.info.codec="opus",t.info.sampleRate=xe;else if("flac"===d)t.info.codec="flac";else if("ulaw"===d)t.info.codec="ulaw";else if("alaw"===d)t.info.codec="alaw";else if("ac-3"===d)t.info.codec="ac3";else if("ec-3"===d)t.info.codec="eac3";else if("twos"===d)8===c?t.info.codec="pcm-s8":16===c?t.info.codec=t.info.pcmLittleEndian?"pcm-s16":"pcm-s16be":(console.warn(`Unsupported sample size ${c} for codec 'twos'.`),t.info.codec=null);else if("sowt"===d)8===c?t.info.codec="pcm-s8":16===c?t.info.codec="pcm-s16":(console.warn(`Unsupported sample size ${c} for codec 'sowt'.`),t.info.codec=null);else if("raw "===d)t.info.codec="pcm-u8";else if("in24"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-s24":"pcm-s24be";else if("in32"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-s32":"pcm-s32be";else if("fl32"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-f32":"pcm-f32be";else if("fl64"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-f64":"pcm-f64be";else if("ipcm"===d){const e=t.info.pcmSampleSize;t.info.pcmLittleEndian?16===e?t.info.codec="pcm-s16":24===e?t.info.codec="pcm-s24":32===e?t.info.codec="pcm-s32":(console.warn(`Invalid ipcm sample size ${e}.`),t.info.codec=null):16===e?t.info.codec="pcm-s16be":24===e?t.info.codec="pcm-s24be":32===e?t.info.codec="pcm-s32be":(console.warn(`Invalid ipcm sample size ${e}.`),t.info.codec=null)}else if("fpcm"===d){const e=t.info.pcmSampleSize;t.info.pcmLittleEndian?32===e?t.info.codec="pcm-f32":64===e?t.info.codec="pcm-f64":(console.warn(`Invalid fpcm sample size ${e}.`),t.info.codec=null):32===e?t.info.codec="pcm-f32be":64===e?t.info.codec="pcm-f64be":(console.warn(`Invalid fpcm sample size ${e}.`),t.info.codec=null)}else if("lpcm"===d&&null!==u){const e=c+7>>3,i=Boolean(1&u),r=Boolean(2&u),a=4&u?-1:0;c>0&&c<=64&&(i?32===c&&(t.info.codec=r?"pcm-f32be":"pcm-f32"):a&1<0?(t.encryptionInfo.defaultCryptByteBlock=r>>4,t.encryptionInfo.defaultSkipByteBlock=15&r):(t.encryptionInfo.defaultCryptByteBlock=0,t.encryptionInfo.defaultSkipByteBlock=0),t.encryptionInfo.defaultIsProtected=0!==un(e),t.encryptionInfo.defaultPerSampleIvSize=un(e),t.encryptionInfo.defaultKid=w(ln(e,16)),t.encryptionInfo.defaultIsProtected&&0===t.encryptionInfo.defaultPerSampleIvSize){const i=un(e),r=new Uint8Array(16);r.set(ln(e,i),0),t.encryptionInfo.defaultConstantIv=r}}break;case"avcC":{const t=this.currentTrack;if(!t)break;i(t.info),t.info.codecDescription=ln(e,j.contentSize)}break;case"hvcC":{const t=this.currentTrack;if(!t)break;i(t.info),t.info.codecDescription=ln(e,j.contentSize)}break;case"vpcC":{const t=this.currentTrack;if(!t)break;i("video"===t.info?.type),e.skip(4);const r=un(e),a=un(e),s=un(e),n=s>>4,o=s>>1&7,c=1&s,l=un(e),u=un(e),d=un(e);t.info.vp9CodecInfo={profile:r,level:a,bitDepth:n,chromaSubsampling:o,videoFullRangeFlag:c,colourPrimaries:l,transferCharacteristics:u,matrixCoefficients:d}}break;case"av1C":{const t=this.currentTrack;if(!t)break;i("video"===t.info?.type),e.skip(1);const r=un(e),a=r>>5,s=31&r,n=un(e),o=n>>7,c=n>>6&1,l=n>>4&1,u=n>>3&1,d=n>>2&1,h=3&n,f=2===a&&c?n>>5&1?12:10:c?10:8;t.info.av1CodecInfo={profile:a,level:s,tier:o,bitDepth:f,monochrome:l,chromaSubsamplingX:u,chromaSubsamplingY:d,chromaSamplePosition:h}}break;case"colr":{const t=this.currentTrack;if(!t)break;i("video"===t.info?.type);if("nclx"!==In(e,4))break;const r=hn(e),a=hn(e),s=hn(e),n=Boolean(128&un(e));t.info.colorSpace={primaries:h[r],transfer:m[a],matrix:g[s],fullRange:n}}break;case"pasp":{const t=this.currentTrack;if(!t)break;i("video"===t.info?.type);const r=gn(e),a=gn(e);r>0&&a>0&&(r>a?t.info.squarePixelWidth=Math.round(t.info.width*r/a):t.info.squarePixelHeight=Math.round(t.info.height*a/r))}break;case"esds":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),e.skip(4);i(3===un(e)),qt(e),e.skip(2);const r=un(e),a=0!==(64&r),s=0!==(32&r);if(0!==(128&r)&&e.skip(2),a){const t=un(e);e.skip(t)}s&&e.skip(2);i(4===un(e));const n=qt(e),o=e.filePos,c=un(e);if(64===c||103===c?(t.info.codec="aac",t.info.aacCodecInfo={isMpeg2:103===c,objectType:null}):105===c||107===c?t.info.codec="mp3":221===c?t.info.codec="vorbis":console.warn(`Unsupported audio codec (objectTypeIndication ${c}) - discarding track.`),e.skip(12),n>e.filePos-o){i(5===un(e));const r=qt(e);if(t.info.codecDescription=ln(e,r),"aac"===t.info.codec){const e=ge(t.info.codecDescription);null!==e.numberOfChannels&&(t.info.numberOfChannels=e.numberOfChannels),null!==e.sampleRate&&(t.info.sampleRate=e.sampleRate)}}}break;case"enda":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),t.info.pcmLittleEndian=!!(255&hn(e))}break;case"pcmC":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),e.skip(4);const r=un(e);t.info.pcmLittleEndian=Boolean(1&r),t.info.pcmSampleSize=un(e)}break;case"dOps":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),e.skip(1);const r=un(e),a=hn(e),s=gn(e),n=mn(e),o=un(e);let c;c=0!==o?ln(e,2+r):new Uint8Array(0);const l=new Uint8Array(19+c.byteLength),u=new DataView(l.buffer);u.setUint32(0,1332770163,!1),u.setUint32(4,1214603620,!1),u.setUint8(8,1),u.setUint8(9,r),u.setUint16(10,a,!0),u.setUint32(12,s,!0),u.setInt16(16,n,!0),u.setUint8(18,o),l.set(c,19),t.info.codecDescription=l,t.info.numberOfChannels=r}break;case"dfLa":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type),e.skip(4);const r=127,a=128,s=e.filePos;for(;e.filePos<$;){const i=un(e),s=fn(e);if((i&r)===Pt.STREAMINFO){e.skip(10);const i=gn(e),r=i>>>12,a=1+(i>>9&7);t.info.sampleRate=r,t.info.numberOfChannels=a,e.skip(20)}else e.skip(s);if(i&a)break}const n=e.filePos;e.filePos=s;const o=ln(e,n-s),c=new Uint8Array(4+o.byteLength);new DataView(c.buffer).setUint32(0,1716281667,!1),c.set(o,4),t.info.codecDescription=c}break;case"dac3":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type);const r=ln(e,3),a=new fe(r),s=a.readBits(2);a.skipBits(8);const n=a.readBits(3),o=a.readBits(1);s<3&&(t.info.sampleRate=ze[s]),t.info.numberOfChannels=xt[n]+o}break;case"dec3":{const t=this.currentTrack;if(!t)break;i("audio"===t.info?.type);const r=(e=>{if(e.length<2)return null;const t=new fe(e),i=t.readBits(13),r=t.readBits(3),a=[];for(let s=0;s<=r&&!(Math.ceil(t.pos/8)+3>e.length);s++){const e=t.readBits(2),i=t.readBits(5);t.skipBits(1),t.skipBits(1);const r=t.readBits(3),s=t.readBits(3),n=t.readBits(1);t.skipBits(3);const o=t.readBits(4);let c=0;o>0?c=t.readBits(9):t.skipBits(1),a.push({fscod:e,fscod2:null,bsid:i,bsmod:r,acmod:s,lfeon:n,numDepSub:o,chanLoc:c})}return 0===a.length?null:{dataRate:i,substreams:a}})(ln(e,j.contentSize));if(!r){console.warn("Invalid dec3 box contents, ignoring.");break}const a=At(r);null!==a&&(t.info.sampleRate=a),t.info.numberOfChannels=Ft(r)}break;case"stts":{const t=this.currentTrack;if(!t)break;if(!t.sampleTable)break;e.skip(4);const i=gn(e);let r=0,a=0;for(let s=0;se.id===i);if(!r)break;const a=gn(e),s=(12&a)>>2,n=3&a,o=[un,hn,fn,gn],c=o[(48&a)>>4],l=o[s],u=o[n],d=gn(e);for(let h=0;he.timestamp-t.timestamp);for(let e=0;e({presentationTimestamp:e.presentationTimestamp,sampleIndex:t})).sort((e,t)=>e.presentationTimestamp-t.presentationTimestamp);for(let i=0;ie.id===u);if(!d)break;const h=this.fragmentTrackDefaults.find(e=>e.trackId===u);this.currentTrack=d,d.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:h?.defaultSampleDescriptionIndex??null,defaultSampleDuration:h?.defaultSampleDuration??null,defaultSampleSize:h?.defaultSampleSize??null,defaultSampleFlags:h?.defaultSampleFlags??null,startTimestamp:null,encryptionAuxInfo:null},r?d.currentFragmentState.baseDataOffset=wn(e):l&&(d.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),a&&(d.currentFragmentState.sampleDescriptionIndex=gn(e)),s&&(d.currentFragmentState.defaultSampleDuration=gn(e)),n&&(d.currentFragmentState.defaultSampleSize=gn(e)),o&&(d.currentFragmentState.defaultSampleFlags=gn(e)),c&&(d.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{const t=this.currentTrack;if(!t)break;i(t.currentFragmentState);const r=un(e);e.skip(3);const a=0===r?gn(e):wn(e);t.currentFragmentState.startTimestamp=a}break;case"trun":{const t=this.currentTrack;if(!t)break;i(this.currentFragment),i(t.currentFragmentState);const r=un(e),a=fn(e),s=Boolean(1&a),n=Boolean(4&a),o=Boolean(256&a),c=Boolean(512&a),l=Boolean(1024&a),u=Boolean(2048&a),d=gn(e);let h=null;s&&(h=bn(e));let f,m=null;if(n&&(m=gn(e)),this.currentFragment.trackData.has(t.id)?(f=this.currentFragment.trackData.get(t.id),null!==h&&(f.currentOffset=t.currentFragmentState.baseDataOffset+h)):(f={track:t,currentTimestamp:0,currentOffset:t.currentFragmentState.baseDataOffset+(h??0),startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1,encryptionAuxInfo:null},this.currentFragment.trackData.set(t.id,f)),0===d){this.currentFragment.implicitBaseDataOffset=f.currentOffset;break}for(let p=0;p0&&(a=ln(e,r));const s=di(t);s.defaultSampleInfoSize=i,s.sampleSizes=a,s.sampleCount=r}break;case"saio":{const t=this.currentTrack;if(!t||!t.encryptionInfo)break;const i=un(e);if(1&fn(e)){const i=In(e,4),r=gn(e);if(i!==t.encryptionInfo.scheme||0!==r)break}const r=gn(e);if(0===r)break;r>1&&console.warn("Multiple saio entries are not supported; using the first offset only.");let a=0===i?gn(e):Number(wn(e));this.currentFragment&&(a+=this.currentFragment.moofOffset);di(t).offset=a}break;case"senc":{const t=this.currentTrack;if(!t||!t.encryptionInfo)break;i(this.currentFragment);const r=this.currentFragment.trackData.get(t.id);if(!r)break;e.skip(1);const a=fn(e),s=Boolean(2&a),n=gn(e),o=t.encryptionInfo.defaultPerSampleIvSize;i(null!==o);for(let i=0;i0?a.set(ln(e,o),0):a.set(t.encryptionInfo.defaultConstantIv,0);let n=null;if(s){const t=hn(e);n=[];for(let i=0;i0&&((z=this.metadataTags).trackNumber??(z.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&((U=this.metadataTags).tracksTotal??(U.tracksTotal=i))}break;case"trkn":if(a instanceof Uint8Array&&a.length>=6){const e=c(a),t=e.getUint16(2,!1),i=e.getUint16(4,!1);t>0&&((q=this.metadataTags).trackNumber??(q.trackNumber=t)),i>0&&((W=this.metadataTags).tracksTotal??(W.tracksTotal=i))}break;case"disc":case"disk":if(a instanceof Uint8Array&&a.length>=6){const e=c(a),t=e.getUint16(2,!1),i=e.getUint16(4,!1);t>0&&((V=this.metadataTags).discNumber??(V.discNumber=t)),i>0&&((H=this.metadataTags).discsTotal??(H.discsTotal=i))}}}}}var Q,G;return e.filePos=$,!0}}class ti{constructor(e){this.internalTrack=e,this.packetToSampleIndex=new WeakMap,this.packetToFragmentLocation=new WeakMap}getId(){return this.internalTrack.id}getNumber(){const e=this.internalTrack.demuxer,t=this.internalTrack.trackBacking.getType();let i=0;for(const r of e.tracks)if(r.trackBacking.getType()===t&&i++,r===this.internalTrack)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.internalCodecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.timescale}isRelativeToUnixEpoch(){return!1}getDisposition(){return this.internalTrack.disposition}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){const e=this.internalTrack;if(e.durationInMediaTimescale<=0)return null;i(e.trackBacking);const t=await e.trackBacking.getFirstPacket({metadataOnly:!0});return(t?.timestamp??0)+e.durationInMediaTimescale/e.timescale}async getLiveRefreshInterval(){return null}async getFirstPacket(e){const t=await this.fetchPacketForSampleIndex(0,e);return t||!this.internalTrack.demuxer.isFragmented?t:this.performFragmentedLookup(null,e=>e.trackData.get(this.internalTrack.id)?{sampleIndex:0,correctSampleFound:!0}:{sampleIndex:-1,correctSampleFound:!1},-1/0,1/0,e)}mapTimestampIntoTimescale(e){return D(e*this.internalTrack.timescale)+this.internalTrack.editListOffset}async getPacket(e,t){const i=this.mapTimestampIntoTimescale(e),r=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),a=ai(r,i),s=await this.fetchPacketForSampleIndex(a,t);return ui(r)&&this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const r=P(t.presentationTimestamps,i,e=>e.presentationTimestamp);return{sampleIndex:-1!==r?t.presentationTimestamps[r].sampleIndex:-1,correctSampleFound:-1!==r&&i{if(e===r.fragment){const t=e.trackData.get(this.internalTrack.id);if(r.sampleIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const r=C(t.presentationTimestamps,e=>t.samples[e.sampleIndex].isKeyFrame&&e.presentationTimestamp<=i);return{sampleIndex:-1!==r?t.presentationTimestamps[r].sampleIndex:-1,correctSampleFound:-1!==r&&i{if(e===a.fragment){const t=e.trackData.get(this.internalTrack.id).samples.findIndex((e,t)=>e.isKeyFrame&&t>a.sampleIndex);if(-1!==t)return{sampleIndex:t,correctSampleFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.samples.findIndex(e=>e.isKeyFrame);return i(-1!==e),{sampleIndex:e,correctSampleFound:!0}}}return{sampleIndex:-1,correctSampleFound:!1}},-1/0,1/0,t)}async fetchPacketForSampleIndex(e,t){if(-1===e)return null;const r=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),a=ni(r,e);if(!a)return null;let s;if(t.metadataOnly)s=Dt;else{let t=this.internalTrack.demuxer.reader.requestSlice(a.sampleOffset,a.sampleSize);if(t instanceof Promise&&(t=await t),!t)return null;if(s=ln(t,a.sampleSize),this.internalTrack.encryptionAuxInfo){i(this.internalTrack.encryptionInfo);const t=await hi(this.internalTrack.demuxer.reader,this.internalTrack.encryptionInfo,this.internalTrack.encryptionAuxInfo);ee.timestamp),d=-1!==u?this.internalTrack.fragmentLookupTable[u]:null,h=P(this.internalTrack.fragmentPositionCache,r,e=>e.startTimestamp),f=-1!==h?this.internalTrack.fragmentPositionCache[h]:null,m=Math.max(d?.moofOffset??0,f?.moofOffset??0)||null;let p;for(e?null===m||e.moofOffset>=m?(p=e.moofOffset+e.moofSize,o=e):p=m:p=m??0;;){if(o){const e=o.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>a)break}let e=n.reader.requestSliceRange(p,8,16);if(e instanceof Promise&&(e=await e),!e)break;const i=p,r=Lt(e);if(!r)break;if("moof"===r.name){o=await n.readFragment(i);const{sampleIndex:e,correctSampleFound:r}=t(o);if(r)return this.fetchPacketInFragment(o,e,s);-1!==e&&(c=o,l=e)}p=i+r.totalSize}if(d&&(!c||c.moofOffset{if("vp9"!==this.internalTrack.info.codec||this.internalTrack.info.vp9CodecInfo){if("av1"===this.internalTrack.info.codec&&!this.internalTrack.info.av1CodecInfo){const e=await this.getFirstPacket({});this.internalTrack.info.av1CodecInfo=e&&yt(e.data)}}else{const e=await this.getFirstPacket({});this.internalTrack.info.vp9CodecInfo=e&&kt(e.data)}const e={codec:ve(this.internalTrack.info),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0};return this.internalTrack.info.width===this.internalTrack.info.squarePixelWidth&&this.internalTrack.info.height===this.internalTrack.info.squarePixelHeight||(e.displayAspectWidth=this.internalTrack.info.squarePixelWidth,e.displayAspectHeight=this.internalTrack.info.squarePixelHeight),e})()):null}}class ri extends ti{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getType(){return"audio"}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return this.internalTrack.info.codec?this.decoderConfig??(this.decoderConfig={codec:Ie(this.internalTrack.info),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}):null}}const ai=(e,t)=>{if(e.presentationTimestamps){const i=P(e.presentationTimestamps,t,e=>e.presentationTimestamp);return-1===i?-1:e.presentationTimestamps[i].sampleIndex}{const i=P(e.sampleTimingEntries,t,e=>e.startDecodeTimestamp);if(-1===i)return-1;const r=e.sampleTimingEntries[i];return r.startIndex+Math.min(Math.floor((t-r.startDecodeTimestamp)/r.delta),r.count-1)}},si=(e,t)=>{if(!e.keySampleIndices)return ai(e,t);if(e.presentationTimestamps){const i=P(e.presentationTimestamps,t,e=>e.presentationTimestamp);if(-1===i)return-1;for(let t=i;t>=0;t--){const i=e.presentationTimestamps[t].sampleIndex;if(-1!==S(e.keySampleIndices,i,e=>e))return i}return-1}{const i=ai(e,t),r=P(e.keySampleIndices,i,e=>e);return e.keySampleIndices[r]??-1}},ni=(e,t)=>{const r=P(e.sampleTimingEntries,t,e=>e.startIndex),a=e.sampleTimingEntries[r];if(!a||a.startIndex+a.count<=t)return null;let s=a.startDecodeTimestamp+(t-a.startIndex)*a.delta;const n=P(e.sampleCompositionTimeOffsets,t,e=>e.startIndex),o=e.sampleCompositionTimeOffsets[n];o&&t-o.startIndexe.startSampleIndex),u=e.sampleToChunk[l];i(u);const d=u.startChunkIndex+Math.floor((t-u.startSampleIndex)/u.samplesPerChunk),h=e.chunkOffsets[d],f=u.startSampleIndex+(d-u.startChunkIndex)*u.samplesPerChunk;let m=0,p=h;if(1===e.sampleSizes.length)p+=c*(t-f),m+=c*u.samplesPerChunk;else for(let i=f;ie)}},oi=(e,t)=>{if(!e.keySampleIndices)return t+1;const i=P(e.keySampleIndices,t,e=>e);return e.keySampleIndices[i+1]??-1},ci=(e,t)=>{e.startTimestamp+=t,e.endTimestamp+=t;for(const i of e.samples)i.presentationTimestamp+=t;for(const i of e.presentationTimestamps)i.presentationTimestamp+=t},li=e=>{const[t,i]=e,r=Math.atan2(i,t);return Number.isFinite(r)?r*(180/Math.PI):0},ui=e=>0===e.sampleSizes.length,di=e=>{var t;return e.currentFragmentState?(t=e.currentFragmentState).encryptionAuxInfo??(t.encryptionAuxInfo={defaultSampleInfoSize:0,sampleSizes:null,sampleCount:0,offset:null,resolved:null}):e.encryptionAuxInfo??(e.encryptionAuxInfo={defaultSampleInfoSize:0,sampleSizes:null,sampleCount:0,offset:null,resolved:null})},hi=async(e,t,r)=>{if(r.resolved)return r.resolved;if(null===r.offset||0===r.sampleCount)throw new Error("Incomplete saiz/saio info; cannot resolve encryption data.");let a=0;if(r.defaultSampleInfoSize>0)a=r.defaultSampleInfoSize*r.sampleCount;else{i(r.sampleSizes);for(let e=0;e0?r.defaultSampleInfoSize:r.sampleSizes[i],a=new Uint8Array(16);n>0?a.set(ln(s,n),0):a.set(t.defaultConstantIv,0);let c=null;if(e>n){const e=hn(s);c=[];for(let t=0;t{i(e.encryptionInfo);const s=e.encryptionInfo;i(null!==s.defaultKid);const n=s.defaultKid;let o;const c=e.demuxer.decryptionKeyCache.get(n);if(c)o=await c;else{if(!e.demuxer.input._formatOptions.isobmff?.resolveKeyId)throw new Error("Encrypted media samples encountered. To decrypt them, please provide a callback for InputOptions.formatOptions.isobmff.resolveKeyId.");const t=(async()=>{let t=e.demuxer.psshBoxes;if(a){t=[...t,...a.psshBoxes].filter(e=>null===e.keyIds||e.keyIds.includes(n));for(let e=0;e{i(e.length%2===0);const t=new Uint8Array(e.length/2);for(let i=0;i{const s=new Uint8Array(16);s.set(r.iv,0);const n=await crypto.subtle.importKey("raw",e,{name:"AES-CTR"},!1,["decrypt"]),o=async e=>{const t=await crypto.subtle.decrypt({name:"AES-CTR",counter:s,length:64},n,e);return new Uint8Array(t)};if(!r.subsamples)return o(a);i(null!==t.defaultCryptByteBlock&&null!==t.defaultSkipByteBlock);const c=gi(r.subsamples,t.defaultCryptByteBlock,t.defaultSkipByteBlock);let l=0;for(const i of c)for(const e of i.perSubsample)l+=e.length;const u=new Uint8Array(l);let d=0;for(const i of c)for(const e of i.perSubsample)u.set(a.subarray(e.offset,e.offset+e.length),d),d+=e.length;const h=await o(u),f=new Uint8Array(a);let m=0;for(const i of c)for(const e of i.perSubsample)f.set(h.subarray(m,m+e.length),e.offset),m+=e.length;return f},pi=(e,t,r,a)=>{const s=new Zt;s.init({key:e,iv:r.iv});const n=t.defaultCryptByteBlock,o=t.defaultSkipByteBlock;if(i(null!==n&&null!==o),!r.subsamples){const e=new Uint8Array(a),t=Math.floor(a.length/16);for(let i=0;i{const r=[],a=0!==t||0!==i;let s=0;for(const n of e){s+=n.clearLen;const e=[];if(a){let r=n.protectedLen,a=s;for(;r>0&&!(r<16*t);){const s=16*t;e.push({offset:a,length:s}),a+=s,r-=s;const n=Math.min(16*i,r);a+=n,r-=n}s+=n.protectedLen}else n.protectedLen>0&&e.push({offset:s,length:n.protectedLen}),s+=n.protectedLen;r.push({perSubsample:e})}return r};var ki,bi;(bi=ki||(ki={}))[bi.EBML=440786851]="EBML",bi[bi.EBMLVersion=17030]="EBMLVersion",bi[bi.EBMLReadVersion=17143]="EBMLReadVersion",bi[bi.EBMLMaxIDLength=17138]="EBMLMaxIDLength",bi[bi.EBMLMaxSizeLength=17139]="EBMLMaxSizeLength",bi[bi.DocType=17026]="DocType",bi[bi.DocTypeVersion=17031]="DocTypeVersion",bi[bi.DocTypeReadVersion=17029]="DocTypeReadVersion",bi[bi.Void=236]="Void",bi[bi.Segment=408125543]="Segment",bi[bi.SeekHead=290298740]="SeekHead",bi[bi.Seek=19899]="Seek",bi[bi.SeekID=21419]="SeekID",bi[bi.SeekPosition=21420]="SeekPosition",bi[bi.Duration=17545]="Duration",bi[bi.Info=357149030]="Info",bi[bi.TimestampScale=2807729]="TimestampScale",bi[bi.MuxingApp=19840]="MuxingApp",bi[bi.WritingApp=22337]="WritingApp",bi[bi.Tracks=374648427]="Tracks",bi[bi.TrackEntry=174]="TrackEntry",bi[bi.TrackNumber=215]="TrackNumber",bi[bi.TrackUID=29637]="TrackUID",bi[bi.TrackType=131]="TrackType",bi[bi.FlagEnabled=185]="FlagEnabled",bi[bi.FlagDefault=136]="FlagDefault",bi[bi.FlagForced=21930]="FlagForced",bi[bi.FlagOriginal=21934]="FlagOriginal",bi[bi.FlagHearingImpaired=21931]="FlagHearingImpaired",bi[bi.FlagVisualImpaired=21932]="FlagVisualImpaired",bi[bi.FlagCommentary=21935]="FlagCommentary",bi[bi.FlagLacing=156]="FlagLacing",bi[bi.Name=21358]="Name",bi[bi.Language=2274716]="Language",bi[bi.LanguageBCP47=2274717]="LanguageBCP47",bi[bi.CodecID=134]="CodecID",bi[bi.CodecPrivate=25506]="CodecPrivate",bi[bi.CodecDelay=22186]="CodecDelay",bi[bi.SeekPreRoll=22203]="SeekPreRoll",bi[bi.DefaultDuration=2352003]="DefaultDuration",bi[bi.Video=224]="Video",bi[bi.PixelWidth=176]="PixelWidth",bi[bi.PixelHeight=186]="PixelHeight",bi[bi.DisplayWidth=21680]="DisplayWidth",bi[bi.DisplayHeight=21690]="DisplayHeight",bi[bi.DisplayUnit=21682]="DisplayUnit",bi[bi.AlphaMode=21440]="AlphaMode",bi[bi.Audio=225]="Audio",bi[bi.SamplingFrequency=181]="SamplingFrequency",bi[bi.Channels=159]="Channels",bi[bi.BitDepth=25188]="BitDepth",bi[bi.SimpleBlock=163]="SimpleBlock",bi[bi.BlockGroup=160]="BlockGroup",bi[bi.Block=161]="Block",bi[bi.BlockAdditions=30113]="BlockAdditions",bi[bi.BlockMore=166]="BlockMore",bi[bi.BlockAdditional=165]="BlockAdditional",bi[bi.BlockAddID=238]="BlockAddID",bi[bi.BlockDuration=155]="BlockDuration",bi[bi.ReferenceBlock=251]="ReferenceBlock",bi[bi.Cluster=524531317]="Cluster",bi[bi.Timestamp=231]="Timestamp",bi[bi.Cues=475249515]="Cues",bi[bi.CuePoint=187]="CuePoint",bi[bi.CueTime=179]="CueTime",bi[bi.CueTrackPositions=183]="CueTrackPositions",bi[bi.CueTrack=247]="CueTrack",bi[bi.CueClusterPosition=241]="CueClusterPosition",bi[bi.Colour=21936]="Colour",bi[bi.MatrixCoefficients=21937]="MatrixCoefficients",bi[bi.TransferCharacteristics=21946]="TransferCharacteristics",bi[bi.Primaries=21947]="Primaries",bi[bi.Range=21945]="Range",bi[bi.Projection=30320]="Projection",bi[bi.ProjectionType=30321]="ProjectionType",bi[bi.ProjectionPoseRoll=30325]="ProjectionPoseRoll",bi[bi.Attachments=423732329]="Attachments",bi[bi.AttachedFile=24999]="AttachedFile",bi[bi.FileDescription=18046]="FileDescription",bi[bi.FileName=18030]="FileName",bi[bi.FileMediaType=18016]="FileMediaType",bi[bi.FileData=18012]="FileData",bi[bi.FileUID=18094]="FileUID",bi[bi.Chapters=272869232]="Chapters",bi[bi.Tags=307544935]="Tags",bi[bi.Tag=29555]="Tag",bi[bi.Targets=25536]="Targets",bi[bi.TargetTypeValue=26826]="TargetTypeValue",bi[bi.TargetType=25546]="TargetType",bi[bi.TagTrackUID=25541]="TagTrackUID",bi[bi.TagEditionUID=25545]="TagEditionUID",bi[bi.TagChapterUID=25540]="TagChapterUID",bi[bi.TagAttachmentUID=25542]="TagAttachmentUID",bi[bi.SimpleTag=26568]="SimpleTag",bi[bi.TagName=17827]="TagName",bi[bi.TagLanguage=17530]="TagLanguage",bi[bi.TagString=17543]="TagString",bi[bi.TagBinary=17541]="TagBinary",bi[bi.ContentEncodings=28032]="ContentEncodings",bi[bi.ContentEncoding=25152]="ContentEncoding",bi[bi.ContentEncodingOrder=20529]="ContentEncodingOrder",bi[bi.ContentEncodingScope=20530]="ContentEncodingScope",bi[bi.ContentCompression=20532]="ContentCompression",bi[bi.ContentCompAlgo=16980]="ContentCompAlgo",bi[bi.ContentCompSettings=16981]="ContentCompSettings",bi[bi.ContentEncryption=20533]="ContentEncryption";const yi=[ki.EBML,ki.Segment],wi=[ki.SeekHead,ki.Info,ki.Cluster,ki.Tracks,ki.Cues,ki.Attachments,ki.Chapters,ki.Tags],Ti=[...yi,...wi],Si=16,Pi=e=>{if(e.remainingLength<1)return null;const t=un(e);if(e.skip(-1),0===t)return null;let i=1,r=128;for(;0===(t&r);)i++,r>>=1;return e.remainingLength{if(e.remainingLength<1)return null;const t=un(e);if(0===t)return null;let i=1,r=128;for(;0===(t&r);)i++,r>>=1;if(e.remainingLength{if(t<1||t>8)throw new Error("Bad unsigned int size "+t);let i=0;for(let r=0;r{const t=Pi(e);if(null===t)return null;if(e.remainingLength{if(e.remainingLength<1)return null;if(255===un(e))return;e.skip(-1);const t=vi(e);return null===t?null:72057594037927940!==t?t:void 0},Bi=e=>{i(e.remainingLength>=2);const t=xi(e);if(null===t)return null;const r=Ci(e);return null===r?null:{id:t,size:r}},Ei=(e,t)=>{const i=ln(e,t);let r=0;for(;r{const i=ln(e,t);let r=0;for(;r{if(0===t)return 0;if(4!==t&&8!==t)throw new Error("Bad float size "+t);return 4===t?Pn(e):vn(e)},Fi=async(e,t,i,r)=>{const a=new Set(i);let s=t;for(;null===r||ss?r:s,found:!1}},Ri=async(e,t,i,r)=>{const a=new Set(i);let s=t;for(;se.tracks.map(e=>e.trackBacking))}async getMimeType(){await this.readMetadata();const e=await this.getTrackBackings(),t=await Promise.all(e.map(e=>e.getDecoderConfig().then(e=>e?.codec??null)));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isWebM?"webm":"x-matroska");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings.filter(Boolean))].join(", ")}"`);return t})({isWebM:this.isWebM,hasVideo:this.segments.some(e=>e.tracks.some(e=>"video"===e.info?.type)),hasAudio:this.segments.some(e=>e.tracks.some(e=>"audio"===e.info?.type)),codecStrings:t.filter(Boolean)})}async getMetadataTags(){await this.readMetadata();for(const t of this.segments)t.metadataTagsCollected||(null!==this.reader.fileSize&&await this.loadSegmentMetadata(t),t.metadataTagsCollected=!0);let e={};for(const t of this.segments)e={...e,...t.metadataTags};return e}readMetadata(){return this.readMetadataPromise??(this.readMetadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,2,Si);if(t instanceof Promise&&(t=await t),!t)break;const i=Bi(t);if(!i)break;const r=i.id;let s=i.size;const n=t.filePos;if(r===ki.EBML){ji(s);let e=this.reader.requestSlice(n,s);if(e instanceof Promise&&(e=await e),!e)break;this.readContiguousElements(e)}else if(r===ki.Segment){if(await this.readSegment(n,s),void 0===s)break;if(null===this.reader.fileSize)break}else if(r===ki.Cluster){if(null===this.reader.fileSize)break;if(void 0===s){s=(await Fi(this.reader,n,Ti,this.reader.fileSize)).pos-n}const e=a(this.segments);e&&(e.elementEndPos=n+s)}ji(s),e=n+s}})())}async readSegment(e,t){this.currentSegment={seekHeadSeen:!1,infoSeen:!1,tracksSeen:!1,cuesSeen:!1,tagsSeen:!1,attachmentsSeen:!1,timestampScale:-1,timestampFactor:-1,duration:-1,seekEntries:[],tracks:[],cuePoints:[],dataStartPos:e,elementEndPos:void 0===t?null:e+t,clusterSeekStartPos:e,lastReadCluster:null,metadataTags:{},metadataTagsCollected:!1},this.segments.push(this.currentSegment);let i=e;for(;null===this.currentSegment.elementEndPos||ie.id===a);if(-1!==o){const e=Zi[o].flag;this.currentSegment[e]=!0,ji(s);let t=this.reader.requestSlice(n,s);t instanceof Promise&&(t=await t),t&&this.readContiguousElements(t)}else if(a===ki.Tags||a===ki.Attachments){a===ki.Tags?this.currentSegment.tagsSeen=!0:this.currentSegment.attachmentsSeen=!0,ji(s);let e=this.reader.requestSlice(n,s);e instanceof Promise&&(e=await e),e&&this.readContiguousElements(e)}else if(a===ki.Cluster){this.currentSegment.clusterSeekStartPos=t;break}if(void 0===s)break;i=n+s}if(this.currentSegment.seekEntries.sort((e,t)=>e.segmentPosition-t.segmentPosition),null!==this.reader.fileSize)for(const n of this.currentSegment.seekEntries){const t=Zi.find(e=>e.id===n.id);if(!t)continue;if(this.currentSegment[t.flag])continue;let i=this.reader.requestSliceRange(e+n.segmentPosition,2,Si);if(i instanceof Promise&&(i=await i),!i)continue;const r=Bi(i);if(!r)continue;const{id:a,size:s}=r;if(a!==t.id)continue;ji(s),this.currentSegment[t.flag]=!0;let o=this.reader.requestSlice(i.filePos,s);o instanceof Promise&&(o=await o),o&&this.readContiguousElements(o)}-1===this.currentSegment.timestampScale&&(this.currentSegment.timestampScale=1e6,this.currentSegment.timestampFactor=1e3);for(const n of this.currentSegment.tracks)null!==n.defaultDurationNs&&(n.defaultDuration=this.currentSegment.timestampFactor*n.defaultDurationNs/1e9);const r=new Map(this.currentSegment.tracks.map(e=>[e.id,e]));for(const n of this.currentSegment.cuePoints){const e=r.get(n.trackId);e&&e.cuePoints.push(n)}for(const n of this.currentSegment.tracks){n.cuePoints.sort((e,t)=>e.time-t.time);for(let e=0;es&&(s=n.cuePoints.length,a=n);for(const n of this.currentSegment.tracks)0===n.cuePoints.length&&(n.cuePoints=a.cuePoints);this.currentSegment=null}async readCluster(e,t){if(t.lastReadCluster?.elementStartPos===e)return t.lastReadCluster;let r=this.reader.requestSliceRange(e,2,Si);r instanceof Promise&&(r=await r),i(r);const s=e,n=Bi(r);i(n);i(n.id===ki.Cluster);let o=n.size;const c=r.filePos;if(void 0===o){o=(await Fi(this.reader,c,Ti,t.elementEndPos)).pos-c}let l=this.reader.requestSlice(c,o);l instanceof Promise&&(l=await l);const u={segment:t,elementStartPos:s,elementEndPos:c+o,dataStartPos:c,timestamp:-1,trackData:new Map};if(this.currentCluster=u,l){const e=this.readContiguousElements(l,Ti);u.elementEndPos=e}for(const[,d]of u.trackData){const e=d.track;i(d.blocks.length>0);let t=!1;for(let i=0;i({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp);for(let i=0;i({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp));const r=d.blocks[d.presentationTimestamps[0].blockIndex],n=d.blocks[a(d.presentationTimestamps).blockIndex];d.startTimestamp=r.timestamp,d.endTimestamp=n.timestamp+n.duration;const o=P(e.clusterPositionCache,d.startTimestamp,e=>e.startTimestamp);-1!==o&&e.clusterPositionCache[o].elementStartPos===s||e.clusterPositionCache.splice(o+1,0,{elementStartPos:u.elementStartPos,startTimestamp:d.startTimestamp})}return t.lastReadCluster=u,u}getTrackDataInCluster(e,t){let i=e.trackData.get(t);if(!i){const r=e.segment.tracks.find(e=>e.id===t);if(!r)return null;i={track:r,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,blocks:[],presentationTimestamps:[]},e.trackData.set(t,i)}return i}expandLacedBlocks(e,t){for(let r=0;r=2;){const i=e.filePos;if(!this.traverseElement(e,t))return i}return e.filePos}traverseElement(e,t){const a=Bi(e);if(!a)return!1;if(t&&t.includes(a.id))return!1;const{id:s,size:n}=a,o=e.filePos;switch(ji(n),s){case ki.DocType:this.isWebM="webm"===Ei(e,n);break;case ki.Seek:{if(!this.currentSegment)break;const t={id:-1,segmentPosition:-1};this.currentSegment.seekEntries.push(t),this.readContiguousElements(e.slice(o,n)),-1!==t.id&&-1!==t.segmentPosition||this.currentSegment.seekEntries.pop()}break;case ki.SeekID:{const t=this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.id=Ii(e,n)}break;case ki.SeekPosition:{const t=this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.segmentPosition=Ii(e,n)}break;case ki.TimestampScale:if(!this.currentSegment)break;this.currentSegment.timestampScale=Ii(e,n),this.currentSegment.timestampFactor=1e9/this.currentSegment.timestampScale;break;case ki.Duration:if(!this.currentSegment)break;this.currentSegment.duration=Ai(e,n);break;case ki.TrackEntry:if(!this.currentSegment)break;if(this.currentTrack={id:-1,segment:this.currentSegment,demuxer:this,clusterPositionCache:[],cuePoints:[],disposition:{...he,primary:!1},trackBacking:null,codecId:null,codecPrivate:null,defaultDuration:null,defaultDurationNs:null,name:null,languageCode:"eng",hasLanguageBcp47:!1,decodingInstructions:[],info:null},this.readContiguousElements(e.slice(o,n)),!this.currentTrack)break;if(this.currentTrack.decodingInstructions.some(e=>"decompress"!==e.data?.type||e.scope!==Qi.Block||e.data.algorithm!==Yi.HeaderStripping)&&(console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`),this.currentTrack=null),this.currentTrack&&-1!==this.currentTrack.id&&this.currentTrack.codecId&&this.currentTrack.info){const e=this.currentTrack.codecId.indexOf("/"),t=-1===e?this.currentTrack.codecId:this.currentTrack.codecId.slice(0,e);if("video"===this.currentTrack.info.type&&-1!==this.currentTrack.info.width&&-1!==this.currentTrack.info.height){if(this.currentTrack.info.squarePixelWidth=this.currentTrack.info.width,this.currentTrack.info.squarePixelHeight=this.currentTrack.info.height,null!==this.currentTrack.info.displayWidth&&null!==this.currentTrack.info.displayHeight){const e=this.currentTrack.info.displayWidth*this.currentTrack.info.height,t=this.currentTrack.info.displayHeight*this.currentTrack.info.width;e>0&&t>0&&(e>t?this.currentTrack.info.squarePixelWidth=Math.round(this.currentTrack.info.width*e/t):this.currentTrack.info.squarePixelHeight=Math.round(this.currentTrack.info.height*t/e))}this.currentTrack.codecId===Di?(this.currentTrack.info.codec="avc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Mi?(this.currentTrack.info.codec="hevc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ni?this.currentTrack.info.codec="vp8":t===Oi?this.currentTrack.info.codec="vp9":t===Li&&(this.currentTrack.info.codec="av1");const e=this.currentTrack;this.currentTrack.trackBacking=new rr(e),this.currentSegment.tracks.push(this.currentTrack)}else if("audio"===this.currentTrack.info.type){t===zi?(this.currentTrack.info.codec="aac",this.currentTrack.info.aacCodecInfo={isMpeg2:this.currentTrack.codecId.includes("MPEG2"),objectType:null},this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Ui?this.currentTrack.info.codec="mp3":t===qi?(this.currentTrack.info.codec="opus",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate,this.currentTrack.info.sampleRate=xe):t===Wi?(this.currentTrack.info.codec="vorbis",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Vi?(this.currentTrack.info.codec="flac",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Hi?(this.currentTrack.info.codec="ac3",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ki?(this.currentTrack.info.codec="eac3",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):"A_PCM/INT/LIT"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32"):"A_PCM/INT/BIG"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16be":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24be":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32be"):"A_PCM/FLOAT/IEEE"===this.currentTrack.codecId&&(32===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-f32":64===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-f64"));const e=this.currentTrack;this.currentTrack.trackBacking=new ar(e),this.currentSegment.tracks.push(this.currentTrack)}}this.currentTrack=null;break;case ki.TrackNumber:if(!this.currentTrack)break;this.currentTrack.id=Ii(e,n);break;case ki.TrackType:{if(!this.currentTrack)break;const t=Ii(e,n);1===t?this.currentTrack.info={type:"video",width:-1,height:-1,displayWidth:null,displayHeight:null,displayUnit:null,squarePixelWidth:-1,squarePixelHeight:-1,rotation:0,codec:null,codecDescription:null,colorSpace:null,alphaMode:!1}:2===t&&(this.currentTrack.info={type:"audio",numberOfChannels:1,sampleRate:8e3,bitDepth:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case ki.FlagEnabled:if(!this.currentTrack)break;Ii(e,n)||(this.currentTrack=null);break;case ki.FlagDefault:if(!this.currentTrack)break;this.currentTrack.disposition.default=!!Ii(e,n);break;case ki.FlagForced:if(!this.currentTrack)break;this.currentTrack.disposition.forced=!!Ii(e,n);break;case ki.FlagOriginal:if(!this.currentTrack)break;this.currentTrack.disposition.original=!!Ii(e,n);break;case ki.FlagHearingImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.hearingImpaired=!!Ii(e,n);break;case ki.FlagVisualImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.visuallyImpaired=!!Ii(e,n);break;case ki.FlagCommentary:if(!this.currentTrack)break;this.currentTrack.disposition.commentary=!!Ii(e,n);break;case ki.CodecID:if(!this.currentTrack)break;this.currentTrack.codecId=Ei(e,n);break;case ki.CodecPrivate:if(!this.currentTrack)break;this.currentTrack.codecPrivate=ln(e,n);break;case ki.DefaultDuration:if(!this.currentTrack)break;this.currentTrack.defaultDurationNs=Ii(e,n);break;case ki.Name:if(!this.currentTrack)break;this.currentTrack.name=_i(e,n);break;case ki.Language:if(!this.currentTrack)break;if(this.currentTrack.hasLanguageBcp47)break;this.currentTrack.languageCode=Ei(e,n),L(this.currentTrack.languageCode)||(this.currentTrack.languageCode=R);break;case ki.LanguageBCP47:{if(!this.currentTrack)break;const t=Ei(e,n).split("-")[0];this.currentTrack.languageCode=t||R,this.currentTrack.hasLanguageBcp47=!0}break;case ki.Video:if("video"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case ki.PixelWidth:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.width=Ii(e,n);break;case ki.PixelHeight:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.height=Ii(e,n);break;case ki.DisplayWidth:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.displayWidth=Ii(e,n);break;case ki.DisplayHeight:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.displayHeight=Ii(e,n);break;case ki.DisplayUnit:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.displayUnit=Ii(e,n);break;case ki.AlphaMode:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.alphaMode=1===Ii(e,n);break;case ki.Colour:if("video"!==this.currentTrack?.info?.type)break;this.currentTrack.info.colorSpace={},this.readContiguousElements(e.slice(o,n));break;case ki.MatrixCoefficients:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=Ii(e,n),i=g[t]??null;this.currentTrack.info.colorSpace.matrix=i}break;case ki.Range:if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;this.currentTrack.info.colorSpace.fullRange=2===Ii(e,n);break;case ki.TransferCharacteristics:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=Ii(e,n),i=m[t]??null;this.currentTrack.info.colorSpace.transfer=i}break;case ki.Primaries:{if("video"!==this.currentTrack?.info?.type||!this.currentTrack.info.colorSpace)break;const t=Ii(e,n),i=h[t]??null;this.currentTrack.info.colorSpace.primaries=i}break;case ki.Projection:if("video"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case ki.ProjectionPoseRoll:{if("video"!==this.currentTrack?.info?.type)break;const t=-Ai(e,n);try{this.currentTrack.info.rotation=r(t)}catch{}}break;case ki.Audio:if("audio"!==this.currentTrack?.info?.type)break;this.readContiguousElements(e.slice(o,n));break;case ki.SamplingFrequency:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.sampleRate=Ai(e,n);break;case ki.Channels:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.numberOfChannels=Ii(e,n);break;case ki.BitDepth:if("audio"!==this.currentTrack?.info?.type)break;this.currentTrack.info.bitDepth=Ii(e,n);break;case ki.CuePoint:if(!this.currentSegment)break;this.readContiguousElements(e.slice(o,n)),this.currentCueTime=null;break;case ki.CueTime:this.currentCueTime=Ii(e,n);break;case ki.CueTrackPositions:{if(null===this.currentCueTime)break;i(this.currentSegment);const t={time:this.currentCueTime,trackId:-1,clusterPosition:-1};this.currentSegment.cuePoints.push(t),this.readContiguousElements(e.slice(o,n)),-1!==t.trackId&&-1!==t.clusterPosition||this.currentSegment.cuePoints.pop()}break;case ki.CueTrack:{const t=this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;t.trackId=Ii(e,n)}break;case ki.CueClusterPosition:{const t=this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;i(this.currentSegment),t.clusterPosition=this.currentSegment.dataStartPos+Ii(e,n)}break;case ki.Timestamp:if(!this.currentCluster)break;this.currentCluster.timestamp=Ii(e,n);break;case ki.SimpleBlock:{if(!this.currentCluster)break;const t=vi(e);if(null===t)break;const i=this.getTrackDataInCluster(this.currentCluster,t);if(!i)break;const r=mn(e),a=un(e),s=a>>1&3;let c=!!(128&a);"audio"===i.track.info?.type&&i.track.info.codec&&(c=!0);const l=ln(e,n-(e.filePos-o)),u=i.track.decodingInstructions.length>0;i.blocks.push({timestamp:r,duration:0,isKeyFrame:c,data:l,lacing:s,decoded:!u,mainAdditional:null})}break;case ki.BlockGroup:if(!this.currentCluster)break;this.readContiguousElements(e.slice(o,n)),this.currentBlock=null;break;case ki.Block:{if(!this.currentCluster)break;const t=vi(e);if(null===t)break;const i=this.getTrackDataInCluster(this.currentCluster,t);if(!i)break;const r=mn(e),a=un(e)>>1&3,s=ln(e,n-(e.filePos-o)),c=i.track.decodingInstructions.length>0;this.currentBlock={timestamp:r,duration:0,isKeyFrame:!0,data:s,lacing:a,decoded:!c,mainAdditional:null},i.blocks.push(this.currentBlock)}break;case ki.BlockAdditions:this.readContiguousElements(e.slice(o,n));break;case ki.BlockMore:if(!this.currentBlock)break;this.currentBlockAdditional={addId:1,data:null},this.readContiguousElements(e.slice(o,n)),this.currentBlockAdditional.data&&1===this.currentBlockAdditional.addId&&(this.currentBlock.mainAdditional=this.currentBlockAdditional.data),this.currentBlockAdditional=null;break;case ki.BlockAdditional:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.data=ln(e,n);break;case ki.BlockAddID:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.addId=Ii(e,n);break;case ki.BlockDuration:if(!this.currentBlock)break;this.currentBlock.duration=Ii(e,n);break;case ki.ReferenceBlock:if(!this.currentBlock)break;this.currentBlock.isKeyFrame=!1;break;case ki.Tag:this.currentTagTargetIsMovie=!0,this.readContiguousElements(e.slice(o,n));break;case ki.Targets:this.readContiguousElements(e.slice(o,n));break;case ki.TargetTypeValue:50!==Ii(e,n)&&(this.currentTagTargetIsMovie=!1);break;case ki.TagTrackUID:case ki.TagEditionUID:case ki.TagChapterUID:case ki.TagAttachmentUID:this.currentTagTargetIsMovie=!1;break;case ki.SimpleTag:if(!this.currentTagTargetIsMovie)break;this.currentSimpleTagName=null,this.readContiguousElements(e.slice(o,n));break;case ki.TagName:this.currentSimpleTagName=_i(e,n);break;case ki.TagString:{if(!this.currentSimpleTagName)break;const t=_i(e,n);this.processTagValue(this.currentSimpleTagName,t)}break;case ki.TagBinary:{if(!this.currentSimpleTagName)break;const t=ln(e,n);this.processTagValue(this.currentSimpleTagName,t)}break;case ki.AttachedFile:{if(!this.currentSegment)break;this.currentAttachedFile={fileUid:null,fileName:null,fileMediaType:null,fileData:null,fileDescription:null},this.readContiguousElements(e.slice(o,n));const t=this.currentSegment.metadataTags;if(this.currentAttachedFile.fileUid&&this.currentAttachedFile.fileData&&(t.raw??(t.raw={}),t.raw[this.currentAttachedFile.fileUid.toString()]=new de(this.currentAttachedFile.fileData,this.currentAttachedFile.fileMediaType??void 0,this.currentAttachedFile.fileName??void 0,this.currentAttachedFile.fileDescription??void 0)),this.currentAttachedFile.fileMediaType?.startsWith("image/")&&this.currentAttachedFile.fileData){const e=this.currentAttachedFile.fileName;let i="unknown";if(e){const t=e.toLowerCase();t.startsWith("cover.")?i="coverFront":t.startsWith("back.")&&(i="coverBack")}t.images??(t.images=[]),t.images.push({data:this.currentAttachedFile.fileData,mimeType:this.currentAttachedFile.fileMediaType,kind:i,name:this.currentAttachedFile.fileName??void 0,description:this.currentAttachedFile.fileDescription??void 0})}this.currentAttachedFile=null}break;case ki.FileUID:if(!this.currentAttachedFile)break;this.currentAttachedFile.fileUid=((e,t)=>{if(t<1)throw new Error("Bad unsigned int size "+t);let i=0n;for(let r=0;rt.order-e.order);break;case ki.ContentEncoding:this.currentDecodingInstruction={order:0,scope:Qi.Block,data:null},this.readContiguousElements(e.slice(o,n)),this.currentDecodingInstruction.data&&this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction),this.currentDecodingInstruction=null;break;case ki.ContentEncodingOrder:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.order=Ii(e,n);break;case ki.ContentEncodingScope:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.scope=Ii(e,n);break;case ki.ContentCompression:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decompress",algorithm:Yi.Zlib,settings:null},this.readContiguousElements(e.slice(o,n));break;case ki.ContentCompAlgo:if("decompress"!==this.currentDecodingInstruction?.data?.type)break;this.currentDecodingInstruction.data.algorithm=Ii(e,n);break;case ki.ContentCompSettings:if("decompress"!==this.currentDecodingInstruction?.data?.type)break;this.currentDecodingInstruction.data.settings=ln(e,n);break;case ki.ContentEncryption:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decrypt"}}return e.filePos=o+n,!0}decodeBlockData(e,t){i(e.decodingInstructions.length>0);let r=t;for(const a of e.decodingInstructions)if(i(a.data),"decompress"===a.data.type)if(a.data.algorithm===Yi.HeaderStripping)if(a.data.settings&&a.data.settings.length>0){const e=a.data.settings,t=new Uint8Array(e.length+r.length);t.set(e,0),t.set(r,e.length),r=t}return r}processTagValue(e,t){var i;if(!this.currentSegment?.metadataTags)return;const r=this.currentSegment.metadataTags;if(r.raw??(r.raw={}),(i=r.raw)[e]??(i[e]=t),"string"===typeof t)switch(e.toLowerCase()){case"title":r.title??(r.title=t);break;case"description":r.description??(r.description=t);break;case"artist":r.artist??(r.artist=t);break;case"album":r.album??(r.album=t);break;case"album_artist":r.albumArtist??(r.albumArtist=t);break;case"genre":r.genre??(r.genre=t);break;case"comment":r.comment??(r.comment=t);break;case"lyrics":r.lyrics??(r.lyrics=t);break;case"date":{const e=new Date(t);Number.isNaN(e.getTime())||(r.date??(r.date=e))}break;case"track_number":case"part_number":{const e=t.split("/"),i=Number.parseInt(e[0],10),a=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(r.trackNumber??(r.trackNumber=i)),a&&Number.isInteger(a)&&a>0&&(r.tracksTotal??(r.tracksTotal=a))}break;case"disc_number":case"disc":{const e=t.split("/"),i=Number.parseInt(e[0],10),a=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(r.discNumber??(r.discNumber=i)),a&&Number.isInteger(a)&&a>0&&(r.discsTotal??(r.discsTotal=a))}}}}class ir{constructor(e){this.internalTrack=e,this.packetToClusterLocation=new WeakMap}getId(){return this.internalTrack.id}getNumber(){const e=this.internalTrack.demuxer,t=this.internalTrack.trackBacking.getType();let i=0;for(const r of e.segments)for(const e of r.tracks)if(e.trackBacking.getType()===t&&i++,e===this.internalTrack)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.codecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.segment.timestampFactor}isRelativeToUnixEpoch(){return!1}getDisposition(){return this.internalTrack.disposition}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){const e=this.internalTrack.segment;if(e.duration<=0)return null;let t=e.duration/e.timestampFactor;const i=await this.getFirstPacket({metadataOnly:!0});return t+=i?.timestamp??0,t}async getLiveRefreshInterval(){return null}async getFirstPacket(e){return this.performClusterLookup(null,e=>e.trackData.get(this.internalTrack.id)?{blockIndex:0,correctBlockFound:!0}:{blockIndex:-1,correctBlockFound:!1},-1/0,1/0,e)}intoTimescale(e){return D(e*this.internalTrack.segment.timestampFactor)}async getPacket(e,t){const i=this.intoTimescale(e);return this.performClusterLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const r=P(t.presentationTimestamps,i,e=>e.timestamp);return{blockIndex:-1!==r?t.presentationTimestamps[r].blockIndex:-1,correctBlockFound:-1!==r&&i{if(e===i.cluster){const t=e.trackData.get(this.internalTrack.id);if(i.blockIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const r=C(t.presentationTimestamps,e=>t.blocks[e.blockIndex].isKeyFrame&&e.timestamp<=i);return{blockIndex:-1!==r?t.presentationTimestamps[r].blockIndex:-1,correctBlockFound:-1!==r&&i{if(e===r.cluster){const t=e.trackData.get(this.internalTrack.id).blocks.findIndex((e,t)=>e.isKeyFrame&&t>r.blockIndex);if(-1!==t)return{blockIndex:t,correctBlockFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.blocks.findIndex(e=>e.isKeyFrame);return i(-1!==e),{blockIndex:e,correctBlockFound:!0}}}return{blockIndex:-1,correctBlockFound:!1}},-1/0,1/0,t)}async fetchPacketInCluster(e,t,r){if(-1===t)return null;const a=e.trackData.get(this.internalTrack.id).blocks[t];i(a),a.decoded||(a.data=this.internalTrack.demuxer.decodeBlockData(this.internalTrack,a.data),a.decoded=!0);const s=r.metadataOnly?Dt:a.data,n=a.timestamp/this.internalTrack.segment.timestampFactor,o=a.duration/this.internalTrack.segment.timestampFactor,c={};a.mainAdditional&&"video"===this.internalTrack.info?.type&&this.internalTrack.info.alphaMode&&(c.alpha=r.metadataOnly?Dt:a.mainAdditional,c.alphaByteLength=a.mainAdditional.byteLength);const l=new Mt(s,a.isKeyFrame?"key":"delta",n,o,e.dataStartPos+t,a.data.byteLength,c);return this.packetToClusterLocation.set(l,{cluster:e,blockIndex:t}),l}async performClusterLookup(e,t,r,a,s){const{demuxer:n,segment:o}=this.internalTrack;let c=null,l=null,u=-1;if(e){const{blockIndex:i,correctBlockFound:r}=t(e);if(r)return this.fetchPacketInCluster(e,i,s);-1!==i&&(l=e,u=i)}const d=P(this.internalTrack.cuePoints,r,e=>e.time),h=-1!==d?this.internalTrack.cuePoints[d]:null,f=P(this.internalTrack.clusterPositionCache,r,e=>e.startTimestamp),m=-1!==f?this.internalTrack.clusterPositionCache[f]:null,p=Math.max(h?.clusterPosition??0,m?.elementStartPos??0)||null;let g;for(e?null===p||e.elementStartPos>=p?(g=e.elementEndPos,c=e):g=p:g=p??o.clusterSeekStartPos;null===o.elementEndPos||g<=o.elementEndPos-2;){if(c){const e=c.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>a)break}let e=n.reader.requestSliceRange(g,2,Si);if(e instanceof Promise&&(e=await e),!e)break;const r=g,d=Bi(e);if(!d||!wi.includes(d.id)&&d.id!==ki.Void){const e=await Ri(n.reader,r,wi,Math.min(o.elementEndPos??1/0,r+er));if(e){g=e;continue}break}const h=d.id;let f=d.size;const m=e.filePos;if(h===ki.Cluster){c=await n.readCluster(r,o),f=c.elementEndPos-m;const{blockIndex:e,correctBlockFound:i}=t(c);if(i)return this.fetchPacketInCluster(c,e,s);-1!==e&&(l=c,u=e)}if(void 0===f){i(h!==ki.Cluster);f=(await Fi(n.reader,m,Ti,o.elementEndPos)).pos-m}const p=m+f;if(null===o.elementEndPos){let e=n.reader.requestSliceRange(p,2,Si);if(e instanceof Promise&&(e=await e),!e)break;if(xi(e)===ki.Segment){o.elementEndPos=p;break}}g=p}if(h&&(!l||l.elementStartPos{let e=null;("vp9"===this.internalTrack.info.codec||"av1"===this.internalTrack.info.codec||"avc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription||"hevc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription)&&(e=await this.getFirstPacket({}));const t={codec:ve({width:this.internalTrack.info.width,height:this.internalTrack.info.height,codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,colorSpace:this.internalTrack.info.colorSpace,avcType:1,avcCodecInfo:"avc"===this.internalTrack.info.codec&&e?Ze(e.data):null,hevcCodecInfo:"hevc"===this.internalTrack.info.codec&&e?nt(e.data):null,vp9CodecInfo:"vp9"===this.internalTrack.info.codec&&e?kt(e.data):null,av1CodecInfo:"av1"===this.internalTrack.info.codec&&e?yt(e.data):null}),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:this.internalTrack.info.codecDescription??void 0,colorSpace:this.internalTrack.info.colorSpace??void 0};return this.internalTrack.info.width===this.internalTrack.info.squarePixelWidth&&this.internalTrack.info.height===this.internalTrack.info.squarePixelHeight||(t.displayAspectWidth=this.internalTrack.info.squarePixelWidth,t.displayAspectHeight=this.internalTrack.info.squarePixelHeight),t})()):null}}class ar extends ir{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getType(){return"audio"}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}async getDecoderConfig(){return this.internalTrack.info.codec?this.decoderConfig??(this.decoderConfig={codec:Ie({codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,aacCodecInfo:this.internalTrack.info.aacCodecInfo}),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:this.internalTrack.info.codecDescription??void 0}):null}}const sr=async(e,t,i)=>{let r=t;for(;null===i||r=4;){const t=a.filePos,i=gn(a),s=null!==e.fileSize?e.fileSize-r:null,n=Me(i,s);if(n.header)return{header:n.header,startPos:r};a.filePos=t+n.bytesAdvanced,r=a.filePos}}return null};class nr extends Rt{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.firstFrameHeaderPos=null,this.loadedSamples=[],this.metadataTags=null,this.xingData=null,this.trackBackings=[],this.readingMutex=new b,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)await this.advanceReader();if(!this.firstFrameHeader)throw new Error("No valid MP3 frame found.");this.trackBackings=[new or(this)]})())}async advanceReader(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,Fn);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const t=Nn(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}const e=await sr(this.reader,this.lastLoadedPos,this.reader.fileSize);if(!e)return void(this.lastSampleLoaded=!0);const t=e.header;this.lastLoadedPos=e.startPos+t.totalSize-1;const i=De(t.mpegVersionId,t.channel);let r=this.reader.requestSlice(e.startPos+i,4);if(r instanceof Promise&&(r=await r),r){const t=gn(r);if(t===Fe||t===Re){if(!this.xingData){let t=this.reader.requestSlice(e.startPos+i+4,12);if(t instanceof Promise&&(t=await t),t){const e=ln(t,12),i=c(e),r=i.getUint32(0,!1);this.xingData={frameCount:r&Oe.FrameCount?i.getUint32(4,!1):null,fileSize:r&Oe.FileSize?i.getUint32(8,!1):null}}}return}}this.firstFrameHeader||(this.firstFrameHeader=t,this.firstFrameHeaderPos=e.startPos),t.sampleRate!==this.firstFrameHeader.sampleRate&&console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${t.sampleRate} Hz. Might be a bug, so please report this file.`);const a=t.audioSamplesInFrame/this.firstFrameHeader.sampleRate,s={timestamp:this.nextTimestampInSamples/this.firstFrameHeader.sampleRate,duration:a,dataStart:e.startPos,dataSize:t.totalSize};this.loadedSamples.push(s),this.nextTimestampInSamples+=t.audioSamplesInFrame}async getMimeType(){return"audio/mpeg"}async getTrackBackings(){return await this.readMetadata(),this.trackBackings}async getMetadataTags(){const e=await this.readingMutex.acquire();try{if(await this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0,t=!1;for(;;){let i=this.reader.requestSlice(e,Fn);if(i instanceof Promise&&(i=await i),!i)break;const r=Nn(i);if(!r)break;t=!0;let a=this.reader.requestSlice(i.filePos,r.size);if(a instanceof Promise&&(a=await a),!a)break;On(a,r,this.metadataTags),e=i.filePos+r.size}if(!t&&null!==this.reader.fileSize&&this.reader.fileSize>=An){let e=this.reader.requestSlice(this.reader.fileSize-An,An);e instanceof Promise&&(e=await e),i(e);"TAG"===In(e,3)&&Dn(e,this.metadataTags)}return this.metadataTags}finally{e()}}}class or{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getTimeResolution(){return i(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.sampleRate/this.demuxer.firstFrameHeader.audioSamplesInFrame}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){const e=this.demuxer;if(i(null!==e.firstFrameHeader),i(null!==e.firstFrameHeaderPos),e.xingData){if(null!==e.xingData.frameCount)return e.xingData.frameCount*e.firstFrameHeader.audioSamplesInFrame/e.firstFrameHeader.sampleRate}else if(null!==e.reader.fileSize){const i=(t=e.firstFrameHeader.lowSamplingFrequency,r=e.firstFrameHeader.layer,a=e.firstFrameHeader.bitrate,s=e.firstFrameHeader.sampleRate,0===r?0:1===r?144*a/(s<e.timestamp);if(-1===i)throw new Error("Packet was not created from this track.");const r=i+1;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{i()}}async getPacket(e,t){const i=await this.demuxer.readingMutex.acquire();try{for(;;){const i=P(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===i&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(i,t);if(i>=0&&i+1>>0&4294967295}const ur=e=>{const t=c(e),i=t.getUint32(22,!0);t.setUint32(22,0,!0);let r=0;for(let a=0;a>>24^t])>>>0}return t.setUint32(22,i,!0),r},dr=(e,t,r)=>{let a=0,s=null;if(e.length>0)if("vorbis"===t.codec){i(t.vorbisInfo);const n=(1<<(e=>{let t=0;for(;e;)t++,e>>=1;return t})(t.vorbisInfo.modeBlockflags.length-1))-1<<1,o=(e[0]&n)>>1;if(o>=t.vorbisInfo.modeBlockflags.length)throw new Error("Invalid mode number.");let c=r;const l=t.vorbisInfo.modeBlockflags[o];if(s=t.vorbisInfo.blocksizes[l],1===l){const i=1+(1|n),r=e[0]&i?1:0;c=t.vorbisInfo.blocksizes[r]}a=null!==c?c+s>>2:0}else if("opus"===t.codec){a=(e=>{const t=e[0]>>3;return{durationInSamples:wt[t]}})(e).durationInSamples}return{durationInSamples:a,vorbisBlockSize:s}},hr=27,fr=282,mr=e=>{const t=e.filePos;if(kn(e)!==cr)return null;e.skip(1);const i=un(e),r=Sn(e),a=kn(e),s=kn(e),n=kn(e),o=un(e),c=new Uint8Array(o);for(let d=0;de+t,0);return{headerStartPos:t,totalSize:l+u,dataStartPos:t+l,dataSize:u,headerType:i,granulePosition:r,serialNumber:a,sequenceNumber:s,checksum:n,lacingValues:c}},pr=(e,t)=>{for(;e.filePos>>8&255)===i||(t>>>16&255)===i||(t>>>24&255)===i){if(e.skip(-4),t===cr)return!0;e.skip(1)}}return!1};class gr extends Rt{constructor(e){super(e),this.metadataPromise=null,this.bitstreams=[],this.trackBackings=[],this.metadataTags={},this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=0;for(;;){let t=this.reader.requestSliceRange(e,hr,fr);if(t instanceof Promise&&(t=await t),!t)break;const i=mr(t);if(!i)break;if(!!!(2&i.headerType))break;this.bitstreams.push({serialNumber:i.serialNumber,bosPage:i,description:null,numberOfChannels:-1,sampleRate:-1,codecInfo:{codec:null,vorbisInfo:null,opusInfo:null},lastMetadataPacket:null}),e=i.headerStartPos+i.totalSize}for(const t of this.bitstreams){const e=await this.readPacket(t.bosPage,0);e&&(e.data.byteLength>=7&&1===e.data[0]&&118===e.data[1]&&111===e.data[2]&&114===e.data[3]&&98===e.data[4]&&105===e.data[5]&&115===e.data[6]?await this.readVorbisMetadata(e,t):e.data.byteLength>=8&&79===e.data[0]&&112===e.data[1]&&117===e.data[2]&&115===e.data[3]&&72===e.data[4]&&101===e.data[5]&&97===e.data[6]&&100===e.data[7]&&await this.readOpusMetadata(e,t),null!==t.codecInfo.codec&&this.trackBackings.push(new kr(t,this)))}})())}async readVorbisMetadata(e,t){let i=await this.findNextPacketStart(e);if(!i)return;const r=await this.readPacket(i.startPage,i.startSegmentIndex);if(!r)return;if(i=await this.findNextPacketStart(r),!i)return;const a=await this.readPacket(i.startPage,i.startSegmentIndex);if(!a)return;if(3!==r.data[0]||5!==a.data[0])return;const s=[],n=e=>{for(;s.push(Math.min(255,e)),!(e<255);)e-=255};n(e.data.length),n(r.data.length);const o=new Uint8Array(1+s.length+e.data.length+r.data.length+a.data.length);o[0]=2,o.set(s,1),o.set(e.data,1+s.length),o.set(r.data,1+s.length+e.data.length),o.set(a.data,1+s.length+e.data.length+r.data.length),t.codecInfo.codec="vorbis",t.description=o,t.lastMetadataPacket=a;const l=c(e.data);t.numberOfChannels=l.getUint8(11),t.sampleRate=l.getUint32(12,!0);const u=l.getUint8(28);t.codecInfo.vorbisInfo={blocksizes:[1<<(15&u),1<<(u>>4)],modeBlockflags:Tt(a.data).modeBlockflags},It(r.data.subarray(7),this.metadataTags)}async readOpusMetadata(e,t){const i=await this.findNextPacketStart(e);if(!i)return;const r=await this.readPacket(i.startPage,i.startSegmentIndex);if(!r)return;t.codecInfo.codec="opus",t.description=e.data,t.lastMetadataPacket=r;const a=(e=>{const t=c(e),i=t.getUint8(9),r=t.getUint16(10,!0),a=t.getUint32(12,!0),s=t.getInt16(16,!0),n=t.getUint8(18);let o=null;return n&&(o=e.subarray(19,21+i)),{outputChannelCount:i,preSkip:r,inputSampleRate:a,outputGain:s,channelMappingFamily:n,channelMappingTable:o}})(e.data);t.numberOfChannels=a.outputChannelCount,t.sampleRate=xe,t.codecInfo.opusInfo={preSkip:a.preSkip},It(r.data.subarray(8),this.metadataTags)}async readPacket(e,t){i(te+t.length,0);if(0===c)return null;const l=new Uint8Array(c);let u=0;for(let i=0;i{let t="audio/ogg";e.codecStrings&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({codecStrings:(await Promise.all(this.trackBackings.map(e=>e.getDecoderConfig().then(e=>e?.codec??null)))).filter(Boolean)})}async getTrackBackings(){return await this.readMetadata(),this.trackBackings}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}}class kr{constructor(e,t){this.bitstream=e,this.demuxer=t,this.encodedPacketToMetadata=new WeakMap,this.sequentialScanCache=[],this.sequentialScanMutex=new b,this.internalSampleRate="opus"===e.codecInfo.codec?xe:e.sampleRate}getType(){return"audio"}getId(){return this.bitstream.serialNumber}getNumber(){const e=this.demuxer.trackBackings.findIndex(e=>e.bitstream===this.bitstream);return i(-1!==e),e+1}getNumberOfChannels(){return this.bitstream.numberOfChannels}getSampleRate(){return this.bitstream.sampleRate}getTimeResolution(){return this.bitstream.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return null}async getLiveRefreshInterval(){return null}getCodec(){return this.bitstream.codecInfo.codec}getInternalCodecId(){return null}async getDecoderConfig(){return i(this.bitstream.codecInfo.codec),{codec:this.bitstream.codecInfo.codec,numberOfChannels:this.bitstream.numberOfChannels,sampleRate:this.bitstream.sampleRate,description:this.bitstream.description??void 0}}getName(){return null}getLanguageCode(){return R}getDisposition(){return{...he,primary:!1}}granulePositionToTimestampInSamples(e){return"opus"===this.bitstream.codecInfo.codec?(i(this.bitstream.codecInfo.opusInfo),e-this.bitstream.codecInfo.opusInfo.preSkip):e}createEncodedPacketFromOggPacket(e,t,i){if(!e)return null;const{durationInSamples:r,vorbisBlockSize:a}=dr(e.data,this.bitstream.codecInfo,t.vorbisLastBlocksize),s=new Mt(i.metadataOnly?Dt:e.data,"key",Math.max(0,t.timestampInSamples)/this.internalSampleRate,r/this.internalSampleRate,e.endPage.headerStartPos+e.endSegmentIndex,e.data.byteLength);return this.encodedPacketToMetadata.set(s,{packet:e,timestampInSamples:t.timestampInSamples,durationInSamples:r,vorbisLastBlockSize:t.vorbisLastBlocksize,vorbisBlockSize:a}),s}async getFirstPacket(e){i(this.bitstream.lastMetadataPacket);const t=await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!t)return null;let r=0;"opus"===this.bitstream.codecInfo.codec&&(i(this.bitstream.codecInfo.opusInfo),r-=this.bitstream.codecInfo.opusInfo.preSkip);const a=await this.demuxer.readPacket(t.startPage,t.startSegmentIndex);return this.createEncodedPacketFromOggPacket(a,{timestampInSamples:r,vorbisLastBlocksize:null},e)}async getNextPacket(e,t){const i=this.encodedPacketToMetadata.get(e);if(!i)throw new Error("Packet was not created from this track.");const r=await this.demuxer.findNextPacketStart(i.packet);if(!r)return null;const a=i.timestampInSamples+i.durationInSamples,s=await this.demuxer.readPacket(r.startPage,r.startSegmentIndex);return this.createEncodedPacketFromOggPacket(s,{timestampInSamples:a,vorbisLastBlocksize:i.vorbisBlockSize},t)}async getPacket(e,t){if(null===this.demuxer.reader.fileSize)return this.getPacketSequential(e,t);const r=D(e*this.internalSampleRate);if(0===r)return this.getFirstPacket(t);if(r<0)return null;i(this.bitstream.lastMetadataPacket);const a=await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!a)return null;let s=a.startPage,n=this.demuxer.reader.fileSize;const o=[s];e:for(;s.headerStartPos+s.totalSizer?n=u.headerStartPos:(s=u,o.push(u));continue e}a=u.headerStartPos+u.totalSize}}let c=a.startPage;for(const i of o){if(i.granulePosition===s.granulePosition)break;(!c||i.headerStartPos>c.headerStartPos)&&(c=i)}let l=c;const u=[l];for(;l.serialNumber!==this.bitstream.serialNumber||l.granulePosition!==s.granulePosition;){const e=l.headerStartPos+l.totalSize;let t=this.demuxer.reader.requestSliceRange(e,hr,fr);t instanceof Promise&&(t=await t),i(t);const r=mr(t);i(r),l=r,l.serialNumber===this.bitstream.serialNumber&&u.push(l)}i(-1!==l.granulePosition);let d,h,f=null,m=l,p=0;if(l.headerStartPos===a.startPage.headerStartPos)d=this.granulePositionToTimestampInSamples(0),h=!0,f=0;else{d=0,h=!1;for(let t=l.lacingValues.length-1;t>=0;t--){if(l.lacingValues[t]<255){f=t+1;break}}if(null===f)throw new Error("Invalid page with granule position: no packets end on this page.");p=f-1;const e={data:Dt,endPage:m,endSegmentIndex:p};if(await this.demuxer.findNextPacketStart(e)){const e=yr(u,l,f);i(e);const t=br(u,e.page,e.segmentIndex);t&&(l=t.page,f=t.segmentIndex)}else for(;;){const e=yr(u,l,f);if(!e)break;const t=br(u,e.page,e.segmentIndex);if(!t)break;if(l=t.page,f=t.segmentIndex,e.page.headerStartPos!==m.headerStartPos){m=e.page,p=e.segmentIndex;break}}}let g=null,k=null;for(;null!==l;){i(null!==f);const e=await this.demuxer.readPacket(l,f);if(!e)break;if(!(l.headerStartPos===a.startPage.headerStartPos&&fr||Math.max(s.timestampInSamples,0)===r))break}const s=await this.demuxer.findNextPacketStart(e);if(!s)break;l=s.startPage,f=s.startSegmentIndex}return g}async getPacketSequential(e,t){const r=await this.sequentialScanMutex.acquire();try{const r=D(e*this.internalSampleRate);e=r/this.internalSampleRate;const s=P(this.sequentialScanCache,r,e=>e.timestampInSamples);let n;if(-1!==s){const e=this.sequentialScanCache[s];n=this.createEncodedPacketFromOggPacket(e.packet,{timestampInSamples:e.timestampInSamples,vorbisLastBlocksize:e.vorbisLastBlockSize},t)}else n=await this.getFirstPacket(t);let o=0;for(;n&&n.timestampe)break;if(n=r,o++,100===o){o=0;const e=this.encodedPacketToMetadata.get(n);i(e),this.sequentialScanCache.length>0&&i(a(this.sequentialScanCache).timestampInSamples<=e.timestampInSamples),this.sequentialScanCache.push(e)}}return n}finally{r()}}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const br=(e,t,r)=>{let a=t,s=r;e:for(;;){for(s--;s>=0;s--){if(a.lacingValues[s]<255){s++;break e}}i(-1===s);if(!(1&a.headerType)){s=0;break}const t=x(e,e=>e.headerStartPos{if(i>0)return{page:t,segmentIndex:i-1};const r=x(e,e=>e.headerStartPos{let e=this.reader.requestSlice(0,12);e instanceof Promise&&(e=await e),i(e);const t=In(e,4),r="RIFX"!==t,a="RF64"===t,s=pn(e,r);let n=a?this.reader.fileSize:Math.min(s+8,this.reader.fileSize??1/0);if("WAVE"!==In(e,4))throw new Error("Invalid WAVE file - wrong format");let o=0,c=null,l=e.filePos;for(;null===n||l=18&&357!==a){const e=dn(r,i),s=t-18;if(Math.min(s,e)>=22&&a===wr.EXTENSIBLE){r.skip(6);const e=ln(r,16);a=e[0]|e[1]<<8}}a!==wr.MULAW&&a!==wr.ALAW||(c=8),this.audioInfo={format:a,numberOfChannels:s,sampleRate:n,sampleSizeInBytes:Math.ceil(c/8),blockSizeInBytes:o}}async parseListChunk(e,t,i){var r,a,s,n,o,c,l,u,d,h,f;let m=this.reader.requestSlice(e,t);if(m instanceof Promise&&(m=await m),!m)return;const p=In(m,4);if("INFO"!==p&&"INF0"!==p)return;let g=m.filePos;for(;g<=e+t-8;){m.filePos=g;const e=In(m,4),t=pn(m,i),p=ln(m,t);let k=0;for(let i=0;i0&&((c=this.metadataTags).trackNumber??(c.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&((l=this.metadataTags).tracksTotal??(l.tracksTotal=i))}break;case"ICRD":case"IDIT":{const e=new Date(b);Number.isNaN(e.getTime())||((u=this.metadataTags).date??(u.date=e))}break;case"YEAR":{const e=Number.parseInt(b,10);Number.isInteger(e)&&e>0&&((d=this.metadataTags).date??(d.date=new Date(e,0,1)))}break;case"IGNR":case"GENR":(h=this.metadataTags).genre??(h.genre=b);break;case"ICMT":case"CMNT":case"COMM":(f=this.metadataTags).comment??(f.comment=b)}g+=8+t+(1&t)}}async parseId3Chunk(e,t){let i=this.reader.requestSlice(e,t);if(i instanceof Promise&&(i=await i),!i)return;const r=Nn(i);if(r){const a=t-Fn;if(r.size=Math.min(r.size,a),r.size>0){const t=i.slice(e+Fn,r.size);On(t,r,this.metadataTags)}}}getCodec(){if(i(this.audioInfo),this.audioInfo.format===wr.MULAW)return"ulaw";if(this.audioInfo.format===wr.ALAW)return"alaw";if(this.audioInfo.format===wr.PCM){if(1===this.audioInfo.sampleSizeInBytes)return"pcm-u8";if(2===this.audioInfo.sampleSizeInBytes)return"pcm-s16";if(3===this.audioInfo.sampleSizeInBytes)return"pcm-s24";if(4===this.audioInfo.sampleSizeInBytes)return"pcm-s32"}return this.audioInfo.format===wr.IEEE_FLOAT&&4===this.audioInfo.sampleSizeInBytes?"pcm-f32":null}async getMimeType(){return"audio/wav"}async getTrackBackings(){return await this.readMetadata(),this.trackBackings}async getMetadataTags(){return await this.readMetadata(),this.metadataTags}}const Pr=2048;class vr{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getCodec(){return this.demuxer.getCodec()}getInternalCodecId(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.format}async getDecoderConfig(){const e=this.demuxer.getCodec();return e?(i(this.demuxer.audioInfo),{codec:e,numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate}):null}getNumberOfChannels(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getTimeResolution(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return i(-1!==this.demuxer.dataSize),this.demuxer.dataSize/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate}async getLiveRefreshInterval(){return null}getName(){return null}getLanguageCode(){return R}getDisposition(){return{...he}}async getPacketAtIndex(e,t){i(e>=0),i(this.demuxer.audioInfo);const r=e*Pr*this.demuxer.audioInfo.blockSizeInBytes;if(r>=this.demuxer.dataSize)return null;const a=Math.min(Pr*this.demuxer.audioInfo.blockSizeInBytes,this.demuxer.dataSize-r);if(null===this.demuxer.reader.fileSize){let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+r,a);if(e instanceof Promise&&(e=await e),!e)return null}let s;if(t.metadataOnly)s=Dt;else{let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+r,a);e instanceof Promise&&(e=await e),i(e),s=ln(e,a)}const n=e*Pr/this.demuxer.audioInfo.sampleRate,o=a/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate;return this.demuxer.lastKnownPacketIndex=Math.max(e,this.demuxer.lastKnownPacketIndex),new Mt(s,"key",n,o,e,a)}getFirstPacket(e){return this.getPacketAtIndex(0,e)}async getPacket(e,t){i(this.demuxer.audioInfo);const r=Math.floor(Math.min(e*this.demuxer.audioInfo.sampleRate/Pr,(this.demuxer.dataSize-1)/(Pr*this.demuxer.audioInfo.blockSizeInBytes)));if(r<0)return null;const a=await this.getPacketAtIndex(r,t);if(a)return a;if(0===r)return null;i(null===this.demuxer.reader.fileSize);let s=await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex,t);for(;s;){const e=await this.getNextPacket(s,t);if(!e)break;s=e}return s}getNextPacket(e,t){i(this.demuxer.audioInfo);const r=Math.round(e.timestamp*this.demuxer.audioInfo.sampleRate/Pr);return this.getPacketAtIndex(r+1,t)}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Ir=e=>{const t=e.filePos,i=ln(e,9),r=new fe(i);if(4095!==r.readBits(12))return null;r.skipBits(1);if(0!==r.readBits(2))return null;const a=r.readBits(1),s=r.readBits(2)+1,n=r.readBits(4);if(15===n)return null;r.skipBits(1);const o=r.readBits(3);if(0===o)throw new Error("ADTS frames with channel configuration 0 are not supported.");r.skipBits(1),r.skipBits(1),r.skipBits(1),r.skipBits(1);const c=r.readBits(13);r.skipBits(11);const l=r.readBits(2)+1;if(1!==l)throw new Error("ADTS frames with more than one AAC frame are not supported.");let u=null;return 1===a?e.filePos-=2:u=r.readBits(16),{objectType:s,samplingFrequencyIndex:n,channelConfiguration:o,frameLength:c,numberOfAacFrames:l,crcCheck:u,startPos:t}},xr=1024;class Cr extends Rt{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.loadedSamples=[],this.metadataTags=null,this.trackBackings=[],this.readingMutex=new b,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)await this.advanceReader();i(this.firstFrameHeader),this.trackBackings=[new Br(this)]})())}async advanceReader(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,Fn);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const t=Nn(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}let e=this.reader.requestSliceRange(this.lastLoadedPos,7,9);if(e instanceof Promise&&(e=await e),!e)return void(this.lastSampleLoaded=!0);const t=Ir(e);if(!t)return void(this.lastSampleLoaded=!0);if(null!==this.reader.fileSize&&t.startPos+t.frameLength>this.reader.fileSize)return void(this.lastSampleLoaded=!0);this.firstFrameHeader||(this.firstFrameHeader=t);const r=me[t.samplingFrequencyIndex];i(void 0!==r);const a=xr/r,s={timestamp:this.nextTimestampInSamples/r,duration:a,dataStart:t.startPos,dataSize:t.frameLength};this.loadedSamples.push(s),this.nextTimestampInSamples+=xr,this.lastLoadedPos=t.startPos+t.frameLength}async getMimeType(){return"audio/aac"}async getTrackBackings(){return await this.readMetadata(),this.trackBackings}async getMetadataTags(){const e=await this.readingMutex.acquire();try{if(await this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0;for(;;){let t=this.reader.requestSlice(e,Fn);if(t instanceof Promise&&(t=await t),!t)break;const i=Nn(t);if(!i)break;let r=this.reader.requestSlice(t.filePos,i.size);if(r instanceof Promise&&(r=await r),!r)break;On(r,i,this.metadataTags),e=t.filePos+i.size}return this.metadataTags}finally{e()}}}class Br{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getTimeResolution(){return this.getSampleRate()/xr}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return null}async getLiveRefreshInterval(){return null}getName(){return null}getLanguageCode(){return R}getCodec(){return"aac"}getInternalCodecId(){return i(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.objectType}getNumberOfChannels(){i(this.demuxer.firstFrameHeader);const e=pe[this.demuxer.firstFrameHeader.channelConfiguration];return i(void 0!==e),e}getSampleRate(){i(this.demuxer.firstFrameHeader);const e=me[this.demuxer.firstFrameHeader.samplingFrequencyIndex];return i(void 0!==e),e}getDisposition(){return{...he}}async getDecoderConfig(){return i(this.demuxer.firstFrameHeader),{codec:`mp4a.40.${this.demuxer.firstFrameHeader.objectType}`,numberOfChannels:this.getNumberOfChannels(),sampleRate:this.getSampleRate()}}async getPacketAtIndex(e,t){if(-1===e)return null;const i=this.demuxer.loadedSamples[e];if(!i)return null;let r;if(t.metadataOnly)r=Dt;else{let e=this.demuxer.reader.requestSlice(i.dataStart,i.dataSize);if(e instanceof Promise&&(e=await e),!e)return null;r=ln(e,i.dataSize)}return new Mt(r,"key",i.timestamp,i.duration,e,i.dataSize)}getFirstPacket(e){return this.getPacketAtIndex(0,e)}async getNextPacket(e,t){const i=await this.demuxer.readingMutex.acquire();try{const i=S(this.demuxer.loadedSamples,e.timestamp,e=>e.timestamp);if(-1===i)throw new Error("Packet was not created from this track.");const r=i+1;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{i()}}async getPacket(e,t){const i=await this.demuxer.readingMutex.acquire();try{for(;;){const i=P(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===i&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(i,t);if(i>=0&&i+1{for(var t;null===this.reader.fileSize||en.end-6)return{num:o.num,blockSize:o.blockSize,sampleRate:o.sampleRate,size:n.end-e,isLastFrame:!0};if(255===un(n)){const t=n.filePos;if(un(n)!==(1===this.blockingBit?249:248)){n.filePos=t;continue}n.skip(-2);const i=n.filePos-e,r=this.readFlacFrameHeader({slice:n,isFirstPacket:!1});if(!r){n.filePos=t;continue}if(0===this.blockingBit){if(r.num-o.num!==1){n.filePos=t;continue}}else if(r.num-o.num!==o.blockSize){n.filePos=t;continue}return{num:o.num,blockSize:o.blockSize,sampleRate:o.sampleRate,size:i,isLastFrame:!1}}}}readFlacFrameHeader({slice:e,isFirstPacket:t}){const r=e.filePos,a=ln(e,4),s=new fe(a);if(32764!==s.readBits(15))return null;if(null===this.blockingBit){i(t);const e=s.readBits(1);this.blockingBit=e}else if(1===this.blockingBit){i(!t);if(1!==s.readBits(1))return null}else{if(0!==this.blockingBit)throw new Error("Invalid blocking bit");i(!t);if(0!==s.readBits(1))return null}const n=(e=>0===e?null:1===e?192:e>=2&&e<=5?144*2**e:6===e?"uncommon-u8":7===e?"uncommon-u16":e>=8&&e<=15?2**e:null)(s.readBits(4));if(!n)return null;i(this.audioInfo);const o=((e,t)=>{switch(e){case 0:return t;case 1:return 88200;case 2:return 176400;case 3:return 192e3;case 4:return 8e3;case 5:return 16e3;case 6:return 22050;case 7:return 24e3;case 8:return 32e3;case 9:return 44100;case 10:return 48e3;case 11:return 96e3;case 12:return"uncommon-u8";case 13:return"uncommon-u16";case 14:return"uncommon-u16-10";default:return null}})(s.readBits(4),this.audioInfo.sampleRate);if(!o)return null;s.readBits(4),s.readBits(3);if(0!==s.readBits(1))return null;const c=(e=>{let t=0;const i=new fe(ln(e,1));for(;1===i.readBits(1);)t++;if(0===t)return i.readBits(7);const r=[],a=t-1,s=new fe(ln(e,a)),n=8-t-1;for(let o=0;oe|t<"uncommon-u16"===t?hn(e)+1:"uncommon-u8"===t?un(e)+1:"number"===typeof t?t:(B(t),void i(!1)))(e,n),u=((e,t)=>"uncommon-u16"===t?hn(e):"uncommon-u16-10"===t?10*hn(e):"uncommon-u8"===t?un(e):"number"===typeof t?t:null)(e,o);if(null===u)return null;if(u!==this.audioInfo.sampleRate)return null;const d=e.filePos-r,h=un(e);e.skip(-d),e.skip(-1);const f=(e=>{let t=0;for(const i of e){t^=i;for(let e=0;e<8;e++)0!==(128&t)?t=t<<1^7:t<<=1,t&=255}return t})(ln(e,d));return h!==f?null:{num:c,blockSize:l,sampleRate:u}}async advanceReader(){await this.readMetadata(),i(null!==this.lastLoadedPos),i(this.audioInfo);const e=this.lastLoadedPos,t=await this.readNextFlacFrame({startPos:e,isFirstPacket:0===this.loadedSamples.length});if(!t)return void(this.lastSampleLoaded=!0);const r=this.loadedSamples[this.loadedSamples.length-1],a={blockOffset:r?r.blockOffset+r.blockSize:0,blockSize:t.blockSize,byteOffset:e,byteSize:t.size};this.lastLoadedPos=this.lastLoadedPos+t.size,this.loadedSamples.push(a),t.isLastFrame&&(this.lastSampleLoaded=!0)}}class _r{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getCodec(){return"flac"}getInternalCodecId(){return null}getNumberOfChannels(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return R}getTimeResolution(){return i(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return i(this.demuxer.audioInfo),0===this.demuxer.audioInfo.totalSamples?null:this.demuxer.audioInfo.totalSamples/this.demuxer.audioInfo.sampleRate}async getLiveRefreshInterval(){return null}getDisposition(){return{...he}}async getDecoderConfig(){return i(this.demuxer.audioInfo),{codec:"flac",numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate,description:this.demuxer.audioInfo.description}}async getPacket(e,t){if(i(this.demuxer.audioInfo),e<0)throw new Error("Timestamp cannot be negative");const r=await this.demuxer.readingMutex.acquire();try{for(;;){const i=P(this.demuxer.loadedSamples,e,e=>e.blockOffset/this.demuxer.audioInfo.sampleRate);if(-1===i){await this.demuxer.advanceReader();continue}const r=this.demuxer.loadedSamples[i],a=r.blockOffset/this.demuxer.audioInfo.sampleRate;if(!(a+r.blockSize/this.demuxer.audioInfo.sampleRate<=e))return this.getPacketAtIndex(i,t);if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(this.demuxer.loadedSamples.length-1,t);await this.demuxer.advanceReader()}}finally{r()}}async getNextPacket(e,t){const i=await this.demuxer.readingMutex.acquire();try{const i=e.sequenceNumber+1;if(this.demuxer.lastSampleLoaded&&i>=this.demuxer.loadedSamples.length)return null;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{i()}}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}async getPacketAtIndex(e,t){const r=this.demuxer.loadedSamples[e];if(!r)return null;let a;if(t.metadataOnly)a=Dt;else{let e=this.demuxer.reader.requestSlice(r.byteOffset,r.byteSize);if(e instanceof Promise&&(e=await e),!e)return null;a=ln(e,r.byteSize)}i(this.demuxer.audioInfo);const s=r.blockOffset/this.demuxer.audioInfo.sampleRate,n=r.blockSize/this.demuxer.audioInfo.sampleRate;return new Mt(a,"key",s,n,e,r.byteSize)}async getFirstPacket(e){for(;0===this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)await this.demuxer.advanceReader();return this.getPacketAtIndex(0,e)}}const Ar=9e4,Fr=188,Rr="PES packet is missing PTS where it was expected. PES packets without PTS are not currently supported. If you think this file should be supported, please report it.",Dr=new Set;class Mr extends Rt{constructor(e){super(e),this.metadataPromise=null,this.elementaryStreams=[],this.trackBackingEntries=[],this.packetOffset=0,this.packetStride=-1,this.sectionEndPositions=[],this.seekChunkSize=5242880,this.minReferencePointByteDistance=-1,this.reader=e._reader}async readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{let e=this.reader.requestSlice(0,205);e instanceof Promise&&(e=await e),i(e);const t=ln(e,205);if(71===t[0]&&71===t[188])this.packetOffset=0,this.packetStride=Fr;else if(71===t[0]&&71===t[204])this.packetOffset=0,this.packetStride=204;else{if(71!==t[4]||71!==t[196])throw new Error("Unreachable.");this.packetOffset=4,this.packetStride=192}this.minReferencePointByteDistance=256*this.packetStride;let r=this.packetOffset,a=null,s=!1,n=!1;for(;;){const e=await this.readPacketHeader(r);if(!e)break;if(0===e.payloadUnitStartIndicator){r+=this.packetStride;continue}const t=await this.readSection(r,!0,!n);if(!t)break;const o=3,c=32;let l=!1;if(!n&&0!==t.pid){if(!(0===t.payload[0]&&0===t.payload[1]&&1===t.payload[2])){const e=new fe(t.payload),i=e.readAlignedByte();e.skipBits(8*i);l=2===e.readBits(8)}}if(0!==t.pid||s)if(t.pid!==a&&!l||n){const e=this.elementaryStreams.find(e=>e.pid===t.pid);e:if(e&&!e.initialized){const r=Or(t,!0);if(!r)throw new Error(`Couldn't read first PES packet for Elementary Stream with PID ${e.pid}`);if(e.firstSection=t,e.canBeTrustedWithKeyPackets=1===t.randomAccessIndicator,this.input._initInput){const i=(await this.input._initInput._getDemuxer()).elementaryStreams.find(i=>i.pid===t.pid&&i.info.codec===e.info.codec);if(i){e.info=i.info,e.initialized=!0;break e}}const a=new Wr(e,r);if("video"===e.info.type){for(;;){if(a.suppliedPacket=null,await a.markNextPacket(),"avc"===e.info.codec){if(!a.suppliedPacket)throw new Error("Invalid AVC video stream; could not extract AVCDecoderConfigurationRecord from any packet.");if(e.info.avcCodecInfo=Ze(a.suppliedPacket.data),!e.info.avcCodecInfo)continue;const t=e.info.avcCodecInfo.sequenceParameterSets[0];i(t);const r=tt(t);e.info.width=r.displayWidth,e.info.height=r.displayHeight;const s=r.pixelAspectRatio.num,n=r.pixelAspectRatio.den;s>0&&n>0&&(s>n?(e.info.squarePixelWidth=Math.round(e.info.width*s/n),e.info.squarePixelHeight=e.info.height):(e.info.squarePixelWidth=e.info.width,e.info.squarePixelHeight=Math.round(e.info.height*n/s))),e.info.colorSpace={primaries:h[r.colourPrimaries],transfer:m[r.transferCharacteristics],matrix:g[r.matrixCoefficients],fullRange:!!r.fullRangeFlag},e.info.reorderSize=r.maxDecFrameBuffering;break}if("hevc"===e.info.codec){if(!a.suppliedPacket)throw new Error("Invalid HEVC video stream; could not extract HVCDecoderConfigurationRecord from first packet.");if(e.info.hevcCodecInfo=nt(a.suppliedPacket.data),!e.info.hevcCodecInfo)continue;const t=e.info.hevcCodecInfo.arrays.find(e=>e.nalUnitType===Ve.SPS_NUT).nalUnits[0];i(t);const r=st(t);e.info.width=r.displayWidth,e.info.height=r.displayHeight,r.pixelAspectRatio.num>r.pixelAspectRatio.den?(e.info.squarePixelWidth=Math.round(e.info.width*r.pixelAspectRatio.num/r.pixelAspectRatio.den),e.info.squarePixelHeight=e.info.height):(e.info.squarePixelWidth=e.info.width,e.info.squarePixelHeight=Math.round(e.info.height*r.pixelAspectRatio.den/r.pixelAspectRatio.num)),e.info.colorSpace={primaries:h[r.colourPrimaries],transfer:m[r.transferCharacteristics],matrix:g[r.matrixCoefficients],fullRange:!!r.fullRangeFlag},e.info.reorderSize=r.maxDecFrameBuffering;break}throw new Error("Unhandled.")}e.info.decoderConfig={codec:ve({width:e.info.width,height:e.info.height,codec:e.info.codec,codecDescription:null,colorSpace:e.info.colorSpace,avcType:1,avcCodecInfo:e.info.avcCodecInfo,hevcCodecInfo:e.info.hevcCodecInfo,vp9CodecInfo:null,av1CodecInfo:null}),codedWidth:e.info.width,codedHeight:e.info.height,colorSpace:e.info.colorSpace},e.info.width===e.info.squarePixelWidth&&e.info.height===e.info.squarePixelHeight||(e.info.decoderConfig.displayAspectWidth=e.info.squarePixelWidth,e.info.decoderConfig.displayAspectHeight=e.info.squarePixelHeight),e.initialized=!0}else{if(await a.markNextPacket(),!a.suppliedPacket)throw new Error(`Couldn't parse first media packet for Elementary Stream with PID ${e.pid}`);if("aac"===e.info.codec){const t=on.tempFromBytes(a.suppliedPacket.data),i=Ir(t);if(!i)throw new Error("Invalid AAC audio stream; could not read ADTS frame header from first packet.");e.info.aacCodecInfo={isMpeg2:!1,objectType:i.objectType},e.info.numberOfChannels=pe[i.channelConfiguration],e.info.sampleRate=me[i.samplingFrequencyIndex]}else if("mp3"===e.info.codec){const t=gn(on.tempFromBytes(a.suppliedPacket.data)),i=Me(t,a.suppliedPacket.data.byteLength);if(!i.header)throw new Error("Invalid MP3 audio stream; could not read frame header from first packet.");e.info.numberOfChannels=3===i.header.channel?1:2,e.info.sampleRate=i.header.sampleRate}else if("ac3"===e.info.codec){const t=Ct(a.suppliedPacket.data);if(!t)throw new Error("Invalid AC-3 audio stream; could not read sync frame from first packet.");if(3===t.fscod)throw new Error("Invalid AC-3 audio stream; reserved sample rate code found in first packet.");e.info.numberOfChannels=xt[t.acmod]+t.lfeon,e.info.sampleRate=ze[t.fscod]}else{if("eac3"!==e.info.codec)throw new Error("Unhandled.");{const t=_t(a.suppliedPacket.data);if(!t)throw new Error("Invalid E-AC-3 audio stream; could not read sync frame from first packet.");const i=At(t);if(null===i)throw new Error("Invalid E-AC-3 audio stream; reserved sample rate code found in first packet.");e.info.numberOfChannels=Ft(t),e.info.sampleRate=i}}e.info.decoderConfig={codec:Ie({codec:e.info.codec,codecDescription:null,aacCodecInfo:e.info.aacCodecInfo}),numberOfChannels:e.info.numberOfChannels,sampleRate:e.info.sampleRate},e.initialized=!0}}}else{const e=new fe(t.payload),i=e.readAlignedByte();e.skipBits(8*i),e.skipBits(12);const r=e.readBits(12);e.skipBits(43),e.readBits(13),e.skipBits(6);const a=e.readBits(10);for(e.skipBits(8*a);8*(r+o)-e.pos>c;){const t=e.readBits(8);e.skipBits(3);const i=e.readBits(13);e.skipBits(6);const r=e.readBits(10),a=e.pos+8*r;let s=!1,n=!1;for(;e.posc;){const t=e.readBits(16);e.skipBits(3);const i=e.readBits(13);if(0!==t){if(null!==a)throw new Error("Only files with a single program are supported.");a=i}}if(null===a)throw new Error("Program Association Table must link to a Program Map Table.");s=!0}if(n&&this.elementaryStreams.every(e=>e.initialized))break;r+=this.packetStride}if(!n){if(!s)throw new Error("No Program Association Table found in the file.");throw new Error("No Program Map Table found in the file.")}for(const i of this.elementaryStreams)"video"===i.info.type?this.trackBackingEntries.push(new zr(i)):this.trackBackingEntries.push(new Ur(i))})())}async getTrackBackings(){return await this.readMetadata(),this.trackBackingEntries}async getMetadataTags(){return{}}async getMimeType(){await this.readMetadata();return(e=>{let t="video/MP2T";const i=[...new Set(e.filter(Boolean))];return i.length>0&&(t+=`; codecs="${i.join(", ")}"`),t})(await Promise.all(this.trackBackingEntries.map(e=>e.getDecoderConfig().then(e=>e?.codec??null))))}async readSection(e,t,i=!1){let r=e,a=e;const s=[];let n,o=0,c=null,l=!0,u=0;for(;;){const e=await this.readPacket(a);if(a+=this.packetStride,!e)break;if(c){if(e.pid!==c.pid){if(i)break;continue}if(1===e.payloadUnitStartIndicator)break}else{if(0===e.payloadUnitStartIndicator)break;c=e}const n=!!(2&e.adaptationFieldControl),d=!!(1&e.adaptationFieldControl);let h=0;if(n&&(h=1+e.body[0],e===c&&h>1&&(u=e.body[1]>>6&1)),d&&(0===h?(s.push(e.body),o+=e.body.byteLength):(s.push(e.body.subarray(h)),o+=e.body.byteLength-h)),r=a,!t&&o>=64){l=!1;break}if(-1!==S(this.sectionEndPositions,r,e=>e)){l=!1;break}}if(l){const e=P(this.sectionEndPositions,r,e=>e);this.sectionEndPositions.splice(e+1,0,r)}if(!c)return null;if(1===s.length)n=s[0];else{const e=s.reduce((e,t)=>e+t.length,0);n=new Uint8Array(e);let t=0;for(const i of s)n.set(i,t),t+=i.length}return{startPos:e,endPos:t?r:null,pid:c.pid,payload:n,randomAccessIndicator:u}}async readPacketHeader(e){let t=this.reader.requestSlice(e,4);if(t instanceof Promise&&(t=await t),!t)return null;if(71!==un(t))throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file.");const i=hn(t);return{payloadUnitStartIndicator:i>>14&1,pid:8191&i,adaptationFieldControl:un(t)>>4&3}}async readPacket(e){let t=this.reader.requestSlice(e,Fr);if(t instanceof Promise&&(t=await t),!t)return null;const i=ln(t,Fr);if(71!==i[0])throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file.");const r=(i[1]<<8)+i[2];return{payloadUnitStartIndicator:r>>14&1,pid:8191&r,adaptationFieldControl:i[3]>>4&3,body:i.subarray(4)}}}const Nr=(e,t)=>{if(e.payload.byteLength<3)return null;const i=new fe(e.payload);if(1!==i.readBits(24))return null;const r=i.readBits(8);if(i.skipBits(16),188===r||190===r||191===r||240===r||241===r||255===r||242===r||248===r)return null;i.skipBits(8);const a=i.readBits(2);i.skipBits(14);let s=null;if(2===a||3===a)s=0,i.skipBits(4),s+=i.readBits(3)*(1<<30),i.skipBits(1),s+=32768*i.readBits(15),i.skipBits(1),s+=i.readBits(15);else if(t)throw new Error(Rr);return{sectionStartPos:e.startPos,sectionEndPos:e.endPos,pts:s,randomAccessIndicator:e.randomAccessIndicator}},Or=(e,t)=>{i(null!==e.endPos);const r=Nr(e,t);if(!r)return null;const a=new fe(e.payload);a.skipBits(32);const s=a.readBits(16);a.skipBits(16);const n=a.readBits(8),o=a.pos+8*n;a.pos=o;const c=o/8;i(Number.isInteger(c));const l=e.payload.subarray(c,s>0?6+s:e.payload.byteLength);return{...r,data:l}};class Lr{constructor(e){this.elementaryStream=e,this.packetBuffers=new WeakMap,this.packetSectionStarts=new WeakMap}getId(){return this.elementaryStream.pid}getNumber(){const e=this.elementaryStream.demuxer,t=this.elementaryStream.info.type;let r=0;for(const a of e.trackBackingEntries)if(a.getType()===t&&r++,i(a instanceof Lr),a.elementaryStream===this.elementaryStream)break;return r}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.elementaryStream.streamType}getName(){return null}getLanguageCode(){return R}getDisposition(){return{...he,primary:!1}}getTimeResolution(){return Ar}isRelativeToUnixEpoch(){return!1}getPairingMask(){return 1n}getBitrate(){return null}getAverageBitrate(){return null}async getDurationFromMetadata(){return null}async getLiveRefreshInterval(){return null}createEncodedPacket(e,t,i){let r;return r=this.allPacketsAreKeyPackets()||1===e.randomAccessIndicator?"key":"delta",new Mt(i.metadataOnly?Dt:e.data,r,e.pts/Ar,Math.max(t/Ar,0),e.sequenceNumber,e.data.byteLength)}async getFirstPacket(e){const t=this.elementaryStream.firstSection;i(t);const r=Or(t,!0);i(r);const a=new Wr(this.elementaryStream,r),s=new Vr(this,a),n=await s.readNext();if(!n)return null;const o=this.createEncodedPacket(n.packet,n.duration,e);return this.packetBuffers.set(o,s),this.packetSectionStarts.set(o,n.packet.sectionStartPos),o}async getNextPacket(e,t){let r=this.packetBuffers.get(e);if(r){const i=await r.readNext();if(!i)return null;this.packetBuffers.delete(e);const a=this.createEncodedPacket(i.packet,i.duration,t);return this.packetBuffers.set(a,r),this.packetSectionStarts.set(a,i.packet.sectionStartPos),a}const a=this.packetSectionStarts.get(e);if(void 0===a)throw new Error("Packet was not created from this track.");const s=this.elementaryStream.demuxer,n=await s.readSection(a,!0);i(n);const o=Or(n,!0);i(o);const c=new Wr(this.elementaryStream,o);r=new Vr(this,c);const l=e.sequenceNumber;for(;;){const e=await r.readNext();if(!e)return null;if(e.packet.sequenceNumber>l){const i=this.createEncodedPacket(e.packet,e.duration,t);return this.packetBuffers.set(i,r),this.packetSectionStarts.set(i,e.packet.sectionStartPos),i}}}async getNextKeyPacket(e,t){let i=e;for(;;){if(i=await this.getNextPacket(i,t),!i)return null;if("key"===i.type)return i}}getPacket(e,t){return this.doPacketLookup(e,!1,t)}getKeyPacket(e,t){return this.doPacketLookup(e,!0,t)}async doPacketLookup(e,t,r){const s=D(e*Ar),n=this.elementaryStream.demuxer,{reader:o,seekChunkSize:c}=n,l=this.elementaryStream.pid,u=async(e,t,i)=>{let r=e;for(;re.pts),g=-1!==p?m[p]:null;if(g&&s-g.pts<45e3)f=g.sectionStartPos;else{let e=0;if(null!==o.fileSize){const t=Math.ceil(o.fileSize/c);if(t>1){let i=0,r=t-1;for(e=i;i<=r;){const t=Math.floor((i+r)/2),a=N(t*c,n.packetStride)+h.sectionStartPos,o=a+c,l=await u(a,o,!1);l?l.pesPacketHeader.pts<=s?(e=t,i=t+1):r=t-1:r=t-1}}}f=N(e*c,n.packetStride)+h.sectionStartPos}const k=await u(f,o.fileSize??1/0,!1);let b=k?.pesPacketHeader??null;b||(b=h);const y=this.getReorderSize(),w=async(e,t)=>{const o=await n.readSection(e,!0);i(o);const c=Or(o,!0);i(c);const l=new Wr(this.elementaryStream,c),u=new Vr(this,l);for(;;){if((a(u.presentationOrderPackets)?.pts??-1/0)>=s)break;if(!(await u.readNextPacket()))break}const d=C(u.presentationOrderPackets,t);if(-1===d)return null;const h=u.presentationOrderPackets[d],f=0===d?0:h.pts-u.presentationOrderPackets[d-1].pts;for(;u.decodeOrderPackets[0]!==h;)u.decodeOrderPackets.shift();u.lastDuration=f;const m=await u.readNext();i(m);const p=this.createEncodedPacket(m.packet,m.duration,r);return this.packetBuffers.set(p,u),this.packetSectionStarts.set(p,m.packet.sectionStartPos),p};if(!t||this.allPacketsAreKeyPackets()){e:for(;;){let e=b.sectionStartPos+n.packetStride;for(;;){const t=await n.readPacketHeader(e);if(!t)break e;if(t.pid===l&&1===t.payloadUnitStartIndicator){const t=await n.readSection(e,!1);if(t){const e=Nr(t,!1);if(e&&null!==e.pts){if(e.pts>s)break e;b=e,qr(this.elementaryStream,b);break}}}e+=n.packetStride}}e:for(let e=0;e=n.packetOffset;){const t=await n.readPacketHeader(e);if(!t)break e;if(t.pid===l&&1===t.payloadUnitStartIndicator){const t=await n.readSection(e,!1);if(t){const e=Nr(t,!1);if(e&&null!==e.pts){b=e;break}}}e-=n.packetStride}}return w(b.sectionStartPos,e=>e.pts<=s)}{let e=f,t=null;const r=!this.elementaryStream.canBeTrustedWithKeyPackets;for(;;){let a=null;const f=e<=h.sectionStartPos;let m,p=null;if(f)m=h,p=d;else{const t=await u(e,o.fileSize??1/0,r);m=t?.pesPacketHeader??null,p=t?.section??null}let g=!1,k=0;e:for(;m&&!(null!==t&&m.sectionStartPos>=t);){if(m.pts<=s){let e;if(this.elementaryStream.canBeTrustedWithKeyPackets)e=1===m.randomAccessIndicator;else{i(p);const t=Or(p,!0);i(t);const r=new Wr(this.elementaryStream,t);await r.markNextPacket(),e=1===r.suppliedPacket?.randomAccessIndicator}e&&(a=m)}if(m.pts>s&&(g=!0),g&&(k++,k>y))break;let e=m.sectionStartPos+n.packetStride;for(;;){const t=await n.readPacketHeader(e);if(!t)break e;if(t.pid===l&&1===t.payloadUnitStartIndicator){const t=await n.readSection(e,r);if(t){const e=Nr(t,!1);if(e&&null!==e.pts){m=e,p=t,qr(this.elementaryStream,m);break}}}e+=n.packetStride}}if(a){let e=a;if(0===k)e:for(let i=0;i=n.packetOffset;){const i=await n.readPacketHeader(t);if(!i)break e;if(i.pid===l&&1===i.payloadUnitStartIndicator){const i=await n.readSection(t,r);if(i){const t=Nr(i,!1);if(t&&null!==t.pts){e=t;break}}}t-=n.packetStride}}const t=await w(e.sectionStartPos,e=>e.pts<=s&&1===e.randomAccessIndicator);return i(t),t}if(f)return null;t=e,e=Math.max(N(e-h.sectionStartPos-c,n.packetStride)+h.sectionStartPos,h.sectionStartPos)}}}}class zr extends Lr{getType(){return"video"}getCodec(){return this.elementaryStream.info.codec}getCodedWidth(){return this.elementaryStream.info.width}getCodedHeight(){return this.elementaryStream.info.height}getSquarePixelWidth(){return this.elementaryStream.info.squarePixelWidth}getSquarePixelHeight(){return this.elementaryStream.info.squarePixelHeight}getRotation(){return 0}async getColorSpace(){return this.elementaryStream.info.colorSpace}async canBeTransparent(){return!1}async getDecoderConfig(){return i(this.elementaryStream.info.decoderConfig),this.elementaryStream.info.decoderConfig}allPacketsAreKeyPackets(){return!1}getReorderSize(){return this.elementaryStream.info.reorderSize}}class Ur extends Lr{getType(){return"audio"}getCodec(){return this.elementaryStream.info.codec}getNumberOfChannels(){return this.elementaryStream.info.numberOfChannels}getSampleRate(){return this.elementaryStream.info.sampleRate}async getDecoderConfig(){return i(this.elementaryStream.info.decoderConfig),this.elementaryStream.info.decoderConfig}allPacketsAreKeyPackets(){return!0}getReorderSize(){return 0}}const qr=(e,t)=>{const i=e.referencePesPackets,r=P(i,t.sectionStartPos,e=>e.sectionStartPos);if(r>=0){const a=i[r];if(t.pts<=a.pts)return!1;const s=e.demuxer.minReferencePointByteDistance;if(t.sectionStartPos-a.sectionStartPos=e?e:this.bufferData(e-t).then(()=>Math.min(this.endPos-this.currentPos,e))}getCurrentPesPacket(){const e=this.pesPackets[this.currentPesPacketIndex];return i(e),e}async bufferData(e){const t=this.endPos+e;for(;this.endPos=n)break;o=e;const i=a+o;if(o+4>=n){this.seekTo(i);break}const c=s[o+1],l=s[o+2],u=s[o+3];let d=0,h=null;if(0===c&&0===l&&1===u?(d=4,h=s[o+4]):0===c&&1===l&&(d=3,h=u),0===d){o++;continue}const f=i;if(null!==r){if(null!==h){const e="avc"===t?$e(h):at(h);if("avc"===t?e===qe.AUD:e===Ve.AUD_NUT){const e=f-r;return this.seekTo(r),this.supplyPacket(e,0)}}o+=d}else r=f,o+=d}if(e>6,o=63&s[4];if(3===n||o>37){this.seekTo(t+1);continue}const c=Bt[3*o+n];i(void 0!==c),this.seekTo(t),a=this.ensureBuffered(c),a instanceof Promise&&(a=await a);const l=Math.round(13824e4/e.info.sampleRate);return this.supplyPacket(a,l)}if("eac3"===t){if(11!==r)continue;this.skip(-1);const t=this.currentPos;let i=this.ensureBuffered(5);if(i instanceof Promise&&(i=await i),i<5)return;const a=this.readBytes(5);if(11!==a[0]||119!==a[1]){this.seekTo(t+1);continue}const s=2*(((7&a[2])<<8|a[3])+1),n=3===a[4]>>6?3:a[4]>>4&3,o=Et[n];this.seekTo(t),i=this.ensureBuffered(s),i instanceof Promise&&(i=await i);const c=256*o,l=Math.round(c*Ar/e.info.sampleRate);return this.supplyPacket(i,l)}throw new Error("Unhandled.")}{if(255!==r)continue;this.skip(-1);const t=this.currentPos;let i=this.ensureBuffered(4);if(i instanceof Promise&&(i=await i),i<4)return;const a=this.readBytes(4),s=c(a).getUint32(0),n=Me(s,null);if(n.header){this.seekTo(t);let i=this.ensureBuffered(n.header.totalSize);i instanceof Promise&&(i=await i);const r=n.header.audioSamplesInFrame*Ar/e.info.sampleRate;return this.supplyPacket(i,Math.round(r))}this.seekTo(t+1)}}}if(a=0)}async readNext(){if(0===this.decodeOrderPackets.length){if(!(await this.readNextPacket()))return null}await this.ensureCurrentPacketHasNext();const e=this.decodeOrderPackets[0],t=this.presentationOrderPackets.indexOf(e);let r;if(i(-1!==t),t===this.presentationOrderPackets.length-1)r=this.lastDuration;else{r=this.presentationOrderPackets[t+1].pts-e.pts,this.lastDuration=r}for(this.decodeOrderPackets.shift();this.presentationOrderPackets.length>0;){const e=this.presentationOrderPackets[0];if(this.decodeOrderPackets.includes(e))break;this.presentationOrderPackets.shift()}return{packet:e,duration:r}}async readNextPacket(){if(this.reachedEnd)return!1;let e;return this.context.suppliedPacket||await this.context.markNextPacket(),e=this.context.suppliedPacket,this.context.suppliedPacket=null,e?(this.decodeOrderPackets.push(e),this.processPacketThroughReorderBuffer(e),!0):(this.reachedEnd=!0,this.flushReorderBuffer(),!1)}async ensureCurrentPacketHasNext(){const e=this.decodeOrderPackets[0];for(i(e);;){const t=this.presentationOrderPackets.indexOf(e);if(-1!==t&&t<=this.presentationOrderPackets.length-2)break;if(!(await this.readNextPacket()))break}}processPacketThroughReorderBuffer(e){if(this.reorderBuffer.push(e),this.reorderBuffer.length>this.reorderSize){let e=0;for(let i=1;ie.pts-t.pts),this.presentationOrderPackets.push(...this.reorderBuffer),this.reorderBuffer.length=0}}const Hr="application/vnd.apple.mpegurl",Kr="#EXT-X-STREAM-INF:",jr="#EXT-X-I-FRAME-STREAM-INF:",Xr="#EXT-X-MEDIA:",$r="#EXTINF:",Qr="#EXT-X-MAP:",Gr="#EXT-X-KEY:",Yr="#EXT-X-MEDIA-SEQUENCE:",Jr="#EXT-X-BYTERANGE:",Zr="#EXT-X-PROGRAM-DATE-TIME:",ea="#EXT-X-TARGETDURATION:",ta="#EXT-X-PLAYLIST-TYPE:",ia=e=>0===e.length||e.startsWith("#")&&!e.startsWith("#EXT");class ra{constructor(e){this._attributes={};let t="",i="",r=!1,a=!1;for(let s=0;s{const e=[];if(this.trackDeclarations){for(const t of this.trackDeclarations)if("video"===t.type){const i=ae(e,e=>"video"===e.getType())+1;e.push(new na(this,t,i))}else if("audio"===t.type){const i=ae(e,e=>"audio"===e.getType())+1;e.push(new oa(this,t,i))}}else{if(this.firstSegment=await this.getFirstSegment({}),!this.firstSegment)return[];const t=this.getInputForSegment(this.firstSegment),i=await t.getTracks();for(const r of i)if("video"===r.type){const t=ae(e,e=>"video"===e.getType())+1;e.push(new na(this,{id:e.length+1,type:"video"},t))}else if("audio"===r.type){const t=ae(e,e=>"audio"===e.getType())+1;e.push(new oa(this,{id:e.length+1,type:"audio"},t))}}return e})())}async getFirstTimestampForInput(e){const t=this.firstTimestampCache.get(e);if(void 0!==t)return t;const i=await e.getFirstTimestamp();return this.firstTimestampCache.set(e,i),i}async getMediaOffset(e,t){const i=e.firstSegment??e;let r;if(this.firstSegmentFirstTimestamps.has(i))r=this.firstSegmentFirstTimestamps.get(i);else{const e=this.getInputForSegment(i);r=await this.getFirstTimestampForInput(e),this.firstSegmentFirstTimestamps.set(i,r)}if(i===e)return i.timestamp-r;const a=await this.getFirstTimestampForInput(t),s=e.timestamp-i.timestamp,n=a-r-s;return Math.abs(n)<=Math.min(.25,s)?i.timestamp-r:e.timestamp-a}dispose(){for(const e of this.inputCache)e.input.dispose();this.inputCache.length=0}}class sa{constructor(e,t,i){this.packetInfos=new WeakMap,this.hydrationPromise=null,this.firstInputTrack=null,this.segmentedInput=e,this.decl=t,this.number=i}hydrate(){return this.hydrationPromise??(this.hydrationPromise=(async()=>{var e;if((e=this.segmentedInput).firstSegment??(e.firstSegment=await this.segmentedInput.getFirstSegment({})),!this.segmentedInput.firstSegment)throw new Error("Missing first segment, can't retrieve track.");const t=this.segmentedInput.getInputForSegment(this.segmentedInput.firstSegment),i=(await t.getTracks()).find(e=>e.type===this.decl.type&&e.number===this.number);if(!i)throw new Error("No matching track found in underlying media data.");this.firstInputTrack=i})())}getId(){return this.decl.id}getType(){return this.decl.type}getNumber(){return this.number}delegate(e){return this.firstInputTrack?e():this.hydrate().then(e)}async getDecoderConfig(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())}getHasOnlyKeyPackets(){return this.delegate(()=>this.firstInputTrack._backing.getHasOnlyKeyPackets?.()??null)}getPairingMask(){return 1n}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getInternalCodecId(){return this.delegate(()=>this.firstInputTrack._backing.getInternalCodecId())}getDisposition(){return this.delegate(()=>this.firstInputTrack._backing.getDisposition())}getLanguageCode(){return this.delegate(()=>this.firstInputTrack._backing.getLanguageCode())}getName(){return this.delegate(()=>this.firstInputTrack._backing.getName())}getTimeResolution(){return this.delegate(()=>this.firstInputTrack._backing.getTimeResolution())}async isRelativeToUnixEpoch(){return await this.hydrate(),i(this.segmentedInput.firstSegment),this.segmentedInput.firstSegment.relativeToUnixEpoch}getBitrate(){return this.delegate(()=>this.firstInputTrack._backing.getBitrate())}getAverageBitrate(){return this.delegate(()=>this.firstInputTrack._backing.getAverageBitrate())}getDurationFromMetadata(e){return this.segmentedInput.getDurationFromMetadata(e)}getLiveRefreshInterval(){return this.segmentedInput.getLiveRefreshInterval()}async createAdjustedPacket(e,t,r){i(e.sequenceNumber>=0),i(this.segmentedInput.firstSegment);const a=await this.segmentedInput.getMediaOffset(t,r.input),s=t.timestamp-this.segmentedInput.firstSegment.timestamp,n=e.clone({timestamp:M(e.timestamp+a,await r.getTimeResolution()),sequenceNumber:Math.floor(1e8*s)+e.sequenceNumber});return this.packetInfos.set(n,{segment:t,track:r,sourcePacket:e}),n}async getFirstPacket(e){await this.hydrate(),i(this.segmentedInput.firstSegment),i(this.firstInputTrack);const t=await this.firstInputTrack._backing.getFirstPacket(e);return t?this.createAdjustedPacket(t,this.segmentedInput.firstSegment,this.firstInputTrack):null}getNextPacket(e,t){return this._getNextInternal(e,t,!1)}getNextKeyPacket(e,t){return this._getNextInternal(e,t,!0)}async _getNextInternal(e,t,i){const r=this.packetInfos.get(e);if(!r)throw new Error("Packet was not created from this track.");const a=i?await r.track._backing.getNextKeyPacket(r.sourcePacket,t):await r.track._backing.getNextPacket(r.sourcePacket,t);if(a)return this.createAdjustedPacket(a,r.segment,r.track);let s=r.segment;for(;;){const e=await this.segmentedInput.getNextSegment(s,{skipLiveWait:t.skipLiveWait});if(!e)return null;const i=this.segmentedInput.getInputForSegment(e),a=(await i.getTracks()).find(e=>e.type===r.track.type&&e.number===r.track.number);if(!a){s=e;continue}const n=await a._backing.getFirstPacket(t);return n?this.createAdjustedPacket(n,e,a):null}}getPacket(e,t){return this._getPacketInternal(e,t,!1)}getKeyPacket(e,t){return this._getPacketInternal(e,t,!0)}async _getPacketInternal(e,t,i){let r=await this.segmentedInput.getSegmentAt(e,{skipLiveWait:t.skipLiveWait});if(!r)return null;for(await this.hydrate();r;){const a=this.segmentedInput.getInputForSegment(r),s=(await a.getTracks()).find(e=>e.type===this.firstInputTrack.type&&e.number===this.firstInputTrack.number);if(!s){r=await this.segmentedInput.getPreviousSegment(r,{skipLiveWait:t.skipLiveWait});continue}const n=e-await this.segmentedInput.getMediaOffset(r,a),o=i?await s._backing.getKeyPacket(n,t):await s._backing.getPacket(n,t);if(o)return this.createAdjustedPacket(o,r,s);r=await this.segmentedInput.getPreviousSegment(r,{skipLiveWait:t.skipLiveWait})}return null}}class na extends sa{getType(){return"video"}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getCodedWidth(){return this.delegate(()=>this.firstInputTrack._backing.getCodedWidth())}getCodedHeight(){return this.delegate(()=>this.firstInputTrack._backing.getCodedHeight())}getSquarePixelWidth(){return this.delegate(()=>this.firstInputTrack._backing.getSquarePixelWidth())}getSquarePixelHeight(){return this.delegate(()=>this.firstInputTrack._backing.getSquarePixelHeight())}getRotation(){return this.delegate(()=>this.firstInputTrack._backing.getRotation())}async getColorSpace(){return this.delegate(()=>this.firstInputTrack._backing.getColorSpace())}async canBeTransparent(){return this.delegate(()=>this.firstInputTrack._backing.canBeTransparent())}async getDecoderConfig(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())}}class oa extends sa{getType(){return"audio"}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getNumberOfChannels(){return this.delegate(()=>this.firstInputTrack._backing.getNumberOfChannels())}getSampleRate(){return this.delegate(()=>this.firstInputTrack._backing.getSampleRate())}async getDecoderConfig(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())}}te();const ca=1/0;class la extends le{constructor(){super(...arguments),this._disposed=!1,this._refCount=0,this._usedForHls=!1,this._sizePromise=null,this.onread=null}async getSizeOrNull(){if(this._disposed)throw new sn;return this._sizePromise??(this._sizePromise=(async()=>{let e=this._getFileSize();return void 0!==e||(await this._read(0,1,0,ca),e=this._getFileSize(),i(void 0!==e)),e})())}async getSize(){if(this._disposed)throw new sn;const e=await this.getSizeOrNull();if(null===e)throw new Error("Cannot determine the size of an unsized source.");return e}slice(e,t){if(!Number.isInteger(e)||e<0)throw new TypeError("offset must be a non-negative integer.");if(void 0!==t&&(!Number.isInteger(t)||t<0))throw new TypeError("length, when provided, must be a non-negative integer.");return new Ta(this,e,t)}_dispatchRead(e,t){this.onread?.(e,t),this._emit("read",{start:e,end:t})}ref(){return new ua(this)}}class ua{constructor(e){if(this._freed=!1,e._disposed)throw new Error("Cannot ref a disposed source.");e._refCount++,this._source=e}get source(){if(!this._source)throw new Error("Can't get source; ref has already been freed.");return this._source}get freed(){return this._freed}free(){if(this._freed)throw new Error("Illegal operation: double free on SourceRef.");const e=this.source;i(e._refCount>0),e._refCount--,0===e._refCount&&(e._dispose(),e._disposed=!0),this._freed=!0,this._source=null}[Symbol.dispose](){this.freed||this.free()}}class da extends la{constructor(e,t){if("string"!==typeof e)throw new TypeError("rootPath must be a string.");if("function"!==typeof t)throw new TypeError("requestHandler must be a function.");super(),this.rootPath=e,this.requestHandler=t}_resolveRequest(e){const t=this.requestHandler(e),i=e=>{var t;if(!(e instanceof la||e instanceof ua))throw new TypeError("requestHandler must return or resolve to a Source or SourceRef.");const i=e instanceof la?e.ref():e;return(t=i.source)._usedForHls||(t._usedForHls=this._usedForHls),i};return t instanceof Promise?t.then(i):i(t)}}const ha=(e,t)=>e.path===t.path;class fa extends da{constructor(){super(...arguments),this._root=null,this._rootRequest=null}_read(e,t,r,a){if(!this._root){if(!this._rootRequest){const e=this._resolveRequest({path:this.rootPath,isRoot:!0}),t=e=>{const t=e instanceof la?e.ref():e;return this._root=t,this._rootRequest=null,t};e instanceof Promise?this._rootRequest=e.then(t):(t(e),i(this._root))}if(this._rootRequest)return this._rootRequest.then(i=>i.source._read(e,t,r,a))}return this._root.source._read(e,t,r,a)}_getFileSize(){if(this._root)return this._root.source._getFileSize()}_dispose(){this._root?this._root.free():this._rootRequest&&this._rootRequest.then(e=>e.free())}}class ma extends la{constructor(e,t={}){if(!(e instanceof Blob))throw new TypeError("blob must be a Blob.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!ie(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._readers=new WeakMap,this._blob=e,this._orchestrator=new wa({maxCacheSize:t.maxCacheSize??8388608,maxWorkerCount:4,runWorker:this._runWorker.bind(this),prefetchProfile:ya.fileSystem}),this._orchestrator.fileSize=e.size}_getFileSize(){return this._orchestrator.fileSize}_read(e,t,i,r){return this._orchestrator.read(e,t,i,r)}async _runWorker(e){i(e.strictTarget);let t=this._readers.get(e);if(void 0===t){if("stream"in this._blob&&!K()){t=this._blob.slice(e.currentPos).stream().getReader()}else t=null;this._readers.set(e,t)}for(;e.currentPos{if(t instanceof Error&&(t.message.includes("Failed to fetch")||t.message.includes("Load failed")||t.message.includes("NetworkError when attempting to fetch resource"))){let e=null;try{"undefined"!==typeof window&&"undefined"!==typeof window.location&&(e=new URL(i instanceof Request?i.url:i,window.location.href).origin)}catch{}if(("undefined"===typeof navigator||"boolean"!==typeof navigator.onLine||navigator.onLine)&&null!==e&&e!==window.location.origin)return console.warn("Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option."),null}return Math.min(2**(e-2),16)},ga=new Set;class ka extends da{constructor(e,t={}){if("string"!==typeof e&&!(e instanceof URL)&&!("undefined"!==typeof Request&&e instanceof Request))throw new TypeError("url must be a string, URL or Request.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.requestInit&&(!t.requestInit||"object"!==typeof t.requestInit))throw new TypeError("options.requestInit, when provided, must be an object.");if(void 0!==t.getRetryDelay&&"function"!==typeof t.getRetryDelay)throw new TypeError("options.getRetryDelay, when provided, must be a function.");if(void 0!==t.maxCacheSize&&(!ie(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");if(void 0!==t.parallelism&&(!Number.isInteger(t.parallelism)||t.parallelism<1))throw new TypeError("options.parallelism, when provided, must be a positive number.");if(void 0!==t.fetchFn&&"function"!==typeof t.fetchFn)throw new TypeError("options.fetchFn, when provided, must be a function.");super(e instanceof Request?e.url:e instanceof URL?e.href:e,e=>new ka(e.path,this._options)),this._fileSizeDetermined=!1,this._url=e,this._options=t,this._getRetryDelay=t.getRetryDelay??pa;this._orchestrator=new wa({maxCacheSize:t.maxCacheSize??67108864,maxWorkerCount:t.parallelism??2,runWorker:this._runWorker.bind(this),prefetchProfile:ya.network})}_getFileSize(){return this._fileSizeDetermined?this._orchestrator.fileSize:void 0}_read(e,t,i,r){return this._orchestrator.read(e,t,i,r)}async _runWorker(e){for(;;){const i=new AbortController,r=await W(this._options.fetchFn??fetch,this._url,U(this._options.requestInit??{},{headers:{Range:`bytes=${e.currentPos}-`},signal:i.signal}),this._getRetryDelay,()=>this._disposed);if(!r.ok)throw new Error(`Error fetching ${String(this._url)}: ${r.status} ${r.statusText}`);e:if(null===this._orchestrator.fileSize){const t=r.headers.get("Content-Range");if(t){const e=/\/(\d+)/.exec(t);if(e){this._orchestrator.supplyFileSize(Number(e[1]));break e}}const i=r.headers.get("Content-Length");i&&this._orchestrator.supplyFileSize(e.currentPos+Number(i))}if(this._fileSizeDetermined=!0,206!==r.status){if(!this._usedForHls){const e=new URL(this._url instanceof Request?this._url.url:this._url,"undefined"!==typeof window?window.location.href:void 0);"null"===e.origin||e.pathname.endsWith(".m3u8")||e.pathname.endsWith(".m3u")||ga.has(e.origin)||(console.log(this._usedForHls,this._url,e.pathname),console.warn(`HTTP server (origin ${e.origin}) did not respond to a range request with 206 Partial Content, meaning the entire resource will now be downloaded. To enable efficient media file streaming across a network, please make sure your server supports range requests.`),ga.add(e.origin))}e.currentPos=0,this._orchestrator.options.maxCacheSize=1/0,null!==this._orchestrator.fileSize?e.targetPos=this._orchestrator.fileSize:(e.targetPos=1/0,e.strictTarget=!1),this._orchestrator.consolidateEverythingIntoOneWorker(e)}if(!r.body)throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream.");const a=r.body.getReader();for(;;){if(e.currentPos>=e.targetPos||e.aborted)return i.abort(),void this._orchestrator.signalWorkerStoppedRunning(e);let r;try{r=await a.read()}catch(t){if(this._disposed)throw t;const e=this._getRetryDelay(1,t,this._url);if(null!==e){console.error("Error while reading response stream. Attempting to resume.",t),await ce(1e3*e);break}throw t}if(e.aborted)continue;const{done:s,value:n}=r;if(s){if(e.currentPos>=e.targetPos)return void this._orchestrator.onWorkerFinished(e);if(e.strictTarget)break;return void this._orchestrator.onWorkerFinished(e)}this._dispatchRead(e.currentPos,e.currentPos+n.length),this._orchestrator.supplyWorkerData(e,n)}}}_dispose(){this._orchestrator.dispose()}}class ba extends la{constructor(e,t={}){if(!(e instanceof ReadableStream))throw new TypeError("stream must be a ReadableStream.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!ie(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._reader=null,this._cache=[],this._pendingSlices=[],this._currentIndex=0,this._targetIndex=0,this._maxRequestedIndex=0,this._endIndex=null,this._pulling=!1,this._stream=e,this._maxCacheSize=t.maxCacheSize??16777216}_getFileSize(){return this._endIndex}_read(e,t){if(null!==this._endIndex&&t>this._endIndex)return null;this._maxRequestedIndex=Math.max(this._maxRequestedIndex,t);const i=P(this._cache,e,e=>e.start),r=-1!==i?this._cache[i]:null;if(r&&r.start<=e&&t<=r.end)return{bytes:r.bytes,view:r.view,offset:r.start};let a=e;const s=new Uint8Array(t-e);if(-1!==i)for(let c=i;c=t)break;const r=Math.max(e,i.start);r>a&&this._throwDueToCacheMiss();const n=Math.min(t,i.end);ra&&this._throwDueToCacheMiss();const{promise:n,resolve:o,reject:l}=I();return this._pendingSlices.push({start:e,end:t,bytes:s,resolve:o,reject:l}),this._targetIndex=Math.max(this._targetIndex,t),this._pulling||(this._pulling=!0,this._pull().catch(e=>{if(this._pulling=!1,!(this._pendingSlices.length>0))throw e;this._pendingSlices.forEach(t=>t.reject(e)),this._pendingSlices.length=0})),n}_throwDueToCacheMiss(){throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache.")}async _pull(){for(this._reader??(this._reader=this._stream.getReader());this._currentIndex0;){const e=this._cache[0];if(this._maxRequestedIndex-e.end<=this._maxCacheSize)break;this._cache.shift()}this._currentIndex+=t.byteLength}this._pulling=!1}_dispose(){this._pendingSlices.length=0,this._cache.length=0,this._reader?.cancel()}}const ya={fileSystem:(e,t)=>{const i=65536;return{start:e=Math.floor((e-i)/i)*i,end:t=Math.ceil((t+i)/i)*i}},network:(e,t,i)=>{const r=65536;e=Math.max(0,Math.floor((e-r)/r)*r);for(const a of i){const i=8388608,r=Math.max((a.startPos+a.targetPos)/2,a.targetPos-i);if(Z(e,t,r,a.targetPos)){const e=a.targetPos-a.startPos,r=Math.ceil((e+1)/i)*i,s=2**Math.ceil(Math.log2(e+1)),n=Math.min(s,r);t=Math.max(t,a.startPos+n)}}return{start:e,end:t=Math.max(t,e+524288)}}};class wa{constructor(e){this.options=e,this.fileSize=null,this.nextAge=0,this.workers=[],this.cache=[],this.currentCacheSize=0,this.disposed=!1,this.queuedReads=[]}read(e,t,r,a){i(!this.disposed);const s=this.options.prefetchProfile(e,t,this.workers),n=Math.max(s.start,r),o=Math.min(s.end,this.fileSize??1/0,a);i(n<=e&&t<=o);let l=null;const u=P(this.cache,e,e=>e.start),d=-1!==u?this.cache[u]:null;d&&d.start<=e&&t<=d.end&&(d.age=this.nextAge++,l={bytes:d.bytes,view:d.view,offset:d.start});const h=P(this.cache,n,e=>e.start),f=l?null:new Uint8Array(t-e);let m=0,p=n;const g=[];if(-1!==h){for(let r=h;r=o)break;if(a.end<=n)continue;const s=Math.max(n,a.start),c=Math.min(o,a.end);if(i(s<=c),p=f.length&&(l={bytes:f,view:c(f),offset:e}),0===g.length)return i(l),l;const{promise:k,resolve:b,reject:y}=I(),w=[];for(const i of g){const r=Math.max(e,i.start),a=Math.min(t,i.end);r===i.start&&a===i.end?w.push(i):re.hole.start),r=-1!==t?this.queuedReads[t]:null;for(r&&i.start<=r.hole.end?(r.hole.end=Math.max(r.hole.end,i.end),r.strictTarget&&(r.strictTarget=e),T&&r.pendingSlices.push(T)):(t++,r={hole:{start:i.start,end:i.end},strictTarget:e,pendingSlices:T?[T]:[],age:this.nextAge++},this.queuedReads.splice(t,0,r));t+1r.hole.end)break;r.hole.end=Math.max(r.hole.end,e.hole.end),r.pendingSlices.push(...e.pendingSlices),r.strictTarget&&(r.strictTarget=e.strictTarget),r.age=Math.min(r.age,e.age),this.queuedReads.splice(t+1,1)}}}return l||(i(f),l=k.then(t=>t&&{bytes:t,view:c(t),offset:e})),l}checkHoleAgainstWorker(e,t,i){if(Z(t.start-2**17,t.start,e.currentPos,e.targetPos)){e.targetPos=Math.max(e.targetPos,t.end);for(let t=0;t=this.options.maxWorkerCount){let e=null,t=null;for(let i=0;i{if(e.running=!1,!(e.pendingSlices.length>0))throw t;e.pendingSlices.forEach(e=>e.reject(t)),e.pendingSlices.length=0}).finally(()=>{if(!e.running&&this.queuedReads.length>0){let e=0;for(let i=1;ie.targetPos&&(e.targetPos=e.currentPos,this.checkQueuedReadsAgainstWorker(e));for(let i=0;it.start&&(t.start=a),t.end<=t.start&&(s.holes.splice(e,1),e--)}0===s.holes.length&&(s.resolve(s.bytes),e.pendingSlices.splice(i,1),i--)}for(let i=0;ie){r.resolve(null),t.pendingSlices.splice(i,1),i--;break}}}for(let t=0;t=e){for(const e of i.pendingSlices)e.resolve(null);this.queuedReads.splice(t,1),t--}else if(i.hole.end>e){i.hole.end=e,i.strictTarget=!0;for(let t=0;t=e&&(r.resolve(null),i.pendingSlices.splice(t,1),t--)}}}}signalWorkerStoppedRunning(e){e.running=!1,e.pendingSlices.length=0}onWorkerFinished(e){const t=this.workers.indexOf(e);i(-1!==t),e.running=!1,this.workers.splice(t,1),null===this.fileSize&&this.supplyFileSize(e.currentPos);for(const i of e.pendingSlices)i.resolve(null)}insertIntoCache(e){if(0===this.options.maxCacheSize)return;let t=P(this.cache,e.start,e=>e.start)+1;if(t>0){const i=this.cache[t-1];if(i.end>=e.end)return;if(i.end>e.start){const r=new Uint8Array(e.end-i.start);r.set(i.bytes,0),r.set(e.bytes,e.start-i.start),this.currentCacheSize+=e.end-i.end,i.bytes=r,i.view=c(r),i.end=e.end,t--,e=i}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length;for(let i=t+1;i=t.end){this.cache.splice(i,1),this.currentCacheSize-=t.bytes.length,i--;continue}const r=new Uint8Array(t.end-e.start);r.set(e.bytes,0),r.set(t.bytes,t.start-e.start),this.currentCacheSize-=e.end-t.start,e.bytes=r,e.view=c(r),e.end=t.end,this.cache.splice(i,1);break}for(;this.currentCacheSize>this.options.maxCacheSize;){let e=0,t=this.cache[0];for(let i=1;ithis._length)return null;const a=this._baseSource._read(this._offset+e,this._offset+t,this._offset+i,this._offset+r);return a instanceof Promise?a.then(e=>e?(e.offset-=this._offset,e):null):a?(a.offset-=this._offset,a):null}_dispose(){this._ref?.free()}ref(){return this._ref??(this._ref=this._baseSource.ref()),super.ref()}}var Sa=function(e,t,i){if(null!==t&&void 0!==t){if("object"!==typeof t&&"function"!==typeof t)throw new TypeError("Object expected.");var r,a;if(i){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");r=t[Symbol.asyncDispose]}if(void 0===r){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");r=t[Symbol.dispose],i&&(a=r)}if("function"!==typeof r)throw new TypeError("Object not disposable.");a&&(r=function(){try{a.call(this)}catch(e){return Promise.reject(e)}}),e.stack.push({value:t,dispose:r,async:i})}else i&&e.stack.push({async:!0});return t},Pa=function(e){return function(t){function i(i){t.error=t.hasError?new e(i,t.error,"An error was suppressed during disposal."):i,t.hasError=!0}var r,a=0;return function e(){for(;r=t.stack.pop();)try{if(!r.async&&1===a)return a=0,t.stack.push(r),Promise.resolve().then(e);if(r.dispose){var s=r.dispose.call(r.value);if(r.async)return a|=2,Promise.resolve(s).then(e,function(t){return i(t),e()})}else a|=1}catch(n){i(n)}if(1===a)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}()}}("function"===typeof SuppressedError?SuppressedError:function(e,t,i){var r=new Error(i);return r.name="SuppressedError",r.error=e,r.suppressed=t,r});const va=/^0[xX][0-9a-fA-F]+$/,Ia=/^data:.*;base64,/i;class xa extends aa{constructor(e,t,i,r){super(e.input,t,i),this.segments=[],this.nextLines=null,this.currentUpdateSegmentsPromise=null,this.streamHasEnded=!1,this.lastSegmentUpdateTime=-1/0,this.refreshInterval=5,this.demuxer=e,this.nextLines=r}runUpdateSegments(){return this.currentUpdateSegmentsPromise??(this.currentUpdateSegmentsPromise=(async()=>{try{const e=this.getRemainingWaitTimeMs();e>0&&await ce(e),this.lastSegmentUpdateTime=performance.now(),await this.updateSegments()}finally{this.currentUpdateSegmentsPromise=null}})())}getRemainingWaitTimeMs(){const e=performance.now()-this.lastSegmentUpdateTime,t=Math.max(0,1e3*this.refreshInterval-e);return t<=50?0:t}async updateSegments(){let e=this.nextLines;if(this.nextLines=null,!e){const t={stack:[],error:void 0,hasError:!1};try{const r=Sa(t,await this.demuxer.input._getSourceUncached({path:this.path,isRoot:!1}),!1),a=new nn(r.source),s=await a.requestEntireFile();i(s),e=xn(s,s.length,{ignore:ia})}catch(y){t.error=y,t.hasError=!0}finally{Pa(t)}}let t=!1,r=0,s=null,n=null,o=0,l=null,u=null,d=null,h=null,f=null,m=null,p=!1,g=a(this.segments)??null;const k=e=>{const t=e.indexOf("@"),i=Number(-1===t?e:e.slice(0,t));if(!Number.isInteger(i)||i<0)throw new Error(`Invalid #EXT-X-BYTERANGE length '${e}'.`);let r=null;if(-1!==t&&(r=Number(e.slice(t+1)),!Number.isInteger(r)||r<0))throw new Error(`Invalid #EXT-X-BYTERANGE offset '${e}'.`);return{length:i,offset:r}},b=e=>{o=e,g&&(i(null!==g.sequenceNumber),g.sequenceNumber0&&null!==m&&(r=o*m),p=!0);const e=y.slice(8),t=e.indexOf(","),i=-1===t?e:e.slice(0,t),a=Number(i);if(!Number.isFinite(a)||a<0)throw new Error(`Invalid #EXTINF tag duration '${i}'.`);s=a}else if(y.startsWith(Qr)){const e=new ra(y.slice(11)),t=e.get("uri");if(!t)throw new Error("Invalid #EXT-X-MAP tag; missing URI attribute.");const i=e.get("byterange");let a=null;if(null!==i&&(a=k(i)),a&&null===a.offset)throw new Error("Invalid #EXT-X-MAP tag; BYTERANGE attribute must have a specified offset.");if(!g){const e={path:re(this.path,t),offset:a?.offset??0,length:a?.length??null};if("AES-128"===n?.method&&!n.iv)throw new Error("IV attribute must be set on #EXT-X-KEY tag preceding the #EXT-X-MAP tag.");u={timestamp:r,relativeToUnixEpoch:null!==f,firstSegment:null,sequenceNumber:null,location:e,duration:0,encryption:n,initSegment:null,lastProgramDateTimeSeconds:f}}s=null,null===h?d=null:h=null}else if(y.startsWith(Gr)){const e=new ra(y.slice(11)),t=e.get("method");if("NONE"===t)n=null;else if("AES-128"===t){const t=e.get("uri");if(!t)throw new Error("Invalid #EXT-X-KEY: AES-128 requires a URI attribute.");let i=null;const r=e.get("iv");if(r){if(!va.test(r))throw new Error(`Unsupported IV format '${r}'.`);let e=r.slice(2);e=e.padStart(32,"0"),i=new Uint8Array(Ht);for(let t=0;t=8&&112===t[4]&&115===t[5]&&115===t[6]&&104===t[7]){const e=c(t).getUint32(0);r=Nt(t.subarray(8,Math.min(e,t.length)))}}n={method:t,psshBox:r}}}}else if(y.startsWith(Yr)){const e=y.slice(22),t=Number(e);if(!Number.isInteger(t)||t<0)throw new Error(`Invalid EXT-X-MEDIA-SEQUENCE value '${e}'.`);b(t)}else if(y.startsWith(Jr)){const e=k(y.slice(17));if(null===e.offset){if(null===d)throw new Error("Invalid M3U8 file; #EXT-X-BYTERANGE without offset requires a previous byte range.");e.offset=d}h=e,d=e.offset+e.length}else if(y.startsWith(Zr)){if(g)continue;const e=y.slice(25),t=Date.parse(e);if(!Number.isFinite(t))continue;const i=t/1e3;if(f===i)continue;if(null===f&&this.segments.length>0){const e=a(this.segments),t=i-(e.timestamp+e.duration);for(const i of this.segments)i.timestamp+=t,i.relativeToUnixEpoch=!0;r+=t}f=i,r=i}else if("#EXT-X-DISCONTINUITY"===y)l=null;else if(y.startsWith(ea)){const e=y.slice(22),t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error(`Invalid EXT-X-TARGETDURATION value '${e}'.`);this.refreshInterval=t,m=t}else{if("#EXT-X-ENDLIST"===y){this.streamHasEnded=!0;break}if(y.startsWith(ta)){"vod"===y.slice(21).toLowerCase()&&(this.streamHasEnded=!0)}}}else{if("#EXTM3U"!==y)throw new Error("Invalid M3U8 file; expected first line to be #EXTM3U.");t=!0}}if(!t)throw new Error("Invalid M3U8 file; no #EXTM3U header.")}async getFirstSegment(){return 0===this.segments.length&&await this.runUpdateSegments(),this.segments[0]??null}async getSegmentAt(e,t){0===this.segments.length&&await this.runUpdateSegments();let i=!!t.skipLiveWait&&this.getRemainingWaitTimeMs()>0;for(;;){const r=P(this.segments,e,e=>e.timestamp);if(-1===r)return null;if(r0;for(;;){if(ae.segment===t);if(r)return r.age=this.nextInputCacheAge++,r.input;let a=null;(t.initSegment||t.firstSegment)&&(a=this.getInputForSegment(t.initSegment??t.firstSegment));const s={...this.input._formatOptions,isobmff:{...this.input._formatOptions.isobmff,resolveKeyId:this.input._formatOptions.isobmff?.resolveKeyId&&(e=>{if(!t.encryption||"SAMPLE-AES"!==t.encryption.method&&"SAMPLE-AES-CTR"!==t.encryption.method||!t.encryption.psshBox)return this.input._formatOptions.isobmff.resolveKeyId(e);let i=e.psshBoxes;const{psshBox:r}=t.encryption;return null!==r.keyIds&&!r.keyIds.includes(e.keyId)||i.some(e=>Ot(e,r))||(i=[...i,r]),this.input._formatOptions.isobmff.resolveKeyId({...e,psshBoxes:i})})}},n=new rn({source:new fa(t.location.path,async e=>{i(e.isRoot);const r={...e,isRoot:!1};let a;const s=t.location.offset>0||null!==t.location.length;if(t.encryption&&"SAMPLE-AES"!==t.encryption.method&&"SAMPLE-AES-CTR"!==t.encryption.method)if("AES-128"===t.encryption.method){const e=t.encryption;i(e.iv);let n=await this.input._getSourceCached(r);if(s){const e=n.source.slice(t.location.offset,t.location.length??void 0).ref();n.free(),n=e}const o=((e,t,i)=>{let r=!1,a=0;const s=new Zt;return new ReadableStream({pull:async n=>{r||(s.init(await t()),r=!0);let o=e.requestSliceRange(a,0,65552);if(o instanceof Promise&&(o=await o),!o||0===o.length)throw new Error("Invalid ciphertext.");const c=o.length;if(c%16!==0)throw new Error("Invalid ciphertext.");const l=65552===c?c-16:c,u=ln(o,l),d=new Uint8Array(l);for(let e=0;e16)throw new Error("Invalid PKCS#7 padding. Incorrect key or corrupted data.");const t=d.subarray(0,l-e);n.enqueue(t),n.close(),i()}},cancel:()=>{i()}})})(new nn(n.source),async()=>{const t={stack:[],error:void 0,hasError:!1};try{const i=Sa(t,await this.input._getSourceCached({path:e.keyUri,isRoot:!1},en),!1),r=new nn(i.source),a=await r.requestSlice(0,Ht);if(!a)throw new Error("Invalid AES-128 key; expected at least 16 bytes of data.");return{key:ln(a,Ht),iv:e.iv}}catch(i){t.error=i,t.hasError=!0}finally{Pa(t)}},()=>{n.free()});a=new ba(o).ref()}else i(!1);else if(a=await this.input._getSourceCached(r),s){const e=a.source.slice(t.location.offset,t.location.length??void 0).ref();a.free(),a=e}return a}),formats:this.input._formats.filter(e=>!(e instanceof ja)),initInput:a??void 0,formatOptions:s});n._onFormatDetermined=e=>{if(("SAMPLE-AES"===t.encryption?.method||"SAMPLE-AES-CTR"===t.encryption?.method)&&!e._isIsobmff)throw new Error("The SAMPLE-AES and SAMPLE-AES-CTR encryption methods are currently only supported for ISOBMFF files.")},this.inputCache.push({segment:t,input:n,age:this.nextInputCacheAge++});if(this.inputCache.length>4){const e=se(this.inputCache,e=>e.age);i(-1!==e),this.inputCache.splice(e,1)}return n}async getLiveRefreshInterval(){return 0===this.getRemainingWaitTimeMs()&&await this.runUpdateSegments(),this.streamHasEnded?null:this.refreshInterval}}class Ca extends Rt{constructor(e){super(e),this.metadataPromise=null,this.trackBackings=null,this.internalTracks=null,this.segmentedInputs=[],this.hasMasterPlaylist=!0}readMetadata(){return this.metadataPromise??(this.metadataPromise=(async()=>{i(this.input._rootSource instanceof da);const{rootPath:e}=this.input._rootSource,t=await this.input._reader.requestEntireFile();i(t);const r=xn(t,t.length,{ignore:ia}),a=[],s=[];for(let i=1;i"video"===e.attributes.get("type").toLowerCase()).map(e=>e.attributes.get("group-id")))],o=[...new Set(s.filter(e=>"audio"===e.attributes.get("type").toLowerCase()).map(e=>e.attributes.get("group-id")))],c=await Promise.all(a.map(async(t,r)=>{const a=[],c=t.attributes.get("codecs");let l;if(c)l=c.split(",").map(e=>e.trim());else{const e=this.getSegmentedInputForPath(t.fullPath),i=await e.getTrackBackings(),r=await Promise.all(i.map(async e=>({track:e,codec:await e.getCodec()})));l=await Promise.all(r.filter(e=>null!==e.codec).map(e=>e.track.getDecoderConfig().then(e=>e.codec)))}const u=t.attributes.get("video"),d=t.attributes.get("audio"),h=l.some(e=>ke.includes(Ee(e))),f=l.some(e=>ye.includes(Ee(e)));if(null!==u&&!h){if(!n.includes(u))throw new Error(`Invalid M3U8 file; variant stream references video group "${u}" which is not defined in any #EXT-X-MEDIA tags.`);const t=s.find(e=>{const t=e.attributes.get("group-id"),i=e.attributes.get("type");return t===u&&"video"===i.toLowerCase()});e:if(t){const r=t.attributes.get("uri");if(null===r)break e;const a=re(e,r),s=this.getSegmentedInputForPath(a),n=(await s.getTrackBackings()).find(e=>"video"===e.getType());if(!n||null===await n.getCodec())break e;const o=await n.getDecoderConfig().then(e=>e?.codec??null);i(null!==o),l.push(o)}}if(null!==d&&!f){if(!o.includes(d))throw new Error(`Invalid M3U8 file; variant stream references audio group "${d}" which is not defined in any #EXT-X-MEDIA tags.`);const t=s.find(e=>{const t=e.attributes.get("group-id"),i=e.attributes.get("type");return t===d&&"audio"===i.toLowerCase()});e:if(t){const r=t.attributes.get("uri");if(null===r)break e;const a=re(e,r),s=this.getSegmentedInputForPath(a),n=(await s.getTrackBackings()).find(e=>"audio"===e.getType());if(!n||null===await n.getCodec())break e;const o=await n.getDecoderConfig().then(e=>e?.codec??null);i(null!==o),l.push(o)}}l=[...new Set(l)];let m=null,p=null;const g=t.attributes.getAsNumber("bandwidth");i(null!==g);const k=t.attributes.getAsNumber("average-bandwidth"),b=t.attributes.get("name");for(const e of l){const i=Ee(e);if(null!==i)if(ke.includes(i)){if(null!==m)throw new Error("Unsupported M3U8 file; multiple video codecs found in the CODECS attribute of a variant stream.");m=e;const i=t.attributes.get("video");if(null===i){const e=t.attributes.get("resolution");let i=null,s=null;if(e){const t=e.match(/^(\d+)x(\d+)$/);t&&(i=Number(t[1]),s=Number(t[2]))}a.push({id:-1,demuxer:this,backingTrack:null,default:!0,autoselect:!0,languageCode:R,lineNumber:t.lineNumber,fullPath:t.fullPath,fullCodecString:m,pairingMask:1n<0?i:null}})}else{if(!o.includes(i))throw new Error(`Invalid M3U8 file; variant stream references audio group "${i}" which is not defined in any #EXT-X-MEDIA tags.`);for(const e of s){const s=e.attributes.get("group-id"),n=e.attributes.get("type");if(s!==i||"audio"!==n.toLowerCase())continue;const o=e.attributes.get("channels")??t.attributes.get("channels"),c=null!==o?Number(o.split("/")[0]):null;a.push({id:-1,demuxer:this,backingTrack:null,default:Aa(e.attributes),autoselect:Aa(e.attributes)||Fa(e.attributes),languageCode:Ra(e.attributes.get("language")),lineNumber:e.lineNumber,fullPath:e.fullPath??t.fullPath,fullCodecString:p,pairingMask:1n<0?c:null}})}}}}return a})),l=[],u=e=>{const t=l.find(t=>t.fullPath===e.fullPath&&t.info.type===e.info.type);t?(t.pairingMask|=e.pairingMask,t.default||(t.default=e.default),t.autoselect||(t.autoselect=e.autoselect),t.lineNumber=Math.min(t.lineNumber,e.lineNumber),null!==e.peakBitrate&&(t.peakBitrate=Math.max(t.peakBitrate??-1/0,e.peakBitrate)),null!==e.averageBitrate&&(t.averageBitrate=Math.max(t.averageBitrate??-1/0,e.averageBitrate)),t.languageCode===R&&(t.languageCode=e.languageCode)):(e.id=l.length+1,l.push(e))};for(const i of c)for(const e of i)u(e);l.sort((e,t)=>e.lineNumber-t.lineNumber),this.trackBackings=[];for(const i of l)"video"===i.info.type?this.trackBackings.push(new Ea(i)):this.trackBackings.push(new _a(i));this.internalTracks=l})())}async getTrackBackings(){return await this.readMetadata(),i(this.trackBackings),this.trackBackings}getSegmentedInputForPath(e){let t=this.segmentedInputs.find(t=>t.path===e);if(t)return t;let i=null;if(this.internalTracks){i=this.internalTracks.filter(t=>t.fullPath===e).map(e=>({id:e.id,type:e.info.type}))}return t=new xa(this,e,i,null),this.segmentedInputs.push(t),t}async getMetadataTags(){return{}}async getMimeType(){return Hr}dispose(){if(this.segmentedInputs){for(const e of this.segmentedInputs)e.dispose();this.segmentedInputs.length=0}}}class Ba{constructor(e){this.internalTrack=e,this.hydrationPromise=null}hydrate(){return this.hydrationPromise??(this.hydrationPromise=(async()=>{const e=this.internalTrack.demuxer.getSegmentedInputForPath(this.internalTrack.fullPath);let t=null;const r=(await e.getTrackBackings()).filter(e=>e.getType()===this.getType());if(1===r.length)t=r[0];else if(this instanceof Ea){for(const i of r)if(await i.getCodec()===this.getCodec()){t=i;break}}else{i(this instanceof _a);for(const e of r)if(await e.getCodec()===this.getCodec()){t=e;break}}if(!t)throw new Error("Could not find matching track in underlying media data.");this.internalTrack.backingTrack=t})())}delegate(e){return this.internalTrack.backingTrack?e():this.hydrate().then(e)}getCodec(){throw new Error("Not implemented on base class.")}getDisposition(){return{...he,default:this.internalTrack.autoselect,primary:this.internalTrack.default}}getId(){return this.internalTrack.id}getPairingMask(){return this.internalTrack.pairingMask}getInternalCodecId(){return null}getLanguageCode(){return this.internalTrack.languageCode}getName(){return this.internalTrack.name}getNumber(){i(this.internalTrack.demuxer.internalTracks);const e=this.internalTrack.info.type;let t=0;for(const i of this.internalTrack.demuxer.internalTracks)if(i.info.type===e&&t++,i===this.internalTrack)break;return t}getTimeResolution(){return this.delegate(()=>this.internalTrack.backingTrack.getTimeResolution())}isRelativeToUnixEpoch(){return this.delegate(()=>this.internalTrack.backingTrack.isRelativeToUnixEpoch())}getBitrate(){return this.internalTrack.peakBitrate}getAverageBitrate(){return this.internalTrack.averageBitrate}async getDurationFromMetadata(e){return await this.hydrate(),this.internalTrack.backingTrack.getDurationFromMetadata(e)}async getLiveRefreshInterval(){return await this.hydrate(),this.internalTrack.backingTrack.getLiveRefreshInterval()}getHasOnlyKeyPackets(){return this.internalTrack.hasOnlyKeyPackets||null}async getFirstPacket(e){return await this.hydrate(),this.internalTrack.backingTrack.getFirstPacket(e)}async getPacket(e,t){return await this.hydrate(),this.internalTrack.backingTrack.getPacket(e,t)}async getKeyPacket(e,t){return await this.hydrate(),this.internalTrack.backingTrack.getKeyPacket(e,t)}async getNextPacket(e,t){return await this.hydrate(),this.internalTrack.backingTrack.getNextPacket(e,t)}async getNextKeyPacket(e,t){return await this.hydrate(),this.internalTrack.backingTrack.getNextKeyPacket(e,t)}}class Ea extends Ba{constructor(e){super(e)}get backingVideoTrack(){return this.internalTrack.backingTrack}getType(){return"video"}getCodec(){return Ee(this.internalTrack.fullCodecString)}getCodedWidth(){return this.delegate(()=>this.backingVideoTrack.getCodedWidth())}getCodedHeight(){return this.delegate(()=>this.backingVideoTrack.getCodedHeight())}getSquarePixelWidth(){return this.delegate(()=>this.backingVideoTrack.getSquarePixelWidth())}getSquarePixelHeight(){return this.delegate(()=>this.backingVideoTrack.getSquarePixelHeight())}getMetadataDisplayWidth(){return this.backingVideoTrack?null:this.internalTrack.info.width}getMetadataDisplayHeight(){return this.backingVideoTrack?null:this.internalTrack.info.height}getRotation(){return this.delegate(()=>this.backingVideoTrack.getRotation())}async getColorSpace(){return await this.hydrate(),this.backingVideoTrack.getColorSpace()}async canBeTransparent(){return await this.hydrate(),this.backingVideoTrack.canBeTransparent()}getMetadataCodecParameterString(){return this.backingVideoTrack?null:this.internalTrack.fullCodecString}async getDecoderConfig(){return await this.hydrate(),this.backingVideoTrack.getDecoderConfig()}}class _a extends Ba{constructor(e){super(e)}get backingAudioTrack(){return this.internalTrack.backingTrack}getType(){return"audio"}getCodec(){return Ee(this.internalTrack.fullCodecString)}getNumberOfChannels(){return null!==this.internalTrack.info.numberOfChannels?this.internalTrack.info.numberOfChannels:this.delegate(()=>this.backingAudioTrack.getNumberOfChannels())}getSampleRate(){return this.delegate(()=>this.backingAudioTrack.getSampleRate())}getMetadataCodecParameterString(){return this.backingAudioTrack?null:this.internalTrack.fullCodecString}async getDecoderConfig(){return await this.hydrate(),this.backingAudioTrack.getDecoderConfig()}}const Aa=e=>{const t=e.get("default");if(null===t)return!1;const i=t.toUpperCase();if("YES"===i)return!0;if("NO"===i)return!1;throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA DEFAULT attribute must be YES or NO, got "${t}".`)},Fa=e=>{const t=e.get("autoselect");if(null===t)return!1;const i=t.toUpperCase();if("YES"===i)return!0;if("NO"===i)return!1;throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA AUTOSELECT attribute must be YES or NO, got "${t}".`)},Ra=e=>{if(null===e)return R;const t=e.split("-")[0];return t||R};class Da{constructor(){this._isIsobmff=!1}}class Ma extends Da{constructor(){super(...arguments),this._isIsobmff=!0}async _getMajorBrand(e){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=await t),!t)return null;t.skip(4);const i=In(t,4);return"ftyp"!==i&&"styp"!==i?null:In(t,4)}_createDemuxer(e){return new ei(e)}}class Na extends Ma{async _canReadInput(e){const t=await this._getMajorBrand(e);if(null!==t)return"qt "!==t;let i=e._reader.requestSlice(4,4);return i instanceof Promise&&(i=await i),!!i&&"moof"===In(i,4)}get name(){return"MP4"}get mimeType(){return"video/mp4"}}class Oa extends Ma{async _canReadInput(e){return"qt "===await this._getMajorBrand(e)}get name(){return"QuickTime File Format"}get mimeType(){return"video/quicktime"}}class La extends Da{async isSupportedEBMLOfDocType(e,t){let i=e._reader.requestSlice(0,Si);if(i instanceof Promise&&(i=await i),!i)return!1;const r=Pi(i);if(null===r)return!1;if(r<1||r>8)return!1;if(Ii(i,r)!==ki.EBML)return!1;const a=Ci(i);if("number"!==typeof a)return!1;let s=e._reader.requestSlice(i.filePos,a);if(s instanceof Promise&&(s=await s),!s)return!1;const n=i.filePos;for(;s.filePos<=n+a-2;){const e=Bi(s);if(!e)break;const{id:i,size:r}=e,a=s.filePos;if(void 0===r)return!1;switch(i){case ki.EBMLVersion:if(1!==Ii(s,r))return!1;break;case ki.EBMLReadVersion:if(1!==Ii(s,r))return!1;break;case ki.DocType:if(Ei(s,r)!==t)return!1;break;case ki.DocTypeVersion:if(Ii(s,r)>4)return!1}s.filePos=a+r}return!0}_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"matroska")}_createDemuxer(e){return new tr(e)}get name(){return"Matroska"}get mimeType(){return"video/x-matroska"}}class za extends La{_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"webm")}get name(){return"WebM"}get mimeType(){return"video/webm"}}class Ua extends Da{async _canReadInput(e){let t=0;for(;;){let i=e._reader.requestSlice(t,Fn);if(i instanceof Promise&&(i=await i),!i)break;const r=Nn(i);if(!r)break;t=i.filePos+r.size}const i=await sr(e._reader,t,t+4096);if(!i)return!1;const r=i.header,a=De(r.mpegVersionId,r.channel);let s=e._reader.requestSlice(i.startPos+a,4);if(s instanceof Promise&&(s=await s),!s)return!1;const n=gn(s);if(n===Fe||n===Re)return!0;t=i.startPos+i.header.totalSize;const o=await sr(e._reader,t,t+4);if(!o)return!1;const c=o.header;return r.channel===c.channel&&r.sampleRate===c.sampleRate}_createDemuxer(e){return new nr(e)}get name(){return"MP3"}get mimeType(){return"audio/mpeg"}}class qa extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=await t),!t)return!1;const i=In(t,4);if("RIFF"!==i&&"RIFX"!==i&&"RF64"!==i)return!1;t.skip(4);return"WAVE"===In(t,4)}_createDemuxer(e){return new Sr(e)}get name(){return"WAVE"}get mimeType(){return"audio/wav"}}class Wa extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=await t),!!t&&"OggS"===In(t,4)}_createDemuxer(e){return new gr(e)}get name(){return"Ogg"}get mimeType(){return"application/ogg"}}class Va extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=await t),!!t&&"fLaC"===In(t,4)}get name(){return"FLAC"}get mimeType(){return"audio/flac"}_createDemuxer(e){return new Er(e)}}class Ha extends Da{async _canReadInput(e){let t=0;for(;;){let i=e._reader.requestSlice(t,Fn);if(i instanceof Promise&&(i=await i),!i)break;const r=Nn(i);if(!r)break;t=i.filePos+r.size}let i=e._reader.requestSliceRange(t,7,9);if(i instanceof Promise&&(i=await i),!i)return!1;const r=Ir(i);if(!r)return!1;if(t+=r.frameLength,i=e._reader.requestSliceRange(t,7,9),i instanceof Promise&&(i=await i),!i)return!1;const a=Ir(i);return!!a&&(r.objectType===a.objectType&&r.samplingFrequencyIndex===a.samplingFrequencyIndex&&r.channelConfiguration===a.channelConfiguration)}_createDemuxer(e){return new Cr(e)}get name(){return"ADTS"}get mimeType(){return"audio/aac"}}class Ka extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,205);if(t instanceof Promise&&(t=await t),!t)return!1;const i=ln(t,205);return 71===i[0]&&71===i[188]||(71===i[0]&&71===i[204]||71===i[4]&&71===i[196])}_createDemuxer(e){return new Mr(e)}get name(){return"MPEG Transport Stream"}get mimeType(){return"video/MP2T"}}class ja extends Da{async _canReadInput(e){let t=e._reader.requestSlice(0,7);if(t instanceof Promise&&(t=await t),!t)return!1;if(!("#EXTM3U"===In(t,7)))return!1;if(!(e._rootSource instanceof da))throw new TypeError("HLS inputs require `InputOptions.source` to be a PathedSource or a ref to one.");return e._rootSource._usedForHls=!0,!0}_createDemuxer(e){return new Ca(e)}get name(){return"HTTP Live Streaming (HLS)"}get mimeType(){return Hr}}const Xa=new Na,$a=new Oa,Qa=new La,Ga=new za,Ya=new Ua,Ja=new qa,Za=new Wa,es=new Ha,ts=new Va,is=new Ka,rs=new ja,as=[rs,Xa,$a,Qa,Ga,Ja,Za,ts,Ya,es,is],ss=[rs,Xa,$a,Ya,es,is];te();let ns=-1/0,os=-1/0,cs=null;"undefined"!==typeof FinalizationRegistry&&(cs=new FinalizationRegistry(e=>{const t=performance.now();"video"===e.type?(t-ns>=1e3&&(console.error("A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them."),ns=t),"undefined"!==typeof VideoFrame&&e.data instanceof VideoFrame&&e.data.close()):(t-os>=1e3&&(console.error("An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them."),os=t),"undefined"!==typeof AudioData&&e.data instanceof AudioData&&e.data.close())}));const ls=["I420","I420P10","I420P12","I420A","I420AP10","I420AP12","I422","I422P10","I422P12","I422A","I422AP10","I422AP12","I444","I444P10","I444P12","I444A","I444AP10","I444AP12","NV12","RGBA","RGBX","BGRA","BGRX"],us=new Set(ls);class ds{get codedWidth(){return this.visibleRect.width}get codedHeight(){return this.visibleRect.height}get displayWidth(){return this.rotation%180===0?this.squarePixelWidth:this.squarePixelHeight}get displayHeight(){return this.rotation%180===0?this.squarePixelHeight:this.squarePixelWidth}get microsecondTimestamp(){return Math.trunc(z*this.timestamp)}get microsecondDuration(){return Math.trunc(z*this.duration)}get hasAlpha(){return this.format&&this.format.includes("A")}constructor(e,t){if(this._closed=!1,e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e)){if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0===t.format||!us.has(t.format))throw new TypeError("init.format must be one of: "+ls.join(", "));if(!Number.isInteger(t.codedWidth)||t.codedWidth<=0)throw new TypeError("init.codedWidth must be a positive integer.");if(!Number.isInteger(t.codedHeight)||t.codedHeight<=0)throw new TypeError("init.codedHeight must be a positive integer.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if(void 0!==t.layout){if(!Array.isArray(t.layout))throw new TypeError("init.layout, when provided, must be an array.");for(const e of t.layout){if(!e||"object"!==typeof e||Array.isArray(e))throw new TypeError("Each entry in init.layout must be an object.");if(!Number.isInteger(e.offset)||e.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(e.stride)||e.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==t.visibleRect&&oe(t.visibleRect,"init.visibleRect"),void 0!==t.displayWidth&&(!Number.isInteger(t.displayWidth)||t.displayWidth<=0))throw new TypeError("init.displayWidth, when provided, must be a positive integer.");if(void 0!==t.displayHeight&&(!Number.isInteger(t.displayHeight)||t.displayHeight<=0))throw new TypeError("init.displayHeight, when provided, must be a positive integer.");if(void 0!==t.displayWidth!==(void 0!==t.displayHeight))throw new TypeError("init.displayWidth and init.displayHeight must be either both provided or both omitted.");this._data=o(e).slice(),this._layout=t.layout??ks(t.format,t.codedWidth,t.codedHeight),this.format=t.format,this.rotation=t.rotation??0,this.timestamp=t.timestamp,this.duration=t.duration??0,this.colorSpace=new hs(t.colorSpace),this.visibleRect={left:t.visibleRect?.left??0,top:t.visibleRect?.top??0,width:t.visibleRect?.width??t.codedWidth,height:t.visibleRect?.height??t.codedHeight},void 0!==t.displayWidth?(this.squarePixelWidth=this.rotation%180===0?t.displayWidth:t.displayHeight,this.squarePixelHeight=this.rotation%180===0?t.displayHeight:t.displayWidth):(this.squarePixelWidth=this.codedWidth,this.squarePixelHeight=this.codedHeight)}else if("undefined"!==typeof VideoFrame&&e instanceof VideoFrame){if(void 0!==t?.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(void 0!==t?.timestamp&&!Number.isFinite(t?.timestamp))throw new TypeError("init.timestamp, when provided, must be a number.");if(void 0!==t?.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");void 0!==t?.visibleRect&&oe(t.visibleRect,"init.visibleRect"),this._data=e,this._layout=null,this.format=e.format,this.visibleRect={left:e.visibleRect?.x??0,top:e.visibleRect?.y??0,width:e.visibleRect?.width??e.codedWidth,height:e.visibleRect?.height??e.codedHeight},this.rotation=t?.rotation??0,this.squarePixelWidth=e.displayWidth,this.squarePixelHeight=e.displayHeight,this.timestamp=t?.timestamp??e.timestamp/1e6,this.duration=t?.duration??(e.duration??0)/1e6,this.colorSpace=new hs(e.colorSpace)}else{if(!("undefined"!==typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!==typeof SVGImageElement&&e instanceof SVGImageElement||"undefined"!==typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!==typeof HTMLVideoElement&&e instanceof HTMLVideoElement||"undefined"!==typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!==typeof OffscreenCanvas&&e instanceof OffscreenCanvas))throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource.");{if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if("undefined"!==typeof VideoFrame)return new ds(new VideoFrame(e,{timestamp:Math.trunc(t.timestamp*z),duration:Math.trunc((t.duration??0)*z)||void 0}),t);let r=0,a=0;if("naturalWidth"in e?(r=e.naturalWidth,a=e.naturalHeight):"videoWidth"in e?(r=e.videoWidth,a=e.videoHeight):"width"in e&&(r=Number(e.width),a=Number(e.height)),!r||!a)throw new TypeError("Could not determine dimensions.");const s=new OffscreenCanvas(r,a),n=s.getContext("2d",{alpha:X(),willReadFrequently:!0});i(n),n.drawImage(e,0,0),this._data=s,this._layout=null,this.format="RGBX",this.visibleRect={left:0,top:0,width:r,height:a},this.squarePixelWidth=r,this.squarePixelHeight=a,this.rotation=t.rotation??0,this.timestamp=t.timestamp,this.duration=t.duration??0,this.colorSpace=new hs({matrix:"rgb",primaries:"bt709",transfer:"iec61966-2-1",fullRange:!0})}}this.pixelAspectRatio=ne({num:this.squarePixelWidth*this.codedHeight,den:this.squarePixelHeight*this.codedWidth}),cs?.register(this,{type:"video",data:this._data},this)}clone(){if(this._closed)throw new Error("VideoSample is closed.");return i(null!==this._data),fs(this._data)?new ds(this._data.clone(),{timestamp:this.timestamp,duration:this.duration,rotation:this.rotation}):this._data instanceof Uint8Array?(i(this._layout),new ds(this._data,{format:this.format,layout:this._layout,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation,visibleRect:this.visibleRect,displayWidth:this.displayWidth,displayHeight:this.displayHeight})):new ds(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation,visibleRect:this.visibleRect,displayWidth:this.displayWidth,displayHeight:this.displayHeight})}close(){this._closed||(cs?.unregister(this),fs(this._data)?this._data.close():this._data=null,this._closed=!0)}allocationSize(e={}){if(gs(e),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot get allocation size when format is null. Sorry!");if(i(null!==this._data),!fs(this._data)&&(e.colorSpace||e.format&&e.format!==this.format||e.layout||e.rect)){const t=this.toVideoFrame(),i=t.allocationSize(e);return t.close(),i}return fs(this._data)?this._data.allocationSize(e):this._data instanceof Uint8Array?this._data.byteLength:this.codedWidth*this.codedHeight*4}async copyTo(e,t={}){if(!k(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(gs(t),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot copy video sample data when format is null. Sorry!");if(i(null!==this._data),!fs(this._data)&&(t.colorSpace||t.format&&t.format!==this.format||t.layout||t.rect)){const i=this.toVideoFrame(),r=await i.copyTo(e,t);return i.close(),r}if(fs(this._data))return this._data.copyTo(e,t);if(this._data instanceof Uint8Array){i(this._layout);return o(e).set(this._data),this._layout}{const t=this._data.getContext("2d");i(t);const r=t.getImageData(0,0,this.codedWidth,this.codedHeight);return o(e).set(r.data),[{offset:0,stride:4*this.codedWidth}]}}toVideoFrame(){if(this._closed)throw new Error("VideoSample is closed.");return i(null!==this._data),fs(this._data)?new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0}):this._data instanceof Uint8Array?new VideoFrame(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0,colorSpace:this.colorSpace}):new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0})}draw(e,t,i,r,a,s,n,o,c){let l=0,u=0,d=this.displayWidth,h=this.displayHeight,f=0,m=0,p=this.displayWidth,g=this.displayHeight;if(void 0!==s?(l=t,u=i,d=r,h=a,f=s,m=n,void 0!==o?(p=o,g=c):(p=d,g=h)):(f=t,m=i,void 0!==r&&(p=r,g=a)),!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!Number.isFinite(l))throw new TypeError("sx must be a number.");if(!Number.isFinite(u))throw new TypeError("sy must be a number.");if(!Number.isFinite(d)||d<0)throw new TypeError("sWidth must be a non-negative number.");if(!Number.isFinite(h)||h<0)throw new TypeError("sHeight must be a non-negative number.");if(!Number.isFinite(f))throw new TypeError("dx must be a number.");if(!Number.isFinite(m))throw new TypeError("dy must be a number.");if(!Number.isFinite(p)||p<0)throw new TypeError("dWidth must be a non-negative number.");if(!Number.isFinite(g)||g<0)throw new TypeError("dHeight must be a non-negative number.");if(this._closed)throw new Error("VideoSample is closed.");({sx:l,sy:u,sWidth:d,sHeight:h}=this._rotateSourceRegion(l,u,d,h,this.rotation));const k=this.toCanvasImageSource();e.save();const b=f+p/2,y=m+g/2;e.translate(b,y),e.rotate(this.rotation*Math.PI/180);const w=this.rotation%180===0?1:p/g;e.scale(1/w,w),e.drawImage(k,l,u,d,h,-p/2,-g/2,p,g),e.restore()}drawWithFit(e,t){if(!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!["fill","contain","cover"].includes(t.fit))throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270.");void 0!==t.crop&&ps(t.crop,"options.");const i=e.canvas.width,r=e.canvas.height,a=t.rotation??this.rotation,[s,n]=a%180===0?[this.squarePixelWidth,this.squarePixelHeight]:[this.squarePixelHeight,this.squarePixelWidth];let o,c,l,u;t.crop&&ms(t.crop,s,n);const{sx:d,sy:h,sWidth:f,sHeight:m}=this._rotateSourceRegion(t.crop?.left??0,t.crop?.top??0,t.crop?.width??s,t.crop?.height??n,a);if("fill"===t.fit)o=0,c=0,l=i,u=r;else{const[e,a]=t.crop?[t.crop.width,t.crop.height]:[s,n],d="contain"===t.fit?Math.min(i/e,r/a):Math.max(i/e,r/a);l=e*d,u=a*d,o=(i-l)/2,c=(r-u)/2}e.save();const p=a%180===0?1:l/u;e.translate(i/2,r/2),e.rotate(a*Math.PI/180),e.scale(1/p,p),e.translate(-i/2,-r/2),e.drawImage(this.toCanvasImageSource(),d,h,f,m,o,c,l,u),e.restore()}_rotateSourceRegion(e,t,i,r,a){return 90===a?[e,t,i,r]=[t,this.squarePixelHeight-e-i,r,i]:180===a?[e,t]=[this.squarePixelWidth-e-i,this.squarePixelHeight-t-r]:270===a&&([e,t,i,r]=[this.squarePixelWidth-t-r,e,r,i]),{sx:e,sy:t,sWidth:i,sHeight:r}}toCanvasImageSource(){if(this._closed)throw new Error("VideoSample is closed.");if(i(null!==this._data),this._data instanceof Uint8Array){const e=this.toVideoFrame();return queueMicrotask(()=>e.close()),e}return this._data}setRotation(e){if(![0,90,180,270].includes(e))throw new TypeError("newRotation must be 0, 90, 180, or 270.");this.rotation=e}setTimestamp(e){if(!Number.isFinite(e))throw new TypeError("newTimestamp must be a number.");this.timestamp=e}setDuration(e){if(!Number.isFinite(e)||e<0)throw new TypeError("newDuration must be a non-negative number.");this.duration=e}[Symbol.dispose](){this.close()}}class hs{constructor(e){if(void 0!==e){if(!e||"object"!==typeof e)throw new TypeError("init.colorSpace, when provided, must be an object.");const t=Object.keys(d);if(null!=e.primaries&&!t.includes(e.primaries))throw new TypeError(`init.colorSpace.primaries, when provided, must be one of ${t.join(", ")}.`);const i=Object.keys(f);if(null!=e.transfer&&!i.includes(e.transfer))throw new TypeError(`init.colorSpace.transfer, when provided, must be one of ${i.join(", ")}.`);const r=Object.keys(p);if(null!=e.matrix&&!r.includes(e.matrix))throw new TypeError(`init.colorSpace.matrix, when provided, must be one of ${r.join(", ")}.`);if(null!=e.fullRange&&"boolean"!==typeof e.fullRange)throw new TypeError("init.colorSpace.fullRange, when provided, must be a boolean.")}this.primaries=e?.primaries??null,this.transfer=e?.transfer??null,this.matrix=e?.matrix??null,this.fullRange=e?.fullRange??null}toJSON(){return{primaries:this.primaries,transfer:this.transfer,matrix:this.matrix,fullRange:this.fullRange}}}const fs=e=>"undefined"!==typeof VideoFrame&&e instanceof VideoFrame,ms=(e,t,r)=>{const a=Math.min(e.left,t),s=Math.min(e.top,r),n=Math.min(e.width,t-a),o=Math.min(e.height,r-s);return i(n>=0),i(o>=0),{left:a,top:s,width:n,height:o}},ps=(e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(t+"crop, when provided, must be an object.");if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(t+"crop.left must be a non-negative integer.");if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(t+"crop.top must be a non-negative integer.");if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(t+"crop.width must be a non-negative integer.");if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(t+"crop.height must be a non-negative integer.")},gs=e=>{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.colorSpace&&!["display-p3","srgb"].includes(e.colorSpace))throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");if(void 0!==e.format&&"string"!==typeof e.format)throw new TypeError("options.format, when provided, must be a string.");if(void 0!==e.layout){if(!Array.isArray(e.layout))throw new TypeError("options.layout, when provided, must be an array.");for(const t of e.layout){if(!t||"object"!==typeof t)throw new TypeError("Each entry in options.layout must be an object.");if(!Number.isInteger(t.offset)||t.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(t.stride)||t.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==e.rect){if(!e.rect||"object"!==typeof e.rect)throw new TypeError("options.rect, when provided, must be an object.");if(void 0!==e.rect.x&&(!Number.isInteger(e.rect.x)||e.rect.x<0))throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");if(void 0!==e.rect.y&&(!Number.isInteger(e.rect.y)||e.rect.y<0))throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");if(void 0!==e.rect.width&&(!Number.isInteger(e.rect.width)||e.rect.width<0))throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");if(void 0!==e.rect.height&&(!Number.isInteger(e.rect.height)||e.rect.height<0))throw new TypeError("options.rect.height, when provided, must be a non-negative integer.")}},ks=(e,t,i)=>{const r=bs(e),a=[];let s=0;for(const n of r){const e=Math.ceil(t/n.widthDivisor),r=Math.ceil(i/n.heightDivisor),o=e*n.sampleBytes,c=o*r;a.push({offset:s,stride:o}),s+=c}return a},bs=e=>{const t=(e,t,i,r,a)=>{const s=[{sampleBytes:e,widthDivisor:1,heightDivisor:1},{sampleBytes:t,widthDivisor:i,heightDivisor:r},{sampleBytes:t,widthDivisor:i,heightDivisor:r}];return a&&s.push({sampleBytes:e,widthDivisor:1,heightDivisor:1}),s};switch(e){case"I420":return t(1,1,2,2,!1);case"I420P10":case"I420P12":return t(2,2,2,2,!1);case"I420A":return t(1,1,2,2,!0);case"I420AP10":case"I420AP12":return t(2,2,2,2,!0);case"I422":return t(1,1,2,1,!1);case"I422P10":case"I422P12":return t(2,2,2,1,!1);case"I422A":return t(1,1,2,1,!0);case"I422AP10":case"I422AP12":return t(2,2,2,1,!0);case"I444":return t(1,1,1,1,!1);case"I444P10":case"I444P12":return t(2,2,1,1,!1);case"I444A":return t(1,1,1,1,!0);case"I444AP10":case"I444AP12":return t(2,2,1,1,!0);case"NV12":return[{sampleBytes:1,widthDivisor:1,heightDivisor:1},{sampleBytes:2,widthDivisor:2,heightDivisor:2}];case"RGBA":case"RGBX":case"BGRA":case"BGRX":return[{sampleBytes:4,widthDivisor:1,heightDivisor:1}];default:B(e),i(!1)}},ys=new Set(["f32","f32-planar","s16","s16-planar","s32","s32-planar","u8","u8-planar"]);class ws{get microsecondTimestamp(){return Math.trunc(z*this.timestamp)}get microsecondDuration(){return Math.trunc(z*this.duration)}constructor(e){if(this._closed=!1,Is(e)){if(null===e.format)throw new TypeError("AudioData with null format is not supported.");this._data=e,this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=e.numberOfFrames,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp/1e6,this.duration=e.numberOfFrames/e.sampleRate}else{if(!e||"object"!==typeof e)throw new TypeError("Invalid AudioDataInit: must be an object.");if(!ys.has(e.format))throw new TypeError("Invalid AudioDataInit: invalid format.");if(!Number.isFinite(e.sampleRate)||e.sampleRate<=0)throw new TypeError("Invalid AudioDataInit: sampleRate must be > 0.");if(!Number.isInteger(e.numberOfChannels)||0===e.numberOfChannels)throw new TypeError("Invalid AudioDataInit: numberOfChannels must be an integer > 0.");if(!Number.isFinite(e?.timestamp))throw new TypeError("init.timestamp must be a number.");const t=e.data.byteLength/(Ts(e.format)*e.numberOfChannels);if(!Number.isInteger(t))throw new TypeError("Invalid AudioDataInit: data size is not a multiple of frame size.");let i;if(this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=t,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp,this.duration=t/e.sampleRate,e.data instanceof ArrayBuffer)i=new Uint8Array(e.data);else{if(!ArrayBuffer.isView(e.data))throw new TypeError("Invalid AudioDataInit: data is not a BufferSource.");i=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength)}const r=this.numberOfFrames*this.numberOfChannels*Ts(this.format);if(i.byteLength=this.numberOfFrames)throw new RangeError("frameOffset out of range");const r=void 0!==e.frameCount?e.frameCount:this.numberOfFrames-i;if(r>this.numberOfFrames-i)throw new RangeError("frameCount out of range");const a=Ts(t),s=Ss(t);if(s&&e.planeIndex>=this.numberOfChannels)throw new RangeError("planeIndex out of range");if(!s&&0!==e.planeIndex)throw new RangeError("planeIndex out of range");return(s?r:r*this.numberOfChannels)*a}copyTo(e,t){if(!k(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!Number.isInteger(t.planeIndex)||t.planeIndex<0)throw new TypeError("planeIndex must be a non-negative integer.");if(void 0!==t.format&&!ys.has(t.format))throw new TypeError("Invalid format.");if(void 0!==t.frameOffset&&(!Number.isInteger(t.frameOffset)||t.frameOffset<0))throw new TypeError("frameOffset must be a non-negative integer.");if(void 0!==t.frameCount&&(!Number.isInteger(t.frameCount)||t.frameCount<0))throw new TypeError("frameCount must be a non-negative integer.");if(this._closed)throw new Error("AudioSample is closed.");const{planeIndex:i,format:r,frameCount:a,frameOffset:s}=t,n=this.format,o=r??this.format;if(!o)throw new Error("Destination format not determined");const l=this.numberOfFrames,u=this.numberOfChannels,d=s??0;if(d>=l)throw new RangeError("frameOffset out of range");const h=void 0!==a?a:l-d;if(h>l-d)throw new RangeError("frameCount out of range");const f=Ts(o),m=Ss(o);if(m&&i>=u)throw new RangeError("planeIndex out of range");if(!m&&0!==i)throw new RangeError("planeIndex out of range");const p=(m?h:h*u)*f;if(e.byteLength2&&o!==n?xs(this._data,g,n,o,u,i,d,h):this._data.copyTo(e,{planeIndex:i,frameOffset:d,frameCount:h,format:o});else{const e=this._data,t=c(e),r=Ps(n),a=Ts(n),s=Ss(n);for(let n=0;n0;){const a=Math.min(s,o),c=new Float32Array(i*a);for(let t=0;t0;){const a=Math.min(s,o),l=new Float32Array(i*a);for(let t=0;t{switch(e){case"u8":case"u8-planar":return 1;case"s16":case"s16-planar":return 2;case"s32":case"s32-planar":case"f32":case"f32-planar":return 4;default:throw new Error("Unknown AudioSampleFormat")}},Ss=e=>{switch(e){case"u8-planar":case"s16-planar":case"s32-planar":case"f32-planar":return!0;default:return!1}},Ps=e=>{switch(e){case"u8":case"u8-planar":return(e,t)=>(e.getUint8(t)-128)/128;case"s16":case"s16-planar":return(e,t)=>e.getInt16(t,!0)/32768;case"s32":case"s32-planar":return(e,t)=>e.getInt32(t,!0)/2147483648;case"f32":case"f32-planar":return(e,t)=>e.getFloat32(t,!0)}},vs=e=>{switch(e){case"u8":case"u8-planar":return(e,t,i)=>e.setUint8(t,F(127.5*(i+1),0,255));case"s16":case"s16-planar":return(e,t,i)=>e.setInt16(t,F(Math.round(32767*i),-32768,32767),!0);case"s32":case"s32-planar":return(e,t,i)=>e.setInt32(t,F(Math.round(2147483647*i),-2147483648,2147483647),!0);case"f32":case"f32-planar":return(e,t,i)=>e.setFloat32(t,i,!0)}},Is=e=>"undefined"!==typeof AudioData&&e instanceof AudioData,xs=(e,t,i,r,a,s,n,o)=>{const l=Ps(i),u=vs(r),d=Ts(i),h=Ts(r),f=Ss(i);if(Ss(r))if(f){const r=new ArrayBuffer(o*d),a=c(r);e.copyTo(r,{planeIndex:s,frameOffset:n,frameCount:o,format:i});for(let e=0;e{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.metadataOnly&&"boolean"!==typeof e.metadataOnly)throw new TypeError("options.metadataOnly, when defined, must be a boolean.");if(void 0!==e.verifyKeyPackets&&"boolean"!==typeof e.verifyKeyPackets)throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");if(e.verifyKeyPackets&&e.metadataOnly)throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.");if(void 0!==e.skipLiveWait&&"boolean"!==typeof e.skipLiveWait)throw new TypeError("options.skipLiveWait, when defined, must be a boolean.")},_s=e=>{if(!ie(e))throw new TypeError("timestamp must be a number.")},As=(e,t,i)=>i.verifyKeyPackets?t.then(async t=>{if(!t||"delta"===t.type)return t;const i=await e.determinePacketType(t);return i&&(t.type=i),t}):t;class Fs{constructor(e){if(!(e instanceof Hs))throw new TypeError("track must be an InputTrack.");this._track=e}async getFirstPacket(e={}){if(Es(e),this._track.input._disposed)throw new sn;return As(this._track,this._track._backing.getFirstPacket(e),e)}async getFirstKeyPacket(e={}){Es(e);const t=await this.getFirstPacket(e);return t?"key"===t.type?t:this.getNextKeyPacket(t,e):null}async getPacket(e,t={}){if(_s(e),Es(t),this._track.input._disposed)throw new sn;return As(this._track,this._track._backing.getPacket(e,t),t)}async getNextPacket(e,t={}){if(!(e instanceof Mt))throw new TypeError("packet must be an EncodedPacket.");if(Es(t),this._track.input._disposed)throw new sn;return As(this._track,this._track._backing.getNextPacket(e,t),t)}async getKeyPacket(e,t={}){if(_s(e),Es(t),this._track.input._disposed)throw new sn;if(!t.verifyKeyPackets)return this._track._backing.getKeyPacket(e,t);const r=await this._track._backing.getKeyPacket(e,t);if(!r)return r;i("key"===r.type);return"delta"===await this._track.determinePacketType(r)?this.getKeyPacket(r.timestamp-1/await this._track.getTimeResolution(),t):r}async getNextKeyPacket(e,t={}){if(!(e instanceof Mt))throw new TypeError("packet must be an EncodedPacket.");if(Es(t),this._track.input._disposed)throw new sn;if(!t.verifyKeyPackets)return this._track._backing.getNextKeyPacket(e,t);const r=await this._track._backing.getNextKeyPacket(e,t);if(!r)return r;i("key"===r.type);return"delta"===await this._track.determinePacketType(r)?this.getNextKeyPacket(r,t):r}packets(e,t,i={}){if(void 0!==e&&!(e instanceof Mt))throw new TypeError("startPacket must be an EncodedPacket.");if(void 0!==e&&e.isMetadataOnly&&!i?.metadataOnly)throw new TypeError("startPacket can only be metadata-only if options.metadataOnly is enabled.");if(void 0!==t&&!(t instanceof Mt))throw new TypeError("endPacket must be an EncodedPacket.");if(Es(i),this._track.input._disposed)throw new sn;const r=[];let{promise:a,resolve:s}=I(),{promise:n,resolve:o}=I(),c=!1,l=!1,u=null;const d=[],h=()=>Math.max(2,d.length);(async()=>{let u=e??await this.getFirstPacket(i);for(;u&&!l&&!this._track.input._disposed&&!(t&&u.sequenceNumber>=t?.sequenceNumber);)r.length>h()?(({promise:n,resolve:o}=I()),await n):(r.push(u),s(),({promise:a,resolve:s}=I()),u=await this.getNextPacket(u,i));c=!0,s()})().catch(e=>{u||(u=e,s())});const f=this._track;return{async next(){for(;;){if(f.input._disposed)throw new sn;if(l)return{value:void 0,done:!0};if(u)throw u;if(r.length>0){const e=r.shift(),t=performance.now();for(d.push(t);d.length>0&&t-d[0]>=1e3;)d.shift();return o(),{value:e,done:!1}}if(c)return{value:void 0,done:!0};await a}},return:async()=>(l=!0,o(),s(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}}class Rs{constructor(e,t){this.onSample=e,this.onError=t}}class Ds{mediaSamplesInRange(e=0,t=1/0,i){_s(e),_s(t);const r=[];let a=!1,s=null,{promise:n,resolve:o}=I(),{promise:c,resolve:l}=I(),u=!1,d=!1,h=!1,f=null;const m={...i,verifyKeyPackets:!0,metadataOnly:!1};(async()=>{const i=await this._createDecoder(i=>{l(),i.timestamp>=t&&(d=!0),d?i.close():(s&&(i.timestamp>e?(r.push(s),a=!0):s.close()),i.timestamp>=e&&(r.push(i),a=!0),s=a?null:i,r.length>0&&(o(),({promise:n,resolve:o}=I())))},e=>{f||(f=e,o())}),p=this._createPacketSink(),g=await p.getKeyPacket(e,m)??await p.getFirstKeyPacket(m);let k=g;const b=p.packets(g??void 0,void 0,m);for(await b.next();k&&!d&&!this._track.input._disposed;){const e=Ms(r.length);if(r.length+i.getDecodeQueueSize()>e){({promise:c,resolve:l}=I()),await c;continue}i.decode(k);const t=await b.next();if(t.done)break;k=t.value}await b.return(),h||this._track.input._disposed||await i.flush(),i.close(),!a&&s&&r.push(s),u=!0,o()})().catch(e=>{f||(f=e,o())});const p=this._track,g=()=>{s?.close();for(const e of r)e.close()};return{async next(){for(;;){if(p.input._disposed)throw g(),new sn;if(h)return{value:void 0,done:!0};if(f)throw g(),f;if(r.length>0){const e=r.shift();return l(),{value:e,done:!1}}if(u)return{value:void 0,done:!0};await n}},return:async()=>(h=!0,d=!0,l(),o(),g(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}mediaSamplesAtTimestamps(e,t){(e=>{if(!(Symbol.iterator in e)&&!(Symbol.asyncIterator in e))throw new TypeError("Argument must be an iterable or async iterable.")})(e);const r=async function*(e){Symbol.iterator in e?yield*e[Symbol.iterator]():yield*e[Symbol.asyncIterator]()}(e),a=[],s=[];let{promise:n,resolve:o}=I(),{promise:c,resolve:l}=I(),u=!1,d=!1,h=null;const f=e=>{s.push(e),o(),({promise:n,resolve:o}=I())},m={...t,verifyKeyPackets:!0,metadataOnly:!1};(async()=>{const e=await this._createDecoder(e=>{if(l(),d)return void e.close();let t=0;for(;a.length>0&&e.timestamp-a[0]>-1e-10;)t++,a.shift();if(t>0)for(let i=0;i{h||(h=e,o())}),t=this._createPacketSink();let n=null,p=null,g=-1;const k=async()=>{i(p);let r=p;for(e.decode(r);r.sequenceNumbera&&!d;)({promise:c,resolve:l}=I()),await c;if(d)break;const n=await t.getNextPacket(r,m);i(n),e.decode(n),r=n}g=-1},b=async()=>{await e.flush();for(let e=0;e{h||(h=e,o())});const p=this._track,g=()=>{for(const e of s)e?.close()};return{async next(){for(;;){if(p.input._disposed)throw g(),new sn;if(d)return{value:void 0,done:!0};if(h)throw g(),h;if(s.length>0){const e=s.shift();return i(void 0!==e),l(),{value:e,done:!1}}if(u)return{value:void 0,done:!0};await n}},return:async()=>(d=!0,l(),o(),g(),{value:void 0,done:!0}),async throw(e){throw e},[Symbol.asyncIterator](){return this}}}}const Ms=e=>0===e?40:8;class Ns extends Rs{constructor(e,t,r,a,s,n){super(e,t),this.codec=r,this.decoderConfig=a,this.rotation=s,this.timeResolution=n,this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new V,this.customDecoderQueueSize=0,this.inputTimestamps=[],this.sampleQueue=[],this.currentPacketIndex=0,this.raslSkipped=!1,this.alphaDecoder=null,this.alphaHadKeyframe=!1,this.colorQueue=[],this.alphaQueue=[],this.merger=null,this.mergerCreationFailed=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue=[],this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1;const l=Cs.find(e=>e.supports(r,a));if(l)this.customDecoder=new l,this.customDecoder.codec=r,this.customDecoder.config=a,this.customDecoder.onSample=e=>{if(!(e instanceof ds))throw new TypeError("The argument passed to onSample must be a VideoSample.");this.finalizeAndEmitSample(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=e=>{if(this.alphaQueue.length>0){const t=this.alphaQueue.shift();i(void 0!==t),this.mergeAlpha(e,t)}else this.colorQueue.push(e)};if("avc"===r&&this.decoderConfig.description&&Q()){const e=(e=>{try{const t=c(e);let i=0;const r=t.getUint8(i++),a=t.getUint8(i++),s=t.getUint8(i++),n=t.getUint8(i++),o=3&t.getUint8(i++),l=31&t.getUint8(i++),u=[];for(let c=0;c0){const t=tt(e.sequenceParameterSets[0]);t&&0===t.frameMbsOnlyFlag&&(this.decoderConfig={...this.decoderConfig,hardwareAcceleration:"prefer-software"})}}const t=new Error("Decoding error").stack;this.decoder=new VideoDecoder({output:t=>{try{e(t)}catch(i){this.onError(i)}},error:e=>{e.stack=t,this.onError(e)}}),this.decoder.configure(this.decoderConfig)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(i(this.decoder),Math.max(this.decoder.decodeQueueSize,this.alphaDecoder?.decodeQueueSize??0))}decode(e){if("hevc"===this.codec&&this.currentPacketIndex>0&&!this.raslSkipped){if(this.hasHevcRaslPicture(e.data))return;this.raslSkipped=!0}if(this.customDecoder)this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--);else{if(i(this.decoder),K()||v(this.inputTimestamps,e.timestamp,e=>e),Q()&&0===this.currentPacketIndex)if("avc"===this.codec){const t=[];for(const r of Xe(e.data,this.decoderConfig)){const i=$e(e.data[r.offset]);i>=20&&i<=31||t.push(e.data.subarray(r.offset,r.offset+r.length))}const i=((e,t)=>{if(t.description){const i=3&o(t.description)[4];return Je(e,i+1)}return Ye(e)})(t,this.decoderConfig);e=new Mt(i,e.type,e.timestamp,e.duration)}else if("hevc"===this.codec){const t=gt(e.data,this.decoderConfig);t&&(e=new Mt(t,e.type,e.timestamp,e.duration))}this.decoder.decode(e.toEncodedVideoChunk()),this.decodeAlphaData(e)}this.currentPacketIndex++}decodeAlphaData(e){if(!e.sideData.alpha||this.mergerCreationFailed)return void this.pushNullAlphaFrame();if(!this.merger)try{this.merger=new Os}catch(r){return console.error("Due to an error, only color data will be decoded.",r),this.mergerCreationFailed=!0,void this.decodeAlphaData(e)}if(!this.alphaDecoder){const e=e=>{if(this.alphaDecoderQueueSize--,this.colorQueue.length>0){const t=this.colorQueue.shift();i(void 0!==t),this.mergeAlpha(t,e)}else this.alphaQueue.push(e);for(this.decodedAlphaChunkCount++;this.nullAlphaFrameQueue.length>0&&this.nullAlphaFrameQueue[0]===this.decodedAlphaChunkCount;)if(this.nullAlphaFrameQueue.shift(),this.colorQueue.length>0){const e=this.colorQueue.shift();i(void 0!==e),this.mergeAlpha(e,null)}else this.alphaQueue.push(null)},t=new Error("Decoding error").stack;this.alphaDecoder=new VideoDecoder({output:t=>{try{e(t)}catch(r){this.onError(r)}},error:e=>{e.stack=t,this.onError(e)}}),this.alphaDecoder.configure(this.decoderConfig)}const t=St(this.codec,this.decoderConfig,e.sideData.alpha);if(this.alphaHadKeyframe||(this.alphaHadKeyframe="key"===t),this.alphaHadKeyframe){if("hevc"===this.codec&&this.currentAlphaPacketIndex>0&&!this.alphaRaslSkipped){if(this.hasHevcRaslPicture(e.sideData.alpha))return void this.pushNullAlphaFrame();this.alphaRaslSkipped=!0}this.currentAlphaPacketIndex++,this.alphaDecoder.decode(e.alphaToEncodedVideoChunk(t??e.type)),this.alphaDecoderQueueSize++}else this.pushNullAlphaFrame()}pushNullAlphaFrame(){0===this.alphaDecoderQueueSize?this.alphaQueue.push(null):this.nullAlphaFrameQueue.push(this.decodedAlphaChunkCount+this.alphaDecoderQueueSize)}hasHevcRaslPicture(e){for(const t of rt(e,this.decoderConfig)){const i=at(e[t.offset]);if(i===Ve.RASL_N||i===Ve.RASL_R)return!0}return!1}sampleHandler(e){if(K()){if(this.sampleQueue.length>0&&e.timestamp>=a(this.sampleQueue).timestamp){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}v(this.sampleQueue,e,e=>e.timestamp)}else{const t=this.inputTimestamps.shift();i(void 0!==t),e.setTimestamp(t),this.finalizeAndEmitSample(e)}}finalizeAndEmitSample(e){e.setTimestamp(Math.round(e.timestamp*this.timeResolution)/this.timeResolution),e.setDuration(Math.round(e.duration*this.timeResolution)/this.timeResolution),e.setRotation(this.rotation),this.onSample(e)}mergeAlpha(e,t){if(!t){const t=new ds(e);return void this.sampleHandler(t)}i(this.merger),this.merger.update(e,t),e.close(),t.close();const r=new VideoFrame(this.merger.canvas,{timestamp:e.timestamp,duration:e.duration??void 0}),a=new ds(r);this.sampleHandler(a)}async flush(){if(this.customDecoder?await this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(i(this.decoder),await Promise.all([this.decoder.flush(),this.alphaDecoder?.flush()]),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>e?.close()),this.alphaQueue.length=0,this.alphaHadKeyframe=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue.length=0,this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1),K()){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}this.currentPacketIndex=0,this.raslSkipped=!1}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(i(this.decoder),this.decoder.close(),this.alphaDecoder?.close(),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>e?.close()),this.alphaQueue.length=0,this.merger?.close());for(const e of this.sampleQueue)e.close();this.sampleQueue.length=0}}class Os{constructor(){"undefined"!==typeof OffscreenCanvas?this.canvas=new OffscreenCanvas(300,150):this.canvas=document.createElement("canvas");const e=this.canvas.getContext("webgl2",{premultipliedAlpha:!1});if(!e)throw new Error("Couldn't acquire WebGL 2 context.");this.gl=e,this.program=this.createProgram(),this.vao=this.createVAO(),this.colorTexture=this.createTexture(),this.alphaTexture=this.createTexture(),this.gl.useProgram(this.program),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_colorTexture"),0),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_alphaTexture"),1)}createProgram(){const e=this.createShader(this.gl.VERTEX_SHADER,"#version 300 es\n\t\t\tin vec2 a_position;\n\t\t\tin vec2 a_texCoord;\n\t\t\tout vec2 v_texCoord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = vec4(a_position, 0.0, 1.0);\n\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t}\n\t\t"),t=this.createShader(this.gl.FRAGMENT_SHADER,"#version 300 es\n\t\t\tprecision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_colorTexture;\n\t\t\tuniform sampler2D u_alphaTexture;\n\t\t\tin vec2 v_texCoord;\n\t\t\tout vec4 fragColor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture(u_colorTexture, v_texCoord).rgb;\n\t\t\t\tfloat alpha = texture(u_alphaTexture, v_texCoord).r;\n\t\t\t\tfragColor = vec4(color, alpha);\n\t\t\t}\n\t\t"),i=this.gl.createProgram();return this.gl.attachShader(i,e),this.gl.attachShader(i,t),this.gl.linkProgram(i),i}createShader(e,t){const i=this.gl.createShader(e);return this.gl.shaderSource(i,t),this.gl.compileShader(i),i}createVAO(){const e=this.gl.createVertexArray();this.gl.bindVertexArray(e);const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,i),this.gl.bufferData(this.gl.ARRAY_BUFFER,t,this.gl.STATIC_DRAW);const r=this.gl.getAttribLocation(this.program,"a_position"),a=this.gl.getAttribLocation(this.program,"a_texCoord");return this.gl.enableVertexAttribArray(r),this.gl.vertexAttribPointer(r,2,this.gl.FLOAT,!1,16,0),this.gl.enableVertexAttribArray(a),this.gl.vertexAttribPointer(a,2,this.gl.FLOAT,!1,16,8),e}createTexture(){const e=this.gl.createTexture();return this.gl.bindTexture(this.gl.TEXTURE_2D,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),e}update(e,t){e.displayWidth===this.canvas.width&&e.displayHeight===this.canvas.height||(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colorTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),this.gl.activeTexture(this.gl.TEXTURE1),this.gl.bindTexture(this.gl.TEXTURE_2D,this.alphaTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.bindVertexArray(this.vao),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)}close(){this.gl.getExtension("WEBGL_lose_context")?.loseContext(),this.gl=null}}class Ls extends Ds{constructor(e){if(!(e instanceof Xs))throw new TypeError("videoTrack must be an InputVideoTrack.");super(),this._track=e}async _createDecoder(e,t){if(!(await this._track.canDecode()))throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track.");const r=await this._track.getCodec(),a=await this._track.getRotation(),s=await this._track.getDecoderConfig(),n=await this._track.getTimeResolution();return i(r&&s),new Ns(e,t,r,s,a,n)}_createPacketSink(){return new Fs(this._track)}async getSample(e,t={}){_s(e);for await(const i of this.mediaSamplesAtTimestamps([e],t))return i;throw new Error("Internal error: Iterator returned nothing.")}samples(e=0,t=1/0,i={}){return this.mediaSamplesInRange(e,t,i)}samplesAtTimestamps(e,t={}){return this.mediaSamplesAtTimestamps(e,t)}}class zs{constructor(e,t={}){if(this._rotation=0,this._initPromise=null,this._nextCanvasIndex=0,!(e instanceof Xs))throw new TypeError("videoTrack must be an InputVideoTrack.");if(t&&"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.alpha&&"boolean"!==typeof t.alpha)throw new TypeError("options.alpha, when provided, must be a boolean.");if(void 0!==t.width&&(!Number.isInteger(t.width)||t.width<=0))throw new TypeError("options.width, when defined, must be a positive integer.");if(void 0!==t.height&&(!Number.isInteger(t.height)||t.height<=0))throw new TypeError("options.height, when defined, must be a positive integer.");if(void 0!==t.fit&&!["fill","contain","cover"].includes(t.fit))throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".');if(void 0!==t.width&&void 0!==t.height&&void 0===t.fit)throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180 or 270.");if(void 0!==t.crop&&ps(t.crop,"options."),void 0!==t.poolSize&&("number"!==typeof t.poolSize||!Number.isInteger(t.poolSize)||t.poolSize<0))throw new TypeError("poolSize must be a non-negative integer.");this._videoTrack=e,this._alpha=t.alpha??!1,this._options=t,this._fit=t.fit??"fill",this._videoSampleSink=new Ls(e),this._canvasPool=Array.from({length:t.poolSize??0},()=>null)}_ensureInit(){return this._initPromise??(this._initPromise=(async()=>{const e=this._options,t=this._videoTrack,i=e.rotation??await t.getRotation(),r=await t.getSquarePixelWidth(),a=await t.getSquarePixelHeight(),[s,n]=i%180===0?[r,a]:[a,r];let o=e.crop;o&&(o=ms(o,s,n));let[c,l]=o?[o.width,o.height]:[s,n];const u=c/l;void 0!==e.width&&void 0===e.height?(c=e.width,l=Math.round(c/u)):void 0===e.width&&void 0!==e.height?(l=e.height,c=Math.round(l*u)):void 0!==e.width&&void 0!==e.height&&(c=e.width,l=e.height),this._width=c,this._height=l,this._rotation=i,this._crop=o})())}_videoSampleToWrappedCanvas(e){const t=this._width,r=this._height;let a=this._canvasPool[this._nextCanvasIndex],s=!1;a||("undefined"!==typeof document?(a=document.createElement("canvas"),a.width=t,a.height=r):a=new OffscreenCanvas(t,r),this._canvasPool.length>0&&(this._canvasPool[this._nextCanvasIndex]=a),s=!0),this._canvasPool.length>0&&(this._nextCanvasIndex=(this._nextCanvasIndex+1)%this._canvasPool.length);const n=a.getContext("2d",{alpha:this._alpha||X()});i(n),n.resetTransform(),s||(!this._alpha&&X()?(n.fillStyle="black",n.fillRect(0,0,t,r)):n.clearRect(0,0,t,r)),e.drawWithFit(n,{fit:this._fit,rotation:this._rotation,crop:this._crop});const o={canvas:a,timestamp:e.timestamp,duration:e.duration};return e.close(),o}async getCanvas(e,t){_s(e),await this._ensureInit();const i=await this._videoSampleSink.getSample(e,t);return i&&this._videoSampleToWrappedCanvas(i)}async*canvases(e=0,t=1/0,i){await this._ensureInit(),yield*A(this._videoSampleSink.samples(e,t,i),e=>this._videoSampleToWrappedCanvas(e))}async*canvasesAtTimestamps(e,t){await this._ensureInit(),yield*A(this._videoSampleSink.samplesAtTimestamps(e,t),e=>e&&this._videoSampleToWrappedCanvas(e))}}class Us extends Rs{constructor(e,t,i,r){super(e,t),this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new V,this.customDecoderQueueSize=0,this.currentTimestamp=null;const a=t=>{(null===this.currentTimestamp||Math.abs(t.timestamp-this.currentTimestamp)>=t.duration)&&(this.currentTimestamp=t.timestamp);const i=this.currentTimestamp;if(this.currentTimestamp+=t.duration,0===t.numberOfFrames)return void t.close();const a=r.sampleRate;t.setTimestamp(Math.round(i*a)/a),e(t)},s=Bs.find(e=>e.supports(i,r));if(s)this.customDecoder=new s,this.customDecoder.codec=i,this.customDecoder.config=r,this.customDecoder.onSample=e=>{if(!(e instanceof ws))throw new TypeError("The argument passed to onSample must be an AudioSample.");a(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=new Error("Decoding error").stack;this.decoder=new AudioDecoder({output:e=>{try{a(new ws(e))}catch(t){this.onError(t)}},error:t=>{t.stack=e,this.onError(t)}}),this.decoder.configure(r)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(i(this.decoder),this.decoder.decodeQueueSize)}decode(e){this.customDecoder?(this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--)):(i(this.decoder),this.decoder.decode(e.toEncodedAudioChunk()))}flush(){return this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(i(this.decoder),this.decoder.flush())}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(i(this.decoder),this.decoder.close())}}class qs extends Rs{constructor(e,t,r){super(e,t),this.decoderConfig=r,this.currentTimestamp=null,i(be.includes(r.codec)),this.codec=r.codec;const{dataType:a,sampleSize:s,littleEndian:n}=Be(this.codec);switch(this.inputSampleSize=s,s){case 1:"unsigned"===a?this.readInputValue=(e,t)=>e.getUint8(t)-128:"signed"===a?this.readInputValue=(e,t)=>e.getInt8(t):"ulaw"===a?this.readInputValue=(e,t)=>(e=>{let t=0,i=0,r=~e;128&r&&(r&=-129,t=-1),i=5+((240&r)>>4);const a=(1<(e=>{let t=0,i=0,r=85^e;128&r&&(r&=-129,t=-1),i=4+((240&r)>>4);let a=0;return a=4!==i?1<e.getUint16(t,n)-32768:"signed"===a?this.readInputValue=(e,t)=>e.getInt16(t,n):i(!1);break;case 3:"unsigned"===a?this.readInputValue=(e,t)=>E(e,t,n)-2**23:"signed"===a?this.readInputValue=(e,t)=>((e,t,i)=>E(e,t,i)<<8>>8)(e,t,n):i(!1);break;case 4:"unsigned"===a?this.readInputValue=(e,t)=>e.getUint32(t,n)-2**31:"signed"===a?this.readInputValue=(e,t)=>e.getInt32(t,n):"float"===a?this.readInputValue=(e,t)=>e.getFloat32(t,n):i(!1);break;case 8:"float"===a?this.readInputValue=(e,t)=>e.getFloat64(t,n):i(!1);break;default:B(s),i(!1)}switch(s){case 1:"ulaw"===a||"alaw"===a?(this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,i)=>e.setInt16(t,i,!0)):(this.outputSampleSize=1,this.outputFormat="u8",this.writeOutputValue=(e,t,i)=>e.setUint8(t,i+128));break;case 2:this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,i)=>e.setInt16(t,i,!0);break;case 3:this.outputSampleSize=4,this.outputFormat="s32",this.writeOutputValue=(e,t,i)=>e.setInt32(t,i<<8,!0);break;case 4:this.outputSampleSize=4,"float"===a?(this.outputFormat="f32",this.writeOutputValue=(e,t,i)=>e.setFloat32(t,i,!0)):(this.outputFormat="s32",this.writeOutputValue=(e,t,i)=>e.setInt32(t,i,!0));break;case 8:this.outputSampleSize=4,this.outputFormat="f32",this.writeOutputValue=(e,t,i)=>e.setFloat32(t,i,!0);break;default:B(s),i(!1)}}getDecodeQueueSize(){return 0}decode(e){const t=c(e.data),i=e.byteLength/this.decoderConfig.numberOfChannels/this.inputSampleSize,r=i*this.decoderConfig.numberOfChannels*this.outputSampleSize,a=new ArrayBuffer(r),s=new DataView(a);for(let c=0;c=n)&&(this.currentTimestamp=e.timestamp);const o=this.currentTimestamp;this.currentTimestamp+=n;const l=new ws({format:this.outputFormat,data:a,numberOfChannels:this.decoderConfig.numberOfChannels,sampleRate:this.decoderConfig.sampleRate,numberOfFrames:i,timestamp:o});this.onSample(l)}async flush(){}close(){}}class Ws extends Ds{constructor(e){if(!(e instanceof $s))throw new TypeError("audioTrack must be an InputAudioTrack.");super(),this._track=e}async _createDecoder(e,t){if(!(await this._track.canDecode()))throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track.");const r=await this._track.getCodec(),a=await this._track.getDecoderConfig();return i(r&&a),be.includes(a.codec)?new qs(e,t,a):new Us(e,t,r,a)}_createPacketSink(){return new Fs(this._track)}async getSample(e,t={}){_s(e);for await(const i of this.mediaSamplesAtTimestamps([e],t))return i;throw new Error("Internal error: Iterator returned nothing.")}samples(e=0,t=1/0,i={}){return this.mediaSamplesInRange(e,t,i)}samplesAtTimestamps(e,t={}){return this.mediaSamplesAtTimestamps(e,t)}}class Vs{constructor(e){if(!(e instanceof $s))throw new TypeError("audioTrack must be an InputAudioTrack.");this._audioSampleSink=new Ws(e)}_audioSampleToWrappedArrayBuffer(e){const t={buffer:e.toAudioBuffer(),timestamp:e.timestamp,duration:e.duration};return e.close(),t}async getBuffer(e,t){_s(e);const i=await this._audioSampleSink.getSample(e,t);return i&&this._audioSampleToWrappedArrayBuffer(i)}buffers(e=0,t=1/0,i){return A(this._audioSampleSink.samples(e,t,i),e=>this._audioSampleToWrappedArrayBuffer(e))}buffersAtTimestamps(e,t){return A(this._audioSampleSink.samplesAtTimestamps(e,t),e=>e&&this._audioSampleToWrappedArrayBuffer(e))}}class Hs{constructor(e,t){this.input=e,this._backing=t}isVideoTrack(){return this instanceof Xs}isAudioTrack(){return this instanceof $s}get id(){return this._backing.getId()}get number(){return this._backing.getNumber()}async getInternalCodecId(){return this._backing.getInternalCodecId()}get internalCodecId(){return Ks(this._backing.getInternalCodecId(),"internalCodecId","getInternalCodecId")}async getLanguageCode(){return this._backing.getLanguageCode()}get languageCode(){return Ks(this._backing.getLanguageCode(),"languageCode","getLanguageCode")}async getName(){return this._backing.getName()}get name(){return Ks(this._backing.getName(),"name","getName")}async getTimeResolution(){return this._backing.getTimeResolution()}get timeResolution(){return Ks(this._backing.getTimeResolution(),"timeResolution","getTimeResolution")}async isRelativeToUnixEpoch(){return this._backing.isRelativeToUnixEpoch()}async getDisposition(){return this._backing.getDisposition()}get disposition(){return Ks(this._backing.getDisposition(),"disposition","getDisposition")}async getBitrate(){return this._backing.getBitrate()}async getAverageBitrate(){return this._backing.getAverageBitrate()}async getFirstTimestamp(){const e=await this._backing.getFirstPacket({metadataOnly:!0});return e?.timestamp??0}async computeDuration(e){const t=await this._backing.getPacket(1/0,{metadataOnly:!0,...e});return M((t?.timestamp??0)+(t?.duration??0),await this.getTimeResolution())}async getDurationFromMetadata(e={}){return this._backing.getDurationFromMetadata(e)}async computePacketStats(e=1/0,t){const i=new Fs(this);let r=1/0,a=-1/0,s=0,n=0;for await(const o of i.packets(void 0,void 0,{metadataOnly:!0,...t})){if(s>=e&&o.timestamp>=a)break;r=Math.min(r,o.timestamp),a=Math.max(a,o.timestamp+o.duration),s++,n+=o.byteLength}return{packetCount:s,averagePacketRate:s?Number((s/(a-r)).toPrecision(16)):0,averageBitrate:s?Number((8*n/(a-r)).toPrecision(16)):0}}async isLive(){return null!==await this._backing.getLiveRefreshInterval()}async getLiveRefreshInterval(){return this._backing.getLiveRefreshInterval()}canBePairedWith(e){if(!(e instanceof Hs))throw new TypeError("other must be an InputTrack.");return this.input===e.input&&this!==e&&0n!==(this._backing.getPairingMask()&e._backing.getPairingMask())}async getPairableTracks(e){return this.input.getTracks(Js({filter:e=>e.canBePairedWith(this)},e))}async getPairableVideoTracks(e){return this.input.getVideoTracks(Js({filter:e=>e.canBePairedWith(this)},e))}async getPairableAudioTracks(e){return this.input.getAudioTracks(Js({filter:e=>e.canBePairedWith(this)},e))}async getPrimaryPairableVideoTrack(e){return this.input.getPrimaryVideoTrack(Js({filter:e=>e.canBePairedWith(this)},e))}async getPrimaryPairableAudioTrack(e){return this.input.getPrimaryAudioTrack(Js({filter:e=>e.canBePairedWith(this)},e))}async hasPairableTrack(e){e&&(e=js(e));const t=await this.input.getTracks();for(const i of t)if(this.canBePairedWith(i)&&(!e||await e(i)))return!0;return!1}hasPairableVideoTrack(e){return e&&(e=js(e)),this.hasPairableTrack(async t=>t.isVideoTrack()&&(!e||await e(t)))}hasPairableAudioTrack(e){return e&&(e=js(e)),this.hasPairableTrack(async t=>t.isAudioTrack()&&(!e||await e(t)))}}const Ks=(e,t,i)=>{if(e instanceof Promise)throw new Error(`'${t}' is deprecated and not available synchronously for this track. Use the preferred '${i}()' instead.`);return e},js=e=>{if(void 0!==e&&"function"!==typeof e)throw new TypeError("predicate, when provided, must be a function.");return e?t=>{const i=e=>{if("boolean"!==typeof e)throw new TypeError("predicate must return or resolve to a boolean value.");return e},r=e(t);return r instanceof Promise?r.then(i):i(r)}:void 0};class Xs extends Hs{constructor(e,t){super(e,t),this._pixelAspectRatioCache=null,this._backing=t}get type(){return"video"}async getCodec(){return this._backing.getCodec()}get codec(){return Ks(this._backing.getCodec(),"codec","getCodec")}async hasOnlyKeyPackets(){return await(this._backing.getHasOnlyKeyPackets?.())??!1}async getCodedWidth(){return this._backing.getCodedWidth()}get codedWidth(){return Ks(this._backing.getCodedWidth(),"codedWidth","getCodedWidth")}async getCodedHeight(){return this._backing.getCodedHeight()}get codedHeight(){return Ks(this._backing.getCodedHeight(),"codedHeight","getCodedHeight")}async getRotation(){return this._backing.getRotation()}get rotation(){return Ks(this._backing.getRotation(),"rotation","getRotation")}async getSquarePixelWidth(){return this._backing.getSquarePixelWidth()}get squarePixelWidth(){return Ks(this._backing.getSquarePixelWidth(),"squarePixelWidth","getSquarePixelWidth")}async getSquarePixelHeight(){return this._backing.getSquarePixelHeight()}get squarePixelHeight(){return Ks(this._backing.getSquarePixelHeight(),"squarePixelHeight","getSquarePixelHeight")}async getPixelAspectRatio(){return this._pixelAspectRatioCache??(this._pixelAspectRatioCache=ne({num:await this.getSquarePixelWidth()*await this.getCodedHeight(),den:await this.getSquarePixelHeight()*await this.getCodedWidth()}))}get pixelAspectRatio(){return this._pixelAspectRatioCache??(this._pixelAspectRatioCache=ne({num:Ks(this._backing.getSquarePixelWidth(),"pixelAspectRatio","getPixelAspectRatio")*Ks(this._backing.getCodedHeight(),"pixelAspectRatio","getPixelAspectRatio"),den:Ks(this._backing.getSquarePixelHeight(),"pixelAspectRatio","getPixelAspectRatio")*Ks(this._backing.getCodedWidth(),"pixelAspectRatio","getPixelAspectRatio")}))}async getDisplayWidth(){const e=await(this._backing.getMetadataDisplayWidth?.());if(null!=e)return e;return await this.getRotation()%180===0?this.getSquarePixelWidth():this.getSquarePixelHeight()}get displayWidth(){const e=this._backing.getMetadataDisplayWidth?.();if(void 0!==e){const t=Ks(e,"displayWidth","getDisplayWidth");if(null!==t)return t}const t=Ks(this._backing.getRotation(),"displayWidth","getDisplayWidth")%180===0?this._backing.getSquarePixelWidth():this._backing.getSquarePixelHeight();return Ks(t,"displayWidth","getDisplayWidth")}async getDisplayHeight(){const e=await(this._backing.getMetadataDisplayHeight?.());if(null!=e)return e;return await this.getRotation()%180===0?this.getSquarePixelHeight():this.getSquarePixelWidth()}get displayHeight(){const e=this._backing.getMetadataDisplayHeight?.();if(void 0!==e){const t=Ks(e,"displayHeight","getDisplayHeight");if(null!==t)return t}const t=Ks(this._backing.getRotation(),"displayHeight","getDisplayHeight")%180===0?this._backing.getSquarePixelHeight():this._backing.getSquarePixelWidth();return Ks(t,"displayHeight","getDisplayHeight")}async getColorSpace(){return this._backing.getColorSpace()}async hasHighDynamicRange(){const e=await this._backing.getColorSpace();return"bt2020"===e.primaries||"smpte432"===e.primaries||"pg"===e.transfer||"hlg"===e.transfer||"bt2020-ncl"===e.matrix}async canBeTransparent(){return this._backing.canBeTransparent()}async getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecParameterString(){const e=await(this._backing.getMetadataCodecParameterString?.());if(null!=e)return e;const t=await this._backing.getDecoderConfig();return t?.codec??null}async canDecode(){try{const e=await this._backing.getDecoderConfig();if(!e)return!1;const t=await this._backing.getCodec();if(i(null!==t),Cs.some(i=>i.supports(t,e)))return!0;if("undefined"===typeof VideoDecoder)return!1;return!0===(await VideoDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}}async determinePacketType(e){if(!(e instanceof Mt))throw new TypeError("packet must be an EncodedPacket.");if(e.isMetadataOnly)throw new TypeError("packet must not be metadata-only to determine its type.");const t=await this.getCodec();if(null===t)return null;const r=await this.getDecoderConfig();return i(r),St(t,r,e.data)}}class $s extends Hs{constructor(e,t){super(e,t),this._backing=t}get type(){return"audio"}async getCodec(){return this._backing.getCodec()}get codec(){return Ks(this._backing.getCodec(),"codec","getCodec")}async hasOnlyKeyPackets(){return await(this._backing.getHasOnlyKeyPackets?.())??!0}async getNumberOfChannels(){return this._backing.getNumberOfChannels()}get numberOfChannels(){return Ks(this._backing.getNumberOfChannels(),"numberOfChannels","getNumberOfChannels")}async getSampleRate(){return this._backing.getSampleRate()}get sampleRate(){return Ks(this._backing.getSampleRate(),"sampleRate","getSampleRate")}async getDecoderConfig(){return this._backing.getDecoderConfig()}async getCodecParameterString(){const e=await(this._backing.getMetadataCodecParameterString?.());if(null!=e)return e;const t=await this._backing.getDecoderConfig();return t?.codec??null}async canDecode(){try{const e=await this._backing.getDecoderConfig();if(!e)return!1;const t=await this._backing.getCodec();if(i(null!==t),Bs.some(i=>i.supports(t,e)))return!0;if(e.codec.startsWith("pcm-"))return!0;if("undefined"===typeof AudioDecoder)return!1;return!0===(await AudioDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}}async determinePacketType(e){if(!(e instanceof Mt))throw new TypeError("packet must be an EncodedPacket.");return null===await this.getCodec()?null:"key"}}const Qs=e=>-(e??-1/0),Gs=e=>-e,Ys=e=>{if("object"!==typeof e||!e)throw new TypeError("query must be an object.");if(void 0!==e.filter&&"function"!==typeof e.filter)throw new TypeError("query.filter, when provided, must be a function.");if(void 0!==e.sortBy&&"function"!==typeof e.sortBy)throw new TypeError("query.sortBy, when provided, must be a function.");return{filter:e.filter?t=>{const i=e=>{if("boolean"!==typeof e)throw new TypeError("query.filter must return or resolve to a boolean.");return e},r=e.filter(t);return r instanceof Promise?r.then(i):i(r)}:void 0,sortBy:e.sortBy?t=>{const i=e=>{if("number"!==typeof e&&(!Array.isArray(e)||!e.every(e=>"number"===typeof e)))throw new TypeError("query.sortBy must return or resolve to a number or an array of numbers.");return e},r=e.sortBy(t);return r instanceof Promise?r.then(i):i(r)}:void 0}},Js=(e,t)=>({filter:e?.filter||t?.filter?i=>{const r=e?.filter?.(i)??!0,a=e=>!1!==e&&(t?.filter?.(i)??!0);return r instanceof Promise?r.then(a):a(r)}:void 0,sortBy:e?.sortBy||t?.sortBy?i=>{const r=e?.sortBy?.(i)??[],a=t?.sortBy?.(i)??[],s=(e,t)=>[...Array.isArray(e)?e:[e],...Array.isArray(t)?t:[t]];return r instanceof Promise||a instanceof Promise?Promise.all([r,a]).then(([e,t])=>s(e,t)):s(r,a)}:void 0}),Zs=async(e,t)=>{let i=e;if(t?.filter){const r=e.map(e=>t.filter(e));if(r.some(e=>e instanceof Promise)){const t=await Promise.all(r);i=e.filter((e,i)=>t[i])}else i=e.filter((e,t)=>r[t])}if(!t?.sortBy)return i;const r=i.map(e=>t.sortBy(e)),a=r.some(e=>e instanceof Promise)?await Promise.all(r):r;return i.map((e,t)=>({track:e,sortValue:a[t]})).sort((e,t)=>{const i=Array.isArray(e.sortValue)?e.sortValue:[e.sortValue],r=Array.isArray(t.sortValue)?t.sortValue:[t.sortValue],a=Math.max(i.length,r.length);for(let s=0;se.track)};te();const en=2;let tn=null;"undefined"!==typeof FinalizationRegistry&&(tn=new FinalizationRegistry(e=>{for(const t of e)t.freed||t.free()}));class rn extends le{get disposed(){return this._disposed}constructor(e){if(super(),this._demuxerPromise=null,this._format=null,this._trackBackingsCache=null,this._backingToTrack=new Map,this._disposed=!1,this._nextSourceCacheAge=0,this._sourceRefs=[],this._sourceCache=[],this._sourceCachePromises=[],this._onFormatDetermined=null,!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(!Array.isArray(e.formats)||e.formats.some(e=>!(e instanceof Da)))throw new TypeError("options.formats must be an array of InputFormat.");if(!(e.source instanceof la||e.source instanceof ua))throw new TypeError("options.source must be a Source or SourceRef.");if(e.source instanceof la&&e.source._disposed)throw new TypeError("options.source must not be a disposed Source.");if(void 0!==e.initInput&&!(e.initInput instanceof rn))throw new TypeError("options.initInput, when provided, must be an Input.");void 0!==e.formatOptions&&((e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(`${t}, when provided, must be an object.`);if(void 0!==e.isobmff){if(!e.isobmff||"object"!==typeof e.isobmff)throw new TypeError(`${t}.isobmff, when provided, must be an object.`);if(void 0!==e.isobmff.resolveKeyId&&"function"!==typeof e.isobmff.resolveKeyId)throw new TypeError(`${t}.isobmff.resolveKeyId, when provided, must be a function.`)}})(e.formatOptions,"formatOptions"),this._formats=e.formats,this._initInput=e.initInput??null,this._formatOptions=e.formatOptions??{},e.source instanceof la?this._rootRef=e.source.ref():this._rootRef=e.source,this._sourceRefs.push(this._rootRef),tn?.register(this,this._sourceRefs,this)}get _rootSource(){return this._rootRef.source}async _getSourceUncached(e){i(this._rootSource instanceof da);const t=await this._rootSource._resolveRequest(e);return this._emit("source",{source:t.source,request:e,isRoot:e.isRoot}),t}_getSourceCached(e,t=1){const r=this._sourceCache.find(i=>i.cacheGroup===t&&ha(i.request,e));if(r)return r.age++,Promise.resolve(r.sourceRef.source.ref());const a=this._sourceCachePromises.find(i=>i.cacheGroup===t&&ha(i.request,e));if(a)return a.promise.then(e=>e.sourceRef.source.ref());const s=(async()=>{const r=await this._getSourceUncached(e);if(ae(this._sourceCache,e=>e.cacheGroup===t&&1===e.sourceRef.source._refCount)>=4){const e=se(this._sourceCache,e=>e.cacheGroup===t&&1===e.sourceRef.source._refCount?e.age:1/0);i(-1!==e);const r=this._sourceCache[e];this._sourceCache.splice(e,1),r.sourceRef.free(),((e,t)=>{const i=e.indexOf(t);-1!==i&&e.splice(i,1)})(this._sourceRefs,r.sourceRef)}this._sourceRefs.push(r);const a=this._sourceCachePromises.findIndex(t=>t.request===e);i(-1!==a),this._sourceCachePromises.splice(a,1);return{request:e,sourceRef:r,age:this._nextSourceCacheAge++,cacheGroup:t}})();return this._sourceCachePromises.push({request:e,cacheGroup:t,promise:s}),s.then(e=>{const t=e.sourceRef.source.ref();return this._sourceCache.push(e),t})}_getDemuxer(){return this._demuxerPromise??(this._demuxerPromise=(async()=>{this._reader=new nn(this._rootSource),this._emit("source",{source:this._rootSource,request:null,isRoot:!0});for(const e of this._formats){if(await e._canReadInput(this))return this._format=e,this._onFormatDetermined?.(e),e._createDemuxer(this)}throw new an})())}get source(){return this._rootSource}async getFormat(){return await this._getDemuxer(),i(this._format),this._format}async canRead(){try{return await this._getDemuxer(),!0}catch(e){if(e instanceof an)return!1;throw e}}async getFirstTimestamp(e){e??(e=await this.getTracks());const t=e.filter(e=>null!==e);if(0===t.length)return 0;const i=await Promise.all(t.map(e=>e.getFirstTimestamp()));return Math.min(...i)}async computeDuration(e,t){e??(e=await this.getTracks());const i=e.filter(e=>null!==e);if(0===i.length)return 0;const r=await Promise.all(i.map(e=>e.computeDuration(t)));return Math.max(...r)}async getDurationFromMetadata(e,t){e??(e=await this.getTracks());const i=e.filter(e=>null!==e),r=(await Promise.all(i.map(e=>e.getDurationFromMetadata(t)))).filter(e=>null!==e);return 0===r.length?null:Math.max(...r)}async getTracks(e){e&&(e=Ys(e));const t=(await this._getTrackBackings()).map(e=>this._wrapBackingAsTrack(e));return Zs(t,e)}async getVideoTracks(e){e&&(e=Ys(e));const t=(await this.getTracks()).filter(e=>e.isVideoTrack());return Zs(t,e)}async getAudioTracks(e){e&&(e=Ys(e));const t=(await this.getTracks()).filter(e=>e.isAudioTrack());return Zs(t,e)}async getPrimaryVideoTrack(e){e&&(e=Ys(e));const t=Js(e,{sortBy:async e=>[Gs((await e.getDisposition()).default),Gs(await e.hasPairableAudioTrack()),Gs(!(await e.hasOnlyKeyPackets())),Qs(await e.getBitrate())]});return(await this.getVideoTracks(t))[0]??null}async getPrimaryAudioTrack(e){e&&(e=Ys(e));const t=await this.getPrimaryVideoTrack(),i=Js(e,{sortBy:async e=>[Gs(!t||e.canBePairedWith(t)),Gs((await e.getDisposition()).default),Qs(await e.getBitrate())]});return(await this.getAudioTracks(i))[0]??null}async _getTrackBackings(){const e=await this._getDemuxer();return this._trackBackingsCache??(this._trackBackingsCache=await e.getTrackBackings())}_wrapBackingAsTrack(e){const t=this._backingToTrack.get(e);if(t)return t;const i="video"===e.getType()?new Xs(this,e):new $s(this,e);return this._backingToTrack.set(e,i),i}async getMimeType(){return(await this._getDemuxer()).getMimeType()}async getMetadataTags(){return(await this._getDemuxer()).getMetadataTags()}dispose(){if(!this._disposed){this._disposed=!0;for(const e of this._sourceRefs)e.free();this._sourceRefs.length=0,tn?.unregister(this),this._demuxerPromise?.then(e=>e.dispose())}}[Symbol.dispose](){this.dispose()}}class an extends Error{constructor(e="Input has an unsupported or unrecognizable format."){super(e),this.name="UnsupportedInputFormatError"}}class sn extends Error{constructor(e="Input has been disposed."){super(e),this.name="InputDisposedError"}}class nn{constructor(e){this.source=e}get fileSize(){const e=this.source._getFileSize();if(void 0===e)throw new Error("Reading file size too early; read required first.");return e}get fileSizeNonStrict(){return this.source._getFileSize()??null}requestSlice(e,t){if(this.source._disposed)throw new sn;if(e<0)return null;if(null!==this.fileSizeNonStrict&&e+t>this.fileSizeNonStrict)return null;if(0===t){const t=new Uint8Array(0);return new on(t,c(t),0,e,e)}const i=e+t,r=this.source._read(e,i,0,ca);return r instanceof Promise?r.then(t=>t?new on(t.bytes,t.view,t.offset,e,i):null):r?new on(r.bytes,r.view,r.offset,e,i):null}requestSliceRange(e,t,r){if(this.source._disposed)throw new sn;if(e<0)return null;if(null!==this.fileSizeNonStrict)return this.requestSlice(e,F(this.fileSizeNonStrict-e,t,r));{const a=this.requestSlice(e,r),s=a=>a||(i(null!==this.fileSizeNonStrict),this.requestSlice(e,F(this.fileSizeNonStrict-e,t,r)));return a instanceof Promise?a.then(s):s(a)}}requestEntireFile(){if(null!==this.fileSizeNonStrict)return this.requestSlice(0,this.fileSizeNonStrict);return(async()=>{const e=[];let t=0;for(;;){if(1===e.length&&null!==this.fileSizeNonStrict)return this.requestSlice(0,this.fileSizeNonStrict);const i=1024*e.length;let r=this.requestSliceRange(i,0,1024);if(r instanceof Promise&&(r=await r),!r)break;e.push(ln(r,r.length)),t+=r.length}const i=new Uint8Array(t);let r=0;for(const a of e)i.set(a,r),r+=a.length;return new on(i,c(i),0,0,t)})()}}class on{constructor(e,t,i,r,a){this.bytes=e,this.view=t,this.offset=i,this.start=r,this.end=a,this.bufferPos=r-i}static tempFromBytes(e){return new on(e,c(e),0,0,e.length)}get length(){return this.end-this.start}get filePos(){return this.offset+this.bufferPos}set filePos(e){this.bufferPos=e-this.offset}get remainingLength(){return Math.max(this.end-this.filePos,0)}skip(e){this.bufferPos+=e}slice(e,t=this.end-e){if(ethis.end)throw new RangeError("Slicing outside of original slice.");return new on(this.bytes,this.view,this.offset,e,e+t)}}const cn=(e,t)=>{if(e.filePose.end)throw new RangeError(`Tried reading [${e.filePos}, ${e.filePos+t}), but slice is [${e.start}, ${e.end}). This is likely an internal error, please report it alongside the file that caused it.`)},ln=(e,t)=>{cn(e,t);const i=e.bytes.subarray(e.bufferPos,e.bufferPos+t);return e.bufferPos+=t,i},un=e=>(cn(e,1),e.view.getUint8(e.bufferPos++)),dn=(e,t)=>{cn(e,2);const i=e.view.getUint16(e.bufferPos,t);return e.bufferPos+=2,i},hn=e=>{cn(e,2);const t=e.view.getUint16(e.bufferPos,!1);return e.bufferPos+=2,t},fn=e=>{cn(e,3);const t=E(e.view,e.bufferPos,!1);return e.bufferPos+=3,t},mn=e=>{cn(e,2);const t=e.view.getInt16(e.bufferPos,!1);return e.bufferPos+=2,t},pn=(e,t)=>{cn(e,4);const i=e.view.getUint32(e.bufferPos,t);return e.bufferPos+=4,i},gn=e=>{cn(e,4);const t=e.view.getUint32(e.bufferPos,!1);return e.bufferPos+=4,t},kn=e=>{cn(e,4);const t=e.view.getUint32(e.bufferPos,!0);return e.bufferPos+=4,t},bn=e=>{cn(e,4);const t=e.view.getInt32(e.bufferPos,!1);return e.bufferPos+=4,t},yn=(e,t)=>{let i,r;return t?(i=pn(e,!0),r=pn(e,!0)):(r=pn(e,!1),i=pn(e,!1)),4294967296*r+i},wn=e=>4294967296*gn(e)+gn(e),Tn=e=>4294967296*bn(e)+gn(e),Sn=e=>{const t=kn(e),i=(e=>{cn(e,4);const t=e.view.getInt32(e.bufferPos,!0);return e.bufferPos+=4,t})(e);return 4294967296*i+t},Pn=e=>{cn(e,4);const t=e.view.getFloat32(e.bufferPos,!1);return e.bufferPos+=4,t},vn=e=>{cn(e,8);const t=e.view.getFloat64(e.bufferPos,!1);return e.bufferPos+=8,t},In=(e,t)=>{cn(e,t);let i="";for(let r=0;rl.decode(ln(e,t)).split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!i?.ignore?.(e));var Cn,Bn,En,_n;(Bn=Cn||(Cn={}))[Bn.Unsynchronisation=128]="Unsynchronisation",Bn[Bn.ExtendedHeader=64]="ExtendedHeader",Bn[Bn.ExperimentalIndicator=32]="ExperimentalIndicator",Bn[Bn.Footer=16]="Footer",(_n=En||(En={}))[_n.ISO_8859_1=0]="ISO_8859_1",_n[_n.UTF_16_WITH_BOM=1]="UTF_16_WITH_BOM",_n[_n.UTF_16_BE_NO_BOM=2]="UTF_16_BE_NO_BOM",_n[_n.UTF_8=3]="UTF_8";const An=128,Fn=10,Rn=["Blues","Classic rock","Country","Dance","Disco","Funk","Grunge","Hip-hop","Jazz","Metal","New age","Oldies","Other","Pop","Rhythm and blues","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death metal","Pranks","Soundtrack","Euro-techno","Ambient","Trip-hop","Vocal","Jazz & funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound clip","Gospel","Noise","Alternative rock","Bass","Soul","Punk","Space","Meditative","Instrumental pop","Instrumental rock","Ethnic","Gothic","Darkwave","Techno-industrial","Electronic","Pop-folk","Eurodance","Dream","Southern rock","Comedy","Cult","Gangsta","Top 40","Christian rap","Pop/funk","Jungle music","Native US","Cabaret","New wave","Psychedelic","Rave","Showtunes","Trailer","Lo-fi","Tribal","Acid punk","Acid jazz","Polka","Retro","Musical","Rock 'n' roll","Hard rock","Folk","Folk rock","National folk","Swing","Fast fusion","Bebop","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic rock","Progressive rock","Psychedelic rock","Symphonic rock","Slow rock","Big band","Chorus","Easy listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber music","Sonata","Symphony","Booty bass","Primus","Porn groove","Satire","Slow jam","Club","Tango","Samba","Folklore","Ballad","Power ballad","Rhythmic Soul","Freestyle","Duet","Punk rock","Drum solo","A cappella","Euro-house","Dance hall","Goa music","Drum & bass","Club-house","Hardcore techno","Terror","Indie","Britpop","Negerpunk","Polsk punk","Beat","Christian gangsta rap","Heavy metal","Black metal","Crossover","Contemporary Christian","Christian rock","Merengue","Salsa","Thrash metal","Anime","Jpop","Synthpop","Christmas","Art rock","Baroque","Bhangra","Big beat","Breakbeat","Chillout","Downtempo","Dub","EBM","Eclectic","Electro","Electroclash","Emo","Experimental","Garage","Global","IDM","Illbient","Industro-Goth","Jam Band","Krautrock","Leftfield","Lounge","Math rock","New romantic","Nu-breakz","Post-punk","Post-rock","Psytrance","Shoegaze","Space rock","Trop rock","World music","Neoclassical","Audiobook","Audio theatre","Neue Deutsche Welle","Podcast","Indie rock","G-Funk","Dubstep","Garage rock","Psybient"],Dn=(e,t)=>{var i;const r=e.filePos;t.raw??(t.raw={}),(i=t.raw).TAG??(i.TAG=ln(e,An-3)),e.filePos=r;const a=Mn(e,30);a&&(t.title??(t.title=a));const s=Mn(e,30);s&&(t.artist??(t.artist=s));const n=Mn(e,30);n&&(t.album??(t.album=n));const o=Mn(e,4),c=Number.parseInt(o,10);Number.isInteger(c)&&c>0&&(t.date??(t.date=new Date(c,0,1)));const l=ln(e,30);let u;if(0===l[28]&&0!==l[29]){const i=l[29];i>0&&(t.trackNumber??(t.trackNumber=i)),e.skip(-30),u=Mn(e,28),e.skip(2)}else e.skip(-30),u=Mn(e,30);u&&(t.comment??(t.comment=u));const d=un(e);d{const i=ln(e,t),r=J(i.indexOf(0),i.length),a=i.subarray(0,r);let s="";for(let n=0;n{const t=e.filePos,i=In(e,3),r=un(e),a=un(e),s=un(e),n=gn(e);if("ID3"!==i||255===r||255===a||0!==(2155905152&n))return e.filePos=t,null;return{majorVersion:r,revision:a,flags:s,size:Ne(n)}},On=(e,t,i)=>{var r,a,s,n,o;if(![2,3,4].includes(t.majorVersion))return void console.warn(`Unsupported ID3v2 major version: ${t.majorVersion}`);const c=ln(e,t.size),l=new Ln(t,c);if(t.flags&Cn.Footer&&l.removeFooter(),t.flags&Cn.Unsynchronisation&&3===t.majorVersion&&l.ununsynchronizeAll(),t.flags&Cn.ExtendedHeader){const e=l.readU32();3===t.majorVersion?l.pos+=e:l.pos+=e-4}for(;l.pos<=l.bytes.length-l.frameHeaderSize();){const e=l.readId3V2Frame();if(!e)break;const c=l.pos,u=l.pos+e.size;let d=!1,h=!1,f=!1;if(3===t.majorVersion?(d=!!(64&e.flags),h=!!(128&e.flags)):4===t.majorVersion&&(d=!!(4&e.flags),h=!!(8&e.flags),f=!!(2&e.flags)||!!(t.flags&Cn.Unsynchronisation)),d)console.warn(`Skipping encrypted ID3v2 frame ${e.id}`),l.pos=u;else if(h)console.warn(`Skipping compressed ID3v2 frame ${e.id}`),l.pos=u;else{if(f&&l.ununsynchronizeRegion(l.pos,u),i.raw??(i.raw={}),"TXXX"===e.id){const e=(r=i.raw).TXXX??(r.TXXX={}),t=l.readId3V2TextEncoding(),a=l.readId3V2Text(t,u),s=l.readId3V2Text(t,u);e[a]??(e[a]=s)}else"T"===e.id[0]?(a=i.raw)[s=e.id]??(a[s]=l.readId3V2EncodingAndText(u)):(n=i.raw)[o=e.id]??(n[o]=l.readBytes(e.size));switch(l.pos=c,e.id){case"TIT2":case"TT2":i.title??(i.title=l.readId3V2EncodingAndText(u));break;case"TIT3":case"TT3":i.description??(i.description=l.readId3V2EncodingAndText(u));break;case"TPE1":case"TP1":i.artist??(i.artist=l.readId3V2EncodingAndText(u));break;case"TALB":case"TAL":i.album??(i.album=l.readId3V2EncodingAndText(u));break;case"TPE2":case"TP2":i.albumArtist??(i.albumArtist=l.readId3V2EncodingAndText(u));break;case"TRCK":case"TRK":{const e=l.readId3V2EncodingAndText(u).split("/"),t=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(i.trackNumber??(i.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&(i.tracksTotal??(i.tracksTotal=r))}break;case"TPOS":case"TPA":{const e=l.readId3V2EncodingAndText(u).split("/"),t=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(i.discNumber??(i.discNumber=t)),r&&Number.isInteger(r)&&r>0&&(i.discsTotal??(i.discsTotal=r))}break;case"TCON":case"TCO":{const e=l.readId3V2EncodingAndText(u);let t=/^\((\d+)\)/.exec(e);if(t){const e=Number.parseInt(t[1]);if(void 0!==Rn[e]){i.genre??(i.genre=Rn[e]);break}}if(t=/^\d+$/.exec(e),t){const e=Number.parseInt(t[0]);if(void 0!==Rn[e]){i.genre??(i.genre=Rn[e]);break}}i.genre??(i.genre=e)}break;case"TDRC":case"TDAT":{const e=l.readId3V2EncodingAndText(u),t=new Date(e);Number.isNaN(t.getTime())||(i.date??(i.date=t))}break;case"TYER":case"TYE":{const e=l.readId3V2EncodingAndText(u),t=Number.parseInt(e,10);Number.isInteger(t)&&(i.date??(i.date=new Date(t,0,1)))}break;case"USLT":case"ULT":{const e=l.readU8();l.pos+=3,l.readId3V2Text(e,u),i.lyrics??(i.lyrics=l.readId3V2Text(e,u))}break;case"COMM":case"COM":{const e=l.readU8();l.pos+=3,l.readId3V2Text(e,u),i.comment??(i.comment=l.readId3V2Text(e,u))}break;case"APIC":case"PIC":{const e=l.readId3V2TextEncoding();let r;if(2===t.majorVersion){const e=l.readAscii(3);r="PNG"===e?"image/png":"JPG"===e?"image/jpeg":"image/*"}else r=l.readId3V2Text(e,u);const a=l.readU8(),s=l.readId3V2Text(e,u).trimEnd(),n=u-l.pos;if(n>=0){const e=l.readBytes(n);i.images||(i.images=[]),i.images.push({data:e,mimeType:r,kind:3===a?"coverFront":4===a?"coverBack":"unknown",description:s})}}break;default:l.pos+=e.size}l.pos=u}}};class Ln{constructor(e,t){this.header=e,this.bytes=t,this.pos=0,this.view=new DataView(t.buffer,t.byteOffset,t.byteLength)}frameHeaderSize(){return 2===this.header.majorVersion?6:10}ununsynchronizeAll(){const e=[];for(let t=0;t{const t=this.pos+e;if(t>this.bytes.length)return!1;if(t<=this.bytes.length-this.frameHeaderSize()){this.pos+=e;const t=this.readAscii(4);if("\0\0\0\0"!==t&&!/[0-9A-Z]{4}/.test(t))return!1}return!0};if(!s(i)){const e=4===this.header.majorVersion?t:Ne(t);s(e)&&(i=e)}return this.pos=a,{id:e,size:i,flags:r}}}readId3V2TextEncoding(){const e=this.readU8();if(e>3)throw new Error(`Unsupported text encoding: ${e}`);return e}readId3V2Text(e,t){const i=this.pos,r=this.readBytes(t-this.pos);switch(e){case En.ISO_8859_1:{let e="";for(let t=0;t0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(2,t))}if(254===r[0]&&255===r[1]){const e=new TextDecoder("utf-16be"),t=J(r.findIndex((e,t)=>0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(2,t))}{const e=J(r.findIndex(e=>0===e),r.length);return this.pos=i+Math.min(e+1,r.length),l.decode(r.subarray(0,e))}case En.UTF_16_BE_NO_BOM:{const e=new TextDecoder("utf-16be"),t=J(r.findIndex((e,t)=>0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(0,t))}case En.UTF_8:{const e=J(r.findIndex(e=>0===e),r.length);return this.pos=i+Math.min(e+1,r.length),l.decode(r.subarray(0,e))}}}readId3V2EncodingAndText(e){if(this.pos>=e)return"";const t=this.readId3V2TextEncoding();return this.readId3V2Text(t,e)}}class zn{constructor(e){this.events=e,this.input=null,this.audioSink=null,this.audioIterator=null,this.audioContext=null,this.gainNode=null,this.audioContextStartTime=0,this.playbackTimeAtStart=0,this.latestScheduledEndTime=0,this.duration=Number.NaN,this.paused=!0,this.volume=.7,this.muted=!1,this.playbackRate=1,this.asyncId=0,this.queuedNodes=new Set}get currentTime(){return this.paused?this.playbackTimeAtStart:(this.audioContext.currentTime-this.audioContextStartTime)*this.playbackRate+this.playbackTimeAtStart}ensureAudioContext(e){if(this.audioContext)return;const t=window.AudioContext||window.webkitAudioContext;try{this.audioContext=new t({sampleRate:e})}catch{this.audioContext=new t}this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination),this.updateGain()}updateGain(){if(!this.gainNode)return;const e=this.muted?0:this.volume;this.gainNode.gain.value=e*e}stopQueuedNodes(){this.queuedNodes.forEach(e=>e.stop()),this.queuedNodes.clear()}async stopIterator(){await(this.audioIterator?.return()),this.audioIterator=null}handleNoAudioTrack(){this.audioSink=null,this.ensureAudioContext()}async load(e,t){++this.asyncId,await this.stopIterator(),this.stopQueuedNodes(),this.paused=!0,this.playbackTimeAtStart=0,this.audioContextStartTime=0;const{input:i,audioTrack:r,duration:a}=e;return this.input=i,this.duration=a,r?null!==r.codec&&await r.canDecode()?(this.ensureAudioContext(r.sampleRate),this.audioSink=new Vs(r),void t?.()):(this.audioSink=null,this.ensureAudioContext(),void t?.()):(this.handleNoAudioTrack(),void t?.())}async runIterator(e){if(this.audioSink)for(await this.stopIterator(),this.audioIterator=this.audioSink.buffers(this.currentTime);;){if(e!==this.asyncId||this.paused)return;const i=this.audioIterator.next(),r=setInterval(()=>{e!==this.asyncId||this.paused?clearInterval(r):"running"===this.audioContext.state&&this.audioContext.currentTime>=this.latestScheduledEndTime-.2&&(this.audioContext.suspend(),this.events.emit("waiting"))},50);let a;try{a=await i}catch(t){console.error("Audio iterator error:",t);break}finally{clearInterval(r)}if(e!==this.asyncId||this.paused)return;if("suspended"===this.audioContext.state&&(await this.audioContext.resume(),this.events.emit("canplay"),this.events.emit("playing")),a.done)break;const{buffer:s,timestamp:n}=a.value,o=this.audioContext.createBufferSource();o.buffer=s,o.connect(this.gainNode),o.playbackRate.value=this.playbackRate;const c=this.audioContextStartTime+(n-this.playbackTimeAtStart)/this.playbackRate,l=c+s.duration/this.playbackRate;l>this.latestScheduledEndTime&&(this.latestScheduledEndTime=l),c>=this.audioContext.currentTime?o.start(c):o.start(this.audioContext.currentTime,(this.audioContext.currentTime-c)*this.playbackRate),this.queuedNodes.add(o),o.onended=()=>this.queuedNodes.delete(o)}}async play(){if(!this.paused)return;this.audioContext||this.ensureAudioContext(),"suspended"===this.audioContext.state&&await this.audioContext.resume(),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime,this.paused=!1;const e=++this.asyncId;this.runIterator(e)}pause(){this.paused||(this.playbackTimeAtStart=this.currentTime,this.paused=!0,this.stopIterator(),this.stopQueuedNodes())}async seek(e){this.playbackTimeAtStart=Math.max(0,e),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime;const t=++this.asyncId;this.paused||this.runIterator(t)}setVolume(e,t){this.volume=e,this.muted=t,this.updateGain()}setPlaybackRate(e){if(e!==this.playbackRate&&(this.paused||(this.playbackTimeAtStart=this.currentTime,this.audioContextStartTime=this.audioContext.currentTime),this.playbackRate=e,!this.paused)){const e=++this.asyncId;this.runIterator(e)}}destroy(){this.asyncId++,this.pause(),this.audioContext?.close(),this.audioContext=null,this.input=null,this.audioSink=null}}const Un=/\.m3u8(?:$|[?#])/i;function qn(e){return"string"===typeof e&&Un.test(e)}function Wn(e){const t=function(e){return"string"===typeof e?new ka(e):e instanceof Blob?new ma(e):"undefined"!==typeof ReadableStream&&e instanceof ReadableStream?new ba(e):e??null}(e);return t?new rn({source:t,formats:qn(e)?ss:as}):null}async function Vn({input:e,videoTrack:t,audioTrack:i}){const r=[t,i].filter(Boolean),a=t||i,s=Boolean(a&&await a.isLive());let n=Number.NaN;return r.length>0&&(n=await e.getDurationFromMetadata(r,{skipLiveWait:!0}),null!==n||s||(n=await e.computeDuration(r,{skipLiveWait:!0}))),s?Number.POSITIVE_INFINITY:n??Number.NaN}async function Hn(e){return await e.getAverageBitrate()??await e.getBitrate()??0}class Kn{constructor({canvas:e,ctx:t,events:i,timeupdateInterval:r=250,avSyncTolerance:a=.12,dropLateFrames:s=!1,poster:n="",preflightRange:o=!1}){this.canvas=e,this.ctx=t,this.events=i,this.timeupdateInterval=r,this.avSyncTolerance=a,this.dropLateFrames=s,this.poster=n,this.preflightRange=o,this.input=null,this.videoSink=null,this.videoIterator=null,this.nextFrame=null,this.rafId=0,this.asyncId=0,this.width=0,this.height=0,this.duration=Number.NaN,this.audioClock=null,this.lastTimeUpdate=0,this.stalled=!1,this.playbackRate=1,this.posterDrawn=!1,this.isFetching=!1}async preflight(e){if(!this.preflightRange||"string"!==typeof e||qn(e))return!0;try{const t=(await fetch(e,{method:"HEAD"})).headers.get("accept-ranges");return!(!t||"none"===t)||(this.events.emit("error",new Event("RangeNotSupported")),!1)}catch(t){return console.warn("Preflight check failed:",t),!0}}drawPoster(){if(!this.poster||this.posterDrawn)return;const e=new Image;e.onload=()=>{this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width=e.naturalWidth||this.canvas.width,this.canvas.height=e.naturalHeight||this.canvas.height,this.ctx.drawImage(e,0,0,this.canvas.width,this.canvas.height),this.posterDrawn=!0},e.src=this.poster}async stopIterator(){await(this.videoIterator?.return()),this.videoIterator=null}clear(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}async load(e,t){++this.asyncId,await this.stopIterator(),this.clear(),this.posterDrawn=!1;const{input:i,videoTrack:r,duration:a}=e;if(this.input=i,this.duration=a,!r)return this.handleNoVideoTrack(),void t?.();if(null===r.codec||!(await r.canDecode()))return this.handleNoVideoTrack(),void t?.();const s=await r.canBeTransparent();this.videoSink=new zs(r,{poolSize:2,fit:"contain",alpha:s}),this.width=r.displayWidth,this.height=r.displayHeight,this.canvas.width=this.width,this.canvas.height=this.height,t?.(),await this.resetIterator(0)}handleNoVideoTrack(){this.videoSink=null,this.width=0,this.height=0,this.canvas.width=0,this.canvas.height=0,this.clear(),this.drawPoster()}async resetIterator(e){if(await this.stopIterator(),!this.videoSink)return;this.videoIterator=this.videoSink.canvases(e);const t=(await this.videoIterator.next()).value??null,i=(await this.videoIterator.next()).value??null;this.nextFrame=i,t?this.ctx.drawImage(t.canvas,0,0):this.drawPoster()}async updateNextFrame(e){if(this.videoIterator&&!this.isFetching){this.isFetching=!0;try{for(;;){const t=(await this.videoIterator.next()).value??null;if(!t||e!==this.asyncId)return;const i=this.audioClock.currentTime,r=this.dropLateFrames?Math.max(.06,this.avSyncTolerance/Math.max(1,this.playbackRate)):0;if(!(this.dropLateFrames&&t.timestampi)return void(this.nextFrame=null)}}}finally{this.isFetching=!1}}}render(){if(!this.audioClock)return;const e=this.audioClock.currentTime,t=Date.now();if(t-this.lastTimeUpdate>=this.timeupdateInterval&&(this.events.emit("timeupdate"),this.lastTimeUpdate=t),Number.isFinite(this.duration)&&e>=this.duration)return this.stop(),this.stalled=!1,this.events.emit("ended"),this.events.emit("pause"),void this.events.emit("canplay");this.nextFrame&&this.nextFrame.timestamp<=e?(this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextFrame.canvas,0,0),this.nextFrame=null,this.updateNextFrame(this.asyncId),this.stalled&&(this.events.emit("canplay"),this.events.emit("playing"),this.stalled=!1)):this.nextFrame||(this.updateNextFrame(this.asyncId),!this.nextFrame&&Number.isFinite(this.duration)&&ethis.render())}start(e){this.audioClock=e,this.asyncId++,this.stalled=!1,this.updateNextFrame(this.asyncId),this.rafId=requestAnimationFrame(()=>this.render())}stop(){cancelAnimationFrame(this.rafId)}async seek(e){this.asyncId++,await this.resetIterator(e)}setPlaybackRate(e){this.playbackRate=Math.max(.1,Number(e)||1)}destroy(){this.asyncId++,this.stop(),this.stopIterator(),this.posterDrawn=!1,this.videoSink=null,this.input=null}}class jn{constructor({canvas:e,ctx:t,events:i,option:r={}}){this.events=i,this.option=r,this.audio=new zn(i),this.video=new Kn({canvas:e,ctx:t,events:i,timeupdateInterval:r.timeupdateInterval??250,avSyncTolerance:r.avSyncTolerance??.12,dropLateFrames:r.dropLateFrames??!1,poster:r.poster??"",preflightRange:r.preflightRange??!1}),this.paused=!0,this.ended=!1,this.readyState=0,this.networkState=0,this.error=null,this.seeking=!1,this.loadSeq=0,this.input=null,this.media=null,i.addEventListener?.("ended",()=>{this.ended=!0,this.paused=!0})}async load(e){const t=++this.loadSeq;this.pause(),this.disposeInput(),this.ended=!1,this.error=null,this.networkState=2,this.readyState=0,setTimeout(()=>this.events.emit("waiting"),0),setTimeout(()=>this.events.emit("loadstart"),0);const i=Number.isFinite(this.option.loadTimeout)?this.option.loadTimeout:0;try{await Promise.race([this.performLoad(e,t),i>0?this.createTimeout(i):new Promise(()=>{})])}catch(r){if(t!==this.loadSeq)return;this.loadSeq++,this.error={code:4,message:r.message},this.networkState=3,this.events.emit("error")}}async performLoad(e,t){if(!(await this.video.preflight(e)))return;const i=Wn(e);if(!i)return this.video.handleNoVideoTrack(),void this.audio.handleNoAudioTrack();const r=await async function(e,t){const i=await e.getPrimaryVideoTrack(),r=i?await i.getPrimaryPairableAudioTrack():await e.getPrimaryAudioTrack(),a=await Vn({input:e,videoTrack:i,audioTrack:r});return{input:e,videoTrack:i,audioTrack:r,duration:a,isLive:!Number.isFinite(a)&&Boolean((i||r)&&await(i||r).isLive()),isHls:qn(t),videoMode:qn(t)?"auto":"manual",audioMode:qn(t)?"auto":"manual"}}(i,e);if(t!==this.loadSeq)return void i.dispose();this.disposeInput(),this.input=i,this.media=r;let a=!r.videoTrack,s=!r.audioTrack;const n=()=>{a&&s&&(this.readyState=1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"))};try{if(await Promise.all([this.video.load(r,()=>{t===this.loadSeq&&(a=!0,n())}),this.audio.load(r,()=>{t===this.loadSeq&&(s=!0,n())})]),t!==this.loadSeq)return;this.readyState=4,this.networkState=1,this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("progress")}catch(o){if(t!==this.loadSeq)return;this.error={code:4,message:o.message},this.networkState=3,this.events.emit("error"),console.error("MediaBunny load error:",o)}}createTimeout(e){return new Promise((t,i)=>{setTimeout(()=>i(new Error("Load timeout")),e)})}disposeInput(){this.input?.dispose(),this.input=null,this.media=null}async replaceTracks({videoTrack:e,audioTrack:t,videoMode:i,audioMode:r}){if(!this.media)return;const a={...this.media,videoTrack:e,audioTrack:t,videoMode:i,audioMode:r},s=!this.paused,n=this.currentTime;this.pause(),this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),a.duration=await Vn(a),this.media=a,await Promise.all([this.video.load(a),this.audio.load(a)]),await Promise.all([this.video.seek(n),this.audio.seek(n)]),this.readyState=4,this.networkState=1,this.seeking=!1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"),this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("seeked"),s&&await this.play()}async selectHlsQuality(e){if(!this.media?.isHls||!this.input)return;const t=await this.input.getVideoTracks(),i="auto"===e?await this.input.getPrimaryVideoTrack():t.find(t=>t.id===e)??this.media.videoTrack;if(!i)return;let r=this.media.audioTrack,a=this.media.audioMode;r&&i.canBePairedWith(r)||(r=await i.getPrimaryPairableAudioTrack(),a="auto"),await this.replaceTracks({videoTrack:i,audioTrack:r,videoMode:"auto"===e?"auto":"manual",audioMode:a})}async selectHlsAudio(e){if(!this.media?.isHls||!this.input)return;const t=await this.input.getAudioTracks(),i="auto"===e?this.media.videoTrack?await this.media.videoTrack.getPrimaryPairableAudioTrack():await this.input.getPrimaryAudioTrack():t.find(t=>t.id===e)??this.media.audioTrack;if(!i)return;let r=this.media.videoTrack,a=this.media.videoMode;r&&i.canBePairedWith(r)||(r=await i.getPrimaryPairableVideoTrack(),a="auto"),await this.replaceTracks({videoTrack:r,audioTrack:i,videoMode:a,audioMode:"auto"===e?"auto":"manual"})}getHlsState(){return async function(e){if(!e?.isHls||!e.input)return null;const[t,i]=await Promise.all([e.input.getVideoTracks(),e.videoTrack?e.videoTrack.getPairableAudioTracks():[]]),[r,a]=await Promise.all([Promise.all(t.map(async(e,t)=>({id:e.id,track:e,index:t,name:await e.getName(),height:await e.getDisplayHeight(),bitrate:await Hn(e)}))),Promise.all(i.map(async(e,t)=>{const i=await e.getName(),r=await e.getLanguageCode();return{id:e.id,track:e,index:t,name:i,lang:r,language:r,bitrate:await Hn(e)}}))]);return{levels:r,audios:a,currentLevel:e.videoTrack?r.find(t=>t.id===e.videoTrack.id)??null:null,currentAudio:e.audioTrack?a.find(t=>t.id===e.audioTrack.id)??null:null,videoMode:e.videoMode??"auto",audioMode:e.audioMode??"auto"}}(this.media)}async play(){this.paused&&(this.ended&&(this.ended=!1,await this.seek(0)),this.paused=!1,await this.audio.play(),this.video.start(this.audio),this.events.emit("play"),this.events.emit("playing"))}pause(){this.paused||(this.paused=!0,this.audio.pause(),this.video.stop(),this.events.emit("pause"))}async seek(e){const t=!this.paused;this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),this.pause(),await Promise.all([this.audio.seek(e),this.video.seek(e)]),this.seeking=!1,this.events.emit("seeked"),t&&!this.ended&&await this.play()}setVolume(e,t){this.audio.setVolume(e,t)}setPlaybackRate(e){this.audio.setPlaybackRate(e),this.video.setPlaybackRate(e)}destroy(){this.pause(),this.disposeInput(),this.audio.destroy(),this.video.destroy()}get currentTime(){return this.audio.currentTime}get duration(){return this.media?.duration??this.audio.duration??this.video.duration}get videoWidth(){return this.video.width}get videoHeight(){return this.video.height}}class Xn{constructor({art:e,canvas:i,ctx:r,option:a}){this.art=e,this.canvas=i,this.option=a,this.events=new t,this.engine=new jn({canvas:i,ctx:r,events:this.events,option:a}),this._src=null,this._volume=a.volume??.7,this._muted=!!a.muted,this._playbackRate=1,this.engine.setVolume(this._volume,this._muted),this.setupEventForwarding(),a.source?this.src=a.source:e.option?.url&&(this.src=e.option.url)}setupEventForwarding(){const{events:e}=this.art.constructor.config;e.forEach(e=>{this.events.addEventListener(e,e=>{this.art.emit(`video:${e.type}`,e)})})}addEventListener(e,t){this.events.addEventListener(e,t)}removeEventListener(e,t){this.events.removeEventListener(e,t)}get src(){return this._src}set src(e){this._src=e,e&&this.engine.load(e)}get currentSrc(){return this._src}get currentTime(){return this.engine.currentTime}set currentTime(e){this.engine.seek(Number(e)||0)}get duration(){return this.engine.duration}get buffered(){return this.createTimeRanges(0,this.engine.duration)}get played(){return this.createTimeRanges(0,this.engine.currentTime)}get seekable(){return this.createTimeRanges(0,this.engine.duration)}createTimeRanges(e,t){const i=this.engine.duration;return!i||Number.isNaN(i)||t<=0?{length:0,start:()=>0,end:()=>0}:{length:1,start:()=>e,end:()=>t}}get paused(){return this.engine.paused}get playing(){return!this.engine.paused&&!this.engine.ended}get ended(){return this.engine.ended}get seeking(){return this.engine.seeking}get readyState(){return this.engine.readyState}get networkState(){return this.engine.networkState}get error(){return this.engine.error}get playbackRate(){return this._playbackRate}set playbackRate(e){const t=Number(e);Number.isNaN(t)||t<=0||(this._playbackRate=t,this.engine.setPlaybackRate(t),this.events.emit("ratechange"))}get volume(){return this._volume}set volume(e){this._volume=function(e,t,i){return Math.max(t,Math.min(i,Number(e)||0))}(e,0,1),this._muted=!1,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}get muted(){return this._muted}set muted(e){this._muted=!!e,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}play(){return this.engine.play()}pause(){this.engine.pause()}load(){this._src&&this.engine.load(this._src)}getM3u8State(){return this.engine.getHlsState()}switchM3u8Quality(e){return this.engine.selectHlsQuality(e)}switchM3u8Audio(e){return this.engine.selectHlsAudio(e)}get videoWidth(){return this.engine.videoWidth}get videoHeight(){return this.engine.videoHeight}get poster(){return this.option.poster||""}set poster(e){this.option.poster=e}get autoplay(){return this.option.autoplay||!1}set autoplay(e){}get loop(){return this.option.loop||!1}set loop(e){}get controls(){return!1}set controls(e){}get playsInline(){return!0}set playsInline(e){}get crossOrigin(){return this.option.crossOrigin||""}set crossOrigin(e){}get preload(){return"auto"}set preload(e){}get defaultMuted(){return!1}set defaultMuted(e){}get defaultPlaybackRate(){return 1}set defaultPlaybackRate(e){}canPlayType(e){return"maybe"}getBoundingClientRect(){return this.canvas.getBoundingClientRect()}requestVideoFrameCallback(e){return requestAnimationFrame(t=>{e(t,{presentationTime:this.engine.currentTime,expectedDisplayTime:t+16.6,width:this.engine.videoWidth,height:this.engine.videoHeight,mediaTime:this.engine.currentTime,presentedFrames:0,processingDuration:0,captureTime:t,receiveTime:t,rtpTimestamp:0})})}cancelVideoFrameCallback(e){cancelAnimationFrame(e)}setAttribute(e,t){"src"===e?this.src=t:"autoplay"===e?this.autoplay=t:"loop"===e?this.loop=t:"muted"===e?this.muted=!0:this.canvas.setAttribute(e,t)}destroy(){this.engine.destroy()}}return function(t={}){return i=>{const{constructor:r}=i,{createElement:a}=r.utils,s=a("canvas"),n=s.getContext("2d"),o=new Xn({art:i,canvas:s,ctx:n,option:t});i.mediabunny=o;const c={};for(const e in s)"function"===typeof s[e]&&(c[e]=s[e].bind(s));const l=new Set([...Object.getOwnPropertyNames(o),...Object.getOwnPropertyNames(Object.getPrototypeOf(o))]);for(const e of l)"constructor"!==e&&(e in s||Object.defineProperty(s,e,{get(){const t=o[e];return"function"===typeof t?t.bind(o):t},set(t){o[e]=t},configurable:!0,enumerable:!0}));for(const e in c)s[e]=(...t)=>c[e](...t);function u(){const e=i.template?.$player;e&&!i.option.autoSize&&Object.assign(s.style,{width:"100%",height:"100%",objectFit:"contain"})}return i.on("resize",u),i.on("video:loadedmetadata",u),function({art:t,shim:i,option:r}){if(r.m3u8)return t.on("video:loadedmetadata",d),t.on("restart",d),{update:d};function a(e){t.controls.cache.has(e)&&t.controls.remove(e)}function s(e){t.setting.find(e)&&t.setting.remove(e)}function n(){a("mediabunny-quality"),s("mediabunny-quality")}function o(){a("mediabunny-audio"),s("mediabunny-audio")}function c(e={}){return e.control||e.setting}async function l(a){const s=r.m3u8?.quality||{};if(!c(s)||!a?.levels.length)return void n();const o=s.auto||"Auto",l=s.title||"Quality",u=s.getName||(e=>e.name||`${e.height}P`),h=a.currentLevel?u(a.currentLevel):o,f=e(a.levels.map(e=>({html:u(e),value:e.id,default:a.currentLevel?.id===e.id})),"html").sort((e,t)=>{const i=a.levels.find(t=>t.id===e.value),r=a.levels.find(e=>e.id===t.value);return(r?.height||0)-(i?.height||0)});f.push({html:o,value:"auto",default:!a.currentLevel});const m=async e=>(await i.switchM3u8Quality(e.value),t.notice.show=`${l}: ${e.html}`,await d(),e.html);s.control&&t.controls.update({name:"mediabunny-quality",position:"right",html:h,style:{padding:"0 10px"},selector:f,onSelect:m}),s.setting&&t.setting.update({name:"mediabunny-quality",tooltip:h,html:l,icon:'',width:200,selector:f,onSelect:m})}async function u(a){const s=r.m3u8?.audio||{};if(!c(s)||!a?.audios.length||a.audios.length<2)return void o();const n=s.auto||"Auto",l=s.title||"Audio",u=s.getName||(e=>e.name||e.lang||e.language),h=a.currentAudio?u(a.currentAudio):n,f=e(a.audios.map(e=>({html:u(e),value:e.id,default:a.currentAudio?.id===e.id})),"html");f.push({html:n,value:"auto",default:!a.currentAudio});const m=async e=>(await i.switchM3u8Audio(e.value),t.notice.show=`${l}: ${e.html}`,await d(),e.html);s.control&&t.controls.update({name:"mediabunny-audio",position:"right",html:h,style:{padding:"0 10px"},selector:f,onSelect:m}),s.setting&&t.setting.update({name:"mediabunny-audio",tooltip:h,html:l,icon:'',width:200,selector:f,onSelect:m})}async function d(){const e=await i.getM3u8State();if(!e)return n(),void o();await Promise.all([l(e),u(e)])}}({art:i,shim:o,option:t}),i.on("destroy",()=>{delete i.mediabunny,o.destroy()}),s}}}); diff --git a/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.legacy.js b/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.legacy.js index 979246864..7e89ad8c9 100644 --- a/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.legacy.js +++ b/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.legacy.js @@ -1,7 +1,7 @@ /*! - * artplayer-proxy-mediabunny.js v1.1.0 + * artplayer-proxy-mediabunny.js v1.2.0 * Github: https://github.com/zhw2590582/ArtPlayer * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,r=Object.getOwnPropertyDescriptors,i=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,a=(e,t)=>(t=Symbol[e])?t:Symbol.for("Symbol."+e),o=Math.pow,l=(t,r,i)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[r]=i,c=(e,t)=>{for(var r in t||(t={}))n.call(t,r)&&l(e,r,t[r]);if(i)for(var r of i(t))s.call(t,r)&&l(e,r,t[r]);return e},u=(e,t,r)=>new Promise((i,n)=>{var s=e=>{try{o(r.next(e))}catch(t){n(t)}},a=e=>{try{o(r.throw(e))}catch(t){n(t)}},o=e=>e.done?i(e.value):Promise.resolve(e.value).then(s,a);o((r=r.apply(e,t)).next())}),d=function(e,t){this[0]=e,this[1]=t},h=e=>{var t,r=e[a("asyncIterator")],i=!1,n={};return null==r?(r=e[a("iterator")](),t=e=>n[e]=t=>r[e](t)):(r=r.call(e),t=e=>n[e]=t=>{if(i){if(i=!1,"throw"===e)throw t;return t}return i=!0,{done:!1,value:new d(new Promise(i=>{var n=r[e](t);n instanceof Object||(e=>{throw TypeError(e)})("Object expected"),i(n)}),1)}}),n[a("iterator")]=()=>n,t("next"),"throw"in r?t("throw"):n.throw=e=>{throw e},"return"in r&&t("return"),n},m=(e,t,r)=>(t=e[a("asyncIterator")])?t.call(e):(e=e[a("iterator")](),t={},(r=(r,i)=>(i=e[r])&&(t[r]=t=>new Promise((r,n,s)=>(t=i.call(e,t),s=t.done,Promise.resolve(t.value).then(e=>r({value:e,done:s}),n)))))("next"),r("return"),t);class f{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const r=this.listeners.get(e);if(!r)return;const i=r.indexOf(t);i>=0&&r.splice(i,1)}emit(e,t){const r=new Event(e);r.detail=t;const i=this.listeners.get(e);i&&i.forEach(e=>e(r))}}function p(e){if(!e)throw new Error("Assertion failed.")}const g=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},k=e=>e&&e[e.length-1];class b{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){var e;const t=Math.floor(this.pos/8),r=null!=(e=this.bytes[t])?e:0,i=7-(7&this.pos),n=(r&1<>i;return this.pos++,n}readBits(e){if(1===e)return this.readBit();let t=0;for(let r=0;r>r-i-1<{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<{const t=y(e);return 0===(1&t)?-(t>>1):t+1>>1},S=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),v=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),w=new TextDecoder,I=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),P={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},x=I(P),C={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},_=I(C),B={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},E=I(B),F=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class D{constructor(){this.currentPromise=Promise.resolve()}acquire(){return u(this,null,function*(){let e;const t=new Promise(t=>{e=t}),r=this.currentPromise;return this.currentPromise=t,yield r,e})}}const A=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),R=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,M=(e,t,r)=>{let i=0,n=e.length-1,s=-1;for(;i<=n;){const a=i+n>>1,o=r(e[a]);o===t?(s=a,n=a-1):o{let i=0,n=e.length-1,s=-1;for(;i<=n;){const a=i+(n-i+1)/2|0;r(e[a])<=t?(s=a,i=a+1):n=a-1}return s},z=(e,t,r)=>{const i=N(e,r(t),r);e.splice(i+1,0,t)},O=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},L=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return e[r]},U=(e,t)=>{for(let r=e.length-1;r>=0;r--)if(t(e[r]))return r;return-1},V=function(e){return((e,t,r)=>{var i=(e,t,n,s)=>{try{var a=r[e](t),o=(t=a.value)instanceof d,l=a.done;Promise.resolve(o?t[0]:t).then(r=>o?i("return"===e?e:"next",t[1]?{done:r.done,value:r.value}:r,n,s):n({value:r,done:l})).catch(e=>i("throw",e,n,s))}catch(c){s(c)}},n=e=>s[e]=t=>new Promise((r,n)=>i(e,t,r,n)),s={};return r=r.apply(e,t),s[a("asyncIterator")]=()=>s,n("next"),n("throw"),n("return"),s})(this,null,function*(){Symbol.iterator in e?yield*h(e[Symbol.iterator]()):yield*h(e[Symbol.asyncIterator]())})},q=e=>{throw new Error(`Unexpected value: ${e}`)},H=(e,t,r)=>{const i=e.getUint8(t),n=e.getUint8(t+1),s=e.getUint8(t+2);return r?i|n<<8|s<<16:i<<16|n<<8|s},W=(e,t,r,i)=>{r>>>=0,r&=16777215,e.setUint8(t,r>>>16&255),e.setUint8(t+1,r>>>8&255),e.setUint8(t+2,255&r)},j=(e,t)=>({next(){return u(this,null,function*(){const r=yield e.next();return r.done?{value:void 0,done:!0}:{value:t(r.value),done:!1}})},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),K=(e,t,r)=>Math.max(t,Math.min(r,e)),$="und",Q=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},G=/^[a-z]{3}$/,X=e=>G.test(e),Y=1e6*(1+Number.EPSILON),J=(e,t)=>{const r=c(c({},e),t);if(e.headers||t.headers){const i=e.headers?Z(e.headers):{},n=t.headers?Z(t.headers):{},s=c({},i);Object.entries(n).forEach(([e,t])=>{const r=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());r&&delete s[r],s[e]=t}),r.headers=s}return r},Z=e=>{if(e instanceof Headers){const t={};return e.forEach((e,r)=>{t[r]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,r])=>{t[e]=r}),t}return e},ee=(e,t,r,i,n)=>u(null,null,function*(){let s=0;for(;;)try{return yield e(t,r)}catch(a){if(n())throw a;s++;const e=i(s,a,t);if(null===e)throw a;if(console.error("Retrying failed fetch. Error:",a),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&(yield new Promise(t=>setTimeout(t,1e3*e))),n())throw a}});class te{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let re=null;const ie=()=>{var e;return null!==re?re:re=!("undefined"===typeof navigator||!((null==(e=navigator.vendor)?void 0:e.match(/apple/i))||/AppleWebKit/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)||/\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent)))};let ne=null;const se=()=>{var e;return null!==ne?ne:ne="undefined"!==typeof navigator&&(null==(e=navigator.userAgent)?void 0:e.includes("Firefox"))};let ae=null;const oe=()=>{var e;return null!==ae?ae:ae=!("undefined"===typeof navigator||!(null==(e=navigator.vendor)?void 0:e.includes("Google Inc"))&&!/Chrome/.test(navigator.userAgent))};let le=null;const ce=(e,t)=>-1!==e?e:t,ue=(e,t,r,i)=>e<=i&&r<=t,de=e=>{const t=atob(e),r=new Uint8Array(t.length);for(let i=0;i{null!=Symbol.dispose||(Symbol.dispose=Symbol("Symbol.dispose"))},me=e=>"number"===typeof e&&!Number.isNaN(e);class fe{constructor(e,t){if(this.data=e,this.mimeType=t,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("string"!==typeof t)throw new TypeError("mimeType must be a string.")}}class pe{constructor(e,t,r,i){if(this.data=e,this.mimeType=t,this.name=r,this.description=i,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if(void 0!==t&&"string"!==typeof t)throw new TypeError("mimeType, when provided, must be a string.");if(void 0!==r&&"string"!==typeof r)throw new TypeError("name, when provided, must be a string.");if(void 0!==i&&"string"!==typeof i)throw new TypeError("description, when provided, must be a string.")}}const ge={default:!0,forced:!1,original:!1,commentary:!1,hearingImpaired:!1,visuallyImpaired:!1},ke=["pcm-s16","pcm-s16be","pcm-s24","pcm-s24be","pcm-s32","pcm-s32be","pcm-f32","pcm-f32be","pcm-f64","pcm-f64be","pcm-u8","pcm-s8","ulaw","alaw"],be=[{maxPictureSize:36864,maxBitrate:2e5,level:10},{maxPictureSize:73728,maxBitrate:8e5,level:11},{maxPictureSize:122880,maxBitrate:18e5,level:20},{maxPictureSize:245760,maxBitrate:36e5,level:21},{maxPictureSize:552960,maxBitrate:72e5,level:30},{maxPictureSize:983040,maxBitrate:12e6,level:31},{maxPictureSize:2228224,maxBitrate:18e6,level:40},{maxPictureSize:2228224,maxBitrate:3e7,level:41},{maxPictureSize:8912896,maxBitrate:6e7,level:50},{maxPictureSize:8912896,maxBitrate:12e7,level:51},{maxPictureSize:8912896,maxBitrate:18e7,level:52},{maxPictureSize:35651584,maxBitrate:18e7,level:60},{maxPictureSize:35651584,maxBitrate:24e7,level:61},{maxPictureSize:35651584,maxBitrate:48e7,level:62}],ye=".01.01.01.01.00",Te=".0.110.01.01.01.0",Se=e=>{const{codec:t,codecDescription:r,colorSpace:i,avcCodecInfo:n,hevcCodecInfo:s,vp9CodecInfo:a,av1CodecInfo:o}=e;if("avc"===t){if(p(null!==e.avcType),n){const t=new Uint8Array([n.avcProfileIndication,n.profileCompatibility,n.avcLevelIndication]);return`avc${e.avcType}.${A(t)}`}if(!r||r.byteLength<4)throw new TypeError("AVC decoder description is not provided or is not at least 4 bytes long.");return`avc${e.avcType}.${A(r.subarray(1,4))}`}if("hevc"===t){let e,t,i,n,a,o;if(s)e=s.generalProfileSpace,t=s.generalProfileIdc,i=R(s.generalProfileCompatibilityFlags),n=s.generalTierFlag,a=s.generalLevelIdc,o=[...s.generalConstraintIndicatorFlags];else{if(!r||r.byteLength<23)throw new TypeError("HEVC decoder description is not provided or is not at least 23 bytes long.");const s=v(r),l=s.getUint8(1);e=l>>6&3,t=31&l,i=R(s.getUint32(2)),n=l>>5&1,a=s.getUint8(12),o=[];for(let e=0;e<6;e++)o.push(s.getUint8(6+e))}let l="hev1.";for(l+=["","A","B","C"][e]+t,l+=".",l+=i.toString(16).toUpperCase(),l+=".",l+=0===n?"L":"H",l+=a;o.length>0&&0===o[o.length-1];)o.pop();return o.length>0&&(l+=".",l+=o.map(e=>e.toString(16).toUpperCase()).join(".")),l}if("vp8"===t)return"vp8";if("vp9"===t){if(!a){const t=e.width*e.height;let r=k(be).level;for(const e of be)if(t<=e.maxPictureSize){r=e.level;break}return`vp09.00.${r.toString().padStart(2,"0")}.08`}let t=`vp09.${a.profile.toString().padStart(2,"0")}.${a.level.toString().padStart(2,"0")}.${a.bitDepth.toString().padStart(2,"0")}.${a.chromaSubsampling.toString().padStart(2,"0")}`;return t+=`.${a.colourPrimaries.toString().padStart(2,"0")}.${a.transferCharacteristics.toString().padStart(2,"0")}.${a.matrixCoefficients.toString().padStart(2,"0")}.${a.videoFullRangeFlag.toString().padStart(2,"0")}`,t.endsWith(ye)&&(t=t.slice(0,-15)),t}if("av1"===t){if(!o){const t=e.width*e.height;let r=k(be).level;for(const e of be)if(t<=e.maxPictureSize){r=e.level;break}return`av01.0.${r.toString().padStart(2,"0")}M.08`}const t=o.profile,r=o.level.toString().padStart(2,"0"),n=o.tier?"H":"M",s=o.bitDepth.toString().padStart(2,"0"),a=o.monochrome?"1":"0",l=100*o.chromaSubsamplingX+10*o.chromaSubsamplingY+1*(o.chromaSubsamplingX&&o.chromaSubsamplingY?o.chromaSamplePosition:0),c=(null==i?void 0:i.primaries)?P[i.primaries]:1,u=(null==i?void 0:i.transfer)?C[i.transfer]:1,d=(null==i?void 0:i.matrix)?B[i.matrix]:1,h=(null==i?void 0:i.fullRange)?1:0;let m=`av01.${t}.${r}${n}.${s}`;return m+=`.${a}.${l.toString().padStart(3,"0")}`,m+=`.${c.toString().padStart(2,"0")}`,m+=`.${u.toString().padStart(2,"0")}`,m+=`.${d.toString().padStart(2,"0")}`,m+=`.${h}`,m.endsWith(Te)&&(m=m.slice(0,-17)),m}throw new TypeError(`Unhandled codec '${t}'.`)},ve=e=>{const{codec:t,codecDescription:r,aacCodecInfo:i}=e;if("aac"===t){if(!i)throw new TypeError("AAC codec info must be provided.");if(i.isMpeg2)return"mp4a.67";return`mp4a.40.${Pe(r).objectType}`}if("mp3"===t)return"mp3";if("opus"===t)return"opus";if("vorbis"===t)return"vorbis";if("flac"===t)return"flac";if(t&&ke.includes(t))return t;throw new TypeError(`Unhandled codec '${t}'.`)},we=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350],Ie=[-1,1,2,3,4,5,6,8],Pe=e=>{if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");const t=new b(e);let r=t.readBits(5);31===r&&(r=32+t.readBits(6));const i=t.readBits(4);let n=null;15===i?n=t.readBits(24):i=1&&s<=7&&(a=Ie[s]),{objectType:r,frequencyIndex:i,sampleRate:n,channelConfiguration:s,numberOfChannels:a}},xe=48e3,Ce=/^pcm-([usf])(\d+)+(be)?$/,_e=e=>{if(p(ke.includes(e)),"ulaw"===e)return{dataType:"ulaw",sampleSize:1,littleEndian:!0,silentValue:255};if("alaw"===e)return{dataType:"alaw",sampleSize:1,littleEndian:!0,silentValue:213};const t=Ce.exec(e);let r;p(t),r="u"===t[1]?"unsigned":"s"===t[1]?"signed":"float";return{dataType:r,sampleSize:Number(t[2])/8,littleEndian:"be"!==t[3],silentValue:"pcm-u8"===e?o(2,7):0}};var Be,Ee,Fe,De;(Ee=Be||(Be={}))[Ee.IDR=5]="IDR",Ee[Ee.SEI=6]="SEI",Ee[Ee.SPS=7]="SPS",Ee[Ee.PPS=8]="PPS",Ee[Ee.SPS_EXT=13]="SPS_EXT",(De=Fe||(Fe={}))[De.RASL_N=8]="RASL_N",De[De.RASL_R=9]="RASL_R",De[De.BLA_W_LP=16]="BLA_W_LP",De[De.RSV_IRAP_VCL23=23]="RSV_IRAP_VCL23",De[De.VPS_NUT=32]="VPS_NUT",De[De.SPS_NUT=33]="SPS_NUT",De[De.PPS_NUT=34]="PPS_NUT",De[De.PREFIX_SEI_NUT=39]="PREFIX_SEI_NUT",De[De.SUFFIX_SEI_NUT=40]="SUFFIX_SEI_NUT";const Ae=e=>{const t=[];let r=0;for(;r0&&i>r){const n=e.subarray(r,i);n.length>0&&t.push(n)}r=i+n}if(r0&&t.push(i)}return t},Re=(e,t)=>{const r=[];let i=0;const n=new DataView(e.buffer,e.byteOffset,e.byteLength);for(;i+t<=e.length;){let s;1===t?s=n.getUint8(i):2===t?s=n.getUint16(i,!1):3===t?s=H(n,i,!1):4===t?s=n.getUint32(i,!1):(q(t),p(!1)),i+=t;const a=e.subarray(i,i+s);r.push(a),i+=s}return r},Me=e=>{const t=[],r=e.length;for(let i=0;i{if(t.description){const r=3&S(t.description)[4];return Re(e,r+1)}return Ae(e)},Oe=(e,t)=>{if(t.description){return((e,t)=>{const r=e.reduce((e,r)=>e+t+r.byteLength,0),i=new Uint8Array(r);let n=0;for(const s of e){const e=new DataView(i.buffer,i.byteOffset,i.byteLength);switch(t){case 1:e.setUint8(n,s.byteLength);break;case 2:e.setUint16(n,s.byteLength,!1);break;case 3:W(e,n,s.byteLength);break;case 4:e.setUint32(n,s.byteLength,!1)}n+=t,i.set(s,n),n+=s.byteLength}return i})(e,(3&S(t.description)[4])+1)}return(e=>{const t=e.reduce((e,t)=>e+Ne.byteLength+t.byteLength,0),r=new Uint8Array(t);let i=0;for(const n of e)r.set(Ne,i),i+=Ne.byteLength,r.set(n,i),i+=n.byteLength;return r})(e)},Le=e=>31&e[0],Ue=e=>{try{const t=Ae(e),r=t.filter(e=>Le(e)===Be.SPS),i=t.filter(e=>Le(e)===Be.PPS),n=t.filter(e=>Le(e)===Be.SPS_EXT);if(0===r.length)return null;if(0===i.length)return null;const s=r[0],a=Ve(s);p(null!==a);const o=100===a.profileIdc||110===a.profileIdc||122===a.profileIdc||144===a.profileIdc;return{configurationVersion:1,avcProfileIndication:a.profileIdc,profileCompatibility:a.constraintFlags,avcLevelIndication:a.levelIdc,lengthSizeMinusOne:3,sequenceParameterSets:r,pictureParameterSets:i,chromaFormat:o?a.chromaFormatIdc:null,bitDepthLumaMinus8:o?a.bitDepthLumaMinus8:null,bitDepthChromaMinus8:o?a.bitDepthChromaMinus8:null,sequenceParameterSetExt:o?n:null}}catch(t){return console.error("Error building AVC Decoder Configuration Record:",t),null}},Ve=e=>{try{const t=new b(Me(e));t.skipBits(1),t.skipBits(2);if(7!==t.readBits(5))return null;const r=t.readAlignedByte(),i=t.readAlignedByte(),n=t.readAlignedByte();y(t);let s=null,a=null,o=null;if(100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r){s=y(t),3===s&&t.skipBits(1),a=y(t),o=y(t),t.skipBits(1);if(t.readBits(1))for(let e=0;e<(3!==s?8:12);e++){if(t.readBits(1)){const r=e<6?16:64;let i=8,n=8;for(let e=0;e{if(t.description){const r=3&S(t.description)[21];return Re(e,r+1)}return Ae(e)},He=e=>e[0]>>1&63,We=e=>{try{const t=Ae(e),r=t.filter(e=>He(e)===Fe.VPS_NUT),i=t.filter(e=>He(e)===Fe.SPS_NUT),n=t.filter(e=>He(e)===Fe.PPS_NUT),s=t.filter(e=>He(e)===Fe.PREFIX_SEI_NUT||He(e)===Fe.SUFFIX_SEI_NUT);if(0===i.length||0===n.length)return null;const a=i[0],o=new b(Me(a));o.skipBits(16),o.readBits(4);const l=o.readBits(3),c=o.readBits(1),{general_profile_space:u,general_tier_flag:d,general_profile_idc:h,general_profile_compatibility_flags:m,general_constraint_indicator_flags:f,general_level_idc:p}=je(o,l);y(o);const g=y(o);3===g&&o.skipBits(1),y(o),y(o),o.readBits(1)&&(y(o),y(o),y(o),y(o));const k=y(o),S=y(o);y(o);const v=o.readBits(1);for(let e=v?0:l;e<=l;e++)y(o),y(o),y(o);y(o),y(o),y(o),y(o),y(o),y(o),o.readBits(1)&&o.readBits(1)&&Ke(o),o.skipBits(1),o.skipBits(1),o.readBits(1)&&(o.skipBits(4),o.skipBits(4),y(o),y(o),o.skipBits(1));const w=y(o);if($e(o,w),o.readBits(1)){const e=y(o);for(let t=0;t0){const e=n[0],t=new b(Me(e));t.skipBits(16),y(t),y(t),t.skipBits(1),t.skipBits(1),t.skipBits(3),t.skipBits(1),t.skipBits(1),y(t),y(t),T(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&y(t),T(t),T(t),t.skipBits(1),t.skipBits(1),t.skipBits(1),t.skipBits(1);const r=t.readBits(1),i=t.readBits(1);P=r||i?r&&!i?2:!r&&i?3:0:0}const x=[...r.length?[{arrayCompleteness:1,nalUnitType:Fe.VPS_NUT,nalUnits:r}]:[],...i.length?[{arrayCompleteness:1,nalUnitType:Fe.SPS_NUT,nalUnits:i}]:[],...n.length?[{arrayCompleteness:1,nalUnitType:Fe.PPS_NUT,nalUnits:n}]:[],...s.length?[{arrayCompleteness:1,nalUnitType:He(s[0]),nalUnits:s}]:[]];return{configurationVersion:1,generalProfileSpace:u,generalTierFlag:d,generalProfileIdc:h,generalProfileCompatibilityFlags:m,generalConstraintIndicatorFlags:f,generalLevelIdc:p,minSpatialSegmentationIdc:I,parallelismType:P,chromaFormatIdc:g,bitDepthLumaMinus8:k,bitDepthChromaMinus8:S,avgFrameRate:0,constantFrameRate:0,numTemporalLayers:l+1,temporalIdNested:c,lengthSizeMinusOne:3,arrays:x}}catch(t){return console.error("Error building HEVC Decoder Configuration Record:",t),null}},je=(e,t)=>{const r=e.readBits(2),i=e.readBits(1),n=e.readBits(5);let s=0;for(let u=0;u<32;u++)s=s<<1|e.readBits(1);const a=new Uint8Array(6);for(let u=0;u<6;u++)a[u]=e.readBits(8);const o=e.readBits(8),l=[],c=[];for(let u=0;u0)for(let u=t;u<8;u++)e.skipBits(2);for(let u=0;u{for(let t=0;t<4;t++)for(let r=0;r<(3===t?2:6);r++){if(e.readBits(1)){const r=Math.min(64,1<<4+(t<<1));t>1&&T(e);for(let t=0;t{const r=[];for(let i=0;i{var n;let s=0,a=0,o=0;if(0!==t&&(a=e.readBits(1)),a){if(t===r){o=t-(y(e)+1)}else o=t-1;e.readBits(1),y(e);const a=null!=(n=i[o])?n:0;for(let t=0;t<=a;t++){e.readBits(1)||e.readBits(1)}s=i[o]}else{const t=y(e),r=y(e);for(let i=0;i{if(e.readBits(1)){255===e.readBits(8)&&(e.readBits(16),e.readBits(16))}if(e.readBits(1)&&e.readBits(1),e.readBits(1)&&(e.readBits(3),e.readBits(1),e.readBits(1)&&(e.readBits(8),e.readBits(8),e.readBits(8))),e.readBits(1)&&(y(e),y(e)),e.readBits(1),e.readBits(1),e.readBits(1),e.readBits(1)&&(y(e),y(e),y(e),y(e)),e.readBits(1)&&(e.readBits(32),e.readBits(32),e.readBits(1)&&y(e),e.readBits(1)&&Xe(e,!0,t)),e.readBits(1)){e.readBits(1),e.readBits(1),e.readBits(1);const t=y(e);return y(e),y(e),y(e),y(e),t}return 0},Xe=(e,t,r)=>{let i=!1,n=!1,s=!1;i=1===e.readBits(1),n=1===e.readBits(1),(i||n)&&(s=1===e.readBits(1),s&&(e.readBits(8),e.readBits(5),e.readBits(1),e.readBits(5)),e.readBits(4),e.readBits(4),s&&e.readBits(4),e.readBits(5),e.readBits(5),e.readBits(5));for(let a=0;a<=r;a++){let t=!0;1===e.readBits(1)||(t=1===e.readBits(1));let r=!1;t?y(e):r=1===e.readBits(1);let a=1;if(!r){a=y(e)+1}i&&Ye(e,a,s),n&&Ye(e,a,s)}},Ye=(e,t,r)=>{for(let i=0;i{const t=new b(e);if(2!==t.readBits(2))return null;const r=t.readBits(1),i=(t.readBits(1)<<1)+r;3===i&&t.skipBits(1);if(1===t.readBits(1))return null;if(0!==t.readBits(1))return null;t.skipBits(2);if(4817730!==t.readBits(24))return null;let n=8;if(i>=2){n=t.readBits(1)?12:10}const s=t.readBits(3);let a=0,o=0;if(7!==s){if(o=t.readBits(1),1===i||3===i){const e=t.readBits(1),r=t.readBits(1);a=e||r?e&&!r?2:1:3,t.skipBits(1)}else a=1}else a=3,o=1;const l=(t.readBits(16)+1)*(t.readBits(16)+1);let c=k(be).level;for(const u of be)if(l<=u.maxPictureSize){c=u.level;break}return{profile:i,level:c,bitDepth:n,chromaSubsampling:a,videoFullRangeFlag:o,colourPrimaries:2===s?1:1===s?6:2,transferCharacteristics:2===s?1:1===s?6:2,matrixCoefficients:7===s?0:2===s?1:1===s?6:2}},Ze=function*(e){const t=new b(e),r=()=>{let e=0;for(let r=0;r<8;r++){const i=t.readAlignedByte();if(e|=(127&i)<<7*r,!(128&i))break;if(7===r&&128&i)return null}return e>=o(2,32)-1?null:e};for(;t.getBitsLeft()>=8;){t.skipBits(1);const i=t.readBits(4),n=t.readBits(1),s=t.readBits(1);let a;if(t.skipBits(1),n&&t.skipBits(8),s){const e=r();if(null===e)return;a=e}else a=Math.floor(t.getBitsLeft()/8);p(t.pos%8===0),yield{type:i,data:e.subarray(t.pos/8,t.pos/8+a)},t.skipBits(8*a)}},et=e=>{for(const{type:t,data:r}of Ze(e)){if(1!==t)continue;const e=new b(r),i=e.readBits(3);e.readBits(1);const n=e.readBits(1);let s=0,a=0,o=0;if(n)s=e.readBits(5);else{if(e.readBits(1)){e.skipBits(32),e.skipBits(32);if(e.readBits(1))return null}const t=e.readBits(1);t&&(o=e.readBits(5),e.skipBits(32),e.skipBits(5),e.skipBits(5));const r=e.readBits(5);for(let i=0;i<=r;i++){e.skipBits(12);const r=e.readBits(5);if(0===i&&(s=r),r>7){const t=e.readBits(1);0===i&&(a=t)}if(t){if(e.readBits(1)){const t=o+1;e.skipBits(t),e.skipBits(t),e.skipBits(1)}}e.readBits(1)&&e.skipBits(4)}}const l=e.readBits(4),c=e.readBits(4),u=l+1;e.skipBits(u);const d=c+1;e.skipBits(d);let h=0;if(h=n?0:e.readBits(1),h&&(e.skipBits(4),e.skipBits(3)),e.skipBits(1),e.skipBits(1),e.skipBits(1),!n){e.skipBits(1),e.skipBits(1),e.skipBits(1),e.skipBits(1);const t=e.readBits(1);t&&(e.skipBits(1),e.skipBits(1));let r=0;if(r=e.readBits(1)?2:e.readBits(1),r>0){e.readBits(1)||e.skipBits(1)}t&&e.skipBits(3)}e.skipBits(1),e.skipBits(1),e.skipBits(1);const m=e.readBits(1);let f=8;if(2===i&&m){f=e.readBits(1)?12:10}else i<=2&&(f=m?10:8);let p=0;1!==i&&(p=e.readBits(1));let g=1,k=1,y=0;return p||(0===i?(g=1,k=1):1===i?(g=0,k=0):12===f&&(g=e.readBits(1),g&&(k=e.readBits(1))),g&&k&&(y=e.readBits(2))),{profile:i,level:s,tier:a,bitDepth:f,monochrome:p,chromaSubsamplingX:g,chromaSubsamplingY:k,chromaSamplePosition:y}}return null},tt=[480,960,1920,2880,480,960,1920,2880,480,960,1920,2880,480,960,480,960,120,240,480,960,120,240,480,960,120,240,480,960,120,240,480,960],rt=e=>{if(e.length<7)throw new Error("Setup header is too short.");if(5!==e[0])throw new Error("Wrong packet type in Setup header.");if("vorbis"!==String.fromCharCode(...e.slice(1,7)))throw new Error("Invalid packet signature in Setup header.");const t=e.length,r=new Uint8Array(t);for(let u=0;u97;)if(1===i.readBits(1)){n=i.pos;break}if(0===n)throw new Error("Invalid Setup header: framing bit not found.");let s=0,a=!1,o=0;for(;i.getBitsLeft()>=97;){const e=i.pos,t=i.readBits(8),r=i.readBits(16),n=i.readBits(16);if(t>63||0!==r||0!==n){i.pos=e;break}if(i.skipBits(1),s++,s>64)break;i.clone().readBits(6)+1===s&&(a=!0,o=s)}if(!a)throw new Error("Invalid Setup header: mode header not found.");if(o>63)throw new Error(`Unsupported mode count: ${o}.`);const l=o;i.pos=0,i.skipBits(n);const c=Array(l).fill(0);for(let u=l-1;u>=0;u--)i.skipBits(40),c[u]=i.readBits(1);return{modeBlockflags:c}},it=(e,t,r)=>{switch(e){case"avc":{const e=ze(r,t);let i=e.some(e=>Le(e)===Be.IDR);if(!i&&(!oe()||(()=>{if(null!==le)return le;if("undefined"===typeof navigator)return null;const e=/\bChrome\/(\d+)/.exec(navigator.userAgent);return e?le=Number(e[1]):null})()>=144))for(const t of e){if(Le(t)!==Be.SEI)continue;const e=Me(t);let r=1;do{let t=0;for(;;){const i=e[r++];if(void 0===i)break;if(t+=i,i<255)break}let n=0;for(;;){const t=e[r++];if(void 0===t)break;if(n+=t,t<255)break}if(t===6){const t=new b(e);t.pos=8*r;const n=y(t),s=t.readBits(1);if(0===n&&1===s){i=!0;break}}r+=n}while(r{const t=He(e);return Fe.BLA_W_LP<=t&&t<=Fe.RSV_IRAP_VCL23})?"key":"delta";case"vp8":return 0===(1&r[0])?"key":"delta";case"vp9":{const e=new b(r);if(2!==e.readBits(2))return null;const t=e.readBits(1);3===(e.readBits(1)<<1)+t&&e.skipBits(1);if(e.readBits(1))return null;return 0===e.readBits(1)?"key":"delta"}case"av1":{let e=!1;for(const{type:t,data:i}of Ze(r))if(1===t){const t=new b(i);t.skipBits(4),e=!!t.readBits(1)}else if(3===t||6===t||7===t){if(e)return"key";const t=new b(i);if(t.readBits(1))return null;return 0===t.readBits(2)?"key":"delta"}return null}default:q(e),p(!1)}};var nt,st;(st=nt||(nt={}))[st.STREAMINFO=0]="STREAMINFO",st[st.VORBIS_COMMENT=4]="VORBIS_COMMENT",st[st.PICTURE=6]="PICTURE";const at=(e,t)=>{var r,i;const n=v(e);let s=0;const a=n.getUint32(s,!0);s+=4;const o=w.decode(e.subarray(s,s+a));s+=a,a>0&&(null!=t.raw||(t.raw={}),null!=(r=t.raw).vendor||(r.vendor=o));const l=n.getUint32(s,!0);s+=4;for(let c=0;c0&&(null!=t.trackNumber||(t.trackNumber=r)),i&&Number.isInteger(i)&&i>0&&(null!=t.tracksTotal||(t.tracksTotal=i))}break;case"TRACKTOTAL":{const e=Number.parseInt(c,10);Number.isInteger(e)&&e>0&&(null!=t.tracksTotal||(t.tracksTotal=e))}break;case"DISCNUMBER":{const e=c.split("/"),r=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(null!=t.discNumber||(t.discNumber=r)),i&&Number.isInteger(i)&&i>0&&(null!=t.discsTotal||(t.discsTotal=i))}break;case"DISCTOTAL":{const e=Number.parseInt(c,10);Number.isInteger(e)&&e>0&&(null!=t.discsTotal||(t.discsTotal=e))}break;case"DATE":{const e=new Date(c);Number.isNaN(e.getTime())||null!=t.date||(t.date=e)}break;case"GENRE":null!=t.genre||(t.genre=c);break;case"METADATA_BLOCK_PICTURE":{const e=de(c),r=v(e),i=r.getUint32(0,!1),n=r.getUint32(4,!1),s=String.fromCharCode(...e.subarray(8,8+n)),a=r.getUint32(8+n,!1),o=w.decode(e.subarray(12+n,12+n+a)),l=r.getUint32(n+a+28),u=e.subarray(n+a+32,n+a+32+l);null!=t.images||(t.images=[]),t.images.push({data:u,mimeType:s,kind:3===i?"coverFront":4===i?"coverBack":"unknown",name:void 0,description:o||void 0})}}}};class ot{constructor(e){this.input=e}}const lt=[],ct=[],ut=new Uint8Array(0);class dt{constructor(e,t,r,i,n=-1,s,a){if(this.data=e,this.type=t,this.timestamp=r,this.duration=i,this.sequenceNumber=n,e===ut&&void 0===s)throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets.");if(void 0===s&&(s=e.byteLength),!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("key"!==t&&"delta"!==t)throw new TypeError('type must be either "key" or "delta".');if(!Number.isFinite(r))throw new TypeError("timestamp must be a number.");if(!Number.isFinite(i)||i<0)throw new TypeError("duration must be a non-negative number.");if(!Number.isFinite(n))throw new TypeError("sequenceNumber must be a number.");if(!Number.isInteger(s)||s<0)throw new TypeError("byteLength must be a non-negative integer.");if(void 0!==a&&("object"!==typeof a||!a))throw new TypeError("sideData, when provided, must be an object.");if(void 0!==(null==a?void 0:a.alpha)&&!(a.alpha instanceof Uint8Array))throw new TypeError("sideData.alpha, when provided, must be a Uint8Array.");if(void 0!==(null==a?void 0:a.alphaByteLength)&&(!Number.isInteger(a.alphaByteLength)||a.alphaByteLength<0))throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer.");this.byteLength=s,this.sideData=null!=a?a:{},this.sideData.alpha&&void 0===this.sideData.alphaByteLength&&(this.sideData.alphaByteLength=this.sideData.alpha.byteLength)}get isMetadataOnly(){return this.data===ut}get microsecondTimestamp(){return Math.trunc(Y*this.timestamp)}get microsecondDuration(){return Math.trunc(Y*this.duration)}toEncodedVideoChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}alphaToEncodedVideoChunk(e=this.type){if(!this.sideData.alpha)throw new TypeError("This packet does not contain alpha side data.");if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.sideData.alpha,type:e,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}toEncodedAudioChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to an audio chunk.");if("undefined"===typeof EncodedAudioChunk)throw new Error("Your browser does not support EncodedAudioChunk.");return new EncodedAudioChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}static fromEncodedChunk(e,t){var r;if(!(e instanceof EncodedVideoChunk||e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk.");const i=new Uint8Array(e.byteLength);return e.copyTo(i),new dt(i,e.type,e.timestamp/1e6,(null!=(r=e.duration)?r:0)/1e6,void 0,void 0,t)}clone(e){var t,r;if(void 0!==e&&("object"!==typeof e||null===e))throw new TypeError("options, when provided, must be an object.");if(void 0!==(null==e?void 0:e.timestamp)&&!Number.isFinite(e.timestamp))throw new TypeError("options.timestamp, when provided, must be a number.");if(void 0!==(null==e?void 0:e.duration)&&!Number.isFinite(e.duration))throw new TypeError("options.duration, when provided, must be a number.");return new dt(this.data,this.type,null!=(t=null==e?void 0:e.timestamp)?t:this.timestamp,null!=(r=null==e?void 0:e.duration)?r:this.duration,this.sequenceNumber,this.byteLength)}}he();let ht=-1/0,mt=-1/0,ft=null;"undefined"!==typeof FinalizationRegistry&&(ft=new FinalizationRegistry(e=>{const t=Date.now();"video"===e.type?(t-ht>=1e3&&(console.error("A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them."),ht=t),"undefined"!==typeof VideoFrame&&e.data instanceof VideoFrame&&e.data.close()):(t-mt>=1e3&&(console.error("An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them."),mt=t),"undefined"!==typeof AudioData&&e.data instanceof AudioData&&e.data.close())}));const pt=["I420","I420P10","I420P12","I420A","I420AP10","I420AP12","I422","I422P10","I422P12","I422A","I422AP10","I422AP12","I444","I444P10","I444P12","I444A","I444AP10","I444AP12","NV12","RGBA","RGBX","BGRA","BGRX"],gt=new Set(pt);class kt{get displayWidth(){return this.rotation%180===0?this.codedWidth:this.codedHeight}get displayHeight(){return this.rotation%180===0?this.codedHeight:this.codedWidth}get microsecondTimestamp(){return Math.trunc(Y*this.timestamp)}get microsecondDuration(){return Math.trunc(Y*this.duration)}get hasAlpha(){return this.format&&this.format.includes("A")}constructor(e,t){var r,i,n,s,a,o,l,c,u,d;if(this._closed=!1,e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e)){if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0===t.format||!gt.has(t.format))throw new TypeError("init.format must be one of: "+pt.join(", "));if(!Number.isInteger(t.codedWidth)||t.codedWidth<=0)throw new TypeError("init.codedWidth must be a positive integer.");if(!Number.isInteger(t.codedHeight)||t.codedHeight<=0)throw new TypeError("init.codedHeight must be a positive integer.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");this._data=S(e).slice(),this._layout=null!=(r=t.layout)?r:wt(t.format,t.codedWidth,t.codedHeight),this.format=t.format,this.codedWidth=t.codedWidth,this.codedHeight=t.codedHeight,this.rotation=null!=(i=t.rotation)?i:0,this.timestamp=t.timestamp,this.duration=null!=(n=t.duration)?n:0,this.colorSpace=new bt(t.colorSpace)}else if("undefined"!==typeof VideoFrame&&e instanceof VideoFrame){if(void 0!==(null==t?void 0:t.rotation)&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(void 0!==(null==t?void 0:t.timestamp)&&!Number.isFinite(null==t?void 0:t.timestamp))throw new TypeError("init.timestamp, when provided, must be a number.");if(void 0!==(null==t?void 0:t.duration)&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");this._data=e,this._layout=null,this.format=e.format,this.codedWidth=e.displayWidth,this.codedHeight=e.displayHeight,this.rotation=null!=(s=null==t?void 0:t.rotation)?s:0,this.timestamp=null!=(a=null==t?void 0:t.timestamp)?a:e.timestamp/1e6,this.duration=null!=(l=null==t?void 0:t.duration)?l:(null!=(o=e.duration)?o:0)/1e6,this.colorSpace=new bt(e.colorSpace)}else{if(!("undefined"!==typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!==typeof SVGImageElement&&e instanceof SVGImageElement||"undefined"!==typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!==typeof HTMLVideoElement&&e instanceof HTMLVideoElement||"undefined"!==typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!==typeof OffscreenCanvas&&e instanceof OffscreenCanvas))throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource.");{if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if("undefined"!==typeof VideoFrame)return new kt(new VideoFrame(e,{timestamp:Math.trunc(t.timestamp*Y),duration:Math.trunc((null!=(c=t.duration)?c:0)*Y)||void 0}),t);let r=0,i=0;if("naturalWidth"in e?(r=e.naturalWidth,i=e.naturalHeight):"videoWidth"in e?(r=e.videoWidth,i=e.videoHeight):"width"in e&&(r=Number(e.width),i=Number(e.height)),!r||!i)throw new TypeError("Could not determine dimensions.");const n=new OffscreenCanvas(r,i),s=n.getContext("2d",{alpha:se(),willReadFrequently:!0});p(s),s.drawImage(e,0,0),this._data=n,this._layout=null,this.format="RGBX",this.codedWidth=r,this.codedHeight=i,this.rotation=null!=(u=t.rotation)?u:0,this.timestamp=t.timestamp,this.duration=null!=(d=t.duration)?d:0,this.colorSpace=new bt({matrix:"rgb",primaries:"bt709",transfer:"iec61966-2-1",fullRange:!0})}}null==ft||ft.register(this,{type:"video",data:this._data},this)}clone(){if(this._closed)throw new Error("VideoSample is closed.");return p(null!==this._data),yt(this._data)?new kt(this._data.clone(),{timestamp:this.timestamp,duration:this.duration,rotation:this.rotation}):this._data instanceof Uint8Array?(p(this._layout),new kt(this._data,{format:this.format,layout:this._layout,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation})):new kt(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation})}close(){this._closed||(null==ft||ft.unregister(this),yt(this._data)?this._data.close():this._data=null,this._closed=!0)}allocationSize(e={}){if(vt(e),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot get allocation size when format is null. Sorry!");if(p(null!==this._data),!yt(this._data)&&(e.colorSpace||e.format&&e.format!==this.format||e.layout||e.rect)){const t=this.toVideoFrame(),r=t.allocationSize(e);return t.close(),r}return yt(this._data)?this._data.allocationSize(e):this._data instanceof Uint8Array?this._data.byteLength:this.codedWidth*this.codedHeight*4}copyTo(e){return u(this,arguments,function*(e,t={}){if(!F(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(vt(t),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot copy video sample data when format is null. Sorry!");if(p(null!==this._data),!yt(this._data)&&(t.colorSpace||t.format&&t.format!==this.format||t.layout||t.rect)){const r=this.toVideoFrame(),i=yield r.copyTo(e,t);return r.close(),i}if(yt(this._data))return this._data.copyTo(e,t);if(this._data instanceof Uint8Array){p(this._layout);return S(e).set(this._data),this._layout}{const t=this._data.getContext("2d");p(t);const r=t.getImageData(0,0,this.codedWidth,this.codedHeight);return S(e).set(r.data),[{offset:0,stride:4*this.codedWidth}]}})}toVideoFrame(){if(this._closed)throw new Error("VideoSample is closed.");return p(null!==this._data),yt(this._data)?new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0}):this._data instanceof Uint8Array?new VideoFrame(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0,colorSpace:this.colorSpace}):new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0})}draw(e,t,r,i,n,s,a,o,l){let c=0,u=0,d=this.displayWidth,h=this.displayHeight,m=0,f=0,p=this.displayWidth,g=this.displayHeight;if(void 0!==s?(c=t,u=r,d=i,h=n,m=s,f=a,void 0!==o?(p=o,g=l):(p=d,g=h)):(m=t,f=r,void 0!==i&&(p=i,g=n)),!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!Number.isFinite(c))throw new TypeError("sx must be a number.");if(!Number.isFinite(u))throw new TypeError("sy must be a number.");if(!Number.isFinite(d)||d<0)throw new TypeError("sWidth must be a non-negative number.");if(!Number.isFinite(h)||h<0)throw new TypeError("sHeight must be a non-negative number.");if(!Number.isFinite(m))throw new TypeError("dx must be a number.");if(!Number.isFinite(f))throw new TypeError("dy must be a number.");if(!Number.isFinite(p)||p<0)throw new TypeError("dWidth must be a non-negative number.");if(!Number.isFinite(g)||g<0)throw new TypeError("dHeight must be a non-negative number.");if(this._closed)throw new Error("VideoSample is closed.");({sx:c,sy:u,sWidth:d,sHeight:h}=this._rotateSourceRegion(c,u,d,h,this.rotation));const k=this.toCanvasImageSource();e.save();const b=m+p/2,y=f+g/2;e.translate(b,y),e.rotate(this.rotation*Math.PI/180);const T=this.rotation%180===0?1:p/g;e.scale(1/T,T),e.drawImage(k,c,u,d,h,-p/2,-g/2,p,g),e.restore()}drawWithFit(e,t){var r,i,n,s,a,o,l,c,u;if(!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!["fill","contain","cover"].includes(t.fit))throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270.");void 0!==t.crop&&St(t.crop,"options.");const d=e.canvas.width,h=e.canvas.height,m=null!=(r=t.rotation)?r:this.rotation,[f,p]=m%180===0?[this.codedWidth,this.codedHeight]:[this.codedHeight,this.codedWidth];let g,k,b,y;t.crop&&Tt(t.crop,f,p);const{sx:T,sy:S,sWidth:v,sHeight:w}=this._rotateSourceRegion(null!=(n=null==(i=t.crop)?void 0:i.left)?n:0,null!=(a=null==(s=t.crop)?void 0:s.top)?a:0,null!=(l=null==(o=t.crop)?void 0:o.width)?l:f,null!=(u=null==(c=t.crop)?void 0:c.height)?u:p,m);if("fill"===t.fit)g=0,k=0,b=d,y=h;else{const[e,r]=t.crop?[t.crop.width,t.crop.height]:[f,p],i="contain"===t.fit?Math.min(d/e,h/r):Math.max(d/e,h/r);b=e*i,y=r*i,g=(d-b)/2,k=(h-y)/2}e.save();const I=m%180===0?1:b/y;e.translate(d/2,h/2),e.rotate(m*Math.PI/180),e.scale(1/I,I),e.translate(-d/2,-h/2),e.drawImage(this.toCanvasImageSource(),T,S,v,w,g,k,b,y),e.restore()}_rotateSourceRegion(e,t,r,i,n){return 90===n?[e,t,r,i]=[t,this.codedHeight-e-r,i,r]:180===n?[e,t]=[this.codedWidth-e-r,this.codedHeight-t-i]:270===n&&([e,t,r,i]=[this.codedWidth-t-i,e,i,r]),{sx:e,sy:t,sWidth:r,sHeight:i}}toCanvasImageSource(){if(this._closed)throw new Error("VideoSample is closed.");if(p(null!==this._data),this._data instanceof Uint8Array){const e=this.toVideoFrame();return queueMicrotask(()=>e.close()),e}return this._data}setRotation(e){if(![0,90,180,270].includes(e))throw new TypeError("newRotation must be 0, 90, 180, or 270.");this.rotation=e}setTimestamp(e){if(!Number.isFinite(e))throw new TypeError("newTimestamp must be a number.");this.timestamp=e}setDuration(e){if(!Number.isFinite(e)||e<0)throw new TypeError("newDuration must be a non-negative number.");this.duration=e}[Symbol.dispose](){this.close()}}class bt{constructor(e){var t,r,i,n;this.primaries=null!=(t=null==e?void 0:e.primaries)?t:null,this.transfer=null!=(r=null==e?void 0:e.transfer)?r:null,this.matrix=null!=(i=null==e?void 0:e.matrix)?i:null,this.fullRange=null!=(n=null==e?void 0:e.fullRange)?n:null}toJSON(){return{primaries:this.primaries,transfer:this.transfer,matrix:this.matrix,fullRange:this.fullRange}}}const yt=e=>"undefined"!==typeof VideoFrame&&e instanceof VideoFrame,Tt=(e,t,r)=>{e.left=Math.min(e.left,t),e.top=Math.min(e.top,r),e.width=Math.min(e.width,t-e.left),e.height=Math.min(e.height,r-e.top),p(e.width>=0),p(e.height>=0)},St=(e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(t+"crop, when provided, must be an object.");if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(t+"crop.left must be a non-negative integer.");if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(t+"crop.top must be a non-negative integer.");if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(t+"crop.width must be a non-negative integer.");if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(t+"crop.height must be a non-negative integer.")},vt=e=>{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.colorSpace&&!["display-p3","srgb"].includes(e.colorSpace))throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");if(void 0!==e.format&&"string"!==typeof e.format)throw new TypeError("options.format, when provided, must be a string.");if(void 0!==e.layout){if(!Array.isArray(e.layout))throw new TypeError("options.layout, when provided, must be an array.");for(const t of e.layout){if(!t||"object"!==typeof t)throw new TypeError("Each entry in options.layout must be an object.");if(!Number.isInteger(t.offset)||t.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(t.stride)||t.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==e.rect){if(!e.rect||"object"!==typeof e.rect)throw new TypeError("options.rect, when provided, must be an object.");if(void 0!==e.rect.x&&(!Number.isInteger(e.rect.x)||e.rect.x<0))throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");if(void 0!==e.rect.y&&(!Number.isInteger(e.rect.y)||e.rect.y<0))throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");if(void 0!==e.rect.width&&(!Number.isInteger(e.rect.width)||e.rect.width<0))throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");if(void 0!==e.rect.height&&(!Number.isInteger(e.rect.height)||e.rect.height<0))throw new TypeError("options.rect.height, when provided, must be a non-negative integer.")}},wt=(e,t,r)=>{const i=It(e),n=[];let s=0;for(const a of i){const e=Math.ceil(t/a.widthDivisor),i=Math.ceil(r/a.heightDivisor),o=e*a.sampleBytes,l=o*i;n.push({offset:s,stride:o}),s+=l}return n},It=e=>{const t=(e,t,r,i,n)=>{const s=[{sampleBytes:e,widthDivisor:1,heightDivisor:1},{sampleBytes:t,widthDivisor:r,heightDivisor:i},{sampleBytes:t,widthDivisor:r,heightDivisor:i}];return n&&s.push({sampleBytes:e,widthDivisor:1,heightDivisor:1}),s};switch(e){case"I420":return t(1,1,2,2,!1);case"I420P10":case"I420P12":return t(2,2,2,2,!1);case"I420A":return t(1,1,2,2,!0);case"I420AP10":case"I420AP12":return t(2,2,2,2,!0);case"I422":return t(1,1,2,1,!1);case"I422P10":case"I422P12":return t(2,2,2,1,!1);case"I422A":return t(1,1,2,1,!0);case"I422AP10":case"I422AP12":return t(2,2,2,1,!0);case"I444":return t(1,1,1,1,!1);case"I444P10":case"I444P12":return t(2,2,1,1,!1);case"I444A":return t(1,1,1,1,!0);case"I444AP10":case"I444AP12":return t(2,2,1,1,!0);case"NV12":return[{sampleBytes:1,widthDivisor:1,heightDivisor:1},{sampleBytes:2,widthDivisor:2,heightDivisor:2}];case"RGBA":case"RGBX":case"BGRA":case"BGRX":return[{sampleBytes:4,widthDivisor:1,heightDivisor:1}];default:q(e),p(!1)}},Pt=new Set(["f32","f32-planar","s16","s16-planar","s32","s32-planar","u8","u8-planar"]);class xt{get microsecondTimestamp(){return Math.trunc(Y*this.timestamp)}get microsecondDuration(){return Math.trunc(Y*this.duration)}constructor(e){if(this._closed=!1,Ft(e)){if(null===e.format)throw new TypeError("AudioData with null format is not supported.");this._data=e,this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=e.numberOfFrames,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp/1e6,this.duration=e.numberOfFrames/e.sampleRate}else{if(!e||"object"!==typeof e)throw new TypeError("Invalid AudioDataInit: must be an object.");if(!Pt.has(e.format))throw new TypeError("Invalid AudioDataInit: invalid format.");if(!Number.isFinite(e.sampleRate)||e.sampleRate<=0)throw new TypeError("Invalid AudioDataInit: sampleRate must be > 0.");if(!Number.isInteger(e.numberOfChannels)||0===e.numberOfChannels)throw new TypeError("Invalid AudioDataInit: numberOfChannels must be an integer > 0.");if(!Number.isFinite(null==e?void 0:e.timestamp))throw new TypeError("init.timestamp must be a number.");const t=e.data.byteLength/(Ct(e.format)*e.numberOfChannels);if(!Number.isInteger(t))throw new TypeError("Invalid AudioDataInit: data size is not a multiple of frame size.");let r;if(this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=t,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp,this.duration=t/e.sampleRate,e.data instanceof ArrayBuffer)r=new Uint8Array(e.data);else{if(!ArrayBuffer.isView(e.data))throw new TypeError("Invalid AudioDataInit: data is not a BufferSource.");r=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength)}const i=this.numberOfFrames*this.numberOfChannels*Ct(this.format);if(r.byteLength=this.numberOfFrames)throw new RangeError("frameOffset out of range");const s=void 0!==e.frameCount?e.frameCount:this.numberOfFrames-n;if(s>this.numberOfFrames-n)throw new RangeError("frameCount out of range");const a=Ct(i),o=_t(i);if(o&&e.planeIndex>=this.numberOfChannels)throw new RangeError("planeIndex out of range");if(!o&&0!==e.planeIndex)throw new RangeError("planeIndex out of range");return(o?s:s*this.numberOfChannels)*a}copyTo(e,t){if(!F(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!Number.isInteger(t.planeIndex)||t.planeIndex<0)throw new TypeError("planeIndex must be a non-negative integer.");if(void 0!==t.format&&!Pt.has(t.format))throw new TypeError("Invalid format.");if(void 0!==t.frameOffset&&(!Number.isInteger(t.frameOffset)||t.frameOffset<0))throw new TypeError("frameOffset must be a non-negative integer.");if(void 0!==t.frameCount&&(!Number.isInteger(t.frameCount)||t.frameCount<0))throw new TypeError("frameCount must be a non-negative integer.");if(this._closed)throw new Error("AudioSample is closed.");const{planeIndex:r,format:i,frameCount:n,frameOffset:s}=t,a=this.format,o=null!=i?i:this.format;if(!o)throw new Error("Destination format not determined");const l=this.numberOfFrames,c=this.numberOfChannels,u=null!=s?s:0;if(u>=l)throw new RangeError("frameOffset out of range");const d=void 0!==n?n:l-u;if(d>l-u)throw new RangeError("frameCount out of range");const h=Ct(o),m=_t(o);if(m&&r>=c)throw new RangeError("planeIndex out of range");if(!m&&0!==r)throw new RangeError("planeIndex out of range");const f=(m?d:d*c)*h;if(e.byteLength2&&o!==a?Dt(this._data,p,a,o,c,r,u,d):this._data.copyTo(e,{planeIndex:r,frameOffset:u,frameCount:d,format:o});else{const e=this._data,t=v(e),i=Bt(a),n=Ct(a),s=_t(a);for(let a=0;a0;){const n=Math.min(s,o),l=new Float32Array(r*n);for(let t=0;t0;){const n=Math.min(s,o),c=new Float32Array(r*n);for(let t=0;t{switch(e){case"u8":case"u8-planar":return 1;case"s16":case"s16-planar":return 2;case"s32":case"s32-planar":case"f32":case"f32-planar":return 4;default:throw new Error("Unknown AudioSampleFormat")}},_t=e=>{switch(e){case"u8-planar":case"s16-planar":case"s32-planar":case"f32-planar":return!0;default:return!1}},Bt=e=>{switch(e){case"u8":case"u8-planar":return(e,t)=>(e.getUint8(t)-128)/128;case"s16":case"s16-planar":return(e,t)=>e.getInt16(t,!0)/32768;case"s32":case"s32-planar":return(e,t)=>e.getInt32(t,!0)/2147483648;case"f32":case"f32-planar":return(e,t)=>e.getFloat32(t,!0)}},Et=e=>{switch(e){case"u8":case"u8-planar":return(e,t,r)=>e.setUint8(t,K(127.5*(r+1),0,255));case"s16":case"s16-planar":return(e,t,r)=>e.setInt16(t,K(Math.round(32767*r),-32768,32767),!0);case"s32":case"s32-planar":return(e,t,r)=>e.setInt32(t,K(Math.round(2147483647*r),-2147483648,2147483647),!0);case"f32":case"f32-planar":return(e,t,r)=>e.setFloat32(t,r,!0)}},Ft=e=>"undefined"!==typeof AudioData&&e instanceof AudioData,Dt=(e,t,r,i,n,s,a,o)=>{const l=Bt(r),c=Et(i),u=Ct(r),d=Ct(i),h=_t(r);if(_t(i))if(h){const i=new ArrayBuffer(o*u),n=v(i);e.copyTo(i,{planeIndex:s,frameOffset:a,frameCount:o,format:r});for(let e=0;e{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.metadataOnly&&"boolean"!==typeof e.metadataOnly)throw new TypeError("options.metadataOnly, when defined, must be a boolean.");if(void 0!==e.verifyKeyPackets&&"boolean"!==typeof e.verifyKeyPackets)throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");if(e.verifyKeyPackets&&e.metadataOnly)throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.")},Rt=e=>{if(!me(e))throw new TypeError("timestamp must be a number.")},Mt=(e,t,r)=>r.verifyKeyPackets?t.then(t=>u(null,null,function*(){if(!t||"delta"===t.type)return t;const r=yield e.determinePacketType(t);return r&&(t.type=r),t})):t;class Nt{constructor(e){if(!(e instanceof Qt))throw new TypeError("track must be an InputTrack.");this._track=e}getFirstPacket(e={}){if(At(e),this._track.input._disposed)throw new gn;return Mt(this._track,this._track._backing.getFirstPacket(e),e)}getPacket(e,t={}){if(Rt(e),At(t),this._track.input._disposed)throw new gn;return Mt(this._track,this._track._backing.getPacket(e,t),t)}getNextPacket(e,t={}){if(!(e instanceof dt))throw new TypeError("packet must be an EncodedPacket.");if(At(t),this._track.input._disposed)throw new gn;return Mt(this._track,this._track._backing.getNextPacket(e,t),t)}getKeyPacket(e){return u(this,arguments,function*(e,t={}){if(Rt(e),At(t),this._track.input._disposed)throw new gn;if(!t.verifyKeyPackets)return this._track._backing.getKeyPacket(e,t);const r=yield this._track._backing.getKeyPacket(e,t);if(!r)return r;p("key"===r.type);return"delta"===(yield this._track.determinePacketType(r))?this.getKeyPacket(r.timestamp-1/this._track.timeResolution,t):r})}getNextKeyPacket(e){return u(this,arguments,function*(e,t={}){if(!(e instanceof dt))throw new TypeError("packet must be an EncodedPacket.");if(At(t),this._track.input._disposed)throw new gn;if(!t.verifyKeyPackets)return this._track._backing.getNextKeyPacket(e,t);const r=yield this._track._backing.getNextKeyPacket(e,t);if(!r)return r;p("key"===r.type);return"delta"===(yield this._track.determinePacketType(r))?this.getNextKeyPacket(r,t):r})}packets(e,t,r={}){if(void 0!==e&&!(e instanceof dt))throw new TypeError("startPacket must be an EncodedPacket.");if(void 0!==e&&e.isMetadataOnly&&!(null==r?void 0:r.metadataOnly))throw new TypeError("startPacket can only be metadata-only if options.metadataOnly is enabled.");if(void 0!==t&&!(t instanceof dt))throw new TypeError("endPacket must be an EncodedPacket.");if(At(r),this._track.input._disposed)throw new gn;const i=[];let{promise:n,resolve:s}=O(),{promise:a,resolve:o}=O(),l=!1,c=!1,d=null;const h=[],m=()=>Math.max(2,h.length);(()=>u(this,null,function*(){let u=null!=e?e:yield this.getFirstPacket(r);for(;u&&!c&&!this._track.input._disposed&&!(t&&u.sequenceNumber>=(null==t?void 0:t.sequenceNumber));)i.length>m()?(({promise:a,resolve:o}=O()),yield a):(i.push(u),s(),({promise:n,resolve:s}=O()),u=yield this.getNextPacket(u,r));l=!0,s()}))().catch(e=>{d||(d=e,s())});const f=this._track;return{next(){return u(this,null,function*(){for(;;){if(f.input._disposed)throw new gn;if(c)return{value:void 0,done:!0};if(d)throw d;if(i.length>0){const e=i.shift(),t=performance.now();for(h.push(t);h.length>0&&t-h[0]>=1e3;)h.shift();return o(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};yield n}})},return(){return u(this,null,function*(){return c=!0,o(),s(),{value:void 0,done:!0}})},throw(e){return u(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}}class zt{constructor(e,t){this.onSample=e,this.onError=t}}class Ot{mediaSamplesInRange(e=0,t=1/0){Rt(e),Rt(t);const r=[];let i=!1,n=null,{promise:s,resolve:a}=O(),{promise:o,resolve:l}=O(),c=!1,d=!1,h=!1,m=null;(()=>u(this,null,function*(){var u;const f=yield this._createDecoder(o=>{l(),o.timestamp>=t&&(d=!0),d?o.close():(n&&(o.timestamp>e?(r.push(n),i=!0):n.close()),o.timestamp>=e&&(r.push(o),i=!0),n=i?null:o,r.length>0&&(a(),({promise:s,resolve:a}=O())))},e=>{m||(m=e,a())}),p=this._createPacketSink(),g=null!=(u=yield p.getKeyPacket(e,{verifyKeyPackets:!0}))?u:yield p.getFirstPacket();let k=g;const b=p.packets(null!=g?g:void 0,void 0);for(yield b.next();k&&!d&&!this._track.input._disposed;){const e=Lt(r.length);if(r.length+f.getDecodeQueueSize()>e){({promise:o,resolve:l}=O()),yield o;continue}f.decode(k);const t=yield b.next();if(t.done)break;k=t.value}yield b.return(),h||this._track.input._disposed||(yield f.flush()),f.close(),!i&&n&&r.push(n),c=!0,a()}))().catch(e=>{m||(m=e,a())});const f=this._track,p=()=>{null==n||n.close();for(const e of r)e.close()};return{next(){return u(this,null,function*(){for(;;){if(f.input._disposed)throw p(),new gn;if(h)return{value:void 0,done:!0};if(m)throw p(),m;if(r.length>0){const e=r.shift();return l(),{value:e,done:!1}}if(c)return{value:void 0,done:!0};yield s}})},return(){return u(this,null,function*(){return h=!0,d=!0,l(),a(),p(),{value:void 0,done:!0}})},throw(e){return u(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}mediaSamplesAtTimestamps(e){(e=>{if(!(Symbol.iterator in e)&&!(Symbol.asyncIterator in e))throw new TypeError("Argument must be an iterable or async iterable.")})(e);const t=V(e),r=[],i=[];let{promise:n,resolve:s}=O(),{promise:a,resolve:o}=O(),l=!1,c=!1,d=null;const h=e=>{i.push(e),s(),({promise:n,resolve:s}=O())};(()=>u(this,null,function*(){const e=yield this._createDecoder(e=>{if(o(),c)return void e.close();let t=0;for(;r.length>0&&e.timestamp-r[0]>-1e-10;)t++,r.shift();if(t>0)for(let r=0;r{d||(d=e,s())}),n=this._createPacketSink();let f=null,g=null,k=-1;const b=()=>u(this,null,function*(){p(g);let t=g;for(e.decode(t);t.sequenceNumberr&&!c;)({promise:a,resolve:o}=O()),yield a;if(c)break;const s=yield n.getNextPacket(t);p(s),e.decode(s),t=s}k=-1}),y=()=>u(this,null,function*(){yield e.flush();for(let e=0;e{d||(d=e,s())});const f=this._track,g=()=>{for(const e of i)null==e||e.close()};return{next(){return u(this,null,function*(){for(;;){if(f.input._disposed)throw g(),new gn;if(c)return{value:void 0,done:!0};if(d)throw g(),d;if(i.length>0){const e=i.shift();return p(void 0!==e),o(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};yield n}})},return(){return u(this,null,function*(){return c=!0,o(),s(),g(),{value:void 0,done:!0}})},throw(e){return u(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}}const Lt=e=>0===e?40:8;class Ut extends zt{constructor(e,i,n,s,a,o){super(e,i),this.codec=n,this.decoderConfig=s,this.rotation=a,this.timeResolution=o,this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new te,this.customDecoderQueueSize=0,this.inputTimestamps=[],this.sampleQueue=[],this.currentPacketIndex=0,this.raslSkipped=!1,this.alphaDecoder=null,this.alphaHadKeyframe=!1,this.colorQueue=[],this.alphaQueue=[],this.merger=null,this.mergerCreationFailed=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue=[],this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1;const l=lt.find(e=>e.supports(n,s));if(l)this.customDecoder=new l,this.customDecoder.codec=n,this.customDecoder.config=s,this.customDecoder.onSample=e=>{if(!(e instanceof kt))throw new TypeError("The argument passed to onSample must be a VideoSample.");this.finalizeAndEmitSample(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=e=>{if(this.alphaQueue.length>0){const t=this.alphaQueue.shift();p(void 0!==t),this.mergeAlpha(e,t)}else this.colorQueue.push(e)};if("avc"===n&&this.decoderConfig.description&&oe()){const e=(e=>{try{const t=v(e);let r=0;const i=t.getUint8(r++),n=t.getUint8(r++),s=t.getUint8(r++),a=t.getUint8(r++),o=3&t.getUint8(r++),l=31&t.getUint8(r++),c=[];for(let m=0;m0){const i=Ve(e.sequenceParameterSets[0]);i&&0===i.frameMbsOnlyFlag&&(this.decoderConfig=(u=c({},this.decoderConfig),t(u,r({hardwareAcceleration:"prefer-software"}))))}}const i=new Error("Decoding error").stack;this.decoder=new VideoDecoder({output:t=>{try{e(t)}catch(r){this.onError(r)}},error:e=>{e.stack=i,this.onError(e)}}),this.decoder.configure(this.decoderConfig)}var u}getDecodeQueueSize(){var e,t;return this.customDecoder?this.customDecoderQueueSize:(p(this.decoder),Math.max(this.decoder.decodeQueueSize,null!=(t=null==(e=this.alphaDecoder)?void 0:e.decodeQueueSize)?t:0))}decode(e){if("hevc"===this.codec&&this.currentPacketIndex>0&&!this.raslSkipped){if(this.hasHevcRaslPicture(e.data))return;this.raslSkipped=!0}if(this.customDecoder)this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--);else{if(p(this.decoder),ie()||z(this.inputTimestamps,e.timestamp,e=>e),oe()&&0===this.currentPacketIndex&&"avc"===this.codec){const t=ze(e.data,this.decoderConfig).filter(e=>{const t=Le(e);return!(t>=20&&t<=31)}),r=Oe(t,this.decoderConfig);e=new dt(r,e.type,e.timestamp,e.duration)}this.decoder.decode(e.toEncodedVideoChunk()),this.decodeAlphaData(e)}this.currentPacketIndex++}decodeAlphaData(e){if(!e.sideData.alpha||this.mergerCreationFailed)return void this.pushNullAlphaFrame();if(!this.merger)try{this.merger=new Vt}catch(r){return console.error("Due to an error, only color data will be decoded.",r),this.mergerCreationFailed=!0,void this.decodeAlphaData(e)}if(!this.alphaDecoder){const e=e=>{if(this.alphaDecoderQueueSize--,this.colorQueue.length>0){const t=this.colorQueue.shift();p(void 0!==t),this.mergeAlpha(t,e)}else this.alphaQueue.push(e);for(this.decodedAlphaChunkCount++;this.nullAlphaFrameQueue.length>0&&this.nullAlphaFrameQueue[0]===this.decodedAlphaChunkCount;)if(this.nullAlphaFrameQueue.shift(),this.colorQueue.length>0){const e=this.colorQueue.shift();p(void 0!==e),this.mergeAlpha(e,null)}else this.alphaQueue.push(null)},t=new Error("Decoding error").stack;this.alphaDecoder=new VideoDecoder({output:t=>{try{e(t)}catch(r){this.onError(r)}},error:e=>{e.stack=t,this.onError(e)}}),this.alphaDecoder.configure(this.decoderConfig)}const t=it(this.codec,this.decoderConfig,e.sideData.alpha);if(this.alphaHadKeyframe||(this.alphaHadKeyframe="key"===t),this.alphaHadKeyframe){if("hevc"===this.codec&&this.currentAlphaPacketIndex>0&&!this.alphaRaslSkipped){if(this.hasHevcRaslPicture(e.sideData.alpha))return void this.pushNullAlphaFrame();this.alphaRaslSkipped=!0}this.currentAlphaPacketIndex++,this.alphaDecoder.decode(e.alphaToEncodedVideoChunk(null!=t?t:e.type)),this.alphaDecoderQueueSize++}else this.pushNullAlphaFrame()}pushNullAlphaFrame(){0===this.alphaDecoderQueueSize?this.alphaQueue.push(null):this.nullAlphaFrameQueue.push(this.decodedAlphaChunkCount+this.alphaDecoderQueueSize)}hasHevcRaslPicture(e){return qe(e,this.decoderConfig).some(e=>{const t=He(e);return t===Fe.RASL_N||t===Fe.RASL_R})}sampleHandler(e){if(ie()){if(this.sampleQueue.length>0&&e.timestamp>=k(this.sampleQueue).timestamp){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}z(this.sampleQueue,e,e=>e.timestamp)}else{const t=this.inputTimestamps.shift();p(void 0!==t),e.setTimestamp(t),this.finalizeAndEmitSample(e)}}finalizeAndEmitSample(e){e.setTimestamp(Math.round(e.timestamp*this.timeResolution)/this.timeResolution),e.setDuration(Math.round(e.duration*this.timeResolution)/this.timeResolution),e.setRotation(this.rotation),this.onSample(e)}mergeAlpha(e,t){var r;if(!t){const t=new kt(e);return void this.sampleHandler(t)}p(this.merger),this.merger.update(e,t),e.close(),t.close();const i=new VideoFrame(this.merger.canvas,{timestamp:e.timestamp,duration:null!=(r=e.duration)?r:void 0}),n=new kt(i);this.sampleHandler(n)}flush(){return u(this,null,function*(){var e;if(this.customDecoder?yield this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(p(this.decoder),yield Promise.all([this.decoder.flush(),null==(e=this.alphaDecoder)?void 0:e.flush()]),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>null==e?void 0:e.close()),this.alphaQueue.length=0,this.alphaHadKeyframe=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue.length=0,this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1),ie()){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}this.currentPacketIndex=0,this.raslSkipped=!1})}close(){var e,t;this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(p(this.decoder),this.decoder.close(),null==(e=this.alphaDecoder)||e.close(),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>null==e?void 0:e.close()),this.alphaQueue.length=0,null==(t=this.merger)||t.close());for(const r of this.sampleQueue)r.close();this.sampleQueue.length=0}}class Vt{constructor(){"undefined"!==typeof OffscreenCanvas?this.canvas=new OffscreenCanvas(300,150):this.canvas=document.createElement("canvas");const e=this.canvas.getContext("webgl2",{premultipliedAlpha:!1});if(!e)throw new Error("Couldn't acquire WebGL 2 context.");this.gl=e,this.program=this.createProgram(),this.vao=this.createVAO(),this.colorTexture=this.createTexture(),this.alphaTexture=this.createTexture(),this.gl.useProgram(this.program),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_colorTexture"),0),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_alphaTexture"),1)}createProgram(){const e=this.createShader(this.gl.VERTEX_SHADER,"#version 300 es\n\t\t\tin vec2 a_position;\n\t\t\tin vec2 a_texCoord;\n\t\t\tout vec2 v_texCoord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = vec4(a_position, 0.0, 1.0);\n\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t}\n\t\t"),t=this.createShader(this.gl.FRAGMENT_SHADER,"#version 300 es\n\t\t\tprecision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_colorTexture;\n\t\t\tuniform sampler2D u_alphaTexture;\n\t\t\tin vec2 v_texCoord;\n\t\t\tout vec4 fragColor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture(u_colorTexture, v_texCoord).rgb;\n\t\t\t\tfloat alpha = texture(u_alphaTexture, v_texCoord).r;\n\t\t\t\tfragColor = vec4(color, alpha);\n\t\t\t}\n\t\t"),r=this.gl.createProgram();return this.gl.attachShader(r,e),this.gl.attachShader(r,t),this.gl.linkProgram(r),r}createShader(e,t){const r=this.gl.createShader(e);return this.gl.shaderSource(r,t),this.gl.compileShader(r),r}createVAO(){const e=this.gl.createVertexArray();this.gl.bindVertexArray(e);const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),r=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,r),this.gl.bufferData(this.gl.ARRAY_BUFFER,t,this.gl.STATIC_DRAW);const i=this.gl.getAttribLocation(this.program,"a_position"),n=this.gl.getAttribLocation(this.program,"a_texCoord");return this.gl.enableVertexAttribArray(i),this.gl.vertexAttribPointer(i,2,this.gl.FLOAT,!1,16,0),this.gl.enableVertexAttribArray(n),this.gl.vertexAttribPointer(n,2,this.gl.FLOAT,!1,16,8),e}createTexture(){const e=this.gl.createTexture();return this.gl.bindTexture(this.gl.TEXTURE_2D,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),e}update(e,t){e.displayWidth===this.canvas.width&&e.displayHeight===this.canvas.height||(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colorTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),this.gl.activeTexture(this.gl.TEXTURE1),this.gl.bindTexture(this.gl.TEXTURE_2D,this.alphaTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.bindVertexArray(this.vao),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)}close(){var e;null==(e=this.gl.getExtension("WEBGL_lose_context"))||e.loseContext(),this.gl=null}}class qt extends Ot{constructor(e){if(!(e instanceof Gt))throw new TypeError("videoTrack must be an InputVideoTrack.");super(),this._track=e}_createDecoder(e,t){return u(this,null,function*(){if(!(yield this._track.canDecode()))throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track.");const r=this._track.codec,i=this._track.rotation,n=yield this._track.getDecoderConfig(),s=this._track.timeResolution;return p(r&&n),new Ut(e,t,r,n,i,s)})}_createPacketSink(){return new Nt(this._track)}getSample(e){return u(this,null,function*(){Rt(e);try{for(var t,r,i,n=m(this.mediaSamplesAtTimestamps([e]));t=!(r=yield n.next()).done;t=!1){return r.value}}catch(r){i=[r]}finally{try{t&&(r=n.return)&&(yield r.call(n))}finally{if(i)throw i[0]}}throw new Error("Internal error: Iterator returned nothing.")})}samples(e=0,t=1/0){return this.mediaSamplesInRange(e,t)}samplesAtTimestamps(e){return this.mediaSamplesAtTimestamps(e)}}class Ht{constructor(e,t={}){var r,i,n,s;if(this._nextCanvasIndex=0,!(e instanceof Gt))throw new TypeError("videoTrack must be an InputVideoTrack.");if(t&&"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.alpha&&"boolean"!==typeof t.alpha)throw new TypeError("options.alpha, when provided, must be a boolean.");if(void 0!==t.width&&(!Number.isInteger(t.width)||t.width<=0))throw new TypeError("options.width, when defined, must be a positive integer.");if(void 0!==t.height&&(!Number.isInteger(t.height)||t.height<=0))throw new TypeError("options.height, when defined, must be a positive integer.");if(void 0!==t.fit&&!["fill","contain","cover"].includes(t.fit))throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".');if(void 0!==t.width&&void 0!==t.height&&void 0===t.fit)throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180 or 270.");if(void 0!==t.crop&&St(t.crop,"options."),void 0!==t.poolSize&&("number"!==typeof t.poolSize||!Number.isInteger(t.poolSize)||t.poolSize<0))throw new TypeError("poolSize must be a non-negative integer.");const a=null!=(r=t.rotation)?r:e.rotation,[o,l]=a%180===0?[e.codedWidth,e.codedHeight]:[e.codedHeight,e.codedWidth],c=t.crop;c&&Tt(c,o,l);let[u,d]=c?[c.width,c.height]:[o,l];const h=u/d;void 0!==t.width&&void 0===t.height?(u=t.width,d=Math.round(u/h)):void 0===t.width&&void 0!==t.height?(d=t.height,u=Math.round(d*h)):void 0!==t.width&&void 0!==t.height&&(u=t.width,d=t.height),this._videoTrack=e,this._alpha=null!=(i=t.alpha)&&i,this._width=u,this._height=d,this._rotation=a,this._crop=c,this._fit=null!=(n=t.fit)?n:"fill",this._videoSampleSink=new qt(e),this._canvasPool=Array.from({length:null!=(s=t.poolSize)?s:0},()=>null)}_videoSampleToWrappedCanvas(e){let t=this._canvasPool[this._nextCanvasIndex],r=!1;t||("undefined"!==typeof document?(t=document.createElement("canvas"),t.width=this._width,t.height=this._height):t=new OffscreenCanvas(this._width,this._height),this._canvasPool.length>0&&(this._canvasPool[this._nextCanvasIndex]=t),r=!0),this._canvasPool.length>0&&(this._nextCanvasIndex=(this._nextCanvasIndex+1)%this._canvasPool.length);const i=t.getContext("2d",{alpha:this._alpha||se()});p(i),i.resetTransform(),r||(!this._alpha&&se()?(i.fillStyle="black",i.fillRect(0,0,this._width,this._height)):i.clearRect(0,0,this._width,this._height)),e.drawWithFit(i,{fit:this._fit,rotation:this._rotation,crop:this._crop});const n={canvas:t,timestamp:e.timestamp,duration:e.duration};return e.close(),n}getCanvas(e){return u(this,null,function*(){Rt(e);const t=yield this._videoSampleSink.getSample(e);return t&&this._videoSampleToWrappedCanvas(t)})}canvases(e=0,t=1/0){return j(this._videoSampleSink.samples(e,t),e=>this._videoSampleToWrappedCanvas(e))}canvasesAtTimestamps(e){return j(this._videoSampleSink.samplesAtTimestamps(e),e=>e&&this._videoSampleToWrappedCanvas(e))}}class Wt extends zt{constructor(e,t,r,i){super(e,t),this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new te,this.customDecoderQueueSize=0,this.currentTimestamp=null;const n=t=>{(null===this.currentTimestamp||Math.abs(t.timestamp-this.currentTimestamp)>=t.duration)&&(this.currentTimestamp=t.timestamp);const r=this.currentTimestamp;if(this.currentTimestamp+=t.duration,0===t.numberOfFrames)return void t.close();const n=i.sampleRate;t.setTimestamp(Math.round(r*n)/n),e(t)},s=ct.find(e=>e.supports(r,i));if(s)this.customDecoder=new s,this.customDecoder.codec=r,this.customDecoder.config=i,this.customDecoder.onSample=e=>{if(!(e instanceof xt))throw new TypeError("The argument passed to onSample must be an AudioSample.");n(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=new Error("Decoding error").stack;this.decoder=new AudioDecoder({output:e=>{try{n(new xt(e))}catch(t){this.onError(t)}},error:t=>{t.stack=e,this.onError(t)}}),this.decoder.configure(i)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(p(this.decoder),this.decoder.decodeQueueSize)}decode(e){this.customDecoder?(this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--)):(p(this.decoder),this.decoder.decode(e.toEncodedAudioChunk()))}flush(){return this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(p(this.decoder),this.decoder.flush())}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(p(this.decoder),this.decoder.close())}}class jt extends zt{constructor(e,t,r){super(e,t),this.decoderConfig=r,this.currentTimestamp=null,p(ke.includes(r.codec)),this.codec=r.codec;const{dataType:i,sampleSize:n,littleEndian:s}=_e(this.codec);switch(this.inputSampleSize=n,n){case 1:"unsigned"===i?this.readInputValue=(e,t)=>e.getUint8(t)-o(2,7):"signed"===i?this.readInputValue=(e,t)=>e.getInt8(t):"ulaw"===i?this.readInputValue=(e,t)=>(e=>{let t=0,r=0,i=~e;128&i&&(i&=-129,t=-1),r=5+((240&i)>>4);const n=(1<(e=>{let t=0,r=0,i=85^e;128&i&&(i&=-129,t=-1),r=4+((240&i)>>4);let n=0;return n=4!==r?1<e.getUint16(t,s)-o(2,15):"signed"===i?this.readInputValue=(e,t)=>e.getInt16(t,s):p(!1);break;case 3:"unsigned"===i?this.readInputValue=(e,t)=>H(e,t,s)-o(2,23):"signed"===i?this.readInputValue=(e,t)=>((e,t,r)=>H(e,t,r)<<8>>8)(e,t,s):p(!1);break;case 4:"unsigned"===i?this.readInputValue=(e,t)=>e.getUint32(t,s)-o(2,31):"signed"===i?this.readInputValue=(e,t)=>e.getInt32(t,s):"float"===i?this.readInputValue=(e,t)=>e.getFloat32(t,s):p(!1);break;case 8:"float"===i?this.readInputValue=(e,t)=>e.getFloat64(t,s):p(!1);break;default:q(n),p(!1)}switch(n){case 1:"ulaw"===i||"alaw"===i?(this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,r)=>e.setInt16(t,r,!0)):(this.outputSampleSize=1,this.outputFormat="u8",this.writeOutputValue=(e,t,r)=>e.setUint8(t,r+o(2,7)));break;case 2:this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,r)=>e.setInt16(t,r,!0);break;case 3:this.outputSampleSize=4,this.outputFormat="s32",this.writeOutputValue=(e,t,r)=>e.setInt32(t,r<<8,!0);break;case 4:this.outputSampleSize=4,"float"===i?(this.outputFormat="f32",this.writeOutputValue=(e,t,r)=>e.setFloat32(t,r,!0)):(this.outputFormat="s32",this.writeOutputValue=(e,t,r)=>e.setInt32(t,r,!0));break;case 8:this.outputSampleSize=4,this.outputFormat="f32",this.writeOutputValue=(e,t,r)=>e.setFloat32(t,r,!0);break;default:q(n),p(!1)}}getDecodeQueueSize(){return 0}decode(e){const t=v(e.data),r=e.byteLength/this.decoderConfig.numberOfChannels/this.inputSampleSize,i=r*this.decoderConfig.numberOfChannels*this.outputSampleSize,n=new ArrayBuffer(i),s=new DataView(n);for(let c=0;c=a)&&(this.currentTimestamp=e.timestamp);const o=this.currentTimestamp;this.currentTimestamp+=a;const l=new xt({format:this.outputFormat,data:n,numberOfChannels:this.decoderConfig.numberOfChannels,sampleRate:this.decoderConfig.sampleRate,numberOfFrames:r,timestamp:o});this.onSample(l)}flush(){return u(this,null,function*(){})}close(){}}class Kt extends Ot{constructor(e){if(!(e instanceof Xt))throw new TypeError("audioTrack must be an InputAudioTrack.");super(),this._track=e}_createDecoder(e,t){return u(this,null,function*(){if(!(yield this._track.canDecode()))throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track.");const r=this._track.codec,i=yield this._track.getDecoderConfig();return p(r&&i),ke.includes(i.codec)?new jt(e,t,i):new Wt(e,t,r,i)})}_createPacketSink(){return new Nt(this._track)}getSample(e){return u(this,null,function*(){Rt(e);try{for(var t,r,i,n=m(this.mediaSamplesAtTimestamps([e]));t=!(r=yield n.next()).done;t=!1){return r.value}}catch(r){i=[r]}finally{try{t&&(r=n.return)&&(yield r.call(n))}finally{if(i)throw i[0]}}throw new Error("Internal error: Iterator returned nothing.")})}samples(e=0,t=1/0){return this.mediaSamplesInRange(e,t)}samplesAtTimestamps(e){return this.mediaSamplesAtTimestamps(e)}}class $t{constructor(e){if(!(e instanceof Xt))throw new TypeError("audioTrack must be an InputAudioTrack.");this._audioSampleSink=new Kt(e)}_audioSampleToWrappedArrayBuffer(e){const t={buffer:e.toAudioBuffer(),timestamp:e.timestamp,duration:e.duration};return e.close(),t}getBuffer(e){return u(this,null,function*(){Rt(e);const t=yield this._audioSampleSink.getSample(e);return t&&this._audioSampleToWrappedArrayBuffer(t)})}buffers(e=0,t=1/0){return j(this._audioSampleSink.samples(e,t),e=>this._audioSampleToWrappedArrayBuffer(e))}buffersAtTimestamps(e){return j(this._audioSampleSink.samplesAtTimestamps(e),e=>e&&this._audioSampleToWrappedArrayBuffer(e))}}class Qt{constructor(e,t){this.input=e,this._backing=t}isVideoTrack(){return this instanceof Gt}isAudioTrack(){return this instanceof Xt}get id(){return this._backing.getId()}get internalCodecId(){return this._backing.getInternalCodecId()}get languageCode(){return this._backing.getLanguageCode()}get name(){return this._backing.getName()}get timeResolution(){return this._backing.getTimeResolution()}get disposition(){return this._backing.getDisposition()}getFirstTimestamp(){return this._backing.getFirstTimestamp()}computeDuration(){return this._backing.computeDuration()}computePacketStats(e=1/0){return u(this,null,function*(){const t=new Nt(this);let r=1/0,i=-1/0,n=0,s=0;try{for(var a,o,l,c=m(t.packets(void 0,void 0,{metadataOnly:!0}));a=!(o=yield c.next()).done;a=!1){const t=o.value;if(n>=e&&t.timestamp>=i)break;r=Math.min(r,t.timestamp),i=Math.max(i,t.timestamp+t.duration),n++,s+=t.byteLength}}catch(o){l=[o]}finally{try{a&&(o=c.return)&&(yield o.call(c))}finally{if(l)throw l[0]}}return{packetCount:n,averagePacketRate:n?Number((n/(i-r)).toPrecision(16)):0,averageBitrate:n?Number((8*s/(i-r)).toPrecision(16)):0}})}}class Gt extends Qt{constructor(e,t){super(e,t),this._backing=t}get type(){return"video"}get codec(){return this._backing.getCodec()}get codedWidth(){return this._backing.getCodedWidth()}get codedHeight(){return this._backing.getCodedHeight()}get rotation(){return this._backing.getRotation()}get displayWidth(){return this._backing.getRotation()%180===0?this._backing.getCodedWidth():this._backing.getCodedHeight()}get displayHeight(){return this._backing.getRotation()%180===0?this._backing.getCodedHeight():this._backing.getCodedWidth()}getColorSpace(){return this._backing.getColorSpace()}hasHighDynamicRange(){return u(this,null,function*(){const e=yield this._backing.getColorSpace();return"bt2020"===e.primaries||"smpte432"===e.primaries||"pg"===e.transfer||"hlg"===e.transfer||"bt2020-ncl"===e.matrix})}canBeTransparent(){return this._backing.canBeTransparent()}getDecoderConfig(){return this._backing.getDecoderConfig()}getCodecParameterString(){return u(this,null,function*(){var e;const t=yield this._backing.getDecoderConfig();return null!=(e=null==t?void 0:t.codec)?e:null})}canDecode(){return u(this,null,function*(){try{const e=yield this._backing.getDecoderConfig();if(!e)return!1;const t=this._backing.getCodec();if(p(null!==t),lt.some(r=>r.supports(t,e)))return!0;if("undefined"===typeof VideoDecoder)return!1;return!0===(yield VideoDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}})}determinePacketType(e){return u(this,null,function*(){if(!(e instanceof dt))throw new TypeError("packet must be an EncodedPacket.");if(e.isMetadataOnly)throw new TypeError("packet must not be metadata-only to determine its type.");if(null===this.codec)return null;const t=yield this.getDecoderConfig();return p(t),it(this.codec,t,e.data)})}}class Xt extends Qt{constructor(e,t){super(e,t),this._backing=t}get type(){return"audio"}get codec(){return this._backing.getCodec()}get numberOfChannels(){return this._backing.getNumberOfChannels()}get sampleRate(){return this._backing.getSampleRate()}getDecoderConfig(){return this._backing.getDecoderConfig()}getCodecParameterString(){return u(this,null,function*(){var e;const t=yield this._backing.getDecoderConfig();return null!=(e=null==t?void 0:t.codec)?e:null})}canDecode(){return u(this,null,function*(){try{const e=yield this._backing.getDecoderConfig();if(!e)return!1;const t=this._backing.getCodec();if(p(null!==t),ct.some(r=>r.supports(t,e)))return!0;if(e.codec.startsWith("pcm-"))return!0;if("undefined"===typeof AudioDecoder)return!1;return!0===(yield AudioDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}})}determinePacketType(e){return u(this,null,function*(){if(!(e instanceof dt))throw new TypeError("packet must be an EncodedPacket.");return null===this.codec?null:"key"})}}const Yt=e=>{let t=Cn(e);const r=Nn(e,4);let i=8;1===t&&(t=Fn(e),i=16);const n=t-i;return n<0?null:{name:r,totalSize:t,headerSize:i,contentSize:n}},Jt=e=>Bn(e)/65536,Zt=e=>Bn(e)/1073741824,er=e=>{let t=0;for(let r=0;r<4;r++){t<<=7;const r=Sn(e);if(t|=127&r,0===(128&r))break}return t},tr=e=>{let t=wn(e);return e.skip(2),t=Math.min(t,e.remainingLength),w.decode(Tn(e,t))},rr=e=>{const t=Yt(e);if(!t||"data"!==t.name)return null;if(e.remainingLength<8)return null;const r=Cn(e);e.skip(4);const i=Tn(e,t.contentSize-8);switch(r){case 1:return w.decode(i);case 2:return new TextDecoder("utf-16be").decode(i);case 13:return new fe(i,"image/jpeg");case 14:return new fe(i,"image/png");case 27:return new fe(i,"image/bmp");default:return i}};class ir extends ot{constructor(e){super(e),this.moovSlice=null,this.currentTrack=null,this.tracks=[],this.metadataPromise=null,this.movieTimescale=-1,this.movieDurationInTimescale=-1,this.isQuickTime=!1,this.metadataTags={},this.currentMetadataKeys=null,this.isFragmented=!1,this.fragmentTrackDefaults=[],this.currentFragment=null,this.lastReadFragment=null,this.reader=e._reader}computeDuration(){return u(this,null,function*(){const e=yield this.getTracks(),t=yield Promise.all(e.map(e=>e.computeDuration()));return Math.max(0,...t)})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks.map(e=>e.inputTrack)})}getMimeType(){return u(this,null,function*(){yield this.readMetadata();const e=yield Promise.all(this.tracks.map(e=>e.inputTrack.getCodecParameterString()));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isQuickTime?"quicktime":"mp4");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({isQuickTime:this.isQuickTime,hasVideo:this.tracks.some(e=>{var t;return"video"===(null==(t=e.info)?void 0:t.type)}),hasAudio:this.tracks.some(e=>{var t;return"audio"===(null==(t=e.info)?void 0:t.type)}),codecStrings:e.filter(Boolean)})})}getMetadataTags(){return u(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}readMetadata(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>u(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,8,16);if(t instanceof Promise&&(t=yield t),!t)break;const r=e,i=Yt(t);if(!i)break;if("ftyp"===i.name){const e=Nn(t,4);this.isQuickTime="qt "===e}else if("moov"===i.name){let e=this.reader.requestSlice(t.filePos,i.contentSize);if(e instanceof Promise&&(e=yield e),!e)break;this.moovSlice=e,this.readContiguousBoxes(this.moovSlice),this.tracks.sort((e,t)=>Number(t.disposition.default)-Number(e.disposition.default));for(const t of this.tracks){const e=t.editListPreviousSegmentDurations/this.movieTimescale;t.editListOffset-=Math.round(e*t.timescale)}break}e=r+i.totalSize}if(this.isFragmented&&null!==this.reader.fileSize){let e=this.reader.requestSlice(this.reader.fileSize-4,4);e instanceof Promise&&(e=yield e),p(e);const t=Cn(e),r=this.reader.fileSize-t;if(r>=0&&r<=this.reader.fileSize-16){let e=this.reader.requestSliceRange(r,8,16);if(e instanceof Promise&&(e=yield e),e){const t=Yt(e);if(t&&"mfra"===t.name){let r=this.reader.requestSlice(e.filePos,t.contentSize);r instanceof Promise&&(r=yield r),r&&this.readContiguousBoxes(r)}}}}}))()}getSampleTableForTrack(e){var t,r;if(e.sampleTable)return e.sampleTable;const i={sampleTimingEntries:[],sampleCompositionTimeOffsets:[],sampleSizes:[],keySampleIndices:null,chunkOffsets:[],sampleToChunk:[],presentationTimestamps:null,presentationTimestampIndexMap:null};e.sampleTable=i,p(this.moovSlice);const n=this.moovSlice.slice(e.sampleTableByteOffset);this.currentTrack=e,this.traverseBox(n),this.currentTrack=null;if("audio"===(null==(t=e.info)?void 0:t.type)&&e.info.codec&&ke.includes(e.info.codec)&&0===i.sampleCompositionTimeOffsets.length){p("audio"===(null==(r=e.info)?void 0:r.type));const t=_e(e.info.codec),n=[],s=[];for(let r=0;re.startIndex),u=i.sampleTimingEntries[c],d=N(i.sampleTimingEntries,l,e=>e.startIndex),h=i.sampleTimingEntries[d],m=u.startDecodeTimestamp+(o-u.startIndex)*u.delta,f=h.startDecodeTimestamp+(l-h.startIndex)*h.delta-m,p=k(n);p&&p.delta===f?p.count++:n.push({startIndex:a.startChunkIndex+r,startDecodeTimestamp:m,count:1,delta:f});const g=a.samplesPerChunk*t.sampleSize*e.info.numberOfChannels;s.push(g)}a.startSampleIndex=a.startChunkIndex,a.samplesPerChunk=1}i.sampleTimingEntries=n,i.sampleSizes=s}if(i.sampleCompositionTimeOffsets.length>0){i.presentationTimestamps=[];for(const e of i.sampleTimingEntries)for(let t=0;te.presentationTimestamp-t.presentationTimestamp),i.presentationTimestampIndexMap=Array(i.presentationTimestamps.length).fill(-1);for(let e=0;ee.moofOffset===s.moofOffset);if(i)dr(e,i.timestamp);else{const t=N(r,s.moofOffset-1,e=>e.moofOffset);if(-1!==t){const i=r[t];dr(e,i.endTimestamp)}}e.startTimestampIsFinal=!0}const i=N(r,e.startTimestamp,e=>e.startTimestamp);-1!==i&&r[i].moofOffset===s.moofOffset||r.splice(i+1,0,{moofOffset:s.moofOffset,startTimestamp:e.startTimestamp,endTimestamp:e.endTimestamp})}return s})}readContiguousBoxes(e){const t=e.filePos;for(;e.filePos-t<=e.length-8;){if(!this.traverseBox(e))break}}*iterateContiguousBoxes(e){const t=e.filePos;for(;e.filePos-t<=e.length-8;){const t=e.filePos,r=Yt(e);if(!r)break;yield{boxInfo:r,slice:e},e.filePos=t+r.totalSize}}traverseBox(e){var t,r,i,n,s,a,o,l,u,d,h,m,f,y,T,S,I,P,C,B,F,D,A,R,M,N,z,O,L,U,V,q,H,W,j,K,Q,G,Y,J,Z,ee,te,re,ie;const ne=e.filePos,se=Yt(e);if(!se)return!1;const ae=e.filePos,oe=ne+se.totalSize;switch(se.name){case"mdia":case"minf":case"dinf":case"mfra":case"edts":case"wave":this.readContiguousBoxes(e.slice(ae,se.contentSize));break;case"mvhd":{const t=Sn(e);e.skip(3),1===t?(e.skip(16),this.movieTimescale=Cn(e),this.movieDurationInTimescale=Fn(e)):(e.skip(8),this.movieTimescale=Cn(e),this.movieDurationInTimescale=Cn(e))}break;case"trak":{const t={id:-1,demuxer:this,inputTrack:null,disposition:c({},ge),info:null,timescale:-1,durationInMovieTimescale:-1,durationInMediaTimescale:-1,rotation:0,internalCodecId:null,name:null,languageCode:$,sampleTableByteOffset:-1,sampleTable:null,fragmentLookupTable:[],currentFragmentState:null,fragmentPositionCache:[],editListPreviousSegmentDurations:0,editListOffset:0};if(this.currentTrack=t,this.readContiguousBoxes(e.slice(ae,se.contentSize)),-1!==t.id&&-1!==t.timescale&&null!==t.info)if("video"===t.info.type&&-1!==t.info.width){const e=t;t.inputTrack=new Gt(this.input,new sr(e)),this.tracks.push(t)}else if("audio"===t.info.type&&-1!==t.info.numberOfChannels){const e=t;t.inputTrack=new Xt(this.input,new ar(e)),this.tracks.push(t)}this.currentTrack=null}break;case"tkhd":{const t=this.currentTrack;if(!t)break;const r=Sn(e),i=!!(1&In(e));if(t.disposition.default=i,0===r)e.skip(8),t.id=Cn(e),e.skip(4),t.durationInMovieTimescale=Cn(e);else{if(1!==r)throw new Error(`Incorrect track header version ${r}.`);e.skip(16),t.id=Cn(e),e.skip(4),t.durationInMovieTimescale=Fn(e)}e.skip(16);const n=[Jt(e),Jt(e),Zt(e),Jt(e),Jt(e),Zt(e),Jt(e),Jt(e),Zt(e)],s=g((le=hr(n),ce=90,Math.round(le/ce)*ce));p(0===s||90===s||180===s||270===s),t.rotation=s}break;case"elst":{const t=this.currentTrack;if(!t)break;const r=Sn(e);e.skip(3);let i=!1,n=0;const s=Cn(e);for(let a=0;a0){t.languageCode="";for(let e=0;e<3;e++)t.languageCode=String.fromCharCode(96+(31&i))+t.languageCode,i>>=5;X(t.languageCode)||(t.languageCode=$)}}break;case"hdlr":{const t=this.currentTrack;if(!t)break;e.skip(8);const r=Nn(e,4);"vide"===r?t.info={type:"video",width:-1,height:-1,codec:null,codecDescription:null,colorSpace:null,avcType:null,avcCodecInfo:null,hevcCodecInfo:null,vp9CodecInfo:null,av1CodecInfo:null}:"soun"===r&&(t.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case"stbl":{const t=this.currentTrack;if(!t)break;t.sampleTableByteOffset=ne,this.readContiguousBoxes(e.slice(ae,se.contentSize))}break;case"stsd":{const t=this.currentTrack;if(!t)break;if(null===t.info||t.sampleTable)break;const r=Sn(e);e.skip(3);const i=Cn(e);for(let n=0;n0)if(1===a)e.skip(4),l=8*Cn(e),e.skip(8);else if(2===a){e.skip(4),c=Mn(e),o=Cn(e),e.skip(4),l=Cn(e);const r=Cn(e);if(e.skip(8),"lpcm"===s){const e=l+7>>3,i=Boolean(1&r),n=Boolean(2&r),s=4&r?-1:0;l>0&&l<=64&&(i?32===l&&(t.info.codec=n?"pcm-f32be":"pcm-f32"):s&1<>4,o=s>>1&7,l=1&s,c=Sn(e),u=Sn(e),d=Sn(e);r.info.vp9CodecInfo={profile:i,level:n,bitDepth:a,chromaSubsampling:o,videoFullRangeFlag:l,colourPrimaries:c,transferCharacteristics:u,matrixCoefficients:d}}break;case"av1C":{const t=this.currentTrack;if(!t)break;p("video"===(null==(r=t.info)?void 0:r.type)),e.skip(1);const i=Sn(e),n=i>>5,s=31&i,a=Sn(e),o=a>>7,l=a>>6&1,c=a>>4&1,u=a>>3&1,d=a>>2&1,h=3&a,m=2===n&&l?a>>5&1?12:10:l?10:8;t.info.av1CodecInfo={profile:n,level:s,tier:o,bitDepth:m,monochrome:c,chromaSubsamplingX:u,chromaSubsamplingY:d,chromaSamplePosition:h}}break;case"colr":{const t=this.currentTrack;if(!t)break;p("video"===(null==(i=t.info)?void 0:i.type));if("nclx"!==Nn(e,4))break;const r=wn(e),n=wn(e),s=wn(e),a=Boolean(128&Sn(e));t.info.colorSpace={primaries:x[r],transfer:_[n],matrix:E[s],fullRange:a}}break;case"esds":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(n=t.info)?void 0:n.type)),e.skip(4);p(3===Sn(e)),er(e),e.skip(2);const r=Sn(e),i=0!==(64&r),s=0!==(32&r);if(0!==(128&r)&&e.skip(2),i){const t=Sn(e);e.skip(t)}s&&e.skip(2);p(4===Sn(e));const a=er(e),o=e.filePos,l=Sn(e);if(64===l||103===l?(t.info.codec="aac",t.info.aacCodecInfo={isMpeg2:103===l}):105===l||107===l?t.info.codec="mp3":221===l?t.info.codec="vorbis":console.warn(`Unsupported audio codec (objectTypeIndication ${l}) - discarding track.`),e.skip(12),a>e.filePos-o){p(5===Sn(e));const r=er(e);if(t.info.codecDescription=Tn(e,r),"aac"===t.info.codec){const e=Pe(t.info.codecDescription);null!==e.numberOfChannels&&(t.info.numberOfChannels=e.numberOfChannels),null!==e.sampleRate&&(t.info.sampleRate=e.sampleRate)}}}break;case"enda":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(s=t.info)?void 0:s.type));255&wn(e)&&("pcm-s16be"===t.info.codec?t.info.codec="pcm-s16":"pcm-s24be"===t.info.codec?t.info.codec="pcm-s24":"pcm-s32be"===t.info.codec?t.info.codec="pcm-s32":"pcm-f32be"===t.info.codec?t.info.codec="pcm-f32":"pcm-f64be"===t.info.codec&&(t.info.codec="pcm-f64"))}break;case"pcmC":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(a=t.info)?void 0:a.type)),e.skip(4);const r=Sn(e),i=Boolean(1&r),n=Sn(e);"pcm-s16be"===t.info.codec?i?16===n?t.info.codec="pcm-s16":24===n?t.info.codec="pcm-s24":32===n?t.info.codec="pcm-s32":(console.warn(`Invalid ipcm sample size ${n}.`),t.info.codec=null):16===n?t.info.codec="pcm-s16be":24===n?t.info.codec="pcm-s24be":32===n?t.info.codec="pcm-s32be":(console.warn(`Invalid ipcm sample size ${n}.`),t.info.codec=null):"pcm-f32be"===t.info.codec&&(i?32===n?t.info.codec="pcm-f32":64===n?t.info.codec="pcm-f64":(console.warn(`Invalid fpcm sample size ${n}.`),t.info.codec=null):32===n?t.info.codec="pcm-f32be":64===n?t.info.codec="pcm-f64be":(console.warn(`Invalid fpcm sample size ${n}.`),t.info.codec=null));break}case"dOps":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(o=t.info)?void 0:o.type)),e.skip(1);const r=Sn(e),i=wn(e),n=Cn(e),s=Pn(e),a=Sn(e);let l;l=0!==a?Tn(e,2+r):new Uint8Array(0);const c=new Uint8Array(19+l.byteLength),u=new DataView(c.buffer);u.setUint32(0,1332770163,!1),u.setUint32(4,1214603620,!1),u.setUint8(8,1),u.setUint8(9,r),u.setUint16(10,i,!0),u.setUint32(12,n,!0),u.setInt16(16,s,!0),u.setUint8(18,a),c.set(l,19),t.info.codecDescription=c,t.info.numberOfChannels=r}break;case"dfLa":{const t=this.currentTrack;if(!t)break;p("audio"===(null==(l=t.info)?void 0:l.type)),e.skip(4);const r=127,i=128,n=e.filePos;for(;e.filePos>>12,n=1+(r>>9&7);t.info.sampleRate=i,t.info.numberOfChannels=n,e.skip(20)}else e.skip(s);if(n&i)break}const s=e.filePos;e.filePos=n;const a=Tn(e,s-n),o=new Uint8Array(4+a.byteLength);new DataView(o.buffer).setUint32(0,1716281667,!1),o.set(a,4),t.info.codecDescription=o}break;case"stts":{const t=this.currentTrack;if(!t)break;if(!t.sampleTable)break;e.skip(4);const r=Cn(e);let i=0,n=0;for(let s=0;se.id===r);if(!i)break;const n=Cn(e),s=(12&n)>>2,a=3&n,o=[Sn,wn,In,Cn],l=o[(48&n)>>4],c=o[s],u=o[a],d=Cn(e);for(let h=0;he.timestamp-t.timestamp);for(let e=0;ee.id===c);if(!f)break;const g=this.fragmentTrackDefaults.find(e=>e.trackId===c);this.currentTrack=f,f.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:null!=(u=null==g?void 0:g.defaultSampleDescriptionIndex)?u:null,defaultSampleDuration:null!=(d=null==g?void 0:g.defaultSampleDuration)?d:null,defaultSampleSize:null!=(h=null==g?void 0:g.defaultSampleSize)?h:null,defaultSampleFlags:null!=(m=null==g?void 0:g.defaultSampleFlags)?m:null,startTimestamp:null},r?f.currentFragmentState.baseDataOffset=Fn(e):l&&(f.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),i&&(f.currentFragmentState.sampleDescriptionIndex=Cn(e)),n&&(f.currentFragmentState.defaultSampleDuration=Cn(e)),s&&(f.currentFragmentState.defaultSampleSize=Cn(e)),a&&(f.currentFragmentState.defaultSampleFlags=Cn(e)),o&&(f.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{const t=this.currentTrack;if(!t)break;p(t.currentFragmentState);const r=Sn(e);e.skip(3);const i=0===r?Cn(e):Fn(e);t.currentFragmentState.startTimestamp=i}break;case"trun":{const t=this.currentTrack;if(!t)break;if(p(this.currentFragment),p(t.currentFragmentState),this.currentFragment.trackData.has(t.id)){console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring...");break}const r=Sn(e),i=In(e),n=Boolean(1&i),s=Boolean(4&i),a=Boolean(256&i),o=Boolean(512&i),l=Boolean(1024&i),c=Boolean(2048&i),u=Cn(e);let d=t.currentFragmentState.baseDataOffset;n&&(d+=Bn(e));let h=null;s&&(h=Cn(e));let m=d;if(0===u){this.currentFragment.implicitBaseDataOffset=m;break}let f=0;const g={track:t,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1};this.currentFragment.trackData.set(t.id,g);for(let k=0;k({presentationTimestamp:e.presentationTimestamp,sampleIndex:t})).sort((e,t)=>e.presentationTimestamp-t.presentationTimestamp);for(let e=0;e0&&(null!=(J=this.metadataTags).trackNumber||(J.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&(null!=(Z=this.metadataTags).tracksTotal||(Z.tracksTotal=r))}break;case"trkn":if(n instanceof Uint8Array&&n.length>=6){const e=v(n),t=e.getUint16(2,!1),r=e.getUint16(4,!1);t>0&&(null!=(ee=this.metadataTags).trackNumber||(ee.trackNumber=t)),r>0&&(null!=(te=this.metadataTags).tracksTotal||(te.tracksTotal=r))}break;case"disc":case"disk":if(n instanceof Uint8Array&&n.length>=6){const e=v(n),t=e.getUint16(2,!1),r=e.getUint16(4,!1);t>0&&(null!=(re=this.metadataTags).discNumber||(re.discNumber=t)),r>0&&(null!=(ie=this.metadataTags).discsTotal||(ie.discsTotal=r))}}}}}var le,ce;return e.filePos=oe,!0}}class nr{constructor(e){this.internalTrack=e,this.packetToSampleIndex=new WeakMap,this.packetToFragmentLocation=new WeakMap}getId(){return this.internalTrack.id}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.internalCodecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.timescale}getDisposition(){return this.internalTrack.disposition}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getFirstTimestamp(){return u(this,null,function*(){var e;const t=yield this.getFirstPacket({metadataOnly:!0});return null!=(e=null==t?void 0:t.timestamp)?e:0})}getFirstPacket(e){return u(this,null,function*(){const t=yield this.fetchPacketForSampleIndex(0,e);return t||!this.internalTrack.demuxer.isFragmented?t:this.performFragmentedLookup(null,e=>e.trackData.get(this.internalTrack.id)?{sampleIndex:0,correctSampleFound:!0}:{sampleIndex:-1,correctSampleFound:!1},-1/0,1/0,e)})}mapTimestampIntoTimescale(e){return Q(e*this.internalTrack.timescale)+this.internalTrack.editListOffset}getPacket(e,t){return u(this,null,function*(){const r=this.mapTimestampIntoTimescale(e),i=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=or(i,r),s=yield this.fetchPacketForSampleIndex(n,t);return mr(i)&&this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const i=N(t.presentationTimestamps,r,e=>e.presentationTimestamp);return{sampleIndex:-1!==i?t.presentationTimestamps[i].sampleIndex:-1,correctSampleFound:-1!==i&&r{if(e===i.fragment){const t=e.trackData.get(this.internalTrack.id);if(i.sampleIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const i=U(t.presentationTimestamps,e=>t.samples[e.sampleIndex].isKeyFrame&&e.presentationTimestamp<=r);return{sampleIndex:-1!==i?t.presentationTimestamps[i].sampleIndex:-1,correctSampleFound:-1!==i&&r{if(e===i.fragment){const t=e.trackData.get(this.internalTrack.id).samples.findIndex((e,t)=>e.isKeyFrame&&t>i.sampleIndex);if(-1!==t)return{sampleIndex:t,correctSampleFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.samples.findIndex(e=>e.isKeyFrame);return p(-1!==e),{sampleIndex:e,correctSampleFound:!0}}}return{sampleIndex:-1,correctSampleFound:!1}},-1/0,1/0,t)})}fetchPacketForSampleIndex(e,t){return u(this,null,function*(){if(-1===e)return null;const r=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),i=cr(r,e);if(!i)return null;let n;if(t.metadataOnly)n=ut;else{let e=this.internalTrack.demuxer.reader.requestSlice(i.sampleOffset,i.sampleSize);e instanceof Promise&&(e=yield e),p(e),n=Tn(e,i.sampleSize)}const s=(i.presentationTimestamp-this.internalTrack.editListOffset)/this.internalTrack.timescale,a=i.duration/this.internalTrack.timescale,o=new dt(n,i.isKeyFrame?"key":"delta",s,a,e,i.sampleSize);return this.packetToSampleIndex.set(o,e),o})}fetchPacketInFragment(e,t,r){return u(this,null,function*(){if(-1===t)return null;const i=e.trackData.get(this.internalTrack.id).samples[t];let n;if(p(i),r.metadataOnly)n=ut;else{let e=this.internalTrack.demuxer.reader.requestSlice(i.byteOffset,i.byteSize);e instanceof Promise&&(e=yield e),p(e),n=Tn(e,i.byteSize)}const s=(i.presentationTimestamp-this.internalTrack.editListOffset)/this.internalTrack.timescale,a=i.duration/this.internalTrack.timescale,o=new dt(n,i.isKeyFrame?"key":"delta",s,a,e.moofOffset+t,i.byteSize);return this.packetToFragmentLocation.set(o,{fragment:e,sampleIndex:t}),o})}performFragmentedLookup(e,t,r,i,n){return u(this,null,function*(){var s,a,o;const l=this.internalTrack.demuxer;let c=null,u=null,d=-1;if(e){const{sampleIndex:r,correctSampleFound:i}=t(e);if(i)return this.fetchPacketInFragment(e,r,n);-1!==r&&(u=e,d=r)}const h=N(this.internalTrack.fragmentLookupTable,r,e=>e.timestamp),m=-1!==h?this.internalTrack.fragmentLookupTable[h]:null,f=N(this.internalTrack.fragmentPositionCache,r,e=>e.startTimestamp),g=-1!==f?this.internalTrack.fragmentPositionCache[f]:null,k=Math.max(null!=(s=null==m?void 0:m.moofOffset)?s:0,null!=(a=null==g?void 0:g.moofOffset)?a:0)||null;let b;for(e?null===k||e.moofOffset>=k?(b=e.moofOffset+e.moofSize,c=e):b=k:b=null!=k?k:0;;){if(c){const e=c.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>i)break}let e=l.reader.requestSliceRange(b,8,16);if(e instanceof Promise&&(e=yield e),!e)break;const r=b,s=Yt(e);if(!s)break;if("moof"===s.name){c=yield l.readFragment(r);const{sampleIndex:e,correctSampleFound:i}=t(c);if(i)return this.fetchPacketInFragment(c,e,n);-1!==e&&(u=c,d=e)}b=r+s.totalSize}if(m&&(!u||u.moofOffsetu(this,null,function*(){var e,t;if("vp9"!==this.internalTrack.info.codec||this.internalTrack.info.vp9CodecInfo){if("av1"===this.internalTrack.info.codec&&!this.internalTrack.info.av1CodecInfo){const e=yield this.getFirstPacket({});this.internalTrack.info.av1CodecInfo=e&&et(e.data)}}else{const e=yield this.getFirstPacket({});this.internalTrack.info.vp9CodecInfo=e&&Je(e.data)}return{codec:Se(this.internalTrack.info),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0,colorSpace:null!=(t=this.internalTrack.info.colorSpace)?t:void 0}}))():null})}}class ar extends nr{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}getDecoderConfig(){return u(this,null,function*(){var e,t;return this.internalTrack.info.codec?null!=(t=this.decoderConfig)?t:this.decoderConfig={codec:ve(this.internalTrack.info),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0}:null})}}const or=(e,t)=>{if(e.presentationTimestamps){const r=N(e.presentationTimestamps,t,e=>e.presentationTimestamp);return-1===r?-1:e.presentationTimestamps[r].sampleIndex}{const r=N(e.sampleTimingEntries,t,e=>e.startDecodeTimestamp);if(-1===r)return-1;const i=e.sampleTimingEntries[r];return i.startIndex+Math.min(Math.floor((t-i.startDecodeTimestamp)/i.delta),i.count-1)}},lr=(e,t)=>{var r;if(!e.keySampleIndices)return or(e,t);if(e.presentationTimestamps){const r=N(e.presentationTimestamps,t,e=>e.presentationTimestamp);if(-1===r)return-1;for(let t=r;t>=0;t--){const r=e.presentationTimestamps[t].sampleIndex;if(-1!==M(e.keySampleIndices,r,e=>e))return r}return-1}{const i=or(e,t),n=N(e.keySampleIndices,i,e=>e);return null!=(r=e.keySampleIndices[n])?r:-1}},cr=(e,t)=>{const r=N(e.sampleTimingEntries,t,e=>e.startIndex),i=e.sampleTimingEntries[r];if(!i||i.startIndex+i.count<=t)return null;let n=i.startDecodeTimestamp+(t-i.startIndex)*i.delta;const s=N(e.sampleCompositionTimeOffsets,t,e=>e.startIndex),a=e.sampleCompositionTimeOffsets[s];a&&t-a.startIndexe.startSampleIndex),c=e.sampleToChunk[l];p(c);const u=c.startChunkIndex+Math.floor((t-c.startSampleIndex)/c.samplesPerChunk),d=e.chunkOffsets[u],h=c.startSampleIndex+(u-c.startChunkIndex)*c.samplesPerChunk;let m=0,f=d;if(1===e.sampleSizes.length)f+=o*(t-h),m+=o*c.samplesPerChunk;else for(let p=h;pe)}},ur=(e,t)=>{var r;if(!e.keySampleIndices)return t+1;const i=N(e.keySampleIndices,t,e=>e);return null!=(r=e.keySampleIndices[i+1])?r:-1},dr=(e,t)=>{e.startTimestamp+=t,e.endTimestamp+=t;for(const r of e.samples)r.presentationTimestamp+=t;for(const r of e.presentationTimestamps)r.presentationTimestamp+=t},hr=e=>{const[t,,,r]=e,i=Math.hypot(t,r),n=t/i,s=r/i,a=-Math.atan2(s,n)*(180/Math.PI);return Number.isFinite(a)?a:0},mr=e=>0===e.sampleSizes.length;var fr,pr;(pr=fr||(fr={}))[pr.EBML=440786851]="EBML",pr[pr.EBMLVersion=17030]="EBMLVersion",pr[pr.EBMLReadVersion=17143]="EBMLReadVersion",pr[pr.EBMLMaxIDLength=17138]="EBMLMaxIDLength",pr[pr.EBMLMaxSizeLength=17139]="EBMLMaxSizeLength",pr[pr.DocType=17026]="DocType",pr[pr.DocTypeVersion=17031]="DocTypeVersion",pr[pr.DocTypeReadVersion=17029]="DocTypeReadVersion",pr[pr.Void=236]="Void",pr[pr.Segment=408125543]="Segment",pr[pr.SeekHead=290298740]="SeekHead",pr[pr.Seek=19899]="Seek",pr[pr.SeekID=21419]="SeekID",pr[pr.SeekPosition=21420]="SeekPosition",pr[pr.Duration=17545]="Duration",pr[pr.Info=357149030]="Info",pr[pr.TimestampScale=2807729]="TimestampScale",pr[pr.MuxingApp=19840]="MuxingApp",pr[pr.WritingApp=22337]="WritingApp",pr[pr.Tracks=374648427]="Tracks",pr[pr.TrackEntry=174]="TrackEntry",pr[pr.TrackNumber=215]="TrackNumber",pr[pr.TrackUID=29637]="TrackUID",pr[pr.TrackType=131]="TrackType",pr[pr.FlagEnabled=185]="FlagEnabled",pr[pr.FlagDefault=136]="FlagDefault",pr[pr.FlagForced=21930]="FlagForced",pr[pr.FlagOriginal=21934]="FlagOriginal",pr[pr.FlagHearingImpaired=21931]="FlagHearingImpaired",pr[pr.FlagVisualImpaired=21932]="FlagVisualImpaired",pr[pr.FlagCommentary=21935]="FlagCommentary",pr[pr.FlagLacing=156]="FlagLacing",pr[pr.Name=21358]="Name",pr[pr.Language=2274716]="Language",pr[pr.LanguageBCP47=2274717]="LanguageBCP47",pr[pr.CodecID=134]="CodecID",pr[pr.CodecPrivate=25506]="CodecPrivate",pr[pr.CodecDelay=22186]="CodecDelay",pr[pr.SeekPreRoll=22203]="SeekPreRoll",pr[pr.DefaultDuration=2352003]="DefaultDuration",pr[pr.Video=224]="Video",pr[pr.PixelWidth=176]="PixelWidth",pr[pr.PixelHeight=186]="PixelHeight",pr[pr.AlphaMode=21440]="AlphaMode",pr[pr.Audio=225]="Audio",pr[pr.SamplingFrequency=181]="SamplingFrequency",pr[pr.Channels=159]="Channels",pr[pr.BitDepth=25188]="BitDepth",pr[pr.SimpleBlock=163]="SimpleBlock",pr[pr.BlockGroup=160]="BlockGroup",pr[pr.Block=161]="Block",pr[pr.BlockAdditions=30113]="BlockAdditions",pr[pr.BlockMore=166]="BlockMore",pr[pr.BlockAdditional=165]="BlockAdditional",pr[pr.BlockAddID=238]="BlockAddID",pr[pr.BlockDuration=155]="BlockDuration",pr[pr.ReferenceBlock=251]="ReferenceBlock",pr[pr.Cluster=524531317]="Cluster",pr[pr.Timestamp=231]="Timestamp",pr[pr.Cues=475249515]="Cues",pr[pr.CuePoint=187]="CuePoint",pr[pr.CueTime=179]="CueTime",pr[pr.CueTrackPositions=183]="CueTrackPositions",pr[pr.CueTrack=247]="CueTrack",pr[pr.CueClusterPosition=241]="CueClusterPosition",pr[pr.Colour=21936]="Colour",pr[pr.MatrixCoefficients=21937]="MatrixCoefficients",pr[pr.TransferCharacteristics=21946]="TransferCharacteristics",pr[pr.Primaries=21947]="Primaries",pr[pr.Range=21945]="Range",pr[pr.Projection=30320]="Projection",pr[pr.ProjectionType=30321]="ProjectionType",pr[pr.ProjectionPoseRoll=30325]="ProjectionPoseRoll",pr[pr.Attachments=423732329]="Attachments",pr[pr.AttachedFile=24999]="AttachedFile",pr[pr.FileDescription=18046]="FileDescription",pr[pr.FileName=18030]="FileName",pr[pr.FileMediaType=18016]="FileMediaType",pr[pr.FileData=18012]="FileData",pr[pr.FileUID=18094]="FileUID",pr[pr.Chapters=272869232]="Chapters",pr[pr.Tags=307544935]="Tags",pr[pr.Tag=29555]="Tag",pr[pr.Targets=25536]="Targets",pr[pr.TargetTypeValue=26826]="TargetTypeValue",pr[pr.TargetType=25546]="TargetType",pr[pr.TagTrackUID=25541]="TagTrackUID",pr[pr.TagEditionUID=25545]="TagEditionUID",pr[pr.TagChapterUID=25540]="TagChapterUID",pr[pr.TagAttachmentUID=25542]="TagAttachmentUID",pr[pr.SimpleTag=26568]="SimpleTag",pr[pr.TagName=17827]="TagName",pr[pr.TagLanguage=17530]="TagLanguage",pr[pr.TagString=17543]="TagString",pr[pr.TagBinary=17541]="TagBinary",pr[pr.ContentEncodings=28032]="ContentEncodings",pr[pr.ContentEncoding=25152]="ContentEncoding",pr[pr.ContentEncodingOrder=20529]="ContentEncodingOrder",pr[pr.ContentEncodingScope=20530]="ContentEncodingScope",pr[pr.ContentCompression=20532]="ContentCompression",pr[pr.ContentCompAlgo=16980]="ContentCompAlgo",pr[pr.ContentCompSettings=16981]="ContentCompSettings",pr[pr.ContentEncryption=20533]="ContentEncryption";const gr=[fr.EBML,fr.Segment],kr=[fr.SeekHead,fr.Info,fr.Cluster,fr.Tracks,fr.Cues,fr.Attachments,fr.Chapters,fr.Tags],br=[...gr,...kr],yr=16,Tr=e=>{if(e.remainingLength<1)return null;const t=Sn(e);if(e.skip(-1),0===t)return null;let r=1,i=128;for(;0===(t&i);)r++,i>>=1;return e.remainingLength{if(e.remainingLength<1)return null;const t=Sn(e);if(0===t)return null;let r=1,i=128;for(;0===(t&i);)r++,i>>=1;if(e.remainingLength{if(t<1||t>8)throw new Error("Bad unsigned int size "+t);let r=0;for(let i=0;i{const t=Tr(e);if(null===t)return null;if(e.remainingLength{if(e.remainingLength<1)return null;if(255===Sn(e))return;e.skip(-1);const t=Sr(e);return null===t?null:72057594037927940!==t?t:void 0},Pr=e=>{p(e.remainingLength>=2);const t=wr(e);if(null===t)return null;const r=Ir(e);return null===r?null:{id:t,size:r}},xr=(e,t)=>{const r=Tn(e,t);let i=0;for(;i{const r=Tn(e,t);let i=0;for(;i{if(0===t)return 0;if(4!==t&&8!==t)throw new Error("Bad float size "+t);return 4===t?Rn(e):Mn(e)},Br=(e,t,r,i)=>u(null,null,function*(){const n=new Set(r);let s=t;for(;null===i||ss?i:s,found:!1}}),Er=(e,t,r,i)=>u(null,null,function*(){const n=o(2,16),s=new Set(r);let a=t;for(;ae.computeDuration()));return Math.max(0,...t)})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.segments.flatMap(e=>e.tracks.map(e=>e.inputTrack))})}getMimeType(){return u(this,null,function*(){yield this.readMetadata();const e=yield this.getTracks(),t=yield Promise.all(e.map(e=>e.getCodecParameterString()));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isWebM?"webm":"x-matroska");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings.filter(Boolean))].join(", ")}"`);return t})({isWebM:this.isWebM,hasVideo:this.segments.some(e=>e.tracks.some(e=>{var t;return"video"===(null==(t=e.info)?void 0:t.type)})),hasAudio:this.segments.some(e=>e.tracks.some(e=>{var t;return"audio"===(null==(t=e.info)?void 0:t.type)})),codecStrings:t.filter(Boolean)})})}getMetadataTags(){return u(this,null,function*(){yield this.readMetadata();for(const t of this.segments)t.metadataTagsCollected||(null!==this.reader.fileSize&&(yield this.loadSegmentMetadata(t)),t.metadataTagsCollected=!0);let e={};for(const t of this.segments)e=c(c({},e),t.metadataTags);return e})}readMetadata(){var e;return null!=(e=this.readMetadataPromise)?e:this.readMetadataPromise=(()=>u(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,2,yr);if(t instanceof Promise&&(t=yield t),!t)break;const r=Pr(t);if(!r)break;const i=r.id;let n=r.size;const s=t.filePos;if(i===fr.EBML){Vr(n);let e=this.reader.requestSlice(s,n);if(e instanceof Promise&&(e=yield e),!e)break;this.readContiguousElements(e)}else if(i===fr.Segment){if(yield this.readSegment(s,n),void 0===n)break;if(null===this.reader.fileSize)break}else if(i===fr.Cluster){if(null===this.reader.fileSize)break;if(void 0===n){n=(yield Br(this.reader,s,br,this.reader.fileSize)).pos-s}const e=k(this.segments);e&&(e.elementEndPos=s+n)}Vr(n),e=s+n}}))()}readSegment(e,t){return u(this,null,function*(){var r;this.currentSegment={seekHeadSeen:!1,infoSeen:!1,tracksSeen:!1,cuesSeen:!1,tagsSeen:!1,attachmentsSeen:!1,timestampScale:-1,timestampFactor:-1,duration:-1,seekEntries:[],tracks:[],cuePoints:[],dataStartPos:e,elementEndPos:void 0===t?null:e+t,clusterSeekStartPos:e,lastReadCluster:null,metadataTags:{},metadataTagsCollected:!1},this.segments.push(this.currentSegment);let i=e;for(;null===this.currentSegment.elementEndPos||ie.id===s);if(-1!==l){const e=Qr[l].flag;this.currentSegment[e]=!0,Vr(a);let t=this.reader.requestSlice(o,a);t instanceof Promise&&(t=yield t),t&&this.readContiguousElements(t)}else if(s===fr.Tags||s===fr.Attachments){s===fr.Tags?this.currentSegment.tagsSeen=!0:this.currentSegment.attachmentsSeen=!0,Vr(a);let e=this.reader.requestSlice(o,a);e instanceof Promise&&(e=yield e),e&&this.readContiguousElements(e)}else if(s===fr.Cluster){this.currentSegment.clusterSeekStartPos=t;break}if(void 0===a)break;i=o+a}if(this.currentSegment.seekEntries.sort((e,t)=>e.segmentPosition-t.segmentPosition),null!==this.reader.fileSize)for(const t of this.currentSegment.seekEntries){const r=Qr.find(e=>e.id===t.id);if(!r)continue;if(this.currentSegment[r.flag])continue;let i=this.reader.requestSliceRange(e+t.segmentPosition,2,yr);if(i instanceof Promise&&(i=yield i),!i)continue;const n=Pr(i);if(!n)continue;const{id:s,size:a}=n;if(s!==r.id)continue;Vr(a),this.currentSegment[r.flag]=!0;let o=this.reader.requestSlice(i.filePos,a);o instanceof Promise&&(o=yield o),o&&this.readContiguousElements(o)}-1===this.currentSegment.timestampScale&&(this.currentSegment.timestampScale=1e6,this.currentSegment.timestampFactor=1e3);for(const e of this.currentSegment.tracks)null!==e.defaultDurationNs&&(e.defaultDuration=this.currentSegment.timestampFactor*e.defaultDurationNs/1e9);this.currentSegment.tracks.sort((e,t)=>Number(t.disposition.default)-Number(e.disposition.default));const n=new Map(this.currentSegment.tracks.map(e=>[e.id,e]));for(const e of this.currentSegment.cuePoints){const t=n.get(e.trackId);t&&t.cuePoints.push(e)}for(const e of this.currentSegment.tracks){e.cuePoints.sort((e,t)=>e.time-t.time);for(let t=0;ta&&(a=e.cuePoints.length,s=e);for(const e of this.currentSegment.tracks)0===e.cuePoints.length&&(e.cuePoints=s.cuePoints);this.currentSegment=null})}readCluster(e,t){return u(this,null,function*(){var r;if((null==(r=t.lastReadCluster)?void 0:r.elementStartPos)===e)return t.lastReadCluster;let i=this.reader.requestSliceRange(e,2,yr);i instanceof Promise&&(i=yield i),p(i);const n=e,s=Pr(i);p(s);p(s.id===fr.Cluster);let a=s.size;const o=i.filePos;if(void 0===a){a=(yield Br(this.reader,o,br,t.elementEndPos)).pos-o}let l=this.reader.requestSlice(o,a);l instanceof Promise&&(l=yield l);const c={segment:t,elementStartPos:n,elementEndPos:o+a,dataStartPos:o,timestamp:-1,trackData:new Map};if(this.currentCluster=c,l){const e=this.readContiguousElements(l,br);c.elementEndPos=e}for(const[,e]of c.trackData){const t=e.track;p(e.blocks.length>0);let r=!1;for(let n=0;n({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp);for(let n=0;n({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp));const i=e.blocks[e.presentationTimestamps[0].blockIndex],s=e.blocks[k(e.presentationTimestamps).blockIndex];e.startTimestamp=i.timestamp,e.endTimestamp=s.timestamp+s.duration;const a=N(t.clusterPositionCache,e.startTimestamp,e=>e.startTimestamp);-1!==a&&t.clusterPositionCache[a].elementStartPos===n||t.clusterPositionCache.splice(a+1,0,{elementStartPos:c.elementStartPos,startTimestamp:e.startTimestamp})}return t.lastReadCluster=c,c})}getTrackDataInCluster(e,t){let r=e.trackData.get(t);if(!r){const i=e.segment.tracks.find(e=>e.id===t);if(!i)return null;r={track:i,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,blocks:[],presentationTimestamps:[]},e.trackData.set(t,r)}return r}expandLacedBlocks(e,t){var r;for(let i=0;i=2;){const r=e.filePos;if(!this.traverseElement(e,t))return r}return e.filePos}traverseElement(e,t){var r,i,n,s,a,o,l,u,d,h,m,f,k,b,y,T,S,v,w,I,P,C,B,F,D,A,R,M,N,z,O,L,U,V,q,H,W,j,K,Q,G,Y,J,Z,ee,te,re,ie;const ne=Pr(e);if(!ne)return!1;if(t&&t.includes(ne.id))return!1;const{id:se,size:ae}=ne,oe=e.filePos;switch(Vr(ae),se){case fr.DocType:this.isWebM="webm"===xr(e,ae);break;case fr.Seek:{if(!this.currentSegment)break;const t={id:-1,segmentPosition:-1};this.currentSegment.seekEntries.push(t),this.readContiguousElements(e.slice(oe,ae)),-1!==t.id&&-1!==t.segmentPosition||this.currentSegment.seekEntries.pop()}break;case fr.SeekID:{const t=null==(r=this.currentSegment)?void 0:r.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.id=vr(e,ae)}break;case fr.SeekPosition:{const t=null==(i=this.currentSegment)?void 0:i.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.segmentPosition=vr(e,ae)}break;case fr.TimestampScale:if(!this.currentSegment)break;this.currentSegment.timestampScale=vr(e,ae),this.currentSegment.timestampFactor=1e9/this.currentSegment.timestampScale;break;case fr.Duration:if(!this.currentSegment)break;this.currentSegment.duration=_r(e,ae);break;case fr.TrackEntry:if(!this.currentSegment)break;if(this.currentTrack={id:-1,segment:this.currentSegment,demuxer:this,clusterPositionCache:[],cuePoints:[],disposition:c({},ge),inputTrack:null,codecId:null,codecPrivate:null,defaultDuration:null,defaultDurationNs:null,name:null,languageCode:$,decodingInstructions:[],info:null},this.readContiguousElements(e.slice(oe,ae)),!this.currentTrack)break;if(this.currentTrack.decodingInstructions.some(e=>{var t;return"decompress"!==(null==(t=e.data)?void 0:t.type)||e.scope!==Wr.Block||e.data.algorithm!==Kr.HeaderStripping})&&(console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`),this.currentTrack=null),this.currentTrack&&-1!==this.currentTrack.id&&this.currentTrack.codecId&&this.currentTrack.info){const e=this.currentTrack.codecId.indexOf("/"),t=-1===e?this.currentTrack.codecId:this.currentTrack.codecId.slice(0,e);if("video"===this.currentTrack.info.type&&-1!==this.currentTrack.info.width&&-1!==this.currentTrack.info.height){this.currentTrack.codecId===Fr?(this.currentTrack.info.codec="avc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Dr?(this.currentTrack.info.codec="hevc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ar?this.currentTrack.info.codec="vp8":t===Rr?this.currentTrack.info.codec="vp9":t===Mr&&(this.currentTrack.info.codec="av1");const e=this.currentTrack,r=new Gt(this.input,new Jr(e));this.currentTrack.inputTrack=r,this.currentSegment.tracks.push(this.currentTrack)}else if("audio"===this.currentTrack.info.type&&-1!==this.currentTrack.info.numberOfChannels&&-1!==this.currentTrack.info.sampleRate){t===Nr?(this.currentTrack.info.codec="aac",this.currentTrack.info.aacCodecInfo={isMpeg2:this.currentTrack.codecId.includes("MPEG2")},this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===zr?this.currentTrack.info.codec="mp3":t===Or?(this.currentTrack.info.codec="opus",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate,this.currentTrack.info.sampleRate=xe):t===Lr?(this.currentTrack.info.codec="vorbis",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ur?(this.currentTrack.info.codec="flac",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):"A_PCM/INT/LIT"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32"):"A_PCM/INT/BIG"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16be":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24be":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32be"):"A_PCM/FLOAT/IEEE"===this.currentTrack.codecId&&(32===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-f32":64===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-f64"));const e=this.currentTrack,r=new Xt(this.input,new Zr(e));this.currentTrack.inputTrack=r,this.currentSegment.tracks.push(this.currentTrack)}}this.currentTrack=null;break;case fr.TrackNumber:if(!this.currentTrack)break;this.currentTrack.id=vr(e,ae);break;case fr.TrackType:{if(!this.currentTrack)break;const t=vr(e,ae);1===t?this.currentTrack.info={type:"video",width:-1,height:-1,rotation:0,codec:null,codecDescription:null,colorSpace:null,alphaMode:!1}:2===t&&(this.currentTrack.info={type:"audio",numberOfChannels:-1,sampleRate:-1,bitDepth:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case fr.FlagEnabled:if(!this.currentTrack)break;vr(e,ae)||(this.currentTrack=null);break;case fr.FlagDefault:if(!this.currentTrack)break;this.currentTrack.disposition.default=!!vr(e,ae);break;case fr.FlagForced:if(!this.currentTrack)break;this.currentTrack.disposition.forced=!!vr(e,ae);break;case fr.FlagOriginal:if(!this.currentTrack)break;this.currentTrack.disposition.original=!!vr(e,ae);break;case fr.FlagHearingImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.hearingImpaired=!!vr(e,ae);break;case fr.FlagVisualImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.visuallyImpaired=!!vr(e,ae);break;case fr.FlagCommentary:if(!this.currentTrack)break;this.currentTrack.disposition.commentary=!!vr(e,ae);break;case fr.CodecID:if(!this.currentTrack)break;this.currentTrack.codecId=xr(e,ae);break;case fr.CodecPrivate:if(!this.currentTrack)break;this.currentTrack.codecPrivate=Tn(e,ae);break;case fr.DefaultDuration:if(!this.currentTrack)break;this.currentTrack.defaultDurationNs=vr(e,ae);break;case fr.Name:if(!this.currentTrack)break;this.currentTrack.name=Cr(e,ae);break;case fr.Language:if(!this.currentTrack)break;if(this.currentTrack.languageCode!==$)break;this.currentTrack.languageCode=xr(e,ae),X(this.currentTrack.languageCode)||(this.currentTrack.languageCode=$);break;case fr.LanguageBCP47:{if(!this.currentTrack)break;const t=xr(e,ae).split("-")[0];this.currentTrack.languageCode=t||$}break;case fr.Video:if("video"!==(null==(s=null==(n=this.currentTrack)?void 0:n.info)?void 0:s.type))break;this.readContiguousElements(e.slice(oe,ae));break;case fr.PixelWidth:if("video"!==(null==(o=null==(a=this.currentTrack)?void 0:a.info)?void 0:o.type))break;this.currentTrack.info.width=vr(e,ae);break;case fr.PixelHeight:if("video"!==(null==(u=null==(l=this.currentTrack)?void 0:l.info)?void 0:u.type))break;this.currentTrack.info.height=vr(e,ae);break;case fr.AlphaMode:if("video"!==(null==(h=null==(d=this.currentTrack)?void 0:d.info)?void 0:h.type))break;this.currentTrack.info.alphaMode=1===vr(e,ae);break;case fr.Colour:if("video"!==(null==(f=null==(m=this.currentTrack)?void 0:m.info)?void 0:f.type))break;this.currentTrack.info.colorSpace={},this.readContiguousElements(e.slice(oe,ae));break;case fr.MatrixCoefficients:{if("video"!==(null==(b=null==(k=this.currentTrack)?void 0:k.info)?void 0:b.type)||!this.currentTrack.info.colorSpace)break;const t=vr(e,ae),r=null!=(y=E[t])?y:null;this.currentTrack.info.colorSpace.matrix=r}break;case fr.Range:if("video"!==(null==(S=null==(T=this.currentTrack)?void 0:T.info)?void 0:S.type)||!this.currentTrack.info.colorSpace)break;this.currentTrack.info.colorSpace.fullRange=2===vr(e,ae);break;case fr.TransferCharacteristics:{if("video"!==(null==(w=null==(v=this.currentTrack)?void 0:v.info)?void 0:w.type)||!this.currentTrack.info.colorSpace)break;const t=vr(e,ae),r=null!=(I=_[t])?I:null;this.currentTrack.info.colorSpace.transfer=r}break;case fr.Primaries:{if("video"!==(null==(C=null==(P=this.currentTrack)?void 0:P.info)?void 0:C.type)||!this.currentTrack.info.colorSpace)break;const t=vr(e,ae),r=null!=(B=x[t])?B:null;this.currentTrack.info.colorSpace.primaries=r}break;case fr.Projection:if("video"!==(null==(D=null==(F=this.currentTrack)?void 0:F.info)?void 0:D.type))break;this.readContiguousElements(e.slice(oe,ae));break;case fr.ProjectionPoseRoll:{if("video"!==(null==(R=null==(A=this.currentTrack)?void 0:A.info)?void 0:R.type))break;const t=-_r(e,ae);try{this.currentTrack.info.rotation=g(t)}catch(le){}}break;case fr.Audio:if("audio"!==(null==(N=null==(M=this.currentTrack)?void 0:M.info)?void 0:N.type))break;this.readContiguousElements(e.slice(oe,ae));break;case fr.SamplingFrequency:if("audio"!==(null==(O=null==(z=this.currentTrack)?void 0:z.info)?void 0:O.type))break;this.currentTrack.info.sampleRate=_r(e,ae);break;case fr.Channels:if("audio"!==(null==(U=null==(L=this.currentTrack)?void 0:L.info)?void 0:U.type))break;this.currentTrack.info.numberOfChannels=vr(e,ae);break;case fr.BitDepth:if("audio"!==(null==(q=null==(V=this.currentTrack)?void 0:V.info)?void 0:q.type))break;this.currentTrack.info.bitDepth=vr(e,ae);break;case fr.CuePoint:if(!this.currentSegment)break;this.readContiguousElements(e.slice(oe,ae)),this.currentCueTime=null;break;case fr.CueTime:this.currentCueTime=vr(e,ae);break;case fr.CueTrackPositions:{if(null===this.currentCueTime)break;p(this.currentSegment);const t={time:this.currentCueTime,trackId:-1,clusterPosition:-1};this.currentSegment.cuePoints.push(t),this.readContiguousElements(e.slice(oe,ae)),-1!==t.trackId&&-1!==t.clusterPosition||this.currentSegment.cuePoints.pop()}break;case fr.CueTrack:{const t=null==(H=this.currentSegment)?void 0:H.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;t.trackId=vr(e,ae)}break;case fr.CueClusterPosition:{const t=null==(W=this.currentSegment)?void 0:W.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;p(this.currentSegment),t.clusterPosition=this.currentSegment.dataStartPos+vr(e,ae)}break;case fr.Timestamp:if(!this.currentCluster)break;this.currentCluster.timestamp=vr(e,ae);break;case fr.SimpleBlock:{if(!this.currentCluster)break;const t=Sr(e);if(null===t)break;const r=this.getTrackDataInCluster(this.currentCluster,t);if(!r)break;const i=Pn(e),n=Sn(e),s=n>>1&3;let a=!!(128&n);"audio"===(null==(j=r.track.info)?void 0:j.type)&&r.track.info.codec&&(a=!0);const o=Tn(e,ae-(e.filePos-oe)),l=r.track.decodingInstructions.length>0;r.blocks.push({timestamp:i,duration:0,isKeyFrame:a,data:o,lacing:s,decoded:!l,mainAdditional:null})}break;case fr.BlockGroup:if(!this.currentCluster)break;this.readContiguousElements(e.slice(oe,ae)),this.currentBlock=null;break;case fr.Block:{if(!this.currentCluster)break;const t=Sr(e);if(null===t)break;const r=this.getTrackDataInCluster(this.currentCluster,t);if(!r)break;const i=Pn(e),n=Sn(e)>>1&3,s=Tn(e,ae-(e.filePos-oe)),a=r.track.decodingInstructions.length>0;this.currentBlock={timestamp:i,duration:0,isKeyFrame:!0,data:s,lacing:n,decoded:!a,mainAdditional:null},r.blocks.push(this.currentBlock)}break;case fr.BlockAdditions:this.readContiguousElements(e.slice(oe,ae));break;case fr.BlockMore:if(!this.currentBlock)break;this.currentBlockAdditional={addId:1,data:null},this.readContiguousElements(e.slice(oe,ae)),this.currentBlockAdditional.data&&1===this.currentBlockAdditional.addId&&(this.currentBlock.mainAdditional=this.currentBlockAdditional.data),this.currentBlockAdditional=null;break;case fr.BlockAdditional:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.data=Tn(e,ae);break;case fr.BlockAddID:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.addId=vr(e,ae);break;case fr.BlockDuration:if(!this.currentBlock)break;this.currentBlock.duration=vr(e,ae);break;case fr.ReferenceBlock:if(!this.currentBlock)break;this.currentBlock.isKeyFrame=!1;break;case fr.Tag:this.currentTagTargetIsMovie=!0,this.readContiguousElements(e.slice(oe,ae));break;case fr.Targets:this.readContiguousElements(e.slice(oe,ae));break;case fr.TargetTypeValue:50!==vr(e,ae)&&(this.currentTagTargetIsMovie=!1);break;case fr.TagTrackUID:case fr.TagEditionUID:case fr.TagChapterUID:case fr.TagAttachmentUID:this.currentTagTargetIsMovie=!1;break;case fr.SimpleTag:if(!this.currentTagTargetIsMovie)break;this.currentSimpleTagName=null,this.readContiguousElements(e.slice(oe,ae));break;case fr.TagName:this.currentSimpleTagName=Cr(e,ae);break;case fr.TagString:{if(!this.currentSimpleTagName)break;const t=Cr(e,ae);this.processTagValue(this.currentSimpleTagName,t)}break;case fr.TagBinary:{if(!this.currentSimpleTagName)break;const t=Tn(e,ae);this.processTagValue(this.currentSimpleTagName,t)}break;case fr.AttachedFile:{if(!this.currentSegment)break;this.currentAttachedFile={fileUid:null,fileName:null,fileMediaType:null,fileData:null,fileDescription:null},this.readContiguousElements(e.slice(oe,ae));const t=this.currentSegment.metadataTags;if(this.currentAttachedFile.fileUid&&this.currentAttachedFile.fileData&&(null!=t.raw||(t.raw={}),t.raw[this.currentAttachedFile.fileUid.toString()]=new pe(this.currentAttachedFile.fileData,null!=(K=this.currentAttachedFile.fileMediaType)?K:void 0,null!=(Q=this.currentAttachedFile.fileName)?Q:void 0,null!=(G=this.currentAttachedFile.fileDescription)?G:void 0)),(null==(Y=this.currentAttachedFile.fileMediaType)?void 0:Y.startsWith("image/"))&&this.currentAttachedFile.fileData){const e=this.currentAttachedFile.fileName;let r="unknown";if(e){const t=e.toLowerCase();t.startsWith("cover.")?r="coverFront":t.startsWith("back.")&&(r="coverBack")}null!=t.images||(t.images=[]),t.images.push({data:this.currentAttachedFile.fileData,mimeType:this.currentAttachedFile.fileMediaType,kind:r,name:null!=(J=this.currentAttachedFile.fileName)?J:void 0,description:null!=(Z=this.currentAttachedFile.fileDescription)?Z:void 0})}this.currentAttachedFile=null}break;case fr.FileUID:if(!this.currentAttachedFile)break;this.currentAttachedFile.fileUid=((e,t)=>{if(t<1)throw new Error("Bad unsigned int size "+t);let r=BigInt("0");for(let i=0;it.order-e.order);break;case fr.ContentEncoding:this.currentDecodingInstruction={order:0,scope:Wr.Block,data:null},this.readContiguousElements(e.slice(oe,ae)),this.currentDecodingInstruction.data&&this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction),this.currentDecodingInstruction=null;break;case fr.ContentEncodingOrder:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.order=vr(e,ae);break;case fr.ContentEncodingScope:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.scope=vr(e,ae);break;case fr.ContentCompression:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decompress",algorithm:Kr.Zlib,settings:null},this.readContiguousElements(e.slice(oe,ae));break;case fr.ContentCompAlgo:if("decompress"!==(null==(te=null==(ee=this.currentDecodingInstruction)?void 0:ee.data)?void 0:te.type))break;this.currentDecodingInstruction.data.algorithm=vr(e,ae);break;case fr.ContentCompSettings:if("decompress"!==(null==(ie=null==(re=this.currentDecodingInstruction)?void 0:re.data)?void 0:ie.type))break;this.currentDecodingInstruction.data.settings=Tn(e,ae);break;case fr.ContentEncryption:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decrypt"}}return e.filePos=oe+ae,!0}decodeBlockData(e,t){p(e.decodingInstructions.length>0);let r=t;for(const i of e.decodingInstructions)if(p(i.data),"decompress"===i.data.type)if(i.data.algorithm===Kr.HeaderStripping)if(i.data.settings&&i.data.settings.length>0){const e=i.data.settings,t=new Uint8Array(e.length+r.length);t.set(e,0),t.set(r,e.length),r=t}return r}processTagValue(e,t){var r,i;if(!(null==(r=this.currentSegment)?void 0:r.metadataTags))return;const n=this.currentSegment.metadataTags;if(null!=n.raw||(n.raw={}),null!=(i=n.raw)[e]||(i[e]=t),"string"===typeof t)switch(e.toLowerCase()){case"title":null!=n.title||(n.title=t);break;case"description":null!=n.description||(n.description=t);break;case"artist":null!=n.artist||(n.artist=t);break;case"album":null!=n.album||(n.album=t);break;case"album_artist":null!=n.albumArtist||(n.albumArtist=t);break;case"genre":null!=n.genre||(n.genre=t);break;case"comment":null!=n.comment||(n.comment=t);break;case"lyrics":null!=n.lyrics||(n.lyrics=t);break;case"date":{const e=new Date(t);Number.isNaN(e.getTime())||null!=n.date||(n.date=e)}break;case"track_number":case"part_number":{const e=t.split("/"),r=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(null!=n.trackNumber||(n.trackNumber=r)),i&&Number.isInteger(i)&&i>0&&(null!=n.tracksTotal||(n.tracksTotal=i))}break;case"disc_number":case"disc":{const e=t.split("/"),r=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(r)&&r>0&&(null!=n.discNumber||(n.discNumber=r)),i&&Number.isInteger(i)&&i>0&&(null!=n.discsTotal||(n.discsTotal=i))}}}}class Yr{constructor(e){this.internalTrack=e,this.packetToClusterLocation=new WeakMap}getId(){return this.internalTrack.id}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.codecId}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getFirstTimestamp(){return u(this,null,function*(){var e;const t=yield this.getFirstPacket({metadataOnly:!0});return null!=(e=null==t?void 0:t.timestamp)?e:0})}getTimeResolution(){return this.internalTrack.segment.timestampFactor}getDisposition(){return this.internalTrack.disposition}getFirstPacket(e){return u(this,null,function*(){return this.performClusterLookup(null,e=>e.trackData.get(this.internalTrack.id)?{blockIndex:0,correctBlockFound:!0}:{blockIndex:-1,correctBlockFound:!1},-1/0,1/0,e)})}intoTimescale(e){return Q(e*this.internalTrack.segment.timestampFactor)}getPacket(e,t){return u(this,null,function*(){const r=this.intoTimescale(e);return this.performClusterLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const i=N(t.presentationTimestamps,r,e=>e.timestamp);return{blockIndex:-1!==i?t.presentationTimestamps[i].blockIndex:-1,correctBlockFound:-1!==i&&r{if(e===r.cluster){const t=e.trackData.get(this.internalTrack.id);if(r.blockIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const i=U(t.presentationTimestamps,e=>t.blocks[e.blockIndex].isKeyFrame&&e.timestamp<=r);return{blockIndex:-1!==i?t.presentationTimestamps[i].blockIndex:-1,correctBlockFound:-1!==i&&r{if(e===r.cluster){const t=e.trackData.get(this.internalTrack.id).blocks.findIndex((e,t)=>e.isKeyFrame&&t>r.blockIndex);if(-1!==t)return{blockIndex:t,correctBlockFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.blocks.findIndex(e=>e.isKeyFrame);return p(-1!==e),{blockIndex:e,correctBlockFound:!0}}}return{blockIndex:-1,correctBlockFound:!1}},-1/0,1/0,t)})}fetchPacketInCluster(e,t,r){return u(this,null,function*(){var i;if(-1===t)return null;const n=e.trackData.get(this.internalTrack.id).blocks[t];p(n),n.decoded||(n.data=this.internalTrack.demuxer.decodeBlockData(this.internalTrack,n.data),n.decoded=!0);const s=r.metadataOnly?ut:n.data,a=n.timestamp/this.internalTrack.segment.timestampFactor,o=n.duration/this.internalTrack.segment.timestampFactor,l={};n.mainAdditional&&"video"===(null==(i=this.internalTrack.info)?void 0:i.type)&&this.internalTrack.info.alphaMode&&(l.alpha=r.metadataOnly?ut:n.mainAdditional,l.alphaByteLength=n.mainAdditional.byteLength);const c=new dt(s,n.isKeyFrame?"key":"delta",a,o,e.dataStartPos+t,n.data.byteLength,l);return this.packetToClusterLocation.set(c,{cluster:e,blockIndex:t}),c})}performClusterLookup(e,t,r,i,n){return u(this,null,function*(){var s,a,o,l;const{demuxer:c,segment:u}=this.internalTrack;let d=null,h=null,m=-1;if(e){const{blockIndex:r,correctBlockFound:i}=t(e);if(i)return this.fetchPacketInCluster(e,r,n);-1!==r&&(h=e,m=r)}const f=N(this.internalTrack.cuePoints,r,e=>e.time),g=-1!==f?this.internalTrack.cuePoints[f]:null,k=N(this.internalTrack.clusterPositionCache,r,e=>e.startTimestamp),b=-1!==k?this.internalTrack.clusterPositionCache[k]:null,y=Math.max(null!=(s=null==g?void 0:g.clusterPosition)?s:0,null!=(a=null==b?void 0:b.elementStartPos)?a:0)||null;let T;for(e?null===y||e.elementStartPos>=y?(T=e.elementEndPos,d=e):T=y:T=null!=y?y:u.clusterSeekStartPos;null===u.elementEndPos||T<=u.elementEndPos-2;){if(d){const e=d.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>i)break}let e=c.reader.requestSliceRange(T,2,yr);if(e instanceof Promise&&(e=yield e),!e)break;const r=T,s=Pr(e);if(!s||!kr.includes(s.id)&&s.id!==fr.Void){const e=yield Er(c.reader,r,kr,Math.min(null!=(o=u.elementEndPos)?o:1/0,r+Gr));if(e){T=e;continue}break}const a=s.id;let l=s.size;const f=e.filePos;if(a===fr.Cluster){d=yield c.readCluster(r,u),l=d.elementEndPos-f;const{blockIndex:e,correctBlockFound:i}=t(d);if(i)return this.fetchPacketInCluster(d,e,n);-1!==e&&(h=d,m=e)}if(void 0===l){p(a!==fr.Cluster);l=(yield Br(c.reader,f,br,u.elementEndPos)).pos-f}const g=f+l;if(null===u.elementEndPos){let e=c.reader.requestSliceRange(g,2,yr);if(e instanceof Promise&&(e=yield e),!e)break;if(wr(e)===fr.Segment){u.elementEndPos=g;break}}T=g}if(g&&(!h||h.elementStartPosu(this,null,function*(){var e,t;let r=null;return("vp9"===this.internalTrack.info.codec||"av1"===this.internalTrack.info.codec||"avc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription||"hevc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription)&&(r=yield this.getFirstPacket({})),{codec:Se({width:this.internalTrack.info.width,height:this.internalTrack.info.height,codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,colorSpace:this.internalTrack.info.colorSpace,avcType:1,avcCodecInfo:"avc"===this.internalTrack.info.codec&&r?Ue(r.data):null,hevcCodecInfo:"hevc"===this.internalTrack.info.codec&&r?We(r.data):null,vp9CodecInfo:"vp9"===this.internalTrack.info.codec&&r?Je(r.data):null,av1CodecInfo:"av1"===this.internalTrack.info.codec&&r?et(r.data):null}),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0,colorSpace:null!=(t=this.internalTrack.info.colorSpace)?t:void 0}}))():null})}}class Zr extends Yr{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}getDecoderConfig(){return u(this,null,function*(){var e,t;return this.internalTrack.info.codec?null!=(t=this.decoderConfig)?t:this.decoderConfig={codec:ve({codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,aacCodecInfo:this.internalTrack.info.aacCodecInfo}),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0}:null})}}const ei=[44100,48e3,32e3],ti=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1,-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1,-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1],ri=(e,t)=>{const r=e>>>24,i=e>>>16&255,n=e>>>8&255,s=255&e;if(255!==r&&255!==i&&255!==n&&255!==s)return{header:null,bytesAdvanced:4};if(255!==r)return{header:null,bytesAdvanced:1};if(224!==(224&i))return{header:null,bytesAdvanced:1};let a=0,o=0;16&i?a=8&i?0:1:(a=1,o=1);const l=i>>3&3,c=i>>1&3,u=(n>>2&3)%3,d=s>>6&3,h=s>>4&3,m=s>>3&1,f=s>>2&1,p=3&s,g=ti[16*a*4+16*c+(n>>4&15)];if(-1===g)return{header:null,bytesAdvanced:1};const k=1e3*g,b=ei[u]>>a+o,y=((e,t,r,i,n)=>0===t?0:1===t?Math.floor(144*r/(i<>1&1);if(null!==t&&t{let t=2130706432,r=0;for(;0!==t;)r>>=1,r|=e&t,t>>=8;return r};var ni,si,ai,oi;(si=ni||(ni={}))[si.Unsynchronisation=128]="Unsynchronisation",si[si.ExtendedHeader=64]="ExtendedHeader",si[si.ExperimentalIndicator=32]="ExperimentalIndicator",si[si.Footer=16]="Footer",(oi=ai||(ai={}))[oi.ISO_8859_1=0]="ISO_8859_1",oi[oi.UTF_16_WITH_BOM=1]="UTF_16_WITH_BOM",oi[oi.UTF_16_BE_NO_BOM=2]="UTF_16_BE_NO_BOM",oi[oi.UTF_8=3]="UTF_8";const li=128,ci=["Blues","Classic rock","Country","Dance","Disco","Funk","Grunge","Hip-hop","Jazz","Metal","New age","Oldies","Other","Pop","Rhythm and blues","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death metal","Pranks","Soundtrack","Euro-techno","Ambient","Trip-hop","Vocal","Jazz & funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound clip","Gospel","Noise","Alternative rock","Bass","Soul","Punk","Space","Meditative","Instrumental pop","Instrumental rock","Ethnic","Gothic","Darkwave","Techno-industrial","Electronic","Pop-folk","Eurodance","Dream","Southern rock","Comedy","Cult","Gangsta","Top 40","Christian rap","Pop/funk","Jungle music","Native US","Cabaret","New wave","Psychedelic","Rave","Showtunes","Trailer","Lo-fi","Tribal","Acid punk","Acid jazz","Polka","Retro","Musical","Rock 'n' roll","Hard rock","Folk","Folk rock","National folk","Swing","Fast fusion","Bebop","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic rock","Progressive rock","Psychedelic rock","Symphonic rock","Slow rock","Big band","Chorus","Easy listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber music","Sonata","Symphony","Booty bass","Primus","Porn groove","Satire","Slow jam","Club","Tango","Samba","Folklore","Ballad","Power ballad","Rhythmic Soul","Freestyle","Duet","Punk rock","Drum solo","A cappella","Euro-house","Dance hall","Goa music","Drum & bass","Club-house","Hardcore techno","Terror","Indie","Britpop","Negerpunk","Polsk punk","Beat","Christian gangsta rap","Heavy metal","Black metal","Crossover","Contemporary Christian","Christian rock","Merengue","Salsa","Thrash metal","Anime","Jpop","Synthpop","Christmas","Art rock","Baroque","Bhangra","Big beat","Breakbeat","Chillout","Downtempo","Dub","EBM","Eclectic","Electro","Electroclash","Emo","Experimental","Garage","Global","IDM","Illbient","Industro-Goth","Jam Band","Krautrock","Leftfield","Lounge","Math rock","New romantic","Nu-breakz","Post-punk","Post-rock","Psytrance","Shoegaze","Space rock","Trop rock","World music","Neoclassical","Audiobook","Audio theatre","Neue Deutsche Welle","Podcast","Indie rock","G-Funk","Dubstep","Garage rock","Psybient"],ui=(e,t)=>{const r=Tn(e,t),i=ce(r.indexOf(0),r.length),n=r.subarray(0,i);let s="";for(let a=0;a{const t=e.filePos,r=Nn(e,3),i=Sn(e),n=Sn(e),s=Sn(e),a=Cn(e);if("ID3"!==r||255===i||255===n||0!==(2155905152&a))return e.filePos=t,null;return{majorVersion:i,revision:n,flags:s,size:ii(a)}},hi=(e,t,r)=>{var i,n,s,a;if(![2,3,4].includes(t.majorVersion))return void console.warn(`Unsupported ID3v2 major version: ${t.majorVersion}`);const o=Tn(e,t.size),l=new mi(t,o);if(t.flags&ni.Footer&&l.removeFooter(),t.flags&ni.Unsynchronisation&&3===t.majorVersion&&l.ununsynchronizeAll(),t.flags&ni.ExtendedHeader){const e=l.readU32();3===t.majorVersion?l.pos+=e:l.pos+=e-4}for(;l.pos<=l.bytes.length-l.frameHeaderSize();){const e=l.readId3V2Frame();if(!e)break;const o=l.pos,c=l.pos+e.size;let u=!1,d=!1,h=!1;if(3===t.majorVersion?(u=!!(64&e.flags),d=!!(128&e.flags)):4===t.majorVersion&&(u=!!(4&e.flags),d=!!(8&e.flags),h=!!(2&e.flags)||!!(t.flags&ni.Unsynchronisation)),u)console.warn(`Skipping encrypted ID3v2 frame ${e.id}`),l.pos=c;else if(d)console.warn(`Skipping compressed ID3v2 frame ${e.id}`),l.pos=c;else{switch(h&&l.ununsynchronizeRegion(l.pos,c),null!=r.raw||(r.raw={}),"T"===e.id[0]?null!=(i=r.raw)[n=e.id]||(i[n]=l.readId3V2EncodingAndText(c)):null!=(s=r.raw)[a=e.id]||(s[a]=l.readBytes(e.size)),l.pos=o,e.id){case"TIT2":case"TT2":null!=r.title||(r.title=l.readId3V2EncodingAndText(c));break;case"TIT3":case"TT3":null!=r.description||(r.description=l.readId3V2EncodingAndText(c));break;case"TPE1":case"TP1":null!=r.artist||(r.artist=l.readId3V2EncodingAndText(c));break;case"TALB":case"TAL":null!=r.album||(r.album=l.readId3V2EncodingAndText(c));break;case"TPE2":case"TP2":null!=r.albumArtist||(r.albumArtist=l.readId3V2EncodingAndText(c));break;case"TRCK":case"TRK":{const e=l.readId3V2EncodingAndText(c).split("/"),t=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(null!=r.trackNumber||(r.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&(null!=r.tracksTotal||(r.tracksTotal=i))}break;case"TPOS":case"TPA":{const e=l.readId3V2EncodingAndText(c).split("/"),t=Number.parseInt(e[0],10),i=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(null!=r.discNumber||(r.discNumber=t)),i&&Number.isInteger(i)&&i>0&&(null!=r.discsTotal||(r.discsTotal=i))}break;case"TCON":case"TCO":{const e=l.readId3V2EncodingAndText(c);let t=/^\((\d+)\)/.exec(e);if(t){const e=Number.parseInt(t[1]);if(void 0!==ci[e]){null!=r.genre||(r.genre=ci[e]);break}}if(t=/^\d+$/.exec(e),t){const e=Number.parseInt(t[0]);if(void 0!==ci[e]){null!=r.genre||(r.genre=ci[e]);break}}null!=r.genre||(r.genre=e)}break;case"TDRC":case"TDAT":{const e=l.readId3V2EncodingAndText(c),t=new Date(e);Number.isNaN(t.getTime())||null!=r.date||(r.date=t)}break;case"TYER":case"TYE":{const e=l.readId3V2EncodingAndText(c),t=Number.parseInt(e,10);Number.isInteger(t)&&(null!=r.date||(r.date=new Date(t,0,1)))}break;case"USLT":case"ULT":{const e=l.readU8();l.pos+=3,l.readId3V2Text(e,c),null!=r.lyrics||(r.lyrics=l.readId3V2Text(e,c))}break;case"COMM":case"COM":{const e=l.readU8();l.pos+=3,l.readId3V2Text(e,c),null!=r.comment||(r.comment=l.readId3V2Text(e,c))}break;case"APIC":case"PIC":{const e=l.readId3V2TextEncoding();let i;if(2===t.majorVersion){const e=l.readAscii(3);i="PNG"===e?"image/png":"JPG"===e?"image/jpeg":"image/*"}else i=l.readId3V2Text(e,c);const n=l.readU8(),s=l.readId3V2Text(e,c).trimEnd(),a=c-l.pos;if(a>=0){const e=l.readBytes(a);r.images||(r.images=[]),r.images.push({data:e,mimeType:i,kind:3===n?"coverFront":4===n?"coverBack":"unknown",description:s})}}break;default:l.pos+=e.size}l.pos=c}}};class mi{constructor(e,t){this.header=e,this.bytes=t,this.pos=0,this.view=new DataView(t.buffer,t.byteOffset,t.byteLength)}frameHeaderSize(){return 2===this.header.majorVersion?6:10}ununsynchronizeAll(){const e=[];for(let t=0;t{const t=this.pos+e;if(t>this.bytes.length)return!1;if(t<=this.bytes.length-this.frameHeaderSize()){this.pos+=e;const t=this.readAscii(4);if("\0\0\0\0"!==t&&!/[0-9A-Z]{4}/.test(t))return!1}return!0};if(!s(r)){const e=4===this.header.majorVersion?t:ii(t);s(e)&&(r=e)}return this.pos=n,{id:e,size:r,flags:i}}}readId3V2TextEncoding(){const e=this.readU8();if(e>3)throw new Error(`Unsupported text encoding: ${e}`);return e}readId3V2Text(e,t){const r=this.pos,i=this.readBytes(t-this.pos);switch(e){case ai.ISO_8859_1:{let e="";for(let t=0;t0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(2,t))}if(254===i[0]&&255===i[1]){const e=new TextDecoder("utf-16be"),t=ce(i.findIndex((e,t)=>0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(2,t))}{const e=ce(i.findIndex(e=>0===e),i.length);return this.pos=r+Math.min(e+1,i.length),w.decode(i.subarray(0,e))}case ai.UTF_16_BE_NO_BOM:{const e=new TextDecoder("utf-16be"),t=ce(i.findIndex((e,t)=>0===e&&0===i[t+1]&&t%2===0),i.length);return this.pos=r+Math.min(t+2,i.length),e.decode(i.subarray(0,t))}case ai.UTF_8:{const e=ce(i.findIndex(e=>0===e),i.length);return this.pos=r+Math.min(e+1,i.length),w.decode(i.subarray(0,e))}}}readId3V2EncodingAndText(e){if(this.pos>=e)return"";const t=this.readId3V2TextEncoding();return this.readId3V2Text(t,e)}}const fi=(e,t,r)=>u(null,null,function*(){let i=t;for(;null===r||iu(this,null,function*(){for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)yield this.advanceReader();if(!this.firstFrameHeader)throw new Error("No valid MP3 frame found.");this.tracks=[new Xt(this.input,new gi(this))]}))()})}advanceReader(){return u(this,null,function*(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,10);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=di(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}const e=yield fi(this.reader,this.lastLoadedPos,this.reader.fileSize);if(!e)return void(this.lastSampleLoaded=!0);const t=e.header;this.lastLoadedPos=e.startPos+t.totalSize-1;const r=(i=t.mpegVersionId,n=t.channel,3===i?3===n?21:36:3===n?13:21);var i,n;let s=this.reader.requestSlice(e.startPos+r,4);if(s instanceof Promise&&(s=yield s),s){const e=Cn(s);if(1483304551===e||1231971951===e)return}this.firstFrameHeader||(this.firstFrameHeader=t),t.sampleRate!==this.firstFrameHeader.sampleRate&&console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${t.sampleRate} Hz. Might be a bug, so please report this file.`);const a=t.audioSamplesInFrame/this.firstFrameHeader.sampleRate,o={timestamp:this.nextTimestampInSamples/this.firstFrameHeader.sampleRate,duration:a,dataStart:e.startPos,dataSize:t.totalSize};this.loadedSamples.push(o),this.nextTimestampInSamples+=t.audioSamplesInFrame})}getMimeType(){return u(this,null,function*(){return"audio/mpeg"})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks})}computeDuration(){return u(this,null,function*(){yield this.readMetadata();const e=this.tracks[0];return p(e),e.computeDuration()})}getMetadataTags(){return u(this,null,function*(){const e=yield this.readingMutex.acquire();try{if(yield this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0,t=!1;for(;;){let r=this.reader.requestSlice(e,10);if(r instanceof Promise&&(r=yield r),!r)break;const i=di(r);if(!i)break;t=!0;let n=this.reader.requestSlice(r.filePos,i.size);if(n instanceof Promise&&(n=yield n),!n)break;hi(n,i,this.metadataTags),e=r.filePos+i.size}if(!t&&null!==this.reader.fileSize&&this.reader.fileSize>=li){let e=this.reader.requestSlice(this.reader.fileSize-li,li);e instanceof Promise&&(e=yield e),p(e);"TAG"===Nn(e,3)&&((e,t)=>{var r;const i=e.filePos;null!=t.raw||(t.raw={}),null!=(r=t.raw).TAG||(r.TAG=Tn(e,125)),e.filePos=i;const n=ui(e,30);n&&(null!=t.title||(t.title=n));const s=ui(e,30);s&&(null!=t.artist||(t.artist=s));const a=ui(e,30);a&&(null!=t.album||(t.album=a));const o=ui(e,4),l=Number.parseInt(o,10);Number.isInteger(l)&&l>0&&(null!=t.date||(t.date=new Date(l,0,1)));const c=Tn(e,30);let u;if(0===c[28]&&0!==c[29]){const r=c[29];r>0&&(null!=t.trackNumber||(t.trackNumber=r)),e.skip(-30),u=ui(e,28),e.skip(2)}else e.skip(-30),u=ui(e,30);u&&(null!=t.comment||(t.comment=u));const d=Sn(e);de.timestamp);if(-1===r)throw new Error("Packet was not created from this track.");const i=r+1;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{r()}})}getPacket(e,t){return u(this,null,function*(){const r=yield this.demuxer.readingMutex.acquire();try{for(;;){const r=N(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===r&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(r,t);if(r>=0&&r+1>>0&4294967295}const yi=e=>{const t=v(e),r=t.getUint32(22,!0);t.setUint32(22,0,!0);let i=0;for(let n=0;n>>24^t])>>>0}return t.setUint32(22,r,!0),i},Ti=(e,t,r)=>{let i=0,n=null;if(e.length>0)if("vorbis"===t.codec){p(t.vorbisInfo);const s=(1<<(e=>{let t=0;for(;e;)t++,e>>=1;return t})(t.vorbisInfo.modeBlockflags.length-1))-1<<1,a=(e[0]&s)>>1;if(a>=t.vorbisInfo.modeBlockflags.length)throw new Error("Invalid mode number.");let o=r;const l=t.vorbisInfo.modeBlockflags[a];if(n=t.vorbisInfo.blocksizes[l],1===l){const r=1+(1|s),i=e[0]&r?1:0;o=t.vorbisInfo.blocksizes[i]}i=null!==o?o+n>>2:0}else if("opus"===t.codec){i=(e=>{const t=e[0]>>3;return{durationInSamples:tt[t]}})(e).durationInSamples}return{durationInSamples:i,vorbisBlockSize:n}},Si=27,vi=282,wi=e=>{const t=e.filePos;if(_n(e)!==ki)return null;e.skip(1);const r=Sn(e),i=An(e),n=_n(e),s=_n(e),a=_n(e),o=Sn(e),l=new Uint8Array(o);for(let d=0;de+t,0);return{headerStartPos:t,totalSize:c+u,dataStartPos:t+c,dataSize:u,headerType:r,granulePosition:i,serialNumber:n,sequenceNumber:s,checksum:a,lacingValues:l}},Ii=(e,t)=>{for(;e.filePos>>8&255)===r||(t>>>16&255)===r||(t>>>24&255)===r){if(e.skip(-4),t===ki)return!0;e.skip(1)}}return!1};class Pi extends ot{constructor(e){super(e),this.metadataPromise=null,this.bitstreams=[],this.tracks=[],this.metadataTags={},this.reader=e._reader}readMetadata(){return u(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>u(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,Si,vi);if(t instanceof Promise&&(t=yield t),!t)break;const r=wi(t);if(!r)break;if(!!!(2&r.headerType))break;this.bitstreams.push({serialNumber:r.serialNumber,bosPage:r,description:null,numberOfChannels:-1,sampleRate:-1,codecInfo:{codec:null,vorbisInfo:null,opusInfo:null},lastMetadataPacket:null}),e=r.headerStartPos+r.totalSize}for(const t of this.bitstreams){const e=yield this.readPacket(t.bosPage,0);e&&(e.data.byteLength>=7&&1===e.data[0]&&118===e.data[1]&&111===e.data[2]&&114===e.data[3]&&98===e.data[4]&&105===e.data[5]&&115===e.data[6]?yield this.readVorbisMetadata(e,t):e.data.byteLength>=8&&79===e.data[0]&&112===e.data[1]&&117===e.data[2]&&115===e.data[3]&&72===e.data[4]&&101===e.data[5]&&97===e.data[6]&&100===e.data[7]&&(yield this.readOpusMetadata(e,t)),null!==t.codecInfo.codec&&this.tracks.push(new Xt(this.input,new xi(t,this))))}}))()})}readVorbisMetadata(e,t){return u(this,null,function*(){let r=yield this.findNextPacketStart(e);if(!r)return;const i=yield this.readPacket(r.startPage,r.startSegmentIndex);if(!i)return;if(r=yield this.findNextPacketStart(i),!r)return;const n=yield this.readPacket(r.startPage,r.startSegmentIndex);if(!n)return;if(3!==i.data[0]||5!==n.data[0])return;const s=[],a=e=>{for(;s.push(Math.min(255,e)),!(e<255);)e-=255};a(e.data.length),a(i.data.length);const o=new Uint8Array(1+s.length+e.data.length+i.data.length+n.data.length);o[0]=2,o.set(s,1),o.set(e.data,1+s.length),o.set(i.data,1+s.length+e.data.length),o.set(n.data,1+s.length+e.data.length+i.data.length),t.codecInfo.codec="vorbis",t.description=o,t.lastMetadataPacket=n;const l=v(e.data);t.numberOfChannels=l.getUint8(11),t.sampleRate=l.getUint32(12,!0);const c=l.getUint8(28);t.codecInfo.vorbisInfo={blocksizes:[1<<(15&c),1<<(c>>4)],modeBlockflags:rt(n.data).modeBlockflags},at(i.data.subarray(7),this.metadataTags)})}readOpusMetadata(e,t){return u(this,null,function*(){const r=yield this.findNextPacketStart(e);if(!r)return;const i=yield this.readPacket(r.startPage,r.startSegmentIndex);if(!i)return;t.codecInfo.codec="opus",t.description=e.data,t.lastMetadataPacket=i;const n=(e=>{const t=v(e),r=t.getUint8(9),i=t.getUint16(10,!0),n=t.getUint32(12,!0),s=t.getInt16(16,!0),a=t.getUint8(18);let o=null;return a&&(o=e.subarray(19,21+r)),{outputChannelCount:r,preSkip:i,inputSampleRate:n,outputGain:s,channelMappingFamily:a,channelMappingTable:o}})(e.data);t.numberOfChannels=n.outputChannelCount,t.sampleRate=xe,t.codecInfo.opusInfo={preSkip:n.preSkip},at(i.data.subarray(8),this.metadataTags)})}readPacket(e,t){return u(this,null,function*(){p(te+t.length,0);if(0===o)return null;const l=new Uint8Array(o);let c=0;for(let e=0;e{let t="audio/ogg";e.codecStrings&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({codecStrings:(yield Promise.all(this.tracks.map(e=>e.getCodecParameterString()))).filter(Boolean)})})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks})}computeDuration(){return u(this,null,function*(){const e=yield this.getTracks(),t=yield Promise.all(e.map(e=>e.computeDuration()));return Math.max(0,...t)})}getMetadataTags(){return u(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}}class xi{constructor(e,t){this.bitstream=e,this.demuxer=t,this.encodedPacketToMetadata=new WeakMap,this.sequentialScanCache=[],this.sequentialScanMutex=new D,this.internalSampleRate="opus"===e.codecInfo.codec?xe:e.sampleRate}getId(){return this.bitstream.serialNumber}getNumberOfChannels(){return this.bitstream.numberOfChannels}getSampleRate(){return this.bitstream.sampleRate}getTimeResolution(){return this.bitstream.sampleRate}getCodec(){return this.bitstream.codecInfo.codec}getInternalCodecId(){return null}getDecoderConfig(){return u(this,null,function*(){var e;return p(this.bitstream.codecInfo.codec),{codec:this.bitstream.codecInfo.codec,numberOfChannels:this.bitstream.numberOfChannels,sampleRate:this.bitstream.sampleRate,description:null!=(e=this.bitstream.description)?e:void 0}})}getName(){return null}getLanguageCode(){return $}getDisposition(){return c({},ge)}getFirstTimestamp(){return u(this,null,function*(){return 0})}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}granulePositionToTimestampInSamples(e){return"opus"===this.bitstream.codecInfo.codec?(p(this.bitstream.codecInfo.opusInfo),e-this.bitstream.codecInfo.opusInfo.preSkip):e}createEncodedPacketFromOggPacket(e,t,r){if(!e)return null;const{durationInSamples:i,vorbisBlockSize:n}=Ti(e.data,this.bitstream.codecInfo,t.vorbisLastBlocksize),s=new dt(r.metadataOnly?ut:e.data,"key",Math.max(0,t.timestampInSamples)/this.internalSampleRate,i/this.internalSampleRate,e.endPage.headerStartPos+e.endSegmentIndex,e.data.byteLength);return this.encodedPacketToMetadata.set(s,{packet:e,timestampInSamples:t.timestampInSamples,durationInSamples:i,vorbisLastBlockSize:t.vorbisLastBlocksize,vorbisBlockSize:n}),s}getFirstPacket(e){return u(this,null,function*(){p(this.bitstream.lastMetadataPacket);const t=yield this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!t)return null;let r=0;"opus"===this.bitstream.codecInfo.codec&&(p(this.bitstream.codecInfo.opusInfo),r-=this.bitstream.codecInfo.opusInfo.preSkip);const i=yield this.demuxer.readPacket(t.startPage,t.startSegmentIndex);return this.createEncodedPacketFromOggPacket(i,{timestampInSamples:r,vorbisLastBlocksize:null},e)})}getNextPacket(e,t){return u(this,null,function*(){const r=this.encodedPacketToMetadata.get(e);if(!r)throw new Error("Packet was not created from this track.");const i=yield this.demuxer.findNextPacketStart(r.packet);if(!i)return null;const n=r.timestampInSamples+r.durationInSamples,s=yield this.demuxer.readPacket(i.startPage,i.startSegmentIndex);return this.createEncodedPacketFromOggPacket(s,{timestampInSamples:n,vorbisLastBlocksize:r.vorbisBlockSize},t)})}getPacket(e,t){return u(this,null,function*(){var r,i;if(null===this.demuxer.reader.fileSize)return this.getPacketSequential(e,t);const n=Q(e*this.internalSampleRate);if(0===n)return this.getFirstPacket(t);if(n<0)return null;p(this.bitstream.lastMetadataPacket);const s=yield this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!s)return null;let a=s.startPage,o=this.demuxer.reader.fileSize;const l=[a];e:for(;a.headerStartPos+a.totalSizen?o=c.headerStartPos:(a=c,l.push(c));continue e}r=c.headerStartPos+c.totalSize}}let c=s.startPage;for(const e of l){if(e.granulePosition===a.granulePosition)break;(!c||e.headerStartPos>c.headerStartPos)&&(c=e)}let u=c;const d=[u];for(;u.serialNumber!==this.bitstream.serialNumber||u.granulePosition!==a.granulePosition;){const e=u.headerStartPos+u.totalSize;let t=this.demuxer.reader.requestSliceRange(e,Si,vi);t instanceof Promise&&(t=yield t),p(t);const r=wi(t);p(r),u=r,u.serialNumber===this.bitstream.serialNumber&&d.push(u)}p(-1!==u.granulePosition);let h,m,f=null,g=u,k=0;if(u.headerStartPos===s.startPage.headerStartPos)h=this.granulePositionToTimestampInSamples(0),m=!0,f=0;else{h=0,m=!1;for(let t=u.lacingValues.length-1;t>=0;t--){if(u.lacingValues[t]<255){f=t+1;break}}if(null===f)throw new Error("Invalid page with granule position: no packets end on this page.");k=f-1;const e={data:ut,endPage:g,endSegmentIndex:k};if(yield this.demuxer.findNextPacketStart(e)){const e=_i(d,u,f);p(e);const t=Ci(d,e.page,e.segmentIndex);t&&(u=t.page,f=t.segmentIndex)}else for(;;){const e=_i(d,u,f);if(!e)break;const t=Ci(d,e.page,e.segmentIndex);if(!t)break;if(u=t.page,f=t.segmentIndex,e.page.headerStartPos!==g.headerStartPos){g=e.page,k=e.segmentIndex;break}}}let b=null,y=null;for(;null!==u;){p(null!==f);const e=yield this.demuxer.readPacket(u,f);if(!e)break;if(!(u.headerStartPos===s.startPage.headerStartPos&&fn||Math.max(a.timestampInSamples,0)===n))break}const a=yield this.demuxer.findNextPacketStart(e);if(!a)break;u=a.startPage,f=a.startSegmentIndex}return b})}getPacketSequential(e,t){return u(this,null,function*(){const r=yield this.sequentialScanMutex.acquire();try{const r=Q(e*this.internalSampleRate);e=r/this.internalSampleRate;const i=N(this.sequentialScanCache,r,e=>e.timestampInSamples);let n;if(-1!==i){const e=this.sequentialScanCache[i];n=this.createEncodedPacketFromOggPacket(e.packet,{timestampInSamples:e.timestampInSamples,vorbisLastBlocksize:e.vorbisLastBlockSize},t)}else n=yield this.getFirstPacket(t);let s=0;for(;n&&n.timestampe)break;if(n=r,s++,100===s){s=0;const e=this.encodedPacketToMetadata.get(n);p(e),this.sequentialScanCache.length>0&&p(k(this.sequentialScanCache).timestampInSamples<=e.timestampInSamples),this.sequentialScanCache.push(e)}}return n}finally{r()}})}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Ci=(e,t,r)=>{let i=t,n=r;e:for(;;){for(n--;n>=0;n--){if(i.lacingValues[n]<255){n++;break e}}p(-1===n);if(!(1&i.headerType)){n=0;break}const t=L(e,e=>e.headerStartPos{if(r>0)return{page:t,segmentIndex:r-1};const i=L(e,e=>e.headerStartPosu(this,null,function*(){var e,t;let r=this.reader.requestSlice(0,12);r instanceof Promise&&(r=yield r),p(r);const i=Nn(r,4),n="RIFX"!==i,s="RF64"===i,a=xn(r,n);let o=s?this.reader.fileSize:Math.min(a+8,null!=(e=this.reader.fileSize)?e:1/0);if("WAVE"!==Nn(r,4))throw new Error("Invalid WAVE file - wrong format");let l=0,c=null,u=r.filePos;for(;null===o||u=18&&357!==n){const e=vn(i,r),s=t-18;if(Math.min(s,e)>=22&&n===Bi.EXTENSIBLE){i.skip(6);const e=Tn(i,16);n=e[0]|e[1]<<8}}n!==Bi.MULAW&&n!==Bi.ALAW||(l=8),this.audioInfo={format:n,numberOfChannels:s,sampleRate:a,sampleSizeInBytes:Math.ceil(l/8),blockSizeInBytes:o}})}parseListChunk(e,t,r){return u(this,null,function*(){var i,n,s,a,o,l,c,u,d,h,m;let f=this.reader.requestSlice(e,t);if(f instanceof Promise&&(f=yield f),!f)return;const p=Nn(f,4);if("INFO"!==p&&"INF0"!==p)return;let g=f.filePos;for(;g<=e+t-8;){f.filePos=g;const e=Nn(f,4),t=xn(f,r),p=Tn(f,t);let k=0;for(let r=0;r0&&(null!=(l=this.metadataTags).trackNumber||(l.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&(null!=(c=this.metadataTags).tracksTotal||(c.tracksTotal=r))}break;case"ICRD":case"IDIT":{const e=new Date(b);Number.isNaN(e.getTime())||null!=(u=this.metadataTags).date||(u.date=e)}break;case"YEAR":{const e=Number.parseInt(b,10);Number.isInteger(e)&&e>0&&(null!=(d=this.metadataTags).date||(d.date=new Date(e,0,1)))}break;case"IGNR":case"GENR":null!=(h=this.metadataTags).genre||(h.genre=b);break;case"ICMT":case"CMNT":case"COMM":null!=(m=this.metadataTags).comment||(m.comment=b)}g+=8+t+(1&t)}})}parseId3Chunk(e,t){return u(this,null,function*(){let r=this.reader.requestSlice(e,t);if(r instanceof Promise&&(r=yield r),!r)return;const i=di(r);if(i){const t=r.slice(e+10,i.size);hi(t,i,this.metadataTags)}})}getCodec(){if(p(this.audioInfo),this.audioInfo.format===Bi.MULAW)return"ulaw";if(this.audioInfo.format===Bi.ALAW)return"alaw";if(this.audioInfo.format===Bi.PCM){if(1===this.audioInfo.sampleSizeInBytes)return"pcm-u8";if(2===this.audioInfo.sampleSizeInBytes)return"pcm-s16";if(3===this.audioInfo.sampleSizeInBytes)return"pcm-s24";if(4===this.audioInfo.sampleSizeInBytes)return"pcm-s32"}return this.audioInfo.format===Bi.IEEE_FLOAT&&4===this.audioInfo.sampleSizeInBytes?"pcm-f32":null}getMimeType(){return u(this,null,function*(){return"audio/wav"})}computeDuration(){return u(this,null,function*(){yield this.readMetadata();const e=this.tracks[0];return p(e),e.computeDuration()})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks})}getMetadataTags(){return u(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}}const Di=2048;class Ai{constructor(e){this.demuxer=e}getId(){return 1}getCodec(){return this.demuxer.getCodec()}getInternalCodecId(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.format}getDecoderConfig(){return u(this,null,function*(){const e=this.demuxer.getCodec();return e?(p(this.demuxer.audioInfo),{codec:e,numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate}):null})}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getNumberOfChannels(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getTimeResolution(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return $}getDisposition(){return c({},ge)}getFirstTimestamp(){return u(this,null,function*(){return 0})}getPacketAtIndex(e,t){return u(this,null,function*(){p(this.demuxer.audioInfo);const r=e*Di*this.demuxer.audioInfo.blockSizeInBytes;if(r>=this.demuxer.dataSize)return null;const i=Math.min(Di*this.demuxer.audioInfo.blockSizeInBytes,this.demuxer.dataSize-r);if(null===this.demuxer.reader.fileSize){let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+r,i);if(e instanceof Promise&&(e=yield e),!e)return null}let n;if(t.metadataOnly)n=ut;else{let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+r,i);e instanceof Promise&&(e=yield e),p(e),n=Tn(e,i)}const s=e*Di/this.demuxer.audioInfo.sampleRate,a=i/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate;return this.demuxer.lastKnownPacketIndex=Math.max(e,s),new dt(n,"key",s,a,e,i)})}getFirstPacket(e){return this.getPacketAtIndex(0,e)}getPacket(e,t){return u(this,null,function*(){p(this.demuxer.audioInfo);const r=Math.floor(Math.min(e*this.demuxer.audioInfo.sampleRate/Di,(this.demuxer.dataSize-1)/(Di*this.demuxer.audioInfo.blockSizeInBytes))),i=yield this.getPacketAtIndex(r,t);if(i)return i;if(0===r)return null;p(null===this.demuxer.reader.fileSize);let n=yield this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex,t);for(;n;){const e=yield this.getNextPacket(n,t);if(!e)break;n=e}return n})}getNextPacket(e,t){p(this.demuxer.audioInfo);const r=Math.round(e.timestamp*this.demuxer.audioInfo.sampleRate/Di);return this.getPacketAtIndex(r+1,t)}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Ri=e=>{const t=e.filePos,r=Tn(e,9),i=new b(r);if(4095!==i.readBits(12))return null;i.skipBits(1);if(0!==i.readBits(2))return null;const n=i.readBits(1),s=i.readBits(2)+1,a=i.readBits(4);if(15===a)return null;i.skipBits(1);const o=i.readBits(3);if(0===o)throw new Error("ADTS frames with channel configuration 0 are not supported.");i.skipBits(1),i.skipBits(1),i.skipBits(1),i.skipBits(1);const l=i.readBits(13);i.skipBits(11);const c=i.readBits(2)+1;if(1!==c)throw new Error("ADTS frames with more than one AAC frame are not supported.");let u=null;return 1===n?e.filePos-=2:u=i.readBits(16),{objectType:s,samplingFrequencyIndex:a,channelConfiguration:o,frameLength:l,numberOfAacFrames:c,crcCheck:u,startPos:t}},Mi=1024;class Ni extends ot{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.loadedSamples=[],this.tracks=[],this.readingMutex=new D,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}readMetadata(){return u(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>u(this,null,function*(){for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)yield this.advanceReader();p(this.firstFrameHeader),this.tracks=[new Xt(this.input,new zi(this))]}))()})}advanceReader(){return u(this,null,function*(){let e=this.reader.requestSliceRange(this.lastLoadedPos,7,9);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=Ri(e);if(!t)return void(this.lastSampleLoaded=!0);if(null!==this.reader.fileSize&&t.startPos+t.frameLength>this.reader.fileSize)return void(this.lastSampleLoaded=!0);this.firstFrameHeader||(this.firstFrameHeader=t);const r=we[t.samplingFrequencyIndex];p(void 0!==r);const i=Mi/r,n=t.crcCheck?9:7,s={timestamp:this.nextTimestampInSamples/r,duration:i,dataStart:t.startPos+n,dataSize:t.frameLength-n};this.loadedSamples.push(s),this.nextTimestampInSamples+=Mi,this.lastLoadedPos=t.startPos+t.frameLength})}getMimeType(){return u(this,null,function*(){return"audio/aac"})}getTracks(){return u(this,null,function*(){return yield this.readMetadata(),this.tracks})}computeDuration(){return u(this,null,function*(){yield this.readMetadata();const e=this.tracks[0];return p(e),e.computeDuration()})}getMetadataTags(){return u(this,null,function*(){return{}})}}class zi{constructor(e){this.demuxer=e}getId(){return 1}getFirstTimestamp(){return u(this,null,function*(){return 0})}getTimeResolution(){return this.getSampleRate()/Mi}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getName(){return null}getLanguageCode(){return $}getCodec(){return"aac"}getInternalCodecId(){return p(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.objectType}getNumberOfChannels(){p(this.demuxer.firstFrameHeader);const e=Ie[this.demuxer.firstFrameHeader.channelConfiguration];return p(void 0!==e),e}getSampleRate(){p(this.demuxer.firstFrameHeader);const e=we[this.demuxer.firstFrameHeader.samplingFrequencyIndex];return p(void 0!==e),e}getDisposition(){return c({},ge)}getDecoderConfig(){return u(this,null,function*(){p(this.demuxer.firstFrameHeader);const e=new Uint8Array(3),t=new b(e),{objectType:r,samplingFrequencyIndex:i,channelConfiguration:n}=this.demuxer.firstFrameHeader;return r>31?(t.writeBits(5,31),t.writeBits(6,r-32)):t.writeBits(5,r),t.writeBits(4,i),t.writeBits(4,n),{codec:`mp4a.40.${this.demuxer.firstFrameHeader.objectType}`,numberOfChannels:this.getNumberOfChannels(),sampleRate:this.getSampleRate(),description:e.subarray(0,Math.ceil((t.pos-1)/8))}})}getPacketAtIndex(e,t){return u(this,null,function*(){if(-1===e)return null;const r=this.demuxer.loadedSamples[e];if(!r)return null;let i;if(t.metadataOnly)i=ut;else{let e=this.demuxer.reader.requestSlice(r.dataStart,r.dataSize);if(e instanceof Promise&&(e=yield e),!e)return null;i=Tn(e,r.dataSize)}return new dt(i,"key",r.timestamp,r.duration,e,r.dataSize)})}getFirstPacket(e){return this.getPacketAtIndex(0,e)}getNextPacket(e,t){return u(this,null,function*(){const r=yield this.demuxer.readingMutex.acquire();try{const r=M(this.demuxer.loadedSamples,e.timestamp,e=>e.timestamp);if(-1===r)throw new Error("Packet was not created from this track.");const i=r+1;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{r()}})}getPacket(e,t){return u(this,null,function*(){const r=yield this.demuxer.readingMutex.acquire();try{for(;;){const r=N(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===r&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(r,t);if(r>=0&&r+1u(this,null,function*(){for(var e;null===this.reader.fileSize||ti.end-6)return{num:n.num,blockSize:n.blockSize,sampleRate:n.sampleRate,size:i.end-e,isLastFrame:!0};if(255===Sn(i)){const t=i.filePos;if(Sn(i)!==(1===this.blockingBit?249:248)){i.filePos=t;continue}i.skip(-2);const r=i.filePos-e,s=this.readFlacFrameHeader({slice:i,isFirstPacket:!1});if(!s){i.filePos=t;continue}if(0===this.blockingBit){if(s.num-n.num!==1){i.filePos=t;continue}}else if(s.num-n.num!==n.blockSize){i.filePos=t;continue}return{num:n.num,blockSize:n.blockSize,sampleRate:n.sampleRate,size:r,isLastFrame:!1}}}})}readFlacFrameHeader({slice:e,isFirstPacket:t}){const r=e.filePos,i=Tn(e,4),n=new b(i);if(32764!==n.readBits(15))return null;if(null===this.blockingBit){p(t);const e=n.readBits(1);this.blockingBit=e}else if(1===this.blockingBit){p(!t);if(1!==n.readBits(1))return null}else{if(0!==this.blockingBit)throw new Error("Invalid blocking bit");p(!t);if(0!==n.readBits(1))return null}const s=(e=>0===e?null:1===e?192:e>=2&&e<=5?144*o(2,e):6===e?"uncommon-u8":7===e?"uncommon-u16":e>=8&&e<=15?o(2,e):null)(n.readBits(4));if(!s)return null;p(this.audioInfo);const a=((e,t)=>{switch(e){case 0:return t;case 1:return 88200;case 2:return 176400;case 3:return 192e3;case 4:return 8e3;case 5:return 16e3;case 6:return 22050;case 7:return 24e3;case 8:return 32e3;case 9:return 44100;case 10:return 48e3;case 11:return 96e3;case 12:return"uncommon-u8";case 13:return"uncommon-u16";case 14:return"uncommon-u16-10";default:return null}})(n.readBits(4),this.audioInfo.sampleRate);if(!a)return null;n.readBits(4),n.readBits(3);if(0!==n.readBits(1))return null;const l=(e=>{let t=0;const r=new b(Tn(e,1));for(;1===r.readBits(1);)t++;if(0===t)return r.readBits(7);const i=[],n=t-1,s=new b(Tn(e,n)),a=8-t-1;for(let o=0;oe|t<"uncommon-u16"===t?wn(e)+1:"uncommon-u8"===t?Sn(e)+1:"number"===typeof t?t:(q(t),void p(!1)))(e,s),u=((e,t)=>"uncommon-u16"===t?wn(e):"uncommon-u16-10"===t?10*wn(e):"uncommon-u8"===t?Sn(e):"number"===typeof t?t:null)(e,a);if(null===u)return null;if(u!==this.audioInfo.sampleRate)return null;const d=e.filePos-r,h=Sn(e);e.skip(-d),e.skip(-1);const m=(e=>{let t=0;for(const r of e){t^=r;for(let e=0;e<8;e++)0!==(128&t)?t=t<<1^7:t<<=1,t&=255}return t})(Tn(e,d));return h!==m?null:{num:l,blockSize:c,sampleRate:u}}advanceReader(){return u(this,null,function*(){yield this.readMetadata(),p(null!==this.lastLoadedPos),p(this.audioInfo);const e=this.lastLoadedPos,t=yield this.readNextFlacFrame({startPos:e,isFirstPacket:0===this.loadedSamples.length});if(!t)return void(this.lastSampleLoaded=!0);const r=this.loadedSamples[this.loadedSamples.length-1],i={blockOffset:r?r.blockOffset+r.blockSize:0,blockSize:t.blockSize,byteOffset:e,byteSize:t.size};this.lastLoadedPos=this.lastLoadedPos+t.size,this.loadedSamples.push(i),t.isLastFrame&&(this.lastSampleLoaded=!0)})}}class Li{constructor(e){this.demuxer=e}getId(){return 1}getCodec(){return"flac"}getInternalCodecId(){return null}getNumberOfChannels(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}computeDuration(){return u(this,null,function*(){var e,t;const r=yield this.getPacket(1/0,{metadataOnly:!0});return(null!=(e=null==r?void 0:r.timestamp)?e:0)+(null!=(t=null==r?void 0:r.duration)?t:0)})}getSampleRate(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return $}getTimeResolution(){return p(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getDisposition(){return c({},ge)}getFirstTimestamp(){return u(this,null,function*(){return 0})}getDecoderConfig(){return u(this,null,function*(){return p(this.demuxer.audioInfo),{codec:"flac",numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate,description:this.demuxer.audioInfo.description}})}getPacket(e,t){return u(this,null,function*(){if(p(this.demuxer.audioInfo),e<0)throw new Error("Timestamp cannot be negative");const r=yield this.demuxer.readingMutex.acquire();try{for(;;){const r=N(this.demuxer.loadedSamples,e,e=>e.blockOffset/this.demuxer.audioInfo.sampleRate);if(-1===r){yield this.demuxer.advanceReader();continue}const i=this.demuxer.loadedSamples[r],n=i.blockOffset/this.demuxer.audioInfo.sampleRate;if(!(n+i.blockSize/this.demuxer.audioInfo.sampleRate<=e))return this.getPacketAtIndex(r,t);if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(this.demuxer.loadedSamples.length-1,t);yield this.demuxer.advanceReader()}}finally{r()}})}getNextPacket(e,t){return u(this,null,function*(){const r=yield this.demuxer.readingMutex.acquire();try{const r=e.sequenceNumber+1;if(this.demuxer.lastSampleLoaded&&r>=this.demuxer.loadedSamples.length)return null;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{r()}})}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}getPacketAtIndex(e,t){return u(this,null,function*(){const r=this.demuxer.loadedSamples[e];if(!r)return null;let i;if(t.metadataOnly)i=ut;else{let e=this.demuxer.reader.requestSlice(r.byteOffset,r.byteSize);if(e instanceof Promise&&(e=yield e),!e)return null;i=Tn(e,r.byteSize)}p(this.demuxer.audioInfo);const n=r.blockOffset/this.demuxer.audioInfo.sampleRate,s=r.blockSize/this.demuxer.audioInfo.sampleRate;return new dt(i,"key",n,s,e,r.byteSize)})}getFirstPacket(e){return u(this,null,function*(){for(;0===this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(0,e)})}}class Ui{}class Vi extends Ui{_getMajorBrand(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=yield t),!t)return null;t.skip(4);return"ftyp"!==Nn(t,4)?null:Nn(t,4)})}_createDemuxer(e){return new ir(e)}}class qi extends Vi{_canReadInput(e){return u(this,null,function*(){const t=yield this._getMajorBrand(e);return!!t&&"qt "!==t})}get name(){return"MP4"}get mimeType(){return"video/mp4"}}class Hi extends Vi{_canReadInput(e){return u(this,null,function*(){return"qt "===(yield this._getMajorBrand(e))})}get name(){return"QuickTime File Format"}get mimeType(){return"video/quicktime"}}class Wi extends Ui{isSupportedEBMLOfDocType(e,t){return u(this,null,function*(){let r=e._reader.requestSlice(0,yr);if(r instanceof Promise&&(r=yield r),!r)return!1;const i=Tr(r);if(null===i)return!1;if(i<1||i>8)return!1;if(vr(r,i)!==fr.EBML)return!1;const n=Ir(r);if("number"!==typeof n)return!1;let s=e._reader.requestSlice(r.filePos,n);if(s instanceof Promise&&(s=yield s),!s)return!1;const a=r.filePos;for(;s.filePos<=a+n-2;){const e=Pr(s);if(!e)break;const{id:r,size:i}=e,n=s.filePos;if(void 0===i)return!1;switch(r){case fr.EBMLVersion:if(1!==vr(s,i))return!1;break;case fr.EBMLReadVersion:if(1!==vr(s,i))return!1;break;case fr.DocType:if(xr(s,i)!==t)return!1;break;case fr.DocTypeVersion:if(vr(s,i)>4)return!1}s.filePos=n+i}return!0})}_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"matroska")}_createDemuxer(e){return new Xr(e)}get name(){return"Matroska"}get mimeType(){return"video/x-matroska"}}class ji extends Wi{_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"webm")}get name(){return"WebM"}get mimeType(){return"video/webm"}}class Ki extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,10);if(t instanceof Promise&&(t=yield t),!t)return!1;let r=0,i=!1;for(;;){let t=e._reader.requestSlice(r,10);if(t instanceof Promise&&(t=yield t),!t)break;const n=di(t);if(!n)break;i=!0,r=t.filePos+n.size}const n=yield fi(e._reader,r,r+4096);if(!n)return!1;if(i)return!0;r=n.startPos+n.header.totalSize;const s=yield fi(e._reader,r,r+4);if(!s)return!1;const a=n.header,o=s.header;return a.channel===o.channel&&a.sampleRate===o.sampleRate})}_createDemuxer(e){return new pi(e)}get name(){return"MP3"}get mimeType(){return"audio/mpeg"}}class $i extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=yield t),!t)return!1;const r=Nn(t,4);if("RIFF"!==r&&"RIFX"!==r&&"RF64"!==r)return!1;t.skip(4);return"WAVE"===Nn(t,4)})}_createDemuxer(e){return new Fi(e)}get name(){return"WAVE"}get mimeType(){return"audio/wav"}}class Qi extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=yield t),!!t&&"OggS"===Nn(t,4)})}_createDemuxer(e){return new Pi(e)}get name(){return"Ogg"}get mimeType(){return"application/ogg"}}class Gi extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=yield t),!!t&&"fLaC"===Nn(t,4)})}get name(){return"FLAC"}get mimeType(){return"audio/flac"}_createDemuxer(e){return new Oi(e)}}class Xi extends Ui{_canReadInput(e){return u(this,null,function*(){let t=e._reader.requestSliceRange(0,7,9);if(t instanceof Promise&&(t=yield t),!t)return!1;const r=Ri(t);if(!r)return!1;if(t=e._reader.requestSliceRange(r.frameLength,7,9),t instanceof Promise&&(t=yield t),!t)return!1;const i=Ri(t);return!!i&&(r.objectType===i.objectType&&r.samplingFrequencyIndex===i.samplingFrequencyIndex&&r.channelConfiguration===i.channelConfiguration)})}_createDemuxer(e){return new Ni(e)}get name(){return"ADTS"}get mimeType(){return"audio/aac"}}const Yi=new qi,Ji=new Hi,Zi=new Wi,en=new ji,tn=new Ki,rn=new $i,nn=new Qi,sn=new Xi,an=[Yi,Ji,Zi,en,rn,nn,new Gi,tn,sn];class on{constructor(){this._disposed=!1,this._sizePromise=null,this.onread=null}getSizeOrNull(){return u(this,null,function*(){var e;if(this._disposed)throw new gn;return null!=(e=this._sizePromise)?e:this._sizePromise=Promise.resolve(this._retrieveSize())})}getSize(){return u(this,null,function*(){if(this._disposed)throw new gn;const e=yield this.getSizeOrNull();if(null===e)throw new Error("Cannot determine the size of an unsized source.");return e})}}class ln extends on{constructor(e,t={}){var r;if(!(e instanceof Blob))throw new TypeError("blob must be a Blob.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!me(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._readers=new WeakMap,this._blob=e,this._orchestrator=new fn({maxCacheSize:null!=(r=t.maxCacheSize)?r:8*o(2,20),maxWorkerCount:4,runWorker:this._runWorker.bind(this),prefetchProfile:mn.fileSystem})}_retrieveSize(){const e=this._blob.size;return this._orchestrator.fileSize=e,e}_read(e,t){return this._orchestrator.read(e,t)}_runWorker(e){return u(this,null,function*(){var t,r;let i=this._readers.get(e);if(void 0===i){if("stream"in this._blob&&!ie()){i=this._blob.slice(e.currentPos).stream().getReader()}else i=null;this._readers.set(e,i)}for(;e.currentPos{if(t instanceof Error&&(t.message.includes("Failed to fetch")||t.message.includes("Load failed")||t.message.includes("NetworkError when attempting to fetch resource"))){let e=null;try{"undefined"!==typeof window&&"undefined"!==typeof window.location&&(e=new URL(r instanceof Request?r.url:r,window.location.href).origin)}catch(i){}if(("undefined"===typeof navigator||"boolean"!==typeof navigator.onLine||navigator.onLine)&&null!==e&&e!==window.location.origin)return console.warn("Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option."),null}return Math.min(o(2,e-2),16)};class dn extends on{constructor(e,t={}){var r,i;if("string"!==typeof e&&!(e instanceof URL)&&!("undefined"!==typeof Request&&e instanceof Request))throw new TypeError("url must be a string, URL or Request.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.requestInit&&(!t.requestInit||"object"!==typeof t.requestInit))throw new TypeError("options.requestInit, when provided, must be an object.");if(void 0!==t.getRetryDelay&&"function"!==typeof t.getRetryDelay)throw new TypeError("options.getRetryDelay, when provided, must be a function.");if(void 0!==t.maxCacheSize&&(!me(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");if(void 0!==t.fetchFn&&"function"!==typeof t.fetchFn)throw new TypeError("options.fetchFn, when provided, must be a function.");super(),this._existingResponses=new WeakMap,this._url=e,this._options=t,this._getRetryDelay=null!=(r=t.getRetryDelay)?r:un,this._orchestrator=new fn({maxCacheSize:null!=(i=t.maxCacheSize)?i:64*o(2,20),maxWorkerCount:2,runWorker:this._runWorker.bind(this),prefetchProfile:mn.network})}_retrieveSize(){return u(this,null,function*(){var e,t;const r=new AbortController,i=yield ee(null!=(e=this._options.fetchFn)?e:fetch,this._url,J(null!=(t=this._options.requestInit)?t:{},{headers:{Range:"bytes=0-"},signal:r.signal}),this._getRetryDelay,()=>this._disposed);if(!i.ok)throw new Error(`Error fetching ${String(this._url)}: ${i.status} ${i.statusText}`);let n,s;if(206===i.status)s=this._getTotalLengthFromRangeResponse(i),n=this._orchestrator.createWorker(0,Math.min(s,cn));else{const e=i.headers.get("Content-Length");if(!e)throw new Error(`HTTP response (status ${i.status}) must surface Content-Length header.`);s=Number(e),n=this._orchestrator.createWorker(0,s),this._orchestrator.options.maxCacheSize=1/0,console.warn("HTTP server did not respond with 206 Partial Content, meaning the entire remote resource now has to be downloaded. For efficient media file streaming across a network, please make sure your server supports range requests.")}return this._orchestrator.fileSize=s,this._existingResponses.set(n,{response:i,abortController:r}),this._orchestrator.runWorker(n),s})}_read(e,t){return this._orchestrator.read(e,t)}_runWorker(e){return u(this,null,function*(){for(var t,r,i;;){const s=this._existingResponses.get(e);this._existingResponses.delete(e);let a=null==s?void 0:s.abortController,o=null==s?void 0:s.response;if(a||(a=new AbortController,o=yield ee(null!=(t=this._options.fetchFn)?t:fetch,this._url,J(null!=(r=this._options.requestInit)?r:{},{headers:{Range:`bytes=${e.currentPos}-`},signal:a.signal}),this._getRetryDelay,()=>this._disposed)),p(o),!o.ok)throw new Error(`Error fetching ${String(this._url)}: ${o.status} ${o.statusText}`);if(e.currentPos>0&&206!==o.status)throw new Error("HTTP server did not respond with 206 Partial Content to a range request. To enable efficient media file streaming across a network, please make sure your server supports range requests.");if(!o.body)throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream.");const l=o.body.getReader();for(;;){if(e.currentPos>=e.targetPos||e.aborted)return a.abort(),void(e.running=!1);let t;try{t=yield l.read()}catch(n){if(this._disposed)throw n;const e=this._getRetryDelay(1,n,this._url);if(null!==e){console.error("Error while reading response stream. Attempting to resume.",n),yield new Promise(t=>setTimeout(t,1e3*e));break}throw n}if(e.aborted)continue;const{done:r,value:s}=t;if(r){if(e.currentPos>=e.targetPos)return this._orchestrator.forgetWorker(e),void(e.running=!1);break}null==(i=this.onread)||i.call(this,e.currentPos,e.currentPos+s.length),this._orchestrator.supplyWorkerData(e,s)}}})}_getTotalLengthFromRangeResponse(e){const t=e.headers.get("Content-Range");if(t){const e=/\/(\d+)/.exec(t);if(e)return Number(e[1])}const r=e.headers.get("Content-Length");if(r)return Number(r);throw new Error("Partial HTTP response (status 206) must surface either Content-Range or Content-Length header.")}_dispose(){this._orchestrator.dispose()}}class hn extends on{constructor(e,t={}){var r;if(!(e instanceof ReadableStream))throw new TypeError("stream must be a ReadableStream.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!me(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._reader=null,this._cache=[],this._pendingSlices=[],this._currentIndex=0,this._targetIndex=0,this._maxRequestedIndex=0,this._endIndex=null,this._pulling=!1,this._stream=e,this._maxCacheSize=null!=(r=t.maxCacheSize)?r:16*o(2,20)}_retrieveSize(){return this._endIndex}_read(e,t){if(null!==this._endIndex&&t>this._endIndex)return null;this._maxRequestedIndex=Math.max(this._maxRequestedIndex,t);const r=N(this._cache,e,e=>e.start),i=-1!==r?this._cache[r]:null;if(i&&i.start<=e&&t<=i.end)return{bytes:i.bytes,view:i.view,offset:i.start};let n=e;const s=new Uint8Array(t-e);if(-1!==r)for(let c=r;c=t)break;const i=Math.max(e,r.start);i>n&&this._throwDueToCacheMiss();const a=Math.min(t,r.end);in&&this._throwDueToCacheMiss();const{promise:a,resolve:o,reject:l}=O();return this._pendingSlices.push({start:e,end:t,bytes:s,resolve:o,reject:l}),this._targetIndex=Math.max(this._targetIndex,t),this._pulling||(this._pulling=!0,this._pull().catch(e=>{if(this._pulling=!1,!(this._pendingSlices.length>0))throw e;this._pendingSlices.forEach(t=>t.reject(e)),this._pendingSlices.length=0})),a}_throwDueToCacheMiss(){throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache.")}_pull(){return u(this,null,function*(){for(null!=this._reader||(this._reader=this._stream.getReader());this._currentIndex0;){const e=this._cache[0];if(this._maxRequestedIndex-e.end<=this._maxCacheSize)break;this._cache.shift()}this._currentIndex+=t.byteLength}this._pulling=!1})}_dispose(){this._pendingSlices.length=0,this._cache.length=0}}const mn={fileSystem:(e,t)=>{const r=o(2,16);return{start:e=Math.floor((e-r)/r)*r,end:t=Math.ceil((t+r)/r)*r}},network:(e,t,r)=>{const i=o(2,16);e=Math.max(0,Math.floor((e-i)/i)*i);for(const n of r){const r=8*o(2,20),i=Math.max((n.startPos+n.targetPos)/2,n.targetPos-r);if(ue(e,t,i,n.targetPos)){const e=n.targetPos-n.startPos,i=Math.ceil((e+1)/r)*r,s=o(2,Math.ceil(Math.log2(e+1))),a=Math.min(s,i);t=Math.max(t,n.startPos+a)}}return{start:e,end:t=Math.max(t,e+cn)}}};class fn{constructor(e){this.options=e,this.fileSize=null,this.nextAge=0,this.workers=[],this.cache=[],this.currentCacheSize=0,this.disposed=!1}read(e,t){p(null!==this.fileSize);const r=this.options.prefetchProfile(e,t,this.workers),i=Math.max(r.start,0),n=Math.min(r.end,this.fileSize);p(i<=e&&t<=n);let s=null;const a=N(this.cache,e,e=>e.start),l=-1!==a?this.cache[a]:null;l&&l.start<=e&&t<=l.end&&(l.age=this.nextAge++,s={bytes:l.bytes,view:l.view,offset:l.start});const c=N(this.cache,i,e=>e.start),u=s?null:new Uint8Array(t-e);let d=0,h=i;const m=[];if(-1!==c){for(let r=c;r=n)break;if(s.end<=i)continue;const a=Math.max(i,s.start),o=Math.min(n,s.end);if(p(a<=o),h=u.length&&(s={bytes:u,view:v(u),offset:e}),0===m.length)return p(s),s;const{promise:f,resolve:g,reject:k}=O(),b=[];for(const o of m){const r=Math.max(e,o.start),i=Math.min(t,o.end);r===o.start&&i===o.end?b.push(o):r({bytes:t,view:v(t),offset:e}))),s}createWorker(e,t){const r={startPos:e,currentPos:e,targetPos:t,running:!1,aborted:this.disposed,pendingSlices:[],age:this.nextAge++};for(this.workers.push(r);this.workers.length>this.options.maxWorkerCount;){let e=0,t=this.workers[0];for(let r=1;r0)break;t.aborted=!0,this.workers.splice(e,1)}return r}runWorker(e){p(!e.running),p(e.currentPos{if(e.running=!1,!(e.pendingSlices.length>0))throw t;e.pendingSlices.forEach(e=>e.reject(t)),e.pendingSlices.length=0})}supplyWorkerData(e,t){p(!e.aborted);const r=e.currentPos,i=r+t.length;this.insertIntoCache({start:r,end:i,bytes:t,view:v(t),age:this.nextAge++}),e.currentPos+=t.length,e.targetPos=Math.max(e.targetPos,e.currentPos);for(let n=0;nt.start&&(t.start=i),t.end<=t.start&&(s.holes.splice(e,1),e--)}0===s.holes.length&&(s.resolve(s.bytes),e.pendingSlices.splice(n,1),n--)}for(let n=0;ne.start)+1;if(t>0){const r=this.cache[t-1];if(r.end>=e.end)return;if(r.end>e.start){const i=new Uint8Array(e.end-r.start);i.set(r.bytes,0),i.set(e.bytes,e.start-r.start),this.currentCacheSize+=e.end-r.end,r.bytes=i,r.view=v(i),r.end=e.end,t--,e=r}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length;for(let r=t+1;r=t.end){this.cache.splice(r,1),this.currentCacheSize-=t.bytes.length,r--;continue}const i=new Uint8Array(t.end-e.start);i.set(e.bytes,0),i.set(t.bytes,t.start-e.start),this.currentCacheSize-=e.end-t.start,e.bytes=i,e.view=v(i),e.end=t.end,this.cache.splice(r,1);break}for(;this.currentCacheSize>this.options.maxCacheSize;){let e=0,t=this.cache[0];for(let r=1;r!(e instanceof Ui)))throw new TypeError("options.formats must be an array of InputFormat.");if(!(e.source instanceof on))throw new TypeError("options.source must be a Source.");if(e.source._disposed)throw new Error("options.source must not be disposed.");this._formats=e.formats,this._source=e.source,this._reader=new kn(e.source)}_getDemuxer(){var e;return null!=(e=this._demuxerPromise)?e:this._demuxerPromise=(()=>u(this,null,function*(){this._reader.fileSize=yield this._source.getSizeOrNull();for(const e of this._formats){if(yield e._canReadInput(this))return this._format=e,e._createDemuxer(this)}throw new Error("Input has an unsupported or unrecognizable format.")}))()}get source(){return this._source}getFormat(){return u(this,null,function*(){return yield this._getDemuxer(),p(this._format),this._format})}computeDuration(){return u(this,null,function*(){return(yield this._getDemuxer()).computeDuration()})}getTracks(){return u(this,null,function*(){return(yield this._getDemuxer()).getTracks()})}getVideoTracks(){return u(this,null,function*(){return(yield this.getTracks()).filter(e=>e.isVideoTrack())})}getAudioTracks(){return u(this,null,function*(){return(yield this.getTracks()).filter(e=>e.isAudioTrack())})}getPrimaryVideoTrack(){return u(this,null,function*(){var e;return null!=(e=(yield this.getTracks()).find(e=>e.isVideoTrack()))?e:null})}getPrimaryAudioTrack(){return u(this,null,function*(){var e;return null!=(e=(yield this.getTracks()).find(e=>e.isAudioTrack()))?e:null})}getMimeType(){return u(this,null,function*(){return(yield this._getDemuxer()).getMimeType()})}getMetadataTags(){return u(this,null,function*(){return(yield this._getDemuxer()).getMetadataTags()})}dispose(){this._disposed||(this._disposed=!0,this._source._disposed=!0,this._source._dispose())}[Symbol.dispose](){this.dispose()}}class gn extends Error{constructor(e="Input has been disposed."){super(e),this.name="InputDisposedError"}}class kn{constructor(e){this.source=e}requestSlice(e,t){if(this.source._disposed)throw new gn;if(null!==this.fileSize&&e+t>this.fileSize)return null;const r=e+t,i=this.source._read(e,r);return i instanceof Promise?i.then(t=>t?new bn(t.bytes,t.view,t.offset,e,r):null):i?new bn(i.bytes,i.view,i.offset,e,r):null}requestSliceRange(e,t,r){if(this.source._disposed)throw new gn;if(null!==this.fileSize)return this.requestSlice(e,K(this.fileSize-e,t,r));{const i=this.requestSlice(e,r),n=i=>{if(i)return i;const n=i=>(p(null!==i),this.requestSlice(e,K(i-e,t,r))),s=this.source._retrieveSize();return s instanceof Promise?s.then(n):n(s)};return i instanceof Promise?i.then(n):n(i)}}}class bn{constructor(e,t,r,i,n){this.bytes=e,this.view=t,this.offset=r,this.start=i,this.end=n,this.bufferPos=i-r}static tempFromBytes(e){return new bn(e,v(e),0,0,e.length)}get length(){return this.end-this.start}get filePos(){return this.offset+this.bufferPos}set filePos(e){this.bufferPos=e-this.offset}get remainingLength(){return Math.max(this.end-this.filePos,0)}skip(e){this.bufferPos+=e}slice(e,t=this.end-e){if(ethis.end)throw new RangeError("Slicing outside of original slice.");return new bn(this.bytes,this.view,this.offset,e,e+t)}}const yn=(e,t)=>{if(e.filePose.end)throw new RangeError(`Tried reading [${e.filePos}, ${e.filePos+t}), but slice is [${e.start}, ${e.end}). This is likely an internal error, please report it alongside the file that caused it.`)},Tn=(e,t)=>{yn(e,t);const r=e.bytes.subarray(e.bufferPos,e.bufferPos+t);return e.bufferPos+=t,r},Sn=e=>(yn(e,1),e.view.getUint8(e.bufferPos++)),vn=(e,t)=>{yn(e,2);const r=e.view.getUint16(e.bufferPos,t);return e.bufferPos+=2,r},wn=e=>{yn(e,2);const t=e.view.getUint16(e.bufferPos,!1);return e.bufferPos+=2,t},In=e=>{yn(e,3);const t=H(e.view,e.bufferPos,!1);return e.bufferPos+=3,t},Pn=e=>{yn(e,2);const t=e.view.getInt16(e.bufferPos,!1);return e.bufferPos+=2,t},xn=(e,t)=>{yn(e,4);const r=e.view.getUint32(e.bufferPos,t);return e.bufferPos+=4,r},Cn=e=>{yn(e,4);const t=e.view.getUint32(e.bufferPos,!1);return e.bufferPos+=4,t},_n=e=>{yn(e,4);const t=e.view.getUint32(e.bufferPos,!0);return e.bufferPos+=4,t},Bn=e=>{yn(e,4);const t=e.view.getInt32(e.bufferPos,!1);return e.bufferPos+=4,t},En=(e,t)=>{let r,i;return t?(r=xn(e,!0),i=xn(e,!0)):(i=xn(e,!1),r=xn(e,!1)),4294967296*i+r},Fn=e=>4294967296*Cn(e)+Cn(e),Dn=e=>4294967296*Bn(e)+Cn(e),An=e=>{const t=_n(e),r=(e=>{yn(e,4);const t=e.view.getInt32(e.bufferPos,!0);return e.bufferPos+=4,t})(e);return 4294967296*r+t},Rn=e=>{yn(e,4);const t=e.view.getFloat32(e.bufferPos,!1);return e.bufferPos+=4,t},Mn=e=>{yn(e,8);const t=e.view.getFloat64(e.bufferPos,!1);return e.bufferPos+=8,t},Nn=(e,t)=>{yn(e,t);let r="";for(let i=0;ie.stop()),this.queuedNodes.clear()}stopIterator(){return u(this,null,function*(){var e;yield null==(e=this.audioIterator)?void 0:e.return(),this.audioIterator=null})}load(e,t){return u(this,null,function*(){const r=++this.asyncId;yield this.stopIterator(),this.stopQueuedNodes(),this.paused=!0,this.playbackTimeAtStart=0,this.audioContextStartTime=0;const i=this.normalizeSource(e);if(!i)return;if(this.input=new pn({source:i,formats:an}),this.duration=yield this.input.computeDuration(),r!==this.asyncId)return;const n=yield this.input.getPrimaryAudioTrack();return n&&null!==n.codec&&(yield n.canDecode())?(this.ensureAudioContext(n.sampleRate),this.audioSink=new $t(n),void(null==t||t())):(this.audioSink=null,this.ensureAudioContext(),void(null==t||t()))})}runIterator(e){return u(this,null,function*(){if(this.audioSink)for(yield this.stopIterator(),this.audioIterator=this.audioSink.buffers(this.currentTime);;){if(e!==this.asyncId||this.paused)return;const r=this.audioIterator.next(),i=setInterval(()=>{e!==this.asyncId||this.paused?clearInterval(i):"running"===this.audioContext.state&&this.audioContext.currentTime>=this.latestScheduledEndTime-.2&&(this.audioContext.suspend(),this.events.emit("waiting"))},50);let n;try{n=yield r}catch(t){console.error("Audio iterator error:",t);break}finally{clearInterval(i)}if(e!==this.asyncId||this.paused)return;if("suspended"===this.audioContext.state&&(yield this.audioContext.resume(),this.events.emit("canplay"),this.events.emit("playing")),n.done)break;const{buffer:s,timestamp:a}=n.value,o=this.audioContext.createBufferSource();o.buffer=s,o.connect(this.gainNode),o.playbackRate.value=this.playbackRate;const l=this.audioContextStartTime+(a-this.playbackTimeAtStart)/this.playbackRate,c=l+s.duration/this.playbackRate;c>this.latestScheduledEndTime&&(this.latestScheduledEndTime=c),l>=this.audioContext.currentTime?o.start(l):o.start(this.audioContext.currentTime,(this.audioContext.currentTime-l)*this.playbackRate),this.queuedNodes.add(o),o.onended=()=>this.queuedNodes.delete(o)}})}play(){return u(this,null,function*(){if(!this.paused)return;this.audioContext||this.ensureAudioContext(),"suspended"===this.audioContext.state&&(yield this.audioContext.resume()),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime,this.paused=!1;const e=++this.asyncId;this.runIterator(e)})}pause(){this.paused||(this.playbackTimeAtStart=this.currentTime,this.paused=!0,this.stopIterator(),this.stopQueuedNodes())}seek(e){return u(this,null,function*(){this.playbackTimeAtStart=Math.max(0,e),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime;const t=++this.asyncId;this.paused||this.runIterator(t)})}setVolume(e,t){this.volume=e,this.muted=t,this.updateGain()}setPlaybackRate(e){if(e!==this.playbackRate&&(this.paused||(this.playbackTimeAtStart=this.currentTime,this.audioContextStartTime=this.audioContext.currentTime),this.playbackRate=e,!this.paused)){const e=++this.asyncId;this.runIterator(e)}}destroy(){var e;this.asyncId++,this.pause(),null==(e=this.audioContext)||e.close(),this.audioContext=null,this.input=null,this.audioSink=null}}class On{constructor({canvas:e,ctx:t,events:r,timeupdateInterval:i=250,avSyncTolerance:n=.12,dropLateFrames:s=!1,poster:a="",preflightRange:o=!1}){this.canvas=e,this.ctx=t,this.events=r,this.timeupdateInterval=i,this.avSyncTolerance=n,this.dropLateFrames=s,this.poster=a,this.preflightRange=o,this.input=null,this.videoSink=null,this.videoIterator=null,this.nextFrame=null,this.rafId=0,this.asyncId=0,this.width=0,this.height=0,this.duration=Number.NaN,this.audioClock=null,this.lastTimeUpdate=0,this.stalled=!1,this.playbackRate=1,this.posterDrawn=!1,this.isFetching=!1}normalizeSource(e){return"string"===typeof e?new dn(e):e instanceof Blob?new ln(e):"undefined"!==typeof ReadableStream&&e instanceof ReadableStream?new hn(e):e}preflight(e){return u(this,null,function*(){if(!this.preflightRange||"string"!==typeof e)return!0;try{const t=(yield fetch(e,{method:"HEAD"})).headers.get("accept-ranges");return!(!t||"none"===t)||(this.events.emit("error",new Event("RangeNotSupported")),!1)}catch(t){return console.warn("Preflight check failed:",t),!0}})}drawPoster(){if(!this.poster||this.posterDrawn)return;const e=new Image;e.onload=()=>{this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width=e.naturalWidth||this.canvas.width,this.canvas.height=e.naturalHeight||this.canvas.height,this.ctx.drawImage(e,0,0,this.canvas.width,this.canvas.height),this.posterDrawn=!0},e.src=this.poster}stopIterator(){return u(this,null,function*(){var e;yield null==(e=this.videoIterator)?void 0:e.return(),this.videoIterator=null})}clear(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}load(e,t){return u(this,null,function*(){const r=++this.asyncId;if(yield this.stopIterator(),this.clear(),this.posterDrawn=!1,!(yield this.preflight(e)))return;const i=this.normalizeSource(e);if(!i)return void this.drawPoster();if(this.input=new pn({source:i,formats:an}),this.duration=yield this.input.computeDuration(),r!==this.asyncId)return;const n=yield this.input.getPrimaryVideoTrack();if(!n)return this.handleNoVideoTrack(),void(null==t||t());if(null===n.codec||!(yield n.canDecode()))return this.handleNoVideoTrack(),void(null==t||t());const s=yield n.canBeTransparent();this.videoSink=new Ht(n,{poolSize:2,fit:"contain",alpha:s}),this.width=n.displayWidth,this.height=n.displayHeight,this.canvas.width=this.width,this.canvas.height=this.height,null==t||t(),yield this.resetIterator(0)})}handleNoVideoTrack(){this.videoSink=null,this.width=0,this.height=0,this.canvas.width=0,this.canvas.height=0,this.clear(),this.drawPoster()}resetIterator(e){return u(this,null,function*(){var t,r;if(yield this.stopIterator(),!this.videoSink)return;this.videoIterator=this.videoSink.canvases(e);const i=null!=(t=(yield this.videoIterator.next()).value)?t:null,n=null!=(r=(yield this.videoIterator.next()).value)?r:null;this.nextFrame=n,i?(this.ctx.drawImage(i.canvas,0,0),this.events.emit("loadeddata")):this.drawPoster()})}updateNextFrame(e){return u(this,null,function*(){var t;if(this.videoIterator&&!this.isFetching){this.isFetching=!0;try{for(;;){const r=null!=(t=(yield this.videoIterator.next()).value)?t:null;if(!r||e!==this.asyncId)return;const i=this.audioClock.currentTime,n=this.dropLateFrames?Math.max(.06,this.avSyncTolerance/Math.max(1,this.playbackRate)):0;if(!(this.dropLateFrames&&r.timestampi)return void(this.nextFrame=null)}}}finally{this.isFetching=!1}}})}render(){if(!this.audioClock)return;const e=this.audioClock.currentTime,t=Date.now();if(t-this.lastTimeUpdate>=this.timeupdateInterval&&(this.events.emit("timeupdate"),this.lastTimeUpdate=t),Number.isFinite(this.duration)&&e>=this.duration)return this.stop(),this.stalled=!1,this.events.emit("ended"),this.events.emit("pause"),void this.events.emit("canplay");this.nextFrame&&this.nextFrame.timestamp<=e?(this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextFrame.canvas,0,0),this.nextFrame=null,this.updateNextFrame(this.asyncId),this.stalled&&(this.events.emit("canplay"),this.events.emit("playing"),this.stalled=!1)):this.nextFrame||(this.updateNextFrame(this.asyncId),!this.nextFrame&&Number.isFinite(this.duration)&&ethis.render())}start(e){this.audioClock=e,this.asyncId++,this.stalled=!1,this.updateNextFrame(this.asyncId),this.rafId=requestAnimationFrame(()=>this.render())}stop(){cancelAnimationFrame(this.rafId)}seek(e){return u(this,null,function*(){this.asyncId++,yield this.resetIterator(e)})}setPlaybackRate(e){this.playbackRate=Math.max(.1,Number(e)||1)}destroy(){this.asyncId++,this.stop(),this.stopIterator(),this.posterDrawn=!1,this.input=null,this.videoSink=null}}class Ln{constructor({canvas:e,ctx:t,events:r,option:i={}}){var n,s,a,o,l,c;this.events=r,this.option=i,this.audio=new zn(r),this.video=new On({canvas:e,ctx:t,events:r,timeupdateInterval:null!=(n=i.timeupdateInterval)?n:250,avSyncTolerance:null!=(s=i.avSyncTolerance)?s:.12,dropLateFrames:null!=(a=i.dropLateFrames)&&a,poster:null!=(o=i.poster)?o:"",preflightRange:null!=(l=i.preflightRange)&&l}),this.paused=!0,this.ended=!1,this.readyState=0,this.networkState=0,this.error=null,this.seeking=!1,this.loadSeq=0,null==(c=r.addEventListener)||c.call(r,"ended",()=>{this.ended=!0,this.paused=!0})}load(e){return u(this,null,function*(){const t=++this.loadSeq;this.pause(),this.ended=!1,this.error=null,this.networkState=2,this.readyState=0,setTimeout(()=>this.events.emit("waiting"),0),setTimeout(()=>this.events.emit("loadstart"),0);const r=Number.isFinite(this.option.loadTimeout)?this.option.loadTimeout:0;try{yield Promise.race([this.performLoad(e,t),r>0?this.createTimeout(r):new Promise(()=>{})])}catch(i){if(t!==this.loadSeq)return;this.loadSeq++,this.error={code:4,message:i.message},this.networkState=3,this.events.emit("error")}})}performLoad(e,t){return u(this,null,function*(){let r=!1,i=!1;const n=()=>{r&&i&&(this.readyState=1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"))};try{if(yield Promise.all([this.video.load(e,()=>{t===this.loadSeq&&(r=!0,n())}),this.audio.load(e,()=>{t===this.loadSeq&&(i=!0,n())})]),t!==this.loadSeq)return;this.readyState=4,this.networkState=1,this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("progress")}catch(s){if(t!==this.loadSeq)return;this.error={code:4,message:s.message},this.networkState=3,this.events.emit("error"),console.error("MediaBunny load error:",s)}})}createTimeout(e){return new Promise((t,r)=>{setTimeout(()=>r(new Error("Load timeout")),e)})}play(){return u(this,null,function*(){this.paused&&(this.ended&&(this.ended=!1,yield this.seek(0)),this.paused=!1,yield this.audio.play(),this.video.start(this.audio),this.events.emit("play"),this.events.emit("playing"))})}pause(){this.paused||(this.paused=!0,this.audio.pause(),this.video.stop(),this.events.emit("pause"))}seek(e){return u(this,null,function*(){const t=!this.paused;this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),this.pause(),yield Promise.all([this.audio.seek(e),this.video.seek(e)]),this.seeking=!1,this.events.emit("seeked"),t&&!this.ended&&(yield this.play())})}setVolume(e,t){this.audio.setVolume(e,t)}setPlaybackRate(e){this.audio.setPlaybackRate(e),this.video.setPlaybackRate(e)}destroy(){this.pause(),this.audio.destroy(),this.video.destroy()}get currentTime(){return this.audio.currentTime}get duration(){return this.audio.duration||this.video.duration}get videoWidth(){return this.video.width}get videoHeight(){return this.video.height}}class Un{constructor({art:e,canvas:t,ctx:r,option:i}){var n,s;this.art=e,this.canvas=t,this.option=i,this.events=new f,this.engine=new Ln({canvas:t,ctx:r,events:this.events,option:i}),this._src=null,this._volume=null!=(n=i.volume)?n:.7,this._muted=!!i.muted,this._playbackRate=1,this.engine.setVolume(this._volume,this._muted),this.setupEventForwarding(),i.source?this.src=i.source:(null==(s=e.option)?void 0:s.url)&&(this.src=e.option.url)}setupEventForwarding(){const{events:e}=this.art.constructor.config;e.forEach(e=>{this.events.addEventListener(e,e=>{this.art.emit(`video:${e.type}`,e)})})}addEventListener(e,t){this.events.addEventListener(e,t)}removeEventListener(e,t){this.events.removeEventListener(e,t)}get src(){return this._src}set src(e){this._src=e,e&&this.engine.load(e)}get currentSrc(){return this._src}get currentTime(){return this.engine.currentTime}set currentTime(e){this.engine.seek(Number(e)||0)}get duration(){return this.engine.duration}get buffered(){return this.createTimeRanges(0,this.engine.duration)}get played(){return this.createTimeRanges(0,this.engine.currentTime)}get seekable(){return this.createTimeRanges(0,this.engine.duration)}createTimeRanges(e,t){const r=this.engine.duration;return!r||Number.isNaN(r)||t<=0?{length:0,start:()=>0,end:()=>0}:{length:1,start:()=>e,end:()=>t}}get paused(){return this.engine.paused}get playing(){return!this.engine.paused&&!this.engine.ended}get ended(){return this.engine.ended}get seeking(){return this.engine.seeking}get readyState(){return this.engine.readyState}get networkState(){return this.engine.networkState}get error(){return this.engine.error}get playbackRate(){return this._playbackRate}set playbackRate(e){const t=Number(e);Number.isNaN(t)||t<=0||(this._playbackRate=t,this.engine.setPlaybackRate(t),this.events.emit("ratechange"))}get volume(){return this._volume}set volume(e){this._volume=function(e,t,r){return Math.max(t,Math.min(r,Number(e)||0))}(e,0,1),this._muted=!1,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}get muted(){return this._muted}set muted(e){this._muted=!!e,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}play(){return this.engine.play()}pause(){this.engine.pause()}load(){this._src&&this.engine.load(this._src)}get videoWidth(){return this.engine.videoWidth}get videoHeight(){return this.engine.videoHeight}get poster(){return this.option.poster||""}set poster(e){this.option.poster=e}get autoplay(){return this.option.autoplay||!1}set autoplay(e){}get loop(){return this.option.loop||!1}set loop(e){}get controls(){return!1}set controls(e){}get playsInline(){return!0}set playsInline(e){}get crossOrigin(){return this.option.crossOrigin||""}set crossOrigin(e){}get preload(){return"auto"}set preload(e){}get defaultMuted(){return!1}set defaultMuted(e){}get defaultPlaybackRate(){return 1}set defaultPlaybackRate(e){}canPlayType(e){return"maybe"}getBoundingClientRect(){return this.canvas.getBoundingClientRect()}requestVideoFrameCallback(e){return requestAnimationFrame(t=>{e(t,{presentationTime:this.engine.currentTime,expectedDisplayTime:t+16.6,width:this.engine.videoWidth,height:this.engine.videoHeight,mediaTime:this.engine.currentTime,presentedFrames:0,processingDuration:0,captureTime:t,receiveTime:t,rtpTimestamp:0})})}cancelVideoFrameCallback(e){cancelAnimationFrame(e)}setAttribute(e,t){"src"===e?this.src=t:"autoplay"===e?this.autoplay=t:"loop"===e?this.loop=t:"muted"===e?this.muted=!0:this.canvas.setAttribute(e,t)}destroy(){this.engine.destroy()}}return function(e={}){return t=>{const{constructor:r}=t,{createElement:i}=r.utils,n=i("canvas"),s=n.getContext("2d"),a=new Un({art:t,canvas:n,ctx:s,option:e}),o={};for(const e in n)"function"===typeof n[e]&&(o[e]=n[e].bind(n));const l=new Set([...Object.getOwnPropertyNames(a),...Object.getOwnPropertyNames(Object.getPrototypeOf(a))]);for(const e of l)"constructor"!==e&&(e in n||Object.defineProperty(n,e,{get(){const t=a[e];return"function"===typeof t?t.bind(a):t},set(t){a[e]=t},configurable:!0,enumerable:!0}));for(const e in o)n[e]=(...t)=>o[e](...t);function c(){var e;(null==(e=t.template)?void 0:e.$player)&&!t.option.autoSize&&Object.assign(n.style,{width:"100%",height:"100%",objectFit:"contain"})}return t.on("resize",c),t.on("video:loadedmetadata",c),t.on("destroy",()=>{a.destroy()}),n}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(t.artplayerProxyMediabunny=t(),define(function(){return t.artplayerProxyMediabunny})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerProxyMediabunny=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,i=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,a=(e,t)=>(t=Symbol[e])?t:Symbol.for("Symbol."+e),o=Math.pow,l=(t,i,r)=>i in t?e(t,i,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[i]=r,c=(e,t)=>{for(var i in t||(t={}))n.call(t,i)&&l(e,i,t[i]);if(r)for(var i of r(t))s.call(t,i)&&l(e,i,t[i]);return e},u=(e,r)=>t(e,i(r)),d=(e,t,i)=>new Promise((r,n)=>{var s=e=>{try{o(i.next(e))}catch(t){n(t)}},a=e=>{try{o(i.throw(e))}catch(t){n(t)}},o=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,a);o((i=i.apply(e,t)).next())}),h=function(e,t){this[0]=e,this[1]=t},f=(e,t,i)=>{var r=(e,t,n,s)=>{try{var a=i[e](t),o=(t=a.value)instanceof h,l=a.done;Promise.resolve(o?t[0]:t).then(i=>o?r("return"===e?e:"next",t[1]?{done:i.done,value:i.value}:i,n,s):n({value:i,done:l})).catch(e=>r("throw",e,n,s))}catch(c){s(c)}},n=e=>s[e]=t=>new Promise((i,n)=>r(e,t,i,n)),s={};return i=i.apply(e,t),s[a("asyncIterator")]=()=>s,n("next"),n("throw"),n("return"),s},m=e=>{var t,i=e[a("asyncIterator")],r=!1,n={};return null==i?(i=e[a("iterator")](),t=e=>n[e]=t=>i[e](t)):(i=i.call(e),t=e=>n[e]=t=>{if(r){if(r=!1,"throw"===e)throw t;return t}return r=!0,{done:!1,value:new h(new Promise(r=>{var n=i[e](t);n instanceof Object||(e=>{throw TypeError(e)})("Object expected"),r(n)}),1)}}),n[a("iterator")]=()=>n,t("next"),"throw"in i?t("throw"):n.throw=e=>{throw e},"return"in i&&t("return"),n},p=(e,t,i)=>(t=e[a("asyncIterator")])?t.call(e):(e=e[a("iterator")](),t={},(i=(i,r)=>(r=e[i])&&(t[i]=t=>new Promise((i,n,s)=>(t=r.call(e,t),s=t.done,Promise.resolve(t.value).then(e=>i({value:e,done:s}),n)))))("next"),i("return"),t);function g(e,t){const i=new Map;return e.filter(e=>{const r=e[t];return void 0===r||!i.has(r)&&i.set(r,1)})}class k{constructor(){this.listeners=new Map}addEventListener(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}removeEventListener(e,t){const i=this.listeners.get(e);if(!i)return;const r=i.indexOf(t);r>=0&&i.splice(r,1)}emit(e,t){const i=new Event(e);i.detail=t;const r=this.listeners.get(e);r&&r.forEach(e=>e(i))}}function y(e){if(!e)throw new Error("Assertion failed.")}const b=e=>{const t=(e%360+360)%360;if(0===t||90===t||180===t||270===t)return t;throw new Error(`Invalid rotation ${e}.`)},T=e=>e&&e[e.length-1],S=e=>{let t=0;for(;0===e.readBits(1)&&t<32;)t++;if(t>=32)throw new Error("Invalid exponential-Golomb code.");return(1<{const t=S(e);return 0===(1&t)?-(t>>1):t+1>>1},w=e=>e.constructor===Uint8Array?e:ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),P=e=>e.constructor===DataView?e:ArrayBuffer.isView(e)?new DataView(e.buffer,e.byteOffset,e.byteLength):new DataView(e),I=new TextDecoder,x=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[t,e])),C={bt709:1,bt470bg:5,smpte170m:6,bt2020:9,smpte432:12},B=x(C),E={bt709:1,smpte170m:6,linear:8,"iec61966-2-1":13,pq:16,hlg:18},_=x(E),A={rgb:0,bt709:1,bt470bg:5,smpte170m:6,"bt2020-ncl":9},F=x(A),R=e=>e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e);class D{constructor(){this.currentPromise=Promise.resolve(),this.pending=0}acquire(){return d(this,null,function*(){let e;const t=new Promise(t=>{let i=!1;e=()=>{i||(t(),this.pending--,i=!0)}}),i=this.currentPromise;return this.currentPromise=t,this.pending++,yield i,e})}}const M=/^[0-9a-fA-F]+$/,N=e=>[...e].map(e=>e.toString(16).padStart(2,"0")).join(""),O=e=>(e=(e=(e=(e=(e=e>>1&1431655765|(1431655765&e)<<1)>>2&858993459|(858993459&e)<<2)>>4&252645135|(252645135&e)<<4)>>8&16711935|(16711935&e)<<8)>>16&65535|(65535&e)<<16)>>>0,L=(e,t,i)=>{let r=0,n=e.length-1,s=-1;for(;r<=n;){const a=r+n>>1,o=i(e[a]);o===t?(s=a,n=a-1):o{let r=0,n=e.length-1,s=-1;for(;r<=n;){const a=r+(n-r+1)/2|0;i(e[a])<=t?(s=a,r=a+1):n=a-1}return s},U=(e,t,i)=>{const r=z(e,i(t),i);e.splice(r+1,0,t)},q=()=>{let e,t;return{promise:new Promise((i,r)=>{e=i,t=r}),resolve:e,reject:t}},W=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return e[i]},V=(e,t)=>{for(let i=e.length-1;i>=0;i--)if(t(e[i]))return i;return-1},H=e=>{throw new Error(`Unexpected value: ${e}`)},K=(e,t,i)=>{const r=e.getUint8(t),n=e.getUint8(t+1),s=e.getUint8(t+2);return i?r|n<<8|s<<16:r<<16|n<<8|s},j=(e,t,i,r)=>{i>>>=0,i&=16777215,e.setUint8(t,i>>>16&255),e.setUint8(t+1,i>>>8&255),e.setUint8(t+2,255&i)},X=(e,t)=>({next(){return d(this,null,function*(){const i=yield e.next();return i.done?{value:void 0,done:!0}:{value:t(i.value),done:!1}})},return:()=>e.return(),throw:t=>e.throw(t),[Symbol.asyncIterator](){return this}}),$=(e,t,i)=>Math.max(t,Math.min(i,e)),Q="und",G=e=>{const t=Math.round(e);return Math.abs(e/t-1)<10*Number.EPSILON?t:e},Y=(e,t)=>Math.round(e*t)/t,J=(e,t)=>Math.floor(e/t)*t,Z=/^[a-z]{3}$/,ee=e=>Z.test(e),te=1e6*(1+Number.EPSILON),ie=(e,t)=>{const i=c(c({},e),t);if(e.headers||t.headers){const r=e.headers?re(e.headers):{},n=t.headers?re(t.headers):{},s=c({},r);Object.entries(n).forEach(([e,t])=>{const i=Object.keys(s).find(t=>t.toLowerCase()===e.toLowerCase());i&&delete s[i],s[e]=t}),i.headers=s}return i},re=e=>{if(e instanceof Headers){const t={};return e.forEach((e,i)=>{t[i]=e}),t}if(Array.isArray(e)){const t={};return e.forEach(([e,i])=>{t[e]=i}),t}return e},ne=(e,t,i,r,n)=>d(null,null,function*(){let s=0;for(;;)try{return yield e(t,i)}catch(a){if(n())throw a;s++;const e=r(s,a,t);if(null===e)throw a;if(console.error("Retrying failed fetch. Error:",a),!Number.isFinite(e)||e<0)throw new TypeError("Retry delay must be a non-negative finite number.");if(e>0&&(yield Pe(1e3*e)),n())throw a}});class se{constructor(){this.currentPromise=Promise.resolve()}call(e){return this.currentPromise=this.currentPromise.then(e)}}let ae=null;const oe=()=>{var e;return null!==ae?ae:ae=!("undefined"===typeof navigator||!((null==(e=navigator.vendor)?void 0:e.match(/apple/i))||/AppleWebKit/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)||/\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent)))};let le=null;const ce=()=>{var e;return null!==le?le:le="undefined"!==typeof navigator&&(null==(e=navigator.userAgent)?void 0:e.includes("Firefox"))};let ue=null;const de=()=>{var e;return null!==ue?ue:ue=!("undefined"===typeof navigator||!(null==(e=navigator.vendor)?void 0:e.includes("Google Inc"))&&!/Chrome/.test(navigator.userAgent))};let he=null;const fe=()=>{if(null!==he)return he;if("undefined"===typeof navigator)return null;const e=/\bChrome\/(\d+)/.exec(navigator.userAgent);return e?he=Number(e[1]):null},me=(e,t)=>-1!==e?e:t,pe=(e,t,i,r)=>e<=r&&i<=t,ge=e=>{const t=atob(e),i=new Uint8Array(t.length);for(let r=0;r{null!=Symbol.dispose||(Symbol.dispose=Symbol("Symbol.dispose"))},ye=e=>"number"===typeof e&&!Number.isNaN(e),be=(e,t)=>{if(t.includes("://"))return t;if(e.includes("://")){const t=e.indexOf("?");-1!==t&&(e=e.slice(0,t))}let i;if(t.startsWith("/")){const r=e.indexOf("://");if(-1===r)i=t;else{const n=e.indexOf("/",r+3);i=-1===n?e+t:e.slice(0,n)+t}}else{const r=e.lastIndexOf("/");i=-1===r?t:e.slice(0,r+1)+t}let r="";const n=i.indexOf("://");if(-1!==n){const e=i.indexOf("/",n+3);-1!==e&&(r=i.slice(0,e),i=i.slice(e))}const s=i.split("/"),a=[];for(const o of s)".."===o?a.pop():"."!==o&&a.push(o);return r+a.join("/")},Te=(e,t)=>{let i=0;for(let r=0;r{let i=-1,r=1/0;for(let n=0;n{y(Number.isInteger(e.num)),y(Number.isInteger(e.den)),y(0!==e.den);let t=Math.abs(e.num),i=Math.abs(e.den);for(;0!==i;){const e=t%i;t=i,i=e}const r=t||1;return{num:e.num/r,den:e.den/r}},we=(e,t)=>{if("object"!==typeof e||!e)throw new TypeError(`${t} must be an object.`);if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(`${t}.left must be a non-negative integer.`);if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(`${t}.top must be a non-negative integer.`);if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(`${t}.width must be a non-negative integer.`);if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(`${t}.height must be a non-negative integer.`)},Pe=e=>new Promise(t=>setTimeout(t,e));class Ie{constructor(){this._listeners=new Map}on(e,t,i){var r;this._listeners.has(e)||this._listeners.set(e,new Set);const n={fn:t,once:null!=(r=null==i?void 0:i.once)&&r};return this._listeners.get(e).add(n),()=>{var t;null==(t=this._listeners.get(e))||t.delete(n)}}_emit(...e){const[t,i]=e,r=this._listeners.get(t);if(r)for(const s of r){try{s.fn(i)}catch(n){console.error(n)}s.once&&r.delete(s)}}}class xe{constructor(e,t){if(this.data=e,this.mimeType=t,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("string"!==typeof t)throw new TypeError("mimeType must be a string.")}}class Ce{constructor(e,t,i,r){if(this.data=e,this.mimeType=t,this.name=i,this.description=r,!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if(void 0!==t&&"string"!==typeof t)throw new TypeError("mimeType, when provided, must be a string.");if(void 0!==i&&"string"!==typeof i)throw new TypeError("name, when provided, must be a string.");if(void 0!==r&&"string"!==typeof r)throw new TypeError("description, when provided, must be a string.")}}const Be={default:!0,primary:!0,forced:!1,original:!1,commentary:!1,hearingImpaired:!1,visuallyImpaired:!1};class Ee{constructor(e){this.bytes=e,this.pos=0}seekToByte(e){this.pos=8*e}readBit(){var e;const t=Math.floor(this.pos/8),i=null!=(e=this.bytes[t])?e:0,r=7-(7&this.pos),n=(i&1<>r;return this.pos++,n}readBits(e){if(1===e)return this.readBit();let t=0;for(let i=0;i>i-r-1<{if(!e||e.byteLength<2)throw new TypeError("AAC description must be at least 2 bytes long.");const t=new Ee(e);let i=t.readBits(5);31===i&&(i=32+t.readBits(6));const r=t.readBits(4);let n=null;15===r?n=t.readBits(24):r<_e.length&&(n=_e[r]);const s=t.readBits(4);let a=null;return s>=1&&s<=7&&(a=Ae[s]),{objectType:i,frequencyIndex:r,sampleRate:n,channelConfiguration:s,numberOfChannels:a}},Re=["avc","hevc","vp9","av1","vp8"],De=["pcm-s16","pcm-s16be","pcm-s24","pcm-s24be","pcm-s32","pcm-s32be","pcm-f32","pcm-f32be","pcm-f64","pcm-f64be","pcm-u8","pcm-s8","ulaw","alaw"],Me=["aac","opus","mp3","vorbis","flac","ac3","eac3",...De],Ne=[{maxMacroblocks:99,maxBitrate:64e3,maxDpbMbs:396,level:10},{maxMacroblocks:396,maxBitrate:192e3,maxDpbMbs:900,level:11},{maxMacroblocks:396,maxBitrate:384e3,maxDpbMbs:2376,level:12},{maxMacroblocks:396,maxBitrate:768e3,maxDpbMbs:2376,level:13},{maxMacroblocks:396,maxBitrate:2e6,maxDpbMbs:2376,level:20},{maxMacroblocks:792,maxBitrate:4e6,maxDpbMbs:4752,level:21},{maxMacroblocks:1620,maxBitrate:4e6,maxDpbMbs:8100,level:22},{maxMacroblocks:1620,maxBitrate:1e7,maxDpbMbs:8100,level:30},{maxMacroblocks:3600,maxBitrate:14e6,maxDpbMbs:18e3,level:31},{maxMacroblocks:5120,maxBitrate:2e7,maxDpbMbs:20480,level:32},{maxMacroblocks:8192,maxBitrate:2e7,maxDpbMbs:32768,level:40},{maxMacroblocks:8192,maxBitrate:5e7,maxDpbMbs:32768,level:41},{maxMacroblocks:8704,maxBitrate:5e7,maxDpbMbs:34816,level:42},{maxMacroblocks:22080,maxBitrate:135e6,maxDpbMbs:110400,level:50},{maxMacroblocks:36864,maxBitrate:24e7,maxDpbMbs:184320,level:51},{maxMacroblocks:36864,maxBitrate:24e7,maxDpbMbs:184320,level:52},{maxMacroblocks:139264,maxBitrate:24e7,maxDpbMbs:696320,level:60},{maxMacroblocks:139264,maxBitrate:48e7,maxDpbMbs:696320,level:61},{maxMacroblocks:139264,maxBitrate:8e8,maxDpbMbs:696320,level:62}],Oe=[{maxPictureSize:36864,maxBitrate:2e5,level:10},{maxPictureSize:73728,maxBitrate:8e5,level:11},{maxPictureSize:122880,maxBitrate:18e5,level:20},{maxPictureSize:245760,maxBitrate:36e5,level:21},{maxPictureSize:552960,maxBitrate:72e5,level:30},{maxPictureSize:983040,maxBitrate:12e6,level:31},{maxPictureSize:2228224,maxBitrate:18e6,level:40},{maxPictureSize:2228224,maxBitrate:3e7,level:41},{maxPictureSize:8912896,maxBitrate:6e7,level:50},{maxPictureSize:8912896,maxBitrate:12e7,level:51},{maxPictureSize:8912896,maxBitrate:18e7,level:52},{maxPictureSize:35651584,maxBitrate:18e7,level:60},{maxPictureSize:35651584,maxBitrate:24e7,level:61},{maxPictureSize:35651584,maxBitrate:48e7,level:62}],Le=".01.01.01.01.00",ze=".0.110.01.01.01.0",Ue=e=>{const{codec:t,codecDescription:i,colorSpace:r,avcCodecInfo:n,hevcCodecInfo:s,vp9CodecInfo:a,av1CodecInfo:o}=e;if("avc"===t){if(y(null!==e.avcType),n){const t=new Uint8Array([n.avcProfileIndication,n.profileCompatibility,n.avcLevelIndication]);return`avc${e.avcType}.${N(t)}`}if(!i||i.byteLength<4)throw new TypeError("AVC decoder description is not provided or is not at least 4 bytes long.");return`avc${e.avcType}.${N(i.subarray(1,4))}`}if("hevc"===t){let e,t,r,n,a,o;if(s)e=s.generalProfileSpace,t=s.generalProfileIdc,r=O(s.generalProfileCompatibilityFlags),n=s.generalTierFlag,a=s.generalLevelIdc,o=[...s.generalConstraintIndicatorFlags];else{if(!i||i.byteLength<23)throw new TypeError("HEVC decoder description is not provided or is not at least 23 bytes long.");const s=P(i),l=s.getUint8(1);e=l>>6&3,t=31&l,r=O(s.getUint32(2)),n=l>>5&1,a=s.getUint8(12),o=[];for(let e=0;e<6;e++)o.push(s.getUint8(6+e))}let l="hev1.";for(l+=["","A","B","C"][e]+t,l+=".",l+=r.toString(16).toUpperCase(),l+=".",l+=0===n?"L":"H",l+=a;o.length>0&&0===o[o.length-1];)o.pop();return o.length>0&&(l+=".",l+=o.map(e=>e.toString(16).toUpperCase()).join(".")),l}if("vp8"===t)return"vp8";if("vp9"===t){if(!a){const t=e.width*e.height;let i=T(Oe).level;for(const e of Oe)if(t<=e.maxPictureSize){i=e.level;break}return`vp09.00.${i.toString().padStart(2,"0")}.08`}let t=`vp09.${a.profile.toString().padStart(2,"0")}.${a.level.toString().padStart(2,"0")}.${a.bitDepth.toString().padStart(2,"0")}.${a.chromaSubsampling.toString().padStart(2,"0")}`;return t+=`.${a.colourPrimaries.toString().padStart(2,"0")}.${a.transferCharacteristics.toString().padStart(2,"0")}.${a.matrixCoefficients.toString().padStart(2,"0")}.${a.videoFullRangeFlag.toString().padStart(2,"0")}`,t.endsWith(Le)&&(t=t.slice(0,-15)),t}if("av1"===t){if(!o){const t=e.width*e.height;let i=T(Oe).level;for(const e of Oe)if(t<=e.maxPictureSize){i=e.level;break}return`av01.0.${i.toString().padStart(2,"0")}M.08`}const t=o.profile,i=o.level.toString().padStart(2,"0"),n=o.tier?"H":"M",s=o.bitDepth.toString().padStart(2,"0"),a=o.monochrome?"1":"0",l=100*o.chromaSubsamplingX+10*o.chromaSubsamplingY+1*(o.chromaSubsamplingX&&o.chromaSubsamplingY?o.chromaSamplePosition:0),c=(null==r?void 0:r.primaries)?C[r.primaries]:1,u=(null==r?void 0:r.transfer)?E[r.transfer]:1,d=(null==r?void 0:r.matrix)?A[r.matrix]:1,h=(null==r?void 0:r.fullRange)?1:0;let f=`av01.${t}.${i}${n}.${s}`;return f+=`.${a}.${l.toString().padStart(3,"0")}`,f+=`.${c.toString().padStart(2,"0")}`,f+=`.${u.toString().padStart(2,"0")}`,f+=`.${d.toString().padStart(2,"0")}`,f+=`.${h}`,f.endsWith(ze)&&(f=f.slice(0,-17)),f}throw new TypeError(`Unhandled codec '${t}'.`)},qe=e=>{const{codec:t,codecDescription:i,aacCodecInfo:r}=e;if("aac"===t){if(!r)throw new TypeError("AAC codec info must be provided.");if(r.isMpeg2)return"mp4a.67";{let e;if(null!==r.objectType)e=r.objectType;else{e=Fe(i).objectType}return`mp4a.40.${e}`}}if("mp3"===t)return"mp3";if("opus"===t)return"opus";if("vorbis"===t)return"vorbis";if("flac"===t)return"flac";if("ac3"===t)return"ac-3";if("eac3"===t)return"ec-3";if(t&&De.includes(t))return t;throw new TypeError(`Unhandled codec '${t}'.`)},We=48e3,Ve=/^pcm-([usf])(\d+)+(be)?$/,He=e=>{if(y(De.includes(e)),"ulaw"===e)return{dataType:"ulaw",sampleSize:1,littleEndian:!0,silentValue:255};if("alaw"===e)return{dataType:"alaw",sampleSize:1,littleEndian:!0,silentValue:213};const t=Ve.exec(e);let i;y(t),i="u"===t[1]?"unsigned":"s"===t[1]?"signed":"float";return{dataType:i,sampleSize:Number(t[2])/8,littleEndian:"be"!==t[3],silentValue:"pcm-u8"===e?o(2,7):0}},Ke=e=>e.startsWith("avc1")||e.startsWith("avc3")?"avc":e.startsWith("hev1")||e.startsWith("hvc1")?"hevc":"vp8"===e?"vp8":e.startsWith("vp09")?"vp9":e.startsWith("av01")?"av1":"mp3"===e||"mp4a.69"===e||"mp4a.6B"===e||"mp4a.6b"===e||"mp4a.40.34"===e?"mp3":e.startsWith("mp4a.40.")||"mp4a.67"===e?"aac":"opus"===e?"opus":"vorbis"===e?"vorbis":"flac"===e?"flac":"ac-3"===e||"ac3"===e?"ac3":"ec-3"===e||"eac3"===e?"eac3":"ulaw"===e?"ulaw":"alaw"===e?"alaw":Ve.test(e)?e:"webvtt"===e?"webvtt":null,je=[44100,48e3,32e3],Xe=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1,-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384,-1,-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,-1,-1,32,48,56,64,80,96,112,128,144,160,176,192,224,256,-1],$e=1483304551,Qe=1231971951,Ge=(e,t)=>3===e?3===t?21:36:3===t?13:21,Ye=(e,t)=>{const i=e>>>24,r=e>>>16&255,n=e>>>8&255,s=255&e;if(255!==i&&255!==r&&255!==n&&255!==s)return{header:null,bytesAdvanced:4};if(255!==i)return{header:null,bytesAdvanced:1};if(224!==(224&r))return{header:null,bytesAdvanced:1};let a=0,o=0;16&r?a=8&r?0:1:(a=1,o=1);const l=r>>3&3,c=r>>1&3,u=(n>>2&3)%3,d=s>>6&3,h=s>>4&3,f=s>>3&1,m=s>>2&1,p=3&s,g=Xe[16*a*4+16*c+(n>>4&15)];if(-1===g)return{header:null,bytesAdvanced:1};const k=1e3*g,y=je[u]>>a+o,b=((e,t,i,r,n)=>0===t?0:1===t?Math.floor(144*i/(r<>1&1);if(null!==t&&t{let t=2130706432,i=0;for(;0!==t;)i>>=1,i|=e&t,t>>=8;return i};var Ze,et;(et=Ze||(Ze={}))[et.FrameCount=1]="FrameCount",et[et.FileSize=2]="FileSize",et[et.Toc=4]="Toc";const tt=[48e3,44100,32e3],it=[24e3,22050,16e3];var rt,nt,st,at;(nt=rt||(rt={}))[nt.NON_IDR_SLICE=1]="NON_IDR_SLICE",nt[nt.SLICE_DPA=2]="SLICE_DPA",nt[nt.SLICE_DPB=3]="SLICE_DPB",nt[nt.SLICE_DPC=4]="SLICE_DPC",nt[nt.IDR=5]="IDR",nt[nt.SEI=6]="SEI",nt[nt.SPS=7]="SPS",nt[nt.PPS=8]="PPS",nt[nt.AUD=9]="AUD",nt[nt.SPS_EXT=13]="SPS_EXT",(at=st||(st={}))[at.RASL_N=8]="RASL_N",at[at.RASL_R=9]="RASL_R",at[at.BLA_W_LP=16]="BLA_W_LP",at[at.RSV_IRAP_VCL23=23]="RSV_IRAP_VCL23",at[at.VPS_NUT=32]="VPS_NUT",at[at.SPS_NUT=33]="SPS_NUT",at[at.PPS_NUT=34]="PPS_NUT",at[at.AUD_NUT=35]="AUD_NUT",at[at.PREFIX_SEI_NUT=39]="PREFIX_SEI_NUT",at[at.SUFFIX_SEI_NUT=40]="SUFFIX_SEI_NUT";const ot=function*(e){let t=0,i=-1;for(;t=e.length-2)break;t=r;let n=0;t+3i&&(yield{offset:i,length:t-i}),i=t+n,t=i):t++}-1!==i&&i{if(t.description){const i=3&w(t.description)[4];return lt(e,i+1)}return ot(e)},ut=e=>31&e,dt=e=>{const t=[],i=e.length;for(let r=0;r{const t=e.reduce((e,t)=>e+ht.byteLength+t.byteLength,0),i=new Uint8Array(t);let r=0;for(const n of e)i.set(ht,r),r+=ht.byteLength,i.set(n,r),r+=n.byteLength;return i},mt=(e,t)=>{const i=e.reduce((e,i)=>e+t+i.byteLength,0),r=new Uint8Array(i);let n=0;for(const s of e){const e=new DataView(r.buffer,r.byteOffset,r.byteLength);switch(t){case 1:e.setUint8(n,s.byteLength);break;case 2:e.setUint16(n,s.byteLength,!1);break;case 3:j(e,n,s.byteLength);break;case 4:e.setUint32(n,s.byteLength,!1)}n+=t,r.set(s,n),n+=s.byteLength}return r},pt=e=>{try{const t=[],i=[],r=[];for(const o of ot(e)){const n=e.subarray(o.offset,o.offset+o.length),s=ut(n[0]);s===rt.SPS?t.push(n):s===rt.PPS?i.push(n):s===rt.SPS_EXT&&r.push(n)}if(0===t.length)return null;if(0===i.length)return null;const n=t[0],s=kt(n);y(null!==s);const a=100===s.profileIdc||110===s.profileIdc||122===s.profileIdc||144===s.profileIdc;return{configurationVersion:1,avcProfileIndication:s.profileIdc,profileCompatibility:s.constraintFlags,avcLevelIndication:s.levelIdc,lengthSizeMinusOne:3,sequenceParameterSets:t,pictureParameterSets:i,chromaFormat:a?s.chromaFormatIdc:null,bitDepthLumaMinus8:a?s.bitDepthLumaMinus8:null,bitDepthChromaMinus8:a?s.bitDepthChromaMinus8:null,sequenceParameterSetExt:a?r:null}}catch(t){return console.error("Error building AVC Decoder Configuration Record:",t),null}},gt={1:{num:1,den:1},2:{num:12,den:11},3:{num:10,den:11},4:{num:16,den:11},5:{num:40,den:33},6:{num:24,den:11},7:{num:20,den:11},8:{num:32,den:11},9:{num:80,den:33},10:{num:18,den:11},11:{num:15,den:11},12:{num:64,den:33},13:{num:160,den:99},14:{num:4,den:3},15:{num:3,den:2},16:{num:2,den:1}},kt=e=>{var t;try{const i=new Ee(dt(e));i.skipBits(1),i.skipBits(2);if(7!==i.readBits(5))return null;const r=i.readAlignedByte(),n=i.readAlignedByte(),s=i.readAlignedByte();S(i);let a=1,o=0,l=0,c=0;if(100===r||110===r||122===r||244===r||44===r||83===r||86===r||118===r||128===r){a=S(i),3===a&&(c=i.readBits(1)),o=S(i),l=S(i),i.skipBits(1);if(i.readBits(1))for(let e=0;e<(3!==a?8:12);e++){if(i.readBits(1)){const t=e<6?16:64;let r=8,n=8;for(let e=0;ee.level>=s))?t:T(Ne),n=Math.min(Math.floor(r.maxDpbMbs/(e*i)),16);C=n,B=n}else C=0,B=0}return y(null!==B),{profileIdc:r,constraintFlags:n,levelIdc:s,frameMbsOnlyFlag:k,chromaFormatIdc:a,bitDepthLumaMinus8:o,bitDepthChromaMinus8:l,codedWidth:f,codedHeight:m,displayWidth:p,displayHeight:g,pixelAspectRatio:x,colourPrimaries:b,matrixCoefficients:P,transferCharacteristics:w,fullRangeFlag:I,numReorderFrames:C,maxDecFrameBuffering:B}}catch(i){return console.error("Error parsing AVC SPS:",i),null}},yt=e=>{const t=S(e);e.skipBits(4),e.skipBits(4);for(let i=0;i<=t;i++)S(e),S(e),e.skipBits(1);e.skipBits(5),e.skipBits(5),e.skipBits(5),e.skipBits(5)},bt=(e,t)=>{if(t.description){const i=3&w(t.description)[21];return lt(e,i+1)}return ot(e)},Tt=e=>e>>1&63,St=e=>{try{const t=new Ee(dt(e));t.skipBits(16),t.readBits(4);const i=t.readBits(3),r=t.readBits(1),{general_profile_space:n,general_tier_flag:s,general_profile_idc:a,general_profile_compatibility_flags:o,general_constraint_indicator_flags:l,general_level_idc:c}=wt(t,i);S(t);const u=S(t);let d=0;3===u&&(d=t.readBits(1));const h=S(t),f=S(t);let m=h,p=f;if(t.readBits(1)){const e=S(t),i=S(t),r=S(t),n=S(t);let s=1,a=1;const o=0===d?u:0;1===o?(s=2,a=2):2===o&&(s=2,a=1),m-=(e+i)*s,p-=(r+n)*a}const g=S(t),k=S(t);S(t);const y=t.readBits(1);let b=0;for(let e=y?0:i;e<=i;e++)S(t),b=S(t),S(t);S(t),S(t),S(t),S(t),S(t),S(t),t.readBits(1)&&t.readBits(1)&&Pt(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&(t.skipBits(4),t.skipBits(4),S(t),S(t),t.skipBits(1));const T=S(t);if(It(t,T),t.readBits(1)){const e=S(t);for(let i=0;i{try{const t=[],i=[],r=[],n=[];for(const l of ot(e)){const s=e.subarray(l.offset,l.offset+l.length),a=Tt(s[0]);a===st.VPS_NUT?t.push(s):a===st.SPS_NUT?i.push(s):a===st.PPS_NUT?r.push(s):a!==st.PREFIX_SEI_NUT&&a!==st.SUFFIX_SEI_NUT||n.push(s)}if(0===i.length||0===r.length)return null;const s=St(i[0]);if(!s)return null;let a=0;if(r.length>0){const e=r[0],t=new Ee(dt(e));t.skipBits(16),S(t),S(t),t.skipBits(1),t.skipBits(1),t.skipBits(3),t.skipBits(1),t.skipBits(1),S(t),S(t),v(t),t.skipBits(1),t.skipBits(1),t.readBits(1)&&S(t),v(t),v(t),t.skipBits(1),t.skipBits(1),t.skipBits(1),t.skipBits(1);const i=t.readBits(1),n=t.readBits(1);a=i||n?i&&!n?2:!i&&n?3:0:0}const o=[...t.length?[{arrayCompleteness:1,nalUnitType:st.VPS_NUT,nalUnits:t}]:[],...i.length?[{arrayCompleteness:1,nalUnitType:st.SPS_NUT,nalUnits:i}]:[],...r.length?[{arrayCompleteness:1,nalUnitType:st.PPS_NUT,nalUnits:r}]:[],...n.length?[{arrayCompleteness:1,nalUnitType:Tt(n[0][0]),nalUnits:n}]:[]];return{configurationVersion:1,generalProfileSpace:s.generalProfileSpace,generalTierFlag:s.generalTierFlag,generalProfileIdc:s.generalProfileIdc,generalProfileCompatibilityFlags:s.generalProfileCompatibilityFlags,generalConstraintIndicatorFlags:s.generalConstraintIndicatorFlags,generalLevelIdc:s.generalLevelIdc,minSpatialSegmentationIdc:s.minSpatialSegmentationIdc,parallelismType:a,chromaFormatIdc:s.chromaFormatIdc,bitDepthLumaMinus8:s.bitDepthLumaMinus8,bitDepthChromaMinus8:s.bitDepthChromaMinus8,avgFrameRate:0,constantFrameRate:0,numTemporalLayers:s.spsMaxSubLayersMinus1+1,temporalIdNested:s.spsTemporalIdNestingFlag,lengthSizeMinusOne:3,arrays:o}}catch(t){return console.error("Error building HEVC Decoder Configuration Record:",t),null}},wt=(e,t)=>{const i=e.readBits(2),r=e.readBits(1),n=e.readBits(5);let s=0;for(let u=0;u<32;u++)s=s<<1|e.readBits(1);const a=new Uint8Array(6);for(let u=0;u<6;u++)a[u]=e.readBits(8);const o=e.readBits(8),l=[],c=[];for(let u=0;u0)for(let u=t;u<8;u++)e.skipBits(2);for(let u=0;u{for(let t=0;t<4;t++)for(let i=0;i<(3===t?2:6);i++){if(e.readBits(1)){const i=Math.min(64,1<<4+(t<<1));t>1&&v(e);for(let t=0;t{const i=[];for(let r=0;r{var n;let s=0,a=0,o=0;if(0!==t&&(a=e.readBits(1)),a){if(t===i){o=t-(S(e)+1)}else o=t-1;e.readBits(1),S(e);const a=null!=(n=r[o])?n:0;for(let t=0;t<=a;t++){e.readBits(1)||e.readBits(1)}s=r[o]}else{const t=S(e),i=S(e);for(let r=0;r{let i=2,r=2,n=2,s=0,a=0,o={num:1,den:1};if(e.readBits(1)){const t=e.readBits(8);if(255===t)o={num:e.readBits(16),den:e.readBits(16)};else{const e=gt[t];e&&(o=e)}}return e.readBits(1)&&e.readBits(1),e.readBits(1)&&(e.readBits(3),s=e.readBits(1),e.readBits(1)&&(i=e.readBits(8),r=e.readBits(8),n=e.readBits(8))),e.readBits(1)&&(S(e),S(e)),e.readBits(1),e.readBits(1),e.readBits(1),e.readBits(1)&&(S(e),S(e),S(e),S(e)),e.readBits(1)&&(e.readBits(32),e.readBits(32),e.readBits(1)&&S(e),e.readBits(1)&&Bt(e,!0,t)),e.readBits(1)&&(e.readBits(1),e.readBits(1),e.readBits(1),a=S(e),S(e),S(e),S(e),S(e)),{pixelAspectRatio:o,colourPrimaries:i,transferCharacteristics:r,matrixCoefficients:n,fullRangeFlag:s,minSpatialSegmentationIdc:a}},Bt=(e,t,i)=>{let r=!1,n=!1,s=!1;r=1===e.readBits(1),n=1===e.readBits(1),(r||n)&&(s=1===e.readBits(1),s&&(e.readBits(8),e.readBits(5),e.readBits(1),e.readBits(5)),e.readBits(4),e.readBits(4),s&&e.readBits(4),e.readBits(5),e.readBits(5),e.readBits(5));for(let a=0;a<=i;a++){let t=!0;1===e.readBits(1)||(t=1===e.readBits(1));let i=!1;t?S(e):i=1===e.readBits(1);let a=1;if(!i){a=S(e)+1}r&&Et(e,a,s),n&&Et(e,a,s)}},Et=(e,t,i)=>{for(let r=0;r{const i=new Set;let r=_t.audAllowed;for(const s of bt(e,t)){if(r===_t.noMoreDataAllowed){i.add(s.offset);continue}const t=Tt(e[s.offset]);if(r===_t.eoBitstreamAllowed&&37!==t){i.add(s.offset);continue}let n=!1;35===t?r>_t.audAllowed?n=!0:r=_t.beforeFirstVcl:t<=31?r>_t.afterFirstVcl?n=!0:r=_t.afterFirstVcl:36===t?r!==_t.afterFirstVcl?n=!0:r=_t.eoBitstreamAllowed:37===t?r<_t.afterFirstVcl?n=!0:r=_t.noMoreDataAllowed:32===t||33===t||34===t||39===t||t>=41&&t<=44||t>=48&&t<=55?r>_t.beforeFirstVcl?n=!0:r=_t.beforeFirstVcl:(38===t||40===t||t>=45&&t<=47||t>=56&&t<=63)&&r<_t.afterFirstVcl&&(n=!0),n&&i.add(s.offset)}if(0===i.size)return null;const n=[];for(const s of bt(e,t))i.has(s.offset)||n.push(e.subarray(s.offset,s.offset+s.length));return((e,t)=>{if(t.description){const i=3&w(t.description)[21];return mt(e,i+1)}return ft(e)})(n,t)},Rt=e=>{const t=new Ee(e);if(2!==t.readBits(2))return null;const i=t.readBits(1),r=(t.readBits(1)<<1)+i;3===r&&t.skipBits(1);if(1===t.readBits(1))return null;if(0!==t.readBits(1))return null;t.skipBits(2);if(4817730!==t.readBits(24))return null;let n=8;if(r>=2){n=t.readBits(1)?12:10}const s=t.readBits(3);let a=0,o=0;if(7!==s){if(o=t.readBits(1),1===r||3===r){const e=t.readBits(1),i=t.readBits(1);a=e||i?e&&!i?2:1:3,t.skipBits(1)}else a=1}else a=3,o=1;const l=(t.readBits(16)+1)*(t.readBits(16)+1);let c=T(Oe).level;for(const u of Oe)if(l<=u.maxPictureSize){c=u.level;break}return{profile:r,level:c,bitDepth:n,chromaSubsampling:a,videoFullRangeFlag:o,colourPrimaries:2===s?1:1===s?6:2,transferCharacteristics:2===s?1:1===s?6:2,matrixCoefficients:7===s?0:2===s?1:1===s?6:2}},Dt=function*(e){const t=new Ee(e),i=()=>{let e=0;for(let i=0;i<8;i++){const r=t.readAlignedByte();if(e|=(127&r)<<7*i,!(128&r))break;if(7===i&&128&r)return null}return e>=o(2,32)-1?null:e};for(;t.getBitsLeft()>=8;){t.skipBits(1);const r=t.readBits(4),n=t.readBits(1),s=t.readBits(1);let a;if(t.skipBits(1),n&&t.skipBits(8),s){const e=i();if(null===e)return;a=e}else a=Math.floor(t.getBitsLeft()/8);y(t.pos%8===0),yield{type:r,data:e.subarray(t.pos/8,t.pos/8+a)},t.skipBits(8*a)}},Mt=e=>{for(const{type:t,data:i}of Dt(e)){if(1!==t)continue;const e=new Ee(i),r=e.readBits(3);e.readBits(1);const n=e.readBits(1);let s=0,a=0,o=0;if(n)s=e.readBits(5);else{if(e.readBits(1)){e.skipBits(32),e.skipBits(32);if(e.readBits(1))return null}const t=e.readBits(1);t&&(o=e.readBits(5),e.skipBits(32),e.skipBits(5),e.skipBits(5));const i=e.readBits(5);for(let r=0;r<=i;r++){e.skipBits(12);const i=e.readBits(5);if(0===r&&(s=i),i>7){const t=e.readBits(1);0===r&&(a=t)}if(t){if(e.readBits(1)){const t=o+1;e.skipBits(t),e.skipBits(t),e.skipBits(1)}}e.readBits(1)&&e.skipBits(4)}}const l=e.readBits(4),c=e.readBits(4),u=l+1;e.skipBits(u);const d=c+1;e.skipBits(d);let h=0;if(h=n?0:e.readBits(1),h&&(e.skipBits(4),e.skipBits(3)),e.skipBits(1),e.skipBits(1),e.skipBits(1),!n){e.skipBits(1),e.skipBits(1),e.skipBits(1),e.skipBits(1);const t=e.readBits(1);t&&(e.skipBits(1),e.skipBits(1));let i=0;if(i=e.readBits(1)?2:e.readBits(1),i>0){e.readBits(1)||e.skipBits(1)}t&&e.skipBits(3)}e.skipBits(1),e.skipBits(1),e.skipBits(1);const f=e.readBits(1);let m=8;if(2===r&&f){m=e.readBits(1)?12:10}else r<=2&&(m=f?10:8);let p=0;1!==r&&(p=e.readBits(1));let g=1,k=1,y=0;return p||(0===r?(g=1,k=1):1===r?(g=0,k=0):12===m&&(g=e.readBits(1),g&&(k=e.readBits(1))),g&&k&&(y=e.readBits(2))),{profile:r,level:s,tier:a,bitDepth:m,monochrome:p,chromaSubsamplingX:g,chromaSubsamplingY:k,chromaSamplePosition:y}}return null},Nt=[480,960,1920,2880,480,960,1920,2880,480,960,1920,2880,480,960,480,960,120,240,480,960,120,240,480,960,120,240,480,960,120,240,480,960],Ot=e=>{if(e.length<7)throw new Error("Setup header is too short.");if(5!==e[0])throw new Error("Wrong packet type in Setup header.");if("vorbis"!==String.fromCharCode(...e.slice(1,7)))throw new Error("Invalid packet signature in Setup header.");const t=e.length,i=new Uint8Array(t);for(let u=0;u97;)if(1===r.readBits(1)){n=r.pos;break}if(0===n)throw new Error("Invalid Setup header: framing bit not found.");let s=0,a=!1,o=0;for(;r.getBitsLeft()>=97;){const e=r.pos,t=r.readBits(8),i=r.readBits(16),n=r.readBits(16);if(t>63||0!==i||0!==n){r.pos=e;break}if(r.skipBits(1),s++,s>64)break;r.clone().readBits(6)+1===s&&(a=!0,o=s)}if(!a)throw new Error("Invalid Setup header: mode header not found.");if(o>63)throw new Error(`Unsupported mode count: ${o}.`);const l=o;r.pos=0,r.skipBits(n);const c=Array(l).fill(0);for(let u=l-1;u>=0;u--)r.skipBits(40),c[u]=r.readBits(1);return{modeBlockflags:c}},Lt=(e,t,i)=>{switch(e){case"avc":for(const e of ct(i,t)){const t=i[e.offset],r=ut(t);if(r>=rt.NON_IDR_SLICE&&r<=rt.SLICE_DPC)return"delta";if(r===rt.IDR)return"key";if(r===rt.SEI&&(!de()||fe()>=144)){const t=i.subarray(e.offset,e.offset+e.length),r=dt(t);let n=1;do{let e=0;for(;;){const t=r[n++];if(void 0===t)break;if(e+=t,t<255)break}let t=0;for(;;){const e=r[n++];if(void 0===e)break;if(t+=e,e<255)break}if(e===6){const e=new Ee(r);e.pos=8*n;const t=S(e),i=e.readBits(1);if(0===t&&1===i)return"key"}n+=t}while(n{var i,r;const n=P(e);let s=0;const a=n.getUint32(s,!0);s+=4;const o=I.decode(e.subarray(s,s+a));s+=a,a>0&&(null!=t.raw||(t.raw={}),null!=(i=t.raw).vendor||(i.vendor=o));const l=n.getUint32(s,!0);s+=4;for(let c=0;c0&&(null!=t.trackNumber||(t.trackNumber=i)),r&&Number.isInteger(r)&&r>0&&(null!=t.tracksTotal||(t.tracksTotal=r))}break;case"TRACKTOTAL":{const e=Number.parseInt(c,10);Number.isInteger(e)&&e>0&&(null!=t.tracksTotal||(t.tracksTotal=e))}break;case"DISCNUMBER":{const e=c.split("/"),i=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(null!=t.discNumber||(t.discNumber=i)),r&&Number.isInteger(r)&&r>0&&(null!=t.discsTotal||(t.discsTotal=r))}break;case"DISCTOTAL":{const e=Number.parseInt(c,10);Number.isInteger(e)&&e>0&&(null!=t.discsTotal||(t.discsTotal=e))}break;case"DATE":{const e=new Date(c);Number.isNaN(e.getTime())||null!=t.date||(t.date=e)}break;case"GENRE":null!=t.genre||(t.genre=c);break;case"METADATA_BLOCK_PICTURE":{const e=ge(c),i=P(e),r=i.getUint32(0,!1),n=i.getUint32(4,!1),s=String.fromCharCode(...e.subarray(8,8+n)),a=i.getUint32(8+n,!1),o=I.decode(e.subarray(12+n,12+n+a)),l=i.getUint32(n+a+28),u=e.subarray(n+a+32,n+a+32+l);null!=t.images||(t.images=[]),t.images.push({data:u,mimeType:s,kind:3===r?"coverFront":4===r?"coverBack":"unknown",name:void 0,description:o||void 0})}}}},Wt=[2,1,2,3,3,4,4,5],Vt=e=>{if(e.length<7)return null;if(11!==e[0]||119!==e[1])return null;const t=new Ee(e);t.skipBits(16),t.skipBits(16);const i=t.readBits(2);if(3===i)return null;const r=t.readBits(6),n=t.readBits(5);if(n>8)return null;const s=t.readBits(3),a=t.readBits(3);0!==(1&a)&&1!==a&&t.skipBits(2),0!==(4&a)&&t.skipBits(2),2===a&&t.skipBits(2);return{fscod:i,bsid:n,bsmod:s,acmod:a,lfeon:t.readBits(1),bitRateCode:Math.floor(r/2)}},Ht=[128,138,192,128,140,192,160,174,240,160,176,240,192,208,288,192,210,288,224,242,336,224,244,336,256,278,384,256,280,384,320,348,480,320,350,480,384,416,576,384,418,576,448,486,672,448,488,672,512,556,768,512,558,768,640,696,960,640,698,960,768,834,1152,768,836,1152,896,974,1344,896,976,1344,1024,1114,1536,1024,1116,1536,1280,1392,1920,1280,1394,1920,1536,1670,2304,1536,1672,2304,1792,1950,2688,1792,1952,2688,2048,2228,3072,2048,2230,3072,2304,2506,3456,2304,2508,3456,2560,2786,3840,2560,2788,3840],Kt=[1,2,3,6],jt=e=>{if(e.length<6)return null;if(11!==e[0]||119!==e[1])return null;const t=new Ee(e);t.skipBits(16);const i=t.readBits(2);if(t.skipBits(3),0!==i&&2!==i)return null;const r=t.readBits(11),n=t.readBits(2);let s,a=0;3===n?(a=t.readBits(2),s=3):s=t.readBits(2);const o=t.readBits(3),l=t.readBits(1),c=t.readBits(5);if(c<11||c>16)return null;const u=Kt[s];let d;d=n<3?tt[n]/1e3:it[a]/1e3;return{dataRate:Math.round((r+1)*d/(16*u)),substreams:[{fscod:n,fscod2:a,bsid:c,bsmod:0,acmod:o,lfeon:l,numDepSub:0,chanLoc:0}]}},Xt=e=>{const t=e.substreams[0];return y(t),t.fscod<3?tt[t.fscod]:null!==t.fscod2&&t.fscod2<3?it[t.fscod2]:null},$t=e=>{const t=e.substreams[0];y(t);let i=Wt[t.acmod]+t.lfeon;if(t.numDepSub>0){const e=[2,2,1,1,2,2,2,1,1];for(let r=0;r<9;r++)t.chanLoc&1<<8-r&&(i+=e[r])}return i};class Qt{constructor(e){this.input=e}dispose(){}}const Gt=new Uint8Array(0);class Yt{constructor(e,t,i,r,n=-1,s,a){if(this.data=e,this.type=t,this.timestamp=i,this.duration=r,this.sequenceNumber=n,e===Gt&&void 0===s)throw new Error("Internal error: byteLength must be explicitly provided when constructing metadata-only packets.");if(void 0===s&&(s=e.byteLength),!(e instanceof Uint8Array))throw new TypeError("data must be a Uint8Array.");if("key"!==t&&"delta"!==t)throw new TypeError('type must be either "key" or "delta".');if(!Number.isFinite(i))throw new TypeError("timestamp must be a number.");if(!Number.isFinite(r)||r<0)throw new TypeError("duration must be a non-negative number.");if(!Number.isFinite(n))throw new TypeError("sequenceNumber must be a number.");if(!Number.isInteger(s)||s<0)throw new TypeError("byteLength must be a non-negative integer.");if(void 0!==a&&("object"!==typeof a||!a))throw new TypeError("sideData, when provided, must be an object.");if(void 0!==(null==a?void 0:a.alpha)&&!(a.alpha instanceof Uint8Array))throw new TypeError("sideData.alpha, when provided, must be a Uint8Array.");if(void 0!==(null==a?void 0:a.alphaByteLength)&&(!Number.isInteger(a.alphaByteLength)||a.alphaByteLength<0))throw new TypeError("sideData.alphaByteLength, when provided, must be a non-negative integer.");this.byteLength=s,this.sideData=null!=a?a:{},this.sideData.alpha&&void 0===this.sideData.alphaByteLength&&(this.sideData.alphaByteLength=this.sideData.alpha.byteLength)}get isMetadataOnly(){return this.data===Gt}get microsecondTimestamp(){return Math.trunc(te*this.timestamp)}get microsecondDuration(){return Math.trunc(te*this.duration)}toEncodedVideoChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}alphaToEncodedVideoChunk(e=this.type){if(!this.sideData.alpha)throw new TypeError("This packet does not contain alpha side data.");if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to a video chunk.");if("undefined"===typeof EncodedVideoChunk)throw new Error("Your browser does not support EncodedVideoChunk.");return new EncodedVideoChunk({data:this.sideData.alpha,type:e,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}toEncodedAudioChunk(){if(this.isMetadataOnly)throw new TypeError("Metadata-only packets cannot be converted to an audio chunk.");if("undefined"===typeof EncodedAudioChunk)throw new Error("Your browser does not support EncodedAudioChunk.");return new EncodedAudioChunk({data:this.data,type:this.type,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration})}static fromEncodedChunk(e,t){var i;if(!(e instanceof EncodedVideoChunk||e instanceof EncodedAudioChunk))throw new TypeError("chunk must be an EncodedVideoChunk or EncodedAudioChunk.");const r=new Uint8Array(e.byteLength);return e.copyTo(r),new Yt(r,e.type,e.timestamp/1e6,(null!=(i=e.duration)?i:0)/1e6,void 0,void 0,t)}clone(e){var t,i,r,n,s,a;if(void 0!==e&&("object"!==typeof e||null===e))throw new TypeError("options, when provided, must be an object.");if(void 0!==(null==e?void 0:e.data)&&!(e.data instanceof Uint8Array))throw new TypeError("options.data, when provided, must be a Uint8Array.");if(void 0!==(null==e?void 0:e.type)&&"key"!==e.type&&"delta"!==e.type)throw new TypeError('options.type, when provided, must be either "key" or "delta".');if(void 0!==(null==e?void 0:e.timestamp)&&!Number.isFinite(e.timestamp))throw new TypeError("options.timestamp, when provided, must be a number.");if(void 0!==(null==e?void 0:e.duration)&&!Number.isFinite(e.duration))throw new TypeError("options.duration, when provided, must be a number.");if(void 0!==(null==e?void 0:e.sequenceNumber)&&!Number.isFinite(e.sequenceNumber))throw new TypeError("options.sequenceNumber, when provided, must be a number.");if(void 0!==(null==e?void 0:e.sideData)&&("object"!==typeof e.sideData||null===e.sideData))throw new TypeError("options.sideData, when provided, must be an object.");return new Yt(null!=(t=null==e?void 0:e.data)?t:this.data,null!=(i=null==e?void 0:e.type)?i:this.type,null!=(r=null==e?void 0:e.timestamp)?r:this.timestamp,null!=(n=null==e?void 0:e.duration)?n:this.duration,null!=(s=null==e?void 0:e.sequenceNumber)?s:this.sequenceNumber,this.byteLength,null!=(a=null==e?void 0:e.sideData)?a:this.sideData)}}const Jt=e=>{const t=P(e);let i=0;const r=t.getUint8(i);i+=1,i+=3;const n=N(e.subarray(i,i+16));i+=16;let s=null;if(r>0){const r=t.getUint32(i);if(i+=4,r>0){s=[];for(let t=0;te.systemId===t.systemId&&((e,t)=>{if(e.length!==t.length)return!1;for(let i=0;i{let t=Ra(e);const i=Wa(e,4);let r=8;1===t&&(t=Oa(e),r=16);const n=t-r;return n<0?null:{name:i,totalSize:t,headerSize:r,contentSize:n}},ti=e=>Ma(e)/65536,ii=e=>Ma(e)/1073741824,ri=e=>{let t=0;for(let i=0;i<4;i++){t<<=7;const i=Ca(e);if(t|=127&i,0===(128&i))break}return t},ni=e=>{let t=Ea(e);return e.skip(2),t=Math.min(t,e.remainingLength),I.decode(xa(e,t))},si=e=>{const t=ei(e);if(!t||"data"!==t.name)return null;if(e.remainingLength<8)return null;const i=Ra(e);e.skip(4);const r=xa(e,t.contentSize-8);switch(i){case 1:return I.decode(r);case 2:return new TextDecoder("utf-16be").decode(r);case 13:return new xe(r,"image/jpeg");case 14:return new xe(r,"image/png");case 27:return new xe(r,"image/bmp");default:return r}},ai=16,oi=new Uint32Array(256),li=new Uint32Array(256),ci=new Uint32Array(256),ui=new Uint32Array(256),di=new Uint32Array(256),hi=new Uint32Array(256),fi=new Uint32Array(10);let mi=!1;class pi{constructor(){this.roundkey=new Uint32Array(44),this.iv=new Uint32Array(ai/Uint32Array.BYTES_PER_ELEMENT),this.in=new Uint8Array(ai),this.out=new Uint8Array(ai),this.inView=new DataView(this.in.buffer),this.outView=new DataView(this.out.buffer)}init({key:e,iv:t}){y(16===e.byteLength),y(16===t.byteLength),mi||(()=>{const e=new Uint8Array(256),t=new Uint8Array(256),i=new Uint8Array(256);for(let s=0,a=1;s<256;s++)i[s]=a,t[a]=s,a=a^a<<1^(128&a?283:0);const r=(e,r)=>e&&r?i[(t[e]+t[r])%255]:0;e[0]=99;for(let s=1;s<256;s++){const r=i[255-t[s]];let n=r^r<<1^r<<2^r<<3^r<<4;n=n>>>8^255&n^99,e[s]=n}for(let s=0;s<256;s++){const t=e[s],i=e.indexOf(s);oi[s]=t<<24|t<<16|t<<8|t,hi[s]=i<<24|i<<16|i<<8|i;const n=r(i,14)<<24|r(i,9)<<16|r(i,13)<<8|r(i,11);li[s]=n,ci[s]=n>>>8|n<<24,ui[s]=n>>>16|n<<16,di[s]=n>>>24|n<<8}let n=1;for(let s=0;s<10;s++)fi[s]=n<<24,n=n<<1^(128&n?283:0);mi=!0})();const i=new DataView(e.buffer,e.byteOffset,e.byteLength),r=new DataView(t.buffer,t.byteOffset,t.byteLength);this.roundkey[0]=i.getUint32(0,!1),this.roundkey[1]=i.getUint32(4,!1),this.roundkey[2]=i.getUint32(8,!1),this.roundkey[3]=i.getUint32(12,!1),this.iv[0]=r.getUint32(0,!1),this.iv[1]=r.getUint32(4,!1),this.iv[2]=r.getUint32(8,!1),this.iv[3]=r.getUint32(12,!1);for(let n=4;n<44;n+=4){const e=this.roundkey[n-1];this.roundkey[n]=this.roundkey[n-4]^4278190080&oi[e>>>16&255]^16711680&oi[e>>>8&255]^65280&oi[e>>>0&255]^255&oi[e>>>24&255]^fi[n/4-1],this.roundkey[n+1]=this.roundkey[n-3]^this.roundkey[n],this.roundkey[n+2]=this.roundkey[n-2]^this.roundkey[n+1],this.roundkey[n+3]=this.roundkey[n-1]^this.roundkey[n+2]}for(let n=0,s=40;n>>24&255]]^ci[255&oi[t>>>16&255]]^ui[255&oi[t>>>8&255]]^di[255&oi[t>>>0&255]]}}decrypt(){let e=this.inView.getUint32(0,!1)^this.roundkey[0],t=this.inView.getUint32(4,!1)^this.roundkey[1],i=this.inView.getUint32(8,!1)^this.roundkey[2],r=this.inView.getUint32(12,!1)^this.roundkey[3];const n=this.inView.getUint32(0,!1),s=this.inView.getUint32(4,!1),a=this.inView.getUint32(8,!1),o=this.inView.getUint32(12,!1);let l,c,u,d;for(let g=1;g<10;g++){const n=4*g;l=li[e>>>24]^ci[r>>>16&255]^ui[i>>>8&255]^di[255&t]^this.roundkey[n],c=li[t>>>24]^ci[e>>>16&255]^ui[r>>>8&255]^di[255&i]^this.roundkey[n+1],u=li[i>>>24]^ci[t>>>16&255]^ui[e>>>8&255]^di[255&r]^this.roundkey[n+2],d=li[r>>>24]^ci[i>>>16&255]^ui[t>>>8&255]^di[255&e]^this.roundkey[n+3],e=l,t=c,i=u,r=d}const h=4278190080&hi[e>>>24&255]^16711680&hi[r>>>16&255]^65280&hi[i>>>8&255]^255&hi[t>>>0&255]^this.roundkey[40],f=4278190080&hi[t>>>24&255]^16711680&hi[e>>>16&255]^65280&hi[r>>>8&255]^255&hi[i>>>0&255]^this.roundkey[41],m=4278190080&hi[i>>>24&255]^16711680&hi[t>>>16&255]^65280&hi[e>>>8&255]^255&hi[r>>>0&255]^this.roundkey[42],p=4278190080&hi[r>>>24&255]^16711680&hi[i>>>16&255]^65280&hi[t>>>8&255]^255&hi[e>>>0&255]^this.roundkey[43];this.outView.setUint32(0,h^this.iv[0],!1),this.outView.setUint32(4,f^this.iv[1],!1),this.outView.setUint32(8,m^this.iv[2],!1),this.outView.setUint32(12,p^this.iv[3],!1),this.iv[0]=n,this.iv[1]=s,this.iv[2]=a,this.iv[3]=o}}class gi extends Qt{constructor(e){super(e),this.moovSlice=null,this.currentTrack=null,this.tracks=[],this.metadataPromise=null,this.movieTimescale=-1,this.movieDurationInTimescale=-1,this.isQuickTime=!1,this.metadataTags={},this.currentMetadataKeys=null,this.isFragmented=!1,this.fragmentTrackDefaults=[],this.psshBoxes=[],this.currentFragment=null,this.lastReadFragment=null,this.decryptionKeyCache=new Map,this.reader=e._reader}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.tracks.map(e=>e.trackBacking)})}getMimeType(){return d(this,null,function*(){yield this.readMetadata();const e=yield this.getTrackBackings(),t=yield Promise.all(e.map(e=>e.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null})));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isQuickTime?"quicktime":"mp4");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({isQuickTime:this.isQuickTime,hasVideo:this.tracks.some(e=>{var t;return"video"===(null==(t=e.info)?void 0:t.type)}),hasAudio:this.tracks.some(e=>{var t;return"audio"===(null==(t=e.info)?void 0:t.type)}),codecStrings:t.filter(Boolean)})})}getMetadataTags(){return d(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}readMetadata(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){let e=0,t=!1;for(;;){let i=this.reader.requestSliceRange(e,8,16);if(i instanceof Promise&&(i=yield i),!i)break;const r=e,n=ei(i);if(!n)break;if("ftyp"===n.name||"styp"===n.name){const e=Wa(i,4);this.isQuickTime="qt "===e}else{if("moov"===n.name){let e=this.reader.requestSlice(i.filePos,n.contentSize);if(e instanceof Promise&&(e=yield e),!e)break;this.moovSlice=e,this.readContiguousBoxes(this.moovSlice);for(const t of this.tracks){const e=t.editListPreviousSegmentDurations/this.movieTimescale;t.editListOffset-=Math.round(e*t.timescale)}t=this.isFragmented&&null!==this.reader.fileSize&&this.reader.fileSize>r+n.totalSize;break}if("moof"===n.name){if(!this.input._initInput)throw new Error('"moof" box encountered with no "moov" box present; this file is likely a Segment as described in ISO/IEC 14496-12 Section 8.16. A separate init file that contains a "moov" box is required to read this file, please provide it using InputOptions.initInput.');const e=yield this.input._initInput._getDemuxer();if(e.constructor!==gi)throw new Error("Init input must match the input's format.");yield e.readMetadata(),this.movieTimescale=e.movieTimescale,this.movieDurationInTimescale=e.movieDurationInTimescale,this.metadataTags=e.metadataTags,this.isFragmented=!0,this.fragmentTrackDefaults=e.fragmentTrackDefaults,this.psshBoxes=e.psshBoxes;for(const t of e.tracks){const e={id:t.id,demuxer:this,trackBacking:null,disposition:t.disposition,timescale:t.timescale,durationInMediaTimescale:t.durationInMediaTimescale,durationInMovieTimescale:t.durationInMovieTimescale,rotation:t.rotation,internalCodecId:t.internalCodecId,name:t.name,languageCode:t.languageCode,sampleTableByteOffset:null,sampleTable:null,fragmentLookupTable:[],currentFragmentState:null,fragmentPositionCache:[],editListPreviousSegmentDurations:t.editListPreviousSegmentDurations,editListOffset:t.editListOffset,encryptionInfo:t.encryptionInfo,encryptionAuxInfo:null,frmaCodecString:null,info:t.info};if(t.trackBacking)if(y(e.info),"video"===e.info.type&&-1!==e.info.width){const t=e;e.trackBacking=new yi(t),this.tracks.push(e)}else if("audio"===e.info.type&&-1!==e.info.numberOfChannels){const t=e;e.trackBacking=new bi(t),this.tracks.push(e)}}t=!1;break}}e=r+n.totalSize}if(t){y(null!==this.reader.fileSize);let e=this.reader.requestSlice(this.reader.fileSize-4,4);e instanceof Promise&&(e=yield e),y(e);const t=Ra(e),i=this.reader.fileSize-t;if(i>=0&&i<=this.reader.fileSize-16){let e=this.reader.requestSliceRange(i,8,16);if(e instanceof Promise&&(e=yield e),e){const t=ei(e);if(t&&"mfra"===t.name){let i=this.reader.requestSlice(e.filePos,t.contentSize);i instanceof Promise&&(i=yield i),i&&this.readContiguousBoxes(i)}}}}}))()}getSampleTableForTrack(e){var t,i;if(e.sampleTable)return e.sampleTable;const r={sampleTimingEntries:[],sampleCompositionTimeOffsets:[],sampleSizes:[],keySampleIndices:null,chunkOffsets:[],sampleToChunk:[],presentationTimestamps:null,presentationTimestampIndexMap:null};if(e.sampleTable=r,null===e.sampleTableByteOffset)return r;y(this.moovSlice);const n=this.moovSlice.slice(e.sampleTableByteOffset);this.currentTrack=e,this.traverseBox(n),this.currentTrack=null;if("audio"===(null==(t=e.info)?void 0:t.type)&&e.info.codec&&De.includes(e.info.codec)&&0===r.sampleCompositionTimeOffsets.length){y("audio"===(null==(i=e.info)?void 0:i.type));const t=He(e.info.codec),n=[],s=[];for(let i=0;ie.startIndex),u=r.sampleTimingEntries[c],d=z(r.sampleTimingEntries,l,e=>e.startIndex),h=r.sampleTimingEntries[d],f=u.startDecodeTimestamp+(o-u.startIndex)*u.delta,m=h.startDecodeTimestamp+(l-h.startIndex)*h.delta-f,p=T(n);p&&p.delta===m?p.count++:n.push({startIndex:a.startChunkIndex+i,startDecodeTimestamp:f,count:1,delta:m});const g=a.samplesPerChunk*t.sampleSize*e.info.numberOfChannels;s.push(g)}a.startSampleIndex=a.startChunkIndex,a.samplesPerChunk=1}r.sampleTimingEntries=n,r.sampleSizes=s}if(r.sampleCompositionTimeOffsets.length>0){r.presentationTimestamps=[];for(const e of r.sampleTimingEntries)for(let t=0;te.presentationTimestamp-t.presentationTimestamp),r.presentationTimestampIndexMap=Array(r.presentationTimestamps.length).fill(-1);for(let e=0;ee.moofOffset===s.moofOffset);if(r)Pi(e,r.timestamp);else{const t=z(i,s.moofOffset-1,e=>e.moofOffset);if(-1!==t){const r=i[t];Pi(e,r.endTimestamp)}}e.startTimestampIsFinal=!0}const r=z(i,e.startTimestamp,e=>e.startTimestamp);if(-1!==r&&i[r].moofOffset===s.moofOffset||i.splice(r+1,0,{moofOffset:s.moofOffset,startTimestamp:e.startTimestamp,endTimestamp:e.endTimestamp}),e.encryptionAuxInfo&&t.encryptionInfo){const i=yield Bi(this.reader,t.encryptionInfo,e.encryptionAuxInfo);for(let t=0;t0){t.languageCode="";for(let e=0;e<3;e++)t.languageCode=String.fromCharCode(96+(31&r))+t.languageCode,r>>=5;ee(t.languageCode)||(t.languageCode=Q)}}break;case"hdlr":{const t=this.currentTrack;if(!t)break;e.skip(8);const i=Wa(e,4);"vide"===i?t.info={type:"video",width:-1,height:-1,squarePixelWidth:-1,squarePixelHeight:-1,codec:null,codecDescription:null,colorSpace:null,avcType:null,avcCodecInfo:null,hevcCodecInfo:null,vp9CodecInfo:null,av1CodecInfo:null}:"soun"===i&&(t.info={type:"audio",numberOfChannels:-1,sampleRate:-1,codec:null,codecDescription:null,aacCodecInfo:null,pcmLittleEndian:!1,pcmSampleSize:null})}break;case"stbl":{const t=this.currentTrack;if(!t)break;t.sampleTableByteOffset=ce,this.readContiguousBoxes(e.slice(de,ue.contentSize))}break;case"stsd":{const t=this.currentTrack;if(!t)break;if(null===t.info||t.sampleTable)break;const i=Ca(e);e.skip(3);const r=Ra(e);for(let n=0;n0&&(1===a?(e.skip(4),l=8*Ra(e),e.skip(8)):2===a&&(e.skip(4),c=qa(e),o=Ra(e),e.skip(4),l=Ra(e),u=Ra(e),e.skip(8))),t.info.numberOfChannels=o,t.info.sampleRate=c,t.frmaCodecString=null,this.readContiguousBoxes(e.slice(e.filePos,r+n.totalSize-e.filePos));const d="enca"===s?t.frmaCodecString:s;if(t.frmaCodecString=null,"mp4a"===d);else if("opus"===d)t.info.codec="opus",t.info.sampleRate=We;else if("flac"===d)t.info.codec="flac";else if("ulaw"===d)t.info.codec="ulaw";else if("alaw"===d)t.info.codec="alaw";else if("ac-3"===d)t.info.codec="ac3";else if("ec-3"===d)t.info.codec="eac3";else if("twos"===d)8===l?t.info.codec="pcm-s8":16===l?t.info.codec=t.info.pcmLittleEndian?"pcm-s16":"pcm-s16be":(console.warn(`Unsupported sample size ${l} for codec 'twos'.`),t.info.codec=null);else if("sowt"===d)8===l?t.info.codec="pcm-s8":16===l?t.info.codec="pcm-s16":(console.warn(`Unsupported sample size ${l} for codec 'sowt'.`),t.info.codec=null);else if("raw "===d)t.info.codec="pcm-u8";else if("in24"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-s24":"pcm-s24be";else if("in32"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-s32":"pcm-s32be";else if("fl32"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-f32":"pcm-f32be";else if("fl64"===d)t.info.codec=t.info.pcmLittleEndian?"pcm-f64":"pcm-f64be";else if("ipcm"===d){const e=t.info.pcmSampleSize;t.info.pcmLittleEndian?16===e?t.info.codec="pcm-s16":24===e?t.info.codec="pcm-s24":32===e?t.info.codec="pcm-s32":(console.warn(`Invalid ipcm sample size ${e}.`),t.info.codec=null):16===e?t.info.codec="pcm-s16be":24===e?t.info.codec="pcm-s24be":32===e?t.info.codec="pcm-s32be":(console.warn(`Invalid ipcm sample size ${e}.`),t.info.codec=null)}else if("fpcm"===d){const e=t.info.pcmSampleSize;t.info.pcmLittleEndian?32===e?t.info.codec="pcm-f32":64===e?t.info.codec="pcm-f64":(console.warn(`Invalid fpcm sample size ${e}.`),t.info.codec=null):32===e?t.info.codec="pcm-f32be":64===e?t.info.codec="pcm-f64be":(console.warn(`Invalid fpcm sample size ${e}.`),t.info.codec=null)}else if("lpcm"===d&&null!==u){const e=l+7>>3,i=Boolean(1&u),r=Boolean(2&u),n=4&u?-1:0;l>0&&l<=64&&(i?32===l&&(t.info.codec=r?"pcm-f32be":"pcm-f32"):n&1<0?(t.encryptionInfo.defaultCryptByteBlock=r>>4,t.encryptionInfo.defaultSkipByteBlock=15&r):(t.encryptionInfo.defaultCryptByteBlock=0,t.encryptionInfo.defaultSkipByteBlock=0),t.encryptionInfo.defaultIsProtected=0!==Ca(e),t.encryptionInfo.defaultPerSampleIvSize=Ca(e),t.encryptionInfo.defaultKid=N(xa(e,16)),t.encryptionInfo.defaultIsProtected&&0===t.encryptionInfo.defaultPerSampleIvSize){const i=Ca(e),r=new Uint8Array(16);r.set(xa(e,i),0),t.encryptionInfo.defaultConstantIv=r}}break;case"avcC":{const t=this.currentTrack;if(!t)break;y(t.info),t.info.codecDescription=xa(e,ue.contentSize)}break;case"hvcC":{const t=this.currentTrack;if(!t)break;y(t.info),t.info.codecDescription=xa(e,ue.contentSize)}break;case"vpcC":{const i=this.currentTrack;if(!i)break;y("video"===(null==(t=i.info)?void 0:t.type)),e.skip(4);const r=Ca(e),n=Ca(e),s=Ca(e),a=s>>4,o=s>>1&7,l=1&s,c=Ca(e),u=Ca(e),d=Ca(e);i.info.vp9CodecInfo={profile:r,level:n,bitDepth:a,chromaSubsampling:o,videoFullRangeFlag:l,colourPrimaries:c,transferCharacteristics:u,matrixCoefficients:d}}break;case"av1C":{const t=this.currentTrack;if(!t)break;y("video"===(null==(i=t.info)?void 0:i.type)),e.skip(1);const r=Ca(e),n=r>>5,s=31&r,a=Ca(e),o=a>>7,l=a>>6&1,c=a>>4&1,u=a>>3&1,d=a>>2&1,h=3&a,f=2===n&&l?a>>5&1?12:10:l?10:8;t.info.av1CodecInfo={profile:n,level:s,tier:o,bitDepth:f,monochrome:c,chromaSubsamplingX:u,chromaSubsamplingY:d,chromaSamplePosition:h}}break;case"colr":{const t=this.currentTrack;if(!t)break;y("video"===(null==(r=t.info)?void 0:r.type));if("nclx"!==Wa(e,4))break;const i=Ea(e),n=Ea(e),s=Ea(e),a=Boolean(128&Ca(e));t.info.colorSpace={primaries:B[i],transfer:_[n],matrix:F[s],fullRange:a}}break;case"pasp":{const t=this.currentTrack;if(!t)break;y("video"===(null==(n=t.info)?void 0:n.type));const i=Ra(e),r=Ra(e);i>0&&r>0&&(i>r?t.info.squarePixelWidth=Math.round(t.info.width*i/r):t.info.squarePixelHeight=Math.round(t.info.height*r/i))}break;case"esds":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(s=t.info)?void 0:s.type)),e.skip(4);y(3===Ca(e)),ri(e),e.skip(2);const i=Ca(e),r=0!==(64&i),n=0!==(32&i);if(0!==(128&i)&&e.skip(2),r){const t=Ca(e);e.skip(t)}n&&e.skip(2);y(4===Ca(e));const a=ri(e),o=e.filePos,l=Ca(e);if(64===l||103===l?(t.info.codec="aac",t.info.aacCodecInfo={isMpeg2:103===l,objectType:null}):105===l||107===l?t.info.codec="mp3":221===l?t.info.codec="vorbis":console.warn(`Unsupported audio codec (objectTypeIndication ${l}) - discarding track.`),e.skip(12),a>e.filePos-o){y(5===Ca(e));const i=ri(e);if(t.info.codecDescription=xa(e,i),"aac"===t.info.codec){const e=Fe(t.info.codecDescription);null!==e.numberOfChannels&&(t.info.numberOfChannels=e.numberOfChannels),null!==e.sampleRate&&(t.info.sampleRate=e.sampleRate)}}}break;case"enda":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(a=t.info)?void 0:a.type)),t.info.pcmLittleEndian=!!(255&Ea(e))}break;case"pcmC":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(o=t.info)?void 0:o.type)),e.skip(4);const i=Ca(e);t.info.pcmLittleEndian=Boolean(1&i),t.info.pcmSampleSize=Ca(e)}break;case"dOps":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(l=t.info)?void 0:l.type)),e.skip(1);const i=Ca(e),r=Ea(e),n=Ra(e),s=Aa(e),a=Ca(e);let o;o=0!==a?xa(e,2+i):new Uint8Array(0);const c=new Uint8Array(19+o.byteLength),u=new DataView(c.buffer);u.setUint32(0,1332770163,!1),u.setUint32(4,1214603620,!1),u.setUint8(8,1),u.setUint8(9,i),u.setUint16(10,r,!0),u.setUint32(12,n,!0),u.setInt16(16,s,!0),u.setUint8(18,a),c.set(o,19),t.info.codecDescription=c,t.info.numberOfChannels=i}break;case"dfLa":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(d=t.info)?void 0:d.type)),e.skip(4);const i=127,r=128,n=e.filePos;for(;e.filePos>>12,n=1+(i>>9&7);t.info.sampleRate=r,t.info.numberOfChannels=n,e.skip(20)}else e.skip(s);if(n&r)break}const s=e.filePos;e.filePos=n;const a=xa(e,s-n),o=new Uint8Array(4+a.byteLength);new DataView(o.buffer).setUint32(0,1716281667,!1),o.set(a,4),t.info.codecDescription=o}break;case"dac3":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(h=t.info)?void 0:h.type));const i=xa(e,3),r=new Ee(i),n=r.readBits(2);r.skipBits(8);const s=r.readBits(3),a=r.readBits(1);n<3&&(t.info.sampleRate=tt[n]),t.info.numberOfChannels=Wt[s]+a}break;case"dec3":{const t=this.currentTrack;if(!t)break;y("audio"===(null==(f=t.info)?void 0:f.type));const i=(e=>{if(e.length<2)return null;const t=new Ee(e),i=t.readBits(13),r=t.readBits(3),n=[];for(let s=0;s<=r&&!(Math.ceil(t.pos/8)+3>e.length);s++){const e=t.readBits(2),i=t.readBits(5);t.skipBits(1),t.skipBits(1);const r=t.readBits(3),s=t.readBits(3),a=t.readBits(1);t.skipBits(3);const o=t.readBits(4);let l=0;o>0?l=t.readBits(9):t.skipBits(1),n.push({fscod:e,fscod2:null,bsid:i,bsmod:r,acmod:s,lfeon:a,numDepSub:o,chanLoc:l})}return 0===n.length?null:{dataRate:i,substreams:n}})(xa(e,ue.contentSize));if(!i){console.warn("Invalid dec3 box contents, ignoring.");break}const r=Xt(i);null!==r&&(t.info.sampleRate=r),t.info.numberOfChannels=$t(i)}break;case"stts":{const t=this.currentTrack;if(!t)break;if(!t.sampleTable)break;e.skip(4);const i=Ra(e);let r=0,n=0;for(let s=0;se.id===i);if(!r)break;const n=Ra(e),s=(12&n)>>2,a=3&n,o=[Ca,Ea,_a,Ra],l=o[(48&n)>>4],c=o[s],u=o[a],d=Ra(e);for(let h=0;he.timestamp-t.timestamp);for(let e=0;e({presentationTimestamp:e.presentationTimestamp,sampleIndex:t})).sort((e,t)=>e.presentationTimestamp-t.presentationTimestamp);for(let n=0;ne.id===c);if(!u)break;const d=this.fragmentTrackDefaults.find(e=>e.trackId===c);this.currentTrack=u,u.currentFragmentState={baseDataOffset:this.currentFragment.implicitBaseDataOffset,sampleDescriptionIndex:null!=(p=null==d?void 0:d.defaultSampleDescriptionIndex)?p:null,defaultSampleDuration:null!=(g=null==d?void 0:d.defaultSampleDuration)?g:null,defaultSampleSize:null!=(k=null==d?void 0:d.defaultSampleSize)?k:null,defaultSampleFlags:null!=(S=null==d?void 0:d.defaultSampleFlags)?S:null,startTimestamp:null,encryptionAuxInfo:null},i?u.currentFragmentState.baseDataOffset=Oa(e):l&&(u.currentFragmentState.baseDataOffset=this.currentFragment.moofOffset),r&&(u.currentFragmentState.sampleDescriptionIndex=Ra(e)),n&&(u.currentFragmentState.defaultSampleDuration=Ra(e)),s&&(u.currentFragmentState.defaultSampleSize=Ra(e)),a&&(u.currentFragmentState.defaultSampleFlags=Ra(e)),o&&(u.currentFragmentState.defaultSampleDuration=0)}break;case"tfdt":{const t=this.currentTrack;if(!t)break;y(t.currentFragmentState);const i=Ca(e);e.skip(3);const r=0===i?Ra(e):Oa(e);t.currentFragmentState.startTimestamp=r}break;case"trun":{const t=this.currentTrack;if(!t)break;y(this.currentFragment),y(t.currentFragmentState);const i=Ca(e),r=_a(e),n=Boolean(1&r),s=Boolean(4&r),a=Boolean(256&r),o=Boolean(512&r),l=Boolean(1024&r),c=Boolean(2048&r),u=Ra(e);let d=null;n&&(d=Ma(e));let h,f=null;if(s&&(f=Ra(e)),this.currentFragment.trackData.has(t.id)?(h=this.currentFragment.trackData.get(t.id),null!==d&&(h.currentOffset=t.currentFragmentState.baseDataOffset+d)):(h={track:t,currentTimestamp:0,currentOffset:t.currentFragmentState.baseDataOffset+(null!=d?d:0),startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,samples:[],presentationTimestamps:[],startTimestampIsFinal:!1,encryptionAuxInfo:null},this.currentFragment.trackData.set(t.id,h)),0===u){this.currentFragment.implicitBaseDataOffset=h.currentOffset;break}for(let m=0;m0&&(n=xa(e,r));const s=Ci(t);s.defaultSampleInfoSize=i,s.sampleSizes=n,s.sampleCount=r}break;case"saio":{const t=this.currentTrack;if(!t||!t.encryptionInfo)break;const i=Ca(e);if(1&_a(e)){const i=Wa(e,4),r=Ra(e);if(i!==t.encryptionInfo.scheme||0!==r)break}const r=Ra(e);if(0===r)break;r>1&&console.warn("Multiple saio entries are not supported; using the first offset only.");let n=0===i?Ra(e):Number(Oa(e));this.currentFragment&&(n+=this.currentFragment.moofOffset);Ci(t).offset=n}break;case"senc":{const t=this.currentTrack;if(!t||!t.encryptionInfo)break;y(this.currentFragment);const i=this.currentFragment.trackData.get(t.id);if(!i)break;e.skip(1);const r=_a(e),n=Boolean(2&r),s=Ra(e),a=t.encryptionInfo.defaultPerSampleIvSize;y(null!==a);for(let o=0;o0?r.set(xa(e,a),0):r.set(t.encryptionInfo.defaultConstantIv,0);let s=null;if(n){const t=Ea(e);s=[];for(let i=0;i0&&(null!=(re=this.metadataTags).trackNumber||(re.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&(null!=(ne=this.metadataTags).tracksTotal||(ne.tracksTotal=i))}break;case"trkn":if(n instanceof Uint8Array&&n.length>=6){const e=P(n),t=e.getUint16(2,!1),i=e.getUint16(4,!1);t>0&&(null!=(se=this.metadataTags).trackNumber||(se.trackNumber=t)),i>0&&(null!=(ae=this.metadataTags).tracksTotal||(ae.tracksTotal=i))}break;case"disc":case"disk":if(n instanceof Uint8Array&&n.length>=6){const e=P(n),t=e.getUint16(2,!1),i=e.getUint16(4,!1);t>0&&(null!=(oe=this.metadataTags).discNumber||(oe.discNumber=t)),i>0&&(null!=(le=this.metadataTags).discsTotal||(le.discsTotal=i))}}}}}var fe,me;return e.filePos=he,!0}}class ki{constructor(e){this.internalTrack=e,this.packetToSampleIndex=new WeakMap,this.packetToFragmentLocation=new WeakMap}getId(){return this.internalTrack.id}getNumber(){const e=this.internalTrack.demuxer,t=this.internalTrack.trackBacking.getType();let i=0;for(const r of e.tracks)if(r.trackBacking.getType()===t&&i++,r===this.internalTrack)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.internalCodecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.timescale}isRelativeToUnixEpoch(){return!1}getDisposition(){return this.internalTrack.disposition}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){var e;const t=this.internalTrack;if(t.durationInMediaTimescale<=0)return null;y(t.trackBacking);const i=yield t.trackBacking.getFirstPacket({metadataOnly:!0});return(null!=(e=null==i?void 0:i.timestamp)?e:0)+t.durationInMediaTimescale/t.timescale})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getFirstPacket(e){return d(this,null,function*(){const t=yield this.fetchPacketForSampleIndex(0,e);return t||!this.internalTrack.demuxer.isFragmented?t:this.performFragmentedLookup(null,e=>e.trackData.get(this.internalTrack.id)?{sampleIndex:0,correctSampleFound:!0}:{sampleIndex:-1,correctSampleFound:!1},-1/0,1/0,e)})}mapTimestampIntoTimescale(e){return G(e*this.internalTrack.timescale)+this.internalTrack.editListOffset}getPacket(e,t){return d(this,null,function*(){const i=this.mapTimestampIntoTimescale(e),r=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),n=Ti(r,i),s=yield this.fetchPacketForSampleIndex(n,t);return xi(r)&&this.internalTrack.demuxer.isFragmented?this.performFragmentedLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const r=z(t.presentationTimestamps,i,e=>e.presentationTimestamp);return{sampleIndex:-1!==r?t.presentationTimestamps[r].sampleIndex:-1,correctSampleFound:-1!==r&&i{if(e===r.fragment){const t=e.trackData.get(this.internalTrack.id);if(r.sampleIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{sampleIndex:-1,correctSampleFound:!1};const r=V(t.presentationTimestamps,e=>t.samples[e.sampleIndex].isKeyFrame&&e.presentationTimestamp<=i);return{sampleIndex:-1!==r?t.presentationTimestamps[r].sampleIndex:-1,correctSampleFound:-1!==r&&i{if(e===r.fragment){const t=e.trackData.get(this.internalTrack.id).samples.findIndex((e,t)=>e.isKeyFrame&&t>r.sampleIndex);if(-1!==t)return{sampleIndex:t,correctSampleFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.samples.findIndex(e=>e.isKeyFrame);return y(-1!==e),{sampleIndex:e,correctSampleFound:!0}}}return{sampleIndex:-1,correctSampleFound:!1}},-1/0,1/0,t)})}fetchPacketForSampleIndex(e,t){return d(this,null,function*(){if(-1===e)return null;const i=this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack),r=vi(i,e);if(!r)return null;let n;if(t.metadataOnly)n=Gt;else{let t=this.internalTrack.demuxer.reader.requestSlice(r.sampleOffset,r.sampleSize);if(t instanceof Promise&&(t=yield t),!t)return null;if(n=xa(t,r.sampleSize),this.internalTrack.encryptionAuxInfo){y(this.internalTrack.encryptionInfo);const t=yield Bi(this.internalTrack.demuxer.reader,this.internalTrack.encryptionInfo,this.internalTrack.encryptionAuxInfo);ee.timestamp),f=-1!==h?this.internalTrack.fragmentLookupTable[h]:null,m=z(this.internalTrack.fragmentPositionCache,i,e=>e.startTimestamp),p=-1!==m?this.internalTrack.fragmentPositionCache[m]:null,g=Math.max(null!=(s=null==f?void 0:f.moofOffset)?s:0,null!=(a=null==p?void 0:p.moofOffset)?a:0)||null;let k;for(e?null===g||e.moofOffset>=g?(k=e.moofOffset+e.moofSize,c=e):k=g:k=null!=g?g:0;;){if(c){const e=c.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>r)break}let e=l.reader.requestSliceRange(k,8,16);if(e instanceof Promise&&(e=yield e),!e)break;const i=k,s=ei(e);if(!s)break;if("moof"===s.name){c=yield l.readFragment(i);const{sampleIndex:e,correctSampleFound:r}=t(c);if(r)return this.fetchPacketInFragment(c,e,n);-1!==e&&(u=c,d=e)}k=i+s.totalSize}if(f&&(!u||u.moofOffsetd(this,null,function*(){var e,t;if("vp9"!==this.internalTrack.info.codec||this.internalTrack.info.vp9CodecInfo){if("av1"===this.internalTrack.info.codec&&!this.internalTrack.info.av1CodecInfo){const e=yield this.getFirstPacket({});this.internalTrack.info.av1CodecInfo=e&&Mt(e.data)}}else{const e=yield this.getFirstPacket({});this.internalTrack.info.vp9CodecInfo=e&&Rt(e.data)}const i={codec:Ue(this.internalTrack.info),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0,colorSpace:null!=(t=this.internalTrack.info.colorSpace)?t:void 0};return this.internalTrack.info.width===this.internalTrack.info.squarePixelWidth&&this.internalTrack.info.height===this.internalTrack.info.squarePixelHeight||(i.displayAspectWidth=this.internalTrack.info.squarePixelWidth,i.displayAspectHeight=this.internalTrack.info.squarePixelHeight),i}))():null})}}class bi extends ki{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getType(){return"audio"}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}getDecoderConfig(){return d(this,null,function*(){var e,t;return this.internalTrack.info.codec?null!=(t=this.decoderConfig)?t:this.decoderConfig={codec:qe(this.internalTrack.info),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0}:null})}}const Ti=(e,t)=>{if(e.presentationTimestamps){const i=z(e.presentationTimestamps,t,e=>e.presentationTimestamp);return-1===i?-1:e.presentationTimestamps[i].sampleIndex}{const i=z(e.sampleTimingEntries,t,e=>e.startDecodeTimestamp);if(-1===i)return-1;const r=e.sampleTimingEntries[i];return r.startIndex+Math.min(Math.floor((t-r.startDecodeTimestamp)/r.delta),r.count-1)}},Si=(e,t)=>{var i;if(!e.keySampleIndices)return Ti(e,t);if(e.presentationTimestamps){const i=z(e.presentationTimestamps,t,e=>e.presentationTimestamp);if(-1===i)return-1;for(let t=i;t>=0;t--){const i=e.presentationTimestamps[t].sampleIndex;if(-1!==L(e.keySampleIndices,i,e=>e))return i}return-1}{const r=Ti(e,t),n=z(e.keySampleIndices,r,e=>e);return null!=(i=e.keySampleIndices[n])?i:-1}},vi=(e,t)=>{const i=z(e.sampleTimingEntries,t,e=>e.startIndex),r=e.sampleTimingEntries[i];if(!r||r.startIndex+r.count<=t)return null;let n=r.startDecodeTimestamp+(t-r.startIndex)*r.delta;const s=z(e.sampleCompositionTimeOffsets,t,e=>e.startIndex),a=e.sampleCompositionTimeOffsets[s];a&&t-a.startIndexe.startSampleIndex),c=e.sampleToChunk[l];y(c);const u=c.startChunkIndex+Math.floor((t-c.startSampleIndex)/c.samplesPerChunk),d=e.chunkOffsets[u],h=c.startSampleIndex+(u-c.startChunkIndex)*c.samplesPerChunk;let f=0,m=d;if(1===e.sampleSizes.length)m+=o*(t-h),f+=o*c.samplesPerChunk;else for(let g=h;ge)}},wi=(e,t)=>{var i;if(!e.keySampleIndices)return t+1;const r=z(e.keySampleIndices,t,e=>e);return null!=(i=e.keySampleIndices[r+1])?i:-1},Pi=(e,t)=>{e.startTimestamp+=t,e.endTimestamp+=t;for(const i of e.samples)i.presentationTimestamp+=t;for(const i of e.presentationTimestamps)i.presentationTimestamp+=t},Ii=e=>{const[t,i]=e,r=Math.atan2(i,t);return Number.isFinite(r)?r*(180/Math.PI):0},xi=e=>0===e.sampleSizes.length,Ci=e=>{var t,i,r;return e.currentFragmentState?null!=(i=(t=e.currentFragmentState).encryptionAuxInfo)?i:t.encryptionAuxInfo={defaultSampleInfoSize:0,sampleSizes:null,sampleCount:0,offset:null,resolved:null}:null!=(r=e.encryptionAuxInfo)?r:e.encryptionAuxInfo={defaultSampleInfoSize:0,sampleSizes:null,sampleCount:0,offset:null,resolved:null}},Bi=(e,t,i)=>d(null,null,function*(){if(i.resolved)return i.resolved;if(null===i.offset||0===i.sampleCount)throw new Error("Incomplete saiz/saio info; cannot resolve encryption data.");let r=0;if(i.defaultSampleInfoSize>0)r=i.defaultSampleInfoSize*i.sampleCount;else{y(i.sampleSizes);for(let e=0;e0?i.defaultSampleInfoSize:i.sampleSizes[e],o=new Uint8Array(16);s>0?o.set(xa(n,s),0):o.set(t.defaultConstantIv,0);let l=null;if(r>s){const e=Ea(n);l=[];for(let t=0;td(null,null,function*(){var n;y(e.encryptionInfo);const s=e.encryptionInfo;y(null!==s.defaultKid);const a=s.defaultKid;let o;const l=e.demuxer.decryptionKeyCache.get(a);if(l)o=yield l;else{if(!(null==(n=e.demuxer.input._formatOptions.isobmff)?void 0:n.resolveKeyId))throw new Error("Encrypted media samples encountered. To decrypt them, please provide a callback for InputOptions.formatOptions.isobmff.resolveKeyId.");const t=d(null,null,function*(){let t=e.demuxer.psshBoxes;if(r){t=[...t,...r.psshBoxes].filter(e=>null===e.keyIds||e.keyIds.includes(a));for(let e=0;e{y(e.length%2===0);const t=new Uint8Array(e.length/2);for(let i=0;id(null,null,function*(){const n=new Uint8Array(16);n.set(i.iv,0);const s=yield crypto.subtle.importKey("raw",e,{name:"AES-CTR"},!1,["decrypt"]),a=e=>d(null,null,function*(){const t=yield crypto.subtle.decrypt({name:"AES-CTR",counter:n,length:64},s,e);return new Uint8Array(t)});if(!i.subsamples)return a(r);y(null!==t.defaultCryptByteBlock&&null!==t.defaultSkipByteBlock);const o=Fi(i.subsamples,t.defaultCryptByteBlock,t.defaultSkipByteBlock);let l=0;for(const e of o)for(const t of e.perSubsample)l+=t.length;const c=new Uint8Array(l);let u=0;for(const e of o)for(const t of e.perSubsample)c.set(r.subarray(t.offset,t.offset+t.length),u),u+=t.length;const h=yield a(c),f=new Uint8Array(r);let m=0;for(const e of o)for(const t of e.perSubsample)f.set(h.subarray(m,m+t.length),t.offset),m+=t.length;return f}),Ai=(e,t,i,r)=>{const n=new pi;n.init({key:e,iv:i.iv});const s=t.defaultCryptByteBlock,a=t.defaultSkipByteBlock;if(y(null!==s&&null!==a),!i.subsamples){const e=new Uint8Array(r),t=Math.floor(r.length/16);for(let i=0;i{const r=[],n=0!==t||0!==i;let s=0;for(const a of e){s+=a.clearLen;const e=[];if(n){let r=a.protectedLen,n=s;for(;r>0&&!(r<16*t);){const s=16*t;e.push({offset:n,length:s}),n+=s,r-=s;const a=Math.min(16*i,r);n+=a,r-=a}s+=a.protectedLen}else a.protectedLen>0&&e.push({offset:s,length:a.protectedLen}),s+=a.protectedLen;r.push({perSubsample:e})}return r};var Ri,Di;(Di=Ri||(Ri={}))[Di.EBML=440786851]="EBML",Di[Di.EBMLVersion=17030]="EBMLVersion",Di[Di.EBMLReadVersion=17143]="EBMLReadVersion",Di[Di.EBMLMaxIDLength=17138]="EBMLMaxIDLength",Di[Di.EBMLMaxSizeLength=17139]="EBMLMaxSizeLength",Di[Di.DocType=17026]="DocType",Di[Di.DocTypeVersion=17031]="DocTypeVersion",Di[Di.DocTypeReadVersion=17029]="DocTypeReadVersion",Di[Di.Void=236]="Void",Di[Di.Segment=408125543]="Segment",Di[Di.SeekHead=290298740]="SeekHead",Di[Di.Seek=19899]="Seek",Di[Di.SeekID=21419]="SeekID",Di[Di.SeekPosition=21420]="SeekPosition",Di[Di.Duration=17545]="Duration",Di[Di.Info=357149030]="Info",Di[Di.TimestampScale=2807729]="TimestampScale",Di[Di.MuxingApp=19840]="MuxingApp",Di[Di.WritingApp=22337]="WritingApp",Di[Di.Tracks=374648427]="Tracks",Di[Di.TrackEntry=174]="TrackEntry",Di[Di.TrackNumber=215]="TrackNumber",Di[Di.TrackUID=29637]="TrackUID",Di[Di.TrackType=131]="TrackType",Di[Di.FlagEnabled=185]="FlagEnabled",Di[Di.FlagDefault=136]="FlagDefault",Di[Di.FlagForced=21930]="FlagForced",Di[Di.FlagOriginal=21934]="FlagOriginal",Di[Di.FlagHearingImpaired=21931]="FlagHearingImpaired",Di[Di.FlagVisualImpaired=21932]="FlagVisualImpaired",Di[Di.FlagCommentary=21935]="FlagCommentary",Di[Di.FlagLacing=156]="FlagLacing",Di[Di.Name=21358]="Name",Di[Di.Language=2274716]="Language",Di[Di.LanguageBCP47=2274717]="LanguageBCP47",Di[Di.CodecID=134]="CodecID",Di[Di.CodecPrivate=25506]="CodecPrivate",Di[Di.CodecDelay=22186]="CodecDelay",Di[Di.SeekPreRoll=22203]="SeekPreRoll",Di[Di.DefaultDuration=2352003]="DefaultDuration",Di[Di.Video=224]="Video",Di[Di.PixelWidth=176]="PixelWidth",Di[Di.PixelHeight=186]="PixelHeight",Di[Di.DisplayWidth=21680]="DisplayWidth",Di[Di.DisplayHeight=21690]="DisplayHeight",Di[Di.DisplayUnit=21682]="DisplayUnit",Di[Di.AlphaMode=21440]="AlphaMode",Di[Di.Audio=225]="Audio",Di[Di.SamplingFrequency=181]="SamplingFrequency",Di[Di.Channels=159]="Channels",Di[Di.BitDepth=25188]="BitDepth",Di[Di.SimpleBlock=163]="SimpleBlock",Di[Di.BlockGroup=160]="BlockGroup",Di[Di.Block=161]="Block",Di[Di.BlockAdditions=30113]="BlockAdditions",Di[Di.BlockMore=166]="BlockMore",Di[Di.BlockAdditional=165]="BlockAdditional",Di[Di.BlockAddID=238]="BlockAddID",Di[Di.BlockDuration=155]="BlockDuration",Di[Di.ReferenceBlock=251]="ReferenceBlock",Di[Di.Cluster=524531317]="Cluster",Di[Di.Timestamp=231]="Timestamp",Di[Di.Cues=475249515]="Cues",Di[Di.CuePoint=187]="CuePoint",Di[Di.CueTime=179]="CueTime",Di[Di.CueTrackPositions=183]="CueTrackPositions",Di[Di.CueTrack=247]="CueTrack",Di[Di.CueClusterPosition=241]="CueClusterPosition",Di[Di.Colour=21936]="Colour",Di[Di.MatrixCoefficients=21937]="MatrixCoefficients",Di[Di.TransferCharacteristics=21946]="TransferCharacteristics",Di[Di.Primaries=21947]="Primaries",Di[Di.Range=21945]="Range",Di[Di.Projection=30320]="Projection",Di[Di.ProjectionType=30321]="ProjectionType",Di[Di.ProjectionPoseRoll=30325]="ProjectionPoseRoll",Di[Di.Attachments=423732329]="Attachments",Di[Di.AttachedFile=24999]="AttachedFile",Di[Di.FileDescription=18046]="FileDescription",Di[Di.FileName=18030]="FileName",Di[Di.FileMediaType=18016]="FileMediaType",Di[Di.FileData=18012]="FileData",Di[Di.FileUID=18094]="FileUID",Di[Di.Chapters=272869232]="Chapters",Di[Di.Tags=307544935]="Tags",Di[Di.Tag=29555]="Tag",Di[Di.Targets=25536]="Targets",Di[Di.TargetTypeValue=26826]="TargetTypeValue",Di[Di.TargetType=25546]="TargetType",Di[Di.TagTrackUID=25541]="TagTrackUID",Di[Di.TagEditionUID=25545]="TagEditionUID",Di[Di.TagChapterUID=25540]="TagChapterUID",Di[Di.TagAttachmentUID=25542]="TagAttachmentUID",Di[Di.SimpleTag=26568]="SimpleTag",Di[Di.TagName=17827]="TagName",Di[Di.TagLanguage=17530]="TagLanguage",Di[Di.TagString=17543]="TagString",Di[Di.TagBinary=17541]="TagBinary",Di[Di.ContentEncodings=28032]="ContentEncodings",Di[Di.ContentEncoding=25152]="ContentEncoding",Di[Di.ContentEncodingOrder=20529]="ContentEncodingOrder",Di[Di.ContentEncodingScope=20530]="ContentEncodingScope",Di[Di.ContentCompression=20532]="ContentCompression",Di[Di.ContentCompAlgo=16980]="ContentCompAlgo",Di[Di.ContentCompSettings=16981]="ContentCompSettings",Di[Di.ContentEncryption=20533]="ContentEncryption";const Mi=[Ri.EBML,Ri.Segment],Ni=[Ri.SeekHead,Ri.Info,Ri.Cluster,Ri.Tracks,Ri.Cues,Ri.Attachments,Ri.Chapters,Ri.Tags],Oi=[...Mi,...Ni],Li=16,zi=e=>{if(e.remainingLength<1)return null;const t=Ca(e);if(e.skip(-1),0===t)return null;let i=1,r=128;for(;0===(t&r);)i++,r>>=1;return e.remainingLength{if(e.remainingLength<1)return null;const t=Ca(e);if(0===t)return null;let i=1,r=128;for(;0===(t&r);)i++,r>>=1;if(e.remainingLength{if(t<1||t>8)throw new Error("Bad unsigned int size "+t);let i=0;for(let r=0;r{const t=zi(e);if(null===t)return null;if(e.remainingLength{if(e.remainingLength<1)return null;if(255===Ca(e))return;e.skip(-1);const t=Ui(e);return null===t?null:72057594037927940!==t?t:void 0},Hi=e=>{y(e.remainingLength>=2);const t=Wi(e);if(null===t)return null;const i=Vi(e);return null===i?null:{id:t,size:i}},Ki=(e,t)=>{const i=xa(e,t);let r=0;for(;r{const i=xa(e,t);let r=0;for(;r{if(0===t)return 0;if(4!==t&&8!==t)throw new Error("Bad float size "+t);return 4===t?Ua(e):qa(e)},$i=(e,t,i,r)=>d(null,null,function*(){const n=new Set(i);let s=t;for(;null===r||ss?r:s,found:!1}}),Qi=(e,t,i,r)=>d(null,null,function*(){const n=o(2,16),s=new Set(i);let a=t;for(;ae.tracks.map(e=>e.trackBacking))})}getMimeType(){return d(this,null,function*(){yield this.readMetadata();const e=yield this.getTrackBackings(),t=yield Promise.all(e.map(e=>e.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null})));return(e=>{let t=(e.hasVideo?"video/":e.hasAudio?"audio/":"application/")+(e.isWebM?"webm":"x-matroska");e.codecStrings.length>0&&(t+=`; codecs="${[...new Set(e.codecStrings.filter(Boolean))].join(", ")}"`);return t})({isWebM:this.isWebM,hasVideo:this.segments.some(e=>e.tracks.some(e=>{var t;return"video"===(null==(t=e.info)?void 0:t.type)})),hasAudio:this.segments.some(e=>e.tracks.some(e=>{var t;return"audio"===(null==(t=e.info)?void 0:t.type)})),codecStrings:t.filter(Boolean)})})}getMetadataTags(){return d(this,null,function*(){yield this.readMetadata();for(const t of this.segments)t.metadataTagsCollected||(null!==this.reader.fileSize&&(yield this.loadSegmentMetadata(t)),t.metadataTagsCollected=!0);let e={};for(const t of this.segments)e=c(c({},e),t.metadataTags);return e})}readMetadata(){var e;return null!=(e=this.readMetadataPromise)?e:this.readMetadataPromise=(()=>d(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,2,Li);if(t instanceof Promise&&(t=yield t),!t)break;const i=Hi(t);if(!i)break;const r=i.id;let n=i.size;const s=t.filePos;if(r===Ri.EBML){lr(n);let e=this.reader.requestSlice(s,n);if(e instanceof Promise&&(e=yield e),!e)break;this.readContiguousElements(e)}else if(r===Ri.Segment){if(yield this.readSegment(s,n),void 0===n)break;if(null===this.reader.fileSize)break}else if(r===Ri.Cluster){if(null===this.reader.fileSize)break;if(void 0===n){n=(yield $i(this.reader,s,Oi,this.reader.fileSize)).pos-s}const e=T(this.segments);e&&(e.elementEndPos=s+n)}lr(n),e=s+n}}))()}readSegment(e,t){return d(this,null,function*(){var i;this.currentSegment={seekHeadSeen:!1,infoSeen:!1,tracksSeen:!1,cuesSeen:!1,tagsSeen:!1,attachmentsSeen:!1,timestampScale:-1,timestampFactor:-1,duration:-1,seekEntries:[],tracks:[],cuePoints:[],dataStartPos:e,elementEndPos:void 0===t?null:e+t,clusterSeekStartPos:e,lastReadCluster:null,metadataTags:{},metadataTagsCollected:!1},this.segments.push(this.currentSegment);let r=e;for(;null===this.currentSegment.elementEndPos||re.id===s);if(-1!==l){const e=pr[l].flag;this.currentSegment[e]=!0,lr(a);let t=this.reader.requestSlice(o,a);t instanceof Promise&&(t=yield t),t&&this.readContiguousElements(t)}else if(s===Ri.Tags||s===Ri.Attachments){s===Ri.Tags?this.currentSegment.tagsSeen=!0:this.currentSegment.attachmentsSeen=!0,lr(a);let e=this.reader.requestSlice(o,a);e instanceof Promise&&(e=yield e),e&&this.readContiguousElements(e)}else if(s===Ri.Cluster){this.currentSegment.clusterSeekStartPos=t;break}if(void 0===a)break;r=o+a}if(this.currentSegment.seekEntries.sort((e,t)=>e.segmentPosition-t.segmentPosition),null!==this.reader.fileSize)for(const t of this.currentSegment.seekEntries){const i=pr.find(e=>e.id===t.id);if(!i)continue;if(this.currentSegment[i.flag])continue;let r=this.reader.requestSliceRange(e+t.segmentPosition,2,Li);if(r instanceof Promise&&(r=yield r),!r)continue;const n=Hi(r);if(!n)continue;const{id:s,size:a}=n;if(s!==i.id)continue;lr(a),this.currentSegment[i.flag]=!0;let o=this.reader.requestSlice(r.filePos,a);o instanceof Promise&&(o=yield o),o&&this.readContiguousElements(o)}-1===this.currentSegment.timestampScale&&(this.currentSegment.timestampScale=1e6,this.currentSegment.timestampFactor=1e3);for(const e of this.currentSegment.tracks)null!==e.defaultDurationNs&&(e.defaultDuration=this.currentSegment.timestampFactor*e.defaultDurationNs/1e9);const n=new Map(this.currentSegment.tracks.map(e=>[e.id,e]));for(const e of this.currentSegment.cuePoints){const t=n.get(e.trackId);t&&t.cuePoints.push(e)}for(const e of this.currentSegment.tracks){e.cuePoints.sort((e,t)=>e.time-t.time);for(let t=0;ta&&(a=e.cuePoints.length,s=e);for(const e of this.currentSegment.tracks)0===e.cuePoints.length&&(e.cuePoints=s.cuePoints);this.currentSegment=null})}readCluster(e,t){return d(this,null,function*(){var i;if((null==(i=t.lastReadCluster)?void 0:i.elementStartPos)===e)return t.lastReadCluster;let r=this.reader.requestSliceRange(e,2,Li);r instanceof Promise&&(r=yield r),y(r);const n=e,s=Hi(r);y(s);y(s.id===Ri.Cluster);let a=s.size;const o=r.filePos;if(void 0===a){a=(yield $i(this.reader,o,Oi,t.elementEndPos)).pos-o}let l=this.reader.requestSlice(o,a);l instanceof Promise&&(l=yield l);const c={segment:t,elementStartPos:n,elementEndPos:o+a,dataStartPos:o,timestamp:-1,trackData:new Map};if(this.currentCluster=c,l){const e=this.readContiguousElements(l,Oi);c.elementEndPos=e}for(const[,e]of c.trackData){const t=e.track;y(e.blocks.length>0);let i=!1;for(let n=0;n({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp);for(let n=0;n({timestamp:e.timestamp,blockIndex:t})).sort((e,t)=>e.timestamp-t.timestamp));const r=e.blocks[e.presentationTimestamps[0].blockIndex],s=e.blocks[T(e.presentationTimestamps).blockIndex];e.startTimestamp=r.timestamp,e.endTimestamp=s.timestamp+s.duration;const a=z(t.clusterPositionCache,e.startTimestamp,e=>e.startTimestamp);-1!==a&&t.clusterPositionCache[a].elementStartPos===n||t.clusterPositionCache.splice(a+1,0,{elementStartPos:c.elementStartPos,startTimestamp:e.startTimestamp})}return t.lastReadCluster=c,c})}getTrackDataInCluster(e,t){let i=e.trackData.get(t);if(!i){const r=e.segment.tracks.find(e=>e.id===t);if(!r)return null;i={track:r,startTimestamp:0,endTimestamp:0,firstKeyFrameTimestamp:null,blocks:[],presentationTimestamps:[]},e.trackData.set(t,i)}return i}expandLacedBlocks(e,t){var i;for(let r=0;r=2;){const i=e.filePos;if(!this.traverseElement(e,t))return i}return e.filePos}traverseElement(e,t){var i,r,n,s,a,o,l,d,h,f,m,p,g,k,T,S,v,w,P,I,x,C,E,A,R,D,M,N,O,L,z,U,q,W,V,H,K,j,X,$,G,Y,J,Z,te,ie,re,ne,se,ae,oe,le,ce,ue;const de=Hi(e);if(!de)return!1;if(t&&t.includes(de.id))return!1;const{id:he,size:fe}=de,me=e.filePos;switch(lr(fe),he){case Ri.DocType:this.isWebM="webm"===Ki(e,fe);break;case Ri.Seek:{if(!this.currentSegment)break;const t={id:-1,segmentPosition:-1};this.currentSegment.seekEntries.push(t),this.readContiguousElements(e.slice(me,fe)),-1!==t.id&&-1!==t.segmentPosition||this.currentSegment.seekEntries.pop()}break;case Ri.SeekID:{const t=null==(i=this.currentSegment)?void 0:i.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.id=qi(e,fe)}break;case Ri.SeekPosition:{const t=null==(r=this.currentSegment)?void 0:r.seekEntries[this.currentSegment.seekEntries.length-1];if(!t)break;t.segmentPosition=qi(e,fe)}break;case Ri.TimestampScale:if(!this.currentSegment)break;this.currentSegment.timestampScale=qi(e,fe),this.currentSegment.timestampFactor=1e9/this.currentSegment.timestampScale;break;case Ri.Duration:if(!this.currentSegment)break;this.currentSegment.duration=Xi(e,fe);break;case Ri.TrackEntry:if(!this.currentSegment)break;if(this.currentTrack={id:-1,segment:this.currentSegment,demuxer:this,clusterPositionCache:[],cuePoints:[],disposition:u(c({},Be),{primary:!1}),trackBacking:null,codecId:null,codecPrivate:null,defaultDuration:null,defaultDurationNs:null,name:null,languageCode:"eng",hasLanguageBcp47:!1,decodingInstructions:[],info:null},this.readContiguousElements(e.slice(me,fe)),!this.currentTrack)break;if(this.currentTrack.decodingInstructions.some(e=>{var t;return"decompress"!==(null==(t=e.data)?void 0:t.type)||e.scope!==dr.Block||e.data.algorithm!==fr.HeaderStripping})&&(console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`),this.currentTrack=null),this.currentTrack&&-1!==this.currentTrack.id&&this.currentTrack.codecId&&this.currentTrack.info){const e=this.currentTrack.codecId.indexOf("/"),t=-1===e?this.currentTrack.codecId:this.currentTrack.codecId.slice(0,e);if("video"===this.currentTrack.info.type&&-1!==this.currentTrack.info.width&&-1!==this.currentTrack.info.height){if(this.currentTrack.info.squarePixelWidth=this.currentTrack.info.width,this.currentTrack.info.squarePixelHeight=this.currentTrack.info.height,null!==this.currentTrack.info.displayWidth&&null!==this.currentTrack.info.displayHeight){const e=this.currentTrack.info.displayWidth*this.currentTrack.info.height,t=this.currentTrack.info.displayHeight*this.currentTrack.info.width;e>0&&t>0&&(e>t?this.currentTrack.info.squarePixelWidth=Math.round(this.currentTrack.info.width*e/t):this.currentTrack.info.squarePixelHeight=Math.round(this.currentTrack.info.height*t/e))}this.currentTrack.codecId===Gi?(this.currentTrack.info.codec="avc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===Yi?(this.currentTrack.info.codec="hevc",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===Ji?this.currentTrack.info.codec="vp8":t===Zi?this.currentTrack.info.codec="vp9":t===er&&(this.currentTrack.info.codec="av1");const e=this.currentTrack;this.currentTrack.trackBacking=new br(e),this.currentSegment.tracks.push(this.currentTrack)}else if("audio"===this.currentTrack.info.type){t===tr?(this.currentTrack.info.codec="aac",this.currentTrack.info.aacCodecInfo={isMpeg2:this.currentTrack.codecId.includes("MPEG2"),objectType:null},this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):this.currentTrack.codecId===ir?this.currentTrack.info.codec="mp3":t===rr?(this.currentTrack.info.codec="opus",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate,this.currentTrack.info.sampleRate=We):t===nr?(this.currentTrack.info.codec="vorbis",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===sr?(this.currentTrack.info.codec="flac",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===ar?(this.currentTrack.info.codec="ac3",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):t===or?(this.currentTrack.info.codec="eac3",this.currentTrack.info.codecDescription=this.currentTrack.codecPrivate):"A_PCM/INT/LIT"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32"):"A_PCM/INT/BIG"===this.currentTrack.codecId?8===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-u8":16===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s16be":24===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-s24be":32===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-s32be"):"A_PCM/FLOAT/IEEE"===this.currentTrack.codecId&&(32===this.currentTrack.info.bitDepth?this.currentTrack.info.codec="pcm-f32":64===this.currentTrack.info.bitDepth&&(this.currentTrack.info.codec="pcm-f64"));const e=this.currentTrack;this.currentTrack.trackBacking=new Tr(e),this.currentSegment.tracks.push(this.currentTrack)}}this.currentTrack=null;break;case Ri.TrackNumber:if(!this.currentTrack)break;this.currentTrack.id=qi(e,fe);break;case Ri.TrackType:{if(!this.currentTrack)break;const t=qi(e,fe);1===t?this.currentTrack.info={type:"video",width:-1,height:-1,displayWidth:null,displayHeight:null,displayUnit:null,squarePixelWidth:-1,squarePixelHeight:-1,rotation:0,codec:null,codecDescription:null,colorSpace:null,alphaMode:!1}:2===t&&(this.currentTrack.info={type:"audio",numberOfChannels:1,sampleRate:8e3,bitDepth:-1,codec:null,codecDescription:null,aacCodecInfo:null})}break;case Ri.FlagEnabled:if(!this.currentTrack)break;qi(e,fe)||(this.currentTrack=null);break;case Ri.FlagDefault:if(!this.currentTrack)break;this.currentTrack.disposition.default=!!qi(e,fe);break;case Ri.FlagForced:if(!this.currentTrack)break;this.currentTrack.disposition.forced=!!qi(e,fe);break;case Ri.FlagOriginal:if(!this.currentTrack)break;this.currentTrack.disposition.original=!!qi(e,fe);break;case Ri.FlagHearingImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.hearingImpaired=!!qi(e,fe);break;case Ri.FlagVisualImpaired:if(!this.currentTrack)break;this.currentTrack.disposition.visuallyImpaired=!!qi(e,fe);break;case Ri.FlagCommentary:if(!this.currentTrack)break;this.currentTrack.disposition.commentary=!!qi(e,fe);break;case Ri.CodecID:if(!this.currentTrack)break;this.currentTrack.codecId=Ki(e,fe);break;case Ri.CodecPrivate:if(!this.currentTrack)break;this.currentTrack.codecPrivate=xa(e,fe);break;case Ri.DefaultDuration:if(!this.currentTrack)break;this.currentTrack.defaultDurationNs=qi(e,fe);break;case Ri.Name:if(!this.currentTrack)break;this.currentTrack.name=ji(e,fe);break;case Ri.Language:if(!this.currentTrack)break;if(this.currentTrack.hasLanguageBcp47)break;this.currentTrack.languageCode=Ki(e,fe),ee(this.currentTrack.languageCode)||(this.currentTrack.languageCode=Q);break;case Ri.LanguageBCP47:{if(!this.currentTrack)break;const t=Ki(e,fe).split("-")[0];this.currentTrack.languageCode=t||Q,this.currentTrack.hasLanguageBcp47=!0}break;case Ri.Video:if("video"!==(null==(s=null==(n=this.currentTrack)?void 0:n.info)?void 0:s.type))break;this.readContiguousElements(e.slice(me,fe));break;case Ri.PixelWidth:if("video"!==(null==(o=null==(a=this.currentTrack)?void 0:a.info)?void 0:o.type))break;this.currentTrack.info.width=qi(e,fe);break;case Ri.PixelHeight:if("video"!==(null==(d=null==(l=this.currentTrack)?void 0:l.info)?void 0:d.type))break;this.currentTrack.info.height=qi(e,fe);break;case Ri.DisplayWidth:if("video"!==(null==(f=null==(h=this.currentTrack)?void 0:h.info)?void 0:f.type))break;this.currentTrack.info.displayWidth=qi(e,fe);break;case Ri.DisplayHeight:if("video"!==(null==(p=null==(m=this.currentTrack)?void 0:m.info)?void 0:p.type))break;this.currentTrack.info.displayHeight=qi(e,fe);break;case Ri.DisplayUnit:if("video"!==(null==(k=null==(g=this.currentTrack)?void 0:g.info)?void 0:k.type))break;this.currentTrack.info.displayUnit=qi(e,fe);break;case Ri.AlphaMode:if("video"!==(null==(S=null==(T=this.currentTrack)?void 0:T.info)?void 0:S.type))break;this.currentTrack.info.alphaMode=1===qi(e,fe);break;case Ri.Colour:if("video"!==(null==(w=null==(v=this.currentTrack)?void 0:v.info)?void 0:w.type))break;this.currentTrack.info.colorSpace={},this.readContiguousElements(e.slice(me,fe));break;case Ri.MatrixCoefficients:{if("video"!==(null==(I=null==(P=this.currentTrack)?void 0:P.info)?void 0:I.type)||!this.currentTrack.info.colorSpace)break;const t=qi(e,fe),i=null!=(x=F[t])?x:null;this.currentTrack.info.colorSpace.matrix=i}break;case Ri.Range:if("video"!==(null==(E=null==(C=this.currentTrack)?void 0:C.info)?void 0:E.type)||!this.currentTrack.info.colorSpace)break;this.currentTrack.info.colorSpace.fullRange=2===qi(e,fe);break;case Ri.TransferCharacteristics:{if("video"!==(null==(R=null==(A=this.currentTrack)?void 0:A.info)?void 0:R.type)||!this.currentTrack.info.colorSpace)break;const t=qi(e,fe),i=null!=(D=_[t])?D:null;this.currentTrack.info.colorSpace.transfer=i}break;case Ri.Primaries:{if("video"!==(null==(N=null==(M=this.currentTrack)?void 0:M.info)?void 0:N.type)||!this.currentTrack.info.colorSpace)break;const t=qi(e,fe),i=null!=(O=B[t])?O:null;this.currentTrack.info.colorSpace.primaries=i}break;case Ri.Projection:if("video"!==(null==(z=null==(L=this.currentTrack)?void 0:L.info)?void 0:z.type))break;this.readContiguousElements(e.slice(me,fe));break;case Ri.ProjectionPoseRoll:{if("video"!==(null==(q=null==(U=this.currentTrack)?void 0:U.info)?void 0:q.type))break;const t=-Xi(e,fe);try{this.currentTrack.info.rotation=b(t)}catch(pe){}}break;case Ri.Audio:if("audio"!==(null==(V=null==(W=this.currentTrack)?void 0:W.info)?void 0:V.type))break;this.readContiguousElements(e.slice(me,fe));break;case Ri.SamplingFrequency:if("audio"!==(null==(K=null==(H=this.currentTrack)?void 0:H.info)?void 0:K.type))break;this.currentTrack.info.sampleRate=Xi(e,fe);break;case Ri.Channels:if("audio"!==(null==(X=null==(j=this.currentTrack)?void 0:j.info)?void 0:X.type))break;this.currentTrack.info.numberOfChannels=qi(e,fe);break;case Ri.BitDepth:if("audio"!==(null==(G=null==($=this.currentTrack)?void 0:$.info)?void 0:G.type))break;this.currentTrack.info.bitDepth=qi(e,fe);break;case Ri.CuePoint:if(!this.currentSegment)break;this.readContiguousElements(e.slice(me,fe)),this.currentCueTime=null;break;case Ri.CueTime:this.currentCueTime=qi(e,fe);break;case Ri.CueTrackPositions:{if(null===this.currentCueTime)break;y(this.currentSegment);const t={time:this.currentCueTime,trackId:-1,clusterPosition:-1};this.currentSegment.cuePoints.push(t),this.readContiguousElements(e.slice(me,fe)),-1!==t.trackId&&-1!==t.clusterPosition||this.currentSegment.cuePoints.pop()}break;case Ri.CueTrack:{const t=null==(Y=this.currentSegment)?void 0:Y.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;t.trackId=qi(e,fe)}break;case Ri.CueClusterPosition:{const t=null==(J=this.currentSegment)?void 0:J.cuePoints[this.currentSegment.cuePoints.length-1];if(!t)break;y(this.currentSegment),t.clusterPosition=this.currentSegment.dataStartPos+qi(e,fe)}break;case Ri.Timestamp:if(!this.currentCluster)break;this.currentCluster.timestamp=qi(e,fe);break;case Ri.SimpleBlock:{if(!this.currentCluster)break;const t=Ui(e);if(null===t)break;const i=this.getTrackDataInCluster(this.currentCluster,t);if(!i)break;const r=Aa(e),n=Ca(e),s=n>>1&3;let a=!!(128&n);"audio"===(null==(Z=i.track.info)?void 0:Z.type)&&i.track.info.codec&&(a=!0);const o=xa(e,fe-(e.filePos-me)),l=i.track.decodingInstructions.length>0;i.blocks.push({timestamp:r,duration:0,isKeyFrame:a,data:o,lacing:s,decoded:!l,mainAdditional:null})}break;case Ri.BlockGroup:if(!this.currentCluster)break;this.readContiguousElements(e.slice(me,fe)),this.currentBlock=null;break;case Ri.Block:{if(!this.currentCluster)break;const t=Ui(e);if(null===t)break;const i=this.getTrackDataInCluster(this.currentCluster,t);if(!i)break;const r=Aa(e),n=Ca(e)>>1&3,s=xa(e,fe-(e.filePos-me)),a=i.track.decodingInstructions.length>0;this.currentBlock={timestamp:r,duration:0,isKeyFrame:!0,data:s,lacing:n,decoded:!a,mainAdditional:null},i.blocks.push(this.currentBlock)}break;case Ri.BlockAdditions:this.readContiguousElements(e.slice(me,fe));break;case Ri.BlockMore:if(!this.currentBlock)break;this.currentBlockAdditional={addId:1,data:null},this.readContiguousElements(e.slice(me,fe)),this.currentBlockAdditional.data&&1===this.currentBlockAdditional.addId&&(this.currentBlock.mainAdditional=this.currentBlockAdditional.data),this.currentBlockAdditional=null;break;case Ri.BlockAdditional:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.data=xa(e,fe);break;case Ri.BlockAddID:if(!this.currentBlockAdditional)break;this.currentBlockAdditional.addId=qi(e,fe);break;case Ri.BlockDuration:if(!this.currentBlock)break;this.currentBlock.duration=qi(e,fe);break;case Ri.ReferenceBlock:if(!this.currentBlock)break;this.currentBlock.isKeyFrame=!1;break;case Ri.Tag:this.currentTagTargetIsMovie=!0,this.readContiguousElements(e.slice(me,fe));break;case Ri.Targets:this.readContiguousElements(e.slice(me,fe));break;case Ri.TargetTypeValue:50!==qi(e,fe)&&(this.currentTagTargetIsMovie=!1);break;case Ri.TagTrackUID:case Ri.TagEditionUID:case Ri.TagChapterUID:case Ri.TagAttachmentUID:this.currentTagTargetIsMovie=!1;break;case Ri.SimpleTag:if(!this.currentTagTargetIsMovie)break;this.currentSimpleTagName=null,this.readContiguousElements(e.slice(me,fe));break;case Ri.TagName:this.currentSimpleTagName=ji(e,fe);break;case Ri.TagString:{if(!this.currentSimpleTagName)break;const t=ji(e,fe);this.processTagValue(this.currentSimpleTagName,t)}break;case Ri.TagBinary:{if(!this.currentSimpleTagName)break;const t=xa(e,fe);this.processTagValue(this.currentSimpleTagName,t)}break;case Ri.AttachedFile:{if(!this.currentSegment)break;this.currentAttachedFile={fileUid:null,fileName:null,fileMediaType:null,fileData:null,fileDescription:null},this.readContiguousElements(e.slice(me,fe));const t=this.currentSegment.metadataTags;if(this.currentAttachedFile.fileUid&&this.currentAttachedFile.fileData&&(null!=t.raw||(t.raw={}),t.raw[this.currentAttachedFile.fileUid.toString()]=new Ce(this.currentAttachedFile.fileData,null!=(te=this.currentAttachedFile.fileMediaType)?te:void 0,null!=(ie=this.currentAttachedFile.fileName)?ie:void 0,null!=(re=this.currentAttachedFile.fileDescription)?re:void 0)),(null==(ne=this.currentAttachedFile.fileMediaType)?void 0:ne.startsWith("image/"))&&this.currentAttachedFile.fileData){const e=this.currentAttachedFile.fileName;let i="unknown";if(e){const t=e.toLowerCase();t.startsWith("cover.")?i="coverFront":t.startsWith("back.")&&(i="coverBack")}null!=t.images||(t.images=[]),t.images.push({data:this.currentAttachedFile.fileData,mimeType:this.currentAttachedFile.fileMediaType,kind:i,name:null!=(se=this.currentAttachedFile.fileName)?se:void 0,description:null!=(ae=this.currentAttachedFile.fileDescription)?ae:void 0})}this.currentAttachedFile=null}break;case Ri.FileUID:if(!this.currentAttachedFile)break;this.currentAttachedFile.fileUid=((e,t)=>{if(t<1)throw new Error("Bad unsigned int size "+t);let i=BigInt("0");for(let r=0;rt.order-e.order);break;case Ri.ContentEncoding:this.currentDecodingInstruction={order:0,scope:dr.Block,data:null},this.readContiguousElements(e.slice(me,fe)),this.currentDecodingInstruction.data&&this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction),this.currentDecodingInstruction=null;break;case Ri.ContentEncodingOrder:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.order=qi(e,fe);break;case Ri.ContentEncodingScope:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.scope=qi(e,fe);break;case Ri.ContentCompression:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decompress",algorithm:fr.Zlib,settings:null},this.readContiguousElements(e.slice(me,fe));break;case Ri.ContentCompAlgo:if("decompress"!==(null==(le=null==(oe=this.currentDecodingInstruction)?void 0:oe.data)?void 0:le.type))break;this.currentDecodingInstruction.data.algorithm=qi(e,fe);break;case Ri.ContentCompSettings:if("decompress"!==(null==(ue=null==(ce=this.currentDecodingInstruction)?void 0:ce.data)?void 0:ue.type))break;this.currentDecodingInstruction.data.settings=xa(e,fe);break;case Ri.ContentEncryption:if(!this.currentDecodingInstruction)break;this.currentDecodingInstruction.data={type:"decrypt"}}return e.filePos=me+fe,!0}decodeBlockData(e,t){y(e.decodingInstructions.length>0);let i=t;for(const r of e.decodingInstructions)if(y(r.data),"decompress"===r.data.type)if(r.data.algorithm===fr.HeaderStripping)if(r.data.settings&&r.data.settings.length>0){const e=r.data.settings,t=new Uint8Array(e.length+i.length);t.set(e,0),t.set(i,e.length),i=t}return i}processTagValue(e,t){var i,r;if(!(null==(i=this.currentSegment)?void 0:i.metadataTags))return;const n=this.currentSegment.metadataTags;if(null!=n.raw||(n.raw={}),null!=(r=n.raw)[e]||(r[e]=t),"string"===typeof t)switch(e.toLowerCase()){case"title":null!=n.title||(n.title=t);break;case"description":null!=n.description||(n.description=t);break;case"artist":null!=n.artist||(n.artist=t);break;case"album":null!=n.album||(n.album=t);break;case"album_artist":null!=n.albumArtist||(n.albumArtist=t);break;case"genre":null!=n.genre||(n.genre=t);break;case"comment":null!=n.comment||(n.comment=t);break;case"lyrics":null!=n.lyrics||(n.lyrics=t);break;case"date":{const e=new Date(t);Number.isNaN(e.getTime())||null!=n.date||(n.date=e)}break;case"track_number":case"part_number":{const e=t.split("/"),i=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(null!=n.trackNumber||(n.trackNumber=i)),r&&Number.isInteger(r)&&r>0&&(null!=n.tracksTotal||(n.tracksTotal=r))}break;case"disc_number":case"disc":{const e=t.split("/"),i=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(i)&&i>0&&(null!=n.discNumber||(n.discNumber=i)),r&&Number.isInteger(r)&&r>0&&(null!=n.discsTotal||(n.discsTotal=r))}}}}class yr{constructor(e){this.internalTrack=e,this.packetToClusterLocation=new WeakMap}getId(){return this.internalTrack.id}getNumber(){const e=this.internalTrack.demuxer,t=this.internalTrack.trackBacking.getType();let i=0;for(const r of e.segments)for(const e of r.tracks)if(e.trackBacking.getType()===t&&i++,e===this.internalTrack)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.internalTrack.codecId}getName(){return this.internalTrack.name}getLanguageCode(){return this.internalTrack.languageCode}getTimeResolution(){return this.internalTrack.segment.timestampFactor}isRelativeToUnixEpoch(){return!1}getDisposition(){return this.internalTrack.disposition}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){var e;const t=this.internalTrack.segment;if(t.duration<=0)return null;let i=t.duration/t.timestampFactor;const r=yield this.getFirstPacket({metadataOnly:!0});return i+=null!=(e=null==r?void 0:r.timestamp)?e:0,i})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getFirstPacket(e){return d(this,null,function*(){return this.performClusterLookup(null,e=>e.trackData.get(this.internalTrack.id)?{blockIndex:0,correctBlockFound:!0}:{blockIndex:-1,correctBlockFound:!1},-1/0,1/0,e)})}intoTimescale(e){return G(e*this.internalTrack.segment.timestampFactor)}getPacket(e,t){return d(this,null,function*(){const i=this.intoTimescale(e);return this.performClusterLookup(null,e=>{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const r=z(t.presentationTimestamps,i,e=>e.timestamp);return{blockIndex:-1!==r?t.presentationTimestamps[r].blockIndex:-1,correctBlockFound:-1!==r&&i{if(e===i.cluster){const t=e.trackData.get(this.internalTrack.id);if(i.blockIndex+1{const t=e.trackData.get(this.internalTrack.id);if(!t)return{blockIndex:-1,correctBlockFound:!1};const r=V(t.presentationTimestamps,e=>t.blocks[e.blockIndex].isKeyFrame&&e.timestamp<=i);return{blockIndex:-1!==r?t.presentationTimestamps[r].blockIndex:-1,correctBlockFound:-1!==r&&i{if(e===i.cluster){const t=e.trackData.get(this.internalTrack.id).blocks.findIndex((e,t)=>e.isKeyFrame&&t>i.blockIndex);if(-1!==t)return{blockIndex:t,correctBlockFound:!0}}else{const t=e.trackData.get(this.internalTrack.id);if(t&&null!==t.firstKeyFrameTimestamp){const e=t.blocks.findIndex(e=>e.isKeyFrame);return y(-1!==e),{blockIndex:e,correctBlockFound:!0}}}return{blockIndex:-1,correctBlockFound:!1}},-1/0,1/0,t)})}fetchPacketInCluster(e,t,i){return d(this,null,function*(){var r;if(-1===t)return null;const n=e.trackData.get(this.internalTrack.id).blocks[t];y(n),n.decoded||(n.data=this.internalTrack.demuxer.decodeBlockData(this.internalTrack,n.data),n.decoded=!0);const s=i.metadataOnly?Gt:n.data,a=n.timestamp/this.internalTrack.segment.timestampFactor,o=n.duration/this.internalTrack.segment.timestampFactor,l={};n.mainAdditional&&"video"===(null==(r=this.internalTrack.info)?void 0:r.type)&&this.internalTrack.info.alphaMode&&(l.alpha=i.metadataOnly?Gt:n.mainAdditional,l.alphaByteLength=n.mainAdditional.byteLength);const c=new Yt(s,n.isKeyFrame?"key":"delta",a,o,e.dataStartPos+t,n.data.byteLength,l);return this.packetToClusterLocation.set(c,{cluster:e,blockIndex:t}),c})}performClusterLookup(e,t,i,r,n){return d(this,null,function*(){var s,a,o,l;const{demuxer:c,segment:u}=this.internalTrack;let d=null,h=null,f=-1;if(e){const{blockIndex:i,correctBlockFound:r}=t(e);if(r)return this.fetchPacketInCluster(e,i,n);-1!==i&&(h=e,f=i)}const m=z(this.internalTrack.cuePoints,i,e=>e.time),p=-1!==m?this.internalTrack.cuePoints[m]:null,g=z(this.internalTrack.clusterPositionCache,i,e=>e.startTimestamp),k=-1!==g?this.internalTrack.clusterPositionCache[g]:null,b=Math.max(null!=(s=null==p?void 0:p.clusterPosition)?s:0,null!=(a=null==k?void 0:k.elementStartPos)?a:0)||null;let T;for(e?null===b||e.elementStartPos>=b?(T=e.elementEndPos,d=e):T=b:T=null!=b?b:u.clusterSeekStartPos;null===u.elementEndPos||T<=u.elementEndPos-2;){if(d){const e=d.trackData.get(this.internalTrack.id);if(e&&e.startTimestamp>r)break}let e=c.reader.requestSliceRange(T,2,Li);if(e instanceof Promise&&(e=yield e),!e)break;const i=T,s=Hi(e);if(!s||!Ni.includes(s.id)&&s.id!==Ri.Void){const e=yield Qi(c.reader,i,Ni,Math.min(null!=(o=u.elementEndPos)?o:1/0,i+gr));if(e){T=e;continue}break}const a=s.id;let l=s.size;const m=e.filePos;if(a===Ri.Cluster){d=yield c.readCluster(i,u),l=d.elementEndPos-m;const{blockIndex:e,correctBlockFound:r}=t(d);if(r)return this.fetchPacketInCluster(d,e,n);-1!==e&&(h=d,f=e)}if(void 0===l){y(a!==Ri.Cluster);l=(yield $i(c.reader,m,Oi,u.elementEndPos)).pos-m}const p=m+l;if(null===u.elementEndPos){let e=c.reader.requestSliceRange(p,2,Li);if(e instanceof Promise&&(e=yield e),!e)break;if(Wi(e)===Ri.Segment){u.elementEndPos=p;break}}T=p}if(p&&(!h||h.elementStartPosd(this,null,function*(){var e,t;let i=null;("vp9"===this.internalTrack.info.codec||"av1"===this.internalTrack.info.codec||"avc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription||"hevc"===this.internalTrack.info.codec&&!this.internalTrack.info.codecDescription)&&(i=yield this.getFirstPacket({}));const r={codec:Ue({width:this.internalTrack.info.width,height:this.internalTrack.info.height,codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,colorSpace:this.internalTrack.info.colorSpace,avcType:1,avcCodecInfo:"avc"===this.internalTrack.info.codec&&i?pt(i.data):null,hevcCodecInfo:"hevc"===this.internalTrack.info.codec&&i?vt(i.data):null,vp9CodecInfo:"vp9"===this.internalTrack.info.codec&&i?Rt(i.data):null,av1CodecInfo:"av1"===this.internalTrack.info.codec&&i?Mt(i.data):null}),codedWidth:this.internalTrack.info.width,codedHeight:this.internalTrack.info.height,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0,colorSpace:null!=(t=this.internalTrack.info.colorSpace)?t:void 0};return this.internalTrack.info.width===this.internalTrack.info.squarePixelWidth&&this.internalTrack.info.height===this.internalTrack.info.squarePixelHeight||(r.displayAspectWidth=this.internalTrack.info.squarePixelWidth,r.displayAspectHeight=this.internalTrack.info.squarePixelHeight),r}))():null})}}class Tr extends yr{constructor(e){super(e),this.decoderConfig=null,this.internalTrack=e}getType(){return"audio"}getCodec(){return this.internalTrack.info.codec}getNumberOfChannels(){return this.internalTrack.info.numberOfChannels}getSampleRate(){return this.internalTrack.info.sampleRate}getDecoderConfig(){return d(this,null,function*(){var e,t;return this.internalTrack.info.codec?null!=(t=this.decoderConfig)?t:this.decoderConfig={codec:qe({codec:this.internalTrack.info.codec,codecDescription:this.internalTrack.info.codecDescription,aacCodecInfo:this.internalTrack.info.aacCodecInfo}),numberOfChannels:this.internalTrack.info.numberOfChannels,sampleRate:this.internalTrack.info.sampleRate,description:null!=(e=this.internalTrack.info.codecDescription)?e:void 0}:null})}}const Sr=(e,t,i)=>d(null,null,function*(){const r=o(2,16);let n=t;for(;null===i||n=4;){const t=s.filePos,i=Ra(s),r=null!==e.fileSize?e.fileSize-n:null,a=Ye(i,r);if(a.header)return{header:a.header,startPos:n};s.filePos=t+a.bytesAdvanced,n=s.filePos}}return null});class vr extends Qt{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.firstFrameHeaderPos=null,this.loadedSamples=[],this.metadataTags=null,this.xingData=null,this.trackBackings=[],this.readingMutex=new D,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}readMetadata(){return d(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)yield this.advanceReader();if(!this.firstFrameHeader)throw new Error("No valid MP3 frame found.");this.trackBackings=[new wr(this)]}))()})}advanceReader(){return d(this,null,function*(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,Qa);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=Za(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}const e=yield Sr(this.reader,this.lastLoadedPos,this.reader.fileSize);if(!e)return void(this.lastSampleLoaded=!0);const t=e.header;this.lastLoadedPos=e.startPos+t.totalSize-1;const i=Ge(t.mpegVersionId,t.channel);let r=this.reader.requestSlice(e.startPos+i,4);if(r instanceof Promise&&(r=yield r),r){const t=Ra(r);if(t===$e||t===Qe){if(!this.xingData){let t=this.reader.requestSlice(e.startPos+i+4,12);if(t instanceof Promise&&(t=yield t),t){const e=xa(t,12),i=P(e),r=i.getUint32(0,!1);this.xingData={frameCount:r&Ze.FrameCount?i.getUint32(4,!1):null,fileSize:r&Ze.FileSize?i.getUint32(8,!1):null}}}return}}this.firstFrameHeader||(this.firstFrameHeader=t,this.firstFrameHeaderPos=e.startPos),t.sampleRate!==this.firstFrameHeader.sampleRate&&console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${t.sampleRate} Hz. Might be a bug, so please report this file.`);const n=t.audioSamplesInFrame/this.firstFrameHeader.sampleRate,s={timestamp:this.nextTimestampInSamples/this.firstFrameHeader.sampleRate,duration:n,dataStart:e.startPos,dataSize:t.totalSize};this.loadedSamples.push(s),this.nextTimestampInSamples+=t.audioSamplesInFrame})}getMimeType(){return d(this,null,function*(){return"audio/mpeg"})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackings})}getMetadataTags(){return d(this,null,function*(){const e=yield this.readingMutex.acquire();try{if(yield this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0,t=!1;for(;;){let i=this.reader.requestSlice(e,Qa);if(i instanceof Promise&&(i=yield i),!i)break;const r=Za(i);if(!r)break;t=!0;let n=this.reader.requestSlice(i.filePos,r.size);if(n instanceof Promise&&(n=yield n),!n)break;eo(n,r,this.metadataTags),e=i.filePos+r.size}if(!t&&null!==this.reader.fileSize&&this.reader.fileSize>=$a){let e=this.reader.requestSlice(this.reader.fileSize-$a,$a);e instanceof Promise&&(e=yield e),y(e);"TAG"===Wa(e,3)&&Ya(e,this.metadataTags)}return this.metadataTags}finally{e()}})}}class wr{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getTimeResolution(){return y(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.sampleRate/this.demuxer.firstFrameHeader.audioSamplesInFrame}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){const e=this.demuxer;if(y(null!==e.firstFrameHeader),y(null!==e.firstFrameHeaderPos),e.xingData){if(null!==e.xingData.frameCount)return e.xingData.frameCount*e.firstFrameHeader.audioSamplesInFrame/e.firstFrameHeader.sampleRate}else if(null!==e.reader.fileSize){const s=(t=e.firstFrameHeader.lowSamplingFrequency,i=e.firstFrameHeader.layer,r=e.firstFrameHeader.bitrate,n=e.firstFrameHeader.sampleRate,0===i?0:1===i?144*r/(n<e.timestamp);if(-1===i)throw new Error("Packet was not created from this track.");const r=i+1;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{i()}})}getPacket(e,t){return d(this,null,function*(){const i=yield this.demuxer.readingMutex.acquire();try{for(;;){const i=z(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===i&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(i,t);if(i>=0&&i+1>>0&4294967295}const xr=e=>{const t=P(e),i=t.getUint32(22,!0);t.setUint32(22,0,!0);let r=0;for(let n=0;n>>24^t])>>>0}return t.setUint32(22,i,!0),r},Cr=(e,t,i)=>{let r=0,n=null;if(e.length>0)if("vorbis"===t.codec){y(t.vorbisInfo);const s=(1<<(e=>{let t=0;for(;e;)t++,e>>=1;return t})(t.vorbisInfo.modeBlockflags.length-1))-1<<1,a=(e[0]&s)>>1;if(a>=t.vorbisInfo.modeBlockflags.length)throw new Error("Invalid mode number.");let o=i;const l=t.vorbisInfo.modeBlockflags[a];if(n=t.vorbisInfo.blocksizes[l],1===l){const i=1+(1|s),r=e[0]&i?1:0;o=t.vorbisInfo.blocksizes[r]}r=null!==o?o+n>>2:0}else if("opus"===t.codec){r=(e=>{const t=e[0]>>3;return{durationInSamples:Nt[t]}})(e).durationInSamples}return{durationInSamples:r,vorbisBlockSize:n}},Br=27,Er=282,_r=e=>{const t=e.filePos;if(Da(e)!==Pr)return null;e.skip(1);const i=Ca(e),r=za(e),n=Da(e),s=Da(e),a=Da(e),o=Ca(e),l=new Uint8Array(o);for(let d=0;de+t,0);return{headerStartPos:t,totalSize:c+u,dataStartPos:t+c,dataSize:u,headerType:i,granulePosition:r,serialNumber:n,sequenceNumber:s,checksum:a,lacingValues:l}},Ar=(e,t)=>{for(;e.filePos>>8&255)===i||(t>>>16&255)===i||(t>>>24&255)===i){if(e.skip(-4),t===Pr)return!0;e.skip(1)}}return!1};class Fr extends Qt{constructor(e){super(e),this.metadataPromise=null,this.bitstreams=[],this.trackBackings=[],this.metadataTags={},this.reader=e._reader}readMetadata(){return d(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){let e=0;for(;;){let t=this.reader.requestSliceRange(e,Br,Er);if(t instanceof Promise&&(t=yield t),!t)break;const i=_r(t);if(!i)break;if(!!!(2&i.headerType))break;this.bitstreams.push({serialNumber:i.serialNumber,bosPage:i,description:null,numberOfChannels:-1,sampleRate:-1,codecInfo:{codec:null,vorbisInfo:null,opusInfo:null},lastMetadataPacket:null}),e=i.headerStartPos+i.totalSize}for(const t of this.bitstreams){const e=yield this.readPacket(t.bosPage,0);e&&(e.data.byteLength>=7&&1===e.data[0]&&118===e.data[1]&&111===e.data[2]&&114===e.data[3]&&98===e.data[4]&&105===e.data[5]&&115===e.data[6]?yield this.readVorbisMetadata(e,t):e.data.byteLength>=8&&79===e.data[0]&&112===e.data[1]&&117===e.data[2]&&115===e.data[3]&&72===e.data[4]&&101===e.data[5]&&97===e.data[6]&&100===e.data[7]&&(yield this.readOpusMetadata(e,t)),null!==t.codecInfo.codec&&this.trackBackings.push(new Rr(t,this)))}}))()})}readVorbisMetadata(e,t){return d(this,null,function*(){let i=yield this.findNextPacketStart(e);if(!i)return;const r=yield this.readPacket(i.startPage,i.startSegmentIndex);if(!r)return;if(i=yield this.findNextPacketStart(r),!i)return;const n=yield this.readPacket(i.startPage,i.startSegmentIndex);if(!n)return;if(3!==r.data[0]||5!==n.data[0])return;const s=[],a=e=>{for(;s.push(Math.min(255,e)),!(e<255);)e-=255};a(e.data.length),a(r.data.length);const o=new Uint8Array(1+s.length+e.data.length+r.data.length+n.data.length);o[0]=2,o.set(s,1),o.set(e.data,1+s.length),o.set(r.data,1+s.length+e.data.length),o.set(n.data,1+s.length+e.data.length+r.data.length),t.codecInfo.codec="vorbis",t.description=o,t.lastMetadataPacket=n;const l=P(e.data);t.numberOfChannels=l.getUint8(11),t.sampleRate=l.getUint32(12,!0);const c=l.getUint8(28);t.codecInfo.vorbisInfo={blocksizes:[1<<(15&c),1<<(c>>4)],modeBlockflags:Ot(n.data).modeBlockflags},qt(r.data.subarray(7),this.metadataTags)})}readOpusMetadata(e,t){return d(this,null,function*(){const i=yield this.findNextPacketStart(e);if(!i)return;const r=yield this.readPacket(i.startPage,i.startSegmentIndex);if(!r)return;t.codecInfo.codec="opus",t.description=e.data,t.lastMetadataPacket=r;const n=(e=>{const t=P(e),i=t.getUint8(9),r=t.getUint16(10,!0),n=t.getUint32(12,!0),s=t.getInt16(16,!0),a=t.getUint8(18);let o=null;return a&&(o=e.subarray(19,21+i)),{outputChannelCount:i,preSkip:r,inputSampleRate:n,outputGain:s,channelMappingFamily:a,channelMappingTable:o}})(e.data);t.numberOfChannels=n.outputChannelCount,t.sampleRate=We,t.codecInfo.opusInfo={preSkip:n.preSkip},qt(r.data.subarray(8),this.metadataTags)})}readPacket(e,t){return d(this,null,function*(){y(te+t.length,0);if(0===o)return null;const l=new Uint8Array(o);let c=0;for(let e=0;e{let t="audio/ogg";e.codecStrings&&(t+=`; codecs="${[...new Set(e.codecStrings)].join(", ")}"`);return t})({codecStrings:(yield Promise.all(this.trackBackings.map(e=>e.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null})))).filter(Boolean)})})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackings})}getMetadataTags(){return d(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}}class Rr{constructor(e,t){this.bitstream=e,this.demuxer=t,this.encodedPacketToMetadata=new WeakMap,this.sequentialScanCache=[],this.sequentialScanMutex=new D,this.internalSampleRate="opus"===e.codecInfo.codec?We:e.sampleRate}getType(){return"audio"}getId(){return this.bitstream.serialNumber}getNumber(){const e=this.demuxer.trackBackings.findIndex(e=>e.bitstream===this.bitstream);return y(-1!==e),e+1}getNumberOfChannels(){return this.bitstream.numberOfChannels}getSampleRate(){return this.bitstream.sampleRate}getTimeResolution(){return this.bitstream.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return null})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getCodec(){return this.bitstream.codecInfo.codec}getInternalCodecId(){return null}getDecoderConfig(){return d(this,null,function*(){var e;return y(this.bitstream.codecInfo.codec),{codec:this.bitstream.codecInfo.codec,numberOfChannels:this.bitstream.numberOfChannels,sampleRate:this.bitstream.sampleRate,description:null!=(e=this.bitstream.description)?e:void 0}})}getName(){return null}getLanguageCode(){return Q}getDisposition(){return u(c({},Be),{primary:!1})}granulePositionToTimestampInSamples(e){return"opus"===this.bitstream.codecInfo.codec?(y(this.bitstream.codecInfo.opusInfo),e-this.bitstream.codecInfo.opusInfo.preSkip):e}createEncodedPacketFromOggPacket(e,t,i){if(!e)return null;const{durationInSamples:r,vorbisBlockSize:n}=Cr(e.data,this.bitstream.codecInfo,t.vorbisLastBlocksize),s=new Yt(i.metadataOnly?Gt:e.data,"key",Math.max(0,t.timestampInSamples)/this.internalSampleRate,r/this.internalSampleRate,e.endPage.headerStartPos+e.endSegmentIndex,e.data.byteLength);return this.encodedPacketToMetadata.set(s,{packet:e,timestampInSamples:t.timestampInSamples,durationInSamples:r,vorbisLastBlockSize:t.vorbisLastBlocksize,vorbisBlockSize:n}),s}getFirstPacket(e){return d(this,null,function*(){y(this.bitstream.lastMetadataPacket);const t=yield this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!t)return null;let i=0;"opus"===this.bitstream.codecInfo.codec&&(y(this.bitstream.codecInfo.opusInfo),i-=this.bitstream.codecInfo.opusInfo.preSkip);const r=yield this.demuxer.readPacket(t.startPage,t.startSegmentIndex);return this.createEncodedPacketFromOggPacket(r,{timestampInSamples:i,vorbisLastBlocksize:null},e)})}getNextPacket(e,t){return d(this,null,function*(){const i=this.encodedPacketToMetadata.get(e);if(!i)throw new Error("Packet was not created from this track.");const r=yield this.demuxer.findNextPacketStart(i.packet);if(!r)return null;const n=i.timestampInSamples+i.durationInSamples,s=yield this.demuxer.readPacket(r.startPage,r.startSegmentIndex);return this.createEncodedPacketFromOggPacket(s,{timestampInSamples:n,vorbisLastBlocksize:i.vorbisBlockSize},t)})}getPacket(e,t){return d(this,null,function*(){var i,r;if(null===this.demuxer.reader.fileSize)return this.getPacketSequential(e,t);const n=G(e*this.internalSampleRate);if(0===n)return this.getFirstPacket(t);if(n<0)return null;y(this.bitstream.lastMetadataPacket);const s=yield this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket);if(!s)return null;let a=s.startPage,o=this.demuxer.reader.fileSize;const l=[a];e:for(;a.headerStartPos+a.totalSizen?o=c.headerStartPos:(a=c,l.push(c));continue e}i=c.headerStartPos+c.totalSize}}let c=s.startPage;for(const e of l){if(e.granulePosition===a.granulePosition)break;(!c||e.headerStartPos>c.headerStartPos)&&(c=e)}let u=c;const d=[u];for(;u.serialNumber!==this.bitstream.serialNumber||u.granulePosition!==a.granulePosition;){const e=u.headerStartPos+u.totalSize;let t=this.demuxer.reader.requestSliceRange(e,Br,Er);t instanceof Promise&&(t=yield t),y(t);const i=_r(t);y(i),u=i,u.serialNumber===this.bitstream.serialNumber&&d.push(u)}y(-1!==u.granulePosition);let h,f,m=null,p=u,g=0;if(u.headerStartPos===s.startPage.headerStartPos)h=this.granulePositionToTimestampInSamples(0),f=!0,m=0;else{h=0,f=!1;for(let t=u.lacingValues.length-1;t>=0;t--){if(u.lacingValues[t]<255){m=t+1;break}}if(null===m)throw new Error("Invalid page with granule position: no packets end on this page.");g=m-1;const e={data:Gt,endPage:p,endSegmentIndex:g};if(yield this.demuxer.findNextPacketStart(e)){const e=Mr(d,u,m);y(e);const t=Dr(d,e.page,e.segmentIndex);t&&(u=t.page,m=t.segmentIndex)}else for(;;){const e=Mr(d,u,m);if(!e)break;const t=Dr(d,e.page,e.segmentIndex);if(!t)break;if(u=t.page,m=t.segmentIndex,e.page.headerStartPos!==p.headerStartPos){p=e.page,g=e.segmentIndex;break}}}let k=null,b=null;for(;null!==u;){y(null!==m);const e=yield this.demuxer.readPacket(u,m);if(!e)break;if(!(u.headerStartPos===s.startPage.headerStartPos&&mn||Math.max(a.timestampInSamples,0)===n))break}const a=yield this.demuxer.findNextPacketStart(e);if(!a)break;u=a.startPage,m=a.startSegmentIndex}return k})}getPacketSequential(e,t){return d(this,null,function*(){const i=yield this.sequentialScanMutex.acquire();try{const i=G(e*this.internalSampleRate);e=i/this.internalSampleRate;const r=z(this.sequentialScanCache,i,e=>e.timestampInSamples);let n;if(-1!==r){const e=this.sequentialScanCache[r];n=this.createEncodedPacketFromOggPacket(e.packet,{timestampInSamples:e.timestampInSamples,vorbisLastBlocksize:e.vorbisLastBlockSize},t)}else n=yield this.getFirstPacket(t);let s=0;for(;n&&n.timestampe)break;if(n=i,s++,100===s){s=0;const e=this.encodedPacketToMetadata.get(n);y(e),this.sequentialScanCache.length>0&&y(T(this.sequentialScanCache).timestampInSamples<=e.timestampInSamples),this.sequentialScanCache.push(e)}}return n}finally{i()}})}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const Dr=(e,t,i)=>{let r=t,n=i;e:for(;;){for(n--;n>=0;n--){if(r.lacingValues[n]<255){n++;break e}}y(-1===n);if(!(1&r.headerType)){n=0;break}const t=W(e,e=>e.headerStartPos{if(i>0)return{page:t,segmentIndex:i-1};const r=W(e,e=>e.headerStartPosd(this,null,function*(){var e,t;let i=this.reader.requestSlice(0,12);i instanceof Promise&&(i=yield i),y(i);const r=Wa(i,4),n="RIFX"!==r,s="RF64"===r,a=Fa(i,n);let o=s?this.reader.fileSize:Math.min(a+8,null!=(e=this.reader.fileSize)?e:1/0);if("WAVE"!==Wa(i,4))throw new Error("Invalid WAVE file - wrong format");let l=0,c=null,u=i.filePos;for(;null===o||u=18&&357!==n){const e=Ba(r,i),s=t-18;if(Math.min(s,e)>=22&&n===Nr.EXTENSIBLE){r.skip(6);const e=xa(r,16);n=e[0]|e[1]<<8}}n!==Nr.MULAW&&n!==Nr.ALAW||(l=8),this.audioInfo={format:n,numberOfChannels:s,sampleRate:a,sampleSizeInBytes:Math.ceil(l/8),blockSizeInBytes:o}})}parseListChunk(e,t,i){return d(this,null,function*(){var r,n,s,a,o,l,c,u,d,h,f;let m=this.reader.requestSlice(e,t);if(m instanceof Promise&&(m=yield m),!m)return;const p=Wa(m,4);if("INFO"!==p&&"INF0"!==p)return;let g=m.filePos;for(;g<=e+t-8;){m.filePos=g;const e=Wa(m,4),t=Fa(m,i),p=xa(m,t);let k=0;for(let i=0;i0&&(null!=(l=this.metadataTags).trackNumber||(l.trackNumber=t)),i&&Number.isInteger(i)&&i>0&&(null!=(c=this.metadataTags).tracksTotal||(c.tracksTotal=i))}break;case"ICRD":case"IDIT":{const e=new Date(y);Number.isNaN(e.getTime())||null!=(u=this.metadataTags).date||(u.date=e)}break;case"YEAR":{const e=Number.parseInt(y,10);Number.isInteger(e)&&e>0&&(null!=(d=this.metadataTags).date||(d.date=new Date(e,0,1)))}break;case"IGNR":case"GENR":null!=(h=this.metadataTags).genre||(h.genre=y);break;case"ICMT":case"CMNT":case"COMM":null!=(f=this.metadataTags).comment||(f.comment=y)}g+=8+t+(1&t)}})}parseId3Chunk(e,t){return d(this,null,function*(){let i=this.reader.requestSlice(e,t);if(i instanceof Promise&&(i=yield i),!i)return;const r=Za(i);if(r){const n=t-Qa;if(r.size=Math.min(r.size,n),r.size>0){const t=i.slice(e+Qa,r.size);eo(t,r,this.metadataTags)}}})}getCodec(){if(y(this.audioInfo),this.audioInfo.format===Nr.MULAW)return"ulaw";if(this.audioInfo.format===Nr.ALAW)return"alaw";if(this.audioInfo.format===Nr.PCM){if(1===this.audioInfo.sampleSizeInBytes)return"pcm-u8";if(2===this.audioInfo.sampleSizeInBytes)return"pcm-s16";if(3===this.audioInfo.sampleSizeInBytes)return"pcm-s24";if(4===this.audioInfo.sampleSizeInBytes)return"pcm-s32"}return this.audioInfo.format===Nr.IEEE_FLOAT&&4===this.audioInfo.sampleSizeInBytes?"pcm-f32":null}getMimeType(){return d(this,null,function*(){return"audio/wav"})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackings})}getMetadataTags(){return d(this,null,function*(){return yield this.readMetadata(),this.metadataTags})}}const zr=2048;class Ur{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getCodec(){return this.demuxer.getCodec()}getInternalCodecId(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.format}getDecoderConfig(){return d(this,null,function*(){const e=this.demuxer.getCodec();return e?(y(this.demuxer.audioInfo),{codec:e,numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate}):null})}getNumberOfChannels(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getTimeResolution(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return y(-1!==this.demuxer.dataSize),this.demuxer.dataSize/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getName(){return null}getLanguageCode(){return Q}getDisposition(){return c({},Be)}getPacketAtIndex(e,t){return d(this,null,function*(){y(e>=0),y(this.demuxer.audioInfo);const i=e*zr*this.demuxer.audioInfo.blockSizeInBytes;if(i>=this.demuxer.dataSize)return null;const r=Math.min(zr*this.demuxer.audioInfo.blockSizeInBytes,this.demuxer.dataSize-i);if(null===this.demuxer.reader.fileSize){let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+i,r);if(e instanceof Promise&&(e=yield e),!e)return null}let n;if(t.metadataOnly)n=Gt;else{let e=this.demuxer.reader.requestSlice(this.demuxer.dataStart+i,r);e instanceof Promise&&(e=yield e),y(e),n=xa(e,r)}const s=e*zr/this.demuxer.audioInfo.sampleRate,a=r/this.demuxer.audioInfo.blockSizeInBytes/this.demuxer.audioInfo.sampleRate;return this.demuxer.lastKnownPacketIndex=Math.max(e,this.demuxer.lastKnownPacketIndex),new Yt(n,"key",s,a,e,r)})}getFirstPacket(e){return this.getPacketAtIndex(0,e)}getPacket(e,t){return d(this,null,function*(){y(this.demuxer.audioInfo);const i=Math.floor(Math.min(e*this.demuxer.audioInfo.sampleRate/zr,(this.demuxer.dataSize-1)/(zr*this.demuxer.audioInfo.blockSizeInBytes)));if(i<0)return null;const r=yield this.getPacketAtIndex(i,t);if(r)return r;if(0===i)return null;y(null===this.demuxer.reader.fileSize);let n=yield this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex,t);for(;n;){const e=yield this.getNextPacket(n,t);if(!e)break;n=e}return n})}getNextPacket(e,t){y(this.demuxer.audioInfo);const i=Math.round(e.timestamp*this.demuxer.audioInfo.sampleRate/zr);return this.getPacketAtIndex(i+1,t)}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}}const qr=e=>{const t=e.filePos,i=xa(e,9),r=new Ee(i);if(4095!==r.readBits(12))return null;r.skipBits(1);if(0!==r.readBits(2))return null;const n=r.readBits(1),s=r.readBits(2)+1,a=r.readBits(4);if(15===a)return null;r.skipBits(1);const o=r.readBits(3);if(0===o)throw new Error("ADTS frames with channel configuration 0 are not supported.");r.skipBits(1),r.skipBits(1),r.skipBits(1),r.skipBits(1);const l=r.readBits(13);r.skipBits(11);const c=r.readBits(2)+1;if(1!==c)throw new Error("ADTS frames with more than one AAC frame are not supported.");let u=null;return 1===n?e.filePos-=2:u=r.readBits(16),{objectType:s,samplingFrequencyIndex:a,channelConfiguration:o,frameLength:l,numberOfAacFrames:c,crcCheck:u,startPos:t}},Wr=1024;class Vr extends Qt{constructor(e){super(e),this.metadataPromise=null,this.firstFrameHeader=null,this.loadedSamples=[],this.metadataTags=null,this.trackBackings=[],this.readingMutex=new D,this.lastSampleLoaded=!1,this.lastLoadedPos=0,this.nextTimestampInSamples=0,this.reader=e._reader}readMetadata(){return d(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){for(;!this.firstFrameHeader&&!this.lastSampleLoaded;)yield this.advanceReader();y(this.firstFrameHeader),this.trackBackings=[new Hr(this)]}))()})}advanceReader(){return d(this,null,function*(){if(0===this.lastLoadedPos)for(;;){let e=this.reader.requestSlice(this.lastLoadedPos,Qa);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=Za(e);if(!t)break;this.lastLoadedPos=e.filePos+t.size}let e=this.reader.requestSliceRange(this.lastLoadedPos,7,9);if(e instanceof Promise&&(e=yield e),!e)return void(this.lastSampleLoaded=!0);const t=qr(e);if(!t)return void(this.lastSampleLoaded=!0);if(null!==this.reader.fileSize&&t.startPos+t.frameLength>this.reader.fileSize)return void(this.lastSampleLoaded=!0);this.firstFrameHeader||(this.firstFrameHeader=t);const i=_e[t.samplingFrequencyIndex];y(void 0!==i);const r=Wr/i,n={timestamp:this.nextTimestampInSamples/i,duration:r,dataStart:t.startPos,dataSize:t.frameLength};this.loadedSamples.push(n),this.nextTimestampInSamples+=Wr,this.lastLoadedPos=t.startPos+t.frameLength})}getMimeType(){return d(this,null,function*(){return"audio/aac"})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackings})}getMetadataTags(){return d(this,null,function*(){const e=yield this.readingMutex.acquire();try{if(yield this.readMetadata(),this.metadataTags)return this.metadataTags;this.metadataTags={};let e=0;for(;;){let t=this.reader.requestSlice(e,Qa);if(t instanceof Promise&&(t=yield t),!t)break;const i=Za(t);if(!i)break;let r=this.reader.requestSlice(t.filePos,i.size);if(r instanceof Promise&&(r=yield r),!r)break;eo(r,i,this.metadataTags),e=t.filePos+i.size}return this.metadataTags}finally{e()}})}}class Hr{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getTimeResolution(){return this.getSampleRate()/Wr}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return null})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getName(){return null}getLanguageCode(){return Q}getCodec(){return"aac"}getInternalCodecId(){return y(this.demuxer.firstFrameHeader),this.demuxer.firstFrameHeader.objectType}getNumberOfChannels(){y(this.demuxer.firstFrameHeader);const e=Ae[this.demuxer.firstFrameHeader.channelConfiguration];return y(void 0!==e),e}getSampleRate(){y(this.demuxer.firstFrameHeader);const e=_e[this.demuxer.firstFrameHeader.samplingFrequencyIndex];return y(void 0!==e),e}getDisposition(){return c({},Be)}getDecoderConfig(){return d(this,null,function*(){return y(this.demuxer.firstFrameHeader),{codec:`mp4a.40.${this.demuxer.firstFrameHeader.objectType}`,numberOfChannels:this.getNumberOfChannels(),sampleRate:this.getSampleRate()}})}getPacketAtIndex(e,t){return d(this,null,function*(){if(-1===e)return null;const i=this.demuxer.loadedSamples[e];if(!i)return null;let r;if(t.metadataOnly)r=Gt;else{let e=this.demuxer.reader.requestSlice(i.dataStart,i.dataSize);if(e instanceof Promise&&(e=yield e),!e)return null;r=xa(e,i.dataSize)}return new Yt(r,"key",i.timestamp,i.duration,e,i.dataSize)})}getFirstPacket(e){return this.getPacketAtIndex(0,e)}getNextPacket(e,t){return d(this,null,function*(){const i=yield this.demuxer.readingMutex.acquire();try{const i=L(this.demuxer.loadedSamples,e.timestamp,e=>e.timestamp);if(-1===i)throw new Error("Packet was not created from this track.");const r=i+1;for(;r>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(r,t)}finally{i()}})}getPacket(e,t){return d(this,null,function*(){const i=yield this.demuxer.readingMutex.acquire();try{for(;;){const i=z(this.demuxer.loadedSamples,e,e=>e.timestamp);if(-1===i&&this.demuxer.loadedSamples.length>0)return null;if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(i,t);if(i>=0&&i+1d(this,null,function*(){for(var e;null===this.reader.fileSize||ts.end-6)return{num:a.num,blockSize:a.blockSize,sampleRate:a.sampleRate,size:s.end-e,isLastFrame:!0};if(255===Ca(s)){const t=s.filePos;if(Ca(s)!==(1===this.blockingBit?249:248)){s.filePos=t;continue}s.skip(-2);const i=s.filePos-e,r=this.readFlacFrameHeader({slice:s,isFirstPacket:!1});if(!r){s.filePos=t;continue}if(0===this.blockingBit){if(r.num-a.num!==1){s.filePos=t;continue}}else if(r.num-a.num!==a.blockSize){s.filePos=t;continue}return{num:a.num,blockSize:a.blockSize,sampleRate:a.sampleRate,size:i,isLastFrame:!1}}}})}readFlacFrameHeader({slice:e,isFirstPacket:t}){const i=e.filePos,r=xa(e,4),n=new Ee(r);if(32764!==n.readBits(15))return null;if(null===this.blockingBit){y(t);const e=n.readBits(1);this.blockingBit=e}else if(1===this.blockingBit){y(!t);if(1!==n.readBits(1))return null}else{if(0!==this.blockingBit)throw new Error("Invalid blocking bit");y(!t);if(0!==n.readBits(1))return null}const s=(e=>0===e?null:1===e?192:e>=2&&e<=5?144*o(2,e):6===e?"uncommon-u8":7===e?"uncommon-u16":e>=8&&e<=15?o(2,e):null)(n.readBits(4));if(!s)return null;y(this.audioInfo);const a=((e,t)=>{switch(e){case 0:return t;case 1:return 88200;case 2:return 176400;case 3:return 192e3;case 4:return 8e3;case 5:return 16e3;case 6:return 22050;case 7:return 24e3;case 8:return 32e3;case 9:return 44100;case 10:return 48e3;case 11:return 96e3;case 12:return"uncommon-u8";case 13:return"uncommon-u16";case 14:return"uncommon-u16-10";default:return null}})(n.readBits(4),this.audioInfo.sampleRate);if(!a)return null;n.readBits(4),n.readBits(3);if(0!==n.readBits(1))return null;const l=(e=>{let t=0;const i=new Ee(xa(e,1));for(;1===i.readBits(1);)t++;if(0===t)return i.readBits(7);const r=[],n=t-1,s=new Ee(xa(e,n)),a=8-t-1;for(let o=0;oe|t<"uncommon-u16"===t?Ea(e)+1:"uncommon-u8"===t?Ca(e)+1:"number"===typeof t?t:(H(t),void y(!1)))(e,s),u=((e,t)=>"uncommon-u16"===t?Ea(e):"uncommon-u16-10"===t?10*Ea(e):"uncommon-u8"===t?Ca(e):"number"===typeof t?t:null)(e,a);if(null===u)return null;if(u!==this.audioInfo.sampleRate)return null;const d=e.filePos-i,h=Ca(e);e.skip(-d),e.skip(-1);const f=(e=>{let t=0;for(const i of e){t^=i;for(let e=0;e<8;e++)0!==(128&t)?t=t<<1^7:t<<=1,t&=255}return t})(xa(e,d));return h!==f?null:{num:l,blockSize:c,sampleRate:u}}advanceReader(){return d(this,null,function*(){yield this.readMetadata(),y(null!==this.lastLoadedPos),y(this.audioInfo);const e=this.lastLoadedPos,t=yield this.readNextFlacFrame({startPos:e,isFirstPacket:0===this.loadedSamples.length});if(!t)return void(this.lastSampleLoaded=!0);const i=this.loadedSamples[this.loadedSamples.length-1],r={blockOffset:i?i.blockOffset+i.blockSize:0,blockSize:t.blockSize,byteOffset:e,byteSize:t.size};this.lastLoadedPos=this.lastLoadedPos+t.size,this.loadedSamples.push(r),t.isLastFrame&&(this.lastSampleLoaded=!0)})}}class jr{constructor(e){this.demuxer=e}getType(){return"audio"}getId(){return 1}getNumber(){return 1}getCodec(){return"flac"}getInternalCodecId(){return null}getNumberOfChannels(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.numberOfChannels}getSampleRate(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}getName(){return null}getLanguageCode(){return Q}getTimeResolution(){return y(this.demuxer.audioInfo),this.demuxer.audioInfo.sampleRate}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return y(this.demuxer.audioInfo),0===this.demuxer.audioInfo.totalSamples?null:this.demuxer.audioInfo.totalSamples/this.demuxer.audioInfo.sampleRate})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}getDisposition(){return c({},Be)}getDecoderConfig(){return d(this,null,function*(){return y(this.demuxer.audioInfo),{codec:"flac",numberOfChannels:this.demuxer.audioInfo.numberOfChannels,sampleRate:this.demuxer.audioInfo.sampleRate,description:this.demuxer.audioInfo.description}})}getPacket(e,t){return d(this,null,function*(){if(y(this.demuxer.audioInfo),e<0)throw new Error("Timestamp cannot be negative");const i=yield this.demuxer.readingMutex.acquire();try{for(;;){const i=z(this.demuxer.loadedSamples,e,e=>e.blockOffset/this.demuxer.audioInfo.sampleRate);if(-1===i){yield this.demuxer.advanceReader();continue}const r=this.demuxer.loadedSamples[i],n=r.blockOffset/this.demuxer.audioInfo.sampleRate;if(!(n+r.blockSize/this.demuxer.audioInfo.sampleRate<=e))return this.getPacketAtIndex(i,t);if(this.demuxer.lastSampleLoaded)return this.getPacketAtIndex(this.demuxer.loadedSamples.length-1,t);yield this.demuxer.advanceReader()}}finally{i()}})}getNextPacket(e,t){return d(this,null,function*(){const i=yield this.demuxer.readingMutex.acquire();try{const i=e.sequenceNumber+1;if(this.demuxer.lastSampleLoaded&&i>=this.demuxer.loadedSamples.length)return null;for(;i>=this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(i,t)}finally{i()}})}getKeyPacket(e,t){return this.getPacket(e,t)}getNextKeyPacket(e,t){return this.getNextPacket(e,t)}getPacketAtIndex(e,t){return d(this,null,function*(){const i=this.demuxer.loadedSamples[e];if(!i)return null;let r;if(t.metadataOnly)r=Gt;else{let e=this.demuxer.reader.requestSlice(i.byteOffset,i.byteSize);if(e instanceof Promise&&(e=yield e),!e)return null;r=xa(e,i.byteSize)}y(this.demuxer.audioInfo);const n=i.blockOffset/this.demuxer.audioInfo.sampleRate,s=i.blockSize/this.demuxer.audioInfo.sampleRate;return new Yt(r,"key",n,s,e,i.byteSize)})}getFirstPacket(e){return d(this,null,function*(){for(;0===this.demuxer.loadedSamples.length&&!this.demuxer.lastSampleLoaded;)yield this.demuxer.advanceReader();return this.getPacketAtIndex(0,e)})}}const Xr=9e4,$r=188,Qr="PES packet is missing PTS where it was expected. PES packets without PTS are not currently supported. If you think this file should be supported, please report it.",Gr=new Set;class Yr extends Qt{constructor(e){super(e),this.metadataPromise=null,this.elementaryStreams=[],this.trackBackingEntries=[],this.packetOffset=0,this.packetStride=-1,this.sectionEndPositions=[],this.seekChunkSize=5242880,this.minReferencePointByteDistance=-1,this.reader=e._reader}readMetadata(){return d(this,null,function*(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){let e=this.reader.requestSlice(0,205);e instanceof Promise&&(e=yield e),y(e);const t=xa(e,205);if(71===t[0]&&71===t[188])this.packetOffset=0,this.packetStride=$r;else if(71===t[0]&&71===t[204])this.packetOffset=0,this.packetStride=204;else{if(71!==t[4]||71!==t[196])throw new Error("Unreachable.");this.packetOffset=4,this.packetStride=192}this.minReferencePointByteDistance=256*this.packetStride;let i=this.packetOffset,r=null,n=!1,s=!1;for(;;){const e=yield this.readPacketHeader(i);if(!e)break;if(0===e.payloadUnitStartIndicator){i+=this.packetStride;continue}const t=yield this.readSection(i,!0,!s);if(!t)break;const a=3,o=32;let l=!1;if(!s&&0!==t.pid){if(!(0===t.payload[0]&&0===t.payload[1]&&1===t.payload[2])){const e=new Ee(t.payload),i=e.readAlignedByte();e.skipBits(8*i);l=2===e.readBits(8)}}if(0!==t.pid||n)if(t.pid!==r&&!l||s){const e=this.elementaryStreams.find(e=>e.pid===t.pid);e:if(e&&!e.initialized){const i=Zr(t,!0);if(!i)throw new Error(`Couldn't read first PES packet for Elementary Stream with PID ${e.pid}`);if(e.firstSection=t,e.canBeTrustedWithKeyPackets=1===t.randomAccessIndicator,this.input._initInput){const i=(yield this.input._initInput._getDemuxer()).elementaryStreams.find(i=>i.pid===t.pid&&i.info.codec===e.info.codec);if(i){e.info=i.info,e.initialized=!0;break e}}const r=new sn(e,i);if("video"===e.info.type){for(;;){if(r.suppliedPacket=null,yield r.markNextPacket(),"avc"===e.info.codec){if(!r.suppliedPacket)throw new Error("Invalid AVC video stream; could not extract AVCDecoderConfigurationRecord from any packet.");if(e.info.avcCodecInfo=pt(r.suppliedPacket.data),!e.info.avcCodecInfo)continue;const t=e.info.avcCodecInfo.sequenceParameterSets[0];y(t);const i=kt(t);e.info.width=i.displayWidth,e.info.height=i.displayHeight;const n=i.pixelAspectRatio.num,s=i.pixelAspectRatio.den;n>0&&s>0&&(n>s?(e.info.squarePixelWidth=Math.round(e.info.width*n/s),e.info.squarePixelHeight=e.info.height):(e.info.squarePixelWidth=e.info.width,e.info.squarePixelHeight=Math.round(e.info.height*s/n))),e.info.colorSpace={primaries:B[i.colourPrimaries],transfer:_[i.transferCharacteristics],matrix:F[i.matrixCoefficients],fullRange:!!i.fullRangeFlag},e.info.reorderSize=i.maxDecFrameBuffering;break}if("hevc"===e.info.codec){if(!r.suppliedPacket)throw new Error("Invalid HEVC video stream; could not extract HVCDecoderConfigurationRecord from first packet.");if(e.info.hevcCodecInfo=vt(r.suppliedPacket.data),!e.info.hevcCodecInfo)continue;const t=e.info.hevcCodecInfo.arrays.find(e=>e.nalUnitType===st.SPS_NUT).nalUnits[0];y(t);const i=St(t);e.info.width=i.displayWidth,e.info.height=i.displayHeight,i.pixelAspectRatio.num>i.pixelAspectRatio.den?(e.info.squarePixelWidth=Math.round(e.info.width*i.pixelAspectRatio.num/i.pixelAspectRatio.den),e.info.squarePixelHeight=e.info.height):(e.info.squarePixelWidth=e.info.width,e.info.squarePixelHeight=Math.round(e.info.height*i.pixelAspectRatio.den/i.pixelAspectRatio.num)),e.info.colorSpace={primaries:B[i.colourPrimaries],transfer:_[i.transferCharacteristics],matrix:F[i.matrixCoefficients],fullRange:!!i.fullRangeFlag},e.info.reorderSize=i.maxDecFrameBuffering;break}throw new Error("Unhandled.")}e.info.decoderConfig={codec:Ue({width:e.info.width,height:e.info.height,codec:e.info.codec,codecDescription:null,colorSpace:e.info.colorSpace,avcType:1,avcCodecInfo:e.info.avcCodecInfo,hevcCodecInfo:e.info.hevcCodecInfo,vp9CodecInfo:null,av1CodecInfo:null}),codedWidth:e.info.width,codedHeight:e.info.height,colorSpace:e.info.colorSpace},e.info.width===e.info.squarePixelWidth&&e.info.height===e.info.squarePixelHeight||(e.info.decoderConfig.displayAspectWidth=e.info.squarePixelWidth,e.info.decoderConfig.displayAspectHeight=e.info.squarePixelHeight),e.initialized=!0}else{if(yield r.markNextPacket(),!r.suppliedPacket)throw new Error(`Couldn't parse first media packet for Elementary Stream with PID ${e.pid}`);if("aac"===e.info.codec){const t=Pa.tempFromBytes(r.suppliedPacket.data),i=qr(t);if(!i)throw new Error("Invalid AAC audio stream; could not read ADTS frame header from first packet.");e.info.aacCodecInfo={isMpeg2:!1,objectType:i.objectType},e.info.numberOfChannels=Ae[i.channelConfiguration],e.info.sampleRate=_e[i.samplingFrequencyIndex]}else if("mp3"===e.info.codec){const t=Ra(Pa.tempFromBytes(r.suppliedPacket.data)),i=Ye(t,r.suppliedPacket.data.byteLength);if(!i.header)throw new Error("Invalid MP3 audio stream; could not read frame header from first packet.");e.info.numberOfChannels=3===i.header.channel?1:2,e.info.sampleRate=i.header.sampleRate}else if("ac3"===e.info.codec){const t=Vt(r.suppliedPacket.data);if(!t)throw new Error("Invalid AC-3 audio stream; could not read sync frame from first packet.");if(3===t.fscod)throw new Error("Invalid AC-3 audio stream; reserved sample rate code found in first packet.");e.info.numberOfChannels=Wt[t.acmod]+t.lfeon,e.info.sampleRate=tt[t.fscod]}else{if("eac3"!==e.info.codec)throw new Error("Unhandled.");{const t=jt(r.suppliedPacket.data);if(!t)throw new Error("Invalid E-AC-3 audio stream; could not read sync frame from first packet.");const i=Xt(t);if(null===i)throw new Error("Invalid E-AC-3 audio stream; reserved sample rate code found in first packet.");e.info.numberOfChannels=$t(t),e.info.sampleRate=i}}e.info.decoderConfig={codec:qe({codec:e.info.codec,codecDescription:null,aacCodecInfo:e.info.aacCodecInfo}),numberOfChannels:e.info.numberOfChannels,sampleRate:e.info.sampleRate},e.initialized=!0}}}else{const e=new Ee(t.payload),i=e.readAlignedByte();e.skipBits(8*i),e.skipBits(12);const r=e.readBits(12);e.skipBits(43),e.readBits(13),e.skipBits(6);const n=e.readBits(10);for(e.skipBits(8*n);8*(r+a)-e.pos>o;){const t=e.readBits(8);e.skipBits(3);const i=e.readBits(13);e.skipBits(6);const r=e.readBits(10),n=e.pos+8*r;let s=!1,a=!1;for(;e.poso;){const t=e.readBits(16);e.skipBits(3);const i=e.readBits(13);if(0!==t){if(null!==r)throw new Error("Only files with a single program are supported.");r=i}}if(null===r)throw new Error("Program Association Table must link to a Program Map Table.");n=!0}if(s&&this.elementaryStreams.every(e=>e.initialized))break;i+=this.packetStride}if(!s){if(!n)throw new Error("No Program Association Table found in the file.");throw new Error("No Program Map Table found in the file.")}for(const a of this.elementaryStreams)"video"===a.info.type?this.trackBackingEntries.push(new tn(a)):this.trackBackingEntries.push(new rn(a))}))()})}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),this.trackBackingEntries})}getMetadataTags(){return d(this,null,function*(){return{}})}getMimeType(){return d(this,null,function*(){yield this.readMetadata();return(e=>{let t="video/MP2T";const i=[...new Set(e.filter(Boolean))];return i.length>0&&(t+=`; codecs="${i.join(", ")}"`),t})(yield Promise.all(this.trackBackingEntries.map(e=>e.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null}))))})}readSection(e,t,i=!1){return d(this,null,function*(){let r=e,n=e;const s=[];let a,o=0,l=null,c=!0,u=0;for(;;){const e=yield this.readPacket(n);if(n+=this.packetStride,!e)break;if(l){if(e.pid!==l.pid){if(i)break;continue}if(1===e.payloadUnitStartIndicator)break}else{if(0===e.payloadUnitStartIndicator)break;l=e}const a=!!(2&e.adaptationFieldControl),d=!!(1&e.adaptationFieldControl);let h=0;if(a&&(h=1+e.body[0],e===l&&h>1&&(u=e.body[1]>>6&1)),d&&(0===h?(s.push(e.body),o+=e.body.byteLength):(s.push(e.body.subarray(h)),o+=e.body.byteLength-h)),r=n,!t&&o>=64){c=!1;break}if(-1!==L(this.sectionEndPositions,r,e=>e)){c=!1;break}}if(c){const e=z(this.sectionEndPositions,r,e=>e);this.sectionEndPositions.splice(e+1,0,r)}if(!l)return null;if(1===s.length)a=s[0];else{const e=s.reduce((e,t)=>e+t.length,0);a=new Uint8Array(e);let t=0;for(const i of s)a.set(i,t),t+=i.length}return{startPos:e,endPos:t?r:null,pid:l.pid,payload:a,randomAccessIndicator:u}})}readPacketHeader(e){return d(this,null,function*(){let t=this.reader.requestSlice(e,4);if(t instanceof Promise&&(t=yield t),!t)return null;if(71!==Ca(t))throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file.");const i=Ea(t);return{payloadUnitStartIndicator:i>>14&1,pid:8191&i,adaptationFieldControl:Ca(t)>>4&3}})}readPacket(e){return d(this,null,function*(){let t=this.reader.requestSlice(e,$r);if(t instanceof Promise&&(t=yield t),!t)return null;const i=xa(t,$r);if(71!==i[0])throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file.");const r=(i[1]<<8)+i[2];return{payloadUnitStartIndicator:r>>14&1,pid:8191&r,adaptationFieldControl:i[3]>>4&3,body:i.subarray(4)}})}}const Jr=(e,t)=>{if(e.payload.byteLength<3)return null;const i=new Ee(e.payload);if(1!==i.readBits(24))return null;const r=i.readBits(8);if(i.skipBits(16),188===r||190===r||191===r||240===r||241===r||255===r||242===r||248===r)return null;i.skipBits(8);const n=i.readBits(2);i.skipBits(14);let s=null;if(2===n||3===n)s=0,i.skipBits(4),s+=i.readBits(3)*(1<<30),i.skipBits(1),s+=32768*i.readBits(15),i.skipBits(1),s+=i.readBits(15);else if(t)throw new Error(Qr);return{sectionStartPos:e.startPos,sectionEndPos:e.endPos,pts:s,randomAccessIndicator:e.randomAccessIndicator}},Zr=(e,t)=>{y(null!==e.endPos);const i=Jr(e,t);if(!i)return null;const r=new Ee(e.payload);r.skipBits(32);const n=r.readBits(16);r.skipBits(16);const s=r.readBits(8),a=r.pos+8*s;r.pos=a;const o=a/8;y(Number.isInteger(o));const l=e.payload.subarray(o,n>0?6+n:e.payload.byteLength);return u(c({},i),{data:l})};class en{constructor(e){this.elementaryStream=e,this.packetBuffers=new WeakMap,this.packetSectionStarts=new WeakMap}getId(){return this.elementaryStream.pid}getNumber(){const e=this.elementaryStream.demuxer,t=this.elementaryStream.info.type;let i=0;for(const r of e.trackBackingEntries)if(r.getType()===t&&i++,y(r instanceof en),r.elementaryStream===this.elementaryStream)break;return i}getCodec(){throw new Error("Not implemented on base class.")}getInternalCodecId(){return this.elementaryStream.streamType}getName(){return null}getLanguageCode(){return Q}getDisposition(){return u(c({},Be),{primary:!1})}getTimeResolution(){return Xr}isRelativeToUnixEpoch(){return!1}getPairingMask(){return BigInt("1")}getBitrate(){return null}getAverageBitrate(){return null}getDurationFromMetadata(){return d(this,null,function*(){return null})}getLiveRefreshInterval(){return d(this,null,function*(){return null})}createEncodedPacket(e,t,i){let r;return r=this.allPacketsAreKeyPackets()||1===e.randomAccessIndicator?"key":"delta",new Yt(i.metadataOnly?Gt:e.data,r,e.pts/Xr,Math.max(t/Xr,0),e.sequenceNumber,e.data.byteLength)}getFirstPacket(e){return d(this,null,function*(){const t=this.elementaryStream.firstSection;y(t);const i=Zr(t,!0);y(i);const r=new sn(this.elementaryStream,i),n=new an(this,r),s=yield n.readNext();if(!s)return null;const a=this.createEncodedPacket(s.packet,s.duration,e);return this.packetBuffers.set(a,n),this.packetSectionStarts.set(a,s.packet.sectionStartPos),a})}getNextPacket(e,t){return d(this,null,function*(){let i=this.packetBuffers.get(e);if(i){const r=yield i.readNext();if(!r)return null;this.packetBuffers.delete(e);const n=this.createEncodedPacket(r.packet,r.duration,t);return this.packetBuffers.set(n,i),this.packetSectionStarts.set(n,r.packet.sectionStartPos),n}const r=this.packetSectionStarts.get(e);if(void 0===r)throw new Error("Packet was not created from this track.");const n=this.elementaryStream.demuxer,s=yield n.readSection(r,!0);y(s);const a=Zr(s,!0);y(a);const o=new sn(this.elementaryStream,a);i=new an(this,o);const l=e.sequenceNumber;for(;;){const e=yield i.readNext();if(!e)return null;if(e.packet.sequenceNumber>l){const r=this.createEncodedPacket(e.packet,e.duration,t);return this.packetBuffers.set(r,i),this.packetSectionStarts.set(r,e.packet.sectionStartPos),r}}})}getNextKeyPacket(e,t){return d(this,null,function*(){let i=e;for(;;){if(i=yield this.getNextPacket(i,t),!i)return null;if("key"===i.type)return i}})}getPacket(e,t){return this.doPacketLookup(e,!1,t)}getKeyPacket(e,t){return this.doPacketLookup(e,!0,t)}doPacketLookup(e,t,i){return d(this,null,function*(){var r,n,s,a,o,l;const c=G(e*Xr),u=this.elementaryStream.demuxer,{reader:h,seekChunkSize:f}=u,m=this.elementaryStream.pid,p=(e,t,i)=>d(this,null,function*(){let r=e;for(;re.pts),w=-1!==v?S[v]:null;if(w&&c-w.pts<45e3)b=w.sectionStartPos;else{let e=0;if(null!==h.fileSize){const t=Math.ceil(h.fileSize/f);if(t>1){let i=0,r=t-1;for(e=i;i<=r;){const t=Math.floor((i+r)/2),n=J(t*f,u.packetStride)+k.sectionStartPos,s=n+f,a=yield p(n,s,!1);a?a.pesPacketHeader.pts<=c?(e=t,i=t+1):r=t-1:r=t-1}}}b=J(e*f,u.packetStride)+k.sectionStartPos}const P=yield p(b,null!=(r=h.fileSize)?r:1/0,!1);let I=null!=(n=null==P?void 0:P.pesPacketHeader)?n:null;I||(I=k);const x=this.getReorderSize(),C=(e,t)=>d(this,null,function*(){var r,n;const s=yield u.readSection(e,!0);y(s);const a=Zr(s,!0);y(a);const o=new sn(this.elementaryStream,a),l=new an(this,o);for(;;){if((null!=(n=null==(r=T(l.presentationOrderPackets))?void 0:r.pts)?n:-1/0)>=c)break;if(!(yield l.readNextPacket()))break}const d=V(l.presentationOrderPackets,t);if(-1===d)return null;const h=l.presentationOrderPackets[d],f=0===d?0:h.pts-l.presentationOrderPackets[d-1].pts;for(;l.decodeOrderPackets[0]!==h;)l.decodeOrderPackets.shift();l.lastDuration=f;const m=yield l.readNext();y(m);const p=this.createEncodedPacket(m.packet,m.duration,i);return this.packetBuffers.set(p,l),this.packetSectionStarts.set(p,m.packet.sectionStartPos),p});if(!t||this.allPacketsAreKeyPackets()){e:for(;;){let e=I.sectionStartPos+u.packetStride;for(;;){const t=yield u.readPacketHeader(e);if(!t)break e;if(t.pid===m&&1===t.payloadUnitStartIndicator){const t=yield u.readSection(e,!1);if(t){const e=Jr(t,!1);if(e&&null!==e.pts){if(e.pts>c)break e;I=e,nn(this.elementaryStream,I);break}}}e+=u.packetStride}}e:for(let e=0;e=u.packetOffset;){const t=yield u.readPacketHeader(e);if(!t)break e;if(t.pid===m&&1===t.payloadUnitStartIndicator){const t=yield u.readSection(e,!1);if(t){const e=Jr(t,!1);if(e&&null!==e.pts){I=e;break}}}e-=u.packetStride}}return C(I.sectionStartPos,e=>e.pts<=c)}{let e=b,t=null;const i=!this.elementaryStream.canBeTrustedWithKeyPackets;for(;;){let r=null;const n=e<=k.sectionStartPos;let d,b=null;if(n)d=k,b=g;else{const t=yield p(e,null!=(s=h.fileSize)?s:1/0,i);d=null!=(a=null==t?void 0:t.pesPacketHeader)?a:null,b=null!=(o=null==t?void 0:t.section)?o:null}let T=!1,S=0;e:for(;d&&!(null!==t&&d.sectionStartPos>=t);){if(d.pts<=c){let e;if(this.elementaryStream.canBeTrustedWithKeyPackets)e=1===d.randomAccessIndicator;else{y(b);const t=Zr(b,!0);y(t);const i=new sn(this.elementaryStream,t);yield i.markNextPacket(),e=1===(null==(l=i.suppliedPacket)?void 0:l.randomAccessIndicator)}e&&(r=d)}if(d.pts>c&&(T=!0),T&&(S++,S>x))break;let e=d.sectionStartPos+u.packetStride;for(;;){const t=yield u.readPacketHeader(e);if(!t)break e;if(t.pid===m&&1===t.payloadUnitStartIndicator){const t=yield u.readSection(e,i);if(t){const e=Jr(t,!1);if(e&&null!==e.pts){d=e,b=t,nn(this.elementaryStream,d);break}}}e+=u.packetStride}}if(r){let e=r;if(0===S)e:for(let r=0;r=u.packetOffset;){const r=yield u.readPacketHeader(t);if(!r)break e;if(r.pid===m&&1===r.payloadUnitStartIndicator){const r=yield u.readSection(t,i);if(r){const t=Jr(r,!1);if(t&&null!==t.pts){e=t;break}}}t-=u.packetStride}}const t=yield C(e.sectionStartPos,e=>e.pts<=c&&1===e.randomAccessIndicator);return y(t),t}if(n)return null;t=e,e=Math.max(J(e-k.sectionStartPos-f,u.packetStride)+k.sectionStartPos,k.sectionStartPos)}}})}}class tn extends en{getType(){return"video"}getCodec(){return this.elementaryStream.info.codec}getCodedWidth(){return this.elementaryStream.info.width}getCodedHeight(){return this.elementaryStream.info.height}getSquarePixelWidth(){return this.elementaryStream.info.squarePixelWidth}getSquarePixelHeight(){return this.elementaryStream.info.squarePixelHeight}getRotation(){return 0}getColorSpace(){return d(this,null,function*(){return this.elementaryStream.info.colorSpace})}canBeTransparent(){return d(this,null,function*(){return!1})}getDecoderConfig(){return d(this,null,function*(){return y(this.elementaryStream.info.decoderConfig),this.elementaryStream.info.decoderConfig})}allPacketsAreKeyPackets(){return!1}getReorderSize(){return this.elementaryStream.info.reorderSize}}class rn extends en{getType(){return"audio"}getCodec(){return this.elementaryStream.info.codec}getNumberOfChannels(){return this.elementaryStream.info.numberOfChannels}getSampleRate(){return this.elementaryStream.info.sampleRate}getDecoderConfig(){return d(this,null,function*(){return y(this.elementaryStream.info.decoderConfig),this.elementaryStream.info.decoderConfig})}allPacketsAreKeyPackets(){return!0}getReorderSize(){return 0}}const nn=(e,t)=>{const i=e.referencePesPackets,r=z(i,t.sectionStartPos,e=>e.sectionStartPos);if(r>=0){const n=i[r];if(t.pts<=n.pts)return!1;const s=e.demuxer.minReferencePointByteDistance;if(t.sectionStartPos-n.sectionStartPos=e?e:this.bufferData(e-t).then(()=>Math.min(this.endPos-this.currentPos,e))}getCurrentPesPacket(){const e=this.pesPackets[this.currentPesPacketIndex];return y(e),e}bufferData(e){return d(this,null,function*(){const t=this.endPos+e;for(;this.endPos=a)break;o=e;const i=n+o;if(o+4>=a){this.seekTo(i);break}const l=s[o+1],c=s[o+2],u=s[o+3];let d=0,h=null;if(0===l&&0===c&&1===u?(d=4,h=s[o+4]):0===l&&1===c&&(d=3,h=u),0===d){o++;continue}const f=i;if(null!==r){if(null!==h){const e="avc"===t?ut(h):Tt(h);if("avc"===t?e===rt.AUD:e===st.AUD_NUT){const e=f-r;return this.seekTo(r),this.supplyPacket(e,0)}}o+=d}else r=f,o+=d}if(e>6,a=63&n[4];if(3===s||a>37){this.seekTo(t+1);continue}const o=Ht[3*a+s];y(void 0!==o),this.seekTo(t),r=this.ensureBuffered(o),r instanceof Promise&&(r=yield r);const l=Math.round(13824e4/e.info.sampleRate);return this.supplyPacket(r,l)}if("eac3"===t){if(11!==i)continue;this.skip(-1);const t=this.currentPos;let r=this.ensureBuffered(5);if(r instanceof Promise&&(r=yield r),r<5)return;const n=this.readBytes(5);if(11!==n[0]||119!==n[1]){this.seekTo(t+1);continue}const s=2*(((7&n[2])<<8|n[3])+1),a=3===n[4]>>6?3:n[4]>>4&3,o=Kt[a];this.seekTo(t),r=this.ensureBuffered(s),r instanceof Promise&&(r=yield r);const l=256*o,c=Math.round(l*Xr/e.info.sampleRate);return this.supplyPacket(r,c)}throw new Error("Unhandled.")}{if(255!==i)continue;this.skip(-1);const t=this.currentPos;let r=this.ensureBuffered(4);if(r instanceof Promise&&(r=yield r),r<4)return;const n=this.readBytes(4),s=P(n).getUint32(0),a=Ye(s,null);if(a.header){this.seekTo(t);let i=this.ensureBuffered(a.header.totalSize);i instanceof Promise&&(i=yield i);const r=a.header.audioSamplesInFrame*Xr/e.info.sampleRate;return this.supplyPacket(i,Math.round(r))}this.seekTo(t+1)}}}if(r=0)}readNext(){return d(this,null,function*(){if(0===this.decodeOrderPackets.length){if(!(yield this.readNextPacket()))return null}yield this.ensureCurrentPacketHasNext();const e=this.decodeOrderPackets[0],t=this.presentationOrderPackets.indexOf(e);let i;if(y(-1!==t),t===this.presentationOrderPackets.length-1)i=this.lastDuration;else{i=this.presentationOrderPackets[t+1].pts-e.pts,this.lastDuration=i}for(this.decodeOrderPackets.shift();this.presentationOrderPackets.length>0;){const e=this.presentationOrderPackets[0];if(this.decodeOrderPackets.includes(e))break;this.presentationOrderPackets.shift()}return{packet:e,duration:i}})}readNextPacket(){return d(this,null,function*(){if(this.reachedEnd)return!1;let e;return this.context.suppliedPacket||(yield this.context.markNextPacket()),e=this.context.suppliedPacket,this.context.suppliedPacket=null,e?(this.decodeOrderPackets.push(e),this.processPacketThroughReorderBuffer(e),!0):(this.reachedEnd=!0,this.flushReorderBuffer(),!1)})}ensureCurrentPacketHasNext(){return d(this,null,function*(){const e=this.decodeOrderPackets[0];for(y(e);;){const t=this.presentationOrderPackets.indexOf(e);if(-1!==t&&t<=this.presentationOrderPackets.length-2)break;if(!(yield this.readNextPacket()))break}})}processPacketThroughReorderBuffer(e){if(this.reorderBuffer.push(e),this.reorderBuffer.length>this.reorderSize){let e=0;for(let i=1;ie.pts-t.pts),this.presentationOrderPackets.push(...this.reorderBuffer),this.reorderBuffer.length=0}}const on="application/vnd.apple.mpegurl",ln="#EXT-X-STREAM-INF:",cn="#EXT-X-I-FRAME-STREAM-INF:",un="#EXT-X-MEDIA:",dn="#EXTINF:",hn="#EXT-X-MAP:",fn="#EXT-X-KEY:",mn="#EXT-X-MEDIA-SEQUENCE:",pn="#EXT-X-BYTERANGE:",gn="#EXT-X-PROGRAM-DATE-TIME:",kn="#EXT-X-TARGETDURATION:",yn="#EXT-X-PLAYLIST-TYPE:",bn=e=>0===e.length||e.startsWith("#")&&!e.startsWith("#EXT");class Tn{constructor(e){this._attributes={};let t="",i="",r=!1,n=!1;for(let s=0;sd(this,null,function*(){const e=[];if(this.trackDeclarations){for(const t of this.trackDeclarations)if("video"===t.type){const i=Te(e,e=>"video"===e.getType())+1;e.push(new wn(this,t,i))}else if("audio"===t.type){const i=Te(e,e=>"audio"===e.getType())+1;e.push(new Pn(this,t,i))}}else{if(this.firstSegment=yield this.getFirstSegment({}),!this.firstSegment)return[];const t=this.getInputForSegment(this.firstSegment),i=yield t.getTracks();for(const r of i)if("video"===r.type){const t=Te(e,e=>"video"===e.getType())+1;e.push(new wn(this,{id:e.length+1,type:"video"},t))}else if("audio"===r.type){const t=Te(e,e=>"audio"===e.getType())+1;e.push(new Pn(this,{id:e.length+1,type:"audio"},t))}}return e}))()})}getFirstTimestampForInput(e){return d(this,null,function*(){const t=this.firstTimestampCache.get(e);if(void 0!==t)return t;const i=yield e.getFirstTimestamp();return this.firstTimestampCache.set(e,i),i})}getMediaOffset(e,t){return d(this,null,function*(){var i;const r=null!=(i=e.firstSegment)?i:e;let n;if(this.firstSegmentFirstTimestamps.has(r))n=this.firstSegmentFirstTimestamps.get(r);else{const e=this.getInputForSegment(r);n=yield this.getFirstTimestampForInput(e),this.firstSegmentFirstTimestamps.set(r,n)}if(r===e)return r.timestamp-n;const s=yield this.getFirstTimestampForInput(t),a=e.timestamp-r.timestamp,o=s-n-a;return Math.abs(o)<=Math.min(.25,a)?r.timestamp-n:e.timestamp-s})}dispose(){for(const e of this.inputCache)e.input.dispose();this.inputCache.length=0}}class vn{constructor(e,t,i){this.packetInfos=new WeakMap,this.hydrationPromise=null,this.firstInputTrack=null,this.segmentedInput=e,this.decl=t,this.number=i}hydrate(){var e;return null!=(e=this.hydrationPromise)?e:this.hydrationPromise=(()=>d(this,null,function*(){var e;if(null!=(e=this.segmentedInput).firstSegment||(e.firstSegment=yield this.segmentedInput.getFirstSegment({})),!this.segmentedInput.firstSegment)throw new Error("Missing first segment, can't retrieve track.");const t=this.segmentedInput.getInputForSegment(this.segmentedInput.firstSegment),i=(yield t.getTracks()).find(e=>e.type===this.decl.type&&e.number===this.number);if(!i)throw new Error("No matching track found in underlying media data.");this.firstInputTrack=i}))()}getId(){return this.decl.id}getType(){return this.decl.type}getNumber(){return this.number}delegate(e){return this.firstInputTrack?e():this.hydrate().then(e)}getDecoderConfig(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())})}getHasOnlyKeyPackets(){return this.delegate(()=>{var e,t,i;return null!=(i=null==(t=(e=this.firstInputTrack._backing).getHasOnlyKeyPackets)?void 0:t.call(e))?i:null})}getPairingMask(){return BigInt("1")}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getInternalCodecId(){return this.delegate(()=>this.firstInputTrack._backing.getInternalCodecId())}getDisposition(){return this.delegate(()=>this.firstInputTrack._backing.getDisposition())}getLanguageCode(){return this.delegate(()=>this.firstInputTrack._backing.getLanguageCode())}getName(){return this.delegate(()=>this.firstInputTrack._backing.getName())}getTimeResolution(){return this.delegate(()=>this.firstInputTrack._backing.getTimeResolution())}isRelativeToUnixEpoch(){return d(this,null,function*(){return yield this.hydrate(),y(this.segmentedInput.firstSegment),this.segmentedInput.firstSegment.relativeToUnixEpoch})}getBitrate(){return this.delegate(()=>this.firstInputTrack._backing.getBitrate())}getAverageBitrate(){return this.delegate(()=>this.firstInputTrack._backing.getAverageBitrate())}getDurationFromMetadata(e){return this.segmentedInput.getDurationFromMetadata(e)}getLiveRefreshInterval(){return this.segmentedInput.getLiveRefreshInterval()}createAdjustedPacket(e,t,i){return d(this,null,function*(){y(e.sequenceNumber>=0),y(this.segmentedInput.firstSegment);const r=yield this.segmentedInput.getMediaOffset(t,i.input),n=t.timestamp-this.segmentedInput.firstSegment.timestamp,s=e.clone({timestamp:Y(e.timestamp+r,yield i.getTimeResolution()),sequenceNumber:Math.floor(1e8*n)+e.sequenceNumber});return this.packetInfos.set(s,{segment:t,track:i,sourcePacket:e}),s})}getFirstPacket(e){return d(this,null,function*(){yield this.hydrate(),y(this.segmentedInput.firstSegment),y(this.firstInputTrack);const t=yield this.firstInputTrack._backing.getFirstPacket(e);return t?this.createAdjustedPacket(t,this.segmentedInput.firstSegment,this.firstInputTrack):null})}getNextPacket(e,t){return this._getNextInternal(e,t,!1)}getNextKeyPacket(e,t){return this._getNextInternal(e,t,!0)}_getNextInternal(e,t,i){return d(this,null,function*(){const r=this.packetInfos.get(e);if(!r)throw new Error("Packet was not created from this track.");const n=i?yield r.track._backing.getNextKeyPacket(r.sourcePacket,t):yield r.track._backing.getNextPacket(r.sourcePacket,t);if(n)return this.createAdjustedPacket(n,r.segment,r.track);let s=r.segment;for(;;){const e=yield this.segmentedInput.getNextSegment(s,{skipLiveWait:t.skipLiveWait});if(!e)return null;const i=this.segmentedInput.getInputForSegment(e),n=(yield i.getTracks()).find(e=>e.type===r.track.type&&e.number===r.track.number);if(!n){s=e;continue}const a=yield n._backing.getFirstPacket(t);return a?this.createAdjustedPacket(a,e,n):null}})}getPacket(e,t){return this._getPacketInternal(e,t,!1)}getKeyPacket(e,t){return this._getPacketInternal(e,t,!0)}_getPacketInternal(e,t,i){return d(this,null,function*(){let r=yield this.segmentedInput.getSegmentAt(e,{skipLiveWait:t.skipLiveWait});if(!r)return null;for(yield this.hydrate();r;){const n=this.segmentedInput.getInputForSegment(r),s=(yield n.getTracks()).find(e=>e.type===this.firstInputTrack.type&&e.number===this.firstInputTrack.number);if(!s){r=yield this.segmentedInput.getPreviousSegment(r,{skipLiveWait:t.skipLiveWait});continue}const a=yield this.segmentedInput.getMediaOffset(r,n),o=e-a,l=i?yield s._backing.getKeyPacket(o,t):yield s._backing.getPacket(o,t);if(l)return this.createAdjustedPacket(l,r,s);r=yield this.segmentedInput.getPreviousSegment(r,{skipLiveWait:t.skipLiveWait})}return null})}}class wn extends vn{getType(){return"video"}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getCodedWidth(){return this.delegate(()=>this.firstInputTrack._backing.getCodedWidth())}getCodedHeight(){return this.delegate(()=>this.firstInputTrack._backing.getCodedHeight())}getSquarePixelWidth(){return this.delegate(()=>this.firstInputTrack._backing.getSquarePixelWidth())}getSquarePixelHeight(){return this.delegate(()=>this.firstInputTrack._backing.getSquarePixelHeight())}getRotation(){return this.delegate(()=>this.firstInputTrack._backing.getRotation())}getColorSpace(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.getColorSpace())})}canBeTransparent(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.canBeTransparent())})}getDecoderConfig(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())})}}class Pn extends vn{getType(){return"audio"}getCodec(){return this.delegate(()=>this.firstInputTrack._backing.getCodec())}getNumberOfChannels(){return this.delegate(()=>this.firstInputTrack._backing.getNumberOfChannels())}getSampleRate(){return this.delegate(()=>this.firstInputTrack._backing.getSampleRate())}getDecoderConfig(){return d(this,null,function*(){return this.delegate(()=>this.firstInputTrack._backing.getDecoderConfig())})}}ke();const In=1/0;class xn extends Ie{constructor(){super(...arguments),this._disposed=!1,this._refCount=0,this._usedForHls=!1,this._sizePromise=null,this.onread=null}getSizeOrNull(){return d(this,null,function*(){var e;if(this._disposed)throw new va;return null!=(e=this._sizePromise)?e:this._sizePromise=(()=>d(this,null,function*(){let e=this._getFileSize();return void 0!==e||(yield this._read(0,1,0,In),e=this._getFileSize(),y(void 0!==e)),e}))()})}getSize(){return d(this,null,function*(){if(this._disposed)throw new va;const e=yield this.getSizeOrNull();if(null===e)throw new Error("Cannot determine the size of an unsized source.");return e})}slice(e,t){if(!Number.isInteger(e)||e<0)throw new TypeError("offset must be a non-negative integer.");if(void 0!==t&&(!Number.isInteger(t)||t<0))throw new TypeError("length, when provided, must be a non-negative integer.");return new zn(this,e,t)}_dispatchRead(e,t){var i;null==(i=this.onread)||i.call(this,e,t),this._emit("read",{start:e,end:t})}ref(){return new Cn(this)}}class Cn{constructor(e){if(this._freed=!1,e._disposed)throw new Error("Cannot ref a disposed source.");e._refCount++,this._source=e}get source(){if(!this._source)throw new Error("Can't get source; ref has already been freed.");return this._source}get freed(){return this._freed}free(){if(this._freed)throw new Error("Illegal operation: double free on SourceRef.");const e=this.source;y(e._refCount>0),e._refCount--,0===e._refCount&&(e._dispose(),e._disposed=!0),this._freed=!0,this._source=null}[Symbol.dispose](){this.freed||this.free()}}class Bn extends xn{constructor(e,t){if("string"!==typeof e)throw new TypeError("rootPath must be a string.");if("function"!==typeof t)throw new TypeError("requestHandler must be a function.");super(),this.rootPath=e,this.requestHandler=t}_resolveRequest(e){const t=this.requestHandler(e),i=e=>{var t;if(!(e instanceof xn||e instanceof Cn))throw new TypeError("requestHandler must return or resolve to a Source or SourceRef.");const i=e instanceof xn?e.ref():e;return(t=i.source)._usedForHls||(t._usedForHls=this._usedForHls),i};return t instanceof Promise?t.then(i):i(t)}}const En=(e,t)=>e.path===t.path;class _n extends Bn{constructor(){super(...arguments),this._root=null,this._rootRequest=null}_read(e,t,i,r){if(!this._root){if(!this._rootRequest){const e=this._resolveRequest({path:this.rootPath,isRoot:!0}),t=e=>{const t=e instanceof xn?e.ref():e;return this._root=t,this._rootRequest=null,t};e instanceof Promise?this._rootRequest=e.then(t):(t(e),y(this._root))}if(this._rootRequest)return this._rootRequest.then(n=>n.source._read(e,t,i,r))}return this._root.source._read(e,t,i,r)}_getFileSize(){if(this._root)return this._root.source._getFileSize()}_dispose(){this._root?this._root.free():this._rootRequest&&this._rootRequest.then(e=>e.free())}}class An extends xn{constructor(e,t={}){var i;if(!(e instanceof Blob))throw new TypeError("blob must be a Blob.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!ye(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._readers=new WeakMap,this._blob=e,this._orchestrator=new Ln({maxCacheSize:null!=(i=t.maxCacheSize)?i:8*o(2,20),maxWorkerCount:4,runWorker:this._runWorker.bind(this),prefetchProfile:On.fileSystem}),this._orchestrator.fileSize=e.size}_getFileSize(){return this._orchestrator.fileSize}_read(e,t,i,r){return this._orchestrator.read(e,t,i,r)}_runWorker(e){return d(this,null,function*(){y(e.strictTarget);let t=this._readers.get(e);if(void 0===t){if("stream"in this._blob&&!oe()){t=this._blob.slice(e.currentPos).stream().getReader()}else t=null;this._readers.set(e,t)}for(;e.currentPos{if(t instanceof Error&&(t.message.includes("Failed to fetch")||t.message.includes("Load failed")||t.message.includes("NetworkError when attempting to fetch resource"))){let e=null;try{"undefined"!==typeof window&&"undefined"!==typeof window.location&&(e=new URL(i instanceof Request?i.url:i,window.location.href).origin)}catch(r){}if(("undefined"===typeof navigator||"boolean"!==typeof navigator.onLine||navigator.onLine)&&null!==e&&e!==window.location.origin)return console.warn("Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option."),null}return Math.min(o(2,e-2),16)},Dn=new Set;class Mn extends Bn{constructor(e,t={}){var i,r,n;if("string"!==typeof e&&!(e instanceof URL)&&!("undefined"!==typeof Request&&e instanceof Request))throw new TypeError("url must be a string, URL or Request.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.requestInit&&(!t.requestInit||"object"!==typeof t.requestInit))throw new TypeError("options.requestInit, when provided, must be an object.");if(void 0!==t.getRetryDelay&&"function"!==typeof t.getRetryDelay)throw new TypeError("options.getRetryDelay, when provided, must be a function.");if(void 0!==t.maxCacheSize&&(!ye(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");if(void 0!==t.parallelism&&(!Number.isInteger(t.parallelism)||t.parallelism<1))throw new TypeError("options.parallelism, when provided, must be a positive number.");if(void 0!==t.fetchFn&&"function"!==typeof t.fetchFn)throw new TypeError("options.fetchFn, when provided, must be a function.");super(e instanceof Request?e.url:e instanceof URL?e.href:e,e=>new Mn(e.path,this._options)),this._fileSizeDetermined=!1,this._url=e,this._options=t,this._getRetryDelay=null!=(i=t.getRetryDelay)?i:Rn;this._orchestrator=new Ln({maxCacheSize:null!=(r=t.maxCacheSize)?r:64*o(2,20),maxWorkerCount:null!=(n=t.parallelism)?n:2,runWorker:this._runWorker.bind(this),prefetchProfile:On.network})}_getFileSize(){return this._fileSizeDetermined?this._orchestrator.fileSize:void 0}_read(e,t,i,r){return this._orchestrator.read(e,t,i,r)}_runWorker(e){return d(this,null,function*(){for(var t,i;;){const n=new AbortController,s=yield ne(null!=(t=this._options.fetchFn)?t:fetch,this._url,ie(null!=(i=this._options.requestInit)?i:{},{headers:{Range:`bytes=${e.currentPos}-`},signal:n.signal}),this._getRetryDelay,()=>this._disposed);if(!s.ok)throw new Error(`Error fetching ${String(this._url)}: ${s.status} ${s.statusText}`);e:if(null===this._orchestrator.fileSize){const t=s.headers.get("Content-Range");if(t){const e=/\/(\d+)/.exec(t);if(e){this._orchestrator.supplyFileSize(Number(e[1]));break e}}const i=s.headers.get("Content-Length");i&&this._orchestrator.supplyFileSize(e.currentPos+Number(i))}if(this._fileSizeDetermined=!0,206!==s.status){if(!this._usedForHls){const e=new URL(this._url instanceof Request?this._url.url:this._url,"undefined"!==typeof window?window.location.href:void 0);"null"===e.origin||e.pathname.endsWith(".m3u8")||e.pathname.endsWith(".m3u")||Dn.has(e.origin)||(console.log(this._usedForHls,this._url,e.pathname),console.warn(`HTTP server (origin ${e.origin}) did not respond to a range request with 206 Partial Content, meaning the entire resource will now be downloaded. To enable efficient media file streaming across a network, please make sure your server supports range requests.`),Dn.add(e.origin))}e.currentPos=0,this._orchestrator.options.maxCacheSize=1/0,null!==this._orchestrator.fileSize?e.targetPos=this._orchestrator.fileSize:(e.targetPos=1/0,e.strictTarget=!1),this._orchestrator.consolidateEverythingIntoOneWorker(e)}if(!s.body)throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream.");const a=s.body.getReader();for(;;){if(e.currentPos>=e.targetPos||e.aborted)return n.abort(),void this._orchestrator.signalWorkerStoppedRunning(e);let t;try{t=yield a.read()}catch(r){if(this._disposed)throw r;const e=this._getRetryDelay(1,r,this._url);if(null!==e){console.error("Error while reading response stream. Attempting to resume.",r),yield Pe(1e3*e);break}throw r}if(e.aborted)continue;const{done:i,value:s}=t;if(i){if(e.currentPos>=e.targetPos)return void this._orchestrator.onWorkerFinished(e);if(e.strictTarget)break;return void this._orchestrator.onWorkerFinished(e)}this._dispatchRead(e.currentPos,e.currentPos+s.length),this._orchestrator.supplyWorkerData(e,s)}}})}_dispose(){this._orchestrator.dispose()}}class Nn extends xn{constructor(e,t={}){var i;if(!(e instanceof ReadableStream))throw new TypeError("stream must be a ReadableStream.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.maxCacheSize&&(!ye(t.maxCacheSize)||t.maxCacheSize<0))throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number.");super(),this._reader=null,this._cache=[],this._pendingSlices=[],this._currentIndex=0,this._targetIndex=0,this._maxRequestedIndex=0,this._endIndex=null,this._pulling=!1,this._stream=e,this._maxCacheSize=null!=(i=t.maxCacheSize)?i:16*o(2,20)}_getFileSize(){return this._endIndex}_read(e,t){if(null!==this._endIndex&&t>this._endIndex)return null;this._maxRequestedIndex=Math.max(this._maxRequestedIndex,t);const i=z(this._cache,e,e=>e.start),r=-1!==i?this._cache[i]:null;if(r&&r.start<=e&&t<=r.end)return{bytes:r.bytes,view:r.view,offset:r.start};let n=e;const s=new Uint8Array(t-e);if(-1!==i)for(let c=i;c=t)break;const r=Math.max(e,i.start);r>n&&this._throwDueToCacheMiss();const a=Math.min(t,i.end);rn&&this._throwDueToCacheMiss();const{promise:a,resolve:o,reject:l}=q();return this._pendingSlices.push({start:e,end:t,bytes:s,resolve:o,reject:l}),this._targetIndex=Math.max(this._targetIndex,t),this._pulling||(this._pulling=!0,this._pull().catch(e=>{if(this._pulling=!1,!(this._pendingSlices.length>0))throw e;this._pendingSlices.forEach(t=>t.reject(e)),this._pendingSlices.length=0})),a}_throwDueToCacheMiss(){throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache.")}_pull(){return d(this,null,function*(){for(null!=this._reader||(this._reader=this._stream.getReader());this._currentIndex0;){const e=this._cache[0];if(this._maxRequestedIndex-e.end<=this._maxCacheSize)break;this._cache.shift()}this._currentIndex+=t.byteLength}this._pulling=!1})}_dispose(){var e;this._pendingSlices.length=0,this._cache.length=0,null==(e=this._reader)||e.cancel()}}const On={fileSystem:(e,t)=>{const i=o(2,16);return{start:e=Math.floor((e-i)/i)*i,end:t=Math.ceil((t+i)/i)*i}},network:(e,t,i)=>{const r=o(2,16);e=Math.max(0,Math.floor((e-r)/r)*r);for(const n of i){const i=8*o(2,20),r=Math.max((n.startPos+n.targetPos)/2,n.targetPos-i);if(pe(e,t,r,n.targetPos)){const e=n.targetPos-n.startPos,r=Math.ceil((e+1)/i)*i,s=o(2,Math.ceil(Math.log2(e+1))),a=Math.min(s,r);t=Math.max(t,n.startPos+a)}}return{start:e,end:t=Math.max(t,e+Fn)}}};class Ln{constructor(e){this.options=e,this.fileSize=null,this.nextAge=0,this.workers=[],this.cache=[],this.currentCacheSize=0,this.disposed=!1,this.queuedReads=[]}read(e,t,i,r){var n;y(!this.disposed);const s=this.options.prefetchProfile(e,t,this.workers),a=Math.max(s.start,i),o=Math.min(s.end,null!=(n=this.fileSize)?n:1/0,r);y(a<=e&&t<=o);let l=null;const c=z(this.cache,e,e=>e.start),u=-1!==c?this.cache[c]:null;u&&u.start<=e&&t<=u.end&&(u.age=this.nextAge++,l={bytes:u.bytes,view:u.view,offset:u.start});const d=z(this.cache,a,e=>e.start),h=l?null:new Uint8Array(t-e);let f=0,m=a;const p=[];if(-1!==d){for(let i=d;i=o)break;if(r.end<=a)continue;const n=Math.max(a,r.start),s=Math.min(o,r.end);if(y(n<=s),m=h.length&&(l={bytes:h,view:P(h),offset:e}),0===p.length)return y(l),l;const{promise:g,resolve:k,reject:b}=q(),T=[];for(const y of p){const i=Math.max(e,y.start),r=Math.min(t,y.end);i===y.start&&r===y.end?T.push(y):ie.hole.start),i=-1!==t?this.queuedReads[t]:null;for(i&&y.start<=i.hole.end?(i.hole.end=Math.max(i.hole.end,y.end),i.strictTarget&&(i.strictTarget=e),S&&i.pendingSlices.push(S)):(t++,i={hole:{start:y.start,end:y.end},strictTarget:e,pendingSlices:S?[S]:[],age:this.nextAge++},this.queuedReads.splice(t,0,i));t+1i.hole.end)break;i.hole.end=Math.max(i.hole.end,e.hole.end),i.pendingSlices.push(...e.pendingSlices),i.strictTarget&&(i.strictTarget=e.strictTarget),i.age=Math.min(i.age,e.age),this.queuedReads.splice(t+1,1)}}}return l||(y(h),l=g.then(t=>t&&{bytes:t,view:P(t),offset:e})),l}checkHoleAgainstWorker(e,t,i){const r=o(2,17);if(pe(t.start-r,t.start,e.currentPos,e.targetPos)){e.targetPos=Math.max(e.targetPos,t.end);for(let t=0;t=this.options.maxWorkerCount){let e=null,t=null;for(let i=0;i{if(e.running=!1,!(e.pendingSlices.length>0))throw t;e.pendingSlices.forEach(e=>e.reject(t)),e.pendingSlices.length=0}).finally(()=>{if(!e.running&&this.queuedReads.length>0){let e=0;for(let r=1;re.targetPos&&(e.targetPos=e.currentPos,this.checkQueuedReadsAgainstWorker(e));for(let n=0;nt.start&&(t.start=r),t.end<=t.start&&(s.holes.splice(e,1),e--)}0===s.holes.length&&(s.resolve(s.bytes),e.pendingSlices.splice(n,1),n--)}for(let n=0;ne){r.resolve(null),t.pendingSlices.splice(i,1),i--;break}}}for(let t=0;t=e){for(const e of i.pendingSlices)e.resolve(null);this.queuedReads.splice(t,1),t--}else if(i.hole.end>e){i.hole.end=e,i.strictTarget=!0;for(let t=0;t=e&&(r.resolve(null),i.pendingSlices.splice(t,1),t--)}}}}signalWorkerStoppedRunning(e){e.running=!1,e.pendingSlices.length=0}onWorkerFinished(e){const t=this.workers.indexOf(e);y(-1!==t),e.running=!1,this.workers.splice(t,1),null===this.fileSize&&this.supplyFileSize(e.currentPos);for(const i of e.pendingSlices)i.resolve(null)}insertIntoCache(e){if(0===this.options.maxCacheSize)return;let t=z(this.cache,e.start,e=>e.start)+1;if(t>0){const i=this.cache[t-1];if(i.end>=e.end)return;if(i.end>e.start){const r=new Uint8Array(e.end-i.start);r.set(i.bytes,0),r.set(e.bytes,e.start-i.start),this.currentCacheSize+=e.end-i.end,i.bytes=r,i.view=P(r),i.end=e.end,t--,e=i}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length}else this.cache.splice(t,0,e),this.currentCacheSize+=e.bytes.length;for(let i=t+1;i=t.end){this.cache.splice(i,1),this.currentCacheSize-=t.bytes.length,i--;continue}const r=new Uint8Array(t.end-e.start);r.set(e.bytes,0),r.set(t.bytes,t.start-e.start),this.currentCacheSize-=e.end-t.start,e.bytes=r,e.view=P(r),e.end=t.end,this.cache.splice(i,1);break}for(;this.currentCacheSize>this.options.maxCacheSize;){let e=0,t=this.cache[0];for(let i=1;ithis._length)return null;const n=this._baseSource._read(this._offset+e,this._offset+t,this._offset+i,this._offset+r);return n instanceof Promise?n.then(e=>e?(e.offset-=this._offset,e):null):n?(n.offset-=this._offset,n):null}_dispose(){var e;null==(e=this._ref)||e.free()}ref(){return null!=this._ref||(this._ref=this._baseSource.ref()),super.ref()}}var Un=function(e,t,i){if(null!==t&&void 0!==t){if("object"!==typeof t&&"function"!==typeof t)throw new TypeError("Object expected.");var r,n;if(i){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");r=t[Symbol.asyncDispose]}if(void 0===r){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");r=t[Symbol.dispose],i&&(n=r)}if("function"!==typeof r)throw new TypeError("Object not disposable.");n&&(r=function(){try{n.call(this)}catch(e){return Promise.reject(e)}}),e.stack.push({value:t,dispose:r,async:i})}else i&&e.stack.push({async:!0});return t},qn=function(e){return function(t){function i(i){t.error=t.hasError?new e(i,t.error,"An error was suppressed during disposal."):i,t.hasError=!0}var r,n=0;return function e(){for(;r=t.stack.pop();)try{if(!r.async&&1===n)return n=0,t.stack.push(r),Promise.resolve().then(e);if(r.dispose){var s=r.dispose.call(r.value);if(r.async)return n|=2,Promise.resolve(s).then(e,function(t){return i(t),e()})}else n|=1}catch(a){i(a)}if(1===n)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}()}}("function"===typeof SuppressedError?SuppressedError:function(e,t,i){var r=new Error(i);return r.name="SuppressedError",r.error=e,r.suppressed=t,r});const Wn=/^0[xX][0-9a-fA-F]+$/,Vn=/^data:.*;base64,/i;class Hn extends Sn{constructor(e,t,i,r){super(e.input,t,i),this.segments=[],this.nextLines=null,this.currentUpdateSegmentsPromise=null,this.streamHasEnded=!1,this.lastSegmentUpdateTime=-1/0,this.refreshInterval=5,this.demuxer=e,this.nextLines=r}runUpdateSegments(){var e;return null!=(e=this.currentUpdateSegmentsPromise)?e:this.currentUpdateSegmentsPromise=(()=>d(this,null,function*(){try{const e=this.getRemainingWaitTimeMs();e>0&&(yield Pe(e)),this.lastSegmentUpdateTime=performance.now(),yield this.updateSegments()}finally{this.currentUpdateSegmentsPromise=null}}))()}getRemainingWaitTimeMs(){const e=performance.now()-this.lastSegmentUpdateTime,t=Math.max(0,1e3*this.refreshInterval-e);return t<=50?0:t}updateSegments(){return d(this,null,function*(){var e,t,i,r,n,s,a;let l=this.nextLines;if(this.nextLines=null,!l){const e={stack:[],error:void 0,hasError:!1};try{const t=Un(e,yield this.demuxer.input._getSourceUncached({path:this.path,isRoot:!1}),!1),i=new wa(t.source),r=yield i.requestEntireFile();y(r),l=Va(r,r.length,{ignore:bn})}catch(E){e.error=E,e.hasError=!0}finally{qn(e)}}let d=!1,h=0,f=null,m=null,p=0,g=null,k=null,b=null,S=null,v=null,w=null,I=!1,x=null!=(e=T(this.segments))?e:null;const C=e=>{const t=e.indexOf("@"),i=Number(-1===t?e:e.slice(0,t));if(!Number.isInteger(i)||i<0)throw new Error(`Invalid #EXT-X-BYTERANGE length '${e}'.`);let r=null;if(-1!==t&&(r=Number(e.slice(t+1)),!Number.isInteger(r)||r<0))throw new Error(`Invalid #EXT-X-BYTERANGE offset '${e}'.`);return{length:i,offset:r}},B=e=>{p=e,x&&(y(null!==x.sequenceNumber),x.sequenceNumber0&&null!==w&&(h=p*w),I=!0);const t=e.slice(8),i=t.indexOf(","),r=-1===i?t:t.slice(0,i),n=Number(r);if(!Number.isFinite(n)||n<0)throw new Error(`Invalid #EXTINF tag duration '${r}'.`);f=n}else if(e.startsWith(hn)){const t=new Tn(e.slice(11)),i=t.get("uri");if(!i)throw new Error("Invalid #EXT-X-MAP tag; missing URI attribute.");const s=t.get("byterange");let a=null;if(null!==s&&(a=C(s)),a&&null===a.offset)throw new Error("Invalid #EXT-X-MAP tag; BYTERANGE attribute must have a specified offset.");if(!x){const e={path:be(this.path,i),offset:null!=(r=null==a?void 0:a.offset)?r:0,length:null!=(n=null==a?void 0:a.length)?n:null};if("AES-128"===(null==m?void 0:m.method)&&!m.iv)throw new Error("IV attribute must be set on #EXT-X-KEY tag preceding the #EXT-X-MAP tag.");k={timestamp:h,relativeToUnixEpoch:null!==v,firstSegment:null,sequenceNumber:null,location:e,duration:0,encryption:m,initSegment:null,lastProgramDateTimeSeconds:v}}f=null,null===S?b=null:S=null}else if(e.startsWith(fn)){const t=new Tn(e.slice(11)),i=t.get("method");if("NONE"===i)m=null;else if("AES-128"===i){const e=t.get("uri");if(!e)throw new Error("Invalid #EXT-X-KEY: AES-128 requires a URI attribute.");let i=null;const r=t.get("iv");if(r){if(!Wn.test(r))throw new Error(`Unsupported IV format '${r}'.`);let e=r.slice(2);e=e.padStart(32,"0"),i=new Uint8Array(ai);for(let t=0;t=8&&112===i[4]&&115===i[5]&&115===i[6]&&104===i[7]){const e=P(i).getUint32(0);r=Jt(i.subarray(8,Math.min(e,i.length)))}}m={method:i,psshBox:r}}}}else if(e.startsWith(mn)){const t=e.slice(22),i=Number(t);if(!Number.isInteger(i)||i<0)throw new Error(`Invalid EXT-X-MEDIA-SEQUENCE value '${t}'.`);B(i)}else if(e.startsWith(pn)){const t=C(e.slice(17));if(null===t.offset){if(null===b)throw new Error("Invalid M3U8 file; #EXT-X-BYTERANGE without offset requires a previous byte range.");t.offset=b}S=t,b=t.offset+t.length}else if(e.startsWith(gn)){if(x)continue;const t=e.slice(25),i=Date.parse(t);if(!Number.isFinite(i))continue;const r=i/1e3;if(v===r)continue;if(null===v&&this.segments.length>0){const e=T(this.segments),t=r-(e.timestamp+e.duration);for(const i of this.segments)i.timestamp+=t,i.relativeToUnixEpoch=!0;h+=t}v=r,h=r}else if("#EXT-X-DISCONTINUITY"===e)g=null;else if(e.startsWith(kn)){const t=e.slice(22),i=Number(t);if(!Number.isFinite(i)||i<0)throw new Error(`Invalid EXT-X-TARGETDURATION value '${t}'.`);this.refreshInterval=i,w=i}else{if("#EXT-X-ENDLIST"===e){this.streamHasEnded=!0;break}if(e.startsWith(yn)){"vod"===e.slice(21).toLowerCase()&&(this.streamHasEnded=!0)}}}else{if("#EXTM3U"!==e)throw new Error("Invalid M3U8 file; expected first line to be #EXTM3U.");d=!0}}if(!d)throw new Error("Invalid M3U8 file; no #EXTM3U header.")})}getFirstSegment(){return d(this,null,function*(){var e;return 0===this.segments.length&&(yield this.runUpdateSegments()),null!=(e=this.segments[0])?e:null})}getSegmentAt(e,t){return d(this,null,function*(){0===this.segments.length&&(yield this.runUpdateSegments());let i=!!t.skipLiveWait&&this.getRemainingWaitTimeMs()>0;for(;;){const r=z(this.segments,e,e=>e.timestamp);if(-1===r)return null;if(r0;for(;;){if(re.segment===r);if(n)return n.age=this.nextInputCacheAge++,n.input;let s=null;(r.initSegment||r.firstSegment)&&(s=this.getInputForSegment(null!=(t=r.initSegment)?t:r.firstSegment));const a=u(c({},this.input._formatOptions),{isobmff:u(c({},this.input._formatOptions.isobmff),{resolveKeyId:(null==(i=this.input._formatOptions.isobmff)?void 0:i.resolveKeyId)&&(e=>{if(!r.encryption||"SAMPLE-AES"!==r.encryption.method&&"SAMPLE-AES-CTR"!==r.encryption.method||!r.encryption.psshBox)return this.input._formatOptions.isobmff.resolveKeyId(e);let t=e.psshBoxes;const{psshBox:i}=r.encryption;return null!==i.keyIds&&!i.keyIds.includes(e.keyId)||t.some(e=>Zt(e,i))||(t=[...t,i]),this.input._formatOptions.isobmff.resolveKeyId(u(c({},e),{psshBoxes:t}))})})}),l=new Ta({source:new _n(r.location.path,e=>d(this,null,function*(){var t,i;y(e.isRoot);const n=u(c({},e),{isRoot:!1});let s;const a=r.location.offset>0||null!==r.location.length;if(r.encryption&&"SAMPLE-AES"!==r.encryption.method&&"SAMPLE-AES-CTR"!==r.encryption.method)if("AES-128"===r.encryption.method){const e=r.encryption;y(e.iv);let t=yield this.input._getSourceCached(n);if(a){const e=t.source.slice(r.location.offset,null!=(i=r.location.length)?i:void 0).ref();t.free(),t=e}const l=((e,t,i)=>{let r=!1,n=0;const s=o(2,16),a=new pi;return new ReadableStream({pull:o=>d(null,null,function*(){r||(a.init(yield t()),r=!0);const l=s+16;let c=e.requestSliceRange(n,0,l);if(c instanceof Promise&&(c=yield c),!c||0===c.length)throw new Error("Invalid ciphertext.");const u=c.length;if(u%16!==0)throw new Error("Invalid ciphertext.");const d=u===l?u-16:u,h=xa(c,d),f=new Uint8Array(d);for(let e=0;e16)throw new Error("Invalid PKCS#7 padding. Incorrect key or corrupted data.");const t=f.subarray(0,d-e);o.enqueue(t),o.close(),i()}}),cancel:()=>{i()}})})(new wa(t.source),()=>d(this,null,function*(){const t={stack:[],error:void 0,hasError:!1};try{const i=Un(t,yield this.input._getSourceCached({path:e.keyUri,isRoot:!1},ya),!1),r=new wa(i.source),n=yield r.requestSlice(0,ai);if(!n)throw new Error("Invalid AES-128 key; expected at least 16 bytes of data.");return{key:xa(n,ai),iv:e.iv}}catch(i){t.error=i,t.hasError=!0}finally{qn(t)}}),()=>{t.free()});s=new Nn(l).ref()}else y(!1);else if(s=yield this.input._getSourceCached(n),a){const e=s.source.slice(r.location.offset,null!=(t=r.location.length)?t:void 0).ref();s.free(),s=e}return s})),formats:this.input._formats.filter(e=>!(e instanceof us)),initInput:null!=s?s:void 0,formatOptions:a});l._onFormatDetermined=e=>{var t,i;if(("SAMPLE-AES"===(null==(t=r.encryption)?void 0:t.method)||"SAMPLE-AES-CTR"===(null==(i=r.encryption)?void 0:i.method))&&!e._isIsobmff)throw new Error("The SAMPLE-AES and SAMPLE-AES-CTR encryption methods are currently only supported for ISOBMFF files.")},this.inputCache.push({segment:r,input:l,age:this.nextInputCacheAge++});if(this.inputCache.length>4){const e=Se(this.inputCache,e=>e.age);y(-1!==e),this.inputCache.splice(e,1)}return l}getLiveRefreshInterval(){return d(this,null,function*(){return 0===this.getRemainingWaitTimeMs()&&(yield this.runUpdateSegments()),this.streamHasEnded?null:this.refreshInterval})}}class Kn extends Qt{constructor(e){super(e),this.metadataPromise=null,this.trackBackings=null,this.internalTracks=null,this.segmentedInputs=[],this.hasMasterPlaylist=!0}readMetadata(){var e;return null!=(e=this.metadataPromise)?e:this.metadataPromise=(()=>d(this,null,function*(){y(this.input._rootSource instanceof Bn);const{rootPath:e}=this.input._rootSource,t=yield this.input._reader.requestEntireFile();y(t);const i=Va(t,t.length,{ignore:bn}),r=[],n=[];for(let u=1;u"video"===e.attributes.get("type").toLowerCase()).map(e=>e.attributes.get("group-id")))],a=[...new Set(n.filter(e=>"audio"===e.attributes.get("type").toLowerCase()).map(e=>e.attributes.get("group-id")))],o=yield Promise.all(r.map((t,i)=>d(this,null,function*(){var r,o,l,c;const u=[],h=t.attributes.get("codecs");let f;if(h)f=h.split(",").map(e=>e.trim());else{const e=this.getSegmentedInputForPath(t.fullPath),i=yield e.getTrackBackings(),r=yield Promise.all(i.map(e=>d(this,null,function*(){return{track:e,codec:yield e.getCodec()}})));f=yield Promise.all(r.filter(e=>null!==e.codec).map(e=>e.track.getDecoderConfig().then(e=>e.codec)))}const m=t.attributes.get("video"),p=t.attributes.get("audio"),g=f.some(e=>Re.includes(Ke(e))),k=f.some(e=>Me.includes(Ke(e)));if(null!==m&&!g){if(!s.includes(m))throw new Error(`Invalid M3U8 file; variant stream references video group "${m}" which is not defined in any #EXT-X-MEDIA tags.`);const t=n.find(e=>{const t=e.attributes.get("group-id"),i=e.attributes.get("type");return t===m&&"video"===i.toLowerCase()});e:if(t){const i=t.attributes.get("uri");if(null===i)break e;const r=be(e,i),n=this.getSegmentedInputForPath(r),s=(yield n.getTrackBackings()).find(e=>"video"===e.getType());if(!s||null===(yield s.getCodec()))break e;const a=yield s.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null});y(null!==a),f.push(a)}}if(null!==p&&!k){if(!a.includes(p))throw new Error(`Invalid M3U8 file; variant stream references audio group "${p}" which is not defined in any #EXT-X-MEDIA tags.`);const t=n.find(e=>{const t=e.attributes.get("group-id"),i=e.attributes.get("type");return t===p&&"audio"===i.toLowerCase()});e:if(t){const i=t.attributes.get("uri");if(null===i)break e;const r=be(e,i),n=this.getSegmentedInputForPath(r),s=(yield n.getTrackBackings()).find(e=>"audio"===e.getType());if(!s||null===(yield s.getCodec()))break e;const a=yield s.getDecoderConfig().then(e=>{var t;return null!=(t=null==e?void 0:e.codec)?t:null});y(null!==a),f.push(a)}}f=[...new Set(f)];let b=null,T=null;const S=t.attributes.getAsNumber("bandwidth");y(null!==S);const v=t.attributes.getAsNumber("average-bandwidth"),w=t.attributes.get("name");for(const e of f){const d=Ke(e);if(null!==d)if(Re.includes(d)){if(null!==b)throw new Error("Unsupported M3U8 file; multiple video codecs found in the CODECS attribute of a variant stream.");b=e;const a=t.attributes.get("video");if(null===a){const e=t.attributes.get("resolution");let r=null,n=null;if(e){const t=e.match(/^(\d+)x(\d+)$/);t&&(r=Number(t[1]),n=Number(t[2]))}u.push({id:-1,demuxer:this,backingTrack:null,default:!0,autoselect:!0,languageCode:Q,lineNumber:t.lineNumber,fullPath:t.fullPath,fullCodecString:b,pairingMask:BigInt("1")<0?r:null}})}else{if(!a.includes(r))throw new Error(`Invalid M3U8 file; variant stream references audio group "${r}" which is not defined in any #EXT-X-MEDIA tags.`);for(const e of n){const n=e.attributes.get("group-id"),s=e.attributes.get("type");if(n!==r||"audio"!==s.toLowerCase())continue;const a=null!=(l=e.attributes.get("channels"))?l:t.attributes.get("channels"),o=null!==a?Number(a.split("/")[0]):null;u.push({id:-1,demuxer:this,backingTrack:null,default:Qn(e.attributes),autoselect:Qn(e.attributes)||Gn(e.attributes),languageCode:Yn(e.attributes.get("language")),lineNumber:e.lineNumber,fullPath:null!=(c=e.fullPath)?c:t.fullPath,fullCodecString:T,pairingMask:BigInt("1")<0?o:null}})}}}}return u}))),l=[],c=e=>{var t,i;const r=l.find(t=>t.fullPath===e.fullPath&&t.info.type===e.info.type);r?(r.pairingMask|=e.pairingMask,r.default||(r.default=e.default),r.autoselect||(r.autoselect=e.autoselect),r.lineNumber=Math.min(r.lineNumber,e.lineNumber),null!==e.peakBitrate&&(r.peakBitrate=Math.max(null!=(t=r.peakBitrate)?t:-1/0,e.peakBitrate)),null!==e.averageBitrate&&(r.averageBitrate=Math.max(null!=(i=r.averageBitrate)?i:-1/0,e.averageBitrate)),r.languageCode===Q&&(r.languageCode=e.languageCode)):(e.id=l.length+1,l.push(e))};for(const u of o)for(const e of u)c(e);l.sort((e,t)=>e.lineNumber-t.lineNumber),this.trackBackings=[];for(const u of l)"video"===u.info.type?this.trackBackings.push(new Xn(u)):this.trackBackings.push(new $n(u));this.internalTracks=l}))()}getTrackBackings(){return d(this,null,function*(){return yield this.readMetadata(),y(this.trackBackings),this.trackBackings})}getSegmentedInputForPath(e){let t=this.segmentedInputs.find(t=>t.path===e);if(t)return t;let i=null;if(this.internalTracks){i=this.internalTracks.filter(t=>t.fullPath===e).map(e=>({id:e.id,type:e.info.type}))}return t=new Hn(this,e,i,null),this.segmentedInputs.push(t),t}getMetadataTags(){return d(this,null,function*(){return{}})}getMimeType(){return d(this,null,function*(){return on})}dispose(){if(this.segmentedInputs){for(const e of this.segmentedInputs)e.dispose();this.segmentedInputs.length=0}}}class jn{constructor(e){this.internalTrack=e,this.hydrationPromise=null}hydrate(){var e;return null!=(e=this.hydrationPromise)?e:this.hydrationPromise=(()=>d(this,null,function*(){const e=this.internalTrack.demuxer.getSegmentedInputForPath(this.internalTrack.fullPath);let t=null;const i=(yield e.getTrackBackings()).filter(e=>e.getType()===this.getType());if(1===i.length)t=i[0];else if(this instanceof Xn){for(const r of i)if((yield r.getCodec())===this.getCodec()){t=r;break}}else{y(this instanceof $n);for(const e of i)if((yield e.getCodec())===this.getCodec()){t=e;break}}if(!t)throw new Error("Could not find matching track in underlying media data.");this.internalTrack.backingTrack=t}))()}delegate(e){return this.internalTrack.backingTrack?e():this.hydrate().then(e)}getCodec(){throw new Error("Not implemented on base class.")}getDisposition(){return u(c({},Be),{default:this.internalTrack.autoselect,primary:this.internalTrack.default})}getId(){return this.internalTrack.id}getPairingMask(){return this.internalTrack.pairingMask}getInternalCodecId(){return null}getLanguageCode(){return this.internalTrack.languageCode}getName(){return this.internalTrack.name}getNumber(){y(this.internalTrack.demuxer.internalTracks);const e=this.internalTrack.info.type;let t=0;for(const i of this.internalTrack.demuxer.internalTracks)if(i.info.type===e&&t++,i===this.internalTrack)break;return t}getTimeResolution(){return this.delegate(()=>this.internalTrack.backingTrack.getTimeResolution())}isRelativeToUnixEpoch(){return this.delegate(()=>this.internalTrack.backingTrack.isRelativeToUnixEpoch())}getBitrate(){return this.internalTrack.peakBitrate}getAverageBitrate(){return this.internalTrack.averageBitrate}getDurationFromMetadata(e){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getDurationFromMetadata(e)})}getLiveRefreshInterval(){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getLiveRefreshInterval()})}getHasOnlyKeyPackets(){return this.internalTrack.hasOnlyKeyPackets||null}getFirstPacket(e){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getFirstPacket(e)})}getPacket(e,t){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getPacket(e,t)})}getKeyPacket(e,t){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getKeyPacket(e,t)})}getNextPacket(e,t){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getNextPacket(e,t)})}getNextKeyPacket(e,t){return d(this,null,function*(){return yield this.hydrate(),this.internalTrack.backingTrack.getNextKeyPacket(e,t)})}}class Xn extends jn{constructor(e){super(e)}get backingVideoTrack(){return this.internalTrack.backingTrack}getType(){return"video"}getCodec(){return Ke(this.internalTrack.fullCodecString)}getCodedWidth(){return this.delegate(()=>this.backingVideoTrack.getCodedWidth())}getCodedHeight(){return this.delegate(()=>this.backingVideoTrack.getCodedHeight())}getSquarePixelWidth(){return this.delegate(()=>this.backingVideoTrack.getSquarePixelWidth())}getSquarePixelHeight(){return this.delegate(()=>this.backingVideoTrack.getSquarePixelHeight())}getMetadataDisplayWidth(){return this.backingVideoTrack?null:this.internalTrack.info.width}getMetadataDisplayHeight(){return this.backingVideoTrack?null:this.internalTrack.info.height}getRotation(){return this.delegate(()=>this.backingVideoTrack.getRotation())}getColorSpace(){return d(this,null,function*(){return yield this.hydrate(),this.backingVideoTrack.getColorSpace()})}canBeTransparent(){return d(this,null,function*(){return yield this.hydrate(),this.backingVideoTrack.canBeTransparent()})}getMetadataCodecParameterString(){return this.backingVideoTrack?null:this.internalTrack.fullCodecString}getDecoderConfig(){return d(this,null,function*(){return yield this.hydrate(),this.backingVideoTrack.getDecoderConfig()})}}class $n extends jn{constructor(e){super(e)}get backingAudioTrack(){return this.internalTrack.backingTrack}getType(){return"audio"}getCodec(){return Ke(this.internalTrack.fullCodecString)}getNumberOfChannels(){return null!==this.internalTrack.info.numberOfChannels?this.internalTrack.info.numberOfChannels:this.delegate(()=>this.backingAudioTrack.getNumberOfChannels())}getSampleRate(){return this.delegate(()=>this.backingAudioTrack.getSampleRate())}getMetadataCodecParameterString(){return this.backingAudioTrack?null:this.internalTrack.fullCodecString}getDecoderConfig(){return d(this,null,function*(){return yield this.hydrate(),this.backingAudioTrack.getDecoderConfig()})}}const Qn=e=>{const t=e.get("default");if(null===t)return!1;const i=t.toUpperCase();if("YES"===i)return!0;if("NO"===i)return!1;throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA DEFAULT attribute must be YES or NO, got "${t}".`)},Gn=e=>{const t=e.get("autoselect");if(null===t)return!1;const i=t.toUpperCase();if("YES"===i)return!0;if("NO"===i)return!1;throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA AUTOSELECT attribute must be YES or NO, got "${t}".`)},Yn=e=>{if(null===e)return Q;const t=e.split("-")[0];return t||Q};class Jn{constructor(){this._isIsobmff=!1}}class Zn extends Jn{constructor(){super(...arguments),this._isIsobmff=!0}_getMajorBrand(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=yield t),!t)return null;t.skip(4);const i=Wa(t,4);return"ftyp"!==i&&"styp"!==i?null:Wa(t,4)})}_createDemuxer(e){return new gi(e)}}class es extends Zn{_canReadInput(e){return d(this,null,function*(){const t=yield this._getMajorBrand(e);if(null!==t)return"qt "!==t;let i=e._reader.requestSlice(4,4);return i instanceof Promise&&(i=yield i),!!i&&"moof"===Wa(i,4)})}get name(){return"MP4"}get mimeType(){return"video/mp4"}}class ts extends Zn{_canReadInput(e){return d(this,null,function*(){return"qt "===(yield this._getMajorBrand(e))})}get name(){return"QuickTime File Format"}get mimeType(){return"video/quicktime"}}class is extends Jn{isSupportedEBMLOfDocType(e,t){return d(this,null,function*(){let i=e._reader.requestSlice(0,Li);if(i instanceof Promise&&(i=yield i),!i)return!1;const r=zi(i);if(null===r)return!1;if(r<1||r>8)return!1;if(qi(i,r)!==Ri.EBML)return!1;const n=Vi(i);if("number"!==typeof n)return!1;let s=e._reader.requestSlice(i.filePos,n);if(s instanceof Promise&&(s=yield s),!s)return!1;const a=i.filePos;for(;s.filePos<=a+n-2;){const e=Hi(s);if(!e)break;const{id:i,size:r}=e,n=s.filePos;if(void 0===r)return!1;switch(i){case Ri.EBMLVersion:if(1!==qi(s,r))return!1;break;case Ri.EBMLReadVersion:if(1!==qi(s,r))return!1;break;case Ri.DocType:if(Ki(s,r)!==t)return!1;break;case Ri.DocTypeVersion:if(qi(s,r)>4)return!1}s.filePos=n+r}return!0})}_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"matroska")}_createDemuxer(e){return new kr(e)}get name(){return"Matroska"}get mimeType(){return"video/x-matroska"}}class rs extends is{_canReadInput(e){return this.isSupportedEBMLOfDocType(e,"webm")}get name(){return"WebM"}get mimeType(){return"video/webm"}}class ns extends Jn{_canReadInput(e){return d(this,null,function*(){let t=0;for(;;){let i=e._reader.requestSlice(t,Qa);if(i instanceof Promise&&(i=yield i),!i)break;const r=Za(i);if(!r)break;t=i.filePos+r.size}const i=yield Sr(e._reader,t,t+4096);if(!i)return!1;const r=i.header,n=Ge(r.mpegVersionId,r.channel);let s=e._reader.requestSlice(i.startPos+n,4);if(s instanceof Promise&&(s=yield s),!s)return!1;const a=Ra(s);if(a===$e||a===Qe)return!0;t=i.startPos+i.header.totalSize;const o=yield Sr(e._reader,t,t+4);if(!o)return!1;const l=o.header;return r.channel===l.channel&&r.sampleRate===l.sampleRate})}_createDemuxer(e){return new vr(e)}get name(){return"MP3"}get mimeType(){return"audio/mpeg"}}class ss extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,12);if(t instanceof Promise&&(t=yield t),!t)return!1;const i=Wa(t,4);if("RIFF"!==i&&"RIFX"!==i&&"RF64"!==i)return!1;t.skip(4);return"WAVE"===Wa(t,4)})}_createDemuxer(e){return new Lr(e)}get name(){return"WAVE"}get mimeType(){return"audio/wav"}}class as extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=yield t),!!t&&"OggS"===Wa(t,4)})}_createDemuxer(e){return new Fr(e)}get name(){return"Ogg"}get mimeType(){return"application/ogg"}}class os extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,4);return t instanceof Promise&&(t=yield t),!!t&&"fLaC"===Wa(t,4)})}get name(){return"FLAC"}get mimeType(){return"audio/flac"}_createDemuxer(e){return new Kr(e)}}class ls extends Jn{_canReadInput(e){return d(this,null,function*(){let t=0;for(;;){let i=e._reader.requestSlice(t,Qa);if(i instanceof Promise&&(i=yield i),!i)break;const r=Za(i);if(!r)break;t=i.filePos+r.size}let i=e._reader.requestSliceRange(t,7,9);if(i instanceof Promise&&(i=yield i),!i)return!1;const r=qr(i);if(!r)return!1;if(t+=r.frameLength,i=e._reader.requestSliceRange(t,7,9),i instanceof Promise&&(i=yield i),!i)return!1;const n=qr(i);return!!n&&(r.objectType===n.objectType&&r.samplingFrequencyIndex===n.samplingFrequencyIndex&&r.channelConfiguration===n.channelConfiguration)})}_createDemuxer(e){return new Vr(e)}get name(){return"ADTS"}get mimeType(){return"audio/aac"}}class cs extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,205);if(t instanceof Promise&&(t=yield t),!t)return!1;const i=xa(t,205);return 71===i[0]&&71===i[188]||(71===i[0]&&71===i[204]||71===i[4]&&71===i[196])})}_createDemuxer(e){return new Yr(e)}get name(){return"MPEG Transport Stream"}get mimeType(){return"video/MP2T"}}class us extends Jn{_canReadInput(e){return d(this,null,function*(){let t=e._reader.requestSlice(0,7);if(t instanceof Promise&&(t=yield t),!t)return!1;if(!("#EXTM3U"===Wa(t,7)))return!1;if(!(e._rootSource instanceof Bn))throw new TypeError("HLS inputs require `InputOptions.source` to be a PathedSource or a ref to one.");return e._rootSource._usedForHls=!0,!0})}_createDemuxer(e){return new Kn(e)}get name(){return"HTTP Live Streaming (HLS)"}get mimeType(){return on}}const ds=new es,hs=new ts,fs=new is,ms=new rs,ps=new ns,gs=new ss,ks=new as,ys=new ls,bs=new os,Ts=new cs,Ss=new us,vs=[Ss,ds,hs,fs,ms,gs,ks,bs,ps,ys,Ts],ws=[Ss,ds,hs,ps,ys,Ts];ke();let Ps=-1/0,Is=-1/0,xs=null;"undefined"!==typeof FinalizationRegistry&&(xs=new FinalizationRegistry(e=>{const t=performance.now();"video"===e.type?(t-Ps>=1e3&&(console.error("A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them."),Ps=t),"undefined"!==typeof VideoFrame&&e.data instanceof VideoFrame&&e.data.close()):(t-Is>=1e3&&(console.error("An AudioSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your AudioSamples as soon as you're done using them."),Is=t),"undefined"!==typeof AudioData&&e.data instanceof AudioData&&e.data.close())}));const Cs=["I420","I420P10","I420P12","I420A","I420AP10","I420AP12","I422","I422P10","I422P12","I422A","I422AP10","I422AP12","I444","I444P10","I444P12","I444A","I444AP10","I444AP12","NV12","RGBA","RGBX","BGRA","BGRX"],Bs=new Set(Cs);class Es{get codedWidth(){return this.visibleRect.width}get codedHeight(){return this.visibleRect.height}get displayWidth(){return this.rotation%180===0?this.squarePixelWidth:this.squarePixelHeight}get displayHeight(){return this.rotation%180===0?this.squarePixelHeight:this.squarePixelWidth}get microsecondTimestamp(){return Math.trunc(te*this.timestamp)}get microsecondDuration(){return Math.trunc(te*this.duration)}get hasAlpha(){return this.format&&this.format.includes("A")}constructor(e,t){var i,r,n,s,a,o,l,c,u,d,h,f,m,p,g,k,b,T,S,v,P,I,x,C,B,E;if(this._closed=!1,e instanceof ArrayBuffer||"undefined"!==typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer||ArrayBuffer.isView(e)){if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0===t.format||!Bs.has(t.format))throw new TypeError("init.format must be one of: "+Cs.join(", "));if(!Number.isInteger(t.codedWidth)||t.codedWidth<=0)throw new TypeError("init.codedWidth must be a positive integer.");if(!Number.isInteger(t.codedHeight)||t.codedHeight<=0)throw new TypeError("init.codedHeight must be a positive integer.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if(void 0!==t.layout){if(!Array.isArray(t.layout))throw new TypeError("init.layout, when provided, must be an array.");for(const e of t.layout){if(!e||"object"!==typeof e||Array.isArray(e))throw new TypeError("Each entry in init.layout must be an object.");if(!Number.isInteger(e.offset)||e.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(e.stride)||e.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==t.visibleRect&&we(t.visibleRect,"init.visibleRect"),void 0!==t.displayWidth&&(!Number.isInteger(t.displayWidth)||t.displayWidth<=0))throw new TypeError("init.displayWidth, when provided, must be a positive integer.");if(void 0!==t.displayHeight&&(!Number.isInteger(t.displayHeight)||t.displayHeight<=0))throw new TypeError("init.displayHeight, when provided, must be a positive integer.");if(void 0!==t.displayWidth!==(void 0!==t.displayHeight))throw new TypeError("init.displayWidth and init.displayHeight must be either both provided or both omitted.");this._data=w(e).slice(),this._layout=null!=(i=t.layout)?i:Ms(t.format,t.codedWidth,t.codedHeight),this.format=t.format,this.rotation=null!=(r=t.rotation)?r:0,this.timestamp=t.timestamp,this.duration=null!=(n=t.duration)?n:0,this.colorSpace=new _s(t.colorSpace),this.visibleRect={left:null!=(a=null==(s=t.visibleRect)?void 0:s.left)?a:0,top:null!=(l=null==(o=t.visibleRect)?void 0:o.top)?l:0,width:null!=(u=null==(c=t.visibleRect)?void 0:c.width)?u:t.codedWidth,height:null!=(h=null==(d=t.visibleRect)?void 0:d.height)?h:t.codedHeight},void 0!==t.displayWidth?(this.squarePixelWidth=this.rotation%180===0?t.displayWidth:t.displayHeight,this.squarePixelHeight=this.rotation%180===0?t.displayHeight:t.displayWidth):(this.squarePixelWidth=this.codedWidth,this.squarePixelHeight=this.codedHeight)}else if("undefined"!==typeof VideoFrame&&e instanceof VideoFrame){if(void 0!==(null==t?void 0:t.rotation)&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(void 0!==(null==t?void 0:t.timestamp)&&!Number.isFinite(null==t?void 0:t.timestamp))throw new TypeError("init.timestamp, when provided, must be a number.");if(void 0!==(null==t?void 0:t.duration)&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");void 0!==(null==t?void 0:t.visibleRect)&&we(t.visibleRect,"init.visibleRect"),this._data=e,this._layout=null,this.format=e.format,this.visibleRect={left:null!=(m=null==(f=e.visibleRect)?void 0:f.x)?m:0,top:null!=(g=null==(p=e.visibleRect)?void 0:p.y)?g:0,width:null!=(b=null==(k=e.visibleRect)?void 0:k.width)?b:e.codedWidth,height:null!=(S=null==(T=e.visibleRect)?void 0:T.height)?S:e.codedHeight},this.rotation=null!=(v=null==t?void 0:t.rotation)?v:0,this.squarePixelWidth=e.displayWidth,this.squarePixelHeight=e.displayHeight,this.timestamp=null!=(P=null==t?void 0:t.timestamp)?P:e.timestamp/1e6,this.duration=null!=(x=null==t?void 0:t.duration)?x:(null!=(I=e.duration)?I:0)/1e6,this.colorSpace=new _s(e.colorSpace)}else{if(!("undefined"!==typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!==typeof SVGImageElement&&e instanceof SVGImageElement||"undefined"!==typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!==typeof HTMLVideoElement&&e instanceof HTMLVideoElement||"undefined"!==typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!==typeof OffscreenCanvas&&e instanceof OffscreenCanvas))throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource.");{if(!t||"object"!==typeof t)throw new TypeError("init must be an object.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270.");if(!Number.isFinite(t.timestamp))throw new TypeError("init.timestamp must be a number.");if(void 0!==t.duration&&(!Number.isFinite(t.duration)||t.duration<0))throw new TypeError("init.duration, when provided, must be a non-negative number.");if("undefined"!==typeof VideoFrame)return new Es(new VideoFrame(e,{timestamp:Math.trunc(t.timestamp*te),duration:Math.trunc((null!=(C=t.duration)?C:0)*te)||void 0}),t);let i=0,r=0;if("naturalWidth"in e?(i=e.naturalWidth,r=e.naturalHeight):"videoWidth"in e?(i=e.videoWidth,r=e.videoHeight):"width"in e&&(i=Number(e.width),r=Number(e.height)),!i||!r)throw new TypeError("Could not determine dimensions.");const n=new OffscreenCanvas(i,r),s=n.getContext("2d",{alpha:ce(),willReadFrequently:!0});y(s),s.drawImage(e,0,0),this._data=n,this._layout=null,this.format="RGBX",this.visibleRect={left:0,top:0,width:i,height:r},this.squarePixelWidth=i,this.squarePixelHeight=r,this.rotation=null!=(B=t.rotation)?B:0,this.timestamp=t.timestamp,this.duration=null!=(E=t.duration)?E:0,this.colorSpace=new _s({matrix:"rgb",primaries:"bt709",transfer:"iec61966-2-1",fullRange:!0})}}this.pixelAspectRatio=ve({num:this.squarePixelWidth*this.codedHeight,den:this.squarePixelHeight*this.codedWidth}),null==xs||xs.register(this,{type:"video",data:this._data},this)}clone(){if(this._closed)throw new Error("VideoSample is closed.");return y(null!==this._data),As(this._data)?new Es(this._data.clone(),{timestamp:this.timestamp,duration:this.duration,rotation:this.rotation}):this._data instanceof Uint8Array?(y(this._layout),new Es(this._data,{format:this.format,layout:this._layout,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation,visibleRect:this.visibleRect,displayWidth:this.displayWidth,displayHeight:this.displayHeight})):new Es(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.timestamp,duration:this.duration,colorSpace:this.colorSpace,rotation:this.rotation,visibleRect:this.visibleRect,displayWidth:this.displayWidth,displayHeight:this.displayHeight})}close(){this._closed||(null==xs||xs.unregister(this),As(this._data)?this._data.close():this._data=null,this._closed=!0)}allocationSize(e={}){if(Ds(e),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot get allocation size when format is null. Sorry!");if(y(null!==this._data),!As(this._data)&&(e.colorSpace||e.format&&e.format!==this.format||e.layout||e.rect)){const t=this.toVideoFrame(),i=t.allocationSize(e);return t.close(),i}return As(this._data)?this._data.allocationSize(e):this._data instanceof Uint8Array?this._data.byteLength:this.codedWidth*this.codedHeight*4}copyTo(e){return d(this,arguments,function*(e,t={}){if(!R(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(Ds(t),this._closed)throw new Error("VideoSample is closed.");if(null===this.format)throw new Error("Cannot copy video sample data when format is null. Sorry!");if(y(null!==this._data),!As(this._data)&&(t.colorSpace||t.format&&t.format!==this.format||t.layout||t.rect)){const i=this.toVideoFrame(),r=yield i.copyTo(e,t);return i.close(),r}if(As(this._data))return this._data.copyTo(e,t);if(this._data instanceof Uint8Array){y(this._layout);return w(e).set(this._data),this._layout}{const t=this._data.getContext("2d");y(t);const i=t.getImageData(0,0,this.codedWidth,this.codedHeight);return w(e).set(i.data),[{offset:0,stride:4*this.codedWidth}]}})}toVideoFrame(){if(this._closed)throw new Error("VideoSample is closed.");return y(null!==this._data),As(this._data)?new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0}):this._data instanceof Uint8Array?new VideoFrame(this._data,{format:this.format,codedWidth:this.codedWidth,codedHeight:this.codedHeight,timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0,colorSpace:this.colorSpace}):new VideoFrame(this._data,{timestamp:this.microsecondTimestamp,duration:this.microsecondDuration||void 0})}draw(e,t,i,r,n,s,a,o,l){let c=0,u=0,d=this.displayWidth,h=this.displayHeight,f=0,m=0,p=this.displayWidth,g=this.displayHeight;if(void 0!==s?(c=t,u=i,d=r,h=n,f=s,m=a,void 0!==o?(p=o,g=l):(p=d,g=h)):(f=t,m=i,void 0!==r&&(p=r,g=n)),!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!Number.isFinite(c))throw new TypeError("sx must be a number.");if(!Number.isFinite(u))throw new TypeError("sy must be a number.");if(!Number.isFinite(d)||d<0)throw new TypeError("sWidth must be a non-negative number.");if(!Number.isFinite(h)||h<0)throw new TypeError("sHeight must be a non-negative number.");if(!Number.isFinite(f))throw new TypeError("dx must be a number.");if(!Number.isFinite(m))throw new TypeError("dy must be a number.");if(!Number.isFinite(p)||p<0)throw new TypeError("dWidth must be a non-negative number.");if(!Number.isFinite(g)||g<0)throw new TypeError("dHeight must be a non-negative number.");if(this._closed)throw new Error("VideoSample is closed.");({sx:c,sy:u,sWidth:d,sHeight:h}=this._rotateSourceRegion(c,u,d,h,this.rotation));const k=this.toCanvasImageSource();e.save();const y=f+p/2,b=m+g/2;e.translate(y,b),e.rotate(this.rotation*Math.PI/180);const T=this.rotation%180===0?1:p/g;e.scale(1/T,T),e.drawImage(k,c,u,d,h,-p/2,-g/2,p,g),e.restore()}drawWithFit(e,t){var i,r,n,s,a,o,l,c,u;if(!("undefined"!==typeof CanvasRenderingContext2D&&e instanceof CanvasRenderingContext2D||"undefined"!==typeof OffscreenCanvasRenderingContext2D&&e instanceof OffscreenCanvasRenderingContext2D))throw new TypeError("context must be a CanvasRenderingContext2D or OffscreenCanvasRenderingContext2D.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!["fill","contain","cover"].includes(t.fit))throw new TypeError("options.fit must be 'fill', 'contain', or 'cover'.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180, or 270.");void 0!==t.crop&&Rs(t.crop,"options.");const d=e.canvas.width,h=e.canvas.height,f=null!=(i=t.rotation)?i:this.rotation,[m,p]=f%180===0?[this.squarePixelWidth,this.squarePixelHeight]:[this.squarePixelHeight,this.squarePixelWidth];let g,k,y,b;t.crop&&Fs(t.crop,m,p);const{sx:T,sy:S,sWidth:v,sHeight:w}=this._rotateSourceRegion(null!=(n=null==(r=t.crop)?void 0:r.left)?n:0,null!=(a=null==(s=t.crop)?void 0:s.top)?a:0,null!=(l=null==(o=t.crop)?void 0:o.width)?l:m,null!=(u=null==(c=t.crop)?void 0:c.height)?u:p,f);if("fill"===t.fit)g=0,k=0,y=d,b=h;else{const[e,i]=t.crop?[t.crop.width,t.crop.height]:[m,p],r="contain"===t.fit?Math.min(d/e,h/i):Math.max(d/e,h/i);y=e*r,b=i*r,g=(d-y)/2,k=(h-b)/2}e.save();const P=f%180===0?1:y/b;e.translate(d/2,h/2),e.rotate(f*Math.PI/180),e.scale(1/P,P),e.translate(-d/2,-h/2),e.drawImage(this.toCanvasImageSource(),T,S,v,w,g,k,y,b),e.restore()}_rotateSourceRegion(e,t,i,r,n){return 90===n?[e,t,i,r]=[t,this.squarePixelHeight-e-i,r,i]:180===n?[e,t]=[this.squarePixelWidth-e-i,this.squarePixelHeight-t-r]:270===n&&([e,t,i,r]=[this.squarePixelWidth-t-r,e,r,i]),{sx:e,sy:t,sWidth:i,sHeight:r}}toCanvasImageSource(){if(this._closed)throw new Error("VideoSample is closed.");if(y(null!==this._data),this._data instanceof Uint8Array){const e=this.toVideoFrame();return queueMicrotask(()=>e.close()),e}return this._data}setRotation(e){if(![0,90,180,270].includes(e))throw new TypeError("newRotation must be 0, 90, 180, or 270.");this.rotation=e}setTimestamp(e){if(!Number.isFinite(e))throw new TypeError("newTimestamp must be a number.");this.timestamp=e}setDuration(e){if(!Number.isFinite(e)||e<0)throw new TypeError("newDuration must be a non-negative number.");this.duration=e}[Symbol.dispose](){this.close()}}class _s{constructor(e){var t,i,r,n;if(void 0!==e){if(!e||"object"!==typeof e)throw new TypeError("init.colorSpace, when provided, must be an object.");const t=Object.keys(C);if(null!=e.primaries&&!t.includes(e.primaries))throw new TypeError(`init.colorSpace.primaries, when provided, must be one of ${t.join(", ")}.`);const i=Object.keys(E);if(null!=e.transfer&&!i.includes(e.transfer))throw new TypeError(`init.colorSpace.transfer, when provided, must be one of ${i.join(", ")}.`);const r=Object.keys(A);if(null!=e.matrix&&!r.includes(e.matrix))throw new TypeError(`init.colorSpace.matrix, when provided, must be one of ${r.join(", ")}.`);if(null!=e.fullRange&&"boolean"!==typeof e.fullRange)throw new TypeError("init.colorSpace.fullRange, when provided, must be a boolean.")}this.primaries=null!=(t=null==e?void 0:e.primaries)?t:null,this.transfer=null!=(i=null==e?void 0:e.transfer)?i:null,this.matrix=null!=(r=null==e?void 0:e.matrix)?r:null,this.fullRange=null!=(n=null==e?void 0:e.fullRange)?n:null}toJSON(){return{primaries:this.primaries,transfer:this.transfer,matrix:this.matrix,fullRange:this.fullRange}}}const As=e=>"undefined"!==typeof VideoFrame&&e instanceof VideoFrame,Fs=(e,t,i)=>{const r=Math.min(e.left,t),n=Math.min(e.top,i),s=Math.min(e.width,t-r),a=Math.min(e.height,i-n);return y(s>=0),y(a>=0),{left:r,top:n,width:s,height:a}},Rs=(e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(t+"crop, when provided, must be an object.");if(!Number.isInteger(e.left)||e.left<0)throw new TypeError(t+"crop.left must be a non-negative integer.");if(!Number.isInteger(e.top)||e.top<0)throw new TypeError(t+"crop.top must be a non-negative integer.");if(!Number.isInteger(e.width)||e.width<0)throw new TypeError(t+"crop.width must be a non-negative integer.");if(!Number.isInteger(e.height)||e.height<0)throw new TypeError(t+"crop.height must be a non-negative integer.")},Ds=e=>{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.colorSpace&&!["display-p3","srgb"].includes(e.colorSpace))throw new TypeError("options.colorSpace, when provided, must be 'display-p3' or 'srgb'.");if(void 0!==e.format&&"string"!==typeof e.format)throw new TypeError("options.format, when provided, must be a string.");if(void 0!==e.layout){if(!Array.isArray(e.layout))throw new TypeError("options.layout, when provided, must be an array.");for(const t of e.layout){if(!t||"object"!==typeof t)throw new TypeError("Each entry in options.layout must be an object.");if(!Number.isInteger(t.offset)||t.offset<0)throw new TypeError("plane.offset must be a non-negative integer.");if(!Number.isInteger(t.stride)||t.stride<0)throw new TypeError("plane.stride must be a non-negative integer.")}}if(void 0!==e.rect){if(!e.rect||"object"!==typeof e.rect)throw new TypeError("options.rect, when provided, must be an object.");if(void 0!==e.rect.x&&(!Number.isInteger(e.rect.x)||e.rect.x<0))throw new TypeError("options.rect.x, when provided, must be a non-negative integer.");if(void 0!==e.rect.y&&(!Number.isInteger(e.rect.y)||e.rect.y<0))throw new TypeError("options.rect.y, when provided, must be a non-negative integer.");if(void 0!==e.rect.width&&(!Number.isInteger(e.rect.width)||e.rect.width<0))throw new TypeError("options.rect.width, when provided, must be a non-negative integer.");if(void 0!==e.rect.height&&(!Number.isInteger(e.rect.height)||e.rect.height<0))throw new TypeError("options.rect.height, when provided, must be a non-negative integer.")}},Ms=(e,t,i)=>{const r=Ns(e),n=[];let s=0;for(const a of r){const e=Math.ceil(t/a.widthDivisor),r=Math.ceil(i/a.heightDivisor),o=e*a.sampleBytes,l=o*r;n.push({offset:s,stride:o}),s+=l}return n},Ns=e=>{const t=(e,t,i,r,n)=>{const s=[{sampleBytes:e,widthDivisor:1,heightDivisor:1},{sampleBytes:t,widthDivisor:i,heightDivisor:r},{sampleBytes:t,widthDivisor:i,heightDivisor:r}];return n&&s.push({sampleBytes:e,widthDivisor:1,heightDivisor:1}),s};switch(e){case"I420":return t(1,1,2,2,!1);case"I420P10":case"I420P12":return t(2,2,2,2,!1);case"I420A":return t(1,1,2,2,!0);case"I420AP10":case"I420AP12":return t(2,2,2,2,!0);case"I422":return t(1,1,2,1,!1);case"I422P10":case"I422P12":return t(2,2,2,1,!1);case"I422A":return t(1,1,2,1,!0);case"I422AP10":case"I422AP12":return t(2,2,2,1,!0);case"I444":return t(1,1,1,1,!1);case"I444P10":case"I444P12":return t(2,2,1,1,!1);case"I444A":return t(1,1,1,1,!0);case"I444AP10":case"I444AP12":return t(2,2,1,1,!0);case"NV12":return[{sampleBytes:1,widthDivisor:1,heightDivisor:1},{sampleBytes:2,widthDivisor:2,heightDivisor:2}];case"RGBA":case"RGBX":case"BGRA":case"BGRX":return[{sampleBytes:4,widthDivisor:1,heightDivisor:1}];default:H(e),y(!1)}},Os=new Set(["f32","f32-planar","s16","s16-planar","s32","s32-planar","u8","u8-planar"]);class Ls{get microsecondTimestamp(){return Math.trunc(te*this.timestamp)}get microsecondDuration(){return Math.trunc(te*this.duration)}constructor(e){if(this._closed=!1,Vs(e)){if(null===e.format)throw new TypeError("AudioData with null format is not supported.");this._data=e,this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=e.numberOfFrames,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp/1e6,this.duration=e.numberOfFrames/e.sampleRate}else{if(!e||"object"!==typeof e)throw new TypeError("Invalid AudioDataInit: must be an object.");if(!Os.has(e.format))throw new TypeError("Invalid AudioDataInit: invalid format.");if(!Number.isFinite(e.sampleRate)||e.sampleRate<=0)throw new TypeError("Invalid AudioDataInit: sampleRate must be > 0.");if(!Number.isInteger(e.numberOfChannels)||0===e.numberOfChannels)throw new TypeError("Invalid AudioDataInit: numberOfChannels must be an integer > 0.");if(!Number.isFinite(null==e?void 0:e.timestamp))throw new TypeError("init.timestamp must be a number.");const t=e.data.byteLength/(zs(e.format)*e.numberOfChannels);if(!Number.isInteger(t))throw new TypeError("Invalid AudioDataInit: data size is not a multiple of frame size.");let i;if(this.format=e.format,this.sampleRate=e.sampleRate,this.numberOfFrames=t,this.numberOfChannels=e.numberOfChannels,this.timestamp=e.timestamp,this.duration=t/e.sampleRate,e.data instanceof ArrayBuffer)i=new Uint8Array(e.data);else{if(!ArrayBuffer.isView(e.data))throw new TypeError("Invalid AudioDataInit: data is not a BufferSource.");i=new Uint8Array(e.data.buffer,e.data.byteOffset,e.data.byteLength)}const r=this.numberOfFrames*this.numberOfChannels*zs(this.format);if(i.byteLength=this.numberOfFrames)throw new RangeError("frameOffset out of range");const s=void 0!==e.frameCount?e.frameCount:this.numberOfFrames-n;if(s>this.numberOfFrames-n)throw new RangeError("frameCount out of range");const a=zs(r),o=Us(r);if(o&&e.planeIndex>=this.numberOfChannels)throw new RangeError("planeIndex out of range");if(!o&&0!==e.planeIndex)throw new RangeError("planeIndex out of range");return(o?s:s*this.numberOfChannels)*a}copyTo(e,t){if(!R(e))throw new TypeError("destination must be an ArrayBuffer or an ArrayBuffer view.");if(!t||"object"!==typeof t)throw new TypeError("options must be an object.");if(!Number.isInteger(t.planeIndex)||t.planeIndex<0)throw new TypeError("planeIndex must be a non-negative integer.");if(void 0!==t.format&&!Os.has(t.format))throw new TypeError("Invalid format.");if(void 0!==t.frameOffset&&(!Number.isInteger(t.frameOffset)||t.frameOffset<0))throw new TypeError("frameOffset must be a non-negative integer.");if(void 0!==t.frameCount&&(!Number.isInteger(t.frameCount)||t.frameCount<0))throw new TypeError("frameCount must be a non-negative integer.");if(this._closed)throw new Error("AudioSample is closed.");const{planeIndex:i,format:r,frameCount:n,frameOffset:s}=t,a=this.format,o=null!=r?r:this.format;if(!o)throw new Error("Destination format not determined");const l=this.numberOfFrames,c=this.numberOfChannels,u=null!=s?s:0;if(u>=l)throw new RangeError("frameOffset out of range");const d=void 0!==n?n:l-u;if(d>l-u)throw new RangeError("frameCount out of range");const h=zs(o),f=Us(o);if(f&&i>=c)throw new RangeError("planeIndex out of range");if(!f&&0!==i)throw new RangeError("planeIndex out of range");const m=(f?d:d*c)*h;if(e.byteLength2&&o!==a?Hs(this._data,p,a,o,c,i,u,d):this._data.copyTo(e,{planeIndex:i,frameOffset:u,frameCount:d,format:o});else{const e=this._data,t=P(e),r=qs(a),n=zs(a),s=Us(a);for(let a=0;a0;){const n=Math.min(s,o),l=new Float32Array(i*n);for(let t=0;t0;){const n=Math.min(s,o),c=new Float32Array(i*n);for(let t=0;t{switch(e){case"u8":case"u8-planar":return 1;case"s16":case"s16-planar":return 2;case"s32":case"s32-planar":case"f32":case"f32-planar":return 4;default:throw new Error("Unknown AudioSampleFormat")}},Us=e=>{switch(e){case"u8-planar":case"s16-planar":case"s32-planar":case"f32-planar":return!0;default:return!1}},qs=e=>{switch(e){case"u8":case"u8-planar":return(e,t)=>(e.getUint8(t)-128)/128;case"s16":case"s16-planar":return(e,t)=>e.getInt16(t,!0)/32768;case"s32":case"s32-planar":return(e,t)=>e.getInt32(t,!0)/2147483648;case"f32":case"f32-planar":return(e,t)=>e.getFloat32(t,!0)}},Ws=e=>{switch(e){case"u8":case"u8-planar":return(e,t,i)=>e.setUint8(t,$(127.5*(i+1),0,255));case"s16":case"s16-planar":return(e,t,i)=>e.setInt16(t,$(Math.round(32767*i),-32768,32767),!0);case"s32":case"s32-planar":return(e,t,i)=>e.setInt32(t,$(Math.round(2147483647*i),-2147483648,2147483647),!0);case"f32":case"f32-planar":return(e,t,i)=>e.setFloat32(t,i,!0)}},Vs=e=>"undefined"!==typeof AudioData&&e instanceof AudioData,Hs=(e,t,i,r,n,s,a,o)=>{const l=qs(i),c=Ws(r),u=zs(i),d=zs(r),h=Us(i);if(Us(r))if(h){const r=new ArrayBuffer(o*u),n=P(r);e.copyTo(r,{planeIndex:s,frameOffset:a,frameCount:o,format:i});for(let e=0;e{if(!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(void 0!==e.metadataOnly&&"boolean"!==typeof e.metadataOnly)throw new TypeError("options.metadataOnly, when defined, must be a boolean.");if(void 0!==e.verifyKeyPackets&&"boolean"!==typeof e.verifyKeyPackets)throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");if(e.verifyKeyPackets&&e.metadataOnly)throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.");if(void 0!==e.skipLiveWait&&"boolean"!==typeof e.skipLiveWait)throw new TypeError("options.skipLiveWait, when defined, must be a boolean.")},$s=e=>{if(!ye(e))throw new TypeError("timestamp must be a number.")},Qs=(e,t,i)=>i.verifyKeyPackets?t.then(t=>d(null,null,function*(){if(!t||"delta"===t.type)return t;const i=yield e.determinePacketType(t);return i&&(t.type=i),t})):t;class Gs{constructor(e){if(!(e instanceof la))throw new TypeError("track must be an InputTrack.");this._track=e}getFirstPacket(){return d(this,arguments,function*(e={}){if(Xs(e),this._track.input._disposed)throw new va;return Qs(this._track,this._track._backing.getFirstPacket(e),e)})}getFirstKeyPacket(){return d(this,arguments,function*(e={}){Xs(e);const t=yield this.getFirstPacket(e);return t?"key"===t.type?t:this.getNextKeyPacket(t,e):null})}getPacket(e){return d(this,arguments,function*(e,t={}){if($s(e),Xs(t),this._track.input._disposed)throw new va;return Qs(this._track,this._track._backing.getPacket(e,t),t)})}getNextPacket(e){return d(this,arguments,function*(e,t={}){if(!(e instanceof Yt))throw new TypeError("packet must be an EncodedPacket.");if(Xs(t),this._track.input._disposed)throw new va;return Qs(this._track,this._track._backing.getNextPacket(e,t),t)})}getKeyPacket(e){return d(this,arguments,function*(e,t={}){if($s(e),Xs(t),this._track.input._disposed)throw new va;if(!t.verifyKeyPackets)return this._track._backing.getKeyPacket(e,t);const i=yield this._track._backing.getKeyPacket(e,t);if(!i)return i;y("key"===i.type);return"delta"===(yield this._track.determinePacketType(i))?this.getKeyPacket(i.timestamp-1/(yield this._track.getTimeResolution()),t):i})}getNextKeyPacket(e){return d(this,arguments,function*(e,t={}){if(!(e instanceof Yt))throw new TypeError("packet must be an EncodedPacket.");if(Xs(t),this._track.input._disposed)throw new va;if(!t.verifyKeyPackets)return this._track._backing.getNextKeyPacket(e,t);const i=yield this._track._backing.getNextKeyPacket(e,t);if(!i)return i;y("key"===i.type);return"delta"===(yield this._track.determinePacketType(i))?this.getNextKeyPacket(i,t):i})}packets(e,t,i={}){if(void 0!==e&&!(e instanceof Yt))throw new TypeError("startPacket must be an EncodedPacket.");if(void 0!==e&&e.isMetadataOnly&&!(null==i?void 0:i.metadataOnly))throw new TypeError("startPacket can only be metadata-only if options.metadataOnly is enabled.");if(void 0!==t&&!(t instanceof Yt))throw new TypeError("endPacket must be an EncodedPacket.");if(Xs(i),this._track.input._disposed)throw new va;const r=[];let{promise:n,resolve:s}=q(),{promise:a,resolve:o}=q(),l=!1,c=!1,u=null;const h=[],f=()=>Math.max(2,h.length);(()=>d(this,null,function*(){let u=null!=e?e:yield this.getFirstPacket(i);for(;u&&!c&&!this._track.input._disposed&&!(t&&u.sequenceNumber>=(null==t?void 0:t.sequenceNumber));)r.length>f()?(({promise:a,resolve:o}=q()),yield a):(r.push(u),s(),({promise:n,resolve:s}=q()),u=yield this.getNextPacket(u,i));l=!0,s()}))().catch(e=>{u||(u=e,s())});const m=this._track;return{next(){return d(this,null,function*(){for(;;){if(m.input._disposed)throw new va;if(c)return{value:void 0,done:!0};if(u)throw u;if(r.length>0){const e=r.shift(),t=performance.now();for(h.push(t);h.length>0&&t-h[0]>=1e3;)h.shift();return o(),{value:e,done:!1}}if(l)return{value:void 0,done:!0};yield n}})},return(){return d(this,null,function*(){return c=!0,o(),s(),{value:void 0,done:!0}})},throw(e){return d(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}}class Ys{constructor(e,t){this.onSample=e,this.onError=t}}class Js{mediaSamplesInRange(e=0,t=1/0,i){$s(e),$s(t);const r=[];let n=!1,s=null,{promise:a,resolve:o}=q(),{promise:l,resolve:h}=q(),f=!1,m=!1,p=!1,g=null;const k=u(c({},i),{verifyKeyPackets:!0,metadataOnly:!1});(()=>d(this,null,function*(){var i;const c=yield this._createDecoder(i=>{h(),i.timestamp>=t&&(m=!0),m?i.close():(s&&(i.timestamp>e?(r.push(s),n=!0):s.close()),i.timestamp>=e&&(r.push(i),n=!0),s=n?null:i,r.length>0&&(o(),({promise:a,resolve:o}=q())))},e=>{g||(g=e,o())}),u=this._createPacketSink(),d=null!=(i=yield u.getKeyPacket(e,k))?i:yield u.getFirstKeyPacket(k);let y=d;const b=u.packets(null!=d?d:void 0,void 0,k);for(yield b.next();y&&!m&&!this._track.input._disposed;){const e=Zs(r.length);if(r.length+c.getDecodeQueueSize()>e){({promise:l,resolve:h}=q()),yield l;continue}c.decode(y);const t=yield b.next();if(t.done)break;y=t.value}yield b.return(),p||this._track.input._disposed||(yield c.flush()),c.close(),!n&&s&&r.push(s),f=!0,o()}))().catch(e=>{g||(g=e,o())});const y=this._track,b=()=>{null==s||s.close();for(const e of r)e.close()};return{next(){return d(this,null,function*(){for(;;){if(y.input._disposed)throw b(),new va;if(p)return{value:void 0,done:!0};if(g)throw b(),g;if(r.length>0){const e=r.shift();return h(),{value:e,done:!1}}if(f)return{value:void 0,done:!0};yield a}})},return(){return d(this,null,function*(){return p=!0,m=!0,h(),o(),b(),{value:void 0,done:!0}})},throw(e){return d(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}mediaSamplesAtTimestamps(e,t){(e=>{if(!(Symbol.iterator in e)&&!(Symbol.asyncIterator in e))throw new TypeError("Argument must be an iterable or async iterable.")})(e);const i=function(e){return f(this,null,function*(){Symbol.iterator in e?yield*m(e[Symbol.iterator]()):yield*m(e[Symbol.asyncIterator]())})}(e),r=[],n=[];let{promise:s,resolve:a}=q(),{promise:o,resolve:l}=q(),h=!1,g=!1,k=null;const b=e=>{n.push(e),a(),({promise:s,resolve:a}=q())},T=u(c({},t),{verifyKeyPackets:!0,metadataOnly:!1});(()=>d(this,null,function*(){const e=yield this._createDecoder(e=>{if(l(),g)return void e.close();let t=0;for(;r.length>0&&e.timestamp-r[0]>-1e-10;)t++,r.shift();if(t>0)for(let i=0;i{k||(k=e,a())}),t=this._createPacketSink();let s=null,c=null,u=-1;const f=()=>d(this,null,function*(){y(c);let i=c;for(e.decode(i);i.sequenceNumberr&&!g;)({promise:o,resolve:l}=q()),yield o;if(g)break;const s=yield t.getNextPacket(i,T);y(s),e.decode(s),i=s}u=-1}),m=()=>d(this,null,function*(){yield e.flush();for(let e=0;e{k||(k=e,a())});const S=this._track,v=()=>{for(const e of n)null==e||e.close()};return{next(){return d(this,null,function*(){for(;;){if(S.input._disposed)throw v(),new va;if(g)return{value:void 0,done:!0};if(k)throw v(),k;if(n.length>0){const e=n.shift();return y(void 0!==e),l(),{value:e,done:!1}}if(h)return{value:void 0,done:!0};yield s}})},return(){return d(this,null,function*(){return g=!0,l(),a(),v(),{value:void 0,done:!0}})},throw(e){return d(this,null,function*(){throw e})},[Symbol.asyncIterator](){return this}}}}const Zs=e=>0===e?40:8;class ea extends Ys{constructor(e,t,i,r,n,s){super(e,t),this.codec=i,this.decoderConfig=r,this.rotation=n,this.timeResolution=s,this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new se,this.customDecoderQueueSize=0,this.inputTimestamps=[],this.sampleQueue=[],this.currentPacketIndex=0,this.raslSkipped=!1,this.alphaDecoder=null,this.alphaHadKeyframe=!1,this.colorQueue=[],this.alphaQueue=[],this.merger=null,this.mergerCreationFailed=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue=[],this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1;const a=Ks.find(e=>e.supports(i,r));if(a)this.customDecoder=new a,this.customDecoder.codec=i,this.customDecoder.config=r,this.customDecoder.onSample=e=>{if(!(e instanceof Es))throw new TypeError("The argument passed to onSample must be a VideoSample.");this.finalizeAndEmitSample(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=e=>{if(this.alphaQueue.length>0){const t=this.alphaQueue.shift();y(void 0!==t),this.mergeAlpha(e,t)}else this.colorQueue.push(e)};if("avc"===i&&this.decoderConfig.description&&de()){const e=(e=>{try{const t=P(e);let i=0;const r=t.getUint8(i++),n=t.getUint8(i++),s=t.getUint8(i++),a=t.getUint8(i++),o=3&t.getUint8(i++),l=31&t.getUint8(i++),c=[];for(let f=0;f0){const t=kt(e.sequenceParameterSets[0]);t&&0===t.frameMbsOnlyFlag&&(this.decoderConfig=u(c({},this.decoderConfig),{hardwareAcceleration:"prefer-software"}))}}const t=new Error("Decoding error").stack;this.decoder=new VideoDecoder({output:t=>{try{e(t)}catch(i){this.onError(i)}},error:e=>{e.stack=t,this.onError(e)}}),this.decoder.configure(this.decoderConfig)}}getDecodeQueueSize(){var e,t;return this.customDecoder?this.customDecoderQueueSize:(y(this.decoder),Math.max(this.decoder.decodeQueueSize,null!=(t=null==(e=this.alphaDecoder)?void 0:e.decodeQueueSize)?t:0))}decode(e){if("hevc"===this.codec&&this.currentPacketIndex>0&&!this.raslSkipped){if(this.hasHevcRaslPicture(e.data))return;this.raslSkipped=!0}if(this.customDecoder)this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--);else{if(y(this.decoder),oe()||U(this.inputTimestamps,e.timestamp,e=>e),de()&&0===this.currentPacketIndex)if("avc"===this.codec){const t=[];for(const r of ct(e.data,this.decoderConfig)){const i=ut(e.data[r.offset]);i>=20&&i<=31||t.push(e.data.subarray(r.offset,r.offset+r.length))}const i=((e,t)=>{if(t.description){const i=3&w(t.description)[4];return mt(e,i+1)}return ft(e)})(t,this.decoderConfig);e=new Yt(i,e.type,e.timestamp,e.duration)}else if("hevc"===this.codec){const t=Ft(e.data,this.decoderConfig);t&&(e=new Yt(t,e.type,e.timestamp,e.duration))}this.decoder.decode(e.toEncodedVideoChunk()),this.decodeAlphaData(e)}this.currentPacketIndex++}decodeAlphaData(e){if(!e.sideData.alpha||this.mergerCreationFailed)return void this.pushNullAlphaFrame();if(!this.merger)try{this.merger=new ta}catch(i){return console.error("Due to an error, only color data will be decoded.",i),this.mergerCreationFailed=!0,void this.decodeAlphaData(e)}if(!this.alphaDecoder){const e=e=>{if(this.alphaDecoderQueueSize--,this.colorQueue.length>0){const t=this.colorQueue.shift();y(void 0!==t),this.mergeAlpha(t,e)}else this.alphaQueue.push(e);for(this.decodedAlphaChunkCount++;this.nullAlphaFrameQueue.length>0&&this.nullAlphaFrameQueue[0]===this.decodedAlphaChunkCount;)if(this.nullAlphaFrameQueue.shift(),this.colorQueue.length>0){const e=this.colorQueue.shift();y(void 0!==e),this.mergeAlpha(e,null)}else this.alphaQueue.push(null)},t=new Error("Decoding error").stack;this.alphaDecoder=new VideoDecoder({output:t=>{try{e(t)}catch(i){this.onError(i)}},error:e=>{e.stack=t,this.onError(e)}}),this.alphaDecoder.configure(this.decoderConfig)}const t=Lt(this.codec,this.decoderConfig,e.sideData.alpha);if(this.alphaHadKeyframe||(this.alphaHadKeyframe="key"===t),this.alphaHadKeyframe){if("hevc"===this.codec&&this.currentAlphaPacketIndex>0&&!this.alphaRaslSkipped){if(this.hasHevcRaslPicture(e.sideData.alpha))return void this.pushNullAlphaFrame();this.alphaRaslSkipped=!0}this.currentAlphaPacketIndex++,this.alphaDecoder.decode(e.alphaToEncodedVideoChunk(null!=t?t:e.type)),this.alphaDecoderQueueSize++}else this.pushNullAlphaFrame()}pushNullAlphaFrame(){0===this.alphaDecoderQueueSize?this.alphaQueue.push(null):this.nullAlphaFrameQueue.push(this.decodedAlphaChunkCount+this.alphaDecoderQueueSize)}hasHevcRaslPicture(e){for(const t of bt(e,this.decoderConfig)){const i=Tt(e[t.offset]);if(i===st.RASL_N||i===st.RASL_R)return!0}return!1}sampleHandler(e){if(oe()){if(this.sampleQueue.length>0&&e.timestamp>=T(this.sampleQueue).timestamp){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}U(this.sampleQueue,e,e=>e.timestamp)}else{const t=this.inputTimestamps.shift();y(void 0!==t),e.setTimestamp(t),this.finalizeAndEmitSample(e)}}finalizeAndEmitSample(e){e.setTimestamp(Math.round(e.timestamp*this.timeResolution)/this.timeResolution),e.setDuration(Math.round(e.duration*this.timeResolution)/this.timeResolution),e.setRotation(this.rotation),this.onSample(e)}mergeAlpha(e,t){var i;if(!t){const t=new Es(e);return void this.sampleHandler(t)}y(this.merger),this.merger.update(e,t),e.close(),t.close();const r=new VideoFrame(this.merger.canvas,{timestamp:e.timestamp,duration:null!=(i=e.duration)?i:void 0}),n=new Es(r);this.sampleHandler(n)}flush(){return d(this,null,function*(){var e;if(this.customDecoder?yield this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(y(this.decoder),yield Promise.all([this.decoder.flush(),null==(e=this.alphaDecoder)?void 0:e.flush()]),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>null==e?void 0:e.close()),this.alphaQueue.length=0,this.alphaHadKeyframe=!1,this.decodedAlphaChunkCount=0,this.alphaDecoderQueueSize=0,this.nullAlphaFrameQueue.length=0,this.currentAlphaPacketIndex=0,this.alphaRaslSkipped=!1),oe()){for(const e of this.sampleQueue)this.finalizeAndEmitSample(e);this.sampleQueue.length=0}this.currentPacketIndex=0,this.raslSkipped=!1})}close(){var e,t;this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(y(this.decoder),this.decoder.close(),null==(e=this.alphaDecoder)||e.close(),this.colorQueue.forEach(e=>e.close()),this.colorQueue.length=0,this.alphaQueue.forEach(e=>null==e?void 0:e.close()),this.alphaQueue.length=0,null==(t=this.merger)||t.close());for(const i of this.sampleQueue)i.close();this.sampleQueue.length=0}}class ta{constructor(){"undefined"!==typeof OffscreenCanvas?this.canvas=new OffscreenCanvas(300,150):this.canvas=document.createElement("canvas");const e=this.canvas.getContext("webgl2",{premultipliedAlpha:!1});if(!e)throw new Error("Couldn't acquire WebGL 2 context.");this.gl=e,this.program=this.createProgram(),this.vao=this.createVAO(),this.colorTexture=this.createTexture(),this.alphaTexture=this.createTexture(),this.gl.useProgram(this.program),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_colorTexture"),0),this.gl.uniform1i(this.gl.getUniformLocation(this.program,"u_alphaTexture"),1)}createProgram(){const e=this.createShader(this.gl.VERTEX_SHADER,"#version 300 es\n\t\t\tin vec2 a_position;\n\t\t\tin vec2 a_texCoord;\n\t\t\tout vec2 v_texCoord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = vec4(a_position, 0.0, 1.0);\n\t\t\t\tv_texCoord = a_texCoord;\n\t\t\t}\n\t\t"),t=this.createShader(this.gl.FRAGMENT_SHADER,"#version 300 es\n\t\t\tprecision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_colorTexture;\n\t\t\tuniform sampler2D u_alphaTexture;\n\t\t\tin vec2 v_texCoord;\n\t\t\tout vec4 fragColor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture(u_colorTexture, v_texCoord).rgb;\n\t\t\t\tfloat alpha = texture(u_alphaTexture, v_texCoord).r;\n\t\t\t\tfragColor = vec4(color, alpha);\n\t\t\t}\n\t\t"),i=this.gl.createProgram();return this.gl.attachShader(i,e),this.gl.attachShader(i,t),this.gl.linkProgram(i),i}createShader(e,t){const i=this.gl.createShader(e);return this.gl.shaderSource(i,t),this.gl.compileShader(i),i}createVAO(){const e=this.gl.createVertexArray();this.gl.bindVertexArray(e);const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=this.gl.createBuffer();this.gl.bindBuffer(this.gl.ARRAY_BUFFER,i),this.gl.bufferData(this.gl.ARRAY_BUFFER,t,this.gl.STATIC_DRAW);const r=this.gl.getAttribLocation(this.program,"a_position"),n=this.gl.getAttribLocation(this.program,"a_texCoord");return this.gl.enableVertexAttribArray(r),this.gl.vertexAttribPointer(r,2,this.gl.FLOAT,!1,16,0),this.gl.enableVertexAttribArray(n),this.gl.vertexAttribPointer(n,2,this.gl.FLOAT,!1,16,8),e}createTexture(){const e=this.gl.createTexture();return this.gl.bindTexture(this.gl.TEXTURE_2D,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),e}update(e,t){e.displayWidth===this.canvas.width&&e.displayHeight===this.canvas.height||(this.canvas.width=e.displayWidth,this.canvas.height=e.displayHeight),this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colorTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),this.gl.activeTexture(this.gl.TEXTURE1),this.gl.bindTexture(this.gl.TEXTURE_2D,this.alphaTexture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.bindVertexArray(this.vao),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4)}close(){var e;null==(e=this.gl.getExtension("WEBGL_lose_context"))||e.loseContext(),this.gl=null}}class ia extends Js{constructor(e){if(!(e instanceof da))throw new TypeError("videoTrack must be an InputVideoTrack.");super(),this._track=e}_createDecoder(e,t){return d(this,null,function*(){if(!(yield this._track.canDecode()))throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track.");const i=yield this._track.getCodec(),r=yield this._track.getRotation(),n=yield this._track.getDecoderConfig(),s=yield this._track.getTimeResolution();return y(i&&n),new ea(e,t,i,n,r,s)})}_createPacketSink(){return new Gs(this._track)}getSample(e){return d(this,arguments,function*(e,t={}){$s(e);try{for(var i,r,n,s=p(this.mediaSamplesAtTimestamps([e],t));i=!(r=yield s.next()).done;i=!1){return r.value}}catch(r){n=[r]}finally{try{i&&(r=s.return)&&(yield r.call(s))}finally{if(n)throw n[0]}}throw new Error("Internal error: Iterator returned nothing.")})}samples(e=0,t=1/0,i={}){return this.mediaSamplesInRange(e,t,i)}samplesAtTimestamps(e,t={}){return this.mediaSamplesAtTimestamps(e,t)}}class ra{constructor(e,t={}){var i,r,n;if(this._rotation=0,this._initPromise=null,this._nextCanvasIndex=0,!(e instanceof da))throw new TypeError("videoTrack must be an InputVideoTrack.");if(t&&"object"!==typeof t)throw new TypeError("options must be an object.");if(void 0!==t.alpha&&"boolean"!==typeof t.alpha)throw new TypeError("options.alpha, when provided, must be a boolean.");if(void 0!==t.width&&(!Number.isInteger(t.width)||t.width<=0))throw new TypeError("options.width, when defined, must be a positive integer.");if(void 0!==t.height&&(!Number.isInteger(t.height)||t.height<=0))throw new TypeError("options.height, when defined, must be a positive integer.");if(void 0!==t.fit&&!["fill","contain","cover"].includes(t.fit))throw new TypeError('options.fit, when provided, must be one of "fill", "contain", or "cover".');if(void 0!==t.width&&void 0!==t.height&&void 0===t.fit)throw new TypeError("When both options.width and options.height are provided, options.fit must also be provided.");if(void 0!==t.rotation&&![0,90,180,270].includes(t.rotation))throw new TypeError("options.rotation, when provided, must be 0, 90, 180 or 270.");if(void 0!==t.crop&&Rs(t.crop,"options."),void 0!==t.poolSize&&("number"!==typeof t.poolSize||!Number.isInteger(t.poolSize)||t.poolSize<0))throw new TypeError("poolSize must be a non-negative integer.");this._videoTrack=e,this._alpha=null!=(i=t.alpha)&&i,this._options=t,this._fit=null!=(r=t.fit)?r:"fill",this._videoSampleSink=new ia(e),this._canvasPool=Array.from({length:null!=(n=t.poolSize)?n:0},()=>null)}_ensureInit(){var e;return null!=(e=this._initPromise)?e:this._initPromise=(()=>d(this,null,function*(){var e;const t=this._options,i=this._videoTrack,r=null!=(e=t.rotation)?e:yield i.getRotation(),n=yield i.getSquarePixelWidth(),s=yield i.getSquarePixelHeight(),[a,o]=r%180===0?[n,s]:[s,n];let l=t.crop;l&&(l=Fs(l,a,o));let[c,u]=l?[l.width,l.height]:[a,o];const d=c/u;void 0!==t.width&&void 0===t.height?(c=t.width,u=Math.round(c/d)):void 0===t.width&&void 0!==t.height?(u=t.height,c=Math.round(u*d)):void 0!==t.width&&void 0!==t.height&&(c=t.width,u=t.height),this._width=c,this._height=u,this._rotation=r,this._crop=l}))()}_videoSampleToWrappedCanvas(e){const t=this._width,i=this._height;let r=this._canvasPool[this._nextCanvasIndex],n=!1;r||("undefined"!==typeof document?(r=document.createElement("canvas"),r.width=t,r.height=i):r=new OffscreenCanvas(t,i),this._canvasPool.length>0&&(this._canvasPool[this._nextCanvasIndex]=r),n=!0),this._canvasPool.length>0&&(this._nextCanvasIndex=(this._nextCanvasIndex+1)%this._canvasPool.length);const s=r.getContext("2d",{alpha:this._alpha||ce()});y(s),s.resetTransform(),n||(!this._alpha&&ce()?(s.fillStyle="black",s.fillRect(0,0,t,i)):s.clearRect(0,0,t,i)),e.drawWithFit(s,{fit:this._fit,rotation:this._rotation,crop:this._crop});const a={canvas:r,timestamp:e.timestamp,duration:e.duration};return e.close(),a}getCanvas(e,t){return d(this,null,function*(){$s(e),yield this._ensureInit();const i=yield this._videoSampleSink.getSample(e,t);return i&&this._videoSampleToWrappedCanvas(i)})}canvases(e=0,t=1/0,i){return f(this,null,function*(){yield new h(this._ensureInit()),yield*m(X(this._videoSampleSink.samples(e,t,i),e=>this._videoSampleToWrappedCanvas(e)))})}canvasesAtTimestamps(e,t){return f(this,null,function*(){yield new h(this._ensureInit()),yield*m(X(this._videoSampleSink.samplesAtTimestamps(e,t),e=>e&&this._videoSampleToWrappedCanvas(e)))})}}class na extends Ys{constructor(e,t,i,r){super(e,t),this.decoder=null,this.customDecoder=null,this.customDecoderCallSerializer=new se,this.customDecoderQueueSize=0,this.currentTimestamp=null;const n=t=>{(null===this.currentTimestamp||Math.abs(t.timestamp-this.currentTimestamp)>=t.duration)&&(this.currentTimestamp=t.timestamp);const i=this.currentTimestamp;if(this.currentTimestamp+=t.duration,0===t.numberOfFrames)return void t.close();const n=r.sampleRate;t.setTimestamp(Math.round(i*n)/n),e(t)},s=js.find(e=>e.supports(i,r));if(s)this.customDecoder=new s,this.customDecoder.codec=i,this.customDecoder.config=r,this.customDecoder.onSample=e=>{if(!(e instanceof Ls))throw new TypeError("The argument passed to onSample must be an AudioSample.");n(e)},this.customDecoderCallSerializer.call(()=>this.customDecoder.init());else{const e=new Error("Decoding error").stack;this.decoder=new AudioDecoder({output:e=>{try{n(new Ls(e))}catch(t){this.onError(t)}},error:t=>{t.stack=e,this.onError(t)}}),this.decoder.configure(r)}}getDecodeQueueSize(){return this.customDecoder?this.customDecoderQueueSize:(y(this.decoder),this.decoder.decodeQueueSize)}decode(e){this.customDecoder?(this.customDecoderQueueSize++,this.customDecoderCallSerializer.call(()=>this.customDecoder.decode(e)).then(()=>this.customDecoderQueueSize--)):(y(this.decoder),this.decoder.decode(e.toEncodedAudioChunk()))}flush(){return this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.flush()):(y(this.decoder),this.decoder.flush())}close(){this.customDecoder?this.customDecoderCallSerializer.call(()=>this.customDecoder.close()):(y(this.decoder),this.decoder.close())}}class sa extends Ys{constructor(e,t,i){super(e,t),this.decoderConfig=i,this.currentTimestamp=null,y(De.includes(i.codec)),this.codec=i.codec;const{dataType:r,sampleSize:n,littleEndian:s}=He(this.codec);switch(this.inputSampleSize=n,n){case 1:"unsigned"===r?this.readInputValue=(e,t)=>e.getUint8(t)-o(2,7):"signed"===r?this.readInputValue=(e,t)=>e.getInt8(t):"ulaw"===r?this.readInputValue=(e,t)=>(e=>{let t=0,i=0,r=~e;128&r&&(r&=-129,t=-1),i=5+((240&r)>>4);const n=(1<(e=>{let t=0,i=0,r=85^e;128&r&&(r&=-129,t=-1),i=4+((240&r)>>4);let n=0;return n=4!==i?1<e.getUint16(t,s)-o(2,15):"signed"===r?this.readInputValue=(e,t)=>e.getInt16(t,s):y(!1);break;case 3:"unsigned"===r?this.readInputValue=(e,t)=>K(e,t,s)-o(2,23):"signed"===r?this.readInputValue=(e,t)=>((e,t,i)=>K(e,t,i)<<8>>8)(e,t,s):y(!1);break;case 4:"unsigned"===r?this.readInputValue=(e,t)=>e.getUint32(t,s)-o(2,31):"signed"===r?this.readInputValue=(e,t)=>e.getInt32(t,s):"float"===r?this.readInputValue=(e,t)=>e.getFloat32(t,s):y(!1);break;case 8:"float"===r?this.readInputValue=(e,t)=>e.getFloat64(t,s):y(!1);break;default:H(n),y(!1)}switch(n){case 1:"ulaw"===r||"alaw"===r?(this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,i)=>e.setInt16(t,i,!0)):(this.outputSampleSize=1,this.outputFormat="u8",this.writeOutputValue=(e,t,i)=>e.setUint8(t,i+o(2,7)));break;case 2:this.outputSampleSize=2,this.outputFormat="s16",this.writeOutputValue=(e,t,i)=>e.setInt16(t,i,!0);break;case 3:this.outputSampleSize=4,this.outputFormat="s32",this.writeOutputValue=(e,t,i)=>e.setInt32(t,i<<8,!0);break;case 4:this.outputSampleSize=4,"float"===r?(this.outputFormat="f32",this.writeOutputValue=(e,t,i)=>e.setFloat32(t,i,!0)):(this.outputFormat="s32",this.writeOutputValue=(e,t,i)=>e.setInt32(t,i,!0));break;case 8:this.outputSampleSize=4,this.outputFormat="f32",this.writeOutputValue=(e,t,i)=>e.setFloat32(t,i,!0);break;default:H(n),y(!1)}}getDecodeQueueSize(){return 0}decode(e){const t=P(e.data),i=e.byteLength/this.decoderConfig.numberOfChannels/this.inputSampleSize,r=i*this.decoderConfig.numberOfChannels*this.outputSampleSize,n=new ArrayBuffer(r),s=new DataView(n);for(let c=0;c=a)&&(this.currentTimestamp=e.timestamp);const o=this.currentTimestamp;this.currentTimestamp+=a;const l=new Ls({format:this.outputFormat,data:n,numberOfChannels:this.decoderConfig.numberOfChannels,sampleRate:this.decoderConfig.sampleRate,numberOfFrames:i,timestamp:o});this.onSample(l)}flush(){return d(this,null,function*(){})}close(){}}class aa extends Js{constructor(e){if(!(e instanceof ha))throw new TypeError("audioTrack must be an InputAudioTrack.");super(),this._track=e}_createDecoder(e,t){return d(this,null,function*(){if(!(yield this._track.canDecode()))throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track.");const i=yield this._track.getCodec(),r=yield this._track.getDecoderConfig();return y(i&&r),De.includes(r.codec)?new sa(e,t,r):new na(e,t,i,r)})}_createPacketSink(){return new Gs(this._track)}getSample(e){return d(this,arguments,function*(e,t={}){$s(e);try{for(var i,r,n,s=p(this.mediaSamplesAtTimestamps([e],t));i=!(r=yield s.next()).done;i=!1){return r.value}}catch(r){n=[r]}finally{try{i&&(r=s.return)&&(yield r.call(s))}finally{if(n)throw n[0]}}throw new Error("Internal error: Iterator returned nothing.")})}samples(e=0,t=1/0,i={}){return this.mediaSamplesInRange(e,t,i)}samplesAtTimestamps(e,t={}){return this.mediaSamplesAtTimestamps(e,t)}}class oa{constructor(e){if(!(e instanceof ha))throw new TypeError("audioTrack must be an InputAudioTrack.");this._audioSampleSink=new aa(e)}_audioSampleToWrappedArrayBuffer(e){const t={buffer:e.toAudioBuffer(),timestamp:e.timestamp,duration:e.duration};return e.close(),t}getBuffer(e,t){return d(this,null,function*(){$s(e);const i=yield this._audioSampleSink.getSample(e,t);return i&&this._audioSampleToWrappedArrayBuffer(i)})}buffers(e=0,t=1/0,i){return X(this._audioSampleSink.samples(e,t,i),e=>this._audioSampleToWrappedArrayBuffer(e))}buffersAtTimestamps(e,t){return X(this._audioSampleSink.samplesAtTimestamps(e,t),e=>e&&this._audioSampleToWrappedArrayBuffer(e))}}class la{constructor(e,t){this.input=e,this._backing=t}isVideoTrack(){return this instanceof da}isAudioTrack(){return this instanceof ha}get id(){return this._backing.getId()}get number(){return this._backing.getNumber()}getInternalCodecId(){return d(this,null,function*(){return this._backing.getInternalCodecId()})}get internalCodecId(){return ca(this._backing.getInternalCodecId(),"internalCodecId","getInternalCodecId")}getLanguageCode(){return d(this,null,function*(){return this._backing.getLanguageCode()})}get languageCode(){return ca(this._backing.getLanguageCode(),"languageCode","getLanguageCode")}getName(){return d(this,null,function*(){return this._backing.getName()})}get name(){return ca(this._backing.getName(),"name","getName")}getTimeResolution(){return d(this,null,function*(){return this._backing.getTimeResolution()})}get timeResolution(){return ca(this._backing.getTimeResolution(),"timeResolution","getTimeResolution")}isRelativeToUnixEpoch(){return d(this,null,function*(){return this._backing.isRelativeToUnixEpoch()})}getDisposition(){return d(this,null,function*(){return this._backing.getDisposition()})}get disposition(){return ca(this._backing.getDisposition(),"disposition","getDisposition")}getBitrate(){return d(this,null,function*(){return this._backing.getBitrate()})}getAverageBitrate(){return d(this,null,function*(){return this._backing.getAverageBitrate()})}getFirstTimestamp(){return d(this,null,function*(){var e;const t=yield this._backing.getFirstPacket({metadataOnly:!0});return null!=(e=null==t?void 0:t.timestamp)?e:0})}computeDuration(e){return d(this,null,function*(){var t,i;const r=yield this._backing.getPacket(1/0,c({metadataOnly:!0},e)),n=(null!=(t=null==r?void 0:r.timestamp)?t:0)+(null!=(i=null==r?void 0:r.duration)?i:0);return Y(n,yield this.getTimeResolution())})}getDurationFromMetadata(){return d(this,arguments,function*(e={}){return this._backing.getDurationFromMetadata(e)})}computePacketStats(e=1/0,t){return d(this,null,function*(){const i=new Gs(this);let r=1/0,n=-1/0,s=0,a=0;try{for(var o,l,u,d=p(i.packets(void 0,void 0,c({metadataOnly:!0},t)));o=!(l=yield d.next()).done;o=!1){const t=l.value;if(s>=e&&t.timestamp>=n)break;r=Math.min(r,t.timestamp),n=Math.max(n,t.timestamp+t.duration),s++,a+=t.byteLength}}catch(l){u=[l]}finally{try{o&&(l=d.return)&&(yield l.call(d))}finally{if(u)throw u[0]}}return{packetCount:s,averagePacketRate:s?Number((s/(n-r)).toPrecision(16)):0,averageBitrate:s?Number((8*a/(n-r)).toPrecision(16)):0}})}isLive(){return d(this,null,function*(){return null!==(yield this._backing.getLiveRefreshInterval())})}getLiveRefreshInterval(){return d(this,null,function*(){return this._backing.getLiveRefreshInterval()})}canBePairedWith(e){if(!(e instanceof la))throw new TypeError("other must be an InputTrack.");return this.input===e.input&&this!==e&&(this._backing.getPairingMask()&e._backing.getPairingMask())!==BigInt("0")}getPairableTracks(e){return d(this,null,function*(){return this.input.getTracks(ga({filter:e=>e.canBePairedWith(this)},e))})}getPairableVideoTracks(e){return d(this,null,function*(){return this.input.getVideoTracks(ga({filter:e=>e.canBePairedWith(this)},e))})}getPairableAudioTracks(e){return d(this,null,function*(){return this.input.getAudioTracks(ga({filter:e=>e.canBePairedWith(this)},e))})}getPrimaryPairableVideoTrack(e){return d(this,null,function*(){return this.input.getPrimaryVideoTrack(ga({filter:e=>e.canBePairedWith(this)},e))})}getPrimaryPairableAudioTrack(e){return d(this,null,function*(){return this.input.getPrimaryAudioTrack(ga({filter:e=>e.canBePairedWith(this)},e))})}hasPairableTrack(e){return d(this,null,function*(){e&&(e=ua(e));const t=yield this.input.getTracks();for(const i of t)if(this.canBePairedWith(i)&&(!e||(yield e(i))))return!0;return!1})}hasPairableVideoTrack(e){return e&&(e=ua(e)),this.hasPairableTrack(t=>d(this,null,function*(){return t.isVideoTrack()&&(!e||(yield e(t)))}))}hasPairableAudioTrack(e){return e&&(e=ua(e)),this.hasPairableTrack(t=>d(this,null,function*(){return t.isAudioTrack()&&(!e||(yield e(t)))}))}}const ca=(e,t,i)=>{if(e instanceof Promise)throw new Error(`'${t}' is deprecated and not available synchronously for this track. Use the preferred '${i}()' instead.`);return e},ua=e=>{if(void 0!==e&&"function"!==typeof e)throw new TypeError("predicate, when provided, must be a function.");return e?t=>{const i=e=>{if("boolean"!==typeof e)throw new TypeError("predicate must return or resolve to a boolean value.");return e},r=e(t);return r instanceof Promise?r.then(i):i(r)}:void 0};class da extends la{constructor(e,t){super(e,t),this._pixelAspectRatioCache=null,this._backing=t}get type(){return"video"}getCodec(){return d(this,null,function*(){return this._backing.getCodec()})}get codec(){return ca(this._backing.getCodec(),"codec","getCodec")}hasOnlyKeyPackets(){return d(this,null,function*(){var e,t,i;return null!=(i=yield null==(t=(e=this._backing).getHasOnlyKeyPackets)?void 0:t.call(e))&&i})}getCodedWidth(){return d(this,null,function*(){return this._backing.getCodedWidth()})}get codedWidth(){return ca(this._backing.getCodedWidth(),"codedWidth","getCodedWidth")}getCodedHeight(){return d(this,null,function*(){return this._backing.getCodedHeight()})}get codedHeight(){return ca(this._backing.getCodedHeight(),"codedHeight","getCodedHeight")}getRotation(){return d(this,null,function*(){return this._backing.getRotation()})}get rotation(){return ca(this._backing.getRotation(),"rotation","getRotation")}getSquarePixelWidth(){return d(this,null,function*(){return this._backing.getSquarePixelWidth()})}get squarePixelWidth(){return ca(this._backing.getSquarePixelWidth(),"squarePixelWidth","getSquarePixelWidth")}getSquarePixelHeight(){return d(this,null,function*(){return this._backing.getSquarePixelHeight()})}get squarePixelHeight(){return ca(this._backing.getSquarePixelHeight(),"squarePixelHeight","getSquarePixelHeight")}getPixelAspectRatio(){return d(this,null,function*(){var e;return null!=(e=this._pixelAspectRatioCache)?e:this._pixelAspectRatioCache=ve({num:(yield this.getSquarePixelWidth())*(yield this.getCodedHeight()),den:(yield this.getSquarePixelHeight())*(yield this.getCodedWidth())})})}get pixelAspectRatio(){var e;return null!=(e=this._pixelAspectRatioCache)?e:this._pixelAspectRatioCache=ve({num:ca(this._backing.getSquarePixelWidth(),"pixelAspectRatio","getPixelAspectRatio")*ca(this._backing.getCodedHeight(),"pixelAspectRatio","getPixelAspectRatio"),den:ca(this._backing.getSquarePixelHeight(),"pixelAspectRatio","getPixelAspectRatio")*ca(this._backing.getCodedWidth(),"pixelAspectRatio","getPixelAspectRatio")})}getDisplayWidth(){return d(this,null,function*(){var e,t;const i=yield null==(t=(e=this._backing).getMetadataDisplayWidth)?void 0:t.call(e);if(null!=i)return i;return(yield this.getRotation())%180===0?this.getSquarePixelWidth():this.getSquarePixelHeight()})}get displayWidth(){var e,t;const i=null==(t=(e=this._backing).getMetadataDisplayWidth)?void 0:t.call(e);if(void 0!==i){const e=ca(i,"displayWidth","getDisplayWidth");if(null!==e)return e}const r=ca(this._backing.getRotation(),"displayWidth","getDisplayWidth")%180===0?this._backing.getSquarePixelWidth():this._backing.getSquarePixelHeight();return ca(r,"displayWidth","getDisplayWidth")}getDisplayHeight(){return d(this,null,function*(){var e,t;const i=yield null==(t=(e=this._backing).getMetadataDisplayHeight)?void 0:t.call(e);if(null!=i)return i;return(yield this.getRotation())%180===0?this.getSquarePixelHeight():this.getSquarePixelWidth()})}get displayHeight(){var e,t;const i=null==(t=(e=this._backing).getMetadataDisplayHeight)?void 0:t.call(e);if(void 0!==i){const e=ca(i,"displayHeight","getDisplayHeight");if(null!==e)return e}const r=ca(this._backing.getRotation(),"displayHeight","getDisplayHeight")%180===0?this._backing.getSquarePixelHeight():this._backing.getSquarePixelWidth();return ca(r,"displayHeight","getDisplayHeight")}getColorSpace(){return d(this,null,function*(){return this._backing.getColorSpace()})}hasHighDynamicRange(){return d(this,null,function*(){const e=yield this._backing.getColorSpace();return"bt2020"===e.primaries||"smpte432"===e.primaries||"pg"===e.transfer||"hlg"===e.transfer||"bt2020-ncl"===e.matrix})}canBeTransparent(){return d(this,null,function*(){return this._backing.canBeTransparent()})}getDecoderConfig(){return d(this,null,function*(){return this._backing.getDecoderConfig()})}getCodecParameterString(){return d(this,null,function*(){var e,t,i;const r=yield null==(t=(e=this._backing).getMetadataCodecParameterString)?void 0:t.call(e);if(null!=r)return r;const n=yield this._backing.getDecoderConfig();return null!=(i=null==n?void 0:n.codec)?i:null})}canDecode(){return d(this,null,function*(){try{const e=yield this._backing.getDecoderConfig();if(!e)return!1;const t=yield this._backing.getCodec();if(y(null!==t),Ks.some(i=>i.supports(t,e)))return!0;if("undefined"===typeof VideoDecoder)return!1;return!0===(yield VideoDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}})}determinePacketType(e){return d(this,null,function*(){if(!(e instanceof Yt))throw new TypeError("packet must be an EncodedPacket.");if(e.isMetadataOnly)throw new TypeError("packet must not be metadata-only to determine its type.");const t=yield this.getCodec();if(null===t)return null;const i=yield this.getDecoderConfig();return y(i),Lt(t,i,e.data)})}}class ha extends la{constructor(e,t){super(e,t),this._backing=t}get type(){return"audio"}getCodec(){return d(this,null,function*(){return this._backing.getCodec()})}get codec(){return ca(this._backing.getCodec(),"codec","getCodec")}hasOnlyKeyPackets(){return d(this,null,function*(){var e,t,i;return null==(i=yield null==(t=(e=this._backing).getHasOnlyKeyPackets)?void 0:t.call(e))||i})}getNumberOfChannels(){return d(this,null,function*(){return this._backing.getNumberOfChannels()})}get numberOfChannels(){return ca(this._backing.getNumberOfChannels(),"numberOfChannels","getNumberOfChannels")}getSampleRate(){return d(this,null,function*(){return this._backing.getSampleRate()})}get sampleRate(){return ca(this._backing.getSampleRate(),"sampleRate","getSampleRate")}getDecoderConfig(){return d(this,null,function*(){return this._backing.getDecoderConfig()})}getCodecParameterString(){return d(this,null,function*(){var e,t,i;const r=yield null==(t=(e=this._backing).getMetadataCodecParameterString)?void 0:t.call(e);if(null!=r)return r;const n=yield this._backing.getDecoderConfig();return null!=(i=null==n?void 0:n.codec)?i:null})}canDecode(){return d(this,null,function*(){try{const e=yield this._backing.getDecoderConfig();if(!e)return!1;const t=yield this._backing.getCodec();if(y(null!==t),js.some(i=>i.supports(t,e)))return!0;if(e.codec.startsWith("pcm-"))return!0;if("undefined"===typeof AudioDecoder)return!1;return!0===(yield AudioDecoder.isConfigSupported(e)).supported}catch(e){return console.error("Error during decodability check:",e),!1}})}determinePacketType(e){return d(this,null,function*(){if(!(e instanceof Yt))throw new TypeError("packet must be an EncodedPacket.");return null===(yield this.getCodec())?null:"key"})}}const fa=e=>-(null!=e?e:-1/0),ma=e=>-e,pa=e=>{if("object"!==typeof e||!e)throw new TypeError("query must be an object.");if(void 0!==e.filter&&"function"!==typeof e.filter)throw new TypeError("query.filter, when provided, must be a function.");if(void 0!==e.sortBy&&"function"!==typeof e.sortBy)throw new TypeError("query.sortBy, when provided, must be a function.");return{filter:e.filter?t=>{const i=e=>{if("boolean"!==typeof e)throw new TypeError("query.filter must return or resolve to a boolean.");return e},r=e.filter(t);return r instanceof Promise?r.then(i):i(r)}:void 0,sortBy:e.sortBy?t=>{const i=e=>{if("number"!==typeof e&&(!Array.isArray(e)||!e.every(e=>"number"===typeof e)))throw new TypeError("query.sortBy must return or resolve to a number or an array of numbers.");return e},r=e.sortBy(t);return r instanceof Promise?r.then(i):i(r)}:void 0}},ga=(e,t)=>({filter:(null==e?void 0:e.filter)||(null==t?void 0:t.filter)?i=>{var r,n;const s=null==(n=null==(r=null==e?void 0:e.filter)?void 0:r.call(e,i))||n,a=e=>{var r,n;return!1!==e&&(null==(n=null==(r=null==t?void 0:t.filter)?void 0:r.call(t,i))||n)};return s instanceof Promise?s.then(a):a(s)}:void 0,sortBy:(null==e?void 0:e.sortBy)||(null==t?void 0:t.sortBy)?i=>{var r,n,s,a;const o=null!=(n=null==(r=null==e?void 0:e.sortBy)?void 0:r.call(e,i))?n:[],l=null!=(a=null==(s=null==t?void 0:t.sortBy)?void 0:s.call(t,i))?a:[],c=(e,t)=>[...Array.isArray(e)?e:[e],...Array.isArray(t)?t:[t]];return o instanceof Promise||l instanceof Promise?Promise.all([o,l]).then(([e,t])=>c(e,t)):c(o,l)}:void 0}),ka=(e,t)=>d(null,null,function*(){let i=e;if(null==t?void 0:t.filter){const r=e.map(e=>t.filter(e));if(r.some(e=>e instanceof Promise)){const t=yield Promise.all(r);i=e.filter((e,i)=>t[i])}else i=e.filter((e,t)=>r[t])}if(!(null==t?void 0:t.sortBy))return i;const r=i.map(e=>t.sortBy(e)),n=r.some(e=>e instanceof Promise)?yield Promise.all(r):r;return i.map((e,t)=>({track:e,sortValue:n[t]})).sort((e,t)=>{var i,r;const n=Array.isArray(e.sortValue)?e.sortValue:[e.sortValue],s=Array.isArray(t.sortValue)?t.sortValue:[t.sortValue],a=Math.max(n.length,s.length);for(let o=0;oe.track)});ke();const ya=2;let ba=null;"undefined"!==typeof FinalizationRegistry&&(ba=new FinalizationRegistry(e=>{for(const t of e)t.freed||t.free()}));class Ta extends Ie{get disposed(){return this._disposed}constructor(e){var t,i;if(super(),this._demuxerPromise=null,this._format=null,this._trackBackingsCache=null,this._backingToTrack=new Map,this._disposed=!1,this._nextSourceCacheAge=0,this._sourceRefs=[],this._sourceCache=[],this._sourceCachePromises=[],this._onFormatDetermined=null,!e||"object"!==typeof e)throw new TypeError("options must be an object.");if(!Array.isArray(e.formats)||e.formats.some(e=>!(e instanceof Jn)))throw new TypeError("options.formats must be an array of InputFormat.");if(!(e.source instanceof xn||e.source instanceof Cn))throw new TypeError("options.source must be a Source or SourceRef.");if(e.source instanceof xn&&e.source._disposed)throw new TypeError("options.source must not be a disposed Source.");if(void 0!==e.initInput&&!(e.initInput instanceof Ta))throw new TypeError("options.initInput, when provided, must be an Input.");void 0!==e.formatOptions&&((e,t)=>{if(!e||"object"!==typeof e)throw new TypeError(`${t}, when provided, must be an object.`);if(void 0!==e.isobmff){if(!e.isobmff||"object"!==typeof e.isobmff)throw new TypeError(`${t}.isobmff, when provided, must be an object.`);if(void 0!==e.isobmff.resolveKeyId&&"function"!==typeof e.isobmff.resolveKeyId)throw new TypeError(`${t}.isobmff.resolveKeyId, when provided, must be a function.`)}})(e.formatOptions,"formatOptions"),this._formats=e.formats,this._initInput=null!=(t=e.initInput)?t:null,this._formatOptions=null!=(i=e.formatOptions)?i:{},e.source instanceof xn?this._rootRef=e.source.ref():this._rootRef=e.source,this._sourceRefs.push(this._rootRef),null==ba||ba.register(this,this._sourceRefs,this)}get _rootSource(){return this._rootRef.source}_getSourceUncached(e){return d(this,null,function*(){y(this._rootSource instanceof Bn);const t=yield this._rootSource._resolveRequest(e);return this._emit("source",{source:t.source,request:e,isRoot:e.isRoot}),t})}_getSourceCached(e,t=1){const i=this._sourceCache.find(i=>i.cacheGroup===t&&En(i.request,e));if(i)return i.age++,Promise.resolve(i.sourceRef.source.ref());const r=this._sourceCachePromises.find(i=>i.cacheGroup===t&&En(i.request,e));if(r)return r.promise.then(e=>e.sourceRef.source.ref());const n=(()=>d(this,null,function*(){const i=yield this._getSourceUncached(e);if(Te(this._sourceCache,e=>e.cacheGroup===t&&1===e.sourceRef.source._refCount)>=4){const e=Se(this._sourceCache,e=>e.cacheGroup===t&&1===e.sourceRef.source._refCount?e.age:1/0);y(-1!==e);const i=this._sourceCache[e];this._sourceCache.splice(e,1),i.sourceRef.free(),((e,t)=>{const i=e.indexOf(t);-1!==i&&e.splice(i,1)})(this._sourceRefs,i.sourceRef)}this._sourceRefs.push(i);const r=this._sourceCachePromises.findIndex(t=>t.request===e);y(-1!==r),this._sourceCachePromises.splice(r,1);return{request:e,sourceRef:i,age:this._nextSourceCacheAge++,cacheGroup:t}}))();return this._sourceCachePromises.push({request:e,cacheGroup:t,promise:n}),n.then(e=>{const t=e.sourceRef.source.ref();return this._sourceCache.push(e),t})}_getDemuxer(){var e;return null!=(e=this._demuxerPromise)?e:this._demuxerPromise=(()=>d(this,null,function*(){var e;this._reader=new wa(this._rootSource),this._emit("source",{source:this._rootSource,request:null,isRoot:!0});for(const t of this._formats){if(yield t._canReadInput(this))return this._format=t,null==(e=this._onFormatDetermined)||e.call(this,t),t._createDemuxer(this)}throw new Sa}))()}get source(){return this._rootSource}getFormat(){return d(this,null,function*(){return yield this._getDemuxer(),y(this._format),this._format})}canRead(){return d(this,null,function*(){try{return yield this._getDemuxer(),!0}catch(e){if(e instanceof Sa)return!1;throw e}})}getFirstTimestamp(e){return d(this,null,function*(){null!=e||(e=yield this.getTracks());const t=e.filter(e=>null!==e);if(0===t.length)return 0;const i=yield Promise.all(t.map(e=>e.getFirstTimestamp()));return Math.min(...i)})}computeDuration(e,t){return d(this,null,function*(){null!=e||(e=yield this.getTracks());const i=e.filter(e=>null!==e);if(0===i.length)return 0;const r=yield Promise.all(i.map(e=>e.computeDuration(t)));return Math.max(...r)})}getDurationFromMetadata(e,t){return d(this,null,function*(){null!=e||(e=yield this.getTracks());const i=e.filter(e=>null!==e),r=(yield Promise.all(i.map(e=>e.getDurationFromMetadata(t)))).filter(e=>null!==e);return 0===r.length?null:Math.max(...r)})}getTracks(e){return d(this,null,function*(){e&&(e=pa(e));const t=(yield this._getTrackBackings()).map(e=>this._wrapBackingAsTrack(e));return ka(t,e)})}getVideoTracks(e){return d(this,null,function*(){e&&(e=pa(e));const t=(yield this.getTracks()).filter(e=>e.isVideoTrack());return ka(t,e)})}getAudioTracks(e){return d(this,null,function*(){e&&(e=pa(e));const t=(yield this.getTracks()).filter(e=>e.isAudioTrack());return ka(t,e)})}getPrimaryVideoTrack(e){return d(this,null,function*(){var t;e&&(e=pa(e));const i=ga(e,{sortBy:e=>d(null,null,function*(){return[ma((yield e.getDisposition()).default),ma(yield e.hasPairableAudioTrack()),ma(!(yield e.hasOnlyKeyPackets())),fa(yield e.getBitrate())]})});return null!=(t=(yield this.getVideoTracks(i))[0])?t:null})}getPrimaryAudioTrack(e){return d(this,null,function*(){var t;e&&(e=pa(e));const i=yield this.getPrimaryVideoTrack(),r=ga(e,{sortBy:e=>d(this,null,function*(){return[ma(!i||e.canBePairedWith(i)),ma((yield e.getDisposition()).default),fa(yield e.getBitrate())]})});return null!=(t=(yield this.getAudioTracks(r))[0])?t:null})}_getTrackBackings(){return d(this,null,function*(){var e;const t=yield this._getDemuxer();return null!=(e=this._trackBackingsCache)?e:this._trackBackingsCache=yield t.getTrackBackings()})}_wrapBackingAsTrack(e){const t=this._backingToTrack.get(e);if(t)return t;const i="video"===e.getType()?new da(this,e):new ha(this,e);return this._backingToTrack.set(e,i),i}getMimeType(){return d(this,null,function*(){return(yield this._getDemuxer()).getMimeType()})}getMetadataTags(){return d(this,null,function*(){return(yield this._getDemuxer()).getMetadataTags()})}dispose(){var e;if(!this._disposed){this._disposed=!0;for(const e of this._sourceRefs)e.free();this._sourceRefs.length=0,null==ba||ba.unregister(this),null==(e=this._demuxerPromise)||e.then(e=>e.dispose())}}[Symbol.dispose](){this.dispose()}}class Sa extends Error{constructor(e="Input has an unsupported or unrecognizable format."){super(e),this.name="UnsupportedInputFormatError"}}class va extends Error{constructor(e="Input has been disposed."){super(e),this.name="InputDisposedError"}}class wa{constructor(e){this.source=e}get fileSize(){const e=this.source._getFileSize();if(void 0===e)throw new Error("Reading file size too early; read required first.");return e}get fileSizeNonStrict(){var e;return null!=(e=this.source._getFileSize())?e:null}requestSlice(e,t){if(this.source._disposed)throw new va;if(e<0)return null;if(null!==this.fileSizeNonStrict&&e+t>this.fileSizeNonStrict)return null;if(0===t){const t=new Uint8Array(0);return new Pa(t,P(t),0,e,e)}const i=e+t,r=this.source._read(e,i,0,In);return r instanceof Promise?r.then(t=>t?new Pa(t.bytes,t.view,t.offset,e,i):null):r?new Pa(r.bytes,r.view,r.offset,e,i):null}requestSliceRange(e,t,i){if(this.source._disposed)throw new va;if(e<0)return null;if(null!==this.fileSizeNonStrict)return this.requestSlice(e,$(this.fileSizeNonStrict-e,t,i));{const r=this.requestSlice(e,i),n=r=>r||(y(null!==this.fileSizeNonStrict),this.requestSlice(e,$(this.fileSizeNonStrict-e,t,i)));return r instanceof Promise?r.then(n):n(r)}}requestEntireFile(){if(null!==this.fileSizeNonStrict)return this.requestSlice(0,this.fileSizeNonStrict);return(()=>d(this,null,function*(){const e=[];let t=0;for(;;){if(1===e.length&&null!==this.fileSizeNonStrict)return this.requestSlice(0,this.fileSizeNonStrict);const i=1024*e.length;let r=this.requestSliceRange(i,0,1024);if(r instanceof Promise&&(r=yield r),!r)break;e.push(xa(r,r.length)),t+=r.length}const i=new Uint8Array(t);let r=0;for(const n of e)i.set(n,r),r+=n.length;return new Pa(i,P(i),0,0,t)}))()}}class Pa{constructor(e,t,i,r,n){this.bytes=e,this.view=t,this.offset=i,this.start=r,this.end=n,this.bufferPos=r-i}static tempFromBytes(e){return new Pa(e,P(e),0,0,e.length)}get length(){return this.end-this.start}get filePos(){return this.offset+this.bufferPos}set filePos(e){this.bufferPos=e-this.offset}get remainingLength(){return Math.max(this.end-this.filePos,0)}skip(e){this.bufferPos+=e}slice(e,t=this.end-e){if(ethis.end)throw new RangeError("Slicing outside of original slice.");return new Pa(this.bytes,this.view,this.offset,e,e+t)}}const Ia=(e,t)=>{if(e.filePose.end)throw new RangeError(`Tried reading [${e.filePos}, ${e.filePos+t}), but slice is [${e.start}, ${e.end}). This is likely an internal error, please report it alongside the file that caused it.`)},xa=(e,t)=>{Ia(e,t);const i=e.bytes.subarray(e.bufferPos,e.bufferPos+t);return e.bufferPos+=t,i},Ca=e=>(Ia(e,1),e.view.getUint8(e.bufferPos++)),Ba=(e,t)=>{Ia(e,2);const i=e.view.getUint16(e.bufferPos,t);return e.bufferPos+=2,i},Ea=e=>{Ia(e,2);const t=e.view.getUint16(e.bufferPos,!1);return e.bufferPos+=2,t},_a=e=>{Ia(e,3);const t=K(e.view,e.bufferPos,!1);return e.bufferPos+=3,t},Aa=e=>{Ia(e,2);const t=e.view.getInt16(e.bufferPos,!1);return e.bufferPos+=2,t},Fa=(e,t)=>{Ia(e,4);const i=e.view.getUint32(e.bufferPos,t);return e.bufferPos+=4,i},Ra=e=>{Ia(e,4);const t=e.view.getUint32(e.bufferPos,!1);return e.bufferPos+=4,t},Da=e=>{Ia(e,4);const t=e.view.getUint32(e.bufferPos,!0);return e.bufferPos+=4,t},Ma=e=>{Ia(e,4);const t=e.view.getInt32(e.bufferPos,!1);return e.bufferPos+=4,t},Na=(e,t)=>{let i,r;return t?(i=Fa(e,!0),r=Fa(e,!0)):(r=Fa(e,!1),i=Fa(e,!1)),4294967296*r+i},Oa=e=>4294967296*Ra(e)+Ra(e),La=e=>4294967296*Ma(e)+Ra(e),za=e=>{const t=Da(e),i=(e=>{Ia(e,4);const t=e.view.getInt32(e.bufferPos,!0);return e.bufferPos+=4,t})(e);return 4294967296*i+t},Ua=e=>{Ia(e,4);const t=e.view.getFloat32(e.bufferPos,!1);return e.bufferPos+=4,t},qa=e=>{Ia(e,8);const t=e.view.getFloat64(e.bufferPos,!1);return e.bufferPos+=8,t},Wa=(e,t)=>{Ia(e,t);let i="";for(let r=0;rI.decode(xa(e,t)).split("\n").map(e=>e.trim()).filter(e=>{var t;return e.length>0&&!(null==(t=null==i?void 0:i.ignore)?void 0:t.call(i,e))});var Ha,Ka,ja,Xa;(Ka=Ha||(Ha={}))[Ka.Unsynchronisation=128]="Unsynchronisation",Ka[Ka.ExtendedHeader=64]="ExtendedHeader",Ka[Ka.ExperimentalIndicator=32]="ExperimentalIndicator",Ka[Ka.Footer=16]="Footer",(Xa=ja||(ja={}))[Xa.ISO_8859_1=0]="ISO_8859_1",Xa[Xa.UTF_16_WITH_BOM=1]="UTF_16_WITH_BOM",Xa[Xa.UTF_16_BE_NO_BOM=2]="UTF_16_BE_NO_BOM",Xa[Xa.UTF_8=3]="UTF_8";const $a=128,Qa=10,Ga=["Blues","Classic rock","Country","Dance","Disco","Funk","Grunge","Hip-hop","Jazz","Metal","New age","Oldies","Other","Pop","Rhythm and blues","Rap","Reggae","Rock","Techno","Industrial","Alternative","Ska","Death metal","Pranks","Soundtrack","Euro-techno","Ambient","Trip-hop","Vocal","Jazz & funk","Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound clip","Gospel","Noise","Alternative rock","Bass","Soul","Punk","Space","Meditative","Instrumental pop","Instrumental rock","Ethnic","Gothic","Darkwave","Techno-industrial","Electronic","Pop-folk","Eurodance","Dream","Southern rock","Comedy","Cult","Gangsta","Top 40","Christian rap","Pop/funk","Jungle music","Native US","Cabaret","New wave","Psychedelic","Rave","Showtunes","Trailer","Lo-fi","Tribal","Acid punk","Acid jazz","Polka","Retro","Musical","Rock 'n' roll","Hard rock","Folk","Folk rock","National folk","Swing","Fast fusion","Bebop","Latin","Revival","Celtic","Bluegrass","Avantgarde","Gothic rock","Progressive rock","Psychedelic rock","Symphonic rock","Slow rock","Big band","Chorus","Easy listening","Acoustic","Humour","Speech","Chanson","Opera","Chamber music","Sonata","Symphony","Booty bass","Primus","Porn groove","Satire","Slow jam","Club","Tango","Samba","Folklore","Ballad","Power ballad","Rhythmic Soul","Freestyle","Duet","Punk rock","Drum solo","A cappella","Euro-house","Dance hall","Goa music","Drum & bass","Club-house","Hardcore techno","Terror","Indie","Britpop","Negerpunk","Polsk punk","Beat","Christian gangsta rap","Heavy metal","Black metal","Crossover","Contemporary Christian","Christian rock","Merengue","Salsa","Thrash metal","Anime","Jpop","Synthpop","Christmas","Art rock","Baroque","Bhangra","Big beat","Breakbeat","Chillout","Downtempo","Dub","EBM","Eclectic","Electro","Electroclash","Emo","Experimental","Garage","Global","IDM","Illbient","Industro-Goth","Jam Band","Krautrock","Leftfield","Lounge","Math rock","New romantic","Nu-breakz","Post-punk","Post-rock","Psytrance","Shoegaze","Space rock","Trop rock","World music","Neoclassical","Audiobook","Audio theatre","Neue Deutsche Welle","Podcast","Indie rock","G-Funk","Dubstep","Garage rock","Psybient"],Ya=(e,t)=>{var i;const r=e.filePos;null!=t.raw||(t.raw={}),null!=(i=t.raw).TAG||(i.TAG=xa(e,$a-3)),e.filePos=r;const n=Ja(e,30);n&&(null!=t.title||(t.title=n));const s=Ja(e,30);s&&(null!=t.artist||(t.artist=s));const a=Ja(e,30);a&&(null!=t.album||(t.album=a));const o=Ja(e,4),l=Number.parseInt(o,10);Number.isInteger(l)&&l>0&&(null!=t.date||(t.date=new Date(l,0,1)));const c=xa(e,30);let u;if(0===c[28]&&0!==c[29]){const i=c[29];i>0&&(null!=t.trackNumber||(t.trackNumber=i)),e.skip(-30),u=Ja(e,28),e.skip(2)}else e.skip(-30),u=Ja(e,30);u&&(null!=t.comment||(t.comment=u));const d=Ca(e);d{const i=xa(e,t),r=me(i.indexOf(0),i.length),n=i.subarray(0,r);let s="";for(let a=0;a{const t=e.filePos,i=Wa(e,3),r=Ca(e),n=Ca(e),s=Ca(e),a=Ra(e);if("ID3"!==i||255===r||255===n||0!==(2155905152&a))return e.filePos=t,null;return{majorVersion:r,revision:n,flags:s,size:Je(a)}},eo=(e,t,i)=>{var r,n,s,a,o,l;if(![2,3,4].includes(t.majorVersion))return void console.warn(`Unsupported ID3v2 major version: ${t.majorVersion}`);const c=xa(e,t.size),u=new to(t,c);if(t.flags&Ha.Footer&&u.removeFooter(),t.flags&Ha.Unsynchronisation&&3===t.majorVersion&&u.ununsynchronizeAll(),t.flags&Ha.ExtendedHeader){const e=u.readU32();3===t.majorVersion?u.pos+=e:u.pos+=e-4}for(;u.pos<=u.bytes.length-u.frameHeaderSize();){const e=u.readId3V2Frame();if(!e)break;const c=u.pos,d=u.pos+e.size;let h=!1,f=!1,m=!1;if(3===t.majorVersion?(h=!!(64&e.flags),f=!!(128&e.flags)):4===t.majorVersion&&(h=!!(4&e.flags),f=!!(8&e.flags),m=!!(2&e.flags)||!!(t.flags&Ha.Unsynchronisation)),h)console.warn(`Skipping encrypted ID3v2 frame ${e.id}`),u.pos=d;else if(f)console.warn(`Skipping compressed ID3v2 frame ${e.id}`),u.pos=d;else{if(m&&u.ununsynchronizeRegion(u.pos,d),null!=i.raw||(i.raw={}),"TXXX"===e.id){const e=null!=(n=(r=i.raw).TXXX)?n:r.TXXX={},t=u.readId3V2TextEncoding(),s=u.readId3V2Text(t,d),a=u.readId3V2Text(t,d);null!=e[s]||(e[s]=a)}else"T"===e.id[0]?null!=(s=i.raw)[a=e.id]||(s[a]=u.readId3V2EncodingAndText(d)):null!=(o=i.raw)[l=e.id]||(o[l]=u.readBytes(e.size));switch(u.pos=c,e.id){case"TIT2":case"TT2":null!=i.title||(i.title=u.readId3V2EncodingAndText(d));break;case"TIT3":case"TT3":null!=i.description||(i.description=u.readId3V2EncodingAndText(d));break;case"TPE1":case"TP1":null!=i.artist||(i.artist=u.readId3V2EncodingAndText(d));break;case"TALB":case"TAL":null!=i.album||(i.album=u.readId3V2EncodingAndText(d));break;case"TPE2":case"TP2":null!=i.albumArtist||(i.albumArtist=u.readId3V2EncodingAndText(d));break;case"TRCK":case"TRK":{const e=u.readId3V2EncodingAndText(d).split("/"),t=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(null!=i.trackNumber||(i.trackNumber=t)),r&&Number.isInteger(r)&&r>0&&(null!=i.tracksTotal||(i.tracksTotal=r))}break;case"TPOS":case"TPA":{const e=u.readId3V2EncodingAndText(d).split("/"),t=Number.parseInt(e[0],10),r=e[1]&&Number.parseInt(e[1],10);Number.isInteger(t)&&t>0&&(null!=i.discNumber||(i.discNumber=t)),r&&Number.isInteger(r)&&r>0&&(null!=i.discsTotal||(i.discsTotal=r))}break;case"TCON":case"TCO":{const e=u.readId3V2EncodingAndText(d);let t=/^\((\d+)\)/.exec(e);if(t){const e=Number.parseInt(t[1]);if(void 0!==Ga[e]){null!=i.genre||(i.genre=Ga[e]);break}}if(t=/^\d+$/.exec(e),t){const e=Number.parseInt(t[0]);if(void 0!==Ga[e]){null!=i.genre||(i.genre=Ga[e]);break}}null!=i.genre||(i.genre=e)}break;case"TDRC":case"TDAT":{const e=u.readId3V2EncodingAndText(d),t=new Date(e);Number.isNaN(t.getTime())||null!=i.date||(i.date=t)}break;case"TYER":case"TYE":{const e=u.readId3V2EncodingAndText(d),t=Number.parseInt(e,10);Number.isInteger(t)&&(null!=i.date||(i.date=new Date(t,0,1)))}break;case"USLT":case"ULT":{const e=u.readU8();u.pos+=3,u.readId3V2Text(e,d),null!=i.lyrics||(i.lyrics=u.readId3V2Text(e,d))}break;case"COMM":case"COM":{const e=u.readU8();u.pos+=3,u.readId3V2Text(e,d),null!=i.comment||(i.comment=u.readId3V2Text(e,d))}break;case"APIC":case"PIC":{const e=u.readId3V2TextEncoding();let r;if(2===t.majorVersion){const e=u.readAscii(3);r="PNG"===e?"image/png":"JPG"===e?"image/jpeg":"image/*"}else r=u.readId3V2Text(e,d);const n=u.readU8(),s=u.readId3V2Text(e,d).trimEnd(),a=d-u.pos;if(a>=0){const e=u.readBytes(a);i.images||(i.images=[]),i.images.push({data:e,mimeType:r,kind:3===n?"coverFront":4===n?"coverBack":"unknown",description:s})}}break;default:u.pos+=e.size}u.pos=d}}};class to{constructor(e,t){this.header=e,this.bytes=t,this.pos=0,this.view=new DataView(t.buffer,t.byteOffset,t.byteLength)}frameHeaderSize(){return 2===this.header.majorVersion?6:10}ununsynchronizeAll(){const e=[];for(let t=0;t{const t=this.pos+e;if(t>this.bytes.length)return!1;if(t<=this.bytes.length-this.frameHeaderSize()){this.pos+=e;const t=this.readAscii(4);if("\0\0\0\0"!==t&&!/[0-9A-Z]{4}/.test(t))return!1}return!0};if(!s(i)){const e=4===this.header.majorVersion?t:Je(t);s(e)&&(i=e)}return this.pos=n,{id:e,size:i,flags:r}}}readId3V2TextEncoding(){const e=this.readU8();if(e>3)throw new Error(`Unsupported text encoding: ${e}`);return e}readId3V2Text(e,t){const i=this.pos,r=this.readBytes(t-this.pos);switch(e){case ja.ISO_8859_1:{let e="";for(let t=0;t0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(2,t))}if(254===r[0]&&255===r[1]){const e=new TextDecoder("utf-16be"),t=me(r.findIndex((e,t)=>0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(2,t))}{const e=me(r.findIndex(e=>0===e),r.length);return this.pos=i+Math.min(e+1,r.length),I.decode(r.subarray(0,e))}case ja.UTF_16_BE_NO_BOM:{const e=new TextDecoder("utf-16be"),t=me(r.findIndex((e,t)=>0===e&&0===r[t+1]&&t%2===0),r.length);return this.pos=i+Math.min(t+2,r.length),e.decode(r.subarray(0,t))}case ja.UTF_8:{const e=me(r.findIndex(e=>0===e),r.length);return this.pos=i+Math.min(e+1,r.length),I.decode(r.subarray(0,e))}}}readId3V2EncodingAndText(e){if(this.pos>=e)return"";const t=this.readId3V2TextEncoding();return this.readId3V2Text(t,e)}}class io{constructor(e){this.events=e,this.input=null,this.audioSink=null,this.audioIterator=null,this.audioContext=null,this.gainNode=null,this.audioContextStartTime=0,this.playbackTimeAtStart=0,this.latestScheduledEndTime=0,this.duration=Number.NaN,this.paused=!0,this.volume=.7,this.muted=!1,this.playbackRate=1,this.asyncId=0,this.queuedNodes=new Set}get currentTime(){return this.paused?this.playbackTimeAtStart:(this.audioContext.currentTime-this.audioContextStartTime)*this.playbackRate+this.playbackTimeAtStart}ensureAudioContext(e){if(this.audioContext)return;const t=window.AudioContext||window.webkitAudioContext;try{this.audioContext=new t({sampleRate:e})}catch(i){this.audioContext=new t}this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination),this.updateGain()}updateGain(){if(!this.gainNode)return;const e=this.muted?0:this.volume;this.gainNode.gain.value=e*e}stopQueuedNodes(){this.queuedNodes.forEach(e=>e.stop()),this.queuedNodes.clear()}stopIterator(){return d(this,null,function*(){var e;yield null==(e=this.audioIterator)?void 0:e.return(),this.audioIterator=null})}handleNoAudioTrack(){this.audioSink=null,this.ensureAudioContext()}load(e,t){return d(this,null,function*(){++this.asyncId,yield this.stopIterator(),this.stopQueuedNodes(),this.paused=!0,this.playbackTimeAtStart=0,this.audioContextStartTime=0;const{input:i,audioTrack:r,duration:n}=e;return this.input=i,this.duration=n,r?null!==r.codec&&(yield r.canDecode())?(this.ensureAudioContext(r.sampleRate),this.audioSink=new oa(r),void(null==t||t())):(this.audioSink=null,this.ensureAudioContext(),void(null==t||t())):(this.handleNoAudioTrack(),void(null==t||t()))})}runIterator(e){return d(this,null,function*(){if(this.audioSink)for(yield this.stopIterator(),this.audioIterator=this.audioSink.buffers(this.currentTime);;){if(e!==this.asyncId||this.paused)return;const i=this.audioIterator.next(),r=setInterval(()=>{e!==this.asyncId||this.paused?clearInterval(r):"running"===this.audioContext.state&&this.audioContext.currentTime>=this.latestScheduledEndTime-.2&&(this.audioContext.suspend(),this.events.emit("waiting"))},50);let n;try{n=yield i}catch(t){console.error("Audio iterator error:",t);break}finally{clearInterval(r)}if(e!==this.asyncId||this.paused)return;if("suspended"===this.audioContext.state&&(yield this.audioContext.resume(),this.events.emit("canplay"),this.events.emit("playing")),n.done)break;const{buffer:s,timestamp:a}=n.value,o=this.audioContext.createBufferSource();o.buffer=s,o.connect(this.gainNode),o.playbackRate.value=this.playbackRate;const l=this.audioContextStartTime+(a-this.playbackTimeAtStart)/this.playbackRate,c=l+s.duration/this.playbackRate;c>this.latestScheduledEndTime&&(this.latestScheduledEndTime=c),l>=this.audioContext.currentTime?o.start(l):o.start(this.audioContext.currentTime,(this.audioContext.currentTime-l)*this.playbackRate),this.queuedNodes.add(o),o.onended=()=>this.queuedNodes.delete(o)}})}play(){return d(this,null,function*(){if(!this.paused)return;this.audioContext||this.ensureAudioContext(),"suspended"===this.audioContext.state&&(yield this.audioContext.resume()),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime,this.paused=!1;const e=++this.asyncId;this.runIterator(e)})}pause(){this.paused||(this.playbackTimeAtStart=this.currentTime,this.paused=!0,this.stopIterator(),this.stopQueuedNodes())}seek(e){return d(this,null,function*(){this.playbackTimeAtStart=Math.max(0,e),this.audioContextStartTime=this.audioContext.currentTime,this.latestScheduledEndTime=this.audioContextStartTime;const t=++this.asyncId;this.paused||this.runIterator(t)})}setVolume(e,t){this.volume=e,this.muted=t,this.updateGain()}setPlaybackRate(e){if(e!==this.playbackRate&&(this.paused||(this.playbackTimeAtStart=this.currentTime,this.audioContextStartTime=this.audioContext.currentTime),this.playbackRate=e,!this.paused)){const e=++this.asyncId;this.runIterator(e)}}destroy(){var e;this.asyncId++,this.pause(),null==(e=this.audioContext)||e.close(),this.audioContext=null,this.input=null,this.audioSink=null}}const ro=/\.m3u8(?:$|[?#])/i;function no(e){return"string"===typeof e&&ro.test(e)}function so(e){const t=function(e){return"string"===typeof e?new Mn(e):e instanceof Blob?new An(e):"undefined"!==typeof ReadableStream&&e instanceof ReadableStream?new Nn(e):null!=e?e:null}(e);return t?new Ta({source:t,formats:no(e)?ws:vs}):null}function ao(e){return d(this,arguments,function*({input:e,videoTrack:t,audioTrack:i}){const r=[t,i].filter(Boolean),n=t||i,s=Boolean(n&&(yield n.isLive()));let a=Number.NaN;return r.length>0&&(a=yield e.getDurationFromMetadata(r,{skipLiveWait:!0}),null!==a||s||(a=yield e.computeDuration(r,{skipLiveWait:!0}))),s?Number.POSITIVE_INFINITY:null!=a?a:Number.NaN})}function oo(e){return d(this,null,function*(){var t,i;return null!=(i=null!=(t=yield e.getAverageBitrate())?t:yield e.getBitrate())?i:0})}class lo{constructor({canvas:e,ctx:t,events:i,timeupdateInterval:r=250,avSyncTolerance:n=.12,dropLateFrames:s=!1,poster:a="",preflightRange:o=!1}){this.canvas=e,this.ctx=t,this.events=i,this.timeupdateInterval=r,this.avSyncTolerance=n,this.dropLateFrames=s,this.poster=a,this.preflightRange=o,this.input=null,this.videoSink=null,this.videoIterator=null,this.nextFrame=null,this.rafId=0,this.asyncId=0,this.width=0,this.height=0,this.duration=Number.NaN,this.audioClock=null,this.lastTimeUpdate=0,this.stalled=!1,this.playbackRate=1,this.posterDrawn=!1,this.isFetching=!1}preflight(e){return d(this,null,function*(){if(!this.preflightRange||"string"!==typeof e||no(e))return!0;try{const t=(yield fetch(e,{method:"HEAD"})).headers.get("accept-ranges");return!(!t||"none"===t)||(this.events.emit("error",new Event("RangeNotSupported")),!1)}catch(t){return console.warn("Preflight check failed:",t),!0}})}drawPoster(){if(!this.poster||this.posterDrawn)return;const e=new Image;e.onload=()=>{this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.width=e.naturalWidth||this.canvas.width,this.canvas.height=e.naturalHeight||this.canvas.height,this.ctx.drawImage(e,0,0,this.canvas.width,this.canvas.height),this.posterDrawn=!0},e.src=this.poster}stopIterator(){return d(this,null,function*(){var e;yield null==(e=this.videoIterator)?void 0:e.return(),this.videoIterator=null})}clear(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}load(e,t){return d(this,null,function*(){++this.asyncId,yield this.stopIterator(),this.clear(),this.posterDrawn=!1;const{input:i,videoTrack:r,duration:n}=e;if(this.input=i,this.duration=n,!r)return this.handleNoVideoTrack(),void(null==t||t());if(null===r.codec||!(yield r.canDecode()))return this.handleNoVideoTrack(),void(null==t||t());const s=yield r.canBeTransparent();this.videoSink=new ra(r,{poolSize:2,fit:"contain",alpha:s}),this.width=r.displayWidth,this.height=r.displayHeight,this.canvas.width=this.width,this.canvas.height=this.height,null==t||t(),yield this.resetIterator(0)})}handleNoVideoTrack(){this.videoSink=null,this.width=0,this.height=0,this.canvas.width=0,this.canvas.height=0,this.clear(),this.drawPoster()}resetIterator(e){return d(this,null,function*(){var t,i;if(yield this.stopIterator(),!this.videoSink)return;this.videoIterator=this.videoSink.canvases(e);const r=null!=(t=(yield this.videoIterator.next()).value)?t:null,n=null!=(i=(yield this.videoIterator.next()).value)?i:null;this.nextFrame=n,r?this.ctx.drawImage(r.canvas,0,0):this.drawPoster()})}updateNextFrame(e){return d(this,null,function*(){var t;if(this.videoIterator&&!this.isFetching){this.isFetching=!0;try{for(;;){const i=null!=(t=(yield this.videoIterator.next()).value)?t:null;if(!i||e!==this.asyncId)return;const r=this.audioClock.currentTime,n=this.dropLateFrames?Math.max(.06,this.avSyncTolerance/Math.max(1,this.playbackRate)):0;if(!(this.dropLateFrames&&i.timestampr)return void(this.nextFrame=null)}}}finally{this.isFetching=!1}}})}render(){if(!this.audioClock)return;const e=this.audioClock.currentTime,t=Date.now();if(t-this.lastTimeUpdate>=this.timeupdateInterval&&(this.events.emit("timeupdate"),this.lastTimeUpdate=t),Number.isFinite(this.duration)&&e>=this.duration)return this.stop(),this.stalled=!1,this.events.emit("ended"),this.events.emit("pause"),void this.events.emit("canplay");this.nextFrame&&this.nextFrame.timestamp<=e?(this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextFrame.canvas,0,0),this.nextFrame=null,this.updateNextFrame(this.asyncId),this.stalled&&(this.events.emit("canplay"),this.events.emit("playing"),this.stalled=!1)):this.nextFrame||(this.updateNextFrame(this.asyncId),!this.nextFrame&&Number.isFinite(this.duration)&&ethis.render())}start(e){this.audioClock=e,this.asyncId++,this.stalled=!1,this.updateNextFrame(this.asyncId),this.rafId=requestAnimationFrame(()=>this.render())}stop(){cancelAnimationFrame(this.rafId)}seek(e){return d(this,null,function*(){this.asyncId++,yield this.resetIterator(e)})}setPlaybackRate(e){this.playbackRate=Math.max(.1,Number(e)||1)}destroy(){this.asyncId++,this.stop(),this.stopIterator(),this.posterDrawn=!1,this.videoSink=null,this.input=null}}class co{constructor({canvas:e,ctx:t,events:i,option:r={}}){var n,s,a,o,l,c;this.events=i,this.option=r,this.audio=new io(i),this.video=new lo({canvas:e,ctx:t,events:i,timeupdateInterval:null!=(n=r.timeupdateInterval)?n:250,avSyncTolerance:null!=(s=r.avSyncTolerance)?s:.12,dropLateFrames:null!=(a=r.dropLateFrames)&&a,poster:null!=(o=r.poster)?o:"",preflightRange:null!=(l=r.preflightRange)&&l}),this.paused=!0,this.ended=!1,this.readyState=0,this.networkState=0,this.error=null,this.seeking=!1,this.loadSeq=0,this.input=null,this.media=null,null==(c=i.addEventListener)||c.call(i,"ended",()=>{this.ended=!0,this.paused=!0})}load(e){return d(this,null,function*(){const t=++this.loadSeq;this.pause(),this.disposeInput(),this.ended=!1,this.error=null,this.networkState=2,this.readyState=0,setTimeout(()=>this.events.emit("waiting"),0),setTimeout(()=>this.events.emit("loadstart"),0);const i=Number.isFinite(this.option.loadTimeout)?this.option.loadTimeout:0;try{yield Promise.race([this.performLoad(e,t),i>0?this.createTimeout(i):new Promise(()=>{})])}catch(r){if(t!==this.loadSeq)return;this.loadSeq++,this.error={code:4,message:r.message},this.networkState=3,this.events.emit("error")}})}performLoad(e,t){return d(this,null,function*(){if(!(yield this.video.preflight(e)))return;const i=so(e);if(!i)return this.video.handleNoVideoTrack(),void this.audio.handleNoAudioTrack();const r=yield function(e,t){return d(this,null,function*(){const i=yield e.getPrimaryVideoTrack(),r=i?yield i.getPrimaryPairableAudioTrack():yield e.getPrimaryAudioTrack(),n=yield ao({input:e,videoTrack:i,audioTrack:r});return{input:e,videoTrack:i,audioTrack:r,duration:n,isLive:!Number.isFinite(n)&&Boolean((i||r)&&(yield(i||r).isLive())),isHls:no(t),videoMode:no(t)?"auto":"manual",audioMode:no(t)?"auto":"manual"}})}(i,e);if(t!==this.loadSeq)return void i.dispose();this.disposeInput(),this.input=i,this.media=r;let n=!r.videoTrack,s=!r.audioTrack;const a=()=>{n&&s&&(this.readyState=1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"))};try{if(yield Promise.all([this.video.load(r,()=>{t===this.loadSeq&&(n=!0,a())}),this.audio.load(r,()=>{t===this.loadSeq&&(s=!0,a())})]),t!==this.loadSeq)return;this.readyState=4,this.networkState=1,this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("progress")}catch(o){if(t!==this.loadSeq)return;this.error={code:4,message:o.message},this.networkState=3,this.events.emit("error"),console.error("MediaBunny load error:",o)}})}createTimeout(e){return new Promise((t,i)=>{setTimeout(()=>i(new Error("Load timeout")),e)})}disposeInput(){var e;null==(e=this.input)||e.dispose(),this.input=null,this.media=null}replaceTracks(e){return d(this,arguments,function*({videoTrack:e,audioTrack:t,videoMode:i,audioMode:r}){if(!this.media)return;const n=u(c({},this.media),{videoTrack:e,audioTrack:t,videoMode:i,audioMode:r}),s=!this.paused,a=this.currentTime;this.pause(),this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),n.duration=yield ao(n),this.media=n,yield Promise.all([this.video.load(n),this.audio.load(n)]),yield Promise.all([this.video.seek(a),this.audio.seek(a)]),this.readyState=4,this.networkState=1,this.seeking=!1,this.events.emit("loadedmetadata"),this.events.emit("durationchange"),this.events.emit("progress"),this.events.emit("loadeddata"),this.events.emit("canplay"),this.events.emit("canplaythrough"),this.events.emit("seeked"),s&&(yield this.play())})}selectHlsQuality(e){return d(this,null,function*(){var t,i;if(!(null==(t=this.media)?void 0:t.isHls)||!this.input)return;const r=yield this.input.getVideoTracks(),n="auto"===e?yield this.input.getPrimaryVideoTrack():null!=(i=r.find(t=>t.id===e))?i:this.media.videoTrack;if(!n)return;let s=this.media.audioTrack,a=this.media.audioMode;s&&n.canBePairedWith(s)||(s=yield n.getPrimaryPairableAudioTrack(),a="auto"),yield this.replaceTracks({videoTrack:n,audioTrack:s,videoMode:"auto"===e?"auto":"manual",audioMode:a})})}selectHlsAudio(e){return d(this,null,function*(){var t,i;if(!(null==(t=this.media)?void 0:t.isHls)||!this.input)return;const r=yield this.input.getAudioTracks(),n="auto"===e?this.media.videoTrack?yield this.media.videoTrack.getPrimaryPairableAudioTrack():yield this.input.getPrimaryAudioTrack():null!=(i=r.find(t=>t.id===e))?i:this.media.audioTrack;if(!n)return;let s=this.media.videoTrack,a=this.media.videoMode;s&&n.canBePairedWith(s)||(s=yield n.getPrimaryPairableVideoTrack(),a="auto"),yield this.replaceTracks({videoTrack:s,audioTrack:n,videoMode:a,audioMode:"auto"===e?"auto":"manual"})})}getHlsState(){return function(e){return d(this,null,function*(){var t,i,r,n;if(!(null==e?void 0:e.isHls)||!e.input)return null;const[s,a]=yield Promise.all([e.input.getVideoTracks(),e.videoTrack?e.videoTrack.getPairableAudioTracks():[]]),[o,l]=yield Promise.all([Promise.all(s.map((e,t)=>d(null,null,function*(){return{id:e.id,track:e,index:t,name:yield e.getName(),height:yield e.getDisplayHeight(),bitrate:yield oo(e)}}))),Promise.all(a.map((e,t)=>d(null,null,function*(){const i=yield e.getName(),r=yield e.getLanguageCode();return{id:e.id,track:e,index:t,name:i,lang:r,language:r,bitrate:yield oo(e)}})))]);return{levels:o,audios:l,currentLevel:e.videoTrack&&null!=(t=o.find(t=>t.id===e.videoTrack.id))?t:null,currentAudio:e.audioTrack&&null!=(i=l.find(t=>t.id===e.audioTrack.id))?i:null,videoMode:null!=(r=e.videoMode)?r:"auto",audioMode:null!=(n=e.audioMode)?n:"auto"}})}(this.media)}play(){return d(this,null,function*(){this.paused&&(this.ended&&(this.ended=!1,yield this.seek(0)),this.paused=!1,yield this.audio.play(),this.video.start(this.audio),this.events.emit("play"),this.events.emit("playing"))})}pause(){this.paused||(this.paused=!0,this.audio.pause(),this.video.stop(),this.events.emit("pause"))}seek(e){return d(this,null,function*(){const t=!this.paused;this.ended=!1,this.seeking=!0,this.events.emit("seeking"),this.events.emit("waiting"),this.pause(),yield Promise.all([this.audio.seek(e),this.video.seek(e)]),this.seeking=!1,this.events.emit("seeked"),t&&!this.ended&&(yield this.play())})}setVolume(e,t){this.audio.setVolume(e,t)}setPlaybackRate(e){this.audio.setPlaybackRate(e),this.video.setPlaybackRate(e)}destroy(){this.pause(),this.disposeInput(),this.audio.destroy(),this.video.destroy()}get currentTime(){return this.audio.currentTime}get duration(){var e,t,i;return null!=(i=null!=(t=null==(e=this.media)?void 0:e.duration)?t:this.audio.duration)?i:this.video.duration}get videoWidth(){return this.video.width}get videoHeight(){return this.video.height}}class uo{constructor({art:e,canvas:t,ctx:i,option:r}){var n,s;this.art=e,this.canvas=t,this.option=r,this.events=new k,this.engine=new co({canvas:t,ctx:i,events:this.events,option:r}),this._src=null,this._volume=null!=(n=r.volume)?n:.7,this._muted=!!r.muted,this._playbackRate=1,this.engine.setVolume(this._volume,this._muted),this.setupEventForwarding(),r.source?this.src=r.source:(null==(s=e.option)?void 0:s.url)&&(this.src=e.option.url)}setupEventForwarding(){const{events:e}=this.art.constructor.config;e.forEach(e=>{this.events.addEventListener(e,e=>{this.art.emit(`video:${e.type}`,e)})})}addEventListener(e,t){this.events.addEventListener(e,t)}removeEventListener(e,t){this.events.removeEventListener(e,t)}get src(){return this._src}set src(e){this._src=e,e&&this.engine.load(e)}get currentSrc(){return this._src}get currentTime(){return this.engine.currentTime}set currentTime(e){this.engine.seek(Number(e)||0)}get duration(){return this.engine.duration}get buffered(){return this.createTimeRanges(0,this.engine.duration)}get played(){return this.createTimeRanges(0,this.engine.currentTime)}get seekable(){return this.createTimeRanges(0,this.engine.duration)}createTimeRanges(e,t){const i=this.engine.duration;return!i||Number.isNaN(i)||t<=0?{length:0,start:()=>0,end:()=>0}:{length:1,start:()=>e,end:()=>t}}get paused(){return this.engine.paused}get playing(){return!this.engine.paused&&!this.engine.ended}get ended(){return this.engine.ended}get seeking(){return this.engine.seeking}get readyState(){return this.engine.readyState}get networkState(){return this.engine.networkState}get error(){return this.engine.error}get playbackRate(){return this._playbackRate}set playbackRate(e){const t=Number(e);Number.isNaN(t)||t<=0||(this._playbackRate=t,this.engine.setPlaybackRate(t),this.events.emit("ratechange"))}get volume(){return this._volume}set volume(e){this._volume=function(e,t,i){return Math.max(t,Math.min(i,Number(e)||0))}(e,0,1),this._muted=!1,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}get muted(){return this._muted}set muted(e){this._muted=!!e,this.engine.setVolume(this._volume,this._muted),this.events.emit("volumechange")}play(){return this.engine.play()}pause(){this.engine.pause()}load(){this._src&&this.engine.load(this._src)}getM3u8State(){return this.engine.getHlsState()}switchM3u8Quality(e){return this.engine.selectHlsQuality(e)}switchM3u8Audio(e){return this.engine.selectHlsAudio(e)}get videoWidth(){return this.engine.videoWidth}get videoHeight(){return this.engine.videoHeight}get poster(){return this.option.poster||""}set poster(e){this.option.poster=e}get autoplay(){return this.option.autoplay||!1}set autoplay(e){}get loop(){return this.option.loop||!1}set loop(e){}get controls(){return!1}set controls(e){}get playsInline(){return!0}set playsInline(e){}get crossOrigin(){return this.option.crossOrigin||""}set crossOrigin(e){}get preload(){return"auto"}set preload(e){}get defaultMuted(){return!1}set defaultMuted(e){}get defaultPlaybackRate(){return 1}set defaultPlaybackRate(e){}canPlayType(e){return"maybe"}getBoundingClientRect(){return this.canvas.getBoundingClientRect()}requestVideoFrameCallback(e){return requestAnimationFrame(t=>{e(t,{presentationTime:this.engine.currentTime,expectedDisplayTime:t+16.6,width:this.engine.videoWidth,height:this.engine.videoHeight,mediaTime:this.engine.currentTime,presentedFrames:0,processingDuration:0,captureTime:t,receiveTime:t,rtpTimestamp:0})})}cancelVideoFrameCallback(e){cancelAnimationFrame(e)}setAttribute(e,t){"src"===e?this.src=t:"autoplay"===e?this.autoplay=t:"loop"===e?this.loop=t:"muted"===e?this.muted=!0:this.canvas.setAttribute(e,t)}destroy(){this.engine.destroy()}}return function(e={}){return t=>{const{constructor:i}=t,{createElement:r}=i.utils,n=r("canvas"),s=n.getContext("2d"),a=new uo({art:t,canvas:n,ctx:s,option:e});t.mediabunny=a;const o={};for(const e in n)"function"===typeof n[e]&&(o[e]=n[e].bind(n));const l=new Set([...Object.getOwnPropertyNames(a),...Object.getOwnPropertyNames(Object.getPrototypeOf(a))]);for(const e of l)"constructor"!==e&&(e in n||Object.defineProperty(n,e,{get(){const t=a[e];return"function"===typeof t?t.bind(a):t},set(t){a[e]=t},configurable:!0,enumerable:!0}));for(const e in o)n[e]=(...t)=>o[e](...t);function c(){var e;(null==(e=t.template)?void 0:e.$player)&&!t.option.autoSize&&Object.assign(n.style,{width:"100%",height:"100%",objectFit:"contain"})}return t.on("resize",c),t.on("video:loadedmetadata",c),function({art:e,shim:t,option:i}){if(i.m3u8)return e.on("video:loadedmetadata",u),e.on("restart",u),{update:u};function r(t){e.controls.cache.has(t)&&e.controls.remove(t)}function n(t){e.setting.find(t)&&e.setting.remove(t)}function s(){r("mediabunny-quality"),n("mediabunny-quality")}function a(){r("mediabunny-audio"),n("mediabunny-audio")}function o(e={}){return e.control||e.setting}function l(r){return d(this,null,function*(){var n;const a=(null==(n=i.m3u8)?void 0:n.quality)||{};if(!o(a)||!(null==r?void 0:r.levels.length))return void s();const l=a.auto||"Auto",c=a.title||"Quality",h=a.getName||(e=>e.name||`${e.height}P`),f=r.currentLevel?h(r.currentLevel):l,m=g(r.levels.map(e=>{var t;return{html:h(e),value:e.id,default:(null==(t=r.currentLevel)?void 0:t.id)===e.id}}),"html").sort((e,t)=>{const i=r.levels.find(t=>t.id===e.value),n=r.levels.find(e=>e.id===t.value);return((null==n?void 0:n.height)||0)-((null==i?void 0:i.height)||0)});m.push({html:l,value:"auto",default:!r.currentLevel});const p=i=>d(null,null,function*(){return yield t.switchM3u8Quality(i.value),e.notice.show=`${c}: ${i.html}`,yield u(),i.html});a.control&&e.controls.update({name:"mediabunny-quality",position:"right",html:f,style:{padding:"0 10px"},selector:m,onSelect:p}),a.setting&&e.setting.update({name:"mediabunny-quality",tooltip:f,html:c,icon:'',width:200,selector:m,onSelect:p})})}function c(r){return d(this,null,function*(){var n;const s=(null==(n=i.m3u8)?void 0:n.audio)||{};if(!o(s)||!(null==r?void 0:r.audios.length)||r.audios.length<2)return void a();const l=s.auto||"Auto",c=s.title||"Audio",h=s.getName||(e=>e.name||e.lang||e.language),f=r.currentAudio?h(r.currentAudio):l,m=g(r.audios.map(e=>{var t;return{html:h(e),value:e.id,default:(null==(t=r.currentAudio)?void 0:t.id)===e.id}}),"html");m.push({html:l,value:"auto",default:!r.currentAudio});const p=i=>d(null,null,function*(){return yield t.switchM3u8Audio(i.value),e.notice.show=`${c}: ${i.html}`,yield u(),i.html});s.control&&e.controls.update({name:"mediabunny-audio",position:"right",html:f,style:{padding:"0 10px"},selector:m,onSelect:p}),s.setting&&e.setting.update({name:"mediabunny-audio",tooltip:f,html:c,icon:'',width:200,selector:m,onSelect:p})})}function u(){return d(this,null,function*(){const e=yield t.getM3u8State();if(!e)return s(),void a();yield Promise.all([l(e),c(e)])})}}({art:t,shim:a,option:e}),t.on("destroy",()=>{delete t.mediabunny,a.destroy()}),n}}}); diff --git a/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.mjs b/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.mjs index 77d3f9981..2cb05293a 100644 --- a/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.mjs +++ b/packages/artplayer-proxy-mediabunny/dist/artplayer-proxy-mediabunny.mjs @@ -1,9 +1,171 @@ /*! - * artplayer-proxy-mediabunny.js v1.1.0 + * artplayer-proxy-mediabunny.js v1.2.0 * Github: https://github.com/zhw2590582/ArtPlayer * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ +const $audio = ''; +const $quality = ''; +function uniqBy(array, property) { + const seen = /* @__PURE__ */ new Map(); + return array.filter((item) => { + const key = item[property]; + if (key === void 0) { + return true; + } + return !seen.has(key) && seen.set(key, 1); + }); +} +function setupM3u8Controls({ art, shim, option }) { + if (!option.m3u8) + return; + function removeControl(name) { + if (art.controls.cache.has(name)) { + art.controls.remove(name); + } + } + function removeSetting(name) { + if (art.setting.find(name)) { + art.setting.remove(name); + } + } + function clearQuality() { + removeControl("mediabunny-quality"); + removeSetting("mediabunny-quality"); + } + function clearAudio() { + removeControl("mediabunny-audio"); + removeSetting("mediabunny-audio"); + } + function canRender(config = {}) { + return config.control || config.setting; + } + async function updateQuality(state) { + const config = option.m3u8?.quality || {}; + if (!canRender(config) || !state?.levels.length) { + clearQuality(); + return; + } + const auto = config.auto || "Auto"; + const title = config.title || "Quality"; + const getName = config.getName || ((level) => level.name || `${level.height}P`); + const defaultHtml = state.currentLevel ? getName(state.currentLevel) : auto; + const selector = uniqBy( + state.levels.map((item) => { + return { + html: getName(item), + value: item.id, + default: state.currentLevel?.id === item.id + }; + }), + "html" + ).sort((a, b) => { + const left = state.levels.find((item) => item.id === a.value); + const right = state.levels.find((item) => item.id === b.value); + return (right?.height || 0) - (left?.height || 0); + }); + selector.push({ + html: auto, + value: "auto", + default: !state.currentLevel + }); + const onSelect = async (item) => { + await shim.switchM3u8Quality(item.value); + art.notice.show = `${title}: ${item.html}`; + await update(); + return item.html; + }; + if (config.control) { + art.controls.update({ + name: "mediabunny-quality", + position: "right", + html: defaultHtml, + style: { padding: "0 10px" }, + selector, + onSelect + }); + } + if (config.setting) { + art.setting.update({ + name: "mediabunny-quality", + tooltip: defaultHtml, + html: title, + icon: $quality, + width: 200, + selector, + onSelect + }); + } + } + async function updateAudio(state) { + const config = option.m3u8?.audio || {}; + if (!canRender(config) || !state?.audios.length || state.audios.length < 2) { + clearAudio(); + return; + } + const auto = config.auto || "Auto"; + const title = config.title || "Audio"; + const getName = config.getName || ((track) => track.name || track.lang || track.language); + const defaultHtml = state.currentAudio ? getName(state.currentAudio) : auto; + const selector = uniqBy( + state.audios.map((item) => { + return { + html: getName(item), + value: item.id, + default: state.currentAudio?.id === item.id + }; + }), + "html" + ); + selector.push({ + html: auto, + value: "auto", + default: !state.currentAudio + }); + const onSelect = async (item) => { + await shim.switchM3u8Audio(item.value); + art.notice.show = `${title}: ${item.html}`; + await update(); + return item.html; + }; + if (config.control) { + art.controls.update({ + name: "mediabunny-audio", + position: "right", + html: defaultHtml, + style: { padding: "0 10px" }, + selector, + onSelect + }); + } + if (config.setting) { + art.setting.update({ + name: "mediabunny-audio", + tooltip: defaultHtml, + html: title, + icon: $audio, + width: 200, + selector, + onSelect + }); + } + } + async function update() { + const state = await shim.getM3u8State(); + if (!state) { + clearQuality(); + clearAudio(); + return; + } + await Promise.all([ + updateQuality(state), + updateAudio(state) + ]); + } + art.on("video:loadedmetadata", update); + art.on("restart", update); + return { update }; +} class EventTarget { constructor() { this.listeners = /* @__PURE__ */ new Map(); @@ -48,66 +210,6 @@ const normalizeRotation = (rotation) => { const last = (arr) => { return arr && arr[arr.length - 1]; }; -class Bitstream { - constructor(bytes) { - this.bytes = bytes; - this.pos = 0; - } - seekToByte(byteOffset) { - this.pos = 8 * byteOffset; - } - readBit() { - const byteIndex = Math.floor(this.pos / 8); - const byte = this.bytes[byteIndex] ?? 0; - const bitIndex = 7 - (this.pos & 7); - const bit = (byte & 1 << bitIndex) >> bitIndex; - this.pos++; - return bit; - } - readBits(n) { - if (n === 1) { - return this.readBit(); - } - let result = 0; - for (let i = 0; i < n; i++) { - result <<= 1; - result |= this.readBit(); - } - return result; - } - writeBits(n, value) { - const end = this.pos + n; - for (let i = this.pos; i < end; i++) { - const byteIndex = Math.floor(i / 8); - let byte = this.bytes[byteIndex]; - const bitIndex = 7 - (i & 7); - byte &= ~(1 << bitIndex); - byte |= (value & 1 << end - i - 1) >> end - i - 1 << bitIndex; - this.bytes[byteIndex] = byte; - } - this.pos = end; - } - readAlignedByte() { - if (this.pos % 8 !== 0) { - throw new Error("Bitstream is not byte-aligned."); - } - const byteIndex = this.pos / 8; - const byte = this.bytes[byteIndex] ?? 0; - this.pos += 8; - return byte; - } - skipBits(n) { - this.pos += n; - } - getBitsLeft() { - return this.bytes.length * 8 - this.pos; - } - clone() { - const clone = new Bitstream(this.bytes); - clone.pos = this.pos; - return clone; - } -} const readExpGolomb = (bitstream) => { let leadingZeroBits = 0; while (bitstream.readBits(1) === 0 && leadingZeroBits < 32) { @@ -192,21 +294,40 @@ const isAllowSharedBufferSource = (x) => { class AsyncMutex { constructor() { this.currentPromise = Promise.resolve(); + this.pending = 0; } async acquire() { let resolver; const nextPromise = new Promise((resolve) => { - resolver = resolve; + let resolved = false; + resolver = () => { + if (resolved) { + return; + } + resolve(); + this.pending--; + resolved = true; + }; }); const currentPromiseAlias = this.currentPromise; this.currentPromise = nextPromise; + this.pending++; await currentPromiseAlias; return resolver; } } +const HEX_STRING_REGEX = /^[0-9a-fA-F]+$/; const bytesToHexString = (bytes) => { return [...bytes].map((x) => x.toString(16).padStart(2, "0")).join(""); }; +const hexStringToBytes = (hexString) => { + assert(hexString.length % 2 === 0); + const bytes = new Uint8Array(hexString.length / 2); + for (let i = 0; i < hexString.length; i += 2) { + bytes[i / 2] = parseInt(hexString.slice(i, i + 2), 16); + } + return bytes; +}; const reverseBitsU32 = (x) => { x = x >> 1 & 1431655765 | (x & 1431655765) << 1; x = x >> 2 & 858993459 | (x & 858993459) << 2; @@ -262,6 +383,12 @@ const promiseWithResolvers = () => { }); return { promise, resolve, reject }; }; +const removeItem = (arr, item) => { + const index = arr.indexOf(item); + if (index !== -1) { + arr.splice(index, 1); + } +}; const findLast = (arr, predicate) => { for (let i = arr.length - 1; i >= 0; i--) { if (predicate(arr[i])) { @@ -351,6 +478,12 @@ const roundIfAlmostInteger = (value) => { const roundToMultiple = (value, multiple) => { return Math.round(value / multiple) * multiple; }; +const roundToDivisor = (value, multiple) => { + return Math.round(value * multiple) / multiple; +}; +const floorToMultiple = (value, multiple) => { + return Math.floor(value / multiple) * multiple; +}; const ilog = (x) => { let ret = 0; while (x) { @@ -417,7 +550,7 @@ const retriedFetch = async (fetchFn, url, requestInit, getRetryDelay, shouldStop throw new TypeError("Retry delay must be a non-negative finite number."); } if (retryDelayInSeconds > 0) { - await new Promise((resolve) => setTimeout(resolve, 1e3 * retryDelayInSeconds)); + await wait(1e3 * retryDelayInSeconds); } if (shouldStop()) { throw error; @@ -438,7 +571,8 @@ const isWebKit = () => { if (isWebKitCache !== null) { return isWebKitCache; } - return isWebKitCache = !!(typeof navigator !== "undefined" && (navigator.vendor?.match(/apple/i) || /AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) || /\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent))); + return isWebKitCache = !!(typeof navigator !== "undefined" && // eslint-disable-next-line @typescript-eslint/no-deprecated + (navigator.vendor?.match(/apple/i) || /AppleWebKit/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent) || /\b(iPad|iPhone|iPod)\b/.test(navigator.userAgent))); }; let isFirefoxCache = null; const isFirefox = () => { @@ -482,12 +616,166 @@ const base64ToBytes = (base64) => { } return bytes; }; +const uint8ArraysAreEqual = (a, b) => { + if (a.length !== b.length) { + return false; + } + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; +}; const polyfillSymbolDispose = () => { Symbol.dispose ?? (Symbol.dispose = /* @__PURE__ */ Symbol("Symbol.dispose")); }; const isNumber = (x) => { return typeof x === "number" && !Number.isNaN(x); }; +const joinPaths = (basePath, relativePath) => { + if (relativePath.includes("://")) { + return relativePath; + } + if (basePath.includes("://")) { + const queryIndex = basePath.indexOf("?"); + if (queryIndex !== -1) { + basePath = basePath.slice(0, queryIndex); + } + } + let result; + if (relativePath.startsWith("/")) { + const protocolIndex2 = basePath.indexOf("://"); + if (protocolIndex2 === -1) { + result = relativePath; + } else { + const pathStart = basePath.indexOf("/", protocolIndex2 + 3); + if (pathStart === -1) { + result = basePath + relativePath; + } else { + result = basePath.slice(0, pathStart) + relativePath; + } + } + } else { + const lastSlash = basePath.lastIndexOf("/"); + if (lastSlash === -1) { + result = relativePath; + } else { + result = basePath.slice(0, lastSlash + 1) + relativePath; + } + } + let prefix = ""; + const protocolIndex = result.indexOf("://"); + if (protocolIndex !== -1) { + const pathStart = result.indexOf("/", protocolIndex + 3); + if (pathStart !== -1) { + prefix = result.slice(0, pathStart); + result = result.slice(pathStart); + } + } + const segments = result.split("/"); + const normalized = []; + for (const segment of segments) { + if (segment === "..") { + normalized.pop(); + } else if (segment !== ".") { + normalized.push(segment); + } + } + return prefix + normalized.join("/"); +}; +const arrayCount = (array, predicate) => { + let count = 0; + for (let i = 0; i < array.length; i++) { + if (predicate(array[i])) { + count++; + } + } + return count; +}; +const arrayArgmin = (array, getValue) => { + let minIndex = -1; + let minValue = Infinity; + for (let i = 0; i < array.length; i++) { + const value = getValue(array[i]); + if (value < minValue) { + minValue = value; + minIndex = i; + } + } + return minIndex; +}; +const simplifyRational = (rational) => { + assert(Number.isInteger(rational.num)); + assert(Number.isInteger(rational.den)); + assert(rational.den !== 0); + let a = Math.abs(rational.num); + let b = Math.abs(rational.den); + while (b !== 0) { + const t = a % b; + a = b; + b = t; + } + const gcd = a || 1; + return { + num: rational.num / gcd, + den: rational.den / gcd + }; +}; +const validateRectangle = (rect, propertyPath) => { + if (typeof rect !== "object" || !rect) { + throw new TypeError(`${propertyPath} must be an object.`); + } + if (!Number.isInteger(rect.left) || rect.left < 0) { + throw new TypeError(`${propertyPath}.left must be a non-negative integer.`); + } + if (!Number.isInteger(rect.top) || rect.top < 0) { + throw new TypeError(`${propertyPath}.top must be a non-negative integer.`); + } + if (!Number.isInteger(rect.width) || rect.width < 0) { + throw new TypeError(`${propertyPath}.width must be a non-negative integer.`); + } + if (!Number.isInteger(rect.height) || rect.height < 0) { + throw new TypeError(`${propertyPath}.height must be a non-negative integer.`); + } +}; +const wait = (ms) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; +class EventEmitter { + constructor() { + this._listeners = /* @__PURE__ */ new Map(); + } + /** Registers a listener for the given event. */ + on(event, listener, options) { + if (!this._listeners.has(event)) { + this._listeners.set(event, /* @__PURE__ */ new Set()); + } + const entry = { fn: listener, once: options?.once ?? false }; + this._listeners.get(event).add(entry); + return () => { + this._listeners.get(event)?.delete(entry); + }; + } + /** @internal */ + _emit(...args) { + const [event, data] = args; + const listeners = this._listeners.get(event); + if (!listeners) { + return; + } + for (const entry of listeners) { + try { + entry.fn(data); + } catch (error) { + console.error(error); + } + if (entry.once) { + listeners.delete(entry); + } + } + } +} class RichImageData { /** Creates a new {@link RichImageData}. */ constructor(data, mimeType) { @@ -524,12 +812,127 @@ class AttachedFile { } const DEFAULT_TRACK_DISPOSITION = { default: true, + primary: true, forced: false, original: false, commentary: false, hearingImpaired: false, visuallyImpaired: false }; +class Bitstream { + constructor(bytes) { + this.bytes = bytes; + this.pos = 0; + } + seekToByte(byteOffset) { + this.pos = 8 * byteOffset; + } + readBit() { + const byteIndex = Math.floor(this.pos / 8); + const byte = this.bytes[byteIndex] ?? 0; + const bitIndex = 7 - (this.pos & 7); + const bit = (byte & 1 << bitIndex) >> bitIndex; + this.pos++; + return bit; + } + readBits(n) { + if (n === 1) { + return this.readBit(); + } + let result = 0; + for (let i = 0; i < n; i++) { + result <<= 1; + result |= this.readBit(); + } + return result; + } + writeBits(n, value) { + const end = this.pos + n; + for (let i = this.pos; i < end; i++) { + const byteIndex = Math.floor(i / 8); + let byte = this.bytes[byteIndex]; + const bitIndex = 7 - (i & 7); + byte &= ~(1 << bitIndex); + byte |= (value & 1 << end - i - 1) >> end - i - 1 << bitIndex; + this.bytes[byteIndex] = byte; + } + this.pos = end; + } + readAlignedByte() { + if (this.pos % 8 !== 0) { + throw new Error("Bitstream is not byte-aligned."); + } + const byteIndex = this.pos / 8; + const byte = this.bytes[byteIndex] ?? 0; + this.pos += 8; + return byte; + } + skipBits(n) { + this.pos += n; + } + getBitsLeft() { + return this.bytes.length * 8 - this.pos; + } + clone() { + const clone = new Bitstream(this.bytes); + clone.pos = this.pos; + return clone; + } +} +const aacFrequencyTable = [ + 96e3, + 88200, + 64e3, + 48e3, + 44100, + 32e3, + 24e3, + 22050, + 16e3, + 12e3, + 11025, + 8e3, + 7350 +]; +const aacChannelMap = [-1, 1, 2, 3, 4, 5, 6, 8]; +const parseAacAudioSpecificConfig = (bytes) => { + if (!bytes || bytes.byteLength < 2) { + throw new TypeError("AAC description must be at least 2 bytes long."); + } + const bitstream = new Bitstream(bytes); + let objectType = bitstream.readBits(5); + if (objectType === 31) { + objectType = 32 + bitstream.readBits(6); + } + const frequencyIndex = bitstream.readBits(4); + let sampleRate = null; + if (frequencyIndex === 15) { + sampleRate = bitstream.readBits(24); + } else { + if (frequencyIndex < aacFrequencyTable.length) { + sampleRate = aacFrequencyTable[frequencyIndex]; + } + } + const channelConfiguration = bitstream.readBits(4); + let numberOfChannels = null; + if (channelConfiguration >= 1 && channelConfiguration <= 7) { + numberOfChannels = aacChannelMap[channelConfiguration]; + } + return { + objectType, + frequencyIndex, + sampleRate, + channelConfiguration, + numberOfChannels + }; +}; +const VIDEO_CODECS = [ + "avc", + "hevc", + "vp9", + "av1", + "vp8" +]; const PCM_AUDIO_CODECS = [ "pcm-s16", // We don't prefix 'le' so we're compatible with the WebCodecs-registered PCM codec strings @@ -547,6 +950,59 @@ const PCM_AUDIO_CODECS = [ "ulaw", "alaw" ]; +const NON_PCM_AUDIO_CODECS = [ + "aac", + "opus", + "mp3", + "vorbis", + "flac", + "ac3", + "eac3" +]; +const AUDIO_CODECS = [ + ...NON_PCM_AUDIO_CODECS, + ...PCM_AUDIO_CODECS +]; +const AVC_LEVEL_TABLE = [ + { maxMacroblocks: 99, maxBitrate: 64e3, maxDpbMbs: 396, level: 10 }, + // Level 1 + { maxMacroblocks: 396, maxBitrate: 192e3, maxDpbMbs: 900, level: 11 }, + // Level 1.1 + { maxMacroblocks: 396, maxBitrate: 384e3, maxDpbMbs: 2376, level: 12 }, + // Level 1.2 + { maxMacroblocks: 396, maxBitrate: 768e3, maxDpbMbs: 2376, level: 13 }, + // Level 1.3 + { maxMacroblocks: 396, maxBitrate: 2e6, maxDpbMbs: 2376, level: 20 }, + // Level 2 + { maxMacroblocks: 792, maxBitrate: 4e6, maxDpbMbs: 4752, level: 21 }, + // Level 2.1 + { maxMacroblocks: 1620, maxBitrate: 4e6, maxDpbMbs: 8100, level: 22 }, + // Level 2.2 + { maxMacroblocks: 1620, maxBitrate: 1e7, maxDpbMbs: 8100, level: 30 }, + // Level 3 + { maxMacroblocks: 3600, maxBitrate: 14e6, maxDpbMbs: 18e3, level: 31 }, + // Level 3.1 + { maxMacroblocks: 5120, maxBitrate: 2e7, maxDpbMbs: 20480, level: 32 }, + // Level 3.2 + { maxMacroblocks: 8192, maxBitrate: 2e7, maxDpbMbs: 32768, level: 40 }, + // Level 4 + { maxMacroblocks: 8192, maxBitrate: 5e7, maxDpbMbs: 32768, level: 41 }, + // Level 4.1 + { maxMacroblocks: 8704, maxBitrate: 5e7, maxDpbMbs: 34816, level: 42 }, + // Level 4.2 + { maxMacroblocks: 22080, maxBitrate: 135e6, maxDpbMbs: 110400, level: 50 }, + // Level 5 + { maxMacroblocks: 36864, maxBitrate: 24e7, maxDpbMbs: 184320, level: 51 }, + // Level 5.1 + { maxMacroblocks: 36864, maxBitrate: 24e7, maxDpbMbs: 184320, level: 52 }, + // Level 5.2 + { maxMacroblocks: 139264, maxBitrate: 24e7, maxDpbMbs: 696320, level: 60 }, + // Level 6 + { maxMacroblocks: 139264, maxBitrate: 48e7, maxDpbMbs: 696320, level: 61 }, + // Level 6.1 + { maxMacroblocks: 139264, maxBitrate: 8e8, maxDpbMbs: 696320, level: 62 } + // Level 6.2 +]; const VP9_LEVEL_TABLE = [ { maxPictureSize: 36864, maxBitrate: 2e5, level: 10 }, // Level 1 @@ -712,8 +1168,14 @@ const extractAudioCodecString = (trackInfo) => { if (aacCodecInfo.isMpeg2) { return "mp4a.67"; } else { - const audioSpecificConfig = parseAacAudioSpecificConfig(codecDescription); - return `mp4a.40.${audioSpecificConfig.objectType}`; + let objectType; + if (aacCodecInfo.objectType !== null) { + objectType = aacCodecInfo.objectType; + } else { + const audioSpecificConfig = parseAacAudioSpecificConfig(codecDescription); + objectType = audioSpecificConfig.objectType; + } + return `mp4a.40.${objectType}`; } } else if (codec === "mp3") { return "mp3"; @@ -723,58 +1185,15 @@ const extractAudioCodecString = (trackInfo) => { return "vorbis"; } else if (codec === "flac") { return "flac"; + } else if (codec === "ac3") { + return "ac-3"; + } else if (codec === "eac3") { + return "ec-3"; } else if (codec && PCM_AUDIO_CODECS.includes(codec)) { return codec; } throw new TypeError(`Unhandled codec '${codec}'.`); }; -const aacFrequencyTable = [ - 96e3, - 88200, - 64e3, - 48e3, - 44100, - 32e3, - 24e3, - 22050, - 16e3, - 12e3, - 11025, - 8e3, - 7350 -]; -const aacChannelMap = [-1, 1, 2, 3, 4, 5, 6, 8]; -const parseAacAudioSpecificConfig = (bytes) => { - if (!bytes || bytes.byteLength < 2) { - throw new TypeError("AAC description must be at least 2 bytes long."); - } - const bitstream = new Bitstream(bytes); - let objectType = bitstream.readBits(5); - if (objectType === 31) { - objectType = 32 + bitstream.readBits(6); - } - const frequencyIndex = bitstream.readBits(4); - let sampleRate = null; - if (frequencyIndex === 15) { - sampleRate = bitstream.readBits(24); - } else { - if (frequencyIndex < aacFrequencyTable.length) { - sampleRate = aacFrequencyTable[frequencyIndex]; - } - } - const channelConfiguration = bitstream.readBits(4); - let numberOfChannels = null; - if (channelConfiguration >= 1 && channelConfiguration <= 7) { - numberOfChannels = aacChannelMap[channelConfiguration]; - } - return { - objectType, - frequencyIndex, - sampleRate, - channelConfiguration, - numberOfChannels - }; -}; const OPUS_SAMPLE_RATE = 48e3; const PCM_CODEC_REGEX = /^pcm-([usf])(\d+)+(be)?$/; const parsePcmCodec = (codec) => { @@ -799,12 +1218,318 @@ const parsePcmCodec = (codec) => { const silentValue = codec === "pcm-u8" ? 2 ** 7 : 0; return { dataType, sampleSize, littleEndian, silentValue }; }; +const inferCodecFromCodecString = (codecString) => { + if (codecString.startsWith("avc1") || codecString.startsWith("avc3")) { + return "avc"; + } else if (codecString.startsWith("hev1") || codecString.startsWith("hvc1")) { + return "hevc"; + } else if (codecString === "vp8") { + return "vp8"; + } else if (codecString.startsWith("vp09")) { + return "vp9"; + } else if (codecString.startsWith("av01")) { + return "av1"; + } + if (codecString === "mp3" || codecString === "mp4a.69" || codecString === "mp4a.6B" || codecString === "mp4a.6b" || codecString === "mp4a.40.34") { + return "mp3"; + } else if (codecString.startsWith("mp4a.40.") || codecString === "mp4a.67") { + return "aac"; + } else if (codecString === "opus") { + return "opus"; + } else if (codecString === "vorbis") { + return "vorbis"; + } else if (codecString === "flac") { + return "flac"; + } else if (codecString === "ac-3" || codecString === "ac3") { + return "ac3"; + } else if (codecString === "ec-3" || codecString === "eac3") { + return "eac3"; + } else if (codecString === "ulaw") { + return "ulaw"; + } else if (codecString === "alaw") { + return "alaw"; + } else if (PCM_CODEC_REGEX.test(codecString)) { + return codecString; + } + if (codecString === "webvtt") { + return "webvtt"; + } + return null; +}; +const FRAME_HEADER_SIZE = 4; +const SAMPLING_RATES = [44100, 48e3, 32e3]; +const KILOBIT_RATES = [ + // lowSamplingFrequency === 0 + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + // layer = 0 + -1, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + -1, + // layer 1 + -1, + 32, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 160, + 192, + 224, + 256, + 320, + 384, + -1, + // layer = 2 + -1, + 32, + 64, + 96, + 128, + 160, + 192, + 224, + 256, + 288, + 320, + 352, + 384, + 416, + 448, + -1, + // layer = 3 + // lowSamplingFrequency === 1 + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + // layer = 0 + -1, + 8, + 16, + 24, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + -1, + // layer = 1 + -1, + 8, + 16, + 24, + 32, + 40, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + -1, + // layer = 2 + -1, + 32, + 48, + 56, + 64, + 80, + 96, + 112, + 128, + 144, + 160, + 176, + 192, + 224, + 256, + -1 + // layer = 3 +]; +const XING = 1483304551; +const INFO = 1231971951; +const computeMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate, padding) => { + if (layer === 0) { + return 0; + } else if (layer === 1) { + return Math.floor(144 * bitrate / (sampleRate << lowSamplingFrequency)) + padding; + } else if (layer === 2) { + return Math.floor(144 * bitrate / sampleRate) + padding; + } else { + return (Math.floor(12 * bitrate / sampleRate) + padding) * 4; + } +}; +const computeAverageMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate) => { + if (layer === 0) { + return 0; + } else if (layer === 1) { + return 144 * bitrate / (sampleRate << lowSamplingFrequency); + } else if (layer === 2) { + return 144 * bitrate / sampleRate; + } else { + return 12 * bitrate / sampleRate * 4; + } +}; +const getXingOffset = (mpegVersionId, channel) => { + return mpegVersionId === 3 ? channel === 3 ? 21 : 36 : channel === 3 ? 13 : 21; +}; +const readMp3FrameHeader = (word, remainingBytes) => { + const firstByte = word >>> 24; + const secondByte = word >>> 16 & 255; + const thirdByte = word >>> 8 & 255; + const fourthByte = word & 255; + if (firstByte !== 255 && secondByte !== 255 && thirdByte !== 255 && fourthByte !== 255) { + return { + header: null, + bytesAdvanced: 4 + }; + } + if (firstByte !== 255) { + return { header: null, bytesAdvanced: 1 }; + } + if ((secondByte & 224) !== 224) { + return { header: null, bytesAdvanced: 1 }; + } + let lowSamplingFrequency = 0; + let mpeg25 = 0; + if (secondByte & 1 << 4) { + lowSamplingFrequency = secondByte & 1 << 3 ? 0 : 1; + } else { + lowSamplingFrequency = 1; + mpeg25 = 1; + } + const mpegVersionId = secondByte >> 3 & 3; + const layer = secondByte >> 1 & 3; + const bitrateIndex = thirdByte >> 4 & 15; + const frequencyIndex = (thirdByte >> 2 & 3) % 3; + const padding = thirdByte >> 1 & 1; + const channel = fourthByte >> 6 & 3; + const modeExtension = fourthByte >> 4 & 3; + const copyright = fourthByte >> 3 & 1; + const original = fourthByte >> 2 & 1; + const emphasis = fourthByte & 3; + const kilobitRate = KILOBIT_RATES[lowSamplingFrequency * 16 * 4 + layer * 16 + bitrateIndex]; + if (kilobitRate === -1) { + return { header: null, bytesAdvanced: 1 }; + } + const bitrate = kilobitRate * 1e3; + const sampleRate = SAMPLING_RATES[frequencyIndex] >> lowSamplingFrequency + mpeg25; + const frameLength = computeMp3FrameSize(lowSamplingFrequency, layer, bitrate, sampleRate, padding); + if (remainingBytes !== null && remainingBytes < frameLength) { + return { header: null, bytesAdvanced: 1 }; + } + let audioSamplesInFrame; + if (mpegVersionId === 3) { + audioSamplesInFrame = layer === 3 ? 384 : 1152; + } else { + if (layer === 3) { + audioSamplesInFrame = 384; + } else if (layer === 2) { + audioSamplesInFrame = 1152; + } else { + audioSamplesInFrame = 576; + } + } + return { + header: { + totalSize: frameLength, + mpegVersionId, + lowSamplingFrequency, + layer, + bitrate, + frequencyIndex, + sampleRate, + channel, + modeExtension, + copyright, + original, + emphasis, + audioSamplesInFrame + }, + bytesAdvanced: 1 + }; +}; +const decodeSynchsafe = (synchsafed) => { + let mask = 2130706432; + let unsynchsafed = 0; + while (mask !== 0) { + unsynchsafed >>= 1; + unsynchsafed |= synchsafed & mask; + mask >>= 8; + } + return unsynchsafed; +}; +var XingFlags; +(function(XingFlags2) { + XingFlags2[XingFlags2["FrameCount"] = 1] = "FrameCount"; + XingFlags2[XingFlags2["FileSize"] = 2] = "FileSize"; + XingFlags2[XingFlags2["Toc"] = 4] = "Toc"; +})(XingFlags || (XingFlags = {})); +const AC3_SAMPLE_RATES = [48e3, 44100, 32e3]; +const EAC3_REDUCED_SAMPLE_RATES = [24e3, 22050, 16e3]; var AvcNalUnitType; (function(AvcNalUnitType2) { + AvcNalUnitType2[AvcNalUnitType2["NON_IDR_SLICE"] = 1] = "NON_IDR_SLICE"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPA"] = 2] = "SLICE_DPA"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPB"] = 3] = "SLICE_DPB"; + AvcNalUnitType2[AvcNalUnitType2["SLICE_DPC"] = 4] = "SLICE_DPC"; AvcNalUnitType2[AvcNalUnitType2["IDR"] = 5] = "IDR"; AvcNalUnitType2[AvcNalUnitType2["SEI"] = 6] = "SEI"; AvcNalUnitType2[AvcNalUnitType2["SPS"] = 7] = "SPS"; AvcNalUnitType2[AvcNalUnitType2["PPS"] = 8] = "PPS"; + AvcNalUnitType2[AvcNalUnitType2["AUD"] = 9] = "AUD"; AvcNalUnitType2[AvcNalUnitType2["SPS_EXT"] = 13] = "SPS_EXT"; })(AvcNalUnitType || (AvcNalUnitType = {})); var HevcNalUnitType; @@ -816,48 +1541,46 @@ var HevcNalUnitType; HevcNalUnitType2[HevcNalUnitType2["VPS_NUT"] = 32] = "VPS_NUT"; HevcNalUnitType2[HevcNalUnitType2["SPS_NUT"] = 33] = "SPS_NUT"; HevcNalUnitType2[HevcNalUnitType2["PPS_NUT"] = 34] = "PPS_NUT"; + HevcNalUnitType2[HevcNalUnitType2["AUD_NUT"] = 35] = "AUD_NUT"; HevcNalUnitType2[HevcNalUnitType2["PREFIX_SEI_NUT"] = 39] = "PREFIX_SEI_NUT"; HevcNalUnitType2[HevcNalUnitType2["SUFFIX_SEI_NUT"] = 40] = "SUFFIX_SEI_NUT"; })(HevcNalUnitType || (HevcNalUnitType = {})); -const findNalUnitsInAnnexB = (packetData) => { - const nalUnits = []; +const iterateNalUnitsInAnnexB = function* (packetData) { let i = 0; - while (i < packetData.length) { - let startCodePos = -1; - let startCodeLength = 0; - for (let j = i; j < packetData.length - 3; j++) { - if (packetData[j] === 0 && packetData[j + 1] === 0 && packetData[j + 2] === 1) { - startCodePos = j; - startCodeLength = 3; - break; - } - if (j < packetData.length - 4 && packetData[j] === 0 && packetData[j + 1] === 0 && packetData[j + 2] === 0 && packetData[j + 3] === 1) { - startCodePos = j; - startCodeLength = 4; - break; - } - } - if (startCodePos === -1) { + let nalStart = -1; + while (i < packetData.length - 2) { + const zeroIndex = packetData.indexOf(0, i); + if (zeroIndex === -1 || zeroIndex >= packetData.length - 2) { break; } - if (i > 0 && startCodePos > i) { - const nalData = packetData.subarray(i, startCodePos); - if (nalData.length > 0) { - nalUnits.push(nalData); - } + i = zeroIndex; + let startCodeLength = 0; + if (i + 3 < packetData.length && packetData[i + 1] === 0 && packetData[i + 2] === 0 && packetData[i + 3] === 1) { + startCodeLength = 4; + } else if (packetData[i + 1] === 0 && packetData[i + 2] === 1) { + startCodeLength = 3; } - i = startCodePos + startCodeLength; - } - if (i < packetData.length) { - const nalData = packetData.subarray(i); - if (nalData.length > 0) { - nalUnits.push(nalData); + if (startCodeLength === 0) { + i++; + continue; } + if (nalStart !== -1 && i > nalStart) { + yield { + offset: nalStart, + length: i - nalStart + }; + } + nalStart = i + startCodeLength; + i = nalStart; + } + if (nalStart !== -1 && nalStart < packetData.length) { + yield { + offset: nalStart, + length: packetData.length - nalStart + }; } - return nalUnits; }; -const findNalUnitsInLengthPrefixed = (packetData, lengthSize) => { - const nalUnits = []; +const iterateNalUnitsInLengthPrefixed = function* (packetData, lengthSize) { let offset = 0; const dataView = new DataView(packetData.buffer, packetData.byteOffset, packetData.byteLength); while (offset + lengthSize <= packetData.length) { @@ -868,18 +1591,30 @@ const findNalUnitsInLengthPrefixed = (packetData, lengthSize) => { nalUnitLength = dataView.getUint16(offset, false); } else if (lengthSize === 3) { nalUnitLength = getUint24(dataView, offset, false); - } else if (lengthSize === 4) { - nalUnitLength = dataView.getUint32(offset, false); } else { - assertNever(lengthSize); - assert(false); + assert(lengthSize === 4); + nalUnitLength = dataView.getUint32(offset, false); } offset += lengthSize; - const nalUnit = packetData.subarray(offset, offset + nalUnitLength); - nalUnits.push(nalUnit); + yield { + offset, + length: nalUnitLength + }; offset += nalUnitLength; } - return nalUnits; +}; +const iterateAvcNalUnits = (packetData, decoderConfig) => { + if (decoderConfig.description) { + const bytes = toUint8Array(decoderConfig.description); + const lengthSizeMinusOne = bytes[4] & 3; + const lengthSize = lengthSizeMinusOne + 1; + return iterateNalUnitsInLengthPrefixed(packetData, lengthSize); + } else { + return iterateNalUnitsInAnnexB(packetData); + } +}; +const extractNalUnitTypeForAvc = (byte) => { + return byte & 31; }; const removeEmulationPreventionBytes = (data) => { const result = []; @@ -933,16 +1668,6 @@ const concatNalUnitsInLengthPrefixed = (nalUnits, lengthSize) => { } return result; }; -const extractAvcNalUnits = (packetData, decoderConfig) => { - if (decoderConfig.description) { - const bytes = toUint8Array(decoderConfig.description); - const lengthSizeMinusOne = bytes[4] & 3; - const lengthSize = lengthSizeMinusOne + 1; - return findNalUnitsInLengthPrefixed(packetData, lengthSize); - } else { - return findNalUnitsInAnnexB(packetData); - } -}; const concatAvcNalUnits = (nalUnits, decoderConfig) => { if (decoderConfig.description) { const bytes = toUint8Array(decoderConfig.description); @@ -953,15 +1678,22 @@ const concatAvcNalUnits = (nalUnits, decoderConfig) => { return concatNalUnitsInAnnexB(nalUnits); } }; -const extractNalUnitTypeForAvc = (data) => { - return data[0] & 31; -}; const extractAvcDecoderConfigurationRecord = (packetData) => { try { - const nalUnits = findNalUnitsInAnnexB(packetData); - const spsUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.SPS); - const ppsUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.PPS); - const spsExtUnits = nalUnits.filter((unit) => extractNalUnitTypeForAvc(unit) === AvcNalUnitType.SPS_EXT); + const spsUnits = []; + const ppsUnits = []; + const spsExtUnits = []; + for (const loc of iterateNalUnitsInAnnexB(packetData)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); + const type = extractNalUnitTypeForAvc(nalUnit[0]); + if (type === AvcNalUnitType.SPS) { + spsUnits.push(nalUnit); + } else if (type === AvcNalUnitType.PPS) { + ppsUnits.push(nalUnit); + } else if (type === AvcNalUnitType.SPS_EXT) { + spsExtUnits.push(nalUnit); + } + } if (spsUnits.length === 0) { return null; } @@ -1052,6 +1784,24 @@ const deserializeAvcDecoderConfigurationRecord = (data) => { return null; } }; +const AVC_HEVC_ASPECT_RATIO_IDC_TABLE = { + 1: { num: 1, den: 1 }, + 2: { num: 12, den: 11 }, + 3: { num: 10, den: 11 }, + 4: { num: 16, den: 11 }, + 5: { num: 40, den: 33 }, + 6: { num: 24, den: 11 }, + 7: { num: 20, den: 11 }, + 8: { num: 32, den: 11 }, + 9: { num: 80, den: 33 }, + 10: { num: 18, den: 11 }, + 11: { num: 15, den: 11 }, + 12: { num: 64, den: 33 }, + 13: { num: 160, den: 99 }, + 14: { num: 4, den: 3 }, + 15: { num: 3, den: 2 }, + 16: { num: 2, den: 1 } +}; const parseAvcSps = (sps) => { try { const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); @@ -1065,13 +1815,14 @@ const parseAvcSps = (sps) => { const constraintFlags = bitstream.readAlignedByte(); const levelIdc = bitstream.readAlignedByte(); readExpGolomb(bitstream); - let chromaFormatIdc = null; - let bitDepthLumaMinus8 = null; - let bitDepthChromaMinus8 = null; + let chromaFormatIdc = 1; + let bitDepthLumaMinus8 = 0; + let bitDepthChromaMinus8 = 0; + let separateColourPlaneFlag = 0; if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) { chromaFormatIdc = readExpGolomb(bitstream); if (chromaFormatIdc === 3) { - bitstream.skipBits(1); + separateColourPlaneFlag = bitstream.readBits(1); } bitDepthLumaMinus8 = readExpGolomb(bitstream); bitDepthChromaMinus8 = readExpGolomb(bitstream); @@ -1110,9 +1861,128 @@ const parseAvcSps = (sps) => { } readExpGolomb(bitstream); bitstream.skipBits(1); - readExpGolomb(bitstream); - readExpGolomb(bitstream); + const picWidthInMbsMinus1 = readExpGolomb(bitstream); + const picHeightInMapUnitsMinus1 = readExpGolomb(bitstream); + const codedWidth = 16 * (picWidthInMbsMinus1 + 1); + const codedHeight = 16 * (picHeightInMapUnitsMinus1 + 1); + let displayWidth = codedWidth; + let displayHeight = codedHeight; const frameMbsOnlyFlag = bitstream.readBits(1); + if (!frameMbsOnlyFlag) { + bitstream.skipBits(1); + } + bitstream.skipBits(1); + const frameCroppingFlag = bitstream.readBits(1); + if (frameCroppingFlag) { + const frameCropLeftOffset = readExpGolomb(bitstream); + const frameCropRightOffset = readExpGolomb(bitstream); + const frameCropTopOffset = readExpGolomb(bitstream); + const frameCropBottomOffset = readExpGolomb(bitstream); + let cropUnitX; + let cropUnitY; + const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0; + if (chromaArrayType === 0) { + cropUnitX = 1; + cropUnitY = 2 - frameMbsOnlyFlag; + } else { + const subWidthC = chromaFormatIdc === 3 ? 1 : 2; + const subHeightC = chromaFormatIdc === 1 ? 2 : 1; + cropUnitX = subWidthC; + cropUnitY = subHeightC * (2 - frameMbsOnlyFlag); + } + displayWidth -= cropUnitX * (frameCropLeftOffset + frameCropRightOffset); + displayHeight -= cropUnitY * (frameCropTopOffset + frameCropBottomOffset); + } + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let pixelAspectRatio = { num: 1, den: 1 }; + let numReorderFrames = null; + let maxDecFrameBuffering = null; + const vuiParametersPresentFlag = bitstream.readBits(1); + if (vuiParametersPresentFlag) { + const aspectRatioInfoPresentFlag = bitstream.readBits(1); + if (aspectRatioInfoPresentFlag) { + const aspectRatioIdc = bitstream.readBits(8); + if (aspectRatioIdc === 255) { + pixelAspectRatio = { + num: bitstream.readBits(16), + den: bitstream.readBits(16) + }; + } else { + const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspectRatioIdc]; + if (aspectRatio) { + pixelAspectRatio = aspectRatio; + } + } + } + const overscanInfoPresentFlag = bitstream.readBits(1); + if (overscanInfoPresentFlag) { + bitstream.skipBits(1); + } + const videoSignalTypePresentFlag = bitstream.readBits(1); + if (videoSignalTypePresentFlag) { + bitstream.skipBits(3); + fullRangeFlag = bitstream.readBits(1); + const colourDescriptionPresentFlag = bitstream.readBits(1); + if (colourDescriptionPresentFlag) { + colourPrimaries = bitstream.readBits(8); + transferCharacteristics = bitstream.readBits(8); + matrixCoefficients = bitstream.readBits(8); + } + } + const chromaLocInfoPresentFlag = bitstream.readBits(1); + if (chromaLocInfoPresentFlag) { + readExpGolomb(bitstream); + readExpGolomb(bitstream); + } + const timingInfoPresentFlag = bitstream.readBits(1); + if (timingInfoPresentFlag) { + bitstream.skipBits(32); + bitstream.skipBits(32); + bitstream.skipBits(1); + } + const nalHrdParametersPresentFlag = bitstream.readBits(1); + if (nalHrdParametersPresentFlag) { + skipAvcHrdParameters(bitstream); + } + const vclHrdParametersPresentFlag = bitstream.readBits(1); + if (vclHrdParametersPresentFlag) { + skipAvcHrdParameters(bitstream); + } + if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) { + bitstream.skipBits(1); + } + bitstream.skipBits(1); + const bitstreamRestrictionFlag = bitstream.readBits(1); + if (bitstreamRestrictionFlag) { + bitstream.skipBits(1); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + readExpGolomb(bitstream); + numReorderFrames = readExpGolomb(bitstream); + maxDecFrameBuffering = readExpGolomb(bitstream); + } + } + if (numReorderFrames === null) { + assert(maxDecFrameBuffering === null); + const constraintSet3Flag = constraintFlags & 16; + if ((profileIdc === 44 || profileIdc === 86 || profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244) && constraintSet3Flag) { + numReorderFrames = 0; + maxDecFrameBuffering = 0; + } else { + const picWidthInMbs = picWidthInMbsMinus1 + 1; + const picHeightInMapUnits = picHeightInMapUnitsMinus1 + 1; + const frameHeightInMbs = (2 - frameMbsOnlyFlag) * picHeightInMapUnits; + const levelInfo = AVC_LEVEL_TABLE.find((x) => x.level >= levelIdc) ?? last(AVC_LEVEL_TABLE); + const maxDpbFrames = Math.min(Math.floor(levelInfo.maxDpbMbs / (picWidthInMbs * frameHeightInMbs)), 16); + numReorderFrames = maxDpbFrames; + maxDecFrameBuffering = maxDpbFrames; + } + } + assert(maxDecFrameBuffering !== null); return { profileIdc, constraintFlags, @@ -1120,62 +1990,106 @@ const parseAvcSps = (sps) => { frameMbsOnlyFlag, chromaFormatIdc, bitDepthLumaMinus8, - bitDepthChromaMinus8 + bitDepthChromaMinus8, + codedWidth, + codedHeight, + displayWidth, + displayHeight, + pixelAspectRatio, + colourPrimaries, + matrixCoefficients, + transferCharacteristics, + fullRangeFlag, + numReorderFrames, + maxDecFrameBuffering }; } catch (error) { console.error("Error parsing AVC SPS:", error); return null; } }; -const extractHevcNalUnits = (packetData, decoderConfig) => { +const skipAvcHrdParameters = (bitstream) => { + const cpb_cnt_minus1 = readExpGolomb(bitstream); + bitstream.skipBits(4); + bitstream.skipBits(4); + for (let i = 0; i <= cpb_cnt_minus1; i++) { + readExpGolomb(bitstream); + readExpGolomb(bitstream); + bitstream.skipBits(1); + } + bitstream.skipBits(5); + bitstream.skipBits(5); + bitstream.skipBits(5); + bitstream.skipBits(5); +}; +const concatHevcNalUnits = (nalUnits, decoderConfig) => { if (decoderConfig.description) { const bytes = toUint8Array(decoderConfig.description); const lengthSizeMinusOne = bytes[21] & 3; const lengthSize = lengthSizeMinusOne + 1; - return findNalUnitsInLengthPrefixed(packetData, lengthSize); + return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize); } else { - return findNalUnitsInAnnexB(packetData); + return concatNalUnitsInAnnexB(nalUnits); } }; -const extractNalUnitTypeForHevc = (data) => { - return data[0] >> 1 & 63; +const iterateHevcNalUnits = (packetData, decoderConfig) => { + if (decoderConfig.description) { + const bytes = toUint8Array(decoderConfig.description); + const lengthSizeMinusOne = bytes[21] & 3; + const lengthSize = lengthSizeMinusOne + 1; + return iterateNalUnitsInLengthPrefixed(packetData, lengthSize); + } else { + return iterateNalUnitsInAnnexB(packetData); + } }; -const extractHevcDecoderConfigurationRecord = (packetData) => { +const extractNalUnitTypeForHevc = (byte) => { + return byte >> 1 & 63; +}; +const parseHevcSps = (sps) => { try { - const nalUnits = findNalUnitsInAnnexB(packetData); - const vpsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.VPS_NUT); - const spsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.SPS_NUT); - const ppsUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.PPS_NUT); - const seiUnits = nalUnits.filter((unit) => extractNalUnitTypeForHevc(unit) === HevcNalUnitType.PREFIX_SEI_NUT || extractNalUnitTypeForHevc(unit) === HevcNalUnitType.SUFFIX_SEI_NUT); - if (spsUnits.length === 0 || ppsUnits.length === 0) - return null; - const sps = spsUnits[0]; const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); bitstream.skipBits(16); bitstream.readBits(4); - const sps_max_sub_layers_minus1 = bitstream.readBits(3); - const sps_temporal_id_nesting_flag = bitstream.readBits(1); - const { general_profile_space, general_tier_flag, general_profile_idc, general_profile_compatibility_flags, general_constraint_indicator_flags, general_level_idc } = parseProfileTierLevel(bitstream, sps_max_sub_layers_minus1); + const spsMaxSubLayersMinus1 = bitstream.readBits(3); + const spsTemporalIdNestingFlag = bitstream.readBits(1); + const { general_profile_space, general_tier_flag, general_profile_idc, general_profile_compatibility_flags, general_constraint_indicator_flags, general_level_idc } = parseProfileTierLevel(bitstream, spsMaxSubLayersMinus1); readExpGolomb(bitstream); - const chroma_format_idc = readExpGolomb(bitstream); - if (chroma_format_idc === 3) - bitstream.skipBits(1); - readExpGolomb(bitstream); - readExpGolomb(bitstream); - if (bitstream.readBits(1)) { - readExpGolomb(bitstream); - readExpGolomb(bitstream); - readExpGolomb(bitstream); - readExpGolomb(bitstream); + const chromaFormatIdc = readExpGolomb(bitstream); + let separateColourPlaneFlag = 0; + if (chromaFormatIdc === 3) { + separateColourPlaneFlag = bitstream.readBits(1); } - const bit_depth_luma_minus8 = readExpGolomb(bitstream); - const bit_depth_chroma_minus8 = readExpGolomb(bitstream); + const picWidthInLumaSamples = readExpGolomb(bitstream); + const picHeightInLumaSamples = readExpGolomb(bitstream); + let displayWidth = picWidthInLumaSamples; + let displayHeight = picHeightInLumaSamples; + if (bitstream.readBits(1)) { + const confWinLeftOffset = readExpGolomb(bitstream); + const confWinRightOffset = readExpGolomb(bitstream); + const confWinTopOffset = readExpGolomb(bitstream); + const confWinBottomOffset = readExpGolomb(bitstream); + let subWidthC = 1; + let subHeightC = 1; + const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0; + if (chromaArrayType === 1) { + subWidthC = 2; + subHeightC = 2; + } else if (chromaArrayType === 2) { + subWidthC = 2; + subHeightC = 1; + } + displayWidth -= (confWinLeftOffset + confWinRightOffset) * subWidthC; + displayHeight -= (confWinTopOffset + confWinBottomOffset) * subHeightC; + } + const bitDepthLumaMinus8 = readExpGolomb(bitstream); + const bitDepthChromaMinus8 = readExpGolomb(bitstream); readExpGolomb(bitstream); - const sps_sub_layer_ordering_info_present_flag = bitstream.readBits(1); - const maxNum = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; - for (let i = maxNum; i <= sps_max_sub_layers_minus1; i++) { - readExpGolomb(bitstream); + const spsSubLayerOrderingInfoPresentFlag = bitstream.readBits(1); + const startI = spsSubLayerOrderingInfoPresentFlag ? 0 : spsMaxSubLayersMinus1; + let spsMaxNumReorderPics = 0; + for (let i = startI; i <= spsMaxSubLayersMinus1; i++) { readExpGolomb(bitstream); + spsMaxNumReorderPics = readExpGolomb(bitstream); readExpGolomb(bitstream); } readExpGolomb(bitstream); @@ -1198,21 +2112,83 @@ const extractHevcDecoderConfigurationRecord = (packetData) => { readExpGolomb(bitstream); bitstream.skipBits(1); } - const num_short_term_ref_pic_sets = readExpGolomb(bitstream); - skipAllStRefPicSets(bitstream, num_short_term_ref_pic_sets); + const numShortTermRefPicSets = readExpGolomb(bitstream); + skipAllStRefPicSets(bitstream, numShortTermRefPicSets); if (bitstream.readBits(1)) { - const num_long_term_ref_pics_sps = readExpGolomb(bitstream); - for (let i = 0; i < num_long_term_ref_pics_sps; i++) { + const numLongTermRefPicsSps = readExpGolomb(bitstream); + for (let i = 0; i < numLongTermRefPicsSps; i++) { readExpGolomb(bitstream); bitstream.skipBits(1); } } bitstream.skipBits(1); bitstream.skipBits(1); - let min_spatial_segmentation_idc = 0; + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let minSpatialSegmentationIdc = 0; + let pixelAspectRatio = { num: 1, den: 1 }; if (bitstream.readBits(1)) { - min_spatial_segmentation_idc = parseVuiForMinSpatialSegmentationIdc(bitstream, sps_max_sub_layers_minus1); + const vui = parseHevcVui(bitstream, spsMaxSubLayersMinus1); + pixelAspectRatio = vui.pixelAspectRatio; + colourPrimaries = vui.colourPrimaries; + transferCharacteristics = vui.transferCharacteristics; + matrixCoefficients = vui.matrixCoefficients; + fullRangeFlag = vui.fullRangeFlag; + minSpatialSegmentationIdc = vui.minSpatialSegmentationIdc; } + return { + displayWidth, + displayHeight, + pixelAspectRatio, + colourPrimaries, + transferCharacteristics, + matrixCoefficients, + fullRangeFlag, + maxDecFrameBuffering: spsMaxNumReorderPics + 1, + spsMaxSubLayersMinus1, + spsTemporalIdNestingFlag, + generalProfileSpace: general_profile_space, + generalTierFlag: general_tier_flag, + generalProfileIdc: general_profile_idc, + generalProfileCompatibilityFlags: general_profile_compatibility_flags, + generalConstraintIndicatorFlags: general_constraint_indicator_flags, + generalLevelIdc: general_level_idc, + chromaFormatIdc, + bitDepthLumaMinus8, + bitDepthChromaMinus8, + minSpatialSegmentationIdc + }; + } catch (error) { + console.error("Error parsing HEVC SPS:", error); + return null; + } +}; +const extractHevcDecoderConfigurationRecord = (packetData) => { + try { + const vpsUnits = []; + const spsUnits = []; + const ppsUnits = []; + const seiUnits = []; + for (const loc of iterateNalUnitsInAnnexB(packetData)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); + const type = extractNalUnitTypeForHevc(nalUnit[0]); + if (type === HevcNalUnitType.VPS_NUT) { + vpsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.SPS_NUT) { + spsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.PPS_NUT) { + ppsUnits.push(nalUnit); + } else if (type === HevcNalUnitType.PREFIX_SEI_NUT || type === HevcNalUnitType.SUFFIX_SEI_NUT) { + seiUnits.push(nalUnit); + } + } + if (spsUnits.length === 0 || ppsUnits.length === 0) + return null; + const spsInfo = parseHevcSps(spsUnits[0]); + if (!spsInfo) + return null; let parallelismType = 0; if (ppsUnits.length > 0) { const pps = ppsUnits[0]; @@ -1275,28 +2251,28 @@ const extractHevcDecoderConfigurationRecord = (packetData) => { ...seiUnits.length ? [ { arrayCompleteness: 1, - nalUnitType: extractNalUnitTypeForHevc(seiUnits[0]), + nalUnitType: extractNalUnitTypeForHevc(seiUnits[0][0]), nalUnits: seiUnits } ] : [] ]; const record = { configurationVersion: 1, - generalProfileSpace: general_profile_space, - generalTierFlag: general_tier_flag, - generalProfileIdc: general_profile_idc, - generalProfileCompatibilityFlags: general_profile_compatibility_flags, - generalConstraintIndicatorFlags: general_constraint_indicator_flags, - generalLevelIdc: general_level_idc, - minSpatialSegmentationIdc: min_spatial_segmentation_idc, + generalProfileSpace: spsInfo.generalProfileSpace, + generalTierFlag: spsInfo.generalTierFlag, + generalProfileIdc: spsInfo.generalProfileIdc, + generalProfileCompatibilityFlags: spsInfo.generalProfileCompatibilityFlags, + generalConstraintIndicatorFlags: spsInfo.generalConstraintIndicatorFlags, + generalLevelIdc: spsInfo.generalLevelIdc, + minSpatialSegmentationIdc: spsInfo.minSpatialSegmentationIdc, parallelismType, - chromaFormatIdc: chroma_format_idc, - bitDepthLumaMinus8: bit_depth_luma_minus8, - bitDepthChromaMinus8: bit_depth_chroma_minus8, + chromaFormatIdc: spsInfo.chromaFormatIdc, + bitDepthLumaMinus8: spsInfo.bitDepthLumaMinus8, + bitDepthChromaMinus8: spsInfo.bitDepthChromaMinus8, avgFrameRate: 0, constantFrameRate: 0, - numTemporalLayers: sps_max_sub_layers_minus1 + 1, - temporalIdNested: sps_temporal_id_nesting_flag, + numTemporalLayers: spsInfo.spsMaxSubLayersMinus1 + 1, + temporalIdNested: spsInfo.spsTemporalIdNestingFlag, lengthSizeMinusOne: 3, arrays }; @@ -1408,12 +2384,25 @@ const skipStRefPicSet = (bitstream, stRpsIdx, num_short_term_ref_pic_sets, NumDe } return NumDeltaPocsThis; }; -const parseVuiForMinSpatialSegmentationIdc = (bitstream, sps_max_sub_layers_minus1) => { +const parseHevcVui = (bitstream, sps_max_sub_layers_minus1) => { + let colourPrimaries = 2; + let transferCharacteristics = 2; + let matrixCoefficients = 2; + let fullRangeFlag = 0; + let minSpatialSegmentationIdc = 0; + let pixelAspectRatio = { num: 1, den: 1 }; if (bitstream.readBits(1)) { const aspect_ratio_idc = bitstream.readBits(8); if (aspect_ratio_idc === 255) { - bitstream.readBits(16); - bitstream.readBits(16); + pixelAspectRatio = { + num: bitstream.readBits(16), + den: bitstream.readBits(16) + }; + } else { + const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspect_ratio_idc]; + if (aspectRatio) { + pixelAspectRatio = aspectRatio; + } } } if (bitstream.readBits(1)) { @@ -1421,11 +2410,11 @@ const parseVuiForMinSpatialSegmentationIdc = (bitstream, sps_max_sub_layers_minu } if (bitstream.readBits(1)) { bitstream.readBits(3); - bitstream.readBits(1); + fullRangeFlag = bitstream.readBits(1); if (bitstream.readBits(1)) { - bitstream.readBits(8); - bitstream.readBits(8); - bitstream.readBits(8); + colourPrimaries = bitstream.readBits(8); + transferCharacteristics = bitstream.readBits(8); + matrixCoefficients = bitstream.readBits(8); } } if (bitstream.readBits(1)) { @@ -1448,23 +2437,29 @@ const parseVuiForMinSpatialSegmentationIdc = (bitstream, sps_max_sub_layers_minu readExpGolomb(bitstream); } if (bitstream.readBits(1)) { - skipHrdParameters(bitstream, true, sps_max_sub_layers_minus1); + skipHevcHrdParameters(bitstream, true, sps_max_sub_layers_minus1); } } if (bitstream.readBits(1)) { bitstream.readBits(1); bitstream.readBits(1); bitstream.readBits(1); - const min_spatial_segmentation_idc = readExpGolomb(bitstream); + minSpatialSegmentationIdc = readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); readExpGolomb(bitstream); - return min_spatial_segmentation_idc; } - return 0; + return { + pixelAspectRatio, + colourPrimaries, + transferCharacteristics, + matrixCoefficients, + fullRangeFlag, + minSpatialSegmentationIdc + }; }; -const skipHrdParameters = (bitstream, commonInfPresentFlag, maxNumSubLayersMinus1) => { +const skipHevcHrdParameters = (bitstream, commonInfPresentFlag, maxNumSubLayersMinus1) => { let nal_hrd_parameters_present_flag = false; let vcl_hrd_parameters_present_flag = false; let sub_pic_hrd_params_present_flag = false; @@ -1525,6 +2520,78 @@ const skipSubLayerHrdParameters = (bitstream, CpbCnt, sub_pic_hrd_params_present bitstream.readBits(1); } }; +var HevcNaluOrderState; +(function(HevcNaluOrderState2) { + HevcNaluOrderState2[HevcNaluOrderState2["audAllowed"] = 0] = "audAllowed"; + HevcNaluOrderState2[HevcNaluOrderState2["beforeFirstVcl"] = 1] = "beforeFirstVcl"; + HevcNaluOrderState2[HevcNaluOrderState2["afterFirstVcl"] = 2] = "afterFirstVcl"; + HevcNaluOrderState2[HevcNaluOrderState2["eoBitstreamAllowed"] = 3] = "eoBitstreamAllowed"; + HevcNaluOrderState2[HevcNaluOrderState2["noMoreDataAllowed"] = 4] = "noMoreDataAllowed"; +})(HevcNaluOrderState || (HevcNaluOrderState = {})); +const sanitizeHevcPacketForChromium = (packetData, decoderConfig) => { + const removedNalUnits = /* @__PURE__ */ new Set(); + let orderState = HevcNaluOrderState.audAllowed; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + if (orderState === HevcNaluOrderState.noMoreDataAllowed) { + removedNalUnits.add(loc.offset); + continue; + } + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (orderState === HevcNaluOrderState.eoBitstreamAllowed && type !== 37) { + removedNalUnits.add(loc.offset); + continue; + } + let remove = false; + if (type === 35) { + if (orderState > HevcNaluOrderState.audAllowed) { + remove = true; + } else { + orderState = HevcNaluOrderState.beforeFirstVcl; + } + } else if (type <= 31) { + if (orderState > HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.afterFirstVcl; + } + } else if (type === 36) { + if (orderState !== HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.eoBitstreamAllowed; + } + } else if (type === 37) { + if (orderState < HevcNaluOrderState.afterFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.noMoreDataAllowed; + } + } else if (type === 32 || type === 33 || type === 34 || type === 39 || type >= 41 && type <= 44 || type >= 48 && type <= 55) { + if (orderState > HevcNaluOrderState.beforeFirstVcl) { + remove = true; + } else { + orderState = HevcNaluOrderState.beforeFirstVcl; + } + } else if (type === 38 || type === 40 || type >= 45 && type <= 47 || type >= 56 && type <= 63) { + if (orderState < HevcNaluOrderState.afterFirstVcl) { + remove = true; + } + } + if (remove) { + removedNalUnits.add(loc.offset); + } + } + if (removedNalUnits.size === 0) { + return null; + } + const filteredNalUnits = []; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + if (!removedNalUnits.has(loc.offset)) { + filteredNalUnits.push(packetData.subarray(loc.offset, loc.offset + loc.length)); + } + } + return concatHevcNalUnits(filteredNalUnits, decoderConfig); +}; const extractVp9CodecInfoFromPacket = (packet) => { const bitstream = new Bitstream(packet); const frameMarker = bitstream.readBits(2); @@ -1929,14 +2996,17 @@ const parseModesFromVorbisSetupPacket = (setupHeader) => { const determineVideoPacketType = (codec, decoderConfig, packetData) => { switch (codec) { case "avc": { - const nalUnits = extractAvcNalUnits(packetData, decoderConfig); - let isKeyframe = nalUnits.some((x) => extractNalUnitTypeForAvc(x) === AvcNalUnitType.IDR); - if (!isKeyframe && (!isChromium() || getChromiumVersion() >= 144)) { - for (const nalUnit of nalUnits) { - const type = extractNalUnitTypeForAvc(nalUnit); - if (type !== AvcNalUnitType.SEI) { - continue; - } + for (const loc of iterateAvcNalUnits(packetData, decoderConfig)) { + const nalTypeByte = packetData[loc.offset]; + const type = extractNalUnitTypeForAvc(nalTypeByte); + if (type >= AvcNalUnitType.NON_IDR_SLICE && type <= AvcNalUnitType.SLICE_DPC) { + return "delta"; + } + if (type === AvcNalUnitType.IDR) { + return "key"; + } + if (type === AvcNalUnitType.SEI && (!isChromium() || getChromiumVersion() >= 144)) { + const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length); const bytes = removeEmulationPreventionBytes(nalUnit); let pos = 1; do { @@ -1967,23 +3037,26 @@ const determineVideoPacketType = (codec, decoderConfig, packetData) => { const recoveryFrameCount = readExpGolomb(bitstream); const exactMatchFlag = bitstream.readBits(1); if (recoveryFrameCount === 0 && exactMatchFlag === 1) { - isKeyframe = true; - break; + return "key"; } } pos += payloadSize; } while (pos < bytes.length - 1); } } - return isKeyframe ? "key" : "delta"; + return "delta"; } case "hevc": { - const nalUnits = extractHevcNalUnits(packetData, decoderConfig); - const isKeyframe = nalUnits.some((x) => { - const type = extractNalUnitTypeForHevc(x); - return HevcNalUnitType.BLA_W_LP <= type && type <= HevcNalUnitType.RSV_IRAP_VCL23; - }); - return isKeyframe ? "key" : "delta"; + for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) { + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (type < HevcNalUnitType.BLA_W_LP) { + return "delta"; + } + if (type <= HevcNalUnitType.RSV_IRAP_VCL23) { + return "key"; + } + } + return "delta"; } case "vp8": { const frameType = packetData[0] & 1; @@ -2183,13 +3256,290 @@ const readVorbisComments = (bytes, metadataTags) => { } } }; +const AC3_ACMOD_CHANNEL_COUNTS = [2, 1, 2, 3, 3, 4, 4, 5]; +const parseAc3SyncFrame = (data) => { + if (data.length < 7) { + return null; + } + if (data[0] !== 11 || data[1] !== 119) { + return null; + } + const bitstream = new Bitstream(data); + bitstream.skipBits(16); + bitstream.skipBits(16); + const fscod = bitstream.readBits(2); + if (fscod === 3) { + return null; + } + const frmsizecod = bitstream.readBits(6); + const bsid = bitstream.readBits(5); + if (bsid > 8) { + return null; + } + const bsmod = bitstream.readBits(3); + const acmod = bitstream.readBits(3); + if ((acmod & 1) !== 0 && acmod !== 1) { + bitstream.skipBits(2); + } + if ((acmod & 4) !== 0) { + bitstream.skipBits(2); + } + if (acmod === 2) { + bitstream.skipBits(2); + } + const lfeon = bitstream.readBits(1); + const bitRateCode = Math.floor(frmsizecod / 2); + return { fscod, bsid, bsmod, acmod, lfeon, bitRateCode }; +}; +const AC3_FRAME_SIZES = [ + // frmsizecod, [48kHz, 44.1kHz, 32kHz] in bytes + 64 * 2, + 69 * 2, + 96 * 2, + 64 * 2, + 70 * 2, + 96 * 2, + 80 * 2, + 87 * 2, + 120 * 2, + 80 * 2, + 88 * 2, + 120 * 2, + 96 * 2, + 104 * 2, + 144 * 2, + 96 * 2, + 105 * 2, + 144 * 2, + 112 * 2, + 121 * 2, + 168 * 2, + 112 * 2, + 122 * 2, + 168 * 2, + 128 * 2, + 139 * 2, + 192 * 2, + 128 * 2, + 140 * 2, + 192 * 2, + 160 * 2, + 174 * 2, + 240 * 2, + 160 * 2, + 175 * 2, + 240 * 2, + 192 * 2, + 208 * 2, + 288 * 2, + 192 * 2, + 209 * 2, + 288 * 2, + 224 * 2, + 243 * 2, + 336 * 2, + 224 * 2, + 244 * 2, + 336 * 2, + 256 * 2, + 278 * 2, + 384 * 2, + 256 * 2, + 279 * 2, + 384 * 2, + 320 * 2, + 348 * 2, + 480 * 2, + 320 * 2, + 349 * 2, + 480 * 2, + 384 * 2, + 417 * 2, + 576 * 2, + 384 * 2, + 418 * 2, + 576 * 2, + 448 * 2, + 487 * 2, + 672 * 2, + 448 * 2, + 488 * 2, + 672 * 2, + 512 * 2, + 557 * 2, + 768 * 2, + 512 * 2, + 558 * 2, + 768 * 2, + 640 * 2, + 696 * 2, + 960 * 2, + 640 * 2, + 697 * 2, + 960 * 2, + 768 * 2, + 835 * 2, + 1152 * 2, + 768 * 2, + 836 * 2, + 1152 * 2, + 896 * 2, + 975 * 2, + 1344 * 2, + 896 * 2, + 976 * 2, + 1344 * 2, + 1024 * 2, + 1114 * 2, + 1536 * 2, + 1024 * 2, + 1115 * 2, + 1536 * 2, + 1152 * 2, + 1253 * 2, + 1728 * 2, + 1152 * 2, + 1254 * 2, + 1728 * 2, + 1280 * 2, + 1393 * 2, + 1920 * 2, + 1280 * 2, + 1394 * 2, + 1920 * 2 +]; +const AC3_SAMPLES_PER_FRAME = 1536; +const EAC3_NUMBLKS_TABLE = [1, 2, 3, 6]; +const parseEac3SyncFrame = (data) => { + if (data.length < 6) { + return null; + } + if (data[0] !== 11 || data[1] !== 119) { + return null; + } + const bitstream = new Bitstream(data); + bitstream.skipBits(16); + const strmtyp = bitstream.readBits(2); + bitstream.skipBits(3); + if (strmtyp !== 0 && strmtyp !== 2) { + return null; + } + const frmsiz = bitstream.readBits(11); + const fscod = bitstream.readBits(2); + let fscod2 = 0; + let numblkscod; + if (fscod === 3) { + fscod2 = bitstream.readBits(2); + numblkscod = 3; + } else { + numblkscod = bitstream.readBits(2); + } + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + const bsid = bitstream.readBits(5); + if (bsid < 11 || bsid > 16) { + return null; + } + const numblks = EAC3_NUMBLKS_TABLE[numblkscod]; + let fs; + if (fscod < 3) { + fs = AC3_SAMPLE_RATES[fscod] / 1e3; + } else { + fs = EAC3_REDUCED_SAMPLE_RATES[fscod2] / 1e3; + } + const dataRate = Math.round((frmsiz + 1) * fs / (numblks * 16)); + const bsmod = 0; + const numDepSub = 0; + const chanLoc = 0; + const substream = { + fscod, + fscod2, + bsid, + bsmod, + acmod, + lfeon, + numDepSub, + chanLoc + }; + return { + dataRate, + substreams: [substream] + }; +}; +const parseEac3Config = (data) => { + if (data.length < 2) { + return null; + } + const bitstream = new Bitstream(data); + const dataRate = bitstream.readBits(13); + const numIndSub = bitstream.readBits(3); + const substreams = []; + for (let i = 0; i <= numIndSub; i++) { + if (Math.ceil(bitstream.pos / 8) + 3 > data.length) { + break; + } + const fscod = bitstream.readBits(2); + const bsid = bitstream.readBits(5); + bitstream.skipBits(1); + bitstream.skipBits(1); + const bsmod = bitstream.readBits(3); + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + bitstream.skipBits(3); + const numDepSub = bitstream.readBits(4); + let chanLoc = 0; + if (numDepSub > 0) { + chanLoc = bitstream.readBits(9); + } else { + bitstream.skipBits(1); + } + substreams.push({ + fscod, + fscod2: null, + bsid, + bsmod, + acmod, + lfeon, + numDepSub, + chanLoc + }); + } + if (substreams.length === 0) { + return null; + } + return { dataRate, substreams }; +}; +const getEac3SampleRate = (config) => { + const sub = config.substreams[0]; + assert(sub); + if (sub.fscod < 3) { + return AC3_SAMPLE_RATES[sub.fscod]; + } else if (sub.fscod2 !== null && sub.fscod2 < 3) { + return EAC3_REDUCED_SAMPLE_RATES[sub.fscod2]; + } + return null; +}; +const getEac3ChannelCount = (config) => { + const sub = config.substreams[0]; + assert(sub); + let channels = AC3_ACMOD_CHANNEL_COUNTS[sub.acmod] + sub.lfeon; + if (sub.numDepSub > 0) { + const CHAN_LOC_COUNTS = [2, 2, 1, 1, 2, 2, 2, 1, 1]; + for (let bit = 0; bit < 9; bit++) { + if (sub.chanLoc & 1 << 8 - bit) { + channels += CHAN_LOC_COUNTS[bit]; + } + } + } + return channels; +}; class Demuxer { constructor(input) { this.input = input; } + dispose() { + } } -const customVideoDecoders = []; -const customAudioDecoders = []; const PLACEHOLDER_DATA = /* @__PURE__ */ new Uint8Array(0); class EncodedPacket { /** Creates a new {@link EncodedPacket} from raw bytes and timing information. */ @@ -2323,49 +3673,12569 @@ class EncodedPacket { chunk.copyTo(data); return new EncodedPacket(data, chunk.type, chunk.timestamp / 1e6, (chunk.duration ?? 0) / 1e6, void 0, void 0, sideData); } - /** Clones this packet while optionally updating timing information. */ + /** Clones this packet while optionally modifying the new packet's data. */ clone(options) { if (options !== void 0 && (typeof options !== "object" || options === null)) { throw new TypeError("options, when provided, must be an object."); } + if (options?.data !== void 0 && !(options.data instanceof Uint8Array)) { + throw new TypeError("options.data, when provided, must be a Uint8Array."); + } + if (options?.type !== void 0 && options.type !== "key" && options.type !== "delta") { + throw new TypeError('options.type, when provided, must be either "key" or "delta".'); + } if (options?.timestamp !== void 0 && !Number.isFinite(options.timestamp)) { throw new TypeError("options.timestamp, when provided, must be a number."); } if (options?.duration !== void 0 && !Number.isFinite(options.duration)) { throw new TypeError("options.duration, when provided, must be a number."); } - return new EncodedPacket(this.data, this.type, options?.timestamp ?? this.timestamp, options?.duration ?? this.duration, this.sequenceNumber, this.byteLength); + if (options?.sequenceNumber !== void 0 && !Number.isFinite(options.sequenceNumber)) { + throw new TypeError("options.sequenceNumber, when provided, must be a number."); + } + if (options?.sideData !== void 0 && (typeof options.sideData !== "object" || options.sideData === null)) { + throw new TypeError("options.sideData, when provided, must be an object."); + } + return new EncodedPacket(options?.data ?? this.data, options?.type ?? this.type, options?.timestamp ?? this.timestamp, options?.duration ?? this.duration, options?.sequenceNumber ?? this.sequenceNumber, this.byteLength, options?.sideData ?? this.sideData); } } -const fromUlaw = (u8) => { - const MULAW_BIAS = 33; - let sign = 0; - let position = 0; - let number = ~u8; - if (number & 128) { - number &= -129; - sign = -1; +const buildIsobmffMimeType = (info) => { + const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; + let string = base + (info.isQuickTime ? "quicktime" : "mp4"); + if (info.codecStrings.length > 0) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; } - position = ((number & 240) >> 4) + 5; - const decoded = (1 << position | (number & 15) << position - 4 | 1 << position - 5) - MULAW_BIAS; - return sign === 0 ? decoded : -decoded; + return string; }; -const fromAlaw = (u8) => { - let sign = 0; - let position = 0; - let number = u8 ^ 85; - if (number & 128) { - number &= -129; - sign = -1; +const parsePsshBoxContents = (contents) => { + const view = toDataView(contents); + let pos = 0; + const version = view.getUint8(pos); + pos += 1; + pos += 3; + const systemId = bytesToHexString(contents.subarray(pos, pos + 16)); + pos += 16; + let keyIds = null; + if (version > 0) { + const kidCount = view.getUint32(pos); + pos += 4; + if (kidCount > 0) { + keyIds = []; + for (let i = 0; i < kidCount; i++) { + keyIds.push(bytesToHexString(contents.subarray(pos, pos + 16))); + pos += 16; + } + } } - position = ((number & 240) >> 4) + 4; - let decoded = 0; - if (position !== 4) { - decoded = 1 << position | (number & 15) << position - 4 | 1 << position - 5; + const dataSize = view.getUint32(pos); + pos += 4; + return { + systemId, + keyIds, + data: contents.slice(pos, pos + dataSize) + }; +}; +const psshBoxesAreEqual = (a, b) => a.systemId === b.systemId && uint8ArraysAreEqual(a.data, b.data); +const MIN_BOX_HEADER_SIZE = 8; +const MAX_BOX_HEADER_SIZE = 16; +const readBoxHeader = (slice) => { + let totalSize = readU32Be(slice); + const name = readAscii(slice, 4); + let headerSize = 8; + const hasLargeSize = totalSize === 1; + if (hasLargeSize) { + totalSize = readU64Be(slice); + headerSize = 16; + } + const contentSize = totalSize - headerSize; + if (contentSize < 0) { + return null; + } + return { name, totalSize, headerSize, contentSize }; +}; +const readFixed_16_16 = (slice) => { + return readI32Be(slice) / 65536; +}; +const readFixed_2_30 = (slice) => { + return readI32Be(slice) / 1073741824; +}; +const readIsomVariableInteger = (slice) => { + let result = 0; + for (let i = 0; i < 4; i++) { + result <<= 7; + const nextByte = readU8(slice); + result |= nextByte & 127; + if ((nextByte & 128) === 0) { + break; + } + } + return result; +}; +const readMetadataStringShort = (slice) => { + let stringLength = readU16Be(slice); + slice.skip(2); + stringLength = Math.min(stringLength, slice.remainingLength); + return textDecoder.decode(readBytes(slice, stringLength)); +}; +const readDataBox = (slice) => { + const header = readBoxHeader(slice); + if (!header || header.name !== "data") { + return null; + } + if (slice.remainingLength < 8) { + return null; + } + const typeIndicator = readU32Be(slice); + slice.skip(4); + const data = readBytes(slice, header.contentSize - 8); + switch (typeIndicator) { + case 1: + return textDecoder.decode(data); + // UTF-8 + case 2: + return new TextDecoder("utf-16be").decode(data); + // UTF-16-BE + case 13: + return new RichImageData(data, "image/jpeg"); + case 14: + return new RichImageData(data, "image/png"); + case 27: + return new RichImageData(data, "image/bmp"); + default: + return data; + } +}; +const AES_128_BLOCK_SIZE = 16; +const Te4 = new Uint32Array(256); +const Td0 = new Uint32Array(256); +const Td1 = new Uint32Array(256); +const Td2 = new Uint32Array(256); +const Td3 = new Uint32Array(256); +const Td4 = new Uint32Array(256); +const rcon = new Uint32Array(10); +let tablesGenerated = false; +const generateAesTables = () => { + const sbox = new Uint8Array(256); + const log = new Uint8Array(256); + const pow = new Uint8Array(256); + for (let i = 0, p = 1; i < 256; i++) { + pow[i] = p; + log[p] = i; + p = p ^ p << 1 ^ (p & 128 ? 283 : 0); + } + const mul = (a, b) => a && b ? pow[(log[a] + log[b]) % 255] : 0; + sbox[0] = 99; + for (let i = 1; i < 256; i++) { + const x = pow[255 - log[i]]; + let s = x ^ x << 1 ^ x << 2 ^ x << 3 ^ x << 4; + s = s >>> 8 ^ s & 255 ^ 99; + sbox[i] = s; + } + for (let i = 0; i < 256; i++) { + const s = sbox[i]; + const is = sbox.indexOf(i); + Te4[i] = s << 24 | s << 16 | s << 8 | s; + Td4[i] = is << 24 | is << 16 | is << 8 | is; + const b0 = mul(is, 14); + const b1 = mul(is, 9); + const b2 = mul(is, 13); + const b3 = mul(is, 11); + const w = b0 << 24 | b1 << 16 | b2 << 8 | b3; + Td0[i] = w; + Td1[i] = w >>> 8 | w << 24; + Td2[i] = w >>> 16 | w << 16; + Td3[i] = w >>> 24 | w << 8; + } + let r = 1; + for (let i = 0; i < 10; i++) { + rcon[i] = r << 24; + r = r << 1 ^ (r & 128 ? 283 : 0); + } + tablesGenerated = true; +}; +class Aes128CbcContext { + constructor() { + this.roundkey = new Uint32Array(44); + this.iv = new Uint32Array(AES_128_BLOCK_SIZE / Uint32Array.BYTES_PER_ELEMENT); + this.in = new Uint8Array(AES_128_BLOCK_SIZE); + this.out = new Uint8Array(AES_128_BLOCK_SIZE); + this.inView = new DataView(this.in.buffer); + this.outView = new DataView(this.out.buffer); + } + init({ key, iv }) { + assert(key.byteLength === 16); + assert(iv.byteLength === 16); + if (!tablesGenerated) { + generateAesTables(); + } + const keyView = new DataView(key.buffer, key.byteOffset, key.byteLength); + const ivView = new DataView(iv.buffer, iv.byteOffset, iv.byteLength); + this.roundkey[0] = keyView.getUint32(0, false); + this.roundkey[1] = keyView.getUint32(4, false); + this.roundkey[2] = keyView.getUint32(8, false); + this.roundkey[3] = keyView.getUint32(12, false); + this.iv[0] = ivView.getUint32(0, false); + this.iv[1] = ivView.getUint32(4, false); + this.iv[2] = ivView.getUint32(8, false); + this.iv[3] = ivView.getUint32(12, false); + for (let index = 4; index < 44; index += 4) { + const temp = this.roundkey[index - 1]; + this.roundkey[index] = this.roundkey[index - 4] ^ Te4[temp >>> 16 & 255] & 4278190080 ^ Te4[temp >>> 8 & 255] & 16711680 ^ Te4[temp >>> 0 & 255] & 65280 ^ Te4[temp >>> 24 & 255] & 255 ^ rcon[index / 4 - 1]; + this.roundkey[index + 1] = this.roundkey[index - 3] ^ this.roundkey[index]; + this.roundkey[index + 2] = this.roundkey[index - 2] ^ this.roundkey[index + 1]; + this.roundkey[index + 3] = this.roundkey[index - 1] ^ this.roundkey[index + 2]; + } + for (let i = 0, j = 40; i < j; i += 4, j -= 4) { + for (let k = 0; k < 4; k++) { + const temp = this.roundkey[i + k]; + this.roundkey[i + k] = this.roundkey[j + k]; + this.roundkey[j + k] = temp; + } + } + for (let index = 4; index < 40; index += 4) { + for (let k = 0; k < 4; k++) { + const rk = this.roundkey[index + k]; + this.roundkey[index + k] = Td0[Te4[rk >>> 24 & 255] & 255] ^ Td1[Te4[rk >>> 16 & 255] & 255] ^ Td2[Te4[rk >>> 8 & 255] & 255] ^ Td3[Te4[rk >>> 0 & 255] & 255]; + } + } + } + decrypt() { + let s0 = this.inView.getUint32(0, false) ^ this.roundkey[0]; + let s1 = this.inView.getUint32(4, false) ^ this.roundkey[1]; + let s2 = this.inView.getUint32(8, false) ^ this.roundkey[2]; + let s3 = this.inView.getUint32(12, false) ^ this.roundkey[3]; + const temp0 = this.inView.getUint32(0, false); + const temp1 = this.inView.getUint32(4, false); + const temp2 = this.inView.getUint32(8, false); + const temp3 = this.inView.getUint32(12, false); + let t0, t1, t2, t3; + for (let round = 1; round < 10; round++) { + const offset = round * 4; + t0 = Td0[s0 >>> 24] ^ Td1[s3 >>> 16 & 255] ^ Td2[s2 >>> 8 & 255] ^ Td3[s1 & 255] ^ this.roundkey[offset]; + t1 = Td0[s1 >>> 24] ^ Td1[s0 >>> 16 & 255] ^ Td2[s3 >>> 8 & 255] ^ Td3[s2 & 255] ^ this.roundkey[offset + 1]; + t2 = Td0[s2 >>> 24] ^ Td1[s1 >>> 16 & 255] ^ Td2[s0 >>> 8 & 255] ^ Td3[s3 & 255] ^ this.roundkey[offset + 2]; + t3 = Td0[s3 >>> 24] ^ Td1[s2 >>> 16 & 255] ^ Td2[s1 >>> 8 & 255] ^ Td3[s0 & 255] ^ this.roundkey[offset + 3]; + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + const f0 = Td4[s0 >>> 24 & 255] & 4278190080 ^ Td4[s3 >>> 16 & 255] & 16711680 ^ Td4[s2 >>> 8 & 255] & 65280 ^ Td4[s1 >>> 0 & 255] & 255 ^ this.roundkey[40]; + const f1 = Td4[s1 >>> 24 & 255] & 4278190080 ^ Td4[s0 >>> 16 & 255] & 16711680 ^ Td4[s3 >>> 8 & 255] & 65280 ^ Td4[s2 >>> 0 & 255] & 255 ^ this.roundkey[41]; + const f2 = Td4[s2 >>> 24 & 255] & 4278190080 ^ Td4[s1 >>> 16 & 255] & 16711680 ^ Td4[s0 >>> 8 & 255] & 65280 ^ Td4[s3 >>> 0 & 255] & 255 ^ this.roundkey[42]; + const f3 = Td4[s3 >>> 24 & 255] & 4278190080 ^ Td4[s2 >>> 16 & 255] & 16711680 ^ Td4[s1 >>> 8 & 255] & 65280 ^ Td4[s0 >>> 0 & 255] & 255 ^ this.roundkey[43]; + this.outView.setUint32(0, f0 ^ this.iv[0], false); + this.outView.setUint32(4, f1 ^ this.iv[1], false); + this.outView.setUint32(8, f2 ^ this.iv[2], false); + this.outView.setUint32(12, f3 ^ this.iv[3], false); + this.iv[0] = temp0; + this.iv[1] = temp1; + this.iv[2] = temp2; + this.iv[3] = temp3; + } +} +const createAes128CbcDecryptStream = (reader, getInit, close) => { + let initted = false; + let pos = 0; + const CHUNK_SIZE = 2 ** 16; + const BLOCK_SIZE = 16; + const aesContext = new Aes128CbcContext(); + return new ReadableStream({ + pull: async (controller) => { + if (!initted) { + aesContext.init(await getInit()); + initted = true; + } + const requestedLength = CHUNK_SIZE + BLOCK_SIZE; + let nextSlice = reader.requestSliceRange(pos, 0, requestedLength); + if (nextSlice instanceof Promise) + nextSlice = await nextSlice; + if (!nextSlice || nextSlice.length === 0) { + throw new Error("Invalid ciphertext."); + } + const sliceLength = nextSlice.length; + if (sliceLength % 16 !== 0) { + throw new Error("Invalid ciphertext."); + } + const bytesToRead = sliceLength === requestedLength ? sliceLength - BLOCK_SIZE : sliceLength; + const input = readBytes(nextSlice, bytesToRead); + const output = new Uint8Array(bytesToRead); + for (let i = 0; i < bytesToRead; i += 16) { + aesContext.in.set(input.subarray(i, i + 16)); + aesContext.decrypt(); + output.set(aesContext.out, i); + } + if (bytesToRead < sliceLength) { + controller.enqueue(output); + pos += bytesToRead; + } else { + const paddingLength = output[bytesToRead - 1]; + if (paddingLength === 0 || paddingLength > 16) { + throw new Error("Invalid PKCS#7 padding. Incorrect key or corrupted data."); + } + const trimmedOutput = output.subarray(0, bytesToRead - paddingLength); + controller.enqueue(trimmedOutput); + controller.close(); + close(); + } + }, + cancel: () => { + close(); + } + }); +}; +class IsobmffDemuxer extends Demuxer { + constructor(input) { + super(input); + this.moovSlice = null; + this.currentTrack = null; + this.tracks = []; + this.metadataPromise = null; + this.movieTimescale = -1; + this.movieDurationInTimescale = -1; + this.isQuickTime = false; + this.metadataTags = {}; + this.currentMetadataKeys = null; + this.isFragmented = false; + this.fragmentTrackDefaults = []; + this.psshBoxes = []; + this.currentFragment = null; + this.lastReadFragment = null; + this.decryptionKeyCache = /* @__PURE__ */ new Map(); + this.reader = input._reader; + } + async getTrackBackings() { + await this.readMetadata(); + return this.tracks.map((track) => track.trackBacking); + } + async getMimeType() { + await this.readMetadata(); + const backings = await this.getTrackBackings(); + const codecStrings = await Promise.all(backings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildIsobmffMimeType({ + isQuickTime: this.isQuickTime, + hasVideo: this.tracks.some((x) => x.info?.type === "video"), + hasAudio: this.tracks.some((x) => x.info?.type === "audio"), + codecStrings: codecStrings.filter(Boolean) + }); + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } + readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let currentPos = 0; + let lookForMfraBox = false; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const startPos = currentPos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + if (boxInfo.name === "ftyp" || boxInfo.name === "styp") { + const majorBrand = readAscii(slice, 4); + this.isQuickTime = majorBrand === "qt "; + } else if (boxInfo.name === "moov") { + let moovSlice = this.reader.requestSlice(slice.filePos, boxInfo.contentSize); + if (moovSlice instanceof Promise) + moovSlice = await moovSlice; + if (!moovSlice) + break; + this.moovSlice = moovSlice; + this.readContiguousBoxes(this.moovSlice); + for (const track of this.tracks) { + const previousSegmentDurationsInSeconds = track.editListPreviousSegmentDurations / this.movieTimescale; + track.editListOffset -= Math.round(previousSegmentDurationsInSeconds * track.timescale); + } + lookForMfraBox = this.isFragmented && this.reader.fileSize !== null && this.reader.fileSize > startPos + boxInfo.totalSize; + break; + } else if (boxInfo.name === "moof") { + if (!this.input._initInput) { + throw new Error('"moof" box encountered with no "moov" box present; this file is likely a Segment as described in ISO/IEC 14496-12 Section 8.16. A separate init file that contains a "moov" box is required to read this file, please provide it using InputOptions.initInput.'); + } + const initDemuxer = await this.input._initInput._getDemuxer(); + if (initDemuxer.constructor !== IsobmffDemuxer) { + throw new Error("Init input must match the input's format."); + } + await initDemuxer.readMetadata(); + this.movieTimescale = initDemuxer.movieTimescale; + this.movieDurationInTimescale = initDemuxer.movieDurationInTimescale; + this.metadataTags = initDemuxer.metadataTags; + this.isFragmented = true; + this.fragmentTrackDefaults = initDemuxer.fragmentTrackDefaults; + this.psshBoxes = initDemuxer.psshBoxes; + for (const foreignTrack of initDemuxer.tracks) { + const track = { + id: foreignTrack.id, + demuxer: this, + trackBacking: null, + disposition: foreignTrack.disposition, + timescale: foreignTrack.timescale, + durationInMediaTimescale: foreignTrack.durationInMediaTimescale, + durationInMovieTimescale: foreignTrack.durationInMovieTimescale, + rotation: foreignTrack.rotation, + internalCodecId: foreignTrack.internalCodecId, + name: foreignTrack.name, + languageCode: foreignTrack.languageCode, + sampleTableByteOffset: null, + sampleTable: null, + fragmentLookupTable: [], + currentFragmentState: null, + fragmentPositionCache: [], + editListPreviousSegmentDurations: foreignTrack.editListPreviousSegmentDurations, + editListOffset: foreignTrack.editListOffset, + encryptionInfo: foreignTrack.encryptionInfo, + encryptionAuxInfo: null, + frmaCodecString: null, + info: foreignTrack.info + }; + if (foreignTrack.trackBacking) { + assert(track.info); + if (track.info.type === "video" && track.info.width !== -1) { + const videoTrack = track; + track.trackBacking = new IsobmffVideoTrackBacking(videoTrack); + this.tracks.push(track); + } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { + const audioTrack = track; + track.trackBacking = new IsobmffAudioTrackBacking(audioTrack); + this.tracks.push(track); + } + } + } + lookForMfraBox = false; + break; + } + currentPos = startPos + boxInfo.totalSize; + } + if (lookForMfraBox) { + assert(this.reader.fileSize !== null); + let lastWordSlice = this.reader.requestSlice(this.reader.fileSize - 4, 4); + if (lastWordSlice instanceof Promise) + lastWordSlice = await lastWordSlice; + assert(lastWordSlice); + const lastWord = readU32Be(lastWordSlice); + const potentialMfraPos = this.reader.fileSize - lastWord; + if (potentialMfraPos >= 0 && potentialMfraPos <= this.reader.fileSize - MAX_BOX_HEADER_SIZE) { + let mfraHeaderSlice = this.reader.requestSliceRange(potentialMfraPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (mfraHeaderSlice instanceof Promise) + mfraHeaderSlice = await mfraHeaderSlice; + if (mfraHeaderSlice) { + const boxInfo = readBoxHeader(mfraHeaderSlice); + if (boxInfo && boxInfo.name === "mfra") { + let mfraSlice = this.reader.requestSlice(mfraHeaderSlice.filePos, boxInfo.contentSize); + if (mfraSlice instanceof Promise) + mfraSlice = await mfraSlice; + if (mfraSlice) { + this.readContiguousBoxes(mfraSlice); + } + } + } + } + } + })()); + } + getSampleTableForTrack(internalTrack) { + if (internalTrack.sampleTable) { + return internalTrack.sampleTable; + } + const sampleTable = { + sampleTimingEntries: [], + sampleCompositionTimeOffsets: [], + sampleSizes: [], + keySampleIndices: null, + chunkOffsets: [], + sampleToChunk: [], + presentationTimestamps: null, + presentationTimestampIndexMap: null + }; + internalTrack.sampleTable = sampleTable; + if (internalTrack.sampleTableByteOffset === null) { + return sampleTable; + } + assert(this.moovSlice); + const stblContainerSlice = this.moovSlice.slice(internalTrack.sampleTableByteOffset); + this.currentTrack = internalTrack; + this.traverseBox(stblContainerSlice); + this.currentTrack = null; + const isPcmCodec = internalTrack.info?.type === "audio" && internalTrack.info.codec && PCM_AUDIO_CODECS.includes(internalTrack.info.codec); + if (isPcmCodec && sampleTable.sampleCompositionTimeOffsets.length === 0) { + assert(internalTrack.info?.type === "audio"); + const pcmInfo = parsePcmCodec(internalTrack.info.codec); + const newSampleTimingEntries = []; + const newSampleSizes = []; + for (let i = 0; i < sampleTable.sampleToChunk.length; i++) { + const chunkEntry = sampleTable.sampleToChunk[i]; + const nextEntry = sampleTable.sampleToChunk[i + 1]; + const chunkCount = (nextEntry ? nextEntry.startChunkIndex : sampleTable.chunkOffsets.length) - chunkEntry.startChunkIndex; + for (let j = 0; j < chunkCount; j++) { + const startSampleIndex = chunkEntry.startSampleIndex + j * chunkEntry.samplesPerChunk; + const endSampleIndex = startSampleIndex + chunkEntry.samplesPerChunk; + const startTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, startSampleIndex, (x) => x.startIndex); + const startTimingEntry = sampleTable.sampleTimingEntries[startTimingEntryIndex]; + const endTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, endSampleIndex, (x) => x.startIndex); + const endTimingEntry = sampleTable.sampleTimingEntries[endTimingEntryIndex]; + const firstSampleTimestamp = startTimingEntry.startDecodeTimestamp + (startSampleIndex - startTimingEntry.startIndex) * startTimingEntry.delta; + const lastSampleTimestamp = endTimingEntry.startDecodeTimestamp + (endSampleIndex - endTimingEntry.startIndex) * endTimingEntry.delta; + const delta = lastSampleTimestamp - firstSampleTimestamp; + const lastSampleTimingEntry = last(newSampleTimingEntries); + if (lastSampleTimingEntry && lastSampleTimingEntry.delta === delta) { + lastSampleTimingEntry.count++; + } else { + newSampleTimingEntries.push({ + startIndex: chunkEntry.startChunkIndex + j, + startDecodeTimestamp: firstSampleTimestamp, + count: 1, + delta + }); + } + const chunkSize = chunkEntry.samplesPerChunk * pcmInfo.sampleSize * internalTrack.info.numberOfChannels; + newSampleSizes.push(chunkSize); + } + chunkEntry.startSampleIndex = chunkEntry.startChunkIndex; + chunkEntry.samplesPerChunk = 1; + } + sampleTable.sampleTimingEntries = newSampleTimingEntries; + sampleTable.sampleSizes = newSampleSizes; + } + if (sampleTable.sampleCompositionTimeOffsets.length > 0) { + sampleTable.presentationTimestamps = []; + for (const entry of sampleTable.sampleTimingEntries) { + for (let i = 0; i < entry.count; i++) { + sampleTable.presentationTimestamps.push({ + presentationTimestamp: entry.startDecodeTimestamp + i * entry.delta, + sampleIndex: entry.startIndex + i + }); + } + } + for (const entry of sampleTable.sampleCompositionTimeOffsets) { + for (let i = 0; i < entry.count; i++) { + const sampleIndex = entry.startIndex + i; + const sample = sampleTable.presentationTimestamps[sampleIndex]; + if (!sample) { + continue; + } + sample.presentationTimestamp += entry.offset; + } + } + sampleTable.presentationTimestamps.sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); + sampleTable.presentationTimestampIndexMap = Array(sampleTable.presentationTimestamps.length).fill(-1); + for (let i = 0; i < sampleTable.presentationTimestamps.length; i++) { + sampleTable.presentationTimestampIndexMap[sampleTable.presentationTimestamps[i].sampleIndex] = i; + } + } + return sampleTable; + } + async readFragment(startPos) { + if (this.lastReadFragment?.moofOffset === startPos) { + return this.lastReadFragment; + } + let headerSlice = this.reader.requestSliceRange(startPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const moofBoxInfo = readBoxHeader(headerSlice); + assert(moofBoxInfo?.name === "moof"); + let entireSlice = this.reader.requestSlice(startPos, moofBoxInfo.totalSize); + if (entireSlice instanceof Promise) + entireSlice = await entireSlice; + assert(entireSlice); + this.traverseBox(entireSlice); + const fragment = this.lastReadFragment; + assert(fragment && fragment.moofOffset === startPos); + for (const [, trackData] of fragment.trackData) { + const track = trackData.track; + const { fragmentPositionCache } = track; + if (!trackData.startTimestampIsFinal) { + const lookupEntry = track.fragmentLookupTable.find((x) => x.moofOffset === fragment.moofOffset); + if (lookupEntry) { + offsetFragmentTrackDataByTimestamp(trackData, lookupEntry.timestamp); + } else { + const lastCacheIndex = binarySearchLessOrEqual(fragmentPositionCache, fragment.moofOffset - 1, (x) => x.moofOffset); + if (lastCacheIndex !== -1) { + const lastCache = fragmentPositionCache[lastCacheIndex]; + offsetFragmentTrackDataByTimestamp(trackData, lastCache.endTimestamp); + } + } + trackData.startTimestampIsFinal = true; + } + const insertionIndex = binarySearchLessOrEqual(fragmentPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); + if (insertionIndex === -1 || fragmentPositionCache[insertionIndex].moofOffset !== fragment.moofOffset) { + fragmentPositionCache.splice(insertionIndex + 1, 0, { + moofOffset: fragment.moofOffset, + startTimestamp: trackData.startTimestamp, + endTimestamp: trackData.endTimestamp + }); + } + if (trackData.encryptionAuxInfo && track.encryptionInfo) { + const entries = await resolveEncryptionAuxInfo(this.reader, track.encryptionInfo, trackData.encryptionAuxInfo); + for (let i = 0; i < Math.min(trackData.samples.length, entries.length); i++) { + const entry = entries[i]; + trackData.samples[i].encryption = entry; + } + } + } + return fragment; + } + readContiguousBoxes(slice) { + const startIndex = slice.filePos; + while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { + const foundBox = this.traverseBox(slice); + if (!foundBox) { + break; + } + } + } + // eslint-disable-next-line @stylistic/generator-star-spacing + *iterateContiguousBoxes(slice) { + const startIndex = slice.filePos; + while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { + const startPos = slice.filePos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + yield { boxInfo, slice }; + slice.filePos = startPos + boxInfo.totalSize; + } + } + traverseBox(slice) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G; + const startPos = slice.filePos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + return false; + } + const contentStartPos = slice.filePos; + const boxEndPos = startPos + boxInfo.totalSize; + switch (boxInfo.name) { + case "mdia": + case "minf": + case "dinf": + case "mfra": + case "edts": + case "sinf": + case "schi": + { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "mvhd": + { + const version = readU8(slice); + slice.skip(3); + if (version === 1) { + slice.skip(8 + 8); + this.movieTimescale = readU32Be(slice); + this.movieDurationInTimescale = readU64Be(slice); + } else { + slice.skip(4 + 4); + this.movieTimescale = readU32Be(slice); + this.movieDurationInTimescale = readU32Be(slice); + } + } + break; + case "trak": + { + const track = { + id: -1, + demuxer: this, + trackBacking: null, + disposition: { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }, + info: null, + timescale: -1, + durationInMovieTimescale: -1, + durationInMediaTimescale: -1, + rotation: 0, + internalCodecId: null, + name: null, + languageCode: UNDETERMINED_LANGUAGE, + sampleTableByteOffset: -1, + sampleTable: null, + fragmentLookupTable: [], + currentFragmentState: null, + fragmentPositionCache: [], + editListPreviousSegmentDurations: 0, + editListOffset: 0, + encryptionInfo: null, + encryptionAuxInfo: null, + frmaCodecString: null + }; + this.currentTrack = track; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + if (track.id !== -1 && track.timescale !== -1 && track.info !== null) { + if (track.info.type === "video" && track.info.width !== -1) { + const videoTrack = track; + track.trackBacking = new IsobmffVideoTrackBacking(videoTrack); + this.tracks.push(track); + } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { + const audioTrack = track; + track.trackBacking = new IsobmffAudioTrackBacking(audioTrack); + this.tracks.push(track); + } + } + this.currentTrack = null; + } + break; + case "tkhd": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + const flags = readU24Be(slice); + const trackEnabled = !!(flags & 1); + track.disposition.default = trackEnabled; + if (version === 0) { + slice.skip(8); + track.id = readU32Be(slice); + slice.skip(4); + track.durationInMovieTimescale = readU32Be(slice); + } else if (version === 1) { + slice.skip(16); + track.id = readU32Be(slice); + slice.skip(4); + track.durationInMovieTimescale = readU64Be(slice); + } else { + throw new Error(`Incorrect track header version ${version}.`); + } + slice.skip(2 * 4 + 2 + 2 + 2 + 2); + const matrix = [ + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice), + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice), + readFixed_16_16(slice), + readFixed_16_16(slice), + readFixed_2_30(slice) + ]; + const rotation = normalizeRotation(roundToMultiple(extractRotationFromMatrix(matrix), 90)); + assert(rotation === 0 || rotation === 90 || rotation === 180 || rotation === 270); + track.rotation = rotation; + } + break; + case "elst": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + slice.skip(3); + let relevantEntryFound = false; + let previousSegmentDurations = 0; + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const segmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); + const mediaTime = version === 1 ? readI64Be(slice) : readI32Be(slice); + const mediaRate = readFixed_16_16(slice); + if (segmentDuration === 0) { + continue; + } + if (relevantEntryFound) { + console.warn("Unsupported edit list: multiple edits are not currently supported. Only using first edit."); + break; + } + if (mediaTime === -1) { + previousSegmentDurations += segmentDuration; + continue; + } + if (mediaRate !== 1) { + console.warn("Unsupported edit list entry: media rate must be 1."); + break; + } + track.editListPreviousSegmentDurations = previousSegmentDurations; + track.editListOffset = mediaTime; + relevantEntryFound = true; + } + } + break; + case "mdhd": + { + const track = this.currentTrack; + if (!track) { + break; + } + const version = readU8(slice); + slice.skip(3); + if (version === 0) { + slice.skip(8); + track.timescale = readU32Be(slice); + track.durationInMediaTimescale = readU32Be(slice); + } else if (version === 1) { + slice.skip(16); + track.timescale = readU32Be(slice); + track.durationInMediaTimescale = readU64Be(slice); + } + let language = readU16Be(slice); + if (language > 0) { + track.languageCode = ""; + for (let i = 0; i < 3; i++) { + track.languageCode = String.fromCharCode(96 + (language & 31)) + track.languageCode; + language >>= 5; + } + if (!isIso639Dash2LanguageCode(track.languageCode)) { + track.languageCode = UNDETERMINED_LANGUAGE; + } + } + } + break; + case "hdlr": + { + const track = this.currentTrack; + if (!track) { + break; + } + slice.skip(8); + const handlerType = readAscii(slice, 4); + if (handlerType === "vide") { + track.info = { + type: "video", + width: -1, + height: -1, + squarePixelWidth: -1, + squarePixelHeight: -1, + codec: null, + codecDescription: null, + colorSpace: null, + avcType: null, + avcCodecInfo: null, + hevcCodecInfo: null, + vp9CodecInfo: null, + av1CodecInfo: null + }; + } else if (handlerType === "soun") { + track.info = { + type: "audio", + numberOfChannels: -1, + sampleRate: -1, + codec: null, + codecDescription: null, + aacCodecInfo: null, + pcmLittleEndian: false, + pcmSampleSize: null + }; + } + } + break; + case "stbl": + { + const track = this.currentTrack; + if (!track) { + break; + } + track.sampleTableByteOffset = startPos; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "stsd": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (track.info === null || track.sampleTable) { + break; + } + const stsdVersion = readU8(slice); + slice.skip(3); + const entries = readU32Be(slice); + for (let i = 0; i < entries; i++) { + const sampleBoxStartPos = slice.filePos; + const sampleBoxInfo = readBoxHeader(slice); + if (!sampleBoxInfo) { + break; + } + track.internalCodecId = sampleBoxInfo.name; + const lowercaseBoxName = sampleBoxInfo.name.toLowerCase(); + if (track.info.type === "video") { + slice.skip(6 * 1 + 2 + 2 + 2 + 3 * 4); + track.info.width = readU16Be(slice); + track.info.height = readU16Be(slice); + track.info.squarePixelWidth = track.info.width; + track.info.squarePixelHeight = track.info.height; + slice.skip(4 + 4 + 4 + 2 + 32 + 2 + 2); + track.frmaCodecString = null; + this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); + const codecName = lowercaseBoxName === "encv" ? track.frmaCodecString : lowercaseBoxName; + track.frmaCodecString = null; + if (codecName === "avc1" || codecName === "avc3") { + track.info.codec = "avc"; + track.info.avcType = codecName === "avc1" ? 1 : 3; + } else if (codecName === "hvc1" || codecName === "hev1") { + track.info.codec = "hevc"; + } else if (codecName === "vp08") { + track.info.codec = "vp8"; + } else if (codecName === "vp09") { + track.info.codec = "vp9"; + } else if (codecName === "av01") { + track.info.codec = "av1"; + } else if (codecName === null) { + console.warn(`Unknown encrypted video codec due to missing frma box.`); + } else { + console.warn(`Unsupported video codec (sample entry type '${sampleBoxInfo.name}').`); + } + } else { + slice.skip(6 * 1 + 2); + const version = readU16Be(slice); + slice.skip(3 * 2); + let channelCount = readU16Be(slice); + let sampleSize = readU16Be(slice); + slice.skip(2 * 2); + let sampleRate = readU32Be(slice) / 65536; + let lpcmFlags = null; + if (stsdVersion === 0 && version > 0) { + if (version === 1) { + slice.skip(4); + sampleSize = 8 * readU32Be(slice); + slice.skip(2 * 4); + } else if (version === 2) { + slice.skip(4); + sampleRate = readF64Be(slice); + channelCount = readU32Be(slice); + slice.skip(4); + sampleSize = readU32Be(slice); + lpcmFlags = readU32Be(slice); + slice.skip(2 * 4); + } + } + track.info.numberOfChannels = channelCount; + track.info.sampleRate = sampleRate; + track.frmaCodecString = null; + this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); + const codecName = lowercaseBoxName === "enca" ? track.frmaCodecString : lowercaseBoxName; + track.frmaCodecString = null; + if (codecName === "mp4a") ; + else if (codecName === "opus") { + track.info.codec = "opus"; + track.info.sampleRate = OPUS_SAMPLE_RATE; + } else if (codecName === "flac") { + track.info.codec = "flac"; + } else if (codecName === "ulaw") { + track.info.codec = "ulaw"; + } else if (codecName === "alaw") { + track.info.codec = "alaw"; + } else if (codecName === "ac-3") { + track.info.codec = "ac3"; + } else if (codecName === "ec-3") { + track.info.codec = "eac3"; + } else if (codecName === "twos") { + if (sampleSize === 8) { + track.info.codec = "pcm-s8"; + } else if (sampleSize === 16) { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s16" : "pcm-s16be"; + } else { + console.warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`); + track.info.codec = null; + } + } else if (codecName === "sowt") { + if (sampleSize === 8) { + track.info.codec = "pcm-s8"; + } else if (sampleSize === 16) { + track.info.codec = "pcm-s16"; + } else { + console.warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`); + track.info.codec = null; + } + } else if (codecName === "raw ") { + track.info.codec = "pcm-u8"; + } else if (codecName === "in24") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s24" : "pcm-s24be"; + } else if (codecName === "in32") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-s32" : "pcm-s32be"; + } else if (codecName === "fl32") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-f32" : "pcm-f32be"; + } else if (codecName === "fl64") { + track.info.codec = track.info.pcmLittleEndian ? "pcm-f64" : "pcm-f64be"; + } else if (codecName === "ipcm") { + const pcmSampleSize = track.info.pcmSampleSize; + if (track.info.pcmLittleEndian) { + if (pcmSampleSize === 16) { + track.info.codec = "pcm-s16"; + } else if (pcmSampleSize === 24) { + track.info.codec = "pcm-s24"; + } else if (pcmSampleSize === 32) { + track.info.codec = "pcm-s32"; + } else { + console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } else { + if (pcmSampleSize === 16) { + track.info.codec = "pcm-s16be"; + } else if (pcmSampleSize === 24) { + track.info.codec = "pcm-s24be"; + } else if (pcmSampleSize === 32) { + track.info.codec = "pcm-s32be"; + } else { + console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } + } else if (codecName === "fpcm") { + const pcmSampleSize = track.info.pcmSampleSize; + if (track.info.pcmLittleEndian) { + if (pcmSampleSize === 32) { + track.info.codec = "pcm-f32"; + } else if (pcmSampleSize === 64) { + track.info.codec = "pcm-f64"; + } else { + console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } else { + if (pcmSampleSize === 32) { + track.info.codec = "pcm-f32be"; + } else if (pcmSampleSize === 64) { + track.info.codec = "pcm-f64be"; + } else { + console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); + track.info.codec = null; + } + } + } else if (codecName === "lpcm" && lpcmFlags !== null) { + const bytesPerSample = sampleSize + 7 >> 3; + const isFloat = Boolean(lpcmFlags & 1); + const isBigEndian = Boolean(lpcmFlags & 2); + const sFlags = lpcmFlags & 4 ? -1 : 0; + if (sampleSize > 0 && sampleSize <= 64) { + if (isFloat) { + if (sampleSize === 32) { + track.info.codec = isBigEndian ? "pcm-f32be" : "pcm-f32"; + } + } else { + if (sFlags & 1 << bytesPerSample - 1) { + if (bytesPerSample === 1) { + track.info.codec = "pcm-s8"; + } else if (bytesPerSample === 2) { + track.info.codec = isBigEndian ? "pcm-s16be" : "pcm-s16"; + } else if (bytesPerSample === 3) { + track.info.codec = isBigEndian ? "pcm-s24be" : "pcm-s24"; + } else if (bytesPerSample === 4) { + track.info.codec = isBigEndian ? "pcm-s32be" : "pcm-s32"; + } + } else { + if (bytesPerSample === 1) { + track.info.codec = "pcm-u8"; + } + } + } + } + if (track.info.codec === null) { + console.warn("Unsupported PCM format."); + } + } else if (codecName === null) { + console.warn(`Unknown encrypted audio codec due to missing frma box.`); + } else { + console.warn(`Unsupported audio codec (sample entry type '${sampleBoxInfo.name}').`); + } + } + slice.filePos = sampleBoxStartPos + sampleBoxInfo.totalSize; + } + } + break; + case "frma": + { + const track = this.currentTrack; + if (!track) { + break; + } + const format = readAscii(slice, 4); + const lowercase = format.toLowerCase(); + track.frmaCodecString = lowercase; + } + break; + case "schm": + { + const track = this.currentTrack; + if (!track) { + break; + } + slice.skip(4); + const schemeType = readAscii(slice, 4); + if (schemeType === "cenc" || schemeType === "cens" || schemeType === "cbcs") { + track.encryptionInfo = { + scheme: schemeType, + defaultKid: null, + defaultIsProtected: null, + defaultPerSampleIvSize: null, + defaultConstantIv: null, + defaultCryptByteBlock: null, + defaultSkipByteBlock: null + }; + } else { + console.warn(`Unsupported encryption scheme '${schemeType}'.`); + } + } + break; + case "tenc": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + const version = readU8(slice); + slice.skip(3); + slice.skip(1); + const patternByte = readU8(slice); + if (version > 0) { + track.encryptionInfo.defaultCryptByteBlock = patternByte >> 4; + track.encryptionInfo.defaultSkipByteBlock = patternByte & 15; + } else { + track.encryptionInfo.defaultCryptByteBlock = 0; + track.encryptionInfo.defaultSkipByteBlock = 0; + } + track.encryptionInfo.defaultIsProtected = readU8(slice) !== 0; + track.encryptionInfo.defaultPerSampleIvSize = readU8(slice); + track.encryptionInfo.defaultKid = bytesToHexString(readBytes(slice, 16)); + if (track.encryptionInfo.defaultIsProtected && track.encryptionInfo.defaultPerSampleIvSize === 0) { + const constantIvSize = readU8(slice); + const constantIv = new Uint8Array(16); + constantIv.set(readBytes(slice, constantIvSize), 0); + track.encryptionInfo.defaultConstantIv = constantIv; + } + } + break; + case "avcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info); + track.info.codecDescription = readBytes(slice, boxInfo.contentSize); + } + break; + case "hvcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info); + track.info.codecDescription = readBytes(slice, boxInfo.contentSize); + } + break; + case "vpcC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + slice.skip(4); + const profile = readU8(slice); + const level = readU8(slice); + const thirdByte = readU8(slice); + const bitDepth = thirdByte >> 4; + const chromaSubsampling = thirdByte >> 1 & 7; + const videoFullRangeFlag = thirdByte & 1; + const colourPrimaries = readU8(slice); + const transferCharacteristics = readU8(slice); + const matrixCoefficients = readU8(slice); + track.info.vp9CodecInfo = { + profile, + level, + bitDepth, + chromaSubsampling, + videoFullRangeFlag, + colourPrimaries, + transferCharacteristics, + matrixCoefficients + }; + } + break; + case "av1C": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + slice.skip(1); + const secondByte = readU8(slice); + const profile = secondByte >> 5; + const level = secondByte & 31; + const thirdByte = readU8(slice); + const tier = thirdByte >> 7; + const highBitDepth = thirdByte >> 6 & 1; + const twelveBit = thirdByte >> 5 & 1; + const monochrome = thirdByte >> 4 & 1; + const chromaSubsamplingX = thirdByte >> 3 & 1; + const chromaSubsamplingY = thirdByte >> 2 & 1; + const chromaSamplePosition = thirdByte & 3; + const bitDepth = profile === 2 && highBitDepth ? twelveBit ? 12 : 10 : highBitDepth ? 10 : 8; + track.info.av1CodecInfo = { + profile, + level, + tier, + bitDepth, + monochrome, + chromaSubsamplingX, + chromaSubsamplingY, + chromaSamplePosition + }; + } + break; + case "colr": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + const colourType = readAscii(slice, 4); + if (colourType !== "nclx") { + break; + } + const colourPrimaries = readU16Be(slice); + const transferCharacteristics = readU16Be(slice); + const matrixCoefficients = readU16Be(slice); + const fullRangeFlag = Boolean(readU8(slice) & 128); + track.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients], + fullRange: fullRangeFlag + }; + } + break; + case "pasp": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "video"); + const num = readU32Be(slice); + const den = readU32Be(slice); + if (num > 0 && den > 0) { + if (num > den) { + track.info.squarePixelWidth = Math.round(track.info.width * num / den); + } else { + track.info.squarePixelHeight = Math.round(track.info.height * den / num); + } + } + } + break; + case "wave": + { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "esds": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(4); + const tag = readU8(slice); + assert(tag === 3); + readIsomVariableInteger(slice); + slice.skip(2); + const mixed = readU8(slice); + const streamDependenceFlag = (mixed & 128) !== 0; + const urlFlag = (mixed & 64) !== 0; + const ocrStreamFlag = (mixed & 32) !== 0; + if (streamDependenceFlag) { + slice.skip(2); + } + if (urlFlag) { + const urlLength = readU8(slice); + slice.skip(urlLength); + } + if (ocrStreamFlag) { + slice.skip(2); + } + const decoderConfigTag = readU8(slice); + assert(decoderConfigTag === 4); + const decoderConfigDescriptorLength = readIsomVariableInteger(slice); + const payloadStart = slice.filePos; + const objectTypeIndication = readU8(slice); + if (objectTypeIndication === 64 || objectTypeIndication === 103) { + track.info.codec = "aac"; + track.info.aacCodecInfo = { + isMpeg2: objectTypeIndication === 103, + objectType: null + }; + } else if (objectTypeIndication === 105 || objectTypeIndication === 107) { + track.info.codec = "mp3"; + } else if (objectTypeIndication === 221) { + track.info.codec = "vorbis"; + } else { + console.warn(`Unsupported audio codec (objectTypeIndication ${objectTypeIndication}) - discarding track.`); + } + slice.skip(1 + 3 + 4 + 4); + if (decoderConfigDescriptorLength > slice.filePos - payloadStart) { + const decoderSpecificInfoTag = readU8(slice); + assert(decoderSpecificInfoTag === 5); + const decoderSpecificInfoLength = readIsomVariableInteger(slice); + track.info.codecDescription = readBytes(slice, decoderSpecificInfoLength); + if (track.info.codec === "aac") { + const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); + if (audioSpecificConfig.numberOfChannels !== null) { + track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; + } + if (audioSpecificConfig.sampleRate !== null) { + track.info.sampleRate = audioSpecificConfig.sampleRate; + } + } + } + } + break; + case "enda": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + track.info.pcmLittleEndian = !!(readU16Be(slice) & 255); + } + break; + case "pcmC": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(1 + 3); + const formatFlags = readU8(slice); + track.info.pcmLittleEndian = Boolean(formatFlags & 1); + track.info.pcmSampleSize = readU8(slice); + } + break; + case "dOps": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(1); + const outputChannelCount = readU8(slice); + const preSkip = readU16Be(slice); + const inputSampleRate = readU32Be(slice); + const outputGain = readI16Be(slice); + const channelMappingFamily = readU8(slice); + let channelMappingTable; + if (channelMappingFamily !== 0) { + channelMappingTable = readBytes(slice, 2 + outputChannelCount); + } else { + channelMappingTable = new Uint8Array(0); + } + const description = new Uint8Array(8 + 1 + 1 + 2 + 4 + 2 + 1 + channelMappingTable.byteLength); + const view = new DataView(description.buffer); + view.setUint32(0, 1332770163, false); + view.setUint32(4, 1214603620, false); + view.setUint8(8, 1); + view.setUint8(9, outputChannelCount); + view.setUint16(10, preSkip, true); + view.setUint32(12, inputSampleRate, true); + view.setInt16(16, outputGain, true); + view.setUint8(18, channelMappingFamily); + description.set(channelMappingTable, 19); + track.info.codecDescription = description; + track.info.numberOfChannels = outputChannelCount; + } + break; + case "dfLa": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + slice.skip(4); + const BLOCK_TYPE_MASK = 127; + const LAST_METADATA_BLOCK_FLAG_MASK = 128; + const startPos2 = slice.filePos; + while (slice.filePos < boxEndPos) { + const flagAndType = readU8(slice); + const metadataBlockLength = readU24Be(slice); + const type = flagAndType & BLOCK_TYPE_MASK; + if (type === FlacBlockType.STREAMINFO) { + slice.skip(10); + const word = readU32Be(slice); + const sampleRate = word >>> 12; + const numberOfChannels = (word >> 9 & 7) + 1; + track.info.sampleRate = sampleRate; + track.info.numberOfChannels = numberOfChannels; + slice.skip(20); + } else { + slice.skip(metadataBlockLength); + } + if (flagAndType & LAST_METADATA_BLOCK_FLAG_MASK) { + break; + } + } + const endPos = slice.filePos; + slice.filePos = startPos2; + const bytes = readBytes(slice, endPos - startPos2); + const description = new Uint8Array(4 + bytes.byteLength); + const view = new DataView(description.buffer); + view.setUint32(0, 1716281667, false); + description.set(bytes, 4); + track.info.codecDescription = description; + } + break; + case "dac3": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + const bytes = readBytes(slice, 3); + const bitstream = new Bitstream(bytes); + const fscod = bitstream.readBits(2); + bitstream.skipBits(5 + 3); + const acmod = bitstream.readBits(3); + const lfeon = bitstream.readBits(1); + if (fscod < 3) { + track.info.sampleRate = AC3_SAMPLE_RATES[fscod]; + } + track.info.numberOfChannels = AC3_ACMOD_CHANNEL_COUNTS[acmod] + lfeon; + } + break; + case "dec3": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.info?.type === "audio"); + const bytes = readBytes(slice, boxInfo.contentSize); + const config = parseEac3Config(bytes); + if (!config) { + console.warn("Invalid dec3 box contents, ignoring."); + break; + } + const sampleRate = getEac3SampleRate(config); + if (sampleRate !== null) { + track.info.sampleRate = sampleRate; + } + track.info.numberOfChannels = getEac3ChannelCount(config); + } + break; + case "stts": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + let currentIndex = 0; + let currentTimestamp = 0; + for (let i = 0; i < entryCount; i++) { + const sampleCount = readU32Be(slice); + const sampleDelta = readU32Be(slice); + track.sampleTable.sampleTimingEntries.push({ + startIndex: currentIndex, + startDecodeTimestamp: currentTimestamp, + count: sampleCount, + delta: sampleDelta + }); + currentIndex += sampleCount; + currentTimestamp += sampleCount * sampleDelta; + } + } + break; + case "ctts": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(1 + 3); + const entryCount = readU32Be(slice); + let sampleIndex = 0; + for (let i = 0; i < entryCount; i++) { + const sampleCount = readU32Be(slice); + const sampleOffset = readI32Be(slice); + track.sampleTable.sampleCompositionTimeOffsets.push({ + startIndex: sampleIndex, + count: sampleCount, + offset: sampleOffset + }); + sampleIndex += sampleCount; + } + } + break; + case "stsz": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const sampleSize = readU32Be(slice); + const sampleCount = readU32Be(slice); + if (sampleSize === 0) { + for (let i = 0; i < sampleCount; i++) { + const sampleSize2 = readU32Be(slice); + track.sampleTable.sampleSizes.push(sampleSize2); + } + } else { + track.sampleTable.sampleSizes.push(sampleSize); + } + } + break; + case "stz2": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + slice.skip(3); + const fieldSize = readU8(slice); + const sampleCount = readU32Be(slice); + const bytes = readBytes(slice, Math.ceil(sampleCount * fieldSize / 8)); + const bitstream = new Bitstream(bytes); + for (let i = 0; i < sampleCount; i++) { + const sampleSize = bitstream.readBits(fieldSize); + track.sampleTable.sampleSizes.push(sampleSize); + } + } + break; + case "stss": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + track.sampleTable.keySampleIndices = []; + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const sampleIndex = readU32Be(slice) - 1; + track.sampleTable.keySampleIndices.push(sampleIndex); + } + if (track.sampleTable.keySampleIndices[0] !== 0) { + track.sampleTable.keySampleIndices.unshift(0); + } + } + break; + case "stsc": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const startChunkIndex = readU32Be(slice) - 1; + const samplesPerChunk = readU32Be(slice); + const sampleDescriptionIndex = readU32Be(slice); + track.sampleTable.sampleToChunk.push({ + startSampleIndex: -1, + startChunkIndex, + samplesPerChunk, + sampleDescriptionIndex + }); + } + let startSampleIndex = 0; + for (let i = 0; i < track.sampleTable.sampleToChunk.length; i++) { + track.sampleTable.sampleToChunk[i].startSampleIndex = startSampleIndex; + if (i < track.sampleTable.sampleToChunk.length - 1) { + const nextChunk = track.sampleTable.sampleToChunk[i + 1]; + const chunkCount = nextChunk.startChunkIndex - track.sampleTable.sampleToChunk[i].startChunkIndex; + startSampleIndex += chunkCount * track.sampleTable.sampleToChunk[i].samplesPerChunk; + } + } + } + break; + case "stco": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const chunkOffset = readU32Be(slice); + track.sampleTable.chunkOffsets.push(chunkOffset); + } + } + break; + case "co64": + { + const track = this.currentTrack; + if (!track) { + break; + } + if (!track.sampleTable) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const chunkOffset = readU64Be(slice); + track.sampleTable.chunkOffsets.push(chunkOffset); + } + } + break; + case "mvex": + { + this.isFragmented = true; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } + break; + case "mehd": + { + const version = readU8(slice); + slice.skip(3); + const fragmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); + this.movieDurationInTimescale = fragmentDuration; + } + break; + case "trex": + { + slice.skip(4); + const trackId = readU32Be(slice); + const defaultSampleDescriptionIndex = readU32Be(slice); + const defaultSampleDuration = readU32Be(slice); + const defaultSampleSize = readU32Be(slice); + const defaultSampleFlags = readU32Be(slice); + this.fragmentTrackDefaults.push({ + trackId, + defaultSampleDescriptionIndex, + defaultSampleDuration, + defaultSampleSize, + defaultSampleFlags + }); + } + break; + case "tfra": + { + const version = readU8(slice); + slice.skip(3); + const trackId = readU32Be(slice); + const track = this.tracks.find((x) => x.id === trackId); + if (!track) { + break; + } + const word = readU32Be(slice); + const lengthSizeOfTrafNum = (word & 48) >> 4; + const lengthSizeOfTrunNum = (word & 12) >> 2; + const lengthSizeOfSampleNum = word & 3; + const functions = [readU8, readU16Be, readU24Be, readU32Be]; + const readTrafNum = functions[lengthSizeOfTrafNum]; + const readTrunNum = functions[lengthSizeOfTrunNum]; + const readSampleNum = functions[lengthSizeOfSampleNum]; + const numberOfEntries = readU32Be(slice); + for (let i = 0; i < numberOfEntries; i++) { + const time = version === 1 ? readU64Be(slice) : readU32Be(slice); + const moofOffset = version === 1 ? readU64Be(slice) : readU32Be(slice); + readTrafNum(slice); + readTrunNum(slice); + readSampleNum(slice); + track.fragmentLookupTable.push({ + timestamp: time, + moofOffset + }); + } + track.fragmentLookupTable.sort((a, b) => a.timestamp - b.timestamp); + for (let i = 0; i < track.fragmentLookupTable.length - 1; i++) { + const entry1 = track.fragmentLookupTable[i]; + const entry2 = track.fragmentLookupTable[i + 1]; + if (entry1.timestamp === entry2.timestamp) { + track.fragmentLookupTable.splice(i + 1, 1); + i--; + } + } + } + break; + case "moof": + { + this.currentFragment = { + moofOffset: startPos, + moofSize: boxInfo.totalSize, + implicitBaseDataOffset: startPos, + trackData: /* @__PURE__ */ new Map(), + psshBoxes: [] + }; + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + this.lastReadFragment = this.currentFragment; + this.currentFragment = null; + } + break; + case "traf": + { + assert(this.currentFragment); + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + if (this.currentTrack) { + const trackData = this.currentFragment.trackData.get(this.currentTrack.id); + if (trackData) { + this.currentFragment.implicitBaseDataOffset = trackData.currentOffset; + trackData.presentationTimestamps = trackData.samples.map((x, i) => ({ presentationTimestamp: x.presentationTimestamp, sampleIndex: i })).sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); + for (let i = 0; i < trackData.presentationTimestamps.length; i++) { + const currentEntry = trackData.presentationTimestamps[i]; + const currentSample = trackData.samples[currentEntry.sampleIndex]; + if (trackData.firstKeyFrameTimestamp === null && currentSample.isKeyFrame) { + trackData.firstKeyFrameTimestamp = currentSample.presentationTimestamp; + } + if (i < trackData.presentationTimestamps.length - 1) { + const nextEntry = trackData.presentationTimestamps[i + 1]; + const duration = nextEntry.presentationTimestamp - currentEntry.presentationTimestamp; + currentSample.duration = duration; + } + } + const firstSample = trackData.samples[trackData.presentationTimestamps[0].sampleIndex]; + const lastSample = trackData.samples[last(trackData.presentationTimestamps).sampleIndex]; + trackData.startTimestamp = firstSample.presentationTimestamp; + trackData.endTimestamp = lastSample.presentationTimestamp + lastSample.duration; + const { currentFragmentState } = this.currentTrack; + assert(currentFragmentState); + if (currentFragmentState.startTimestamp !== null) { + offsetFragmentTrackDataByTimestamp(trackData, currentFragmentState.startTimestamp); + trackData.startTimestampIsFinal = true; + } + if (currentFragmentState.encryptionAuxInfo && !trackData.samples[0].encryption) { + trackData.encryptionAuxInfo = currentFragmentState.encryptionAuxInfo; + } + } + this.currentTrack.currentFragmentState = null; + this.currentTrack = null; + } + } + break; + case "pssh": + { + if (this.input._formatOptions.isobmff?._suppressPsshParsing) { + break; + } + const psshBox = parsePsshBoxContents(readBytes(slice, boxInfo.contentSize)); + if (this.currentFragment) { + this.currentFragment.psshBoxes.push(psshBox); + } else if (!this.currentTrack) { + this.psshBoxes.push(psshBox); + } + } + break; + case "tfhd": + { + assert(this.currentFragment); + slice.skip(1); + const flags = readU24Be(slice); + const baseDataOffsetPresent = Boolean(flags & 1); + const sampleDescriptionIndexPresent = Boolean(flags & 2); + const defaultSampleDurationPresent = Boolean(flags & 8); + const defaultSampleSizePresent = Boolean(flags & 16); + const defaultSampleFlagsPresent = Boolean(flags & 32); + const durationIsEmpty = Boolean(flags & 65536); + const defaultBaseIsMoof = Boolean(flags & 131072); + const trackId = readU32Be(slice); + const track = this.tracks.find((x) => x.id === trackId); + if (!track) { + break; + } + const defaults = this.fragmentTrackDefaults.find((x) => x.trackId === trackId); + this.currentTrack = track; + track.currentFragmentState = { + baseDataOffset: this.currentFragment.implicitBaseDataOffset, + sampleDescriptionIndex: defaults?.defaultSampleDescriptionIndex ?? null, + defaultSampleDuration: defaults?.defaultSampleDuration ?? null, + defaultSampleSize: defaults?.defaultSampleSize ?? null, + defaultSampleFlags: defaults?.defaultSampleFlags ?? null, + startTimestamp: null, + encryptionAuxInfo: null + }; + if (baseDataOffsetPresent) { + track.currentFragmentState.baseDataOffset = readU64Be(slice); + } else if (defaultBaseIsMoof) { + track.currentFragmentState.baseDataOffset = this.currentFragment.moofOffset; + } + if (sampleDescriptionIndexPresent) { + track.currentFragmentState.sampleDescriptionIndex = readU32Be(slice); + } + if (defaultSampleDurationPresent) { + track.currentFragmentState.defaultSampleDuration = readU32Be(slice); + } + if (defaultSampleSizePresent) { + track.currentFragmentState.defaultSampleSize = readU32Be(slice); + } + if (defaultSampleFlagsPresent) { + track.currentFragmentState.defaultSampleFlags = readU32Be(slice); + } + if (durationIsEmpty) { + track.currentFragmentState.defaultSampleDuration = 0; + } + } + break; + case "tfdt": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(track.currentFragmentState); + const version = readU8(slice); + slice.skip(3); + const baseMediaDecodeTime = version === 0 ? readU32Be(slice) : readU64Be(slice); + track.currentFragmentState.startTimestamp = baseMediaDecodeTime; + } + break; + case "trun": + { + const track = this.currentTrack; + if (!track) { + break; + } + assert(this.currentFragment); + assert(track.currentFragmentState); + const version = readU8(slice); + const flags = readU24Be(slice); + const dataOffsetPresent = Boolean(flags & 1); + const firstSampleFlagsPresent = Boolean(flags & 4); + const sampleDurationPresent = Boolean(flags & 256); + const sampleSizePresent = Boolean(flags & 512); + const sampleFlagsPresent = Boolean(flags & 1024); + const sampleCompositionTimeOffsetsPresent = Boolean(flags & 2048); + const sampleCount = readU32Be(slice); + let dataOffset = null; + if (dataOffsetPresent) { + dataOffset = readI32Be(slice); + } + let firstSampleFlags = null; + if (firstSampleFlagsPresent) { + firstSampleFlags = readU32Be(slice); + } + let trackData; + if (this.currentFragment.trackData.has(track.id)) { + trackData = this.currentFragment.trackData.get(track.id); + if (dataOffset !== null) { + trackData.currentOffset = track.currentFragmentState.baseDataOffset + dataOffset; + } + } else { + trackData = { + track, + currentTimestamp: 0, + currentOffset: track.currentFragmentState.baseDataOffset + (dataOffset ?? 0), + startTimestamp: 0, + endTimestamp: 0, + firstKeyFrameTimestamp: null, + samples: [], + presentationTimestamps: [], + startTimestampIsFinal: false, + encryptionAuxInfo: null + }; + this.currentFragment.trackData.set(track.id, trackData); + } + if (sampleCount === 0) { + this.currentFragment.implicitBaseDataOffset = trackData.currentOffset; + break; + } + for (let i = 0; i < sampleCount; i++) { + let sampleDuration; + if (sampleDurationPresent) { + sampleDuration = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleDuration !== null); + sampleDuration = track.currentFragmentState.defaultSampleDuration; + } + let sampleSize; + if (sampleSizePresent) { + sampleSize = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleSize !== null); + sampleSize = track.currentFragmentState.defaultSampleSize; + } + let sampleFlags; + if (sampleFlagsPresent) { + sampleFlags = readU32Be(slice); + } else { + assert(track.currentFragmentState.defaultSampleFlags !== null); + sampleFlags = track.currentFragmentState.defaultSampleFlags; + } + if (i === 0 && firstSampleFlags !== null) { + sampleFlags = firstSampleFlags; + } + let sampleCompositionTimeOffset = 0; + if (sampleCompositionTimeOffsetsPresent) { + if (version === 0) { + sampleCompositionTimeOffset = readU32Be(slice); + } else { + sampleCompositionTimeOffset = readI32Be(slice); + } + } + const isKeyFrame = !(sampleFlags & 65536); + trackData.samples.push({ + presentationTimestamp: trackData.currentTimestamp + sampleCompositionTimeOffset, + duration: sampleDuration, + byteOffset: trackData.currentOffset, + byteSize: sampleSize, + isKeyFrame, + encryption: null + }); + trackData.currentOffset += sampleSize; + trackData.currentTimestamp += sampleDuration; + } + } + break; + case "saiz": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + slice.skip(1); + const flags = readU24Be(slice); + if (flags & 1) { + const auxInfoType = readAscii(slice, 4); + const auxInfoTypeParam = readU32Be(slice); + if (auxInfoType !== track.encryptionInfo.scheme || auxInfoTypeParam !== 0) { + break; + } + } + const defaultSampleInfoSize = readU8(slice); + const sampleCount = readU32Be(slice); + let sampleSizes = null; + if (defaultSampleInfoSize === 0 && sampleCount > 0) { + sampleSizes = readBytes(slice, sampleCount); + } + const aux = getOrCreateEncryptionAuxInfo(track); + aux.defaultSampleInfoSize = defaultSampleInfoSize; + aux.sampleSizes = sampleSizes; + aux.sampleCount = sampleCount; + } + break; + case "saio": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + const version = readU8(slice); + const flags = readU24Be(slice); + if (flags & 1) { + const auxInfoType = readAscii(slice, 4); + const auxInfoTypeParam = readU32Be(slice); + if (auxInfoType !== track.encryptionInfo.scheme || auxInfoTypeParam !== 0) { + break; + } + } + const entryCount = readU32Be(slice); + if (entryCount === 0) { + break; + } + if (entryCount > 1) { + console.warn("Multiple saio entries are not supported; using the first offset only."); + } + let offset = version === 0 ? readU32Be(slice) : Number(readU64Be(slice)); + if (this.currentFragment) { + offset += this.currentFragment.moofOffset; + } + const aux = getOrCreateEncryptionAuxInfo(track); + aux.offset = offset; + } + break; + case "senc": + { + const track = this.currentTrack; + if (!track || !track.encryptionInfo) { + break; + } + assert(this.currentFragment); + const trackData = this.currentFragment.trackData.get(track.id); + if (!trackData) { + break; + } + slice.skip(1); + const flags = readU24Be(slice); + const useSubsamples = Boolean(flags & 2); + const sampleCount = readU32Be(slice); + const ivSize = track.encryptionInfo.defaultPerSampleIvSize; + assert(ivSize !== null); + for (let i = 0; i < Math.min(sampleCount, trackData.samples.length); i++) { + const iv = new Uint8Array(16); + if (ivSize > 0) { + iv.set(readBytes(slice, ivSize), 0); + } else { + iv.set(track.encryptionInfo.defaultConstantIv, 0); + } + let subsamples = null; + if (useSubsamples) { + const subsampleCount = readU16Be(slice); + subsamples = []; + for (let j = 0; j < subsampleCount; j++) { + const clearLen = readU16Be(slice); + const protectedLen = readU32Be(slice); + subsamples.push({ clearLen, protectedLen }); + } + } + const sample = trackData.samples[i]; + sample.encryption = { iv, subsamples }; + } + } + break; + // Metadata section + // https://exiftool.org/TagNames/QuickTime.html + // https://mp4workshop.com/about + case "udta": + { + const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { + if (boxInfo2.name !== "meta" && !this.currentTrack) { + const startPos2 = slice2.filePos; + (_a = this.metadataTags).raw ?? (_a.raw = {}); + if (boxInfo2.name[0] === "©") { + (_b = this.metadataTags.raw)[_c = boxInfo2.name] ?? (_b[_c] = readMetadataStringShort(slice2)); + } else { + (_d = this.metadataTags.raw)[_e = boxInfo2.name] ?? (_d[_e] = readBytes(slice2, boxInfo2.contentSize)); + } + slice2.filePos = startPos2; + } + switch (boxInfo2.name) { + case "meta": + { + slice2.skip(-boxInfo2.headerSize); + this.traverseBox(slice2); + } + break; + case "©nam": + case "name": + { + if (this.currentTrack) { + this.currentTrack.name = textDecoder.decode(readBytes(slice2, boxInfo2.contentSize)); + } else { + (_f = this.metadataTags).title ?? (_f.title = readMetadataStringShort(slice2)); + } + } + break; + case "©des": + { + if (!this.currentTrack) { + (_g = this.metadataTags).description ?? (_g.description = readMetadataStringShort(slice2)); + } + } + break; + case "©ART": + { + if (!this.currentTrack) { + (_h = this.metadataTags).artist ?? (_h.artist = readMetadataStringShort(slice2)); + } + } + break; + case "©alb": + { + if (!this.currentTrack) { + (_i = this.metadataTags).album ?? (_i.album = readMetadataStringShort(slice2)); + } + } + break; + case "albr": + { + if (!this.currentTrack) { + (_j = this.metadataTags).albumArtist ?? (_j.albumArtist = readMetadataStringShort(slice2)); + } + } + break; + case "©gen": + { + if (!this.currentTrack) { + (_k = this.metadataTags).genre ?? (_k.genre = readMetadataStringShort(slice2)); + } + } + break; + case "©day": + { + if (!this.currentTrack) { + const date = new Date(readMetadataStringShort(slice2)); + if (!Number.isNaN(date.getTime())) { + (_l = this.metadataTags).date ?? (_l.date = date); + } + } + } + break; + case "©cmt": + { + if (!this.currentTrack) { + (_m = this.metadataTags).comment ?? (_m.comment = readMetadataStringShort(slice2)); + } + } + break; + case "©lyr": + { + if (!this.currentTrack) { + (_n = this.metadataTags).lyrics ?? (_n.lyrics = readMetadataStringShort(slice2)); + } + } + break; + } + } + } + break; + case "meta": + { + if (this.currentTrack) { + break; + } + const word = readU32Be(slice); + const isQuickTime = word !== 0; + this.currentMetadataKeys = /* @__PURE__ */ new Map(); + if (isQuickTime) { + this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + } else { + this.readContiguousBoxes(slice.slice(contentStartPos + 4, boxInfo.contentSize - 4)); + } + this.currentMetadataKeys = null; + } + break; + case "keys": + { + if (!this.currentMetadataKeys) { + break; + } + slice.skip(4); + const entryCount = readU32Be(slice); + for (let i = 0; i < entryCount; i++) { + const keySize = readU32Be(slice); + slice.skip(4); + const keyName = textDecoder.decode(readBytes(slice, keySize - 8)); + this.currentMetadataKeys.set(i + 1, keyName); + } + } + break; + case "ilst": + { + if (!this.currentMetadataKeys) { + break; + } + const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); + for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { + let metadataKey = boxInfo2.name; + const nameAsNumber = (metadataKey.charCodeAt(0) << 24) + (metadataKey.charCodeAt(1) << 16) + (metadataKey.charCodeAt(2) << 8) + metadataKey.charCodeAt(3); + if (this.currentMetadataKeys.has(nameAsNumber)) { + metadataKey = this.currentMetadataKeys.get(nameAsNumber); + } + const data = readDataBox(slice2); + (_o = this.metadataTags).raw ?? (_o.raw = {}); + (_p = this.metadataTags.raw)[metadataKey] ?? (_p[metadataKey] = data); + switch (metadataKey) { + case "©nam": + case "titl": + case "com.apple.quicktime.title": + case "title": + { + if (typeof data === "string") { + (_q = this.metadataTags).title ?? (_q.title = data); + } + } + break; + case "©des": + case "desc": + case "dscp": + case "com.apple.quicktime.description": + case "description": + { + if (typeof data === "string") { + (_r = this.metadataTags).description ?? (_r.description = data); + } + } + break; + case "©ART": + case "com.apple.quicktime.artist": + case "artist": + { + if (typeof data === "string") { + (_s = this.metadataTags).artist ?? (_s.artist = data); + } + } + break; + case "©alb": + case "albm": + case "com.apple.quicktime.album": + case "album": + { + if (typeof data === "string") { + (_t = this.metadataTags).album ?? (_t.album = data); + } + } + break; + case "aART": + case "album_artist": + { + if (typeof data === "string") { + (_u = this.metadataTags).albumArtist ?? (_u.albumArtist = data); + } + } + break; + case "©cmt": + case "com.apple.quicktime.comment": + case "comment": + { + if (typeof data === "string") { + (_v = this.metadataTags).comment ?? (_v.comment = data); + } + } + break; + case "©gen": + case "gnre": + case "com.apple.quicktime.genre": + case "genre": + { + if (typeof data === "string") { + (_w = this.metadataTags).genre ?? (_w.genre = data); + } + } + break; + case "©lyr": + case "lyrics": + { + if (typeof data === "string") { + (_x = this.metadataTags).lyrics ?? (_x.lyrics = data); + } + } + break; + case "©day": + case "rldt": + case "com.apple.quicktime.creationdate": + case "date": + { + if (typeof data === "string") { + const date = new Date(data); + if (!Number.isNaN(date.getTime())) { + (_y = this.metadataTags).date ?? (_y.date = date); + } + } + } + break; + case "covr": + case "com.apple.quicktime.artwork": + { + if (data instanceof RichImageData) { + (_z = this.metadataTags).images ?? (_z.images = []); + this.metadataTags.images.push({ + data: data.data, + kind: "coverFront", + mimeType: data.mimeType + }); + } else if (data instanceof Uint8Array) { + (_A = this.metadataTags).images ?? (_A.images = []); + this.metadataTags.images.push({ + data, + kind: "coverFront", + mimeType: "image/*" + }); + } + } + break; + case "track": + { + if (typeof data === "string") { + const parts = data.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + (_B = this.metadataTags).trackNumber ?? (_B.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + (_C = this.metadataTags).tracksTotal ?? (_C.tracksTotal = tracksTotal); + } + } + } + break; + case "trkn": + { + if (data instanceof Uint8Array && data.length >= 6) { + const view = toDataView(data); + const trackNumber = view.getUint16(2, false); + const tracksTotal = view.getUint16(4, false); + if (trackNumber > 0) { + (_D = this.metadataTags).trackNumber ?? (_D.trackNumber = trackNumber); + } + if (tracksTotal > 0) { + (_E = this.metadataTags).tracksTotal ?? (_E.tracksTotal = tracksTotal); + } + } + } + break; + case "disc": + case "disk": + { + if (data instanceof Uint8Array && data.length >= 6) { + const view = toDataView(data); + const discNumber = view.getUint16(2, false); + const discNumberMax = view.getUint16(4, false); + if (discNumber > 0) { + (_F = this.metadataTags).discNumber ?? (_F.discNumber = discNumber); + } + if (discNumberMax > 0) { + (_G = this.metadataTags).discsTotal ?? (_G.discsTotal = discNumberMax); + } + } + } + break; + } + } + } + break; + } + slice.filePos = boxEndPos; + return true; + } +} +class IsobmffTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.packetToSampleIndex = /* @__PURE__ */ new WeakMap(); + this.packetToFragmentLocation = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.internalTrack.id; + } + getNumber() { + const demuxer = this.internalTrack.demuxer; + const trackType = this.internalTrack.trackBacking.getType(); + let number = 0; + for (const track of demuxer.tracks) { + if (track.trackBacking.getType() === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.internalTrack.internalCodecId; + } + getName() { + return this.internalTrack.name; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getTimeResolution() { + return this.internalTrack.timescale; + } + isRelativeToUnixEpoch() { + return false; + } + getDisposition() { + return this.internalTrack.disposition; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const track = this.internalTrack; + if (track.durationInMediaTimescale <= 0) { + return null; + } + assert(track.trackBacking); + const firstPacket = await track.trackBacking.getFirstPacket({ metadataOnly: true }); + return (firstPacket?.timestamp ?? 0) + track.durationInMediaTimescale / track.timescale; + } + async getLiveRefreshInterval() { + return null; + } + async getFirstPacket(options) { + const regularPacket = await this.fetchPacketForSampleIndex(0, options); + if (regularPacket || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup( + null, + (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData) { + return { + sampleIndex: 0, + correctSampleFound: true + }; + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + mapTimestampIntoTimescale(timestamp) { + return roundIfAlmostInteger(timestamp * this.internalTrack.timescale) + this.internalTrack.editListOffset; + } + async getPacket(timestamp, options) { + const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); + const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); + if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup(null, (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (!trackData) { + return { sampleIndex: -1, correctSampleFound: false }; + } + const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.presentationTimestamp); + const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; + const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { sampleIndex: sampleIndex2, correctSampleFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextPacket(packet, options) { + const regularSampleIndex = this.packetToSampleIndex.get(packet); + if (regularSampleIndex !== void 0) { + return this.fetchPacketForSampleIndex(regularSampleIndex + 1, options); + } + const locationInFragment = this.packetToFragmentLocation.get(packet); + if (locationInFragment === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performFragmentedLookup( + locationInFragment.fragment, + (fragment) => { + if (fragment === locationInFragment.fragment) { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (locationInFragment.sampleIndex + 1 < trackData.samples.length) { + return { + sampleIndex: locationInFragment.sampleIndex + 1, + correctSampleFound: true + }; + } + } else { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData) { + return { + sampleIndex: 0, + correctSampleFound: true + }; + } + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + async getKeyPacket(timestamp, options) { + const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleIndex = getKeyframeSampleIndexForTimestamp(sampleTable, timestampInTimescale); + const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); + if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { + return regularPacket; + } + return this.performFragmentedLookup(null, (fragment) => { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (!trackData) { + return { sampleIndex: -1, correctSampleFound: false }; + } + const index = findLastIndex(trackData.presentationTimestamps, (x) => { + const sample = trackData.samples[x.sampleIndex]; + return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; + }); + const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; + const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { sampleIndex: sampleIndex2, correctSampleFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextKeyPacket(packet, options) { + const regularSampleIndex = this.packetToSampleIndex.get(packet); + if (regularSampleIndex !== void 0) { + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, regularSampleIndex); + return this.fetchPacketForSampleIndex(nextKeyFrameSampleIndex, options); + } + const locationInFragment = this.packetToFragmentLocation.get(packet); + if (locationInFragment === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performFragmentedLookup( + locationInFragment.fragment, + (fragment) => { + if (fragment === locationInFragment.fragment) { + const trackData = fragment.trackData.get(this.internalTrack.id); + const nextKeyFrameIndex = trackData.samples.findIndex((x, i) => x.isKeyFrame && i > locationInFragment.sampleIndex); + if (nextKeyFrameIndex !== -1) { + return { + sampleIndex: nextKeyFrameIndex, + correctSampleFound: true + }; + } + } else { + const trackData = fragment.trackData.get(this.internalTrack.id); + if (trackData && trackData.firstKeyFrameTimestamp !== null) { + const keyFrameIndex = trackData.samples.findIndex((x) => x.isKeyFrame); + assert(keyFrameIndex !== -1); + return { + sampleIndex: keyFrameIndex, + correctSampleFound: true + }; + } + } + return { + sampleIndex: -1, + correctSampleFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the lookup entries + Infinity, + options + ); + } + async fetchPacketForSampleIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); + const sampleInfo = getSampleInfo(sampleTable, sampleIndex); + if (!sampleInfo) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.internalTrack.demuxer.reader.requestSlice(sampleInfo.sampleOffset, sampleInfo.sampleSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, sampleInfo.sampleSize); + if (this.internalTrack.encryptionAuxInfo) { + assert(this.internalTrack.encryptionInfo); + const entries = await resolveEncryptionAuxInfo(this.internalTrack.demuxer.reader, this.internalTrack.encryptionInfo, this.internalTrack.encryptionAuxInfo); + if (sampleIndex < entries.length) { + data = await decryptSample(this.internalTrack, entries[sampleIndex], data, null); + } + } + } + const timestamp = (sampleInfo.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; + const duration = sampleInfo.duration / this.internalTrack.timescale; + const packet = new EncodedPacket(data, sampleInfo.isKeyFrame ? "key" : "delta", timestamp, duration, sampleIndex, sampleInfo.sampleSize); + this.packetToSampleIndex.set(packet, sampleIndex); + return packet; + } + async fetchPacketInFragment(fragment, sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const trackData = fragment.trackData.get(this.internalTrack.id); + const fragmentSample = trackData.samples[sampleIndex]; + assert(fragmentSample); + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.internalTrack.demuxer.reader.requestSlice(fragmentSample.byteOffset, fragmentSample.byteSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, fragmentSample.byteSize); + if (fragmentSample.encryption) { + data = await decryptSample(this.internalTrack, fragmentSample.encryption, data, fragment); + } + } + const timestamp = (fragmentSample.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; + const duration = fragmentSample.duration / this.internalTrack.timescale; + const packet = new EncodedPacket(data, fragmentSample.isKeyFrame ? "key" : "delta", timestamp, duration, fragment.moofOffset + sampleIndex, fragmentSample.byteSize); + this.packetToFragmentLocation.set(packet, { fragment, sampleIndex }); + return packet; + } + /** Looks for a packet in the fragments while trying to load as few fragments as possible to retrieve it. */ + async performFragmentedLookup(startFragment, getMatchInFragment, searchTimestamp, latestTimestamp, options) { + const demuxer = this.internalTrack.demuxer; + let currentFragment = null; + let bestFragment = null; + let bestSampleIndex = -1; + if (startFragment) { + const { sampleIndex, correctSampleFound } = getMatchInFragment(startFragment); + if (correctSampleFound) { + return this.fetchPacketInFragment(startFragment, sampleIndex, options); + } + if (sampleIndex !== -1) { + bestFragment = startFragment; + bestSampleIndex = sampleIndex; + } + } + const lookupEntryIndex = binarySearchLessOrEqual(this.internalTrack.fragmentLookupTable, searchTimestamp, (x) => x.timestamp); + const lookupEntry = lookupEntryIndex !== -1 ? this.internalTrack.fragmentLookupTable[lookupEntryIndex] : null; + const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.fragmentPositionCache, searchTimestamp, (x) => x.startTimestamp); + const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.fragmentPositionCache[positionCacheIndex] : null; + const lookupEntryPosition = Math.max(lookupEntry?.moofOffset ?? 0, positionCacheEntry?.moofOffset ?? 0) || null; + let currentPos; + if (!startFragment) { + currentPos = lookupEntryPosition ?? 0; + } else { + if (lookupEntryPosition === null || startFragment.moofOffset >= lookupEntryPosition) { + currentPos = startFragment.moofOffset + startFragment.moofSize; + currentFragment = startFragment; + } else { + currentPos = lookupEntryPosition; + } + } + while (true) { + if (currentFragment) { + const trackData = currentFragment.trackData.get(this.internalTrack.id); + if (trackData && trackData.startTimestamp > latestTimestamp) { + break; + } + } + let slice = demuxer.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const boxStartPos = currentPos; + const boxInfo = readBoxHeader(slice); + if (!boxInfo) { + break; + } + if (boxInfo.name === "moof") { + currentFragment = await demuxer.readFragment(boxStartPos); + const { sampleIndex, correctSampleFound } = getMatchInFragment(currentFragment); + if (correctSampleFound) { + return this.fetchPacketInFragment(currentFragment, sampleIndex, options); + } + if (sampleIndex !== -1) { + bestFragment = currentFragment; + bestSampleIndex = sampleIndex; + } + } + currentPos = boxStartPos + boxInfo.totalSize; + } + if (lookupEntry && (!bestFragment || bestFragment.moofOffset < lookupEntry.moofOffset)) { + const previousLookupEntry = this.internalTrack.fragmentLookupTable[lookupEntryIndex - 1]; + assert(!previousLookupEntry || previousLookupEntry.timestamp < lookupEntry.timestamp); + const newSearchTimestamp = previousLookupEntry?.timestamp ?? -Infinity; + return this.performFragmentedLookup(null, getMatchInFragment, newSearchTimestamp, latestTimestamp, options); + } + if (bestFragment) { + return this.fetchPacketInFragment(bestFragment, bestSampleIndex, options); + } + return null; + } +} +class IsobmffVideoTrackBacking extends IsobmffTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfigPromise = null; + this.internalTrack = internalTrack; + } + getType() { + return "video"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getCodedWidth() { + return this.internalTrack.info.width; + } + getCodedHeight() { + return this.internalTrack.info.height; + } + getSquarePixelWidth() { + return this.internalTrack.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.internalTrack.info.squarePixelHeight; + } + getRotation() { + return this.internalTrack.rotation; + } + async getColorSpace() { + return { + primaries: this.internalTrack.info.colorSpace?.primaries, + transfer: this.internalTrack.info.colorSpace?.transfer, + matrix: this.internalTrack.info.colorSpace?.matrix, + fullRange: this.internalTrack.info.colorSpace?.fullRange + }; + } + async canBeTransparent() { + return false; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { + if (this.internalTrack.info.codec === "vp9" && !this.internalTrack.info.vp9CodecInfo) { + const firstPacket = await this.getFirstPacket({}); + this.internalTrack.info.vp9CodecInfo = firstPacket && extractVp9CodecInfoFromPacket(firstPacket.data); + } else if (this.internalTrack.info.codec === "av1" && !this.internalTrack.info.av1CodecInfo) { + const firstPacket = await this.getFirstPacket({}); + this.internalTrack.info.av1CodecInfo = firstPacket && extractAv1CodecInfoFromPacket(firstPacket.data); + } + const config = { + codec: extractVideoCodecString(this.internalTrack.info), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? void 0, + colorSpace: this.internalTrack.info.colorSpace ?? void 0 + }; + if (this.internalTrack.info.width !== this.internalTrack.info.squarePixelWidth || this.internalTrack.info.height !== this.internalTrack.info.squarePixelHeight) { + config.displayAspectWidth = this.internalTrack.info.squarePixelWidth; + config.displayAspectHeight = this.internalTrack.info.squarePixelHeight; + } + return config; + })()); + } +} +class IsobmffAudioTrackBacking extends IsobmffTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfig = null; + this.internalTrack = internalTrack; + } + getType() { + return "audio"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getNumberOfChannels() { + return this.internalTrack.info.numberOfChannels; + } + getSampleRate() { + return this.internalTrack.info.sampleRate; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfig ?? (this.decoderConfig = { + codec: extractAudioCodecString(this.internalTrack.info), + numberOfChannels: this.internalTrack.info.numberOfChannels, + sampleRate: this.internalTrack.info.sampleRate, + description: this.internalTrack.info.codecDescription ?? void 0 + }); + } +} +const getSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { + if (sampleTable.presentationTimestamps) { + const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); + if (index === -1) { + return -1; + } + return sampleTable.presentationTimestamps[index].sampleIndex; } else { - decoded = number << 1 | 1; + const index = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, timescaleUnits, (x) => x.startDecodeTimestamp); + if (index === -1) { + return -1; + } + const entry = sampleTable.sampleTimingEntries[index]; + return entry.startIndex + Math.min(Math.floor((timescaleUnits - entry.startDecodeTimestamp) / entry.delta), entry.count - 1); + } +}; +const getKeyframeSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { + if (!sampleTable.keySampleIndices) { + return getSampleIndexForTimestamp(sampleTable, timescaleUnits); + } + if (sampleTable.presentationTimestamps) { + const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); + if (index === -1) { + return -1; + } + for (let i = index; i >= 0; i--) { + const sampleIndex = sampleTable.presentationTimestamps[i].sampleIndex; + const isKeyFrame = binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1; + if (isKeyFrame) { + return sampleIndex; + } + } + return -1; + } else { + const sampleIndex = getSampleIndexForTimestamp(sampleTable, timescaleUnits); + const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); + return sampleTable.keySampleIndices[index] ?? -1; + } +}; +const getSampleInfo = (sampleTable, sampleIndex) => { + const timingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, sampleIndex, (x) => x.startIndex); + const timingEntry = sampleTable.sampleTimingEntries[timingEntryIndex]; + if (!timingEntry || timingEntry.startIndex + timingEntry.count <= sampleIndex) { + return null; + } + const decodeTimestamp = timingEntry.startDecodeTimestamp + (sampleIndex - timingEntry.startIndex) * timingEntry.delta; + let presentationTimestamp = decodeTimestamp; + const offsetEntryIndex = binarySearchLessOrEqual(sampleTable.sampleCompositionTimeOffsets, sampleIndex, (x) => x.startIndex); + const offsetEntry = sampleTable.sampleCompositionTimeOffsets[offsetEntryIndex]; + if (offsetEntry && sampleIndex - offsetEntry.startIndex < offsetEntry.count) { + presentationTimestamp += offsetEntry.offset; + } + const sampleSize = sampleTable.sampleSizes[Math.min(sampleIndex, sampleTable.sampleSizes.length - 1)]; + const chunkEntryIndex = binarySearchLessOrEqual(sampleTable.sampleToChunk, sampleIndex, (x) => x.startSampleIndex); + const chunkEntry = sampleTable.sampleToChunk[chunkEntryIndex]; + assert(chunkEntry); + const chunkIndex = chunkEntry.startChunkIndex + Math.floor((sampleIndex - chunkEntry.startSampleIndex) / chunkEntry.samplesPerChunk); + const chunkOffset = sampleTable.chunkOffsets[chunkIndex]; + const startSampleIndexOfChunk = chunkEntry.startSampleIndex + (chunkIndex - chunkEntry.startChunkIndex) * chunkEntry.samplesPerChunk; + let chunkSize = 0; + let sampleOffset = chunkOffset; + if (sampleTable.sampleSizes.length === 1) { + sampleOffset += sampleSize * (sampleIndex - startSampleIndexOfChunk); + chunkSize += sampleSize * chunkEntry.samplesPerChunk; + } else { + for (let i = startSampleIndexOfChunk; i < startSampleIndexOfChunk + chunkEntry.samplesPerChunk; i++) { + const sampleSize2 = sampleTable.sampleSizes[i]; + if (i < sampleIndex) { + sampleOffset += sampleSize2; + } + chunkSize += sampleSize2; + } + } + let duration = timingEntry.delta; + if (sampleTable.presentationTimestamps) { + const presentationIndex = sampleTable.presentationTimestampIndexMap[sampleIndex]; + assert(presentationIndex !== void 0); + if (presentationIndex < sampleTable.presentationTimestamps.length - 1) { + const nextEntry = sampleTable.presentationTimestamps[presentationIndex + 1]; + const nextPresentationTimestamp = nextEntry.presentationTimestamp; + duration = nextPresentationTimestamp - presentationTimestamp; + } + } + return { + presentationTimestamp, + duration, + sampleOffset, + sampleSize, + chunkOffset, + chunkSize, + isKeyFrame: sampleTable.keySampleIndices ? binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1 : true + }; +}; +const getNextKeyframeIndexForSample = (sampleTable, sampleIndex) => { + if (!sampleTable.keySampleIndices) { + return sampleIndex + 1; + } + const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); + return sampleTable.keySampleIndices[index + 1] ?? -1; +}; +const offsetFragmentTrackDataByTimestamp = (trackData, timestamp) => { + trackData.startTimestamp += timestamp; + trackData.endTimestamp += timestamp; + for (const sample of trackData.samples) { + sample.presentationTimestamp += timestamp; + } + for (const entry of trackData.presentationTimestamps) { + entry.presentationTimestamp += timestamp; + } +}; +const extractRotationFromMatrix = (matrix) => { + const [a, b] = matrix; + const radians = Math.atan2(b, a); + if (!Number.isFinite(radians)) { + return 0; + } + return radians * (180 / Math.PI); +}; +const sampleTableIsEmpty = (sampleTable) => { + return sampleTable.sampleSizes.length === 0; +}; +const getOrCreateEncryptionAuxInfo = (track) => { + var _a; + if (track.currentFragmentState) { + return (_a = track.currentFragmentState).encryptionAuxInfo ?? (_a.encryptionAuxInfo = { + defaultSampleInfoSize: 0, + sampleSizes: null, + sampleCount: 0, + offset: null, + resolved: null + }); + } else { + return track.encryptionAuxInfo ?? (track.encryptionAuxInfo = { + defaultSampleInfoSize: 0, + sampleSizes: null, + sampleCount: 0, + offset: null, + resolved: null + }); + } +}; +const resolveEncryptionAuxInfo = async (reader, encryptionInfo, aux) => { + if (aux.resolved) { + return aux.resolved; + } + if (aux.offset === null || aux.sampleCount === 0) { + throw new Error("Incomplete saiz/saio info; cannot resolve encryption data."); + } + let totalSize = 0; + if (aux.defaultSampleInfoSize > 0) { + totalSize = aux.defaultSampleInfoSize * aux.sampleCount; + } else { + assert(aux.sampleSizes); + for (let i = 0; i < aux.sampleCount; i++) { + totalSize += aux.sampleSizes[i]; + } + } + let slice = reader.requestSlice(aux.offset, totalSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + throw new Error("Failed to read auxiliary encryption info."); + } + const ivSize = encryptionInfo.defaultPerSampleIvSize; + assert(ivSize !== null); + const entries = []; + for (let i = 0; i < aux.sampleCount; i++) { + const entrySize = aux.defaultSampleInfoSize > 0 ? aux.defaultSampleInfoSize : aux.sampleSizes[i]; + const iv = new Uint8Array(16); + if (ivSize > 0) { + iv.set(readBytes(slice, ivSize), 0); + } else { + iv.set(encryptionInfo.defaultConstantIv, 0); + } + let subsamples = null; + if (entrySize > ivSize) { + const subsampleCount = readU16Be(slice); + subsamples = []; + for (let j = 0; j < subsampleCount; j++) { + const clearLen = readU16Be(slice); + const protectedLen = readU32Be(slice); + subsamples.push({ clearLen, protectedLen }); + } + } + entries.push({ iv, subsamples }); + } + aux.resolved = entries; + return entries; +}; +const decryptSample = async (track, sampleEncryption, data, fragment) => { + assert(track.encryptionInfo); + const encryptionInfo = track.encryptionInfo; + assert(encryptionInfo.defaultKid !== null); + const keyId = encryptionInfo.defaultKid; + let keyBytes; + const cacheEntry = track.demuxer.decryptionKeyCache.get(keyId); + if (cacheEntry) { + keyBytes = await cacheEntry; + } else { + if (!track.demuxer.input._formatOptions.isobmff?.resolveKeyId) { + throw new Error("Encrypted media samples encountered. To decrypt them, please provide a callback for InputOptions.formatOptions.isobmff.resolveKeyId."); + } + const promise = (async () => { + let psshBoxes = track.demuxer.psshBoxes; + if (fragment) { + psshBoxes = [ + ...psshBoxes, + ...fragment.psshBoxes + ].filter((x) => x.keyIds === null || x.keyIds.includes(keyId)); + for (let i = 0; i < psshBoxes.length - 1; i++) { + for (let j = i + 1; j < psshBoxes.length; j++) { + if (psshBoxesAreEqual(psshBoxes[i], psshBoxes[j])) { + psshBoxes.splice(j, 1); + j--; + } + } + } + } + const keyResult = await track.demuxer.input._formatOptions.isobmff.resolveKeyId({ keyId, psshBoxes }); + if (!(typeof keyResult === "string" && keyResult.length === 32 && HEX_STRING_REGEX.test(keyResult) || keyResult instanceof Uint8Array && keyResult.byteLength === 16)) { + throw new TypeError("resolveKeyId must return a 32-character hex string or a 16-byte Uint8Array containing the decryption key."); + } + return keyResult instanceof Uint8Array ? keyResult : hexStringToBytes(keyResult); + })(); + track.demuxer.decryptionKeyCache.set(keyId, promise); + keyBytes = await promise; + } + if (encryptionInfo.scheme === "cenc" || encryptionInfo.scheme === "cens") { + return decryptCtr(keyBytes, encryptionInfo, sampleEncryption, data); + } else { + return decryptCbcs(keyBytes, encryptionInfo, sampleEncryption, data); + } +}; +const decryptCtr = async (key, encryptionInfo, sampleEncryption, data) => { + const counter = new Uint8Array(16); + counter.set(sampleEncryption.iv, 0); + const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "AES-CTR" }, false, ["decrypt"]); + const cryptApply = async (input) => { + const plaintext = await crypto.subtle.decrypt({ name: "AES-CTR", counter, length: 64 }, cryptoKey, input); + return new Uint8Array(plaintext); + }; + if (!sampleEncryption.subsamples) { + return cryptApply(data); + } + assert(encryptionInfo.defaultCryptByteBlock !== null && encryptionInfo.defaultSkipByteBlock !== null); + const cryptRanges = collectCryptRanges(sampleEncryption.subsamples, encryptionInfo.defaultCryptByteBlock, encryptionInfo.defaultSkipByteBlock); + let totalCryptLen = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + totalCryptLen += seg.length; + } + } + const cryptBuffer = new Uint8Array(totalCryptLen); + let writePos = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + cryptBuffer.set(data.subarray(seg.offset, seg.offset + seg.length), writePos); + writePos += seg.length; + } + } + const plain = await cryptApply(cryptBuffer); + const output = new Uint8Array(data); + let readPos = 0; + for (const range of cryptRanges) { + for (const seg of range.perSubsample) { + output.set(plain.subarray(readPos, readPos + seg.length), seg.offset); + readPos += seg.length; + } + } + return output; +}; +const decryptCbcs = (key, encryptionInfo, sampleEncryption, data) => { + const ctx = new Aes128CbcContext(); + ctx.init({ key, iv: sampleEncryption.iv }); + const cryptByteBlock = encryptionInfo.defaultCryptByteBlock; + const skipByteBlock = encryptionInfo.defaultSkipByteBlock; + assert(cryptByteBlock !== null && skipByteBlock !== null); + if (!sampleEncryption.subsamples) { + const output2 = new Uint8Array(data); + const numBlocks = Math.floor(data.length / 16); + for (let b = 0; b < numBlocks; b++) { + const off = b * 16; + ctx.in.set(data.subarray(off, off + 16)); + ctx.decrypt(); + output2.set(ctx.out, off); + } + return output2; + } + if (cryptByteBlock === 0 && skipByteBlock === 0) { + throw new Error("cbcs with subsamples requires pattern encryption."); + } + const output = new Uint8Array(data); + const cryptRanges = collectCryptRanges(sampleEncryption.subsamples, cryptByteBlock, skipByteBlock); + const ivView = new DataView(sampleEncryption.iv.buffer, sampleEncryption.iv.byteOffset, 16); + for (const range of cryptRanges) { + ctx.iv[0] = ivView.getUint32(0, false); + ctx.iv[1] = ivView.getUint32(4, false); + ctx.iv[2] = ivView.getUint32(8, false); + ctx.iv[3] = ivView.getUint32(12, false); + for (const seg of range.perSubsample) { + const numBlocks = seg.length / 16; + for (let b = 0; b < numBlocks; b++) { + const offset = seg.offset + b * 16; + ctx.in.set(data.subarray(offset, offset + 16)); + ctx.decrypt(); + output.set(ctx.out, offset); + } + } + } + return output; +}; +const collectCryptRanges = (subsamples, cryptByteBlock, skipByteBlock) => { + const ranges = []; + const hasPattern = cryptByteBlock !== 0 || skipByteBlock !== 0; + let cursor = 0; + for (const subsample of subsamples) { + cursor += subsample.clearLen; + const perSubsample = []; + if (!hasPattern) { + if (subsample.protectedLen > 0) { + perSubsample.push({ offset: cursor, length: subsample.protectedLen }); + } + cursor += subsample.protectedLen; + } else { + let remaining = subsample.protectedLen; + let pos = cursor; + while (remaining > 0) { + if (remaining < 16 * cryptByteBlock) { + break; + } + const cryptBytes = 16 * cryptByteBlock; + perSubsample.push({ offset: pos, length: cryptBytes }); + pos += cryptBytes; + remaining -= cryptBytes; + const skipBytes = Math.min(16 * skipByteBlock, remaining); + pos += skipBytes; + remaining -= skipBytes; + } + cursor += subsample.protectedLen; + } + ranges.push({ perSubsample }); + } + return ranges; +}; +var EBMLId; +(function(EBMLId2) { + EBMLId2[EBMLId2["EBML"] = 440786851] = "EBML"; + EBMLId2[EBMLId2["EBMLVersion"] = 17030] = "EBMLVersion"; + EBMLId2[EBMLId2["EBMLReadVersion"] = 17143] = "EBMLReadVersion"; + EBMLId2[EBMLId2["EBMLMaxIDLength"] = 17138] = "EBMLMaxIDLength"; + EBMLId2[EBMLId2["EBMLMaxSizeLength"] = 17139] = "EBMLMaxSizeLength"; + EBMLId2[EBMLId2["DocType"] = 17026] = "DocType"; + EBMLId2[EBMLId2["DocTypeVersion"] = 17031] = "DocTypeVersion"; + EBMLId2[EBMLId2["DocTypeReadVersion"] = 17029] = "DocTypeReadVersion"; + EBMLId2[EBMLId2["Void"] = 236] = "Void"; + EBMLId2[EBMLId2["Segment"] = 408125543] = "Segment"; + EBMLId2[EBMLId2["SeekHead"] = 290298740] = "SeekHead"; + EBMLId2[EBMLId2["Seek"] = 19899] = "Seek"; + EBMLId2[EBMLId2["SeekID"] = 21419] = "SeekID"; + EBMLId2[EBMLId2["SeekPosition"] = 21420] = "SeekPosition"; + EBMLId2[EBMLId2["Duration"] = 17545] = "Duration"; + EBMLId2[EBMLId2["Info"] = 357149030] = "Info"; + EBMLId2[EBMLId2["TimestampScale"] = 2807729] = "TimestampScale"; + EBMLId2[EBMLId2["MuxingApp"] = 19840] = "MuxingApp"; + EBMLId2[EBMLId2["WritingApp"] = 22337] = "WritingApp"; + EBMLId2[EBMLId2["Tracks"] = 374648427] = "Tracks"; + EBMLId2[EBMLId2["TrackEntry"] = 174] = "TrackEntry"; + EBMLId2[EBMLId2["TrackNumber"] = 215] = "TrackNumber"; + EBMLId2[EBMLId2["TrackUID"] = 29637] = "TrackUID"; + EBMLId2[EBMLId2["TrackType"] = 131] = "TrackType"; + EBMLId2[EBMLId2["FlagEnabled"] = 185] = "FlagEnabled"; + EBMLId2[EBMLId2["FlagDefault"] = 136] = "FlagDefault"; + EBMLId2[EBMLId2["FlagForced"] = 21930] = "FlagForced"; + EBMLId2[EBMLId2["FlagOriginal"] = 21934] = "FlagOriginal"; + EBMLId2[EBMLId2["FlagHearingImpaired"] = 21931] = "FlagHearingImpaired"; + EBMLId2[EBMLId2["FlagVisualImpaired"] = 21932] = "FlagVisualImpaired"; + EBMLId2[EBMLId2["FlagCommentary"] = 21935] = "FlagCommentary"; + EBMLId2[EBMLId2["FlagLacing"] = 156] = "FlagLacing"; + EBMLId2[EBMLId2["Name"] = 21358] = "Name"; + EBMLId2[EBMLId2["Language"] = 2274716] = "Language"; + EBMLId2[EBMLId2["LanguageBCP47"] = 2274717] = "LanguageBCP47"; + EBMLId2[EBMLId2["CodecID"] = 134] = "CodecID"; + EBMLId2[EBMLId2["CodecPrivate"] = 25506] = "CodecPrivate"; + EBMLId2[EBMLId2["CodecDelay"] = 22186] = "CodecDelay"; + EBMLId2[EBMLId2["SeekPreRoll"] = 22203] = "SeekPreRoll"; + EBMLId2[EBMLId2["DefaultDuration"] = 2352003] = "DefaultDuration"; + EBMLId2[EBMLId2["Video"] = 224] = "Video"; + EBMLId2[EBMLId2["PixelWidth"] = 176] = "PixelWidth"; + EBMLId2[EBMLId2["PixelHeight"] = 186] = "PixelHeight"; + EBMLId2[EBMLId2["DisplayWidth"] = 21680] = "DisplayWidth"; + EBMLId2[EBMLId2["DisplayHeight"] = 21690] = "DisplayHeight"; + EBMLId2[EBMLId2["DisplayUnit"] = 21682] = "DisplayUnit"; + EBMLId2[EBMLId2["AlphaMode"] = 21440] = "AlphaMode"; + EBMLId2[EBMLId2["Audio"] = 225] = "Audio"; + EBMLId2[EBMLId2["SamplingFrequency"] = 181] = "SamplingFrequency"; + EBMLId2[EBMLId2["Channels"] = 159] = "Channels"; + EBMLId2[EBMLId2["BitDepth"] = 25188] = "BitDepth"; + EBMLId2[EBMLId2["SimpleBlock"] = 163] = "SimpleBlock"; + EBMLId2[EBMLId2["BlockGroup"] = 160] = "BlockGroup"; + EBMLId2[EBMLId2["Block"] = 161] = "Block"; + EBMLId2[EBMLId2["BlockAdditions"] = 30113] = "BlockAdditions"; + EBMLId2[EBMLId2["BlockMore"] = 166] = "BlockMore"; + EBMLId2[EBMLId2["BlockAdditional"] = 165] = "BlockAdditional"; + EBMLId2[EBMLId2["BlockAddID"] = 238] = "BlockAddID"; + EBMLId2[EBMLId2["BlockDuration"] = 155] = "BlockDuration"; + EBMLId2[EBMLId2["ReferenceBlock"] = 251] = "ReferenceBlock"; + EBMLId2[EBMLId2["Cluster"] = 524531317] = "Cluster"; + EBMLId2[EBMLId2["Timestamp"] = 231] = "Timestamp"; + EBMLId2[EBMLId2["Cues"] = 475249515] = "Cues"; + EBMLId2[EBMLId2["CuePoint"] = 187] = "CuePoint"; + EBMLId2[EBMLId2["CueTime"] = 179] = "CueTime"; + EBMLId2[EBMLId2["CueTrackPositions"] = 183] = "CueTrackPositions"; + EBMLId2[EBMLId2["CueTrack"] = 247] = "CueTrack"; + EBMLId2[EBMLId2["CueClusterPosition"] = 241] = "CueClusterPosition"; + EBMLId2[EBMLId2["Colour"] = 21936] = "Colour"; + EBMLId2[EBMLId2["MatrixCoefficients"] = 21937] = "MatrixCoefficients"; + EBMLId2[EBMLId2["TransferCharacteristics"] = 21946] = "TransferCharacteristics"; + EBMLId2[EBMLId2["Primaries"] = 21947] = "Primaries"; + EBMLId2[EBMLId2["Range"] = 21945] = "Range"; + EBMLId2[EBMLId2["Projection"] = 30320] = "Projection"; + EBMLId2[EBMLId2["ProjectionType"] = 30321] = "ProjectionType"; + EBMLId2[EBMLId2["ProjectionPoseRoll"] = 30325] = "ProjectionPoseRoll"; + EBMLId2[EBMLId2["Attachments"] = 423732329] = "Attachments"; + EBMLId2[EBMLId2["AttachedFile"] = 24999] = "AttachedFile"; + EBMLId2[EBMLId2["FileDescription"] = 18046] = "FileDescription"; + EBMLId2[EBMLId2["FileName"] = 18030] = "FileName"; + EBMLId2[EBMLId2["FileMediaType"] = 18016] = "FileMediaType"; + EBMLId2[EBMLId2["FileData"] = 18012] = "FileData"; + EBMLId2[EBMLId2["FileUID"] = 18094] = "FileUID"; + EBMLId2[EBMLId2["Chapters"] = 272869232] = "Chapters"; + EBMLId2[EBMLId2["Tags"] = 307544935] = "Tags"; + EBMLId2[EBMLId2["Tag"] = 29555] = "Tag"; + EBMLId2[EBMLId2["Targets"] = 25536] = "Targets"; + EBMLId2[EBMLId2["TargetTypeValue"] = 26826] = "TargetTypeValue"; + EBMLId2[EBMLId2["TargetType"] = 25546] = "TargetType"; + EBMLId2[EBMLId2["TagTrackUID"] = 25541] = "TagTrackUID"; + EBMLId2[EBMLId2["TagEditionUID"] = 25545] = "TagEditionUID"; + EBMLId2[EBMLId2["TagChapterUID"] = 25540] = "TagChapterUID"; + EBMLId2[EBMLId2["TagAttachmentUID"] = 25542] = "TagAttachmentUID"; + EBMLId2[EBMLId2["SimpleTag"] = 26568] = "SimpleTag"; + EBMLId2[EBMLId2["TagName"] = 17827] = "TagName"; + EBMLId2[EBMLId2["TagLanguage"] = 17530] = "TagLanguage"; + EBMLId2[EBMLId2["TagString"] = 17543] = "TagString"; + EBMLId2[EBMLId2["TagBinary"] = 17541] = "TagBinary"; + EBMLId2[EBMLId2["ContentEncodings"] = 28032] = "ContentEncodings"; + EBMLId2[EBMLId2["ContentEncoding"] = 25152] = "ContentEncoding"; + EBMLId2[EBMLId2["ContentEncodingOrder"] = 20529] = "ContentEncodingOrder"; + EBMLId2[EBMLId2["ContentEncodingScope"] = 20530] = "ContentEncodingScope"; + EBMLId2[EBMLId2["ContentCompression"] = 20532] = "ContentCompression"; + EBMLId2[EBMLId2["ContentCompAlgo"] = 16980] = "ContentCompAlgo"; + EBMLId2[EBMLId2["ContentCompSettings"] = 16981] = "ContentCompSettings"; + EBMLId2[EBMLId2["ContentEncryption"] = 20533] = "ContentEncryption"; +})(EBMLId || (EBMLId = {})); +const LEVEL_0_EBML_IDS = [ + EBMLId.EBML, + EBMLId.Segment +]; +const LEVEL_1_EBML_IDS = [ + EBMLId.SeekHead, + EBMLId.Info, + EBMLId.Cluster, + EBMLId.Tracks, + EBMLId.Cues, + EBMLId.Attachments, + EBMLId.Chapters, + EBMLId.Tags +]; +const LEVEL_0_AND_1_EBML_IDS = [ + ...LEVEL_0_EBML_IDS, + ...LEVEL_1_EBML_IDS +]; +const MAX_VAR_INT_SIZE = 8; +const MIN_HEADER_SIZE = 2; +const MAX_HEADER_SIZE = 2 * MAX_VAR_INT_SIZE; +const readVarIntSize = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + slice.skip(-1); + if (firstByte === 0) { + return null; + } + let width = 1; + let mask = 128; + while ((firstByte & mask) === 0) { + width++; + mask >>= 1; + } + if (slice.remainingLength < width) { + return null; + } + return width; +}; +const readVarInt = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + if (firstByte === 0) { + return null; + } + let width = 1; + let mask = 1 << 7; + while ((firstByte & mask) === 0) { + width++; + mask >>= 1; + } + if (slice.remainingLength < width - 1) { + return null; + } + let value = firstByte & mask - 1; + for (let i = 1; i < width; i++) { + value *= 1 << 8; + value += readU8(slice); + } + return value; +}; +const readUnsignedInt = (slice, width) => { + if (width < 1 || width > 8) { + throw new Error("Bad unsigned int size " + width); + } + let value = 0; + for (let i = 0; i < width; i++) { + value *= 1 << 8; + value += readU8(slice); + } + return value; +}; +const readUnsignedBigInt = (slice, width) => { + if (width < 1) { + throw new Error("Bad unsigned int size " + width); + } + let value = 0n; + for (let i = 0; i < width; i++) { + value <<= 8n; + value += BigInt(readU8(slice)); + } + return value; +}; +const readElementId = (slice) => { + const size = readVarIntSize(slice); + if (size === null) { + return null; + } + if (slice.remainingLength < size) { + return null; + } + const id = readUnsignedInt(slice, size); + return id; +}; +const readElementSize = (slice) => { + if (slice.remainingLength < 1) { + return null; + } + const firstByte = readU8(slice); + if (firstByte === 255) { + return void 0; + } + slice.skip(-1); + const size = readVarInt(slice); + if (size === null) { + return null; + } + if (size === 72057594037927940) { + return void 0; + } + return size; +}; +const readElementHeader = (slice) => { + assert(slice.remainingLength >= MIN_HEADER_SIZE); + const id = readElementId(slice); + if (id === null) { + return null; + } + const size = readElementSize(slice); + if (size === null) { + return null; + } + return { id, size }; +}; +const readAsciiString = (slice, length) => { + const bytes = readBytes(slice, length); + let strLength = 0; + while (strLength < length && bytes[strLength] !== 0) { + strLength += 1; + } + return String.fromCharCode(...bytes.subarray(0, strLength)); +}; +const readUnicodeString = (slice, length) => { + const bytes = readBytes(slice, length); + let strLength = 0; + while (strLength < length && bytes[strLength] !== 0) { + strLength += 1; + } + return textDecoder.decode(bytes.subarray(0, strLength)); +}; +const readFloat = (slice, width) => { + if (width === 0) { + return 0; + } + if (width !== 4 && width !== 8) { + throw new Error("Bad float size " + width); + } + return width === 4 ? readF32Be(slice) : readF64Be(slice); +}; +const searchForNextElementId = async (reader, startPos, ids, until) => { + const idsSet = new Set(ids); + let currentPos = startPos; + while (until === null || currentPos < until) { + let slice = reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementHeader = readElementHeader(slice); + if (!elementHeader) { + break; + } + if (idsSet.has(elementHeader.id)) { + return { pos: currentPos, found: true }; + } + assertDefinedSize(elementHeader.size); + currentPos = slice.filePos + elementHeader.size; + } + return { pos: until !== null && until > currentPos ? until : currentPos, found: false }; +}; +const resync = async (reader, startPos, ids, until) => { + const CHUNK_SIZE = 2 ** 16; + const idsSet = new Set(ids); + let currentPos = startPos; + while (currentPos < until) { + let slice = reader.requestSliceRange(currentPos, 0, Math.min(CHUNK_SIZE, until - currentPos)); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + if (slice.length < MAX_VAR_INT_SIZE) + break; + for (let i = 0; i < slice.length - MAX_VAR_INT_SIZE; i++) { + slice.filePos = currentPos; + const elementId = readElementId(slice); + if (elementId !== null && idsSet.has(elementId)) { + return currentPos; + } + currentPos++; + } + } + return null; +}; +const CODEC_STRING_MAP = { + "avc": "V_MPEG4/ISO/AVC", + "hevc": "V_MPEGH/ISO/HEVC", + "vp8": "V_VP8", + "vp9": "V_VP9", + "av1": "V_AV1", + "aac": "A_AAC", + "mp3": "A_MPEG/L3", + "opus": "A_OPUS", + "vorbis": "A_VORBIS", + "flac": "A_FLAC", + "ac3": "A_AC3", + "eac3": "A_EAC3" +}; +function assertDefinedSize(size) { + if (size === void 0) { + throw new Error("Undefined element size is used in a place where it is not supported."); + } +} +const buildMatroskaMimeType = (info) => { + const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; + let string = base + (info.isWebM ? "webm" : "x-matroska"); + if (info.codecStrings.length > 0) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings.filter(Boolean))]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; + } + return string; +}; +var BlockLacing; +(function(BlockLacing2) { + BlockLacing2[BlockLacing2["None"] = 0] = "None"; + BlockLacing2[BlockLacing2["Xiph"] = 1] = "Xiph"; + BlockLacing2[BlockLacing2["FixedSize"] = 2] = "FixedSize"; + BlockLacing2[BlockLacing2["Ebml"] = 3] = "Ebml"; +})(BlockLacing || (BlockLacing = {})); +var ContentEncodingScope; +(function(ContentEncodingScope2) { + ContentEncodingScope2[ContentEncodingScope2["Block"] = 1] = "Block"; + ContentEncodingScope2[ContentEncodingScope2["Private"] = 2] = "Private"; + ContentEncodingScope2[ContentEncodingScope2["Next"] = 4] = "Next"; +})(ContentEncodingScope || (ContentEncodingScope = {})); +var ContentCompAlgo; +(function(ContentCompAlgo2) { + ContentCompAlgo2[ContentCompAlgo2["Zlib"] = 0] = "Zlib"; + ContentCompAlgo2[ContentCompAlgo2["Bzlib"] = 1] = "Bzlib"; + ContentCompAlgo2[ContentCompAlgo2["lzo1x"] = 2] = "lzo1x"; + ContentCompAlgo2[ContentCompAlgo2["HeaderStripping"] = 3] = "HeaderStripping"; +})(ContentCompAlgo || (ContentCompAlgo = {})); +const METADATA_ELEMENTS = [ + { id: EBMLId.SeekHead, flag: "seekHeadSeen" }, + { id: EBMLId.Info, flag: "infoSeen" }, + { id: EBMLId.Tracks, flag: "tracksSeen" }, + { id: EBMLId.Cues, flag: "cuesSeen" } +]; +const MAX_RESYNC_LENGTH = 10 * 2 ** 20; +class MatroskaDemuxer extends Demuxer { + constructor(input) { + super(input); + this.readMetadataPromise = null; + this.segments = []; + this.currentSegment = null; + this.currentTrack = null; + this.currentCluster = null; + this.currentBlock = null; + this.currentBlockAdditional = null; + this.currentCueTime = null; + this.currentDecodingInstruction = null; + this.currentTagTargetIsMovie = true; + this.currentSimpleTagName = null; + this.currentAttachedFile = null; + this.isWebM = false; + this.reader = input._reader; + } + async getTrackBackings() { + await this.readMetadata(); + return this.segments.flatMap((segment) => segment.tracks.map((track) => track.trackBacking)); + } + async getMimeType() { + await this.readMetadata(); + const backings = await this.getTrackBackings(); + const codecStrings = await Promise.all(backings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildMatroskaMimeType({ + isWebM: this.isWebM, + hasVideo: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "video")), + hasAudio: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "audio")), + codecStrings: codecStrings.filter(Boolean) + }); + } + async getMetadataTags() { + await this.readMetadata(); + for (const segment of this.segments) { + if (!segment.metadataTagsCollected) { + if (this.reader.fileSize !== null) { + await this.loadSegmentMetadata(segment); + } + segment.metadataTagsCollected = true; + } + } + let metadataTags = {}; + for (const segment of this.segments) { + metadataTags = { ...metadataTags, ...segment.metadataTags }; + } + return metadataTags; + } + readMetadata() { + return this.readMetadataPromise ?? (this.readMetadataPromise = (async () => { + let currentPos = 0; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const header = readElementHeader(slice); + if (!header) { + break; + } + const id = header.id; + let size = header.size; + const dataStartPos = slice.filePos; + if (id === EBMLId.EBML) { + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + this.readContiguousElements(slice2); + } else if (id === EBMLId.Segment) { + await this.readSegment(dataStartPos, size); + if (size === void 0) { + break; + } + if (this.reader.fileSize === null) { + break; + } + } else if (id === EBMLId.Cluster) { + if (this.reader.fileSize === null) { + break; + } + if (size === void 0) { + const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, this.reader.fileSize); + size = nextElementPos.pos - dataStartPos; + } + const lastSegment = last(this.segments); + if (lastSegment) { + lastSegment.elementEndPos = dataStartPos + size; + } + } + assertDefinedSize(size); + currentPos = dataStartPos + size; + } + })()); + } + async readSegment(segmentDataStart, dataSize) { + this.currentSegment = { + seekHeadSeen: false, + infoSeen: false, + tracksSeen: false, + cuesSeen: false, + tagsSeen: false, + attachmentsSeen: false, + timestampScale: -1, + timestampFactor: -1, + duration: -1, + seekEntries: [], + tracks: [], + cuePoints: [], + dataStartPos: segmentDataStart, + elementEndPos: dataSize === void 0 ? null : segmentDataStart + dataSize, + clusterSeekStartPos: segmentDataStart, + lastReadCluster: null, + metadataTags: {}, + metadataTagsCollected: false + }; + this.segments.push(this.currentSegment); + let currentPos = segmentDataStart; + while (this.currentSegment.elementEndPos === null || currentPos < this.currentSegment.elementEndPos) { + let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementStartPos = currentPos; + const header = readElementHeader(slice); + if (!header || !LEVEL_1_EBML_IDS.includes(header.id) && header.id !== EBMLId.Void) { + const nextPos = await resync(this.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(this.currentSegment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); + if (nextPos) { + currentPos = nextPos; + continue; + } else { + break; + } + } + const { id, size } = header; + const dataStartPos = slice.filePos; + const metadataElementIndex = METADATA_ELEMENTS.findIndex((x) => x.id === id); + if (metadataElementIndex !== -1) { + const field = METADATA_ELEMENTS[metadataElementIndex].flag; + this.currentSegment[field] = true; + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (slice2) { + this.readContiguousElements(slice2); + } + } else if (id === EBMLId.Tags || id === EBMLId.Attachments) { + if (id === EBMLId.Tags) { + this.currentSegment.tagsSeen = true; + } else { + this.currentSegment.attachmentsSeen = true; + } + assertDefinedSize(size); + let slice2 = this.reader.requestSlice(dataStartPos, size); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (slice2) { + this.readContiguousElements(slice2); + } + } else if (id === EBMLId.Cluster) { + this.currentSegment.clusterSeekStartPos = elementStartPos; + break; + } + if (size === void 0) { + break; + } else { + currentPos = dataStartPos + size; + } + } + this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition); + if (this.reader.fileSize !== null) { + for (const seekEntry of this.currentSegment.seekEntries) { + const target = METADATA_ELEMENTS.find((x) => x.id === seekEntry.id); + if (!target) { + continue; + } + if (this.currentSegment[target.flag]) + continue; + let slice = this.reader.requestSliceRange(segmentDataStart + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + continue; + const header = readElementHeader(slice); + if (!header) + continue; + const { id, size } = header; + if (id !== target.id) + continue; + assertDefinedSize(size); + this.currentSegment[target.flag] = true; + let dataSlice = this.reader.requestSlice(slice.filePos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (!dataSlice) + continue; + this.readContiguousElements(dataSlice); + } + } + if (this.currentSegment.timestampScale === -1) { + this.currentSegment.timestampScale = 1e6; + this.currentSegment.timestampFactor = 1e9 / 1e6; + } + for (const track of this.currentSegment.tracks) { + if (track.defaultDurationNs !== null) { + track.defaultDuration = this.currentSegment.timestampFactor * track.defaultDurationNs / 1e9; + } + } + const idToTrack = new Map(this.currentSegment.tracks.map((x) => [x.id, x])); + for (const cuePoint of this.currentSegment.cuePoints) { + const track = idToTrack.get(cuePoint.trackId); + if (track) { + track.cuePoints.push(cuePoint); + } + } + for (const track of this.currentSegment.tracks) { + track.cuePoints.sort((a, b) => a.time - b.time); + for (let i = 0; i < track.cuePoints.length - 1; i++) { + const cuePoint1 = track.cuePoints[i]; + const cuePoint2 = track.cuePoints[i + 1]; + if (cuePoint1.time === cuePoint2.time) { + track.cuePoints.splice(i + 1, 1); + i--; + } + } + } + let trackWithMostCuePoints = null; + let maxCuePointCount = -Infinity; + for (const track of this.currentSegment.tracks) { + if (track.cuePoints.length > maxCuePointCount) { + maxCuePointCount = track.cuePoints.length; + trackWithMostCuePoints = track; + } + } + for (const track of this.currentSegment.tracks) { + if (track.cuePoints.length === 0) { + track.cuePoints = trackWithMostCuePoints.cuePoints; + } + } + this.currentSegment = null; + } + async readCluster(startPos, segment) { + if (segment.lastReadCluster?.elementStartPos === startPos) { + return segment.lastReadCluster; + } + let headerSlice = this.reader.requestSliceRange(startPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const elementStartPos = startPos; + const elementHeader = readElementHeader(headerSlice); + assert(elementHeader); + const id = elementHeader.id; + assert(id === EBMLId.Cluster); + let size = elementHeader.size; + const dataStartPos = headerSlice.filePos; + if (size === void 0) { + const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); + size = nextElementPos.pos - dataStartPos; + } + let dataSlice = this.reader.requestSlice(dataStartPos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + const cluster = { + segment, + elementStartPos, + elementEndPos: dataStartPos + size, + dataStartPos, + timestamp: -1, + trackData: /* @__PURE__ */ new Map() + }; + this.currentCluster = cluster; + if (dataSlice) { + const endPos = this.readContiguousElements(dataSlice, LEVEL_0_AND_1_EBML_IDS); + cluster.elementEndPos = endPos; + } + for (const [, trackData] of cluster.trackData) { + const track = trackData.track; + assert(trackData.blocks.length > 0); + let hasLacedBlocks = false; + for (let i = 0; i < trackData.blocks.length; i++) { + const block = trackData.blocks[i]; + block.timestamp += cluster.timestamp; + hasLacedBlocks || (hasLacedBlocks = block.lacing !== BlockLacing.None); + } + trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); + for (let i = 0; i < trackData.presentationTimestamps.length; i++) { + const currentEntry = trackData.presentationTimestamps[i]; + const currentBlock = trackData.blocks[currentEntry.blockIndex]; + if (trackData.firstKeyFrameTimestamp === null && currentBlock.isKeyFrame) { + trackData.firstKeyFrameTimestamp = currentBlock.timestamp; + } + if (i < trackData.presentationTimestamps.length - 1) { + const nextEntry = trackData.presentationTimestamps[i + 1]; + currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp; + } else if (currentBlock.duration === 0) { + if (track.defaultDuration != null) { + if (currentBlock.lacing === BlockLacing.None) { + currentBlock.duration = track.defaultDuration; + } + } + } + } + if (hasLacedBlocks) { + this.expandLacedBlocks(trackData.blocks, track); + trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); + } + const firstBlock = trackData.blocks[trackData.presentationTimestamps[0].blockIndex]; + const lastBlock = trackData.blocks[last(trackData.presentationTimestamps).blockIndex]; + trackData.startTimestamp = firstBlock.timestamp; + trackData.endTimestamp = lastBlock.timestamp + lastBlock.duration; + const insertionIndex = binarySearchLessOrEqual(track.clusterPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); + if (insertionIndex === -1 || track.clusterPositionCache[insertionIndex].elementStartPos !== elementStartPos) { + track.clusterPositionCache.splice(insertionIndex + 1, 0, { + elementStartPos: cluster.elementStartPos, + startTimestamp: trackData.startTimestamp + }); + } + } + segment.lastReadCluster = cluster; + return cluster; + } + getTrackDataInCluster(cluster, trackNumber) { + let trackData = cluster.trackData.get(trackNumber); + if (!trackData) { + const track = cluster.segment.tracks.find((x) => x.id === trackNumber); + if (!track) { + return null; + } + trackData = { + track, + startTimestamp: 0, + endTimestamp: 0, + firstKeyFrameTimestamp: null, + blocks: [], + presentationTimestamps: [] + }; + cluster.trackData.set(trackNumber, trackData); + } + return trackData; + } + expandLacedBlocks(blocks, track) { + for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) { + const originalBlock = blocks[blockIndex]; + if (originalBlock.lacing === BlockLacing.None) { + continue; + } + if (!originalBlock.decoded) { + originalBlock.data = this.decodeBlockData(track, originalBlock.data); + originalBlock.decoded = true; + } + const slice = FileSlice.tempFromBytes(originalBlock.data); + const frameSizes = []; + const frameCount = readU8(slice) + 1; + switch (originalBlock.lacing) { + case BlockLacing.Xiph: + { + let totalUsedSize = 0; + for (let i = 0; i < frameCount - 1; i++) { + let frameSize = 0; + while (slice.bufferPos < slice.length) { + const value = readU8(slice); + frameSize += value; + if (value < 255) { + frameSizes.push(frameSize); + totalUsedSize += frameSize; + break; + } + } + } + frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); + } + break; + case BlockLacing.FixedSize: + { + const totalDataSize = slice.length - 1; + const frameSize = Math.floor(totalDataSize / frameCount); + for (let i = 0; i < frameCount; i++) { + frameSizes.push(frameSize); + } + } + break; + case BlockLacing.Ebml: + { + const firstResult = readVarInt(slice); + assert(firstResult !== null); + let currentSize = firstResult; + frameSizes.push(currentSize); + let totalUsedSize = currentSize; + for (let i = 1; i < frameCount - 1; i++) { + const startPos = slice.bufferPos; + const diffResult = readVarInt(slice); + assert(diffResult !== null); + const unsignedDiff = diffResult; + const width = slice.bufferPos - startPos; + const bias = (1 << width * 7 - 1) - 1; + const diff = unsignedDiff - bias; + currentSize += diff; + frameSizes.push(currentSize); + totalUsedSize += currentSize; + } + frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); + } + break; + default: + assert(false); + } + assert(frameSizes.length === frameCount); + blocks.splice(blockIndex, 1); + const blockDuration = originalBlock.duration || frameCount * (track.defaultDuration ?? 0); + for (let i = 0; i < frameCount; i++) { + const frameSize = frameSizes[i]; + const frameData = readBytes(slice, frameSize); + const frameTimestamp = originalBlock.timestamp + blockDuration * i / frameCount; + const frameDuration = blockDuration / frameCount; + blocks.splice(blockIndex + i, 0, { + timestamp: frameTimestamp, + duration: frameDuration, + isKeyFrame: originalBlock.isKeyFrame, + data: frameData, + lacing: BlockLacing.None, + decoded: true, + mainAdditional: originalBlock.mainAdditional + }); + } + blockIndex += frameCount; + blockIndex--; + } + } + async loadSegmentMetadata(segment) { + for (const seekEntry of segment.seekEntries) { + if (seekEntry.id === EBMLId.Tags && !segment.tagsSeen) ; + else if (seekEntry.id === EBMLId.Attachments && !segment.attachmentsSeen) ; + else { + continue; + } + let slice = this.reader.requestSliceRange(segment.dataStartPos + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + continue; + const header = readElementHeader(slice); + if (!header || header.id !== seekEntry.id) + continue; + const { size } = header; + assertDefinedSize(size); + assert(!this.currentSegment); + this.currentSegment = segment; + let dataSlice = this.reader.requestSlice(slice.filePos, size); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (dataSlice) { + this.readContiguousElements(dataSlice); + } + this.currentSegment = null; + if (seekEntry.id === EBMLId.Tags) { + segment.tagsSeen = true; + } else if (seekEntry.id === EBMLId.Attachments) { + segment.attachmentsSeen = true; + } + } + } + readContiguousElements(slice, stopIds) { + while (slice.remainingLength >= MIN_HEADER_SIZE) { + const startPos = slice.filePos; + const foundElement = this.traverseElement(slice, stopIds); + if (!foundElement) { + return startPos; + } + } + return slice.filePos; + } + traverseElement(slice, stopIds) { + const header = readElementHeader(slice); + if (!header) { + return false; + } + if (stopIds && stopIds.includes(header.id)) { + return false; + } + const { id, size } = header; + const dataStartPos = slice.filePos; + assertDefinedSize(size); + switch (id) { + case EBMLId.DocType: + { + this.isWebM = readAsciiString(slice, size) === "webm"; + } + break; + case EBMLId.Seek: + { + if (!this.currentSegment) + break; + const seekEntry = { id: -1, segmentPosition: -1 }; + this.currentSegment.seekEntries.push(seekEntry); + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (seekEntry.id === -1 || seekEntry.segmentPosition === -1) { + this.currentSegment.seekEntries.pop(); + } + } + break; + case EBMLId.SeekID: + { + const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; + if (!lastSeekEntry) + break; + lastSeekEntry.id = readUnsignedInt(slice, size); + } + break; + case EBMLId.SeekPosition: + { + const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; + if (!lastSeekEntry) + break; + lastSeekEntry.segmentPosition = readUnsignedInt(slice, size); + } + break; + case EBMLId.TimestampScale: + { + if (!this.currentSegment) + break; + this.currentSegment.timestampScale = readUnsignedInt(slice, size); + this.currentSegment.timestampFactor = 1e9 / this.currentSegment.timestampScale; + } + break; + case EBMLId.Duration: + { + if (!this.currentSegment) + break; + this.currentSegment.duration = readFloat(slice, size); + } + break; + case EBMLId.TrackEntry: + { + if (!this.currentSegment) + break; + this.currentTrack = { + id: -1, + segment: this.currentSegment, + demuxer: this, + clusterPositionCache: [], + cuePoints: [], + disposition: { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }, + trackBacking: null, + codecId: null, + codecPrivate: null, + defaultDuration: null, + defaultDurationNs: null, + name: null, + languageCode: "eng", + // The default in Matroska + hasLanguageBcp47: false, + decodingInstructions: [], + info: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (!this.currentTrack) { + break; + } + if (this.currentTrack.decodingInstructions.some((instruction) => { + return instruction.data?.type !== "decompress" || instruction.scope !== ContentEncodingScope.Block || instruction.data.algorithm !== ContentCompAlgo.HeaderStripping; + })) { + console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`); + this.currentTrack = null; + } + if (this.currentTrack && this.currentTrack.id !== -1 && this.currentTrack.codecId && this.currentTrack.info) { + const slashIndex = this.currentTrack.codecId.indexOf("/"); + const codecIdWithoutSuffix = slashIndex === -1 ? this.currentTrack.codecId : this.currentTrack.codecId.slice(0, slashIndex); + if (this.currentTrack.info.type === "video" && this.currentTrack.info.width !== -1 && this.currentTrack.info.height !== -1) { + this.currentTrack.info.squarePixelWidth = this.currentTrack.info.width; + this.currentTrack.info.squarePixelHeight = this.currentTrack.info.height; + if (this.currentTrack.info.displayWidth !== null && this.currentTrack.info.displayHeight !== null) { + const num = this.currentTrack.info.displayWidth * this.currentTrack.info.height; + const den = this.currentTrack.info.displayHeight * this.currentTrack.info.width; + if (num > 0 && den > 0) { + if (num > den) { + this.currentTrack.info.squarePixelWidth = Math.round(this.currentTrack.info.width * num / den); + } else { + this.currentTrack.info.squarePixelHeight = Math.round(this.currentTrack.info.height * den / num); + } + } + } + if (this.currentTrack.codecId === CODEC_STRING_MAP.avc) { + this.currentTrack.info.codec = "avc"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === CODEC_STRING_MAP.hevc) { + this.currentTrack.info.codec = "hevc"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp8) { + this.currentTrack.info.codec = "vp8"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp9) { + this.currentTrack.info.codec = "vp9"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.av1) { + this.currentTrack.info.codec = "av1"; + } + const videoTrack = this.currentTrack; + this.currentTrack.trackBacking = new MatroskaVideoTrackBacking(videoTrack); + this.currentSegment.tracks.push(this.currentTrack); + } else if (this.currentTrack.info.type === "audio") { + if (codecIdWithoutSuffix === CODEC_STRING_MAP.aac) { + this.currentTrack.info.codec = "aac"; + this.currentTrack.info.aacCodecInfo = { + isMpeg2: this.currentTrack.codecId.includes("MPEG2"), + objectType: null + }; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === CODEC_STRING_MAP.mp3) { + this.currentTrack.info.codec = "mp3"; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.opus) { + this.currentTrack.info.codec = "opus"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + this.currentTrack.info.sampleRate = OPUS_SAMPLE_RATE; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vorbis) { + this.currentTrack.info.codec = "vorbis"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.flac) { + this.currentTrack.info.codec = "flac"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.ac3) { + this.currentTrack.info.codec = "ac3"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.eac3) { + this.currentTrack.info.codec = "eac3"; + this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; + } else if (this.currentTrack.codecId === "A_PCM/INT/LIT") { + if (this.currentTrack.info.bitDepth === 8) { + this.currentTrack.info.codec = "pcm-u8"; + } else if (this.currentTrack.info.bitDepth === 16) { + this.currentTrack.info.codec = "pcm-s16"; + } else if (this.currentTrack.info.bitDepth === 24) { + this.currentTrack.info.codec = "pcm-s24"; + } else if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-s32"; + } + } else if (this.currentTrack.codecId === "A_PCM/INT/BIG") { + if (this.currentTrack.info.bitDepth === 8) { + this.currentTrack.info.codec = "pcm-u8"; + } else if (this.currentTrack.info.bitDepth === 16) { + this.currentTrack.info.codec = "pcm-s16be"; + } else if (this.currentTrack.info.bitDepth === 24) { + this.currentTrack.info.codec = "pcm-s24be"; + } else if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-s32be"; + } + } else if (this.currentTrack.codecId === "A_PCM/FLOAT/IEEE") { + if (this.currentTrack.info.bitDepth === 32) { + this.currentTrack.info.codec = "pcm-f32"; + } else if (this.currentTrack.info.bitDepth === 64) { + this.currentTrack.info.codec = "pcm-f64"; + } + } + const audioTrack = this.currentTrack; + this.currentTrack.trackBacking = new MatroskaAudioTrackBacking(audioTrack); + this.currentSegment.tracks.push(this.currentTrack); + } + } + this.currentTrack = null; + } + break; + case EBMLId.TrackNumber: + { + if (!this.currentTrack) + break; + this.currentTrack.id = readUnsignedInt(slice, size); + } + break; + case EBMLId.TrackType: + { + if (!this.currentTrack) + break; + const type = readUnsignedInt(slice, size); + if (type === 1) { + this.currentTrack.info = { + type: "video", + width: -1, + height: -1, + displayWidth: null, + displayHeight: null, + displayUnit: null, + squarePixelWidth: -1, + squarePixelHeight: -1, + rotation: 0, + codec: null, + codecDescription: null, + colorSpace: null, + alphaMode: false + }; + } else if (type === 2) { + this.currentTrack.info = { + type: "audio", + numberOfChannels: 1, + // Default value + sampleRate: 8e3, + // Default value + bitDepth: -1, + codec: null, + codecDescription: null, + aacCodecInfo: null + }; + } + } + break; + case EBMLId.FlagEnabled: + { + if (!this.currentTrack) + break; + const enabled = readUnsignedInt(slice, size); + if (!enabled) { + this.currentTrack = null; + } + } + break; + case EBMLId.FlagDefault: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.default = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagForced: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.forced = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagOriginal: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.original = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagHearingImpaired: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.hearingImpaired = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagVisualImpaired: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.visuallyImpaired = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.FlagCommentary: + { + if (!this.currentTrack) + break; + this.currentTrack.disposition.commentary = !!readUnsignedInt(slice, size); + } + break; + case EBMLId.CodecID: + { + if (!this.currentTrack) + break; + this.currentTrack.codecId = readAsciiString(slice, size); + } + break; + case EBMLId.CodecPrivate: + { + if (!this.currentTrack) + break; + this.currentTrack.codecPrivate = readBytes(slice, size); + } + break; + case EBMLId.DefaultDuration: + { + if (!this.currentTrack) + break; + this.currentTrack.defaultDurationNs = readUnsignedInt(slice, size); + } + break; + case EBMLId.Name: + { + if (!this.currentTrack) + break; + this.currentTrack.name = readUnicodeString(slice, size); + } + break; + case EBMLId.Language: + { + if (!this.currentTrack) + break; + if (this.currentTrack.hasLanguageBcp47) { + break; + } + this.currentTrack.languageCode = readAsciiString(slice, size); + if (!isIso639Dash2LanguageCode(this.currentTrack.languageCode)) { + this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; + } + } + break; + case EBMLId.LanguageBCP47: + { + if (!this.currentTrack) + break; + const bcp47 = readAsciiString(slice, size); + const languageSubtag = bcp47.split("-")[0]; + if (languageSubtag) { + this.currentTrack.languageCode = languageSubtag; + } else { + this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; + } + this.currentTrack.hasLanguageBcp47 = true; + } + break; + case EBMLId.Video: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.PixelWidth: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.width = readUnsignedInt(slice, size); + } + break; + case EBMLId.PixelHeight: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.height = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayWidth: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayWidth = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayHeight: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayHeight = readUnsignedInt(slice, size); + } + break; + case EBMLId.DisplayUnit: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.displayUnit = readUnsignedInt(slice, size); + } + break; + case EBMLId.AlphaMode: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.alphaMode = readUnsignedInt(slice, size) === 1; + } + break; + case EBMLId.Colour: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.currentTrack.info.colorSpace = {}; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.MatrixCoefficients: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const matrixCoefficients = readUnsignedInt(slice, size); + const mapped = MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients] ?? null; + this.currentTrack.info.colorSpace.matrix = mapped; + } + break; + case EBMLId.Range: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + this.currentTrack.info.colorSpace.fullRange = readUnsignedInt(slice, size) === 2; + } + break; + case EBMLId.TransferCharacteristics: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const transferCharacteristics = readUnsignedInt(slice, size); + const mapped = TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics] ?? null; + this.currentTrack.info.colorSpace.transfer = mapped; + } + break; + case EBMLId.Primaries: + { + if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) + break; + const primaries = readUnsignedInt(slice, size); + const mapped = COLOR_PRIMARIES_MAP_INVERSE[primaries] ?? null; + this.currentTrack.info.colorSpace.primaries = mapped; + } + break; + case EBMLId.Projection: + { + if (this.currentTrack?.info?.type !== "video") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.ProjectionPoseRoll: + { + if (this.currentTrack?.info?.type !== "video") + break; + const rotation = readFloat(slice, size); + const flippedRotation = -rotation; + try { + this.currentTrack.info.rotation = normalizeRotation(flippedRotation); + } catch { + } + } + break; + case EBMLId.Audio: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.SamplingFrequency: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.sampleRate = readFloat(slice, size); + } + break; + case EBMLId.Channels: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.numberOfChannels = readUnsignedInt(slice, size); + } + break; + case EBMLId.BitDepth: + { + if (this.currentTrack?.info?.type !== "audio") + break; + this.currentTrack.info.bitDepth = readUnsignedInt(slice, size); + } + break; + case EBMLId.CuePoint: + { + if (!this.currentSegment) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentCueTime = null; + } + break; + case EBMLId.CueTime: + { + this.currentCueTime = readUnsignedInt(slice, size); + } + break; + case EBMLId.CueTrackPositions: + { + if (this.currentCueTime === null) + break; + assert(this.currentSegment); + const cuePoint = { time: this.currentCueTime, trackId: -1, clusterPosition: -1 }; + this.currentSegment.cuePoints.push(cuePoint); + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (cuePoint.trackId === -1 || cuePoint.clusterPosition === -1) { + this.currentSegment.cuePoints.pop(); + } + } + break; + case EBMLId.CueTrack: + { + const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; + if (!lastCuePoint) + break; + lastCuePoint.trackId = readUnsignedInt(slice, size); + } + break; + case EBMLId.CueClusterPosition: + { + const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; + if (!lastCuePoint) + break; + assert(this.currentSegment); + lastCuePoint.clusterPosition = this.currentSegment.dataStartPos + readUnsignedInt(slice, size); + } + break; + case EBMLId.Timestamp: + { + if (!this.currentCluster) + break; + this.currentCluster.timestamp = readUnsignedInt(slice, size); + } + break; + case EBMLId.SimpleBlock: + { + if (!this.currentCluster) + break; + const trackNumber = readVarInt(slice); + if (trackNumber === null) + break; + const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); + if (!trackData) + break; + const relativeTimestamp = readI16Be(slice); + const flags = readU8(slice); + const lacing = flags >> 1 & 3; + let isKeyFrame = !!(flags & 128); + if (trackData.track.info?.type === "audio" && trackData.track.info.codec) { + isKeyFrame = true; + } + const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); + const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; + trackData.blocks.push({ + timestamp: relativeTimestamp, + // We'll add the cluster's timestamp to this later + duration: 0, + // Will set later + isKeyFrame, + data: blockData, + lacing, + decoded: !hasDecodingInstructions, + mainAdditional: null + }); + } + break; + case EBMLId.BlockGroup: + { + if (!this.currentCluster) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentBlock = null; + } + break; + case EBMLId.Block: + { + if (!this.currentCluster) + break; + const trackNumber = readVarInt(slice); + if (trackNumber === null) + break; + const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); + if (!trackData) + break; + const relativeTimestamp = readI16Be(slice); + const flags = readU8(slice); + const lacing = flags >> 1 & 3; + const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); + const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; + this.currentBlock = { + timestamp: relativeTimestamp, + // We'll add the cluster's timestamp to this later + duration: 0, + // Will set later + isKeyFrame: true, + data: blockData, + lacing, + decoded: !hasDecodingInstructions, + mainAdditional: null + }; + trackData.blocks.push(this.currentBlock); + } + break; + case EBMLId.BlockAdditions: + { + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.BlockMore: + { + if (!this.currentBlock) + break; + this.currentBlockAdditional = { + addId: 1, + data: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (this.currentBlockAdditional.data && this.currentBlockAdditional.addId === 1) { + this.currentBlock.mainAdditional = this.currentBlockAdditional.data; + } + this.currentBlockAdditional = null; + } + break; + case EBMLId.BlockAdditional: + { + if (!this.currentBlockAdditional) + break; + this.currentBlockAdditional.data = readBytes(slice, size); + } + break; + case EBMLId.BlockAddID: + { + if (!this.currentBlockAdditional) + break; + this.currentBlockAdditional.addId = readUnsignedInt(slice, size); + } + break; + case EBMLId.BlockDuration: + { + if (!this.currentBlock) + break; + this.currentBlock.duration = readUnsignedInt(slice, size); + } + break; + case EBMLId.ReferenceBlock: + { + if (!this.currentBlock) + break; + this.currentBlock.isKeyFrame = false; + } + break; + case EBMLId.Tag: + { + this.currentTagTargetIsMovie = true; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.Targets: + { + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.TargetTypeValue: + { + const targetTypeValue = readUnsignedInt(slice, size); + if (targetTypeValue !== 50) { + this.currentTagTargetIsMovie = false; + } + } + break; + case EBMLId.TagTrackUID: + case EBMLId.TagEditionUID: + case EBMLId.TagChapterUID: + case EBMLId.TagAttachmentUID: + { + this.currentTagTargetIsMovie = false; + } + break; + case EBMLId.SimpleTag: + { + if (!this.currentTagTargetIsMovie) + break; + this.currentSimpleTagName = null; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.TagName: + { + this.currentSimpleTagName = readUnicodeString(slice, size); + } + break; + case EBMLId.TagString: + { + if (!this.currentSimpleTagName) + break; + const value = readUnicodeString(slice, size); + this.processTagValue(this.currentSimpleTagName, value); + } + break; + case EBMLId.TagBinary: + { + if (!this.currentSimpleTagName) + break; + const value = readBytes(slice, size); + this.processTagValue(this.currentSimpleTagName, value); + } + break; + case EBMLId.AttachedFile: + { + if (!this.currentSegment) + break; + this.currentAttachedFile = { + fileUid: null, + fileName: null, + fileMediaType: null, + fileData: null, + fileDescription: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + const tags = this.currentSegment.metadataTags; + if (this.currentAttachedFile.fileUid && this.currentAttachedFile.fileData) { + tags.raw ?? (tags.raw = {}); + tags.raw[this.currentAttachedFile.fileUid.toString()] = new AttachedFile(this.currentAttachedFile.fileData, this.currentAttachedFile.fileMediaType ?? void 0, this.currentAttachedFile.fileName ?? void 0, this.currentAttachedFile.fileDescription ?? void 0); + } + if (this.currentAttachedFile.fileMediaType?.startsWith("image/") && this.currentAttachedFile.fileData) { + const fileName = this.currentAttachedFile.fileName; + let kind = "unknown"; + if (fileName) { + const lowerName = fileName.toLowerCase(); + if (lowerName.startsWith("cover.")) { + kind = "coverFront"; + } else if (lowerName.startsWith("back.")) { + kind = "coverBack"; + } + } + tags.images ?? (tags.images = []); + tags.images.push({ + data: this.currentAttachedFile.fileData, + mimeType: this.currentAttachedFile.fileMediaType, + kind, + name: this.currentAttachedFile.fileName ?? void 0, + description: this.currentAttachedFile.fileDescription ?? void 0 + }); + } + this.currentAttachedFile = null; + } + break; + case EBMLId.FileUID: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileUid = readUnsignedBigInt(slice, size); + } + break; + case EBMLId.FileName: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileName = readUnicodeString(slice, size); + } + break; + case EBMLId.FileMediaType: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileMediaType = readAsciiString(slice, size); + } + break; + case EBMLId.FileData: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileData = readBytes(slice, size); + } + break; + case EBMLId.FileDescription: + { + if (!this.currentAttachedFile) + break; + this.currentAttachedFile.fileDescription = readUnicodeString(slice, size); + } + break; + case EBMLId.ContentEncodings: + { + if (!this.currentTrack) + break; + this.readContiguousElements(slice.slice(dataStartPos, size)); + this.currentTrack.decodingInstructions.sort((a, b) => b.order - a.order); + } + break; + case EBMLId.ContentEncoding: + { + this.currentDecodingInstruction = { + order: 0, + scope: ContentEncodingScope.Block, + data: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + if (this.currentDecodingInstruction.data) { + this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction); + } + this.currentDecodingInstruction = null; + } + break; + case EBMLId.ContentEncodingOrder: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.order = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentEncodingScope: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.scope = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentCompression: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.data = { + type: "decompress", + algorithm: ContentCompAlgo.Zlib, + settings: null + }; + this.readContiguousElements(slice.slice(dataStartPos, size)); + } + break; + case EBMLId.ContentCompAlgo: + { + if (this.currentDecodingInstruction?.data?.type !== "decompress") + break; + this.currentDecodingInstruction.data.algorithm = readUnsignedInt(slice, size); + } + break; + case EBMLId.ContentCompSettings: + { + if (this.currentDecodingInstruction?.data?.type !== "decompress") + break; + this.currentDecodingInstruction.data.settings = readBytes(slice, size); + } + break; + case EBMLId.ContentEncryption: + { + if (!this.currentDecodingInstruction) + break; + this.currentDecodingInstruction.data = { + type: "decrypt" + }; + } + break; + } + slice.filePos = dataStartPos + size; + return true; + } + decodeBlockData(track, rawData) { + assert(track.decodingInstructions.length > 0); + let currentData = rawData; + for (const instruction of track.decodingInstructions) { + assert(instruction.data); + switch (instruction.data.type) { + case "decompress": + { + switch (instruction.data.algorithm) { + case ContentCompAlgo.HeaderStripping: + { + if (instruction.data.settings && instruction.data.settings.length > 0) { + const prefix = instruction.data.settings; + const newData = new Uint8Array(prefix.length + currentData.length); + newData.set(prefix, 0); + newData.set(currentData, prefix.length); + currentData = newData; + } + } + break; + } + } + break; + } + } + return currentData; + } + processTagValue(name, value) { + var _a; + if (!this.currentSegment?.metadataTags) + return; + const metadataTags = this.currentSegment.metadataTags; + metadataTags.raw ?? (metadataTags.raw = {}); + (_a = metadataTags.raw)[name] ?? (_a[name] = value); + if (typeof value === "string") { + switch (name.toLowerCase()) { + case "title": + { + metadataTags.title ?? (metadataTags.title = value); + } + break; + case "description": + { + metadataTags.description ?? (metadataTags.description = value); + } + break; + case "artist": + { + metadataTags.artist ?? (metadataTags.artist = value); + } + break; + case "album": + { + metadataTags.album ?? (metadataTags.album = value); + } + break; + case "album_artist": + { + metadataTags.albumArtist ?? (metadataTags.albumArtist = value); + } + break; + case "genre": + { + metadataTags.genre ?? (metadataTags.genre = value); + } + break; + case "comment": + { + metadataTags.comment ?? (metadataTags.comment = value); + } + break; + case "lyrics": + { + metadataTags.lyrics ?? (metadataTags.lyrics = value); + } + break; + case "date": + { + const date = new Date(value); + if (!Number.isNaN(date.getTime())) { + metadataTags.date ?? (metadataTags.date = date); + } + } + break; + case "track_number": + case "part_number": + { + const parts = value.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + metadataTags.trackNumber ?? (metadataTags.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + metadataTags.tracksTotal ?? (metadataTags.tracksTotal = tracksTotal); + } + } + break; + case "disc_number": + case "disc": + { + const discParts = value.split("/"); + const discNum = Number.parseInt(discParts[0], 10); + const discsTotal = discParts[1] && Number.parseInt(discParts[1], 10); + if (Number.isInteger(discNum) && discNum > 0) { + metadataTags.discNumber ?? (metadataTags.discNumber = discNum); + } + if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) { + metadataTags.discsTotal ?? (metadataTags.discsTotal = discsTotal); + } + } + break; + } + } + } +} +class MatroskaTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.packetToClusterLocation = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.internalTrack.id; + } + getNumber() { + const demuxer = this.internalTrack.demuxer; + const trackType = this.internalTrack.trackBacking.getType(); + let number = 0; + for (const segment of demuxer.segments) { + for (const track of segment.tracks) { + if (track.trackBacking.getType() === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.internalTrack.codecId; + } + getName() { + return this.internalTrack.name; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getTimeResolution() { + return this.internalTrack.segment.timestampFactor; + } + isRelativeToUnixEpoch() { + return false; + } + getDisposition() { + return this.internalTrack.disposition; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const segment = this.internalTrack.segment; + if (segment.duration <= 0) { + return null; + } + let endTimestamp = segment.duration / segment.timestampFactor; + const firstPacket = await this.getFirstPacket({ metadataOnly: true }); + endTimestamp += firstPacket?.timestamp ?? 0; + return endTimestamp; + } + async getLiveRefreshInterval() { + return null; + } + async getFirstPacket(options) { + return this.performClusterLookup( + null, + (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData) { + return { + blockIndex: 0, + correctBlockFound: true + }; + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + intoTimescale(timestamp) { + return roundIfAlmostInteger(timestamp * this.internalTrack.segment.timestampFactor); + } + async getPacket(timestamp, options) { + const timestampInTimescale = this.intoTimescale(timestamp); + return this.performClusterLookup(null, (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (!trackData) { + return { blockIndex: -1, correctBlockFound: false }; + } + const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.timestamp); + const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; + const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { blockIndex, correctBlockFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextPacket(packet, options) { + const locationInCluster = this.packetToClusterLocation.get(packet); + if (locationInCluster === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performClusterLookup( + locationInCluster.cluster, + (cluster) => { + if (cluster === locationInCluster.cluster) { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (locationInCluster.blockIndex + 1 < trackData.blocks.length) { + return { + blockIndex: locationInCluster.blockIndex + 1, + correctBlockFound: true + }; + } + } else { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData) { + return { + blockIndex: 0, + correctBlockFound: true + }; + } + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + async getKeyPacket(timestamp, options) { + const timestampInTimescale = this.intoTimescale(timestamp); + return this.performClusterLookup(null, (cluster) => { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (!trackData) { + return { blockIndex: -1, correctBlockFound: false }; + } + const index = findLastIndex(trackData.presentationTimestamps, (x) => { + const block = trackData.blocks[x.blockIndex]; + return block.isKeyFrame && x.timestamp <= timestampInTimescale; + }); + const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; + const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; + return { blockIndex, correctBlockFound }; + }, timestampInTimescale, timestampInTimescale, options); + } + async getNextKeyPacket(packet, options) { + const locationInCluster = this.packetToClusterLocation.get(packet); + if (locationInCluster === void 0) { + throw new Error("Packet was not created from this track."); + } + return this.performClusterLookup( + locationInCluster.cluster, + (cluster) => { + if (cluster === locationInCluster.cluster) { + const trackData = cluster.trackData.get(this.internalTrack.id); + const nextKeyFrameIndex = trackData.blocks.findIndex((x, i) => x.isKeyFrame && i > locationInCluster.blockIndex); + if (nextKeyFrameIndex !== -1) { + return { + blockIndex: nextKeyFrameIndex, + correctBlockFound: true + }; + } + } else { + const trackData = cluster.trackData.get(this.internalTrack.id); + if (trackData && trackData.firstKeyFrameTimestamp !== null) { + const keyFrameIndex = trackData.blocks.findIndex((x) => x.isKeyFrame); + assert(keyFrameIndex !== -1); + return { + blockIndex: keyFrameIndex, + correctBlockFound: true + }; + } + } + return { + blockIndex: -1, + correctBlockFound: false + }; + }, + -Infinity, + // Use -Infinity as a search timestamp to avoid using the cues + Infinity, + options + ); + } + async fetchPacketInCluster(cluster, blockIndex, options) { + if (blockIndex === -1) { + return null; + } + const trackData = cluster.trackData.get(this.internalTrack.id); + const block = trackData.blocks[blockIndex]; + assert(block); + if (!block.decoded) { + block.data = this.internalTrack.demuxer.decodeBlockData(this.internalTrack, block.data); + block.decoded = true; + } + const data = options.metadataOnly ? PLACEHOLDER_DATA : block.data; + const timestamp = block.timestamp / this.internalTrack.segment.timestampFactor; + const duration = block.duration / this.internalTrack.segment.timestampFactor; + const sideData = {}; + if (block.mainAdditional && this.internalTrack.info?.type === "video" && this.internalTrack.info.alphaMode) { + sideData.alpha = options.metadataOnly ? PLACEHOLDER_DATA : block.mainAdditional; + sideData.alphaByteLength = block.mainAdditional.byteLength; + } + const packet = new EncodedPacket(data, block.isKeyFrame ? "key" : "delta", timestamp, duration, cluster.dataStartPos + blockIndex, block.data.byteLength, sideData); + this.packetToClusterLocation.set(packet, { cluster, blockIndex }); + return packet; + } + /** Looks for a packet in the clusters while trying to load as few clusters as possible to retrieve it. */ + async performClusterLookup(startCluster, getMatchInCluster, searchTimestamp, latestTimestamp, options) { + const { demuxer, segment } = this.internalTrack; + let currentCluster = null; + let bestCluster = null; + let bestBlockIndex = -1; + if (startCluster) { + const { blockIndex, correctBlockFound } = getMatchInCluster(startCluster); + if (correctBlockFound) { + return this.fetchPacketInCluster(startCluster, blockIndex, options); + } + if (blockIndex !== -1) { + bestCluster = startCluster; + bestBlockIndex = blockIndex; + } + } + const cuePointIndex = binarySearchLessOrEqual(this.internalTrack.cuePoints, searchTimestamp, (x) => x.time); + const cuePoint = cuePointIndex !== -1 ? this.internalTrack.cuePoints[cuePointIndex] : null; + const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.clusterPositionCache, searchTimestamp, (x) => x.startTimestamp); + const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.clusterPositionCache[positionCacheIndex] : null; + const lookupEntryPosition = Math.max(cuePoint?.clusterPosition ?? 0, positionCacheEntry?.elementStartPos ?? 0) || null; + let currentPos; + if (!startCluster) { + currentPos = lookupEntryPosition ?? segment.clusterSeekStartPos; + } else { + if (lookupEntryPosition === null || startCluster.elementStartPos >= lookupEntryPosition) { + currentPos = startCluster.elementEndPos; + currentCluster = startCluster; + } else { + currentPos = lookupEntryPosition; + } + } + while (segment.elementEndPos === null || currentPos <= segment.elementEndPos - MIN_HEADER_SIZE) { + if (currentCluster) { + const trackData = currentCluster.trackData.get(this.internalTrack.id); + if (trackData && trackData.startTimestamp > latestTimestamp) { + break; + } + } + let slice = demuxer.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const elementStartPos = currentPos; + const elementHeader = readElementHeader(slice); + if (!elementHeader || !LEVEL_1_EBML_IDS.includes(elementHeader.id) && elementHeader.id !== EBMLId.Void) { + const nextPos = await resync(demuxer.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(segment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); + if (nextPos) { + currentPos = nextPos; + continue; + } else { + break; + } + } + const id = elementHeader.id; + let size = elementHeader.size; + const dataStartPos = slice.filePos; + if (id === EBMLId.Cluster) { + currentCluster = await demuxer.readCluster(elementStartPos, segment); + size = currentCluster.elementEndPos - dataStartPos; + const { blockIndex, correctBlockFound } = getMatchInCluster(currentCluster); + if (correctBlockFound) { + return this.fetchPacketInCluster(currentCluster, blockIndex, options); + } + if (blockIndex !== -1) { + bestCluster = currentCluster; + bestBlockIndex = blockIndex; + } + } + if (size === void 0) { + assert(id !== EBMLId.Cluster); + const nextElementPos = await searchForNextElementId(demuxer.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); + size = nextElementPos.pos - dataStartPos; + } + const endPos = dataStartPos + size; + if (segment.elementEndPos === null) { + let slice2 = demuxer.reader.requestSliceRange(endPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const elementId = readElementId(slice2); + if (elementId === EBMLId.Segment) { + segment.elementEndPos = endPos; + break; + } + } + currentPos = endPos; + } + if (cuePoint && (!bestCluster || bestCluster.elementStartPos < cuePoint.clusterPosition)) { + const previousCuePoint = this.internalTrack.cuePoints[cuePointIndex - 1]; + assert(!previousCuePoint || previousCuePoint.time < cuePoint.time); + const newSearchTimestamp = previousCuePoint?.time ?? -Infinity; + return this.performClusterLookup(null, getMatchInCluster, newSearchTimestamp, latestTimestamp, options); + } + if (bestCluster) { + return this.fetchPacketInCluster(bestCluster, bestBlockIndex, options); + } + return null; + } +} +class MatroskaVideoTrackBacking extends MatroskaTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfigPromise = null; + this.internalTrack = internalTrack; + } + getType() { + return "video"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getCodedWidth() { + return this.internalTrack.info.width; + } + getCodedHeight() { + return this.internalTrack.info.height; + } + getSquarePixelWidth() { + return this.internalTrack.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.internalTrack.info.squarePixelHeight; + } + getRotation() { + return this.internalTrack.info.rotation; + } + async getColorSpace() { + return { + primaries: this.internalTrack.info.colorSpace?.primaries, + transfer: this.internalTrack.info.colorSpace?.transfer, + matrix: this.internalTrack.info.colorSpace?.matrix, + fullRange: this.internalTrack.info.colorSpace?.fullRange + }; + } + async canBeTransparent() { + return this.internalTrack.info.alphaMode; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { + let firstPacket = null; + const needsPacketForAdditionalInfo = this.internalTrack.info.codec === "vp9" || this.internalTrack.info.codec === "av1" || this.internalTrack.info.codec === "avc" && !this.internalTrack.info.codecDescription || this.internalTrack.info.codec === "hevc" && !this.internalTrack.info.codecDescription; + if (needsPacketForAdditionalInfo) { + firstPacket = await this.getFirstPacket({}); + } + const config = { + codec: extractVideoCodecString({ + width: this.internalTrack.info.width, + height: this.internalTrack.info.height, + codec: this.internalTrack.info.codec, + codecDescription: this.internalTrack.info.codecDescription, + colorSpace: this.internalTrack.info.colorSpace, + avcType: 1, + // We don't know better (or do we?) so just assume 'avc1' + avcCodecInfo: this.internalTrack.info.codec === "avc" && firstPacket ? extractAvcDecoderConfigurationRecord(firstPacket.data) : null, + hevcCodecInfo: this.internalTrack.info.codec === "hevc" && firstPacket ? extractHevcDecoderConfigurationRecord(firstPacket.data) : null, + vp9CodecInfo: this.internalTrack.info.codec === "vp9" && firstPacket ? extractVp9CodecInfoFromPacket(firstPacket.data) : null, + av1CodecInfo: this.internalTrack.info.codec === "av1" && firstPacket ? extractAv1CodecInfoFromPacket(firstPacket.data) : null + }), + codedWidth: this.internalTrack.info.width, + codedHeight: this.internalTrack.info.height, + description: this.internalTrack.info.codecDescription ?? void 0, + colorSpace: this.internalTrack.info.colorSpace ?? void 0 + }; + if (this.internalTrack.info.width !== this.internalTrack.info.squarePixelWidth || this.internalTrack.info.height !== this.internalTrack.info.squarePixelHeight) { + config.displayAspectWidth = this.internalTrack.info.squarePixelWidth; + config.displayAspectHeight = this.internalTrack.info.squarePixelHeight; + } + return config; + })()); + } +} +class MatroskaAudioTrackBacking extends MatroskaTrackBacking { + constructor(internalTrack) { + super(internalTrack); + this.decoderConfig = null; + this.internalTrack = internalTrack; + } + getType() { + return "audio"; + } + getCodec() { + return this.internalTrack.info.codec; + } + getNumberOfChannels() { + return this.internalTrack.info.numberOfChannels; + } + getSampleRate() { + return this.internalTrack.info.sampleRate; + } + async getDecoderConfig() { + if (!this.internalTrack.info.codec) { + return null; + } + return this.decoderConfig ?? (this.decoderConfig = { + codec: extractAudioCodecString({ + codec: this.internalTrack.info.codec, + codecDescription: this.internalTrack.info.codecDescription, + aacCodecInfo: this.internalTrack.info.aacCodecInfo + }), + numberOfChannels: this.internalTrack.info.numberOfChannels, + sampleRate: this.internalTrack.info.sampleRate, + description: this.internalTrack.info.codecDescription ?? void 0 + }); + } +} +const readNextMp3FrameHeader = async (reader, startPos, until) => { + const CHUNK_SIZE = 2 ** 16; + let currentPos = startPos; + while (until === null || currentPos < until) { + const maxLength = until !== null ? Math.min(CHUNK_SIZE, until - currentPos) : CHUNK_SIZE; + let slice = reader.requestSliceRange(currentPos, FRAME_HEADER_SIZE, maxLength); + if (slice instanceof Promise) + slice = await slice; + if (!slice || slice.length < FRAME_HEADER_SIZE) + break; + while (slice.remainingLength >= FRAME_HEADER_SIZE) { + const posBeforeRead = slice.filePos; + const word = readU32Be(slice); + const remainingBytes = reader.fileSize !== null ? reader.fileSize - currentPos : null; + const result = readMp3FrameHeader(word, remainingBytes); + if (result.header) { + return { header: result.header, startPos: currentPos }; + } + slice.filePos = posBeforeRead + result.bytesAdvanced; + currentPos = slice.filePos; + } + } + return null; +}; +class Mp3Demuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.firstFrameHeader = null; + this.firstFrameHeaderPos = null; + this.loadedSamples = []; + this.metadataTags = null; + this.xingData = null; + this.trackBackings = []; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.lastLoadedPos = 0; + this.nextTimestampInSamples = 0; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + while (!this.firstFrameHeader && !this.lastSampleLoaded) { + await this.advanceReader(); + } + if (!this.firstFrameHeader) { + throw new Error("No valid MP3 frame found."); + } + this.trackBackings = [new Mp3AudioTrackBacking(this)]; + })()); + } + async advanceReader() { + if (this.lastLoadedPos === 0) { + while (true) { + let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) { + this.lastSampleLoaded = true; + return; + } + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + this.lastLoadedPos = slice2.filePos + id3V2Header.size; + } + } + const result = await readNextMp3FrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize); + if (!result) { + this.lastSampleLoaded = true; + return; + } + const header = result.header; + this.lastLoadedPos = result.startPos + header.totalSize - 1; + const xingOffset = getXingOffset(header.mpegVersionId, header.channel); + let slice = this.reader.requestSlice(result.startPos + xingOffset, 4); + if (slice instanceof Promise) + slice = await slice; + if (slice) { + const word = readU32Be(slice); + const isXing = word === XING || word === INFO; + if (isXing) { + if (!this.xingData) { + let xingDataSlice = this.reader.requestSlice(result.startPos + xingOffset + 4, 12); + if (xingDataSlice instanceof Promise) + xingDataSlice = await xingDataSlice; + if (xingDataSlice) { + const xingData = readBytes(xingDataSlice, 12); + const view = toDataView(xingData); + const flags = view.getUint32(0, false); + this.xingData = { + frameCount: flags & XingFlags.FrameCount ? view.getUint32(4, false) : null, + fileSize: flags & XingFlags.FileSize ? view.getUint32(8, false) : null + }; + } + } + return; + } + } + if (!this.firstFrameHeader) { + this.firstFrameHeader = header; + this.firstFrameHeaderPos = result.startPos; + } + if (header.sampleRate !== this.firstFrameHeader.sampleRate) { + console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${header.sampleRate} Hz. Might be a bug, so please report this file.`); + } + const sampleDuration = header.audioSamplesInFrame / this.firstFrameHeader.sampleRate; + const sample = { + timestamp: this.nextTimestampInSamples / this.firstFrameHeader.sampleRate, + duration: sampleDuration, + dataStart: result.startPos, + dataSize: header.totalSize + }; + this.loadedSamples.push(sample); + this.nextTimestampInSamples += header.audioSamplesInFrame; + return; + } + async getMimeType() { + return "audio/mpeg"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + const release = await this.readingMutex.acquire(); + try { + await this.readMetadata(); + if (this.metadataTags) { + return this.metadataTags; + } + this.metadataTags = {}; + let currentPos = 0; + let id3V2HeaderFound = false; + while (true) { + let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + break; + const id3V2Header = readId3V2Header(headerSlice); + if (!id3V2Header) { + break; + } + id3V2HeaderFound = true; + let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); + if (contentSlice instanceof Promise) + contentSlice = await contentSlice; + if (!contentSlice) + break; + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + currentPos = headerSlice.filePos + id3V2Header.size; + } + if (!id3V2HeaderFound && this.reader.fileSize !== null && this.reader.fileSize >= ID3_V1_TAG_SIZE) { + let slice = this.reader.requestSlice(this.reader.fileSize - ID3_V1_TAG_SIZE, ID3_V1_TAG_SIZE); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const tag = readAscii(slice, 3); + if (tag === "TAG") { + parseId3V1Tag(slice, this.metadataTags); + } + } + return this.metadataTags; + } finally { + release(); + } + } +} +class Mp3AudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getTimeResolution() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.sampleRate / this.demuxer.firstFrameHeader.audioSamplesInFrame; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + const demuxer = this.demuxer; + assert(demuxer.firstFrameHeader !== null); + assert(demuxer.firstFrameHeaderPos !== null); + if (demuxer.xingData) { + if (demuxer.xingData.frameCount !== null) { + return demuxer.xingData.frameCount * demuxer.firstFrameHeader.audioSamplesInFrame / demuxer.firstFrameHeader.sampleRate; + } + } else { + if (demuxer.reader.fileSize !== null) { + const averageFrameSize = computeAverageMp3FrameSize(demuxer.firstFrameHeader.lowSamplingFrequency, demuxer.firstFrameHeader.layer, demuxer.firstFrameHeader.bitrate, demuxer.firstFrameHeader.sampleRate); + const frameCount = (demuxer.reader.fileSize - demuxer.firstFrameHeaderPos) / averageFrameSize; + return Math.round(frameCount) * demuxer.firstFrameHeader.audioSamplesInFrame / demuxer.firstFrameHeader.sampleRate; + } + } + return null; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getCodec() { + return "mp3"; + } + getInternalCodecId() { + return null; + } + getNumberOfChannels() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2; + } + getSampleRate() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.sampleRate; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.firstFrameHeader); + return { + codec: "mp3", + numberOfChannels: this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2, + sampleRate: this.demuxer.firstFrameHeader.sampleRate + }; + } + async getPacketAtIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.dataSize); + } + return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); + if (sampleIndex === -1) { + throw new Error("Packet was not created from this track."); + } + const nextIndex = sampleIndex + 1; + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + async getPacket(timestamp, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); + if (index === -1 && this.demuxer.loadedSamples.length > 0) { + return null; + } + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(index, options); + } + if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { + return this.getPacketAtIndex(index, options); + } + await this.demuxer.advanceReader(); + } + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } +} +const OGGS = 1399285583; +const OGG_CRC_POLYNOMIAL = 79764919; +const OGG_CRC_TABLE = new Uint32Array(256); +for (let n = 0; n < 256; n++) { + let crc = n << 24; + for (let k = 0; k < 8; k++) { + crc = crc & 2147483648 ? crc << 1 ^ OGG_CRC_POLYNOMIAL : crc << 1; + } + OGG_CRC_TABLE[n] = crc >>> 0 & 4294967295; +} +const computeOggPageCrc = (bytes) => { + const view = toDataView(bytes); + const originalChecksum = view.getUint32(22, true); + view.setUint32(22, 0, true); + let crc = 0; + for (let i = 0; i < bytes.length; i++) { + const byte = bytes[i]; + crc = (crc << 8 ^ OGG_CRC_TABLE[crc >>> 24 ^ byte]) >>> 0; + } + view.setUint32(22, originalChecksum, true); + return crc; +}; +const extractSampleMetadata = (data, codecInfo, vorbisLastBlocksize) => { + let durationInSamples = 0; + let currentBlocksize = null; + if (data.length > 0) { + if (codecInfo.codec === "vorbis") { + assert(codecInfo.vorbisInfo); + const vorbisModeCount = codecInfo.vorbisInfo.modeBlockflags.length; + const bitCount = ilog(vorbisModeCount - 1); + const modeMask = (1 << bitCount) - 1 << 1; + const modeNumber = (data[0] & modeMask) >> 1; + if (modeNumber >= codecInfo.vorbisInfo.modeBlockflags.length) { + throw new Error("Invalid mode number."); + } + let prevBlocksize = vorbisLastBlocksize; + const blockflag = codecInfo.vorbisInfo.modeBlockflags[modeNumber]; + currentBlocksize = codecInfo.vorbisInfo.blocksizes[blockflag]; + if (blockflag === 1) { + const prevMask = (modeMask | 1) + 1; + const flag = data[0] & prevMask ? 1 : 0; + prevBlocksize = codecInfo.vorbisInfo.blocksizes[flag]; + } + durationInSamples = prevBlocksize !== null ? prevBlocksize + currentBlocksize >> 2 : 0; + } else if (codecInfo.codec === "opus") { + const toc = parseOpusTocByte(data); + durationInSamples = toc.durationInSamples; + } + } + return { + durationInSamples, + vorbisBlockSize: currentBlocksize + }; +}; +const buildOggMimeType = (info) => { + let string = "audio/ogg"; + if (info.codecStrings) { + const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; + string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; + } + return string; +}; +const MIN_PAGE_HEADER_SIZE = 27; +const MAX_PAGE_HEADER_SIZE = 27 + 255; +const MAX_PAGE_SIZE = MAX_PAGE_HEADER_SIZE + 255 * 255; +const readPageHeader = (slice) => { + const startPos = slice.filePos; + const capturePattern = readU32Le(slice); + if (capturePattern !== OGGS) { + return null; + } + slice.skip(1); + const headerType = readU8(slice); + const granulePosition = readI64Le(slice); + const serialNumber = readU32Le(slice); + const sequenceNumber = readU32Le(slice); + const checksum = readU32Le(slice); + const numberPageSegments = readU8(slice); + const lacingValues = new Uint8Array(numberPageSegments); + for (let i = 0; i < numberPageSegments; i++) { + lacingValues[i] = readU8(slice); + } + const headerSize = 27 + numberPageSegments; + const dataSize = lacingValues.reduce((a, b) => a + b, 0); + const totalSize = headerSize + dataSize; + return { + headerStartPos: startPos, + totalSize, + dataStartPos: startPos + headerSize, + dataSize, + headerType, + granulePosition, + serialNumber, + sequenceNumber, + checksum, + lacingValues + }; +}; +const findNextPageHeader = (slice, until) => { + while (slice.filePos < until - (4 - 1)) { + const word = readU32Le(slice); + const firstByte = word & 255; + const secondByte = word >>> 8 & 255; + const thirdByte = word >>> 16 & 255; + const fourthByte = word >>> 24 & 255; + const O = 79; + if (firstByte !== O && secondByte !== O && thirdByte !== O && fourthByte !== O) { + continue; + } + slice.skip(-4); + if (word === OGGS) { + return true; + } + slice.skip(1); + } + return false; +}; +class OggDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.bitstreams = []; + this.trackBackings = []; + this.metadataTags = {}; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let currentPos = 0; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + break; + const page = readPageHeader(slice); + if (!page) { + break; + } + const isBos = !!(page.headerType & 2); + if (!isBos) { + break; + } + this.bitstreams.push({ + serialNumber: page.serialNumber, + bosPage: page, + description: null, + numberOfChannels: -1, + sampleRate: -1, + codecInfo: { + codec: null, + vorbisInfo: null, + opusInfo: null + }, + lastMetadataPacket: null + }); + currentPos = page.headerStartPos + page.totalSize; + } + for (const bitstream of this.bitstreams) { + const firstPacket = await this.readPacket(bitstream.bosPage, 0); + if (!firstPacket) { + continue; + } + if ( + // Check for Vorbis + firstPacket.data.byteLength >= 7 && firstPacket.data[0] === 1 && firstPacket.data[1] === 118 && firstPacket.data[2] === 111 && firstPacket.data[3] === 114 && firstPacket.data[4] === 98 && firstPacket.data[5] === 105 && firstPacket.data[6] === 115 + ) { + await this.readVorbisMetadata(firstPacket, bitstream); + } else if ( + // Check for Opus + firstPacket.data.byteLength >= 8 && firstPacket.data[0] === 79 && firstPacket.data[1] === 112 && firstPacket.data[2] === 117 && firstPacket.data[3] === 115 && firstPacket.data[4] === 72 && firstPacket.data[5] === 101 && firstPacket.data[6] === 97 && firstPacket.data[7] === 100 + ) { + await this.readOpusMetadata(firstPacket, bitstream); + } + if (bitstream.codecInfo.codec !== null) { + this.trackBackings.push(new OggAudioTrackBacking(bitstream, this)); + } + } + })()); + } + async readVorbisMetadata(firstPacket, bitstream) { + let nextPacketPosition = await this.findNextPacketStart(firstPacket); + if (!nextPacketPosition) { + return; + } + const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!secondPacket) { + return; + } + nextPacketPosition = await this.findNextPacketStart(secondPacket); + if (!nextPacketPosition) { + return; + } + const thirdPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!thirdPacket) { + return; + } + if (secondPacket.data[0] !== 3 || thirdPacket.data[0] !== 5) { + return; + } + const lacingValues = []; + const addBytesToSegmentTable = (bytes) => { + while (true) { + lacingValues.push(Math.min(255, bytes)); + if (bytes < 255) { + break; + } + bytes -= 255; + } + }; + addBytesToSegmentTable(firstPacket.data.length); + addBytesToSegmentTable(secondPacket.data.length); + const description = new Uint8Array(1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length + thirdPacket.data.length); + description[0] = 2; + description.set(lacingValues, 1); + description.set(firstPacket.data, 1 + lacingValues.length); + description.set(secondPacket.data, 1 + lacingValues.length + firstPacket.data.length); + description.set(thirdPacket.data, 1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length); + bitstream.codecInfo.codec = "vorbis"; + bitstream.description = description; + bitstream.lastMetadataPacket = thirdPacket; + const view = toDataView(firstPacket.data); + bitstream.numberOfChannels = view.getUint8(11); + bitstream.sampleRate = view.getUint32(12, true); + const blockSizeByte = view.getUint8(28); + bitstream.codecInfo.vorbisInfo = { + blocksizes: [ + 1 << (blockSizeByte & 15), + 1 << (blockSizeByte >> 4) + ], + modeBlockflags: parseModesFromVorbisSetupPacket(thirdPacket.data).modeBlockflags + }; + readVorbisComments(secondPacket.data.subarray(7), this.metadataTags); + } + async readOpusMetadata(firstPacket, bitstream) { + const nextPacketPosition = await this.findNextPacketStart(firstPacket); + if (!nextPacketPosition) { + return; + } + const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); + if (!secondPacket) { + return; + } + bitstream.codecInfo.codec = "opus"; + bitstream.description = firstPacket.data; + bitstream.lastMetadataPacket = secondPacket; + const header = parseOpusIdentificationHeader(firstPacket.data); + bitstream.numberOfChannels = header.outputChannelCount; + bitstream.sampleRate = OPUS_SAMPLE_RATE; + bitstream.codecInfo.opusInfo = { + preSkip: header.preSkip + }; + readVorbisComments(secondPacket.data.subarray(8), this.metadataTags); + } + async readPacket(startPage, startSegmentIndex) { + assert(startSegmentIndex < startPage.lacingValues.length); + let startDataOffset = 0; + for (let i = 0; i < startSegmentIndex; i++) { + startDataOffset += startPage.lacingValues[i]; + } + let currentPage = startPage; + let currentDataOffset = startDataOffset; + let currentSegmentIndex = startSegmentIndex; + const chunks = []; + outer: while (true) { + let pageSlice = this.reader.requestSlice(currentPage.dataStartPos, currentPage.dataSize); + if (pageSlice instanceof Promise) + pageSlice = await pageSlice; + assert(pageSlice); + const pageData = readBytes(pageSlice, currentPage.dataSize); + while (true) { + if (currentSegmentIndex === currentPage.lacingValues.length) { + chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); + break; + } + const lacingValue = currentPage.lacingValues[currentSegmentIndex]; + currentDataOffset += lacingValue; + if (lacingValue < 255) { + chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); + break outer; + } + currentSegmentIndex++; + } + let currentPos = currentPage.headerStartPos + currentPage.totalSize; + while (true) { + let headerSlice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) { + return null; + } + const nextPage = readPageHeader(headerSlice); + if (!nextPage) { + return null; + } + currentPage = nextPage; + if (currentPage.serialNumber === startPage.serialNumber) { + break; + } + currentPos = currentPage.headerStartPos + currentPage.totalSize; + } + startDataOffset = 0; + currentDataOffset = 0; + currentSegmentIndex = 0; + } + const totalPacketSize = chunks.reduce((sum, chunk) => sum + chunk.length, 0); + if (totalPacketSize === 0) { + return null; + } + const packetData = new Uint8Array(totalPacketSize); + let offset = 0; + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + packetData.set(chunk, offset); + offset += chunk.length; + } + return { + data: packetData, + endPage: currentPage, + endSegmentIndex: currentSegmentIndex + }; + } + async findNextPacketStart(lastPacket) { + if (lastPacket.endSegmentIndex < lastPacket.endPage.lacingValues.length - 1) { + return { startPage: lastPacket.endPage, startSegmentIndex: lastPacket.endSegmentIndex + 1 }; + } + const isEos = !!(lastPacket.endPage.headerType & 4); + if (isEos) { + return null; + } + let currentPos = lastPacket.endPage.headerStartPos + lastPacket.endPage.totalSize; + while (true) { + let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const nextPage = readPageHeader(slice); + if (!nextPage) { + return null; + } + if (nextPage.serialNumber === lastPacket.endPage.serialNumber) { + return { startPage: nextPage, startSegmentIndex: 0 }; + } + currentPos = nextPage.headerStartPos + nextPage.totalSize; + } + } + async getMimeType() { + await this.readMetadata(); + const codecStrings = await Promise.all(this.trackBackings.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildOggMimeType({ + codecStrings: codecStrings.filter(Boolean) + }); + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } +} +class OggAudioTrackBacking { + constructor(bitstream, demuxer) { + this.bitstream = bitstream; + this.demuxer = demuxer; + this.encodedPacketToMetadata = /* @__PURE__ */ new WeakMap(); + this.sequentialScanCache = []; + this.sequentialScanMutex = new AsyncMutex(); + this.internalSampleRate = bitstream.codecInfo.codec === "opus" ? OPUS_SAMPLE_RATE : bitstream.sampleRate; + } + getType() { + return "audio"; + } + getId() { + return this.bitstream.serialNumber; + } + getNumber() { + const index = this.demuxer.trackBackings.findIndex((x) => x.bitstream === this.bitstream); + assert(index !== -1); + return index + 1; + } + getNumberOfChannels() { + return this.bitstream.numberOfChannels; + } + getSampleRate() { + return this.bitstream.sampleRate; + } + getTimeResolution() { + return this.bitstream.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + getCodec() { + return this.bitstream.codecInfo.codec; + } + getInternalCodecId() { + return null; + } + async getDecoderConfig() { + assert(this.bitstream.codecInfo.codec); + return { + codec: this.bitstream.codecInfo.codec, + numberOfChannels: this.bitstream.numberOfChannels, + sampleRate: this.bitstream.sampleRate, + description: this.bitstream.description ?? void 0 + }; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }; + } + granulePositionToTimestampInSamples(granulePosition) { + if (this.bitstream.codecInfo.codec === "opus") { + assert(this.bitstream.codecInfo.opusInfo); + return granulePosition - this.bitstream.codecInfo.opusInfo.preSkip; + } + return granulePosition; + } + createEncodedPacketFromOggPacket(packet, additional, options) { + if (!packet) { + return null; + } + const { durationInSamples, vorbisBlockSize } = extractSampleMetadata(packet.data, this.bitstream.codecInfo, additional.vorbisLastBlocksize); + const encodedPacket = new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : packet.data, "key", Math.max(0, additional.timestampInSamples) / this.internalSampleRate, durationInSamples / this.internalSampleRate, packet.endPage.headerStartPos + packet.endSegmentIndex, packet.data.byteLength); + this.encodedPacketToMetadata.set(encodedPacket, { + packet, + timestampInSamples: additional.timestampInSamples, + durationInSamples, + vorbisLastBlockSize: additional.vorbisLastBlocksize, + vorbisBlockSize + }); + return encodedPacket; + } + async getFirstPacket(options) { + assert(this.bitstream.lastMetadataPacket); + const packetPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); + if (!packetPosition) { + return null; + } + let timestampInSamples = 0; + if (this.bitstream.codecInfo.codec === "opus") { + assert(this.bitstream.codecInfo.opusInfo); + timestampInSamples -= this.bitstream.codecInfo.opusInfo.preSkip; + } + const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); + return this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples, + vorbisLastBlocksize: null + }, options); + } + async getNextPacket(prevPacket, options) { + const prevMetadata = this.encodedPacketToMetadata.get(prevPacket); + if (!prevMetadata) { + throw new Error("Packet was not created from this track."); + } + const packetPosition = await this.demuxer.findNextPacketStart(prevMetadata.packet); + if (!packetPosition) { + return null; + } + const timestampInSamples = prevMetadata.timestampInSamples + prevMetadata.durationInSamples; + const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); + return this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples, + vorbisLastBlocksize: prevMetadata.vorbisBlockSize + }, options); + } + async getPacket(timestamp, options) { + if (this.demuxer.reader.fileSize === null) { + return this.getPacketSequential(timestamp, options); + } + const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); + if (timestampInSamples === 0) { + return this.getFirstPacket(options); + } + if (timestampInSamples < 0) { + return null; + } + assert(this.bitstream.lastMetadataPacket); + const startPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); + if (!startPosition) { + return null; + } + let lowPage = startPosition.startPage; + let high = this.demuxer.reader.fileSize; + const lowPages = [lowPage]; + outer: while (lowPage.headerStartPos + lowPage.totalSize < high) { + const low = lowPage.headerStartPos; + const mid = Math.floor((low + high) / 2); + let searchStartPos = mid; + while (true) { + const until = Math.min(searchStartPos + MAX_PAGE_SIZE, high - MIN_PAGE_HEADER_SIZE); + let searchSlice = this.demuxer.reader.requestSlice(searchStartPos, until - searchStartPos); + if (searchSlice instanceof Promise) + searchSlice = await searchSlice; + assert(searchSlice); + const found = findNextPageHeader(searchSlice, until); + if (!found) { + high = mid + MIN_PAGE_HEADER_SIZE; + continue outer; + } + let headerSlice = this.demuxer.reader.requestSliceRange(searchSlice.filePos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + assert(headerSlice); + const page = readPageHeader(headerSlice); + assert(page); + let pageValid = false; + if (page.serialNumber === this.bitstream.serialNumber) { + pageValid = true; + } else { + let pageSlice = this.demuxer.reader.requestSlice(page.headerStartPos, page.totalSize); + if (pageSlice instanceof Promise) + pageSlice = await pageSlice; + assert(pageSlice); + const bytes = readBytes(pageSlice, page.totalSize); + const crc = computeOggPageCrc(bytes); + pageValid = crc === page.checksum; + } + if (!pageValid) { + searchStartPos = page.headerStartPos + 4; + continue; + } + if (pageValid && page.serialNumber !== this.bitstream.serialNumber) { + searchStartPos = page.headerStartPos + page.totalSize; + continue; + } + const isContinuationPage = page.granulePosition === -1; + if (isContinuationPage) { + searchStartPos = page.headerStartPos + page.totalSize; + continue; + } + if (this.granulePositionToTimestampInSamples(page.granulePosition) > timestampInSamples) { + high = page.headerStartPos; + } else { + lowPage = page; + lowPages.push(page); + } + continue outer; + } + } + let lowerPage = startPosition.startPage; + for (const otherLowPage of lowPages) { + if (otherLowPage.granulePosition === lowPage.granulePosition) { + break; + } + if (!lowerPage || otherLowPage.headerStartPos > lowerPage.headerStartPos) { + lowerPage = otherLowPage; + } + } + let currentPage = lowerPage; + const previousPages = [currentPage]; + while (true) { + if (currentPage.serialNumber === this.bitstream.serialNumber && currentPage.granulePosition === lowPage.granulePosition) { + break; + } + const nextPos = currentPage.headerStartPos + currentPage.totalSize; + let slice = this.demuxer.reader.requestSliceRange(nextPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const nextPage = readPageHeader(slice); + assert(nextPage); + currentPage = nextPage; + if (currentPage.serialNumber === this.bitstream.serialNumber) { + previousPages.push(currentPage); + } + } + assert(currentPage.granulePosition !== -1); + let currentSegmentIndex = null; + let currentTimestampInSamples; + let currentTimestampIsCorrect; + let endPage = currentPage; + let endSegmentIndex = 0; + if (currentPage.headerStartPos === startPosition.startPage.headerStartPos) { + currentTimestampInSamples = this.granulePositionToTimestampInSamples(0); + currentTimestampIsCorrect = true; + currentSegmentIndex = 0; + } else { + currentTimestampInSamples = 0; + currentTimestampIsCorrect = false; + for (let i = currentPage.lacingValues.length - 1; i >= 0; i--) { + const value = currentPage.lacingValues[i]; + if (value < 255) { + currentSegmentIndex = i + 1; + break; + } + } + if (currentSegmentIndex === null) { + throw new Error("Invalid page with granule position: no packets end on this page."); + } + endSegmentIndex = currentSegmentIndex - 1; + const pseudopacket = { + data: PLACEHOLDER_DATA, + endPage, + endSegmentIndex + }; + const nextPosition = await this.demuxer.findNextPacketStart(pseudopacket); + if (nextPosition) { + const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); + assert(endPosition); + const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); + if (startPosition2) { + currentPage = startPosition2.page; + currentSegmentIndex = startPosition2.segmentIndex; + } + } else { + while (true) { + const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); + if (!endPosition) { + break; + } + const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); + if (!startPosition2) { + break; + } + currentPage = startPosition2.page; + currentSegmentIndex = startPosition2.segmentIndex; + if (endPosition.page.headerStartPos !== endPage.headerStartPos) { + endPage = endPosition.page; + endSegmentIndex = endPosition.segmentIndex; + break; + } + } + } + } + let lastEncodedPacket = null; + let lastEncodedPacketMetadata = null; + while (currentPage !== null) { + assert(currentSegmentIndex !== null); + const packet = await this.demuxer.readPacket(currentPage, currentSegmentIndex); + if (!packet) { + break; + } + const skipPacket = currentPage.headerStartPos === startPosition.startPage.headerStartPos && currentSegmentIndex < startPosition.startSegmentIndex; + if (!skipPacket) { + let encodedPacket = this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples: currentTimestampInSamples, + vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null + }, options); + assert(encodedPacket); + let encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); + assert(encodedPacketMetadata); + if (!currentTimestampIsCorrect && packet.endPage.headerStartPos === endPage.headerStartPos && packet.endSegmentIndex === endSegmentIndex) { + currentTimestampInSamples = this.granulePositionToTimestampInSamples(currentPage.granulePosition); + currentTimestampIsCorrect = true; + encodedPacket = this.createEncodedPacketFromOggPacket(packet, { + timestampInSamples: currentTimestampInSamples - encodedPacketMetadata.durationInSamples, + vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null + }, options); + assert(encodedPacket); + encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); + assert(encodedPacketMetadata); + } else { + currentTimestampInSamples += encodedPacketMetadata.durationInSamples; + } + lastEncodedPacket = encodedPacket; + lastEncodedPacketMetadata = encodedPacketMetadata; + if (currentTimestampIsCorrect && // Next timestamp will be too late + (Math.max(currentTimestampInSamples, 0) > timestampInSamples || Math.max(encodedPacketMetadata.timestampInSamples, 0) === timestampInSamples)) { + break; + } + } + const nextPosition = await this.demuxer.findNextPacketStart(packet); + if (!nextPosition) { + break; + } + currentPage = nextPosition.startPage; + currentSegmentIndex = nextPosition.startSegmentIndex; + } + return lastEncodedPacket; + } + // A slower but simpler and sequential algorithm for finding a packet in a file + async getPacketSequential(timestamp, options) { + const release = await this.sequentialScanMutex.acquire(); + try { + const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); + timestamp = timestampInSamples / this.internalSampleRate; + const index = binarySearchLessOrEqual(this.sequentialScanCache, timestampInSamples, (x) => x.timestampInSamples); + let currentPacket; + if (index !== -1) { + const cacheEntry = this.sequentialScanCache[index]; + currentPacket = this.createEncodedPacketFromOggPacket(cacheEntry.packet, { + timestampInSamples: cacheEntry.timestampInSamples, + vorbisLastBlocksize: cacheEntry.vorbisLastBlockSize + }, options); + } else { + currentPacket = await this.getFirstPacket(options); + } + let i = 0; + while (currentPacket && currentPacket.timestamp < timestamp) { + const nextPacket = await this.getNextPacket(currentPacket, options); + if (!nextPacket || nextPacket.timestamp > timestamp) { + break; + } + currentPacket = nextPacket; + i++; + if (i === 100) { + i = 0; + const metadata = this.encodedPacketToMetadata.get(currentPacket); + assert(metadata); + if (this.sequentialScanCache.length > 0) { + assert(last(this.sequentialScanCache).timestampInSamples <= metadata.timestampInSamples); + } + this.sequentialScanCache.push(metadata); + } + } + return currentPacket; + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } +} +const findPacketStartPosition = (pageList, endPage, endSegmentIndex) => { + let page = endPage; + let segmentIndex = endSegmentIndex; + outer: while (true) { + segmentIndex--; + for (segmentIndex; segmentIndex >= 0; segmentIndex--) { + const lacingValue = page.lacingValues[segmentIndex]; + if (lacingValue < 255) { + segmentIndex++; + break outer; + } + } + assert(segmentIndex === -1); + const pageStartsWithFreshPacket = !(page.headerType & 1); + if (pageStartsWithFreshPacket) { + segmentIndex = 0; + break; + } + const previousPage = findLast(pageList, (x) => x.headerStartPos < page.headerStartPos); + if (!previousPage) { + return null; + } + page = previousPage; + segmentIndex = page.lacingValues.length; + } + assert(segmentIndex !== -1); + if (segmentIndex === page.lacingValues.length) { + const nextPage = pageList[pageList.indexOf(page) + 1]; + assert(nextPage); + page = nextPage; + segmentIndex = 0; + } + return { page, segmentIndex }; +}; +const findPreviousPacketEndPosition = (pageList, startPage, startSegmentIndex) => { + if (startSegmentIndex > 0) { + return { page: startPage, segmentIndex: startSegmentIndex - 1 }; + } + const previousPage = findLast(pageList, (x) => x.headerStartPos < startPage.headerStartPos); + if (!previousPage) { + return null; + } + return { page: previousPage, segmentIndex: previousPage.lacingValues.length - 1 }; +}; +var WaveFormat; +(function(WaveFormat2) { + WaveFormat2[WaveFormat2["PCM"] = 1] = "PCM"; + WaveFormat2[WaveFormat2["IEEE_FLOAT"] = 3] = "IEEE_FLOAT"; + WaveFormat2[WaveFormat2["ALAW"] = 6] = "ALAW"; + WaveFormat2[WaveFormat2["MULAW"] = 7] = "MULAW"; + WaveFormat2[WaveFormat2["EXTENSIBLE"] = 65534] = "EXTENSIBLE"; +})(WaveFormat || (WaveFormat = {})); +class WaveDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.dataStart = -1; + this.dataSize = -1; + this.audioInfo = null; + this.trackBackings = []; + this.lastKnownPacketIndex = 0; + this.metadataTags = {}; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + let slice = this.reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + const riffType = readAscii(slice, 4); + const littleEndian = riffType !== "RIFX"; + const isRf64 = riffType === "RF64"; + const outerChunkSize = readU32(slice, littleEndian); + let totalFileSize = isRf64 ? this.reader.fileSize : Math.min(outerChunkSize + 8, this.reader.fileSize ?? Infinity); + const format = readAscii(slice, 4); + if (format !== "WAVE") { + throw new Error("Invalid WAVE file - wrong format"); + } + let chunksRead = 0; + let dataChunkSize = null; + let currentPos = slice.filePos; + while (totalFileSize === null || currentPos < totalFileSize) { + let slice2 = this.reader.requestSlice(currentPos, 8); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const chunkId = readAscii(slice2, 4); + const chunkSize = readU32(slice2, littleEndian); + const startPos = slice2.filePos; + if (isRf64 && chunksRead === 0 && chunkId !== "ds64") { + throw new Error('Invalid RF64 file: First chunk must be "ds64".'); + } + if (chunkId === "fmt ") { + await this.parseFmtChunk(startPos, chunkSize, littleEndian); + } else if (chunkId === "data") { + dataChunkSize ?? (dataChunkSize = chunkSize); + this.dataStart = slice2.filePos; + this.dataSize = Math.min(dataChunkSize, (totalFileSize ?? Infinity) - this.dataStart); + if (this.reader.fileSize === null) { + break; + } + } else if (chunkId === "ds64") { + let ds64Slice = this.reader.requestSlice(startPos, chunkSize); + if (ds64Slice instanceof Promise) + ds64Slice = await ds64Slice; + if (!ds64Slice) + break; + const riffChunkSize = readU64(ds64Slice, littleEndian); + dataChunkSize = readU64(ds64Slice, littleEndian); + totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity); + } else if (chunkId === "LIST") { + await this.parseListChunk(startPos, chunkSize, littleEndian); + } else if (chunkId === "ID3 " || chunkId === "id3 ") { + await this.parseId3Chunk(startPos, chunkSize); + } + currentPos = startPos + chunkSize + (chunkSize & 1); + chunksRead++; + } + if (!this.audioInfo) { + throw new Error('Invalid WAVE file - missing "fmt " chunk'); + } + if (this.dataStart === -1) { + throw new Error('Invalid WAVE file - missing "data" chunk'); + } + const blockSize = this.audioInfo.blockSizeInBytes; + this.dataSize = Math.floor(this.dataSize / blockSize) * blockSize; + this.trackBackings.push(new WaveAudioTrackBacking(this)); + })()); + } + async parseFmtChunk(startPos, size, littleEndian) { + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + let formatTag = readU16(slice, littleEndian); + const numChannels = readU16(slice, littleEndian); + const sampleRate = readU32(slice, littleEndian); + slice.skip(4); + const blockAlign = readU16(slice, littleEndian); + let bitsPerSample; + if (size === 14) { + bitsPerSample = 8; + } else { + bitsPerSample = readU16(slice, littleEndian); + } + if (size >= 18 && formatTag !== 357) { + const cbSize = readU16(slice, littleEndian); + const remainingSize = size - 18; + const extensionSize = Math.min(remainingSize, cbSize); + if (extensionSize >= 22 && formatTag === WaveFormat.EXTENSIBLE) { + slice.skip(2 + 4); + const subFormat = readBytes(slice, 16); + formatTag = subFormat[0] | subFormat[1] << 8; + } + } + if (formatTag === WaveFormat.MULAW || formatTag === WaveFormat.ALAW) { + bitsPerSample = 8; + } + this.audioInfo = { + format: formatTag, + numberOfChannels: numChannels, + sampleRate, + sampleSizeInBytes: Math.ceil(bitsPerSample / 8), + blockSizeInBytes: blockAlign + }; + } + async parseListChunk(startPos, size, littleEndian) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + const infoType = readAscii(slice, 4); + if (infoType !== "INFO" && infoType !== "INF0") { + return; + } + let currentPos = slice.filePos; + while (currentPos <= startPos + size - 8) { + slice.filePos = currentPos; + const chunkName = readAscii(slice, 4); + const chunkSize = readU32(slice, littleEndian); + const bytes = readBytes(slice, chunkSize); + let stringLength = 0; + for (let i = 0; i < bytes.length; i++) { + if (bytes[i] === 0) { + break; + } + stringLength++; + } + const value = String.fromCharCode(...bytes.subarray(0, stringLength)); + (_a = this.metadataTags).raw ?? (_a.raw = {}); + this.metadataTags.raw[chunkName] = value; + switch (chunkName) { + case "INAM": + case "TITL": + { + (_b = this.metadataTags).title ?? (_b.title = value); + } + break; + case "TIT3": + { + (_c = this.metadataTags).description ?? (_c.description = value); + } + break; + case "IART": + { + (_d = this.metadataTags).artist ?? (_d.artist = value); + } + break; + case "IPRD": + { + (_e = this.metadataTags).album ?? (_e.album = value); + } + break; + case "IPRT": + case "ITRK": + case "TRCK": + { + const parts = value.split("/"); + const trackNum = Number.parseInt(parts[0], 10); + const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); + if (Number.isInteger(trackNum) && trackNum > 0) { + (_f = this.metadataTags).trackNumber ?? (_f.trackNumber = trackNum); + } + if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { + (_g = this.metadataTags).tracksTotal ?? (_g.tracksTotal = tracksTotal); + } + } + break; + case "ICRD": + case "IDIT": + { + const date = new Date(value); + if (!Number.isNaN(date.getTime())) { + (_h = this.metadataTags).date ?? (_h.date = date); + } + } + break; + case "YEAR": + { + const year = Number.parseInt(value, 10); + if (Number.isInteger(year) && year > 0) { + (_i = this.metadataTags).date ?? (_i.date = new Date(year, 0, 1)); + } + } + break; + case "IGNR": + case "GENR": + { + (_j = this.metadataTags).genre ?? (_j.genre = value); + } + break; + case "ICMT": + case "CMNT": + case "COMM": + { + (_k = this.metadataTags).comment ?? (_k.comment = value); + } + break; + } + currentPos += 8 + chunkSize + (chunkSize & 1); + } + } + async parseId3Chunk(startPos, size) { + let slice = this.reader.requestSlice(startPos, size); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return; + const id3V2Header = readId3V2Header(slice); + if (id3V2Header) { + const availableSize = size - ID3_V2_HEADER_SIZE; + id3V2Header.size = Math.min(id3V2Header.size, availableSize); + if (id3V2Header.size > 0) { + const contentSlice = slice.slice(startPos + ID3_V2_HEADER_SIZE, id3V2Header.size); + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + } + } + } + getCodec() { + assert(this.audioInfo); + if (this.audioInfo.format === WaveFormat.MULAW) { + return "ulaw"; + } + if (this.audioInfo.format === WaveFormat.ALAW) { + return "alaw"; + } + if (this.audioInfo.format === WaveFormat.PCM) { + if (this.audioInfo.sampleSizeInBytes === 1) { + return "pcm-u8"; + } else if (this.audioInfo.sampleSizeInBytes === 2) { + return "pcm-s16"; + } else if (this.audioInfo.sampleSizeInBytes === 3) { + return "pcm-s24"; + } else if (this.audioInfo.sampleSizeInBytes === 4) { + return "pcm-s32"; + } + } + if (this.audioInfo.format === WaveFormat.IEEE_FLOAT) { + if (this.audioInfo.sampleSizeInBytes === 4) { + return "pcm-f32"; + } + } + return null; + } + async getMimeType() { + return "audio/wav"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } +} +const PACKET_SIZE_IN_FRAMES = 2048; +class WaveAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getCodec() { + return this.demuxer.getCodec(); + } + getInternalCodecId() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.format; + } + async getDecoderConfig() { + const codec = this.demuxer.getCodec(); + if (!codec) { + return null; + } + assert(this.demuxer.audioInfo); + return { + codec, + numberOfChannels: this.demuxer.audioInfo.numberOfChannels, + sampleRate: this.demuxer.audioInfo.sampleRate + }; + } + getNumberOfChannels() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + getTimeResolution() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + assert(this.demuxer.dataSize !== -1); + return this.demuxer.dataSize / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getPacketAtIndex(packetIndex, options) { + assert(packetIndex >= 0); + assert(this.demuxer.audioInfo); + const startOffset = packetIndex * PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes; + if (startOffset >= this.demuxer.dataSize) { + return null; + } + const sizeInBytes = Math.min(PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes, this.demuxer.dataSize - startOffset); + if (this.demuxer.reader.fileSize === null) { + let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); + if (slice instanceof Promise) + slice = await slice; + assert(slice); + data = readBytes(slice, sizeInBytes); + } + const timestamp = packetIndex * PACKET_SIZE_IN_FRAMES / this.demuxer.audioInfo.sampleRate; + const duration = sizeInBytes / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; + this.demuxer.lastKnownPacketIndex = Math.max(packetIndex, this.demuxer.lastKnownPacketIndex); + return new EncodedPacket(data, "key", timestamp, duration, packetIndex, sizeInBytes); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getPacket(timestamp, options) { + assert(this.demuxer.audioInfo); + const packetIndex = Math.floor(Math.min(timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES, (this.demuxer.dataSize - 1) / (PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes))); + if (packetIndex < 0) { + return null; + } + const packet = await this.getPacketAtIndex(packetIndex, options); + if (packet) { + return packet; + } + if (packetIndex === 0) { + return null; + } + assert(this.demuxer.reader.fileSize === null); + let currentPacket = await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex, options); + while (currentPacket) { + const nextPacket = await this.getNextPacket(currentPacket, options); + if (!nextPacket) { + break; + } + currentPacket = nextPacket; + } + return currentPacket; + } + getNextPacket(packet, options) { + assert(this.demuxer.audioInfo); + const packetIndex = Math.round(packet.timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES); + return this.getPacketAtIndex(packetIndex + 1, options); + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } +} +const MIN_ADTS_FRAME_HEADER_SIZE = 7; +const MAX_ADTS_FRAME_HEADER_SIZE = 9; +const readAdtsFrameHeader = (slice) => { + const startPos = slice.filePos; + const bytes = readBytes(slice, 9); + const bitstream = new Bitstream(bytes); + const syncword = bitstream.readBits(12); + if (syncword !== 4095) { + return null; + } + bitstream.skipBits(1); + const layer = bitstream.readBits(2); + if (layer !== 0) { + return null; + } + const protectionAbsence = bitstream.readBits(1); + const objectType = bitstream.readBits(2) + 1; + const samplingFrequencyIndex = bitstream.readBits(4); + if (samplingFrequencyIndex === 15) { + return null; + } + bitstream.skipBits(1); + const channelConfiguration = bitstream.readBits(3); + if (channelConfiguration === 0) { + throw new Error("ADTS frames with channel configuration 0 are not supported."); + } + bitstream.skipBits(1); + bitstream.skipBits(1); + bitstream.skipBits(1); + bitstream.skipBits(1); + const frameLength = bitstream.readBits(13); + bitstream.skipBits(11); + const numberOfAacFrames = bitstream.readBits(2) + 1; + if (numberOfAacFrames !== 1) { + throw new Error("ADTS frames with more than one AAC frame are not supported."); + } + let crcCheck = null; + if (protectionAbsence === 1) { + slice.filePos -= 2; + } else { + crcCheck = bitstream.readBits(16); + } + return { + objectType, + samplingFrequencyIndex, + channelConfiguration, + frameLength, + numberOfAacFrames, + crcCheck, + startPos + }; +}; +const SAMPLES_PER_AAC_FRAME = 1024; +class AdtsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.firstFrameHeader = null; + this.loadedSamples = []; + this.metadataTags = null; + this.trackBackings = []; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.lastLoadedPos = 0; + this.nextTimestampInSamples = 0; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + while (!this.firstFrameHeader && !this.lastSampleLoaded) { + await this.advanceReader(); + } + assert(this.firstFrameHeader); + this.trackBackings = [new AdtsAudioTrackBacking(this)]; + })()); + } + async advanceReader() { + if (this.lastLoadedPos === 0) { + while (true) { + let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) { + this.lastSampleLoaded = true; + return; + } + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + this.lastLoadedPos = slice2.filePos + id3V2Header.size; + } + } + let slice = this.reader.requestSliceRange(this.lastLoadedPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + this.lastSampleLoaded = true; + return; + } + const header = readAdtsFrameHeader(slice); + if (!header) { + this.lastSampleLoaded = true; + return; + } + if (this.reader.fileSize !== null && header.startPos + header.frameLength > this.reader.fileSize) { + this.lastSampleLoaded = true; + return; + } + if (!this.firstFrameHeader) { + this.firstFrameHeader = header; + } + const sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; + assert(sampleRate !== void 0); + const sampleDuration = SAMPLES_PER_AAC_FRAME / sampleRate; + const sample = { + timestamp: this.nextTimestampInSamples / sampleRate, + duration: sampleDuration, + dataStart: header.startPos, + dataSize: header.frameLength + }; + this.loadedSamples.push(sample); + this.nextTimestampInSamples += SAMPLES_PER_AAC_FRAME; + this.lastLoadedPos = header.startPos + header.frameLength; + } + async getMimeType() { + return "audio/aac"; + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackings; + } + async getMetadataTags() { + const release = await this.readingMutex.acquire(); + try { + await this.readMetadata(); + if (this.metadataTags) { + return this.metadataTags; + } + this.metadataTags = {}; + let currentPos = 0; + while (true) { + let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + break; + const id3V2Header = readId3V2Header(headerSlice); + if (!id3V2Header) { + break; + } + let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); + if (contentSlice instanceof Promise) + contentSlice = await contentSlice; + if (!contentSlice) + break; + parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); + currentPos = headerSlice.filePos + id3V2Header.size; + } + return this.metadataTags; + } finally { + release(); + } + } +} +class AdtsAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getTimeResolution() { + const sampleRate = this.getSampleRate(); + return sampleRate / SAMPLES_PER_AAC_FRAME; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getCodec() { + return "aac"; + } + getInternalCodecId() { + assert(this.demuxer.firstFrameHeader); + return this.demuxer.firstFrameHeader.objectType; + } + getNumberOfChannels() { + assert(this.demuxer.firstFrameHeader); + const numberOfChannels = aacChannelMap[this.demuxer.firstFrameHeader.channelConfiguration]; + assert(numberOfChannels !== void 0); + return numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.firstFrameHeader); + const sampleRate = aacFrequencyTable[this.demuxer.firstFrameHeader.samplingFrequencyIndex]; + assert(sampleRate !== void 0); + return sampleRate; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.firstFrameHeader); + return { + codec: `mp4a.40.${this.demuxer.firstFrameHeader.objectType}`, + numberOfChannels: this.getNumberOfChannels(), + sampleRate: this.getSampleRate() + }; + } + async getPacketAtIndex(sampleIndex, options) { + if (sampleIndex === -1) { + return null; + } + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.dataSize); + } + return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); + } + getFirstPacket(options) { + return this.getPacketAtIndex(0, options); + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); + if (sampleIndex === -1) { + throw new Error("Packet was not created from this track."); + } + const nextIndex = sampleIndex + 1; + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + async getPacket(timestamp, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); + if (index === -1 && this.demuxer.loadedSamples.length > 0) { + return null; + } + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(index, options); + } + if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { + return this.getPacketAtIndex(index, options); + } + await this.demuxer.advanceReader(); + } + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } +} +const getBlockSizeOrUncommon = (bits) => { + if (bits === 0) { + return null; + } else if (bits === 1) { + return 192; + } else if (bits >= 2 && bits <= 5) { + return 144 * 2 ** bits; + } else if (bits === 6) { + return "uncommon-u8"; + } else if (bits === 7) { + return "uncommon-u16"; + } else if (bits >= 8 && bits <= 15) { + return 2 ** bits; + } else { + return null; + } +}; +const getSampleRateOrUncommon = (sampleRateBits, streamInfoSampleRate) => { + switch (sampleRateBits) { + case 0: + return streamInfoSampleRate; + case 1: + return 88200; + case 2: + return 176400; + case 3: + return 192e3; + case 4: + return 8e3; + case 5: + return 16e3; + case 6: + return 22050; + case 7: + return 24e3; + case 8: + return 32e3; + case 9: + return 44100; + case 10: + return 48e3; + case 11: + return 96e3; + case 12: + return "uncommon-u8"; + case 13: + return "uncommon-u16"; + case 14: + return "uncommon-u16-10"; + default: + return null; + } +}; +const readCodedNumber = (fileSlice) => { + let ones = 0; + const bitstream1 = new Bitstream(readBytes(fileSlice, 1)); + while (bitstream1.readBits(1) === 1) { + ones++; + } + if (ones === 0) { + return bitstream1.readBits(7); + } + const bitArray = []; + const extraBytes = ones - 1; + const bitstream2 = new Bitstream(readBytes(fileSlice, extraBytes)); + const firstByteBits = 8 - ones - 1; + for (let i = 0; i < firstByteBits; i++) { + bitArray.unshift(bitstream1.readBits(1)); + } + for (let i = 0; i < extraBytes; i++) { + for (let j = 0; j < 8; j++) { + const val = bitstream2.readBits(1); + if (j < 2) { + continue; + } + bitArray.unshift(val); + } + } + const encoded = bitArray.reduce((acc, bit, index) => { + return acc | bit << index; + }, 0); + return encoded; +}; +const readBlockSize = (slice, blockSizeBits) => { + if (blockSizeBits === "uncommon-u16") { + return readU16Be(slice) + 1; + } else if (blockSizeBits === "uncommon-u8") { + return readU8(slice) + 1; + } else if (typeof blockSizeBits === "number") { + return blockSizeBits; + } else { + assertNever(blockSizeBits); + assert(false); + } +}; +const readSampleRate = (slice, sampleRateOrUncommon) => { + if (sampleRateOrUncommon === "uncommon-u16") { + return readU16Be(slice); + } + if (sampleRateOrUncommon === "uncommon-u16-10") { + return readU16Be(slice) * 10; + } + if (sampleRateOrUncommon === "uncommon-u8") { + return readU8(slice); + } + if (typeof sampleRateOrUncommon === "number") { + return sampleRateOrUncommon; + } + return null; +}; +const calculateCrc8 = (data) => { + const polynomial = 7; + let crc = 0; + for (const byte of data) { + crc ^= byte; + for (let i = 0; i < 8; i++) { + if ((crc & 128) !== 0) { + crc = crc << 1 ^ polynomial; + } else { + crc <<= 1; + } + crc &= 255; + } + } + return crc; +}; +class FlacDemuxer extends Demuxer { + constructor(input) { + super(input); + this.loadedSamples = []; + this.metadataPromise = null; + this.trackBacking = null; + this.metadataTags = {}; + this.audioInfo = null; + this.lastLoadedPos = null; + this.blockingBit = null; + this.readingMutex = new AsyncMutex(); + this.lastSampleLoaded = false; + this.reader = input._reader; + } + async getMetadataTags() { + await this.readMetadata(); + return this.metadataTags; + } + async getTrackBackings() { + await this.readMetadata(); + assert(this.trackBacking); + return [this.trackBacking]; + } + async getMimeType() { + return "audio/flac"; + } + async readMetadata() { + let currentPos = 4; + return this.metadataPromise ?? (this.metadataPromise = (async () => { + var _a; + while (this.reader.fileSize === null || currentPos < this.reader.fileSize) { + let sizeSlice = this.reader.requestSlice(currentPos, 4); + if (sizeSlice instanceof Promise) + sizeSlice = await sizeSlice; + currentPos += 4; + if (sizeSlice === null) { + throw new Error(`Metadata block at position ${currentPos} is too small! Corrupted file.`); + } + assert(sizeSlice); + const byte = readU8(sizeSlice); + const size = readU24Be(sizeSlice); + const isLastMetadata = (byte & 128) !== 0; + const metaBlockType = byte & 127; + switch (metaBlockType) { + case FlacBlockType.STREAMINFO: { + let streamInfoBlock = this.reader.requestSlice(currentPos, size); + if (streamInfoBlock instanceof Promise) + streamInfoBlock = await streamInfoBlock; + assert(streamInfoBlock); + if (streamInfoBlock === null) { + throw new Error(`StreamInfo block at position ${currentPos} is too small! Corrupted file.`); + } + const streamInfoBytes = readBytes(streamInfoBlock, 34); + const bitstream = new Bitstream(streamInfoBytes); + const minimumBlockSize = bitstream.readBits(16); + const maximumBlockSize = bitstream.readBits(16); + const minimumFrameSize = bitstream.readBits(24); + const maximumFrameSize = bitstream.readBits(24); + const sampleRate = bitstream.readBits(20); + const numberOfChannels = bitstream.readBits(3) + 1; + bitstream.readBits(5); + const totalSamples = bitstream.readBits(36); + bitstream.skipBits(16 * 8); + const description = new Uint8Array(42); + description.set(new Uint8Array([102, 76, 97, 67]), 0); + description.set(new Uint8Array([128, 0, 0, 34]), 4); + description.set(streamInfoBytes, 8); + this.audioInfo = { + numberOfChannels, + sampleRate, + totalSamples, + minimumBlockSize, + maximumBlockSize, + minimumFrameSize, + maximumFrameSize, + description + }; + this.trackBacking = new FlacAudioTrackBacking(this); + break; + } + case FlacBlockType.VORBIS_COMMENT: { + let vorbisCommentBlock = this.reader.requestSlice(currentPos, size); + if (vorbisCommentBlock instanceof Promise) + vorbisCommentBlock = await vorbisCommentBlock; + assert(vorbisCommentBlock); + readVorbisComments(readBytes(vorbisCommentBlock, size), this.metadataTags); + break; + } + case FlacBlockType.PICTURE: { + let pictureBlock = this.reader.requestSlice(currentPos, size); + if (pictureBlock instanceof Promise) + pictureBlock = await pictureBlock; + assert(pictureBlock); + const pictureType = readU32Be(pictureBlock); + const mediaTypeLength = readU32Be(pictureBlock); + const mediaType = textDecoder.decode(readBytes(pictureBlock, mediaTypeLength)); + const descriptionLength = readU32Be(pictureBlock); + const description = textDecoder.decode(readBytes(pictureBlock, descriptionLength)); + pictureBlock.skip(4 + 4 + 4 + 4); + const dataLength = readU32Be(pictureBlock); + const data = readBytes(pictureBlock, dataLength); + (_a = this.metadataTags).images ?? (_a.images = []); + this.metadataTags.images.push({ + data, + mimeType: mediaType, + // https://www.rfc-editor.org/rfc/rfc9639.html#table13 + kind: pictureType === 3 ? "coverFront" : pictureType === 4 ? "coverBack" : "unknown", + description + }); + break; + } + } + currentPos += size; + if (isLastMetadata) { + this.lastLoadedPos = currentPos; + break; + } + } + if (!this.audioInfo) { + throw new Error("Missing STREAMINFO metadata block! Corrupted FLAC file."); + } + })()); + } + async readNextFlacFrame({ startPos, isFirstPacket }) { + assert(this.audioInfo); + const minimumHeaderLength = 6; + const maximumHeaderLength = 16; + const minimumFrameLength = 10; + const maximumFrameLength = this.audioInfo.maximumBlockSize * this.audioInfo.numberOfChannels * 4 + maximumHeaderLength + 2; + const effectiveMinFrameSize = this.audioInfo.minimumFrameSize || minimumFrameLength; + const effectiveMaxFrameSize = this.audioInfo.maximumFrameSize || maximumFrameLength; + const maximumSliceLength = effectiveMaxFrameSize + maximumHeaderLength; + const slice = await this.reader.requestSliceRange(startPos, maximumHeaderLength, maximumSliceLength); + if (!slice) { + return null; + } + const frameHeader = this.readFlacFrameHeader({ + slice, + isFirstPacket + }); + if (!frameHeader) { + return null; + } + slice.filePos = startPos + effectiveMinFrameSize; + while (true) { + if (slice.filePos > slice.end - minimumHeaderLength) { + return { + num: frameHeader.num, + blockSize: frameHeader.blockSize, + sampleRate: frameHeader.sampleRate, + size: slice.end - startPos, + isLastFrame: true + }; + } + const nextByte = readU8(slice); + if (nextByte === 255) { + const positionBeforeReading = slice.filePos; + const byteAfterNextByte = readU8(slice); + const expected = this.blockingBit === 1 ? 249 : 248; + if (byteAfterNextByte !== expected) { + slice.filePos = positionBeforeReading; + continue; + } + slice.skip(-2); + const lengthIfNextFlacFrameHeaderIsLegit = slice.filePos - startPos; + const nextFrameHeader = this.readFlacFrameHeader({ + slice, + isFirstPacket: false + }); + if (!nextFrameHeader) { + slice.filePos = positionBeforeReading; + continue; + } + if (this.blockingBit === 0) { + if (nextFrameHeader.num - frameHeader.num !== 1) { + slice.filePos = positionBeforeReading; + continue; + } + } else { + if (nextFrameHeader.num - frameHeader.num !== frameHeader.blockSize) { + slice.filePos = positionBeforeReading; + continue; + } + } + return { + num: frameHeader.num, + blockSize: frameHeader.blockSize, + sampleRate: frameHeader.sampleRate, + size: lengthIfNextFlacFrameHeaderIsLegit, + isLastFrame: false + }; + } + } + } + readFlacFrameHeader({ slice, isFirstPacket }) { + const startOffset = slice.filePos; + const bytes = readBytes(slice, 4); + const bitstream = new Bitstream(bytes); + const bits = bitstream.readBits(15); + if (bits !== 32764) { + return null; + } + if (this.blockingBit === null) { + assert(isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + this.blockingBit = newBlockingBit; + } else if (this.blockingBit === 1) { + assert(!isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + if (newBlockingBit !== 1) { + return null; + } + } else if (this.blockingBit === 0) { + assert(!isFirstPacket); + const newBlockingBit = bitstream.readBits(1); + if (newBlockingBit !== 0) { + return null; + } + } else { + throw new Error("Invalid blocking bit"); + } + const blockSizeOrUncommon = getBlockSizeOrUncommon(bitstream.readBits(4)); + if (!blockSizeOrUncommon) { + return null; + } + assert(this.audioInfo); + const sampleRateOrUncommon = getSampleRateOrUncommon(bitstream.readBits(4), this.audioInfo.sampleRate); + if (!sampleRateOrUncommon) { + return null; + } + bitstream.readBits(4); + bitstream.readBits(3); + const reservedZero = bitstream.readBits(1); + if (reservedZero !== 0) { + return null; + } + const num = readCodedNumber(slice); + const blockSize = readBlockSize(slice, blockSizeOrUncommon); + const sampleRate = readSampleRate(slice, sampleRateOrUncommon); + if (sampleRate === null) { + return null; + } + if (sampleRate !== this.audioInfo.sampleRate) { + return null; + } + const size = slice.filePos - startOffset; + const crc = readU8(slice); + slice.skip(-size); + slice.skip(-1); + const crcCalculated = calculateCrc8(readBytes(slice, size)); + if (crc !== crcCalculated) { + return null; + } + return { num, blockSize, sampleRate }; + } + async advanceReader() { + await this.readMetadata(); + assert(this.lastLoadedPos !== null); + assert(this.audioInfo); + const startPos = this.lastLoadedPos; + const frame = await this.readNextFlacFrame({ + startPos, + isFirstPacket: this.loadedSamples.length === 0 + }); + if (!frame) { + this.lastSampleLoaded = true; + return; + } + const lastSample = this.loadedSamples[this.loadedSamples.length - 1]; + const blockOffset = lastSample ? lastSample.blockOffset + lastSample.blockSize : 0; + const sample = { + blockOffset, + blockSize: frame.blockSize, + byteOffset: startPos, + byteSize: frame.size + }; + this.lastLoadedPos = this.lastLoadedPos + frame.size; + this.loadedSamples.push(sample); + if (frame.isLastFrame) { + this.lastSampleLoaded = true; + return; + } + } +} +class FlacAudioTrackBacking { + constructor(demuxer) { + this.demuxer = demuxer; + } + getType() { + return "audio"; + } + getId() { + return 1; + } + getNumber() { + return 1; + } + getCodec() { + return "flac"; + } + getInternalCodecId() { + return null; + } + getNumberOfChannels() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.numberOfChannels; + } + getSampleRate() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getTimeResolution() { + assert(this.demuxer.audioInfo); + return this.demuxer.audioInfo.sampleRate; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + assert(this.demuxer.audioInfo); + if (this.demuxer.audioInfo.totalSamples === 0) { + return null; + } + return this.demuxer.audioInfo.totalSamples / this.demuxer.audioInfo.sampleRate; + } + async getLiveRefreshInterval() { + return null; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION + }; + } + async getDecoderConfig() { + assert(this.demuxer.audioInfo); + return { + codec: "flac", + numberOfChannels: this.demuxer.audioInfo.numberOfChannels, + sampleRate: this.demuxer.audioInfo.sampleRate, + description: this.demuxer.audioInfo.description + }; + } + async getPacket(timestamp, options) { + assert(this.demuxer.audioInfo); + if (timestamp < 0) { + throw new Error("Timestamp cannot be negative"); + } + const release = await this.demuxer.readingMutex.acquire(); + try { + while (true) { + const packetIndex = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.blockOffset / this.demuxer.audioInfo.sampleRate); + if (packetIndex === -1) { + await this.demuxer.advanceReader(); + continue; + } + const packet = this.demuxer.loadedSamples[packetIndex]; + const sampleTimestamp = packet.blockOffset / this.demuxer.audioInfo.sampleRate; + const sampleDuration = packet.blockSize / this.demuxer.audioInfo.sampleRate; + if (sampleTimestamp + sampleDuration <= timestamp) { + if (this.demuxer.lastSampleLoaded) { + return this.getPacketAtIndex(this.demuxer.loadedSamples.length - 1, options); + } + await this.demuxer.advanceReader(); + continue; + } + return this.getPacketAtIndex(packetIndex, options); + } + } finally { + release(); + } + } + async getNextPacket(packet, options) { + const release = await this.demuxer.readingMutex.acquire(); + try { + const nextIndex = packet.sequenceNumber + 1; + if (this.demuxer.lastSampleLoaded && nextIndex >= this.demuxer.loadedSamples.length) { + return null; + } + while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(nextIndex, options); + } finally { + release(); + } + } + getKeyPacket(timestamp, options) { + return this.getPacket(timestamp, options); + } + getNextKeyPacket(packet, options) { + return this.getNextPacket(packet, options); + } + async getPacketAtIndex(sampleIndex, options) { + const rawSample = this.demuxer.loadedSamples[sampleIndex]; + if (!rawSample) { + return null; + } + let data; + if (options.metadataOnly) { + data = PLACEHOLDER_DATA; + } else { + let slice = this.demuxer.reader.requestSlice(rawSample.byteOffset, rawSample.byteSize); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + data = readBytes(slice, rawSample.byteSize); + } + assert(this.demuxer.audioInfo); + const timestamp = rawSample.blockOffset / this.demuxer.audioInfo.sampleRate; + const duration = rawSample.blockSize / this.demuxer.audioInfo.sampleRate; + return new EncodedPacket(data, "key", timestamp, duration, sampleIndex, rawSample.byteSize); + } + async getFirstPacket(options) { + while (this.demuxer.loadedSamples.length === 0 && !this.demuxer.lastSampleLoaded) { + await this.demuxer.advanceReader(); + } + return this.getPacketAtIndex(0, options); + } +} +const TIMESCALE = 9e4; +const TS_PACKET_SIZE = 188; +const buildMpegTsMimeType = (codecStrings) => { + let string = "video/MP2T"; + const uniqueCodecStrings = [...new Set(codecStrings.filter(Boolean))]; + if (uniqueCodecStrings.length > 0) { + string += `; codecs="${uniqueCodecStrings.join(", ")}"`; + } + return string; +}; +const MISSING_PTS_ERROR_MESSAGE = "PES packet is missing PTS where it was expected. PES packets without PTS are not currently supported. If you think this file should be supported, please report it."; +const ignoredStreamTypes = /* @__PURE__ */ new Set(); +class MpegTsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.elementaryStreams = []; + this.trackBackingEntries = []; + this.packetOffset = 0; + this.packetStride = -1; + this.sectionEndPositions = []; + this.seekChunkSize = 5 * 1024 * 1024; + this.minReferencePointByteDistance = -1; + this.reader = input._reader; + } + async readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + const lengthToCheck = TS_PACKET_SIZE + 16 + 1; + let startingSlice = this.reader.requestSlice(0, lengthToCheck); + if (startingSlice instanceof Promise) + startingSlice = await startingSlice; + assert(startingSlice); + const startingBytes = readBytes(startingSlice, lengthToCheck); + if (startingBytes[0] === 71 && startingBytes[TS_PACKET_SIZE] === 71) { + this.packetOffset = 0; + this.packetStride = TS_PACKET_SIZE; + } else if (startingBytes[0] === 71 && startingBytes[TS_PACKET_SIZE + 16] === 71) { + this.packetOffset = 0; + this.packetStride = TS_PACKET_SIZE + 16; + } else if (startingBytes[4] === 71 && startingBytes[4 + TS_PACKET_SIZE + 4] === 71) { + this.packetOffset = 4; + this.packetStride = TS_PACKET_SIZE + 4; + } else { + throw new Error("Unreachable."); + } + const MIN_REFERENCE_POINT_PACKET_DISTANCE = 256; + this.minReferencePointByteDistance = MIN_REFERENCE_POINT_PACKET_DISTANCE * this.packetStride; + let currentPos = this.packetOffset; + let programMapPid = null; + let hasProgramAssociationTable = false; + let hasProgramMap = false; + while (true) { + const packetHeader = await this.readPacketHeader(currentPos); + if (!packetHeader) { + break; + } + if (packetHeader.payloadUnitStartIndicator === 0) { + currentPos += this.packetStride; + continue; + } + const section = await this.readSection(currentPos, true, !hasProgramMap); + if (!section) { + break; + } + const BYTES_BEFORE_SECTION_LENGTH = 3; + const BITS_IN_CRC_32 = 32; + let isProbablyProgramMap = false; + if (!hasProgramMap && section.pid !== 0) { + const isPesPacket = section.payload[0] === 0 && section.payload[1] === 0 && section.payload[2] === 1; + if (!isPesPacket) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + const tableId = bitstream.readBits(8); + isProbablyProgramMap = tableId === 2; + } + } + if (section.pid === 0 && !hasProgramAssociationTable) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + bitstream.skipBits(14); + const sectionLength = bitstream.readBits(10); + bitstream.skipBits(40); + while (8 * (sectionLength + BYTES_BEFORE_SECTION_LENGTH) - bitstream.pos > BITS_IN_CRC_32) { + const programNumber = bitstream.readBits(16); + bitstream.skipBits(3); + const id = bitstream.readBits(13); + if (programNumber !== 0) { + if (programMapPid !== null) { + throw new Error("Only files with a single program are supported."); + } else { + programMapPid = id; + } + } + } + if (programMapPid === null) { + throw new Error("Program Association Table must link to a Program Map Table."); + } + hasProgramAssociationTable = true; + } else if ((section.pid === programMapPid || isProbablyProgramMap) && !hasProgramMap) { + const bitstream = new Bitstream(section.payload); + const pointerField = bitstream.readAlignedByte(); + bitstream.skipBits(8 * pointerField); + bitstream.skipBits(12); + const sectionLength = bitstream.readBits(12); + bitstream.skipBits(43); + bitstream.readBits(13); + bitstream.skipBits(6); + const programInfoLength = bitstream.readBits(10); + bitstream.skipBits(8 * programInfoLength); + while (8 * (sectionLength + BYTES_BEFORE_SECTION_LENGTH) - bitstream.pos > BITS_IN_CRC_32) { + const streamType = bitstream.readBits(8); + bitstream.skipBits(3); + const elementaryPid = bitstream.readBits(13); + bitstream.skipBits(6); + const esInfoLength = bitstream.readBits(10); + const esInfoEndPos = bitstream.pos + 8 * esInfoLength; + let hasAc3Descriptor = false; + let hasEac3Descriptor = false; + while (bitstream.pos < esInfoEndPos) { + const descriptorTag = bitstream.readBits(8); + const descriptorLength = bitstream.readBits(8); + if (descriptorTag === 106) { + hasAc3Descriptor = true; + } else if (descriptorTag === 122 || descriptorTag === 204) { + hasEac3Descriptor = true; + } + bitstream.skipBits(8 * descriptorLength); + } + let info = null; + switch (streamType) { + case 27: + case 36: + { + const codec = streamType === 27 ? "avc" : "hevc"; + info = { + type: "video", + codec, + decoderConfig: null, + avcCodecInfo: null, + hevcCodecInfo: null, + colorSpace: { + primaries: null, + transfer: null, + matrix: null, + fullRange: null + }, + width: -1, + height: -1, + squarePixelWidth: -1, + squarePixelHeight: -1, + reorderSize: -1 + }; + } + break; + case 3: + case 4: + case 15: + case 129: + case 135: + { + let codec; + if (streamType === 3 || streamType === 4) { + codec = "mp3"; + } else if (streamType === 15) { + codec = "aac"; + } else if (streamType === 129) { + codec = "ac3"; + } else if (streamType === 135) { + codec = "eac3"; + } else { + throw new Error("Unreachable."); + } + info = { + type: "audio", + codec, + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } + break; + case 6: + { + if (hasEac3Descriptor) { + info = { + type: "audio", + codec: "eac3", + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } else if (hasAc3Descriptor) { + info = { + type: "audio", + codec: "ac3", + decoderConfig: null, + aacCodecInfo: null, + numberOfChannels: -1, + sampleRate: -1 + }; + } + } + break; + default: { + if (!ignoredStreamTypes.has(streamType)) { + console.warn(`Note: MPEG-TS streams with stream_type 0x${streamType.toString(16)} are not currently supported.`); + ignoredStreamTypes.add(streamType); + } + } + } + if (info) { + this.elementaryStreams.push({ + demuxer: this, + pid: elementaryPid, + streamType, + initialized: false, + firstSection: null, + canBeTrustedWithKeyPackets: false, + info, + referencePesPackets: [] + }); + } + } + hasProgramMap = true; + } else { + const elementaryStream = this.elementaryStreams.find((x) => x.pid === section.pid); + outer: if (elementaryStream && !elementaryStream.initialized) { + const pesPacket = readPesPacket(section, true); + if (!pesPacket) { + throw new Error(`Couldn't read first PES packet for Elementary Stream with PID ${elementaryStream.pid}`); + } + elementaryStream.firstSection = section; + elementaryStream.canBeTrustedWithKeyPackets = section.randomAccessIndicator === 1; + if (this.input._initInput) { + const initDemuxer = await this.input._initInput._getDemuxer(); + const matchingStream = initDemuxer.elementaryStreams.find((x) => x.pid === section.pid && x.info.codec === elementaryStream.info.codec); + if (matchingStream) { + elementaryStream.info = matchingStream.info; + elementaryStream.initialized = true; + break outer; + } + } + const context = new PacketReadingContext(elementaryStream, pesPacket); + if (elementaryStream.info.type === "video") { + while (true) { + const contextAlias = context; + contextAlias.suppliedPacket = null; + await context.markNextPacket(); + if (elementaryStream.info.codec === "avc") { + if (!context.suppliedPacket) { + throw new Error("Invalid AVC video stream; could not extract AVCDecoderConfigurationRecord from any packet."); + } + elementaryStream.info.avcCodecInfo = extractAvcDecoderConfigurationRecord(context.suppliedPacket.data); + if (!elementaryStream.info.avcCodecInfo) { + continue; + } + const spsUnit = elementaryStream.info.avcCodecInfo.sequenceParameterSets[0]; + assert(spsUnit); + const spsInfo = parseAvcSps(spsUnit); + elementaryStream.info.width = spsInfo.displayWidth; + elementaryStream.info.height = spsInfo.displayHeight; + const num = spsInfo.pixelAspectRatio.num; + const den = spsInfo.pixelAspectRatio.den; + if (num > 0 && den > 0) { + if (num > den) { + elementaryStream.info.squarePixelWidth = Math.round(elementaryStream.info.width * num / den); + elementaryStream.info.squarePixelHeight = elementaryStream.info.height; + } else { + elementaryStream.info.squarePixelWidth = elementaryStream.info.width; + elementaryStream.info.squarePixelHeight = Math.round(elementaryStream.info.height * den / num); + } + } + elementaryStream.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[spsInfo.transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[spsInfo.matrixCoefficients], + fullRange: !!spsInfo.fullRangeFlag + }; + elementaryStream.info.reorderSize = spsInfo.maxDecFrameBuffering; + break; + } else if (elementaryStream.info.codec === "hevc") { + if (!context.suppliedPacket) { + throw new Error("Invalid HEVC video stream; could not extract HVCDecoderConfigurationRecord from first packet."); + } + elementaryStream.info.hevcCodecInfo = extractHevcDecoderConfigurationRecord(context.suppliedPacket.data); + if (!elementaryStream.info.hevcCodecInfo) { + continue; + } + const spsArray = elementaryStream.info.hevcCodecInfo.arrays.find((a) => a.nalUnitType === HevcNalUnitType.SPS_NUT); + const spsUnit = spsArray.nalUnits[0]; + assert(spsUnit); + const spsInfo = parseHevcSps(spsUnit); + elementaryStream.info.width = spsInfo.displayWidth; + elementaryStream.info.height = spsInfo.displayHeight; + if (spsInfo.pixelAspectRatio.num > spsInfo.pixelAspectRatio.den) { + elementaryStream.info.squarePixelWidth = Math.round(elementaryStream.info.width * spsInfo.pixelAspectRatio.num / spsInfo.pixelAspectRatio.den); + elementaryStream.info.squarePixelHeight = elementaryStream.info.height; + } else { + elementaryStream.info.squarePixelWidth = elementaryStream.info.width; + elementaryStream.info.squarePixelHeight = Math.round(elementaryStream.info.height * spsInfo.pixelAspectRatio.den / spsInfo.pixelAspectRatio.num); + } + elementaryStream.info.colorSpace = { + primaries: COLOR_PRIMARIES_MAP_INVERSE[spsInfo.colourPrimaries], + transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[spsInfo.transferCharacteristics], + matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[spsInfo.matrixCoefficients], + fullRange: !!spsInfo.fullRangeFlag + }; + elementaryStream.info.reorderSize = spsInfo.maxDecFrameBuffering; + break; + } else { + throw new Error("Unhandled."); + } + } + elementaryStream.info.decoderConfig = { + codec: extractVideoCodecString({ + width: elementaryStream.info.width, + height: elementaryStream.info.height, + codec: elementaryStream.info.codec, + codecDescription: null, + colorSpace: elementaryStream.info.colorSpace, + avcType: 1, + avcCodecInfo: elementaryStream.info.avcCodecInfo, + hevcCodecInfo: elementaryStream.info.hevcCodecInfo, + vp9CodecInfo: null, + av1CodecInfo: null + }), + codedWidth: elementaryStream.info.width, + codedHeight: elementaryStream.info.height, + colorSpace: elementaryStream.info.colorSpace + }; + if (elementaryStream.info.width !== elementaryStream.info.squarePixelWidth || elementaryStream.info.height !== elementaryStream.info.squarePixelHeight) { + elementaryStream.info.decoderConfig.displayAspectWidth = elementaryStream.info.squarePixelWidth; + elementaryStream.info.decoderConfig.displayAspectHeight = elementaryStream.info.squarePixelHeight; + } + elementaryStream.initialized = true; + } else { + await context.markNextPacket(); + if (!context.suppliedPacket) { + throw new Error(`Couldn't parse first media packet for Elementary Stream with PID ${elementaryStream.pid}`); + } + if (elementaryStream.info.codec === "aac") { + const slice = FileSlice.tempFromBytes(context.suppliedPacket.data); + const header = readAdtsFrameHeader(slice); + if (!header) { + throw new Error("Invalid AAC audio stream; could not read ADTS frame header from first packet."); + } + elementaryStream.info.aacCodecInfo = { + isMpeg2: false, + objectType: header.objectType + }; + elementaryStream.info.numberOfChannels = aacChannelMap[header.channelConfiguration]; + elementaryStream.info.sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; + } else if (elementaryStream.info.codec === "mp3") { + const word = readU32Be(FileSlice.tempFromBytes(context.suppliedPacket.data)); + const result = readMp3FrameHeader(word, context.suppliedPacket.data.byteLength); + if (!result.header) { + throw new Error("Invalid MP3 audio stream; could not read frame header from first packet."); + } + elementaryStream.info.numberOfChannels = result.header.channel === 3 ? 1 : 2; + elementaryStream.info.sampleRate = result.header.sampleRate; + } else if (elementaryStream.info.codec === "ac3") { + const frameInfo = parseAc3SyncFrame(context.suppliedPacket.data); + if (!frameInfo) { + throw new Error("Invalid AC-3 audio stream; could not read sync frame from first packet."); + } + if (frameInfo.fscod === 3) { + throw new Error("Invalid AC-3 audio stream; reserved sample rate code found in first packet."); + } + elementaryStream.info.numberOfChannels = AC3_ACMOD_CHANNEL_COUNTS[frameInfo.acmod] + frameInfo.lfeon; + elementaryStream.info.sampleRate = AC3_SAMPLE_RATES[frameInfo.fscod]; + } else if (elementaryStream.info.codec === "eac3") { + const frameInfo = parseEac3SyncFrame(context.suppliedPacket.data); + if (!frameInfo) { + throw new Error("Invalid E-AC-3 audio stream; could not read sync frame from first packet."); + } + const sampleRate = getEac3SampleRate(frameInfo); + if (sampleRate === null) { + throw new Error("Invalid E-AC-3 audio stream; reserved sample rate code found in first packet."); + } + elementaryStream.info.numberOfChannels = getEac3ChannelCount(frameInfo); + elementaryStream.info.sampleRate = sampleRate; + } else { + throw new Error("Unhandled."); + } + elementaryStream.info.decoderConfig = { + codec: extractAudioCodecString({ + codec: elementaryStream.info.codec, + codecDescription: null, + aacCodecInfo: elementaryStream.info.aacCodecInfo + }), + numberOfChannels: elementaryStream.info.numberOfChannels, + sampleRate: elementaryStream.info.sampleRate + }; + elementaryStream.initialized = true; + } + } + } + const isDone = hasProgramMap && this.elementaryStreams.every((x) => x.initialized); + if (isDone) { + break; + } + currentPos += this.packetStride; + } + if (!hasProgramMap) { + if (!hasProgramAssociationTable) { + throw new Error("No Program Association Table found in the file."); + } + throw new Error("No Program Map Table found in the file."); + } + for (const stream of this.elementaryStreams) { + if (stream.info.type === "video") { + this.trackBackingEntries.push(new MpegTsVideoTrackBacking(stream)); + } else { + this.trackBackingEntries.push(new MpegTsAudioTrackBacking(stream)); + } + } + })()); + } + async getTrackBackings() { + await this.readMetadata(); + return this.trackBackingEntries; + } + async getMetadataTags() { + return {}; + } + async getMimeType() { + await this.readMetadata(); + const codecStrings = await Promise.all(this.trackBackingEntries.map((x) => x.getDecoderConfig().then((c) => c?.codec ?? null))); + return buildMpegTsMimeType(codecStrings); + } + async readSection(startPos, full, contiguous = false) { + let endPos = startPos; + let currentPos = startPos; + const chunks = []; + let chunksByteLength = 0; + let firstPacket = null; + let mustAddSectionEnd = true; + let randomAccessIndicator = 0; + while (true) { + const packet = await this.readPacket(currentPos); + currentPos += this.packetStride; + if (!packet) { + break; + } + if (!firstPacket) { + if (packet.payloadUnitStartIndicator === 0) { + break; + } + firstPacket = packet; + } else { + if (packet.pid !== firstPacket.pid) { + if (contiguous) { + break; + } else { + continue; + } + } + if (packet.payloadUnitStartIndicator === 1) { + break; + } + } + const hasAdaptationField = !!(packet.adaptationFieldControl & 2); + const hasPayload = !!(packet.adaptationFieldControl & 1); + let adaptationFieldLength = 0; + if (hasAdaptationField) { + adaptationFieldLength = 1 + packet.body[0]; + if (packet === firstPacket && adaptationFieldLength > 1) { + randomAccessIndicator = packet.body[1] >> 6 & 1; + } + } + if (hasPayload) { + if (adaptationFieldLength === 0) { + chunks.push(packet.body); + chunksByteLength += packet.body.byteLength; + } else { + chunks.push(packet.body.subarray(adaptationFieldLength)); + chunksByteLength += packet.body.byteLength - adaptationFieldLength; + } + } + endPos = currentPos; + if (!full && chunksByteLength >= 64) { + mustAddSectionEnd = false; + break; + } + const isKnownSectionEnd = binarySearchExact(this.sectionEndPositions, endPos, (x) => x) !== -1; + if (isKnownSectionEnd) { + mustAddSectionEnd = false; + break; + } + } + if (mustAddSectionEnd) { + const index = binarySearchLessOrEqual(this.sectionEndPositions, endPos, (x) => x); + this.sectionEndPositions.splice(index + 1, 0, endPos); + } + if (!firstPacket) { + return null; + } + let merged; + if (chunks.length === 1) { + merged = chunks[0]; + } else { + const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0); + merged = new Uint8Array(totalLength); + let offset = 0; + for (const chunk of chunks) { + merged.set(chunk, offset); + offset += chunk.length; + } + } + return { + startPos, + endPos: full ? endPos : null, + pid: firstPacket.pid, + payload: merged, + randomAccessIndicator + }; + } + async readPacketHeader(pos) { + let slice = this.reader.requestSlice(pos, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const syncByte = readU8(slice); + if (syncByte !== 71) { + throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file."); + } + const nextTwoBytes = readU16Be(slice); + const payloadUnitStartIndicator = nextTwoBytes >> 14 & 1; + const pid = nextTwoBytes & 8191; + const nextByte = readU8(slice); + const adaptationFieldControl = nextByte >> 4 & 3; + return { + payloadUnitStartIndicator, + pid, + adaptationFieldControl + }; + } + async readPacket(pos) { + let slice = this.reader.requestSlice(pos, TS_PACKET_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + return null; + } + const bytes = readBytes(slice, TS_PACKET_SIZE); + const syncByte = bytes[0]; + if (syncByte !== 71) { + throw new Error("Invalid TS packet sync byte. Likely an internal bug, please report this file."); + } + const nextTwoBytes = (bytes[1] << 8) + bytes[2]; + const payloadUnitStartIndicator = nextTwoBytes >> 14 & 1; + const pid = nextTwoBytes & 8191; + const nextByte = bytes[3]; + const adaptationFieldControl = nextByte >> 4 & 3; + return { + payloadUnitStartIndicator, + pid, + adaptationFieldControl, + body: bytes.subarray(4) + }; + } +} +const readPesPacketHeader = (section, expectPts) => { + if (section.payload.byteLength < 3) { + return null; + } + const bitstream = new Bitstream(section.payload); + const startCodePrefix = bitstream.readBits(24); + if (startCodePrefix !== 1) { + return null; + } + const streamId = bitstream.readBits(8); + bitstream.skipBits(16); + if (streamId === 188 || streamId === 190 || streamId === 191 || streamId === 240 || streamId === 241 || streamId === 255 || streamId === 242 || streamId === 248) { + return null; + } + bitstream.skipBits(8); + const ptsDtsFlags = bitstream.readBits(2); + bitstream.skipBits(14); + let pts = null; + if (ptsDtsFlags === 2 || ptsDtsFlags === 3) { + pts = 0; + bitstream.skipBits(4); + pts += bitstream.readBits(3) * (1 << 30); + bitstream.skipBits(1); + pts += bitstream.readBits(15) * (1 << 15); + bitstream.skipBits(1); + pts += bitstream.readBits(15); + } else { + if (expectPts) { + throw new Error(MISSING_PTS_ERROR_MESSAGE); + } + } + return { + sectionStartPos: section.startPos, + sectionEndPos: section.endPos, + pts, + randomAccessIndicator: section.randomAccessIndicator + }; +}; +const readPesPacket = (section, expectPts) => { + assert(section.endPos !== null); + const header = readPesPacketHeader(section, expectPts); + if (!header) { + return null; + } + const bitstream = new Bitstream(section.payload); + bitstream.skipBits(32); + const pesPacketLength = bitstream.readBits(16); + const BYTES_UNTIL_END_OF_PES_PACKET_LENGTH = 6; + bitstream.skipBits(16); + const pesHeaderDataLength = bitstream.readBits(8); + const pesHeaderEndPos = bitstream.pos + 8 * pesHeaderDataLength; + bitstream.pos = pesHeaderEndPos; + const bytePos = pesHeaderEndPos / 8; + assert(Number.isInteger(bytePos)); + const data = section.payload.subarray( + bytePos, + // "A value of 0 indicates that the PES packet length is neither specified nor bounded and is allowed only in + // PES packets whose payload consists of bytes from a video elementary stream contained in + // transport stream packets." + pesPacketLength > 0 ? BYTES_UNTIL_END_OF_PES_PACKET_LENGTH + pesPacketLength : section.payload.byteLength + ); + return { + ...header, + data + }; +}; +class MpegTsTrackBacking { + constructor(elementaryStream) { + this.elementaryStream = elementaryStream; + this.packetBuffers = /* @__PURE__ */ new WeakMap(); + this.packetSectionStarts = /* @__PURE__ */ new WeakMap(); + } + getId() { + return this.elementaryStream.pid; + } + getNumber() { + const demuxer = this.elementaryStream.demuxer; + const trackType = this.elementaryStream.info.type; + let number = 0; + for (const backing of demuxer.trackBackingEntries) { + if (backing.getType() === trackType) { + number++; + } + assert(backing instanceof MpegTsTrackBacking); + if (backing.elementaryStream === this.elementaryStream) { + break; + } + } + return number; + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getInternalCodecId() { + return this.elementaryStream.streamType; + } + getName() { + return null; + } + getLanguageCode() { + return UNDETERMINED_LANGUAGE; + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + primary: false + }; + } + getTimeResolution() { + return TIMESCALE; + } + isRelativeToUnixEpoch() { + return false; + } + getPairingMask() { + return 1n; + } + getBitrate() { + return null; + } + getAverageBitrate() { + return null; + } + async getDurationFromMetadata() { + return null; + } + async getLiveRefreshInterval() { + return null; + } + createEncodedPacket(suppliedPacket, duration, options) { + let packetType; + if (this.allPacketsAreKeyPackets()) { + packetType = "key"; + } else { + packetType = suppliedPacket.randomAccessIndicator === 1 ? "key" : "delta"; + } + return new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : suppliedPacket.data, packetType, suppliedPacket.pts / TIMESCALE, Math.max(duration / TIMESCALE, 0), suppliedPacket.sequenceNumber, suppliedPacket.data.byteLength); + } + async getFirstPacket(options) { + const section = this.elementaryStream.firstSection; + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + const buffer = new PacketBuffer(this, context); + const result = await buffer.readNext(); + if (!result) { + return null; + } + const packet = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(packet, buffer); + this.packetSectionStarts.set(packet, result.packet.sectionStartPos); + return packet; + } + async getNextPacket(packet, options) { + let buffer = this.packetBuffers.get(packet); + if (buffer) { + const result = await buffer.readNext(); + if (!result) { + return null; + } + this.packetBuffers.delete(packet); + const newPacket = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(newPacket, buffer); + this.packetSectionStarts.set(newPacket, result.packet.sectionStartPos); + return newPacket; + } + const sectionStartPos = this.packetSectionStarts.get(packet); + if (sectionStartPos === void 0) { + throw new Error("Packet was not created from this track."); + } + const demuxer = this.elementaryStream.demuxer; + const section = await demuxer.readSection(sectionStartPos, true); + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + buffer = new PacketBuffer(this, context); + const targetSequenceNumber = packet.sequenceNumber; + while (true) { + const result = await buffer.readNext(); + if (!result) { + return null; + } + if (result.packet.sequenceNumber > targetSequenceNumber) { + const newPacket = this.createEncodedPacket(result.packet, result.duration, options); + this.packetBuffers.set(newPacket, buffer); + this.packetSectionStarts.set(newPacket, result.packet.sectionStartPos); + return newPacket; + } + } + } + async getNextKeyPacket(packet, options) { + let currentPacket = packet; + while (true) { + currentPacket = await this.getNextPacket(currentPacket, options); + if (!currentPacket) { + return null; + } + if (currentPacket.type === "key") { + return currentPacket; + } + } + } + getPacket(timestamp, options) { + return this.doPacketLookup(timestamp, false, options); + } + getKeyPacket(timestamp, options) { + return this.doPacketLookup(timestamp, true, options); + } + /** + * Searches for the packet with the largest timestamp not larger than `timestamp` in the file, using a combination + * of chunk-based binary search and linear refinement. The reason the coarse search is done in large chunks is to + * make it more performant for small files and over high-latency readers such as the network. + */ + async doPacketLookup(timestamp, keyframesOnly, options) { + const searchPts = roundIfAlmostInteger(timestamp * TIMESCALE); + const demuxer = this.elementaryStream.demuxer; + const { reader, seekChunkSize } = demuxer; + const pid = this.elementaryStream.pid; + const findFirstPesPacketHeaderInChunk = async (startPos, endPos, readSectionInFull) => { + let currentPos = startPos; + while (currentPos < endPos) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + return null; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, readSectionInFull); + if (!section) { + return null; + } + const pesPacketHeader = readPesPacketHeader(section, false); + if (pesPacketHeader && pesPacketHeader.pts !== null) { + return { + pesPacketHeader, + section + }; + } + } + currentPos += demuxer.packetStride; + } + return null; + }; + const firstSection = this.elementaryStream.firstSection; + assert(firstSection); + const firstPesPacketHeader = readPesPacketHeader(firstSection, true); + assert(firstPesPacketHeader); + if (searchPts < firstPesPacketHeader.pts) { + return null; + } + let scanStartPos; + const referencePesPackets = this.elementaryStream.referencePesPackets; + const referencePointIndex = binarySearchLessOrEqual(referencePesPackets, searchPts, (x) => x.pts); + const referencePoint = referencePointIndex !== -1 ? referencePesPackets[referencePointIndex] : null; + if (referencePoint && searchPts - referencePoint.pts < TIMESCALE / 2) { + scanStartPos = referencePoint.sectionStartPos; + } else { + let startChunkIndex = 0; + if (reader.fileSize !== null) { + const numChunks = Math.ceil(reader.fileSize / seekChunkSize); + if (numChunks > 1) { + let low = 0; + let high = numChunks - 1; + startChunkIndex = low; + while (low <= high) { + const mid = Math.floor((low + high) / 2); + const chunkStartPos = floorToMultiple(mid * seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos; + const chunkEndPos = chunkStartPos + seekChunkSize; + const result2 = await findFirstPesPacketHeaderInChunk(chunkStartPos, chunkEndPos, false); + if (!result2) { + high = mid - 1; + continue; + } + if (result2.pesPacketHeader.pts <= searchPts) { + startChunkIndex = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + } + } + scanStartPos = floorToMultiple(startChunkIndex * seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos; + } + const result = await findFirstPesPacketHeaderInChunk(scanStartPos, reader.fileSize ?? Infinity, false); + let currentPesHeader = result?.pesPacketHeader ?? null; + if (!currentPesHeader) { + currentPesHeader = firstPesPacketHeader; + } + const reorderSize = this.getReorderSize(); + const retrieveEncodedPacket = async (sectionStartPos, predicate) => { + const section = await demuxer.readSection(sectionStartPos, true); + assert(section); + const pesPacket = readPesPacket(section, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + const buffer = new PacketBuffer(this, context); + while (true) { + const topPts = last(buffer.presentationOrderPackets)?.pts ?? -Infinity; + if (topPts >= searchPts) { + break; + } + const didRead = await buffer.readNextPacket(); + if (!didRead) { + break; + } + } + const targetIndex = findLastIndex(buffer.presentationOrderPackets, predicate); + if (targetIndex === -1) { + return null; + } + const targetPacket = buffer.presentationOrderPackets[targetIndex]; + const lastDuration = targetIndex === 0 ? 0 : targetPacket.pts - buffer.presentationOrderPackets[targetIndex - 1].pts; + while (buffer.decodeOrderPackets[0] !== targetPacket) { + buffer.decodeOrderPackets.shift(); + } + buffer.lastDuration = lastDuration; + const result2 = await buffer.readNext(); + assert(result2); + const packet = this.createEncodedPacket(result2.packet, result2.duration, options); + this.packetBuffers.set(packet, buffer); + this.packetSectionStarts.set(packet, result2.packet.sectionStartPos); + return packet; + }; + if (!keyframesOnly || this.allPacketsAreKeyPackets()) { + outer: while (true) { + let currentPos = currentPesHeader.sectionStartPos + demuxer.packetStride; + while (true) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, false); + if (section) { + const nextPesHeader = readPesPacketHeader(section, false); + if (nextPesHeader && nextPesHeader.pts !== null) { + if (nextPesHeader.pts > searchPts) { + break outer; + } + currentPesHeader = nextPesHeader; + maybeInsertReferencePacket(this.elementaryStream, currentPesHeader); + break; + } + } + } + currentPos += demuxer.packetStride; + } + } + outer: for (let i = 0; i < reorderSize + 1; i++) { + let pos = currentPesHeader.sectionStartPos - demuxer.packetStride; + while (pos >= demuxer.packetOffset) { + const packetHeader = await demuxer.readPacketHeader(pos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(pos, false); + if (section) { + const header = readPesPacketHeader(section, false); + if (header && header.pts !== null) { + currentPesHeader = header; + break; + } + } + } + pos -= demuxer.packetStride; + } + } + return retrieveEncodedPacket(currentPesHeader.sectionStartPos, (p) => p.pts <= searchPts); + } else { + let currentChunkStartPos = scanStartPos; + let nextChunkStartPos = null; + const readSectionsInFull = !this.elementaryStream.canBeTrustedWithKeyPackets; + while (true) { + let bestKeyPesHeader = null; + const isFirstChunk = currentChunkStartPos <= firstPesPacketHeader.sectionStartPos; + let pesHeader; + let pesHeaderSection = null; + if (isFirstChunk) { + pesHeader = firstPesPacketHeader; + pesHeaderSection = firstSection; + } else { + const result2 = await findFirstPesPacketHeaderInChunk(currentChunkStartPos, reader.fileSize ?? Infinity, readSectionsInFull); + pesHeader = result2?.pesPacketHeader ?? null; + pesHeaderSection = result2?.section ?? null; + } + let passedSearchPts = false; + let lookaheadCount = 0; + outer: while (pesHeader) { + if (nextChunkStartPos !== null && pesHeader.sectionStartPos >= nextChunkStartPos) { + break; + } + if (pesHeader.pts <= searchPts) { + let isKeyPacket; + if (this.elementaryStream.canBeTrustedWithKeyPackets) { + isKeyPacket = pesHeader.randomAccessIndicator === 1; + } else { + assert(pesHeaderSection); + const pesPacket = readPesPacket(pesHeaderSection, true); + assert(pesPacket); + const context = new PacketReadingContext(this.elementaryStream, pesPacket); + await context.markNextPacket(); + isKeyPacket = context.suppliedPacket?.randomAccessIndicator === 1; + } + if (isKeyPacket) { + bestKeyPesHeader = pesHeader; + } + } + if (pesHeader.pts > searchPts) { + passedSearchPts = true; + } + if (passedSearchPts) { + lookaheadCount++; + if (lookaheadCount > reorderSize) { + break; + } + } + let currentPos = pesHeader.sectionStartPos + demuxer.packetStride; + while (true) { + const packetHeader = await demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(currentPos, readSectionsInFull); + if (section) { + const nextPesHeader = readPesPacketHeader(section, false); + if (nextPesHeader && nextPesHeader.pts !== null) { + pesHeader = nextPesHeader; + pesHeaderSection = section; + maybeInsertReferencePacket(this.elementaryStream, pesHeader); + break; + } + } + } + currentPos += demuxer.packetStride; + } + } + if (bestKeyPesHeader) { + let startPesHeader = bestKeyPesHeader; + if (lookaheadCount === 0) { + outer: for (let i = 0; i < reorderSize; i++) { + let pos = startPesHeader.sectionStartPos - demuxer.packetStride; + while (pos >= demuxer.packetOffset) { + const packetHeader = await demuxer.readPacketHeader(pos); + if (!packetHeader) { + break outer; + } + if (packetHeader.pid === pid && packetHeader.payloadUnitStartIndicator === 1) { + const section = await demuxer.readSection(pos, readSectionsInFull); + if (section) { + const header = readPesPacketHeader(section, false); + if (header && header.pts !== null) { + startPesHeader = header; + break; + } + } + } + pos -= demuxer.packetStride; + } + } + } + const encodedPacket = await retrieveEncodedPacket(startPesHeader.sectionStartPos, (p) => p.pts <= searchPts && p.randomAccessIndicator === 1); + assert(encodedPacket); + return encodedPacket; + } + if (isFirstChunk) { + return null; + } + nextChunkStartPos = currentChunkStartPos; + currentChunkStartPos = Math.max(floorToMultiple(currentChunkStartPos - firstPesPacketHeader.sectionStartPos - seekChunkSize, demuxer.packetStride) + firstPesPacketHeader.sectionStartPos, firstPesPacketHeader.sectionStartPos); + } + } + } +} +class MpegTsVideoTrackBacking extends MpegTsTrackBacking { + getType() { + return "video"; + } + getCodec() { + return this.elementaryStream.info.codec; + } + getCodedWidth() { + return this.elementaryStream.info.width; + } + getCodedHeight() { + return this.elementaryStream.info.height; + } + getSquarePixelWidth() { + return this.elementaryStream.info.squarePixelWidth; + } + getSquarePixelHeight() { + return this.elementaryStream.info.squarePixelHeight; + } + getRotation() { + return 0; + } + async getColorSpace() { + return this.elementaryStream.info.colorSpace; + } + async canBeTransparent() { + return false; + } + async getDecoderConfig() { + assert(this.elementaryStream.info.decoderConfig); + return this.elementaryStream.info.decoderConfig; + } + allPacketsAreKeyPackets() { + return false; + } + getReorderSize() { + return this.elementaryStream.info.reorderSize; + } +} +class MpegTsAudioTrackBacking extends MpegTsTrackBacking { + getType() { + return "audio"; + } + getCodec() { + return this.elementaryStream.info.codec; + } + getNumberOfChannels() { + return this.elementaryStream.info.numberOfChannels; + } + getSampleRate() { + return this.elementaryStream.info.sampleRate; + } + async getDecoderConfig() { + assert(this.elementaryStream.info.decoderConfig); + return this.elementaryStream.info.decoderConfig; + } + allPacketsAreKeyPackets() { + return true; + } + getReorderSize() { + return 0; + } +} +const maybeInsertReferencePacket = (elementaryStream, pesPacketHeader) => { + const referencePesPackets = elementaryStream.referencePesPackets; + const index = binarySearchLessOrEqual(referencePesPackets, pesPacketHeader.sectionStartPos, (x) => x.sectionStartPos); + if (index >= 0) { + const entry = referencePesPackets[index]; + if (pesPacketHeader.pts <= entry.pts) { + return false; + } + const minByteDistance = elementaryStream.demuxer.minReferencePointByteDistance; + if (pesPacketHeader.sectionStartPos - entry.sectionStartPos < minByteDistance) { + return false; + } + if (index < referencePesPackets.length - 1) { + const nextEntry = referencePesPackets[index + 1]; + if (nextEntry.pts < pesPacketHeader.pts) { + return false; + } + if (nextEntry.sectionStartPos - pesPacketHeader.sectionStartPos < minByteDistance) { + return false; + } + } + } + referencePesPackets.splice(index + 1, 0, pesPacketHeader); + return true; +}; +class PacketReadingContext { + constructor(elementaryStream, startingPesPacket) { + this.currentPos = 0; + this.pesPackets = []; + this.currentPesPacketIndex = 0; + this.currentPesPacketPos = 0; + this.endPos = 0; + this.lastSuppliedPesPacket = null; + this.nextPts = null; + this.suppliedPacket = null; + this.elementaryStream = elementaryStream; + this.pid = elementaryStream.pid; + this.demuxer = elementaryStream.demuxer; + this.startingPesPacket = startingPesPacket; + } + ensureBuffered(length) { + const remaining = this.endPos - this.currentPos; + if (remaining >= length) { + return length; + } + return this.bufferData(length - remaining).then(() => Math.min(this.endPos - this.currentPos, length)); + } + getCurrentPesPacket() { + const packet = this.pesPackets[this.currentPesPacketIndex]; + assert(packet); + return packet; + } + async bufferData(length) { + const targetEndPos = this.endPos + length; + while (this.endPos < targetEndPos) { + let pesPacket; + if (this.pesPackets.length === 0) { + pesPacket = this.startingPesPacket; + } else { + let currentPos = last(this.pesPackets).sectionEndPos; + assert(currentPos !== null); + while (true) { + const packetHeader = await this.demuxer.readPacketHeader(currentPos); + if (!packetHeader) { + return; + } + if (packetHeader.pid === this.pid) { + const nextSection = await this.demuxer.readSection(currentPos, true); + if (!nextSection) { + return; + } + const nextPesPacket = readPesPacket(nextSection, false); + if (nextPesPacket) { + pesPacket = nextPesPacket; + break; + } + } + currentPos += this.demuxer.packetStride; + } + } + this.pesPackets.push(pesPacket); + this.endPos += pesPacket.data.byteLength; + } + } + readBytes(length) { + const currentPesPacket = this.getCurrentPesPacket(); + const relativeStartOffset = this.currentPos - this.currentPesPacketPos; + const relativeEndOffset = relativeStartOffset + length; + this.currentPos += length; + if (relativeEndOffset <= currentPesPacket.data.byteLength) { + return currentPesPacket.data.subarray(relativeStartOffset, relativeEndOffset); + } + const result = new Uint8Array(length); + result.set(currentPesPacket.data.subarray(relativeStartOffset)); + let offset = currentPesPacket.data.byteLength - relativeStartOffset; + while (true) { + this.advanceCurrentPacket(); + const currentPesPacket2 = this.getCurrentPesPacket(); + const relativeEndOffset2 = length - offset; + if (relativeEndOffset2 <= currentPesPacket2.data.byteLength) { + result.set(currentPesPacket2.data.subarray(0, relativeEndOffset2), offset); + break; + } + result.set(currentPesPacket2.data, offset); + offset += currentPesPacket2.data.byteLength; + } + return result; + } + readU8() { + let currentPesPacket = this.getCurrentPesPacket(); + const relativeOffset = this.currentPos - this.currentPesPacketPos; + this.currentPos++; + if (relativeOffset < currentPesPacket.data.byteLength) { + return currentPesPacket.data[relativeOffset]; + } + this.advanceCurrentPacket(); + currentPesPacket = this.getCurrentPesPacket(); + return currentPesPacket.data[0]; + } + seekTo(pos) { + if (pos === this.currentPos) { + return; + } + if (pos < this.currentPos) { + while (pos < this.currentPesPacketPos) { + this.currentPesPacketIndex--; + const currentPacket = this.getCurrentPesPacket(); + this.currentPesPacketPos -= currentPacket.data.byteLength; + } + } else { + while (true) { + const currentPesPacket = this.getCurrentPesPacket(); + const currentEndPos = this.currentPesPacketPos + currentPesPacket.data.byteLength; + if (pos < currentEndPos) { + break; + } + this.currentPesPacketPos += currentPesPacket.data.byteLength; + this.currentPesPacketIndex++; + } + } + this.currentPos = pos; + } + skip(n) { + this.seekTo(this.currentPos + n); + } + advanceCurrentPacket() { + this.currentPesPacketPos += this.getCurrentPesPacket().data.byteLength; + this.currentPesPacketIndex++; + } + async markNextPacket() { + assert(!this.suppliedPacket); + const elementaryStream = this.elementaryStream; + if (elementaryStream.info.type === "video") { + const codec = elementaryStream.info.codec; + const CHUNK_SIZE = 1024; + if (codec !== "avc" && codec !== "hevc") { + throw new Error("Unhandled."); + } + let packetStartPos = null; + while (true) { + let remaining = this.ensureBuffered(CHUNK_SIZE); + if (remaining instanceof Promise) + remaining = await remaining; + if (remaining === 0) { + break; + } + const chunkStartPos = this.currentPos; + const chunk = this.readBytes(remaining); + const length = chunk.byteLength; + let i = 0; + while (i < length) { + const zeroIndex = chunk.indexOf(0, i); + if (zeroIndex === -1 || zeroIndex >= length) { + break; + } + i = zeroIndex; + const posBeforeZero = chunkStartPos + i; + if (i + 4 >= length) { + this.seekTo(posBeforeZero); + break; + } + const b1 = chunk[i + 1]; + const b2 = chunk[i + 2]; + const b3 = chunk[i + 3]; + let startCodeLength = 0; + let nalUnitTypeByte = null; + if (b1 === 0 && b2 === 0 && b3 === 1) { + startCodeLength = 4; + nalUnitTypeByte = chunk[i + 4]; + } else if (b1 === 0 && b2 === 1) { + startCodeLength = 3; + nalUnitTypeByte = b3; + } + if (startCodeLength === 0) { + i++; + continue; + } + const startCodePos = posBeforeZero; + if (packetStartPos === null) { + packetStartPos = startCodePos; + i += startCodeLength; + continue; + } + if (nalUnitTypeByte !== null) { + const nalUnitType = codec === "avc" ? extractNalUnitTypeForAvc(nalUnitTypeByte) : extractNalUnitTypeForHevc(nalUnitTypeByte); + const isAud = codec === "avc" ? nalUnitType === AvcNalUnitType.AUD : nalUnitType === HevcNalUnitType.AUD_NUT; + if (isAud) { + const packetLength = startCodePos - packetStartPos; + this.seekTo(packetStartPos); + return this.supplyPacket(packetLength, 0); + } + } + i += startCodeLength; + } + if (remaining < CHUNK_SIZE) { + break; + } + } + if (packetStartPos !== null) { + const packetLength = this.endPos - packetStartPos; + this.seekTo(packetStartPos); + return this.supplyPacket(packetLength, 0); + } + } else { + const codec = elementaryStream.info.codec; + const CHUNK_SIZE = 128; + while (true) { + let remaining = this.ensureBuffered(CHUNK_SIZE); + if (remaining instanceof Promise) + remaining = await remaining; + const startPos = this.currentPos; + while (this.currentPos - startPos < remaining) { + const byte = this.readU8(); + if (codec === "aac") { + if (byte !== 255) { + continue; + } + this.skip(-1); + const possibleHeaderStartPos = this.currentPos; + let remaining2 = this.ensureBuffered(MAX_ADTS_FRAME_HEADER_SIZE); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < MAX_ADTS_FRAME_HEADER_SIZE) { + return; + } + const headerBytes = this.readBytes(MAX_ADTS_FRAME_HEADER_SIZE); + const header = readAdtsFrameHeader(FileSlice.tempFromBytes(headerBytes)); + if (header) { + this.seekTo(possibleHeaderStartPos); + let remaining3 = this.ensureBuffered(header.frameLength); + if (remaining3 instanceof Promise) + remaining3 = await remaining3; + return this.supplyPacket(remaining3, Math.round(SAMPLES_PER_AAC_FRAME * TIMESCALE / elementaryStream.info.sampleRate)); + } else { + this.seekTo(possibleHeaderStartPos + 1); + } + } else if (codec === "mp3") { + if (byte !== 255) { + continue; + } + this.skip(-1); + const possibleHeaderStartPos = this.currentPos; + let remaining2 = this.ensureBuffered(FRAME_HEADER_SIZE); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < FRAME_HEADER_SIZE) { + return; + } + const headerBytes = this.readBytes(FRAME_HEADER_SIZE); + const word = toDataView(headerBytes).getUint32(0); + const result = readMp3FrameHeader(word, null); + if (result.header) { + this.seekTo(possibleHeaderStartPos); + let remaining3 = this.ensureBuffered(result.header.totalSize); + if (remaining3 instanceof Promise) + remaining3 = await remaining3; + const duration = result.header.audioSamplesInFrame * TIMESCALE / elementaryStream.info.sampleRate; + return this.supplyPacket(remaining3, Math.round(duration)); + } else { + this.seekTo(possibleHeaderStartPos + 1); + } + } else if (codec === "ac3") { + if (byte !== 11) { + continue; + } + this.skip(-1); + const possibleSyncPos = this.currentPos; + let remaining2 = this.ensureBuffered(5); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < 5) { + return; + } + const headerBytes = this.readBytes(5); + if (headerBytes[0] !== 11 || headerBytes[1] !== 119) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const fscod = headerBytes[4] >> 6; + const frmsizecod = headerBytes[4] & 63; + if (fscod === 3 || frmsizecod > 37) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const frameSize = AC3_FRAME_SIZES[3 * frmsizecod + fscod]; + assert(frameSize !== void 0); + this.seekTo(possibleSyncPos); + remaining2 = this.ensureBuffered(frameSize); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + const duration = Math.round(AC3_SAMPLES_PER_FRAME * TIMESCALE / elementaryStream.info.sampleRate); + return this.supplyPacket(remaining2, duration); + } else if (codec === "eac3") { + if (byte !== 11) { + continue; + } + this.skip(-1); + const possibleSyncPos = this.currentPos; + let remaining2 = this.ensureBuffered(5); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + if (remaining2 < 5) { + return; + } + const headerBytes = this.readBytes(5); + if (headerBytes[0] !== 11 || headerBytes[1] !== 119) { + this.seekTo(possibleSyncPos + 1); + continue; + } + const frmsiz = (headerBytes[2] & 7) << 8 | headerBytes[3]; + const frameSize = (frmsiz + 1) * 2; + const fscod = headerBytes[4] >> 6; + const numblkscod = fscod === 3 ? 3 : headerBytes[4] >> 4 & 3; + const numblks = EAC3_NUMBLKS_TABLE[numblkscod]; + this.seekTo(possibleSyncPos); + remaining2 = this.ensureBuffered(frameSize); + if (remaining2 instanceof Promise) + remaining2 = await remaining2; + const samplesPerFrame = numblks * 256; + const duration = Math.round(samplesPerFrame * TIMESCALE / elementaryStream.info.sampleRate); + return this.supplyPacket(remaining2, duration); + } else { + throw new Error("Unhandled."); + } + } + if (remaining < CHUNK_SIZE) { + break; + } + } + } + } + /** Supplies the context with a new encoded packet, beginning at the current position. */ + supplyPacket(packetLength, intrinsicDuration) { + const currentPesPacket = this.getCurrentPesPacket(); + let pts; + if (this.lastSuppliedPesPacket === currentPesPacket) { + assert(this.nextPts !== null); + pts = this.nextPts; + } else { + if (currentPesPacket.pts === null) { + throw new Error(MISSING_PTS_ERROR_MESSAGE); + } + pts = currentPesPacket.pts; + maybeInsertReferencePacket(this.elementaryStream, currentPesPacket); + } + this.lastSuppliedPesPacket = currentPesPacket; + this.nextPts = pts + intrinsicDuration; + const sectionStartPos = currentPesPacket.sectionStartPos; + const sequenceNumber = sectionStartPos + (this.currentPos - this.currentPesPacketPos); + const data = this.readBytes(packetLength); + let randomAccessIndicator = currentPesPacket.randomAccessIndicator; + if (randomAccessIndicator === 0 && !this.elementaryStream.canBeTrustedWithKeyPackets) { + if (this.elementaryStream.info.type === "audio") { + randomAccessIndicator = 1; + } else { + if (this.elementaryStream.info.decoderConfig) { + const isKey = determineVideoPacketType(this.elementaryStream.info.codec, this.elementaryStream.info.decoderConfig, data) === "key"; + randomAccessIndicator = Number(isKey); + } + } + } + this.suppliedPacket = { + pts, + data, + sequenceNumber, + sectionStartPos, + randomAccessIndicator + }; + this.pesPackets.splice(0, this.currentPesPacketIndex); + this.currentPesPacketIndex = 0; + } +} +class PacketBuffer { + constructor(backing, context) { + this.decodeOrderPackets = []; + this.reorderBuffer = []; + this.presentationOrderPackets = []; + this.reachedEnd = false; + this.lastDuration = 0; + this.backing = backing; + this.context = context; + this.reorderSize = backing.getReorderSize(); + assert(this.reorderSize >= 0); + } + async readNext() { + if (this.decodeOrderPackets.length === 0) { + const didRead = await this.readNextPacket(); + if (!didRead) { + return null; + } + } + await this.ensureCurrentPacketHasNext(); + const packet = this.decodeOrderPackets[0]; + const presentationIndex = this.presentationOrderPackets.indexOf(packet); + assert(presentationIndex !== -1); + let duration; + if (presentationIndex === this.presentationOrderPackets.length - 1) { + duration = this.lastDuration; + } else { + const nextPacket = this.presentationOrderPackets[presentationIndex + 1]; + duration = nextPacket.pts - packet.pts; + this.lastDuration = duration; + } + this.decodeOrderPackets.shift(); + while (this.presentationOrderPackets.length > 0) { + const first = this.presentationOrderPackets[0]; + if (this.decodeOrderPackets.includes(first)) { + break; + } + this.presentationOrderPackets.shift(); + } + return { packet, duration }; + } + async readNextPacket() { + if (this.reachedEnd) { + return false; + } + let suppliedPacket; + if (this.context.suppliedPacket) { + suppliedPacket = this.context.suppliedPacket; + } else { + await this.context.markNextPacket(); + suppliedPacket = this.context.suppliedPacket; + } + this.context.suppliedPacket = null; + if (!suppliedPacket) { + this.reachedEnd = true; + this.flushReorderBuffer(); + return false; + } + this.decodeOrderPackets.push(suppliedPacket); + this.processPacketThroughReorderBuffer(suppliedPacket); + return true; + } + async ensureCurrentPacketHasNext() { + const current = this.decodeOrderPackets[0]; + assert(current); + while (true) { + const presentationIndex = this.presentationOrderPackets.indexOf(current); + if (presentationIndex !== -1 && presentationIndex <= this.presentationOrderPackets.length - 2) { + break; + } + const didRead = await this.readNextPacket(); + if (!didRead) { + break; + } + } + } + processPacketThroughReorderBuffer(packet) { + this.reorderBuffer.push(packet); + if (this.reorderBuffer.length > this.reorderSize) { + let minIndex = 0; + for (let i = 1; i < this.reorderBuffer.length; i++) { + if (this.reorderBuffer[i].pts < this.reorderBuffer[minIndex].pts) { + minIndex = i; + } + } + const packet2 = this.reorderBuffer[minIndex]; + this.presentationOrderPackets.push(packet2); + this.reorderBuffer.splice(minIndex, 1); + } + } + flushReorderBuffer() { + this.reorderBuffer.sort((a, b) => a.pts - b.pts); + this.presentationOrderPackets.push(...this.reorderBuffer); + this.reorderBuffer.length = 0; + } +} +const HLS_MIME_TYPE = "application/vnd.apple.mpegurl"; +const TAG_STREAM_INF = "#EXT-X-STREAM-INF:"; +const TAG_I_FRAME_STREAM_INF = "#EXT-X-I-FRAME-STREAM-INF:"; +const TAG_MEDIA = "#EXT-X-MEDIA:"; +const TAG_EXTINF = "#EXTINF:"; +const TAG_MAP = "#EXT-X-MAP:"; +const TAG_KEY = "#EXT-X-KEY:"; +const TAG_MEDIA_SEQUENCE = "#EXT-X-MEDIA-SEQUENCE:"; +const TAG_BYTERANGE = "#EXT-X-BYTERANGE:"; +const TAG_PROGRAM_DATE_TIME = "#EXT-X-PROGRAM-DATE-TIME:"; +const TAG_DISCONTINUITY = "#EXT-X-DISCONTINUITY"; +const TAG_TARGETDURATION = "#EXT-X-TARGETDURATION:"; +const TAG_ENDLIST = "#EXT-X-ENDLIST"; +const TAG_PLAYLIST_TYPE = "#EXT-X-PLAYLIST-TYPE:"; +const TAG_I_FRAMES_ONLY = "#EXT-X-I-FRAMES-ONLY"; +const canIgnoreLine = (line) => line.length === 0 || line.startsWith("#") && !line.startsWith("#EXT"); +class AttributeList { + constructor(str) { + this._attributes = {}; + let key = ""; + let value = ""; + let inValue = false; + let inQuotes = false; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + if (char === '"') { + inQuotes = !inQuotes; + } else if (char === "=" && !inValue && !inQuotes) { + inValue = true; + } else if (char === "," && !inQuotes) { + if (key) { + this._attributes[key.trim().toLowerCase()] = value; + } + key = ""; + value = ""; + inValue = false; + } else if (inValue) { + value += char; + } else { + key += char; + } + } + if (key) { + this._attributes[key.trim().toLowerCase()] = value; + } + } + get(name) { + return this._attributes[name.toLowerCase()] ?? null; + } + getAsNumber(name) { + const value = this.get(name); + if (value === null) { + return null; + } + const num = Number(value); + return Number.isFinite(num) ? num : null; + } + merge(other) { + Object.assign(this._attributes, other._attributes); + } +} +class SegmentedInput { + constructor(input, path, trackDeclarations) { + this.nextInputCacheAge = 0; + this.inputCache = []; + this.trackBackingsPromise = null; + this.firstSegment = null; + this.firstSegmentFirstTimestamps = /* @__PURE__ */ new WeakMap(); + this.firstTimestampCache = /* @__PURE__ */ new WeakMap(); + this.input = input; + this.path = path; + this.trackDeclarations = trackDeclarations; + } + async getDurationFromMetadata(options) { + const lastSegment = await this.getSegmentAt(Infinity, { + skipLiveWait: options.skipLiveWait + }); + if (!lastSegment) { + return null; + } + return lastSegment.timestamp + lastSegment.duration; + } + async getTrackBackings() { + return this.trackBackingsPromise ?? (this.trackBackingsPromise = (async () => { + const backings = []; + if (this.trackDeclarations) { + for (const decl of this.trackDeclarations) { + if (decl.type === "video") { + const number = arrayCount(backings, (x) => x.getType() === "video") + 1; + backings.push(new SegmentedInputInputVideoTrackBacking(this, decl, number)); + } else if (decl.type === "audio") { + const number = arrayCount(backings, (x) => x.getType() === "audio") + 1; + backings.push(new SegmentedInputInputAudioTrackBacking(this, decl, number)); + } + } + } else { + this.firstSegment = await this.getFirstSegment({}); + if (!this.firstSegment) { + return []; + } + const input = this.getInputForSegment(this.firstSegment); + const inputTracks = await input.getTracks(); + for (const track of inputTracks) { + if (track.type === "video") { + const number = arrayCount(backings, (x) => x.getType() === "video") + 1; + backings.push(new SegmentedInputInputVideoTrackBacking(this, { + id: backings.length + 1, + type: "video" + }, number)); + } else if (track.type === "audio") { + const number = arrayCount(backings, (x) => x.getType() === "audio") + 1; + backings.push(new SegmentedInputInputAudioTrackBacking(this, { + id: backings.length + 1, + type: "audio" + }, number)); + } + } + } + return backings; + })()); + } + // This operation is done a lot and can be semi-expensive, so it's good to have a cache for it + async getFirstTimestampForInput(input) { + const existing = this.firstTimestampCache.get(input); + if (existing !== void 0) { + return existing; + } + const firstTimestamp = await input.getFirstTimestamp(); + this.firstTimestampCache.set(input, firstTimestamp); + return firstTimestamp; + } + async getMediaOffset(segment, input) { + const firstSegment = segment.firstSegment ?? segment; + let firstSegmentFirstTimestamp; + if (this.firstSegmentFirstTimestamps.has(firstSegment)) { + firstSegmentFirstTimestamp = this.firstSegmentFirstTimestamps.get(firstSegment); + } else { + const firstInput = this.getInputForSegment(firstSegment); + firstSegmentFirstTimestamp = await this.getFirstTimestampForInput(firstInput); + this.firstSegmentFirstTimestamps.set(firstSegment, firstSegmentFirstTimestamp); + } + if (firstSegment === segment) { + return firstSegment.timestamp - firstSegmentFirstTimestamp; + } + const segmentFirstTimestamp = await this.getFirstTimestampForInput(input); + const segmentElapsed = segment.timestamp - firstSegment.timestamp; + const inputElapsed = segmentFirstTimestamp - firstSegmentFirstTimestamp; + const difference = inputElapsed - segmentElapsed; + if (Math.abs(difference) <= Math.min(0.25, segmentElapsed)) { + return firstSegment.timestamp - firstSegmentFirstTimestamp; + } else { + return segment.timestamp - segmentFirstTimestamp; + } + } + dispose() { + for (const entry of this.inputCache) { + entry.input.dispose(); + } + this.inputCache.length = 0; + } +} +class SegmentedInputInputTrackBacking { + constructor(segmentedInput, decl, number) { + this.packetInfos = /* @__PURE__ */ new WeakMap(); + this.hydrationPromise = null; + this.firstInputTrack = null; + this.segmentedInput = segmentedInput; + this.decl = decl; + this.number = number; + } + hydrate() { + return this.hydrationPromise ?? (this.hydrationPromise = (async () => { + var _a; + (_a = this.segmentedInput).firstSegment ?? (_a.firstSegment = await this.segmentedInput.getFirstSegment({})); + if (!this.segmentedInput.firstSegment) { + throw new Error("Missing first segment, can't retrieve track."); + } + const input = this.segmentedInput.getInputForSegment(this.segmentedInput.firstSegment); + const inputTracks = await input.getTracks(); + const track = inputTracks.find((x) => x.type === this.decl.type && x.number === this.number); + if (!track) { + throw new Error("No matching track found in underlying media data."); + } + this.firstInputTrack = track; + })()); + } + getId() { + return this.decl.id; + } + getType() { + return this.decl.type; + } + getNumber() { + return this.number; + } + /** If the backing track is already present, delegate synchronously; otherwise, hydrate first. */ + delegate(fn) { + if (this.firstInputTrack) { + return fn(); + } + return this.hydrate().then(fn); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } + getHasOnlyKeyPackets() { + return this.delegate(() => this.firstInputTrack._backing.getHasOnlyKeyPackets?.() ?? null); + } + getPairingMask() { + return 1n; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getInternalCodecId() { + return this.delegate(() => this.firstInputTrack._backing.getInternalCodecId()); + } + getDisposition() { + return this.delegate(() => this.firstInputTrack._backing.getDisposition()); + } + getLanguageCode() { + return this.delegate(() => this.firstInputTrack._backing.getLanguageCode()); + } + getName() { + return this.delegate(() => this.firstInputTrack._backing.getName()); + } + getTimeResolution() { + return this.delegate(() => this.firstInputTrack._backing.getTimeResolution()); + } + async isRelativeToUnixEpoch() { + await this.hydrate(); + assert(this.segmentedInput.firstSegment); + return this.segmentedInput.firstSegment.relativeToUnixEpoch; + } + getBitrate() { + return this.delegate(() => this.firstInputTrack._backing.getBitrate()); + } + getAverageBitrate() { + return this.delegate(() => this.firstInputTrack._backing.getAverageBitrate()); + } + getDurationFromMetadata(options) { + return this.segmentedInput.getDurationFromMetadata(options); + } + getLiveRefreshInterval() { + return this.segmentedInput.getLiveRefreshInterval(); + } + async createAdjustedPacket(packet, segment, track) { + assert(packet.sequenceNumber >= 0); + assert(this.segmentedInput.firstSegment); + const mediaOffset = await this.segmentedInput.getMediaOffset(segment, track.input); + const segmentTimestampRelativeToFirst = segment.timestamp - this.segmentedInput.firstSegment.timestamp; + const modified = packet.clone({ + timestamp: roundToDivisor(packet.timestamp + mediaOffset, await track.getTimeResolution()), + // The 1e8 assumes a max of 100 MB per second, highly unlikely to be hit, so this should guarantee + // monotonically increasing sequence numbers across segments. + sequenceNumber: Math.floor(1e8 * segmentTimestampRelativeToFirst) + packet.sequenceNumber + }); + this.packetInfos.set(modified, { + segment, + track, + sourcePacket: packet + }); + return modified; + } + async getFirstPacket(options) { + await this.hydrate(); + assert(this.segmentedInput.firstSegment); + assert(this.firstInputTrack); + const packet = await this.firstInputTrack._backing.getFirstPacket(options); + if (!packet) { + return null; + } + return this.createAdjustedPacket(packet, this.segmentedInput.firstSegment, this.firstInputTrack); + } + getNextPacket(packet, options) { + return this._getNextInternal(packet, options, false); + } + getNextKeyPacket(packet, options) { + return this._getNextInternal(packet, options, true); + } + async _getNextInternal(packet, options, keyframesOnly) { + const info = this.packetInfos.get(packet); + if (!info) { + throw new Error("Packet was not created from this track."); + } + const nextPacket = keyframesOnly ? await info.track._backing.getNextKeyPacket(info.sourcePacket, options) : await info.track._backing.getNextPacket(info.sourcePacket, options); + if (nextPacket) { + return this.createAdjustedPacket(nextPacket, info.segment, info.track); + } + let currentSegment = info.segment; + while (true) { + const nextSegment = await this.segmentedInput.getNextSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + if (!nextSegment) { + return null; + } + const nextInput = this.segmentedInput.getInputForSegment(nextSegment); + const nextTracks = await nextInput.getTracks(); + const nextTrack = nextTracks.find((t) => t.type === info.track.type && t.number === info.track.number); + if (!nextTrack) { + currentSegment = nextSegment; + continue; + } + const firstPacket = await nextTrack._backing.getFirstPacket(options); + if (!firstPacket) { + return null; + } + return this.createAdjustedPacket(firstPacket, nextSegment, nextTrack); + } + } + getPacket(timestamp, options) { + return this._getPacketInternal(timestamp, options, false); + } + getKeyPacket(timestamp, options) { + return this._getPacketInternal(timestamp, options, true); + } + async _getPacketInternal(timestamp, options, keyframesOnly) { + let currentSegment = await this.segmentedInput.getSegmentAt(timestamp, { + skipLiveWait: options.skipLiveWait + }); + if (!currentSegment) { + return null; + } + await this.hydrate(); + while (currentSegment) { + const input = this.segmentedInput.getInputForSegment(currentSegment); + const tracks = await input.getTracks(); + const track = tracks.find((t) => t.type === this.firstInputTrack.type && t.number === this.firstInputTrack.number); + if (!track) { + currentSegment = await this.segmentedInput.getPreviousSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + continue; + } + const mediaOffset = await this.segmentedInput.getMediaOffset(currentSegment, input); + const offsetTimestamp = timestamp - mediaOffset; + const packet = keyframesOnly ? await track._backing.getKeyPacket(offsetTimestamp, options) : await track._backing.getPacket(offsetTimestamp, options); + if (!packet) { + currentSegment = await this.segmentedInput.getPreviousSegment(currentSegment, { + skipLiveWait: options.skipLiveWait + }); + continue; + } + return this.createAdjustedPacket(packet, currentSegment, track); + } + return null; + } +} +class SegmentedInputInputVideoTrackBacking extends SegmentedInputInputTrackBacking { + getType() { + return "video"; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getCodedWidth() { + return this.delegate(() => this.firstInputTrack._backing.getCodedWidth()); + } + getCodedHeight() { + return this.delegate(() => this.firstInputTrack._backing.getCodedHeight()); + } + getSquarePixelWidth() { + return this.delegate(() => this.firstInputTrack._backing.getSquarePixelWidth()); + } + getSquarePixelHeight() { + return this.delegate(() => this.firstInputTrack._backing.getSquarePixelHeight()); + } + getRotation() { + return this.delegate(() => this.firstInputTrack._backing.getRotation()); + } + async getColorSpace() { + return this.delegate(() => this.firstInputTrack._backing.getColorSpace()); + } + async canBeTransparent() { + return this.delegate(() => this.firstInputTrack._backing.canBeTransparent()); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } +} +class SegmentedInputInputAudioTrackBacking extends SegmentedInputInputTrackBacking { + getType() { + return "audio"; + } + getCodec() { + return this.delegate(() => this.firstInputTrack._backing.getCodec()); + } + getNumberOfChannels() { + return this.delegate(() => this.firstInputTrack._backing.getNumberOfChannels()); + } + getSampleRate() { + return this.delegate(() => this.firstInputTrack._backing.getSampleRate()); + } + async getDecoderConfig() { + return this.delegate(() => this.firstInputTrack._backing.getDecoderConfig()); + } +} +polyfillSymbolDispose(); +const DEFAULT_MIN_READ_POSITION = 0; +const DEFAULT_MAX_READ_POSITION = Infinity; +class Source extends EventEmitter { + constructor() { + super(...arguments); + this._disposed = false; + this._refCount = 0; + this._usedForHls = false; + this._sizePromise = null; + this.onread = null; + } + /** + * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call + * will retrieve the size. + * + * Returns null if the source is unsized. + */ + async getSizeOrNull() { + if (this._disposed) { + throw new InputDisposedError(); + } + return this._sizePromise ?? (this._sizePromise = (async () => { + let size = this._getFileSize(); + if (size !== void 0) { + return size; + } + await this._read(0, 1, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION); + size = this._getFileSize(); + assert(size !== void 0); + return size; + })()); + } + /** + * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call + * will retrieve the size. + * + * Throws an error if the source is unsized. + */ + async getSize() { + if (this._disposed) { + throw new InputDisposedError(); + } + const result = await this.getSizeOrNull(); + if (result === null) { + throw new Error("Cannot determine the size of an unsized source."); + } + return result; + } + /** + * Returns a new {@link RangedSource} that maps data onto this source using the given offset and length. If a length + * is not provided, the ranged source spans until the end of this source's data. + * + * Useful for reading files that are embedded within larger files. + */ + slice(offset, length) { + if (!Number.isInteger(offset) || offset < 0) { + throw new TypeError("offset must be a non-negative integer."); + } + if (length !== void 0 && (!Number.isInteger(length) || length < 0)) { + throw new TypeError("length, when provided, must be a non-negative integer."); + } + return new RangedSource(this, offset, length); + } + /** @internal */ + _dispatchRead(start, end) { + this.onread?.(start, end); + this._emit("read", { start, end }); + } + /** + * Creates a new `SourceRef` pointing to this source. You are expected to call `.free()` on said `SourceRef` when + * you're done with it. + */ + ref() { + return new SourceRef(this); + } +} +class SourceRef { + /** @internal */ + constructor(source) { + this._freed = false; + if (source._disposed) { + throw new Error("Cannot ref a disposed source."); + } + source._refCount++; + this._source = source; + } + /** The {@link Source} this ref references. Accessing this field throws an error after having freed the ref. */ + get source() { + if (!this._source) { + throw new Error("Can't get source; ref has already been freed."); + } + return this._source; + } + /** Whether or not this reference has been freed via {@link SourceRef.free}. */ + get freed() { + return this._freed; + } + /** + * Frees the ref, decrementing the source's internal reference count. If the source's internal reference count + * reaches zero, it gets disposed. To catch bugs, this method throws if the ref is already freed. + */ + free() { + if (this._freed) { + throw new Error("Illegal operation: double free on SourceRef."); + } + const source = this.source; + assert(source._refCount > 0); + source._refCount--; + if (source._refCount === 0) { + source._dispose(); + source._disposed = true; + } + this._freed = true; + this._source = null; + } + /** + * Calls {@link SourceRef.free}. + */ + [Symbol.dispose]() { + if (!this.freed) { + this.free(); + } + } +} +class PathedSource extends Source { + constructor(rootPath, requestHandler) { + if (typeof rootPath !== "string") { + throw new TypeError("rootPath must be a string."); + } + if (typeof requestHandler !== "function") { + throw new TypeError("requestHandler must be a function."); + } + super(); + this.rootPath = rootPath; + this.requestHandler = requestHandler; + } + /** @internal */ + _resolveRequest(request) { + const result = this.requestHandler(request); + const handle = (result2) => { + var _a; + if (!(result2 instanceof Source || result2 instanceof SourceRef)) { + throw new TypeError("requestHandler must return or resolve to a Source or SourceRef."); + } + const ref = result2 instanceof Source ? result2.ref() : result2; + (_a = ref.source)._usedForHls || (_a._usedForHls = this._usedForHls); + return ref; + }; + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } +} +const sourceRequestsAreEqual = (a, b) => { + return a.path === b.path; +}; +class CustomPathedSource extends PathedSource { + constructor() { + super(...arguments); + this._root = null; + this._rootRequest = null; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + if (!this._root) { + if (!this._rootRequest) { + const result = this._resolveRequest({ path: this.rootPath, isRoot: true }); + const handle = (result2) => { + const ref = result2 instanceof Source ? result2.ref() : result2; + this._root = ref; + this._rootRequest = null; + return ref; + }; + if (result instanceof Promise) { + this._rootRequest = result.then(handle); + } else { + handle(result); + assert(this._root); + } + } + if (this._rootRequest) { + return this._rootRequest.then((ref) => ref.source._read(start, end, minReadPosition, maxReadPosition)); + } + } + return this._root.source._read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + _getFileSize() { + if (this._root) { + return this._root.source._getFileSize(); + } + return void 0; + } + /** @internal */ + _dispose() { + if (this._root) { + this._root.free(); + } else if (this._rootRequest) { + void this._rootRequest.then((ref) => ref.free()); + } + } +} +class BlobSource extends Source { + /** + * Creates a new {@link BlobSource} backed by the specified + * [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). + */ + constructor(blob, options = {}) { + if (!(blob instanceof Blob)) { + throw new TypeError("blob must be a Blob."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + super(); + this._readers = /* @__PURE__ */ new WeakMap(); + this._blob = blob; + this._orchestrator = new ReadOrchestrator({ + maxCacheSize: options.maxCacheSize ?? 8 * 2 ** 20, + maxWorkerCount: 4, + runWorker: this._runWorker.bind(this), + prefetchProfile: PREFETCH_PROFILES.fileSystem + }); + this._orchestrator.fileSize = blob.size; + } + /** @internal */ + _getFileSize() { + return this._orchestrator.fileSize; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + return this._orchestrator.read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + async _runWorker(worker) { + assert(worker.strictTarget); + let reader = this._readers.get(worker); + if (reader === void 0) { + if ("stream" in this._blob && !isWebKit()) { + const slice = this._blob.slice(worker.currentPos); + reader = slice.stream().getReader(); + } else { + reader = null; + } + this._readers.set(worker, reader); + } + while (worker.currentPos < worker.targetPos && !worker.aborted) { + if (reader) { + const { done, value } = await reader.read(); + if (done) { + this._orchestrator.onWorkerFinished(worker); + throw new Error("Blob reader stopped unexpectedly before all requested data was read."); + } + if (worker.aborted) { + break; + } + this._dispatchRead(worker.currentPos, worker.currentPos + value.length); + this._orchestrator.supplyWorkerData(worker, value); + } else { + const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer(); + if (worker.aborted) { + break; + } + this._dispatchRead(worker.currentPos, worker.currentPos + data.byteLength); + this._orchestrator.supplyWorkerData(worker, new Uint8Array(data)); + } + } + this._orchestrator.signalWorkerStoppedRunning(worker); + if (worker.aborted) { + await reader?.cancel(); + } + } + /** @internal */ + _dispose() { + this._orchestrator.dispose(); + } +} +const URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20; +const DEFAULT_RETRY_DELAY = ((previousAttempts, error, src) => { + const couldBeCorsError = error instanceof Error && (error.message.includes("Failed to fetch") || error.message.includes("Load failed") || error.message.includes("NetworkError when attempting to fetch resource")); + if (couldBeCorsError) { + let originOfSrc = null; + try { + if (typeof window !== "undefined" && typeof window.location !== "undefined") { + originOfSrc = new URL(src instanceof Request ? src.url : src, window.location.href).origin; + } + } catch { + } + const isOnline = typeof navigator !== "undefined" && typeof navigator.onLine === "boolean" ? navigator.onLine : true; + if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) { + console.warn(`Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option.`); + return null; + } + } + return Math.min(2 ** (previousAttempts - 2), 16); +}); +const warnedOrigins = /* @__PURE__ */ new Set(); +class UrlSource extends PathedSource { + /** + * Creates a new {@link UrlSource} backed by the resource at the specified URL. + * + * When passing a `Request` instance, note that the `signal` and `headers.Range` options will be overridden by + * Mediabunny. If you want to cancel ongoing requests, use {@link Input.dispose}. + */ + constructor(url, options = {}) { + if (typeof url !== "string" && !(url instanceof URL) && !(typeof Request !== "undefined" && url instanceof Request)) { + throw new TypeError("url must be a string, URL or Request."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.requestInit !== void 0 && (!options.requestInit || typeof options.requestInit !== "object")) { + throw new TypeError("options.requestInit, when provided, must be an object."); + } + if (options.getRetryDelay !== void 0 && typeof options.getRetryDelay !== "function") { + throw new TypeError("options.getRetryDelay, when provided, must be a function."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + if (options.parallelism !== void 0 && (!Number.isInteger(options.parallelism) || options.parallelism < 1)) { + throw new TypeError("options.parallelism, when provided, must be a positive number."); + } + if (options.fetchFn !== void 0 && typeof options.fetchFn !== "function") { + throw new TypeError("options.fetchFn, when provided, must be a function."); + } + const urlString = url instanceof Request ? url.url : url instanceof URL ? url.href : url; + super(urlString, (request) => new UrlSource(request.path, this._options)); + this._fileSizeDetermined = false; + this._url = url; + this._options = options; + this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY; + const DEFAULT_PARALLELISM = 2; + this._orchestrator = new ReadOrchestrator({ + maxCacheSize: options.maxCacheSize ?? 64 * 2 ** 20, + maxWorkerCount: options.parallelism ?? DEFAULT_PARALLELISM, + runWorker: this._runWorker.bind(this), + prefetchProfile: PREFETCH_PROFILES.network + }); + } + /** @internal */ + _getFileSize() { + return this._fileSizeDetermined ? this._orchestrator.fileSize : void 0; + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + return this._orchestrator.read(start, end, minReadPosition, maxReadPosition); + } + /** @internal */ + async _runWorker(worker) { + while (true) { + const abortController = new AbortController(); + const response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { + headers: { + // Always sending a range request is a good way to probe if the server supports them + Range: `bytes=${worker.currentPos}-` + }, + signal: abortController.signal + }), this._getRetryDelay, () => this._disposed); + if (!response.ok) { + throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); + } + outer: if (this._orchestrator.fileSize === null) { + const contentRange = response.headers.get("Content-Range"); + if (contentRange) { + const match = /\/(\d+)/.exec(contentRange); + if (match) { + this._orchestrator.supplyFileSize(Number(match[1])); + break outer; + } + } + const contentLength = response.headers.get("Content-Length"); + if (contentLength) { + this._orchestrator.supplyFileSize(worker.currentPos + Number(contentLength)); + } + } + this._fileSizeDetermined = true; + if (response.status !== 206) { + if (!this._usedForHls) { + const url = new URL(this._url instanceof Request ? this._url.url : this._url, typeof window !== "undefined" ? window.location.href : void 0); + if (url.origin !== "null" && !(url.pathname.endsWith(".m3u8") || url.pathname.endsWith(".m3u"))) { + if (!warnedOrigins.has(url.origin)) { + console.log(this._usedForHls, this._url, url.pathname); + console.warn(`HTTP server (origin ${url.origin}) did not respond to a range request with 206 Partial Content, meaning the entire resource will now be downloaded. To enable efficient media file streaming across a network, please make sure your server supports range requests.`); + warnedOrigins.add(url.origin); + } + } + } + worker.currentPos = 0; + this._orchestrator.options.maxCacheSize = Infinity; + if (this._orchestrator.fileSize !== null) { + worker.targetPos = this._orchestrator.fileSize; + } else { + worker.targetPos = Infinity; + worker.strictTarget = false; + } + this._orchestrator.consolidateEverythingIntoOneWorker(worker); + } + if (!response.body) { + throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream."); + } + const reader = response.body.getReader(); + while (true) { + if (worker.currentPos >= worker.targetPos || worker.aborted) { + abortController.abort(); + this._orchestrator.signalWorkerStoppedRunning(worker); + return; + } + let readResult; + try { + readResult = await reader.read(); + } catch (error) { + if (this._disposed) { + throw error; + } + const retryDelayInSeconds = this._getRetryDelay(1, error, this._url); + if (retryDelayInSeconds !== null) { + console.error("Error while reading response stream. Attempting to resume.", error); + await wait(1e3 * retryDelayInSeconds); + break; + } else { + throw error; + } + } + if (worker.aborted) { + continue; + } + const { done, value } = readResult; + if (done) { + if (worker.currentPos >= worker.targetPos) { + this._orchestrator.onWorkerFinished(worker); + return; + } + if (worker.strictTarget) { + break; + } else { + this._orchestrator.onWorkerFinished(worker); + return; + } + } + this._dispatchRead(worker.currentPos, worker.currentPos + value.length); + this._orchestrator.supplyWorkerData(worker, value); + } + } + } + /** @internal */ + _dispose() { + this._orchestrator.dispose(); + } +} +class ReadableStreamSource extends Source { + /** Creates a new {@link ReadableStreamSource} backed by the specified `ReadableStream`. */ + constructor(stream, options = {}) { + if (!(stream instanceof ReadableStream)) { + throw new TypeError("stream must be a ReadableStream."); + } + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { + throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); + } + super(); + this._reader = null; + this._cache = []; + this._pendingSlices = []; + this._currentIndex = 0; + this._targetIndex = 0; + this._maxRequestedIndex = 0; + this._endIndex = null; + this._pulling = false; + this._stream = stream; + this._maxCacheSize = options.maxCacheSize ?? 16 * 2 ** 20; + } + /** @internal */ + _getFileSize() { + return this._endIndex; + } + /** @internal */ + _read(start, end) { + if (this._endIndex !== null && end > this._endIndex) { + return null; + } + this._maxRequestedIndex = Math.max(this._maxRequestedIndex, end); + const cacheStartIndex = binarySearchLessOrEqual(this._cache, start, (x) => x.start); + const cacheStartEntry = cacheStartIndex !== -1 ? this._cache[cacheStartIndex] : null; + if (cacheStartEntry && cacheStartEntry.start <= start && end <= cacheStartEntry.end) { + return { + bytes: cacheStartEntry.bytes, + view: cacheStartEntry.view, + offset: cacheStartEntry.start + }; + } + let lastEnd = start; + const bytes = new Uint8Array(end - start); + if (cacheStartIndex !== -1) { + for (let i = cacheStartIndex; i < this._cache.length; i++) { + const cacheEntry = this._cache[i]; + if (cacheEntry.start >= end) { + break; + } + const cappedStart = Math.max(start, cacheEntry.start); + if (cappedStart > lastEnd) { + this._throwDueToCacheMiss(); + } + const cappedEnd = Math.min(end, cacheEntry.end); + if (cappedStart < cappedEnd) { + bytes.set(cacheEntry.bytes.subarray(cappedStart - cacheEntry.start, cappedEnd - cacheEntry.start), cappedStart - start); + lastEnd = cappedEnd; + } + } + } + if (lastEnd === end) { + return { + bytes, + view: toDataView(bytes), + offset: start + }; + } + if (this._currentIndex > lastEnd) { + this._throwDueToCacheMiss(); + } + const { promise, resolve, reject } = promiseWithResolvers(); + this._pendingSlices.push({ + start, + end, + bytes, + resolve, + reject + }); + this._targetIndex = Math.max(this._targetIndex, end); + if (!this._pulling) { + this._pulling = true; + void this._pull().catch((error) => { + this._pulling = false; + if (this._pendingSlices.length > 0) { + this._pendingSlices.forEach((x) => x.reject(error)); + this._pendingSlices.length = 0; + } else { + throw error; + } + }); + } + return promise; + } + /** @internal */ + _throwDueToCacheMiss() { + throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache."); + } + /** @internal */ + async _pull() { + this._reader ?? (this._reader = this._stream.getReader()); + while (this._currentIndex < this._targetIndex && !this._disposed) { + const { done, value } = await this._reader.read(); + if (done) { + for (const pendingSlice of this._pendingSlices) { + pendingSlice.resolve(null); + } + this._pendingSlices.length = 0; + this._endIndex = this._currentIndex; + break; + } + const startIndex = this._currentIndex; + const endIndex = this._currentIndex + value.byteLength; + for (let i = 0; i < this._pendingSlices.length; i++) { + const pendingSlice = this._pendingSlices[i]; + const cappedStart = Math.max(startIndex, pendingSlice.start); + const cappedEnd = Math.min(endIndex, pendingSlice.end); + if (cappedStart < cappedEnd) { + pendingSlice.bytes.set(value.subarray(cappedStart - startIndex, cappedEnd - startIndex), cappedStart - pendingSlice.start); + if (cappedEnd === pendingSlice.end) { + pendingSlice.resolve({ + bytes: pendingSlice.bytes, + view: toDataView(pendingSlice.bytes), + offset: pendingSlice.start + }); + this._pendingSlices.splice(i, 1); + i--; + } + } + } + this._cache.push({ + start: startIndex, + end: endIndex, + bytes: value, + view: toDataView(value), + age: 0 + // Unused + }); + while (this._cache.length > 0) { + const firstEntry = this._cache[0]; + const distance = this._maxRequestedIndex - firstEntry.end; + if (distance <= this._maxCacheSize) { + break; + } + this._cache.shift(); + } + this._currentIndex += value.byteLength; + } + this._pulling = false; + } + /** @internal */ + _dispose() { + this._pendingSlices.length = 0; + this._cache.length = 0; + void this._reader?.cancel(); + } +} +const PREFETCH_PROFILES = { + fileSystem: (start, end) => { + const padding = 2 ** 16; + start = Math.floor((start - padding) / padding) * padding; + end = Math.ceil((end + padding) / padding) * padding; + return { start, end }; + }, + network: (start, end, workers) => { + const paddingStart = 2 ** 16; + start = Math.max(0, Math.floor((start - paddingStart) / paddingStart) * paddingStart); + for (const worker of workers) { + const maxExtensionAmount = 8 * 2 ** 20; + const thresholdPoint = Math.max((worker.startPos + worker.targetPos) / 2, worker.targetPos - maxExtensionAmount); + if (closedIntervalsOverlap(start, end, thresholdPoint, worker.targetPos)) { + const size = worker.targetPos - worker.startPos; + const a = Math.ceil((size + 1) / maxExtensionAmount) * maxExtensionAmount; + const b = 2 ** Math.ceil(Math.log2(size + 1)); + const extent = Math.min(b, a); + end = Math.max(end, worker.startPos + extent); + } + } + end = Math.max(end, start + URL_SOURCE_MIN_LOAD_AMOUNT); + return { + start, + end + }; + } +}; +class ReadOrchestrator { + constructor(options) { + this.options = options; + this.fileSize = null; + this.nextAge = 0; + this.workers = []; + this.cache = []; + this.currentCacheSize = 0; + this.disposed = false; + this.queuedReads = []; + } + read(innerStart, innerEnd, minReadPosition, maxReadPosition) { + assert(!this.disposed); + const prefetchRange = this.options.prefetchProfile(innerStart, innerEnd, this.workers); + const outerStart = Math.max(prefetchRange.start, minReadPosition); + const outerEnd = Math.min(prefetchRange.end, this.fileSize ?? Infinity, maxReadPosition); + assert(outerStart <= innerStart && innerEnd <= outerEnd); + let result = null; + const innerCacheStartIndex = binarySearchLessOrEqual(this.cache, innerStart, (x) => x.start); + const innerStartEntry = innerCacheStartIndex !== -1 ? this.cache[innerCacheStartIndex] : null; + if (innerStartEntry && innerStartEntry.start <= innerStart && innerEnd <= innerStartEntry.end) { + innerStartEntry.age = this.nextAge++; + result = { + bytes: innerStartEntry.bytes, + view: innerStartEntry.view, + offset: innerStartEntry.start + }; + } + const outerCacheStartIndex = binarySearchLessOrEqual(this.cache, outerStart, (x) => x.start); + const bytes = result ? null : new Uint8Array(innerEnd - innerStart); + let contiguousBytesWriteEnd = 0; + let lastEnd = outerStart; + const outerHoles = []; + if (outerCacheStartIndex !== -1) { + for (let i = outerCacheStartIndex; i < this.cache.length; i++) { + const entry = this.cache[i]; + if (entry.start >= outerEnd) { + break; + } + if (entry.end <= outerStart) { + continue; + } + const cappedOuterStart = Math.max(outerStart, entry.start); + const cappedOuterEnd = Math.min(outerEnd, entry.end); + assert(cappedOuterStart <= cappedOuterEnd); + if (lastEnd < cappedOuterStart) { + outerHoles.push({ start: lastEnd, end: cappedOuterStart }); + } + lastEnd = cappedOuterEnd; + if (bytes) { + const cappedInnerStart = Math.max(innerStart, entry.start); + const cappedInnerEnd = Math.min(innerEnd, entry.end); + if (cappedInnerStart < cappedInnerEnd) { + const relativeOffset = cappedInnerStart - innerStart; + bytes.set(entry.bytes.subarray(cappedInnerStart - entry.start, cappedInnerEnd - entry.start), relativeOffset); + if (relativeOffset === contiguousBytesWriteEnd) { + contiguousBytesWriteEnd = cappedInnerEnd - innerStart; + } + } + } + entry.age = this.nextAge++; + } + if (lastEnd < outerEnd) { + outerHoles.push({ start: lastEnd, end: outerEnd }); + } + } else { + outerHoles.push({ start: outerStart, end: outerEnd }); + } + if (bytes && contiguousBytesWriteEnd >= bytes.length) { + result = { + bytes, + view: toDataView(bytes), + offset: innerStart + }; + } + if (outerHoles.length === 0) { + assert(result); + return result; + } + const { promise, resolve, reject } = promiseWithResolvers(); + const innerHoles = []; + for (const outerHole of outerHoles) { + const cappedStart = Math.max(innerStart, outerHole.start); + const cappedEnd = Math.min(innerEnd, outerHole.end); + if (cappedStart === outerHole.start && cappedEnd === outerHole.end) { + innerHoles.push(outerHole); + } else if (cappedStart < cappedEnd) { + innerHoles.push({ start: cappedStart, end: cappedEnd }); + } + } + const pendingSlice = bytes && { + start: innerStart, + bytes, + holes: innerHoles, + resolve, + reject + }; + outer: for (const outerHole of outerHoles) { + for (const worker of this.workers) { + const addedToWorker = this.checkHoleAgainstWorker(worker, outerHole, pendingSlice ? [pendingSlice] : []); + if (addedToWorker) { + this.checkQueuedReadsAgainstWorker(worker); + continue outer; + } + } + const strictTarget = outerHole.end < outerEnd || this.fileSize !== null; + const newWorker = this.createWorker(outerHole.start, outerHole.end, strictTarget); + if (newWorker) { + if (pendingSlice) { + newWorker.pendingSlices = [pendingSlice]; + } + this.runWorker(newWorker); + } else { + let index = binarySearchLessOrEqual(this.queuedReads, outerHole.start, (x) => x.hole.start); + let entry = index !== -1 ? this.queuedReads[index] : null; + if (entry && outerHole.start <= entry.hole.end) { + entry.hole.end = Math.max(entry.hole.end, outerHole.end); + entry.strictTarget && (entry.strictTarget = strictTarget); + if (pendingSlice) { + entry.pendingSlices.push(pendingSlice); + } + } else { + index++; + entry = { + hole: { + // Clone the hole because it might be mutated later + start: outerHole.start, + end: outerHole.end + }, + strictTarget, + pendingSlices: pendingSlice ? [pendingSlice] : [], + age: this.nextAge++ + }; + this.queuedReads.splice(index, 0, entry); + } + while (index + 1 < this.queuedReads.length) { + const nextEntry = this.queuedReads[index + 1]; + if (nextEntry.hole.start > entry.hole.end) { + break; + } + entry.hole.end = Math.max(entry.hole.end, nextEntry.hole.end); + entry.pendingSlices.push(...nextEntry.pendingSlices); + entry.strictTarget && (entry.strictTarget = nextEntry.strictTarget); + entry.age = Math.min(entry.age, nextEntry.age); + this.queuedReads.splice(index + 1, 1); + } + } + } + if (!result) { + assert(bytes); + result = promise.then((bytes2) => bytes2 && { + bytes: bytes2, + view: toDataView(bytes2), + offset: innerStart + }); + } + return result; + } + checkHoleAgainstWorker(worker, hole, pendingSlices) { + const gapTolerance = 2 ** 17; + if (closedIntervalsOverlap(hole.start - gapTolerance, hole.start, worker.currentPos, worker.targetPos)) { + worker.targetPos = Math.max(worker.targetPos, hole.end); + for (let i = 0; i < pendingSlices.length; i++) { + const pendingSlice = pendingSlices[i]; + if (!worker.pendingSlices.includes(pendingSlice)) { + worker.pendingSlices.push(pendingSlice); + } + } + if (!worker.running) { + this.runWorker(worker); + } + return true; + } + return false; + } + checkQueuedReadsAgainstWorker(worker) { + let wasTrueOnce = false; + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + const result = this.checkHoleAgainstWorker(worker, queuedRead.hole, queuedRead.pendingSlices); + if (result) { + this.queuedReads.splice(i, 1); + i--; + wasTrueOnce = true; + } else if (wasTrueOnce) { + break; + } + } + } + createWorker(startPos, targetPos, strictTarget) { + if (this.workers.length >= this.options.maxWorkerCount) { + let oldestWorker = null; + let oldestIndex = null; + for (let i = 0; i < this.workers.length; i++) { + const worker2 = this.workers[i]; + if (!worker2.running && worker2.pendingSlices.length === 0 && (!oldestWorker || worker2.age < oldestWorker.age)) { + oldestIndex = i; + oldestWorker = worker2; + } + } + if (oldestWorker) { + assert(oldestIndex !== null); + assert(oldestWorker.pendingSlices.length === 0); + this.workers.splice(oldestIndex, 1); + } else { + return null; + } + } + const worker = { + startPos, + currentPos: startPos, + targetPos, + strictTarget, + running: false, + // Due to async shenanigans, it can happen that workers are started after disposal. In this case, instead of + // simply not creating the worker, we allow it to run but immediately label it as aborted, so it can then + // shut itself down. + aborted: this.disposed, + pendingSlices: [], + age: this.nextAge++ + }; + this.workers.push(worker); + return worker; + } + runWorker(worker) { + assert(!worker.running); + assert(worker.currentPos < worker.targetPos); + worker.running = true; + worker.age = this.nextAge++; + void this.options.runWorker(worker).catch((error) => { + worker.running = false; + if (worker.pendingSlices.length > 0) { + worker.pendingSlices.forEach((x) => x.reject(error)); + worker.pendingSlices.length = 0; + } else { + throw error; + } + }).finally(() => { + if (worker.running) { + return; + } + if (this.queuedReads.length > 0) { + let oldestIndex = 0; + for (let i = 1; i < this.queuedReads.length; i++) { + const queuedRead2 = this.queuedReads[i]; + if (queuedRead2.age < this.queuedReads[oldestIndex].age) { + oldestIndex = i; + } + } + const queuedRead = this.queuedReads[oldestIndex]; + this.queuedReads.splice(oldestIndex, 1); + const newWorker = this.createWorker(queuedRead.hole.start, queuedRead.hole.end, queuedRead.strictTarget); + assert(newWorker); + newWorker.pendingSlices = queuedRead.pendingSlices; + this.runWorker(newWorker); + } + }); + } + consolidateEverythingIntoOneWorker(worker) { + const uniqueSlices = new Set(worker.pendingSlices); + for (let i = 0; i < this.workers.length; i++) { + const otherWorker = this.workers[i]; + if (otherWorker === worker) { + continue; + } + for (const slice of otherWorker.pendingSlices) { + uniqueSlices.add(slice); + } + otherWorker.aborted = true; + otherWorker.pendingSlices.length = 0; + this.workers.splice(i, 1); + i--; + } + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + for (const slice of queuedRead.pendingSlices) { + uniqueSlices.add(slice); + } + } + worker.pendingSlices = [...uniqueSlices]; + this.queuedReads.length = 0; + } + /** Called by a worker when it has read some data. */ + supplyWorkerData(worker, bytes) { + assert(!worker.aborted); + const start = worker.currentPos; + const end = start + bytes.length; + this.insertIntoCache({ + start, + end, + bytes, + view: toDataView(bytes), + age: this.nextAge++ + }); + worker.currentPos += bytes.length; + if (worker.currentPos > worker.targetPos) { + worker.targetPos = worker.currentPos; + this.checkQueuedReadsAgainstWorker(worker); + } + for (let i = 0; i < worker.pendingSlices.length; i++) { + const pendingSlice = worker.pendingSlices[i]; + const clampedStart = Math.max(start, pendingSlice.start); + const clampedEnd = Math.min(end, pendingSlice.start + pendingSlice.bytes.length); + if (clampedStart < clampedEnd) { + pendingSlice.bytes.set(bytes.subarray(clampedStart - start, clampedEnd - start), clampedStart - pendingSlice.start); + } + for (let j = 0; j < pendingSlice.holes.length; j++) { + const hole = pendingSlice.holes[j]; + if (start <= hole.start && end > hole.start) { + hole.start = end; + } + if (hole.end <= hole.start) { + pendingSlice.holes.splice(j, 1); + j--; + } + } + if (pendingSlice.holes.length === 0) { + pendingSlice.resolve(pendingSlice.bytes); + worker.pendingSlices.splice(i, 1); + i--; + } + } + for (let i = 0; i < this.workers.length; i++) { + const otherWorker = this.workers[i]; + if (worker === otherWorker || otherWorker.running) { + continue; + } + if (closedIntervalsOverlap(start, end, otherWorker.currentPos, otherWorker.targetPos)) { + this.workers.splice(i, 1); + i--; + } + } + } + supplyFileSize(size) { + assert(this.fileSize === null); + this.fileSize = size; + for (const worker of this.workers) { + worker.targetPos = Math.min(worker.targetPos, size); + worker.strictTarget = true; + for (let i = 0; i < worker.pendingSlices.length; i++) { + const pendingSlice = worker.pendingSlices[i]; + for (const hole of pendingSlice.holes) { + if (hole.end > size) { + pendingSlice.resolve(null); + worker.pendingSlices.splice(i, 1); + i--; + break; + } + } + } + } + for (let i = 0; i < this.queuedReads.length; i++) { + const queuedRead = this.queuedReads[i]; + if (queuedRead.hole.start >= size) { + for (const slice of queuedRead.pendingSlices) + slice.resolve(null); + this.queuedReads.splice(i, 1); + i--; + } else if (queuedRead.hole.end > size) { + queuedRead.hole.end = size; + queuedRead.strictTarget = true; + for (let j = 0; j < queuedRead.pendingSlices.length; j++) { + const slice = queuedRead.pendingSlices[j]; + if (slice.start >= size) { + slice.resolve(null); + queuedRead.pendingSlices.splice(j, 1); + j--; + } + } + } + } + } + signalWorkerStoppedRunning(worker) { + worker.running = false; + worker.pendingSlices.length = 0; + } + /** Called when a worker reaches the end of the underlying data and must be cleaned up. */ + onWorkerFinished(worker) { + const index = this.workers.indexOf(worker); + assert(index !== -1); + worker.running = false; + this.workers.splice(index, 1); + if (this.fileSize === null) { + this.supplyFileSize(worker.currentPos); + } + for (const pendingSlice of worker.pendingSlices) { + pendingSlice.resolve(null); + } + } + insertIntoCache(entry) { + if (this.options.maxCacheSize === 0) { + return; + } + let insertionIndex = binarySearchLessOrEqual(this.cache, entry.start, (x) => x.start) + 1; + if (insertionIndex > 0) { + const previous = this.cache[insertionIndex - 1]; + if (previous.end >= entry.end) { + return; + } + if (previous.end > entry.start) { + const joined = new Uint8Array(entry.end - previous.start); + joined.set(previous.bytes, 0); + joined.set(entry.bytes, entry.start - previous.start); + this.currentCacheSize += entry.end - previous.end; + previous.bytes = joined; + previous.view = toDataView(joined); + previous.end = entry.end; + insertionIndex--; + entry = previous; + } else { + this.cache.splice(insertionIndex, 0, entry); + this.currentCacheSize += entry.bytes.length; + } + } else { + this.cache.splice(insertionIndex, 0, entry); + this.currentCacheSize += entry.bytes.length; + } + for (let i = insertionIndex + 1; i < this.cache.length; i++) { + const next = this.cache[i]; + if (entry.end <= next.start) { + break; + } + if (entry.end >= next.end) { + this.cache.splice(i, 1); + this.currentCacheSize -= next.bytes.length; + i--; + continue; + } + const joined = new Uint8Array(next.end - entry.start); + joined.set(entry.bytes, 0); + joined.set(next.bytes, next.start - entry.start); + this.currentCacheSize -= entry.end - next.start; + entry.bytes = joined; + entry.view = toDataView(joined); + entry.end = next.end; + this.cache.splice(i, 1); + break; + } + while (this.currentCacheSize > this.options.maxCacheSize) { + let oldestIndex = 0; + let oldestEntry = this.cache[0]; + for (let i = 1; i < this.cache.length; i++) { + const entry2 = this.cache[i]; + if (entry2.age < oldestEntry.age) { + oldestIndex = i; + oldestEntry = entry2; + } + } + if (this.currentCacheSize - oldestEntry.bytes.length <= this.options.maxCacheSize) { + break; + } + this.cache.splice(oldestIndex, 1); + this.currentCacheSize -= oldestEntry.bytes.length; + } + } + dispose() { + for (const worker of this.workers) { + worker.aborted = true; + } + this.workers.length = 0; + this.cache.length = 0; + this.disposed = true; + } +} +class RangedSource extends Source { + /** @internal */ + constructor(baseSource, offset, length) { + super(); + this._ref = null; + if (baseSource._disposed) { + throw new Error("Cannot create a slice of a disposed source."); + } + this._baseSource = baseSource; + this._offset = offset; + this._length = length ?? null; + } + /** @internal */ + _getFileSize() { + const baseSize = this._baseSource._getFileSize(); + if (baseSize === void 0) { + return this._length !== null ? this._length : void 0; + } + if (baseSize === null) { + if (this._length !== null) { + return this._length; + } else { + return null; + } + } + return clamp$1(baseSize - this._offset, 0, this._length ?? Infinity); + } + /** @internal */ + _read(start, end, minReadPosition, maxReadPosition) { + if (this._length !== null && end > this._length) { + return null; + } + const result = this._baseSource._read(this._offset + start, this._offset + end, this._offset + minReadPosition, this._offset + maxReadPosition); + if (result instanceof Promise) { + return result.then((result2) => { + if (!result2) { + return null; + } + result2.offset -= this._offset; + return result2; + }); + } else { + if (!result) { + return null; + } + result.offset -= this._offset; + return result; + } + } + /** @internal */ + _dispose() { + this._ref?.free(); + } + ref() { + this._ref ?? (this._ref = this._baseSource.ref()); + return super.ref(); + } +} +var __addDisposableResource = function(env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose, inner; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + if (async) inner = dispose; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + if (inner) dispose = function() { + try { + inner.call(this); + } catch (e) { + return Promise.reject(e); + } + }; + env.stack.push({ value, dispose, async }); + } else if (async) { + env.stack.push({ async: true }); + } + return value; +}; +var __disposeResources = /* @__PURE__ */ (function(SuppressedError2) { + return function(env) { + function fail(e) { + env.error = env.hasError ? new SuppressedError2(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + var r, s = 0; + function next() { + while (r = env.stack.pop()) { + try { + if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); + if (r.dispose) { + var result = r.dispose.call(r.value); + if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { + fail(e); + return next(); + }); + } else s |= 1; + } catch (e) { + fail(e); + } + } + if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); + if (env.hasError) throw env.error; + } + return next(); + }; +})(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}); +const IV_STRING_REGEX = /^0[xX][0-9a-fA-F]+$/; +const BASE64_DATA_URI_REGEX = /^data:.*;base64,/i; +class HlsSegmentedInput extends SegmentedInput { + constructor(demuxer, path, trackDeclarations, lines) { + super(demuxer.input, path, trackDeclarations); + this.segments = []; + this.nextLines = null; + this.currentUpdateSegmentsPromise = null; + this.streamHasEnded = false; + this.lastSegmentUpdateTime = -Infinity; + this.refreshInterval = 5; + this.demuxer = demuxer; + this.nextLines = lines; + } + runUpdateSegments() { + return this.currentUpdateSegmentsPromise ?? (this.currentUpdateSegmentsPromise = (async () => { + try { + const remainingWaitTimeMs = this.getRemainingWaitTimeMs(); + if (remainingWaitTimeMs > 0) { + await wait(remainingWaitTimeMs); + } + this.lastSegmentUpdateTime = performance.now(); + await this.updateSegments(); + } finally { + this.currentUpdateSegmentsPromise = null; + } + })()); + } + getRemainingWaitTimeMs() { + const elapsed = performance.now() - this.lastSegmentUpdateTime; + const result = Math.max(0, 1e3 * this.refreshInterval - elapsed); + if (result <= 50) { + return 0; + } + return result; + } + /** + * Reads and parses the segment info from the playlist file. When called more than one, it updates the existing + * segments by appending the new ones. Existing segments are never removed. + */ + async updateSegments() { + let lines = this.nextLines; + this.nextLines = null; + if (!lines) { + const env_1 = { stack: [], error: void 0, hasError: false }; + try { + const ref = __addDisposableResource(env_1, await this.demuxer.input._getSourceUncached({ path: this.path, isRoot: false }), false); + const reader = new Reader(ref.source); + const slice = await reader.requestEntireFile(); + assert(slice); + lines = readAllLines(slice, slice.length, { ignore: canIgnoreLine }); + } catch (e_1) { + env_1.error = e_1; + env_1.hasError = true; + } finally { + __disposeResources(env_1); + } + } + let headerRead = false; + let accumulatedTime = 0; + let nextSegmentDuration = null; + let currentKey = null; + let nextSequenceNumber = 0; + let currentFirstSegment = null; + let currentInitSegment = null; + let lastByteRangeEnd = null; + let nextByteRange = null; + let lastProgramDateTimeSeconds = null; + let targetDuration = null; + let segmentSeen = false; + let prevLastSegment = last(this.segments) ?? null; + const parseByteRange = (content) => { + const atIndex = content.indexOf("@"); + const length = Number(atIndex === -1 ? content : content.slice(0, atIndex)); + if (!Number.isInteger(length) || length < 0) { + throw new Error(`Invalid #EXT-X-BYTERANGE length '${content}'.`); + } + let offset = null; + if (atIndex !== -1) { + offset = Number(content.slice(atIndex + 1)); + if (!Number.isInteger(offset) || offset < 0) { + throw new Error(`Invalid #EXT-X-BYTERANGE offset '${content}'.`); + } + } + return { length, offset }; + }; + const setNextSequenceNumber = (number) => { + nextSequenceNumber = number; + if (prevLastSegment) { + assert(prevLastSegment.sequenceNumber !== null); + if (prevLastSegment.sequenceNumber < number) { + accumulatedTime = prevLastSegment.timestamp + prevLastSegment.duration; + currentFirstSegment = prevLastSegment.firstSegment; + currentInitSegment = prevLastSegment.initSegment; + lastProgramDateTimeSeconds = prevLastSegment.lastProgramDateTimeSeconds; + prevLastSegment = null; + } + } + }; + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!headerRead) { + if (line !== "#EXTM3U") { + throw new Error("Invalid M3U8 file; expected first line to be #EXTM3U."); + } + headerRead = true; + continue; + } + if (!line.startsWith("#")) { + if (!prevLastSegment) { + if (nextSegmentDuration === null) { + throw new Error("Invalid M3U8 file; a segment must be preceded by an #EXTINF tag."); + } + let key = currentKey; + if (key && key.method === "AES-128" && !key.iv) { + const iv = new Uint8Array(AES_128_BLOCK_SIZE); + const view = toDataView(iv); + view.setUint32(8, Math.floor(nextSequenceNumber / 2 ** 32)); + view.setUint32(12, nextSequenceNumber); + key = { ...key, iv }; + } + const fullPath = joinPaths(this.path, line); + const location = { + path: fullPath, + offset: nextByteRange?.offset ?? 0, + length: nextByteRange?.length ?? null + }; + const segment = { + timestamp: accumulatedTime, + relativeToUnixEpoch: lastProgramDateTimeSeconds !== null, + firstSegment: currentFirstSegment, + sequenceNumber: nextSequenceNumber, + location, + duration: nextSegmentDuration, + encryption: key, + initSegment: currentInitSegment, + lastProgramDateTimeSeconds + }; + currentFirstSegment ?? (currentFirstSegment = segment); + accumulatedTime += nextSegmentDuration; + this.segments.push(segment); + } + nextSegmentDuration = null; + if (nextByteRange === null) { + lastByteRangeEnd = null; + } else { + nextByteRange = null; + } + setNextSequenceNumber(nextSequenceNumber + 1); + } + if (line.startsWith(TAG_EXTINF)) { + if (prevLastSegment) { + segmentSeen = true; + continue; + } + if (!segmentSeen) { + if (lastProgramDateTimeSeconds === null && nextSequenceNumber > 0 && targetDuration !== null) { + accumulatedTime = nextSequenceNumber * targetDuration; + } + segmentSeen = true; + } + const extinfContent = line.slice(TAG_EXTINF.length); + const commaIndex = extinfContent.indexOf(","); + const durationStr = commaIndex === -1 ? extinfContent : extinfContent.slice(0, commaIndex); + const duration = Number(durationStr); + if (!Number.isFinite(duration) || duration < 0) { + throw new Error(`Invalid #EXTINF tag duration '${durationStr}'.`); + } + nextSegmentDuration = duration; + } else if (line.startsWith(TAG_MAP)) { + const attributes = new AttributeList(line.slice(TAG_MAP.length)); + const uri = attributes.get("uri"); + if (!uri) { + throw new Error("Invalid #EXT-X-MAP tag; missing URI attribute."); + } + const byteRange = attributes.get("byterange"); + let parsedByteRange = null; + if (byteRange !== null) { + parsedByteRange = parseByteRange(byteRange); + } + if (parsedByteRange && parsedByteRange.offset === null) { + throw new Error("Invalid #EXT-X-MAP tag; BYTERANGE attribute must have a specified offset."); + } + if (!prevLastSegment) { + const fullPath = joinPaths(this.path, uri); + const location = { + path: fullPath, + offset: parsedByteRange?.offset ?? 0, + length: parsedByteRange?.length ?? null + }; + if (currentKey?.method === "AES-128" && !currentKey.iv) { + throw new Error("IV attribute must be set on #EXT-X-KEY tag preceding the #EXT-X-MAP tag."); + } + const segment = { + timestamp: accumulatedTime, + relativeToUnixEpoch: lastProgramDateTimeSeconds !== null, + firstSegment: null, + sequenceNumber: null, + location, + duration: 0, + encryption: currentKey, + initSegment: null, + lastProgramDateTimeSeconds + }; + currentInitSegment = segment; + } + nextSegmentDuration = null; + if (nextByteRange === null) { + lastByteRangeEnd = null; + } else { + nextByteRange = null; + } + } else if (line.startsWith(TAG_KEY)) { + const attributes = new AttributeList(line.slice(TAG_KEY.length)); + const method = attributes.get("method"); + if (method === "NONE") { + currentKey = null; + } else if (method === "AES-128") { + const uri = attributes.get("uri"); + if (!uri) { + throw new Error("Invalid #EXT-X-KEY: AES-128 requires a URI attribute."); + } + let iv = null; + const ivString = attributes.get("iv"); + if (ivString) { + if (!IV_STRING_REGEX.test(ivString)) { + throw new Error(`Unsupported IV format '${ivString}'.`); + } + let hex = ivString.slice(2); + hex = hex.padStart(AES_128_BLOCK_SIZE * 2, "0"); + iv = new Uint8Array(AES_128_BLOCK_SIZE); + for (let i2 = 0; i2 < AES_128_BLOCK_SIZE; i2++) { + const startIndex = -AES_128_BLOCK_SIZE * 2 + i2; + iv[i2] = parseInt(hex.slice(startIndex, startIndex + 2), 16); + } + } + const keyFormat = attributes.get("keyformat") ?? "identity"; + if (keyFormat !== "identity") { + throw new Error("For AES-128 encryption, only the 'identity' KEYFORMAT is currently supported. If you think other formats should be supported, please raise an issue."); + } + currentKey = { + method: "AES-128", + keyUri: joinPaths(this.path, uri), + iv, + keyFormat + }; + } else if (method === "SAMPLE-AES" || method === "SAMPLE-AES-CTR") { + const uri = attributes.get("uri"); + if (!uri) { + throw new Error(`Invalid #EXT-X-KEY: ${method} requires a URI attribute.`); + } + const keyFormat = attributes.get("keyformat") ?? "identity"; + if (keyFormat === "identity") { + throw new Error("For SAMPLE-AES and SAMPLE-AES-CTR encryption, the 'identity' KEYFORMAT is not supported. If you think this format should be supported, please raise an issue."); + } + let psshBox = null; + if (BASE64_DATA_URI_REGEX.test(uri)) { + const commaIndex = uri.indexOf(","); + const bytes = base64ToBytes(uri.slice(commaIndex + 1)); + if (bytes.length >= 8 && bytes[4] === 112 && bytes[5] === 115 && bytes[6] === 115 && bytes[7] === 104) { + const size = toDataView(bytes).getUint32(0); + psshBox = parsePsshBoxContents(bytes.subarray(8, Math.min(size, bytes.length))); + } + } + currentKey = { + method, + psshBox + }; + } else { + throw new Error(`Unsupported encryption method '${method}'. If you think this method should be supported, please raise an issue.`); + } + } else if (line.startsWith(TAG_MEDIA_SEQUENCE)) { + const value = line.slice(TAG_MEDIA_SEQUENCE.length); + const number = Number(value); + if (!Number.isInteger(number) || number < 0) { + throw new Error(`Invalid EXT-X-MEDIA-SEQUENCE value '${value}'.`); + } + setNextSequenceNumber(number); + } else if (line.startsWith(TAG_BYTERANGE)) { + const parsed = parseByteRange(line.slice(TAG_BYTERANGE.length)); + if (parsed.offset === null) { + if (lastByteRangeEnd === null) { + throw new Error("Invalid M3U8 file; #EXT-X-BYTERANGE without offset requires a previous byte range."); + } + parsed.offset = lastByteRangeEnd; + } + nextByteRange = parsed; + lastByteRangeEnd = parsed.offset + parsed.length; + } else if (line.startsWith(TAG_PROGRAM_DATE_TIME)) { + if (prevLastSegment) { + continue; + } + const dateTime = line.slice(TAG_PROGRAM_DATE_TIME.length); + const dateTimeMs = Date.parse(dateTime); + if (!Number.isFinite(dateTimeMs)) { + continue; + } + const dateTimeSeconds = dateTimeMs / 1e3; + if (lastProgramDateTimeSeconds === dateTimeSeconds) { + continue; + } + if (lastProgramDateTimeSeconds === null && this.segments.length > 0) { + const lastSegment = last(this.segments); + const lastSegmentEnd = lastSegment.timestamp + lastSegment.duration; + const offset = dateTimeSeconds - lastSegmentEnd; + for (const segment of this.segments) { + segment.timestamp += offset; + segment.relativeToUnixEpoch = true; + } + accumulatedTime += offset; + } + lastProgramDateTimeSeconds = dateTimeSeconds; + accumulatedTime = dateTimeSeconds; + } else if (line === TAG_DISCONTINUITY) { + currentFirstSegment = null; + } else if (line.startsWith(TAG_TARGETDURATION)) { + const value = line.slice(TAG_TARGETDURATION.length); + const duration = Number(value); + if (!Number.isFinite(duration) || duration < 0) { + throw new Error(`Invalid EXT-X-TARGETDURATION value '${value}'.`); + } + this.refreshInterval = duration; + targetDuration = duration; + } else if (line === TAG_ENDLIST) { + this.streamHasEnded = true; + break; + } else if (line.startsWith(TAG_PLAYLIST_TYPE)) { + const type = line.slice(TAG_PLAYLIST_TYPE.length); + if (type.toLowerCase() === "vod") { + this.streamHasEnded = true; + } + } + } + if (!headerRead) { + throw new Error("Invalid M3U8 file; no #EXTM3U header."); + } + } + async getFirstSegment() { + if (this.segments.length === 0) { + await this.runUpdateSegments(); + } + return this.segments[0] ?? null; + } + async getSegmentAt(timestamp, options) { + if (this.segments.length === 0) { + await this.runUpdateSegments(); + } + let isLazy = !!options.skipLiveWait && this.getRemainingWaitTimeMs() > 0; + while (true) { + const index = binarySearchLessOrEqual(this.segments, timestamp, (x) => x.timestamp); + if (index === -1) { + return null; + } + if (index < this.segments.length - 1 || this.streamHasEnded || isLazy) { + return this.segments[index]; + } + const segment = this.segments[index]; + if (timestamp < segment.timestamp + segment.duration) { + return segment; + } + await this.runUpdateSegments(); + if (options.skipLiveWait) { + isLazy = true; + } + } + } + async getNextSegment(segment, options) { + const index = this.segments.indexOf(segment); + assert(index !== -1); + const nextIndex = index + 1; + let isLazy = !!options.skipLiveWait && this.getRemainingWaitTimeMs() > 0; + while (true) { + if (nextIndex < this.segments.length) { + return this.segments[nextIndex]; + } + if (this.streamHasEnded || isLazy) { + return null; + } + await this.runUpdateSegments(); + if (options.skipLiveWait) { + isLazy = true; + } + } + } + async getPreviousSegment(segment) { + const index = this.segments.indexOf(segment); + assert(index !== -1); + return this.segments[index - 1] ?? null; + } + getInputForSegment(segment) { + const hlsSegment = segment; + const cacheEntry = this.inputCache.find((x) => x.segment === hlsSegment); + if (cacheEntry) { + cacheEntry.age = this.nextInputCacheAge++; + return cacheEntry.input; + } + let initInput = null; + if (hlsSegment.initSegment || hlsSegment.firstSegment) { + initInput = this.getInputForSegment(hlsSegment.initSegment ?? hlsSegment.firstSegment); + } + const formatOptions = { + ...this.input._formatOptions, + isobmff: { + ...this.input._formatOptions.isobmff, + // Intercept calls to resolveKeyId to inject our psshBox knowledge into it + resolveKeyId: this.input._formatOptions.isobmff?.resolveKeyId && ((options) => { + if (!hlsSegment.encryption || !(hlsSegment.encryption.method === "SAMPLE-AES" || hlsSegment.encryption.method === "SAMPLE-AES-CTR") || !hlsSegment.encryption.psshBox) { + return this.input._formatOptions.isobmff.resolveKeyId(options); + } + let psshBoxes = options.psshBoxes; + const { psshBox } = hlsSegment.encryption; + if ((psshBox.keyIds === null || psshBox.keyIds.includes(options.keyId)) && !psshBoxes.some((x) => psshBoxesAreEqual(x, psshBox))) { + psshBoxes = [...psshBoxes, psshBox]; + } + return this.input._formatOptions.isobmff.resolveKeyId({ ...options, psshBoxes }); + }) + } + }; + const input = new Input({ + source: new CustomPathedSource(hlsSegment.location.path, async (request) => { + assert(request.isRoot); + const proxiedRequest = { + ...request, + isRoot: false + }; + let ref; + const needsSlice = hlsSegment.location.offset > 0 || hlsSegment.location.length !== null; + if (!hlsSegment.encryption || hlsSegment.encryption.method === "SAMPLE-AES" || hlsSegment.encryption.method === "SAMPLE-AES-CTR") { + ref = await this.input._getSourceCached(proxiedRequest); + if (needsSlice) { + const slice = ref.source.slice(hlsSegment.location.offset, hlsSegment.location.length ?? void 0); + const sliceRef = slice.ref(); + ref.free(); + ref = sliceRef; + } + } else if (hlsSegment.encryption.method === "AES-128") { + const encryption = hlsSegment.encryption; + assert(encryption.iv); + let ciphertextRef = await this.input._getSourceCached(proxiedRequest); + if (needsSlice) { + const slice = ciphertextRef.source.slice(hlsSegment.location.offset, hlsSegment.location.length ?? void 0); + const sliceRef = slice.ref(); + ciphertextRef.free(); + ciphertextRef = sliceRef; + } + const ciphertextReader = new Reader(ciphertextRef.source); + const stream = createAes128CbcDecryptStream(ciphertextReader, async () => { + const env_2 = { stack: [], error: void 0, hasError: false }; + try { + const keyRef = __addDisposableResource(env_2, await this.input._getSourceCached({ path: encryption.keyUri, isRoot: false }, ENCRYPTION_KEY_CACHE_GROUP), false); + const keyReader = new Reader(keyRef.source); + const keySlice = await keyReader.requestSlice(0, AES_128_BLOCK_SIZE); + if (!keySlice) { + throw new Error("Invalid AES-128 key; expected at least 16 bytes of data."); + } + const key = readBytes(keySlice, AES_128_BLOCK_SIZE); + return { key, iv: encryption.iv }; + } catch (e_2) { + env_2.error = e_2; + env_2.hasError = true; + } finally { + __disposeResources(env_2); + } + }, () => { + ciphertextRef.free(); + }); + ref = new ReadableStreamSource(stream).ref(); + } else { + assert(false); + } + return ref; + }), + // Do not allow recursive HLS. Cool on paper, but allows for nasty infinite-depth request trees. + formats: this.input._formats.filter((x) => !(x instanceof HlsInputFormat)), + initInput: initInput ?? void 0, + formatOptions + }); + input._onFormatDetermined = (format) => { + if ((hlsSegment.encryption?.method === "SAMPLE-AES" || hlsSegment.encryption?.method === "SAMPLE-AES-CTR") && !format._isIsobmff) { + throw new Error("The SAMPLE-AES and SAMPLE-AES-CTR encryption methods are currently only supported for ISOBMFF files."); + } + }; + this.inputCache.push({ + segment: hlsSegment, + input, + age: this.nextInputCacheAge++ + }); + const MAX_INPUT_CACHE_SIZE = 4; + if (this.inputCache.length > MAX_INPUT_CACHE_SIZE) { + const minAgeIndex = arrayArgmin(this.inputCache, (x) => x.age); + assert(minAgeIndex !== -1); + this.inputCache.splice(minAgeIndex, 1); + } + return input; + } + async getLiveRefreshInterval() { + if (this.getRemainingWaitTimeMs() === 0) { + await this.runUpdateSegments(); + } + return this.streamHasEnded ? null : this.refreshInterval; + } +} +class HlsDemuxer extends Demuxer { + constructor(input) { + super(input); + this.metadataPromise = null; + this.trackBackings = null; + this.internalTracks = null; + this.segmentedInputs = []; + this.hasMasterPlaylist = true; + } + readMetadata() { + return this.metadataPromise ?? (this.metadataPromise = (async () => { + assert(this.input._rootSource instanceof PathedSource); + const { rootPath } = this.input._rootSource; + const slice = await this.input._reader.requestEntireFile(); + assert(slice); + const lines = readAllLines(slice, slice.length, { ignore: canIgnoreLine }); + const variantStreams = []; + const mediaTags = []; + for (let i = 1; i < lines.length; i++) { + const line = lines[i]; + if (line.startsWith(TAG_STREAM_INF)) { + const streamInfLineNumber = i; + const playlistPath = lines[++i]; + if (playlistPath === void 0) { + throw new Error("Incorrect M3U8 file; a line must follow the #EXT-X-STREAM-INF tag."); + } + const fullPath = joinPaths(rootPath, playlistPath); + const attributes = new AttributeList(line.slice(TAG_STREAM_INF.length)); + const bandwidth = attributes.getAsNumber("bandwidth"); + if (bandwidth === null) { + throw new Error("Invalid M3U8 file; #EXT-X-STREAM-INF tag requires a BANDWIDTH attribute with a valid numerical value."); + } + variantStreams.push({ + fullPath, + attributes, + lineNumber: streamInfLineNumber, + hasOnlyKeyPackets: false + }); + } else if (line.startsWith(TAG_I_FRAME_STREAM_INF)) { + const attributes = new AttributeList(line.slice(TAG_I_FRAME_STREAM_INF.length)); + const playlistPath = attributes.get("uri"); + if (playlistPath === null) { + throw new Error("Invalid M3U8 file; #EXT-X-I-FRAME-STREAM-INF tag requires a URI attribute."); + } + const bandwidth = attributes.getAsNumber("bandwidth"); + if (bandwidth === null) { + throw new Error("Invalid M3U8 file; #EXT-X-I-FRAME-STREAM-INF tag requires a BANDWIDTH attribute with a valid numerical value."); + } + const fullPath = joinPaths(rootPath, playlistPath); + variantStreams.push({ + fullPath, + attributes, + lineNumber: i, + hasOnlyKeyPackets: true + }); + } else if (line.startsWith(TAG_MEDIA)) { + const attributes = new AttributeList(line.slice(TAG_MEDIA.length)); + const type = attributes.get("type"); + if (type === null) { + throw new Error("Invalid M3U8 file; #EXT-X-MEDIA tag requires a TYPE attribute."); + } + const groupId = attributes.get("group-id"); + if (groupId === null) { + throw new Error("Invalid M3U8 file; #EXT-X-MEDIA tag requires a GROUP-ID attribute."); + } + let fullPath = null; + const uri = attributes.get("uri"); + if (uri !== null) { + fullPath = joinPaths(rootPath, uri); + } + mediaTags.push({ fullPath, attributes, lineNumber: i }); + } else if (line === TAG_I_FRAMES_ONLY) ; + else if (line.startsWith(TAG_EXTINF)) { + const segmentedInput = new HlsSegmentedInput(this, rootPath, null, lines); + this.segmentedInputs = [segmentedInput]; + this.hasMasterPlaylist = false; + this.trackBackings = await segmentedInput.getTrackBackings(); + return; + } + } + const videoGroupIds = [ + ...new Set(mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "video").map((tag) => tag.attributes.get("group-id"))) + ]; + const audioGroupIds = [ + ...new Set(mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "audio").map((tag) => tag.attributes.get("group-id"))) + ]; + const internalTracksByVariant = await Promise.all(variantStreams.map(async (variantStream, i) => { + const result = []; + const codecsList = variantStream.attributes.get("codecs"); + let codecStrings; + if (codecsList) { + codecStrings = codecsList.split(",").map((x) => x.trim()); + } else { + const segmentedInput = this.getSegmentedInputForPath(variantStream.fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const tracksWithCodec = await Promise.all(trackBackings.map(async (t) => ({ track: t, codec: await t.getCodec() }))); + codecStrings = await Promise.all(tracksWithCodec.filter((x) => x.codec !== null).map((x) => x.track.getDecoderConfig().then((x2) => x2.codec))); + } + const videoGroupId = variantStream.attributes.get("video"); + const audioGroupId = variantStream.attributes.get("audio"); + const containsVideoCodecs = codecStrings.some((x) => VIDEO_CODECS.includes(inferCodecFromCodecString(x))); + const containsAudioCodecs = codecStrings.some((x) => AUDIO_CODECS.includes(inferCodecFromCodecString(x))); + if (videoGroupId !== null && !containsVideoCodecs) { + if (!videoGroupIds.includes(videoGroupId)) { + throw new Error(`Invalid M3U8 file; variant stream references video group "${videoGroupId}" which is not defined in any #EXT-X-MEDIA tags.`); + } + const matchingVideoMediaTag = mediaTags.find((mediaTag) => { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + return groupId === videoGroupId && type.toLowerCase() === "video"; + }); + outer: if (matchingVideoMediaTag) { + const uri = matchingVideoMediaTag.attributes.get("uri"); + if (uri === null) { + break outer; + } + const fullPath = joinPaths(rootPath, uri); + const segmentedInput = this.getSegmentedInputForPath(fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const videoTrack = trackBackings.find((x) => x.getType() === "video"); + if (!videoTrack || await videoTrack.getCodec() === null) { + break outer; + } + const additionalCodecString = await videoTrack.getDecoderConfig().then((x) => x?.codec ?? null); + assert(additionalCodecString !== null); + codecStrings.push(additionalCodecString); + } + } + if (audioGroupId !== null && !containsAudioCodecs) { + if (!audioGroupIds.includes(audioGroupId)) { + throw new Error(`Invalid M3U8 file; variant stream references audio group "${audioGroupId}" which is not defined in any #EXT-X-MEDIA tags.`); + } + const matchingAudioMediaTag = mediaTags.find((tag) => { + const groupId = tag.attributes.get("group-id"); + const type = tag.attributes.get("type"); + return groupId === audioGroupId && type.toLowerCase() === "audio"; + }); + outer: if (matchingAudioMediaTag) { + const uri = matchingAudioMediaTag.attributes.get("uri"); + if (uri === null) { + break outer; + } + const fullPath = joinPaths(rootPath, uri); + const segmentedInput = this.getSegmentedInputForPath(fullPath); + const trackBackings = await segmentedInput.getTrackBackings(); + const audioTrack = trackBackings.find((x) => x.getType() === "audio"); + if (!audioTrack || await audioTrack.getCodec() === null) { + break outer; + } + const additionalCodecString = await audioTrack.getDecoderConfig().then((x) => x?.codec ?? null); + assert(additionalCodecString !== null); + codecStrings.push(additionalCodecString); + } + } + codecStrings = [...new Set(codecStrings)]; + let videoCodecString = null; + let audioCodecString = null; + const bandwidth = variantStream.attributes.getAsNumber("bandwidth"); + assert(bandwidth !== null); + const averageBandwidth = variantStream.attributes.getAsNumber("average-bandwidth"); + const name = variantStream.attributes.get("name"); + for (const codecString of codecStrings) { + const inferredCodec = inferCodecFromCodecString(codecString); + if (inferredCodec === null) { + continue; + } + if (VIDEO_CODECS.includes(inferredCodec)) { + if (videoCodecString !== null) { + throw new Error("Unsupported M3U8 file; multiple video codecs found in the CODECS attribute of a variant stream."); + } + videoCodecString = codecString; + const videoGroupId2 = variantStream.attributes.get("video"); + if (videoGroupId2 === null) { + const resolution = variantStream.attributes.get("resolution"); + let width = null; + let height = null; + if (resolution) { + const match = resolution.match(/^(\d+)x(\d+)$/); + if (match) { + width = Number(match[1]); + height = Number(match[2]); + } + } + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: true, + autoselect: true, + languageCode: UNDETERMINED_LANGUAGE, + lineNumber: variantStream.lineNumber, + fullPath: variantStream.fullPath, + fullCodecString: videoCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: bandwidth, + averageBitrate: averageBandwidth, + name, + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "video", + width, + height + } + }); + } else { + if (!videoGroupIds.includes(videoGroupId2)) { + throw new Error(`Invalid M3U8 file; variant stream references video group "${videoGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`); + } + for (const mediaTag of mediaTags) { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + if (groupId !== videoGroupId2 || type.toLowerCase() !== "video") { + continue; + } + const resolution = mediaTag.attributes.get("resolution") ?? variantStream.attributes.get("resolution"); + let width = null; + let height = null; + if (resolution) { + const match = resolution.match(/^(\d+)x(\d+)$/); + if (match) { + width = Number(match[1]); + height = Number(match[2]); + } + } + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: getMediaTagDefault(mediaTag.attributes), + // Autoselect is inferred to be true if the default is true + autoselect: getMediaTagDefault(mediaTag.attributes) || getMediaTagAutoselect(mediaTag.attributes), + languageCode: preprocessLanguageCode(mediaTag.attributes.get("language")), + lineNumber: mediaTag.lineNumber, + fullPath: mediaTag.fullPath ?? variantStream.fullPath, + fullCodecString: videoCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: null, + averageBitrate: null, + name: mediaTag.attributes.get("name"), + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "video", + width, + height + } + }); + } + } + } else if (AUDIO_CODECS.includes(inferredCodec)) { + if (audioCodecString !== null) { + throw new Error("Unsupported M3U8 file; multiple audio codecs found in the CODECS attribute of a variant stream."); + } + audioCodecString = codecString; + const audioGroupId2 = variantStream.attributes.get("audio"); + if (audioGroupId2 === null) { + const channels = variantStream.attributes.get("channels"); + const parsedChannels = channels !== null ? Number(channels.split("/")[0]) : null; + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: true, + autoselect: true, + languageCode: UNDETERMINED_LANGUAGE, + lineNumber: variantStream.lineNumber, + fullPath: variantStream.fullPath, + fullCodecString: audioCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: bandwidth, + averageBitrate: averageBandwidth, + name, + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "audio", + numberOfChannels: parsedChannels !== null && Number.isInteger(parsedChannels) && parsedChannels > 0 ? parsedChannels : null + } + }); + } else { + if (!audioGroupIds.includes(audioGroupId2)) { + throw new Error(`Invalid M3U8 file; variant stream references audio group "${audioGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`); + } + for (const mediaTag of mediaTags) { + const groupId = mediaTag.attributes.get("group-id"); + const type = mediaTag.attributes.get("type"); + if (groupId !== audioGroupId2 || type.toLowerCase() !== "audio") { + continue; + } + const channels = mediaTag.attributes.get("channels") ?? variantStream.attributes.get("channels"); + const parsedChannels = channels !== null ? Number(channels.split("/")[0]) : null; + result.push({ + id: -1, + demuxer: this, + backingTrack: null, + default: getMediaTagDefault(mediaTag.attributes), + // Autoselect is inferred to be true if the default is true + autoselect: getMediaTagDefault(mediaTag.attributes) || getMediaTagAutoselect(mediaTag.attributes), + languageCode: preprocessLanguageCode(mediaTag.attributes.get("language")), + lineNumber: mediaTag.lineNumber, + fullPath: mediaTag.fullPath ?? variantStream.fullPath, + fullCodecString: audioCodecString, + pairingMask: 1n << BigInt(i), + peakBitrate: null, + averageBitrate: null, + name: mediaTag.attributes.get("name"), + hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets, + info: { + type: "audio", + numberOfChannels: parsedChannels !== null && Number.isInteger(parsedChannels) && parsedChannels > 0 ? parsedChannels : null + } + }); + } + } + } + } + return result; + })); + const internalTracks = []; + const addInternalTrack = (track) => { + const existingTrack = internalTracks.find((x) => x.fullPath === track.fullPath && x.info.type === track.info.type); + if (existingTrack) { + existingTrack.pairingMask |= track.pairingMask; + existingTrack.default || (existingTrack.default = track.default); + existingTrack.autoselect || (existingTrack.autoselect = track.autoselect); + existingTrack.lineNumber = Math.min(existingTrack.lineNumber, track.lineNumber); + if (track.peakBitrate !== null) { + existingTrack.peakBitrate = Math.max(existingTrack.peakBitrate ?? -Infinity, track.peakBitrate); + } + if (track.averageBitrate !== null) { + existingTrack.averageBitrate = Math.max(existingTrack.averageBitrate ?? -Infinity, track.averageBitrate); + } + if (existingTrack.languageCode === UNDETERMINED_LANGUAGE) { + existingTrack.languageCode = track.languageCode; + } + } else { + track.id = internalTracks.length + 1; + internalTracks.push(track); + } + }; + for (const variantInternalTracks of internalTracksByVariant) { + for (const trackEntry of variantInternalTracks) { + addInternalTrack(trackEntry); + } + } + internalTracks.sort((a, b) => a.lineNumber - b.lineNumber); + this.trackBackings = []; + for (const internalTrack of internalTracks) { + if (internalTrack.info.type === "video") { + this.trackBackings.push(new HlsInputVideoTrackBacking(internalTrack)); + } else { + this.trackBackings.push(new HlsInputAudioTrackBacking(internalTrack)); + } + } + this.internalTracks = internalTracks; + })()); + } + async getTrackBackings() { + await this.readMetadata(); + assert(this.trackBackings); + return this.trackBackings; + } + getSegmentedInputForPath(path) { + let segmentedInput = this.segmentedInputs.find((x) => x.path === path); + if (segmentedInput) { + return segmentedInput; + } + let decls = null; + if (this.internalTracks) { + const tracks = this.internalTracks.filter((x) => x.fullPath === path); + decls = tracks.map((x) => ({ + id: x.id, + type: x.info.type + })); + } + segmentedInput = new HlsSegmentedInput(this, path, decls, null); + this.segmentedInputs.push(segmentedInput); + return segmentedInput; + } + async getMetadataTags() { + return {}; + } + async getMimeType() { + return HLS_MIME_TYPE; + } + dispose() { + if (this.segmentedInputs) { + for (const segInput of this.segmentedInputs) { + segInput.dispose(); + } + this.segmentedInputs.length = 0; + } + } +} +class HlsInputTrackBacking { + constructor(internalTrack) { + this.internalTrack = internalTrack; + this.hydrationPromise = null; + } + hydrate() { + return this.hydrationPromise ?? (this.hydrationPromise = (async () => { + const segmentedInput = this.internalTrack.demuxer.getSegmentedInputForPath(this.internalTrack.fullPath); + let trackBacking = null; + const trackBackings = await segmentedInput.getTrackBackings(); + const matchingType = trackBackings.filter((x) => x.getType() === this.getType()); + if (matchingType.length === 1) { + trackBacking = matchingType[0]; + } else { + if (this instanceof HlsInputVideoTrackBacking) { + for (const backing of matchingType) { + if (await backing.getCodec() === this.getCodec()) { + trackBacking = backing; + break; + } + } + } else { + assert(this instanceof HlsInputAudioTrackBacking); + for (const backing of matchingType) { + if (await backing.getCodec() === this.getCodec()) { + trackBacking = backing; + break; + } + } + } + } + if (!trackBacking) { + throw new Error("Could not find matching track in underlying media data."); + } + this.internalTrack.backingTrack = trackBacking; + })()); + } + /** If the backing track is already present, delegate synchronously; otherwise, hydrate first. */ + delegate(fn) { + if (this.internalTrack.backingTrack) { + return fn(); + } + return this.hydrate().then(fn); + } + getCodec() { + throw new Error("Not implemented on base class."); + } + getDisposition() { + return { + ...DEFAULT_TRACK_DISPOSITION, + // Meanings are swapped in HLS: "Default" means that a track is the primary track. + default: this.internalTrack.autoselect, + primary: this.internalTrack.default + }; + } + getId() { + return this.internalTrack.id; + } + getPairingMask() { + return this.internalTrack.pairingMask; + } + getInternalCodecId() { + return null; + } + getLanguageCode() { + return this.internalTrack.languageCode; + } + getName() { + return this.internalTrack.name; + } + getNumber() { + assert(this.internalTrack.demuxer.internalTracks); + const trackType = this.internalTrack.info.type; + let number = 0; + for (const track of this.internalTrack.demuxer.internalTracks) { + if (track.info.type === trackType) { + number++; + } + if (track === this.internalTrack) { + break; + } + } + return number; + } + getTimeResolution() { + return this.delegate(() => this.internalTrack.backingTrack.getTimeResolution()); + } + isRelativeToUnixEpoch() { + return this.delegate(() => this.internalTrack.backingTrack.isRelativeToUnixEpoch()); + } + getBitrate() { + return this.internalTrack.peakBitrate; + } + getAverageBitrate() { + return this.internalTrack.averageBitrate; + } + async getDurationFromMetadata(options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getDurationFromMetadata(options); + } + async getLiveRefreshInterval() { + await this.hydrate(); + return this.internalTrack.backingTrack.getLiveRefreshInterval(); + } + getHasOnlyKeyPackets() { + return this.internalTrack.hasOnlyKeyPackets || null; + } + async getFirstPacket(options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getFirstPacket(options); + } + async getPacket(timestamp, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getPacket(timestamp, options); + } + async getKeyPacket(timestamp, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getKeyPacket(timestamp, options); + } + async getNextPacket(packet, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getNextPacket(packet, options); + } + async getNextKeyPacket(packet, options) { + await this.hydrate(); + return this.internalTrack.backingTrack.getNextKeyPacket(packet, options); + } +} +class HlsInputVideoTrackBacking extends HlsInputTrackBacking { + constructor(internalTrack) { + super(internalTrack); + } + get backingVideoTrack() { + return this.internalTrack.backingTrack; + } + getType() { + return "video"; + } + getCodec() { + const inferredCodec = inferCodecFromCodecString(this.internalTrack.fullCodecString); + return inferredCodec; + } + getCodedWidth() { + return this.delegate(() => this.backingVideoTrack.getCodedWidth()); + } + getCodedHeight() { + return this.delegate(() => this.backingVideoTrack.getCodedHeight()); + } + getSquarePixelWidth() { + return this.delegate(() => this.backingVideoTrack.getSquarePixelWidth()); + } + getSquarePixelHeight() { + return this.delegate(() => this.backingVideoTrack.getSquarePixelHeight()); + } + getMetadataDisplayWidth() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.info.width; + } + getMetadataDisplayHeight() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.info.height; + } + getRotation() { + return this.delegate(() => this.backingVideoTrack.getRotation()); + } + async getColorSpace() { + await this.hydrate(); + return this.backingVideoTrack.getColorSpace(); + } + async canBeTransparent() { + await this.hydrate(); + return this.backingVideoTrack.canBeTransparent(); + } + getMetadataCodecParameterString() { + if (this.backingVideoTrack) { + return null; + } + return this.internalTrack.fullCodecString; + } + async getDecoderConfig() { + await this.hydrate(); + return this.backingVideoTrack.getDecoderConfig(); + } +} +class HlsInputAudioTrackBacking extends HlsInputTrackBacking { + constructor(internalTrack) { + super(internalTrack); + } + get backingAudioTrack() { + return this.internalTrack.backingTrack; + } + getType() { + return "audio"; + } + getCodec() { + const inferredCodec = inferCodecFromCodecString(this.internalTrack.fullCodecString); + return inferredCodec; + } + getNumberOfChannels() { + if (this.internalTrack.info.numberOfChannels !== null) { + return this.internalTrack.info.numberOfChannels; + } + return this.delegate(() => this.backingAudioTrack.getNumberOfChannels()); + } + getSampleRate() { + return this.delegate(() => this.backingAudioTrack.getSampleRate()); + } + getMetadataCodecParameterString() { + if (this.backingAudioTrack) { + return null; + } + return this.internalTrack.fullCodecString; + } + async getDecoderConfig() { + await this.hydrate(); + return this.backingAudioTrack.getDecoderConfig(); + } +} +const getMediaTagDefault = (attributes) => { + const value = attributes.get("default"); + if (value === null) { + return false; + } + const normalized = value.toUpperCase(); + if (normalized === "YES") { + return true; + } + if (normalized === "NO") { + return false; + } + throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA DEFAULT attribute must be YES or NO, got "${value}".`); +}; +const getMediaTagAutoselect = (attributes) => { + const value = attributes.get("autoselect"); + if (value === null) { + return false; + } + const normalized = value.toUpperCase(); + if (normalized === "YES") { + return true; + } + if (normalized === "NO") { + return false; + } + throw new Error(`Invalid M3U8 file; #EXT-X-MEDIA AUTOSELECT attribute must be YES or NO, got "${value}".`); +}; +const preprocessLanguageCode = (code) => { + if (code === null) { + return UNDETERMINED_LANGUAGE; + } + const languageSubtag = code.split("-")[0]; + if (!languageSubtag) { + return UNDETERMINED_LANGUAGE; + } + return languageSubtag; +}; +class InputFormat { + constructor() { + this._isIsobmff = false; + } +} +class IsobmffInputFormat extends InputFormat { + constructor() { + super(...arguments); + this._isIsobmff = true; + } + /** @internal */ + async _getMajorBrand(input) { + let slice = input._reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return null; + slice.skip(4); + const fourCc = readAscii(slice, 4); + if (fourCc !== "ftyp" && fourCc !== "styp") { + return null; + } + return readAscii(slice, 4); + } + /** @internal */ + _createDemuxer(input) { + return new IsobmffDemuxer(input); + } +} +class Mp4InputFormat extends IsobmffInputFormat { + /** @internal */ + async _canReadInput(input) { + const majorBrand = await this._getMajorBrand(input); + if (majorBrand !== null) { + return majorBrand !== "qt "; + } + let slice = input._reader.requestSlice(4, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "moof"; + } + get name() { + return "MP4"; + } + get mimeType() { + return "video/mp4"; + } +} +class QuickTimeInputFormat extends IsobmffInputFormat { + /** @internal */ + async _canReadInput(input) { + const majorBrand = await this._getMajorBrand(input); + return majorBrand === "qt "; + } + get name() { + return "QuickTime File Format"; + } + get mimeType() { + return "video/quicktime"; + } +} +class MatroskaInputFormat extends InputFormat { + /** @internal */ + async isSupportedEBMLOfDocType(input, desiredDocType) { + let headerSlice = input._reader.requestSlice(0, MAX_HEADER_SIZE); + if (headerSlice instanceof Promise) + headerSlice = await headerSlice; + if (!headerSlice) + return false; + const varIntSize = readVarIntSize(headerSlice); + if (varIntSize === null) { + return false; + } + if (varIntSize < 1 || varIntSize > 8) { + return false; + } + const id = readUnsignedInt(headerSlice, varIntSize); + if (id !== EBMLId.EBML) { + return false; + } + const dataSize = readElementSize(headerSlice); + if (typeof dataSize !== "number") { + return false; + } + let dataSlice = input._reader.requestSlice(headerSlice.filePos, dataSize); + if (dataSlice instanceof Promise) + dataSlice = await dataSlice; + if (!dataSlice) + return false; + const startPos = headerSlice.filePos; + while (dataSlice.filePos <= startPos + dataSize - MIN_HEADER_SIZE) { + const header = readElementHeader(dataSlice); + if (!header) + break; + const { id: id2, size } = header; + const dataStartPos = dataSlice.filePos; + if (size === void 0) + return false; + switch (id2) { + case EBMLId.EBMLVersion: + { + const ebmlVersion = readUnsignedInt(dataSlice, size); + if (ebmlVersion !== 1) { + return false; + } + } + break; + case EBMLId.EBMLReadVersion: + { + const ebmlReadVersion = readUnsignedInt(dataSlice, size); + if (ebmlReadVersion !== 1) { + return false; + } + } + break; + case EBMLId.DocType: + { + const docType = readAsciiString(dataSlice, size); + if (docType !== desiredDocType) { + return false; + } + } + break; + case EBMLId.DocTypeVersion: + { + const docTypeVersion = readUnsignedInt(dataSlice, size); + if (docTypeVersion > 4) { + return false; + } + } + break; + } + dataSlice.filePos = dataStartPos + size; + } + return true; + } + /** @internal */ + _canReadInput(input) { + return this.isSupportedEBMLOfDocType(input, "matroska"); + } + /** @internal */ + _createDemuxer(input) { + return new MatroskaDemuxer(input); + } + get name() { + return "Matroska"; + } + get mimeType() { + return "video/x-matroska"; + } +} +class WebMInputFormat extends MatroskaInputFormat { + /** @internal */ + _canReadInput(input) { + return this.isSupportedEBMLOfDocType(input, "webm"); + } + get name() { + return "WebM"; + } + get mimeType() { + return "video/webm"; + } +} +class Mp3InputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let currentPos = 0; + while (true) { + let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + currentPos = slice2.filePos + id3V2Header.size; + } + const firstResult = await readNextMp3FrameHeader(input._reader, currentPos, currentPos + 4096); + if (!firstResult) { + return false; + } + const firstHeader = firstResult.header; + const xingOffset = getXingOffset(firstHeader.mpegVersionId, firstHeader.channel); + let slice = input._reader.requestSlice(firstResult.startPos + xingOffset, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const word = readU32Be(slice); + const isXing = word === XING || word === INFO; + if (isXing) { + return true; + } + currentPos = firstResult.startPos + firstResult.header.totalSize; + const secondResult = await readNextMp3FrameHeader(input._reader, currentPos, currentPos + FRAME_HEADER_SIZE); + if (!secondResult) { + return false; + } + const secondHeader = secondResult.header; + if (firstHeader.channel !== secondHeader.channel || firstHeader.sampleRate !== secondHeader.sampleRate) { + return false; + } + return true; + } + /** @internal */ + _createDemuxer(input) { + return new Mp3Demuxer(input); + } + get name() { + return "MP3"; + } + get mimeType() { + return "audio/mpeg"; + } +} +class WaveInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 12); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const riffType = readAscii(slice, 4); + if (riffType !== "RIFF" && riffType !== "RIFX" && riffType !== "RF64") { + return false; + } + slice.skip(4); + const format = readAscii(slice, 4); + return format === "WAVE"; + } + /** @internal */ + _createDemuxer(input) { + return new WaveDemuxer(input); + } + get name() { + return "WAVE"; + } + get mimeType() { + return "audio/wav"; + } +} +class OggInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "OggS"; + } + /** @internal */ + _createDemuxer(input) { + return new OggDemuxer(input); + } + get name() { + return "Ogg"; + } + get mimeType() { + return "application/ogg"; + } +} +class FlacInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 4); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + return readAscii(slice, 4) === "fLaC"; + } + get name() { + return "FLAC"; + } + get mimeType() { + return "audio/flac"; + } + /** @internal */ + _createDemuxer(input) { + return new FlacDemuxer(input); + } +} +class AdtsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let currentPos = 0; + while (true) { + let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); + if (slice2 instanceof Promise) + slice2 = await slice2; + if (!slice2) + break; + const id3V2Header = readId3V2Header(slice2); + if (!id3V2Header) { + break; + } + currentPos = slice2.filePos + id3V2Header.size; + } + let slice = input._reader.requestSliceRange(currentPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const firstHeader = readAdtsFrameHeader(slice); + if (!firstHeader) { + return false; + } + currentPos += firstHeader.frameLength; + slice = input._reader.requestSliceRange(currentPos, MIN_ADTS_FRAME_HEADER_SIZE, MAX_ADTS_FRAME_HEADER_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const secondHeader = readAdtsFrameHeader(slice); + if (!secondHeader) { + return false; + } + return firstHeader.objectType === secondHeader.objectType && firstHeader.samplingFrequencyIndex === secondHeader.samplingFrequencyIndex && firstHeader.channelConfiguration === secondHeader.channelConfiguration; + } + /** @internal */ + _createDemuxer(input) { + return new AdtsDemuxer(input); + } + get name() { + return "ADTS"; + } + get mimeType() { + return "audio/aac"; + } +} +class MpegTsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + const lengthToCheck = TS_PACKET_SIZE + 16 + 1; + let slice = input._reader.requestSlice(0, lengthToCheck); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const bytes = readBytes(slice, lengthToCheck); + if (bytes[0] === 71 && bytes[TS_PACKET_SIZE] === 71) { + return true; + } else if (bytes[0] === 71 && bytes[TS_PACKET_SIZE + 16] === 71) { + return true; + } else if (bytes[4] === 71 && bytes[4 + TS_PACKET_SIZE + 4] === 71) { + return true; + } + return false; + } + /** @internal */ + _createDemuxer(input) { + return new MpegTsDemuxer(input); + } + get name() { + return "MPEG Transport Stream"; + } + get mimeType() { + return "video/MP2T"; + } +} +class HlsInputFormat extends InputFormat { + /** @internal */ + async _canReadInput(input) { + let slice = input._reader.requestSlice(0, 7); + if (slice instanceof Promise) + slice = await slice; + if (!slice) + return false; + const isM3u8 = readAscii(slice, 7) === "#EXTM3U"; + if (!isM3u8) { + return false; + } + if (!(input._rootSource instanceof PathedSource)) { + throw new TypeError("HLS inputs require `InputOptions.source` to be a PathedSource or a ref to one."); + } + input._rootSource._usedForHls = true; + return true; + } + /** @internal */ + _createDemuxer(input) { + return new HlsDemuxer(input); + } + get name() { + return "HTTP Live Streaming (HLS)"; + } + get mimeType() { + return HLS_MIME_TYPE; + } +} +const MP4 = /* @__PURE__ */ new Mp4InputFormat(); +const QTFF = /* @__PURE__ */ new QuickTimeInputFormat(); +const MATROSKA = /* @__PURE__ */ new MatroskaInputFormat(); +const WEBM = /* @__PURE__ */ new WebMInputFormat(); +const MP3 = /* @__PURE__ */ new Mp3InputFormat(); +const WAVE = /* @__PURE__ */ new WaveInputFormat(); +const OGG = /* @__PURE__ */ new OggInputFormat(); +const ADTS = /* @__PURE__ */ new AdtsInputFormat(); +const FLAC = /* @__PURE__ */ new FlacInputFormat(); +const MPEG_TS = /* @__PURE__ */ new MpegTsInputFormat(); +const HLS = /* @__PURE__ */ new HlsInputFormat(); +const ALL_FORMATS = [HLS, MP4, QTFF, MATROSKA, WEBM, WAVE, OGG, FLAC, MP3, ADTS, MPEG_TS]; +const HLS_FORMATS = [HLS, MP4, QTFF, MP3, ADTS, MPEG_TS]; +const validateInputFormatOptions = (options, prefix) => { + if (!options || typeof options !== "object") { + throw new TypeError(`${prefix}, when provided, must be an object.`); + } + if (options.isobmff !== void 0) { + if (!options.isobmff || typeof options.isobmff !== "object") { + throw new TypeError(`${prefix}.isobmff, when provided, must be an object.`); + } + if (options.isobmff.resolveKeyId !== void 0 && typeof options.isobmff.resolveKeyId !== "function") { + throw new TypeError(`${prefix}.isobmff.resolveKeyId, when provided, must be a function.`); + } } - return sign === 0 ? decoded : -decoded; }; polyfillSymbolDispose(); let lastVideoGcErrorLog = -Infinity; @@ -2373,7 +16243,7 @@ let lastAudioGcErrorLog = -Infinity; let finalizationRegistry = null; if (typeof FinalizationRegistry !== "undefined") { finalizationRegistry = new FinalizationRegistry((value) => { - const now = Date.now(); + const now = performance.now(); if (value.type === "video") { if (now - lastVideoGcErrorLog >= 1e3) { console.error(`A VideoSample was garbage collected without first being closed. For proper resource management, make sure to call close() on all your VideoSamples as soon as you're done using them.`); @@ -2431,13 +16301,21 @@ const VIDEO_SAMPLE_PIXEL_FORMATS = [ ]; const VIDEO_SAMPLE_PIXEL_FORMATS_SET = new Set(VIDEO_SAMPLE_PIXEL_FORMATS); class VideoSample { - /** The width of the frame in pixels after rotation. */ - get displayWidth() { - return this.rotation % 180 === 0 ? this.codedWidth : this.codedHeight; + /** The width of the frame in pixels. */ + get codedWidth() { + return this.visibleRect.width; } - /** The height of the frame in pixels after rotation. */ + /** The height of the frame in pixels. */ + get codedHeight() { + return this.visibleRect.height; + } + /** The display width of the frame in pixels, after aspect ratio adjustment and rotation. */ + get displayWidth() { + return this.rotation % 180 === 0 ? this.squarePixelWidth : this.squarePixelHeight; + } + /** The display height of the frame in pixels, after aspect ratio adjustment and rotation. */ get displayHeight() { - return this.rotation % 180 === 0 ? this.codedHeight : this.codedWidth; + return this.rotation % 180 === 0 ? this.squarePixelHeight : this.squarePixelWidth; } /** The presentation timestamp of the frame in microseconds. */ get microsecondTimestamp() { @@ -2478,15 +16356,54 @@ class VideoSample { if (init.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { throw new TypeError("init.duration, when provided, must be a non-negative number."); } + if (init.layout !== void 0) { + if (!Array.isArray(init.layout)) { + throw new TypeError("init.layout, when provided, must be an array."); + } + for (const plane of init.layout) { + if (!plane || typeof plane !== "object" || Array.isArray(plane)) { + throw new TypeError("Each entry in init.layout must be an object."); + } + if (!Number.isInteger(plane.offset) || plane.offset < 0) { + throw new TypeError("plane.offset must be a non-negative integer."); + } + if (!Number.isInteger(plane.stride) || plane.stride < 0) { + throw new TypeError("plane.stride must be a non-negative integer."); + } + } + } + if (init.visibleRect !== void 0) { + validateRectangle(init.visibleRect, "init.visibleRect"); + } + if (init.displayWidth !== void 0 && (!Number.isInteger(init.displayWidth) || init.displayWidth <= 0)) { + throw new TypeError("init.displayWidth, when provided, must be a positive integer."); + } + if (init.displayHeight !== void 0 && (!Number.isInteger(init.displayHeight) || init.displayHeight <= 0)) { + throw new TypeError("init.displayHeight, when provided, must be a positive integer."); + } + if (init.displayWidth !== void 0 !== (init.displayHeight !== void 0)) { + throw new TypeError("init.displayWidth and init.displayHeight must be either both provided or both omitted."); + } this._data = toUint8Array(data).slice(); this._layout = init.layout ?? createDefaultPlaneLayout(init.format, init.codedWidth, init.codedHeight); this.format = init.format; - this.codedWidth = init.codedWidth; - this.codedHeight = init.codedHeight; this.rotation = init.rotation ?? 0; this.timestamp = init.timestamp; this.duration = init.duration ?? 0; this.colorSpace = new VideoSampleColorSpace(init.colorSpace); + this.visibleRect = { + left: init.visibleRect?.left ?? 0, + top: init.visibleRect?.top ?? 0, + width: init.visibleRect?.width ?? init.codedWidth, + height: init.visibleRect?.height ?? init.codedHeight + }; + if (init.displayWidth !== void 0) { + this.squarePixelWidth = this.rotation % 180 === 0 ? init.displayWidth : init.displayHeight; + this.squarePixelHeight = this.rotation % 180 === 0 ? init.displayHeight : init.displayWidth; + } else { + this.squarePixelWidth = this.codedWidth; + this.squarePixelHeight = this.codedHeight; + } } else if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) { if (init?.rotation !== void 0 && ![0, 90, 180, 270].includes(init.rotation)) { throw new TypeError("init.rotation, when provided, must be 0, 90, 180, or 270."); @@ -2497,12 +16414,21 @@ class VideoSample { if (init?.duration !== void 0 && (!Number.isFinite(init.duration) || init.duration < 0)) { throw new TypeError("init.duration, when provided, must be a non-negative number."); } + if (init?.visibleRect !== void 0) { + validateRectangle(init.visibleRect, "init.visibleRect"); + } this._data = data; this._layout = null; this.format = data.format; - this.codedWidth = data.displayWidth; - this.codedHeight = data.displayHeight; + this.visibleRect = { + left: data.visibleRect?.x ?? 0, + top: data.visibleRect?.y ?? 0, + width: data.visibleRect?.width ?? data.codedWidth, + height: data.visibleRect?.height ?? data.codedHeight + }; this.rotation = init?.rotation ?? 0; + this.squarePixelWidth = data.displayWidth; + this.squarePixelHeight = data.displayHeight; this.timestamp = init?.timestamp ?? data.timestamp / 1e6; this.duration = init?.duration ?? (data.duration ?? 0) / 1e6; this.colorSpace = new VideoSampleColorSpace(data.colorSpace); @@ -2552,8 +16478,9 @@ class VideoSample { this._data = canvas; this._layout = null; this.format = "RGBX"; - this.codedWidth = width; - this.codedHeight = height; + this.visibleRect = { left: 0, top: 0, width, height }; + this.squarePixelWidth = width; + this.squarePixelHeight = height; this.rotation = init.rotation ?? 0; this.timestamp = init.timestamp; this.duration = init.duration ?? 0; @@ -2566,6 +16493,10 @@ class VideoSample { } else { throw new TypeError("Invalid data type: Must be a BufferSource or CanvasImageSource."); } + this.pixelAspectRatio = simplifyRational({ + num: this.squarePixelWidth * this.codedHeight, + den: this.squarePixelHeight * this.codedWidth + }); finalizationRegistry?.register(this, { type: "video", data: this._data }, this); } /** Clones this video sample. */ @@ -2590,7 +16521,10 @@ class VideoSample { timestamp: this.timestamp, duration: this.duration, colorSpace: this.colorSpace, - rotation: this.rotation + rotation: this.rotation, + visibleRect: this.visibleRect, + displayWidth: this.displayWidth, + displayHeight: this.displayHeight }); } else { return new VideoSample(this._data, { @@ -2600,7 +16534,10 @@ class VideoSample { timestamp: this.timestamp, duration: this.duration, colorSpace: this.colorSpace, - rotation: this.rotation + rotation: this.rotation, + visibleRect: this.visibleRect, + displayWidth: this.displayWidth, + displayHeight: this.displayHeight }); } } @@ -2818,7 +16755,7 @@ class VideoSample { const canvasWidth = context.canvas.width; const canvasHeight = context.canvas.height; const rotation = options.rotation ?? this.rotation; - const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [this.codedWidth, this.codedHeight] : [this.codedHeight, this.codedWidth]; + const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [this.squarePixelWidth, this.squarePixelHeight] : [this.squarePixelHeight, this.squarePixelWidth]; if (options.crop) { clampCropRectangle(options.crop, rotatedWidth, rotatedHeight); } @@ -2854,18 +16791,18 @@ class VideoSample { if (rotation === 90) { [sx, sy, sWidth, sHeight] = [ sy, - this.codedHeight - sx - sWidth, + this.squarePixelHeight - sx - sWidth, sHeight, sWidth ]; } else if (rotation === 180) { [sx, sy] = [ - this.codedWidth - sx - sWidth, - this.codedHeight - sy - sHeight + this.squarePixelWidth - sx - sWidth, + this.squarePixelHeight - sy - sHeight ]; } else if (rotation === 270) { [sx, sy, sWidth, sHeight] = [ - this.codedWidth - sy - sHeight, + this.squarePixelWidth - sy - sHeight, sx, sHeight, sWidth @@ -2922,6 +16859,26 @@ class VideoSample { class VideoSampleColorSpace { /** Creates a new VideoSampleColorSpace. */ constructor(init) { + if (init !== void 0) { + if (!init || typeof init !== "object") { + throw new TypeError("init.colorSpace, when provided, must be an object."); + } + const primariesValues = Object.keys(COLOR_PRIMARIES_MAP); + if (init.primaries != null && !primariesValues.includes(init.primaries)) { + throw new TypeError(`init.colorSpace.primaries, when provided, must be one of ${primariesValues.join(", ")}.`); + } + const transferValues = Object.keys(TRANSFER_CHARACTERISTICS_MAP); + if (init.transfer != null && !transferValues.includes(init.transfer)) { + throw new TypeError(`init.colorSpace.transfer, when provided, must be one of ${transferValues.join(", ")}.`); + } + const matrixValues = Object.keys(MATRIX_COEFFICIENTS_MAP); + if (init.matrix != null && !matrixValues.includes(init.matrix)) { + throw new TypeError(`init.colorSpace.matrix, when provided, must be one of ${matrixValues.join(", ")}.`); + } + if (init.fullRange != null && typeof init.fullRange !== "boolean") { + throw new TypeError("init.colorSpace.fullRange, when provided, must be a boolean."); + } + } this.primaries = init?.primaries ?? null; this.transfer = init?.transfer ?? null; this.matrix = init?.matrix ?? null; @@ -2941,12 +16898,13 @@ const isVideoFrame = (x) => { return typeof VideoFrame !== "undefined" && x instanceof VideoFrame; }; const clampCropRectangle = (crop, outerWidth, outerHeight) => { - crop.left = Math.min(crop.left, outerWidth); - crop.top = Math.min(crop.top, outerHeight); - crop.width = Math.min(crop.width, outerWidth - crop.left); - crop.height = Math.min(crop.height, outerHeight - crop.top); - assert(crop.width >= 0); - assert(crop.height >= 0); + const left = Math.min(crop.left, outerWidth); + const top = Math.min(crop.top, outerHeight); + const width = Math.min(crop.width, outerWidth - left); + const height = Math.min(crop.height, outerHeight - top); + assert(width >= 0); + assert(height >= 0); + return { left, top, width, height }; }; const validateCropRectangle = (crop, prefix) => { if (!crop || typeof crop !== "object") { @@ -3620,6 +17578,38 @@ const doAudioDataCopyToWebKitWorkaround = (audioData, destView, srcFormat, destF } } }; +const customVideoDecoders = []; +const customAudioDecoders = []; +const fromUlaw = (u8) => { + const MULAW_BIAS = 33; + let sign = 0; + let position = 0; + let number = ~u8; + if (number & 128) { + number &= -129; + sign = -1; + } + position = ((number & 240) >> 4) + 5; + const decoded = (1 << position | (number & 15) << position - 4 | 1 << position - 5) - MULAW_BIAS; + return sign === 0 ? decoded : -decoded; +}; +const fromAlaw = (u8) => { + let sign = 0; + let position = 0; + let number = u8 ^ 85; + if (number & 128) { + number &= -129; + sign = -1; + } + position = ((number & 240) >> 4) + 4; + let decoded = 0; + if (position !== 4) { + decoded = 1 << position | (number & 15) << position - 4 | 1 << position - 5; + } else { + decoded = number << 1 | 1; + } + return sign === 0 ? decoded : -decoded; +}; const validatePacketRetrievalOptions = (options) => { if (!options || typeof options !== "object") { throw new TypeError("options must be an object."); @@ -3633,6 +17623,9 @@ const validatePacketRetrievalOptions = (options) => { if (options.verifyKeyPackets && options.metadataOnly) { throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together."); } + if (options.skipLiveWait !== void 0 && typeof options.skipLiveWait !== "boolean") { + throw new TypeError("options.skipLiveWait, when defined, must be a boolean."); + } }; const validateTimestamp = (timestamp) => { if (!isNumber(timestamp)) { @@ -3665,15 +17658,27 @@ class EncodedPacketSink { } /** * Retrieves the track's first packet (in decode order), or null if it has no packets. The first packet is very - * likely to be a key packet. + * likely to be a key packet, but it doesn't have to be. */ - getFirstPacket(options = {}) { + async getFirstPacket(options = {}) { validatePacketRetrievalOptions(options); if (this._track.input._disposed) { throw new InputDisposedError(); } return maybeFixPacketType(this._track, this._track._backing.getFirstPacket(options), options); } + /** Retrieves the track's first key packet (in decode order), or null if it has no key packets. */ + async getFirstKeyPacket(options = {}) { + validatePacketRetrievalOptions(options); + const firstPacket = await this.getFirstPacket(options); + if (!firstPacket) { + return null; + } + if (firstPacket.type === "key") { + return firstPacket; + } + return this.getNextKeyPacket(firstPacket, options); + } /** * Retrieves the packet corresponding to the given timestamp, in seconds. More specifically, returns the last packet * (in presentation order) with a start timestamp less than or equal to the given timestamp. This method can be @@ -3682,7 +17687,7 @@ class EncodedPacketSink { * * @param timestamp - The timestamp used for retrieval, in seconds. */ - getPacket(timestamp, options = {}) { + async getPacket(timestamp, options = {}) { validateTimestamp(timestamp); validatePacketRetrievalOptions(options); if (this._track.input._disposed) { @@ -3694,7 +17699,7 @@ class EncodedPacketSink { * Retrieves the packet following the given packet (in decode order), or null if the given packet is the * last packet. */ - getNextPacket(packet, options = {}) { + async getNextPacket(packet, options = {}) { if (!(packet instanceof EncodedPacket)) { throw new TypeError("packet must be an EncodedPacket."); } @@ -3731,7 +17736,7 @@ class EncodedPacketSink { assert(packet.type === "key"); const determinedType = await this._track.determinePacketType(packet); if (determinedType === "delta") { - return this.getKeyPacket(packet.timestamp - 1 / this._track.timeResolution, options); + return this.getKeyPacket(packet.timestamp - 1 / await this._track.getTimeResolution(), options); } return packet; } @@ -3768,7 +17773,7 @@ class EncodedPacketSink { * method will intelligently preload packets based on the speed of the consumer. * * @param startPacket - (optional) The packet from which iteration should begin. This packet will also be yielded. - * @param endTimestamp - (optional) The timestamp at which iteration should end. This packet will _not_ be yielded. + * @param endPacket - (optional) The packet at which iteration should end. This packet will _not_ be yielded. */ packets(startPacket, endPacket, options = {}) { if (startPacket !== void 0 && !(startPacket instanceof EncodedPacket)) { @@ -3865,7 +17870,7 @@ class DecoderWrapper { } class BaseMediaSampleSink { /** @internal */ - mediaSamplesInRange(startTimestamp = 0, endTimestamp = Infinity) { + mediaSamplesInRange(startTimestamp = 0, endTimestamp = Infinity, options) { validateTimestamp(startTimestamp); validateTimestamp(endTimestamp); const sampleQueue = []; @@ -3877,6 +17882,11 @@ class BaseMediaSampleSink { let ended = false; let terminated = false; let outOfBandError = null; + const packetRetrievalOptions = { + ...options, + verifyKeyPackets: true, + metadataOnly: false + }; (async () => { const decoder = await this._createDecoder((sample) => { onQueueDequeue(); @@ -3911,10 +17921,10 @@ class BaseMediaSampleSink { } }); const packetSink = this._createPacketSink(); - const keyPacket = await packetSink.getKeyPacket(startTimestamp, { verifyKeyPackets: true }) ?? await packetSink.getFirstPacket(); + const keyPacket = await packetSink.getKeyPacket(startTimestamp, packetRetrievalOptions) ?? await packetSink.getFirstKeyPacket(packetRetrievalOptions); let currentPacket = keyPacket; const endPacket = void 0; - const packets = packetSink.packets(keyPacket ?? void 0, endPacket); + const packets = packetSink.packets(keyPacket ?? void 0, endPacket, packetRetrievalOptions); await packets.next(); while (currentPacket && !ended && !this._track.input._disposed) { const maxQueueSize = computeMaxQueueSize(sampleQueue.length); @@ -3992,7 +18002,7 @@ class BaseMediaSampleSink { }; } /** @internal */ - mediaSamplesAtTimestamps(timestamps) { + mediaSamplesAtTimestamps(timestamps, options) { validateAnyIterable(timestamps); const timestampIterator = toAsyncIterator(timestamps); const timestampsOfInterest = []; @@ -4007,6 +18017,11 @@ class BaseMediaSampleSink { onQueueNotEmpty(); ({ promise: queueNotEmpty, resolve: onQueueNotEmpty } = promiseWithResolvers()); }; + const retrievalOptions = { + ...options, + verifyKeyPackets: true, + metadataOnly: false + }; (async () => { const decoder = await this._createDecoder((sample) => { onQueueDequeue(); @@ -4049,7 +18064,7 @@ class BaseMediaSampleSink { if (terminated) { break; } - const nextPacket = await packetSink.getNextPacket(currentPacket); + const nextPacket = await packetSink.getNextPacket(currentPacket, retrievalOptions); assert(nextPacket); decoder.decode(nextPacket); currentPacket = nextPacket; @@ -4068,8 +18083,8 @@ class BaseMediaSampleSink { if (terminated || this._track.input._disposed) { break; } - const targetPacket = await packetSink.getPacket(timestamp); - const keyPacket = targetPacket && await packetSink.getKeyPacket(timestamp, { verifyKeyPackets: true }); + const targetPacket = await packetSink.getPacket(timestamp, retrievalOptions); + const keyPacket = targetPacket && await packetSink.getKeyPacket(timestamp, retrievalOptions); if (!keyPacket) { if (maxSequenceNumber !== -1) { await decodePackets(); @@ -4251,14 +18266,23 @@ class VideoDecoderWrapper extends DecoderWrapper { if (!isWebKit()) { insertSorted(this.inputTimestamps, packet.timestamp, (x) => x); } - if (isChromium() && this.currentPacketIndex === 0 && this.codec === "avc") { - const nalUnits = extractAvcNalUnits(packet.data, this.decoderConfig); - const filteredNalUnits = nalUnits.filter((x) => { - const type = extractNalUnitTypeForAvc(x); - return !(type >= 20 && type <= 31); - }); - const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig); - packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration); + if (isChromium() && this.currentPacketIndex === 0) { + if (this.codec === "avc") { + const filteredNalUnits = []; + for (const loc of iterateAvcNalUnits(packet.data, this.decoderConfig)) { + const type = extractNalUnitTypeForAvc(packet.data[loc.offset]); + if (!(type >= 20 && type <= 31)) { + filteredNalUnits.push(packet.data.subarray(loc.offset, loc.offset + loc.length)); + } + } + const newData = concatAvcNalUnits(filteredNalUnits, this.decoderConfig); + packet = new EncodedPacket(newData, packet.type, packet.timestamp, packet.duration); + } else if (this.codec === "hevc") { + const sanitizedData = sanitizeHevcPacketForChromium(packet.data, this.decoderConfig); + if (sanitizedData) { + packet = new EncodedPacket(sanitizedData, packet.type, packet.timestamp, packet.duration); + } + } } this.decoder.decode(packet.toEncodedVideoChunk()); this.decodeAlphaData(packet); @@ -4351,11 +18375,13 @@ class VideoDecoderWrapper extends DecoderWrapper { * and causes bugs upstream. So, let's take the dropping into our own hands. */ hasHevcRaslPicture(packetData) { - const nalUnits = extractHevcNalUnits(packetData, this.decoderConfig); - return nalUnits.some((x) => { - const type = extractNalUnitTypeForHevc(x); - return type === HevcNalUnitType.RASL_N || type === HevcNalUnitType.RASL_R; - }); + for (const loc of iterateHevcNalUnits(packetData, this.decoderConfig)) { + const type = extractNalUnitTypeForHevc(packetData[loc.offset]); + if (type === HevcNalUnitType.RASL_N || type === HevcNalUnitType.RASL_R) { + return true; + } + } + return false; } /** Handler for the WebCodecs VideoDecoder for ironing out browser differences. */ sampleHandler(sample) { @@ -4580,10 +18606,10 @@ class VideoSampleSink extends BaseMediaSampleSink { if (!await this._track.canDecode()) { throw new Error("This video track cannot be decoded by this browser. Make sure to check decodability before using a track."); } - const codec = this._track.codec; - const rotation = this._track.rotation; + const codec = await this._track.getCodec(); + const rotation = await this._track.getRotation(); const decoderConfig = await this._track.getDecoderConfig(); - const timeResolution = this._track.timeResolution; + const timeResolution = await this._track.getTimeResolution(); assert(codec && decoderConfig); return new VideoDecoderWrapper(onSample, onError, codec, decoderConfig, rotation, timeResolution); } @@ -4597,10 +18623,11 @@ class VideoSampleSink extends BaseMediaSampleSink { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getSample(timestamp) { + async getSample(timestamp, options = {}) { validateTimestamp(timestamp); - for await (const sample of this.mediaSamplesAtTimestamps([timestamp])) { + for await (const sample of this.mediaSamplesAtTimestamps([timestamp], options)) { return sample; } throw new Error("Internal error: Iterator returned nothing."); @@ -4611,9 +18638,10 @@ class VideoSampleSink extends BaseMediaSampleSink { * * @param startTimestamp - The timestamp in seconds at which to start yielding samples (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding samples (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - samples(startTimestamp = 0, endTimestamp = Infinity) { - return this.mediaSamplesInRange(startTimestamp, endTimestamp); + samples(startTimestamp = 0, endTimestamp = Infinity, options = {}) { + return this.mediaSamplesInRange(startTimestamp, endTimestamp, options); } /** * Creates an async iterator that yields a video sample (frame) for each timestamp in the argument. This method @@ -4622,14 +18650,17 @@ class VideoSampleSink extends BaseMediaSampleSink { * yield null if no frame is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - samplesAtTimestamps(timestamps) { - return this.mediaSamplesAtTimestamps(timestamps); + samplesAtTimestamps(timestamps, options = {}) { + return this.mediaSamplesAtTimestamps(timestamps, options); } } class CanvasSink { /** Creates a new {@link CanvasSink} for the given {@link InputVideoTrack}. */ constructor(videoTrack, options = {}) { + this._rotation = 0; + this._initPromise = null; this._nextCanvasIndex = 0; if (!(videoTrack instanceof InputVideoTrack)) { throw new TypeError("videoTrack must be an InputVideoTrack."); @@ -4661,45 +18692,57 @@ class CanvasSink { if (options.poolSize !== void 0 && (typeof options.poolSize !== "number" || !Number.isInteger(options.poolSize) || options.poolSize < 0)) { throw new TypeError("poolSize must be a non-negative integer."); } - const rotation = options.rotation ?? videoTrack.rotation; - const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [videoTrack.codedWidth, videoTrack.codedHeight] : [videoTrack.codedHeight, videoTrack.codedWidth]; - const crop = options.crop; - if (crop) { - clampCropRectangle(crop, rotatedWidth, rotatedHeight); - } - let [width, height] = crop ? [crop.width, crop.height] : [rotatedWidth, rotatedHeight]; - const originalAspectRatio = width / height; - if (options.width !== void 0 && options.height === void 0) { - width = options.width; - height = Math.round(width / originalAspectRatio); - } else if (options.width === void 0 && options.height !== void 0) { - height = options.height; - width = Math.round(height * originalAspectRatio); - } else if (options.width !== void 0 && options.height !== void 0) { - width = options.width; - height = options.height; - } this._videoTrack = videoTrack; this._alpha = options.alpha ?? false; - this._width = width; - this._height = height; - this._rotation = rotation; - this._crop = crop; + this._options = options; this._fit = options.fit ?? "fill"; this._videoSampleSink = new VideoSampleSink(videoTrack); this._canvasPool = Array.from({ length: options.poolSize ?? 0 }, () => null); } /** @internal */ + _ensureInit() { + return this._initPromise ?? (this._initPromise = (async () => { + const options = this._options; + const videoTrack = this._videoTrack; + const rotation = options.rotation ?? await videoTrack.getRotation(); + const squarePixelWidth = await videoTrack.getSquarePixelWidth(); + const squarePixelHeight = await videoTrack.getSquarePixelHeight(); + const [rotatedWidth, rotatedHeight] = rotation % 180 === 0 ? [squarePixelWidth, squarePixelHeight] : [squarePixelHeight, squarePixelWidth]; + let crop = options.crop; + if (crop) { + crop = clampCropRectangle(crop, rotatedWidth, rotatedHeight); + } + let [width, height] = crop ? [crop.width, crop.height] : [rotatedWidth, rotatedHeight]; + const originalAspectRatio = width / height; + if (options.width !== void 0 && options.height === void 0) { + width = options.width; + height = Math.round(width / originalAspectRatio); + } else if (options.width === void 0 && options.height !== void 0) { + height = options.height; + width = Math.round(height * originalAspectRatio); + } else if (options.width !== void 0 && options.height !== void 0) { + width = options.width; + height = options.height; + } + this._width = width; + this._height = height; + this._rotation = rotation; + this._crop = crop; + })()); + } + /** @internal */ _videoSampleToWrappedCanvas(sample) { + const width = this._width; + const height = this._height; let canvas = this._canvasPool[this._nextCanvasIndex]; let canvasIsNew = false; if (!canvas) { if (typeof document !== "undefined") { canvas = document.createElement("canvas"); - canvas.width = this._width; - canvas.height = this._height; + canvas.width = width; + canvas.height = height; } else { - canvas = new OffscreenCanvas(this._width, this._height); + canvas = new OffscreenCanvas(width, height); } if (this._canvasPool.length > 0) { this._canvasPool[this._nextCanvasIndex] = canvas; @@ -4718,9 +18761,9 @@ class CanvasSink { if (!canvasIsNew) { if (!this._alpha && isFirefox()) { context.fillStyle = "black"; - context.fillRect(0, 0, this._width, this._height); + context.fillRect(0, 0, width, height); } else { - context.clearRect(0, 0, this._width, this._height); + context.clearRect(0, 0, width, height); } } sample.drawWithFit(context, { @@ -4742,10 +18785,12 @@ class CanvasSink { * timestamp. Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getCanvas(timestamp) { + async getCanvas(timestamp, options) { validateTimestamp(timestamp); - const sample = await this._videoSampleSink.getSample(timestamp); + await this._ensureInit(); + const sample = await this._videoSampleSink.getSample(timestamp, options); return sample && this._videoSampleToWrappedCanvas(sample); } /** @@ -4754,9 +18799,11 @@ class CanvasSink { * * @param startTimestamp - The timestamp in seconds at which to start yielding canvases (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding canvases (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - canvases(startTimestamp = 0, endTimestamp = Infinity) { - return mapAsyncGenerator(this._videoSampleSink.samples(startTimestamp, endTimestamp), (sample) => this._videoSampleToWrappedCanvas(sample)); + async *canvases(startTimestamp = 0, endTimestamp = Infinity, options) { + await this._ensureInit(); + yield* mapAsyncGenerator(this._videoSampleSink.samples(startTimestamp, endTimestamp, options), (sample) => this._videoSampleToWrappedCanvas(sample)); } /** * Creates an async iterator that yields a canvas for each timestamp in the argument. This method uses an optimized @@ -4765,9 +18812,11 @@ class CanvasSink { * no frame is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - canvasesAtTimestamps(timestamps) { - return mapAsyncGenerator(this._videoSampleSink.samplesAtTimestamps(timestamps), (sample) => sample && this._videoSampleToWrappedCanvas(sample)); + async *canvasesAtTimestamps(timestamps, options) { + await this._ensureInit(); + yield* mapAsyncGenerator(this._videoSampleSink.samplesAtTimestamps(timestamps, options), (sample) => sample && this._videoSampleToWrappedCanvas(sample)); } } class AudioDecoderWrapper extends DecoderWrapper { @@ -5033,7 +19082,7 @@ class AudioSampleSink extends BaseMediaSampleSink { if (!await this._track.canDecode()) { throw new Error("This audio track cannot be decoded by this browser. Make sure to check decodability before using a track."); } - const codec = this._track.codec; + const codec = await this._track.getCodec(); const decoderConfig = await this._track.getDecoderConfig(); assert(codec && decoderConfig); if (PCM_AUDIO_CODECS.includes(decoderConfig.codec)) { @@ -5052,10 +19101,11 @@ class AudioSampleSink extends BaseMediaSampleSink { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getSample(timestamp) { + async getSample(timestamp, options = {}) { validateTimestamp(timestamp); - for await (const sample of this.mediaSamplesAtTimestamps([timestamp])) { + for await (const sample of this.mediaSamplesAtTimestamps([timestamp], options)) { return sample; } throw new Error("Internal error: Iterator returned nothing."); @@ -5066,9 +19116,10 @@ class AudioSampleSink extends BaseMediaSampleSink { * * @param startTimestamp - The timestamp in seconds at which to start yielding samples (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding samples (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - samples(startTimestamp = 0, endTimestamp = Infinity) { - return this.mediaSamplesInRange(startTimestamp, endTimestamp); + samples(startTimestamp = 0, endTimestamp = Infinity, options = {}) { + return this.mediaSamplesInRange(startTimestamp, endTimestamp, options); } /** * Creates an async iterator that yields an audio sample for each timestamp in the argument. This method @@ -5077,9 +19128,10 @@ class AudioSampleSink extends BaseMediaSampleSink { * yield null if no sample is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - samplesAtTimestamps(timestamps) { - return this.mediaSamplesAtTimestamps(timestamps); + samplesAtTimestamps(timestamps, options = {}) { + return this.mediaSamplesAtTimestamps(timestamps, options); } } class AudioBufferSink { @@ -5106,10 +19158,11 @@ class AudioBufferSink { * Returns null if the timestamp is before the track's first timestamp. * * @param timestamp - The timestamp used for retrieval, in seconds. + * @param options - Options used for the underlying packet retrieval. */ - async getBuffer(timestamp) { + async getBuffer(timestamp, options) { validateTimestamp(timestamp); - const data = await this._audioSampleSink.getSample(timestamp); + const data = await this._audioSampleSink.getSample(timestamp, options); return data && this._audioSampleToWrappedArrayBuffer(data); } /** @@ -5118,9 +19171,10 @@ class AudioBufferSink { * * @param startTimestamp - The timestamp in seconds at which to start yielding buffers (inclusive). * @param endTimestamp - The timestamp in seconds at which to stop yielding buffers (exclusive). + * @param options - Options used for the underlying packet retrieval. */ - buffers(startTimestamp = 0, endTimestamp = Infinity) { - return mapAsyncGenerator(this._audioSampleSink.samples(startTimestamp, endTimestamp), (data) => this._audioSampleToWrappedArrayBuffer(data)); + buffers(startTimestamp = 0, endTimestamp = Infinity, options) { + return mapAsyncGenerator(this._audioSampleSink.samples(startTimestamp, endTimestamp, options), (data) => this._audioSampleToWrappedArrayBuffer(data)); } /** * Creates an async iterator that yields an audio buffer for each timestamp in the argument. This method @@ -5129,9 +19183,10 @@ class AudioBufferSink { * yield null if no buffer is available for a given timestamp. * * @param timestamps - An iterable or async iterable of timestamps in seconds. + * @param options - Options used for the underlying packet retrieval. */ - buffersAtTimestamps(timestamps) { - return mapAsyncGenerator(this._audioSampleSink.samplesAtTimestamps(timestamps), (data) => data && this._audioSampleToWrappedArrayBuffer(data)); + buffersAtTimestamps(timestamps, options) { + return mapAsyncGenerator(this._audioSampleSink.samplesAtTimestamps(timestamps, options), (data) => data && this._audioSampleToWrappedArrayBuffer(data)); } } class InputTrack { @@ -5153,52 +19208,141 @@ class InputTrack { return this._backing.getId(); } /** - * The identifier of the codec used internally by the container. It is not homogenized by Mediabunny + * The 1-based index of this track among all tracks of the same type in the input file. For example, the first + * video track has number 1, the second video track has number 2, and so on. The index refers to the order in + * which the tracks are returned by {@link Input.getTracks}. + */ + get number() { + return this._backing.getNumber(); + } + /** + * Returns the identifier of the codec used internally by the container. It is not homogenized by Mediabunny * and depends entirely on the container format. * - * This field can be used to determine the codec of a track in case Mediabunny doesn't know that codec. + * This method can be used to determine the codec of a track in case Mediabunny doesn't know that codec. * - * - For ISOBMFF files, this field returns the name of the Sample Description Box (e.g. `'avc1'`). - * - For Matroska files, this field returns the value of the `CodecID` element. - * - For WAVE files, this field returns the value of the format tag in the `'fmt '` chunk. - * - For ADTS files, this field contains the `MPEG-4 Audio Object Type`. - * - In all other cases, this field is `null`. + * - For ISOBMFF files, this resolves to the name of the Sample Description Box (e.g. `'avc1'`). + * - For Matroska files, this resolves to the value of the `CodecID` element. + * - For WAVE files, this resolves to the value of the format tag in the `'fmt '` chunk. + * - For ADTS files, this resolves to the `MPEG-4 Audio Object Type`. + * - For MPEG-TS files, this resolves to the `streamType` value from the Program Map Table. + * - In all other cases, this resolves to `null`. */ - get internalCodecId() { + async getInternalCodecId() { return this._backing.getInternalCodecId(); } /** - * The ISO 639-2/T language code for this track. If the language is unknown, this field is `'und'` (undetermined). + * See {@link InputTrack.getInternalCodecId}. + * @deprecated Use {@link InputTrack.getInternalCodecId} instead. */ - get languageCode() { + get internalCodecId() { + return requireSync(this._backing.getInternalCodecId(), "internalCodecId", "getInternalCodecId"); + } + /** + * Returns the ISO 639-2/T language code for this track. If the language is unknown, this resolves to `'und'` + * (undetermined). + */ + async getLanguageCode() { return this._backing.getLanguageCode(); } - /** A user-defined name for this track. */ - get name() { + /** + * The ISO 639-2/T language code for this track. If the language is unknown, this field is `'und'` (undetermined). + * @deprecated Use {@link InputTrack.getLanguageCode} instead. + */ + get languageCode() { + return requireSync(this._backing.getLanguageCode(), "languageCode", "getLanguageCode"); + } + /** Returns the user-defined name for this track. */ + async getName() { return this._backing.getName(); } + /** + * A user-defined name for this track. + * @deprecated Use {@link InputTrack.getName} instead. + */ + get name() { + return requireSync(this._backing.getName(), "name", "getName"); + } + /** + * Returns a positive number x such that all timestamps and durations of all packets of this track are + * integer multiples of 1/x. + */ + async getTimeResolution() { + return this._backing.getTimeResolution(); + } /** * A positive number x such that all timestamps and durations of all packets of this track are * integer multiples of 1/x. + * @deprecated Use {@link InputTrack.getTimeResolution} instead. */ get timeResolution() { - return this._backing.getTimeResolution(); + return requireSync(this._backing.getTimeResolution(), "timeResolution", "getTimeResolution"); } - /** The track's disposition, i.e. information about its intended usage. */ - get disposition() { + /** + * Returns whether the timestamps of this track are relative to the Unix epoch (January 1, 1970 00:00:00 UTC). + * When `true`, each timestamp maps to a definitive point in time. + */ + async isRelativeToUnixEpoch() { + return this._backing.isRelativeToUnixEpoch(); + } + /** Returns the track's disposition, i.e. information about its intended usage. */ + async getDisposition() { return this._backing.getDisposition(); } + /** + * The track's disposition, i.e. information about its intended usage. + * @deprecated Use {@link InputTrack.getDisposition} instead. + */ + get disposition() { + return requireSync(this._backing.getDisposition(), "disposition", "getDisposition"); + } + /** + * Returns the peak bitrate of the track in bits per second, as specified in the track's metadata. This might not + * match the actual media data's bitrate. + */ + async getBitrate() { + return this._backing.getBitrate(); + } + /** + * Returns the average bitrate of the track in bits per second, as specified in the track's metadata. This might + * not match the actual media data's bitrate. + */ + async getAverageBitrate() { + return this._backing.getAverageBitrate(); + } /** * Returns the start timestamp of the first packet of this track, in seconds. While often near zero, this value * may be positive or even negative. A negative starting timestamp means the track's timing has been offset. Samples * with a negative timestamp should not be presented. */ - getFirstTimestamp() { - return this._backing.getFirstTimestamp(); + async getFirstTimestamp() { + const firstPacket = await this._backing.getFirstPacket({ metadataOnly: true }); + return firstPacket?.timestamp ?? 0; } - /** Returns the end timestamp of the last packet of this track, in seconds. */ - computeDuration() { - return this._backing.computeDuration(); + /** + * Returns the end timestamp of the last packet of this track, in seconds. + * + * By default, when the underlying media is live, this method will only resolve once the live stream ends. If you + * want to query the current end timestamp of the stream, set {@link PacketRetrievalOptions.skipLiveWait} to `true` + * in the options. + */ + async computeDuration(options) { + const lastPacket = await this._backing.getPacket(Infinity, { metadataOnly: true, ...options }); + const result = (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); + return roundToDivisor(result, await this.getTimeResolution()); + } + /** + * Gets the duration (end timestamp) in seconds of this track from metadata stored in the file. This value may be + * approximate or diverge from the actual, precise duration returned by `.computeDuration()`, but compared to that + * method, this method is cheaper. When the duration cannot be determined from the file metadata, `null` + * is returned. + * + * By default, when the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set + * {@link DurationMetadataRequestOptions.skipLiveWait} to `true` in the options. + */ + async getDurationFromMetadata(options = {}) { + return this._backing.getDurationFromMetadata(options); } /** * Computes aggregate packet statistics for this track, such as average packet rate or bitrate. @@ -5207,14 +19351,18 @@ class InputTrack { * looked at before it can return early; this means, you can use it to aggregate only a subset (prefix) of all * packets. This is very useful for getting a great estimate of video frame rate without having to scan through the * entire file. + * + * By default, when the underlying media is live and `targetPacketCount` is not set, this method will only resolve + * once the live stream ends. If you want to query the current packet statistics of the stream, set + * {@link PacketRetrievalOptions.skipLiveWait} to `true` in the options. */ - async computePacketStats(targetPacketCount = Infinity) { + async computePacketStats(targetPacketCount = Infinity, options) { const sink = new EncodedPacketSink(this); let startTimestamp = Infinity; let endTimestamp = -Infinity; let packetCount = 0; let totalPacketBytes = 0; - for await (const packet of sink.packets(void 0, void 0, { metadataOnly: true })) { + for await (const packet of sink.packets(void 0, void 0, { metadataOnly: true, ...options })) { if (packetCount >= targetPacketCount && packet.timestamp >= endTimestamp) { break; } @@ -5229,43 +19377,282 @@ class InputTrack { averageBitrate: packetCount ? Number((8 * totalPacketBytes / (endTimestamp - startTimestamp)).toPrecision(16)) : 0 }; } + /** + * Whether or not this track is currently live, meaning the media's end is still unknown. + * + * The value returned by this method may change over time as the track stops being live. To keep track of the + * track's live status, poll this method at the track's refresh interval + * via {@link InputTrack.getLiveRefreshInterval}. + */ + async isLive() { + return await this._backing.getLiveRefreshInterval() !== null; + } + /** + * Returns the track's live refresh interval in seconds, or `null` if the track is not live. This interval describes + * the time it takes, on average, for new live media data to become available. + */ + async getLiveRefreshInterval() { + return this._backing.getLiveRefreshInterval(); + } + /** + * Returns `true` if this track can be paired with the given track. Two tracks being pairable means they can be + * presented (displayed) together. + * + * Returns `false` if `other` equals `this`. + */ + canBePairedWith(other) { + if (!(other instanceof InputTrack)) { + throw new TypeError("other must be an InputTrack."); + } + if (this.input !== other.input || this === other) { + return false; + } + return (this._backing.getPairingMask() & other._backing.getPairingMask()) !== 0n; + } + /** + * Gets the list of other tracks that can be paired with this track. An optional query can be provided to narrow + * down the results. + */ + async getPairableTracks(query) { + return this.input.getTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** + * Gets the list of other video tracks that can be paired with this track. An optional query can be provided to + * narrow down the results. + */ + async getPairableVideoTracks(query) { + return this.input.getVideoTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** + * Gets the list of other audio tracks that can be paired with this track. An optional query can be provided to + * narrow down the results. + */ + async getPairableAudioTracks(query) { + return this.input.getAudioTracks(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns the primary track that can be paired with this track, optionally steered by the provided query. */ + async getPrimaryPairableVideoTrack(query) { + return this.input.getPrimaryVideoTrack(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns the primary track that can be paired with this track, optionally steered by the provided query. */ + async getPrimaryPairableAudioTrack(query) { + return this.input.getPrimaryAudioTrack(mergeInputTrackQueries({ + filter: (t) => t.canBePairedWith(this) + }, query)); + } + /** Returns `true` if there is another track that can be paired with this track. */ + async hasPairableTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + const tracks = await this.input.getTracks(); + for (const track of tracks) { + if (!this.canBePairedWith(track)) { + continue; + } + if (!predicate || await predicate(track)) { + return true; + } + } + return false; + } + /** Returns `true` if there is a video track that can be paired with this track. */ + hasPairableVideoTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + return this.hasPairableTrack(async (x) => x.isVideoTrack() && (!predicate || await predicate(x))); + } + /** Returns `true` if there is an audio track that can be paired with this track. */ + hasPairableAudioTrack(predicate) { + predicate && (predicate = toValidatedPredicate(predicate)); + return this.hasPairableTrack(async (x) => x.isAudioTrack() && (!predicate || await predicate(x))); + } } +const requireSync = (value, getterName, asyncName) => { + if (value instanceof Promise) { + throw new Error(`'${getterName}' is deprecated and not available synchronously for this track. Use the preferred '${asyncName}()' instead.`); + } + return value; +}; +const toValidatedPredicate = (predicate) => { + if (predicate !== void 0 && typeof predicate !== "function") { + throw new TypeError("predicate, when provided, must be a function."); + } + return predicate ? (track) => { + const handle = (result2) => { + if (typeof result2 !== "boolean") { + throw new TypeError("predicate must return or resolve to a boolean value."); + } + return result2; + }; + const result = predicate(track); + if (result instanceof Promise) { + return result.then(handle); + } + return handle(result); + } : void 0; +}; class InputVideoTrack extends InputTrack { /** @internal */ constructor(input, backing) { super(input, backing); + this._pixelAspectRatioCache = null; this._backing = backing; } get type() { return "video"; } - get codec() { + /** The codec of the track's packets. */ + async getCodec() { return this._backing.getCodec(); } - /** The width in pixels of the track's coded samples, before any transformations or rotations. */ - get codedWidth() { + /** + * The codec of the track's packets. + * @deprecated Use {@link InputVideoTrack.getCodec} instead. + */ + get codec() { + return requireSync(this._backing.getCodec(), "codec", "getCodec"); + } + async hasOnlyKeyPackets() { + return await this._backing.getHasOnlyKeyPackets?.() ?? false; + } + /** Returns the width in pixels of the track's coded samples, before any transformations or rotations. */ + async getCodedWidth() { return this._backing.getCodedWidth(); } - /** The height in pixels of the track's coded samples, before any transformations or rotations. */ - get codedHeight() { + /** + * The width in pixels of the track's coded samples, before any transformations or rotations. + * @deprecated Use {@link InputVideoTrack.getCodedWidth} instead. + */ + get codedWidth() { + return requireSync(this._backing.getCodedWidth(), "codedWidth", "getCodedWidth"); + } + /** Returns the height in pixels of the track's coded samples, before any transformations or rotations. */ + async getCodedHeight() { return this._backing.getCodedHeight(); } - /** The angle in degrees by which the track's frames should be rotated (clockwise). */ - get rotation() { + /** + * The height in pixels of the track's coded samples, before any transformations or rotations. + * @deprecated Use {@link InputVideoTrack.getCodedHeight} instead. + */ + get codedHeight() { + return requireSync(this._backing.getCodedHeight(), "codedHeight", "getCodedHeight"); + } + /** Returns the angle in degrees by which the track's frames should be rotated (clockwise). */ + async getRotation() { return this._backing.getRotation(); } - /** The width in pixels of the track's frames after rotation. */ - get displayWidth() { - const rotation = this._backing.getRotation(); - return rotation % 180 === 0 ? this._backing.getCodedWidth() : this._backing.getCodedHeight(); + /** + * The angle in degrees by which the track's frames should be rotated (clockwise). + * @deprecated Use {@link InputVideoTrack.getRotation} instead. + */ + get rotation() { + return requireSync(this._backing.getRotation(), "rotation", "getRotation"); } - /** The height in pixels of the track's frames after rotation. */ + /** + * Returns the width of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + */ + async getSquarePixelWidth() { + return this._backing.getSquarePixelWidth(); + } + /** + * The width of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + * @deprecated Use {@link InputVideoTrack.getSquarePixelWidth} instead. + */ + get squarePixelWidth() { + return requireSync(this._backing.getSquarePixelWidth(), "squarePixelWidth", "getSquarePixelWidth"); + } + /** + * Returns the height of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + */ + async getSquarePixelHeight() { + return this._backing.getSquarePixelHeight(); + } + /** + * The height of the track's frames in square pixels, adjusted for pixel aspect ratio but before rotation. + * @deprecated Use {@link InputVideoTrack.getSquarePixelHeight} instead. + */ + get squarePixelHeight() { + return requireSync(this._backing.getSquarePixelHeight(), "squarePixelHeight", "getSquarePixelHeight"); + } + /** + * Returns the pixel aspect ratio of the track's frames as a rational number in its reduced form. Most videos use + * square pixels (1:1). + */ + async getPixelAspectRatio() { + return this._pixelAspectRatioCache ?? (this._pixelAspectRatioCache = simplifyRational({ + num: await this.getSquarePixelWidth() * await this.getCodedHeight(), + den: await this.getSquarePixelHeight() * await this.getCodedWidth() + })); + } + /** + * The pixel aspect ratio of the track's frames, as a rational number in its reduced form. Most videos use + * square pixels (1:1). + * @deprecated Use {@link InputVideoTrack.getPixelAspectRatio} instead. + */ + get pixelAspectRatio() { + return this._pixelAspectRatioCache ?? (this._pixelAspectRatioCache = simplifyRational({ + num: requireSync(this._backing.getSquarePixelWidth(), "pixelAspectRatio", "getPixelAspectRatio") * requireSync(this._backing.getCodedHeight(), "pixelAspectRatio", "getPixelAspectRatio"), + den: requireSync(this._backing.getSquarePixelHeight(), "pixelAspectRatio", "getPixelAspectRatio") * requireSync(this._backing.getCodedWidth(), "pixelAspectRatio", "getPixelAspectRatio") + })); + } + /** Returns the display width of the track's frames in pixels, after aspect ratio adjustment and rotation. */ + async getDisplayWidth() { + const metadata = await this._backing.getMetadataDisplayWidth?.(); + if (metadata != null) { + return metadata; + } + const rotation = await this.getRotation(); + return rotation % 180 === 0 ? this.getSquarePixelWidth() : this.getSquarePixelHeight(); + } + /** + * The display width of the track's frames in pixels, after aspect ratio adjustment and rotation. + * @deprecated Use {@link InputVideoTrack.getDisplayWidth} instead. + */ + get displayWidth() { + const metadataRaw = this._backing.getMetadataDisplayWidth?.(); + if (metadataRaw !== void 0) { + const metadata = requireSync(metadataRaw, "displayWidth", "getDisplayWidth"); + if (metadata !== null) { + return metadata; + } + } + const rotation = requireSync(this._backing.getRotation(), "displayWidth", "getDisplayWidth"); + const value = rotation % 180 === 0 ? this._backing.getSquarePixelWidth() : this._backing.getSquarePixelHeight(); + return requireSync(value, "displayWidth", "getDisplayWidth"); + } + /** Returns the display height of the track's frames in pixels, after aspect ratio adjustment and rotation. */ + async getDisplayHeight() { + const metadata = await this._backing.getMetadataDisplayHeight?.(); + if (metadata != null) { + return metadata; + } + const rotation = await this.getRotation(); + return rotation % 180 === 0 ? this.getSquarePixelHeight() : this.getSquarePixelWidth(); + } + /** + * The display height of the track's frames in pixels, after aspect ratio adjustment and rotation. + * @deprecated Use {@link InputVideoTrack.getDisplayHeight} instead. + */ get displayHeight() { - const rotation = this._backing.getRotation(); - return rotation % 180 === 0 ? this._backing.getCodedHeight() : this._backing.getCodedWidth(); + const metadataRaw = this._backing.getMetadataDisplayHeight?.(); + if (metadataRaw !== void 0) { + const metadata = requireSync(metadataRaw, "displayHeight", "getDisplayHeight"); + if (metadata !== null) { + return metadata; + } + } + const rotation = requireSync(this._backing.getRotation(), "displayHeight", "getDisplayHeight"); + const value = rotation % 180 === 0 ? this._backing.getSquarePixelHeight() : this._backing.getSquarePixelWidth(); + return requireSync(value, "displayHeight", "getDisplayHeight"); } /** Returns the color space of the track's samples. */ - getColorSpace() { + async getColorSpace() { return this._backing.getColorSpace(); } /** If this method returns true, the track's samples use a high dynamic range (HDR). */ @@ -5274,7 +19661,7 @@ class InputVideoTrack extends InputTrack { return colorSpace.primaries === "bt2020" || colorSpace.primaries === "smpte432" || colorSpace.transfer === "pg" || colorSpace.transfer === "hlg" || colorSpace.matrix === "bt2020-ncl"; } /** Checks if this track may contain transparent samples with alpha data. */ - canBeTransparent() { + async canBeTransparent() { return this._backing.canBeTransparent(); } /** @@ -5282,10 +19669,14 @@ class InputVideoTrack extends InputTrack { * track's packets using a [`VideoDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder). Returns * null if the track's codec is unknown. */ - getDecoderConfig() { + async getDecoderConfig() { return this._backing.getDecoderConfig(); } async getCodecParameterString() { + const fromMetadata = await this._backing.getMetadataCodecParameterString?.(); + if (fromMetadata != null) { + return fromMetadata; + } const decoderConfig = await this._backing.getDecoderConfig(); return decoderConfig?.codec ?? null; } @@ -5295,7 +19686,7 @@ class InputVideoTrack extends InputTrack { if (!decoderConfig) { return false; } - const codec = this._backing.getCodec(); + const codec = await this._backing.getCodec(); assert(codec !== null); if (customVideoDecoders.some((x) => x.supports(codec, decoderConfig))) { return true; @@ -5317,12 +19708,13 @@ class InputVideoTrack extends InputTrack { if (packet.isMetadataOnly) { throw new TypeError("packet must not be metadata-only to determine its type."); } - if (this.codec === null) { + const codec = await this.getCodec(); + if (codec === null) { return null; } const decoderConfig = await this.getDecoderConfig(); assert(decoderConfig); - return determineVideoPacketType(this.codec, decoderConfig, packet.data); + return determineVideoPacketType(codec, decoderConfig, packet.data); } } class InputAudioTrack extends InputTrack { @@ -5334,26 +19726,55 @@ class InputAudioTrack extends InputTrack { get type() { return "audio"; } - get codec() { + /** The codec of the track's packets. */ + async getCodec() { return this._backing.getCodec(); } - /** The number of audio channels in the track. */ - get numberOfChannels() { + /** + * The codec of the track's packets. + * @deprecated Use {@link InputAudioTrack.getCodec} instead. + */ + get codec() { + return requireSync(this._backing.getCodec(), "codec", "getCodec"); + } + async hasOnlyKeyPackets() { + return await this._backing.getHasOnlyKeyPackets?.() ?? true; + } + /** Returns the number of audio channels in the track. */ + async getNumberOfChannels() { return this._backing.getNumberOfChannels(); } - /** The track's audio sample rate in hertz. */ - get sampleRate() { + /** + * The number of audio channels in the track. + * @deprecated Use {@link InputAudioTrack.getNumberOfChannels} instead. + */ + get numberOfChannels() { + return requireSync(this._backing.getNumberOfChannels(), "numberOfChannels", "getNumberOfChannels"); + } + /** Returns the track's audio sample rate in hertz. */ + async getSampleRate() { return this._backing.getSampleRate(); } + /** + * The track's audio sample rate in hertz. + * @deprecated Use {@link InputAudioTrack.getSampleRate} instead. + */ + get sampleRate() { + return requireSync(this._backing.getSampleRate(), "sampleRate", "getSampleRate"); + } /** * Returns the [decoder configuration](https://www.w3.org/TR/webcodecs/#audio-decoder-config) for decoding the * track's packets using an [`AudioDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder). Returns * null if the track's codec is unknown. */ - getDecoderConfig() { + async getDecoderConfig() { return this._backing.getDecoderConfig(); } async getCodecParameterString() { + const fromMetadata = await this._backing.getMetadataCodecParameterString?.(); + if (fromMetadata != null) { + return fromMetadata; + } const decoderConfig = await this._backing.getDecoderConfig(); return decoderConfig?.codec ?? null; } @@ -5363,7 +19784,7 @@ class InputAudioTrack extends InputTrack { if (!decoderConfig) { return false; } - const codec = this._backing.getCodec(); + const codec = await this._backing.getCodec(); assert(codec !== null); if (customAudioDecoders.some((x) => x.supports(codec, decoderConfig))) { return true; @@ -5386,4698 +19807,744 @@ class InputAudioTrack extends InputTrack { if (!(packet instanceof EncodedPacket)) { throw new TypeError("packet must be an EncodedPacket."); } - if (this.codec === null) { + if (await this.getCodec() === null) { return null; } return "key"; } } -const buildIsobmffMimeType = (info) => { - const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; - let string = base + (info.isQuickTime ? "quicktime" : "mp4"); - if (info.codecStrings.length > 0) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; - } - return string; +const desc = (value) => { + return -(value ?? -Infinity); }; -const MIN_BOX_HEADER_SIZE = 8; -const MAX_BOX_HEADER_SIZE = 16; -const readBoxHeader = (slice) => { - let totalSize = readU32Be(slice); - const name = readAscii(slice, 4); - let headerSize = 8; - const hasLargeSize = totalSize === 1; - if (hasLargeSize) { - totalSize = readU64Be(slice); - headerSize = 16; - } - const contentSize = totalSize - headerSize; - if (contentSize < 0) { - return null; - } - return { name, totalSize, headerSize, contentSize }; +const prefer = (value) => { + return -value; }; -const readFixed_16_16 = (slice) => { - return readI32Be(slice) / 65536; -}; -const readFixed_2_30 = (slice) => { - return readI32Be(slice) / 1073741824; -}; -const readIsomVariableInteger = (slice) => { - let result = 0; - for (let i = 0; i < 4; i++) { - result <<= 7; - const nextByte = readU8(slice); - result |= nextByte & 127; - if ((nextByte & 128) === 0) { - break; - } +const toValidatedInputTrackQuery = (query) => { + if (typeof query !== "object" || !query) { + throw new TypeError("query must be an object."); } - return result; -}; -const readMetadataStringShort = (slice) => { - let stringLength = readU16Be(slice); - slice.skip(2); - stringLength = Math.min(stringLength, slice.remainingLength); - return textDecoder.decode(readBytes(slice, stringLength)); -}; -const readDataBox = (slice) => { - const header = readBoxHeader(slice); - if (!header || header.name !== "data") { - return null; + if (query.filter !== void 0 && typeof query.filter !== "function") { + throw new TypeError("query.filter, when provided, must be a function."); } - if (slice.remainingLength < 8) { - return null; - } - const typeIndicator = readU32Be(slice); - slice.skip(4); - const data = readBytes(slice, header.contentSize - 8); - switch (typeIndicator) { - case 1: - return textDecoder.decode(data); - // UTF-8 - case 2: - return new TextDecoder("utf-16be").decode(data); - // UTF-16-BE - case 13: - return new RichImageData(data, "image/jpeg"); - case 14: - return new RichImageData(data, "image/png"); - case 27: - return new RichImageData(data, "image/bmp"); - default: - return data; - } -}; -class IsobmffDemuxer extends Demuxer { - constructor(input) { - super(input); - this.moovSlice = null; - this.currentTrack = null; - this.tracks = []; - this.metadataPromise = null; - this.movieTimescale = -1; - this.movieDurationInTimescale = -1; - this.isQuickTime = false; - this.metadataTags = {}; - this.currentMetadataKeys = null; - this.isFragmented = false; - this.fragmentTrackDefaults = []; - this.currentFragment = null; - this.lastReadFragment = null; - this.reader = input._reader; - } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); - } - async getTracks() { - await this.readMetadata(); - return this.tracks.map((track) => track.inputTrack); - } - async getMimeType() { - await this.readMetadata(); - const codecStrings = await Promise.all(this.tracks.map((x) => x.inputTrack.getCodecParameterString())); - return buildIsobmffMimeType({ - isQuickTime: this.isQuickTime, - hasVideo: this.tracks.some((x) => x.info?.type === "video"), - hasAudio: this.tracks.some((x) => x.info?.type === "audio"), - codecStrings: codecStrings.filter(Boolean) - }); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } - readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const startPos = currentPos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - if (boxInfo.name === "ftyp") { - const majorBrand = readAscii(slice, 4); - this.isQuickTime = majorBrand === "qt "; - } else if (boxInfo.name === "moov") { - let moovSlice = this.reader.requestSlice(slice.filePos, boxInfo.contentSize); - if (moovSlice instanceof Promise) - moovSlice = await moovSlice; - if (!moovSlice) - break; - this.moovSlice = moovSlice; - this.readContiguousBoxes(this.moovSlice); - this.tracks.sort((a, b) => Number(b.disposition.default) - Number(a.disposition.default)); - for (const track of this.tracks) { - const previousSegmentDurationsInSeconds = track.editListPreviousSegmentDurations / this.movieTimescale; - track.editListOffset -= Math.round(previousSegmentDurationsInSeconds * track.timescale); - } - break; - } - currentPos = startPos + boxInfo.totalSize; - } - if (this.isFragmented && this.reader.fileSize !== null) { - let lastWordSlice = this.reader.requestSlice(this.reader.fileSize - 4, 4); - if (lastWordSlice instanceof Promise) - lastWordSlice = await lastWordSlice; - assert(lastWordSlice); - const lastWord = readU32Be(lastWordSlice); - const potentialMfraPos = this.reader.fileSize - lastWord; - if (potentialMfraPos >= 0 && potentialMfraPos <= this.reader.fileSize - MAX_BOX_HEADER_SIZE) { - let mfraHeaderSlice = this.reader.requestSliceRange(potentialMfraPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (mfraHeaderSlice instanceof Promise) - mfraHeaderSlice = await mfraHeaderSlice; - if (mfraHeaderSlice) { - const boxInfo = readBoxHeader(mfraHeaderSlice); - if (boxInfo && boxInfo.name === "mfra") { - let mfraSlice = this.reader.requestSlice(mfraHeaderSlice.filePos, boxInfo.contentSize); - if (mfraSlice instanceof Promise) - mfraSlice = await mfraSlice; - if (mfraSlice) { - this.readContiguousBoxes(mfraSlice); - } - } - } - } - } - })()); - } - getSampleTableForTrack(internalTrack) { - if (internalTrack.sampleTable) { - return internalTrack.sampleTable; - } - const sampleTable = { - sampleTimingEntries: [], - sampleCompositionTimeOffsets: [], - sampleSizes: [], - keySampleIndices: null, - chunkOffsets: [], - sampleToChunk: [], - presentationTimestamps: null, - presentationTimestampIndexMap: null - }; - internalTrack.sampleTable = sampleTable; - assert(this.moovSlice); - const stblContainerSlice = this.moovSlice.slice(internalTrack.sampleTableByteOffset); - this.currentTrack = internalTrack; - this.traverseBox(stblContainerSlice); - this.currentTrack = null; - const isPcmCodec = internalTrack.info?.type === "audio" && internalTrack.info.codec && PCM_AUDIO_CODECS.includes(internalTrack.info.codec); - if (isPcmCodec && sampleTable.sampleCompositionTimeOffsets.length === 0) { - assert(internalTrack.info?.type === "audio"); - const pcmInfo = parsePcmCodec(internalTrack.info.codec); - const newSampleTimingEntries = []; - const newSampleSizes = []; - for (let i = 0; i < sampleTable.sampleToChunk.length; i++) { - const chunkEntry = sampleTable.sampleToChunk[i]; - const nextEntry = sampleTable.sampleToChunk[i + 1]; - const chunkCount = (nextEntry ? nextEntry.startChunkIndex : sampleTable.chunkOffsets.length) - chunkEntry.startChunkIndex; - for (let j = 0; j < chunkCount; j++) { - const startSampleIndex = chunkEntry.startSampleIndex + j * chunkEntry.samplesPerChunk; - const endSampleIndex = startSampleIndex + chunkEntry.samplesPerChunk; - const startTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, startSampleIndex, (x) => x.startIndex); - const startTimingEntry = sampleTable.sampleTimingEntries[startTimingEntryIndex]; - const endTimingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, endSampleIndex, (x) => x.startIndex); - const endTimingEntry = sampleTable.sampleTimingEntries[endTimingEntryIndex]; - const firstSampleTimestamp = startTimingEntry.startDecodeTimestamp + (startSampleIndex - startTimingEntry.startIndex) * startTimingEntry.delta; - const lastSampleTimestamp = endTimingEntry.startDecodeTimestamp + (endSampleIndex - endTimingEntry.startIndex) * endTimingEntry.delta; - const delta = lastSampleTimestamp - firstSampleTimestamp; - const lastSampleTimingEntry = last(newSampleTimingEntries); - if (lastSampleTimingEntry && lastSampleTimingEntry.delta === delta) { - lastSampleTimingEntry.count++; - } else { - newSampleTimingEntries.push({ - startIndex: chunkEntry.startChunkIndex + j, - startDecodeTimestamp: firstSampleTimestamp, - count: 1, - delta - }); - } - const chunkSize = chunkEntry.samplesPerChunk * pcmInfo.sampleSize * internalTrack.info.numberOfChannels; - newSampleSizes.push(chunkSize); - } - chunkEntry.startSampleIndex = chunkEntry.startChunkIndex; - chunkEntry.samplesPerChunk = 1; - } - sampleTable.sampleTimingEntries = newSampleTimingEntries; - sampleTable.sampleSizes = newSampleSizes; - } - if (sampleTable.sampleCompositionTimeOffsets.length > 0) { - sampleTable.presentationTimestamps = []; - for (const entry of sampleTable.sampleTimingEntries) { - for (let i = 0; i < entry.count; i++) { - sampleTable.presentationTimestamps.push({ - presentationTimestamp: entry.startDecodeTimestamp + i * entry.delta, - sampleIndex: entry.startIndex + i - }); - } - } - for (const entry of sampleTable.sampleCompositionTimeOffsets) { - for (let i = 0; i < entry.count; i++) { - const sampleIndex = entry.startIndex + i; - const sample = sampleTable.presentationTimestamps[sampleIndex]; - if (!sample) { - continue; - } - sample.presentationTimestamp += entry.offset; - } - } - sampleTable.presentationTimestamps.sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); - sampleTable.presentationTimestampIndexMap = Array(sampleTable.presentationTimestamps.length).fill(-1); - for (let i = 0; i < sampleTable.presentationTimestamps.length; i++) { - sampleTable.presentationTimestampIndexMap[sampleTable.presentationTimestamps[i].sampleIndex] = i; - } - } - return sampleTable; - } - async readFragment(startPos) { - if (this.lastReadFragment?.moofOffset === startPos) { - return this.lastReadFragment; - } - let headerSlice = this.reader.requestSliceRange(startPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const moofBoxInfo = readBoxHeader(headerSlice); - assert(moofBoxInfo?.name === "moof"); - let entireSlice = this.reader.requestSlice(startPos, moofBoxInfo.totalSize); - if (entireSlice instanceof Promise) - entireSlice = await entireSlice; - assert(entireSlice); - this.traverseBox(entireSlice); - const fragment = this.lastReadFragment; - assert(fragment && fragment.moofOffset === startPos); - for (const [, trackData] of fragment.trackData) { - const track = trackData.track; - const { fragmentPositionCache } = track; - if (!trackData.startTimestampIsFinal) { - const lookupEntry = track.fragmentLookupTable.find((x) => x.moofOffset === fragment.moofOffset); - if (lookupEntry) { - offsetFragmentTrackDataByTimestamp(trackData, lookupEntry.timestamp); - } else { - const lastCacheIndex = binarySearchLessOrEqual(fragmentPositionCache, fragment.moofOffset - 1, (x) => x.moofOffset); - if (lastCacheIndex !== -1) { - const lastCache = fragmentPositionCache[lastCacheIndex]; - offsetFragmentTrackDataByTimestamp(trackData, lastCache.endTimestamp); - } - } - trackData.startTimestampIsFinal = true; - } - const insertionIndex = binarySearchLessOrEqual(fragmentPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); - if (insertionIndex === -1 || fragmentPositionCache[insertionIndex].moofOffset !== fragment.moofOffset) { - fragmentPositionCache.splice(insertionIndex + 1, 0, { - moofOffset: fragment.moofOffset, - startTimestamp: trackData.startTimestamp, - endTimestamp: trackData.endTimestamp - }); - } - } - return fragment; - } - readContiguousBoxes(slice) { - const startIndex = slice.filePos; - while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { - const foundBox = this.traverseBox(slice); - if (!foundBox) { - break; - } - } - } - // eslint-disable-next-line @stylistic/generator-star-spacing - *iterateContiguousBoxes(slice) { - const startIndex = slice.filePos; - while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) { - const startPos = slice.filePos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - yield { boxInfo, slice }; - slice.filePos = startPos + boxInfo.totalSize; - } - } - traverseBox(slice) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G; - const startPos = slice.filePos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - return false; - } - const contentStartPos = slice.filePos; - const boxEndPos = startPos + boxInfo.totalSize; - switch (boxInfo.name) { - case "mdia": - case "minf": - case "dinf": - case "mfra": - case "edts": - { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "mvhd": - { - const version = readU8(slice); - slice.skip(3); - if (version === 1) { - slice.skip(8 + 8); - this.movieTimescale = readU32Be(slice); - this.movieDurationInTimescale = readU64Be(slice); - } else { - slice.skip(4 + 4); - this.movieTimescale = readU32Be(slice); - this.movieDurationInTimescale = readU32Be(slice); - } - } - break; - case "trak": - { - const track = { - id: -1, - demuxer: this, - inputTrack: null, - disposition: { - ...DEFAULT_TRACK_DISPOSITION - }, - info: null, - timescale: -1, - durationInMovieTimescale: -1, - durationInMediaTimescale: -1, - rotation: 0, - internalCodecId: null, - name: null, - languageCode: UNDETERMINED_LANGUAGE, - sampleTableByteOffset: -1, - sampleTable: null, - fragmentLookupTable: [], - currentFragmentState: null, - fragmentPositionCache: [], - editListPreviousSegmentDurations: 0, - editListOffset: 0 - }; - this.currentTrack = track; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - if (track.id !== -1 && track.timescale !== -1 && track.info !== null) { - if (track.info.type === "video" && track.info.width !== -1) { - const videoTrack = track; - track.inputTrack = new InputVideoTrack(this.input, new IsobmffVideoTrackBacking(videoTrack)); - this.tracks.push(track); - } else if (track.info.type === "audio" && track.info.numberOfChannels !== -1) { - const audioTrack = track; - track.inputTrack = new InputAudioTrack(this.input, new IsobmffAudioTrackBacking(audioTrack)); - this.tracks.push(track); - } - } - this.currentTrack = null; - } - break; - case "tkhd": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - const flags = readU24Be(slice); - const trackEnabled = !!(flags & 1); - track.disposition.default = trackEnabled; - if (version === 0) { - slice.skip(8); - track.id = readU32Be(slice); - slice.skip(4); - track.durationInMovieTimescale = readU32Be(slice); - } else if (version === 1) { - slice.skip(16); - track.id = readU32Be(slice); - slice.skip(4); - track.durationInMovieTimescale = readU64Be(slice); - } else { - throw new Error(`Incorrect track header version ${version}.`); - } - slice.skip(2 * 4 + 2 + 2 + 2 + 2); - const matrix = [ - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice), - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice), - readFixed_16_16(slice), - readFixed_16_16(slice), - readFixed_2_30(slice) - ]; - const rotation = normalizeRotation(roundToMultiple(extractRotationFromMatrix(matrix), 90)); - assert(rotation === 0 || rotation === 90 || rotation === 180 || rotation === 270); - track.rotation = rotation; - } - break; - case "elst": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - slice.skip(3); - let relevantEntryFound = false; - let previousSegmentDurations = 0; - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const segmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); - const mediaTime = version === 1 ? readI64Be(slice) : readI32Be(slice); - const mediaRate = readFixed_16_16(slice); - if (segmentDuration === 0) { - continue; - } - if (relevantEntryFound) { - console.warn("Unsupported edit list: multiple edits are not currently supported. Only using first edit."); - break; - } - if (mediaTime === -1) { - previousSegmentDurations += segmentDuration; - continue; - } - if (mediaRate !== 1) { - console.warn("Unsupported edit list entry: media rate must be 1."); - break; - } - track.editListPreviousSegmentDurations = previousSegmentDurations; - track.editListOffset = mediaTime; - relevantEntryFound = true; - } - } - break; - case "mdhd": - { - const track = this.currentTrack; - if (!track) { - break; - } - const version = readU8(slice); - slice.skip(3); - if (version === 0) { - slice.skip(8); - track.timescale = readU32Be(slice); - track.durationInMediaTimescale = readU32Be(slice); - } else if (version === 1) { - slice.skip(16); - track.timescale = readU32Be(slice); - track.durationInMediaTimescale = readU64Be(slice); - } - let language = readU16Be(slice); - if (language > 0) { - track.languageCode = ""; - for (let i = 0; i < 3; i++) { - track.languageCode = String.fromCharCode(96 + (language & 31)) + track.languageCode; - language >>= 5; - } - if (!isIso639Dash2LanguageCode(track.languageCode)) { - track.languageCode = UNDETERMINED_LANGUAGE; - } - } - } - break; - case "hdlr": - { - const track = this.currentTrack; - if (!track) { - break; - } - slice.skip(8); - const handlerType = readAscii(slice, 4); - if (handlerType === "vide") { - track.info = { - type: "video", - width: -1, - height: -1, - codec: null, - codecDescription: null, - colorSpace: null, - avcType: null, - avcCodecInfo: null, - hevcCodecInfo: null, - vp9CodecInfo: null, - av1CodecInfo: null - }; - } else if (handlerType === "soun") { - track.info = { - type: "audio", - numberOfChannels: -1, - sampleRate: -1, - codec: null, - codecDescription: null, - aacCodecInfo: null - }; - } - } - break; - case "stbl": - { - const track = this.currentTrack; - if (!track) { - break; - } - track.sampleTableByteOffset = startPos; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "stsd": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (track.info === null || track.sampleTable) { - break; - } - const stsdVersion = readU8(slice); - slice.skip(3); - const entries = readU32Be(slice); - for (let i = 0; i < entries; i++) { - const sampleBoxStartPos = slice.filePos; - const sampleBoxInfo = readBoxHeader(slice); - if (!sampleBoxInfo) { - break; - } - track.internalCodecId = sampleBoxInfo.name; - const lowercaseBoxName = sampleBoxInfo.name.toLowerCase(); - if (track.info.type === "video") { - if (lowercaseBoxName === "avc1" || lowercaseBoxName === "avc3") { - track.info.codec = "avc"; - track.info.avcType = lowercaseBoxName === "avc1" ? 1 : 3; - } else if (lowercaseBoxName === "hvc1" || lowercaseBoxName === "hev1") { - track.info.codec = "hevc"; - } else if (lowercaseBoxName === "vp08") { - track.info.codec = "vp8"; - } else if (lowercaseBoxName === "vp09") { - track.info.codec = "vp9"; - } else if (lowercaseBoxName === "av01") { - track.info.codec = "av1"; - } else { - console.warn(`Unsupported video codec (sample entry type '${sampleBoxInfo.name}').`); - } - slice.skip(6 * 1 + 2 + 2 + 2 + 3 * 4); - track.info.width = readU16Be(slice); - track.info.height = readU16Be(slice); - slice.skip(4 + 4 + 4 + 2 + 32 + 2 + 2); - this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); - } else { - if (lowercaseBoxName === "mp4a") ; - else if (lowercaseBoxName === "opus") { - track.info.codec = "opus"; - } else if (lowercaseBoxName === "flac") { - track.info.codec = "flac"; - } else if (lowercaseBoxName === "twos" || lowercaseBoxName === "sowt" || lowercaseBoxName === "raw " || lowercaseBoxName === "in24" || lowercaseBoxName === "in32" || lowercaseBoxName === "fl32" || lowercaseBoxName === "fl64" || lowercaseBoxName === "lpcm" || lowercaseBoxName === "ipcm" || lowercaseBoxName === "fpcm") ; - else if (lowercaseBoxName === "ulaw") { - track.info.codec = "ulaw"; - } else if (lowercaseBoxName === "alaw") { - track.info.codec = "alaw"; - } else { - console.warn(`Unsupported audio codec (sample entry type '${sampleBoxInfo.name}').`); - } - slice.skip(6 * 1 + 2); - const version = readU16Be(slice); - slice.skip(3 * 2); - let channelCount = readU16Be(slice); - let sampleSize = readU16Be(slice); - slice.skip(2 * 2); - let sampleRate = readU32Be(slice) / 65536; - if (stsdVersion === 0 && version > 0) { - if (version === 1) { - slice.skip(4); - sampleSize = 8 * readU32Be(slice); - slice.skip(2 * 4); - } else if (version === 2) { - slice.skip(4); - sampleRate = readF64Be(slice); - channelCount = readU32Be(slice); - slice.skip(4); - sampleSize = readU32Be(slice); - const flags = readU32Be(slice); - slice.skip(2 * 4); - if (lowercaseBoxName === "lpcm") { - const bytesPerSample = sampleSize + 7 >> 3; - const isFloat = Boolean(flags & 1); - const isBigEndian = Boolean(flags & 2); - const sFlags = flags & 4 ? -1 : 0; - if (sampleSize > 0 && sampleSize <= 64) { - if (isFloat) { - if (sampleSize === 32) { - track.info.codec = isBigEndian ? "pcm-f32be" : "pcm-f32"; - } - } else { - if (sFlags & 1 << bytesPerSample - 1) { - if (bytesPerSample === 1) { - track.info.codec = "pcm-s8"; - } else if (bytesPerSample === 2) { - track.info.codec = isBigEndian ? "pcm-s16be" : "pcm-s16"; - } else if (bytesPerSample === 3) { - track.info.codec = isBigEndian ? "pcm-s24be" : "pcm-s24"; - } else if (bytesPerSample === 4) { - track.info.codec = isBigEndian ? "pcm-s32be" : "pcm-s32"; - } - } else { - if (bytesPerSample === 1) { - track.info.codec = "pcm-u8"; - } - } - } - } - if (track.info.codec === null) { - console.warn("Unsupported PCM format."); - } - } - } - } - if (track.info.codec === "opus") { - sampleRate = OPUS_SAMPLE_RATE; - } - track.info.numberOfChannels = channelCount; - track.info.sampleRate = sampleRate; - if (lowercaseBoxName === "twos") { - if (sampleSize === 8) { - track.info.codec = "pcm-s8"; - } else if (sampleSize === 16) { - track.info.codec = "pcm-s16be"; - } else { - console.warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`); - track.info.codec = null; - } - } else if (lowercaseBoxName === "sowt") { - if (sampleSize === 8) { - track.info.codec = "pcm-s8"; - } else if (sampleSize === 16) { - track.info.codec = "pcm-s16"; - } else { - console.warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`); - track.info.codec = null; - } - } else if (lowercaseBoxName === "raw ") { - track.info.codec = "pcm-u8"; - } else if (lowercaseBoxName === "in24") { - track.info.codec = "pcm-s24be"; - } else if (lowercaseBoxName === "in32") { - track.info.codec = "pcm-s32be"; - } else if (lowercaseBoxName === "fl32") { - track.info.codec = "pcm-f32be"; - } else if (lowercaseBoxName === "fl64") { - track.info.codec = "pcm-f64be"; - } else if (lowercaseBoxName === "ipcm") { - track.info.codec = "pcm-s16be"; - } else if (lowercaseBoxName === "fpcm") { - track.info.codec = "pcm-f32be"; - } - this.readContiguousBoxes(slice.slice(slice.filePos, sampleBoxStartPos + sampleBoxInfo.totalSize - slice.filePos)); - } - } - } - break; - case "avcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info); - track.info.codecDescription = readBytes(slice, boxInfo.contentSize); - } - break; - case "hvcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info); - track.info.codecDescription = readBytes(slice, boxInfo.contentSize); - } - break; - case "vpcC": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - slice.skip(4); - const profile = readU8(slice); - const level = readU8(slice); - const thirdByte = readU8(slice); - const bitDepth = thirdByte >> 4; - const chromaSubsampling = thirdByte >> 1 & 7; - const videoFullRangeFlag = thirdByte & 1; - const colourPrimaries = readU8(slice); - const transferCharacteristics = readU8(slice); - const matrixCoefficients = readU8(slice); - track.info.vp9CodecInfo = { - profile, - level, - bitDepth, - chromaSubsampling, - videoFullRangeFlag, - colourPrimaries, - transferCharacteristics, - matrixCoefficients - }; - } - break; - case "av1C": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - slice.skip(1); - const secondByte = readU8(slice); - const profile = secondByte >> 5; - const level = secondByte & 31; - const thirdByte = readU8(slice); - const tier = thirdByte >> 7; - const highBitDepth = thirdByte >> 6 & 1; - const twelveBit = thirdByte >> 5 & 1; - const monochrome = thirdByte >> 4 & 1; - const chromaSubsamplingX = thirdByte >> 3 & 1; - const chromaSubsamplingY = thirdByte >> 2 & 1; - const chromaSamplePosition = thirdByte & 3; - const bitDepth = profile === 2 && highBitDepth ? twelveBit ? 12 : 10 : highBitDepth ? 10 : 8; - track.info.av1CodecInfo = { - profile, - level, - tier, - bitDepth, - monochrome, - chromaSubsamplingX, - chromaSubsamplingY, - chromaSamplePosition - }; - } - break; - case "colr": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "video"); - const colourType = readAscii(slice, 4); - if (colourType !== "nclx") { - break; - } - const colourPrimaries = readU16Be(slice); - const transferCharacteristics = readU16Be(slice); - const matrixCoefficients = readU16Be(slice); - const fullRangeFlag = Boolean(readU8(slice) & 128); - track.info.colorSpace = { - primaries: COLOR_PRIMARIES_MAP_INVERSE[colourPrimaries], - transfer: TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics], - matrix: MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients], - fullRange: fullRangeFlag - }; - } - break; - case "wave": - { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "esds": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(4); - const tag = readU8(slice); - assert(tag === 3); - readIsomVariableInteger(slice); - slice.skip(2); - const mixed = readU8(slice); - const streamDependenceFlag = (mixed & 128) !== 0; - const urlFlag = (mixed & 64) !== 0; - const ocrStreamFlag = (mixed & 32) !== 0; - if (streamDependenceFlag) { - slice.skip(2); - } - if (urlFlag) { - const urlLength = readU8(slice); - slice.skip(urlLength); - } - if (ocrStreamFlag) { - slice.skip(2); - } - const decoderConfigTag = readU8(slice); - assert(decoderConfigTag === 4); - const decoderConfigDescriptorLength = readIsomVariableInteger(slice); - const payloadStart = slice.filePos; - const objectTypeIndication = readU8(slice); - if (objectTypeIndication === 64 || objectTypeIndication === 103) { - track.info.codec = "aac"; - track.info.aacCodecInfo = { isMpeg2: objectTypeIndication === 103 }; - } else if (objectTypeIndication === 105 || objectTypeIndication === 107) { - track.info.codec = "mp3"; - } else if (objectTypeIndication === 221) { - track.info.codec = "vorbis"; - } else { - console.warn(`Unsupported audio codec (objectTypeIndication ${objectTypeIndication}) - discarding track.`); - } - slice.skip(1 + 3 + 4 + 4); - if (decoderConfigDescriptorLength > slice.filePos - payloadStart) { - const decoderSpecificInfoTag = readU8(slice); - assert(decoderSpecificInfoTag === 5); - const decoderSpecificInfoLength = readIsomVariableInteger(slice); - track.info.codecDescription = readBytes(slice, decoderSpecificInfoLength); - if (track.info.codec === "aac") { - const audioSpecificConfig = parseAacAudioSpecificConfig(track.info.codecDescription); - if (audioSpecificConfig.numberOfChannels !== null) { - track.info.numberOfChannels = audioSpecificConfig.numberOfChannels; - } - if (audioSpecificConfig.sampleRate !== null) { - track.info.sampleRate = audioSpecificConfig.sampleRate; - } - } - } - } - break; - case "enda": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - const littleEndian = readU16Be(slice) & 255; - if (littleEndian) { - if (track.info.codec === "pcm-s16be") { - track.info.codec = "pcm-s16"; - } else if (track.info.codec === "pcm-s24be") { - track.info.codec = "pcm-s24"; - } else if (track.info.codec === "pcm-s32be") { - track.info.codec = "pcm-s32"; - } else if (track.info.codec === "pcm-f32be") { - track.info.codec = "pcm-f32"; - } else if (track.info.codec === "pcm-f64be") { - track.info.codec = "pcm-f64"; - } - } - } - break; - case "pcmC": { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(1 + 3); - const formatFlags = readU8(slice); - const isLittleEndian = Boolean(formatFlags & 1); - const pcmSampleSize = readU8(slice); - if (track.info.codec === "pcm-s16be") { - if (isLittleEndian) { - if (pcmSampleSize === 16) { - track.info.codec = "pcm-s16"; - } else if (pcmSampleSize === 24) { - track.info.codec = "pcm-s24"; - } else if (pcmSampleSize === 32) { - track.info.codec = "pcm-s32"; - } else { - console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } else { - if (pcmSampleSize === 16) { - track.info.codec = "pcm-s16be"; - } else if (pcmSampleSize === 24) { - track.info.codec = "pcm-s24be"; - } else if (pcmSampleSize === 32) { - track.info.codec = "pcm-s32be"; - } else { - console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } - } else if (track.info.codec === "pcm-f32be") { - if (isLittleEndian) { - if (pcmSampleSize === 32) { - track.info.codec = "pcm-f32"; - } else if (pcmSampleSize === 64) { - track.info.codec = "pcm-f64"; - } else { - console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } else { - if (pcmSampleSize === 32) { - track.info.codec = "pcm-f32be"; - } else if (pcmSampleSize === 64) { - track.info.codec = "pcm-f64be"; - } else { - console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`); - track.info.codec = null; - } - } - } - break; - } - case "dOps": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(1); - const outputChannelCount = readU8(slice); - const preSkip = readU16Be(slice); - const inputSampleRate = readU32Be(slice); - const outputGain = readI16Be(slice); - const channelMappingFamily = readU8(slice); - let channelMappingTable; - if (channelMappingFamily !== 0) { - channelMappingTable = readBytes(slice, 2 + outputChannelCount); - } else { - channelMappingTable = new Uint8Array(0); - } - const description = new Uint8Array(8 + 1 + 1 + 2 + 4 + 2 + 1 + channelMappingTable.byteLength); - const view = new DataView(description.buffer); - view.setUint32(0, 1332770163, false); - view.setUint32(4, 1214603620, false); - view.setUint8(8, 1); - view.setUint8(9, outputChannelCount); - view.setUint16(10, preSkip, true); - view.setUint32(12, inputSampleRate, true); - view.setInt16(16, outputGain, true); - view.setUint8(18, channelMappingFamily); - description.set(channelMappingTable, 19); - track.info.codecDescription = description; - track.info.numberOfChannels = outputChannelCount; - } - break; - case "dfLa": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.info?.type === "audio"); - slice.skip(4); - const BLOCK_TYPE_MASK = 127; - const LAST_METADATA_BLOCK_FLAG_MASK = 128; - const startPos2 = slice.filePos; - while (slice.filePos < boxEndPos) { - const flagAndType = readU8(slice); - const metadataBlockLength = readU24Be(slice); - const type = flagAndType & BLOCK_TYPE_MASK; - if (type === FlacBlockType.STREAMINFO) { - slice.skip(10); - const word = readU32Be(slice); - const sampleRate = word >>> 12; - const numberOfChannels = (word >> 9 & 7) + 1; - track.info.sampleRate = sampleRate; - track.info.numberOfChannels = numberOfChannels; - slice.skip(20); - } else { - slice.skip(metadataBlockLength); - } - if (flagAndType & LAST_METADATA_BLOCK_FLAG_MASK) { - break; - } - } - const endPos = slice.filePos; - slice.filePos = startPos2; - const bytes = readBytes(slice, endPos - startPos2); - const description = new Uint8Array(4 + bytes.byteLength); - const view = new DataView(description.buffer); - view.setUint32(0, 1716281667, false); - description.set(bytes, 4); - track.info.codecDescription = description; - } - break; - case "stts": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - let currentIndex = 0; - let currentTimestamp = 0; - for (let i = 0; i < entryCount; i++) { - const sampleCount = readU32Be(slice); - const sampleDelta = readU32Be(slice); - track.sampleTable.sampleTimingEntries.push({ - startIndex: currentIndex, - startDecodeTimestamp: currentTimestamp, - count: sampleCount, - delta: sampleDelta - }); - currentIndex += sampleCount; - currentTimestamp += sampleCount * sampleDelta; - } - } - break; - case "ctts": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(1 + 3); - const entryCount = readU32Be(slice); - let sampleIndex = 0; - for (let i = 0; i < entryCount; i++) { - const sampleCount = readU32Be(slice); - const sampleOffset = readI32Be(slice); - track.sampleTable.sampleCompositionTimeOffsets.push({ - startIndex: sampleIndex, - count: sampleCount, - offset: sampleOffset - }); - sampleIndex += sampleCount; - } - } - break; - case "stsz": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const sampleSize = readU32Be(slice); - const sampleCount = readU32Be(slice); - if (sampleSize === 0) { - for (let i = 0; i < sampleCount; i++) { - const sampleSize2 = readU32Be(slice); - track.sampleTable.sampleSizes.push(sampleSize2); - } - } else { - track.sampleTable.sampleSizes.push(sampleSize); - } - } - break; - case "stz2": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - slice.skip(3); - const fieldSize = readU8(slice); - const sampleCount = readU32Be(slice); - const bytes = readBytes(slice, Math.ceil(sampleCount * fieldSize / 8)); - const bitstream = new Bitstream(bytes); - for (let i = 0; i < sampleCount; i++) { - const sampleSize = bitstream.readBits(fieldSize); - track.sampleTable.sampleSizes.push(sampleSize); - } - } - break; - case "stss": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - track.sampleTable.keySampleIndices = []; - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const sampleIndex = readU32Be(slice) - 1; - track.sampleTable.keySampleIndices.push(sampleIndex); - } - if (track.sampleTable.keySampleIndices[0] !== 0) { - track.sampleTable.keySampleIndices.unshift(0); - } - } - break; - case "stsc": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const startChunkIndex = readU32Be(slice) - 1; - const samplesPerChunk = readU32Be(slice); - const sampleDescriptionIndex = readU32Be(slice); - track.sampleTable.sampleToChunk.push({ - startSampleIndex: -1, - startChunkIndex, - samplesPerChunk, - sampleDescriptionIndex - }); - } - let startSampleIndex = 0; - for (let i = 0; i < track.sampleTable.sampleToChunk.length; i++) { - track.sampleTable.sampleToChunk[i].startSampleIndex = startSampleIndex; - if (i < track.sampleTable.sampleToChunk.length - 1) { - const nextChunk = track.sampleTable.sampleToChunk[i + 1]; - const chunkCount = nextChunk.startChunkIndex - track.sampleTable.sampleToChunk[i].startChunkIndex; - startSampleIndex += chunkCount * track.sampleTable.sampleToChunk[i].samplesPerChunk; - } - } - } - break; - case "stco": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const chunkOffset = readU32Be(slice); - track.sampleTable.chunkOffsets.push(chunkOffset); - } - } - break; - case "co64": - { - const track = this.currentTrack; - if (!track) { - break; - } - if (!track.sampleTable) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const chunkOffset = readU64Be(slice); - track.sampleTable.chunkOffsets.push(chunkOffset); - } - } - break; - case "mvex": - { - this.isFragmented = true; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } - break; - case "mehd": - { - const version = readU8(slice); - slice.skip(3); - const fragmentDuration = version === 1 ? readU64Be(slice) : readU32Be(slice); - this.movieDurationInTimescale = fragmentDuration; - } - break; - case "trex": - { - slice.skip(4); - const trackId = readU32Be(slice); - const defaultSampleDescriptionIndex = readU32Be(slice); - const defaultSampleDuration = readU32Be(slice); - const defaultSampleSize = readU32Be(slice); - const defaultSampleFlags = readU32Be(slice); - this.fragmentTrackDefaults.push({ - trackId, - defaultSampleDescriptionIndex, - defaultSampleDuration, - defaultSampleSize, - defaultSampleFlags - }); - } - break; - case "tfra": - { - const version = readU8(slice); - slice.skip(3); - const trackId = readU32Be(slice); - const track = this.tracks.find((x) => x.id === trackId); - if (!track) { - break; - } - const word = readU32Be(slice); - const lengthSizeOfTrafNum = (word & 48) >> 4; - const lengthSizeOfTrunNum = (word & 12) >> 2; - const lengthSizeOfSampleNum = word & 3; - const functions = [readU8, readU16Be, readU24Be, readU32Be]; - const readTrafNum = functions[lengthSizeOfTrafNum]; - const readTrunNum = functions[lengthSizeOfTrunNum]; - const readSampleNum = functions[lengthSizeOfSampleNum]; - const numberOfEntries = readU32Be(slice); - for (let i = 0; i < numberOfEntries; i++) { - const time = version === 1 ? readU64Be(slice) : readU32Be(slice); - const moofOffset = version === 1 ? readU64Be(slice) : readU32Be(slice); - readTrafNum(slice); - readTrunNum(slice); - readSampleNum(slice); - track.fragmentLookupTable.push({ - timestamp: time, - moofOffset - }); - } - track.fragmentLookupTable.sort((a, b) => a.timestamp - b.timestamp); - for (let i = 0; i < track.fragmentLookupTable.length - 1; i++) { - const entry1 = track.fragmentLookupTable[i]; - const entry2 = track.fragmentLookupTable[i + 1]; - if (entry1.timestamp === entry2.timestamp) { - track.fragmentLookupTable.splice(i + 1, 1); - i--; - } - } - } - break; - case "moof": - { - this.currentFragment = { - moofOffset: startPos, - moofSize: boxInfo.totalSize, - implicitBaseDataOffset: startPos, - trackData: /* @__PURE__ */ new Map() - }; - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - this.lastReadFragment = this.currentFragment; - this.currentFragment = null; - } - break; - case "traf": - { - assert(this.currentFragment); - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - if (this.currentTrack) { - const trackData = this.currentFragment.trackData.get(this.currentTrack.id); - if (trackData) { - const { currentFragmentState } = this.currentTrack; - assert(currentFragmentState); - if (currentFragmentState.startTimestamp !== null) { - offsetFragmentTrackDataByTimestamp(trackData, currentFragmentState.startTimestamp); - trackData.startTimestampIsFinal = true; - } - } - this.currentTrack.currentFragmentState = null; - this.currentTrack = null; - } - } - break; - case "tfhd": - { - assert(this.currentFragment); - slice.skip(1); - const flags = readU24Be(slice); - const baseDataOffsetPresent = Boolean(flags & 1); - const sampleDescriptionIndexPresent = Boolean(flags & 2); - const defaultSampleDurationPresent = Boolean(flags & 8); - const defaultSampleSizePresent = Boolean(flags & 16); - const defaultSampleFlagsPresent = Boolean(flags & 32); - const durationIsEmpty = Boolean(flags & 65536); - const defaultBaseIsMoof = Boolean(flags & 131072); - const trackId = readU32Be(slice); - const track = this.tracks.find((x) => x.id === trackId); - if (!track) { - break; - } - const defaults = this.fragmentTrackDefaults.find((x) => x.trackId === trackId); - this.currentTrack = track; - track.currentFragmentState = { - baseDataOffset: this.currentFragment.implicitBaseDataOffset, - sampleDescriptionIndex: defaults?.defaultSampleDescriptionIndex ?? null, - defaultSampleDuration: defaults?.defaultSampleDuration ?? null, - defaultSampleSize: defaults?.defaultSampleSize ?? null, - defaultSampleFlags: defaults?.defaultSampleFlags ?? null, - startTimestamp: null - }; - if (baseDataOffsetPresent) { - track.currentFragmentState.baseDataOffset = readU64Be(slice); - } else if (defaultBaseIsMoof) { - track.currentFragmentState.baseDataOffset = this.currentFragment.moofOffset; - } - if (sampleDescriptionIndexPresent) { - track.currentFragmentState.sampleDescriptionIndex = readU32Be(slice); - } - if (defaultSampleDurationPresent) { - track.currentFragmentState.defaultSampleDuration = readU32Be(slice); - } - if (defaultSampleSizePresent) { - track.currentFragmentState.defaultSampleSize = readU32Be(slice); - } - if (defaultSampleFlagsPresent) { - track.currentFragmentState.defaultSampleFlags = readU32Be(slice); - } - if (durationIsEmpty) { - track.currentFragmentState.defaultSampleDuration = 0; - } - } - break; - case "tfdt": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(track.currentFragmentState); - const version = readU8(slice); - slice.skip(3); - const baseMediaDecodeTime = version === 0 ? readU32Be(slice) : readU64Be(slice); - track.currentFragmentState.startTimestamp = baseMediaDecodeTime; - } - break; - case "trun": - { - const track = this.currentTrack; - if (!track) { - break; - } - assert(this.currentFragment); - assert(track.currentFragmentState); - if (this.currentFragment.trackData.has(track.id)) { - console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring..."); - break; - } - const version = readU8(slice); - const flags = readU24Be(slice); - const dataOffsetPresent = Boolean(flags & 1); - const firstSampleFlagsPresent = Boolean(flags & 4); - const sampleDurationPresent = Boolean(flags & 256); - const sampleSizePresent = Boolean(flags & 512); - const sampleFlagsPresent = Boolean(flags & 1024); - const sampleCompositionTimeOffsetsPresent = Boolean(flags & 2048); - const sampleCount = readU32Be(slice); - let dataOffset = track.currentFragmentState.baseDataOffset; - if (dataOffsetPresent) { - dataOffset += readI32Be(slice); - } - let firstSampleFlags = null; - if (firstSampleFlagsPresent) { - firstSampleFlags = readU32Be(slice); - } - let currentOffset = dataOffset; - if (sampleCount === 0) { - this.currentFragment.implicitBaseDataOffset = currentOffset; - break; - } - let currentTimestamp = 0; - const trackData = { - track, - startTimestamp: 0, - endTimestamp: 0, - firstKeyFrameTimestamp: null, - samples: [], - presentationTimestamps: [], - startTimestampIsFinal: false - }; - this.currentFragment.trackData.set(track.id, trackData); - for (let i = 0; i < sampleCount; i++) { - let sampleDuration; - if (sampleDurationPresent) { - sampleDuration = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleDuration !== null); - sampleDuration = track.currentFragmentState.defaultSampleDuration; - } - let sampleSize; - if (sampleSizePresent) { - sampleSize = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleSize !== null); - sampleSize = track.currentFragmentState.defaultSampleSize; - } - let sampleFlags; - if (sampleFlagsPresent) { - sampleFlags = readU32Be(slice); - } else { - assert(track.currentFragmentState.defaultSampleFlags !== null); - sampleFlags = track.currentFragmentState.defaultSampleFlags; - } - if (i === 0 && firstSampleFlags !== null) { - sampleFlags = firstSampleFlags; - } - let sampleCompositionTimeOffset = 0; - if (sampleCompositionTimeOffsetsPresent) { - if (version === 0) { - sampleCompositionTimeOffset = readU32Be(slice); - } else { - sampleCompositionTimeOffset = readI32Be(slice); - } - } - const isKeyFrame = !(sampleFlags & 65536); - trackData.samples.push({ - presentationTimestamp: currentTimestamp + sampleCompositionTimeOffset, - duration: sampleDuration, - byteOffset: currentOffset, - byteSize: sampleSize, - isKeyFrame - }); - currentOffset += sampleSize; - currentTimestamp += sampleDuration; - } - trackData.presentationTimestamps = trackData.samples.map((x, i) => ({ presentationTimestamp: x.presentationTimestamp, sampleIndex: i })).sort((a, b) => a.presentationTimestamp - b.presentationTimestamp); - for (let i = 0; i < trackData.presentationTimestamps.length; i++) { - const currentEntry = trackData.presentationTimestamps[i]; - const currentSample = trackData.samples[currentEntry.sampleIndex]; - if (trackData.firstKeyFrameTimestamp === null && currentSample.isKeyFrame) { - trackData.firstKeyFrameTimestamp = currentSample.presentationTimestamp; - } - if (i < trackData.presentationTimestamps.length - 1) { - const nextEntry = trackData.presentationTimestamps[i + 1]; - currentSample.duration = nextEntry.presentationTimestamp - currentEntry.presentationTimestamp; - } - } - const firstSample = trackData.samples[trackData.presentationTimestamps[0].sampleIndex]; - const lastSample = trackData.samples[last(trackData.presentationTimestamps).sampleIndex]; - trackData.startTimestamp = firstSample.presentationTimestamp; - trackData.endTimestamp = lastSample.presentationTimestamp + lastSample.duration; - this.currentFragment.implicitBaseDataOffset = currentOffset; - } - break; - // Metadata section - // https://exiftool.org/TagNames/QuickTime.html - // https://mp4workshop.com/about - case "udta": - { - const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { - if (boxInfo2.name !== "meta" && !this.currentTrack) { - const startPos2 = slice2.filePos; - (_a = this.metadataTags).raw ?? (_a.raw = {}); - if (boxInfo2.name[0] === "©") { - (_b = this.metadataTags.raw)[_c = boxInfo2.name] ?? (_b[_c] = readMetadataStringShort(slice2)); - } else { - (_d = this.metadataTags.raw)[_e = boxInfo2.name] ?? (_d[_e] = readBytes(slice2, boxInfo2.contentSize)); - } - slice2.filePos = startPos2; - } - switch (boxInfo2.name) { - case "meta": - { - slice2.skip(-boxInfo2.headerSize); - this.traverseBox(slice2); - } - break; - case "©nam": - case "name": - { - if (this.currentTrack) { - this.currentTrack.name = textDecoder.decode(readBytes(slice2, boxInfo2.contentSize)); - } else { - (_f = this.metadataTags).title ?? (_f.title = readMetadataStringShort(slice2)); - } - } - break; - case "©des": - { - if (!this.currentTrack) { - (_g = this.metadataTags).description ?? (_g.description = readMetadataStringShort(slice2)); - } - } - break; - case "©ART": - { - if (!this.currentTrack) { - (_h = this.metadataTags).artist ?? (_h.artist = readMetadataStringShort(slice2)); - } - } - break; - case "©alb": - { - if (!this.currentTrack) { - (_i = this.metadataTags).album ?? (_i.album = readMetadataStringShort(slice2)); - } - } - break; - case "albr": - { - if (!this.currentTrack) { - (_j = this.metadataTags).albumArtist ?? (_j.albumArtist = readMetadataStringShort(slice2)); - } - } - break; - case "©gen": - { - if (!this.currentTrack) { - (_k = this.metadataTags).genre ?? (_k.genre = readMetadataStringShort(slice2)); - } - } - break; - case "©day": - { - if (!this.currentTrack) { - const date = new Date(readMetadataStringShort(slice2)); - if (!Number.isNaN(date.getTime())) { - (_l = this.metadataTags).date ?? (_l.date = date); - } - } - } - break; - case "©cmt": - { - if (!this.currentTrack) { - (_m = this.metadataTags).comment ?? (_m.comment = readMetadataStringShort(slice2)); - } - } - break; - case "©lyr": - { - if (!this.currentTrack) { - (_n = this.metadataTags).lyrics ?? (_n.lyrics = readMetadataStringShort(slice2)); - } - } - break; - } - } - } - break; - case "meta": - { - if (this.currentTrack) { - break; - } - const word = readU32Be(slice); - const isQuickTime = word !== 0; - this.currentMetadataKeys = /* @__PURE__ */ new Map(); - if (isQuickTime) { - this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - } else { - this.readContiguousBoxes(slice.slice(contentStartPos + 4, boxInfo.contentSize - 4)); - } - this.currentMetadataKeys = null; - } - break; - case "keys": - { - if (!this.currentMetadataKeys) { - break; - } - slice.skip(4); - const entryCount = readU32Be(slice); - for (let i = 0; i < entryCount; i++) { - const keySize = readU32Be(slice); - slice.skip(4); - const keyName = textDecoder.decode(readBytes(slice, keySize - 8)); - this.currentMetadataKeys.set(i + 1, keyName); - } - } - break; - case "ilst": - { - if (!this.currentMetadataKeys) { - break; - } - const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize)); - for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) { - let metadataKey = boxInfo2.name; - const nameAsNumber = (metadataKey.charCodeAt(0) << 24) + (metadataKey.charCodeAt(1) << 16) + (metadataKey.charCodeAt(2) << 8) + metadataKey.charCodeAt(3); - if (this.currentMetadataKeys.has(nameAsNumber)) { - metadataKey = this.currentMetadataKeys.get(nameAsNumber); - } - const data = readDataBox(slice2); - (_o = this.metadataTags).raw ?? (_o.raw = {}); - (_p = this.metadataTags.raw)[metadataKey] ?? (_p[metadataKey] = data); - switch (metadataKey) { - case "©nam": - case "titl": - case "com.apple.quicktime.title": - case "title": - { - if (typeof data === "string") { - (_q = this.metadataTags).title ?? (_q.title = data); - } - } - break; - case "©des": - case "desc": - case "dscp": - case "com.apple.quicktime.description": - case "description": - { - if (typeof data === "string") { - (_r = this.metadataTags).description ?? (_r.description = data); - } - } - break; - case "©ART": - case "com.apple.quicktime.artist": - case "artist": - { - if (typeof data === "string") { - (_s = this.metadataTags).artist ?? (_s.artist = data); - } - } - break; - case "©alb": - case "albm": - case "com.apple.quicktime.album": - case "album": - { - if (typeof data === "string") { - (_t = this.metadataTags).album ?? (_t.album = data); - } - } - break; - case "aART": - case "album_artist": - { - if (typeof data === "string") { - (_u = this.metadataTags).albumArtist ?? (_u.albumArtist = data); - } - } - break; - case "©cmt": - case "com.apple.quicktime.comment": - case "comment": - { - if (typeof data === "string") { - (_v = this.metadataTags).comment ?? (_v.comment = data); - } - } - break; - case "©gen": - case "gnre": - case "com.apple.quicktime.genre": - case "genre": - { - if (typeof data === "string") { - (_w = this.metadataTags).genre ?? (_w.genre = data); - } - } - break; - case "©lyr": - case "lyrics": - { - if (typeof data === "string") { - (_x = this.metadataTags).lyrics ?? (_x.lyrics = data); - } - } - break; - case "©day": - case "rldt": - case "com.apple.quicktime.creationdate": - case "date": - { - if (typeof data === "string") { - const date = new Date(data); - if (!Number.isNaN(date.getTime())) { - (_y = this.metadataTags).date ?? (_y.date = date); - } - } - } - break; - case "covr": - case "com.apple.quicktime.artwork": - { - if (data instanceof RichImageData) { - (_z = this.metadataTags).images ?? (_z.images = []); - this.metadataTags.images.push({ - data: data.data, - kind: "coverFront", - mimeType: data.mimeType - }); - } else if (data instanceof Uint8Array) { - (_A = this.metadataTags).images ?? (_A.images = []); - this.metadataTags.images.push({ - data, - kind: "coverFront", - mimeType: "image/*" - }); - } - } - break; - case "track": - { - if (typeof data === "string") { - const parts = data.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - (_B = this.metadataTags).trackNumber ?? (_B.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - (_C = this.metadataTags).tracksTotal ?? (_C.tracksTotal = tracksTotal); - } - } - } - break; - case "trkn": - { - if (data instanceof Uint8Array && data.length >= 6) { - const view = toDataView(data); - const trackNumber = view.getUint16(2, false); - const tracksTotal = view.getUint16(4, false); - if (trackNumber > 0) { - (_D = this.metadataTags).trackNumber ?? (_D.trackNumber = trackNumber); - } - if (tracksTotal > 0) { - (_E = this.metadataTags).tracksTotal ?? (_E.tracksTotal = tracksTotal); - } - } - } - break; - case "disc": - case "disk": - { - if (data instanceof Uint8Array && data.length >= 6) { - const view = toDataView(data); - const discNumber = view.getUint16(2, false); - const discNumberMax = view.getUint16(4, false); - if (discNumber > 0) { - (_F = this.metadataTags).discNumber ?? (_F.discNumber = discNumber); - } - if (discNumberMax > 0) { - (_G = this.metadataTags).discsTotal ?? (_G.discsTotal = discNumberMax); - } - } - } - break; - } - } - } - break; - } - slice.filePos = boxEndPos; - return true; - } -} -class IsobmffTrackBacking { - constructor(internalTrack) { - this.internalTrack = internalTrack; - this.packetToSampleIndex = /* @__PURE__ */ new WeakMap(); - this.packetToFragmentLocation = /* @__PURE__ */ new WeakMap(); - } - getId() { - return this.internalTrack.id; - } - getCodec() { - throw new Error("Not implemented on base class."); - } - getInternalCodecId() { - return this.internalTrack.internalCodecId; - } - getName() { - return this.internalTrack.name; - } - getLanguageCode() { - return this.internalTrack.languageCode; - } - getTimeResolution() { - return this.internalTrack.timescale; - } - getDisposition() { - return this.internalTrack.disposition; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - async getFirstTimestamp() { - const firstPacket = await this.getFirstPacket({ metadataOnly: true }); - return firstPacket?.timestamp ?? 0; - } - async getFirstPacket(options) { - const regularPacket = await this.fetchPacketForSampleIndex(0, options); - if (regularPacket || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup( - null, - (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData) { - return { - sampleIndex: 0, - correctSampleFound: true - }; - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - mapTimestampIntoTimescale(timestamp) { - return roundIfAlmostInteger(timestamp * this.internalTrack.timescale) + this.internalTrack.editListOffset; - } - async getPacket(timestamp, options) { - const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleIndex = getSampleIndexForTimestamp(sampleTable, timestampInTimescale); - const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); - if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup(null, (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (!trackData) { - return { sampleIndex: -1, correctSampleFound: false }; - } - const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.presentationTimestamp); - const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; - const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { sampleIndex: sampleIndex2, correctSampleFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextPacket(packet, options) { - const regularSampleIndex = this.packetToSampleIndex.get(packet); - if (regularSampleIndex !== void 0) { - return this.fetchPacketForSampleIndex(regularSampleIndex + 1, options); - } - const locationInFragment = this.packetToFragmentLocation.get(packet); - if (locationInFragment === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performFragmentedLookup( - locationInFragment.fragment, - (fragment) => { - if (fragment === locationInFragment.fragment) { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (locationInFragment.sampleIndex + 1 < trackData.samples.length) { - return { - sampleIndex: locationInFragment.sampleIndex + 1, - correctSampleFound: true - }; - } - } else { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData) { - return { - sampleIndex: 0, - correctSampleFound: true - }; - } - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - async getKeyPacket(timestamp, options) { - const timestampInTimescale = this.mapTimestampIntoTimescale(timestamp); - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleIndex = getKeyframeSampleIndexForTimestamp(sampleTable, timestampInTimescale); - const regularPacket = await this.fetchPacketForSampleIndex(sampleIndex, options); - if (!sampleTableIsEmpty(sampleTable) || !this.internalTrack.demuxer.isFragmented) { - return regularPacket; - } - return this.performFragmentedLookup(null, (fragment) => { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (!trackData) { - return { sampleIndex: -1, correctSampleFound: false }; - } - const index = findLastIndex(trackData.presentationTimestamps, (x) => { - const sample = trackData.samples[x.sampleIndex]; - return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale; - }); - const sampleIndex2 = index !== -1 ? trackData.presentationTimestamps[index].sampleIndex : -1; - const correctSampleFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { sampleIndex: sampleIndex2, correctSampleFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextKeyPacket(packet, options) { - const regularSampleIndex = this.packetToSampleIndex.get(packet); - if (regularSampleIndex !== void 0) { - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const nextKeyFrameSampleIndex = getNextKeyframeIndexForSample(sampleTable, regularSampleIndex); - return this.fetchPacketForSampleIndex(nextKeyFrameSampleIndex, options); - } - const locationInFragment = this.packetToFragmentLocation.get(packet); - if (locationInFragment === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performFragmentedLookup( - locationInFragment.fragment, - (fragment) => { - if (fragment === locationInFragment.fragment) { - const trackData = fragment.trackData.get(this.internalTrack.id); - const nextKeyFrameIndex = trackData.samples.findIndex((x, i) => x.isKeyFrame && i > locationInFragment.sampleIndex); - if (nextKeyFrameIndex !== -1) { - return { - sampleIndex: nextKeyFrameIndex, - correctSampleFound: true - }; - } - } else { - const trackData = fragment.trackData.get(this.internalTrack.id); - if (trackData && trackData.firstKeyFrameTimestamp !== null) { - const keyFrameIndex = trackData.samples.findIndex((x) => x.isKeyFrame); - assert(keyFrameIndex !== -1); - return { - sampleIndex: keyFrameIndex, - correctSampleFound: true - }; - } - } - return { - sampleIndex: -1, - correctSampleFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the lookup entries - Infinity, - options - ); - } - async fetchPacketForSampleIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const sampleTable = this.internalTrack.demuxer.getSampleTableForTrack(this.internalTrack); - const sampleInfo = getSampleInfo(sampleTable, sampleIndex); - if (!sampleInfo) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.internalTrack.demuxer.reader.requestSlice(sampleInfo.sampleOffset, sampleInfo.sampleSize); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, sampleInfo.sampleSize); - } - const timestamp = (sampleInfo.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; - const duration = sampleInfo.duration / this.internalTrack.timescale; - const packet = new EncodedPacket(data, sampleInfo.isKeyFrame ? "key" : "delta", timestamp, duration, sampleIndex, sampleInfo.sampleSize); - this.packetToSampleIndex.set(packet, sampleIndex); - return packet; - } - async fetchPacketInFragment(fragment, sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const trackData = fragment.trackData.get(this.internalTrack.id); - const fragmentSample = trackData.samples[sampleIndex]; - assert(fragmentSample); - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.internalTrack.demuxer.reader.requestSlice(fragmentSample.byteOffset, fragmentSample.byteSize); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, fragmentSample.byteSize); - } - const timestamp = (fragmentSample.presentationTimestamp - this.internalTrack.editListOffset) / this.internalTrack.timescale; - const duration = fragmentSample.duration / this.internalTrack.timescale; - const packet = new EncodedPacket(data, fragmentSample.isKeyFrame ? "key" : "delta", timestamp, duration, fragment.moofOffset + sampleIndex, fragmentSample.byteSize); - this.packetToFragmentLocation.set(packet, { fragment, sampleIndex }); - return packet; - } - /** Looks for a packet in the fragments while trying to load as few fragments as possible to retrieve it. */ - async performFragmentedLookup(startFragment, getMatchInFragment, searchTimestamp, latestTimestamp, options) { - const demuxer = this.internalTrack.demuxer; - let currentFragment = null; - let bestFragment = null; - let bestSampleIndex = -1; - if (startFragment) { - const { sampleIndex, correctSampleFound } = getMatchInFragment(startFragment); - if (correctSampleFound) { - return this.fetchPacketInFragment(startFragment, sampleIndex, options); - } - if (sampleIndex !== -1) { - bestFragment = startFragment; - bestSampleIndex = sampleIndex; - } - } - const lookupEntryIndex = binarySearchLessOrEqual(this.internalTrack.fragmentLookupTable, searchTimestamp, (x) => x.timestamp); - const lookupEntry = lookupEntryIndex !== -1 ? this.internalTrack.fragmentLookupTable[lookupEntryIndex] : null; - const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.fragmentPositionCache, searchTimestamp, (x) => x.startTimestamp); - const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.fragmentPositionCache[positionCacheIndex] : null; - const lookupEntryPosition = Math.max(lookupEntry?.moofOffset ?? 0, positionCacheEntry?.moofOffset ?? 0) || null; - let currentPos; - if (!startFragment) { - currentPos = lookupEntryPosition ?? 0; - } else { - if (lookupEntryPosition === null || startFragment.moofOffset >= lookupEntryPosition) { - currentPos = startFragment.moofOffset + startFragment.moofSize; - currentFragment = startFragment; - } else { - currentPos = lookupEntryPosition; - } - } - while (true) { - if (currentFragment) { - const trackData = currentFragment.trackData.get(this.internalTrack.id); - if (trackData && trackData.startTimestamp > latestTimestamp) { - break; - } - } - let slice = demuxer.reader.requestSliceRange(currentPos, MIN_BOX_HEADER_SIZE, MAX_BOX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const boxStartPos = currentPos; - const boxInfo = readBoxHeader(slice); - if (!boxInfo) { - break; - } - if (boxInfo.name === "moof") { - currentFragment = await demuxer.readFragment(boxStartPos); - const { sampleIndex, correctSampleFound } = getMatchInFragment(currentFragment); - if (correctSampleFound) { - return this.fetchPacketInFragment(currentFragment, sampleIndex, options); - } - if (sampleIndex !== -1) { - bestFragment = currentFragment; - bestSampleIndex = sampleIndex; - } - } - currentPos = boxStartPos + boxInfo.totalSize; - } - if (lookupEntry && (!bestFragment || bestFragment.moofOffset < lookupEntry.moofOffset)) { - const previousLookupEntry = this.internalTrack.fragmentLookupTable[lookupEntryIndex - 1]; - assert(!previousLookupEntry || previousLookupEntry.timestamp < lookupEntry.timestamp); - const newSearchTimestamp = previousLookupEntry?.timestamp ?? -Infinity; - return this.performFragmentedLookup(null, getMatchInFragment, newSearchTimestamp, latestTimestamp, options); - } - if (bestFragment) { - return this.fetchPacketInFragment(bestFragment, bestSampleIndex, options); - } - return null; - } -} -class IsobmffVideoTrackBacking extends IsobmffTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfigPromise = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getCodedWidth() { - return this.internalTrack.info.width; - } - getCodedHeight() { - return this.internalTrack.info.height; - } - getRotation() { - return this.internalTrack.rotation; - } - async getColorSpace() { - return { - primaries: this.internalTrack.info.colorSpace?.primaries, - transfer: this.internalTrack.info.colorSpace?.transfer, - matrix: this.internalTrack.info.colorSpace?.matrix, - fullRange: this.internalTrack.info.colorSpace?.fullRange - }; - } - async canBeTransparent() { - return false; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { - if (this.internalTrack.info.codec === "vp9" && !this.internalTrack.info.vp9CodecInfo) { - const firstPacket = await this.getFirstPacket({}); - this.internalTrack.info.vp9CodecInfo = firstPacket && extractVp9CodecInfoFromPacket(firstPacket.data); - } else if (this.internalTrack.info.codec === "av1" && !this.internalTrack.info.av1CodecInfo) { - const firstPacket = await this.getFirstPacket({}); - this.internalTrack.info.av1CodecInfo = firstPacket && extractAv1CodecInfoFromPacket(firstPacket.data); - } - return { - codec: extractVideoCodecString(this.internalTrack.info), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? void 0, - colorSpace: this.internalTrack.info.colorSpace ?? void 0 - }; - })()); - } -} -class IsobmffAudioTrackBacking extends IsobmffTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfig = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getNumberOfChannels() { - return this.internalTrack.info.numberOfChannels; - } - getSampleRate() { - return this.internalTrack.info.sampleRate; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfig ?? (this.decoderConfig = { - codec: extractAudioCodecString(this.internalTrack.info), - numberOfChannels: this.internalTrack.info.numberOfChannels, - sampleRate: this.internalTrack.info.sampleRate, - description: this.internalTrack.info.codecDescription ?? void 0 - }); - } -} -const getSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { - if (sampleTable.presentationTimestamps) { - const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); - if (index === -1) { - return -1; - } - return sampleTable.presentationTimestamps[index].sampleIndex; - } else { - const index = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, timescaleUnits, (x) => x.startDecodeTimestamp); - if (index === -1) { - return -1; - } - const entry = sampleTable.sampleTimingEntries[index]; - return entry.startIndex + Math.min(Math.floor((timescaleUnits - entry.startDecodeTimestamp) / entry.delta), entry.count - 1); - } -}; -const getKeyframeSampleIndexForTimestamp = (sampleTable, timescaleUnits) => { - if (!sampleTable.keySampleIndices) { - return getSampleIndexForTimestamp(sampleTable, timescaleUnits); - } - if (sampleTable.presentationTimestamps) { - const index = binarySearchLessOrEqual(sampleTable.presentationTimestamps, timescaleUnits, (x) => x.presentationTimestamp); - if (index === -1) { - return -1; - } - for (let i = index; i >= 0; i--) { - const sampleIndex = sampleTable.presentationTimestamps[i].sampleIndex; - const isKeyFrame = binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1; - if (isKeyFrame) { - return sampleIndex; - } - } - return -1; - } else { - const sampleIndex = getSampleIndexForTimestamp(sampleTable, timescaleUnits); - const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); - return sampleTable.keySampleIndices[index] ?? -1; - } -}; -const getSampleInfo = (sampleTable, sampleIndex) => { - const timingEntryIndex = binarySearchLessOrEqual(sampleTable.sampleTimingEntries, sampleIndex, (x) => x.startIndex); - const timingEntry = sampleTable.sampleTimingEntries[timingEntryIndex]; - if (!timingEntry || timingEntry.startIndex + timingEntry.count <= sampleIndex) { - return null; - } - const decodeTimestamp = timingEntry.startDecodeTimestamp + (sampleIndex - timingEntry.startIndex) * timingEntry.delta; - let presentationTimestamp = decodeTimestamp; - const offsetEntryIndex = binarySearchLessOrEqual(sampleTable.sampleCompositionTimeOffsets, sampleIndex, (x) => x.startIndex); - const offsetEntry = sampleTable.sampleCompositionTimeOffsets[offsetEntryIndex]; - if (offsetEntry && sampleIndex - offsetEntry.startIndex < offsetEntry.count) { - presentationTimestamp += offsetEntry.offset; - } - const sampleSize = sampleTable.sampleSizes[Math.min(sampleIndex, sampleTable.sampleSizes.length - 1)]; - const chunkEntryIndex = binarySearchLessOrEqual(sampleTable.sampleToChunk, sampleIndex, (x) => x.startSampleIndex); - const chunkEntry = sampleTable.sampleToChunk[chunkEntryIndex]; - assert(chunkEntry); - const chunkIndex = chunkEntry.startChunkIndex + Math.floor((sampleIndex - chunkEntry.startSampleIndex) / chunkEntry.samplesPerChunk); - const chunkOffset = sampleTable.chunkOffsets[chunkIndex]; - const startSampleIndexOfChunk = chunkEntry.startSampleIndex + (chunkIndex - chunkEntry.startChunkIndex) * chunkEntry.samplesPerChunk; - let chunkSize = 0; - let sampleOffset = chunkOffset; - if (sampleTable.sampleSizes.length === 1) { - sampleOffset += sampleSize * (sampleIndex - startSampleIndexOfChunk); - chunkSize += sampleSize * chunkEntry.samplesPerChunk; - } else { - for (let i = startSampleIndexOfChunk; i < startSampleIndexOfChunk + chunkEntry.samplesPerChunk; i++) { - const sampleSize2 = sampleTable.sampleSizes[i]; - if (i < sampleIndex) { - sampleOffset += sampleSize2; - } - chunkSize += sampleSize2; - } - } - let duration = timingEntry.delta; - if (sampleTable.presentationTimestamps) { - const presentationIndex = sampleTable.presentationTimestampIndexMap[sampleIndex]; - assert(presentationIndex !== void 0); - if (presentationIndex < sampleTable.presentationTimestamps.length - 1) { - const nextEntry = sampleTable.presentationTimestamps[presentationIndex + 1]; - const nextPresentationTimestamp = nextEntry.presentationTimestamp; - duration = nextPresentationTimestamp - presentationTimestamp; - } + if (query.sortBy !== void 0 && typeof query.sortBy !== "function") { + throw new TypeError("query.sortBy, when provided, must be a function."); } return { - presentationTimestamp, - duration, - sampleOffset, - sampleSize, - chunkOffset, - chunkSize, - isKeyFrame: sampleTable.keySampleIndices ? binarySearchExact(sampleTable.keySampleIndices, sampleIndex, (x) => x) !== -1 : true + filter: query.filter ? (track) => { + const handle = (bool) => { + if (typeof bool !== "boolean") { + throw new TypeError("query.filter must return or resolve to a boolean."); + } + return bool; + }; + const result = query.filter(track); + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } : void 0, + sortBy: query.sortBy ? (track) => { + const handle = (value) => { + if (typeof value !== "number" && (!Array.isArray(value) || !value.every((x) => typeof x === "number"))) { + throw new TypeError("query.sortBy must return or resolve to a number or an array of numbers."); + } + return value; + }; + const result = query.sortBy(track); + if (result instanceof Promise) { + return result.then(handle); + } else { + return handle(result); + } + } : void 0 }; }; -const getNextKeyframeIndexForSample = (sampleTable, sampleIndex) => { - if (!sampleTable.keySampleIndices) { - return sampleIndex + 1; - } - const index = binarySearchLessOrEqual(sampleTable.keySampleIndices, sampleIndex, (x) => x); - return sampleTable.keySampleIndices[index + 1] ?? -1; -}; -const offsetFragmentTrackDataByTimestamp = (trackData, timestamp) => { - trackData.startTimestamp += timestamp; - trackData.endTimestamp += timestamp; - for (const sample of trackData.samples) { - sample.presentationTimestamp += timestamp; - } - for (const entry of trackData.presentationTimestamps) { - entry.presentationTimestamp += timestamp; - } -}; -const extractRotationFromMatrix = (matrix) => { - const [m11, , , m21] = matrix; - const scaleX = Math.hypot(m11, m21); - const cosTheta = m11 / scaleX; - const sinTheta = m21 / scaleX; - const result = -Math.atan2(sinTheta, cosTheta) * (180 / Math.PI); - if (!Number.isFinite(result)) { - return 0; - } - return result; -}; -const sampleTableIsEmpty = (sampleTable) => { - return sampleTable.sampleSizes.length === 0; -}; -var EBMLId; -(function(EBMLId2) { - EBMLId2[EBMLId2["EBML"] = 440786851] = "EBML"; - EBMLId2[EBMLId2["EBMLVersion"] = 17030] = "EBMLVersion"; - EBMLId2[EBMLId2["EBMLReadVersion"] = 17143] = "EBMLReadVersion"; - EBMLId2[EBMLId2["EBMLMaxIDLength"] = 17138] = "EBMLMaxIDLength"; - EBMLId2[EBMLId2["EBMLMaxSizeLength"] = 17139] = "EBMLMaxSizeLength"; - EBMLId2[EBMLId2["DocType"] = 17026] = "DocType"; - EBMLId2[EBMLId2["DocTypeVersion"] = 17031] = "DocTypeVersion"; - EBMLId2[EBMLId2["DocTypeReadVersion"] = 17029] = "DocTypeReadVersion"; - EBMLId2[EBMLId2["Void"] = 236] = "Void"; - EBMLId2[EBMLId2["Segment"] = 408125543] = "Segment"; - EBMLId2[EBMLId2["SeekHead"] = 290298740] = "SeekHead"; - EBMLId2[EBMLId2["Seek"] = 19899] = "Seek"; - EBMLId2[EBMLId2["SeekID"] = 21419] = "SeekID"; - EBMLId2[EBMLId2["SeekPosition"] = 21420] = "SeekPosition"; - EBMLId2[EBMLId2["Duration"] = 17545] = "Duration"; - EBMLId2[EBMLId2["Info"] = 357149030] = "Info"; - EBMLId2[EBMLId2["TimestampScale"] = 2807729] = "TimestampScale"; - EBMLId2[EBMLId2["MuxingApp"] = 19840] = "MuxingApp"; - EBMLId2[EBMLId2["WritingApp"] = 22337] = "WritingApp"; - EBMLId2[EBMLId2["Tracks"] = 374648427] = "Tracks"; - EBMLId2[EBMLId2["TrackEntry"] = 174] = "TrackEntry"; - EBMLId2[EBMLId2["TrackNumber"] = 215] = "TrackNumber"; - EBMLId2[EBMLId2["TrackUID"] = 29637] = "TrackUID"; - EBMLId2[EBMLId2["TrackType"] = 131] = "TrackType"; - EBMLId2[EBMLId2["FlagEnabled"] = 185] = "FlagEnabled"; - EBMLId2[EBMLId2["FlagDefault"] = 136] = "FlagDefault"; - EBMLId2[EBMLId2["FlagForced"] = 21930] = "FlagForced"; - EBMLId2[EBMLId2["FlagOriginal"] = 21934] = "FlagOriginal"; - EBMLId2[EBMLId2["FlagHearingImpaired"] = 21931] = "FlagHearingImpaired"; - EBMLId2[EBMLId2["FlagVisualImpaired"] = 21932] = "FlagVisualImpaired"; - EBMLId2[EBMLId2["FlagCommentary"] = 21935] = "FlagCommentary"; - EBMLId2[EBMLId2["FlagLacing"] = 156] = "FlagLacing"; - EBMLId2[EBMLId2["Name"] = 21358] = "Name"; - EBMLId2[EBMLId2["Language"] = 2274716] = "Language"; - EBMLId2[EBMLId2["LanguageBCP47"] = 2274717] = "LanguageBCP47"; - EBMLId2[EBMLId2["CodecID"] = 134] = "CodecID"; - EBMLId2[EBMLId2["CodecPrivate"] = 25506] = "CodecPrivate"; - EBMLId2[EBMLId2["CodecDelay"] = 22186] = "CodecDelay"; - EBMLId2[EBMLId2["SeekPreRoll"] = 22203] = "SeekPreRoll"; - EBMLId2[EBMLId2["DefaultDuration"] = 2352003] = "DefaultDuration"; - EBMLId2[EBMLId2["Video"] = 224] = "Video"; - EBMLId2[EBMLId2["PixelWidth"] = 176] = "PixelWidth"; - EBMLId2[EBMLId2["PixelHeight"] = 186] = "PixelHeight"; - EBMLId2[EBMLId2["AlphaMode"] = 21440] = "AlphaMode"; - EBMLId2[EBMLId2["Audio"] = 225] = "Audio"; - EBMLId2[EBMLId2["SamplingFrequency"] = 181] = "SamplingFrequency"; - EBMLId2[EBMLId2["Channels"] = 159] = "Channels"; - EBMLId2[EBMLId2["BitDepth"] = 25188] = "BitDepth"; - EBMLId2[EBMLId2["SimpleBlock"] = 163] = "SimpleBlock"; - EBMLId2[EBMLId2["BlockGroup"] = 160] = "BlockGroup"; - EBMLId2[EBMLId2["Block"] = 161] = "Block"; - EBMLId2[EBMLId2["BlockAdditions"] = 30113] = "BlockAdditions"; - EBMLId2[EBMLId2["BlockMore"] = 166] = "BlockMore"; - EBMLId2[EBMLId2["BlockAdditional"] = 165] = "BlockAdditional"; - EBMLId2[EBMLId2["BlockAddID"] = 238] = "BlockAddID"; - EBMLId2[EBMLId2["BlockDuration"] = 155] = "BlockDuration"; - EBMLId2[EBMLId2["ReferenceBlock"] = 251] = "ReferenceBlock"; - EBMLId2[EBMLId2["Cluster"] = 524531317] = "Cluster"; - EBMLId2[EBMLId2["Timestamp"] = 231] = "Timestamp"; - EBMLId2[EBMLId2["Cues"] = 475249515] = "Cues"; - EBMLId2[EBMLId2["CuePoint"] = 187] = "CuePoint"; - EBMLId2[EBMLId2["CueTime"] = 179] = "CueTime"; - EBMLId2[EBMLId2["CueTrackPositions"] = 183] = "CueTrackPositions"; - EBMLId2[EBMLId2["CueTrack"] = 247] = "CueTrack"; - EBMLId2[EBMLId2["CueClusterPosition"] = 241] = "CueClusterPosition"; - EBMLId2[EBMLId2["Colour"] = 21936] = "Colour"; - EBMLId2[EBMLId2["MatrixCoefficients"] = 21937] = "MatrixCoefficients"; - EBMLId2[EBMLId2["TransferCharacteristics"] = 21946] = "TransferCharacteristics"; - EBMLId2[EBMLId2["Primaries"] = 21947] = "Primaries"; - EBMLId2[EBMLId2["Range"] = 21945] = "Range"; - EBMLId2[EBMLId2["Projection"] = 30320] = "Projection"; - EBMLId2[EBMLId2["ProjectionType"] = 30321] = "ProjectionType"; - EBMLId2[EBMLId2["ProjectionPoseRoll"] = 30325] = "ProjectionPoseRoll"; - EBMLId2[EBMLId2["Attachments"] = 423732329] = "Attachments"; - EBMLId2[EBMLId2["AttachedFile"] = 24999] = "AttachedFile"; - EBMLId2[EBMLId2["FileDescription"] = 18046] = "FileDescription"; - EBMLId2[EBMLId2["FileName"] = 18030] = "FileName"; - EBMLId2[EBMLId2["FileMediaType"] = 18016] = "FileMediaType"; - EBMLId2[EBMLId2["FileData"] = 18012] = "FileData"; - EBMLId2[EBMLId2["FileUID"] = 18094] = "FileUID"; - EBMLId2[EBMLId2["Chapters"] = 272869232] = "Chapters"; - EBMLId2[EBMLId2["Tags"] = 307544935] = "Tags"; - EBMLId2[EBMLId2["Tag"] = 29555] = "Tag"; - EBMLId2[EBMLId2["Targets"] = 25536] = "Targets"; - EBMLId2[EBMLId2["TargetTypeValue"] = 26826] = "TargetTypeValue"; - EBMLId2[EBMLId2["TargetType"] = 25546] = "TargetType"; - EBMLId2[EBMLId2["TagTrackUID"] = 25541] = "TagTrackUID"; - EBMLId2[EBMLId2["TagEditionUID"] = 25545] = "TagEditionUID"; - EBMLId2[EBMLId2["TagChapterUID"] = 25540] = "TagChapterUID"; - EBMLId2[EBMLId2["TagAttachmentUID"] = 25542] = "TagAttachmentUID"; - EBMLId2[EBMLId2["SimpleTag"] = 26568] = "SimpleTag"; - EBMLId2[EBMLId2["TagName"] = 17827] = "TagName"; - EBMLId2[EBMLId2["TagLanguage"] = 17530] = "TagLanguage"; - EBMLId2[EBMLId2["TagString"] = 17543] = "TagString"; - EBMLId2[EBMLId2["TagBinary"] = 17541] = "TagBinary"; - EBMLId2[EBMLId2["ContentEncodings"] = 28032] = "ContentEncodings"; - EBMLId2[EBMLId2["ContentEncoding"] = 25152] = "ContentEncoding"; - EBMLId2[EBMLId2["ContentEncodingOrder"] = 20529] = "ContentEncodingOrder"; - EBMLId2[EBMLId2["ContentEncodingScope"] = 20530] = "ContentEncodingScope"; - EBMLId2[EBMLId2["ContentCompression"] = 20532] = "ContentCompression"; - EBMLId2[EBMLId2["ContentCompAlgo"] = 16980] = "ContentCompAlgo"; - EBMLId2[EBMLId2["ContentCompSettings"] = 16981] = "ContentCompSettings"; - EBMLId2[EBMLId2["ContentEncryption"] = 20533] = "ContentEncryption"; -})(EBMLId || (EBMLId = {})); -const LEVEL_0_EBML_IDS = [ - EBMLId.EBML, - EBMLId.Segment -]; -const LEVEL_1_EBML_IDS = [ - EBMLId.SeekHead, - EBMLId.Info, - EBMLId.Cluster, - EBMLId.Tracks, - EBMLId.Cues, - EBMLId.Attachments, - EBMLId.Chapters, - EBMLId.Tags -]; -const LEVEL_0_AND_1_EBML_IDS = [ - ...LEVEL_0_EBML_IDS, - ...LEVEL_1_EBML_IDS -]; -const MAX_VAR_INT_SIZE = 8; -const MIN_HEADER_SIZE = 2; -const MAX_HEADER_SIZE = 2 * MAX_VAR_INT_SIZE; -const readVarIntSize = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - slice.skip(-1); - if (firstByte === 0) { - return null; - } - let width = 1; - let mask = 128; - while ((firstByte & mask) === 0) { - width++; - mask >>= 1; - } - if (slice.remainingLength < width) { - return null; - } - return width; -}; -const readVarInt = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - if (firstByte === 0) { - return null; - } - let width = 1; - let mask = 1 << 7; - while ((firstByte & mask) === 0) { - width++; - mask >>= 1; - } - if (slice.remainingLength < width - 1) { - return null; - } - let value = firstByte & mask - 1; - for (let i = 1; i < width; i++) { - value *= 1 << 8; - value += readU8(slice); - } - return value; -}; -const readUnsignedInt = (slice, width) => { - if (width < 1 || width > 8) { - throw new Error("Bad unsigned int size " + width); - } - let value = 0; - for (let i = 0; i < width; i++) { - value *= 1 << 8; - value += readU8(slice); - } - return value; -}; -const readUnsignedBigInt = (slice, width) => { - if (width < 1) { - throw new Error("Bad unsigned int size " + width); - } - let value = 0n; - for (let i = 0; i < width; i++) { - value <<= 8n; - value += BigInt(readU8(slice)); - } - return value; -}; -const readElementId = (slice) => { - const size = readVarIntSize(slice); - if (size === null) { - return null; - } - if (slice.remainingLength < size) { - return null; - } - const id = readUnsignedInt(slice, size); - return id; -}; -const readElementSize = (slice) => { - if (slice.remainingLength < 1) { - return null; - } - const firstByte = readU8(slice); - if (firstByte === 255) { - return void 0; - } - slice.skip(-1); - const size = readVarInt(slice); - if (size === null) { - return null; - } - if (size === 72057594037927940) { - return void 0; - } - return size; -}; -const readElementHeader = (slice) => { - assert(slice.remainingLength >= MIN_HEADER_SIZE); - const id = readElementId(slice); - if (id === null) { - return null; - } - const size = readElementSize(slice); - if (size === null) { - return null; - } - return { id, size }; -}; -const readAsciiString = (slice, length) => { - const bytes = readBytes(slice, length); - let strLength = 0; - while (strLength < length && bytes[strLength] !== 0) { - strLength += 1; - } - return String.fromCharCode(...bytes.subarray(0, strLength)); -}; -const readUnicodeString = (slice, length) => { - const bytes = readBytes(slice, length); - let strLength = 0; - while (strLength < length && bytes[strLength] !== 0) { - strLength += 1; - } - return textDecoder.decode(bytes.subarray(0, strLength)); -}; -const readFloat = (slice, width) => { - if (width === 0) { - return 0; - } - if (width !== 4 && width !== 8) { - throw new Error("Bad float size " + width); - } - return width === 4 ? readF32Be(slice) : readF64Be(slice); -}; -const searchForNextElementId = async (reader, startPos, ids, until) => { - const idsSet = new Set(ids); - let currentPos = startPos; - while (until === null || currentPos < until) { - let slice = reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementHeader = readElementHeader(slice); - if (!elementHeader) { - break; - } - if (idsSet.has(elementHeader.id)) { - return { pos: currentPos, found: true }; - } - assertDefinedSize(elementHeader.size); - currentPos = slice.filePos + elementHeader.size; - } - return { pos: until !== null && until > currentPos ? until : currentPos, found: false }; -}; -const resync = async (reader, startPos, ids, until) => { - const CHUNK_SIZE = 2 ** 16; - const idsSet = new Set(ids); - let currentPos = startPos; - while (currentPos < until) { - let slice = reader.requestSliceRange(currentPos, 0, Math.min(CHUNK_SIZE, until - currentPos)); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - if (slice.length < MAX_VAR_INT_SIZE) - break; - for (let i = 0; i < slice.length - MAX_VAR_INT_SIZE; i++) { - slice.filePos = currentPos; - const elementId = readElementId(slice); - if (elementId !== null && idsSet.has(elementId)) { - return currentPos; +const mergeInputTrackQueries = (queryA, queryB) => { + return { + filter: queryA?.filter || queryB?.filter ? (track) => { + const resultA = queryA?.filter?.(track) ?? true; + const handleResultA = (resultA2) => { + if (resultA2 === false) { + return false; + } + return queryB?.filter?.(track) ?? true; + }; + if (resultA instanceof Promise) { + return resultA.then(handleResultA); + } else { + return handleResultA(resultA); } - currentPos++; + } : void 0, + sortBy: queryA?.sortBy || queryB?.sortBy ? (track) => { + const resultA = queryA?.sortBy?.(track) ?? []; + const resultB = queryB?.sortBy?.(track) ?? []; + const join = (resultA2, resultB2) => { + return [ + ...Array.isArray(resultA2) ? resultA2 : [resultA2], + ...Array.isArray(resultB2) ? resultB2 : [resultB2] + ]; + }; + if (resultA instanceof Promise || resultB instanceof Promise) { + return Promise.all([resultA, resultB]).then(([resultA2, resultB2]) => { + return join(resultA2, resultB2); + }); + } else { + return join(resultA, resultB); + } + } : void 0 + }; +}; +const queryInputTracks = async (tracks, query) => { + let matched = tracks; + if (query?.filter) { + const filterMatches = tracks.map((t) => query.filter(t)); + const hasAsyncFilter = filterMatches.some((x) => x instanceof Promise); + if (hasAsyncFilter) { + const resolvedFilterMatches = await Promise.all(filterMatches); + matched = tracks.filter((_, i) => resolvedFilterMatches[i]); + } else { + matched = tracks.filter((_, i) => filterMatches[i]); } } - return null; -}; -const CODEC_STRING_MAP = { - "avc": "V_MPEG4/ISO/AVC", - "hevc": "V_MPEGH/ISO/HEVC", - "vp8": "V_VP8", - "vp9": "V_VP9", - "av1": "V_AV1", - "aac": "A_AAC", - "mp3": "A_MPEG/L3", - "opus": "A_OPUS", - "vorbis": "A_VORBIS", - "flac": "A_FLAC" -}; -function assertDefinedSize(size) { - if (size === void 0) { - throw new Error("Undefined element size is used in a place where it is not supported."); + if (!query?.sortBy) { + return matched; } + const sortValues = matched.map((t) => query.sortBy(t)); + const hasAsyncSort = sortValues.some((x) => x instanceof Promise); + const resolvedSortValues = hasAsyncSort ? await Promise.all(sortValues) : sortValues; + return matched.map((track, i) => ({ track, sortValue: resolvedSortValues[i] })).sort((a, b) => { + const aValues = Array.isArray(a.sortValue) ? a.sortValue : [a.sortValue]; + const bValues = Array.isArray(b.sortValue) ? b.sortValue : [b.sortValue]; + const maxLength = Math.max(aValues.length, bValues.length); + for (let i = 0; i < maxLength; i++) { + const aValue = aValues[i] ?? 0; + const bValue = bValues[i] ?? 0; + if (aValue === bValue) { + continue; + } + return aValue - bValue; + } + return 0; + }).map((x) => x.track); +}; +polyfillSymbolDispose(); +const DEFAULT_SOURCE_CACHE_GROUP = 1; +const ENCRYPTION_KEY_CACHE_GROUP = 2; +let inputFinalizationRegistry = null; +if (typeof FinalizationRegistry !== "undefined") { + inputFinalizationRegistry = new FinalizationRegistry((refs) => { + for (const ref of refs) { + if (!ref.freed) { + ref.free(); + } + } + }); } -const buildMatroskaMimeType = (info) => { - const base = info.hasVideo ? "video/" : info.hasAudio ? "audio/" : "application/"; - let string = base + (info.isWebM ? "webm" : "x-matroska"); - if (info.codecStrings.length > 0) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings.filter(Boolean))]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; +class Input extends EventEmitter { + /** True if the input has been disposed. */ + get disposed() { + return this._disposed; } - return string; -}; -var BlockLacing; -(function(BlockLacing2) { - BlockLacing2[BlockLacing2["None"] = 0] = "None"; - BlockLacing2[BlockLacing2["Xiph"] = 1] = "Xiph"; - BlockLacing2[BlockLacing2["FixedSize"] = 2] = "FixedSize"; - BlockLacing2[BlockLacing2["Ebml"] = 3] = "Ebml"; -})(BlockLacing || (BlockLacing = {})); -var ContentEncodingScope; -(function(ContentEncodingScope2) { - ContentEncodingScope2[ContentEncodingScope2["Block"] = 1] = "Block"; - ContentEncodingScope2[ContentEncodingScope2["Private"] = 2] = "Private"; - ContentEncodingScope2[ContentEncodingScope2["Next"] = 4] = "Next"; -})(ContentEncodingScope || (ContentEncodingScope = {})); -var ContentCompAlgo; -(function(ContentCompAlgo2) { - ContentCompAlgo2[ContentCompAlgo2["Zlib"] = 0] = "Zlib"; - ContentCompAlgo2[ContentCompAlgo2["Bzlib"] = 1] = "Bzlib"; - ContentCompAlgo2[ContentCompAlgo2["lzo1x"] = 2] = "lzo1x"; - ContentCompAlgo2[ContentCompAlgo2["HeaderStripping"] = 3] = "HeaderStripping"; -})(ContentCompAlgo || (ContentCompAlgo = {})); -const METADATA_ELEMENTS = [ - { id: EBMLId.SeekHead, flag: "seekHeadSeen" }, - { id: EBMLId.Info, flag: "infoSeen" }, - { id: EBMLId.Tracks, flag: "tracksSeen" }, - { id: EBMLId.Cues, flag: "cuesSeen" } -]; -const MAX_RESYNC_LENGTH = 10 * 2 ** 20; -class MatroskaDemuxer extends Demuxer { - constructor(input) { - super(input); - this.readMetadataPromise = null; - this.segments = []; - this.currentSegment = null; - this.currentTrack = null; - this.currentCluster = null; - this.currentBlock = null; - this.currentBlockAdditional = null; - this.currentCueTime = null; - this.currentDecodingInstruction = null; - this.currentTagTargetIsMovie = true; - this.currentSimpleTagName = null; - this.currentAttachedFile = null; - this.isWebM = false; - this.reader = input._reader; + /** + * Creates a new input file from the specified options. No reading operations will be performed until methods are + * called on this instance. + */ + constructor(options) { + super(); + this._demuxerPromise = null; + this._format = null; + this._trackBackingsCache = null; + this._backingToTrack = /* @__PURE__ */ new Map(); + this._disposed = false; + this._nextSourceCacheAge = 0; + this._sourceRefs = []; + this._sourceCache = []; + this._sourceCachePromises = []; + this._onFormatDetermined = null; + if (!options || typeof options !== "object") { + throw new TypeError("options must be an object."); + } + if (!Array.isArray(options.formats) || options.formats.some((x) => !(x instanceof InputFormat))) { + throw new TypeError("options.formats must be an array of InputFormat."); + } + if (!(options.source instanceof Source || options.source instanceof SourceRef)) { + throw new TypeError("options.source must be a Source or SourceRef."); + } + if (options.source instanceof Source && options.source._disposed) { + throw new TypeError("options.source must not be a disposed Source."); + } + if (options.initInput !== void 0 && !(options.initInput instanceof Input)) { + throw new TypeError("options.initInput, when provided, must be an Input."); + } + if (options.formatOptions !== void 0) { + validateInputFormatOptions(options.formatOptions, "formatOptions"); + } + this._formats = options.formats; + this._initInput = options.initInput ?? null; + this._formatOptions = options.formatOptions ?? {}; + if (options.source instanceof Source) { + this._rootRef = options.source.ref(); + } else { + this._rootRef = options.source; + } + this._sourceRefs.push(this._rootRef); + inputFinalizationRegistry?.register(this, this._sourceRefs, this); } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); + /** @internal */ + get _rootSource() { + return this._rootRef.source; } - async getTracks() { - await this.readMetadata(); - return this.segments.flatMap((segment) => segment.tracks.map((track) => track.inputTrack)); + /** @internal */ + async _getSourceUncached(request) { + assert(this._rootSource instanceof PathedSource); + const ref = await this._rootSource._resolveRequest(request); + this._emit("source", { source: ref.source, request, isRoot: request.isRoot }); + return ref; } - async getMimeType() { - await this.readMetadata(); - const tracks = await this.getTracks(); - const codecStrings = await Promise.all(tracks.map((x) => x.getCodecParameterString())); - return buildMatroskaMimeType({ - isWebM: this.isWebM, - hasVideo: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "video")), - hasAudio: this.segments.some((segment) => segment.tracks.some((x) => x.info?.type === "audio")), - codecStrings: codecStrings.filter(Boolean) + /** @internal */ + _getSourceCached(request, cacheGroup = DEFAULT_SOURCE_CACHE_GROUP) { + const cachedEntry = this._sourceCache.find((x) => x.cacheGroup === cacheGroup && sourceRequestsAreEqual(x.request, request)); + if (cachedEntry) { + cachedEntry.age++; + return Promise.resolve(cachedEntry.sourceRef.source.ref()); + } + const cachedPromiseEntry = this._sourceCachePromises.find((x) => x.cacheGroup === cacheGroup && sourceRequestsAreEqual(x.request, request)); + if (cachedPromiseEntry) { + return cachedPromiseEntry.promise.then((x) => x.sourceRef.source.ref()); + } + const promise = (async () => { + const sourceRef = await this._getSourceUncached(request); + const MAX_SOURCE_CACHE_SIZE = 4; + const count = arrayCount(this._sourceCache, (x) => x.cacheGroup === cacheGroup && x.sourceRef.source._refCount === 1); + if (count >= MAX_SOURCE_CACHE_SIZE) { + const minAgeIndex = arrayArgmin(this._sourceCache, (x) => x.cacheGroup === cacheGroup && x.sourceRef.source._refCount === 1 ? x.age : Infinity); + assert(minAgeIndex !== -1); + const entry = this._sourceCache[minAgeIndex]; + this._sourceCache.splice(minAgeIndex, 1); + entry.sourceRef.free(); + removeItem(this._sourceRefs, entry.sourceRef); + } + this._sourceRefs.push(sourceRef); + const promiseIndex = this._sourceCachePromises.findIndex((x) => x.request === request); + assert(promiseIndex !== -1); + this._sourceCachePromises.splice(promiseIndex, 1); + const cacheEntry = { + request, + sourceRef, + age: this._nextSourceCacheAge++, + cacheGroup + }; + return cacheEntry; + })(); + this._sourceCachePromises.push({ + request, + cacheGroup, + promise + }); + return promise.then((entry) => { + const ref = entry.sourceRef.source.ref(); + this._sourceCache.push(entry); + return ref; }); } - async getMetadataTags() { - await this.readMetadata(); - for (const segment of this.segments) { - if (!segment.metadataTagsCollected) { - if (this.reader.fileSize !== null) { - await this.loadSegmentMetadata(segment); + /** @internal */ + _getDemuxer() { + return this._demuxerPromise ?? (this._demuxerPromise = (async () => { + this._reader = new Reader(this._rootSource); + this._emit("source", { source: this._rootSource, request: null, isRoot: true }); + for (const format of this._formats) { + const canRead = await format._canReadInput(this); + if (canRead) { + this._format = format; + this._onFormatDetermined?.(format); + return format._createDemuxer(this); } - segment.metadataTagsCollected = true; - } - } - let metadataTags = {}; - for (const segment of this.segments) { - metadataTags = { ...metadataTags, ...segment.metadataTags }; - } - return metadataTags; - } - readMetadata() { - return this.readMetadataPromise ?? (this.readMetadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const header = readElementHeader(slice); - if (!header) { - break; - } - const id = header.id; - let size = header.size; - const dataStartPos = slice.filePos; - if (id === EBMLId.EBML) { - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - this.readContiguousElements(slice2); - } else if (id === EBMLId.Segment) { - await this.readSegment(dataStartPos, size); - if (size === void 0) { - break; - } - if (this.reader.fileSize === null) { - break; - } - } else if (id === EBMLId.Cluster) { - if (this.reader.fileSize === null) { - break; - } - if (size === void 0) { - const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, this.reader.fileSize); - size = nextElementPos.pos - dataStartPos; - } - const lastSegment = last(this.segments); - if (lastSegment) { - lastSegment.elementEndPos = dataStartPos + size; - } - } - assertDefinedSize(size); - currentPos = dataStartPos + size; } + throw new UnsupportedInputFormatError(); })()); } - async readSegment(segmentDataStart, dataSize) { - this.currentSegment = { - seekHeadSeen: false, - infoSeen: false, - tracksSeen: false, - cuesSeen: false, - tagsSeen: false, - attachmentsSeen: false, - timestampScale: -1, - timestampFactor: -1, - duration: -1, - seekEntries: [], - tracks: [], - cuePoints: [], - dataStartPos: segmentDataStart, - elementEndPos: dataSize === void 0 ? null : segmentDataStart + dataSize, - clusterSeekStartPos: segmentDataStart, - lastReadCluster: null, - metadataTags: {}, - metadataTagsCollected: false - }; - this.segments.push(this.currentSegment); - let currentPos = segmentDataStart; - while (this.currentSegment.elementEndPos === null || currentPos < this.currentSegment.elementEndPos) { - let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementStartPos = currentPos; - const header = readElementHeader(slice); - if (!header || !LEVEL_1_EBML_IDS.includes(header.id) && header.id !== EBMLId.Void) { - const nextPos = await resync(this.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(this.currentSegment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); - if (nextPos) { - currentPos = nextPos; - continue; - } else { - break; - } - } - const { id, size } = header; - const dataStartPos = slice.filePos; - const metadataElementIndex = METADATA_ELEMENTS.findIndex((x) => x.id === id); - if (metadataElementIndex !== -1) { - const field = METADATA_ELEMENTS[metadataElementIndex].flag; - this.currentSegment[field] = true; - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (slice2) { - this.readContiguousElements(slice2); - } - } else if (id === EBMLId.Tags || id === EBMLId.Attachments) { - if (id === EBMLId.Tags) { - this.currentSegment.tagsSeen = true; - } else { - this.currentSegment.attachmentsSeen = true; - } - assertDefinedSize(size); - let slice2 = this.reader.requestSlice(dataStartPos, size); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (slice2) { - this.readContiguousElements(slice2); - } - } else if (id === EBMLId.Cluster) { - this.currentSegment.clusterSeekStartPos = elementStartPos; - break; - } - if (size === void 0) { - break; - } else { - currentPos = dataStartPos + size; - } - } - this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition); - if (this.reader.fileSize !== null) { - for (const seekEntry of this.currentSegment.seekEntries) { - const target = METADATA_ELEMENTS.find((x) => x.id === seekEntry.id); - if (!target) { - continue; - } - if (this.currentSegment[target.flag]) - continue; - let slice = this.reader.requestSliceRange(segmentDataStart + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - continue; - const header = readElementHeader(slice); - if (!header) - continue; - const { id, size } = header; - if (id !== target.id) - continue; - assertDefinedSize(size); - this.currentSegment[target.flag] = true; - let dataSlice = this.reader.requestSlice(slice.filePos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (!dataSlice) - continue; - this.readContiguousElements(dataSlice); - } - } - if (this.currentSegment.timestampScale === -1) { - this.currentSegment.timestampScale = 1e6; - this.currentSegment.timestampFactor = 1e9 / 1e6; - } - for (const track of this.currentSegment.tracks) { - if (track.defaultDurationNs !== null) { - track.defaultDuration = this.currentSegment.timestampFactor * track.defaultDurationNs / 1e9; - } - } - this.currentSegment.tracks.sort((a, b) => Number(b.disposition.default) - Number(a.disposition.default)); - const idToTrack = new Map(this.currentSegment.tracks.map((x) => [x.id, x])); - for (const cuePoint of this.currentSegment.cuePoints) { - const track = idToTrack.get(cuePoint.trackId); - if (track) { - track.cuePoints.push(cuePoint); - } - } - for (const track of this.currentSegment.tracks) { - track.cuePoints.sort((a, b) => a.time - b.time); - for (let i = 0; i < track.cuePoints.length - 1; i++) { - const cuePoint1 = track.cuePoints[i]; - const cuePoint2 = track.cuePoints[i + 1]; - if (cuePoint1.time === cuePoint2.time) { - track.cuePoints.splice(i + 1, 1); - i--; - } - } - } - let trackWithMostCuePoints = null; - let maxCuePointCount = -Infinity; - for (const track of this.currentSegment.tracks) { - if (track.cuePoints.length > maxCuePointCount) { - maxCuePointCount = track.cuePoints.length; - trackWithMostCuePoints = track; - } - } - for (const track of this.currentSegment.tracks) { - if (track.cuePoints.length === 0) { - track.cuePoints = trackWithMostCuePoints.cuePoints; - } - } - this.currentSegment = null; + /** + * Returns the source from which this input file reads data for the root path. + */ + get source() { + return this._rootSource; } - async readCluster(startPos, segment) { - if (segment.lastReadCluster?.elementStartPos === startPos) { - return segment.lastReadCluster; + /** + * Returns the format of the input file. You can compare this result directly to the {@link InputFormat} singletons + * or use `instanceof` checks for subset-aware logic (for example, `format instanceof MatroskaInputFormat` is true + * for both MKV and WebM). + */ + async getFormat() { + await this._getDemuxer(); + assert(this._format); + return this._format; + } + /** Returns `true` if the format of the input file is known and the file can be read, `false` otherwise. */ + async canRead() { + try { + await this._getDemuxer(); + return true; + } catch (error) { + if (error instanceof UnsupportedInputFormatError) { + return false; + } + throw error; } - let headerSlice = this.reader.requestSliceRange(startPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const elementStartPos = startPos; - const elementHeader = readElementHeader(headerSlice); - assert(elementHeader); - const id = elementHeader.id; - assert(id === EBMLId.Cluster); - let size = elementHeader.size; - const dataStartPos = headerSlice.filePos; + } + /** + * Returns the timestamp at which the input file starts. More precisely, returns the smallest starting timestamp + * among all tracks. + * + * Optionally, you can pass in the list of tracks for which you want to compute the starting timestamp. + * + * Note that this method is potentially expensive for inputs with many tracks (such as HLS manifests), since it + * probes every track. + */ + async getFirstTimestamp(tracks) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + if (filtered.length === 0) { + return 0; + } + const firstTimestamps = await Promise.all(filtered.map((x) => x.getFirstTimestamp())); + return Math.min(...firstTimestamps); + } + /** + * Computes the duration of the input file, in seconds. More precisely, returns the largest end timestamp among + * all tracks. + * + * Optionally, you can pass in the list of tracks for which you want to compute the duration. + * + * This method can be potentially expensive depending on the underlying file format, because it returns the most + * accurate duration possible and must check all tracks. Use {@link Input.getDurationFromMetadata} for a faster but + * less accurate estimate of duration. + * + * By default, when any track in the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set {@link PacketRetrievalOptions.skipLiveWait} + * to `true` in the options. + */ + async computeDuration(tracks, options) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + if (filtered.length === 0) { + return 0; + } + const tracksDurations = await Promise.all(filtered.map((x) => x.computeDuration(options))); + return Math.max(...tracksDurations); + } + /** + * Gets the duration (end timestamp) in seconds of the input file from metadata stored in the file. This value may + * be approximate or diverge from the actual, precise duration returned by `.computeDuration()`, but compared to + * that method, this method is cheaper. When the duration cannot be determined from the file metadata, `null` + * is returned. + * + * Optionally, you can pass in the list of tracks for which you want to get the duration from metadata. + * + * By default, when the underlying media is live, this method will only resolve once the live stream + * ends. If you want to query the current duration of the media, set + * {@link DurationMetadataRequestOptions.skipLiveWait} to `true` in the options. + */ + async getDurationFromMetadata(tracks, options) { + tracks ?? (tracks = await this.getTracks()); + const filtered = tracks.filter((x) => x !== null); + const tracksDurations = await Promise.all(filtered.map((x) => x.getDurationFromMetadata(options))); + const nonNullDurations = tracksDurations.filter((x) => x !== null); + if (nonNullDurations.length === 0) { + return null; + } + return Math.max(...nonNullDurations); + } + /** + * Returns the list of all tracks of this input file in the order in which they appear in the file. An optional + * query can be provided. + */ + async getTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const backings = await this._getTrackBackings(); + const tracks = backings.map((backing) => this._wrapBackingAsTrack(backing)); + return queryInputTracks(tracks, query); + } + /** Returns the list of all video tracks of this input file. An optional query can be provided. */ + async getVideoTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const tracks = await this.getTracks(); + const videoTracks = tracks.filter((x) => x.isVideoTrack()); + return queryInputTracks(videoTracks, query); + } + /** Returns the list of all audio tracks of this input file. An optional query can be provided. */ + async getAudioTracks(query) { + query && (query = toValidatedInputTrackQuery(query)); + const tracks = await this.getTracks(); + const audioTracks = tracks.filter((x) => x.isAudioTrack()); + return queryInputTracks(audioTracks, query); + } + /** + * Returns the primary video track of this input file, or null if there are no video tracks. + * + * Multiple factors determine which track is considered primary, including its position in the file, disposition, + * bitrate (higher bitrate is preferred), and if it can be paired with an audio track. + */ + async getPrimaryVideoTrack(query) { + query && (query = toValidatedInputTrackQuery(query)); + const merged = mergeInputTrackQueries(query, { + sortBy: async (t) => [ + prefer((await t.getDisposition()).default), + prefer(await t.hasPairableAudioTrack()), + prefer(!await t.hasOnlyKeyPackets()), + desc(await t.getBitrate()) + ] + }); + const sorted = await this.getVideoTracks(merged); + return sorted[0] ?? null; + } + /** + * Returns the primary audio track of this input file, or null if there are no audio tracks. + * + * Multiple factors determine which track is considered primary, including its position in the file, disposition, + * bitrate (higher bitrate is preferred), and if it can be paired with the primary video track. + */ + async getPrimaryAudioTrack(query) { + query && (query = toValidatedInputTrackQuery(query)); + const primaryVideoTrack = await this.getPrimaryVideoTrack(); + const merged = mergeInputTrackQueries(query, { + sortBy: async (t) => [ + prefer(!primaryVideoTrack || t.canBePairedWith(primaryVideoTrack)), + prefer((await t.getDisposition()).default), + desc(await t.getBitrate()) + ] + }); + const sorted = await this.getAudioTracks(merged); + return sorted[0] ?? null; + } + /** @internal */ + async _getTrackBackings() { + const demuxer = await this._getDemuxer(); + return this._trackBackingsCache ?? (this._trackBackingsCache = await demuxer.getTrackBackings()); + } + /** @internal */ + _wrapBackingAsTrack(backing) { + const existing = this._backingToTrack.get(backing); + if (existing) { + return existing; + } + const type = backing.getType(); + const track = type === "video" ? new InputVideoTrack(this, backing) : new InputAudioTrack(this, backing); + this._backingToTrack.set(backing, track); + return track; + } + /** Returns the full MIME type of this input file, including track codecs. */ + async getMimeType() { + const demuxer = await this._getDemuxer(); + return demuxer.getMimeType(); + } + /** + * Returns descriptive metadata tags about the media file, such as title, author, date, cover art, or other + * attached files. + */ + async getMetadataTags() { + const demuxer = await this._getDemuxer(); + return demuxer.getMetadataTags(); + } + /** + * Disposes this input and frees connected resources. When an input is disposed, ongoing read operations will be + * canceled, all future read operations will fail, any open decoders will be closed, and all ongoing media sink + * operations will be canceled. Disallowed and canceled operations will throw an {@link InputDisposedError}. + * + * You are expected not to use an input after disposing it. While some operations may still work, it is not + * specified and may change in any future update. + */ + dispose() { + if (this._disposed) { + return; + } + this._disposed = true; + for (const ref of this._sourceRefs) { + ref.free(); + } + this._sourceRefs.length = 0; + inputFinalizationRegistry?.unregister(this); + void this._demuxerPromise?.then((demuxer) => demuxer.dispose()); + } + /** + * Calls `.dispose()` on the input, implementing the `Disposable` interface for use with + * JavaScript Explicit Resource Management features. + */ + [Symbol.dispose]() { + this.dispose(); + } +} +class UnsupportedInputFormatError extends Error { + /** Creates a new {@link UnsupportedInputFormatError}. */ + constructor(message = "Input has an unsupported or unrecognizable format.") { + super(message); + this.name = "UnsupportedInputFormatError"; + } +} +class InputDisposedError extends Error { + /** Creates a new {@link InputDisposedError}. */ + constructor(message = "Input has been disposed.") { + super(message); + this.name = "InputDisposedError"; + } +} +class Reader { + constructor(source) { + this.source = source; + } + get fileSize() { + const size = this.source._getFileSize(); if (size === void 0) { - const nextElementPos = await searchForNextElementId(this.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); - size = nextElementPos.pos - dataStartPos; + throw new Error("Reading file size too early; read required first."); } - let dataSlice = this.reader.requestSlice(dataStartPos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - const cluster = { - segment, - elementStartPos, - elementEndPos: dataStartPos + size, - dataStartPos, - timestamp: -1, - trackData: /* @__PURE__ */ new Map() - }; - this.currentCluster = cluster; - if (dataSlice) { - const endPos = this.readContiguousElements(dataSlice, LEVEL_0_AND_1_EBML_IDS); - cluster.elementEndPos = endPos; - } - for (const [, trackData] of cluster.trackData) { - const track = trackData.track; - assert(trackData.blocks.length > 0); - let hasLacedBlocks = false; - for (let i = 0; i < trackData.blocks.length; i++) { - const block = trackData.blocks[i]; - block.timestamp += cluster.timestamp; - hasLacedBlocks || (hasLacedBlocks = block.lacing !== BlockLacing.None); - } - trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); - for (let i = 0; i < trackData.presentationTimestamps.length; i++) { - const currentEntry = trackData.presentationTimestamps[i]; - const currentBlock = trackData.blocks[currentEntry.blockIndex]; - if (trackData.firstKeyFrameTimestamp === null && currentBlock.isKeyFrame) { - trackData.firstKeyFrameTimestamp = currentBlock.timestamp; - } - if (i < trackData.presentationTimestamps.length - 1) { - const nextEntry = trackData.presentationTimestamps[i + 1]; - currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp; - } else if (currentBlock.duration === 0) { - if (track.defaultDuration != null) { - if (currentBlock.lacing === BlockLacing.None) { - currentBlock.duration = track.defaultDuration; - } - } - } - } - if (hasLacedBlocks) { - this.expandLacedBlocks(trackData.blocks, track); - trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp); - } - const firstBlock = trackData.blocks[trackData.presentationTimestamps[0].blockIndex]; - const lastBlock = trackData.blocks[last(trackData.presentationTimestamps).blockIndex]; - trackData.startTimestamp = firstBlock.timestamp; - trackData.endTimestamp = lastBlock.timestamp + lastBlock.duration; - const insertionIndex = binarySearchLessOrEqual(track.clusterPositionCache, trackData.startTimestamp, (x) => x.startTimestamp); - if (insertionIndex === -1 || track.clusterPositionCache[insertionIndex].elementStartPos !== elementStartPos) { - track.clusterPositionCache.splice(insertionIndex + 1, 0, { - elementStartPos: cluster.elementStartPos, - startTimestamp: trackData.startTimestamp - }); - } - } - segment.lastReadCluster = cluster; - return cluster; + return size; } - getTrackDataInCluster(cluster, trackNumber) { - let trackData = cluster.trackData.get(trackNumber); - if (!trackData) { - const track = cluster.segment.tracks.find((x) => x.id === trackNumber); - if (!track) { + get fileSizeNonStrict() { + return this.source._getFileSize() ?? null; + } + requestSlice(start, length) { + if (this.source._disposed) { + throw new InputDisposedError(); + } + if (start < 0) { + return null; + } + if (this.fileSizeNonStrict !== null && start + length > this.fileSizeNonStrict) { + return null; + } + if (length === 0) { + const buffer = new Uint8Array(0); + return new FileSlice(buffer, toDataView(buffer), 0, start, start); + } + const end = start + length; + const result = this.source._read(start, end, DEFAULT_MIN_READ_POSITION, DEFAULT_MAX_READ_POSITION); + if (result instanceof Promise) { + return result.then((x) => { + if (!x) { + return null; + } + return new FileSlice(x.bytes, x.view, x.offset, start, end); + }); + } else { + if (!result) { return null; } - trackData = { - track, - startTimestamp: 0, - endTimestamp: 0, - firstKeyFrameTimestamp: null, - blocks: [], - presentationTimestamps: [] - }; - cluster.trackData.set(trackNumber, trackData); - } - return trackData; - } - expandLacedBlocks(blocks, track) { - for (let blockIndex = 0; blockIndex < blocks.length; blockIndex++) { - const originalBlock = blocks[blockIndex]; - if (originalBlock.lacing === BlockLacing.None) { - continue; - } - if (!originalBlock.decoded) { - originalBlock.data = this.decodeBlockData(track, originalBlock.data); - originalBlock.decoded = true; - } - const slice = FileSlice.tempFromBytes(originalBlock.data); - const frameSizes = []; - const frameCount = readU8(slice) + 1; - switch (originalBlock.lacing) { - case BlockLacing.Xiph: - { - let totalUsedSize = 0; - for (let i = 0; i < frameCount - 1; i++) { - let frameSize = 0; - while (slice.bufferPos < slice.length) { - const value = readU8(slice); - frameSize += value; - if (value < 255) { - frameSizes.push(frameSize); - totalUsedSize += frameSize; - break; - } - } - } - frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); - } - break; - case BlockLacing.FixedSize: - { - const totalDataSize = slice.length - 1; - const frameSize = Math.floor(totalDataSize / frameCount); - for (let i = 0; i < frameCount; i++) { - frameSizes.push(frameSize); - } - } - break; - case BlockLacing.Ebml: - { - const firstResult = readVarInt(slice); - assert(firstResult !== null); - let currentSize = firstResult; - frameSizes.push(currentSize); - let totalUsedSize = currentSize; - for (let i = 1; i < frameCount - 1; i++) { - const startPos = slice.bufferPos; - const diffResult = readVarInt(slice); - assert(diffResult !== null); - const unsignedDiff = diffResult; - const width = slice.bufferPos - startPos; - const bias = (1 << width * 7 - 1) - 1; - const diff = unsignedDiff - bias; - currentSize += diff; - frameSizes.push(currentSize); - totalUsedSize += currentSize; - } - frameSizes.push(slice.length - (slice.bufferPos + totalUsedSize)); - } - break; - default: - assert(false); - } - assert(frameSizes.length === frameCount); - blocks.splice(blockIndex, 1); - const blockDuration = originalBlock.duration || frameCount * (track.defaultDuration ?? 0); - for (let i = 0; i < frameCount; i++) { - const frameSize = frameSizes[i]; - const frameData = readBytes(slice, frameSize); - const frameTimestamp = originalBlock.timestamp + blockDuration * i / frameCount; - const frameDuration = blockDuration / frameCount; - blocks.splice(blockIndex + i, 0, { - timestamp: frameTimestamp, - duration: frameDuration, - isKeyFrame: originalBlock.isKeyFrame, - data: frameData, - lacing: BlockLacing.None, - decoded: true, - mainAdditional: originalBlock.mainAdditional - }); - } - blockIndex += frameCount; - blockIndex--; + return new FileSlice(result.bytes, result.view, result.offset, start, end); } } - async loadSegmentMetadata(segment) { - for (const seekEntry of segment.seekEntries) { - if (seekEntry.id === EBMLId.Tags && !segment.tagsSeen) ; - else if (seekEntry.id === EBMLId.Attachments && !segment.attachmentsSeen) ; - else { - continue; - } - let slice = this.reader.requestSliceRange(segment.dataStartPos + seekEntry.segmentPosition, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - continue; - const header = readElementHeader(slice); - if (!header || header.id !== seekEntry.id) - continue; - const { size } = header; - assertDefinedSize(size); - assert(!this.currentSegment); - this.currentSegment = segment; - let dataSlice = this.reader.requestSlice(slice.filePos, size); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (dataSlice) { - this.readContiguousElements(dataSlice); - } - this.currentSegment = null; - if (seekEntry.id === EBMLId.Tags) { - segment.tagsSeen = true; - } else if (seekEntry.id === EBMLId.Attachments) { - segment.attachmentsSeen = true; - } + requestSliceRange(start, minLength, maxLength) { + if (this.source._disposed) { + throw new InputDisposedError(); } - } - readContiguousElements(slice, stopIds) { - while (slice.remainingLength >= MIN_HEADER_SIZE) { - const startPos = slice.filePos; - const foundElement = this.traverseElement(slice, stopIds); - if (!foundElement) { - return startPos; - } - } - return slice.filePos; - } - traverseElement(slice, stopIds) { - const header = readElementHeader(slice); - if (!header) { - return false; - } - if (stopIds && stopIds.includes(header.id)) { - return false; - } - const { id, size } = header; - const dataStartPos = slice.filePos; - assertDefinedSize(size); - switch (id) { - case EBMLId.DocType: - { - this.isWebM = readAsciiString(slice, size) === "webm"; - } - break; - case EBMLId.Seek: - { - if (!this.currentSegment) - break; - const seekEntry = { id: -1, segmentPosition: -1 }; - this.currentSegment.seekEntries.push(seekEntry); - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (seekEntry.id === -1 || seekEntry.segmentPosition === -1) { - this.currentSegment.seekEntries.pop(); - } - } - break; - case EBMLId.SeekID: - { - const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; - if (!lastSeekEntry) - break; - lastSeekEntry.id = readUnsignedInt(slice, size); - } - break; - case EBMLId.SeekPosition: - { - const lastSeekEntry = this.currentSegment?.seekEntries[this.currentSegment.seekEntries.length - 1]; - if (!lastSeekEntry) - break; - lastSeekEntry.segmentPosition = readUnsignedInt(slice, size); - } - break; - case EBMLId.TimestampScale: - { - if (!this.currentSegment) - break; - this.currentSegment.timestampScale = readUnsignedInt(slice, size); - this.currentSegment.timestampFactor = 1e9 / this.currentSegment.timestampScale; - } - break; - case EBMLId.Duration: - { - if (!this.currentSegment) - break; - this.currentSegment.duration = readFloat(slice, size); - } - break; - case EBMLId.TrackEntry: - { - if (!this.currentSegment) - break; - this.currentTrack = { - id: -1, - segment: this.currentSegment, - demuxer: this, - clusterPositionCache: [], - cuePoints: [], - disposition: { - ...DEFAULT_TRACK_DISPOSITION - }, - inputTrack: null, - codecId: null, - codecPrivate: null, - defaultDuration: null, - defaultDurationNs: null, - name: null, - languageCode: UNDETERMINED_LANGUAGE, - decodingInstructions: [], - info: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (!this.currentTrack) { - break; - } - if (this.currentTrack.decodingInstructions.some((instruction) => { - return instruction.data?.type !== "decompress" || instruction.scope !== ContentEncodingScope.Block || instruction.data.algorithm !== ContentCompAlgo.HeaderStripping; - })) { - console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`); - this.currentTrack = null; - } - if (this.currentTrack && this.currentTrack.id !== -1 && this.currentTrack.codecId && this.currentTrack.info) { - const slashIndex = this.currentTrack.codecId.indexOf("/"); - const codecIdWithoutSuffix = slashIndex === -1 ? this.currentTrack.codecId : this.currentTrack.codecId.slice(0, slashIndex); - if (this.currentTrack.info.type === "video" && this.currentTrack.info.width !== -1 && this.currentTrack.info.height !== -1) { - if (this.currentTrack.codecId === CODEC_STRING_MAP.avc) { - this.currentTrack.info.codec = "avc"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === CODEC_STRING_MAP.hevc) { - this.currentTrack.info.codec = "hevc"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp8) { - this.currentTrack.info.codec = "vp8"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vp9) { - this.currentTrack.info.codec = "vp9"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.av1) { - this.currentTrack.info.codec = "av1"; - } - const videoTrack = this.currentTrack; - const inputTrack = new InputVideoTrack(this.input, new MatroskaVideoTrackBacking(videoTrack)); - this.currentTrack.inputTrack = inputTrack; - this.currentSegment.tracks.push(this.currentTrack); - } else if (this.currentTrack.info.type === "audio" && this.currentTrack.info.numberOfChannels !== -1 && this.currentTrack.info.sampleRate !== -1) { - if (codecIdWithoutSuffix === CODEC_STRING_MAP.aac) { - this.currentTrack.info.codec = "aac"; - this.currentTrack.info.aacCodecInfo = { - isMpeg2: this.currentTrack.codecId.includes("MPEG2") - }; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === CODEC_STRING_MAP.mp3) { - this.currentTrack.info.codec = "mp3"; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.opus) { - this.currentTrack.info.codec = "opus"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - this.currentTrack.info.sampleRate = OPUS_SAMPLE_RATE; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.vorbis) { - this.currentTrack.info.codec = "vorbis"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (codecIdWithoutSuffix === CODEC_STRING_MAP.flac) { - this.currentTrack.info.codec = "flac"; - this.currentTrack.info.codecDescription = this.currentTrack.codecPrivate; - } else if (this.currentTrack.codecId === "A_PCM/INT/LIT") { - if (this.currentTrack.info.bitDepth === 8) { - this.currentTrack.info.codec = "pcm-u8"; - } else if (this.currentTrack.info.bitDepth === 16) { - this.currentTrack.info.codec = "pcm-s16"; - } else if (this.currentTrack.info.bitDepth === 24) { - this.currentTrack.info.codec = "pcm-s24"; - } else if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-s32"; - } - } else if (this.currentTrack.codecId === "A_PCM/INT/BIG") { - if (this.currentTrack.info.bitDepth === 8) { - this.currentTrack.info.codec = "pcm-u8"; - } else if (this.currentTrack.info.bitDepth === 16) { - this.currentTrack.info.codec = "pcm-s16be"; - } else if (this.currentTrack.info.bitDepth === 24) { - this.currentTrack.info.codec = "pcm-s24be"; - } else if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-s32be"; - } - } else if (this.currentTrack.codecId === "A_PCM/FLOAT/IEEE") { - if (this.currentTrack.info.bitDepth === 32) { - this.currentTrack.info.codec = "pcm-f32"; - } else if (this.currentTrack.info.bitDepth === 64) { - this.currentTrack.info.codec = "pcm-f64"; - } - } - const audioTrack = this.currentTrack; - const inputTrack = new InputAudioTrack(this.input, new MatroskaAudioTrackBacking(audioTrack)); - this.currentTrack.inputTrack = inputTrack; - this.currentSegment.tracks.push(this.currentTrack); - } - } - this.currentTrack = null; - } - break; - case EBMLId.TrackNumber: - { - if (!this.currentTrack) - break; - this.currentTrack.id = readUnsignedInt(slice, size); - } - break; - case EBMLId.TrackType: - { - if (!this.currentTrack) - break; - const type = readUnsignedInt(slice, size); - if (type === 1) { - this.currentTrack.info = { - type: "video", - width: -1, - height: -1, - rotation: 0, - codec: null, - codecDescription: null, - colorSpace: null, - alphaMode: false - }; - } else if (type === 2) { - this.currentTrack.info = { - type: "audio", - numberOfChannels: -1, - sampleRate: -1, - bitDepth: -1, - codec: null, - codecDescription: null, - aacCodecInfo: null - }; - } - } - break; - case EBMLId.FlagEnabled: - { - if (!this.currentTrack) - break; - const enabled = readUnsignedInt(slice, size); - if (!enabled) { - this.currentTrack = null; - } - } - break; - case EBMLId.FlagDefault: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.default = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagForced: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.forced = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagOriginal: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.original = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagHearingImpaired: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.hearingImpaired = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagVisualImpaired: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.visuallyImpaired = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.FlagCommentary: - { - if (!this.currentTrack) - break; - this.currentTrack.disposition.commentary = !!readUnsignedInt(slice, size); - } - break; - case EBMLId.CodecID: - { - if (!this.currentTrack) - break; - this.currentTrack.codecId = readAsciiString(slice, size); - } - break; - case EBMLId.CodecPrivate: - { - if (!this.currentTrack) - break; - this.currentTrack.codecPrivate = readBytes(slice, size); - } - break; - case EBMLId.DefaultDuration: - { - if (!this.currentTrack) - break; - this.currentTrack.defaultDurationNs = readUnsignedInt(slice, size); - } - break; - case EBMLId.Name: - { - if (!this.currentTrack) - break; - this.currentTrack.name = readUnicodeString(slice, size); - } - break; - case EBMLId.Language: - { - if (!this.currentTrack) - break; - if (this.currentTrack.languageCode !== UNDETERMINED_LANGUAGE) { - break; - } - this.currentTrack.languageCode = readAsciiString(slice, size); - if (!isIso639Dash2LanguageCode(this.currentTrack.languageCode)) { - this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; - } - } - break; - case EBMLId.LanguageBCP47: - { - if (!this.currentTrack) - break; - const bcp47 = readAsciiString(slice, size); - const languageSubtag = bcp47.split("-")[0]; - if (languageSubtag) { - this.currentTrack.languageCode = languageSubtag; - } else { - this.currentTrack.languageCode = UNDETERMINED_LANGUAGE; - } - } - break; - case EBMLId.Video: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.PixelWidth: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.width = readUnsignedInt(slice, size); - } - break; - case EBMLId.PixelHeight: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.height = readUnsignedInt(slice, size); - } - break; - case EBMLId.AlphaMode: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.alphaMode = readUnsignedInt(slice, size) === 1; - } - break; - case EBMLId.Colour: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.currentTrack.info.colorSpace = {}; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.MatrixCoefficients: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const matrixCoefficients = readUnsignedInt(slice, size); - const mapped = MATRIX_COEFFICIENTS_MAP_INVERSE[matrixCoefficients] ?? null; - this.currentTrack.info.colorSpace.matrix = mapped; - } - break; - case EBMLId.Range: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - this.currentTrack.info.colorSpace.fullRange = readUnsignedInt(slice, size) === 2; - } - break; - case EBMLId.TransferCharacteristics: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const transferCharacteristics = readUnsignedInt(slice, size); - const mapped = TRANSFER_CHARACTERISTICS_MAP_INVERSE[transferCharacteristics] ?? null; - this.currentTrack.info.colorSpace.transfer = mapped; - } - break; - case EBMLId.Primaries: - { - if (this.currentTrack?.info?.type !== "video" || !this.currentTrack.info.colorSpace) - break; - const primaries = readUnsignedInt(slice, size); - const mapped = COLOR_PRIMARIES_MAP_INVERSE[primaries] ?? null; - this.currentTrack.info.colorSpace.primaries = mapped; - } - break; - case EBMLId.Projection: - { - if (this.currentTrack?.info?.type !== "video") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.ProjectionPoseRoll: - { - if (this.currentTrack?.info?.type !== "video") - break; - const rotation = readFloat(slice, size); - const flippedRotation = -rotation; - try { - this.currentTrack.info.rotation = normalizeRotation(flippedRotation); - } catch { - } - } - break; - case EBMLId.Audio: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.SamplingFrequency: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.sampleRate = readFloat(slice, size); - } - break; - case EBMLId.Channels: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.numberOfChannels = readUnsignedInt(slice, size); - } - break; - case EBMLId.BitDepth: - { - if (this.currentTrack?.info?.type !== "audio") - break; - this.currentTrack.info.bitDepth = readUnsignedInt(slice, size); - } - break; - case EBMLId.CuePoint: - { - if (!this.currentSegment) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentCueTime = null; - } - break; - case EBMLId.CueTime: - { - this.currentCueTime = readUnsignedInt(slice, size); - } - break; - case EBMLId.CueTrackPositions: - { - if (this.currentCueTime === null) - break; - assert(this.currentSegment); - const cuePoint = { time: this.currentCueTime, trackId: -1, clusterPosition: -1 }; - this.currentSegment.cuePoints.push(cuePoint); - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (cuePoint.trackId === -1 || cuePoint.clusterPosition === -1) { - this.currentSegment.cuePoints.pop(); - } - } - break; - case EBMLId.CueTrack: - { - const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; - if (!lastCuePoint) - break; - lastCuePoint.trackId = readUnsignedInt(slice, size); - } - break; - case EBMLId.CueClusterPosition: - { - const lastCuePoint = this.currentSegment?.cuePoints[this.currentSegment.cuePoints.length - 1]; - if (!lastCuePoint) - break; - assert(this.currentSegment); - lastCuePoint.clusterPosition = this.currentSegment.dataStartPos + readUnsignedInt(slice, size); - } - break; - case EBMLId.Timestamp: - { - if (!this.currentCluster) - break; - this.currentCluster.timestamp = readUnsignedInt(slice, size); - } - break; - case EBMLId.SimpleBlock: - { - if (!this.currentCluster) - break; - const trackNumber = readVarInt(slice); - if (trackNumber === null) - break; - const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); - if (!trackData) - break; - const relativeTimestamp = readI16Be(slice); - const flags = readU8(slice); - const lacing = flags >> 1 & 3; - let isKeyFrame = !!(flags & 128); - if (trackData.track.info?.type === "audio" && trackData.track.info.codec) { - isKeyFrame = true; - } - const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); - const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; - trackData.blocks.push({ - timestamp: relativeTimestamp, - // We'll add the cluster's timestamp to this later - duration: 0, - // Will set later - isKeyFrame, - data: blockData, - lacing, - decoded: !hasDecodingInstructions, - mainAdditional: null - }); - } - break; - case EBMLId.BlockGroup: - { - if (!this.currentCluster) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentBlock = null; - } - break; - case EBMLId.Block: - { - if (!this.currentCluster) - break; - const trackNumber = readVarInt(slice); - if (trackNumber === null) - break; - const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber); - if (!trackData) - break; - const relativeTimestamp = readI16Be(slice); - const flags = readU8(slice); - const lacing = flags >> 1 & 3; - const blockData = readBytes(slice, size - (slice.filePos - dataStartPos)); - const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0; - this.currentBlock = { - timestamp: relativeTimestamp, - // We'll add the cluster's timestamp to this later - duration: 0, - // Will set later - isKeyFrame: true, - data: blockData, - lacing, - decoded: !hasDecodingInstructions, - mainAdditional: null - }; - trackData.blocks.push(this.currentBlock); - } - break; - case EBMLId.BlockAdditions: - { - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.BlockMore: - { - if (!this.currentBlock) - break; - this.currentBlockAdditional = { - addId: 1, - data: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (this.currentBlockAdditional.data && this.currentBlockAdditional.addId === 1) { - this.currentBlock.mainAdditional = this.currentBlockAdditional.data; - } - this.currentBlockAdditional = null; - } - break; - case EBMLId.BlockAdditional: - { - if (!this.currentBlockAdditional) - break; - this.currentBlockAdditional.data = readBytes(slice, size); - } - break; - case EBMLId.BlockAddID: - { - if (!this.currentBlockAdditional) - break; - this.currentBlockAdditional.addId = readUnsignedInt(slice, size); - } - break; - case EBMLId.BlockDuration: - { - if (!this.currentBlock) - break; - this.currentBlock.duration = readUnsignedInt(slice, size); - } - break; - case EBMLId.ReferenceBlock: - { - if (!this.currentBlock) - break; - this.currentBlock.isKeyFrame = false; - } - break; - case EBMLId.Tag: - { - this.currentTagTargetIsMovie = true; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.Targets: - { - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.TargetTypeValue: - { - const targetTypeValue = readUnsignedInt(slice, size); - if (targetTypeValue !== 50) { - this.currentTagTargetIsMovie = false; - } - } - break; - case EBMLId.TagTrackUID: - case EBMLId.TagEditionUID: - case EBMLId.TagChapterUID: - case EBMLId.TagAttachmentUID: - { - this.currentTagTargetIsMovie = false; - } - break; - case EBMLId.SimpleTag: - { - if (!this.currentTagTargetIsMovie) - break; - this.currentSimpleTagName = null; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.TagName: - { - this.currentSimpleTagName = readUnicodeString(slice, size); - } - break; - case EBMLId.TagString: - { - if (!this.currentSimpleTagName) - break; - const value = readUnicodeString(slice, size); - this.processTagValue(this.currentSimpleTagName, value); - } - break; - case EBMLId.TagBinary: - { - if (!this.currentSimpleTagName) - break; - const value = readBytes(slice, size); - this.processTagValue(this.currentSimpleTagName, value); - } - break; - case EBMLId.AttachedFile: - { - if (!this.currentSegment) - break; - this.currentAttachedFile = { - fileUid: null, - fileName: null, - fileMediaType: null, - fileData: null, - fileDescription: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - const tags = this.currentSegment.metadataTags; - if (this.currentAttachedFile.fileUid && this.currentAttachedFile.fileData) { - tags.raw ?? (tags.raw = {}); - tags.raw[this.currentAttachedFile.fileUid.toString()] = new AttachedFile(this.currentAttachedFile.fileData, this.currentAttachedFile.fileMediaType ?? void 0, this.currentAttachedFile.fileName ?? void 0, this.currentAttachedFile.fileDescription ?? void 0); - } - if (this.currentAttachedFile.fileMediaType?.startsWith("image/") && this.currentAttachedFile.fileData) { - const fileName = this.currentAttachedFile.fileName; - let kind = "unknown"; - if (fileName) { - const lowerName = fileName.toLowerCase(); - if (lowerName.startsWith("cover.")) { - kind = "coverFront"; - } else if (lowerName.startsWith("back.")) { - kind = "coverBack"; - } - } - tags.images ?? (tags.images = []); - tags.images.push({ - data: this.currentAttachedFile.fileData, - mimeType: this.currentAttachedFile.fileMediaType, - kind, - name: this.currentAttachedFile.fileName ?? void 0, - description: this.currentAttachedFile.fileDescription ?? void 0 - }); - } - this.currentAttachedFile = null; - } - break; - case EBMLId.FileUID: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileUid = readUnsignedBigInt(slice, size); - } - break; - case EBMLId.FileName: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileName = readUnicodeString(slice, size); - } - break; - case EBMLId.FileMediaType: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileMediaType = readAsciiString(slice, size); - } - break; - case EBMLId.FileData: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileData = readBytes(slice, size); - } - break; - case EBMLId.FileDescription: - { - if (!this.currentAttachedFile) - break; - this.currentAttachedFile.fileDescription = readUnicodeString(slice, size); - } - break; - case EBMLId.ContentEncodings: - { - if (!this.currentTrack) - break; - this.readContiguousElements(slice.slice(dataStartPos, size)); - this.currentTrack.decodingInstructions.sort((a, b) => b.order - a.order); - } - break; - case EBMLId.ContentEncoding: - { - this.currentDecodingInstruction = { - order: 0, - scope: ContentEncodingScope.Block, - data: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - if (this.currentDecodingInstruction.data) { - this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction); - } - this.currentDecodingInstruction = null; - } - break; - case EBMLId.ContentEncodingOrder: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.order = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentEncodingScope: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.scope = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentCompression: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.data = { - type: "decompress", - algorithm: ContentCompAlgo.Zlib, - settings: null - }; - this.readContiguousElements(slice.slice(dataStartPos, size)); - } - break; - case EBMLId.ContentCompAlgo: - { - if (this.currentDecodingInstruction?.data?.type !== "decompress") - break; - this.currentDecodingInstruction.data.algorithm = readUnsignedInt(slice, size); - } - break; - case EBMLId.ContentCompSettings: - { - if (this.currentDecodingInstruction?.data?.type !== "decompress") - break; - this.currentDecodingInstruction.data.settings = readBytes(slice, size); - } - break; - case EBMLId.ContentEncryption: - { - if (!this.currentDecodingInstruction) - break; - this.currentDecodingInstruction.data = { - type: "decrypt" - }; - } - break; - } - slice.filePos = dataStartPos + size; - return true; - } - decodeBlockData(track, rawData) { - assert(track.decodingInstructions.length > 0); - let currentData = rawData; - for (const instruction of track.decodingInstructions) { - assert(instruction.data); - switch (instruction.data.type) { - case "decompress": - { - switch (instruction.data.algorithm) { - case ContentCompAlgo.HeaderStripping: - { - if (instruction.data.settings && instruction.data.settings.length > 0) { - const prefix = instruction.data.settings; - const newData = new Uint8Array(prefix.length + currentData.length); - newData.set(prefix, 0); - newData.set(currentData, prefix.length); - currentData = newData; - } - } - break; - } - } - break; - } - } - return currentData; - } - processTagValue(name, value) { - var _a; - if (!this.currentSegment?.metadataTags) - return; - const metadataTags = this.currentSegment.metadataTags; - metadataTags.raw ?? (metadataTags.raw = {}); - (_a = metadataTags.raw)[name] ?? (_a[name] = value); - if (typeof value === "string") { - switch (name.toLowerCase()) { - case "title": - { - metadataTags.title ?? (metadataTags.title = value); - } - break; - case "description": - { - metadataTags.description ?? (metadataTags.description = value); - } - break; - case "artist": - { - metadataTags.artist ?? (metadataTags.artist = value); - } - break; - case "album": - { - metadataTags.album ?? (metadataTags.album = value); - } - break; - case "album_artist": - { - metadataTags.albumArtist ?? (metadataTags.albumArtist = value); - } - break; - case "genre": - { - metadataTags.genre ?? (metadataTags.genre = value); - } - break; - case "comment": - { - metadataTags.comment ?? (metadataTags.comment = value); - } - break; - case "lyrics": - { - metadataTags.lyrics ?? (metadataTags.lyrics = value); - } - break; - case "date": - { - const date = new Date(value); - if (!Number.isNaN(date.getTime())) { - metadataTags.date ?? (metadataTags.date = date); - } - } - break; - case "track_number": - case "part_number": - { - const parts = value.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - metadataTags.trackNumber ?? (metadataTags.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - metadataTags.tracksTotal ?? (metadataTags.tracksTotal = tracksTotal); - } - } - break; - case "disc_number": - case "disc": - { - const discParts = value.split("/"); - const discNum = Number.parseInt(discParts[0], 10); - const discsTotal = discParts[1] && Number.parseInt(discParts[1], 10); - if (Number.isInteger(discNum) && discNum > 0) { - metadataTags.discNumber ?? (metadataTags.discNumber = discNum); - } - if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) { - metadataTags.discsTotal ?? (metadataTags.discsTotal = discsTotal); - } - } - break; - } - } - } -} -class MatroskaTrackBacking { - constructor(internalTrack) { - this.internalTrack = internalTrack; - this.packetToClusterLocation = /* @__PURE__ */ new WeakMap(); - } - getId() { - return this.internalTrack.id; - } - getCodec() { - throw new Error("Not implemented on base class."); - } - getInternalCodecId() { - return this.internalTrack.codecId; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return this.internalTrack.name; - } - getLanguageCode() { - return this.internalTrack.languageCode; - } - async getFirstTimestamp() { - const firstPacket = await this.getFirstPacket({ metadataOnly: true }); - return firstPacket?.timestamp ?? 0; - } - getTimeResolution() { - return this.internalTrack.segment.timestampFactor; - } - getDisposition() { - return this.internalTrack.disposition; - } - async getFirstPacket(options) { - return this.performClusterLookup( - null, - (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData) { - return { - blockIndex: 0, - correctBlockFound: true - }; - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - intoTimescale(timestamp) { - return roundIfAlmostInteger(timestamp * this.internalTrack.segment.timestampFactor); - } - async getPacket(timestamp, options) { - const timestampInTimescale = this.intoTimescale(timestamp); - return this.performClusterLookup(null, (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (!trackData) { - return { blockIndex: -1, correctBlockFound: false }; - } - const index = binarySearchLessOrEqual(trackData.presentationTimestamps, timestampInTimescale, (x) => x.timestamp); - const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; - const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { blockIndex, correctBlockFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextPacket(packet, options) { - const locationInCluster = this.packetToClusterLocation.get(packet); - if (locationInCluster === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performClusterLookup( - locationInCluster.cluster, - (cluster) => { - if (cluster === locationInCluster.cluster) { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (locationInCluster.blockIndex + 1 < trackData.blocks.length) { - return { - blockIndex: locationInCluster.blockIndex + 1, - correctBlockFound: true - }; - } - } else { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData) { - return { - blockIndex: 0, - correctBlockFound: true - }; - } - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - async getKeyPacket(timestamp, options) { - const timestampInTimescale = this.intoTimescale(timestamp); - return this.performClusterLookup(null, (cluster) => { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (!trackData) { - return { blockIndex: -1, correctBlockFound: false }; - } - const index = findLastIndex(trackData.presentationTimestamps, (x) => { - const block = trackData.blocks[x.blockIndex]; - return block.isKeyFrame && x.timestamp <= timestampInTimescale; - }); - const blockIndex = index !== -1 ? trackData.presentationTimestamps[index].blockIndex : -1; - const correctBlockFound = index !== -1 && timestampInTimescale < trackData.endTimestamp; - return { blockIndex, correctBlockFound }; - }, timestampInTimescale, timestampInTimescale, options); - } - async getNextKeyPacket(packet, options) { - const locationInCluster = this.packetToClusterLocation.get(packet); - if (locationInCluster === void 0) { - throw new Error("Packet was not created from this track."); - } - return this.performClusterLookup( - locationInCluster.cluster, - (cluster) => { - if (cluster === locationInCluster.cluster) { - const trackData = cluster.trackData.get(this.internalTrack.id); - const nextKeyFrameIndex = trackData.blocks.findIndex((x, i) => x.isKeyFrame && i > locationInCluster.blockIndex); - if (nextKeyFrameIndex !== -1) { - return { - blockIndex: nextKeyFrameIndex, - correctBlockFound: true - }; - } - } else { - const trackData = cluster.trackData.get(this.internalTrack.id); - if (trackData && trackData.firstKeyFrameTimestamp !== null) { - const keyFrameIndex = trackData.blocks.findIndex((x) => x.isKeyFrame); - assert(keyFrameIndex !== -1); - return { - blockIndex: keyFrameIndex, - correctBlockFound: true - }; - } - } - return { - blockIndex: -1, - correctBlockFound: false - }; - }, - -Infinity, - // Use -Infinity as a search timestamp to avoid using the cues - Infinity, - options - ); - } - async fetchPacketInCluster(cluster, blockIndex, options) { - if (blockIndex === -1) { + if (start < 0) { return null; } - const trackData = cluster.trackData.get(this.internalTrack.id); - const block = trackData.blocks[blockIndex]; - assert(block); - if (!block.decoded) { - block.data = this.internalTrack.demuxer.decodeBlockData(this.internalTrack, block.data); - block.decoded = true; - } - const data = options.metadataOnly ? PLACEHOLDER_DATA : block.data; - const timestamp = block.timestamp / this.internalTrack.segment.timestampFactor; - const duration = block.duration / this.internalTrack.segment.timestampFactor; - const sideData = {}; - if (block.mainAdditional && this.internalTrack.info?.type === "video" && this.internalTrack.info.alphaMode) { - sideData.alpha = options.metadataOnly ? PLACEHOLDER_DATA : block.mainAdditional; - sideData.alphaByteLength = block.mainAdditional.byteLength; - } - const packet = new EncodedPacket(data, block.isKeyFrame ? "key" : "delta", timestamp, duration, cluster.dataStartPos + blockIndex, block.data.byteLength, sideData); - this.packetToClusterLocation.set(packet, { cluster, blockIndex }); - return packet; - } - /** Looks for a packet in the clusters while trying to load as few clusters as possible to retrieve it. */ - async performClusterLookup(startCluster, getMatchInCluster, searchTimestamp, latestTimestamp, options) { - const { demuxer, segment } = this.internalTrack; - let currentCluster = null; - let bestCluster = null; - let bestBlockIndex = -1; - if (startCluster) { - const { blockIndex, correctBlockFound } = getMatchInCluster(startCluster); - if (correctBlockFound) { - return this.fetchPacketInCluster(startCluster, blockIndex, options); - } - if (blockIndex !== -1) { - bestCluster = startCluster; - bestBlockIndex = blockIndex; - } - } - const cuePointIndex = binarySearchLessOrEqual(this.internalTrack.cuePoints, searchTimestamp, (x) => x.time); - const cuePoint = cuePointIndex !== -1 ? this.internalTrack.cuePoints[cuePointIndex] : null; - const positionCacheIndex = binarySearchLessOrEqual(this.internalTrack.clusterPositionCache, searchTimestamp, (x) => x.startTimestamp); - const positionCacheEntry = positionCacheIndex !== -1 ? this.internalTrack.clusterPositionCache[positionCacheIndex] : null; - const lookupEntryPosition = Math.max(cuePoint?.clusterPosition ?? 0, positionCacheEntry?.elementStartPos ?? 0) || null; - let currentPos; - if (!startCluster) { - currentPos = lookupEntryPosition ?? segment.clusterSeekStartPos; + if (this.fileSizeNonStrict !== null) { + return this.requestSlice(start, clamp$1(this.fileSizeNonStrict - start, minLength, maxLength)); } else { - if (lookupEntryPosition === null || startCluster.elementStartPos >= lookupEntryPosition) { - currentPos = startCluster.elementEndPos; - currentCluster = startCluster; + const promisedAttempt = this.requestSlice(start, maxLength); + const handleAttempt = (attempt) => { + if (attempt) { + return attempt; + } + assert(this.fileSizeNonStrict !== null); + return this.requestSlice(start, clamp$1(this.fileSizeNonStrict - start, minLength, maxLength)); + }; + if (promisedAttempt instanceof Promise) { + return promisedAttempt.then(handleAttempt); } else { - currentPos = lookupEntryPosition; + return handleAttempt(promisedAttempt); } } - while (segment.elementEndPos === null || currentPos <= segment.elementEndPos - MIN_HEADER_SIZE) { - if (currentCluster) { - const trackData = currentCluster.trackData.get(this.internalTrack.id); - if (trackData && trackData.startTimestamp > latestTimestamp) { - break; - } - } - let slice = demuxer.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const elementStartPos = currentPos; - const elementHeader = readElementHeader(slice); - if (!elementHeader || !LEVEL_1_EBML_IDS.includes(elementHeader.id) && elementHeader.id !== EBMLId.Void) { - const nextPos = await resync(demuxer.reader, elementStartPos, LEVEL_1_EBML_IDS, Math.min(segment.elementEndPos ?? Infinity, elementStartPos + MAX_RESYNC_LENGTH)); - if (nextPos) { - currentPos = nextPos; - continue; - } else { - break; - } - } - const id = elementHeader.id; - let size = elementHeader.size; - const dataStartPos = slice.filePos; - if (id === EBMLId.Cluster) { - currentCluster = await demuxer.readCluster(elementStartPos, segment); - size = currentCluster.elementEndPos - dataStartPos; - const { blockIndex, correctBlockFound } = getMatchInCluster(currentCluster); - if (correctBlockFound) { - return this.fetchPacketInCluster(currentCluster, blockIndex, options); - } - if (blockIndex !== -1) { - bestCluster = currentCluster; - bestBlockIndex = blockIndex; - } - } - if (size === void 0) { - assert(id !== EBMLId.Cluster); - const nextElementPos = await searchForNextElementId(demuxer.reader, dataStartPos, LEVEL_0_AND_1_EBML_IDS, segment.elementEndPos); - size = nextElementPos.pos - dataStartPos; - } - const endPos = dataStartPos + size; - if (segment.elementEndPos === null) { - let slice2 = demuxer.reader.requestSliceRange(endPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const elementId = readElementId(slice2); - if (elementId === EBMLId.Segment) { - segment.elementEndPos = endPos; - break; - } - } - currentPos = endPos; + } + requestEntireFile() { + if (this.fileSizeNonStrict !== null) { + return this.requestSlice(0, this.fileSizeNonStrict); } - if (cuePoint && (!bestCluster || bestCluster.elementStartPos < cuePoint.clusterPosition)) { - const previousCuePoint = this.internalTrack.cuePoints[cuePointIndex - 1]; - assert(!previousCuePoint || previousCuePoint.time < cuePoint.time); - const newSearchTimestamp = previousCuePoint?.time ?? -Infinity; - return this.performClusterLookup(null, getMatchInCluster, newSearchTimestamp, latestTimestamp, options); - } - if (bestCluster) { - return this.fetchPacketInCluster(bestCluster, bestBlockIndex, options); - } - return null; + const CHUNK_SIZE = 1024; + return (async () => { + const chunks = []; + let currentSize = 0; + while (true) { + if (chunks.length === 1 && this.fileSizeNonStrict !== null) { + return this.requestSlice(0, this.fileSizeNonStrict); + } + const startOffset = chunks.length * CHUNK_SIZE; + let slice = this.requestSliceRange(startOffset, 0, CHUNK_SIZE); + if (slice instanceof Promise) + slice = await slice; + if (!slice) { + break; + } + chunks.push(readBytes(slice, slice.length)); + currentSize += slice.length; + } + const joined = new Uint8Array(currentSize); + let offset = 0; + for (const chunk of chunks) { + joined.set(chunk, offset); + offset += chunk.length; + } + return new FileSlice(joined, toDataView(joined), 0, 0, currentSize); + })(); } } -class MatroskaVideoTrackBacking extends MatroskaTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfigPromise = null; - this.internalTrack = internalTrack; +class FileSlice { + constructor(bytes, view, offset, start, end) { + this.bytes = bytes; + this.view = view; + this.offset = offset; + this.start = start; + this.end = end; + this.bufferPos = start - offset; } - getCodec() { - return this.internalTrack.info.codec; + static tempFromBytes(bytes) { + return new FileSlice(bytes, toDataView(bytes), 0, 0, bytes.length); } - getCodedWidth() { - return this.internalTrack.info.width; + get length() { + return this.end - this.start; } - getCodedHeight() { - return this.internalTrack.info.height; + get filePos() { + return this.offset + this.bufferPos; } - getRotation() { - return this.internalTrack.info.rotation; + set filePos(value) { + this.bufferPos = value - this.offset; } - async getColorSpace() { - return { - primaries: this.internalTrack.info.colorSpace?.primaries, - transfer: this.internalTrack.info.colorSpace?.transfer, - matrix: this.internalTrack.info.colorSpace?.matrix, - fullRange: this.internalTrack.info.colorSpace?.fullRange - }; + /** The number of bytes left from the current pos to the end of the slice. */ + get remainingLength() { + return Math.max(this.end - this.filePos, 0); } - async canBeTransparent() { - return this.internalTrack.info.alphaMode; + skip(byteCount) { + this.bufferPos += byteCount; } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; + /** Creates a new subslice of this slice whose byte range must be contained within this slice. */ + slice(filePos, length = this.end - filePos) { + if (filePos < this.start || filePos + length > this.end) { + throw new RangeError("Slicing outside of original slice."); } - return this.decoderConfigPromise ?? (this.decoderConfigPromise = (async () => { - let firstPacket = null; - const needsPacketForAdditionalInfo = this.internalTrack.info.codec === "vp9" || this.internalTrack.info.codec === "av1" || this.internalTrack.info.codec === "avc" && !this.internalTrack.info.codecDescription || this.internalTrack.info.codec === "hevc" && !this.internalTrack.info.codecDescription; - if (needsPacketForAdditionalInfo) { - firstPacket = await this.getFirstPacket({}); - } - return { - codec: extractVideoCodecString({ - width: this.internalTrack.info.width, - height: this.internalTrack.info.height, - codec: this.internalTrack.info.codec, - codecDescription: this.internalTrack.info.codecDescription, - colorSpace: this.internalTrack.info.colorSpace, - avcType: 1, - // We don't know better (or do we?) so just assume 'avc1' - avcCodecInfo: this.internalTrack.info.codec === "avc" && firstPacket ? extractAvcDecoderConfigurationRecord(firstPacket.data) : null, - hevcCodecInfo: this.internalTrack.info.codec === "hevc" && firstPacket ? extractHevcDecoderConfigurationRecord(firstPacket.data) : null, - vp9CodecInfo: this.internalTrack.info.codec === "vp9" && firstPacket ? extractVp9CodecInfoFromPacket(firstPacket.data) : null, - av1CodecInfo: this.internalTrack.info.codec === "av1" && firstPacket ? extractAv1CodecInfoFromPacket(firstPacket.data) : null - }), - codedWidth: this.internalTrack.info.width, - codedHeight: this.internalTrack.info.height, - description: this.internalTrack.info.codecDescription ?? void 0, - colorSpace: this.internalTrack.info.colorSpace ?? void 0 - }; - })()); + return new FileSlice(this.bytes, this.view, this.offset, filePos, filePos + length); } } -class MatroskaAudioTrackBacking extends MatroskaTrackBacking { - constructor(internalTrack) { - super(internalTrack); - this.decoderConfig = null; - this.internalTrack = internalTrack; - } - getCodec() { - return this.internalTrack.info.codec; - } - getNumberOfChannels() { - return this.internalTrack.info.numberOfChannels; - } - getSampleRate() { - return this.internalTrack.info.sampleRate; - } - async getDecoderConfig() { - if (!this.internalTrack.info.codec) { - return null; - } - return this.decoderConfig ?? (this.decoderConfig = { - codec: extractAudioCodecString({ - codec: this.internalTrack.info.codec, - codecDescription: this.internalTrack.info.codecDescription, - aacCodecInfo: this.internalTrack.info.aacCodecInfo - }), - numberOfChannels: this.internalTrack.info.numberOfChannels, - sampleRate: this.internalTrack.info.sampleRate, - description: this.internalTrack.info.codecDescription ?? void 0 - }); - } -} -const FRAME_HEADER_SIZE = 4; -const SAMPLING_RATES = [44100, 48e3, 32e3]; -const KILOBIT_RATES = [ - // lowSamplingFrequency === 0 - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - // layer = 0 - -1, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224, - 256, - 320, - -1, - // layer 1 - -1, - 32, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 160, - 192, - 224, - 256, - 320, - 384, - -1, - // layer = 2 - -1, - 32, - 64, - 96, - 128, - 160, - 192, - 224, - 256, - 288, - 320, - 352, - 384, - 416, - 448, - -1, - // layer = 3 - // lowSamplingFrequency === 1 - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - // layer = 0 - -1, - 8, - 16, - 24, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - -1, - // layer = 1 - -1, - 8, - 16, - 24, - 32, - 40, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - -1, - // layer = 2 - -1, - 32, - 48, - 56, - 64, - 80, - 96, - 112, - 128, - 144, - 160, - 176, - 192, - 224, - 256, - -1 - // layer = 3 -]; -const XING = 1483304551; -const INFO = 1231971951; -const computeMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate, padding) => { - if (layer === 0) { - return 0; - } else if (layer === 1) { - return Math.floor(144 * bitrate / (sampleRate << lowSamplingFrequency)) + padding; - } else if (layer === 2) { - return Math.floor(144 * bitrate / sampleRate) + padding; - } else { - return (Math.floor(12 * bitrate / sampleRate) + padding) * 4; +const checkIsInRange = (slice, bytesToRead) => { + if (slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) { + throw new RangeError(`Tried reading [${slice.filePos}, ${slice.filePos + bytesToRead}), but slice is [${slice.start}, ${slice.end}). This is likely an internal error, please report it alongside the file that caused it.`); } }; -const getXingOffset = (mpegVersionId, channel) => { - return mpegVersionId === 3 ? channel === 3 ? 21 : 36 : channel === 3 ? 13 : 21; +const readBytes = (slice, length) => { + checkIsInRange(slice, length); + const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length); + slice.bufferPos += length; + return bytes; }; -const readFrameHeader$1 = (word, remainingBytes) => { - const firstByte = word >>> 24; - const secondByte = word >>> 16 & 255; - const thirdByte = word >>> 8 & 255; - const fourthByte = word & 255; - if (firstByte !== 255 && secondByte !== 255 && thirdByte !== 255 && fourthByte !== 255) { - return { - header: null, - bytesAdvanced: 4 - }; - } - if (firstByte !== 255) { - return { header: null, bytesAdvanced: 1 }; - } - if ((secondByte & 224) !== 224) { - return { header: null, bytesAdvanced: 1 }; - } - let lowSamplingFrequency = 0; - let mpeg25 = 0; - if (secondByte & 1 << 4) { - lowSamplingFrequency = secondByte & 1 << 3 ? 0 : 1; - } else { - lowSamplingFrequency = 1; - mpeg25 = 1; - } - const mpegVersionId = secondByte >> 3 & 3; - const layer = secondByte >> 1 & 3; - const bitrateIndex = thirdByte >> 4 & 15; - const frequencyIndex = (thirdByte >> 2 & 3) % 3; - const padding = thirdByte >> 1 & 1; - const channel = fourthByte >> 6 & 3; - const modeExtension = fourthByte >> 4 & 3; - const copyright = fourthByte >> 3 & 1; - const original = fourthByte >> 2 & 1; - const emphasis = fourthByte & 3; - const kilobitRate = KILOBIT_RATES[lowSamplingFrequency * 16 * 4 + layer * 16 + bitrateIndex]; - if (kilobitRate === -1) { - return { header: null, bytesAdvanced: 1 }; - } - const bitrate = kilobitRate * 1e3; - const sampleRate = SAMPLING_RATES[frequencyIndex] >> lowSamplingFrequency + mpeg25; - const frameLength = computeMp3FrameSize(lowSamplingFrequency, layer, bitrate, sampleRate, padding); - if (remainingBytes !== null && remainingBytes < frameLength) { - return { header: null, bytesAdvanced: 1 }; - } - let audioSamplesInFrame; - if (mpegVersionId === 3) { - audioSamplesInFrame = layer === 3 ? 384 : 1152; - } else { - if (layer === 3) { - audioSamplesInFrame = 384; - } else if (layer === 2) { - audioSamplesInFrame = 1152; - } else { - audioSamplesInFrame = 576; - } - } - return { - header: { - totalSize: frameLength, - mpegVersionId, - layer, - bitrate, - frequencyIndex, - sampleRate, - channel, - modeExtension, - copyright, - original, - emphasis, - audioSamplesInFrame - }, - bytesAdvanced: 1 - }; +const readU8 = (slice) => { + checkIsInRange(slice, 1); + return slice.view.getUint8(slice.bufferPos++); }; -const decodeSynchsafe = (synchsafed) => { - let mask = 2130706432; - let unsynchsafed = 0; - while (mask !== 0) { - unsynchsafed >>= 1; - unsynchsafed |= synchsafed & mask; - mask >>= 8; +const readU16 = (slice, littleEndian) => { + checkIsInRange(slice, 2); + const value = slice.view.getUint16(slice.bufferPos, littleEndian); + slice.bufferPos += 2; + return value; +}; +const readU16Be = (slice) => { + checkIsInRange(slice, 2); + const value = slice.view.getUint16(slice.bufferPos, false); + slice.bufferPos += 2; + return value; +}; +const readU24Be = (slice) => { + checkIsInRange(slice, 3); + const value = getUint24(slice.view, slice.bufferPos, false); + slice.bufferPos += 3; + return value; +}; +const readI16Be = (slice) => { + checkIsInRange(slice, 2); + const value = slice.view.getInt16(slice.bufferPos, false); + slice.bufferPos += 2; + return value; +}; +const readU32 = (slice, littleEndian) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, littleEndian); + slice.bufferPos += 4; + return value; +}; +const readU32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; +}; +const readU32Le = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getUint32(slice.bufferPos, true); + slice.bufferPos += 4; + return value; +}; +const readI32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getInt32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; +}; +const readI32Le = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getInt32(slice.bufferPos, true); + slice.bufferPos += 4; + return value; +}; +const readU64 = (slice, littleEndian) => { + let low; + let high; + if (littleEndian) { + low = readU32(slice, true); + high = readU32(slice, true); + } else { + high = readU32(slice, false); + low = readU32(slice, false); } - return unsynchsafed; + return high * 4294967296 + low; +}; +const readU64Be = (slice) => { + const high = readU32Be(slice); + const low = readU32Be(slice); + return high * 4294967296 + low; +}; +const readI64Be = (slice) => { + const high = readI32Be(slice); + const low = readU32Be(slice); + return high * 4294967296 + low; +}; +const readI64Le = (slice) => { + const low = readU32Le(slice); + const high = readI32Le(slice); + return high * 4294967296 + low; +}; +const readF32Be = (slice) => { + checkIsInRange(slice, 4); + const value = slice.view.getFloat32(slice.bufferPos, false); + slice.bufferPos += 4; + return value; +}; +const readF64Be = (slice) => { + checkIsInRange(slice, 8); + const value = slice.view.getFloat64(slice.bufferPos, false); + slice.bufferPos += 8; + return value; +}; +const readAscii = (slice, length) => { + checkIsInRange(slice, length); + let str = ""; + for (let i = 0; i < length; i++) { + str += String.fromCharCode(slice.bytes[slice.bufferPos++]); + } + return str; +}; +const readAllLines = (slice, length, options) => { + const text = textDecoder.decode(readBytes(slice, length)); + const lines = text.split("\n").map((x) => x.trim()).filter((x) => x.length > 0 && !options?.ignore?.(x)); + return lines; }; var Id3V2HeaderFlags; (function(Id3V2HeaderFlags2) { @@ -10355,7 +20822,7 @@ const readId3V2Header = (slice) => { return { majorVersion, revision, flags, size }; }; const parseId3V2Tag = (slice, header, tags) => { - var _a, _b, _c, _d; + var _a, _b, _c, _d, _e; if (![2, 3, 4].includes(header.majorVersion)) { console.warn(`Unsupported ID3v2 major version: ${header.majorVersion}`); return; @@ -10408,10 +20875,16 @@ const parseId3V2Tag = (slice, header, tags) => { reader.ununsynchronizeRegion(reader.pos, frameEndPos); } tags.raw ?? (tags.raw = {}); - if (frame.id[0] === "T") { - (_a = tags.raw)[_b = frame.id] ?? (_a[_b] = reader.readId3V2EncodingAndText(frameEndPos)); + if (frame.id === "TXXX") { + const txxx = (_a = tags.raw)["TXXX"] ?? (_a["TXXX"] = {}); + const encoding = reader.readId3V2TextEncoding(); + const description = reader.readId3V2Text(encoding, frameEndPos); + const value = reader.readId3V2Text(encoding, frameEndPos); + txxx[description] ?? (txxx[description] = value); + } else if (frame.id[0] === "T") { + (_b = tags.raw)[_c = frame.id] ?? (_b[_c] = reader.readId3V2EncodingAndText(frameEndPos)); } else { - (_c = tags.raw)[_d = frame.id] ?? (_c[_d] = reader.readBytes(frame.size)); + (_d = tags.raw)[_e = frame.id] ?? (_d[_e] = reader.readBytes(frame.size)); } reader.pos = frameStartPos; switch (frame.id) { @@ -10757,3701 +21230,6 @@ class Id3V2Reader { return this.readId3V2Text(encoding, until); } } -const readNextFrameHeader = async (reader, startPos, until) => { - let currentPos = startPos; - while (until === null || currentPos < until) { - let slice = reader.requestSlice(currentPos, FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const word = readU32Be(slice); - const result = readFrameHeader$1(word, reader.fileSize !== null ? reader.fileSize - currentPos : null); - if (result.header) { - return { header: result.header, startPos: currentPos }; - } - currentPos += result.bytesAdvanced; - } - return null; -}; -class Mp3Demuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.firstFrameHeader = null; - this.loadedSamples = []; - this.metadataTags = null; - this.tracks = []; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.lastLoadedPos = 0; - this.nextTimestampInSamples = 0; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - while (!this.firstFrameHeader && !this.lastSampleLoaded) { - await this.advanceReader(); - } - if (!this.firstFrameHeader) { - throw new Error("No valid MP3 frame found."); - } - this.tracks = [new InputAudioTrack(this.input, new Mp3AudioTrackBacking(this))]; - })()); - } - async advanceReader() { - if (this.lastLoadedPos === 0) { - while (true) { - let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) { - this.lastSampleLoaded = true; - return; - } - const id3V2Header = readId3V2Header(slice2); - if (!id3V2Header) { - break; - } - this.lastLoadedPos = slice2.filePos + id3V2Header.size; - } - } - const result = await readNextFrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize); - if (!result) { - this.lastSampleLoaded = true; - return; - } - const header = result.header; - this.lastLoadedPos = result.startPos + header.totalSize - 1; - const xingOffset = getXingOffset(header.mpegVersionId, header.channel); - let slice = this.reader.requestSlice(result.startPos + xingOffset, 4); - if (slice instanceof Promise) - slice = await slice; - if (slice) { - const word = readU32Be(slice); - const isXing = word === XING || word === INFO; - if (isXing) { - return; - } - } - if (!this.firstFrameHeader) { - this.firstFrameHeader = header; - } - if (header.sampleRate !== this.firstFrameHeader.sampleRate) { - console.warn(`MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${header.sampleRate} Hz. Might be a bug, so please report this file.`); - } - const sampleDuration = header.audioSamplesInFrame / this.firstFrameHeader.sampleRate; - const sample = { - timestamp: this.nextTimestampInSamples / this.firstFrameHeader.sampleRate, - duration: sampleDuration, - dataStart: result.startPos, - dataSize: header.totalSize - }; - this.loadedSamples.push(sample); - this.nextTimestampInSamples += header.audioSamplesInFrame; - return; - } - async getMimeType() { - return "audio/mpeg"; - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getMetadataTags() { - const release = await this.readingMutex.acquire(); - try { - await this.readMetadata(); - if (this.metadataTags) { - return this.metadataTags; - } - this.metadataTags = {}; - let currentPos = 0; - let id3V2HeaderFound = false; - while (true) { - let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) - break; - const id3V2Header = readId3V2Header(headerSlice); - if (!id3V2Header) { - break; - } - id3V2HeaderFound = true; - let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size); - if (contentSlice instanceof Promise) - contentSlice = await contentSlice; - if (!contentSlice) - break; - parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); - currentPos = headerSlice.filePos + id3V2Header.size; - } - if (!id3V2HeaderFound && this.reader.fileSize !== null && this.reader.fileSize >= ID3_V1_TAG_SIZE) { - let slice = this.reader.requestSlice(this.reader.fileSize - ID3_V1_TAG_SIZE, ID3_V1_TAG_SIZE); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const tag = readAscii(slice, 3); - if (tag === "TAG") { - parseId3V1Tag(slice, this.metadataTags); - } - } - return this.metadataTags; - } finally { - release(); - } - } -} -class Mp3AudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - async getFirstTimestamp() { - return 0; - } - getTimeResolution() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.sampleRate / this.demuxer.firstFrameHeader.audioSamplesInFrame; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getCodec() { - return "mp3"; - } - getInternalCodecId() { - return null; - } - getNumberOfChannels() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2; - } - getSampleRate() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getDecoderConfig() { - assert(this.demuxer.firstFrameHeader); - return { - codec: "mp3", - numberOfChannels: this.demuxer.firstFrameHeader.channel === 3 ? 1 : 2, - sampleRate: this.demuxer.firstFrameHeader.sampleRate - }; - } - async getPacketAtIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.dataSize); - } - return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); - if (sampleIndex === -1) { - throw new Error("Packet was not created from this track."); - } - const nextIndex = sampleIndex + 1; - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - async getPacket(timestamp, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); - if (index === -1 && this.demuxer.loadedSamples.length > 0) { - return null; - } - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(index, options); - } - if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { - return this.getPacketAtIndex(index, options); - } - await this.demuxer.advanceReader(); - } - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } -} -const OGGS = 1399285583; -const OGG_CRC_POLYNOMIAL = 79764919; -const OGG_CRC_TABLE = new Uint32Array(256); -for (let n = 0; n < 256; n++) { - let crc = n << 24; - for (let k = 0; k < 8; k++) { - crc = crc & 2147483648 ? crc << 1 ^ OGG_CRC_POLYNOMIAL : crc << 1; - } - OGG_CRC_TABLE[n] = crc >>> 0 & 4294967295; -} -const computeOggPageCrc = (bytes) => { - const view = toDataView(bytes); - const originalChecksum = view.getUint32(22, true); - view.setUint32(22, 0, true); - let crc = 0; - for (let i = 0; i < bytes.length; i++) { - const byte = bytes[i]; - crc = (crc << 8 ^ OGG_CRC_TABLE[crc >>> 24 ^ byte]) >>> 0; - } - view.setUint32(22, originalChecksum, true); - return crc; -}; -const extractSampleMetadata = (data, codecInfo, vorbisLastBlocksize) => { - let durationInSamples = 0; - let currentBlocksize = null; - if (data.length > 0) { - if (codecInfo.codec === "vorbis") { - assert(codecInfo.vorbisInfo); - const vorbisModeCount = codecInfo.vorbisInfo.modeBlockflags.length; - const bitCount = ilog(vorbisModeCount - 1); - const modeMask = (1 << bitCount) - 1 << 1; - const modeNumber = (data[0] & modeMask) >> 1; - if (modeNumber >= codecInfo.vorbisInfo.modeBlockflags.length) { - throw new Error("Invalid mode number."); - } - let prevBlocksize = vorbisLastBlocksize; - const blockflag = codecInfo.vorbisInfo.modeBlockflags[modeNumber]; - currentBlocksize = codecInfo.vorbisInfo.blocksizes[blockflag]; - if (blockflag === 1) { - const prevMask = (modeMask | 1) + 1; - const flag = data[0] & prevMask ? 1 : 0; - prevBlocksize = codecInfo.vorbisInfo.blocksizes[flag]; - } - durationInSamples = prevBlocksize !== null ? prevBlocksize + currentBlocksize >> 2 : 0; - } else if (codecInfo.codec === "opus") { - const toc = parseOpusTocByte(data); - durationInSamples = toc.durationInSamples; - } - } - return { - durationInSamples, - vorbisBlockSize: currentBlocksize - }; -}; -const buildOggMimeType = (info) => { - let string = "audio/ogg"; - if (info.codecStrings) { - const uniqueCodecMimeTypes = [...new Set(info.codecStrings)]; - string += `; codecs="${uniqueCodecMimeTypes.join(", ")}"`; - } - return string; -}; -const MIN_PAGE_HEADER_SIZE = 27; -const MAX_PAGE_HEADER_SIZE = 27 + 255; -const MAX_PAGE_SIZE = MAX_PAGE_HEADER_SIZE + 255 * 255; -const readPageHeader = (slice) => { - const startPos = slice.filePos; - const capturePattern = readU32Le(slice); - if (capturePattern !== OGGS) { - return null; - } - slice.skip(1); - const headerType = readU8(slice); - const granulePosition = readI64Le(slice); - const serialNumber = readU32Le(slice); - const sequenceNumber = readU32Le(slice); - const checksum = readU32Le(slice); - const numberPageSegments = readU8(slice); - const lacingValues = new Uint8Array(numberPageSegments); - for (let i = 0; i < numberPageSegments; i++) { - lacingValues[i] = readU8(slice); - } - const headerSize = 27 + numberPageSegments; - const dataSize = lacingValues.reduce((a, b) => a + b, 0); - const totalSize = headerSize + dataSize; - return { - headerStartPos: startPos, - totalSize, - dataStartPos: startPos + headerSize, - dataSize, - headerType, - granulePosition, - serialNumber, - sequenceNumber, - checksum, - lacingValues - }; -}; -const findNextPageHeader = (slice, until) => { - while (slice.filePos < until - (4 - 1)) { - const word = readU32Le(slice); - const firstByte = word & 255; - const secondByte = word >>> 8 & 255; - const thirdByte = word >>> 16 & 255; - const fourthByte = word >>> 24 & 255; - const O = 79; - if (firstByte !== O && secondByte !== O && thirdByte !== O && fourthByte !== O) { - continue; - } - slice.skip(-4); - if (word === OGGS) { - return true; - } - slice.skip(1); - } - return false; -}; -class OggDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.bitstreams = []; - this.tracks = []; - this.metadataTags = {}; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let currentPos = 0; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - break; - const page = readPageHeader(slice); - if (!page) { - break; - } - const isBos = !!(page.headerType & 2); - if (!isBos) { - break; - } - this.bitstreams.push({ - serialNumber: page.serialNumber, - bosPage: page, - description: null, - numberOfChannels: -1, - sampleRate: -1, - codecInfo: { - codec: null, - vorbisInfo: null, - opusInfo: null - }, - lastMetadataPacket: null - }); - currentPos = page.headerStartPos + page.totalSize; - } - for (const bitstream of this.bitstreams) { - const firstPacket = await this.readPacket(bitstream.bosPage, 0); - if (!firstPacket) { - continue; - } - if ( - // Check for Vorbis - firstPacket.data.byteLength >= 7 && firstPacket.data[0] === 1 && firstPacket.data[1] === 118 && firstPacket.data[2] === 111 && firstPacket.data[3] === 114 && firstPacket.data[4] === 98 && firstPacket.data[5] === 105 && firstPacket.data[6] === 115 - ) { - await this.readVorbisMetadata(firstPacket, bitstream); - } else if ( - // Check for Opus - firstPacket.data.byteLength >= 8 && firstPacket.data[0] === 79 && firstPacket.data[1] === 112 && firstPacket.data[2] === 117 && firstPacket.data[3] === 115 && firstPacket.data[4] === 72 && firstPacket.data[5] === 101 && firstPacket.data[6] === 97 && firstPacket.data[7] === 100 - ) { - await this.readOpusMetadata(firstPacket, bitstream); - } - if (bitstream.codecInfo.codec !== null) { - this.tracks.push(new InputAudioTrack(this.input, new OggAudioTrackBacking(bitstream, this))); - } - } - })()); - } - async readVorbisMetadata(firstPacket, bitstream) { - let nextPacketPosition = await this.findNextPacketStart(firstPacket); - if (!nextPacketPosition) { - return; - } - const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!secondPacket) { - return; - } - nextPacketPosition = await this.findNextPacketStart(secondPacket); - if (!nextPacketPosition) { - return; - } - const thirdPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!thirdPacket) { - return; - } - if (secondPacket.data[0] !== 3 || thirdPacket.data[0] !== 5) { - return; - } - const lacingValues = []; - const addBytesToSegmentTable = (bytes) => { - while (true) { - lacingValues.push(Math.min(255, bytes)); - if (bytes < 255) { - break; - } - bytes -= 255; - } - }; - addBytesToSegmentTable(firstPacket.data.length); - addBytesToSegmentTable(secondPacket.data.length); - const description = new Uint8Array(1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length + thirdPacket.data.length); - description[0] = 2; - description.set(lacingValues, 1); - description.set(firstPacket.data, 1 + lacingValues.length); - description.set(secondPacket.data, 1 + lacingValues.length + firstPacket.data.length); - description.set(thirdPacket.data, 1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length); - bitstream.codecInfo.codec = "vorbis"; - bitstream.description = description; - bitstream.lastMetadataPacket = thirdPacket; - const view = toDataView(firstPacket.data); - bitstream.numberOfChannels = view.getUint8(11); - bitstream.sampleRate = view.getUint32(12, true); - const blockSizeByte = view.getUint8(28); - bitstream.codecInfo.vorbisInfo = { - blocksizes: [ - 1 << (blockSizeByte & 15), - 1 << (blockSizeByte >> 4) - ], - modeBlockflags: parseModesFromVorbisSetupPacket(thirdPacket.data).modeBlockflags - }; - readVorbisComments(secondPacket.data.subarray(7), this.metadataTags); - } - async readOpusMetadata(firstPacket, bitstream) { - const nextPacketPosition = await this.findNextPacketStart(firstPacket); - if (!nextPacketPosition) { - return; - } - const secondPacket = await this.readPacket(nextPacketPosition.startPage, nextPacketPosition.startSegmentIndex); - if (!secondPacket) { - return; - } - bitstream.codecInfo.codec = "opus"; - bitstream.description = firstPacket.data; - bitstream.lastMetadataPacket = secondPacket; - const header = parseOpusIdentificationHeader(firstPacket.data); - bitstream.numberOfChannels = header.outputChannelCount; - bitstream.sampleRate = OPUS_SAMPLE_RATE; - bitstream.codecInfo.opusInfo = { - preSkip: header.preSkip - }; - readVorbisComments(secondPacket.data.subarray(8), this.metadataTags); - } - async readPacket(startPage, startSegmentIndex) { - assert(startSegmentIndex < startPage.lacingValues.length); - let startDataOffset = 0; - for (let i = 0; i < startSegmentIndex; i++) { - startDataOffset += startPage.lacingValues[i]; - } - let currentPage = startPage; - let currentDataOffset = startDataOffset; - let currentSegmentIndex = startSegmentIndex; - const chunks = []; - outer: while (true) { - let pageSlice = this.reader.requestSlice(currentPage.dataStartPos, currentPage.dataSize); - if (pageSlice instanceof Promise) - pageSlice = await pageSlice; - assert(pageSlice); - const pageData = readBytes(pageSlice, currentPage.dataSize); - while (true) { - if (currentSegmentIndex === currentPage.lacingValues.length) { - chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); - break; - } - const lacingValue = currentPage.lacingValues[currentSegmentIndex]; - currentDataOffset += lacingValue; - if (lacingValue < 255) { - chunks.push(pageData.subarray(startDataOffset, currentDataOffset)); - break outer; - } - currentSegmentIndex++; - } - let currentPos = currentPage.headerStartPos + currentPage.totalSize; - while (true) { - let headerSlice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) { - return null; - } - const nextPage = readPageHeader(headerSlice); - if (!nextPage) { - return null; - } - currentPage = nextPage; - if (currentPage.serialNumber === startPage.serialNumber) { - break; - } - currentPos = currentPage.headerStartPos + currentPage.totalSize; - } - startDataOffset = 0; - currentDataOffset = 0; - currentSegmentIndex = 0; - } - const totalPacketSize = chunks.reduce((sum, chunk) => sum + chunk.length, 0); - if (totalPacketSize === 0) { - return null; - } - const packetData = new Uint8Array(totalPacketSize); - let offset = 0; - for (let i = 0; i < chunks.length; i++) { - const chunk = chunks[i]; - packetData.set(chunk, offset); - offset += chunk.length; - } - return { - data: packetData, - endPage: currentPage, - endSegmentIndex: currentSegmentIndex - }; - } - async findNextPacketStart(lastPacket) { - if (lastPacket.endSegmentIndex < lastPacket.endPage.lacingValues.length - 1) { - return { startPage: lastPacket.endPage, startSegmentIndex: lastPacket.endSegmentIndex + 1 }; - } - const isEos = !!(lastPacket.endPage.headerType & 4); - if (isEos) { - return null; - } - let currentPos = lastPacket.endPage.headerStartPos + lastPacket.endPage.totalSize; - while (true) { - let slice = this.reader.requestSliceRange(currentPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - const nextPage = readPageHeader(slice); - if (!nextPage) { - return null; - } - if (nextPage.serialNumber === lastPacket.endPage.serialNumber) { - return { startPage: nextPage, startSegmentIndex: 0 }; - } - currentPos = nextPage.headerStartPos + nextPage.totalSize; - } - } - async getMimeType() { - await this.readMetadata(); - const codecStrings = await Promise.all(this.tracks.map((x) => x.getCodecParameterString())); - return buildOggMimeType({ - codecStrings: codecStrings.filter(Boolean) - }); - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - const tracks = await this.getTracks(); - const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration())); - return Math.max(0, ...trackDurations); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } -} -class OggAudioTrackBacking { - constructor(bitstream, demuxer) { - this.bitstream = bitstream; - this.demuxer = demuxer; - this.encodedPacketToMetadata = /* @__PURE__ */ new WeakMap(); - this.sequentialScanCache = []; - this.sequentialScanMutex = new AsyncMutex(); - this.internalSampleRate = bitstream.codecInfo.codec === "opus" ? OPUS_SAMPLE_RATE : bitstream.sampleRate; - } - getId() { - return this.bitstream.serialNumber; - } - getNumberOfChannels() { - return this.bitstream.numberOfChannels; - } - getSampleRate() { - return this.bitstream.sampleRate; - } - getTimeResolution() { - return this.bitstream.sampleRate; - } - getCodec() { - return this.bitstream.codecInfo.codec; - } - getInternalCodecId() { - return null; - } - async getDecoderConfig() { - assert(this.bitstream.codecInfo.codec); - return { - codec: this.bitstream.codecInfo.codec, - numberOfChannels: this.bitstream.numberOfChannels, - sampleRate: this.bitstream.sampleRate, - description: this.bitstream.description ?? void 0 - }; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - granulePositionToTimestampInSamples(granulePosition) { - if (this.bitstream.codecInfo.codec === "opus") { - assert(this.bitstream.codecInfo.opusInfo); - return granulePosition - this.bitstream.codecInfo.opusInfo.preSkip; - } - return granulePosition; - } - createEncodedPacketFromOggPacket(packet, additional, options) { - if (!packet) { - return null; - } - const { durationInSamples, vorbisBlockSize } = extractSampleMetadata(packet.data, this.bitstream.codecInfo, additional.vorbisLastBlocksize); - const encodedPacket = new EncodedPacket(options.metadataOnly ? PLACEHOLDER_DATA : packet.data, "key", Math.max(0, additional.timestampInSamples) / this.internalSampleRate, durationInSamples / this.internalSampleRate, packet.endPage.headerStartPos + packet.endSegmentIndex, packet.data.byteLength); - this.encodedPacketToMetadata.set(encodedPacket, { - packet, - timestampInSamples: additional.timestampInSamples, - durationInSamples, - vorbisLastBlockSize: additional.vorbisLastBlocksize, - vorbisBlockSize - }); - return encodedPacket; - } - async getFirstPacket(options) { - assert(this.bitstream.lastMetadataPacket); - const packetPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); - if (!packetPosition) { - return null; - } - let timestampInSamples = 0; - if (this.bitstream.codecInfo.codec === "opus") { - assert(this.bitstream.codecInfo.opusInfo); - timestampInSamples -= this.bitstream.codecInfo.opusInfo.preSkip; - } - const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); - return this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples, - vorbisLastBlocksize: null - }, options); - } - async getNextPacket(prevPacket, options) { - const prevMetadata = this.encodedPacketToMetadata.get(prevPacket); - if (!prevMetadata) { - throw new Error("Packet was not created from this track."); - } - const packetPosition = await this.demuxer.findNextPacketStart(prevMetadata.packet); - if (!packetPosition) { - return null; - } - const timestampInSamples = prevMetadata.timestampInSamples + prevMetadata.durationInSamples; - const packet = await this.demuxer.readPacket(packetPosition.startPage, packetPosition.startSegmentIndex); - return this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples, - vorbisLastBlocksize: prevMetadata.vorbisBlockSize - }, options); - } - async getPacket(timestamp, options) { - if (this.demuxer.reader.fileSize === null) { - return this.getPacketSequential(timestamp, options); - } - const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); - if (timestampInSamples === 0) { - return this.getFirstPacket(options); - } - if (timestampInSamples < 0) { - return null; - } - assert(this.bitstream.lastMetadataPacket); - const startPosition = await this.demuxer.findNextPacketStart(this.bitstream.lastMetadataPacket); - if (!startPosition) { - return null; - } - let lowPage = startPosition.startPage; - let high = this.demuxer.reader.fileSize; - const lowPages = [lowPage]; - outer: while (lowPage.headerStartPos + lowPage.totalSize < high) { - const low = lowPage.headerStartPos; - const mid = Math.floor((low + high) / 2); - let searchStartPos = mid; - while (true) { - const until = Math.min(searchStartPos + MAX_PAGE_SIZE, high - MIN_PAGE_HEADER_SIZE); - let searchSlice = this.demuxer.reader.requestSlice(searchStartPos, until - searchStartPos); - if (searchSlice instanceof Promise) - searchSlice = await searchSlice; - assert(searchSlice); - const found = findNextPageHeader(searchSlice, until); - if (!found) { - high = mid + MIN_PAGE_HEADER_SIZE; - continue outer; - } - let headerSlice = this.demuxer.reader.requestSliceRange(searchSlice.filePos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - assert(headerSlice); - const page = readPageHeader(headerSlice); - assert(page); - let pageValid = false; - if (page.serialNumber === this.bitstream.serialNumber) { - pageValid = true; - } else { - let pageSlice = this.demuxer.reader.requestSlice(page.headerStartPos, page.totalSize); - if (pageSlice instanceof Promise) - pageSlice = await pageSlice; - assert(pageSlice); - const bytes = readBytes(pageSlice, page.totalSize); - const crc = computeOggPageCrc(bytes); - pageValid = crc === page.checksum; - } - if (!pageValid) { - searchStartPos = page.headerStartPos + 4; - continue; - } - if (pageValid && page.serialNumber !== this.bitstream.serialNumber) { - searchStartPos = page.headerStartPos + page.totalSize; - continue; - } - const isContinuationPage = page.granulePosition === -1; - if (isContinuationPage) { - searchStartPos = page.headerStartPos + page.totalSize; - continue; - } - if (this.granulePositionToTimestampInSamples(page.granulePosition) > timestampInSamples) { - high = page.headerStartPos; - } else { - lowPage = page; - lowPages.push(page); - } - continue outer; - } - } - let lowerPage = startPosition.startPage; - for (const otherLowPage of lowPages) { - if (otherLowPage.granulePosition === lowPage.granulePosition) { - break; - } - if (!lowerPage || otherLowPage.headerStartPos > lowerPage.headerStartPos) { - lowerPage = otherLowPage; - } - } - let currentPage = lowerPage; - const previousPages = [currentPage]; - while (true) { - if (currentPage.serialNumber === this.bitstream.serialNumber && currentPage.granulePosition === lowPage.granulePosition) { - break; - } - const nextPos = currentPage.headerStartPos + currentPage.totalSize; - let slice = this.demuxer.reader.requestSliceRange(nextPos, MIN_PAGE_HEADER_SIZE, MAX_PAGE_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const nextPage = readPageHeader(slice); - assert(nextPage); - currentPage = nextPage; - if (currentPage.serialNumber === this.bitstream.serialNumber) { - previousPages.push(currentPage); - } - } - assert(currentPage.granulePosition !== -1); - let currentSegmentIndex = null; - let currentTimestampInSamples; - let currentTimestampIsCorrect; - let endPage = currentPage; - let endSegmentIndex = 0; - if (currentPage.headerStartPos === startPosition.startPage.headerStartPos) { - currentTimestampInSamples = this.granulePositionToTimestampInSamples(0); - currentTimestampIsCorrect = true; - currentSegmentIndex = 0; - } else { - currentTimestampInSamples = 0; - currentTimestampIsCorrect = false; - for (let i = currentPage.lacingValues.length - 1; i >= 0; i--) { - const value = currentPage.lacingValues[i]; - if (value < 255) { - currentSegmentIndex = i + 1; - break; - } - } - if (currentSegmentIndex === null) { - throw new Error("Invalid page with granule position: no packets end on this page."); - } - endSegmentIndex = currentSegmentIndex - 1; - const pseudopacket = { - data: PLACEHOLDER_DATA, - endPage, - endSegmentIndex - }; - const nextPosition = await this.demuxer.findNextPacketStart(pseudopacket); - if (nextPosition) { - const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); - assert(endPosition); - const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); - if (startPosition2) { - currentPage = startPosition2.page; - currentSegmentIndex = startPosition2.segmentIndex; - } - } else { - while (true) { - const endPosition = findPreviousPacketEndPosition(previousPages, currentPage, currentSegmentIndex); - if (!endPosition) { - break; - } - const startPosition2 = findPacketStartPosition(previousPages, endPosition.page, endPosition.segmentIndex); - if (!startPosition2) { - break; - } - currentPage = startPosition2.page; - currentSegmentIndex = startPosition2.segmentIndex; - if (endPosition.page.headerStartPos !== endPage.headerStartPos) { - endPage = endPosition.page; - endSegmentIndex = endPosition.segmentIndex; - break; - } - } - } - } - let lastEncodedPacket = null; - let lastEncodedPacketMetadata = null; - while (currentPage !== null) { - assert(currentSegmentIndex !== null); - const packet = await this.demuxer.readPacket(currentPage, currentSegmentIndex); - if (!packet) { - break; - } - const skipPacket = currentPage.headerStartPos === startPosition.startPage.headerStartPos && currentSegmentIndex < startPosition.startSegmentIndex; - if (!skipPacket) { - let encodedPacket = this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples: currentTimestampInSamples, - vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null - }, options); - assert(encodedPacket); - let encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); - assert(encodedPacketMetadata); - if (!currentTimestampIsCorrect && packet.endPage.headerStartPos === endPage.headerStartPos && packet.endSegmentIndex === endSegmentIndex) { - currentTimestampInSamples = this.granulePositionToTimestampInSamples(currentPage.granulePosition); - currentTimestampIsCorrect = true; - encodedPacket = this.createEncodedPacketFromOggPacket(packet, { - timestampInSamples: currentTimestampInSamples - encodedPacketMetadata.durationInSamples, - vorbisLastBlocksize: lastEncodedPacketMetadata?.vorbisBlockSize ?? null - }, options); - assert(encodedPacket); - encodedPacketMetadata = this.encodedPacketToMetadata.get(encodedPacket); - assert(encodedPacketMetadata); - } else { - currentTimestampInSamples += encodedPacketMetadata.durationInSamples; - } - lastEncodedPacket = encodedPacket; - lastEncodedPacketMetadata = encodedPacketMetadata; - if (currentTimestampIsCorrect && // Next timestamp will be too late - (Math.max(currentTimestampInSamples, 0) > timestampInSamples || Math.max(encodedPacketMetadata.timestampInSamples, 0) === timestampInSamples)) { - break; - } - } - const nextPosition = await this.demuxer.findNextPacketStart(packet); - if (!nextPosition) { - break; - } - currentPage = nextPosition.startPage; - currentSegmentIndex = nextPosition.startSegmentIndex; - } - return lastEncodedPacket; - } - // A slower but simpler and sequential algorithm for finding a packet in a file - async getPacketSequential(timestamp, options) { - const release = await this.sequentialScanMutex.acquire(); - try { - const timestampInSamples = roundIfAlmostInteger(timestamp * this.internalSampleRate); - timestamp = timestampInSamples / this.internalSampleRate; - const index = binarySearchLessOrEqual(this.sequentialScanCache, timestampInSamples, (x) => x.timestampInSamples); - let currentPacket; - if (index !== -1) { - const cacheEntry = this.sequentialScanCache[index]; - currentPacket = this.createEncodedPacketFromOggPacket(cacheEntry.packet, { - timestampInSamples: cacheEntry.timestampInSamples, - vorbisLastBlocksize: cacheEntry.vorbisLastBlockSize - }, options); - } else { - currentPacket = await this.getFirstPacket(options); - } - let i = 0; - while (currentPacket && currentPacket.timestamp < timestamp) { - const nextPacket = await this.getNextPacket(currentPacket, options); - if (!nextPacket || nextPacket.timestamp > timestamp) { - break; - } - currentPacket = nextPacket; - i++; - if (i === 100) { - i = 0; - const metadata = this.encodedPacketToMetadata.get(currentPacket); - assert(metadata); - if (this.sequentialScanCache.length > 0) { - assert(last(this.sequentialScanCache).timestampInSamples <= metadata.timestampInSamples); - } - this.sequentialScanCache.push(metadata); - } - } - return currentPacket; - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } -} -const findPacketStartPosition = (pageList, endPage, endSegmentIndex) => { - let page = endPage; - let segmentIndex = endSegmentIndex; - outer: while (true) { - segmentIndex--; - for (segmentIndex; segmentIndex >= 0; segmentIndex--) { - const lacingValue = page.lacingValues[segmentIndex]; - if (lacingValue < 255) { - segmentIndex++; - break outer; - } - } - assert(segmentIndex === -1); - const pageStartsWithFreshPacket = !(page.headerType & 1); - if (pageStartsWithFreshPacket) { - segmentIndex = 0; - break; - } - const previousPage = findLast(pageList, (x) => x.headerStartPos < page.headerStartPos); - if (!previousPage) { - return null; - } - page = previousPage; - segmentIndex = page.lacingValues.length; - } - assert(segmentIndex !== -1); - if (segmentIndex === page.lacingValues.length) { - const nextPage = pageList[pageList.indexOf(page) + 1]; - assert(nextPage); - page = nextPage; - segmentIndex = 0; - } - return { page, segmentIndex }; -}; -const findPreviousPacketEndPosition = (pageList, startPage, startSegmentIndex) => { - if (startSegmentIndex > 0) { - return { page: startPage, segmentIndex: startSegmentIndex - 1 }; - } - const previousPage = findLast(pageList, (x) => x.headerStartPos < startPage.headerStartPos); - if (!previousPage) { - return null; - } - return { page: previousPage, segmentIndex: previousPage.lacingValues.length - 1 }; -}; -var WaveFormat; -(function(WaveFormat2) { - WaveFormat2[WaveFormat2["PCM"] = 1] = "PCM"; - WaveFormat2[WaveFormat2["IEEE_FLOAT"] = 3] = "IEEE_FLOAT"; - WaveFormat2[WaveFormat2["ALAW"] = 6] = "ALAW"; - WaveFormat2[WaveFormat2["MULAW"] = 7] = "MULAW"; - WaveFormat2[WaveFormat2["EXTENSIBLE"] = 65534] = "EXTENSIBLE"; -})(WaveFormat || (WaveFormat = {})); -class WaveDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.dataStart = -1; - this.dataSize = -1; - this.audioInfo = null; - this.tracks = []; - this.lastKnownPacketIndex = 0; - this.metadataTags = {}; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - let slice = this.reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - const riffType = readAscii(slice, 4); - const littleEndian = riffType !== "RIFX"; - const isRf64 = riffType === "RF64"; - const outerChunkSize = readU32(slice, littleEndian); - let totalFileSize = isRf64 ? this.reader.fileSize : Math.min(outerChunkSize + 8, this.reader.fileSize ?? Infinity); - const format = readAscii(slice, 4); - if (format !== "WAVE") { - throw new Error("Invalid WAVE file - wrong format"); - } - let chunksRead = 0; - let dataChunkSize = null; - let currentPos = slice.filePos; - while (totalFileSize === null || currentPos < totalFileSize) { - let slice2 = this.reader.requestSlice(currentPos, 8); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const chunkId = readAscii(slice2, 4); - const chunkSize = readU32(slice2, littleEndian); - const startPos = slice2.filePos; - if (isRf64 && chunksRead === 0 && chunkId !== "ds64") { - throw new Error('Invalid RF64 file: First chunk must be "ds64".'); - } - if (chunkId === "fmt ") { - await this.parseFmtChunk(startPos, chunkSize, littleEndian); - } else if (chunkId === "data") { - dataChunkSize ?? (dataChunkSize = chunkSize); - this.dataStart = slice2.filePos; - this.dataSize = Math.min(dataChunkSize, (totalFileSize ?? Infinity) - this.dataStart); - if (this.reader.fileSize === null) { - break; - } - } else if (chunkId === "ds64") { - let ds64Slice = this.reader.requestSlice(startPos, chunkSize); - if (ds64Slice instanceof Promise) - ds64Slice = await ds64Slice; - if (!ds64Slice) - break; - const riffChunkSize = readU64(ds64Slice, littleEndian); - dataChunkSize = readU64(ds64Slice, littleEndian); - totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity); - } else if (chunkId === "LIST") { - await this.parseListChunk(startPos, chunkSize, littleEndian); - } else if (chunkId === "ID3 " || chunkId === "id3 ") { - await this.parseId3Chunk(startPos, chunkSize); - } - currentPos = startPos + chunkSize + (chunkSize & 1); - chunksRead++; - } - if (!this.audioInfo) { - throw new Error('Invalid WAVE file - missing "fmt " chunk'); - } - if (this.dataStart === -1) { - throw new Error('Invalid WAVE file - missing "data" chunk'); - } - const blockSize = this.audioInfo.blockSizeInBytes; - this.dataSize = Math.floor(this.dataSize / blockSize) * blockSize; - this.tracks.push(new InputAudioTrack(this.input, new WaveAudioTrackBacking(this))); - })()); - } - async parseFmtChunk(startPos, size, littleEndian) { - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - let formatTag = readU16(slice, littleEndian); - const numChannels = readU16(slice, littleEndian); - const sampleRate = readU32(slice, littleEndian); - slice.skip(4); - const blockAlign = readU16(slice, littleEndian); - let bitsPerSample; - if (size === 14) { - bitsPerSample = 8; - } else { - bitsPerSample = readU16(slice, littleEndian); - } - if (size >= 18 && formatTag !== 357) { - const cbSize = readU16(slice, littleEndian); - const remainingSize = size - 18; - const extensionSize = Math.min(remainingSize, cbSize); - if (extensionSize >= 22 && formatTag === WaveFormat.EXTENSIBLE) { - slice.skip(2 + 4); - const subFormat = readBytes(slice, 16); - formatTag = subFormat[0] | subFormat[1] << 8; - } - } - if (formatTag === WaveFormat.MULAW || formatTag === WaveFormat.ALAW) { - bitsPerSample = 8; - } - this.audioInfo = { - format: formatTag, - numberOfChannels: numChannels, - sampleRate, - sampleSizeInBytes: Math.ceil(bitsPerSample / 8), - blockSizeInBytes: blockAlign - }; - } - async parseListChunk(startPos, size, littleEndian) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - const infoType = readAscii(slice, 4); - if (infoType !== "INFO" && infoType !== "INF0") { - return; - } - let currentPos = slice.filePos; - while (currentPos <= startPos + size - 8) { - slice.filePos = currentPos; - const chunkName = readAscii(slice, 4); - const chunkSize = readU32(slice, littleEndian); - const bytes = readBytes(slice, chunkSize); - let stringLength = 0; - for (let i = 0; i < bytes.length; i++) { - if (bytes[i] === 0) { - break; - } - stringLength++; - } - const value = String.fromCharCode(...bytes.subarray(0, stringLength)); - (_a = this.metadataTags).raw ?? (_a.raw = {}); - this.metadataTags.raw[chunkName] = value; - switch (chunkName) { - case "INAM": - case "TITL": - { - (_b = this.metadataTags).title ?? (_b.title = value); - } - break; - case "TIT3": - { - (_c = this.metadataTags).description ?? (_c.description = value); - } - break; - case "IART": - { - (_d = this.metadataTags).artist ?? (_d.artist = value); - } - break; - case "IPRD": - { - (_e = this.metadataTags).album ?? (_e.album = value); - } - break; - case "IPRT": - case "ITRK": - case "TRCK": - { - const parts = value.split("/"); - const trackNum = Number.parseInt(parts[0], 10); - const tracksTotal = parts[1] && Number.parseInt(parts[1], 10); - if (Number.isInteger(trackNum) && trackNum > 0) { - (_f = this.metadataTags).trackNumber ?? (_f.trackNumber = trackNum); - } - if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) { - (_g = this.metadataTags).tracksTotal ?? (_g.tracksTotal = tracksTotal); - } - } - break; - case "ICRD": - case "IDIT": - { - const date = new Date(value); - if (!Number.isNaN(date.getTime())) { - (_h = this.metadataTags).date ?? (_h.date = date); - } - } - break; - case "YEAR": - { - const year = Number.parseInt(value, 10); - if (Number.isInteger(year) && year > 0) { - (_i = this.metadataTags).date ?? (_i.date = new Date(year, 0, 1)); - } - } - break; - case "IGNR": - case "GENR": - { - (_j = this.metadataTags).genre ?? (_j.genre = value); - } - break; - case "ICMT": - case "CMNT": - case "COMM": - { - (_k = this.metadataTags).comment ?? (_k.comment = value); - } - break; - } - currentPos += 8 + chunkSize + (chunkSize & 1); - } - } - async parseId3Chunk(startPos, size) { - let slice = this.reader.requestSlice(startPos, size); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return; - const id3V2Header = readId3V2Header(slice); - if (id3V2Header) { - const contentSlice = slice.slice(startPos + 10, id3V2Header.size); - parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags); - } - } - getCodec() { - assert(this.audioInfo); - if (this.audioInfo.format === WaveFormat.MULAW) { - return "ulaw"; - } - if (this.audioInfo.format === WaveFormat.ALAW) { - return "alaw"; - } - if (this.audioInfo.format === WaveFormat.PCM) { - if (this.audioInfo.sampleSizeInBytes === 1) { - return "pcm-u8"; - } else if (this.audioInfo.sampleSizeInBytes === 2) { - return "pcm-s16"; - } else if (this.audioInfo.sampleSizeInBytes === 3) { - return "pcm-s24"; - } else if (this.audioInfo.sampleSizeInBytes === 4) { - return "pcm-s32"; - } - } - if (this.audioInfo.format === WaveFormat.IEEE_FLOAT) { - if (this.audioInfo.sampleSizeInBytes === 4) { - return "pcm-f32"; - } - } - return null; - } - async getMimeType() { - return "audio/wav"; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } -} -const PACKET_SIZE_IN_FRAMES = 2048; -class WaveAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - getCodec() { - return this.demuxer.getCodec(); - } - getInternalCodecId() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.format; - } - async getDecoderConfig() { - const codec = this.demuxer.getCodec(); - if (!codec) { - return null; - } - assert(this.demuxer.audioInfo); - return { - codec, - numberOfChannels: this.demuxer.audioInfo.numberOfChannels, - sampleRate: this.demuxer.audioInfo.sampleRate - }; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getNumberOfChannels() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.numberOfChannels; - } - getSampleRate() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getTimeResolution() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async getPacketAtIndex(packetIndex, options) { - assert(this.demuxer.audioInfo); - const startOffset = packetIndex * PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes; - if (startOffset >= this.demuxer.dataSize) { - return null; - } - const sizeInBytes = Math.min(PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes, this.demuxer.dataSize - startOffset); - if (this.demuxer.reader.fileSize === null) { - let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(this.demuxer.dataStart + startOffset, sizeInBytes); - if (slice instanceof Promise) - slice = await slice; - assert(slice); - data = readBytes(slice, sizeInBytes); - } - const timestamp = packetIndex * PACKET_SIZE_IN_FRAMES / this.demuxer.audioInfo.sampleRate; - const duration = sizeInBytes / this.demuxer.audioInfo.blockSizeInBytes / this.demuxer.audioInfo.sampleRate; - this.demuxer.lastKnownPacketIndex = Math.max(packetIndex, timestamp); - return new EncodedPacket(data, "key", timestamp, duration, packetIndex, sizeInBytes); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getPacket(timestamp, options) { - assert(this.demuxer.audioInfo); - const packetIndex = Math.floor(Math.min(timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES, (this.demuxer.dataSize - 1) / (PACKET_SIZE_IN_FRAMES * this.demuxer.audioInfo.blockSizeInBytes))); - const packet = await this.getPacketAtIndex(packetIndex, options); - if (packet) { - return packet; - } - if (packetIndex === 0) { - return null; - } - assert(this.demuxer.reader.fileSize === null); - let currentPacket = await this.getPacketAtIndex(this.demuxer.lastKnownPacketIndex, options); - while (currentPacket) { - const nextPacket = await this.getNextPacket(currentPacket, options); - if (!nextPacket) { - break; - } - currentPacket = nextPacket; - } - return currentPacket; - } - getNextPacket(packet, options) { - assert(this.demuxer.audioInfo); - const packetIndex = Math.round(packet.timestamp * this.demuxer.audioInfo.sampleRate / PACKET_SIZE_IN_FRAMES); - return this.getPacketAtIndex(packetIndex + 1, options); - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } -} -const MIN_FRAME_HEADER_SIZE = 7; -const MAX_FRAME_HEADER_SIZE = 9; -const readFrameHeader = (slice) => { - const startPos = slice.filePos; - const bytes = readBytes(slice, 9); - const bitstream = new Bitstream(bytes); - const syncword = bitstream.readBits(12); - if (syncword !== 4095) { - return null; - } - bitstream.skipBits(1); - const layer = bitstream.readBits(2); - if (layer !== 0) { - return null; - } - const protectionAbsence = bitstream.readBits(1); - const objectType = bitstream.readBits(2) + 1; - const samplingFrequencyIndex = bitstream.readBits(4); - if (samplingFrequencyIndex === 15) { - return null; - } - bitstream.skipBits(1); - const channelConfiguration = bitstream.readBits(3); - if (channelConfiguration === 0) { - throw new Error("ADTS frames with channel configuration 0 are not supported."); - } - bitstream.skipBits(1); - bitstream.skipBits(1); - bitstream.skipBits(1); - bitstream.skipBits(1); - const frameLength = bitstream.readBits(13); - bitstream.skipBits(11); - const numberOfAacFrames = bitstream.readBits(2) + 1; - if (numberOfAacFrames !== 1) { - throw new Error("ADTS frames with more than one AAC frame are not supported."); - } - let crcCheck = null; - if (protectionAbsence === 1) { - slice.filePos -= 2; - } else { - crcCheck = bitstream.readBits(16); - } - return { - objectType, - samplingFrequencyIndex, - channelConfiguration, - frameLength, - numberOfAacFrames, - crcCheck, - startPos - }; -}; -const SAMPLES_PER_AAC_FRAME = 1024; -class AdtsDemuxer extends Demuxer { - constructor(input) { - super(input); - this.metadataPromise = null; - this.firstFrameHeader = null; - this.loadedSamples = []; - this.tracks = []; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.lastLoadedPos = 0; - this.nextTimestampInSamples = 0; - this.reader = input._reader; - } - async readMetadata() { - return this.metadataPromise ?? (this.metadataPromise = (async () => { - while (!this.firstFrameHeader && !this.lastSampleLoaded) { - await this.advanceReader(); - } - assert(this.firstFrameHeader); - this.tracks = [new InputAudioTrack(this.input, new AdtsAudioTrackBacking(this))]; - })()); - } - async advanceReader() { - let slice = this.reader.requestSliceRange(this.lastLoadedPos, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - this.lastSampleLoaded = true; - return; - } - const header = readFrameHeader(slice); - if (!header) { - this.lastSampleLoaded = true; - return; - } - if (this.reader.fileSize !== null && header.startPos + header.frameLength > this.reader.fileSize) { - this.lastSampleLoaded = true; - return; - } - if (!this.firstFrameHeader) { - this.firstFrameHeader = header; - } - const sampleRate = aacFrequencyTable[header.samplingFrequencyIndex]; - assert(sampleRate !== void 0); - const sampleDuration = SAMPLES_PER_AAC_FRAME / sampleRate; - const headerSize = header.crcCheck ? MAX_FRAME_HEADER_SIZE : MIN_FRAME_HEADER_SIZE; - const sample = { - timestamp: this.nextTimestampInSamples / sampleRate, - duration: sampleDuration, - dataStart: header.startPos + headerSize, - dataSize: header.frameLength - headerSize - }; - this.loadedSamples.push(sample); - this.nextTimestampInSamples += SAMPLES_PER_AAC_FRAME; - this.lastLoadedPos = header.startPos + header.frameLength; - } - async getMimeType() { - return "audio/aac"; - } - async getTracks() { - await this.readMetadata(); - return this.tracks; - } - async computeDuration() { - await this.readMetadata(); - const track = this.tracks[0]; - assert(track); - return track.computeDuration(); - } - async getMetadataTags() { - return {}; - } -} -class AdtsAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - async getFirstTimestamp() { - return 0; - } - getTimeResolution() { - const sampleRate = this.getSampleRate(); - return sampleRate / SAMPLES_PER_AAC_FRAME; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getCodec() { - return "aac"; - } - getInternalCodecId() { - assert(this.demuxer.firstFrameHeader); - return this.demuxer.firstFrameHeader.objectType; - } - getNumberOfChannels() { - assert(this.demuxer.firstFrameHeader); - const numberOfChannels = aacChannelMap[this.demuxer.firstFrameHeader.channelConfiguration]; - assert(numberOfChannels !== void 0); - return numberOfChannels; - } - getSampleRate() { - assert(this.demuxer.firstFrameHeader); - const sampleRate = aacFrequencyTable[this.demuxer.firstFrameHeader.samplingFrequencyIndex]; - assert(sampleRate !== void 0); - return sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getDecoderConfig() { - assert(this.demuxer.firstFrameHeader); - const bytes = new Uint8Array(3); - const bitstream = new Bitstream(bytes); - const { objectType, samplingFrequencyIndex, channelConfiguration } = this.demuxer.firstFrameHeader; - if (objectType > 31) { - bitstream.writeBits(5, 31); - bitstream.writeBits(6, objectType - 32); - } else { - bitstream.writeBits(5, objectType); - } - bitstream.writeBits(4, samplingFrequencyIndex); - bitstream.writeBits(4, channelConfiguration); - return { - codec: `mp4a.40.${this.demuxer.firstFrameHeader.objectType}`, - numberOfChannels: this.getNumberOfChannels(), - sampleRate: this.getSampleRate(), - description: bytes.subarray(0, Math.ceil((bitstream.pos - 1) / 8)) - }; - } - async getPacketAtIndex(sampleIndex, options) { - if (sampleIndex === -1) { - return null; - } - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.dataStart, rawSample.dataSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.dataSize); - } - return new EncodedPacket(data, "key", rawSample.timestamp, rawSample.duration, sampleIndex, rawSample.dataSize); - } - getFirstPacket(options) { - return this.getPacketAtIndex(0, options); - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const sampleIndex = binarySearchExact(this.demuxer.loadedSamples, packet.timestamp, (x) => x.timestamp); - if (sampleIndex === -1) { - throw new Error("Packet was not created from this track."); - } - const nextIndex = sampleIndex + 1; - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - async getPacket(timestamp, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const index = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.timestamp); - if (index === -1 && this.demuxer.loadedSamples.length > 0) { - return null; - } - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(index, options); - } - if (index >= 0 && index + 1 < this.demuxer.loadedSamples.length) { - return this.getPacketAtIndex(index, options); - } - await this.demuxer.advanceReader(); - } - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } -} -const getBlockSizeOrUncommon = (bits) => { - if (bits === 0) { - return null; - } else if (bits === 1) { - return 192; - } else if (bits >= 2 && bits <= 5) { - return 144 * 2 ** bits; - } else if (bits === 6) { - return "uncommon-u8"; - } else if (bits === 7) { - return "uncommon-u16"; - } else if (bits >= 8 && bits <= 15) { - return 2 ** bits; - } else { - return null; - } -}; -const getSampleRateOrUncommon = (sampleRateBits, streamInfoSampleRate) => { - switch (sampleRateBits) { - case 0: - return streamInfoSampleRate; - case 1: - return 88200; - case 2: - return 176400; - case 3: - return 192e3; - case 4: - return 8e3; - case 5: - return 16e3; - case 6: - return 22050; - case 7: - return 24e3; - case 8: - return 32e3; - case 9: - return 44100; - case 10: - return 48e3; - case 11: - return 96e3; - case 12: - return "uncommon-u8"; - case 13: - return "uncommon-u16"; - case 14: - return "uncommon-u16-10"; - default: - return null; - } -}; -const readCodedNumber = (fileSlice) => { - let ones = 0; - const bitstream1 = new Bitstream(readBytes(fileSlice, 1)); - while (bitstream1.readBits(1) === 1) { - ones++; - } - if (ones === 0) { - return bitstream1.readBits(7); - } - const bitArray = []; - const extraBytes = ones - 1; - const bitstream2 = new Bitstream(readBytes(fileSlice, extraBytes)); - const firstByteBits = 8 - ones - 1; - for (let i = 0; i < firstByteBits; i++) { - bitArray.unshift(bitstream1.readBits(1)); - } - for (let i = 0; i < extraBytes; i++) { - for (let j = 0; j < 8; j++) { - const val = bitstream2.readBits(1); - if (j < 2) { - continue; - } - bitArray.unshift(val); - } - } - const encoded = bitArray.reduce((acc, bit, index) => { - return acc | bit << index; - }, 0); - return encoded; -}; -const readBlockSize = (slice, blockSizeBits) => { - if (blockSizeBits === "uncommon-u16") { - return readU16Be(slice) + 1; - } else if (blockSizeBits === "uncommon-u8") { - return readU8(slice) + 1; - } else if (typeof blockSizeBits === "number") { - return blockSizeBits; - } else { - assertNever(blockSizeBits); - assert(false); - } -}; -const readSampleRate = (slice, sampleRateOrUncommon) => { - if (sampleRateOrUncommon === "uncommon-u16") { - return readU16Be(slice); - } - if (sampleRateOrUncommon === "uncommon-u16-10") { - return readU16Be(slice) * 10; - } - if (sampleRateOrUncommon === "uncommon-u8") { - return readU8(slice); - } - if (typeof sampleRateOrUncommon === "number") { - return sampleRateOrUncommon; - } - return null; -}; -const calculateCrc8 = (data) => { - const polynomial = 7; - let crc = 0; - for (const byte of data) { - crc ^= byte; - for (let i = 0; i < 8; i++) { - if ((crc & 128) !== 0) { - crc = crc << 1 ^ polynomial; - } else { - crc <<= 1; - } - crc &= 255; - } - } - return crc; -}; -class FlacDemuxer extends Demuxer { - constructor(input) { - super(input); - this.loadedSamples = []; - this.metadataPromise = null; - this.track = null; - this.metadataTags = {}; - this.audioInfo = null; - this.lastLoadedPos = null; - this.blockingBit = null; - this.readingMutex = new AsyncMutex(); - this.lastSampleLoaded = false; - this.reader = input._reader; - } - async computeDuration() { - await this.readMetadata(); - assert(this.track); - return this.track.computeDuration(); - } - async getMetadataTags() { - await this.readMetadata(); - return this.metadataTags; - } - async getTracks() { - await this.readMetadata(); - assert(this.track); - return [this.track]; - } - async getMimeType() { - return "audio/flac"; - } - async readMetadata() { - let currentPos = 4; - return this.metadataPromise ?? (this.metadataPromise = (async () => { - var _a; - while (this.reader.fileSize === null || currentPos < this.reader.fileSize) { - let sizeSlice = this.reader.requestSlice(currentPos, 4); - if (sizeSlice instanceof Promise) - sizeSlice = await sizeSlice; - currentPos += 4; - if (sizeSlice === null) { - throw new Error(`Metadata block at position ${currentPos} is too small! Corrupted file.`); - } - assert(sizeSlice); - const byte = readU8(sizeSlice); - const size = readU24Be(sizeSlice); - const isLastMetadata = (byte & 128) !== 0; - const metaBlockType = byte & 127; - switch (metaBlockType) { - case FlacBlockType.STREAMINFO: { - let streamInfoBlock = this.reader.requestSlice(currentPos, size); - if (streamInfoBlock instanceof Promise) - streamInfoBlock = await streamInfoBlock; - assert(streamInfoBlock); - if (streamInfoBlock === null) { - throw new Error(`StreamInfo block at position ${currentPos} is too small! Corrupted file.`); - } - const streamInfoBytes = readBytes(streamInfoBlock, 34); - const bitstream = new Bitstream(streamInfoBytes); - const minimumBlockSize = bitstream.readBits(16); - const maximumBlockSize = bitstream.readBits(16); - const minimumFrameSize = bitstream.readBits(24); - const maximumFrameSize = bitstream.readBits(24); - const sampleRate = bitstream.readBits(20); - const numberOfChannels = bitstream.readBits(3) + 1; - bitstream.readBits(5); - const totalSamples = bitstream.readBits(36); - bitstream.skipBits(16 * 8); - const description = new Uint8Array(42); - description.set(new Uint8Array([102, 76, 97, 67]), 0); - description.set(new Uint8Array([128, 0, 0, 34]), 4); - description.set(streamInfoBytes, 8); - this.audioInfo = { - numberOfChannels, - sampleRate, - totalSamples, - minimumBlockSize, - maximumBlockSize, - minimumFrameSize, - maximumFrameSize, - description - }; - this.track = new InputAudioTrack(this.input, new FlacAudioTrackBacking(this)); - break; - } - case FlacBlockType.VORBIS_COMMENT: { - let vorbisCommentBlock = this.reader.requestSlice(currentPos, size); - if (vorbisCommentBlock instanceof Promise) - vorbisCommentBlock = await vorbisCommentBlock; - assert(vorbisCommentBlock); - readVorbisComments(readBytes(vorbisCommentBlock, size), this.metadataTags); - break; - } - case FlacBlockType.PICTURE: { - let pictureBlock = this.reader.requestSlice(currentPos, size); - if (pictureBlock instanceof Promise) - pictureBlock = await pictureBlock; - assert(pictureBlock); - const pictureType = readU32Be(pictureBlock); - const mediaTypeLength = readU32Be(pictureBlock); - const mediaType = textDecoder.decode(readBytes(pictureBlock, mediaTypeLength)); - const descriptionLength = readU32Be(pictureBlock); - const description = textDecoder.decode(readBytes(pictureBlock, descriptionLength)); - pictureBlock.skip(4 + 4 + 4 + 4); - const dataLength = readU32Be(pictureBlock); - const data = readBytes(pictureBlock, dataLength); - (_a = this.metadataTags).images ?? (_a.images = []); - this.metadataTags.images.push({ - data, - mimeType: mediaType, - // https://www.rfc-editor.org/rfc/rfc9639.html#table13 - kind: pictureType === 3 ? "coverFront" : pictureType === 4 ? "coverBack" : "unknown", - description - }); - break; - } - } - currentPos += size; - if (isLastMetadata) { - this.lastLoadedPos = currentPos; - break; - } - } - })()); - } - async readNextFlacFrame({ startPos, isFirstPacket }) { - assert(this.audioInfo); - const minimumHeaderLength = 6; - const maximumHeaderSize = 16; - const maximumSliceLength = this.audioInfo.maximumFrameSize + maximumHeaderSize; - const slice = await this.reader.requestSliceRange(startPos, this.audioInfo.minimumFrameSize, maximumSliceLength); - if (!slice) { - return null; - } - const frameHeader = this.readFlacFrameHeader({ - slice, - isFirstPacket - }); - if (!frameHeader) { - return null; - } - slice.filePos = startPos + this.audioInfo.minimumFrameSize; - while (true) { - if (slice.filePos > slice.end - minimumHeaderLength) { - return { - num: frameHeader.num, - blockSize: frameHeader.blockSize, - sampleRate: frameHeader.sampleRate, - size: slice.end - startPos, - isLastFrame: true - }; - } - const nextByte = readU8(slice); - if (nextByte === 255) { - const positionBeforeReading = slice.filePos; - const byteAfterNextByte = readU8(slice); - const expected = this.blockingBit === 1 ? 249 : 248; - if (byteAfterNextByte !== expected) { - slice.filePos = positionBeforeReading; - continue; - } - slice.skip(-2); - const lengthIfNextFlacFrameHeaderIsLegit = slice.filePos - startPos; - const nextFrameHeader = this.readFlacFrameHeader({ - slice, - isFirstPacket: false - }); - if (!nextFrameHeader) { - slice.filePos = positionBeforeReading; - continue; - } - if (this.blockingBit === 0) { - if (nextFrameHeader.num - frameHeader.num !== 1) { - slice.filePos = positionBeforeReading; - continue; - } - } else { - if (nextFrameHeader.num - frameHeader.num !== frameHeader.blockSize) { - slice.filePos = positionBeforeReading; - continue; - } - } - return { - num: frameHeader.num, - blockSize: frameHeader.blockSize, - sampleRate: frameHeader.sampleRate, - size: lengthIfNextFlacFrameHeaderIsLegit, - isLastFrame: false - }; - } - } - } - readFlacFrameHeader({ slice, isFirstPacket }) { - const startOffset = slice.filePos; - const bytes = readBytes(slice, 4); - const bitstream = new Bitstream(bytes); - const bits = bitstream.readBits(15); - if (bits !== 32764) { - return null; - } - if (this.blockingBit === null) { - assert(isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - this.blockingBit = newBlockingBit; - } else if (this.blockingBit === 1) { - assert(!isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - if (newBlockingBit !== 1) { - return null; - } - } else if (this.blockingBit === 0) { - assert(!isFirstPacket); - const newBlockingBit = bitstream.readBits(1); - if (newBlockingBit !== 0) { - return null; - } - } else { - throw new Error("Invalid blocking bit"); - } - const blockSizeOrUncommon = getBlockSizeOrUncommon(bitstream.readBits(4)); - if (!blockSizeOrUncommon) { - return null; - } - assert(this.audioInfo); - const sampleRateOrUncommon = getSampleRateOrUncommon(bitstream.readBits(4), this.audioInfo.sampleRate); - if (!sampleRateOrUncommon) { - return null; - } - bitstream.readBits(4); - bitstream.readBits(3); - const reservedZero = bitstream.readBits(1); - if (reservedZero !== 0) { - return null; - } - const num = readCodedNumber(slice); - const blockSize = readBlockSize(slice, blockSizeOrUncommon); - const sampleRate = readSampleRate(slice, sampleRateOrUncommon); - if (sampleRate === null) { - return null; - } - if (sampleRate !== this.audioInfo.sampleRate) { - return null; - } - const size = slice.filePos - startOffset; - const crc = readU8(slice); - slice.skip(-size); - slice.skip(-1); - const crcCalculated = calculateCrc8(readBytes(slice, size)); - if (crc !== crcCalculated) { - return null; - } - return { num, blockSize, sampleRate }; - } - async advanceReader() { - await this.readMetadata(); - assert(this.lastLoadedPos !== null); - assert(this.audioInfo); - const startPos = this.lastLoadedPos; - const frame = await this.readNextFlacFrame({ - startPos, - isFirstPacket: this.loadedSamples.length === 0 - }); - if (!frame) { - this.lastSampleLoaded = true; - return; - } - const lastSample = this.loadedSamples[this.loadedSamples.length - 1]; - const blockOffset = lastSample ? lastSample.blockOffset + lastSample.blockSize : 0; - const sample = { - blockOffset, - blockSize: frame.blockSize, - byteOffset: startPos, - byteSize: frame.size - }; - this.lastLoadedPos = this.lastLoadedPos + frame.size; - this.loadedSamples.push(sample); - if (frame.isLastFrame) { - this.lastSampleLoaded = true; - return; - } - } -} -class FlacAudioTrackBacking { - constructor(demuxer) { - this.demuxer = demuxer; - } - getId() { - return 1; - } - getCodec() { - return "flac"; - } - getInternalCodecId() { - return null; - } - getNumberOfChannels() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.numberOfChannels; - } - async computeDuration() { - const lastPacket = await this.getPacket(Infinity, { metadataOnly: true }); - return (lastPacket?.timestamp ?? 0) + (lastPacket?.duration ?? 0); - } - getSampleRate() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getName() { - return null; - } - getLanguageCode() { - return UNDETERMINED_LANGUAGE; - } - getTimeResolution() { - assert(this.demuxer.audioInfo); - return this.demuxer.audioInfo.sampleRate; - } - getDisposition() { - return { - ...DEFAULT_TRACK_DISPOSITION - }; - } - async getFirstTimestamp() { - return 0; - } - async getDecoderConfig() { - assert(this.demuxer.audioInfo); - return { - codec: "flac", - numberOfChannels: this.demuxer.audioInfo.numberOfChannels, - sampleRate: this.demuxer.audioInfo.sampleRate, - description: this.demuxer.audioInfo.description - }; - } - async getPacket(timestamp, options) { - assert(this.demuxer.audioInfo); - if (timestamp < 0) { - throw new Error("Timestamp cannot be negative"); - } - const release = await this.demuxer.readingMutex.acquire(); - try { - while (true) { - const packetIndex = binarySearchLessOrEqual(this.demuxer.loadedSamples, timestamp, (x) => x.blockOffset / this.demuxer.audioInfo.sampleRate); - if (packetIndex === -1) { - await this.demuxer.advanceReader(); - continue; - } - const packet = this.demuxer.loadedSamples[packetIndex]; - const sampleTimestamp = packet.blockOffset / this.demuxer.audioInfo.sampleRate; - const sampleDuration = packet.blockSize / this.demuxer.audioInfo.sampleRate; - if (sampleTimestamp + sampleDuration <= timestamp) { - if (this.demuxer.lastSampleLoaded) { - return this.getPacketAtIndex(this.demuxer.loadedSamples.length - 1, options); - } - await this.demuxer.advanceReader(); - continue; - } - return this.getPacketAtIndex(packetIndex, options); - } - } finally { - release(); - } - } - async getNextPacket(packet, options) { - const release = await this.demuxer.readingMutex.acquire(); - try { - const nextIndex = packet.sequenceNumber + 1; - if (this.demuxer.lastSampleLoaded && nextIndex >= this.demuxer.loadedSamples.length) { - return null; - } - while (nextIndex >= this.demuxer.loadedSamples.length && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(nextIndex, options); - } finally { - release(); - } - } - getKeyPacket(timestamp, options) { - return this.getPacket(timestamp, options); - } - getNextKeyPacket(packet, options) { - return this.getNextPacket(packet, options); - } - async getPacketAtIndex(sampleIndex, options) { - const rawSample = this.demuxer.loadedSamples[sampleIndex]; - if (!rawSample) { - return null; - } - let data; - if (options.metadataOnly) { - data = PLACEHOLDER_DATA; - } else { - let slice = this.demuxer.reader.requestSlice(rawSample.byteOffset, rawSample.byteSize); - if (slice instanceof Promise) - slice = await slice; - if (!slice) { - return null; - } - data = readBytes(slice, rawSample.byteSize); - } - assert(this.demuxer.audioInfo); - const timestamp = rawSample.blockOffset / this.demuxer.audioInfo.sampleRate; - const duration = rawSample.blockSize / this.demuxer.audioInfo.sampleRate; - return new EncodedPacket(data, "key", timestamp, duration, sampleIndex, rawSample.byteSize); - } - async getFirstPacket(options) { - while (this.demuxer.loadedSamples.length === 0 && !this.demuxer.lastSampleLoaded) { - await this.demuxer.advanceReader(); - } - return this.getPacketAtIndex(0, options); - } -} -class InputFormat { -} -class IsobmffInputFormat extends InputFormat { - /** @internal */ - async _getMajorBrand(input) { - let slice = input._reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return null; - slice.skip(4); - const fourCc = readAscii(slice, 4); - if (fourCc !== "ftyp") { - return null; - } - return readAscii(slice, 4); - } - /** @internal */ - _createDemuxer(input) { - return new IsobmffDemuxer(input); - } -} -class Mp4InputFormat extends IsobmffInputFormat { - /** @internal */ - async _canReadInput(input) { - const majorBrand = await this._getMajorBrand(input); - return !!majorBrand && majorBrand !== "qt "; - } - get name() { - return "MP4"; - } - get mimeType() { - return "video/mp4"; - } -} -class QuickTimeInputFormat extends IsobmffInputFormat { - /** @internal */ - async _canReadInput(input) { - const majorBrand = await this._getMajorBrand(input); - return majorBrand === "qt "; - } - get name() { - return "QuickTime File Format"; - } - get mimeType() { - return "video/quicktime"; - } -} -class MatroskaInputFormat extends InputFormat { - /** @internal */ - async isSupportedEBMLOfDocType(input, desiredDocType) { - let headerSlice = input._reader.requestSlice(0, MAX_HEADER_SIZE); - if (headerSlice instanceof Promise) - headerSlice = await headerSlice; - if (!headerSlice) - return false; - const varIntSize = readVarIntSize(headerSlice); - if (varIntSize === null) { - return false; - } - if (varIntSize < 1 || varIntSize > 8) { - return false; - } - const id = readUnsignedInt(headerSlice, varIntSize); - if (id !== EBMLId.EBML) { - return false; - } - const dataSize = readElementSize(headerSlice); - if (typeof dataSize !== "number") { - return false; - } - let dataSlice = input._reader.requestSlice(headerSlice.filePos, dataSize); - if (dataSlice instanceof Promise) - dataSlice = await dataSlice; - if (!dataSlice) - return false; - const startPos = headerSlice.filePos; - while (dataSlice.filePos <= startPos + dataSize - MIN_HEADER_SIZE) { - const header = readElementHeader(dataSlice); - if (!header) - break; - const { id: id2, size } = header; - const dataStartPos = dataSlice.filePos; - if (size === void 0) - return false; - switch (id2) { - case EBMLId.EBMLVersion: - { - const ebmlVersion = readUnsignedInt(dataSlice, size); - if (ebmlVersion !== 1) { - return false; - } - } - break; - case EBMLId.EBMLReadVersion: - { - const ebmlReadVersion = readUnsignedInt(dataSlice, size); - if (ebmlReadVersion !== 1) { - return false; - } - } - break; - case EBMLId.DocType: - { - const docType = readAsciiString(dataSlice, size); - if (docType !== desiredDocType) { - return false; - } - } - break; - case EBMLId.DocTypeVersion: - { - const docTypeVersion = readUnsignedInt(dataSlice, size); - if (docTypeVersion > 4) { - return false; - } - } - break; - } - dataSlice.filePos = dataStartPos + size; - } - return true; - } - /** @internal */ - _canReadInput(input) { - return this.isSupportedEBMLOfDocType(input, "matroska"); - } - /** @internal */ - _createDemuxer(input) { - return new MatroskaDemuxer(input); - } - get name() { - return "Matroska"; - } - get mimeType() { - return "video/x-matroska"; - } -} -class WebMInputFormat extends MatroskaInputFormat { - /** @internal */ - _canReadInput(input) { - return this.isSupportedEBMLOfDocType(input, "webm"); - } - get name() { - return "WebM"; - } - get mimeType() { - return "video/webm"; - } -} -class Mp3InputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 10); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - let currentPos = 0; - let id3V2HeaderFound = false; - while (true) { - let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE); - if (slice2 instanceof Promise) - slice2 = await slice2; - if (!slice2) - break; - const id3V2Header = readId3V2Header(slice2); - if (!id3V2Header) { - break; - } - id3V2HeaderFound = true; - currentPos = slice2.filePos + id3V2Header.size; - } - const firstResult = await readNextFrameHeader(input._reader, currentPos, currentPos + 4096); - if (!firstResult) { - return false; - } - if (id3V2HeaderFound) { - return true; - } - currentPos = firstResult.startPos + firstResult.header.totalSize; - const secondResult = await readNextFrameHeader(input._reader, currentPos, currentPos + FRAME_HEADER_SIZE); - if (!secondResult) { - return false; - } - const firstHeader = firstResult.header; - const secondHeader = secondResult.header; - if (firstHeader.channel !== secondHeader.channel || firstHeader.sampleRate !== secondHeader.sampleRate) { - return false; - } - return true; - } - /** @internal */ - _createDemuxer(input) { - return new Mp3Demuxer(input); - } - get name() { - return "MP3"; - } - get mimeType() { - return "audio/mpeg"; - } -} -class WaveInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 12); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const riffType = readAscii(slice, 4); - if (riffType !== "RIFF" && riffType !== "RIFX" && riffType !== "RF64") { - return false; - } - slice.skip(4); - const format = readAscii(slice, 4); - return format === "WAVE"; - } - /** @internal */ - _createDemuxer(input) { - return new WaveDemuxer(input); - } - get name() { - return "WAVE"; - } - get mimeType() { - return "audio/wav"; - } -} -class OggInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 4); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - return readAscii(slice, 4) === "OggS"; - } - /** @internal */ - _createDemuxer(input) { - return new OggDemuxer(input); - } - get name() { - return "Ogg"; - } - get mimeType() { - return "application/ogg"; - } -} -class FlacInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSlice(0, 4); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - return readAscii(slice, 4) === "fLaC"; - } - get name() { - return "FLAC"; - } - get mimeType() { - return "audio/flac"; - } - /** @internal */ - _createDemuxer(input) { - return new FlacDemuxer(input); - } -} -class AdtsInputFormat extends InputFormat { - /** @internal */ - async _canReadInput(input) { - let slice = input._reader.requestSliceRange(0, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const firstHeader = readFrameHeader(slice); - if (!firstHeader) { - return false; - } - slice = input._reader.requestSliceRange(firstHeader.frameLength, MIN_FRAME_HEADER_SIZE, MAX_FRAME_HEADER_SIZE); - if (slice instanceof Promise) - slice = await slice; - if (!slice) - return false; - const secondHeader = readFrameHeader(slice); - if (!secondHeader) { - return false; - } - return firstHeader.objectType === secondHeader.objectType && firstHeader.samplingFrequencyIndex === secondHeader.samplingFrequencyIndex && firstHeader.channelConfiguration === secondHeader.channelConfiguration; - } - /** @internal */ - _createDemuxer(input) { - return new AdtsDemuxer(input); - } - get name() { - return "ADTS"; - } - get mimeType() { - return "audio/aac"; - } -} -const MP4 = /* @__PURE__ */ new Mp4InputFormat(); -const QTFF = /* @__PURE__ */ new QuickTimeInputFormat(); -const MATROSKA = /* @__PURE__ */ new MatroskaInputFormat(); -const WEBM = /* @__PURE__ */ new WebMInputFormat(); -const MP3 = /* @__PURE__ */ new Mp3InputFormat(); -const WAVE = /* @__PURE__ */ new WaveInputFormat(); -const OGG = /* @__PURE__ */ new OggInputFormat(); -const ADTS = /* @__PURE__ */ new AdtsInputFormat(); -const FLAC = /* @__PURE__ */ new FlacInputFormat(); -const ALL_FORMATS = [MP4, QTFF, MATROSKA, WEBM, WAVE, OGG, FLAC, MP3, ADTS]; -class Source { - constructor() { - this._disposed = false; - this._sizePromise = null; - this.onread = null; - } - /** - * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call - * will retrieve the size. - * - * Returns null if the source is unsized. - */ - async getSizeOrNull() { - if (this._disposed) { - throw new InputDisposedError(); - } - return this._sizePromise ?? (this._sizePromise = Promise.resolve(this._retrieveSize())); - } - /** - * Resolves with the total size of the file in bytes. This function is memoized, meaning only the first call - * will retrieve the size. - * - * Throws an error if the source is unsized. - */ - async getSize() { - if (this._disposed) { - throw new InputDisposedError(); - } - const result = await this.getSizeOrNull(); - if (result === null) { - throw new Error("Cannot determine the size of an unsized source."); - } - return result; - } -} -class BlobSource extends Source { - /** - * Creates a new {@link BlobSource} backed by the specified - * [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). - */ - constructor(blob, options = {}) { - if (!(blob instanceof Blob)) { - throw new TypeError("blob must be a Blob."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - super(); - this._readers = /* @__PURE__ */ new WeakMap(); - this._blob = blob; - this._orchestrator = new ReadOrchestrator({ - maxCacheSize: options.maxCacheSize ?? 8 * 2 ** 20, - maxWorkerCount: 4, - runWorker: this._runWorker.bind(this), - prefetchProfile: PREFETCH_PROFILES.fileSystem - }); - } - /** @internal */ - _retrieveSize() { - const size = this._blob.size; - this._orchestrator.fileSize = size; - return size; - } - /** @internal */ - _read(start, end) { - return this._orchestrator.read(start, end); - } - /** @internal */ - async _runWorker(worker) { - let reader = this._readers.get(worker); - if (reader === void 0) { - if ("stream" in this._blob && !isWebKit()) { - const slice = this._blob.slice(worker.currentPos); - reader = slice.stream().getReader(); - } else { - reader = null; - } - this._readers.set(worker, reader); - } - while (worker.currentPos < worker.targetPos && !worker.aborted) { - if (reader) { - const { done, value } = await reader.read(); - if (done) { - this._orchestrator.forgetWorker(worker); - throw new Error("Blob reader stopped unexpectedly before all requested data was read."); - } - if (worker.aborted) { - break; - } - this.onread?.(worker.currentPos, worker.currentPos + value.length); - this._orchestrator.supplyWorkerData(worker, value); - } else { - const data = await this._blob.slice(worker.currentPos, worker.targetPos).arrayBuffer(); - if (worker.aborted) { - break; - } - this.onread?.(worker.currentPos, worker.currentPos + data.byteLength); - this._orchestrator.supplyWorkerData(worker, new Uint8Array(data)); - } - } - worker.running = false; - if (worker.aborted) { - await reader?.cancel(); - } - } - /** @internal */ - _dispose() { - this._orchestrator.dispose(); - } -} -const URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20; -const DEFAULT_RETRY_DELAY = ((previousAttempts, error, src) => { - const couldBeCorsError = error instanceof Error && (error.message.includes("Failed to fetch") || error.message.includes("Load failed") || error.message.includes("NetworkError when attempting to fetch resource")); - if (couldBeCorsError) { - let originOfSrc = null; - try { - if (typeof window !== "undefined" && typeof window.location !== "undefined") { - originOfSrc = new URL(src instanceof Request ? src.url : src, window.location.href).origin; - } - } catch { - } - const isOnline = typeof navigator !== "undefined" && typeof navigator.onLine === "boolean" ? navigator.onLine : true; - if (isOnline && originOfSrc !== null && originOfSrc !== window.location.origin) { - console.warn(`Request will not be retried because a CORS error was suspected due to different origins. You can modify this behavior by providing your own function for the 'getRetryDelay' option.`); - return null; - } - } - return Math.min(2 ** (previousAttempts - 2), 16); -}); -class UrlSource extends Source { - /** Creates a new {@link UrlSource} backed by the resource at the specified URL. */ - constructor(url, options = {}) { - if (typeof url !== "string" && !(url instanceof URL) && !(typeof Request !== "undefined" && url instanceof Request)) { - throw new TypeError("url must be a string, URL or Request."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.requestInit !== void 0 && (!options.requestInit || typeof options.requestInit !== "object")) { - throw new TypeError("options.requestInit, when provided, must be an object."); - } - if (options.getRetryDelay !== void 0 && typeof options.getRetryDelay !== "function") { - throw new TypeError("options.getRetryDelay, when provided, must be a function."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - if (options.fetchFn !== void 0 && typeof options.fetchFn !== "function") { - throw new TypeError("options.fetchFn, when provided, must be a function."); - } - super(); - this._existingResponses = /* @__PURE__ */ new WeakMap(); - this._url = url; - this._options = options; - this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY; - this._orchestrator = new ReadOrchestrator({ - maxCacheSize: options.maxCacheSize ?? 64 * 2 ** 20, - // Most files in the real-world have a single sequential access pattern, but having two in parallel can - // also happen - maxWorkerCount: 2, - runWorker: this._runWorker.bind(this), - prefetchProfile: PREFETCH_PROFILES.network - }); - } - /** @internal */ - async _retrieveSize() { - const abortController = new AbortController(); - const response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { - headers: { - // We could also send a non-range request to request the same bytes (all of them), but doing it like - // this is an easy way to check if the server supports range requests in the first place - Range: "bytes=0-" - }, - signal: abortController.signal - }), this._getRetryDelay, () => this._disposed); - if (!response.ok) { - throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); - } - let worker; - let fileSize; - if (response.status === 206) { - fileSize = this._getTotalLengthFromRangeResponse(response); - worker = this._orchestrator.createWorker(0, Math.min(fileSize, URL_SOURCE_MIN_LOAD_AMOUNT)); - } else { - const contentLength = response.headers.get("Content-Length"); - if (contentLength) { - fileSize = Number(contentLength); - worker = this._orchestrator.createWorker(0, fileSize); - this._orchestrator.options.maxCacheSize = Infinity; - console.warn("HTTP server did not respond with 206 Partial Content, meaning the entire remote resource now has to be downloaded. For efficient media file streaming across a network, please make sure your server supports range requests."); - } else { - throw new Error(`HTTP response (status ${response.status}) must surface Content-Length header.`); - } - } - this._orchestrator.fileSize = fileSize; - this._existingResponses.set(worker, { response, abortController }); - this._orchestrator.runWorker(worker); - return fileSize; - } - /** @internal */ - _read(start, end) { - return this._orchestrator.read(start, end); - } - /** @internal */ - async _runWorker(worker) { - while (true) { - const existing = this._existingResponses.get(worker); - this._existingResponses.delete(worker); - let abortController = existing?.abortController; - let response = existing?.response; - if (!abortController) { - abortController = new AbortController(); - response = await retriedFetch(this._options.fetchFn ?? fetch, this._url, mergeRequestInit(this._options.requestInit ?? {}, { - headers: { - Range: `bytes=${worker.currentPos}-` - }, - signal: abortController.signal - }), this._getRetryDelay, () => this._disposed); - } - assert(response); - if (!response.ok) { - throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`); - } - if (worker.currentPos > 0 && response.status !== 206) { - throw new Error("HTTP server did not respond with 206 Partial Content to a range request. To enable efficient media file streaming across a network, please make sure your server supports range requests."); - } - if (!response.body) { - throw new Error("Missing HTTP response body stream. The used fetch function must provide the response body as a ReadableStream."); - } - const reader = response.body.getReader(); - while (true) { - if (worker.currentPos >= worker.targetPos || worker.aborted) { - abortController.abort(); - worker.running = false; - return; - } - let readResult; - try { - readResult = await reader.read(); - } catch (error) { - if (this._disposed) { - throw error; - } - const retryDelayInSeconds = this._getRetryDelay(1, error, this._url); - if (retryDelayInSeconds !== null) { - console.error("Error while reading response stream. Attempting to resume.", error); - await new Promise((resolve) => setTimeout(resolve, 1e3 * retryDelayInSeconds)); - break; - } else { - throw error; - } - } - if (worker.aborted) { - continue; - } - const { done, value } = readResult; - if (done) { - if (worker.currentPos >= worker.targetPos) { - this._orchestrator.forgetWorker(worker); - worker.running = false; - return; - } - break; - } - this.onread?.(worker.currentPos, worker.currentPos + value.length); - this._orchestrator.supplyWorkerData(worker, value); - } - } - } - /** @internal */ - _getTotalLengthFromRangeResponse(response) { - const contentRange = response.headers.get("Content-Range"); - if (contentRange) { - const match = /\/(\d+)/.exec(contentRange); - if (match) { - return Number(match[1]); - } - } - const contentLength = response.headers.get("Content-Length"); - if (contentLength) { - return Number(contentLength); - } else { - throw new Error("Partial HTTP response (status 206) must surface either Content-Range or Content-Length header."); - } - } - /** @internal */ - _dispose() { - this._orchestrator.dispose(); - } -} -class ReadableStreamSource extends Source { - /** Creates a new {@link ReadableStreamSource} backed by the specified `ReadableStream`. */ - constructor(stream, options = {}) { - if (!(stream instanceof ReadableStream)) { - throw new TypeError("stream must be a ReadableStream."); - } - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (options.maxCacheSize !== void 0 && (!isNumber(options.maxCacheSize) || options.maxCacheSize < 0)) { - throw new TypeError("options.maxCacheSize, when provided, must be a non-negative number."); - } - super(); - this._reader = null; - this._cache = []; - this._pendingSlices = []; - this._currentIndex = 0; - this._targetIndex = 0; - this._maxRequestedIndex = 0; - this._endIndex = null; - this._pulling = false; - this._stream = stream; - this._maxCacheSize = options.maxCacheSize ?? 16 * 2 ** 20; - } - /** @internal */ - _retrieveSize() { - return this._endIndex; - } - /** @internal */ - _read(start, end) { - if (this._endIndex !== null && end > this._endIndex) { - return null; - } - this._maxRequestedIndex = Math.max(this._maxRequestedIndex, end); - const cacheStartIndex = binarySearchLessOrEqual(this._cache, start, (x) => x.start); - const cacheStartEntry = cacheStartIndex !== -1 ? this._cache[cacheStartIndex] : null; - if (cacheStartEntry && cacheStartEntry.start <= start && end <= cacheStartEntry.end) { - return { - bytes: cacheStartEntry.bytes, - view: cacheStartEntry.view, - offset: cacheStartEntry.start - }; - } - let lastEnd = start; - const bytes = new Uint8Array(end - start); - if (cacheStartIndex !== -1) { - for (let i = cacheStartIndex; i < this._cache.length; i++) { - const cacheEntry = this._cache[i]; - if (cacheEntry.start >= end) { - break; - } - const cappedStart = Math.max(start, cacheEntry.start); - if (cappedStart > lastEnd) { - this._throwDueToCacheMiss(); - } - const cappedEnd = Math.min(end, cacheEntry.end); - if (cappedStart < cappedEnd) { - bytes.set(cacheEntry.bytes.subarray(cappedStart - cacheEntry.start, cappedEnd - cacheEntry.start), cappedStart - start); - lastEnd = cappedEnd; - } - } - } - if (lastEnd === end) { - return { - bytes, - view: toDataView(bytes), - offset: start - }; - } - if (this._currentIndex > lastEnd) { - this._throwDueToCacheMiss(); - } - const { promise, resolve, reject } = promiseWithResolvers(); - this._pendingSlices.push({ - start, - end, - bytes, - resolve, - reject - }); - this._targetIndex = Math.max(this._targetIndex, end); - if (!this._pulling) { - this._pulling = true; - void this._pull().catch((error) => { - this._pulling = false; - if (this._pendingSlices.length > 0) { - this._pendingSlices.forEach((x) => x.reject(error)); - this._pendingSlices.length = 0; - } else { - throw error; - } - }); - } - return promise; - } - /** @internal */ - _throwDueToCacheMiss() { - throw new Error("Read is before the cached region. With ReadableStreamSource, you must access the data more sequentially or increase the size of its cache."); - } - /** @internal */ - async _pull() { - this._reader ?? (this._reader = this._stream.getReader()); - while (this._currentIndex < this._targetIndex && !this._disposed) { - const { done, value } = await this._reader.read(); - if (done) { - for (const pendingSlice of this._pendingSlices) { - pendingSlice.resolve(null); - } - this._pendingSlices.length = 0; - this._endIndex = this._currentIndex; - break; - } - const startIndex = this._currentIndex; - const endIndex = this._currentIndex + value.byteLength; - for (let i = 0; i < this._pendingSlices.length; i++) { - const pendingSlice = this._pendingSlices[i]; - const cappedStart = Math.max(startIndex, pendingSlice.start); - const cappedEnd = Math.min(endIndex, pendingSlice.end); - if (cappedStart < cappedEnd) { - pendingSlice.bytes.set(value.subarray(cappedStart - startIndex, cappedEnd - startIndex), cappedStart - pendingSlice.start); - if (cappedEnd === pendingSlice.end) { - pendingSlice.resolve({ - bytes: pendingSlice.bytes, - view: toDataView(pendingSlice.bytes), - offset: pendingSlice.start - }); - this._pendingSlices.splice(i, 1); - i--; - } - } - } - this._cache.push({ - start: startIndex, - end: endIndex, - bytes: value, - view: toDataView(value), - age: 0 - // Unused - }); - while (this._cache.length > 0) { - const firstEntry = this._cache[0]; - const distance = this._maxRequestedIndex - firstEntry.end; - if (distance <= this._maxCacheSize) { - break; - } - this._cache.shift(); - } - this._currentIndex += value.byteLength; - } - this._pulling = false; - } - /** @internal */ - _dispose() { - this._pendingSlices.length = 0; - this._cache.length = 0; - } -} -const PREFETCH_PROFILES = { - fileSystem: (start, end) => { - const padding = 2 ** 16; - start = Math.floor((start - padding) / padding) * padding; - end = Math.ceil((end + padding) / padding) * padding; - return { start, end }; - }, - network: (start, end, workers) => { - const paddingStart = 2 ** 16; - start = Math.max(0, Math.floor((start - paddingStart) / paddingStart) * paddingStart); - for (const worker of workers) { - const maxExtensionAmount = 8 * 2 ** 20; - const thresholdPoint = Math.max((worker.startPos + worker.targetPos) / 2, worker.targetPos - maxExtensionAmount); - if (closedIntervalsOverlap(start, end, thresholdPoint, worker.targetPos)) { - const size = worker.targetPos - worker.startPos; - const a = Math.ceil((size + 1) / maxExtensionAmount) * maxExtensionAmount; - const b = 2 ** Math.ceil(Math.log2(size + 1)); - const extent = Math.min(b, a); - end = Math.max(end, worker.startPos + extent); - } - } - end = Math.max(end, start + URL_SOURCE_MIN_LOAD_AMOUNT); - return { - start, - end - }; - } -}; -class ReadOrchestrator { - constructor(options) { - this.options = options; - this.fileSize = null; - this.nextAge = 0; - this.workers = []; - this.cache = []; - this.currentCacheSize = 0; - this.disposed = false; - } - read(innerStart, innerEnd) { - assert(this.fileSize !== null); - const prefetchRange = this.options.prefetchProfile(innerStart, innerEnd, this.workers); - const outerStart = Math.max(prefetchRange.start, 0); - const outerEnd = Math.min(prefetchRange.end, this.fileSize); - assert(outerStart <= innerStart && innerEnd <= outerEnd); - let result = null; - const innerCacheStartIndex = binarySearchLessOrEqual(this.cache, innerStart, (x) => x.start); - const innerStartEntry = innerCacheStartIndex !== -1 ? this.cache[innerCacheStartIndex] : null; - if (innerStartEntry && innerStartEntry.start <= innerStart && innerEnd <= innerStartEntry.end) { - innerStartEntry.age = this.nextAge++; - result = { - bytes: innerStartEntry.bytes, - view: innerStartEntry.view, - offset: innerStartEntry.start - }; - } - const outerCacheStartIndex = binarySearchLessOrEqual(this.cache, outerStart, (x) => x.start); - const bytes = result ? null : new Uint8Array(innerEnd - innerStart); - let contiguousBytesWriteEnd = 0; - let lastEnd = outerStart; - const outerHoles = []; - if (outerCacheStartIndex !== -1) { - for (let i = outerCacheStartIndex; i < this.cache.length; i++) { - const entry = this.cache[i]; - if (entry.start >= outerEnd) { - break; - } - if (entry.end <= outerStart) { - continue; - } - const cappedOuterStart = Math.max(outerStart, entry.start); - const cappedOuterEnd = Math.min(outerEnd, entry.end); - assert(cappedOuterStart <= cappedOuterEnd); - if (lastEnd < cappedOuterStart) { - outerHoles.push({ start: lastEnd, end: cappedOuterStart }); - } - lastEnd = cappedOuterEnd; - if (bytes) { - const cappedInnerStart = Math.max(innerStart, entry.start); - const cappedInnerEnd = Math.min(innerEnd, entry.end); - if (cappedInnerStart < cappedInnerEnd) { - const relativeOffset = cappedInnerStart - innerStart; - bytes.set(entry.bytes.subarray(cappedInnerStart - entry.start, cappedInnerEnd - entry.start), relativeOffset); - if (relativeOffset === contiguousBytesWriteEnd) { - contiguousBytesWriteEnd = cappedInnerEnd - innerStart; - } - } - } - entry.age = this.nextAge++; - } - if (lastEnd < outerEnd) { - outerHoles.push({ start: lastEnd, end: outerEnd }); - } - } else { - outerHoles.push({ start: outerStart, end: outerEnd }); - } - if (bytes && contiguousBytesWriteEnd >= bytes.length) { - result = { - bytes, - view: toDataView(bytes), - offset: innerStart - }; - } - if (outerHoles.length === 0) { - assert(result); - return result; - } - const { promise, resolve, reject } = promiseWithResolvers(); - const innerHoles = []; - for (const outerHole of outerHoles) { - const cappedStart = Math.max(innerStart, outerHole.start); - const cappedEnd = Math.min(innerEnd, outerHole.end); - if (cappedStart === outerHole.start && cappedEnd === outerHole.end) { - innerHoles.push(outerHole); - } else if (cappedStart < cappedEnd) { - innerHoles.push({ start: cappedStart, end: cappedEnd }); - } - } - for (const outerHole of outerHoles) { - const pendingSlice = bytes && { - start: innerStart, - bytes, - holes: innerHoles, - resolve, - reject - }; - let workerFound = false; - for (const worker of this.workers) { - const gapTolerance = 2 ** 17; - if (closedIntervalsOverlap(outerHole.start - gapTolerance, outerHole.start, worker.currentPos, worker.targetPos)) { - worker.targetPos = Math.max(worker.targetPos, outerHole.end); - workerFound = true; - if (pendingSlice && !worker.pendingSlices.includes(pendingSlice)) { - worker.pendingSlices.push(pendingSlice); - } - if (!worker.running) { - this.runWorker(worker); - } - break; - } - } - if (!workerFound) { - const newWorker = this.createWorker(outerHole.start, outerHole.end); - if (pendingSlice) { - newWorker.pendingSlices = [pendingSlice]; - } - this.runWorker(newWorker); - } - } - if (!result) { - assert(bytes); - result = promise.then((bytes2) => ({ - bytes: bytes2, - view: toDataView(bytes2), - offset: innerStart - })); - } - return result; - } - createWorker(startPos, targetPos) { - const worker = { - startPos, - currentPos: startPos, - targetPos, - running: false, - // Due to async shenanigans, it can happen that workers are started after disposal. In this case, instead of - // simply not creating the worker, we allow it to run but immediately label it as aborted, so it can then - // shut itself down. - aborted: this.disposed, - pendingSlices: [], - age: this.nextAge++ - }; - this.workers.push(worker); - while (this.workers.length > this.options.maxWorkerCount) { - let oldestIndex = 0; - let oldestWorker = this.workers[0]; - for (let i = 1; i < this.workers.length; i++) { - const worker2 = this.workers[i]; - if (worker2.age < oldestWorker.age) { - oldestIndex = i; - oldestWorker = worker2; - } - } - if (oldestWorker.running && oldestWorker.pendingSlices.length > 0) { - break; - } - oldestWorker.aborted = true; - this.workers.splice(oldestIndex, 1); - } - return worker; - } - runWorker(worker) { - assert(!worker.running); - assert(worker.currentPos < worker.targetPos); - worker.running = true; - worker.age = this.nextAge++; - void this.options.runWorker(worker).catch((error) => { - worker.running = false; - if (worker.pendingSlices.length > 0) { - worker.pendingSlices.forEach((x) => x.reject(error)); - worker.pendingSlices.length = 0; - } else { - throw error; - } - }); - } - /** Called by a worker when it has read some data. */ - supplyWorkerData(worker, bytes) { - assert(!worker.aborted); - const start = worker.currentPos; - const end = start + bytes.length; - this.insertIntoCache({ - start, - end, - bytes, - view: toDataView(bytes), - age: this.nextAge++ - }); - worker.currentPos += bytes.length; - worker.targetPos = Math.max(worker.targetPos, worker.currentPos); - for (let i = 0; i < worker.pendingSlices.length; i++) { - const pendingSlice = worker.pendingSlices[i]; - const clampedStart = Math.max(start, pendingSlice.start); - const clampedEnd = Math.min(end, pendingSlice.start + pendingSlice.bytes.length); - if (clampedStart < clampedEnd) { - pendingSlice.bytes.set(bytes.subarray(clampedStart - start, clampedEnd - start), clampedStart - pendingSlice.start); - } - for (let j = 0; j < pendingSlice.holes.length; j++) { - const hole = pendingSlice.holes[j]; - if (start <= hole.start && end > hole.start) { - hole.start = end; - } - if (hole.end <= hole.start) { - pendingSlice.holes.splice(j, 1); - j--; - } - } - if (pendingSlice.holes.length === 0) { - pendingSlice.resolve(pendingSlice.bytes); - worker.pendingSlices.splice(i, 1); - i--; - } - } - for (let i = 0; i < this.workers.length; i++) { - const otherWorker = this.workers[i]; - if (worker === otherWorker || otherWorker.running) { - continue; - } - if (closedIntervalsOverlap(start, end, otherWorker.currentPos, otherWorker.targetPos)) { - this.workers.splice(i, 1); - i--; - } - } - } - forgetWorker(worker) { - const index = this.workers.indexOf(worker); - assert(index !== -1); - this.workers.splice(index, 1); - } - insertIntoCache(entry) { - if (this.options.maxCacheSize === 0) { - return; - } - let insertionIndex = binarySearchLessOrEqual(this.cache, entry.start, (x) => x.start) + 1; - if (insertionIndex > 0) { - const previous = this.cache[insertionIndex - 1]; - if (previous.end >= entry.end) { - return; - } - if (previous.end > entry.start) { - const joined = new Uint8Array(entry.end - previous.start); - joined.set(previous.bytes, 0); - joined.set(entry.bytes, entry.start - previous.start); - this.currentCacheSize += entry.end - previous.end; - previous.bytes = joined; - previous.view = toDataView(joined); - previous.end = entry.end; - insertionIndex--; - entry = previous; - } else { - this.cache.splice(insertionIndex, 0, entry); - this.currentCacheSize += entry.bytes.length; - } - } else { - this.cache.splice(insertionIndex, 0, entry); - this.currentCacheSize += entry.bytes.length; - } - for (let i = insertionIndex + 1; i < this.cache.length; i++) { - const next = this.cache[i]; - if (entry.end <= next.start) { - break; - } - if (entry.end >= next.end) { - this.cache.splice(i, 1); - this.currentCacheSize -= next.bytes.length; - i--; - continue; - } - const joined = new Uint8Array(next.end - entry.start); - joined.set(entry.bytes, 0); - joined.set(next.bytes, next.start - entry.start); - this.currentCacheSize -= entry.end - next.start; - entry.bytes = joined; - entry.view = toDataView(joined); - entry.end = next.end; - this.cache.splice(i, 1); - break; - } - while (this.currentCacheSize > this.options.maxCacheSize) { - let oldestIndex = 0; - let oldestEntry = this.cache[0]; - for (let i = 1; i < this.cache.length; i++) { - const entry2 = this.cache[i]; - if (entry2.age < oldestEntry.age) { - oldestIndex = i; - oldestEntry = entry2; - } - } - if (this.currentCacheSize - oldestEntry.bytes.length <= this.options.maxCacheSize) { - break; - } - this.cache.splice(oldestIndex, 1); - this.currentCacheSize -= oldestEntry.bytes.length; - } - } - dispose() { - for (const worker of this.workers) { - worker.aborted = true; - } - this.workers.length = 0; - this.cache.length = 0; - this.disposed = true; - } -} -polyfillSymbolDispose(); -class Input { - /** True if the input has been disposed. */ - get disposed() { - return this._disposed; - } - /** - * Creates a new input file from the specified options. No reading operations will be performed until methods are - * called on this instance. - */ - constructor(options) { - this._demuxerPromise = null; - this._format = null; - this._disposed = false; - if (!options || typeof options !== "object") { - throw new TypeError("options must be an object."); - } - if (!Array.isArray(options.formats) || options.formats.some((x) => !(x instanceof InputFormat))) { - throw new TypeError("options.formats must be an array of InputFormat."); - } - if (!(options.source instanceof Source)) { - throw new TypeError("options.source must be a Source."); - } - if (options.source._disposed) { - throw new Error("options.source must not be disposed."); - } - this._formats = options.formats; - this._source = options.source; - this._reader = new Reader(options.source); - } - /** @internal */ - _getDemuxer() { - return this._demuxerPromise ?? (this._demuxerPromise = (async () => { - this._reader.fileSize = await this._source.getSizeOrNull(); - for (const format of this._formats) { - const canRead = await format._canReadInput(this); - if (canRead) { - this._format = format; - return format._createDemuxer(this); - } - } - throw new Error("Input has an unsupported or unrecognizable format."); - })()); - } - /** - * Returns the source from which this input file reads its data. This is the same source that was passed to the - * constructor. - */ - get source() { - return this._source; - } - /** - * Returns the format of the input file. You can compare this result directly to the {@link InputFormat} singletons - * or use `instanceof` checks for subset-aware logic (for example, `format instanceof MatroskaInputFormat` is true - * for both MKV and WebM). - */ - async getFormat() { - await this._getDemuxer(); - assert(this._format); - return this._format; - } - /** - * Computes the duration of the input file, in seconds. More precisely, returns the largest end timestamp among - * all tracks. - */ - async computeDuration() { - const demuxer = await this._getDemuxer(); - return demuxer.computeDuration(); - } - /** Returns the list of all tracks of this input file. */ - async getTracks() { - const demuxer = await this._getDemuxer(); - return demuxer.getTracks(); - } - /** Returns the list of all video tracks of this input file. */ - async getVideoTracks() { - const tracks = await this.getTracks(); - return tracks.filter((x) => x.isVideoTrack()); - } - /** Returns the list of all audio tracks of this input file. */ - async getAudioTracks() { - const tracks = await this.getTracks(); - return tracks.filter((x) => x.isAudioTrack()); - } - /** Returns the primary video track of this input file, or null if there are no video tracks. */ - async getPrimaryVideoTrack() { - const tracks = await this.getTracks(); - return tracks.find((x) => x.isVideoTrack()) ?? null; - } - /** Returns the primary audio track of this input file, or null if there are no audio tracks. */ - async getPrimaryAudioTrack() { - const tracks = await this.getTracks(); - return tracks.find((x) => x.isAudioTrack()) ?? null; - } - /** Returns the full MIME type of this input file, including track codecs. */ - async getMimeType() { - const demuxer = await this._getDemuxer(); - return demuxer.getMimeType(); - } - /** - * Returns descriptive metadata tags about the media file, such as title, author, date, cover art, or other - * attached files. - */ - async getMetadataTags() { - const demuxer = await this._getDemuxer(); - return demuxer.getMetadataTags(); - } - /** - * Disposes this input and frees connected resources. When an input is disposed, ongoing read operations will be - * canceled, all future read operations will fail, any open decoders will be closed, and all ongoing media sink - * operations will be canceled. Disallowed and canceled operations will throw an {@link InputDisposedError}. - * - * You are expected not to use an input after disposing it. While some operations may still work, it is not - * specified and may change in any future update. - */ - dispose() { - if (this._disposed) { - return; - } - this._disposed = true; - this._source._disposed = true; - this._source._dispose(); - } - /** - * Calls `.dispose()` on the input, implementing the `Disposable` interface for use with - * JavaScript Explicit Resource Management features. - */ - [Symbol.dispose]() { - this.dispose(); - } -} -class InputDisposedError extends Error { - /** Creates a new {@link InputDisposedError}. */ - constructor(message = "Input has been disposed.") { - super(message); - this.name = "InputDisposedError"; - } -} -class Reader { - constructor(source) { - this.source = source; - } - requestSlice(start, length) { - if (this.source._disposed) { - throw new InputDisposedError(); - } - if (this.fileSize !== null && start + length > this.fileSize) { - return null; - } - const end = start + length; - const result = this.source._read(start, end); - if (result instanceof Promise) { - return result.then((x) => { - if (!x) { - return null; - } - return new FileSlice(x.bytes, x.view, x.offset, start, end); - }); - } else { - if (!result) { - return null; - } - return new FileSlice(result.bytes, result.view, result.offset, start, end); - } - } - requestSliceRange(start, minLength, maxLength) { - if (this.source._disposed) { - throw new InputDisposedError(); - } - if (this.fileSize !== null) { - return this.requestSlice(start, clamp$1(this.fileSize - start, minLength, maxLength)); - } else { - const promisedAttempt = this.requestSlice(start, maxLength); - const handleAttempt = (attempt) => { - if (attempt) { - return attempt; - } - const handleFileSize = (fileSize) => { - assert(fileSize !== null); - return this.requestSlice(start, clamp$1(fileSize - start, minLength, maxLength)); - }; - const promisedFileSize = this.source._retrieveSize(); - if (promisedFileSize instanceof Promise) { - return promisedFileSize.then(handleFileSize); - } else { - return handleFileSize(promisedFileSize); - } - }; - if (promisedAttempt instanceof Promise) { - return promisedAttempt.then(handleAttempt); - } else { - return handleAttempt(promisedAttempt); - } - } - } -} -class FileSlice { - constructor(bytes, view, offset, start, end) { - this.bytes = bytes; - this.view = view; - this.offset = offset; - this.start = start; - this.end = end; - this.bufferPos = start - offset; - } - static tempFromBytes(bytes) { - return new FileSlice(bytes, toDataView(bytes), 0, 0, bytes.length); - } - get length() { - return this.end - this.start; - } - get filePos() { - return this.offset + this.bufferPos; - } - set filePos(value) { - this.bufferPos = value - this.offset; - } - /** The number of bytes left from the current pos to the end of the slice. */ - get remainingLength() { - return Math.max(this.end - this.filePos, 0); - } - skip(byteCount) { - this.bufferPos += byteCount; - } - /** Creates a new subslice of this slice whose byte range must be contained within this slice. */ - slice(filePos, length = this.end - filePos) { - if (filePos < this.start || filePos + length > this.end) { - throw new RangeError("Slicing outside of original slice."); - } - return new FileSlice(this.bytes, this.view, this.offset, filePos, filePos + length); - } -} -const checkIsInRange = (slice, bytesToRead) => { - if (slice.filePos < slice.start || slice.filePos + bytesToRead > slice.end) { - throw new RangeError(`Tried reading [${slice.filePos}, ${slice.filePos + bytesToRead}), but slice is [${slice.start}, ${slice.end}). This is likely an internal error, please report it alongside the file that caused it.`); - } -}; -const readBytes = (slice, length) => { - checkIsInRange(slice, length); - const bytes = slice.bytes.subarray(slice.bufferPos, slice.bufferPos + length); - slice.bufferPos += length; - return bytes; -}; -const readU8 = (slice) => { - checkIsInRange(slice, 1); - return slice.view.getUint8(slice.bufferPos++); -}; -const readU16 = (slice, littleEndian) => { - checkIsInRange(slice, 2); - const value = slice.view.getUint16(slice.bufferPos, littleEndian); - slice.bufferPos += 2; - return value; -}; -const readU16Be = (slice) => { - checkIsInRange(slice, 2); - const value = slice.view.getUint16(slice.bufferPos, false); - slice.bufferPos += 2; - return value; -}; -const readU24Be = (slice) => { - checkIsInRange(slice, 3); - const value = getUint24(slice.view, slice.bufferPos, false); - slice.bufferPos += 3; - return value; -}; -const readI16Be = (slice) => { - checkIsInRange(slice, 2); - const value = slice.view.getInt16(slice.bufferPos, false); - slice.bufferPos += 2; - return value; -}; -const readU32 = (slice, littleEndian) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, littleEndian); - slice.bufferPos += 4; - return value; -}; -const readU32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; -}; -const readU32Le = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getUint32(slice.bufferPos, true); - slice.bufferPos += 4; - return value; -}; -const readI32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getInt32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; -}; -const readI32Le = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getInt32(slice.bufferPos, true); - slice.bufferPos += 4; - return value; -}; -const readU64 = (slice, littleEndian) => { - let low; - let high; - if (littleEndian) { - low = readU32(slice, true); - high = readU32(slice, true); - } else { - high = readU32(slice, false); - low = readU32(slice, false); - } - return high * 4294967296 + low; -}; -const readU64Be = (slice) => { - const high = readU32Be(slice); - const low = readU32Be(slice); - return high * 4294967296 + low; -}; -const readI64Be = (slice) => { - const high = readI32Be(slice); - const low = readU32Be(slice); - return high * 4294967296 + low; -}; -const readI64Le = (slice) => { - const low = readU32Le(slice); - const high = readI32Le(slice); - return high * 4294967296 + low; -}; -const readF32Be = (slice) => { - checkIsInRange(slice, 4); - const value = slice.view.getFloat32(slice.bufferPos, false); - slice.bufferPos += 4; - return value; -}; -const readF64Be = (slice) => { - checkIsInRange(slice, 8); - const value = slice.view.getFloat64(slice.bufferPos, false); - slice.bufferPos += 8; - return value; -}; -const readAscii = (slice, length) => { - checkIsInRange(slice, length); - let str = ""; - for (let i = 0; i < length; i++) { - str += String.fromCharCode(slice.bytes[slice.bufferPos++]); - } - return str; -}; class AudioEngine { constructor(events) { this.events = events; @@ -14476,16 +21254,6 @@ class AudioEngine { return this.playbackTimeAtStart; return (this.audioContext.currentTime - this.audioContextStartTime) * this.playbackRate + this.playbackTimeAtStart; } - normalizeSource(src) { - if (typeof src === "string") - return new UrlSource(src); - if (src instanceof Blob) - return new BlobSource(src); - if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { - return new ReadableStreamSource(src); - } - return src; - } ensureAudioContext(sampleRate) { if (this.audioContext) return; @@ -14513,27 +21281,22 @@ class AudioEngine { await this.audioIterator?.return(); this.audioIterator = null; } - async load(src, onMetadata) { - const id = ++this.asyncId; + handleNoAudioTrack() { + this.audioSink = null; + this.ensureAudioContext(); + } + async load(media, onMetadata) { + ++this.asyncId; await this.stopIterator(); this.stopQueuedNodes(); this.paused = true; this.playbackTimeAtStart = 0; this.audioContextStartTime = 0; - const source = this.normalizeSource(src); - if (!source) - return; - this.input = new Input({ - source, - formats: ALL_FORMATS - }); - this.duration = await this.input.computeDuration(); - if (id !== this.asyncId) - return; - const audioTrack = await this.input.getPrimaryAudioTrack(); + const { input, audioTrack, duration } = media; + this.input = input; + this.duration = duration; if (!audioTrack) { - this.audioSink = null; - this.ensureAudioContext(); + this.handleNoAudioTrack(); onMetadata?.(); return; } @@ -14666,6 +21429,99 @@ class AudioEngine { this.audioSink = null; } } +const M3U8_RE = /\.m3u8(?:$|[?#])/i; +function isHlsSource(src) { + return typeof src === "string" && M3U8_RE.test(src); +} +function normalizeSource(src) { + if (typeof src === "string") + return new UrlSource(src); + if (src instanceof Blob) + return new BlobSource(src); + if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { + return new ReadableStreamSource(src); + } + return src ?? null; +} +function createInput(src) { + const source = normalizeSource(src); + if (!source) + return null; + return new Input({ + source, + formats: isHlsSource(src) ? HLS_FORMATS : ALL_FORMATS + }); +} +async function resolveDuration({ input, videoTrack, audioTrack }) { + const tracks = [videoTrack, audioTrack].filter(Boolean); + const referenceTrack = videoTrack || audioTrack; + const isLive = Boolean(referenceTrack && await referenceTrack.isLive()); + let duration = Number.NaN; + if (tracks.length > 0) { + duration = await input.getDurationFromMetadata(tracks, { skipLiveWait: true }); + if (duration === null && !isLive) { + duration = await input.computeDuration(tracks, { skipLiveWait: true }); + } + } + return isLive ? Number.POSITIVE_INFINITY : duration ?? Number.NaN; +} +async function selectPlaybackTracks(input, src) { + const videoTrack = await input.getPrimaryVideoTrack(); + const audioTrack = videoTrack ? await videoTrack.getPrimaryPairableAudioTrack() : await input.getPrimaryAudioTrack(); + const duration = await resolveDuration({ input, videoTrack, audioTrack }); + return { + input, + videoTrack, + audioTrack, + duration, + isLive: Number.isFinite(duration) ? false : Boolean((videoTrack || audioTrack) && await (videoTrack || audioTrack).isLive()), + isHls: isHlsSource(src), + videoMode: isHlsSource(src) ? "auto" : "manual", + audioMode: isHlsSource(src) ? "auto" : "manual" + }; +} +async function getTrackBitrate(track) { + return await track.getAverageBitrate() ?? await track.getBitrate() ?? 0; +} +async function getHlsState(media) { + if (!media?.isHls || !media.input) + return null; + const [videoTracks, pairableAudioTracks] = await Promise.all([ + media.input.getVideoTracks(), + media.videoTrack ? media.videoTrack.getPairableAudioTracks() : [] + ]); + const [levels, audios] = await Promise.all([ + Promise.all(videoTracks.map(async (track, index) => ({ + id: track.id, + track, + index, + name: await track.getName(), + height: await track.getDisplayHeight(), + bitrate: await getTrackBitrate(track) + }))), + Promise.all(pairableAudioTracks.map(async (track, index) => { + const name = await track.getName(); + const language = await track.getLanguageCode(); + return { + id: track.id, + track, + index, + name, + lang: language, + language, + bitrate: await getTrackBitrate(track) + }; + })) + ]); + return { + levels, + audios, + currentLevel: media.videoTrack ? levels.find((item) => item.id === media.videoTrack.id) ?? null : null, + currentAudio: media.audioTrack ? audios.find((item) => item.id === media.audioTrack.id) ?? null : null, + videoMode: media.videoMode ?? "auto", + audioMode: media.audioMode ?? "auto" + }; +} class VideoEngine { constructor({ canvas, @@ -14701,18 +21557,8 @@ class VideoEngine { this.posterDrawn = false; this.isFetching = false; } - normalizeSource(src) { - if (typeof src === "string") - return new UrlSource(src); - if (src instanceof Blob) - return new BlobSource(src); - if (typeof ReadableStream !== "undefined" && src instanceof ReadableStream) { - return new ReadableStreamSource(src); - } - return src; - } async preflight(url) { - if (!this.preflightRange || typeof url !== "string") + if (!this.preflightRange || typeof url !== "string" || isHlsSource(url)) return true; try { const res = await fetch(url, { method: "HEAD" }); @@ -14747,26 +21593,14 @@ class VideoEngine { clear() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); } - async load(src, onMetadata) { - const id = ++this.asyncId; + async load(media, onMetadata) { + ++this.asyncId; await this.stopIterator(); this.clear(); this.posterDrawn = false; - if (!await this.preflight(src)) - return; - const source = this.normalizeSource(src); - if (!source) { - this.drawPoster(); - return; - } - this.input = new Input({ - source, - formats: ALL_FORMATS - }); - this.duration = await this.input.computeDuration(); - if (id !== this.asyncId) - return; - const videoTrack = await this.input.getPrimaryVideoTrack(); + const { input, videoTrack, duration } = media; + this.input = input; + this.duration = duration; if (!videoTrack) { this.handleNoVideoTrack(); onMetadata?.(); @@ -14809,7 +21643,6 @@ class VideoEngine { this.nextFrame = second; if (first) { this.ctx.drawImage(first.canvas, 0, 0); - this.events.emit("loadeddata"); } else { this.drawPoster(); } @@ -14902,8 +21735,8 @@ class VideoEngine { this.stop(); this.stopIterator(); this.posterDrawn = false; - this.input = null; this.videoSink = null; + this.input = null; } } class MediaBunnyEngine { @@ -14928,6 +21761,8 @@ class MediaBunnyEngine { this.error = null; this.seeking = false; this.loadSeq = 0; + this.input = null; + this.media = null; events.addEventListener?.("ended", () => { this.ended = true; this.paused = true; @@ -14936,6 +21771,7 @@ class MediaBunnyEngine { async load(src) { const id = ++this.loadSeq; this.pause(); + this.disposeInput(); this.ended = false; this.error = null; this.networkState = 2; @@ -14959,8 +21795,24 @@ class MediaBunnyEngine { } } async performLoad(src, id) { - let videoMetadataLoaded = false; - let audioMetadataLoaded = false; + if (!await this.video.preflight(src)) + return; + const input = createInput(src); + if (!input) { + this.video.handleNoVideoTrack(); + this.audio.handleNoAudioTrack(); + return; + } + const media = await selectPlaybackTracks(input, src); + if (id !== this.loadSeq) { + input.dispose(); + return; + } + this.disposeInput(); + this.input = input; + this.media = media; + let videoMetadataLoaded = !media.videoTrack; + let audioMetadataLoaded = !media.audioTrack; const checkMetadata = () => { if (videoMetadataLoaded && audioMetadataLoaded) { this.readyState = 1; @@ -14971,13 +21823,13 @@ class MediaBunnyEngine { }; try { await Promise.all([ - this.video.load(src, () => { + this.video.load(media, () => { if (id !== this.loadSeq) return; videoMetadataLoaded = true; checkMetadata(); }), - this.audio.load(src, () => { + this.audio.load(media, () => { if (id !== this.loadSeq) return; audioMetadataLoaded = true; @@ -15006,6 +21858,95 @@ class MediaBunnyEngine { setTimeout(() => reject(new Error("Load timeout")), ms); }); } + disposeInput() { + this.input?.dispose(); + this.input = null; + this.media = null; + } + async replaceTracks({ videoTrack, audioTrack, videoMode, audioMode }) { + if (!this.media) + return; + const nextMedia = { + ...this.media, + videoTrack, + audioTrack, + videoMode, + audioMode + }; + const shouldResume = !this.paused; + const currentTime = this.currentTime; + this.pause(); + this.ended = false; + this.seeking = true; + this.events.emit("seeking"); + this.events.emit("waiting"); + nextMedia.duration = await resolveDuration(nextMedia); + this.media = nextMedia; + await Promise.all([ + this.video.load(nextMedia), + this.audio.load(nextMedia) + ]); + await Promise.all([ + this.video.seek(currentTime), + this.audio.seek(currentTime) + ]); + this.readyState = 4; + this.networkState = 1; + this.seeking = false; + this.events.emit("loadedmetadata"); + this.events.emit("durationchange"); + this.events.emit("progress"); + this.events.emit("loadeddata"); + this.events.emit("canplay"); + this.events.emit("canplaythrough"); + this.events.emit("seeked"); + if (shouldResume) { + await this.play(); + } + } + async selectHlsQuality(value) { + if (!this.media?.isHls || !this.input) + return; + const videoTracks = await this.input.getVideoTracks(); + const videoTrack = value === "auto" ? await this.input.getPrimaryVideoTrack() : videoTracks.find((track) => track.id === value) ?? this.media.videoTrack; + if (!videoTrack) + return; + let audioTrack = this.media.audioTrack; + let audioMode = this.media.audioMode; + if (!audioTrack || !videoTrack.canBePairedWith(audioTrack)) { + audioTrack = await videoTrack.getPrimaryPairableAudioTrack(); + audioMode = "auto"; + } + await this.replaceTracks({ + videoTrack, + audioTrack, + videoMode: value === "auto" ? "auto" : "manual", + audioMode + }); + } + async selectHlsAudio(value) { + if (!this.media?.isHls || !this.input) + return; + const audioTracks = await this.input.getAudioTracks(); + const audioTrack = value === "auto" ? this.media.videoTrack ? await this.media.videoTrack.getPrimaryPairableAudioTrack() : await this.input.getPrimaryAudioTrack() : audioTracks.find((track) => track.id === value) ?? this.media.audioTrack; + if (!audioTrack) + return; + let videoTrack = this.media.videoTrack; + let videoMode = this.media.videoMode; + if (!videoTrack || !audioTrack.canBePairedWith(videoTrack)) { + videoTrack = await audioTrack.getPrimaryPairableVideoTrack(); + videoMode = "auto"; + } + await this.replaceTracks({ + videoTrack, + audioTrack, + videoMode, + audioMode: value === "auto" ? "auto" : "manual" + }); + } + getHlsState() { + return getHlsState(this.media); + } async play() { if (!this.paused) return; @@ -15053,6 +21994,7 @@ class MediaBunnyEngine { } destroy() { this.pause(); + this.disposeInput(); this.audio.destroy(); this.video.destroy(); } @@ -15061,7 +22003,7 @@ class MediaBunnyEngine { return this.audio.currentTime; } get duration() { - return this.audio.duration || this.video.duration; + return this.media?.duration ?? this.audio.duration ?? this.video.duration; } get videoWidth() { return this.video.width; @@ -15214,6 +22156,15 @@ class VideoShim { if (this._src) this.engine.load(this._src); } + getM3u8State() { + return this.engine.getHlsState(); + } + switchM3u8Quality(value) { + return this.engine.selectHlsQuality(value); + } + switchM3u8Audio(value) { + return this.engine.selectHlsAudio(value); + } // Video dimensions get videoWidth() { return this.engine.videoWidth; @@ -15324,6 +22275,7 @@ function artplayerProxyMediabunny(option = {}) { ctx, option }); + art.mediabunny = shim; const originalCanvasMethods = {}; for (const prop in canvas) { if (typeof canvas[prop] === "function") { @@ -15366,7 +22318,9 @@ function artplayerProxyMediabunny(option = {}) { } art.on("resize", resize); art.on("video:loadedmetadata", resize); + setupM3u8Controls({ art, shim, option }); art.on("destroy", () => { + delete art.mediabunny; shim.destroy(); }); return canvas; diff --git a/packages/artplayer-proxy-mediabunny/package.json b/packages/artplayer-proxy-mediabunny/package.json index 97d0e3d8a..85e81e67e 100644 --- a/packages/artplayer-proxy-mediabunny/package.json +++ b/packages/artplayer-proxy-mediabunny/package.json @@ -1,6 +1,6 @@ { "name": "artplayer-proxy-mediabunny", - "version": "1.1.0", + "version": "1.2.0", "description": "mediabunny proxy for ArtPlayer", "author": "Harvey Zhao ", "license": "MIT", @@ -35,6 +35,6 @@ "legacy": "./dist/artplayer-proxy-mediabunny.legacy.js", "browserslist": "last 1 Chrome version", "dependencies": { - "mediabunny": "^1.27.3" + "mediabunny": "^1.43.1" } } diff --git a/packages/artplayer-proxy-mediabunny/src/AudioEngine.js b/packages/artplayer-proxy-mediabunny/src/AudioEngine.js index 129bc9282..b6b4240dd 100644 --- a/packages/artplayer-proxy-mediabunny/src/AudioEngine.js +++ b/packages/artplayer-proxy-mediabunny/src/AudioEngine.js @@ -3,12 +3,7 @@ * Handles audio playback using Web Audio API */ import { - ALL_FORMATS, AudioBufferSink, - BlobSource, - Input, - ReadableStreamSource, - UrlSource, } from 'mediabunny' export default class AudioEngine { @@ -51,17 +46,6 @@ export default class AudioEngine { ) } - normalizeSource(src) { - if (typeof src === 'string') - return new UrlSource(src) - if (src instanceof Blob) - return new BlobSource(src) - if (typeof ReadableStream !== 'undefined' && src instanceof ReadableStream) { - return new ReadableStreamSource(src) - } - return src - } - ensureAudioContext(sampleRate) { if (this.audioContext) return @@ -97,8 +81,13 @@ export default class AudioEngine { this.audioIterator = null } - async load(src, onMetadata) { - const id = ++this.asyncId + handleNoAudioTrack() { + this.audioSink = null + this.ensureAudioContext() + } + + async load(media, onMetadata) { + ++this.asyncId await this.stopIterator() this.stopQueuedNodes() @@ -107,23 +96,12 @@ export default class AudioEngine { this.playbackTimeAtStart = 0 this.audioContextStartTime = 0 - const source = this.normalizeSource(src) - if (!source) - return + const { input, audioTrack, duration } = media + this.input = input + this.duration = duration - this.input = new Input({ - source, - formats: ALL_FORMATS, - }) - - this.duration = await this.input.computeDuration() - if (id !== this.asyncId) - return - - const audioTrack = await this.input.getPrimaryAudioTrack() if (!audioTrack) { - this.audioSink = null - this.ensureAudioContext() + this.handleNoAudioTrack() onMetadata?.() return } diff --git a/packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.js b/packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.js index 3353120c3..62ae900b9 100644 --- a/packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.js +++ b/packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.js @@ -3,6 +3,7 @@ * Coordinates audio and video playback */ import AudioEngine from './AudioEngine.js' +import { createInput, getHlsState, resolveDuration, selectPlaybackTracks } from './input.js' import VideoEngine from './VideoEngine.js' export default class MediaBunnyEngine { @@ -31,6 +32,8 @@ export default class MediaBunnyEngine { this.error = null this.seeking = false this.loadSeq = 0 + this.input = null + this.media = null // Listen to ended event events.addEventListener?.('ended', () => { @@ -43,6 +46,7 @@ export default class MediaBunnyEngine { const id = ++this.loadSeq this.pause() + this.disposeInput() this.ended = false this.error = null this.networkState = 2 // NETWORK_LOADING @@ -73,8 +77,28 @@ export default class MediaBunnyEngine { } async performLoad(src, id) { - let videoMetadataLoaded = false - let audioMetadataLoaded = false + if (!(await this.video.preflight(src))) + return + + const input = createInput(src) + if (!input) { + this.video.handleNoVideoTrack() + this.audio.handleNoAudioTrack() + return + } + + const media = await selectPlaybackTracks(input, src) + if (id !== this.loadSeq) { + input.dispose() + return + } + + this.disposeInput() + this.input = input + this.media = media + + let videoMetadataLoaded = !media.videoTrack + let audioMetadataLoaded = !media.audioTrack const checkMetadata = () => { if (videoMetadataLoaded && audioMetadataLoaded) { @@ -87,13 +111,13 @@ export default class MediaBunnyEngine { try { await Promise.all([ - this.video.load(src, () => { + this.video.load(media, () => { if (id !== this.loadSeq) return videoMetadataLoaded = true checkMetadata() }), - this.audio.load(src, () => { + this.audio.load(media, () => { if (id !== this.loadSeq) return audioMetadataLoaded = true @@ -128,6 +152,124 @@ export default class MediaBunnyEngine { }) } + disposeInput() { + this.input?.dispose() + this.input = null + this.media = null + } + + async replaceTracks({ videoTrack, audioTrack, videoMode, audioMode }) { + if (!this.media) + return + + const nextMedia = { + ...this.media, + videoTrack, + audioTrack, + videoMode, + audioMode, + } + + const shouldResume = !this.paused + const currentTime = this.currentTime + + this.pause() + this.ended = false + this.seeking = true + this.events.emit('seeking') + this.events.emit('waiting') + + nextMedia.duration = await resolveDuration(nextMedia) + this.media = nextMedia + + await Promise.all([ + this.video.load(nextMedia), + this.audio.load(nextMedia), + ]) + + await Promise.all([ + this.video.seek(currentTime), + this.audio.seek(currentTime), + ]) + + this.readyState = 4 + this.networkState = 1 + this.seeking = false + this.events.emit('loadedmetadata') + this.events.emit('durationchange') + this.events.emit('progress') + this.events.emit('loadeddata') + this.events.emit('canplay') + this.events.emit('canplaythrough') + this.events.emit('seeked') + + if (shouldResume) { + await this.play() + } + } + + async selectHlsQuality(value) { + if (!this.media?.isHls || !this.input) + return + + const videoTracks = await this.input.getVideoTracks() + const videoTrack = value === 'auto' + ? await this.input.getPrimaryVideoTrack() + : videoTracks.find(track => track.id === value) ?? this.media.videoTrack + + if (!videoTrack) + return + + let audioTrack = this.media.audioTrack + let audioMode = this.media.audioMode + + if (!audioTrack || !videoTrack.canBePairedWith(audioTrack)) { + audioTrack = await videoTrack.getPrimaryPairableAudioTrack() + audioMode = 'auto' + } + + await this.replaceTracks({ + videoTrack, + audioTrack, + videoMode: value === 'auto' ? 'auto' : 'manual', + audioMode, + }) + } + + async selectHlsAudio(value) { + if (!this.media?.isHls || !this.input) + return + + const audioTracks = await this.input.getAudioTracks() + const audioTrack = value === 'auto' + ? this.media.videoTrack + ? await this.media.videoTrack.getPrimaryPairableAudioTrack() + : await this.input.getPrimaryAudioTrack() + : audioTracks.find(track => track.id === value) ?? this.media.audioTrack + + if (!audioTrack) + return + + let videoTrack = this.media.videoTrack + let videoMode = this.media.videoMode + + if (!videoTrack || !audioTrack.canBePairedWith(videoTrack)) { + videoTrack = await audioTrack.getPrimaryPairableVideoTrack() + videoMode = 'auto' + } + + await this.replaceTracks({ + videoTrack, + audioTrack, + videoMode, + audioMode: value === 'auto' ? 'auto' : 'manual', + }) + } + + getHlsState() { + return getHlsState(this.media) + } + async play() { if (!this.paused) return @@ -193,6 +335,7 @@ export default class MediaBunnyEngine { destroy() { this.pause() + this.disposeInput() this.audio.destroy() this.video.destroy() } @@ -203,7 +346,7 @@ export default class MediaBunnyEngine { } get duration() { - return this.audio.duration || this.video.duration + return this.media?.duration ?? this.audio.duration ?? this.video.duration } get videoWidth() { diff --git a/packages/artplayer-proxy-mediabunny/src/VideoEngine.js b/packages/artplayer-proxy-mediabunny/src/VideoEngine.js index f742a5c5e..ea1c959db 100644 --- a/packages/artplayer-proxy-mediabunny/src/VideoEngine.js +++ b/packages/artplayer-proxy-mediabunny/src/VideoEngine.js @@ -3,13 +3,9 @@ * Handles video frame rendering and synchronization */ import { - ALL_FORMATS, - BlobSource, CanvasSink, - Input, - ReadableStreamSource, - UrlSource, } from 'mediabunny' +import { isHlsSource } from './input.js' export default class VideoEngine { constructor({ @@ -55,19 +51,8 @@ export default class VideoEngine { this.isFetching = false } - normalizeSource(src) { - if (typeof src === 'string') - return new UrlSource(src) - if (src instanceof Blob) - return new BlobSource(src) - if (typeof ReadableStream !== 'undefined' && src instanceof ReadableStream) { - return new ReadableStreamSource(src) - } - return src - } - async preflight(url) { - if (!this.preflightRange || typeof url !== 'string') + if (!this.preflightRange || typeof url !== 'string' || isHlsSource(url)) return true try { @@ -109,32 +94,17 @@ export default class VideoEngine { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) } - async load(src, onMetadata) { - const id = ++this.asyncId + async load(media, onMetadata) { + ++this.asyncId await this.stopIterator() this.clear() this.posterDrawn = false - if (!(await this.preflight(src))) - return + const { input, videoTrack, duration } = media + this.input = input + this.duration = duration - const source = this.normalizeSource(src) - if (!source) { - this.drawPoster() - return - } - - this.input = new Input({ - source, - formats: ALL_FORMATS, - }) - - this.duration = await this.input.computeDuration() - if (id !== this.asyncId) - return - - const videoTrack = await this.input.getPrimaryVideoTrack() if (!videoTrack) { this.handleNoVideoTrack() onMetadata?.() @@ -190,7 +160,6 @@ export default class VideoEngine { if (first) { this.ctx.drawImage(first.canvas, 0, 0) - this.events.emit('loadeddata') } else { this.drawPoster() @@ -312,7 +281,7 @@ export default class VideoEngine { this.stop() this.stopIterator() this.posterDrawn = false - this.input = null this.videoSink = null + this.input = null } } diff --git a/packages/artplayer-proxy-mediabunny/src/VideoShim.js b/packages/artplayer-proxy-mediabunny/src/VideoShim.js index 23df3766d..085ee150a 100644 --- a/packages/artplayer-proxy-mediabunny/src/VideoShim.js +++ b/packages/artplayer-proxy-mediabunny/src/VideoShim.js @@ -194,6 +194,18 @@ export default class VideoShim { this.engine.load(this._src) } + getM3u8State() { + return this.engine.getHlsState() + } + + switchM3u8Quality(value) { + return this.engine.selectHlsQuality(value) + } + + switchM3u8Audio(value) { + return this.engine.selectHlsAudio(value) + } + // Video dimensions get videoWidth() { return this.engine.videoWidth diff --git a/packages/artplayer-proxy-mediabunny/src/index.js b/packages/artplayer-proxy-mediabunny/src/index.js index 4142bc2a9..3391c4885 100644 --- a/packages/artplayer-proxy-mediabunny/src/index.js +++ b/packages/artplayer-proxy-mediabunny/src/index.js @@ -1,3 +1,4 @@ +import { setupM3u8Controls } from './m3u8.js' /** * ArtPlayer MediaBunny Proxy * Main entry point @@ -20,6 +21,7 @@ export default function artplayerProxyMediabunny(option = {}) { ctx, option, }) + art.mediabunny = shim // Proxy canvas methods to shim const originalCanvasMethods = {} @@ -74,9 +76,11 @@ export default function artplayerProxyMediabunny(option = {}) { art.on('resize', resize) art.on('video:loadedmetadata', resize) + setupM3u8Controls({ art, shim, option }) // Cleanup on destroy art.on('destroy', () => { + delete art.mediabunny shim.destroy() }) diff --git a/packages/artplayer-proxy-mediabunny/src/input.js b/packages/artplayer-proxy-mediabunny/src/input.js new file mode 100644 index 000000000..a69609404 --- /dev/null +++ b/packages/artplayer-proxy-mediabunny/src/input.js @@ -0,0 +1,120 @@ +import { + ALL_FORMATS, + BlobSource, + HLS_FORMATS, + Input, + ReadableStreamSource, + UrlSource, +} from 'mediabunny' + +const M3U8_RE = /\.m3u8(?:$|[?#])/i + +export function isHlsSource(src) { + return typeof src === 'string' && M3U8_RE.test(src) +} + +export function normalizeSource(src) { + if (typeof src === 'string') + return new UrlSource(src) + if (src instanceof Blob) + return new BlobSource(src) + if (typeof ReadableStream !== 'undefined' && src instanceof ReadableStream) { + return new ReadableStreamSource(src) + } + return src ?? null +} + +export function createInput(src) { + const source = normalizeSource(src) + if (!source) + return null + + return new Input({ + source, + formats: isHlsSource(src) ? HLS_FORMATS : ALL_FORMATS, + }) +} + +export async function resolveDuration({ input, videoTrack, audioTrack }) { + const tracks = [videoTrack, audioTrack].filter(Boolean) + const referenceTrack = videoTrack || audioTrack + const isLive = Boolean(referenceTrack && await referenceTrack.isLive()) + + let duration = Number.NaN + if (tracks.length > 0) { + duration = await input.getDurationFromMetadata(tracks, { skipLiveWait: true }) + if (duration === null && !isLive) { + duration = await input.computeDuration(tracks, { skipLiveWait: true }) + } + } + + return isLive ? Number.POSITIVE_INFINITY : duration ?? Number.NaN +} + +export async function selectPlaybackTracks(input, src) { + const videoTrack = await input.getPrimaryVideoTrack() + const audioTrack = videoTrack + ? await videoTrack.getPrimaryPairableAudioTrack() + : await input.getPrimaryAudioTrack() + const duration = await resolveDuration({ input, videoTrack, audioTrack }) + + return { + input, + videoTrack, + audioTrack, + duration, + isLive: Number.isFinite(duration) ? false : Boolean((videoTrack || audioTrack) && await (videoTrack || audioTrack).isLive()), + isHls: isHlsSource(src), + videoMode: isHlsSource(src) ? 'auto' : 'manual', + audioMode: isHlsSource(src) ? 'auto' : 'manual', + } +} + +async function getTrackBitrate(track) { + return await track.getAverageBitrate() ?? await track.getBitrate() ?? 0 +} + +export async function getHlsState(media) { + if (!media?.isHls || !media.input) + return null + + const [videoTracks, pairableAudioTracks] = await Promise.all([ + media.input.getVideoTracks(), + media.videoTrack + ? media.videoTrack.getPairableAudioTracks() + : [], + ]) + + const [levels, audios] = await Promise.all([ + Promise.all(videoTracks.map(async (track, index) => ({ + id: track.id, + track, + index, + name: await track.getName(), + height: await track.getDisplayHeight(), + bitrate: await getTrackBitrate(track), + }))), + Promise.all(pairableAudioTracks.map(async (track, index) => { + const name = await track.getName() + const language = await track.getLanguageCode() + return { + id: track.id, + track, + index, + name, + lang: language, + language, + bitrate: await getTrackBitrate(track), + } + })), + ]) + + return { + levels, + audios, + currentLevel: media.videoTrack ? levels.find(item => item.id === media.videoTrack.id) ?? null : null, + currentAudio: media.audioTrack ? audios.find(item => item.id === media.audioTrack.id) ?? null : null, + videoMode: media.videoMode ?? 'auto', + audioMode: media.audioMode ?? 'auto', + } +} diff --git a/packages/artplayer-proxy-mediabunny/src/m3u8.js b/packages/artplayer-proxy-mediabunny/src/m3u8.js new file mode 100644 index 000000000..06cb0131c --- /dev/null +++ b/packages/artplayer-proxy-mediabunny/src/m3u8.js @@ -0,0 +1,191 @@ +import $audio from '../../artplayer-plugin-hls-control/src/audio.svg?raw' +import $quality from '../../artplayer-plugin-hls-control/src/quality.svg?raw' + +function uniqBy(array, property) { + const seen = new Map() + return array.filter((item) => { + const key = item[property] + if (key === undefined) { + return true + } + return !seen.has(key) && seen.set(key, 1) + }) +} + +export function setupM3u8Controls({ art, shim, option }) { + if (!option.m3u8) + return + + function removeControl(name) { + if (art.controls.cache.has(name)) { + art.controls.remove(name) + } + } + + function removeSetting(name) { + if (art.setting.find(name)) { + art.setting.remove(name) + } + } + + function clearQuality() { + removeControl('mediabunny-quality') + removeSetting('mediabunny-quality') + } + + function clearAudio() { + removeControl('mediabunny-audio') + removeSetting('mediabunny-audio') + } + + function canRender(config = {}) { + return config.control || config.setting + } + + async function updateQuality(state) { + const config = option.m3u8?.quality || {} + if (!canRender(config) || !state?.levels.length) { + clearQuality() + return + } + + const auto = config.auto || 'Auto' + const title = config.title || 'Quality' + const getName = config.getName || (level => level.name || `${level.height}P`) + const defaultHtml = state.currentLevel + ? getName(state.currentLevel) + : auto + + const selector = uniqBy( + state.levels.map((item) => { + return { + html: getName(item), + value: item.id, + default: state.currentLevel?.id === item.id, + } + }), + 'html', + ).sort((a, b) => { + const left = state.levels.find(item => item.id === a.value) + const right = state.levels.find(item => item.id === b.value) + return (right?.height || 0) - (left?.height || 0) + }) + + selector.push({ + html: auto, + value: 'auto', + default: !state.currentLevel, + }) + + const onSelect = async (item) => { + await shim.switchM3u8Quality(item.value) + art.notice.show = `${title}: ${item.html}` + await update() + return item.html + } + + if (config.control) { + art.controls.update({ + name: 'mediabunny-quality', + position: 'right', + html: defaultHtml, + style: { padding: '0 10px' }, + selector, + onSelect, + }) + } + + if (config.setting) { + art.setting.update({ + name: 'mediabunny-quality', + tooltip: defaultHtml, + html: title, + icon: $quality, + width: 200, + selector, + onSelect, + }) + } + } + + async function updateAudio(state) { + const config = option.m3u8?.audio || {} + if (!canRender(config) || !state?.audios.length || state.audios.length < 2) { + clearAudio() + return + } + + const auto = config.auto || 'Auto' + const title = config.title || 'Audio' + const getName = config.getName || (track => track.name || track.lang || track.language) + const defaultHtml = state.currentAudio + ? getName(state.currentAudio) + : auto + + const selector = uniqBy( + state.audios.map((item) => { + return { + html: getName(item), + value: item.id, + default: state.currentAudio?.id === item.id, + } + }), + 'html', + ) + + selector.push({ + html: auto, + value: 'auto', + default: !state.currentAudio, + }) + + const onSelect = async (item) => { + await shim.switchM3u8Audio(item.value) + art.notice.show = `${title}: ${item.html}` + await update() + return item.html + } + + if (config.control) { + art.controls.update({ + name: 'mediabunny-audio', + position: 'right', + html: defaultHtml, + style: { padding: '0 10px' }, + selector, + onSelect, + }) + } + + if (config.setting) { + art.setting.update({ + name: 'mediabunny-audio', + tooltip: defaultHtml, + html: title, + icon: $audio, + width: 200, + selector, + onSelect, + }) + } + } + + async function update() { + const state = await shim.getM3u8State() + if (!state) { + clearQuality() + clearAudio() + return + } + + await Promise.all([ + updateQuality(state), + updateAudio(state), + ]) + } + + art.on('video:loadedmetadata', update) + art.on('restart', update) + + return { update } +} diff --git a/packages/artplayer-proxy-mediabunny/types/artplayer-proxy-mediabunny.d.ts b/packages/artplayer-proxy-mediabunny/types/artplayer-proxy-mediabunny.d.ts index e7927db16..59f257d8b 100644 --- a/packages/artplayer-proxy-mediabunny/types/artplayer-proxy-mediabunny.d.ts +++ b/packages/artplayer-proxy-mediabunny/types/artplayer-proxy-mediabunny.d.ts @@ -1,6 +1,36 @@ import type Artplayer from 'artplayer' interface Option { + m3u8?: { + quality?: { + control?: boolean + setting?: boolean + title?: string + auto?: string + getName?: (level: { + id: number + index: number + name: null | string + height: number + bitrate: number + }) => string + } + audio?: { + control?: boolean + setting?: boolean + title?: string + auto?: string + getName?: (track: { + id: number + index: number + name: null | string + lang: string + language: string + bitrate: number + }) => string + } + } + /** * Timeout for loading media in milliseconds * @default 0 diff --git a/packages/artplayer/dist/artplayer.js b/packages/artplayer/dist/artplayer.js index 858619e16..cc6d0d1c0 100644 --- a/packages/artplayer/dist/artplayer.js +++ b/packages/artplayer/dist/artplayer.js @@ -4,4 +4,4 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";function t(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var e,r={exports:{}};var a=(e||(e=1,r.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var o=t(r);if("boolean"===o)return"boolean";if("string"===o)return"string";if("number"===o)return"number";if("symbol"===o)return"symbol";if("function"===o)return"GeneratorFunction"===a(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(a(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(o=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return o.slice(8,-1).toLowerCase().replace(/\s/g,"")};function a(t){return t.constructor?t.constructor.name:null}function o(t,e){var a=2=1,p=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(s)||d,h="undefined"!==typeof window&&"undefined"!==typeof document;function u(t,e=document){return e.querySelector(t)}function m(t,e=document){return Array.from(e.querySelectorAll(t))}function f(t,e){return t.classList.add(e)}function g(t,e){return t.classList.remove(e)}function v(t,e){return t.classList.contains(e)}function y(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function b(t){return t.parentNode.removeChild(t)}function w(t,e,r){return t.style[e]=r,t}function x(t,e){for(const r in e)w(t,r,e[r]);return t}function k(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function $(t,e){k(t).forEach(t=>g(t,e)),f(t,e)}function T(t,e,r="top"){p||(t.setAttribute("aria-label",e),f(t,"hint--rounded"),f(t,`hint--${r}`))}function E(t,e=0){const r=t.getBoundingClientRect(),a=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=a&&r.top+r.height+e>=0,i=r.left-e<=o+e&&r.left+r.width+e>=0;return n&&i}function C(t,e){return R(t).includes(e)}function z(t,e){return e.parentNode.replaceChild(t,e),t}function L(t){return document.createElement(t)}function S(t="",e=""){const r=L("i");return f(r,"art-icon"),f(r,`art-icon-${t}`),y(r,e),r}function M(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function I(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function A(t){return t.getBoundingClientRect()}function P(t,e){return new Promise((r,a)=>{const o=new Image;o.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=o.width*e,n.height=o.height*e,i.drawImage(o,0,0,n.width,n.height),n.toBlob(e=>{const o=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(o),a(new Error(`Image load failed: ${t}`))},n.src=o})}else r(o)},o.onerror=function(){a(new Error(`Image load failed: ${t}`))},o.src=t})}function R(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function O(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class _ extends Error{constructor(t,e){super(t),"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function V(t,e){if(!t)throw new _(e);return t}function Y(t){return t.includes("?")?Y(t.split("?")[0]):t.includes("#")?Y(t.split("#")[0]):t.trim().toLowerCase().split(".").pop()}function N(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r)}function D(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function F(t){return t.charAt(0).toUpperCase()+t.slice(1)}function B(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),a=Math.floor(t-3600*e-60*r);return(e>0?[e,r,a]:[r,a]).map(t=>t<10?`0${t}`:String(t)).join(":")}function H(t){return t.replace(/[&<>'"]/g,t=>({"&":"&","<":"<",">":">","'":"'",'"':"""}[t]||t))}const W=Object.defineProperty,{hasOwnProperty:j}=Object.prototype;function U(t,e){return j.call(t,e)}function q(t,e){return Object.getOwnPropertyDescriptor(t,e)}function X(...t){const e=t=>t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(a=>{const o=t[a],n=r[a];Array.isArray(o)&&Array.isArray(n)?t[a]=o.concat(...n):e(o)&&e(n)?t[a]=X(o,n):t[a]=n}),t),{})}function G(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let a=r.slice(0,3);return 1===r.length&&(a=`${r}00`),2===r.length&&(a=`${r}0`),`${e},${a}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function K(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function Z(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const a=t.match(e);return a?{start:r(a[1].trim()),end:r(a[2].trim()),text:a[5].replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}:null}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function J(t=0){return new Promise(e=>setTimeout(e,t))}function Q(t,e){let r;return function(...a){clearTimeout(r),r=setTimeout(()=>(r=null,t.apply(this,a)),e)}}function tt(t,e){let r=!1;return function(...a){r||(t.apply(this,a),r=!0,setTimeout(()=>{r=!1},e))}}const et=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:_,addClass:f,append:y,assToVtt:Z,capitalize:F,clamp:D,createElement:L,debounce:Q,def:W,download:N,errorHandle:V,escape:H,get:q,getComposedPath:R,getExt:Y,getIcon:S,getRect:A,getSafeAreaInsets:O,getStyle:function(t,e,r=!0){const a=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(a):a},has:U,hasClass:v,includeFromEvent:C,inverseClass:$,isBrowser:h,isIOS:c,isIOS13:d,isInViewport:E,isMobile:p,isSafari:l,loadImg:P,mergeDeep:X,query:u,queryAll:m,remove:b,removeClass:g,replaceElement:z,secondToTime:B,setStyle:w,setStyleText:M,setStyles:x,siblings:k,sleep:J,srtToVtt:G,supportsFlex:I,throttle:tt,tooltip:T,unescape:function(t){const e={"&":"&","<":"<",">":">","'":"'",""":'"'},r=new RegExp(`(${Object.keys(e).join("|")})`,"g");return t.replace(r,t=>e[t]||t)},userAgent:s,vttToBlob:K},Symbol.toStringTag,{value:"Module"})),rt="array",at="boolean",ot="string",nt="number",it="object",st="function";function lt(t,e,r){return V(e===ot||e===nt||t instanceof Element,`${r.join(".")} require '${ot}' or 'Element' type`)}const ct={html:lt,disable:`?${at}`,name:`?${ot}`,index:`?${nt}`,style:`?${it}`,click:`?${st}`,mounted:`?${st}`,tooltip:`?${ot}|${nt}`,width:`?${nt}`,selector:`?${rt}`,onSelect:`?${st}`,switch:`?${at}`,onSwitch:`?${st}`,range:`?${rt}`,onRange:`?${st}`,onChange:`?${st}`},dt={id:ot,container:lt,url:ot,poster:ot,type:ot,theme:ot,lang:ot,volume:nt,isLive:at,muted:at,autoplay:at,autoSize:at,autoMini:at,loop:at,flip:at,playbackRate:at,aspectRatio:at,screenshot:at,setting:at,hotkey:at,pip:at,mutex:at,backdrop:at,fullscreen:at,fullscreenWeb:at,subtitleOffset:at,miniProgressBar:at,useSSR:at,playsInline:at,lock:at,gesture:at,fastForward:at,autoPlayback:at,autoOrientation:at,airplay:at,proxy:`?${st}`,plugins:[st],layers:[ct],contextmenu:[ct],settings:[ct],controls:[{...ct,position:(t,e,r)=>{const a=["top","left","right"];return V(a.includes(t),`${r.join(".")} only accept ${a.toString()} as parameters`)}}],quality:[{default:`?${at}`,html:ot,url:ot}],highlight:[{time:nt,text:ot}],thumbnails:{url:ot,number:nt,column:nt,width:nt,height:nt,scale:nt},subtitle:{url:ot,name:ot,type:ot,style:it,escape:at,encoding:ot,onVttLoad:st},moreVideoAttr:it,i18n:it,icons:it,cssVar:it,customType:it};class pt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return v(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?f(e,r):g(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",o(e,ct),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;V(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const a=L("div");f(a,`art-${this.name}`),f(a,`art-${this.name}-${r}`);const n=Array.from(this.$parent.children);a.dataset.index=e.index||this.id;const i=n.find(t=>Number(t.dataset.index)>=Number(a.dataset.index));i?i.insertAdjacentElement("beforebegin",a):y(this.$parent,a),e.html&&y(a,e.html),e.style&&x(a,e.style),e.tooltip&&T(a,e.tooltip);const s=[];if(e.click){const t=this.art.events.proxy(a,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});s.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,a,s),this[r]=a,this.cache.set(r,{$ref:a,events:s,option:e}),e.mounted&&e.mounted.call(this.art,a),a}remove(t){V(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],b(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class ht extends pt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,p||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:a}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:a}}=e,o=a.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return{...t,html:`${r.get("Play Speed")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.playbackRate=Number(a),t.show=!1)},mounted:t=>{const r=u('[data-value="1"]',t);r&&$(r,"art-current"),e.on("video:ratechange",()=>{const r=m("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&$(r,"art-current")})}}}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:a}}=e,o=a.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return{...t,html:`${r.get("Aspect Ratio")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.aspectRatio=a,t.show=!1)},mounted:t=>{const r=u('[data-value="default"]',t);r&&$(r,"art-current"),e.on("aspectRatio",e=>{const r=m("span",t).find(t=>t.dataset.value===e);r&&$(r,"art-current")})}}}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:a}}=e,o=a.map(t=>`${r.get(F(t))}`).join("");return{...t,html:`${r.get("Video Flip")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.flip=a.toLowerCase(),t.show=!1)},mounted:t=>{const r=u('[data-value="normal"]',t);r&&$(r,"art-current"),e.on("flip",e=>{const r=m("span",t).find(t=>t.dataset.value===e);r&&$(r,"art-current")})}}}}({name:"flip",index:30})),this.add(function(t){return e=>({...t,html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){const e=h?location.href:"";return{...t,html:`ArtPlayer ${n}`}}({name:"version",index:50})),this.add(function(t){return e=>({...t,html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let o=0;o{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,o=t.clientY,{height:n,width:i,left:s,top:l}=A(r),{height:c,width:d}=A(a);let p=e-s,h=o-l;e+d>s+i&&(p=i-d),o+c>l+n&&(h=n-c),x(a,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{C(t,a)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}function ut(t,e){const{$progress:r}=t.template,{left:a}=A(r),o=D((p?e.touches[0].clientX:e.clientX)-a,0,r.clientWidth),n=o/r.clientWidth*t.duration;return{second:n,time:B(n),width:o,percentage:D(o/r.clientWidth,0,1)}}function mt(t,e){if(t.isRotate){const r=e.touches[0].clientY/t.height,a=r*t.duration;t.emit("setBar","played",r,e),t.seek=a}else{const{second:r,percentage:a}=ut(t,e);t.emit("setBar","played",a,e),t.seek=r}}function ft(t){return e=>{const{icons:r,option:a,proxy:o}=e,{$player:n,$progress:i}=e.template;return{...t,html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=u(".art-progress-hover",t),d=u(".art-progress-loaded",t),h=u(".art-progress-played",t),m=u(".art-progress-highlight",t),v=u(".art-progress-indicator",t),b=u(".art-progress-tip",t);function x(r,a){const{width:o,time:n}=a||ut(e,r);b.textContent=n||"00:00";const i=b.clientWidth;o<=i/2?w(b,"left",0):o>t.clientWidth-i/2?w(b,"left",t.clientWidth-i+"px"):w(b,"left",o-i/2+"px")}r.indicator?y(v,r.indicator):w(v,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,a,o){const i="played"===r&&o&&p;if("loaded"===r&&w(d,"width",100*a+"%"),"hover"===r&&(w(c,"width",100*a+"%"),C(o,m)?function(r){const{width:a}=ut(e,r),{text:o}=r.target.dataset;b.textContent=o;const n=b.clientWidth;a<=n/2?w(b,"left",0):a>t.clientWidth-n/2?w(b,"left",t.clientWidth-n+"px"):w(b,"left",a-n/2+"px")}(o):x(o),0===a?g(n,"art-progress-hover"):f(n,"art-progress-hover")),"played"===r&&(w(h,"width",100*a+"%"),w(v,"left",100*a+"%")),i){f(n,"art-progress-hover");x(o,{width:t.clientWidth*a,time:B(a*e.duration)}),clearTimeout(s),s=setTimeout(()=>{g(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){m.textContent="";for(let t=0;t`;y(m,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),p||(o(i,"click",t=>{t.target!==v&&mt(e,t)}),o(i,"mousemove",t=>{const{percentage:r}=ut(e,t);e.emit("setBar","hover",r,t)}),o(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),o(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:a}=ut(e,t);e.emit("setBar","played",a,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}}}}class gt extends pt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:a}=this.art.template;t.on("mousemove",()=>{p||(this.show=!0)}),t.on("click",()=>{p?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=C(t,a)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(g(r,"art-hide-cursor"),f(r,"art-hover"),this.timer=Date.now()):(f(r,"art-hide-cursor"),g(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(ft({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.play),i=y(t,a.pause);function s(){w(n,"display","flex"),w(i,"display","none")}function l(){w(n,"display","none"),w(i,"display","flex")}T(n,o.get("Play")),T(i,o.get("Pause")),r(n,"click",()=>{e.play()}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:a}=e,o=y(t,a.volume),n=y(t,a.volumeClose),i=y(t,'
'),s=y(i,'
'),l=y(s,'
'),c=y(s,'
'),d=y(c,'
'),h=y(d,'
'),u=y(c,'
');function m(t){const{top:e,height:r}=A(c);return 1-(t.clientY-e)/r}function f(){if(e.muted||0===e.volume)w(o,"display","none"),w(n,"display","flex"),w(u,"top","100%"),w(h,"top","100%"),l.textContent=0;else{const t=100*e.volume;w(o,"display","flex"),w(n,"display","none"),w(u,"top",100-t+"%"),w(h,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(f(),e.on("video:volumechange",f),r(o,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),p)w(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=m(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=m(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>({...t,style:p?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${B(e.currentTime)} / ${B(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const a=["video:loadedmetadata","video:timeupdate","video:progress"];for(let o=0;o{this.art.quality=t.quality}),t.screenshot&&!p&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:a}=e;y(t,a.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e;y(t,a.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{T(t,o.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e;y(t,a.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{T(t,o.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:a}=e;y(t,a.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.fullscreenWebOn),i=y(t,a.fullscreenWebOff);w(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(T(t,o.get("Exit Web Fullscreen")),w(n,"display","none"),w(i,"display","inline-flex")):(T(t,o.get("Web Fullscreen")),w(n,"display","inline-flex"),w(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.fullscreenOn),i=y(t,a.fullscreenOff);w(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(T(t,o.get("Exit Fullscreen")),w(n,"display","none"),w(i,"display","inline-flex")):(T(t,o.get("Fullscreen")),w(n,"display","inline-flex"),w(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),W(e,"$control_item",{get:()=>r}),W(e,"$control_value",{get:()=>o})}const i=a(n,"click",async e=>{const r=R(e),a=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(a),t.onSelect&&(o.innerHTML=await t.onSelect.call(this.art,a,a.$control_item,e))});r.push(i)}}function vt(t,e,r,a){const o=e-a,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(o)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,o);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}class yt{constructor(t){this.destroyEvents=new Set,this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:a,$video:o}}=t;function n(e){C(e,a)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(o,"click",e=>{const a=Date.now();i.push(a);const{MOBILE_CLICK_PLAY:o,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>a-t<=n);switch(c.length){case 1:t.emit("click",e),p?!t.isLock&&o&&t.toggle():t.toggle(),i=c;break;case 2:t.emit("dblclick",e),p?!t.isLock&&s&&t.toggle():l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{f(r,"art-hover"),t.emit("hover",!0,e)},e=>{g(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:a}=t;t.on("resize",()=>{const{aspectRatio:e,notice:a}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,a.show=""});const o=Q(()=>t.emit("resize"),a.RESIZE_TIME);t.on("window:orientationchange",()=>o()),t.on("window:resize",()=>o()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>o())}(t,this),function(t,e){if(p&&!t.option.isLive){const{$video:r,$progress:a}=t.template;let o=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){o===a&&mt(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:a,pageY:n}=e.touches[0],c=vt(i,s,a,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=D((a-i)/t.width,-1,1),d=D((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=o===r?t.constructor.TOUCH_MOVE_RATIO:1,u=D(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",D(u/t.duration,0,1),e),t.notice.show=`${B(u)} / ${B(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,o=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{o=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(a,"touchstart",t=>{o=a,c(t)}),e.proxy(a,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:a}}=t,o=tt(()=>{t.emit("view",E(a,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>o()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],a=["resize","scroll","orientationchange"],o=[];function n(n={}){for(let t=0;t{const a=n.document||i.ownerDocument||document,s=e.proxy(a,r,e=>{t.emit(`document:${r}`,e)});o.push(s)}),a.forEach(r=>{const a=n.window||i.ownerDocument?.defaultView||window,s=e.proxy(a,r,e=>{t.emit(`window:${r}`,e)});o.push(s)})}n(),e.bindGlobalEvents=n}(t,this),function(t){if(t.constructor.USE_RAF){let e=null;!function r(){t.playing&&t.emit("raf"),t.isDestroy||(e=requestAnimationFrame(r))}(),t.on("destroy",()=>{cancelAnimationFrame(e)})}}(t)}proxy(t,e,r,a={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,a));t.addEventListener(e,r,a);const o=()=>t.removeEventListener(e,r,a);return this.destroyEvents.add(o),o}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class bt{constructor(t){this.art=t,this.keys={},p||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{this.art.toggle()}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',state:'\n\n\n',play:'\n \n',pause:'\n \n',check:'\n\n',volume:'\n \n \n',volumeClose:'\n \n \n',screenshot:'\n\t\n\n',setting:'\n \n \n',pip:'\n\n',arrowLeft:'\n \n',arrowRight:'\n \n',playbackRate:'',aspectRatio:'',config:'',lock:'\n\n\n\n\n',flip:'\n\n\n\n\n\n',unlock:'\n\n\n',fullscreenOff:'\n\n\n\n\n',fullscreenOn:'\n\n\n\n\n',fullscreenWebOff:'\n\n\n\n\n',fullscreenWebOn:'\n\n\n\n\n',switchOn:'\n\n\n \n',switchOff:'\n\n\n \n\n',error:'\n\n\n\n\n',close:'\n\n\n\n\n',airplay:'\n \n \n \n \n\n',...t.option.icons};for(const r in e)W(this,r,{get:()=>S(r,e[r])})}}class $t extends pt{constructor(t){super(t),this.name="info",p||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:a,$video:o}}=this.art;t(a,"click",()=>{this.show=!1});let n=null;const i=m("[data-video]",r)||[];this.art.on("destroy",()=>clearTimeout(n)),function t(){for(let e=0;e{w(o,"display","none"),w(n,"display",null)}),a.proxy(e.$state,"click",()=>t.play())}}class zt{constructor(t){this.art=t,this.timer=null,t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){const{constructor:e,template:{$player:r,$noticeInner:a}}=this.art;t?(a.textContent=t instanceof Error?t.message.trim():t,f(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{a.textContent="",g(r,"art-notice-show")},e.NOTICE_TIME)):g(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}const Lt=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],St=(()=>{if("undefined"===typeof document)return!1;const t=Lt[0],e={};for(const r of Lt){if(r[1]in document){for(const[a,o]of r.entries())e[t[a]]=o;return e}}return!1})(),Mt={change:St.fullscreenchange,error:St.fullscreenerror},It={request:(t=document.documentElement,e)=>new Promise((r,a)=>{const o=()=>{It.off("change",o),r()};It.on("change",o);const n=t[St.requestFullscreen](e);n instanceof Promise&&n.then(o).catch(a)}),exit:()=>new Promise((t,e)=>{if(!It.isFullscreen)return void t();const r=()=>{It.off("change",r),t()};It.on("change",r);const a=document[St.exitFullscreen]();a instanceof Promise&&a.then(r).catch(e)}),toggle:(t,e)=>It.isFullscreen?It.exit():It.request(t,e),onchange(t){It.on("change",t)},onerror(t){It.on("error",t)},on(t,e){const r=Mt[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Mt[t];r&&document.removeEventListener(r,e,!1)},raw:St};function At(t){const{i18n:e,notice:r,template:{$video:a,$player:o}}=t;t.once("video:loadedmetadata",()=>{var n;It.isEnabled?(n=t,It.on("change",()=>{n.emit("fullscreen",It.isFullscreen),It.isFullscreen?(n.state="fullscreen",f(o,"art-fullscreen")):g(o,"art-fullscreen"),n.emit("resize")}),It.on("error",t=>{n.emit("fullscreenError",t)}),W(n,"fullscreen",{get:()=>It.isFullscreen,async set(t){t?await It.request(o):await It.exit()}})):a.webkitSupportsFullscreen?(t=>{t.on("document:webkitfullscreenchange",()=>{t.emit("fullscreen",t.fullscreen),t.emit("resize")}),W(t,"fullscreen",{get:()=>document.fullscreenElement===a,set(e){e?(t.state="fullscreen",a.webkitEnterFullscreen()):a.webkitExitFullscreen()}})})(t):W(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),W(t,"fullscreen",q(t,"fullscreen"))})}function Pt(t){const{icons:e,proxy:r,storage:a,template:{$player:o,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(g(o,"art-mini"),w(e,"display","none"),o.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(w(e,"display","none"),w(r,"display","flex")):(w(e,"display","flex"),w(r,"display","none"))}function p(){const{$mini:e}=t.template,r=A(e),o=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;a.set("top",o),a.set("left",n),w(e,"top",`${o}px`),w(e,"left",`${n}px`)}W(t,"mini",{get:()=>v(o,"art-mini"),set(h){if(h){t.state="mini",f(o,"art-mini");const h=function(){const{$mini:o}=t.template;if(o)return y(o,n),w(o,"display","flex");{const o=L("div");f(o,"art-mini-popup"),y(document.body,o),t.template.$mini=o,y(o,n);const p=y(o,'
');y(p,e.close),r(p,"click",c);const h=y(o,'
'),u=y(h,e.play),m=y(h,e.pause);return r(u,"click",()=>t.play()),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(o,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){f(o,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;w(o,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,g(o,"art-mini-dragging");const t=A(o);a.set("left",t.left),a.set("top",t.top),w(o,"left",`${t.left}px`),w(o,"top",`${t.top}px`),w(o,"transform",null)}}),o}}(),u=a.get("top"),m=a.get("left");"number"===typeof u&&"number"===typeof m?(w(h,"top",`${u}px`),w(h,"left",`${m}px`),E(h)||p()):p(),t.emit("mini",!0)}else c()}})}function Rt(t){const{i18n:e,notice:r,template:{$video:a}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:a}=t;e.disablePictureInPicture=!1,W(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw a.show=t,t})):document.exitPictureInPicture().catch(t=>{throw a.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):a.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),W(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):W(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ot(t){const{option:e,template:{$progress:r,$video:a}}=t;let o=null,n=!1,i=null;t.on("setBar",async(o,s,l)=>{const c=t.controls?.thumbnails,{url:d,scale:h}=e.thumbnails;if(!c||!d)return;if("hover"===o||"played"===o&&l&&p){if(i||n||(n=!0,i=await P(d,h),n=!1),!i)return;const o=r.clientWidth*s;o>0&&or.clientWidth-h/2?w(n,"left",r.clientWidth-h+"px"):w(n,"left",o-h/2+"px")}(o)}}),W(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(o),o=null,n=!1,i=null)}})}Object.defineProperties(It,{isFullscreen:{get:()=>Boolean(document[St.fullscreenElement])},element:{enumerable:!0,get:()=>document[St.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[St.fullscreenEnabled])}});class _t{constructor(t){!function(t){const{option:e,template:{$video:r}}=t;W(t,"url",{get:()=>r.src,async set(a){if(a){const o=t.url,n=e.type||Y(a),i=e.customType[n];n&&i?(await J(),t.loading.show=!0,i.call(t,r,a,t)):(URL.revokeObjectURL(o),r.src=a),o!==t.url&&(t.option.url=a,t.isReady&&o&&t.once("video:canplay",()=>{t.emit("restart",a)}))}else await J(),t.loading.show=!0}})}(t),function(t){const{template:{$video:e}}=t;W(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:a,constructor:{instances:o},template:{$video:n}}=t;W(t,"play",{async value(){const i=await n.play();if(r.show=e.get("Play"),t.emit("play"),a.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;W(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${B(t.currentTime)} / ${B(t.duration)}`),t.emit("seek",t.currentTime,r)}}),W(t,"forward",{set(e){t.seek=t.currentTime+e}}),W(t,"backward",{set(e){t.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:a,storage:o}=t;W(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=D(t,0,1),a.show=`${r.get("Volume")}: ${Number.parseInt(100*e.volume,10)}`,0!==e.volume&&o.set("volume",e.volume)}}),W(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;W(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{r=Number.parseFloat(r),Number.isNaN(r)||(e.currentTime=D(r,0,t.duration))}})}(t),function(t){W(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){function e(e,r){return new Promise((a,o)=>{if(e===t.url)return void a();const{playing:n,aspectRatio:i,playbackRate:s}=t;t.pause(),t.url=e,t.notice.show="";const l={error:e=>{t.off("video:canplay",l.canplay),t.off("video:loadedmetadata",l.metadata),o(e)},metadata:()=>{t.currentTime=r},canplay:async()=>{t.off("video:error",l.error),t.playbackRate=s,t.aspectRatio=i,n&&await t.play(),t.notice.show="",a()}};t.once("video:error",l.error),t.once("video:loadedmetadata",l.metadata),t.once("video:canplay",l.canplay)})}W(t,"switchQuality",{value:r=>e(r,t.currentTime)}),W(t,"switchUrl",{value:t=>e(t,0)}),W(t,"switch",{set:t.switchUrl})}(t),function(t){const{template:{$video:e},i18n:r,notice:a}=t;W(t,"playbackRate",{get:()=>e.playbackRate,set(o){if(o){if(o===e.playbackRate)return;e.playbackRate=o,a.show=`${r.get("Rate")}: ${1===o?r.get("Normal"):`${o}x`}`}else t.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:a,$player:o}}=t;W(t,"aspectRatio",{get:()=>o.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)w(a,"width",null),w(a,"height",null),w(a,"margin",null),delete o.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=o,i=e/r,s=t[0]/t[1];i>s?(w(a,"width",s*r+"px"),w(a,"height","100%"),w(a,"margin","0 auto")):(w(a,"width","100%"),w(a,"height",e/s+"px"),w(a,"margin","auto 0")),o.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,a=L("canvas");W(t,"getDataURL",{value:()=>new Promise((t,o)=>{try{a.width=r.videoWidth,a.height=r.videoHeight,a.getContext("2d").drawImage(r,0,0),t(a.toDataURL("image/png"))}catch(n){e.show=n,o(n)}})}),W(t,"getBlobUrl",{value:()=>new Promise((t,o)=>{try{a.width=r.videoWidth,a.height=r.videoHeight,a.getContext("2d").drawImage(r,0,0),a.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,o(n)}})}),W(t,"screenshot",{value:async e=>{const a=await t.getDataURL();return N(a,`${e||`artplayer_${B(r.currentTime)}`}.png`),t.emit("screenshot",a),a}})}(t),At(t),function(t){const{constructor:e,template:{$container:r,$player:a}}=t;let o="";W(t,"fullscreenWeb",{get:()=>v(a,"art-fullscreen-web"),set(n){n?(o=a.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&y(document.body,a),t.state="fullscreenWeb",w(a,"width","100%"),w(a,"height","100%"),f(a,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&y(r,a),o&&(a.style.cssText=o,o=""),g(a,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),Rt(t),function(t){const{$video:e}=t.template;W(t,"loaded",{get:()=>t.loadedTime/e.duration}),W(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){W(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;W(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:a}=t.template;W(t,"autoSize",{value(){const{videoWidth:o,videoHeight:n}=a,{width:i,height:s}=A(e),l=o/n;if(i/s>l)w(r,"width",s*l/i*100+"%"),w(r,"height","100%");else{const t=i/l/s*100;w(r,"width","100%"),w(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){W(t,"rect",{get:()=>A(t.template.$player)});const e=["bottom","height","left","right","top","width"];for(let r=0;rt.rect[a]})}W(t,"x",{get:()=>t.left+window.pageXOffset}),W(t,"y",{get:()=>t.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:a}=t;W(t,"flip",{get:()=>e.dataset.flip||"normal",set(o){o||(o="normal"),"normal"===o?delete e.dataset.flip:e.dataset.flip=o,a.show=`${r.get("Video Flip")}: ${r.get(F(o))}`,t.emit("flip",o)}})}(t),Pt(t),function(t){const{template:{$poster:e}}=t;W(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch{return""}},set(t){w(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;W(t,"autoHeight",{value(){const{clientWidth:a}=e,{videoHeight:o,videoWidth:n}=r,i=o*(a/n);w(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;W(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){W(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){W(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];W(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let a=0;aa.$track?.offset||0,set(o){const{cues:n}=t.subtitle;if(!a.$track||0===n.length)return;const i=D(o,-10,10);a.$track.offset=i;for(let e=0;e{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,W(t,"airplay",{value(){n?(o.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){W(t,"quality",{set(e){const{controls:r,notice:a,i18n:o}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:n?.html||"",selector:e,onSelect:async e=>(await t.switchQuality(e.url),a.show=`${o.get("Switch Video")}: ${e.html}`,e.html)})}})}(t),Ot(t),function(t){const{i18n:e,notice:r,option:a,constructor:o,proxy:n,template:{$player:s,$video:l,$poster:c}}=t;let d=0;for(let p=0;p{t.emit(`video:${e.type}`,e)});t.on("video:canplay",()=>{d=0,t.loading.show=!1}),t.once("video:canplay",()=>{t.loading.show=!1,t.controls.show=!0,t.mask.show=!0,t.isReady=!0,t.emit("ready")}),t.on("video:ended",()=>{a.loop?(t.seek=0,t.play(),t.controls.show=!1,t.mask.show=!1):(t.controls.show=!0,t.mask.show=!0)}),t.on("video:error",async n=>{d{t.emit("resize"),p&&(t.loading.show=!1,t.controls.show=!0,t.mask.show=!0)}),t.on("video:loadstart",()=>{t.loading.show=!0,t.mask.show=!1,t.controls.show=!0}),t.on("video:pause",()=>{t.controls.show=!0,t.mask.show=!0}),t.on("video:play",()=>{t.mask.show=!1,w(c,"display","none")}),t.on("video:playing",()=>{t.mask.show=!1}),t.on("video:progress",()=>{t.playing&&(t.loading.show=!1)}),t.on("video:seeked",()=>{t.loading.show=!1,t.mask.show=!0}),t.on("video:seeking",()=>{t.loading.show=!0,t.mask.show=!1}),t.on("video:timeupdate",()=>{t.mask.show=!1}),t.on("video:waiting",()=>{t.loading.show=!0,t.mask.show=!1})}(t),function(t){const{option:e,storage:r,template:{$video:a,$poster:o}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(a.volume=D(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(a.volume=D(n,0,1)),e.poster&&w(o,"backgroundImage",`url(${e.poster})`),e.autoplay&&(a.autoplay=e.autoplay),e.playsInline&&(a.playsInline=!0,a["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Vt(t){const{notice:e,constructor:r,template:{$player:a,$video:o}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=o,r=document.documentElement.clientWidth,a=document.documentElement.clientHeight;return t>e&&ra}return t.on("fullscreenWeb",e=>{if(e){if(l()){const e=Number(r.AUTO_ORIENTATION_TIME??0);setTimeout(()=>{t.fullscreenWeb&&!v(a,n)&&function(){const e=O(),r=document.documentElement.clientWidth,o=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;w(a,"width",`${o}px`),w(a,"height",`${i}px`),w(a,"transform-origin","0 0"),w(a,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),f(a,n),t.isRotate=!0,t.emit("resize")}()},e)}}else v(a,n)&&(w(a,"width",""),w(a,"height",""),w(a,"transform-origin",""),w(a,"transform",""),g(a,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",async t=>{const r=!!screen?.orientation?.lock;if(t){if(r&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";await screen.orientation.lock(t),s=!0,f(a,i)}catch(o){s=!1,e.show=o}}else if(v(a,i)&&g(a,i),r&&s){try{screen.orientation.unlock()}catch{}s=!1}}),{name:"autoOrientation",get state(){return v(a,n)}}}function Yt(t){const{i18n:e,icons:r,storage:a,constructor:o,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=u(".art-auto-playback-last",s),c=u(".art-auto-playback-jump",s),d=u(".art-auto-playback-close",s);y(d,r.close);let p=null;function h(){const r=(a.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),w(s,"display","none"),r&&r>=o.AUTO_PLAYBACK_MIN&&(w(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${B(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{w(s,"display","none")}),n(c,"click",()=>{t.seek=r,t.play(),w(i,"display","none"),w(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{w(s,"display","none")},o.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=a.get("times")||{},r=Object.keys(e);r.length>o.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,a.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return a.get("times")||{}},clear:()=>a.del("times"),delete(t){const e=a.get("times")||{};return delete e[t],a.set("times",e),e}}}function Nt(t){const{constructor:e,proxy:r,template:{$player:a,$video:o}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,g(a,"art-fast-forward"))};return r(o,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,f(a,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return v(a,"art-fast-forward")}}}function Dt(t){const{layers:e,icons:r,template:{$player:a}}=t;function o(){return v(a,"art-lock")}function n(){f(a,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){g(a,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const a=y(e,r.lock),o=y(e,r.unlock);w(a,"display","none"),t.on("lock",t=>{t?(w(a,"display","inline-flex"),w(o,"display","none")):(w(a,"display","none"),w(o,"display","inline-flex"))})},click(){o()?i():n()}}),{name:"lock",get state(){return o()},set state(t){t?n():i()}}}function Ft(t){return t.on("control",e=>{e?g(t.template.$player,"art-mini-progress-bar"):f(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Bt{constructor(t){this.art=t,this.id=0;const{option:e}=t;e.miniProgressBar&&!e.isLive&&this.add(Ft),e.lock&&p&&this.add(Dt),e.autoPlayback&&!e.isLive&&this.add(Yt),e.autoOrientation&&p&&this.add(Vt),e.fastForward&&p&&!e.isLive&&this.add(Nt);for(let r=0;rthis.next(t,e)):this.next(t,e)}next(t,e){const r=e&&e.name||t.name||`plugin${this.id}`;return V(!U(this,r),`Cannot add a plugin that already has the same name: ${r}`),W(this,r,{value:e}),this}}class Ht extends pt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:a}}=t;this.name="setting",this.$parent=a,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=C(t,r.setting),a=C(t,this.$parent);!this.show||e||a||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,PLAYBACK_RATE:o}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:a,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:o.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,ASPECT_RATIO:o}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:a,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:o.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,FLIP:o}}=t;function n(t){return e.get(F(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:a,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:o.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:a}=t;return{width:a.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){for(let r=0;r{e.default=e===t,e.default&&e.$item&&$(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,a=[]){for(let o=0;oe}),W(n,"$parents",{get:()=>r}),W(n,"$option",{get:()=>t});const a=[];W(n,"$events",{get:()=>a}),W(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,a)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){const{controls:t,constructor:{SETTING_WIDTH:e,SETTING_ITEM_HEIGHT:r},template:{$player:a,$setting:o}}=this.art;if(t.setting&&this.show){const n=this.active[0]?.$parent?.width||e,{left:i,width:s}=A(t.setting),{left:l,width:c}=A(a),d=i-l+s/2-n/2;if(w(o,"height",`${this.active===this.option?this.active.length*r:(this.active.length+1)*r}px`),w(o,"width",`${n}px`),this.art.isRotate||p)return;d+n>c?(w(o,"left",null),w(o,"right",null)):(w(o,"left",`${d}px`),w(o,"right","auto"))}}inactivate(t){for(let e=0;e'),s=L("div");f(s,"art-setting-item-left-icon"),y(s,a),y(i,s),y(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),y(e,n)}createItem(t,e=!1){if(!this.cache.has(t.$option))return;const r=this.cache.get(t.$option),a=t.$item;let o="selector";U(t,"switch")&&(o="switch"),U(t,"range")&&(o="range"),U(t,"onClick")&&(o="button");const{icons:n,proxy:i,constructor:s}=this.art,l=L("div");f(l,"art-setting-item"),w(l,"height",`${s.SETTING_ITEM_HEIGHT}px`),l.dataset.name=t.name||"",l.dataset.value=t.value||"";const c=y(l,'
'),d=y(l,'
'),p=L("div");switch(f(p,"art-setting-item-left-icon"),o){case"button":case"switch":case"range":y(p,t.icon||n.config);break;case"selector":t.selector?.length?y(p,t.icon||n.config):y(p,n.check)}y(c,p),W(t,"$icon",{configurable:!0,get:()=>p}),W(t,"icon",{configurable:!0,get:()=>p.innerHTML,set(t){p.innerHTML="",y(p,t)}});const h=L("div");f(h,"art-setting-item-left-text"),y(h,t.html||""),y(c,h),W(t,"$html",{configurable:!0,get:()=>h}),W(t,"html",{configurable:!0,get:()=>h.innerHTML,set(t){h.innerHTML="",y(h,t)}});const u=L("div");switch(f(u,"art-setting-item-right-tooltip"),y(u,t.tooltip||""),y(d,u),W(t,"$tooltip",{configurable:!0,get:()=>u}),W(t,"tooltip",{configurable:!0,get:()=>u.innerHTML,set(t){u.innerHTML="",y(u,t)}}),o){case"switch":{const e=L("div");f(e,"art-setting-item-right-icon");const r=y(e,n.switchOn),a=y(e,n.switchOff);w(t.switch?a:r,"display","none"),y(d,e),W(t,"$switch",{configurable:!0,get:()=>e});let o=t.switch;W(t,"switch",{configurable:!0,get:()=>o,set(t){o=t,t?(w(a,"display","none"),w(r,"display",null)):(w(a,"display",null),w(r,"display","none"))}});break}case"range":{const e=L("div");f(e,"art-setting-item-right-icon");const r=y(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],f(r,"art-setting-range"),y(d,e),W(t,"$range",{configurable:!0,get:()=>r});let a=[...t.range];W(t,"range",{configurable:!0,get:()=>a,set(t){a=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(t.selector?.length){const t=L("div");f(t,"art-setting-item-right-icon"),y(t,n.arrowRight),y(d,t)}}switch(o){case"switch":if(t.onSwitch){const e=i(l,"click",async e=>{t.switch=await t.onSwitch.call(this.art,t,l,e)});t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=i(t.$range,"change",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onRange.call(this.art,t,l,e)});t.$events.push(e)}if(t.onChange){const e=i(t.$range,"input",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onChange.call(this.art,t,l,e)});t.$events.push(e)}}break;case"selector":{const e=i(l,"click",async e=>{t.selector?.length?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=await t.$parent.onSelect.call(this.art,t,l,e)))});t.$events.push(e),t.default&&f(l,"art-current")}break;case"button":if(t.onClick){const e=i(l,"click",async e=>{t.tooltip=await t.onClick.call(this.art,t,l,e)});t.$events.push(e)}}W(t,"$item",{configurable:!0,get:()=>l}),e?z(l,a):y(r,l),t.mounted&&setTimeout(()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){if(this.active=t,this.cache.has(t)){$(this.cache.get(t),"art-current")}else{const e=L("div");this.cache.set(t,e),f(e,"art-setting-panel"),y(this.$parent,e),$(e,"art-current"),t[0]?.$parent&&this.createHeader(t[0]);for(let r=0;rnull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){return this.art.template.$video?.textTracks?.[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?x(r,t):w(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?H(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(t,e={}){const{i18n:r,notice:a,option:o}=this.art,n={...o.subtitle,...e,url:t},i=await this.init(n);return e.name&&(a.show=`${r.get("Switch Subtitle")}: ${e.name}`),i}createTrack(t,e){const{template:r,proxy:a,option:o}=this.art,{$video:n,$track:i}=r,s=L("track");s.default=!0,s.kind=t,s.src=e,s.label=o.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,b(i),y(n,s),r.$track=s,this.destroyEvent=a(this.textTrack,"cuechange",()=>this.update())}async init(t){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(o(t,dt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||Y(t.url)){case"srt":{const e=G(r);return K(t.onVttLoad(e))}case"ass":{const e=Z(r);return K(t.onVttLoad(e))}case"vtt":return K(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null}}class qt{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=u(e.container),V(this.$container,`No container element found by ${e.container}`)),V(I(),"The current browser does not support flex layout");const a=this.$container.tagName.toLowerCase();V("div"===a,`Unsupported container element type, only support 'div' but got '${a}'`),V(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=t.id,this.init()}static get html(){return`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${n}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `}query(t){return u(t,this.$container)}init(){const{option:t}=this.art;if(t.useSSR||(this.$container.innerHTML=qt.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);V(e instanceof HTMLVideoElement||e instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),z(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&f(this.$player,"art-backdrop"),p&&f(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":f(this.$player,"art-destroy")}}class Xt{on(t,e,r){const a=this.e||(this.e={});return(a[t]||(a[t]=[])).push({fn:e,ctx:r}),this}once(t,e,r){const a=this;function o(...n){a.off(t,o),e.apply(r,n)}return o._=e,this.on(t,o,r)}emit(t,...e){const r=((this.e||(this.e={}))[t]||[]).slice();for(let a=0;ae.call(this,this)),Zt.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${Zt.version}`);for(let e=0;et(`Event@${e.type}`))}Kt.push(this)}static get instances(){return Kt}static get version(){return n}static get config(){return i}static get utils(){return et}static get scheme(){return dt}static get Emitter(){return Xt}static get validator(){return o}static get kindOf(){return o.kindOf}static get html(){return qt.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:l?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:navigator?.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){Zt.REMOVE_SRC_WHEN_DESTROY&&this.reset(),this.events.destroy(),this.template.destroy(t),Kt.splice(Kt.indexOf(this),1),this.isDestroy=!0,this.emit("destroy")}}return Zt.STYLE=jt,Zt.DEBUG=!1,Zt.CONTEXTMENU=!0,Zt.NOTICE_TIME=2e3,Zt.SETTING_WIDTH=250,Zt.SETTING_ITEM_WIDTH=200,Zt.SETTING_ITEM_HEIGHT=35,Zt.RESIZE_TIME=200,Zt.SCROLL_TIME=200,Zt.SCROLL_GAP=50,Zt.AUTO_PLAYBACK_MAX=10,Zt.AUTO_PLAYBACK_MIN=5,Zt.AUTO_PLAYBACK_TIMEOUT=3e3,Zt.RECONNECT_TIME_MAX=5,Zt.RECONNECT_SLEEP_TIME=1e3,Zt.CONTROL_HIDE_TIME=3e3,Zt.DBCLICK_TIME=300,Zt.DBCLICK_FULLSCREEN=!0,Zt.MOBILE_DBCLICK_PLAY=!0,Zt.MOBILE_CLICK_PLAY=!1,Zt.AUTO_ORIENTATION_TIME=200,Zt.INFO_LOOP_TIME=1e3,Zt.FAST_FORWARD_VALUE=3,Zt.FAST_FORWARD_TIME=1e3,Zt.TOUCH_MOVE_RATIO=.5,Zt.VOLUME_STEP=.1,Zt.SEEK_STEP=5,Zt.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],Zt.ASPECT_RATIO=["default","4:3","16:9"],Zt.FLIP=["normal","horizontal","vertical"],Zt.FULLSCREEN_WEB_IN_BODY=!0,Zt.LOG_VERSION=!0,Zt.USE_RAF=!1,Zt.REMOVE_SRC_WHEN_DESTROY=!0,h&&(M("artplayer-style",jt),setTimeout(()=>{Zt.LOG_VERSION&&console.log(`%c ArtPlayer %c ${Zt.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),Zt}); +!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";function t(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var e,r={exports:{}};var a=(e||(e=1,r.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var o=t(r);if("boolean"===o)return"boolean";if("string"===o)return"string";if("number"===o)return"number";if("symbol"===o)return"symbol";if("function"===o)return"GeneratorFunction"===a(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(a(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(o=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return o.slice(8,-1).toLowerCase().replace(/\s/g,"")};function a(t){return t.constructor?t.constructor.name:null}function o(t,e){var a=2=1,p=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(s)||d,h="undefined"!==typeof window&&"undefined"!==typeof document;function u(t,e=document){return e.querySelector(t)}function m(t,e=document){return Array.from(e.querySelectorAll(t))}function f(t,e){return t.classList.add(e)}function g(t,e){return t.classList.remove(e)}function v(t,e){return t.classList.contains(e)}function y(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function b(t){return t.parentNode.removeChild(t)}function w(t,e,r){return t.style[e]=r,t}function x(t,e){for(const r in e)w(t,r,e[r]);return t}function k(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function $(t,e){k(t).forEach(t=>g(t,e)),f(t,e)}function T(t,e,r="top"){p||(t.setAttribute("aria-label",e),f(t,"hint--rounded"),f(t,`hint--${r}`))}function E(t,e=0){const r=t.getBoundingClientRect(),a=window.innerHeight||document.documentElement.clientHeight,o=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=a&&r.top+r.height+e>=0,i=r.left-e<=o+e&&r.left+r.width+e>=0;return n&&i}function C(t,e){return R(t).includes(e)}function z(t,e){return e.parentNode.replaceChild(t,e),t}function L(t){return document.createElement(t)}function S(t="",e=""){const r=L("i");return f(r,"art-icon"),f(r,`art-icon-${t}`),y(r,e),r}function M(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function I(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function A(t){return t.getBoundingClientRect()}function P(t,e){return new Promise((r,a)=>{const o=new Image;o.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=o.width*e,n.height=o.height*e,i.drawImage(o,0,0,n.width,n.height),n.toBlob(e=>{const o=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(o),a(new Error(`Image load failed: ${t}`))},n.src=o})}else r(o)},o.onerror=function(){a(new Error(`Image load failed: ${t}`))},o.src=t})}function R(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function O(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class _ extends Error{constructor(t,e){super(t),"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function V(t,e){if(!t)throw new _(e);return t}function Y(t){return t.includes("?")?Y(t.split("?")[0]):t.includes("#")?Y(t.split("#")[0]):t.trim().toLowerCase().split(".").pop()}function N(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r)}function D(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function F(t){return t.charAt(0).toUpperCase()+t.slice(1)}function B(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),a=Math.floor(t-3600*e-60*r);return(e>0?[e,r,a]:[r,a]).map(t=>t<10?`0${t}`:String(t)).join(":")}function H(t){return t.replace(/[&<>'"]/g,t=>({"&":"&","<":"<",">":">","'":"'",'"':"""}[t]||t))}const W=Object.defineProperty,{hasOwnProperty:j}=Object.prototype;function U(t,e){return j.call(t,e)}function q(t,e){return Object.getOwnPropertyDescriptor(t,e)}function X(...t){const e=t=>t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(a=>{const o=t[a],n=r[a];Array.isArray(o)&&Array.isArray(n)?t[a]=o.concat(...n):e(o)&&e(n)?t[a]=X(o,n):t[a]=n}),t),{})}function G(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let a=r.slice(0,3);return 1===r.length&&(a=`${r}00`),2===r.length&&(a=`${r}0`),`${e},${a}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function K(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function Z(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const a=t.match(e);return a?{start:r(a[1].trim()),end:r(a[2].trim()),text:a[5].replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}:null}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function J(t=0){return new Promise(e=>setTimeout(e,t))}function Q(t,e){let r;return function(...a){clearTimeout(r),r=setTimeout(()=>(r=null,t.apply(this,a)),e)}}function tt(t,e){let r=!1;return function(...a){r||(t.apply(this,a),r=!0,setTimeout(()=>{r=!1},e))}}const et=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:_,addClass:f,append:y,assToVtt:Z,capitalize:F,clamp:D,createElement:L,debounce:Q,def:W,download:N,errorHandle:V,escape:H,get:q,getComposedPath:R,getExt:Y,getIcon:S,getRect:A,getSafeAreaInsets:O,getStyle:function(t,e,r=!0){const a=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(a):a},has:U,hasClass:v,includeFromEvent:C,inverseClass:$,isBrowser:h,isIOS:c,isIOS13:d,isInViewport:E,isMobile:p,isSafari:l,loadImg:P,mergeDeep:X,query:u,queryAll:m,remove:b,removeClass:g,replaceElement:z,secondToTime:B,setStyle:w,setStyleText:M,setStyles:x,siblings:k,sleep:J,srtToVtt:G,supportsFlex:I,throttle:tt,tooltip:T,unescape:function(t){const e={"&":"&","<":"<",">":">","'":"'",""":'"'},r=new RegExp(`(${Object.keys(e).join("|")})`,"g");return t.replace(r,t=>e[t]||t)},userAgent:s,vttToBlob:K},Symbol.toStringTag,{value:"Module"})),rt="array",at="boolean",ot="string",nt="number",it="object",st="function";function lt(t,e,r){return V(e===ot||e===nt||t instanceof Element,`${r.join(".")} require '${ot}' or 'Element' type`)}const ct={html:lt,disable:`?${at}`,name:`?${ot}`,index:`?${nt}`,style:`?${it}`,click:`?${st}`,mounted:`?${st}`,tooltip:`?${ot}|${nt}`,width:`?${nt}`,selector:`?${rt}`,onSelect:`?${st}`,switch:`?${at}`,onSwitch:`?${st}`,range:`?${rt}`,onRange:`?${st}`,onChange:`?${st}`},dt={id:ot,container:lt,url:ot,poster:ot,type:ot,theme:ot,lang:ot,volume:nt,isLive:at,muted:at,autoplay:at,autoSize:at,autoMini:at,loop:at,flip:at,playbackRate:at,aspectRatio:at,screenshot:at,setting:at,hotkey:at,pip:at,mutex:at,backdrop:at,fullscreen:at,fullscreenWeb:at,subtitleOffset:at,miniProgressBar:at,useSSR:at,playsInline:at,lock:at,gesture:at,fastForward:at,autoPlayback:at,autoOrientation:at,airplay:at,proxy:`?${st}`,plugins:[st],layers:[ct],contextmenu:[ct],settings:[ct],controls:[{...ct,position:(t,e,r)=>{const a=["top","left","right"];return V(a.includes(t),`${r.join(".")} only accept ${a.toString()} as parameters`)}}],quality:[{default:`?${at}`,html:ot,url:ot}],highlight:[{time:nt,text:ot}],thumbnails:{url:ot,number:nt,column:nt,width:nt,height:nt,scale:nt},subtitle:{url:ot,name:ot,type:ot,style:it,escape:at,encoding:ot,onVttLoad:st},moreVideoAttr:it,i18n:it,icons:it,cssVar:it,customType:it};class pt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return v(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?f(e,r):g(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",o(e,ct),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;V(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const a=L("div");f(a,`art-${this.name}`),f(a,`art-${this.name}-${r}`);const n=Array.from(this.$parent.children);a.dataset.index=e.index||this.id;const i=n.find(t=>Number(t.dataset.index)>=Number(a.dataset.index));i?i.insertAdjacentElement("beforebegin",a):y(this.$parent,a),e.html&&y(a,e.html),e.style&&x(a,e.style),e.tooltip&&T(a,e.tooltip);const s=[];if(e.click){const t=this.art.events.proxy(a,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});s.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,a,s),this[r]=a,this.cache.set(r,{$ref:a,events:s,option:e}),e.mounted&&e.mounted.call(this.art,a),a}remove(t){V(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],b(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class ht extends pt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,p||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:a}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:a}}=e,o=a.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return{...t,html:`${r.get("Play Speed")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.playbackRate=Number(a),t.show=!1)},mounted:t=>{const r=u('[data-value="1"]',t);r&&$(r,"art-current"),e.on("video:ratechange",()=>{const r=m("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&$(r,"art-current")})}}}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:a}}=e,o=a.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return{...t,html:`${r.get("Aspect Ratio")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.aspectRatio=a,t.show=!1)},mounted:t=>{const r=u('[data-value="default"]',t);r&&$(r,"art-current"),e.on("aspectRatio",e=>{const r=m("span",t).find(t=>t.dataset.value===e);r&&$(r,"art-current")})}}}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:a}}=e,o=a.map(t=>`${r.get(F(t))}`).join("");return{...t,html:`${r.get("Video Flip")}: ${o}`,click:(t,r)=>{const{value:a}=r.target.dataset;a&&(e.flip=a.toLowerCase(),t.show=!1)},mounted:t=>{const r=u('[data-value="normal"]',t);r&&$(r,"art-current"),e.on("flip",e=>{const r=m("span",t).find(t=>t.dataset.value===e);r&&$(r,"art-current")})}}}}({name:"flip",index:30})),this.add(function(t){return e=>({...t,html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){const e=h?location.href:"";return{...t,html:`ArtPlayer ${n}`}}({name:"version",index:50})),this.add(function(t){return e=>({...t,html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let o=0;o{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,o=t.clientY,{height:n,width:i,left:s,top:l}=A(r),{height:c,width:d}=A(a);let p=e-s,h=o-l;e+d>s+i&&(p=i-d),o+c>l+n&&(h=n-c),x(a,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{C(t,a)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}function ut(t,e){const{$progress:r}=t.template,{left:a}=A(r),o=D((p?e.touches[0].clientX:e.clientX)-a,0,r.clientWidth),n=o/r.clientWidth*t.duration;return{second:n,time:B(n),width:o,percentage:D(o/r.clientWidth,0,1)}}function mt(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,a=r*t.duration;t.emit("setBar","played",r,e),t.seek=a}else{const{second:r,percentage:a}=ut(t,e);t.emit("setBar","played",a,e),t.seek=r}}function ft(t){return e=>{const{icons:r,option:a,proxy:o}=e,{$player:n,$progress:i}=e.template;return{...t,html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=u(".art-progress-hover",t),d=u(".art-progress-loaded",t),h=u(".art-progress-played",t),m=u(".art-progress-highlight",t),v=u(".art-progress-indicator",t),b=u(".art-progress-tip",t);function x(r,a){const{width:o,time:n}=a||ut(e,r);b.textContent=n||"00:00";const i=b.clientWidth;o<=i/2?w(b,"left",0):o>t.clientWidth-i/2?w(b,"left",t.clientWidth-i+"px"):w(b,"left",o-i/2+"px")}r.indicator?y(v,r.indicator):w(v,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,a,o){const i="played"===r&&o&&p;if("loaded"===r&&w(d,"width",100*a+"%"),"hover"===r&&(w(c,"width",100*a+"%"),C(o,m)?function(r){const{width:a}=ut(e,r),{text:o}=r.target.dataset;b.textContent=o;const n=b.clientWidth;a<=n/2?w(b,"left",0):a>t.clientWidth-n/2?w(b,"left",t.clientWidth-n+"px"):w(b,"left",a-n/2+"px")}(o):x(o),0===a?g(n,"art-progress-hover"):f(n,"art-progress-hover")),"played"===r&&(w(h,"width",100*a+"%"),w(v,"left",100*a+"%")),i){f(n,"art-progress-hover");x(o,{width:t.clientWidth*a,time:B(a*e.duration)}),clearTimeout(s),s=setTimeout(()=>{g(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){m.textContent="";for(let t=0;t`;y(m,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),p||(o(i,"click",t=>{t.target!==v&&mt(e,t)}),o(i,"mousemove",t=>{const{percentage:r}=ut(e,t);e.emit("setBar","hover",r,t)}),o(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),o(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:a}=ut(e,t);e.emit("setBar","played",a,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}}}}class gt extends pt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:a}=this.art.template;t.on("mousemove",()=>{p||(this.show=!0)}),t.on("click",()=>{p?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=C(t,a)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(g(r,"art-hide-cursor"),f(r,"art-hover"),this.timer=Date.now()):(f(r,"art-hide-cursor"),g(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(ft({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.play),i=y(t,a.pause);function s(){w(n,"display","flex"),w(i,"display","none")}function l(){w(n,"display","none"),w(i,"display","flex")}T(n,o.get("Play")),T(i,o.get("Pause")),r(n,"click",()=>{e.play()}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:a}=e,o=y(t,a.volume),n=y(t,a.volumeClose),i=y(t,'
'),s=y(i,'
'),l=y(s,'
'),c=y(s,'
'),d=y(c,'
'),h=y(d,'
'),u=y(c,'
');function m(t){const{top:e,height:r}=A(c);return 1-(t.clientY-e)/r}function f(){if(e.muted||0===e.volume)w(o,"display","none"),w(n,"display","flex"),w(u,"top","100%"),w(h,"top","100%"),l.textContent=0;else{const t=100*e.volume;w(o,"display","flex"),w(n,"display","none"),w(u,"top",100-t+"%"),w(h,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(f(),e.on("video:volumechange",f),r(o,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),p)w(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=m(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=m(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>({...t,style:p?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${B(e.currentTime)} / ${B(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const a=["video:loadedmetadata","video:timeupdate","video:progress"];for(let o=0;o{this.art.quality=t.quality}),t.screenshot&&!p&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:a}=e;y(t,a.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e;y(t,a.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{T(t,o.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e;y(t,a.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{T(t,o.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:a}=e;y(t,a.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.fullscreenWebOn),i=y(t,a.fullscreenWebOff);w(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(T(t,o.get("Exit Web Fullscreen")),w(n,"display","none"),w(i,"display","inline-flex")):(T(t,o.get("Web Fullscreen")),w(n,"display","inline-flex"),w(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:a,i18n:o}=e,n=y(t,a.fullscreenOn),i=y(t,a.fullscreenOff);w(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(T(t,o.get("Exit Fullscreen")),w(n,"display","none"),w(i,"display","inline-flex")):(T(t,o.get("Fullscreen")),w(n,"display","inline-flex"),w(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),W(e,"$control_item",{get:()=>r}),W(e,"$control_value",{get:()=>o})}const i=a(n,"click",async e=>{const r=R(e),a=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(a),t.onSelect&&(o.innerHTML=await t.onSelect.call(this.art,a,a.$control_item,e))});r.push(i)}}function vt(t,e,r,a){const o=e-a,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(o)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,o);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}class yt{constructor(t){this.destroyEvents=new Set,this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:a,$video:o}}=t;function n(e){C(e,a)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(o,"click",e=>{const a=Date.now();i.push(a);const{MOBILE_CLICK_PLAY:o,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>a-t<=n);switch(c.length){case 1:t.emit("click",e),p?!t.isLock&&o&&t.toggle():t.toggle(),i=c;break;case 2:t.emit("dblclick",e),p?!t.isLock&&s&&t.toggle():l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{f(r,"art-hover"),t.emit("hover",!0,e)},e=>{g(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:a}=t;t.on("resize",()=>{const{aspectRatio:e,notice:a}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,a.show=""});const o=Q(()=>t.emit("resize"),a.RESIZE_TIME);t.on("window:orientationchange",()=>o()),t.on("window:resize",()=>o()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>o())}(t,this),function(t,e){if(p&&!t.option.isLive){const{$video:r,$progress:a}=t.template;let o=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){o===a&&mt(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:a,pageY:n}=e.touches[0],c=vt(i,s,a,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=D((a-i)/t.width,-1,1),d=D((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=o===r?t.constructor.TOUCH_MOVE_RATIO:1,u=D(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",D(u/t.duration,0,1),e),t.notice.show=`${B(u)} / ${B(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,o=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{o=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(a,"touchstart",t=>{o=a,c(t)}),e.proxy(a,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:a}}=t,o=tt(()=>{t.emit("view",E(a,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>o()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],a=["resize","scroll","orientationchange"],o=[];function n(n={}){for(let t=0;t{const a=n.document||i.ownerDocument||document,s=e.proxy(a,r,e=>{t.emit(`document:${r}`,e)});o.push(s)}),a.forEach(r=>{const a=n.window||i.ownerDocument?.defaultView||window,s=e.proxy(a,r,e=>{t.emit(`window:${r}`,e)});o.push(s)})}n(),e.bindGlobalEvents=n}(t,this),function(t){if(t.constructor.USE_RAF){let e=null;!function r(){t.playing&&t.emit("raf"),t.isDestroy||(e=requestAnimationFrame(r))}(),t.on("destroy",()=>{cancelAnimationFrame(e)})}}(t)}proxy(t,e,r,a={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,a));t.addEventListener(e,r,a);const o=()=>t.removeEventListener(e,r,a);return this.destroyEvents.add(o),o}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class bt{constructor(t){this.art=t,this.keys={},p||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{this.art.toggle()}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',state:'\n\n\n',play:'\n \n',pause:'\n \n',check:'\n\n',volume:'\n \n \n',volumeClose:'\n \n \n',screenshot:'\n\t\n\n',setting:'\n \n \n',pip:'\n\n',arrowLeft:'\n \n',arrowRight:'\n \n',playbackRate:'',aspectRatio:'',config:'',lock:'\n\n\n\n\n',flip:'\n\n\n\n\n\n',unlock:'\n\n\n',fullscreenOff:'\n\n\n\n\n',fullscreenOn:'\n\n\n\n\n',fullscreenWebOff:'\n\n\n\n\n',fullscreenWebOn:'\n\n\n\n\n',switchOn:'\n\n\n \n',switchOff:'\n\n\n \n\n',error:'\n\n\n\n\n',close:'\n\n\n\n\n',airplay:'\n \n \n \n \n\n',...t.option.icons};for(const r in e)W(this,r,{get:()=>S(r,e[r])})}}class $t extends pt{constructor(t){super(t),this.name="info",p||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:a,$video:o}}=this.art;t(a,"click",()=>{this.show=!1});let n=null;const i=m("[data-video]",r)||[];this.art.on("destroy",()=>clearTimeout(n)),function t(){for(let e=0;e{w(o,"display","none"),w(n,"display",null)}),a.proxy(e.$state,"click",()=>t.play())}}class zt{constructor(t){this.art=t,this.timer=null,t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){const{constructor:e,template:{$player:r,$noticeInner:a}}=this.art;t?(a.textContent=t instanceof Error?t.message.trim():t,f(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{a.textContent="",g(r,"art-notice-show")},e.NOTICE_TIME)):g(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}const Lt=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],St=(()=>{if("undefined"===typeof document)return!1;const t=Lt[0],e={};for(const r of Lt){if(r[1]in document){for(const[a,o]of r.entries())e[t[a]]=o;return e}}return!1})(),Mt={change:St.fullscreenchange,error:St.fullscreenerror},It={request:(t=document.documentElement,e)=>new Promise((r,a)=>{const o=()=>{It.off("change",o),r()};It.on("change",o);const n=t[St.requestFullscreen](e);n instanceof Promise&&n.then(o).catch(a)}),exit:()=>new Promise((t,e)=>{if(!It.isFullscreen)return void t();const r=()=>{It.off("change",r),t()};It.on("change",r);const a=document[St.exitFullscreen]();a instanceof Promise&&a.then(r).catch(e)}),toggle:(t,e)=>It.isFullscreen?It.exit():It.request(t,e),onchange(t){It.on("change",t)},onerror(t){It.on("error",t)},on(t,e){const r=Mt[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Mt[t];r&&document.removeEventListener(r,e,!1)},raw:St};function At(t){const{i18n:e,notice:r,template:{$video:a,$player:o}}=t;t.once("video:loadedmetadata",()=>{var n;It.isEnabled?(n=t,It.on("change",()=>{n.emit("fullscreen",It.isFullscreen),It.isFullscreen?(n.state="fullscreen",f(o,"art-fullscreen")):g(o,"art-fullscreen"),n.emit("resize")}),It.on("error",t=>{n.emit("fullscreenError",t)}),W(n,"fullscreen",{get:()=>It.isFullscreen,async set(t){t?await It.request(o):await It.exit()}})):a.webkitSupportsFullscreen?(t=>{t.on("document:webkitfullscreenchange",()=>{t.emit("fullscreen",t.fullscreen),t.emit("resize")}),W(t,"fullscreen",{get:()=>document.fullscreenElement===a,set(e){e?(t.state="fullscreen",a.webkitEnterFullscreen()):a.webkitExitFullscreen()}})})(t):W(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),W(t,"fullscreen",q(t,"fullscreen"))})}function Pt(t){const{icons:e,proxy:r,storage:a,template:{$player:o,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(g(o,"art-mini"),w(e,"display","none"),o.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(w(e,"display","none"),w(r,"display","flex")):(w(e,"display","flex"),w(r,"display","none"))}function p(){const{$mini:e}=t.template,r=A(e),o=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;a.set("top",o),a.set("left",n),w(e,"top",`${o}px`),w(e,"left",`${n}px`)}W(t,"mini",{get:()=>v(o,"art-mini"),set(h){if(h){t.state="mini",f(o,"art-mini");const h=function(){const{$mini:o}=t.template;if(o)return y(o,n),w(o,"display","flex");{const o=L("div");f(o,"art-mini-popup"),y(document.body,o),t.template.$mini=o,y(o,n);const p=y(o,'
');y(p,e.close),r(p,"click",c);const h=y(o,'
'),u=y(h,e.play),m=y(h,e.pause);return r(u,"click",()=>t.play()),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(o,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){f(o,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;w(o,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,g(o,"art-mini-dragging");const t=A(o);a.set("left",t.left),a.set("top",t.top),w(o,"left",`${t.left}px`),w(o,"top",`${t.top}px`),w(o,"transform",null)}}),o}}(),u=a.get("top"),m=a.get("left");"number"===typeof u&&"number"===typeof m?(w(h,"top",`${u}px`),w(h,"left",`${m}px`),E(h)||p()):p(),t.emit("mini",!0)}else c()}})}function Rt(t){const{i18n:e,notice:r,template:{$video:a}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:a}=t;e.disablePictureInPicture=!1,W(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw a.show=t,t})):document.exitPictureInPicture().catch(t=>{throw a.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):a.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),W(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):W(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ot(t){const{option:e,template:{$progress:r,$video:a}}=t;let o=null,n=!1,i=null;t.on("setBar",async(o,s,l)=>{const c=t.controls?.thumbnails,{url:d,scale:h}=e.thumbnails;if(!c||!d)return;if("hover"===o||"played"===o&&l&&p){if(i||n||(n=!0,i=await P(d,h),n=!1),!i)return;const o=r.clientWidth*s;o>0&&or.clientWidth-h/2?w(n,"left",r.clientWidth-h+"px"):w(n,"left",o-h/2+"px")}(o)}}),W(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(o),o=null,n=!1,i=null)}})}Object.defineProperties(It,{isFullscreen:{get:()=>Boolean(document[St.fullscreenElement])},element:{enumerable:!0,get:()=>document[St.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[St.fullscreenEnabled])}});class _t{constructor(t){!function(t){const{option:e,template:{$video:r}}=t;W(t,"url",{get:()=>r.src,async set(a){if(a){const o=t.url,n=e.type||Y(a),i=e.customType[n];n&&i?(await J(),t.loading.show=!0,i.call(t,r,a,t)):(URL.revokeObjectURL(o),r.src=a),o!==t.url&&(t.option.url=a,t.isReady&&o&&t.once("video:canplay",()=>{t.emit("restart",a)}))}else await J(),t.loading.show=!0}})}(t),function(t){const{template:{$video:e}}=t;W(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:a,constructor:{instances:o},template:{$video:n}}=t;W(t,"play",{async value(){const i=await n.play();if(r.show=e.get("Play"),t.emit("play"),a.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;W(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${B(t.currentTime)} / ${B(t.duration)}`),t.emit("seek",t.currentTime,r)}}),W(t,"forward",{set(e){t.seek=t.currentTime+e}}),W(t,"backward",{set(e){t.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:a,storage:o}=t;W(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=D(t,0,1),a.show=`${r.get("Volume")}: ${Number.parseInt(100*e.volume,10)}`,0!==e.volume&&o.set("volume",e.volume)}}),W(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;W(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{r=Number.parseFloat(r),Number.isNaN(r)||(e.currentTime=D(r,0,t.duration))}})}(t),function(t){W(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){function e(e,r){return new Promise((a,o)=>{if(e===t.url)return void a();const{playing:n,aspectRatio:i,playbackRate:s}=t;t.pause(),t.url=e,t.notice.show="";const l={error:e=>{t.off("video:canplay",l.canplay),t.off("video:loadedmetadata",l.metadata),o(e)},metadata:()=>{t.currentTime=r},canplay:async()=>{t.off("video:error",l.error),t.playbackRate=s,t.aspectRatio=i,n&&await t.play(),t.notice.show="",a()}};t.once("video:error",l.error),t.once("video:loadedmetadata",l.metadata),t.once("video:canplay",l.canplay)})}W(t,"switchQuality",{value:r=>e(r,t.currentTime)}),W(t,"switchUrl",{value:t=>e(t,0)}),W(t,"switch",{set:t.switchUrl})}(t),function(t){const{template:{$video:e},i18n:r,notice:a}=t;W(t,"playbackRate",{get:()=>e.playbackRate,set(o){if(o){if(o===e.playbackRate)return;e.playbackRate=o,a.show=`${r.get("Rate")}: ${1===o?r.get("Normal"):`${o}x`}`}else t.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:a,$player:o}}=t;W(t,"aspectRatio",{get:()=>o.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)w(a,"width",null),w(a,"height",null),w(a,"margin",null),delete o.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=o,i=e/r,s=t[0]/t[1];i>s?(w(a,"width",s*r+"px"),w(a,"height","100%"),w(a,"margin","0 auto")):(w(a,"width","100%"),w(a,"height",e/s+"px"),w(a,"margin","auto 0")),o.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,a=L("canvas");W(t,"getDataURL",{value:()=>new Promise((t,o)=>{try{a.width=r.videoWidth,a.height=r.videoHeight,a.getContext("2d").drawImage(r,0,0),t(a.toDataURL("image/png"))}catch(n){e.show=n,o(n)}})}),W(t,"getBlobUrl",{value:()=>new Promise((t,o)=>{try{a.width=r.videoWidth,a.height=r.videoHeight,a.getContext("2d").drawImage(r,0,0),a.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,o(n)}})}),W(t,"screenshot",{value:async e=>{const a=await t.getDataURL();return N(a,`${e||`artplayer_${B(r.currentTime)}`}.png`),t.emit("screenshot",a),a}})}(t),At(t),function(t){const{constructor:e,template:{$container:r,$player:a}}=t;let o="";W(t,"fullscreenWeb",{get:()=>v(a,"art-fullscreen-web"),set(n){n?(o=a.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&y(document.body,a),t.state="fullscreenWeb",w(a,"width","100%"),w(a,"height","100%"),f(a,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&y(r,a),o&&(a.style.cssText=o,o=""),g(a,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),Rt(t),function(t){const{$video:e}=t.template;W(t,"loaded",{get:()=>t.loadedTime/e.duration}),W(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){W(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;W(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:a}=t.template;W(t,"autoSize",{value(){const{videoWidth:o,videoHeight:n}=a,{width:i,height:s}=A(e),l=o/n;if(i/s>l)w(r,"width",s*l/i*100+"%"),w(r,"height","100%");else{const t=i/l/s*100;w(r,"width","100%"),w(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){W(t,"rect",{get:()=>A(t.template.$player)});const e=["bottom","height","left","right","top","width"];for(let r=0;rt.rect[a]})}W(t,"x",{get:()=>t.left+window.pageXOffset}),W(t,"y",{get:()=>t.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:a}=t;W(t,"flip",{get:()=>e.dataset.flip||"normal",set(o){o||(o="normal"),"normal"===o?delete e.dataset.flip:e.dataset.flip=o,a.show=`${r.get("Video Flip")}: ${r.get(F(o))}`,t.emit("flip",o)}})}(t),Pt(t),function(t){const{template:{$poster:e}}=t;W(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch{return""}},set(t){w(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;W(t,"autoHeight",{value(){const{clientWidth:a}=e,{videoHeight:o,videoWidth:n}=r,i=o*(a/n);w(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;W(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){W(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){W(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];W(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let a=0;aa.$track?.offset||0,set(o){const{cues:n}=t.subtitle;if(!a.$track||0===n.length)return;const i=D(o,-10,10);a.$track.offset=i;for(let e=0;e{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,W(t,"airplay",{value(){n?(o.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){W(t,"quality",{set(e){const{controls:r,notice:a,i18n:o}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:n?.html||"",selector:e,onSelect:async e=>(await t.switchQuality(e.url),a.show=`${o.get("Switch Video")}: ${e.html}`,e.html)})}})}(t),Ot(t),function(t){const{i18n:e,notice:r,option:a,constructor:o,proxy:n,template:{$player:s,$video:l,$poster:c}}=t;let d=0;for(let p=0;p{t.emit(`video:${e.type}`,e)});t.on("video:canplay",()=>{d=0,t.loading.show=!1}),t.once("video:canplay",()=>{t.loading.show=!1,t.controls.show=!0,t.mask.show=!0,t.isReady=!0,t.emit("ready")}),t.on("video:ended",()=>{a.loop?(t.seek=0,t.play(),t.controls.show=!1,t.mask.show=!1):(t.controls.show=!0,t.mask.show=!0)}),t.on("video:error",async n=>{d{t.emit("resize"),p&&(t.loading.show=!1,t.controls.show=!0,t.mask.show=!0)}),t.on("video:loadstart",()=>{t.loading.show=!0,t.mask.show=!1,t.controls.show=!0}),t.on("video:pause",()=>{t.controls.show=!0,t.mask.show=!0}),t.on("video:play",()=>{t.mask.show=!1,w(c,"display","none")}),t.on("video:playing",()=>{t.mask.show=!1}),t.on("video:progress",()=>{t.playing&&(t.loading.show=!1)}),t.on("video:seeked",()=>{t.loading.show=!1,t.mask.show=!0}),t.on("video:seeking",()=>{t.loading.show=!0,t.mask.show=!1}),t.on("video:timeupdate",()=>{t.mask.show=!1}),t.on("video:waiting",()=>{t.loading.show=!0,t.mask.show=!1})}(t),function(t){const{option:e,storage:r,template:{$video:a,$poster:o}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(a.volume=D(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(a.volume=D(n,0,1)),e.poster&&w(o,"backgroundImage",`url(${e.poster})`),e.autoplay&&(a.autoplay=e.autoplay),e.playsInline&&(a.playsInline=!0,a["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Vt(t){const{notice:e,constructor:r,template:{$player:a,$video:o}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=o,r=document.documentElement.clientWidth,a=document.documentElement.clientHeight;return t>e&&ra}return t.on("fullscreenWeb",e=>{if(e){if(l()){const e=Number(r.AUTO_ORIENTATION_TIME??0);setTimeout(()=>{t.fullscreenWeb&&!v(a,n)&&function(){const e=O(),r=document.documentElement.clientWidth,o=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;w(a,"width",`${o}px`),w(a,"height",`${i}px`),w(a,"transform-origin","0 0"),w(a,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),f(a,n),t.isRotate=!0,t.emit("resize")}()},e)}}else v(a,n)&&(w(a,"width",""),w(a,"height",""),w(a,"transform-origin",""),w(a,"transform",""),g(a,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",async t=>{const r=!!screen?.orientation?.lock;if(t){if(r&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";await screen.orientation.lock(t),s=!0,f(a,i)}catch(o){s=!1,e.show=o}}else if(v(a,i)&&g(a,i),r&&s){try{screen.orientation.unlock()}catch{}s=!1}}),{name:"autoOrientation",get state(){return v(a,n)}}}function Yt(t){const{i18n:e,icons:r,storage:a,constructor:o,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=u(".art-auto-playback-last",s),c=u(".art-auto-playback-jump",s),d=u(".art-auto-playback-close",s);y(d,r.close);let p=null;function h(){const r=(a.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),w(s,"display","none"),r&&r>=o.AUTO_PLAYBACK_MIN&&(w(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${B(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{w(s,"display","none")}),n(c,"click",()=>{t.seek=r,t.play(),w(i,"display","none"),w(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{w(s,"display","none")},o.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=a.get("times")||{},r=Object.keys(e);r.length>o.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,a.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return a.get("times")||{}},clear:()=>a.del("times"),delete(t){const e=a.get("times")||{};return delete e[t],a.set("times",e),e}}}function Nt(t){const{constructor:e,proxy:r,template:{$player:a,$video:o}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,g(a,"art-fast-forward"))};return r(o,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,f(a,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return v(a,"art-fast-forward")}}}function Dt(t){const{layers:e,icons:r,template:{$player:a}}=t;function o(){return v(a,"art-lock")}function n(){f(a,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){g(a,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const a=y(e,r.lock),o=y(e,r.unlock);w(a,"display","none"),t.on("lock",t=>{t?(w(a,"display","inline-flex"),w(o,"display","none")):(w(a,"display","none"),w(o,"display","inline-flex"))})},click(){o()?i():n()}}),{name:"lock",get state(){return o()},set state(t){t?n():i()}}}function Ft(t){return t.on("control",e=>{e?g(t.template.$player,"art-mini-progress-bar"):f(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Bt{constructor(t){this.art=t,this.id=0;const{option:e}=t;e.miniProgressBar&&!e.isLive&&this.add(Ft),e.lock&&p&&this.add(Dt),e.autoPlayback&&!e.isLive&&this.add(Yt),e.autoOrientation&&p&&this.add(Vt),e.fastForward&&p&&!e.isLive&&this.add(Nt);for(let r=0;rthis.next(t,e)):this.next(t,e)}next(t,e){const r=e&&e.name||t.name||`plugin${this.id}`;return V(!U(this,r),`Cannot add a plugin that already has the same name: ${r}`),W(this,r,{value:e}),this}}class Ht extends pt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:a}}=t;this.name="setting",this.$parent=a,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=C(t,r.setting),a=C(t,this.$parent);!this.show||e||a||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,PLAYBACK_RATE:o}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:a,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:o.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,ASPECT_RATIO:o}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:a,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:o.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:a,FLIP:o}}=t;function n(t){return e.get(F(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:a,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:o.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:a}=t;return{width:a.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){for(let r=0;r{e.default=e===t,e.default&&e.$item&&$(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,a=[]){for(let o=0;oe}),W(n,"$parents",{get:()=>r}),W(n,"$option",{get:()=>t});const a=[];W(n,"$events",{get:()=>a}),W(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,a)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){const{controls:t,constructor:{SETTING_WIDTH:e,SETTING_ITEM_HEIGHT:r},template:{$player:a,$setting:o}}=this.art;if(t.setting&&this.show){const n=this.active[0]?.$parent?.width||e,{left:i,width:s}=A(t.setting),{left:l,width:c}=A(a),d=i-l+s/2-n/2;if(w(o,"height",`${this.active===this.option?this.active.length*r:(this.active.length+1)*r}px`),w(o,"width",`${n}px`),this.art.isRotate||p)return;d+n>c?(w(o,"left",null),w(o,"right",null)):(w(o,"left",`${d}px`),w(o,"right","auto"))}}inactivate(t){for(let e=0;e'),s=L("div");f(s,"art-setting-item-left-icon"),y(s,a),y(i,s),y(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),y(e,n)}createItem(t,e=!1){if(!this.cache.has(t.$option))return;const r=this.cache.get(t.$option),a=t.$item;let o="selector";U(t,"switch")&&(o="switch"),U(t,"range")&&(o="range"),U(t,"onClick")&&(o="button");const{icons:n,proxy:i,constructor:s}=this.art,l=L("div");f(l,"art-setting-item"),w(l,"height",`${s.SETTING_ITEM_HEIGHT}px`),l.dataset.name=t.name||"",l.dataset.value=t.value||"";const c=y(l,'
'),d=y(l,'
'),p=L("div");switch(f(p,"art-setting-item-left-icon"),o){case"button":case"switch":case"range":y(p,t.icon||n.config);break;case"selector":t.selector?.length?y(p,t.icon||n.config):y(p,n.check)}y(c,p),W(t,"$icon",{configurable:!0,get:()=>p}),W(t,"icon",{configurable:!0,get:()=>p.innerHTML,set(t){p.innerHTML="",y(p,t)}});const h=L("div");f(h,"art-setting-item-left-text"),y(h,t.html||""),y(c,h),W(t,"$html",{configurable:!0,get:()=>h}),W(t,"html",{configurable:!0,get:()=>h.innerHTML,set(t){h.innerHTML="",y(h,t)}});const u=L("div");switch(f(u,"art-setting-item-right-tooltip"),y(u,t.tooltip||""),y(d,u),W(t,"$tooltip",{configurable:!0,get:()=>u}),W(t,"tooltip",{configurable:!0,get:()=>u.innerHTML,set(t){u.innerHTML="",y(u,t)}}),o){case"switch":{const e=L("div");f(e,"art-setting-item-right-icon");const r=y(e,n.switchOn),a=y(e,n.switchOff);w(t.switch?a:r,"display","none"),y(d,e),W(t,"$switch",{configurable:!0,get:()=>e});let o=t.switch;W(t,"switch",{configurable:!0,get:()=>o,set(t){o=t,t?(w(a,"display","none"),w(r,"display",null)):(w(a,"display",null),w(r,"display","none"))}});break}case"range":{const e=L("div");f(e,"art-setting-item-right-icon");const r=y(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],f(r,"art-setting-range"),y(d,e),W(t,"$range",{configurable:!0,get:()=>r});let a=[...t.range];W(t,"range",{configurable:!0,get:()=>a,set(t){a=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(t.selector?.length){const t=L("div");f(t,"art-setting-item-right-icon"),y(t,n.arrowRight),y(d,t)}}switch(o){case"switch":if(t.onSwitch){const e=i(l,"click",async e=>{t.switch=await t.onSwitch.call(this.art,t,l,e)});t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=i(t.$range,"change",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onRange.call(this.art,t,l,e)});t.$events.push(e)}if(t.onChange){const e=i(t.$range,"input",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onChange.call(this.art,t,l,e)});t.$events.push(e)}}break;case"selector":{const e=i(l,"click",async e=>{t.selector?.length?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=await t.$parent.onSelect.call(this.art,t,l,e)))});t.$events.push(e),t.default&&f(l,"art-current")}break;case"button":if(t.onClick){const e=i(l,"click",async e=>{t.tooltip=await t.onClick.call(this.art,t,l,e)});t.$events.push(e)}}W(t,"$item",{configurable:!0,get:()=>l}),e?z(l,a):y(r,l),t.mounted&&setTimeout(()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){if(this.active=t,this.cache.has(t)){$(this.cache.get(t),"art-current")}else{const e=L("div");this.cache.set(t,e),f(e,"art-setting-panel"),y(this.$parent,e),$(e,"art-current"),t[0]?.$parent&&this.createHeader(t[0]);for(let r=0;rnull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){return this.art.template.$video?.textTracks?.[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?x(r,t):w(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?H(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(t,e={}){const{i18n:r,notice:a,option:o}=this.art,n={...o.subtitle,...e,url:t},i=await this.init(n);return e.name&&(a.show=`${r.get("Switch Subtitle")}: ${e.name}`),i}createTrack(t,e){const{template:r,proxy:a,option:o}=this.art,{$video:n,$track:i}=r,s=L("track");s.default=!0,s.kind=t,s.src=e,s.label=o.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,b(i),y(n,s),r.$track=s,this.destroyEvent=a(this.textTrack,"cuechange",()=>this.update())}async init(t){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(o(t,dt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||Y(t.url)){case"srt":{const e=G(r);return K(t.onVttLoad(e))}case"ass":{const e=Z(r);return K(t.onVttLoad(e))}case"vtt":return K(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null}}class qt{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=u(e.container),V(this.$container,`No container element found by ${e.container}`)),V(I(),"The current browser does not support flex layout");const a=this.$container.tagName.toLowerCase();V("div"===a,`Unsupported container element type, only support 'div' but got '${a}'`),V(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=t.id,this.init()}static get html(){return`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${n}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `}query(t){return u(t,this.$container)}init(){const{option:t}=this.art;if(t.useSSR||(this.$container.innerHTML=qt.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);V(e instanceof HTMLVideoElement||e instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),z(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&f(this.$player,"art-backdrop"),p&&f(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":f(this.$player,"art-destroy")}}class Xt{on(t,e,r){const a=this.e||(this.e={});return(a[t]||(a[t]=[])).push({fn:e,ctx:r}),this}once(t,e,r){const a=this;function o(...n){a.off(t,o),e.apply(r,n)}return o._=e,this.on(t,o,r)}emit(t,...e){const r=((this.e||(this.e={}))[t]||[]).slice();for(let a=0;ae.call(this,this)),Zt.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${Zt.version}`);for(let e=0;et(`Event@${e.type}`))}Kt.push(this)}static get instances(){return Kt}static get version(){return n}static get config(){return i}static get utils(){return et}static get scheme(){return dt}static get Emitter(){return Xt}static get validator(){return o}static get kindOf(){return o.kindOf}static get html(){return qt.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:l?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:navigator?.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){Zt.REMOVE_SRC_WHEN_DESTROY&&this.reset(),this.events.destroy(),this.template.destroy(t),Kt.splice(Kt.indexOf(this),1),this.isDestroy=!0,this.emit("destroy")}}return Zt.STYLE=jt,Zt.DEBUG=!1,Zt.CONTEXTMENU=!0,Zt.NOTICE_TIME=2e3,Zt.SETTING_WIDTH=250,Zt.SETTING_ITEM_WIDTH=200,Zt.SETTING_ITEM_HEIGHT=35,Zt.RESIZE_TIME=200,Zt.SCROLL_TIME=200,Zt.SCROLL_GAP=50,Zt.AUTO_PLAYBACK_MAX=10,Zt.AUTO_PLAYBACK_MIN=5,Zt.AUTO_PLAYBACK_TIMEOUT=3e3,Zt.RECONNECT_TIME_MAX=5,Zt.RECONNECT_SLEEP_TIME=1e3,Zt.CONTROL_HIDE_TIME=3e3,Zt.DBCLICK_TIME=300,Zt.DBCLICK_FULLSCREEN=!0,Zt.MOBILE_DBCLICK_PLAY=!0,Zt.MOBILE_CLICK_PLAY=!1,Zt.AUTO_ORIENTATION_TIME=200,Zt.INFO_LOOP_TIME=1e3,Zt.FAST_FORWARD_VALUE=3,Zt.FAST_FORWARD_TIME=1e3,Zt.TOUCH_MOVE_RATIO=.5,Zt.VOLUME_STEP=.1,Zt.SEEK_STEP=5,Zt.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],Zt.ASPECT_RATIO=["default","4:3","16:9"],Zt.FLIP=["normal","horizontal","vertical"],Zt.FULLSCREEN_WEB_IN_BODY=!0,Zt.LOG_VERSION=!0,Zt.USE_RAF=!1,Zt.REMOVE_SRC_WHEN_DESTROY=!0,h&&(M("artplayer-style",jt),setTimeout(()=>{Zt.LOG_VERSION&&console.log(`%c ArtPlayer %c ${Zt.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),Zt}); diff --git a/packages/artplayer/dist/artplayer.legacy.js b/packages/artplayer/dist/artplayer.legacy.js index deb358eb6..85e7d8eca 100644 --- a/packages/artplayer/dist/artplayer.legacy.js +++ b/packages/artplayer/dist/artplayer.legacy.js @@ -4,4 +4,4 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";var t,e=Object.defineProperty,r=Object.defineProperties,o=Object.getOwnPropertyDescriptors,a=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(t,r,o)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[r]=o,l=(t,e)=>{for(var r in e||(e={}))n.call(e,r)&&s(t,r,e[r]);if(a)for(var r of a(e))i.call(e,r)&&s(t,r,e[r]);return t},c=(t,e)=>r(t,o(e)),d=(t,e,r)=>new Promise((o,a)=>{var n=t=>{try{s(r.next(t))}catch(e){a(e)}},i=t=>{try{s(r.throw(t))}catch(e){a(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(n,i);s((r=r.apply(t,e)).next())});function p(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var h,u={exports:{}};var m=(h||(h=1,u.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var a=t(r);if("boolean"===a)return"boolean";if("string"===a)return"string";if("number"===a)return"number";if("symbol"===a)return"symbol";if("function"===a)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(a=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return a.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function a(t,e){var o=2=1,k=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(y)||x,$="undefined"!==typeof window&&"undefined"!==typeof document;function T(t,e=document){return e.querySelector(t)}function E(t,e=document){return Array.from(e.querySelectorAll(t))}function C(t,e){return t.classList.add(e)}function z(t,e){return t.classList.remove(e)}function L(t,e){return t.classList.contains(e)}function S(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function M(t){return t.parentNode.removeChild(t)}function I(t,e,r){return t.style[e]=r,t}function P(t,e){for(const r in e)I(t,r,e[r]);return t}function A(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function O(t,e){A(t).forEach(t=>z(t,e)),C(t,e)}function R(t,e,r="top"){k||(t.setAttribute("aria-label",e),C(t,"hint--rounded"),C(t,`hint--${r}`))}function _(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,a=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=a+e&&r.left+r.width+e>=0;return n&&i}function V(t,e){return j(t).includes(e)}function Y(t,e){return e.parentNode.replaceChild(t,e),t}function N(t){return document.createElement(t)}function D(t="",e=""){const r=N("i");return C(r,"art-icon"),C(r,`art-icon-${t}`),S(r,e),r}function F(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function B(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function H(t){return t.getBoundingClientRect()}function W(t,e){return new Promise((r,o)=>{const a=new Image;a.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=a.width*e,n.height=a.height*e,i.drawImage(a,0,0,n.width,n.height),n.toBlob(e=>{const a=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(a),o(new Error(`Image load failed: ${t}`))},n.src=a})}else r(a)},a.onerror=function(){o(new Error(`Image load failed: ${t}`))},a.src=t})}function j(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function U(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class q extends Error{constructor(t,e){super(t),"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function X(t,e){if(!t)throw new q(e);return t}function G(t){return t.includes("?")?G(t.split("?")[0]):t.includes("#")?G(t.split("#")[0]):t.trim().toLowerCase().split(".").pop()}function K(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r)}function Z(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function J(t){return t.charAt(0).toUpperCase()+t.slice(1)}function Q(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}function tt(t){return t.replace(/[&<>'"]/g,t=>({"&":"&","<":"<",">":">","'":"'",'"':"""}[t]||t))}const et=Object.defineProperty,{hasOwnProperty:rt}=Object.prototype;function ot(t,e){return rt.call(t,e)}function at(t,e){return Object.getOwnPropertyDescriptor(t,e)}function nt(...t){const e=t=>t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const a=t[o],n=r[o];Array.isArray(a)&&Array.isArray(n)?t[o]=a.concat(...n):e(a)&&e(n)?t[o]=nt(a,n):t[o]=n}),t),{})}function it(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function st(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function lt(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);return o?{start:r(o[1].trim()),end:r(o[2].trim()),text:o[5].replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}:null}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function ct(t=0){return new Promise(e=>setTimeout(e,t))}function dt(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=null,t.apply(this,o)),e)}}function pt(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const ht=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:q,addClass:C,append:S,assToVtt:lt,capitalize:J,clamp:Z,createElement:N,debounce:dt,def:et,download:K,errorHandle:X,escape:tt,get:at,getComposedPath:j,getExt:G,getIcon:D,getRect:H,getSafeAreaInsets:U,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:ot,hasClass:L,includeFromEvent:V,inverseClass:O,isBrowser:$,isIOS:w,isIOS13:x,isInViewport:_,isMobile:k,isSafari:b,loadImg:W,mergeDeep:nt,query:T,queryAll:E,remove:M,removeClass:z,replaceElement:Y,secondToTime:Q,setStyle:I,setStyleText:F,setStyles:P,siblings:A,sleep:ct,srtToVtt:it,supportsFlex:B,throttle:pt,tooltip:R,unescape:function(t){const e={"&":"&","<":"<",">":">","'":"'",""":'"'},r=new RegExp(`(${Object.keys(e).join("|")})`,"g");return t.replace(r,t=>e[t]||t)},userAgent:y,vttToBlob:st},Symbol.toStringTag,{value:"Module"})),ut="array",mt="boolean",ft="string",gt="number",vt="object",yt="function";function bt(t,e,r){return X(e===ft||e===gt||t instanceof Element,`${r.join(".")} require '${ft}' or 'Element' type`)}const wt={html:bt,disable:`?${mt}`,name:`?${ft}`,index:`?${gt}`,style:`?${vt}`,click:`?${yt}`,mounted:`?${yt}`,tooltip:`?${ft}|${gt}`,width:`?${gt}`,selector:`?${ut}`,onSelect:`?${yt}`,switch:`?${mt}`,onSwitch:`?${yt}`,range:`?${ut}`,onRange:`?${yt}`,onChange:`?${yt}`},xt={id:ft,container:bt,url:ft,poster:ft,type:ft,theme:ft,lang:ft,volume:gt,isLive:mt,muted:mt,autoplay:mt,autoSize:mt,autoMini:mt,loop:mt,flip:mt,playbackRate:mt,aspectRatio:mt,screenshot:mt,setting:mt,hotkey:mt,pip:mt,mutex:mt,backdrop:mt,fullscreen:mt,fullscreenWeb:mt,subtitleOffset:mt,miniProgressBar:mt,useSSR:mt,playsInline:mt,lock:mt,gesture:mt,fastForward:mt,autoPlayback:mt,autoOrientation:mt,airplay:mt,proxy:`?${yt}`,plugins:[yt],layers:[wt],contextmenu:[wt],settings:[wt],controls:[c(l({},wt),{position:(t,e,r)=>{const o=["top","left","right"];return X(o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}})],quality:[{default:`?${mt}`,html:ft,url:ft}],highlight:[{time:gt,text:ft}],thumbnails:{url:ft,number:gt,column:gt,width:gt,height:gt,scale:gt},subtitle:{url:ft,name:ft,type:ft,style:vt,escape:mt,encoding:ft,onVttLoad:yt},moreVideoAttr:vt,i18n:vt,icons:vt,cssVar:vt,customType:vt};class kt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return L(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?C(e,r):z(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",f(e,wt),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;X(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const o=N("div");C(o,`art-${this.name}`),C(o,`art-${this.name}-${r}`);const a=Array.from(this.$parent.children);o.dataset.index=e.index||this.id;const n=a.find(t=>Number(t.dataset.index)>=Number(o.dataset.index));n?n.insertAdjacentElement("beforebegin",o):S(this.$parent,o),e.html&&S(o,e.html),e.style&&P(o,e.style),e.tooltip&&R(o,e.tooltip);const i=[];if(e.click){const t=this.art.events.proxy(o,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});i.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,o,i),this[r]=o,this.cache.set(r,{$ref:o,events:i,option:e}),e.mounted&&e.mounted.call(this.art,o),o}remove(t){X(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],M(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class $t extends kt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,k||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:o}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,a=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return c(l({},t),{html:`${r.get("Play Speed")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const r=T('[data-value="1"]',t);r&&O(r,"art-current"),e.on("video:ratechange",()=>{const r=E("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&O(r,"art-current")})}})}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,a=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return c(l({},t),{html:`${r.get("Aspect Ratio")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const r=T('[data-value="default"]',t);r&&O(r,"art-current"),e.on("aspectRatio",e=>{const r=E("span",t).find(t=>t.dataset.value===e);r&&O(r,"art-current")})}})}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,a=o.map(t=>`${r.get(J(t))}`).join("");return c(l({},t),{html:`${r.get("Video Flip")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const r=T('[data-value="normal"]',t);r&&O(r,"art-current"),e.on("flip",e=>{const r=E("span",t).find(t=>t.dataset.value===e);r&&O(r,"art-current")})}})}}({name:"flip",index:30})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){const e=$?location.href:"";return c(l({},t),{html:`ArtPlayer ${g}`})}({name:"version",index:50})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,a=t.clientY,{height:n,width:i,left:s,top:l}=H(r),{height:c,width:d}=H(o);let p=e-s,h=a-l;e+d>s+i&&(p=i-d),a+c>l+n&&(h=n-c),P(o,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{V(t,o)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}function Tt(t,e){const{$progress:r}=t.template,{left:o}=H(r),a=Z((k?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),n=a/r.clientWidth*t.duration;return{second:n,time:Q(n),width:a,percentage:Z(a/r.clientWidth,0,1)}}function Et(t,e){if(t.isRotate){const r=e.touches[0].clientY/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=Tt(t,e);t.emit("setBar","played",o,e),t.seek=r}}function Ct(t){return e=>{const{icons:r,option:o,proxy:a}=e,{$player:n,$progress:i}=e.template;return c(l({},t),{html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=T(".art-progress-hover",t),d=T(".art-progress-loaded",t),p=T(".art-progress-played",t),h=T(".art-progress-highlight",t),u=T(".art-progress-indicator",t),m=T(".art-progress-tip",t);function f(r,o){const{width:a,time:n}=o||Tt(e,r);m.textContent=n||"00:00";const i=m.clientWidth;a<=i/2?I(m,"left",0):a>t.clientWidth-i/2?I(m,"left",t.clientWidth-i+"px"):I(m,"left",a-i/2+"px")}r.indicator?S(u,r.indicator):I(u,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,o,a){const i="played"===r&&a&&k;if("loaded"===r&&I(d,"width",100*o+"%"),"hover"===r&&(I(c,"width",100*o+"%"),V(a,h)?function(r){const{width:o}=Tt(e,r),{text:a}=r.target.dataset;m.textContent=a;const n=m.clientWidth;o<=n/2?I(m,"left",0):o>t.clientWidth-n/2?I(m,"left",t.clientWidth-n+"px"):I(m,"left",o-n/2+"px")}(a):f(a),0===o?z(n,"art-progress-hover"):C(n,"art-progress-hover")),"played"===r&&(I(p,"width",100*o+"%"),I(u,"left",100*o+"%")),i){C(n,"art-progress-hover");f(a,{width:t.clientWidth*o,time:Q(o*e.duration)}),clearTimeout(s),s=setTimeout(()=>{z(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){h.textContent="";for(let t=0;t`;S(h,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),k||(a(i,"click",t=>{t.target!==u&&Et(e,t)}),a(i,"mousemove",t=>{const{percentage:r}=Tt(e,t);e.emit("setBar","hover",r,t)}),a(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),a(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:o}=Tt(e,t);e.emit("setBar","played",o,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}})}}class zt extends kt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;t.on("mousemove",()=>{k||(this.show=!0)}),t.on("click",()=>{k?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=V(t,o)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(z(r,"art-hide-cursor"),C(r,"art-hover"),this.timer=Date.now()):(C(r,"art-hide-cursor"),z(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(Ct({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.play),i=S(t,o.pause);function s(){I(n,"display","flex"),I(i,"display","none")}function l(){I(n,"display","none"),I(i,"display","flex")}R(n,a.get("Play")),R(i,a.get("Pause")),r(n,"click",()=>{e.play()}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o}=e,a=S(t,o.volume),n=S(t,o.volumeClose),i=S(t,'
'),s=S(i,'
'),l=S(s,'
'),c=S(s,'
'),d=S(c,'
'),p=S(d,'
'),h=S(c,'
');function u(t){const{top:e,height:r}=H(c);return 1-(t.clientY-e)/r}function m(){if(e.muted||0===e.volume)I(a,"display","none"),I(n,"display","flex"),I(h,"top","100%"),I(p,"top","100%"),l.textContent=0;else{const t=100*e.volume;I(a,"display","flex"),I(n,"display","none"),I(h,"top",100-t+"%"),I(p,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(m(),e.on("video:volumechange",m),r(a,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),k)I(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=u(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=u(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>c(l({},t),{style:k?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${Q(e.currentTime)} / ${Q(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const o=["video:loadedmetadata","video:timeupdate","video:progress"];for(let a=0;a{this.art.quality=t.quality}),t.screenshot&&!k&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:o}=e;S(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;S(t,o.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{R(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;S(t,o.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{R(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:o}=e;S(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.fullscreenWebOn),i=S(t,o.fullscreenWebOff);I(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(R(t,a.get("Exit Web Fullscreen")),I(n,"display","none"),I(i,"display","inline-flex")):(R(t,a.get("Web Fullscreen")),I(n,"display","inline-flex"),I(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.fullscreenOn),i=S(t,o.fullscreenOff);I(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(R(t,a.get("Exit Fullscreen")),I(n,"display","none"),I(i,"display","inline-flex")):(R(t,a.get("Fullscreen")),I(n,"display","inline-flex"),I(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),et(e,"$control_item",{get:()=>r}),et(e,"$control_value",{get:()=>a})}const i=o(n,"click",e=>d(this,null,function*(){const r=j(e),o=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(o),t.onSelect&&(a.innerHTML=yield t.onSelect.call(this.art,o,o.$control_item,e))}));r.push(i)}}function Lt(t,e,r,o){const a=e-o,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(a)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,a);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}class St{constructor(t){this.destroyEvents=new Set,this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:a}}=t;function n(e){V(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(a,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:a,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=n);switch(c.length){case 1:t.emit("click",e),k?!t.isLock&&a&&t.toggle():t.toggle(),i=c;break;case 2:t.emit("dblclick",e),k?!t.isLock&&s&&t.toggle():l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{C(r,"art-hover"),t.emit("hover",!0,e)},e=>{z(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const a=dt(()=>t.emit("resize"),o.RESIZE_TIME);t.on("window:orientationchange",()=>a()),t.on("window:resize",()=>a()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>a())}(t,this),function(t,e){if(k&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let a=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){a===o&&Et(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:o,pageY:n}=e.touches[0],c=Lt(i,s,o,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=Z((o-i)/t.width,-1,1),d=Z((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=a===r?t.constructor.TOUCH_MOVE_RATIO:1,u=Z(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",Z(u/t.duration,0,1),e),t.notice.show=`${Q(u)} / ${Q(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,a=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{a=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{a=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,a=pt(()=>{t.emit("view",_(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>a()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],a=[];function n(n={}){for(let t=0;t{const o=n.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});a.push(s)}),o.forEach(r=>{var o;const s=n.window||(null==(o=i.ownerDocument)?void 0:o.defaultView)||window,l=e.proxy(s,r,e=>{t.emit(`window:${r}`,e)});a.push(l)})}n(),e.bindGlobalEvents=n}(t,this),function(t){if(t.constructor.USE_RAF){let e=null;!function r(){t.playing&&t.emit("raf"),t.isDestroy||(e=requestAnimationFrame(r))}(),t.on("destroy",()=>{cancelAnimationFrame(e)})}}(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));t.addEventListener(e,r,o);const a=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(a),a}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class Mt{constructor(t){this.art=t,this.keys={},k||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{this.art.toggle()}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',state:'\n\n\n',play:'\n \n',pause:'\n \n',check:'\n\n',volume:'\n \n \n',volumeClose:'\n \n \n',screenshot:'\n\t\n\n',setting:'\n \n \n',pip:'\n\n',arrowLeft:'\n \n',arrowRight:'\n \n',playbackRate:'',aspectRatio:'',config:'',lock:'\n\n\n\n\n',flip:'\n\n\n\n\n\n',unlock:'\n\n\n',fullscreenOff:'\n\n\n\n\n',fullscreenOn:'\n\n\n\n\n',fullscreenWebOff:'\n\n\n\n\n',fullscreenWebOn:'\n\n\n\n\n',switchOn:'\n\n\n \n',switchOff:'\n\n\n \n\n',error:'\n\n\n\n\n',close:'\n\n\n\n\n',airplay:'\n \n \n \n \n\n'},t.option.icons);for(const r in e)et(this,r,{get:()=>D(r,e[r])})}}class Ot extends kt{constructor(t){super(t),this.name="info",k||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:a}}=this.art;t(o,"click",()=>{this.show=!1});let n=null;const i=E("[data-video]",r)||[];this.art.on("destroy",()=>clearTimeout(n)),function t(){for(let e=0;e{I(a,"display","none"),I(n,"display",null)}),o.proxy(e.$state,"click",()=>t.play())}}class Yt{constructor(t){this.art=t,this.timer=null,t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,C(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",z(r,"art-notice-show")},e.NOTICE_TIME)):z(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}const Nt=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],Dt=(()=>{if("undefined"===typeof document)return!1;const t=Nt[0],e={};for(const r of Nt){if(r[1]in document){for(const[o,a]of r.entries())e[t[o]]=a;return e}}return!1})(),Ft={change:Dt.fullscreenchange,error:Dt.fullscreenerror},Bt={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const a=()=>{Bt.off("change",a),r()};Bt.on("change",a);const n=t[Dt.requestFullscreen](e);n instanceof Promise&&n.then(a).catch(o)}),exit:()=>new Promise((t,e)=>{if(!Bt.isFullscreen)return void t();const r=()=>{Bt.off("change",r),t()};Bt.on("change",r);const o=document[Dt.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>Bt.isFullscreen?Bt.exit():Bt.request(t,e),onchange(t){Bt.on("change",t)},onerror(t){Bt.on("error",t)},on(t,e){const r=Ft[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Ft[t];r&&document.removeEventListener(r,e,!1)},raw:Dt};function Ht(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t,n=t=>{Bt.on("change",()=>{t.emit("fullscreen",Bt.isFullscreen),Bt.isFullscreen?(t.state="fullscreen",C(a,"art-fullscreen")):z(a,"art-fullscreen"),t.emit("resize")}),Bt.on("error",e=>{t.emit("fullscreenError",e)}),et(t,"fullscreen",{get:()=>Bt.isFullscreen,set(t){return d(this,null,function*(){t?yield Bt.request(a):yield Bt.exit()})}})};t.once("video:loadedmetadata",()=>{var a;Bt.isEnabled?n(t):o.webkitSupportsFullscreen?((a=t).on("document:webkitfullscreenchange",()=>{a.emit("fullscreen",a.fullscreen),a.emit("resize")}),et(a,"fullscreen",{get:()=>document.fullscreenElement===o,set(t){t?(a.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})):et(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),et(t,"fullscreen",at(t,"fullscreen"))})}function Wt(t){const{icons:e,proxy:r,storage:o,template:{$player:a,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(z(a,"art-mini"),I(e,"display","none"),a.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(I(e,"display","none"),I(r,"display","flex")):(I(e,"display","flex"),I(r,"display","none"))}function p(){const{$mini:e}=t.template,r=H(e),a=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;o.set("top",a),o.set("left",n),I(e,"top",`${a}px`),I(e,"left",`${n}px`)}et(t,"mini",{get:()=>L(a,"art-mini"),set(h){if(h){t.state="mini",C(a,"art-mini");const h=function(){const{$mini:a}=t.template;if(a)return S(a,n),I(a,"display","flex");{const a=N("div");C(a,"art-mini-popup"),S(document.body,a),t.template.$mini=a,S(a,n);const p=S(a,'
');S(p,e.close),r(p,"click",c);const h=S(a,'
'),u=S(h,e.play),m=S(h,e.pause);return r(u,"click",()=>t.play()),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(a,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){C(a,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;I(a,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,z(a,"art-mini-dragging");const t=H(a);o.set("left",t.left),o.set("top",t.top),I(a,"left",`${t.left}px`),I(a,"top",`${t.top}px`),I(a,"transform",null)}}),a}}(),u=o.get("top"),m=o.get("left");"number"===typeof u&&"number"===typeof m?(I(h,"top",`${u}px`),I(h,"left",`${m}px`),_(h)||p()):p(),t.emit("mini",!0)}else c()}})}function jt(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,et(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),et(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):et(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ut(t){const{option:e,template:{$progress:r,$video:o}}=t;let a=null,n=!1,i=null;t.on("setBar",(a,s,l)=>d(null,null,function*(){var c;const d=null==(c=t.controls)?void 0:c.thumbnails,{url:p,scale:h}=e.thumbnails;if(!d||!p)return;if("hover"===a||"played"===a&&l&&k){if(i||n||(n=!0,i=yield W(p,h),n=!1),!i)return;const a=r.clientWidth*s;a>0&&ar.clientWidth-u/2?I(s,"left",r.clientWidth-u+"px"):I(s,"left",a-u/2+"px")}(a)}})),et(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(a),a=null,n=!1,i=null)}})}Object.defineProperties(Bt,{isFullscreen:{get:()=>Boolean(document[Dt.fullscreenElement])},element:{enumerable:!0,get:()=>document[Dt.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[Dt.fullscreenEnabled])}});class qt{constructor(t){!function(t){const{option:e,template:{$video:r}}=t;et(t,"url",{get:()=>r.src,set(o){return d(this,null,function*(){if(o){const a=t.url,n=e.type||G(o),i=e.customType[n];n&&i?(yield ct(),t.loading.show=!0,i.call(t,r,o,t)):(URL.revokeObjectURL(a),r.src=o),a!==t.url&&(t.option.url=o,t.isReady&&a&&t.once("video:canplay",()=>{t.emit("restart",o)}))}else yield ct(),t.loading.show=!0})}})}(t),function(t){const{template:{$video:e}}=t;et(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:a},template:{$video:n}}=t;et(t,"play",{value(){return d(this,null,function*(){const i=yield n.play();if(r.show=e.get("Play"),t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;et(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${Q(t.currentTime)} / ${Q(t.duration)}`),t.emit("seek",t.currentTime,r)}}),et(t,"forward",{set(e){t.seek=t.currentTime+e}}),et(t,"backward",{set(e){t.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:a}=t;et(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=Z(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(100*e.volume,10)}`,0!==e.volume&&a.set("volume",e.volume)}}),et(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;et(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{r=Number.parseFloat(r),Number.isNaN(r)||(e.currentTime=Z(r,0,t.duration))}})}(t),function(t){et(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){function e(e,r){return new Promise((o,a)=>{if(e===t.url)return void o();const{playing:n,aspectRatio:i,playbackRate:s}=t;t.pause(),t.url=e,t.notice.show="";const l={error:e=>{t.off("video:canplay",l.canplay),t.off("video:loadedmetadata",l.metadata),a(e)},metadata:()=>{t.currentTime=r},canplay:()=>d(null,null,function*(){t.off("video:error",l.error),t.playbackRate=s,t.aspectRatio=i,n&&(yield t.play()),t.notice.show="",o()})};t.once("video:error",l.error),t.once("video:loadedmetadata",l.metadata),t.once("video:canplay",l.canplay)})}et(t,"switchQuality",{value:r=>e(r,t.currentTime)}),et(t,"switchUrl",{value:t=>e(t,0)}),et(t,"switch",{set:t.switchUrl})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t;et(t,"playbackRate",{get:()=>e.playbackRate,set(a){if(a){if(a===e.playbackRate)return;e.playbackRate=a,o.show=`${r.get("Rate")}: ${1===a?r.get("Normal"):`${a}x`}`}else t.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t;et(t,"aspectRatio",{get:()=>a.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)I(o,"width",null),I(o,"height",null),I(o,"margin",null),delete a.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=a,i=e/r,s=t[0]/t[1];i>s?(I(o,"width",s*r+"px"),I(o,"height","100%"),I(o,"margin","0 auto")):(I(o,"width","100%"),I(o,"height",e/s+"px"),I(o,"margin","auto 0")),a.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=N("canvas");et(t,"getDataURL",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(n){e.show=n,a(n)}})}),et(t,"getBlobUrl",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,a(n)}})}),et(t,"screenshot",{value:e=>d(null,null,function*(){const o=yield t.getDataURL();return K(o,`${e||`artplayer_${Q(r.currentTime)}`}.png`),t.emit("screenshot",o),o})})}(t),Ht(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let a="";et(t,"fullscreenWeb",{get:()=>L(o,"art-fullscreen-web"),set(n){n?(a=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&S(document.body,o),t.state="fullscreenWeb",I(o,"width","100%"),I(o,"height","100%"),C(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&S(r,o),a&&(o.style.cssText=a,a=""),z(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),jt(t),function(t){const{$video:e}=t.template;et(t,"loaded",{get:()=>t.loadedTime/e.duration}),et(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){et(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;et(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;et(t,"autoSize",{value(){const{videoWidth:a,videoHeight:n}=o,{width:i,height:s}=H(e),l=a/n;if(i/s>l)I(r,"width",s*l/i*100+"%"),I(r,"height","100%");else{const t=i/l/s*100;I(r,"width","100%"),I(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){et(t,"rect",{get:()=>H(t.template.$player)});const e=["bottom","height","left","right","top","width"];for(let r=0;rt.rect[o]})}et(t,"x",{get:()=>t.left+window.pageXOffset}),et(t,"y",{get:()=>t.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;et(t,"flip",{get:()=>e.dataset.flip||"normal",set(a){a||(a="normal"),"normal"===a?delete e.dataset.flip:e.dataset.flip=a,o.show=`${r.get("Video Flip")}: ${r.get(J(a))}`,t.emit("flip",a)}})}(t),Wt(t),function(t){const{template:{$poster:e}}=t;et(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch(t){return""}},set(t){I(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;et(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:a,videoWidth:n}=r,i=a*(o/n);I(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;et(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){et(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){et(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];et(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;o{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,et(t,"airplay",{value(){n?(a.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){et(t,"quality",{set(e){const{controls:r,notice:o,i18n:a}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:(null==n?void 0:n.html)||"",selector:e,onSelect(e){return d(this,null,function*(){return yield t.switchQuality(e.url),o.show=`${a.get("Switch Video")}: ${e.html}`,e.html})}})}})}(t),Ut(t),function(t){const{i18n:e,notice:r,option:o,constructor:a,proxy:n,template:{$player:i,$video:s,$poster:l}}=t;let c=0;for(let d=0;d{t.emit(`video:${e.type}`,e)});t.on("video:canplay",()=>{c=0,t.loading.show=!1}),t.once("video:canplay",()=>{t.loading.show=!1,t.controls.show=!0,t.mask.show=!0,t.isReady=!0,t.emit("ready")}),t.on("video:ended",()=>{o.loop?(t.seek=0,t.play(),t.controls.show=!1,t.mask.show=!1):(t.controls.show=!0,t.mask.show=!0)}),t.on("video:error",n=>d(null,null,function*(){c{t.emit("resize"),k&&(t.loading.show=!1,t.controls.show=!0,t.mask.show=!0)}),t.on("video:loadstart",()=>{t.loading.show=!0,t.mask.show=!1,t.controls.show=!0}),t.on("video:pause",()=>{t.controls.show=!0,t.mask.show=!0}),t.on("video:play",()=>{t.mask.show=!1,I(l,"display","none")}),t.on("video:playing",()=>{t.mask.show=!1}),t.on("video:progress",()=>{t.playing&&(t.loading.show=!1)}),t.on("video:seeked",()=>{t.loading.show=!1,t.mask.show=!0}),t.on("video:seeking",()=>{t.loading.show=!0,t.mask.show=!1}),t.on("video:timeupdate",()=>{t.mask.show=!1}),t.on("video:waiting",()=>{t.loading.show=!0,t.mask.show=!1})}(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:a}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=Z(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(o.volume=Z(n,0,1)),e.poster&&I(a,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Xt(t){const{notice:e,constructor:r,template:{$player:o,$video:a}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=a,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{var a;if(e){if(l()){const e=Number(null!=(a=r.AUTO_ORIENTATION_TIME)?a:0);setTimeout(()=>{t.fullscreenWeb&&!L(o,n)&&function(){const e=U(),r=document.documentElement.clientWidth,a=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;I(o,"width",`${a}px`),I(o,"height",`${i}px`),I(o,"transform-origin","0 0"),I(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),C(o,n),t.isRotate=!0,t.emit("resize")}()},e)}}else L(o,n)&&(I(o,"width",""),I(o,"height",""),I(o,"transform-origin",""),I(o,"transform",""),z(o,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",t=>d(null,null,function*(){var r;const a=!!(null==(r=null==screen?void 0:screen.orientation)?void 0:r.lock);if(t){if(a&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";yield screen.orientation.lock(t),s=!0,C(o,i)}catch(n){s=!1,e.show=n}}else if(L(o,i)&&z(o,i),a&&s){try{screen.orientation.unlock()}catch(c){}s=!1}})),{name:"autoOrientation",get state(){return L(o,n)}}}function Gt(t){const{i18n:e,icons:r,storage:o,constructor:a,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=T(".art-auto-playback-last",s),c=T(".art-auto-playback-jump",s),d=T(".art-auto-playback-close",s);S(d,r.close);let p=null;function h(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),I(s,"display","none"),r&&r>=a.AUTO_PLAYBACK_MIN&&(I(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${Q(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{I(s,"display","none")}),n(c,"click",()=>{t.seek=r,t.play(),I(i,"display","none"),I(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{I(s,"display","none")},a.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>a.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function Kt(t){const{constructor:e,proxy:r,template:{$player:o,$video:a}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,z(o,"art-fast-forward"))};return r(a,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,C(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return L(o,"art-fast-forward")}}}function Zt(t){const{layers:e,icons:r,template:{$player:o}}=t;function a(){return L(o,"art-lock")}function n(){C(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){z(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=S(e,r.lock),a=S(e,r.unlock);I(o,"display","none"),t.on("lock",t=>{t?(I(o,"display","inline-flex"),I(a,"display","none")):(I(o,"display","none"),I(a,"display","inline-flex"))})},click(){a()?i():n()}}),{name:"lock",get state(){return a()},set state(t){t?n():i()}}}function Jt(t){return t.on("control",e=>{e?z(t.template.$player,"art-mini-progress-bar"):C(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Qt{constructor(t){this.art=t,this.id=0;const{option:e}=t;e.miniProgressBar&&!e.isLive&&this.add(Jt),e.lock&&k&&this.add(Zt),e.autoPlayback&&!e.isLive&&this.add(Gt),e.autoOrientation&&k&&this.add(Xt),e.fastForward&&k&&!e.isLive&&this.add(Kt);for(let r=0;rthis.next(t,e)):this.next(t,e)}next(t,e){const r=e&&e.name||t.name||`plugin${this.id}`;return X(!ot(this,r),`Cannot add a plugin that already has the same name: ${r}`),et(this,r,{value:e}),this}}class te extends kt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=V(t,r.setting),o=V(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:a}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:a.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:a}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:a.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:a}}=t;function n(t){return e.get(J(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:a.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){var r;for(let o=0;o{e.default=e===t,e.default&&e.$item&&O(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let a=0;ae}),et(n,"$parents",{get:()=>r}),et(n,"$option",{get:()=>t});const o=[];et(n,"$events",{get:()=>o}),et(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){var t,e;const{controls:r,constructor:{SETTING_WIDTH:o,SETTING_ITEM_HEIGHT:a},template:{$player:n,$setting:i}}=this.art;if(r.setting&&this.show){const s=(null==(e=null==(t=this.active[0])?void 0:t.$parent)?void 0:e.width)||o,{left:l,width:c}=H(r.setting),{left:d,width:p}=H(n),h=l-d+c/2-s/2;if(I(i,"height",`${this.active===this.option?this.active.length*a:(this.active.length+1)*a}px`),I(i,"width",`${s}px`),this.art.isRotate||k)return;h+s>p?(I(i,"left",null),I(i,"right",null)):(I(i,"left",`${h}px`),I(i,"right","auto"))}}inactivate(t){for(let e=0;e'),s=N("div");C(s,"art-setting-item-left-icon"),S(s,o),S(i,s),S(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),S(e,n)}createItem(t,e=!1){var r,o;if(!this.cache.has(t.$option))return;const a=this.cache.get(t.$option),n=t.$item;let i="selector";ot(t,"switch")&&(i="switch"),ot(t,"range")&&(i="range"),ot(t,"onClick")&&(i="button");const{icons:s,proxy:l,constructor:c}=this.art,p=N("div");C(p,"art-setting-item"),I(p,"height",`${c.SETTING_ITEM_HEIGHT}px`),p.dataset.name=t.name||"",p.dataset.value=t.value||"";const h=S(p,'
'),u=S(p,'
'),m=N("div");switch(C(m,"art-setting-item-left-icon"),i){case"button":case"switch":case"range":S(m,t.icon||s.config);break;case"selector":(null==(r=t.selector)?void 0:r.length)?S(m,t.icon||s.config):S(m,s.check)}S(h,m),et(t,"$icon",{configurable:!0,get:()=>m}),et(t,"icon",{configurable:!0,get:()=>m.innerHTML,set(t){m.innerHTML="",S(m,t)}});const f=N("div");C(f,"art-setting-item-left-text"),S(f,t.html||""),S(h,f),et(t,"$html",{configurable:!0,get:()=>f}),et(t,"html",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",S(f,t)}});const g=N("div");switch(C(g,"art-setting-item-right-tooltip"),S(g,t.tooltip||""),S(u,g),et(t,"$tooltip",{configurable:!0,get:()=>g}),et(t,"tooltip",{configurable:!0,get:()=>g.innerHTML,set(t){g.innerHTML="",S(g,t)}}),i){case"switch":{const e=N("div");C(e,"art-setting-item-right-icon");const r=S(e,s.switchOn),o=S(e,s.switchOff);I(t.switch?o:r,"display","none"),S(u,e),et(t,"$switch",{configurable:!0,get:()=>e});let a=t.switch;et(t,"switch",{configurable:!0,get:()=>a,set(t){a=t,t?(I(o,"display","none"),I(r,"display",null)):(I(o,"display",null),I(r,"display","none"))}});break}case"range":{const e=N("div");C(e,"art-setting-item-right-icon");const r=S(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],C(r,"art-setting-range"),S(u,e),et(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];et(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(null==(o=t.selector)?void 0:o.length){const t=N("div");C(t,"art-setting-item-right-icon"),S(t,s.arrowRight),S(u,t)}}switch(i){case"switch":if(t.onSwitch){const e=l(p,"click",e=>d(this,null,function*(){t.switch=yield t.onSwitch.call(this.art,t,p,e)}));t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=l(t.$range,"change",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onRange.call(this.art,t,p,e)}));t.$events.push(e)}if(t.onChange){const e=l(t.$range,"input",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onChange.call(this.art,t,p,e)}));t.$events.push(e)}}break;case"selector":{const e=l(p,"click",e=>d(this,null,function*(){var r;(null==(r=t.selector)?void 0:r.length)?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=yield t.$parent.onSelect.call(this.art,t,p,e)))}));t.$events.push(e),t.default&&C(p,"art-current")}break;case"button":if(t.onClick){const e=l(p,"click",e=>d(this,null,function*(){t.tooltip=yield t.onClick.call(this.art,t,p,e)}));t.$events.push(e)}}et(t,"$item",{configurable:!0,get:()=>p}),e?Y(p,n):S(a,p),t.mounted&&setTimeout(()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){var e;if(this.active=t,this.cache.has(t)){O(this.cache.get(t),"art-current")}else{const r=N("div");this.cache.set(t,r),C(r,"art-setting-panel"),S(this.$parent,r),O(r,"art-current"),(null==(e=t[0])?void 0:e.$parent)&&this.createHeader(t[0]);for(let e=0;enull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){var t,e;return null==(e=null==(t=this.art.template.$video)?void 0:t.textTracks)?void 0:e[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?P(r,t):I(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?tt(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}switch(t){return d(this,arguments,function*(t,e={}){const{i18n:r,notice:o,option:a}=this.art,n=c(l(l({},a.subtitle),e),{url:t}),i=yield this.init(n);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i})}createTrack(t,e){const{template:r,proxy:o,option:a}=this.art,{$video:n,$track:i}=r,s=N("track");s.default=!0,s.kind=t,s.src=e,s.label=a.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,M(i),S(n,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}init(t){return d(this,null,function*(){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(f(t,xt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||G(t.url)){case"srt":{const e=it(r);return st(t.onVttLoad(e))}case"ass":{const e=lt(r);return st(t.onVttLoad(e))}case"vtt":return st(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null})}}class ae{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=T(e.container),X(this.$container,`No container element found by ${e.container}`)),X(B(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();X("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),X(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=t.id,this.init()}static get html(){return`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${g}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `}query(t){return T(t,this.$container)}init(){const{option:t}=this.art;if(t.useSSR||(this.$container.innerHTML=ae.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);X(e instanceof HTMLVideoElement||e instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),Y(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&C(this.$player,"art-backdrop"),k&&C(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":C(this.$player,"art-destroy")}}class ne{on(t,e,r){const o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:r}),this}once(t,e,r){const o=this;function a(...n){o.off(t,a),e.apply(r,n)}return a._=e,this.on(t,a,r)}emit(t,...e){const r=((this.e||(this.e={}))[t]||[]).slice();for(let o=0;oe.call(this,this)),le.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${le.version}`);for(let e=0;et(`Event@${e.type}`))}se.push(this)}static get instances(){return se}static get version(){return g}static get config(){return v}static get utils(){return ht}static get scheme(){return xt}static get Emitter(){return ne}static get validator(){return f}static get kindOf(){return f.kindOf}static get html(){return ae.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:b?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:null==navigator?void 0:navigator.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){le.REMOVE_SRC_WHEN_DESTROY&&this.reset(),this.events.destroy(),this.template.destroy(t),se.splice(se.indexOf(this),1),this.isDestroy=!0,this.emit("destroy")}}return le.STYLE=re,le.DEBUG=!1,le.CONTEXTMENU=!0,le.NOTICE_TIME=2e3,le.SETTING_WIDTH=250,le.SETTING_ITEM_WIDTH=200,le.SETTING_ITEM_HEIGHT=35,le.RESIZE_TIME=200,le.SCROLL_TIME=200,le.SCROLL_GAP=50,le.AUTO_PLAYBACK_MAX=10,le.AUTO_PLAYBACK_MIN=5,le.AUTO_PLAYBACK_TIMEOUT=3e3,le.RECONNECT_TIME_MAX=5,le.RECONNECT_SLEEP_TIME=1e3,le.CONTROL_HIDE_TIME=3e3,le.DBCLICK_TIME=300,le.DBCLICK_FULLSCREEN=!0,le.MOBILE_DBCLICK_PLAY=!0,le.MOBILE_CLICK_PLAY=!1,le.AUTO_ORIENTATION_TIME=200,le.INFO_LOOP_TIME=1e3,le.FAST_FORWARD_VALUE=3,le.FAST_FORWARD_TIME=1e3,le.TOUCH_MOVE_RATIO=.5,le.VOLUME_STEP=.1,le.SEEK_STEP=5,le.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],le.ASPECT_RATIO=["default","4:3","16:9"],le.FLIP=["normal","horizontal","vertical"],le.FULLSCREEN_WEB_IN_BODY=!0,le.LOG_VERSION=!0,le.USE_RAF=!1,le.REMOVE_SRC_WHEN_DESTROY=!0,$&&(F("artplayer-style",re),setTimeout(()=>{le.LOG_VERSION&&console.log(`%c ArtPlayer %c ${le.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),le}); +!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";var t,e=Object.defineProperty,r=Object.defineProperties,o=Object.getOwnPropertyDescriptors,a=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(t,r,o)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[r]=o,l=(t,e)=>{for(var r in e||(e={}))n.call(e,r)&&s(t,r,e[r]);if(a)for(var r of a(e))i.call(e,r)&&s(t,r,e[r]);return t},c=(t,e)=>r(t,o(e)),d=(t,e,r)=>new Promise((o,a)=>{var n=t=>{try{s(r.next(t))}catch(e){a(e)}},i=t=>{try{s(r.throw(t))}catch(e){a(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(n,i);s((r=r.apply(t,e)).next())});function p(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var h,u={exports:{}};var m=(h||(h=1,u.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var a=t(r);if("boolean"===a)return"boolean";if("string"===a)return"string";if("number"===a)return"number";if("symbol"===a)return"symbol";if("function"===a)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(a=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return a.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function a(t,e){var o=2=1,k=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(y)||x,$="undefined"!==typeof window&&"undefined"!==typeof document;function T(t,e=document){return e.querySelector(t)}function E(t,e=document){return Array.from(e.querySelectorAll(t))}function C(t,e){return t.classList.add(e)}function z(t,e){return t.classList.remove(e)}function L(t,e){return t.classList.contains(e)}function S(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function M(t){return t.parentNode.removeChild(t)}function I(t,e,r){return t.style[e]=r,t}function P(t,e){for(const r in e)I(t,r,e[r]);return t}function A(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function O(t,e){A(t).forEach(t=>z(t,e)),C(t,e)}function R(t,e,r="top"){k||(t.setAttribute("aria-label",e),C(t,"hint--rounded"),C(t,`hint--${r}`))}function _(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,a=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=a+e&&r.left+r.width+e>=0;return n&&i}function V(t,e){return j(t).includes(e)}function Y(t,e){return e.parentNode.replaceChild(t,e),t}function N(t){return document.createElement(t)}function D(t="",e=""){const r=N("i");return C(r,"art-icon"),C(r,`art-icon-${t}`),S(r,e),r}function F(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function B(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function H(t){return t.getBoundingClientRect()}function W(t,e){return new Promise((r,o)=>{const a=new Image;a.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=a.width*e,n.height=a.height*e,i.drawImage(a,0,0,n.width,n.height),n.toBlob(e=>{const a=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(a),o(new Error(`Image load failed: ${t}`))},n.src=a})}else r(a)},a.onerror=function(){o(new Error(`Image load failed: ${t}`))},a.src=t})}function j(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function U(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class q extends Error{constructor(t,e){super(t),"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function X(t,e){if(!t)throw new q(e);return t}function G(t){return t.includes("?")?G(t.split("?")[0]):t.includes("#")?G(t.split("#")[0]):t.trim().toLowerCase().split(".").pop()}function K(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r)}function Z(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function J(t){return t.charAt(0).toUpperCase()+t.slice(1)}function Q(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}function tt(t){return t.replace(/[&<>'"]/g,t=>({"&":"&","<":"<",">":">","'":"'",'"':"""}[t]||t))}const et=Object.defineProperty,{hasOwnProperty:rt}=Object.prototype;function ot(t,e){return rt.call(t,e)}function at(t,e){return Object.getOwnPropertyDescriptor(t,e)}function nt(...t){const e=t=>t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const a=t[o],n=r[o];Array.isArray(a)&&Array.isArray(n)?t[o]=a.concat(...n):e(a)&&e(n)?t[o]=nt(a,n):t[o]=n}),t),{})}function it(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function st(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function lt(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);return o?{start:r(o[1].trim()),end:r(o[2].trim()),text:o[5].replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}:null}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function ct(t=0){return new Promise(e=>setTimeout(e,t))}function dt(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=null,t.apply(this,o)),e)}}function pt(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const ht=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:q,addClass:C,append:S,assToVtt:lt,capitalize:J,clamp:Z,createElement:N,debounce:dt,def:et,download:K,errorHandle:X,escape:tt,get:at,getComposedPath:j,getExt:G,getIcon:D,getRect:H,getSafeAreaInsets:U,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:ot,hasClass:L,includeFromEvent:V,inverseClass:O,isBrowser:$,isIOS:w,isIOS13:x,isInViewport:_,isMobile:k,isSafari:b,loadImg:W,mergeDeep:nt,query:T,queryAll:E,remove:M,removeClass:z,replaceElement:Y,secondToTime:Q,setStyle:I,setStyleText:F,setStyles:P,siblings:A,sleep:ct,srtToVtt:it,supportsFlex:B,throttle:pt,tooltip:R,unescape:function(t){const e={"&":"&","<":"<",">":">","'":"'",""":'"'},r=new RegExp(`(${Object.keys(e).join("|")})`,"g");return t.replace(r,t=>e[t]||t)},userAgent:y,vttToBlob:st},Symbol.toStringTag,{value:"Module"})),ut="array",mt="boolean",ft="string",gt="number",vt="object",yt="function";function bt(t,e,r){return X(e===ft||e===gt||t instanceof Element,`${r.join(".")} require '${ft}' or 'Element' type`)}const wt={html:bt,disable:`?${mt}`,name:`?${ft}`,index:`?${gt}`,style:`?${vt}`,click:`?${yt}`,mounted:`?${yt}`,tooltip:`?${ft}|${gt}`,width:`?${gt}`,selector:`?${ut}`,onSelect:`?${yt}`,switch:`?${mt}`,onSwitch:`?${yt}`,range:`?${ut}`,onRange:`?${yt}`,onChange:`?${yt}`},xt={id:ft,container:bt,url:ft,poster:ft,type:ft,theme:ft,lang:ft,volume:gt,isLive:mt,muted:mt,autoplay:mt,autoSize:mt,autoMini:mt,loop:mt,flip:mt,playbackRate:mt,aspectRatio:mt,screenshot:mt,setting:mt,hotkey:mt,pip:mt,mutex:mt,backdrop:mt,fullscreen:mt,fullscreenWeb:mt,subtitleOffset:mt,miniProgressBar:mt,useSSR:mt,playsInline:mt,lock:mt,gesture:mt,fastForward:mt,autoPlayback:mt,autoOrientation:mt,airplay:mt,proxy:`?${yt}`,plugins:[yt],layers:[wt],contextmenu:[wt],settings:[wt],controls:[c(l({},wt),{position:(t,e,r)=>{const o=["top","left","right"];return X(o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}})],quality:[{default:`?${mt}`,html:ft,url:ft}],highlight:[{time:gt,text:ft}],thumbnails:{url:ft,number:gt,column:gt,width:gt,height:gt,scale:gt},subtitle:{url:ft,name:ft,type:ft,style:vt,escape:mt,encoding:ft,onVttLoad:yt},moreVideoAttr:vt,i18n:vt,icons:vt,cssVar:vt,customType:vt};class kt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return L(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?C(e,r):z(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",f(e,wt),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;X(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const o=N("div");C(o,`art-${this.name}`),C(o,`art-${this.name}-${r}`);const a=Array.from(this.$parent.children);o.dataset.index=e.index||this.id;const n=a.find(t=>Number(t.dataset.index)>=Number(o.dataset.index));n?n.insertAdjacentElement("beforebegin",o):S(this.$parent,o),e.html&&S(o,e.html),e.style&&P(o,e.style),e.tooltip&&R(o,e.tooltip);const i=[];if(e.click){const t=this.art.events.proxy(o,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});i.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,o,i),this[r]=o,this.cache.set(r,{$ref:o,events:i,option:e}),e.mounted&&e.mounted.call(this.art,o),o}remove(t){X(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],M(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class $t extends kt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,k||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:o}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,a=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return c(l({},t),{html:`${r.get("Play Speed")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const r=T('[data-value="1"]',t);r&&O(r,"art-current"),e.on("video:ratechange",()=>{const r=E("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&O(r,"art-current")})}})}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,a=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return c(l({},t),{html:`${r.get("Aspect Ratio")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const r=T('[data-value="default"]',t);r&&O(r,"art-current"),e.on("aspectRatio",e=>{const r=E("span",t).find(t=>t.dataset.value===e);r&&O(r,"art-current")})}})}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,a=o.map(t=>`${r.get(J(t))}`).join("");return c(l({},t),{html:`${r.get("Video Flip")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const r=T('[data-value="normal"]',t);r&&O(r,"art-current"),e.on("flip",e=>{const r=E("span",t).find(t=>t.dataset.value===e);r&&O(r,"art-current")})}})}}({name:"flip",index:30})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){const e=$?location.href:"";return c(l({},t),{html:`ArtPlayer ${g}`})}({name:"version",index:50})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,a=t.clientY,{height:n,width:i,left:s,top:l}=H(r),{height:c,width:d}=H(o);let p=e-s,h=a-l;e+d>s+i&&(p=i-d),a+c>l+n&&(h=n-c),P(o,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{V(t,o)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}function Tt(t,e){const{$progress:r}=t.template,{left:o}=H(r),a=Z((k?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),n=a/r.clientWidth*t.duration;return{second:n,time:Q(n),width:a,percentage:Z(a/r.clientWidth,0,1)}}function Et(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=Tt(t,e);t.emit("setBar","played",o,e),t.seek=r}}function Ct(t){return e=>{const{icons:r,option:o,proxy:a}=e,{$player:n,$progress:i}=e.template;return c(l({},t),{html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=T(".art-progress-hover",t),d=T(".art-progress-loaded",t),p=T(".art-progress-played",t),h=T(".art-progress-highlight",t),u=T(".art-progress-indicator",t),m=T(".art-progress-tip",t);function f(r,o){const{width:a,time:n}=o||Tt(e,r);m.textContent=n||"00:00";const i=m.clientWidth;a<=i/2?I(m,"left",0):a>t.clientWidth-i/2?I(m,"left",t.clientWidth-i+"px"):I(m,"left",a-i/2+"px")}r.indicator?S(u,r.indicator):I(u,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,o,a){const i="played"===r&&a&&k;if("loaded"===r&&I(d,"width",100*o+"%"),"hover"===r&&(I(c,"width",100*o+"%"),V(a,h)?function(r){const{width:o}=Tt(e,r),{text:a}=r.target.dataset;m.textContent=a;const n=m.clientWidth;o<=n/2?I(m,"left",0):o>t.clientWidth-n/2?I(m,"left",t.clientWidth-n+"px"):I(m,"left",o-n/2+"px")}(a):f(a),0===o?z(n,"art-progress-hover"):C(n,"art-progress-hover")),"played"===r&&(I(p,"width",100*o+"%"),I(u,"left",100*o+"%")),i){C(n,"art-progress-hover");f(a,{width:t.clientWidth*o,time:Q(o*e.duration)}),clearTimeout(s),s=setTimeout(()=>{z(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){h.textContent="";for(let t=0;t`;S(h,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),k||(a(i,"click",t=>{t.target!==u&&Et(e,t)}),a(i,"mousemove",t=>{const{percentage:r}=Tt(e,t);e.emit("setBar","hover",r,t)}),a(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),a(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:o}=Tt(e,t);e.emit("setBar","played",o,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}})}}class zt extends kt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;t.on("mousemove",()=>{k||(this.show=!0)}),t.on("click",()=>{k?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=V(t,o)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(z(r,"art-hide-cursor"),C(r,"art-hover"),this.timer=Date.now()):(C(r,"art-hide-cursor"),z(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(Ct({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.play),i=S(t,o.pause);function s(){I(n,"display","flex"),I(i,"display","none")}function l(){I(n,"display","none"),I(i,"display","flex")}R(n,a.get("Play")),R(i,a.get("Pause")),r(n,"click",()=>{e.play()}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o}=e,a=S(t,o.volume),n=S(t,o.volumeClose),i=S(t,'
'),s=S(i,'
'),l=S(s,'
'),c=S(s,'
'),d=S(c,'
'),p=S(d,'
'),h=S(c,'
');function u(t){const{top:e,height:r}=H(c);return 1-(t.clientY-e)/r}function m(){if(e.muted||0===e.volume)I(a,"display","none"),I(n,"display","flex"),I(h,"top","100%"),I(p,"top","100%"),l.textContent=0;else{const t=100*e.volume;I(a,"display","flex"),I(n,"display","none"),I(h,"top",100-t+"%"),I(p,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(m(),e.on("video:volumechange",m),r(a,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),k)I(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=u(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=u(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>c(l({},t),{style:k?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${Q(e.currentTime)} / ${Q(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const o=["video:loadedmetadata","video:timeupdate","video:progress"];for(let a=0;a{this.art.quality=t.quality}),t.screenshot&&!k&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:o}=e;S(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;S(t,o.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{R(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;S(t,o.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{R(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:o}=e;S(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.fullscreenWebOn),i=S(t,o.fullscreenWebOff);I(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(R(t,a.get("Exit Web Fullscreen")),I(n,"display","none"),I(i,"display","inline-flex")):(R(t,a.get("Web Fullscreen")),I(n,"display","inline-flex"),I(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=S(t,o.fullscreenOn),i=S(t,o.fullscreenOff);I(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(R(t,a.get("Exit Fullscreen")),I(n,"display","none"),I(i,"display","inline-flex")):(R(t,a.get("Fullscreen")),I(n,"display","inline-flex"),I(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),et(e,"$control_item",{get:()=>r}),et(e,"$control_value",{get:()=>a})}const i=o(n,"click",e=>d(this,null,function*(){const r=j(e),o=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(o),t.onSelect&&(a.innerHTML=yield t.onSelect.call(this.art,o,o.$control_item,e))}));r.push(i)}}function Lt(t,e,r,o){const a=e-o,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(a)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,a);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}class St{constructor(t){this.destroyEvents=new Set,this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:a}}=t;function n(e){V(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(a,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:a,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=n);switch(c.length){case 1:t.emit("click",e),k?!t.isLock&&a&&t.toggle():t.toggle(),i=c;break;case 2:t.emit("dblclick",e),k?!t.isLock&&s&&t.toggle():l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{C(r,"art-hover"),t.emit("hover",!0,e)},e=>{z(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const a=dt(()=>t.emit("resize"),o.RESIZE_TIME);t.on("window:orientationchange",()=>a()),t.on("window:resize",()=>a()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>a())}(t,this),function(t,e){if(k&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let a=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){a===o&&Et(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:o,pageY:n}=e.touches[0],c=Lt(i,s,o,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=Z((o-i)/t.width,-1,1),d=Z((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=a===r?t.constructor.TOUCH_MOVE_RATIO:1,u=Z(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",Z(u/t.duration,0,1),e),t.notice.show=`${Q(u)} / ${Q(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,a=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{a=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{a=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,a=pt(()=>{t.emit("view",_(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>a()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],a=[];function n(n={}){for(let t=0;t{const o=n.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});a.push(s)}),o.forEach(r=>{var o;const s=n.window||(null==(o=i.ownerDocument)?void 0:o.defaultView)||window,l=e.proxy(s,r,e=>{t.emit(`window:${r}`,e)});a.push(l)})}n(),e.bindGlobalEvents=n}(t,this),function(t){if(t.constructor.USE_RAF){let e=null;!function r(){t.playing&&t.emit("raf"),t.isDestroy||(e=requestAnimationFrame(r))}(),t.on("destroy",()=>{cancelAnimationFrame(e)})}}(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));t.addEventListener(e,r,o);const a=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(a),a}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class Mt{constructor(t){this.art=t,this.keys={},k||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{this.art.toggle()}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n',state:'\n\n\n',play:'\n \n',pause:'\n \n',check:'\n\n',volume:'\n \n \n',volumeClose:'\n \n \n',screenshot:'\n\t\n\n',setting:'\n \n \n',pip:'\n\n',arrowLeft:'\n \n',arrowRight:'\n \n',playbackRate:'',aspectRatio:'',config:'',lock:'\n\n\n\n\n',flip:'\n\n\n\n\n\n',unlock:'\n\n\n',fullscreenOff:'\n\n\n\n\n',fullscreenOn:'\n\n\n\n\n',fullscreenWebOff:'\n\n\n\n\n',fullscreenWebOn:'\n\n\n\n\n',switchOn:'\n\n\n \n',switchOff:'\n\n\n \n\n',error:'\n\n\n\n\n',close:'\n\n\n\n\n',airplay:'\n \n \n \n \n\n'},t.option.icons);for(const r in e)et(this,r,{get:()=>D(r,e[r])})}}class Ot extends kt{constructor(t){super(t),this.name="info",k||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:a}}=this.art;t(o,"click",()=>{this.show=!1});let n=null;const i=E("[data-video]",r)||[];this.art.on("destroy",()=>clearTimeout(n)),function t(){for(let e=0;e{I(a,"display","none"),I(n,"display",null)}),o.proxy(e.$state,"click",()=>t.play())}}class Yt{constructor(t){this.art=t,this.timer=null,t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,C(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",z(r,"art-notice-show")},e.NOTICE_TIME)):z(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}const Nt=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],Dt=(()=>{if("undefined"===typeof document)return!1;const t=Nt[0],e={};for(const r of Nt){if(r[1]in document){for(const[o,a]of r.entries())e[t[o]]=a;return e}}return!1})(),Ft={change:Dt.fullscreenchange,error:Dt.fullscreenerror},Bt={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const a=()=>{Bt.off("change",a),r()};Bt.on("change",a);const n=t[Dt.requestFullscreen](e);n instanceof Promise&&n.then(a).catch(o)}),exit:()=>new Promise((t,e)=>{if(!Bt.isFullscreen)return void t();const r=()=>{Bt.off("change",r),t()};Bt.on("change",r);const o=document[Dt.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>Bt.isFullscreen?Bt.exit():Bt.request(t,e),onchange(t){Bt.on("change",t)},onerror(t){Bt.on("error",t)},on(t,e){const r=Ft[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Ft[t];r&&document.removeEventListener(r,e,!1)},raw:Dt};function Ht(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t,n=t=>{Bt.on("change",()=>{t.emit("fullscreen",Bt.isFullscreen),Bt.isFullscreen?(t.state="fullscreen",C(a,"art-fullscreen")):z(a,"art-fullscreen"),t.emit("resize")}),Bt.on("error",e=>{t.emit("fullscreenError",e)}),et(t,"fullscreen",{get:()=>Bt.isFullscreen,set(t){return d(this,null,function*(){t?yield Bt.request(a):yield Bt.exit()})}})};t.once("video:loadedmetadata",()=>{var a;Bt.isEnabled?n(t):o.webkitSupportsFullscreen?((a=t).on("document:webkitfullscreenchange",()=>{a.emit("fullscreen",a.fullscreen),a.emit("resize")}),et(a,"fullscreen",{get:()=>document.fullscreenElement===o,set(t){t?(a.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})):et(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),et(t,"fullscreen",at(t,"fullscreen"))})}function Wt(t){const{icons:e,proxy:r,storage:o,template:{$player:a,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(z(a,"art-mini"),I(e,"display","none"),a.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(I(e,"display","none"),I(r,"display","flex")):(I(e,"display","flex"),I(r,"display","none"))}function p(){const{$mini:e}=t.template,r=H(e),a=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;o.set("top",a),o.set("left",n),I(e,"top",`${a}px`),I(e,"left",`${n}px`)}et(t,"mini",{get:()=>L(a,"art-mini"),set(h){if(h){t.state="mini",C(a,"art-mini");const h=function(){const{$mini:a}=t.template;if(a)return S(a,n),I(a,"display","flex");{const a=N("div");C(a,"art-mini-popup"),S(document.body,a),t.template.$mini=a,S(a,n);const p=S(a,'
');S(p,e.close),r(p,"click",c);const h=S(a,'
'),u=S(h,e.play),m=S(h,e.pause);return r(u,"click",()=>t.play()),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(a,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){C(a,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;I(a,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,z(a,"art-mini-dragging");const t=H(a);o.set("left",t.left),o.set("top",t.top),I(a,"left",`${t.left}px`),I(a,"top",`${t.top}px`),I(a,"transform",null)}}),a}}(),u=o.get("top"),m=o.get("left");"number"===typeof u&&"number"===typeof m?(I(h,"top",`${u}px`),I(h,"left",`${m}px`),_(h)||p()):p(),t.emit("mini",!0)}else c()}})}function jt(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,et(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),et(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):et(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ut(t){const{option:e,template:{$progress:r,$video:o}}=t;let a=null,n=!1,i=null;t.on("setBar",(a,s,l)=>d(null,null,function*(){var c;const d=null==(c=t.controls)?void 0:c.thumbnails,{url:p,scale:h}=e.thumbnails;if(!d||!p)return;if("hover"===a||"played"===a&&l&&k){if(i||n||(n=!0,i=yield W(p,h),n=!1),!i)return;const a=r.clientWidth*s;a>0&&ar.clientWidth-u/2?I(s,"left",r.clientWidth-u+"px"):I(s,"left",a-u/2+"px")}(a)}})),et(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(a),a=null,n=!1,i=null)}})}Object.defineProperties(Bt,{isFullscreen:{get:()=>Boolean(document[Dt.fullscreenElement])},element:{enumerable:!0,get:()=>document[Dt.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[Dt.fullscreenEnabled])}});class qt{constructor(t){!function(t){const{option:e,template:{$video:r}}=t;et(t,"url",{get:()=>r.src,set(o){return d(this,null,function*(){if(o){const a=t.url,n=e.type||G(o),i=e.customType[n];n&&i?(yield ct(),t.loading.show=!0,i.call(t,r,o,t)):(URL.revokeObjectURL(a),r.src=o),a!==t.url&&(t.option.url=o,t.isReady&&a&&t.once("video:canplay",()=>{t.emit("restart",o)}))}else yield ct(),t.loading.show=!0})}})}(t),function(t){const{template:{$video:e}}=t;et(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:a},template:{$video:n}}=t;et(t,"play",{value(){return d(this,null,function*(){const i=yield n.play();if(r.show=e.get("Play"),t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;et(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${Q(t.currentTime)} / ${Q(t.duration)}`),t.emit("seek",t.currentTime,r)}}),et(t,"forward",{set(e){t.seek=t.currentTime+e}}),et(t,"backward",{set(e){t.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:a}=t;et(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=Z(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(100*e.volume,10)}`,0!==e.volume&&a.set("volume",e.volume)}}),et(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;et(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{r=Number.parseFloat(r),Number.isNaN(r)||(e.currentTime=Z(r,0,t.duration))}})}(t),function(t){et(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){function e(e,r){return new Promise((o,a)=>{if(e===t.url)return void o();const{playing:n,aspectRatio:i,playbackRate:s}=t;t.pause(),t.url=e,t.notice.show="";const l={error:e=>{t.off("video:canplay",l.canplay),t.off("video:loadedmetadata",l.metadata),a(e)},metadata:()=>{t.currentTime=r},canplay:()=>d(null,null,function*(){t.off("video:error",l.error),t.playbackRate=s,t.aspectRatio=i,n&&(yield t.play()),t.notice.show="",o()})};t.once("video:error",l.error),t.once("video:loadedmetadata",l.metadata),t.once("video:canplay",l.canplay)})}et(t,"switchQuality",{value:r=>e(r,t.currentTime)}),et(t,"switchUrl",{value:t=>e(t,0)}),et(t,"switch",{set:t.switchUrl})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t;et(t,"playbackRate",{get:()=>e.playbackRate,set(a){if(a){if(a===e.playbackRate)return;e.playbackRate=a,o.show=`${r.get("Rate")}: ${1===a?r.get("Normal"):`${a}x`}`}else t.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t;et(t,"aspectRatio",{get:()=>a.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)I(o,"width",null),I(o,"height",null),I(o,"margin",null),delete a.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=a,i=e/r,s=t[0]/t[1];i>s?(I(o,"width",s*r+"px"),I(o,"height","100%"),I(o,"margin","0 auto")):(I(o,"width","100%"),I(o,"height",e/s+"px"),I(o,"margin","auto 0")),a.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=N("canvas");et(t,"getDataURL",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(n){e.show=n,a(n)}})}),et(t,"getBlobUrl",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,a(n)}})}),et(t,"screenshot",{value:e=>d(null,null,function*(){const o=yield t.getDataURL();return K(o,`${e||`artplayer_${Q(r.currentTime)}`}.png`),t.emit("screenshot",o),o})})}(t),Ht(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let a="";et(t,"fullscreenWeb",{get:()=>L(o,"art-fullscreen-web"),set(n){n?(a=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&S(document.body,o),t.state="fullscreenWeb",I(o,"width","100%"),I(o,"height","100%"),C(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&S(r,o),a&&(o.style.cssText=a,a=""),z(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),jt(t),function(t){const{$video:e}=t.template;et(t,"loaded",{get:()=>t.loadedTime/e.duration}),et(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){et(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;et(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;et(t,"autoSize",{value(){const{videoWidth:a,videoHeight:n}=o,{width:i,height:s}=H(e),l=a/n;if(i/s>l)I(r,"width",s*l/i*100+"%"),I(r,"height","100%");else{const t=i/l/s*100;I(r,"width","100%"),I(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){et(t,"rect",{get:()=>H(t.template.$player)});const e=["bottom","height","left","right","top","width"];for(let r=0;rt.rect[o]})}et(t,"x",{get:()=>t.left+window.pageXOffset}),et(t,"y",{get:()=>t.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;et(t,"flip",{get:()=>e.dataset.flip||"normal",set(a){a||(a="normal"),"normal"===a?delete e.dataset.flip:e.dataset.flip=a,o.show=`${r.get("Video Flip")}: ${r.get(J(a))}`,t.emit("flip",a)}})}(t),Wt(t),function(t){const{template:{$poster:e}}=t;et(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch(t){return""}},set(t){I(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;et(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:a,videoWidth:n}=r,i=a*(o/n);I(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;et(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){et(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){et(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];et(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;o{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,et(t,"airplay",{value(){n?(a.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){et(t,"quality",{set(e){const{controls:r,notice:o,i18n:a}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:(null==n?void 0:n.html)||"",selector:e,onSelect(e){return d(this,null,function*(){return yield t.switchQuality(e.url),o.show=`${a.get("Switch Video")}: ${e.html}`,e.html})}})}})}(t),Ut(t),function(t){const{i18n:e,notice:r,option:o,constructor:a,proxy:n,template:{$player:i,$video:s,$poster:l}}=t;let c=0;for(let d=0;d{t.emit(`video:${e.type}`,e)});t.on("video:canplay",()=>{c=0,t.loading.show=!1}),t.once("video:canplay",()=>{t.loading.show=!1,t.controls.show=!0,t.mask.show=!0,t.isReady=!0,t.emit("ready")}),t.on("video:ended",()=>{o.loop?(t.seek=0,t.play(),t.controls.show=!1,t.mask.show=!1):(t.controls.show=!0,t.mask.show=!0)}),t.on("video:error",n=>d(null,null,function*(){c{t.emit("resize"),k&&(t.loading.show=!1,t.controls.show=!0,t.mask.show=!0)}),t.on("video:loadstart",()=>{t.loading.show=!0,t.mask.show=!1,t.controls.show=!0}),t.on("video:pause",()=>{t.controls.show=!0,t.mask.show=!0}),t.on("video:play",()=>{t.mask.show=!1,I(l,"display","none")}),t.on("video:playing",()=>{t.mask.show=!1}),t.on("video:progress",()=>{t.playing&&(t.loading.show=!1)}),t.on("video:seeked",()=>{t.loading.show=!1,t.mask.show=!0}),t.on("video:seeking",()=>{t.loading.show=!0,t.mask.show=!1}),t.on("video:timeupdate",()=>{t.mask.show=!1}),t.on("video:waiting",()=>{t.loading.show=!0,t.mask.show=!1})}(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:a}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=Z(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(o.volume=Z(n,0,1)),e.poster&&I(a,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Xt(t){const{notice:e,constructor:r,template:{$player:o,$video:a}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=a,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{var a;if(e){if(l()){const e=Number(null!=(a=r.AUTO_ORIENTATION_TIME)?a:0);setTimeout(()=>{t.fullscreenWeb&&!L(o,n)&&function(){const e=U(),r=document.documentElement.clientWidth,a=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;I(o,"width",`${a}px`),I(o,"height",`${i}px`),I(o,"transform-origin","0 0"),I(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),C(o,n),t.isRotate=!0,t.emit("resize")}()},e)}}else L(o,n)&&(I(o,"width",""),I(o,"height",""),I(o,"transform-origin",""),I(o,"transform",""),z(o,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",t=>d(null,null,function*(){var r;const a=!!(null==(r=null==screen?void 0:screen.orientation)?void 0:r.lock);if(t){if(a&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";yield screen.orientation.lock(t),s=!0,C(o,i)}catch(n){s=!1,e.show=n}}else if(L(o,i)&&z(o,i),a&&s){try{screen.orientation.unlock()}catch(c){}s=!1}})),{name:"autoOrientation",get state(){return L(o,n)}}}function Gt(t){const{i18n:e,icons:r,storage:o,constructor:a,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=T(".art-auto-playback-last",s),c=T(".art-auto-playback-jump",s),d=T(".art-auto-playback-close",s);S(d,r.close);let p=null;function h(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),I(s,"display","none"),r&&r>=a.AUTO_PLAYBACK_MIN&&(I(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${Q(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{I(s,"display","none")}),n(c,"click",()=>{t.seek=r,t.play(),I(i,"display","none"),I(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{I(s,"display","none")},a.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>a.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function Kt(t){const{constructor:e,proxy:r,template:{$player:o,$video:a}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,z(o,"art-fast-forward"))};return r(a,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,C(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return L(o,"art-fast-forward")}}}function Zt(t){const{layers:e,icons:r,template:{$player:o}}=t;function a(){return L(o,"art-lock")}function n(){C(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){z(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=S(e,r.lock),a=S(e,r.unlock);I(o,"display","none"),t.on("lock",t=>{t?(I(o,"display","inline-flex"),I(a,"display","none")):(I(o,"display","none"),I(a,"display","inline-flex"))})},click(){a()?i():n()}}),{name:"lock",get state(){return a()},set state(t){t?n():i()}}}function Jt(t){return t.on("control",e=>{e?z(t.template.$player,"art-mini-progress-bar"):C(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Qt{constructor(t){this.art=t,this.id=0;const{option:e}=t;e.miniProgressBar&&!e.isLive&&this.add(Jt),e.lock&&k&&this.add(Zt),e.autoPlayback&&!e.isLive&&this.add(Gt),e.autoOrientation&&k&&this.add(Xt),e.fastForward&&k&&!e.isLive&&this.add(Kt);for(let r=0;rthis.next(t,e)):this.next(t,e)}next(t,e){const r=e&&e.name||t.name||`plugin${this.id}`;return X(!ot(this,r),`Cannot add a plugin that already has the same name: ${r}`),et(this,r,{value:e}),this}}class te extends kt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=V(t,r.setting),o=V(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:a}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:a.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:a}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:a.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:a}}=t;function n(t){return e.get(J(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:a.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){var r;for(let o=0;o{e.default=e===t,e.default&&e.$item&&O(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let a=0;ae}),et(n,"$parents",{get:()=>r}),et(n,"$option",{get:()=>t});const o=[];et(n,"$events",{get:()=>o}),et(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){var t,e;const{controls:r,constructor:{SETTING_WIDTH:o,SETTING_ITEM_HEIGHT:a},template:{$player:n,$setting:i}}=this.art;if(r.setting&&this.show){const s=(null==(e=null==(t=this.active[0])?void 0:t.$parent)?void 0:e.width)||o,{left:l,width:c}=H(r.setting),{left:d,width:p}=H(n),h=l-d+c/2-s/2;if(I(i,"height",`${this.active===this.option?this.active.length*a:(this.active.length+1)*a}px`),I(i,"width",`${s}px`),this.art.isRotate||k)return;h+s>p?(I(i,"left",null),I(i,"right",null)):(I(i,"left",`${h}px`),I(i,"right","auto"))}}inactivate(t){for(let e=0;e'),s=N("div");C(s,"art-setting-item-left-icon"),S(s,o),S(i,s),S(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),S(e,n)}createItem(t,e=!1){var r,o;if(!this.cache.has(t.$option))return;const a=this.cache.get(t.$option),n=t.$item;let i="selector";ot(t,"switch")&&(i="switch"),ot(t,"range")&&(i="range"),ot(t,"onClick")&&(i="button");const{icons:s,proxy:l,constructor:c}=this.art,p=N("div");C(p,"art-setting-item"),I(p,"height",`${c.SETTING_ITEM_HEIGHT}px`),p.dataset.name=t.name||"",p.dataset.value=t.value||"";const h=S(p,'
'),u=S(p,'
'),m=N("div");switch(C(m,"art-setting-item-left-icon"),i){case"button":case"switch":case"range":S(m,t.icon||s.config);break;case"selector":(null==(r=t.selector)?void 0:r.length)?S(m,t.icon||s.config):S(m,s.check)}S(h,m),et(t,"$icon",{configurable:!0,get:()=>m}),et(t,"icon",{configurable:!0,get:()=>m.innerHTML,set(t){m.innerHTML="",S(m,t)}});const f=N("div");C(f,"art-setting-item-left-text"),S(f,t.html||""),S(h,f),et(t,"$html",{configurable:!0,get:()=>f}),et(t,"html",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",S(f,t)}});const g=N("div");switch(C(g,"art-setting-item-right-tooltip"),S(g,t.tooltip||""),S(u,g),et(t,"$tooltip",{configurable:!0,get:()=>g}),et(t,"tooltip",{configurable:!0,get:()=>g.innerHTML,set(t){g.innerHTML="",S(g,t)}}),i){case"switch":{const e=N("div");C(e,"art-setting-item-right-icon");const r=S(e,s.switchOn),o=S(e,s.switchOff);I(t.switch?o:r,"display","none"),S(u,e),et(t,"$switch",{configurable:!0,get:()=>e});let a=t.switch;et(t,"switch",{configurable:!0,get:()=>a,set(t){a=t,t?(I(o,"display","none"),I(r,"display",null)):(I(o,"display",null),I(r,"display","none"))}});break}case"range":{const e=N("div");C(e,"art-setting-item-right-icon");const r=S(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],C(r,"art-setting-range"),S(u,e),et(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];et(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(null==(o=t.selector)?void 0:o.length){const t=N("div");C(t,"art-setting-item-right-icon"),S(t,s.arrowRight),S(u,t)}}switch(i){case"switch":if(t.onSwitch){const e=l(p,"click",e=>d(this,null,function*(){t.switch=yield t.onSwitch.call(this.art,t,p,e)}));t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=l(t.$range,"change",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onRange.call(this.art,t,p,e)}));t.$events.push(e)}if(t.onChange){const e=l(t.$range,"input",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onChange.call(this.art,t,p,e)}));t.$events.push(e)}}break;case"selector":{const e=l(p,"click",e=>d(this,null,function*(){var r;(null==(r=t.selector)?void 0:r.length)?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=yield t.$parent.onSelect.call(this.art,t,p,e)))}));t.$events.push(e),t.default&&C(p,"art-current")}break;case"button":if(t.onClick){const e=l(p,"click",e=>d(this,null,function*(){t.tooltip=yield t.onClick.call(this.art,t,p,e)}));t.$events.push(e)}}et(t,"$item",{configurable:!0,get:()=>p}),e?Y(p,n):S(a,p),t.mounted&&setTimeout(()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){var e;if(this.active=t,this.cache.has(t)){O(this.cache.get(t),"art-current")}else{const r=N("div");this.cache.set(t,r),C(r,"art-setting-panel"),S(this.$parent,r),O(r,"art-current"),(null==(e=t[0])?void 0:e.$parent)&&this.createHeader(t[0]);for(let e=0;enull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){var t,e;return null==(e=null==(t=this.art.template.$video)?void 0:t.textTracks)?void 0:e[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?P(r,t):I(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?tt(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}switch(t){return d(this,arguments,function*(t,e={}){const{i18n:r,notice:o,option:a}=this.art,n=c(l(l({},a.subtitle),e),{url:t}),i=yield this.init(n);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i})}createTrack(t,e){const{template:r,proxy:o,option:a}=this.art,{$video:n,$track:i}=r,s=N("track");s.default=!0,s.kind=t,s.src=e,s.label=a.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,M(i),S(n,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}init(t){return d(this,null,function*(){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(f(t,xt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||G(t.url)){case"srt":{const e=it(r);return st(t.onVttLoad(e))}case"ass":{const e=lt(r);return st(t.onVttLoad(e))}case"vtt":return st(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null})}}class ae{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=T(e.container),X(this.$container,`No container element found by ${e.container}`)),X(B(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();X("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),X(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),this.$container.dataset.artId=t.id,this.init()}static get html(){return`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${g}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `}query(t){return T(t,this.$container)}init(){const{option:t}=this.art;if(t.useSSR||(this.$container.innerHTML=ae.html),this.$player=this.query(".art-video-player"),this.$video=this.query(".art-video"),this.$track=this.query("track"),this.$poster=this.query(".art-poster"),this.$subtitle=this.query(".art-subtitle"),this.$danmuku=this.query(".art-danmuku"),this.$bottom=this.query(".art-bottom"),this.$progress=this.query(".art-progress"),this.$controls=this.query(".art-controls"),this.$controlsLeft=this.query(".art-controls-left"),this.$controlsCenter=this.query(".art-controls-center"),this.$controlsRight=this.query(".art-controls-right"),this.$layer=this.query(".art-layers"),this.$loading=this.query(".art-loading"),this.$notice=this.query(".art-notice"),this.$noticeInner=this.query(".art-notice-inner"),this.$mask=this.query(".art-mask"),this.$state=this.query(".art-state"),this.$setting=this.query(".art-settings"),this.$info=this.query(".art-info"),this.$infoPanel=this.query(".art-info-panel"),this.$infoClose=this.query(".art-info-close"),this.$contextmenu=this.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);X(e instanceof HTMLVideoElement||e instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'"),Y(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&C(this.$player,"art-backdrop"),k&&C(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":C(this.$player,"art-destroy")}}class ne{on(t,e,r){const o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:r}),this}once(t,e,r){const o=this;function a(...n){o.off(t,a),e.apply(r,n)}return a._=e,this.on(t,a,r)}emit(t,...e){const r=((this.e||(this.e={}))[t]||[]).slice();for(let o=0;oe.call(this,this)),le.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${le.version}`);for(let e=0;et(`Event@${e.type}`))}se.push(this)}static get instances(){return se}static get version(){return g}static get config(){return v}static get utils(){return ht}static get scheme(){return xt}static get Emitter(){return ne}static get validator(){return f}static get kindOf(){return f.kindOf}static get html(){return ae.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:b?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:null==navigator?void 0:navigator.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){le.REMOVE_SRC_WHEN_DESTROY&&this.reset(),this.events.destroy(),this.template.destroy(t),se.splice(se.indexOf(this),1),this.isDestroy=!0,this.emit("destroy")}}return le.STYLE=re,le.DEBUG=!1,le.CONTEXTMENU=!0,le.NOTICE_TIME=2e3,le.SETTING_WIDTH=250,le.SETTING_ITEM_WIDTH=200,le.SETTING_ITEM_HEIGHT=35,le.RESIZE_TIME=200,le.SCROLL_TIME=200,le.SCROLL_GAP=50,le.AUTO_PLAYBACK_MAX=10,le.AUTO_PLAYBACK_MIN=5,le.AUTO_PLAYBACK_TIMEOUT=3e3,le.RECONNECT_TIME_MAX=5,le.RECONNECT_SLEEP_TIME=1e3,le.CONTROL_HIDE_TIME=3e3,le.DBCLICK_TIME=300,le.DBCLICK_FULLSCREEN=!0,le.MOBILE_DBCLICK_PLAY=!0,le.MOBILE_CLICK_PLAY=!1,le.AUTO_ORIENTATION_TIME=200,le.INFO_LOOP_TIME=1e3,le.FAST_FORWARD_VALUE=3,le.FAST_FORWARD_TIME=1e3,le.TOUCH_MOVE_RATIO=.5,le.VOLUME_STEP=.1,le.SEEK_STEP=5,le.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],le.ASPECT_RATIO=["default","4:3","16:9"],le.FLIP=["normal","horizontal","vertical"],le.FULLSCREEN_WEB_IN_BODY=!0,le.LOG_VERSION=!0,le.USE_RAF=!1,le.REMOVE_SRC_WHEN_DESTROY=!0,$&&(F("artplayer-style",re),setTimeout(()=>{le.LOG_VERSION&&console.log(`%c ArtPlayer %c ${le.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),le}); diff --git a/packages/artplayer/dist/artplayer.mjs b/packages/artplayer/dist/artplayer.mjs index 49f7546c5..a9c2bac69 100644 --- a/packages/artplayer/dist/artplayer.mjs +++ b/packages/artplayer/dist/artplayer.mjs @@ -1205,7 +1205,7 @@ function getPosFromEvent(art, event) { } function setCurrentTime(art, event) { if (art.isRotate) { - const percentage = event.touches[0].clientY / art.height; + const percentage = (event.touches[0].clientY - art.top) / art.height; const second = percentage * art.duration; art.emit("setBar", "played", percentage, event); art.seek = second;