標籤: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)
主要步驟:
- 獲得網路攝影機管理器CameraManager mCameraManager,mCameraManager.openCamera()來開啟網路攝影機
- 指定要開啟的網路攝影機,並建立openCamera()所需要的CameraDevice.StateCallback stateCallback
- 在CameraDevice.StateCallback stateCallback中調用takePreview(),這個方法中,使用CaptureRequest.Builder建立預覽需要的CameraRequest,並初始化了CameraCaptureSession,最後調用了setRepeatingRequest(previewRequest, null, childHandler)進行了預覽
- 點擊拍照按鈕,調用takePicture(),這個方法內,最終調用了capture(mCaptureRequest, null, childHandler)
- 在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