国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android Camera2 實(shí)現(xiàn)預(yù)覽功能

2019-10-21 21:35:41
字體:
供稿:網(wǎng)友

1. 概述

最近在做一些關(guān)于人臉識(shí)別的項(xiàng)目,需要用到 Android 相機(jī)的預(yù)覽功能。網(wǎng)上查閱相關(guān)資料后,發(fā)現(xiàn) Android 5.0 及以后的版本中,原有的 Camera API 已經(jīng)被 Camera2 API 所取代。

全新的 Camera2 在 Camera 的基礎(chǔ)上進(jìn)行了改造,大幅提升了 Android 系統(tǒng)的拍照功能。它通過以下幾個(gè)類與方法來實(shí)現(xiàn)相機(jī)預(yù)覽時(shí)的工作過程:

•CameraManager :攝像頭管理器,主要用于檢測系統(tǒng)攝像頭、打開系統(tǒng)攝像頭等;
•CameraDevice : 用于描述系統(tǒng)攝像頭,可用于關(guān)閉相機(jī)、創(chuàng)建相機(jī)會(huì)話、發(fā)送拍照請求等;
•CameraCharacteristics :用于描述攝像頭所支持的各種特性;
•CameraCaptureSession :當(dāng)程序需要預(yù)覽、拍照時(shí),都需要先通過 CameraCaptureSession 來實(shí)現(xiàn)。該會(huì)話通過調(diào)用方法 setRepeatingRequest() 實(shí)現(xiàn)預(yù)覽;
•CameraRequest :代表一次捕獲請求,用于描述捕獲圖片的各種參數(shù)設(shè)置;
•CameraRequest.Builder :負(fù)責(zé)生成 CameraRequest 對象。

2. 相機(jī)預(yù)覽

下面通過源碼來講解如何使用 Camera2 來實(shí)現(xiàn)相機(jī)的預(yù)覽功能。

2.1 相機(jī)權(quán)限設(shè)置

<uses-permission android:name="android.permission.CAMERA" />

2.2 App 布局

•activity_main.xml

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000" tools:context=".MainActivity"></FrameLayout>•fragment_camera.xml<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".CameraFragment"> <com.lightweh.camera2preview.AutoFitTextureView android:id="@+id/textureView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /></RelativeLayout>

2.3 相機(jī)自定義View

public class AutoFitTextureView extends TextureView { private int mRatioWidth = 0; private int mRatioHeight = 0; public AutoFitTextureView(Context context) { this(context, null); } public AutoFitTextureView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setAspectRatio(int width, int height) { if (width < 0 || height < 0) { throw new IllegalArgumentException("Size cannot be negative."); } mRatioWidth = width; mRatioHeight = height; requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (0 == mRatioWidth || 0 == mRatioHeight) { setMeasuredDimension(width, height); } else { if (width < height * mRatioWidth / mRatioHeight) { setMeasuredDimension(width, width * mRatioHeight / mRatioWidth); } else { setMeasuredDimension(height * mRatioWidth / mRatioHeight, height); } } }}

2.4 動(dòng)態(tài)申請相機(jī)權(quán)限

public class MainActivity extends AppCompatActivity { private static final int REQUEST_PERMISSION = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (hasPermission()) { if (null == savedInstanceState) { setFragment(); } } else { requestPermission(); } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { if (requestCode == REQUEST_PERMISSION) { if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { setFragment(); } else { requestPermission(); } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } // 權(quán)限判斷,當(dāng)系統(tǒng)版本大于23時(shí),才有必要判斷是否獲取權(quán)限 private boolean hasPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; } else { return true; } } // 請求相機(jī)權(quán)限 private void requestPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { Toast.makeText(MainActivity.this, "Camera permission are required for this demo", Toast.LENGTH_LONG).show(); } requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_PERMISSION); } } // 啟動(dòng)相機(jī)Fragment private void setFragment() { getSupportFragmentManager() .beginTransaction() .replace(R.id.container, CameraFragment.newInstance()) .commitNowAllowingStateLoss(); }}

2.5 開啟相機(jī)預(yù)覽

首先,在onResume()中,我們需要開啟一個(gè) HandlerThread,然后利用該線程的 Looper 對象構(gòu)建一個(gè) Handler 用于相機(jī)回調(diào)。

@Overridepublic void onResume() { super.onResume(); startBackgroundThread(); // When the screen is turned off and turned back on, the SurfaceTexture is  // already available, and "onSurfaceTextureAvailable" will not be called. In  // that case, we can open a camera and start preview from here (otherwise, we  // wait until the surface is ready in the SurfaceTextureListener). if (mTextureView.isAvailable()) { openCamera(mTextureView.getWidth(), mTextureView.getHeight()); } else { mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); }}private void startBackgroundThread() { mBackgroundThread = new HandlerThread("CameraBackground"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper());}

同時(shí),在 onPause() 中有對應(yīng)的 HandlerThread 關(guān)閉方法。

當(dāng)屏幕關(guān)閉后重新開啟,SurfaceTexture 已經(jīng)就緒,此時(shí)不會(huì)觸發(fā) onSurfaceTextureAvailable 回調(diào)。因此,我們判斷 mTextureView 如果可用,則直接打開相機(jī),否則等待 SurfaceTexture 回調(diào)就緒后再開啟相機(jī)。

private void openCamera(int width, int height) { if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } setUpCameraOutputs(width, height); configureTransform(width, height); Activity activity = getActivity(); CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); try { if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) { throw new RuntimeException("Time out waiting to lock camera opening."); } manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } catch (InterruptedException e) { throw new RuntimeException("Interrupted while trying to lock camera opening.", e); }}

