HDR 8 min read

Eclipsa Video on Android 17: The HDR Standard That Finally Makes Video Look Right on Every Screen

If you've spent any time building a video app for Android, you know the frustration: you carefully test your player on one device and the HDR content looks stunning, then a user fires up the same content on their phone with a different panel type and the highlights are blown out, the shadows are crushed, or the whole thing looks washed and flat. The content didn't change. The player didn't change. The display just doesn't know how to map HDR signals to its own physical capabilities, and no amount of ExoPlayer tuning on your end fixes that.

Android 17 (API 37) ships Eclipsa Video, a new platform-level HDR standard built on the SMPTE ST 2094-50 specification, specifically to fix this. It's the Android answer to a problem that's plagued mobile video for years — and the good news for developers is that if you're already using Media3 ExoPlayer, you get most of the benefit for free.

API 37
Minimum Android version for Eclipsa Video platform support
Auto
SMPTE 2094-50 metadata extracted and applied automatically by ExoPlayer
Zero
Custom codec configuration required on the playback side

Why HDR on Mobile Has Always Been Messy

The core problem is that HDR content is graded against a reference display — typically a professional monitor with known peak brightness and a specific color gamut. When that content lands on a consumer phone, the device has to make a mapping decision: how do I take these HDR luminance values and render them on this panel that has completely different capabilities?

Without per-frame metadata telling the display how to make that mapping, the device just guesses. Some devices clip highlights. Some apply a generic tone-mapping curve that makes everything look flat. Some push brightness so high that the image blows out on anything above 50% brightness. The result is wildly inconsistent rendering of the same content across devices, even devices with nominally similar specs.

Add to that the problem of mixed SDR/HDR compositing — an HDR video player running alongside system UI that's still in SDR — and you get jarring brightness transitions that no user understands and no developer can easily fix from application code.

What Eclipsa Video Actually Is

Eclipsa Video is built on the SMPTE ST 2094-50 specification and works through two complementary mechanisms embedded as per-frame metadata in the video container.

Reference White Anchor

The first mechanism pins the peak brightness of SDR content to the display's reference white point. Any luminance value above that anchor is reserved exclusively for HDR highlights. This matters most in mixed-content scenarios: when you've got a video player alongside notification badges, status bar icons, or any other SDR UI, the Reference White Anchor ensures there's a consistent visual relationship between the two. The jarring "everything got brighter when I opened the video" problem — which I've seen reported in user reviews for Musist — comes from exactly this missing contract. Eclipsa's metadata establishes it.

Headroom-Adaptive Gain Curves

The second mechanism is where the real flexibility lives. The metadata carries parametric gain curves that tell the display how to scale HDR content given its actual headroom — the ratio between the display's real peak brightness and its reference white. A device with a very bright panel has a lot of headroom; one with a dimmer panel has less. The gain curves let the content creator specify a family of tone-mapping responses that gracefully degrade as headroom shrinks, rather than having the platform pick one generic curve that might look great on one device and terrible on another.

The creator can choose from three broad intents: soft-clip highlights (preserves more specular detail, slight roll-off at the top), hard-clip (maximum punch on bright devices, accepts clipping at lower headroom), or midtone/shadow compression (sacrifices some shadow detail to preserve highlight brightness). Each of these is parameterized in the SMPTE 2094-50 metadata, not hardcoded — so the display adapts to its own capabilities at runtime rather than you, the app developer, trying to predict every target panel at encode time.

Playback: ExoPlayer Gets It for Free

For most video app developers, this is where the story starts and ends. If you're using Media3 ExoPlayer, Eclipsa Video support requires no changes to your player setup. The library extracts SMPTE 2094-50 metadata from the container during demuxing, passes it through the decode pipeline, and the platform applies it during composition. Your standard player initialization already covers it:

val player = ExoPlayer.Builder(context).build()
player.setMediaItem(MediaItem.fromUri(videoUri))
player.prepare()
player.play()
// Eclipsa metadata extracted and applied automatically on API 37+

There's no new flag to pass, no HDRController to initialize, no codec configuration to adjust. The metadata handling is entirely internal to the framework. For apps like HailUp and Musist, which are already on Media3 ExoPlayer, this means Eclipsa-encoded content will just work correctly on Android 17 devices — including proper mixed-content compositing with the system UI — with nothing more than a SDK bump.

Why this is the right call: HDR metadata handling at the platform level, not the app level, is the only way to get consistent rendering across the Android ecosystem. App-level tone mapping can't know the display's real-time capabilities (ambient sensor adjustments, battery saver brightness caps, thermal throttling). The platform always has that context. Eclipsa puts the decision where it belongs.

One caveat: on Android 16 (API 36) and lower, you may see platform-level decoding artifacts on Eclipsa-encoded content because the SMPTE 2094-50 metadata wasn't understood. This isn't introduced by updating your app — it's the baseline behavior that already exists on those devices. The fix is for users to be on Android 17, not for you to conditionally strip the metadata out.

