@give-tech/ec-player 0.0.1-beta.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.
- package/dist/decoder/H264Decoder.d.ts +14 -0
- package/dist/decoder/H264Decoder.d.ts.map +1 -0
- package/dist/decoder/HEVCDecoder.d.ts +21 -0
- package/dist/decoder/HEVCDecoder.d.ts.map +1 -0
- package/dist/decoder/WASMLoader.d.ts +10 -0
- package/dist/decoder/WASMLoader.d.ts.map +1 -0
- package/dist/decoder/index.d.ts +4 -0
- package/dist/decoder/index.d.ts.map +1 -0
- package/dist/demuxer/DemuxerFactory.d.ts +24 -0
- package/dist/demuxer/DemuxerFactory.d.ts.map +1 -0
- package/dist/demuxer/FLVDemuxer.d.ts +132 -0
- package/dist/demuxer/FLVDemuxer.d.ts.map +1 -0
- package/dist/demuxer/FormatDetector.d.ts +21 -0
- package/dist/demuxer/FormatDetector.d.ts.map +1 -0
- package/dist/demuxer/PESExtractor.d.ts +11 -0
- package/dist/demuxer/PESExtractor.d.ts.map +1 -0
- package/dist/demuxer/TSDemuxer.d.ts +17 -0
- package/dist/demuxer/TSDemuxer.d.ts.map +1 -0
- package/dist/demuxer/fMP4Demuxer.d.ts +131 -0
- package/dist/demuxer/fMP4Demuxer.d.ts.map +1 -0
- package/dist/demuxer/index.d.ts +7 -0
- package/dist/demuxer/index.d.ts.map +1 -0
- package/dist/env/EnvDetector.d.ts +167 -0
- package/dist/env/EnvDetector.d.ts.map +1 -0
- package/dist/env/index.d.ts +5 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3869 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/NALParser.d.ts +21 -0
- package/dist/parser/NALParser.d.ts.map +1 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/player/BasePlayer.d.ts +118 -0
- package/dist/player/BasePlayer.d.ts.map +1 -0
- package/dist/player/EcPlayerCore.d.ts +77 -0
- package/dist/player/EcPlayerCore.d.ts.map +1 -0
- package/dist/player/FLVPlayer.d.ts +134 -0
- package/dist/player/FLVPlayer.d.ts.map +1 -0
- package/dist/player/HLSPlayer.d.ts +99 -0
- package/dist/player/HLSPlayer.d.ts.map +1 -0
- package/dist/player/index.d.ts +3 -0
- package/dist/player/index.d.ts.map +1 -0
- package/dist/prefetch/BasePrefetcher.d.ts +99 -0
- package/dist/prefetch/BasePrefetcher.d.ts.map +1 -0
- package/dist/prefetch/SegmentPrefetcher.d.ts +116 -0
- package/dist/prefetch/SegmentPrefetcher.d.ts.map +1 -0
- package/dist/prefetch/StreamPrefetcher.d.ts +113 -0
- package/dist/prefetch/StreamPrefetcher.d.ts.map +1 -0
- package/dist/prefetch/index.d.ts +13 -0
- package/dist/prefetch/index.d.ts.map +1 -0
- package/dist/prefetch/types.d.ts +93 -0
- package/dist/prefetch/types.d.ts.map +1 -0
- package/dist/renderer/Canvas2DRenderer.d.ts +16 -0
- package/dist/renderer/Canvas2DRenderer.d.ts.map +1 -0
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +117 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/package.json +48 -0
- package/wasm/decoder-simd.js +19 -0
- package/wasm/decoder-simd.wasm +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/decoder/WASMLoader.ts","../src/decoder/H264Decoder.ts","../src/player/BasePlayer.ts","../src/demuxer/TSDemuxer.ts","../src/demuxer/PESExtractor.ts","../src/demuxer/fMP4Demuxer.ts","../src/parser/NALParser.ts","../src/prefetch/BasePrefetcher.ts","../src/prefetch/SegmentPrefetcher.ts","../src/prefetch/StreamPrefetcher.ts","../src/prefetch/types.ts","../src/player/HLSPlayer.ts","../src/demuxer/FLVDemuxer.ts","../src/decoder/HEVCDecoder.ts","../src/player/FLVPlayer.ts","../src/demuxer/FormatDetector.ts","../src/renderer/Canvas2DRenderer.ts","../src/player/EcPlayerCore.ts","../src/env/EnvDetector.ts","../src/utils/logger.ts"],"sourcesContent":["/**\n * WASM 加载器\n */\n\nimport type { WASMModule } from '../types'\n\nexport class WASMLoader {\n private module: WASMModule | null = null\n\n async load(wasmPath: string): Promise<WASMModule> {\n return new Promise((resolve, reject) => {\n const script = document.createElement('script')\n script.src = wasmPath\n script.type = 'text/javascript'\n\n script.onload = async () => {\n try {\n const createFFmpegDecoder = (window as any).createFFmpegDecoder\n if (typeof createFFmpegDecoder !== 'function') {\n reject(new Error('createFFmpegDecoder not found'))\n return\n }\n\n this.module = await createFFmpegDecoder()\n\n if (typeof this.module?._create_decoder !== 'function') {\n reject(new Error('Module initialization failed'))\n return\n }\n\n resolve(this.module)\n } catch (e: any) {\n reject(new Error(`Failed to initialize decoder: ${e.message}`))\n }\n }\n\n script.onerror = () => {\n reject(new Error(`Failed to load script: ${wasmPath}`))\n }\n\n document.head.appendChild(script)\n })\n }\n\n getModule(): WASMModule | null {\n return this.module\n }\n}\n","/**\n * H.264 解码器\n */\n\nimport type { WASMModule, DecoderContext, VideoFrame, NALUnit } from '../types'\nimport { WASMLoader } from './WASMLoader'\n\nexport class H264Decoder {\n private wasmModule: WASMModule | null = null\n private decoderContext: DecoderContext | null = null\n\n constructor(wasmLoader: WASMLoader) {\n this.wasmModule = wasmLoader.getModule()\n }\n\n async init(): Promise<void> {\n if (!this.wasmModule) {\n throw new Error('WASM module not loaded')\n }\n\n this.decoderContext = this.wasmModule._create_decoder(27)\n\n if (this.decoderContext === 0 || this.decoderContext === null) {\n throw new Error('Failed to create decoder context')\n }\n }\n\n decode(nalUnit: NALUnit): VideoFrame | null {\n if (this.decoderContext === null || !this.wasmModule) {\n return null\n }\n\n const dataPtr = this.wasmModule._malloc(nalUnit.size)\n this.wasmModule.HEAPU8.set(nalUnit.data, dataPtr)\n\n const result = this.wasmModule._decode_video(\n this.decoderContext,\n dataPtr,\n nalUnit.size\n )\n\n this.wasmModule._free(dataPtr)\n\n if (result === 1) {\n const width = this.wasmModule._get_frame_width(this.decoderContext)\n const height = this.wasmModule._get_frame_height(this.decoderContext)\n\n if (width <= 0 || height <= 0) {\n return null\n }\n\n const yPtr = this.wasmModule._get_frame_data(this.decoderContext, 0)\n const uPtr = this.wasmModule._get_frame_data(this.decoderContext, 1)\n const vPtr = this.wasmModule._get_frame_data(this.decoderContext, 2)\n\n const yLineSize = this.wasmModule._get_frame_linesize(this.decoderContext, 0)\n const uLineSize = this.wasmModule._get_frame_linesize(this.decoderContext, 1)\n const vLineSize = this.wasmModule._get_frame_linesize(this.decoderContext, 2)\n\n const frameData = this.yuv420pToRgba(\n yPtr, uPtr, vPtr,\n width, height,\n yLineSize, uLineSize, vLineSize\n )\n\n return { width, height, data: frameData }\n }\n\n return null\n }\n\n private yuv420pToRgba(\n yPtr: number, uPtr: number, vPtr: number,\n width: number, height: number,\n yLineSize: number, uLineSize: number, vLineSize: number\n ): Uint8Array {\n const rgba = new Uint8Array(width * height * 4)\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const yIndex = y * yLineSize + x\n const uIndex = (y >> 1) * uLineSize + (x >> 1)\n const vIndex = (y >> 1) * vLineSize + (x >> 1)\n\n const yValue = this.wasmModule!.HEAPU8[yPtr + yIndex]\n const uValue = this.wasmModule!.HEAPU8[uPtr + uIndex]\n const vValue = this.wasmModule!.HEAPU8[vPtr + vIndex]\n\n const c = yValue - 16\n const d = uValue - 128\n const e = vValue - 128\n\n let r = (298 * c + 409 * e + 128) >> 8\n let g = (298 * c - 100 * d - 208 * e + 128) >> 8\n let b = (298 * c + 516 * d + 128) >> 8\n\n r = r < 0 ? 0 : (r > 255 ? 255 : r)\n g = g < 0 ? 0 : (g > 255 ? 255 : g)\n b = b < 0 ? 0 : (b > 255 ? 255 : b)\n\n const rgbaIndex = (y * width + x) * 4\n rgba[rgbaIndex] = r\n rgba[rgbaIndex + 1] = g\n rgba[rgbaIndex + 2] = b\n rgba[rgbaIndex + 3] = 255\n }\n }\n\n return rgba\n }\n}\n","/**\n * 播放器基类\n *\n * 提供播放器的公共功能:\n * - 解码器初始化\n * - 渲染循环\n * - 状态管理\n * - 工具方法\n */\n\nimport { WASMLoader } from '../decoder/WASMLoader'\nimport { H264Decoder } from '../decoder/H264Decoder'\nimport { Canvas2DRenderer } from '../renderer/Canvas2DRenderer'\nimport type { PlayerState, PlayerCallbacks, VideoFrame } from '../types'\n\n// 播放器配置\nexport interface PlayerConfig {\n /** WASM 文件路径 */\n wasmPath?: string\n /** 帧缓冲区目标大小 - 控制缓冲的最大帧数 */\n targetBufferSize?: number\n /** 每批解码帧数 - 批量解码后再让出主线程 */\n decodeBatchSize?: number\n /** NAL/Sample 队列上限 - 超过则暂停下载 */\n maxQueueSize?: number\n /** 是否为直播流 - 直播流会持续下载数据 */\n isLive?: boolean\n}\n\n// 默认配置\nexport const DEFAULT_PLAYER_CONFIG: Required<PlayerConfig> = {\n wasmPath: '/wasm/decoder-simd.js',\n targetBufferSize: 60,\n decodeBatchSize: 2,\n maxQueueSize: 200,\n isLive: false\n}\n\nexport abstract class BasePlayer<Config extends PlayerConfig = PlayerConfig> {\n protected config: Required<Config>\n protected callbacks: PlayerCallbacks\n\n protected wasmLoader = new WASMLoader()\n protected decoder: H264Decoder | null = null\n protected renderer: Canvas2DRenderer | null = null\n protected decoderInitialized = false\n\n protected isPlaying = false\n protected frameTimer: number | null = null\n protected frameBuffer: VideoFrame[] = []\n protected droppedFrames = 0\n protected decodeLoopAbort = false\n\n // 时间追踪\n protected _currentTime = 0\n protected _duration = 0\n\n protected state: PlayerState = {\n isPlaying: false,\n isLoaded: false,\n isLoading: false,\n fps: 0,\n resolution: '-',\n decoded: 0,\n downloaded: 0,\n droppedFrames: 0,\n isPrefetching: false,\n segmentIndex: 0,\n totalSegments: 0,\n downloadSpeed: 0,\n currentTime: 0,\n duration: 0\n }\n\n constructor(config: Config, callbacks: PlayerCallbacks, defaults: Required<Config>) {\n this.config = { ...defaults, ...config } as Required<Config>\n this.callbacks = callbacks\n }\n\n // ==================== 抽象方法 ====================\n // 子类必须实现这些方法\n\n /**\n * 加载视频源\n */\n abstract load(url: string): Promise<void>\n\n /**\n * 解码循环\n */\n protected abstract decodeLoop(): Promise<void>\n\n /**\n * 跳转到指定时间\n * @param time 目标时间(毫秒)\n */\n abstract seek(time: number): Promise<void>\n\n // ==================== 公共方法 ====================\n\n /**\n * 设置渲染器\n */\n setRenderer(renderer: Canvas2DRenderer): void {\n this.renderer = renderer\n }\n\n /**\n * 初始化解码器\n */\n async initDecoder(): Promise<void> {\n await this.wasmLoader.load(this.config.wasmPath as string)\n this.decoder = new H264Decoder(this.wasmLoader)\n await this.decoder.init()\n }\n\n /**\n * 开始播放\n */\n async play(): Promise<void> {\n this.isPlaying = true\n this.decodeLoopAbort = false\n this.updateState({ isPlaying: true })\n // 启动解码循环\n this.decodeLoop()\n // 启动渲染循环\n this.frameTimer = requestAnimationFrame(this.renderLoop)\n }\n\n /**\n * 暂停播放\n */\n pause(): void {\n this.isPlaying = false\n this.decodeLoopAbort = true\n this.updateState({ isPlaying: false })\n if (this.frameTimer !== null) {\n cancelAnimationFrame(this.frameTimer)\n this.frameTimer = null\n }\n }\n\n /**\n * 销毁播放器,释放资源\n */\n destroy(): void {\n console.log('[BasePlayer] Destroying player...')\n\n // 停止播放\n this.pause()\n\n // 清空缓冲区\n this.frameBuffer = []\n\n // 重置状态\n this.resetState()\n this.state = {\n isPlaying: false,\n isLoaded: false,\n isLoading: false,\n fps: 0,\n resolution: '-',\n decoded: 0,\n downloaded: 0,\n droppedFrames: 0,\n isPrefetching: false,\n segmentIndex: 0,\n totalSegments: 0,\n downloadSpeed: 0,\n currentTime: 0,\n duration: 0\n }\n\n // 清理解码器引用\n this.decoder = null\n this.renderer = null\n\n console.log('[BasePlayer] Player destroyed')\n }\n\n /**\n * 获取播放状态\n */\n getState(): PlayerState {\n return { ...this.state }\n }\n\n /**\n * 获取当前播放时间(毫秒)\n */\n getCurrentTime(): number {\n return this._currentTime\n }\n\n /**\n * 获取总时长(毫秒)\n */\n getDuration(): number {\n return this._duration\n }\n\n /**\n * 设置当前时间(供子类调用)\n */\n protected setCurrentTime(time: number): void {\n this._currentTime = time\n this.updateState({ currentTime: time })\n }\n\n /**\n * 设置总时长(供子类调用)\n */\n protected setDuration(duration: number): void {\n this._duration = duration\n this.updateState({ duration })\n }\n\n // ==================== 受保护的工具方法 ====================\n\n /**\n * 更新状态\n */\n protected updateState(partial: Partial<PlayerState>): void {\n this.state = { ...this.state, ...partial }\n this.callbacks.onStateChange?.(partial)\n }\n\n /**\n * 快速让出主线程\n */\n protected yieldFast(): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, 0))\n }\n\n /**\n * 休眠\n */\n protected sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n }\n\n /**\n * 重置播放器状态\n */\n protected resetState(): void {\n this.frameBuffer = []\n this.droppedFrames = 0\n this.decoderInitialized = false\n this.decodeLoopAbort = false\n this._currentTime = 0\n this._duration = 0\n }\n\n // ==================== 受保护方法 ====================\n\n /**\n * 渲染循环\n * 子类可以覆盖此方法以实现自定义渲染逻辑\n */\n protected renderLoop = (): void => {\n if (!this.isPlaying) return\n\n this.updateState({\n decoded: this.frameBuffer.length,\n droppedFrames: this.droppedFrames\n })\n\n if (this.frameBuffer.length > 0 && this.renderer) {\n const frame = this.frameBuffer.shift()!\n this.renderer.render(frame)\n this.updateState({ resolution: `${frame.width}x${frame.height}` })\n const fps = this.renderer.updateFps()\n this.updateState({ fps })\n this.callbacks.onFrameRender?.(frame)\n }\n\n this.frameTimer = requestAnimationFrame(this.renderLoop)\n }\n}\n","/**\n * TS 解复用器\n */\n\nexport interface TSPacket {\n data: Uint8Array\n pid: number\n stream: 'video' | 'audio' | null\n}\n\nexport class TSDemuxer {\n private videoPID = 0x0102\n private audioPID = 0x0101\n\n parse(data: Uint8Array): { video: TSPacket[]; audio: TSPacket[] } {\n let offset = 0\n const packets: TSPacket[] = []\n\n while (offset < data.length - 188) {\n if (data[offset] !== 0x47) {\n offset++\n continue\n }\n\n if (offset + 188 > data.length) break\n\n // TS 包头解析\n // 字节 3: TSC(2) | AFC(2) | CC(4)\n // AFC 在 bits 4-5\n const adaptationFieldControl = (data[offset + 3] >> 4) & 0x03\n const hasPayload = adaptationFieldControl === 0x01 || adaptationFieldControl === 0x03\n\n if (!hasPayload) {\n offset += 188\n continue\n }\n\n const pidValue = ((data[offset + 1] & 0x1F) << 8) | data[offset + 2]\n\n let streamType: 'video' | 'audio' | null = null\n if (pidValue === this.videoPID) {\n streamType = 'video'\n } else if (pidValue === this.audioPID) {\n streamType = 'audio'\n }\n\n packets.push({\n data: data.subarray(offset, offset + 188),\n pid: pidValue,\n stream: streamType\n })\n\n offset += 188\n }\n\n return {\n video: packets.filter(p => p.stream === 'video'),\n audio: packets.filter(p => p.stream === 'audio')\n }\n }\n}\n","/**\n * PES 提取器 - 从 TS 包中提取 H.264 视频数据\n */\n\nimport type { TSPacket } from './TSDemuxer'\n\nexport class PESExtractor {\n /**\n * 从视频 TS 包中提取 payload 数据\n */\n extractVideoPayload(packets: TSPacket[]): Uint8Array {\n const payloads: Uint8Array[] = []\n let pesHeaderProcessed = false\n\n for (const packet of packets) {\n const data = packet.data\n if (data.length < 5) continue\n\n const payloadUnitStart = (data[1] & 0x40) !== 0\n const adaptationFieldControl = (data[3] >> 4) & 0x03\n let payloadStart = 4\n\n // 跳过 adaptation field\n if (adaptationFieldControl === 0x02 || adaptationFieldControl === 0x03) {\n const adaptationFieldLength = data[4]\n payloadStart += 1 + adaptationFieldLength\n }\n\n if (adaptationFieldControl === 0x01 || adaptationFieldControl === 0x03) {\n if (payloadStart < data.length) {\n let payload = data.subarray(payloadStart)\n\n // PES start code 是 3 字节: 00 00 01\n if (payloadUnitStart && payload.length >= 9) {\n if (payload[0] === 0x00 && payload[1] === 0x00 && payload[2] === 0x01) {\n // PES 结构:\n // [0-2]: start code (00 00 01)\n // [3]: stream_id\n // [4-5]: PES_packet_length\n // [6-7]: flags\n // [8]: PES_header_data_length\n const pesHeaderDataLength = payload[8]\n const pesHeaderSize = 9 + pesHeaderDataLength\n if (payload.length > pesHeaderSize) {\n payload = payload.subarray(pesHeaderSize)\n pesHeaderProcessed = true\n }\n }\n }\n\n if (payload.length > 0 && pesHeaderProcessed) {\n payloads.push(payload)\n }\n }\n }\n }\n\n // 合并所有 payload\n const totalSize = payloads.reduce((sum, p) => sum + p.length, 0)\n const result = new Uint8Array(totalSize)\n let offset = 0\n\n for (const payload of payloads) {\n result.set(payload, offset)\n offset += payload.length\n }\n\n return result\n }\n}\n","/**\n * fMP4 (Fragmented MP4) 解析器\n *\n * 用于解析 HLS fMP4 流的分片\n */\n\n// ============================================================================\n// 工具函数\n// ============================================================================\n\nfunction readUint32(data: Uint8Array, offset: number): number {\n return (\n (data[offset] << 24) |\n (data[offset + 1] << 16) |\n (data[offset + 2] << 8) |\n data[offset + 3]\n ) >>> 0\n}\n\nfunction readInt32(data: Uint8Array, offset: number): number {\n const value = readUint32(data, offset)\n return value > 0x7fffffff ? value - 0x100000000 : value\n}\n\nfunction readUint64(data: Uint8Array, offset: number): number {\n const view = new DataView(data.buffer, data.byteOffset, data.length)\n return Number(view.getBigUint64(offset))\n}\n\nfunction readFourCC(data: Uint8Array, offset: number): string {\n return String.fromCharCode(\n data[offset],\n data[offset + 1],\n data[offset + 2],\n data[offset + 3]\n )\n}\n\nfunction readBoxFlags(data: Uint8Array, offset: number): number {\n return (\n (data[offset] << 16) |\n (data[offset + 1] << 8) |\n data[offset + 2]\n ) >>> 0\n}\n\n// ============================================================================\n// 类型定义\n// ============================================================================\n\nexport interface TrunSample {\n duration?: number\n size?: number\n flags?: number\n compositionTimeOffset?: number\n}\n\nexport interface TfhdBox {\n trackId: number\n baseDataOffset?: number\n sampleDescriptionIndex?: number\n defaultSampleDuration?: number\n defaultSampleSize?: number\n defaultSampleFlags?: number\n}\n\nexport interface TfdtBox {\n baseMediaDecodeTime: number\n}\n\nexport interface TrunBox {\n sampleCount: number\n dataOffset?: number\n firstSampleFlags?: number\n samples: TrunSample[]\n}\n\nexport interface TrafBox {\n tfhd?: TfhdBox\n tfdt?: TfdtBox\n truns: TrunBox[]\n}\n\nexport interface MoofBox {\n mfhd?: { sequenceNumber: number }\n trafs: TrafBox[]\n dataOffset: number // moof 在文件中的偏移\n size: number\n}\n\nexport interface VideoSample {\n data: Uint8Array\n dts: number\n pts: number\n duration: number\n isSync: boolean\n}\n\nexport interface InitSegment {\n trackId: number\n timescale: number\n avcC?: Uint8Array // AVC 解码器配置\n}\n\n// ============================================================================\n// fMP4 解析器\n// ============================================================================\n\nexport class fMP4Demuxer {\n private timescale = 1000\n private trackId = 1\n private avcC: Uint8Array | null = null\n\n /**\n * 解析初始化段 (ftyp + moov)\n */\n parseInitSegment(data: Uint8Array): InitSegment | null {\n let offset = 0\n\n while (offset < data.length - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'moov') {\n this.parseMoov(data, offset, boxSize)\n }\n\n offset += boxSize\n }\n\n return {\n trackId: this.trackId,\n timescale: this.timescale,\n avcC: this.avcC || undefined\n }\n }\n\n /**\n * 解析 moov box\n */\n private parseMoov(data: Uint8Array, moovOffset: number, moovSize: number): void {\n let offset = moovOffset + 8\n const endOffset = moovOffset + moovSize\n\n while (offset < endOffset - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'trak') {\n this.parseTrak(data, offset, boxSize)\n }\n\n offset += boxSize\n }\n }\n\n /**\n * 解析 trak box\n */\n private parseTrak(data: Uint8Array, trakOffset: number, trakSize: number): void {\n let offset = trakOffset + 8\n const endOffset = trakOffset + trakSize\n\n while (offset < endOffset - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'mdia') {\n this.parseMdia(data, offset, boxSize)\n }\n\n offset += boxSize\n }\n }\n\n /**\n * 解析 mdia box\n */\n private parseMdia(data: Uint8Array, mdiaOffset: number, mdiaSize: number): void {\n let offset = mdiaOffset + 8\n const endOffset = mdiaOffset + mdiaSize\n\n while (offset < endOffset - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'mdhd') {\n this.parseMdhd(data, offset + 8)\n } else if (boxType === 'minf') {\n this.parseMinf(data, offset, boxSize)\n }\n\n offset += boxSize\n }\n }\n\n /**\n * 解析 mdhd box 获取 timescale\n */\n private parseMdhd(data: Uint8Array, boxDataOffset: number): void {\n const version = data[boxDataOffset]\n if (version === 1) {\n this.timescale = readUint32(data, boxDataOffset + 20)\n } else {\n this.timescale = readUint32(data, boxDataOffset + 12)\n }\n }\n\n /**\n * 解析 minf box\n */\n private parseMinf(data: Uint8Array, minfOffset: number, minfSize: number): void {\n let offset = minfOffset + 8\n const endOffset = minfOffset + minfSize\n\n while (offset < endOffset - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'stbl') {\n this.parseStbl(data, offset, boxSize)\n }\n\n offset += boxSize\n }\n }\n\n /**\n * 解析 stbl box 获取 avcC\n */\n private parseStbl(data: Uint8Array, stblOffset: number, stblSize: number): void {\n let offset = stblOffset + 8\n const endOffset = stblOffset + stblSize\n\n while (offset < endOffset - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'stsd') {\n this.parseStsd(data, offset, boxSize)\n }\n\n offset += boxSize\n }\n }\n\n /**\n * 解析 stsd box 获取 avcC\n */\n private parseStsd(data: Uint8Array, stsdOffset: number, stsdSize: number): void {\n const boxDataOffset = stsdOffset + 8\n const entryCount = readUint32(data, boxDataOffset + 4)\n\n let offset = boxDataOffset + 8\n const endOffset = stsdOffset + stsdSize\n\n for (let i = 0; i < entryCount && offset < endOffset - 8; i++) {\n const entrySize = readUint32(data, offset)\n const entryType = readFourCC(data, offset + 4)\n\n if (entryType === 'avc1' || entryType === 'avc3') {\n this.parseAvcSampleEntry(data, offset, entrySize)\n return\n }\n\n offset += entrySize\n }\n }\n\n /**\n * 解析 AVC Sample Entry\n */\n private parseAvcSampleEntry(data: Uint8Array, entryOffset: number, entrySize: number): void {\n let offset = entryOffset + 8 + 78 // 跳过 sample entry 头部\n const endOffset = entryOffset + entrySize\n\n while (offset < endOffset - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'avcC') {\n this.avcC = data.slice(offset, offset + boxSize)\n return\n }\n\n offset += boxSize\n }\n }\n\n /**\n * 解析 moof box\n */\n parseMoof(data: Uint8Array, moofOffset: number): MoofBox {\n const moofSize = readUint32(data, moofOffset)\n const moof: MoofBox = {\n mfhd: undefined,\n trafs: [],\n dataOffset: moofOffset,\n size: moofSize\n }\n\n let offset = moofOffset + 8\n const endOffset = moofOffset + moofSize\n\n while (offset < endOffset - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'mfhd') {\n moof.mfhd = {\n sequenceNumber: readUint32(data, offset + 8 + 4)\n }\n } else if (boxType === 'traf') {\n const traf = this.parseTraf(data, offset, boxSize)\n moof.trafs.push(traf)\n }\n\n offset += boxSize\n }\n\n return moof\n }\n\n /**\n * 解析 traf box\n */\n private parseTraf(data: Uint8Array, trafOffset: number, trafSize: number): TrafBox {\n const traf: TrafBox = {\n truns: []\n }\n\n let offset = trafOffset + 8\n const endOffset = trafOffset + trafSize\n\n while (offset < endOffset - 8) {\n const boxSize = readUint32(data, offset)\n const boxType = readFourCC(data, offset + 4)\n\n if (boxSize < 8) break\n\n if (boxType === 'tfhd') {\n traf.tfhd = this.parseTfhd(data, offset + 8)\n } else if (boxType === 'tfdt') {\n traf.tfdt = this.parseTfdt(data, offset + 8)\n } else if (boxType === 'trun') {\n if (traf.tfhd) {\n traf.truns.push(this.parseTrun(data, offset + 8, traf.tfhd))\n }\n }\n\n offset += boxSize\n }\n\n return traf\n }\n\n /**\n * 解析 tfhd box\n */\n private parseTfhd(data: Uint8Array, boxDataOffset: number): TfhdBox {\n const flags = readBoxFlags(data, boxDataOffset)\n const tfhd: TfhdBox = {\n trackId: readUint32(data, boxDataOffset + 4)\n }\n\n let offset = boxDataOffset + 8\n\n if (flags & 0x01) {\n tfhd.baseDataOffset = readUint64(data, offset)\n offset += 8\n }\n if (flags & 0x02) {\n tfhd.sampleDescriptionIndex = readUint32(data, offset)\n offset += 4\n }\n if (flags & 0x08) {\n tfhd.defaultSampleDuration = readUint32(data, offset)\n offset += 4\n }\n if (flags & 0x10) {\n tfhd.defaultSampleSize = readUint32(data, offset)\n offset += 4\n }\n if (flags & 0x20) {\n tfhd.defaultSampleFlags = readUint32(data, offset)\n }\n\n return tfhd\n }\n\n /**\n * 解析 tfdt box\n */\n private parseTfdt(data: Uint8Array, boxDataOffset: number): TfdtBox {\n const version = data[boxDataOffset]\n return {\n baseMediaDecodeTime: version === 1\n ? readUint64(data, boxDataOffset + 4)\n : readUint32(data, boxDataOffset + 4)\n }\n }\n\n /**\n * 解析 trun box\n */\n private parseTrun(data: Uint8Array, boxDataOffset: number, tfhd: TfhdBox): TrunBox {\n const version = data[boxDataOffset]\n const flags = readBoxFlags(data, boxDataOffset + 1)\n const sampleCount = readUint32(data, boxDataOffset + 4)\n\n const trun: TrunBox = {\n sampleCount,\n samples: []\n }\n\n let offset = boxDataOffset + 8\n\n if (flags & 0x0001) {\n trun.dataOffset = readInt32(data, offset)\n offset += 4\n }\n if (flags & 0x0004) {\n trun.firstSampleFlags = readUint32(data, offset)\n offset += 4\n }\n\n const hasDuration = (flags & 0x0100) !== 0\n const hasSize = (flags & 0x0200) !== 0\n const hasFlags = (flags & 0x0400) !== 0\n const hasCto = (flags & 0x0800) !== 0\n\n for (let i = 0; i < sampleCount; i++) {\n const sample: TrunSample = {}\n\n if (hasDuration) {\n sample.duration = readUint32(data, offset)\n offset += 4\n } else {\n sample.duration = tfhd.defaultSampleDuration\n }\n\n if (hasSize) {\n sample.size = readUint32(data, offset)\n offset += 4\n } else {\n sample.size = tfhd.defaultSampleSize\n }\n\n if (hasFlags) {\n sample.flags = readUint32(data, offset)\n offset += 4\n } else if (i === 0 && trun.firstSampleFlags !== undefined) {\n sample.flags = trun.firstSampleFlags\n } else {\n sample.flags = tfhd.defaultSampleFlags\n }\n\n if (hasCto) {\n sample.compositionTimeOffset = version === 0\n ? readUint32(data, offset)\n : readInt32(data, offset)\n offset += 4\n }\n\n trun.samples.push(sample)\n }\n\n return trun\n }\n\n /**\n * 从 moof + mdat 提取视频样本\n */\n extractSamples(moof: MoofBox, mdatData: Uint8Array, mdatOffset: number): VideoSample[] {\n const samples: VideoSample[] = []\n\n for (const traf of moof.trafs) {\n if (!traf.tfhd || !traf.tfdt) continue\n\n let baseDts = traf.tfdt.baseMediaDecodeTime\n\n for (const trun of traf.truns) {\n // 计算数据偏移\n let dataOffset = 0\n if (trun.dataOffset !== undefined) {\n dataOffset = trun.dataOffset - mdatOffset - 8 // 减去 mdat header\n }\n\n for (const sample of trun.samples) {\n if (sample.size === undefined || sample.size <= 0) continue\n\n const sampleData = mdatData.slice(dataOffset, dataOffset + sample.size)\n\n // 判断是否为关键帧 (flags & 0x01000000 = is_sync)\n const isSync = (sample.flags ?? 0) & 0x01000000\n\n // 计算 PTS\n const cto = sample.compositionTimeOffset ?? 0\n const duration = sample.duration ?? 0\n\n samples.push({\n data: sampleData,\n dts: baseDts,\n pts: baseDts + cto,\n duration,\n isSync: isSync !== 0\n })\n\n dataOffset += sample.size\n baseDts += duration\n }\n }\n }\n\n return samples\n }\n\n /**\n * 获取 timescale\n */\n getTimescale(): number {\n return this.timescale\n }\n\n /**\n * 获取 avcC 配置\n */\n getAvcC(): Uint8Array | null {\n return this.avcC\n }\n}\n\n/**\n * 检测是否为 fMP4 格式\n */\nexport function isFragmentedMp4(data: Uint8Array): boolean {\n if (data.length < 12) return false\n\n const ftyp = readFourCC(data, 4)\n if (ftyp !== 'ftyp' && ftyp !== 'styp') return false\n\n // 检查兼容品牌\n const majorBrand = readFourCC(data, 8)\n if (majorBrand === 'iso5' || majorBrand === 'iso6' || majorBrand === 'msdh') {\n return true\n }\n\n // 检查兼容品牌列表\n let offset = 16\n while (offset < Math.min(data.length, 64)) {\n const brand = readFourCC(data, offset)\n if (brand === 'iso5' || brand === 'iso6' || brand === 'msdh' || brand === 'iso4') {\n return true\n }\n offset += 4\n }\n\n return false\n}\n","/**\n * NAL 单元解析器\n */\n\nimport type { NALUnit } from '../types'\n\n// NAL 类型常量\nexport const NAL_TYPES = {\n SLICE: 1, // Non-IDR slice\n IDR: 5, // IDR slice\n SEI: 6, // Supplemental Enhancement Information\n SPS: 7, // Sequence Parameter Set\n PPS: 8, // Picture Parameter Set\n AUD: 9, // Access Unit Delimiter\n} as const\n\nexport type NALType = typeof NAL_TYPES[keyof typeof NAL_TYPES]\n\nexport class NALParser {\n /**\n * 解析 H.264 NAL 单元\n * 支持 3 字节和 4 字节的 start code\n */\n parse(data: Uint8Array): NALUnit[] {\n const units: NALUnit[] = []\n let i = 0\n const len = data.length\n\n while (i < len - 3) {\n let startCodeSize = 0\n let nalStart = 0\n\n // 检查 4 字节 start code: 00 00 00 01\n if (data[i] === 0x00 && data[i + 1] === 0x00 && data[i + 2] === 0x00 && data[i + 3] === 0x01) {\n startCodeSize = 4\n nalStart = i + 4\n }\n // 检查 3 字节 start code: 00 00 01\n else if (data[i] === 0x00 && data[i + 1] === 0x00 && data[i + 2] === 0x01) {\n startCodeSize = 3\n nalStart = i + 3\n }\n\n if (startCodeSize > 0) {\n // 查找下一个 start code\n let nalEnd = len\n for (let j = nalStart; j < len - 3; j++) {\n if (data[j] === 0x00 && data[j + 1] === 0x00) {\n if (data[j + 2] === 0x00 && data[j + 3] === 0x01) {\n nalEnd = j\n break\n } else if (data[j + 2] === 0x01) {\n nalEnd = j\n break\n }\n }\n }\n\n const nalType = data[nalStart] & 0x1F\n units.push({\n type: nalType,\n data: data.subarray(nalStart, nalEnd),\n size: nalEnd - nalStart\n })\n\n i = nalEnd\n } else {\n i++\n }\n }\n\n return units\n }\n}\n","/**\n * 预取器抽象基类\n *\n * 提供通用的预取循环控制、水位检查、动态间隔、速度监控和状态管理\n */\n\nimport type {\n PrefetcherConfig,\n PrefetcherStatus,\n PrefetcherCallbacks,\n DEFAULT_PREFETCHER_CONFIG\n} from './types'\n\n/**\n * 预取器抽象基类\n *\n * 子类需要实现:\n * - getQueueSize(): 获取当前队列大小\n * - shouldPrefetch(): 判断是否需要预取\n * - doPrefetch(): 执行实际的预取操作\n * - doReset(): 重置状态\n */\nexport abstract class BasePrefetcher<\n TConfig extends PrefetcherConfig = PrefetcherConfig,\n TStatus extends PrefetcherStatus = PrefetcherStatus\n> {\n protected config: TConfig\n protected callbacks: PrefetcherCallbacks\n protected status: TStatus\n protected isRunning = false\n protected abortFlag = false\n protected prefetchPromise: Promise<void> | null = null\n\n // 速度监控\n protected downloadStartTime = 0\n protected downloadStartBytes = 0\n protected lastSpeedLogTime = 0\n protected lastSpeedLogBytes = 0\n protected currentSpeed = 0 // KB/s\n\n // 循环计数\n protected loopCount = 0\n\n constructor(\n config: TConfig,\n callbacks: PrefetcherCallbacks = {}\n ) {\n this.config = config\n this.callbacks = callbacks\n this.status = this.createInitialState()\n }\n\n /**\n * 创建初始状态(子类可覆盖)\n */\n protected createInitialState(): TStatus {\n return {\n isPrefetching: false,\n queueSize: 0,\n downloadSpeed: 0,\n totalBytes: 0\n } as TStatus\n }\n\n /**\n * 启动预取循环\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n console.log('[BasePrefetcher] Already running')\n return\n }\n\n this.isRunning = true\n this.abortFlag = false\n this.loopCount = 0\n\n console.log('[BasePrefetcher] Starting prefetch loop...')\n\n this.prefetchPromise = this.prefetchLoop()\n await this.prefetchPromise\n }\n\n /**\n * 停止预取循环\n */\n stop(): void {\n console.log('[BasePrefetcher] Stopping prefetch loop...')\n this.abortFlag = true\n this.isRunning = false\n this.updateStatus({ isPrefetching: false })\n }\n\n /**\n * 获取当前状态\n */\n getStatus(): TStatus {\n return { ...this.status }\n }\n\n /**\n * 获取下载速度 (KB/s)\n */\n getDownloadSpeed(): number {\n return this.currentSpeed\n }\n\n /**\n * 预取循环\n */\n protected async prefetchLoop(): Promise<void> {\n try {\n while (this.isRunning && !this.abortFlag) {\n this.loopCount++\n\n // 更新队列大小\n const queueSize = this.getQueueSize()\n this.updateStatus({ queueSize })\n\n // 检查是否需要预取\n if (this.shouldPrefetch()) {\n this.updateStatus({ isPrefetching: true })\n await this.doPrefetch()\n this.updateStatus({ isPrefetching: false })\n }\n\n // 动态调整等待间隔\n const interval = this.calculateInterval(queueSize)\n await this.sleep(interval)\n }\n\n console.log('[BasePrefetcher] Prefetch loop ended')\n } catch (error) {\n console.error('[BasePrefetcher] Prefetch loop error:', error)\n this.callbacks.onError?.(error as Error)\n this.updateStatus({\n isPrefetching: false,\n lastError: (error as Error).message\n })\n }\n }\n\n /**\n * 计算动态等待间隔\n */\n protected calculateInterval(queueSize: number): number {\n if (!this.config.dynamicInterval) {\n return this.config.prefetchInterval\n }\n\n const lowWater = this.config.lowWaterMark\n\n if (queueSize < lowWater / 2) {\n return 1 // 队列很低:快速检查\n } else if (queueSize < lowWater) {\n return 3 // 队列较低:较快检查\n } else if (queueSize < this.config.highWaterMark) {\n return this.config.prefetchInterval // 正常检查\n } else {\n return this.config.prefetchInterval * 2 // 队列充足:减少检查频率\n }\n }\n\n /**\n * 更新下载速度\n */\n protected updateDownloadSpeed(totalBytes: number): void {\n const now = Date.now()\n\n // 每秒更新一次速度\n if (now - this.lastSpeedLogTime >= 1000) {\n const elapsed = (now - this.lastSpeedLogTime) / 1000\n const downloaded = totalBytes - this.lastSpeedLogBytes\n const speed = downloaded / elapsed / 1024 // KB/s\n\n this.currentSpeed = Math.round(speed)\n this.updateStatus({\n downloadSpeed: this.currentSpeed,\n totalBytes\n })\n\n this.lastSpeedLogTime = now\n this.lastSpeedLogBytes = totalBytes\n }\n }\n\n /**\n * 初始化速度监控\n */\n protected initSpeedMonitor(initialBytes: number): void {\n this.downloadStartTime = Date.now()\n this.downloadStartBytes = initialBytes\n this.lastSpeedLogTime = this.downloadStartTime\n this.lastSpeedLogBytes = initialBytes\n }\n\n /**\n * 更新状态(子类可覆盖以支持扩展属性)\n */\n protected updateStatus(partial: Record<string, unknown>): void {\n this.status = { ...this.status, ...partial } as TStatus\n this.callbacks.onStatusChange?.(this.status)\n }\n\n /**\n * 辅助方法:休眠\n */\n protected sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n }\n\n /**\n * 辅助方法:快速让出(用于不阻塞事件循环)\n */\n protected async yieldFast(): Promise<void> {\n // 使用 setImmediate 或 setTimeout(0) 让出执行\n await this.sleep(0)\n }\n\n /**\n * 重置预取器状态\n */\n reset(): void {\n this.stop()\n this.doReset()\n this.status = this.createInitialState()\n this.currentSpeed = 0\n this.loopCount = 0\n console.log('[BasePrefetcher] Reset complete')\n }\n\n // ==================== 抽象方法(子类必须实现) ====================\n\n /**\n * 获取当前队列大小\n */\n abstract getQueueSize(): number\n\n /**\n * 判断是否应该预取\n */\n abstract shouldPrefetch(): boolean\n\n /**\n * 执行预取操作\n */\n abstract doPrefetch(): Promise<void>\n\n /**\n * 重置状态(子类实现)\n */\n abstract doReset(): void\n}\n","/**\n * 分片预取器(用于 HLS)\n *\n * 管理分片下载队列,支持 TS 和 fMP4 格式\n */\n\nimport { BasePrefetcher } from './BasePrefetcher'\nimport type {\n SegmentPrefetcherConfig,\n PrefetcherStatus,\n PrefetcherCallbacks,\n PrefetchQueueItem,\n DEFAULT_SEGMENT_PREFETCHER_CONFIG\n} from './types'\n\n/**\n * 分片信息\n */\nexport interface SegmentInfo {\n /** 分片 URI */\n uri: string\n /** 分片时长(秒) */\n duration: number\n /** 字节范围(可选,用于 fMP4) */\n byteRange?: {\n start: number\n end: number\n }\n}\n\n/**\n * 分片预取器状态\n */\nexport interface SegmentPrefetcherStatus extends PrefetcherStatus {\n /** 当前分片索引 */\n currentSegmentIndex: number\n /** 总分片数 */\n totalSegments: number\n /** 预取队列大小 */\n prefetchQueueSize: number\n}\n\n/**\n * 分片预取器回调\n */\nexport interface SegmentPrefetcherCallbacks extends PrefetcherCallbacks {\n /** 分片下载完成回调 */\n onSegmentFetched?: (segmentIndex: number, data: Uint8Array) => void\n /** 分片解析完成回调 */\n onSegmentParsed?: (segmentIndex: number, itemCount: number) => void\n}\n\n/**\n * 分片预取器\n *\n * 用于 HLS 流的分片预取,支持:\n * - TS 分片\n * - fMP4 分片(支持字节范围)\n */\nexport abstract class SegmentPrefetcher extends BasePrefetcher<\n SegmentPrefetcherConfig,\n SegmentPrefetcherStatus\n> {\n /** 预取队列:存储已下载但尚未解析的分片 */\n protected prefetchQueue: PrefetchQueueItem[] = []\n\n /** 分片列表 */\n protected segments: SegmentInfo[] = []\n\n /** 当前分片索引 */\n protected currentSegmentIndex = 0\n\n /** 基础 URL(用于解析相对路径) */\n protected baseUrl = ''\n\n /** 正在预取标志 */\n protected isPrefetchingSegment = false\n\n constructor(\n config: SegmentPrefetcherConfig,\n callbacks: SegmentPrefetcherCallbacks = {}\n ) {\n super(config, callbacks)\n }\n\n /**\n * 创建初始状态\n */\n protected override createInitialState(): SegmentPrefetcherStatus {\n return {\n ...super.createInitialState(),\n currentSegmentIndex: 0,\n totalSegments: 0,\n prefetchQueueSize: 0\n }\n }\n\n /**\n * 设置分片列表\n */\n setSegments(segments: SegmentInfo[], baseUrl: string): void {\n this.segments = segments\n this.baseUrl = baseUrl\n this.currentSegmentIndex = 0\n this.prefetchQueue = []\n this.updateStatus({\n totalSegments: segments.length,\n currentSegmentIndex: 0,\n prefetchQueueSize: 0\n })\n console.log(`[SegmentPrefetcher] Set ${segments.length} segments, baseUrl: ${baseUrl}`)\n }\n\n /**\n * 设置当前分片索引(用于 seek)\n */\n setCurrentSegmentIndex(index: number): void {\n this.currentSegmentIndex = index\n // 清空预取队列(因为索引变了)\n this.prefetchQueue = []\n this.updateStatus({\n currentSegmentIndex: index,\n prefetchQueueSize: 0\n })\n console.log(`[SegmentPrefetcher] Current segment index set to ${index}`)\n }\n\n /**\n * 获取当前队列大小(返回预取队列大小)\n */\n override getQueueSize(): number {\n return this.prefetchQueue.length\n }\n\n /**\n * 判断是否应该预取\n */\n override shouldPrefetch(): boolean {\n // 不在预取中\n if (this.isPrefetchingSegment) return false\n\n // 没有分片\n if (this.segments.length === 0) return false\n\n // 预取队列未满\n const prefetchAhead = this.config.prefetchAhead\n if (this.prefetchQueue.length >= prefetchAhead) return false\n\n // 还有分片需要预取\n const nextIndex = this.currentSegmentIndex + this.prefetchQueue.length\n return nextIndex < this.segments.length\n }\n\n /**\n * 执行预取\n */\n override async doPrefetch(): Promise<void> {\n if (this.isPrefetchingSegment) return\n\n this.isPrefetchingSegment = true\n this.updateStatus({ isPrefetching: true })\n\n try {\n const nextIndex = this.currentSegmentIndex + this.prefetchQueue.length\n\n // 检查边界\n if (nextIndex >= this.segments.length) {\n return\n }\n\n const segment = this.segments[nextIndex]\n const fetchStart = performance.now()\n\n // 下载分片\n const data = await this.fetchSegment(segment, nextIndex)\n const fetchTime = performance.now() - fetchStart\n\n // 加入预取队列\n this.prefetchQueue.push({\n data,\n segmentIndex: nextIndex,\n fetchTime\n })\n\n this.updateStatus({ prefetchQueueSize: this.prefetchQueue.length })\n\n // 回调\n const callbacks = this.callbacks as SegmentPrefetcherCallbacks\n callbacks.onSegmentFetched?.(nextIndex, data)\n\n console.log(`[SegmentPrefetcher] Fetched segment #${nextIndex}: ${data.length} bytes, ${fetchTime.toFixed(0)}ms`)\n\n } catch (error: any) {\n console.error(`[SegmentPrefetcher] Fetch failed:`, error.message)\n this.callbacks.onError?.(error)\n } finally {\n this.isPrefetchingSegment = false\n this.updateStatus({ isPrefetching: false })\n }\n }\n\n /**\n * 处理预取队列中的数据\n *\n * @returns 是否有数据被处理\n */\n processQueue(): boolean {\n let processed = false\n\n while (this.prefetchQueue.length > 0) {\n const item = this.prefetchQueue[0]\n\n // 确保处理的是当前需要的分片\n if (item.segmentIndex !== this.currentSegmentIndex) {\n break\n }\n\n // 从队列移除\n this.prefetchQueue.shift()\n this.updateStatus({ prefetchQueueSize: this.prefetchQueue.length })\n\n // 解析分片\n const parseStart = performance.now()\n const itemCount = this.parseSegment(item.data, item.segmentIndex)\n const parseTime = performance.now() - parseStart\n\n // 更新当前索引\n this.currentSegmentIndex++\n this.updateStatus({ currentSegmentIndex: this.currentSegmentIndex })\n\n // 回调\n const callbacks = this.callbacks as SegmentPrefetcherCallbacks\n callbacks.onSegmentParsed?.(item.segmentIndex, itemCount)\n\n console.log(`[SegmentPrefetcher] Parsed segment #${item.segmentIndex}: ${itemCount} items, ${parseTime.toFixed(0)}ms`)\n\n processed = true\n }\n\n return processed\n }\n\n /**\n * 重置状态\n */\n override doReset(): void {\n this.prefetchQueue = []\n this.segments = []\n this.currentSegmentIndex = 0\n this.baseUrl = ''\n this.isPrefetchingSegment = false\n }\n\n /**\n * 获取当前分片索引\n */\n getCurrentSegmentIndex(): number {\n return this.currentSegmentIndex\n }\n\n /**\n * 获取总分片数\n */\n getTotalSegments(): number {\n return this.segments.length\n }\n\n // ==================== 抽象方法(子类实现) ====================\n\n /**\n * 获取分片数据(子类实现具体下载逻辑)\n */\n abstract fetchSegment(segment: SegmentInfo, index: number): Promise<Uint8Array>\n\n /**\n * 解析分片数据(子类实现具体解析逻辑)\n *\n * @param data 分片数据\n * @param index 分片索引\n * @returns 解析出的项目数量\n */\n abstract parseSegment(data: Uint8Array, index: number): number\n}\n","/**\n * 流式预取器(用于 FLV)\n *\n * 管理 ReadableStream 下载,支持动态扩容缓冲区\n */\n\nimport { BasePrefetcher } from './BasePrefetcher'\nimport type {\n StreamPrefetcherConfig,\n PrefetcherStatus,\n PrefetcherCallbacks,\n DownloadBufferInfo,\n DEFAULT_STREAM_PREFETCHER_CONFIG\n} from './types'\n\n/**\n * 流式预取器状态\n */\nexport interface StreamPrefetcherStatus extends PrefetcherStatus {\n /** 缓冲区使用量 */\n bufferLength: number\n /** 缓冲区容量 */\n bufferCapacity: number\n /** 是否已完成下载 */\n downloadComplete: boolean\n}\n\n/**\n * 流式预取器回调\n */\nexport interface StreamPrefetcherCallbacks extends PrefetcherCallbacks {\n /** 数据到达回调 */\n onDataReceived?: (totalBytes: number) => void\n /** 缓冲区处理回调 */\n onBufferProcessed?: (processedBytes: number) => void\n}\n\n/**\n * 流式预取器\n *\n * 用于 FLV 流的流式预取,支持:\n * - 动态扩容缓冲区\n * - ReadableStream 读取\n * - 增量解析\n */\nexport abstract class StreamPrefetcher extends BasePrefetcher<\n StreamPrefetcherConfig,\n StreamPrefetcherStatus\n> {\n /** 下载缓冲区 */\n protected downloadBuffer: Uint8Array | null = null\n\n /** 已使用的缓冲区长度 */\n protected bufferLength = 0\n\n /** 流读取器 */\n protected reader: ReadableStreamDefaultReader<Uint8Array> | null = null\n\n /** 下载完成标志 */\n protected downloadComplete = false\n\n /** 下载 Promise */\n protected downloadPromise: Promise<void> | null = null\n\n /** 总下载字节数 */\n protected totalDownloadedBytes = 0\n\n constructor(\n config: StreamPrefetcherConfig,\n callbacks: StreamPrefetcherCallbacks = {}\n ) {\n super(config, callbacks)\n }\n\n /**\n * 创建初始状态\n */\n protected override createInitialState(): StreamPrefetcherStatus {\n return {\n ...super.createInitialState(),\n bufferLength: 0,\n bufferCapacity: 0,\n downloadComplete: false\n }\n }\n\n /**\n * 设置流读取器\n */\n setReader(reader: ReadableStreamDefaultReader<Uint8Array>, initialData?: Uint8Array): void {\n this.reader = reader\n this.downloadComplete = false\n this.totalDownloadedBytes = 0\n\n // 初始化缓冲区\n const initialSize = this.config.initialBufferSize\n this.downloadBuffer = new Uint8Array(initialSize)\n this.bufferLength = 0\n\n // 如果有初始数据,写入缓冲区\n if (initialData && initialData.length > 0) {\n this.ensureCapacity(initialData.length)\n this.downloadBuffer!.set(initialData, 0)\n this.bufferLength = initialData.length\n this.totalDownloadedBytes = initialData.length\n }\n\n this.updateStatus({\n bufferLength: this.bufferLength,\n bufferCapacity: this.downloadBuffer!.length,\n downloadComplete: false,\n totalBytes: this.totalDownloadedBytes\n })\n\n // 初始化速度监控\n this.initSpeedMonitor(this.totalDownloadedBytes)\n\n console.log(`[StreamPrefetcher] Reader set, initial buffer: ${this.bufferLength} bytes, capacity: ${this.downloadBuffer!.length}`)\n }\n\n /**\n * 确保缓冲区有足够的容量\n */\n protected ensureCapacity(needed: number): void {\n if (!this.downloadBuffer) {\n const size = Math.max(this.config.initialBufferSize, needed * 2)\n this.downloadBuffer = new Uint8Array(size)\n this.bufferLength = 0\n return\n }\n\n const remaining = this.downloadBuffer.length - this.bufferLength\n if (remaining < needed) {\n // 扩容:新大小 = max(当前大小 * 2, 当前使用量 + 需要量)\n const newSize = Math.max(\n this.downloadBuffer.length * 2,\n this.bufferLength + needed\n )\n const newBuffer = new Uint8Array(newSize)\n newBuffer.set(this.downloadBuffer.slice(0, this.bufferLength), 0)\n this.downloadBuffer = newBuffer\n\n console.log(`[StreamPrefetcher] Buffer expanded to ${newSize} bytes`)\n\n this.updateStatus({ bufferCapacity: newSize })\n }\n }\n\n /**\n * 获取当前队列大小(使用缓冲区长度)\n */\n override getQueueSize(): number {\n return this.bufferLength\n }\n\n /**\n * 判断是否应该预取\n */\n override shouldPrefetch(): boolean {\n // 没有读取器\n if (!this.reader) return false\n\n // 下载已完成\n if (this.downloadComplete) return false\n\n // 缓冲区未满\n return this.bufferLength < this.config.highWaterMark * 1000 // 转换为字节\n }\n\n /**\n * 执行预取(从流读取数据)\n */\n override async doPrefetch(): Promise<void> {\n if (!this.reader || this.downloadComplete) return\n\n try {\n const { done, value } = await this.reader.read()\n\n if (value) {\n // 确保缓冲区有足够空间\n this.ensureCapacity(value.length)\n\n // 追加到缓冲区\n if (this.downloadBuffer) {\n this.downloadBuffer.set(value, this.bufferLength)\n this.bufferLength += value.length\n this.totalDownloadedBytes += value.length\n }\n\n // 更新速度\n this.updateDownloadSpeed(this.totalDownloadedBytes)\n\n // 更新状态\n this.updateStatus({\n bufferLength: this.bufferLength,\n totalBytes: this.totalDownloadedBytes\n })\n\n // 回调\n const callbacks = this.callbacks as StreamPrefetcherCallbacks\n callbacks.onDataReceived?.(this.totalDownloadedBytes)\n }\n\n if (done) {\n this.downloadComplete = true\n this.updateStatus({ downloadComplete: true })\n console.log(`[StreamPrefetcher] Download complete: ${this.totalDownloadedBytes} bytes`)\n }\n\n } catch (error: any) {\n console.error(`[StreamPrefetcher] Read error:`, error.message)\n this.callbacks.onError?.(error)\n }\n }\n\n /**\n * 处理缓冲区数据\n *\n * @returns 是否有数据被处理\n */\n processBuffer(): boolean {\n if (!this.downloadBuffer || this.bufferLength === 0) {\n return false\n }\n\n // 获取当前缓冲区数据的切片\n const data = this.downloadBuffer.slice(0, this.bufferLength)\n\n // 调用子类的处理方法\n const result = this.processBufferData(data)\n\n // 更新状态\n this.updateStatus({ bufferLength: this.bufferLength })\n\n const callbacks = this.callbacks as StreamPrefetcherCallbacks\n callbacks.onBufferProcessed?.(result.processedBytes)\n\n return result.hasNewData\n }\n\n /**\n * 获取缓冲区信息\n */\n getBufferInfo(): DownloadBufferInfo {\n return {\n buffer: this.downloadBuffer,\n length: this.bufferLength,\n capacity: this.downloadBuffer?.length || 0\n }\n }\n\n /**\n * 获取缓冲区数据(复制)\n */\n getBufferData(): Uint8Array | null {\n if (!this.downloadBuffer || this.bufferLength === 0) {\n return null\n }\n return this.downloadBuffer.slice(0, this.bufferLength)\n }\n\n /**\n * 重置状态\n */\n override doReset(): void {\n this.downloadBuffer = null\n this.bufferLength = 0\n this.reader = null\n this.downloadComplete = false\n this.downloadPromise = null\n this.totalDownloadedBytes = 0\n }\n\n /**\n * 取消下载\n */\n cancelDownload(): void {\n if (this.reader) {\n this.reader.cancel()\n this.reader = null\n }\n this.downloadComplete = true\n this.updateStatus({ downloadComplete: true })\n console.log(`[StreamPrefetcher] Download cancelled`)\n }\n\n /**\n * 是否下载完成\n */\n isDownloadComplete(): boolean {\n return this.downloadComplete\n }\n\n // ==================== 抽象方法(子类实现) ====================\n\n /**\n * 处理缓冲区数据(子类实现具体解析逻辑)\n *\n * @param data 当前缓冲区数据\n * @returns 处理结果\n */\n abstract processBufferData(data: Uint8Array): {\n /** 是否有新数据 */\n hasNewData: boolean\n /** 已处理的字节数 */\n processedBytes: number\n }\n}\n","/**\n * 预取器类型定义\n *\n * 定义通用的预取器配置、状态和回调接口\n */\n\n/**\n * 预取器配置\n */\nexport interface PrefetcherConfig {\n /** 低水位:队列低于此值开始预取 */\n lowWaterMark: number\n /** 高水位:队列达到此值暂停预取 */\n highWaterMark: number\n /** 预取间隔(毫秒) */\n prefetchInterval: number\n /** 是否启用动态间隔调整 */\n dynamicInterval: boolean\n}\n\n/**\n * 预取器状态\n */\nexport interface PrefetcherStatus {\n /** 是否正在预取 */\n isPrefetching: boolean\n /** 当前队列大小 */\n queueSize: number\n /** 下载速度 (KB/s) */\n downloadSpeed: number\n /** 已预取的总字节数 */\n totalBytes: number\n /** 预取错误信息 */\n lastError?: string\n}\n\n/**\n * 预取器回调\n */\nexport interface PrefetcherCallbacks {\n /** 状态变化回调 */\n onStatusChange?: (status: PrefetcherStatus) => void\n /** 预取完成回调 */\n onPrefetchComplete?: (bytesFetched: number) => void\n /** 错误回调 */\n onError?: (error: Error) => void\n}\n\n/**\n * 默认预取器配置\n */\nexport const DEFAULT_PREFETCHER_CONFIG: PrefetcherConfig = {\n lowWaterMark: 30,\n highWaterMark: 100,\n prefetchInterval: 10,\n dynamicInterval: true\n}\n\n/**\n * 分片预取器配置(扩展基础配置)\n */\nexport interface SegmentPrefetcherConfig extends PrefetcherConfig {\n /** 提前预取的分片数量 */\n prefetchAhead: number\n}\n\n/**\n * 默认分片预取器配置\n */\nexport const DEFAULT_SEGMENT_PREFETCHER_CONFIG: SegmentPrefetcherConfig = {\n ...DEFAULT_PREFETCHER_CONFIG,\n prefetchAhead: 2\n}\n\n/**\n * 流式预取器配置(扩展基础配置)\n */\nexport interface StreamPrefetcherConfig extends PrefetcherConfig {\n /** 初始缓冲区大小 */\n initialBufferSize: number\n}\n\n/**\n * 默认流式预取器配置\n */\nexport const DEFAULT_STREAM_PREFETCHER_CONFIG: StreamPrefetcherConfig = {\n ...DEFAULT_PREFETCHER_CONFIG,\n lowWaterMark: 100,\n highWaterMark: 500,\n initialBufferSize: 2 * 1024 * 1024 // 2MB\n}\n\n/**\n * 预取队列项(分片模式)\n */\nexport interface PrefetchQueueItem {\n /** 分片数据 */\n data: Uint8Array\n /** 分片索引 */\n segmentIndex: number\n /** 获取时间 */\n fetchTime: number\n}\n\n/**\n * 下载缓冲区信息(流式模式)\n */\nexport interface DownloadBufferInfo {\n /** 缓冲区 */\n buffer: Uint8Array | null\n /** 已使用长度 */\n length: number\n /** 总容量 */\n capacity: number\n}\n","/**\n * HLS 播放器\n *\n * 支持 HLS TS 和 fMP4 格式\n */\n\nimport { TSDemuxer } from '../demuxer/TSDemuxer'\nimport { PESExtractor } from '../demuxer/PESExtractor'\nimport { fMP4Demuxer, type VideoSample } from '../demuxer/fMP4Demuxer'\nimport { NALParser } from '../parser/NALParser'\nimport { BasePlayer, DEFAULT_PLAYER_CONFIG } from './BasePlayer'\nimport type { HLSPlayerConfig, VideoFrame, NALUnit } from '../types'\nimport {\n SegmentPrefetcher,\n type SegmentInfo,\n type SegmentPrefetcherConfig,\n DEFAULT_SEGMENT_PREFETCHER_CONFIG\n} from '../prefetch'\n\n// TS 分片\ninterface Segment {\n uri: string\n duration: number\n}\n\n// fMP4 分片(支持字节范围)\ninterface fMP4Segment {\n uri: string\n duration: number\n byteRange?: {\n start: number\n end: number\n }\n}\n\n// fMP4 初始化段\ninterface InitSegment {\n uri: string\n byteRange?: {\n start: number\n end: number\n }\n}\n\n// NAL 队列项\ninterface QueuedNAL {\n nalUnit: NALUnit\n pts: number\n}\n\n// fMP4 Sample 队列项\ninterface QueuedSample {\n sample: VideoSample\n}\n\ninterface ParsedPlaylist {\n isMaster: boolean\n isFMP4: boolean\n segments: Segment[]\n fmp4Segments: fMP4Segment[]\n initSegment?: InitSegment\n variants: number\n}\n\n// HLS 预取器配置\nconst HLS_PREFETCHER_CONFIG: SegmentPrefetcherConfig = {\n ...DEFAULT_SEGMENT_PREFETCHER_CONFIG,\n lowWaterMark: 30,\n highWaterMark: 100,\n prefetchAhead: 2,\n prefetchInterval: 10,\n dynamicInterval: true\n}\n\n// 默认配置\nconst DEFAULT_HLS_CONFIG: Required<HLSPlayerConfig> = {\n ...DEFAULT_PLAYER_CONFIG\n}\n\n/**\n * HLS 分片预取器(内部类)\n *\n * 继承 SegmentPrefetcher,实现 HLS 特定的分片获取和解析逻辑\n */\nclass HLSSegmentPrefetcher extends SegmentPrefetcher {\n private player: HLSPlayer\n\n constructor(\n config: SegmentPrefetcherConfig,\n callbacks: import('../prefetch').SegmentPrefetcherCallbacks,\n player: HLSPlayer\n ) {\n super(config, callbacks)\n this.player = player\n }\n\n /**\n * 获取分片数据\n */\n override async fetchSegment(segment: SegmentInfo, index: number): Promise<Uint8Array> {\n const baseUrl = this.baseUrl\n const url = segment.uri.startsWith('http') ? segment.uri : baseUrl + segment.uri\n\n const headers: HeadersInit = {}\n if (segment.byteRange) {\n const { start, end } = segment.byteRange\n headers['Range'] = `bytes=${start}-${end}`\n }\n\n const response = await fetch(url, { headers })\n return new Uint8Array(await response.arrayBuffer())\n }\n\n /**\n * 解析分片数据\n */\n override parseSegment(data: Uint8Array, index: number): number {\n // 调用 player 的解析方法\n if (this.player.isFMP4) {\n return this.player.parseFMP4Data(data)\n } else {\n return this.player.parseTSData(data)\n }\n }\n\n /**\n * 获取队列大小(使用 player 的解码队列大小)\n */\n override getQueueSize(): number {\n if (this.player.isFMP4) {\n return this.player.sampleQueue.length\n } else {\n return this.player.nalQueue.length\n }\n }\n}\n\nexport class HLSPlayer extends BasePlayer<HLSPlayerConfig> {\n // HLS 特有的解封装器\n private tsDemuxer = new TSDemuxer()\n private pesExtractor = new PESExtractor()\n private nalParser = new NALParser()\n private fmp4Demuxer = new fMP4Demuxer()\n\n // HLS 特有的状态\n private isPrefetching = false\n private currentSegmentIndex = 0\n private segments: Segment[] = []\n private fmp4Segments: fMP4Segment[] = []\n private initSegment: InitSegment | null = null\n private _isFMP4 = false\n private currentPlaylistUrl = ''\n\n // HLS 特有的队列\n private _nalQueue: QueuedNAL[] = []\n private _sampleQueue: QueuedSample[] = []\n\n // 预取器(使用通用预取抽象层)\n private prefetcher: HLSSegmentPrefetcher | null = null\n\n // 公共访问器(供预取器使用)\n get isFMP4(): boolean { return this._isFMP4 }\n get nalQueue(): QueuedNAL[] { return this._nalQueue }\n get sampleQueue(): QueuedSample[] { return this._sampleQueue }\n\n constructor(config: HLSPlayerConfig = {}, callbacks: import('../types').PlayerCallbacks = {}) {\n super(config, callbacks, DEFAULT_HLS_CONFIG)\n }\n\n /**\n * 加载 HLS 播放列表\n */\n async load(url: string): Promise<void> {\n this.currentPlaylistUrl = url\n\n // 重置状态\n this.segments = []\n this.fmp4Segments = []\n this.initSegment = null\n this._nalQueue.length = 0\n this._sampleQueue.length = 0\n this.currentSegmentIndex = 0\n this.resetState()\n\n // 重置预取器\n if (this.prefetcher) {\n this.prefetcher.reset()\n this.prefetcher = null\n }\n\n const playlist = await this.parsePlaylist(url)\n\n this._isFMP4 = playlist.isFMP4\n console.log('[load] Detected format:', this.isFMP4 ? 'fMP4' : 'TS')\n\n if (playlist.isFMP4) {\n if (!playlist.fmp4Segments || playlist.fmp4Segments.length === 0) {\n throw new Error('No fMP4 segments found')\n }\n this.fmp4Segments = playlist.fmp4Segments\n if (playlist.initSegment) {\n this.initSegment = playlist.initSegment\n }\n console.log('[HLSPlayer] fMP4 stream parsed:', playlist.fmp4Segments.length, 'segments')\n } else {\n if (!playlist.segments || playlist.segments.length === 0) {\n throw new Error('No TS segments found')\n }\n this.segments = playlist.segments\n console.log('[HLSPlayer] TS stream parsed:', playlist.segments.length, 'segments')\n }\n\n this.currentSegmentIndex = 0\n\n // 计算总时长\n const segments = this.isFMP4 ? this.fmp4Segments : this.segments\n const totalDuration = segments.reduce((sum, seg) => sum + (seg.duration * 1000), 0)\n this.setDuration(totalDuration)\n\n this.updateState({\n isLoaded: true,\n totalSegments: segments.length\n })\n }\n\n /**\n * 初始化解码器(覆盖基类方法,添加 fMP4 支持)\n */\n override async initDecoder(): Promise<void> {\n await super.initDecoder()\n\n // fMP4 需要先加载初始化段\n if (this.isFMP4 && this.initSegment) {\n await this.loadInitSegment()\n }\n }\n\n /**\n * 开始播放(覆盖基类方法,使用自定义渲染循环)\n */\n override async play(): Promise<void> {\n this.isPlaying = true\n this.decodeLoopAbort = false\n this.updateState({ isPlaying: true })\n\n // 创建并初始化预取器\n this.initPrefetcher()\n\n // 启动预取循环(并行运行)\n this.prefetcher?.start()\n\n // 启动解码循环\n this.decodeLoop()\n\n // 启动渲染循环\n this.frameTimer = requestAnimationFrame(this.renderLoop)\n }\n\n /**\n * 跳转到指定时间\n */\n async seek(time: number): Promise<void> {\n const segments = this.isFMP4 ? this.fmp4Segments : this.segments\n if (segments.length === 0) return\n\n // 找到目标分片\n let accumulatedTime = 0\n let targetIndex = 0\n\n for (let i = 0; i < segments.length; i++) {\n const segmentDuration = segments[i].duration * 1000\n if (accumulatedTime + segmentDuration > time) {\n targetIndex = i\n break\n }\n accumulatedTime += segmentDuration\n targetIndex = i\n }\n\n // 清空缓冲区\n this.frameBuffer = []\n this._nalQueue.length = 0\n this._sampleQueue.length = 0\n\n // 更新分片索引\n this.currentSegmentIndex = targetIndex\n\n // 更新预取器索引\n if (this.prefetcher) {\n this.prefetcher.setCurrentSegmentIndex(targetIndex)\n }\n this.setCurrentTime(time)\n\n console.log('[HLSPlayer] Seek to', time, 'ms, segment:', targetIndex)\n }\n\n /**\n * 解码循环\n */\n protected override async decodeLoop(): Promise<void> {\n console.log('[DecodeLoop] START, isFMP4:', this.isFMP4)\n let batchCount = 0\n\n while (this.isPlaying && !this.decodeLoopAbort) {\n // 1. 从预取队列处理数据\n this.prefetcher?.processQueue()\n\n // 2. 批量解码\n const batchSize = this.config.decodeBatchSize\n let decodedInBatch = 0\n\n if (this.isFMP4) {\n // fMP4 解码\n while (this.sampleQueue.length > 0 && decodedInBatch < batchSize) {\n const queuedSample = this.sampleQueue.shift()!\n const sample = queuedSample.sample\n\n const frame = this.decodeSample(sample)\n if (frame) {\n this.frameBuffer.push(frame)\n decodedInBatch++\n\n while (this.frameBuffer.length > this.config.targetBufferSize) {\n this.frameBuffer.shift()\n this.droppedFrames++\n }\n }\n }\n } else {\n // TS 解码\n while (this.nalQueue.length > 0 && decodedInBatch < batchSize) {\n const queuedNal = this.nalQueue.shift()!\n const nalUnit = queuedNal.nalUnit\n\n if (!this.decoderInitialized && (nalUnit.type === 7 || nalUnit.type === 8)) {\n this.initDecoderParamsSync([nalUnit])\n }\n\n if (nalUnit.type === 5 || nalUnit.type === 1) {\n const frame = this.decodeNAL(nalUnit)\n\n if (frame) {\n this.frameBuffer.push(frame)\n decodedInBatch++\n\n while (this.frameBuffer.length > this.config.targetBufferSize) {\n this.frameBuffer.shift()\n this.droppedFrames++\n }\n }\n }\n }\n }\n\n batchCount++\n\n if (decodedInBatch > 0) {\n await this.yieldFast()\n } else {\n await this.sleep(2)\n }\n }\n\n console.log('[DecodeLoop] END, batches:', batchCount)\n }\n\n /**\n * 初始化预取器\n */\n private initPrefetcher(): void {\n this.prefetcher = new HLSSegmentPrefetcher(\n HLS_PREFETCHER_CONFIG,\n {\n onStatusChange: (status) => {\n this.updateState({\n isPrefetching: status.isPrefetching,\n downloadSpeed: status.downloadSpeed\n })\n },\n onSegmentParsed: (segmentIndex, itemCount) => {\n this.currentSegmentIndex = segmentIndex + 1\n this.updateState({ segmentIndex: this.currentSegmentIndex })\n }\n },\n this\n )\n\n const baseUrl = this.currentPlaylistUrl.substring(0, this.currentPlaylistUrl.lastIndexOf('/') + 1)\n if (this.isFMP4) {\n const segmentInfos: SegmentInfo[] = this.fmp4Segments.map(seg => ({\n uri: seg.uri,\n duration: seg.duration,\n byteRange: seg.byteRange\n }))\n this.prefetcher.setSegments(segmentInfos, baseUrl)\n } else {\n const segmentInfos: SegmentInfo[] = this.segments.map(seg => ({\n uri: seg.uri,\n duration: seg.duration\n }))\n this.prefetcher.setSegments(segmentInfos, baseUrl)\n }\n }\n\n // ==================== 解析方法 ====================\n\n /**\n * 解析 fMP4 数据\n */\n parseFMP4Data(data: Uint8Array): number {\n let moofOffset = -1\n let mdatOffset = -1\n let mdatSize = 0\n\n let offset = 0\n while (offset < data.length - 8) {\n const boxSize = this.readBoxSize(data, offset)\n const boxType = this.readBoxType(data, offset + 4)\n\n if (boxType === 'moof') {\n moofOffset = offset\n } else if (boxType === 'mdat') {\n mdatOffset = offset\n mdatSize = boxSize\n break\n }\n\n offset += boxSize\n }\n\n let sampleCount = 0\n\n if (moofOffset >= 0 && mdatOffset >= 0) {\n const moof = this.fmp4Demuxer.parseMoof(data, moofOffset)\n const mdatData = data.slice(mdatOffset + 8, mdatOffset + mdatSize)\n const samples = this.fmp4Demuxer.extractSamples(moof, mdatData, mdatOffset)\n\n for (const sample of samples) {\n this._sampleQueue.push({ sample })\n }\n sampleCount = samples.length\n }\n\n return sampleCount\n }\n\n /**\n * 解析 TS 数据\n */\n parseTSData(tsData: Uint8Array): number {\n const packets = this.tsDemuxer.parse(tsData)\n let nalCount = 0\n\n if (packets.video.length > 0) {\n const videoPayload = this.pesExtractor.extractVideoPayload(packets.video)\n if (videoPayload.length > 0) {\n const nalUnits = this.nalParser.parse(videoPayload)\n\n if (!this.decoderInitialized) {\n this.initDecoderParamsSync(nalUnits)\n }\n\n for (const nalUnit of nalUnits) {\n this._nalQueue.push({ nalUnit, pts: 0 })\n }\n nalCount = nalUnits.length\n }\n }\n\n return nalCount\n }\n\n // ==================== 私有方法 ====================\n\n /**\n * 加载 fMP4 初始化段\n */\n private async loadInitSegment(): Promise<void> {\n if (!this.initSegment) {\n console.error('[fMP4] No init segment defined!')\n return\n }\n\n const baseUrl = this.currentPlaylistUrl.substring(0, this.currentPlaylistUrl.lastIndexOf('/') + 1)\n const url = this.initSegment.uri.startsWith('http') ? this.initSegment.uri : baseUrl + this.initSegment.uri\n\n console.log('[fMP4] Loading init segment:', url, this.initSegment.byteRange)\n\n const headers: HeadersInit = {}\n if (this.initSegment.byteRange) {\n const { start, end } = this.initSegment.byteRange\n headers['Range'] = `bytes=${start}-${end}`\n }\n\n const response = await fetch(url, { headers })\n const data = new Uint8Array(await response.arrayBuffer())\n\n console.log('[fMP4] Init segment data size:', data.length, 'bytes')\n\n const initInfo = this.fmp4Demuxer.parseInitSegment(data)\n console.log('[fMP4] Parse result:', initInfo)\n\n if (initInfo?.avcC) {\n console.log('[fMP4] avcC size:', initInfo.avcC.length)\n this.initDecoderFromAvcC(initInfo.avcC)\n console.log('[fMP4] Init segment loaded, timescale:', initInfo.timescale)\n } else {\n console.error('[fMP4] Failed to parse init segment or no avcC found!')\n throw new Error('Failed to parse fMP4 init segment')\n }\n }\n\n /**\n * 从 avcC 初始化解码器\n */\n private initDecoderFromAvcC(avcC: Uint8Array): void {\n if (this.decoderInitialized || !this.decoder) return\n\n let offset = 8\n\n const configVersion = avcC[offset]\n const profile = avcC[offset + 1]\n const compatibility = avcC[offset + 2]\n const level = avcC[offset + 3]\n offset += 5\n\n const spsCount = avcC[offset] & 0x1F\n offset += 1\n\n console.log(`[fMP4] avcC: version=${configVersion}, profile=${profile}, level=${level}, spsCount=${spsCount}`)\n\n if (spsCount > 0) {\n const spsLength = (avcC[offset] << 8) | avcC[offset + 1]\n offset += 2\n const spsData = avcC.slice(offset, offset + spsLength)\n offset += spsLength\n\n const spsWithStartCode = new Uint8Array(4 + spsLength)\n spsWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n spsWithStartCode.set(spsData, 4)\n this.decoder.decode({ type: 7, data: spsWithStartCode, size: spsWithStartCode.length })\n console.log(`[fMP4] SPS decoded, length=${spsLength}`)\n\n for (let i = 1; i < spsCount; i++) {\n const skipLength = (avcC[offset] << 8) | avcC[offset + 1]\n offset += 2 + skipLength\n }\n }\n\n const ppsCount = avcC[offset]\n offset += 1\n\n if (ppsCount > 0) {\n const ppsLength = (avcC[offset] << 8) | avcC[offset + 1]\n offset += 2\n const ppsData = avcC.slice(offset, offset + ppsLength)\n\n const ppsWithStartCode = new Uint8Array(4 + ppsLength)\n ppsWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n ppsWithStartCode.set(ppsData, 4)\n this.decoder.decode({ type: 8, data: ppsWithStartCode, size: ppsWithStartCode.length })\n console.log(`[fMP4] PPS decoded, length=${ppsLength}`)\n }\n\n this.decoderInitialized = true\n console.log('[fMP4] Decoder initialized from avcC')\n }\n\n /**\n * 解析 HLS 播放列表\n */\n private async parsePlaylist(url: string): Promise<ParsedPlaylist> {\n const response = await fetch(url)\n const content = await response.text()\n\n const lines = content.split('\\n')\n const segments: Segment[] = []\n const fmp4Segments: fMP4Segment[] = []\n const variants: string[] = []\n let initSegment: InitSegment | undefined\n\n const isMaster = lines.some(line => line.includes('#EXT-X-STREAM-INF:'))\n\n if (isMaster) {\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim()\n if (line.startsWith('#EXT-X-STREAM-INF:')) {\n const uri = lines[++i]?.trim()\n if (uri && !uri.startsWith('#')) {\n variants.push(uri)\n }\n }\n }\n\n if (variants.length > 0) {\n const baseUrl = url.substring(0, url.lastIndexOf('/') + 1)\n const variantUrl = variants[0].startsWith('http') ? variants[0] : baseUrl + variants[0]\n this.currentPlaylistUrl = variantUrl\n return this.parsePlaylist(variantUrl)\n }\n\n return { isMaster: true, isFMP4: false, segments: [], fmp4Segments: [], variants: variants.length }\n }\n\n const isFMP4 = lines.some(line => line.includes('#EXT-X-MAP:'))\n console.log('[parsePlaylist] isFMP4:', isFMP4, 'url:', url)\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim()\n if (line.startsWith('#EXT-X-MAP:')) {\n const mapInfo = line.substring('#EXT-X-MAP:'.length)\n\n const uriMatch = mapInfo.match(/URI=\"([^\"]+)\"/)\n if (uriMatch) {\n initSegment = { uri: uriMatch[1] }\n\n const byteRangeMatch = mapInfo.match(/BYTERANGE=\"(\\d+)@(\\d+)\"/)\n if (byteRangeMatch) {\n initSegment.byteRange = {\n start: parseInt(byteRangeMatch[2]),\n end: parseInt(byteRangeMatch[2]) + parseInt(byteRangeMatch[1]) - 1\n }\n }\n }\n }\n }\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim()\n if (line.startsWith('#EXTINF:')) {\n const duration = parseFloat(line.split(':')[1].split(',')[0])\n\n let byteRange: { start: number; end: number } | undefined\n let nextLine = lines[++i]?.trim()\n\n if (nextLine?.startsWith('#EXT-X-BYTERANGE:')) {\n const byteRangeMatch = nextLine.match(/#EXT-X-BYTERANGE:(\\d+)@(\\d+)/)\n if (byteRangeMatch) {\n byteRange = {\n start: parseInt(byteRangeMatch[2]),\n end: parseInt(byteRangeMatch[2]) + parseInt(byteRangeMatch[1]) - 1\n }\n }\n nextLine = lines[++i]?.trim()\n }\n\n const uri = nextLine\n\n if (uri && !uri.startsWith('#')) {\n if (isFMP4) {\n fmp4Segments.push({ uri, duration, byteRange })\n } else {\n segments.push({ uri, duration })\n }\n }\n }\n }\n\n return { isMaster: false, isFMP4, segments, fmp4Segments, initSegment, variants: 1 }\n }\n\n /**\n * 同步初始化解码器参数(SPS/PPS)- TS 流\n */\n private initDecoderParamsSync(nalUnits: NALUnit[]): void {\n if (this.decoderInitialized || !this.decoder) return\n\n const spsUnit = nalUnits.find(u => u.type === 7)\n const ppsUnit = nalUnits.find(u => u.type === 8)\n\n if (spsUnit) {\n const nalWithStartCode = new Uint8Array(spsUnit.size + 4)\n nalWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n nalWithStartCode.set(spsUnit.data, 4)\n this.decoder.decode({ type: 7, data: nalWithStartCode, size: nalWithStartCode.length })\n }\n if (ppsUnit) {\n const nalWithStartCode = new Uint8Array(ppsUnit.size + 4)\n nalWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n nalWithStartCode.set(ppsUnit.data, 4)\n this.decoder.decode({ type: 8, data: nalWithStartCode, size: nalWithStartCode.length })\n }\n\n if (spsUnit || ppsUnit) {\n this.decoderInitialized = true\n console.log('[Decoder] Initialized with SPS/PPS')\n }\n }\n\n private readBoxSize(data: Uint8Array, offset: number): number {\n return (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]\n }\n\n private readBoxType(data: Uint8Array, offset: number): string {\n return String.fromCharCode(data[offset], data[offset + 1], data[offset + 2], data[offset + 3])\n }\n\n /**\n * 解码 fMP4 sample\n */\n private decodeSample(sample: VideoSample): VideoFrame | null {\n if (!this.decoder) {\n console.warn('[fMP4] Decoder not available')\n return null\n }\n\n if (!this.decoderInitialized) {\n console.warn('[fMP4] Decoder not initialized, skipping sample')\n return null\n }\n\n const data = sample.data\n\n const hasStartCode = data.length >= 4 && data[0] === 0 && data[1] === 0 &&\n (data[2] === 1 || (data[2] === 0 && data[3] === 1))\n\n if (hasStartCode) {\n return this.decoder.decode({\n type: sample.isSync ? 5 : 1,\n data,\n size: data.length\n })\n }\n\n let nalCount = 0\n let totalSize = 0\n let offset = 0\n\n while (offset + 4 <= data.length) {\n const nalLength = (data[offset] << 24) | (data[offset + 1] << 16) |\n (data[offset + 2] << 8) | data[offset + 3]\n\n if (nalLength <= 0 || offset + 4 + nalLength > data.length) {\n console.warn(`[fMP4] Invalid NAL length: ${nalLength} at offset ${offset}`)\n break\n }\n\n totalSize += 4 + nalLength\n offset += 4 + nalLength\n nalCount++\n }\n\n if (nalCount === 0) {\n console.warn('[fMP4] No valid NAL units found in sample')\n return null\n }\n\n const annexBData = new Uint8Array(totalSize)\n let writeOffset = 0\n offset = 0\n\n while (offset + 4 <= data.length) {\n const nalLength = (data[offset] << 24) | (data[offset + 1] << 16) |\n (data[offset + 2] << 8) | data[offset + 3]\n\n if (nalLength <= 0 || offset + 4 + nalLength > data.length) {\n break\n }\n\n annexBData[writeOffset] = 0\n annexBData[writeOffset + 1] = 0\n annexBData[writeOffset + 2] = 0\n annexBData[writeOffset + 3] = 1\n writeOffset += 4\n\n annexBData.set(data.slice(offset + 4, offset + 4 + nalLength), writeOffset)\n writeOffset += nalLength\n\n offset += 4 + nalLength\n }\n\n const frame = this.decoder.decode({\n type: sample.isSync ? 5 : 1,\n data: annexBData,\n size: annexBData.length\n })\n\n return frame\n }\n\n /**\n * 解码单个 NAL 单元\n */\n private decodeNAL(nalUnit: NALUnit): VideoFrame | null {\n if (!this.decoder) return null\n\n const nalWithStartCode = new Uint8Array(nalUnit.size + 4)\n nalWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n nalWithStartCode.set(nalUnit.data, 4)\n\n return this.decoder.decode({\n type: nalUnit.type,\n data: nalWithStartCode,\n size: nalWithStartCode.length\n })\n }\n\n /**\n * 渲染循环\n */\n protected override renderLoop = (): void => {\n if (!this.isPlaying) return\n\n const downloaded = this.isFMP4 ? this.sampleQueue.length : this.nalQueue.length\n const segments = this.isFMP4 ? this.fmp4Segments : this.segments\n const totalSegments = segments.length\n\n let currentTime = 0\n for (let i = 0; i < this.currentSegmentIndex && i < segments.length; i++) {\n currentTime += segments[i].duration * 1000\n }\n this.setCurrentTime(currentTime)\n\n this.updateState({\n decoded: this.frameBuffer.length,\n downloaded,\n droppedFrames: this.droppedFrames,\n segmentIndex: this.currentSegmentIndex,\n totalSegments\n })\n\n if (this.frameBuffer.length > 0 && this.renderer) {\n const frame = this.frameBuffer.shift()!\n this.renderer.render(frame)\n this.updateState({ resolution: `${frame.width}x${frame.height}` })\n const fps = this.renderer.updateFps()\n this.updateState({ fps })\n this.callbacks.onFrameRender?.(frame)\n }\n\n this.frameTimer = requestAnimationFrame(this.renderLoop)\n }\n}\n","/**\n * FLV (Flash Video) 解析器\n *\n * 用于解析 FLV 文件格式\n *\n * FLV 格式结构:\n * - FLV Header (9 bytes): Signature, Version, Flags, Header Size\n * - Previous Tag Size 0 (4 bytes)\n * - Tag 循环:\n * - Tag Header (11 bytes): Type, Data Size, Timestamp, Stream ID\n * - Tag Data\n * - Previous Tag Size (4 bytes)\n */\n\nimport type {\n FLVVideoTag,\n FLVAVCConfig,\n FLVParseResult,\n FLVHEVCConfig\n} from '../types'\n\n// FLV Header 常量\nconst FLV_SIGNATURE = [0x46, 0x4C, 0x56] // 'F' 'L' 'V'\nconst FLV_VERSION = 1\nconst FLV_HEADER_SIZE = 9\n\n// Tag 类型\nconst TAG_TYPE_AUDIO = 8\nconst TAG_TYPE_VIDEO = 9\nconst TAG_TYPE_SCRIPT = 18\n\n// AVC/HEVC Packet 类型\nconst AVC_PACKET_SEQUENCE_HEADER = 0\nconst AVC_PACKET_NALU = 1\n\n// Codec ID\nconst CODEC_ID_AVC = 7 // H.264\nconst CODEC_ID_HEVC = 12 // H.265\n\n// 帧类型\nconst FRAME_TYPE_KEYFRAME = 1\nconst FRAME_TYPE_INTER_FRAME = 2\n\n/**\n * 读取 3 字节大端序整数\n */\nfunction readUint24(data: Uint8Array, offset: number): number {\n return (data[offset] << 16) | (data[offset + 1] << 8) | data[offset + 2]\n}\n\n/**\n * 读取 4 字节大端序整数\n */\nfunction readUint32(data: Uint8Array, offset: number): number {\n return (\n (data[offset] << 24) |\n (data[offset + 1] << 16) |\n (data[offset + 2] << 8) |\n data[offset + 3]\n ) >>> 0\n}\n\n/**\n * 读取 3 字节有符号整数 (Composition Time Offset)\n */\nfunction readInt24(data: Uint8Array, offset: number): number {\n const value = (data[offset] << 16) | (data[offset + 1] << 8) | data[offset + 2]\n // 如果最高位是 1,则为负数\n return value > 0x7FFFFF ? value - 0x1000000 : value\n}\n\nexport class FLVDemuxer {\n private avcConfig: FLVAVCConfig | null = null\n private hevcConfig: FLVHEVCConfig | null = null\n private codecId: number = CODEC_ID_AVC // 默认 H.264\n\n // 增量解析状态\n private parseOffset = 0 // 当前解析到的位置\n private headerParsed = false // 是否已解析过 header\n private headerSize = 9 // FLV header 大小\n\n /**\n * 检测是否为 FLV 格式\n */\n static isFLV(data: Uint8Array): boolean {\n if (data.length < 13) return false\n\n // 检查签名 \"FLV\"\n if (data[0] !== FLV_SIGNATURE[0] ||\n data[1] !== FLV_SIGNATURE[1] ||\n data[2] !== FLV_SIGNATURE[2]) {\n return false\n }\n\n // 检查版本\n if (data[3] !== FLV_VERSION) {\n return false\n }\n\n return true\n }\n\n /**\n * 解析 FLV 数据\n */\n parse(data: Uint8Array): FLVParseResult {\n const videoTags: FLVVideoTag[] = []\n let duration = 0\n\n if (!FLVDemuxer.isFLV(data)) {\n console.error('[FLVDemuxer] Invalid FLV format')\n return { videoTags, avcConfig: null, hevcConfig: null, duration: 0 }\n }\n\n // 解析 Header\n // byte 4: Flags (bit 0: audio, bit 2: video)\n // byte 5-8: Header Size (通常为 9)\n const headerSize = readUint32(data, 5)\n\n // 跳过 Header 和第一个 PreviousTagSize\n let offset = headerSize + 4\n\n while (offset < data.length - 15) { // 至少需要 Tag Header (11) + PreviousTagSize (4)\n // Tag Header (11 bytes):\n // byte 0: Type (audio=8, video=9, script=18)\n // byte 1-3: Data Size (24 bits)\n // byte 4-7: Timestamp (24 bits + 8 bits extended)\n // byte 8-10: Stream ID (usually 0)\n const tagType = data[offset]\n const dataSize = readUint24(data, offset + 1)\n const timestamp = readUint24(data, offset + 4) | (data[offset + 7] << 24)\n // const streamId = readUint24(data, offset + 8)\n\n offset += 11 // Tag Header size\n\n if (offset + dataSize > data.length) {\n console.warn('[FLVDemuxer] Incomplete tag data, stopping')\n break\n }\n\n const tagData = data.slice(offset, offset + dataSize)\n\n if (tagType === TAG_TYPE_VIDEO) {\n const videoTag = this.parseVideoTag(tagData, timestamp)\n if (videoTag) {\n videoTags.push(videoTag)\n if (videoTag.timestamp > duration) {\n duration = videoTag.timestamp\n }\n }\n } else if (tagType === TAG_TYPE_SCRIPT) {\n // 可以解析 onMetaData 获取 duration\n // 暂时跳过\n }\n\n offset += dataSize\n\n // 跳过 PreviousTagSize (4 bytes)\n offset += 4\n }\n\n return {\n videoTags,\n avcConfig: this.avcConfig,\n hevcConfig: this.hevcConfig,\n duration\n }\n }\n\n /**\n * 增量解析 FLV 数据(用于流式下载)\n * 只解析新收到的数据,避免重复解析\n * @param data 完整的 FLV 数据(包含已解析和未解析的部分)\n * @returns 新解析的视频标签\n */\n parseIncremental(data: Uint8Array): FLVParseResult {\n const videoTags: FLVVideoTag[] = []\n let duration = 0\n\n // 首次解析:检查 FLV 头并跳过\n if (!this.headerParsed) {\n if (!FLVDemuxer.isFLV(data)) {\n console.error('[FLVDemuxer] Invalid FLV format')\n return { videoTags: [], avcConfig: null, hevcConfig: null, duration: 0 }\n }\n\n this.headerSize = readUint32(data, 5)\n this.parseOffset = this.headerSize + 4 // 跳过 header 和第一个 PreviousTagSize\n this.headerParsed = true\n }\n\n // 从上次解析到的位置继续\n let offset = this.parseOffset\n\n while (offset < data.length - 15) { // 至少需要 Tag Header (11) + PreviousTagSize (4)\n const tagType = data[offset]\n const dataSize = readUint24(data, offset + 1)\n const timestamp = readUint24(data, offset + 4) | (data[offset + 7] << 24)\n\n offset += 11 // Tag Header size\n\n // 检查是否有足够的数据\n if (offset + dataSize > data.length) {\n // 数据不完整,等待更多数据\n break\n }\n\n const tagData = data.slice(offset, offset + dataSize)\n\n if (tagType === TAG_TYPE_VIDEO) {\n const videoTag = this.parseVideoTag(tagData, timestamp)\n if (videoTag) {\n videoTags.push(videoTag)\n if (videoTag.timestamp > duration) {\n duration = videoTag.timestamp\n }\n }\n }\n\n offset += dataSize\n offset += 4 // PreviousTagSize\n\n // 更新解析位置\n this.parseOffset = offset\n }\n\n return {\n videoTags,\n avcConfig: this.avcConfig,\n hevcConfig: this.hevcConfig,\n duration\n }\n }\n\n /**\n * 重置增量解析状态(用于重新加载新的 FLV)\n */\n resetIncremental(): void {\n this.parseOffset = 0\n this.headerParsed = false\n this.avcConfig = null\n this.hevcConfig = null\n }\n\n /**\n * 同步增量解析位置(用于从已解析的数据继续)\n * @param offset 已经解析到的字节位置\n */\n syncParseOffset(offset: number): void {\n this.headerParsed = true\n this.parseOffset = offset\n }\n\n /**\n * 解析 Video Tag\n *\n * Video Tag Data 格式 (AVC/HEVC):\n * byte 0: Frame Type (4 bits) + Codec ID (4 bits)\n * byte 1: AVC/HEVC Packet Type\n * byte 2-4: Composition Time Offset (24 bits signed)\n * byte 5+: AVC/HEVC Data\n */\n private parseVideoTag(data: Uint8Array, timestamp: number): FLVVideoTag | null {\n if (data.length < 5) {\n return null\n }\n\n const frameType = (data[0] >> 4) & 0x0F\n const codecId = data[0] & 0x0F\n const avcPacketType = data[1]\n const compositionTimeOffset = readInt24(data, 2)\n\n // 只处理 AVC (H.264) 和 HEVC (H.265) 编码\n if (codecId !== CODEC_ID_AVC && codecId !== CODEC_ID_HEVC) {\n console.warn('[FLVDemuxer] Unsupported codec ID:', codecId)\n return null\n }\n\n // 记录当前编码类型\n this.codecId = codecId\n\n const avcData = data.slice(5)\n\n // 处理 Sequence Header\n if (avcPacketType === AVC_PACKET_SEQUENCE_HEADER) {\n if (codecId === CODEC_ID_HEVC) {\n this.hevcConfig = this.parseHEVCSequenceHeader(avcData)\n console.log('[FLVDemuxer] Parsed HEVC Sequence Header:', {\n vpsCount: this.hevcConfig?.vpsList.length,\n spsCount: this.hevcConfig?.spsList.length,\n ppsCount: this.hevcConfig?.ppsList.length\n })\n } else {\n this.avcConfig = this.parseSequenceHeader(avcData)\n console.log('[FLVDemuxer] Parsed AVC Sequence Header:', {\n profile: this.avcConfig?.avcProfileIndication,\n level: this.avcConfig?.avcLevelIndication,\n spsCount: this.avcConfig?.spsList.length,\n ppsCount: this.avcConfig?.ppsList.length\n })\n }\n // Sequence Header 不是一个有效的视频帧\n return null\n }\n\n // 处理 NALU 数据\n if (avcPacketType === AVC_PACKET_NALU) {\n return {\n timestamp,\n frameType,\n codecId,\n avcPacketType,\n compositionTimeOffset,\n data: avcData\n }\n }\n\n return null\n }\n\n /**\n * 解析 AVC Sequence Header (AVCDecoderConfigurationRecord)\n *\n * 结构 (ISO 14496-15):\n * byte 0: configurationVersion (usually 1)\n * byte 1: AVCProfileIndication\n * byte 2: profile_compatibility\n * byte 3: AVCLevelIndication\n * byte 4: lengthSizeMinusOne (高6位保留=0x3F, 低2位=NALU长度字节数-1)\n * byte 5: numOfSequenceParameterSets (高3位保留=0xE0, 低5位=SPS数量)\n * SPS 列表:\n * - 2 bytes: SPS length\n * - n bytes: SPS data\n * byte: numOfPictureParameterSets\n * PPS 列表:\n * - 2 bytes: PPS length\n * - n bytes: PPS data\n */\n parseSequenceHeader(data: Uint8Array): FLVAVCConfig | null {\n if (data.length < 7) {\n console.error('[FLVDemuxer] Sequence Header too short')\n return null\n }\n\n let offset = 0\n\n const configurationVersion = data[offset++]\n const avcProfileIndication = data[offset++]\n const profileCompatibility = data[offset++]\n const avcLevelIndication = data[offset++]\n const lengthSizeMinusOne = data[offset++] & 0x03\n\n // 读取 SPS 列表\n const spsCount = data[offset++] & 0x1F\n const spsList: Uint8Array[] = []\n\n for (let i = 0; i < spsCount; i++) {\n if (offset + 2 > data.length) {\n console.error('[FLVDemuxer] Incomplete SPS length')\n return null\n }\n const spsLength = (data[offset] << 8) | data[offset + 1]\n offset += 2\n\n if (offset + spsLength > data.length) {\n console.error('[FLVDemuxer] Incomplete SPS data')\n return null\n }\n spsList.push(data.slice(offset, offset + spsLength))\n offset += spsLength\n }\n\n // 读取 PPS 列表\n if (offset >= data.length) {\n console.error('[FLVDemuxer] Missing PPS count')\n return null\n }\n const ppsCount = data[offset++]\n const ppsList: Uint8Array[] = []\n\n for (let i = 0; i < ppsCount; i++) {\n if (offset + 2 > data.length) {\n console.error('[FLVDemuxer] Incomplete PPS length')\n return null\n }\n const ppsLength = (data[offset] << 8) | data[offset + 1]\n offset += 2\n\n if (offset + ppsLength > data.length) {\n console.error('[FLVDemuxer] Incomplete PPS data')\n return null\n }\n ppsList.push(data.slice(offset, offset + ppsLength))\n offset += ppsLength\n }\n\n return {\n configurationVersion,\n avcProfileIndication,\n profileCompatibility,\n avcLevelIndication,\n lengthSizeMinusOne,\n spsList,\n ppsList\n }\n }\n\n /**\n * 解析 HEVC Sequence Header (HEVCDecoderConfigurationRecord)\n *\n * 结构 (ISO 14496-15):\n * byte 0: configurationVersion (usually 1)\n * byte 1: general_profile_space (2 bits) + general_tier_flag (1 bit) + general_profile_idc (5 bits)\n * byte 2-5: general_profile_compatibility_flags (32 bits)\n * byte 6-11: general_constraint_indicator_flags (48 bits)\n * byte 12: general_level_idc\n * byte 13-14: min_spatial_segmentation_idc (高4位保留)\n * byte 15: parallelismType (高6位保留)\n * byte 16: chromaFormat (高6位保留)\n * byte 17: bitDepthLumaMinus8 (高5位保留)\n * byte 18: bitDepthChromaMinus8 (高5位保留)\n * byte 19-20: avgFrameRate\n * byte 21: constantFrameRate (2 bits) + numTemporalLayers (3 bits) + temporalIdNested (1 bit) + lengthSizeMinusOne (2 bits)\n * byte 22: numOfArrays (高3位保留)\n * Arrays:\n * byte 0: array_completeness (1 bit) + reserved (1 bit) + NAL_unit_type (6 bits)\n * byte 1-2: numNalus\n * NALUs:\n * byte 0-1: nalUnitLength\n * byte n: nalUnit data\n */\n parseHEVCSequenceHeader(data: Uint8Array): FLVHEVCConfig | null {\n if (data.length < 23) {\n console.error('[FLVDemuxer] HEVC Sequence Header too short')\n return null\n }\n\n let offset = 0\n\n const configurationVersion = data[offset++]\n if (configurationVersion !== 1) {\n console.warn('[FLVDemuxer] Unknown HEVC configuration version:', configurationVersion)\n }\n\n const byte1 = data[offset++]\n const general_profile_space = (byte1 >> 6) & 0x03\n const general_tier_flag = (byte1 >> 5) & 0x01\n const general_profile_idc = byte1 & 0x1F\n\n const general_profile_compatibility_flags =\n (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]\n offset += 4\n\n // 48 bits (6 bytes) for constraint indicator flags\n const general_constraint_indicator_flags =\n (BigInt(data[offset]) << 40n) |\n (BigInt(data[offset + 1]) << 32n) |\n (BigInt(data[offset + 2]) << 24n) |\n (BigInt(data[offset + 3]) << 16n) |\n (BigInt(data[offset + 4]) << 8n) |\n BigInt(data[offset + 5])\n offset += 6\n\n const general_level_idc = data[offset++]\n\n // min_spatial_segmentation_idc (high 4 bits reserved)\n offset += 2\n\n // parallelismType (high 6 bits reserved)\n offset += 1\n\n // chromaFormat (high 6 bits reserved)\n offset += 1\n\n // bitDepthLumaMinus8 (high 5 bits reserved)\n offset += 1\n\n // bitDepthChromaMinus8 (high 5 bits reserved)\n offset += 1\n\n // avgFrameRate\n offset += 2\n\n const byte21 = data[offset++]\n // const constantFrameRate = (byte21 >> 6) & 0x03\n // const numTemporalLayers = (byte21 >> 3) & 0x07\n // const temporalIdNested = (byte21 >> 2) & 0x01\n const lengthSizeMinusOne = byte21 & 0x03\n\n const numOfArrays = data[offset++]\n\n const vpsList: Uint8Array[] = []\n const spsList: Uint8Array[] = []\n const ppsList: Uint8Array[] = []\n\n for (let i = 0; i < numOfArrays; i++) {\n if (offset >= data.length) {\n console.error('[FLVDemuxer] Incomplete HEVC array header')\n break\n }\n\n const nalUnitType = data[offset++] & 0x3F\n\n if (offset + 2 > data.length) {\n console.error('[FLVDemuxer] Incomplete numNalus')\n break\n }\n const numNalus = (data[offset] << 8) | data[offset + 1]\n offset += 2\n\n for (let j = 0; j < numNalus; j++) {\n if (offset + 2 > data.length) {\n console.error('[FLVDemuxer] Incomplete NAL unit length')\n break\n }\n const nalUnitLength = (data[offset] << 8) | data[offset + 1]\n offset += 2\n\n if (offset + nalUnitLength > data.length) {\n console.error('[FLVDemuxer] Incomplete NAL unit data')\n break\n }\n\n const nalData = data.slice(offset, offset + nalUnitLength)\n offset += nalUnitLength\n\n // NAL type 32 = VPS, 33 = SPS, 34 = PPS\n if (nalUnitType === 32) {\n vpsList.push(nalData)\n } else if (nalUnitType === 33) {\n spsList.push(nalData)\n } else if (nalUnitType === 34) {\n ppsList.push(nalData)\n }\n }\n }\n\n return {\n configurationVersion,\n general_profile_space,\n general_tier_flag,\n general_profile_idc,\n general_profile_compatibility_flags,\n general_constraint_indicator_flags,\n general_level_idc,\n lengthSizeMinusOne,\n vpsList,\n spsList,\n ppsList\n }\n }\n\n /**\n * 获取 AVC 配置\n */\n getAvcConfig(): FLVAVCConfig | null {\n return this.avcConfig\n }\n\n /**\n * 获取 HEVC 配置\n */\n getHevcConfig(): FLVHEVCConfig | null {\n return this.hevcConfig\n }\n\n /**\n * 获取当前编码类型\n */\n getCodecId(): number {\n return this.codecId\n }\n\n /**\n * 将 Video Tag 转换为 Annex B 格式的数据\n *\n * FLV 中的 AVC 数据使用 AVCC 格式 (长度前缀),\n * 需要转换为 Annex B 格式 (start code) 才能被解码器处理\n *\n * @param tag FLV Video Tag\n * @param lengthSize NALU 长度字节数 (从 Sequence Header 获取, 通常为 4)\n * @returns Annex B 格式的数据\n */\n videoTagToAnnexB(tag: FLVVideoTag, lengthSize: number = 4): Uint8Array | null {\n const data = tag.data\n if (data.length === 0) return null\n\n // 计算转换后的大小\n let nalCount = 0\n let totalSize = 0\n let offset = 0\n\n while (offset + lengthSize <= data.length) {\n // 读取 NALU 长度\n let nalLength = 0\n for (let i = 0; i < lengthSize; i++) {\n nalLength = (nalLength << 8) | data[offset + i]\n }\n offset += lengthSize\n\n if (nalLength <= 0 || offset + nalLength > data.length) {\n console.warn(`[FLVDemuxer] Invalid NAL length: ${nalLength} at offset ${offset - lengthSize}`)\n break\n }\n\n totalSize += 4 + nalLength // 4 bytes start code + NAL data\n offset += nalLength\n nalCount++\n }\n\n if (nalCount === 0) {\n console.warn('[FLVDemuxer] No valid NAL units found')\n return null\n }\n\n // 创建 Annex B 格式数据\n const annexBData = new Uint8Array(totalSize)\n let writeOffset = 0\n offset = 0\n\n while (offset + lengthSize <= data.length) {\n let nalLength = 0\n for (let i = 0; i < lengthSize; i++) {\n nalLength = (nalLength << 8) | data[offset + i]\n }\n offset += lengthSize\n\n if (nalLength <= 0 || offset + nalLength > data.length) {\n break\n }\n\n // 写入 start code (0x00000001)\n annexBData[writeOffset++] = 0\n annexBData[writeOffset++] = 0\n annexBData[writeOffset++] = 0\n annexBData[writeOffset++] = 1\n\n // 写入 NAL 数据\n annexBData.set(data.slice(offset, offset + nalLength), writeOffset)\n writeOffset += nalLength\n offset += nalLength\n }\n\n return annexBData\n }\n\n /**\n * 判断 Video Tag 是否为关键帧\n */\n isKeyframe(tag: FLVVideoTag): boolean {\n return tag.frameType === FRAME_TYPE_KEYFRAME\n }\n}\n\n/**\n * 检测是否为 FLV 格式\n */\nexport function isFLV(data: Uint8Array): boolean {\n return FLVDemuxer.isFLV(data)\n}\n","/**\n * H.265/HEVC 解码器\n */\n\nimport type { WASMModule, DecoderContext, VideoFrame, NALUnit } from '../types'\nimport { WASMLoader } from './WASMLoader'\n\n// HEVC NAL unit types\nexport const HEVC_NAL_TYPE = {\n VPS: 32, // Video Parameter Set\n SPS: 33, // Sequence Parameter Set\n PPS: 34, // Picture Parameter Set\n IDR_W_RADL: 19, // IDR slice\n IDR_N_LP: 20, // IDR slice\n} as const\n\nexport class HEVCDecoder {\n private wasmModule: WASMModule | null = null\n private decoderContext: DecoderContext | null = null\n\n constructor(wasmLoader: WASMLoader) {\n this.wasmModule = wasmLoader.getModule()\n }\n\n async init(): Promise<void> {\n if (!this.wasmModule) {\n throw new Error('WASM module not loaded')\n }\n\n // HEVC codec ID = 173 (AV_CODEC_ID_HEVC)\n this.decoderContext = this.wasmModule._create_decoder(173)\n\n if (this.decoderContext === 0 || this.decoderContext === null) {\n throw new Error('Failed to create HEVC decoder context')\n }\n\n console.log('[HEVCDecoder] Initialized with codec_id=173')\n }\n\n decode(nalUnit: NALUnit): VideoFrame | null {\n if (this.decoderContext === null || !this.wasmModule) {\n return null\n }\n\n const dataPtr = this.wasmModule._malloc(nalUnit.size)\n this.wasmModule.HEAPU8.set(nalUnit.data, dataPtr)\n\n const result = this.wasmModule._decode_video(\n this.decoderContext,\n dataPtr,\n nalUnit.size\n )\n\n this.wasmModule._free(dataPtr)\n\n if (result === 1) {\n const width = this.wasmModule._get_frame_width(this.decoderContext)\n const height = this.wasmModule._get_frame_height(this.decoderContext)\n\n if (width <= 0 || height <= 0) {\n return null\n }\n\n const yPtr = this.wasmModule._get_frame_data(this.decoderContext, 0)\n const uPtr = this.wasmModule._get_frame_data(this.decoderContext, 1)\n const vPtr = this.wasmModule._get_frame_data(this.decoderContext, 2)\n\n const yLineSize = this.wasmModule._get_frame_linesize(this.decoderContext, 0)\n const uLineSize = this.wasmModule._get_frame_linesize(this.decoderContext, 1)\n const vLineSize = this.wasmModule._get_frame_linesize(this.decoderContext, 2)\n\n const frameData = this.yuv420pToRgba(\n yPtr, uPtr, vPtr,\n width, height,\n yLineSize, uLineSize, vLineSize\n )\n\n return { width, height, data: frameData }\n }\n\n return null\n }\n\n private yuv420pToRgba(\n yPtr: number, uPtr: number, vPtr: number,\n width: number, height: number,\n yLineSize: number, uLineSize: number, vLineSize: number\n ): Uint8Array {\n const rgba = new Uint8Array(width * height * 4)\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const yIndex = y * yLineSize + x\n const uIndex = (y >> 1) * uLineSize + (x >> 1)\n const vIndex = (y >> 1) * vLineSize + (x >> 1)\n\n const yValue = this.wasmModule!.HEAPU8[yPtr + yIndex]\n const uValue = this.wasmModule!.HEAPU8[uPtr + uIndex]\n const vValue = this.wasmModule!.HEAPU8[vPtr + vIndex]\n\n const c = yValue - 16\n const d = uValue - 128\n const e = vValue - 128\n\n let r = (298 * c + 409 * e + 128) >> 8\n let g = (298 * c - 100 * d - 208 * e + 128) >> 8\n let b = (298 * c + 516 * d + 128) >> 8\n\n r = r < 0 ? 0 : (r > 255 ? 255 : r)\n g = g < 0 ? 0 : (g > 255 ? 255 : g)\n b = b < 0 ? 0 : (b > 255 ? 255 : b)\n\n const rgbaIndex = (y * width + x) * 4\n rgba[rgbaIndex] = r\n rgba[rgbaIndex + 1] = g\n rgba[rgbaIndex + 2] = b\n rgba[rgbaIndex + 3] = 255\n }\n }\n\n return rgba\n }\n}\n","/**\n * FLV 播放器\n *\n * 支持 FLV 文件播放,基于时间戳控制播放速度\n * 支持 H.264 (AVC) 和 H.265 (HEVC) 编码\n *\n * 使用 StreamPrefetcher 预取抽象层\n */\n\nimport { FLVDemuxer } from '../demuxer/FLVDemuxer'\nimport { BasePlayer, DEFAULT_PLAYER_CONFIG } from './BasePlayer'\nimport { H264Decoder } from '../decoder/H264Decoder'\nimport { HEVCDecoder, HEVC_NAL_TYPE } from '../decoder/HEVCDecoder'\nimport type { FLVPlayerConfig, FLVVideoTag, VideoFrame, NALUnit } from '../types'\nimport {\n StreamPrefetcher,\n type StreamPrefetcherConfig,\n DEFAULT_STREAM_PREFETCHER_CONFIG\n} from '../prefetch'\n\n// Codec ID 常量\nconst CODEC_ID_AVC = 7 // H.264\nconst CODEC_ID_HEVC = 12 // H.265\n\n// FLV 预取器配置\nconst FLV_PREFETCHER_CONFIG: StreamPrefetcherConfig = {\n ...DEFAULT_STREAM_PREFETCHER_CONFIG,\n lowWaterMark: 100,\n highWaterMark: 500,\n initialBufferSize: 2 * 1024 * 1024, // 2MB\n prefetchInterval: 10,\n dynamicInterval: true\n}\n\n// 默认配置\nconst DEFAULT_FLV_CONFIG: Required<FLVPlayerConfig> = {\n ...DEFAULT_PLAYER_CONFIG\n}\n\n// Video Tag 队列项\ninterface QueuedVideoTag {\n tag: FLVVideoTag\n annexBData: Uint8Array\n}\n\n// 带时间戳的帧\ninterface TimedFrame {\n frame: VideoFrame\n dts: number // 解码时间戳 (ms) - 用于播放控制\n pts: number // 显示时间戳 (ms) - 用于排序\n}\n\n/**\n * FLV 流式预取器(内部类)\n *\n * 继承 StreamPrefetcher,实现 FLV 特定的数据处理逻辑\n */\nclass FLVStreamPrefetcher extends StreamPrefetcher {\n private player: FLVPlayer\n\n constructor(\n config: StreamPrefetcherConfig,\n callbacks: import('../prefetch').StreamPrefetcherCallbacks,\n player: FLVPlayer\n ) {\n super(config, callbacks)\n this.player = player\n }\n\n /**\n * 判断是否应该预取\n * 对于直播流:只要有 reader 且未完成,就持续下载\n */\n override shouldPrefetch(): boolean {\n if (!this.reader) return false\n if (this.downloadComplete) return false\n // 直播流持续下载,不检查水位\n return true\n }\n\n /**\n * 处理缓冲区数据\n */\n override processBufferData(data: Uint8Array): { hasNewData: boolean; processedBytes: number } {\n return this.player.processPrefetchBuffer(data)\n }\n\n /**\n * 获取队列大小(使用 player 的 videoTagQueue 大小)\n */\n override getQueueSize(): number {\n return this.player.videoTagQueue.length\n }\n}\n\nexport class FLVPlayer extends BasePlayer<FLVPlayerConfig> {\n // FLV 特有的解封装器\n private flvDemuxer = new FLVDemuxer()\n\n // 解码器 - 支持 H.264 和 H.265\n private h264Decoder: H264Decoder | null = null\n private hevcDecoder: HEVCDecoder | null = null\n\n // FLV 特有的状态\n private isPrefetching = false\n private currentUrl = ''\n private _currentCodecId: number = CODEC_ID_AVC // 默认 H.264\n\n // FLV 特有的队列(使用 TimedFrame 而不是 VideoFrame)\n private _timedFrameBuffer: TimedFrame[] = []\n private _videoTagQueue: QueuedVideoTag[] = []\n\n // 播放时间控制\n private playStartTime = 0\n private firstFrameDts = -1\n private lastRenderTime = 0\n private decodeFailCount = 0\n\n // 动态缓冲配置(根据分辨率调整)\n private dynamicMinBufferSize = 10\n private dynamicTargetBufferSize = 60\n private videoWidth = 0\n private videoHeight = 0\n\n // 预取器(使用通用预取抽象层)\n private prefetcher: FLVStreamPrefetcher | null = null\n\n // 流读取器\n private liveReader: ReadableStreamDefaultReader<Uint8Array> | null = null\n private liveDownloadAbort = false\n private _lastQueuedTimestamp = -1\n\n // 下载速度(对外暴露)\n private _currentDownloadSpeed = 0\n\n // 公共访问器(供预取器使用)\n get videoTagQueue(): QueuedVideoTag[] { return this._videoTagQueue }\n get currentCodecId(): number { return this._currentCodecId }\n get lastQueuedTimestamp(): number { return this._lastQueuedTimestamp }\n\n constructor(config: FLVPlayerConfig = {}, callbacks: import('../types').PlayerCallbacks = {}) {\n super(config, callbacks, DEFAULT_FLV_CONFIG)\n }\n\n /**\n * 加载 FLV 文件\n */\n async load(url: string): Promise<void> {\n console.log('[FLVPlayer] Loading URL:', url)\n this.currentUrl = url\n\n // 停止之前的直播流下载\n this.stopLiveDownload()\n\n // 重置状态\n this._timedFrameBuffer = []\n this._videoTagQueue = []\n this.liveDownloadAbort = false\n this.resetState()\n\n // 重置播放时间控制\n this.playStartTime = 0\n this.firstFrameDts = -1\n this.lastRenderTime = 0\n this.decodeFailCount = 0\n\n // 重置动态缓冲配置\n this.dynamicMinBufferSize = 10\n this.dynamicTargetBufferSize = this.config.targetBufferSize\n this.videoWidth = 0\n this.videoHeight = 0\n\n // 重置预取器\n if (this.prefetcher) {\n this.prefetcher.reset()\n this.prefetcher = null\n }\n\n this._currentDownloadSpeed = 0\n this._lastQueuedTimestamp = -1\n this.updateState({ downloadSpeed: 0 })\n\n // 重置 FLV 解封装器\n this.flvDemuxer = new FLVDemuxer()\n\n // 流式加载 FLV\n await this.loadFLV(url)\n\n this.updateState({ isLoaded: true })\n console.log('[FLVPlayer] Loaded, video tags:', this._videoTagQueue.length)\n }\n\n /**\n * 初始化解码器(覆盖基类方法,支持 AVC 和 HEVC)\n */\n override async initDecoder(): Promise<void> {\n await this.wasmLoader.load(this.config.wasmPath as string)\n\n // 检测编码类型\n const avcConfig = this.flvDemuxer.getAvcConfig()\n const hevcConfig = this.flvDemuxer.getHevcConfig()\n this._currentCodecId = this.flvDemuxer.getCodecId()\n\n if (hevcConfig) {\n console.log('[FLVPlayer] Initializing HEVC decoder...')\n this.hevcDecoder = new HEVCDecoder(this.wasmLoader)\n await this.hevcDecoder.init()\n\n if (hevcConfig.vpsList.length > 0 || hevcConfig.spsList.length > 0) {\n this.initDecoderFromHEVCConfig(hevcConfig)\n this.decoderInitialized = true\n } else {\n console.log('[FLVPlayer] HEVC config has no VPS/SPS/PPS, will init from first NALU')\n if (this._videoTagQueue.length > 0) {\n const firstTag = this._videoTagQueue[0]\n this.tryInitFromData(firstTag.annexBData)\n }\n }\n } else if (avcConfig) {\n console.log('[FLVPlayer] Initializing AVC decoder...')\n this.h264Decoder = new H264Decoder(this.wasmLoader)\n await this.h264Decoder.init()\n\n if (avcConfig.spsList.length > 0) {\n this.initDecoderFromAVCConfig(avcConfig)\n this.decoderInitialized = true\n } else {\n console.log('[FLVPlayer] AVC config has no SPS/PPS, will init from first NALU')\n if (this._videoTagQueue.length > 0) {\n const firstTag = this._videoTagQueue[0]\n this.tryInitFromData(firstTag.annexBData)\n }\n }\n } else {\n console.warn('[FLVPlayer] No config found, will try to init from first frames')\n }\n }\n\n /**\n * 根据视频分辨率动态调整缓冲参数\n */\n private adjustBufferForResolution(width: number, height: number): void {\n this.videoWidth = width\n this.videoHeight = height\n const pixels = width * height\n const basePixels = 1920 * 1080\n const ratio = pixels / basePixels\n\n if (ratio > 2) {\n this.dynamicMinBufferSize = 30\n this.dynamicTargetBufferSize = Math.min(150, this.config.targetBufferSize * 2)\n console.log(`[FLVPlayer] High resolution (${width}x${height}), using larger buffer`)\n } else if (ratio > 1) {\n this.dynamicMinBufferSize = 20\n this.dynamicTargetBufferSize = Math.min(100, Math.floor(this.config.targetBufferSize * 1.5))\n console.log(`[FLVPlayer] Medium-high resolution (${width}x${height}), using medium buffer`)\n } else {\n this.dynamicMinBufferSize = 10\n this.dynamicTargetBufferSize = this.config.targetBufferSize\n }\n }\n\n /**\n * 开始播放(覆盖基类方法)\n */\n override async play(): Promise<void> {\n const MIN_BUFFER_SIZE = this.dynamicMinBufferSize\n const MAX_WAIT_TIME = 10000\n const startTime = Date.now()\n\n console.log(`[FLVPlayer] Waiting for buffer (target: ${MIN_BUFFER_SIZE} frames)...`)\n\n let aggressiveDecodeCount = 0\n const MAX_AGGRESSIVE_DECODE = 100\n\n while (this._timedFrameBuffer.length < MIN_BUFFER_SIZE && this._videoTagQueue.length > 0) {\n if (Date.now() - startTime > MAX_WAIT_TIME) {\n console.log('[FLVPlayer] Wait timeout, starting with', this._timedFrameBuffer.length, 'frames')\n break\n }\n\n const batchSize = Math.min(10, this._videoTagQueue.length)\n for (let i = 0; i < batchSize && this._videoTagQueue.length > 0; i++) {\n const queuedTag = this._videoTagQueue.shift()!\n const frame = this.decodeVideoTag(queuedTag)\n if (frame) {\n const dts = queuedTag.tag.timestamp\n const pts = dts + queuedTag.tag.compositionTimeOffset\n this._timedFrameBuffer.push({ frame, dts, pts })\n\n if (this.videoWidth === 0 || this.videoHeight === 0) {\n this.adjustBufferForResolution(frame.width, frame.height)\n }\n }\n aggressiveDecodeCount++\n }\n\n if (aggressiveDecodeCount > MAX_AGGRESSIVE_DECODE) {\n await this.sleep(10)\n aggressiveDecodeCount = 0\n }\n }\n\n console.log('[FLVPlayer] Buffer ready, frames:', this._timedFrameBuffer.length, 'queue:', this._videoTagQueue.length)\n\n if (this._timedFrameBuffer.length > 0) {\n this.firstFrameDts = this._timedFrameBuffer[0].dts\n this.playStartTime = performance.now()\n console.log('[FLVPlayer] Play time initialized, firstFrameDts:', this.firstFrameDts)\n }\n\n this.isPlaying = true\n this.decodeLoopAbort = false\n this.updateState({ isPlaying: true })\n\n // 启动预取器\n if (this.prefetcher) {\n this.prefetcher.start()\n }\n\n // 启动解码循环\n this.decodeLoop()\n\n // 启动渲染循环\n this.frameTimer = requestAnimationFrame(this.renderLoop)\n }\n\n /**\n * 暂停播放\n */\n override pause(): void {\n super.pause()\n if (this.prefetcher) {\n this.prefetcher.stop()\n }\n if (this.config.isLive) {\n console.log('[FLVPlayer] Pausing live stream, stopping download')\n this.stopLiveDownload()\n }\n }\n\n /**\n * 处理预取缓冲区数据(供预取器调用)\n */\n processPrefetchBuffer(data: Uint8Array): { hasNewData: boolean; processedBytes: number } {\n if (!data || data.length === 0) {\n return { hasNewData: false, processedBytes: 0 }\n }\n\n const result = this.flvDemuxer.parseIncremental(data)\n\n // 使用当前已知的 lengthSize,而不是从 result 获取(因为增量解析可能不返回 config)\n // 默认 4 字节长度,这是最常见的\n let lengthSize = 4\n\n // 只有当 result 中有新的 config 时才更新\n if (result.hevcConfig) {\n lengthSize = result.hevcConfig.lengthSizeMinusOne + 1\n this._currentCodecId = CODEC_ID_HEVC\n } else if (result.avcConfig) {\n lengthSize = result.avcConfig.lengthSizeMinusOne + 1\n this._currentCodecId = CODEC_ID_AVC\n }\n\n let newCount = 0\n for (const tag of result.videoTags) {\n if (tag.timestamp > this._lastQueuedTimestamp) {\n // 尝试使用当前 lengthSize\n let annexBData = this.flvDemuxer.videoTagToAnnexB(tag, lengthSize)\n\n // 如果失败,尝试其他长度(1, 2, 4)\n if (!annexBData) {\n for (const trySize of [4, 2, 1]) {\n if (trySize !== lengthSize) {\n annexBData = this.flvDemuxer.videoTagToAnnexB(tag, trySize)\n if (annexBData) {\n lengthSize = trySize\n break\n }\n }\n }\n }\n\n if (annexBData) {\n this._videoTagQueue.push({ tag, annexBData })\n this._lastQueuedTimestamp = tag.timestamp\n newCount++\n }\n }\n }\n\n if (newCount > 0) {\n console.log(`[FLVPlayer] Prefetch: +${newCount} new tags, queue: ${this._videoTagQueue.length}`)\n }\n\n return { hasNewData: newCount > 0, processedBytes: data.length }\n }\n\n /**\n * 跳转到指定时间\n */\n async seek(time: number): Promise<void> {\n this._timedFrameBuffer = []\n this.firstFrameDts = -1\n this.playStartTime = 0\n this.setCurrentTime(time)\n console.log('[FLVPlayer] Seek to', time, 'ms')\n }\n\n /**\n * 解码循环\n */\n protected override async decodeLoop(): Promise<void> {\n console.log('[FLVPlayer] DecodeLoop START, queue size:', this._videoTagQueue.length)\n\n let emptyQueueCount = 0\n const MAX_EMPTY_QUEUE_WAIT = 100\n\n while (this.isPlaying && !this.decodeLoopAbort) {\n // 处理预取缓冲区\n this.prefetcher?.processBuffer()\n\n const targetBuffer = this.dynamicTargetBufferSize\n const bufferRatio = this._timedFrameBuffer.length / targetBuffer\n let batchSize: number\n if (bufferRatio < 0.3) {\n batchSize = Math.max(1, this.config.decodeBatchSize)\n } else if (bufferRatio < 0.6) {\n batchSize = Math.max(3, this.config.decodeBatchSize)\n } else {\n batchSize = Math.max(5, this.config.decodeBatchSize)\n }\n\n let decodedInBatch = 0\n\n while (this._videoTagQueue.length > 0 && decodedInBatch < batchSize) {\n if (this._timedFrameBuffer.length >= targetBuffer) {\n break\n }\n\n const queuedTag = this._videoTagQueue.shift()!\n const frame = this.decodeVideoTag(queuedTag)\n\n if (frame) {\n const dts = queuedTag.tag.timestamp\n const pts = dts + queuedTag.tag.compositionTimeOffset\n this._timedFrameBuffer.push({ frame, dts, pts })\n decodedInBatch++\n\n if (this.videoWidth === 0 || this.videoHeight === 0) {\n this.adjustBufferForResolution(frame.width, frame.height)\n }\n\n if (this._timedFrameBuffer.length <= 5) {\n console.log('[FLVPlayer] Frame decoded, dts:', dts, 'pts:', pts, 'buffer size:', this._timedFrameBuffer.length)\n }\n } else {\n this.decodeFailCount++\n if (this.decodeFailCount <= 10) {\n console.log('[FLVPlayer] Decode failed, dts:', queuedTag.tag.timestamp, 'total fails:', this.decodeFailCount)\n }\n }\n }\n\n if (decodedInBatch > 0) {\n emptyQueueCount = 0\n if (this._timedFrameBuffer.length < targetBuffer * 0.3) {\n await this.yieldFast()\n } else if (this._timedFrameBuffer.length < targetBuffer * 0.6) {\n await this.yieldFast()\n } else {\n await this.sleep(2)\n }\n } else {\n if (this._videoTagQueue.length === 0 && this._timedFrameBuffer.length === 0) {\n emptyQueueCount++\n if (emptyQueueCount >= MAX_EMPTY_QUEUE_WAIT) {\n console.log('[FLVPlayer] No more data after waiting, stopping decode loop')\n break\n }\n if (emptyQueueCount === 1) {\n console.log('[FLVPlayer] Queue empty, waiting for more data...')\n }\n } else {\n emptyQueueCount = 0\n }\n await this.sleep(50)\n }\n }\n\n console.log('[FLVPlayer] DecodeLoop END, decoded:', this._timedFrameBuffer.length + this.droppedFrames, 'failed:', this.decodeFailCount, 'dropped:', this.droppedFrames)\n }\n\n // ==================== 私有方法 ====================\n\n /**\n * 流式加载 FLV 文件\n */\n private async loadFLV(url: string): Promise<void> {\n console.log('[FLVPlayer] Fetching FLV...')\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch FLV: ${response.status}`)\n }\n console.log('[FLVPlayer] Fetch response OK, status:', response.status)\n\n this.isPrefetching = true\n this.updateState({ isPrefetching: true })\n\n const isLive = this.config.isLive || false\n console.log('[FLVPlayer] isLive:', isLive)\n\n try {\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('ReadableStream not supported')\n }\n\n const chunks: Uint8Array[] = []\n let totalLength = 0\n const MIN_DATA_SIZE = isLive ? 100 * 1024 : 500 * 1024\n const TIMEOUT_MS = isLive ? 5000 : 8000\n const startTime = Date.now()\n let started = false\n let lastLoggedTags = 0\n\n this.liveReader = reader\n\n while (true) {\n const { done, value } = await reader.read()\n\n if (value) {\n chunks.push(value)\n totalLength += value.length\n }\n\n const shouldStart = totalLength >= MIN_DATA_SIZE || Date.now() - startTime > TIMEOUT_MS\n\n if (!started && shouldStart && totalLength > 0) {\n started = true\n console.log('[FLVPlayer] Buffered', totalLength, 'bytes, starting...')\n\n const data = new Uint8Array(totalLength)\n let offset = 0\n for (const chunk of chunks) {\n data.set(chunk, offset)\n offset += chunk.length\n }\n\n this.parseAndQueueFLV(data)\n lastLoggedTags = this._videoTagQueue.length\n this.updateState({ isLoaded: true })\n console.log('[FLVPlayer] Stream ready, video tags:', this._videoTagQueue.length)\n\n // 初始化预取器\n this.initPrefetcher(reader, chunks, totalLength)\n\n return\n }\n\n if (started && totalLength > 0) {\n const allData = new Uint8Array(totalLength)\n let offset = 0\n for (const chunk of chunks) {\n allData.set(chunk, offset)\n offset += chunk.length\n }\n\n this._videoTagQueue = []\n this.parseAndQueueFLV(allData)\n\n if (this._videoTagQueue.length - lastLoggedTags >= 50) {\n console.log('[FLVPlayer] Stream:', this._videoTagQueue.length, 'tags,', totalLength, 'bytes')\n lastLoggedTags = this._videoTagQueue.length\n }\n }\n\n if (done) {\n console.log('[FLVPlayer] Download complete:', totalLength, 'bytes')\n if (!started && totalLength > 0) {\n const data = new Uint8Array(totalLength)\n let offset = 0\n for (const chunk of chunks) {\n data.set(chunk, offset)\n offset += chunk.length\n }\n this.parseAndQueueFLV(data)\n this.updateState({ isLoaded: true })\n }\n break\n }\n }\n\n } catch (error) {\n console.error('[FLVPlayer] Error loading FLV:', error)\n throw error\n } finally {\n if (!this.config.isLive) {\n this.isPrefetching = false\n this.updateState({ isPrefetching: false })\n }\n }\n }\n\n /**\n * 初始化预取器\n */\n private initPrefetcher(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n chunks: Uint8Array[],\n initialLength: number\n ): void {\n // 合并初始数据\n const initialData = new Uint8Array(initialLength)\n let offset = 0\n for (const chunk of chunks) {\n initialData.set(chunk, offset)\n offset += chunk.length\n }\n\n // 创建预取器\n this.prefetcher = new FLVStreamPrefetcher(\n FLV_PREFETCHER_CONFIG,\n {\n onStatusChange: (status) => {\n this.updateState({\n isPrefetching: status.isPrefetching,\n downloadSpeed: status.downloadSpeed\n })\n this._currentDownloadSpeed = status.downloadSpeed\n },\n onDataReceived: (totalBytes) => {\n console.log(`[FLVPlayer] Data received: ${totalBytes} bytes`)\n }\n },\n this\n )\n\n // 设置读取器和初始数据\n this.prefetcher.setReader(reader, initialData)\n\n // 同步 FLVDemuxer 的增量解析状态\n // 关键:使用 parseIncremental 来同步解析位置,而不是直接设置偏移量\n // 这样可以确保 parseOffset 指向有效的 tag 边界\n this.flvDemuxer.parseIncremental(initialData)\n\n console.log(`[FLVPlayer] Prefetcher initialized with ${initialLength} bytes`)\n }\n\n /**\n * 停止直播流下载\n */\n private stopLiveDownload(): void {\n this.liveDownloadAbort = true\n if (this.liveReader) {\n this.liveReader.cancel()\n this.liveReader = null\n }\n if (this.prefetcher) {\n this.prefetcher.cancelDownload()\n }\n }\n\n /**\n * 解析 FLV 数据并入队\n */\n private parseAndQueueFLV(data: Uint8Array): void {\n if (data.length < 13) {\n throw new Error('Invalid FLV: data too short')\n }\n const flvHeader = String.fromCharCode(data[0], data[1], data[2])\n if (flvHeader !== 'FLV') {\n throw new Error('Invalid FLV: header not found, got: ' + flvHeader)\n }\n console.log('[FLVPlayer] FLV header valid')\n\n const result = this.flvDemuxer.parse(data)\n console.log('[FLVPlayer] Parsed FLV:', {\n videoTags: result.videoTags.length,\n duration: result.duration,\n hasAvcConfig: !!result.avcConfig,\n hasHevcConfig: !!result.hevcConfig\n })\n\n this.setDuration(result.duration)\n\n let lengthSize = 4\n if (result.hevcConfig) {\n lengthSize = result.hevcConfig.lengthSizeMinusOne + 1\n this._currentCodecId = CODEC_ID_HEVC\n } else if (result.avcConfig) {\n lengthSize = result.avcConfig.lengthSizeMinusOne + 1\n this._currentCodecId = CODEC_ID_AVC\n }\n\n let detectedLengthSize = lengthSize\n for (const tag of result.videoTags) {\n let annexBData = this.flvDemuxer.videoTagToAnnexB(tag, detectedLengthSize)\n\n if (!annexBData && detectedLengthSize !== 4) {\n annexBData = this.flvDemuxer.videoTagToAnnexB(tag, 4)\n if (annexBData) {\n detectedLengthSize = 4\n console.log('[FLVPlayer] Auto-detected length size: 4 bytes')\n }\n }\n\n if (annexBData) {\n this._videoTagQueue.push({ tag, annexBData })\n if (tag.timestamp > this._lastQueuedTimestamp) {\n this._lastQueuedTimestamp = tag.timestamp\n }\n }\n }\n\n console.log('[FLVPlayer] Queued', this._videoTagQueue.length, 'video tags, lengthSize:', detectedLengthSize)\n }\n\n /**\n * 从 AVC 配置初始化解码器\n */\n private initDecoderFromAVCConfig(config: import('../types').FLVAVCConfig): void {\n if (!this.h264Decoder) return\n\n if (config.spsList.length > 0) {\n const sps = config.spsList[0]\n const spsWithStartCode = new Uint8Array(4 + sps.length)\n spsWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n spsWithStartCode.set(sps, 4)\n this.h264Decoder.decode({ type: 7, data: spsWithStartCode, size: spsWithStartCode.length })\n console.log('[FLVPlayer] AVC SPS decoded, length:', sps.length)\n }\n\n if (config.ppsList.length > 0) {\n const pps = config.ppsList[0]\n const ppsWithStartCode = new Uint8Array(4 + pps.length)\n ppsWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n ppsWithStartCode.set(pps, 4)\n this.h264Decoder.decode({ type: 8, data: ppsWithStartCode, size: ppsWithStartCode.length })\n console.log('[FLVPlayer] AVC PPS decoded, length:', pps.length)\n }\n\n console.log('[FLVPlayer] Decoder initialized from AVC config')\n }\n\n /**\n * 从 HEVC 配置初始化解码器\n */\n private initDecoderFromHEVCConfig(config: import('../types').FLVHEVCConfig): void {\n if (!this.hevcDecoder) return\n\n if (config.vpsList.length > 0) {\n const vps = config.vpsList[0]\n const vpsWithStartCode = new Uint8Array(4 + vps.length)\n vpsWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n vpsWithStartCode.set(vps, 4)\n this.hevcDecoder.decode({ type: 32, data: vpsWithStartCode, size: vpsWithStartCode.length })\n console.log('[FLVPlayer] HEVC VPS decoded, length:', vps.length)\n }\n\n if (config.spsList.length > 0) {\n const sps = config.spsList[0]\n const spsWithStartCode = new Uint8Array(4 + sps.length)\n spsWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n spsWithStartCode.set(sps, 4)\n this.hevcDecoder.decode({ type: 33, data: spsWithStartCode, size: spsWithStartCode.length })\n console.log('[FLVPlayer] HEVC SPS decoded, length:', sps.length)\n }\n\n if (config.ppsList.length > 0) {\n const pps = config.ppsList[0]\n const ppsWithStartCode = new Uint8Array(4 + pps.length)\n ppsWithStartCode.set([0x00, 0x00, 0x00, 0x01], 0)\n ppsWithStartCode.set(pps, 4)\n this.hevcDecoder.decode({ type: 34, data: ppsWithStartCode, size: ppsWithStartCode.length })\n console.log('[FLVPlayer] HEVC PPS decoded, length:', pps.length)\n }\n\n console.log('[FLVPlayer] Decoder initialized from HEVC config')\n }\n\n /**\n * 解码 Video Tag\n */\n private decodeVideoTag(queuedTag: QueuedVideoTag): VideoFrame | null {\n const decoder = this._currentCodecId === CODEC_ID_HEVC ? this.hevcDecoder : this.h264Decoder\n\n if (!decoder) {\n console.warn('[FLVPlayer] Decoder not available')\n return null\n }\n\n if (!this.decoderInitialized) {\n if (this.flvDemuxer.isKeyframe(queuedTag.tag)) {\n this.tryInitFromData(queuedTag.annexBData)\n }\n if (!this.decoderInitialized) {\n return null\n }\n }\n\n const isKeyframe = this.flvDemuxer.isKeyframe(queuedTag.tag)\n const frame = decoder.decode({\n type: isKeyframe ? 5 : 1,\n data: queuedTag.annexBData,\n size: queuedTag.annexBData.length\n })\n\n return frame\n }\n\n /**\n * 尝试从 Annex B 数据中初始化解码器\n */\n private tryInitFromData(data: Uint8Array): void {\n if (this.decoderInitialized) return\n\n const decoder = this._currentCodecId === CODEC_ID_HEVC ? this.hevcDecoder : this.h264Decoder\n if (!decoder) return\n\n if (this._currentCodecId === CODEC_ID_HEVC) {\n this.tryInitHEVCFromData(data, decoder as HEVCDecoder)\n } else {\n this.tryInitAVCFromData(data, decoder as H264Decoder)\n }\n }\n\n /**\n * 从数据中初始化 AVC 解码器\n */\n private tryInitAVCFromData(data: Uint8Array, decoder: H264Decoder): void {\n let offset = 0\n let sps: Uint8Array | null = null\n let pps: Uint8Array | null = null\n\n while (offset + 4 < data.length) {\n if (data[offset] === 0 && data[offset + 1] === 0 &&\n (data[offset + 2] === 1 || (data[offset + 2] === 0 && data[offset + 3] === 1))) {\n\n const startCodeSize = data[offset + 2] === 1 ? 3 : 4\n const nalStart = offset + startCodeSize\n\n if (nalStart >= data.length) break\n\n const nalType = data[nalStart] & 0x1F\n\n let nalEnd = data.length\n for (let i = nalStart + 1; i < data.length - 3; i++) {\n if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 1) {\n nalEnd = i\n break\n }\n }\n\n if (nalType === 7 && !sps) {\n sps = data.slice(offset, nalEnd)\n } else if (nalType === 8 && !pps) {\n pps = data.slice(offset, nalEnd)\n }\n\n offset = nalEnd\n } else {\n offset++\n }\n }\n\n if (sps) {\n decoder.decode({ type: 7, data: sps, size: sps.length })\n console.log('[FLVPlayer] AVC SPS decoded from data')\n }\n if (pps) {\n decoder.decode({ type: 8, data: pps, size: pps.length })\n console.log('[FLVPlayer] AVC PPS decoded from data')\n }\n\n if (sps || pps) {\n this.decoderInitialized = true\n }\n }\n\n /**\n * 从数据中初始化 HEVC 解码器\n */\n private tryInitHEVCFromData(data: Uint8Array, decoder: HEVCDecoder): void {\n if (!data) return\n\n let offset = 0\n let vps: Uint8Array | null = null\n let sps: Uint8Array | null = null\n let pps: Uint8Array | null = null\n\n while (offset + 5 < data.length) {\n if (data[offset] === 0 && data[offset + 1] === 0 &&\n (data[offset + 2] === 1 || (data[offset + 2] === 0 && data[offset + 3] === 1))) {\n\n const startCodeSize = data[offset + 2] === 1 ? 3 : 4\n const nalStart = offset + startCodeSize\n\n if (nalStart >= data.length) break\n\n const nalType = (data[nalStart] >> 1) & 0x3F\n\n let nalEnd = data.length\n for (let i = nalStart + 1; i < data.length - 3; i++) {\n if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 1) {\n nalEnd = i\n break\n }\n }\n\n if (nalType === 32 && !vps) {\n vps = data.slice(offset, nalEnd)\n } else if (nalType === 33 && !sps) {\n sps = data.slice(offset, nalEnd)\n } else if (nalType === 34 && !pps) {\n pps = data.slice(offset, nalEnd)\n }\n\n offset = nalEnd\n } else {\n offset++\n }\n }\n\n if (vps) {\n decoder.decode({ type: 32, data: vps, size: vps.length })\n console.log('[FLVPlayer] HEVC VPS decoded from data')\n }\n if (sps) {\n decoder.decode({ type: 33, data: sps, size: sps.length })\n console.log('[FLVPlayer] HEVC SPS decoded from data')\n }\n if (pps) {\n decoder.decode({ type: 34, data: pps, size: pps.length })\n console.log('[FLVPlayer] HEVC PPS decoded from data')\n }\n\n if (vps || sps || pps) {\n this.decoderInitialized = true\n }\n }\n\n // 渲染统计\n private renderedFrames = 0\n private lastRenderLogTime = 0\n private consecutiveEmptyBuffer = 0\n private lastRenderedDts = -1\n private pausedTime = 0\n private bufferEmptyStartTime = 0\n private playStartTimeOffset = 0\n private resyncCount = 0\n\n /**\n * 渲染循环\n */\n protected override renderLoop = (): void => {\n if (!this.isPlaying) return\n\n this.updateState({\n decoded: this._timedFrameBuffer.length,\n downloaded: this._videoTagQueue.length,\n droppedFrames: this.droppedFrames\n })\n\n const now = performance.now()\n const isLive = this.config.isLive\n\n if (this._timedFrameBuffer.length > 0 && this.renderer) {\n this.consecutiveEmptyBuffer = 0\n\n if (this.firstFrameDts < 0) {\n this.firstFrameDts = this._timedFrameBuffer[0].dts\n this.playStartTime = now\n this.playStartTimeOffset = 0\n console.log('[FLVPlayer] RenderLoop initialized, firstFrameDts:', this.firstFrameDts, 'isLive:', isLive)\n }\n\n if (isLive) {\n const elapsed = now - this.playStartTime - this.pausedTime\n const currentTargetDts = this.firstFrameDts + elapsed\n this.setCurrentTime(Math.floor(currentTargetDts))\n\n let frameToRender: TimedFrame | null = null\n while (this._timedFrameBuffer.length > 0 && this._timedFrameBuffer[0].dts <= currentTargetDts) {\n if (frameToRender) {\n this.droppedFrames++\n }\n frameToRender = this._timedFrameBuffer.shift()!\n }\n\n if (frameToRender) {\n this.renderFrame(frameToRender, now)\n }\n } else {\n const nextFrame = this._timedFrameBuffer[0]\n const elapsed = now - this.playStartTime - this.playStartTimeOffset\n const currentTargetPts = this.firstFrameDts + elapsed\n\n if (this.lastRenderedDts >= 0) {\n this.setCurrentTime(Math.floor(this.lastRenderedDts))\n }\n\n if (nextFrame.dts <= currentTargetPts) {\n const frameToRender = this._timedFrameBuffer.shift()!\n this.renderFrame(frameToRender, now)\n this.lastRenderedDts = frameToRender.dts\n\n const lag = currentTargetPts - frameToRender.dts\n if (lag > 1000) {\n this.playStartTime = now\n this.playStartTimeOffset = 0\n this.firstFrameDts = frameToRender.dts\n this.resyncCount++\n if (this.resyncCount <= 3) {\n console.log('[FLVPlayer] Major resync, lag:', Math.floor(lag), 'ms')\n }\n }\n }\n }\n\n if (now - this.lastRenderLogTime > 5000) {\n console.log('[FLVPlayer] RenderLoop stats:', {\n renderedFrames: this.renderedFrames,\n droppedFrames: this.droppedFrames,\n decoded: this._timedFrameBuffer.length,\n downloaded: this._videoTagQueue.length,\n mode: isLive ? 'live' : 'vod'\n })\n this.lastRenderLogTime = now\n }\n } else {\n if (this.consecutiveEmptyBuffer === 0 && this.lastRenderedDts >= 0) {\n this.bufferEmptyStartTime = now\n }\n this.consecutiveEmptyBuffer++\n\n if (isLive && this.bufferEmptyStartTime > 0) {\n this.pausedTime = now - this.bufferEmptyStartTime\n } else if (!isLive && this.bufferEmptyStartTime > 0) {\n this.playStartTimeOffset = now - this.bufferEmptyStartTime\n }\n\n if (this.consecutiveEmptyBuffer === 1) {\n console.warn('[FLVPlayer] Buffer empty, waiting for frames... queue:', this._videoTagQueue.length)\n } else if (this.consecutiveEmptyBuffer % 60 === 0) {\n console.warn('[FLVPlayer] Buffer still empty after', Math.floor(this.consecutiveEmptyBuffer / 60), 'seconds')\n }\n }\n\n this.frameTimer = requestAnimationFrame(this.renderLoop)\n }\n\n /**\n * 渲染一帧\n */\n private renderFrame(frame: TimedFrame, now: number): void {\n if (!this.renderer) return\n\n this.renderer.render(frame.frame)\n this.renderedFrames++\n this.lastRenderedDts = frame.dts\n this.updateState({ resolution: `${frame.frame.width}x${frame.frame.height}` })\n const fps = this.renderer.updateFps()\n this.updateState({ fps })\n this.callbacks.onFrameRender?.(frame.frame)\n this.lastRenderTime = now\n }\n}\n","/**\n * 格式检测工具\n *\n * 支持通过 URL、数据头、Content-Type 检测流格式\n */\n\nexport type StreamFormat = 'hls-ts' | 'hls-fmp4' | 'flv' | 'mp4' | 'unknown'\n\nexport class FormatDetector {\n /**\n * 通过 URL 检测格式\n */\n static detectFromUrl(url: string): StreamFormat {\n try {\n const urlObj = new URL(url)\n const pathname = urlObj.pathname.toLowerCase()\n\n if (pathname.endsWith('.m3u8') || pathname.endsWith('.m3u')) {\n return 'hls-ts' // 需要进一步检测是 TS 还是 fMP4\n }\n if (pathname.endsWith('.flv')) {\n return 'flv'\n }\n if (pathname.endsWith('.mp4')) {\n return 'mp4'\n }\n } catch {\n // URL 解析失败,降级为简单匹配\n const lower = url.toLowerCase()\n if (lower.includes('.m3u8') || lower.includes('.m3u')) return 'hls-ts'\n if (lower.includes('.flv')) return 'flv'\n if (lower.includes('.mp4')) return 'mp4'\n }\n return 'unknown'\n }\n\n /**\n * 通过数据头检测格式\n */\n static detectFromData(data: Uint8Array): StreamFormat {\n if (data.length < 4) return 'unknown'\n\n // FLV: 0x46 0x4C 0x56 (FLV)\n if (data[0] === 0x46 && data[1] === 0x4C && data[2] === 0x56) {\n return 'flv'\n }\n\n // fMP4: ftyp box (offset 4)\n if (data.length >= 8 &&\n data[4] === 0x66 && data[5] === 0x74 &&\n data[6] === 0x79 && data[7] === 0x70) {\n return 'hls-fmp4'\n }\n\n // TS: 0x47 sync byte\n if (data[0] === 0x47) {\n return 'hls-ts'\n }\n\n return 'unknown'\n }\n\n /**\n * 通过 Content-Type 检测格式\n */\n static detectFromContentType(contentType: string): StreamFormat {\n const type = contentType.toLowerCase()\n\n if (type.includes('mpegurl') || type.includes('x-mpegurl')) {\n return 'hls-ts'\n }\n if (type.includes('x-flv') || type.includes('flv')) {\n return 'flv'\n }\n if (type.includes('mp4')) {\n return 'mp4'\n }\n return 'unknown'\n }\n}\n","/**\n * Canvas 2D 渲染器\n */\n\nimport type { VideoFrame } from '../types'\n\nexport class Canvas2DRenderer {\n private canvas: HTMLCanvasElement\n private ctx: CanvasRenderingContext2D | null = null\n private frameCount = 0\n private lastFpsUpdate = performance.now()\n private lastFps = 0\n\n constructor(canvas: HTMLCanvasElement) {\n this.canvas = canvas\n this.ctx = canvas.getContext('2d')\n if (!this.ctx) {\n throw new Error('Invalid canvas element')\n }\n }\n\n render(frame: VideoFrame): void {\n const { width, height, data } = frame\n\n if (this.canvas.width !== width || this.canvas.height !== height) {\n this.canvas.width = width\n this.canvas.height = height\n }\n\n const imageData = new ImageData(new Uint8ClampedArray(data), width, height)\n this.ctx!.putImageData(imageData, 0, 0)\n }\n\n updateFps(): number {\n this.frameCount++\n const now = performance.now()\n if (now - this.lastFpsUpdate >= 1000) {\n this.lastFps = this.frameCount\n this.frameCount = 0\n this.lastFpsUpdate = now\n }\n return this.lastFps\n }\n\n getCanvas(): HTMLCanvasElement {\n return this.canvas\n }\n}\n","/**\n * EcPlayerCore 统一播放器入口\n *\n * 自动检测视频格式(HLS/FLV/MP4),创建对应的播放器实例\n * 提供统一的 API,简化使用\n */\n\nimport { BasePlayer, type PlayerConfig, DEFAULT_PLAYER_CONFIG } from './BasePlayer'\nimport { HLSPlayer } from './HLSPlayer'\nimport { FLVPlayer } from './FLVPlayer'\nimport { FormatDetector, type StreamFormat } from '../demuxer/FormatDetector'\nimport { Canvas2DRenderer } from '../renderer/Canvas2DRenderer'\nimport type { PlayerState, PlayerCallbacks } from '../types'\n\n// EcPlayerCore 配置(继承通用播放器配置)\nexport interface EcPlayerCoreConfig extends PlayerConfig {\n /** Canvas 元素,用于渲染视频 */\n canvas?: HTMLCanvasElement\n}\n\n// 播放参数\nexport interface PlayOptions {\n /** 视频 URL(不传则继续播放当前视频) */\n url?: string\n /** 是否为直播流 */\n isLive?: boolean\n}\n\n// 默认配置\nconst DEFAULT_EC_CONFIG: EcPlayerCoreConfig = {\n ...DEFAULT_PLAYER_CONFIG\n}\n\nexport class EcPlayerCore {\n private player: BasePlayer | null = null\n private config: EcPlayerCoreConfig\n private callbacks: PlayerCallbacks\n private detectedFormat: StreamFormat = 'unknown'\n private pendingRenderer: Canvas2DRenderer | null = null\n private renderer: Canvas2DRenderer | null = null\n\n constructor(config: EcPlayerCoreConfig = {}, callbacks: PlayerCallbacks = {}) {\n this.config = { ...DEFAULT_EC_CONFIG, ...config }\n this.callbacks = callbacks\n\n // 如果传入了 canvas,自动创建渲染器\n if (this.config.canvas) {\n this.renderer = new Canvas2DRenderer(this.config.canvas)\n this.pendingRenderer = this.renderer\n }\n }\n\n /**\n * 加载视频(自动检测格式、初始化解码器)\n * @param url 视频 URL\n * @param isLive 是否为直播流(直播流会持续下载数据)\n */\n async load(url: string, isLive?: boolean): Promise<void> {\n // 设置加载中状态\n this.callbacks.onStateChange?.({ isLoading: true, isLoaded: false })\n\n try {\n // 检测格式\n this.detectedFormat = FormatDetector.detectFromUrl(url)\n console.log('[EcPlayerCore] Detected format:', this.detectedFormat, 'from URL:', url, 'isLive:', isLive)\n\n // 更新配置中的 isLive\n if (isLive !== undefined) {\n this.config.isLive = isLive\n }\n\n // 创建对应的播放器\n this.player = this.createPlayer(this.detectedFormat)\n\n // 如果有等待设置的渲染器,立即设置\n if (this.pendingRenderer) {\n this.player.setRenderer(this.pendingRenderer)\n this.pendingRenderer = null\n }\n\n // 加载视频流\n await this.player.load(url)\n\n // 自动初始化解码器\n await this.player.initDecoder()\n\n this.callbacks.onStateChange?.({ isLoaded: true })\n } finally {\n // 加载完成,清除加载中状态\n this.callbacks.onStateChange?.({ isLoading: false })\n }\n }\n\n /**\n * 根据格式创建播放器\n */\n private createPlayer(format: StreamFormat): BasePlayer {\n switch (format) {\n case 'flv':\n return new FLVPlayer(this.config, this.callbacks)\n case 'hls-ts':\n case 'hls-fmp4':\n case 'unknown':\n default:\n // HLSPlayer 可以处理 TS 和 fMP4,以及未知格式\n return new HLSPlayer(this.config, this.callbacks)\n }\n }\n\n // ==================== 公共 API ====================\n\n /**\n * 播放视频\n * @param options 播放参数\n */\n async play(options?: PlayOptions): Promise<void> {\n if (options?.url) {\n // 加载新视频并播放\n await this.load(options.url, options.isLive)\n }\n\n // 开始/继续播放\n return this.player?.play()\n }\n\n /**\n * 暂停播放\n */\n pause(): void {\n this.player?.pause()\n }\n\n /**\n * 跳转到指定时间\n */\n async seek(time: number): Promise<void> {\n return this.player?.seek(time)\n }\n\n /**\n * 获取当前播放时间(毫秒)\n */\n getCurrentTime(): number {\n return this.player?.getCurrentTime() ?? 0\n }\n\n /**\n * 获取总时长(毫秒)\n */\n getDuration(): number {\n return this.player?.getDuration() ?? 0\n }\n\n /**\n * 获取播放状态\n */\n getState(): PlayerState {\n if (!this.player) {\n return {\n isPlaying: false,\n isLoaded: false,\n isLoading: false,\n fps: 0,\n resolution: '-',\n decoded: 0,\n downloaded: 0,\n droppedFrames: 0,\n isPrefetching: false,\n segmentIndex: 0,\n totalSegments: 0,\n downloadSpeed: 0,\n currentTime: 0,\n duration: 0\n }\n }\n return this.player.getState()\n }\n\n /**\n * 获取检测到的格式\n */\n getDetectedFormat(): StreamFormat {\n return this.detectedFormat\n }\n\n /**\n * 销毁播放器,释放资源\n */\n destroy(): void {\n console.log('[EcPlayerCore] Destroying player...')\n if (this.player) {\n this.player.destroy()\n this.player = null\n }\n this.pendingRenderer = null\n this.renderer = null\n this.detectedFormat = 'unknown'\n console.log('[EcPlayerCore] Player destroyed')\n }\n\n /**\n * 获取内部播放器实例\n * 用于需要访问特定播放器功能的场景\n */\n getPlayer(): BasePlayer | null {\n return this.player\n }\n}\n","/**\n * 环境检测器\n *\n * 检测当前运行环境:\n * - 微信小程序 WebView\n * - PC 浏览器\n * - 移动端浏览器\n *\n * 同时检测各种能力:SIMD、WebGL、WebAudio 等\n */\n\n/**\n * 运行平台\n */\nexport enum Platform {\n /** PC 浏览器 */\n PC_BROWSER = 'pc-browser',\n /** 移动端浏览器 */\n MOBILE_BROWSER = 'mobile-browser',\n /** 微信小程序 WebView */\n WECHAT_MINIPROGRAM = 'wechat-miniprogram',\n /** 支付宝小程序 WebView */\n ALIPAY_MINIPROGRAM = 'alipay-miniprogram',\n /** 其他小程序 */\n OTHER_MINIPROGRAM = 'other-miniprogram',\n /** 未知环境 */\n UNKNOWN = 'unknown',\n}\n\n/**\n * 环境类型(简化分类)\n */\nexport enum EnvType {\n /** 浏览器环境(PC + 移动端) */\n BROWSER = 'browser',\n /** 小程序环境 */\n MINIPROGRAM = 'miniprogram',\n}\n\n/**\n * 环境能力\n */\nexport interface EnvCapabilities {\n /** SharedArrayBuffer 是否可用 */\n sharedArrayBuffer: boolean\n /** WASM 多线程是否可用 */\n wasmThreads: boolean\n /** WASM SIMD 是否可用 */\n wasmSimd: boolean\n /** WebGL 是否可用 */\n webGL: boolean\n /** WebGL 2 是否可用 */\n webGL2: boolean\n /** VideoFrame API 是否可用 */\n videoFrame: boolean\n /** OffscreenCanvas 是否可用 */\n offscreenCanvas: boolean\n /** Web Audio API 是否可用 */\n webAudio: boolean\n /** Web Worker 是否可用 */\n webWorker: boolean\n /** Fetch API 是否可用 */\n fetch: boolean\n /** WebSocket 是否可用 */\n webSocket: boolean\n /** 是否支持 ReadableStream */\n readableStream: boolean\n}\n\n/**\n * 环境检测结果\n */\nexport interface EnvInfo {\n /** 平台类型 */\n platform: Platform\n /** 环境类型(简化) */\n envType: EnvType\n /** 是否为小程序环境 */\n isMiniProgram: boolean\n /** 是否为微信小程序 */\n isWeChat: boolean\n /** 是否为移动设备 */\n isMobile: boolean\n /** User Agent 字符串 */\n userAgent: string\n /** 环境能力 */\n capabilities: EnvCapabilities\n}\n\n/**\n * 环境检测器\n *\n * 使用方式:\n * ```typescript\n * const env = EnvDetector.detect()\n * console.log(env.platform) // Platform.PC_BROWSER\n * console.log(env.isMiniProgram) // false\n * console.log(env.capabilities.wasmSimd) // true\n * ```\n */\nexport class EnvDetector {\n private static cache: EnvInfo | null = null\n\n /**\n * 检测当前环境(带缓存)\n */\n static detect(): EnvInfo {\n if (this.cache) {\n return this.cache\n }\n\n const ua = this.getUserAgent()\n const platform = this.detectPlatform(ua)\n const isMiniProgram = this.isMiniProgramEnv(ua, platform)\n const isWeChat = platform === Platform.WECHAT_MINIPROGRAM\n const isMobile = this.isMobileDevice(ua)\n const capabilities = this.detectCapabilities(isMiniProgram)\n\n this.cache = {\n platform,\n envType: isMiniProgram ? EnvType.MINIPROGRAM : EnvType.BROWSER,\n isMiniProgram,\n isWeChat,\n isMobile,\n userAgent: ua,\n capabilities,\n }\n\n return this.cache\n }\n\n /**\n * 获取 User Agent\n */\n private static getUserAgent(): string {\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return navigator.userAgent\n }\n return ''\n }\n\n /**\n * 检测平台类型\n */\n private static detectPlatform(ua: string): Platform {\n const uaLower = ua.toLowerCase()\n\n // 检测微信小程序\n if (this.checkIsWeChatMiniProgram(uaLower)) {\n return Platform.WECHAT_MINIPROGRAM\n }\n\n // 检测支付宝小程序\n if (uaLower.includes('alipay') && uaLower.includes('miniprogram')) {\n return Platform.ALIPAY_MINIPROGRAM\n }\n\n // 检测百度小程序\n if (uaLower.includes('swan-baiduboxapp')) {\n return Platform.OTHER_MINIPROGRAM\n }\n\n // 检测字节跳动小程序\n if (uaLower.includes('toutiaomicroapp')) {\n return Platform.OTHER_MINIPROGRAM\n }\n\n // 检测 QQ 小程序\n if (uaLower.includes('qqminiapp')) {\n return Platform.OTHER_MINIPROGRAM\n }\n\n // 检测移动端浏览器\n if (this.isMobileDevice(ua)) {\n return Platform.MOBILE_BROWSER\n }\n\n // 检测 PC 浏览器\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n return Platform.PC_BROWSER\n }\n\n return Platform.UNKNOWN\n }\n\n /**\n * 检测微信小程序环境(内部方法)\n */\n private static checkIsWeChatMiniProgram(uaLower: string): boolean {\n // 方法1:检测 __wxjs_environment 变量\n if (typeof globalThis !== 'undefined') {\n const g = globalThis as any\n if (g.__wxjs_environment === 'miniprogram') {\n return true\n }\n }\n\n // 方法2:检测 window.__wxjs_environment\n if (typeof window !== 'undefined') {\n const win = window as any\n if (win.__wxjs_environment === 'miniprogram') {\n return true\n }\n }\n\n // 方法3:检测 User Agent 中的 miniprogram 标识\n if (uaLower.includes('miniprogram')) {\n // 排除其他小程序(支付宝等已经在前面的检测中处理)\n if (uaLower.includes('micromessenger') || uaLower.includes('wechat')) {\n return true\n }\n // 如果只包含 miniprogram 但不包含其他平台标识,也认为是微信\n if (!uaLower.includes('alipay') && !uaLower.includes('baidu') && !uaLower.includes('toutiao')) {\n return true\n }\n }\n\n // 方法4:检测微信特有的 miniprogramwebview 标识\n if (uaLower.includes('miniprogramwebview')) {\n return true\n }\n\n return false\n }\n\n /**\n * 判断是否为小程序环境\n */\n private static isMiniProgramEnv(ua: string, platform: Platform): boolean {\n // 如果已经检测出小程序平台,直接返回 true\n if (\n platform === Platform.WECHAT_MINIPROGRAM ||\n platform === Platform.ALIPAY_MINIPROGRAM ||\n platform === Platform.OTHER_MINIPROGRAM\n ) {\n return true\n }\n\n return false\n }\n\n /**\n * 检测是否为移动设备\n */\n private static isMobileDevice(ua: string): boolean {\n const uaLower = ua.toLowerCase()\n const mobileKeywords = [\n 'android',\n 'webos',\n 'iphone',\n 'ipad',\n 'ipod',\n 'blackberry',\n 'windows phone',\n 'mobile',\n ]\n\n return mobileKeywords.some((keyword) => uaLower.includes(keyword))\n }\n\n /**\n * 检测环境能力\n */\n private static detectCapabilities(isMiniProgram: boolean): EnvCapabilities {\n const capabilities: EnvCapabilities = {\n sharedArrayBuffer: false,\n wasmThreads: false,\n wasmSimd: false,\n webGL: false,\n webGL2: false,\n videoFrame: false,\n offscreenCanvas: false,\n webAudio: false,\n webWorker: false,\n fetch: false,\n webSocket: false,\n readableStream: false,\n }\n\n // 检测 SharedArrayBuffer\n capabilities.sharedArrayBuffer = this.checkSharedArrayBuffer()\n\n // 小程序环境禁用 WASM 线程\n if (isMiniProgram) {\n capabilities.wasmThreads = false\n } else {\n capabilities.wasmThreads = capabilities.sharedArrayBuffer\n }\n\n // 检测 WASM SIMD\n capabilities.wasmSimd = this.checkWasmSimd()\n\n // 检测 WebGL\n capabilities.webGL = this.checkWebGL()\n capabilities.webGL2 = this.checkWebGL2()\n\n // 检测其他 API\n capabilities.videoFrame = typeof VideoFrame !== 'undefined'\n capabilities.offscreenCanvas = typeof OffscreenCanvas !== 'undefined'\n capabilities.webAudio = typeof AudioContext !== 'undefined' ||\n (typeof window !== 'undefined' && 'webkitAudioContext' in window)\n capabilities.webWorker = typeof Worker !== 'undefined'\n capabilities.fetch = typeof fetch !== 'undefined'\n capabilities.webSocket = typeof WebSocket !== 'undefined'\n capabilities.readableStream = typeof ReadableStream !== 'undefined'\n\n return capabilities\n }\n\n /**\n * 检测 SharedArrayBuffer\n */\n private static checkSharedArrayBuffer(): boolean {\n // 方法1:检查 crossOriginIsolated(最可靠)\n // 当页面有正确的 COOP/COEP 头时,window.crossOriginIsolated 为 true\n if (typeof window !== 'undefined' && window.crossOriginIsolated === false) {\n return false\n }\n\n // 方法2:检查 SharedArrayBuffer 是否存在\n if (typeof SharedArrayBuffer === 'undefined') {\n return false\n }\n\n // 方法3:尝试实际创建(某些环境可能定义了但无法使用)\n try {\n new SharedArrayBuffer(1)\n return true\n } catch {\n // 缺少 COOP/COEP 头时会抛出错误\n return false\n }\n }\n\n /**\n * 检测 WASM SIMD 支持\n */\n private static checkWasmSimd(): boolean {\n // 使用一个简单的有效 SIMD WASM 模块进行检测\n // 该模块包含 v128.const 指令,这是 SIMD 的核心指令\n // 编译自:\n // (module\n // (func (export \"test\") (result v128)\n // v128.const i32x4 0 0 0 0\n // )\n // )\n const simdTestBytes = new Uint8Array([\n 0x00, 0x61, 0x73, 0x6d, // magic: \\0asm\n 0x01, 0x00, 0x00, 0x00, // version: 1\n // Type section (1)\n 0x01, 0x05, 0x01, // section id=1, size=5, 1 type\n 0x60, 0x00, 0x01, 0x7b, // func () -> v128\n // Function section (3)\n 0x03, 0x02, 0x01, // section id=3, size=2, 1 func\n 0x00, // function 0 uses type 0\n // Export section (7)\n 0x07, 0x08, 0x01, // section id=7, size=8, 1 export\n 0x04, 0x74, 0x65, 0x73, 0x74, // name: \"test\"\n 0x00, // export kind: function\n 0x00, // function index: 0\n // Code section (10)\n 0x0a, 0x13, 0x01, // section id=10, size=19, 1 func\n 0x11, 0x00, // func body size=17, 0 locals\n // v128.const i32x4 0 0 0 0\n 0xfd, 0x0c, // v128.const\n 0x00, // i32x4 lane format\n 0x00, 0x00, 0x00, 0x00, // lane 0\n 0x00, 0x00, 0x00, 0x00, // lane 1\n 0x00, 0x00, 0x00, 0x00, // lane 2\n 0x00, 0x00, 0x00, 0x00, // lane 3\n 0x0b, // end\n ])\n\n try {\n return WebAssembly.validate(simdTestBytes)\n } catch {\n return false\n }\n }\n\n /**\n * 检测 WebGL 支持\n */\n private static checkWebGL(): boolean {\n if (typeof document === 'undefined') {\n return false\n }\n\n try {\n const canvas = document.createElement('canvas')\n const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')\n return !!gl\n } catch {\n return false\n }\n }\n\n /**\n * 检测 WebGL 2 支持\n */\n private static checkWebGL2(): boolean {\n if (typeof document === 'undefined') {\n return false\n }\n\n try {\n const canvas = document.createElement('canvas')\n const gl = canvas.getContext('webgl2')\n return !!gl\n } catch {\n return false\n }\n }\n\n /**\n * 清除缓存(用于测试)\n */\n static resetCache(): void {\n this.cache = null\n }\n\n /**\n * 快速判断是否为小程序环境\n */\n static isMiniProgram(): boolean {\n return this.detect().isMiniProgram\n }\n\n /**\n * 快速判断是否为微信小程序\n */\n static isWeChatMiniProgram(): boolean {\n return this.detect().isWeChat\n }\n\n /**\n * 快速获取平台类型\n */\n static getPlatform(): Platform {\n return this.detect().platform\n }\n\n /**\n * 快速获取环境能力\n */\n static getCapabilities(): EnvCapabilities {\n return this.detect().capabilities\n }\n\n /**\n * 打印环境信息(调试用)\n */\n static printEnvInfo(): void {\n const env = this.detect()\n console.log('=== 环境检测结果 ===')\n console.log('平台:', env.platform)\n console.log('环境类型:', env.envType)\n console.log('是否小程序:', env.isMiniProgram)\n console.log('是否微信:', env.isWeChat)\n console.log('是否移动端:', env.isMobile)\n console.log('能力检测:', env.capabilities)\n console.log('UA:', env.userAgent)\n console.log('==================')\n }\n}\n","/**\n * 日志级别\n */\nexport enum LogLevel {\n NONE = 0,\n ERROR = 1,\n WARN = 2,\n INFO = 3,\n DEBUG = 4\n}\n\nconst LOG_LEVEL_NAMES: Record<LogLevel, string> = {\n [LogLevel.NONE]: 'NONE',\n [LogLevel.ERROR]: 'ERROR',\n [LogLevel.WARN]: 'WARN',\n [LogLevel.INFO]: 'INFO',\n [LogLevel.DEBUG]: 'DEBUG'\n}\n\n// 当前日志级别\nlet currentLogLevel: LogLevel = LogLevel.INFO\n\n/**\n * 设置全局日志级别\n */\nexport function setLogLevel(level: LogLevel): void {\n currentLogLevel = level\n}\n\n/**\n * 获取当前日志级别\n */\nexport function getLogLevel(): LogLevel {\n return currentLogLevel\n}\n\n/**\n * 创建带模块名的日志器\n */\nexport function createLogger(moduleName: string) {\n const prefix = `[${moduleName}]`\n\n return {\n error: (...args: any[]) => {\n if (currentLogLevel >= LogLevel.ERROR) {\n console.error(prefix, ...args)\n }\n },\n\n warn: (...args: any[]) => {\n if (currentLogLevel >= LogLevel.WARN) {\n console.warn(prefix, ...args)\n }\n },\n\n info: (...args: any[]) => {\n if (currentLogLevel >= LogLevel.INFO) {\n console.log(prefix, ...args)\n }\n },\n\n debug: (...args: any[]) => {\n if (currentLogLevel >= LogLevel.DEBUG) {\n console.log(prefix, ...args)\n }\n },\n\n log: (...args: any[]) => {\n // log 等同于 info\n if (currentLogLevel >= LogLevel.INFO) {\n console.log(prefix, ...args)\n }\n }\n }\n}\n\n// 默认日志器\nexport const logger = createLogger('EcPlayer')\n"],"names":["readUint32","CODEC_ID_AVC","CODEC_ID_HEVC","LogLevel"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NAL 单元解析器
|
|
3
|
+
*/
|
|
4
|
+
import type { NALUnit } from '../types';
|
|
5
|
+
export declare const NAL_TYPES: {
|
|
6
|
+
readonly SLICE: 1;
|
|
7
|
+
readonly IDR: 5;
|
|
8
|
+
readonly SEI: 6;
|
|
9
|
+
readonly SPS: 7;
|
|
10
|
+
readonly PPS: 8;
|
|
11
|
+
readonly AUD: 9;
|
|
12
|
+
};
|
|
13
|
+
export type NALType = typeof NAL_TYPES[keyof typeof NAL_TYPES];
|
|
14
|
+
export declare class NALParser {
|
|
15
|
+
/**
|
|
16
|
+
* 解析 H.264 NAL 单元
|
|
17
|
+
* 支持 3 字节和 4 字节的 start code
|
|
18
|
+
*/
|
|
19
|
+
parse(data: Uint8Array): NALUnit[];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=NALParser.d.ts.map
|