13

Is there a way to query the available camera resolutions using CameraX? With Camera2 this is possible using StreamConfigurationMap.getOutputSizes(). However, I can't find a way to do this using CameraX.

It doesn't help that the documentation is quite outdated. Currently it references version 1.0.0-alpha06 and many APIs have changed in the latest 1.0.0-beta01.

EDIT:

There is a way to get the available resolutions using Camera2 APIs (thanks to Wasim's answer below). However, that's only possible after the camera is bound to the lifecycle and therefore the target resolution cannot be changed anymore, which makes it quite useless.

Sure I can specify the target resolution without knowing the available ones but this way I have no control over the resulted aspect ratio. In my case, I end up with a 16:9 Preview and a 4:3 ImageAnalysis although the targetResolution for my ImageAnalysis is in 16:9 (224x126).

For the record, this is how you could get the output sizes:

val camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalyzer)
val cameraId = Camera2CameraInfo.extractCameraId(camera.cameraInfo)
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val streamConfigurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
val outputSizes = streamConfigurationMap.getOutputSizes(format)

Still looking for an actual solution. Thanks in advance.

Georgios
  • 4,764
  • 35
  • 48
  • Unresolved reference: extractCameraId ... How did you import the "Camera2CameraInfo" class? – Greelings Sep 20 '21 at 15:43
  • Hi did you solve the question? Thanks! – ch271828n Mar 21 '22 at 00:28
  • @ch271828n no, I ended up using Camera2 instead. It's been two years since then though and I haven't worked on that project in a long time so perhaps there's a better solution with CameraX nowadays. – Georgios Mar 21 '22 at 22:37
  • @Greelings : import androidx.camera.camera2.interop.Camera2CameraInfo – frank Jul 23 '23 at 06:40

6 Answers6

2

This could help anyone googling here.

Android CameraX, get camera characteristics such as CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE.

For 2021 the syntax is like ...

So, you've gone through the process of getting the camera ...

theCamera = cameraProvider.bindToLifecycle((LifecycleOwner)this,
              yourCameraSelector, yourImageAnalysis, yourPreview);

the code nowadays is:

CameraCharacteristics camChars = Camera2CameraInfo
   .extractCameraCharacteristics(theCamera.getCameraInfo());
float discoveredMinFocusDistance = camChars
   .get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);

You'll probably need a

@SuppressLint("UnsafeExperimentalUsageError")
CameraCharacteristics camChars =  ...

for that first line.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • 1
    Can you get the available resolutions, too, though? It doesn't look like this is part of `CameraCharacteristics`, right? – Georgios Mar 12 '21 at 19:08
  • hi @Georgios - I'm afraid I dop not know that :/ I'm afraid my current struggle is this: https://stackoverflow.com/questions/66602624 – Fattie Mar 12 '21 at 19:24
2

This worked for me:

val camera = cameraProvider.bindToLifecycle(mainActivity, cameraSelector, CameraManager.imageAnalysis)

val cameraId = Camera2CameraInfo.from(camera.cameraInfo).cameraId
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val configs: StreamConfigurationMap? = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)

val imageAnalysisSizes = configs?.getOutputSizes(ImageFormat.YUV_420_888)
imageAnalysisSizes?.forEach {
    Log.i("LOG", "Image capturing YUV_420_888 available output size: $it")
}

val previewSizes = configs?.getOutputSizes(SurfaceTexture::class.java)
previewSizes?.forEach {
    Log.i("LOG", "Preview available output size: $it")
}
Greelings
  • 4,964
  • 7
  • 34
  • 70
  • Hi, I wonder how to get resolution *before* bindToLifecycle? i.e. When doing `ImageCapture.Builder().setCaptureResolution`? – ch271828n Mar 21 '22 at 00:41
2

