Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: resolve size mismatch issue in MediaStreamClip during tab recording#343 #359

Merged
merged 7 commits into from
Jan 23, 2025
5 changes: 5 additions & 0 deletions .changeset/seven-olives-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@webav/av-cliper': patch
---

fix: Initialize MediaStreamClip's width, height and cvs in the first call of onChunk with the firstFrame information #343
5 changes: 5 additions & 0 deletions .changeset/thin-cows-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@webav/av-cliper': patch
---

resolve size mismatch issue in MediaStreamClip during tab recording #343
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
}
}
39 changes: 24 additions & 15 deletions packages/av-cliper/src/clips/media-stream-clip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,22 @@ export class MediaStreamClip implements IClip {
#ms: MediaStream;
constructor(ms: MediaStream) {
this.#ms = ms;
this.audioTrack = ms.getAudioTracks()[0] ?? null;
this.#meta.duration = Infinity;
const videoTrack = ms.getVideoTracks()[0];
if (videoTrack != null) {
const { width, height } = videoTrack.getSettings();
videoTrack.contentHint = 'motion';
this.#meta.width = width ?? 0;
this.#meta.height = height ?? 0;

this.#cvs = new OffscreenCanvas(width ?? 0, height ?? 0);
this.#stopRenderCvs = renderVideoTrackToCvs(
this.#cvs.getContext('2d')!,
videoTrack,
);
this.ready = new Promise((resolve) => {
this.#stopRenderCvs = renderVideoTrackToCvs(videoTrack, (cvs) => {
this.#meta.width = cvs.width;
this.#meta.height = cvs.height;
this.#cvs = cvs;
resolve(this.meta);
});
});
} else {
this.ready = Promise.resolve(this.meta);
}

this.audioTrack = ms.getAudioTracks()[0] ?? null;

this.#meta.duration = Infinity;
this.ready = Promise.resolve(this.meta);
}

async tick(): Promise<{
Expand Down Expand Up @@ -91,15 +89,26 @@ export class MediaStreamClip implements IClip {
}

function renderVideoTrackToCvs(
cvsCtx: OffscreenCanvasRenderingContext2D,
track: MediaStreamVideoTrack,
onOffscreenCanvasReady: (cvs: OffscreenCanvas) => void,
) {
let emitFF = false;
let cvsCtx: OffscreenCanvasRenderingContext2D;
return autoReadStream(
new MediaStreamTrackProcessor({
track,
}).readable,
{
onChunk: async (frame) => {
if (!emitFF) {
const { displayHeight, displayWidth } = frame;
const width = displayWidth ?? 0;
const height = displayHeight ?? 0;
const cvs = new OffscreenCanvas(width, height);
cvsCtx = cvs.getContext('2d')!;
onOffscreenCanvasReady(cvs);
emitFF = true;
}
cvsCtx.drawImage(frame, 0, 0);
frame.close();
},
Expand Down
Loading