@yume-chan/scrcpy-decoder-webcodecs 0.0.24 → 1.0.0

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 (43) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/README.md +49 -29
  3. package/esm/video/codec/h265.d.ts.map +1 -1
  4. package/esm/video/codec/h265.js +3 -0
  5. package/esm/video/codec/h265.js.map +1 -1
  6. package/esm/video/decoder.d.ts +14 -7
  7. package/esm/video/decoder.d.ts.map +1 -1
  8. package/esm/video/decoder.js +166 -67
  9. package/esm/video/decoder.js.map +1 -1
  10. package/esm/video/render/bitmap.d.ts +4 -4
  11. package/esm/video/render/bitmap.d.ts.map +1 -1
  12. package/esm/video/render/bitmap.js +9 -11
  13. package/esm/video/render/bitmap.js.map +1 -1
  14. package/esm/video/render/canvas.d.ts +9 -0
  15. package/esm/video/render/canvas.d.ts.map +1 -0
  16. package/esm/video/render/canvas.js +22 -0
  17. package/esm/video/render/canvas.js.map +1 -0
  18. package/esm/video/render/index.d.ts +2 -0
  19. package/esm/video/render/index.d.ts.map +1 -1
  20. package/esm/video/render/index.js +3 -0
  21. package/esm/video/render/index.js.map +1 -1
  22. package/esm/video/render/insertable-stream.d.ts +10 -0
  23. package/esm/video/render/insertable-stream.d.ts.map +1 -0
  24. package/esm/video/render/insertable-stream.js +45 -0
  25. package/esm/video/render/insertable-stream.js.map +1 -0
  26. package/esm/video/render/type.d.ts +4 -2
  27. package/esm/video/render/type.d.ts.map +1 -1
  28. package/esm/video/render/webgl.d.ts +5 -4
  29. package/esm/video/render/webgl.d.ts.map +1 -1
  30. package/esm/video/render/webgl.js +26 -14
  31. package/esm/video/render/webgl.js.map +1 -1
  32. package/package.json +11 -14
  33. package/src/video/codec/h265.ts +3 -0
  34. package/src/video/decoder.ts +197 -69
  35. package/src/video/render/bitmap.ts +11 -17
  36. package/src/video/render/canvas.ts +29 -0
  37. package/src/video/render/index.ts +4 -0
  38. package/src/video/render/insertable-stream.ts +62 -0
  39. package/src/video/render/type.ts +6 -2
  40. package/src/video/render/webgl.ts +47 -19
  41. package/tsconfig.build.json +4 -1
  42. package/tsconfig.build.tsbuildinfo +1 -1
  43. package/CHANGELOG.json +0 -89
package/CHANGELOG.md CHANGED
@@ -1,8 +1,32 @@
1
1
  # Change Log - @yume-chan/scrcpy-decoder-webcodecs
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch 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.
10
+
11
+ - db8466f: Fix H.265 rendering in Microsoft Edge
12
+ - 8e4c1ef: Add a renderer based on Insertable Stream API
13
+ - db8466f: Add a `snapshot` method to convert the last rendered frame into PNG
14
+ - Updated dependencies [53688d3]
15
+ - Updated dependencies [db8466f]
16
+ - Updated dependencies [db8466f]
17
+ - Updated dependencies [ea5002b]
18
+ - Updated dependencies [ea5002b]
19
+ - Updated dependencies [db8466f]
20
+ - @yume-chan/scrcpy-decoder-tinyh264@1.0.1
21
+ - @yume-chan/no-data-view@1.0.1
22
+ - @yume-chan/stream-extra@1.0.1
23
+ - @yume-chan/scrcpy@1.0.1
24
+ - @yume-chan/event@1.0.1
25
+
3
26
  This log was last generated on Tue, 18 Jun 2024 02:49:43 GMT and should not be manually modified.
4
27
 
5
28
  ## 0.0.24
29
+
6
30
  Tue, 18 Jun 2024 02:49:43 GMT
7
31
 
8
32
  ### Updates
@@ -11,6 +35,7 @@ Tue, 18 Jun 2024 02:49:43 GMT
11
35
  - Add `enableCapture` option to `WebCodecsVideoDecoder` which allows `renderer.readPixels` and `renderer.toDataURL` to work. The performance will be slightly affected when enabled.
12
36
 
13
37
  ## 0.0.23
