{"record":{"id":"5e1f753e813bf01a","repo":"google/ExoPlayer","slug":"failed-to-load-decoder-native-library","errorCode":null,"errorMessage":"Failed to load decoder native library.","messagePattern":"Failed to load decoder native library\\.","errorType":"exception","errorClass":"Gav1DecoderException","httpStatus":null,"severity":"critical","filePath":"extensions/av1/src/main/java/com/google/android/exoplayer2/ext/av1/Gav1Decoder.java","lineNumber":68,"sourceCode":"  private volatile @C.VideoOutputMode int outputMode;\n\n  /**\n   * Creates a Gav1Decoder.\n   *\n   * @param numInputBuffers Number of input buffers.\n   * @param numOutputBuffers Number of output buffers.\n   * @param initialInputBufferSize The initial size of each input buffer, in bytes.\n   * @param threads Number of threads libgav1 will use to decode. If {@link\n   *     Libgav1VideoRenderer#THREAD_COUNT_AUTODETECT} is passed, then this class will auto detect\n   *     the number of threads to be used.\n   * @throws Gav1DecoderException Thrown if an exception occurs when initializing the decoder.\n   */\n  public Gav1Decoder(\n      int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, int threads)\n      throws Gav1DecoderException {\n    super(new DecoderInputBuffer[numInputBuffers], new VideoDecoderOutputBuffer[numOutputBuffers]);\n    if (!Gav1Library.isAvailable()) {\n      throw new Gav1DecoderException(\"Failed to load decoder native library.\");\n    }\n\n    if (threads == Libgav1VideoRenderer.THREAD_COUNT_AUTODETECT) {\n      // Try to get the optimal number of threads from the AV1 heuristic.\n      threads = gav1GetThreads();\n      if (threads <= 0) {\n        // If that is not available, default to the number of available processors.\n        threads = getRuntime().availableProcessors();\n      }\n    }\n\n    gav1DecoderContext = gav1Init(threads);\n    if (gav1DecoderContext == GAV1_ERROR || gav1CheckError(gav1DecoderContext) == GAV1_ERROR) {\n      throw new Gav1DecoderException(\n          \"Failed to initialize decoder. Error: \" + gav1GetErrorMessage(gav1DecoderContext));\n    }\n    setInitialInputBufferSize(initialInputBufferSize);\n  }","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/extensions/av1/src/main/java/com/google/android/exoplayer2/ext/av1/Gav1Decoder.java#L50-L86","documentation":"Gav1DecoderException thrown by the Gav1Decoder constructor when Gav1Library.isAvailable() is false, meaning the libgav1 JNI native library (.so) could not be loaded. The extension decodes AV1 in software via libgav1, so the native library is mandatory; without it the renderer cannot be constructed at all.","triggerScenarios":"Constructing Gav1Decoder (via Libgav1VideoRenderer on an AV1 stream) in an app that ships the extension Java code but not the native libgav1 .so; missing ABIs (e.g. only arm64-v8a packaged while the device is armeabi-v7a); proguard or packaging options excluding jniLibs.","commonSituations":"Depending on extension-av1 without building/packaging the native artifacts; using abiFilters that exclude the shipped ABI; running on an emulator image whose ABI is not packaged; split APKs stripping the native lib.","solutions":["Package the libgav1 native library for every ABI you support (check the APK's lib/<abi>/libgav1.so via Analyze APK)","Add or fix abiFilters / splits so each delivered APK contains a matching .so","Check Gav1Library.isAvailable() before enabling Libgav1VideoRenderer and fall back to platform AV1 decoding or a different renderer","If bundling manually, ensure jniLibs.useLegacyPackaging and the extension AAR with native artifacts are both on the classpath"],"exampleFix":"// before\nGav1Decoder decoder = new Gav1Decoder(numInputBuffers, numOutputBuffers, initialInputBufferSize, threads);\n\n// after: gate renderer registration on native availability\nRenderersFactory factory = new DefaultRenderersFactory(context) {\n  @Override\n  protected void buildVideoRenderers(Context ctx, ExtensionRendererMode mode,\n      ArrayList<Renderer> out) {\n    if (Gav1Library.isAvailable()) {\n      out.add(new Libgav1VideoRenderer(...));\n    }\n    super.buildVideoRenderers(ctx, mode, out);\n  }\n};","handlingStrategy":"validation","validationCode":"if (!Gav1Library.isAvailable()) {\n  // do not construct Gav1Decoder / Libgav1VideoRenderer;\n  // rely on platform AV1 decode (MediaCodec) instead\n}","typeGuard":null,"tryCatchPattern":"try {\n  decoder = new Gav1Decoder(numIn, numOut, initialInputBufferSize, threads);\n} catch (Gav1DecoderException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"native library\")) {\n    // packaging problem: check APK lib/<abi>/libgav1.so, then fall back\n    Log.e(TAG, \"libgav1 missing\", e);\n  }\n  throw e;\n}","preventionTips":["After every release build, verify libgav1.so appears under every ABI you ship (Analyze APK)","Gate extension renderer registration on XxxLibrary.isAvailable() so absence degrades instead of crashing","Keep abiFilters and split APK configuration in sync with the packaged native ABIs"],"tags":["android","av1","native-library","decoder","extension"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}