Revisit Full2PictureRecorder using actions

pull/580/head
Mattia Iavarone 6 years ago
parent eb6193757c
commit f08221b46a
  1. 32
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  2. 3
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/action/ActionHolder.java
  3. 113
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full2PictureRecorder.java

@ -137,6 +137,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
return value == null ? fallback : value;
}
@SuppressWarnings("DuplicateBranchesInSwitch")
@NonNull
private CameraException createCameraException(@NonNull CameraAccessException exception) {
int reason;
@ -151,6 +152,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
return new CameraException(exception, reason);
}
@SuppressWarnings("DuplicateBranchesInSwitch")
@NonNull
private CameraException createCameraException(int stateCallbackError) {
int reason;
@ -246,10 +248,6 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
private final CameraCaptureSession.CaptureCallback mRepeatingRequestCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
if (mPictureRecorder instanceof Full2PictureRecorder) {
((Full2PictureRecorder) mPictureRecorder).onCaptureStarted(request);
}
for (Action action : mActions) {
action.onCaptureStarted(Camera2Engine.this, request);
}
@ -257,7 +255,6 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
super.onCaptureProgressed(session, request, partialResult);
if (mMeter != null && mMeter.isMetering()) {
mMeter.onCapture(partialResult);
}
@ -271,11 +268,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
mLastRepeatingResult = result;
if (mPictureRecorder instanceof Full2PictureRecorder) {
((Full2PictureRecorder) mPictureRecorder).onCaptureCompleted(result);
}
if (mPictureRecorder instanceof Snapshot2PictureRecorder) {
((Snapshot2PictureRecorder) mPictureRecorder).onCaptureCompleted(result);
}
@ -683,14 +676,18 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
} else {
LOG.i("onTakePicture:", "doMetering is false. Performing.");
try {
if (mPictureCaptureStopsPreview) {
// These two are present in official samples and are probably meant to speed things up?
// But from my tests, they actually make everything slower. So this is disabled by default
// with a boolean flag. Maybe in the future we can make this configurable as some
// people might want to stop the preview while picture is being taken even if it
// increases the latency.
mSession.stopRepeating();
mSession.abortCaptures();
}
CaptureRequest.Builder builder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
applyAllParameters(builder, mRepeatingRequestBuilder);
mPictureRecorder = new Full2PictureRecorder(stub, this,
mSession,
mRepeatingRequestCallback,
builder,
mPictureReader,
mPictureCaptureStopsPreview);
mPictureRecorder = new Full2PictureRecorder(stub, this, builder, mPictureReader);
mPictureRecorder.take();
} catch (CameraAccessException e) {
throw createCameraException(e);
@ -1421,5 +1418,10 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
applyRepeatingRequestBuilder();
}
@Override
public void applyBuilder(@NonNull Action source, @NonNull CaptureRequest.Builder builder) throws CameraAccessException {
mSession.capture(builder.build(), mRepeatingRequestCallback, null);
}
//endregion
}

@ -1,5 +1,6 @@
package com.otaliastudios.cameraview.engine.action;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
@ -23,4 +24,6 @@ public interface ActionHolder {
CaptureRequest.Builder getBuilder(@NonNull Action action);
void applyBuilder(@NonNull Action source);
void applyBuilder(@NonNull Action source, @NonNull CaptureRequest.Builder builder) throws CameraAccessException;
}

