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