@yume-chan/scrcpy-decoder-webcodecs 2.5.3 → 3.0.0-beta.1

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 (127) 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 +2 -1
  20. package/esm/video/codec/index.d.ts.map +1 -1
  21. package/esm/video/codec/index.js +2 -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/codec/vp8.d.ts +7 -0
  26. package/esm/video/codec/vp8.d.ts.map +1 -0
  27. package/esm/video/codec/vp8.js +36 -0
  28. package/esm/video/codec/vp8.js.map +1 -0
  29. package/esm/video/codec/vp9.d.ts +7 -0
  30. package/esm/video/codec/vp9.d.ts.map +1 -0
  31. package/esm/video/codec/vp9.js +40 -0
  32. package/esm/video/codec/vp9.js.map +1 -0
  33. package/esm/video/decoder.d.ts +60 -16
  34. package/esm/video/decoder.d.ts.map +1 -1
  35. package/esm/video/decoder.js +178 -136
  36. package/esm/video/decoder.js.map +1 -1
  37. package/esm/video/index.d.ts +1 -0
  38. package/esm/video/index.d.ts.map +1 -1
  39. package/esm/video/index.js +1 -0
  40. package/esm/video/index.js.map +1 -1
  41. package/esm/video/render/auto-canvas.d.ts +26 -0
  42. package/esm/video/render/auto-canvas.d.ts.map +1 -0
  43. package/esm/video/render/auto-canvas.js +80 -0
  44. package/esm/video/render/auto-canvas.js.map +1 -0
  45. package/esm/video/render/bitmap.d.ts +2 -2
  46. package/esm/video/render/bitmap.d.ts.map +1 -1
  47. package/esm/video/render/bitmap.js +18 -8
  48. package/esm/video/render/bitmap.js.map +1 -1
  49. package/esm/video/render/canvas.d.ts +38 -4
  50. package/esm/video/render/canvas.d.ts.map +1 -1
  51. package/esm/video/render/canvas.js +97 -10
  52. package/esm/video/render/canvas.js.map +1 -1
  53. package/esm/video/render/flow-control.d.ts +32 -0
  54. package/esm/video/render/flow-control.d.ts.map +1 -0
  55. package/esm/video/render/flow-control.js +139 -0
  56. package/esm/video/render/flow-control.js.map +1 -0
  57. package/esm/video/render/index.d.ts +2 -0
  58. package/esm/video/render/index.d.ts.map +1 -1
  59. package/esm/video/render/index.js +2 -0
  60. package/esm/video/render/index.js.map +1 -1
  61. package/esm/video/render/insertable-stream.d.ts +15 -3
  62. package/esm/video/render/insertable-stream.d.ts.map +1 -1
  63. package/esm/video/render/insertable-stream.js +29 -11
  64. package/esm/video/render/insertable-stream.js.map +1 -1
  65. package/esm/video/render/redraw.d.ts +31 -0
  66. package/esm/video/render/redraw.d.ts.map +1 -0
  67. package/esm/video/render/redraw.js +75 -0
  68. package/esm/video/render/redraw.js.map +1 -0
  69. package/esm/video/render/type.d.ts +8 -2
  70. package/esm/video/render/type.d.ts.map +1 -1
  71. package/esm/video/render/webgl.d.ts +38 -5
  72. package/esm/video/render/webgl.d.ts.map +1 -1
  73. package/esm/video/render/webgl.js +228 -59
  74. package/esm/video/render/webgl.js.map +1 -1
  75. package/esm/video/utils/index.d.ts +4 -0
  76. package/esm/video/utils/index.d.ts.map +1 -0
  77. package/esm/video/utils/index.js +4 -0
  78. package/esm/video/utils/index.js.map +1 -0
  79. package/esm/video/utils/snapshot.d.ts +2 -0
  80. package/esm/video/utils/snapshot.d.ts.map +1 -0
  81. package/esm/video/utils/snapshot.js +18 -0
  82. package/esm/video/utils/snapshot.js.map +1 -0
  83. package/esm/video/utils/timestamp.d.ts +19 -0
  84. package/esm/video/utils/timestamp.d.ts.map +1 -0
  85. package/esm/video/utils/timestamp.js +87 -0
  86. package/esm/video/utils/timestamp.js.map +1 -0
  87. package/esm/video/utils/video-decoder-stream.d.ts +30 -0
  88. package/esm/video/utils/video-decoder-stream.d.ts.map +1 -0
  89. package/esm/video/utils/video-decoder-stream.js +289 -0
  90. package/esm/video/utils/video-decoder-stream.js.map +1 -0
  91. package/package.json +12 -11
  92. package/src/video/codec/av1.ts +41 -131
  93. package/src/video/codec/h264.ts +15 -37
  94. package/src/video/codec/h265.ts +16 -45
  95. package/src/video/codec/h26x.ts +45 -96
  96. package/src/video/codec/index.ts +2 -1
  97. package/src/video/codec/type.ts +32 -12
  98. package/src/video/codec/vp8.ts +52 -0
  99. package/src/video/codec/vp9.ts +55 -0
  100. package/src/video/decoder.ts +212 -166
  101. package/src/video/index.ts +1 -0
  102. package/src/video/render/auto-canvas.ts +105 -0
  103. package/src/video/render/bitmap.ts +23 -9
  104. package/src/video/render/canvas.ts +157 -12
  105. package/src/video/render/flow-control.ts +182 -0
  106. package/src/video/render/index.ts +2 -0
  107. package/src/video/render/insertable-stream.ts +50 -10
  108. package/src/video/render/redraw.ts +88 -0
  109. package/src/video/render/type.ts +10 -2
  110. package/src/video/render/webgl.ts +316 -80
  111. package/src/video/utils/index.ts +3 -0
  112. package/src/video/utils/snapshot.ts +22 -0
  113. package/src/video/utils/timestamp.ts +108 -0
  114. package/src/video/utils/video-decoder-stream.ts +413 -0
  115. package/tsconfig.build.json +0 -14
  116. package/CHANGELOG.md +0 -140
  117. package/esm/video/codec/utils.d.ts +0 -4
  118. package/esm/video/codec/utils.d.ts.map +0 -1
  119. package/esm/video/codec/utils.js +0 -10
  120. package/esm/video/codec/utils.js.map +0 -1
  121. package/esm/video/snapshot.d.ts +0 -6
  122. package/esm/video/snapshot.d.ts.map +0 -1
  123. package/esm/video/snapshot.js +0 -41
  124. package/esm/video/snapshot.js.map +0 -1
  125. package/src/video/codec/utils.ts +0 -11
  126. package/src/video/snapshot.ts +0 -41
  127. package/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,413 @@
