Skip to content

vo/opengl/android: add HDR10/HLG output - #18814

Closed
clemenswasser wants to merge 2 commits into
mpv-player:masterfrom
clemenswasser:android-hdr
Closed

clemenswasser wants to merge 2 commits into
mpv-player:masterfrom
clemenswasser:android-hdr

Conversation

@clemenswasser

Copy link
Copy Markdown

Adds HDR10/HLG output to the Android GL backend: set_color switches the
ANativeWindow dataspace and recreates the EGL surface with the matching
EGL_GL_COLORSPACE_*_EXT, and preferred_csp detects HDR displays so
--target-colorspace-hint=auto works without the embedding app passing
anything.

Android always reports the panel capability, so the default target hint
mode also renders SDR into the HDR container.
--target-colorspace-hint-mode=source keeps SDR as SDR.

The NDK has no HDR capability query, so this goes through JNI and depends on
the hidden ActivityThread.currentApplication() API.

Tested on a Galaxy Tab S9: DV/HDR10 -> BT2020/PQ at 540 nits,
HLG -> BT2020/HLG.

AI disclosure: developed with DeepSeek V4.1 Flash 1017 running in OpenCode.
I reviewed the changes and ran the tests above on the device.

Implement the ra_swapchain set_color hook: switch the ANativeWindow
dataspace to BT.2020/PQ or HLG and recreate the EGL surface with the
matching EGL_GL_COLORSPACE_*_EXT. Previously the window stayed in sRGB
and gpu-next always tone-mapped to SDR.

Implement ra_ctx_params.preferred_csp() through JNI (ActivityThread ->
DisplayManager -> getHdrCapabilities, there is no NDK API for this), so
--target-colorspace-hint=auto detects the display and tone maps to the
panel peak without the application passing anything.
HDR output is limited to 8 bits unless the window surface is 10-bit.
The surface and the context must share an EGLConfig, so this has to
happen at context creation.
@kasper93

Copy link
Copy Markdown
Member

Duplicate of: #18710

And my review does not change from the other one. This should be implemented using EGL extensions (which are builtin on Android) in libplacebo as colorspace hint, which the same way as Vulkan and d3d11. Then there is zero changes needed in mpv.

@clemenswasser

Copy link
Copy Markdown
Author

@kasper93 Sorry, I did not check for duplicates before opening this. I'll close this and redo the
work in libplacebo.

On Android, eglSurfaceAttrib(EGL_GL_COLORSPACE_KHR, ...) is not usable: on the Adreno 740 it returns
EGL_BAD_ATTRIBUTE, because libEGL only honors the colorspace in eglCreateWindowSurface. The only
way to change it on a live surface is ANativeWindow_setBuffersDataSpace(), which is the same call
libEGL makes when it creates the surface from a colorspace attribute. Setting ADATASPACE_BT2020_PQ
moved the layer to dataspace=BT2020_PQ without recreating the surface.

So I plan to pass the native window to the GL swapchain, which lets colorspace_hint set the dataspace
and the SMPTE2086/CTA861 metadata without owning the surface. mpv would only pass the window through.
The metadata needs no Android API, eglSurfaceAttrib supports it.

Does that work for you? target-colorspace-hint=auto also needs preferred_csp(), an existing
ra_ctx_params hook, so I would keep the Android implementation of it.

@kasper93

Copy link
Copy Markdown
Member

@kasper93 Sorry, I did not check for duplicates before opening this. I'll close this and redo the work in libplacebo.

On Android, eglSurfaceAttrib(EGL_GL_COLORSPACE_KHR, ...) is not usable: on the Adreno 740 it returns EGL_BAD_ATTRIBUTE, because libEGL only honors the colorspace in eglCreateWindowSurface. The only way to change it on a live surface is ANativeWindow_setBuffersDataSpace(), which is the same call libEGL makes when it creates the surface from a colorspace attribute. Setting ADATASPACE_BT2020_PQ moved the layer to dataspace=BT2020_PQ without recreating the surface.

So I plan to pass the native window to the GL swapchain, which lets colorspace_hint set the dataspace and the SMPTE2086/CTA861 metadata without owning the surface. mpv would only pass the window through. The metadata needs no Android API, eglSurfaceAttrib supports it.

Does that work for you? target-colorspace-hint=auto also needs preferred_csp(), an existing ra_ctx_params hook, so I would keep the Android implementation of it.

I cannot comment on the details, because I would have to look closely into it. But the general idea is that we implement colorspace_hint in libplacebo, using what's needed for that EGL_EXT_surface_SMPTE2086_metadata, EGL_EXT_surface_CTA861_3_metadata, EGL_EXT_gl_colorspace_bt2020_pq, EGL_EXT_gl_colorspace_bt2020_hlg, seems like the things to use.

Then indeed like you said the preferred_csp() implementation is on the mpv side of things. But this is not directly related, because, the =source mode doesn't need it at all for example. Either way, it's good to have to have proper default output based on the display parameters.

We can discuss the details after there is better initial shape.

@clemenswasser

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants