diff --git a/.changeset/violet-rules-fly.md b/.changeset/violet-rules-fly.md new file mode 100644 index 00000000..90563983 --- /dev/null +++ b/.changeset/violet-rules-fly.md @@ -0,0 +1,5 @@ +--- +'@webav/av-cliper': patch +--- + +add tickInterceptor to audio-clip diff --git a/packages/av-cliper/src/clips/__tests__/audio-clip.test.ts b/packages/av-cliper/src/clips/__tests__/audio-clip.test.ts index 439690f9..ed57558a 100644 --- a/packages/av-cliper/src/clips/__tests__/audio-clip.test.ts +++ b/packages/av-cliper/src/clips/__tests__/audio-clip.test.ts @@ -28,6 +28,21 @@ test('AudioClip tick', async () => { expect(s2).toBe('done'); }); +test('AudioClip tickInterceptor', async () => { + const clip = new AudioClip((await fetch(m4a_44kHz_2chan)).body!); + let frameCnt = 0; + clip.tickInterceptor = async (_, tickRet) => { + if (tickRet.audio != null) frameCnt += 1; + return tickRet; + }; + await clip.ready; + await clip.tick(1000 * 30 * 2); + await clip.tick(-1); + await clip.tick(180 * 1e6); + + expect(frameCnt).toBe(3); +}); + test('AudioClip volume', async () => { const clip1 = new AudioClip((await fetch(m4a_44kHz_2chan)).body!); const clip2 = new AudioClip((await fetch(m4a_44kHz_2chan)).body!, { diff --git a/packages/av-cliper/src/clips/audio-clip.ts b/packages/av-cliper/src/clips/audio-clip.ts index 9c8b15b1..876978e9 100644 --- a/packages/av-cliper/src/clips/audio-clip.ts +++ b/packages/av-cliper/src/clips/audio-clip.ts @@ -113,6 +113,18 @@ export class AudioClip implements IClip { ); } + /** + * 拦截 {@link AudioClip.tick} 方法返回的数据,用于对音频数据二次处理 + * @param time 调用 tick 的时间 + * @param tickRet tick 返回的数据 + * + * @see [移除视频绿幕背景](https://bilibili.github.io/WebAV/demo/3_2-chromakey-video) + */ + tickInterceptor: >>( + time: number, + tickRet: T, + ) => Promise = async (_, tickRet) => tickRet; + // 微秒 #ts = 0; #frameOffset = 0; @@ -131,7 +143,7 @@ export class AudioClip implements IClip { }> { if (!this.#opts.loop && time >= this.#meta.duration) { // 待观察:如果time跨度较大,返回done,理论上会丢失一些音频帧 - return { audio: [], state: 'done' }; + return await this.tickInterceptor(time, { audio: [], state: 'done' }); } const deltaTime = time - this.#ts; @@ -142,10 +154,10 @@ export class AudioClip implements IClip { this.#frameOffset = Math.ceil( (this.#ts / 1e6) * DEFAULT_AUDIO_CONF.sampleRate, ); - return { + return await this.tickInterceptor(time, { audio: [new Float32Array(0), new Float32Array(0)], state: 'success', - }; + }); } this.#ts = time; @@ -164,7 +176,7 @@ export class AudioClip implements IClip { ]; this.#frameOffset = endIdx; - return { audio, state: 'success' }; + return await this.tickInterceptor(time, { audio, state: 'success' }); } /**