@yume-chan/scrcpy 0.0.13 → 0.0.16

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 (80) hide show
  1. package/CHANGELOG.json +45 -0
  2. package/CHANGELOG.md +25 -1
  3. package/LICENSE +21 -21
  4. package/README.md +90 -89
  5. package/bin/scrcpy-server +0 -0
  6. package/bin/version.d.ts +1 -1
  7. package/bin/version.js +1 -1
  8. package/esm/client.d.ts +14 -2
  9. package/esm/client.d.ts.map +1 -1
  10. package/esm/client.js +275 -143
  11. package/esm/client.js.map +1 -1
  12. package/esm/connection.d.ts.map +1 -1
  13. package/esm/connection.js +74 -86
  14. package/esm/connection.js.map +1 -1
  15. package/esm/decoder/tinyh264/index.js +48 -48
  16. package/esm/decoder/tinyh264/index.js.map +1 -1
  17. package/esm/decoder/tinyh264/wrapper.js +3 -2
  18. package/esm/decoder/tinyh264/wrapper.js.map +1 -1
  19. package/esm/decoder/web-codecs/index.js +26 -21
  20. package/esm/decoder/web-codecs/index.js.map +1 -1
  21. package/esm/message.d.ts +13 -8
  22. package/esm/message.d.ts.map +1 -1
  23. package/esm/message.js +14 -8
  24. package/esm/message.js.map +1 -1
  25. package/esm/options/1_16/index.d.ts +8 -4
  26. package/esm/options/1_16/index.d.ts.map +1 -1
  27. package/esm/options/1_16/index.js +44 -18
  28. package/esm/options/1_16/index.js.map +1 -1
  29. package/esm/options/1_16/sps.js +3 -2
  30. package/esm/options/1_16/sps.js.map +1 -1
  31. package/esm/options/1_18.d.ts +3 -2
  32. package/esm/options/1_18.d.ts.map +1 -1
  33. package/esm/options/1_18.js +24 -1
  34. package/esm/options/1_18.js.map +1 -1
  35. package/esm/options/1_21.js +4 -1
  36. package/esm/options/1_21.js.map +1 -1
  37. package/esm/options/1_22.d.ts +3 -3
  38. package/esm/options/1_22.d.ts.map +1 -1
  39. package/esm/options/1_22.js +9 -6
  40. package/esm/options/1_22.js.map +1 -1
  41. package/esm/options/1_23.js +4 -1
  42. package/esm/options/1_23.js.map +1 -1
  43. package/esm/options/1_24.d.ts +9 -0
  44. package/esm/options/1_24.d.ts.map +1 -0
  45. package/esm/options/1_24.js +13 -0
  46. package/esm/options/1_24.js.map +1 -0
  47. package/esm/options/common.d.ts +2 -0
  48. package/esm/options/common.d.ts.map +1 -1
  49. package/esm/options/common.js.map +1 -1
  50. package/esm/options/index.d.ts +1 -0
  51. package/esm/options/index.d.ts.map +1 -1
  52. package/esm/options/index.js +1 -0
  53. package/esm/options/index.js.map +1 -1
  54. package/esm/push-server.js +5 -10
  55. package/esm/push-server.js.map +1 -1
  56. package/package.json +8 -8
  57. package/scrcpy.LICENSE +203 -203
  58. package/scripts/fetch-server.cjs +28 -28
  59. package/src/client.ts +435 -275
  60. package/src/codec.ts +35 -35
  61. package/src/connection.ts +148 -145
  62. package/src/decoder/index.ts +3 -3
  63. package/src/decoder/tinyh264/index.ts +112 -112
  64. package/src/decoder/tinyh264/types.d.ts +137 -137
  65. package/src/decoder/tinyh264/worker.ts +2 -2
  66. package/src/decoder/tinyh264/wrapper.ts +89 -89
  67. package/src/decoder/types.ts +35 -35
  68. package/src/decoder/web-codecs/index.ts +99 -99
  69. package/src/index.ts +8 -8
  70. package/src/message.ts +113 -105
  71. package/src/options/1_16/index.ts +345 -315
  72. package/src/options/1_16/sps.ts +300 -300
  73. package/src/options/1_18.ts +61 -41
  74. package/src/options/1_21.ts +34 -34
  75. package/src/options/1_22.ts +78 -80
  76. package/src/options/1_24.ts +18 -0
  77. package/src/options/common.ts +66 -63
  78. package/src/options/index.ts +7 -6
  79. package/src/push-server.ts +24 -24
  80. package/src/utils.ts +5 -5
