Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[camera] android-rework part 3: Android exposure related features #3797

Merged
merged 13 commits into from
May 27, 2021

Conversation

mvanbeusekom
Copy link
Contributor

Adds exposure related features containing the implementation to handle auto exposure, exposure lock, exposure offset and exposure point via the Android Camera2 API.

This is the third PR in a series of pull-requests which will gradually introduce changes from PR #3651, making it easier to review the code (as discussed with @stuartmorgan).

If you had to change anything in the flutter/tests repo, include a link to the migration guide as per the breaking change policy.

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I signed the CLA.
  • The title of the PR starts with the name of the plugin surrounded by square brackets, e.g. [shared_preferences]
  • I listed at least one issue that this PR fixes in the description above.
  • I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy.
    • Since this will be a series of pull-requests I will update the version in the last PR of the series.
  • I updated CHANGELOG.md to add a description of the change.
    • Since this will be a series of pull-requests I will update the version in the last PR of the series.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@google-cla
Copy link

google-cla bot commented Apr 8, 2021

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@acoutts
Copy link
Contributor

acoutts commented Apr 8, 2021

@googlebot I consent.

@google-cla google-cla bot added cla: yes and removed cla: no labels Apr 8, 2021
@mvanbeusekom mvanbeusekom force-pushed the camera-android/exposure_features branch from 7a37b86 to 461309a Compare April 20, 2021 11:48
Copy link
Contributor

@stuartmorgan stuartmorgan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial pass comments below; I haven't reviewed the tests yet.

default:
requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to write this as a switch rather than just: requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, currentSetting = ExposureMode.locked);?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, no particular reason. I have adjusted the code.

}