Capture: Camera2 with the HLG10_SMPTE_2094_50 Profile

For apps that do video recording — and HailUp's video upload flow made me think carefully about this — Eclipsa Video is also supported on the capture side through Camera2's dynamic range profiles. The relevant constant is DynamicRangeProfiles.HLG10_SMPTE_2094_50.

The workflow looks like this: first validate device support via CameraCharacteristics, then configure your capture session to route the stream to an encoder surface with the Eclipsa dynamic range profile attached:

val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
val cameraId = cameraManager.cameraIdList[0]
val characteristics = cameraManager.getCameraCharacteristics(cameraId)

val profiles = characteristics.get(
    CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES
)

val supportsEclipsa = profiles?.supportedProfiles?.contains(
    DynamicRangeProfiles.HLG10_SMPTE_2094_50
) == true

if (supportsEclipsa) {
    // Configure capture session with HLG10_SMPTE_2094_50 profile
    val outputConfig = OutputConfiguration(encoderSurface).apply {
        dynamicRangeProfile = DynamicRangeProfiles.HLG10_SMPTE_2094_50
    }
    // Build session with outputConfig...
}

The key thing to understand: you don't configure the SMPTE 2094-50 metadata manually. If the device supports the profile, the Android media framework generates and attaches the gain curve metadata automatically during encoding. This is by design — the platform has access to the display and sensor state needed to generate meaningful metadata; your app code doesn't.

What to do on devices that don't support it

Not all Android 17 devices will advertise the HLG10_SMPTE_2094_50 profile — hardware support varies. The correct fallback is DynamicRangeProfiles.HLG10 (HLG without the Eclipsa gain curves), then standard STANDARD for SDR. Check the CameraCharacteristics query result before attempting to configure the profile, and fail gracefully.

Checking Hardware Acceleration at Runtime

On playback, you can query whether the current display has hardware-accelerated support for Eclipsa rendering using the Display overlay properties API. This is useful if you want to log telemetry or make quality decisions based on the playback path:

val display = context.display
val lutProperties = display?.overlayProperties?.lutProperties

if (lutProperties != null) {
    // Hardware-accelerated path — Eclipsa rendering is optimal
} else {
    // Software fallback — rendering still works, just not hardware-accelerated
}

LutProperties being non-null means the display supports hardware LUT-based tone mapping, which is the fast path for Eclipsa's gain curve application. Devices without it fall back to a software path. As of Android 17, the option for apps to explicitly opt out of Eclipsa rendering on non-accelerated devices is still under development — so there's no user-facing control here yet.

Don't use this to gate feature exposure to users. Whether the display takes the hardware or software path is an implementation detail users don't need to know about. The rendering difference is in performance budget, not visual output quality. Use lutProperties for diagnostics, not for "HDR not supported on this device" messaging.

What This Means for Video Apps in Practice

I've shipped two apps with significant video components — Musist and HailUp — and the consistent complaint from users on flagship devices with high-brightness OLED panels was that HDR content in the player looked different from the same content in the system gallery or a streaming app. That gap came from exactly the problem Eclipsa solves: no per-frame metadata to tell the display how to tone-map, so different apps ended up in different rendering paths.

Once the content library catches up — meaning Eclipsa-encoded content is available — that inconsistency goes away on Android 17 devices for apps using Media3 ExoPlayer. You don't have to do anything other than be on a recent Media3 version. For the recording side, HLG10_SMPTE_2094_50 means user-captured content from capable devices will carry metadata that makes it look right when played back anywhere the format is understood, not just on the device that shot it.

For streaming apps consuming content from a CDN, the main action item is on the encoding pipeline side: ensure your backend generates Eclipsa-compatible streams (HLG base layer with SMPTE 2094-50 metadata) so Android 17 clients can use the full rendering path. The ExoPlayer client side is already ready.

The Bigger Picture

Eclipsa Video is part of a broader shift in how Android handles the HDR ecosystem — moving from per-app workarounds toward platform-level contracts that give every app consistent behavior without every developer needing to be an HDR color scientist. APV (Avatar Performer Video), which became a mandatory codec in Android 16, and now Eclipsa in Android 17, both point in the same direction: the platform absorbs the hard parts of modern video formats so application developers can stay at the ExoPlayer level.

That's the right tradeoff. The display knows its own peak brightness, its panel characteristics, its current calibration state. The app doesn't and can't. Eclipsa's metadata-driven approach finally gives that knowledge a proper channel from the display back to the content, and the Media3 layer makes sure developers don't have to touch the plumbing.

If you ship a video app and you're already on Media3 ExoPlayer, you're done — Eclipsa support will show up when your users are on Android 17 devices playing Eclipsa-encoded content. If you do in-app recording, add a check for HLG10_SMPTE_2094_50 in your Camera2 capture configuration. Everything else is a platform concern, not an app concern.

Comments 0

No comments yet. Be the first to leave one!

Leave a comment