-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Copy pathvideo-export.html
108 lines (86 loc) · 3.1 KB
/
video-export.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
104
105
106
107
108
<!DOCTYPE html>
<html>
<head>
<title>Mapbox GL JS debug page</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel='stylesheet' href='../dist/mapbox-gl.css' />
<style>
#map { width: 960px; height: 540px; }
</style>
</head>
<body>
<div id='map'></div>
<script src='../dist/mapbox-gl-dev.js'></script>
<script src='../debug/access_token_generated.js'></script>
<script type="module">
import loadEncoder from 'https://unpkg.com/[email protected]/build/mp4-encoder.js';
import {simd} from "https://unpkg.com/wasm-feature-detect?module";
const map = window.map = new mapboxgl.Map({
container: 'map',
devtools: true,
center: [7.533634776071096, 45.486077107185565],
zoom: 13.5,
pitch: 61,
bearing: -160,
style: 'mapbox://styles/mapbox/satellite-v9'
});
async function animate() {
// do all the animations you need to record here
map.easeTo({
bearing: map.getBearing() - 20,
duration: 3000,
easing: t => t
});
// wait for animation to finish
await map.once('moveend');
}
map.on('load', async () => {
map.addSource('dem', {type: 'raster-dem', url: 'mapbox://mapbox.mapbox-terrain-dem-v1'});
map.setTerrain({source: 'dem', exaggeration: 1.5});
// wait until the map settles
await map.once('idle');
// uncomment to fine-tune animation without recording:
// animate(); return;
// don't forget to enable WebAssembly SIMD in chrome://flags for faster encoding
const supportsSIMD = await simd();
// initialize H264 video encoder
const Encoder = await loadEncoder({simd: supportsSIMD});
const gl = map.painter.context.gl;
const width = gl.drawingBufferWidth;
const height = gl.drawingBufferHeight;
const encoder = Encoder.create({
width,
height,
fps: 60,
kbps: 64000,
rgbFlipY: true
});
// stub performance.now for deterministic rendering per-frame (only available in dev build)
let now = performance.now();
mapboxgl.setNow(now);
const ptr = encoder.getRGBPointer(); // keep a pointer to encoder WebAssembly heap memory
function frame() {
// increment stub time by 16.6ms (60 fps)
now += 1000 / 60;
mapboxgl.setNow(now);
const pixels = encoder.memory().subarray(ptr); // get a view into encoder memory
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels); // read pixels into encoder
encoder.encodeRGBPointer(); // encode the frame
}
map.on('render', frame); // set up frame-by-frame recording
await animate(); // run all the animations
// stop recording
map.off('render', frame);
mapboxgl.restoreNow();
// download the encoded video file
const mp4 = encoder.end();
const anchor = document.createElement("a");
anchor.href = URL.createObjectURL(new Blob([mp4], {type: "video/mp4"}));
anchor.download = "mapbox-gl";
anchor.click();
// make sure to run `ffmpeg -i mapbox-gl.mp4 mapbox-gl-optimized.mp4` to compress the video
});
</script>
</body>
</html>