@yume-chan/scrcpy-decoder-webcodecs 0.0.23 → 0.0.24
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.
- package/CHANGELOG.json +15 -0
- package/CHANGELOG.md +9 -1
- package/LICENSE +1 -1
- package/esm/index.d.ts +1 -20
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -181
- package/esm/index.js.map +1 -1
- package/esm/video/codec/av1.d.ts +8 -0
- package/esm/video/codec/av1.d.ts.map +1 -0
- package/esm/video/codec/av1.js +71 -0
- package/esm/video/codec/av1.js.map +1 -0
- package/esm/video/codec/h264.d.ts +7 -0
- package/esm/video/codec/h264.d.ts.map +1 -0
- package/esm/video/codec/h264.js +27 -0
- package/esm/video/codec/h264.js.map +1 -0
- package/esm/video/codec/h265.d.ts +7 -0
- package/esm/video/codec/h265.d.ts.map +1 -0
- package/esm/video/codec/h265.js +30 -0
- package/esm/video/codec/h265.js.map +1 -0
- package/esm/video/codec/h26x.d.ts +9 -0
- package/esm/video/codec/h26x.d.ts.map +1 -0
- package/esm/video/codec/h26x.js +35 -0
- package/esm/video/codec/h26x.js.map +1 -0
- package/esm/video/codec/index.d.ts +7 -0
- package/esm/video/codec/index.d.ts.map +1 -0
- package/esm/video/codec/index.js +7 -0
- package/esm/video/codec/index.js.map +1 -0
- package/esm/video/codec/type.d.ts +8 -0
- package/esm/video/codec/type.d.ts.map +1 -0
- package/esm/video/codec/type.js +2 -0
- package/esm/video/codec/type.js.map +1 -0
- package/esm/video/codec/utils.d.ts +4 -0
- package/esm/video/codec/utils.d.ts.map +1 -0
- package/esm/video/codec/utils.js +10 -0
- package/esm/video/codec/utils.js.map +1 -0
- package/esm/video/decoder.d.ts +28 -0
- package/esm/video/decoder.d.ts.map +1 -0
- package/esm/video/decoder.js +141 -0
- package/esm/video/decoder.js.map +1 -0
- package/esm/video/index.d.ts +4 -0
- package/esm/video/index.d.ts.map +1 -0
- package/esm/video/index.js +4 -0
- package/esm/video/index.js.map +1 -0
- package/esm/{bitmap.d.ts → video/render/bitmap.d.ts} +1 -1
- package/esm/video/render/bitmap.d.ts.map +1 -0
- package/esm/video/render/bitmap.js.map +1 -0
- package/esm/video/render/index.d.ts +4 -0
- package/esm/video/render/index.d.ts.map +1 -0
- package/esm/video/render/index.js +4 -0
- package/esm/video/render/index.js.map +1 -0
- package/esm/{renderer.d.ts → video/render/type.d.ts} +1 -1
- package/esm/video/render/type.d.ts.map +1 -0
- package/esm/video/render/type.js +2 -0
- package/esm/video/render/type.js.map +1 -0
- package/esm/video/render/webgl.d.ts +16 -0
- package/esm/video/render/webgl.d.ts.map +1 -0
- package/esm/{webgl.js → video/render/webgl.js} +23 -14
- package/esm/video/render/webgl.js.map +1 -0
- package/package.json +12 -14
- package/src/index.ts +1 -247
- package/src/video/codec/av1.ts +101 -0
- package/src/video/codec/h264.ts +42 -0
- package/src/video/codec/h265.ts +47 -0
- package/src/video/codec/h26x.ts +45 -0
- package/src/video/codec/index.ts +6 -0
- package/src/video/codec/type.ts +12 -0
- package/src/video/codec/utils.ts +11 -0
- package/src/video/decoder.ts +179 -0
- package/src/video/index.ts +3 -0
- package/src/{bitmap.ts → video/render/bitmap.ts} +1 -1
- package/src/video/render/index.ts +3 -0
- package/src/{webgl.ts → video/render/webgl.ts} +24 -15
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/bitmap.d.ts.map +0 -1
- package/esm/bitmap.js.map +0 -1
- package/esm/renderer.d.ts.map +0 -1
- package/esm/renderer.js +0 -2
- package/esm/renderer.js.map +0 -1
- package/esm/webgl.d.ts +0 -9
- package/esm/webgl.d.ts.map +0 -1
- package/esm/webgl.js.map +0 -1
- /package/esm/{bitmap.js → video/render/bitmap.js} +0 -0
- /package/src/{renderer.ts → video/render/type.ts} +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { EventEmitter } from "@yume-chan/event";
|
|
2
|
+
import { ScrcpyVideoCodecId } from "@yume-chan/scrcpy";
|
|
3
|
+
import { WritableStream } from "@yume-chan/stream-extra";
|
|
4
|
+
import { Av1Codec, H264Decoder, H265Decoder } from "./codec/index.js";
|
|
5
|
+
import { BitmapFrameRenderer, WebGLFrameRenderer } from "./render/index.js";
|
|
6
|
+
export class WebCodecsVideoDecoder {
|
|
7
|
+
static isSupported() {
|
|
8
|
+
return typeof globalThis.VideoDecoder !== "undefined";
|
|
9
|
+
}
|
|
10
|
+
static capabilities = {
|
|
11
|
+
h264: {},
|
|
12
|
+
h265: {},
|
|
13
|
+
};
|
|
14
|
+
#codec;
|
|
15
|
+
get codec() {
|
|
16
|
+
return this.#codec;
|
|
17
|
+
}
|
|
18
|
+
#codecDecoder;
|
|
19
|
+
#writable;
|
|
20
|
+
get writable() {
|
|
21
|
+
return this.#writable;
|
|
22
|
+
}
|
|
23
|
+
#canvas;
|
|
24
|
+
get renderer() {
|
|
25
|
+
return this.#canvas;
|
|
26
|
+
}
|
|
27
|
+
#frameRendered = 0;
|
|
28
|
+
get framesRendered() {
|
|
29
|
+
return this.#frameRendered;
|
|
30
|
+
}
|
|
31
|
+
#frameSkipped = 0;
|
|
32
|
+
get framesSkipped() {
|
|
33
|
+
return this.#frameSkipped;
|
|
34
|
+
}
|
|
35
|
+
#sizeChanged = new EventEmitter();
|
|
36
|
+
get sizeChanged() {
|
|
37
|
+
return this.#sizeChanged.event;
|
|
38
|
+
}
|
|
39
|
+
#decoder;
|
|
40
|
+
#renderer;
|
|
41
|
+
#currentFrameRendered = false;
|
|
42
|
+
#animationFrameId = 0;
|
|
43
|
+
/**
|
|
44
|
+
* Create a new WebCodecs video decoder.
|
|
45
|
+
* @param codec The video codec to decode
|
|
46
|
+
* @param enableCapture
|
|
47
|
+
* Whether to allow capturing the canvas content using APIs like `readPixels` and `toDataURL`.
|
|
48
|
+
* Enable this option may reduce performance.
|
|
49
|
+
*/
|
|
50
|
+
constructor(codec, enableCapture) {
|
|
51
|
+
this.#codec = codec;
|
|
52
|
+
this.#canvas = document.createElement("canvas");
|
|
53
|
+
try {
|
|
54
|
+
this.#renderer = new WebGLFrameRenderer(this.#canvas, enableCapture);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
this.#renderer = new BitmapFrameRenderer(this.#canvas);
|
|
58
|
+
}
|
|
59
|
+
this.#decoder = new VideoDecoder({
|
|
60
|
+
output: (frame) => {
|
|
61
|
+
if (this.#currentFrameRendered) {
|
|
62
|
+
this.#frameRendered += 1;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
this.#frameSkipped += 1;
|
|
66
|
+
}
|
|
67
|
+
this.#currentFrameRendered = false;
|
|
68
|
+
// PERF: Draw every frame to minimize latency at cost of performance.
|
|
69
|
+
// When multiple frames are drawn in one vertical sync interval,
|
|
70
|
+
// only the last one is visible to users.
|
|
71
|
+
// But this ensures users can always see the most up-to-date screen.
|
|
72
|
+
// This is also the behavior of official Scrcpy client.
|
|
73
|
+
// https://github.com/Genymobile/scrcpy/issues/3679
|
|
74
|
+
this.#updateSize(frame.displayWidth, frame.displayHeight);
|
|
75
|
+
this.#renderer.draw(frame);
|
|
76
|
+
},
|
|
77
|
+
error(e) {
|
|
78
|
+
if (controller) {
|
|
79
|
+
try {
|
|
80
|
+
controller.error(e);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// ignore
|
|
84
|
+
// `controller` may already in error state
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
error = e;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
switch (this.#codec) {
|
|
93
|
+
case ScrcpyVideoCodecId.H264:
|
|
94
|
+
this.#codecDecoder = new H264Decoder(this.#decoder, this.#updateSize);
|
|
95
|
+
break;
|
|
96
|
+
case ScrcpyVideoCodecId.H265:
|
|
97
|
+
this.#codecDecoder = new H265Decoder(this.#decoder, this.#updateSize);
|
|
98
|
+
break;
|
|
99
|
+
case ScrcpyVideoCodecId.AV1:
|
|
100
|
+
this.#codecDecoder = new Av1Codec(this.#decoder, this.#updateSize);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
let error;
|
|
104
|
+
let controller;
|
|
105
|
+
this.#writable = new WritableStream({
|
|
106
|
+
start: (_controller) => {
|
|
107
|
+
if (error) {
|
|
108
|
+
_controller.error(error);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
controller = _controller;
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
write: (packet) => {
|
|
115
|
+
this.#codecDecoder.decode(packet);
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
this.#onFramePresented();
|
|
119
|
+
}
|
|
120
|
+
#updateSize = (width, height) => {
|
|
121
|
+
if (width !== this.#canvas.width || height !== this.#canvas.height) {
|
|
122
|
+
this.#canvas.width = width;
|
|
123
|
+
this.#canvas.height = height;
|
|
124
|
+
this.#sizeChanged.fire({
|
|
125
|
+
width: width,
|
|
126
|
+
height: height,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
#onFramePresented = () => {
|
|
131
|
+
this.#currentFrameRendered = true;
|
|
132
|
+
this.#animationFrameId = requestAnimationFrame(this.#onFramePresented);
|
|
133
|
+
};
|
|
134
|
+
dispose() {
|
|
135
|
+
cancelAnimationFrame(this.#animationFrameId);
|
|
136
|
+
if (this.#decoder.state !== "closed") {
|
|
137
|
+
this.#decoder.close();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=decoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/video/decoder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/video/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/video/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitmap.d.ts","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,qBAAa,mBAAoB,YAAW,aAAa;;gBAGzC,MAAM,EAAE,iBAAiB;IAIrC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAchC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitmap.js","sourceRoot":"","sources":["../../../src/video/render/bitmap.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,mBAAmB;IAC5B,QAAQ,CAA8B;IAEtC,YAAY,MAAyB;QACjC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAE,CAAC;IAC3E,CAAC;IAED,IAAI,CAAC,KAAiB;QAClB,iBAAiB,CAAC,KAAK,CAAC;aACnB,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACb,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;YAC9C,KAAK,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,OAAO,CAAC,IAAI,CACR,uCAAuC,EACvC,oBAAoB,EACpB,CAAC,CACJ,CAAC;QACN,CAAC,CAAC,CAAC;IACX,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/video/render/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/video/render/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/video/render/type.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC1B,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CACjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type.js","sourceRoot":"","sources":["../../../src/video/render/type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FrameRenderer } from "./type.js";
|
|
2
|
+
export declare class WebGLFrameRenderer implements FrameRenderer {
|
|
3
|
+
#private;
|
|
4
|
+
static vertexShaderSource: string;
|
|
5
|
+
static fragmentShaderSource: string;
|
|
6
|
+
/**
|
|
7
|
+
* Create a new WebGL frame renderer.
|
|
8
|
+
* @param canvas The canvas to render frames to.
|
|
9
|
+
* @param enableCapture
|
|
10
|
+
* Whether to allow capturing the canvas content using APIs like `readPixels` and `toDataURL`.
|
|
11
|
+
* Enable this option may reduce performance.
|
|
12
|
+
*/
|
|
13
|
+
constructor(canvas: HTMLCanvasElement, enableCapture: boolean);
|
|
14
|
+
draw(frame: VideoFrame): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=webgl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgl.d.ts","sourceRoot":"","sources":["../../../src/video/render/webgl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,qBAAa,kBAAmB,YAAW,aAAa;;IACpD,MAAM,CAAC,kBAAkB,SAW3B;IAEE,MAAM,CAAC,oBAAoB,SAQ7B;IAIE;;;;;;OAMG;gBACS,MAAM,EAAE,iBAAiB,EAAE,aAAa,EAAE,OAAO;IAiE7D,IAAI,CAAC,KAAK,EAAE,UAAU;CAezB"}
|
|
@@ -1,34 +1,43 @@
|
|
|
1
1
|
export class WebGLFrameRenderer {
|
|
2
2
|
static vertexShaderSource = `
|
|
3
|
-
attribute vec2 xy;
|
|
3
|
+
attribute vec2 xy;
|
|
4
4
|
|
|
5
|
-
varying highp vec2 uv;
|
|
5
|
+
varying highp vec2 uv;
|
|
6
6
|
|
|
7
|
-
void main(void) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
7
|
+
void main(void) {
|
|
8
|
+
gl_Position = vec4(xy, 0.0, 1.0);
|
|
9
|
+
// Map vertex coordinates (-1 to +1) to UV coordinates (0 to 1).
|
|
10
|
+
// UV coordinates are Y-flipped relative to vertex coordinates.
|
|
11
|
+
uv = vec2((1.0 + xy.x) / 2.0, (1.0 - xy.y) / 2.0);
|
|
12
|
+
}
|
|
13
13
|
`;
|
|
14
14
|
static fragmentShaderSource = `
|
|
15
|
-
varying highp vec2 uv;
|
|
15
|
+
varying highp vec2 uv;
|
|
16
16
|
|
|
17
|
-
uniform sampler2D texture;
|
|
17
|
+
uniform sampler2D texture;
|
|
18
18
|
|
|
19
|
-
void main(void) {
|
|
20
|
-
|
|
21
|
-
}
|
|
19
|
+
void main(void) {
|
|
20
|
+
gl_FragColor = texture2D(texture, uv);
|
|
21
|
+
}
|
|
22
22
|
`;
|
|
23
23
|
#context;
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Create a new WebGL frame renderer.
|
|
26
|
+
* @param canvas The canvas to render frames to.
|
|
27
|
+
* @param enableCapture
|
|
28
|
+
* Whether to allow capturing the canvas content using APIs like `readPixels` and `toDataURL`.
|
|
29
|
+
* Enable this option may reduce performance.
|
|
30
|
+
*/
|
|
31
|
+
constructor(canvas, enableCapture) {
|
|
25
32
|
const gl = canvas.getContext("webgl2", {
|
|
26
33
|
alpha: false,
|
|
27
34
|
failIfMajorPerformanceCaveat: true,
|
|
35
|
+
preserveDrawingBuffer: enableCapture,
|
|
28
36
|
}) ||
|
|
29
37
|
canvas.getContext("webgl", {
|
|
30
38
|
alpha: false,
|
|
31
39
|
failIfMajorPerformanceCaveat: true,
|
|
40
|
+
preserveDrawingBuffer: enableCapture,
|
|
32
41
|
});
|
|
33
42
|
if (!gl) {
|
|
34
43
|
throw new Error("WebGL not supported");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgl.js","sourceRoot":"","sources":["../../../src/video/render/webgl.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yume-chan/scrcpy-decoder-webcodecs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "Raw H.264 stream decoder and renderer using WebCodecs API (requires modern browser).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adb",
|
|
@@ -27,27 +27,25 @@
|
|
|
27
27
|
"main": "esm/index.js",
|
|
28
28
|
"types": "esm/index.d.ts",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@yume-chan/event": "^0.0.
|
|
31
|
-
"@yume-chan/
|
|
32
|
-
"@yume-chan/scrcpy
|
|
33
|
-
"@yume-chan/
|
|
34
|
-
"
|
|
30
|
+
"@yume-chan/event": "^0.0.24",
|
|
31
|
+
"@yume-chan/no-data-view": "^0.0.24",
|
|
32
|
+
"@yume-chan/scrcpy": "^0.0.24",
|
|
33
|
+
"@yume-chan/scrcpy-decoder-tinyh264": "^0.0.24",
|
|
34
|
+
"@yume-chan/stream-extra": "^0.0.24"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@jest/globals": "^30.0.0-alpha.
|
|
37
|
+
"@jest/globals": "^30.0.0-alpha.4",
|
|
38
38
|
"@yume-chan/eslint-config": "^1.0.0",
|
|
39
39
|
"@yume-chan/tsconfig": "^1.0.0",
|
|
40
40
|
"cross-env": "^7.0.3",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"typescript": "^5.4.2"
|
|
41
|
+
"jest": "^30.0.0-alpha.4",
|
|
42
|
+
"prettier": "^3.3.2",
|
|
43
|
+
"ts-jest": "^29.1.4",
|
|
44
|
+
"typescript": "^5.4.5"
|
|
46
45
|
},
|
|
47
46
|
"scripts": {
|
|
48
47
|
"build": "tsc -b tsconfig.build.json",
|
|
49
48
|
"build:watch": "tsc -b tsconfig.build.json",
|
|
50
|
-
"
|
|
51
|
-
"lint": "eslint src/**/*.ts --fix && prettier src/**/*.ts --write --tab-width 4"
|
|
49
|
+
"lint": "run-eslint && prettier src/**/*.ts --write --tab-width 4"
|
|
52
50
|
}
|
|
53
51
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,247 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type {
|
|
3
|
-
ScrcpyMediaStreamDataPacket,
|
|
4
|
-
ScrcpyMediaStreamPacket,
|
|
5
|
-
} from "@yume-chan/scrcpy";
|
|
6
|
-
import {
|
|
7
|
-
ScrcpyVideoCodecId,
|
|
8
|
-
h264ParseConfiguration,
|
|
9
|
-
h265ParseConfiguration,
|
|
10
|
-
} from "@yume-chan/scrcpy";
|
|
11
|
-
import type {
|
|
12
|
-
ScrcpyVideoDecoder,
|
|
13
|
-
ScrcpyVideoDecoderCapability,
|
|
14
|
-
} from "@yume-chan/scrcpy-decoder-tinyh264";
|
|
15
|
-
import { WritableStream } from "@yume-chan/stream-extra";
|
|
16
|
-
|
|
17
|
-
import { BitmapFrameRenderer } from "./bitmap.js";
|
|
18
|
-
import type { FrameRenderer } from "./renderer.js";
|
|
19
|
-
import { WebGLFrameRenderer } from "./webgl.js";
|
|
20
|
-
|
|
21
|
-
function toHex(value: number) {
|
|
22
|
-
return value.toString(16).padStart(2, "0").toUpperCase();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function toUint32Le(data: Uint8Array, offset: number) {
|
|
26
|
-
return (
|
|
27
|
-
data[offset]! |
|
|
28
|
-
(data[offset + 1]! << 8) |
|
|
29
|
-
(data[offset + 2]! << 16) |
|
|
30
|
-
(data[offset + 3]! << 24)
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export class WebCodecsDecoder implements ScrcpyVideoDecoder {
|
|
35
|
-
static isSupported() {
|
|
36
|
-
return typeof globalThis.VideoDecoder !== "undefined";
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static readonly capabilities: Record<string, ScrcpyVideoDecoderCapability> =
|
|
40
|
-
{
|
|
41
|
-
h264: {},
|
|
42
|
-
h265: {},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
#codec: ScrcpyVideoCodecId;
|
|
46
|
-
get codec() {
|
|
47
|
-
return this.#codec;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
#writable: WritableStream<ScrcpyMediaStreamPacket>;
|
|
51
|
-
get writable() {
|
|
52
|
-
return this.#writable;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
#canvas: HTMLCanvasElement;
|
|
56
|
-
get renderer() {
|
|
57
|
-
return this.#canvas;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
#frameRendered = 0;
|
|
61
|
-
get frameRendered() {
|
|
62
|
-
return this.#frameRendered;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
#frameSkipped = 0;
|
|
66
|
-
get frameSkipped() {
|
|
67
|
-
return this.#frameSkipped;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
#sizeChanged = new EventEmitter<{ width: number; height: number }>();
|
|
71
|
-
get sizeChanged() {
|
|
72
|
-
return this.#sizeChanged.event;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
#decoder: VideoDecoder;
|
|
76
|
-
#config: Uint8Array | undefined;
|
|
77
|
-
#renderer: FrameRenderer;
|
|
78
|
-
|
|
79
|
-
#currentFrameRendered = false;
|
|
80
|
-
#animationFrameId = 0;
|
|
81
|
-
|
|
82
|
-
constructor(codec: ScrcpyVideoCodecId) {
|
|
83
|
-
this.#codec = codec;
|
|
84
|
-
|
|
85
|
-
this.#canvas = document.createElement("canvas");
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
this.#renderer = new WebGLFrameRenderer(this.#canvas);
|
|
89
|
-
} catch {
|
|
90
|
-
this.#renderer = new BitmapFrameRenderer(this.#canvas);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
this.#decoder = new VideoDecoder({
|
|
94
|
-
output: (frame) => {
|
|
95
|
-
if (this.#currentFrameRendered) {
|
|
96
|
-
this.#frameRendered += 1;
|
|
97
|
-
} else {
|
|
98
|
-
this.#frameSkipped += 1;
|
|
99
|
-
}
|
|
100
|
-
this.#currentFrameRendered = false;
|
|
101
|
-
|
|
102
|
-
// PERF: H.264 renderer may draw multiple frames in one vertical sync interval to minimize latency.
|
|
103
|
-
// When multiple frames are drawn in one vertical sync interval,
|
|
104
|
-
// only the last one is visible to users.
|
|
105
|
-
// But this ensures users can always see the most up-to-date screen.
|
|
106
|
-
// This is also the behavior of official Scrcpy client.
|
|
107
|
-
// https://github.com/Genymobile/scrcpy/issues/3679
|
|
108
|
-
this.#renderer.draw(frame);
|
|
109
|
-
},
|
|
110
|
-
error(e) {
|
|
111
|
-
console.warn(
|
|
112
|
-
"[@yume-chan/scrcpy-decoder-webcodecs]",
|
|
113
|
-
"VideoDecoder error",
|
|
114
|
-
e,
|
|
115
|
-
);
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
this.#writable = new WritableStream<ScrcpyMediaStreamPacket>({
|
|
120
|
-
write: (packet) => {
|
|
121
|
-
switch (packet.type) {
|
|
122
|
-
case "configuration":
|
|
123
|
-
this.#configure(packet.data);
|
|
124
|
-
break;
|
|
125
|
-
case "data":
|
|
126
|
-
this.#decode(packet);
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
this.#onFramePresented();
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
#onFramePresented = () => {
|
|
136
|
-
this.#currentFrameRendered = true;
|
|
137
|
-
this.#animationFrameId = requestAnimationFrame(this.#onFramePresented);
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
#configure(data: Uint8Array) {
|
|
141
|
-
switch (this.#codec) {
|
|
142
|
-
case ScrcpyVideoCodecId.H264: {
|
|
143
|
-
const {
|
|
144
|
-
profileIndex,
|
|
145
|
-
constraintSet,
|
|
146
|
-
levelIndex,
|
|
147
|
-
croppedWidth,
|
|
148
|
-
croppedHeight,
|
|
149
|
-
} = h264ParseConfiguration(data);
|
|
150
|
-
|
|
151
|
-
this.#canvas.width = croppedWidth;
|
|
152
|
-
this.#canvas.height = croppedHeight;
|
|
153
|
-
this.#sizeChanged.fire({
|
|
154
|
-
width: croppedWidth,
|
|
155
|
-
height: croppedHeight,
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// https://www.rfc-editor.org/rfc/rfc6381#section-3.3
|
|
159
|
-
// ISO Base Media File Format Name Space
|
|
160
|
-
const codec = `avc1.${[profileIndex, constraintSet, levelIndex]
|
|
161
|
-
.map(toHex)
|
|
162
|
-
.join("")}`;
|
|
163
|
-
this.#decoder.configure({
|
|
164
|
-
codec: codec,
|
|
165
|
-
optimizeForLatency: true,
|
|
166
|
-
});
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
case ScrcpyVideoCodecId.H265: {
|
|
170
|
-
const {
|
|
171
|
-
generalProfileSpace,
|
|
172
|
-
generalProfileIndex,
|
|
173
|
-
generalProfileCompatibilitySet,
|
|
174
|
-
generalTierFlag,
|
|
175
|
-
generalLevelIndex,
|
|
176
|
-
generalConstraintSet,
|
|
177
|
-
croppedWidth,
|
|
178
|
-
croppedHeight,
|
|
179
|
-
} = h265ParseConfiguration(data);
|
|
180
|
-
|
|
181
|
-
this.#canvas.width = croppedWidth;
|
|
182
|
-
this.#canvas.height = croppedHeight;
|
|
183
|
-
this.#sizeChanged.fire({
|
|
184
|
-
width: croppedWidth,
|
|
185
|
-
height: croppedHeight,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
const codec = [
|
|
189
|
-
"hev1",
|
|
190
|
-
["", "A", "B", "C"][generalProfileSpace]! +
|
|
191
|
-
generalProfileIndex.toString(),
|
|
192
|
-
toUint32Le(generalProfileCompatibilitySet, 0).toString(16),
|
|
193
|
-
(generalTierFlag ? "H" : "L") +
|
|
194
|
-
generalLevelIndex.toString(),
|
|
195
|
-
toUint32Le(generalConstraintSet, 0)
|
|
196
|
-
.toString(16)
|
|
197
|
-
.toUpperCase(),
|
|
198
|
-
toUint32Le(generalConstraintSet, 4)
|
|
199
|
-
.toString(16)
|
|
200
|
-
.toUpperCase(),
|
|
201
|
-
].join(".");
|
|
202
|
-
this.#decoder.configure({
|
|
203
|
-
codec,
|
|
204
|
-
optimizeForLatency: true,
|
|
205
|
-
});
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
this.#config = data;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
#decode(packet: ScrcpyMediaStreamDataPacket) {
|
|
213
|
-
if (this.#decoder.state !== "configured") {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// WebCodecs requires configuration data to be with the first frame.
|
|
218
|
-
// https://www.w3.org/TR/webcodecs-avc-codec-registration/#encodedvideochunk-type
|
|
219
|
-
let data: Uint8Array;
|
|
220
|
-
if (this.#config !== undefined) {
|
|
221
|
-
data = new Uint8Array(
|
|
222
|
-
this.#config.byteLength + packet.data.byteLength,
|
|
223
|
-
);
|
|
224
|
-
data.set(this.#config, 0);
|
|
225
|
-
data.set(packet.data, this.#config.byteLength);
|
|
226
|
-
this.#config = undefined;
|
|
227
|
-
} else {
|
|
228
|
-
data = packet.data;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
this.#decoder.decode(
|
|
232
|
-
new EncodedVideoChunk({
|
|
233
|
-
// Treat `undefined` as `key`, otherwise won't decode.
|
|
234
|
-
type: packet.keyframe === false ? "delta" : "key",
|
|
235
|
-
timestamp: 0,
|
|
236
|
-
data,
|
|
237
|
-
}),
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
dispose() {
|
|
242
|
-
cancelAnimationFrame(this.#animationFrameId);
|
|
243
|
-
if (this.#decoder.state !== "closed") {
|
|
244
|
-
this.#decoder.close();
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
1
|
+
export * from "./video/index.js";
|