@yume-chan/scrcpy-decoder-webcodecs 2.5.3 → 3.0.0-beta.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 (117) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -1
  3. package/esm/video/codec/av1.d.ts +4 -6
  4. package/esm/video/codec/av1.d.ts.map +1 -1
  5. package/esm/video/codec/av1.js +29 -95
  6. package/esm/video/codec/av1.js.map +1 -1
  7. package/esm/video/codec/h264.d.ts +4 -6
  8. package/esm/video/codec/h264.d.ts.map +1 -1
  9. package/esm/video/codec/h264.js +11 -21
  10. package/esm/video/codec/h264.js.map +1 -1
  11. package/esm/video/codec/h265.d.ts +4 -6
  12. package/esm/video/codec/h265.d.ts.map +1 -1
  13. package/esm/video/codec/h265.js +13 -27
  14. package/esm/video/codec/h265.js.map +1 -1
  15. package/esm/video/codec/h26x.d.ts +9 -6
  16. package/esm/video/codec/h26x.d.ts.map +1 -1
  17. package/esm/video/codec/h26x.js +25 -69
  18. package/esm/video/codec/h26x.js.map +1 -1
  19. package/esm/video/codec/index.d.ts +0 -1
  20. package/esm/video/codec/index.d.ts.map +1 -1
  21. package/esm/video/codec/index.js +0 -1
  22. package/esm/video/codec/index.js.map +1 -1
  23. package/esm/video/codec/type.d.ts +23 -8
  24. package/esm/video/codec/type.d.ts.map +1 -1
  25. package/esm/video/decoder.d.ts +62 -15
  26. package/esm/video/decoder.d.ts.map +1 -1
  27. package/esm/video/decoder.js +170 -134
  28. package/esm/video/decoder.js.map +1 -1
  29. package/esm/video/index.d.ts +1 -0
  30. package/esm/video/index.d.ts.map +1 -1
  31. package/esm/video/index.js +1 -0
  32. package/esm/video/index.js.map +1 -1
  33. package/esm/video/render/auto-canvas.d.ts +26 -0
  34. package/esm/video/render/auto-canvas.d.ts.map +1 -0
  35. package/esm/video/render/auto-canvas.js +80 -0
  36. package/esm/video/render/auto-canvas.js.map +1 -0
  37. package/esm/video/render/bitmap.d.ts +2 -2
  38. package/esm/video/render/bitmap.d.ts.map +1 -1
  39. package/esm/video/render/bitmap.js +18 -8
  40. package/esm/video/render/bitmap.js.map +1 -1
  41. package/esm/video/render/canvas.d.ts +38 -4
  42. package/esm/video/render/canvas.d.ts.map +1 -1
  43. package/esm/video/render/canvas.js +97 -10
  44. package/esm/video/render/canvas.js.map +1 -1
  45. package/esm/video/render/flow-control.d.ts +32 -0
  46. package/esm/video/render/flow-control.d.ts.map +1 -0
  47. package/esm/video/render/flow-control.js +139 -0
  48. package/esm/video/render/flow-control.js.map +1 -0
  49. package/esm/video/render/index.d.ts +2 -0
  50. package/esm/video/render/index.d.ts.map +1 -1
  51. package/esm/video/render/index.js +2 -0
  52. package/esm/video/render/index.js.map +1 -1
  53. package/esm/video/render/insertable-stream.d.ts +15 -3
  54. package/esm/video/render/insertable-stream.d.ts.map +1 -1
  55. package/esm/video/render/insertable-stream.js +29 -11
  56. package/esm/video/render/insertable-stream.js.map +1 -1
  57. package/esm/video/render/redraw.d.ts +31 -0
  58. package/esm/video/render/redraw.d.ts.map +1 -0
  59. package/esm/video/render/redraw.js +75 -0
  60. package/esm/video/render/redraw.js.map +1 -0
  61. package/esm/video/render/type.d.ts +8 -2
  62. package/esm/video/render/type.d.ts.map +1 -1
  63. package/esm/video/render/webgl.d.ts +38 -5
  64. package/esm/video/render/webgl.d.ts.map +1 -1
  65. package/esm/video/render/webgl.js +228 -59
  66. package/esm/video/render/webgl.js.map +1 -1
  67. package/esm/video/utils/index.d.ts +4 -0
  68. package/esm/video/utils/index.d.ts.map +1 -0
  69. package/esm/video/utils/index.js +4 -0
  70. package/esm/video/utils/index.js.map +1 -0
  71. package/esm/video/utils/snapshot.d.ts +2 -0
  72. package/esm/video/utils/snapshot.d.ts.map +1 -0
  73. package/esm/video/utils/snapshot.js +18 -0
  74. package/esm/video/utils/snapshot.js.map +1 -0
  75. package/esm/video/utils/timestamp.d.ts +19 -0
  76. package/esm/video/utils/timestamp.d.ts.map +1 -0
  77. package/esm/video/utils/timestamp.js +87 -0
  78. package/esm/video/utils/timestamp.js.map +1 -0
  79. package/esm/video/utils/video-decoder-stream.d.ts +30 -0
  80. package/esm/video/utils/video-decoder-stream.d.ts.map +1 -0
  81. package/esm/video/utils/video-decoder-stream.js +284 -0
  82. package/esm/video/utils/video-decoder-stream.js.map +1 -0
  83. package/package.json +12 -11
  84. package/src/video/codec/av1.ts +41 -131
  85. package/src/video/codec/h264.ts +15 -37
  86. package/src/video/codec/h265.ts +16 -45
  87. package/src/video/codec/h26x.ts +45 -96
  88. package/src/video/codec/index.ts +0 -1
  89. package/src/video/codec/type.ts +32 -12
  90. package/src/video/decoder.ts +203 -165
  91. package/src/video/index.ts +1 -0
  92. package/src/video/render/auto-canvas.ts +105 -0
  93. package/src/video/render/bitmap.ts +23 -9
  94. package/src/video/render/canvas.ts +157 -12
  95. package/src/video/render/flow-control.ts +182 -0
  96. package/src/video/render/index.ts +2 -0
  97. package/src/video/render/insertable-stream.ts +50 -10
  98. package/src/video/render/redraw.ts +88 -0
  99. package/src/video/render/type.ts +10 -2
  100. package/src/video/render/webgl.ts +316 -80
  101. package/src/video/utils/index.ts +3 -0
  102. package/src/video/utils/snapshot.ts +22 -0
  103. package/src/video/utils/timestamp.ts +108 -0
  104. package/src/video/utils/video-decoder-stream.ts +406 -0
  105. package/tsconfig.build.json +0 -14
  106. package/CHANGELOG.md +0 -140
  107. package/esm/video/codec/utils.d.ts +0 -4
  108. package/esm/video/codec/utils.d.ts.map +0 -1
  109. package/esm/video/codec/utils.js +0 -10
  110. package/esm/video/codec/utils.js.map +0 -1
  111. package/esm/video/snapshot.d.ts +0 -6
  112. package/esm/video/snapshot.d.ts.map +0 -1
  113. package/esm/video/snapshot.js +0 -41
  114. package/esm/video/snapshot.js.map +0 -1
  115. package/src/video/codec/utils.ts +0 -11
  116. package/src/video/snapshot.ts +0 -41
  117. package/tsconfig.build.tsbuildinfo +0 -1
