Add setFrameProcessingMaxWidth and setFrameProcessingMaxHeight

pull/704/head
Mattia Iavarone 6 years ago
parent f7a95e1ff1
commit 2adf88a1c6
  1. 21
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewTest.java
  2. 21
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/CameraIntegrationTest.java
  3. 6
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/MockCameraEngine.java
  4. 36
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  5. 11
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java
  6. 40
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  7. 76
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraBaseEngine.java
  8. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java

@ -170,6 +170,8 @@ public class CameraViewTest extends BaseTest {
assertEquals(cameraView.getZoom(), 0f, 0f);
assertEquals(cameraView.getVideoMaxDuration(), 0, 0);
assertEquals(cameraView.getVideoMaxSize(), 0, 0);
assertEquals(cameraView.getSnapshotMaxWidth(), 0, 0);
assertEquals(cameraView.getSnapshotMaxHeight(), 0, 0);
// Self managed
GestureParser gestures = new GestureParser(empty);
@ -801,6 +803,22 @@ public class CameraViewTest extends BaseTest {
assertEquals(cameraView.getPreviewFrameRate(), 60, 0);
}
@Test
public void testSnapshotMaxSize() {
cameraView.setSnapshotMaxWidth(500);
assertEquals(cameraView.getSnapshotMaxWidth(), 500);
cameraView.setSnapshotMaxHeight(700);
assertEquals(cameraView.getSnapshotMaxHeight(), 700);
}
@Test
public void testFrameProcessingMaxSize() {
cameraView.setFrameProcessingMaxWidth(500);
assertEquals(cameraView.getFrameProcessingMaxWidth(), 500);
cameraView.setFrameProcessingMaxHeight(700);
assertEquals(cameraView.getFrameProcessingMaxHeight(), 700);
}
//endregion
//region Lists of listeners and processors
@ -975,7 +993,6 @@ public class CameraViewTest extends BaseTest {
}
//endregion
// TODO: test permissions
//region Filter
@ -1002,4 +1019,6 @@ public class CameraViewTest extends BaseTest {
//noinspection ResultOfMethodCallIgnored
verify(mockPreview, times(1)).getCurrentFilter();
}
//endregion
}

@ -1043,6 +1043,27 @@ public abstract class CameraIntegrationTest<E extends CameraBaseEngine> extends
assert15Frames(processor);
}
@Test
@Retry(emulatorOnly = true)
@SdkExclude(maxSdkVersion = 22, emulatorOnly = true)
public void testFrameProcessing_maxSize() {
final int max = 600;
camera.setFrameProcessingMaxWidth(max);
camera.setFrameProcessingMaxHeight(max);
final Op<Size> sizeOp = new Op<>();
camera.addFrameProcessor(new FrameProcessor() {
@Override
public void process(@NonNull Frame frame) {
sizeOp.controller().end(frame.getSize());
}
});
openSync(true);
Size size = sizeOp.await(2000);
assertNotNull(size);
assertTrue(size.getWidth() <= max);
assertTrue(size.getHeight() <= max);
}
@Test
@Retry(emulatorOnly = true)
@SdkExclude(maxSdkVersion = 22, emulatorOnly = true)

@ -171,6 +171,12 @@ public class MockCameraEngine extends CameraBaseEngine {
return new ArrayList<>();
}
@NonNull
@Override
protected List<Size> getFrameProcessingAvailableSizes() {
return new ArrayList<>();
}
@Override
public void startAutoFocus(@Nullable Gesture gesture, @NonNull PointF point) {
mFocusStarted = true;

@ -1730,6 +1730,24 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mCameraEngine.setSnapshotMaxHeight(maxHeight);
}
/**
* The max width for snapshots.
* @see #setSnapshotMaxWidth(int)
* @return max width
*/
public int getSnapshotMaxWidth() {
return mCameraEngine.getSnapshotMaxWidth();
}
/**
* The max height for snapshots.
* @see #setSnapshotMaxHeight(int)
* @return max height
*/
public int getSnapshotMaxHeight() {
return mCameraEngine.getSnapshotMaxHeight();
}
/**
* Returns the size used for snapshots, or null if it hasn't been computed
* (for example if the surface is not ready). This is the preview size, rotated to match
@ -2305,6 +2323,24 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mCameraEngine.setFrameProcessingMaxHeight(maxHeight);
}
/**
* The max width for frame processing frames.
* @see #setFrameProcessingMaxWidth(int)
* @return max width
*/
public int getFrameProcessingMaxWidth() {
return mCameraEngine.getFrameProcessingMaxWidth();
}
/**
* The max height for frame processing frames.
* @see #setFrameProcessingMaxHeight(int)
* @return max height
*/
public int getFrameProcessingMaxHeight() {
return mCameraEngine.getFrameProcessingMaxHeight();
}
//endregion
//region Overlays

