dotnet/android-libraries

CameraSelector.Builder().AddCameraFilter effectively unusable (cannot select specific camera lens)

Closed this issue · 2 comments

Android application type

Android for .NET (net6.0-android, etc.)

Affected platform version

Xamarin.AndroidX.Camera.Core 1.3.1.1

Description

To choose a specific camera lens (NOT default front or back), we would use code like this:

var selector = new CameraSelector.Builder()
                    .AddCameraFilter( <your filter here - how do we use this?> )
                    .Build()

and then pass that into cameraProvider.BindToLifecycle.

The Kotlin code would look like:

val selector = CameraSelector.Builder()
                    .addCameraFilter { cameras -> camera.first { someSelector(it) } }
                    .build()

The camera filter is type ICameraFilter, which has a method List<ICameraInfo> filter(ICameraInfo cameras).

However, this is very difficult, impossible, or very unintuitive to use - I haven't been able to figure it out.

Lambdas don't work. Subclassing requires implementing a boatload of JNI-related methods. All sample code online I've found doesn't use AddCameraFilter, only RequireLensFacing.

Steps to Reproduce

  1. This is not my project, but should be a working CameraX sample project: https://github.com/v-hogood/CameraXSamples/tree/master
  2. Navigate to CameraActivity (https://github.com/v-hogood/CameraXSamples/blob/9aac3649fa8bdd247ca6828d8940e6a0deaef5eb/CameraXTfLite/CameraActivity.cs#L161).
  3. Pretend that you have already queried the device to find a physical camera lens with id 3.
  4. Try to modify new CameraSelector.Builder().RequireLensFacing(lensFacing).Build(); so that it specifically selects the CameraInfo with lens id 3. The way to do this is with AddCameraFilter.

Did you find any workaround?

No workaround found.

Relevant log output

No response

I think it would be something like:

var selector = new CameraSelector.Builder ()
                    .AddCameraFilter (new MyCameraFilter ())
                    .Build ();

class MyCameraFilter : Java.Lang.Object, ICameraFilter {
    public IList<ICameraInfo> Filter (IList<ICameraInfo> p0) => p0.Where (c => c.LensFacing == 3);
}

That works perfectly. : Java.Lang.Object, was the missing key.

Thank you so much. Up to you whether to leave this open; I did ask for help on a large C# Discord server and nobody who answered could figure it out either.


Note to anyone finding this later:
The list you return from filter must be modifiable (the Java implementation calls retainAll on it).

Therefore, simply returning the same list passed in (p0) will result in a Java.Lang.UnsupportedOperationException. Calling ToList() on it fixes it.


Also, LensFacing is not the same as the lens id. There doesn't seem to be a way to get that directly from CameraInfo, so you'll need to store that mapping in memory elsewhere and do a lookup.