Inspiration
I built this app for two key reasons: existing video players on the Meta platform offer very limited hand-tracking controls, and most have trouble rendering advanced, vector-based subtitle formats—leaving much of the foreign-language video content difficult to watch.
What it does
Emei VR Video Player is a video player designed for smooth playback of users videos stored locally, on network shares, and on USB devices.
Features
- Metadata and thumbnail caching
- Automatic video aspect/shape detection
- Support for flat, 3D stereo (FSBS, HSBS, HOU, OU), and equirectangular formats (180, 180SBS, 180OU, 360, 360OU)
- Curved-screen viewing mode
- USB OTG exFat/NTFS support
- SMB and WebDAV streaming support
- Accurate, fully-featured SSA subtitle rendering
- Full control via controller or hand tracking
- Comprehensive video player controls: play/pause/seek, chapters, playback speed, image filters (brightness/contrast/saturation/gamma), and audio/subtitle/video track selection
- Dedicated subtitle display mode for 3D stereo videos (subtitles rendered outside the video panel)
- Saving playback state and tracks preferences per video
How we built it
The app is built using the Meta Spatial SDK. Alongside that, I rely on several Kotlin libraries to support the various storage types:
- smbj and for SMB network access
- NanoHTTPD for running a lightweight local HTTP proxy so the player can access SMB and USB files via HTTP
- libaums for USB NTFS/exFAT storage support
Challenges we ran into
Implementing USB support was a challenge. Because Meta Quest doesn't support external storage natively I had to use library for it. Unfortunately libaums USB library does not support random access, and my attempts to add it manually didn’t perform well. To solve this, I began proxying USB files through a local HTTP server, allowing me to use HTTP range requests for proper video seeking.
One feature I’m disappointed I couldn’t ship is the wrist-mounted hand-tracking UI. I had a prototype where the control panel would appear on the user’s wrist when they looked at it. Unfortunately, actually “finger-clicking” buttons this way felt too unreliable to include.
The biggest ongoing issue is that a handful of videos — always low/medium quality H.264 encodes — sometimes trigger Android MediaCodec errors. I mitigated this by falling back to software decoding for lower-bitrate videos.
Accomplishments that we're proud of
I’m proud of building this app at all. As a web developer, this hackathon was essentially my first real dive into the Android ecosystem. A year ago, I wanted to create something similar in Unity but found it too difficult. Thanks to Meta’s Spatial SDK, I finally brought the idea to life.
What we learned
I learned a great deal about video codecs, video configuration, Kotlin pitfalls, Jetpack Composables styling.
What's next for Emei VR Video Player
So far, I’ve only implemented the “video player” portion of my vision. In the future, I want to add:
- Fully 3D environments inside the app
- A built-in web browser
- Support for more network and cloud storage options
- Ambient lighting around the video panel
I also plan to continue improving the UI and add support for adjustable panel distances, so users can switch between a cinematic viewing mode and a more intimate “hold the screen in your hands” mode.
Built With
- coil
- compose
- jetpack
- jni
- koin
- kotlin
- libaums
- metaspatial
- roomdb
- smbj
- spatialsdk

Log in or sign up for Devpost to join the conversation.