CameraX Extensions API

CameraX provides an Extensions API for accessing extensions that device manufacturers have implemented on various Android devices. For a list of supported extension modes, see Camera extensions.

For a list of devices that support extensions, see Supported devices.

Extensions architecture

The following image shows the camera extensions architecture.

Figure 1. Camera Extensions architecture

A CameraX application can use extensions through the CameraX Extensions API. The CameraX Extensions API manages querying for available extensions, configuring an extension camera session, and communicating with the Camera Extensions OEM library. This allows your application to use capabilities like Night, HDR, Auto, Bokeh, or Face Retouch.

Enable an extension for image capture and preview

Before using the extensions API, retrieve an ExtensionsManager instance using the ExtensionsManager#getInstanceAsync(Context, CameraProvider) method. This will allow you to query the extension availability information. Then retrieve an extension enabled CameraSelector. The extension mode will be applied on the image capture and preview use cases when calling the bindToLifecycle() method with the CameraSelector extension enabled.

To implement the extension for the image capture and preview use cases, refer to the following code sample:

Kotlin

import androidx.camera.extensions.ExtensionMode
import androidx.camera.extensions.ExtensionsManager

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val lifecycleOwner = this

    val cameraProviderFuture = ProcessCameraProvider.getInstance(applicationContext)
    cameraProviderFuture.addListener({
        // Obtain an instance of a process camera provider
        // The camera provider provides access to the set of cameras associated with the device.
        // The camera obtained from the provider will be bound to the activity lifecycle.
        val cameraProvider = cameraProviderFuture.get()

        val extensionsManagerFuture =
            ExtensionsManager.getInstanceAsync(applicationContext, cameraProvider)
        extensionsManagerFuture.addListener({
            // Obtain an instance of the extensions manager
            // The extensions manager enables a camera to use extension capabilities available on
            // the device.
            val extensionsManager = extensionsManagerFuture.get()

            // Select the camera
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            // Query if extension is available.
            // Not all devices will support extensions or might only support a subset of
            // extensions.
            if (extensionsManager.isExtensionAvailable(cameraSelector, ExtensionMode.NIGHT)) {
                // Unbind all use cases before enabling different extension modes.
                try {
                    cameraProvider.unbindAll()

                    // Retrieve a night extension enabled camera selector
                    val nightCameraSelector =
                        extensionsManager.getExtensionEnabledCameraSelector(
                            cameraSelector,
                            ExtensionMode.NIGHT
                        )

                    // Bind image capture and preview use cases with the extension enabled camera
                    // selector.
                    val imageCapture = ImageCapture.Builder().build()
                    val preview = Preview.Builder().build()
                    // Connect the preview to receive the surface the camera outputs the frames
                    // to. This will allow displaying the camera frames in either a TextureView
                    // or SurfaceView. The SurfaceProvider can be obtained from the PreviewView.
                    preview.setSurfaceProvider(surfaceProvider)

                    // Returns an instance of the camera bound to the lifecycle
                    // Use this camera object to control various operations with the camera
                    // Example: flash, zoom, focus metering etc.
                    val camera = cameraProvider.bindToLifecycle(
                        lifecycleOwner,
                        nightCameraSelector,
                        imageCapture,
                        preview
                    )
                } catch (e: Exception) {
                    Log.e(TAG, "Use case binding failed", e)
                }
            }
        }, ContextCompat.getMainExecutor(this))
    }, ContextCompat.getMainExecutor(this))
}

Java

