-
Notifications
You must be signed in to change notification settings - Fork 5
/
encoder-worker.js
113 lines (107 loc) · 4.72 KB
/
encoder-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
105
106
107
108
109
110
111
112
113
function onerror(e) {
console.error(e);
self.postMessage({
type: 'error',
detail: e.message
});
}
onmessage = async function (e) {
const msg = e.data;
switch (msg.type) {
case 'start':
try {
const Encoder = msg.audio ? AudioEncoder : VideoEncoder;
const type = msg.audio ? 'audio-data' : 'video-data';
let key_frame_interval = msg.audio ? 0 : msg.key_frame_interval;
if (key_frame_interval > 0) {
if (msg.count_frames) {
if (!msg.config.framerate) {
throw new Error('framerate not configured');
}
} else {
key_frame_interval *= 1000000;
}
}
let encoder;
if (msg.config.codec !== 'pcm') {
encoder = new Encoder({
output: chunk => {
const data = new ArrayBuffer(chunk.byteLength);
chunk.copyTo(data);
self.postMessage({
type,
timestamp: chunk.timestamp,
duration: chunk.duration,
is_key: msg.audio || chunk.type === 'key',
data
}, [data]);
},
error: onerror
});
await encoder.configure(msg.config);
}
const reader = msg.readable.getReader();
let last_key_frame = -1;
let frame_count = 0;
while (true) {
const result = await reader.read();
if (result.done) {
if (encoder) {
await encoder.flush();
}
self.postMessage({ type: 'exit' });
break;
}
if (msg.audio) {
if (encoder) {
encoder.encode(result.value);
} else if (result.value.format !== 'f32-planar') {
throw new Error(`unexpected audio format: ${result.value.format}`);
} else {
// Convert from planar to interleaved
const nc = result.value.numberOfChannels;
let total_size = 0;
const bufs = [];
for (let i = 0; i < nc; ++i) {
const options = { planeIndex: i };
const size = result.value.allocationSize(options);
total_size += size;
const buf = new ArrayBuffer(size);
result.value.copyTo(buf, options);
bufs.push(buf);
}
const data = new ArrayBuffer(total_size);
const buf = new Uint8Array(data);
for (let i = 0; i < total_size; i += 4) {
const d = i / 4;
buf.set(new Uint8Array(bufs[Math.floor(d) % nc], Math.floor(d / nc) * 4, 4), i);
}
self.postMessage({
type,
timestamp: result.value.timestamp,
duration: result.value.duration,
is_key: true,
data
}, [data]);
}
} else {
let keyFrame = false;
if (key_frame_interval > 0) {
if (msg.count_frames) {
keyFrame = frame_count++ % (msg.config.framerate * key_frame_interval) == 0;
} else if ((last_key_frame < 0) ||
((result.value.timestamp - last_key_frame) > key_frame_interval)) {
keyFrame = true;
last_key_frame = result.value.timestamp;
}
}
encoder.encode(result.value, { keyFrame });
}
result.value.close();
}
} catch (ex) {
onerror(ex);
}
break;
}
};