Android Camerax crash on real devices - android

I started to use CameraX (1.0.8 alpha) library in my Android application and during development on real Samnsung A50 device + emulators all working fine. But when it was release to Play Store - I see a lot of crashes on Pixel 2XL and Nexus 5X devices (I tried my app on emulators for this devices, but all is working fine).
I'm just call bindToLifecle:
Fatal Exception: java.lang.IllegalArgumentException: Can not get supported output size under supported maximum for the format: 34
at androidx.camera.camera2.internal.SupportedSurfaceCombination.getSupportedOutputSizes(SupportedSurfaceCombination.java:29)
at androidx.camera.camera2.internal.Camera2DeviceSurfaceManager.getSuggestedResolutions(Camera2DeviceSurfaceManager.java:29)
at androidx.camera.core.CameraX.calculateSuggestedResolutions(CameraX.java:14)
at androidx.camera.lifecycle.ProcessCameraProvider.bindToLifecycle(ProcessCameraProvider.java)
Does anybody had such issues?
Code for init:
#SuppressLint("RestrictedApi")
private void definePermissionsCallback() {
allPermissionsCheck = Dexter.withActivity(this)
.withPermissions(WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
isFileStoragePermissionGiven = true;
isCameraPermissionGiven = true;
SharedPreferences sharedPreferences = getSharedPreferences(APPLICATION_SETTINGS, MODE_PRIVATE);
sharedPreferences.edit().putBoolean(ALLOW_CAMERA, true).apply();
findViewById(R.id.switch_camera).setEnabled(true);
cameraProviderFuture = ProcessCameraProvider.getInstance(MainActivity.this);
cameraProviderFuture.addListener(() -> {
try {
cameraProvider = (ProcessCameraProvider) cameraProviderFuture.get();
bindPreview();
} catch (ExecutionException | InterruptedException e) {
Crashlytics.logException(e);
}
}, ContextCompat.getMainExecutor(MainActivity.this));
return;
}...
void bindPreview() {
cameraProvider.unbindAll();
Preview preview = new Preview.Builder()
.setTargetName("Preview")
.build();
preview.setPreviewSurfaceProvider(previewView.getPreviewSurfaceProvider());
cameraSelector = new CameraSelector.Builder().requireLensFacing(lensFacing).build();
cameraProvider.bindToLifecycle(this, cameraSelector, preview);
}

This may not answer perfectly and I could be wrong, but give following a try:
The Preview instance you are using to bind to life cycle, has the Builder which allows setting either of target resolution or target aspect ratio with setTargetResoltion or setTargetAspectRation.
It calls out that if not set
If not set, the default selected resolution will be the best size match to the device's screen resolution, or to 1080p (1920x1080), whichever is smaller.
And
If not set, resolutions with aspect ratio 4:3 will be considered in higher priority.
Respectively.
Based on the error message
Can not get supported output size under supported maximum for the format
It looks like it's not able to get the output size that it's trying to find for the default values for certain devices. This is possible as the HAL implementation of the Camera is done by OEMs (like Nokia, Huawei etc) and can have support for different supported size. If you want to look at supported resolutions in a given device you can use this app: Camera2Api Probe
Pointer to how Camera X selects automatic resolution
TL;DR;
While the API should provide this support implicitly, considering it in alpha, try to set the Aspect Ratio or the Target Resolution explicitly so it works for most of devices. To make it highly configurable you can query the supported resolution using this api
Note that, I have no link or ownership with the mentioned app Camera2Api, but I used it to query Camera2 information for devices in my job.

You could use this function (written in Kotlin) to get the possible output sizes:
private fun getOutputSizes(lensFacing: Int = CameraCharacteristics.LENS_FACING_BACK): Array<Size>? {
val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
for (cameraId in manager.cameraIdList) {
val characteristics = manager.getCameraCharacteristics(cameraId)
val orientation = characteristics[CameraCharacteristics.LENS_FACING]!!
if (orientation == lensFacing) {
val configurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
return configurationMap.getOutputSizes(SurfaceTexture::class.java)
}
}
return null
}
And simply try them until one of them is working:
for (outputSize in getOutputSizes()!!) {
try {
CameraX.bindToLifecycle(this, qrCodePreview.useCase, qrCodeImageAnalysis.useCase)
return
}
catch (e: IllegalArgumentException) {}
}
TODO("No valid output size found, handle error ...")

Sometimes this happens when you use the old or new version of lib. Try to change it

From the official documentation:
"The CameraX library is in alpha stage, as its API surfaces aren't yet finalized. We do not recommend using Alpha libraries in production. Libraries should strictly avoid depending on Alpha libraries in production, as their API surfaces may change in source- and binary-incompatible ways."
You can wait for a stable release or use api's of Camera or Camera2.

According to official code:
(outputSizeCandidates.isEmpty() && !isDefaultResolutionSupported) {
throw new IllegalArgumentException(
"Can not get supported output size for the desired output size quality for "
+ "the format: "
+ imageFormat);
}
I've got the same on device with Legacy Camera Support. Hope it helps to find answer.
UPD: It happened because CameraX lib can't find best resolution to fit Camera output for Display resolution. For example:
Display resolution: 1280x720
Closest supported camera resolution: 1920x720
DispRes < CamRes. Failed! Lib can't properly setup size.
Lib works if display resolution smaller than camera resolution.
For example:
Display resolution: 1280x800
Closest supported camera resolution: 1280x720
DispRes > CamRes. Success!

Related

Checking Android device camera video supports at least 30fps

I need to have a function that tells whether I the phone's camera video supports at least 30fps.
I'm using both camera1 and camera2 api, depending on the phone's camera2 support (or lack thereof)
I though about using this :
val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val cameras = manager.cameraIdList
for (camera in cameras) {
val cc = manager.getCameraCharacteristics(camera)
val fpsRange = cc.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES)!!
--> Log.d("TAG", "fps : ${fpsRange.find { it.lower == 30 && it.upper == 30 }}") // is this correct?
}
but I'm not sure whether it's the right solution, I don't understand the ranges that I get and whether I chose the right CameraCharacteristics.
That expression will evaluate to true for a fixed 30fps frame rate (minimum frame rate=maximum frame rate=30). That will be generally supported on all Android devices, since it's required for standard video recording.

