google/ExoPlayer · critical · FfmpegDecoderException
Failed to load decoder native libraries.
Error message
Failed to load decoder native libraries.
What it means
FfmpegDecoderException thrown by the FfmpegAudioDecoder constructor when FfmpegLibrary.isAvailable() is false — the FFmpeg JNI native libraries were not loaded. Unlike the AAR-published extensions, the FFmpeg extension requires you to build and package libffmpeg JNI .so files yourself, so this error means the native side is missing at runtime.
Solutions
- Build the FFmpeg extension natives (scripts in extensions/ffmpeg) and package libffmpegJNI.so for every target ABI; verify with Analyze APK
- Check FfmpegLibrary.isAvailable() before registering FfmpegAudioRenderer and fall back to platform MediaCodec decoding
- Fix abiFilters/splits so the delivered APK matches device ABIs; rebuild .so with 16KB alignment for Android 15+ targets
- Verify FfmpegLibrary.supportsFormat(sampleMimeType) too, since the codec list depends on how FFmpeg was configured at build time
Example fix
// before
out.add(new FfmpegAudioRenderer(...)); // crashes when natives are absent
// after
if (FfmpegLibrary.isAvailable()) {
out.add(new FfmpegAudioRenderer(...));
} else {
Log.w(TAG, "FFmpeg natives missing; using platform decoders");
}
super.buildAudioRenderers(context, extensionRendererMode, ...); // platform fallback Defensive patterns
Strategy: validation
Validate before calling
if (FfmpegLibrary.isAvailable()) {
// safe to construct FfmpegAudioDecoder / register FfmpegAudioRenderer
} else {
// libffmpegJNI.so not packaged: use platform MediaCodec rendering only
} Try / catch
try {
decoder = new FfmpegAudioDecoder(format, numIn, numOut, initialSize, outputFloat);
} catch (FfmpegDecoderException e) {
if (e.getMessage() != null && e.getMessage().contains("native libraries")) {
// packaging problem: verify lib/<abi>/libffmpegJNI.so, then fall back
Log.e(TAG, "FFmpeg natives missing", e);
}
throw e;
} Prevention
- Build and package the FFmpeg extension natives for every shipped ABI; verify in the APK artifact
- Gate FFmpeg renderer registration on FfmpegLibrary.isAvailable() and keep MediaCodec as fallback
- Rebuild natives when targeting Android 15+ (16KB page alignment) or new ABIs
When it happens
Trigger: Enabling FfmpegAudioRenderer in an app whose APK contains no lib/<abi>/libffmpegJNI.so; shipping the Java dependency only (compileOnly-style usage); building FFmpeg for a subset of ABIs and running on an excluded device; proguard/packaging stripping the .so.
Common situations: Adding the ffmpeg extension source without running its native build; abiFilters mismatch; using a third-party maven artifact of the extension that ships no natives; 16KB-page devices rejecting an old-style .so alignment.
Related errors
- Failed to load decoder native library.
- Initialization failed.
- Buffer render error
- DECODER_QUERY_ERROR
- Error instantiating FFmpeg extension
AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14).
Data as JSON: /api/errors/9f7a682e978361cd.
Report an issue: GitHub.
Appendix: source
Thrown at extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioDecoder.java:69
@Nullable private final byte[] extraData;
private final @C.PcmEncoding int encoding;
private final int outputBufferSize;
private long nativeContext; // May be reassigned on resetting the codec.
private boolean hasOutputFormat;
private volatile int channelCount;
private volatile int sampleRate;
public FfmpegAudioDecoder(
Format format,
int numInputBuffers,
int numOutputBuffers,
int initialInputBufferSize,
boolean outputFloat)
throws FfmpegDecoderException {
super(new DecoderInputBuffer[numInputBuffers], new SimpleDecoderOutputBuffer[numOutputBuffers]);
if (!FfmpegLibrary.isAvailable()) {
throw new FfmpegDecoderException("Failed to load decoder native libraries.");
}
Assertions.checkNotNull(format.sampleMimeType);
codecName = Assertions.checkNotNull(FfmpegLibrary.getCodecName(format.sampleMimeType));
extraData = getExtraData(format.sampleMimeType, format.initializationData);
encoding = outputFloat ? C.ENCODING_PCM_FLOAT : C.ENCODING_PCM_16BIT;
outputBufferSize = outputFloat ? OUTPUT_BUFFER_SIZE_32BIT : OUTPUT_BUFFER_SIZE_16BIT;
nativeContext =
ffmpegInitialize(codecName, extraData, outputFloat, format.sampleRate, format.channelCount);
if (nativeContext == 0) {
throw new FfmpegDecoderException("Initialization failed.");
}
setInitialInputBufferSize(initialInputBufferSize);
}
@Override
public String getName() {
return "ffmpeg" + FfmpegLibrary.getVersion() + "-" + codecName;
}View on GitHub (pinned to dd430f7053)