|
|
@ -1,18 +1,18 @@ |
|
|
|
package com.otaliastudios.cameraview.picture; |
|
|
|
package com.otaliastudios.cameraview.picture; |
|
|
|
|
|
|
|
|
|
|
|
import android.hardware.camera2.CameraAccessException; |
|
|
|
import android.hardware.camera2.CameraAccessException; |
|
|
|
import android.hardware.camera2.CameraCaptureSession; |
|
|
|
|
|
|
|
import android.hardware.camera2.CameraCharacteristics; |
|
|
|
|
|
|
|
import android.hardware.camera2.CameraDevice; |
|
|
|
import android.hardware.camera2.CameraDevice; |
|
|
|
import android.hardware.camera2.CaptureRequest; |
|
|
|
import android.hardware.camera2.CaptureRequest; |
|
|
|
import android.hardware.camera2.CaptureResult; |
|
|
|
|
|
|
|
import android.hardware.camera2.TotalCaptureResult; |
|
|
|
|
|
|
|
import android.media.Image; |
|
|
|
import android.media.Image; |
|
|
|
import android.media.ImageReader; |
|
|
|
import android.media.ImageReader; |
|
|
|
import android.os.Build; |
|
|
|
import android.os.Build; |
|
|
|
|
|
|
|
|
|
|
|
import com.otaliastudios.cameraview.CameraLogger; |
|
|
|
import com.otaliastudios.cameraview.CameraLogger; |
|
|
|
import com.otaliastudios.cameraview.PictureResult; |
|
|
|
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.ExifHelper; |
|
|
|
import com.otaliastudios.cameraview.internal.utils.WorkerHandler; |
|
|
|
import com.otaliastudios.cameraview.internal.utils.WorkerHandler; |
|
|
|
|
|
|
|
|
|
|
@ -21,7 +21,6 @@ import java.io.IOException; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull; |
|
|
|
import androidx.annotation.NonNull; |
|
|
|
import androidx.annotation.Nullable; |
|
|
|
|
|
|
|
import androidx.annotation.RequiresApi; |
|
|
|
import androidx.annotation.RequiresApi; |
|
|
|
import androidx.exifinterface.media.ExifInterface; |
|
|
|
import androidx.exifinterface.media.ExifInterface; |
|
|
|
|
|
|
|
|
|
|
@ -34,51 +33,30 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader |
|
|
|
private static final String TAG = Full2PictureRecorder.class.getSimpleName(); |
|
|
|
private static final String TAG = Full2PictureRecorder.class.getSimpleName(); |
|
|
|
private static final CameraLogger LOG = CameraLogger.create(TAG); |
|
|
|
private static final CameraLogger LOG = CameraLogger.create(TAG); |
|
|
|
|
|
|
|
|
|
|
|
private static final int STATE_IDLE = 0; |
|
|
|
private final ActionHolder mHolder; |
|
|
|
private static final int STATE_WAITING_CAPTURE = 1; |
|
|
|
private final Action mAction; |
|
|
|
private static final int STATE_WAITING_IMAGE = 2; |
|
|
|
private final ImageReader mPictureReader; |
|
|
|
|
|
|
|
private final CaptureRequest.Builder mPictureBuilder; |
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Full2PictureRecorder(@NonNull PictureResult.Stub stub, |
|
|
|
public Full2PictureRecorder(@NonNull PictureResult.Stub stub, |
|
|
|
@Nullable PictureResultListener listener, |
|
|
|
@NonNull Camera2Engine engine, |
|
|
|
@NonNull CameraCaptureSession session, |
|
|
|
|
|
|
|
@NonNull CameraCaptureSession.CaptureCallback callback, |
|
|
|
|
|
|
|
@NonNull CaptureRequest.Builder pictureBuilder, |
|
|
|
@NonNull CaptureRequest.Builder pictureBuilder, |
|
|
|
@NonNull ImageReader pictureReader, |
|
|
|
@NonNull ImageReader pictureReader) { |
|
|
|
boolean stopPreviewBeforeCapture) { |
|
|
|
super(stub, engine); |
|
|
|
super(stub, listener); |
|
|
|
mHolder = engine; |
|
|
|
mSession = session; |
|
|
|
|
|
|
|
mCallback = callback; |
|
|
|
|
|
|
|
mPictureBuilder = pictureBuilder; |
|
|
|
mPictureBuilder = pictureBuilder; |
|
|
|
mStopPreviewBeforeCapture = stopPreviewBeforeCapture; |
|
|
|
|
|
|
|
mPictureReader = pictureReader; |
|
|
|
mPictureReader = pictureReader; |
|
|
|
mPictureReader.setOnImageAvailableListener(this, WorkerHandler.get().getHandler()); |
|
|
|
mPictureReader.setOnImageAvailableListener(this, WorkerHandler.get().getHandler()); |
|
|
|
} |
|
|
|
mAction = new BaseAction() { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void take() { |
|
|
|
protected void onStart(@NonNull ActionHolder holder) { |
|
|
|
try { |
|
|
|
super.onStart(holder); |
|
|
|
mState = STATE_WAITING_CAPTURE; |
|
|
|
|
|
|
|
mPictureBuilder.addTarget(mPictureReader.getSurface()); |
|
|
|
mPictureBuilder.addTarget(mPictureReader.getSurface()); |
|
|
|
mPictureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mResult.rotation); |
|
|
|
mPictureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mResult.rotation); |
|
|
|
mPictureBuilder.setTag(CameraDevice.TEMPLATE_STILL_CAPTURE); |
|
|
|
mPictureBuilder.setTag(CameraDevice.TEMPLATE_STILL_CAPTURE); |
|
|
|
if (mStopPreviewBeforeCapture) { |
|
|
|
try { |
|
|
|
// These two are present in official samples and are probably meant to speed things up?
|
|
|
|
holder.applyBuilder(this, mPictureBuilder); |
|
|
|
// 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(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mSequenceId = mSession.capture(mPictureBuilder.build(), mCallback, null); |
|
|
|
|
|
|
|
} catch (CameraAccessException e) { |
|
|
|
} catch (CameraAccessException e) { |
|
|
|
mResult = null; |
|
|
|
mResult = null; |
|
|
|
mError = e; |
|
|
|
mError = e; |
|
|
@ -86,29 +64,26 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void onCaptureStarted(@NonNull CaptureRequest request) { |
|
|
|
@Override |
|
|
|
if (mState == STATE_WAITING_CAPTURE) { |
|
|
|
public void onCaptureStarted(@NonNull ActionHolder holder, @NonNull CaptureRequest request) { |
|
|
|
|
|
|
|
super.onCaptureStarted(holder, request); |
|
|
|
if (request.getTag() == (Integer) CameraDevice.TEMPLATE_STILL_CAPTURE) { |
|
|
|
if (request.getTag() == (Integer) CameraDevice.TEMPLATE_STILL_CAPTURE) { |
|
|
|
|
|
|
|
LOG.i("onCaptureStarted:", "Dispatching picture shutter."); |
|
|
|
dispatchOnShutter(false); |
|
|
|
dispatchOnShutter(false); |
|
|
|
|
|
|
|
setState(STATE_COMPLETED); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void onCaptureCompleted(@NonNull TotalCaptureResult result) { |
|
|
|
@Override |
|
|
|
if (mState == STATE_WAITING_CAPTURE) { |
|
|
|
public void take() { |
|
|
|
if (result.getSequenceId() == mSequenceId) { |
|
|
|
mAction.start(mHolder); |
|
|
|
// 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 |
|
|
|
@Override |
|
|
|
public void onImageAvailable(ImageReader reader) { |
|
|
|
public void onImageAvailable(ImageReader reader) { |
|
|
|
LOG.i("onImageAvailable started."); |
|
|
|
LOG.i("onImageAvailable started."); |
|
|
|
mState = STATE_IDLE; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Read the JPEG.
|
|
|
|
// Read the JPEG.
|
|
|
|
Image image = null; |
|
|
|
Image image = null; |
|
|
|
//noinspection TryFinallyCanBeTryWithResources
|
|
|
|
//noinspection TryFinallyCanBeTryWithResources
|
|
|
@ -133,7 +108,8 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader |
|
|
|
mResult.rotation = 0; |
|
|
|
mResult.rotation = 0; |
|
|
|
try { |
|
|
|
try { |
|
|
|
ExifInterface exif = new ExifInterface(new ByteArrayInputStream(mResult.data)); |
|
|
|
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); |
|
|
|
mResult.rotation = ExifHelper.readExifOrientation(exifOrientation); |
|
|
|
} catch (IOException ignore) { } |
|
|
|
} catch (IOException ignore) { } |
|
|
|
|
|
|
|
|
|
|
@ -141,11 +117,4 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader |
|
|
|
LOG.i("onImageAvailable ended."); |
|
|
|
LOG.i("onImageAvailable ended."); |
|
|
|
dispatchResult(); |
|
|
|
dispatchResult(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected void dispatchResult() { |
|
|
|
|
|
|
|
mState = STATE_IDLE; |
|
|
|
|
|
|
|
super.dispatchResult(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|