google/ExoPlayer · error · IllegalArgumentException
Unsupported color transfer: {colorTransfer}
Error message
Unsupported color transfer: {colorTransfer} What it means
Thrown by GlUtil.createEglSurface(...) when the requested C.COLOR_TRANSFER value is neither SDR (gamma) nor one of the two supported HDR transfers (SMPTE 2084 PQ handled above, or HLG handled just before). This argument must be one of the C.COLOR_TRANSFER_* constants; arbitrary integers or ColorInfo values with an unknown transfer function are rejected before EGL surface creation.
Source
Thrown at library/common/src/main/java/com/google/android/exoplayer2/util/GlUtil.java:328
windowAttributes = EGL_WINDOW_SURFACE_ATTRIBUTES_NONE;
} else if (colorTransfer == C.COLOR_TRANSFER_ST2084) {
configAttributes = EGL_CONFIG_ATTRIBUTES_RGBA_1010102;
if (isEncoderInputSurface) {
// Outputting BT2020 PQ with EGL_WINDOW_SURFACE_ATTRIBUTES_BT2020_PQ to an encoder causes
// the encoder to incorrectly switch to full range color, even if the encoder is configured
// with limited range color, because EGL_WINDOW_SURFACE_ATTRIBUTES_BT2020_PQ sets full range
// color output, and GL windowAttributes overrides encoder settings.
windowAttributes = EGL_WINDOW_SURFACE_ATTRIBUTES_NONE;
} else {
// TODO(b/262259999) HDR10 PQ content looks dark on the screen.
windowAttributes = EGL_WINDOW_SURFACE_ATTRIBUTES_BT2020_PQ;
}
} else if (colorTransfer == C.COLOR_TRANSFER_HLG) {
checkArgument(isEncoderInputSurface, "Outputting HLG to the screen is not supported.");
configAttributes = EGL_CONFIG_ATTRIBUTES_RGBA_1010102;
windowAttributes = EGL_WINDOW_SURFACE_ATTRIBUTES_NONE;
} else {
throw new IllegalArgumentException("Unsupported color transfer: " + colorTransfer);
}
return Api17.createEglSurface(eglDisplay, surface, configAttributes, windowAttributes);
}
/**
* Creates a new {@link EGLSurface} wrapping a pixel buffer.
*
* @param eglDisplay The {@link EGLDisplay} to attach the surface to.
* @param width The width of the pixel buffer.
* @param height The height of the pixel buffer.
* @param configAttributes EGL configuration attributes. Valid arguments include {@link
* #EGL_CONFIG_ATTRIBUTES_RGBA_8888} and {@link #EGL_CONFIG_ATTRIBUTES_RGBA_1010102}.
*/
@RequiresApi(17)
private static EGLSurface createPbufferSurface(
EGLDisplay eglDisplay, int width, int height, int[] configAttributes) throws GlException {
int[] pbufferAttributes =
new int[] {View on GitHub (pinned to dd430f7053)
Solutions
- Map or clamp the transfer before calling: treat COLOR_TRANSFER_UNKNOWN/LINEAR/GAMMA_2_2 as C.COLOR_TRANSFER_SDR_VIDEO (or skip EGL HDR path)
- Apply tone mapping (or force SDR) when the source transfer is unsupported: set the experimental tone-mapping setting in DefaultRenderersFactory, or transcode to SDR first
- Validate ColorInfo.colorTransfer against the supported set {COLOR_TRANSFER_SDR_VIDEO, COLOR_TRANSFER_SDR_GAMMA_2_2 (SDR path), COLOR_TRANSFER_HLG, COLOR_TRANSFER_SMPTE_170M/2084 as handled} and fail with a clear upstream message before touching EGL
- Upgrade media3 — HDR/EGL transfer support expands across versions (b/262259999 and friends track added transfers)
Example fix
// before
EGLSurface surface = GlUtil.createEglSurface(eglDisplay, outputSurface, colorInfo.colorTransfer);
// after
int transfer = colorInfo.colorTransfer;
boolean hdrOk = transfer == C.COLOR_TRANSFER_SDR_VIDEO
|| transfer == C.COLOR_TRANSFER_HLG
|| transfer == C.COLOR_TRANSFER_SMPTE_2084;
int safeTransfer = hdrOk ? transfer : C.COLOR_TRANSFER_SDR_VIDEO;
EGLSurface surface = GlUtil.createEglSurface(eglDisplay, outputSurface, safeTransfer); Defensive patterns
Strategy: type-guard
Validate before calling
private static final Set<Integer> SUPPORTED = Set.of(
C.COLOR_TRANSFER_SDR_VIDEO, C.COLOR_TRANSFER_SDR_GAMMA_2_2,
C.COLOR_TRANSFER_HLG, C.COLOR_TRANSFER_SMPTE_2084);
int transfer = SUPPORTED.contains(colorInfo.colorTransfer)
? colorInfo.colorTransfer : C.COLOR_TRANSFER_SDR_VIDEO; Type guard
static boolean isSupportedColorTransfer(@Nullable ColorInfo info) {
return info != null && (info.colorTransfer == C.COLOR_TRANSFER_SDR_VIDEO
|| info.colorTransfer == C.COLOR_TRANSFER_SDR_GAMMA_2_2
|| info.colorTransfer == C.COLOR_TRANSFER_HLG
|| info.colorTransfer == C.COLOR_TRANSFER_SMPTE_2084);
} Try / catch
catch (IllegalArgumentException e) { /* downgrade transfer to SDR and retry createEglSurface */ } Prevention
- Normalize ColorInfo from arbitrary media at ingest: unknown transfer -> SDR
- Enable tone mapping when shipping HDR through effects on mixed device fleets
- Remember HLG requires an encoder-input surface (isEncoderInputSurface=true)
When it happens
Trigger: Passing colorTransfer from ColorInfo.colorTransfer when it is COLOR_TRANSFER_SDR_VIDEO/HLG is fine, but a value like C.COLOR_TRANSFER_LINEAR, C.COLOR_TRANSFER_GAMMA_2_2, an unrecognized vendor transfer, or COLOR_TRANSFER_UNKNOWN (-1) reaches the final else and throws IllegalArgumentException. Also, HLG on a non-encoder (display) surface throws earlier via checkArgument, not here.
Common situations: Building a transformer/effects pipeline that copies ColorInfo from arbitrary source media (some cameras tag LINEAR or GAMMA_2_2), forwarding ToneMapping-heavy or AV1-HDR metadata into GlUtil.createEglSurface, or passing 0/-1 defaults from an uninitialized ColorInfo instead of a concrete transfer constant.
Related errors
- eglChooseConfig failed.
- eglCreateContext() failed to create a valid context. The dev
- Failed to render output buffer to surface: decoder is not in
- No call to setSamplerTexId() before bind.
- Unexpected uniform type: {type}
AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14).
Data as JSON: /api/errors/aab18a83929c6d83.
Report an issue: GitHub.