{"version":3,"file":"av-cliper.umd.cjs","sources":["../src/chromakey.ts","../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/combinator.ts","../src/sprite/rect.ts","../src/sprite/base-sprite.ts","../src/sprite/offscreen-sprite.ts","../src/sprite/visible-sprite.ts"],"sourcesContent":["// 改编自 https://jameshfisher.com/2020/08/11/production-ready-green-screen-in-the-browser/\r\nconst vertexShader = `#version 300 es\r\n  layout (location = 0) in vec4 a_position;\r\n  layout (location = 1) in vec2 a_texCoord;\r\n  out vec2 v_texCoord;\r\n  void main () {\r\n    gl_Position = a_position;\r\n    v_texCoord = a_texCoord;\r\n  }\r\n`;\r\n\r\nconst fragmentShader = `#version 300 es\r\nprecision mediump float;\r\nout vec4 FragColor;\r\nin vec2 v_texCoord;\r\n\r\nuniform sampler2D frameTexture;\r\nuniform vec3 keyColor;\r\n\r\n// 色度的相似度计算\r\nuniform float similarity;\r\n// 透明度的平滑度计算\r\nuniform float smoothness;\r\n// 降低绿幕饱和度，提高抠图准确度\r\nuniform float spill;\r\n\r\nvec2 RGBtoUV(vec3 rgb) {\r\n  return vec2(\r\n    rgb.r * -0.169 + rgb.g * -0.331 + rgb.b *  0.5    + 0.5,\r\n    rgb.r *  0.5   + rgb.g * -0.419 + rgb.b * -0.081  + 0.5\r\n  );\r\n}\r\n\r\nvoid main() {\r\n  // 获取当前像素的rgba值\r\n  vec4 rgba = texture(frameTexture, v_texCoord);\r\n  // 计算当前像素与绿幕像素的色度差值\r\n  vec2 chromaVec = RGBtoUV(rgba.rgb) - RGBtoUV(keyColor);\r\n  // 计算当前像素与绿幕像素的色度距离（向量长度）, 越相像则色度距离越小\r\n  float chromaDist = sqrt(dot(chromaVec, chromaVec));\r\n  // 设置了一个相似度阈值，baseMask为负，则表明是绿幕，为正则表明不是绿幕\r\n  float baseMask = chromaDist - similarity;\r\n  // 如果baseMask为负数，fullMask等于0；baseMask为正数，越大，则透明度越低\r\n  float fullMask = pow(clamp(baseMask / smoothness, 0., 1.), 1.5);\r\n  rgba.a = fullMask; // 设置透明度\r\n  // 如果baseMask为负数，spillVal等于0；baseMask为整数，越小，饱和度越低\r\n  float spillVal = pow(clamp(baseMask / spill, 0., 1.), 1.5);\r\n  float desat = clamp(rgba.r * 0.2126 + rgba.g * 0.7152 + rgba.b * 0.0722, 0., 1.); // 计算当前像素的灰度值\r\n  rgba.rgb = mix(vec3(desat, desat, desat), rgba.rgb, spillVal);\r\n  FragColor = rgba;\r\n}\r\n`;\r\n\r\nconst POINT_POS = [-1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1];\r\nconst TEX_COORD_POS = [0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1];\r\n\r\n//  初始化着色器程序，让 WebGL 知道如何绘制我们的数据\r\nfunction initShaderProgram(\r\n  gl: WebGLRenderingContext,\r\n  vsSource: string,\r\n  fsSource: string,\r\n) {\r\n  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource)!;\r\n  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource)!;\r\n\r\n  // 创建着色器程序\r\n  const shaderProgram = gl.createProgram()!;\r\n  gl.attachShader(shaderProgram, vertexShader);\r\n  gl.attachShader(shaderProgram, fragmentShader);\r\n  gl.linkProgram(shaderProgram);\r\n\r\n  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {\r\n    throw Error(\r\n      gl.getProgramInfoLog(shaderProgram) ??\r\n        'Unable to initialize the shader program',\r\n    );\r\n  }\r\n\r\n  return shaderProgram;\r\n}\r\n\r\n// 创建指定类型的着色器，上传 source 源码并编译\r\nfunction loadShader(gl: WebGLRenderingContext, type: number, source: string) {\r\n  const shader = gl.createShader(type)!;\r\n\r\n  // Send the source to the shader object\r\n  gl.shaderSource(shader, source);\r\n\r\n  // Compile the shader program\r\n  gl.compileShader(shader);\r\n\r\n  // See if it compiled successfully\r\n  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\r\n    const errMsg = gl.getShaderInfoLog(shader);\r\n    gl.deleteShader(shader);\r\n    throw Error(errMsg ?? 'An error occurred compiling the shaders');\r\n  }\r\n\r\n  return shader;\r\n}\r\n\r\nfunction updateTexture(\r\n  gl: WebGLRenderingContext,\r\n  img: TImgSource,\r\n  texture: WebGLTexture,\r\n) {\r\n  gl.bindTexture(gl.TEXTURE_2D, texture);\r\n  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);\r\n  gl.drawArrays(gl.TRIANGLES, 0, 6);\r\n}\r\n\r\nfunction initTexture(gl: WebGLRenderingContext) {\r\n  const texture = gl.createTexture();\r\n  if (texture == null) throw Error('Create WebGL texture error');\r\n  gl.bindTexture(gl.TEXTURE_2D, texture);\r\n\r\n  // put a single pixel in the texture so we can use it immediately.\r\n  const level = 0;\r\n  const internalFormat = gl.RGBA;\r\n  const width = 1;\r\n  const height = 1;\r\n  const border = 0;\r\n  const srcFormat = gl.RGBA;\r\n  const srcType = gl.UNSIGNED_BYTE;\r\n  const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue\r\n  gl.texImage2D(\r\n    gl.TEXTURE_2D,\r\n    level,\r\n    internalFormat,\r\n    width,\r\n    height,\r\n    border,\r\n    srcFormat,\r\n    srcType,\r\n    pixel,\r\n  );\r\n\r\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\r\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\r\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\r\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\r\n\r\n  return texture;\r\n}\r\n\r\ninterface IChromakeyOpts {\r\n  keyColor: [number, number, number];\r\n  similarity: number;\r\n  smoothness: number;\r\n  spill: number;\r\n}\r\n\r\nfunction initCvs(\r\n  opts: {\r\n    width: number;\r\n    height: number;\r\n  } & IChromakeyOpts,\r\n) {\r\n  const cvs =\r\n    'document' in globalThis\r\n      ? globalThis.document.createElement('canvas')\r\n      : new OffscreenCanvas(opts.width, opts.height);\r\n  cvs.width = opts.width;\r\n  cvs.height = opts.height;\r\n\r\n  const gl = cvs.getContext('webgl2', {\r\n    premultipliedAlpha: false,\r\n    alpha: true,\r\n  }) as WebGL2RenderingContext | null;\r\n\r\n  if (gl == null) throw Error('Cant create gl context');\r\n\r\n  const shaderProgram = initShaderProgram(gl, vertexShader, fragmentShader);\r\n  gl.useProgram(shaderProgram);\r\n\r\n  gl.uniform3fv(\r\n    gl.getUniformLocation(shaderProgram, 'keyColor'),\r\n    opts.keyColor.map((v) => v / 255),\r\n  );\r\n  gl.uniform1f(\r\n    gl.getUniformLocation(shaderProgram, 'similarity'),\r\n    opts.similarity,\r\n  );\r\n  gl.uniform1f(\r\n    gl.getUniformLocation(shaderProgram, 'smoothness'),\r\n    opts.smoothness,\r\n  );\r\n  gl.uniform1f(gl.getUniformLocation(shaderProgram, 'spill'), opts.spill);\r\n\r\n  const posBuffer = gl.createBuffer();\r\n  gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);\r\n  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(POINT_POS), gl.STATIC_DRAW);\r\n  const a_position = gl.getAttribLocation(shaderProgram, 'a_position');\r\n  gl.vertexAttribPointer(\r\n    a_position,\r\n    2,\r\n    gl.FLOAT,\r\n    false,\r\n    Float32Array.BYTES_PER_ELEMENT * 2,\r\n    0,\r\n  );\r\n  gl.enableVertexAttribArray(a_position);\r\n\r\n  const texCoordBuffer = gl.createBuffer();\r\n  gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);\r\n  gl.bufferData(\r\n    gl.ARRAY_BUFFER,\r\n    new Float32Array(TEX_COORD_POS),\r\n    gl.STATIC_DRAW,\r\n  );\r\n  const a_texCoord = gl.getAttribLocation(shaderProgram, 'a_texCoord');\r\n  gl.vertexAttribPointer(\r\n    a_texCoord,\r\n    2,\r\n    gl.FLOAT,\r\n    false,\r\n    Float32Array.BYTES_PER_ELEMENT * 2,\r\n    0,\r\n  );\r\n  gl.enableVertexAttribArray(a_texCoord);\r\n\r\n  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);\r\n\r\n  return { cvs, gl };\r\n}\r\n\r\ntype TImgSource =\r\n  | HTMLVideoElement\r\n  | HTMLCanvasElement\r\n  | HTMLImageElement\r\n  | ImageBitmap\r\n  | OffscreenCanvas\r\n  | VideoFrame;\r\n\r\nfunction getSourceWH(imgSource: TImgSource) {\r\n  return imgSource instanceof VideoFrame\r\n    ? { width: imgSource.codedWidth, height: imgSource.codedHeight }\r\n    : { width: imgSource.width, height: imgSource.height };\r\n}\r\n\r\nfunction getKeyColor(imgSource: TImgSource) {\r\n  const cvs = new OffscreenCanvas(1, 1);\r\n  const ctx = cvs.getContext('2d')!;\r\n  ctx.drawImage(imgSource, 0, 0);\r\n  const {\r\n    data: [r, g, b],\r\n  } = ctx.getImageData(0, 0, 1, 1);\r\n  return [r, g, b] as [number, number, number];\r\n}\r\n\r\n/**\r\n * 绿幕抠图\r\n * keyColor 需要扣除的背景色，若不传则取第一个像素点\r\n * similarity 背景色相似度阈值，过小可能保留背景色，过大可能扣掉更多非背景像素点\r\n * smoothness 平滑度；过小可能出现锯齿，过大导致整体变透明\r\n * spill      饱和度；过小可能保留绿色混合，过大导致图片变灰度\r\n * @param opts: {\r\n *   keyColor?: [r, g, b]\r\n *   similarity: number\r\n *   smoothness: number\r\n *   spill: number\r\n * }\r\n */\r\nexport const createChromakey = (\r\n  opts: Omit<IChromakeyOpts, 'keyColor'> & {\r\n    keyColor?: [number, number, number];\r\n  },\r\n) => {\r\n  let cvs: HTMLCanvasElement | OffscreenCanvas | null = null;\r\n  let gl: WebGLRenderingContext | null = null;\r\n  let keyC = opts.keyColor;\r\n  let texture: WebGLTexture | null = null;\r\n\r\n  return async (imgSource: TImgSource) => {\r\n    if (cvs == null || gl == null || texture == null) {\r\n      if (keyC == null) keyC = getKeyColor(imgSource);\r\n      ({ cvs, gl } = initCvs({\r\n        ...getSourceWH(imgSource),\r\n        keyColor: keyC,\r\n        ...opts,\r\n      }));\r\n      texture = initTexture(gl);\r\n    }\r\n\r\n    updateTexture(gl, imgSource, texture);\r\n\r\n    if (\r\n      globalThis.VideoFrame != null &&\r\n      imgSource instanceof globalThis.VideoFrame\r\n    ) {\r\n      const rs = new VideoFrame(cvs, {\r\n        alpha: 'keep',\r\n        timestamp: imgSource.timestamp,\r\n        duration: imgSource.duration ?? undefined,\r\n      });\r\n      imgSource.close();\r\n      return rs;\r\n    }\r\n\r\n    return createImageBitmap(cvs, {\r\n      imageOrientation: imgSource instanceof ImageBitmap ? 'flipY' : 'none',\r\n    });\r\n  };\r\n};\r\n","// 在主线程中执行的 工具函数\r\n\r\n/**\r\n * 创建一个新的 HTML 元素\r\n * @param tagName - 要创建的元素的标签名\r\n * @returns 新创建的 HTML 元素\r\n */\r\nexport function createEl(tagName: string): HTMLElement {\r\n  return document.createElement(tagName);\r\n}\r\n\r\nfunction arrayBufferToBase64(buffer: ArrayBuffer) {\r\n  var binary = '';\r\n  var bytes = new Uint8Array(buffer);\r\n  var len = bytes.byteLength;\r\n  for (let i = 0; i < len; i++) {\r\n    binary += String.fromCharCode(bytes[i]);\r\n  }\r\n  return window.btoa(binary);\r\n}\r\n\r\n/**\r\n * 将文本渲染为图片\r\n * @param txt - 要渲染的文本\r\n * @param cssText - 应用于文本的 CSS 样式\r\n * @returns 渲染后的图片元素\r\n */\r\nexport async function renderTxt2Img(\r\n  txt: string,\r\n  cssText: string,\r\n  opts: {\r\n    font?: { name: string; url: string };\r\n    onCreated?: (el: HTMLElement) => void;\r\n  } = {},\r\n): Promise<HTMLImageElement> {\r\n  const div = createEl('pre');\r\n  div.style.cssText = `margin: 0; ${cssText}; position: fixed;`;\r\n  div.textContent = txt;\r\n  document.body.appendChild(div);\r\n  opts.onCreated?.(div);\r\n\r\n  const { width, height } = div.getBoundingClientRect();\r\n  // 计算出 rect，立即从dom移除\r\n  div.remove();\r\n\r\n  const img = new Image();\r\n  img.width = width;\r\n  img.height = height;\r\n  const fontFaceStr =\r\n    opts.font == null\r\n      ? ''\r\n      : `\r\n    @font-face {\r\n      font-family: '${opts.font.name}';\r\n      src: url('data:font/woff2;base64,${arrayBufferToBase64(await (await fetch(opts.font.url)).arrayBuffer())}') format('woff2');\r\n    }\r\n  `;\r\n  const svgStr = `\r\n    <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\">\r\n      <style>\r\n        ${fontFaceStr}\r\n      </style>\r\n      <foreignObject width=\"100%\" height=\"100%\">\r\n        <div xmlns=\"http://www.w3.org/1999/xhtml\">${div.outerHTML}</div>\r\n      </foreignObject>\r\n    </svg>\r\n  `\r\n    .replace(/\\t/g, '')\r\n    .replace(/#/g, '%23');\r\n\r\n  img.src = `data:image/svg+xml;charset=utf-8,${svgStr}`;\r\n\r\n  await new Promise((resolve) => {\r\n    img.onload = resolve;\r\n  });\r\n  return img;\r\n}\r\n\r\n/**\r\n * 将文本渲染为 {@link ImageBitmap}，用来创建 {@link ImgClip}\r\n * @param txt - 要渲染的文本\r\n * @param cssText - 应用于文本的 CSS 样式\r\n * @param opts - 选项\r\n * @param opts.font -  自定义字体\r\n * @param opts.onCreated - 创建完成后的回调\r\n *\r\n * @example\r\n * new ImgClip(\r\n *   await renderTxt2ImgBitmap(\r\n *     '水印',\r\n *    `font-size:40px; color: white; text-shadow: 2px 2px 6px red; font-family: CustomFont;`,\r\n *    {\r\n *      font: {\r\n *        name: 'CustomFont',\r\n *        url: '/CustomFont.ttf',\r\n *      },\r\n *    },\r\n *   )\r\n * )\r\n */\r\nexport async function renderTxt2ImgBitmap(\r\n  txt: string,\r\n  cssText: string,\r\n  opts: {\r\n    font?: { name: string; url: string };\r\n    onCreated?: (el: HTMLElement) => void;\r\n  } = {},\r\n): Promise<ImageBitmap> {\r\n  const imgEl = await renderTxt2Img(txt, cssText, opts);\r\n  const cvs = new OffscreenCanvas(imgEl.width, imgEl.height);\r\n  const ctx = cvs.getContext('2d');\r\n  ctx?.drawImage(imgEl, 0, 0, imgEl.width, imgEl.height);\r\n  return await createImageBitmap(cvs);\r\n}\r\n","// 能同时在 worker 和主线程中运行的工具函数\n\nimport { workerTimer } from '@webrock/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 * 改变 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 {\r\n  width: number;\r\n  height: number;\r\n  duration: number;\r\n}\r\n\r\n/**\r\n * 所有素材需要实现的接口\r\n *\r\n * 素材（Clip）是不同数据类型的抽象，给其他模块提供数据\r\n *\r\n * WebAV 内置了 {@link MP4Clip}, {@link AudioClip}, {@link ImgClip}, {@link MediaStreamClip} 等常用素材，用于给 {@link Combinator} {@link AVCanvas} 提供数据\r\n *\r\n * 你只需实现该接口即可自定义素材，拥有最大的灵活度来生成视频内容，比如动画、转场效果等\r\n * @see [自定义素材](https://webav-tech.github.io/WebAV/demo/2_6-custom-clip)\r\n *\r\n */\r\nexport interface IClip {\r\n  /**\r\n   * 从素材中提取指定时间数据\r\n   * @param time 时间，单位 微秒\r\n   */\r\n  tick: (time: number) => Promise<{\r\n    video?: VideoFrame | ImageBitmap | null;\r\n    audio?: Float32Array[];\r\n    state: 'done' | 'success';\r\n  }>;\r\n\r\n  /**\r\n   * 当素材准备完成，ready 会切换到 resolved 状态\r\n   */\r\n  readonly ready: Promise<IClipMeta>;\r\n\r\n  /**\r\n   * 数据元数据\r\n   */\r\n  readonly meta: IClipMeta;\r\n\r\n  /**\r\n   * clone，返回一个新素材\r\n   */\r\n  clone: () => Promise<this>;\r\n\r\n  /**\r\n   * 按指定时间切割，返回该时刻前后两个新素材，常用于剪辑场景按时间分割素材\r\n   *\r\n   * 该方法不会破坏原素材的数据\r\n   *\r\n   * @param time 时间，微秒\r\n   * @returns\r\n   */\r\n  split?: (time: number) => Promise<[this, this]>;\r\n\r\n  /**\r\n   * 销毁实例，释放资源\r\n   */\r\n  destroy: () => void;\r\n}\r\n\r\n/**\r\n * 默认的音频设置，⚠️ 不要变更它的值 ⚠️\r\n */\r\nexport const DEFAULT_AUDIO_CONF = {\r\n  sampleRate: 48000,\r\n  channelCount: 2,\r\n  codec: 'mp4a.40.2',\r\n} as const;\r\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 { file } from 'opfs-tools';\nimport { DEFAULT_AUDIO_CONF } from '../clips';\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:\n        videoDesc instanceof Uint8Array ? videoDesc : new Uint8Array(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 { Log } from '@webrock/internal-utils';\nimport { file, tmpfile, write } from 'opfs-tools';\nimport { audioResample, extractPCM4AudioData, sleep } from '../av-utils';\nimport {\n  extractFileConfig,\n  quickParseMP4File,\n} from '../mp4-utils/mp4box-utils';\nimport { DEFAULT_AUDIO_CONF, IClip } from './iclip';\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 { Log } from '@webrock/internal-utils';\nimport { decodeImg } from '../av-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 { Log } from '@webrock/internal-utils';\nimport {\n  concatPCMFragments,\n  extractPCM4AudioBuffer,\n  ringSliceFloat32Array,\n} from '../av-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: Float32Array = new Float32Array();\n  #chan1Buf: Float32Array = 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 '@webrock/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';\r\n\r\ninterface IEmbedSubtitlesOpts {\r\n  color?: string;\r\n  textBgColor?: string | null;\r\n  type?: 'srt';\r\n  fontFamily?: string;\r\n  fontSize?: number;\r\n  letterSpacing?: string | null;\r\n  // 字幕偏离底部的距离\r\n  bottomOffset?: number;\r\n  strokeStyle?: string;\r\n  lineWidth?: number | null;\r\n  lineCap?: CanvasLineCap | null;\r\n  lineJoin?: CanvasLineJoin | null;\r\n  textShadow?: {\r\n    offsetX: number;\r\n    offsetY: number;\r\n    blur: number;\r\n    color: string;\r\n  };\r\n  videoWidth: number;\r\n  videoHeight: number;\r\n  fontWeight?: string | number;\r\n  fontStyle?: 'normal' | 'italic';\r\n}\r\n\r\ndeclare global {\r\n  interface OffscreenCanvasRenderingContext2D {\r\n    letterSpacing: string;\r\n  }\r\n}\r\n\r\ninterface SubtitleStruct {\r\n  start: number;\r\n  end: number;\r\n  text: string;\r\n}\r\n\r\n/**\r\n * 嵌入式字幕，将字幕（目前仅支持 SRT 格式）嵌入视频画面中\r\n *\r\n * @example\r\n * const es = new EmbedSubtitlesClip(srtSubtitleStr, {\r\n *   videoWidth: 1280,\r\n *   videoHeight: 720,\r\n *   fontFamily: 'Noto Sans SC',\r\n *   color: 'white',\r\n * });\r\n */\r\nexport class EmbedSubtitlesClip implements IClip {\r\n  ready: IClip['ready'];\r\n\r\n  #subtitles: SubtitleStruct[] = [];\r\n\r\n  #meta = {\r\n    width: 0,\r\n    height: 0,\r\n    duration: 0,\r\n  };\r\n\r\n  get meta() {\r\n    return { ...this.#meta };\r\n  }\r\n\r\n  #opts: Required<IEmbedSubtitlesOpts> = {\r\n    color: '#FFF',\r\n    textBgColor: null,\r\n    type: 'srt',\r\n    fontSize: 30,\r\n    letterSpacing: null,\r\n    bottomOffset: 30,\r\n    fontFamily: 'Noto Sans SC',\r\n    strokeStyle: '#000',\r\n    lineWidth: null,\r\n    lineCap: null,\r\n    lineJoin: null,\r\n    textShadow: {\r\n      offsetX: 2,\r\n      offsetY: 2,\r\n      blur: 4,\r\n      color: '#000',\r\n    },\r\n    videoWidth: 1280,\r\n    videoHeight: 720,\r\n    fontWeight: 'normal',\r\n    fontStyle: 'normal',\r\n  };\r\n\r\n  #cvs: OffscreenCanvas;\r\n  #ctx: OffscreenCanvasRenderingContext2D;\r\n\r\n  #lastVF: VideoFrame | null = null;\r\n\r\n  #lineHeight = 0;\r\n  #linePadding = 0;\r\n\r\n  constructor(content: string | SubtitleStruct[], opts: IEmbedSubtitlesOpts) {\r\n    this.#subtitles = Array.isArray(content)\r\n      ? content\r\n      : parseSrt(content).map(({ start, end, text }) => ({\r\n          start: start * 1e6,\r\n          end: end * 1e6,\r\n          text,\r\n        }));\r\n    if (this.#subtitles.length === 0) throw Error('No subtitles content');\r\n\r\n    this.#opts = Object.assign(this.#opts, opts);\r\n    // 如果需要绘制背景，则需要给文字添加边距\r\n    this.#linePadding =\r\n      opts.textBgColor == null ? 0 : (opts.fontSize ?? 50) * 0.2;\r\n\r\n    const {\r\n      fontSize,\r\n      fontFamily,\r\n      fontWeight,\r\n      fontStyle,\r\n      videoWidth,\r\n      videoHeight,\r\n      letterSpacing,\r\n    } = this.#opts;\r\n    this.#lineHeight = fontSize + this.#linePadding * 2;\r\n    this.#cvs = new OffscreenCanvas(videoWidth, videoHeight);\r\n    this.#ctx = this.#cvs.getContext('2d')!;\r\n    this.#ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;\r\n    this.#ctx.textAlign = 'center';\r\n    this.#ctx.textBaseline = 'top';\r\n    this.#ctx.letterSpacing = letterSpacing ?? '0px';\r\n\r\n    this.#meta = {\r\n      width: videoWidth,\r\n      height: videoHeight,\r\n      duration: this.#subtitles.at(-1)?.end ?? 0,\r\n    };\r\n    // 字幕的宽高 由视频画面内容决定\r\n    this.ready = Promise.resolve(this.meta);\r\n  }\r\n\r\n  #renderTxt(txt: string) {\r\n    const lines = txt\r\n      .split('\\n')\r\n      .reverse()\r\n      .map((t) => t.trim());\r\n\r\n    const { width, height } = this.#cvs;\r\n\r\n    const {\r\n      color,\r\n      fontSize,\r\n      textBgColor,\r\n      textShadow,\r\n      strokeStyle,\r\n      lineWidth,\r\n      lineCap,\r\n      lineJoin,\r\n      bottomOffset,\r\n    } = this.#opts;\r\n    const ctx = this.#ctx;\r\n\r\n    ctx.clearRect(0, 0, width, height);\r\n    ctx.globalAlpha = 0.6;\r\n    // 测试canvas背景\r\n    // ctx.fillStyle = 'red'\r\n    // ctx.fillRect(0, 0, this.#cvs.width, this.#cvs.height)\r\n\r\n    let bottomDistance = bottomOffset;\r\n    for (const lineStr of lines) {\r\n      const txtMeas = ctx.measureText(lineStr);\r\n      const centerX = width / 2;\r\n      if (textBgColor != null) {\r\n        ctx.shadowOffsetX = 0;\r\n        ctx.shadowOffsetY = 0;\r\n        ctx.shadowBlur = 0;\r\n        // 字幕背景\r\n        ctx.fillStyle = textBgColor;\r\n        ctx.globalAlpha = 0.5;\r\n        ctx.fillRect(\r\n          centerX - txtMeas.actualBoundingBoxLeft - this.#linePadding,\r\n          height - bottomDistance - this.#lineHeight,\r\n          txtMeas.width + this.#linePadding * 2,\r\n          this.#lineHeight,\r\n        );\r\n      } else {\r\n      }\r\n\r\n      ctx.shadowColor = textShadow.color;\r\n      ctx.shadowOffsetX = textShadow.offsetX;\r\n      ctx.shadowOffsetY = textShadow.offsetY;\r\n      ctx.shadowBlur = textShadow.blur;\r\n\r\n      ctx.globalAlpha = 1;\r\n\r\n      if (strokeStyle != null) {\r\n        ctx.lineWidth = lineWidth ?? fontSize / 6;\r\n        if (lineCap != null) ctx.lineCap = lineCap;\r\n        if (lineJoin != null) ctx.lineJoin = lineJoin;\r\n        ctx.strokeStyle = strokeStyle;\r\n        ctx.strokeText(\r\n          lineStr,\r\n          centerX,\r\n          height - bottomDistance - this.#lineHeight + this.#linePadding,\r\n        );\r\n      }\r\n\r\n      ctx.fillStyle = color;\r\n      ctx.fillText(\r\n        lineStr,\r\n        centerX,\r\n        height - bottomDistance - this.#lineHeight + this.#linePadding,\r\n      );\r\n\r\n      // 多行，底部偏移距离叠加\r\n      bottomDistance += this.#lineHeight + fontSize * 0.2;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * @see {@link IClip.tick}\r\n   */\r\n  async tick(time: number): Promise<{\r\n    video?: VideoFrame;\r\n    state: 'done' | 'success';\r\n  }> {\r\n    if (\r\n      this.#lastVF != null &&\r\n      time >= this.#lastVF.timestamp &&\r\n      time <= this.#lastVF.timestamp + (this.#lastVF.duration ?? 0)\r\n    ) {\r\n      return { video: this.#lastVF.clone(), state: 'success' };\r\n    }\r\n\r\n    let i = 0;\r\n    for (; i < this.#subtitles.length; i += 1) {\r\n      if (time <= this.#subtitles[i].end) break;\r\n    }\r\n\r\n    const it = this.#subtitles[i] ?? this.#subtitles.at(-1);\r\n    if (time > it.end) return { state: 'done' };\r\n    if (time < it.start) {\r\n      // 此时无字幕内容，清空画布\r\n      this.#ctx.clearRect(0, 0, this.#cvs.width, this.#cvs.height);\r\n      const vf = new VideoFrame(this.#cvs, {\r\n        timestamp: time,\r\n        // 直到下个字幕出现的时机\r\n        duration: it.start - time,\r\n      });\r\n      this.#lastVF?.close();\r\n      this.#lastVF = vf;\r\n\r\n      return { video: vf.clone(), state: 'success' };\r\n    }\r\n\r\n    this.#renderTxt(it.text);\r\n\r\n    const vf = new VideoFrame(this.#cvs, {\r\n      timestamp: time,\r\n      duration: it.end - time,\r\n    });\r\n    this.#lastVF?.close();\r\n    this.#lastVF = vf;\r\n\r\n    return { video: vf.clone(), state: 'success' };\r\n  }\r\n\r\n  /**\r\n   * @see {@link IClip.split}\r\n   */\r\n  async split(time: number) {\r\n    await this.ready;\r\n    let hitIdx = -1;\r\n    for (let i = 0; i < this.#subtitles.length; i++) {\r\n      const sub = this.#subtitles[i];\r\n      if (time > sub.start) continue;\r\n      hitIdx = i;\r\n      break;\r\n    }\r\n    if (hitIdx === -1) throw Error('Not found subtitle by time');\r\n    const preSlice = this.#subtitles.slice(0, hitIdx).map((s) => ({ ...s }));\r\n    let preLastIt = preSlice.at(-1);\r\n    let postFirstIt = null;\r\n    // 切割时间命中字幕区间，需要将当前字幕元素拆成前后两份\r\n    if (preLastIt != null && preLastIt.end > time) {\r\n      postFirstIt = {\r\n        start: 0,\r\n        end: preLastIt.end - time,\r\n        text: preLastIt.text,\r\n      };\r\n\r\n      preLastIt.end = time;\r\n    }\r\n    const postSlice = this.#subtitles\r\n      .slice(hitIdx)\r\n      .map((s) => ({ ...s, start: s.start - time, end: s.end - time }));\r\n    if (postFirstIt != null) postSlice.unshift(postFirstIt);\r\n    return [\r\n      new EmbedSubtitlesClip(preSlice, this.#opts),\r\n      new EmbedSubtitlesClip(postSlice, this.#opts),\r\n    ] as [this, this];\r\n  }\r\n\r\n  /**\r\n   * @see {@link IClip.clone}\r\n   */\r\n  async clone() {\r\n    return new EmbedSubtitlesClip(this.#subtitles.slice(0), this.#opts) as this;\r\n  }\r\n\r\n  /**\r\n   * @see {@link IClip.destroy}\r\n   */\r\n  destroy() {\r\n    this.#lastVF?.close();\r\n  }\r\n}\r\n\r\n// SRT字幕格式 https://www.cnblogs.com/tocy/p/subtitle-format-srt.html\r\nfunction srtTimeToSeconds(time: string) {\r\n  const match = time.match(/(\\d{2}):(\\d{2}):(\\d{2}),(\\d{3})/);\r\n  if (match == null) throw Error(`time format error: ${time}`);\r\n\r\n  const hours = Number(match[1]);\r\n  const minutes = Number(match[2]);\r\n  const seconds = Number(match[3]);\r\n  const milliseconds = Number(match[4]);\r\n\r\n  return hours * 60 * 60 + minutes * 60 + seconds + milliseconds / 1000;\r\n}\r\n\r\nfunction parseSrt(srt: string) {\r\n  return (\r\n    srt\r\n      .split(/\\r|\\n/)\r\n      .map((s) => s.trim())\r\n      .filter((str) => str.length > 0)\r\n      // 匹配时间戳标记行，匹配失败的为字幕内容\r\n      .map((s) => ({\r\n        lineStr: s,\r\n        match: s.match(\r\n          /(\\d{2}:\\d{2}:\\d{2},\\d{3}) --> (\\d{2}:\\d{2}:\\d{2},\\d{3})/,\r\n        ),\r\n      }))\r\n      // 过滤掉时间上一行的数字标记\r\n      .filter(\r\n        ({ lineStr }, idx, source) =>\r\n          !(/^\\d+$/.test(lineStr) && source[idx + 1]?.match != null),\r\n      )\r\n      // 按时间标记行聚合，拼接字幕内容到 text 字段\r\n      .reduce(\r\n        (acc, { lineStr, match }) => {\r\n          if (match == null) {\r\n            const last = acc.at(-1);\r\n            if (last == null) return acc;\r\n\r\n            last.text += last.text.length === 0 ? lineStr : `\\n${lineStr}`;\r\n          } else {\r\n            acc.push({\r\n              start: srtTimeToSeconds(match[1]),\r\n              end: srtTimeToSeconds(match[2]),\r\n              text: '',\r\n            });\r\n          }\r\n\r\n          return acc;\r\n        },\r\n        [] as Array<{\r\n          start: number;\r\n          end: number;\r\n          text: string;\r\n        }>,\r\n      )\r\n  );\r\n}\r\n","import mp4box, {\r\n  MP4ArrayBuffer,\r\n  MP4File,\r\n  MP4Info,\r\n  MP4Sample,\r\n} from '@webav/mp4box.js';\r\n\r\n/**\r\n * 将原始字节流转换成 MP4Sample 流\r\n */\r\nexport class SampleTransform {\r\n  readable: ReadableStream<\r\n    | {\r\n        chunkType: 'ready';\r\n        data: { info: MP4Info; file: MP4File };\r\n      }\r\n    | {\r\n        chunkType: 'samples';\r\n        data: { id: number; type: 'video' | 'audio'; samples: MP4Sample[] };\r\n      }\r\n  >;\r\n\r\n  writable: WritableStream<Uint8Array>;\r\n\r\n  #inputBufOffset = 0;\r\n\r\n  constructor() {\r\n    const file = mp4box.createFile();\r\n    let streamCancelled = false;\r\n    this.readable = new ReadableStream(\r\n      {\r\n        start: (ctrl) => {\r\n          file.onReady = (info) => {\r\n            const vTrackId = info.videoTracks[0]?.id;\r\n            if (vTrackId != null)\r\n              file.setExtractionOptions(vTrackId, 'video', { nbSamples: 100 });\r\n\r\n            const aTrackId = info.audioTracks[0]?.id;\r\n            if (aTrackId != null)\r\n              file.setExtractionOptions(aTrackId, 'audio', { nbSamples: 100 });\r\n\r\n            ctrl.enqueue({ chunkType: 'ready', data: { info, file } });\r\n            file.start();\r\n          };\r\n\r\n          const releasedCnt: Record<number, number> = {};\r\n          file.onSamples = (id, type, samples) => {\r\n            ctrl.enqueue({\r\n              chunkType: 'samples',\r\n              data: { id, type, samples: samples.map((s) => ({ ...s })) },\r\n            });\r\n            releasedCnt[id] = (releasedCnt[id] ?? 0) + samples.length;\r\n            file.releaseUsedSamples(id, releasedCnt[id]);\r\n          };\r\n\r\n          file.onFlush = () => {\r\n            ctrl.close();\r\n          };\r\n        },\r\n        cancel: () => {\r\n          file.stop();\r\n          streamCancelled = true;\r\n        },\r\n      },\r\n      {\r\n        // 每条消息 100 个 samples\r\n        highWaterMark: 50,\r\n      },\r\n    );\r\n\r\n    this.writable = new WritableStream({\r\n      write: async (ui8Arr) => {\r\n        if (streamCancelled) {\r\n          this.writable.abort();\r\n          return;\r\n        }\r\n\r\n        const inputBuf = ui8Arr.buffer as MP4ArrayBuffer;\r\n        inputBuf.fileStart = this.#inputBufOffset;\r\n        this.#inputBufOffset += inputBuf.byteLength;\r\n        file.appendBuffer(inputBuf);\r\n      },\r\n      close: () => {\r\n        file.flush();\r\n        file.stop();\r\n        file.onFlush?.();\r\n      },\r\n    });\r\n  }\r\n}\r\n","import mp4box, {\n  MP4File,\n  MP4Sample,\n  SampleOpts,\n  TrakBoxParser,\n} from '@webav/mp4box.js';\nimport { autoReadStream, file2stream, Log } from '@webrock/internal-utils';\nimport { tmpfile, write } from 'opfs-tools';\nimport {\n  concatPCMFragments,\n  extractPCM4AudioBuffer,\n  extractPCM4AudioData,\n  mixinPCM,\n  ringSliceFloat32Array,\n} from '../av-utils';\nimport { DEFAULT_AUDIO_CONF } from '../clips';\nimport { extractFileConfig } from './mp4box-utils';\nimport { SampleTransform } from './sample-transform';\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              const ab = s.data.buffer.slice(\n                s.data.byteOffset,\n                s.data.byteOffset + s.data.byteLength,\n              );\n              outfile.addSample(\n                trackId,\n                ab instanceof ArrayBuffer ? ab : new ArrayBuffer(0),\n                {\n                  duration: s.duration,\n                  dts: s.dts + offsetDTS,\n                  cts: s.cts + offsetCTS,\n                  is_sync: s.is_sync,\n                },\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) => {\n            const ab = s.data.buffer.slice(\n              s.data.byteOffset,\n              s.data.byteOffset + s.data.byteLength,\n            );\n            outfile.addSample(\n              id,\n              ab instanceof ArrayBuffer ? ab : new ArrayBuffer(0),\n              s,\n            );\n          });\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","import {\n  EventTool,\n  file2stream,\n  Log,\n  recodemux,\n} from '@webrock/internal-utils';\nimport { sleep } from './av-utils';\nimport { DEFAULT_AUDIO_CONF } from './clips';\nimport { OffscreenSprite } from './sprite/offscreen-sprite';\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","import { EventTool } from '@webrock/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 '@webrock/internal-utils';\nimport { IRectBaseProps, Rect } from './rect';\n\n// 缓动函数类型\nexport enum EasingType {\n  Linear = 'linear',\n  EaseIn = 'ease-in',\n  EaseOut = 'ease-out',\n  EaseInOut = 'ease-in-out',\n  EaseInQuad = 'ease-in-quad',\n  EaseOutQuad = 'ease-out-quad',\n  EaseInOutQuad = 'ease-in-out-quad',\n  EaseInCubic = 'ease-in-cubic',\n  EaseOutCubic = 'ease-out-cubic',\n  EaseInOutCubic = 'ease-in-out-cubic',\n  EaseInBack = 'ease-in-back',\n  EaseOutBack = 'ease-out-back',\n  EaseInOutBack = 'ease-in-out-back',\n  EaseInBounce = 'ease-in-bounce',\n  EaseOutBounce = 'ease-out-bounce',\n  EaseInOutBounce = 'ease-in-out-bounce',\n}\n\n// 缓动函数映射\nexport const EASING_FUNCTIONS = {\n  [EasingType.Linear]: (t: number) => t,\n  [EasingType.EaseIn]: (t: number) => t * t,\n  [EasingType.EaseOut]: (t: number) => 1 - (1 - t) * (1 - t),\n  [EasingType.EaseInOut]: (t: number) =>\n    t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,\n  [EasingType.EaseInQuad]: (t: number) => t * t,\n  [EasingType.EaseOutQuad]: (t: number) => 1 - (1 - t) * (1 - t),\n  [EasingType.EaseInOutQuad]: (t: number) =>\n    t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,\n  [EasingType.EaseInCubic]: (t: number) => t * t * t,\n  [EasingType.EaseOutCubic]: (t: number) => 1 - Math.pow(1 - t, 3),\n  [EasingType.EaseInOutCubic]: (t: number) =>\n    t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,\n  [EasingType.EaseInBack]: (t: number) => {\n    const c1 = 1.70158;\n    const c3 = c1 + 1;\n    return c3 * t * t * t - c1 * t * t;\n  },\n  [EasingType.EaseOutBack]: (t: number) => {\n    const c1 = 1.70158;\n    const c3 = c1 + 1;\n    return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);\n  },\n  [EasingType.EaseInOutBack]: (t: number) => {\n    const c1 = 1.70158;\n    const c2 = c1 * 1.525;\n    return t < 0.5\n      ? (Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2\n      : (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;\n  },\n  [EasingType.EaseInBounce]: (t: number) =>\n    1 - EASING_FUNCTIONS[EasingType.EaseOutBounce](1 - t),\n  [EasingType.EaseOutBounce]: (t: number) => {\n    const n1 = 7.5625;\n    const d1 = 2.75;\n    if (t < 1 / d1) {\n      return n1 * t * t;\n    } else if (t < 2 / d1) {\n      return n1 * (t -= 1.5 / d1) * t + 0.75;\n    } else if (t < 2.5 / d1) {\n      return n1 * (t -= 2.25 / d1) * t + 0.9375;\n    } else {\n      return n1 * (t -= 2.625 / d1) * t + 0.984375;\n    }\n  },\n  [EasingType.EaseInOutBounce]: (t: number) => {\n    return t < 0.5\n      ? (1 - EASING_FUNCTIONS[EasingType.EaseOutBounce](1 - 2 * t)) / 2\n      : (1 + EASING_FUNCTIONS[EasingType.EaseOutBounce](2 * t - 1)) / 2;\n  },\n};\n\ninterface IAnimationOpts {\n  duration: number;\n  delay?: number;\n  iterCount?: number;\n  easing?: EasingType;\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  rect = new Rect();\n\n  #time = {\n    offset: 0,\n    duration: 0,\n    playbackRate: 1,\n  };\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  on = this.#evtTool.on;\n\n  #zIndex = 0;\n  get zIndex(): number {\n    return this.#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  opacity = 1;\n  flip: 'horizontal' | 'vertical' | null = null;\n\n  // #animatKeyFrame: TAnimationKeyFrame | null = null;\n  // #animatOpts: Required<IAnimationOpts> | null = null;\n  public animatKeyFrame: TAnimationKeyFrame | null = null;\n  public animatOpts: Required<IAnimationOpts> | null = null;\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      this.flip === 'horizontal' ? -1 : 1,\n      0,\n      0,\n      this.flip === 'vertical' ? -1 : 1,\n      center.x,\n      center.y,\n    );\n    ctx.rotate((this.flip == null ? 1 : -1) * angle);\n    ctx.globalAlpha = this.opacity;\n  }\n\n  /**\n   * 给素材添加动画，支持缓动\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      easing: opts.easing ?? EasingType.Linear,\n    });\n  }\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  copyStateTo<T extends BaseSprite>(target: T) {\n    target.animatKeyFrame = this.animatKeyFrame\n      ? JSON.parse(JSON.stringify(this.animatKeyFrame))\n      : null;\n    target.animatOpts = this.animatOpts ? { ...this.animatOpts } : null;\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\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  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 rawStateProcess =\n    (process - startState[0]) / (nextState[0] - startState[0]);\n  const easingFn =\n    EASING_FUNCTIONS[opts.easing!] ?? EASING_FUNCTIONS[EasingType.Linear];\n  const stateProcess = easingFn(rawStateProcess);\n\n  for (const prop in nextFrame) {\n    const p = prop as keyof TAnimateProps;\n    if (startFrame[p] == null) continue;\n    // @ts-expect-error\n    rs[p] = (nextFrame[p] - startFrame[p]) * stateProcess + startFrame[p];\n  }\n\n  return rs;\n}\n","import { Log } from '@webrock/internal-utils';\nimport { changePCMPlaybackRate } from '../av-utils';\nimport { IClip } from '../clips';\nimport { BaseSprite } from './base-sprite';\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 { Log } from '@webrock/internal-utils';\nimport { changePCMPlaybackRate } from '../av-utils';\nimport { IClip } from '../clips';\nimport { BaseSprite } from './base-sprite';\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    if (this.#lastTime === time) return;\n    this.#update(time);\n    this.#lastTime = 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"],"names":["vertexShader","fragmentShader","POINT_POS","TEX_COORD_POS","initShaderProgram","gl","vsSource","fsSource","loadShader","shaderProgram","type","source","shader","errMsg","updateTexture","img","texture","initTexture","level","internalFormat","width","height","border","srcFormat","srcType","pixel","initCvs","opts","cvs","v","posBuffer","a_position","texCoordBuffer","a_texCoord","getSourceWH","imgSource","getKeyColor","ctx","r","g","b","createChromakey","keyC","rs","createEl","tagName","arrayBufferToBase64","buffer","binary","bytes","len","i","renderTxt2Img","txt","cssText","div","_a","fontFaceStr","svgStr","resolve","renderTxt2ImgBitmap","imgEl","concatFloat32Array","bufs","buf","a","offset","concatPCMFragments","fragments","chanListPCM","j","extractPCM4AudioData","ad","idx","chanBufSize","chanBuf","convertF32ToPlanar","convertS16ToF32Planar","pcmS16Data","numChannels","numSamples","planarData","channel","sample","pcmF32Data","extractPCM4AudioBuffer","ab","_","decodeImg","stream","init","imageDecoder","frameCnt","mixinPCM","audios","maxLen","data","bufIdx","chan0","chan1","trackIdx","_c0","_c1","_b","audioResample","pcmData","curRate","target","chanCnt","emptyPCM","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","__privateAdd","_insId","_log","Log","__privateGet","__publicField","_destroyed","_meta","_localFile","_headerBoxPos","_volume","_videoSamples","_audioSamples","_videoFrameFinder","_audioFrameFinder","_decoderConf","_opts","tickRet","_thumbAborter","__privateSet","initByStream","s","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","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","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","fontWeight","fontStyle","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","COM_ID","letEncoderCalmDown","getQSize","Combinator","_Combinator_instances","_sprites","_stopOutput","_hasVideoTrack","_evtTool","EventTool","args","os","logAttrs","pick","newOS","mainSpr","maxTime","remux","startRecodeMux_fn","starTime","stopReCodeMux","run_fn","prog","closeOutStream","duration","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","_Rect","x","y","w","h","master","_Rect_instances","_x","_y","_w","_h","_angle","_master","setBaseProps_fn","rect","tx","ty","angle","center","agl","tOX","tOY","mx","my","prop","changed","Rect","EASING_FUNCTIONS","c2","BaseSprite","_time","_zIndex","props","keyFrame","k","val","numK","updateProps","linearTimeFn","kf","offsetTime","process","startState","nextState","nextFrame","startFrame","rawStateProcess","stateProcess","_OffscreenSprite","_clip","_lastVf","state","outAudio","spr","OffscreenSprite","_VisibleSprite","_VisibleSprite_instances","_lastAudio","_ticking","_lastTime","update_fn","VisibleSprite"],"mappings":"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"}