1
+ import { EventEmitter, StickyEventEmitter } from "@yume-chan/event";
2
+ import type { ScrcpyVideoDecoderPerformanceCounterInterface } from "@yume-chan/scrcpy-decoder-shared";
3
+ import { ScrcpyVideoDecoderPerformanceCounter } from "@yume-chan/scrcpy-decoder-shared";
4
+ import { concatBuffers, TransformStream } from "@yume-chan/stream-extra";
5
+
6
+ import type { CodecTransformStream } from "../codec/type.js";
7
+
8
+ type State =
9
+ | {
10
+ type: "unconfigured";
11
+ }
12
+ | {
13
+ type: "configured";
14
+ /**
15
+ * The native decoder.
16
+ *
17
+ * `transform`, `flush` and `cancel` callbacks don't need to
18
+ * check `#decoder.state` for "closed".
19
+ *
20
+ * Decoder can enter "closed" state by either:
21
+ * - Encounter a decoding error: this triggers `controller.error`,
22
+ * so no more transformer callbacks will be called.
23
+ * - Calling `close` manually: this only happens in `flush` and `cancel`,
24
+ * so no more transformer callbacks will be called.
25
+ */
26
+ decoder: VideoDecoder;
27
+ /** Saved configuration for use when resetting/re-creating the decoder. */
28
+ config: CodecTransformStream.Config;
29
+ }
30
+ | {
31
+ type: "decoding";
32
+ decoder: VideoDecoder;
33
+ /** Saved configuration for use when resetting/re-creating the decoder. */
34
+ config: CodecTransformStream.Config;
35
+ /** Saved frames since last keyframe for use when re-creating the decoder */
36
+ frames: CodecTransformStream.VideoChunk[];
37
+ }
38
+ | {
39
+ type: "reclaimed";
40
+ /** Saved configuration for use when re-creating the decoder. */
41
+ config: CodecTransformStream.Config;
42
+ /** Saved frames since last keyframe for use when re-creating the decoder */
43
+ frames: CodecTransformStream.VideoChunk[] | undefined;
44
+ };
45
+
46
+ function decodeFirstKeyFrame(
47
+ decoder: VideoDecoder,
48
+ config: CodecTransformStream.Config,
49
+ chunk: CodecTransformStream.VideoChunk,
50
+ ) {
51
+ decoder.decode(
52
+ new EncodedVideoChunk({
53
+ type: "key",
54
+ timestamp: chunk.timestamp,
55
+ // `lib.dom.d.ts` doesn't allow `duration` to be undefined.
56
+ duration: chunk.duration!,
57
+ data: config.raw
58
+ ? concatBuffers([config.raw, chunk.data])
59
+ : chunk.data,
60
+ }),
61
+ );
62
+ }
63
+
64
+ function decodeFrame(
65
+ decoder: VideoDecoder,
66
+ chunk: CodecTransformStream.VideoChunk,
67
+ ) {
68
+ decoder.decode(
69
+ new EncodedVideoChunk({
70
+ type: chunk.type,
71
+ timestamp: chunk.timestamp,
72
+ // `lib.dom.d.ts` doesn't allow `duration` to be undefined.
73
+ duration: chunk.duration!,
74
+ data: chunk.data,
75
+ }),
76
+ );
77
+ }
78
+
79
+ export class VideoDecoderStream
80
+ extends TransformStream<
81
+ CodecTransformStream.Config | CodecTransformStream.VideoChunk,
82
+ VideoFrame
83
+ >
84
+ implements ScrcpyVideoDecoderPerformanceCounterInterface
85
+ {
86
+ #controller!: TransformStreamDefaultController<VideoFrame>;
87
+
88
+ #state: State = { type: "unconfigured" };
89
+
90
+ #hardwareAcceleration = new StickyEventEmitter<
91
+ Exclude<CodecTransformStream.Config["hardwareAcceleration"], undefined>
92
+ >({
93
+ initialValue: "no-preference",
94
+ equals: (a, b) => a === b,
95
+ });
96
+ get hardwareAcceleration() {
97
+ return this.#hardwareAcceleration.value;
98
+ }
99
+ get onHardwareAccelerationChange() {
100
+ return this.#hardwareAcceleration.event;
101
+ }
102
+
103
+ /**
104
+ * Gets the number of frames waiting to be decoded.
105
+ */
106
+ get decodeQueueSize() {
107
+ if ("decoder" in this.#state) {
108
+ return this.#state.decoder.decodeQueueSize;
109
+ }
110
+
111
+ return 0;
112
+ }
113
+
114
+ #onDequeue = new EventEmitter<undefined>();
115
+ /**
116
+ * Gets an event when a frame is dequeued (either decoded or discarded).
117
+ */
118
+ get onDequeue() {
119
+ return this.#onDequeue.event;
120
+ }
121
+
122
+ #counter = new ScrcpyVideoDecoderPerformanceCounter();
123
+ /**
124
+ * Gets the number of frames decoded by the decoder.
125
+ */
126
+ get framesDecoded() {
127
+ return this.#counter.framesDecoded;
128
+ }
129
+ /**
130
+ * Gets the number of frames skipped by the decoder.
131
+ */
132
+ get framesSkippedDecoding() {
133
+ return this.#counter.framesSkippedDecoding;
134
+ }
135
+ /**
136
+ * Gets the number of times the decoder has been reset to catch up new keyframes.
137
+ */
138
+ get decoderResetCount() {
139
+ return this.#counter.decoderResetCount;
140
+ }
141
+
142
+ #abortController = new AbortController();
143
+ #skipFramesBefore = -1;
144
+
145
+ constructor() {
146
+ let controller!: TransformStreamDefaultController<VideoFrame>;
147
+
148
+ super({
149
+ start: (controller_) => {
150
+ // WARN: can't use `this` here
151
+ controller = controller_;
152
+ },
153
+ transform: async (chunk) => {
154
+ if ("codec" in chunk) {
155
+ this.#hardwareAcceleration.fire(
156
+ chunk.hardwareAcceleration ?? "no-preference",
157
+ );
158
+ // Validate the config by creating decoder right away
159
+ switch (this.#state.type) {
160
+ case "unconfigured":
161
+ case "reclaimed":
162
+ this.#state = {
163
+ type: "configured",
164
+ decoder: this.#createDecoder(chunk),
165
+ config: chunk,
166
+ };
167
+ break;
168
+ // @ts-expect-error: intentional case fallthrough
169
+ case "decoding":
170
+ await this.#state.decoder.flush();
171
+ // fallthrough
172
+ case "configured":
173
+ // Reuse the existing decoder.
174
+ // `decoder` is definitely in "configured" state,
175
+ // otherwise the stream is in error state
176
+ // and no `transform` callbacks will be called.
177
+ this.#state.decoder.configure(chunk);
178
+ this.#state = {
179
+ type: "configured",
180
+ decoder: this.#state.decoder,
181
+ config: chunk,
182
+ };
183
+ break;
184
+ }
185
+ return;
186
+ }
187
+
188
+ this.#handleVideoChunk(chunk);
189
+ },
190
+ flush: async () => {
191
+ // only call `flush` when `decoder.state` is "configured".
192
+ if (
193
+ "decoder" in this.#state &&
194
+ this.#state.decoder.state === "configured"
195
+ ) {
196
+ // This also delays closing `readable` and `writable` streams
197
+ // (if they are not in error state) until all frames are decoded.
198
+ await this.#state.decoder.flush();
199
+ }
200
+ this.#dispose();
201
+ },
202
+ cancel: () => {
203
+ // Immediately close the decoder on stream cancel/error
204
+ this.#dispose();
205
+ },
206
+ });
207
+
208
+ this.#controller = controller;
209
+ }
210
+
211
+ #handleVideoChunk(chunk: CodecTransformStream.VideoChunk) {
212
+ switch (this.#state.type) {
213
+ case "unconfigured":
214
+ throw new Error("Decoder not configured");
215
+ case "configured": {
216
+ if (chunk.type === "delta") {
217
+ throw new Error("Expect a keyframe but got a delta frame");
218
+ }
219
+
220
+ decodeFirstKeyFrame(
221
+ this.#state.decoder,
222
+ this.#state.config,
223
+ chunk,
224
+ );
225
+
226
+ this.#state = {
227
+ type: "decoding",
228
+ decoder: this.#state.decoder,
229
+ config: this.#state.config,
230
+ frames: [chunk],
231
+ };
232
+ break;
233
+ }
234
+ case "decoding":
235
+ if (chunk.type === "key") {
236
+ this.#state.frames.length = 0;
237
+ }
238
+ this.#state.frames.push(chunk);
239
+
240
+ decodeFrame(this.#state.decoder, chunk);
241
+ break;
242
+ case "reclaimed": {
243
+ const decoder = this.#createDecoder(this.#state.config);
244
+
245
+ if (chunk.type === "key") {
246
+ decodeFirstKeyFrame(decoder, this.#state.config, chunk);
247
+
248
+ this.#state = {
249
+ type: "decoding",
250
+ decoder: decoder,
251
+ config: this.#state.config,
252
+ frames: [chunk],
253
+ };
254
+ return;
255
+ }
256
+
257
+ if (!this.#state.frames) {
258
+ // Reclaimed when configured but no frames have been decoded yet,
259
+ // so a keyframe is required to start decoding.
260
+ throw new Error("Expect a keyframe but got a delta frame");
261
+ }
262
+
263
+ decodeFirstKeyFrame(
264
+ decoder,
265
+ this.#state.config,
266
+ this.#state.frames[0]!,
267
+ );
268
+
269
+ // `chunk`s must have monotonic timestamps, so we can skip all frames before `chunk`.
270
+ this.#skipFramesBefore = chunk.timestamp;
271
+ this.#state.frames.push(chunk);
272
+
273
+ for (const frame of this.#state.frames.slice(1)) {
274
+ decodeFrame(decoder, frame);
275
+ }
276
+
277
+ this.#state = {
278
+ type: "decoding",
279
+ decoder: decoder,
280
+ config: this.#state.config,
281
+ frames: this.#state.frames,
282
+ };
283
+
284
+ break;
285
+ }
286
+ }
287
+ }
288
+
289
+ #createDecoder(config: CodecTransformStream.Config) {
290
+ const decoder = new VideoDecoder({
291
+ output: (frame) => {
292
+ if (frame.timestamp < this.#skipFramesBefore) {
293
+ frame.close();
294
+ return;
295
+ }
296
+
297
+ this.#counter.increaseFramesDecoded();
298
+ try {
299
+ this.#controller.enqueue(frame);
300
+ } catch {
301
+ // `controller` is closed
302
+ frame.close();
303
+ }
304
+ },
305
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
306
+ error: async (error) => {
307
+ if (error.name === "QuotaExceededError") {
308
+ // Chrome reclaims inactive `VideoDecoder`'s after 90 seconds
309
+ // (for example due to pausing decoding when the document is hidden).
310
+ // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/webcodecs/reclaimable_codec.cc;l=181;drc=aba14550ed0b4620deb59e7c5f551cbde8970fb3
311
+ // Reset states, it will be recreated in next `transform` call.
312
+ switch (this.#state.type) {
313
+ case "unconfigured":
314
+ case "reclaimed":
315
+ // Don't throw, report errors to stream
316
+ this.#controller.error(
317
+ new Error(
318
+ "Unexpected state when reclaiming decoder",
319
+ ),
320
+ );
321
+ this.#dispose();
322
+ return;
323
+ case "configured":
324
+ // Unlike `transform` callback,
325
+ // this doesn't re-create the decoder immediately,
326
+ // because the config has already been validated,
327
+ // and since browser reclaims the decoder to save hardware resources,
328
+ // we don't want to undo that by creating a new decoder immediately.
329
+ this.#state = {
330
+ type: "reclaimed",
331
+ config,
332
+ frames: undefined,
333
+ };
334
+ break;
335
+ case "decoding":
336
+ this.#state = {
337
+ type: "reclaimed",
338
+ config,
339
+ frames: this.#state.frames,
340
+ };
341
+ break;
342
+ }
343
+ return;
344
+ }
345
+
346
+ // Maybe the decoder is hardware accelerated but the hardware has an issue,
347
+ // retry with software decoder.
348
+ if (
349
+ error.name === "EncodingError" &&
350
+ this.#state.type === "decoding" &&
351
+ config.hardwareAcceleration !== "prefer-software"
352
+ ) {
353
+ config.hardwareAcceleration = "prefer-software";
354
+ // Codecs like H.265 only support hardware acceleration,
355
+ // so we need to check if the software decoder is supported.
356
+ const support =
357
+ await VideoDecoder.isConfigSupported(config);
358
+ if (support.supported) {
359
+ const decoder = this.#createDecoder(config);
360
+
361
+ // Replay frames with rendering skipping
362
+ this.#skipFramesBefore =
363
+ this.#state.frames.at(-1)!.timestamp;
364
+ decodeFirstKeyFrame(
365
+ decoder,
366
+ config,
367
+ this.#state.frames[0]!,
368
+ );
369
+ for (const frame of this.#state.frames.slice(1)) {
370
+ decodeFrame(decoder, frame);
371
+ }
372
+
373
+ // Update state
374
+ this.#hardwareAcceleration.fire("prefer-software");
375
+ this.#state.decoder = decoder;
376
+ return;
377
+ }
378
+ }
379
+
380
+ // Propagate other decoder errors to stream.
381
+ this.#controller.error(error);
382
+ this.#dispose();
383
+ },
384
+ });
385
+
386
+ // `dequeue` event added in Chrome 106,
387
+ // before that `VideoDecoder` is not a `EventTarget`
388
+ if (typeof decoder.addEventListener === "function") {
389
+ decoder.addEventListener(
390
+ "dequeue",
391
+ () => this.#onDequeue.fire(undefined),
392
+ { signal: this.#abortController.signal },
393
+ );
394
+ }
395
+
396
+ decoder.configure(config);
397
+
398
+ return decoder;
399
+ }
400
+
401
+ #dispose() {
402
+ this.#abortController.abort();
403
+ this.#onDequeue.dispose();
404
+
405
+ if (
406
+ "decoder" in this.#state &&
407
+ this.#state.decoder.state !== "closed"
408
+ ) {
409
+ this.#state.decoder.close();
410
+ }
411
+ this.#state = { type: "unconfigured" };
412
+ }
413
+ }
@@ -7,18 +7,4 @@
7
7
  ],
