應用場景
當時用手機攝像頭做實時預覽時、需要對視頻中的圖像做人臉檢測、繪製一些效果到人臉上等。。。
實現思路
1.自定義 CameraView extends SurfaceView 做攝像頭預覽。
2.自定義 FloatingLayerView extends SurfaceView 做上層圖標繪製。
3.自定義 DoubleSurfaceView extends FrameLayout 整合上兩個View、開啓相機、監聽幀數據。
關鍵點:
因爲是要使用兩個SurfaceView重疊在一起實現最終效果、所以處於上層的SurfaceView必須是背景透明的。
使用下面設置來實現:
setZOrderOnTop(true);// 設置層級處於頂層
getHolder().setFormat(PixelFormat.TRANSPARENT);// 設置背景透明
另外一個做攝像頭預覽的CameraView 不需要做設置。
技術點:
開啓攝像頭技術需要使用到的API
靜態方法
- Camera.getNumberOfCameras(); // 獲取攝像頭數量
- Camera.getCameraInfo(camIdx, cameraInfo); // 獲取對應ID的攝像頭信息
- Camera.open(camIdx); // 開啓對應ID的攝像頭
- Camera.CameraInfo.CAMERA_FACING_BACK // 後攝像頭
- Camera.CameraInfo.CAMERA_FACING_FRONT // 前攝像頭
非靜態
- mCamera.setDisplayOrientation(result); // 設置攝像頭旋轉角度
- mCamera.getParameters(); // 獲取當前攝像頭參數信息
示例:
// 根據展示區域設置攝像頭預覽寬高
Camera.Parameters params = mCamera.getParameters();
params.setPreviewSize(width, height);
// 開啓前置攝像頭
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
Camera.getCameraInfo(camIdx, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
camera = Camera.open(camIdx);
break;
} catch (RuntimeException e) {
}
}
}
// int rotation = activity.getWindowManager ().getDefaultDisplay ().getRotation ();
// 根據屏幕旋轉方向--旋轉攝像頭
public void setCameraDisplayOrientation(int rotation, int cameraId, Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int degrees = 0;
switch (rotation) { // 根據屏幕旋轉方向記錄需要旋轉的角度
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { // 前置攝像頭計算方式
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else {// 後置攝像頭計算方式
// back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
SurfaceView預覽攝像頭
獲取實時的數據幀
// 設置監聽(開啓預覽前設置)
mCamera.setPreviewCallback(new Camera.PreviewCallback(){
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
Log.i(TAG, "onPreviewFrame = " + bytes.length);
// 此處獲取每一幀的數據 bytes
}
});
mCamera.setPreviewDisplay(surfaceView.getHolder());// 開啓實現預覽
在預覽圖像上繪製浮層
獲取到每一幀的數據、做對應處理(例如:人臉檢測)、此處不要直接在onPreviewFrame()回調中處理,換一個線程
浮層也是使用SurfaceView
只需要設置兩個屬性就可以了
setZOrderOnTop(true);
getHolder().setFormat(PixelFormat.TRANSPARENT);