Android CameraManager 类

先看代码:

    private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private CameraManager cameraManager; cameraManager = new CameraManager(this);
mSurfaceView = (SurfaceView) findViewById(R.id.java_surface_view);
mSurfaceHolder = mSurfaceView.getHolder(); // mSurfaceView 不需要自己的缓冲区
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// mSurfaceView添加回调
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建
try {
cameraManager.openDriver(mSurfaceHolder);
cameraManager.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override
public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁
holder.removeCallback(this); // Camera is being used after Camera.release() was called
cameraManager.stopPreview();
cameraManager.closeDriver(); }
});

自定义一个 CameraManager 类,在关闭当前页面,释放camera资源时偶尔报错

Camera is being used after Camera.release() was called

第一次,加了一句 holder.removeCallback(this); 运行发现还是时不时出现报错。

第二次在释放 camera前加  camera.setPreviewCallback(null); 问题解决。

    /**
* 关闭预览
*/
public synchronized void stopPreview() {
Log.e(TAG, "stopPreview");
if (autoFocusManager != null) {
autoFocusManager.stop();
autoFocusManager = null;
}
if (camera != null && previewing) {
camera.stopPreview();
camera.setPreviewCallback(null); // Camera is being used after Camera.release() was called
previewing = false;
}
} /**
* 关闭camera
*/
public synchronized void closeDriver() {
Log.e(TAG, "closeDriver");
if (camera != null) {
camera.release();
camera = null;
}
}

原来:如果程序中加入了previewCallback,在surfaceDestroy释放camera的时候,最好执行myCamera.setOneShotPreviewCallback(null); 或者myCamera.setPreviewCallback(null);中止这种回调,然后再释放camera更安全。否则可能会报错。

附:CameraManager类:

