I'm trying to explore cameraX beta version.
I'm stuck in my implementation.
imageCapture.takePicture() imageCapture is null.
// Bind the CameraProvider to the LifeCycleOwner
val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
// CameraProvider
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// ImageCapture
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
// Must unbind the use-cases before rebinding them
cameraProvider.unbindAll()
try {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
camera = cameraProvider.bindToLifecycle(
this, cameraSelector, imageCapture)
} catch(exc: Exception) {
Log.e("TAG", "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
// Create output file to hold the image
photoFile = createFile(externalMediaDirs.first(), FILENAME, PHOTO_EXTENSION)
// Setup image capture metadata
val metadata = Metadata().apply {
// Mirror image when using the front camera
isReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT
}
// Create output options object which contains file + metadata
outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile)
.setMetadata(metadata)
.build()
// Setup image capture listener which is triggered after photo has been taken
imageCapture?.takePicture(
outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val savedUri = output.savedUri ?: Uri.fromFile(photoFile)
Log.d(TAG, "Photo capture succeeded: $savedUri")
}
})
}
(I don't use onClickListener)
My function is called by a service.
If I remove cameraProviderFuture.addListener(Runnable I get Not bound to a valid Camera
I use camerax beta version
The ImageCapture use case doesn't currently work on its own. It has to be used in combination with at least a Preview or ImageAnalysis use case. This might change in future versions of CameraX. For now, you can check the documentation on supported use case combinations.
A simple fix to your problem would be to add an ImageAnalysis use case, its Analyzer can just immediately close the images it receives.
val imageAnalysis = ImageAnalysis.Builder()
.build()
.apply {
setAnalyzer(executor, ImageAnalysis.Analyzer { image ->
image.close()
})
}
// Then bind both the imageAnalysis and ImageCapture
cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture, imageAnalysis)
Related
I'm an android developer beginner and i try to use CameraX.
Is it possible to open the native camera and take a picture instead of build a page with preview and custom button to take a photo ?
I've read multiple article / tutorial but cannot find the solution.
Thanks for helping me
Using the example here, with a few tweaks - I was able to take a photo without any preview.
First we start the camera using ImageCapture use case:
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
imageCapture = ImageCapture.Builder()
.build()
// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, imageCapture)
} catch(exc: Exception) {
Log.e("Error", "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
}
Then we can take a photo by calling takePhoto method:
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// Create time stamped name and MediaStore entry.
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "sample_image")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
}
}
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions
.Builder(contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues)
.build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.e("Error", "Photo capture failed: ${exc.message}", exc)
}
override fun
onImageSaved(output: ImageCapture.OutputFileResults){
val msg = "Photo capture succeeded: ${output.savedUri}"
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
Log.d("Success", msg)
}
}
)
}
I've uploaded a working project to Github
I am using CameraX to capture photos and record videos. In video recorder usecase when I set recorder quality to Quality.HIGHEST preview screen turns black. Also I observerd exception from the library in logs
Exception:
E/CameraCaptureSession: Session 0: Exception while stopping repeating:
android.hardware.camera2.CameraAccessException: CAMERA_ERROR (3): The camera device has encountered a serious error
at android.hardware.camera2.impl.CameraDeviceImpl.checkIfCameraClosedOrInError(CameraDeviceImpl.java:2534)
at
Here is my code
private fun startCamera() {
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(viewDataBinding.preview.surfaceProvider)
}
val recorder = Recorder.Builder()
.setQualitySelector(
QualitySelector.from(
Quality.HIGHEST,
FallbackStrategy.higherQualityOrLowerThan(Quality.SD)
)
)
.build()
val videoCapture = VideoCapture.withOutput(recorder)
val imageCapture = ImageCapture.Builder().build().apply {
flashMode = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA)
ImageCapture.FLASH_MODE_AUTO
else
defaultFlashMode
}
cameraProviderFuture.addListener({
try {
val cameraProvider = cameraProviderFuture.get()
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
this,
cameraSelector,
preview,
imageCapture,
videoCapture
)
} catch (e: Exception) {
ComeraLogger.d(this.javaClass.name, "Use case binding failed")
}
}, ContextCompat.getMainExecutor(this))
}
When I set recorder quality SD or HD, it works fine
val recorder = Recorder.Builder()
.setQualitySelector(
QualitySelector.from(
Quality.HD,
FallbackStrategy.higherQualityOrLowerThan(Quality.SD)
)
)
.build()
Sorry about my English, I dont speak very well.
I have an app that comumnicates with an arduino device by blinking flash.
I notice that both Camera1 and Camera2 have issues to work into all Android devices, so I builded a settings screen that user can test both and choose the one that works fine.
I'm now trying to build the same communication with CameraX, hoping that works fine into more devices, but I cant find examples to just toggle the flash. I'm new at android develop, and the material I found is just about taking pictures and stuff, but I dont want even open a camera screen, just turn on and off the flash, like lantern.
Can someone help with this, or send a documentation that helps?
edit1
I did this in onCreate and I see the logs into logcat but flash dont toggle.
Maybe I need to create case ?
lateinit var cameraControl: CameraControl
val cameraProcessFuture = ProcessCameraProvider.getInstance(this)
cameraProcessFuture.addListener(Runnable {
val cameraProvider = cameraProcessFuture.get()
val lifecycleOwner = this
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector)
cameraControl = camera.cameraControl
val listenableFuture = cameraControl!!.enableTorch(true)
// cameraControl.enableTorch(false)
Log.d("MurilloTesteCamera", "listener")
listenableFuture.addListener(Runnable {
Log.d("MurilloTesteCamera", "listener 2")
}, ContextCompat.getMainExecutor(this))
}, ContextCompat.getMainExecutor(this))
Log.d("MurilloTesteCamera", "oncreate")
edit2
this code I tried to create a case, but no solve my problem and flash stil dont turn on ( my activity implements CameraXConfig.Provider:
val context = this
Log.d("MurilloTesteCamera", "before initialize")
CameraX.initialize(context, cameraXConfig).addListener(Runnable {
Log.d("MurilloTesteCamera", "inside initialize")
CameraX.unbindAll()
val preview = Preview.Builder()
.apply {
setTargetResolution(Size(640, 480))
}
.build()
lateinit var cameraControl: CameraControl
val cameraProcessFuture = ProcessCameraProvider.getInstance(context)
cameraProcessFuture.addListener(Runnable {
val cameraProvider = cameraProcessFuture.get()
val lifecycleOwner = context
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector)
cameraControl = camera.cameraControl
camera.cameraInfo.hasFlashUnit()
Log.d("MurilloTesteCamera", "info before -> " + camera.cameraInfo.torchState)
Log.d("MurilloTesteCamera", "has flash -> " + camera.cameraInfo.hasFlashUnit())
val listenableFuture = cameraControl.enableTorch(true)
Log.d("MurilloTesteCamera", "listener")
listenableFuture.addListener(Runnable {
Log.d("MurilloTesteCamera", "info after -> " + camera.cameraInfo.torchState)
Log.d("MurilloTesteCamera", "listener 2")
}, ContextCompat.getMainExecutor(context))
CameraX.bindToLifecycle(context, cameraSelector, preview)
}, ContextCompat.getMainExecutor(context))
}, ContextCompat.getMainExecutor(context))
Log.d("MurilloTesteCamera", "after initialize")
while (!CameraX.isInitialized()){}
Log.d("MurilloTesteCamera", "after while")
In CameraX, the API to turn on/off the camera torch is CameraControl.enableTorch(boolean). To get a CameraControl instance, you can follow the documentation:
The application can retrieve the CameraControl instance via
Camera.getCameraControl(). CameraControl is ready to start operations
immediately after Camera is retrieved and UseCases are bound to that
camera
This means you'll need to first bind a use case (or multiple use cases) to a lifecycle. You mentioned you don't want to open a camera screen, so I'm assuming you mean you don't want to bind any use cases, in which case you can call bindToLifecycle() with zero use cases. This may or may not work with the latest versions of CameraX.
All in all, you'd have to write something like this:
val cameraProcessFuture = ProcessCameraProvider.getInstance(context)
cameraProcessFuture.addListener(Runnable {
val cameraProvider = cameraProcessFuture.get()
// Choose the lifecycle to which the camera will be attached to
val lifecycleOwner = /* Can be an Activity, Fragment, or a custom lifecycleOwner */
// Choose a valid camera the device has
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
// You might need to create a use case to start capture requests
// with the camera
val imageAnalysis = ImageAnalysis.Builder()
.build()
.apply {
val executor = /* Define an executor */
setAnalyzer(executor, ImageAnalysis.Analyzer {
it.close()
})
}
// Get a camera instance
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector)
// Get a cameraControl instance
val cameraControl = camera.cameraControl
// Call enableTorch(), you can listen to the result to check whether it was successful
cameraControl.enableTorch(true) // enable torch
cameraControl.enableTorch(false) // disbale torch
}, ContextCompat.getMainExecutor(context))
I'm working with Camera X for the first time and I can't find a way to check if a device has a front or rear camera in runtime...
I only need to use the preview I'm not capturing images so i can't use a button for it..
private var lensFacing = CameraX.LensFacing.FRONT
val viewFinderConfig = PreviewConfig.Builder().apply {
setLensFacing(lensFacing)
setTargetAspectRatio(screenAspectRatio)
setTargetRotation(viewFinder.display.rotation)
}.build()
How can I make sure that the app won't crash if the user device has no Front camera?
Thanks in advance!
Check if the device supports at least one camera with the specified lens facing:
version 1.0.0-alpha06:
val hasFrontCamera = CameraX.hasCameraWithLensFacing(CameraX.LensFacing.FRONT)
EDIT :
version >= 1.0.0-alpha07:
From https://developer.android.com/jetpack/androidx/releases/camera:
hasCamera() previously provided by the CameraX class call are now
available via the ProcessCameraProvider
override fun onCreate(savedInstanceState: Bundle?) {
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
}
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
try {
var hasCamera = cameraProvider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA)
} catch (e: CameraInfoUnavailableException) {
e.printStackTrace()
}
}, ContextCompat.getMainExecutor(this))
I've followed the steps here to get CameraX setup, and now I am trying to get a front facing camera button working.
Here is my set up code:
private lateinit var preview: Preview
private fun startCamera() {
// Create configuration object for the viewfinder use case
val previewConfig = PreviewConfig.Builder().apply {
setLensFacing(CameraX.LensFacing.BACK)
}.build()
// Build the viewfinder use case
preview = Preview(previewConfig)
// Every time the viewfinder is updated, recompute layout
preview.setOnPreviewOutputUpdateListener {
// To update the SurfaceTexture, we have to remove it and re-add it
val parent = viewFinder.parent as ViewGroup
parent.removeView(viewFinder)
parent.addView(viewFinder, 0)
viewFinder.surfaceTexture = it.surfaceTexture
updateTransform()
}
// Bind use cases to lifecycle
CameraX.bindToLifecycle(this, preview)
}
When a user clicks the "switch" button I re-configure the preview to use the front camera, then reinitialize the Preview.
private fun initSwitchButton(view: View) {
switchButton = view.findViewById(R.id.switch_button)
switchButton.setOnClickListener {
val previewConfig = PreviewConfig.Builder().apply { setLensFacing(CameraX.LensFacing.FRONT) }.build()
preview = Preview(previewConfig)
}
}
However, this doesn't switch to the front camera. What am I missing?
Since 2021, an update to CameraX has rendered CameraX.LensFacing unusable. Use CameraSelector instead.
private CameraSelector lensFacing = CameraSelector.DEFAULT_FRONT_CAMERA;
private void flipCamera() {
if (lensFacing == CameraSelector.DEFAULT_FRONT_CAMERA) lensFacing = CameraSelector.DEFAULT_BACK_CAMERA;
else if (lensFacing == CameraSelector.DEFAULT_BACK_CAMERA) lensFacing = CameraSelector.DEFAULT_FRONT_CAMERA;
startCamera();
}
private void startCamera() {
ListenableFuture<ProcessCameraProvider> cameraFuture = ProcessCameraProvider.getInstance(requireContext());
cameraFuture.addListener(() -> {
imageCapture = new ImageCapture.Builder()
.setTargetRotation(cameraPreview.getDisplay().getRotation())
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build();
videoCapture = new VideoCapture.Builder().build();
try {
ProcessCameraProvider processCameraProvider = cameraFuture.get();
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(cameraPreview.getSurfaceProvider());
processCameraProvider.unbindAll();
// lensFacing is used here
processCameraProvider.bindToLifecycle(getViewLifecycleOwner(), lensFacing, imageCapture, videoCapture, preview);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(requireContext()));
}
It looks like the recommended way to achieve this is to store the LensFacing position as an instance variable and then call bindToLifecycle() to switch the camera.
Here is a code snippet that worked for me:
private var lensFacing = CameraX.LensFacing.BACK
private var imageCapture: ImageCapture? = null
#SuppressLint("RestrictedApi")
private fun startCamera() {
bindCameraUseCases()
// Listener for button used to switch cameras
switchButton = view.findViewById(R.id.switch_button)
switchButton.setOnClickListener {
lensFacing = if (CameraX.LensFacing.FRONT == lensFacing) {
CameraX.LensFacing.BACK
} else {
CameraX.LensFacing.FRONT
}
try {
// Only bind use cases if we can query a camera with this orientation
CameraX.getCameraWithLensFacing(lensFacing)
bindCameraUseCases()
} catch (exc: Exception) {
// Do nothing
}
}
}
private fun bindCameraUseCases() {
// Make sure that there are no other use cases bound to CameraX
CameraX.unbindAll()
val previewConfig = PreviewConfig.Builder().apply {
setLensFacing(lensFacing)
}.build()
val preview = Preview(previewConfig)
val imageCaptureConfig = ImageCaptureConfig.Builder().apply {
setLensFacing(lensFacing)
}.build()
imageCapture = ImageCapture(imageCaptureConfig)
// Apply declared configs to CameraX using the same lifecycle owner
CameraX.bindToLifecycle(this, preview, imageCapture)
}
private LensFacing lensFacing = CameraX.LensFacing.BACK;
private ImageCapture imageCapture = null;
private Button switchButton;
#SuppressLint("RestrictedApi")
private void startCamera() {
bindCameraUseCases();
// Listener for button used to switch cameras
switchButton = view.findViewById(R.id.switch_button);
switchButton.setOnClickListener(v -> {
lensFacing = lensFacing == LensFacing.FRONT ? LensFacing.BACK : LensFacing.FRONT;
try {
// Only bind use cases if we can query a camera with this orientation
CameraX.getCameraWithLensFacing(lensFacing);
bindCameraUseCases();
} catch (CameraInfoUnavailableException e) {
// Do nothing
}
});
}
private void bindCameraUseCases() {
// Make sure that there are no other use cases bound to CameraX
CameraX.unbindAll();
PreviewConfig previewConfig = new PreviewConfig.Builder().
setLensFacing(lensFacing)
.build();
Preview preview = new Preview(previewConfig);
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setLensFacing(lensFacing)
.build();
imageCapture = new ImageCapture(imageCaptureConfig);
// Apply declared configs to CameraX using the same lifecycle owner
CameraX.bindToLifecycle(this, preview, imageCapture);
}
Java version
Here is how i did mine
private var defaultCameraFacing = CameraSelector.DEFAULT_BACK_CAMERA
btnFlipCamera.setOnClickListener {
Log.d("CameraFacing", defaultCameraFacing.toString())
defaultCameraFacing = if(defaultCameraFacing == CameraSelector.DEFAULT_FRONT_CAMERA){
CameraSelector.DEFAULT_BACK_CAMERA
}else{
CameraSelector.DEFAULT_FRONT_CAMERA
}
try {
// Only bind use cases if we can query a camera with this orientation
startCamera(defaultCameraFacing)
} catch (exc: Exception) {
// Do nothing
}
}
private fun startCamera(defaultCameraFacing: CameraSelector) {
llPictureCaptured.visibility = View.GONE
tvLocationLabel.visibility= View.GONE
pgLoadingLocation.visibility = View.GONE
openCamera.visibility = View.GONE
llCameraControl.visibility = View.VISIBLE
viewFinder.visibility = View.VISIBLE
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(viewFinder.surfaceProvider)
}
imageCapture = ImageCapture.Builder()
.build()
//set image analysis, i.e luminosity analysis
val imageAnalyzer = ImageAnalysis.Builder()
.build()
.also {
it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
Log.d(TAG, "Average luminosity: $luma")
})
}
// Set camera facing
val cameraSelector = defaultCameraFacing
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture, imageAnalyzer)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
}