package com.yydcdut.note.model.camera.impl2; import android.Manifest; import android.annotation.TargetApi; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; 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.support.v4.app.ActivityCompat; import android.view.Surface; import android.view.SurfaceHolder; import com.yydcdut.note.model.camera.ICameraFocus; import com.yydcdut.note.model.camera.ICameraModel; import com.yydcdut.note.model.camera.ICaptureModel; import com.yydcdut.note.model.camera.IPreviewModel; import com.yydcdut.note.model.compare.SizeComparator; import com.yydcdut.note.utils.YLog; import com.yydcdut.note.utils.camera.param.Size; import com.yydcdut.note.widget.camera.AutoFitPreviewView; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Created by yuyidong on 16/2/3. */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class Camera2ModelImpl implements ICameraModel, Camera2SettingModel.OnParameterChangedListener, Camera2FocusModel.OnParameterChangedListener { private static final String TAG = Camera2ModelImpl.class.getSimpleName(); private Context mContext; private CameraManager mCameraManager; private CameraDevice mCameraDevice; private AutoFitPreviewView.PreviewSurface mPreviewSurface; private static final int STATE_CAMERA_CLOSE = 0; private static final int STATE_CAMERA_OPEN = 1; private static final int STATE_CAMERA_PREVIEW = 2; private static final int STATE_CAMERA_CAPTURE = 3; private int mCameraState = STATE_CAMERA_CLOSE; private Camera2SettingModel mCamera2SettingModel; private Camera2FocusModel mCamera2FocusModel; private Camera2PreviewModel mCamera2PreviewModel; private Camera2CaptureModel mCamera2CaptureModel; private ImageReader mJpgImageReader; private PictureCallback mJpegPictureCallback; private ImageReader mYuvImageReader; private PicturesPreviewCallback mPicturesPreviewCallback; private CaptureRequest.Builder mPreviewRequestBuilder; private CameraCaptureSession mSession; public Camera2ModelImpl(Context context) { mContext = context; } @Override public void openCamera(String id, OnCameraOpenedCallback callback, int orientation, Size pictureSize) { if (mCameraState != STATE_CAMERA_CLOSE) { return; } if (callback == null) { throw new IllegalArgumentException(""); } if (mCameraManager == null) { mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); } try { if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. // return null; YLog.i("yuyidong", "no permission"); } mCameraManager.openCamera(id, new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { mCameraState = STATE_CAMERA_OPEN; mCameraDevice = camera; mCamera2PreviewModel = new Camera2PreviewModel(); try { mCamera2SettingModel = new Camera2SettingModel(mCameraManager.getCameraCharacteristics(id), mCameraManager.getCameraIdList().length); mCamera2SettingModel.setOnParameterChangedListener(Camera2ModelImpl.this); Size picSize = null; if (pictureSize == null) { List<Size> list = mCamera2SettingModel.getSupportPictureSizes(); Collections.sort(list, new SizeComparator()); picSize = list.get(list.size() - 1); } else { picSize = pictureSize; } mJpgImageReader = ImageReader.newInstance(picSize.getWidth(), picSize.getHeight(), ImageFormat.JPEG, 2); mJpegPictureCallback = new PictureCallback(); mJpgImageReader.setOnImageAvailableListener(mJpegPictureCallback, null); } catch (CameraAccessException e) { YLog.e(e); } callback.onOpen(mCamera2PreviewModel, mCamera2SettingModel); } @Override public void onDisconnected(CameraDevice camera) { mCameraState = STATE_CAMERA_CLOSE; camera.close(); mCameraDevice = null; } @Override public void onError(CameraDevice camera, int error) { mCameraState = STATE_CAMERA_CLOSE; camera.close(); mCameraDevice = null; callback.onError(); } }, null); } catch (CameraAccessException e) { YLog.e(e); callback.onError(); } } private Surface getSurface(Size previewSize) { SurfaceTexture surfaceTexture = mPreviewSurface.getSurfaceTexture(); SurfaceHolder surfaceHolder = mPreviewSurface.getSurfaceHolder(); Surface surface = null; if (surfaceTexture != null) { if (previewSize != null) { surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); } surface = new Surface(surfaceTexture); } else { if (previewSize != null) { surfaceHolder.setFixedSize(previewSize.getWidth(), previewSize.getHeight()); } surface = surfaceHolder.getSurface(); } return surface; } private Size getYuvSize(Size previewSize) { List<Size> sizeList = mCamera2SettingModel.getSupportYUV420888Sizes(); Size returnSize = null; for (Size size : sizeList) { if (size.equals(previewSize)) { returnSize = previewSize; break; } } if (returnSize == null) { for (Size size : sizeList) { if (size.getWidth() == previewSize.getWidth()) { returnSize = previewSize; break; } if (size.getHeight() == previewSize.getHeight()) { returnSize = previewSize; break; } } } if (returnSize == null) { returnSize = sizeList.get(sizeList.size() / 2); } return returnSize; } @Override public void onChanged(CaptureRequest.Builder builder) { if (mCameraDevice != null && mSession != null && builder != null) { try { mSession.setRepeatingRequest(builder.build(), mCameraCaptureSessionCaptureCallback4Preview, null); } catch (CameraAccessException e) { YLog.e(e); } } } public class Camera2PreviewModel implements IPreviewModel { @Override public void startPreview(AutoFitPreviewView.PreviewSurface previewSurface, OnCameraPreviewCallback callback, Size previewSize) { mPreviewSurface = previewSurface; boolean success = true; Surface surface = getSurface(previewSize); try { Size yuvSize = getYuvSize(previewSize); mYuvImageReader = ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(), ImageFormat.YUV_420_888, 10); mPicturesPreviewCallback = new PicturesPreviewCallback(); mYuvImageReader.setOnImageAvailableListener(mPicturesPreviewCallback, null); mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewRequestBuilder.addTarget(surface); mCamera2SettingModel.setCaptureRequestBuilder(mPreviewRequestBuilder); mCameraDevice.createCaptureSession(Arrays.asList(surface, mJpgImageReader.getSurface(), mYuvImageReader.getSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { if (null == mCameraDevice) { return; } mSession = session; try { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); CaptureRequest previewRequest = mPreviewRequestBuilder.build(); mSession.setRepeatingRequest(previewRequest, mCameraCaptureSessionCaptureCallback4Preview, null); mCameraState = STATE_CAMERA_PREVIEW; } catch (CameraAccessException e) { YLog.e(e); } mCamera2FocusModel = new Camera2FocusModel(mCamera2SettingModel.isFocusSupported(), mPreviewRequestBuilder, mCamera2SettingModel.getActiveArraySize()); mCamera2FocusModel.setOnParameterChangedListener(Camera2ModelImpl.this); mCamera2CaptureModel = new Camera2CaptureModel(); callback.onPreview(mCamera2CaptureModel, mCamera2FocusModel); } @Override public void onConfigureFailed(CameraCaptureSession session) { callback.onPreviewError(); } }, null); } catch (CameraAccessException e) { YLog.e(e); success = false; } if (!success) { callback.onPreviewError(); } } @Override public void continuePreview() { if (mSession != null && mCameraState == STATE_CAMERA_CAPTURE) { try { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); CaptureRequest previewRequest = mPreviewRequestBuilder.build(); mSession.setRepeatingRequest(previewRequest, mCameraCaptureSessionCaptureCallback4Preview, null); mCameraState = STATE_CAMERA_PREVIEW; } catch (CameraAccessException e) { YLog.e(e); } } } @Override public void stopPreview() { if (mSession != null) { try { mSession.stopRepeating(); mCameraState = STATE_CAMERA_OPEN; } catch (CameraAccessException e) { YLog.e(e); } } } @Override public boolean isPreview() { return mCameraState == STATE_CAMERA_PREVIEW; } } private CameraCaptureSession.CaptureCallback mCameraCaptureSessionCaptureCallback4Preview = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) { super.onCaptureProgressed(session, request, partialResult); mCamera2FocusModel.onCaptureProgressed(request, partialResult); } @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); mCamera2FocusModel.onCaptureCompleted(request, result); } }; public class Camera2CaptureModel implements ICaptureModel { @Override public long capture(PictureReturnCallback pictureReturnCallback) { long time = 0l; if (mCamera2FocusModel != null && mCamera2FocusModel.getFocusState() != ICameraFocus.FOCUS_STATE_FOCUSING && mCameraState == STATE_CAMERA_PREVIEW && pictureReturnCallback != null) { time = System.currentTimeMillis(); if (mJpegPictureCallback.pictureReturnCallback == null || mJpegPictureCallback.pictureReturnCallback != pictureReturnCallback) { mJpegPictureCallback.pictureReturnCallback = pictureReturnCallback; } mJpegPictureCallback.time = time; CaptureRequest.Builder captureBuilder; try { captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(mJpgImageReader.getSurface()); captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // // Orientation // int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); // captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); mSession.stopRepeating(); mSession.capture(captureBuilder.build(), mCameraCaptureSessionCaptureCallback4Capture, null); } catch (CameraAccessException e) { YLog.e(e); } } return time; } @Override public void startStillCapture(StillPictureReturnCallback stillPictureReturnCallback) { // if (mCamera2FocusModel != null && mCamera2FocusModel.getFocusState() != ICameraFocus.FOCUS_STATE_FOCUSING // && mCameraState == STATE_CAMERA_PREVIEW) { // if (mPicturesPreviewCallback == null) { // mPicturesPreviewCallback = new PicturesPreviewCallback(); // mPicturesPreviewCallback.stillPictureReturnCallback = stillPictureReturnCallback; // } else { // if (mPicturesPreviewCallback.stillPictureReturnCallback != stillPictureReturnCallback) { // mPicturesPreviewCallback.stillPictureReturnCallback = stillPictureReturnCallback; // } // } // CaptureRequest.Builder stillCaptureBuilder; // try { // stillCaptureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); // stillCaptureBuilder.addTarget(mYuvImageReader.getSurface()); //// Surface surface = getSurface(null); //// stillCaptureBuilder.addTarget(surface); // mSession.stopRepeating(); // mSession.setRepeatingRequest(stillCaptureBuilder.build(), null, null); // } catch (CameraAccessException e) { // e.printStackTrace(); // } // } else { // YLog.i(TAG, "capture focusState--->" + mCamera2FocusModel.getFocusState() + " CameraState--->" + mCameraState); // } } @Override public void stopStillCapture() { // try { // mSession.stopRepeating(); // mSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCameraCaptureSessionCaptureCallback4Preview, null); // } catch (CameraAccessException e) { // e.printStackTrace(); // } } private CameraCaptureSession.CaptureCallback mCameraCaptureSessionCaptureCallback4Capture = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) { super.onCaptureStarted(session, request, timestamp, frameNumber); mCameraState = STATE_CAMERA_CAPTURE; } @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); } }; } class PictureCallback implements ImageReader.OnImageAvailableListener { private long time; private ICaptureModel.PictureReturnCallback pictureReturnCallback; @Override public void onImageAvailable(ImageReader reader) { if (pictureReturnCallback != null) { Image image = reader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); pictureReturnCallback.onPictureTaken(true, bytes, time); image.close(); } } } class PicturesPreviewCallback implements ImageReader.OnImageAvailableListener { private ICaptureModel.StillPictureReturnCallback stillPictureReturnCallback; @Override public void onImageAvailable(ImageReader reader) { if (stillPictureReturnCallback != null) { Image image = reader.acquireNextImage(); stillPictureReturnCallback.onStillPictureTaken(ImageFormat.NV21, convertYUV420ToN21(image), System.currentTimeMillis(), reader.getWidth(), reader.getHeight()); image.close(); } } } private byte[] convertYUV420ToN21(Image imgYUV420) { byte[] rez = new byte[0]; ByteBuffer buffer0 = imgYUV420.getPlanes()[0].getBuffer(); ByteBuffer buffer2 = imgYUV420.getPlanes()[2].getBuffer(); int buffer0_size = buffer0.remaining(); int buffer2_size = buffer2.remaining(); rez = new byte[buffer0_size + buffer2_size]; buffer0.get(rez, 0, buffer0_size); buffer2.get(rez, buffer0_size, buffer2_size); return rez; } @Override public void closeCamera() { if (null != mSession) { mSession.close(); mSession = null; } if (null != mCameraDevice) { mCameraDevice.close(); mCameraDevice = null; } mCameraManager = null; mCameraState = STATE_CAMERA_CLOSE; if (null != mJpgImageReader) { mJpgImageReader.close(); mJpgImageReader = null; } } @Override public boolean isOpen() { return mCameraState == STATE_CAMERA_OPEN; } @Override public int getCameraNumber(Context context) { int number = 0; try { number = ((CameraManager) context.getSystemService(Context.CAMERA_SERVICE)).getCameraIdList().length; } catch (CameraAccessException e) { YLog.e(e); } return number; } }