Add setVideoSize, video size selectors and available video sizes in CameraOptions

v2
Mattia Iavarone 7 years ago
parent e1271d43c7
commit 658137b9bf
  1. 11
      MIGRATION.md
  2. 69
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraOptions1Test.java
  3. 10
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewTest.java
  4. 14
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
  5. 71
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java
  6. 65
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java
  7. 96
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  8. 40
      cameraview/src/main/res/values/attrs.xml
  9. 8
      demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java

@ -22,4 +22,13 @@
- CameraOptions.isVideoSnapshotSupported(): removed, this would be ambiguous now. While in video
mode, you can only use takePictureSnapshot(), not takePicture().
- takePicture(): will now throw an exception if called when Mode == Mode.VIDEO. You can only take snapshots.
- VideoQuality: this has been removed.
- VideoQuality: this has been removed.
- CameraOptions: methods returning a Set now return a Collection.
- CameraOptions: in addition to getSupportedPictureSizes and getSupportedPictureAspectRatio,
now there are video mode equivalents too.
- getPictureSize(): now it returns null when mode == Mode.VIDEO.
- getVideoSize(): added. Returns the size of the capture in video mode. Returns null when
mode == Mode.PICTURE.
- VideoSizeSelector: added. It is needed to choose the capture size in VIDEO mode.
Defaults to SizeSelectors.biggest(), but you can choose by aspect ratio or whatever.

