feat(decoder): disable VSync

This commit is contained in:
Simon Chan 2023-01-20 14:02:44 +08:00
parent 7d1f271cdb
commit 849cb0c7fc
No known key found for this signature in database
GPG key ID: A8B69F750B9BCEDD

View file

@ -37,9 +37,8 @@ export class WebCodecsDecoder {
private context: CanvasRenderingContext2D; private context: CanvasRenderingContext2D;
private decoder: VideoDecoder; private decoder: VideoDecoder;
// Limit FPS to system refresh rate private currentFrameRendered = false;
private lastFrame: VideoFrame | undefined; private animationFrameId = 0;
private animationFrame = 0;
public constructor() { public constructor() {
this._renderer = document.createElement("canvas"); this._renderer = document.createElement("canvas");
@ -47,16 +46,21 @@ export class WebCodecsDecoder {
this.context = this._renderer.getContext("2d")!; this.context = this._renderer.getContext("2d")!;
this.decoder = new VideoDecoder({ this.decoder = new VideoDecoder({
output: (frame) => { output: (frame) => {
if (this.lastFrame) { if (this.currentFrameRendered) {
this._frameSkipped += 1; this._frameSkipped += 1;
this.lastFrame.close(); } else {
this.currentFrameRendered = true;
this._frameRendered += 1;
} }
this.lastFrame = frame;
if (!this.animationFrame) { // PERF: H.264 renderer may draw multiple frames in one vertical sync interval to minimize latency.
// Start render loop on first frame // When multiple frames are drawn in one vertical sync interval,
this.render(); // only the last one is visible to users.
} // But this ensures users can always see the most up-to-date screen.
// This is also the behavior of official Scrcpy client.
// https://github.com/Genymobile/scrcpy/issues/3679
this.context.drawImage(frame, 0, 0);
frame.close();
}, },
error(e) { error(e) {
void e; void e;
@ -83,17 +87,13 @@ export class WebCodecsDecoder {
} }
}, },
}); });
this.onFramePresented();
} }
private render = () => { private onFramePresented = () => {
if (this.lastFrame) { this.currentFrameRendered = false;
this._frameRendered += 1; this.animationFrameId = requestAnimationFrame(this.onFramePresented);
this.context.drawImage(this.lastFrame, 0, 0);
this.lastFrame.close();
this.lastFrame = undefined;
}
this.animationFrame = requestAnimationFrame(this.render);
}; };
private configure(config: H264Configuration) { private configure(config: H264Configuration) {
@ -114,7 +114,7 @@ export class WebCodecsDecoder {
} }
public dispose() { public dispose() {
cancelAnimationFrame(this.animationFrame); cancelAnimationFrame(this.animationFrameId);
this.decoder.close(); this.decoder.close();
} }
} }