38
+
14
39
  Thu, 21 Mar 2024 03:15:10 GMT
15
40
 
16
41
  ### Updates
@@ -19,16 +44,19 @@ Thu, 21 Mar 2024 03:15:10 GMT
19
44
  - Add WebGL and Bitmap based video renderers, which are 1.5 to 3 times faster on Android devices
20
45
 
21
46
  ## 0.0.22
47
+
22
48
  Wed, 13 Dec 2023 05:57:27 GMT
23
49
 
24
50
  _Version update only_
25
51
 
26
52
  ## 0.0.21
53
+
27
54
  Fri, 25 Aug 2023 14:05:18 GMT
28
55
 
29
56
  _Version update only_
30
57
 
31
58
  ## 0.0.20
59
+
32
60
  Mon, 05 Jun 2023 02:51:41 GMT
33
61
 
34
62
  ### Updates
@@ -36,11 +64,13 @@ Mon, 05 Jun 2023 02:51:41 GMT
36
64
  - 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).
37
65
 
38
66
  ## 0.0.19
67
+
39
68
  Sun, 09 Apr 2023 05:55:33 GMT
40
69
 
41
70
  _Version update only_
42
71
 
43
72
  ## 0.0.18
73
+
44
74
  Wed, 25 Jan 2023 21:33:49 GMT
45
75
 
46
76
  ### Updates
@@ -48,9 +78,9 @@ Wed, 25 Jan 2023 21:33:49 GMT
48
78
  - Change to not use vertical sync to minimize latency
49
79
 
50
80
  ## 0.0.17
81
+
51
82
  Tue, 18 Oct 2022 09:32:30 GMT
52
83
 
53
84
  ### Updates
54
85
 
55
86
  - Separated from `@yume-chan/scrcpy` for simpler dependency management.
