New snapshotMaxWidth and snapshotMaxHeight APIs

pull/393/head
Mattia Iavarone 7 years ago
parent 77ed778564
commit 1412e80366
  1. 21
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
  2. 44
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java
  3. 23
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  4. 3
      cameraview/src/main/res/values/attrs.xml

@ -580,18 +580,6 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
/** /**
* Just a note about the snapshot size - it is the PreviewStreamSize, cropped with the view ratio. * Just a note about the snapshot size - it is the PreviewStreamSize, cropped with the view ratio.
* One might be tempted to say that it is the SurfaceSize (which already matches the view ratio),
* but it's not.
*
* The camera sensor will capture preview frames with PreviewStreamSize and that's it. Then they
* are hardware-scaled by the preview surface, but this does not affect the snapshot, as the
* snapshot recorder simply creates another surface.
*
* Done tests to ensure that this is true, by using
* 1. small SurfaceSize and biggest() PreviewStreamSize: output is not low quality
* 2. big SurfaceSize and smallest() PreviewStreamSize: output is low quality
* In both cases the result.size here was set to the biggest of the two.
*
* @param viewAspectRatio the view aspect ratio * @param viewAspectRatio the view aspect ratio
*/ */
@Override @Override
@ -607,7 +595,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
result.location = mLocation; result.location = mLocation;
result.isSnapshot = true; result.isSnapshot = true;
result.facing = mFacing; result.facing = mFacing;
result.size = getPreviewStreamSize(REF_OUTPUT); // Not the real size: it will be cropped to match the view ratio result.size = getUncroppedSnapshotSize(REF_OUTPUT); // Not the real size: it will be cropped to match the view ratio
result.rotation = offset(REF_SENSOR, REF_OUTPUT); // Actually it will be rotated and set to 0. result.rotation = offset(REF_SENSOR, REF_OUTPUT); // Actually it will be rotated and set to 0.
AspectRatio outputRatio = flip(REF_OUTPUT, REF_VIEW) ? viewAspectRatio.inverse() : viewAspectRatio; AspectRatio outputRatio = flip(REF_OUTPUT, REF_VIEW) ? viewAspectRatio.inverse() : viewAspectRatio;
// LOG.e("ROTBUG_pic", "aspectRatio (REF_VIEW):", viewAspectRatio); // LOG.e("ROTBUG_pic", "aspectRatio (REF_VIEW):", viewAspectRatio);
@ -713,11 +701,6 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
/** /**
* Is output size the SurfaceSize or the PreviewStreamSize ?
* I could not find evidence by testing, but I think that comments in {@link #takePictureSnapshot(AspectRatio)}
* would still apply here, despite the capturing mechanism being different.
* So we should use PreviewStreamSize as output size, cropped by the view aspect ratio.
*
* @param file the output file * @param file the output file
* @param viewAspectRatio the view aspect ratio * @param viewAspectRatio the view aspect ratio
*/ */
@ -783,7 +766,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
// Based on this we will use VO for everything. See if we get issues about distortion // Based on this we will use VO for everything. See if we get issues about distortion
// and maybe we can improve. The reason why this happen is beyond my understanding. // and maybe we can improve. The reason why this happen is beyond my understanding.
Size outputSize = getPreviewStreamSize(REF_OUTPUT); Size outputSize = getUncroppedSnapshotSize(REF_OUTPUT);
AspectRatio outputRatio = flip(REF_OUTPUT, REF_VIEW) ? viewAspectRatio.inverse() : viewAspectRatio; AspectRatio outputRatio = flip(REF_OUTPUT, REF_VIEW) ? viewAspectRatio.inverse() : viewAspectRatio;
Rect outputCrop = CropHelper.computeCrop(outputSize, outputRatio); Rect outputCrop = CropHelper.computeCrop(outputSize, outputRatio);
outputSize = new Size(outputCrop.width(), outputCrop.height()); outputSize = new Size(outputCrop.width(), outputCrop.height());

