android camera介绍

Android 中自定义照相机Camera详解
要想定义一个照相机需要用到两个核心类:Camera和SurfaceView
Camera类一些API

Camera用于管理和操作camera资源,他提供了完整的相机底层接口。可以通过camera.getParameters()来获取Camera的参数用以设置照片的预览尺寸、拍摄尺寸、预览帧、拍摄帧、设置光圈、曝光、聚焦、颜色特效等。

SurfaceView类

用于绘制相机的预览功能的类,提供给用户的实时预览的图像。普通的view以及派生类都是共享同一个surface的,所有的绘制都是在UI线程之中绘制的。而surfaceview是一种比较特殊的view,他并不与其他的普通的view共享surface,而是在内部持有了一个独立的surface,surfaceview负责管理这个surface的格式,尺寸及显示位置。由于UI线程还要和其他的线程交互逻辑,因此对view的更新速度和帧率无法保证,而surfaceview由于持有一个独立的surface,因而可以在独立的线程中进行绘制,提供更高的帧率。自定义相机的预览图像由于对更新速度和帧率要求比较高,所以比较实用surfaceview来显示。

SurfaceHolder

surfaceholder是控制surface的一个抽象接口,他能够控制surface的尺寸和格式,修改surface的像素,监视surface的变化等,surface的典型应用就是用于surfaceview中。surfaceview通过getHolder()方法获得surfaceholder实例,通过后者来监听管理surface的状态。

SurfaceHolder.Callback接口

负责监听surface状态变化的接口,有三个方法:

surfaceCreated(SurfaceHolder holder)

在surface创建后立即被调用。在开发自定义相机时,可以通过重载这个函数调用camera.open()、camera.setPreviewDisplay(),来实现获取相机的资源、链接camera和surface等操作。

surfaceChanged(SurfaceHolder holder,int format,int width,int height)

在surface发生format或size变化时调用。在开发自定义相机时,可以通过重载这个函数调用camera.startPreview来开启相机预览,使得camera预览帧数据可以传递给surface,从而实时显示相机预览图像。

surfaceDestory(SurfaceHolder holder)

在surface销毁之前被调用。在开发自定义相机时,可以通过重载这个函数调用camera.stopPreview(),camera.release()来实现停止相机预览及释放相机资源等操作。