CameraCharacteristics doesn't return all the available resolutions

I'm trying to use the maximum resolution when taking a picture using the new camera2 API. First of all, I try to get the available resolutions using the following code:
Charac:
CameraCharacteristics characteristics = mManager.getCameraCharacteristics(mCameraId);
StreamConfigurationMap streamMap =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (streamMap == null) {
throw new RuntimeException("StreamConfigurationMap is null. Should not happen.");
}
streamMap.getOutputSizes(ImageFormat.*); // I replaced the star with all possible values
The issue is this returns the following list of resolutions : [1280x960, 1088x1088, 640x480, 352x288, 176x144, 3264x1836, 3264x2448, 1280x720, 960x720, 720x480, 320x240, 1920x1080, 2400x1080, 1440x1080, 2576x1932, 3264x1468] (biggest is 3264x2448)
However when using the stock camera app (Samsung A70) the picture resolution is surprisingly bigger, ie: 4032x3024.
During investigation I tried to download many camera apps from the store to see what is the max resolution in there case, and all of them returned the same resolution as mine, ie: 3264x2448.
My question is how can the Stock Camera App get a bigger resolution than the rest of us?
Did you check the output of StreamConfigurationMap#getHighResolutionOutputSizes() as well?
Some devices list their highest resolutions there, because they can't maintain >= 20-fps output rate guaranteed by the BURST_CAPTURE capability, which is required for all sizes on the normal size list if you want a FULL-level device. As long as at least 8 MP is listed in normal sizes, the device is compliant with the BURST_CAPTURE rules and higher resolutions can be listed under getHighResolutionOutputSizes.

Setting target resolution for CameraX not working as in documentation

I want to capture photos with fixed resolution (i.e. 1200x1600) using CameraX library.
So according to documentation I can set target resolution for ImageCaptureConfig:
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setLensFacing(CameraX.LensFacing.BACK)
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
.setTargetResolution(Size(1200, 1600))
.setTargetAspectRatio(Rational(3,4))
.build()
Documentation describes setTargetResolution method as follows:
Sets the intended output target resolution.
The target resolution attempts to establish a minimum bound for the
image resolution. The actual image resolution will be the closest
available resolution in size that is not smaller than the target
resolution, as determined by the Camera implementation. However, if no
resolution exists that is equal to or larger than the target
resolution, the nearest available resolution smaller than the target
resolution will be chosen.
Correct me if I am wrong, but if device is able to take photos larger than 1200x1600 (e.g. 3024x4032), the output photo will be at least 1200x1600.
Unfortunately in many devices (e.g. Huawei P20 Pro, Samsung A5) the output photo is significantly smaller than 1200x1600, e.g. 480x640. Notice that these devices are able to take really large photos.
Is my ImageCaptureConfig badly configured or this is a bug?
The android documentation say this:
You cannot set both target aspect ratio and target resolution on the same use case. Doing so will throw an IllegalArgumentException when building the config object.
So decide what is mor important for you and choose only one.
It could be a bug that have been recently fixed at AOSP.
refer https://android.googlesource.com/platform/frameworks/support/+/5c1aed8c4c502a74eb4ee6d30fe2089f4afcaf11
When you use .setTargetResolution(Size), the resolution Size should be expressed in the coordinate frame after rotating the supported sizes by the target rotation.
For example, a device with portrait natural orientation in natural target rotation requesting a portrait image may specify 480x640, and the same device, rotated 90 degrees and targeting landscape orientation may specify 640x480.
So this in Portait:
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetResolution(Size(1200, 1600))
Became that in Landscape:
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetResolution(Size(1600, 1200))
Be careful of the orientation of your device:
fun getTargetResolution(): Size {
return when (resources.configuration.orientation) {
Configuration.ORIENTATION_PORTRAIT -> Size(1200, 1600)
Configuration.ORIENTATION_LANDSCAPE -> Size(1600, 1200)
else -> Size(1600, 1200)
}
}
fun setupCamera() {
...
val resolution = getTargetResolution()
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetResolution(resolution)
...
}
It is the same thing with ImageAnalysis and ImagePreview
If you want some documentation, go here