@@ -1,7 +1,7 @@
1
1
  import { CanvasVideoFrameRenderer } from "./canvas.js";
2
2
  export declare class BitmapVideoFrameRenderer extends CanvasVideoFrameRenderer {
3
3
  #private;
4
- constructor(canvas?: HTMLCanvasElement | OffscreenCanvas);
5
- draw(frame: VideoFrame): Promise<void>;
4
+ get type(): "software";
5
+ constructor(options?: CanvasVideoFrameRenderer.Options);
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,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,qBAAa,wBAAyB,SAAQ,wBAAwB;;gBAGtD,MAAM,CAAC,EAAE,iBAAiB,GAAG,eAAe;IAQlD,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAI/C"}
1
+ {"version":3,"file":"bitmap.d.ts","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,qBAAa,wBAAyB,SAAQ,wBAAwB;;IAClE,IAAa,IAAI,IACN,UAAU,CACpB;gBAIW,OAAO,CAAC,EAAE,wBAAwB,CAAC,OAAO;CAsBzD"}
@@ -1,15 +1,25 @@
1
1
  import { CanvasVideoFrameRenderer } from "./canvas.js";
2
2
  export class BitmapVideoFrameRenderer extends CanvasVideoFrameRenderer {
3
+ get type() {
4
+ return "software";
5
+ }
3
6
  #context;
4
- constructor(canvas) {
5
- super(canvas);
6
- this.#context = this.canvas.getContext("bitmaprenderer", {
7
- alpha: false,
7
+ constructor(options) {
8
+ super(async (frame) => {
9
+ const bitmap = await createImageBitmap(frame);
10
+ this.#context.transferFromImageBitmap(bitmap);
11
+ bitmap.close();
12
+ }, options);
13
+ const context = this.canvas.getContext("bitmaprenderer", {
14
+ // Avoid alpha:false, which can be expensive
15
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#avoid_alphafalse_which_can_be_expensive
16
+ alpha: true,
8
17
  });
9
- }
10
- async draw(frame) {
11
- const bitmap = await createImageBitmap(frame);
12
- this.#context.transferFromImageBitmap(bitmap);
18
+ if (!context) {
19
+ // This can happen if the canvas already has a context of a different type
20
+ throw new Error("Failed to create rendering context");
21
+ }
22
+ this.#context = context;
13
23
  }
14
24
  }
15
25
  //# sourceMappingURL=bitmap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bitmap.js","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,OAAO,wBAAyB,SAAQ,wBAAwB;IAClE,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"}
1
+ {"version":3,"file":"bitmap.js","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,OAAO,wBAAyB,SAAQ,wBAAwB;IAClE,IAAa,IAAI;QACb,OAAO,UAAmB,CAAC;IAC/B,CAAC;IAED,QAAQ,CAA8B;IAEtC,YAAY,OAA0C;QAClD,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAClB,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC,EAAE,OAAO,CAAC,CAAC;QAEZ,MAAM,OAAO,GAAI,IAAI,CAAC,MAA4B,CAAC,UAAU,CACzD,gBAAgB,EAChB;YACI,4CAA4C;YAC5C,0HAA0H;YAC1H,KAAK,EAAE,IAAI;SACd,CACJ,CAAC;QACF,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,0EAA0E;YAC1E,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC5B,CAAC;CACJ"}
@@ -1,9 +1,43 @@
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
2
+ import type { ScrcpyVideoDecoder } from "@yume-chan/scrcpy-decoder-shared";
3
+ import { WritableStream } from "@yume-chan/stream-extra";
1
4
  import type { VideoFrameRenderer } from "./type.js";
2
- export declare abstract class CanvasVideoFrameRenderer implements VideoFrameRenderer {
5
+ export declare abstract class CanvasVideoFrameRenderer<TOptions extends CanvasVideoFrameRenderer.Options = CanvasVideoFrameRenderer.Options> implements VideoFrameRenderer {
3
6
  #private;
7
+ abstract get type(): ScrcpyVideoDecoder.RendererType;
4
8
  get canvas(): HTMLCanvasElement | OffscreenCanvas;
5
- constructor(canvas?: HTMLCanvasElement | OffscreenCanvas);
6
- setSize(width: number, height: number): void;
7
- abstract draw(frame: VideoFrame): Promise<void>;
9
+ get options(): Readonly<TOptions> | undefined;
10
+ get lastFrame(): VideoFrame | undefined;
11
+ get writable(): WritableStream<VideoFrame>;
12
+ constructor(draw: (frame: VideoFrame) => MaybePromiseLike<undefined>, options?: TOptions);
13
+ /**
14
+ * Redraws the last drawn frame.
15
+ *
16
+ * If a draw or redraw is in progress, it waits for them to finish before redrawing.
17
+ *
18
+ * If a redraw is in progress and another one is in queue,
19
+ * it cancels the queued redraw and redraws the latest frame instead.
20
+ */
21
+ redraw(): Promise<undefined>;
22
+ snapshot(options?: ImageEncodeOptions): Promise<Blob | undefined>;
23
+ dispose(): undefined;
24
+ }
25
+ export declare namespace CanvasVideoFrameRenderer {
26
+ interface Options {
27
+ canvas?: HTMLCanvasElement | OffscreenCanvas;
28
+ /**
29
+ * Whether to update the canvas size (rendering resolution) automatically.
30
+ *
31
+ * * `"video"` (default): update the canvas size to match the video resolution
32
+ * * `"display"` (only for `HTMLCanvasElement`):
33
+ * update the canvas size to match the display size.
34
+ * The display size can be set using `canvas.style.width/height`,
35
+ * and must be in correct aspect ratio.
36
+ * * `"external"`: use the canvas size as it is.
37
+ * The size must be manually set using `canvas.width/height`,
38
+ * and must be in correct aspect ratio.
39
+ */
40
+ canvasSize?: "video" | "display" | "external";
41
+ }
8
42
  }
9
43
  //# sourceMappingURL=canvas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../../../src/video/render/canvas.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAEpD,8BAAsB,wBAAyB,YAAW,kBAAkB;;IAExE,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"}
1
+ {"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../../../src/video/render/canvas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAE3E,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAKzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAEpD,8BAAsB,wBAAwB,CAC1C,QAAQ,SAAS,wBAAwB,CAAC,OAAO,GAC7C,wBAAwB,CAAC,OAAO,CACtC,YAAW,kBAAkB;;IAC3B,QAAQ,KAAK,IAAI,IAAI,kBAAkB,CAAC,YAAY,CAAC;IAGrD,IAAI,MAAM,wCAET;IAID,IAAI,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,SAAS,CAE5C;IAcD,IAAI,SAAS,2BAEZ;IAKD,IAAI,QAAQ,+BAEX;gBAGG,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,gBAAgB,CAAC,SAAS,CAAC,EACxD,OAAO,CAAC,EAAE,QAAQ;IAuEtB;;;;;;;OAOG;IACH,MAAM;IAIA,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAOvE,OAAO,IAAI,SAAS;CASvB;AAED,yBAAiB,wBAAwB,CAAC;IACtC,UAAiB,OAAO;QACpB,MAAM,CAAC,EAAE,iBAAiB,GAAG,eAAe,CAAC;QAE7C;;;;;;;;;;;WAWG;QACH,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;KACjD;CACJ"}
@@ -1,22 +1,109 @@
1
- import { createCanvas } from "@yume-chan/scrcpy-decoder-tinyh264";
1
+ import { createCanvas } from "@yume-chan/scrcpy-decoder-shared";
2
+ import { WritableStream } from "@yume-chan/stream-extra";
3
+ import { canvasToBlob } from "../utils/index.js";
4
+ import { RedrawController } from "./redraw.js";
2
5
  export class CanvasVideoFrameRenderer {
3
6
  #canvas;
4
7
  get canvas() {
5
8
  return this.#canvas;
6
9
  }
7
- constructor(canvas) {
8
- if (canvas) {
9
- this.#canvas = canvas;
10
+ #options;
11
+ #canvasSize;
12
+ get options() {
13
+ return this.#options;
14
+ }
15
+ #resizeObserver;
16
+ #displayWidth = Infinity;
17
+ #displayHeight = Infinity;
18
+ #draw;
19
+ #controller = new RedrawController((frame) => {
20
+ if (this.#canvasSize !== "external") {
21
+ this.#updateSize(frame);
22
+ }
23
+ return this.#draw(frame);
24
+ });
25
+ get lastFrame() {
26
+ return this.#controller.lastFrame;
27
+ }
28
+ #writable = new WritableStream({
29
+ write: (frame) => this.#controller.draw(frame),
30
+ });
31
+ get writable() {
32
+ return this.#writable;
33
+ }
34
+ constructor(draw, options) {
35
+ this.#draw = draw;
36
+ this.#canvas = options?.canvas ?? createCanvas();
37
+ this.#options = options;
38
+ this.#canvasSize = options?.canvasSize ?? "video";
39
+ if (this.#canvasSize === "display") {
40
+ if (typeof HTMLCanvasElement === "undefined" ||
41
+ !(this.#canvas instanceof HTMLCanvasElement)) {
42
+ throw new Error("`canvasSize: display` is only supported for HTMLCanvasElement");
43
+ }
44
+ this.#resizeObserver = new ResizeObserver((entries) => {
45
+ const entry = entries[0];
46
+ if (!entry) {
47
+ return;
48
+ }
49
+ const devicePixelSize = entry.devicePixelContentBoxSize?.[0];
50
+ if (devicePixelSize) {
51
+ this.#setDisplaySize(devicePixelSize.inlineSize, devicePixelSize.blockSize);
52
+ return;
53
+ }
54
+ const cssSize = entry.contentBoxSize[0];
55
+ if (cssSize) {
56
+ this.#setDisplaySize(Math.round(cssSize.inlineSize * devicePixelRatio), Math.round(cssSize.blockSize * devicePixelRatio));
57
+ }
58
+ });
59
+ this.#resizeObserver.observe(this.#canvas);
60
+ }
61
+ }
62
+ #setDisplaySize(width, height) {
63
+ if (this.#displayWidth === width && this.#displayHeight === height) {
64
+ return;
10
65
  }
11
- else {
12
- this.#canvas = createCanvas();
66
+ this.#displayWidth = width;
67
+ this.#displayHeight = height;
68
+ void this.#controller.redraw();
69
+ }
70
+ #updateSize(frame) {
71
+ let { codedWidth: width, codedHeight: height } = frame;
72
+ if (this.#canvasSize === "display") {
73
+ width = Math.min(width, this.#displayWidth);
74
+ height = Math.min(height, this.#displayHeight);
75
+ }
76
+ if (this.#canvas.width === width && this.#canvas.height === height) {
77
+ return false;
78
+ }
79
+ this.#canvas.width = width;
80
+ this.#canvas.height = height;
81
+ return true;
82
+ }
83
+ /**
84
+ * Redraws the last drawn frame.
85
+ *
86
+ * If a draw or redraw is in progress, it waits for them to finish before redrawing.
87
+ *
88
+ * If a redraw is in progress and another one is in queue,
89
+ * it cancels the queued redraw and redraws the latest frame instead.
90
+ */
91
+ redraw() {
92
+ return this.#controller.redraw();
93
+ }
94
+ async snapshot(options) {
95
+ if (this.#canvasSize !== "video") {
96
+ return undefined;
13
97
  }
98
+ return canvasToBlob(this.#canvas, options);
14
99
  }
15
- setSize(width, height) {
16
- if (this.#canvas.width !== width || this.#canvas.height !== height) {
17
- this.#canvas.width = width;
18
- this.#canvas.height = height;
100
+ dispose() {
101
+ if (this.#canvasSize !== "external") {
102
+ this.#canvas.width = 0;
103
+ this.#canvas.height = 0;
19
104
  }
105
+ this.#resizeObserver?.disconnect();
106
+ this.#controller.dispose();
20
107
  }
21
108
  }
22
109
  //# sourceMappingURL=canvas.js.map
@@ -1 +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,wBAAwB;IAC1C,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
+ {"version":3,"file":"canvas.js","sourceRoot":"","sources":["../../../src/video/render/canvas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { ScrcpyVideoRendererPerformanceCounterInterface } from "@yume-chan/scrcpy-decoder-shared";
2
+ import type { ReadableStream, TransformStream } from "@yume-chan/stream-extra";
3
+ import { WritableStream } from "@yume-chan/stream-extra";
4
+ export declare class RendererController implements TransformStream<VideoFrame, VideoFrame>, ScrcpyVideoRendererPerformanceCounterInterface {
5
+ #private;
6
+ get readable(): ReadableStream<VideoFrame>;
7
+ get writable(): WritableStream<VideoFrame>;
8
+ get captureFrame(): VideoFrame | undefined;
9
+ /**
10
+ * Gets the number of frames that have been drawn on the renderer.
11
+ */
12
+ get framesRendered(): number;
13
+ /**
14
+ * Gets the number of frames that's visible to the user.
15
+ *
16
+ * Multiple frames might be rendered during one vertical sync interval,
17
+ * but only the last of them is represented to the user.
18
+ * This costs some performance but reduces latency by 1 frame.
19
+ *
20
+ * Might be `0` if the renderer is in a nested Web Worker on Chrome due to a Chrome bug.
21
+ * https://issues.chromium.org/issues/41483010
22
+ */
23
+ get framesDisplayed(): number;
24
+ /**
25
+ * Gets the number of frames that wasn't drawn on the renderer
26
+ * because the renderer can't keep up
27
+ */
28
+ get framesSkippedRendering(): number;
29
+ constructor();
30
+ dispose(): void;
31
+ }
32
+ //# sourceMappingURL=flow-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-control.d.ts","sourceRoot":"","sources":["../../../src/video/render/flow-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8CAA8C,EAAE,MAAM,kCAAkC,CAAC;AAEvG,OAAO,KAAK,EAER,cAAc,EACd,eAAe,EAElB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGH,cAAc,EACjB,MAAM,yBAAyB,CAAC;AAEjC,qBAAa,kBACT,YACI,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,EACvC,8CAA8C;;IAIlD,IAAI,QAAQ,+BAEX;IAID,IAAI,QAAQ,+BAEX;IAGD,IAAI,YAAY,2BAEf;IAOD;;OAEG;IACH,IAAI,cAAc,WAEjB;IACD;;;;;;;;;OASG;IACH,IAAI,eAAe,WAElB;IACD;;;OAGG;IACH,IAAI,sBAAsB,WAEzB;;IAmGD,OAAO;CAgBV"}
@@ -0,0 +1,139 @@
1
+ import { ScrcpyVideoRendererPerformanceCounter } from "@yume-chan/scrcpy-decoder-shared";
2
+ import { PushReadableStream, tryClose, WritableStream, } from "@yume-chan/stream-extra";
3
+ export class RendererController {
4
+ #readable;
5
+ #readableController;
6
+ get readable() {
7
+ return this.#readable;
8
+ }
9
+ #writable;
10
+ #writableController;
11
+ get writable() {
12
+ return this.#writable;
13
+ }
14
+ #captureFrame;
15
+ get captureFrame() {
16
+ return this.#captureFrame;
17
+ }
18
+ #nextFrame;
19
+ #drawTask;
20
+ #counter = new ScrcpyVideoRendererPerformanceCounter();
21
+ /**
22
+ * Gets the number of frames that have been drawn on the renderer.
23
+ */
24
+ get framesRendered() {
25
+ return this.#counter.framesRendered;
26
+ }
27
+ /**
28
+ * Gets the number of frames that's visible to the user.
29
+ *
30
+ * Multiple frames might be rendered during one vertical sync interval,
31
+ * but only the last of them is represented to the user.
32
+ * This costs some performance but reduces latency by 1 frame.
33
+ *
34
+ * Might be `0` if the renderer is in a nested Web Worker on Chrome due to a Chrome bug.
35
+ * https://issues.chromium.org/issues/41483010
36
+ */
37
+ get framesDisplayed() {
38
+ return this.#counter.framesDisplayed;
39
+ }
40
+ /**
41
+ * Gets the number of frames that wasn't drawn on the renderer
42
+ * because the renderer can't keep up
43
+ */
44
+ get framesSkippedRendering() {
45
+ return this.#counter.framesSkippedRendering;
46
+ }
47
+ constructor() {
48
+ this.#readable = new PushReadableStream((controller) => {
49
+ this.#readableController = controller;
50
+ });
51
+ this.#writable = new WritableStream({
52
+ start: (controller) => {
53
+ this.#writableController = controller;
54
+ // Propagate `readable` error back to `writable`
55
+ const signal = this.#readableController.abortSignal;
56
+ signal.addEventListener("abort", () => controller.error(signal.reason));
57
+ },
58
+ write: (frame) => {
59
+ this.#captureFrame?.close();
60
+ // `#captureFrame` and `#nextFrame` must not be the same object
61
+ // because they need to be closed at different times
62
+ this.#captureFrame = frame.clone();
63
+ // Frame A is drawing, frame B (`#nextFrame`) is waiting,
64
+ // then frame C (`frame`) arrives.
65
+ // Skip frame B and queue frame C
66
+ if (this.#nextFrame) {
67
+ this.#nextFrame.close();
68
+ this.#counter.increaseFramesSkippedRendering();
69
+ }
70
+ this.#nextFrame = frame;
71
+ // Don't `await` because this writable needs to
72
+ // accept incoming frames as fast as produced.
73
+ // The `#draw` method then draws the frames
74
+ // as fast as the renderer can keep up
75
+ void this.#tryStartDrawing();
76
+ },
77
+ close: async () => {
78
+ // Normally `WritableStream` only calls `close` after `write` finishes,
79
+ // but because our `write` doesn't wait for `#draw`,
80
+ // we might still need to send `#nextFrame` to `readable`.
81
+ // So wait for `#drawTask` before closing `readable`
82
+ await this.#drawTask;
83
+ // `#nextFrame` must be `undefined` at this point
84
+ // Propagate `writable` close to `readable`
85
+ this.#readableController.close();
86
+ this.#counter.dispose();
87
+ // Don't close `#captureFrame` to allow using `snapshot` on the last frame
88
+ },
89
+ abort: async (reason) => {
90
+ // See `close` above
91
+ await this.#drawTask;
92
+ // Propagate `writable` error to `readable`
93
+ this.#readableController.error(reason);
94
+ this.#counter.dispose();
95
+ },
96
+ });
97
+ }
98
+ async #draw() {
99
+ // PERF: Draw every frame to minimize latency at cost of performance.
100
+ // When multiple frames are drawn in one vertical sync interval,
101
+ // only the last one is visible to users.
102
+ // But this ensures users can always see the most up-to-date screen.
103
+ // This is also the behavior of official Scrcpy client.
104
+ // https://github.com/Genymobile/scrcpy/issues/3679
105
+ let frame;
106
+ while ((frame = this.#nextFrame)) {
107
+ this.#nextFrame = undefined;
108
+ if (await this.#readableController.enqueue(frame)) {
109
+ // The consumer is responsible for closing `frame`
110
+ this.#counter.increaseFramesRendered();
111
+ }
112
+ else {
113
+ // `enqueue` returning `false` means the consumer has called `readable.cancel()`,
114
+ // before consuming the `frame`. So close it here.
115
+ frame.close();
116
+ // Continue looping to close all `#nextFrame`s
117
+ // In the mean time the `writable` is erroring out its source
118
+ // so no more frames will arrive
119
+ }
120
+ }
121
+ this.#drawTask = undefined;
122
+ }
123
+ #tryStartDrawing() {
124
+ if (!this.#drawTask) {
125
+ this.#drawTask = this.#draw();
126
+ }
127
+ }
128
+ dispose() {
129
+ this.#captureFrame?.close();
130
+ this.#captureFrame = undefined;
131
+ this.#nextFrame?.close();
132
+ this.#nextFrame = undefined;
133
+ this.#counter.dispose();
134
+ tryClose(this.#readableController);
135
+ // Throw an error similar to native TransformStream
136
+ this.#writableController.error(new TypeError("The transform stream has been terminated"));
137
+ }
138
+ }
139
+ //# sourceMappingURL=flow-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-control.js","sourceRoot":"","sources":["../../../src/video/render/flow-control.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  export * from "./bitmap.js";
2
2
  export * from "./canvas.js";
3
+ export * from "./auto-canvas.js";
4
+ export * from "./flow-control.js";
3
5
  export * from "./insertable-stream.js";
4
6
  export * from "./type.js";
5
7
  export * from "./webgl.js";
@@ -1 +1 @@
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
+ {"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,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
@@ -1,6 +1,8 @@
1
1
  // cspell: ignore insertable
2
2
  export * from "./bitmap.js";
3
3
  export * from "./canvas.js";
4
+ export * from "./auto-canvas.js";
5
+ export * from "./flow-control.js";
4
6
  export * from "./insertable-stream.js";
5
7
  export * from "./type.js";
6
8
  export * from "./webgl.js";
@@ -1 +1 @@
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"}
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,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
@@ -1,10 +1,22 @@
1
+ import type { WritableStream } from "@yume-chan/stream-extra";
1
2
  import type { VideoFrameRenderer } from "./type.js";
2
3
  export declare class InsertableStreamVideoFrameRenderer implements VideoFrameRenderer {
3
4
  #private;
4
5
  static get isSupported(): boolean;
6
+ get type(): "hardware";
5
7
  get element(): HTMLVideoElement;
6
- constructor(element?: HTMLVideoElement);
7
- setSize(width: number, height: number): void;
8
- draw(frame: VideoFrame): Promise<void>;
8
+ get options(): InsertableStreamVideoFrameRenderer.Options | undefined;
9
+ get writable(): WritableStream<VideoFrame>;
10
+ get stream(): MediaStream;
11
+ constructor(element?: HTMLVideoElement, options?: InsertableStreamVideoFrameRenderer.Options);
12
+ dispose(): undefined;
13
+ }
14
+ export declare namespace InsertableStreamVideoFrameRenderer {
15
+ interface Options {
16
+ /**
17
+ * Whether to update the size of the video element when the size of the video frame changes.
18
+ */
19
+ updateSize?: boolean;
20
+ }
9
21
  }
10
22
  //# sourceMappingURL=insertable-stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"insertable-stream.d.ts","sourceRoot":"","sources":["../../../src/video/render/insertable-stream.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAQpD,qBAAa,kCAAmC,YAAW,kBAAkB;;IACzE,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"}
1
+ {"version":3,"file":"insertable-stream.d.ts","sourceRoot":"","sources":["../../../src/video/render/insertable-stream.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAQpD,qBAAa,kCAAmC,YAAW,kBAAkB;;IACzE,MAAM,KAAK,WAAW,YAErB;IAED,IAAI,IAAI,IACG,UAAU,CACpB;IAGD,IAAI,OAAO,qBAEV;IAGD,IAAI,OAAO,2DAEV;IAGD,IAAI,QAAQ,+BAEX;IAGD,IAAI,MAAM,gBAET;gBAKG,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,kCAAkC,CAAC,OAAO;IAuCxD,OAAO,IAAI,SAAS;CAMvB;AAED,yBAAiB,kCAAkC,CAAC;IAChD,UAAiB,OAAO;QACpB;;WAEG;QACH,UAAU,CAAC,EAAE,OAAO,CAAC;KACxB;CACJ"}
@@ -3,14 +3,27 @@ export class InsertableStreamVideoFrameRenderer {
3
3
  static get isSupported() {
4
4
  return typeof MediaStreamTrackGenerator !== "undefined";
5
5
  }
6
+ get type() {
7
+ return "hardware";
8
+ }
6
9
  #element;
7
10
  get element() {
8
11
  return this.#element;
9
12
  }
13
+ #options;
14
+ get options() {
15
+ return this.#options;
16
+ }
10
17
  #generator;
11
- #writer;
18
+ get writable() {
19
+ return this.#generator.writable;
20
+ }
12
21
  #stream;
13
- constructor(element) {
22
+ get stream() {
23
+ return this.#stream;
24
+ }
25
+ #abortController = new AbortController();
26
+ constructor(element, options) {
14
27
  if (element) {
15
28
  this.#element = element;
16
29
  }
@@ -22,24 +35,29 @@ export class InsertableStreamVideoFrameRenderer {
22
35
  }
23
36
  this.#element.muted = true;
24
37
  this.#element.autoplay = true;
38
+ this.#element.playsInline = true;
25
39
  this.#element.disablePictureInPicture = true;
26
40
  this.#element.disableRemotePlayback = true;
41
+ this.#options = options;
42
+ if (options?.updateSize) {
43
+ this.#element.addEventListener("resize", () => {
44
+ this.#element.width = this.#element.videoWidth;
45
+ this.#element.height = this.#element.videoHeight;
46
+ }, { signal: this.#abortController.signal });
47
+ }
27
48
  // The spec replaced `MediaStreamTrackGenerator` with `VideoTrackGenerator`.
28
49
  // But Chrome has not implemented it yet.
29
50
  // https://issues.chromium.org/issues/40058895
30
51
  this.#generator = new MediaStreamTrackGenerator({ kind: "video" });
31
- this.#writer = this.#generator.writable.getWriter();
52
+ this.#generator.contentHint = "motion";
32
53
  this.#stream = new MediaStream([this.#generator]);
33
54
  this.#element.srcObject = this.#stream;
34
55
  }
35
- setSize(width, height) {
36
- if (this.#element.width !== width || this.#element.height !== height) {
37
- this.#element.width = width;
38
- this.#element.height = height;
39
- }
40
- }
41
- async draw(frame) {
42
- await this.#writer.write(frame);
56
+ dispose() {
57
+ this.#abortController.abort();
58
+ this.#generator.stop();
59
+ this.#stream.removeTrack(this.#generator);
60
+ this.#element.srcObject = null;
43
61
  }
44
62
  }
45
63
  //# sourceMappingURL=insertable-stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"insertable-stream.js","sourceRoot":"","sources":["../../../src/video/render/insertable-stream.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAU5B,MAAM,OAAO,kCAAkC;IAC3C,MAAM,KAAK,WAAW;QAClB,OAAO,OAAO,yBAAyB,KAAK,WAAW,CAAC;IAC5D,CAAC;IAED,QAAQ,CAAmB;IAC3B,IAAI,OAAO;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED,UAAU,CAA4B;IACtC,OAAO,CAA0C;IACjD,OAAO,CAAc;IAErB,YAAY,OAA0B;QAClC,IAAI,OAAO,EAAE,CAAC;YACV,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC5B,CAAC;aAAM,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACzC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACJ,MAAM,IAAI,KAAK,CACX,mEAAmE,CACtE,CAAC;QACN,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,uBAAuB,GAAG,IAAI,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,qBAAqB,GAAG,IAAI,CAAC;QAE3C,4EAA4E;QAC5E,yCAAyC;QACzC,8CAA8C;QAC9C,IAAI,CAAC,UAAU,GAAG,IAAI,yBAAyB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;QAEpD,IAAI,CAAC,OAAO,GAAG,IAAI,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC;IAC3C,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,MAAc;QACjC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACnE,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC;YAC5B,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC;QAClC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAiB;QACxB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;CACJ"}
1
+ {"version":3,"file":"insertable-stream.js","sourceRoot":"","sources":["../../../src/video/render/insertable-stream.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAY5B,MAAM,OAAO,kCAAkC;IAC3C,MAAM,KAAK,WAAW;QAClB,OAAO,OAAO,yBAAyB,KAAK,WAAW,CAAC;IAC5D,CAAC;IAED,IAAI,IAAI;QACJ,OAAO,UAAmB,CAAC;IAC/B,CAAC;IAED,QAAQ,CAAmB;IAC3B,IAAI,OAAO;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED,QAAQ,CAAyD;IACjE,IAAI,OAAO;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED,UAAU,CAA4B;IACtC,IAAI,QAAQ;QACR,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;IACpC,CAAC;IAED,OAAO,CAAc;IACrB,IAAI,MAAM;QACN,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,gBAAgB,GAAG,IAAI,eAAe,EAAE,CAAC;IAEzC,YACI,OAA0B,EAC1B,OAAoD;QAEpD,IAAI,OAAO,EAAE,CAAC;YACV,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC5B,CAAC;aAAM,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACzC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACJ,MAAM,IAAI,KAAK,CACX,mEAAmE,CACtE,CAAC;QACN,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,GAAG,IAAI,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,qBAAqB,GAAG,IAAI,CAAC;QAE3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;YACtB,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAC1B,QAAQ,EACR,GAAG,EAAE;gBACD,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAC/C,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;YACrD,CAAC,EACD,EAAE,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAC3C,CAAC;QACN,CAAC;QAED,4EAA4E;QAC5E,yCAAyC;QACzC,8CAA8C;QAC9C,IAAI,CAAC,UAAU,GAAG,IAAI,yBAAyB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,UAAU,CAAC,WAAW,GAAG,QAAQ,CAAC;QAEvC,IAAI,CAAC,OAAO,GAAG,IAAI,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC;IAC3C,CAAC;IAED,OAAO;QACH,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC;IACnC,CAAC;CACJ"}
@@ -0,0 +1,31 @@
1
+ import type { MaybePromiseLike } from "@yume-chan/async";
2
+ /**
3
+ * Manages drawing and redrawing of video frames.
4
+ */
5
+ export declare class RedrawController {
6
+ #private;
7
+ get lastFrame(): VideoFrame | undefined;
8
+ constructor(draw: (frame: VideoFrame) => MaybePromiseLike<undefined>);
9
+ /**
10
+ * Draws a new frame.
11
+ *
12
+ * If a redraw is in progress, it waits for the redraw to finish before drawing the new frame.
13
+ *
14
+ * If a redraw is in progress and another one is in queue,
15
+ * it cancels the queued redraw and draws the new frame instead.
16
+ *
17
+ * @param frame A `VideoFrame` to draw. The frame will be closed after drawing.
18
+ */
19
+ draw(frame: VideoFrame): Promise<undefined>;
20
+ /**
21
+ * Redraws the last drawn frame.
22
+ *
23
+ * If a draw or redraw is in progress, it waits for them to finish before redrawing.
24
+ *
25
+ * If a redraw is in progress and another one is in queue,
26
+ * it cancels the queued redraw and redraws the latest frame instead.
27
+ */
28
+ redraw(): Promise<undefined>;
29
+ dispose(): void;
30
+ }
31
+ //# sourceMappingURL=redraw.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redraw.d.ts","sourceRoot":"","sources":["../../../src/video/render/redraw.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGzD;;GAEG;AACH,qBAAa,gBAAgB;;IAOzB,IAAI,SAAS,2BAEZ;gBAEW,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,gBAAgB,CAAC,SAAS,CAAC;IAIpE;;;;;;;;;OASG;IACH,IAAI,CAAC,KAAK,EAAE,UAAU;IAgBtB;;;;;;;OAOG;IACG,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC;IAwBlC,OAAO;CAQV"}