Loading libraries/scrcpy-decoder-webcodecs/src/index.ts +39 −19 Original line number Original line Diff line number Diff line Loading @@ -68,7 +68,7 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { return this.#sizeChanged.event; return this.#sizeChanged.event; } } #context: CanvasRenderingContext2D; #context: ImageBitmapRenderingContext; #decoder: VideoDecoder; #decoder: VideoDecoder; #config: Uint8Array | undefined; #config: Uint8Array | undefined; Loading @@ -80,15 +80,19 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { this.#renderer = document.createElement("canvas"); this.#renderer = document.createElement("canvas"); this.#context = this.#renderer.getContext("2d")!; this.#context = this.#renderer.getContext("bitmaprenderer", { alpha: false, })!; this.#decoder = new VideoDecoder({ this.#decoder = new VideoDecoder({ output: (frame) => { output: (frame) => { createImageBitmap(frame) .then((bitmap) => { if (this.#currentFrameRendered) { if (this.#currentFrameRendered) { this.#frameSkipped += 1; } else { this.#currentFrameRendered = true; this.#frameRendered += 1; this.#frameRendered += 1; } else { this.#frameSkipped += 1; } } this.#currentFrameRendered = false; // PERF: H.264 renderer may draw multiple frames in one vertical sync interval to minimize latency. // PERF: H.264 renderer may draw multiple frames in one vertical sync interval to minimize latency. // When multiple frames are drawn in one vertical sync interval, // When multiple frames are drawn in one vertical sync interval, Loading @@ -96,11 +100,23 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { // But this ensures users can always see the most up-to-date screen. // But this ensures users can always see the most up-to-date screen. // This is also the behavior of official Scrcpy client. // This is also the behavior of official Scrcpy client. // https://github.com/Genymobile/scrcpy/issues/3679 // https://github.com/Genymobile/scrcpy/issues/3679 this.#context.drawImage(frame, 0, 0); this.#context.transferFromImageBitmap(bitmap); frame.close(); frame.close(); }) .catch((e) => { console.warn( "[@yume-chan/scrcpy-decoder-webcodecs]", "createImageBitmap error", e, ); }); }, }, error(e) { error(e) { void e; console.warn( "[@yume-chan/scrcpy-decoder-webcodecs]", "VideoDecoder error", e, ); }, }, }); }); Loading @@ -121,7 +137,7 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { } } #onFramePresented = () => { #onFramePresented = () => { this.#currentFrameRendered = false; this.#currentFrameRendered = true; this.#animationFrameId = requestAnimationFrame(this.#onFramePresented); this.#animationFrameId = requestAnimationFrame(this.#onFramePresented); }; }; Loading Loading @@ -168,6 +184,10 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { this.#renderer.width = croppedWidth; this.#renderer.width = croppedWidth; this.#renderer.height = croppedHeight; this.#renderer.height = croppedHeight; this.#sizeChanged.fire({ width: croppedWidth, height: croppedHeight, }); const codec = [ const codec = [ "hev1", "hev1", Loading Loading
libraries/scrcpy-decoder-webcodecs/src/index.ts +39 −19 Original line number Original line Diff line number Diff line Loading @@ -68,7 +68,7 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { return this.#sizeChanged.event; return this.#sizeChanged.event; } } #context: CanvasRenderingContext2D; #context: ImageBitmapRenderingContext; #decoder: VideoDecoder; #decoder: VideoDecoder; #config: Uint8Array | undefined; #config: Uint8Array | undefined; Loading @@ -80,15 +80,19 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { this.#renderer = document.createElement("canvas"); this.#renderer = document.createElement("canvas"); this.#context = this.#renderer.getContext("2d")!; this.#context = this.#renderer.getContext("bitmaprenderer", { alpha: false, })!; this.#decoder = new VideoDecoder({ this.#decoder = new VideoDecoder({ output: (frame) => { output: (frame) => { createImageBitmap(frame) .then((bitmap) => { if (this.#currentFrameRendered) { if (this.#currentFrameRendered) { this.#frameSkipped += 1; } else { this.#currentFrameRendered = true; this.#frameRendered += 1; this.#frameRendered += 1; } else { this.#frameSkipped += 1; } } this.#currentFrameRendered = false; // PERF: H.264 renderer may draw multiple frames in one vertical sync interval to minimize latency. // PERF: H.264 renderer may draw multiple frames in one vertical sync interval to minimize latency. // When multiple frames are drawn in one vertical sync interval, // When multiple frames are drawn in one vertical sync interval, Loading @@ -96,11 +100,23 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { // But this ensures users can always see the most up-to-date screen. // But this ensures users can always see the most up-to-date screen. // This is also the behavior of official Scrcpy client. // This is also the behavior of official Scrcpy client. // https://github.com/Genymobile/scrcpy/issues/3679 // https://github.com/Genymobile/scrcpy/issues/3679 this.#context.drawImage(frame, 0, 0); this.#context.transferFromImageBitmap(bitmap); frame.close(); frame.close(); }) .catch((e) => { console.warn( "[@yume-chan/scrcpy-decoder-webcodecs]", "createImageBitmap error", e, ); }); }, }, error(e) { error(e) { void e; console.warn( "[@yume-chan/scrcpy-decoder-webcodecs]", "VideoDecoder error", e, ); }, }, }); }); Loading @@ -121,7 +137,7 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { } } #onFramePresented = () => { #onFramePresented = () => { this.#currentFrameRendered = false; this.#currentFrameRendered = true; this.#animationFrameId = requestAnimationFrame(this.#onFramePresented); this.#animationFrameId = requestAnimationFrame(this.#onFramePresented); }; }; Loading Loading @@ -168,6 +184,10 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder { this.#renderer.width = croppedWidth; this.#renderer.width = croppedWidth; this.#renderer.height = croppedHeight; this.#renderer.height = croppedHeight; this.#sizeChanged.fire({ width: croppedWidth, height: croppedHeight, }); const codec = [ const codec = [ "hev1", "hev1", Loading