Repository navigation
Client-side media: Generate a local poster during video upload - #79406
adamsilverstein wants to merge 9 commits into
Conversation
Add poster-utils.ts with getPosterFromVideo(), which extracts the first usable still frame of a video client-side using HTMLVideoElement and an OffscreenCanvas. Seeks slightly past the start to avoid an empty frame and falls back to JPEG where WebP is unsupported. No new dependencies.
Add AddPoster and UploadPoster operations to the upload pipeline. For video uploads, prepareItem now queues AddPoster -> Upload -> UploadPoster: - addPosterForItem generates a poster from the video's first frame (best-effort; on failure the video uploads without a poster). - uploadPosterForItem uploads the poster as its own image attachment and pushes its URL to the video block via onChange, setting the block's poster attribute. The poster upload runs independently so the video item completes immediately. The Video block's onSelectVideo now reads media.poster (set by the upload pipeline) in addition to the media-library media.image.src. Fixes #79366.
Unit tests cover the prepareItem video operation sequence and the addPosterForItem/uploadPosterForItem handlers (success, graceful failure, and no-op paths). The e2e test generates a short WebM at runtime via MediaRecorder (so no binary fixture of uncertain provenance is committed), uploads it into a Video block, and asserts the block gains a real poster image URL.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: +622 B (+0.01%) Total Size: 7.92 MB 📦 View Changed
|
…eration # Conflicts: # packages/upload-media/src/store/private-actions.ts # packages/upload-media/src/store/test/private-actions.js # test/e2e/specs/editor/various/client-side-media-processing.spec.js
|
Flaky tests detected in fde9b21. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/31613185208 can use focal point picker to set the focal point of the cover image in
|
# Conflicts: # packages/upload-media/src/store/private-actions.ts # packages/upload-media/src/store/test/private-actions.js # test/e2e/specs/editor/various/client-side-media-processing.spec.js
🤖 PR meta 🤖📦 Bundle sizeSize Change: +629 B (+0.01%) Total Size: 8.21 MB 📦 View Changed
⚡ PerformanceShow the resultsClient side metrics exclude the server response time. front-end-block-theme
front-end-classic-theme
media-processing
media-upload
post-editor
site-editor
|
What
Generates a poster image from a video's first frame, client-side, during upload, and applies it to the Video block automatically.
Closes #79366. Part of #76756.
Why
When a video is uploaded there is no poster to show until the video itself loads, so the area can render blank/late, hurting perceived performance and layout stability. Producing a poster from the first frame at upload time lets the page render meaningful content immediately, and the poster is serialized into the block so it persists.
The original issue assumed we could reuse the poster step from the GIF-to-video work (#76942 / #78410). In practice that step runs vips on a GIF's first frame (a still-image decode) and cannot decode a real video, so there was no reusable video-frame extractor to build on. This PR adds a small, dependency-free extractor instead (the approach proven in
swissspidy/media-experiments), and is implemented independently ontrunk.How
In
@wordpress/upload-media:poster-utils.tswithgetPosterFromVideo()— loads the video, seeks slightly past the start (to avoid an empty first frame), draws it to anOffscreenCanvas, and returns a JPEGFile. No new dependencies.AddPosterandUploadPoster. For video uploads,prepareItemqueuesAddPoster -> Upload -> UploadPoster:addPosterForItemgenerates the poster (best-effort: if the browser can't decode a frame, the video uploads with no poster).uploadPosterForItemuploads the poster as its own image attachment and pushes its URL to the block viaonChange, setting the block'sposterattribute. The poster upload runs independently so the video item completes immediately.In
@wordpress/block-library, the Video block'sonSelectVideonow readsmedia.poster(set by the upload pipeline) in addition to the media-librarymedia.image.src.Graceful fallback
Frame extraction is fully guarded; an unplayable codec, a seek timeout, or a missing canvas context results in no poster and a normal upload.
Note on
featured_mediaLinking the poster as the video attachment's
featured_media(so it is also exposed via the REST API / media library) is intentionally left as a follow-up:@wordpress/upload-mediadelegates all server I/O to injectedsettingscallbacks and has no direct REST dependency, and the poster already persists via the block'sposterattribute in post content. Happy to add it here if reviewers prefer, via a new settings callback.Testing Instructions
posterattribute and<video poster="...">renders it.Automated tests
npx wp-scripts test-unit-js packages/upload-media/src/store/test/private-actions.js— covers the video op sequence and the poster handlers (success, graceful failure, no-op).client-side-media-processing.spec.jsadds a test that generates a short WebM at runtime viaMediaRecorder(so no binary fixture is committed), uploads it, and asserts the block gets a real poster image URL.