開啟相機(jī)時(shí),我們首先判斷是否具備相機(jī)權(quán)限,然后調(diào)用 setUpCameraOutputs 函數(shù)對相機(jī)參數(shù)進(jìn)行設(shè)置(包括指定攝像頭、相機(jī)預(yù)覽方向以及預(yù)覽尺寸的設(shè)定等),接下來調(diào)用 configureTransform 函數(shù)對預(yù)覽圖片的大小和方向進(jìn)行調(diào)整,最后獲取 CameraManager 對象開啟相機(jī)。因?yàn)橄鄼C(jī)有可能會(huì)被其他進(jìn)程同時(shí)訪問,所以在開啟相機(jī)時(shí)需要加鎖。

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice cameraDevice) { mCameraOpenCloseLock.release(); mCameraDevice = cameraDevice; createCameraPreviewSession(); } @Override public void onDisconnected(@NonNull CameraDevice cameraDevice) { mCameraOpenCloseLock.release(); cameraDevice.close(); mCameraDevice = null; } @Override public void onError(@NonNull CameraDevice cameraDevice, int error) { mCameraOpenCloseLock.release(); cameraDevice.close(); mCameraDevice = null; Activity activity = getActivity(); if (null != activity) { activity.finish(); } }};

相機(jī)開啟時(shí)還會(huì)指定相機(jī)的狀態(tài)變化回調(diào)函數(shù) mStateCallback,如果相機(jī)成功開啟,則開始創(chuàng)建相機(jī)預(yù)覽會(huì)話。

private void createCameraPreviewSession() { try { // 獲取 texture 實(shí)例 SurfaceTexture texture = mTextureView.getSurfaceTexture(); assert texture != null; // 設(shè)置 TextureView 緩沖區(qū)大小 texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); // 獲取 Surface 顯示預(yù)覽數(shù)據(jù) Surface surface = new Surface(texture); // 構(gòu)建適合相機(jī)預(yù)覽的請求 mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); // 設(shè)置 surface 作為預(yù)覽數(shù)據(jù)的顯示界面 mPreviewRequestBuilder.addTarget(surface); // 創(chuàng)建相機(jī)捕獲會(huì)話用于預(yù)覽 mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {  @Override  public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {  // 如果相機(jī)關(guān)閉則返回  if (null == mCameraDevice) {  return;  }  // 如果會(huì)話準(zhǔn)備好則開啟預(yù)覽  mCaptureSession = cameraCaptureSession;  try {  // 自動(dòng)對焦  mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,   CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);  mPreviewRequest = mPreviewRequestBuilder.build();  // 設(shè)置反復(fù)捕獲數(shù)據(jù)的請求,預(yù)覽界面一直顯示畫面  mCaptureSession.setRepeatingRequest(mPreviewRequest,   null, mBackgroundHandler);  } catch (CameraAccessException e) {  e.printStackTrace();  }  }  @Override  public void onConfigureFailed(  @NonNull CameraCaptureSession cameraCaptureSession) {  showToast("Failed");  } }, null ); } catch (CameraAccessException e) { e.printStackTrace(); }}

以上便是 Camera2 API 實(shí)現(xiàn)相機(jī)預(yù)覽的主要過程。

3. Demo 源碼

Github:Camera2Preview

4. 參考

• https://github.com/googlesamples/android-Camera2Basic   

總結(jié)

以上所述是小編給大家介紹的Android Camera2 實(shí)現(xiàn)預(yù)覽功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對VEVB武林網(wǎng)網(wǎng)站的支持!


注:相關(guān)教程知識(shí)閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 台南县| 扎兰屯市| 永城市| 建阳市| 滦平县| 安图县| 二连浩特市| 金昌市| 罗江县| 文化| 织金县| 颍上县| 邵东县| 喜德县| 阿尔山市| 漳平市| 永安市| 长垣县| 郴州市| 奉节县| 博爱县| 日喀则市| 湟源县| 萝北县| 五常市| 波密县| 广西| 邢台市| 株洲市| 沁水县| 开封市| 赫章县| 甘洛县| 秀山| 陇西县| 潞西市| 浮梁县| 隆尧县| 栖霞市| 常德市| 商南县|