1. 程式人生 > >android 5.0以上相機模組 照相

android 5.0以上相機模組 照相

package com.example.lxb.camerademo;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import 
android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageReader; import android.media.MediaRecorder;
import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.PersistableBundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.util.Size; import android.util.SparseIntArray; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; /** * Created by lxb on 2017/5/3. */ public class VideoActivity extends Activity { private MediaRecorder mMediaRecorder; private ImageReader mImageReader; private boolean isOpened; private TextureView textureView; private Size imageDimension; private CameraDevice mCameraDevice; private Semaphore mCameraOpenCloseLock = new Semaphore(1); private Handler mBackgroundHandler; private HandlerThread mBackgroundThread; private CameraCaptureSession mCaptureSession; private CaptureRequest mPreviewRequest; private boolean mFlashSupported; private String cameraId; private static final int STATE_PREVIEW = 0; private static final int STATE_WAITING_LOCK = 1; private static final int STATE_WAITING_PRECAPTURE = 2; private static final int STATE_WAITING_NON_PRECAPTURE = 3; private static final int STATE_PICTURE_TAKEN = 4; private int mState = STATE_PREVIEW; private int mSensorOrientation; private CaptureRequest.Builder mPreviewRequestBuilder; static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } private int nOperation = -1; //1 拍照 2:錄影 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_video_layout); initView(); nOperation = getIntent().getIntExtra("type",1); } private void initView() { textureView = (TextureView) findViewById(R.id.texture_video_preview); Button photo = (Button) findViewById(R.id.photo); photo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { takePicture(); } }); } /** * 實時預覽監聽器 */ TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() { public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) { openCamera(); } public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) { configureTransform(width, height); } public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) { return true; } public void onSurfaceTextureUpdated(SurfaceTexture texture) { } }; /** * texture size發生改變時重新配置 * * @param viewWidth * @param viewHeight */ private void configureTransform(int viewWidth, int viewHeight) { if (null == textureView || null == imageDimension) return; int rotation = getWindowManager().getDefaultDisplay().getRotation(); Matrix matrix = new Matrix(); RectF viewRect = new RectF(0, 0, viewWidth, viewHeight); RectF bufferRect = new RectF(0, 0, imageDimension.getHeight(), imageDimension.getWidth()); float centerX = viewRect.centerX(); float centerY = viewRect.centerY(); if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) { bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY()); matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL); float scale = Math.max((float) viewHeight / imageDimension.getHeight(), (float) viewWidth / imageDimension.getWidth()); matrix.postScale(scale, scale, centerX, centerY); matrix.postRotate(90 * (rotation - 2), centerX, centerY); } else if (Surface.ROTATION_180 == rotation) { matrix.postRotate(180, centerX, centerY); } textureView.setTransform(matrix); } private void startBackgroundThread() { mBackgroundThread = new HandlerThread("CameraBackground"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); } private void stopBackgroundThread() { mBackgroundThread.quitSafely(); try { mBackgroundThread.join(); mBackgroundThread = null; mBackgroundHandler = null; } catch (Exception e) { e.printStackTrace(); } } private void openCamera() { if (isOpened) { return; } try { if (!mCameraOpenCloseLock.tryAcquire(4, TimeUnit.SECONDS)) throw new RuntimeException("Time out waiting to lock camera opening."); } catch (InterruptedException e) { e.printStackTrace(); } isOpened = true; CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { cameraId = manager.getCameraIdList()[0];//這個可能會有很多個,但是通常都是兩個,第一個是後置,第二個是前置; CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); assert map != null; imageDimension = map.getOutputSizes(SurfaceTexture.class)[0]; if (ActivityCompat.checkSelfPermission(this, 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; } manager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(final CameraDevice camera) { mCameraDevice = camera; createCameraPreview(camera); } @Override public void onDisconnected(CameraDevice camera) { camera.close(); mCameraDevice = null; } @Override public void onError(CameraDevice camera, int error) { camera.close(); mCameraDevice = null; } }, mBackgroundHandler); //這個指定其後臺執行,如果直接UI執行緒也可以,直接填null} catch (CameraAccessException e) { e.printStackTrace(); } } protected void createCameraPreview(final CameraDevice cameraDevice) { try { if (null == cameraDevice) { return; } final CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); SurfaceTexture texture = textureView.getSurfaceTexture(); texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight()); Surface textureSurface = new Surface(texture); captureRequestBuilder.addTarget(textureSurface); switch(nOperation){ case 1: setUpImageReader(); Surface imageSurface = mImageReader.getSurface(); captureRequestBuilder.addTarget(imageSurface); List<Surface> surfaceList = Arrays.asList(textureSurface, imageSurface); createPhotoView(cameraDevice, surfaceList, captureRequestBuilder); break; case 2: setUpMediaRecorder(); Surface recorderSurface = mMediaRecorder.getSurface(); captureRequestBuilder.addTarget(recorderSurface); List<Surface> surfaceList2 = Arrays.asList(textureSurface, recorderSurface); createVideoView(cameraDevice,surfaceList2,captureRequestBuilder); break; } /*List<Surface> surfaceList = Arrays.asList(textureSurface, recorderSurface); cameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {//配置要接受影象的surface @Override public void onConfigured(CameraCaptureSession cameraCaptureSession) { captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); try { cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);//成功配置後,便開始進行相機影象的監聽 } catch (CameraAccessException e) { e.printStackTrace(); } mMediaRecorder.start(); } @Override public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) { } }, null);*/ } catch (CameraAccessException e) { e.printStackTrace(); } } /** * 建立錄影檢視 * * @param cameraDevice * @param surfaceList * @param captureRequestBuilder */ private void createVideoView(final CameraDevice cameraDevice, List<Surface> surfaceList, final CaptureRequest.Builder captureRequestBuilder) { try { cameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {//配置要接受影象的surface @Override public void onConfigured(CameraCaptureSession cameraCaptureSession) { captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); try { cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);//成功配置後,便開始進行相機影象的監聽 } catch (CameraAccessException e) { e.printStackTrace(); } mMediaRecorder.start(); } @Override public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) { } }, null); } catch (CameraAccessException e) { e.printStackTrace(); } } /** * 初始化媒體類 */ private void setUpMediaRecorder() { mMediaRecorder = new MediaRecorder(); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); mMediaRecorder.setMaxFileSize(0); mMediaRecorder.setOrientationHint(0); mMediaRecorder.setOutputFile(CommonUtils.createFile(CommonUtils.getCurTime() + ".mp4").getAbsolutePath()); try { mMediaRecorder.prepare(); } catch (IOException e) { e.printStackTrace(); } } /** * 建立拍照檢視 * * @param cameraDevice * @param surface * @param captureRequestBuilder */ private void createPhotoView(final CameraDevice cameraDevice, List<Surface> surface, final CaptureRequest.Builder captureRequestBuilder) { try { mPreviewRequestBuilder = captureRequestBuilder; mCameraDevice.createCaptureSession(surface, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { if (null == mCameraDevice) return; mCaptureSession = cameraCaptureSession; try { captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); setAutoFlash(captureRequestBuilder); mPreviewRequest = captureRequestBuilder.build(); mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler); } catch (Exception e) { e.printStackTrace(); Toast.makeText(AppContext.sApp, "開啟相機預覽失敗,再試一次吧", Toast.LENGTH_LONG).show(); // mFinishCalled = true; finish(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { Toast.makeText(AppContext.sApp, "開啟相機預覽失敗,再試一次吧", Toast.LENGTH_LONG).show(); //mFinishCalled = true; finish(); } }, null); } catch (CameraAccessException e) { e.printStackTrace(); } } /** * 拍照的所需的物件資源 */ private void setUpImageReader() { mImageReader = ImageReader.newInstance(imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.YUV_420_888, 10); mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Image image = reader.acquireLatestImage(); if (image != null) { image.close(); } } }, mBackgroundHandler); } /** * 設定閃光燈 * * @param requestBuilder */ private void setAutoFlash(CaptureRequest.Builder requestBuilder) { try { CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); mFlashSupported = available == null ? false : available; /** * 若相機支援自動開啟/關閉閃光燈,則使用. 否則閃光燈總是關閉的. */ if (mFlashSupported) requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); } catch (CameraAccessException e) { e.printStackTrace(); } } /** * 拍照的回撥 */ CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { process(partialResult); } @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { process(result); } }; /** * 處理拍照的過程 * * @param result */ private void process(CaptureResult result) { switch (mState) { case STATE_PREVIEW: { // We have nothing to do when the camera preview is working normally. break; } case STATE_WAITING_LOCK: { Integer afState = result.get(CaptureResult.CONTROL_AF_STATE); /** * 判斷可以立即拍攝的autoFocusState增加到4. */ if (afState == null) { captureStillPicture(); } else if (CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED == afState || CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) { // CONTROL_AE_STATE can be null on some devices Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); /** * 判斷可以立即拍攝的autoExposureState增加到4. */ if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED || aeState == CaptureResult.CONTROL_AE_STATE_LOCKED || aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED) { mState = STATE_PICTURE_TAKEN; captureStillPicture(); } else { runPrecaptureSequence(); } } break; } case STATE_WAITING_PRECAPTURE: { // 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_PRECAPTURE || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) { mState = STATE_WAITING_NON_PRECAPTURE; } break; } case STATE_WAITING_NON_PRECAPTURE: { // 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_PRECAPTURE) { mState = STATE_PICTURE_TAKEN; captureStillPicture(); } break; } } } /** * 捕獲圖片 */ private void captureStillPicture() { try { if (null == mCameraDevice) return; // This is the CaptureRequest.Builder that we use to take a picture. final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(mImageReader.getSurface()); // Use the same AE and AF modes as the preview. captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); setAutoFlash(captureBuilder); // Orientation int rotation = getWindowManager().getDefaultDisplay().getRotation(); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation)); CameraCaptureSession.CaptureCallback CaptureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { System.out.println("757----------------filepath:"); unlockFocus(); } }; mCaptureSession.stopRepeating(); mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null); } catch (Exception e) { e.printStackTrace(); } } private void runPrecaptureSequence() { try { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); mState = STATE_WAITING_PRECAPTURE; mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler); } catch (Exception e) { e.printStackTrace(); } } private int getOrientation(int rotation) { return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360; } /** * 開始拍照 */ private void takePicture() { try { // This is how to tell the camera to lock focus. mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); // Tell #mCaptureCallback to wait for the lock. mState = STATE_WAITING_LOCK; mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler); } catch (Exception e) { e.printStackTrace(); } } /** * 釋放照相機 */ private void unlockFocus() { try { // Reset the auto-focus trigger mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); setAutoFlash(mPreviewRequestBuilder); mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler); // After this, the camera will go back to the normal state of preview. mState = STATE_PREVIEW; mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler); } catch (Exception e) { e.printStackTrace(); } } @Override public void onResume() { super.onResume(); startBackgroundThread(); if (textureView.isAvailable()) { openCamera(); } else { textureView.setSurfaceTextureListener(mSurfaceTextureListener); } } @Override protected void onPause() { super.onPause(); releaseRes(); stopBackgroundThread(); finish(); } @Override protected void onDestroy() { super.onDestroy(); } private void releaseRes() { try { if (mCameraDevice != null) { mCameraDevice.close(); mCameraDevice = null; } if (mMediaRecorder != null) { mMediaRecorder.stop(); mMediaRecorder.reset(); mMediaRecorder.release(); mMediaRecorder = null; } } catch (Exception e) { e.printStackTrace(); } } }

佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
    <TextureView
android:id="@+id/texture_video_preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!--<ImageView
        android:id="@+id/iv_video_button"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_gravity="center_horizontal|bottom"
        android:layout_marginBottom="40dp"
        android:src="@drawable/selector" />-->
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="trigger"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="40dp"
android:text="stop"/>
    <Button
android:id="@+id/photo"
android<