import androidx.camera.extensions.ExtensionMode;
import androidx.camera.extensions.ExtensionsManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final LifecycleOwner lifecycleOwner = this;

    final ListenableFuture cameraProviderFuture =
            ProcessCameraProvider.getInstance(getApplicationContext());

    cameraProviderFuture.addListener(() -> {
      try {
          // Obtain an instance of a process camera provider
          // The camera provider provides access to the set of cameras associated with the
          // device. The camera obtained from the provider will be bound to the activity
          // lifecycle.
          final ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

          final ListenableFuture extensionsManagerFuture =
                  ExtensionsManager.getInstanceAsync(getApplicationContext(), cameraProvider);
          extensionsManagerFuture.addListener(() -> {
              // Obtain an instance of the extensions manager
              // The extensions manager enables a camera to use extension capabilities available
              // on the device.
              try {
                  final ExtensionsManager extensionsManager = extensionsManagerFuture.get();

                  // Select the camera
                  final CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;

                  // Query if extension is available.
                  // Not all devices will support extensions or might only support a subset of
                  // extensions.
                  if (extensionsManager.isExtensionAvailable(
                          cameraSelector,
                          ExtensionMode.NIGHT
                  )) {
                      // Unbind all use cases before enabling different extension modes.
                      cameraProvider.unbindAll();

                      // Retrieve extension enabled camera selector
                      final CameraSelector nightCameraSelector = extensionsManager
                              .getExtensionEnabledCameraSelector(cameraSelector, ExtensionMode.NIGHT);

                      // Bind image capture and preview use cases with the extension enabled camera
                      // selector.
                      final ImageCapture imageCapture = new ImageCapture.Builder().build();
                      final Preview preview = new Preview.Builder().build();
                      // Connect the preview to receive the surface the camera outputs the frames
                      // to. This will allow displaying the camera frames in either a TextureView
                      // or SurfaceView. The SurfaceProvider can be obtained from the PreviewView.
                      preview.setSurfaceProvider(surfaceProvider);

                      cameraProvider.bindToLifecycle(
                              lifecycleOwner,
                              nightCameraSelector,
                              imageCapture,
                              preview
                      );
                  }
              } catch (ExecutionException | InterruptedException e) {
                  throw new RuntimeException(e);
              }
          }, ContextCompat.getMainExecutor(this));

      } catch (ExecutionException | InterruptedException e) {
          throw new RuntimeException(e);
      }

  }, ContextCompat.getMainExecutor(this));
}

Disable the extension

To disable vendor extensions, unbind all use cases and rebind the image capture and preview use cases with a normal camera selector. For example, rebind to the back camera using CameraSelector.DEFAULT_BACK_CAMERA.

Dependencies

The CameraX Extensions API is implemented in the camera-extensions library. The extensions depend on the CameraX core modules (core, camera2, lifecycle).

Groovy

dependencies {
  def camerax_version = "1.2.0-rc01"
  implementation "androidx.camera:camera-core:${camerax_version}"
  implementation "androidx.camera:camera-camera2:${camerax_version}"
  implementation "androidx.camera:camera-lifecycle:${camerax_version}"
  //the CameraX Extensions library
  implementation "androidx.camera:camera-extensions:${camerax_version}"
    ...
}

Kotlin

dependencies {
  val camerax_version = "1.2.0-rc01"
  implementation("androidx.camera:camera-core:${camerax_version}")
  implementation("androidx.camera:camera-camera2:${camerax_version}")
  implementation("androidx.camera:camera-lifecycle:${camerax_version}")
  // the CameraX Extensions library
  implementation("androidx.camera:camera-extensions:${camerax_version}")
    ...
}

Legacy API removal

With the new Extensions API released in 1.0.0-alpha26, the legacy Extensions API released in August 2019 is now deprecated. Starting with version 1.0.0-alpha28, the legacy Extensions API has been removed from the library. Applications using the new Extensions API must now acquire an extension-enabled CameraSelector and use it to bind the use cases.

Applications using the legacy Extensions API should migrate to the new Extensions API to ensure future compatibility with upcoming CameraX releases.

Additional resources

To learn more about CameraX, consult the following additional resources.

Codelab

  • Getting Started with CameraX
  • Code sample

    CameraX Extensions Sample App

    Other references

    CameraX Vendor Extensions

    CameraX Vendor Extensions Validation Tool