Reorder Camera1Engine

pull/494/head
Mattia Iavarone 6 years ago
parent 98741c2bfa
commit a63d446012
  1. 691
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java
  2. 1
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  3. 8
      cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java
  4. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/Snapshot1PictureRecorder.java

@ -3,6 +3,7 @@ package com.otaliastudios.cameraview.engine;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.graphics.ImageFormat; import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
@ -57,52 +58,84 @@ public class Camera1Engine extends CameraEngine implements
private static final String TAG = Camera1Engine.class.getSimpleName(); private static final String TAG = Camera1Engine.class.getSimpleName();
private static final CameraLogger LOG = CameraLogger.create(TAG); private static final CameraLogger LOG = CameraLogger.create(TAG);
private static final int PREVIEW_FORMAT = ImageFormat.NV21;
@VisibleForTesting static final int AUTOFOCUS_END_DELAY_MILLIS = 2500; @VisibleForTesting static final int AUTOFOCUS_END_DELAY_MILLIS = 2500;
private Camera mCamera; private Camera mCamera;
@VisibleForTesting int mCameraId; @VisibleForTesting int mCameraId;
private int mPreviewStreamFormat;
private Runnable mFocusEndRunnable; private Runnable mFocusEndRunnable;
private final Runnable mFocusResetRunnable = new Runnable() {
@Override
public void run() {
if (!isCameraAvailable()) return;
mCamera.cancelAutoFocus();
Camera.Parameters params = mCamera.getParameters();
int maxAF = params.getMaxNumFocusAreas();
int maxAE = params.getMaxNumMeteringAreas();
if (maxAF > 0) params.setFocusAreas(null);
if (maxAE > 0) params.setMeteringAreas(null);
applyDefaultFocus(params); // Revert to internal focus.
mCamera.setParameters(params);
}
};
public Camera1Engine(@NonNull Callback callback) { public Camera1Engine(@NonNull Callback callback) {
super(callback); super(callback);
mMapper = Mapper.get(Engine.CAMERA1); mMapper = Mapper.get(Engine.CAMERA1);
} }
private boolean isCameraAvailable() { //region Utilities
return getEngineState() == STATE_STARTED;
@Override
public void onError(int error, Camera camera) {
if (error == Camera.CAMERA_ERROR_SERVER_DIED) {
// Looks like this is recoverable.
LOG.w("Recoverable error inside the onError callback.", "CAMERA_ERROR_SERVER_DIED");
restart();
return;
}
String message = LOG.e("Internal Camera1 error.", error);
Exception runtime = new RuntimeException(message);
int reason;
switch (error) {
case Camera.CAMERA_ERROR_EVICTED: reason = CameraException.REASON_DISCONNECTED; break;
case Camera.CAMERA_ERROR_UNKNOWN: reason = CameraException.REASON_UNKNOWN; break;
default: reason = CameraException.REASON_UNKNOWN;
}
throw new CameraException(runtime, reason);
} }
private void schedule(@Nullable final Op<Void> op, final boolean ensureAvailable, final Runnable action) { //endregion
mHandler.run(new Runnable() {
@Override //region Protected APIs
public void run() {
if (ensureAvailable && !isCameraAvailable()) { @NonNull
if (op != null) op.end(null); @Override
} else { protected List<Size> getPreviewStreamAvailableSizes() {
action.run(); List<Camera.Size> sizes = mCamera.getParameters().getSupportedPreviewSizes();
if (op != null) op.end(null); List<Size> result = new ArrayList<>(sizes.size());
} for (Camera.Size size : sizes) {
Size add = new Size(size.width, size.height);
if (!result.contains(add)) result.add(add);
}
LOG.i("getPreviewStreamAvailableSizes:", result);
return result;
}
@WorkerThread
@Override
protected void onPreviewStreamSizeChanged() {
restartPreview();
}
@Override
protected boolean collectCameraInfo(@NonNull Facing facing) {
int internalFacing = mMapper.map(facing);
LOG.i("collectCameraInfo", "Facing:", facing, "Internal:", internalFacing, "Cameras:", Camera.getNumberOfCameras());
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == internalFacing) {
mSensorOffset = cameraInfo.orientation;
mCameraId = i;
return true;
} }
}); }
return false;
} }
//endregion
//region Start
@NonNull @NonNull
@WorkerThread @WorkerThread
@Override @Override
@ -119,13 +152,7 @@ public class Camera1Engine extends CameraEngine implements
LOG.i("onStartEngine:", "Applying default parameters."); LOG.i("onStartEngine:", "Applying default parameters.");
Camera.Parameters params = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
mCameraOptions = new CameraOptions(params, flip(REF_SENSOR, REF_VIEW)); mCameraOptions = new CameraOptions(params, flip(REF_SENSOR, REF_VIEW));
applyDefaultFocus(params); applyAllParameters(params);
applyFlash(params, Flash.OFF);
applyLocation(params, null);
applyWhiteBalance(params, WhiteBalance.AUTO);
applyHdr(params, Hdr.OFF);
applyPlaySounds(mPlaySounds);
params.setRecordingHint(getMode() == Mode.VIDEO);
mCamera.setParameters(params); mCamera.setParameters(params);
mCamera.setDisplayOrientation(offset(REF_SENSOR, REF_VIEW)); // <- not allowed during preview mCamera.setDisplayOrientation(offset(REF_SENSOR, REF_VIEW)); // <- not allowed during preview
LOG.i("onStartEngine:", "Ended"); LOG.i("onStartEngine:", "Ended");
@ -168,10 +195,10 @@ public class Camera1Engine extends CameraEngine implements
mPreview.setStreamSize(previewSize.getWidth(), previewSize.getHeight()); mPreview.setStreamSize(previewSize.getWidth(), previewSize.getHeight());
Camera.Parameters params = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
mPreviewStreamFormat = params.getPreviewFormat(); params.setPreviewFormat(ImageFormat.NV21); // should be the default, but let's make sure, since YuvImage will only support this & a few others
params.setPreviewSize(mPreviewStreamSize.getWidth(), mPreviewStreamSize.getHeight()); // <- not allowed during preview params.setPreviewSize(mPreviewStreamSize.getWidth(), mPreviewStreamSize.getHeight()); // not allowed during preview
if (getMode() == Mode.PICTURE) { if (getMode() == Mode.PICTURE) {
params.setPictureSize(mCaptureSize.getWidth(), mCaptureSize.getHeight()); // <- allowed params.setPictureSize(mCaptureSize.getWidth(), mCaptureSize.getHeight()); // allowed during preview
} else { } else {
// mCaptureSize in this case is a video size. The available video sizes are not necessarily // mCaptureSize in this case is a video size. The available video sizes are not necessarily
// a subset of the picture sizes, so we can't use the mCaptureSize value: it might crash. // a subset of the picture sizes, so we can't use the mCaptureSize value: it might crash.
@ -184,7 +211,7 @@ public class Camera1Engine extends CameraEngine implements
mCamera.setPreviewCallbackWithBuffer(null); // Release anything left mCamera.setPreviewCallbackWithBuffer(null); // Release anything left
mCamera.setPreviewCallbackWithBuffer(this); // Add ourselves mCamera.setPreviewCallbackWithBuffer(this); // Add ourselves
getFrameManager().setUp(ImageFormat.getBitsPerPixel(mPreviewStreamFormat), mPreviewStreamSize); getFrameManager().setUp(ImageFormat.getBitsPerPixel(PREVIEW_FORMAT), mPreviewStreamSize);
LOG.i("onStartPreview", "Starting preview with startPreview()."); LOG.i("onStartPreview", "Starting preview with startPreview().");
try { try {
@ -197,6 +224,10 @@ public class Camera1Engine extends CameraEngine implements
return Tasks.forResult(null); return Tasks.forResult(null);
} }
//endregion
//region Stop
@NonNull @NonNull
@Override @Override
protected Task<Void> onStopPreview() { protected Task<Void> onStopPreview() {
@ -205,7 +236,6 @@ public class Camera1Engine extends CameraEngine implements
mVideoRecorder = null; mVideoRecorder = null;
} }
mPictureRecorder = null; mPictureRecorder = null;
mPreviewStreamFormat = 0;
getFrameManager().release(); getFrameManager().release();
mCamera.setPreviewCallbackWithBuffer(null); // Release anything left mCamera.setPreviewCallbackWithBuffer(null); // Release anything left
try { try {
@ -216,7 +246,6 @@ public class Camera1Engine extends CameraEngine implements
return Tasks.forResult(null); return Tasks.forResult(null);
} }
@NonNull @NonNull
@Override @Override
protected Task<Void> onStopBind() { protected Task<Void> onStopBind() {
@ -263,206 +292,9 @@ public class Camera1Engine extends CameraEngine implements
return Tasks.forResult(null); return Tasks.forResult(null);
} }
@WorkerThread //endregion
@Override
protected void onPreviewStreamSizeChanged() {
restartPreview();
}
@Override
protected boolean collectCameraInfo(@NonNull Facing facing) {
int internalFacing = mMapper.map(facing);
LOG.i("collectCameraInfo", "Facing:", facing, "Internal:", internalFacing, "Cameras:", Camera.getNumberOfCameras());
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == internalFacing) {
mSensorOffset = cameraInfo.orientation;
mCameraId = i;
return true;
}
}
return false;
}
@NonNull
@Override
protected FrameManager instantiateFrameManager() {
return new FrameManager(2, this);
}
@Override
public void onBufferAvailable(@NonNull byte[] buffer) {
// TODO: sync with handler?
if (isCameraAvailable()) {
mCamera.addCallbackBuffer(buffer);
}
}
@Override
public void onError(int error, Camera camera) {
if (error == Camera.CAMERA_ERROR_SERVER_DIED) {
// Looks like this is recoverable.
LOG.w("Recoverable error inside the onError callback.", "CAMERA_ERROR_SERVER_DIED");
restart();
return;
}
String message = LOG.e("Internal Camera1 error.", error);
Exception runtime = new RuntimeException(message);
int reason;
switch (error) {
case Camera.CAMERA_ERROR_EVICTED: reason = CameraException.REASON_DISCONNECTED; break;
case Camera.CAMERA_ERROR_UNKNOWN: reason = CameraException.REASON_UNKNOWN; break;
default: reason = CameraException.REASON_UNKNOWN;
}
throw new CameraException(runtime, reason);
}
@Override
public void setLocation(@Nullable Location location) {
final Location oldLocation = mLocation;
mLocation = location;
schedule(mLocationOp, true, new Runnable() {
@Override
public void run() {
Camera.Parameters params = mCamera.getParameters();
if (applyLocation(params, oldLocation)) mCamera.setParameters(params);
}
});
}
private boolean applyLocation(@NonNull Camera.Parameters params,
@SuppressWarnings("unused") @Nullable Location oldLocation) {
if (mLocation != null) {
params.setGpsLatitude(mLocation.getLatitude());
params.setGpsLongitude(mLocation.getLongitude());
params.setGpsAltitude(mLocation.getAltitude());
params.setGpsTimestamp(mLocation.getTime());
params.setGpsProcessingMethod(mLocation.getProvider());
}
return true;
}
@Override //region Pictures
public void setWhiteBalance(@NonNull WhiteBalance whiteBalance) {
final WhiteBalance old = mWhiteBalance;
mWhiteBalance = whiteBalance;
schedule(mWhiteBalanceOp, true, new Runnable() {
@Override
public void run() {
Camera.Parameters params = mCamera.getParameters();
if (applyWhiteBalance(params, old)) mCamera.setParameters(params);
}
});
}
private boolean applyWhiteBalance(@NonNull Camera.Parameters params, @NonNull WhiteBalance oldWhiteBalance) {
if (mCameraOptions.supports(mWhiteBalance)) {
params.setWhiteBalance((String) mMapper.map(mWhiteBalance));
return true;
}
mWhiteBalance = oldWhiteBalance;
return false;
}
@Override
public void setHdr(@NonNull Hdr hdr) {
final Hdr old = mHdr;
mHdr = hdr;
schedule(mHdrOp, true, new Runnable() {
@Override
public void run() {
Camera.Parameters params = mCamera.getParameters();
if (applyHdr(params, old)) mCamera.setParameters(params);
}
});
}
private boolean applyHdr(@NonNull Camera.Parameters params, @NonNull Hdr oldHdr) {
if (mCameraOptions.supports(mHdr)) {
params.setSceneMode((String) mMapper.map(mHdr));
return true;
}
mHdr = oldHdr;
return false;
}
@SuppressWarnings("UnusedReturnValue")
@TargetApi(17)
private boolean applyPlaySounds(boolean oldPlaySound) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(mCameraId, info);
if (info.canDisableShutterSound) {
try {
// this method is documented to throw on some occasions. #377
return mCamera.enableShutterSound(mPlaySounds);
} catch (RuntimeException exception) {
return false;
}
}
}
if (mPlaySounds) {
return true;
}
mPlaySounds = oldPlaySound;
return false;
}
@Override
public void setFlash(@NonNull Flash flash) {
final Flash old = mFlash;
mFlash = flash;
schedule(mFlashOp, true, new Runnable() {
@Override
public void run() {
Camera.Parameters params = mCamera.getParameters();
if (applyFlash(params, old)) mCamera.setParameters(params);
}
});
}
private boolean applyFlash(@NonNull Camera.Parameters params, @NonNull Flash oldFlash) {
if (mCameraOptions.supports(mFlash)) {
params.setFlashMode((String) mMapper.map(mFlash));
return true;
}
mFlash = oldFlash;
return false;
}
// Choose the best default focus, based on session type.
private void applyDefaultFocus(@NonNull Camera.Parameters params) {
List<String> modes = params.getSupportedFocusModes();
if (getMode() == Mode.VIDEO &&
modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
return;
}
if (modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
return;
}
if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
return;
}
if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
//noinspection UnnecessaryReturnStatement
return;
}
}
// -----------------
// Picture recording stuff.
@WorkerThread @WorkerThread
@Override @Override
@ -485,30 +317,12 @@ public class Camera1Engine extends CameraEngine implements
} else { } else {
mPictureRecorder = new Snapshot1PictureRecorder(stub, this, mCamera, outputRatio); mPictureRecorder = new Snapshot1PictureRecorder(stub, this, mCamera, outputRatio);
} }
mPictureRecorder.take(); mPictureRecorder.take();
}
@Override
public void onPreviewFrame(@NonNull byte[] data, Camera camera) {
Frame frame = getFrameManager().getFrame(data,
System.currentTimeMillis(),
offset(REF_SENSOR, REF_OUTPUT),
mPreviewStreamSize,
mPreviewStreamFormat);
mCallback.dispatchFrame(frame);
} }
// ----------------- //endregion
// Video recording stuff.
@Override //region Videos
public void onVideoResult(@Nullable VideoResult.Stub result, @Nullable Exception exception) {
super.onVideoResult(result, exception);
if (result == null) {
// Something went wrong, lock the camera again.
mCamera.lock();
}
}
@Override @Override
protected void onTakeVideo(@NonNull VideoResult.Stub stub) { protected void onTakeVideo(@NonNull VideoResult.Stub stub) {
@ -594,62 +408,303 @@ public class Camera1Engine extends CameraEngine implements
mVideoRecorder.start(stub); mVideoRecorder.start(stub);
} }
// ----------------- @Override
// Zoom and simpler stuff. public void onVideoResult(@Nullable VideoResult.Stub result, @Nullable Exception exception) {
super.onVideoResult(result, exception);
if (result == null) {
// Something went wrong, lock the camera again.
mCamera.lock();
}
}
//endregion
//region Parameters
private void applyAllParameters(@NonNull Camera.Parameters params) {
params.setRecordingHint(getMode() == Mode.VIDEO);
applyDefaultFocus(params);
applyFlash(params, Flash.OFF);
applyLocation(params, null);
applyWhiteBalance(params, WhiteBalance.AUTO);
applyHdr(params, Hdr.OFF);
applyZoom(params, 0F);
applyExposureCorrection(params, 0F);
applyPlaySounds(mPlaySounds);
}
private void applyDefaultFocus(@NonNull Camera.Parameters params) {
List<String> modes = params.getSupportedFocusModes();
if (getMode() == Mode.VIDEO &&
modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
return;
}
if (modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
return;
}
if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
return;
}
if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
//noinspection UnnecessaryReturnStatement
return;
}
}
@Override @Override
public void setZoom(final float zoom, @Nullable final PointF[] points, final boolean notify) { public void setFlash(@NonNull Flash flash) {
schedule(mZoomOp, true, new Runnable() { final Flash old = mFlash;
mFlash = flash;
mHandler.run(new Runnable() {
@Override @Override
public void run() { public void run() {
if (!mCameraOptions.isZoomSupported()) return; if (getEngineState() == STATE_STARTED) {
Camera.Parameters params = mCamera.getParameters();
if (applyFlash(params, old)) mCamera.setParameters(params);
}
mFlashOp.end(null);
}
});
}
mZoomValue = zoom; private boolean applyFlash(@NonNull Camera.Parameters params, @NonNull Flash oldFlash) {
Camera.Parameters params = mCamera.getParameters(); if (mCameraOptions.supports(mFlash)) {
float max = params.getMaxZoom(); params.setFlashMode((String) mMapper.map(mFlash));
params.setZoom((int) (zoom * max)); return true;
mCamera.setParameters(params); }
mFlash = oldFlash;
return false;
}
@Override
public void setLocation(@Nullable Location location) {
final Location oldLocation = mLocation;
mLocation = location;
mHandler.run(new Runnable() {
@Override
public void run() {
if (getEngineState() == STATE_STARTED) {
Camera.Parameters params = mCamera.getParameters();
if (applyLocation(params, oldLocation)) mCamera.setParameters(params);
}
mLocationOp.end(null);
}
});
}
private boolean applyLocation(@NonNull Camera.Parameters params,
@SuppressWarnings("unused") @Nullable Location oldLocation) {
if (mLocation != null) {
params.setGpsLatitude(mLocation.getLatitude());
params.setGpsLongitude(mLocation.getLongitude());
params.setGpsAltitude(mLocation.getAltitude());
params.setGpsTimestamp(mLocation.getTime());
params.setGpsProcessingMethod(mLocation.getProvider());
}
return true;
}
@Override
public void setWhiteBalance(@NonNull WhiteBalance whiteBalance) {
final WhiteBalance old = mWhiteBalance;
mWhiteBalance = whiteBalance;
mHandler.run(new Runnable() {
@Override
public void run() {
if (getEngineState() == STATE_STARTED) {
Camera.Parameters params = mCamera.getParameters();
if (applyWhiteBalance(params, old)) mCamera.setParameters(params);
}
mWhiteBalanceOp.end(null);
}
});
}
private boolean applyWhiteBalance(@NonNull Camera.Parameters params, @NonNull WhiteBalance oldWhiteBalance) {
if (mCameraOptions.supports(mWhiteBalance)) {
params.setWhiteBalance((String) mMapper.map(mWhiteBalance));
return true;
}
mWhiteBalance = oldWhiteBalance;
return false;
}
@Override
public void setHdr(@NonNull Hdr hdr) {
final Hdr old = mHdr;
mHdr = hdr;
mHandler.run(new Runnable() {
@Override
public void run() {
if (getEngineState() == STATE_STARTED) {
Camera.Parameters params = mCamera.getParameters();
if (applyHdr(params, old)) mCamera.setParameters(params);
}
mHdrOp.end(null);
}
});
}
private boolean applyHdr(@NonNull Camera.Parameters params, @NonNull Hdr oldHdr) {
if (mCameraOptions.supports(mHdr)) {
params.setSceneMode((String) mMapper.map(mHdr));
return true;
}
mHdr = oldHdr;
return false;
}
if (notify) { @Override
mCallback.dispatchOnZoomChanged(zoom, points); public void setZoom(final float zoom, @Nullable final PointF[] points, final boolean notify) {
final float old = mZoomValue;
mZoomValue = zoom;
mHandler.run(new Runnable() {
@Override
public void run() {
if (getEngineState() == STATE_STARTED) {
Camera.Parameters params = mCamera.getParameters();
if (applyZoom(params, old)) {
mCamera.setParameters(params);
if (notify) {
mCallback.dispatchOnZoomChanged(mZoomValue, points);
}
}
} }
mZoomOp.end(null);
} }
}); });
} }
private boolean applyZoom(@NonNull Camera.Parameters params, float oldZoom) {
if (mCameraOptions.isZoomSupported()) {
float max = params.getMaxZoom();
params.setZoom((int) (mZoomValue * max));
mCamera.setParameters(params);
return true;
}
mZoomValue = oldZoom;
return false;
}
@Override @Override
public void setExposureCorrection(final float EVvalue, @NonNull final float[] bounds, public void setExposureCorrection(final float EVvalue, @NonNull final float[] bounds,
@Nullable final PointF[] points, final boolean notify) { @Nullable final PointF[] points, final boolean notify) {
schedule(mExposureCorrectionOp, true, new Runnable() { final float old = mExposureCorrectionValue;
mExposureCorrectionValue = EVvalue;
mHandler.run(new Runnable() {
@Override @Override
public void run() { public void run() {
if (!mCameraOptions.isExposureCorrectionSupported()) return; if (getEngineState() == STATE_STARTED) {
Camera.Parameters params = mCamera.getParameters();
if (applyExposureCorrection(params, old)) {
mCamera.setParameters(params);
if (notify) {
mCallback.dispatchOnExposureCorrectionChanged(mExposureCorrectionValue, bounds, points);
}
}
}
mExposureCorrectionOp.end(null);
}
});
}
float value = EVvalue; private boolean applyExposureCorrection(@NonNull Camera.Parameters params, float oldExposureCorrection) {
float max = mCameraOptions.getExposureCorrectionMaxValue(); if (mCameraOptions.isExposureCorrectionSupported()) {
float min = mCameraOptions.getExposureCorrectionMinValue(); // Just make sure we're inside boundaries.
value = value < min ? min : value > max ? max : value; // cap float max = mCameraOptions.getExposureCorrectionMaxValue();
mExposureCorrectionValue = value; float min = mCameraOptions.getExposureCorrectionMinValue();
Camera.Parameters params = mCamera.getParameters(); float val = mExposureCorrectionValue;
int indexValue = (int) (value / params.getExposureCompensationStep()); val = val < min ? min : val > max ? max : val; // cap
params.setExposureCompensation(indexValue); mExposureCorrectionValue = val;
mCamera.setParameters(params); // Apply.
int indexValue = (int) (mExposureCorrectionValue / params.getExposureCompensationStep());
params.setExposureCompensation(indexValue);
return true;
}
mExposureCorrectionValue = oldExposureCorrection;
return false;
}
if (notify) { @Override
mCallback.dispatchOnExposureCorrectionChanged(value, bounds, points); public void setPlaySounds(boolean playSounds) {
final boolean old = mPlaySounds;
mPlaySounds = playSounds;
mHandler.run(new Runnable() {
@Override
public void run() {
if (getEngineState() == STATE_STARTED) {
applyPlaySounds(old);
} }
mPlaySoundsOp.end(null);
} }
}); });
} }
// ----------------- @SuppressWarnings("UnusedReturnValue")
// Tap to focus stuff. @TargetApi(17)
private boolean applyPlaySounds(boolean oldPlaySound) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(mCameraId, info);
if (info.canDisableShutterSound) {
try {
// this method is documented to throw on some occasions. #377
return mCamera.enableShutterSound(mPlaySounds);
} catch (RuntimeException exception) {
return false;
}
}
}
if (mPlaySounds) {
return true;
}
mPlaySounds = oldPlaySound;
return false;
}
//endregion
//region Frame Processing
@NonNull
@Override
protected FrameManager instantiateFrameManager() {
return new FrameManager(2, this);
}
@Override
public void onBufferAvailable(@NonNull byte[] buffer) {
if (getEngineState() == STATE_STARTED) {
mCamera.addCallbackBuffer(buffer);
}
}
@Override
public void onPreviewFrame(@NonNull byte[] data, Camera camera) {
Frame frame = getFrameManager().getFrame(data,
System.currentTimeMillis(),
offset(REF_SENSOR, REF_OUTPUT),
mPreviewStreamSize,
PREVIEW_FORMAT);
mCallback.dispatchFrame(frame);
}
//endregion
//region Auto Focus
@Override @Override
public void startAutoFocus(@Nullable final Gesture gesture, @NonNull final PointF point) { public void startAutoFocus(@Nullable final Gesture gesture, @NonNull final PointF point) {
// Must get width and height from the UI thread. // Must get width and height from the UI thread.
// TODO could take mPreview.surfaceSize like Camera2 does?
int viewWidth = 0, viewHeight = 0; int viewWidth = 0, viewHeight = 0;
if (mPreview != null && mPreview.hasSurface()) { if (mPreview != null && mPreview.hasSurface()) {
viewWidth = mPreview.getView().getWidth(); viewWidth = mPreview.getView().getWidth();
@ -657,10 +712,10 @@ public class Camera1Engine extends CameraEngine implements
} }
final int viewWidthF = viewWidth; final int viewWidthF = viewWidth;
final int viewHeightF = viewHeight; final int viewHeightF = viewHeight;
// Schedule. mHandler.run(new Runnable() {
schedule(null, true, new Runnable() {
@Override @Override
public void run() { public void run() {
if (getEngineState() < STATE_STARTED) return;
if (!mCameraOptions.isAutoFocusSupported()) return; if (!mCameraOptions.isAutoFocusSupported()) return;
final PointF p = new PointF(point.x, point.y); // copy. final PointF p = new PointF(point.x, point.y); // copy.
List<Camera.Area> meteringAreas2 = computeMeteringAreas(p.x, p.y, List<Camera.Area> meteringAreas2 = computeMeteringAreas(p.x, p.y,
@ -683,9 +738,7 @@ public class Camera1Engine extends CameraEngine implements
mFocusEndRunnable = new Runnable() { mFocusEndRunnable = new Runnable() {
@Override @Override
public void run() { public void run() {
if (isCameraAvailable()) { mCallback.dispatchOnFocusEnd(gesture, false, p);
mCallback.dispatchOnFocusEnd(gesture, false, p);
}
} }
}; };
mHandler.post(AUTOFOCUS_END_DELAY_MILLIS, mFocusEndRunnable); mHandler.post(AUTOFOCUS_END_DELAY_MILLIS, mFocusEndRunnable);
@ -712,6 +765,7 @@ public class Camera1Engine extends CameraEngine implements
// Let the mFocusEndRunnable do its job. (could remove it and quickly dispatch // Let the mFocusEndRunnable do its job. (could remove it and quickly dispatch
// onFocusEnd here, but let's make it simpler). // onFocusEnd here, but let's make it simpler).
} }
} }
}); });
} }
@ -758,38 +812,21 @@ public class Camera1Engine extends CameraEngine implements
return new Rect(left, top, right, bottom); return new Rect(left, top, right, bottom);
} }
private final Runnable mFocusResetRunnable = new Runnable() {
// ----------------- @Override
// Size stuff. public void run() {
if (getEngineState() < STATE_STARTED) return;
public final int getPreviewStreamFormat() { mCamera.cancelAutoFocus();
return mPreviewStreamFormat; Camera.Parameters params = mCamera.getParameters();
} int maxAF = params.getMaxNumFocusAreas();
int maxAE = params.getMaxNumMeteringAreas();
if (maxAF > 0) params.setFocusAreas(null);
@NonNull if (maxAE > 0) params.setMeteringAreas(null);
@Override applyDefaultFocus(params); // Revert to internal focus.
protected List<Size> getPreviewStreamAvailableSizes() { mCamera.setParameters(params);
List<Camera.Size> sizes = mCamera.getParameters().getSupportedPreviewSizes();
List<Size> result = new ArrayList<>(sizes.size());
for (Camera.Size size : sizes) {
Size add = new Size(size.width, size.height);
if (!result.contains(add)) result.add(add);
} }
LOG.i("getPreviewStreamAvailableSizes:", result); };
return result;
}
@Override //endregion
public void setPlaySounds(boolean playSounds) {
final boolean old = mPlaySounds;
mPlaySounds = playSounds;
schedule(mPlaySoundsOp, true, new Runnable() {
@Override
public void run() {
applyPlaySounds(old);
}
});
}
} }