8
8
  "types": []
9
9
  },
10
- "references": [
11
- {
12
- "path": "../no-data-view/tsconfig.build.json"
13
- },
14
- {
15
- "path": "../scrcpy-decoder-tinyh264/tsconfig.build.json"
16
- },
17
- {
18
- "path": "../scrcpy/tsconfig.build.json"
19
- },
20
- {
21
- "path": "../stream-extra/tsconfig.build.json"
22
- }
23
- ]
24
10
  }
package/CHANGELOG.md DELETED
@@ -1,140 +0,0 @@
1
- # Change Log - @yume-chan/scrcpy-decoder-webcodecs
2
-
3
- ## 2.5.0
4
-
5
- ### Minor Changes
6
-
7
- - 5ec8923: Expose `VideoDecoder.prototype.configure`'s `hardwareAcceleration` option
8
-
9
- ## 2.1.0
10
-
11
- ### Patch Changes
12
-
13
- - Updated dependencies [40a60ca]
14
- - @yume-chan/stream-extra@2.1.0
15
- - @yume-chan/scrcpy@2.1.0
16
- - @yume-chan/scrcpy-decoder-tinyh264@2.1.0
17
-
18
- ## 2.0.1
19
-
20
- ### Patch Changes
21
-
22
- - @yume-chan/scrcpy@2.0.1
23
- - @yume-chan/stream-extra@2.0.1
24
- - @yume-chan/scrcpy-decoder-tinyh264@2.0.1
25
-
26
- ## 2.0.0
27
-
28
- ### Patch Changes
29
-
30
- - Updated dependencies [fe06652]
31
- - Updated dependencies [05c01ad]
32
- - Updated dependencies [02f5bd5]
33
- - Updated dependencies
34
- - @yume-chan/scrcpy@2.0.0
35
- - @yume-chan/event@2.0.0
36
- - @yume-chan/no-data-view@2.0.0
37
- - @yume-chan/scrcpy-decoder-tinyh264@2.0.0
38
- - @yume-chan/stream-extra@2.0.0
39
-
40
- ## 1.1.0
41
-
42
- ### Minor Changes
43
-
44
- - fba7533: Rename `XXXWebCodecsDecoderRenderer` to `XXXVideoFrameRenderer`
45
-
46
- ### Patch Changes
47
-
48
- - Updated dependencies [6140ebc]
49
- - Updated dependencies [6140ebc]
50
- - Updated dependencies [6140ebc]
51
- - Updated dependencies [8c5b3c2]
52
- - Updated dependencies [7f2a09c]
53
- - Updated dependencies [cb44b63]
54
- - @yume-chan/scrcpy@1.1.0
55
- - @yume-chan/scrcpy-decoder-tinyh264@1.1.0
56
-
57
- ## 1.0.1
58
-
59
- ### Patch Changes
60
-
61
- - 53688d3: Use PNPM workspace and Changesets to manage the monorepo.
62
-
63
- 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.
64
-
65
- - db8466f: Fix H.265 rendering in Microsoft Edge
66
- - 8e4c1ef: Add a renderer based on Insertable Stream API
67
- - db8466f: Add a `snapshot` method to convert the last rendered frame into PNG
68
- - Updated dependencies [53688d3]
69
- - Updated dependencies [db8466f]
70
- - Updated dependencies [db8466f]
71
- - Updated dependencies [ea5002b]
72
- - Updated dependencies [ea5002b]
73
- - Updated dependencies [db8466f]
74
- - @yume-chan/scrcpy-decoder-tinyh264@1.0.1
75
- - @yume-chan/no-data-view@1.0.1
76
- - @yume-chan/stream-extra@1.0.1
77
- - @yume-chan/scrcpy@1.0.1
78
- - @yume-chan/event@1.0.1
79
-
80
- This log was last generated on Tue, 18 Jun 2024 02:49:43 GMT and should not be manually modified.
81
-
82
- ## 0.0.24
83
-
84
- Tue, 18 Jun 2024 02:49:43 GMT
85
-
86
- ### Updates
87
-
88
- - Support decoding AV1
89
- - Add `enableCapture` option to `WebCodecsVideoDecoder` which allows `renderer.readPixels` and `renderer.toDataURL` to work. The performance will be slightly affected when enabled.
90
-
91
- ## 0.0.23
92
-
93
- Thu, 21 Mar 2024 03:15:10 GMT
94
-
95
- ### Updates
96
-
97
- - Add `sizeChanged` event
98
- - Add WebGL and Bitmap based video renderers, which are 1.5 to 3 times faster on Android devices
99
-
100
- ## 0.0.22
101
-
102
- Wed, 13 Dec 2023 05:57:27 GMT
103
-
104
- _Version update only_
105
-
106
- ## 0.0.21
107
-
108
- Fri, 25 Aug 2023 14:05:18 GMT
109
-
110
- _Version update only_
111
-
112
- ## 0.0.20
113
-
114
- Mon, 05 Jun 2023 02:51:41 GMT
115
-
116
- ### Updates
117
-
118
- - 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).
119
-
120
- ## 0.0.19
121
-
122
- Sun, 09 Apr 2023 05:55:33 GMT
123
-
124
- _Version update only_
125
-
126
- ## 0.0.18
127
-
128
- Wed, 25 Jan 2023 21:33:49 GMT
129
-
130
- ### Updates
131
-
132
- - Change to not use vertical sync to minimize latency
133
-
134
- ## 0.0.17
135
-
136
- Tue, 18 Oct 2022 09:32:30 GMT
137
-
138
- ### Updates
139
-
140
- - Separated from `@yume-chan/scrcpy` for simpler dependency management.
@@ -1,4 +0,0 @@
1
- export declare function hexDigits(value: number): string;
2
- export declare function hexTwoDigits(value: number): string;
3
- export declare function decimalTwoDigits(value: number): string;
4
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/video/codec/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,UAEtC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,UAEzC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,UAE7C"}
@@ -1,10 +0,0 @@
1
- export function hexDigits(value) {
2
- return value.toString(16).toUpperCase();
3
- }
4
- export function hexTwoDigits(value) {
5
- return value.toString(16).toUpperCase().padStart(2, "0");
6
- }
7
- export function decimalTwoDigits(value) {
8
- return value.toString(10).padStart(2, "0");
9
- }
10
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/video/codec/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC1C,OAAO,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC/C,CAAC"}
@@ -1,6 +0,0 @@
1
- export declare class VideoFrameCapturer {
2
- #private;
3
- constructor();
4
- capture(frame: VideoFrame): Promise<Blob>;
5
- }
6
- //# sourceMappingURL=snapshot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/video/snapshot.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAkB;;;IAiBrB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAuBlD"}
@@ -1,41 +0,0 @@
1
- export class VideoFrameCapturer {
2
- #canvas;
3
- #context;
4
- constructor() {
5
- if (typeof OffscreenCanvas !== "undefined") {
6
- this.#canvas = new OffscreenCanvas(1, 1);
7
- }
8
- else {
9
- this.#canvas = document.createElement("canvas");
10
- this.#canvas.width = 1;
11
- this.#canvas.height = 1;
12
- }
13
- this.#context = this.#canvas.getContext("bitmaprenderer", {
14
- alpha: false,
15
- });
16
- }
17
- async capture(frame) {
18
- this.#canvas.width = frame.displayWidth;
19
- this.#canvas.height = frame.displayHeight;
20
- const bitmap = await createImageBitmap(frame);
21
- this.#context.transferFromImageBitmap(bitmap);
22
- if (this.#canvas instanceof OffscreenCanvas) {
23
- return await this.#canvas.convertToBlob({
24
- type: "image/png",
25
- });
26
- }
27
- else {
28
- return new Promise((resolve, reject) => {
29
- this.#canvas.toBlob((blob) => {
30
- if (!blob) {
31
- reject(new Error("Failed to convert canvas to blob"));
32
- }
33
- else {
34
- resolve(blob);
35
- }
36
- }, "image/png");
37
- });
38
- }
39
- }
40
- }
41
- //# sourceMappingURL=snapshot.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/video/snapshot.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAkB;IAC3B,OAAO,CAAsC;IAC7C,QAAQ,CAA8B;IAEtC;QACI,IAAI,OAAO,eAAe,KAAK,WAAW,EAAE,CAAC;YACzC,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAChD,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5B,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,EAAE;YACtD,KAAK,EAAE,KAAK;SACf,CAAE,CAAC;IACR,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAiB;QAC3B,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC;QAE1C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAE9C,IAAI,IAAI,CAAC,OAAO,YAAY,eAAe,EAAE,CAAC;YAC1C,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;gBACpC,IAAI,EAAE,WAAW;aACpB,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACJ,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAClC,IAAI,CAAC,OAA6B,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;oBAChD,IAAI,CAAC,IAAI,EAAE,CAAC;wBACR,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;oBAC1D,CAAC;yBAAM,CAAC;wBACJ,OAAO,CAAC,IAAI,CAAC,CAAC;oBAClB,CAAC;gBACL,CAAC,EAAE,WAAW,CAAC,CAAC;YACpB,CAAC,CAAC,CAAC;QACP,CAAC;IACL,CAAC;CACJ"}
@@ -1,11 +0,0 @@
1
- export function hexDigits(value: number) {
2
- return value.toString(16).toUpperCase();
3
- }
4
-
5
- export function hexTwoDigits(value: number) {
6
- return value.toString(16).toUpperCase().padStart(2, "0");
7
- }
8
-
9
- export function decimalTwoDigits(value: number) {
10
- return value.toString(10).padStart(2, "0");
11
- }