{"record":{"id":"b204677f3ba6bce2","repo":"google/ExoPlayer","slug":"error-instantiating-ffmpeg-extension","errorCode":null,"errorMessage":"Error instantiating FFmpeg extension","messagePattern":"Error instantiating FFmpeg extension","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java","lineNumber":546,"sourceCode":"\n    try {\n      // Full class names used for constructor args so the LINT rule triggers if any of them move.\n      Class<?> clazz =\n          Class.forName(\"com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer\");\n      Constructor<?> constructor =\n          clazz.getConstructor(\n              android.os.Handler.class,\n              com.google.android.exoplayer2.audio.AudioRendererEventListener.class,\n              com.google.android.exoplayer2.audio.AudioSink.class);\n      Renderer renderer =\n          (Renderer) constructor.newInstance(eventHandler, eventListener, audioSink);\n      out.add(extensionRendererIndex++, renderer);\n      Log.i(TAG, \"Loaded FfmpegAudioRenderer.\");\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 FFmpeg extension\", e);\n    }\n  }\n\n  /**\n   * Builds text renderers for use by the player.\n   *\n   * @param context The {@link Context} associated with the player.\n   * @param output An output for the renderers.\n   * @param outputLooper The looper associated with the thread on which the output should be called.\n   * @param extensionRendererMode The extension renderer mode.\n   * @param out An array to which the built renderers should be appended.\n   */\n  protected void buildTextRenderers(\n      Context context,\n      TextOutput output,\n      Looper outputLooper,\n      @ExtensionRendererMode int extensionRendererMode,\n      ArrayList<Renderer> out) {","sourceCodeStart":528,"sourceCodeEnd":564,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java#L528-L564","documentation":"DefaultRenderersFactory reflectively instantiates the optional FFmpeg audio renderer (com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer) with the (Handler, AudioRendererEventListener, AudioSink) constructor when extension renderer mode is enabled. Any reflective failure other than ClassNotFoundException — meaning the FFmpeg extension classes exist but cannot be constructed — is rethrown as a RuntimeException with the original cause, aborting renderer creation. This typically surfaces as an UnsatisfiedLinkError cause when the ffmpeg .so was not built or shipped correctly.","triggerScenarios":"Extension renderer mode ON/PREFER with the ffmpeg extension AAR present, but libffmpegJNI.so missing for the device ABI, or the constructor signature changed between the extension build and core.","commonSituations":"The FFmpeg extension must be built manually from source with a chosen component set; using a prebuilt or mis-built AAR whose .so does not cover the running ABI; dependency version drift; R8 removing the renderer's constructor.","solutions":["Check RuntimeException.getCause(); UnsatisfiedLinkError means the native library is absent for that ABI, NoSuchMethodException means signature drift.","Rebuild the FFmpeg extension from the same tag as your core library and package all needed ABIs (follow the extensions/ffmpeg README).","Align exoplayer-core and the extension version numbers exactly.","If hardware decoders suffice, use EXTENSION_RENDERER_MODE_OFF to skip FFmpeg entirely."],"exampleFix":"# before — extension built from a different release than core\n# after — build extension at the exact core tag\ngit clone https://github.com/google/ExoPlayer.git\ncd ExoPlayer && git checkout v2.19.1\ncd extensions/ffmpeg && ./build.sh outputs/ffmpeg  # select codecs when prompted\n# then link settings.gradle per README and depend on the project","handlingStrategy":"try-catch","validationCode":"static boolean ffmpegNativeAvailable() {\n  try {\n    System.loadLibrary(\"ffmpegJNI\");\n    return true;\n  } catch (UnsatisfiedLinkError e) {\n    return false;\n  }\n}\n// enable FFmpeg extension mode only when true","typeGuard":null,"tryCatchPattern":"try {\n  player = new ExoPlayer.Builder(ffmpegFactory).build(context);\n} catch (RuntimeException e) {\n  if (e.getCause() instanceof UnsatisfiedLinkError) {\n    player = new ExoPlayer.Builder(new DefaultRenderersFactory(context)).build(context);\n  } else { throw e; }\n}","preventionTips":["Build the FFmpeg extension from the same git tag as core","Package libffmpegJNI.so for all ABIs listed in abiFilters","CI check: unzip APK and assert the .so exists per ABI","Enable decoder fallback (setEnableDecoderFallback) so MediaCodec covers missing codecs"],"tags":["exoplayer","reflection","extension","ffmpeg","audio","native","initialization"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}