@ -53,6 +53,9 @@ abstract class CameraController implements
private SizeSelector mPictureSizeSelector; private SizeSelector mPictureSizeSelector;
private SizeSelector mVideoSizeSelector; private SizeSelector mVideoSizeSelector;
private int mSnapshotMaxWidth = Integer.MAX_VALUE; // in REF_VIEW for consistency with SizeSelectors
private int mSnapshotMaxHeight = Integer.MAX_VALUE; // in REF_VIEW for consistency with SizeSelectors
protected int mCameraId; protected int mCameraId;
protected CameraOptions mCameraOptions; protected CameraOptions mCameraOptions;
protected Mapper mMapper; protected Mapper mMapper;
@ -311,6 +314,14 @@ abstract class CameraController implements
mAudioBitRate = audioBitRate; mAudioBitRate = audioBitRate;
} }
final void setSnapshotMaxWidth(int maxWidth) {
mSnapshotMaxWidth = maxWidth;
}
final void setSnapshotMaxHeight(int maxHeight) {
mSnapshotMaxHeight = maxHeight;
}
//endregion //endregion
//region Abstract setters and APIs //region Abstract setters and APIs
@ -518,6 +529,39 @@ abstract class CameraController implements
return flip(REF_VIEW, reference) ? mPreview.getSurfaceSize().flip() : mPreview.getSurfaceSize(); return flip(REF_VIEW, reference) ? mPreview.getSurfaceSize().flip() : mPreview.getSurfaceSize();
} }
/**
* Returns the snapshot size, but not cropped with the view dimensions, which
* is what we will do before creating the snapshot. However, cropping is done at various
* levels so we don't want to perform the op here.
*
* The base snapshot size is based on PreviewStreamSize (later cropped with view ratio). Why?
* One might be tempted to say that it is the SurfaceSize (which already matches the view ratio).
*
* The camera sensor will capture preview frames with PreviewStreamSize and that's it. Then they
* are hardware-scaled by the preview surface, but this does not affect the snapshot, as the
* snapshot recorder simply creates another surface.
*
* Done tests to ensure that this is true, by using
* 1. small SurfaceSize and biggest() PreviewStreamSize: output is not low quality
* 2. big SurfaceSize and smallest() PreviewStreamSize: output is low quality
* In both cases the result.size here was set to the biggest of the two.
*
* I could not find the same evidence for videos, but I would say that the same things should
* apply, despite the capturing mechanism being different.
*/
@Nullable
final Size getUncroppedSnapshotSize(int reference) {
Size baseSize = getPreviewStreamSize(reference);
if (baseSize == null) return null;
boolean flip = flip(reference, REF_VIEW);
int maxWidth = flip ? mSnapshotMaxHeight : mSnapshotMaxWidth;
int maxHeight = flip ? mSnapshotMaxWidth : mSnapshotMaxHeight;
return new Size(
Math.min(baseSize.getWidth(), maxWidth),
Math.max(baseSize.getHeight(), maxHeight)
);
}
//endregion //endregion

@ -1388,6 +1388,27 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}); });
} }
/**
* Sets the max width for snapshots taken with {@link #takePictureSnapshot()} or
* {@link #takeVideoSnapshot(File)}. If the snapshot width exceeds this value, the snapshot
* will be scaled down to match this constraint.
*
* @param maxWidth max width for snapshots
*/
public void setSnapshotMaxWidth(int maxWidth) {
mCameraController.setSnapshotMaxWidth(maxWidth);
}
/**
* Sets the max height for snapshots taken with {@link #takePictureSnapshot()} or
* {@link #takeVideoSnapshot(File)}. If the snapshot height exceeds this value, the snapshot
* will be scaled down to match this constraint.
*
* @param maxHeight max height for snapshots
*/
public void setSnapshotMaxHeight(int maxHeight) {
mCameraController.setSnapshotMaxHeight(maxHeight);
}
/** /**
* Returns the size used for snapshots, or null if it hasn't been computed * Returns the size used for snapshots, or null if it hasn't been computed
@ -1402,7 +1423,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
// Get the preview size and crop according to the current view size. // Get the preview size and crop according to the current view size.
// It's better to do calculations in the REF_VIEW reference, and then flip if needed. // It's better to do calculations in the REF_VIEW reference, and then flip if needed.
Size preview = mCameraController.getPreviewStreamSize(CameraController.REF_VIEW); Size preview = mCameraController.getUncroppedSnapshotSize(CameraController.REF_VIEW);
AspectRatio viewRatio = AspectRatio.of(getWidth(), getHeight()); AspectRatio viewRatio = AspectRatio.of(getWidth(), getHeight());
Rect crop = CropHelper.computeCrop(preview, viewRatio); Rect crop = CropHelper.computeCrop(preview, viewRatio);
Size cropSize = new Size(crop.width(), crop.height()); Size cropSize = new Size(crop.width(), crop.height());

@ -25,6 +25,9 @@
<attr name="cameraVideoBitRate" format="integer|reference" /> <attr name="cameraVideoBitRate" format="integer|reference" />
<attr name="cameraAudioBitRate" format="integer|reference" /> <attr name="cameraAudioBitRate" format="integer|reference" />
<attr name="cameraSnapshotMaxWidth" format="integer|reference" />
<attr name="cameraSnapshotMaxHeight" format="integer|reference" />
<attr name="cameraGestureTap" format="enum"> <attr name="cameraGestureTap" format="enum">
<enum name="none" value="0" /> <enum name="none" value="0" />
<enum name="focus" value="1" /> <enum name="focus" value="1" />

Loading…
Cancel
Save