I figured out that you can bind it to the lifecycle with NO use-cases (only 2 arguments) and then query all the camera qualities available. Once that is done, feel free to unbind and then rebind with the use cases and the proper camera qualities (it looks like only binding to lifecycle does not take that much of a toll since the camera isn't actually started).

Here is what I did:

//Add all available camera qualities here for later use
val listOfQualitiesToEnumerate = arrayListOf<String>()

val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
    val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
    val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
    try {
        // Unbind use cases before rebinding
        cameraProvider.unbindAll()
        //Bind cameraProvider with no use cases just to grab camera qualities available
        camera = cameraProvider.bindToLifecycle(this, cameraSelector)
        val supportedQualities = QualitySelector.getSupportedQualities(camera.cameraInfo)
        for (quality in supportedQualities) {
        when (quality) {
            Quality.UHD -> {
                //Add "Ultra High Definition (UHD) - 2160p" to the list
                listOfQualitiesToEnumerate.add("Ultra High Definition (UHD) - 2160p")
            }
            Quality.FHD -> {
                //Add "Full High Definition (FHD) - 1080p" to the list
                listOfQualitiesToEnumerate.add("Full High Definition (FHD) - 1080p")
            }
            Quality.HD -> {
                //Add "High Definition (HD) - 720p" to the list
                listOfQualitiesToEnumerate.add("High Definition (HD) - 720p")
            }
            Quality.SD -> {
                //Add "Standard Definition (SD) - 480p" to the list
                listOfQualitiesToEnumerate.add("Standard Definition (SD) - 480p")
            }
        }
    } catch(exception: Exception) {
        Log.e(TAG, "Camera binding failed", exception)
    }
}, ContextCompat.getMainExecutor(this))

Once you get all the information you need (also using Camera2 to get specific resolutions) you can unbind and then rebind with the proper information applied to your use cases.

Da Mahdi03
  • 1,468
  • 1
  • 9
  • 18
1

Because RecommendedStreamConfigurationMap is not compatable for older platform, so I find below code from camerax

val camera = cameraProvider.bindToLifecycle(...)
val characteristics = CameraCharacteristicsCompat.toCameraCharacteristicsCompat(Camera2CameraInfo.extractCameraCharacteristics(camera.cameraInfo))
val previewSizes = CamcorderProfileResolutionQuirk(characteristics).supportedResolutions

it works for me, copied from camerax CamcorderProfileResolutionQuirk.java

KittenBall
  • 11
  • 2
0

You can always use camera2 api StreamConfigurationMap.getOutputSizes() to get supported resolution even in CameraX. As CameraX is build on top of camera2 it shouldn't matter.

if you want to know what resolution are supported by camerax, there isn't any API. But you can always set resolution of your choice and cameraX will take care of scaling it to nearest supported resolution.

Wasim Ansari
  • 305
  • 1
  • 9
  • 3
    Thanks for your answer. You're right that I can use `StreamConfigurationMap.getOutputSizes()` but in order to get `StreamConfigurationMap` I first need to get an instance of `CameraCharacteristics` and for this one I need to know the `cameraId` which is available only after `ProcessCameraProvider.bindToLifecycle(...)`. At this point the camera is already configured and I can't change the target resolution anymore. – Georgios Mar 30 '20 at 14:07
  • 5
    Regarding setting the resolution of my choice, the problem here is that I don't have control over the aspect ratio. For example, it happens often that I set a target resolution 224x126 (16:9) and the result is in 4:3 instead of the nearest 16:9 to my target. That's particularly troublesome when you end up with a 16:9 `Preview` but 4:3 `ImageAnalysis`, which is what happens in my case. – Georgios Mar 30 '20 at 14:11
0

Here is a way that does not require a Context:

@OptIn(ExperimentalCamera2Interop::class)
fun Camera.getSupportedResolutions(): List<Size> {
    val camera2Info = Camera2CameraInfo.from(cameraInfo)
    val configs = checkNotNull(camera2Info.getCameraCharacteristic(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP))
    val resolutions = configs.getOutputSizes(ImageFormat.JPEG)
    return resolutions
}

Note that the resolutions you get have the sensor orientation (just like in all other answers here), so you may need to flip them according to your target rotation. And anyway, the actual resolution that will be picked by CameraX depends on the particular use case combination.

Eyjafl
  • 1,046
  • 6
  • 14