/**
* Return the minimum exposure offset double value.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returns

s/double value/value/
No need to document things in comments that are expressly indicated by the types in the function signature.

Copy link
Contributor Author

@mvanbeusekom mvanbeusekom May 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

/**
* Return the max exposure offset double value.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

Copy link
Contributor Author

@mvanbeusekom mvanbeusekom May 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


/**
* Returns the exposure offset step size. This is the smallest amount which the exposure offset
* can be changed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This second sentence seems misleading; it implies that this value is a just minimum delta in exposure offset changes, rather than a multiplier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

* This represents the exposure offset value. It holds the minimum and maximum values, as well as
* the current setting value.
*/
public class ExposureOffsetValue {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are min/max and current value the same object? That seems surprising since they are fundamentally different kinds of values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct. The ExposureOffsetValue is currently used to return all values at once to the Camera class. However it would make much more sense if the Camera class could just call the ExposureOffsetFeature.getMinExposureOffset or ExposureOffsetFeature.getMaxExposureOffset methods when it needs to returns these values to the Dart side.

If have removed the ExposureOffsetValue and replaced it with a simple double and made the getMinExposureOffset and getMaxExposureOffset public.

public MeteringRectangle getMeteringRectangleForPoint(Size maxBoundaries, double x, double y) {
assert (x >= 0 && x <= 1);
assert (y >= 0 && y <= 1);
if (maxBoundaries == null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// Interpolate the target coordinate
int targetX = (int) Math.round(x * ((double) (maxBoundaries.getWidth() - 1)));
int targetY = (int) Math.round(y * ((double) (maxBoundaries.getHeight() - 1)));
// Determine the dimensions of the metering triangle (10th of the viewport)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is 1/10th coming from? Is this arbitrarily chosen? A standard? Other? A comment would be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added explanation in the method API documentation.


/**
* Holds the current region boundaries. When this is created, you must provide a
* CaptureRequestBuilder for which we can read the distortion correction settings from.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who are "you" and "we"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have merged the RegionBoundariesFeature class with the CameraRegions class which makes this file obsolete. I made sure to include the feedback you provided in the new structure as well.

The RegionBoundariesFeature in fact was used as a factory to create an instance of the CameraRegions class. The actual implementation didn't represent a "Camera Feature" and was mis-used as a feature and consumed by other feature classes.

super(cameraProperties);

// No distortion correction support
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.P
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just make this check internal to supportsDistortionCorrection? Assuming false is always going to be the fallback, presumably.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to silence the linter, since the else construct contains code that is only available on API level P and higher.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I missed that this was a < check; usually it's the opposite. I think it would be clearer to flip the bodies and use

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && supportsDistortionCorrection()) {
  // the distortion correction code
} else {
  // the fallback code
}

private boolean supportsDistortionCorrection() {
int[] availableDistortionCorrectionModes =
cameraProperties.getDistortionCorrectionAvailableModes();
if (availableDistortionCorrectionModes == null) availableDistortionCorrectionModes = new int[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Braces.

@ghost
Copy link

ghost commented Apr 30, 2021

S.a

@mvanbeusekom
Copy link
Contributor Author

@stuartmorgan thank you for the review. I have processed your feedback and would appreciate it if you could have another look.

Copy link
Contributor

@stuartmorgan stuartmorgan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few small things left, otherwise looks good.

super(cameraProperties);

// No distortion correction support
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.P
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I missed that this was a < check; usually it's the opposite. I think it would be clearer to flip the bodies and use

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && supportsDistortionCorrection()) {
  // the distortion correction code
} else {
  // the fallback code
}

}

/**
* Return the minimum exposure offset double value.
* Returns the minimum exposure offset value, in counts of {@link #getExposureOffsetStepSize}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value is multiplied by stepSize, so this seems wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was strongly influenced by the documentation from the Android Camera2 API when I documented this method.

Here this mention:

Maximum and minimum exposure compensation values for android.control.aeExposureCompensation, in counts of android.control.aeCompensationStep, that are supported by this camera device.

I am not saying this would be necessarily correct or the best, just wanted to quickly verify with you before I update it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow. You're pointing to the documentation for the exposure range, which is line 64 here. This method doesn't return that, it returns that multiplied by the step size (line 67). If you take step counts, and multiply by step sizes, you don't have step counts any more. You have the actual exposure value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right, I completely read the Android documentation wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Range<Integer> range = cameraProperties.getControlAutoExposureCompensationRange();
double minStepped = range == null ? 0 : range.getLower();
double stepSize = getExposureOffsetStepSize();
return minStepped * stepSize;
}

/**
* Return the max exposure offset double value.
* Returns the maximum exposure offset value, in counts of {@link #getExposureOffsetStepSize}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Contributor

@stuartmorgan stuartmorgan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@stuartmorgan
Copy link
Contributor

Something seems to have gone wrong with the Windows re-run; it either didn't schedule, or didn't update the status here. Maybe something related to the jobs changing right around the time I restarted it?

I'm just going to land this, as the Windows test isn't relevant to the change.

@stuartmorgan stuartmorgan merged commit 2bfba7b into flutter:master May 27, 2021
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 27, 2021
@mvanbeusekom mvanbeusekom deleted the camera-android/exposure_features branch May 27, 2021 17:27
yasargil added a commit to yasargil/plugins that referenced this pull request Jun 2, 2021
* master: (131 commits)
  [in_app_purchase] fix "autoConsume" param in "buyConsumable" (flutter#3957)
  [video_player_web] fix: set autoplay to false during initialization (flutter#3985)
  [multiple_web] Adapt web PlatformView widgets to work slotted. (flutter#3964)
  [url_launcher] Add iOS unit and UI tests (flutter#3987)
  [image_picker] Change storage location for camera captures to internal cache on Android, to comply with new Google Play storage requirements.  (flutter#3956)
  [script/tool] Use 'dart pub' instead of deprecated 'pub' (flutter#3991)
  [video_player] Add iOS unit and UI tests (flutter#3986)
  Add pubspec convention checks (flutter#3984)
  Enable pubspec dependency sorting lint (flutter#3983)
  [image_picker] Migrate maven repo from jcenter to mavenCentral (flutter#3915)
  [video_player] Update README.md (flutter#3975)
  [script/tool] speed up the pub get portion of the analyze command (flutter#3982)
  Revert commit e742a7b (flutter#3976)
  Added support to request list of purchases (flutter#3944)
  [google_maps_flutter] Add iOS unit and UI tests (flutter#3978)
  Added Windows to the description (flutter#3936)
  use 'flutter pub get' for both dart and flutter packages (flutter#3973)
  [camera] android-rework part 3: Android exposure related features (flutter#3797)
  Remove exoplayer workaround from everything but video_player (flutter#3980)
  Allow reverts when checking versions (flutter#3981)
  ...
fotiDim pushed a commit to fotiDim/plugins that referenced this pull request Sep 13, 2021
…utter#3797)

Adds exposure related features containing the implementation to handle auto exposure, exposure lock, exposure offset and exposure point via the Android Camera2 API.

This is the third PR in a series of pull-requests which will gradually introduce changes from PR flutter#3651, making it easier to review the code (as discussed with @stuartmorgan).
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants