Android Camera2拍照(一)——使用SurfaceView

Camera2 API簡介

Android 從5.0(21)開始,引入了新的Camera API Camera2,原來的android.hardware.Camera被廢棄(下面稱爲Camera1),還有一個android.graphics.Camera,這個android.graphics.Camera不是用來照相的,是用來處理圖像的,可以做出3D的圖像效果之類的,之前的Camera1則由android.hardware.Camera代替。Camera2支持RAW輸出,可以調節曝光,對焦模式,快門等,功能比原先Camera強大。

這裏引用了管道的概念將安卓設備和攝像頭之間聯通起來,系統向攝像頭髮送 Capture 請求,而攝像頭會返回 CameraMetadata。這一切建立在一個叫作 CameraCaptureSession 的會話中。

  • CameraManaer 攝像頭管理器,用於檢測攝像頭,打開系統攝像頭,調用CameraManager.getCameraCharacteristics(String)可以獲取指定攝像頭的相關特性
  • CameraCharacteristics 攝像頭的特性
  • CameraDevice 攝像頭,類似android.hardware.Camera也就是Camera1的Camera
  • CameraCaptureSession 這個類控制攝像頭的預覽或者拍照,setRepeatingRequest()開啓預覽,capture()拍照,CameraCaptureSession提供了StateCallback、CaptureCallback兩個接口來監聽CameraCaptureSession的創建和拍照過程。
  • CameraRequest和CameraRequest.Builder,預覽或者拍照時,都需要一個CameraRequest對象。CameraRequest表示一次捕獲請求,用來對照片的各種參數設置,比如對焦模式、曝光模式等。CameraRequest.Builder用來生成CameraRequest對象。

Camera2的簡單使用(使用SurfaceView)

主要步驟:

  1. 獲得攝像頭管理器CameraManager mCameraManager,mCameraManager.openCamera()來打開攝像頭
  2. 指定要打開的攝像頭,並創建openCamera()所需要的CameraDevice.StateCallback stateCallback
  3. 在CameraDevice.StateCallback stateCallback中調用takePreview(),這個方法中,使用CaptureRequest.Builder創建預覽需要的CameraRequest,並初始化了CameraCaptureSession,最後調用了setRepeatingRequest(previewRequest, null, childHandler)進行了預覽
  4. 點擊拍照按鈕,調用takePicture(),這個方法內,最終調用了capture(mCaptureRequest, null, childHandler)
  5. 在new ImageReader.OnImageAvailableListener(){}回調方法中,將拍照拿到的圖片進行展示

package org.hunter.a361camera.view;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
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.CaptureRequest;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;

import org.hunter.a361camera.R;

import java.nio.ByteBuffer;
import java.util.Arrays;

import static android.os.Looper.getMainLooper;

/**
 * Main UI for the statistics screen.
 */
public class CameraFragment extends Fragment {
    public static final int REQUEST_CAMERA_CODE = 100;
    public static final String PACKAGE = "package:";

