Until now camera development has been very painful within android development. Although Camera2 API solved some of the problems in the original Camera API, however there were still lots of difficulties existed to write camera features. With the recent launch of JetPack CameraX support library, it aims to make camera app development easier by providing consistency and easy-to-use API that works on devices running Lollipop API-21 or above. In this talk, we will review main uses cases of CameraX Api which are preview, image analysis and image capture. We will also explore device-specific extensions such as portrait, HDR, night and beauty mode
4. Introduction
- Backward compatible with L+ devices
- Consistent behavior across devices
- Easy to use APIs
- Based on Camera2 Apis but hides Hardware layer
- Using CameraX results 70% fewer lines of code vs Camera2
5. Issues tackled
- Front/back camera switch crashes
- Optimized camera closures
- Incorrect Orientation
- Flash not firing
11. Preview API
val previewConfig = PreviewConfig.Builder().build()
val preview = Preview(previewConfig)
val textureView: TextureView = findViewById(R.id.textureView)
12. Preview API
val previewConfig = PreviewConfig.Builder().build()
val preview = Preview(previewConfig)
val textureView: TextureView = findViewById(R.id.textureView)
// The output data-handling is configured in a listener.
preview.setOnPreviewOutputUpdateListener { previewOutput ->
textureView.surfaceTexture = previewOutput.surfaceTexture
}
13. Preview API
val previewConfig = PreviewConfig.Builder().build()
val preview = Preview(previewConfig)
val textureView: TextureView = findViewById(R.id.textureView)
// The output data-handling is configured in a listener.
preview.setOnPreviewOutputUpdateListener { previewOutput ->
textureView.surfaceTexture = previewOutput.surfaceTexture
}
// The use case is bound to an Android Lifecycle with the following code.
CameraX.bindToLifecycle(this as LifecycleOwner, preview)
17. Image Analysis API
val imageAnalysisConfig = ImageAnalysisConfig.Builder()
.setTargetResolution(Size(1280, 720))
.build()
18. Image Analysis API
val imageAnalysisConfig = ImageAnalysisConfig.Builder()
.setTargetResolution(Size(1280, 720))
.build()
val imageAnalysis = ImageAnalysis(imageAnalysisConfig)
19. Image Analysis API
val imageAnalysisConfig = ImageAnalysisConfig.Builder()
.setTargetResolution(Size(1280, 720))
.build()
val imageAnalysis = ImageAnalysis(imageAnalysisConfig)
imageAnalysis.setAnalyzer({ image: ImageProxy, rotationDegrees: Int ->
// insert your code here.
})
20. Image Analysis API
val imageAnalysisConfig = ImageAnalysisConfig.Builder()
.setTargetResolution(Size(1280, 720))
.build()
val imageAnalysis = ImageAnalysis(imageAnalysisConfig)
imageAnalysis.setAnalyzer({ image: ImageProxy, rotationDegrees: Int ->
// insert your code here.
})
CameraX.bindToLifecycle(this as LifecycleOwner, imageAnalysis, preview)
22. Image Capture API (Simplified)
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetRotation(windowManager.defaultDisplay.rotation)
.build()
val imageCapture = ImageCapture(imageCaptureConfig)
CameraX.bindToLifecycle(this as LifecycleOwner,
imageCapture, imageAnalysis, preview)
23. Image Capture API (Advance)
val imageCaptureConfig = ImageCaptureConfig.Builder().apply {
setLensFacing(lensFacing)
setCaptureMode(CaptureMode.MIN_LATENCY)
// We request aspect ratio but no resolution to match preview config but letting
// CameraX optimize for whatever specific resolution best fits requested capture mode
setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
setTargetRotation(viewFinder.display.rotation)
}.build()
24. Image Capture API (Take Photo)
fun onClick() {
val file = File(...)
imageCapture.takePicture(file,
object : ImageCapture.OnImageSavedListener {
override fun onError(error: ImageCapture.UseCaseError,
message: String, exc: Throwable?) {
// insert your code here.
}
override fun onImageSaved(file: File) {
// insert your code here.
}
32. Implement Extension for Preview Use Case 1/2
// Create a Builder same as in normal workflow.
PreviewConfig.Builder builder = new PreviewConfig.Builder();
// Create a Extender object which can be used to apply extension configurations.
BeautyPreviewExtender extender = BeautyPreviewExtender.create(builder);
if (extender.isExtensionAvailable()) {
extender.enableExtension();
}
33. Implement Extension for Preview Use Case 2/2
// Finish constructing configuration with the same flow as when not using extensions.
mPreview = new Preview(builder.build());
TextureView textureView = findViewById(R.id.textureView);
mPreview.setOnPreviewOutputUpdateListener(
new Preview.OnPreviewOutputUpdateListener() {
@Override
public void onUpdated(Preview.PreviewOutput output) {
textureView.setSurfaceTexture(output.getSurfaceTexture());
}
});
// bind use case
CameraX.bindToLifecycle(this, mPreview)
34. Implement Extension for ImageCapture Use Case
val builder = ImageCaptureConfig.Builder()
// Create a Extender object which can be used to apply extension configurations.
val bokehImageCapture = BokehImageCaptureExtender.create(builder)
// Query if extension is available (optional).
if (bokehImageCapture.isExtensionAvailable()) {
bokehImageCapture.enableExtension()
}
// Finish constructing configuration with the same flow as when not using extensions.
val config = builder.build()
val useCase = ImageCapture(config)
CameraX.bindToLifecycle(this as LifecycleOwner, useCase)
35. How to test CameraX Extensions
○ Download AndroidX source code using below link
https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/README.md
○ Open androidx-master-dev/frameworks/support in Android Studio.
○ Select camera-testapp-extensions and install on device
○ Test APK :
https://drive.google.com/open?id=1WR-ncfdojn6brNGVZqJlZkwdqE1KTUOf