diff --git a/library/src/main/api14/com/google/android/cameraview/Camera1.java b/library/src/main/api14/com/google/android/cameraview/Camera1.java index 74ca3832..9a935311 100644 --- a/library/src/main/api14/com/google/android/cameraview/Camera1.java +++ b/library/src/main/api14/com/google/android/cameraview/Camera1.java @@ -121,6 +121,17 @@ void setUpPreview() { } else { mCamera.setPreviewTexture((SurfaceTexture) mPreview.getSurfaceTexture()); } + + mCamera.setPreviewCallback(new Camera.PreviewCallback() { + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + final Camera.Parameters parameters = camera.getParameters(); + final int width = parameters.getPreviewSize().width; + final int height = parameters.getPreviewSize().height; + mCallback.onPreviewFrame(data, parameters.getPreviewFormat(), width, height); + } + }); + } catch (IOException e) { throw new RuntimeException(e); } diff --git a/library/src/main/api21/com/google/android/cameraview/Camera2.java b/library/src/main/api21/com/google/android/cameraview/Camera2.java index 2b6eaf7d..20214d24 100644 --- a/library/src/main/api21/com/google/android/cameraview/Camera2.java +++ b/library/src/main/api21/com/google/android/cameraview/Camera2.java @@ -31,6 +31,7 @@ import android.media.Image; import android.media.ImageReader; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import android.util.SparseIntArray; import android.view.Surface; @@ -156,19 +157,26 @@ public void onReady() { @Override public void onImageAvailable(ImageReader reader) { - try (Image image = reader.acquireNextImage()) { - Image.Plane[] planes = image.getPlanes(); - if (planes.length > 0) { - ByteBuffer buffer = planes[0].getBuffer(); - byte[] data = new byte[buffer.remaining()]; - buffer.get(data); - mCallback.onPictureTaken(data); - } + byte[] data = getByteDataFromImageReader(reader); + if (data != null) { + mCallback.onPictureTaken(data); } } - }; + private final ImageReader.OnImageAvailableListener mOnPreviewImageAvailableListener + = new ImageReader.OnImageAvailableListener() { + + @Override + public void onImageAvailable(ImageReader reader) { + byte[] data = getByteDataFromImageReader(reader); + if (data != null) { + mCallback.onPreviewFrame(data, reader.getImageFormat(), + reader.getWidth(), + reader.getHeight()); + } + } + }; private String mCameraId; @@ -182,6 +190,8 @@ public void onImageAvailable(ImageReader reader) { private ImageReader mImageReader; + private ImageReader mCallbackImageDataReader; + private final SizeMap mPreviewSizes = new SizeMap(); private final SizeMap mPictureSizes = new SizeMap(); @@ -232,6 +242,11 @@ void stop() { mImageReader.close(); mImageReader = null; } + + if (mCallbackImageDataReader != null) { + mCallbackImageDataReader.close(); + mCallbackImageDataReader = null; + } } @Override @@ -435,11 +450,49 @@ protected void collectPictureSizes(SizeMap sizes, StreamConfigurationMap map) { private void prepareImageReader() { Size largest = mPictureSizes.sizes(mAspectRatio).last(); - mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), + initImageReader(largest.getWidth(), largest.getHeight()); + + Size size = chooseOptimalSize(); + initCallbackImageDataReader(size.getWidth(), size.getHeight()); + } + + private void initImageReader(int width, int height){ + mImageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, /* maxImages */ 2); mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, null); } + private void initCallbackImageDataReader(int width, int height) { + + if (mCallbackImageDataReader != null) { + mCallbackImageDataReader.close(); + } + + mCallbackImageDataReader = ImageReader.newInstance(width, height, + ImageFormat.NV21, /* maxImages */ 1); + mCallbackImageDataReader.setOnImageAvailableListener(mOnPreviewImageAvailableListener, null); + } + + /** + * Extract the byte data from the ImageReader + * @param reader + * @return byte array or null if failed + */ + @Nullable + private byte[] getByteDataFromImageReader(@NonNull ImageReader reader) { + byte[] data = null; + try (Image image = reader.acquireNextImage()) { + Image.Plane[] planes = image.getPlanes(); + if (planes.length > 0) { + ByteBuffer buffer = planes[0].getBuffer(); + data = new byte[buffer.remaining()]; + buffer.get(data); + } + } + return data; + } + + /** *
Starts opening a camera device.
*The result will be processed in {@link #mCameraDeviceCallback}.
@@ -463,11 +516,14 @@ void startCaptureSession() { } Size previewSize = chooseOptimalSize(); mPreview.setBufferSize(previewSize.getWidth(), previewSize.getHeight()); + Surface surface = mPreview.getSurface(); try { mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewRequestBuilder.addTarget(surface); - mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), + mPreviewRequestBuilder.addTarget(mCallbackImageDataReader.getSurface()); + mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface(), + mCallbackImageDataReader.getSurface()), mSessionCallback, null); } catch (CameraAccessException e) { throw new RuntimeException("Failed to start camera session"); diff --git a/library/src/main/base/com/google/android/cameraview/CameraViewImpl.java b/library/src/main/base/com/google/android/cameraview/CameraViewImpl.java index 31dab0c4..56cbb6f1 100644 --- a/library/src/main/base/com/google/android/cameraview/CameraViewImpl.java +++ b/library/src/main/base/com/google/android/cameraview/CameraViewImpl.java @@ -77,6 +77,7 @@ interface Callback { void onPictureTaken(byte[] data); + void onPreviewFrame(byte[] data, int format, int width, int height); } } diff --git a/library/src/main/java/com/google/android/cameraview/CameraView.java b/library/src/main/java/com/google/android/cameraview/CameraView.java index 104e53f2..a3e5dd9f 100644 --- a/library/src/main/java/com/google/android/cameraview/CameraView.java +++ b/library/src/main/java/com/google/android/cameraview/CameraView.java @@ -448,6 +448,13 @@ public void onPictureTaken(byte[] data) { } } + @Override + public void onPreviewFrame(byte[] data, int format, int width, int height) { + for (Callback callback : mCallbacks) { + callback.onPreviewFrame(data, format, width, height); + } + } + public void reserveRequestLayoutOnOpen() { mRequestLayoutOnOpen = true; } @@ -534,6 +541,17 @@ public void onCameraClosed(CameraView cameraView) { */ public void onPictureTaken(CameraView cameraView, byte[] data) { } + + /** + * Called when a preview frame is rendered + * @param data raw byte data + * @param format data format + * @param width image width + * @param height image height + */ + public void onPreviewFrame(byte[] data, int format, int width, int height){ + } + } }