@ -1,18 +1,18 @@
package com.otaliastudios.cameraview.picture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import com.otaliastudios.cameraview.CameraLogger;
import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.engine.Camera2Engine;
import com.otaliastudios.cameraview.engine.action.Action;
import com.otaliastudios.cameraview.engine.action.ActionHolder;
import com.otaliastudios.cameraview.engine.action.BaseAction;
import com.otaliastudios.cameraview.internal.utils.ExifHelper;
import com.otaliastudios.cameraview.internal.utils.WorkerHandler;
@ -21,7 +21,6 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.exifinterface.media.ExifInterface;
@ -34,81 +33,57 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader
private static final String TAG = Full2PictureRecorder.class.getSimpleName();
private static final CameraLogger LOG = CameraLogger.create(TAG);
private static final int STATE_IDLE = 0;
private static final int STATE_WAITING_CAPTURE = 1;
private static final int STATE_WAITING_IMAGE = 2;
private CameraCaptureSession mSession;
private CameraCaptureSession.CaptureCallback mCallback;
private ImageReader mPictureReader;
private CaptureRequest.Builder mPictureBuilder;
private boolean mStopPreviewBeforeCapture;
private int mState = STATE_IDLE;
private int mSequenceId;
private final ActionHolder mHolder;
private final Action mAction;
private final ImageReader mPictureReader;
private final CaptureRequest.Builder mPictureBuilder;
public Full2PictureRecorder(@NonNull PictureResult.Stub stub,
@Nullable PictureResultListener listener,
@NonNull CameraCaptureSession session,
@NonNull CameraCaptureSession.CaptureCallback callback,
@NonNull Camera2Engine engine,
@NonNull CaptureRequest.Builder pictureBuilder,
@NonNull ImageReader pictureReader,
boolean stopPreviewBeforeCapture) {
super(stub, listener);
mSession = session;
mCallback = callback;
@NonNull ImageReader pictureReader) {
super(stub, engine);
mHolder = engine;
mPictureBuilder = pictureBuilder;
mStopPreviewBeforeCapture = stopPreviewBeforeCapture;
mPictureReader = pictureReader;
mPictureReader.setOnImageAvailableListener(this, WorkerHandler.get().getHandler());
}
@Override
public void take() {
try {
mState = STATE_WAITING_CAPTURE;
mPictureBuilder.addTarget(mPictureReader.getSurface());
mPictureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mResult.rotation);
mPictureBuilder.setTag(CameraDevice.TEMPLATE_STILL_CAPTURE);
if (mStopPreviewBeforeCapture) {
// These two are present in official samples and are probably meant to speed things up?
// But from my tests, they actually make everything slower. So this is disabled by default
// with a boolean coming from the engine. Maybe in the future we can make this configurable
// as some people might want to stop the preview while picture is being taken even if it
// increases the latency.
mSession.stopRepeating();
mSession.abortCaptures();
mAction = new BaseAction() {
@Override
protected void onStart(@NonNull ActionHolder holder) {
super.onStart(holder);
mPictureBuilder.addTarget(mPictureReader.getSurface());
mPictureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mResult.rotation);
mPictureBuilder.setTag(CameraDevice.TEMPLATE_STILL_CAPTURE);
try {
holder.applyBuilder(this, mPictureBuilder);
} catch (CameraAccessException e) {
mResult = null;
mError = e;
dispatchResult();
}
}
mSequenceId = mSession.capture(mPictureBuilder.build(), mCallback, null);
} catch (CameraAccessException e) {
mResult = null;
mError = e;
dispatchResult();
}
}
public void onCaptureStarted(@NonNull CaptureRequest request) {
if (mState == STATE_WAITING_CAPTURE) {
if (request.getTag() == (Integer) CameraDevice.TEMPLATE_STILL_CAPTURE) {
dispatchOnShutter(false);
@Override
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) {
super.onCaptureStarted(holder, request);
if (request.getTag() == (Integer) CameraDevice.TEMPLATE_STILL_CAPTURE) {
LOG.i("onCaptureStarted:", "Dispatching picture shutter.");
dispatchOnShutter(false);
setState(STATE_COMPLETED);
}
}
}
};
}
public void onCaptureCompleted(@NonNull TotalCaptureResult result) {
if (mState == STATE_WAITING_CAPTURE) {
if (result.getSequenceId() == mSequenceId) {
// This has no real use for now other than logging.
LOG.i("onCaptureCompleted:", "Got result, moving to STATE_WAITING_IMAGE");
mState = STATE_WAITING_IMAGE;
}
}
@Override
public void take() {
mAction.start(mHolder);
}
@Override
public void onImageAvailable(ImageReader reader) {
LOG.i("onImageAvailable started.");
mState = STATE_IDLE;
// Read the JPEG.
Image image = null;
//noinspection TryFinallyCanBeTryWithResources
@ -133,7 +108,8 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader
mResult.rotation = 0;
try {
ExifInterface exif = new ExifInterface(new ByteArrayInputStream(mResult.data));
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
mResult.rotation = ExifHelper.readExifOrientation(exifOrientation);
} catch (IOException ignore) { }
@ -141,11 +117,4 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader
LOG.i("onImageAvailable ended.");
dispatchResult();
}
@Override
protected void dispatchResult() {
mState = STATE_IDLE;
super.dispatchResult();
}
}

Loading…
Cancel
Save