@yume-chan/scrcpy-decoder-webcodecs 0.0.0-20240714132542 → 0.0.0-next-20241129144018

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +28 -15
  2. package/esm/video/codec/h265.d.ts.map +1 -1
  3. package/esm/video/codec/h265.js +3 -0
  4. package/esm/video/codec/h265.js.map +1 -1
  5. package/esm/video/decoder.d.ts +8 -10
  6. package/esm/video/decoder.d.ts.map +1 -1
  7. package/esm/video/decoder.js +164 -68
  8. package/esm/video/decoder.js.map +1 -1
  9. package/esm/video/render/bitmap.d.ts +4 -4
  10. package/esm/video/render/bitmap.d.ts.map +1 -1
  11. package/esm/video/render/bitmap.js +9 -11
  12. package/esm/video/render/bitmap.js.map +1 -1
  13. package/esm/video/render/canvas.d.ts +9 -0
  14. package/esm/video/render/canvas.d.ts.map +1 -0
  15. package/esm/video/render/canvas.js +22 -0
  16. package/esm/video/render/canvas.js.map +1 -0
  17. package/esm/video/render/index.d.ts +2 -0
  18. package/esm/video/render/index.d.ts.map +1 -1
  19. package/esm/video/render/index.js +3 -0
  20. package/esm/video/render/index.js.map +1 -1
  21. package/esm/video/render/insertable-stream.d.ts +10 -0
  22. package/esm/video/render/insertable-stream.d.ts.map +1 -0
  23. package/esm/video/render/insertable-stream.js +45 -0
  24. package/esm/video/render/insertable-stream.js.map +1 -0
  25. package/esm/video/render/type.d.ts +4 -2
  26. package/esm/video/render/type.d.ts.map +1 -1
  27. package/esm/video/render/webgl.d.ts +5 -4
  28. package/esm/video/render/webgl.d.ts.map +1 -1
  29. package/esm/video/render/webgl.js +26 -15
  30. package/esm/video/render/webgl.js.map +1 -1
  31. package/package.json +10 -14
  32. package/src/video/codec/h265.ts +3 -0
  33. package/src/video/decoder.ts +187 -79
  34. package/src/video/render/bitmap.ts +11 -17
  35. package/src/video/render/canvas.ts +29 -0
  36. package/src/video/render/index.ts +4 -0
  37. package/src/video/render/insertable-stream.ts +62 -0
  38. package/src/video/render/type.ts +6 -2
  39. package/src/video/render/webgl.ts +48 -22
  40. package/tsconfig.build.json +4 -1
  41. package/tsconfig.build.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,16 +1,29 @@
1
1
  # Change Log - @yume-chan/scrcpy-decoder-webcodecs
2
2
 
3
- ## 0.0.0-20240714132542
3
+ ## 0.0.0-next-20241129144018
4
+
5
+ ### Major Changes
6
+
7
+ - 53688d3: Use PNPM workspace and Changesets to manage the monorepo.
8
+
9
+ Because Changesets doesn't support alpha versions (`0.x.x`), this version is `1.0.0`. Future versions will follow SemVer rules, for example, breaking API changes will introduce a new major version.
4
10
 
5
11
  ### Patch Changes
6
12
 
7
- - Switch to PNPM workspace and changesets
8
- - Updated dependencies
9
- - @yume-chan/scrcpy-decoder-tinyh264@0.0.0-20240714132542
10
- - @yume-chan/no-data-view@0.0.0-20240714132542
11
- - @yume-chan/stream-extra@0.0.0-20240714132542
12
- - @yume-chan/scrcpy@0.0.0-20240714132542
13
- - @yume-chan/event@0.0.0-20240714132542
13
+ - db8466f: Fix H.265 rendering in Microsoft Edge
14
+ - 8e4c1ef: Add a renderer based on Insertable Stream API
15
+ - db8466f: Add a `snapshot` method to convert the last rendered frame into PNG
16
+ - Updated dependencies [53688d3]
17
+ - Updated dependencies [db8466f]
18
+ - Updated dependencies [db8466f]
19
+ - Updated dependencies [ea5002b]
20
+ - Updated dependencies [ea5002b]
21
+ - Updated dependencies [db8466f]
22
+ - @yume-chan/scrcpy-decoder-tinyh264@0.0.0-next-20241129144018
23
+ - @yume-chan/no-data-view@0.0.0-next-20241129144018
24
+ - @yume-chan/stream-extra@0.0.0-next-20241129144018
25
+ - @yume-chan/scrcpy@0.0.0-next-20241129144018
26
+ - @yume-chan/event@0.0.0-next-20241129144018
14
27
 
15
28
  This log was last generated on Tue, 18 Jun 2024 02:49:43 GMT and should not be manually modified.
16
29
 
@@ -20,8 +33,8 @@ Tue, 18 Jun 2024 02:49:43 GMT
20
33
 
21
34
  ### Updates
22
35
 
