Skip to content

Commit ac131dc

Browse files
committed
Optimize VideoStreamerChunked.js with zero copy views
1 parent 909e20e commit ac131dc

1 file changed

Lines changed: 41 additions & 41 deletions

File tree

examples/VideoStreamerChunked.js

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,32 @@
1-
/* This is an example of sync copying of large files.
2-
* NEVER DO THIS; ONLY FOR TESTING PURPOSES. WILL CAUSE
3-
* SEVERE BACKPRESSURE AND HORRIBLE PERFORMANCE.
4-
* Try navigating to the adderss with Chrome and see the video
5-
* in real time. */
6-
71
const uWS = require('uWebSockets.js');
82
const fs = require('fs');
93

104
const port = 9001;
11-
const fileName = 'spritefright.mp4';
12-
const videoFile = toArrayBuffer(fs.readFileSync(fileName));
13-
const totalSize = videoFile.byteLength;
5+
const fileName = 'Sintel.2010.1080p.mkv';
6+
7+
/**
8+
* Optimized to return a Uint8Array view of the Node.js Buffer
9+
* without creating a new ArrayBuffer copy.
10+
*/
11+
function getFileView(name) {
12+
const buffer = fs.readFileSync(name);
13+
// This creates a Uint8Array pointing to the EXACT same memory Node.js allocated
14+
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
15+
}
16+
17+
const videoView = getFileView(fileName);
18+
const totalSize = videoView.byteLength;
1419

1520
console.log('WARNING: NEVER DO LIKE THIS; WILL CAUSE HORRIBLE BACKPRESSURE!');
1621
console.log('Video size is: ' + totalSize + ' bytes');
1722

18-
const CHUNK_SIZE = 1024 * 64;
23+
const CHUNK_SIZE = 1024 * 256;
1924

20-
/* Helper function converting Node.js buffer to ArrayBuffer */
21-
function toArrayBuffer(buffer) {
22-
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
23-
}
24-
25-
/* Yes, you can easily swap to SSL streaming by uncommenting here */
2625
const app = uWS.App({
27-
key_file_name: 'misc/key.pem',
28-
cert_file_name: 'misc/cert.pem',
29-
passphrase: '1234'
30-
31-
}).get('/spritefright.mp4', (res, req) => {
26+
key_file_name: 'misc/key.pem',
27+
cert_file_name: 'misc/cert.pem',
28+
passphrase: '1234'
29+
}).get('/spritefright.mkv', (res, req) => {
3230
let aborted = false;
3331
let written = 0;
3432

@@ -39,42 +37,44 @@ const app = uWS.App({
3937
const stream = () => {
4038
let ok = true;
4139

42-
// Use res.cork to pack multiple small writes into one syscall
4340
res.cork(() => {
44-
while (ok && written < videoFile.byteLength) {
45-
let chunk = videoFile.slice(written, Math.min(written + CHUNK_SIZE, videoFile.byteLength));
41+
while (ok && written < totalSize) {
42+
const end = Math.min(written + CHUNK_SIZE, totalSize);
4643

47-
// If this is the last chunk, use end() instead of write()
48-
if (written + chunk.byteLength === videoFile.byteLength) {
49-
res.end(chunk);
50-
written += chunk.byteLength;
51-
ok = false; // Stop the loop
44+
/**
45+
* .subarray() is a PURE VIEW.
46+
* No new memory is allocated for the file data here.
47+
*/
48+
const chunk = videoView.subarray(written, end);
49+
50+
if (end === totalSize) {
51+
res.write(chunk);
52+
res.end();
53+
written = totalSize;
54+
ok = false;
5255
} else {
5356
ok = res.write(chunk);
54-
written += chunk.byteLength;
57+
written = end;
5558
}
5659
}
5760
});
5861

5962
return ok;
6063
};
6164

62-
// Initial attempt to stream
6365
let ok = stream();
6466

65-
// If we hit backpressure, set up the drain handler
66-
if (!ok && !aborted && written < videoFile.byteLength) {
67+
if (!ok && !aborted && written < totalSize) {
6768
res.onWritable((offset) => {
6869
return stream();
6970
});
7071
}
7172
}).get('/*', (res, req) => {
72-
/* Make sure to always handle every route */
73-
res.end('Nothing to see here!');
73+
res.end('Nothing to see here!');
7474
}).listen(port, (token) => {
75-
if (token) {
76-
console.log('Listening to port ' + port);
77-
} else {
78-
console.log('Failed to listen to port ' + port);
79-
}
80-
});
75+
if (token) {
76+
console.log('Listening to port ' + port);
77+
} else {
78+
console.log('Failed to listen to port ' + port);
79+
}
80+
});

0 commit comments

Comments
 (0)