Metering improvements (#741)

* Increase metering timeout for touch metering

* Improve DeviceEncoders to respect max block count

* Reorder block

* Update emulator to 29.3.4

* Update emulator to 29.3.4 (2)

* Improve exposure metering for legacy sensors
pull/744/head
Mattia Iavarone 5 years ago committed by GitHub
parent 1a88cd09f4
commit 141902c6cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/build.yml
  2. 4
      cameraview/build.gradle
  3. 7
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  4. 38
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/meter/ExposureMeter.java
  5. 28
      cameraview/src/main/java/com/otaliastudios/cameraview/internal/DeviceEncoders.java

@ -72,7 +72,7 @@ jobs:
disable-animations: true
profile: Nexus 5X
emulator-options: -no-snapshot -no-window -no-boot-anim -camera-back emulated -camera-front emulated -gpu swiftshader_indirect
emulator-build: 6031357
emulator-build: 6110076
script: ./.github/workflows/emulator_script.sh
- name: Upload emulator tests artifact
uses: actions/upload-artifact@v1

@ -145,7 +145,7 @@ bintray {
// From official sample https://github.com/bintray/bintray-examples/blob/master/gradle-aar-example/build.gradle
task sourcesJar(type: Jar) {
classifier = 'sources'
archiveClassifier.set('sources')
from android.sourceSets.main.java.sourceFiles
}
@ -167,7 +167,7 @@ task javadoc(type: Javadoc) {
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
archiveClassifier.set('javadoc')
from javadoc.destinationDir
}

@ -83,7 +83,8 @@ public class Camera2Engine extends CameraBaseEngine implements
ActionHolder {
private static final int FRAME_PROCESSING_FORMAT = ImageFormat.YUV_420_888;
@VisibleForTesting static final long METER_TIMEOUT = 2500;
@VisibleForTesting static final long METER_TIMEOUT = 5000;
private static final long METER_TIMEOUT_SHORT = 2500;
private final CameraManager mManager;
private String mCameraId;
@ -770,7 +771,7 @@ public class Camera2Engine extends CameraBaseEngine implements
boolean doMetering) {
if (doMetering) {
LOG.i("onTakePictureSnapshot:", "doMetering is true. Delaying.");
Action action = Actions.timeout(METER_TIMEOUT, createMeterAction(null));
Action action = Actions.timeout(METER_TIMEOUT_SHORT, createMeterAction(null));
action.addCallback(new CompletionCallback() {
@Override
protected void onActionCompleted(@NonNull Action action) {
@ -803,7 +804,7 @@ public class Camera2Engine extends CameraBaseEngine implements
protected void onTakePicture(@NonNull final PictureResult.Stub stub, boolean doMetering) {
if (doMetering) {
LOG.i("onTakePicture:", "doMetering is true. Delaying.");
Action action = Actions.timeout(METER_TIMEOUT, createMeterAction(null));
Action action = Actions.timeout(METER_TIMEOUT_SHORT, createMeterAction(null));
action.addCallback(new CompletionCallback() {
@Override
protected void onActionCompleted(@NonNull Action action) {

@ -24,6 +24,9 @@ public class ExposureMeter extends BaseMeter {
private static final int STATE_WAITING_PRECAPTURE = 0;
private static final int STATE_WAITING_PRECAPTURE_END = 1;
private boolean mSupportsAreas = false;
private boolean mSupportsTrigger = false;
@SuppressWarnings("WeakerAccess")
public ExposureMeter(@NonNull List<MeteringRectangle> areas, boolean skipIfPossible) {
super(areas, skipIfPossible);
@ -32,9 +35,9 @@ public class ExposureMeter extends BaseMeter {
@Override
protected boolean checkIsSupported(@NonNull ActionHolder holder) {
// In our case, this means checking if we support the AE precapture trigger.
boolean isNotLegacy = readCharacteristic(
boolean isLegacy = readCharacteristic(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL, -1)
!= CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
== CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
Integer aeMode = holder.getBuilder(this).get(CaptureRequest.CONTROL_AE_MODE);
boolean isAEOn = aeMode != null &&
(aeMode == CameraCharacteristics.CONTROL_AE_MODE_ON
@ -43,8 +46,13 @@ public class ExposureMeter extends BaseMeter {
|| aeMode == CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE
|| aeMode == 5
/* CameraCharacteristics.CONTROL_AE_MODE_ON_EXTERNAL_FLASH, API 28 */);
boolean result = isNotLegacy && isAEOn;
LOG.i("checkIsSupported:", result);
mSupportsTrigger = !isLegacy;
mSupportsAreas = readCharacteristic(CameraCharacteristics.CONTROL_MAX_REGIONS_AE,
0) > 0;
boolean result = isAEOn && (mSupportsTrigger || mSupportsAreas);
LOG.i("checkIsSupported:", result,
"trigger:", mSupportsTrigger,
"areas:", mSupportsAreas);
return result;
}
@ -66,22 +74,26 @@ public class ExposureMeter extends BaseMeter {
protected void onStarted(@NonNull ActionHolder holder, @NonNull List<MeteringRectangle> areas) {
LOG.i("onStarted:", "with areas:", areas);
// Launch the precapture trigger.
holder.getBuilder(this).set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
// Check the regions.
int maxRegions = readCharacteristic(CameraCharacteristics.CONTROL_MAX_REGIONS_AE,
0);
if (!areas.isEmpty() && maxRegions > 0) {
int max = Math.min(maxRegions, areas.size());
if (mSupportsAreas && !areas.isEmpty()) {
int max = readCharacteristic(CameraCharacteristics.CONTROL_MAX_REGIONS_AE, 0);
max = Math.min(max, areas.size());
holder.getBuilder(this).set(CaptureRequest.CONTROL_AE_REGIONS,
areas.subList(0, max).toArray(new MeteringRectangle[]{}));
}
if (mSupportsTrigger) {
holder.getBuilder(this).set(
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
}
// Apply
holder.applyBuilder(this);
if (mSupportsTrigger) {
setState(STATE_WAITING_PRECAPTURE);
} else {
setState(STATE_WAITING_PRECAPTURE_END);
}
}
@Override

@ -7,6 +7,7 @@ import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.os.Build;
import android.util.Range;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -196,10 +197,7 @@ public class DeviceEncoders {
public int compare(MediaCodecInfo o1, MediaCodecInfo o2) {
boolean hw1 = isHardwareEncoder(o1.getName());
boolean hw2 = isHardwareEncoder(o2.getName());
if (hw1 && hw2) return 0;
if (hw1) return -1;
if (hw2) return 1;
return 0;
return Boolean.compare(hw2, hw1);
}
});
}
@ -260,6 +258,28 @@ public class DeviceEncoders {
" Range:" + mVideoCapabilities.getSupportedHeights());
}
// We cannot change the aspect ratio, but the max block count might also be the
// issue. Try to find a width that contains a height that would accept our AR.
try {
if (!mVideoCapabilities.getSupportedHeightsFor(width).contains(height)) {
int candidateWidth = width;
int minWidth = mVideoCapabilities.getSupportedWidths().getLower();
int widthAlignment = mVideoCapabilities.getWidthAlignment();
while (candidateWidth >= minWidth) {
// Reduce by 32 and realign just in case, then check if our AR is now
// supported. If it is, restart from scratch to go through the other checks.
candidateWidth -= 32;
while (candidateWidth % widthAlignment != 0) candidateWidth--;
int candidateHeight = (int) Math.round(candidateWidth / aspect);
if (mVideoCapabilities.getSupportedHeightsFor(candidateWidth)
.contains(candidateHeight)) {
LOG.w("getSupportedVideoSize - restarting with smaller size.");
return getSupportedVideoSize(new Size(candidateWidth, candidateHeight));
}
}
}
} catch (IllegalArgumentException ignore) {}
// It's still possible that we're unsupported for other reasons.
if (!mVideoCapabilities.isSizeSupported(width, height)) {
throw new VideoException("Size not supported for unknown reason." +

Loading…
Cancel
Save