-
Notifications
You must be signed in to change notification settings - Fork 143
/
Copy pathworker.js
104 lines (91 loc) · 2.68 KB
/
worker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
importScripts("demuxer_mp4.js", "renderer_2d.js", "renderer_webgl.js", "renderer_webgpu.js");
// Status UI. Messages are batched per animation frame.
let pendingStatus = null;
function setStatus(type, message) {
if (pendingStatus) {
pendingStatus[type] = message;
} else {
pendingStatus = {[type]: message};
self.requestAnimationFrame(statusAnimationFrame);
}
}
function statusAnimationFrame() {
self.postMessage(pendingStatus);
pendingStatus = null;
}
// Rendering. Drawing is limited to once per animation frame.
let renderer = null;
let pendingFrame = null;
let startTime = null;
let frameCount = 0;
function renderFrame(frame) {
if (!pendingFrame) {
// Schedule rendering in the next animation frame.
requestAnimationFrame(renderAnimationFrame);
} else {
// Close the current pending frame before replacing it.
pendingFrame.close();
}
// Set or replace the pending frame.
pendingFrame = frame;
}
function renderAnimationFrame() {
renderer.draw(pendingFrame);
pendingFrame = null;
}
// Startup.
function start({dataUri, rendererName, canvas}) {
// Pick a renderer to use.
switch (rendererName) {
case "2d":
renderer = new Canvas2DRenderer(canvas);
break;
case "webgl":
renderer = new WebGLRenderer(rendererName, canvas);
break;
case "webgl2":
renderer = new WebGLRenderer(rendererName, canvas);
break;
case "webgpu":
renderer = new WebGPURenderer(canvas);
break;
}
let lastTimestamp = -Infinity;
// Set up a VideoDecoer.
const decoder = new VideoDecoder({
output(frame) {
// Update statistics.
if (startTime == null) {
startTime = performance.now();
} else {
const elapsed = (performance.now() - startTime) / 1000;
const fps = ++frameCount / elapsed;
setStatus("render", `${fps.toFixed(0)} fps`);
}
if (frame.timestamp < lastTimestamp) {
console.error(`Decoded frame ${frame.timestamp} µs out of order, last frame was ${lastTimestamp} µs`);
} else {
console.log(`Decoded frame ${frame.timestamp} µs`);
}
lastTimestamp = frame.timestamp;
// Schedule the frame to be rendered.
renderFrame(frame);
},
error(e) {
setStatus("decode", e);
}
});
// Fetch and demux the media data.
const demuxer = new MP4Demuxer(dataUri, {
onConfig(config) {
setStatus("decode", `${config.codec} @ ${config.codedWidth}x${config.codedHeight}`);
decoder.configure(config);
},
onChunk(chunk) {
decoder.decode(chunk);
},
setStatus
});
}
// Listen for the start request.
self.addEventListener("message", message => start(message.data), {once: true});