Back to blog
6 min read
How to Stream HDR10 MV-HEVC Over HLS

SDR Vs HDR

Many SpatialGen customers have requested HDR10 streaming. So much in fact that we built email rules to filter the messages into a folder.

The reasons are painfully obvious in the comparison above. An SDR rendering of the same video is on the left and HDR10 on the right (credit to Hugh Hou and Keeley Turner). HDR10 provides vibrant colors and deeper shadows/highlights. A user would almost always prefer HDR10 content over SDR.

SpatialGen customers have varying creative directions and visions. Some shoot cinematic stories, others landscape hiking videos, others shoot music, comedy, sports, and even magic shows. Imagine washed-out colors as someone breathes fire, or as lights burn through smoke on the stage of a music festival. It just wouldn’t have the same impact.

The Problem

For months, developers across Apple’s forums have lamented the same mystery: MV-HEVC HDR10 files that played flawlessly as standalone videos would stubbornly refuse to stream via HLS. The symptoms were a consistent black screen. Worse yet, Apple’s validation tools would give it a clean bill of health.

No Playback

A screenshot of failing playback

Following our previous blog, many developers (including our own team) hit this wall.

There is a fine line between “the spec” and “the production spec.” So, we got to work. But first, how do you even get a MV-HEVC HDR10 video file?

How To Encode MV-HEVC HDR

Encoding MV-HEVC HDR10 comes down to reading the correct data from your source file and setting the correct color properties on your output file. You can follow our previous blog about the details, but the key part for output is here:

AVVideoColorPropertiesKey: [
    AVVideoColorPrimariesKey: AVVideoColorPrimaries_P3_D65,
    AVVideoTransferFunctionKey: AVVideoTransferFunction_SMPTE_ST_2084_PQ,
    AVVideoYCbCrMatrixKey: AVVideoYCbCrMatrix_ITU_R_709_2
]

Once you have your MV-HEVC HDR10 file, it should play perfectly in the Apple Vision Pro or on a Mac. The issue arises when you segment the file for streaming. For ease-of-use, let’s use mediafilesegmenter. If you’re looking for a guide on streaming MV-HEVC, we recommend our tutorial.

mediafilesegmenter -t 3 input_video_file

When you host these files, playback will show the same dreaded problem without explanation:

No Playback

A screenshot of failing playback

The encoding worked. Local playback succeeded. But HLS streams? Silence from AVPlayer.

The Forensic Investigation

Segmenter Surgery

Over the last month, the SpatialGen team has been diving deep into HDR10 as one of our key initiatives for 2025. Since files failed to play back after segmenting, we thought mediafilesegmenter was not segmenting MV-HEVC HDR10 files correctly.

So we wrote our own TypeScript segmenter using Bun for quick iteration.

Screenshot of our segmenter CLI

To quickly compare these files, we used Bun to build an app for reading bytes of segmented files.

Screenshot of segment zero SDR

If you’re interested in some of the specs behind these files, check out Mike Swanson’s excellent article about how spatial and immersive video is structured for the Vision Pro.


Discovery 1: Both MV-HEVC SDR segments from our segmenter and mediafilesegmenter show identical structures.

Discovery 2: Both MV-HEVC HDR10 segments from our segmenter and mediafilesegmenter show identical structures.

We were following the spec and had gotten the exact same result as mediafilesegmenter… What could be wrong?

This led us to the unsettling idea that perhaps Apple had intentionally restricted MV-HEVC HDR10 HLS playback. If Apple wouldn’t launch an immersive player for the Vision Pro, were we destined to build our own yet again? Surely not, Apple wants great experiences on the Vision Pro, so there must be something wrong!

Desperation: Transplanting Tags

We were quite upset at this point.

Then we realized there is a supported HDR10 MV-HEVC stream. After all, Apple Immersive Video (AIV) is HDR10!

“If AIV is HDR10, let’s just change every piece of metadata to look like what AIV would.” Even the projection type, so we encoded our video to be in the mysterious “Fisheye” projection type:

compressionProperties["ProjectionKind"] =  "Fisheye"

And for good measure, let’s change our playlist file to match the AIV video layout:

REQ-VIDEO-LAYOUT="CH-STEREO/PROJ-FISH"

This results in a segment zero file of the following:

Screenshot of Working MV-HEVC HDR Segment Zero

MV-HEVC HDR10 Playing

It worked! The GIF quality for this page is low, but you get the point. After all that time, writing our own segmenter and analyzing files. Losing sleep and barely making it to the office every morning… we just had to tag our videos as fisheye.

Implementation Guide

For SpatialGen users: ✅ HDR10 MV-HEVC streams now auto-configure with zero changes to your workflow.

For DIY implementers:

  • Encode with ProjectionKind=Fisheye

  • Segment with standard tools

  • Mark the layout as fisheye

This is likely a bug in the player, and using the FISH projection format serves as a temporary workaround. As we talk with Apple, we’ll try to understand better what should be supported according to their spec.

To Apple: We’ve updated our original Feedback Request of #FB15519789 with an explanation.

The Bigger Picture

This journey reveals a critical industry truth: “Spec-compliant” ≠ “Player-ready.” By sharing our findings, we hope to accelerate MV-HEVC HDR adoption over HLS until Apple formalizes support.

Every magic show, concert film, and nature documentary deserves to shine in its full HDR glory—not just those using custom implementations.

This has been quite the journey for us at SpatialGen. To our customers, thank you for pushing us to figure out the unknown. Your HDR10 streams are now live. We appreciate all those message, but we are delighted to delete that email rule.

We are always here to share what we learn and help the community grow. If you have any questions or even want to say hi, please feel free to reach out.


contact@spatialgen.com