@yume-chan/scrcpy-decoder-webcodecs 2.5.0 → 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 +28 -70
  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 +13 -25
  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 +15 -31
  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 -31
  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 +40 -102
  85. package/src/video/codec/h264.ts +17 -41
  86. package/src/video/codec/h265.ts +18 -49
  87. package/src/video/codec/h26x.ts +41 -36
  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,9 +1,20 @@
1
1
  import { CanvasVideoFrameRenderer } from "./canvas.js";
2
- export declare class WebGLVideoFrameRenderer extends CanvasVideoFrameRenderer {
2
+ export declare class WebGLVideoFrameRenderer extends CanvasVideoFrameRenderer<WebGLVideoFrameRenderer.Options> {
3
3
  #private;
4
- static vertexShaderSource: string;
5
- static fragmentShaderSource: string;
4
+ static VertexShader: string;
5
+ static FragmentShader: string;
6
+ /**
7
+ * A single oversized triangle that covers the entire canvas.
8
+ */
9
+ static Vertices: Float32Array<ArrayBuffer>;
6
10
  static get isSupported(): boolean;
11
+ get type(): "hardware";
12
+ /**
13
+ * Fired when the WebGL context is lost and cannot be restored.
14
+ *
15
+ * The current renderer will be automatically disposed.
16
+ */
17
+ get onContextLost(): import("@yume-chan/event").Event<void>;
7
18
  /**
8
19
  * Create a new WebGL frame renderer.
9
20
  * @param canvas The canvas to render frames to.
@@ -11,7 +22,29 @@ export declare class WebGLVideoFrameRenderer extends CanvasVideoFrameRenderer {
11
22
  * Whether to allow capturing the canvas content using APIs like `readPixels` and `toDataURL`.
12
23
  * Enable this option may reduce performance.
13
24
  */
14
- constructor(canvas?: HTMLCanvasElement | OffscreenCanvas, enableCapture?: boolean);
15
- draw(frame: VideoFrame): Promise<void>;
25
+ constructor(options?: WebGLVideoFrameRenderer.Options);
26
+ snapshot(options?: ImageEncodeOptions): Promise<Blob | undefined>;
27
+ dispose(): undefined;
28
+ }
29
+ export declare namespace WebGLVideoFrameRenderer {
30
+ interface Options extends CanvasVideoFrameRenderer.Options {
31
+ /**
32
+ * Whether to allow capturing the canvas content using APIs
33
+ * like `readPixels` and `toDataURL`.
34
+ *
35
+ * Enabling this option may reduce performance.
36
+ */
37
+ enableCapture?: boolean;
38
+ /**
39
+ * The timeout in milliseconds to wait for context restoration
40
+ * before firing `onContextLost`.
41
+ *
42
+ * When set to 0, also disables automatic context restoration,
43
+ * `onContextLost` will be fired immediately when the context is lost.
44
+ *
45
+ * Default is 3000.
46
+ */
47
+ contextRestoreTimeout?: number;
48
+ }
16
49
  }
17
50
  //# sourceMappingURL=webgl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webgl.d.ts","sourceRoot":"","sources":["../../../src/video/render/webgl.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAwBvD,qBAAa,uBAAwB,SAAQ,wBAAwB;;IACjE,MAAM,CAAC,kBAAkB,SAW3B;IAEE,MAAM,CAAC,oBAAoB,SAQ7B;IAEE,MAAM,KAAK,WAAW,YAGrB;IAID;;;;;;OAMG;gBAEC,MAAM,CAAC,EAAE,iBAAiB,GAAG,eAAe,EAC5C,aAAa,CAAC,EAAE,OAAO;IA6D3B,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAgBzC"}
1
+ {"version":3,"file":"webgl.d.ts","sourceRoot":"","sources":["../../../src/video/render/webgl.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAkDvD,qBAAa,uBAAwB,SAAQ,wBAAwB,CAAC,uBAAuB,CAAC,OAAO,CAAC;;IAClG,MAAM,CAAC,YAAY,SAarB;IAEE,MAAM,CAAC,cAAc,SAwEvB;IAEE;;OAEG;IACH,MAAM,CAAC,QAAQ,4BAAwD;IAEvE,MAAM,KAAK,WAAW,YAMrB;IAED,IAAa,IAAI,IACN,UAAU,CACpB;IAID;;;;OAIG;IACH,IAAI,aAAa,2CAEhB;IAWD;;;;;;OAMG;gBACS,OAAO,CAAC,EAAE,uBAAuB,CAAC,OAAO;IAuItC,QAAQ,CACnB,OAAO,CAAC,EAAE,kBAAkB,GAC7B,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC;IAOnB,OAAO,IAAI,SAAS;CAkBhC;AAED,yBAAiB,uBAAuB,CAAC;IACrC,UAAiB,OAAQ,SAAQ,wBAAwB,CAAC,OAAO;QAC7D;;;;;WAKG;QACH,aAAa,CAAC,EAAE,OAAO,CAAC;QAExB;;;;;;;;WAQG;QACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;KAClC;CACJ"}
@@ -1,46 +1,161 @@
1
- import { createCanvas } from "@yume-chan/scrcpy-decoder-tinyh264";
1
+ // cspell: ignore highp
2
+ // cspell: ignore mediump
3
+ import { StickyEventEmitter } from "@yume-chan/event";
4
+ import { glCreateContext, glIsSupported, glLoseContext, } from "@yume-chan/scrcpy-decoder-shared";
2
5
  import { CanvasVideoFrameRenderer } from "./canvas.js";
3
- const Resolved = Promise.resolve();
4
- function createContext(canvas, enableCapture) {
5
- const attributes = {
6
- // Low-power GPU should be enough for video rendering.
7
- powerPreference: "low-power",
8
- alpha: false,
9
- // Disallow software rendering.
10
- // Other rendering methods are faster than software-based WebGL.
11
- failIfMajorPerformanceCaveat: true,
12
- preserveDrawingBuffer: !!enableCapture,
13
- };
14
- return (canvas.getContext("webgl2", attributes) ||
15
- canvas.getContext("webgl", attributes));
6
+ function createShader(gl, type, source) {
7
+ const shader = gl.createShader(type);
8
+ gl.shaderSource(shader, source);
9
+ gl.compileShader(shader);
10
+ return shader;
11
+ }
12
+ function createProgram(gl, vertexShaderSource, fragmentShaderSource) {
13
+ const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
14
+ const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
15
+ const program = gl.createProgram();
16
+ gl.attachShader(program, vertexShader);
17
+ gl.attachShader(program, fragmentShader);
18
+ gl.linkProgram(program);
19
+ try {
20
+ if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
21
+ return program;
22
+ }
23
+ // Don't check shader compile status unless linking fails
24
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#dont_check_shader_compile_status_unless_linking_fails
25
+ if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
26
+ throw new Error(gl.getShaderInfoLog(vertexShader));
27
+ }
28
+ if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
29
+ throw new Error(gl.getShaderInfoLog(fragmentShader));
30
+ }
31
+ throw new Error(gl.getProgramInfoLog(program));
32
+ }
33
+ finally {
34
+ // Delete objects eagerly
35
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#delete_objects_eagerly
36
+ gl.deleteShader(vertexShader);
37
+ gl.deleteShader(fragmentShader);
38
+ }
16
39
  }
