html-video-element-webworker-polyfill 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-GIe-DKmi.js","names":[],"sources":["../src/worker/bridge.ts","../src/worker/media-types.ts","../src/worker/video-element.ts","../src/worker/document.ts"],"sourcesContent":["import {\n CHANNEL,\n type CanPlayTypeResult,\n type ClientMessage,\n type HostMessage,\n type MessageEndpoint,\n isProtocolMessage,\n} from \"../shared/protocol.ts\";\nimport { assertWorker, isMessageEndpoint } from \"../shared/environment.ts\";\n\nexport const MISSING_HOST_WARNING_DELAY = 3000;\n\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\nexport type OutgoingMessage = DistributiveOmit<ClientMessage, typeof CHANNEL | \"seq\">;\n\nexport interface ElementReceiver {\n receive(message: Extract<HostMessage, { id: number }>): void;\n}\n\ninterface Finalizable {\n id: number;\n release: () => void;\n}\n\nexport class Bridge {\n readonly endpoint: MessageEndpoint;\n timeOffset = 0;\n\n #seq = 0;\n #nextId = 1;\n #nextCallId = 1;\n readonly #receivers = new Map<number, WeakRef<ElementReceiver>>();\n readonly #pinned = new Set<object>();\n readonly #calls = new Map<number, { resolve: (value: unknown) => void; reject: (error: unknown) => void }>();\n readonly #canPlayType = new Map<string, CanPlayTypeResult>();\n readonly #registry: FinalizationRegistry<Finalizable> | null;\n #welcomed = false;\n #missingHostTimer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(endpoint: MessageEndpoint) {\n this.endpoint = endpoint;\n this.#registry =\n typeof FinalizationRegistry === \"function\"\n ? new FinalizationRegistry<Finalizable>(({ id, release }) => {\n release();\n this.#receivers.delete(id);\n this.post({ kind: \"dispose\", id });\n })\n : null;\n endpoint.addEventListener(\"message\", this.#onMessage);\n endpoint.start?.();\n this.post({ kind: \"hello\" });\n }\n\n watchForHost(): void {\n if (this.#welcomed || this.#missingHostTimer !== undefined) return;\n this.#missingHostTimer = setTimeout(() => {\n if (this.#welcomed) return;\n console.warn(\n \"html-video-element-webworker-polyfill: no VideoHost answered this worker. \" +\n \"Call createVideoHost(worker) on the main thread right after creating the worker, otherwise videos never load.\",\n );\n }, MISSING_HOST_WARNING_DELAY);\n }\n\n nextId(): number {\n return this.#nextId++;\n }\n\n post(message: OutgoingMessage, transfer: Transferable[] = []): number {\n const seq = ++this.#seq;\n this.endpoint.postMessage({ ...message, [CHANNEL]: 1, seq }, transfer);\n return seq;\n }\n\n call(message: OutgoingMessage & { kind: \"call\" }, transfer?: Transferable[]): [number, Promise<unknown>] {\n const callId = this.#nextCallId++;\n const promise = new Promise((resolve, reject) => this.#calls.set(callId, { resolve, reject }));\n return [this.post({ ...message, callId }, transfer), promise];\n }\n\n register(id: number, element: object, receiver: ElementReceiver, release: () => void): void {\n this.#receivers.set(id, new WeakRef(receiver));\n this.#registry?.register(element, { id, release }, receiver);\n }\n\n unregister(id: number, receiver: ElementReceiver, element: object): void {\n this.#receivers.delete(id);\n this.#registry?.unregister(receiver);\n this.#pinned.delete(element);\n }\n\n pin(element: object, pinned: boolean): void {\n if (pinned) this.#pinned.add(element);\n else this.#pinned.delete(element);\n }\n\n canPlayType(type: string): CanPlayTypeResult {\n const cached = this.#canPlayType.get(type);\n if (cached !== undefined) return cached;\n const callId = this.#nextCallId++;\n this.#calls.set(callId, {\n resolve: (value) => this.#canPlayType.set(type, value as CanPlayTypeResult),\n reject: () => {},\n });\n this.post({ kind: \"canPlayType\", type, callId });\n return guessCanPlayType(type);\n }\n\n #onMessage = (event: MessageEvent): void => {\n if (!isProtocolMessage(event.data)) return;\n const message = event.data as HostMessage;\n switch (message.kind) {\n case \"welcome\": {\n this.#welcomed = true;\n clearTimeout(this.#missingHostTimer);\n this.timeOffset = message.timeOrigin - performance.timeOrigin;\n for (const [type, result] of Object.entries(message.canPlayType)) this.#canPlayType.set(type, result);\n return;\n }\n case \"result\": {\n const call = this.#calls.get(message.callId);\n if (!call) return;\n this.#calls.delete(message.callId);\n if (message.error) call.reject(new DOMException(message.error.message, message.error.name));\n else call.resolve(message.value);\n return;\n }\n default: {\n const receiver = this.#receivers.get(message.id)?.deref();\n if (receiver) receiver.receive(message);\n else if (\"frame\" in message) message.frame?.close();\n if (message.kind === \"frame\") this.post({ kind: \"frameAck\", id: message.id });\n }\n }\n };\n}\n\nconst CONTAINER_CODECS: Record<string, string[]> = {\n \"video/webm\": [\"vp8\", \"vp9\", \"av01.0.05M.08\"],\n \"video/mp4\": [\"avc1.42E01E\", \"av01.0.05M.08\", \"hvc1.1.6.L93.B0\", \"vp09.00.10.08\"],\n \"audio/webm\": [\"opus\", \"vorbis\"],\n \"audio/mp4\": [\"mp4a.40.2\", \"opus\", \"flac\"],\n};\n\nfunction guessCanPlayType(type: string): CanPlayTypeResult {\n const MediaSourceCtor = (globalThis as { MediaSource?: { isTypeSupported(type: string): boolean } }).MediaSource;\n if (!MediaSourceCtor) return \"\";\n if (/codecs\\s*=/i.test(type)) return MediaSourceCtor.isTypeSupported(type) ? \"probably\" : \"\";\n if (MediaSourceCtor.isTypeSupported(type)) return \"maybe\";\n const container = type.split(\";\")[0]!.trim().toLowerCase();\n const codecs = CONTAINER_CODECS[container] ?? [];\n return codecs.some((codec) => MediaSourceCtor.isTypeSupported(`${container}; codecs=\"${codec}\"`)) ? \"maybe\" : \"\";\n}\n\nconst bridges = new WeakMap<object, Bridge>();\nlet defaultEndpoint: MessageEndpoint | undefined;\n\nexport function bridgeFor(endpoint: MessageEndpoint | undefined): Bridge {\n const target = endpoint ?? defaultEndpoint ?? (globalThis as unknown as MessageEndpoint);\n if (!isMessageEndpoint(target)) {\n throw new TypeError(\n \"html-video-element-webworker-polyfill: `transport` must be a MessagePort or another object with postMessage/addEventListener/removeEventListener.\",\n );\n }\n let bridge = bridges.get(target);\n if (!bridge) {\n bridge = new Bridge(target);\n bridges.set(target, bridge);\n }\n return bridge;\n}\n\nexport function configureVideoTransport(endpoint: MessageEndpoint): void {\n assertWorker(\"configureVideoTransport()\");\n if (!isMessageEndpoint(endpoint)) {\n throw new TypeError(\n \"html-video-element-webworker-polyfill: configureVideoTransport() expects a MessagePort or another object with postMessage/addEventListener/removeEventListener.\",\n );\n }\n defaultEndpoint = endpoint;\n}\n","import type { Ranges, SerializedMediaError } from \"../shared/protocol.ts\";\n\nexport class WorkerTimeRanges implements TimeRanges {\n readonly #ranges: Ranges;\n\n constructor(ranges: Ranges = []) {\n this.#ranges = ranges;\n }\n\n get length(): number {\n return this.#ranges.length;\n }\n\n start(index: number): number {\n return this.#at(index)[0];\n }\n\n end(index: number): number {\n return this.#at(index)[1];\n }\n\n #at(index: number): [number, number] {\n const range = this.#ranges[index];\n if (!range) {\n throw new DOMException(\n `The index provided (${index}) is greater than or equal to the maximum bound (${this.#ranges.length}).`,\n \"IndexSizeError\",\n );\n }\n return range;\n }\n}\n\nexport class WorkerMediaError implements MediaError {\n static readonly MEDIA_ERR_ABORTED = 1 as const;\n static readonly MEDIA_ERR_NETWORK = 2 as const;\n static readonly MEDIA_ERR_DECODE = 3 as const;\n static readonly MEDIA_ERR_SRC_NOT_SUPPORTED = 4 as const;\n readonly MEDIA_ERR_ABORTED = 1 as const;\n readonly MEDIA_ERR_NETWORK = 2 as const;\n readonly MEDIA_ERR_DECODE = 3 as const;\n readonly MEDIA_ERR_SRC_NOT_SUPPORTED = 4 as const;\n\n readonly code: number;\n readonly message: string;\n\n constructor({ code, message }: SerializedMediaError) {\n this.code = code;\n this.message = message;\n }\n}\n","import { assertWorker } from \"../shared/environment.ts\";\nimport { FRAME_SOURCE } from \"../shared/frame-source.ts\";\nimport {\n type CanPlayTypeResult,\n type FrameMetadata,\n type HostMessage,\n MEDIA_EVENTS,\n type MediaState,\n type MessageEndpoint,\n} from \"../shared/protocol.ts\";\nimport { type Bridge, type ElementReceiver, bridgeFor } from \"./bridge.ts\";\nimport { WorkerMediaError, WorkerTimeRanges } from \"./media-types.ts\";\n\nexport interface CreateVideoElementOptions {\n transport?: MessageEndpoint;\n}\n\nexport type VideoFrameRequestCallback = (now: number, metadata: FrameMetadata) => void;\n\ntype EventHandler = ((this: WorkerVideoElement, event: Event) => unknown) | null;\n\ninterface MirroredProps {\n autoplay: boolean;\n controls: boolean;\n crossOrigin: string | null;\n defaultMuted: boolean;\n defaultPlaybackRate: number;\n disablePictureInPicture: boolean;\n disableRemotePlayback: boolean;\n height: number;\n loop: boolean;\n playsInline: boolean;\n poster: string;\n preload: \"\" | \"none\" | \"metadata\" | \"auto\";\n preservesPitch: boolean;\n width: number;\n}\n\nconst EMPTY_STATE: MediaState = {\n currentSrc: \"\",\n currentTime: 0,\n duration: Number.NaN,\n ended: false,\n error: null,\n muted: false,\n networkState: 0,\n paused: true,\n playbackRate: 1,\n readyState: 0,\n seeking: false,\n videoHeight: 0,\n videoWidth: 0,\n volume: 1,\n buffered: [],\n played: [],\n seekable: [],\n quality: null,\n};\n\nconst LOAD_RESET: Partial<MediaState> = {\n currentTime: 0,\n duration: Number.NaN,\n ended: false,\n error: null,\n paused: true,\n readyState: 0,\n seeking: false,\n videoHeight: 0,\n videoWidth: 0,\n buffered: [],\n played: [],\n seekable: [],\n};\n\nconst ATTRIBUTES: Record<string, { prop: string; type: \"bool\" | \"string\" | \"number\" | \"nullable\" }> = {\n autoplay: { prop: \"autoplay\", type: \"bool\" },\n controls: { prop: \"controls\", type: \"bool\" },\n crossorigin: { prop: \"crossOrigin\", type: \"nullable\" },\n disablepictureinpicture: { prop: \"disablePictureInPicture\", type: \"bool\" },\n disableremoteplayback: { prop: \"disableRemotePlayback\", type: \"bool\" },\n height: { prop: \"height\", type: \"number\" },\n loop: { prop: \"loop\", type: \"bool\" },\n muted: { prop: \"defaultMuted\", type: \"bool\" },\n playsinline: { prop: \"playsInline\", type: \"bool\" },\n poster: { prop: \"poster\", type: \"string\" },\n preload: { prop: \"preload\", type: \"string\" },\n src: { prop: \"src\", type: \"string\" },\n width: { prop: \"width\", type: \"number\" },\n};\n\nclass Internals implements ElementReceiver {\n readonly element: WorkerVideoElement;\n readonly bridge: Bridge;\n readonly id: number;\n state: MediaState = { ...EMPTY_STATE };\n props: MirroredProps = {\n autoplay: false,\n controls: false,\n crossOrigin: null,\n defaultMuted: false,\n defaultPlaybackRate: 1,\n disablePictureInPicture: false,\n disableRemotePlayback: false,\n height: 0,\n loop: false,\n playsInline: false,\n poster: \"\",\n preload: \"metadata\",\n preservesPitch: true,\n width: 0,\n };\n src = \"\";\n srcObject: unknown = null;\n hasSrcAttribute = false;\n readonly frame: { current: VideoFrame | null } = { current: null };\n readonly localWrites = new Map<string, number>();\n readonly frameCallbacks = new Map<number, VideoFrameRequestCallback>();\n nextFrameCallbackId = 1;\n readonly handlers = new Map<string, { handler: EventHandler; listener: (event: Event) => void }>();\n loadSeq = 0;\n disposed = false;\n\n constructor(element: WorkerVideoElement, bridge: Bridge) {\n this.element = element;\n this.bridge = bridge;\n this.id = bridge.nextId();\n const frame = this.frame;\n bridge.register(this.id, element, this, () => {\n frame.current?.close();\n frame.current = null;\n });\n bridge.post({ kind: \"create\", id: this.id, props: {} });\n }\n\n write(prop: string, value: unknown, local: Partial<MediaState> = {}, transfer?: Transferable[]): number {\n if (this.disposed) return 0;\n const seq = this.bridge.post({ kind: \"set\", id: this.id, prop, value }, transfer);\n this.applyLocal(seq, local);\n return seq;\n }\n\n invoke(\n method: \"pause\" | \"load\" | \"fastSeek\" | \"removeAttribute\",\n args: unknown[],\n local: Partial<MediaState> = {},\n ): number {\n if (this.disposed) return 0;\n const seq = this.bridge.post({ kind: \"call\", id: this.id, method, args });\n this.applyLocal(seq, local);\n return seq;\n }\n\n markLoad(seq: number): void {\n if (seq) this.loadSeq = seq;\n }\n\n applyLocal(seq: number, local: Partial<MediaState>): void {\n for (const [key, value] of Object.entries(local)) {\n (this.state as unknown as Record<string, unknown>)[key] = value;\n this.localWrites.set(key, seq);\n }\n if (\"readyState\" in local && (local.readyState ?? 0) < 2) this.setFrame(null);\n this.updatePin();\n }\n\n updatePin(): void {\n const { paused, seeking, networkState } = this.state;\n this.bridge.pin(this.element, !paused || seeking || networkState === 2);\n }\n\n applyState(ack: number, state: MediaState): void {\n const target = this.state as unknown as Record<string, unknown>;\n for (const [key, value] of Object.entries(state)) {\n const pending = this.localWrites.get(key);\n if (pending !== undefined) {\n if (pending > ack) continue;\n this.localWrites.delete(key);\n }\n target[key] = value;\n }\n this.updatePin();\n }\n\n setFrame(frame: VideoFrame | null): void {\n if (this.frame.current === frame) return;\n this.frame.current?.close();\n this.frame.current = frame;\n }\n\n receive(message: Extract<HostMessage, { id: number }>): void {\n if (this.disposed || (message.kind !== \"state\" && message.ack < this.loadSeq)) {\n if (\"frame\" in message) message.frame?.close();\n if (this.disposed) return;\n }\n this.applyState(message.ack, message.state);\n if (message.kind !== \"state\" && message.ack < this.loadSeq) return;\n switch (message.kind) {\n case \"state\":\n return;\n case \"frame\":\n this.setFrame(message.frame);\n this.runFrameCallbacks(message.metadata);\n return;\n case \"event\": {\n if (message.frame) this.setFrame(message.frame);\n else if (message.type === \"emptied\") this.setFrame(null);\n this.element.dispatchEvent(new Event(message.type));\n if (message.frame && message.metadata) this.runFrameCallbacks(message.metadata);\n }\n }\n }\n\n runFrameCallbacks(metadata: FrameMetadata): void {\n if (this.frameCallbacks.size === 0) return;\n const callbacks = [...this.frameCallbacks.values()];\n this.frameCallbacks.clear();\n const offset = this.bridge.timeOffset;\n const local: FrameMetadata = {\n ...metadata,\n presentationTime: metadata.presentationTime + offset,\n expectedDisplayTime: metadata.expectedDisplayTime + offset,\n };\n const now = performance.now();\n for (const callback of callbacks) {\n try {\n callback.call(this.element, now, local);\n } catch (error) {\n reportError(error);\n }\n }\n }\n\n resolveUrl(value: string): string {\n if (value === \"\") return value;\n const base = (globalThis as { location?: { href: string } }).location?.href;\n try {\n return new URL(value, base).href;\n } catch {\n return value;\n }\n }\n}\n\nfunction reportError(error: unknown): void {\n const report = (globalThis as { reportError?: (error: unknown) => void }).reportError;\n if (report) report(error);\n else\n setTimeout(() => {\n throw error;\n });\n}\n\nconst internals = new WeakMap<WorkerVideoElement, Internals>();\n\nfunction $(element: WorkerVideoElement): Internals {\n const value = internals.get(element);\n if (!value) throw new TypeError(\"Illegal invocation\");\n return value;\n}\n\nexport class WorkerVideoElement extends EventTarget {\n static readonly NETWORK_EMPTY = 0 as const;\n static readonly NETWORK_IDLE = 1 as const;\n static readonly NETWORK_LOADING = 2 as const;\n static readonly NETWORK_NO_SOURCE = 3 as const;\n static readonly HAVE_NOTHING = 0 as const;\n static readonly HAVE_METADATA = 1 as const;\n static readonly HAVE_CURRENT_DATA = 2 as const;\n static readonly HAVE_FUTURE_DATA = 3 as const;\n static readonly HAVE_ENOUGH_DATA = 4 as const;\n readonly NETWORK_EMPTY = 0 as const;\n readonly NETWORK_IDLE = 1 as const;\n readonly NETWORK_LOADING = 2 as const;\n readonly NETWORK_NO_SOURCE = 3 as const;\n readonly HAVE_NOTHING = 0 as const;\n readonly HAVE_METADATA = 1 as const;\n readonly HAVE_CURRENT_DATA = 2 as const;\n readonly HAVE_FUTURE_DATA = 3 as const;\n readonly HAVE_ENOUGH_DATA = 4 as const;\n\n readonly tagName = \"VIDEO\" as const;\n readonly nodeName = \"VIDEO\" as const;\n readonly localName = \"video\" as const;\n\n constructor(options: CreateVideoElementOptions = {}) {\n assertWorker(\"createVideoElement()\");\n super();\n const bridge = bridgeFor(options.transport);\n bridge.watchForHost();\n internals.set(this, new Internals(this, bridge));\n }\n\n get currentFrame(): VideoFrame | null {\n const frame = $(this).frame.current;\n return frame && frame.format !== null ? frame : null;\n }\n\n get disposed(): boolean {\n return $(this).disposed;\n }\n\n dispose(): void {\n const core = $(this);\n if (core.disposed) return;\n core.bridge.post({ kind: \"dispose\", id: core.id });\n core.disposed = true;\n core.setFrame(null);\n core.frameCallbacks.clear();\n core.bridge.unregister(core.id, core, this);\n core.state = { ...EMPTY_STATE };\n core.localWrites.clear();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n get src(): string {\n return $(this).src;\n }\n set src(value: string) {\n const core = $(this);\n core.src = core.resolveUrl(String(value));\n core.hasSrcAttribute = true;\n core.markLoad(core.write(\"src\", core.src, { ...LOAD_RESET, currentSrc: \"\", networkState: 0 }));\n }\n\n get srcObject(): unknown {\n return $(this).srcObject;\n }\n set srcObject(value: unknown) {\n const core = $(this);\n core.srcObject = value ?? null;\n const transfer = value ? [value as Transferable] : [];\n core.markLoad(core.write(\"srcObject\", value ?? null, { ...LOAD_RESET, currentSrc: \"\", networkState: 0 }, transfer));\n }\n\n get currentSrc(): string {\n return $(this).state.currentSrc;\n }\n\n get duration(): number {\n return $(this).state.duration;\n }\n get paused(): boolean {\n return $(this).state.paused;\n }\n get ended(): boolean {\n return $(this).state.ended;\n }\n get seeking(): boolean {\n return $(this).state.seeking;\n }\n get readyState(): number {\n return $(this).state.readyState;\n }\n get networkState(): number {\n return $(this).state.networkState;\n }\n get videoWidth(): number {\n return $(this).state.videoWidth;\n }\n get videoHeight(): number {\n return $(this).state.videoHeight;\n }\n get error(): MediaError | null {\n const error = $(this).state.error;\n return error ? new WorkerMediaError(error) : null;\n }\n get buffered(): TimeRanges {\n return new WorkerTimeRanges($(this).state.buffered);\n }\n get played(): TimeRanges {\n return new WorkerTimeRanges($(this).state.played);\n }\n get seekable(): TimeRanges {\n return new WorkerTimeRanges($(this).state.seekable);\n }\n\n get currentTime(): number {\n return $(this).state.currentTime;\n }\n set currentTime(value: number) {\n const time = Number(value);\n if (!Number.isFinite(time)) {\n throw new TypeError(\"Failed to set the 'currentTime' property: The provided double value is non-finite.\");\n }\n const core = $(this);\n const local: Partial<MediaState> = { currentTime: time, ended: false };\n if (core.state.readyState > 0) local.seeking = true;\n core.write(\"currentTime\", time, local);\n }\n\n fastSeek(time: number): void {\n const core = $(this);\n const local: Partial<MediaState> = { currentTime: time, ended: false };\n if (core.state.readyState > 0) local.seeking = true;\n core.invoke(\"fastSeek\", [time], local);\n }\n\n get volume(): number {\n return $(this).state.volume;\n }\n set volume(value: number) {\n const volume = Number(value);\n if (!(volume >= 0 && volume <= 1)) {\n throw new DOMException(\n `Failed to set the 'volume' property: The volume provided (${value}) is outside the range [0, 1].`,\n \"IndexSizeError\",\n );\n }\n $(this).write(\"volume\", volume, { volume });\n }\n\n get muted(): boolean {\n return $(this).state.muted;\n }\n set muted(value: boolean) {\n $(this).write(\"muted\", Boolean(value), { muted: Boolean(value) });\n }\n\n get playbackRate(): number {\n return $(this).state.playbackRate;\n }\n set playbackRate(value: number) {\n $(this).write(\"playbackRate\", Number(value), { playbackRate: Number(value) });\n }\n\n get autoplay(): boolean {\n return $(this).props.autoplay;\n }\n set autoplay(value: boolean) {\n this.#mirror(\"autoplay\", Boolean(value));\n }\n get controls(): boolean {\n return $(this).props.controls;\n }\n set controls(value: boolean) {\n this.#mirror(\"controls\", Boolean(value));\n }\n get crossOrigin(): string | null {\n return $(this).props.crossOrigin;\n }\n set crossOrigin(value: string | null) {\n this.#mirror(\"crossOrigin\", value === null ? null : String(value));\n }\n get defaultMuted(): boolean {\n return $(this).props.defaultMuted;\n }\n set defaultMuted(value: boolean) {\n this.#mirror(\"defaultMuted\", Boolean(value));\n }\n get defaultPlaybackRate(): number {\n return $(this).props.defaultPlaybackRate;\n }\n set defaultPlaybackRate(value: number) {\n this.#mirror(\"defaultPlaybackRate\", Number(value));\n }\n get disablePictureInPicture(): boolean {\n return $(this).props.disablePictureInPicture;\n }\n set disablePictureInPicture(value: boolean) {\n this.#mirror(\"disablePictureInPicture\", Boolean(value));\n }\n get disableRemotePlayback(): boolean {\n return $(this).props.disableRemotePlayback;\n }\n set disableRemotePlayback(value: boolean) {\n this.#mirror(\"disableRemotePlayback\", Boolean(value));\n }\n get height(): number {\n return $(this).props.height;\n }\n set height(value: number) {\n this.#mirror(\"height\", Math.max(0, Math.trunc(Number(value))) || 0);\n }\n get width(): number {\n return $(this).props.width;\n }\n set width(value: number) {\n this.#mirror(\"width\", Math.max(0, Math.trunc(Number(value))) || 0);\n }\n get loop(): boolean {\n return $(this).props.loop;\n }\n set loop(value: boolean) {\n this.#mirror(\"loop\", Boolean(value));\n }\n get playsInline(): boolean {\n return $(this).props.playsInline;\n }\n set playsInline(value: boolean) {\n this.#mirror(\"playsInline\", Boolean(value));\n }\n get poster(): string {\n return $(this).props.poster;\n }\n set poster(value: string) {\n this.#mirror(\"poster\", $(this).resolveUrl(String(value)));\n }\n get preload(): MirroredProps[\"preload\"] {\n return $(this).props.preload;\n }\n set preload(value: MirroredProps[\"preload\"]) {\n const normalized = String(value).toLowerCase();\n this.#mirror(\"preload\", ([\"none\", \"metadata\", \"auto\"].includes(normalized) ? normalized : \"auto\") as never);\n }\n get preservesPitch(): boolean {\n return $(this).props.preservesPitch;\n }\n set preservesPitch(value: boolean) {\n this.#mirror(\"preservesPitch\", Boolean(value));\n }\n\n #mirror<K extends keyof MirroredProps>(prop: K, value: MirroredProps[K]): void {\n const core = $(this);\n core.props[prop] = value;\n core.write(prop, value);\n }\n\n getAttribute(name: string): string | null {\n const core = $(this);\n const attribute = ATTRIBUTES[name.toLowerCase()];\n if (!attribute) return null;\n if (attribute.prop === \"src\") return core.hasSrcAttribute ? core.src : null;\n const value = (this as unknown as Record<string, unknown>)[attribute.prop];\n switch (attribute.type) {\n case \"bool\":\n return value ? \"\" : null;\n case \"nullable\":\n return value === null ? null : String(value);\n default:\n return String(value);\n }\n }\n\n hasAttribute(name: string): boolean {\n return this.getAttribute(name) !== null;\n }\n\n setAttribute(name: string, value: string): void {\n const attribute = ATTRIBUTES[name.toLowerCase()];\n if (!attribute) return;\n const target = this as unknown as Record<string, unknown>;\n switch (attribute.type) {\n case \"bool\":\n target[attribute.prop] = true;\n break;\n case \"number\":\n target[attribute.prop] = Number.parseInt(value, 10) || 0;\n break;\n default:\n target[attribute.prop] = String(value);\n }\n }\n\n removeAttribute(name: string): void {\n const attribute = ATTRIBUTES[name.toLowerCase()];\n if (!attribute) return;\n const core = $(this);\n if (attribute.prop === \"src\") {\n core.src = \"\";\n core.hasSrcAttribute = false;\n core.invoke(\"removeAttribute\", [\"src\"]);\n return;\n }\n const target = this as unknown as Record<string, unknown>;\n switch (attribute.type) {\n case \"bool\":\n target[attribute.prop] = false;\n break;\n case \"nullable\":\n target[attribute.prop] = null;\n break;\n case \"number\":\n target[attribute.prop] = 0;\n break;\n default:\n target[attribute.prop] = attribute.prop === \"preload\" ? \"metadata\" : \"\";\n }\n }\n\n play(): Promise<void> {\n const core = $(this);\n if (core.disposed) {\n return Promise.reject(new DOMException(\"The element has been disposed.\", \"InvalidStateError\"));\n }\n const [seq, promise] = core.bridge.call({ kind: \"call\", id: core.id, method: \"play\", args: [] });\n core.applyLocal(seq, { paused: false });\n return promise as Promise<void>;\n }\n\n pause(): void {\n $(this).invoke(\"pause\", [], { paused: true });\n }\n\n load(): void {\n const core = $(this);\n core.markLoad(core.invoke(\"load\", [], { ...LOAD_RESET, networkState: 0 }));\n }\n\n canPlayType(type: string): CanPlayTypeResult {\n return $(this).bridge.canPlayType(String(type));\n }\n\n getVideoPlaybackQuality(): VideoPlaybackQuality {\n const quality = $(this).state.quality;\n return (quality ?? {\n creationTime: performance.now(),\n droppedVideoFrames: 0,\n totalVideoFrames: 0,\n }) as VideoPlaybackQuality;\n }\n\n requestVideoFrameCallback(callback: VideoFrameRequestCallback): number {\n const core = $(this);\n const handle = core.nextFrameCallbackId++;\n core.frameCallbacks.set(handle, callback);\n return handle;\n }\n\n cancelVideoFrameCallback(handle: number): void {\n $(this).frameCallbacks.delete(handle);\n }\n\n requestPictureInPicture(): Promise<never> {\n return Promise.reject(new DOMException(\"Picture-in-Picture is not available in workers.\", \"NotSupportedError\"));\n }\n}\n\nexport interface WorkerVideoElement {\n [FRAME_SOURCE](): VideoFrame | null;\n onabort: EventHandler;\n oncanplay: EventHandler;\n oncanplaythrough: EventHandler;\n ondurationchange: EventHandler;\n onemptied: EventHandler;\n onencrypted: EventHandler;\n onended: EventHandler;\n onerror: EventHandler;\n onloadeddata: EventHandler;\n onloadedmetadata: EventHandler;\n onloadstart: EventHandler;\n onpause: EventHandler;\n onplay: EventHandler;\n onplaying: EventHandler;\n onprogress: EventHandler;\n onratechange: EventHandler;\n onresize: EventHandler;\n onseeked: EventHandler;\n onseeking: EventHandler;\n onstalled: EventHandler;\n onsuspend: EventHandler;\n ontimeupdate: EventHandler;\n onvolumechange: EventHandler;\n onwaiting: EventHandler;\n onwaitingforkey: EventHandler;\n}\n\nObject.defineProperty(WorkerVideoElement.prototype, FRAME_SOURCE, {\n configurable: true,\n value(this: WorkerVideoElement): VideoFrame | null {\n return this.currentFrame;\n },\n});\n\nfor (const type of MEDIA_EVENTS) {\n Object.defineProperty(WorkerVideoElement.prototype, `on${type}`, {\n configurable: true,\n enumerable: true,\n get(this: WorkerVideoElement): EventHandler {\n return $(this).handlers.get(type)?.handler ?? null;\n },\n set(this: WorkerVideoElement, handler: EventHandler) {\n const core = $(this);\n const existing = core.handlers.get(type);\n if (typeof handler !== \"function\") {\n if (existing) this.removeEventListener(type, existing.listener);\n core.handlers.delete(type);\n return;\n }\n if (existing) {\n existing.handler = handler;\n return;\n }\n const entry = {\n handler,\n listener: (event: Event) => {\n const result = entry.handler?.call(this, event);\n if (result === false) event.preventDefault();\n },\n };\n core.handlers.set(type, entry);\n this.addEventListener(type, entry.listener);\n },\n });\n}\n\nexport function createVideoElement(options?: CreateVideoElementOptions): WorkerVideoElement {\n return new WorkerVideoElement(options);\n}\n","import type { CreateVideoElementOptions } from \"./video-element.ts\";\nimport { WorkerVideoElement } from \"./video-element.ts\";\nimport { WorkerMediaError, WorkerTimeRanges } from \"./media-types.ts\";\nimport { assertWorker } from \"../shared/environment.ts\";\n\nconst PATCHED: unique symbol = Symbol.for(\"html-video-element-webworker-polyfill.patched\") as never;\n\ninterface DocumentLike {\n createElement(tagName: string, options?: unknown): unknown;\n [PATCHED]?: true;\n}\n\nexport function polyfillDocument(options?: CreateVideoElementOptions): void {\n assertWorker(\"polyfillDocument()\");\n const scope = globalThis as Record<string, unknown>;\n scope.HTMLVideoElement ??= WorkerVideoElement;\n scope.HTMLMediaElement ??= WorkerVideoElement;\n scope.MediaError ??= WorkerMediaError;\n scope.TimeRanges ??= WorkerTimeRanges;\n\n const existing = scope.document as DocumentLike | undefined;\n if (existing && typeof existing.createElement === \"function\") {\n if (existing[PATCHED]) return;\n const original = existing.createElement.bind(existing);\n existing.createElement = (tagName: string, elementOptions?: unknown) =>\n isVideo(tagName) ? new WorkerVideoElement(options) : original(tagName, elementOptions);\n existing[PATCHED] = true;\n return;\n }\n\n const document: DocumentLike = {\n createElement(tagName: string): unknown {\n if (isVideo(tagName)) return new WorkerVideoElement(options);\n throw new DOMException(\n `document.createElement(\"${tagName}\") is not supported in a worker; only \"video\" is polyfilled.`,\n \"NotSupportedError\",\n );\n },\n [PATCHED]: true,\n };\n scope.document = document;\n}\n\nfunction isVideo(tagName: string): boolean {\n return String(tagName).toLowerCase() === \"video\";\n}\n"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ //#region src/shared/environment.ts
2
+ const PACKAGE = "html-video-element-webworker-polyfill";
3
+ var InvalidEnvironmentError = class extends Error {
4
+ name = "InvalidEnvironmentError";
5
+ };
6
+ function isMainThread() {
7
+ const scope = globalThis;
8
+ return typeof scope.Window === "function" && globalThis instanceof scope.Window;
9
+ }
10
+ function isWorker() {
11
+ const scope = globalThis;
12
+ return typeof scope.WorkerGlobalScope === "function" && globalThis instanceof scope.WorkerGlobalScope;
13
+ }
14
+ function assertMainThread(api) {
15
+ if (isMainThread()) return;
16
+ throw new InvalidEnvironmentError(`${PACKAGE}: ${api} must be called on the main thread, where real <video> elements exist. Inside a worker use createVideoElement() or polyfillDocument() and attach the worker on the main thread with createVideoHost(worker).`);
17
+ }
18
+ function assertWorker(api) {
19
+ if (isWorker()) return;
20
+ throw new InvalidEnvironmentError(`${PACKAGE}: ${api} must be called inside a Web Worker. On the main thread use a real <video> element, and serve workers with createVideoHost(worker).`);
21
+ }
22
+ function isMessageEndpoint(value) {
23
+ const endpoint = value;
24
+ return typeof endpoint === "object" && endpoint !== null && typeof endpoint.postMessage === "function" && typeof endpoint.addEventListener === "function" && typeof endpoint.removeEventListener === "function";
25
+ }
26
+ //#endregion
27
+ export { isMessageEndpoint as a, isMainThread as i, assertMainThread as n, isWorker as o, assertWorker as r, InvalidEnvironmentError as t };
28
+
29
+ //# sourceMappingURL=environment-De2r8LaA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment-De2r8LaA.js","names":[],"sources":["../src/shared/environment.ts"],"sourcesContent":["const PACKAGE = \"html-video-element-webworker-polyfill\";\n\nexport class InvalidEnvironmentError extends Error {\n override name: string = \"InvalidEnvironmentError\";\n}\n\nexport function isMainThread(): boolean {\n const scope = globalThis as { Window?: abstract new () => unknown };\n return typeof scope.Window === \"function\" && globalThis instanceof scope.Window;\n}\n\nexport function isWorker(): boolean {\n const scope = globalThis as { WorkerGlobalScope?: abstract new () => unknown };\n return typeof scope.WorkerGlobalScope === \"function\" && globalThis instanceof scope.WorkerGlobalScope;\n}\n\nexport function assertMainThread(api: string): void {\n if (isMainThread()) return;\n throw new InvalidEnvironmentError(\n `${PACKAGE}: ${api} must be called on the main thread, where real <video> elements exist. ` +\n `Inside a worker use createVideoElement() or polyfillDocument() and attach the worker on the main thread with createVideoHost(worker).`,\n );\n}\n\nexport function assertWorker(api: string): void {\n if (isWorker()) return;\n throw new InvalidEnvironmentError(\n `${PACKAGE}: ${api} must be called inside a Web Worker. ` +\n `On the main thread use a real <video> element, and serve workers with createVideoHost(worker).`,\n );\n}\n\nexport function isMessageEndpoint(value: unknown): boolean {\n const endpoint = value as { postMessage?: unknown; addEventListener?: unknown; removeEventListener?: unknown } | null;\n return (\n typeof endpoint === \"object\" &&\n endpoint !== null &&\n typeof endpoint.postMessage === \"function\" &&\n typeof endpoint.addEventListener === \"function\" &&\n typeof endpoint.removeEventListener === \"function\"\n );\n}\n"],"mappings":";AAAA,MAAM,UAAU;AAEhB,IAAa,0BAAb,cAA6C,MAAM;CACjD,OAAwB;AAC1B;AAEA,SAAgB,eAAwB;CACtC,MAAM,QAAQ;CACd,OAAO,OAAO,MAAM,WAAW,cAAc,sBAAsB,MAAM;AAC3E;AAEA,SAAgB,WAAoB;CAClC,MAAM,QAAQ;CACd,OAAO,OAAO,MAAM,sBAAsB,cAAc,sBAAsB,MAAM;AACtF;AAEA,SAAgB,iBAAiB,KAAmB;CAClD,IAAI,aAAa,GAAG;CACpB,MAAM,IAAI,wBACR,GAAG,QAAQ,IAAI,IAAI,6MAErB;AACF;AAEA,SAAgB,aAAa,KAAmB;CAC9C,IAAI,SAAS,GAAG;CAChB,MAAM,IAAI,wBACR,GAAG,QAAQ,IAAI,IAAI,oIAErB;AACF;AAEA,SAAgB,kBAAkB,OAAyB;CACzD,MAAM,WAAW;CACjB,OACE,OAAO,aAAa,YACpB,aAAa,QACb,OAAO,SAAS,gBAAgB,cAChC,OAAO,SAAS,qBAAqB,cACrC,OAAO,SAAS,wBAAwB;AAE5C"}
@@ -0,0 +1,35 @@
1
+ //#region src/shared/protocol.d.ts
2
+ type Ranges = Array<[start: number, end: number]>;
3
+ interface SerializedMediaError {
4
+ code: number;
5
+ message: string;
6
+ }
7
+ interface FrameMetadata {
8
+ presentationTime: number;
9
+ expectedDisplayTime: number;
10
+ width: number;
11
+ height: number;
12
+ mediaTime: number;
13
+ presentedFrames: number;
14
+ processingDuration?: number;
15
+ captureTime?: number;
16
+ receiveTime?: number;
17
+ rtpTimestamp?: number;
18
+ }
19
+ type CanPlayTypeResult = "" | "maybe" | "probably";
20
+ interface MessageEndpoint {
21
+ postMessage(message: unknown, transfer: Transferable[]): void;
22
+ addEventListener(type: "message", listener: (event: MessageEvent) => void): void;
23
+ removeEventListener(type: "message", listener: (event: MessageEvent) => void): void;
24
+ start?: () => void;
25
+ }
26
+ //#endregion
27
+ //#region src/shared/environment.d.ts
28
+ declare class InvalidEnvironmentError extends Error {
29
+ override name: string;
30
+ }
31
+ declare function isMainThread(): boolean;
32
+ declare function isWorker(): boolean;
33
+ //#endregion
34
+ export { FrameMetadata as a, SerializedMediaError as c, CanPlayTypeResult as i, isMainThread as n, MessageEndpoint as o, isWorker as r, Ranges as s, InvalidEnvironmentError as t };
35
+ //# sourceMappingURL=environment-W_2WcDor.d.ts.map
@@ -0,0 +1,43 @@
1
+ //#region src/shared/frame-source.ts
2
+ const FRAME_SOURCE = Symbol.for("html-video-element-webworker-polyfill.frame");
3
+ function isFrameSource(value) {
4
+ return typeof value === "object" && value !== null && typeof value[FRAME_SOURCE] === "function";
5
+ }
6
+ function frameOf(value) {
7
+ if (!isFrameSource(value)) return void 0;
8
+ const frame = value[FRAME_SOURCE]();
9
+ return frame && frame.format !== null ? frame : null;
10
+ }
11
+ const PATCHED = Symbol.for("html-video-element-webworker-polyfill.patched");
12
+ function patchMethod(proto, name, transform, skipped = () => void 0) {
13
+ if (!proto) return;
14
+ const original = proto[name];
15
+ if (typeof original !== "function" || original[PATCHED]) return;
16
+ const patched = { [name](...args) {
17
+ if (!transform(args)) return skipped();
18
+ return original.apply(this, args);
19
+ } }[name];
20
+ patched[PATCHED] = true;
21
+ Object.defineProperty(proto, name, {
22
+ value: patched,
23
+ writable: true,
24
+ configurable: true,
25
+ enumerable: false
26
+ });
27
+ }
28
+ function unwrapArgs(args) {
29
+ for (let i = 0; i < args.length; i++) {
30
+ const frame = frameOf(args[i]);
31
+ if (frame === void 0) continue;
32
+ if (frame === null) return false;
33
+ args[i] = frame;
34
+ }
35
+ return true;
36
+ }
37
+ function noFrameError() {
38
+ return new DOMException("The video element has no decoded frame yet (readyState < HAVE_CURRENT_DATA).", "InvalidStateError");
39
+ }
40
+ //#endregion
41
+ export { patchMethod as a, noFrameError as i, frameOf as n, unwrapArgs as o, isFrameSource as r, FRAME_SOURCE as t };
42
+
43
+ //# sourceMappingURL=frame-source-BG--PzqD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-source-BG--PzqD.js","names":[],"sources":["../src/shared/frame-source.ts"],"sourcesContent":["export const FRAME_SOURCE: unique symbol = Symbol.for(\"html-video-element-webworker-polyfill.frame\") as never;\n\nexport interface FrameSource {\n readonly [FRAME_SOURCE]: () => VideoFrame | null;\n}\n\nexport function isFrameSource(value: unknown): value is FrameSource {\n return (\n typeof value === \"object\" && value !== null && typeof (value as Partial<FrameSource>)[FRAME_SOURCE] === \"function\"\n );\n}\n\nexport function frameOf(value: unknown): VideoFrame | null | undefined {\n if (!isFrameSource(value)) return undefined;\n const frame = value[FRAME_SOURCE]();\n return frame && frame.format !== null ? frame : null;\n}\n\nconst PATCHED: unique symbol = Symbol.for(\"html-video-element-webworker-polyfill.patched\") as never;\n\ntype AnyFn = (this: unknown, ...args: unknown[]) => unknown;\n\nexport function patchMethod(\n proto: object | undefined,\n name: string,\n transform: (args: unknown[]) => boolean,\n skipped: () => unknown = () => undefined,\n): void {\n if (!proto) return;\n const original = (proto as Record<string, unknown>)[name] as (AnyFn & { [PATCHED]?: true }) | undefined;\n if (typeof original !== \"function\" || original[PATCHED]) return;\n const patched = {\n [name](this: unknown, ...args: unknown[]): unknown {\n if (!transform(args)) return skipped();\n return original.apply(this, args);\n },\n }[name] as AnyFn & { [PATCHED]?: true };\n patched[PATCHED] = true;\n Object.defineProperty(proto, name, {\n value: patched,\n writable: true,\n configurable: true,\n enumerable: false,\n });\n}\n\nexport function unwrapArgs(args: unknown[]): boolean {\n for (let i = 0; i < args.length; i++) {\n const frame = frameOf(args[i]);\n if (frame === undefined) continue;\n if (frame === null) return false;\n args[i] = frame;\n }\n return true;\n}\n\nexport function noFrameError(): DOMException {\n return new DOMException(\n \"The video element has no decoded frame yet (readyState < HAVE_CURRENT_DATA).\",\n \"InvalidStateError\",\n );\n}\n"],"mappings":";AAAA,MAAa,eAA8B,OAAO,IAAI,6CAA6C;AAMnG,SAAgB,cAAc,OAAsC;CAClE,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAQ,MAA+B,kBAAkB;AAE5G;AAEA,SAAgB,QAAQ,OAA+C;CACrE,IAAI,CAAC,cAAc,KAAK,GAAG,OAAO,KAAA;CAClC,MAAM,QAAQ,MAAM,aAAa,CAAC;CAClC,OAAO,SAAS,MAAM,WAAW,OAAO,QAAQ;AAClD;AAEA,MAAM,UAAyB,OAAO,IAAI,+CAA+C;AAIzF,SAAgB,YACd,OACA,MACA,WACA,gBAA+B,KAAA,GACzB;CACN,IAAI,CAAC,OAAO;CACZ,MAAM,WAAY,MAAkC;CACpD,IAAI,OAAO,aAAa,cAAc,SAAS,UAAU;CACzD,MAAM,UAAU,EACd,CAAC,MAAqB,GAAG,MAA0B;EACjD,IAAI,CAAC,UAAU,IAAI,GAAG,OAAO,QAAQ;EACrC,OAAO,SAAS,MAAM,MAAM,IAAI;CAClC,EACF,EAAE;CACF,QAAQ,WAAW;CACnB,OAAO,eAAe,OAAO,MAAM;EACjC,OAAO;EACP,UAAU;EACV,cAAc;EACd,YAAY;CACd,CAAC;AACH;AAEA,SAAgB,WAAW,MAA0B;CACnD,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,QAAQ,QAAQ,KAAK,EAAE;EAC7B,IAAI,UAAU,KAAA,GAAW;EACzB,IAAI,UAAU,MAAM,OAAO;EAC3B,KAAK,KAAK;CACZ;CACA,OAAO;AACT;AAEA,SAAgB,eAA6B;CAC3C,OAAO,IAAI,aACT,gFACA,mBACF;AACF"}
@@ -0,0 +1,423 @@
1
+ import { a as isProtocolMessage, i as MIRRORED_PROPERTIES, n as COMMON_MIME_TYPES, r as MEDIA_EVENTS, t as CHANNEL } from "./protocol-Be-N8xdd.js";
2
+ import { a as isMessageEndpoint, i as isMainThread, n as assertMainThread } from "./environment-De2r8LaA.js";
3
+ //#region src/host/video-host.ts
4
+ const FRAME_EVENTS = /* @__PURE__ */ new Set(["loadeddata", "seeked"]);
5
+ const SILENT_STATE_POLL_INTERVAL = 16;
6
+ const SILENT_STATE_POLLS = 32;
7
+ const FRAME_WAIT_TIMEOUT = 500;
8
+ const TIMESTAMP_EPSILON = 1e3;
9
+ const hosted = /* @__PURE__ */ new WeakSet();
10
+ function createVideoHost(endpoint, options = {}) {
11
+ assertMainThread("createVideoHost()");
12
+ if (!isMessageEndpoint(endpoint) || isMainThread() && endpoint === globalThis) throw new TypeError("html-video-element-webworker-polyfill: createVideoHost() expects the Worker (or a MessagePort connected to it) that uses the polyfill.");
13
+ if (hosted.has(endpoint)) throw new DOMException("html-video-element-webworker-polyfill: createVideoHost() was already called for this endpoint; call dispose() on the existing host first.", "InvalidStateError");
14
+ hosted.add(endpoint);
15
+ const entries = /* @__PURE__ */ new Map();
16
+ const videos = /* @__PURE__ */ new Map();
17
+ let ack = 0;
18
+ let disposed = false;
19
+ const sentNetworkState = /* @__PURE__ */ new Map();
20
+ const post = (message, transfer = []) => {
21
+ if (disposed) {
22
+ for (const item of transfer) item.close?.();
23
+ return;
24
+ }
25
+ if ("state" in message) sentNetworkState.set(message.id, message.state.networkState);
26
+ endpoint.postMessage({
27
+ ...message,
28
+ [CHANNEL]: 1
29
+ }, transfer);
30
+ };
31
+ const watching = /* @__PURE__ */ new Map();
32
+ const sendState = (id, video) => {
33
+ post({
34
+ kind: "state",
35
+ id,
36
+ ack,
37
+ state: snapshot(video)
38
+ });
39
+ const existing = watching.get(id);
40
+ if (existing) {
41
+ existing.polls = 0;
42
+ return;
43
+ }
44
+ const watch = { polls: 0 };
45
+ watching.set(id, watch);
46
+ const poll = () => {
47
+ if (entries.get(id)?.video !== video || ++watch.polls > SILENT_STATE_POLLS) {
48
+ watching.delete(id);
49
+ return;
50
+ }
51
+ if (video.networkState !== sentNetworkState.get(id)) post({
52
+ kind: "state",
53
+ id,
54
+ ack,
55
+ state: snapshot(video)
56
+ });
57
+ setTimeout(poll, SILENT_STATE_POLL_INTERVAL);
58
+ };
59
+ setTimeout(poll, SILENT_STATE_POLL_INTERVAL);
60
+ };
61
+ const welcome = () => {
62
+ const probe = document.createElement("video");
63
+ const canPlayType = {};
64
+ for (const type of COMMON_MIME_TYPES) canPlayType[type] = probe.canPlayType(type);
65
+ post({
66
+ kind: "welcome",
67
+ timeOrigin: performance.timeOrigin,
68
+ canPlayType
69
+ });
70
+ };
71
+ const captureFrame = (entry) => {
72
+ const { video } = entry;
73
+ if (video.readyState < 2 || typeof VideoFrame !== "function") return null;
74
+ try {
75
+ return new VideoFrame(video);
76
+ } catch {
77
+ return null;
78
+ }
79
+ };
80
+ const create = (id) => {
81
+ const video = document.createElement("video");
82
+ video.playsInline = true;
83
+ const entry = {
84
+ video,
85
+ frameCallback: null,
86
+ lastFrameTimestamp: null,
87
+ frameInFlight: false,
88
+ pendingFrame: null,
89
+ sendPendingFrame: () => {},
90
+ frameDuration: null,
91
+ detach: () => {}
92
+ };
93
+ const noteFrame = (frame) => {
94
+ entry.lastFrameTimestamp = frame.timestamp;
95
+ };
96
+ let previousPresented = null;
97
+ const learnFrameDuration = (frame, presentedFrames) => {
98
+ const previous = previousPresented;
99
+ previousPresented = {
100
+ frames: presentedFrames,
101
+ timestamp: frame.timestamp
102
+ };
103
+ if (!previous || presentedFrames !== previous.frames + 1 || frame.timestamp <= previous.timestamp) return;
104
+ const delta = frame.timestamp - previous.timestamp;
105
+ entry.frameDuration = entry.frameDuration === null ? delta : Math.min(entry.frameDuration, delta);
106
+ };
107
+ const shows = (frame, target) => {
108
+ if (!video.paused && frame.timestamp >= target - TIMESTAMP_EPSILON) return true;
109
+ if (frame.timestamp > target + TIMESTAMP_EPSILON) return false;
110
+ const duration = frame.duration || entry.frameDuration;
111
+ if (duration) return target < frame.timestamp + duration + TIMESTAMP_EPSILON;
112
+ return frame.timestamp !== entry.lastFrameTimestamp;
113
+ };
114
+ const dropPendingFrame = () => {
115
+ entry.pendingFrame?.frame.close();
116
+ entry.pendingFrame = null;
117
+ };
118
+ const sendFrame = (frame, metadata) => {
119
+ entry.frameInFlight = true;
120
+ post({
121
+ kind: "frame",
122
+ id,
123
+ ack,
124
+ state: snapshot(video),
125
+ frame,
126
+ metadata
127
+ }, [frame]);
128
+ };
129
+ entry.sendPendingFrame = () => {
130
+ entry.frameInFlight = false;
131
+ const pending = entry.pendingFrame;
132
+ if (!pending) return;
133
+ entry.pendingFrame = null;
134
+ sendFrame(pending.frame, pending.metadata);
135
+ };
136
+ const sendEvent = (type, frame) => {
137
+ if (frame || type === "emptied") dropPendingFrame();
138
+ if (!frame) {
139
+ if (type === "emptied") entry.lastFrameTimestamp = null;
140
+ post({
141
+ kind: "event",
142
+ id,
143
+ ack,
144
+ type,
145
+ state: snapshot(video)
146
+ });
147
+ return;
148
+ }
149
+ noteFrame(frame);
150
+ post({
151
+ kind: "event",
152
+ id,
153
+ ack,
154
+ type,
155
+ state: snapshot(video),
156
+ frame,
157
+ metadata: syntheticMetadata(video, frame)
158
+ }, [frame]);
159
+ };
160
+ let held = null;
161
+ const releaseHeld = (frame) => {
162
+ if (!held) return;
163
+ const { type, queue, timer } = held;
164
+ held = null;
165
+ clearTimeout(timer);
166
+ sendEvent(type, frame);
167
+ for (const queued of queue) dispatch(queued);
168
+ };
169
+ const dispatch = (type) => {
170
+ if (held) {
171
+ held.queue.push(type);
172
+ return;
173
+ }
174
+ if (!FRAME_EVENTS.has(type)) {
175
+ sendEvent(type, null);
176
+ return;
177
+ }
178
+ const frame = captureFrame(entry);
179
+ const target = video.currentTime * 1e6;
180
+ if (!frame || shows(frame, target)) {
181
+ sendEvent(type, frame);
182
+ return;
183
+ }
184
+ frame.close();
185
+ held = {
186
+ type,
187
+ target,
188
+ queue: [],
189
+ timer: setTimeout(() => releaseHeld(captureFrame(entry)), FRAME_WAIT_TIMEOUT)
190
+ };
191
+ };
192
+ const onEvent = (event) => dispatch(event.type);
193
+ for (const type of MEDIA_EVENTS) video.addEventListener(type, onEvent);
194
+ const onFrame = (_now, metadata) => {
195
+ entry.frameCallback = video.requestVideoFrameCallback(onFrame);
196
+ const frame = captureFrame(entry);
197
+ if (!frame) return;
198
+ learnFrameDuration(frame, metadata.presentedFrames);
199
+ if (held) {
200
+ if (shows(frame, held.target)) releaseHeld(frame);
201
+ else frame.close();
202
+ return;
203
+ }
204
+ if (frame.timestamp === entry.lastFrameTimestamp) {
205
+ frame.close();
206
+ return;
207
+ }
208
+ noteFrame(frame);
209
+ if (entry.frameInFlight) {
210
+ dropPendingFrame();
211
+ entry.pendingFrame = {
212
+ frame,
213
+ metadata: toMetadata(metadata)
214
+ };
215
+ } else sendFrame(frame, toMetadata(metadata));
216
+ };
217
+ if (typeof video.requestVideoFrameCallback === "function") entry.frameCallback = video.requestVideoFrameCallback(onFrame);
218
+ entry.detach = () => {
219
+ dropPendingFrame();
220
+ for (const type of MEDIA_EVENTS) video.removeEventListener(type, onEvent);
221
+ if (entry.frameCallback !== null) video.cancelVideoFrameCallback(entry.frameCallback);
222
+ if (held) clearTimeout(held.timer);
223
+ held = null;
224
+ };
225
+ entries.set(id, entry);
226
+ videos.set(id, video);
227
+ options.container?.append(video);
228
+ options.onVideoCreated?.(video, id);
229
+ };
230
+ const release = (id) => {
231
+ const entry = entries.get(id);
232
+ if (!entry) return;
233
+ entries.delete(id);
234
+ videos.delete(id);
235
+ sentNetworkState.delete(id);
236
+ const { video } = entry;
237
+ options.onVideoDisposed?.(video, id);
238
+ entry.detach();
239
+ video.pause();
240
+ video.removeAttribute("src");
241
+ video.srcObject = null;
242
+ video.load();
243
+ video.remove();
244
+ };
245
+ const handle = (message) => {
246
+ if ("seq" in message) ack = Math.max(ack, message.seq);
247
+ switch (message.kind) {
248
+ case "hello":
249
+ welcome();
250
+ return;
251
+ case "frameAck":
252
+ entries.get(message.id)?.sendPendingFrame();
253
+ return;
254
+ case "canPlayType":
255
+ post({
256
+ kind: "result",
257
+ callId: message.callId,
258
+ value: probeCanPlayType(message.type)
259
+ });
260
+ return;
261
+ case "create":
262
+ create(message.id);
263
+ break;
264
+ case "dispose":
265
+ release(message.id);
266
+ return;
267
+ case "set": {
268
+ const video = entries.get(message.id)?.video;
269
+ if (!video) return;
270
+ applyProperty(video, message.prop, message.value);
271
+ break;
272
+ }
273
+ case "call": {
274
+ const video = entries.get(message.id)?.video;
275
+ if (!video) {
276
+ if (message.callId !== void 0) post({
277
+ kind: "result",
278
+ callId: message.callId,
279
+ error: {
280
+ name: "InvalidStateError",
281
+ message: "The element has been disposed."
282
+ }
283
+ });
284
+ return;
285
+ }
286
+ invoke(video, message.method, message.args).then((value) => message.callId !== void 0 && post({
287
+ kind: "result",
288
+ callId: message.callId,
289
+ value
290
+ }), (error) => message.callId !== void 0 && post({
291
+ kind: "result",
292
+ callId: message.callId,
293
+ error: serializeError(error)
294
+ }));
295
+ break;
296
+ }
297
+ }
298
+ const video = entries.get(message.id)?.video;
299
+ if (video) sendState(message.id, video);
300
+ };
301
+ const onMessage = (event) => {
302
+ if (isProtocolMessage(event.data)) handle(event.data);
303
+ };
304
+ endpoint.addEventListener("message", onMessage);
305
+ endpoint.start?.();
306
+ welcome();
307
+ return {
308
+ videos,
309
+ dispose() {
310
+ if (disposed) return;
311
+ for (const id of entries.keys()) release(id);
312
+ endpoint.removeEventListener("message", onMessage);
313
+ hosted.delete(endpoint);
314
+ disposed = true;
315
+ }
316
+ };
317
+ }
318
+ function applyProperty(video, prop, value) {
319
+ try {
320
+ if (prop === "src") video.src = value;
321
+ else if (prop === "srcObject") video.srcObject = value;
322
+ else if (prop === "currentTime") video.currentTime = value;
323
+ else if (MIRRORED_PROPERTIES.includes(prop)) video[prop] = value;
324
+ } catch (error) {
325
+ console.warn(`[html-video-element-webworker-polyfill] failed to set "${prop}":`, error);
326
+ }
327
+ }
328
+ async function invoke(video, method, args) {
329
+ switch (method) {
330
+ case "play":
331
+ await video.play();
332
+ return;
333
+ case "pause": return video.pause();
334
+ case "load": return video.load();
335
+ case "fastSeek":
336
+ if (typeof video.fastSeek === "function") video.fastSeek(args[0]);
337
+ else video.currentTime = args[0];
338
+ return;
339
+ case "removeAttribute": return video.removeAttribute(args[0]);
340
+ default: throw new DOMException(`Unknown method ${method}`, "NotSupportedError");
341
+ }
342
+ }
343
+ let canPlayTypeProbe;
344
+ function probeCanPlayType(type) {
345
+ canPlayTypeProbe ??= document.createElement("video");
346
+ return canPlayTypeProbe.canPlayType(type);
347
+ }
348
+ function ranges(timeRanges) {
349
+ const result = [];
350
+ for (let i = 0; i < timeRanges.length; i++) result.push([timeRanges.start(i), timeRanges.end(i)]);
351
+ return result;
352
+ }
353
+ function snapshot(video) {
354
+ const quality = typeof video.getVideoPlaybackQuality === "function" ? video.getVideoPlaybackQuality() : null;
355
+ return {
356
+ currentSrc: video.currentSrc,
357
+ currentTime: video.currentTime,
358
+ duration: video.duration,
359
+ ended: video.ended,
360
+ error: video.error ? {
361
+ code: video.error.code,
362
+ message: video.error.message
363
+ } : null,
364
+ muted: video.muted,
365
+ networkState: video.networkState,
366
+ paused: video.paused,
367
+ playbackRate: video.playbackRate,
368
+ readyState: video.readyState,
369
+ seeking: video.seeking,
370
+ videoHeight: video.videoHeight,
371
+ videoWidth: video.videoWidth,
372
+ volume: video.volume,
373
+ buffered: ranges(video.buffered),
374
+ played: ranges(video.played),
375
+ seekable: ranges(video.seekable),
376
+ quality: quality ? {
377
+ creationTime: quality.creationTime,
378
+ droppedVideoFrames: quality.droppedVideoFrames,
379
+ totalVideoFrames: quality.totalVideoFrames
380
+ } : null
381
+ };
382
+ }
383
+ function toMetadata(metadata) {
384
+ const result = {
385
+ presentationTime: metadata.presentationTime,
386
+ expectedDisplayTime: metadata.expectedDisplayTime,
387
+ width: metadata.width,
388
+ height: metadata.height,
389
+ mediaTime: metadata.mediaTime,
390
+ presentedFrames: metadata.presentedFrames
391
+ };
392
+ if (metadata.processingDuration !== void 0) result.processingDuration = metadata.processingDuration;
393
+ if (metadata.captureTime !== void 0) result.captureTime = metadata.captureTime;
394
+ if (metadata.receiveTime !== void 0) result.receiveTime = metadata.receiveTime;
395
+ if (metadata.rtpTimestamp !== void 0) result.rtpTimestamp = metadata.rtpTimestamp;
396
+ return result;
397
+ }
398
+ function syntheticMetadata(video, frame) {
399
+ const now = performance.now();
400
+ const quality = typeof video.getVideoPlaybackQuality === "function" ? video.getVideoPlaybackQuality() : null;
401
+ return {
402
+ presentationTime: now,
403
+ expectedDisplayTime: now,
404
+ width: frame.displayWidth,
405
+ height: frame.displayHeight,
406
+ mediaTime: frame.timestamp / 1e6,
407
+ presentedFrames: quality?.totalVideoFrames ?? 0
408
+ };
409
+ }
410
+ function serializeError(error) {
411
+ if (error instanceof Error || error instanceof DOMException) return {
412
+ name: error.name,
413
+ message: error.message
414
+ };
415
+ return {
416
+ name: "Error",
417
+ message: String(error)
418
+ };
419
+ }
420
+ //#endregion
421
+ export { createVideoHost as t };
422
+
423
+ //# sourceMappingURL=host-D-rmvsLs.js.map