Make CameraOptions engine aware

pull/691/head
Mattia Iavarone 6 years ago
parent 406f121731
commit 337d845ecc
  1. 314
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java
  2. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java
  3. 128
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Options.java
  4. 35
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  5. 160
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Options.java
  6. 1
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full1PictureRecorder.java
  7. 1
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full2PictureRecorder.java
  8. 1
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/Snapshot1PictureRecorder.java
  9. 1
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java

@ -44,263 +44,26 @@ import java.util.Set;
/**
* Options telling you what is available and what is not.
*/
public class CameraOptions {
private Set<WhiteBalance> supportedWhiteBalance = new HashSet<>(5);
private Set<Facing> supportedFacing = new HashSet<>(2);
private Set<Flash> supportedFlash = new HashSet<>(4);
private Set<Hdr> supportedHdr = new HashSet<>(2);
private Set<Size> supportedPictureSizes = new HashSet<>(15);
private Set<Size> supportedVideoSizes = new HashSet<>(5);
private Set<AspectRatio> supportedPictureAspectRatio = new HashSet<>(4);
private Set<AspectRatio> supportedVideoAspectRatio = new HashSet<>(3);
private boolean zoomSupported;
private boolean exposureCorrectionSupported;
private float exposureCorrectionMinValue;
private float exposureCorrectionMaxValue;
private boolean autoFocusSupported;
private float previewFrameRateMinValue;
private float previewFrameRateMaxValue;
public CameraOptions(@NonNull Camera.Parameters params, int cameraId, boolean flipSizes) {
List<String> strings;
Camera1Mapper mapper = Camera1Mapper.get();
// Facing
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, cameraInfo);
Facing value = mapper.unmapFacing(cameraInfo.facing);
if (value != null) supportedFacing.add(value);
}
// WB
strings = params.getSupportedWhiteBalance();
if (strings != null) {
for (String string : strings) {
WhiteBalance value = mapper.unmapWhiteBalance(string);
if (value != null) supportedWhiteBalance.add(value);
}
}
// Flash
supportedFlash.add(Flash.OFF);
strings = params.getSupportedFlashModes();
if (strings != null) {
for (String string : strings) {
Flash value = mapper.unmapFlash(string);
if (value != null) supportedFlash.add(value);
}
}
// Hdr
supportedHdr.add(Hdr.OFF);
strings = params.getSupportedSceneModes();
if (strings != null) {
for (String string : strings) {
Hdr value = mapper.unmapHdr(string);
if (value != null) supportedHdr.add(value);
}
}
// zoom
zoomSupported = params.isZoomSupported();
// autofocus
autoFocusSupported = params.getSupportedFocusModes()
.contains(Camera.Parameters.FOCUS_MODE_AUTO);
// Exposure correction
float step = params.getExposureCompensationStep();
exposureCorrectionMinValue = (float) params.getMinExposureCompensation() * step;
exposureCorrectionMaxValue = (float) params.getMaxExposureCompensation() * step;
exposureCorrectionSupported = params.getMinExposureCompensation() != 0
|| params.getMaxExposureCompensation() != 0;
// Picture Sizes
List<Camera.Size> sizes = params.getSupportedPictureSizes();
for (Camera.Size size : sizes) {
int width = flipSizes ? size.height : size.width;
int height = flipSizes ? size.width : size.height;
supportedPictureSizes.add(new Size(width, height));
supportedPictureAspectRatio.add(AspectRatio.of(width, height));
}
// Video Sizes
// As a safety measure, remove Sizes bigger than CamcorderProfile.highest
CamcorderProfile profile = CamcorderProfiles.get(cameraId,
new Size(Integer.MAX_VALUE, Integer.MAX_VALUE));
Size videoMaxSize = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
List<Camera.Size> vsizes = params.getSupportedVideoSizes();
if (vsizes != null) {
for (Camera.Size size : vsizes) {
if (size.width <= videoMaxSize.getWidth()
&& size.height <= videoMaxSize.getHeight()) {
int width = flipSizes ? size.height : size.width;
int height = flipSizes ? size.width : size.height;
supportedVideoSizes.add(new Size(width, height));
supportedVideoAspectRatio.add(AspectRatio.of(width, height));
}
}
} else {
// StackOverflow threads seems to agree that if getSupportedVideoSizes is null,
// previews can be used.
List<Camera.Size> fallback = params.getSupportedPreviewSizes();
for (Camera.Size size : fallback) {
if (size.width <= videoMaxSize.getWidth()
&& size.height <= videoMaxSize.getHeight()) {
int width = flipSizes ? size.height : size.width;
int height = flipSizes ? size.width : size.height;
supportedVideoSizes.add(new Size(width, height));
supportedVideoAspectRatio.add(AspectRatio.of(width, height));
}
}
}
// Preview FPS
previewFrameRateMinValue = Float.MAX_VALUE;
previewFrameRateMaxValue = -Float.MAX_VALUE;
List<int[]> fpsRanges = params.getSupportedPreviewFpsRange();
for (int[] fpsRange : fpsRanges) {
float lower = (float) fpsRange[0] / 1000F;
float upper = (float) fpsRange[1] / 1000F;
previewFrameRateMinValue = Math.min(previewFrameRateMinValue, lower);
previewFrameRateMaxValue = Math.max(previewFrameRateMaxValue, upper);
}
}
// Camera2Engine constructor.
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public CameraOptions(@NonNull CameraManager manager,
@NonNull String cameraId,
boolean flipSizes) throws CameraAccessException {
Camera2Mapper mapper = Camera2Mapper.get();
CameraCharacteristics cameraCharacteristics = manager.getCameraCharacteristics(cameraId);
// Facing
for (String cameraId1 : manager.getCameraIdList()) {
CameraCharacteristics cameraCharacteristics1 = manager
.getCameraCharacteristics(cameraId1);
Integer cameraFacing = cameraCharacteristics1.get(CameraCharacteristics.LENS_FACING);
if (cameraFacing != null) {
Facing value = mapper.unmapFacing(cameraFacing);
if (value != null) supportedFacing.add(value);
}
}
// WB
int[] awbModes = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES);
//noinspection ConstantConditions
for (int awbMode : awbModes) {
WhiteBalance value = mapper.unmapWhiteBalance(awbMode);
if (value != null) supportedWhiteBalance.add(value);
}
// Flash
supportedFlash.add(Flash.OFF);
Boolean hasFlash = cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
if (hasFlash != null && hasFlash) {
int[] aeModes = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
//noinspection ConstantConditions
for (int aeMode : aeModes) {
Set<Flash> flashes = mapper.unmapFlash(aeMode);
supportedFlash.addAll(flashes);
}
}
// HDR
supportedHdr.add(Hdr.OFF);
int[] sceneModes = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES);
//noinspection ConstantConditions
for (int sceneMode : sceneModes) {
Hdr value = mapper.unmapHdr(sceneMode);
if (value != null) supportedHdr.add(value);
}
// Zoom
Float maxZoom = cameraCharacteristics.get(
CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
if(maxZoom != null) {
zoomSupported = maxZoom > 1;
}
// AutoFocus
// This now means 3A metering with respect to a specific region of the screen.
// Some controls (AF, AE) have special triggers that might or might not be supported.
// But they can also be on some continuous search mode so that the trigger is not needed.
// What really matters in my opinion is the availability of regions.
Integer afRegions = cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
Integer aeRegions = cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
Integer awbRegions = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
autoFocusSupported = (afRegions != null && afRegions > 0)
|| (aeRegions != null && aeRegions > 0)
|| (awbRegions != null && awbRegions > 0);
// Exposure correction
Range<Integer> exposureRange = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
Rational exposureStep = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);
if (exposureRange != null && exposureStep != null && exposureStep.floatValue() != 0) {
exposureCorrectionMinValue = exposureRange.getLower() / exposureStep.floatValue();
exposureCorrectionMaxValue = exposureRange.getUpper() / exposureStep.floatValue();
}
exposureCorrectionSupported = exposureCorrectionMinValue != 0
&& exposureCorrectionMaxValue != 0;
// Picture Sizes
StreamConfigurationMap streamMap = cameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (streamMap == null) {
throw new RuntimeException("StreamConfigurationMap is null. Should not happen.");
}
android.util.Size[] psizes = streamMap.getOutputSizes(ImageFormat.JPEG);
for (android.util.Size size : psizes) {
int width = flipSizes ? size.getHeight() : size.getWidth();
int height = flipSizes ? size.getWidth() : size.getHeight();
supportedPictureSizes.add(new Size(width, height));
supportedPictureAspectRatio.add(AspectRatio.of(width, height));
}
// Video Sizes
// As a safety measure, remove Sizes bigger than CamcorderProfile.highest
CamcorderProfile profile = CamcorderProfiles.get(cameraId,
new Size(Integer.MAX_VALUE, Integer.MAX_VALUE));
Size videoMaxSize = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
android.util.Size[] vsizes = streamMap.getOutputSizes(MediaRecorder.class);
for (android.util.Size size : vsizes) {
if (size.getWidth() <= videoMaxSize.getWidth()
&& size.getHeight() <= videoMaxSize.getHeight()) {
int width = flipSizes ? size.getHeight() : size.getWidth();
int height = flipSizes ? size.getWidth() : size.getHeight();
supportedVideoSizes.add(new Size(width, height));
supportedVideoAspectRatio.add(AspectRatio.of(width, height));
}
}
// Preview FPS
Range<Integer>[] range = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
if (range != null) {
previewFrameRateMinValue = Float.MAX_VALUE;
previewFrameRateMaxValue = -Float.MAX_VALUE;
for (Range<Integer> fpsRange : range) {
previewFrameRateMinValue = Math.min(previewFrameRateMinValue, fpsRange.getLower());
previewFrameRateMaxValue = Math.max(previewFrameRateMaxValue, fpsRange.getUpper());
}
} else {
previewFrameRateMinValue = 0F;
previewFrameRateMaxValue = 0F;
}
}
public abstract class CameraOptions {
protected Set<WhiteBalance> supportedWhiteBalance = new HashSet<>(5);
protected Set<Facing> supportedFacing = new HashSet<>(2);
protected Set<Flash> supportedFlash = new HashSet<>(4);
protected Set<Hdr> supportedHdr = new HashSet<>(2);
protected Set<Size> supportedPictureSizes = new HashSet<>(15);
protected Set<Size> supportedVideoSizes = new HashSet<>(5);
protected Set<AspectRatio> supportedPictureAspectRatio = new HashSet<>(4);
protected Set<AspectRatio> supportedVideoAspectRatio = new HashSet<>(3);
protected boolean zoomSupported;
protected boolean exposureCorrectionSupported;
protected float exposureCorrectionMinValue;
protected float exposureCorrectionMaxValue;
protected boolean autoFocusSupported;
protected float previewFrameRateMinValue;
protected float previewFrameRateMaxValue;
protected CameraOptions() { }
/**
* Shorthand for getSupported*().contains(value).
@ -308,7 +71,7 @@ public class CameraOptions {
* @param control value to check
* @return whether it's supported
*/
public boolean supports(@NonNull Control control) {
public final boolean supports(@NonNull Control control) {
return getSupportedControls(control.getClass()).contains(control);
}
@ -319,7 +82,7 @@ public class CameraOptions {
* @param action value to be checked
* @return whether it's supported
*/
public boolean supports(@NonNull GestureAction action) {
public final boolean supports(@NonNull GestureAction action) {
switch (action) {
case AUTO_FOCUS:
return isAutoFocusSupported();
@ -338,7 +101,8 @@ public class CameraOptions {
@SuppressWarnings("unchecked")
@NonNull
public <T extends Control> Collection<T> getSupportedControls(@NonNull Class<T> controlClass) {
public final <T extends Control> Collection<T> getSupportedControls(
@NonNull Class<T> controlClass) {
if (controlClass.equals(Audio.class)) {
return (Collection<T>) Arrays.asList(Audio.values());
} else if (controlClass.equals(Facing.class)) {
@ -370,7 +134,7 @@ public class CameraOptions {
* @return a collection of supported values.
*/
@NonNull
public Collection<Size> getSupportedPictureSizes() {
public final Collection<Size> getSupportedPictureSizes() {
return Collections.unmodifiableSet(supportedPictureSizes);
}
@ -381,7 +145,7 @@ public class CameraOptions {
*/
@SuppressWarnings("WeakerAccess")
@NonNull
public Collection<AspectRatio> getSupportedPictureAspectRatios() {
public final Collection<AspectRatio> getSupportedPictureAspectRatios() {
return Collections.unmodifiableSet(supportedPictureAspectRatio);
}
@ -391,7 +155,7 @@ public class CameraOptions {
* @return a collection of supported values.
*/
@NonNull
public Collection<Size> getSupportedVideoSizes() {
public final Collection<Size> getSupportedVideoSizes() {
return Collections.unmodifiableSet(supportedVideoSizes);
}
@ -402,7 +166,7 @@ public class CameraOptions {
*/
@SuppressWarnings("WeakerAccess")
@NonNull
public Collection<AspectRatio> getSupportedVideoAspectRatios() {
public final Collection<AspectRatio> getSupportedVideoAspectRatios() {
return Collections.unmodifiableSet(supportedVideoAspectRatio);
}
@ -414,7 +178,7 @@ public class CameraOptions {
* @return a collection of supported values.
*/
@NonNull
public Collection<Facing> getSupportedFacing() {
public final Collection<Facing> getSupportedFacing() {
return Collections.unmodifiableSet(supportedFacing);
}
@ -428,7 +192,7 @@ public class CameraOptions {
* @return a collection of supported values.
*/
@NonNull
public Collection<Flash> getSupportedFlash() {
public final Collection<Flash> getSupportedFlash() {
return Collections.unmodifiableSet(supportedFlash);
}
@ -443,7 +207,7 @@ public class CameraOptions {
* @return a collection of supported values.
*/
@NonNull
public Collection<WhiteBalance> getSupportedWhiteBalance() {
public final Collection<WhiteBalance> getSupportedWhiteBalance() {
return Collections.unmodifiableSet(supportedWhiteBalance);
}
@ -456,7 +220,7 @@ public class CameraOptions {
*/
@SuppressWarnings("WeakerAccess")
@NonNull
public Collection<Hdr> getSupportedHdr() {
public final Collection<Hdr> getSupportedHdr() {
return Collections.unmodifiableSet(supportedHdr);
}
@ -466,7 +230,7 @@ public class CameraOptions {
*
* @return whether zoom is supported.
*/
public boolean isZoomSupported() {
public final boolean isZoomSupported() {
return zoomSupported;
}
@ -478,7 +242,7 @@ public class CameraOptions {
*
* @return whether auto focus is supported.
*/
public boolean isAutoFocusSupported() {
public final boolean isAutoFocusSupported() {
return autoFocusSupported;
}
@ -490,7 +254,7 @@ public class CameraOptions {
* @see #getExposureCorrectionMaxValue()
* @return whether exposure correction is supported.
*/
public boolean isExposureCorrectionSupported() {
public final boolean isExposureCorrectionSupported() {
return exposureCorrectionSupported;
}
@ -500,7 +264,7 @@ public class CameraOptions {
*
* @return min EV value
*/
public float getExposureCorrectionMinValue() {
public final float getExposureCorrectionMinValue() {
return exposureCorrectionMinValue;
}
@ -511,7 +275,7 @@ public class CameraOptions {
*
* @return max EV value
*/
public float getExposureCorrectionMaxValue() {
public final float getExposureCorrectionMaxValue() {
return exposureCorrectionMaxValue;
}
@ -520,7 +284,7 @@ public class CameraOptions {
*
* @return the min value
*/
public float getPreviewFrameRateMinValue() {
public final float getPreviewFrameRateMinValue() {
return previewFrameRateMinValue;
}
@ -529,7 +293,7 @@ public class CameraOptions {
*
* @return the max value
*/
public float getPreviewFrameRateMaxValue() {
public final float getPreviewFrameRateMaxValue() {
return previewFrameRateMaxValue;
}
}

@ -157,7 +157,7 @@ public class Camera1Engine extends CameraEngine implements
// Set parameters that might have been set before the camera was opened.
LOG.i("onStartEngine:", "Applying default parameters.");
Camera.Parameters params = mCamera.getParameters();
mCameraOptions = new CameraOptions(params, mCameraId,
mCameraOptions = new Camera1Options(params, mCameraId,
getAngles().flip(Reference.SENSOR, Reference.VIEW));
applyAllParameters(params);
mCamera.setParameters(params);

@ -0,0 +1,128 @@
package com.otaliastudios.cameraview.engine;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.CameraOptions;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.controls.Hdr;
import com.otaliastudios.cameraview.controls.WhiteBalance;
import com.otaliastudios.cameraview.engine.mappers.Camera1Mapper;
import com.otaliastudios.cameraview.internal.utils.CamcorderProfiles;
import com.otaliastudios.cameraview.size.AspectRatio;
import com.otaliastudios.cameraview.size.Size;
import java.util.List;
class Camera1Options extends CameraOptions {
Camera1Options(@NonNull Camera.Parameters params, int cameraId, boolean flipSizes) {
List<String> strings;
Camera1Mapper mapper = Camera1Mapper.get();
// Facing
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, cameraInfo);
Facing value = mapper.unmapFacing(cameraInfo.facing);
if (value != null) supportedFacing.add(value);
}
// WB
strings = params.getSupportedWhiteBalance();
if (strings != null) {
for (String string : strings) {
WhiteBalance value = mapper.unmapWhiteBalance(string);
if (value != null) supportedWhiteBalance.add(value);
}
}
// Flash
supportedFlash.add(Flash.OFF);
strings = params.getSupportedFlashModes();
if (strings != null) {
for (String string : strings) {
Flash value = mapper.unmapFlash(string);
if (value != null) supportedFlash.add(value);
}
}
// Hdr
supportedHdr.add(Hdr.OFF);
strings = params.getSupportedSceneModes();
if (strings != null) {
for (String string : strings) {
Hdr value = mapper.unmapHdr(string);
if (value != null) supportedHdr.add(value);
}
}
// zoom
zoomSupported = params.isZoomSupported();
// autofocus
autoFocusSupported = params.getSupportedFocusModes()
.contains(Camera.Parameters.FOCUS_MODE_AUTO);
// Exposure correction
float step = params.getExposureCompensationStep();
exposureCorrectionMinValue = (float) params.getMinExposureCompensation() * step;
exposureCorrectionMaxValue = (float) params.getMaxExposureCompensation() * step;
exposureCorrectionSupported = params.getMinExposureCompensation() != 0
|| params.getMaxExposureCompensation() != 0;
// Picture Sizes
List<Camera.Size> sizes = params.getSupportedPictureSizes();
for (Camera.Size size : sizes) {
int width = flipSizes ? size.height : size.width;
int height = flipSizes ? size.width : size.height;
supportedPictureSizes.add(new Size(width, height));
supportedPictureAspectRatio.add(AspectRatio.of(width, height));
}
// Video Sizes
// As a safety measure, remove Sizes bigger than CamcorderProfile.highest
CamcorderProfile profile = CamcorderProfiles.get(cameraId,
new Size(Integer.MAX_VALUE, Integer.MAX_VALUE));
Size videoMaxSize = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
List<Camera.Size> vsizes = params.getSupportedVideoSizes();
if (vsizes != null) {
for (Camera.Size size : vsizes) {
if (size.width <= videoMaxSize.getWidth()
&& size.height <= videoMaxSize.getHeight()) {
int width = flipSizes ? size.height : size.width;
int height = flipSizes ? size.width : size.height;
supportedVideoSizes.add(new Size(width, height));
supportedVideoAspectRatio.add(AspectRatio.of(width, height));
}
}
} else {
// StackOverflow threads seems to agree that if getSupportedVideoSizes is null,
// previews can be used.
List<Camera.Size> fallback = params.getSupportedPreviewSizes();
for (Camera.Size size : fallback) {
if (size.width <= videoMaxSize.getWidth()
&& size.height <= videoMaxSize.getHeight()) {
int width = flipSizes ? size.height : size.width;
int height = flipSizes ? size.width : size.height;
supportedVideoSizes.add(new Size(width, height));
supportedVideoAspectRatio.add(AspectRatio.of(width, height));
}
}
}
// Preview FPS
previewFrameRateMinValue = Float.MAX_VALUE;
previewFrameRateMaxValue = -Float.MAX_VALUE;
List<int[]> fpsRanges = params.getSupportedPreviewFpsRange();
for (int[] fpsRange : fpsRanges) {
float lower = (float) fpsRange[0] / 1000F;
float upper = (float) fpsRange[1] / 1000F;
previewFrameRateMinValue = Math.min(previewFrameRateMinValue, lower);
previewFrameRateMaxValue = Math.max(previewFrameRateMaxValue, upper);
}
}
}

@ -387,7 +387,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
LOG.i("createCamera:", "Applying default parameters.");
mCameraCharacteristics = mManager.getCameraCharacteristics(mCameraId);
boolean flip = getAngles().flip(Reference.SENSOR, Reference.VIEW);
mCameraOptions = new CameraOptions(mManager, mCameraId, flip);
mCameraOptions = new Camera2Options(mManager, mCameraId, flip);
createRepeatingRequestBuilder(CameraDevice.TEMPLATE_PREVIEW);
} catch (CameraAccessException e) {
task.trySetException(createCameraException(e));
@ -1329,23 +1329,24 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
@Override
public void setPictureFormat(final @NonNull PictureFormat pictureFormat) {
LOG.i("setPictureFormat", "changing to", pictureFormat, "posting.");
if (pictureFormat == mPictureFormat) return;
mPictureFormat = pictureFormat;
mHandler.run(new Runnable() {
@Override
public void run() {
LOG.i("setPictureFormat", "changing to", pictureFormat,
"executing. BindState:", getBindState(),
"PreviewState:", getPreviewState());
if (getBindState() == STATE_STOPPED) {
LOG.i("setPictureFormat", "not bound so won't restart.");
} else {
LOG.i("setPictureFormat", "bound or binding. Calling restartBind()");
restartBind();
if (pictureFormat != mPictureFormat) {
mPictureFormat = pictureFormat;
LOG.i("setPictureFormat", "changing to", pictureFormat, "posting.");
mHandler.run(new Runnable() {
@Override
public void run() {
LOG.i("setPictureFormat", "changing to", pictureFormat,
"executing. EngineState:", getEngineState(),
"BindState:", getBindState());
if (getEngineState() == STATE_STOPPED) {
LOG.i("setPictureFormat", "not started so won't restart.");
} else {
LOG.i("setPictureFormat", "started or starting. Calling restart()");
restart();
}
}
}
});
});
}
}
//endregion

@ -0,0 +1,160 @@
package com.otaliastudios.cameraview.engine;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.util.Range;
import android.util.Rational;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import com.otaliastudios.cameraview.CameraOptions;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.controls.Hdr;
import com.otaliastudios.cameraview.controls.WhiteBalance;
import com.otaliastudios.cameraview.engine.mappers.Camera2Mapper;
import com.otaliastudios.cameraview.internal.utils.CamcorderProfiles;
import com.otaliastudios.cameraview.size.AspectRatio;
import com.otaliastudios.cameraview.size.Size;
import java.util.Set;
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class Camera2Options extends CameraOptions {
Camera2Options(@NonNull CameraManager manager,
@NonNull String cameraId,
boolean flipSizes) throws CameraAccessException {
Camera2Mapper mapper = Camera2Mapper.get();
CameraCharacteristics cameraCharacteristics = manager.getCameraCharacteristics(cameraId);
// Facing
for (String cameraId1 : manager.getCameraIdList()) {
CameraCharacteristics cameraCharacteristics1 = manager
.getCameraCharacteristics(cameraId1);
Integer cameraFacing = cameraCharacteristics1.get(CameraCharacteristics.LENS_FACING);
if (cameraFacing != null) {
Facing value = mapper.unmapFacing(cameraFacing);
if (value != null) supportedFacing.add(value);
}
}
// WB
int[] awbModes = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES);
//noinspection ConstantConditions
for (int awbMode : awbModes) {
WhiteBalance value = mapper.unmapWhiteBalance(awbMode);
if (value != null) supportedWhiteBalance.add(value);
}
// Flash
supportedFlash.add(Flash.OFF);
Boolean hasFlash = cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
if (hasFlash != null && hasFlash) {
int[] aeModes = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
//noinspection ConstantConditions
for (int aeMode : aeModes) {
Set<Flash> flashes = mapper.unmapFlash(aeMode);
supportedFlash.addAll(flashes);
}
}
// HDR
supportedHdr.add(Hdr.OFF);
int[] sceneModes = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES);
//noinspection ConstantConditions
for (int sceneMode : sceneModes) {
Hdr value = mapper.unmapHdr(sceneMode);
if (value != null) supportedHdr.add(value);
}
// Zoom
Float maxZoom = cameraCharacteristics.get(
CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
if(maxZoom != null) {
zoomSupported = maxZoom > 1;
}
// AutoFocus
// This now means 3A metering with respect to a specific region of the screen.
// Some controls (AF, AE) have special triggers that might or might not be supported.
// But they can also be on some continuous search mode so that the trigger is not needed.
// What really matters in my opinion is the availability of regions.
Integer afRegions = cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
Integer aeRegions = cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
Integer awbRegions = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
autoFocusSupported = (afRegions != null && afRegions > 0)
|| (aeRegions != null && aeRegions > 0)
|| (awbRegions != null && awbRegions > 0);
// Exposure correction
Range<Integer> exposureRange = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
Rational exposureStep = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);
if (exposureRange != null && exposureStep != null && exposureStep.floatValue() != 0) {
exposureCorrectionMinValue = exposureRange.getLower() / exposureStep.floatValue();
exposureCorrectionMaxValue = exposureRange.getUpper() / exposureStep.floatValue();
}
exposureCorrectionSupported = exposureCorrectionMinValue != 0
&& exposureCorrectionMaxValue != 0;
// Picture Sizes
StreamConfigurationMap streamMap = cameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (streamMap == null) {
throw new RuntimeException("StreamConfigurationMap is null. Should not happen.");
}
android.util.Size[] psizes = streamMap.getOutputSizes(ImageFormat.JPEG);
for (android.util.Size size : psizes) {
int width = flipSizes ? size.getHeight() : size.getWidth();
int height = flipSizes ? size.getWidth() : size.getHeight();
supportedPictureSizes.add(new Size(width, height));
supportedPictureAspectRatio.add(AspectRatio.of(width, height));
}
// Video Sizes
// As a safety measure, remove Sizes bigger than CamcorderProfile.highest
CamcorderProfile profile = CamcorderProfiles.get(cameraId,
new Size(Integer.MAX_VALUE, Integer.MAX_VALUE));
Size videoMaxSize = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
android.util.Size[] vsizes = streamMap.getOutputSizes(MediaRecorder.class);
for (android.util.Size size : vsizes) {
if (size.getWidth() <= videoMaxSize.getWidth()
&& size.getHeight() <= videoMaxSize.getHeight()) {
int width = flipSizes ? size.getHeight() : size.getWidth();
int height = flipSizes ? size.getWidth() : size.getHeight();
supportedVideoSizes.add(new Size(width, height));
supportedVideoAspectRatio.add(AspectRatio.of(width, height));
}
}
// Preview FPS
Range<Integer>[] range = cameraCharacteristics.get(
CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
if (range != null) {
previewFrameRateMinValue = Float.MAX_VALUE;
previewFrameRateMaxValue = -Float.MAX_VALUE;
for (Range<Integer> fpsRange : range) {
previewFrameRateMinValue = Math.min(previewFrameRateMinValue, fpsRange.getLower());
previewFrameRateMaxValue = Math.max(previewFrameRateMaxValue, fpsRange.getUpper());
}
} else {
previewFrameRateMinValue = 0F;
previewFrameRateMaxValue = 0F;
}
}
}

@ -61,7 +61,6 @@ public class Full1PictureRecorder extends PictureRecorder {
} catch (IOException e) {
exifRotation = 0;
}
mResult.format = PictureResult.FORMAT_JPEG;
mResult.data = data;
mResult.rotation = exifRotation;
camera.startPreview(); // This is needed, read somewhere in the docs.

@ -106,7 +106,6 @@ public class Full2PictureRecorder extends PictureRecorder
// Just like Camera1, unfortunately, the camera might rotate the image
// and put EXIF=0 instead of respecting our EXIF and leave the image unaltered.
mResult.format = PictureResult.FORMAT_JPEG;
mResult.rotation = 0;
try {
ExifInterface exif = new ExifInterface(new ByteArrayInputStream(mResult.data));

@ -81,7 +81,6 @@ public class Snapshot1PictureRecorder extends PictureRecorder {
mResult.data = data;
mResult.size = new Size(outputRect.width(), outputRect.height());
mResult.rotation = 0;
mResult.format = PictureResult.FORMAT_JPEG;
dispatchResult();
}
});

@ -238,7 +238,6 @@ public class SnapshotGlPictureRecorder extends PictureRecorder {
LOG.i("takeFrame:", "timestampUs:", timestampUs);
mViewport.drawFrame(timestampUs, mTextureId, mTransform);
if (mHasOverlay) mOverlayDrawer.render(timestampUs);
mResult.format = PictureResult.FORMAT_JPEG;
mResult.data = eglSurface.saveFrameTo(Bitmap.CompressFormat.JPEG);
// 6. Cleanup

Loading…
Cancel
Save