2015/10/14

Android Camera 2

既然學長要我寫我就寫啦
感謝強者我朋友霸氣資訊支援手機一枚XD,不然光搞視訊鏡頭都不知道要搞多久了啊...

Camera2 API在21版本時新增,它能夠利用多線程去接收需求和反應,跟以往的Camera相比效能差了一大截,不過能接影像的僅有SurfaceView和TextureView

下圖是對岸牛人畫的流程圖,個人認為對不管剛入門還是老手都非常易懂的圖啊

首先啟動執行序
設定好Surface
取得及設定CameraID,CameraID為0(CaptureRequest.LENS_FACING_BACK)或1(CaptureRequest.LENS_FACING_FRONT)
設定好ImageReader,ImageReader用於讀取影像資料的類別
接著開啟相機會觸發CameraDevice.StateCallback該事件內會有方法可以知道相機開啟是否正常
正常情況必須建立Session並透過setRepeatingRequest不斷的請求相機傳送影像,並且可以透過CameraCaptureSession.CaptureCallback來得知擷取影像進度及完成時的事件

以上大概是整體的程序,太久沒寫Android有錯請前輩們多多指教





Layout:
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.cyfang.testcamera.MainActivity" >

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true" />

</RelativeLayout>

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



Code:
package com.cyfang.testcamera;

import java.util.Arrays;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
import android.hardware.camera2.CameraCaptureSession.StateCallback;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

@SuppressLint("NewApi")
public class MainActivity extends Activity {
 private SurfaceView surfaceView;
 private SurfaceHolder holder;

 private CameraManager manager;
 private CaptureRequest.Builder builder;
 private CameraDevice cameraDevice;

 private HandlerThread handlerThread;
 private Handler handler;

 private ImageReader imageReader;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
  surfaceView = (SurfaceView) findViewById(R.id.surfaceView);

  // 取得Holder
  holder = surfaceView.getHolder();

  // 設定預覽大小
  holder.setFixedSize(1280, 960);

  // 設定事件
  holder.addCallback(surfaceCallback);
 }

 private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
   if (cameraDevice != null) {
    cameraDevice.close();
   }
  }

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
   handlerThread = new HandlerThread("HT");
   handlerThread.start();
   handler = new Handler(handlerThread.getLooper());

   // 創建影像物件
   imageReader = ImageReader.newInstance(1280, 960, ImageFormat.RGB_565, 3);
   try {

    // 取得相機鏡頭清單,可用於判斷該相機是否具備雙鏡頭或是單鏡頭
    // manager.getCameraIdList()

    // 開啟相機
    // 0是後面鏡頭 = CaptureRequest.LENS_FACING_BACK
    // 1是前置鏡頭 = CaptureRequest.LENS_FACING_FRONT
    manager.openCamera("0", DeviceStateCallback, handler);
   } catch (CameraAccessException e) {
    Log.e("CameraAccessException", e.getMessage());
   }
  }

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

  }
 };

 // 相機裝置狀態
 private CameraDevice.StateCallback DeviceStateCallback = new CameraDevice.StateCallback() {

  @Override
  public void onOpened(CameraDevice camera) {
   try {
    cameraDevice = camera;

    // 設定預覽模式
    builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

    // 將影像設定置SurfaceView
    builder.addTarget(holder.getSurface());

    // 建立影像傳輸
    cameraDevice.createCaptureSession(Arrays.asList(holder.getSurface(), imageReader.getSurface()),
      CameraCaptureCallback, handler);
   } catch (CameraAccessException e) {
    Log.e("CameraAccessException", e.getMessage());
   }
  }

  @Override
  public void onDisconnected(CameraDevice camera) {

  }

  @Override
  public void onError(CameraDevice camera, int error) {

  }
 };

 // 相機擷取中及完成的事件
 private CameraCaptureSession.CaptureCallback CameracaptureCallback = new CaptureCallback() {

  @Override
  public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
    TotalCaptureResult result) {

  }

  @Override
  public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
    CaptureResult partialResult) {

  }

 };

 // 相機擷取狀態
 private CameraCaptureSession.StateCallback CameraCaptureCallback = new StateCallback() {

  @Override
  public void onConfigured(CameraCaptureSession session) {
   try {
    session.setRepeatingRequest(builder.build(), CameracaptureCallback, handler);
   } catch (CameraAccessException e) {
    Log.e("CameraAccessException", e.getMessage());
   }
  }

  @Override
  public void onConfigureFailed(CameraCaptureSession session) {

  }
 };

}

執行結果:

圖片來源:
http://wiki.jikexueyuan.com/project/android-actual-combat-skills/images/33-3.png