Add video-file playback to HTMLVideoElement (src) for VideoTexture#1770
Add video-file playback to HTMLVideoElement (src) for VideoTexture#1770julapy wants to merge 2 commits into
Conversation
Adds a platform VideoPlayer abstraction (VideoPlayer.h) plus an Apple implementation backed by AVPlayer + AVPlayerItemVideoOutput. Frames are requested as BGRA (no YUV conversion needed), viewed zero-copy through a CVMetalTextureCache and blitted into a persistent MTLTexture, which is wired to Babylon's InternalTexture with the same bgfx::overrideInternal-on-render- thread retry pattern as CameraDevice::UpdateCameraTexture. Each player instance owns its own decoder and texture, so any number of videos can play simultaneously. URLs may be app:///<bundle-relative>, absolute file paths, or http(s). Playback control (play/pause/loop/muted/volume/seek) and metadata (duration/currentTime/dimensions) are exposed for the JS layer; end-of-stream loops via seek-to-zero or reports Ended. Event callbacks may fire on any thread and are documented as caller-marshalled. This is the decode/GPU half of HTMLVideoElement.src support. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…API) Extends the HTMLVideoElement polyfill so a video file/URL can be played and its frames rendered into the Babylon scene, alongside the existing srcObject (camera MediaStream) source. Assigning src creates a VideoPlayer; the two sources are mutually exclusive, matching the web API. Implements the HTMLVideoElement surface Babylon.js's VideoTexture and typical app code use: src, currentTime (get/seek), duration, loop, muted, paused, ended, videoWidth/videoHeight, plus events (loadedmetadata, loadeddata, canplay, playing, pause, seeked, ended, resize). isNative is reported so VideoTexture accepts the element directly. VideoPlayer event callbacks are marshalled onto the JS thread via JsRuntime::Dispatch; the element holds a self-reference while it owns a source so it stays alive during playback. UpdateTexture pulls decoded frames each render frame and raises resize on dimension changes. Babylon.js is unmodified: new BABYLON.VideoTexture(name, videoElement, scene) with videoElement.src set works as on the web, including multiple simultaneous videos. Verified on device (iPhone 15 Pro Max, iOS 26.5) with two independent looping videos plus an out-of-phase seek at 60 FPS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Latest bgfx can do hardware video decoding on D3D11, D3D12, Vulkan, and Metal. You might want to check that feature so that feature it's not macOS only. |
|
hi @bkaradzic-microsoft - "latest bgfx" - is that already in BN and is it just a matter of hooking up video decoding? |
|
Yes, bgfx is the rendering abstraction (over D3D, OpenGL, Vulkan, Metal) that Babylon Native uses. |
|
@julapy I need sync with latest and then HW video decoding will be available in BN. |
|
@julapy I updated CMake to get latest bgfx which has HW video decoder support. You would need to enable BabylonNative/Dependencies/CMakeLists.txt Line 71 in d45b303 And there is example of video player: |
|
@bkaradzic-microsoft thanks for syncing bgfx and pointing me at the gate + the texturev player — I went through If I've read it right: Two questions before I go there, since
Depending on the answers, my thinking would be: keep |
What
Adds video-file playback to
HTMLVideoElement, so Babylon.js content can play a video file/URL and use its frames as aVideoTexture— the same web API, unmodified Babylon.js:Previously the
HTMLVideoElementpolyfill only supportedsrcObject(a cameraMediaStream). This adds thesrcpath alongside it; the two sources are mutually exclusive, matching the web. Any number of videos can play simultaneously (each element owns its own decoder + texture).How
Commit 1 — VideoPlayer backend:
VideoPlayer.h: a small platform abstraction (play/pause/loop/muted/volume/seek, duration/currentTime/dimensions, per-frameUpdateTexture, and load/ended/seeked events).Apple/VideoPlayer.mm:AVPlayer+AVPlayerItemVideoOutputrequesting BGRA frames (no YUV pass), viewed zero-copy viaCVMetalTextureCacheand blitted into a persistentMTLTexture, wired to Babylon'sInternalTexturewith the samebgfx::overrideInternal-on-render-thread retry pattern asCameraDevice::UpdateCameraTexture. Loops via seek-to-zero.Commit 2 — HTMLVideoElement.src:
NativeVideowithsrc,currentTime(get/seek),duration,loop,muted,paused,ended,isNative, and events (loadedmetadata/loadeddata/canplay/playing/pause/seeked/ended/resize). Player callbacks (which may fire on any thread) are marshalled onto the JS thread viaJsRuntime::Dispatch; the element self-references while it owns a source so it isn't collected mid-playback.UpdateTextureroutes to the camera stream or the video player depending on the active source.Only the Apple backend is implemented here; other platforms return
nullptrfromVideoPlayer::Create(video src is a no-op,srcObject/camera unaffected).Testing
Verified on device (iPhone 15 Pro Max, iOS 26.5, Xcode 26, Babylon.js 9.9.1 UMD) via the iOS Playground: a 2000×2000 h264 clip on two independent
HTMLVideoElements, both looping, one seeked out of phase mid-run to exercise the control API — sustained 60 FPS (~1 ms GPU). Also runs concurrently with an activeimmersive-arsession and WebXR raw-camera-access plane in the same scene.🤖 Generated with Claude Code