    private 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 SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private ImageView iv_show;
    private ImageView mCatture;
    private CameraManager mCameraManager;//攝像頭管理器
    private Handler childHandler, mainHandler;
    private String mCameraID;//攝像頭Id 0 爲後  1 爲前
    private ImageReader mImageReader;
    private CameraCaptureSession mCameraCaptureSession;
    private CameraDevice mCameraDevice;
    /**
     * 攝像頭創建監聽
     */
    private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice camera) {//打開攝像頭
            mCameraDevice = camera;
            //開啓預覽
            takePreview();
        }

        @Override
        public void onDisconnected(CameraDevice camera) {//關閉攝像頭
            if (null != mCameraDevice) {
                mCameraDevice.close();
                CameraFragment.this.mCameraDevice = null;
            }
        }

        @Override
        public void onError(CameraDevice camera, int error) {//發生錯誤
            Toast.makeText(getContext(), "攝像頭開啓失敗", Toast.LENGTH_SHORT).show();
        }
    };

    public static CameraFragment newInstance() {
        return new CameraFragment();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.camera_frag, container, false);
        initVIew(root);
        initListener();
        return root;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    /**
     * 初始化
     */
    private void initVIew(View root) {
        iv_show = (ImageView) root.findViewById(R.id.iv_show_camera2);
        //mSurfaceView
        mSurfaceView = (SurfaceView) root.findViewById(R.id.surface_view_camera2);
        mCatture = (ImageView) root.findViewById(R.id.capture);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.setKeepScreenOn(true);
        // mSurfaceView添加回調
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) { //SurfaceView創建
                // 初始化Camera
                initCamera2();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView銷燬
                // 釋放Camera資源
                if (null != mCameraDevice) {
                    mCameraDevice.close();
                    CameraFragment.this.mCameraDevice = null;
                }
            }
        });
    }

    /**
     * 初始化Camera2
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void initCamera2() {
        HandlerThread handlerThread = new HandlerThread("Camera2");
        handlerThread.start();
        childHandler = new Handler(handlerThread.getLooper());
        mainHandler = new Handler(getMainLooper());
        mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//後攝像頭
        mImageReader = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG, 1);
        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在這裏處理拍照得到的臨時照片 例如,寫入本地
            @Override
            public void onImageAvailable(ImageReader reader) {
                //mCameraDevice.close();
                // 拿到拍照照片數據
                Image image = reader.acquireNextImage();
                ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                byte[] bytes = new byte[buffer.remaining()];
                buffer.get(bytes);//由緩衝區存入字節數組
                final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                if (bitmap != null) {
                    iv_show.setImageBitmap(bitmap);
                }
            }
        }, mainHandler);
        //獲取攝像頭管理
        mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
        try {
            if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                //申請WRITE_EXTERNAL_STORAGE權限
                requestPermissions(new String[]{Manifest.permission.CAMERA},
                        REQUEST_CAMERA_CODE);
                //return;
            } else {
                //打開攝像頭
                mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_CODE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission Granted
                try {
                    mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                } catch (SecurityException e) {
                    e.printStackTrace();
                }
            } else {
                // Permission Denied
            }
        }
    }

    /**
     * 開始預覽
     */
    private void takePreview() {
        try {
            // 創建預覽需要的CaptureRequest.Builder
            final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 將SurfaceView的surface作爲CaptureRequest.Builder的目標
            previewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
            // 創建CameraCaptureSession,該對象負責管理處理預覽請求和拍照請求
            mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() // ③
            {
                @Override
                public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                    if (null == mCameraDevice) return;
                    // 當攝像頭已經準備好時,開始顯示預覽
                    mCameraCaptureSession = cameraCaptureSession;
                    try {
                        // 自動對焦
                        previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                        // 打開閃光燈
                        previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                        // 顯示預覽
                        CaptureRequest previewRequest = previewRequestBuilder.build();
                        mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                    Toast.makeText(getContext(), "配置失敗", Toast.LENGTH_SHORT).show();
                }
            }, childHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 拍照
     */
    private void takePicture() {
        if (mCameraDevice == null) return;
        // 創建拍照需要的CaptureRequest.Builder
        final CaptureRequest.Builder captureRequestBuilder;
        try {
            captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            // 將imageReader的surface作爲CaptureRequest.Builder的目標
            captureRequestBuilder.addTarget(mImageReader.getSurface());
            // 自動對焦
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            // 自動曝光
            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            // 獲取手機方向
            int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
            // 根據設備方向計算設置照片的方向
            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
            //拍照
            CaptureRequest mCaptureRequest = captureRequestBuilder.build();
            mCameraCaptureSession.capture(mCaptureRequest, null, childHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void initListener() {
        mCatture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePicture();
            }
        });
    }
}

佈局文件:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <SurfaceView
        android:id="@+id/surface_view_camera2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <org.hunter.a361camera.widget.PorterDuffViewImageView
        android:id="@+id/capture"
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="20dp"
        android:src="@mipmap/capture"/>

    <org.hunter.a361camera.widget.PorterDuffViewImageView
        android:id="@+id/iv_show_camera2"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="20dp"
        android:layout_marginRight="20dp"
        android:scaleType="centerCrop"/>
</RelativeLayout>
源代碼地址:https://github.com/gengqifu/361Camera。歡迎fork/star


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章