package com.myproject.facedetection.entity;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.WindowManager; import com.opencvlib.ObjectDetector; import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import static com.myproject.facedetection.common.myUtils.ByteToBitmap; /**
* User:lizhangqu(513163535@qq.com)
* Date:2015-09-05
* Time: 10:56
*/
public class CameraManager implements Camera.PreviewCallback {
private static final String TAG = CameraManager.class.getName();
private Camera camera;
private Camera.Parameters parameters;
private AutoFocusManager autoFocusManager;
private int requestedCameraId = -1; // 默认打开后置摄像头
private int cameraPosition;//0代表前置摄像头,1代表后置摄像头
private int numCameras = Camera.getNumberOfCameras(); // 初始化摄像头数量
private Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
private Context mContext; private boolean initialized;
private boolean previewing;
private ArrayList<ObjectDetector> mObjectDetects;
private CustomImageButton cimbt;
private SurfaceHolder holder; /**
* 打开摄像头
*
* @param cameraId 摄像头id
* @return Camera
*/
public Camera open(int cameraId) {
if (numCameras <= 0) {
Log.e(TAG, "No cameras!");
return null;
} // 如果 cameraId 在 [0-numCameras) 之间则打开cameraId 否则默认优先打开后置
boolean explicitRequest = (cameraId >= 0 && cameraId < numCameras); int index = 0;
if (!explicitRequest) {
// Select a camera if no explicit camera requested
while (index < numCameras) {
Camera.getCameraInfo(index, cameraInfo);
cameraId = index;
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
cameraPosition = 1;
break;
}
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
cameraPosition = 0;
continue;
} index++;
}
} // 不在 [0-numCameras) 之间 且 没有默认打开的
Camera camera;
if (index < numCameras) {
Log.e(TAG, "Opening camera #" + cameraId);
camera = Camera.open(cameraId);
} else {
Log.e(TAG, "Requested camera does not exist: " + cameraId);
camera = null;
} int rotation = getDisplayOrientation();
camera.setDisplayOrientation(rotation);
camera.setPreviewCallback(this);
//camera.setOneShotPreviewCallback(this); // 激活 onPreviewFrame 执行一次
return camera;
} public int getDisplayOrientation() {
Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int rotation = display.getRotation();
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;
}
Camera.CameraInfo camInfo = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, camInfo);
int result = (camInfo.orientation - degrees + 360) % 360;
return result;
} public CameraManager(Context context, ArrayList<ObjectDetector> mObjectDetects, CustomImageButton cimbt, SurfaceHolder holder) {
this.mContext = context;
this.mObjectDetects = mObjectDetects;
this.cimbt = cimbt;
this.holder = holder;
} /**
* 打开camera
*
* @throws IOException IOException
*/
public synchronized void openDriver()
throws IOException {
Log.e(TAG, "openDriver");
Camera theCamera = camera;
if (theCamera == null) {
theCamera = open(requestedCameraId);
if (theCamera == null) {
throw new IOException();
}
camera = theCamera;
}
theCamera.setPreviewDisplay(holder); if (!initialized) {
initialized = true;
parameters = camera.getParameters();
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); int w = 800;
int h = 600;
for (Camera.Size size : previewSizes) {
Log.e("TAG", "previewSizes width:" + size.width);
Log.e("TAG", "previewSizes height:" + size.height);
if (size.width - w <= 200 & size.width >= w) {
w = size.width;
h = size.height;
break;
}
}
Log.e("w*h", String.format("%d*%d", w, h));
parameters.setPreviewSize(w, h);
parameters.setPictureFormat(ImageFormat.JPEG);
parameters.setJpegQuality(100);
parameters.setPictureSize(800, 600);
theCamera.setParameters(parameters);
}
} /*
切换摄像头
*/
public synchronized void changeCamera() throws IOException {
for (int i = 0; i < numCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息
//现在是后置,变更为前置
if (cameraPosition == 1) {
//代表摄像头的方位 CAMERA_FACING_FRONT前置 CAMERA_FACING_BACK后置
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
stopPreview();
closeDriver(); requestedCameraId = i;
initialized = false; openDriver();
startPreview();
cameraPosition = 0;
break;
}
} else {
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
stopPreview();
closeDriver(); requestedCameraId = i;
initialized = false; openDriver();
startPreview();
cameraPosition = 1;
break;
}
} }
} @Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
Camera.Size previewSize = camera.getParameters().getPreviewSize(); Bitmap bitmap = ByteToBitmap(bytes, previewSize);
//Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);//将data byte型数组转换成bitmap文件 final Matrix matrix = new Matrix();//转换成矩阵旋转90度
if (cameraPosition == 1) {
matrix.setRotate(90);
} else {
matrix.setRotate(-90);
}
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);//旋转图片 Mat grayscaleImage = new Mat(previewSize.height, previewSize.width, CvType.CV_8UC4);
int absoluteFaceSize = (int) (previewSize.height * 0.2); if (bitmap != null) {
Mat inputFrame = new Mat();
Utils.bitmapToMat(bitmap, inputFrame); if (!bitmap.isRecycled()) {
bitmap.recycle();
} // Create a grayscale image
Imgproc.cvtColor(inputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB); MatOfRect mRect = new MatOfRect(); int maxRectArea = 0 * 0;
Rect maxRect = null; int facenum = 0; for (ObjectDetector detector : mObjectDetects) {
// 检测目标
Rect[] object = detector.detectObjectImage(inputFrame, mRect);
Log.e(TAG, object.length + ""); for (Rect rect : object) {
++facenum;
// 找出最大的面积
int tmp = rect.width * rect.height;
if (tmp >= maxRectArea) {
maxRectArea = tmp;
maxRect = rect;
}
}
} Bitmap rectBitmap = null;
if (facenum != 0) {
// 剪切最大的头像
//Log.e("剪切的长宽", String.format("高:%s,宽:%s", maxRect.width, maxRect.height));
Rect rect = new Rect(maxRect.x, maxRect.y, maxRect.width, maxRect.height);
Mat rectMat = new Mat(inputFrame, rect); // 从原始图像拿
rectBitmap = Bitmap.createBitmap(rectMat.cols(), rectMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(rectMat, rectBitmap); Bitmap resizeBmp = cimbt.resizeBitmap(rectBitmap, cimbt.getWidth(), cimbt.getHeight());
cimbt.setBitmap(resizeBmp);
} else {
cimbt.clearnImage();
cimbt.setText("没有检测到人脸");
}
} } public interface OnObjectTrackingInterface {
// 传输camera的字节流
void onCameraByteStream(byte[] bytes, Camera camera); } /**
* camera是否打开
*
* @return camera是否打开
*/ public synchronized boolean isOpen() {
return camera != null;
} /**
* 关闭camera
*/
public synchronized void closeDriver() {
Log.e(TAG, "closeDriver");
if (camera != null) {
camera.release();
camera = null;
}
} /**
* 开始预览
*/
public synchronized void startPreview() {
Log.e(TAG, "startPreview");
Camera theCamera = camera;
if (theCamera != null && !previewing) {
theCamera.startPreview();
previewing = true;
autoFocusManager = new AutoFocusManager(camera);
}
} /**
* 关闭预览
*/
public synchronized void stopPreview() {
Log.e(TAG, "stopPreview");
if (autoFocusManager != null) {
autoFocusManager.stop();
autoFocusManager = null;
}
if (camera != null && previewing) {
camera.stopPreview();
camera.setPreviewCallback(null); // Camera is being used after Camera.release() was called
previewing = false;
}
} /**
* 打开闪光灯
*/
public synchronized void openLight() {
Log.e(TAG, "openLight");
if (camera != null) {
parameters = camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
}
} /**
* 关闭闪光灯
*/
public synchronized void offLight() {
Log.e(TAG, "offLight");
if (camera != null) {
parameters = camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
}
} /**
* 拍照
*
* @param shutter ShutterCallback
* @param raw PictureCallback
* @param jpeg PictureCallback
*/
public synchronized void takePicture(final Camera.ShutterCallback shutter, final Camera.PictureCallback raw,
final Camera.PictureCallback jpeg) {
camera.takePicture(shutter, raw, jpeg);
} private Bitmap reSize(byte[] data) {
Log.i(TAG, "myJpegCallback:onPictureTaken...");
Bitmap cutMap = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字节数据,将其解析成位图
//设置FOCUS_MODE_CONTINUOUS_VIDEO)之后,myParam.set("rotation", 90)失效。图片竟然不能旋转了,故这里要旋转下
Matrix matrix = new Matrix();
matrix.postRotate((float) 90.0);
Bitmap rotaBitmap = Bitmap.createBitmap(cutMap, 0, 0, cutMap.getWidth(), cutMap.getHeight(), matrix, false); //旋转后rotaBitmap是960×1280.预览surfaview的大小是540×800
//将960×1280缩放到540×800
Bitmap sizeBitmap = Bitmap.createScaledBitmap(rotaBitmap, 540, 800, true);
Bitmap rectBitmap = Bitmap.createBitmap(sizeBitmap, 100, 200, 300, 300);//截取
return rectBitmap;
}
}

CameraManager

上一篇:ASP.NET Core Web 应用程序系列(四)- ASP.NET Core 异步编程之async await


下一篇:关于Spring事务回滚的问题