html-video-element-webworker-polyfill 0.1.2 → 0.2.1

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.
@@ -1 +0,0 @@
1
- {"version":3,"file":"host-D-rmvsLs.js","names":[],"sources":["../src/host/video-host.ts"],"sourcesContent":["import {\n CHANNEL,\n COMMON_MIME_TYPES,\n type CanPlayTypeResult,\n type ClientMessage,\n type FrameMetadata,\n type HostMessage,\n MEDIA_EVENTS,\n MIRRORED_PROPERTIES,\n type MediaState,\n type MessageEndpoint,\n type Ranges,\n type SerializedError,\n isProtocolMessage,\n} from \"../shared/protocol.ts\";\nimport { assertMainThread, isMainThread, isMessageEndpoint } from \"../shared/environment.ts\";\n\nexport interface VideoHostOptions {\n container?: HTMLElement | null;\n onVideoCreated?: (video: HTMLVideoElement, id: number) => void;\n onVideoDisposed?: (video: HTMLVideoElement, id: number) => void;\n}\n\nexport interface VideoHost {\n readonly videos: ReadonlyMap<number, HTMLVideoElement>;\n dispose(): void;\n}\n\ntype Distribute<T> = T extends unknown ? Omit<T, typeof CHANNEL> : never;\ntype OutgoingHostMessage = Distribute<HostMessage>;\n\nconst FRAME_EVENTS = new Set([\"loadeddata\", \"seeked\"]);\n\nconst SILENT_STATE_POLL_INTERVAL = 16;\nconst SILENT_STATE_POLLS = 32;\n\ninterface Entry {\n video: HTMLVideoElement;\n frameCallback: number | null;\n frameInFlight: boolean;\n pendingFrame: { frame: VideoFrame; metadata: FrameMetadata } | null;\n sendPendingFrame: () => void;\n lastFrameTimestamp: number | null;\n frameDuration: number | null;\n detach: () => void;\n}\n\nconst FRAME_WAIT_TIMEOUT = 500;\nconst TIMESTAMP_EPSILON = 1000;\n\nconst hosted = new WeakSet<object>();\n\nexport function createVideoHost(endpoint: MessageEndpoint, options: VideoHostOptions = {}): VideoHost {\n assertMainThread(\"createVideoHost()\");\n if (!isMessageEndpoint(endpoint) || (isMainThread() && endpoint === (globalThis as object))) {\n throw new TypeError(\n \"html-video-element-webworker-polyfill: createVideoHost() expects the Worker (or a MessagePort connected to it) that uses the polyfill.\",\n );\n }\n if (hosted.has(endpoint)) {\n throw new DOMException(\n \"html-video-element-webworker-polyfill: createVideoHost() was already called for this endpoint; call dispose() on the existing host first.\",\n \"InvalidStateError\",\n );\n }\n hosted.add(endpoint);\n const entries = new Map<number, Entry>();\n const videos = new Map<number, HTMLVideoElement>();\n let ack = 0;\n let disposed = false;\n\n const sentNetworkState = new Map<number, number>();\n const post = (message: OutgoingHostMessage, transfer: Transferable[] = []): void => {\n if (disposed) {\n for (const item of transfer) (item as Partial<VideoFrame>).close?.();\n return;\n }\n if (\"state\" in message) sentNetworkState.set(message.id, message.state.networkState);\n endpoint.postMessage({ ...message, [CHANNEL]: 1 }, transfer);\n };\n\n const watching = new Map<number, { polls: number }>();\n const sendState = (id: number, video: HTMLVideoElement): void => {\n post({ kind: \"state\", id, ack, state: snapshot(video) });\n const existing = watching.get(id);\n if (existing) {\n existing.polls = 0;\n return;\n }\n const watch = { polls: 0 };\n watching.set(id, watch);\n const poll = (): void => {\n if (entries.get(id)?.video !== video || ++watch.polls > SILENT_STATE_POLLS) {\n watching.delete(id);\n return;\n }\n if (video.networkState !== sentNetworkState.get(id)) {\n post({ kind: \"state\", id, ack, state: snapshot(video) });\n }\n setTimeout(poll, SILENT_STATE_POLL_INTERVAL);\n };\n setTimeout(poll, SILENT_STATE_POLL_INTERVAL);\n };\n\n const welcome = (): void => {\n const probe = document.createElement(\"video\");\n const canPlayType: Record<string, CanPlayTypeResult> = {};\n for (const type of COMMON_MIME_TYPES) canPlayType[type] = probe.canPlayType(type);\n post({ kind: \"welcome\", timeOrigin: performance.timeOrigin, canPlayType });\n };\n\n const captureFrame = (entry: Entry): VideoFrame | null => {\n const { video } = entry;\n if (video.readyState < 2 || typeof VideoFrame !== \"function\") return null;\n try {\n return new VideoFrame(video);\n } catch {\n return null;\n }\n };\n\n const create = (id: number): void => {\n const video = document.createElement(\"video\");\n video.playsInline = true;\n const entry: Entry = {\n video,\n frameCallback: null,\n lastFrameTimestamp: null,\n frameInFlight: false,\n pendingFrame: null,\n sendPendingFrame: () => {},\n frameDuration: null,\n detach: () => {},\n };\n\n const noteFrame = (frame: VideoFrame): void => {\n entry.lastFrameTimestamp = frame.timestamp;\n };\n\n let previousPresented: { frames: number; timestamp: number } | null = null;\n const learnFrameDuration = (frame: VideoFrame, presentedFrames: number): void => {\n const previous = previousPresented;\n previousPresented = { frames: presentedFrames, timestamp: frame.timestamp };\n if (!previous || presentedFrames !== previous.frames + 1 || frame.timestamp <= previous.timestamp) return;\n const delta = frame.timestamp - previous.timestamp;\n entry.frameDuration = entry.frameDuration === null ? delta : Math.min(entry.frameDuration, delta);\n };\n\n const shows = (frame: VideoFrame, target: number): boolean => {\n if (!video.paused && frame.timestamp >= target - TIMESTAMP_EPSILON) return true;\n if (frame.timestamp > target + TIMESTAMP_EPSILON) return false;\n const duration = frame.duration || entry.frameDuration;\n if (duration) return target < frame.timestamp + duration + TIMESTAMP_EPSILON;\n return frame.timestamp !== entry.lastFrameTimestamp;\n };\n\n const dropPendingFrame = (): void => {\n entry.pendingFrame?.frame.close();\n entry.pendingFrame = null;\n };\n\n const sendFrame = (frame: VideoFrame, metadata: FrameMetadata): void => {\n entry.frameInFlight = true;\n post({ kind: \"frame\", id, ack, state: snapshot(video), frame, metadata }, [frame]);\n };\n\n entry.sendPendingFrame = () => {\n entry.frameInFlight = false;\n const pending = entry.pendingFrame;\n if (!pending) return;\n entry.pendingFrame = null;\n sendFrame(pending.frame, pending.metadata);\n };\n\n const sendEvent = (type: string, frame: VideoFrame | null): void => {\n if (frame || type === \"emptied\") dropPendingFrame();\n if (!frame) {\n if (type === \"emptied\") entry.lastFrameTimestamp = null;\n post({ kind: \"event\", id, ack, type, state: snapshot(video) });\n return;\n }\n noteFrame(frame);\n post({ kind: \"event\", id, ack, type, state: snapshot(video), frame, metadata: syntheticMetadata(video, frame) }, [\n frame,\n ]);\n };\n\n let held: { type: string; target: number; queue: string[]; timer: ReturnType<typeof setTimeout> } | null = null;\n\n const releaseHeld = (frame: VideoFrame | null): void => {\n if (!held) return;\n const { type, queue, timer } = held;\n held = null;\n clearTimeout(timer);\n sendEvent(type, frame);\n for (const queued of queue) dispatch(queued);\n };\n\n const dispatch = (type: string): void => {\n if (held) {\n held.queue.push(type);\n return;\n }\n if (!FRAME_EVENTS.has(type)) {\n sendEvent(type, null);\n return;\n }\n const frame = captureFrame(entry);\n const target = video.currentTime * 1e6;\n if (!frame || shows(frame, target)) {\n sendEvent(type, frame);\n return;\n }\n frame.close();\n held = { type, target, queue: [], timer: setTimeout(() => releaseHeld(captureFrame(entry)), FRAME_WAIT_TIMEOUT) };\n };\n\n const onEvent = (event: Event): void => dispatch(event.type);\n for (const type of MEDIA_EVENTS) video.addEventListener(type, onEvent);\n\n const onFrame = (_now: number, metadata: VideoFrameCallbackMetadata): void => {\n entry.frameCallback = video.requestVideoFrameCallback(onFrame);\n const frame = captureFrame(entry);\n if (!frame) return;\n learnFrameDuration(frame, metadata.presentedFrames);\n if (held) {\n if (shows(frame, held.target)) releaseHeld(frame);\n else frame.close();\n return;\n }\n if (frame.timestamp === entry.lastFrameTimestamp) {\n frame.close();\n return;\n }\n noteFrame(frame);\n if (entry.frameInFlight) {\n dropPendingFrame();\n entry.pendingFrame = { frame, metadata: toMetadata(metadata) };\n } else {\n sendFrame(frame, toMetadata(metadata));\n }\n };\n if (typeof video.requestVideoFrameCallback === \"function\") {\n entry.frameCallback = video.requestVideoFrameCallback(onFrame);\n }\n\n entry.detach = () => {\n dropPendingFrame();\n for (const type of MEDIA_EVENTS) video.removeEventListener(type, onEvent);\n if (entry.frameCallback !== null) video.cancelVideoFrameCallback(entry.frameCallback);\n if (held) clearTimeout(held.timer);\n held = null;\n };\n\n entries.set(id, entry);\n videos.set(id, video);\n options.container?.append(video);\n options.onVideoCreated?.(video, id);\n };\n\n const release = (id: number): void => {\n const entry = entries.get(id);\n if (!entry) return;\n entries.delete(id);\n videos.delete(id);\n sentNetworkState.delete(id);\n const { video } = entry;\n options.onVideoDisposed?.(video, id);\n entry.detach();\n video.pause();\n video.removeAttribute(\"src\");\n video.srcObject = null;\n video.load();\n video.remove();\n };\n\n const handle = (message: ClientMessage): void => {\n if (\"seq\" in message) ack = Math.max(ack, message.seq);\n switch (message.kind) {\n case \"hello\":\n welcome();\n return;\n case \"frameAck\":\n entries.get(message.id)?.sendPendingFrame();\n return;\n case \"canPlayType\":\n post({ kind: \"result\", callId: message.callId, value: probeCanPlayType(message.type) });\n return;\n case \"create\":\n create(message.id);\n break;\n case \"dispose\":\n release(message.id);\n return;\n case \"set\": {\n const video = entries.get(message.id)?.video;\n if (!video) return;\n applyProperty(video, message.prop, message.value);\n break;\n }\n case \"call\": {\n const video = entries.get(message.id)?.video;\n if (!video) {\n if (message.callId !== undefined) {\n post({\n kind: \"result\",\n callId: message.callId,\n error: { name: \"InvalidStateError\", message: \"The element has been disposed.\" },\n });\n }\n return;\n }\n invoke(video, message.method, message.args).then(\n (value) => message.callId !== undefined && post({ kind: \"result\", callId: message.callId, value }),\n (error: unknown) =>\n message.callId !== undefined &&\n post({ kind: \"result\", callId: message.callId, error: serializeError(error) }),\n );\n break;\n }\n }\n const video = entries.get(message.id)?.video;\n if (video) sendState(message.id, video);\n };\n\n const onMessage = (event: MessageEvent): void => {\n if (isProtocolMessage(event.data)) handle(event.data as ClientMessage);\n };\n endpoint.addEventListener(\"message\", onMessage);\n endpoint.start?.();\n welcome();\n\n return {\n videos,\n dispose() {\n if (disposed) return;\n for (const id of entries.keys()) release(id);\n endpoint.removeEventListener(\"message\", onMessage);\n hosted.delete(endpoint);\n disposed = true;\n },\n };\n}\n\nfunction applyProperty(video: HTMLVideoElement, prop: string, value: unknown): void {\n try {\n if (prop === \"src\") video.src = value as string;\n else if (prop === \"srcObject\") video.srcObject = value as MediaProvider | null;\n else if (prop === \"currentTime\") video.currentTime = value as number;\n else if (MIRRORED_PROPERTIES.includes(prop)) (video as unknown as Record<string, unknown>)[prop] = value;\n } catch (error) {\n console.warn(`[html-video-element-webworker-polyfill] failed to set \"${prop}\":`, error);\n }\n}\n\nasync function invoke(video: HTMLVideoElement, method: string, args: unknown[]): Promise<unknown> {\n switch (method) {\n case \"play\":\n await video.play();\n return undefined;\n case \"pause\":\n return video.pause();\n case \"load\":\n return video.load();\n case \"fastSeek\":\n if (typeof video.fastSeek === \"function\") video.fastSeek(args[0] as number);\n else video.currentTime = args[0] as number;\n return undefined;\n case \"removeAttribute\":\n return video.removeAttribute(args[0] as string);\n default:\n throw new DOMException(`Unknown method ${method}`, \"NotSupportedError\");\n }\n}\n\nlet canPlayTypeProbe: HTMLVideoElement | undefined;\nfunction probeCanPlayType(type: string): CanPlayTypeResult {\n canPlayTypeProbe ??= document.createElement(\"video\");\n return canPlayTypeProbe.canPlayType(type);\n}\n\nfunction ranges(timeRanges: TimeRanges): Ranges {\n const result: Ranges = [];\n for (let i = 0; i < timeRanges.length; i++) result.push([timeRanges.start(i), timeRanges.end(i)]);\n return result;\n}\n\nfunction snapshot(video: HTMLVideoElement): MediaState {\n const quality = typeof video.getVideoPlaybackQuality === \"function\" ? video.getVideoPlaybackQuality() : null;\n return {\n currentSrc: video.currentSrc,\n currentTime: video.currentTime,\n duration: video.duration,\n ended: video.ended,\n error: video.error ? { code: video.error.code, message: video.error.message } : null,\n muted: video.muted,\n networkState: video.networkState,\n paused: video.paused,\n playbackRate: video.playbackRate,\n readyState: video.readyState,\n seeking: video.seeking,\n videoHeight: video.videoHeight,\n videoWidth: video.videoWidth,\n volume: video.volume,\n buffered: ranges(video.buffered),\n played: ranges(video.played),\n seekable: ranges(video.seekable),\n quality: quality\n ? {\n creationTime: quality.creationTime,\n droppedVideoFrames: quality.droppedVideoFrames,\n totalVideoFrames: quality.totalVideoFrames,\n }\n : null,\n };\n}\n\nfunction toMetadata(metadata: VideoFrameCallbackMetadata): FrameMetadata {\n const result: FrameMetadata = {\n presentationTime: metadata.presentationTime,\n expectedDisplayTime: metadata.expectedDisplayTime,\n width: metadata.width,\n height: metadata.height,\n mediaTime: metadata.mediaTime,\n presentedFrames: metadata.presentedFrames,\n };\n if (metadata.processingDuration !== undefined) result.processingDuration = metadata.processingDuration;\n if (metadata.captureTime !== undefined) result.captureTime = metadata.captureTime;\n if (metadata.receiveTime !== undefined) result.receiveTime = metadata.receiveTime;\n if (metadata.rtpTimestamp !== undefined) result.rtpTimestamp = metadata.rtpTimestamp;\n return result;\n}\n\nfunction syntheticMetadata(video: HTMLVideoElement, frame: VideoFrame): FrameMetadata {\n const now = performance.now();\n const quality = typeof video.getVideoPlaybackQuality === \"function\" ? video.getVideoPlaybackQuality() : null;\n return {\n presentationTime: now,\n expectedDisplayTime: now,\n width: frame.displayWidth,\n height: frame.displayHeight,\n mediaTime: frame.timestamp / 1e6,\n presentedFrames: quality?.totalVideoFrames ?? 0,\n };\n}\n\nfunction serializeError(error: unknown): SerializedError {\n if (error instanceof Error || error instanceof DOMException) return { name: error.name, message: error.message };\n return { name: \"Error\", message: String(error) };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"protocol-Be-N8xdd.js","names":[],"sources":["../src/shared/protocol.ts"],"sourcesContent":["export const CHANNEL = \"__htmlVideoElementWorkerPolyfill\" as const;\n\nexport const MEDIA_EVENTS: readonly string[] = [\n \"abort\",\n \"canplay\",\n \"canplaythrough\",\n \"durationchange\",\n \"emptied\",\n \"encrypted\",\n \"ended\",\n \"error\",\n \"loadeddata\",\n \"loadedmetadata\",\n \"loadstart\",\n \"pause\",\n \"play\",\n \"playing\",\n \"progress\",\n \"ratechange\",\n \"resize\",\n \"seeked\",\n \"seeking\",\n \"stalled\",\n \"suspend\",\n \"timeupdate\",\n \"volumechange\",\n \"waiting\",\n \"waitingforkey\",\n];\n\nexport const MIRRORED_PROPERTIES: readonly string[] = [\n \"autoplay\",\n \"controls\",\n \"crossOrigin\",\n \"defaultMuted\",\n \"defaultPlaybackRate\",\n \"disablePictureInPicture\",\n \"disableRemotePlayback\",\n \"height\",\n \"loop\",\n \"muted\",\n \"playbackRate\",\n \"playsInline\",\n \"poster\",\n \"preload\",\n \"preservesPitch\",\n \"volume\",\n \"width\",\n];\n\nexport type Ranges = Array<[start: number, end: number]>;\n\nexport interface SerializedMediaError {\n code: number;\n message: string;\n}\n\nexport interface SerializedPlaybackQuality {\n creationTime: number;\n droppedVideoFrames: number;\n totalVideoFrames: number;\n}\n\nexport interface MediaState {\n currentSrc: string;\n currentTime: number;\n duration: number;\n ended: boolean;\n error: SerializedMediaError | null;\n muted: boolean;\n networkState: number;\n paused: boolean;\n playbackRate: number;\n readyState: number;\n seeking: boolean;\n videoHeight: number;\n videoWidth: number;\n volume: number;\n buffered: Ranges;\n played: Ranges;\n seekable: Ranges;\n quality: SerializedPlaybackQuality | null;\n}\n\nexport interface FrameMetadata {\n presentationTime: number;\n expectedDisplayTime: number;\n width: number;\n height: number;\n mediaTime: number;\n presentedFrames: number;\n processingDuration?: number;\n captureTime?: number;\n receiveTime?: number;\n rtpTimestamp?: number;\n}\n\nexport interface SerializedError {\n name: string;\n message: string;\n}\n\nexport type ClientMessage =\n | { [CHANNEL]: 1; kind: \"create\"; id: number; seq: number; props: Record<string, unknown> }\n | { [CHANNEL]: 1; kind: \"set\"; id: number; seq: number; prop: string; value: unknown }\n | {\n [CHANNEL]: 1;\n kind: \"call\";\n id: number;\n seq: number;\n method: \"play\" | \"pause\" | \"load\" | \"fastSeek\" | \"removeAttribute\";\n args: unknown[];\n callId?: number;\n }\n | { [CHANNEL]: 1; kind: \"dispose\"; id: number; seq: number }\n | { [CHANNEL]: 1; kind: \"canPlayType\"; type: string; callId: number }\n | { [CHANNEL]: 1; kind: \"frameAck\"; id: number; seq: number }\n | { [CHANNEL]: 1; kind: \"hello\" };\n\nexport type HostMessage =\n | {\n [CHANNEL]: 1;\n kind: \"event\";\n id: number;\n ack: number;\n type: string;\n state: MediaState;\n frame?: VideoFrame;\n metadata?: FrameMetadata;\n }\n | {\n [CHANNEL]: 1;\n kind: \"frame\";\n id: number;\n ack: number;\n state: MediaState;\n frame: VideoFrame;\n metadata: FrameMetadata;\n }\n | { [CHANNEL]: 1; kind: \"state\"; id: number; ack: number; state: MediaState }\n | { [CHANNEL]: 1; kind: \"result\"; callId: number; value?: unknown; error?: SerializedError }\n | {\n [CHANNEL]: 1;\n kind: \"welcome\";\n timeOrigin: number;\n canPlayType: Record<string, CanPlayTypeResult>;\n };\n\nexport type CanPlayTypeResult = \"\" | \"maybe\" | \"probably\";\n\nexport interface MessageEndpoint {\n postMessage(message: unknown, transfer: Transferable[]): void;\n addEventListener(type: \"message\", listener: (event: MessageEvent) => void): void;\n removeEventListener(type: \"message\", listener: (event: MessageEvent) => void): void;\n start?: () => void;\n}\n\nexport function isProtocolMessage(data: unknown): boolean {\n return typeof data === \"object\" && data !== null && (data as Record<string, unknown>)[CHANNEL] === 1;\n}\n\nexport const COMMON_MIME_TYPES: readonly string[] = [\n \"video/mp4\",\n \"video/webm\",\n \"video/ogg\",\n \"video/quicktime\",\n \"video/x-matroska\",\n \"application/vnd.apple.mpegurl\",\n 'video/mp4; codecs=\"avc1.42E01E\"',\n 'video/mp4; codecs=\"avc1.4D401E\"',\n 'video/mp4; codecs=\"avc1.64001E\"',\n 'video/mp4; codecs=\"hvc1.1.6.L93.B0\"',\n 'video/mp4; codecs=\"av01.0.05M.08\"',\n 'video/mp4; codecs=\"vp09.00.10.08\"',\n 'video/webm; codecs=\"vp8\"',\n 'video/webm; codecs=\"vp9\"',\n 'video/webm; codecs=\"av01.0.05M.08\"',\n 'video/ogg; codecs=\"theora\"',\n \"audio/mpeg\",\n \"audio/mp4\",\n \"audio/ogg\",\n \"audio/webm\",\n \"audio/wav\",\n \"audio/flac\",\n];\n"],"mappings":";AAAA,MAAa,UAAU;AAEvB,MAAa,eAAkC;CAC7C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAa,sBAAyC;CACpD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AA6GA,SAAgB,kBAAkB,MAAwB;CACxD,OAAO,OAAO,SAAS,YAAY,SAAS,QAAS,KAAA,wCAA8C;AACrG;AAEA,MAAa,oBAAuC;CAClD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}