@ -647,7 +647,6 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
public void onPictureResult(@Nullable PictureResult.Stub result, @Nullable Exception error) { public void onPictureResult(@Nullable PictureResult.Stub result, @Nullable Exception error) {
boolean fullPicture = mPictureRecorder instanceof Full2PictureRecorder; boolean fullPicture = mPictureRecorder instanceof Full2PictureRecorder;
super.onPictureResult(result, error); super.onPictureResult(result, error);
//noinspection StatementWithEmptyBody
if (fullPicture && mPictureCaptureStopsPreview) { if (fullPicture && mPictureCaptureStopsPreview) {
// See comments in Full2PictureRecorder. // See comments in Full2PictureRecorder.
applyRepeatingRequestBuilder(); applyRepeatingRequestBuilder();

@ -40,16 +40,16 @@ public class EglViewport extends EglElement {
// Stuff from Drawable2d.FULL_RECTANGLE // Stuff from Drawable2d.FULL_RECTANGLE
// A full square, extending from -1 to +1 in both dimensions. // A full square, extending from -1 to +1 in both dimensions.
// When the model/view/projection matrix is identity, this will exactly cover the viewport. // When the model/view/projection matrix is identity, this will exactly cover the viewport.
private static final float FULL_RECTANGLE_COORDS[] = { private static final float[] FULL_RECTANGLE_COORDS = {
-1.0f, -1.0f, // 0 bottom left -1.0f, -1.0f, // 0 bottom left
1.0f, -1.0f, // 1 bottom right 1.0f, -1.0f, // 1 bottom right
-1.0f, 1.0f, // 2 top left -1.0f, 1.0f, // 2 top left
1.0f, 1.0f, // 3 top right 1.0f, 1.0f, // 3 top right
}; };
// Stuff from Drawable2d.FULL_RECTANGLE // Stuff from Drawable2d.FULL_RECTANGLE
// A full square, extending from -1 to +1 in both dimensions. // A full square, extending from -1 to +1 in both dimensions.
private static final float FULL_RECTANGLE_TEX_COORDS[] = { private static final float[] FULL_RECTANGLE_TEX_COORDS = {
0.0f, 0.0f, // 0 bottom left 0.0f, 0.0f, // 0 bottom left
1.0f, 0.0f, // 1 bottom right 1.0f, 0.0f, // 1 bottom right
0.0f, 1.0f, // 2 top left 0.0f, 1.0f, // 2 top left

@ -59,7 +59,7 @@ public class Snapshot1PictureRecorder extends PictureRecorder {
mEngine1 = engine; mEngine1 = engine;
mCamera = camera; mCamera = camera;
mOutputRatio = outputRatio; mOutputRatio = outputRatio;
mFormat = engine.getPreviewStreamFormat(); mFormat = camera.getParameters().getPreviewFormat();
} }
@Override @Override

Loading…
Cancel
Save