Fixed serious bugs. Option to have WRAP_CONTENT to both dimensions

pull/1/head
Mattia Iavarone 7 years ago
parent c5e38fca19
commit b8628d4c2d
  1. 15
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  2. 5
      camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java
  3. 1
      camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java
  4. 29
      camerakit/src/main/base/com/flurgle/camerakit/PreviewImpl.java
  5. 4
      camerakit/src/main/base/com/flurgle/camerakit/TextureViewPreview.java
  6. 64
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java

@ -48,6 +48,7 @@ class Camera1 extends CameraImpl {
private int mDisplayOffset; private int mDisplayOffset;
private int mDeviceOrientation; private int mDeviceOrientation;
private int mSensorOffset;
@Facing private int mFacing; @Facing private int mFacing;
@Flash private int mFlash; @Flash private int mFlash;
@ -130,6 +131,7 @@ class Camera1 extends CameraImpl {
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) { for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, mCameraInfo); Camera.getCameraInfo(i, mCameraInfo);
if (mCameraInfo.facing == internalFacing) { if (mCameraInfo.facing == internalFacing) {
mSensorOffset = mCameraInfo.orientation;
mCameraId = i; mCameraId = i;
mFacing = facing; mFacing = facing;
break; break;
@ -291,6 +293,11 @@ class Camera1 extends CameraImpl {
return mPreviewSize; return mPreviewSize;
} }
@Override
boolean shouldFlipSizes() {
return mSensorOffset % 180 != 0;
}
@Override @Override
boolean isCameraOpened() { boolean isCameraOpened() {
return mCamera != null; return mCamera != null;
@ -337,9 +344,9 @@ class Camera1 extends CameraImpl {
private int computeCameraToDisplayOffset() { private int computeCameraToDisplayOffset() {
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
// or: (360 - ((info.orientation + displayOrientation) % 360)) % 360; // or: (360 - ((info.orientation + displayOrientation) % 360)) % 360;
return ((mCameraInfo.orientation - mDisplayOffset) + 360 + 180) % 360; return ((mSensorOffset - mDisplayOffset) + 360 + 180) % 360;
} else { } else {
return (mCameraInfo.orientation - mDisplayOffset + 360) % 360; return (mSensorOffset - mDisplayOffset + 360) % 360;
} }
} }
@ -348,7 +355,7 @@ class Camera1 extends CameraImpl {
* the camera APIs as long as you call {@link Camera.Parameters#setRotation(int)}. * the camera APIs as long as you call {@link Camera.Parameters#setRotation(int)}.
*/ */
private int computeExifOrientation() { private int computeExifOrientation() {
return (mDeviceOrientation + mCameraInfo.orientation) % 360; return (mDeviceOrientation + mSensorOffset) % 360;
} }
private int calculateCaptureRotation() { private int calculateCaptureRotation() {
@ -388,7 +395,7 @@ class Camera1 extends CameraImpl {
private void adjustCameraParameters() { private void adjustCameraParameters() {
boolean invertPreviewSizes = mDisplayOffset % 180 != 0; boolean invertPreviewSizes = shouldFlipSizes(); // mDisplayOffset % 180 != 0;
mPreview.setDesiredSize( mPreview.setDesiredSize(
invertPreviewSizes ? getPreviewSize().getHeight() : getPreviewSize().getWidth(), invertPreviewSizes ? getPreviewSize().getHeight() : getPreviewSize().getWidth(),
invertPreviewSizes ? getPreviewSize().getWidth() : getPreviewSize().getHeight() invertPreviewSizes ? getPreviewSize().getWidth() : getPreviewSize().getHeight()

@ -231,6 +231,11 @@ class Camera2 extends CameraImpl {
return mPreviewSize; return mPreviewSize;
} }
@Override
boolean shouldFlipSizes() {
return false;
}
@Override @Override
boolean isCameraOpened() { boolean isCameraOpened() {
return mCamera != null; return mCamera != null;

@ -31,6 +31,7 @@ abstract class CameraImpl {
abstract Size getCaptureSize(); abstract Size getCaptureSize();
abstract Size getPreviewSize(); abstract Size getPreviewSize();
abstract boolean shouldFlipSizes(); // Wheter the Sizes should be flipped to match the view orientation.
abstract boolean isCameraOpened(); abstract boolean isCameraOpened();
@Nullable @Nullable

@ -1,6 +1,7 @@
package com.flurgle.camerakit; package com.flurgle.camerakit;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.util.Log;
import android.view.Surface; import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.View; import android.view.View;
@ -14,6 +15,7 @@ abstract class PreviewImpl {
private OnSurfaceChangedCallback mOnSurfaceChangedCallback; private OnSurfaceChangedCallback mOnSurfaceChangedCallback;
// As far as I can see, these are the view/surface dimensions. // As far as I can see, these are the view/surface dimensions.
// This live in the 'View' orientation.
private int mSurfaceWidth; private int mSurfaceWidth;
private int mSurfaceHeight; private int mSurfaceHeight;
@ -49,7 +51,8 @@ abstract class PreviewImpl {
} }
// As far as I can see, these are the view/surface dimensions. // As far as I can see, these are the view/surface dimensions.
// This is called by subclasses. // This is called by subclasses. 1080, 1794 -- 1080, 1440
protected void setSurfaceSize(int width, int height) { protected void setSurfaceSize(int width, int height) {
this.mSurfaceWidth = width; this.mSurfaceWidth = width;
this.mSurfaceHeight = height; this.mSurfaceHeight = height;
@ -57,7 +60,7 @@ abstract class PreviewImpl {
} }
// As far as I can see, these are the actual preview dimensions, as set in CameraParameters. // As far as I can see, these are the actual preview dimensions, as set in CameraParameters.
// This is called by the CameraImpl. // This is called by the CameraImpl. 1200, 1600
void setDesiredSize(int width, int height) { void setDesiredSize(int width, int height) {
this.mDesiredWidth = width; this.mDesiredWidth = width;
this.mDesiredHeight = height; this.mDesiredHeight = height;
@ -73,26 +76,24 @@ abstract class PreviewImpl {
* to match the desired aspect ratio. * to match the desired aspect ratio.
* This means that the external part of the surface will be cropped by the outer view. * This means that the external part of the surface will be cropped by the outer view.
*/ */
protected void refreshScale() { private void refreshScale() {
getView().post(new Runnable() { getView().post(new Runnable() {
@Override @Override
public void run() { public void run() {
if (mDesiredWidth != 0 && mDesiredHeight != 0) { if (mDesiredWidth != 0 && mDesiredHeight != 0) {
AspectRatio aspectRatio = AspectRatio.of(mDesiredWidth, mDesiredHeight); AspectRatio aspectRatio = AspectRatio.of(mDesiredWidth, mDesiredHeight);
int targetHeight = (int) (getView().getWidth() * aspectRatio.toFloat()); float targetHeight = (float) mSurfaceWidth / aspectRatio.toFloat();
float scaleY; float scale = 1;
if (getView().getHeight() > 0) { if (mSurfaceHeight > 0) {
scaleY = (float) targetHeight / (float) getView().getHeight(); scale = targetHeight / (float) mSurfaceHeight;
} else {
scaleY = 1;
} }
if (scaleY > 1) { if (scale > 1) {
getView().setScaleX(1); getView().setScaleX(1f);
getView().setScaleY(scaleY); getView().setScaleY(scale);
} else { } else {
getView().setScaleX(1 / scaleY); getView().setScaleX(1f / scale);
getView().setScaleY(1); getView().setScaleY(1f);
} }
} }
} }

@ -14,7 +14,7 @@ class TextureViewPreview extends PreviewImpl {
private final TextureView mTextureView; private final TextureView mTextureView;
TextureViewPreview(Context context, ViewGroup parent) { TextureViewPreview(Context context, ViewGroup parent) {
final View view = View.inflate(context, R.layout.texture_view, parent); final View view = View.inflate(context, R.layout.texture_view, parent); // MATCH_PARENT
mTextureView = (TextureView) view.findViewById(R.id.texture_view); mTextureView = (TextureView) view.findViewById(R.id.texture_view);
mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@ -28,7 +28,7 @@ class TextureViewPreview extends PreviewImpl {
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
setSurfaceSize(width, height); setSurfaceSize(width, height);
dispatchSurfaceChanged(); dispatchSurfaceChanged();
refreshScale(); // refreshScale();
} }
@Override @Override

@ -11,8 +11,10 @@ import android.content.ContextWrapper;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.YuvImage; import android.graphics.YuvImage;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -24,6 +26,7 @@ import android.util.Log;
import android.view.Display; import android.view.Display;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@ -174,9 +177,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override @Override
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
Log.e(TAG, "onAttachedToWindow");
if (!isInEditMode()) { if (!isInEditMode()) {
Log.e(TAG, "onAttachedToWindow: enabling orientation detector.");
WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay(); Display display = manager.getDefaultDisplay();
mOrientationHelper.enable(display); mOrientationHelper.enable(display);
@ -185,9 +186,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
Log.e(TAG, "onDetachedFromWindow");
if (!isInEditMode()) { if (!isInEditMode()) {
Log.e(TAG, "onDetachedFromWindow: disabling orientation detector.");
mOrientationHelper.disable(); mOrientationHelper.disable();
} }
super.onDetachedFromWindow(); super.onDetachedFromWindow();
@ -215,20 +214,55 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
Size previewSize = getPreviewSize(); Size previewSize = getPreviewSize();
if (previewSize == null) { if (previewSize == null) {
// Early measure.
super.onMeasure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return; return;
} }
if (getLayoutParams().width == LayoutParams.WRAP_CONTENT) { boolean wwc = getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT;
int height = MeasureSpec.getSize(heightMeasureSpec); boolean hwc = getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
float ratio = (float) height / (float) previewSize.getWidth(); boolean flip = mCameraImpl.shouldFlipSizes();
int width = (int) (previewSize.getHeight() * ratio); float previewWidth = flip ? previewSize.getHeight() : previewSize.getWidth();
float previewHeight = flip ? previewSize.getWidth() : previewSize.getHeight();
if (wwc && hwc) {
// If both dimensions are WRAP_CONTENT, let's try to fit the preview size perfectly
// without cropping.
// TODO: This should actually be a flag, like scaleMode, that replaces cropOutput and adjustViewBounds.
// This is like a fitCenter.
// preview: 1600x1200
// parent: 1080x1794
float parentHeight = MeasureSpec.getSize(heightMeasureSpec); // 1794.
float parentWidth = MeasureSpec.getSize(widthMeasureSpec); // 1080. mode = AT_MOST
float targetRatio = previewHeight / previewWidth;
float currentRatio = parentHeight / parentWidth;
Log.e(TAG, "parentHeight="+parentHeight+", parentWidth="+parentWidth);
Log.e(TAG, "previewHeight="+previewHeight+", previewWidth="+previewWidth);
if (currentRatio > targetRatio) {
// View is too tall. Must reduce height.
int newHeight = (int) (parentWidth * targetRatio);
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
} else {
// View is too wide. Must reduce width.
int newWidth = (int) (parentHeight / targetRatio);
super.onMeasure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
}
} else if (wwc) {
// Legacy behavior, with just a WC dimension. This is dangerous because the final size
// might be bigger than the available size, resulting in part of the surface getting cropped.
// Think for example of a 4:3 preview in a 16:9 screen, with width=MP and height=WC.
// This is like a cropCenter.
float height = MeasureSpec.getSize(heightMeasureSpec);
float ratio = height / previewWidth;
int width = (int) (previewHeight * ratio);
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightMeasureSpec); super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightMeasureSpec);
} else if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) { } else if (hwc) {
int width = MeasureSpec.getSize(widthMeasureSpec); float width = MeasureSpec.getSize(widthMeasureSpec);
float ratio = (float) width / (float) previewSize.getHeight(); float ratio = width / previewHeight;
int height = (int) (previewSize.getWidth() * ratio); int height = (int) (previewWidth * ratio);
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
} else { } else {
@ -446,12 +480,18 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
/** /**
* Returns the size used for the preview, * Returns the size used for the preview,
* 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).
* @return a Size
*/ */
@Nullable @Nullable
public Size getPreviewSize() { public Size getPreviewSize() {
return mCameraImpl != null ? mCameraImpl.getPreviewSize() : null; return mCameraImpl != null ? mCameraImpl.getPreviewSize() : null;
} }
/**
* Returns the size used for the capture,
* or null if it hasn't been computed yet (for example if the surface is not ready).
* @return a Size
*/
@Nullable @Nullable
public Size getCaptureSize() { public Size getCaptureSize() {
return mCameraImpl != null ? mCameraImpl.getCaptureSize() : null; return mCameraImpl != null ? mCameraImpl.getCaptureSize() : null;

Loading…
Cancel
Save