mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-28 02:37:46 +00:00
update camera preview strategy
// FREEBIE
This commit is contained in:
parent
7817c7697e
commit
4e8e8978f4
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.components.camera;
|
||||
import android.app.Activity;
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.CameraInfo;
|
||||
import android.hardware.Camera.Parameters;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
@ -12,40 +13,46 @@ import android.view.Surface;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class CameraUtils {
|
||||
private static final String TAG = CameraUtils.class.getSimpleName();
|
||||
/*
|
||||
* modified from: https://github.com/commonsguy/cwac-camera/blob/master/camera/src/com/commonsware/cwac/camera/CameraUtils.java
|
||||
*/
|
||||
public static @Nullable Size getPreferredPreviewSize(int displayOrientation,
|
||||
int width,
|
||||
int height,
|
||||
@NonNull Camera camera) {
|
||||
Log.w("CameraUtils", String.format("getPreferredPreviewSize(%d, %d, %d)", displayOrientation, width, height));
|
||||
double targetRatio = (double)width / height;
|
||||
Size optimalSize = null;
|
||||
double minDiff = Double.MAX_VALUE;
|
||||
@NonNull Parameters parameters) {
|
||||
final int targetWidth = displayOrientation % 180 == 90 ? height : width;
|
||||
final int targetHeight = displayOrientation % 180 == 90 ? width : height;
|
||||
final double targetRatio = (double) targetWidth / targetHeight;
|
||||
|
||||
if (displayOrientation == 90 || displayOrientation == 270) {
|
||||
targetRatio = (double)height / width;
|
||||
}
|
||||
Log.w(TAG, String.format("getPreferredPreviewSize(%d, %d, %d) -> target %dx%d, AR %.02f",
|
||||
displayOrientation, width, height,
|
||||
targetWidth, targetHeight, targetRatio));
|
||||
|
||||
List<Size> sizes = camera.getParameters().getSupportedPreviewSizes();
|
||||
|
||||
Collections.sort(sizes, Collections.reverseOrder(new SizeComparator()));
|
||||
List<Size> sizes = parameters.getSupportedPreviewSizes();
|
||||
List<Size> ideals = new LinkedList<>();
|
||||
List<Size> bigEnough = new LinkedList<>();
|
||||
|
||||
for (Size size : sizes) {
|
||||
double ratio = (double)size.width / size.height;
|
||||
Log.w(TAG, String.format(" %dx%d (%.02f)", size.width, size.height, (float)size.width / size.height));
|
||||
|
||||
if (Math.abs(ratio - targetRatio) < minDiff) {
|
||||
optimalSize = size;
|
||||
minDiff = Math.abs(ratio - targetRatio);
|
||||
if (size.height == size.width * targetRatio && size.height >= targetHeight && size.width >= targetWidth) {
|
||||
ideals.add(size);
|
||||
Log.w(TAG, " (ideal ratio)");
|
||||
} else if (size.width >= targetWidth && size.height >= targetHeight) {
|
||||
bigEnough.add(size);
|
||||
Log.w(TAG, " (good size, suboptimal ratio)");
|
||||
}
|
||||
}
|
||||
|
||||
return optimalSize;
|
||||
if (!ideals.isEmpty()) return Collections.min(ideals, new AreaComparator());
|
||||
else if (!bigEnough.isEmpty()) return Collections.min(bigEnough, new AspectRatioComparator(targetRatio));
|
||||
else return Collections.max(sizes, new AreaComparator());
|
||||
}
|
||||
|
||||
// based on
|
||||
@ -74,15 +81,26 @@ public class CameraUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static class SizeComparator implements Comparator<Size> {
|
||||
private static class AreaComparator implements Comparator<Size> {
|
||||
@Override
|
||||
public int compare(Size lhs, Size rhs) {
|
||||
int left = lhs.width * lhs.height;
|
||||
int right = rhs.width * rhs.height;
|
||||
return Long.signum(lhs.width * lhs.height - rhs.width * rhs.height);
|
||||
}
|
||||
}
|
||||
|
||||
if (left < right) return -1;
|
||||
if (left > right) return 1;
|
||||
else return 0;
|
||||
private static class AspectRatioComparator extends AreaComparator {
|
||||
private final double target;
|
||||
public AspectRatioComparator(double target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Size lhs, Size rhs) {
|
||||
final double lhsDiff = Math.abs(target - (double) lhs.width / lhs.height);
|
||||
final double rhsDiff = Math.abs(target - (double) rhs.width / rhs.height);
|
||||
if (lhsDiff < rhsDiff) return -1;
|
||||
else if (lhsDiff > rhsDiff) return 1;
|
||||
else return super.compare(lhs, rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,10 +58,11 @@ public class CameraView extends FrameLayout {
|
||||
private @NonNull volatile Optional<Camera> camera = Optional.absent();
|
||||
private volatile int cameraId = CameraInfo.CAMERA_FACING_BACK;
|
||||
|
||||
private boolean started;
|
||||
private @NonNull State state = State.PAUSED;
|
||||
private @Nullable Size previewSize;
|
||||
private @Nullable CameraViewListener listener;
|
||||
private int displayOrientation = -1;
|
||||
private int outputOrientation = -1;
|
||||
private int displayOrientation = -1;
|
||||
private int outputOrientation = -1;
|
||||
|
||||
public CameraView(Context context) {
|
||||
this(context, null);
|
||||
@ -92,8 +93,8 @@ public class CameraView extends FrameLayout {
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
public void onResume() {
|
||||
if (started) return;
|
||||
started = true;
|
||||
if (state != State.PAUSED) return;
|
||||
state = State.RESUMED;
|
||||
Log.w(TAG, "onResume() queued");
|
||||
enqueueTask(new SerialAsyncTask<Camera>() {
|
||||
@Override
|
||||
@ -125,8 +126,6 @@ public class CameraView extends FrameLayout {
|
||||
synchronized (CameraView.this) {
|
||||
CameraView.this.notifyAll();
|
||||
}
|
||||
requestLayout();
|
||||
invalidate();
|
||||
Log.w(TAG, "onResume() completed");
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(TAG, "exception when starting camera preview", e);
|
||||
@ -137,8 +136,8 @@ public class CameraView extends FrameLayout {
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
if (!started) return;
|
||||
started = false;
|
||||
if (state == State.PAUSED) return;
|
||||
state = State.PAUSED;
|
||||
Log.w(TAG, "onPause() queued");
|
||||
|
||||
enqueueTask(new SerialAsyncTask<Void>() {
|
||||
@ -175,28 +174,7 @@ public class CameraView extends FrameLayout {
|
||||
}
|
||||
|
||||
public boolean isStarted() {
|
||||
return started;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0 && camera.isPresent()) {
|
||||
final Size preferredPreviewSize = CameraUtils.getPreferredPreviewSize(displayOrientation,
|
||||
getMeasuredWidth(),
|
||||
getMeasuredHeight(),
|
||||
camera.get());
|
||||
final Parameters parameters = camera.get().getParameters();
|
||||
if (preferredPreviewSize != null && !parameters.getPreviewSize().equals(preferredPreviewSize)) {
|
||||
Log.w(TAG, "setting preview size to " + preferredPreviewSize.width + "x" + preferredPreviewSize.height);
|
||||
stopPreview();
|
||||
parameters.setPreviewSize(preferredPreviewSize.width, preferredPreviewSize.height);
|
||||
camera.get().setParameters(parameters);
|
||||
requestLayout();
|
||||
startPreview();
|
||||
}
|
||||
}
|
||||
return state != State.PAUSED;
|
||||
}
|
||||
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
@ -207,8 +185,7 @@ public class CameraView extends FrameLayout {
|
||||
final int previewWidth;
|
||||
final int previewHeight;
|
||||
|
||||
if (camera.isPresent()) {
|
||||
final Size previewSize = camera.get().getParameters().getPreviewSize();
|
||||
if (camera.isPresent() && previewSize != null) {
|
||||
if (displayOrientation == 90 || displayOrientation == 270) {
|
||||
previewWidth = previewSize.height;
|
||||
previewHeight = previewSize.width;
|
||||
@ -225,7 +202,6 @@ public class CameraView extends FrameLayout {
|
||||
Log.w(TAG, "skipping layout due to zero-width/height preview size");
|
||||
return;
|
||||
}
|
||||
Log.w(TAG, "layout " + width + "x" + height + ", target " + previewWidth + "x" + previewHeight);
|
||||
|
||||
if (width * previewHeight > height * previewWidth) {
|
||||
final int scaledChildHeight = previewHeight * width / previewWidth;
|
||||
@ -236,11 +212,18 @@ public class CameraView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
Log.w(TAG, "onSizeChanged(" + oldw + "x" + oldh + " -> " + w + "x" + h + ")");
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
if (camera.isPresent()) startPreview(camera.get().getParameters());
|
||||
}
|
||||
|
||||
public void setListener(@Nullable CameraViewListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setPreviewCallback(final PreviewCallback previewCallback) {
|
||||
public void setPreviewCallback(final @NonNull PreviewCallback previewCallback) {
|
||||
enqueueTask(new PostInitializationTask<Void>() {
|
||||
@Override
|
||||
protected void onPostMain(Void avoid) {
|
||||
@ -252,8 +235,8 @@ public class CameraView extends FrameLayout {
|
||||
return;
|
||||
}
|
||||
|
||||
final int rotation = getCameraPictureOrientation();
|
||||
final Size previewSize = camera.getParameters().getPreviewSize();
|
||||
final int rotation = getCameraPictureOrientation();
|
||||
final Size previewSize = camera.getParameters().getPreviewSize();
|
||||
if (data != null) {
|
||||
previewCallback.onPreviewFrame(new PreviewFrame(data, previewSize.width, previewSize.height, rotation));
|
||||
}
|
||||
@ -308,6 +291,7 @@ public class CameraView extends FrameLayout {
|
||||
if (camera.isPresent()) {
|
||||
try {
|
||||
camera.get().setPreviewDisplay(surface.getHolder());
|
||||
startPreview(parameters);
|
||||
requestLayout();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
@ -317,10 +301,24 @@ public class CameraView extends FrameLayout {
|
||||
});
|
||||
}
|
||||
|
||||
private void startPreview() {
|
||||
if (camera.isPresent()) {
|
||||
private void startPreview(final @NonNull Parameters parameters) {
|
||||
if (this.camera.isPresent()) {
|
||||
try {
|
||||
camera.get().startPreview();
|
||||
final Camera camera = this.camera.get();
|
||||
final Size preferredPreviewSize = getPreferredPreviewSize(parameters);
|
||||
|
||||
if (preferredPreviewSize != null && !parameters.getPreviewSize().equals(preferredPreviewSize)) {
|
||||
Log.w(TAG, "starting preview with size " + preferredPreviewSize.width + "x" + preferredPreviewSize.height);
|
||||
if (state == State.ACTIVE) stopPreview();
|
||||
previewSize = preferredPreviewSize;
|
||||
parameters.setPreviewSize(preferredPreviewSize.width, preferredPreviewSize.height);
|
||||
camera.setParameters(parameters);
|
||||
} else {
|
||||
previewSize = parameters.getPreviewSize();
|
||||
}
|
||||
camera.startPreview();
|
||||
requestLayout();
|
||||
state = State.ACTIVE;
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
@ -331,13 +329,21 @@ public class CameraView extends FrameLayout {
|
||||
if (camera.isPresent()) {
|
||||
try {
|
||||
camera.get().stopPreview();
|
||||
state = State.RESUMED;
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getCameraPictureOrientation() {
|
||||
private Size getPreferredPreviewSize(@NonNull Parameters parameters) {
|
||||
return CameraUtils.getPreferredPreviewSize(displayOrientation,
|
||||
getMeasuredWidth(),
|
||||
getMeasuredHeight(),
|
||||
parameters);
|
||||
}
|
||||
|
||||
private int getCameraPictureOrientation() {
|
||||
if (getActivity().getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
|
||||
outputOrientation = getCameraPictureRotation(getActivity().getWindowManager()
|
||||
.getDefaultDisplay()
|
||||
@ -589,4 +595,8 @@ public class CameraView extends FrameLayout {
|
||||
return orientation;
|
||||
}
|
||||
}
|
||||
|
||||
private enum State {
|
||||
PAUSED, RESUMED, ACTIVE
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user