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

 

 

 

 

posted @ 2017-10-17 09:52  菱花淚硃砂  阅读(2524)  评论(0编辑  收藏  举报