@ -47,6 +47,8 @@ import com.otaliastudios.cameraview.video.SnapshotVideoRecorder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -104,6 +106,15 @@ public class Camera1Engine extends CameraBaseEngine implements
return result;
}
@EngineThread
@NonNull
@Override
protected List<Size> getFrameProcessingAvailableSizes() {
// We don't choose the frame processing size.
// It comes from the preview stream.
return Collections.singletonList(mPreviewStreamSize);
}
@EngineThread
@Override
protected void onPreviewStreamSizeChanged() {

@ -95,7 +95,6 @@ public class Camera2Engine extends CameraBaseEngine implements
private final Camera2Mapper mMapper = Camera2Mapper.get();
// Frame processing
private Size mFrameProcessingSize;
private ImageReader mFrameProcessingReader; // need this or the reader surface is collected
private final WorkerHandler mFrameConversionHandler;
private final Object mFrameProcessingImageLock = new Object();
@ -326,6 +325,29 @@ public class Camera2Engine extends CameraBaseEngine implements
}
}
@EngineThread
@NonNull
@Override
protected List<Size> getFrameProcessingAvailableSizes() {
try {
CameraCharacteristics characteristics = mManager.getCameraCharacteristics(mCameraId);
StreamConfigurationMap streamMap =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (streamMap == null) {
throw new RuntimeException("StreamConfigurationMap is null. Should not happen.");
}
android.util.Size[] sizes = streamMap.getOutputSizes(FRAME_PROCESSING_INPUT_FORMAT);
List<Size> candidates = new ArrayList<>(sizes.length);
for (android.util.Size size : sizes) {
Size add = new Size(size.getWidth(), size.getHeight());
if (!candidates.contains(add)) candidates.add(add);
}
return candidates;
} catch (CameraAccessException e) {
throw createCameraException(e);
}
}
@EngineThread
@Override
protected void onPreviewStreamSizeChanged() {
@ -520,21 +542,7 @@ public class Camera2Engine extends CameraBaseEngine implements
// 4. FRAME PROCESSING
if (hasFrameProcessors()) {
// Choose the size.
StreamConfigurationMap streamMap = mCameraCharacteristics
.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (streamMap == null) {
throw new RuntimeException("StreamConfigurationMap is null. Should not happen.");
}
android.util.Size[] aSizes = streamMap.getOutputSizes(FRAME_PROCESSING_INPUT_FORMAT);
List<Size> sizes = new ArrayList<>();
for (android.util.Size aSize : aSizes) {
sizes.add(new Size(aSize.getWidth(), aSize.getHeight()));
}
mFrameProcessingSize = SizeSelectors.and(
SizeSelectors.maxWidth(Math.min(640, mPreviewStreamSize.getWidth())),
SizeSelectors.maxHeight(Math.min(640, mPreviewStreamSize.getHeight())),
SizeSelectors.biggest()).select(sizes).get(0);
mFrameProcessingSize = computeFrameProcessingSize();
mFrameProcessingReader = ImageReader.newInstance(
mFrameProcessingSize.getWidth(),
mFrameProcessingSize.getHeight(),

@ -51,6 +51,7 @@ public abstract class CameraBaseEngine extends CameraEngine {
@SuppressWarnings("WeakerAccess") protected VideoRecorder mVideoRecorder;
@SuppressWarnings("WeakerAccess") protected Size mCaptureSize;
@SuppressWarnings("WeakerAccess") protected Size mPreviewStreamSize;
@SuppressWarnings("WeakerAccess") protected Size mFrameProcessingSize;
@SuppressWarnings("WeakerAccess") protected Flash mFlash;
@SuppressWarnings("WeakerAccess") protected WhiteBalance mWhiteBalance;
@SuppressWarnings("WeakerAccess") protected VideoCodec mVideoCodec;
@ -80,6 +81,8 @@ public abstract class CameraBaseEngine extends CameraEngine {
private long mAutoFocusResetDelayMillis;
private int mSnapshotMaxWidth; // in REF_VIEW like SizeSelectors
private int mSnapshotMaxHeight; // in REF_VIEW like SizeSelectors
private int mFrameProcessingMaxWidth; // in REF_VIEW like SizeSelectors
private int mFrameProcessingMaxHeight; // in REF_VIEW like SizeSelectors
private Overlay mOverlay;
// Ops used for testing.
@ -261,6 +264,26 @@ public abstract class CameraBaseEngine extends CameraEngine {
return mSnapshotMaxHeight;
}
@Override
public final void setFrameProcessingMaxWidth(int maxWidth) {
mFrameProcessingMaxWidth = maxWidth;
}
@Override
public final int getFrameProcessingMaxWidth() {
return mFrameProcessingMaxWidth;
}
@Override
public final void setFrameProcessingMaxHeight(int maxHeight) {
mFrameProcessingMaxHeight = maxHeight;
}
@Override
public final int getFrameProcessingMaxHeight() {
return mFrameProcessingMaxHeight;
}
@Override
public final void setAutoFocusResetDelay(long delayMillis) {
mAutoFocusResetDelayMillis = delayMillis;
@ -846,5 +869,58 @@ public abstract class CameraBaseEngine extends CameraEngine {
return result;
}
/**
* This is called anytime {@link #computeFrameProcessingSize()} is called.
* Implementors can return null if frame processor size is not selectable
* @return a list of available sizes for frame processing
*/
@EngineThread
@NonNull
protected abstract List<Size> getFrameProcessingAvailableSizes();
@EngineThread
@NonNull
@SuppressWarnings("WeakerAccess")
protected final Size computeFrameProcessingSize() {
@NonNull List<Size> frameSizes = getFrameProcessingAvailableSizes();
// These sizes come in REF_SENSOR. Since there is an external selector involved,
// we must convert all of them to REF_VIEW, then flip back when returning.
boolean flip = getAngles().flip(Reference.SENSOR, Reference.VIEW);
List<Size> sizes = new ArrayList<>(frameSizes.size());
for (Size size : frameSizes) {
sizes.add(flip ? size.flip() : size);
}
AspectRatio targetRatio = AspectRatio.of(
mPreviewStreamSize.getWidth(),
mPreviewStreamSize.getHeight());
if (flip) targetRatio = targetRatio.flip();
int maxWidth = mFrameProcessingMaxWidth;
int maxHeight = mFrameProcessingMaxHeight;
if (maxWidth <= 0 || maxWidth == Integer.MAX_VALUE) maxWidth = 640;
if (maxHeight <= 0 || maxHeight == Integer.MAX_VALUE) maxHeight = 640;
Size targetMaxSize = new Size(maxWidth, maxHeight);
LOG.i("computeFrameProcessingSize:",
"targetRatio:", targetRatio,
"targetMaxSize:", targetMaxSize);
SizeSelector matchRatio = SizeSelectors.aspectRatio(targetRatio, 0);
SizeSelector matchSize = SizeSelectors.and(
SizeSelectors.maxHeight(targetMaxSize.getHeight()),
SizeSelectors.maxWidth(targetMaxSize.getWidth()),
SizeSelectors.biggest());
SizeSelector matchAll = SizeSelectors.or(
SizeSelectors.and(matchRatio, matchSize), // Try to respect both constraints.
matchSize, // If couldn't match aspect ratio, at least respect the size
SizeSelectors.smallest() // If couldn't match any, take the smallest.
);
Size result = matchAll.select(sizes).get(0);
if (!sizes.contains(result)) {
throw new RuntimeException("SizeSelectors must not return Sizes other than " +
"those in the input list.");
}
if (flip) result = result.flip();
LOG.i("computeFrameProcessingSize:", "result:", result, "flip:", flip);
return result;
}
//endregion
}

@ -641,6 +641,12 @@ public abstract class CameraEngine implements
public abstract void setSnapshotMaxHeight(int maxHeight);
public abstract int getSnapshotMaxHeight();
public abstract void setFrameProcessingMaxWidth(int maxWidth);
public abstract int getFrameProcessingMaxWidth();
public abstract void setFrameProcessingMaxHeight(int maxHeight);
public abstract int getFrameProcessingMaxHeight();
public abstract void setAutoFocusResetDelay(long delayMillis);
public abstract long getAutoFocusResetDelay();

Loading…
Cancel
Save