@@ -1,99 +1,99 @@
1
- import { WritableStream } from '@yume-chan/adb';
2
- import type { VideoStreamPacket } from "../../options/index.js";
3
- import type { H264Configuration, H264Decoder } from "../types.js";
4
-
5
- function toHex(value: number) {
6
- return value.toString(16).padStart(2, '0').toUpperCase();
7
- }
8
-
9
- export class WebCodecsDecoder implements H264Decoder {
10
- // Usually, browsers can decode most configurations,
11
- // So let device choose best profile and level for itself.
12
- public readonly maxProfile = undefined;
13
- public readonly maxLevel = undefined;
14
-
15
- private _writable: WritableStream<VideoStreamPacket>;
16
- public get writable() { return this._writable; }
17
-
18
- private _renderer: HTMLCanvasElement;
19
- public get renderer() { return this._renderer; }
20
-
21
- private _frameRendered = 0;
22
- public get frameRendered() { return this._frameRendered; }
23
-
24
- private context: CanvasRenderingContext2D;
25
- private decoder: VideoDecoder;
26
-
27
- // Limit FPS to system refresh rate
28
- private lastFrame: VideoFrame | undefined;
29
- private animationFrame: number = 0;
30
-
31
- public constructor() {
32
- this._renderer = document.createElement('canvas');
33
-
34
- this.context = this._renderer.getContext('2d')!;
35
- this.decoder = new VideoDecoder({
36
- output: (frame) => {
37
- if (this.lastFrame) {
38
- this.lastFrame.close();
39
- }
40
- this.lastFrame = frame;
41
-
42
- if (!this.animationFrame) {
43
- // Start render loop on first frame
44
- this.render();
45
- }
46
- },
47
- error() { },
48
- });
49
-
50
- this._writable = new WritableStream<VideoStreamPacket>({
51
- write: async (packet) => {
52
- switch (packet.type) {
53
- case 'configuration':
54
- this.configure(packet.data);
55
- break;
56
- case 'frame':
57
- this.decoder.decode(new EncodedVideoChunk({
58
- // Treat `undefined` as `key`, otherwise won't decode.
59
- type: packet.keyframe === false ? 'delta' : 'key',
60
- timestamp: 0,
61
- data: packet.data,
62
- }));
63
- break;
64
- }
65
- }
66
- });
67
- }
68
-
69
- private render = () => {
70
- if (this.lastFrame) {
71
- this._frameRendered += 1;
72
- this.context.drawImage(this.lastFrame, 0, 0);
73
- this.lastFrame.close();
74
- this.lastFrame = undefined;
75
- }
76
-
77
- this.animationFrame = requestAnimationFrame(this.render);
78
- };
79
-
80
- private configure(config: H264Configuration) {
81
- const { profileIndex, constraintSet, levelIndex } = config;
82
-
83
- this._renderer.width = config.croppedWidth;
84
- this._renderer.height = config.croppedHeight;
85
-
86
- // https://www.rfc-editor.org/rfc/rfc6381#section-3.3
87
- // ISO Base Media File Format Name Space
88
- const codec = `avc1.${[profileIndex, constraintSet, levelIndex].map(toHex).join('')}`;
89
- this.decoder.configure({
90
- codec: codec,
91
- optimizeForLatency: true,
92
- });
93
- }
94
-
95
- public dispose() {
96
- cancelAnimationFrame(this.animationFrame);
97
- this.decoder.close();
98
- }
99
- }
1
+ import { WritableStream } from '@yume-chan/adb';
2
+ import type { VideoStreamPacket } from "../../options/index.js";
3
+ import type { H264Configuration, H264Decoder } from "../types.js";
4
+
5
+ function toHex(value: number) {
6
+ return value.toString(16).padStart(2, '0').toUpperCase();
7
+ }
8
+
9
+ export class WebCodecsDecoder implements H264Decoder {
10
+ // Usually, browsers can decode most configurations,
11
+ // So let device choose best profile and level for itself.
12
+ public readonly maxProfile = undefined;
13
+ public readonly maxLevel = undefined;
14
+
15
+ private _writable: WritableStream<VideoStreamPacket>;
16
+ public get writable() { return this._writable; }
17
+
18
+ private _renderer: HTMLCanvasElement;
19
+ public get renderer() { return this._renderer; }
20
+
21
+ private _frameRendered = 0;
22
+ public get frameRendered() { return this._frameRendered; }
23
+
24
+ private context: CanvasRenderingContext2D;
25
+ private decoder: VideoDecoder;
26
+
27
+ // Limit FPS to system refresh rate
28
+ private lastFrame: VideoFrame | undefined;
29
+ private animationFrame: number = 0;
30
+
31
+ public constructor() {
32
+ this._renderer = document.createElement('canvas');
33
+
34
+ this.context = this._renderer.getContext('2d')!;
35
+ this.decoder = new VideoDecoder({
36
+ output: (frame) => {
37
+ if (this.lastFrame) {
38
+ this.lastFrame.close();
39
+ }
40
+ this.lastFrame = frame;
41
+
42
+ if (!this.animationFrame) {
43
+ // Start render loop on first frame
44
+ this.render();
45
+ }
46
+ },
47
+ error() { },
48
+ });
49
+
50
+ this._writable = new WritableStream<VideoStreamPacket>({
51
+ write: async (packet) => {
52
+ switch (packet.type) {
53
+ case 'configuration':
54
+ this.configure(packet.data);
55
+ break;
56
+ case 'frame':
57
+ this.decoder.decode(new EncodedVideoChunk({
58
+ // Treat `undefined` as `key`, otherwise won't decode.
59
+ type: packet.keyframe === false ? 'delta' : 'key',
60
+ timestamp: 0,
61
+ data: packet.data,
62
+ }));
63
+ break;
64
+ }
65
+ }
66
+ });
67
+ }
68
+
69
+ private render = () => {
70
+ if (this.lastFrame) {
71
+ this._frameRendered += 1;
72
+ this.context.drawImage(this.lastFrame, 0, 0);
73
+ this.lastFrame.close();
74
+ this.lastFrame = undefined;
75
+ }
76
+
77
+ this.animationFrame = requestAnimationFrame(this.render);
78
+ };
79
+
80
+ private configure(config: H264Configuration) {
81
+ const { profileIndex, constraintSet, levelIndex } = config;
82
+
83
+ this._renderer.width = config.croppedWidth;
84
+ this._renderer.height = config.croppedHeight;
85
+
86
+ // https://www.rfc-editor.org/rfc/rfc6381#section-3.3
87
+ // ISO Base Media File Format Name Space
88
+ const codec = `avc1.${[profileIndex, constraintSet, levelIndex].map(toHex).join('')}`;
89
+ this.decoder.configure({
90
+ codec: codec,
91
+ optimizeForLatency: true,
92
+ });
93
+ }
94
+
95
+ public dispose() {
96
+ cancelAnimationFrame(this.animationFrame);
97
+ this.decoder.close();
98
+ }
99
+ }
package/src/index.ts CHANGED
@@ -1,8 +1,8 @@
1
- export * from './client.js';
2
- export * from './codec.js';
3
- export * from './connection.js';
4
- export * from './decoder/index.js';
5
- export * from './message.js';
6
- export * from './options/index.js';
7
- export * from './push-server.js';
8
- export * from './utils.js';
1
+ export * from './client.js';
2
+ export * from './codec.js';
3
+ export * from './connection.js';
4
+ export * from './decoder/index.js';
5
+ export * from './message.js';
6
+ export * from './options/index.js';
7
+ export * from './push-server.js';
8
+ export * from './utils.js';
package/src/message.ts CHANGED
@@ -1,105 +1,113 @@
1
- import Struct, { placeholder } from '@yume-chan/struct';
2
-
3
- export enum ScrcpyControlMessageType {
4
- InjectKeycode,
5
- InjectText,
6
- InjectTouch,
7
- InjectScroll,
8
- BackOrScreenOn,
9
- ExpandNotificationPanel,
10
- CollapseNotificationPanel,
11
- GetClipboard,
12
- SetClipboard,
13
- SetScreenPowerMode,
14
- RotateDevice,
15
- }
16
-
17
- // https://developer.android.com/reference/android/view/MotionEvent#constants_1
18
- export enum AndroidMotionEventAction {
19
- Down,
20
- Up,
21
- Move,
22
- Cancel,
23
- Outside,
24
- PointerDown,
25
- PointerUp,
26
- HoverMove,
27
- Scroll,
28
- HoverEnter,
29
- HoverExit,
30
- ButtonPress,
31
- ButtonRelease,
32
- }
33
-
34
- export const ScrcpyInjectTouchControlMessage =
35
- new Struct()
36
- .uint8('type', ScrcpyControlMessageType.InjectTouch as const)
37
- .uint8('action', placeholder<AndroidMotionEventAction>())
38
- .uint64('pointerId')
39
- .uint32('pointerX')
40
- .uint32('pointerY')
41
- .uint16('screenWidth')
42
- .uint16('screenHeight')
43
- .uint16('pressure')
44
- .uint32('buttons');
45
-
46
- export type ScrcpyInjectTouchControlMessage = typeof ScrcpyInjectTouchControlMessage['TInit'];
47
-
48
- export const ScrcpyInjectTextControlMessage =
49
- new Struct()
50
- .uint8('type', ScrcpyControlMessageType.InjectText as const)
51
- .uint32('length')
52
- .string('text', { lengthField: 'length' });
53
-
54
- export type ScrcpyInjectTextControlMessage =
55
- typeof ScrcpyInjectTextControlMessage['TInit'];
56
-
57
- export enum AndroidKeyEventAction {
58
- Down = 0,
59
- Up = 1,
60
- }
61
-
62
- export enum AndroidKeyCode {
63
- Home = 3,
64
- Back = 4,
65
- A = 29,
66
- B,
67
- C,
68
- D,
69
- E,
70
- F,
71
- G,
72
- H,
73
- I,
74
- J,
75
- K,
76
- L,
77
- M,
78
- N,
79
- O,
80
- P,
81
- Q,
82
- R,
83
- S,
84
- T,
85
- U,
86
- V,
87
- W,
88
- X,
89
- Y,
90
- Z,
91
- Space = 62,
92
- Delete = 67,
93
- AppSwitch = 187,
94
- }
95
-
96
- export const ScrcpyInjectKeyCodeControlMessage =
97
- new Struct()
98
- .uint8('type', ScrcpyControlMessageType.InjectKeycode as const)
99
- .uint8('action', placeholder<AndroidKeyEventAction>())
100
- .uint32('keyCode')
101
- .uint32('repeat')
102
- .uint32('metaState');
103
-
104
- export type ScrcpyInjectKeyCodeControlMessage =
105
- typeof ScrcpyInjectKeyCodeControlMessage['TInit'];
1
+ import Struct, { placeholder } from '@yume-chan/struct';
2
+
3
+ // https://github.com/Genymobile/scrcpy/blob/fa5b2a29e983a46b49531def9cf3d80c40c3de37/app/src/control_msg.h#L23
4
+ // For their message bodies, see https://github.com/Genymobile/scrcpy/blob/5c62f3419d252d10cd8c9cbb7c918b358b81f2d0/app/src/control_msg.c#L92
5
+ export enum ScrcpyControlMessageType {
6
+ InjectKeycode,
7
+ InjectText,
8
+ InjectTouch,
9
+ InjectScroll,
10
+ BackOrScreenOn,
11
+ ExpandNotificationPanel,
12
+ ExpandSettingPanel,
13
+ CollapseNotificationPanel,
14
+ GetClipboard,
15
+ SetClipboard,
16
+ SetScreenPowerMode,
17
+ RotateDevice,
18
+ }
19
+
20
+ // https://developer.android.com/reference/android/view/MotionEvent#constants_1
21
+ export enum AndroidMotionEventAction {
22
+ Down,
23
+ Up,
24
+ Move,
25
+ Cancel,
26
+ Outside,
27
+ PointerDown,
28
+ PointerUp,
29
+ HoverMove,
30
+ Scroll,
31
+ HoverEnter,
32
+ HoverExit,
33
+ ButtonPress,
34
+ ButtonRelease,
35
+ }
36
+
37
+ export const ScrcpySimpleControlMessage =
38
+ new Struct()
39
+ .uint8('type');
40
+
41
+ export const ScrcpyInjectTouchControlMessage =
42
+ new Struct()
43
+ .fields(ScrcpySimpleControlMessage)
44
+ .uint8('action', placeholder<AndroidMotionEventAction>())
45
+ .uint64('pointerId')
46
+ .uint32('pointerX')
47
+ .uint32('pointerY')
48
+ .uint16('screenWidth')
49
+ .uint16('screenHeight')
50
+ .uint16('pressure')
51
+ .uint32('buttons');
52
+
53
+ export type ScrcpyInjectTouchControlMessage = typeof ScrcpyInjectTouchControlMessage['TInit'];
54
+
55
+ export const ScrcpyInjectTextControlMessage =
56
+ new Struct()
57
+ .fields(ScrcpySimpleControlMessage)
58
+ .uint32('length')
59
+ .string('text', { lengthField: 'length' });
60
+
61
+ export type ScrcpyInjectTextControlMessage =
62
+ typeof ScrcpyInjectTextControlMessage['TInit'];
63
+
64
+ export enum AndroidKeyEventAction {
65
+ Down = 0,
66
+ Up = 1,
67
+ }
68
+
69
+ export enum AndroidKeyCode {
70
+ Home = 3,
71
+ Back = 4,
72
+ A = 29,
73
+ B,
74
+ C,
75
+ D,
76
+ E,
77
+ F,
78
+ G,
79
+ H,
80
+ I,
81
+ J,
82
+ K,
83
+ L,
84
+ M,
85
+ N,
86
+ O,
87
+ P,
88
+ Q,
89
+ R,
90
+ S,
91
+ T,
92
+ U,
93
+ V,
94
+ W,
95
+ X,
96
+ Y,
97
+ Z,
98
+ Space = 62,
99
+ Enter = 66,
100
+ Delete = 67,
101
+ AppSwitch = 187,
102
+ }
103
+
104
+ export const ScrcpyInjectKeyCodeControlMessage =
105
+ new Struct()
106
+ .fields(ScrcpySimpleControlMessage)
107
+ .uint8('action', placeholder<AndroidKeyEventAction>())
108
+ .uint32('keyCode')
109
+ .uint32('repeat')
110
+ .uint32('metaState');
111
+
112
+ export type ScrcpyInjectKeyCodeControlMessage =
113
+ typeof ScrcpyInjectKeyCodeControlMessage['TInit'];