23
- - Support decoding AV1
24
- - Add `enableCapture` option to `WebCodecsVideoDecoder` which allows `renderer.readPixels` and `renderer.toDataURL` to work. The performance will be slightly affected when enabled.
36
+ - Support decoding AV1
37
+ - Add `enableCapture` option to `WebCodecsVideoDecoder` which allows `renderer.readPixels` and `renderer.toDataURL` to work. The performance will be slightly affected when enabled.
25
38
 
26
39
  ## 0.0.23
27
40
 
@@ -29,8 +42,8 @@ Thu, 21 Mar 2024 03:15:10 GMT
29
42
 
30
43
  ### Updates
31
44
 
32
- - Add `sizeChanged` event
33
- - Add WebGL and Bitmap based video renderers, which are 1.5 to 3 times faster on Android devices
45
+ - Add `sizeChanged` event
46
+ - Add WebGL and Bitmap based video renderers, which are 1.5 to 3 times faster on Android devices
34
47
 
35
48
  ## 0.0.22
36
49
 
@@ -50,7 +63,7 @@ Mon, 05 Jun 2023 02:51:41 GMT
50
63
 
51
64
  ### Updates
52
65
 
53
- - Add support for decoding H.265 on supported browsers (Chrome works, Microsoft Edge with HEVC Video Extension from Microsoft Store doesn't decode H.265 correctly).
66
+ - Add support for decoding H.265 on supported browsers (Chrome works, Microsoft Edge with HEVC Video Extension from Microsoft Store doesn't decode H.265 correctly).
54
67
 
55
68
  ## 0.0.19
56
69
 
@@ -64,7 +77,7 @@ Wed, 25 Jan 2023 21:33:49 GMT
64
77
 
65
78
  ### Updates
66
79
 
67
- - Change to not use vertical sync to minimize latency
80
+ - Change to not use vertical sync to minimize latency
68
81
 
69
82
  ## 0.0.17
70
83
 
@@ -72,4 +85,4 @@ Tue, 18 Oct 2022 09:32:30 GMT
72
85
 
73
86
  ### Updates
74
87
 
75
- - Separated from `@yume-chan/scrcpy` for simpler dependency management.
88
+ - Separated from `@yume-chan/scrcpy` for simpler dependency management.
@@ -1 +1 @@
1
- {"version":3,"file":"h265.d.ts","sourceRoot":"","sources":["../../../src/video/codec/h265.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,qBAAa,WAAY,SAAQ,WAAW;;gBAKpC,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI;IAO9C,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;CA2B7C"}
1
+ {"version":3,"file":"h265.d.ts","sourceRoot":"","sources":["../../../src/video/codec/h265.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,qBAAa,WAAY,SAAQ,WAAW;;gBAKpC,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI;IAO9C,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;CA8B7C"}
@@ -23,6 +23,9 @@ export class H265Decoder extends H26xDecoder {
23
23
  ].join(".");
24
24
  this.#decoder.configure({
25
25
  codec,
26
+ // Microsoft Edge requires explicit size to work
27
+ codedWidth: croppedWidth,
28
+ codedHeight: croppedHeight,
26
29
  optimizeForLatency: true,
27
30
  });
28
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"h265.js","sourceRoot":"","sources":["../../../src/video/codec/h265.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,OAAO,WAAY,SAAQ,WAAW;IACxC,QAAQ,CAAe;IACvB,WAAW,CAA0C;IAErD,YACI,OAAqB,EACrB,UAAmD;QAEnD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAClC,CAAC;IAEQ,SAAS,CAAC,IAAgB;QAC/B,MAAM,EACF,mBAAmB,EACnB,mBAAmB,EACnB,8BAA8B,EAC9B,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,aAAa,GAChB,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAEjC,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;QAE9C,MAAM,KAAK,GAAG;YACV,MAAM;YACN,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,mBAAmB,CAAE;gBACrC,mBAAmB,CAAC,QAAQ,EAAE;YAClC,SAAS,CAAC,qBAAqB,CAAC,8BAA8B,EAAE,CAAC,CAAC,CAAC;YACnE,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,QAAQ,EAAE;YAC5D,GAAG,KAAK,CAAC,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC;SACjD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YACpB,KAAK;YACL,kBAAkB,EAAE,IAAI;SAC3B,CAAC,CAAC;IACP,CAAC;CACJ"}
1
+ {"version":3,"file":"h265.js","sourceRoot":"","sources":["../../../src/video/codec/h265.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,OAAO,WAAY,SAAQ,WAAW;IACxC,QAAQ,CAAe;IACvB,WAAW,CAA0C;IAErD,YACI,OAAqB,EACrB,UAAmD;QAEnD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAClC,CAAC;IAEQ,SAAS,CAAC,IAAgB;QAC/B,MAAM,EACF,mBAAmB,EACnB,mBAAmB,EACnB,8BAA8B,EAC9B,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,aAAa,GAChB,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAEjC,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;QAE9C,MAAM,KAAK,GAAG;YACV,MAAM;YACN,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,mBAAmB,CAAE;gBACrC,mBAAmB,CAAC,QAAQ,EAAE;YAClC,SAAS,CAAC,qBAAqB,CAAC,8BAA8B,EAAE,CAAC,CAAC,CAAC;YACnE,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,QAAQ,EAAE;YAC5D,GAAG,KAAK,CAAC,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC;SACjD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YACpB,KAAK;YACL,gDAAgD;YAChD,UAAU,EAAE,YAAY;YACxB,WAAW,EAAE,aAAa;YAC1B,kBAAkB,EAAE,IAAI;SAC3B,CAAC,CAAC;IACP,CAAC;CACJ"}
@@ -1,25 +1,22 @@
1
1
  import type { ScrcpyMediaStreamPacket } from "@yume-chan/scrcpy";
2
2
  import { ScrcpyVideoCodecId } from "@yume-chan/scrcpy";
3
- import type { ScrcpyVideoDecoder, ScrcpyVideoDecoderCapability, TinyH264DecoderInit } from "@yume-chan/scrcpy-decoder-tinyh264";
3
+ import type { ScrcpyVideoDecoder, ScrcpyVideoDecoderCapability } from "@yume-chan/scrcpy-decoder-tinyh264";
4
4
  import { WritableStream } from "@yume-chan/stream-extra";
5
- export interface WebCodecsVideoDecoderInit extends TinyH264DecoderInit {
5
+ import type { WebCodecsVideoDecoderRenderer } from "./render/index.js";
6
+ export interface WebCodecsVideoDecoderInit {
6
7
  /**
7
8
  * The video codec to decode
8
9
  */
9
10
  codec: ScrcpyVideoCodecId;
10
- /**
11
- * Whether to allow capturing the canvas content using APIs like `readPixels` and `toDataURL`.
12
- * Enable this option may reduce performance.
13
- */
14
- enableCapture?: boolean | undefined;
11
+ renderer: WebCodecsVideoDecoderRenderer;
15
12
  }
16
13
  export declare class WebCodecsVideoDecoder implements ScrcpyVideoDecoder {
17
14
  #private;
18
- static isSupported(): boolean;
15
+ static get isSupported(): boolean;
19
16
  static readonly capabilities: Record<string, ScrcpyVideoDecoderCapability>;
20
17
  get codec(): ScrcpyVideoCodecId;
21
18
  get writable(): WritableStream<ScrcpyMediaStreamPacket>;
22
- get renderer(): HTMLCanvasElement | OffscreenCanvas;
19
+ get renderer(): WebCodecsVideoDecoderRenderer;
23
20
  get framesRendered(): number;
24
21
  get framesSkipped(): number;
25
22
  get sizeChanged(): import("@yume-chan/event").AddEventListener<{
@@ -29,7 +26,8 @@ export declare class WebCodecsVideoDecoder implements ScrcpyVideoDecoder {
29
26
  /**
30
27
  * Create a new WebCodecs video decoder.
31
28
  */
32
- constructor({ codec, canvas, enableCapture }: WebCodecsVideoDecoderInit);
29
+ constructor({ codec, renderer }: WebCodecsVideoDecoderInit);
30
+ snapshot(): Promise<Blob | undefined>;
33
31
  dispose(): void;
34
32
  }
35
33
  //# sourceMappingURL=decoder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/video/decoder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EACR,kBAAkB,EAClB,4BAA4B,EAC5B,mBAAmB,EACtB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAOzD,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IAClE;;OAEG;IACH,KAAK,EAAE,kBAAkB,CAAC;IAE1B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACvC;AAED,qBAAa,qBAAsB,YAAW,kBAAkB;;IAC5D,MAAM,CAAC,WAAW;IAIlB,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAIpE;IAGN,IAAI,KAAK,uBAER;IAKD,IAAI,QAAQ,4CAEX;IAGD,IAAI,QAAQ,wCAEX;IAGD,IAAI,cAAc,WAEjB;IAGD,IAAI,aAAa,WAEhB;IAGD,IAAI,WAAW;eAD0B,MAAM;gBAAU,MAAM;gBAG9D;IAQD;;OAEG;gBACS,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,yBAAyB;IA4GvE,OAAO;CAMV"}
1
+ {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/video/decoder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EACR,kBAAkB,EAClB,4BAA4B,EAC/B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAIzD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAsFvE,MAAM,WAAW,yBAAyB;IACtC;;OAEG;IACH,KAAK,EAAE,kBAAkB,CAAC;IAE1B,QAAQ,EAAE,6BAA6B,CAAC;CAC3C;AAED,qBAAa,qBAAsB,YAAW,kBAAkB;;IAC5D,MAAM,KAAK,WAAW,YAErB;IAED,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAKpE;IAGN,IAAI,KAAK,uBAER;IAKD,IAAI,QAAQ,4CAEX;IAMD,IAAI,QAAQ,kCAEX;IAID,IAAI,cAAc,WAEjB;IAGD,IAAI,aAAa,WAEhB;IAGD,IAAI,WAAW;eAD0B,MAAM;gBAAU,MAAM;gBAG9D;IAUD;;OAEG;gBACS,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,yBAAyB;IAsHpD,QAAQ;IAYd,OAAO;CAQV"}
@@ -1,16 +1,87 @@
1
1
  import { EventEmitter } from "@yume-chan/event";
2
2
  import { ScrcpyVideoCodecId } from "@yume-chan/scrcpy";
3
- import { createCanvas } from "@yume-chan/scrcpy-decoder-tinyh264";
4
3
  import { WritableStream } from "@yume-chan/stream-extra";
5
4
  import { Av1Codec, H264Decoder, H265Decoder } from "./codec/index.js";
6
- import { BitmapFrameSink, WebGLFrameSink } from "./render/index.js";
5
+ class Pool {
6
+ #controller;
7
+ #readable = new ReadableStream({
8
+ start: (controller) => {
9
+ this.#controller = controller;
10
+ },
11
+ pull: (controller) => {
12
+ controller.enqueue(this.#initializer());
13
+ },
14
+ }, { highWaterMark: 0 });
15
+ #reader = this.#readable.getReader();
16
+ #initializer;
17
+ #size = 0;
18
+ #capacity;
19
+ constructor(initializer, capacity) {
20
+ this.#initializer = initializer;
21
+ this.#capacity = capacity;
22
+ }
23
+ async borrow() {
24
+ const result = await this.#reader.read();
25
+ return result.value;
26
+ }
27
+ return(value) {
28
+ if (this.#size < this.#capacity) {
29
+ this.#controller.enqueue(value);
30
+ this.#size += 1;
31
+ }
32
+ }
33
+ }
34
+ class VideoFrameCapturer {
35
+ #canvas;
36
+ #context;
37
+ constructor() {
38
+ if (typeof OffscreenCanvas !== "undefined") {
39
+ this.#canvas = new OffscreenCanvas(1, 1);
40
+ }
41
+ else {
42
+ this.#canvas = document.createElement("canvas");
43
+ this.#canvas.width = 1;
44
+ this.#canvas.height = 1;
45
+ }
46
+ this.#context = this.#canvas.getContext("bitmaprenderer", {
47
+ alpha: false,
48
+ });
49
+ }
50
+ async capture(frame) {
51
+ this.#canvas.width = frame.displayWidth;
52
+ this.#canvas.height = frame.displayHeight;
53
+ const bitmap = await createImageBitmap(frame);
54
+ this.#context.transferFromImageBitmap(bitmap);
55
+ if (this.#canvas instanceof OffscreenCanvas) {
56
+ return await this.#canvas.convertToBlob({
57
+ type: "image/png",
58
+ });
59
+ }
60
+ else {
61
+ return new Promise((resolve, reject) => {
62
+ this.#canvas.toBlob((blob) => {
63
+ if (!blob) {
64
+ reject(new Error("Failed to convert canvas to blob"));
65
+ }
66
+ else {
67
+ resolve(blob);
68
+ }
69
+ }, "image/png");
70
+ });
71
+ }
72
+ }
73
+ }
74
+ const VideoFrameCapturerPool =
75
+ /* #__PURE__ */
76
+ new Pool(() => new VideoFrameCapturer(), 4);
7
77
  export class WebCodecsVideoDecoder {
8
- static isSupported() {
78
+ static get isSupported() {
9
79
  return typeof globalThis.VideoDecoder !== "undefined";
10
80
  }
11
81
  static capabilities = {
12
82
  h264: {},
13
83
  h265: {},
84
+ av1: {},
14
85
  };
15
86
  #codec;
16
87
  get codec() {
@@ -21,74 +92,53 @@ export class WebCodecsVideoDecoder {
21
92
  get writable() {
22
93
  return this.#writable;
23
94
  }
95
+ #error;
96
+ #controller;
24
97
  #renderer;
25
98
  get renderer() {
26
99
  return this.#renderer;
27
100
  }
28
- #frameRendered = 0;
101
+ #framesDraw = 0;
102
+ #framesPresented = 0;
29
103
  get framesRendered() {
30
- return this.#frameRendered;
104
+ return this.#framesPresented;
31
105
  }
32
- #frameSkipped = 0;
106
+ #framesSkipped = 0;
33
107
  get framesSkipped() {
34
- return this.#frameSkipped;
108
+ return this.#framesSkipped;
35
109
  }
36
110
  #sizeChanged = new EventEmitter();
37
111
  get sizeChanged() {
38
112
  return this.#sizeChanged.event;
39
113
  }
40
114
  #decoder;
41
- #frameSink;
42
- #currentFrameRendered = false;
115
+ #drawing = false;
116
+ #nextFrame;
117
+ #captureFrame;
43
118
  #animationFrameId = 0;
44
119
  /**
45
120
  * Create a new WebCodecs video decoder.
46
121
  */
47
- constructor({ codec, canvas, enableCapture }) {
122
+ constructor({ codec, renderer }) {
48
123
  this.#codec = codec;
49
- if (canvas) {
50
- this.#renderer = canvas;
51
- }
52
- else {
53
- this.#renderer = createCanvas();
54
- }
55
- try {
56
- this.#frameSink = new WebGLFrameSink(this.#renderer, !!enableCapture);
57
- }
58
- catch {
59
- this.#frameSink = new BitmapFrameSink(this.#renderer);
60
- }
124
+ this.#renderer = renderer;
61
125
  this.#decoder = new VideoDecoder({
62
126
  output: (frame) => {
63
- if (this.#currentFrameRendered) {
64
- this.#frameRendered += 1;
65
- }
66
- else {
67
- this.#frameSkipped += 1;
68
- }
69
- this.#currentFrameRendered = false;
70
- // PERF: Draw every frame to minimize latency at cost of performance.
71
- // When multiple frames are drawn in one vertical sync interval,
72
- // only the last one is visible to users.
73
- // But this ensures users can always see the most up-to-date screen.
74
- // This is also the behavior of official Scrcpy client.
75
- // https://github.com/Genymobile/scrcpy/issues/3679
76
- this.#updateSize(frame.displayWidth, frame.displayHeight);
77
- this.#frameSink.draw(frame);
78
- },
79
- error(e) {
80
- if (controller) {
81
- try {
82
- controller.error(e);
127
+ this.#captureFrame?.close();
128
+ // PERF: `VideoFrame#clone` is cheap
129
+ this.#captureFrame = frame.clone();
130
+ if (this.#drawing) {
131
+ if (this.#nextFrame) {
132
+ this.#nextFrame.close();
133
+ this.#framesSkipped += 1;
83
134
  }
84
- catch {
85
- // ignore
86
- // `controller` may already in error state
87
- }
88
- }
89
- else {
90
- error = e;
135
+ this.#nextFrame = frame;
136
+ return;
91
137
  }
138
+ void this.#draw(frame);
139
+ },
140
+ error: (error) => {
141
+ this.#setError(error);
92
142
  },
93
143
  });
94
144
  switch (this.#codec) {
@@ -101,44 +151,90 @@ export class WebCodecsVideoDecoder {
101
151
  case ScrcpyVideoCodecId.AV1:
102
152
  this.#codecDecoder = new Av1Codec(this.#decoder, this.#updateSize);
103
153
  break;
154
+ default:
155
+ throw new Error(`Unsupported codec: ${this.#codec}`);
104
156
  }
105
- let error;
106
- let controller;
107
157
  this.#writable = new WritableStream({
108
- start: (_controller) => {
109
- if (error) {
110
- _controller.error(error);
158
+ start: (controller) => {
159
+ if (this.#error) {
160
+ controller.error(this.#error);
111
161
  }
112
162
  else {
113
- controller = _controller;
163
+ this.#controller = controller;
114
164
  }
115
165
  },
116
166
  write: (packet) => {
117
167
  this.#codecDecoder.decode(packet);
118
168
  },
119
169
  });
120
- this.#onFramePresented();
170
+ this.#onVerticalSync();
121
171
  }
122
- #updateSize = (width, height) => {
123
- if (width !== this.#renderer.width ||
124
- height !== this.#renderer.height) {
125
- this.#renderer.width = width;
126
- this.#renderer.height = height;
127
- this.#sizeChanged.fire({
128
- width: width,
129
- height: height,
130
- });
172
+ #setError(error) {
173
+ if (this.#controller) {
174
+ try {
175
+ this.#controller.error(error);
176
+ }
177
+ catch {
178
+ // ignore
179
+ }
131
180
  }
181
+ else {
182
+ this.#error = error;
183
+ }
184
+ }
185
+ async #draw(frame) {
186
+ try {
187
+ this.#drawing = true;
188
+ // PERF: Draw every frame to minimize latency at cost of performance.
189
+ // When multiple frames are drawn in one vertical sync interval,
190
+ // only the last one is visible to users.
191
+ // But this ensures users can always see the most up-to-date screen.
192
+ // This is also the behavior of official Scrcpy client.
193
+ // https://github.com/Genymobile/scrcpy/issues/3679
194
+ this.#updateSize(frame.displayWidth, frame.displayHeight);
195
+ await this.#renderer.draw(frame);
196
+ this.#framesDraw += 1;
197
+ frame.close();
198
+ if (this.#nextFrame) {
199
+ const frame = this.#nextFrame;
200
+ this.#nextFrame = undefined;
201
+ await this.#draw(frame);
202
+ }
203
+ this.#drawing = false;
204
+ }
205
+ catch (error) {
206
+ this.#setError(error);
207
+ }
208
+ }
209
+ #updateSize = (width, height) => {
210
+ this.#renderer.setSize(width, height);
211
+ this.#sizeChanged.fire({ width, height });
132
212
  };
133
- #onFramePresented = () => {
134
- this.#currentFrameRendered = true;
135
- this.#animationFrameId = requestAnimationFrame(this.#onFramePresented);
213
+ #onVerticalSync = () => {
214
+ if (this.#framesDraw > 0) {
215
+ this.#framesPresented += 1;
216
+ this.#framesSkipped += this.#framesDraw - 1;
217
+ this.#framesDraw = 0;
218
+ }
219
+ this.#animationFrameId = requestAnimationFrame(this.#onVerticalSync);
136
220
  };
221
+ async snapshot() {
222
+ const frame = this.#captureFrame;
223
+ if (!frame) {
224
+ return undefined;
225
+ }
226
+ const capturer = await VideoFrameCapturerPool.borrow();
227
+ const result = await capturer.capture(frame);
228
+ VideoFrameCapturerPool.return(capturer);
229
+ return result;
230
+ }
137
231
  dispose() {
138
232
  cancelAnimationFrame(this.#animationFrameId);
139
233
  if (this.#decoder.state !== "closed") {
140
234
  this.#decoder.close();
141
235
  }
236
+ this.#nextFrame?.close();
237
+ this.#captureFrame?.close();
142
238
  }
143
239
  }
144
240
  //# sourceMappingURL=decoder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/video/decoder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/video/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAMvD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAItE,MAAM,IAAI;IACN,WAAW,CAAsC;IACjD,SAAS,GAAG,IAAI,cAAc,CAC1B;QACI,KAAK,EAAE,CAAC,UAAU,EAAE,EAAE;YAClB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAClC,CAAC;QACD,IAAI,EAAE,CAAC,UAAU,EAAE,EAAE;YACjB,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAC5C,CAAC;KACJ,EACD,EAAE,aAAa,EAAE,CAAC,EAAE,CACvB,CAAC;IACF,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;IAErC,YAAY,CAAU;IAEtB,KAAK,GAAG,CAAC,CAAC;IACV,SAAS,CAAS;IAElB,YAAY,WAAoB,EAAE,QAAgB;QAC9C,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,MAAM;QACR,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACzC,OAAO,MAAM,CAAC,KAAM,CAAC;IACzB,CAAC;IAED,MAAM,CAAC,KAAQ;QACX,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YAC9B,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QACpB,CAAC;IACL,CAAC;CACJ;AAED,MAAM,kBAAkB;IACpB,OAAO,CAAsC;IAC7C,QAAQ,CAA8B;IAEtC;QACI,IAAI,OAAO,eAAe,KAAK,WAAW,EAAE,CAAC;YACzC,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAChD,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5B,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,EAAE;YACtD,KAAK,EAAE,KAAK;SACf,CAAE,CAAC;IACR,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAiB;QAC3B,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC;QAE1C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAE9C,IAAI,IAAI,CAAC,OAAO,YAAY,eAAe,EAAE,CAAC;YAC1C,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;gBACpC,IAAI,EAAE,WAAW;aACpB,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACJ,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAClC,IAAI,CAAC,OAA6B,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;oBAChD,IAAI,CAAC,IAAI,EAAE,CAAC;wBACR,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;oBAC1D,CAAC;yBAAM,CAAC;wBACJ,OAAO,CAAC,IAAI,CAAC,CAAC;oBAClB,CAAC;gBACL,CAAC,EAAE,WAAW,CAAC,CAAC;YACpB,CAAC,CAAC,CAAC;QACP,CAAC;IACL,CAAC;CACJ;AAED,MAAM,sBAAsB;AACxB,eAAe;AACf,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,kBAAkB,EAAE,EAAE,CAAC,CAAC,CAAC;AAWhD,MAAM,OAAO,qBAAqB;IAC9B,MAAM,KAAK,WAAW;QAClB,OAAO,OAAO,UAAU,CAAC,YAAY,KAAK,WAAW,CAAC;IAC1D,CAAC;IAED,MAAM,CAAU,YAAY,GACxB;QACI,IAAI,EAAE,EAAE;QACR,IAAI,EAAE,EAAE;QACR,GAAG,EAAE,EAAE;KACV,CAAC;IAEN,MAAM,CAAqB;IAC3B,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,aAAa,CAAe;IAE5B,SAAS,CAA0C;IACnD,IAAI,QAAQ;QACR,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;IAED,MAAM,CAAoB;IAC1B,WAAW,CAAmC;IAE9C,SAAS,CAAgC;IACzC,IAAI,QAAQ;QACR,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;IAED,WAAW,GAAG,CAAC,CAAC;IAChB,gBAAgB,GAAG,CAAC,CAAC;IACrB,IAAI,cAAc;QACd,OAAO,IAAI,CAAC,gBAAgB,CAAC;IACjC,CAAC;IAED,cAAc,GAAG,CAAC,CAAC;IACnB,IAAI,aAAa;QACb,OAAO,IAAI,CAAC,cAAc,CAAC;IAC/B,CAAC;IAED,YAAY,GAAG,IAAI,YAAY,EAAqC,CAAC;IACrE,IAAI,WAAW;QACX,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IACnC,CAAC;IAED,QAAQ,CAAe;IAEvB,QAAQ,GAAG,KAAK,CAAC;IACjB,UAAU,CAAyB;IACnC,aAAa,CAAyB;IAEtC,iBAAiB,GAAG,CAAC,CAAC;IAEtB;;OAEG;IACH,YAAY,EAAE,KAAK,EAAE,QAAQ,EAA6B;QACtD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QAEpB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAE1B,IAAI,CAAC,QAAQ,GAAG,IAAI,YAAY,CAAC;YAC7B,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBACd,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC;gBAC5B,oCAAoC;gBACpC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;gBAEnC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAChB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;wBAClB,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;wBACxB,IAAI,CAAC,cAAc,IAAI,CAAC,CAAC;oBAC7B,CAAC;oBACD,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;oBACxB,OAAO;gBACX,CAAC;gBAED,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC;YACD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;gBACb,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC;SACJ,CAAC,CAAC;QAEH,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YAClB,KAAK,kBAAkB,CAAC,IAAI;gBACxB,IAAI,CAAC,aAAa,GAAG,IAAI,WAAW,CAChC,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,WAAW,CACnB,CAAC;gBACF,MAAM;YACV,KAAK,kBAAkB,CAAC,IAAI;gBACxB,IAAI,CAAC,aAAa,GAAG,IAAI,WAAW,CAChC,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,WAAW,CACnB,CAAC;gBACF,MAAM;YACV,KAAK,kBAAkB,CAAC,GAAG;gBACvB,IAAI,CAAC,aAAa,GAAG,IAAI,QAAQ,CAC7B,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,WAAW,CACnB,CAAC;gBACF,MAAM;YACV;gBACI,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,CAAC,MAAgB,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,cAAc,CAA0B;YACzD,KAAK,EAAE,CAAC,UAAU,EAAE,EAAE;gBAClB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBACd,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAClC,CAAC;qBAAM,CAAC;oBACJ,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;gBAClC,CAAC;YACL,CAAC;YACD,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE;gBACd,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtC,CAAC;SACJ,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,EAAE,CAAC;IAC3B,CAAC;IAED,SAAS,CAAC,KAAY;QAClB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,IAAI,CAAC;gBACD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;YAAC,MAAM,CAAC;gBACL,SAAS;YACb,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACxB,CAAC;IACL,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAiB;QACzB,IAAI,CAAC;YACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,qEAAqE;YACrE,gEAAgE;YAChE,yCAAyC;YACzC,oEAAoE;YACpE,uDAAuD;YACvD,mDAAmD;YACnD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;YAC1D,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;YACtB,KAAK,CAAC,KAAK,EAAE,CAAC;YAEd,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBAClB,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;gBAC9B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;gBAC5B,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;YAED,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,SAAS,CAAC,KAAc,CAAC,CAAC;QACnC,CAAC;IACL,CAAC;IAED,WAAW,GAAG,CAAC,KAAa,EAAE,MAAc,EAAE,EAAE;QAC5C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC;IAEF,eAAe,GAAG,GAAG,EAAE;QACnB,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC;YAC3B,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;YAC5C,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,iBAAiB,GAAG,qBAAqB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACzE,CAAC,CAAC;IAEF,KAAK,CAAC,QAAQ;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO,SAAS,CAAC;QACrB,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,MAAM,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7C,sBAAsB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxC,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,OAAO;QACH,oBAAoB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC7C,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC;IAChC,CAAC"}
@@ -1,7 +1,7 @@
1
- import type { FrameSink } from "./type.js";
2
- export declare class BitmapFrameSink implements FrameSink {
1
+ import { CanvasWebCodecsVideoDecoderRenderer } from "./canvas.js";
2
+ export declare class BitmapWebCodecsDecoderRenderer extends CanvasWebCodecsVideoDecoderRenderer {
3
3
  #private;
4
- constructor(canvas: HTMLCanvasElement | OffscreenCanvas);
5
- draw(frame: VideoFrame): void;
4
+ constructor(canvas?: HTMLCanvasElement | OffscreenCanvas);
5
+ draw(frame: VideoFrame): Promise<void>;
6
6
  }
7
7
  //# sourceMappingURL=bitmap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bitmap.d.ts","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,qBAAa,eAAgB,YAAW,SAAS;;gBAGjC,MAAM,EAAE,iBAAiB,GAAG,eAAe;IAIvD,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAchC"}
1
+ {"version":3,"file":"bitmap.d.ts","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,aAAa,CAAC;AAElE,qBAAa,8BAA+B,SAAQ,mCAAmC;;gBAGvE,MAAM,CAAC,EAAE,iBAAiB,GAAG,eAAe;IAQlD,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAI/C"}
@@ -1,17 +1,15 @@
1
- export class BitmapFrameSink {
1
+ import { CanvasWebCodecsVideoDecoderRenderer } from "./canvas.js";
2
+ export class BitmapWebCodecsDecoderRenderer extends CanvasWebCodecsVideoDecoderRenderer {
2
3
  #context;
3
4
  constructor(canvas) {
4
- this.#context = canvas.getContext("bitmaprenderer", { alpha: false });
5
- }
6
- draw(frame) {
7
- createImageBitmap(frame)
8
- .then((bitmap) => {
9
- this.#context.transferFromImageBitmap(bitmap);
10
- frame.close();
11
- })
12
- .catch((e) => {
13
- console.warn("[@yume-chan/scrcpy-decoder-webcodecs]", "VideoDecoder error", e);
5
+ super(canvas);
6
+ this.#context = this.canvas.getContext("bitmaprenderer", {
7
+ alpha: false,
14
8
  });
15
9
  }
10
+ async draw(frame) {
11
+ const bitmap = await createImageBitmap(frame);
12
+ this.#context.transferFromImageBitmap(bitmap);
13
+ }
16
14
  }
17
15
  //# sourceMappingURL=bitmap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bitmap.js","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,eAAe;IACxB,QAAQ,CAA8B;IAEtC,YAAY,MAA2C;QACnD,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAE,CAAC;IAC3E,CAAC;IAED,IAAI,CAAC,KAAiB;QAClB,iBAAiB,CAAC,KAAK,CAAC;aACnB,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACb,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;YAC9C,KAAK,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,OAAO,CAAC,IAAI,CACR,uCAAuC,EACvC,oBAAoB,EACpB,CAAC,CACJ,CAAC;QACN,CAAC,CAAC,CAAC;IACX,CAAC;CACJ"}
1
+ {"version":3,"file":"bitmap.js","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,OAAO,8BAA+B,SAAQ,mCAAmC;IACnF,QAAQ,CAA8B;IAEtC,YAAY,MAA4C;QACpD,KAAK,CAAC,MAAM,CAAC,CAAC;QAEd,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,EAAE;YACrD,KAAK,EAAE,KAAK;SACf,CAAE,CAAC;IACR,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAiB;QACxB,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;CACJ"}
@@ -0,0 +1,9 @@
1
+ import type { WebCodecsVideoDecoderRenderer } from "./type.js";
2
+ export declare abstract class CanvasWebCodecsVideoDecoderRenderer implements WebCodecsVideoDecoderRenderer {
3
+ #private;
4
+ get canvas(): HTMLCanvasElement | OffscreenCanvas;
5
+ constructor(canvas?: HTMLCanvasElement | OffscreenCanvas);
6
+ setSize(width: number, height: number): void;
7
+ abstract draw(frame: VideoFrame): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=canvas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../../../src/video/render/canvas.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAE/D,8BAAsB,mCAClB,YAAW,6BAA6B;;IAGxC,IAAI,MAAM,wCAET;gBAEW,MAAM,CAAC,EAAE,iBAAiB,GAAG,eAAe;IAQxD,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAO5C,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAClD"}
@@ -0,0 +1,22 @@
1
+ import { createCanvas } from "@yume-chan/scrcpy-decoder-tinyh264";
2
+ export class CanvasWebCodecsVideoDecoderRenderer {
3
+ #canvas;
4
+ get canvas() {
5
+ return this.#canvas;
6
+ }
7
+ constructor(canvas) {
8
+ if (canvas) {
9
+ this.#canvas = canvas;
10
+ }
11
+ else {
12
+ this.#canvas = createCanvas();
13
+ }
14
+ }
15
+ setSize(width, height) {
16
+ if (this.#canvas.width !== width || this.#canvas.height !== height) {
17
+ this.#canvas.width = width;
18
+ this.#canvas.height = height;
19
+ }
20
+ }
21
+ }
22
+ //# sourceMappingURL=canvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas.js","sourceRoot":"","sources":["../../../src/video/render/canvas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAIlE,MAAM,OAAgB,mCAAmC;IAGrD,OAAO,CAAsC;IAC7C,IAAI,MAAM;QACN,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,YAAY,MAA4C;QACpD,IAAI,MAAM,EAAE,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QAC1B,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,OAAO,GAAG,YAAY,EAAE,CAAC;QAClC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,MAAc;QACjC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACjE,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;YAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;QACjC,CAAC;IACL,CAAC;CAGJ"}
@@ -1,4 +1,6 @@
1
1
  export * from "./bitmap.js";
2
+ export * from "./canvas.js";
3
+ export * from "./insertable-stream.js";
2
4
  export * from "./type.js";
3
5
  export * from "./webgl.js";
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/video/render/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/video/render/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
@@ -1,4 +1,7 @@
1
+ // cspell: ignore insertable
1
2
  export * from "./bitmap.js";
3
+ export * from "./canvas.js";
4
+ export * from "./insertable-stream.js";
2
5
  export * from "./type.js";
3
6
  export * from "./webgl.js";
4
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/video/render/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/video/render/index.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAE5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { WebCodecsVideoDecoderRenderer } from "./type.js";
2
+ export declare class InsertableStreamWebCodecsDecoderRenderer implements WebCodecsVideoDecoderRenderer {
3
+ #private;
4
+ static get isSupported(): boolean;
5
+ get element(): HTMLVideoElement;
6
+ constructor(element?: HTMLVideoElement);
7
+ setSize(width: number, height: number): void;
8
+ draw(frame: VideoFrame): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=insertable-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insertable-stream.d.ts","sourceRoot":"","sources":["../../../src/video/render/insertable-stream.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAQ/D,qBAAa,wCACT,YAAW,6BAA6B;;IAExC,MAAM,KAAK,WAAW,YAErB;IAGD,IAAI,OAAO,qBAEV;gBAMW,OAAO,CAAC,EAAE,gBAAgB;IAyBtC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAOtC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C"}