CameraX, An Understanding Friend!

Every mobile developer has at least met with a requirement for a Custom Camera.

That’s where it all starts, from learning low level native code to actually understanding Camera API’s and writing a lot of boilers camera configuration code for just adding some buttons for product branding.

Even an experienced developer well known to Android’s Camera Api is prone to make mistakes, where some android devices may not support Camera. Where he might not be responsible to those mistakes, but device manufacturers! for creating devices with aspect ratios, not considering standard formats. Then developer has to do some patch work just to add support for the single device, Still developer is unsure of the code he has written.

Trust me, a state where developer might start doubting his skills.

Even though android makes it simpler for the developer to develop things easier, but when it comes to native hardware, it always a pain in the rear.

Over the period android was aware of issues developers have been facing and device manufactures, Non standard device sizes being released,
And then a new Jetpack’s library was introduced, CameraX!

Get Reading to get some Dopamine shots!

Jetpack’s library which has made developer’s life at ease. No matter how custom requirement may be, CameraX serves it all from camera setup to manipulating each image frame, Accomplished with just a few lines of code.

We can add CameraX to our project with theses few lines of dependency

def camerax_version = "1.0.0-beta07"
def camerax_view ="1.0.0-alpha14"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_view"

In order to cameraX work, it requires several useCases like Image Preview (How camera Stream is going to render), Image Capturer (For Capturing images and the way they are going to save), Image Analyzer also if developer has to work on every single frame of camera Stream.

  • Creating useCase for ImagePreview
val preview = Preview.Builder()
 .setTargetAspectRatio(AspectRatio.RATIO_16_9)    
 .build()
 .also {
   it.setSurfaceProvider(viewFinder.createSurfaceProvider())
 }

Here we create stream preview, the way stream is going to render also we attach it to Ui Preview View using setSurfaceProvider, which we will define soon.

  • Creating useCase for ImageCapturer
val imageCapture = ImageCapture.Builder()
 .setTargetAspectRatio(AspectRatio.RATIO_16_9)
 .build()

Here we tell cameraX to capture image in terms of device 16:9 ratio

  • Creating useCase for Image Analysis
val imageAnalysis = ImageAnalysis.Builder()
 .setTargetAspectRatio(AspectRatio.RATIO_16_9)
 .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
 .build()

imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { image ->
    // Code here to process each frame
})

We assign an aspect ratio for the images we want to receive as above also we set a callback analyser to analyze each frame for performing actions

Now Once all the use cases has been written we define a Camera Preview Ui View.

<androidx.camera.view.PreviewView
    android:id="@+id/cameraTextureView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Now the last steps to bind these use cases to our camera to start stream.

val cameraProviderFuture = ProcessCameraProvider.getInstance(activity)
cameraProviderFuture.addListener(
 Runnable {
  try
      {

  // Used to bind the lifecycle of cameras to the lifecycle owner
    val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
 
  // Select back camera as a default
    val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

    cameraProvider.bindToLifecycle(activity, cameraSelector, preview, imageCapture)

       } catch (exc: Exception) {
     // dont forget to print stack, else it wont be your undersatnding friend 😛
     }
        }, ContextCompat.getMainExecutor(activity))

Using cameraProviderFuture we define a future task and assign a runnable to start camera.

cameraProvider.bindToLifecycle(activity, cameraSelector, preview, imageCapture)

bindToLifecycle method is responsible to perform all actions such as starting the camera and closing it when user abruptly closes the app, which helps developer to not worry if any native resources are kept dangling.

Following is a screenshot of an App showing its capabilities using cameraX

Checkout CameraX demo here.

Happy Coding…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.