{"record":{"id":"77e1311cc817778a","repo":"google/ExoPlayer","slug":"error-instantiating-av1-extension","errorCode":null,"errorMessage":"Error instantiating AV1 extension","messagePattern":"Error instantiating AV1 extension","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java","lineNumber":432,"sourceCode":"          clazz.getConstructor(\n              long.class,\n              android.os.Handler.class,\n              com.google.android.exoplayer2.video.VideoRendererEventListener.class,\n              int.class);\n      Renderer renderer =\n          (Renderer)\n              constructor.newInstance(\n                  allowedVideoJoiningTimeMs,\n                  eventHandler,\n                  eventListener,\n                  MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);\n      out.add(extensionRendererIndex++, renderer);\n      Log.i(TAG, \"Loaded Libgav1VideoRenderer.\");\n    } catch (ClassNotFoundException e) {\n      // Expected if the app was built without the extension.\n    } catch (Exception e) {\n      // The extension is present, but instantiation failed.\n      throw new RuntimeException(\"Error instantiating AV1 extension\", e);\n    }\n  }\n\n  /**\n   * Builds audio renderers for use by the player.\n   *\n   * @param context The {@link Context} associated with the player.\n   * @param extensionRendererMode The extension renderer mode.\n   * @param mediaCodecSelector A decoder selector.\n   * @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder\n   *     initialization fails. This may result in using a decoder that is slower/less efficient than\n   *     the primary decoder.\n   * @param audioSink A sink to which the renderers will output.\n   * @param eventHandler A handler to use when invoking event listeners and outputs.\n   * @param eventListener An event listener.\n   * @param out An array to which the built renderers should be appended.\n   */\n  protected void buildAudioRenderers(","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java#L414-L450","documentation":"DefaultRenderersFactory reflectively instantiates the optional AV1 decoder renderer (com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer) when extension renderers are enabled. ClassNotFoundException (extension not built) is expected and ignored, but any other exception while resolving the constructor or creating the instance proves the extension is present yet unusable, so the factory throws a RuntimeException with the original cause. This prevents a corrupted extension build from silently degrading playback.","triggerScenarios":"EXTENSION_RENDERER_MODE_ON/PREFER with the ext.av1 module on the classpath whose (long, Handler, VideoRendererEventListener, int) constructor is missing (version drift), not accessible, or whose construction throws (native libgav1 .so fails to load).","commonSituations":"Core and extension artifacts from different ExoPlayer releases; obfuscated/shrunk release builds that altered the constructor signature; device ABI without the bundled libgav1 native library; multiple conflicting extension versions on the dependency graph.","solutions":["Inspect the wrapped cause exception to identify whether it is a signature mismatch (NoSuchMethodException) or a native load failure (UnsatisfiedLinkError).","Pin core, exoplayer-av1 (libgav1) and any UI/extension modules to the same release version.","Add ProGuard keep rules so com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer and its constructor survive shrinking.","Ship the extension native library for every ABI you support, or disable the extension renderer mode."],"exampleFix":"// before\nnew DefaultRenderersFactory(context)\n    .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER);\n\n// after\ntry {\n  player = new ExoPlayer.Builder(new DefaultRenderersFactory(context)\n      .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER))\n      .build(context);\n} catch (RuntimeException e) {\n  // Extension present but broken — fall back to core-only renderers.\n  player = new ExoPlayer.Builder(\n      new DefaultRenderersFactory(context)\n          .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF))\n      .build(context);\n}","handlingStrategy":"try-catch","validationCode":"boolean av1Usable = false;\ntry {\n  Class.forName(\"com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer\")\n      .getConstructor(long.class, android.os.Handler.class,\n          com.google.android.exoplayer2.video.VideoRendererEventListener.class, int.class);\n  av1Usable = true;\n} catch (ReflectiveOperationException ignored) {\n}","typeGuard":null,"tryCatchPattern":"try {\n  renderersFactory = withAv1Extension(context);\n} catch (RuntimeException e) {\n  if (e.getCause() instanceof UnsatisfiedLinkError) {\n    renderersFactory = coreOnlyFactory(context); // no AV1 extension\n  } else { throw e; }\n}","preventionTips":["Align extension and core versions in one Gradle version catalog entry","Keep extension classes out of R8 shrinking scope","Prefer platform AV1 decoders (Android 10+) unless software decode is required","CI: assert class-path contains exactly one version of each extension"],"tags":["exoplayer","reflection","extension","av1","renderer","initialization"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}