Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an example of frame-by-frame video export #10172

Merged
merged 3 commits into from
Dec 10, 2020
Merged

Add an example of frame-by-frame video export #10172

merged 3 commits into from
Dec 10, 2020

Conversation

mourner
Copy link
Member

@mourner mourner commented Dec 9, 2020

Ref #5297. I'm adding this as a debug page for now, but will work on a more fleshed-out official example in the docs. The approach can be used with v1 as well.

This uses @mattdesl's excellent new WebAssembly-powered H264-MP4 encoder library to record a predefined GL JS animation frame-by-frame into a 1920x1080 60fps, buttery smooth zero-jank video download.

The sizes produced are quite big, so results need to be re-encoded with ffmpeg -i video.mp4 video2.mp4 (see mattdesl/mp4-h264#4). To make the export ~2x faster, turn on WebAssembly SIMD feature in chrome://flags.

The most tricky part of the approach is that we need to hijack GL JS's browser.now utility used for all animation timings, making it grow with 60fps-adjusted fixed increments on every frame to produce a natural video. Currently the methods for this are only exposed in the mapbox-gl-dev.js build, but I think we should expose it in production build specifically for video export purposes. cc @arindam1993 (update: exposed the methods in second commit).

I've also experimented with using some cool new ES patterns in the demo like in-browser ES modules, async/await and Promises to get a feel for it, and it's super great — we should definitely explore API improvements in this area. I've made subtle eslint config changes for the debug folder to accommodate this page while not affecting other pages.

@mourner mourner mentioned this pull request Dec 9, 2020
Copy link
Contributor

@ryanhamley ryanhamley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome! Great work Vlad.

I've also experimented with using some cool new ES patterns in the demo like in-browser ES modules, async/await and Promises to get a feel for it, and it's super great — we should definitely explore API improvements in this area.

The new render test suite makes use of async/await and I like it quite a bit. I'd be excited to make some updates in this area. I think the docs team is also on board with updating our examples to ES code.


// stub performance.now for deterministic rendering per-frame (only available in dev build)
let now = performance.now();
mapboxgl.setNow(now);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only available with dev builds, I believe. This example isn't directly usable with the built version of GL JS on CDN or NPM. That's fine for this debug page, but it's good to note.

Copy link
Member Author

@mourner mourner Dec 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ryanhamley yes, I mentioned this in the PR description and the code comment above.

Copy link
Member Author

@mourner mourner Dec 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added another commit that documents & exposes these methods in production build, so we can add the official example after this gets into a release. Note that it no longer falls back to Date.now because it should be universally supported now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops I missed that in the PR description.

Note that it no longer falls back to Date.now because it should be universally supported now.

👍 awesome

src/index.js Outdated Show resolved Hide resolved
Copy link
Contributor

@ryanhamley ryanhamley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. I think we just need to update the docs comment for restoreNow

Copy link
Contributor

@arindam1993 arindam1993 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me, this is an amazing example!

One cool way to extend this would be to add some kind of idle_but_animating event that fires while animating, but after all tile loads and placement has finished for that animation frame.
This wouldn't be possible with easeTo /flyTo but should be possible with camera API or jumpTo
jumpTo/setFreeCameraOptions -> setNow -> await idle -> record frame -> repeat

@josuelmm
Copy link

Any example about this?

@jing-tw
Copy link

jing-tw commented Sep 2, 2023

I tried the https://github.com/mapbox/mapbox-gl-js/blob/main/debug/video-export.html. However, the saved mp4 file only has few bytes and cannot open it. I don't know why?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants