{"version":3,"file":"internal-utils.umd.cjs","sources":["../src/event-tool.ts","../src/worker-timer.ts","../src/stream-utils.ts","../src/log.ts","../src/meta-box.ts","../src/recodemux.ts","../src/index.ts"],"sourcesContent":["type EventKey = string | symbol;\n\ntype EventToolType = Record<EventKey, (...args: any[]) => any>;\n\n/**\n * 事件工具类\n *\n * @example\n * const evtTool = new EventTool<{\n *   timeupdate: (time: number) => void;\n *   paused: () => void;\n *   playing: () => void;\n * }>()\n * evtTool.on('paused', () => {})\n * evtTool.emit('paused')\n */\nexport class EventTool<T extends EventToolType> {\n  /**\n   * 在两个 EventTool 实例间转发消息\n   * @param from\n   * @param to\n   * @param evtTypes 需转发的消息类型\n   *\n   * @example\n   * EventTool.forwardEvent(from, to, ['evtName']),\n   */\n  static forwardEvent<\n    T1 extends EventToolType,\n    T2 extends EventToolType,\n    EvtType extends (keyof T1 | [keyof T1, keyof T2])[],\n  >(\n    from: { on: EventTool<T1>['on'] },\n    to: { emit: EventTool<T2>['emit'] },\n    // 转发的事件名，如果 evtTypes 为序对（元组）表示事件名称需要映射\n    evtTypes: EvtType,\n  ): () => void {\n    const removeHandlers = evtTypes.map((evtType) => {\n      const [fromEvtType, toEvtType] = (\n        Array.isArray(evtType) ? evtType : [evtType, evtType]\n      ) as [keyof T1, keyof T2];\n\n      // @ts-expect-error\n      return from.on(fromEvtType, (...args) => {\n        // @ts-expect-error\n        to.emit(toEvtType, ...args);\n      });\n    });\n    return () => {\n      removeHandlers.forEach((fn) => fn());\n    };\n  }\n\n  #listeners = new Map<keyof T, Set<T[keyof T]>>();\n\n  /**\n   * 监听 EventType 中定义的事件\n   */\n  on = <Type extends keyof T>(type: Type, listener: T[Type]): (() => void) => {\n    const handlers = this.#listeners.get(type) ?? new Set<T[keyof T]>();\n    handlers.add(listener);\n\n    if (!this.#listeners.has(type)) {\n      this.#listeners.set(type, handlers);\n    }\n\n    return () => {\n      handlers.delete(listener);\n      if (handlers.size === 0) {\n        this.#listeners.delete(type);\n      }\n    };\n  };\n\n  /**\n   * 监听事件，首次触发后自动移除监听\n   *\n   * 期望回调一次的事件，使用 once; 期望多次回调使用 on\n   */\n  once = <Type extends keyof T>(\n    type: Type,\n    listener: T[Type],\n  ): (() => void) => {\n    // @ts-ignore\n    const off = this.on(type, (...args) => {\n      off();\n      listener(...args);\n    });\n\n    return off;\n  };\n\n  /**\n   * 触发事件\n   * @param type\n   * @param args\n   * @returns\n   */\n  emit = <Type extends keyof T>(\n    type: Type,\n    ...args: Type extends string\n      ? T[Type] extends (...args: any[]) => any\n        ? Parameters<T[Type]>\n        : never\n      : never\n  ): void => {\n    const handlers = this.#listeners.get(type);\n    if (handlers == null) return;\n\n    handlers.forEach((handler) => handler(...args));\n  };\n\n  destroy(): void {\n    this.#listeners.clear();\n  }\n}\n","const setup = (): void => {\n  let timerId: number;\n\n  let interval: number = 16.6;\n\n  self.onmessage = (e) => {\n    if (e.data.event === 'start') {\n      self.clearInterval(timerId);\n      timerId = self.setInterval(() => {\n        self.postMessage({});\n      }, interval);\n    }\n\n    if (e.data.event === 'stop') {\n      self.clearInterval(timerId);\n    }\n  };\n};\n\nconst createWorker = (): Worker => {\n  const blob = new Blob([`(${setup.toString()})()`]);\n  const url = URL.createObjectURL(blob);\n  return new Worker(url);\n};\n\nconst handlerMap = new Map<number, Set<() => void>>();\nlet runCount = 1;\n\nlet worker: Worker | null = null;\nif (globalThis.Worker != null) {\n  worker = createWorker();\n  worker.onmessage = () => {\n    runCount += 1;\n    for (const [k, v] of handlerMap) {\n      if (runCount % k === 0) for (const fn of v) fn();\n    }\n  };\n}\n\n/**\n * 专门解决页面长时间处于后台时，定时器不（或延迟）执行的问题\n *\n * 跟 `setInterval` 很相似，⚠️ 但 time 会有一定偏差，请优先使用 `setInterval`\n *\n * @see [JS 定时器时长控制细节](https://hughfenghen.github.io/posts/2023/06/15/timer-delay/)\n */\nexport const workerTimer = (\n  handler: () => void,\n  time: number,\n): (() => void) => {\n  const groupId = Math.round(time / 16.6);\n  const fns = handlerMap.get(groupId) ?? new Set();\n  fns.add(handler);\n  handlerMap.set(groupId, fns);\n\n  if (handlerMap.size === 1 && fns.size === 1) {\n    worker?.postMessage({ event: 'start' });\n  }\n\n  return () => {\n    fns.delete(handler);\n    if (fns.size === 0) handlerMap.delete(groupId);\n    if (handlerMap.size === 0) {\n      runCount = 0;\n      worker?.postMessage({ event: 'stop' });\n    }\n  };\n};\n","import mp4box, { MP4File } from '@webav/mp4box.js';\n/**\n * 自动读取流并处理每个数据块。\n *\n * @template ST - 可读流的类型。\n * @param stream - 要读取的流。\n * @param cbs - 回调函数对象。\n * @param cbs.onChunk - 当读取到新的数据块时调用的函数。该函数接收一个参数，即数据块，并返回一个 Promise。\n * @param cbs.onDone - 当读取完所有数据块时调用的函数。\n * @returns - 返回一个函数，调用该函数可以停止读取流。\n *\n * @example\n * const stream = getSomeReadableStream();\n * const onChunk = async (chunk) => {\n *   console.log('New chunk:', chunk);\n * };\n * const onDone = () => {\n *   console.log('Done reading stream');\n * };\n * const stopReading = autoReadStream(stream, { onChunk, onDone });\n * // Later...\n * stopReading();\n */\nexport function autoReadStream<ST extends ReadableStream>(\n  stream: ST,\n  cbs: {\n    onChunk: ST extends ReadableStream<infer DT>\n      ? (chunk: DT) => Promise<void>\n      : never;\n    onDone: () => void;\n  },\n) {\n  let stoped = false;\n  async function run() {\n    const reader = stream.getReader();\n\n    while (!stoped) {\n      const { value, done } = await reader.read();\n      if (done) {\n        cbs.onDone();\n        return;\n      }\n      await cbs.onChunk(value);\n    }\n\n    reader.releaseLock();\n    await stream.cancel();\n  }\n\n  run().catch(console.error);\n\n  return () => {\n    stoped = true;\n  };\n}\n\n/**\n * 将 mp4box file 转换为文件流，用于上传服务器或存储到本地\n * @param file - MP4 文件实例 {@link MP4File}。\n * @param timeSlice - 时间片，用于控制流的发送速度。\n * @param onCancel - 当返回的流被取消时触发该回调函数\n */\nexport function file2stream(\n  file: MP4File,\n  timeSlice: number,\n  onCancel?: () => void,\n): {\n  /**\n   * 可读流，流的数据是 `Uint8Array`\n   */\n  stream: ReadableStream<Uint8Array>;\n  /**\n   * 流的生产者主动停止向流中输出数据，可向消费者传递错误信息\n   */\n  stop: (err?: Error) => void;\n} {\n  let timerId = 0;\n\n  let sendedBoxIdx = 0;\n  const boxes = file.boxes;\n\n  let firstMoofReady = false;\n  const deltaBuf = (): Uint8Array | null => {\n    // 避免 moov 未完成时写入文件，导致文件无法被识别\n    if (!firstMoofReady) {\n      if (boxes.find((box) => box.type === 'moof') != null) {\n        firstMoofReady = true;\n      } else {\n        return null;\n      }\n    }\n    if (sendedBoxIdx >= boxes.length) return null;\n\n    const ds = new mp4box.DataStream();\n    ds.endianness = mp4box.DataStream.BIG_ENDIAN;\n\n    let i = sendedBoxIdx;\n    try {\n      for (; i < boxes.length; ) {\n        boxes[i].write(ds);\n        delete boxes[i];\n        i += 1;\n      }\n    } catch (err) {\n      const errBox = boxes[i];\n      if (err instanceof Error && errBox != null) {\n        throw Error(\n          `${err.message} | deltaBuf( boxType: ${errBox.type}, boxSize: ${errBox.size}, boxDataLen: ${errBox.data?.length ?? -1})`,\n        );\n      }\n      throw err;\n    }\n\n    unsafeReleaseMP4BoxFile(file);\n\n    sendedBoxIdx = boxes.length;\n    return new Uint8Array(ds.buffer);\n  };\n\n  let stoped = false;\n  let canceled = false;\n  let exit: ((err?: Error) => void) | null = null;\n  const stream = new ReadableStream({\n    start(ctrl) {\n      timerId = self.setInterval(() => {\n        const d = deltaBuf();\n        if (d != null && !canceled) ctrl.enqueue(d);\n      }, timeSlice);\n\n      exit = (err) => {\n        clearInterval(timerId);\n        file.flush();\n        if (err != null) {\n          ctrl.error(err);\n          return;\n        }\n\n        const d = deltaBuf();\n        if (d != null && !canceled) ctrl.enqueue(d);\n\n        if (!canceled) ctrl.close();\n      };\n\n      // 安全起见，检测如果start触发时已经 stoped\n      if (stoped) exit();\n    },\n    cancel() {\n      canceled = true;\n      clearInterval(timerId);\n      onCancel?.();\n    },\n  });\n\n  return {\n    stream,\n    stop: (err) => {\n      if (stoped) return;\n      stoped = true;\n      exit?.(err);\n    },\n  };\n}\n\n/**\n * 强行回收 mp4boxfile 尽量降低内存占用，会破坏 file 导致无法正常使用\n * 仅用于获取二进制后，不再需要任何 file 功能的场景\n */\nfunction unsafeReleaseMP4BoxFile(file: MP4File) {\n  if (file.moov == null) return;\n  for (var j = 0; j < file.moov.traks.length; j++) {\n    file.moov.traks[j].samples = [];\n  }\n  file.mdats = [];\n  file.moofs = [];\n}\n","/**\n * 将任意对象转换成String，如果包含Error，则将Error转换为err.toString()\n * @param val any\n */\nfunction any2Str(val: any): string {\n  if (val instanceof Error) return String(val);\n  return typeof val === 'object'\n    ? JSON.stringify(val, (_, v) => (v instanceof Error ? String(v) : v))\n    : String(val);\n}\n\nfunction getTimeStr() {\n  const d = new Date();\n  return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`;\n}\n\nlet THRESHOLD = 1;\n\ntype LvName = 'debug' | 'info' | 'warn' | 'error';\nconst history: Array<{ lvName: string; timeStr: string; args: any[] }> = [];\nconst lvHandler = ['debug', 'info', 'warn', 'error'].reduce(\n  (acc, lvName, lvThres) =>\n    Object.assign(acc, {\n      [lvName]: (...args: any[]) => {\n        if (THRESHOLD <= lvThres) {\n          console[lvName as LvName](...args);\n          history.push({\n            lvName,\n            timeStr: getTimeStr(),\n            args,\n          });\n        }\n      },\n    }),\n  {} as Record<LvName, typeof console.log>,\n);\n\nconst map = new Map<Function, number>();\n\n/**\n * 全局日志对象，将日志内容写入 OPFS 临时文件\n */\nexport const Log = {\n  /**\n   * 设置记录日志的级别\n   *\n   * @example\n   * Log.setLogLevel(Log.warn) // 记录 warn，error 日志\n   */\n  setLogLevel: <T extends Function>(logfn: T) => {\n    THRESHOLD = map.get(logfn) ?? 1;\n  },\n  ...lvHandler,\n  /**\n   * 生成一个 log 实例，所有输出前都会附加 tag\n   *\n   * @example\n   * const log = Log.create('<prefix>')\n   * log.info('xxx') // '<prefix> xxx'\n   */\n  create: (tag: string) => {\n    return Object.fromEntries(\n      Object.entries(lvHandler).map(([k, h]) => [\n        k,\n        (...args: any[]) => h(tag, ...args),\n      ]),\n    );\n  },\n\n  /**\n   * 将所有日志导出为一个字符串\n   *\n   * @example\n   * Log.dump() // => [level][time]  内容...\n   *\n   */\n  async dump() {\n    return history.reduce(\n      (acc, { lvName, timeStr, args }) =>\n        acc +\n        `[${lvName}][${timeStr}]  ${args.map((a) => any2Str(a)).join(' ')}\\n`,\n      '',\n    );\n  },\n};\n\nmap.set(Log.debug, 0);\nmap.set(Log.info, 1);\nmap.set(Log.warn, 2);\nmap.set(Log.error, 3);\n\ndeclare const PKG_VERSION: string;\n\ndeclare class PressureObserver {\n  constructor(\n    callback: (changes: PressureRecord[], observer: PressureObserver) => void,\n  );\n  observe(\n    resource: string,\n    options?: { sampleInterval?: number },\n  ): Promise<void>;\n  unobserve(): void;\n  takeRecords(): PressureRecord[];\n}\n\ninterface PressureRecord {\n  state: 'critical' | 'serious' | 'normal';\n}\n\n(async function init() {\n  await Promise.resolve();\n  if (globalThis.navigator == null || globalThis.document == null) return;\n  Log.info(\n    `@webav version: ${PKG_VERSION}, date: ${new Date().toLocaleDateString()}`,\n  );\n  Log.info(globalThis.navigator.userAgent);\n  document.addEventListener('visibilitychange', () => {\n    Log.info(`visibilitychange: ${document.visibilityState}`);\n  });\n\n  if ('PressureObserver' in globalThis) {\n    let lastStateStr = '';\n    const observer = new PressureObserver((records) => {\n      const stateStr = JSON.stringify(records.map((r) => r.state));\n      if (stateStr !== lastStateStr) {\n        Log.info(`cpu state change: ${stateStr}`);\n        lastStateStr = stateStr;\n      }\n    });\n    observer.observe('cpu');\n  }\n})();\n\nif (import.meta.env?.DEV) {\n  Log.setLogLevel(Log.debug);\n}\n\nif (import.meta.env?.MODE === 'test') {\n  Log.setLogLevel(Log.warn);\n}\n","const createBoxHeader = (type: string, size: number): Uint8Array => {\n  const buffer = new Uint8Array(8);\n  const view = new DataView(buffer.buffer);\n  view.setUint32(0, size); // Write size as a 32-bit unsigned integer\n  for (let i = 0; i < 4; i++) {\n    buffer[4 + i] = type.charCodeAt(i); // Write type as a 4-character string\n  }\n  return buffer;\n};\n\nconst createHdlrBox = (): Uint8Array => {\n  const tec = new TextEncoder();\n  const handlerType = tec.encode('mdta');\n  const nameBytes = tec.encode('mp4 handler');\n  // header8 + ?8 + mdta4 + ?12 + nameSize + endFlag1\n  const size = 8 + 8 + 4 + 12 + nameBytes.byteLength + 1;\n  const buffer = new Uint8Array(size);\n  const view = new DataView(buffer.buffer);\n\n  // Box header\n  buffer.set(createBoxHeader('hdlr', size), 0);\n\n  // Full box header (version and flags)\n  view.setUint32(8, 0);\n\n  buffer.set(handlerType, 16);\n  buffer.set(nameBytes, 32);\n\n  return buffer;\n};\n\nconst createKeysBox = (keys: string[]): Uint8Array => {\n  const tec = new TextEncoder();\n  const keyNamespace = tec.encode('mdta');\n  const keyData = keys.map((key) => {\n    const keyBuf = tec.encode(key);\n    // size4 + namespace4 + keyBuf\n    const size = 4 + 4 + keyBuf.byteLength;\n\n    const entryBuf = new Uint8Array(size);\n    const dv = new DataView(entryBuf.buffer);\n    dv.setUint32(0, size);\n    entryBuf.set(keyNamespace, 4);\n    entryBuf.set(keyBuf, 4 + keyNamespace.byteLength);\n\n    return entryBuf;\n  });\n  const keyDataSize = keyData.reduce((acc, cur) => acc + cur.byteLength, 0);\n\n  const size = 16 + keyDataSize; // 16 bytes for the header and version/flags\n  const buffer = new Uint8Array(size);\n  const view = new DataView(buffer.buffer);\n\n  // Box header\n  buffer.set(createBoxHeader('keys', size), 0);\n\n  // Full box header (version and flags)\n  view.setUint32(8, 0);\n  view.setUint32(12, keys.length); // Entry count\n\n  // Keys\n  let offset = 16;\n  for (const keyBuf of keyData) {\n    buffer.set(keyBuf, offset);\n    offset += keyBuf.byteLength;\n  }\n\n  return buffer;\n};\n\nconst createIlstBox = (data: Record<string, string>): Uint8Array => {\n  const tec = new TextEncoder();\n  const dataStrBuf = tec.encode('data');\n  const valueData = Object.entries(data).map(([_, value], index) => {\n    const keyId = index + 1; // Assuming keys start from 1\n    const valueBytes = tec.encode(value);\n    // size4 + keyId4 + valueSize4 + data4 + idx4 + ?4 + value\n    const entrySize = 4 + 4 + 4 + 4 + 4 + 4 + valueBytes.byteLength;\n\n    const buffer = new Uint8Array(entrySize);\n    const view = new DataView(buffer.buffer);\n    view.setUint32(0, entrySize);\n    view.setUint32(4, keyId);\n\n    view.setUint32(8, 16 + valueBytes.byteLength);\n    buffer.set(dataStrBuf, 12); // 'data' type\n\n    // data idx=1\n    view.setUint32(16, 1);\n    // Value\n    buffer.set(valueBytes, 24);\n\n    return buffer;\n  });\n\n  const valueDataSize = valueData.reduce((acc, cur) => acc + cur.byteLength, 0);\n  const totalSizwe = 8 + valueDataSize;\n  const buffer = new Uint8Array(totalSizwe);\n  buffer.set(createBoxHeader('ilst', totalSizwe), 0);\n\n  let offset = 8;\n  for (const entry of valueData) {\n    buffer.set(entry, offset);\n    offset += entry.byteLength;\n  }\n\n  return buffer;\n};\n\nexport const createMetaBox = (data: Record<string, string>): Uint8Array => {\n  const hdlrBox = createHdlrBox();\n  const keysBox = createKeysBox(Object.keys(data));\n  const ilstBox = createIlstBox(data);\n\n  const size = hdlrBox.length + keysBox.length + ilstBox.length;\n  const buffer = new Uint8Array(size);\n\n  // buffer.set(createBoxHeader('meta', size), 0);\n  buffer.set(hdlrBox, 0);\n  buffer.set(keysBox, hdlrBox.length);\n  buffer.set(ilstBox, hdlrBox.length + keysBox.length);\n\n  return buffer;\n};\n","import mp4box, { MP4File, SampleOpts } from '@webav/mp4box.js';\nimport { EventTool } from './event-tool';\nimport { Log } from './log';\nimport { createMetaBox } from './meta-box';\nimport { workerTimer } from './worker-timer';\n\ntype TCleanFn = () => void;\n\n/**\n * 定义 recodemux 函数的配置选项\n */\ninterface IRecodeMuxOpts {\n  /**\n   * 视频配置选项，如果为 null 则不处理视频。\n   */\n  video: {\n    width: number;\n    height: number;\n    expectFPS: number;\n    codec: string;\n    bitrate: number;\n    /**\n     * 不安全，随时可能废弃\n     */\n    __unsafe_hardwareAcceleration__?: HardwareAcceleration;\n  } | null;\n  /**\n   * 音频配置选项，如果为 null 则不处理音频。\n   */\n  audio: {\n    codec: 'opus' | 'aac';\n    sampleRate: number;\n    channelCount: number;\n  } | null;\n  /**\n   * 预设时长，不代表 track 实际时长\n   */\n  duration?: number;\n  metaDataTags?: Record<string, string>;\n}\n\n/**\n * 处理音视频的编码和解码。\n * @param opts - 编码音视频数据的配置\n */\nexport function recodemux(opts: IRecodeMuxOpts): {\n  /**\n   * 编码视频帧\n   */\n  encodeVideo: (\n    frame: VideoFrame,\n    options: VideoEncoderEncodeOptions,\n    gopId?: number,\n  ) => void;\n  /**\n   * 编码音频数据\n   */\n  encodeAudio: (data: AudioData) => void;\n  /**\n   * close 编码器，停止任务\n   */\n  close: TCleanFn;\n  /**\n   * 清空编码器队列\n   */\n  flush: () => Promise<void>;\n  /**\n   * mp4box 实例\n   */\n  mp4file: MP4File;\n  /**\n   * 返回队列长度（背压），用于控制生产视频的进度，队列过大会会占用大量显存\n   */\n  getEncodeQueueSize: () => number;\n} {\n  Log.info('recodemux opts:', opts);\n  const mp4file = mp4box.createFile();\n\n  // 音视频轨道必须同时创建, 保存在 moov 中\n  const avSyncEvtTool = new EventTool<\n    Record<'VideoReady' | 'AudioReady', () => void>\n  >();\n\n  const addMetadata = (\n    moov: NonNullable<MP4File['moov']>,\n    tags: NonNullable<IRecodeMuxOpts['metaDataTags']>,\n  ) => {\n    const udtaBox = moov.add('udta');\n    const metaBox = udtaBox.add('meta');\n    metaBox.data = createMetaBox(tags);\n    metaBox.size = metaBox.data.byteLength;\n  };\n\n  let moovReady = false;\n  const onMoovReady = () => {\n    if (mp4file.moov == null || moovReady) return;\n    moovReady = true;\n\n    if (opts.metaDataTags != null) addMetadata(mp4file.moov, opts.metaDataTags);\n    if (opts.duration != null) {\n      mp4file.moov.mvhd.duration = opts.duration;\n    }\n  };\n\n  avSyncEvtTool.once('VideoReady', onMoovReady);\n  avSyncEvtTool.once('AudioReady', onMoovReady);\n\n  let vEncoder =\n    opts.video != null\n      ? encodeVideoTrack(opts.video, mp4file, avSyncEvtTool)\n      : null;\n  let aEncoder =\n    opts.audio != null\n      ? encodeAudioTrack(opts.audio, mp4file, avSyncEvtTool)\n      : null;\n  if (opts.video == null) avSyncEvtTool.emit('VideoReady');\n  if (opts.audio == null) avSyncEvtTool.emit('AudioReady');\n\n  return {\n    encodeVideo: (vf, opts) => {\n      vEncoder?.encode(vf, opts);\n      vf.close();\n    },\n    encodeAudio: (ad) => {\n      if (aEncoder == null) return;\n      try {\n        aEncoder.encode(ad);\n        ad.close();\n      } catch (err) {\n        const errMsg = `encode audio chunk error: ${(err as Error).message}, state: ${JSON.stringify(\n          {\n            qSize: aEncoder.encodeQueueSize,\n            state: aEncoder.state,\n          },\n        )}`;\n        Log.error(errMsg);\n        throw Error(errMsg);\n      }\n    },\n    getEncodeQueueSize: () =>\n      vEncoder?.encodeQueueSize ?? aEncoder?.encodeQueueSize ?? 0,\n    flush: async () => {\n      await Promise.all([\n        vEncoder?.flush(),\n        aEncoder?.state === 'configured' ? aEncoder.flush() : null,\n      ]);\n      return;\n    },\n    close: () => {\n      avSyncEvtTool.destroy();\n      vEncoder?.close();\n      if (aEncoder?.state === 'configured') aEncoder.close();\n    },\n    mp4file,\n  };\n}\n\nfunction encodeVideoTrack(\n  opts: NonNullable<IRecodeMuxOpts['video']>,\n  mp4File: MP4File,\n  avSyncEvtTool: EventTool<Record<'VideoReady' | 'AudioReady', () => void>>,\n) {\n  const videoTrackOpts = {\n    // 微秒\n    timescale: 1e6,\n    width: opts.width,\n    height: opts.height,\n    brands: ['isom', 'iso2', 'avc1', 'mp42', 'mp41'],\n    avcDecoderConfigRecord: null as ArrayBuffer | undefined | null,\n    hevcDecoderConfigRecord: null as ArrayBuffer | undefined | null,\n    vpcDecoderConfigRecord: null as ArrayBuffer | undefined | null,\n    type: 'avc1',\n    name: 'Track created with WebAV',\n  };\n\n  let trackId = -1;\n  let audioReady = false;\n  avSyncEvtTool.once('AudioReady', () => {\n    audioReady = true;\n  });\n\n  const samplesCache: Record<\n    'encoder0' | 'encoder1',\n    Array<ReturnType<typeof chunk2MP4SampleOpts>>\n  > = {\n    encoder0: [],\n    encoder1: [],\n  };\n  const outputHandler = (\n    encId: 'encoder0' | 'encoder1',\n    chunk: EncodedVideoChunk,\n    meta?: EncodedVideoChunkMetadata,\n  ) => {\n    if (trackId === -1 && meta != null) {\n      let desc = meta.decoderConfig?.description as ArrayBuffer;\n      if (opts.codec.startsWith('avc1')) {\n        fixChromeConstraintSetFlagsBug(desc);\n      } else if (opts.codec.startsWith('vp09') && meta.decoderConfig) {\n        videoTrackOpts.type = 'vp09';\n        desc = createVP9ConfDesc(meta.decoderConfig);\n      }\n      const decorderConfKey = (\n        [\n          ['avc1', 'avcDecoderConfigRecord'],\n          ['hvc1', 'hevcDecoderConfigRecord'],\n          ['vp09', 'vpcDecoderConfigRecord'],\n        ] as const\n      ).find(([codec]) => opts.codec.startsWith(codec))?.[1];\n      if (decorderConfKey != null && desc != null) {\n        videoTrackOpts[decorderConfKey] = desc;\n      }\n\n      trackId = mp4File.addTrack(videoTrackOpts);\n      avSyncEvtTool.emit('VideoReady');\n      Log.info('VideoEncoder, video track ready, trackId:', trackId);\n    }\n\n    samplesCache[encId].push(chunk2MP4SampleOpts(chunk));\n  };\n\n  let curEncId: 'encoder0' | 'encoder1' = 'encoder1';\n  let lastAddedSampleTime = 0;\n  // 双编码器交替消费，保证帧的顺序\n  // 小于期望帧间隔帧判定为连续的\n  const deltaTime = Math.floor((1000 / opts.expectFPS) * 1e3);\n  function checkCache() {\n    if (!audioReady) return;\n    const nextEncId = curEncId === 'encoder1' ? 'encoder0' : 'encoder1';\n    const curCache = samplesCache[curEncId];\n    const nextCache = samplesCache[nextEncId];\n    // 无数据\n    if (curCache.length === 0 && nextCache.length === 0) return;\n\n    let curFirst = curCache[0];\n    // 当前队列正在进行中（非关键帧 或 时间连续），继续消费\n    if (curFirst != null) {\n      if (!curFirst.is_sync || curFirst.cts - lastAddedSampleTime < deltaTime) {\n        const lastTs = addSampleToFile(curCache);\n        if (lastTs > lastAddedSampleTime) lastAddedSampleTime = lastTs;\n      }\n    }\n\n    const nextFirst = nextCache[0];\n\n    // 另一个队列跟已消费的最后一帧是连续的，则需要切换\n    if (nextFirst?.is_sync && nextFirst.cts - lastAddedSampleTime < deltaTime) {\n      curEncId = nextEncId;\n      // 说明另一个队列有数据，尽快消费\n      checkCache();\n      return;\n    }\n\n    // 如果时间不连续，但两个队列都有数据，且都是关键帧，消费时间较早的队列\n    if (curFirst?.is_sync && nextFirst?.is_sync) {\n      if (curFirst.cts <= nextFirst.cts) {\n        const lastTs = addSampleToFile(curCache);\n        if (lastTs > lastAddedSampleTime) lastAddedSampleTime = lastTs;\n      } else {\n        curEncId = nextEncId;\n        // 说明另一个队列有数据，尽快消费\n        checkCache();\n        return;\n      }\n    }\n  }\n\n  function addSampleToFile(\n    chunks: Array<ReturnType<typeof chunk2MP4SampleOpts>>,\n  ) {\n    let lastTime = -1;\n    let i = 0;\n    for (; i < chunks.length; i++) {\n      const c = chunks[i];\n      // 每次消费到下一个关键帧结束，可能需要切换队列\n      if (i > 0 && c.is_sync) break;\n\n      mp4File.addSample(trackId, c.data, c);\n      lastTime = c.cts + c.duration;\n    }\n    chunks.splice(0, i);\n    return lastTime;\n  }\n\n  const stopTimer = workerTimer(checkCache, 15);\n\n  const encoder0 = createVideoEncoder(opts, (chunk, meta) =>\n    outputHandler('encoder0', chunk, meta),\n  );\n  const encoder1 = createVideoEncoder(opts, (chunk, meta) =>\n    outputHandler('encoder1', chunk, meta),\n  );\n\n  let gopId = 0;\n  return {\n    get encodeQueueSize() {\n      return encoder0.encodeQueueSize + encoder1.encodeQueueSize;\n    },\n    encode: (vf: VideoFrame, opts: VideoEncoderEncodeOptions) => {\n      try {\n        if (opts.keyFrame) gopId += 1;\n        const encoder = gopId % 2 === 0 ? encoder0 : encoder1;\n        encoder.encode(vf, opts);\n      } catch (err) {\n        const errMsg = `encode video frame error: ${(err as Error).message}, state: ${JSON.stringify(\n          {\n            ts: vf.timestamp,\n            keyFrame: opts.keyFrame,\n            duration: vf.duration,\n            gopId,\n          },\n        )}`;\n        Log.error(errMsg);\n        throw Error(errMsg);\n      }\n    },\n    flush: async () => {\n      await Promise.all([\n        encoder0.state === 'configured' ? await encoder0.flush() : null,\n        encoder1.state === 'configured' ? await encoder1.flush() : null,\n      ]);\n      stopTimer();\n      checkCache();\n    },\n    close: () => {\n      if (encoder0.state === 'configured') encoder0.close();\n      if (encoder1.state === 'configured') encoder1.close();\n    },\n  };\n}\n\n// https://github.com/WebAV-Tech/WebAV/issues/203\nfunction fixChromeConstraintSetFlagsBug(desc: ArrayBuffer) {\n  const u8 = new Uint8Array(desc);\n  const constraintSetFlag = u8[2];\n  // 如果 constraint_set_flags 字节二进制 第0位或第1位值为1\n  // 说明取值错误，忽略该字段避免解码异常\n  if (constraintSetFlag.toString(2).slice(-2).includes('1')) {\n    u8[2] = 0;\n  }\n}\n\nfunction createVideoEncoder(\n  videoOpts: NonNullable<IRecodeMuxOpts['video']>,\n  outHandler: EncodedVideoChunkOutputCallback,\n): VideoEncoder {\n  const encoderConf = {\n    codec: videoOpts.codec,\n    framerate: videoOpts.expectFPS,\n    hardwareAcceleration: videoOpts.__unsafe_hardwareAcceleration__,\n    // 码率\n    bitrate: videoOpts.bitrate,\n    width: videoOpts.width,\n    height: videoOpts.height,\n    // H264 不支持背景透明度\n    alpha: 'discard',\n    // macos 自带播放器只支持avc\n    avc: { format: 'avc' },\n    // mp4box.js 无法解析 annexb 的 mimeCodec ，只会显示 avc1\n    // avc: { format: 'annexb' }\n  } as const;\n  const encoder = new VideoEncoder({\n    error: (err) => {\n      const errMsg = `VideoEncoder error: ${err.message}, config: ${JSON.stringify(encoderConf)}, state: ${JSON.stringify(\n        {\n          qSize: encoder.encodeQueueSize,\n          state: encoder.state,\n        },\n      )}`;\n      Log.error(errMsg);\n      throw Error(errMsg);\n    },\n    output: outHandler,\n  });\n\n  encoder.configure(encoderConf);\n  return encoder;\n}\n\nfunction encodeAudioTrack(\n  audioOpts: NonNullable<IRecodeMuxOpts['audio']>,\n  mp4File: MP4File,\n  avSyncEvtTool: EventTool<Record<'VideoReady' | 'AudioReady', () => void>>,\n): AudioEncoder {\n  const audioTrackOpts = {\n    timescale: 1e6,\n    samplerate: audioOpts.sampleRate,\n    channel_count: audioOpts.channelCount,\n    hdlr: 'soun',\n    type: audioOpts.codec === 'aac' ? 'mp4a' : 'Opus',\n    name: 'Track created with WebAV',\n  };\n\n  let trackId = -1;\n  let cache: EncodedAudioChunk[] = [];\n  let videoReady = false;\n  avSyncEvtTool.once('VideoReady', () => {\n    videoReady = true;\n    cache.forEach((c) => {\n      const s = chunk2MP4SampleOpts(c);\n      mp4File.addSample(trackId, s.data, s);\n    });\n    cache = [];\n  });\n\n  const encoderConf = {\n    codec: audioOpts.codec === 'aac' ? 'mp4a.40.2' : 'opus',\n    sampleRate: audioOpts.sampleRate,\n    numberOfChannels: audioOpts.channelCount,\n    bitrate: 128_000,\n  } as const;\n\n  const encoder = new AudioEncoder({\n    error: (err) => {\n      const errMsg = `AudioEncoder error: ${err.message}, config: ${JSON.stringify(\n        encoderConf,\n      )}, state: ${JSON.stringify({\n        qSize: encoder.encodeQueueSize,\n        state: encoder.state,\n      })}`;\n      Log.error(errMsg);\n      throw Error(errMsg);\n    },\n    output: (chunk, meta) => {\n      if (trackId === -1) {\n        // 某些设备不会输出 description\n        const desc = meta?.decoderConfig?.description;\n        trackId = mp4File.addTrack({\n          ...audioTrackOpts,\n          description: desc == null ? undefined : createESDSBox(desc),\n        });\n        avSyncEvtTool.emit('AudioReady');\n        Log.info('AudioEncoder, audio track ready, trackId:', trackId);\n      }\n\n      if (videoReady) {\n        const s = chunk2MP4SampleOpts(chunk);\n        mp4File.addSample(trackId, s.data, s);\n      } else {\n        cache.push(chunk);\n      }\n    },\n  });\n  encoder.configure(encoderConf);\n\n  return encoder;\n}\n\n/**\n * 创建 ESDS 盒子（MPEG-4 Elementary Stream Descriptor）\n * ESDS 盒子用于描述 MPEG-4 的流信息，如编解码器类型、流类型、最大比特率、平均比特率等\n * @param config - 配置信息，可以是 `ArrayBuffer` 或 `ArrayBufferView` 类型\n * @return 返回一个 ESDS box\n */\nfunction createESDSBox(config: ArrayBuffer | ArrayBufferView) {\n  const configlen = config.byteLength;\n  const buf = new Uint8Array([\n    0x00, // version 0\n    0x00,\n    0x00,\n    0x00, // flags\n\n    0x03, // descriptor_type\n    0x17 + configlen, // length\n    0x00,\n    // 0x01, // es_id\n    0x02, // es_id\n    0x00, // stream_priority\n\n    0x04, // descriptor_type\n    0x12 + configlen, // length\n    0x40, // codec : mpeg4_audio\n    0x15, // stream_type\n    0x00,\n    0x00,\n    0x00, // buffer_size\n    0x00,\n    0x00,\n    0x00,\n    0x00, // maxBitrate\n    0x00,\n    0x00,\n    0x00,\n    0x00, // avgBitrate\n\n    0x05, // descriptor_type\n\n    configlen,\n    ...new Uint8Array(config instanceof ArrayBuffer ? config : config.buffer),\n\n    0x06,\n    0x01,\n    0x02,\n  ]);\n\n  const esdsBox = new mp4box.BoxParser.esdsBox(buf.byteLength);\n  esdsBox.hdr_size = 0;\n  esdsBox.parse(new mp4box.DataStream(buf, 0, mp4box.DataStream.BIG_ENDIAN));\n  return esdsBox;\n}\n\n/**\n * EncodedAudioChunk | EncodedVideoChunk 转换为 MP4 addSample 需要的参数\n */\nfunction chunk2MP4SampleOpts(\n  chunk: EncodedAudioChunk | EncodedVideoChunk,\n): SampleOpts & {\n  data: ArrayBuffer;\n} {\n  const buf = new ArrayBuffer(chunk.byteLength);\n  chunk.copyTo(buf);\n  const dts = chunk.timestamp;\n  return {\n    duration: chunk.duration ?? 0,\n    dts,\n    cts: dts,\n    is_sync: chunk.type === 'key',\n    data: buf,\n  };\n}\n\nfunction createVP9ConfDesc(decoderConfig: VideoDecoderConfig): ArrayBuffer {\n  const codec = decoderConfig.codec; // e.g., \"vp09.00.40.08\"\n  const codecParts = codec.split('.');\n\n  // Parse codec string: vp09.profile.level.bitDepth\n  const profile = parseInt(codecParts[1] || '0', 10);\n  const level = parseInt(codecParts[2] || '40', 10);\n  const bitDepth = parseInt(codecParts[3] || '08', 10);\n\n  // Map color space values\n  const colourPrimariesMap: Record<string, number> = {\n    bt709: 1,\n    bt601: 5,\n    bt2020: 9,\n  };\n\n  const transferCharacteristicsMap: Record<string, number> = {\n    bt709: 1,\n    srgb: 13,\n    pq: 16,\n    hlg: 18,\n  };\n\n  const matrixCoefficientsMap: Record<string, number> = {\n    bt709: 1,\n    bt601: 5,\n    bt2020: 9,\n  };\n\n  const colourPrimaries =\n    colourPrimariesMap[decoderConfig.colorSpace?.primaries || 'bt709'] || 1;\n  const transferCharacteristics =\n    transferCharacteristicsMap[decoderConfig.colorSpace?.transfer || 'bt709'] ||\n    1;\n  const matrixCoefficients =\n    matrixCoefficientsMap[decoderConfig.colorSpace?.matrix || 'bt709'] || 1;\n  const videoFullRangeFlag = decoderConfig.colorSpace?.fullRange ? 1 : 0;\n\n  // Default chroma subsampling to 4:2:0 (value 1)\n  const chromaSubsampling = 1;\n\n  const codecIntializationDataSize = 0;\n\n  // Create buffer with minimal size (no initialization data)\n  const buffer = new ArrayBuffer(12);\n  const view = new DataView(buffer);\n\n  let offset = 0;\n  view.setUint32(offset, 1 << 24);\n  offset += 4;\n\n  // Profile (8 bits)\n  view.setUint8(offset++, profile);\n\n  // Level (8 bits)\n  view.setUint8(offset++, level);\n\n  // Bit depth (4 bits) + Chroma subsampling (3 bits) + Video full range flag (1 bit)\n  view.setUint8(\n    offset++,\n    (bitDepth << 4) | (chromaSubsampling << 1) | videoFullRangeFlag,\n  );\n\n  // Colour primaries (8 bits)\n  view.setUint8(offset++, colourPrimaries);\n\n  // Transfer characteristics (8 bits)\n  view.setUint8(offset++, transferCharacteristics);\n\n  // Matrix coefficients (8 bits)\n  view.setUint8(offset++, matrixCoefficients);\n\n  // Codec initialization data size (16 bits) - set to 0 for no init data\n  view.setUint16(offset, codecIntializationDataSize);\n\n  return buffer;\n}\n","export { EventTool } from './event-tool';\nexport { workerTimer } from './worker-timer';\nexport { autoReadStream, file2stream } from './stream-utils';\nexport { recodemux } from './recodemux';\nexport { Log } from './log';\n\n/**\n * 函数节流\n */\nexport function throttle<F extends (...args: any[]) => any>(\n  func: F,\n  wait: number,\n): (...rest: Parameters<F>) => undefined | ReturnType<F> {\n  let lastTime: number;\n  return function (this: any, ...rest) {\n    if (lastTime == null || performance.now() - lastTime > wait) {\n      lastTime = performance.now();\n      return func.apply(this, rest);\n    }\n  };\n}\n\n/**\n * 函数防抖\n * 在指定时间内多次调用，只执行最后一次\n */\nexport function debounce<F extends (...args: any[]) => any>(\n  func: F,\n  wait: number,\n): (...rest: Parameters<F>) => void {\n  let timer = 0;\n\n  return function (this: any, ...args: Parameters<F>): void {\n    // 清除之前的定时器\n    if (timer !== 0) clearTimeout(timer);\n\n    // 设置新的定时器\n    timer = setTimeout(() => {\n      func.apply(this, args);\n    }, wait) as unknown as number;\n  };\n}\n"],"names":["EventTool","from","to","evtTypes","removeHandlers","evtType","fromEvtType","toEvtType","args","fn","#listeners","type","listener","handlers","off","handler","setup","timerId","interval","e","createWorker","blob","url","handlerMap","runCount","worker","k","v","workerTimer","time","groupId","fns","autoReadStream","stream","cbs","stoped","run","reader","value","done","file2stream","file","timeSlice","onCancel","sendedBoxIdx","boxes","firstMoofReady","deltaBuf","box","ds","mp4box","i","err","errBox","unsafeReleaseMP4BoxFile","canceled","exit","ctrl","d","j","any2Str","val","_","getTimeStr","THRESHOLD","history","lvHandler","acc","lvName","lvThres","map","Log","logfn","tag","h","timeStr","a","lastStateStr","records","stateStr","r","createBoxHeader","size","buffer","createHdlrBox","tec","handlerType","nameBytes","view","createKeysBox","keys","keyNamespace","keyData","key","keyBuf","entryBuf","cur","offset","createIlstBox","data","dataStrBuf","valueData","index","keyId","valueBytes","entrySize","totalSizwe","entry","createMetaBox","hdlrBox","keysBox","ilstBox","recodemux","opts","mp4file","avSyncEvtTool","addMetadata","moov","tags","metaBox","moovReady","onMoovReady","vEncoder","encodeVideoTrack","aEncoder","encodeAudioTrack","vf","ad","errMsg","mp4File","videoTrackOpts","trackId","audioReady","samplesCache","outputHandler","encId","chunk","meta","desc","fixChromeConstraintSetFlagsBug","createVP9ConfDesc","decorderConfKey","codec","chunk2MP4SampleOpts","curEncId","lastAddedSampleTime","deltaTime","checkCache","nextEncId","curCache","nextCache","curFirst","lastTs","addSampleToFile","nextFirst","chunks","lastTime","c","stopTimer","encoder0","createVideoEncoder","encoder1","gopId","u8","videoOpts","outHandler","encoderConf","encoder","audioOpts","audioTrackOpts","cache","videoReady","s","createESDSBox","config","configlen","buf","esdsBox","dts","decoderConfig","codecParts","profile","level","bitDepth","colourPrimariesMap","transferCharacteristicsMap","matrixCoefficientsMap","colourPrimaries","transferCharacteristics","matrixCoefficients","videoFullRangeFlag","chromaSubsampling","codecIntializationDataSize","throttle","func","wait","rest","debounce","timer"],"mappings":"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"}