-
Notifications
You must be signed in to change notification settings - Fork 53
/
live.html
103 lines (96 loc) · 3.03 KB
/
live.html
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
<!--
Copyright 2018 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE html>
<h1>Live webm wasm demo</h1>
<button id="go">Go</button>
<script>
const framerate = 30;
const bitrate = 200;
const width = 400;
const height = 400;
function createBufferURL(buffer, type = '') {
return URL.createObjectURL(new Blob([buffer], {type}));
}
function cameraStream({ width, height }) {
return new ReadableStream({
async start(controller) {
const cvs = document.createElement("canvas");
const video = document.createElement("video");
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: { ideal: width },
height: { ideal: height }
},
audio: false
});
video.srcObject = stream;
video.play();
await nextEvent(video, "playing");
[cvs.width, cvs.height] = [width, height];
const ctx = cvs.getContext("2d");
const frameTimeout = 1000 / framerate;
setTimeout(async function f() {
ctx.drawImage(video, 0, 0);
await controller.enqueue(
ctx.getImageData(0, 0, width, height)
);
setTimeout(f, frameTimeout);
}, frameTimeout);
}
});
}
// Returns the next <name> event of `target`.
function nextEvent(target, name) {
return new Promise(resolve => {
target.addEventListener(name, resolve, { once: true });
});
}
async function init() {
const worker = new Worker("../dist/webm-worker.js");
worker.postMessage("./webm-wasm.wasm");
await nextEvent(worker, "message");
worker.postMessage({
width,
height,
realtime: true
});
cameraStream({width, height})
.pipeTo(new WritableStream({
write(image) {
worker.postMessage(image.data.buffer, [image.data.buffer]);
}
}));
const mediaSource = new MediaSource();
mediaSource.onsourceopen = () => {
const sourceBuffer = mediaSource.addSourceBuffer(`video/webm; codecs="vp8"`);
worker.onmessage = ev => {
if(!ev.data) {
return mediaSource.endOfStream();
}
sourceBuffer.appendBuffer(ev.data);
};
};
const video = document.createElement("video");
video.muted = true;
video.autoplay = true;
video.loop = true;
video.controls = true;
video.src = URL.createObjectURL(mediaSource);
document.body.append(video);
video.play();
}
document.all.go.onclick = ev => {
ev.target.remove();
init();
};
</script>