Android camera API blurry image on Samsung devices

After implementing the camera2 API for the inApp camera I noticed that on Samsung devices the images appear blurry. After searching about that I found the Sasmung Camera SDK (http://developer.samsung.com/galaxy#camera). So after implementing the SDK on Samsung Galaxy S7 the images are fine now, but on Galaxy S6 they are still blurry. Someone experienced those kind of issues with Samsung devices?
EDIT:
To complement #rcsumners comment. I am setting autofocus by using
mPreviewBuilder.set(SCaptureRequest.CONTROL_AF_TRIGGER, SCaptureRequest.CONTROL_AF_TRIGGER_START);
mSCameraSession.capture(mPreviewBuilder.build(), new SCameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(SCameraCaptureSession session, SCaptureRequest request, STotalCaptureResult result) {
isAFTriggered = true;
}
}, mBackgroundHandler);
It is a long exposure image where the use has to take an image of a static non moving object. For this I am using the CONTROL_AF_MODE_MACRO
mCaptureBuilder.set(SCaptureRequest.CONTROL_AF_MODE, SCaptureRequest.CONTROL_AF_MODE_MACRO);
and also I am enabling auto flash if it is available
requestBuilder.set(SCaptureRequest.CONTROL_AE_MODE,
SCaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
I am not really an expert in this API, I mostly followed the SDK example app.
There could be a number of issues causing this problem. One prominent one is the dimensions of your output image
I ran Camera2 API and the preview is clear, but the output was quite blurry
val characteristics: CameraCharacteristics? = cameraManager.getCameraCharacteristics(cameraId)
val size = characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.getOutputSizes(ImageFormat.JPEG) // The issue
val width = imageDimension.width
val height = imageDimension.height
if (size != null) {
width = size[0].width; height = size[0].height
}
val imageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 5)
The code below was returning a dimension about 245*144 which was way to small to be sent to the image reader. Some how the output was stretching the image making it end up been blurry. Therefore I removed this line below.
val size = characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.getOutputSizes(ImageFormat.JPEG) // this was returning a small
Setting the width and height manually resolved the issue.
You're setting the AF trigger for one frame, but then are you waiting for AF to complete? For AF_MODE_MACRO (are you verifying the device lists support for this AF mode?) you need to wait for AF_STATE_FOCUSED_LOCKED before the image is guaranteed to be stable and sharp. (You may also receive NOT_FOCUSED_LOCKED if the AF algorithm can't reach sharp focus, which could be because the object is just too close for the lens, or the scene is too confusing)
On most modern devices, it's recommended to use CONTINUOUS_PICTURE and not worry about AF triggering unless you really want to lock focus for some time period. In that mode, the device will continuously try to focus to the best of its ability. I'm not sure all that many devices support MACRO, to begin with.

Android getSupportedVideoSizes always returns null

I need some help with the MediaRecorder class on Android.
I try to use getSupportedVideoSizes to get the list of supported video sizes, but it always returns null.
In testing, the following devices return null when getSupportedVideoSizes is queried:
Galaxy Nexus (Android 4.2)
HTC One Mini (Android 4.4.2)
HTCEVOV4G (Android 4.0.3)
The documentation for Camera.getSupportedVideoSizes() which reads,
Returns
a list of Size object if camera has separate preview and video output; otherwise, null is returned.
is not entirely clear. However, it means that if Camera.getSupportedVideoSizes() returns null, then the camera's supported preview sizes and video sizes are the same; in this case, to get the list of supported video sizes, use Camera.getSupportedPreviewSizes().
Sample code:
public List<Size> getSupportedVideoSizes(Camera camera) {
if (camera.getParameters().getSupportedVideoSizes() != null) {
return camera.getParameters().getSupportedVideoSizes();
} else {
// Video sizes may be null, which indicates that all the supported
// preview sizes are supported for video recording.
return camera.getParameters().getSupportedPreviewSizes();
}
}
Or just use
mediarecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
to set the best resolution automatically.

Categories

Resources