17
40
  export class WebGLVideoFrameRenderer extends CanvasVideoFrameRenderer {
18
- static vertexShaderSource = `
41
+ static VertexShader = `
19
42
  attribute vec2 xy;
20
43
 
21
44
  varying highp vec2 uv;
22
45
 
23
46
  void main(void) {
24
47
  gl_Position = vec4(xy, 0.0, 1.0);
48
+
25
49
  // Map vertex coordinates (-1 to +1) to UV coordinates (0 to 1).
50
+ uv = xy * 0.5 + 0.5;
26
51
  // UV coordinates are Y-flipped relative to vertex coordinates.
27
- uv = vec2((1.0 + xy.x) / 2.0, (1.0 - xy.y) / 2.0);
52
+ uv.y = 1.0 - uv.y;
28
53
  }
29
54
  `;
30
- static fragmentShaderSource = `
31
- varying highp vec2 uv;
55
+ static FragmentShader = `
56
+ precision mediump float;
32
57
 
33
- uniform sampler2D texture;
58
+ uniform sampler2D source;
59
+ uniform vec2 texelSize;
60
+ uniform float zoom;
34
61
 
35
- void main(void) {
36
- gl_FragColor = texture2D(texture, uv);
62
+ varying vec2 uv;
63
+
64
+ vec4 tent4(vec2 uv) {
65
+ vec2 dx = vec2(texelSize.x, 0.0);
66
+ vec2 dy = vec2(0.0, texelSize.y);
67
+
68
+ vec4 c0 = texture2D(source, uv);
69
+ vec4 c1 = texture2D(source, uv + dx);
70
+ vec4 c2 = texture2D(source, uv + dy);
71
+ vec4 c3 = texture2D(source, uv + dx + dy);
72
+
73
+ return 0.25 * (c0 + c1 + c2 + c3);
74
+ }
75
+
76
+ float mnWeight(float x) {
77
+ x = abs(x);
78
+ float x2 = x * x;
79
+ float x3 = x2 * x;
80
+
81
+ if (x < 1.0) {
82
+ return (1.0/6.0) * ((12.0 - 9.0 * (1.0/3.0) - 6.0 * (1.0/3.0)) * x3 +
83
+ (-18.0 + 12.0 * (1.0/3.0) + 6.0 * (1.0/3.0)) * x2 +
84
+ (6.0 - 2.0 * (1.0/3.0)));
85
+ } else if (x < 2.0) {
86
+ return (1.0/6.0) * ((- (1.0/3.0) - 6.0 * (1.0/3.0)) * x3 +
87
+ ((6.0 * (1.0/3.0) + 30.0 * (1.0/3.0)) * x2 +
88
+ (-12.0 * (1.0/3.0) - 48.0 * (1.0/3.0)) * x +
89
+ (8.0 * (1.0/3.0) + 24.0 * (1.0/3.0))));
90
+ }
91
+ return 0.0;
92
+ }
93
+
94
+ vec4 bicubicMN(vec2 uv, vec2 texelSize) {
95
+ vec2 texCoord = uv / texelSize;
96
+ vec2 base = floor(texCoord - 0.5);
97
+ vec2 f = texCoord - base - 0.5;
98
+
99
+ vec4 sum = vec4(0.0);
100
+ float total = 0.0;
101
+
102
+ for (int j = -1; j <= 2; j++) {
103
+ float wy = mnWeight(float(j) - f.y);
104
+ for (int i = -1; i <= 2; i++) {
105
+ float wx = mnWeight(float(i) - f.x);
106
+ float w = wx * wy;
107
+
108
+ vec2 coord = (base + vec2(float(i), float(j)) + 0.5) * texelSize;
109
+ sum += texture2D(source, coord) * w;
110
+ total += w;
111
+ }
112
+ }
113
+ return sum / total;
114
+ }
115
+
116
+ void main() {
117
+ if (zoom > 0.95) {
118
+ gl_FragColor = texture2D(source, uv);
119
+ }
120
+ else if (zoom > 0.5) {
121
+ gl_FragColor = bicubicMN(uv, texelSize);
122
+ }
123
+ else {
124
+ gl_FragColor = tent4(uv);
125
+ }
37
126
  }
38
127
  `;
128
+ /**
129
+ * A single oversized triangle that covers the entire canvas.
130
+ */
131
+ static Vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);
39
132
  static get isSupported() {
40
- const canvas = createCanvas();
41
- return !!createContext(canvas);
133
+ return glIsSupported({
134
+ // Disallow software rendering.
135
+ // `ImageBitmapRenderingContext` is faster than software-based WebGL.
136
+ failIfMajorPerformanceCaveat: true,
137
+ });
138
+ }
139
+ get type() {
140
+ return "hardware";
141
+ }
142
+ #contextLostTimer;
143
+ #onContextLost = new StickyEventEmitter();
144
+ /**
145
+ * Fired when the WebGL context is lost and cannot be restored.
146
+ *
147
+ * The current renderer will be automatically disposed.
148
+ */
149
+ get onContextLost() {
150
+ return this.#onContextLost.event;
42
151
  }