@ -58,7 +58,7 @@ public class CameraOptions1Test extends BaseTest {
Camera.Parameters params = mock(Camera.Parameters.class);
when(params.getSupportedPictureSizes()).thenReturn(sizes);
CameraOptions o = new CameraOptions(params, false);
Set<Size> supportedSizes = o.getSupportedPictureSizes();
Collection<Size> supportedSizes = o.getSupportedPictureSizes();
assertEquals(supportedSizes.size(), sizes.size());
for (Camera.Size size : sizes) {
Size internalSize = new Size(size.width, size.height);
@ -77,7 +77,7 @@ public class CameraOptions1Test extends BaseTest {
Camera.Parameters params = mock(Camera.Parameters.class);
when(params.getSupportedPictureSizes()).thenReturn(sizes);
CameraOptions o = new CameraOptions(params, true);
Set<Size> supportedSizes = o.getSupportedPictureSizes();
Collection<Size> supportedSizes = o.getSupportedPictureSizes();
assertEquals(supportedSizes.size(), sizes.size());
for (Camera.Size size : sizes) {
Size internalSize = new Size(size.width, size.height).flip();
@ -102,7 +102,70 @@ public class CameraOptions1Test extends BaseTest {
Camera.Parameters params = mock(Camera.Parameters.class);
when(params.getSupportedPictureSizes()).thenReturn(sizes);
CameraOptions o = new CameraOptions(params, false);
Set<AspectRatio> supportedRatios = o.getSupportedPictureAspectRatios();
Collection<AspectRatio> supportedRatios = o.getSupportedPictureAspectRatios();
assertEquals(supportedRatios.size(), expected.size());
for (AspectRatio ratio : expected) {
assertTrue(supportedRatios.contains(ratio));
}
}
@Test
public void testVideoSizes() {
List<Camera.Size> sizes = Arrays.asList(
mockCameraSize(100, 200),
mockCameraSize(50, 50),
mockCameraSize(1600, 900),
mockCameraSize(1000, 2000)
);
Camera.Parameters params = mock(Camera.Parameters.class);
when(params.getSupportedVideoSizes()).thenReturn(sizes);
CameraOptions o = new CameraOptions(params, false);
Collection<Size> supportedSizes = o.getSupportedVideoSizes();
assertEquals(supportedSizes.size(), sizes.size());
for (Camera.Size size : sizes) {
Size internalSize = new Size(size.width, size.height);
assertTrue(supportedSizes.contains(internalSize));
}
}
@Test
public void testVideoSizesFlip() {
List<Camera.Size> sizes = Arrays.asList(
mockCameraSize(100, 200),
mockCameraSize(50, 50),
mockCameraSize(1600, 900),
mockCameraSize(1000, 2000)
);
Camera.Parameters params = mock(Camera.Parameters.class);
when(params.getSupportedVideoSizes()).thenReturn(sizes);
CameraOptions o = new CameraOptions(params, true);
Collection<Size> supportedSizes = o.getSupportedVideoSizes();
assertEquals(supportedSizes.size(), sizes.size());
for (Camera.Size size : sizes) {
Size internalSize = new Size(size.width, size.height).flip();
assertTrue(supportedSizes.contains(internalSize));
}
}
@Test
public void testVideoAspectRatio() {
List<Camera.Size> sizes = Arrays.asList(
mockCameraSize(100, 200),
mockCameraSize(50, 50),
mockCameraSize(1600, 900),
mockCameraSize(1000, 2000)
);
Set<AspectRatio> expected = new HashSet<>();
expected.add(AspectRatio.of(1, 2));
expected.add(AspectRatio.of(1, 1));
expected.add(AspectRatio.of(16, 9));
Camera.Parameters params = mock(Camera.Parameters.class);
when(params.getSupportedVideoSizes()).thenReturn(sizes);
CameraOptions o = new CameraOptions(params, false);
Collection<AspectRatio> supportedRatios = o.getSupportedVideoAspectRatios();
assertEquals(supportedRatios.size(), expected.size());
for (AspectRatio ratio : expected) {
assertTrue(supportedRatios.contains(ratio));

@ -76,6 +76,7 @@ public class CameraViewTest extends BaseTest {
assertNull(cameraView.getCameraOptions());
assertNull(cameraView.getSnapshotSize());
assertNull(cameraView.getPictureSize());
assertNull(cameraView.getVideoSize());
}
@Test
@ -542,6 +543,15 @@ public class CameraViewTest extends BaseTest {
assertEquals(result, source);
}
@Test
public void testVideoSizeSelector() {
SizeSelector source = SizeSelectors.minHeight(50);
cameraView.setVideoSize(source);
SizeSelector result = mockController.getVideoSizeSelector();
assertNotNull(result);
assertEquals(result, source);
}
@Test
public void testVideoMaxSize() {
cameraView.setVideoMaxSize(5000);

@ -127,7 +127,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
throw new CameraException(e, CameraException.REASON_FAILED_TO_START_PREVIEW);
}
mPictureSize = computePictureSize();
mCaptureSize = computeCaptureSize();
mPreviewSize = computePreviewSize(sizesFromList(mCamera.getParameters().getSupportedPreviewSizes()));
applySizesAndStartPreview("bindToSurface:");
mIsBound = true;
@ -144,7 +144,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
Camera.Parameters params = mCamera.getParameters();
mPreviewFormat = params.getPreviewFormat();
params.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); // <- not allowed during preview
params.setPictureSize(mPictureSize.getWidth(), mPictureSize.getHeight()); // <- allowed
params.setPictureSize(mCaptureSize.getWidth(), mCaptureSize.getHeight()); // <- allowed
mCamera.setParameters(params);
mCamera.setPreviewCallbackWithBuffer(null); // Release anything left
@ -228,7 +228,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
mCameraOptions = null;
mCamera = null;
mPreviewSize = null;
mPictureSize = null;
mCaptureSize = null;
mIsBound = false;
mIsCapturingImage = false;
mIsTakingVideo = false;
@ -632,8 +632,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
mIsTakingVideo = true;
// Create the video result
CamcorderProfile profile = getCamcorderProfile();
Size videoSize = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
final Size videoSize = mCaptureSize;
mVideoResult = new VideoResult();
mVideoResult.file = videoFile;
mVideoResult.isSnapshot = false;
@ -651,9 +650,12 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
// Must be called before setOutputFormat.
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
}
// TODO: should get a profile of a quality compatible with the chosen size.
final CamcorderProfile profile = CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_HIGH);
mMediaRecorder.setOutputFormat(profile.fileFormat);
mMediaRecorder.setVideoFrameRate(profile.videoFrameRate);
mMediaRecorder.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
mMediaRecorder.setVideoSize(videoSize.getWidth(), videoSize.getHeight());
mMediaRecorder.setVideoEncoder(mMapper.map(mVideoCodec));
mMediaRecorder.setVideoEncodingBitRate(profile.videoBitRate);
if (mAudio == Audio.ON) {

@ -6,7 +6,6 @@ import android.location.Location;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
@ -15,6 +14,7 @@ import android.support.annotation.WorkerThread;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
abstract class CameraController implements
@ -56,11 +56,12 @@ abstract class CameraController implements
protected Mapper mMapper;
protected FrameManager mFrameManager;
protected SizeSelector mPictureSizeSelector;
protected SizeSelector mVideoSizeSelector;
protected MediaRecorder mMediaRecorder;
protected VideoResult mVideoResult;
protected long mVideoMaxSize;
protected int mVideoMaxDuration;
protected Size mPictureSize;
protected Size mCaptureSize;
protected Size mPreviewSize;
protected int mPreviewFormat;
@ -280,6 +281,10 @@ abstract class CameraController implements
mPictureSizeSelector = selector;
}
final void setVideoSizeSelector(SizeSelector selector) {
mVideoSizeSelector = selector;
}
final void setVideoMaxSize(long videoMaxSizeBytes) {
mVideoMaxSize = videoMaxSizeBytes;
}
@ -385,10 +390,14 @@ abstract class CameraController implements
return mAudio;
}
final SizeSelector getPictureSizeSelector() {
/* for tests */ final SizeSelector getPictureSizeSelector() {
return mPictureSizeSelector;
}
/* for tests */ final SizeSelector getVideoSizeSelector() {
return mVideoSizeSelector;
}
final float getZoomValue() {
return mZoomValue;
}
@ -444,8 +453,13 @@ abstract class CameraController implements
}
final Size getPictureSize(int reference) {
if (mPictureSize == null) return null;
return flip(REF_SENSOR, reference) ? mPictureSize.flip() : mPictureSize;
if (mCaptureSize == null || mMode == Mode.VIDEO) return null;
return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize;
}
final Size getVideoSize(int reference) {
if (mCaptureSize == null || mMode == Mode.PICTURE) return null;
return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize;
}
final Size getPreviewSize(int reference) {
@ -465,43 +479,33 @@ abstract class CameraController implements
* But when it does, the {@link CameraPreview.SurfaceCallback} should be called,
* and this should be refreshed.
*/
protected final Size computePictureSize() {
// The external selector is expecting stuff in the view world, not in the sensor world.
// Use the list in the camera options, then flip the result if needed.
protected final Size computeCaptureSize() {
// We want to pass stuff into the REF_VIEW reference, not the sensor one.
// This is already managed by CameraOptions, so we just flip again at the end.
boolean flip = flip(REF_SENSOR, REF_VIEW);
SizeSelector selector;
Collection<Size> sizes;
if (mMode == Mode.PICTURE) {
selector = SizeSelectors.or(mPictureSizeSelector, SizeSelectors.biggest());
selector = mPictureSizeSelector;
sizes = mCameraOptions.getSupportedPictureSizes();
} else {
// The Camcorder internally checks for cameraParameters.getSupportedVideoSizes() etc.
// And we want the picture size to be the biggest picture consistent with the video aspect ratio.
// -> Use the external picture selector, but enforce the ratio constraint.
CamcorderProfile profile = getCamcorderProfile();
AspectRatio targetRatio = AspectRatio.of(profile.videoFrameWidth, profile.videoFrameHeight);
if (flip) targetRatio = targetRatio.inverse();
LOG.i("size:", "computeCaptureSize:", "targetRatio:", targetRatio);
SizeSelector matchRatio = SizeSelectors.aspectRatio(targetRatio, 0);
selector = SizeSelectors.or(
SizeSelectors.and(matchRatio, mPictureSizeSelector),
SizeSelectors.and(matchRatio),
mPictureSizeSelector
);
selector = mVideoSizeSelector;
sizes = mCameraOptions.getSupportedVideoSizes();
}
List<Size> list = new ArrayList<>(mCameraOptions.getSupportedPictureSizes());
selector = SizeSelectors.or(selector, SizeSelectors.biggest());
List<Size> list = new ArrayList<>(sizes);
Size result = selector.select(list).get(0);
LOG.i("computePictureSize:", "result:", result, "flip:", flip);
if (flip) result = result.flip();
LOG.i("computeCaptureSize:", "result:", result, "flip:", flip);
if (flip) result = result.flip(); // Go back to REF_SENSOR
return result;
}
protected final Size computePreviewSize(List<Size> previewSizes) {
// instead of flipping everything to the view world, we can just flip the
// surface size to the sensor world
AspectRatio targetRatio = AspectRatio.of(mPictureSize.getWidth(), mPictureSize.getHeight());
// instead of flipping everything to REF_VIEW, we can just flip the
// surface size from REF_VIEW to REF_SENSOR, and reflip at the end.
AspectRatio targetRatio = AspectRatio.of(mCaptureSize.getWidth(), mCaptureSize.getHeight());
Size targetMinSize = mPreview.getSurfaceSize();
boolean flip = flip(REF_SENSOR, REF_VIEW);
boolean flip = flip(REF_VIEW, REF_SENSOR);
if (flip) targetMinSize = targetMinSize.flip();
LOG.i("size:", "computePreviewSize:", "targetRatio:", targetRatio, "targetMinSize:", targetMinSize);
SizeSelector matchRatio = SizeSelectors.and( // Match this aspect ratio and sort by biggest
@ -522,10 +526,5 @@ abstract class CameraController implements
return result;
}
@NonNull
protected final CamcorderProfile getCamcorderProfile() {
return CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_HIGH);
}
//endregion
}

@ -23,10 +23,11 @@ public class CameraOptions {
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 videoSnapshotSupported;
private boolean exposureCorrectionSupported;
private float exposureCorrectionMinValue;
private float exposureCorrectionMaxValue;
@ -75,7 +76,6 @@ public class CameraOptions {
}
zoomSupported = params.isZoomSupported();
videoSnapshotSupported = params.isVideoSnapshotSupported();
autoFocusSupported = params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO);
// Exposure correction
@ -93,6 +93,15 @@ public class CameraOptions {
supportedPictureSizes.add(new Size(width, height));
supportedPictureAspectRatio.add(AspectRatio.of(width, height));
}
List<Camera.Size> vsizes = params.getSupportedVideoSizes();
if (vsizes != null) {
for (Camera.Size size : vsizes) {
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));
}
}
}
@ -163,11 +172,10 @@ public class CameraOptions {
/**
* Set of supported picture sizes for the currently opened camera.
*
* @return a set of supported values.
* @return a collection of supported values.
*/
@NonNull
public Set<Size> getSupportedPictureSizes() {
// TODO v2: return a Collection
public Collection<Size> getSupportedPictureSizes() {
return Collections.unmodifiableSet(supportedPictureSizes);
}
@ -175,25 +183,45 @@ public class CameraOptions {
/**
* Set of supported picture aspect ratios for the currently opened camera.
*
* @return a set of supported values.
* @return a collection of supported values.
*/
@NonNull
public Set<AspectRatio> getSupportedPictureAspectRatios() {
// TODO v2: return a Collection
public Collection<AspectRatio> getSupportedPictureAspectRatios() {
return Collections.unmodifiableSet(supportedPictureAspectRatio);
}
/**
* Set of supported video sizes for the currently opened camera.
*
* @return a collection of supported values.
*/
@NonNull
public Collection<Size> getSupportedVideoSizes() {
return Collections.unmodifiableSet(supportedVideoSizes);
}
/**
* Set of supported picture aspect ratios for the currently opened camera.
*
* @return a set of supported values.
*/
@NonNull
public Collection<AspectRatio> getSupportedVideoAspectRatios() {
return Collections.unmodifiableSet(supportedVideoAspectRatio);
}
/**
* Set of supported facing values.
*
* @see Facing#BACK
* @see Facing#FRONT
* @return a set of supported values.
* @return a collection of supported values.
*/
@NonNull
public Set<Facing> getSupportedFacing() {
// TODO v2: return a Collection
public Collection<Facing> getSupportedFacing() {
return Collections.unmodifiableSet(supportedFacing);
}
@ -205,11 +233,10 @@ public class CameraOptions {
* @see Flash#OFF
* @see Flash#ON
* @see Flash#TORCH
* @return a set of supported values.
* @return a collection of supported values.
*/
@NonNull
public Set<Flash> getSupportedFlash() {
// TODO v2: return a Collection
public Collection<Flash> getSupportedFlash() {
return Collections.unmodifiableSet(supportedFlash);
}
@ -222,11 +249,10 @@ public class CameraOptions {
* @see WhiteBalance#FLUORESCENT
* @see WhiteBalance#DAYLIGHT
* @see WhiteBalance#CLOUDY
* @return a set of supported values.
* @return a collection of supported values.
*/
@NonNull
public Set<WhiteBalance> getSupportedWhiteBalance() {
// TODO v2: return a Collection
public Collection<WhiteBalance> getSupportedWhiteBalance() {
return Collections.unmodifiableSet(supportedWhiteBalance);
}
@ -236,11 +262,10 @@ public class CameraOptions {
*
* @see Hdr#OFF
* @see Hdr#ON
* @return a set of supported values.
* @return a collection of supported values.
*/
@NonNull
public Set<Hdr> getSupportedHdr() {
// TODO v2: return a Collection
public Collection<Hdr> getSupportedHdr() {
return Collections.unmodifiableSet(supportedHdr);
}

@ -107,34 +107,65 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
long videoMaxSize = (long) a.getFloat(R.styleable.CameraView_cameraVideoMaxSize, 0);
int videoMaxDuration = a.getInteger(R.styleable.CameraView_cameraVideoMaxDuration, 0);
// Size selectors
List<SizeSelector> constraints = new ArrayList<>(3);
// Picture size selector
List<SizeSelector> pictureConstraints = new ArrayList<>(3);
if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMinWidth)) {
constraints.add(SizeSelectors.minWidth(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinWidth, 0)));
pictureConstraints.add(SizeSelectors.minWidth(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinWidth, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMaxWidth)) {
constraints.add(SizeSelectors.maxWidth(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxWidth, 0)));
pictureConstraints.add(SizeSelectors.maxWidth(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxWidth, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMinHeight)) {
constraints.add(SizeSelectors.minHeight(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinHeight, 0)));
pictureConstraints.add(SizeSelectors.minHeight(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinHeight, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMaxHeight)) {
constraints.add(SizeSelectors.maxHeight(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxHeight, 0)));
pictureConstraints.add(SizeSelectors.maxHeight(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxHeight, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMinArea)) {
constraints.add(SizeSelectors.minArea(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinArea, 0)));
pictureConstraints.add(SizeSelectors.minArea(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinArea, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMaxArea)) {
constraints.add(SizeSelectors.maxArea(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxArea, 0)));
pictureConstraints.add(SizeSelectors.maxArea(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxArea, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraPictureSizeAspectRatio)) {
//noinspection ConstantConditions
constraints.add(SizeSelectors.aspectRatio(AspectRatio.parse(a.getString(R.styleable.CameraView_cameraPictureSizeAspectRatio)), 0));
pictureConstraints.add(SizeSelectors.aspectRatio(AspectRatio.parse(a.getString(R.styleable.CameraView_cameraPictureSizeAspectRatio)), 0));
}
if (a.getBoolean(R.styleable.CameraView_cameraPictureSizeSmallest, false)) constraints.add(SizeSelectors.smallest());
if (a.getBoolean(R.styleable.CameraView_cameraPictureSizeBiggest, false)) constraints.add(SizeSelectors.biggest());
SizeSelector selector = !constraints.isEmpty() ?
SizeSelectors.and(constraints.toArray(new SizeSelector[0])) :
if (a.getBoolean(R.styleable.CameraView_cameraPictureSizeSmallest, false)) pictureConstraints.add(SizeSelectors.smallest());
if (a.getBoolean(R.styleable.CameraView_cameraPictureSizeBiggest, false)) pictureConstraints.add(SizeSelectors.biggest());
SizeSelector pictureSelector = !pictureConstraints.isEmpty() ?
SizeSelectors.and(pictureConstraints.toArray(new SizeSelector[0])) :
SizeSelectors.biggest();
// Video size selector
List<SizeSelector> videoConstraints = new ArrayList<>(3);
if (a.hasValue(R.styleable.CameraView_cameraVideoSizeMinWidth)) {
videoConstraints.add(SizeSelectors.minWidth(a.getInteger(R.styleable.CameraView_cameraVideoSizeMinWidth, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraVideoSizeMaxWidth)) {
videoConstraints.add(SizeSelectors.maxWidth(a.getInteger(R.styleable.CameraView_cameraVideoSizeMaxWidth, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraVideoSizeMinHeight)) {
videoConstraints.add(SizeSelectors.minHeight(a.getInteger(R.styleable.CameraView_cameraVideoSizeMinHeight, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraVideoSizeMaxHeight)) {
videoConstraints.add(SizeSelectors.maxHeight(a.getInteger(R.styleable.CameraView_cameraVideoSizeMaxHeight, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraVideoSizeMinArea)) {
videoConstraints.add(SizeSelectors.minArea(a.getInteger(R.styleable.CameraView_cameraVideoSizeMinArea, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraVideoSizeMaxArea)) {
videoConstraints.add(SizeSelectors.maxArea(a.getInteger(R.styleable.CameraView_cameraVideoSizeMaxArea, 0)));
}
if (a.hasValue(R.styleable.CameraView_cameraVideoSizeAspectRatio)) {
//noinspection ConstantConditions
videoConstraints.add(SizeSelectors.aspectRatio(AspectRatio.parse(a.getString(R.styleable.CameraView_cameraVideoSizeAspectRatio)), 0));
}
if (a.getBoolean(R.styleable.CameraView_cameraVideoSizeSmallest, false)) videoConstraints.add(SizeSelectors.smallest());
if (a.getBoolean(R.styleable.CameraView_cameraVideoSizeBiggest, false)) videoConstraints.add(SizeSelectors.biggest());
SizeSelector videoSelector = !videoConstraints.isEmpty() ?
SizeSelectors.and(videoConstraints.toArray(new SizeSelector[0])) :
SizeSelectors.biggest();
// Gestures
@ -173,7 +204,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
setGrid(grid);
setHdr(hdr);
setAudio(audio);
setPictureSize(selector);
setPictureSize(pictureSelector);
setVideoSize(videoSelector);
setVideoCodec(codec);
setVideoMaxSize(videoMaxSize);
setVideoMaxDuration(videoMaxDuration);
@ -1003,8 +1035,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
/**
* Sets picture capture size for picture mode.
* The {@link SizeSelector} will be invoked with the list of available size, and the first
* Sets a capture size selector for picture mode.
* The {@link SizeSelector} will be invoked with the list of available sizes, and the first
* acceptable size will be accepted and passed to the internal engine.
* See the {@link SizeSelectors} class for handy utilities for creating selectors.
*
@ -1015,6 +1047,19 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
/**
* Sets a capture size selector for video mode.
* The {@link SizeSelector} will be invoked with the list of available sizes, and the first
* acceptable size will be accepted and passed to the internal engine.
* See the {@link SizeSelectors} class for handy utilities for creating selectors.
*
* @param selector a size selector
*/
public void setVideoSize(@NonNull SizeSelector selector) {
mCameraController.setVideoSizeSelector(selector);
}
/**
* Adds a {@link CameraListener} instance to be notified of all
* interesting events that happen during the camera lifecycle.
@ -1204,7 +1249,9 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
/**
* Returns the size used for pictures taken with {@link #takePicture()},
* or null if it hasn't been computed (for example if the surface is not ready).
* or null if it hasn't been computed (for example if the surface is not ready),
* or null if we are in video mode.
*
* The size is rotated to match the output orientation.
*
* @return the size of pictures
@ -1215,6 +1262,21 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
/**
* Returns the size used for videos taken with {@link #takeVideo(File)},
* or null if it hasn't been computed (for example if the surface is not ready),
* or null if we are in picture mode.
*
* The size is rotated to match the output orientation.
*
* @return the size of videos
*/
@Nullable
public Size getVideoSize() {
return mCameraController.getVideoSize(CameraController.REF_OUTPUT);
}
// If we end up here, we're in M.
@TargetApi(Build.VERSION_CODES.M)
private void requestPermissions(boolean requestCamera, boolean requestAudio) {

@ -3,23 +3,25 @@
<declare-styleable name="CameraView">
<attr name="cameraPictureSizeMinWidth" format="integer|reference"/>
<attr name="cameraPictureSizeMaxWidth" format="integer|reference"/>
<attr name="cameraPictureSizeMinHeight" format="integer|reference"/>
<attr name="cameraPictureSizeMaxHeight" format="integer|reference"/>
<attr name="cameraPictureSizeMinArea" format="integer|reference" />
<attr name="cameraPictureSizeMaxArea" format="integer|reference" />
<attr name="cameraPictureSizeSmallest" format="boolean"/>
<attr name="cameraPictureSizeBiggest" format="boolean"/>
<attr name="cameraPictureSizeAspectRatio" format="string|reference"/>
<attr name="cameraVideoSizeMinWidth" format="integer|reference"/>
<attr name="cameraVideoSizeMaxWidth" format="integer|reference"/>
<attr name="cameraVideoSizeMinHeight" format="integer|reference"/>
<attr name="cameraVideoSizeMaxHeight" format="integer|reference"/>
<attr name="cameraVideoSizeMinArea" format="integer|reference" />
<attr name="cameraVideoSizeMaxArea" format="integer|reference" />
<attr name="cameraVideoSizeSmallest" format="boolean"/>
<attr name="cameraVideoSizeBiggest" format="boolean"/>
<attr name="cameraVideoSizeAspectRatio" format="string|reference"/>
<attr name="cameraGestureTap" format="enum">
<enum name="none" value="0" />
<enum name="focus" value="1" />
@ -116,27 +118,5 @@
<enum name="h264" value="2" />
</attr>
<!-- deprecated attr name="cameraZoomMode" format="enum">
<enum name="off" value="0" />
<enum name="pinch" value="1" />
</attr -->
<!-- deprecated attr name="cameraCaptureMethod" format="enum">
<enum name="standard" value="0" />
<enum name="frame" value="1" />
</attr -->
<!-- deprecated attr name="cameraPermissionPolicy" format="enum">
<enum name="video" value="0" />
<enum name="picture" value="1" />
</attr -->
<!-- deprecated attr name="cameraFocus" format="enum">
<enum name="fixed" value="0" />
<enum name="continuous" value="1" />
<enum name="tap" value="2" />
<enum name="tapWithMarker" value="3" />
</attr -->
</declare-styleable>
</resources>

@ -147,6 +147,10 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
}
private void capturePicture() {
if (camera.getMode() == Mode.VIDEO) {
message("Can't take HQ pictures while in VIDEO mode.", false);
return;
}
if (mCapturingPicture) return;
mCapturingPicture = true;
mCaptureTime = System.currentTimeMillis();
@ -163,8 +167,8 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
}
private void captureVideo() {
if (camera.getMode() != Mode.VIDEO) {
message("Can't record video while session type is 'picture'.", false);
if (camera.getMode() == Mode.PICTURE) {
message("Can't record HQ videos while in PICTURE mode.", false);
return;
}
if (mCapturingPicture || mCapturingVideo) return;

Loading…
Cancel
Save