56
-
package/README.md CHANGED
@@ -1,29 +1,49 @@
1
- # @yume-chan/scrcpy-decoder-webcodecs
2
-
3
- Decode and render H.264 streams using the [WebCodecs API](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API).
4
-
5
- It has no dependencies and high performance, but is only available on recent versions of Chrome.
6
-
7
- **WARNING:** The public API is UNSTABLE. Open a GitHub discussion if you have any questions.
8
-
9
- - [Compatibility](#compatibility)
10
- - [Usage](#usage)
11
-
12
- ## Compatibility
13
-
14
- | Chrome | Firefox | Safari | Performance | Supported H.264 profile/level |
15
- | ------ | ------- | ------ | ------------------------------- | ----------------------------- |
16
- | 94 | No | No | High with hardware acceleration | High level 5 |
17
-
18
- ## Usage
19
-
20
- It draws frames onto `decoder.renderer` (a `<canvas>` element), you can insert it anywhere you want to display the video.
21
-
22
- ```ts
23
- const decoder = new WebCodecsDecoder();
24
- document.body.appendChild(decoder.renderer);
25
-
26
- videoPacketStream // from `@yume-chan/scrcpy`
27
- .pipeTo(decoder.writable)
28
- .catch(() => {});
29
- ```
1
+ <p align="center">
2
+ <img alt="Tango" src="https://raw.githubusercontent.com/yume-chan/ya-webadb/main/.github/logo.svg" width="200">
3
+ </p>
4
+
5
+ <h1 align="center">@yume-chan/scrcpy-decoder-webcodecs</h1>
6
+
7
+ <p align="center">
8
+ Raw H.264 stream decoder and renderer using WebCodecs API (requires modern browser).
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://github.com/yume-chan/ya-webadb/blob/main/LICENSE">
13
+ <img alt="MIT License" src="https://img.shields.io/github/license/yume-chan/ya-webadb">
14
+ </a>
15
+ <a href="https://github.com/yume-chan/ya-webadb/releases">
16
+ <img alt="GitHub release" src="https://img.shields.io/github/v/release/yume-chan/ya-webadb?logo=github">
17
+ </a>
18
+ <a href="https://bundlephobia.com/package/@yume-chan/scrcpy-decoder-webcodecs">
19
+ <img alt="Package Size" src="https://img.shields.io/bundlephobia/minzip/%40yume-chan%2Fscrcpy-decoder-webcodecs">
20
+ </a>
21
+ <a href="https://www.npmjs.com/package/@yume-chan/scrcpy-decoder-webcodecs">
22
+ <img alt="npm" src="https://img.shields.io/npm/dm/%40yume-chan/scrcpy-decoder-webcodecs?logo=npm">
23
+ </a>
24
+ <a href="https://discord.gg/26k3ttC2PN">
25
+ <img alt="Discord" src="https://img.shields.io/discord/1120215514732564502?logo=discord&logoColor=%23ffffff&label=Discord">
26
+ </a>
27
+ </p>
28
+
29
+ This package is part of [Tango ADB](https://github.com/yume-chan/ya-webadb). Generally you need multiple packages to build a complete ADB client that can run on Web browsers and Node.js. Read the documentation for more information.
30
+
31
+ ## Documentation
32
+
33
+ Check the latest documentation at https://docs.tangoapp.dev/scrcpy/video/web-codecs/
34
+
35
+ ## Sponsors
36
+
37
+ [Become a backer](https://opencollective.com/ya-webadb) and get your image on our README on Github with a link to your site.
38
+
39
+ <a href="https://opencollective.com/ya-webadb/backer/0/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/0/avatar.svg?requireActive=false"></a>
40
+ <a href="https://opencollective.com/ya-webadb/backer/1/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/1/avatar.svg?requireActive=false"></a>
41
+ <a href="https://opencollective.com/ya-webadb/backer/2/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/2/avatar.svg?requireActive=false"></a>
42
+ <a href="https://opencollective.com/ya-webadb/backer/3/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/3/avatar.svg?requireActive=false"></a>
43
+ <a href="https://opencollective.com/ya-webadb/backer/4/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/4/avatar.svg?requireActive=false"></a>
44
+ <a href="https://opencollective.com/ya-webadb/backer/5/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/5/avatar.svg?requireActive=false"></a>
45
+ <a href="https://opencollective.com/ya-webadb/backer/6/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/6/avatar.svg?requireActive=false"></a>
46
+ <a href="https://opencollective.com/ya-webadb/backer/7/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/7/avatar.svg?requireActive=false"></a>
47
+ <a href="https://opencollective.com/ya-webadb/backer/8/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/8/avatar.svg?requireActive=false"></a>
48
+ <a href="https://opencollective.com/ya-webadb/backer/9/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/9/avatar.svg?requireActive=false"></a>
49
+ <a href="https://opencollective.com/ya-webadb/backer/10/website?requireActive=false" target="_blank"><img src="https://opencollective.com/ya-webadb/backer/10/avatar.svg?requireActive=false"></a>
@@ -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"}
@@ -2,13 +2,14 @@ import type { ScrcpyMediaStreamPacket } from "@yume-chan/scrcpy";
2
2
  import { ScrcpyVideoCodecId } from "@yume-chan/scrcpy";
3
3
  import type { ScrcpyVideoDecoder, ScrcpyVideoDecoderCapability } from "@yume-chan/scrcpy-decoder-tinyh264";
4
4
  import { WritableStream } from "@yume-chan/stream-extra";
5
+ import type { WebCodecsVideoDecoderRenderer } from "./render/index.js";
5
6
  export declare class WebCodecsVideoDecoder implements ScrcpyVideoDecoder {
6
7
  #private;
7
- static isSupported(): boolean;
8
+ static get isSupported(): boolean;
8
9
  static readonly capabilities: Record<string, ScrcpyVideoDecoderCapability>;
9
10
  get codec(): ScrcpyVideoCodecId;
10
11
  get writable(): WritableStream<ScrcpyMediaStreamPacket>;
11
- get renderer(): HTMLCanvasElement;
12
+ get renderer(): WebCodecsVideoDecoderRenderer;
12
13
  get framesRendered(): number;
13
14
  get framesSkipped(): number;
14
15
  get sizeChanged(): import("@yume-chan/event").AddEventListener<{
@@ -17,12 +18,18 @@ export declare class WebCodecsVideoDecoder implements ScrcpyVideoDecoder {
17
18
  }, unknown>;
18
19
  /**
19
20
  * Create a new WebCodecs video decoder.
20
- * @param codec The video codec to decode
21
- * @param enableCapture
22
- * Whether to allow capturing the canvas content using APIs like `readPixels` and `toDataURL`.
23
- * Enable this option may reduce performance.
24
21
  */
25
- constructor(codec: ScrcpyVideoCodecId, enableCapture: boolean);
22
+ constructor({ codec, renderer }: WebCodecsVideoDecoder.Options);
23
+ snapshot(): Promise<Blob | undefined>;
26
24
  dispose(): void;
27
25
  }
26
+ export declare namespace WebCodecsVideoDecoder {
27
+ interface Options {
28
+ /**
29
+ * The video codec to decode
30
+ */
31
+ codec: ScrcpyVideoCodecId;
32
+ renderer: WebCodecsVideoDecoderRenderer;
33
+ }
34
+ }
28
35
  //# 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,EAC/B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAOzD,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,sBAEX;IAGD,IAAI,cAAc,WAEjB;IAGD,IAAI,aAAa,WAEhB;IAGD,IAAI,WAAW;;;gBAEd;IAQD;;;;;;OAMG;gBACS,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,OAAO;IAqG7D,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,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,qBAAqB,CAAC,OAAO;IAsHxD,QAAQ;IAYd,OAAO;CAQV;AAED,yBAAiB,qBAAqB,CAAC;IACnC,UAAiB,OAAO;QACpB;;WAEG;QACH,KAAK,EAAE,kBAAkB,CAAC;QAE1B,QAAQ,EAAE,6BAA6B,CAAC;KAC3C;CACJ"}
@@ -2,14 +2,86 @@ import { EventEmitter } from "@yume-chan/event";
2
2
  import { ScrcpyVideoCodecId } from "@yume-chan/scrcpy";
3
3
  import { WritableStream } from "@yume-chan/stream-extra";
4
4
  import { Av1Codec, H264Decoder, H265Decoder } from "./codec/index.js";
5
- import { BitmapFrameRenderer, WebGLFrameRenderer } 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);
6
77
  export class WebCodecsVideoDecoder {
7
- static isSupported() {
78
+ static get isSupported() {
8
79
  return typeof globalThis.VideoDecoder !== "undefined";
9
80
  }
10
81
  static capabilities = {
11
82
  h264: {},
12
83
  h265: {},
84
+ av1: {},
13
85
  };
14
86
  #codec;
15
87
  get codec() {
@@ -20,73 +92,53 @@ export class WebCodecsVideoDecoder {
20
92
  get writable() {
21
93
  return this.#writable;
22
94
  }
23
- #canvas;
95
+ #error;
96
+ #controller;
97
+ #renderer;
24
98
  get renderer() {
25
- return this.#canvas;
99
+ return this.#renderer;
26
100
  }
27
- #frameRendered = 0;
101
+ #framesDraw = 0;
102
+ #framesPresented = 0;
28
103
  get framesRendered() {
29
- return this.#frameRendered;
104
+ return this.#framesPresented;
30
105
  }
31
- #frameSkipped = 0;
106
+ #framesSkipped = 0;
32
107
  get framesSkipped() {
33
- return this.#frameSkipped;
108
+ return this.#framesSkipped;
34
109
  }
35
110
  #sizeChanged = new EventEmitter();
36
111
  get sizeChanged() {
37
112
  return this.#sizeChanged.event;
38
113
  }
39
114
  #decoder;
40
- #renderer;
41
- #currentFrameRendered = false;
115
+ #drawing = false;
116
+ #nextFrame;
117
+ #captureFrame;
42
118
  #animationFrameId = 0;
43
119
  /**
44
120
  * Create a new WebCodecs video decoder.
45
- * @param codec The video codec to decode
46
- * @param enableCapture
47
- * Whether to allow capturing the canvas content using APIs like `readPixels` and `toDataURL`.
48
- * Enable this option may reduce performance.
49
121
  */
50
- constructor(codec, enableCapture) {
122
+ constructor({ codec, renderer }) {
51
123
  this.#codec = codec;
52
- this.#canvas = document.createElement("canvas");
53
- try {
54
- this.#renderer = new WebGLFrameRenderer(this.#canvas, enableCapture);
55
- }
56
- catch {
57
- this.#renderer = new BitmapFrameRenderer(this.#canvas);
58
- }
124
+ this.#renderer = renderer;
59
125
  this.#decoder = new VideoDecoder({
60
126
  output: (frame) => {
61
- if (this.#currentFrameRendered) {
62
- this.#frameRendered += 1;
63
- }
64
- else {
65
- this.#frameSkipped += 1;
66
- }
67
- this.#currentFrameRendered = false;
68
- // PERF: Draw every frame to minimize latency at cost of performance.
69
- // When multiple frames are drawn in one vertical sync interval,
70
- // only the last one is visible to users.
71
- // But this ensures users can always see the most up-to-date screen.
72
- // This is also the behavior of official Scrcpy client.
73
- // https://github.com/Genymobile/scrcpy/issues/3679
74
- this.#updateSize(frame.displayWidth, frame.displayHeight);
75
- this.#renderer.draw(frame);
76
- },
77
- error(e) {
78
- if (controller) {
79
- try {
80
- 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;
81
134
  }
82
- catch {
83
- // ignore
84
- // `controller` may already in error state
85
- }
86
- }
87
- else {
88
- error = e;
135
+ this.#nextFrame = frame;
136
+ return;
89
137
  }
138
+ void this.#draw(frame);
139
+ },
140
+ error: (error) => {
141
+ this.#setError(error);
90
142
  },
91
143
  });
92
144
  switch (this.#codec) {
@@ -99,43 +151,90 @@ export class WebCodecsVideoDecoder {
99
151
  case ScrcpyVideoCodecId.AV1:
100
152
  this.#codecDecoder = new Av1Codec(this.#decoder, this.#updateSize);
101
153
  break;
154
+ default:
155
+ throw new Error(`Unsupported codec: ${this.#codec}`);
102
156
  }
103
- let error;
104
- let controller;
105
157
  this.#writable = new WritableStream({
106
- start: (_controller) => {
107
- if (error) {
108
- _controller.error(error);
158
+ start: (controller) => {
159
+ if (this.#error) {
160
+ controller.error(this.#error);
109
161
  }
110
162
  else {
111
- controller = _controller;
163
+ this.#controller = controller;
112
164
  }
113
165
  },
114
166
  write: (packet) => {
115
167
  this.#codecDecoder.decode(packet);
116
168
  },
117
169
  });
118
- this.#onFramePresented();
170
+ this.#onVerticalSync();
119
171
  }
120
- #updateSize = (width, height) => {
121
- if (width !== this.#canvas.width || height !== this.#canvas.height) {
122
- this.#canvas.width = width;
123
- this.#canvas.height = height;
124
- this.#sizeChanged.fire({
125
- width: width,
126
- height: height,
127
- });
172
+ #setError(error) {
173
+ if (this.#controller) {
174
+ try {
175
+ this.#controller.error(error);
176
+ }
177
+ catch {
178
+ // ignore
179
+ }
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);
128
207
  }
208
+ }
209
+ #updateSize = (width, height) => {
210
+ this.#renderer.setSize(width, height);
211
+ this.#sizeChanged.fire({ width, height });
129
212
  };
130
- #onFramePresented = () => {
131
- this.#currentFrameRendered = true;
132
- 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);
133
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
+ }
134
231
  dispose() {
135
232
  cancelAnimationFrame(this.#animationFrameId);
136
233
  if (this.#decoder.state !== "closed") {
137
234
  this.#decoder.close();
138
235
  }
236
+ this.#nextFrame?.close();
237
+ this.#captureFrame?.close();
139
238
  }
140
239
  }
141
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":"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"}
@@ -1,7 +1,7 @@
1
- import type { FrameRenderer } from "./type.js";
2
- export declare class BitmapFrameRenderer implements FrameRenderer {
1
+ import { CanvasWebCodecsDecoderRenderer } from "./canvas.js";
2
+ export declare class BitmapWebCodecsDecoderRenderer extends CanvasWebCodecsDecoderRenderer {
3
3
  #private;
4
- constructor(canvas: HTMLCanvasElement);
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,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,qBAAa,mBAAoB,YAAW,aAAa;;gBAGzC,MAAM,EAAE,iBAAiB;IAIrC,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,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAE7D,qBAAa,8BAA+B,SAAQ,8BAA8B;;gBAGlE,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 BitmapFrameRenderer {
1
+ import { CanvasWebCodecsDecoderRenderer } from "./canvas.js";
2
+ export class BitmapWebCodecsDecoderRenderer extends CanvasWebCodecsDecoderRenderer {
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,mBAAmB;IAC5B,QAAQ,CAA8B;IAEtC,YAAY,MAAyB;QACjC,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,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAE7D,MAAM,OAAO,8BAA+B,SAAQ,8BAA8B;IAC9E,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 CanvasWebCodecsDecoderRenderer 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,8BAClB,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"}