43
152
  #context;
153
+ #program;
154
+ #vertexBuffer;
155
+ #texture;
156
+ #texelSizeLocation;
157
+ #zoomLocation;
158
+ #abortController = new AbortController();
44
159
  /**
45
160
  * Create a new WebGL frame renderer.
46
161
  * @param canvas The canvas to render frames to.
@@ -48,54 +163,108 @@ export class WebGLVideoFrameRenderer extends CanvasVideoFrameRenderer {
48
163
  * Whether to allow capturing the canvas content using APIs like `readPixels` and `toDataURL`.
49
164
  * Enable this option may reduce performance.
50
165
  */
51
- constructor(canvas, enableCapture) {
52
- super(canvas);
53
- const gl = createContext(this.canvas, enableCapture);
166
+ constructor(options) {
167
+ super((frame) => {
168
+ const gl = this.#context;
169
+ if (gl.isContextLost()) {
170
+ // The base class will close the frame.
171
+ return;
172
+ }
173
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame);
174
+ gl.uniform2f(this.#texelSizeLocation, 1.0 / frame.codedWidth, 1.0 / frame.codedHeight);
175
+ gl.uniform1f(this.#zoomLocation, this.canvas.width / frame.codedWidth);
176
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
177
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
178
+ gl.flush();
179
+ }, options);
180
+ const gl = glCreateContext(this.canvas, {
181
+ // Low-power GPU should be enough for video rendering.
182
+ // Note that `OffscreenCanvas` created in Web Workers can only use `low-power` anyway.
183
+ powerPreference: "low-power",
184
+ // Avoid alpha:false, which can be expensive
185
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#avoid_alphafalse_which_can_be_expensive
186
+ alpha: true,
187
+ // Disallow software rendering.
188
+ // `ImageBitmapRenderingContext` is faster than software-based WebGL.
189
+ failIfMajorPerformanceCaveat: true,
190
+ preserveDrawingBuffer: !!this.options?.enableCapture,
191
+ // Enable desynchronized mode when not capturing to reduce latency.
192
+ desynchronized: !this.options?.enableCapture,
193
+ antialias: false,
194
+ depth: false,
195
+ premultipliedAlpha: true,
196
+ stencil: false,
197
+ });
54
198
  if (!gl) {
55
- throw new Error("WebGL not supported");
199
+ throw new Error("WebGL not supported, check `isSupported` first");
56
200
  }
57
201
  this.#context = gl;
58
- const vertexShader = gl.createShader(gl.VERTEX_SHADER);
59
- gl.shaderSource(vertexShader, WebGLVideoFrameRenderer.vertexShaderSource);
60
- gl.compileShader(vertexShader);
61
- if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
62
- throw new Error(gl.getShaderInfoLog(vertexShader));
63
- }
64
- const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
65
- gl.shaderSource(fragmentShader, WebGLVideoFrameRenderer.fragmentShaderSource);
66
- gl.compileShader(fragmentShader);
67
- if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
68
- throw new Error(gl.getShaderInfoLog(fragmentShader));
69
- }
70
- const shaderProgram = gl.createProgram();
71
- gl.attachShader(shaderProgram, vertexShader);
72
- gl.attachShader(shaderProgram, fragmentShader);
73
- gl.linkProgram(shaderProgram);
74
- if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
75
- throw new Error(gl.getProgramInfoLog(shaderProgram));
76
- }
77
- gl.useProgram(shaderProgram);
202
+ this.#initialize();
203
+ this.canvas.addEventListener("webglcontextlost", (e) => {
204
+ if (options?.contextRestoreTimeout === 0) {
205
+ this.#onContextLost.fire();
206
+ this.dispose();
207
+ return;
208
+ }
209
+ // Notify WebGL we want to handle context restoration
210
+ e.preventDefault();
211
+ this.#contextLostTimer = globalThis.setTimeout(() => {
212
+ this.#onContextLost.fire();
213
+ this.dispose();
214
+ }, options?.contextRestoreTimeout ?? 3000);
215
+ }, { signal: this.#abortController.signal });
216
+ this.canvas.addEventListener("webglcontextrestored", () => {
217
+ if (this.#onContextLost.hasValue) {
218
+ // Don't restore context if `onContextLost` has been fired,
219
+ // which means the caller will handle the context loss.
220
+ return;
221
+ }
222
+ globalThis.clearTimeout(this.#contextLostTimer);
223
+ this.#contextLostTimer = undefined;
224
+ this.#initialize();
225
+ void this.redraw();
226
+ }, { signal: this.#abortController.signal });
227
+ }
228
+ #initialize() {
229
+ const gl = this.#context;
230
+ this.#program = createProgram(gl, WebGLVideoFrameRenderer.VertexShader, WebGLVideoFrameRenderer.FragmentShader);
231
+ gl.useProgram(this.#program);
78
232
  // Vertex coordinates, clockwise from bottom-left.
79
- const vertexBuffer = gl.createBuffer();
80
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
81
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1.0, -1.0, -1.0, +1.0, +1.0, +1.0, +1.0, -1.0]), gl.STATIC_DRAW);
82
- const xyLocation = gl.getAttribLocation(shaderProgram, "xy");
233
+ this.#vertexBuffer = gl.createBuffer();
234
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.#vertexBuffer);
235
+ gl.bufferData(gl.ARRAY_BUFFER, WebGLVideoFrameRenderer.Vertices, gl.STATIC_DRAW);
236
+ const xyLocation = gl.getAttribLocation(this.#program, "xy");
83
237
  gl.vertexAttribPointer(xyLocation, 2, gl.FLOAT, false, 0, 0);
84
238
  gl.enableVertexAttribArray(xyLocation);
239
+ this.#texelSizeLocation = gl.getUniformLocation(this.#program, "texelSize");
240
+ this.#zoomLocation = gl.getUniformLocation(this.#program, "zoom");
85
241
  // Create one texture to upload frames to.
86
- const texture = gl.createTexture();
87
- gl.bindTexture(gl.TEXTURE_2D, texture);
242
+ this.#texture = gl.createTexture();
243
+ gl.bindTexture(gl.TEXTURE_2D, this.#texture);
88
244
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
89
245
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
90
246
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
91
247
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
92
248
  }
93
- draw(frame) {
94
- const gl = this.#context;
95
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame);
96
- gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
97
- gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
98
- return Resolved;
249
+ async snapshot(options) {
250
+ if (!this.options?.enableCapture) {
251
+ return undefined;
252
+ }
253
+ return super.snapshot(options);
254
+ }
255
+ dispose() {
256
+ globalThis.clearTimeout(this.#contextLostTimer);
257
+ this.#onContextLost.dispose();
258
+ this.#abortController.abort();
259
+ this.#context.deleteBuffer(this.#vertexBuffer);
260
+ this.#context.deleteTexture(this.#texture);
261
+ this.#context.deleteProgram(this.#program);
262
+ if (!this.#context.isContextLost()) {
263
+ // Lose contexts eagerly
264
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#lose_contexts_eagerly
265
+ glLoseContext(this.#context);
266
+ }
267
+ super.dispose();
99
268
  }
100
269
  }
101
270
  //# sourceMappingURL=webgl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"webgl.js","sourceRoot":"","sources":["../../../src/video/render/webgl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webgl.js","sourceRoot":"","sources":["../../../src/video/render/webgl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from "./snapshot.js";
2
+ export * from "./timestamp.js";
3
+ export * from "./video-decoder-stream.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/video/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./snapshot.js";
2
+ export * from "./timestamp.js";
3
+ export * from "./video-decoder-stream.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/video/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function canvasToBlob(canvas: HTMLCanvasElement | OffscreenCanvas, options?: ImageEncodeOptions): Promise<Blob>;
2
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../../src/video/utils/snapshot.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CACxB,MAAM,EAAE,iBAAiB,GAAG,eAAe,EAC3C,OAAO,CAAC,EAAE,kBAAkB,iBAmB/B"}
@@ -0,0 +1,18 @@
1
+ export function canvasToBlob(canvas, options) {
2
+ if (canvas instanceof OffscreenCanvas) {
3
+ return canvas.convertToBlob(options);
4
+ }
5
+ else {
6
+ return new Promise((resolve, reject) => {
7
+ canvas.toBlob((blob) => {
8
+ if (!blob) {
9
+ reject(new Error("Failed to convert canvas to blob"));
10
+ }
11
+ else {
12
+ resolve(blob);
13
+ }
14
+ }, options?.type, options?.quality);
15
+ });
16
+ }
17
+ }
18
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/video/utils/snapshot.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CACxB,MAA2C,EAC3C,OAA4B;IAE5B,IAAI,MAAM,YAAY,eAAe,EAAE,CAAC;QACpC,OAAO,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACJ,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACzC,MAAM,CAAC,MAAM,CACT,CAAC,IAAI,EAAE,EAAE;gBACL,IAAI,CAAC,IAAI,EAAE,CAAC;oBACR,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;gBAC1D,CAAC;qBAAM,CAAC;oBACJ,OAAO,CAAC,IAAI,CAAC,CAAC;gBAClB,CAAC;YACL,CAAC,EACD,OAAO,EAAE,IAAI,EACb,OAAO,EAAE,OAAO,CACnB,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC;AACL,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { ScrcpyVideoDecoderPauseController } from "@yume-chan/scrcpy-decoder-shared";
2
+ import { TransformStream } from "@yume-chan/stream-extra";
3
+ import type { CodecTransformStream } from "../codec/type.js";
4
+ /**
5
+ * Gets current time.
6
+ *
7
+ * The returned value is guaranteed to be monotonically increasing.
8
+ */
9
+ export declare function increasingNow(): number;
10
+ export declare class TimestampTransforms {
11
+ #private;
12
+ get addTimestamp(): TransformStream<ScrcpyVideoDecoderPauseController.Output, CodecTransformStream.Input>;
13
+ /**
14
+ * Gets the total time spent processing and decoding frames in milliseconds.
15
+ */
16
+ get totalDecodeTime(): number;
17
+ get consumeTimestamp(): TransformStream<VideoFrame, VideoFrame>;
18
+ }
19
+ //# sourceMappingURL=timestamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timestamp.d.ts","sourceRoot":"","sources":["../../../src/video/utils/timestamp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AA0B7D;;;;GAIG;AACH,wBAAgB,aAAa,WAO5B;AAED,qBAAa,mBAAmB;;IA8B5B,IAAI,YAAY,0FAEf;IAQD;;OAEG;IACH,IAAI,eAAe,WAElB;IAgBD,IAAI,gBAAgB,4CAEnB;CACJ"}
@@ -0,0 +1,87 @@
1
+ import { TransformStream } from "@yume-chan/stream-extra";
2
+ const view = new DataView(new ArrayBuffer(8));
3
+ /**
4
+ * Gets the next presentable double-precision floating point value greater than x
5
+ * @param x A number. The caller must ensure that x is not NaN or Infinity
6
+ * @returns The next presentable double-precision floating point value
7
+ */
8
+ function nextUp(x) {
9
+ if (x === 0)
10
+ return Number.MIN_VALUE;
11
+ // Write the number as a float64
12
+ view.setFloat64(0, x, false);
13
+ let bits = view.getBigUint64(0, false);
14
+ // If x > 0, increment bits; if x < 0, decrement bits
15
+ bits += x > 0 ? 1n : -1n;
16
+ view.setBigUint64(0, bits, false);
17
+ return view.getFloat64(0, false);
18
+ }
19
+ let prevValue = 0;
20
+ /**
21
+ * Gets current time.
22
+ *
23
+ * The returned value is guaranteed to be monotonically increasing.
24
+ */
25
+ export function increasingNow() {
26
+ let now = performance.now();
27
+ if (now <= prevValue) {
28
+ now = nextUp(prevValue);
29
+ }
30
+ prevValue = now;
31
+ return now;
32
+ }
33
+ export class TimestampTransforms {
34
+ /**
35
+ * Timestamp of the last frame to be skipped by pause controller.
36
+ */
37
+ #skipFramesUntil = -1;
38
+ #addTimestamp = new TransformStream({
39
+ transform: (packet, controller) => {
40
+ if (packet.type === "configuration") {
41
+ controller.enqueue(packet);
42
+ return;
43
+ }
44
+ // Use `timestamp` to convey `skipRendering` to later step
45
+ // and track total decoding time
46
+ const timestamp = increasingNow();
47
+ if (packet.skipRendering) {
48
+ this.#skipFramesUntil = timestamp;
49
+ }
50
+ controller.enqueue({
51
+ ...packet,
52
+ timestamp,
53
+ });
54
+ },
55
+ });
56
+ get addTimestamp() {
57
+ return this.#addTimestamp;
58
+ }
59
+ // This is not in `VideoDecoderStream` because
60
+ // this time includes all pre-processing time,
61
+ // and requires `EncodedVideoChunk.timestamp` to contain
62
+ // local time of when the frame is received,
63
+ // which is set by this class.
64
+ #totalDecodeTime = 0;
65
+ /**
66
+ * Gets the total time spent processing and decoding frames in milliseconds.
67
+ */
68
+ get totalDecodeTime() {
69
+ return this.#totalDecodeTime;
70
+ }
71
+ #consumeTimestamp = new TransformStream({
72
+ transform: (frame, controller) => {
73
+ // `frame.timestamp` is the same `EncodedVideoChunk.timestamp` set above
74
+ this.#totalDecodeTime += performance.now() - frame.timestamp;
75
+ // Don't count these frames as skipped rendering
76
+ if (frame.timestamp <= this.#skipFramesUntil) {
77
+ frame.close();
78
+ return;
79
+ }
80
+ controller.enqueue(frame);
81
+ },
82
+ });
83
+ get consumeTimestamp() {
84
+ return this.#consumeTimestamp;
85
+ }
86
+ }
87
+ //# sourceMappingURL=timestamp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timestamp.js","sourceRoot":"","sources":["../../../src/video/utils/timestamp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI1D,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9C;;;;GAIG;AACH,SAAS,MAAM,CAAC,CAAS;IACrB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,SAAS,CAAC;IAErC,gCAAgC;IAChC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IAE7B,IAAI,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAEvC,qDAAqD;IACrD,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzB,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACrC,CAAC;AAED,IAAI,SAAS,GAAG,CAAC,CAAC;AAElB;;;;GAIG;AACH,MAAM,UAAU,aAAa;IACzB,IAAI,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC5B,IAAI,GAAG,IAAI,SAAS,EAAE,CAAC;QACnB,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC;IACD,SAAS,GAAG,GAAG,CAAC;IAChB,OAAO,GAAG,CAAC;AACf,CAAC;AAED,MAAM,OAAO,mBAAmB;IAC5B;;OAEG;IACH,gBAAgB,GAAG,CAAC,CAAC,CAAC;IAEtB,aAAa,GAAG,IAAI,eAAe,CAGjC;QACE,SAAS,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE;YAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;gBAClC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC3B,OAAO;YACX,CAAC;YAED,0DAA0D;YAC1D,gCAAgC;YAChC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;YAElC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;gBACvB,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;YACtC,CAAC;YAED,UAAU,CAAC,OAAO,CAAC;gBACf,GAAG,MAAM;gBACT,SAAS;aACZ,CAAC,CAAC;QACP,CAAC;KACJ,CAAC,CAAC;IACH,IAAI,YAAY;QACZ,OAAO,IAAI,CAAC,aAAa,CAAC;IAC9B,CAAC;IAED,8CAA8C;IAC9C,8CAA8C;IAC9C,wDAAwD;IACxD,4CAA4C;IAC5C,8BAA8B;IAC9B,gBAAgB,GAAG,CAAC,CAAC;IACrB;;OAEG;IACH,IAAI,eAAe;QACf,OAAO,IAAI,CAAC,gBAAgB,CAAC;IACjC,CAAC;IAED,iBAAiB,GAAG,IAAI,eAAe,CAAyB;QAC5D,SAAS,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;YAC7B,wEAAwE;YACxE,IAAI,CAAC,gBAAgB,IAAI,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC;YAE7D,gDAAgD;YAChD,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC3C,KAAK,CAAC,KAAK,EAAE,CAAC;gBACd,OAAO;YACX,CAAC;YAED,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;KACJ,CAAC,CAAC;IACH,IAAI,gBAAgB;QAChB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAClC,CAAC;CACJ"}
@@ -0,0 +1,30 @@
1
+ import type { ScrcpyVideoDecoderPerformanceCounterInterface } from "@yume-chan/scrcpy-decoder-shared";
2
+ import { TransformStream } from "@yume-chan/stream-extra";
3
+ import type { CodecTransformStream } from "../codec/type.js";
4
+ export declare class VideoDecoderStream extends TransformStream<CodecTransformStream.Config | CodecTransformStream.VideoChunk, VideoFrame> implements ScrcpyVideoDecoderPerformanceCounterInterface {
5
+ #private;
6
+ get hardwareAcceleration(): HardwareAcceleration;
7
+ get onHardwareAccelerationChange(): import("@yume-chan/event").Event<HardwareAcceleration>;
8
+ /**
9
+ * Gets the number of frames waiting to be decoded.
10
+ */
11
+ get decodeQueueSize(): number;
12
+ /**
13
+ * Gets an event when a frame is dequeued (either decoded or discarded).
14
+ */
15
+ get onDequeue(): import("@yume-chan/event").Event<undefined>;
16
+ /**
17
+ * Gets the number of frames decoded by the decoder.
18
+ */
19
+ get framesDecoded(): number;
20
+ /**
21
+ * Gets the number of frames skipped by the decoder.
22
+ */
23
+ get framesSkippedDecoding(): number;
24
+ /**
25
+ * Gets the number of times the decoder has been reset to catch up new keyframes.
26
+ */
27
+ get decoderResetCount(): number;
28
+ constructor();
29
+ }
30
+ //# sourceMappingURL=video-decoder-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-decoder-stream.d.ts","sourceRoot":"","sources":["../../../src/video/utils/video-decoder-stream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,6CAA6C,EAAE,MAAM,kCAAkC,CAAC;AAEtG,OAAO,EAAiB,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAyE7D,qBAAa,kBACT,SAAQ,eAAe,CACnB,oBAAoB,CAAC,MAAM,GAAG,oBAAoB,CAAC,UAAU,EAC7D,UAAU,CAEd,YAAW,6CAA6C;;IAYxD,IAAI,oBAAoB,yBAEvB;IACD,IAAI,4BAA4B,2DAE/B;IAED;;OAEG;IACH,IAAI,eAAe,WAMlB;IAGD;;OAEG;IACH,IAAI,SAAS,gDAEZ;IAGD;;OAEG;IACH,IAAI,aAAa,WAEhB;IACD;;OAEG;IACH,IAAI,qBAAqB,WAExB;IACD;;OAEG;IACH,IAAI,iBAAiB,WAEpB;;CA0QJ"}