parent
e96c9f0846
commit
87796ea2f7
@ -0,0 +1,195 @@ |
|||||||
|
package com.otaliastudios.cameraview.picture; |
||||||
|
|
||||||
|
import android.hardware.Camera; |
||||||
|
import android.hardware.camera2.CameraAccessException; |
||||||
|
import android.hardware.camera2.CameraCaptureSession; |
||||||
|
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 android.view.Surface; |
||||||
|
|
||||||
|
import com.otaliastudios.cameraview.CameraException; |
||||||
|
import com.otaliastudios.cameraview.CameraLogger; |
||||||
|
import com.otaliastudios.cameraview.PictureResult; |
||||||
|
import com.otaliastudios.cameraview.internal.utils.ExifHelper; |
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream; |
||||||
|
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; |
||||||
|
|
||||||
|
/** |
||||||
|
* A {@link PictureResult} that uses standard APIs. |
||||||
|
*/ |
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) |
||||||
|
public class Full2PictureRecorder extends PictureRecorder { |
||||||
|
|
||||||
|
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_FOCUS_LOCK = 1; |
||||||
|
private static final int STATE_WAITING_PRECAPTURE_START = 2; |
||||||
|
private static final int STATE_WAITING_PRECAPTURE_END = 3; |
||||||
|
private static final int STATE_WAITING_CAPTURE = 4; |
||||||
|
private static final int STATE_WAITING_IMAGE = 5; |
||||||
|
|
||||||
|
private CameraCaptureSession mSession; |
||||||
|
private CaptureRequest.Builder mBuilder; |
||||||
|
private CameraCaptureSession.CaptureCallback mCallback; |
||||||
|
private ImageReader mPictureReader; |
||||||
|
private CaptureRequest.Builder mPictureBuilder; |
||||||
|
private int mState = STATE_IDLE; |
||||||
|
|
||||||
|
public Full2PictureRecorder(@NonNull PictureResult.Stub stub, |
||||||
|
@Nullable PictureResultListener listener, |
||||||
|
@NonNull CameraCaptureSession session, |
||||||
|
@NonNull CaptureRequest.Builder builder, |
||||||
|
@NonNull CameraCaptureSession.CaptureCallback callback, |
||||||
|
@NonNull CaptureRequest.Builder pictureBuilder, |
||||||
|
@NonNull ImageReader pictureReader) { |
||||||
|
super(stub, listener); |
||||||
|
mSession = session; |
||||||
|
mBuilder = builder; |
||||||
|
mCallback = callback; |
||||||
|
mPictureBuilder = pictureBuilder; |
||||||
|
mPictureReader = pictureReader; |
||||||
|
mPictureReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { |
||||||
|
@Override |
||||||
|
public void onImageAvailable(ImageReader reader) { |
||||||
|
mState = STATE_IDLE; |
||||||
|
|
||||||
|
// Read the JPEG.
|
||||||
|
try { |
||||||
|
Image image = reader.acquireLatestImage(); |
||||||
|
ByteBuffer buffer = image.getPlanes()[0].getBuffer(); |
||||||
|
byte[] bytes = new byte[buffer.remaining()]; |
||||||
|
buffer.get(bytes); |
||||||
|
mResult.data = bytes; |
||||||
|
mResult.format = PictureResult.FORMAT_JPEG; |
||||||
|
} catch (Exception e) { |
||||||
|
mResult = null; |
||||||
|
mError = e; |
||||||
|
} |
||||||
|
|
||||||
|
// Before leaving, unlock focus.
|
||||||
|
try { |
||||||
|
mBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, |
||||||
|
CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); |
||||||
|
mSession.capture(mBuilder.build(), mCallback, null); |
||||||
|
} catch (CameraAccessException ignore) { } |
||||||
|
|
||||||
|
// Leave.
|
||||||
|
dispatchResult(); |
||||||
|
} |
||||||
|
}, null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void take() { |
||||||
|
runFocusLock(); |
||||||
|
} |
||||||
|
|
||||||
|
private void runFocusLock() { |
||||||
|
try { |
||||||
|
mState = STATE_WAITING_FOCUS_LOCK; |
||||||
|
mBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, |
||||||
|
CaptureRequest.CONTROL_AF_TRIGGER_START); |
||||||
|
mSession.capture(mBuilder.build(), mCallback, null); |
||||||
|
} catch (CameraAccessException e) { |
||||||
|
mResult = null; |
||||||
|
mError = e; |
||||||
|
dispatchResult(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void runPrecapture() { |
||||||
|
try { |
||||||
|
mState = STATE_WAITING_PRECAPTURE_START; |
||||||
|
mBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, |
||||||
|
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); |
||||||
|
mSession.capture(mBuilder.build(), mCallback, null); |
||||||
|
} catch (CameraAccessException e) { |
||||||
|
mResult = null; |
||||||
|
mError = e; |
||||||
|
dispatchResult(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void runCapture() { |
||||||
|
try { |
||||||
|
mPictureBuilder.setTag(CameraDevice.TEMPLATE_STILL_CAPTURE); |
||||||
|
mPictureBuilder.addTarget(mPictureReader.getSurface()); |
||||||
|
mPictureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mResult.rotation); |
||||||
|
// mCaptureSession.stopRepeating();
|
||||||
|
mSession.abortCaptures(); |
||||||
|
mSession.capture(mPictureBuilder.build(), mCallback, null); |
||||||
|
} catch (CameraAccessException e) { |
||||||
|
mResult = null; |
||||||
|
mError = e; |
||||||
|
dispatchResult(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void process(@NonNull CaptureResult result) { |
||||||
|
switch (mState) { |
||||||
|
case STATE_IDLE: break; |
||||||
|
case STATE_WAITING_FOCUS_LOCK: { |
||||||
|
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE); |
||||||
|
if (afState == null) { |
||||||
|
runCapture(); |
||||||
|
} else if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED |
||||||
|
|| afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) { |
||||||
|
// CONTROL_AE_STATE can be null on some devices
|
||||||
|
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); |
||||||
|
if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) { |
||||||
|
mState = STATE_WAITING_CAPTURE; |
||||||
|
runCapture(); |
||||||
|
} else { |
||||||
|
runPrecapture(); |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
case STATE_WAITING_PRECAPTURE_START: { |
||||||
|
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); |
||||||
|
if (aeState == null || |
||||||
|
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE || |
||||||
|
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) { |
||||||
|
mState = STATE_WAITING_PRECAPTURE_END; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
case STATE_WAITING_PRECAPTURE_END: { |
||||||
|
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); |
||||||
|
if (aeState == null |
||||||
|
|| aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) { |
||||||
|
mState = STATE_WAITING_CAPTURE; |
||||||
|
runCapture(); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
case STATE_WAITING_CAPTURE: { |
||||||
|
if (result instanceof TotalCaptureResult |
||||||
|
&& result.getRequest().getTag() == (Integer) CameraDevice.TEMPLATE_STILL_CAPTURE) { |
||||||
|
mState = STATE_WAITING_IMAGE; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void dispatchResult() { |
||||||
|
mState = STATE_IDLE; |
||||||
|
super.dispatchResult(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue