{"version":3,"file":"av-cliper.umd.cjs","sources":["../src/dom-utils.ts","../src/av-utils.ts","../src/clips/iclip.ts","../src/mp4-utils/mp4box-utils.ts","../src/clips/mp4-clip.ts","../src/clips/img-clip.ts","../src/clips/audio-clip.ts","../src/clips/media-stream-clip.ts","../src/clips/embed-subtitles-clip.ts","../src/mp4-utils/sample-transform.ts","../src/mp4-utils/index.ts","../src/chromakey.ts","../src/sprite/rect.ts","../src/sprite/base-sprite.ts","../src/sprite/offscreen-sprite.ts","../src/sprite/visible-sprite.ts","../src/combinator.ts"],"sourcesContent":["// 在主线程中执行的 工具函数\n\n/**\n * 创建一个新的 HTML 元素\n * @param tagName - 要创建的元素的标签名\n * @returns 新创建的 HTML 元素\n */\nexport function createEl(tagName: string): HTMLElement {\n  return document.createElement(tagName);\n}\n\n/**\n * 将文本渲染为图片\n * @param txt - 要渲染的文本\n * @param cssText - 应用于文本的 CSS 样式\n * @returns 渲染后的图片元素\n */\nexport function renderTxt2Img(txt: string, cssText: string): HTMLImageElement {\n  const div = createEl('pre');\n  div.style.cssText = `margin: 0; ${cssText}; visibility: hidden; position: fixed;`;\n  div.textContent = txt;\n  document.body.appendChild(div);\n\n  const { width, height } = div.getBoundingClientRect();\n  // 计算出 rect，立即从dom移除\n  div.remove();\n  div.style.visibility = 'visible';\n\n  const img = new Image();\n  img.width = width;\n  img.height = height;\n  const svgStr = `\n    <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\">\n    <foreignObject width=\"100%\" height=\"100%\">\n        <div xmlns=\"http://www.w3.org/1999/xhtml\">${div.outerHTML}</div>\n    </foreignObject>\n    </svg>\n  `\n    .replace(/\\t/g, '')\n    .replace(/#/g, '%23');\n\n  img.src = `data:image/svg+xml;charset=utf-8,${svgStr}`;\n  return img;\n}\n\n/**\n * 将文本渲染为 {@link ImageBitmap}，用来创建 {@link ImgClip}\n * @param txt - 要渲染的文本\n * @param cssText - 应用于文本的 CSS 样式\n *\n * @example\n * new ImgClip(\n *   await renderTxt2ImgBitmap(\n *     '水印',\n *    `font-size:40px; color: white; text-shadow: 2px 2px 6px red;`,\n *   )\n * )\n */\nexport async function renderTxt2ImgBitmap(\n  txt: string,\n  cssText: string,\n): Promise<ImageBitmap> {\n  const imgEl = renderTxt2Img(txt, cssText);\n  await new Promise((resolve) => {\n    imgEl.onload = resolve;\n  });\n  const cvs = new OffscreenCanvas(imgEl.width, imgEl.height);\n  const ctx = cvs.getContext('2d');\n  ctx?.drawImage(imgEl, 0, 0, imgEl.width, imgEl.height);\n  return await createImageBitmap(cvs);\n}\n","// 能同时在 worker 和主线程中运行的工具函数\n\nimport { workerTimer } from '@webav/internal-utils';\nimport * as waveResampler from 'wave-resampler';\n\n/**\n * 合并（串联）多个 Float32Array，通常用于合并 PCM 数据\n */\nexport function concatFloat32Array(bufs: Float32Array[]): Float32Array {\n  const rs = new Float32Array(\n    bufs.map((buf) => buf.length).reduce((a, b) => a + b),\n  );\n\n  let offset = 0;\n  for (const buf of bufs) {\n    rs.set(buf, offset);\n    offset += buf.length;\n  }\n\n  return rs;\n}\n\n/**\n * 将小片段的 PCM 合并成一个大片段\n * @param fragments 小片段 PCM，子元素是不同声道的原始 PCM 数据\n */\nexport function concatPCMFragments(\n  fragments: Float32Array[][],\n): Float32Array[] {\n  // fragments: [[chan0, chan1], [chan0, chan1]...]\n  // chanListPCM: [[chan0, chan0...], [chan1, chan1...]]\n  const chanListPCM: Float32Array[][] = [];\n  for (let i = 0; i < fragments.length; i += 1) {\n    for (let j = 0; j < fragments[i].length; j += 1) {\n      if (chanListPCM[j] == null) chanListPCM[j] = [];\n      chanListPCM[j].push(fragments[i][j]);\n    }\n  }\n  // [bigChan0, bigChan1]\n  return chanListPCM.map(concatFloat32Array);\n}\n\n/**\n * 从 AudioData 中提取 PCM 数据的工具函数\n */\nexport function extractPCM4AudioData(ad: AudioData): Float32Array[] {\n  if (ad.format === 'f32-planar') {\n    const rs = [];\n    for (let idx = 0; idx < ad.numberOfChannels; idx += 1) {\n      const chanBufSize = ad.allocationSize({ planeIndex: idx });\n      const chanBuf = new ArrayBuffer(chanBufSize);\n      ad.copyTo(chanBuf, { planeIndex: idx });\n      rs.push(new Float32Array(chanBuf));\n    }\n    return rs;\n  } else if (ad.format === 'f32') {\n    const buf = new ArrayBuffer(ad.allocationSize({ planeIndex: 0 }));\n    ad.copyTo(buf, { planeIndex: 0 });\n    return convertF32ToPlanar(new Float32Array(buf), ad.numberOfChannels);\n  } else if (ad.format === 's16') {\n    const buf = new ArrayBuffer(ad.allocationSize({ planeIndex: 0 }));\n    ad.copyTo(buf, { planeIndex: 0 });\n    return convertS16ToF32Planar(new Int16Array(buf), ad.numberOfChannels);\n  }\n  throw Error('Unsupported audio data format');\n}\n\n/**\n * Convert s16 PCM to f32-planar\n * @param  pcmS16Data - The s16 PCM data.\n * @param  numChannels - Number of audio channels.\n * @returns An array of Float32Array, each containing the audio data for one channel.\n */\nfunction convertS16ToF32Planar(pcmS16Data: Int16Array, numChannels: number) {\n  const numSamples = pcmS16Data.length / numChannels;\n  const planarData = Array.from(\n    { length: numChannels },\n    () => new Float32Array(numSamples),\n  );\n\n  for (let i = 0; i < numSamples; i++) {\n    for (let channel = 0; channel < numChannels; channel++) {\n      const sample = pcmS16Data[i * numChannels + channel];\n      planarData[channel][i] = sample / 32768; // Normalize to range [-1.0, 1.0]\n    }\n  }\n\n  return planarData;\n}\n\nfunction convertF32ToPlanar(pcmF32Data: Float32Array, numChannels: number) {\n  const numSamples = pcmF32Data.length / numChannels;\n  const planarData = Array.from(\n    { length: numChannels },\n    () => new Float32Array(numSamples),\n  );\n\n  for (let i = 0; i < numSamples; i++) {\n    for (let channel = 0; channel < numChannels; channel++) {\n      planarData[channel][i] = pcmF32Data[i * numChannels + channel];\n    }\n  }\n\n  return planarData;\n}\n\n/**\n * 从 AudioBuffer 中提取 PCM\n */\nexport function extractPCM4AudioBuffer(ab: AudioBuffer): Float32Array[] {\n  return Array(ab.numberOfChannels)\n    .fill(0)\n    .map((_, idx) => {\n      return ab.getChannelData(idx);\n    });\n}\n\n/**\n * 调整音频数据的音量\n * @param ad - 要调整的音频对象\n * @param volume - 音量调整系数（0.0 - 1.0）\n * @returns 调整音量后的新音频数据\n */\nexport function adjustAudioDataVolume(ad: AudioData, volume: number) {\n  const data = new Float32Array(\n    concatFloat32Array(extractPCM4AudioData(ad)),\n  ).map((v) => v * volume);\n  const newAd = new AudioData({\n    sampleRate: ad.sampleRate,\n    numberOfChannels: ad.numberOfChannels,\n    timestamp: ad.timestamp,\n    format: ad.format,\n    numberOfFrames: ad.numberOfFrames,\n    data,\n  });\n  ad.close();\n  return newAd;\n}\n\n/**\n * 解码图像流，返回一个视频帧数组。\n *\n * @param stream - 包含图像数据的可读流。\n * @param type - 图像的 MIME 类型，例如 'image/jpeg'。\n *\n * @returns 返回一个 Promise，该 Promise 在解码完成后解析为 {@link VideoFrame} 数组。\n *\n * @see [解码动图](https://webav-tech.github.io/WebAV/demo/1_3-decode-image)\n *\n * @example\n *\n * const frames = await decodeImg(\n *   (await fetch('<gif url>')).body!,\n *   `image/gif`,\n * );\n */\nexport async function decodeImg(\n  stream: ReadableStream<Uint8Array>,\n  type: string,\n): Promise<VideoFrame[]> {\n  const init = {\n    type,\n    data: stream,\n  };\n  const imageDecoder = new ImageDecoder(init);\n\n  await Promise.all([imageDecoder.completed, imageDecoder.tracks.ready]);\n\n  let frameCnt = imageDecoder.tracks.selectedTrack?.frameCount ?? 1;\n\n  const rs: VideoFrame[] = [];\n  for (let i = 0; i < frameCnt; i += 1) {\n    rs.push((await imageDecoder.decode({ frameIndex: i })).image);\n  }\n  return rs;\n}\n\n/**\n * 混合双通道音轨的 PCM 数据，并将多声道并排成一个 Float32Array 输出\n * @param audios - 一个二维数组，每个元素是一个 Float32Array 数组，代表一个音频流的 PCM 数据。\n * 每个 Float32Array 数组的第一个元素是左声道数据，第二个元素（如果有）是右声道数据。\n * 如果只有左声道数据，则右声道将复用左声道数据。\n *\n * @returns 返回一个 Float32Array，返回结果是将这个一个音轨的左右声道并排成 Float32Array。\n *\n * @example\n *\n * const audios = [\n *   [new Float32Array([0.1, 0.2, 0.3]), new Float32Array([0.4, 0.5, 0.6])],\n *   [new Float32Array([0.7, 0.8, 0.9])],\n * ];\n * const mixed = mixinPCM(audios);\n */\nexport function mixinPCM(audios: Float32Array[][]): Float32Array {\n  const maxLen = Math.max(...audios.map((a) => a[0]?.length ?? 0));\n  const data = new Float32Array(maxLen * 2);\n\n  for (let bufIdx = 0; bufIdx < maxLen; bufIdx++) {\n    let chan0 = 0;\n    let chan1 = 0;\n    for (let trackIdx = 0; trackIdx < audios.length; trackIdx++) {\n      const _c0 = audios[trackIdx][0]?.[bufIdx] ?? 0;\n      // 如果是单声道 PCM，第二声道复用第一声道数据\n      const _c1 = audios[trackIdx][1]?.[bufIdx] ?? _c0;\n      chan0 += _c0;\n      chan1 += _c1;\n    }\n    data[bufIdx] = chan0;\n    data[bufIdx + maxLen] = chan1;\n  }\n\n  return data;\n}\n\n/**\n * 对 PCM 音频数据进行重采样。\n *\n * @param pcmData - 一个 Float32Array 数组，每个元素代表一个声道的 PCM 数据。\n * @param curRate - 当前的采样率。\n * @param target - 目标参数对象。\n * @param target.rate - 目标采样率。\n * @param target.chanCount - 目标声道数。\n *\n * @returns 返回一个 Promise，该 Promise 在重采样完成后解析为一个 Float32Array 数组，每个元素代表一个声道的 PCM 数据。\n *\n * @example\n *\n * const pcmData = [new Float32Array([0.1, 0.2, 0.3]), new Float32Array([0.4, 0.5, 0.6])];\n * const curRate = 44100;\n * const target = { rate: 48000, chanCount: 2 };\n * const resampled = await audioResample(pcmData, curRate, target);\n */\nexport async function audioResample(\n  pcmData: Float32Array[],\n  curRate: number,\n  target: {\n    rate: number;\n    chanCount: number;\n  },\n): Promise<Float32Array[]> {\n  const chanCnt = pcmData.length;\n  const emptyPCM = Array(target.chanCount)\n    .fill(0)\n    .map(() => new Float32Array(0));\n  if (chanCnt === 0) return emptyPCM;\n\n  const len = Math.max(...pcmData.map((c) => c.length));\n  if (len === 0) return emptyPCM;\n\n  // The Worker scope does not have access to OfflineAudioContext\n  if (globalThis.OfflineAudioContext == null) {\n    return pcmData.map(\n      (p) =>\n        new Float32Array(\n          waveResampler.resample(p, curRate, target.rate, {\n            method: 'sinc',\n            LPF: false,\n          }),\n        ),\n    );\n  }\n\n  const ctx = new globalThis.OfflineAudioContext(\n    target.chanCount,\n    (len * target.rate) / curRate,\n    target.rate,\n  );\n  const abSource = ctx.createBufferSource();\n  const ab = ctx.createBuffer(chanCnt, len, curRate);\n  pcmData.forEach((d, idx) => ab.copyToChannel(d, idx));\n\n  abSource.buffer = ab;\n  abSource.connect(ctx.destination);\n  abSource.start();\n\n  return extractPCM4AudioBuffer(await ctx.startRendering());\n}\n\n/**\n * 使当前执行环境暂停一段时间。\n * @param time - 暂停的时间，单位为毫秒。\n * @example\n * await sleep(1000);  // 暂停 1 秒\n */\nexport function sleep(time: number): Promise<void> {\n  return new Promise((resolve) => {\n    const stop = workerTimer(() => {\n      stop();\n      resolve();\n    }, time);\n  });\n}\n\n/**\n * 从给定的 Float32Array 中提取一个环形切片，超出边界从 0 开始循环\n *\n * 主要用于截取 PCM 实现循环播放\n *\n * @param data - 输入的 Float32Array。\n * @param start - 切片的开始索引。\n * @param end - 切片的结束索引。\n * @returns - 返回一个新的 Float32Array，包含从 start 到 end 的数据。\n *\n * @example\n * const data = new Float32Array([0, 1, 2, 3, 4, 5]);\n * ringSliceFloat32Array(data, 4, 6); // => Float32Array [4, 5, 0]\n */\nexport function ringSliceFloat32Array(\n  data: Float32Array,\n  start: number,\n  end: number,\n): Float32Array {\n  const cnt = end - start;\n  const rs = new Float32Array(cnt);\n  let i = 0;\n  while (i < cnt) {\n    rs[i] = data[(start + i) % data.length];\n    i += 1;\n  }\n  return rs;\n}\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 * 改变 PCM 数据的播放速率，1 表示正常播放，0.5 表示播放速率减半，2 表示播放速率加倍\n */\nexport function changePCMPlaybackRate(\n  pcmData: Float32Array,\n  playbackRate: number,\n) {\n  // 计算新的采样率\n  const newLength = Math.floor(pcmData.length / playbackRate);\n  const newPcmData = new Float32Array(newLength);\n\n  // 线性插值\n  for (let i = 0; i < newLength; i++) {\n    // 原始数据中的位置\n    const originalIndex = i * playbackRate;\n    const intIndex = Math.floor(originalIndex);\n    const frac = originalIndex - intIndex;\n\n    // 边界检查\n    if (intIndex + 1 < pcmData.length) {\n      newPcmData[i] =\n        pcmData[intIndex] * (1 - frac) + pcmData[intIndex + 1] * frac;\n    } else {\n      newPcmData[i] = pcmData[intIndex]; // 最后一个样本\n    }\n  }\n\n  return newPcmData;\n}\n","interface IClipMeta {\n  width: number;\n  height: number;\n  duration: number;\n}\n\n/**\n * 所有素材需要实现的接口\n *\n * 素材（Clip）是不同数据类型的抽象，给其他模块提供数据\n *\n * WebAV 内置了 {@link MP4Clip}, {@link AudioClip}, {@link ImgClip}, {@link MediaStreamClip} 等常用素材，用于给 {@link Combinator} {@link AVCanvas} 提供数据\n *\n * 你只需实现该接口即可自定义素材，拥有最大的灵活度来生成视频内容，比如动画、转场效果等\n * @see [自定义素材](https://webav-tech.github.io/WebAV/demo/2_6-custom-clip)\n *\n */\nexport interface IClip {\n  /**\n   * 从素材中提取指定时间数据\n   * @param time 时间，单位 微秒\n   */\n  tick: (time: number) => Promise<{\n    video?: VideoFrame | ImageBitmap | null;\n    audio?: Float32Array[];\n    state: 'done' | 'success';\n  }>;\n\n  /**\n   * 当素材准备完成，ready 会切换到 resolved 状态\n   */\n  readonly ready: Promise<IClipMeta>;\n\n  /**\n   * 数据元数据\n   */\n  readonly meta: IClipMeta;\n\n  /**\n   * clone，返回一个新素材\n   */\n  clone: () => Promise<this>;\n\n  /**\n   * 按指定时间切割，返回该时刻前后两个新素材，常用于剪辑场景按时间分割素材\n   *\n   * 该方法不会破坏原素材的数据\n   *\n   * @param time 时间，微秒\n   * @returns\n   */\n  split?: (time: number) => Promise<[this, this]>;\n\n  /**\n   * 销毁实例，释放资源\n   */\n  destroy: () => void;\n}\n\n/**\n * 默认的音频设置，⚠️ 不要变更它的值 ⚠️\n */\nexport const DEFAULT_AUDIO_CONF = {\n  sampleRate: 48000,\n  channelCount: 2,\n  codec: 'mp4a.40.2',\n} as const;\n","import mp4box, {\n  AudioTrackOpts,\n  ESDSBoxParser,\n  MP4ABoxParser,\n  MP4ArrayBuffer,\n  MP4File,\n  MP4Info,\n  MP4Sample,\n  TrakBoxParser,\n  VideoTrackOpts,\n} from '@webav/mp4box.js';\nimport { DEFAULT_AUDIO_CONF } from '../clips';\nimport { file } from 'opfs-tools';\n\nexport function extractFileConfig(file: MP4File, info: MP4Info) {\n  const vTrack = info.videoTracks[0];\n  const rs: {\n    videoTrackConf?: VideoTrackOpts;\n    videoDecoderConf?: Parameters<VideoDecoder['configure']>[0];\n    audioTrackConf?: AudioTrackOpts;\n    audioDecoderConf?: Parameters<AudioDecoder['configure']>[0];\n  } = {};\n  if (vTrack != null) {\n    const videoDesc = parseVideoCodecDesc(file.getTrackById(vTrack.id)).buffer;\n    const { descKey, type } = vTrack.codec.startsWith('avc1')\n      ? { descKey: 'avcDecoderConfigRecord', type: 'avc1' }\n      : vTrack.codec.startsWith('hvc1')\n        ? { descKey: 'hevcDecoderConfigRecord', type: 'hvc1' }\n        : { descKey: '', type: '' };\n    if (descKey !== '') {\n      rs.videoTrackConf = {\n        timescale: vTrack.timescale,\n        duration: vTrack.duration,\n        width: vTrack.video.width,\n        height: vTrack.video.height,\n        brands: info.brands,\n        type,\n        [descKey]: videoDesc,\n      };\n    }\n\n    rs.videoDecoderConf = {\n      codec: vTrack.codec,\n      codedHeight: vTrack.video.height,\n      codedWidth: vTrack.video.width,\n      description: videoDesc,\n    };\n  }\n\n  const aTrack = info.audioTracks[0];\n  if (aTrack != null) {\n    const esdsBox = getESDSBoxFromMP4File(file);\n    rs.audioTrackConf = {\n      timescale: aTrack.timescale,\n      samplerate: aTrack.audio.sample_rate,\n      channel_count: aTrack.audio.channel_count,\n      hdlr: 'soun',\n      type: aTrack.codec.startsWith('mp4a') ? 'mp4a' : aTrack.codec,\n      description: getESDSBoxFromMP4File(file),\n    };\n    rs.audioDecoderConf = {\n      codec: aTrack.codec.startsWith('mp4a')\n        ? DEFAULT_AUDIO_CONF.codec\n        : aTrack.codec,\n      numberOfChannels: aTrack.audio.channel_count,\n      sampleRate: aTrack.audio.sample_rate,\n      ...(esdsBox == null ? {} : parseAudioInfo4ESDSBox(esdsBox)),\n    };\n  }\n  return rs;\n}\n\n// track is H.264, H.265 or VPX.\nfunction parseVideoCodecDesc(track: TrakBoxParser): Uint8Array {\n  for (const entry of track.mdia.minf.stbl.stsd.entries) {\n    // @ts-expect-error\n    const box = entry.avcC ?? entry.hvcC ?? entry.av1C ?? entry.vpcC;\n    if (box != null) {\n      const stream = new mp4box.DataStream(\n        undefined,\n        0,\n        mp4box.DataStream.BIG_ENDIAN,\n      );\n      box.write(stream);\n      return new Uint8Array(stream.buffer.slice(8)); // Remove the box header.\n    }\n  }\n  throw Error('avcC, hvcC, av1C or VPX not found');\n}\n\nfunction getESDSBoxFromMP4File(file: MP4File, codec = 'mp4a') {\n  const mp4aBox = file.moov?.traks\n    .map((t) => t.mdia.minf.stbl.stsd.entries)\n    .flat()\n    .find(({ type }) => type === codec) as MP4ABoxParser;\n\n  return mp4aBox?.esds;\n}\n\n// 解决封装层音频信息标识错误，导致解码异常\nfunction parseAudioInfo4ESDSBox(esds: ESDSBoxParser) {\n  const decoderConf = esds.esd.descs[0]?.descs[0];\n  if (decoderConf == null) return {};\n\n  const [byte1, byte2] = decoderConf.data;\n  // sampleRate 是第一字节后 3bit + 第二字节前 1bit\n  const sampleRateIdx = ((byte1 & 0x07) << 1) + (byte2 >> 7);\n  // numberOfChannels 是第二字节 [2, 5] 4bit\n  const numberOfChannels = (byte2 & 0x7f) >> 3;\n  const sampleRateEnum = [\n    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025,\n    8000, 7350,\n  ] as const;\n  return {\n    sampleRate: sampleRateEnum[sampleRateIdx],\n    numberOfChannels,\n  };\n}\n\n/**\n * 快速解析 mp4 文件，如果是非 fMP4 格式，会优先解析 moov box（略过 mdat）避免占用过多内存\n */\nexport async function quickParseMP4File(\n  reader: Awaited<ReturnType<ReturnType<typeof file>['createReader']>>,\n  onReady: (data: { mp4boxFile: MP4File; info: MP4Info }) => void,\n  onSamples: (\n    id: number,\n    sampleType: 'video' | 'audio',\n    samples: MP4Sample[],\n  ) => void,\n) {\n  const mp4boxFile = mp4box.createFile(false);\n  mp4boxFile.onReady = (info) => {\n    onReady({ mp4boxFile, info });\n    const vTrackId = info.videoTracks[0]?.id;\n    if (vTrackId != null)\n      mp4boxFile.setExtractionOptions(vTrackId, 'video', { nbSamples: 100 });\n\n    const aTrackId = info.audioTracks[0]?.id;\n    if (aTrackId != null)\n      mp4boxFile.setExtractionOptions(aTrackId, 'audio', { nbSamples: 100 });\n\n    mp4boxFile.start();\n  };\n  mp4boxFile.onSamples = onSamples;\n\n  await parse();\n\n  async function parse() {\n    let cursor = 0;\n    const maxReadSize = 30 * 1024 * 1024;\n    while (true) {\n      const data = (await reader.read(maxReadSize, {\n        at: cursor,\n      })) as MP4ArrayBuffer;\n      if (data.byteLength === 0) break;\n      data.fileStart = cursor;\n      const nextPos = mp4boxFile.appendBuffer(data);\n      if (nextPos == null) break;\n      cursor = nextPos;\n    }\n\n    mp4boxFile.stop();\n  }\n}\n","import { MP4Info, MP4Sample } from '@webav/mp4box.js';\nimport { audioResample, extractPCM4AudioData, sleep } from '../av-utils';\nimport { Log } from '@webav/internal-utils';\nimport {\n  extractFileConfig,\n  quickParseMP4File,\n} from '../mp4-utils/mp4box-utils';\nimport { DEFAULT_AUDIO_CONF, IClip } from './iclip';\nimport { file, tmpfile, write } from 'opfs-tools';\n\nlet CLIP_ID = 0;\n\ntype OPFSToolFile = ReturnType<typeof file>;\nfunction isOTFile(obj: any): obj is OPFSToolFile {\n  return obj.kind === 'file' && obj.createReader instanceof Function;\n}\n\n// 用于内部创建 MP4Clip 实例\ntype MPClipCloneArgs = Awaited<ReturnType<typeof mp4FileToSamples>> & {\n  localFile: OPFSToolFile;\n};\n\ninterface MP4DecoderConf {\n  video: VideoDecoderConfig | null;\n  audio: AudioDecoderConfig | null;\n}\n\ninterface MP4ClipOpts {\n  audio?: boolean | { volume: number };\n  /**\n   * 不安全，随时可能废弃\n   */\n  __unsafe_hardwareAcceleration__?: HardwarePreference;\n}\n\ntype ExtMP4Sample = Omit<MP4Sample, 'data'> & {\n  is_idr: boolean;\n  deleted?: boolean;\n  data: null | Uint8Array;\n};\n\ntype LocalFileReader = Awaited<ReturnType<OPFSToolFile['createReader']>>;\n\ntype ThumbnailOpts = {\n  start: number;\n  end: number;\n  step: number;\n};\n\n/**\n * MP4 素材，解析 MP4 文件，使用 {@link MP4Clip.tick} 按需解码指定时间的图像帧\n *\n * 可用于实现视频抽帧、生成缩略图、视频编辑等功能\n *\n * @example\n * new MP4Clip((await fetch('<mp4 url>')).body)\n * new MP4Clip(mp4File.stream())\n *\n * @see {@link Combinator}\n * @see [AVCanvas](../../av-canvas/classes/AVCanvas.html)\n *\n * @see [解码播放视频](https://webav-tech.github.io/WebAV/demo/1_1-decode-video)\n */\nexport class MP4Clip implements IClip {\n  #insId = CLIP_ID++;\n\n  #log = Log.create(`MP4Clip id:${this.#insId},`);\n\n  ready: IClip['ready'];\n\n  #destroyed = false;\n\n  #meta = {\n    // 微秒\n    duration: 0,\n    width: 0,\n    height: 0,\n    audioSampleRate: 0,\n    audioChanCount: 0,\n  };\n\n  get meta() {\n    return { ...this.#meta };\n  }\n\n  #localFile: OPFSToolFile;\n\n  #headerBoxPos: Array<{ start: number; size: number }> = [];\n  /**\n   * 提供视频头（box: ftyp, moov）的二进制数据\n   * 使用任意 mp4 demxer 解析即可获得详细的视频信息\n   * 单元测试包含使用 mp4box.js 解析示例代码\n   */\n  async getFileHeaderBinData() {\n    await this.ready;\n    const oFile = await this.#localFile.getOriginFile();\n    if (oFile == null) throw Error('MP4Clip localFile is not origin file');\n\n    return await new Blob(\n      this.#headerBoxPos.map(({ start, size }) =>\n        oFile.slice(start, start + size),\n      ),\n    ).arrayBuffer();\n  }\n\n  #volume = 1;\n\n  #videoSamples: ExtMP4Sample[] = [];\n\n  #audioSamples: ExtMP4Sample[] = [];\n\n  #videoFrameFinder: VideoFrameFinder | null = null;\n  #audioFrameFinder: AudioFrameFinder | null = null;\n\n  #decoderConf: {\n    video: VideoDecoderConfig | null;\n    audio: AudioDecoderConfig | null;\n  } = {\n    video: null,\n    audio: null,\n  };\n\n  #opts: MP4ClipOpts = { audio: true };\n\n  constructor(\n    source: OPFSToolFile | ReadableStream<Uint8Array> | MPClipCloneArgs,\n    opts: MP4ClipOpts = {},\n  ) {\n    if (\n      !(source instanceof ReadableStream) &&\n      !isOTFile(source) &&\n      !Array.isArray(source.videoSamples)\n    ) {\n      throw Error('Illegal argument');\n    }\n\n    this.#opts = { audio: true, ...opts };\n    this.#volume =\n      typeof opts.audio === 'object' && 'volume' in opts.audio\n        ? opts.audio.volume\n        : 1;\n\n    const initByStream = async (s: ReadableStream) => {\n      await write(this.#localFile, s);\n      return this.#localFile;\n    };\n\n    this.#localFile = isOTFile(source)\n      ? source\n      : 'localFile' in source\n        ? source.localFile // from clone\n        : tmpfile();\n\n    this.ready = (\n      source instanceof ReadableStream\n        ? initByStream(source).then((otFile) =>\n            mp4FileToSamples(otFile, this.#opts),\n          )\n        : isOTFile(source)\n          ? mp4FileToSamples(source, this.#opts)\n          : Promise.resolve(source)\n    ).then(\n      async ({ videoSamples, audioSamples, decoderConf, headerBoxPos }) => {\n        this.#videoSamples = videoSamples;\n        this.#audioSamples = audioSamples;\n        this.#decoderConf = decoderConf;\n        this.#headerBoxPos = headerBoxPos;\n\n        const { videoFrameFinder, audioFrameFinder } = genDecoder(\n          {\n            video:\n              decoderConf.video == null\n                ? null\n                : {\n                    ...decoderConf.video,\n                    hardwareAcceleration:\n                      this.#opts.__unsafe_hardwareAcceleration__,\n                  },\n            audio: decoderConf.audio,\n          },\n          await this.#localFile.createReader(),\n          videoSamples,\n          audioSamples,\n          this.#opts.audio !== false ? this.#volume : 0,\n        );\n        this.#videoFrameFinder = videoFrameFinder;\n        this.#audioFrameFinder = audioFrameFinder;\n\n        this.#meta = genMeta(decoderConf, videoSamples, audioSamples);\n        this.#log.info('MP4Clip meta:', this.#meta);\n        return { ...this.#meta };\n      },\n    );\n  }\n\n  /**\n   * 拦截 {@link MP4Clip.tick} 方法返回的数据，用于对图像、音频数据二次处理\n   * @param time 调用 tick 的时间\n   * @param tickRet tick 返回的数据\n   *\n   * @see [移除视频绿幕背景](https://webav-tech.github.io/WebAV/demo/3_2-chromakey-video)\n   */\n  tickInterceptor: <T extends Awaited<ReturnType<MP4Clip['tick']>>>(\n    time: number,\n    tickRet: T,\n  ) => Promise<T> = async (_, tickRet) => tickRet;\n\n  /**\n   * 获取素材指定时刻的图像帧、音频数据\n   * @param time 微秒\n   */\n  async tick(time: number): Promise<{\n    video?: VideoFrame;\n    audio: Float32Array[];\n    state: 'success' | 'done';\n  }> {\n    if (time >= this.#meta.duration) {\n      return await this.tickInterceptor(time, {\n        audio: (await this.#audioFrameFinder?.find(time)) ?? [],\n        state: 'done',\n      });\n    }\n\n    const [audio, video] = await Promise.all([\n      this.#audioFrameFinder?.find(time) ?? [],\n      this.#videoFrameFinder?.find(time),\n    ]);\n\n    if (video == null) {\n      return await this.tickInterceptor(time, {\n        audio,\n        state: 'success',\n      });\n    }\n\n    return await this.tickInterceptor(time, {\n      video,\n      audio,\n      state: 'success',\n    });\n  }\n\n  #thumbAborter = new AbortController();\n  /**\n   * 生成缩略图，默认每个关键帧生成一个 100px 宽度的缩略图。\n   *\n   * @param imgWidth 缩略图宽度，默认 100\n   * @param opts Partial<ThumbnailOpts>\n   * @returns Promise<Array<{ ts: number; img: Blob }>>\n   */\n  async thumbnails(\n    imgWidth = 100,\n    opts?: Partial<ThumbnailOpts>,\n  ): Promise<Array<{ ts: number; img: Blob }>> {\n    this.#thumbAborter.abort();\n    this.#thumbAborter = new AbortController();\n    const aborterSignal = this.#thumbAborter.signal;\n\n    await this.ready;\n    const abortMsg = 'generate thumbnails aborted';\n    if (aborterSignal.aborted) throw Error(abortMsg);\n\n    const { width, height } = this.#meta;\n    const convtr = createVF2BlobConvtr(\n      imgWidth,\n      Math.round(height * (imgWidth / width)),\n      { quality: 0.1, type: 'image/png' },\n    );\n\n    return new Promise<Array<{ ts: number; img: Blob }>>(\n      async (resolve, reject) => {\n        let pngPromises: Array<{ ts: number; img: Promise<Blob> }> = [];\n        const vc = this.#decoderConf.video;\n        if (vc == null || this.#videoSamples.length === 0) {\n          resolver();\n          return;\n        }\n        aborterSignal.addEventListener('abort', () => {\n          reject(Error(abortMsg));\n        });\n\n        async function resolver() {\n          if (aborterSignal.aborted) return;\n          resolve(\n            await Promise.all(\n              pngPromises.map(async (it) => ({\n                ts: it.ts,\n                img: await it.img,\n              })),\n            ),\n          );\n        }\n\n        function pushPngPromise(vf: VideoFrame) {\n          pngPromises.push({\n            ts: vf.timestamp,\n            img: convtr(vf),\n          });\n        }\n\n        const { start = 0, end = this.#meta.duration, step } = opts ?? {};\n        if (step) {\n          let cur = start;\n          // 创建一个新的 VideoFrameFinder 实例，避免与 tick 方法共用而导致冲突\n          const videoFrameFinder = new VideoFrameFinder(\n            await this.#localFile.createReader(),\n            this.#videoSamples,\n            {\n              ...vc,\n              hardwareAcceleration: this.#opts.__unsafe_hardwareAcceleration__,\n            },\n          );\n          while (cur <= end && !aborterSignal.aborted) {\n            const vf = await videoFrameFinder.find(cur);\n            if (vf) pushPngPromise(vf);\n            cur += step;\n          }\n          videoFrameFinder.destroy();\n          resolver();\n        } else {\n          await thumbnailByKeyFrame(\n            this.#videoSamples,\n            this.#localFile,\n            vc,\n            aborterSignal,\n            { start, end },\n            (vf, done) => {\n              if (vf != null) pushPngPromise(vf);\n              if (done) resolver();\n            },\n          );\n        }\n      },\n    );\n  }\n\n  async split(time: number) {\n    await this.ready;\n\n    if (time <= 0 || time >= this.#meta.duration)\n      throw Error('\"time\" out of bounds');\n\n    const [preVideoSlice, postVideoSlice] = splitVideoSampleByTime(\n      this.#videoSamples,\n      time,\n    );\n    const [preAudioSlice, postAudioSlice] = splitAudioSampleByTime(\n      this.#audioSamples,\n      time,\n    );\n    const preClip = new MP4Clip(\n      {\n        localFile: this.#localFile,\n        videoSamples: preVideoSlice ?? [],\n        audioSamples: preAudioSlice ?? [],\n        decoderConf: this.#decoderConf,\n        headerBoxPos: this.#headerBoxPos,\n      },\n      this.#opts,\n    );\n    const postClip = new MP4Clip(\n      {\n        localFile: this.#localFile,\n        videoSamples: postVideoSlice ?? [],\n        audioSamples: postAudioSlice ?? [],\n        decoderConf: this.#decoderConf,\n        headerBoxPos: this.#headerBoxPos,\n      },\n      this.#opts,\n    );\n    await Promise.all([preClip.ready, postClip.ready]);\n\n    return [preClip, postClip] as [this, this];\n  }\n\n  async clone() {\n    await this.ready;\n    const clip = new MP4Clip(\n      {\n        localFile: this.#localFile,\n        videoSamples: [...this.#videoSamples],\n        audioSamples: [...this.#audioSamples],\n        decoderConf: this.#decoderConf,\n        headerBoxPos: this.#headerBoxPos,\n      },\n      this.#opts,\n    );\n    await clip.ready;\n    clip.tickInterceptor = this.tickInterceptor;\n    return clip as this;\n  }\n\n  /**\n   * 拆分 MP4Clip 为仅包含视频轨道和音频轨道的 MP4Clip\n   * @returns Mp4CLip[]\n   */\n  async splitTrack() {\n    await this.ready;\n    const clips: MP4Clip[] = [];\n    if (this.#videoSamples.length > 0) {\n      const videoClip = new MP4Clip(\n        {\n          localFile: this.#localFile,\n          videoSamples: [...this.#videoSamples],\n          audioSamples: [],\n          decoderConf: {\n            video: this.#decoderConf.video,\n            audio: null,\n          },\n          headerBoxPos: this.#headerBoxPos,\n        },\n        this.#opts,\n      );\n      await videoClip.ready;\n      videoClip.tickInterceptor = this.tickInterceptor;\n      clips.push(videoClip);\n    }\n    if (this.#audioSamples.length > 0) {\n      const audioClip = new MP4Clip(\n        {\n          localFile: this.#localFile,\n          videoSamples: [],\n          audioSamples: [...this.#audioSamples],\n          decoderConf: {\n            audio: this.#decoderConf.audio,\n            video: null,\n          },\n          headerBoxPos: this.#headerBoxPos,\n        },\n        this.#opts,\n      );\n      await audioClip.ready;\n      audioClip.tickInterceptor = this.tickInterceptor;\n      clips.push(audioClip);\n    }\n\n    return clips;\n  }\n\n  destroy(): void {\n    if (this.#destroyed) return;\n    this.#log.info('MP4Clip destroy');\n    this.#destroyed = true;\n\n    this.#videoFrameFinder?.destroy();\n    this.#audioFrameFinder?.destroy();\n  }\n}\n\nfunction genMeta(\n  decoderConf: MP4DecoderConf,\n  videoSamples: ExtMP4Sample[],\n  audioSamples: ExtMP4Sample[],\n) {\n  const meta = {\n    duration: 0,\n    width: 0,\n    height: 0,\n    audioSampleRate: 0,\n    audioChanCount: 0,\n  };\n  if (decoderConf.video != null && videoSamples.length > 0) {\n    meta.width = decoderConf.video.codedWidth ?? 0;\n    meta.height = decoderConf.video.codedHeight ?? 0;\n  }\n  if (decoderConf.audio != null && audioSamples.length > 0) {\n    meta.audioSampleRate = DEFAULT_AUDIO_CONF.sampleRate;\n    meta.audioChanCount = DEFAULT_AUDIO_CONF.channelCount;\n  }\n\n  let vDuration = 0;\n  let aDuration = 0;\n  if (videoSamples.length > 0) {\n    for (let i = videoSamples.length - 1; i >= 0; i--) {\n      const s = videoSamples[i];\n      if (s.deleted) continue;\n      vDuration = s.cts + s.duration;\n      break;\n    }\n  }\n  if (audioSamples.length > 0) {\n    const lastSampele = audioSamples.at(-1)!;\n    aDuration = lastSampele.cts + lastSampele.duration;\n  }\n  meta.duration = Math.max(vDuration, aDuration);\n\n  return meta;\n}\n\nfunction genDecoder(\n  decoderConf: MP4DecoderConf,\n  localFileReader: LocalFileReader,\n  videoSamples: ExtMP4Sample[],\n  audioSamples: ExtMP4Sample[],\n  volume: number,\n) {\n  return {\n    audioFrameFinder:\n      volume === 0 || decoderConf.audio == null || audioSamples.length === 0\n        ? null\n        : new AudioFrameFinder(\n            localFileReader,\n            audioSamples,\n            decoderConf.audio,\n            {\n              volume,\n              targetSampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n            },\n          ),\n    videoFrameFinder:\n      decoderConf.video == null || videoSamples.length === 0\n        ? null\n        : new VideoFrameFinder(\n            localFileReader,\n            videoSamples,\n            decoderConf.video,\n          ),\n  };\n}\n\nasync function mp4FileToSamples(otFile: OPFSToolFile, opts: MP4ClipOpts = {}) {\n  let mp4Info: MP4Info | null = null;\n  const decoderConf: MP4DecoderConf = { video: null, audio: null };\n  let videoSamples: ExtMP4Sample[] = [];\n  let audioSamples: ExtMP4Sample[] = [];\n  let headerBoxPos: Array<{ start: number; size: number }> = [];\n\n  let videoDeltaTS = -1;\n  let audioDeltaTS = -1;\n  const reader = await otFile.createReader();\n  await quickParseMP4File(\n    reader,\n    (data) => {\n      mp4Info = data.info;\n      const ftyp = data.mp4boxFile.ftyp!;\n      headerBoxPos.push({ start: ftyp.start, size: ftyp.size });\n      const moov = data.mp4boxFile.moov!;\n      headerBoxPos.push({ start: moov.start, size: moov.size });\n\n      let { videoDecoderConf: vc, audioDecoderConf: ac } = extractFileConfig(\n        data.mp4boxFile,\n        data.info,\n      );\n      decoderConf.video = vc ?? null;\n      decoderConf.audio = ac ?? null;\n      if (vc == null && ac == null) {\n        Log.error('MP4Clip no video and audio track');\n      }\n      Log.info(\n        'mp4BoxFile moov ready',\n        {\n          ...data.info,\n          tracks: null,\n          videoTracks: null,\n          audioTracks: null,\n        },\n        decoderConf,\n      );\n    },\n    (_, type, samples) => {\n      if (type === 'video') {\n        if (videoDeltaTS === -1) videoDeltaTS = samples[0].dts;\n        for (const s of samples) {\n          videoSamples.push(normalizeTimescale(s, videoDeltaTS, 'video'));\n        }\n      } else if (type === 'audio' && opts.audio) {\n        if (audioDeltaTS === -1) audioDeltaTS = samples[0].dts;\n        for (const s of samples) {\n          audioSamples.push(normalizeTimescale(s, audioDeltaTS, 'audio'));\n        }\n      }\n    },\n  );\n  await reader.close();\n\n  const lastSampele = videoSamples.at(-1) ?? audioSamples.at(-1);\n  if (mp4Info == null) {\n    throw Error('MP4Clip stream is done, but not emit ready');\n  } else if (lastSampele == null) {\n    throw Error('MP4Clip stream not contain any sample');\n  }\n  // 修复首帧黑帧\n  fixFirstBlackFrame(videoSamples);\n  Log.info('mp4 stream parsed');\n  return {\n    videoSamples,\n    audioSamples,\n    decoderConf,\n    headerBoxPos,\n  };\n\n  function normalizeTimescale(\n    s: MP4Sample,\n    delta = 0,\n    sampleType: 'video' | 'audio',\n  ) {\n    // todo: perf 丢弃多余字段，小尺寸对象性能更好\n    const idrOffset =\n      sampleType === 'video' && s.is_sync\n        ? idrNALUOffset(s.data, s.description.type)\n        : -1;\n    let offset = s.offset;\n    let size = s.size;\n    if (idrOffset >= 0) {\n      // 当 IDR 帧前面携带 SEI 数据可能导致解码失败\n      // 所以此处通过控制 offset、size 字段 跳过 SEI 数据\n      offset += idrOffset;\n      size -= idrOffset;\n    }\n    return {\n      ...s,\n      is_idr: idrOffset >= 0,\n      offset,\n      size,\n      cts: ((s.cts - delta) / s.timescale) * 1e6,\n      dts: ((s.dts - delta) / s.timescale) * 1e6,\n      duration: (s.duration / s.timescale) * 1e6,\n      timescale: 1e6,\n      // 音频数据量可控，直接保存在内存中\n      data: sampleType === 'video' ? null : s.data,\n    };\n  }\n}\n\nclass VideoFrameFinder {\n  #dec: VideoDecoder | null = null;\n  constructor(\n    public localFileReader: LocalFileReader,\n    public samples: ExtMP4Sample[],\n    public conf: VideoDecoderConfig,\n  ) {}\n\n  #ts = 0;\n  #curAborter = { abort: false, st: performance.now() };\n  find = async (time: number): Promise<VideoFrame | null> => {\n    if (\n      this.#dec == null ||\n      this.#dec.state === 'closed' ||\n      time <= this.#ts ||\n      time - this.#ts > 3e6\n    ) {\n      this.#reset(time);\n    }\n\n    this.#curAborter.abort = true;\n    this.#ts = time;\n\n    this.#curAborter = { abort: false, st: performance.now() };\n    const vf = await this.#parseFrame(time, this.#dec, this.#curAborter);\n    this.#sleepCnt = 0;\n    return vf;\n  };\n\n  // fix VideoFrame duration is null\n  #lastVfDur = 0;\n\n  #downgradeSoftDecode = false;\n  #videoDecCusorIdx = 0;\n  #videoFrames: VideoFrame[] = [];\n  #outputFrameCnt = 0;\n  #inputChunkCnt = 0;\n  #sleepCnt = 0;\n  #predecodeErr = false;\n  #parseFrame = async (\n    time: number,\n    dec: VideoDecoder | null,\n    aborter: { abort: boolean; st: number },\n  ): Promise<VideoFrame | null> => {\n    if (dec == null || dec.state === 'closed' || aborter.abort) return null;\n\n    if (this.#videoFrames.length > 0) {\n      const vf = this.#videoFrames[0];\n      if (time < vf.timestamp) return null;\n      // 弹出第一帧\n      this.#videoFrames.shift();\n      // 第一帧过期，找下一帧\n      if (time > vf.timestamp + (vf.duration ?? 0)) {\n        vf.close();\n        return await this.#parseFrame(time, dec, aborter);\n      }\n\n      if (!this.#predecodeErr && this.#videoFrames.length < 10) {\n        // 预解码 避免等待\n        this.#startDecode(dec).catch((err) => {\n          this.#predecodeErr = true;\n          this.#reset(time);\n          throw err;\n        });\n      }\n      // 符合期望\n      return vf;\n    }\n\n    // 缺少帧数据\n    if (\n      this.#decoding ||\n      (this.#outputFrameCnt < this.#inputChunkCnt && dec.decodeQueueSize > 0)\n    ) {\n      if (performance.now() - aborter.st > 6e3) {\n        throw Error(\n          `MP4Clip.tick video timeout, ${JSON.stringify(this.#getState())}`,\n        );\n      }\n      // 解码中，等待，然后重试\n      this.#sleepCnt += 1;\n      await sleep(15);\n    } else if (this.#videoDecCusorIdx >= this.samples.length) {\n      // decode completed\n      return null;\n    } else {\n      try {\n        await this.#startDecode(dec);\n      } catch (err) {\n        this.#reset(time);\n        throw err;\n      }\n    }\n    return await this.#parseFrame(time, dec, aborter);\n  };\n\n  #decoding = false;\n  #startDecode = async (dec: VideoDecoder) => {\n    if (this.#decoding || dec.decodeQueueSize > 600) return;\n\n    // 启动解码任务，然后重试\n    let endIdx = this.#videoDecCusorIdx + 1;\n    if (endIdx > this.samples.length) return;\n\n    this.#decoding = true;\n    // 该 GoP 时间区间有时间匹配，且未被删除的帧\n    let hasValidFrame = false;\n    for (; endIdx < this.samples.length; endIdx++) {\n      const s = this.samples[endIdx];\n      if (!hasValidFrame && !s.deleted) {\n        hasValidFrame = true;\n      }\n      // 找一个 GoP，所以是下一个 IDR 帧结束\n      if (s.is_idr) break;\n    }\n\n    if (hasValidFrame) {\n      const samples = this.samples.slice(this.#videoDecCusorIdx, endIdx);\n      if (samples[0]?.is_idr !== true) {\n        Log.warn('First sample not idr frame');\n      } else {\n        const readStarTime = performance.now();\n        const chunks = await videosamples2Chunks(samples, this.localFileReader);\n\n        const readCost = performance.now() - readStarTime;\n        if (readCost > 1000) {\n          const first = samples[0];\n          const last = samples.at(-1)!;\n          const rangSize = last.offset + last.size - first.offset;\n          Log.warn(\n            `Read video samples time cost: ${Math.round(readCost)}ms, file chunk size: ${rangSize}`,\n          );\n        }\n        // Wait for the previous asynchronous operation to complete, at which point the task may have already been terminated\n        if (dec.state === 'closed') return;\n\n        this.#lastVfDur = chunks[0]?.duration ?? 0;\n        decodeGoP(dec, chunks, {\n          onDecodingError: (err) => {\n            if (this.#downgradeSoftDecode) {\n              throw err;\n            } else if (this.#outputFrameCnt === 0) {\n              this.#downgradeSoftDecode = true;\n              Log.warn('Downgrade to software decode');\n              this.#reset();\n            }\n          },\n        });\n\n        this.#inputChunkCnt += chunks.length;\n      }\n    }\n    this.#videoDecCusorIdx = endIdx;\n    this.#decoding = false;\n  };\n\n  #reset = (time?: number) => {\n    this.#decoding = false;\n    this.#videoFrames.forEach((f) => f.close());\n    this.#videoFrames = [];\n    if (time == null || time === 0) {\n      this.#videoDecCusorIdx = 0;\n    } else {\n      let keyIdx = 0;\n      for (let i = 0; i < this.samples.length; i++) {\n        const s = this.samples[i];\n        if (s.is_idr) keyIdx = i;\n        if (s.cts < time) continue;\n        this.#videoDecCusorIdx = keyIdx;\n        break;\n      }\n    }\n    this.#inputChunkCnt = 0;\n    this.#outputFrameCnt = 0;\n    if (this.#dec?.state !== 'closed') this.#dec?.close();\n    const encoderConf = {\n      ...this.conf,\n      ...(this.#downgradeSoftDecode\n        ? { hardwareAcceleration: 'prefer-software' }\n        : {}),\n    } as VideoDecoderConfig;\n    this.#dec = new VideoDecoder({\n      output: (vf) => {\n        this.#outputFrameCnt += 1;\n        if (vf.timestamp === -1) {\n          vf.close();\n          return;\n        }\n        let rsVf = vf;\n        if (vf.duration == null) {\n          rsVf = new VideoFrame(vf, {\n            duration: this.#lastVfDur,\n          });\n          vf.close();\n        }\n        this.#videoFrames.push(rsVf);\n      },\n      error: (err) => {\n        if (err.message.includes('Codec reclaimed due to inactivity')) {\n          // todo:  因无活动被自动关闭的解码器，是否需要自动重启？\n          this.#dec = null;\n          Log.warn(err.message);\n          return;\n        }\n\n        const errMsg = `VideoFinder VideoDecoder err: ${err.message}, config: ${JSON.stringify(encoderConf)}, state: ${JSON.stringify(this.#getState())}`;\n        Log.error(errMsg);\n        throw Error(errMsg);\n      },\n    });\n    this.#dec.configure(encoderConf);\n  };\n\n  #getState = () => ({\n    time: this.#ts,\n    decState: this.#dec?.state,\n    decQSize: this.#dec?.decodeQueueSize,\n    decCusorIdx: this.#videoDecCusorIdx,\n    sampleLen: this.samples.length,\n    inputCnt: this.#inputChunkCnt,\n    outputCnt: this.#outputFrameCnt,\n    cacheFrameLen: this.#videoFrames.length,\n    softDeocde: this.#downgradeSoftDecode,\n    clipIdCnt: CLIP_ID,\n    sleepCnt: this.#sleepCnt,\n    memInfo: memoryUsageInfo(),\n  });\n\n  destroy = () => {\n    if (this.#dec?.state !== 'closed') this.#dec?.close();\n    this.#dec = null;\n    this.#curAborter.abort = true;\n    this.#videoFrames.forEach((f) => f.close());\n    this.#videoFrames = [];\n    this.localFileReader.close();\n  };\n}\n\nfunction findIndexOfSamples(time: number, samples: ExtMP4Sample[]) {\n  for (let i = 0; i < samples.length; i++) {\n    const s = samples[i];\n    if (time >= s.cts && time < s.cts + s.duration) {\n      return i;\n    }\n    if (s.cts > time) break;\n  }\n  return 0;\n}\n\nclass AudioFrameFinder {\n  #volume = 1;\n  #sampleRate;\n  constructor(\n    public localFileReader: LocalFileReader,\n    public samples: ExtMP4Sample[],\n    public conf: AudioDecoderConfig,\n    opts: { volume: number; targetSampleRate: number },\n  ) {\n    this.#volume = opts.volume;\n    this.#sampleRate = opts.targetSampleRate;\n  }\n\n  #dec: ReturnType<typeof createAudioChunksDecoder> | null = null;\n  #curAborter = { abort: false, st: performance.now() };\n  find = async (time: number): Promise<Float32Array[]> => {\n    const needResetTime = time <= this.#ts || time - this.#ts > 0.1e6;\n    if (this.#dec == null || this.#dec.state === 'closed' || needResetTime) {\n      this.#reset();\n    }\n\n    if (needResetTime) {\n      // 前后获取音频数据差异不能超过 100ms(经验值)，否则视为 seek 操作，重置解码器\n      // seek 操作，重置时间\n      this.#ts = time;\n      this.#decCusorIdx = findIndexOfSamples(time, this.samples);\n    }\n\n    this.#curAborter.abort = true;\n    const deltaTime = time - this.#ts;\n    this.#ts = time;\n\n    this.#curAborter = { abort: false, st: performance.now() };\n\n    const pcmData = await this.#parseFrame(\n      Math.ceil(deltaTime * (this.#sampleRate / 1e6)),\n      this.#dec,\n      this.#curAborter,\n    );\n    this.#sleepCnt = 0;\n    return pcmData;\n  };\n\n  #ts = 0;\n  #decCusorIdx = 0;\n  #pcmData: {\n    frameCnt: number;\n    data: [Float32Array, Float32Array][];\n  } = {\n    frameCnt: 0,\n    data: [],\n  };\n  #sleepCnt = 0;\n  #parseFrame = async (\n    emitFrameCnt: number,\n    dec: ReturnType<typeof createAudioChunksDecoder> | null = null,\n    aborter: { abort: boolean; st: number },\n  ): Promise<Float32Array[]> => {\n    if (\n      dec == null ||\n      aborter.abort ||\n      dec.state === 'closed' ||\n      emitFrameCnt === 0\n    ) {\n      return [];\n    }\n\n    // 数据满足需要\n    const ramainFrameCnt = this.#pcmData.frameCnt - emitFrameCnt;\n    if (ramainFrameCnt > 0) {\n      // 剩余音频数据小于 100ms，预先解码\n      if (ramainFrameCnt < DEFAULT_AUDIO_CONF.sampleRate / 10) {\n        this.#startDecode(dec);\n      }\n      return emitAudioFrames(this.#pcmData, emitFrameCnt);\n    }\n\n    if (dec.decoding) {\n      if (performance.now() - aborter.st > 3e3) {\n        aborter.abort = true;\n        throw Error(\n          `MP4Clip.tick audio timeout, ${JSON.stringify(this.#getState())}`,\n        );\n      }\n      // 解码中，等待\n      this.#sleepCnt += 1;\n      await sleep(15);\n    } else if (this.#decCusorIdx >= this.samples.length - 1) {\n      // 最后片段，返回剩余数据\n      return emitAudioFrames(this.#pcmData, this.#pcmData.frameCnt);\n    } else {\n      this.#startDecode(dec);\n    }\n    return this.#parseFrame(emitFrameCnt, dec, aborter);\n  };\n\n  #startDecode = (dec: ReturnType<typeof createAudioChunksDecoder>) => {\n    const onceDecodeCnt = 10;\n    if (dec.decodeQueueSize > onceDecodeCnt) return;\n    // 启动解码任务\n    const samples = [];\n    let i = this.#decCusorIdx;\n    while (i < this.samples.length) {\n      const s = this.samples[i];\n      i += 1;\n      if (s.deleted) continue;\n      samples.push(s);\n      if (samples.length >= onceDecodeCnt) break;\n    }\n    this.#decCusorIdx = i;\n\n    dec.decode(\n      samples.map(\n        (s) =>\n          new EncodedAudioChunk({\n            type: 'key',\n            timestamp: s.cts,\n            duration: s.duration,\n            data: s.data!,\n          }),\n      ),\n    );\n  };\n\n  #reset = () => {\n    this.#ts = 0;\n    this.#decCusorIdx = 0;\n    this.#pcmData = {\n      frameCnt: 0,\n      data: [],\n    };\n    this.#dec?.close();\n    this.#dec = createAudioChunksDecoder(\n      this.conf,\n      {\n        resampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n        volume: this.#volume,\n      },\n      (pcmArr) => {\n        this.#pcmData.data.push(pcmArr as [Float32Array, Float32Array]);\n        this.#pcmData.frameCnt += pcmArr[0].length;\n      },\n    );\n  };\n\n  #getState = () => ({\n    time: this.#ts,\n    decState: this.#dec?.state,\n    decQSize: this.#dec?.decodeQueueSize,\n    decCusorIdx: this.#decCusorIdx,\n    sampleLen: this.samples.length,\n    pcmLen: this.#pcmData.frameCnt,\n    clipIdCnt: CLIP_ID,\n    sleepCnt: this.#sleepCnt,\n    memInfo: memoryUsageInfo(),\n  });\n\n  destroy = () => {\n    this.#dec = null;\n    this.#curAborter.abort = true;\n    this.#pcmData = {\n      frameCnt: 0,\n      data: [],\n    };\n    this.localFileReader.close();\n  };\n}\n\nfunction createAudioChunksDecoder(\n  decoderConf: AudioDecoderConfig,\n  opts: { resampleRate: number; volume: number },\n  outputCb: (pcm: Float32Array[]) => void,\n) {\n  let inputCnt = 0;\n  let outputCnt = 0;\n  const outputHandler = (pcmArr: Float32Array[]) => {\n    outputCnt += 1;\n    if (pcmArr.length === 0) return;\n    // 音量调节\n    if (opts.volume !== 1) {\n      for (const pcm of pcmArr)\n        for (let i = 0; i < pcm.length; i++) pcm[i] *= opts.volume;\n    }\n\n    // 补齐双声道\n    if (pcmArr.length === 1) pcmArr = [pcmArr[0], pcmArr[0]];\n\n    outputCb(pcmArr);\n  };\n  const resampleQ = createPromiseQueue<Float32Array[]>(outputHandler);\n\n  const needResample = opts.resampleRate !== decoderConf.sampleRate;\n  let adec = new AudioDecoder({\n    output: (ad) => {\n      const pcm = extractPCM4AudioData(ad);\n      if (needResample) {\n        resampleQ(() =>\n          audioResample(pcm, ad.sampleRate, {\n            rate: opts.resampleRate,\n            chanCount: ad.numberOfChannels,\n          }),\n        );\n      } else {\n        outputHandler(pcm);\n      }\n      ad.close();\n    },\n    error: (err) => {\n      if (err.message.includes('Codec reclaimed due to inactivity')) {\n        return;\n      }\n      handleDecodeError('MP4Clip AudioDecoder err', err as Error);\n    },\n  });\n  adec.configure(decoderConf);\n\n  function handleDecodeError(prefixStr: string, err: Error) {\n    const errMsg = `${prefixStr}: ${(err as Error).message}, state: ${JSON.stringify(\n      {\n        qSize: adec.decodeQueueSize,\n        state: adec.state,\n        inputCnt,\n        outputCnt,\n      },\n    )}`;\n    Log.error(errMsg);\n    throw Error(errMsg);\n  }\n\n  return {\n    decode(chunks: EncodedAudioChunk[]) {\n      inputCnt += chunks.length;\n      try {\n        for (const chunk of chunks) adec.decode(chunk);\n      } catch (err) {\n        handleDecodeError('decode audio chunk error', err as Error);\n      }\n    },\n    close() {\n      if (adec.state !== 'closed') adec.close();\n    },\n    get decoding() {\n      return inputCnt > outputCnt && adec.decodeQueueSize > 0;\n    },\n    get state() {\n      return adec.state;\n    },\n    get decodeQueueSize() {\n      return adec.decodeQueueSize;\n    },\n  };\n}\n\n// 并行执行任务，但按顺序emit结果\nfunction createPromiseQueue<T extends any>(onResult: (data: T) => void) {\n  const rsCache: T[] = [];\n  let waitingIdx = 0;\n\n  function updateRs(rs: T, emitIdx: number) {\n    rsCache[emitIdx] = rs;\n    emitRs();\n  }\n\n  function emitRs() {\n    const rs = rsCache[waitingIdx];\n    if (rs == null) return;\n    onResult(rs);\n\n    waitingIdx += 1;\n    emitRs();\n  }\n\n  let addIdx = 0;\n  return (task: () => Promise<T>) => {\n    const emitIdx = addIdx;\n    addIdx += 1;\n    task()\n      .then((rs) => updateRs(rs, emitIdx))\n      .catch((err) => updateRs(err, emitIdx));\n  };\n}\n\nfunction emitAudioFrames(\n  pcmData: { frameCnt: number; data: [Float32Array, Float32Array][] },\n  emitCnt: number,\n) {\n  // todo: perf 重复利用内存空间\n  const audio = [new Float32Array(emitCnt), new Float32Array(emitCnt)];\n  let offset = 0;\n  let i = 0;\n  for (; i < pcmData.data.length; ) {\n    const [chan0, chan1] = pcmData.data[i];\n    if (offset + chan0.length > emitCnt) {\n      const gapCnt = emitCnt - offset;\n      audio[0].set(chan0.subarray(0, gapCnt), offset);\n      audio[1].set(chan1.subarray(0, gapCnt), offset);\n      pcmData.data[i][0] = chan0.subarray(gapCnt, chan0.length);\n      pcmData.data[i][1] = chan1.subarray(gapCnt, chan1.length);\n      break;\n    } else {\n      audio[0].set(chan0, offset);\n      audio[1].set(chan1, offset);\n      offset += chan0.length;\n      i++;\n    }\n  }\n  pcmData.data = pcmData.data.slice(i);\n  pcmData.frameCnt -= emitCnt;\n  return audio;\n}\n\nasync function videosamples2Chunks(\n  samples: ExtMP4Sample[],\n  reader: Awaited<ReturnType<OPFSToolFile['createReader']>>,\n): Promise<EncodedVideoChunk[]> {\n  const first = samples[0];\n  const last = samples.at(-1);\n  if (last == null) return [];\n\n  const rangSize = last.offset + last.size - first.offset;\n  if (rangSize < 30e6) {\n    // 单次读取数据小于 30M，就一次性读取数据，降低 IO 频次\n    const data = new Uint8Array(\n      await reader.read(rangSize, { at: first.offset }),\n    );\n    return samples.map((s) => {\n      const offset = s.offset - first.offset;\n      return new EncodedVideoChunk({\n        type: s.is_sync ? 'key' : 'delta',\n        timestamp: s.cts,\n        duration: s.duration,\n        data: data.subarray(offset, offset + s.size),\n      });\n    });\n  }\n\n  return await Promise.all(\n    samples.map(async (s) => {\n      return new EncodedVideoChunk({\n        type: s.is_sync ? 'key' : 'delta',\n        timestamp: s.cts,\n        duration: s.duration,\n        data: await reader.read(s.size, {\n          at: s.offset,\n        }),\n      });\n    }),\n  );\n}\n\nfunction createVF2BlobConvtr(\n  width: number,\n  height: number,\n  opts?: ImageEncodeOptions,\n) {\n  const cvs = new OffscreenCanvas(width, height);\n  const ctx = cvs.getContext('2d')!;\n\n  return async (vf: VideoFrame) => {\n    ctx.drawImage(vf, 0, 0, width, height);\n    vf.close();\n    const blob = await cvs.convertToBlob(opts);\n    return blob;\n  };\n}\n\nfunction splitVideoSampleByTime(videoSamples: ExtMP4Sample[], time: number) {\n  if (videoSamples.length === 0) return [];\n  let gopStartIdx = 0;\n  let gopEndIdx = 0;\n  let hitIdx = -1;\n  for (let i = 0; i < videoSamples.length; i++) {\n    const s = videoSamples[i];\n    if (hitIdx === -1 && time < s.cts) hitIdx = i - 1;\n    if (s.is_idr) {\n      if (hitIdx === -1) {\n        gopStartIdx = i;\n      } else {\n        gopEndIdx = i;\n        break;\n      }\n    }\n  }\n\n  const hitSample = videoSamples[hitIdx];\n  if (hitSample == null) throw Error('Not found video sample by time');\n\n  const preSlice = videoSamples\n    .slice(0, gopEndIdx === 0 ? videoSamples.length : gopEndIdx)\n    .map((s) => ({ ...s }));\n  for (let i = gopStartIdx; i < preSlice.length; i++) {\n    const s = preSlice[i];\n    if (time < s.cts) {\n      s.deleted = true;\n      s.cts = -1;\n    }\n  }\n  fixFirstBlackFrame(preSlice);\n\n  const postSlice = videoSamples\n    .slice(hitSample.is_idr ? hitIdx : gopStartIdx)\n    .map((s) => ({ ...s, cts: s.cts - time }));\n\n  for (const s of postSlice) {\n    if (s.cts < 0) {\n      s.deleted = true;\n      s.cts = -1;\n    }\n  }\n  fixFirstBlackFrame(postSlice);\n\n  return [preSlice, postSlice];\n}\n\nfunction splitAudioSampleByTime(audioSamples: ExtMP4Sample[], time: number) {\n  if (audioSamples.length === 0) return [];\n  let hitIdx = -1;\n  for (let i = 0; i < audioSamples.length; i++) {\n    const s = audioSamples[i];\n    if (time > s.cts) continue;\n    hitIdx = i;\n    break;\n  }\n  if (hitIdx === -1) throw Error('Not found audio sample by time');\n  const preSlice = audioSamples.slice(0, hitIdx).map((s) => ({ ...s }));\n  const postSlice = audioSamples\n    .slice(hitIdx)\n    .map((s) => ({ ...s, cts: s.cts - time }));\n  return [preSlice, postSlice];\n}\n\n// 兼容解码错误\nfunction decodeGoP(\n  dec: VideoDecoder,\n  chunks: EncodedVideoChunk[],\n  opts: {\n    onDecodingError?: (err: Error) => void;\n  },\n) {\n  let i = 0;\n  if (dec.state !== 'configured') return;\n  for (; i < chunks.length; i++) dec.decode(chunks[i]);\n\n  // todo：flush 之后下一帧必须是 IDR 帧，是否可以根据情况再决定调用 flush？\n  // windows 某些设备 flush 可能不会被 resolved，所以不能 await flush\n  dec.flush().catch((err) => {\n    if (!(err instanceof Error)) throw err;\n    if (\n      err.message.includes('Decoding error') &&\n      opts.onDecodingError != null\n    ) {\n      opts.onDecodingError(err);\n      return;\n    }\n    // reset 中断解码器，预期会抛出 AbortedError\n    if (!err.message.includes('Aborted due to close')) {\n      throw err;\n    }\n  });\n}\n\nfunction idrNALUOffset(\n  u8Arr: Uint8Array,\n  type: MP4Sample['description']['type'],\n) {\n  if (type !== 'avc1' && type !== 'hvc1') return 0;\n\n  const dv = new DataView(u8Arr.buffer);\n  let i = 0;\n  for (; i < u8Arr.byteLength - 4; ) {\n    if (type === 'avc1' && (dv.getUint8(i + 4) & 0x1f) === 5) {\n      return i;\n    } else if (type === 'hvc1') {\n      const nalUnitType = (dv.getUint8(i + 4) >> 1) & 0x3f;\n      if (nalUnitType === 19 || nalUnitType === 20) return i;\n    }\n    // 跳至下一个 NALU 继续检查\n    i += dv.getUint32(i) + 4;\n  }\n  return -1;\n}\n\nasync function thumbnailByKeyFrame(\n  samples: ExtMP4Sample[],\n  localFile: OPFSToolFile,\n  decConf: VideoDecoderConfig,\n  abortSingl: AbortSignal,\n  time: { start: number; end: number },\n  onOutput: (vf: VideoFrame | null, done: boolean) => void,\n) {\n  const fileReader = await localFile.createReader();\n\n  const chunks = await videosamples2Chunks(\n    samples.filter(\n      (s) =>\n        !s.deleted && s.is_sync && s.cts >= time.start && s.cts <= time.end,\n    ),\n    fileReader,\n  );\n  if (chunks.length === 0 || abortSingl.aborted) return;\n\n  let outputCnt = 0;\n  decodeGoP(createVideoDec(), chunks, {\n    onDecodingError: (err) => {\n      Log.warn('thumbnailsByKeyFrame', err);\n      // 尝试降级一次\n      if (outputCnt === 0) {\n        decodeGoP(createVideoDec(true), chunks, {\n          onDecodingError: (err) => {\n            fileReader.close();\n            Log.error('thumbnailsByKeyFrame retry soft deocde', err);\n          },\n        });\n      } else {\n        onOutput(null, true);\n        fileReader.close();\n      }\n    },\n  });\n\n  function createVideoDec(downgrade = false) {\n    const encoderConf = {\n      ...decConf,\n      ...(downgrade ? { hardwareAcceleration: 'prefer-software' } : {}),\n    } as VideoDecoderConfig;\n    const dec = new VideoDecoder({\n      output: (vf) => {\n        outputCnt += 1;\n        const done = outputCnt === chunks.length;\n        onOutput(vf, done);\n        if (done) {\n          fileReader.close();\n          if (dec.state !== 'closed') dec.close();\n        }\n      },\n      error: (err) => {\n        const errMsg = `thumbnails decoder error: ${err.message}, config: ${JSON.stringify(encoderConf)}, state: ${JSON.stringify(\n          {\n            qSize: dec.decodeQueueSize,\n            state: dec.state,\n            outputCnt,\n            inputCnt: chunks.length,\n          },\n        )}`;\n        Log.error(errMsg);\n        throw Error(errMsg);\n      },\n    });\n    abortSingl.addEventListener('abort', () => {\n      fileReader.close();\n      if (dec.state !== 'closed') dec.close();\n    });\n    dec.configure(encoderConf);\n    return dec;\n  }\n}\n\n// 如果第一帧出现的时间偏移较大，会导致第一帧为黑帧，这里尝试自动消除第一帧前的黑帧\nfunction fixFirstBlackFrame(samples: ExtMP4Sample[]) {\n  let iframeCnt = 0;\n  let minCtsSample: ExtMP4Sample | null = null;\n  // cts 最小表示视频的第一帧\n  for (const s of samples) {\n    if (s.deleted) continue;\n    // 最多检测两个 I 帧之间的帧\n    if (s.is_sync) iframeCnt += 1;\n    if (iframeCnt >= 2) break;\n\n    if (minCtsSample == null || s.cts < minCtsSample.cts) {\n      minCtsSample = s;\n    }\n  }\n  // 200ms 是经验值，自动消除 200ms 内的黑帧，超过则不处理\n  if (minCtsSample != null && minCtsSample.cts < 200e3) {\n    minCtsSample.duration += minCtsSample.cts;\n    minCtsSample.cts = 0;\n  }\n}\n\nfunction memoryUsageInfo() {\n  try {\n    // @ts-ignore\n    const mem = performance.memory;\n    return {\n      jsHeapSizeLimit: mem.jsHeapSizeLimit,\n      totalJSHeapSize: mem.totalJSHeapSize,\n      usedJSHeapSize: mem.usedJSHeapSize,\n      percentUsed: (mem.usedJSHeapSize / mem.jsHeapSizeLimit).toFixed(3),\n      percentTotal: (mem.totalJSHeapSize / mem.jsHeapSizeLimit).toFixed(3),\n    };\n  } catch (err) {\n    return {};\n  }\n}\n","import { decodeImg } from '../av-utils';\nimport { Log } from '@webav/internal-utils';\nimport { IClip } from './iclip';\n\ntype AnimateImgType = 'avif' | 'webp' | 'png' | 'gif';\n\n/**\n * 图像素材，支持动图\n *\n * 普通文字可通过 {@link renderTxt2ImgBitmap} 转换成图片素材\n *\n * @example\n * new ImgClip((await fetch('<img url>')).body);\n *\n * @example\n * new ImgClip(\n *   await renderTxt2ImgBitmap(\n *     '水印',\n *    `font-size:40px; color: white; text-shadow: 2px 2px 6px red;`,\n *   )\n * )\n *\n * @see [视频合成](https://webav-tech.github.io/WebAV/demo/2_1-concat-video)\n */\nexport class ImgClip implements IClip {\n  ready: IClip['ready'];\n\n  #meta = {\n    // 微秒\n    duration: 0,\n    width: 0,\n    height: 0,\n  };\n\n  /**\n   * ⚠️ 静态图片的 duration 为 Infinity\n   *\n   * 使用 Sprite 包装时需要将它的 duration 设置为有限数\n   *\n   */\n  get meta() {\n    return { ...this.#meta };\n  }\n\n  #img: ImageBitmap | null = null;\n\n  #frames: VideoFrame[] = [];\n\n  /**\n   * 静态图片可使用流、ImageBitmap 初始化\n   *\n   * 动图需要使用 VideoFrame[] 或提供图片类型\n   */\n  constructor(\n    dataSource:\n      | ReadableStream\n      | ImageBitmap\n      | VideoFrame[]\n      | { type: `image/${AnimateImgType}`; stream: ReadableStream },\n  ) {\n    const initWithImgBitmap = (imgBitmap: ImageBitmap) => {\n      this.#img = imgBitmap;\n      this.#meta.width = imgBitmap.width;\n      this.#meta.height = imgBitmap.height;\n      this.#meta.duration = Infinity;\n      return { ...this.#meta };\n    };\n\n    if (dataSource instanceof ReadableStream) {\n      this.ready = new Response(dataSource)\n        .blob()\n        .then((data) => createImageBitmap(data))\n        .then(initWithImgBitmap);\n    } else if (dataSource instanceof ImageBitmap) {\n      this.ready = Promise.resolve(initWithImgBitmap(dataSource));\n    } else if (\n      Array.isArray(dataSource) &&\n      dataSource.every((it) => it instanceof VideoFrame)\n    ) {\n      this.#frames = dataSource;\n      const frame = this.#frames[0];\n      if (frame == null) throw Error('The frame count must be greater than 0');\n      this.#meta = {\n        width: frame.displayWidth,\n        height: frame.displayHeight,\n        duration: this.#frames.reduce(\n          (acc, cur) => acc + (cur.duration ?? 0),\n          0,\n        ),\n      };\n      this.ready = Promise.resolve({ ...this.#meta, duration: Infinity });\n    } else if ('type' in dataSource) {\n      this.ready = this.#initAnimateImg(\n        dataSource.stream,\n        dataSource.type,\n      ).then(() => ({\n        width: this.#meta.width,\n        height: this.#meta.height,\n        duration: Infinity,\n      }));\n    } else {\n      throw Error('Illegal arguments');\n    }\n  }\n\n  async #initAnimateImg(\n    stream: ReadableStream,\n    type: `image/${AnimateImgType}`,\n  ) {\n    this.#frames = await decodeImg(stream, type);\n    const firstVf = this.#frames[0];\n    if (firstVf == null) throw Error('No frame available in gif');\n\n    this.#meta = {\n      duration: this.#frames.reduce((acc, cur) => acc + (cur.duration ?? 0), 0),\n      width: firstVf.codedWidth,\n      height: firstVf.codedHeight,\n    };\n    Log.info('ImgClip ready:', this.#meta);\n  }\n\n  tickInterceptor: <T extends Awaited<ReturnType<ImgClip['tick']>>>(\n    time: number,\n    tickRet: T,\n  ) => Promise<T> = async (_, tickRet) => tickRet;\n\n  async tick(time: number): Promise<{\n    video: ImageBitmap | VideoFrame;\n    state: 'success';\n  }> {\n    if (this.#img != null) {\n      return await this.tickInterceptor(time, {\n        video: await createImageBitmap(this.#img),\n        state: 'success',\n      });\n    }\n    const tt = time % this.#meta.duration;\n    return await this.tickInterceptor(time, {\n      video: (\n        this.#frames.find(\n          (f) => tt >= f.timestamp && tt <= f.timestamp + (f.duration ?? 0),\n        ) ?? this.#frames[0]\n      ).clone(),\n      state: 'success',\n    });\n  }\n\n  async split(time: number) {\n    await this.ready;\n    if (this.#img != null) {\n      return [\n        new ImgClip(await createImageBitmap(this.#img)),\n        new ImgClip(await createImageBitmap(this.#img)),\n      ] as [this, this];\n    }\n    let hitIdx = -1;\n    for (let i = 0; i < this.#frames.length; i++) {\n      const vf = this.#frames[i];\n      if (time > vf.timestamp) continue;\n      hitIdx = i;\n      break;\n    }\n    if (hitIdx === -1) throw Error('Not found frame by time');\n    const preSlice = this.#frames\n      .slice(0, hitIdx)\n      .map((vf) => new VideoFrame(vf));\n    const postSlice = this.#frames.slice(hitIdx).map(\n      (vf) =>\n        new VideoFrame(vf, {\n          timestamp: vf.timestamp - time,\n        }),\n    );\n    return [new ImgClip(preSlice), new ImgClip(postSlice)] as [this, this];\n  }\n\n  async clone() {\n    await this.ready;\n    const data =\n      this.#img == null\n        ? this.#frames.map((vf) => vf.clone())\n        : await createImageBitmap(this.#img);\n    return new ImgClip(data) as this;\n  }\n\n  destroy(): void {\n    Log.info('ImgClip destroy');\n    this.#img?.close();\n    this.#frames.forEach((f) => f.close());\n  }\n}\n","import {\n  concatPCMFragments,\n  extractPCM4AudioBuffer,\n  ringSliceFloat32Array,\n} from '../av-utils';\nimport { Log } from '@webav/internal-utils';\nimport { DEFAULT_AUDIO_CONF, IClip } from './iclip';\n\ninterface IAudioClipOpts {\n  loop?: boolean;\n  volume?: number;\n}\n\n/**\n * 音频素材，为创建、编辑音视频功能提供音频数据\n *\n * @example\n * new AudioClip((await fetch('<mp3 url>')).body, {\n *   loop: true,\n * }),\n */\nexport class AudioClip implements IClip {\n  static ctx: AudioContext | null = null;\n\n  ready: IClip['ready'];\n\n  #meta = {\n    // 微秒\n    duration: 0,\n    width: 0,\n    height: 0,\n  };\n\n  /**\n   * 音频元信息\n   *\n   * ⚠️ 注意，这里是转换后（标准化）的元信息，非原始音频元信息\n   */\n  get meta() {\n    return {\n      ...this.#meta,\n      sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n      chanCount: 2,\n    };\n  }\n\n  #chan0Buf = new Float32Array();\n  #chan1Buf = new Float32Array();\n  /**\n   * 获取音频素材完整的 PCM 数据\n   */\n  getPCMData(): Float32Array[] {\n    return [this.#chan0Buf, this.#chan1Buf];\n  }\n\n  #opts;\n\n  /**\n   *\n   * @param dataSource 音频文件流\n   * @param opts 音频配置，控制音量、是否循环\n   */\n  constructor(\n    dataSource: ReadableStream<Uint8Array> | Float32Array[],\n    opts: IAudioClipOpts = {},\n  ) {\n    this.#opts = {\n      loop: false,\n      volume: 1,\n      ...opts,\n    };\n\n    this.ready = this.#init(dataSource).then(() => ({\n      // audio 没有宽高，无需绘制\n      width: 0,\n      height: 0,\n      duration: opts.loop ? Infinity : this.#meta.duration,\n    }));\n  }\n\n  async #init(\n    dataSource: ReadableStream<Uint8Array> | Float32Array[],\n  ): Promise<void> {\n    if (AudioClip.ctx == null) {\n      AudioClip.ctx = new AudioContext({\n        sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n      });\n    }\n\n    const tStart = performance.now();\n    const pcm =\n      dataSource instanceof ReadableStream\n        ? await parseStream2PCM(dataSource, AudioClip.ctx)\n        : dataSource;\n\n    Log.info('Audio clip decoded complete:', performance.now() - tStart);\n\n    const volume = this.#opts.volume;\n    if (volume !== 1) {\n      for (const chan of pcm)\n        for (let i = 0; i < chan.length; i += 1) chan[i] *= volume;\n    }\n\n    this.#meta.duration = (pcm[0].length / DEFAULT_AUDIO_CONF.sampleRate) * 1e6;\n\n    this.#chan0Buf = pcm[0];\n    // 单声道 转 立体声\n    this.#chan1Buf = pcm[1] ?? this.#chan0Buf;\n\n    Log.info(\n      'Audio clip convert to AudioData, time:',\n      performance.now() - tStart,\n    );\n  }\n\n  /**\n   * 拦截 {@link AudioClip.tick} 方法返回的数据，用于对音频数据二次处理\n   * @param time 调用 tick 的时间\n   * @param tickRet tick 返回的数据\n   *\n   * @see [移除视频绿幕背景](https://webav-tech.github.io/WebAV/demo/3_2-chromakey-video)\n   */\n  tickInterceptor: <T extends Awaited<ReturnType<AudioClip['tick']>>>(\n    time: number,\n    tickRet: T,\n  ) => Promise<T> = async (_, tickRet) => tickRet;\n\n  // 微秒\n  #ts = 0;\n  #frameOffset = 0;\n  /**\n   * 返回上次与当前时刻差对应的音频 PCM 数据；\n   *\n   * 若差值超过 3s 或当前时间小于上次时间，则重置状态\n   * @example\n   * tick(0) // => []\n   * tick(1e6) // => [leftChanPCM(1s), rightChanPCM(1s)]\n   *\n   */\n  async tick(time: number): Promise<{\n    audio: Float32Array[];\n    state: 'success' | 'done';\n  }> {\n    if (!this.#opts.loop && time >= this.#meta.duration) {\n      // 待观察：如果time跨度较大，返回done，理论上会丢失一些音频帧\n      return await this.tickInterceptor(time, { audio: [], state: 'done' });\n    }\n\n    const deltaTime = time - this.#ts;\n\n    // reset\n    if (time < this.#ts || deltaTime > 3e6) {\n      this.#ts = time;\n      this.#frameOffset = Math.ceil(\n        (this.#ts / 1e6) * DEFAULT_AUDIO_CONF.sampleRate,\n      );\n      return await this.tickInterceptor(time, {\n        audio: [new Float32Array(0), new Float32Array(0)],\n        state: 'success',\n      });\n    }\n\n    this.#ts = time;\n    const frameCnt = Math.ceil(\n      (deltaTime / 1e6) * DEFAULT_AUDIO_CONF.sampleRate,\n    );\n    const endIdx = this.#frameOffset + frameCnt;\n    const audio = this.#opts.loop\n      ? [\n          ringSliceFloat32Array(this.#chan0Buf, this.#frameOffset, endIdx),\n          ringSliceFloat32Array(this.#chan1Buf, this.#frameOffset, endIdx),\n        ]\n      : [\n          this.#chan0Buf.slice(this.#frameOffset, endIdx),\n          this.#chan1Buf.slice(this.#frameOffset, endIdx),\n        ];\n    this.#frameOffset = endIdx;\n\n    return await this.tickInterceptor(time, { audio, state: 'success' });\n  }\n\n  /**\n   * 按指定时间切割，返回前后两个音频素材\n   * @param time 时间，单位微秒\n   */\n  async split(time: number) {\n    await this.ready;\n    const frameCnt = Math.ceil((time / 1e6) * DEFAULT_AUDIO_CONF.sampleRate);\n    const preSlice = new AudioClip(\n      this.getPCMData().map((chan) => chan.slice(0, frameCnt)),\n      this.#opts,\n    );\n    const postSlice = new AudioClip(\n      this.getPCMData().map((chan) => chan.slice(frameCnt)),\n      this.#opts,\n    );\n    return [preSlice, postSlice] as [this, this];\n  }\n\n  async clone() {\n    await this.ready;\n    const clip = new AudioClip(this.getPCMData(), this.#opts) as this;\n    await clip.ready;\n    return clip;\n  }\n\n  /**\n   * 销毁实例，释放资源\n   */\n  destroy(): void {\n    this.#chan0Buf = new Float32Array(0);\n    this.#chan1Buf = new Float32Array(0);\n    Log.info('---- audioclip destroy ----');\n  }\n}\n\n/**\n * 拼接多个 AudioClip\n */\nexport async function concatAudioClip(\n  clips: AudioClip[],\n  opts?: IAudioClipOpts,\n) {\n  const bufs: Float32Array[][] = [];\n  for (const clip of clips) {\n    await clip.ready;\n    bufs.push(clip.getPCMData());\n  }\n  return new AudioClip(concatPCMFragments(bufs), opts);\n}\n\nasync function parseStream2PCM(\n  stream: ReadableStream<Uint8Array>,\n  ctx: AudioContext | OfflineAudioContext,\n): Promise<Float32Array[]> {\n  const buf = await new Response(stream).arrayBuffer();\n  return extractPCM4AudioBuffer(await ctx.decodeAudioData(buf));\n}\n","import { autoReadStream } from '@webav/internal-utils';\nimport { IClip } from './iclip';\n\n/**\n * 包装实时音视频流，仅用于 [AVCanvas](../../av-canvas/classes/AVCanvas.html)\n *\n * ⚠️ 不可用于 {@link Combinator} ，因为后台合成视频的速度是快于物理时间的，实时流无法提供非实时的数据\n *\n * @example\n * const spr = new VisibleSprite(\n *   new MediaStreamClip(\n *     await navigator.mediaDevices.getUserMedia({ video: true, audio: true, }),\n *   ),\n * );\n * await avCvs.addSprite(spr);\n */\nexport class MediaStreamClip implements IClip {\n  static ctx: AudioContext | null = null;\n\n  ready: IClip['ready'];\n\n  #meta = {\n    // 微秒\n    duration: 0,\n    width: 0,\n    height: 0,\n  };\n\n  get meta() {\n    return {\n      ...this.#meta,\n    };\n  }\n\n  #stopRenderCvs = () => {};\n\n  /**\n   * 实时流的音轨\n   */\n  readonly audioTrack: MediaStreamAudioTrack | null;\n\n  #cvs: OffscreenCanvas | null = null;\n\n  #ms: MediaStream;\n  constructor(ms: MediaStream) {\n    this.#ms = ms;\n    this.audioTrack = ms.getAudioTracks()[0] ?? null;\n    this.#meta.duration = Infinity;\n    const videoTrack = ms.getVideoTracks()[0];\n    if (videoTrack != null) {\n      videoTrack.contentHint = 'motion';\n      this.ready = new Promise((resolve) => {\n        this.#stopRenderCvs = renderVideoTrackToCvs(videoTrack, (cvs) => {\n          this.#meta.width = cvs.width;\n          this.#meta.height = cvs.height;\n          this.#cvs = cvs;\n          resolve(this.meta);\n        });\n      });\n    } else {\n      this.ready = Promise.resolve(this.meta);\n    }\n  }\n\n  async tick(): Promise<{\n    video: ImageBitmap | null;\n    audio: Float32Array[];\n    state: 'success';\n  }> {\n    return {\n      video: this.#cvs == null ? null : await createImageBitmap(this.#cvs),\n      audio: [],\n      state: 'success',\n    };\n  }\n\n  async split() {\n    return [await this.clone(), await this.clone()] as [this, this];\n  }\n\n  async clone() {\n    return new MediaStreamClip(this.#ms.clone()) as this;\n  }\n\n  destroy(): void {\n    this.#ms.getTracks().forEach((t) => t.stop());\n    this.#stopRenderCvs();\n  }\n}\n\nfunction renderVideoTrackToCvs(\n  track: MediaStreamVideoTrack,\n  onOffscreenCanvasReady: (cvs: OffscreenCanvas) => void,\n) {\n  let emitFF = false;\n  let cvsCtx: OffscreenCanvasRenderingContext2D;\n  return autoReadStream(\n    new MediaStreamTrackProcessor({\n      track,\n    }).readable,\n    {\n      onChunk: async (frame) => {\n        if (!emitFF) {\n          const { displayHeight, displayWidth } = frame;\n          const width = displayWidth ?? 0;\n          const height = displayHeight ?? 0;\n          const cvs = new OffscreenCanvas(width, height);\n          cvsCtx = cvs.getContext('2d')!;\n          onOffscreenCanvasReady(cvs);\n          emitFF = true;\n        }\n        cvsCtx.drawImage(frame, 0, 0);\n        frame.close();\n      },\n      onDone: async () => {},\n    },\n  );\n}\n","import { IClip } from './iclip';\n\ninterface IEmbedSubtitlesOpts {\n  color?: string;\n  textBgColor?: string | null;\n  type?: 'srt';\n  fontFamily?: string;\n  fontSize?: number;\n  letterSpacing?: string | null;\n  // 字幕偏离底部的距离\n  bottomOffset?: number;\n  strokeStyle?: string;\n  lineWidth?: number | null;\n  lineCap?: CanvasLineCap | null;\n  lineJoin?: CanvasLineJoin | null;\n  textShadow?: {\n    offsetX: number;\n    offsetY: number;\n    blur: number;\n    color: string;\n  };\n  videoWidth: number;\n  videoHeight: number;\n}\n\ndeclare global {\n  interface OffscreenCanvasRenderingContext2D {\n    letterSpacing: string;\n  }\n}\n\ninterface SubtitleStruct {\n  start: number;\n  end: number;\n  text: string;\n}\n\n/**\n * 嵌入式字幕，将字幕（目前仅支持 SRT 格式）嵌入视频画面中\n *\n * @example\n * const es = new EmbedSubtitlesClip(srtSubtitleStr, {\n *   videoWidth: 1280,\n *   videoHeight: 720,\n *   fontFamily: 'Noto Sans SC',\n *   color: 'white',\n * });\n */\nexport class EmbedSubtitlesClip implements IClip {\n  ready: IClip['ready'];\n\n  #subtitles: SubtitleStruct[] = [];\n\n  #meta = {\n    width: 0,\n    height: 0,\n    duration: 0,\n  };\n\n  get meta() {\n    return { ...this.#meta };\n  }\n\n  #opts: Required<IEmbedSubtitlesOpts> = {\n    color: '#FFF',\n    textBgColor: null,\n    type: 'srt',\n    fontSize: 30,\n    letterSpacing: null,\n    bottomOffset: 30,\n    fontFamily: 'Noto Sans SC',\n    strokeStyle: '#000',\n    lineWidth: null,\n    lineCap: null,\n    lineJoin: null,\n    textShadow: {\n      offsetX: 2,\n      offsetY: 2,\n      blur: 4,\n      color: '#000',\n    },\n    videoWidth: 1280,\n    videoHeight: 720,\n  };\n\n  #cvs: OffscreenCanvas;\n  #ctx: OffscreenCanvasRenderingContext2D;\n\n  #lastVF: VideoFrame | null = null;\n\n  #lineHeight = 0;\n  #linePadding = 0;\n\n  constructor(content: string | SubtitleStruct[], opts: IEmbedSubtitlesOpts) {\n    this.#subtitles = Array.isArray(content)\n      ? content\n      : parseSrt(content).map(({ start, end, text }) => ({\n          start: start * 1e6,\n          end: end * 1e6,\n          text,\n        }));\n    if (this.#subtitles.length === 0) throw Error('No subtitles content');\n\n    this.#opts = Object.assign(this.#opts, opts);\n    // 如果需要绘制背景，则需要给文字添加边距\n    this.#linePadding =\n      opts.textBgColor == null ? 0 : (opts.fontSize ?? 50) * 0.2;\n\n    const { fontSize, fontFamily, videoWidth, videoHeight, letterSpacing } =\n      this.#opts;\n    this.#lineHeight = fontSize + this.#linePadding * 2;\n    this.#cvs = new OffscreenCanvas(videoWidth, videoHeight);\n    this.#ctx = this.#cvs.getContext('2d')!;\n    this.#ctx.font = `${fontSize}px ${fontFamily}`;\n    this.#ctx.textAlign = 'center';\n    this.#ctx.textBaseline = 'top';\n    this.#ctx.letterSpacing = letterSpacing ?? '0px';\n\n    this.#meta = {\n      width: videoWidth,\n      height: videoHeight,\n      duration: this.#subtitles.at(-1)?.end ?? 0,\n    };\n    // 字幕的宽高 由视频画面内容决定\n    this.ready = Promise.resolve(this.meta);\n  }\n\n  #renderTxt(txt: string) {\n    const lines = txt\n      .split('\\n')\n      .reverse()\n      .map((t) => t.trim());\n\n    const { width, height } = this.#cvs;\n\n    const {\n      color,\n      fontSize,\n      textBgColor,\n      textShadow,\n      strokeStyle,\n      lineWidth,\n      lineCap,\n      lineJoin,\n      bottomOffset,\n    } = this.#opts;\n    const ctx = this.#ctx;\n\n    ctx.clearRect(0, 0, width, height);\n    ctx.globalAlpha = 0.6;\n    // 测试canvas背景\n    // ctx.fillStyle = 'red'\n    // ctx.fillRect(0, 0, this.#cvs.width, this.#cvs.height)\n\n    let bottomDistance = bottomOffset;\n    for (const lineStr of lines) {\n      const txtMeas = ctx.measureText(lineStr);\n      const centerX = width / 2;\n      if (textBgColor != null) {\n        ctx.shadowOffsetX = 0;\n        ctx.shadowOffsetY = 0;\n        ctx.shadowBlur = 0;\n        // 字幕背景\n        ctx.fillStyle = textBgColor;\n        ctx.globalAlpha = 0.5;\n        ctx.fillRect(\n          centerX - txtMeas.actualBoundingBoxLeft - this.#linePadding,\n          height - bottomDistance - this.#lineHeight,\n          txtMeas.width + this.#linePadding * 2,\n          this.#lineHeight,\n        );\n      } else {\n      }\n\n      ctx.shadowColor = textShadow.color;\n      ctx.shadowOffsetX = textShadow.offsetX;\n      ctx.shadowOffsetY = textShadow.offsetY;\n      ctx.shadowBlur = textShadow.blur;\n\n      ctx.globalAlpha = 1;\n\n      if (strokeStyle != null) {\n        ctx.lineWidth = lineWidth ?? fontSize / 6;\n        if (lineCap != null) ctx.lineCap = lineCap;\n        if (lineJoin != null) ctx.lineJoin = lineJoin;\n        ctx.strokeStyle = strokeStyle;\n        ctx.strokeText(\n          lineStr,\n          centerX,\n          height - bottomDistance - this.#lineHeight + this.#linePadding,\n        );\n      }\n\n      ctx.fillStyle = color;\n      ctx.fillText(\n        lineStr,\n        centerX,\n        height - bottomDistance - this.#lineHeight + this.#linePadding,\n      );\n\n      // 多行，底部偏移距离叠加\n      bottomDistance += this.#lineHeight + fontSize * 0.2;\n    }\n  }\n\n  /**\n   * @see {@link IClip.tick}\n   */\n  async tick(time: number): Promise<{\n    video?: VideoFrame;\n    state: 'done' | 'success';\n  }> {\n    if (\n      this.#lastVF != null &&\n      time >= this.#lastVF.timestamp &&\n      time <= this.#lastVF.timestamp + (this.#lastVF.duration ?? 0)\n    ) {\n      return { video: this.#lastVF.clone(), state: 'success' };\n    }\n\n    let i = 0;\n    for (; i < this.#subtitles.length; i += 1) {\n      if (time <= this.#subtitles[i].end) break;\n    }\n\n    const it = this.#subtitles[i] ?? this.#subtitles.at(-1);\n    if (time > it.end) return { state: 'done' };\n    if (time < it.start) {\n      // 此时无字幕内容，清空画布\n      this.#ctx.clearRect(0, 0, this.#cvs.width, this.#cvs.height);\n      const vf = new VideoFrame(this.#cvs, {\n        timestamp: time,\n        // 直到下个字幕出现的时机\n        duration: it.start - time,\n      });\n      this.#lastVF?.close();\n      this.#lastVF = vf;\n\n      return { video: vf.clone(), state: 'success' };\n    }\n\n    this.#renderTxt(it.text);\n\n    const vf = new VideoFrame(this.#cvs, {\n      timestamp: time,\n      duration: it.end - time,\n    });\n    this.#lastVF?.close();\n    this.#lastVF = vf;\n\n    return { video: vf.clone(), state: 'success' };\n  }\n\n  /**\n   * @see {@link IClip.split}\n   */\n  async split(time: number) {\n    await this.ready;\n    let hitIdx = -1;\n    for (let i = 0; i < this.#subtitles.length; i++) {\n      const sub = this.#subtitles[i];\n      if (time > sub.start) continue;\n      hitIdx = i;\n      break;\n    }\n    if (hitIdx === -1) throw Error('Not found subtitle by time');\n    const preSlice = this.#subtitles.slice(0, hitIdx).map((s) => ({ ...s }));\n    let preLastIt = preSlice.at(-1);\n    let postFirstIt = null;\n    // 切割时间命中字幕区间，需要将当前字幕元素拆成前后两份\n    if (preLastIt != null && preLastIt.end > time) {\n      postFirstIt = {\n        start: 0,\n        end: preLastIt.end - time,\n        text: preLastIt.text,\n      };\n\n      preLastIt.end = time;\n    }\n    const postSlice = this.#subtitles\n      .slice(hitIdx)\n      .map((s) => ({ ...s, start: s.start - time, end: s.end - time }));\n    if (postFirstIt != null) postSlice.unshift(postFirstIt);\n    return [\n      new EmbedSubtitlesClip(preSlice, this.#opts),\n      new EmbedSubtitlesClip(postSlice, this.#opts),\n    ] as [this, this];\n  }\n\n  /**\n   * @see {@link IClip.clone}\n   */\n  async clone() {\n    return new EmbedSubtitlesClip(this.#subtitles.slice(0), this.#opts) as this;\n  }\n\n  /**\n   * @see {@link IClip.destroy}\n   */\n  destroy() {\n    this.#lastVF?.close();\n  }\n}\n\n// SRT字幕格式 https://www.cnblogs.com/tocy/p/subtitle-format-srt.html\nfunction srtTimeToSeconds(time: string) {\n  const match = time.match(/(\\d{2}):(\\d{2}):(\\d{2}),(\\d{3})/);\n  if (match == null) throw Error(`time format error: ${time}`);\n\n  const hours = Number(match[1]);\n  const minutes = Number(match[2]);\n  const seconds = Number(match[3]);\n  const milliseconds = Number(match[4]);\n\n  return hours * 60 * 60 + minutes * 60 + seconds + milliseconds / 1000;\n}\n\nfunction parseSrt(srt: string) {\n  return (\n    srt\n      .split(/\\r|\\n/)\n      .map((s) => s.trim())\n      .filter((str) => str.length > 0)\n      // 匹配时间戳标记行，匹配失败的为字幕内容\n      .map((s) => ({\n        lineStr: s,\n        match: s.match(\n          /(\\d{2}:\\d{2}:\\d{2},\\d{3}) --> (\\d{2}:\\d{2}:\\d{2},\\d{3})/,\n        ),\n      }))\n      // 过滤掉时间上一行的数字标记\n      .filter(\n        ({ lineStr }, idx, source) =>\n          !(/^\\d+$/.test(lineStr) && source[idx + 1]?.match != null),\n      )\n      // 按时间标记行聚合，拼接字幕内容到 text 字段\n      .reduce(\n        (acc, { lineStr, match }) => {\n          if (match == null) {\n            const last = acc.at(-1);\n            if (last == null) return acc;\n\n            last.text += last.text.length === 0 ? lineStr : `\\n${lineStr}`;\n          } else {\n            acc.push({\n              start: srtTimeToSeconds(match[1]),\n              end: srtTimeToSeconds(match[2]),\n              text: '',\n            });\n          }\n\n          return acc;\n        },\n        [] as Array<{\n          start: number;\n          end: number;\n          text: string;\n        }>,\n      )\n  );\n}\n","import mp4box, {\n  MP4ArrayBuffer,\n  MP4File,\n  MP4Info,\n  MP4Sample,\n} from '@webav/mp4box.js';\n\n/**\n * 将原始字节流转换成 MP4Sample 流\n */\nexport class SampleTransform {\n  readable: ReadableStream<\n    | {\n        chunkType: 'ready';\n        data: { info: MP4Info; file: MP4File };\n      }\n    | {\n        chunkType: 'samples';\n        data: { id: number; type: 'video' | 'audio'; samples: MP4Sample[] };\n      }\n  >;\n\n  writable: WritableStream<Uint8Array>;\n\n  #inputBufOffset = 0;\n\n  constructor() {\n    const file = mp4box.createFile();\n    let streamCancelled = false;\n    this.readable = new ReadableStream(\n      {\n        start: (ctrl) => {\n          file.onReady = (info) => {\n            const vTrackId = info.videoTracks[0]?.id;\n            if (vTrackId != null)\n              file.setExtractionOptions(vTrackId, 'video', { nbSamples: 100 });\n\n            const aTrackId = info.audioTracks[0]?.id;\n            if (aTrackId != null)\n              file.setExtractionOptions(aTrackId, 'audio', { nbSamples: 100 });\n\n            ctrl.enqueue({ chunkType: 'ready', data: { info, file } });\n            file.start();\n          };\n\n          const releasedCnt: Record<number, number> = {};\n          file.onSamples = (id, type, samples) => {\n            ctrl.enqueue({\n              chunkType: 'samples',\n              data: { id, type, samples: samples.map((s) => ({ ...s })) },\n            });\n            releasedCnt[id] = (releasedCnt[id] ?? 0) + samples.length;\n            file.releaseUsedSamples(id, releasedCnt[id]);\n          };\n\n          file.onFlush = () => {\n            ctrl.close();\n          };\n        },\n        cancel: () => {\n          file.stop();\n          streamCancelled = true;\n        },\n      },\n      {\n        // 每条消息 100 个 samples\n        highWaterMark: 50,\n      },\n    );\n\n    this.writable = new WritableStream({\n      write: async (ui8Arr) => {\n        if (streamCancelled) {\n          this.writable.abort();\n          return;\n        }\n\n        const inputBuf = ui8Arr.buffer as MP4ArrayBuffer;\n        inputBuf.fileStart = this.#inputBufOffset;\n        this.#inputBufOffset += inputBuf.byteLength;\n        file.appendBuffer(inputBuf);\n      },\n      close: () => {\n        file.flush();\n        file.stop();\n        file.onFlush?.();\n      },\n    });\n  }\n}\n","import mp4box, {\n  MP4File,\n  MP4Sample,\n  SampleOpts,\n  TrakBoxParser,\n} from '@webav/mp4box.js';\nimport { autoReadStream, file2stream, Log } from '@webav/internal-utils';\nimport {\n  extractPCM4AudioData,\n  extractPCM4AudioBuffer,\n  mixinPCM,\n  ringSliceFloat32Array,\n  concatPCMFragments,\n} from '../av-utils';\nimport { DEFAULT_AUDIO_CONF } from '../clips';\nimport { SampleTransform } from './sample-transform';\nimport { extractFileConfig } from './mp4box-utils';\nimport { tmpfile, write } from 'opfs-tools';\n\nfunction fixMP4BoxFileDuration(\n  inMP4File: MP4File,\n): () => Promise<ReadableStream<Uint8Array> | null> {\n  let sendedBoxIdx = 0;\n  const boxes = inMP4File.boxes;\n  const tracks: Array<{ track: TrakBoxParser; id: number }> = [];\n  let totalDuration = 0;\n\n  async function write2TmpFile() {\n    const buf = box2Buf(boxes, sendedBoxIdx);\n    sendedBoxIdx = boxes.length;\n    // 释放引用，避免内存泄露\n    // todo: use unsafeReleaseMP4BoxFile\n    tracks.forEach(({ track, id }) => {\n      const s = track.samples.at(-1);\n      if (s != null)\n        totalDuration = Math.max(totalDuration, s.cts + s.duration);\n\n      inMP4File.releaseUsedSamples(id, track.samples.length);\n      track.samples = [];\n    });\n    inMP4File.mdats = [];\n    inMP4File.moofs = [];\n    if (buf != null) await tmpFileWriter?.write(buf);\n  }\n\n  let moovPrevBoxes: typeof boxes = [];\n  function moovBoxReady() {\n    if (moovPrevBoxes.length > 0) return true;\n\n    const moovIdx = boxes.findIndex((box) => box.type === 'moov');\n    if (moovIdx === -1) return false;\n\n    moovPrevBoxes = boxes.slice(0, moovIdx + 1);\n    sendedBoxIdx = moovIdx + 1;\n\n    if (tracks.length === 0) {\n      for (let i = 1; true; i += 1) {\n        const track = inMP4File.getTrackById(i);\n        if (track == null) break;\n        tracks.push({ track, id: i });\n      }\n    }\n\n    return true;\n  }\n\n  let timerId = 0;\n  // 把 moov 之外的 box 先写入临时文件，待更新 duration 之后再拼接临时文件\n  const postFile = tmpfile();\n  let tmpFileWriter: Awaited<\n    ReturnType<ReturnType<typeof tmpfile>['createWriter']>\n  > | null = null;\n\n  const initPromise = (async () => {\n    tmpFileWriter = await postFile.createWriter();\n\n    timerId = self.setInterval(() => {\n      if (!moovBoxReady()) return;\n      write2TmpFile();\n    }, 100);\n  })();\n\n  let stoped = false;\n  return async () => {\n    if (stoped) throw Error('File exported');\n    stoped = true;\n\n    await initPromise;\n    clearInterval(timerId);\n\n    if (!moovBoxReady() || tmpFileWriter == null) return null;\n    inMP4File.flush();\n    await write2TmpFile();\n    await tmpFileWriter?.close();\n\n    const moov = moovPrevBoxes.find((box) => box.type === 'moov') as\n      | typeof inMP4File.moov\n      | undefined;\n    if (moov == null) return null;\n\n    moov.mvhd.duration = totalDuration;\n\n    const rsFile = tmpfile();\n    const buf = box2Buf(moovPrevBoxes, 0)!;\n    await write(rsFile, buf);\n    await write(rsFile, postFile, { overwrite: false });\n\n    return await rsFile.stream();\n  };\n\n  function box2Buf(source: typeof boxes, startIdx: number): Uint8Array | null {\n    if (startIdx >= source.length) return null;\n\n    const ds = new mp4box.DataStream();\n    ds.endianness = mp4box.DataStream.BIG_ENDIAN;\n\n    for (let i = startIdx; i < source.length; i++) {\n      if (source[i] === null) continue;\n      source[i].write(ds);\n      delete source[i];\n    }\n    return new Uint8Array(ds.buffer);\n  }\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\n/**\n * 快速拼接多个mp4 文件流，要求所有 mp4 的属性一致，\n * 属性包括（不限于）：音视频编码格式、分辨率、采样率\n *\n * @param streams 一个包含 Uint8Array 的可读流数组。\n * @returns 返回一个 Promise，该 Promise 在解析时返回一个包含合并后的 MP4 数据的可读流。\n * @throws 如果无法从流生成文件，将抛出错误。\n *\n * @example\n * const streams = [stream1, stream2, stream3];\n * const resultStream = await fastConcatMP4(streams);\n */\nexport async function fastConcatMP4(\n  streams: ReadableStream<Uint8Array>[],\n): Promise<ReadableStream<Uint8Array>> {\n  const outfile = mp4box.createFile();\n\n  const dumpFile = fixMP4BoxFileDuration(outfile);\n  await concatStreamsToMP4BoxFile(streams, outfile);\n  const outStream = await dumpFile();\n  if (outStream == null) throw Error('Can not generate file from streams');\n  return outStream;\n}\n\nasync function concatStreamsToMP4BoxFile(\n  streams: ReadableStream<Uint8Array>[],\n  outfile: MP4File,\n) {\n  let vTrackId = 0;\n  let vDTS = 0;\n  let vCTS = 0;\n  let aTrackId = 0;\n  let aDTS = 0;\n  let aCTS = 0;\n  // ts bug, 不能正确识别类型\n  let lastVSamp: any = null;\n  let lastASamp: any = null;\n  for (const stream of streams) {\n    await new Promise<void>(async (resolve) => {\n      autoReadStream(stream.pipeThrough(new SampleTransform()), {\n        onDone: resolve,\n        onChunk: async ({ chunkType, data }) => {\n          if (chunkType === 'ready') {\n            const { videoTrackConf, audioTrackConf } = extractFileConfig(\n              data.file,\n              data.info,\n            );\n            if (vTrackId === 0 && videoTrackConf != null) {\n              vTrackId = outfile.addTrack(videoTrackConf);\n            }\n            if (aTrackId === 0 && audioTrackConf != null) {\n              aTrackId = outfile.addTrack(audioTrackConf);\n            }\n          } else if (chunkType === 'samples') {\n            const { type, samples } = data;\n            const trackId = type === 'video' ? vTrackId : aTrackId;\n            const offsetDTS = type === 'video' ? vDTS : aDTS;\n            const offsetCTS = type === 'video' ? vCTS : aCTS;\n\n            samples.forEach((s) => {\n              outfile.addSample(trackId, s.data, {\n                duration: s.duration,\n                dts: s.dts + offsetDTS,\n                cts: s.cts + offsetCTS,\n                is_sync: s.is_sync,\n              });\n            });\n\n            const lastSamp = samples.at(-1);\n            if (lastSamp == null) return;\n            if (type === 'video') {\n              lastVSamp = lastSamp;\n            } else if (type === 'audio') {\n              lastASamp = lastSamp;\n            }\n          }\n        },\n      });\n    });\n    if (lastVSamp != null) {\n      vDTS += lastVSamp.dts;\n      vCTS += lastVSamp.cts;\n    }\n    if (lastASamp != null) {\n      aDTS += lastASamp.dts;\n      aCTS += lastASamp.cts;\n    }\n  }\n}\n\n/**\n * 为 WebAV 生成的 fmp4 文件设置正确的时长值\n */\nexport async function fixFMP4Duration(\n  stream: ReadableStream<Uint8Array>,\n): Promise<ReadableStream<Uint8Array>> {\n  return await fastConcatMP4([stream]);\n}\n\n/**\n * 创建 MP4 音频样本解码器。\n * @param adConf - 音频解码器配置参数 {@link AudioDecoderConfig}。\n * @returns 返回一个对象，包含 `decode` 和 `close` 方法。\n * - `decode` 方法用于解码 MP4 音频样本，返回解码后的音频数据数组。\n * - `close` 方法用于关闭音频解码器。\n */\nfunction createMP4AudioSampleDecoder(\n  adConf: Parameters<AudioDecoder['configure']>[0],\n) {\n  let cacheAD: AudioData[] = [];\n  const adDecoder = new AudioDecoder({\n    output: (ad) => {\n      cacheAD.push(ad);\n    },\n    error: Log.error,\n  });\n  adDecoder.configure(adConf);\n\n  return {\n    decode: async (ss: MP4Sample[]) => {\n      ss.forEach((s) => {\n        adDecoder.decode(\n          new EncodedAudioChunk({\n            type: s.is_sync ? 'key' : 'delta',\n            timestamp: (1e6 * s.cts) / s.timescale,\n            duration: (1e6 * s.duration) / s.timescale,\n            data: s.data,\n          }),\n        );\n      });\n\n      await adDecoder.flush();\n\n      const rs = cacheAD;\n      cacheAD = [];\n\n      return rs;\n    },\n    close: () => {\n      adDecoder.close();\n    },\n  };\n}\n\n// 音频编码与解码API有很大区别，\n// 是因为编码中途调用 AudioEncoder.flush ，会导致声音听起来卡顿\nfunction createMP4AudioSampleEncoder(\n  aeConf: Parameters<AudioEncoder['configure']>[0],\n  onOutput: (s: ReturnType<typeof chunk2MP4SampleOpts>) => void,\n) {\n  const encoderConf = {\n    codec: aeConf.codec,\n    sampleRate: aeConf.sampleRate,\n    numberOfChannels: aeConf.numberOfChannels,\n  } as const;\n\n  const adEncoder = new AudioEncoder({\n    output: (chunk) => {\n      onOutput(chunk2MP4SampleOpts(chunk));\n    },\n    error: (err) => {\n      Log.error('AudioEncoder error:', err, ', config:', encoderConf);\n    },\n  });\n\n  adEncoder.configure(encoderConf);\n\n  // 保留一个音频数据，用于最后做声音淡出\n  let lastData: { data: Float32Array; ts: number } | null = null;\n\n  function createAD(data: Float32Array, ts: number) {\n    return new AudioData({\n      timestamp: ts,\n      numberOfChannels: aeConf.numberOfChannels,\n      numberOfFrames: data.length / aeConf.numberOfChannels,\n      sampleRate: aeConf.sampleRate,\n      format: 'f32-planar',\n      data,\n    });\n  }\n  return {\n    encode: async (data: Float32Array, ts: number) => {\n      if (lastData != null) {\n        adEncoder.encode(createAD(lastData.data, lastData.ts));\n      }\n      lastData = { data, ts };\n    },\n    stop: async () => {\n      if (lastData != null) {\n        // 副作用修改数据\n        audioFade(lastData.data, aeConf.numberOfChannels, aeConf.sampleRate);\n        adEncoder.encode(createAD(lastData.data, lastData.ts));\n        lastData = null;\n      }\n      await adEncoder.flush();\n      adEncoder.close();\n    },\n  };\n}\n\n/**\n * 音频线性淡出，避免 POP 声\n * 副作用调整音量值\n */\nfunction audioFade(pcmData: Float32Array, chanCnt: number, sampleRate: number) {\n  const dataLen = pcmData.length - 1;\n  // 避免超出边界，最长 500ms 的淡出时间\n  const fadeLen = Math.min(sampleRate / 2, dataLen);\n  for (let i = 0; i < fadeLen; i++) {\n    for (let j = 1; j <= chanCnt; j++) {\n      // 从尾部开始，调整每个声道音量值\n      pcmData[Math.floor(dataLen / j) - i] *= i / fadeLen;\n    }\n  }\n}\n\n/**\n * 视频配音；混合 MP4 与音频文件，仅重编码音频，视频轨道不变\n * @param mp4Stream - MP4 流\n * @param audio - 音频信息\n * @param audio.stream - 音频数据流\n * @param audio.volume - 音频音量\n * @param audio.loop - 音频时长小于视频时，是否循环使用音频流\n * @returns 输出混合后的音频流\n */\nexport function mixinMP4AndAudio(\n  mp4Stream: ReadableStream<Uint8Array>,\n  audio: {\n    stream: ReadableStream<Uint8Array>;\n    volume: number;\n    loop: boolean;\n  },\n) {\n  Log.info('mixinMP4AndAudio, opts:', {\n    volume: audio.volume,\n    loop: audio.loop,\n  });\n\n  const outfile = mp4box.createFile();\n  const { stream: outStream, stop: stopOut } = file2stream(outfile, 500);\n\n  let audioSampleDecoder: ReturnType<\n    typeof createMP4AudioSampleDecoder\n  > | null = null;\n\n  let audioSampleEncoder: ReturnType<\n    typeof createMP4AudioSampleEncoder\n  > | null = null;\n\n  let inputAudioPCM: Float32Array[] = [];\n\n  let vTrackId = 0;\n  let aTrackId = 0;\n  let audioOffset = 0;\n  let mp4HasAudio = true;\n  let sampleRate = DEFAULT_AUDIO_CONF.sampleRate as number;\n  autoReadStream(mp4Stream.pipeThrough(new SampleTransform()), {\n    onDone: async () => {\n      await audioSampleEncoder?.stop();\n      audioSampleDecoder?.close();\n      stopOut();\n    },\n    onChunk: async ({ chunkType, data }) => {\n      if (chunkType === 'ready') {\n        const { videoTrackConf, audioTrackConf, audioDecoderConf } =\n          extractFileConfig(data.file, data.info);\n        if (vTrackId === 0 && videoTrackConf != null) {\n          vTrackId = outfile.addTrack(videoTrackConf);\n        }\n\n        const safeAudioTrackConf = audioTrackConf ?? {\n          timescale: 1e6,\n          samplerate: sampleRate,\n          channel_count: DEFAULT_AUDIO_CONF.channelCount,\n          hdlr: 'soun',\n          name: 'SoundHandler',\n          type: 'mp4a',\n        };\n        if (aTrackId === 0) {\n          aTrackId = outfile.addTrack(safeAudioTrackConf);\n          sampleRate = audioTrackConf?.samplerate ?? sampleRate;\n          mp4HasAudio = audioTrackConf == null ? false : true;\n        }\n        const audioCtx = new AudioContext({ sampleRate });\n        inputAudioPCM = extractPCM4AudioBuffer(\n          await audioCtx.decodeAudioData(\n            await new Response(audio.stream).arrayBuffer(),\n          ),\n        );\n\n        if (audioDecoderConf != null) {\n          audioSampleDecoder = createMP4AudioSampleDecoder(audioDecoderConf);\n        }\n        audioSampleEncoder = createMP4AudioSampleEncoder(\n          audioDecoderConf ?? {\n            codec:\n              safeAudioTrackConf.type === 'mp4a'\n                ? DEFAULT_AUDIO_CONF.codec\n                : safeAudioTrackConf.type,\n            numberOfChannels: safeAudioTrackConf.channel_count,\n            sampleRate: safeAudioTrackConf.samplerate,\n          },\n          (s) => outfile.addSample(aTrackId, s.data, s),\n        );\n      } else if (chunkType === 'samples') {\n        const { id, type, samples } = data;\n        if (type === 'video') {\n          samples.forEach((s) => outfile.addSample(id, s.data, s));\n\n          if (!mp4HasAudio) await addInputAudio2Track(samples);\n          return;\n        }\n\n        if (type === 'audio') await mixinAudioSampleAndInputPCM(samples);\n      }\n    },\n  });\n\n  function getInputAudioSlice(len: number) {\n    const rs = inputAudioPCM.map((chanBuf) =>\n      audio.loop\n        ? ringSliceFloat32Array(chanBuf, audioOffset, audioOffset + len)\n        : chanBuf.slice(audioOffset, audioOffset + len),\n    );\n    audioOffset += len;\n\n    if (audio.volume !== 1) {\n      for (const buf of rs)\n        for (let i = 0; i < buf.length; i++) buf[i] *= audio.volume;\n    }\n\n    return rs;\n  }\n\n  async function addInputAudio2Track(vdieoSamples: MP4Sample[]) {\n    const firstSamp = vdieoSamples[0];\n    const lastSamp = vdieoSamples[vdieoSamples.length - 1];\n    const pcmLength = Math.floor(\n      ((lastSamp.cts + lastSamp.duration - firstSamp.cts) /\n        lastSamp.timescale) *\n        sampleRate,\n    );\n    const audioDataBuf = mixinPCM([getInputAudioSlice(pcmLength)]);\n    if (audioDataBuf.length === 0) return;\n    audioSampleEncoder?.encode(\n      audioDataBuf,\n      (firstSamp.cts / firstSamp.timescale) * 1e6,\n    );\n  }\n\n  async function mixinAudioSampleAndInputPCM(samples: MP4Sample[]) {\n    if (audioSampleDecoder == null) return;\n\n    // 1. 先解码mp4音频\n    // [[chan0, chan1], [chan0, chan1]...]\n    const pcmFragments = (await audioSampleDecoder.decode(samples)).map(\n      extractPCM4AudioData,\n    );\n    // [chan0, chan1]\n    const mp4AudioPCM = concatPCMFragments(pcmFragments);\n    const inputAudioPCM = getInputAudioSlice(mp4AudioPCM[0].length);\n    const firstSamp = samples[0];\n\n    // 3. 重编码音频\n    audioSampleEncoder?.encode(\n      // 2. 混合输入的音频\n      mixinPCM([mp4AudioPCM, inputAudioPCM]),\n      (firstSamp.cts / firstSamp.timescale) * 1e6,\n    );\n  }\n\n  return outStream;\n}\n","// 改编自 https://jameshfisher.com/2020/08/11/production-ready-green-screen-in-the-browser/\nconst vertexShader = `#version 300 es\n  layout (location = 0) in vec4 a_position;\n  layout (location = 1) in vec2 a_texCoord;\n  out vec2 v_texCoord;\n  void main () {\n    gl_Position = a_position;\n    v_texCoord = a_texCoord;\n  }\n`;\n\nconst fragmentShader = `#version 300 es\nprecision mediump float;\nout vec4 FragColor;\nin vec2 v_texCoord;\n\nuniform sampler2D frameTexture;\nuniform vec3 keyColor;\n\n// 色度的相似度计算\nuniform float similarity;\n// 透明度的平滑度计算\nuniform float smoothness;\n// 降低绿幕饱和度，提高抠图准确度\nuniform float spill;\n\nvec2 RGBtoUV(vec3 rgb) {\n  return vec2(\n    rgb.r * -0.169 + rgb.g * -0.331 + rgb.b *  0.5    + 0.5,\n    rgb.r *  0.5   + rgb.g * -0.419 + rgb.b * -0.081  + 0.5\n  );\n}\n\nvoid main() {\n  // 获取当前像素的rgba值\n  vec4 rgba = texture(frameTexture, v_texCoord);\n  // 计算当前像素与绿幕像素的色度差值\n  vec2 chromaVec = RGBtoUV(rgba.rgb) - RGBtoUV(keyColor);\n  // 计算当前像素与绿幕像素的色度距离（向量长度）, 越相像则色度距离越小\n  float chromaDist = sqrt(dot(chromaVec, chromaVec));\n  // 设置了一个相似度阈值，baseMask为负，则表明是绿幕，为正则表明不是绿幕\n  float baseMask = chromaDist - similarity;\n  // 如果baseMask为负数，fullMask等于0；baseMask为正数，越大，则透明度越低\n  float fullMask = pow(clamp(baseMask / smoothness, 0., 1.), 1.5);\n  rgba.a = fullMask; // 设置透明度\n  // 如果baseMask为负数，spillVal等于0；baseMask为整数，越小，饱和度越低\n  float spillVal = pow(clamp(baseMask / spill, 0., 1.), 1.5);\n  float desat = clamp(rgba.r * 0.2126 + rgba.g * 0.7152 + rgba.b * 0.0722, 0., 1.); // 计算当前像素的灰度值\n  rgba.rgb = mix(vec3(desat, desat, desat), rgba.rgb, spillVal);\n  FragColor = rgba;\n}\n`;\n\nconst POINT_POS = [-1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1];\nconst TEX_COORD_POS = [0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1];\n\n//  初始化着色器程序，让 WebGL 知道如何绘制我们的数据\nfunction initShaderProgram(\n  gl: WebGLRenderingContext,\n  vsSource: string,\n  fsSource: string,\n) {\n  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource)!;\n  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource)!;\n\n  // 创建着色器程序\n  const shaderProgram = gl.createProgram()!;\n  gl.attachShader(shaderProgram, vertexShader);\n  gl.attachShader(shaderProgram, fragmentShader);\n  gl.linkProgram(shaderProgram);\n\n  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {\n    throw Error(\n      gl.getProgramInfoLog(shaderProgram) ??\n        'Unable to initialize the shader program',\n    );\n  }\n\n  return shaderProgram;\n}\n\n// 创建指定类型的着色器，上传 source 源码并编译\nfunction loadShader(gl: WebGLRenderingContext, type: number, source: string) {\n  const shader = gl.createShader(type)!;\n\n  // Send the source to the shader object\n  gl.shaderSource(shader, source);\n\n  // Compile the shader program\n  gl.compileShader(shader);\n\n  // See if it compiled successfully\n  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n    const errMsg = gl.getShaderInfoLog(shader);\n    gl.deleteShader(shader);\n    throw Error(errMsg ?? 'An error occurred compiling the shaders');\n  }\n\n  return shader;\n}\n\nfunction updateTexture(\n  gl: WebGLRenderingContext,\n  img: TImgSource,\n  texture: WebGLTexture,\n) {\n  gl.bindTexture(gl.TEXTURE_2D, texture);\n  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);\n  gl.drawArrays(gl.TRIANGLES, 0, 6);\n}\n\nfunction initTexture(gl: WebGLRenderingContext) {\n  const texture = gl.createTexture();\n  if (texture == null) throw Error('Create WebGL texture error');\n  gl.bindTexture(gl.TEXTURE_2D, texture);\n\n  // put a single pixel in the texture so we can use it immediately.\n  const level = 0;\n  const internalFormat = gl.RGBA;\n  const width = 1;\n  const height = 1;\n  const border = 0;\n  const srcFormat = gl.RGBA;\n  const srcType = gl.UNSIGNED_BYTE;\n  const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue\n  gl.texImage2D(\n    gl.TEXTURE_2D,\n    level,\n    internalFormat,\n    width,\n    height,\n    border,\n    srcFormat,\n    srcType,\n    pixel,\n  );\n\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\n  return texture;\n}\n\ninterface IChromakeyOpts {\n  keyColor: [number, number, number];\n  similarity: number;\n  smoothness: number;\n  spill: number;\n}\n\nfunction initCvs(\n  opts: {\n    width: number;\n    height: number;\n  } & IChromakeyOpts,\n) {\n  const cvs =\n    'document' in globalThis\n      ? globalThis.document.createElement('canvas')\n      : new OffscreenCanvas(opts.width, opts.height);\n  cvs.width = opts.width;\n  cvs.height = opts.height;\n\n  const gl = cvs.getContext('webgl2', {\n    premultipliedAlpha: false,\n    alpha: true,\n  }) as WebGL2RenderingContext | null;\n\n  if (gl == null) throw Error('Cant create gl context');\n\n  const shaderProgram = initShaderProgram(gl, vertexShader, fragmentShader);\n  gl.useProgram(shaderProgram);\n\n  gl.uniform3fv(\n    gl.getUniformLocation(shaderProgram, 'keyColor'),\n    opts.keyColor.map((v) => v / 255),\n  );\n  gl.uniform1f(\n    gl.getUniformLocation(shaderProgram, 'similarity'),\n    opts.similarity,\n  );\n  gl.uniform1f(\n    gl.getUniformLocation(shaderProgram, 'smoothness'),\n    opts.smoothness,\n  );\n  gl.uniform1f(gl.getUniformLocation(shaderProgram, 'spill'), opts.spill);\n\n  const posBuffer = gl.createBuffer();\n  gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);\n  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(POINT_POS), gl.STATIC_DRAW);\n  const a_position = gl.getAttribLocation(shaderProgram, 'a_position');\n  gl.vertexAttribPointer(\n    a_position,\n    2,\n    gl.FLOAT,\n    false,\n    Float32Array.BYTES_PER_ELEMENT * 2,\n    0,\n  );\n  gl.enableVertexAttribArray(a_position);\n\n  const texCoordBuffer = gl.createBuffer();\n  gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);\n  gl.bufferData(\n    gl.ARRAY_BUFFER,\n    new Float32Array(TEX_COORD_POS),\n    gl.STATIC_DRAW,\n  );\n  const a_texCoord = gl.getAttribLocation(shaderProgram, 'a_texCoord');\n  gl.vertexAttribPointer(\n    a_texCoord,\n    2,\n    gl.FLOAT,\n    false,\n    Float32Array.BYTES_PER_ELEMENT * 2,\n    0,\n  );\n  gl.enableVertexAttribArray(a_texCoord);\n\n  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);\n\n  return { cvs, gl };\n}\n\ntype TImgSource =\n  | HTMLVideoElement\n  | HTMLCanvasElement\n  | HTMLImageElement\n  | ImageBitmap\n  | OffscreenCanvas\n  | VideoFrame;\n\nfunction getSourceWH(imgSource: TImgSource) {\n  return imgSource instanceof VideoFrame\n    ? { width: imgSource.codedWidth, height: imgSource.codedHeight }\n    : { width: imgSource.width, height: imgSource.height };\n}\n\nfunction getKeyColor(imgSource: TImgSource) {\n  const cvs = new OffscreenCanvas(1, 1);\n  const ctx = cvs.getContext('2d')!;\n  ctx.drawImage(imgSource, 0, 0);\n  const {\n    data: [r, g, b],\n  } = ctx.getImageData(0, 0, 1, 1);\n  return [r, g, b] as [number, number, number];\n}\n\n/**\n * 绿幕抠图\n * keyColor 需要扣除的背景色，若不传则取第一个像素点\n * similarity 背景色相似度阈值，过小可能保留背景色，过大可能扣掉更多非背景像素点\n * smoothness 平滑度；过小可能出现锯齿，过大导致整体变透明\n * spill      饱和度；过小可能保留绿色混合，过大导致图片变灰度\n * @param opts: {\n *   keyColor?: [r, g, b]\n *   similarity: number\n *   smoothness: number\n *   spill: number\n * }\n */\nexport const createChromakey = (\n  opts: Omit<IChromakeyOpts, 'keyColor'> & {\n    keyColor?: [number, number, number];\n  },\n) => {\n  let cvs: HTMLCanvasElement | OffscreenCanvas | null = null;\n  let gl: WebGLRenderingContext | null = null;\n  let keyC = opts.keyColor;\n  let texture: WebGLTexture | null = null;\n\n  return async (imgSource: TImgSource) => {\n    if (cvs == null || gl == null || texture == null) {\n      if (keyC == null) keyC = getKeyColor(imgSource);\n      ({ cvs, gl } = initCvs({\n        ...getSourceWH(imgSource),\n        keyColor: keyC,\n        ...opts,\n      }));\n      texture = initTexture(gl);\n    }\n\n    updateTexture(gl, imgSource, texture);\n\n    if (\n      globalThis.VideoFrame != null &&\n      imgSource instanceof globalThis.VideoFrame\n    ) {\n      const rs = new VideoFrame(cvs, {\n        alpha: 'keep',\n        timestamp: imgSource.timestamp,\n        duration: imgSource.duration ?? undefined,\n      });\n      imgSource.close();\n      return rs;\n    }\n\n    return createImageBitmap(cvs, {\n      imageOrientation: imgSource instanceof ImageBitmap ? 'flipY' : 'none',\n    });\n  };\n};\n","import { EventTool } from '@webav/internal-utils';\n\ninterface IPoint {\n  x: number;\n  y: number;\n}\n\nexport interface IRectBaseProps {\n  x: number;\n  y: number;\n  w: number;\n  h: number;\n  angle: number;\n}\n\n/**\n * 用于记录素材在视频或画布中的空间属性：位置、大小、旋转\n *\n * 并提供控制点位置，支持用户在画布中缩放、旋转素材\n *\n * 一般由内部 WebAV SDK 内部创建维护\n *\n * @see {@link Combinator}, {@link OffscreenSprite}\n * @see [AVCanvas](../../av-canvas/classes/AVCanvas.html), {@link VisibleSprite}\n *\n * @see [视频剪辑](https://webav-tech.github.io/WebAV/demo/6_4-video-editor)\n */\nexport class Rect implements IRectBaseProps {\n  #evtTool = new EventTool<{\n    propsChange: (props: Partial<IRectBaseProps>) => void;\n  }>();\n  /**\n   * 监听属性变更事件\n   * @example\n   * rect.on('propsChange', (changedProps) => {})\n   */\n  on = this.#evtTool.on;\n\n  #x = 0;\n  /**\n   * x 坐标\n   */\n  get x() {\n    return this.#x;\n  }\n  set x(v) {\n    this.#setBaseProps('x', v);\n  }\n  #y = 0;\n  get y() {\n    return this.#y;\n  }\n  /**\n   * y 坐标\n   */\n  set y(v) {\n    this.#setBaseProps('y', v);\n  }\n  #w = 0;\n  /**\n   * 宽\n   */\n  get w() {\n    return this.#w;\n  }\n  set w(v) {\n    this.#setBaseProps('w', v);\n  }\n  #h = 0;\n  /**\n   * 高\n   */\n  get h() {\n    return this.#h;\n  }\n  set h(v) {\n    this.#setBaseProps('h', v);\n  }\n  #angle = 0;\n  /**\n   * 旋转角度\n   * @see [MDN Canvas rotate](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/rotate)\n   */\n  get angle() {\n    return this.#angle;\n  }\n  set angle(v) {\n    this.#setBaseProps('angle', v);\n  }\n\n  #setBaseProps(prop: keyof IRectBaseProps, v: number) {\n    const changed = this[prop] !== v;\n    switch (prop) {\n      case 'x':\n        this.#x = v;\n        break;\n      case 'y':\n        this.#y = v;\n        break;\n      case 'w':\n        this.#w = v;\n        break;\n      case 'h':\n        this.#h = v;\n        break;\n      case 'angle':\n        this.#angle = v;\n        break;\n    }\n    if (changed) this.#evtTool.emit('propsChange', { [prop]: v });\n  }\n\n  /**\n   * 如果当前实例是 Rect 控制点之一，`master` 将指向该 Rect\n   *\n   * 控制点的坐标是相对于它的 `master` 定位\n   */\n  #master: Rect | null = null;\n\n  constructor(\n    x?: number,\n    y?: number,\n    w?: number,\n    h?: number,\n    master?: Rect | null,\n  ) {\n    this.x = x ?? 0;\n    this.y = y ?? 0;\n    this.w = w ?? 0;\n    this.h = h ?? 0;\n    this.#master = master ?? null;\n  }\n\n  /**\n   * 根据坐标、宽高计算出来的矩形中心点\n   */\n  get center(): IPoint {\n    const { x, y, w, h } = this;\n    return { x: x + w / 2, y: y + h / 2 };\n  }\n\n  /**\n   * 是否保持固定宽高比例，禁止变形缩放\n   *\n   * 值为 true 时，将缺少上下左右四个控制点\n   */\n  fixedAspectRatio = false;\n\n  /**\n   * 是否固定中心点进行缩放\n   * 值为 true 时，固定中心点不变进行缩放\n   * 值为 false 时，固定对角点不变进行缩放\n   */\n  fixedScaleCenter = false;\n\n  clone(): Rect {\n    const { x, y, w, h } = this;\n    const rect = new Rect(x, y, w, h, this.#master);\n    rect.angle = this.angle;\n    rect.fixedAspectRatio = this.fixedAspectRatio;\n    rect.fixedScaleCenter = this.fixedScaleCenter;\n    return rect;\n  }\n\n  /**\n   * 检测目标坐标是否命中当前实例\n   * @param tx 目标点 x 坐标\n   * @param ty 目标点 y 坐标\n   */\n  checkHit(tx: number, ty: number): boolean {\n    let { angle, center, x, y, w, h } = this;\n    // ctrls 的中心点、旋转角度都取自于 master （sprite）\n    const cnt = this.#master?.center ?? center;\n    const agl = this.#master?.angle ?? angle;\n    // ctrl 初始化时其坐标就是相对于 master 的，参见 get ctrls()\n    // 所以此处不用转换\n    if (this.#master == null) {\n      x = x - cnt.x;\n      y = y - cnt.y;\n    }\n    // 鼠标点击坐标映射成以中点为原点的坐标\n    const tOX = tx - cnt.x;\n    const tOY = ty - cnt.y;\n    // 如果有旋转，映射成相对 sprite 原点，旋转前的坐标\n    let mx = tOX;\n    let my = tOY;\n    if (agl !== 0) {\n      // 推导公式 https://github.com/hughfenghen/hughfenghen.github.io/issues/96\n      mx = tOX * Math.cos(agl) + tOY * Math.sin(agl);\n      my = tOY * Math.cos(agl) - tOX * Math.sin(agl);\n    }\n\n    if (mx < x || mx > x + w || my < y || my > y + h) return false;\n\n    return true;\n  }\n}\n","import { EventTool } from '@webav/internal-utils';\nimport { IRectBaseProps, Rect } from './rect';\n\ninterface IAnimationOpts {\n  duration: number;\n  delay?: number;\n  iterCount?: number;\n}\n\ntype TAnimateProps = IRectBaseProps & { opacity: number };\n\nexport type TAnimationKeyFrame = Array<[number, Partial<TAnimateProps>]>;\n\ntype TKeyFrameOpts = Partial<\n  Record<`${number}%` | 'from' | 'to', Partial<TAnimateProps>>\n>;\n\n/**\n * Sprite 基类\n *\n * @see {@link OffscreenSprite}\n * @see {@link VisibleSprite}\n */\nexport abstract class BaseSprite {\n  /**\n   * 控制素材在视频中的空间属性（坐标、旋转、缩放）\n   */\n  rect = new Rect();\n\n  /**\n   * 控制素材在的时间偏移、时长、播放速率，常用于剪辑场景时间轴（轨道）模块\n   * duration 不能大于引用 {@link IClip} 的时长，单位 微秒\n   *\n   * playbackRate 控制当前素材的播放速率，1 表示正常播放；\n   * **注意**\n   *    1. 设置 playbackRate 时需要主动修正 duration\n   *    2. 音频使用最简单的插值算法来改变速率，所以改变速率后音调会产生变化，自定义算法请使用 {@link MP4Clip.tickInterceptor} 配合实现\n   *\n   */\n  #time = {\n    offset: 0,\n    duration: 0,\n    playbackRate: 1,\n  };\n  get time(): { offset: number; duration: number; playbackRate: number } {\n    return this.#time;\n  }\n  set time(v: { offset: number; duration: number; playbackRate?: number }) {\n    Object.assign(this.#time, v);\n  }\n\n  #evtTool = new EventTool<{\n    propsChange: (\n      value: Partial<{ rect: Partial<Rect>; zIndex: number }>,\n    ) => void;\n  }>();\n  /**\n   * 监听属性变更事件\n   * @example\n   * sprite.on('propsChange', (changedProps) => {})\n   */\n  on = this.#evtTool.on;\n\n  #zIndex = 0;\n  get zIndex(): number {\n    return this.#zIndex;\n  }\n\n  /**\n   * 控制素材间的层级关系，zIndex 值较小的素材会被遮挡\n   */\n  set zIndex(v: number) {\n    const changed = this.#zIndex !== v;\n    this.#zIndex = v;\n    if (changed) this.#evtTool.emit('propsChange', { zIndex: v });\n  }\n\n  /**\n   * 不透明度\n   */\n  opacity = 1;\n\n  /**\n   * 水平或垂直方向翻转素材\n   */\n  flip: 'horizontal' | 'vertical' | null = null;\n\n  #animatKeyFrame: TAnimationKeyFrame | null = null;\n\n  #animatOpts: Required<IAnimationOpts> | null = null;\n\n  /**\n   * @see {@link IClip.ready}\n   */\n  ready = Promise.resolve();\n\n  constructor() {\n    this.rect.on('propsChange', (props) => {\n      this.#evtTool.emit('propsChange', { rect: props });\n    });\n  }\n\n  protected _render(\n    ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,\n  ): void {\n    const {\n      rect: { center, angle },\n    } = this;\n    ctx.setTransform(\n      // 水平 缩放、倾斜\n      this.flip === 'horizontal' ? -1 : 1,\n      0,\n      // 垂直 倾斜、缩放\n      0,\n      this.flip === 'vertical' ? -1 : 1,\n      // 坐标原点偏移 x y\n      center.x,\n      center.y,\n    );\n    // 任意方向翻转，旋转角度转为负值，才能与控制点同步\n    ctx.rotate((this.flip == null ? 1 : -1) * angle);\n\n    ctx.globalAlpha = this.opacity;\n  }\n\n  /**\n   * 给素材添加动画，使用方法参考 css animation\n   *\n   * @example\n   * sprite.setAnimation(\n   *   {\n   *     '0%': { x: 0, y: 0 },\n   *     '25%': { x: 1200, y: 680 },\n   *     '50%': { x: 1200, y: 0 },\n   *     '75%': { x: 0, y: 680 },\n   *     '100%': { x: 0, y: 0 },\n   *   },\n   *   { duration: 4e6, iterCount: 1 },\n   * );\n   *\n   * @see [视频水印动画](https://webav-tech.github.io/WebAV/demo/2_1-concat-video)\n   */\n  setAnimation(keyFrame: TKeyFrameOpts, opts: IAnimationOpts): void {\n    this.#animatKeyFrame = Object.entries(keyFrame).map(([k, val]) => {\n      const numK = { from: 0, to: 100 }[k] ?? Number(k.slice(0, -1));\n      if (isNaN(numK) || numK > 100 || numK < 0) {\n        throw Error('keyFrame must between 0~100');\n      }\n      return [numK / 100, val];\n    }) as TAnimationKeyFrame;\n    this.#animatOpts = Object.assign({}, this.#animatOpts, {\n      duration: opts.duration,\n      delay: opts.delay ?? 0,\n      iterCount: opts.iterCount ?? Infinity,\n    });\n  }\n\n  /**\n   * 如果当前 sprite 已被设置动画，将 sprite 的动画属性设定到指定时间的状态\n   */\n  animate(time: number): void {\n    if (\n      this.#animatKeyFrame == null ||\n      this.#animatOpts == null ||\n      time < this.#animatOpts.delay\n    )\n      return;\n    const updateProps = linearTimeFn(\n      time,\n      this.#animatKeyFrame,\n      this.#animatOpts,\n    );\n    for (const k in updateProps) {\n      switch (k) {\n        case 'opacity':\n          this.opacity = updateProps[k] as number;\n          break;\n        case 'x':\n        case 'y':\n        case 'w':\n        case 'h':\n        case 'angle':\n          this.rect[k] = updateProps[k] as number;\n          break;\n      }\n    }\n  }\n\n  /**\n   * 将当前 sprite 的属性赋值到目标\n   *\n   * 用于 clone，或 {@link VisibleSprite} 与 {@link OffscreenSprite} 实例间的类型转换\n   */\n  copyStateTo<T extends BaseSprite>(target: T) {\n    target.#animatKeyFrame = this.#animatKeyFrame;\n    target.#animatOpts = this.#animatOpts;\n    target.zIndex = this.zIndex;\n    target.opacity = this.opacity;\n    target.flip = this.flip;\n    target.rect = this.rect.clone();\n    target.time = { ...this.time };\n  }\n\n  protected destroy() {\n    this.#evtTool.destroy();\n  }\n}\n\nexport function linearTimeFn(\n  time: number,\n  kf: TAnimationKeyFrame,\n  opts: Required<IAnimationOpts>,\n): Partial<TAnimateProps> {\n  const offsetTime = time - opts.delay;\n  if (offsetTime / opts.duration >= opts.iterCount) return {};\n\n  const t = offsetTime % opts.duration;\n\n  const process = offsetTime === opts.duration ? 1 : t / opts.duration;\n  const idx = kf.findIndex((it) => it[0] >= process);\n  if (idx === -1) return {};\n\n  const startState = kf[idx - 1];\n  const nextState = kf[idx];\n  const nextFrame = nextState[1];\n  if (startState == null) return nextFrame;\n  const startFrame = startState[1];\n\n  const rs: Partial<TAnimateProps> = {};\n  // 介于两个Frame状态间的进度\n  const stateProcess =\n    (process - startState[0]) / (nextState[0] - startState[0]);\n  for (const prop in nextFrame) {\n    const p = prop as keyof TAnimateProps;\n    if (startFrame[p] == null) continue;\n    // @ts-expect-error\n    // eslint-disable-next-line\n    rs[p] = (nextFrame[p] - startFrame[p]) * stateProcess + startFrame[p];\n  }\n\n  return rs;\n}\n","import { BaseSprite } from './base-sprite';\nimport { IClip } from '../clips';\nimport { Log } from '@webav/internal-utils';\nimport { changePCMPlaybackRate } from '../av-utils';\n\n/**\n * 包装 {@link IClip} 给素材扩展坐标、层级、透明度等信息，用于 {@link Combinator} 在后台合成视频\n *\n * 跟 {@link VisibleSprite} 非常相似，应用场景不同\n *\n * @example\n * const spr = new OffscreenSprite(\n *   new MP4Clip((await fetch('<mp4 url>')).body),\n * );\n * spr.opacity = 0.5 // 半透明\n * spr.rect.x = 100 // x 坐标偏移 100 像素\n * spr.time.offset = 10e6 // 视频第 10s 开始绘制该视频素材\n *\n * @see [视频合成](https://webav-tech.github.io/WebAV/demo/2_1-concat-video)\n */\nexport class OffscreenSprite extends BaseSprite {\n  #clip: IClip;\n\n  // 保持最近一帧，若 clip 在当前帧无数据，则绘制最近一帧\n  #lastVf: VideoFrame | ImageBitmap | null = null;\n\n  #destroyed = false;\n\n  constructor(clip: IClip) {\n    super();\n    this.#clip = clip;\n    this.ready = clip.ready.then(({ width, height, duration }) => {\n      this.rect.w = this.rect.w === 0 ? width : this.rect.w;\n      this.rect.h = this.rect.h === 0 ? height : this.rect.h;\n      this.time.duration =\n        this.time.duration === 0 ? duration : this.time.duration;\n    });\n  }\n\n  /**\n   * 绘制素材指定时刻的图像到 canvas 上下文，并返回对应的音频数据\n   * @param time 指定时刻，微秒\n   */\n  async offscreenRender(\n    ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,\n    time: number,\n  ): Promise<{\n    audio: Float32Array[];\n    done: boolean;\n  }> {\n    const ts = time * this.time.playbackRate;\n    this.animate(ts);\n    super._render(ctx);\n    const { w, h } = this.rect;\n    const { video, audio, state } = await this.#clip.tick(ts);\n    let outAudio = audio ?? [];\n    if (audio != null && this.time.playbackRate !== 1) {\n      outAudio = audio.map((pcm) =>\n        changePCMPlaybackRate(pcm, this.time.playbackRate),\n      );\n    }\n\n    if (state === 'done') {\n      return {\n        audio: outAudio,\n        done: true,\n      };\n    }\n\n    const imgSource = video ?? this.#lastVf;\n    if (imgSource != null) {\n      ctx.drawImage(imgSource, -w / 2, -h / 2, w, h);\n    }\n\n    if (video != null) {\n      this.#lastVf?.close();\n      this.#lastVf = video;\n    }\n\n    return {\n      audio: outAudio,\n      done: false,\n    };\n  }\n\n  async clone() {\n    const spr = new OffscreenSprite(await this.#clip.clone());\n    await spr.ready;\n    this.copyStateTo(spr);\n    return spr;\n  }\n\n  destroy(): void {\n    if (this.#destroyed) return;\n    this.#destroyed = true;\n\n    Log.info('OffscreenSprite destroy');\n    super.destroy();\n    this.#lastVf?.close();\n    this.#lastVf = null;\n    this.#clip.destroy();\n  }\n}\n","import { BaseSprite } from './base-sprite';\nimport { IClip } from '../clips';\nimport { Log } from '@webav/internal-utils';\nimport { changePCMPlaybackRate } from '../av-utils';\n\n/**\n * 包装 {@link IClip} 给素材扩展坐标、层级、透明度等信息，用于 {@link [AVCanvas](../../av-canvas/classes/AVCanvas.html)} 响应用户交互\n *\n * 跟 {@link OffscreenSprite} 非常相似，应用场景不同\n *\n * @example\n * const spr = new VisibleSprite(\n *   new MP4Clip((await fetch('<mp4 url>')).body),\n * );\n * spr.opacity = 0.5 // 半透明\n * spr.rect.x = 100 // x 坐标偏移 100 像素\n * spr.time.offset = 10e6 // 视频第 10s 开始绘制素材\n *\n * @see [视频剪辑](https://webav-tech.github.io/WebAV/demo/6_4-video-editor)\n *\n */\nexport class VisibleSprite extends BaseSprite {\n  #clip: IClip;\n  getClip() {\n    return this.#clip;\n  }\n\n  /**\n   * 元素是否可见，用于不想删除，期望临时隐藏 Sprite 的场景\n   */\n  visible = true;\n\n  constructor(clip: IClip) {\n    super();\n    this.#clip = clip;\n    this.ready = clip.ready.then(({ width, height, duration }) => {\n      this.rect.w = this.rect.w === 0 ? width : this.rect.w;\n      this.rect.h = this.rect.h === 0 ? height : this.rect.h;\n      this.time.duration =\n        this.time.duration === 0 ? duration : this.time.duration;\n    });\n  }\n\n  // 保持最近一帧，若 clip 在当前帧无数据，则绘制最近一帧\n  #lastVf: VideoFrame | ImageBitmap | null = null;\n  #lastAudio: Float32Array[] = [];\n  #ticking = false;\n  #update(time: number) {\n    if (this.#ticking) return;\n    this.#ticking = true;\n    this.#clip\n      .tick(time * this.time.playbackRate)\n      .then(({ video, audio }) => {\n        if (video != null) {\n          this.#lastVf?.close();\n          this.#lastVf = video ?? null;\n        }\n        this.#lastAudio = audio ?? [];\n        if (audio != null && this.time.playbackRate !== 1) {\n          this.#lastAudio = audio.map((pcm) =>\n            changePCMPlaybackRate(pcm, this.time.playbackRate),\n          );\n        }\n      })\n      .finally(() => {\n        this.#ticking = false;\n      });\n  }\n\n  /**\n   * 提前准备指定 time 的帧\n   */\n  preFrame(time: number) {\n    this.#update(time);\n  }\n\n  #lastTime = -1;\n  /**\n   * 绘制素材指定时刻的图像到 canvas 上下文，并返回对应的音频数据\n   * @param time 指定时刻，微秒\n   */\n  render(\n    ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,\n    time: number,\n  ): { audio: Float32Array[] } {\n    this.animate(time);\n    super._render(ctx);\n    const { w, h } = this.rect;\n    if (this.#lastTime !== time) this.#update(time);\n    this.#lastTime = time;\n\n    const audio = this.#lastAudio;\n    this.#lastAudio = [];\n    const video = this.#lastVf;\n    if (video != null) ctx.drawImage(video, -w / 2, -h / 2, w, h);\n\n    return { audio };\n  }\n\n  copyStateTo<T extends BaseSprite>(target: T): void {\n    super.copyStateTo(target);\n    if (target instanceof VisibleSprite) {\n      target.visible = this.visible;\n    }\n  }\n\n  #destroyed = false;\n  destroy(): void {\n    if (this.#destroyed) return;\n    this.#destroyed = true;\n\n    Log.info('VisibleSprite destroy');\n    super.destroy();\n    this.#lastVf?.close();\n    this.#lastVf = null;\n    this.#clip.destroy();\n  }\n}\n","import { Log, EventTool, file2stream, recodemux } from '@webav/internal-utils';\nimport { OffscreenSprite } from './sprite/offscreen-sprite';\nimport { sleep } from './av-utils';\nimport { DEFAULT_AUDIO_CONF } from './clips';\n\nexport interface ICombinatorOpts {\n  width?: number;\n  height?: number;\n  bitrate?: number;\n  fps?: number;\n  bgColor?: string;\n  videoCodec?: string;\n  /**\n   * false 合成的视频文件中排除音轨\n   */\n  audio?: false;\n  /**\n   * 向输出的视频中写入 meta tags 数据\n   */\n  metaDataTags?: Record<string, string>;\n  /**\n   * 不安全，随时可能废弃\n   */\n  __unsafe_hardwareAcceleration__?: HardwarePreference;\n}\n\nlet COM_ID = 0;\n\n/**\n * 避免 VideoEncoder 队列中的 VideoFrame 过多，打爆显存\n */\nasync function letEncoderCalmDown(getQSize: () => number) {\n  if (getQSize() > 50) {\n    await sleep(15);\n    await letEncoderCalmDown(getQSize);\n  }\n}\n\n/**\n * 视频合成器；能添加多个 {@link OffscreenSprite}，根据它们位置、层级、时间偏移等信息，合成输出为视频文件\n * @see [视频合成](https://webav-tech.github.io/WebAV/demo/2_1-concat-video)\n * @see [视频配音](https://webav-tech.github.io/WebAV/demo/2_2-video-add-audio)\n * @example\n * const spr1 = new OffscreenSprite(\n *   new MP4Clip((await fetch('<mp4 url>')).body),\n * );\n * const spr2 = new OffscreenSprite(\n *   new AudioClip((await fetch('<audio url>')).body),\n * );\n * const com = new Combinator({ width: 1280, height: 720, });\n\n * await com.addSprite(spr1);\n * await com.addSprite(spr2);\n\n * com.output(); // => ReadableStream\n *\n */\nexport class Combinator {\n  /**\n   * 检测当前环境的兼容性\n   * @param args.videoCodec 指定视频编码格式，默认 avc1.42E032\n   * @param args.width 指定视频宽度，默认 1920\n   * @param args.height 指定视频高度，默认 1080\n   * @param args.bitrate 指定视频比特率，默认 5e6\n   */\n  static async isSupported(\n    args: {\n      videoCodec?: string;\n      width?: number;\n      height?: number;\n      bitrate?: number;\n    } = {},\n  ): Promise<boolean> {\n    return (\n      (self.OffscreenCanvas != null &&\n        self.VideoEncoder != null &&\n        self.VideoDecoder != null &&\n        self.VideoFrame != null &&\n        self.AudioEncoder != null &&\n        self.AudioDecoder != null &&\n        self.AudioData != null &&\n        ((\n          await self.VideoEncoder.isConfigSupported({\n            codec: args.videoCodec ?? 'avc1.42E032',\n            width: args.width ?? 1920,\n            height: args.height ?? 1080,\n            bitrate: args.bitrate ?? 7e6,\n          })\n        ).supported ??\n          false) &&\n        (\n          await self.AudioEncoder.isConfigSupported({\n            codec: DEFAULT_AUDIO_CONF.codec,\n            sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n            numberOfChannels: DEFAULT_AUDIO_CONF.channelCount,\n          })\n        ).supported) ??\n      false\n    );\n  }\n\n  #log = Log.create(`id:${COM_ID++},`);\n\n  #destroyed = false;\n\n  #sprites: Array<OffscreenSprite & { main: boolean; expired: boolean }> = [];\n\n  #cvs;\n\n  #ctx;\n\n  // 中断输出\n  #stopOutput: (() => void) | null = null;\n\n  #opts: Required<ICombinatorOpts>;\n\n  #hasVideoTrack: boolean;\n\n  #evtTool = new EventTool<{\n    OutputProgress: (progress: number) => void;\n    error: (err: Error) => void;\n  }>();\n  on = this.#evtTool.on;\n\n  /**\n   * 根据配置创建合成器实例\n   * @param opts ICombinatorOpts\n   */\n  constructor(opts: ICombinatorOpts = {}) {\n    const { width = 0, height = 0 } = opts;\n    this.#cvs = new OffscreenCanvas(width, height);\n    // this.#cvs = document.querySelector('#canvas') as HTMLCanvasElement\n    const ctx = this.#cvs.getContext('2d', { alpha: false });\n    if (ctx == null) throw Error('Can not create 2d offscreen context');\n    this.#ctx = ctx;\n    this.#opts = Object.assign(\n      {\n        bgColor: '#000',\n        width: 0,\n        height: 0,\n        videoCodec: 'avc1.42E032',\n        audio: true,\n        bitrate: 5e6,\n        fps: 30,\n        metaDataTags: null,\n      },\n      opts,\n    );\n\n    this.#hasVideoTrack = width * height > 0;\n  }\n\n  /**\n   * 添加用于合成视频的 Sprite，视频时长默认取所有素材 duration 字段的最大值\n   * @param os Sprite\n   * @param opts.main 如果 main 为 true，视频时长为该素材的 duration 值\n   */\n  async addSprite(\n    os: OffscreenSprite,\n    opts: { main?: boolean } = {},\n  ): Promise<void> {\n    const logAttrs = {\n      rect: pick(['x', 'y', 'w', 'h'], os.rect),\n      time: { ...os.time },\n      zIndex: os.zIndex,\n    };\n    this.#log.info('Combinator add sprite', logAttrs);\n    const newOS = await os.clone();\n    this.#log.info('Combinator add sprite ready');\n    this.#sprites.push(\n      Object.assign(newOS, {\n        main: opts.main ?? false,\n        expired: false,\n      }),\n    );\n    this.#sprites.sort((a, b) => a.zIndex - b.zIndex);\n  }\n\n  #startRecodeMux(duration: number) {\n    const { fps, width, height, videoCodec, bitrate, audio, metaDataTags } =\n      this.#opts;\n    const recodeMuxer = recodemux({\n      video: this.#hasVideoTrack\n        ? {\n            width,\n            height,\n            expectFPS: fps,\n            codec: videoCodec,\n            bitrate,\n            __unsafe_hardwareAcceleration__:\n              this.#opts.__unsafe_hardwareAcceleration__,\n          }\n        : null,\n      audio:\n        audio === false\n          ? null\n          : {\n              codec: 'aac',\n              sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n              channelCount: DEFAULT_AUDIO_CONF.channelCount,\n            },\n      duration,\n      metaDataTags: metaDataTags,\n    });\n    return recodeMuxer;\n  }\n\n  /**\n   * 输出视频文件二进制流\n   */\n  output(): ReadableStream<Uint8Array> {\n    if (this.#sprites.length === 0) throw Error('No sprite added');\n\n    const mainSpr = this.#sprites.find((it) => it.main);\n    // 最大时间，优先取 main sprite，不存在则取最大值\n    const maxTime =\n      mainSpr != null\n        ? mainSpr.time.offset + mainSpr.time.duration\n        : Math.max(\n            ...this.#sprites.map((it) => it.time.offset + it.time.duration),\n          );\n    if (maxTime === Infinity) {\n      throw Error(\n        'Unable to determine the end time, please specify a main sprite, or limit the duration of ImgClip, AudioCli',\n      );\n    }\n    // 主视频（main）的 videoTrack duration 值为 0\n    if (maxTime === -1) {\n      this.#log.warn(\n        \"Unable to determine the end time, process value don't update\",\n      );\n    }\n\n    this.#log.info(`start combinate video, maxTime:${maxTime}`);\n    const remux = this.#startRecodeMux(maxTime);\n    let starTime = performance.now();\n    const stopReCodeMux = this.#run(remux, maxTime, {\n      onProgress: (prog) => {\n        this.#log.debug('OutputProgress:', prog);\n        this.#evtTool.emit('OutputProgress', prog);\n      },\n      onEnded: async () => {\n        await remux.flush();\n        this.#log.info(\n          '===== output ended =====, cost:',\n          performance.now() - starTime,\n        );\n        this.#evtTool.emit('OutputProgress', 1);\n        this.destroy();\n      },\n      onError: (err) => {\n        this.#evtTool.emit('error', err);\n        closeOutStream(err);\n        this.destroy();\n      },\n    });\n\n    this.#stopOutput = () => {\n      stopReCodeMux();\n      remux.close();\n      closeOutStream();\n    };\n    const { stream, stop: closeOutStream } = file2stream(\n      remux.mp4file,\n      500,\n      this.destroy,\n    );\n\n    return stream;\n  }\n\n  /**\n   * 销毁实例，释放资源\n   */\n  destroy() {\n    if (this.#destroyed) return;\n    this.#destroyed = true;\n\n    this.#stopOutput?.();\n    this.#evtTool.destroy();\n  }\n\n  #run(\n    remux: ReturnType<typeof recodemux>,\n    maxTime: number,\n    {\n      onProgress,\n      onEnded,\n      onError,\n    }: {\n      onProgress: (prog: number) => void;\n      onEnded: () => Promise<void>;\n      onError: (err: Error) => void;\n    },\n  ): () => void {\n    let progress = 0;\n    const aborter = { aborted: false };\n    let err: Error | null = null;\n\n    const _run = async () => {\n      const { fps, bgColor, audio: outputAudio } = this.#opts;\n      const timeSlice = Math.round(1e6 / fps);\n\n      const ctx = this.#ctx;\n      const sprRender = createSpritesRender({\n        ctx,\n        bgColor,\n        sprites: this.#sprites,\n        aborter,\n      });\n      const encodeData = createAVEncoder({\n        remux,\n        ctx,\n        cvs: this.#cvs,\n        outputAudio,\n        hasVideoTrack: this.#hasVideoTrack,\n        timeSlice,\n        fps,\n      });\n\n      let ts = 0;\n      while (true) {\n        if (err != null) return;\n        if (\n          aborter.aborted ||\n          (maxTime === -1 ? false : ts > maxTime) ||\n          this.#sprites.length === 0\n        ) {\n          exit();\n          await onEnded();\n          return;\n        }\n        progress = ts / maxTime;\n\n        const { audios, mainSprDone } = await sprRender(ts);\n        if (mainSprDone) {\n          exit();\n          await onEnded();\n          return;\n        }\n\n        if (aborter.aborted) return;\n\n        encodeData(ts, audios);\n\n        ts += timeSlice;\n\n        await letEncoderCalmDown(remux.getEncodeQueueSize);\n      }\n    };\n\n    _run().catch((e) => {\n      err = e;\n      this.#log.error(e);\n      exit();\n      onError(e);\n    });\n\n    const outProgTimer = setInterval(() => {\n      onProgress(progress);\n    }, 500);\n\n    const exit = () => {\n      if (aborter.aborted) return;\n      aborter.aborted = true;\n      clearInterval(outProgTimer);\n      this.#sprites.forEach((it) => it.destroy());\n    };\n\n    return exit;\n  }\n}\n\nfunction createSpritesRender(opts: {\n  ctx: OffscreenCanvasRenderingContext2D;\n  bgColor: string;\n  sprites: Array<OffscreenSprite & { main: boolean; expired: boolean }>;\n  aborter: { aborted: boolean };\n}) {\n  const { ctx, bgColor, sprites, aborter } = opts;\n  const { width, height } = ctx.canvas;\n  return async (ts: number) => {\n    ctx.fillStyle = bgColor;\n    ctx.fillRect(0, 0, width, height);\n\n    const audios: Float32Array[][] = [];\n    let mainSprDone = false;\n    for (const s of sprites) {\n      if (aborter.aborted) break;\n      if (ts < s.time.offset || s.expired) continue;\n\n      ctx.save();\n      const { audio, done } = await s.offscreenRender(ctx, ts - s.time.offset);\n      audios.push(audio);\n      ctx.restore();\n\n      // 超过设定时间主动掐断，或资源结束\n      if (\n        (s.time.duration > 0 && ts > s.time.offset + s.time.duration) ||\n        done\n      ) {\n        if (s.main) mainSprDone = true;\n\n        s.destroy();\n        s.expired = true;\n      }\n    }\n    return {\n      audios,\n      mainSprDone,\n    };\n  };\n}\n\nfunction createAVEncoder(opts: {\n  remux: ReturnType<typeof recodemux>;\n  ctx: OffscreenCanvasRenderingContext2D;\n  cvs: OffscreenCanvas;\n  outputAudio?: boolean;\n  hasVideoTrack: boolean;\n  timeSlice: number;\n  fps: number;\n}) {\n  const { ctx, cvs, outputAudio, remux, hasVideoTrack, timeSlice } = opts;\n  const { width, height } = cvs;\n  let frameCnt = 0;\n  // 3s 一个 GOP\n  const gopSize = Math.floor(3 * opts.fps);\n\n  const audioTrackBuf = createAudioTrackBuf(1024);\n\n  return (ts: number, audios: Float32Array[][]) => {\n    if (outputAudio !== false) {\n      for (const ad of audioTrackBuf(ts, audios)) remux.encodeAudio(ad);\n    }\n\n    if (hasVideoTrack) {\n      const vf = new VideoFrame(cvs, {\n        duration: timeSlice,\n        timestamp: ts,\n      });\n\n      remux.encodeVideo(vf, {\n        keyFrame: frameCnt % gopSize === 0,\n      });\n      ctx.resetTransform();\n      ctx.clearRect(0, 0, width, height);\n\n      frameCnt += 1;\n    }\n  };\n}\n\n/**\n * 缓冲输入的数据，转换成固定帧数的 AudioData\n * @param adFrames 一个 AudioData 实例的音频帧数\n */\nexport function createAudioTrackBuf(adFrames: number) {\n  const adDataSize = adFrames * DEFAULT_AUDIO_CONF.channelCount;\n  // pcm 数据缓存区\n  const chanBuf = new Float32Array(adDataSize * 3);\n  let putOffset = 0;\n\n  let audioTs = 0;\n  const adDuration = (adFrames / DEFAULT_AUDIO_CONF.sampleRate) * 1e6;\n\n  // 缺少音频数据时占位\n  const placeholderData = new Float32Array(adDataSize);\n\n  const getAudioData = (ts: number) => {\n    let readOffset = 0;\n    const adCnt = Math.floor(putOffset / adDataSize);\n    const rs: AudioData[] = [];\n    // 从缓存区按指定帧数获取数据构造 AudioData\n    for (let i = 0; i < adCnt; i++) {\n      rs.push(\n        new AudioData({\n          timestamp: audioTs,\n          numberOfChannels: DEFAULT_AUDIO_CONF.channelCount,\n          numberOfFrames: adFrames,\n          sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n          format: 'f32',\n          data: chanBuf.subarray(readOffset, readOffset + adDataSize),\n        }),\n      );\n      readOffset += adDataSize;\n      audioTs += adDuration;\n    }\n    chanBuf.set(chanBuf.subarray(readOffset, putOffset), 0);\n    putOffset -= readOffset;\n\n    // 已有音频数据不足，使用占位数据填充\n    while (ts - audioTs > adDuration) {\n      rs.push(\n        new AudioData({\n          timestamp: audioTs,\n          numberOfChannels: DEFAULT_AUDIO_CONF.channelCount,\n          numberOfFrames: adFrames,\n          sampleRate: DEFAULT_AUDIO_CONF.sampleRate,\n          format: 'f32',\n          data: placeholderData,\n        }),\n      );\n      audioTs += adDuration;\n    }\n    return rs;\n  };\n\n  return (ts: number, trackAudios: Float32Array[][]) => {\n    const maxLen = Math.max(...trackAudios.map((a) => a[0]?.length ?? 0));\n    for (let bufIdx = 0; bufIdx < maxLen; bufIdx++) {\n      let chan0 = 0;\n      let chan1 = 0;\n      for (let trackIdx = 0; trackIdx < trackAudios.length; trackIdx++) {\n        const _c0 = trackAudios[trackIdx][0]?.[bufIdx] ?? 0;\n        // 如果是单声道 PCM，第二声道复用第一声道数据\n        const _c1 = trackAudios[trackIdx][1]?.[bufIdx] ?? _c0;\n        chan0 += _c0;\n        chan1 += _c1;\n      }\n      // 合成多个素材的音频数据写入缓存区\n      chanBuf[putOffset] = chan0;\n      chanBuf[putOffset + 1] = chan1;\n      putOffset += 2;\n    }\n    // 消费缓存区数据，生成 AudioData\n    return getAudioData(ts);\n  };\n}\n\nfunction pick<K extends keyof T, T extends object>(keys: K[], obj: T) {\n  return keys.reduce(\n    (acc, key) => {\n      acc[key] = obj[key];\n      return acc;\n    },\n    {} as Record<K, T[K]>,\n  );\n}\n"],"names":["createEl","tagName","renderTxt2Img","txt","cssText","div","width","height","img","svgStr","renderTxt2ImgBitmap","imgEl","resolve","cvs","ctx","concatFloat32Array","bufs","rs","buf","a","b","offset","concatPCMFragments","fragments","chanListPCM","i","j","extractPCM4AudioData","ad","idx","chanBufSize","chanBuf","convertF32ToPlanar","convertS16ToF32Planar","pcmS16Data","numChannels","numSamples","planarData","channel","sample","pcmF32Data","extractPCM4AudioBuffer","ab","_","decodeImg","stream","type","init","imageDecoder","frameCnt","_a","mixinPCM","audios","maxLen","data","bufIdx","chan0","chan1","trackIdx","_c0","_c1","_b","audioResample","pcmData","curRate","target","chanCnt","emptyPCM","len","c","p","waveResampler","abSource","d","sleep","time","stop","workerTimer","ringSliceFloat32Array","start","end","cnt","changePCMPlaybackRate","playbackRate","newLength","newPcmData","originalIndex","intIndex","frac","DEFAULT_AUDIO_CONF","extractFileConfig","file","info","vTrack","videoDesc","parseVideoCodecDesc","descKey","aTrack","esdsBox","getESDSBoxFromMP4File","parseAudioInfo4ESDSBox","track","entry","box","mp4box","codec","mp4aBox","t","esds","decoderConf","byte1","byte2","sampleRateIdx","numberOfChannels","quickParseMP4File","reader","onReady","onSamples","mp4boxFile","vTrackId","aTrackId","parse","cursor","maxReadSize","nextPos","CLIP_ID","isOTFile","obj","_MP4Clip","source","opts","__privateAdd","_insId","_log","Log","__privateGet","__publicField","_destroyed","_meta","_localFile","_headerBoxPos","_volume","_videoSamples","_audioSamples","_videoFrameFinder","_audioFrameFinder","_decoderConf","_opts","tickRet","_thumbAborter","__privateSet","initByStream","write","tmpfile","otFile","mp4FileToSamples","videoSamples","audioSamples","headerBoxPos","videoFrameFinder","audioFrameFinder","genDecoder","genMeta","oFile","size","audio","video","_c","imgWidth","aborterSignal","abortMsg","convtr","createVF2BlobConvtr","reject","pngPromises","vc","resolver","it","pushPngPromise","vf","step","cur","VideoFrameFinder","thumbnailByKeyFrame","done","preVideoSlice","postVideoSlice","splitVideoSampleByTime","preAudioSlice","postAudioSlice","splitAudioSampleByTime","preClip","postClip","clip","clips","videoClip","audioClip","MP4Clip","meta","vDuration","aDuration","s","lastSampele","localFileReader","volume","AudioFrameFinder","mp4Info","videoDeltaTS","audioDeltaTS","ftyp","moov","ac","samples","normalizeTimescale","fixFirstBlackFrame","delta","sampleType","idrOffset","idrNALUOffset","conf","_dec","_ts","_curAborter","_reset","_parseFrame","_sleepCnt","_lastVfDur","_downgradeSoftDecode","_videoDecCusorIdx","_videoFrames","_outputFrameCnt","_inputChunkCnt","_predecodeErr","dec","aborter","_startDecode","err","_decoding","_getState","endIdx","hasValidFrame","readStarTime","chunks","videosamples2Chunks","readCost","first","last","rangSize","decodeGoP","f","keyIdx","encoderConf","rsVf","errMsg","memoryUsageInfo","findIndexOfSamples","_sampleRate","needResetTime","_decCusorIdx","deltaTime","_pcmData","emitFrameCnt","ramainFrameCnt","emitAudioFrames","createAudioChunksDecoder","pcmArr","outputCb","inputCnt","outputCnt","outputHandler","pcm","resampleQ","createPromiseQueue","needResample","adec","handleDecodeError","prefixStr","chunk","onResult","rsCache","waitingIdx","updateRs","emitIdx","emitRs","addIdx","task","emitCnt","gapCnt","gopStartIdx","gopEndIdx","hitIdx","hitSample","preSlice","postSlice","u8Arr","dv","nalUnitType","localFile","decConf","abortSingl","onOutput","fileReader","createVideoDec","downgrade","iframeCnt","minCtsSample","mem","_ImgClip","dataSource","_ImgClip_instances","_img","_frames","initWithImgBitmap","imgBitmap","frame","acc","__privateMethod","initAnimateImg_fn","tt","firstVf","ImgClip","_AudioClip","_AudioClip_instances","_chan0Buf","_chan1Buf","_frameOffset","init_fn","chan","tStart","parseStream2PCM","AudioClip","_MediaStreamClip","ms","_stopRenderCvs","_cvs","_ms","videoTrack","renderVideoTrackToCvs","MediaStreamClip","onOffscreenCanvasReady","emitFF","cvsCtx","autoReadStream","displayHeight","displayWidth","_EmbedSubtitlesClip","content","_EmbedSubtitlesClip_instances","_subtitles","_ctx","_lastVF","_lineHeight","_linePadding","parseSrt","text","fontSize","fontFamily","videoWidth","videoHeight","letterSpacing","renderTxt_fn","sub","preLastIt","postFirstIt","lines","color","textBgColor","textShadow","strokeStyle","lineWidth","lineCap","lineJoin","bottomOffset","bottomDistance","lineStr","txtMeas","centerX","EmbedSubtitlesClip","srtTimeToSeconds","match","hours","minutes","seconds","milliseconds","srt","str","SampleTransform","_inputBufOffset","streamCancelled","ctrl","releasedCnt","id","ui8Arr","inputBuf","fixMP4BoxFileDuration","inMP4File","sendedBoxIdx","boxes","tracks","totalDuration","write2TmpFile","box2Buf","tmpFileWriter","moovPrevBoxes","moovBoxReady","moovIdx","timerId","postFile","initPromise","stoped","rsFile","startIdx","ds","chunk2MP4SampleOpts","dts","fastConcatMP4","streams","outfile","dumpFile","concatStreamsToMP4BoxFile","outStream","vDTS","vCTS","aDTS","aCTS","lastVSamp","lastASamp","chunkType","videoTrackConf","audioTrackConf","trackId","offsetDTS","offsetCTS","lastSamp","fixFMP4Duration","createMP4AudioSampleDecoder","adConf","cacheAD","adDecoder","ss","createMP4AudioSampleEncoder","aeConf","adEncoder","lastData","createAD","ts","audioFade","sampleRate","dataLen","fadeLen","mixinMP4AndAudio","mp4Stream","stopOut","file2stream","audioSampleDecoder","audioSampleEncoder","inputAudioPCM","audioOffset","mp4HasAudio","audioDecoderConf","safeAudioTrackConf","audioCtx","addInputAudio2Track","mixinAudioSampleAndInputPCM","getInputAudioSlice","vdieoSamples","firstSamp","pcmLength","audioDataBuf","pcmFragments","mp4AudioPCM","vertexShader","fragmentShader","POINT_POS","TEX_COORD_POS","initShaderProgram","gl","vsSource","fsSource","loadShader","shaderProgram","shader","updateTexture","texture","initTexture","level","internalFormat","border","srcFormat","srcType","pixel","initCvs","v","posBuffer","a_position","texCoordBuffer","a_texCoord","getSourceWH","imgSource","getKeyColor","r","g","createChromakey","keyC","_Rect","x","y","w","h","master","_Rect_instances","_evtTool","EventTool","_x","_y","_w","_h","_angle","_master","setBaseProps_fn","rect","tx","ty","angle","center","agl","tOX","tOY","mx","my","prop","changed","Rect","BaseSprite","_time","_zIndex","_animatKeyFrame","_animatOpts","props","keyFrame","k","val","numK","updateProps","linearTimeFn","kf","offsetTime","process","startState","nextState","nextFrame","startFrame","stateProcess","_OffscreenSprite","_clip","_lastVf","duration","state","outAudio","spr","OffscreenSprite","_VisibleSprite","_VisibleSprite_instances","_lastAudio","_ticking","_lastTime","update_fn","VisibleSprite","COM_ID","letEncoderCalmDown","getQSize","Combinator","_Combinator_instances","_sprites","_stopOutput","_hasVideoTrack","args","os","logAttrs","pick","newOS","mainSpr","maxTime","remux","startRecodeMux_fn","starTime","stopReCodeMux","run_fn","prog","closeOutStream","fps","videoCodec","bitrate","metaDataTags","recodemux","onProgress","onEnded","onError","progress","bgColor","outputAudio","timeSlice","sprRender","createSpritesRender","encodeData","createAVEncoder","exit","mainSprDone","e","outProgTimer","sprites","hasVideoTrack","gopSize","audioTrackBuf","createAudioTrackBuf","adFrames","adDataSize","putOffset","audioTs","adDuration","placeholderData","getAudioData","readOffset","adCnt","trackAudios","keys","key"],"mappings":"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"}