google/ExoPlayer · error · MediaCodecRenderer.DecoderInitializationException
NO_SUITABLE_DECODER_ERROR
NO_SUITABLE_DECODER_ERROR
Error message
Decoder init failed: [{errorCode}], {format} What it means
After the codec query succeeds, MediaCodecRenderer checks the deque of candidate MediaCodecInfos; if it is empty, no installed decoder matches the input format (considering the secure-decoder requirement when DRM needs secure decoding), and it throws DecoderInitializationException with NO_SUITABLE_DECODER_ERROR. Unlike DECODER_QUERY_ERROR, the codec database was queried fine — the device simply has no decoder for the format/profile.
Source
Thrown at library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java:1027
getAvailableCodecInfos(mediaCryptoRequiresSecureDecoder);
availableCodecInfos = new ArrayDeque<>();
if (enableDecoderFallback) {
availableCodecInfos.addAll(allAvailableCodecInfos);
} else if (!allAvailableCodecInfos.isEmpty()) {
availableCodecInfos.add(allAvailableCodecInfos.get(0));
}
preferredDecoderInitializationException = null;
} catch (DecoderQueryException e) {
throw new DecoderInitializationException(
inputFormat,
e,
mediaCryptoRequiresSecureDecoder,
DecoderInitializationException.DECODER_QUERY_ERROR);
}
}
if (availableCodecInfos.isEmpty()) {
throw new DecoderInitializationException(
inputFormat,
/* cause= */ null,
mediaCryptoRequiresSecureDecoder,
DecoderInitializationException.NO_SUITABLE_DECODER_ERROR);
}
MediaCodecInfo preferredCodecInfo = availableCodecInfos.peekFirst();
while (codec == null) {
MediaCodecInfo codecInfo = availableCodecInfos.peekFirst();
if (!shouldInitCodec(codecInfo)) {
return;
}
try {
try {
initCodec(codecInfo, crypto);
} catch (Exception e) {
if (codecInfo == preferredCodecInfo) {
// If creating the preferred decoder failed then sleep briefly before retrying.View on GitHub (pinned to dd430f7053)
Solutions
- Offer multiple renditions/variants (H.264 baseline/main fallback alongside HEVC/AV1) and let ABR + track selection pick a supported codec per device.
- Before playback, query support with MediaCodecUtil.getCodecInfos / MediaCapability and skip or replace unsupported tracks (e.g. prefer an audio-only or lower-profile variant).
- For niche codecs, ship the FFmpeg extension (software video/audio renderers) so decoding is not dependent on OEM hardware.
- For DRM secure-decoder failures, check MediaCodecInfo.hardwareAccelerated/secure playback support per codec and consider L3 streams for devices lacking a secure decoder for that MIME type.
Example fix
// before
TrackSelectionParameters params = player.getTrackSelectionParameters(); // defaults: unsupported video may still be selected first try
// after
TrackSelectionParameters params = player.getTrackSelectionParameters()
.buildUpon()
.setVideoResolutionCeilingForSizeConstrained(1920)
// prefer codecs known broadly supported when packaging offers them
.setOverrideForType(new TrackSelectionOverride(
new TrackGroupInfo..., /* H.264 track index */ 0))
.build();
player.setTrackSelectionParameters(params); Defensive patterns
Strategy: validation
Validate before calling
// Before playback, check the device can decode the primary codec:
MimeTypes primary = MimeTypes.VIDEO_H265;
boolean hevcSupported = false;
try {
for (MediaCodecInfo info : MediaCodecUtil.getCodecInfos()) {
if (info.isDecoder() && info.supportedMimeTypes.contains(primary)
&& info.getCapabilitiesForType(primary).isFormatSupported(format)) {
hevcSupported = true;
break;
}
}
} catch (DecoderQueryException e) {
hevcSupported = false;
}
if (!hevcSupported) {
// select H.264 variant / lower profile instead of failing with NO_SUITABLE_DECODER
} Try / catch
@Override
public void onPlayerError(PlaybackException error) {
if (error.getCause() instanceof DecoderInitializationException
&& ((DecoderInitializationException) error.getCause()).getDecoderName() == null) {
DecoderInitializationException die = (DecoderInitializationException) error.getCause();
if (die.getCause() == null /* no cause -> no suitable decoder */) {
// codec unsupported: switch to fallback rendition (H.264) or audio-only
}
}
} Prevention
- Package at least one universally decodable variant (H.264 main profile, AAC-LC) per stream.
- Use TrackSelectionParameters and track-selection overrides informed by device codec checks, so unsupported tracks are never selected.
- Ship the FFmpeg extension when supporting niche codecs (10-bit HEVC, AV1, DTS) on heterogeneous devices.
- For DRM content, verify a secure decoder exists for the codec+level (MediaDrm security level + codec secure support) before offering L1-only streams.
When it happens
Trigger: Stream codec/profile not supported by the hardware: HEVC on devices without an HEVC decoder, AV1 on pre-Android-10/pre-AV1 devices, H.264 High-10 profile, Dolby Vision, DTS:X etc.; or mediaCryptoRequiresSecureDecoder=true (DRM L1 HD content) and the only matching decoder is insecure, filtering the deque to empty.
Common situations: Single-rendition streams assuming universal codec support; HLS/DASH packaging without per-device variant selection; secure-path DRM content on devices that only offer insecure decoders for that codec; emulators lacking hardware codecs; 10-bit HDR profiles on older chipsets.
Related errors
- DECODER_QUERY_ERROR
- Attempting to open a session using a dummy ExoMediaDrm.
- Failed to load decoder native library.
- Failed to load decoder native libraries.
- Failed to load decoder native libraries.
AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14).
Data as JSON: /api/errors/7d5c20e0ddf5af63.
Report an issue: GitHub.