public class CustomCameraActivity extends Activity implements OnClickListener,
        SurfaceHolder.Callback, Camera.PictureCallback {

    private Camera camera;
    private static final String TAG = "Havorld";
    private Camera.Parameters parameters;
    private int orientationDegrees = 90;
    private FrameLayout frameLayout;
    private ImageButton imageButton, reset, ok;
    /** 路径: /storage/emulated/0/Pictures/ */
    private String savePath;
    private String path;
    private SurfaceHolder surfaceHolder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        savePath = Environment
                .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
                + File.separator;
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        surfaceView.setOnClickListener(this);

        frameLayout = (FrameLayout) findViewById(R.id.frameLayout);
        imageButton = (ImageButton) findViewById(R.id.imageButton);
        reset = (ImageButton) findViewById(R.id.reset);
        ok = (ImageButton) findViewById(R.id.ok);

        frameLayout.setOnClickListener(this);
        imageButton.setOnClickListener(this);
        reset.setOnClickListener(this);
        ok.setOnClickListener(this);

        // 到SurfaceHolder,SurfaceHolder相当于一个监听器,可以通过CallBack来监听 SurfaceView上的变化。
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        // 为了实现照片预览功能,需要将SurfaceHolder的类型设置为PUSH,这样画图缓存就由Camera类来管理,画图缓存是独立于Surface的
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        startOrientationChangeListener();
    }

    private final void startOrientationChangeListener() {

        OrientationEventListener mOrEventListener = new OrientationEventListener(
                this) {
            @Override
            public void onOrientationChanged(int rotation) {

                if (((rotation >= 0) && (rotation <= 45)) || (rotation >= 315)) {

                    orientationDegrees = 90;
                } else if ((rotation > 45) && (rotation < 135)) {

                    orientationDegrees = 180;
                } else if ((rotation >= 135) && (rotation <= 225)) {

                    orientationDegrees = 270;
                } else if ((rotation > 225) && (rotation < 315)) {

                    orientationDegrees = 0;
                }

                // Log.e(TAG, "rotation:"+rotation);

            }
        };
        mOrEventListener.enable();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.e(TAG, "surfaceCreated");
        surfaceHolder = holder;
        initCamera();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        Log.e(TAG, "surfaceChanged");

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.e(TAG, "surfaceDestroyed");

        // 当Surface被销毁的时候,该方法被调用
        // 在这里需要释放Camera资源
        releaseCamera();
    }

    @SuppressWarnings("deprecation")
    private void initCamera() {

        // 判断是否有摄像头
        if (!getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_CAMERA))
            return;

        // 获取摄像头的个数
        // int numberOfCameras = Camera.getNumberOfCameras();
        // 后置摄像头
        camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        /**
         * 获取设备Camera特性参数。由于不同的设备Camera的特性是不同的,所以在设置时需要首先判断设备对应的特性,再加以设置
         */
        parameters = camera.getParameters();
        // 获取可预览的尺寸集合
        List<Size> supportedPreviewSizes = parameters
                .getSupportedPreviewSizes();
        Size previewSize = PreviewSizeUtil
                .getSupportSize(supportedPreviewSizes);
        // 获取可设置图片的大小集合
        List<Size> supportedPictureSizes = parameters
                .getSupportedPictureSizes();
        // 设置生成最大的图片
        // Size pictureSize =
        // PreviewSizeUtil.getSupportSize(supportedPictureSizes);
        Size pictureSize = supportedPictureSizes.get((supportedPictureSizes
                .size() - 1) / 2);
        // 获取可设置的帧数
        List<Integer> supportedPreviewFrameRates = parameters
                .getSupportedPreviewFrameRates();
        Integer frameRates = supportedPreviewFrameRates
                .get((supportedPreviewFrameRates.size() - 1) / 2);
        // 设置Camera的参数
        parameters.setPreviewSize(previewSize.width, previewSize.height);
        parameters.setPictureSize(pictureSize.width, pictureSize.height);
        // 设置帧数(每秒从摄像头里面获得几个画面)
        parameters.setPreviewFrameRate(frameRates);

        // 设置图片格式
        parameters.setPictureFormat(ImageFormat.JPEG);
        // 设置照片质量
        parameters.setJpegQuality(100);

        // 首先获取系统设备支持的所有颜色特效,如果设备不支持颜色特性将返回一个null, 如果有符合我们的则设置
        List<String> colorEffects = parameters.getSupportedColorEffects();
        Iterator<String> colorItor = colorEffects.iterator();
        while (colorItor.hasNext()) {
            String currColor = colorItor.next();
            if (currColor.equals(Camera.Parameters.EFFECT_SOLARIZE)) {
                // parameters.setColorEffect(Camera.Parameters.EFFECT_AQUA);
                break;
            }
        }

        // 获取对焦模式
        List<String> focusModes = parameters.getSupportedFocusModes();
        // [auto, infinity, macro, continuous-video, continuous-picture, manual]
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            // 设置自动对焦
            parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        }

        // 设置闪光灯自动开启
        List<String> flashModes = parameters.getSupportedFlashModes();
        if (flashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {
            // 自动闪光
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
        }

        int orientationDegrees = PreviewSizeUtil.getCameraDisplayOrientation(
                this, Camera.CameraInfo.CAMERA_FACING_BACK);
        // 设置相机镜头旋转角度(默认摄像头是横拍)
        camera.setDisplayOrientation(orientationDegrees);

        try {
            // 设置显示
            camera.setPreviewDisplay(surfaceHolder);

        } catch (IOException exception) {

            releaseCamera();
        }
        // 设置完成需要再次调用setParameter方法才能生效
        camera.setParameters(parameters);

        // 开始预览
        camera.startPreview();

    }

    private void releaseCamera() {
        if (camera != null) {

            camera.setPreviewCallback(null);
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        path = savePath + "XiuMF_" + System.currentTimeMillis() + ".jpg";
        File file = new File(path);
        OutputStream output = null;
        try {
            output = new FileOutputStream(file);
            output.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 拍照后预览会停止,重新开启下
        camera.startPreview();

    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
        case R.id.frameLayout:
        case R.id.imageButton:

            if (parameters != null) {
                // 设置照片在相册的旋转角度(默认摄像头是横放)
                // parameters.setRotation(orientationDegrees);
                parameters.set("rotation", orientationDegrees);
                // 获取当前手机屏幕方向
                camera.setParameters(parameters);
                Log.e(TAG, "orientationDegrees:" + orientationDegrees);
            }
            /**
             * ShutterCallback shutter:按下快门的回调 PictureCallback raw:原始图像数据的回调
             * PictureCallback postview:压缩图像 PictureCallback
             * jpeg:压缩成jpg格式的图像数据的回调
             */
            camera.takePicture(null, null, null, this);
            break;
        case R.id.ok:// 获取照片
            Intent intent = getIntent();
            if (intent != null) {
                intent.putExtra("path", path);
                setResult(-1, intent);
            }
            finish();
            break;
        case R.id.reset: // 删除照片
            File file = new File(path);
            if (file.exists()) {
                file.delete();
            }
            file = null;
            break;
        default:
            break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        releaseCamera();
    }
}

PreviewSizeUtil类

public class PreviewSizeUtil {


    /**
     * 获取最大的预览/图片尺寸
     * 
     * @return 预览尺寸集合
     */
    public static Size getSupportSize(List<Size> listSize) {

        if (listSize == null || listSize.size() <= 0) {

            return null;
        }
        Size  largestSize = listSize.get(0);
        if (listSize.size() > 1) {
            Iterator<Camera.Size> iterator = listSize.iterator();
            while (iterator.hasNext()) {
                Camera.Size size = iterator.next();
                if (size.width > largestSize.width && size.height > largestSize.height) {
                    largestSize = size;
                }
            }
        }  
        return largestSize;

    }


    /**
     * 获取拍照时偏移方向的角度(此方法在手机方向没有锁定,为自由切换时易用)
     * 
     * @param activity
     * @param cameraId 开启相机的id(0.后相机,1.前相机)
     * @return 偏移的角度
     */
    public static int getCameraDisplayOrientation(Activity activity,
            int cameraId) {

        CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay()
                .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;
        }

        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;
        }

        return result;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值