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

來源:互聯網
上載者:User

標籤:UI   setimage   apk   map   version   lol   .sh   append   win   

原文: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


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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.