Camera2 開啟相機預覽介面
camera2 是21之後的api用於代替Camera,提供更加牛X的對相機hardware操作的api
此篇筆記主要是記錄開啟預覽介面
後面會記錄Camera開啟相機預覽的程式碼,對比一下
介面佈局
<?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" >
<com.arvin.camera3.view.AutoFitTextureView
android:id="@+id/surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/capturebtn"
android:layout_width="wrap_content"
android:layout_height ="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="拍照" />
<ImageView
android:id="@+id/preview"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_alignParentBottom ="true" />
</RelativeLayout>
AutoFitTextureView 繼承自 TextureVeiw
1.首先要初始化view,就是一些findviewbyid
2.示例程式碼是在onResume中,能否有更好方式????
if (surfaceView.isAvailable()) {
// FIXME: 2016/6/13
try {
openCamera(surfaceView.getWidth(), surfaceView.getHeight());
} catch (Exception e) {
e.printStackTrace();
}
} else {
surfaceView.setSurfaceTextureListener(mSurfaceTextureListener);
}
surfaceView即TextureView
判斷TextureView狀態
可用,開啟相機,否則設定相應的回撥
先看開啟相機的程式碼
private void openCamera(int width, int height) throws Exception {
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
if (mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
manager.openCamera(mCameraId,deviceStateCallback,mPreviewHandler );
}
}
首先呼叫getSystemService(Context.CAMERA_SERVICE),拿到CameraManager例項,
注:Api 21 新增的,無相容包,估計也不會發布相容包吧,21之後 Camera已棄用
然後通過CameraManager例項的 openCamera()方法開啟相機預覽
我們看下openCamera的宣告
@RequiresPermission(android.Manifest.permission.CAMERA)
public void openCamera(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException {
if (cameraId == null) {
throw new IllegalArgumentException("cameraId was null");
} else if (callback == null) {
throw new IllegalArgumentException("callback was null");
} else if (handler == null) {
if (Looper.myLooper() != null) {
handler = new Handler();
} else {
throw new IllegalArgumentException(
"Handler argument is null, but no looper exists in the calling thread");
}
}
openCameraDeviceUserAsync(cameraId, callback, handler);
}
@RequiresPermission(android.Manifest.permission.CAMERA)
需要camera許可權,在camera宣告,android 6.0之後需要請求,屬於runtime permission
需要傳入三個引數
cameraId : “0”表示後置攝像頭,“1”表示前置攝像頭
callback : CameraDevice.StateCallback 相機狀態回撥
注:CameraDevice 例項代表一個相機
handler : hanlder
回頭看如果TextureView不可用的狀態下
surfaceView.setSurfaceTextureListener(mSurfaceTextureListener);
看下 mSurfaceTextureListener是個什麼東西
private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
try {
openCamera(width, height);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
這個有點和SurfaceView的回撥相似了
設定回撥,然後當surface可用的時候openCamera(),回到上面的流程去了
包含四個方法,分別對應可用,尺寸發生變化,TextureView銷燬,以及更新的時候回撥
繼續看manager.openCamera();
已經說了第一個引數camreaId,“0”代表後置攝像頭,“1”代表前置攝像頭
第二個引數CameraDevice.StateCallback, 直接看
CameraDevice.StateCallback deviceStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCameraOpenCloseLock.release();
mCameraDevice = camera;
try {
createCameraPreviewSession();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onDisconnected(CameraDevice camera) {
mCameraOpenCloseLock.release();
camera.close();
mCameraDevice = null;
}
@Override
public void onError(CameraDevice camera, int error) {
mCameraOpenCloseLock.release();
camera.close();
mCameraDevice = null;
Toast.makeText(getActivity(), "onError,error--->" + error, Toast.LENGTH_SHORT).show();
}
};
通過程式碼可知,CameraDevice.StateCallback 提供了三個回撥方法,分別對應於camrea開啟,失去連線,開啟錯誤的時候回撥,
在開啟的時候會呼叫createCameraPreviewSession() ,看一下方法定義
private void createCameraPreviewSession() throws CameraAccessException {
initSurface();
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewBuilder.addTarget(mSurface);
mCameraDevice.createCaptureSession(Arrays.asList(mSurface), mCaptureSessionStateCallback, mPreviewHandler);
}
private void initSurface() {
SurfaceTexture sufaceTexture = surfaceView.getSurfaceTexture();
assert sufaceTexture != null;
sufaceTexture.setDefaultBufferSize(surfaceView.getWidth(), surfaceView.getHeight());
mSurface = new Surface(sufaceTexture);
}
首先通過TextureView的getSurfaceTexture() 拿到 對應 SurfaceTexture 是不是SurfaceView的getSurfaceHolder()很像
設定顯示大小,建立Surface例項
之後,呼叫 CameraDevice createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) 建立預覽請求
並設定target, CaptureRequest.Builder addTarget(Surface surface)
然後呼叫CameraDevice createCaptureSession(),建立一個相機回話
createCaptureSession()需要傳入三個引數
看下宣告
public abstract void createCaptureSession(@NonNull List<Surface> outputs,
@NonNull CameraCaptureSession.StateCallback callback, @Nullable Handler handler)
List outputs 我的理解是預覽的輸出載體列表,在上面的程式碼中,我們傳入了new Surface(TextureView.getSurface()) 物件
ImageReader 也有 getSurface()方法,ImageReader也可以作為輸出載體
第二個引數CameraCaptureSession.StateCallback 攝像頭採集狀態回撥
直接看程式碼
private CameraCaptureSession.StateCallback mCaptureSessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
if (null == mCameraDevice) {
return;
}
mSession = session;
mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
try {
session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mPreviewHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
};
設定拍攝模式,這裡設定了連拍,flash,其他的模式嘛,我也不清楚了
mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mPreviewHandler);
設定重複請求,字面上這麼理解
同樣是三個引數
第一個是CaptureRequest.Builder buildI() 這個是前面採集請求builder 通過CameraDevice createCaptureRequest建立的
第二個是攝像頭採集回話採集狀態的回撥
private CameraCaptureSession.CaptureCallback mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
}
@Override
public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) {
super.onCaptureProgressed(session, request, partialResult);
}
};
包含兩個狀態,採集進行,採集完成
可以在這裡面去做處理,
貼上一段程式碼
private CameraCaptureSession.CaptureCallback mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
mSession = session;
if (!PreferenceHelper.getCameraFormat(getActivity()).equals("DNG")) {
checkState(result);
}
}
@Override
public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) {
mSession = session;
if (!PreferenceHelper.getCameraFormat(getActivity()).equals("DNG")) {
checkState(partialResult);
}
}
private void checkState(CaptureResult result) {
// mFrameBitmap = mPreviewView.getBitmap();
// mMainHandler.sendEmptyMessage(1);
switch (mState) {
case STATE_PREVIEW:
// NOTHING
break;
case STATE_WAITING_CAPTURE:
int afState = result.get(CaptureResult.CONTROL_AF_STATE);
Log.i("checkState", "afState--->" + afState);
if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState
|| CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED == afState || CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED == afState) {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
Log.i("checkState", "進來了一層,aeState--->" + aeState);
if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
Log.i("checkState", "進來了第二層");
mState = STATE_TRY_DO_CAPTURE;
doStillCapture();
} else {
mState = STATE_TRY_CAPTURE_AGAIN;
tryCaptureAgain();
}
}
break;
case STATE_TRY_CAPTURE_AGAIN:
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_TRY_DO_CAPTURE;
}
break;
case STATE_TRY_DO_CAPTURE:
aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
mState = STATE_TRY_DO_CAPTURE;
doStillCapture();
}
break;
}
}
};
至此,開啟相機預覽的程式碼就結束了,後續比如拍照,錄影什麼的以後再分析啦,這裡的api還沒在學習中
最後附上Camera開啟預覽的程式碼,感覺要簡單好多呀
//佈局檔案
<SurfaceView
android:id="@+id/surface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Camera camera;
surfaceView = (SurfaceView) findViewById(R.id.surface);
holder = surfaceView.getHolder();
holder.addCallback(this); //設定回撥
@Override
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
}
//將camera預覽介面繫結到SurfaceView
//startPreview()
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
程式碼是不是比camera2簡單多了,不過這個預覽介面挺難看的,其他設定也沒有仔細研究,用到的時候再說吧
相關推薦
Camera2 開啟相機預覽介面
camera2 是21之後的api用於代替Camera,提供更加牛X的對相機hardware操作的api 此篇筆記主要是記錄開啟預覽介面 後面會記錄Camera開啟相機預覽的程式碼,對比一下 介面佈局 <?xml version="1.0"
camera2 API 開啟相機預覽後顯示黑屏問題
最近在嘗試用camera2 API自己寫一個相機程式,先搭了一個整體的框架,主要分為以下幾步: 開啟相機->開啟預覽--->關閉相機 整體框架寫好後編譯通過,在真機上測試也沒有報錯,但是再看真機的效果,發現預覽過程中並沒有出現預覽畫面。 這個問題搞了很久,最後對比Googl
(一)Android camera2 實現相機預覽及獲取預覽幀資料流
一、本文重點說明 本文基於 android camera2 實現視訊預覽,暫未相容 camera1 API,基礎實現可以參考 googlesample Camera2 例子 android-Camera2Basic ,本文以工具類形式實現一步呼叫。 谷歌例子中沒有具體指
自定義相機那些坑之預覽介面適配及原理
0.思維導圖 1.問題的產生 當Activity的oritation設定為portrait時,前置/後置攝像頭預覽影象會逆時針旋轉90度展示,如圖: 2.問題產生的本質 相機影象資料來自影象感應器(物理器件)(Image Sensor),影象感應器再將資料輸出
微信呼叫圖片預覽介面
$("img[typename='wxpic']").click(function(){ var url=$(this).attr("src"); if (window.WeixinJSBridge) {
關於 pyspider Web預覽介面太小的解決方法
本人最近在學習pyspider時,遇到Web預覽介面太小而無法很好的進行開發,於是在網上搜索解決方法。 準備: css程式碼: body{margin:0;padding:0;height:100%;overflow:hidden}.warning{color:#f0ad4e}.e
玩轉Android Camera開發 四 預覽介面四周暗中間亮,只拍攝矩形區域圖片 附完整原始碼
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
怎樣在Sublime Text3 中開啟瀏覽器預覽效果
1、首先 ctrl+shift+P 選 Package Control: Install Package 找 SideBarEnhancements 。如果 沒安裝 Install Package 先安裝  
Android Camera開發 給攝像頭預覽介面加個ZoomBar(附完整程式碼下載)
廢話不說了,就是加個seekbar,拖動的話能夠調節焦距,讓畫面變大或縮小。下面是核心程式:一,camera的佈局檔案<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" x
CameraView Android 相機預覽控制元件
Github地址:https://github.com/google/cameraview 該控制元件為Google開源,非官方,只為了開發人員輕鬆整合Camera功能。 混淆: 釋出release版本時,請在主module中得proguard-rules.pro
微信高階群發之五預覽介面
/** * * sendPreview:(通過該介面傳送訊息給指定使用者,在手機端檢視訊息的樣式和排版。). * * @author HanKeQi * @param @par
微信高階群發之預覽介面
例子一:/** * * sendPreview:(通過該介面傳送訊息給指定使用者,在手機端檢視訊息的樣式和排版。). * * @author HanKeQi * @param @param openId 使用者唯一標示 不能為空 * @param @par
Android自定義相機預覽開始時自動對焦
如果是呼叫系統相機不會存在對焦問題,要實現自己的相機在開始的時候自動自動對焦,只需要新增兩句程式碼: parameters.setFocusMode(Camera.Paramet
相機預覽2.1版本一下相容setDisplayOrientation
protected void setDisplayOrientation(Camera camera, int angle){ Method downPolymorphic; try { downPolymorphic = c
如何Android studio 的佈局XML時預覽介面彈出的Rendering Problems?
如何Android studio 的佈局XML時預覽介面彈出的Rendering Problems? 問題圖預覽: 點選“Preview”預覽選單欄的“AppTheme”,從彈出的選單框中選
Android手勢識別 Camera 預覽介面上顯示文字 佈局注意事項(merge佈局)
通常在Surfaceview作為預覽視訊幀的載體,有時需在上面顯示提示文字。以前我弄的都好好的,今天忽然發現疊加的TextView不管咋弄都出不來文字了,跟Surfaceview一起放在FrameLayout也不行,後來想到merge佈局,發現也不行。大爺的,奇了怪了,最
Android相機預覽方向
以前對Camera瞭解的不是太深入,最近有需求把人臉識別 整合到專案,必然會與Camera打交道,遇到一些坑,與大家分享一下。 一、預覽方向 Camera.CameraInfo info = new Camera.CameraInfo(); 首先理解一下 inf
Android使用camera實現拍照後停留在預覽介面的問題
camera實現拍照的程式碼: /** * 開始拍照 */ public void startCapture() { if (null != camera) { camera.takePicture(nu
TextureView 做相機預覽黑屏
特麼使用TextureView 代替Surfaceview 來做相機預覽頁,因為用Surfaceview預覽的話傳一個SurfaceHolder進去,用Textureview預覽的話需要傳進去一個SurfaceTexture,其他的Camera流程不變。de
【騰訊優測乾貨分享】Android 相機預覽方向及其適配探索
由於Android系統的開放策略,Android手機呈現碎片化的趨勢,相容性問題一直是Android App 開發者頭疼的難題。本文以Android相機預覽方向為例,探索在Android機型適配上的一些思路。 1. android相機簡介 由於And