From cc197299616554a25439bb4ae4d0f0410c92e6f3 Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Fri, 27 Oct 2017 21:30:54 +0200 Subject: [PATCH] Add preview format and Size --- README.md | 2 ++ .../cameraview/CameraCallbacksTest.java | 2 +- .../com/otaliastudios/cameraview/Camera1.java | 8 +++-- .../cameraview/CameraController.java | 1 + .../otaliastudios/cameraview/CameraView.java | 7 ++-- .../com/otaliastudios/cameraview/Frame.java | 32 ++++++++++++++++--- .../com/otaliastudios/cameraview/Size.java | 2 +- .../otaliastudios/cameraview/FrameTest.java | 24 ++++++++++---- 8 files changed, 60 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index c3cab3ec..49b518ff 100644 --- a/README.md +++ b/README.md @@ -468,6 +468,8 @@ apply new data to it. So: |`frame.getData()`|`byte[]`|The current preview frame, in its original orientation.| |`frame.getTime()`|`long`|The preview timestamp, in `System.currentTimeMillis()` reference.| |`frame.getRotation()`|`int`|The rotation that should be applied to the byte array in order to see what the user sees.| +|`frame.getSize()`|`Size`|The frame size, before any rotation is applied, to access data.| +|`frame.getFormat()`|`int`|The frame `ImageFormat`. This will always be `ImageFormat.NV_21` for now.| |`frame.freeze()`|`Frame`|Clones this frame and makes it immutable. Can be expensive because requires copying the byte array.| |`frame.release()`|`-`|Disposes the content of this frame. Should be used on frozen frames to release memory.| diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraCallbacksTest.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraCallbacksTest.java index ff78f837..b6f4e871 100644 --- a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraCallbacksTest.java +++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraCallbacksTest.java @@ -301,7 +301,7 @@ public class CameraCallbacksTest extends BaseTest { @Test public void testProcessFrame() { completeTask().when(processor).process(any(Frame.class)); - camera.mCameraCallbacks.dispatchFrame(new byte[]{0, 1, 2, 3}, 1000, 90); + camera.mCameraCallbacks.dispatchFrame(new byte[]{0, 1, 2, 3}, 1000, 90, new Size(1, 1), 0); assertNotNull(task.await(200)); verify(processor, times(1)).process(any(Frame.class)); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java index adfca95e..a55805e5 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java @@ -143,6 +143,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { ); synchronized (mLock) { Camera.Parameters params = mCamera.getParameters(); + mPreviewFormat = params.getPreviewFormat(); params.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); // <- not allowed during preview params.setPictureSize(mCaptureSize.getWidth(), mCaptureSize.getHeight()); // <- allowed mCamera.setParameters(params); @@ -478,7 +479,6 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { // Got to rotate the preview frame, since byte[] data here does not include // EXIF tags automatically set by camera. So either we add EXIF, or we rotate. // Adding EXIF to a byte array, unfortunately, is hard. - Camera.Parameters params = mCamera.getParameters(); final int sensorToDevice = computeExifRotation(); final int sensorToDisplay = computeSensorToDisplayOffset(); final boolean exifFlip = computeExifFlip(); @@ -487,7 +487,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { final int preHeight = mPreviewSize.getHeight(); final int postWidth = flip ? preHeight : preWidth; final int postHeight = flip ? preWidth : preHeight; - final int format = params.getPreviewFormat(); + final int format = mPreviewFormat; WorkerHandler.run(new Runnable() { @Override public void run() { @@ -509,7 +509,9 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { public void onPreviewFrame(byte[] data, Camera camera) { mCameraCallbacks.dispatchFrame(data, System.currentTimeMillis(), - computeExifRotation()); + computeExifRotation(), + mPreviewSize, + mPreviewFormat); } @Override diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java index be221965..cad2eeba 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java @@ -32,6 +32,7 @@ abstract class CameraController implements CameraPreview.SurfaceCallback { protected Size mCaptureSize; protected Size mPreviewSize; + protected int mPreviewFormat; protected ExtraProperties mExtraProperties; protected CameraOptions mOptions; diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index 92a7ebcb..8172e6d9 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -1352,7 +1352,7 @@ public class CameraView extends FrameLayout { void dispatchOnFocusEnd(@Nullable Gesture trigger, boolean success, PointF where); void dispatchOnZoomChanged(final float newValue, final PointF[] fingers); void dispatchOnExposureCorrectionChanged(float newValue, float[] bounds, PointF[] fingers); - void dispatchFrame(byte[] frame, long time, int rotation); + void dispatchFrame(byte[] frame, long time, int rotation, Size size, int previewFormat); } private class Callbacks implements CameraCallbacks { @@ -1605,14 +1605,15 @@ public class CameraView extends FrameLayout { } @Override - public void dispatchFrame(final byte[] frame, final long time, final int rotation) { + public void dispatchFrame(final byte[] frame, final long time, final int rotation, + final Size size, final int previewFormat) { mLogger.i("dispatchFrame", time, rotation, "processors:", mFrameProcessors.size()); if (mFrameProcessors.isEmpty()) return; if (mFrame == null) mFrame = new Frame(); mFrameProcessorsHandler.post(new Runnable() { @Override public void run() { - mFrame.set(frame, time, rotation); + mFrame.set(frame, time, rotation, size, previewFormat); for (FrameProcessor processor : mFrameProcessors) { processor.process(mFrame); } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Frame.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Frame.java index 930d63f6..53542f26 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/Frame.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Frame.java @@ -8,13 +8,17 @@ public class Frame { private byte[] mData = null; private long mTime = -1; private int mRotation = 0; + private Size mSize = null; + private int mFormat = -1; Frame() {} - void set(byte[] data, long time, int rotation) { + void set(byte[] data, long time, int rotation, Size size, int format) { this.mData = data; this.mTime = time; this.mRotation = rotation; + this.mSize = size; + this.mFormat = format; } @Override @@ -33,10 +37,8 @@ public class Frame { public Frame freeze() { byte[] data = new byte[mData.length]; System.arraycopy(mData, 0, data, 0, mData.length); - long time = mTime; - int rotation = mRotation; Frame other = new Frame(); - other.set(data, time, rotation); + other.set(data, mTime, mRotation, mSize, mFormat); return other; } @@ -48,6 +50,8 @@ public class Frame { mData = null; mRotation = 0; mTime = -1; + mSize = null; + mFormat = -1; } /** @@ -78,4 +82,24 @@ public class Frame { public int getRotation() { return mRotation; } + + /** + * Returns the frame size. + * + * @return frame size + */ + public Size getSize() { + return mSize; + } + + /** + * Returns the data format, in one of the + * {@link android.graphics.ImageFormat} constants. + * + * @return the data format + * @see android.graphics.ImageFormat + */ + public int getFormat() { + return mFormat; + } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Size.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Size.java index b6d33548..a3e2e217 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/Size.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Size.java @@ -7,7 +7,7 @@ public class Size implements Comparable { private final int mWidth; private final int mHeight; - public Size(int width, int height) { + Size(int width, int height) { mWidth = width; mHeight = height; } diff --git a/cameraview/src/test/java/com/otaliastudios/cameraview/FrameTest.java b/cameraview/src/test/java/com/otaliastudios/cameraview/FrameTest.java index 3d784647..ce3755da 100644 --- a/cameraview/src/test/java/com/otaliastudios/cameraview/FrameTest.java +++ b/cameraview/src/test/java/com/otaliastudios/cameraview/FrameTest.java @@ -1,6 +1,8 @@ package com.otaliastudios.cameraview; +import android.graphics.ImageFormat; + import org.junit.Test; import static org.junit.Assert.assertArrayEquals; @@ -16,31 +18,36 @@ public class FrameTest { public void testDefaults() { Frame frame = new Frame(); assertEquals(frame.getTime(), -1); + assertEquals(frame.getFormat(), -1); assertEquals(frame.getRotation(), 0); assertNull(frame.getData()); + assertNull(frame.getSize()); } @Test public void testEquals() { Frame f1 = new Frame(); - f1.set(null, 1000, 90); + long time = 1000; + f1.set(null, time, 90, null, ImageFormat.NV21); Frame f2 = new Frame(); - f2.set(new byte[2], 1000, 0); + f2.set(new byte[2], time, 0, new Size(10, 10), ImageFormat.NV21); assertEquals(f1, f2); - f2.set(new byte[2], 1001, 0); + f2.set(new byte[2], time + 1, 0, new Size(10, 10), ImageFormat.NV21); assertNotEquals(f1, f2); } @Test public void testRelease() { Frame frame = new Frame(); - frame.set(new byte[2], 1000, 90); + frame.set(new byte[2], 1000, 90, new Size(10, 10), ImageFormat.NV21); frame.release(); assertEquals(frame.getTime(), -1); + assertEquals(frame.getFormat(), -1); assertEquals(frame.getRotation(), 0); assertNull(frame.getData()); + assertNull(frame.getSize()); } @Test @@ -49,18 +56,23 @@ public class FrameTest { byte[] data = new byte[]{0, 1, 5, 0, 7, 3, 4, 5}; long time = 1000; int rotation = 90; - frame.set(data, time, rotation); + Size size = new Size(10, 10); + int format = ImageFormat.NV21; + frame.set(data, time, rotation, size, format); Frame frozen = frame.freeze(); assertArrayEquals(data, frozen.getData()); assertEquals(time, frozen.getTime()); assertEquals(rotation, frozen.getRotation()); + assertEquals(size, frozen.getSize()); // Mutate the first, ensure that frozen is not affected - frame.set(new byte[]{3, 2, 1}, 50, 180); + frame.set(new byte[]{3, 2, 1}, 50, 180, new Size(1, 1), ImageFormat.JPEG); assertArrayEquals(data, frozen.getData()); assertEquals(time, frozen.getTime()); assertEquals(rotation, frozen.getRotation()); + assertEquals(size, frozen.getSize()); + assertEquals(format, frozen.getFormat()); } }